diff options
Diffstat (limited to 'base')
-rw-r--r-- | base/base.gyp | 1 | ||||
-rw-r--r-- | base/base.gypi | 2 | ||||
-rw-r--r-- | base/i18n/rtl.cc | 16 | ||||
-rw-r--r-- | base/i18n/rtl.h | 7 | ||||
-rw-r--r-- | base/win/i18n.cc | 169 | ||||
-rw-r--r-- | base/win/i18n.h | 32 | ||||
-rw-r--r-- | base/win/i18n_unittest.cc | 42 |
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, ®ion)) { + // 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 |