diff options
author | jshin@chromium.org <jshin@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-10-30 00:18:22 +0000 |
---|---|---|
committer | jshin@chromium.org <jshin@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-10-30 00:18:22 +0000 |
commit | c16605de2a5f9fc7c16cb6c185e565e503667165 (patch) | |
tree | 34045b1a4fc73a7fa8329c49d45bd158b8d78fcd /app | |
parent | 405acd1cd89d050b17c965ffa8dba6b8c93966cb (diff) | |
download | chromium_src-c16605de2a5f9fc7c16cb6c185e565e503667165.zip chromium_src-c16605de2a5f9fc7c16cb6c185e565e503667165.tar.gz chromium_src-c16605de2a5f9fc7c16cb6c185e565e503667165.tar.bz2 |
Use GLib to parse environment variables to determine the default locale.
Switch to using GLib, instead of having a Chromium specific implementation, for
parsing environment variables for language preferences for all POSIX systems
that use GTK+. If we have a non-GTK port in the future, we have to resurrect
our custom code.
This will guarantee that UI language selection in Chromium works just like for
all other GTK+ applications, and simplify the code.
While doing this, also do some cleaning-up of the language preferences code and
add a test case to verify that the prioritization is done correctly.
Original CL by Fredrik Roubert at http://codereview.chromium.org/2901004/show
BUG=NONE
TEST=app_unittest with "--gtest_filter=L10nUt*.*Loc*" passes.
Review URL: http://codereview.chromium.org/4217004
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@64524 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'app')
-rw-r--r-- | app/l10n_util.cc | 139 | ||||
-rw-r--r-- | app/l10n_util_unittest.cc | 48 |
2 files changed, 83 insertions, 104 deletions
diff --git a/app/l10n_util.cc b/app/l10n_util.cc index 27131f2..375f3b6 100644 --- a/app/l10n_util.cc +++ b/app/l10n_util.cc @@ -4,6 +4,10 @@ #include "app/l10n_util.h" +#if defined(TOOLKIT_USES_GTK) +#include <glib/gutils.h> +#endif + #include <cstdlib> #include "app/app_paths.h" @@ -305,59 +309,6 @@ bool CheckAndResolveLocale(const std::string& locale, return false; } - -// Get the locale of the operating system. The return value is of the form -// language[-country] (e.g., en-US) where the language is the 2 letter code from -// ISO-639. -std::string GetSystemLocale() { - std::string language, region; - base::i18n::GetLanguageAndRegionFromOS(&language, ®ion); - std::string ret; - if (!language.empty()) - ret.append(language); - if (!region.empty()) { - ret.append("-"); - ret.append(region); - } - return ret; -} -#endif - -#if defined(OS_POSIX) && !defined(OS_MACOSX) -// 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; - base::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 // On Linux, the text layout engine Pango determines paragraph directionality @@ -379,43 +330,71 @@ void AdjustParagraphDirectionality(string16* paragraph) { namespace l10n_util { std::string GetApplicationLocale(const std::string& pref_locale) { -#if !defined(OS_MACOSX) +#if defined(OS_MACOSX) + + // Use any override (Cocoa for the browser), otherwise use the preference + // passed to the function. + std::string app_locale = l10n_util::GetLocaleOverride(); + if (app_locale.empty()) + app_locale = pref_locale; + + // The above should handle all of the cases Chrome normally hits, but for some + // unit tests, we need something to fall back too. + if (app_locale.empty()) + app_locale = "en-US"; + + // Windows/Linux call SetICUDefaultLocale after determining the actual locale + // with CheckAndResolveLocal to make ICU APIs work in that locale. + // Mac doesn't use a locale directory tree of resources (it uses Mac style + // resources), so mirror the Windows/Linux behavior of calling + // SetICUDefaultLocale. + base::i18n::SetICUDefaultLocale(app_locale); + return app_locale; + +#else + 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, we only // look at the LC_*/LANG environment variables. We do, however, pass --lang // to renderer and plugin processes so they know what language the parent // process decided to use. + #if defined(OS_WIN) + // First, try the preference value. if (!pref_locale.empty()) candidates.push_back(pref_locale); // Next, try the system locale. - candidates.push_back(system_locale); + candidates.push_back(base::i18n::GetConfiguredLocale()); #elif defined(OS_CHROMEOS) + // On ChromeOS, use the application locale preference. if (!pref_locale.empty()) candidates.push_back(pref_locale); -#elif defined(OS_POSIX) - // On POSIX, 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 locale based on LC_ALL/LANG. - if (candidates.empty()) - candidates.push_back(system_locale); +#elif defined(OS_POSIX) && defined(TOOLKIT_USES_GTK) + + // GLib implements correct environment variable parsing with + // the precedence order: LANGUAGE, LC_ALL, LC_MESSAGES and LANG. + // We used to use our custom parsing code along with ICU for this purpose. + // If we have a port that does not depend on GTK, we have to + // restore our custom code for that port. + const char* const* languages = g_get_language_names(); + DCHECK(languages); // A valid pointer is guaranteed. + DCHECK(*languages); // At least one entry, "C", is guaranteed. + + for (; *languages != NULL; ++languages) { + candidates.push_back(base::i18n::GetCanonicalLocale(*languages)); + } + +#else +#error Unsupported platform, see build/build_config.h #endif std::vector<std::string>::const_iterator i = candidates.begin(); @@ -438,27 +417,7 @@ std::string GetApplicationLocale(const std::string& pref_locale) { return std::string(); -#else // !defined(OS_MACOSX) - - // Use any override (Cocoa for the browser), otherwise use the preference - // passed to the function. - std::string app_locale = l10n_util::GetLocaleOverride(); - if (app_locale.empty()) - app_locale = pref_locale; - - // The above should handle all of the cases Chrome normally hits, but for some - // unit tests, we need something to fall back too. - if (app_locale.empty()) - app_locale = "en-US"; - - // Windows/Linux call SetICUDefaultLocale after determining the actual locale - // with CheckAndResolveLocal to make ICU APIs work in that locale. - // Mac doesn't use a locale directory tree of resources (it uses Mac style - // resources), so mirror the Windows/Linux behavior of calling - // SetICUDefaultLocale. - base::i18n::SetICUDefaultLocale(app_locale); - return app_locale; -#endif // !defined(OS_MACOSX) +#endif } string16 GetDisplayNameForLocale(const std::string& locale, diff --git a/app/l10n_util_unittest.cc b/app/l10n_util_unittest.cc index 4a15903..8d48813 100644 --- a/app/l10n_util_unittest.cc +++ b/app/l10n_util_unittest.cc @@ -100,7 +100,17 @@ void SetICUDefaultLocale(const std::string& locale_string) { // The meaning of that API, on the Mac, is "the locale used by Cocoa's main // nib file", which clearly can't be stubbed by a test app that doesn't use // Cocoa. + +void SetDefaultLocaleForTest(const std::string& tag, base::Environment* env) { +#if defined(OS_POSIX) && !defined(OS_CHROMEOS) + env->SetVar("LANGUAGE", tag); +#else + SetICUDefaultLocale(tag); +#endif +} + TEST_F(L10nUtilTest, GetAppLocale) { + scoped_ptr<base::Environment> env; // Use a temporary locale dir so we don't have to actually build the locale // dlls for this test. FilePath orig_locale_dir; @@ -140,7 +150,7 @@ TEST_F(L10nUtilTest, GetAppLocale) { icu::Locale locale = icu::Locale::getDefault(); #if defined(OS_POSIX) && !defined(OS_CHROMEOS) - scoped_ptr<base::Environment> env(base::Environment::Create()); + env.reset(base::Environment::Create()); // Test the support of LANGUAGE environment variable. SetICUDefaultLocale("en-US"); @@ -163,15 +173,25 @@ TEST_F(L10nUtilTest, GetAppLocale) { env->SetVar("LANGUAGE", "/fr:zh_CN"); EXPECT_EQ("zh-CN", l10n_util::GetApplicationLocale("")); - // Make sure the follow tests won't be affected by LANGUAGE environment - // variable. + // Test prioritization of the different environment variables. + env->SetVar("LANGUAGE", "fr"); + env->SetVar("LC_ALL", "es"); + env->SetVar("LC_MESSAGES", "he"); + env->SetVar("LANG", "nb"); + EXPECT_EQ("fr", l10n_util::GetApplicationLocale("")); env->UnSetVar("LANGUAGE"); + EXPECT_EQ("es", l10n_util::GetApplicationLocale("")); + env->UnSetVar("LC_ALL"); + EXPECT_EQ("he", l10n_util::GetApplicationLocale("")); + env->UnSetVar("LC_MESSAGES"); + EXPECT_EQ("nb", l10n_util::GetApplicationLocale("")); + env->UnSetVar("LANG"); #endif // defined(OS_POSIX) && !defined(OS_CHROMEOS) - SetICUDefaultLocale("en-US"); + SetDefaultLocaleForTest("en-US", env.get()); EXPECT_EQ("en-US", l10n_util::GetApplicationLocale("")); - SetICUDefaultLocale("xx"); + SetDefaultLocaleForTest("xx", env.get()); EXPECT_EQ("en-US", l10n_util::GetApplicationLocale("")); #if defined(OS_CHROMEOS) @@ -184,31 +204,31 @@ TEST_F(L10nUtilTest, GetAppLocale) { EXPECT_EQ("en-GB", l10n_util::GetApplicationLocale("en-GB")); #else // defined(OS_CHROMEOS) - SetICUDefaultLocale("en-GB"); + SetDefaultLocaleForTest("en-GB", env.get()); EXPECT_EQ("en-GB", l10n_util::GetApplicationLocale("")); - SetICUDefaultLocale("fr-CA"); + SetDefaultLocaleForTest("fr-CA", env.get()); EXPECT_EQ("fr", l10n_util::GetApplicationLocale("")); - SetICUDefaultLocale("es-MX"); + SetDefaultLocaleForTest("es-MX", env.get()); EXPECT_EQ("es-419", l10n_util::GetApplicationLocale("")); - SetICUDefaultLocale("es-AR"); + SetDefaultLocaleForTest("es-AR", env.get()); EXPECT_EQ("es-419", l10n_util::GetApplicationLocale("")); - SetICUDefaultLocale("es-ES"); + SetDefaultLocaleForTest("es-ES", env.get()); EXPECT_EQ("es", l10n_util::GetApplicationLocale("")); - SetICUDefaultLocale("es"); + SetDefaultLocaleForTest("es", env.get()); EXPECT_EQ("es", l10n_util::GetApplicationLocale("")); - SetICUDefaultLocale("zh-HK"); + SetDefaultLocaleForTest("zh-HK", env.get()); EXPECT_EQ("zh-TW", l10n_util::GetApplicationLocale("")); - SetICUDefaultLocale("zh-MK"); + SetDefaultLocaleForTest("zh-MK", env.get()); EXPECT_EQ("zh-TW", l10n_util::GetApplicationLocale("")); - SetICUDefaultLocale("zh-SG"); + SetDefaultLocaleForTest("zh-SG", env.get()); EXPECT_EQ("zh-CN", l10n_util::GetApplicationLocale("")); #endif // defined (OS_CHROMEOS) |