Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(789)

Unified Diff: chrome/browser/ui/webui/chromeos/login/l10n_util.cc

Issue 397723002: Extract l10n-related parts of NetworkScreenHandler to a helper file (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Derive list of input methods from actual locale, not requested locale. This is how it used to work … Created 6 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: chrome/browser/ui/webui/chromeos/login/l10n_util.cc
diff --git a/chrome/browser/ui/webui/chromeos/login/l10n_util.cc b/chrome/browser/ui/webui/chromeos/login/l10n_util.cc
new file mode 100644
index 0000000000000000000000000000000000000000..6d1cf7b61a7c1b1cfd5fdb374e9e1909e2b83004
--- /dev/null
+++ b/chrome/browser/ui/webui/chromeos/login/l10n_util.cc
@@ -0,0 +1,407 @@
+// Copyright 2014 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 "chrome/browser/ui/webui/chromeos/login/l10n_util.h"
+
+#include <algorithm>
+#include <iterator>
+#include <map>
+#include <set>
+#include <utility>
+
+#include "base/basictypes.h"
+#include "base/i18n/rtl.h"
+#include "base/logging.h"
+#include "base/strings/string16.h"
+#include "base/strings/stringprintf.h"
+#include "base/strings/utf_string_conversions.h"
+#include "base/values.h"
+#include "chrome/browser/browser_process.h"
+#include "chrome/browser/chromeos/customization_document.h"
+#include "chrome/browser/chromeos/input_method/input_method_util.h"
+#include "chromeos/ime/component_extension_ime_manager.h"
+#include "chromeos/ime/input_method_descriptor.h"
+#include "chromeos/ime/input_method_manager.h"
+#include "grit/generated_resources.h"
+#include "ui/base/l10n/l10n_util.h"
+
+namespace chromeos {
+
+namespace {
+
+base::DictionaryValue* CreateInputMethodsEntry(
+ const input_method::InputMethodDescriptor& method,
+ const std::string selected) {
+ input_method::InputMethodUtil* util =
+ input_method::InputMethodManager::Get()->GetInputMethodUtil();
+ const std::string& ime_id = method.id();
+ scoped_ptr<base::DictionaryValue> input_method(new base::DictionaryValue);
+ input_method->SetString("value", ime_id);
+ input_method->SetString("title", util->GetInputMethodLongName(method));
+ input_method->SetBoolean("selected", ime_id == selected);
+ return input_method.release();
+}
+
+// Returns true if element was inserted.
+bool InsertString(const std::string& str, std::set<std::string>& to) {
+ const std::pair<std::set<std::string>::iterator, bool> result =
+ to.insert(str);
+ return result.second;
+}
+
+void AddOptgroupOtherLayouts(base::ListValue* input_methods_list) {
+ scoped_ptr<base::DictionaryValue> optgroup(new base::DictionaryValue);
+ optgroup->SetString(
+ "optionGroupName",
+ l10n_util::GetStringUTF16(IDS_OOBE_OTHER_KEYBOARD_LAYOUTS));
+ input_methods_list->Append(optgroup.release());
+}
+
+// TODO(zork): Remove this blacklist when fonts are added to Chrome OS.
+// see: crbug.com/240586
+bool IsBlacklisted(const std::string& language_code) {
+ return language_code == "si"; // Sinhala
+}
+
+// Gets the list of languages with |descriptors| based on |base_language_codes|.
+// The |most_relevant_language_codes| will be first in the list. If
+// |insert_divider| is true, an entry with its "code" attribute set to
+// kMostRelevantLanguagesDivider is placed between the most relevant languages
+// and all others.
+scoped_ptr<base::ListValue> GetLanguageList(
+ const input_method::InputMethodDescriptors& descriptors,
+ const std::vector<std::string>& base_language_codes,
+ const std::vector<std::string>& most_relevant_language_codes,
+ bool insert_divider) {
+ const std::string app_locale = g_browser_process->GetApplicationLocale();
+
+ std::set<std::string> language_codes;
+ // Collect the language codes from the supported input methods.
+ for (size_t i = 0; i < descriptors.size(); ++i) {
+ const input_method::InputMethodDescriptor& descriptor = descriptors[i];
+ const std::vector<std::string>& languages = descriptor.language_codes();
+ for (size_t i = 0; i < languages.size(); ++i)
+ language_codes.insert(languages[i]);
+ }
+
+ // Language sort order.
+ std::map<std::string, int /* index */> language_index;
+ for (size_t i = 0; i < most_relevant_language_codes.size(); ++i)
+ language_index[most_relevant_language_codes[i]] = i;
+
+ // Map of display name -> {language code, native_display_name}.
+ // In theory, we should be able to create a map that is sorted by
+ // display names using ICU comparator, but doing it is hard, thus we'll
+ // use an auxiliary vector to achieve the same result.
+ typedef std::pair<std::string, base::string16> LanguagePair;
+ typedef std::map<base::string16, LanguagePair> LanguageMap;
+ LanguageMap language_map;
+
+ // The auxiliary vector mentioned above (except the most relevant locales).
+ std::vector<base::string16> display_names;
+
+ // Separate vector of the most relevant locales.
+ std::vector<base::string16> most_relevant_locales_display_names(
+ most_relevant_language_codes.size());
+
+ size_t most_relevant_locales_count = 0;
+
+ // Build the list of display names, and build the language map.
+
+ // The list of configured locales might have entries not in
+ // base_language_codes. If there are unsupported language variants,
+ // but they resolve to backup locale within base_language_codes, also
+ // add them to the list.
+ for (std::map<std::string, int>::const_iterator it = language_index.begin();
+ it != language_index.end(); ++it) {
+ const std::string& language_id = it->first;
+
+ const size_t dash_pos = language_id.find_first_of('-');
+
+ // Ignore non-specific codes.
+ if (dash_pos == std::string::npos || dash_pos == 0)
+ continue;
+
+ if (std::find(base_language_codes.begin(),
+ base_language_codes.end(),
+ language_id) != base_language_codes.end()) {
+ // Language is supported. No need to replace
+ continue;
+ }
+ std::string resolved_locale;
+ if (!l10n_util::CheckAndResolveLocale(language_id, &resolved_locale))
+ continue;
+
+ if (std::find(base_language_codes.begin(),
+ base_language_codes.end(),
+ resolved_locale) == base_language_codes.end()) {
+ // Resolved locale is not supported.
+ continue;
+ }
+
+ const base::string16 display_name =
+ l10n_util::GetDisplayNameForLocale(language_id, app_locale, true);
+ const base::string16 native_display_name =
+ l10n_util::GetDisplayNameForLocale(
+ language_id, language_id, true);
+
+ language_map[display_name] =
+ std::make_pair(language_id, native_display_name);
+
+ most_relevant_locales_display_names[it->second] = display_name;
+ ++most_relevant_locales_count;
+ }
+
+ // Translate language codes, generated from input methods.
+ for (std::set<std::string>::const_iterator it = language_codes.begin();
+ it != language_codes.end(); ++it) {
+ // Exclude the language which is not in |base_langauge_codes| even it has
+ // input methods.
+ if (std::find(base_language_codes.begin(),
+ base_language_codes.end(),
+ *it) == base_language_codes.end()) {
+ continue;
+ }
+
+ const base::string16 display_name =
+ l10n_util::GetDisplayNameForLocale(*it, app_locale, true);
+ const base::string16 native_display_name =
+ l10n_util::GetDisplayNameForLocale(*it, *it, true);
+
+ language_map[display_name] =
+ std::make_pair(*it, native_display_name);
+
+ const std::map<std::string, int>::const_iterator index_pos =
+ language_index.find(*it);
+ if (index_pos != language_index.end()) {
+ base::string16& stored_display_name =
+ most_relevant_locales_display_names[index_pos->second];
+ if (stored_display_name.empty()) {
+ stored_display_name = display_name;
+ ++most_relevant_locales_count;
+ }
+ } else {
+ display_names.push_back(display_name);
+ }
+ }
+ DCHECK_EQ(display_names.size() + most_relevant_locales_count,
+ language_map.size());
+
+ // Build the list of display names, and build the language map.
+ for (size_t i = 0; i < base_language_codes.size(); ++i) {
+ // Skip this language if it was already added.
+ if (language_codes.find(base_language_codes[i]) != language_codes.end())
+ continue;
+
+ // TODO(zork): Remove this blacklist when fonts are added to Chrome OS.
+ // see: crbug.com/240586
+ if (IsBlacklisted(base_language_codes[i]))
+ continue;
+
+ base::string16 display_name =
+ l10n_util::GetDisplayNameForLocale(
+ base_language_codes[i], app_locale, false);
+ base::string16 native_display_name =
+ l10n_util::GetDisplayNameForLocale(
+ base_language_codes[i], base_language_codes[i], false);
+ language_map[display_name] =
+ std::make_pair(base_language_codes[i], native_display_name);
+
+ const std::map<std::string, int>::const_iterator index_pos =
+ language_index.find(base_language_codes[i]);
+ if (index_pos != language_index.end()) {
+ most_relevant_locales_display_names[index_pos->second] = display_name;
+ ++most_relevant_locales_count;
+ } else {
+ display_names.push_back(display_name);
+ }
+ }
+
+ // Sort display names using locale specific sorter.
+ l10n_util::SortStrings16(app_locale, &display_names);
+ // Concatenate most_relevant_locales_display_names and display_names.
+ // Insert special divider in between.
+ std::vector<base::string16> out_display_names;
+ for (size_t i = 0; i < most_relevant_locales_display_names.size(); ++i) {
+ if (most_relevant_locales_display_names[i].size() == 0)
+ continue;
+ out_display_names.push_back(most_relevant_locales_display_names[i]);
+ }
+
+ base::string16 divider16;
+ if (insert_divider) {
+ divider16 = base::ASCIIToUTF16(kMostRelevantLanguagesDivider);
+ out_display_names.push_back(divider16);
+ }
+
+ std::copy(display_names.begin(),
+ display_names.end(),
+ std::back_inserter(out_display_names));
+
+ // Build the language list from the language map.
+ scoped_ptr<base::ListValue> language_list(new base::ListValue());
+ for (size_t i = 0; i < out_display_names.size(); ++i) {
+ // Sets the directionality of the display language name.
+ base::string16 display_name(out_display_names[i]);
+ if (insert_divider && display_name == divider16) {
+ // Insert divider.
+ base::DictionaryValue* dictionary = new base::DictionaryValue();
+ dictionary->SetString("code", kMostRelevantLanguagesDivider);
+ language_list->Append(dictionary);
+ continue;
+ }
+ const bool markup_removal =
+ base::i18n::UnadjustStringForLocaleDirection(&display_name);
+ DCHECK(markup_removal);
+ const bool has_rtl_chars =
+ base::i18n::StringContainsStrongRTLChars(display_name);
+ const std::string directionality = has_rtl_chars ? "rtl" : "ltr";
+
+ const LanguagePair& pair = language_map[out_display_names[i]];
+ base::DictionaryValue* dictionary = new base::DictionaryValue();
+ dictionary->SetString("code", pair.first);
+ dictionary->SetString("displayName", out_display_names[i]);
+ dictionary->SetString("textDirection", directionality);
+ dictionary->SetString("nativeDisplayName", pair.second);
+ language_list->Append(dictionary);
+ }
+
+ return language_list.Pass();
+}
+
+} // namespace
+
+const char kMostRelevantLanguagesDivider[] = "MOST_RELEVANT_LANGUAGES_DIVIDER";
+
+scoped_ptr<base::ListValue> GetUILanguageList(
+ const std::vector<std::string>* most_relevant_language_codes,
+ const std::string& selected) {
+ ComponentExtensionIMEManager* manager =
+ input_method::InputMethodManager::Get()->
+ GetComponentExtensionIMEManager();
+ input_method::InputMethodDescriptors descriptors;
+ if (manager->IsInitialized())
+ descriptors = manager->GetXkbIMEAsInputMethodDescriptor();
+ scoped_ptr<base::ListValue> languages_list(GetLanguageList(
+ descriptors,
+ l10n_util::GetAvailableLocales(),
+ most_relevant_language_codes
+ ? *most_relevant_language_codes
+ : StartupCustomizationDocument::GetInstance()->configured_locales(),
+ true));
+
+ for (size_t i = 0; i < languages_list->GetSize(); ++i) {
+ base::DictionaryValue* language_info = NULL;
+ if (!languages_list->GetDictionary(i, &language_info))
+ NOTREACHED();
+
+ std::string value;
+ language_info->GetString("code", &value);
+ std::string display_name;
+ language_info->GetString("displayName", &display_name);
+ std::string native_name;
+ language_info->GetString("nativeDisplayName", &native_name);
+
+ // If it's an option group divider, add field name.
+ if (value == kMostRelevantLanguagesDivider) {
+ language_info->SetString(
+ "optionGroupName",
+ l10n_util::GetStringUTF16(IDS_OOBE_OTHER_LANGUAGES));
+ }
+ if (display_name != native_name) {
+ display_name = base::StringPrintf("%s - %s",
+ display_name.c_str(),
+ native_name.c_str());
+ }
+
+ language_info->SetString("value", value);
+ language_info->SetString("title", display_name);
+ if (value == selected)
+ language_info->SetBoolean("selected", true);
+ }
+ return languages_list.Pass();
+}
+
+scoped_ptr<base::ListValue> GetAcceptLanguageList() {
+ // Collect the language codes from the supported accept-languages.
+ const std::string app_locale = g_browser_process->GetApplicationLocale();
+ std::vector<std::string> accept_language_codes;
+ l10n_util::GetAcceptLanguagesForLocale(app_locale, &accept_language_codes);
+ return GetLanguageList(
+ *input_method::InputMethodManager::Get()->GetSupportedInputMethods(),
+ accept_language_codes,
+ StartupCustomizationDocument::GetInstance()->configured_locales(),
+ false);
+}
+
+scoped_ptr<base::ListValue> GetLoginKeyboardLayouts(
+ const std::string& locale,
+ const std::string& selected) {
+ scoped_ptr<base::ListValue> input_methods_list(new base::ListValue);
+ input_method::InputMethodManager* manager =
+ input_method::InputMethodManager::Get();
+ input_method::InputMethodUtil* util = manager->GetInputMethodUtil();
+ if (!manager->GetComponentExtensionIMEManager()->IsInitialized()) {
+ input_method::InputMethodDescriptor fallback =
+ util->GetFallbackInputMethodDescriptor();
+ input_methods_list->Append(
+ CreateInputMethodsEntry(fallback, fallback.id()));
+ return input_methods_list.Pass();
+ }
+
+ const std::vector<std::string>& hardware_login_input_methods =
+ util->GetHardwareLoginInputMethodIds();
+ manager->EnableLoginLayouts(locale, hardware_login_input_methods);
+
+ scoped_ptr<input_method::InputMethodDescriptors> input_methods(
+ manager->GetActiveInputMethods());
+ std::set<std::string> input_methods_added;
+
+ for (std::vector<std::string>::const_iterator i =
+ hardware_login_input_methods.begin();
+ i != hardware_login_input_methods.end();
+ ++i) {
+ const input_method::InputMethodDescriptor* ime =
+ util->GetInputMethodDescriptorFromId(*i);
+ // Do not crash in case of misconfiguration.
+ if (ime) {
+ input_methods_added.insert(*i);
+ input_methods_list->Append(CreateInputMethodsEntry(*ime, selected));
+ } else {
+ NOTREACHED();
+ }
+ }
+
+ bool optgroup_added = false;
+ for (size_t i = 0; i < input_methods->size(); ++i) {
+ // Makes sure the id is in legacy xkb id format.
+ const std::string& ime_id = (*input_methods)[i].id();
+ if (!InsertString(ime_id, input_methods_added))
+ continue;
+ if (!optgroup_added) {
+ optgroup_added = true;
+ AddOptgroupOtherLayouts(input_methods_list.get());
+ }
+ input_methods_list->Append(CreateInputMethodsEntry((*input_methods)[i],
+ selected));
+ }
+
+ // "xkb:us::eng" should always be in the list of available layouts.
+ const std::string us_keyboard_id =
+ util->GetFallbackInputMethodDescriptor().id();
+ if (input_methods_added.find(us_keyboard_id) == input_methods_added.end()) {
+ const input_method::InputMethodDescriptor* us_eng_descriptor =
+ util->GetInputMethodDescriptorFromId(us_keyboard_id);
+ DCHECK(us_eng_descriptor);
+ if (!optgroup_added) {
+ optgroup_added = true;
+ AddOptgroupOtherLayouts(input_methods_list.get());
+ }
+ input_methods_list->Append(CreateInputMethodsEntry(*us_eng_descriptor,
+ selected));
+ }
+ return input_methods_list.Pass();
+}
+
+} // namespace chromeos
« no previous file with comments | « chrome/browser/ui/webui/chromeos/login/l10n_util.h ('k') | chrome/browser/ui/webui/chromeos/login/l10n_util_test_util.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698