2 findlocale-0.46.tar.gz from http://icculus.org/~aspirin/findlocale/
4 Copyright (C) 2004 Adam D. Moss (the "Author"). All Rights Reserved.
6 Permission is hereby granted, free of charge, to any person obtaining a copy
7 of this software and associated documentation files (the "Software"), to deal
8 in the Software without restriction, including without limitation the rights
9 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 copies of the Software, and to permit persons to whom the Software is fur-
11 nished to do so, subject to the following conditions:
13 The above copyright notice and this permission notice shall be included in
14 all copies or substantial portions of the Software.
16 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FIT-
18 NESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 AUTHOR BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
20 IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CON-
21 NECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23 Except as contained in this notice, the name of the Author of the
24 Software shall not be used in advertising or otherwise to promote the sale,
25 use or other dealings in this Software without prior written authorization
39 #include "findlocale.hpp"
42 is_lcchar(const int c) {
47 lang_country_variant_from_envstring(const char *str,
54 /* get lang, if any */
56 while (is_lcchar(str[end])) {
61 int len = end - start;
62 char *s = (char*) malloc(len + 1);
63 for (i=0; i<len; ++i) {
64 s[i] = tolower(str[start + i]);
72 if (str[end] && str[end]!=':') { /* not at end of str */
76 /* get country, if any */
78 while (is_lcchar(str[end])) {
83 int len = end - start;
84 char *s = (char*) malloc(len + 1);
85 for (i=0; i<len; ++i) {
86 s[i] = toupper(str[start + i]);
94 if (str[end] && str[end]!=':') { /* not at end of str */
98 /* get variant, if any */
100 while (str[end] && str[end]!=':') {
105 int len = end - start;
106 char *s = (char*) malloc(len + 1);
107 for (i=0; i<len; ++i) {
108 s[i] = str[start + i];
119 accumulate_locstring(const char *str, FL_Locale *l) {
121 char *country = NULL;
122 char *variant = NULL;
124 lang_country_variant_from_envstring(str, &lang, &country, &variant);
127 l->country = country;
128 l->variant = variant;
132 free(lang); free(country); free(variant);
139 accumulate_env(const char *name, FL_Locale *l) {
142 char *country = NULL;
143 char *variant = NULL;
146 return accumulate_locstring(env, l);
148 free(lang); free(country); free(variant);
154 canonise_fl(FL_Locale *l) {
155 /* this function fixes some common locale-specifying mistakes */
157 if (l->lang && 0 == strcmp(l->lang, "en")) {
158 if (l->country && 0 == strcmp(l->country, "UK")) {
159 free((void*)l->country);
160 l->country = strdup("GB");
164 if (l->lang && 0 == strcmp(l->lang, "ja")) {
165 if (l->country && 0 == strcmp(l->country, "JA")) {
166 free((void*)l->country);
167 l->country = strdup("JP");
175 #define ML(pn,sn) MAKELANGID(LANG_##pn, SUBLANG_##pn##_##sn)
176 #define MLN(pn) MAKELANGID(LANG_##pn, SUBLANG_DEFAULT)
177 #define RML(pn,sn) MAKELANGID(LANG_##pn, SUBLANG_##sn)
182 static const IDToCode both_to_code[] = {
183 {ML(ENGLISH,US), "en_US.ISO_8859-1"},
184 {ML(ENGLISH,CAN), "en_CA"}, /* english / canadian */
185 {ML(ENGLISH,UK), "en_GB"},
186 {ML(ENGLISH,EIRE), "en_IE"},
187 {ML(ENGLISH,AUS), "en_AU"},
188 {MLN(GERMAN), "de_DE"},
189 {MLN(SPANISH), "es_ES"},
190 {ML(SPANISH,MEXICAN), "es_MX"},
191 {MLN(FRENCH), "fr_FR"},
192 {ML(FRENCH,CANADIAN), "fr_CA"},
193 {ML(FRENCH,BELGIAN), "fr_BE"}, /* ? */
194 {ML(DUTCH,BELGIAN), "nl_BE"}, /* ? */
195 {ML(PORTUGUESE,BRAZILIAN), "pt_BR"},
196 {MLN(PORTUGUESE), "pt_PT"},
197 {MLN(SWEDISH), "sv_SE"},
198 {ML(CHINESE,HONGKONG), "zh_HK"},
199 /* these are machine-generated and not yet verified */
200 {RML(AFRIKAANS,DEFAULT), "af_ZA"},
201 {RML(ALBANIAN,DEFAULT), "sq_AL"},
202 {RML(ARABIC,ARABIC_ALGERIA), "ar_DZ"},
203 {RML(ARABIC,ARABIC_BAHRAIN), "ar_BH"},
204 {RML(ARABIC,ARABIC_EGYPT), "ar_EG"},
205 {RML(ARABIC,ARABIC_IRAQ), "ar_IQ"},
206 {RML(ARABIC,ARABIC_JORDAN), "ar_JO"},
207 {RML(ARABIC,ARABIC_KUWAIT), "ar_KW"},
208 {RML(ARABIC,ARABIC_LEBANON), "ar_LB"},
209 {RML(ARABIC,ARABIC_LIBYA), "ar_LY"},
210 {RML(ARABIC,ARABIC_MOROCCO), "ar_MA"},
211 {RML(ARABIC,ARABIC_OMAN), "ar_OM"},
212 {RML(ARABIC,ARABIC_QATAR), "ar_QA"},
213 {RML(ARABIC,ARABIC_SAUDI_ARABIA), "ar_SA"},
214 {RML(ARABIC,ARABIC_SYRIA), "ar_SY"},
215 {RML(ARABIC,ARABIC_TUNISIA), "ar_TN"},
216 {RML(ARABIC,ARABIC_UAE), "ar_AE"},
217 {RML(ARABIC,ARABIC_YEMEN), "ar_YE"},
218 {RML(ARMENIAN,DEFAULT), "hy_AM"},
219 {RML(AZERI,AZERI_CYRILLIC), "az_AZ"},
220 {RML(AZERI,AZERI_LATIN), "az_AZ"},
221 {RML(BASQUE,DEFAULT), "eu_ES"},
222 {RML(BELARUSIAN,DEFAULT), "be_BY"},
223 /*{RML(BRETON,DEFAULT), "br_FR"},*/
224 {RML(BULGARIAN,DEFAULT), "bg_BG"},
225 {RML(CATALAN,DEFAULT), "ca_ES"},
226 {RML(CHINESE,CHINESE_HONGKONG), "zh_HK"},
227 {RML(CHINESE,CHINESE_MACAU), "zh_MO"},
228 {RML(CHINESE,CHINESE_SIMPLIFIED), "zh_CN"},
229 {RML(CHINESE,CHINESE_SINGAPORE), "zh_SG"},
230 {RML(CHINESE,CHINESE_TRADITIONAL), "zh_TW"},
231 /*{RML(CORNISH,DEFAULT), "kw_GB"},*/
232 {RML(CZECH,DEFAULT), "cs_CZ"},
233 {RML(DANISH,DEFAULT), "da_DK"},
234 {RML(DUTCH,DUTCH), "nl_NL"},
235 {RML(DUTCH,DUTCH_BELGIAN), "nl_BE"},
236 /*{RML(DUTCH,DUTCH_SURINAM), "nl_SR"},*/
237 {RML(ENGLISH,ENGLISH_AUS), "en_AU"},
238 {RML(ENGLISH,ENGLISH_BELIZE), "en_BZ"},
239 {RML(ENGLISH,ENGLISH_CAN), "en_CA"},
240 {RML(ENGLISH,ENGLISH_CARIBBEAN), "en_CB"},
241 {RML(ENGLISH,ENGLISH_EIRE), "en_IE"},
242 {RML(ENGLISH,ENGLISH_JAMAICA), "en_JM"},
243 {RML(ENGLISH,ENGLISH_NZ), "en_NZ"},
244 {RML(ENGLISH,ENGLISH_PHILIPPINES), "en_PH"},
245 {RML(ENGLISH,ENGLISH_SOUTH_AFRICA), "en_ZA"},
246 {RML(ENGLISH,ENGLISH_TRINIDAD), "en_TT"},
247 {RML(ENGLISH,ENGLISH_UK), "en_GB"},
248 {RML(ENGLISH,ENGLISH_US), "en_US"},
249 {RML(ENGLISH,ENGLISH_ZIMBABWE), "en_ZW"},
250 /*{RML(ESPERANTO,DEFAULT), "eo_"},*/
251 {RML(ESTONIAN,DEFAULT), "et_EE"},
252 {RML(FAEROESE,DEFAULT), "fo_FO"},
253 {RML(FARSI,DEFAULT), "fa_IR"},
254 {RML(FINNISH,DEFAULT), "fi_FI"},
255 {RML(FRENCH,FRENCH), "fr_FR"},
256 {RML(FRENCH,FRENCH_BELGIAN), "fr_BE"},
257 {RML(FRENCH,FRENCH_CANADIAN), "fr_CA"},
258 {RML(FRENCH,FRENCH_LUXEMBOURG), "fr_LU"},
259 {RML(FRENCH,FRENCH_MONACO), "fr_MC"},
260 {RML(FRENCH,FRENCH_SWISS), "fr_CH"},
261 /*{RML(GAELIC,GAELIC), "ga_IE"},*/
262 /*{RML(GAELIC,GAELIC_MANX), "gv_GB"},*/
263 /*{RML(GAELIC,GAELIC_SCOTTISH), "gd_GB"},*/
264 /*{RML(GALICIAN,DEFAULT), "gl_ES"},*/
265 {RML(GEORGIAN,DEFAULT), "ka_GE"},
266 {RML(GERMAN,GERMAN), "de_DE"},
267 {RML(GERMAN,GERMAN_AUSTRIAN), "de_AT"},
268 {RML(GERMAN,GERMAN_LIECHTENSTEIN), "de_LI"},
269 {RML(GERMAN,GERMAN_LUXEMBOURG), "de_LU"},
270 {RML(GERMAN,GERMAN_SWISS), "de_CH"},
271 {RML(GREEK,DEFAULT), "el_GR"},
272 {RML(GUJARATI,DEFAULT), "gu_IN"},
273 {RML(HEBREW,DEFAULT), "he_IL"},
274 {RML(HINDI,DEFAULT), "hi_IN"},
275 {RML(HUNGARIAN,DEFAULT), "hu_HU"},
276 {RML(ICELANDIC,DEFAULT), "is_IS"},
277 {RML(INDONESIAN,DEFAULT), "id_ID"},
278 {RML(ITALIAN,ITALIAN), "it_IT"},
279 {RML(ITALIAN,ITALIAN_SWISS), "it_CH"},
280 {RML(JAPANESE,DEFAULT), "ja_JP"},
281 {RML(KANNADA,DEFAULT), "kn_IN"},
282 {RML(KAZAK,DEFAULT), "kk_KZ"},
283 {RML(KONKANI,DEFAULT), "kok_IN"},
284 {RML(KOREAN,KOREAN), "ko_KR"},
285 /*{RML(KYRGYZ,DEFAULT), "ky_KG"},*/
286 {RML(LATVIAN,DEFAULT), "lv_LV"},
287 {RML(LITHUANIAN,LITHUANIAN), "lt_LT"},
288 {RML(MACEDONIAN,DEFAULT), "mk_MK"},
289 {RML(MALAY,MALAY_BRUNEI_DARUSSALAM), "ms_BN"},
290 {RML(MALAY,MALAY_MALAYSIA), "ms_MY"},
291 {RML(MARATHI,DEFAULT), "mr_IN"},
292 /*{RML(MONGOLIAN,DEFAULT), "mn_MN"},*/
293 {RML(NORWEGIAN,NORWEGIAN_BOKMAL), "nb_NO"},
294 {RML(NORWEGIAN,NORWEGIAN_NYNORSK), "nn_NO"},
295 {RML(POLISH,DEFAULT), "pl_PL"},
296 {RML(PORTUGUESE,PORTUGUESE), "pt_PT"},
297 {RML(PORTUGUESE,PORTUGUESE_BRAZILIAN), "pt_BR"},
298 {RML(PUNJABI,DEFAULT), "pa_IN"},
299 {RML(ROMANIAN,DEFAULT), "ro_RO"},
300 {RML(RUSSIAN,DEFAULT), "ru_RU"},
301 {RML(SANSKRIT,DEFAULT), "sa_IN"},
302 {RML(SERBIAN,DEFAULT), "hr_HR"},
303 {RML(SERBIAN,SERBIAN_CYRILLIC), "sr_SP"},
304 {RML(SERBIAN,SERBIAN_LATIN), "sr_SP"},
305 {RML(SLOVAK,DEFAULT), "sk_SK"},
306 {RML(SLOVENIAN,DEFAULT), "sl_SI"},
307 {RML(SPANISH,SPANISH), "es_ES"},
308 {RML(SPANISH,SPANISH_ARGENTINA), "es_AR"},
309 {RML(SPANISH,SPANISH_BOLIVIA), "es_BO"},
310 {RML(SPANISH,SPANISH_CHILE), "es_CL"},
311 {RML(SPANISH,SPANISH_COLOMBIA), "es_CO"},
312 {RML(SPANISH,SPANISH_COSTA_RICA), "es_CR"},
313 {RML(SPANISH,SPANISH_DOMINICAN_REPUBLIC), "es_DO"},
314 {RML(SPANISH,SPANISH_ECUADOR), "es_EC"},
315 {RML(SPANISH,SPANISH_EL_SALVADOR), "es_SV"},
316 {RML(SPANISH,SPANISH_GUATEMALA), "es_GT"},
317 {RML(SPANISH,SPANISH_HONDURAS), "es_HN"},
318 {RML(SPANISH,SPANISH_MEXICAN), "es_MX"},
319 {RML(SPANISH,SPANISH_MODERN), "es_ES"},
320 {RML(SPANISH,SPANISH_NICARAGUA), "es_NI"},
321 {RML(SPANISH,SPANISH_PANAMA), "es_PA"},
322 {RML(SPANISH,SPANISH_PARAGUAY), "es_PY"},
323 {RML(SPANISH,SPANISH_PERU), "es_PE"},
324 {RML(SPANISH,SPANISH_PUERTO_RICO), "es_PR"},
325 {RML(SPANISH,SPANISH_URUGUAY), "es_UY"},
326 {RML(SPANISH,SPANISH_VENEZUELA), "es_VE"},
327 {RML(SWAHILI,DEFAULT), "sw_KE"},
328 {RML(SWEDISH,SWEDISH), "sv_SE"},
329 {RML(SWEDISH,SWEDISH_FINLAND), "sv_FI"},
330 /*{RML(SYRIAC,DEFAULT), "syr_SY"},*/
331 {RML(TAMIL,DEFAULT), "ta_IN"},
332 {RML(TATAR,DEFAULT), "tt_TA"},
333 {RML(TELUGU,DEFAULT), "te_IN"},
334 {RML(THAI,DEFAULT), "th_TH"},
335 {RML(TURKISH,DEFAULT), "tr_TR"},
336 {RML(UKRAINIAN,DEFAULT), "uk_UA"},
337 {RML(URDU,URDU_PAKISTAN), "ur_PK"},
338 {RML(UZBEK,UZBEK_CYRILLIC), "uz_UZ"},
339 {RML(UZBEK,UZBEK_LATIN), "uz_UZ"},
340 {RML(VIETNAMESE,DEFAULT), "vi_VN"},
341 /*{RML(WALON,DEFAULT), "wa_BE"},*/
342 /*{RML(WELSH,DEFAULT), "cy_GB"},*/
344 static const IDToCode primary_to_code[] = {
345 {LANG_AFRIKAANS, "af"},
348 {LANG_BULGARIAN, "bg"},
349 /*{LANG_BRETON, "br"},*/
350 {LANG_BELARUSIAN, "by"},
351 {LANG_CATALAN, "ca"},
353 /*{LANG_WELSH, "cy"},*/
357 {LANG_ENGLISH, "en"},
358 /*{LANG_ESPERANTO, "eo"},*/
359 {LANG_SPANISH, "es"},
360 {LANG_ESTONIAN, "et"},
363 {LANG_FINNISH, "fi"},
364 {LANG_FAEROESE, "fo"},
366 /*{LANG_GAELIC, "ga"},*/
367 /*{LANG_GALICIAN, "gl"},*/
368 {LANG_GUJARATI, "gu"},
371 {LANG_SERBIAN, "hr"},
372 {LANG_HUNGARIAN, "hu"},
373 {LANG_ARMENIAN, "hy"},
374 {LANG_INDONESIAN, "id"},
375 {LANG_ITALIAN, "it"},
376 {LANG_JAPANESE, "ja"},
377 {LANG_GEORGIAN, "ka"},
379 {LANG_KANNADA, "kn"},
381 /*{LANG_KYRGYZ, "ky"},*/
382 {LANG_LITHUANIAN, "lt"},
383 {LANG_LATVIAN, "lv"},
384 {LANG_MACEDONIAN, "mk"},
385 /*{LANG_MONGOLIAN, "mn"},*/
386 {LANG_MARATHI, "mr"},
388 {LANG_NORWEGIAN, "nb"},
390 {LANG_NORWEGIAN, "nn"},
391 {LANG_NORWEGIAN, "no"},/* unofficial? */
392 {LANG_PUNJABI, "pa"},
394 {LANG_PORTUGUESE, "pt"},
395 {LANG_ROMANIAN, "ro"},
396 {LANG_RUSSIAN, "ru"},
398 {LANG_SLOVENIAN, "sl"},
399 {LANG_ALBANIAN, "sq"},
400 {LANG_SERBIAN, "sr"},
401 {LANG_SWEDISH, "sv"},
402 {LANG_SWAHILI, "sw"},
405 {LANG_TURKISH, "tr"},
407 {LANG_UKRAINIAN, "uk"},
410 {LANG_VIETNAMESE, "vi"},
411 /*{LANG_WALON, "wa"},*/
412 {LANG_CHINESE, "zh"},
414 static int num_primary_to_code =
415 sizeof(primary_to_code) / sizeof(*primary_to_code);
416 static int num_both_to_code =
417 sizeof(both_to_code) / sizeof(*both_to_code);
420 lcid_to_fl(LCID lcid,
422 LANGID langid = LANGIDFROMLCID(lcid);
423 LANGID primary_lang = PRIMARYLANGID(langid);
425 LANGID sub_lang = SUBLANGID(langid);
428 /* try to find an exact primary/sublanguage combo that we know about */
429 for (i=0; i<num_both_to_code; ++i) {
430 if (both_to_code[i].id == langid) {
431 accumulate_locstring(both_to_code[i].code, rtn);
435 /* fallback to just checking the primary language id */
436 for (i=0; i<num_primary_to_code; ++i) {
437 if (primary_to_code[i].id == primary_lang) {
438 accumulate_locstring(primary_to_code[i].code, rtn);
448 FL_FindLocale(FL_Locale **locale, FL_Domain /*domain*/) {
449 FL_Success success = FL_FAILED;
450 FL_Locale *rtn = (FL_Locale*) malloc(sizeof(FL_Locale));
456 /* win32 >= mswindows95 */
458 LCID lcid = GetThreadLocale();
459 if (lcid_to_fl(lcid, rtn)) {
460 success = FL_CONFIDENT;
462 if (success == FL_FAILED) {
463 /* assume US English on mswindows systems unless we know otherwise */
464 if (accumulate_locstring("en_US.ISO_8859-1", rtn)) {
465 success = FL_DEFAULT_GUESS;
473 /* sv_SE.ISO_8859-1 */
474 /* fr_FR.ISO8859-1 */
479 /* try the various vars in decreasing order of authority */
480 if (accumulate_env("LC_ALL", rtn) ||
481 accumulate_env("LC_MESSAGES", rtn) ||
482 accumulate_env("LANG", rtn) ||
483 accumulate_env("LANGUAGE", rtn)) {
484 success = FL_CONFIDENT;
486 if (success == FL_FAILED) {
487 /* assume US English on unixoid systems unless we know otherwise */
488 if (accumulate_locstring("en_US.ISO_8859-1", rtn)) {
489 success = FL_DEFAULT_GUESS;
495 if (success != FL_FAILED) {
505 FL_FreeLocale(FL_Locale **locale) {
507 FL_Locale *l = *locale;
510 free((void*)l->lang);
513 free((void*)l->country);
516 free((void*)l->variant);