language_combobox_model.cc revision 513209b27ff55e2841eac0e4120199c23acce758
1// Copyright (c) 2010 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/language_combobox_model.h"
6
7#include "app/l10n_util.h"
8#include "base/i18n/rtl.h"
9#include "base/string_split.h"
10#include "base/stringprintf.h"
11#include "base/utf_string_conversions.h"
12#include "chrome/browser/browser_process.h"
13#include "chrome/browser/metrics/user_metrics.h"
14#include "chrome/browser/prefs/pref_service.h"
15#include "chrome/browser/profile.h"
16#include "grit/generated_resources.h"
17#include "unicode/uloc.h"
18
19///////////////////////////////////////////////////////////////////////////////
20// LanguageList used to enumerate native names corresponding to the
21// language code (e.g. English (United States) for en-US)
22//
23
24LanguageList::LanguageList() {
25  // Enumerate the languages we know about.
26  const std::vector<std::string>& locale_codes =
27      l10n_util::GetAvailableLocales();
28  InitNativeNames(locale_codes);
29}
30
31LanguageList::LanguageList(
32    const std::vector<std::string>& locale_codes) {
33  InitNativeNames(locale_codes);
34}
35
36LanguageList::~LanguageList() {}
37
38void LanguageList::InitNativeNames(
39    const std::vector<std::string>& locale_codes) {
40  const std::string app_locale = g_browser_process->GetApplicationLocale();
41  for (size_t i = 0; i < locale_codes.size(); ++i) {
42    std::string locale_code_str = locale_codes[i];
43    const char* locale_code = locale_codes[i].c_str();
44
45    // TODO(jungshik): Even though these strings are used for the UI,
46    // the old code does not add an RTL mark for RTL locales. Make sure
47    // that it's ok without that.
48    string16 name_in_current_ui =
49        l10n_util::GetDisplayNameForLocale(locale_code, app_locale, false);
50    string16 name_native =
51        l10n_util::GetDisplayNameForLocale(locale_code, locale_code, false);
52
53    locale_names_.push_back(UTF16ToWideHack(name_in_current_ui));
54    native_names_[UTF16ToWideHack(name_in_current_ui)] = LocaleData(
55        UTF16ToWideHack(name_native), locale_codes[i]);
56  }
57
58  // Sort using locale specific sorter.
59  l10n_util::SortStrings(g_browser_process->GetApplicationLocale(),
60                         &locale_names_);
61}
62
63void LanguageList::CopySpecifiedLanguagesUp(const std::string& locale_codes) {
64  DCHECK(!locale_names_.empty());
65  std::vector<std::string> locale_codes_vector;
66  base::SplitString(locale_codes, ',', &locale_codes_vector);
67  for (size_t i = 0; i != locale_codes_vector.size(); i++) {
68    const int locale_index = GetIndexFromLocale(locale_codes_vector[i]);
69    CHECK_NE(locale_index, -1);
70    locale_names_.insert(locale_names_.begin(), locale_names_[locale_index]);
71  }
72}
73
74// Overridden from ComboboxModel:
75int LanguageList::get_languages_count() const {
76  return static_cast<int>(locale_names_.size());
77}
78
79std::wstring LanguageList::GetLanguageNameAt(int index) const {
80  DCHECK(static_cast<int>(locale_names_.size()) > index);
81  LocaleDataMap::const_iterator it =
82      native_names_.find(locale_names_[index]);
83  DCHECK(it != native_names_.end());
84
85  // If the name is the same in the native language and local language,
86  // don't show it twice.
87  if (it->second.native_name == locale_names_[index])
88    return it->second.native_name;
89
90  // We must add directionality formatting to both the native name and the
91  // locale name in order to avoid text rendering problems such as misplaced
92  // parentheses or languages appearing in the wrong order.
93  std::wstring locale_name_localized;
94  std::wstring locale_name;
95  if (base::i18n::AdjustStringForLocaleDirection(locale_names_[index],
96                                                 &locale_name_localized))
97    locale_name.assign(locale_name_localized);
98  else
99    locale_name.assign(locale_names_[index]);
100
101  std::wstring native_name_localized;
102  std::wstring native_name;
103  if (base::i18n::AdjustStringForLocaleDirection(it->second.native_name,
104                                                 &native_name_localized))
105    native_name.assign(native_name_localized);
106  else
107    native_name.assign(it->second.native_name);
108
109  // We used to have a localizable template here, but none of translators
110  // changed the format. We also want to switch the order of locale_name
111  // and native_name without going back to translators.
112  std::wstring formatted_item;
113  base::SStringPrintf(&formatted_item, L"%ls - %ls", locale_name.c_str(),
114                      native_name.c_str());
115  if (base::i18n::IsRTL())
116    // Somehow combo box (even with LAYOUTRTL flag) doesn't get this
117    // right so we add RTL BDO (U+202E) to set the direction
118    // explicitly.
119    formatted_item.insert(0, L"\x202E");
120  return formatted_item;
121}
122
123// Return the locale for the given index.  E.g., may return pt-BR.
124std::string LanguageList::GetLocaleFromIndex(int index) const {
125  DCHECK(static_cast<int>(locale_names_.size()) > index);
126  LocaleDataMap::const_iterator it =
127      native_names_.find(locale_names_[index]);
128  DCHECK(it != native_names_.end());
129
130  return it->second.locale_code;
131}
132
133int LanguageList::GetIndexFromLocale(const std::string& locale) const {
134  for (size_t i = 0; i < locale_names_.size(); ++i) {
135    LocaleDataMap::const_iterator it =
136        native_names_.find(locale_names_[i]);
137    DCHECK(it != native_names_.end());
138    if (it->second.locale_code == locale)
139      return static_cast<int>(i);
140  }
141  return -1;
142}
143
144///////////////////////////////////////////////////////////////////////////////
145// LanguageComboboxModel used to populate a combobox with native names
146//
147
148LanguageComboboxModel::LanguageComboboxModel()
149    : profile_(NULL) {
150}
151
152LanguageComboboxModel::LanguageComboboxModel(
153    Profile* profile, const std::vector<std::string>& locale_codes)
154    : LanguageList(locale_codes),
155      profile_(profile) {
156}
157
158LanguageComboboxModel::~LanguageComboboxModel() {}
159
160int LanguageComboboxModel::GetItemCount() {
161  return get_languages_count();
162}
163
164string16 LanguageComboboxModel::GetItemAt(int index) {
165  return WideToUTF16Hack(GetLanguageNameAt(index));
166}
167
168// Returns the index of the language currently specified in the user's
169// preference file.  Note that it's possible for language A to be picked
170// while chrome is currently in language B if the user specified language B
171// via --lang.  Since --lang is not a persistent setting, it seems that it
172// shouldn't be reflected in this combo box.  We return -1 if the value in
173// the pref doesn't map to a know language (possible if the user edited the
174// prefs file manually).
175int LanguageComboboxModel::GetSelectedLanguageIndex(const std::string& prefs) {
176  PrefService* local_state;
177  if (!profile_)
178    local_state = g_browser_process->local_state();
179  else
180    local_state = profile_->GetPrefs();
181
182  DCHECK(local_state);
183  const std::string& current_locale = local_state->GetString(prefs.c_str());
184
185  return GetIndexFromLocale(current_locale);
186}
187