90 |
static gettext_domain_t the_domain; |
static gettext_domain_t the_domain; |
91 |
|
|
92 |
|
|
93 |
|
/* Return TRUE if the native user language is not English |
94 |
|
and thus, gettext support is available */ |
95 |
|
static bool |
96 |
|
gettext_is_required (void) |
97 |
|
{ |
98 |
|
LANGID lang = GetUserDefaultLangID (); |
99 |
|
if (PRIMARYLANGID (lang) == LANG_ENGLISH) |
100 |
|
return false; |
101 |
|
return true; |
102 |
|
} |
103 |
|
|
104 |
|
|
105 |
static DWORD |
static DWORD |
106 |
do_swap_u32 (DWORD i) |
do_swap_u32 (DWORD i) |
107 |
{ |
{ |
132 |
} |
} |
133 |
|
|
134 |
|
|
|
/* Missing W32 functions. */ |
|
|
static char* |
|
|
w32_stpcpy (char *a, const char *b) |
|
|
{ |
|
|
while (*b) |
|
|
*a++ = *b++; |
|
|
*a = 0; |
|
|
return (char*)a; |
|
|
} |
|
|
|
|
|
|
|
135 |
static gettext_domain_t |
static gettext_domain_t |
136 |
load_domain (const char *filename) |
load_domain (const char *filename) |
137 |
{ |
{ |
164 |
size_t nb = fread (read_ptr, 1, to_read, fp); |
size_t nb = fread (read_ptr, 1, to_read, fp); |
165 |
if (nb < to_read) { |
if (nb < to_read) { |
166 |
fclose (fp); |
fclose (fp); |
167 |
free(data); |
free (data); |
168 |
return NULL; /* read error */ |
return NULL; /* read error */ |
169 |
} |
} |
170 |
read_ptr += nb; |
read_ptr += nb; |
206 |
} |
} |
207 |
|
|
208 |
/* allocate an array to keep track of code page mappings */ |
/* allocate an array to keep track of code page mappings */ |
209 |
domain->mapped = (char *)calloc( 1, domain->nstrings ); |
domain->mapped = (char *)calloc (1, domain->nstrings); |
210 |
if (!domain->mapped) |
if (!domain->mapped) |
211 |
BUG (0); |
BUG (0); |
212 |
|
|
216 |
} |
} |
217 |
|
|
218 |
|
|
|
/* Returns a string representation of the users system language |
|
|
* if we support it, 'en' otherwise. |
|
|
*/ |
|
|
static const char* |
|
|
get_user_langid (void) |
|
|
{ |
|
|
int lang = GetUserDefaultLangID() & 511; |
|
|
|
|
|
for (int i=0; lang_list[i].id != NULL; i++) { |
|
|
if (lang == lang_list[i].langid) |
|
|
return lang_list[i].id; |
|
|
} |
|
|
return "en"; |
|
|
} |
|
|
|
|
|
|
|
219 |
/* To avoid problems that the current directory is not the |
/* To avoid problems that the current directory is not the |
220 |
* same folder the WinPT.exe is located in, we extract the |
* same folder the WinPT.exe is located in, we extract the |
221 |
* module directory. |
* module directory. |
223 |
char* |
char* |
224 |
get_module_dir (char *buf, DWORD buflen) |
get_module_dir (char *buf, DWORD buflen) |
225 |
{ |
{ |
|
int pos; |
|
|
|
|
226 |
if (buflen < 1 || !GetModuleFileName (glob_hinst, buf, buflen-1)) |
if (buflen < 1 || !GetModuleFileName (glob_hinst, buf, buflen-1)) |
227 |
return NULL; |
return NULL; |
228 |
|
|
229 |
pos = strlen (buf); |
size_t pos = strlen (buf); |
230 |
while (pos > 0 && buf[--pos] != '\\') |
while (pos > 0 && buf[--pos] != '\\') |
231 |
; |
; |
232 |
buf[pos+1] = '\0'; |
buf[pos+1] = '\0'; |
235 |
|
|
236 |
|
|
237 |
/* Returns a localisation name for a specific resource (file). |
/* Returns a localisation name for a specific resource (file). |
238 |
* For instance, lang=DE and file=winpt.chm will become |
* For instance, lang=DE and file=winpt.chm will become winpt.DE.chm |
|
* winpt.DE.chm |
|
239 |
*/ |
*/ |
240 |
char* |
char* |
241 |
get_locale_name (const char *file) |
get_locale_name (const char *file) |
242 |
{ |
{ |
243 |
const char *lang = get_user_langid(); |
const char *lang = gettext_get_langid (); |
244 |
char *name, *ext; |
char *name, *ext; |
245 |
char *p, buf[MAX_PATH+1]; |
char *p, buf[MAX_PATH+1]; |
246 |
|
|
250 |
sprintf (p, "%s.%s", file, lang); |
sprintf (p, "%s.%s", file, lang); |
251 |
return p; |
return p; |
252 |
} |
} |
253 |
name = substr (file, 0, p-file); |
name = substr (file, 0, p - file); |
254 |
ext = substr (file, p-file+1, strlen(file)); |
ext = substr (file, p - file + 1, strlen(file)); |
255 |
p = get_module_dir (buf, MAX_PATH); |
p = get_module_dir (buf, MAX_PATH); |
256 |
if (!p) |
if (!p) |
257 |
BUG (NULL); |
BUG (NULL); |
278 |
} |
} |
279 |
|
|
280 |
|
|
281 |
|
/* Replace and release the old domain and assign a new domain then */ |
282 |
|
static void |
283 |
|
gettext_update_domain (gettext_domain_t new_dom) |
284 |
|
{ |
285 |
|
gettext_free_current_domain (); |
286 |
|
the_domain = new_dom; |
287 |
|
} |
288 |
|
|
289 |
|
|
290 |
char* get_reg_entry_mo (void); |
char* get_reg_entry_mo (void); |
291 |
|
|
292 |
/* Fallback code which is used when no new NLS file |
/* Fallback code which is used when no new NLS file were found. |
293 |
* were found. Then we read the MODir registry key |
Then we read the MODir registry key and check if a file named |
294 |
* and check if a file named 'winpt.mo' exists in this |
'winpt.mo' exists in this directory. */ |
|
* directory. |
|
|
*/ |
|
295 |
static gettext_domain_t |
static gettext_domain_t |
296 |
load_modir_domain (void) |
load_modir_domain (void) |
297 |
{ |
{ |
|
gettext_domain_t domain = NULL; |
|
|
|
|
298 |
char *modir = get_reg_entry_mo (); |
char *modir = get_reg_entry_mo (); |
299 |
if (!modir) |
if (!modir) |
300 |
return NULL; |
return NULL; |
307 |
s += "\\"; |
s += "\\"; |
308 |
s += "winpt.mo"; |
s += "winpt.mo"; |
309 |
|
|
310 |
|
gettext_domain_t domain = NULL; |
311 |
const char *fname = s.getBuffer(); |
const char *fname = s.getBuffer(); |
312 |
if (!file_exist_check (fname)) |
if (!file_exist_check (fname)) |
313 |
domain = load_domain (fname); |
domain = load_domain (fname); |
316 |
} |
} |
317 |
|
|
318 |
|
|
319 |
|
/* Try to load the user domain, either from |
320 |
|
the WinPT.exe directory or from the registry */ |
321 |
int |
int |
322 |
gettext_set_user_domain (void) |
gettext_set_user_domain (void) |
323 |
{ |
{ |
324 |
|
if (!gettext_is_required ()) |
325 |
|
return 0; |
326 |
|
|
327 |
gettext_domain_t domain = NULL; |
gettext_domain_t domain = NULL; |
328 |
char *file = get_locale_name ("winpt.mo"); |
char *file = get_locale_name ("winpt.mo"); |
329 |
if (file && !file_exist_check (file)) |
if (file && !file_exist_check (file)) |
331 |
else |
else |
332 |
domain = load_modir_domain (); |
domain = load_modir_domain (); |
333 |
free_if_alloc (file); |
free_if_alloc (file); |
334 |
gettext_free_current_domain (); |
gettext_update_domain (domain); |
|
the_domain = domain; |
|
335 |
return 0; |
return 0; |
336 |
} |
} |
337 |
|
|
351 |
return 0; |
return 0; |
352 |
} |
} |
353 |
|
|
|
/* Set the file used for translations. Pass a NULL to disable translation. |
|
|
A new filename may be set at anytime. */ |
|
|
int |
|
|
gettext_set_file (const char *filename, const char *nls_dir) |
|
|
{ |
|
|
gettext_domain_t domain = NULL; |
|
|
|
|
|
if (filename && *filename) { |
|
|
if (filename[1] == ':' && filename[2] == '\\') |
|
|
domain = load_domain (filename); /* absolute path - use it as is */ |
|
|
else { /* relative path - append ".mo" and get dir from the environment */ |
|
|
char *buf, *dir; |
|
|
|
|
|
dir = strdup (nls_dir); |
|
|
if (!dir) |
|
|
BUG (0); |
|
|
buf= (char *)malloc (strlen (dir) + strlen (filename)+1+3+1); |
|
|
strcpy (w32_stpcpy (w32_stpcpy ( |
|
|
w32_stpcpy (buf, dir), "\\"), filename),".mo"); |
|
|
domain = load_domain(buf); |
|
|
free (buf); |
|
|
free (dir); |
|
|
} |
|
|
if (!domain) |
|
|
return -1; |
|
|
} |
|
|
|
|
|
gettext_free_current_domain (); |
|
|
the_domain = domain; |
|
|
return 0; |
|
|
} |
|
|
|
|
|
|
|
354 |
static const char* |
static const char* |
355 |
get_string (gettext_domain_t domain, DWORD idx) |
get_string (gettext_domain_t domain, DWORD idx) |
356 |
{ |
{ |
358 |
domain->trans_tab[idx].offset); |
domain->trans_tab[idx].offset); |
359 |
if (!domain->mapped[idx]) |
if (!domain->mapped[idx]) |
360 |
domain->mapped[idx] = 1; |
domain->mapped[idx] = 1; |
361 |
|
/* FIXME: all text is in UTF-8 and need to be converted to |
362 |
|
the locale charset. But the caller does not free the data and |
363 |
|
thus we will get a leak */ |
364 |
return (const char *)p; |
return (const char *)p; |
365 |
} |
} |
366 |
|
|
433 |
} |
} |
434 |
|
|
435 |
|
|
436 |
|
|
437 |
/* Map the user specific language ID to a gettext conform language string. |
/* Map the user specific language ID to a gettext conform language string. |
438 |
|
English "en" is defined as the fallback. |
439 |
Example: LANG_GERMAN -> "de" */ |
Example: LANG_GERMAN -> "de" */ |
440 |
const char* |
const char* |
441 |
gettext_get_langid (void) |
gettext_get_langid (void) |
442 |
{ |
{ |
443 |
LANGID lang = GetUserDefaultLangID (); |
LANGID lang = GetUserDefaultLangID (); |
444 |
if (PRIMARYLANGID (lang) == LANG_ENGLISH) |
|
|
return NULL; |
|
|
|
|
445 |
for (int i=0; lang_list[i].id; i++) { |
for (int i=0; lang_list[i].id; i++) { |
446 |
if (PRIMARYLANGID (lang) == lang_list[i].langid) |
if (PRIMARYLANGID (lang) == lang_list[i].langid) |
447 |
return lang_list[i].id; |
return lang_list[i].id; |
448 |
} |
} |
449 |
return NULL; |
|
450 |
|
return "en"; |
451 |
} |
} |
452 |
|
|
453 |
|
|