| OLD | NEW |
| 1 // Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "app/l10n_util.h" | 5 #include "app/l10n_util.h" |
| 6 | 6 |
| 7 #include <cstdlib> | 7 #include <cstdlib> |
| 8 #include "app/app_paths.h" | 8 #include "app/app_paths.h" |
| 9 #include "app/app_switches.h" | 9 #include "app/app_switches.h" |
| 10 #include "app/gfx/canvas.h" | 10 #include "app/gfx/canvas.h" |
| (...skipping 170 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 181 "zh-TW", // Chinese (Traditional) | 181 "zh-TW", // Chinese (Traditional) |
| 182 "zu", // Zulu | 182 "zu", // Zulu |
| 183 }; | 183 }; |
| 184 | 184 |
| 185 | 185 |
| 186 // Get language and region from the OS. | 186 // Get language and region from the OS. |
| 187 void GetLanguageAndRegionFromOS(std::string* lang, std::string* region) { | 187 void GetLanguageAndRegionFromOS(std::string* lang, std::string* region) { |
| 188 // Later we may have to change this to be OS-dependent so that | 188 // Later we may have to change this to be OS-dependent so that |
| 189 // it's not affected by ICU's default locale. It's all right | 189 // it's not affected by ICU's default locale. It's all right |
| 190 // to do this way because SetICUDefaultLocale is internal | 190 // to do this way because SetICUDefaultLocale is internal |
| 191 // to this file and we know where/when it's called. | 191 // to this file and we know that it's not yet called when this function |
| 192 // is called. |
| 192 icu::Locale locale = icu::Locale::getDefault(); | 193 icu::Locale locale = icu::Locale::getDefault(); |
| 193 const char* language = locale.getLanguage(); | 194 const char* language = locale.getLanguage(); |
| 194 const char* country = locale.getCountry(); | 195 const char* country = locale.getCountry(); |
| 195 DCHECK(language); | 196 DCHECK(language); |
| 196 *lang = language; | 197 *lang = language; |
| 197 *region = country; | 198 *region = country; |
| 198 } | 199 } |
| 199 | 200 |
| 200 // Convert Chrome locale name to ICU locale name | 201 // Convert Chrome locale name to ICU locale name |
| 201 std::string ICULocaleName(const std::string& locale_string) { | 202 std::string ICULocaleName(const std::string& locale_string) { |
| (...skipping 16 matching lines...) Expand all Loading... |
| 218 return lang; | 219 return lang; |
| 219 } | 220 } |
| 220 return "es-MX"; | 221 return "es-MX"; |
| 221 } | 222 } |
| 222 // Currently, Chrome has only "es" and "es-419", but later we may have | 223 // Currently, Chrome has only "es" and "es-419", but later we may have |
| 223 // more specific "es-RR". | 224 // more specific "es-RR". |
| 224 return locale_string; | 225 return locale_string; |
| 225 } | 226 } |
| 226 | 227 |
| 227 // Sets the default locale of ICU. | 228 // Sets the default locale of ICU. |
| 228 // When the application locale (UI locale) of Chrome is specified with | 229 // Once the application locale of Chrome in GetApplicationLocale is determined, |
| 229 // '--lang' command line flag or 'intl.app_locale' entry in the "Preferences", | |
| 230 // the default locale of ICU need to be changed to match the application locale | 230 // the default locale of ICU need to be changed to match the application locale |
| 231 // so that ICU functions work correctly in a locale-dependent manner. | 231 // so that ICU functions work correctly in a locale-dependent manner. |
| 232 // This is handy in that we don't have to call GetApplicationLocale() | 232 // This is handy in that we don't have to call GetApplicationLocale() |
| 233 // everytime we call locale-dependent ICU APIs as long as we make sure | 233 // everytime we call locale-dependent ICU APIs as long as we make sure |
| 234 // that this is called before any locale-dependent API is called. | 234 // that this is called before any locale-dependent API is called. |
| 235 UBool SetICUDefaultLocale(const std::string& locale_string) { | 235 void SetICUDefaultLocale(const std::string& locale_string) { |
| 236 icu::Locale locale(ICULocaleName(locale_string).c_str()); | 236 icu::Locale locale(ICULocaleName(locale_string).c_str()); |
| 237 UErrorCode error_code = U_ZERO_ERROR; | 237 UErrorCode error_code = U_ZERO_ERROR; |
| 238 icu::Locale::setDefault(locale, error_code); | 238 icu::Locale::setDefault(locale, error_code); |
| 239 // This return value is actually bogus because Locale object is | 239 // This return value is actually bogus because Locale object is |
| 240 // an ID and setDefault seems to always succeed (regardless of the | 240 // an ID and setDefault seems to always succeed (regardless of the |
| 241 // presence of actual locale data). However, | 241 // presence of actual locale data). However, |
| 242 // it does not hurt to have it as a sanity check. | 242 // it does not hurt to have it as a sanity check. |
| 243 return U_SUCCESS(error_code); | 243 DCHECK(U_SUCCESS(error_code)); |
| 244 } | 244 } |
| 245 | 245 |
| 246 // Returns true if |locale_name| has an alias in the ICU data file. | 246 // Returns true if |locale_name| has an alias in the ICU data file. |
| 247 bool IsDuplicateName(const std::string& locale_name) { | 247 bool IsDuplicateName(const std::string& locale_name) { |
| 248 static const char* const kDuplicateNames[] = { | 248 static const char* const kDuplicateNames[] = { |
| 249 "en", | 249 "en", |
| 250 "pt", | 250 "pt", |
| 251 "zh", | 251 "zh", |
| 252 "zh_hans_cn", | 252 "zh_hans_cn", |
| 253 "zh_hant_tw" | 253 "zh_hant_tw" |
| (...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 290 return !IsLocaleNameTranslated("en", locale_name); | 290 return !IsLocaleNameTranslated("en", locale_name); |
| 291 } | 291 } |
| 292 | 292 |
| 293 bool IsLocaleAvailable(const std::string& locale, | 293 bool IsLocaleAvailable(const std::string& locale, |
| 294 const FilePath& locale_path) { | 294 const FilePath& locale_path) { |
| 295 // If locale has any illegal characters in it, we don't want to try to | 295 // If locale has any illegal characters in it, we don't want to try to |
| 296 // load it because it may be pointing outside the locale data file directory. | 296 // load it because it may be pointing outside the locale data file directory. |
| 297 if (!file_util::IsFilenameLegal(ASCIIToUTF16(locale))) | 297 if (!file_util::IsFilenameLegal(ASCIIToUTF16(locale))) |
| 298 return false; | 298 return false; |
| 299 | 299 |
| 300 // IsLocalePartiallyPopulated() can be called here for an early return w/o |
| 301 // checking the resource availability below. It'd help when Chrome is run |
| 302 // under a system locale Chrome is not localized to (e.g.Farsi on Linux), |
| 303 // but it'd slow down the start up time a little bit for locales Chrome is |
| 304 // localized to. So, we don't call it here. |
| 300 if (!l10n_util::IsLocaleSupportedByOS(locale)) | 305 if (!l10n_util::IsLocaleSupportedByOS(locale)) |
| 301 return false; | 306 return false; |
| 302 | 307 |
| 303 FilePath test_path = locale_path; | 308 FilePath test_path = locale_path; |
| 304 test_path = | 309 test_path = |
| 305 test_path.AppendASCII(locale).ReplaceExtension(kLocaleFileExtension); | 310 test_path.AppendASCII(locale).ReplaceExtension(kLocaleFileExtension); |
| 306 return file_util::PathExists(test_path) && SetICUDefaultLocale(locale); | 311 return file_util::PathExists(test_path); |
| 307 } | 312 } |
| 308 | 313 |
| 309 bool CheckAndResolveLocale(const std::string& locale, | 314 bool CheckAndResolveLocale(const std::string& locale, |
| 310 const FilePath& locale_path, | 315 const FilePath& locale_path, |
| 311 std::string* resolved_locale) { | 316 std::string* resolved_locale) { |
| 312 if (IsLocaleAvailable(locale, locale_path)) { | 317 if (IsLocaleAvailable(locale, locale_path)) { |
| 313 *resolved_locale = locale; | 318 *resolved_locale = locale; |
| 314 return true; | 319 return true; |
| 315 } | 320 } |
| 316 // If the locale matches language but not country, use that instead. | 321 // If the locale matches language but not country, use that instead. |
| 317 // TODO(jungshik) : Nothing is done about languages that Chrome | 322 // TODO(jungshik) : Nothing is done about languages that Chrome |
| 318 // does not support but available on Windows. We fall | 323 // does not support but available on Windows. We fall |
| 319 // back to en-US in GetApplicationLocale so that it's a not critical, | 324 // back to en-US in GetApplicationLocale so that it's a not critical, |
| 320 // but we can do better. | 325 // but we can do better. |
| 321 std::string::size_type hyphen_pos = locale.find(L'-'); | 326 std::string::size_type hyphen_pos = locale.find('-'); |
| 322 if (hyphen_pos != std::string::npos && hyphen_pos > 0) { | 327 if (hyphen_pos != std::string::npos && hyphen_pos > 0) { |
| 323 std::string lang(locale, 0, hyphen_pos); | 328 std::string lang(locale, 0, hyphen_pos); |
| 324 std::string region(locale, hyphen_pos + 1); | 329 std::string region(locale, hyphen_pos + 1); |
| 325 std::string tmp_locale(lang); | 330 std::string tmp_locale(lang); |
| 326 // Map es-RR other than es-ES to es-419 (Chrome's Latin American | 331 // Map es-RR other than es-ES to es-419 (Chrome's Latin American |
| 327 // Spanish locale). | 332 // Spanish locale). |
| 328 if (LowerCaseEqualsASCII(lang, "es") && !LowerCaseEqualsASCII(region, "es")) | 333 if (LowerCaseEqualsASCII(lang, "es") && !LowerCaseEqualsASCII(region, "es")) |
| 329 tmp_locale.append("-419"); | 334 tmp_locale.append("-419"); |
| 330 else if (LowerCaseEqualsASCII(lang, "zh")) { | 335 else if (LowerCaseEqualsASCII(lang, "zh")) { |
| 331 // Map zh-HK and zh-MK to zh-TW. Otherwise, zh-FOO is mapped to zh-CN. | 336 // Map zh-HK and zh-MK to zh-TW. Otherwise, zh-FOO is mapped to zh-CN. |
| (...skipping 124 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 456 #elif defined(OS_LINUX) | 461 #elif defined(OS_LINUX) |
| 457 // On Linux, we also check LANGUAGE environment variable, which is supported | 462 // On Linux, we also check LANGUAGE environment variable, which is supported |
| 458 // by gettext to specify a priority list of prefered languages. | 463 // by gettext to specify a priority list of prefered languages. |
| 459 const char* env_language = ::getenv("LANGUAGE"); | 464 const char* env_language = ::getenv("LANGUAGE"); |
| 460 if (env_language) | 465 if (env_language) |
| 461 SplitAndNormalizeLanguageList(env_language, &candidates); | 466 SplitAndNormalizeLanguageList(env_language, &candidates); |
| 462 | 467 |
| 463 // Only fallback to the system locale if LANGUAGE is not specified. | 468 // Only fallback to the system locale if LANGUAGE is not specified. |
| 464 // We emulate gettext's behavior here, which ignores LANG/LC_MESSAGES/LC_ALL | 469 // We emulate gettext's behavior here, which ignores LANG/LC_MESSAGES/LC_ALL |
| 465 // when LANGUAGE is specified. If no language specified in LANGUAGE is valid, | 470 // when LANGUAGE is specified. If no language specified in LANGUAGE is valid, |
| 466 // then just fallback to the default language, which is en-US for us. | 471 // then just fallback to the locale based on LC_ALL/LANG. |
| 467 if (candidates.empty()) | 472 if (candidates.empty()) |
| 468 candidates.push_back(system_locale); | 473 candidates.push_back(system_locale); |
| 469 #endif | 474 #endif |
| 470 | 475 |
| 471 std::vector<std::string>::const_iterator i = candidates.begin(); | 476 std::vector<std::string>::const_iterator i = candidates.begin(); |
| 472 for (; i != candidates.end(); ++i) { | 477 for (; i != candidates.end(); ++i) { |
| 473 if (CheckAndResolveLocale(*i, locale_path, &resolved_locale)) | 478 if (CheckAndResolveLocale(*i, locale_path, &resolved_locale)) { |
| 479 SetICUDefaultLocale(resolved_locale); |
| 474 return resolved_locale; | 480 return resolved_locale; |
| 481 } |
| 475 } | 482 } |
| 476 | 483 |
| 477 // Fallback on en-US. | 484 // Fallback on en-US. |
| 478 const std::string fallback_locale("en-US"); | 485 const std::string fallback_locale("en-US"); |
| 479 if (IsLocaleAvailable(fallback_locale, locale_path)) | 486 if (IsLocaleAvailable(fallback_locale, locale_path)) { |
| 487 SetICUDefaultLocale(fallback_locale); |
| 480 return fallback_locale; | 488 return fallback_locale; |
| 489 } |
| 481 | 490 |
| 482 // No locale data file was found; we shouldn't get here. | 491 // No locale data file was found; we shouldn't get here. |
| 483 NOTREACHED(); | 492 NOTREACHED(); |
| 484 | 493 |
| 485 return std::string(); | 494 return std::string(); |
| 486 | 495 |
| 487 #else // !defined(OS_MACOSX) | 496 #else // !defined(OS_MACOSX) |
| 488 | 497 |
| 489 // Use any override (Cocoa for the browser), otherwise use the command line | 498 // Use any override (Cocoa for the browser), otherwise use the command line |
| 490 // argument. | 499 // argument. |
| 491 std::string app_locale = l10n_util::GetLocaleOverride(); | 500 std::string app_locale = l10n_util::GetLocaleOverride(); |
| 492 if (app_locale.empty()) { | 501 if (app_locale.empty()) { |
| 493 const CommandLine& parsed_command_line = *CommandLine::ForCurrentProcess(); | 502 const CommandLine& parsed_command_line = *CommandLine::ForCurrentProcess(); |
| 494 app_locale = parsed_command_line.GetSwitchValueASCII(switches::kLang); | 503 app_locale = parsed_command_line.GetSwitchValueASCII(switches::kLang); |
| 495 } | 504 } |
| 496 | 505 |
| 497 // The above should handle all of the cases Chrome normally hits, but for some | 506 // The above should handle all of the cases Chrome normally hits, but for some |
| 498 // unit tests, we need something to fall back too. | 507 // unit tests, we need something to fall back too. |
| 499 if (app_locale.empty()) | 508 if (app_locale.empty()) |
| 500 app_locale = "en-US"; | 509 app_locale = "en-US"; |
| 501 | 510 |
| 502 // Windows/Linux call CheckAndResolveLocale which calls IsLocaleAvailable | 511 // Windows/Linux call SetICUDefaultLocale after determining the actual locale |
| 503 // which calls SetICUDefaultLocale to let ICU use the same locale. Mac | 512 // with CheckAndResolveLocal to make ICU APIs work in that locale. |
| 504 // doesn't use a locale directory tree of resources (it uses Mac style | 513 // Mac doesn't use a locale directory tree of resources (it uses Mac style |
| 505 // resources), so mirror that ICU behavior by calling SetICUDefaultLocale | 514 // resources), so mirror the Windows/Linux behavior of calling |
| 506 // directly. | 515 // SetICUDefaultLocale. |
| 507 UBool icu_set = SetICUDefaultLocale(app_locale); | 516 SetICUDefaultLocale(app_locale); |
| 508 DCHECK(icu_set); | |
| 509 return app_locale; | 517 return app_locale; |
| 510 #endif // !defined(OS_MACOSX) | 518 #endif // !defined(OS_MACOSX) |
| 511 } | 519 } |
| 512 | 520 |
| 513 string16 GetDisplayNameForLocale(const std::string& locale_code, | 521 string16 GetDisplayNameForLocale(const std::string& locale_code, |
| 514 const std::string& display_locale, | 522 const std::string& display_locale, |
| 515 bool is_for_ui) { | 523 bool is_for_ui) { |
| 516 UErrorCode error = U_ZERO_ERROR; | 524 UErrorCode error = U_ZERO_ERROR; |
| 517 const int buffer_size = 1024; | 525 const int buffer_size = 1024; |
| 518 | 526 |
| (...skipping 258 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 777 (gtk_dir == GTK_TEXT_DIR_LTR) ? LEFT_TO_RIGHT : RIGHT_TO_LEFT; | 785 (gtk_dir == GTK_TEXT_DIR_LTR) ? LEFT_TO_RIGHT : RIGHT_TO_LEFT; |
| 778 #else | 786 #else |
| 779 const icu::Locale& locale = icu::Locale::getDefault(); | 787 const icu::Locale& locale = icu::Locale::getDefault(); |
| 780 g_text_direction = GetTextDirectionForLocale(locale.getName()); | 788 g_text_direction = GetTextDirectionForLocale(locale.getName()); |
| 781 #endif | 789 #endif |
| 782 } | 790 } |
| 783 return g_text_direction; | 791 return g_text_direction; |
| 784 } | 792 } |
| 785 | 793 |
| 786 TextDirection GetTextDirectionForLocale(const char* locale_name) { | 794 TextDirection GetTextDirectionForLocale(const char* locale_name) { |
| 787 UScriptCode scripts[10]; // 10 scripts should be enough for any locale. | 795 UErrorCode status = U_ZERO_ERROR; |
| 788 UErrorCode error = U_ZERO_ERROR; | 796 ULayoutType layout_dir = uloc_getCharacterOrientation(locale_name, &status); |
| 789 int n = uscript_getCode(locale_name, scripts, 10, &error); | 797 DCHECK(U_SUCCESS(status)); |
| 790 DCHECK(U_SUCCESS(error) && n > 0); | 798 // Treat anything other than RTL as LTR. |
| 791 | 799 return (layout_dir != ULOC_LAYOUT_RTL) ? LEFT_TO_RIGHT : RIGHT_TO_LEFT; |
| 792 // Checking Arabic and Hebrew scripts cover Arabic, Hebrew, Farsi, | |
| 793 // Urdu and Azerbaijani written in Arabic. Syriac script | |
| 794 // (another RTL) is not a living script and we didn't yet localize | |
| 795 // to locales using other living RTL scripts such as Thaana and N'ko. | |
| 796 // TODO(jungshik): Use a new ICU API, uloc_getCharacterOrientation to avoid | |
| 797 // 'hardcoded-comparision' with Arabic and Hebrew scripts once we | |
| 798 // upgrade ICU to 4.0 or later or port it to our copy of ICU. | |
| 799 if (scripts[0] == USCRIPT_ARABIC || scripts[0] == USCRIPT_HEBREW) | |
| 800 return RIGHT_TO_LEFT; | |
| 801 return LEFT_TO_RIGHT; | |
| 802 } | 800 } |
| 803 | 801 |
| 804 TextDirection GetFirstStrongCharacterDirection(const std::wstring& text) { | 802 TextDirection GetFirstStrongCharacterDirection(const std::wstring& text) { |
| 805 #if defined(WCHAR_T_IS_UTF32) | 803 #if defined(WCHAR_T_IS_UTF32) |
| 806 string16 text_utf16 = WideToUTF16(text); | 804 string16 text_utf16 = WideToUTF16(text); |
| 807 const UChar* string = text_utf16.c_str(); | 805 const UChar* string = text_utf16.c_str(); |
| 808 #else | 806 #else |
| 809 const UChar* string = text.c_str(); | 807 const UChar* string = text.c_str(); |
| 810 #endif | 808 #endif |
| 811 size_t length = text.length(); | 809 size_t length = text.length(); |
| (...skipping 248 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1060 } | 1058 } |
| 1061 | 1059 |
| 1062 void BiDiLineIterator::GetLogicalRun(int start, | 1060 void BiDiLineIterator::GetLogicalRun(int start, |
| 1063 int* end, | 1061 int* end, |
| 1064 UBiDiLevel* level) { | 1062 UBiDiLevel* level) { |
| 1065 DCHECK(bidi_ != NULL); | 1063 DCHECK(bidi_ != NULL); |
| 1066 ubidi_getLogicalRun(bidi_, start, end, level); | 1064 ubidi_getLogicalRun(bidi_, start, end, level); |
| 1067 } | 1065 } |
| 1068 | 1066 |
| 1069 } // namespace l10n_util | 1067 } // namespace l10n_util |
| OLD | NEW |