summaryrefslogtreecommitdiffstats
path: root/base
diff options
context:
space:
mode:
Diffstat (limited to 'base')
-rw-r--r--base/base.gyp1
-rw-r--r--base/base.gypi2
-rw-r--r--base/i18n/rtl.cc16
-rw-r--r--base/i18n/rtl.h7
-rw-r--r--base/win/i18n.cc169
-rw-r--r--base/win/i18n.h32
-rw-r--r--base/win/i18n_unittest.cc42
7 files changed, 248 insertions, 21 deletions
diff --git a/base/base.gyp b/base/base.gyp
index 6a03b67..0c3918f 100644
--- a/base/base.gyp
+++ b/base/base.gyp
@@ -164,6 +164,7 @@
'win/event_trace_consumer_unittest.cc',
'win/event_trace_controller_unittest.cc',
'win/event_trace_provider_unittest.cc',
+ 'win/i18n_unittest.cc',
'win/pe_image_unittest.cc',
'win/registry_unittest.cc',
'win/scoped_bstr_unittest.cc',
diff --git a/base/base.gypi b/base/base.gypi
index a395299..a90a451 100644
--- a/base/base.gypi
+++ b/base/base.gypi
@@ -294,6 +294,8 @@
'watchdog.h',
'weak_ptr.cc',
'weak_ptr.h',
+ 'win/i18n.cc',
+ 'win/i18n.h',
'win/pe_image.cc',
'win/event_trace_consumer.h',
'win/event_trace_controller.cc',
diff --git a/base/i18n/rtl.cc b/base/i18n/rtl.cc
index 9ff12d8..0881fb7 100644
--- a/base/i18n/rtl.cc
+++ b/base/i18n/rtl.cc
@@ -44,22 +44,6 @@ namespace i18n {
// Represents the locale-specific ICU text direction.
static TextDirection g_icu_text_direction = UNKNOWN_DIRECTION;
-#if defined(OS_WIN)
-void GetLanguageAndRegionFromOS(std::string* lang, std::string* region) {
- // Later we may have to change this to be OS-dependent so that
- // it's not affected by ICU's default locale. It's all right
- // to do this way because SetICUDefaultLocale is internal
- // to this file and we know that it's not yet called when this function
- // is called.
- const icu::Locale& locale = icu::Locale::getDefault();
- const char* language = locale.getLanguage();
- const char* country = locale.getCountry();
- DCHECK(language);
- *lang = language;
- *region = country;
-}
-#endif
-
// Convert the ICU default locale to a string.
std::string GetConfiguredLocale() {
return GetLocaleString(icu::Locale::getDefault());
diff --git a/base/i18n/rtl.h b/base/i18n/rtl.h
index 52b1a2b..ed0882f 100644
--- a/base/i18n/rtl.h
+++ b/base/i18n/rtl.h
@@ -6,6 +6,8 @@
#define BASE_I18N_RTL_H_
#pragma once
+#include <string>
+
#include "base/compiler_specific.h"
#include "base/string16.h"
#include "build/build_config.h"
@@ -29,11 +31,6 @@ enum TextDirection {
LEFT_TO_RIGHT,
};
-#if defined(OS_WIN)
-// Get language and region from the OS. Used by Chrome Frame.
-void GetLanguageAndRegionFromOS(std::string* lang, std::string* region);
-#endif
-
// Get the locale that the currently running process has been configured to use.
// The return value is of the form language[-country] (e.g., en-US) where the
// language is the 2 or 3 letter code from ISO-639.
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