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

Side by Side 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 unified diff | Download patch | Annotate | Revision Log
OLDNEW
(Empty)
1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "chrome/browser/ui/webui/chromeos/login/l10n_util.h"
6
7 #include <algorithm>
8 #include <iterator>
9 #include <map>
10 #include <set>
11 #include <utility>
12
13 #include "base/basictypes.h"
14 #include "base/i18n/rtl.h"
15 #include "base/logging.h"
16 #include "base/strings/string16.h"
17 #include "base/strings/stringprintf.h"
18 #include "base/strings/utf_string_conversions.h"
19 #include "base/values.h"
20 #include "chrome/browser/browser_process.h"
21 #include "chrome/browser/chromeos/customization_document.h"
22 #include "chrome/browser/chromeos/input_method/input_method_util.h"
23 #include "chromeos/ime/component_extension_ime_manager.h"
24 #include "chromeos/ime/input_method_descriptor.h"
25 #include "chromeos/ime/input_method_manager.h"
26 #include "grit/generated_resources.h"
27 #include "ui/base/l10n/l10n_util.h"
28
29 namespace chromeos {
30
31 namespace {
32
33 base::DictionaryValue* CreateInputMethodsEntry(
34 const input_method::InputMethodDescriptor& method,
35 const std::string selected) {
36 input_method::InputMethodUtil* util =
37 input_method::InputMethodManager::Get()->GetInputMethodUtil();
38 const std::string& ime_id = method.id();
39 scoped_ptr<base::DictionaryValue> input_method(new base::DictionaryValue);
40 input_method->SetString("value", ime_id);
41 input_method->SetString("title", util->GetInputMethodLongName(method));
42 input_method->SetBoolean("selected", ime_id == selected);
43 return input_method.release();
44 }
45
46 // Returns true if element was inserted.
47 bool InsertString(const std::string& str, std::set<std::string>& to) {
48 const std::pair<std::set<std::string>::iterator, bool> result =
49 to.insert(str);
50 return result.second;
51 }
52
53 void AddOptgroupOtherLayouts(base::ListValue* input_methods_list) {
54 scoped_ptr<base::DictionaryValue> optgroup(new base::DictionaryValue);
55 optgroup->SetString(
56 "optionGroupName",
57 l10n_util::GetStringUTF16(IDS_OOBE_OTHER_KEYBOARD_LAYOUTS));
58 input_methods_list->Append(optgroup.release());
59 }
60
61 // TODO(zork): Remove this blacklist when fonts are added to Chrome OS.
62 // see: crbug.com/240586
63 bool IsBlacklisted(const std::string& language_code) {
64 return language_code == "si"; // Sinhala
65 }
66
67 // Gets the list of languages with |descriptors| based on |base_language_codes|.
68 // The |most_relevant_language_codes| will be first in the list. If
69 // |insert_divider| is true, an entry with its "code" attribute set to
70 // kMostRelevantLanguagesDivider is placed between the most relevant languages
71 // and all others.
72 scoped_ptr<base::ListValue> GetLanguageList(
73 const input_method::InputMethodDescriptors& descriptors,
74 const std::vector<std::string>& base_language_codes,
75 const std::vector<std::string>& most_relevant_language_codes,
76 bool insert_divider) {
77 const std::string app_locale = g_browser_process->GetApplicationLocale();
78
79 std::set<std::string> language_codes;
80 // Collect the language codes from the supported input methods.
81 for (size_t i = 0; i < descriptors.size(); ++i) {
82 const input_method::InputMethodDescriptor& descriptor = descriptors[i];
83 const std::vector<std::string>& languages = descriptor.language_codes();
84 for (size_t i = 0; i < languages.size(); ++i)
85 language_codes.insert(languages[i]);
86 }
87
88 // Language sort order.
89 std::map<std::string, int /* index */> language_index;
90 for (size_t i = 0; i < most_relevant_language_codes.size(); ++i)
91 language_index[most_relevant_language_codes[i]] = i;
92
93 // Map of display name -> {language code, native_display_name}.
94 // In theory, we should be able to create a map that is sorted by
95 // display names using ICU comparator, but doing it is hard, thus we'll
96 // use an auxiliary vector to achieve the same result.
97 typedef std::pair<std::string, base::string16> LanguagePair;
98 typedef std::map<base::string16, LanguagePair> LanguageMap;
99 LanguageMap language_map;
100
101 // The auxiliary vector mentioned above (except the most relevant locales).
102 std::vector<base::string16> display_names;
103
104 // Separate vector of the most relevant locales.
105 std::vector<base::string16> most_relevant_locales_display_names(
106 most_relevant_language_codes.size());
107
108 size_t most_relevant_locales_count = 0;
109
110 // Build the list of display names, and build the language map.
111
112 // The list of configured locales might have entries not in
113 // base_language_codes. If there are unsupported language variants,
114 // but they resolve to backup locale within base_language_codes, also
115 // add them to the list.
116 for (std::map<std::string, int>::const_iterator it = language_index.begin();
117 it != language_index.end(); ++it) {
118 const std::string& language_id = it->first;
119
120 const size_t dash_pos = language_id.find_first_of('-');
121
122 // Ignore non-specific codes.
123 if (dash_pos == std::string::npos || dash_pos == 0)
124 continue;
125
126 if (std::find(base_language_codes.begin(),
127 base_language_codes.end(),
128 language_id) != base_language_codes.end()) {
129 // Language is supported. No need to replace
130 continue;
131 }
132 std::string resolved_locale;
133 if (!l10n_util::CheckAndResolveLocale(language_id, &resolved_locale))
134 continue;
135
136 if (std::find(base_language_codes.begin(),
137 base_language_codes.end(),
138 resolved_locale) == base_language_codes.end()) {
139 // Resolved locale is not supported.
140 continue;
141 }
142
143 const base::string16 display_name =
144 l10n_util::GetDisplayNameForLocale(language_id, app_locale, true);
145 const base::string16 native_display_name =
146 l10n_util::GetDisplayNameForLocale(
147 language_id, language_id, true);
148
149 language_map[display_name] =
150 std::make_pair(language_id, native_display_name);
151
152 most_relevant_locales_display_names[it->second] = display_name;
153 ++most_relevant_locales_count;
154 }
155
156 // Translate language codes, generated from input methods.
157 for (std::set<std::string>::const_iterator it = language_codes.begin();
158 it != language_codes.end(); ++it) {
159 // Exclude the language which is not in |base_langauge_codes| even it has
160 // input methods.
161 if (std::find(base_language_codes.begin(),
162 base_language_codes.end(),
163 *it) == base_language_codes.end()) {
164 continue;
165 }
166
167 const base::string16 display_name =
168 l10n_util::GetDisplayNameForLocale(*it, app_locale, true);
169 const base::string16 native_display_name =
170 l10n_util::GetDisplayNameForLocale(*it, *it, true);
171
172 language_map[display_name] =
173 std::make_pair(*it, native_display_name);
174
175 const std::map<std::string, int>::const_iterator index_pos =
176 language_index.find(*it);
177 if (index_pos != language_index.end()) {
178 base::string16& stored_display_name =
179 most_relevant_locales_display_names[index_pos->second];
180 if (stored_display_name.empty()) {
181 stored_display_name = display_name;
182 ++most_relevant_locales_count;
183 }
184 } else {
185 display_names.push_back(display_name);
186 }
187 }
188 DCHECK_EQ(display_names.size() + most_relevant_locales_count,
189 language_map.size());
190
191 // Build the list of display names, and build the language map.
192 for (size_t i = 0; i < base_language_codes.size(); ++i) {
193 // Skip this language if it was already added.
194 if (language_codes.find(base_language_codes[i]) != language_codes.end())
195 continue;
196
197 // TODO(zork): Remove this blacklist when fonts are added to Chrome OS.
198 // see: crbug.com/240586
199 if (IsBlacklisted(base_language_codes[i]))
200 continue;
201
202 base::string16 display_name =
203 l10n_util::GetDisplayNameForLocale(
204 base_language_codes[i], app_locale, false);
205 base::string16 native_display_name =
206 l10n_util::GetDisplayNameForLocale(
207 base_language_codes[i], base_language_codes[i], false);
208 language_map[display_name] =
209 std::make_pair(base_language_codes[i], native_display_name);
210
211 const std::map<std::string, int>::const_iterator index_pos =
212 language_index.find(base_language_codes[i]);
213 if (index_pos != language_index.end()) {
214 most_relevant_locales_display_names[index_pos->second] = display_name;
215 ++most_relevant_locales_count;
216 } else {
217 display_names.push_back(display_name);
218 }
219 }
220
221 // Sort display names using locale specific sorter.
222 l10n_util::SortStrings16(app_locale, &display_names);
223 // Concatenate most_relevant_locales_display_names and display_names.
224 // Insert special divider in between.
225 std::vector<base::string16> out_display_names;
226 for (size_t i = 0; i < most_relevant_locales_display_names.size(); ++i) {
227 if (most_relevant_locales_display_names[i].size() == 0)
228 continue;
229 out_display_names.push_back(most_relevant_locales_display_names[i]);
230 }
231
232 base::string16 divider16;
233 if (insert_divider) {
234 divider16 = base::ASCIIToUTF16(kMostRelevantLanguagesDivider);
235 out_display_names.push_back(divider16);
236 }
237
238 std::copy(display_names.begin(),
239 display_names.end(),
240 std::back_inserter(out_display_names));
241
242 // Build the language list from the language map.
243 scoped_ptr<base::ListValue> language_list(new base::ListValue());
244 for (size_t i = 0; i < out_display_names.size(); ++i) {
245 // Sets the directionality of the display language name.
246 base::string16 display_name(out_display_names[i]);
247 if (insert_divider && display_name == divider16) {
248 // Insert divider.
249 base::DictionaryValue* dictionary = new base::DictionaryValue();
250 dictionary->SetString("code", kMostRelevantLanguagesDivider);
251 language_list->Append(dictionary);
252 continue;
253 }
254 const bool markup_removal =
255 base::i18n::UnadjustStringForLocaleDirection(&display_name);
256 DCHECK(markup_removal);
257 const bool has_rtl_chars =
258 base::i18n::StringContainsStrongRTLChars(display_name);
259 const std::string directionality = has_rtl_chars ? "rtl" : "ltr";
260
261 const LanguagePair& pair = language_map[out_display_names[i]];
262 base::DictionaryValue* dictionary = new base::DictionaryValue();
263 dictionary->SetString("code", pair.first);
264 dictionary->SetString("displayName", out_display_names[i]);
265 dictionary->SetString("textDirection", directionality);
266 dictionary->SetString("nativeDisplayName", pair.second);
267 language_list->Append(dictionary);
268 }
269
270 return language_list.Pass();
271 }
272
273 } // namespace
274
275 const char kMostRelevantLanguagesDivider[] = "MOST_RELEVANT_LANGUAGES_DIVIDER";
276
277 scoped_ptr<base::ListValue> GetUILanguageList(
278 const std::vector<std::string>* most_relevant_language_codes,
279 const std::string& selected) {
280 ComponentExtensionIMEManager* manager =
281 input_method::InputMethodManager::Get()->
282 GetComponentExtensionIMEManager();
283 input_method::InputMethodDescriptors descriptors;
284 if (manager->IsInitialized())
285 descriptors = manager->GetXkbIMEAsInputMethodDescriptor();
286 scoped_ptr<base::ListValue> languages_list(GetLanguageList(
287 descriptors,
288 l10n_util::GetAvailableLocales(),
289 most_relevant_language_codes
290 ? *most_relevant_language_codes
291 : StartupCustomizationDocument::GetInstance()->configured_locales(),
292 true));
293
294 for (size_t i = 0; i < languages_list->GetSize(); ++i) {
295 base::DictionaryValue* language_info = NULL;
296 if (!languages_list->GetDictionary(i, &language_info))
297 NOTREACHED();
298
299 std::string value;
300 language_info->GetString("code", &value);
301 std::string display_name;
302 language_info->GetString("displayName", &display_name);
303 std::string native_name;
304 language_info->GetString("nativeDisplayName", &native_name);
305
306 // If it's an option group divider, add field name.
307 if (value == kMostRelevantLanguagesDivider) {
308 language_info->SetString(
309 "optionGroupName",
310 l10n_util::GetStringUTF16(IDS_OOBE_OTHER_LANGUAGES));
311 }
312 if (display_name != native_name) {
313 display_name = base::StringPrintf("%s - %s",
314 display_name.c_str(),
315 native_name.c_str());
316 }
317
318 language_info->SetString("value", value);
319 language_info->SetString("title", display_name);
320 if (value == selected)
321 language_info->SetBoolean("selected", true);
322 }
323 return languages_list.Pass();
324 }
325
326 scoped_ptr<base::ListValue> GetAcceptLanguageList() {
327 // Collect the language codes from the supported accept-languages.
328 const std::string app_locale = g_browser_process->GetApplicationLocale();
329 std::vector<std::string> accept_language_codes;
330 l10n_util::GetAcceptLanguagesForLocale(app_locale, &accept_language_codes);
331 return GetLanguageList(
332 *input_method::InputMethodManager::Get()->GetSupportedInputMethods(),
333 accept_language_codes,
334 StartupCustomizationDocument::GetInstance()->configured_locales(),
335 false);
336 }
337
338 scoped_ptr<base::ListValue> GetLoginKeyboardLayouts(
339 const std::string& locale,
340 const std::string& selected) {
341 scoped_ptr<base::ListValue> input_methods_list(new base::ListValue);
342 input_method::InputMethodManager* manager =
343 input_method::InputMethodManager::Get();
344 input_method::InputMethodUtil* util = manager->GetInputMethodUtil();
345 if (!manager->GetComponentExtensionIMEManager()->IsInitialized()) {
346 input_method::InputMethodDescriptor fallback =
347 util->GetFallbackInputMethodDescriptor();
348 input_methods_list->Append(
349 CreateInputMethodsEntry(fallback, fallback.id()));
350 return input_methods_list.Pass();
351 }
352
353 const std::vector<std::string>& hardware_login_input_methods =
354 util->GetHardwareLoginInputMethodIds();
355 manager->EnableLoginLayouts(locale, hardware_login_input_methods);
356
357 scoped_ptr<input_method::InputMethodDescriptors> input_methods(
358 manager->GetActiveInputMethods());
359 std::set<std::string> input_methods_added;
360
361 for (std::vector<std::string>::const_iterator i =
362 hardware_login_input_methods.begin();
363 i != hardware_login_input_methods.end();
364 ++i) {
365 const input_method::InputMethodDescriptor* ime =
366 util->GetInputMethodDescriptorFromId(*i);
367 // Do not crash in case of misconfiguration.
368 if (ime) {
369 input_methods_added.insert(*i);
370 input_methods_list->Append(CreateInputMethodsEntry(*ime, selected));
371 } else {
372 NOTREACHED();
373 }
374 }
375
376 bool optgroup_added = false;
377 for (size_t i = 0; i < input_methods->size(); ++i) {
378 // Makes sure the id is in legacy xkb id format.
379 const std::string& ime_id = (*input_methods)[i].id();
380 if (!InsertString(ime_id, input_methods_added))
381 continue;
382 if (!optgroup_added) {
383 optgroup_added = true;
384 AddOptgroupOtherLayouts(input_methods_list.get());
385 }
386 input_methods_list->Append(CreateInputMethodsEntry((*input_methods)[i],
387 selected));
388 }
389
390 // "xkb:us::eng" should always be in the list of available layouts.
391 const std::string us_keyboard_id =
392 util->GetFallbackInputMethodDescriptor().id();
393 if (input_methods_added.find(us_keyboard_id) == input_methods_added.end()) {
394 const input_method::InputMethodDescriptor* us_eng_descriptor =
395 util->GetInputMethodDescriptorFromId(us_keyboard_id);
396 DCHECK(us_eng_descriptor);
397 if (!optgroup_added) {
398 optgroup_added = true;
399 AddOptgroupOtherLayouts(input_methods_list.get());
400 }
401 input_methods_list->Append(CreateInputMethodsEntry(*us_eng_descriptor,
402 selected));
403 }
404 return input_methods_list.Pass();
405 }
406
407 } // namespace chromeos
OLDNEW
« 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