// 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 "chrome/browser/language_combobox_model.h"
#include "base/i18n/rtl.h"
#include "base/string_split.h"
#include "base/stringprintf.h"
#include "base/utf_string_conversions.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/metrics/user_metrics.h"
#include "chrome/browser/prefs/pref_service.h"
#include "chrome/browser/profiles/profile.h"
#include "grit/generated_resources.h"
#include "ui/base/l10n/l10n_util.h"
#include "unicode/uloc.h"
///////////////////////////////////////////////////////////////////////////////
// LanguageList used to enumerate native names corresponding to the
// language code (e.g. English (United States) for en-US)
//
LanguageList::LanguageList() {
// Enumerate the languages we know about.
const std::vector<std::string>& locale_codes =
l10n_util::GetAvailableLocales();
InitNativeNames(locale_codes);
}
LanguageList::LanguageList(
const std::vector<std::string>& locale_codes) {
InitNativeNames(locale_codes);
}
LanguageList::~LanguageList() {}
void LanguageList::InitNativeNames(
const std::vector<std::string>& locale_codes) {
const std::string app_locale = g_browser_process->GetApplicationLocale();
for (size_t i = 0; i < locale_codes.size(); ++i) {
std::string locale_code_str = locale_codes[i];
const char* locale_code = locale_codes[i].c_str();
// TODO(jungshik): Even though these strings are used for the UI,
// the old code does not add an RTL mark for RTL locales. Make sure
// that it's ok without that.
string16 name_in_current_ui =
l10n_util::GetDisplayNameForLocale(locale_code, app_locale, false);
string16 name_native =
l10n_util::GetDisplayNameForLocale(locale_code, locale_code, false);
locale_names_.push_back(name_in_current_ui);
native_names_[name_in_current_ui] =
LocaleData(name_native, locale_codes[i]);
}
// Sort using locale specific sorter.
l10n_util::SortStrings16(g_browser_process->GetApplicationLocale(),
&locale_names_);
}
void LanguageList::CopySpecifiedLanguagesUp(const std::string& locale_codes) {
DCHECK(!locale_names_.empty());
std::vector<std::string> locale_codes_vector;
base::SplitString(locale_codes, ',', &locale_codes_vector);
for (size_t i = 0; i != locale_codes_vector.size(); i++) {
const int locale_index = GetIndexFromLocale(locale_codes_vector[i]);
CHECK_NE(locale_index, -1);
locale_names_.insert(locale_names_.begin(), locale_names_[locale_index]);
}
}
// Overridden from ComboboxModel:
int LanguageList::get_languages_count() const {
return static_cast<int>(locale_names_.size());
}
string16 LanguageList::GetLanguageNameAt(int index) const {
DCHECK(static_cast<int>(locale_names_.size()) > index);
LocaleDataMap::const_iterator it =
native_names_.find(locale_names_[index]);
DCHECK(it != native_names_.end());
// If the name is the same in the native language and local language,
// don't show it twice.
if (it->second.native_name == locale_names_[index])
return it->second.native_name;
// We must add directionality formatting to both the native name and the
// locale name in order to avoid text rendering problems such as misplaced
// parentheses or languages appearing in the wrong order.
string16 locale_name = locale_names_[index];
base::i18n::AdjustStringForLocaleDirection(&locale_name);
string16 native_name = it->second.native_name;
base::i18n::AdjustStringForLocaleDirection(&native_name);
// We used to have a localizable template here, but none of translators
// changed the format. We also want to switch the order of locale_name
// and native_name without going back to translators.
std::string formatted_item;
base::SStringPrintf(&formatted_item, "%s - %s",
UTF16ToUTF8(locale_name).c_str(),
UTF16ToUTF8(native_name).c_str());
if (base::i18n::IsRTL())
// Somehow combo box (even with LAYOUTRTL flag) doesn't get this
// right so we add RTL BDO (U+202E) to set the direction
// explicitly.
formatted_item.insert(0, "\xE2\x80\xAE"); // U+202E = UTF-8 0xE280AE
return UTF8ToUTF16(formatted_item);
}
// Return the locale for the given index. E.g., may return pt-BR.
std::string LanguageList::GetLocaleFromIndex(int index) const {
DCHECK(static_cast<int>(locale_names_.size()) > index);
LocaleDataMap::const_iterator it =
native_names_.find(locale_names_[index]);
DCHECK(it != native_names_.end());
return it->second.locale_code;
}
int LanguageList::GetIndexFromLocale(const std::string& locale) const {
for (size_t i = 0; i < locale_names_.size(); ++i) {
LocaleDataMap::const_iterator it =
native_names_.find(locale_names_[i]);
DCHECK(it != native_names_.end());
if (it->second.locale_code == locale)
return static_cast<int>(i);
}
return -1;
}
///////////////////////////////////////////////////////////////////////////////
// LanguageComboboxModel used to populate a combobox with native names
//
LanguageComboboxModel::LanguageComboboxModel()
: profile_(NULL) {
}
LanguageComboboxModel::LanguageComboboxModel(
Profile* profile, const std::vector<std::string>& locale_codes)
: LanguageList(locale_codes),
profile_(profile) {
}
LanguageComboboxModel::~LanguageComboboxModel() {}
int LanguageComboboxModel::GetItemCount() {
return get_languages_count();
}
string16 LanguageComboboxModel::GetItemAt(int index) {
return GetLanguageNameAt(index);
}
// Returns the index of the language currently specified in the user's
// preference file. Note that it's possible for language A to be picked
// while chrome is currently in language B if the user specified language B
// via --lang. Since --lang is not a persistent setting, it seems that it
// shouldn't be reflected in this combo box. We return -1 if the value in
// the pref doesn't map to a know language (possible if the user edited the
// prefs file manually).
int LanguageComboboxModel::GetSelectedLanguageIndex(const std::string& prefs) {
PrefService* local_state;
if (!profile_)
local_state = g_browser_process->local_state();
else
local_state = profile_->GetPrefs();
DCHECK(local_state);
const std::string& current_locale = local_state->GetString(prefs.c_str());
return GetIndexFromLocale(current_locale);
}