1 /*
2   i18n.c
3 
4   For Tux Paint
5   Language-related functions
6 
7   Copyright (c) 2002-2020 by Bill Kendrick and others
8   bill@newbreedsoftware.com
9   http://www.tuxpaint.org/
10 
11   This program is free software; you can redistribute it and/or modify
12   it under the terms of the GNU General Public License as published by
13   the Free Software Foundation; either version 2 of the License, or
14   (at your option) any later version.
15 
16   This program is distributed in the hope that it will be useful,
17   but WITHOUT ANY WARRANTY; without even the implied warranty of
18   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19   GNU General Public License for more details.
20 
21   You should have received a copy of the GNU General Public License
22   along with this program; if not, write to the Free Software
23   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
24   (See COPYING.txt)
25 
26   $Id$
27 
28   June 14, 2002 - July 26, 2020
29 */
30 
31 #include <stdio.h>
32 #include <stdlib.h>
33 #include <string.h>
34 #include <libintl.h>
35 #include <locale.h>
36 #include "i18n.h"
37 #include "debug.h"
38 
39 #ifdef WIN32
40 #include <sys/types.h>
41 #endif
42 
43 #ifdef __BEOS__
44 #include <wchar.h>
45 #else
46 #include <wchar.h>
47 #include <wctype.h>
48 #endif
49 
50 
51 /* Globals: */
52 
53 static int langint = LANG_EN;
54 
55 /* Strings representing each language's ISO 639 (-1 or -2) codes.
56  * Should map to the 'enum' of possible languages ("LANG_xxx")
57  * found in "i18n.h" (where "NUM_LANGS" is found, as the final
58  * entry in the 'enum' list). */
59 const char *lang_prefixes[NUM_LANGS] = {
60   "ach",
61   "af",
62   "ak",
63   "am",
64   "an",
65   "ar",
66   "as",
67   "ast",
68   "az",
69   "be",
70   "bg",
71   "bm",
72   "bn",
73   "bo",
74   "br",
75   "brx",
76   "bs",
77   "ca@valencia",
78   "ca",
79   "cgg",
80   "cs",
81   "cy",
82   "da",
83   "de",
84   "doi",
85   "el",
86   "en",
87   "en_AU",
88   "en_CA",
89   "en_GB",
90   "en_ZA",
91   "eo",
92   "es_MX",
93   "es",
94   "et",
95   "eu",
96   "fa",
97   "ff",
98   "fi",
99   "fo",
100   "fr",
101   "ga",
102   "gd",
103   "gl",
104   "gos",
105   "gu",
106   "he",
107   "hi",
108   "hr",
109   "hu",
110   "hy",
111   "tlh",
112   "id",
113   "is",
114   "it",
115   "iu",
116   "ja",
117   "ka",
118   "kab",
119   "kn",
120   "km",
121   "kok@roman",
122   "kok",
123   "ko",
124   "ks@devanagari",
125   "ks",
126   "ku",
127   "lb",
128   "lg",
129   "lt",
130   "lv",
131   "mai",
132   "ml",
133   "mk",
134   "mn",
135   "mni",
136   "mni@meiteimayek",
137   "mr",
138   "ms",
139   "nb",
140   "ne",
141   "nl",
142   "nn",
143   "nr",
144   "nso",
145   "oc",
146   "oj",
147   "or",
148   "pa",
149   "pl",
150   "pt_BR",
151   "pt",
152   "ro",
153   "ru",
154   "rw",
155   "sat@olchiki",
156   "sat",
157   "sa",
158   "sc",
159   "sd",
160   "sd@devanagari",
161   "shs",
162   "si",
163   "sk",
164   "sl",
165   "son",
166   "sq",
167   "sr@latin",
168   "sr",
169   "su",
170   "sv",
171   "sw",
172   "ta",
173   "te",
174   "th",
175   "tl",
176   "tr",
177   "tw",
178   "uk",
179   "ur",
180   "vec",
181   "ve",
182   "vi",
183   "wa",
184   "wo",
185   "xh",
186   "zam",
187   "zh_CN",
188   "zh_TW",
189   "zu",
190 };
191 
192 
193 /* Languages which don't use the default font */
194 static int lang_use_own_font[] = {
195   LANG_AR,
196   LANG_BO,
197   LANG_GU,
198   LANG_HI,
199   LANG_JA,
200   LANG_KA,
201   LANG_KO,
202   LANG_ML,
203   LANG_TA,
204   LANG_TE,
205   LANG_TH,
206   LANG_ZH_CN,
207   LANG_ZH_TW,
208   -1
209 };
210 
211 /* Languages which are written right-to-left */
212 static int lang_use_right_to_left[] = {
213   LANG_AR,
214   LANG_FA,
215   LANG_HE,
216   LANG_KS,
217   LANG_SD,
218   LANG_UR,
219   -1
220 };
221 
222 /* FIXME: */
223 static int lang_use_right_to_left_word[] = {
224 #ifdef NO_SDLPANGO
225   LANG_HE,
226 #endif
227   -1
228 };
229 
230 /* Languages which require a vertical 'nudge' in
231  * text rendering, and by how much? */
232 static int lang_y_nudge[][2] = {
233   {LANG_KM, 4},
234   {-1, -1}
235 };
236 
237 
238 int need_own_font;
239 int need_right_to_left;
240 int need_right_to_left_word;
241 const char *lang_prefix, *short_lang_prefix;
242 
243 w_langs wished_langs[255];
244 
245 /* Mappings from human-readable language names (found in
246  * config files, or command-line arguments) to the precise
247  * local code to use.  Some locales appear multiple times,
248  * (e.g. "de_DE.UTF-8" is represented by both "german"
249  * (the English name of the language) and "deutsch"
250  * (the German name of the language)).
251  */
252 static const language_to_locale_struct language_to_locale_array[] = {
253   {"english", "C"},
254   {"american-english", "C"},
255   {"acholi", "ach_UG.UTF-8"},
256   {"acoli", "ach_UG.UTF-8"},
257   {"akan", "ak_GH.UTF-8"},
258   {"twi-fante", "ak_GH.UTF-8"},
259   {"amharic", "am_ET.UTF-8"},
260   {"arabic", "ar_SA.UTF-8"},
261   {"aragones", "an_ES.UTF-8"},
262   {"armenian", "hy_AM.UTF-8"},
263   {"hayeren", "hy_AM.UTF-8"},
264   {"assamese", "as_IN.UTF-8"},
265   {"asturian", "ast_ES.UTF-8"},
266   {"azerbaijani", "az_AZ.UTF-8"},
267   {"bambara", "bm_ML.UTF-8"},
268   {"bengali", "bn_IN.UTF-8"},
269   {"bodo", "brx_IN.UTF-8"},
270   {"bosnian", "bs_BA.UTF-8"},
271   {"croatian", "hr_HR.UTF-8"},
272   {"hrvatski", "hr_HR.UTF-8"},
273   {"catalan", "ca_ES.UTF-8"},
274   {"catala", "ca_ES.UTF-8"},
275   {"valencian", "ca_ES.UTF-8@valencia"},
276   {"valencia", "ca_ES.UTF-8@valencia"},
277   {"kiga", "cgg_UG.UTF-8"},
278   {"chiga", "cgg_UG.UTF-8"},
279   {"belarusian", "be_BY.UTF-8"},
280   {"bielaruskaja", "be_BY.UTF-8"},
281   {"czech", "cs_CZ.UTF-8"},
282   {"cesky", "cs_CZ.UTF-8"},
283   {"danish", "da_DK.UTF-8"},
284   {"dansk", "da_DK.UTF-8"},
285   {"dogri", "doi_IN.UTF-8"},
286   {"german", "de_DE.UTF-8"},
287   {"deutsch", "de_DE.UTF-8"},
288   {"estonian", "et_EE.UTF-8"},
289   {"greek", "el_GR.UTF-8"},
290   {"gronings", "gos_NL.UTF-8"},
291   {"zudelk-veenkelonioals", "gos_NL.UTF-8"},
292   {"gujarati", "gu_IN.UTF-8"},
293   {"british-english", "en_GB.UTF-8"},
294   {"british", "en_GB.UTF-8"},
295   {"australian-english", "en_AU.UTF-8"},
296   {"canadian-english", "en_CA.UTF-8"},
297   {"southafrican-english", "en_ZA.UTF-8"},
298   {"esperanto", "eo.UTF-8"},
299   {"spanish", "es_ES.UTF-8"},
300   {"mexican", "es_MX.UTF-8"},
301   {"mexican-spanish", "es_MX.UTF-8"},
302   {"espanol-mejicano", "es_MX.UTF-8"},
303   {"espanol", "es_ES.UTF-8"},
304   {"persian", "fa_IR.UTF-8"},
305   {"fula", "ff_SN.UTF-8"},
306   {"fulah", "ff_SN.UTF-8"},
307   {"pulaar-fulfulde", "ff_SN.UTF-8"},
308   {"finnish", "fi_FI.UTF-8"},
309   {"suomi", "fi_FI.UTF-8"},
310   {"faroese", "fo_FO.UTF-8"},
311   {"french", "fr_FR.UTF-8"},
312   {"francais", "fr_FR.UTF-8"},
313   {"gaelic", "ga_IE.UTF-8"},
314   {"irish-gaelic", "ga_IE.UTF-8"},
315   {"gaidhlig", "ga_IE.UTF-8"},
316   {"scottish", "gd_GB.UTF-8"},
317   {"ghaidhlig", "gd_GB.UTF-8"},
318   {"scottish-gaelic", "gd_GB.UTF-8"},
319   {"galician", "gl_ES.UTF-8"},
320   {"galego", "gl_ES.UTF-8"},
321   {"hebrew", "he_IL.UTF-8"},
322   {"hindi", "hi_IN.UTF-8"},
323   {"hungarian", "hu_HU.UTF-8"},
324   {"magyar", "hu_HU.UTF-8"},
325   {"indonesian", "id_ID.UTF-8"},
326   {"bahasa-indonesia", "id_ID.UTF-8"},
327   {"icelandic", "is_IS.UTF-8"},
328   {"islenska", "is_IS.UTF-8"},
329   {"italian", "it_IT.UTF-8"},
330   {"italiano", "it_IT.UTF-8"},
331   {"inuktitut", "iu_CA.UTF-8"},
332   {"japanese", "ja_JP.UTF-8"},
333   {"venda", "ve_ZA.UTF-8"},
334   {"venetian", "vec.UTF-8"},
335   {"veneto", "vec.UTF-8"},
336   {"vietnamese", "vi_VN.UTF-8"},
337   {"afrikaans", "af_ZA.UTF-8"},
338   {"albanian", "sq_AL.UTF-8"},
339   {"breton", "br_FR.UTF-8"},
340   {"brezhoneg", "br_FR.UTF-8"},
341   {"bulgarian", "bg_BG.UTF-8"},
342   {"welsh", "cy_GB.UTF-8"},
343   {"cymraeg", "cy_GB.UTF-8"},
344   {"bokmal", "nb_NO.UTF-8"},
345   {"basque", "eu_ES.UTF-8"},
346   {"euskara", "eu_ES.UTF-8"},
347   {"georgian", "ka_GE"},
348   {"kabyle", "kab"},
349   {"kabylian", "kab"},
350   {"kinyarwanda", "rw_RW.UTF-8"},
351   {"klingon", "tlh.UTF-8"},
352   {"tlhIngan", "tlh.UTF-8"},
353   {"kannada", "kn_IN.UTF-8"},
354   {"korean", "ko_KR.UTF-8"},
355   {"kashmiri-devanagari", "ks_IN.UTF-8@devanagari"},
356   {"kashmiri-perso-arabic", "ks_IN.UTF-8"},
357   {"kurdish", "ku_TR.UTF-8"},
358   {"tamil", "ta_IN.UTF-8"},
359   {"telugu", "te_IN.UTF-8"},
360   {"lithuanian", "lt_LT.UTF-8"},
361   {"lietuviu", "lt_LT.UTF-8"},
362   {"latvian", "lv_LV.UTF-8"},
363   {"luganda", "lg_UG.UTF-8"},
364   {"luxembourgish", "lb_LU.UTF-8"},
365   {"letzebuergesch", "lb_LU.UTF-8"},
366   {"konkani-devanagari", "kok_IN.UTF-8"},
367   {"konkani-roman", "kok@roman"},
368   {"maithili", "mai_IN.UTF-8"},
369   {"macedonian", "mk_MK.UTF-8"},
370   {"mongolian", "mn_MN.UTF-8"},
371   {"manipuri-bengali", "mni_IN.UTF-8"},
372   {"manipuri-meitei-mayek", "mni@meiteimayek"},
373   {"marathi", "mr_IN.UTF-8"},
374   {"malay", "ms_MY.UTF-8"},
375   {"nepali", "ne_NP.UTF-8"},
376   {"dutch", "nl_NL.UTF-8"},
377   {"nederlands", "nl_NL.UTF-8"},
378   {"norwegian", "nn_NO.UTF-8"},
379   {"nynorsk", "nn_NO.UTF-8"},
380   {"norsk", "nn_NO.UTF-8"},
381   {"ndebele", "nr_ZA.UTF-8"},
382   {"northern-sotho", "nso_ZA.UTF-8"},
383   {"sesotho-sa-leboa", "nso_ZA.UTF-8"},
384   {"occitan", "oc_FR.UTF-8"},
385   {"odia", "or_IN.UTF-8"},      // Proper spelling
386   {"oriya", "or_IN.UTF-8"},     // Alternative
387   {"ojibwe", "oj_CA.UTF-8"},    // Proper spelling
388   {"ojibway", "oj_CA.UTF-8"},   // For compatibility
389   {"punjabi", "pa_IN.UTF-8"},
390   {"panjabi", "pa_IN.UTF-8"},
391   {"polish", "pl_PL.UTF-8"},
392   {"polski", "pl_PL.UTF-8"},
393   {"brazilian-portuguese", "pt_BR.UTF-8"},
394   {"portugues-brazilian", "pt_BR.UTF-8"},
395   {"brazilian", "pt_BR.UTF-8"},
396   {"portuguese", "pt_PT.UTF-8"},
397   {"portugues", "pt_PT.UTF-8"},
398   {"romanian", "ro_RO.UTF-8"},
399   {"russian", "ru_RU.UTF-8"},
400   {"russkiy", "ru_RU.UTF-8"},
401   {"sanskrit", "sa_IN.UTF-8"},
402   {"santali-devanagari", "sat_IN.UTF-8"},
403   {"santali-ol-chiki", "sat@olchiki"},
404   {"sardinian", "sc_IT"},
405   {"sardu", "sc_IT"},
406   {"serbian", "sr_RS.UTF-8"},   /* Was sr_YU, but that's not in /usr/share/i18n/SUPPORTED, and sr_RS is -bjk 2014.08.04 */
407   {"serbian-latin", "sr_RS@latin"},
408   {"shuswap", "shs_CA.UTF-8"},
409   {"secwepemctin", "shs_CA.UTF-8"},
410   {"sindhi-perso-arabic", "sd_IN.UTF-8"},
411   {"sindhi-devanagari", "sd_IN.UTF-8@devanagari"},
412   {"sinhala", "si_LK.UTF-8"},
413   {"slovak", "sk_SK.UTF-8"},
414   {"slovenian", "sl_SI.UTF-8"},
415   {"slovensko", "sl_SI.UTF-8"},
416   {"songhay", "son.UTF-8"},
417   {"sundanese", "su_ID.UTF-8"},
418   {"swedish", "sv_SE.UTF-8"},
419   {"svenska", "sv_SE.UTF-8"},
420   {"swahili", "sw_TZ.UTF-8"},
421   {"tagalog", "tl_PH.UTF-8"},
422   {"thai", "th_TH.UTF-8"},
423   {"tibetan", "bo_CN.UTF-8"},   /* Based on: http://texinfo.org/pipermail/texinfo-pretest/2005-April/000334.html */
424   {"turkish", "tr_TR.UTF-8"},
425   {"twi", "tw_GH.UTF-8"},
426   {"ukrainian", "uk_UA.UTF-8"},
427   {"urdu", "ur_IN.UTF-8"},
428   {"walloon", "wa_BE.UTF-8"},
429   {"walon", "wa_BE.UTF-8"},
430   {"wolof", "wo_SN.UTF-8"},
431   {"xhosa", "xh_ZA.UTF-8"},
432   {"chinese", "zh_CN.UTF-8"},
433   {"simplified-chinese", "zh_CN.UTF-8"},
434   {"traditional-chinese", "zh_TW.UTF-8"},
435   {"zapotec", "zam.UTF-8"},
436   {"miahuatlan-zapotec", "zam.UTF-8"},
437   {"khmer", "km_KH.UTF-8"},
438   {"malayalam", "ml_IN.UTF-8"},
439   {"zulu", "zu_ZA.UTF-8"}
440 };
441 
442 
443 /**
444  * Show available languages
445  *
446  * @param exitcode Exit code; also determines whether STDERR or STDOUT used.
447  *   (e.g., is this output of "--lang help" (STDOUT & exit 0),
448  *   or complaint of an inappropriate "--lang" argument (STDERR & exit 1)?)
449  */
show_lang_usage(int exitcode)450 static void show_lang_usage(int exitcode)
451 {
452   FILE *f = exitcode ? stderr : stdout;
453   const char *const prg = "tuxpaint";
454 
455   /* FIXME: All this should REALLY be array-based!!! */
456   fprintf(f, "\n" "Usage: %s [--lang LANGUAGE]\n" "\n" "LANGUAGE may be one of:\n"
457 /* C */ "  english      american-english\n"
458 /* ach */ "  acholi       acoli\n"
459 /* af */ "  afrikaans\n"
460 /* ak */ "  akan         twi-fante\n"
461 /* sq */ "  albanian\n"
462 /* am */ "  amharic\n"
463 /* ar */ "  arabic\n"
464 /* an */ "  aragones\n"
465 /* hy */ "  armenian     hayeren\n"
466 /* as */ "  assamese\n"
467 /* ast */ "  asturian\n"
468 /* en_AU */ "  australian-english\n"
469 /* az */ "  azerbaijani\n"
470 /* bm */ "  bambara\n"
471 /* eu */ "  basque       euskara\n"
472 /* be */ "  belarusian   bielaruskaja\n"
473 /* bn */ "  bengali\n"
474 /* brx */ "  bodo\n"
475 /* nb */ "  bokmal\n"
476 /* bs */ "  bosnian\n"
477 /* pt_BR */ "  brazilian    brazilian-portuguese   portugues-brazilian\n"
478 /* br */ "  breton       brezhoneg\n"
479 /* en_GB */ "  british      british-english\n"
480 /* bg_BG */ "  bulgarian\n"
481 /* en_CA */ "  canadian-english\n"
482 /* ca */ "  catalan      catala\n"
483 /* zh_CN */ "  chinese      simplified-chinese\n"
484 /* zh_TW */ "               traditional-chinese\n"
485 /* hr */ "  croatian     hrvatski\n"
486 /* cs */ "  czech        cesky\n"
487 /* da */ "  danish       dansk\n"
488 /* doi */ "  dogri\n"
489 /* nl */ "  dutch        nederlands\n"
490 /* eo */ "  esperanto\n"
491 /* et */ "  estonian\n"
492 /* fo */ "  faroese\n"
493 /* fi */ "  finnish      suomi\n"
494 /* fr */ "  french       francais\n"
495 /* ff */ "  fula         fulah                  pulaar-fulfulde\n"
496 /* ga */ "  gaelic       irish-gaelic           gaidhlig\n"
497 /* gl */ "  galician     galego\n"
498 /* ka */ "  georgian\n"
499 /* de */ "  german       deutsch\n"
500 /* el */ "  greek\n"
501 /* gos */ "  gronings     zudelk-veenkelonioals\n"
502 /* gu */ "  gujarati\n"
503 /* he */ "  hebrew\n"
504 /* hi */ "  hindi\n"
505 /* hu */ "  hungarian    magyar\n"
506 /* is */ "  icelandic    islenska\n"
507 /* id */ "  indonesian   bahasa-indonesia\n"
508 /* iu */ "  inuktitut\n"
509 /* it */ "  italian      italiano\n"
510 /* ja */ "  japanese\n"
511 /* kab */ "  kabyle       kabylian\n"
512 /* kn */ "  kannada\n"
513 /* ks@devanagari */ "  kashmiri-devanagari\n"
514 /* ks */ "  kashmiri-perso-arabic\n"
515 /* km */ "  khmer\n"
516 /* cgg */ "  kiga         chiga\n"
517 /* rw */ "  kinyarwanda\n"
518 /* tlh */ "  klingon      tlhIngan\n"
519 /* kok */ "  konkani-devanagari\n"
520 /* kok@roman */ "  konkani-roman\n"
521 /* ko */ "  korean\n"
522 /* ku */ "  kurdish\n"
523 /* lv */ "  latvian\n"
524 /* lt */ "  lithuanian   lietuviu\n"
525 /* lg */ "  luganda\n"
526 /* lb */ "  luxembourgish letzebuergesch\n"
527 /* mai */ "  maithili\n"
528 /* mk */ "  macedonian\n"
529 /* ms */ "  malay\n"
530 /* ml */ "  malayalam\n"
531 /* mni */ "  manipuri-bengali\n"
532 /* mni@meiteimayek */ "  manipuri-meitei-mayek\n"
533 /* nr */ "  marathi\n"
534 /* es_MX */ "  mexican      mexican-spanish        espanol-mejicano\n"
535 /* mn */ "  mongolian\n"
536 /* nr */ "  ndebele\n"
537 /* ne */ "  nepali\n"
538 /* nso */ "  northern-sotho                      sesotho-sa-leboa\n"
539 /* nn */ "  norwegian    nynorsk                norsk\n"
540 /* oc */ "  occitan\n"
541 /* or */ "  odia         oriya\n"
542 /* oj */ "  ojibwe       ojibway\n"
543 /* fa */ "  persian\n"
544 /* pl */ "  polish       polski\n"
545 /* pt */ "  portuguese   portugues\n"
546 /* pa */ "  punjabi      panjabi\n"
547 /* ro */ "  romanian\n"
548 /* ru */ "  russian      russkiy\n"
549 /* sa */ "  sanskrit\n"
550 /* sat */ "  santali-devanagari\n"
551 /* sat@olchiki */ "  santali-ol-chiki\n"
552 /* sc */ "  sardinian    sardu\n"
553 /* gd */ "  scottish     scottish-gaelic        ghaidhlig\n"
554 /* sr */ "  serbian\n"
555 /* sr@latin */ "  serbian-latin\n"
556 /* shs*/ "  shuswap      secwepemctin\n"
557 /* sd@devanagari */ "  sindhi-devanagari\n"
558 /* sd */ "  sindhi-perso-arabic\n"
559 /* si */ "  sinhala\n"
560 /* sk */ "  slovak\n"
561 /* sl */ "  slovenian    slovensko\n"
562 /* en_ZA */ "  southafrican-english\n"
563 /* son */ "  songhay\n"
564 /* es */ "  spanish      espanol\n"
565 /* su */ "  sundanese\n"
566 /* sw */ "  swahili\n"
567 /* sv */ "  swedish      svenska\n"
568 /* tl */ "  tagalog\n"
569 /* ta */ "  tamil\n"
570 /* te */ "  telugu\n"
571 /* th */ "  thai\n"
572 /* twi */ "  twi\n"
573 /* bo */ "  tibetan\n"
574 /* tr */ "  turkish\n"
575 /* uk */ "  ukrainian\n"
576 /* ur */ "  urdu\n"
577 /* ca@valencia */ "  valencian    valencia\n"
578 /* ve */ "  venda\n"
579 /* vec */ "  venetian     veneto\n"
580 /* vi */ "  vietnamese\n"
581 /* wa */ "  walloon      walon\n"
582 /* wo */ "  wolof\n"
583 /* cy */ "  welsh        cymraeg\n"
584 /* xh */ "  xhosa\n"
585 /* zam */ "  zapotec      miahuatlan-zapotec\n"
586 /* zu */ "  zulu\n"
587           "\n", prg);
588   exit(exitcode);
589 }
590 
591 
592 /**
593  * Show available locales as a "usage" output
594  *
595  * @param f File descriptor to write to (e.g., STDOUT or STDERR)
596  * @param prg Program name (e.g., "tuxpaint" or "tuxpaint.exe")
597  */
show_locale_usage(FILE * f,const char * const prg)598 static void show_locale_usage(FILE * f, const char *const prg)
599 {
600   /* FIXME: Add accented characters to the descriptions */
601   fprintf(f,
602           "\n"
603           "Usage: %s [--locale LOCALE]\n"
604           "\n"
605           "LOCALE may be one of:\n"
606           "  C       (English      American English)\n"
607           "  ach_UG  (Acholi       Acoli)\n"
608           "  af_ZA   (Afrikaans)\n"
609           "  ak_GH   (Akan         Twi-Fante)\n"
610           "  am_ET   (Amharic)\n"
611           "  ar_SA   (Arabic)\n"
612           "  an_ES   (Aragones)\n"
613           "  hy_AM   (Armenian)\n"
614           "  as_IN   (Assamese)\n"
615           "  ast_ES  (Asturian)\n"
616           "  az_AZ   (Azerbaijani)\n"
617           "  bm_ML   (Bambara)\n"
618           "  eu_ES   (Basque       Euskara)\n"
619           "  be_BY   (Belarusian   Bielaruskaja)\n"
620           "  bn_IN   (Bengali)\n"
621           "  brx_IN  (Bodo)\n"
622           "  bs_BA   (Bosnian)\n"
623           "  nb_NO   (Bokmal)\n"
624           "  pt_BR   (Brazilian    Brazilian Portuguese   Portugues Brazilian)\n"
625           "  br_FR   (Breton       Brezhoneg)\n"
626           "  en_AU   (Australian English)\n"
627           "  en_CA   (Canadian English)\n"
628           "  en_GB   (British      British English)\n"
629           "  en_ZA   (South African English)\n"
630           "  bg_BG   (Bulgarian)\n"
631           "  ca_ES   (Catalan      Catala)\n"
632           "  ca_ES@valencia   (Valencian    Valencia)n"
633           "  zh_CN   (Chinese-Simplified)\n"
634           "  zh_TW   (Chinese-Traditional)\n"
635           "  cs_CZ   (Czech        Cesky)\n"
636           "  da_DK   (Danish       Dansk)\n"
637           "  doi_IN   (Dogri)\n"
638           "  nl_NL   (Dutch)\n"
639           "  fa_IR   (Persian)\n"
640           "  ff_SN   (Fulah)\n"
641           "  fi_FI   (Finnish      Suomi)\n"
642           "  fo_FO   (Faroese)\n"
643           "  fr_FR   (French       Francais)\n"
644           "  ga_IE   (Irish Gaelic Gaidhlig)\n"
645           "  gd_GB   (Scottish Gaelic  Ghaidhlig)\n"
646           "  gl_ES   (Galician     Galego)\n"
647           "  gos_NL  (Gronings     Zudelk Veenkelonioals)\n"
648           "  gu_IN   (Gujarati)\n"
649           "  de_DE   (German       Deutsch)\n"
650           "  eo      (Esperanto)\n"
651           "  et_EE   (Estonian)\n"
652           "  el_GR   (Greek)\n"
653           "  he_IL   (Hebrew)\n"
654           "  hi_IN   (Hindi)\n"
655           "  hr_HR   (Croatian     Hrvatski)\n"
656           "  hu_HU   (Hungarian    Magyar)\n"
657           "  cgg_UG  (Kiga         Chiga)\n"
658           "  tlh     (Klingon      tlhIngan)\n"
659           "  is_IS   (Icelandic    Islenska)\n"
660           "  id_ID   (Indonesian   Bahasa Indonesia)\n"
661           "  it_IT   (Italian      Italiano)\n"
662           "  iu_CA   (Inuktitut)\n"
663           "  ja_JP   (Japanese)\n"
664           "  ka_GE   (Georgian)\n"
665           "  kn_IN   (Kannada)\n"
666           "  km_KH   (Khmer)\n"
667           "  ko_KR   (Korean)\n"
668           "  ks_IN@devanagari   (Kashmiri (Devanagari))\n"
669           "  ks_IN   (Kashmiri (Perso-Arabic))\n"
670           "  ku_TR   (Kurdish)\n"
671           "  ms_MY   (Malay)\n"
672           "  ml_IN   (Malayalam)\n"
673           "  lg_UG   (Luganda)\n"
674           "  lb_LU   (Luxembourgish Letzebuergesch)\n"
675           "  lv_LV   (Latvian)\n"
676           "  lt_LT   (Lithuanian   Lietuviu)\n"
677           "  kok_IN  (Konkani (Devanagari))\n"
678           "  kok@roman  (Konkani (Roman))\n"
679           "  mai_IN  (Maithili)\n"
680           "  mk_MK   (Macedonian)\n"
681           "  mni_IN  (Manipuri (Bengali))\n"
682           "  mni@meiteimayek (Manipuri(Meitei Mayek))\n"
683           "  mn_MN   (Mongolian)\n"
684           "  mr_IN   (Marathi)\n"
685           "  nr_ZA   (Ndebele)\n"
686           "  ne_NP   (Nepali)\n"
687           "  nso_ZA  (Northern Sotho                      Sotho sa Leboa)\n"
688           "  nn_NO   (Norwegian    Nynorsk                Norsk)\n"
689           "  oc_FR   (Occitan)\n"
690           "  oj_CA   (Ojibway)\n"
691           "  or_IN   (Odia         Oriya)\n"
692           "  pa_IN   (Punjabi      Panjabi)\n"
693           "  pl_PL   (Polish       Polski)\n"
694           "  pt_PT   (Portuguese   Portugues)\n"
695           "  ro_RO   (Romanian)\n"
696           "  ru_RU   (Russian      Russkiy)\n"
697           "  rw_RW   (Kinyarwanda)\n"
698           "  sa_IN   (Sanskrit)\n"
699           "  sat_IN  (Santali)\n"
700           "  sat@olchiki  (Santali (Ol-Chiki))\n"
701           "  sc_IT   (Sardinian)\n"
702           "  sd_IN@devanagari  (Sindhi (Devanagari))\n"
703           "  sd_IN  (Sindhii (Perso-Arabic))\n"
704           "  shs_CA  (Shuswap      Secwepemctin)\n"
705           "  si_LK   (Sinhala)\n"
706           "  sk_SK   (Slovak)\n"
707           "  sl_SI   (Slovenian)\n"
708           "  son     (Songhay)\n"
709           "  sq_AL   (Albanian)\n"
710           "  sr_YU   (Serbian (cyrillic))\n"
711           "  sr_RS@latin  (Serbian (latin))\n"
712           "  es_ES   (Spanish      Espanol)\n"
713           "  su_ID   (Sundanese)\n"
714           "  es_MX   (Mexican      Mexican Spanish       Espanol Mejicano)\n"
715           "  sw_TZ   (Swahili)\n"
716           "  sv_SE   (Swedish      Svenska)\n"
717           "  ta_IN   (Tamil)\n"
718           "  te_IN   (Telugu)\n"
719           "  tl_PH   (Tagalog)\n"
720           "  bo_CN   (Tibetan)\n"
721           "  th_TH   (Thai)\n"
722           "  tr_TR   (Turkish)\n"
723           "  tw_GH  (Twi)\n"
724           "  uk_UA   (Ukrainian)\n"
725           "  ur_IN   (Urdu)\n"
726           "  ve_ZA   (Venda)\n"
727           "  vec     (Venetian)\n"
728           "  vi_VN   (Vietnamese)\n"
729           "  wa_BE   (Walloon)\n"
730           "  wo_SN   (Wolof)\n"
731           "  cy_GB   (Welsh        Cymraeg)\n"
732           "  xh_ZA   (Xhosa)\n" "  zam     (Zapoteco-Miahuatlan)\n" "  zu_ZA   (Zulu)\n" "\n", prg);
733 }
734 
735 /**
736  * Return the current language
737  *
738  * @return The current language (one of the LANG_xxx enums)
739  */
get_current_language(void)740 int get_current_language(void)
741 {
742   return langint;
743 }
744 
745 /**
746  * Search an array of ints for a given int
747  *
748  * @param l The int to search for
749  * @param array The array of ints to search, terminated by -1
750  * @return 1 if "l" is found in "array", 0 otherwise
751  */
search_int_array(int l,int * array)752 static int search_int_array(int l, int *array)
753 {
754   int i;
755 
756   for (i = 0; array[i] != -1; i++)
757     {
758       if (array[i] == l)
759         return 1;
760     }
761 
762   return 0;
763 }
764 
765 /**
766  * Ensures that iswprint() works beyond ASCII,
767  * even if the locale wouldn't normally support that.
768  * Tries fallback locales until one works.
769  * Emits an error message to STDERR if none work.
770  */
ctype_utf8(void)771 static void ctype_utf8(void)
772 {
773 #ifndef _WIN32
774   /* FIXME: should this iterate over more locales?
775      A zapotec speaker may have es_MX.UTF-8 available but not have en_US.UTF-8 for example */
776   const char *names[] = { "en_US.UTF8", "en_US.UTF-8", "UTF8", "UTF-8", "C.UTF-8" };
777   int i = sizeof(names) / sizeof(names[0]);
778 
779   for (;;)
780     {
781       if (iswprint((wchar_t) 0xf7))     // division symbol -- which is in Latin-1 :-/
782         return;
783       if (--i < 0)
784         break;
785       setlocale(LC_CTYPE, names[i]);
786       setlocale(LC_MESSAGES, names[i]);
787     }
788   fprintf(stderr, "Failed to find a locale with iswprint() working!\n");
789 #endif
790 }
791 
792 /**
793  * For a given language, return its local, or exit with a usage error.
794  *
795  * @param langstr Name of language (e.g., "german")
796  * @return Locale (e.g., "de_DE.UTF-8")
797  */
language_to_locale(const char * langstr)798 static const char *language_to_locale(const char *langstr)
799 {
800   int i = sizeof language_to_locale_array / sizeof language_to_locale_array[0];
801 
802   while (i--)
803     {
804       if (!strcmp(langstr, language_to_locale_array[i].language))
805         return language_to_locale_array[i].locale;
806     }
807   if (strcmp(langstr, "help") == 0 || strcmp(langstr, "list") == 0)
808     show_lang_usage(0);
809   fprintf(stderr, "%s is an invalid language\n", langstr);
810   show_lang_usage(59);
811   return NULL;
812 }
813 
814 /**
815  * Set language ("langint" global) based on a given locale;
816  * will try a few ways of checking, is case-insensitive, etc.
817  *
818  * @param loc Locale (e.g., "pt_BR.UTF-8", "pt_BR", "pt_br", etc.)
819  */
set_langint_from_locale_string(const char * restrict loc)820 static void set_langint_from_locale_string(const char *restrict loc)
821 {
822   char *baseloc = strdup(loc);
823   char *dot = strchr(baseloc, '.');
824   char *at = strchr(baseloc, '@');
825   char *cntrycode = strchr(baseloc, '_');
826   char straux[255];
827   char *ataux = NULL;
828   char *ccodeaux = NULL;
829   size_t len_baseloc;
830   int found = 0;
831   int i;
832 
833   //  printf("langint %i\n", langint);
834 
835   if (!loc)
836     return;
837 
838   /* Remove the .UTF-8 extension, then
839      try to find the full locale including country code and variant,
840      if it fails, then try to find the language code plus the variant,
841      if it still fails, try to find language and country code without the variant,
842      finally scan just the lang part.
843      as a last resource reverse the scanning
844    */
845 
846   if (dot)
847     *dot = '\0';
848 
849   if (cntrycode)
850     {
851       ccodeaux = strdup(cntrycode);
852       *cntrycode = '\0';
853     }
854 
855   if (at)
856     {
857       ataux = strdup(at);
858       *at = '\0';
859 
860       if (cntrycode)
861         {
862           /* ll_CC@variant */
863           //if (found == 0)  printf("ll_CC@variant check\n");
864           snprintf(straux, 255, "%s%s%s", baseloc, ccodeaux, ataux);
865           len_baseloc = strlen(straux);
866           for (i = 0; i < NUM_LANGS && found == 0; i++)
867             {
868               // Case-insensitive (both "pt_BR" and "pt_br" work, etc.)
869               if (len_baseloc == strlen(lang_prefixes[i]) && !strncasecmp(straux, lang_prefixes[i], len_baseloc))
870                 {
871                   langint = i;
872                   found = 1;
873                 }
874             }
875         }
876 
877       /* ll@variant */
878       //if (found == 0)  printf("ll@variant check\n");
879       snprintf(straux, 255, "%s%s", baseloc, ataux);
880       len_baseloc = strlen(straux);
881       for (i = 0; i < NUM_LANGS && found == 0; i++)
882         {
883           // Case-insensitive (both "pt_BR" and "pt_br" work, etc.)
884           if (len_baseloc == strlen(lang_prefixes[i]) && !strncasecmp(straux, lang_prefixes[i], len_baseloc))
885             {
886               langint = i;
887               found = 1;
888             }
889         }
890     }
891 
892   if (cntrycode)
893     {
894       /* ll_CC */
895       //if (found == 0)  printf("ll_CC check\n");
896       snprintf(straux, 255, "%s%s", baseloc, ccodeaux);
897       len_baseloc = strlen(straux);
898 
899       /* Which, if any, of the locales is it? */
900 
901       for (i = 0; i < NUM_LANGS && found == 0; i++)
902         {
903           // Case-insensitive (both "pt_BR" and "pt_br" work, etc.)
904           if (len_baseloc == strlen(lang_prefixes[i]) &&
905               !strncasecmp(straux, lang_prefixes[i], strlen(lang_prefixes[i])))
906             {
907               langint = i;
908               found = 1;
909             }
910         }
911     }
912 
913   /* ll */
914   //  if (found == 0)  printf("ll check\n");
915   len_baseloc = strlen(baseloc);
916   /* Which, if any, of the locales is it? */
917 
918   for (i = 0; i < NUM_LANGS && found == 0; i++)
919     {
920       // Case-insensitive (both "pt_BR" and "pt_br" work, etc.)
921       if (len_baseloc == strlen(lang_prefixes[i]) && !strncasecmp(baseloc, lang_prefixes[i], strlen(lang_prefixes[i])))
922         {
923           langint = i;
924           found = 1;
925         }
926     }
927 
928   /* Last resort, we should never arrive here, this check depends
929      on the right order in lang_prefixes[]
930      Languages sharing the same starting letters must be ordered
931      from longest to shortest, like currently are pt_BR and pt */
932 // if (found == 0)
933   // printf("Language still not found: loc= %s  Trying reverse check as last resource...\n", loc);
934 
935   for (i = 0; i < NUM_LANGS && found == 0; i++)
936     {
937       // Case-insensitive (both "pt_BR" and "pt_br" work, etc.)
938       if (!strncasecmp(loc, lang_prefixes[i], strlen(lang_prefixes[i])))
939         {
940           langint = i;
941           found = 1;
942         }
943     }
944   //  printf("langint %i, lang_ext %s\n", langint, lang_prefixes[langint]);
945 
946   free(baseloc);
947   if (ataux)
948     free(ataux);
949   if (ccodeaux)
950     free(ccodeaux);
951 }
952 
953 #define HAVE_SETENV
954 #ifdef WIN32
955 #undef HAVE_SETENV
956 #endif
957 
958 
959 /**
960  * Set an environment variable.
961  * (Wrapper for setenv() or putenv(), depending on OS)
962  *
963  * @param name Variable to set
964  * @param value Value to set the variable to
965  */
mysetenv(const char * name,const char * value)966 static void mysetenv(const char *name, const char *value)
967 {
968 #ifdef HAVE_SETENV
969   setenv(name, value, 1);
970 #else
971   int len = strlen(name) + 1 + strlen(value) + 1;
972   char *str = malloc(len);
973 
974   sprintf(str, "%s=%s", name, value);
975   putenv(str);
976 #endif
977 }
978 
979 
980 /**
981  * Attempt to set Tux Paint's UI language.
982  *
983  * @param loc Locale
984  * @return The Y-nudge value for font rendering in the language.
985  */
986 
set_current_language(const char * restrict loc,int * ptr_num_wished_langs)987 static int set_current_language(const char *restrict loc, int * ptr_num_wished_langs)
988 {
989   int i;
990   int j = 0;
991   char *oldloc;
992   char *env_language;
993   char *env_language_lang;
994   char *env;
995   int num_wished_langs = 0;
996 
997   *ptr_num_wished_langs = 0;
998 
999   if (strlen(loc) > 0)
1000     {
1001       /* Got command line or config file language */
1002       DEBUG_PRINTF("Language via config: %s\n", loc);
1003       mysetenv("LANGUAGE", loc);
1004     }
1005   else
1006     {
1007       DEBUG_PRINTF("Language NOT set via config\n");
1008 
1009       /* Find what language to use from env vars */
1010       env = getenv("LANGUAGE");
1011       if (env == NULL || env[0] == '\0')
1012         {
1013 	  env = getenv("LC_ALL");
1014           if (env != NULL && env[0] != '\0')
1015 	    {
1016               DEBUG_PRINTF("Language via LC_ALL: %s\n", getenv("LC_ALL"));
1017               mysetenv("LANGUAGE", getenv("LC_ALL"));
1018 	    }
1019           else
1020             {
1021 	      env = getenv("LC_MESSAGES");
1022               if (env != NULL && env[0] != '\0')
1023 	        {
1024                   DEBUG_PRINTF("Language via LC_MESSAGES: %s\n", getenv("LC_MESSAGES"));
1025                   mysetenv("LANGUAGE", getenv("LC_MESSAGES"));
1026 	        }
1027 	      else
1028 	        {
1029 	          env = getenv("LANG");
1030                   if (env != NULL && env[0] != '\0')
1031         	    {
1032                       DEBUG_PRINTF("Language via LANG: %s\n", getenv("LANG"));
1033                       mysetenv("LANGUAGE", getenv("LANG"));
1034         	    }
1035 		  else
1036 	            {
1037                       DEBUG_PRINTF("No language set!\n");
1038 	            }
1039 		}
1040 	    }
1041         }
1042       else
1043         {
1044           DEBUG_PRINTF("Language was set to '%s'\n", getenv("LANGUAGE"));
1045 	}
1046     }
1047 
1048   oldloc = strdup(loc);
1049 
1050   /* First set the locale according to the environment, then try to overwrite with loc,
1051      after that, ctype_utf8() call will test the compatibility with utf8 and try to load
1052      a different locale if the resulting one is not compatible. */
1053   DEBUG_PRINTF("Locale BEFORE is: %s\n", setlocale(LC_ALL, NULL));    //EP
1054 
1055   setlocale(LC_ALL, "");
1056   setlocale(LC_ALL, loc);
1057   ctype_utf8();
1058 
1059   DEBUG_PRINTF("Locale AFTER is: %s\n", setlocale(LC_ALL, NULL));     //EP
1060 
1061   bindtextdomain("tuxpaint", LOCALEDIR);
1062   /* Old version of glibc does not have bind_textdomain_codeset() */
1063 #if defined(_WIN32) || (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 2) || __GLIBC__ > 2 || defined(__NetBSD__) || __APPLE__
1064   bind_textdomain_codeset("tuxpaint", "UTF-8");
1065 #endif
1066   textdomain("tuxpaint");
1067 
1068 #ifdef _WIN32
1069   if (!*loc)
1070     loc = _nl_locale_name(LC_MESSAGES, "");
1071 #else
1072   // NULL: Used to direct setlocale() to query the current
1073   // internationalised environment and return the name of the locale().
1074   loc = setlocale(LC_MESSAGES, NULL);
1075 #endif
1076 
1077   if (strcmp(oldloc, "") != 0 && strcmp(loc, oldloc) != 0)
1078     {
1079       /* System doesn't recognize that locale!  Hack, per Albert C., is to set LC_ALL to a valid UTF-8 locale, then set LANGUAGE to the locale we want to force -bjk 2010.10.05 */
1080 
1081       /* Albert's comments from December 2009:
1082          gettext() won't even bother to look up messages unless it
1083          is totally satisfied that you are using one of the locales that
1084          it ships with! Make gettext() unhappy, and it'll switch to the
1085          lobotomized 7-bit Linux "C" locale just to spite you.
1086 
1087          http://sources.redhat.com/cgi-bin/cvsweb.cgi/libc/localedata/SUPPORTED?content-type=text/x-cvsweb-markup&cvsroot=glibc
1088 
1089          You can confuse gettext() into mostly behaving. For example, a
1090          user could pick a random UTF-8 locale and change the messages.
1091          In that case, Tux Paint thinks it's in the other locale but the
1092          messages come out right. Like so: LANGUAGE=zam LC_ALL=fr_FR.UTF-8
1093          It doesn't work to leave LC_ALL unset, set it to "zam", set it to "C",
1094          or set it to random nonsense. Yeah, Tux Paint will think it's in
1095          a French locale, but the messages will be Zapotec nonetheless.
1096 
1097          Maybe it's time to give up on gettext().
1098 
1099          [see also: https://sourceforge.net/mailarchive/message.php?msg_name=787b0d920912222352i5ab22834x92686283b565016b%40mail.gmail.com ]
1100        */
1101 
1102       /* Unneeded here, this has yet been done as part of ctype_utf8() call before, iterating over a list of locales */
1103       //    setlocale(LC_ALL, "en_US.UTF-8"); /* Is it dumb to assume "en_US" is pretty close to "C" locale? */
1104 
1105       mysetenv("LANGUAGE", oldloc);
1106       set_langint_from_locale_string(oldloc);
1107     }
1108   else
1109     {
1110 #ifdef _WIN32
1111       if (getenv("LANGUAGE") == NULL)
1112         mysetenv("LANGUAGE", loc);
1113 #endif
1114 
1115       if (getenv("LANGUAGE") == NULL)
1116         mysetenv("LANGUAGE", "C");
1117     }
1118   env_language = strdup(getenv("LANGUAGE"));
1119 
1120   if (*env_language)
1121     {
1122       env_language_lang = strtok(env_language, ":");
1123       while (env_language_lang != NULL)
1124         {
1125           num_wished_langs++;
1126           set_langint_from_locale_string(env_language_lang);
1127           wished_langs[j].langint = langint;
1128           wished_langs[j].lang_prefix = lang_prefixes[langint];
1129           wished_langs[j].need_own_font = search_int_array(langint, lang_use_own_font);
1130           wished_langs[j].need_right_to_left = search_int_array(langint, lang_use_right_to_left);
1131           wished_langs[j].need_right_to_left_word = search_int_array(langint, lang_use_right_to_left_word);
1132           for (i = 0; lang_y_nudge[i][0] != -1; i++)
1133             {
1134               // printf("lang_y_nudge[%d][0] = %d\n", i, lang_y_nudge[i][0]);
1135               if (lang_y_nudge[i][0] == langint)
1136                 {
1137                   wished_langs[j].lang_y_nudge = lang_y_nudge[i][1];
1138                   break;
1139                 }
1140             }
1141 
1142 
1143           j++;
1144           env_language_lang = strtok(NULL, ":");
1145         }
1146       if (*env_language)
1147         free(env_language);
1148     }
1149   //    set_langint_from_locale_string(loc);
1150 
1151 
1152   lang_prefix = lang_prefixes[wished_langs[0].langint];
1153 
1154   short_lang_prefix = strdup(lang_prefix);
1155   /* When in doubt, cut off country code */
1156   if (strchr(short_lang_prefix, '_'))
1157     *strchr(short_lang_prefix, '_') = '\0';
1158 
1159   need_own_font = wished_langs[0].need_own_font;
1160   need_right_to_left = wished_langs[0].need_right_to_left;
1161   need_right_to_left_word = wished_langs[0].need_right_to_left_word;
1162 
1163 #ifdef DEBUG
1164   fprintf(stderr, "DEBUG: Language is %s (%d) %s/%s\n",
1165           lang_prefix, langint, need_right_to_left ? "(RTL)" : "", need_right_to_left_word ? "(RTL words)" : "");
1166   fflush(stderr);
1167 #endif
1168 
1169   free(oldloc);
1170 
1171   DEBUG_PRINTF("lang_prefixes[%d] is \"%s\"\n", get_current_language(), lang_prefixes[get_current_language()]);
1172 
1173   *ptr_num_wished_langs = num_wished_langs;
1174 
1175   return wished_langs[0].lang_y_nudge;
1176 }
1177 
1178 
1179 /**
1180  * Given a locale (e.g., "de_DE.UTF-8" or a language name (e.g., "german"),
1181  * attempt to set Tux Paint's UI language.  Show help, and exit,
1182  * if asked (either 'locale' or 'lang' are "help"), or if the
1183  * given input is not recognized.
1184  *
1185  * @param char * lang Language name (or NULL)
1186  * @param char * locale Locale (or NULL)
1187  * @param int * a place to return the number of languages we want to use, when scanning stamp descriptions
1188  * @return Y-nudge
1189  */
setup_i18n(const char * restrict lang,const char * restrict locale,int * num_wished_langs)1190 int setup_i18n(const char *restrict lang, const char *restrict locale, int * num_wished_langs)
1191 {
1192   DEBUG_PRINTF("lang %p, locale %p\n", lang, locale);
1193   DEBUG_PRINTF("lang \"%s\", locale \"%s\"\n", lang, locale);
1194 
1195   if (locale)
1196     {
1197       if (!strcmp(locale, "help"))
1198         {
1199           show_locale_usage(stdout, "tuxpaint");
1200           exit(0);
1201         }
1202     }
1203   else
1204     locale = "";
1205 
1206   if (lang)
1207     locale = language_to_locale(lang);
1208   return set_current_language(locale, num_wished_langs);
1209 }
1210 
1211 #ifdef NO_SDLPANGO
1212 /**
1213  * FIXME
1214  */
smash_i18n(void)1215 int smash_i18n(void)
1216 {
1217   int tmp;
1218   return set_current_language("C", &tmp);
1219 }
1220 #endif
1221