summaryrefslogtreecommitdiffstats
path: root/base/win
diff options
context:
space:
mode:
authorgrt@chromium.org <grt@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-11-16 15:28:45 +0000
committergrt@chromium.org <grt@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-11-16 15:28:45 +0000
commit337ca0791390f606472d7530abf7603ad2f24ca8 (patch)
tree660625c6c058dab2acee91549ba258258bdc70f5 /base/win
parent40519596601f58e38c22b3ff9f2d8a47301e7c25 (diff)
downloadchromium_src-337ca0791390f606472d7530abf7603ad2f24ca8.zip
chromium_src-337ca0791390f606472d7530abf7603ad2f24ca8.tar.gz
chromium_src-337ca0791390f606472d7530abf7603ad2f24ca8.tar.bz2
The UI language rather than the locale is now used to pick Chrome's language on Windows. (Also fixed some unrelated lint errors.) With this change, l10n_util::GetApplicationLocale first checks for an override of the "configured locale" (in base::i18n) containing the list of preferred Windows UI languages. The browser triggers an override early in startup before the ApplicationLocale is determined. In effect, the browser no longer uses ICU on Windows for language detection. (This locale override mechanism is borrowed from the OS X port.)
Changes in Chrome Frame are largely a refactor, as some Win32 code in there has been moved into base/win. Also cleaned up language selection in installer_util so that the proper language is chosen for the EULA, installer messages, and shortcuts. In so doing, replaced hand-crafted lists of supported languages with either auto-generated lists (static consts) or logic so that the addition of translations in the future doesn't require code motion (that being said, there may be reason to update the alias and/or wildcard tables in language_selector.cc). In so doing, this change unlocks Amharic, Farsi, and Swahili translations for installer messages and shortcuts. BUG=39986,40496,26470 TEST=New MUI/Win32 calls are tested in base/win/i18n_unittest.cc. To test the overall functionality, uninstall Chrome, remove intl.app_locale user pref, switch to a supported display language (via the "Keyboards and Languages" tab of Win7's "Regional and Language" control panel, and install with { "distribution": { "require_eula": true } } in master_preferences (via -installerdata arg to setup.exe). If all goes well, both EULA and outer frame are in the same language as Windows. Also, from gwilson: "Install system-level Chrome in audit mode on a new machine, then go through the out-of-box-experience, select a language, and the in -product EULA (triggered by "require_eula" : true) and Chrome's UI should be in the language that the user selected." Review URL: http://codereview.chromium.org/4139010 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@66275 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'base/win')
-rw-r--r--base/win/i18n.cc169
-rw-r--r--base/win/i18n.h32
-rw-r--r--base/win/i18n_unittest.cc42
3 files changed, 243 insertions, 0 deletions
diff --git a/base/win/i18n.cc b/base/win/i18n.cc
new file mode 100644
index 0000000..59480f2
--- /dev/null
+++ b/base/win/i18n.cc
@@ -0,0 +1,169 @@
+// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/win/i18n.h"
+
+#include <windows.h>
+
+#include "base/logging.h"
+
+namespace {
+
+// Keep this enum in sync with kLanguageFunctionNames.
+enum LanguageFunction {
+ SYSTEM_LANGUAGES,
+ USER_LANGUAGES,
+ PROCESS_LANGUAGES,
+ THREAD_LANGUAGES,
+ NUM_FUNCTIONS
+};
+
+const char kSystemLanguagesFunctionName[] = "GetSystemPreferredUILanguages";
+const char kUserLanguagesFunctionName[] = "GetUserPreferredUILanguages";
+const char kProcessLanguagesFunctionName[] = "GetProcessPreferredUILanguages";
+const char kThreadLanguagesFunctionName[] = "GetThreadPreferredUILanguages";
+
+// Keep this array in sync with enum LanguageFunction.
+const char *const kLanguageFunctionNames[] = {
+ &kSystemLanguagesFunctionName[0],
+ &kUserLanguagesFunctionName[0],
+ &kProcessLanguagesFunctionName[0],
+ &kThreadLanguagesFunctionName[0]
+};
+
+COMPILE_ASSERT(NUM_FUNCTIONS == arraysize(kLanguageFunctionNames),
+ language_function_enum_and_names_out_of_sync);
+
+// Calls one of the MUI Get*PreferredUILanguages functions, placing the result
+// in |languages|. |function| identifies the function to call and |flags| is
+// the function-specific flags (callers must not specify MUI_LANGUAGE_ID or
+// MUI_LANGUAGE_NAME). Returns true if at least one language is placed in
+// |languages|.
+bool GetMUIPreferredUILanguageList(LanguageFunction function, ULONG flags,
+ std::vector<wchar_t>* languages) {
+ DCHECK(0 <= function && NUM_FUNCTIONS > function);
+ DCHECK_EQ(0U, (flags & (MUI_LANGUAGE_ID | MUI_LANGUAGE_NAME)));
+ DCHECK(languages);
+
+ HMODULE kernel32 = GetModuleHandle(L"kernel32.dll");
+ if (NULL != kernel32) {
+ typedef BOOL (WINAPI* GetPreferredUILanguages_Fn)(
+ DWORD, PULONG, PZZWSTR, PULONG);
+ GetPreferredUILanguages_Fn get_preferred_ui_languages =
+ reinterpret_cast<GetPreferredUILanguages_Fn>(
+ GetProcAddress(kernel32, kLanguageFunctionNames[function]));
+ if (NULL != get_preferred_ui_languages) {
+ const ULONG call_flags = flags | MUI_LANGUAGE_NAME;
+ ULONG language_count = 0;
+ ULONG buffer_length = 0;
+ if (get_preferred_ui_languages(call_flags, &language_count, NULL,
+ &buffer_length) &&
+ 0 != buffer_length) {
+ languages->resize(buffer_length);
+ if (get_preferred_ui_languages(call_flags, &language_count,
+ &(*languages)[0], &buffer_length) &&
+ 0 != language_count) {
+ DCHECK(languages->size() == buffer_length);
+ return true;
+ } else {
+ DPCHECK(0 == language_count)
+ << "Failed getting preferred UI languages.";
+ }
+ } else {
+ DPCHECK(0 == buffer_length)
+ << "Failed getting size of preferred UI languages.";
+ }
+ } else {
+ VLOG(2) << "MUI not available.";
+ }
+ } else {
+ NOTREACHED() << "kernel32.dll not found.";
+ }
+
+ return false;
+}
+
+bool GetUserDefaultUILanguage(std::wstring* language, std::wstring* region) {
+ DCHECK(language);
+
+ LANGID lang_id = ::GetUserDefaultUILanguage();
+ if (LOCALE_CUSTOM_UI_DEFAULT != lang_id) {
+ const LCID locale_id = MAKELCID(lang_id, SORT_DEFAULT);
+ // max size for LOCALE_SISO639LANGNAME and LOCALE_SISO3166CTRYNAME is 9
+ wchar_t result_buffer[9];
+ int result_length =
+ GetLocaleInfo(locale_id, LOCALE_SISO639LANGNAME, &result_buffer[0],
+ arraysize(result_buffer));
+ DPCHECK(0 != result_length) << "Failed getting language id";
+ if (1 < result_length) {
+ language->assign(&result_buffer[0], result_length - 1);
+ region->clear();
+ if (SUBLANG_NEUTRAL != SUBLANGID(lang_id)) {
+ result_length =
+ GetLocaleInfo(locale_id, LOCALE_SISO3166CTRYNAME, &result_buffer[0],
+ arraysize(result_buffer));
+ DPCHECK(0 != result_length) << "Failed getting region id";
+ if (1 < result_length)
+ region->assign(&result_buffer[0], result_length - 1);
+ }
+ return true;
+ }
+ } else {
+ // This is entirely unexpected on pre-Vista, which is the only time we
+ // should try GetUserDefaultUILanguage anyway.
+ NOTREACHED() << "Cannot determine language for a supplemental locale.";
+ }
+ return false;
+}
+
+bool GetPreferredUILanguageList(LanguageFunction function, ULONG flags,
+ std::vector<std::wstring>* languages) {
+ std::vector<wchar_t> buffer;
+ std::wstring language;
+ std::wstring region;
+
+ if (GetMUIPreferredUILanguageList(function, flags, &buffer)) {
+ std::vector<wchar_t>::const_iterator scan = buffer.begin();
+ language.assign(&*scan);
+ while (!language.empty()) {
+ languages->push_back(language);
+ scan += language.size() + 1;
+ language.assign(&*scan);
+ }
+ } else if (GetUserDefaultUILanguage(&language, &region)) {
+ // Mimic the MUI behavior of putting the neutral version of the lang after
+ // the regional one (e.g., "fr-CA, fr").
+ if (!region.empty())
+ languages->push_back(std::wstring(language)
+ .append(1, L'-')
+ .append(region));
+ languages->push_back(language);
+ } else {
+ return false;
+ }
+
+ return true;
+}
+
+} // namespace
+
+namespace base {
+namespace win {
+namespace i18n {
+
+bool GetUserPreferredUILanguageList(std::vector<std::wstring>* languages) {
+ DCHECK(languages);
+ return GetPreferredUILanguageList(USER_LANGUAGES, 0, languages);
+}
+
+bool GetThreadPreferredUILanguageList(std::vector<std::wstring>* languages) {
+ DCHECK(languages);
+ return GetPreferredUILanguageList(
+ THREAD_LANGUAGES, MUI_MERGE_SYSTEM_FALLBACK | MUI_MERGE_USER_FALLBACK,
+ languages);
+}
+
+} // namespace i18n
+} // namespace win
+} // namespace base
diff --git a/base/win/i18n.h b/base/win/i18n.h
new file mode 100644
index 0000000..ba0f74d
--- /dev/null
+++ b/base/win/i18n.h
@@ -0,0 +1,32 @@
+// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_WIN_I18N_H_
+#define BASE_WIN_I18N_H_
+#pragma once
+
+#include <string>
+#include <vector>
+
+#include "base/basictypes.h"
+
+namespace base {
+namespace win {
+namespace i18n {
+
+// Adds to |languages| the list of user preferred UI languages from MUI, if
+// available, falling-back on the user default UI language otherwise. Returns
+// true if at least one language is added.
+bool GetUserPreferredUILanguageList(std::vector<std::wstring>* languages);
+
+// Adds to |languages| the list of thread, process, user, and system preferred
+// UI languages from MUI, if available, falling-back on the user default UI
+// language otherwise. Returns true if at least one language is added.
+bool GetThreadPreferredUILanguageList(std::vector<std::wstring>* languages);
+
+} // namespace i18n
+} // namespace win
+} // namespace base
+
+#endif // BASE_WIN_I18N_H_
diff --git a/base/win/i18n_unittest.cc b/base/win/i18n_unittest.cc
new file mode 100644
index 0000000..781fc39
--- /dev/null
+++ b/base/win/i18n_unittest.cc
@@ -0,0 +1,42 @@
+// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// This file contains unit tests for Windows internationalization funcs.
+
+#include "testing/gtest/include/gtest/gtest.h"
+
+#include "base/win/i18n.h"
+#include "base/win/windows_version.h"
+
+namespace base {
+namespace win {
+namespace i18n {
+
+// Tests that at least one user preferred UI language can be obtained.
+TEST(I18NTest, GetUserPreferredUILanguageList) {
+ std::vector<std::wstring> languages;
+ EXPECT_TRUE(GetUserPreferredUILanguageList(&languages));
+ EXPECT_NE(static_cast<std::vector<std::wstring>::size_type>(0),
+ languages.size());
+ for (std::vector<std::wstring>::const_iterator scan = languages.begin(),
+ end = languages.end(); scan != end; ++scan) {
+ EXPECT_FALSE((*scan).empty());
+ }
+}
+
+// Tests that at least one thread preferred UI language can be obtained.
+TEST(I18NTest, GetThreadPreferredUILanguageList) {
+ std::vector<std::wstring> languages;
+ EXPECT_TRUE(GetThreadPreferredUILanguageList(&languages));
+ EXPECT_NE(static_cast<std::vector<std::wstring>::size_type>(0),
+ languages.size());
+ for (std::vector<std::wstring>::const_iterator scan = languages.begin(),
+ end = languages.end(); scan != end; ++scan) {
+ EXPECT_FALSE((*scan).empty());
+ }
+}
+
+} // namespace i18n
+} // namespace win
+} // namespace base