diff options
author | suzhe@chromium.org <suzhe@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-09-30 14:26:59 +0000 |
---|---|---|
committer | suzhe@chromium.org <suzhe@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-09-30 14:26:59 +0000 |
commit | c7c9b8ff8028602c0f39f4e12af4976f06cc1f30 (patch) | |
tree | 2d0e1f89c47c7ca4594c0373bb1822d98e076b01 /app | |
parent | 2474031c9712cceaa0925aef2226e2acf82b579a (diff) | |
download | chromium_src-c7c9b8ff8028602c0f39f4e12af4976f06cc1f30.zip chromium_src-c7c9b8ff8028602c0f39f4e12af4976f06cc1f30.tar.gz chromium_src-c7c9b8ff8028602c0f39f4e12af4976f06cc1f30.tar.bz2 |
[Linux] Supports the LANGUAGE environment variable.
This CL adds the support for the LANGUAGE environment variable, which is supported by gettext based applications for specifying a priority list of user prefered locales for UI messages translation.
Unlike gettext based applications, which support using different locales for messages translation and other locale categories, like LC_CTYPE, LC_COLLATE, LC_TIME, etc., chromium supports only one application locale for all localization operations.
This CL adds the support of specifying the application locale by LANGUAGE env variable, but doesn't make chromium to support above mentioned behavior of gettext based applications.
BUG=21080: chromium doesn't honor locale fallbacks
TEST=Launch chrome with LANGUAGE=br:fr_FR:fr, French locale shall be used by chrome, as br is not supported by chrome yet.
Review URL: http://codereview.chromium.org/236001
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@27608 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'app')
-rw-r--r-- | app/l10n_util.cc | 78 | ||||
-rw-r--r-- | app/l10n_util_unittest.cc | 32 |
2 files changed, 96 insertions, 14 deletions
diff --git a/app/l10n_util.cc b/app/l10n_util.cc index f23de27..2afdf2b 100644 --- a/app/l10n_util.cc +++ b/app/l10n_util.cc @@ -4,6 +4,7 @@ #include "app/l10n_util.h" +#include <cstdlib> #include "app/app_paths.h" #include "app/app_switches.h" #include "app/gfx/canvas.h" @@ -376,6 +377,43 @@ std::string GetSystemLocale() { return ret; } +#if defined(OS_LINUX) +// Split and normalize the language list specified by LANGUAGE environment. +// LANGUAGE environment specifies a priority list of user prefered locales for +// application UI messages. Locales are separated by ':' character. The format +// of a locale is: language[_territory[.codeset]][@modifier] +// +// This function splits the language list and normalizes each locale into +// language[-territory] format, eg. fr, zh-CN, etc. +void SplitAndNormalizeLanguageList(const std::string& env_language, + std::vector<std::string>* result) { + std::vector<std::string> langs; + SplitString(env_language, ':', &langs); + std::vector<std::string>::iterator i = langs.begin(); + for (; i != langs.end(); ++i) { + size_t end_pos = i->find_first_of(".@"); + // Erase encoding and modifier part. + if (end_pos != std::string::npos) + i->erase(end_pos); + + if (!i->empty()) { + std::string locale; + size_t sep = i->find_first_of("_-"); + if (sep != std::string::npos) { + // language part is always in lower case. + locale = StringToLowerASCII(i->substr(0, sep)); + locale.append("-"); + // territory part is always in upper case. + locale.append(StringToUpperASCII(i->substr(sep + 1))); + } else { + locale = StringToLowerASCII(*i); + } + result->push_back(locale); + } + } +} +#endif + } // namespace namespace l10n_util { @@ -392,6 +430,8 @@ std::string GetApplicationLocale(const std::wstring& pref_locale) { FilePath locale_path; PathService::Get(app::DIR_LOCALES, &locale_path); std::string resolved_locale; + std::vector<std::string> candidates; + const std::string system_locale = GetSystemLocale(); // We only use --lang and the app pref on Windows. On Linux/Mac, we only // look at the LC_*/LANG environment variables. We do, however, pass --lang @@ -402,23 +442,35 @@ std::string GetApplicationLocale(const std::wstring& pref_locale) { const CommandLine& parsed_command_line = *CommandLine::ForCurrentProcess(); const std::string& lang_arg = WideToASCII( parsed_command_line.GetSwitchValue(switches::kLang)); - if (!lang_arg.empty()) { - if (CheckAndResolveLocale(lang_arg, locale_path, &resolved_locale)) - return resolved_locale; - } + if (!lang_arg.empty()) + candidates.push_back(lang_arg); // Second, try user prefs. - if (!pref_locale.empty()) { - if (CheckAndResolveLocale(WideToASCII(pref_locale), - locale_path, &resolved_locale)) - return resolved_locale; - } -#endif + if (!pref_locale.empty()) + candidates.push_back(WideToASCII(pref_locale)); // Next, try the system locale. - const std::string system_locale = GetSystemLocale(); - if (CheckAndResolveLocale(system_locale, locale_path, &resolved_locale)) - return resolved_locale; + candidates.push_back(system_locale); +#elif defined(OS_LINUX) + // On Linux, we also check LANGUAGE environment variable, which is supported + // by gettext to specify a priority list of prefered languages. + const char* env_language = ::getenv("LANGUAGE"); + if (env_language) + SplitAndNormalizeLanguageList(env_language, &candidates); + + // Only fallback to the system locale if LANGUAGE is not specified. + // We emulate gettext's behavior here, which ignores LANG/LC_MESSAGES/LC_ALL + // when LANGUAGE is specified. If no language specified in LANGUAGE is valid, + // then just fallback to the default language, which is en-US for us. + if (candidates.empty()) + candidates.push_back(system_locale); +#endif + + std::vector<std::string>::const_iterator i = candidates.begin(); + for (; i != candidates.end(); ++i) { + if (CheckAndResolveLocale(*i, locale_path, &resolved_locale)) + return resolved_locale; + } // Fallback on en-US. const std::string fallback_locale("en-US"); diff --git a/app/l10n_util_unittest.cc b/app/l10n_util_unittest.cc index c9409fe..0298988 100644 --- a/app/l10n_util_unittest.cc +++ b/app/l10n_util_unittest.cc @@ -4,6 +4,10 @@ #include "build/build_config.h" +#if defined(OS_LINUX) +#include <cstdlib> +#endif + #include "app/app_paths.h" #include "app/l10n_util.h" #if !defined(OS_MACOSX) @@ -136,6 +140,33 @@ TEST_F(L10nUtilTest, GetAppLocale) { // Keep a copy of ICU's default locale before we overwrite it. icu::Locale locale = icu::Locale::getDefault(); +#if defined(OS_LINUX) + // Test the support of LANGUAGE environment variable. + SetICUDefaultLocale("en-US"); + ::setenv("LANGUAGE", "xx:fr_CA", 1); + EXPECT_EQ("fr", l10n_util::GetApplicationLocale(L"")); + + ::setenv("LANGUAGE", "xx:yy:en_gb.utf-8@quot", 1); + EXPECT_EQ("en-GB", l10n_util::GetApplicationLocale(L"")); + + ::setenv("LANGUAGE", "xx:zh-hk", 1); + EXPECT_EQ("zh-TW", l10n_util::GetApplicationLocale(L"")); + + // We emulate gettext's behavior here, which ignores LANG/LC_MESSAGES/LC_ALL + // when LANGUAGE is specified. If no language specified in LANGUAGE is valid, + // then just fallback to the default language, which is en-US for us. + SetICUDefaultLocale("fr-FR"); + ::setenv("LANGUAGE", "xx:yy", 1); + EXPECT_EQ("en-US", l10n_util::GetApplicationLocale(L"")); + + ::setenv("LANGUAGE", "/fr:zh_CN", 1); + EXPECT_EQ("zh-CN", l10n_util::GetApplicationLocale(L"")); + + // Make sure the follow tests won't be affected by LANGUAGE environment + // variable. + ::unsetenv("LANGUAGE"); +#endif + SetICUDefaultLocale("en-US"); EXPECT_EQ("en-US", l10n_util::GetApplicationLocale(L"")); @@ -479,4 +510,3 @@ TEST_F(L10nUtilTest, UpperLower) { result = l10n_util::ToUpper(mixed); EXPECT_EQ(result, expected_upper); } - |