00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029 #include <config.h>
00030
00031 #include <stdlib.h>
00032 #include <string.h>
00033 #include <ctype.h>
00034
00035 #ifdef WIN32
00036 #include <windows.h>
00037 #include <winnt.h>
00038 #endif
00039
00040 #ifdef MACOSX
00041 #include <CoreFoundation/CoreFoundation.h>
00042 #endif
00043
00044 #include "findlocale.hpp"
00045
00046 static int
00047 is_lcchar(const int c) {
00048 return isalnum(c);
00049 }
00050
00051 static void
00052 lang_country_variant_from_envstring(const char *str,
00053 char **lang,
00054 char **country,
00055 char **variant) {
00056 int end = 0;
00057 int start;
00058
00059
00060 start = end;
00061 while (is_lcchar(str[end])) {
00062 ++end;
00063 }
00064 if (start != end) {
00065 int i;
00066 int len = end - start;
00067 char *s = (char*) malloc(len + 1);
00068 for (i=0; i<len; ++i) {
00069 s[i] = tolower(str[start + i]);
00070 }
00071 s[i] = '\0';
00072 *lang = s;
00073 } else {
00074 *lang = NULL;
00075 }
00076
00077 if (str[end] && str[end]!=':') {
00078 ++end;
00079 }
00080
00081
00082 start = end;
00083 while (is_lcchar(str[end])) {
00084 ++end;
00085 }
00086 if (start != end) {
00087 int i;
00088 int len = end - start;
00089 char *s = (char*) malloc(len + 1);
00090 for (i=0; i<len; ++i) {
00091 s[i] = toupper(str[start + i]);
00092 }
00093 s[i] = '\0';
00094 *country = s;
00095 } else {
00096 *country = NULL;
00097 }
00098
00099 if (str[end] && str[end]!=':') {
00100 ++end;
00101 }
00102
00103
00104 start = end;
00105 while (str[end] && str[end]!=':') {
00106 ++end;
00107 }
00108 if (start != end) {
00109 int i;
00110 int len = end - start;
00111 char *s = (char*) malloc(len + 1);
00112 for (i=0; i<len; ++i) {
00113 s[i] = str[start + i];
00114 }
00115 s[i] = '\0';
00116 *variant = s;
00117 } else {
00118 *variant = NULL;
00119 }
00120 }
00121
00122
00123 static int
00124 accumulate_locstring(const char *str, FL_Locale *l) {
00125 char *lang = NULL;
00126 char *country = NULL;
00127 char *variant = NULL;
00128 if (str) {
00129 lang_country_variant_from_envstring(str, &lang, &country, &variant);
00130 if (lang) {
00131 l->lang = lang;
00132 l->country = country;
00133 l->variant = variant;
00134 return 1;
00135 }
00136 }
00137 free(lang); free(country); free(variant);
00138 return 0;
00139 }
00140
00141
00142 #ifndef WIN32
00143 static int
00144 accumulate_env(const char *name, FL_Locale *l) {
00145 char *env;
00146 char *lang = NULL;
00147 char *country = NULL;
00148 char *variant = NULL;
00149 env = getenv(name);
00150 if (env) {
00151 return accumulate_locstring(env, l);
00152 }
00153 free(lang); free(country); free(variant);
00154 return 0;
00155 }
00156 #endif
00157
00158 static void
00159 canonize_fl(FL_Locale *l) {
00160
00161
00162 if (l->lang && 0 == strcmp(l->lang, "en")) {
00163 if (l->country && 0 == strcmp(l->country, "UK")) {
00164 free((void*)l->country);
00165 l->country = strdup("GB");
00166 }
00167 }
00168
00169 if (l->lang && 0 == strcmp(l->lang, "ja")) {
00170 if (l->country && 0 == strcmp(l->country, "JA")) {
00171 free((void*)l->country);
00172 l->country = strdup("JP");
00173 }
00174 }
00175 }
00176
00177
00178 #ifdef WIN32
00179 #include <stdio.h>
00180 #define ML(pn,sn) MAKELANGID(LANG_##pn, SUBLANG_##pn##_##sn)
00181 #define MLN(pn) MAKELANGID(LANG_##pn, SUBLANG_DEFAULT)
00182 #define RML(pn,sn) MAKELANGID(LANG_##pn, SUBLANG_##sn)
00183 typedef struct {
00184 LANGID id;
00185 const char* code;
00186 } IDToCode;
00187 static const IDToCode both_to_code[] = {
00188 {ML(ENGLISH,US), "en_US.ISO_8859-1"},
00189 {ML(ENGLISH,CAN), "en_CA"},
00190 {ML(ENGLISH,UK), "en_GB"},
00191 {ML(ENGLISH,EIRE), "en_IE"},
00192 {ML(ENGLISH,AUS), "en_AU"},
00193 {MLN(GERMAN), "de_DE"},
00194 {MLN(SPANISH), "es_ES"},
00195 {ML(SPANISH,MEXICAN), "es_MX"},
00196 {MLN(FRENCH), "fr_FR"},
00197 {ML(FRENCH,CANADIAN), "fr_CA"},
00198 {ML(FRENCH,BELGIAN), "fr_BE"},
00199 {ML(DUTCH,BELGIAN), "nl_BE"},
00200 {ML(PORTUGUESE,BRAZILIAN), "pt_BR"},
00201 {MLN(PORTUGUESE), "pt_PT"},
00202 {MLN(SWEDISH), "sv_SE"},
00203 {ML(CHINESE,HONGKONG), "zh_HK"},
00204
00205 {RML(AFRIKAANS,DEFAULT), "af_ZA"},
00206 {RML(ALBANIAN,DEFAULT), "sq_AL"},
00207 {RML(ARABIC,ARABIC_ALGERIA), "ar_DZ"},
00208 {RML(ARABIC,ARABIC_BAHRAIN), "ar_BH"},
00209 {RML(ARABIC,ARABIC_EGYPT), "ar_EG"},
00210 {RML(ARABIC,ARABIC_IRAQ), "ar_IQ"},
00211 {RML(ARABIC,ARABIC_JORDAN), "ar_JO"},
00212 {RML(ARABIC,ARABIC_KUWAIT), "ar_KW"},
00213 {RML(ARABIC,ARABIC_LEBANON), "ar_LB"},
00214 {RML(ARABIC,ARABIC_LIBYA), "ar_LY"},
00215 {RML(ARABIC,ARABIC_MOROCCO), "ar_MA"},
00216 {RML(ARABIC,ARABIC_OMAN), "ar_OM"},
00217 {RML(ARABIC,ARABIC_QATAR), "ar_QA"},
00218 {RML(ARABIC,ARABIC_SAUDI_ARABIA), "ar_SA"},
00219 {RML(ARABIC,ARABIC_SYRIA), "ar_SY"},
00220 {RML(ARABIC,ARABIC_TUNISIA), "ar_TN"},
00221 {RML(ARABIC,ARABIC_UAE), "ar_AE"},
00222 {RML(ARABIC,ARABIC_YEMEN), "ar_YE"},
00223 {RML(ARMENIAN,DEFAULT), "hy_AM"},
00224 {RML(AZERI,AZERI_CYRILLIC), "az_AZ"},
00225 {RML(AZERI,AZERI_LATIN), "az_AZ"},
00226 {RML(BASQUE,DEFAULT), "eu_ES"},
00227 {RML(BELARUSIAN,DEFAULT), "be_BY"},
00228
00229 {RML(BULGARIAN,DEFAULT), "bg_BG"},
00230 {RML(CATALAN,DEFAULT), "ca_ES"},
00231 {RML(CHINESE,CHINESE_HONGKONG), "zh_HK"},
00232 {RML(CHINESE,CHINESE_MACAU), "zh_MO"},
00233 {RML(CHINESE,CHINESE_SIMPLIFIED), "zh_CN"},
00234 {RML(CHINESE,CHINESE_SINGAPORE), "zh_SG"},
00235 {RML(CHINESE,CHINESE_TRADITIONAL), "zh_TW"},
00236
00237 {RML(CZECH,DEFAULT), "cs_CZ"},
00238 {RML(DANISH,DEFAULT), "da_DK"},
00239 {RML(DUTCH,DUTCH), "nl_NL"},
00240 {RML(DUTCH,DUTCH_BELGIAN), "nl_BE"},
00241
00242 {RML(ENGLISH,ENGLISH_AUS), "en_AU"},
00243 {RML(ENGLISH,ENGLISH_BELIZE), "en_BZ"},
00244 {RML(ENGLISH,ENGLISH_CAN), "en_CA"},
00245 {RML(ENGLISH,ENGLISH_CARIBBEAN), "en_CB"},
00246 {RML(ENGLISH,ENGLISH_EIRE), "en_IE"},
00247 {RML(ENGLISH,ENGLISH_JAMAICA), "en_JM"},
00248 {RML(ENGLISH,ENGLISH_NZ), "en_NZ"},
00249 {RML(ENGLISH,ENGLISH_PHILIPPINES), "en_PH"},
00250 {RML(ENGLISH,ENGLISH_SOUTH_AFRICA), "en_ZA"},
00251 {RML(ENGLISH,ENGLISH_TRINIDAD), "en_TT"},
00252 {RML(ENGLISH,ENGLISH_UK), "en_GB"},
00253 {RML(ENGLISH,ENGLISH_US), "en_US"},
00254 {RML(ENGLISH,ENGLISH_ZIMBABWE), "en_ZW"},
00255
00256 {RML(ESTONIAN,DEFAULT), "et_EE"},
00257 {RML(FAEROESE,DEFAULT), "fo_FO"},
00258 {RML(FARSI,DEFAULT), "fa_IR"},
00259 {RML(FINNISH,DEFAULT), "fi_FI"},
00260 {RML(FRENCH,FRENCH), "fr_FR"},
00261 {RML(FRENCH,FRENCH_BELGIAN), "fr_BE"},
00262 {RML(FRENCH,FRENCH_CANADIAN), "fr_CA"},
00263 {RML(FRENCH,FRENCH_LUXEMBOURG), "fr_LU"},
00264 {RML(FRENCH,FRENCH_MONACO), "fr_MC"},
00265 {RML(FRENCH,FRENCH_SWISS), "fr_CH"},
00266
00267
00268
00269
00270 {RML(GEORGIAN,DEFAULT), "ka_GE"},
00271 {RML(GERMAN,GERMAN), "de_DE"},
00272 {RML(GERMAN,GERMAN_AUSTRIAN), "de_AT"},
00273 {RML(GERMAN,GERMAN_LIECHTENSTEIN), "de_LI"},
00274 {RML(GERMAN,GERMAN_LUXEMBOURG), "de_LU"},
00275 {RML(GERMAN,GERMAN_SWISS), "de_CH"},
00276 {RML(GREEK,DEFAULT), "el_GR"},
00277 {RML(GUJARATI,DEFAULT), "gu_IN"},
00278 {RML(HEBREW,DEFAULT), "he_IL"},
00279 {RML(HINDI,DEFAULT), "hi_IN"},
00280 {RML(HUNGARIAN,DEFAULT), "hu_HU"},
00281 {RML(ICELANDIC,DEFAULT), "is_IS"},
00282 {RML(INDONESIAN,DEFAULT), "id_ID"},
00283 {RML(ITALIAN,ITALIAN), "it_IT"},
00284 {RML(ITALIAN,ITALIAN_SWISS), "it_CH"},
00285 {RML(JAPANESE,DEFAULT), "ja_JP"},
00286 {RML(KANNADA,DEFAULT), "kn_IN"},
00287 {RML(KAZAK,DEFAULT), "kk_KZ"},
00288 {RML(KONKANI,DEFAULT), "kok_IN"},
00289 {RML(KOREAN,KOREAN), "ko_KR"},
00290
00291 {RML(LATVIAN,DEFAULT), "lv_LV"},
00292 {RML(LITHUANIAN,LITHUANIAN), "lt_LT"},
00293 {RML(MACEDONIAN,DEFAULT), "mk_MK"},
00294 {RML(MALAY,MALAY_BRUNEI_DARUSSALAM), "ms_BN"},
00295 {RML(MALAY,MALAY_MALAYSIA), "ms_MY"},
00296 {RML(MARATHI,DEFAULT), "mr_IN"},
00297
00298 {RML(NORWEGIAN,NORWEGIAN_BOKMAL), "nb_NO"},
00299 {RML(NORWEGIAN,NORWEGIAN_NYNORSK), "nn_NO"},
00300 {RML(POLISH,DEFAULT), "pl_PL"},
00301 {RML(PORTUGUESE,PORTUGUESE), "pt_PT"},
00302 {RML(PORTUGUESE,PORTUGUESE_BRAZILIAN), "pt_BR"},
00303 {RML(PUNJABI,DEFAULT), "pa_IN"},
00304 {RML(ROMANIAN,DEFAULT), "ro_RO"},
00305 {RML(RUSSIAN,DEFAULT), "ru_RU"},
00306 {RML(SANSKRIT,DEFAULT), "sa_IN"},
00307 {RML(SERBIAN,DEFAULT), "hr_HR"},
00308 {RML(SERBIAN,SERBIAN_CYRILLIC), "sr_SP"},
00309 {RML(SERBIAN,SERBIAN_LATIN), "sr_SP"},
00310 {RML(SLOVAK,DEFAULT), "sk_SK"},
00311 {RML(SLOVENIAN,DEFAULT), "sl_SI"},
00312 {RML(SPANISH,SPANISH), "es_ES"},
00313 {RML(SPANISH,SPANISH_ARGENTINA), "es_AR"},
00314 {RML(SPANISH,SPANISH_BOLIVIA), "es_BO"},
00315 {RML(SPANISH,SPANISH_CHILE), "es_CL"},
00316 {RML(SPANISH,SPANISH_COLOMBIA), "es_CO"},
00317 {RML(SPANISH,SPANISH_COSTA_RICA), "es_CR"},
00318 {RML(SPANISH,SPANISH_DOMINICAN_REPUBLIC), "es_DO"},
00319 {RML(SPANISH,SPANISH_ECUADOR), "es_EC"},
00320 {RML(SPANISH,SPANISH_EL_SALVADOR), "es_SV"},
00321 {RML(SPANISH,SPANISH_GUATEMALA), "es_GT"},
00322 {RML(SPANISH,SPANISH_HONDURAS), "es_HN"},
00323 {RML(SPANISH,SPANISH_MEXICAN), "es_MX"},
00324 {RML(SPANISH,SPANISH_MODERN), "es_ES"},
00325 {RML(SPANISH,SPANISH_NICARAGUA), "es_NI"},
00326 {RML(SPANISH,SPANISH_PANAMA), "es_PA"},
00327 {RML(SPANISH,SPANISH_PARAGUAY), "es_PY"},
00328 {RML(SPANISH,SPANISH_PERU), "es_PE"},
00329 {RML(SPANISH,SPANISH_PUERTO_RICO), "es_PR"},
00330 {RML(SPANISH,SPANISH_URUGUAY), "es_UY"},
00331 {RML(SPANISH,SPANISH_VENEZUELA), "es_VE"},
00332 {RML(SWAHILI,DEFAULT), "sw_KE"},
00333 {RML(SWEDISH,SWEDISH), "sv_SE"},
00334 {RML(SWEDISH,SWEDISH_FINLAND), "sv_FI"},
00335
00336 {RML(TAMIL,DEFAULT), "ta_IN"},
00337 {RML(TATAR,DEFAULT), "tt_TA"},
00338 {RML(TELUGU,DEFAULT), "te_IN"},
00339 {RML(THAI,DEFAULT), "th_TH"},
00340 {RML(TURKISH,DEFAULT), "tr_TR"},
00341 {RML(UKRAINIAN,DEFAULT), "uk_UA"},
00342 {RML(URDU,URDU_PAKISTAN), "ur_PK"},
00343 {RML(UZBEK,UZBEK_CYRILLIC), "uz_UZ"},
00344 {RML(UZBEK,UZBEK_LATIN), "uz_UZ"},
00345 {RML(VIETNAMESE,DEFAULT), "vi_VN"},
00346
00347
00348 };
00349 static const IDToCode primary_to_code[] = {
00350 {LANG_AFRIKAANS, "af"},
00351 {LANG_ARABIC, "ar"},
00352 {LANG_AZERI, "az"},
00353 {LANG_BULGARIAN, "bg"},
00354
00355 {LANG_BELARUSIAN, "by"},
00356 {LANG_CATALAN, "ca"},
00357 {LANG_CZECH, "cs"},
00358
00359 {LANG_DANISH, "da"},
00360 {LANG_GERMAN, "de"},
00361 {LANG_GREEK, "el"},
00362 {LANG_ENGLISH, "en"},
00363
00364 {LANG_SPANISH, "es"},
00365 {LANG_ESTONIAN, "et"},
00366 {LANG_BASQUE, "eu"},
00367 {LANG_FARSI, "fa"},
00368 {LANG_FINNISH, "fi"},
00369 {LANG_FAEROESE, "fo"},
00370 {LANG_FRENCH, "fr"},
00371
00372
00373 {LANG_GUJARATI, "gu"},
00374 {LANG_HEBREW, "he"},
00375 {LANG_HINDI, "hi"},
00376 {LANG_SERBIAN, "hr"},
00377 {LANG_HUNGARIAN, "hu"},
00378 {LANG_ARMENIAN, "hy"},
00379 {LANG_INDONESIAN, "id"},
00380 {LANG_ITALIAN, "it"},
00381 {LANG_JAPANESE, "ja"},
00382 {LANG_GEORGIAN, "ka"},
00383 {LANG_KAZAK, "kk"},
00384 {LANG_KANNADA, "kn"},
00385 {LANG_KOREAN, "ko"},
00386
00387 {LANG_LITHUANIAN, "lt"},
00388 {LANG_LATVIAN, "lv"},
00389 {LANG_MACEDONIAN, "mk"},
00390
00391 {LANG_MARATHI, "mr"},
00392 {LANG_MALAY, "ms"},
00393 {LANG_NORWEGIAN, "nb"},
00394 {LANG_DUTCH, "nl"},
00395 {LANG_NORWEGIAN, "nn"},
00396 {LANG_NORWEGIAN, "no"},
00397 {LANG_PUNJABI, "pa"},
00398 {LANG_POLISH, "pl"},
00399 {LANG_PORTUGUESE, "pt"},
00400 {LANG_ROMANIAN, "ro"},
00401 {LANG_RUSSIAN, "ru"},
00402 {LANG_SLOVAK, "sk"},
00403 {LANG_SLOVENIAN, "sl"},
00404 {LANG_ALBANIAN, "sq"},
00405 {LANG_SERBIAN, "sr"},
00406 {LANG_SWEDISH, "sv"},
00407 {LANG_SWAHILI, "sw"},
00408 {LANG_TAMIL, "ta"},
00409 {LANG_THAI, "th"},
00410 {LANG_TURKISH, "tr"},
00411 {LANG_TATAR, "tt"},
00412 {LANG_UKRAINIAN, "uk"},
00413 {LANG_URDU, "ur"},
00414 {LANG_UZBEK, "uz"},
00415 {LANG_VIETNAMESE, "vi"},
00416
00417 {LANG_CHINESE, "zh"},
00418 };
00419 static int num_primary_to_code =
00420 sizeof(primary_to_code) / sizeof(*primary_to_code);
00421 static int num_both_to_code =
00422 sizeof(both_to_code) / sizeof(*both_to_code);
00423
00424 static const int
00425 lcid_to_fl(LCID lcid,
00426 FL_Locale *rtn) {
00427 LANGID langid = LANGIDFROMLCID(lcid);
00428 LANGID primary_lang = PRIMARYLANGID(langid);
00429 #if 0
00430 LANGID sub_lang = SUBLANGID(langid);
00431 #endif
00432 int i;
00433
00434 for (i=0; i<num_both_to_code; ++i) {
00435 if (both_to_code[i].id == langid) {
00436 accumulate_locstring(both_to_code[i].code, rtn);
00437 return 1;
00438 }
00439 }
00440
00441 for (i=0; i<num_primary_to_code; ++i) {
00442 if (primary_to_code[i].id == primary_lang) {
00443 accumulate_locstring(primary_to_code[i].code, rtn);
00444 return 1;
00445 }
00446 }
00447 return 0;
00448 }
00449 #endif
00450
00451
00452 FL_Success
00453 FL_FindLocale(FL_Locale **locale, FL_Domain ) {
00454 FL_Success success = FL_FAILED;
00455 FL_Locale *rtn = (FL_Locale*) malloc(sizeof(FL_Locale));
00456 rtn->lang = NULL;
00457 rtn->country = NULL;
00458 rtn->variant = NULL;
00459
00460 #ifdef WIN32
00461
00462 {
00463 LCID lcid = GetThreadLocale();
00464 if (lcid_to_fl(lcid, rtn)) {
00465 success = FL_CONFIDENT;
00466 }
00467 if (success == FL_FAILED) {
00468
00469 if (accumulate_locstring("en_US.ISO_8859-1", rtn)) {
00470 success = FL_DEFAULT_GUESS;
00471 }
00472 }
00473 }
00474 #else
00475
00476 {
00477 #ifdef MACOSX
00478 CFIndex sz;
00479 CFArrayRef languages;
00480 CFStringRef uxstylelangs;
00481 char *uxsl;
00482
00483
00484 languages = (CFArrayRef)CFPreferencesCopyValue(CFSTR("AppleLanguages"),
00485 kCFPreferencesAnyApplication, kCFPreferencesCurrentUser,
00486 kCFPreferencesAnyHost);
00487
00488
00489 uxstylelangs = CFStringCreateByCombiningStrings(kCFAllocatorDefault,
00490 languages, CFSTR(":"));
00491
00492
00493 sz = CFStringGetLength(uxstylelangs) + 1;
00494 uxsl = (char*)malloc(sz);
00495 CFStringGetCString(uxstylelangs, uxsl, sz, kCFStringEncodingISOLatin1);
00496
00497
00498 if (accumulate_locstring(uxsl, rtn)) {
00499 success = FL_CONFIDENT;
00500 }
00501
00502 #endif
00503
00504
00505
00506
00507
00508
00509
00510
00511 if (accumulate_env("LC_ALL", rtn) ||
00512 accumulate_env("LC_MESSAGES", rtn) ||
00513 accumulate_env("LANG", rtn) ||
00514 accumulate_env("LANGUAGE", rtn)) {
00515 success = FL_CONFIDENT;
00516 }
00517 if (success == FL_FAILED) {
00518
00519 if (accumulate_locstring("en_US.ISO_8859-1", rtn)) {
00520 success = FL_DEFAULT_GUESS;
00521 }
00522 }
00523 }
00524 #endif
00525
00526 if (success != FL_FAILED) {
00527 canonize_fl(rtn);
00528 }
00529
00530 *locale = rtn;
00531 return success;
00532 }
00533
00534
00535 void
00536 FL_FreeLocale(FL_Locale **locale) {
00537 if (locale) {
00538 FL_Locale *l = *locale;
00539 if (l) {
00540 if (l->lang) {
00541 free((void*)l->lang);
00542 }
00543 if (l->country) {
00544 free((void*)l->country);
00545 }
00546 if (l->variant) {
00547 free((void*)l->variant);
00548 }
00549 free(l);
00550 *locale = NULL;
00551 }
00552 }
00553 }