Skip to content

Commit

Permalink
Reland "Updated AllowedUILocales to handle preferred languages."
Browse files Browse the repository at this point in the history
This is a reland of 75d0995

I've fixed the start-up crashes with DCHECK enabled (see diff from PATCHSET-1 to PATCHSET-3).

Original change's description:
> Updated AllowedUILocales to handle preferred languages.
>
> Updated AllowedUILocales to limit not only the ui locales but also the
> available preferred languages. Renamed AllowedUILocales to AllowedLanguages to
> better indicate that.
>
> Bug: 579660
> Cq-Include-Trybots: luci.chromium.try:closure_compilation
> Change-Id: Iae929216e164fe941e5e335a3ce2e7ff47dce0e3
> Reviewed-on: https://chromium-review.googlesource.com/c/1256570
> Commit-Queue: Zakhar Voit <voit@google.com>
> Reviewed-by: Sergey Poromov <poromov@chromium.org>
> Reviewed-by: David Roger <droger@chromium.org>
> Reviewed-by: Steven Bennetts <stevenjb@chromium.org>
> Cr-Commit-Position: refs/heads/master@{#597559}

Bug: 579660, 695042
Change-Id: I5d499843fb500fa9d2852559dedc08adfd012da0
Cq-Include-Trybots: luci.chromium.try:closure_compilation
Reviewed-on: https://chromium-review.googlesource.com/c/1280270
Commit-Queue: Zakhar Voit <voit@google.com>
Reviewed-by: Michael Martis <martis@chromium.org>
Reviewed-by: Alexander Hendrich <hendrich@chromium.org>
Reviewed-by: Steven Bennetts <stevenjb@chromium.org>
Reviewed-by: David Roger <droger@chromium.org>
Reviewed-by: Sergey Poromov <poromov@chromium.org>
Cr-Commit-Position: refs/heads/master@{#603062}
  • Loading branch information
zakharvoit authored and Commit Bot committed Oct 26, 2018
1 parent a9eab1e commit 1f16c5e
Show file tree
Hide file tree
Showing 27 changed files with 224 additions and 118 deletions.
95 changes: 62 additions & 33 deletions chrome/browser/chromeos/base/locale_util.cc
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,9 @@
#include "chrome/browser/chromeos/login/session/user_session_manager.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/common/pref_names.h"
#include "components/language/core/common/locale_util.h"
#include "components/prefs/pref_service.h"
#include "components/translate/core/browser/translate_prefs.h"
#include "content/public/browser/browser_thread.h"
#include "ui/base/ime/chromeos/input_method_manager.h"
#include "ui/base/ime/chromeos/input_method_util.h"
Expand Down Expand Up @@ -63,13 +65,6 @@ void FinishSwitchLanguage(std::unique_ptr<SwitchLanguageData> data) {
g_browser_process->SetApplicationLocale(data->result.loaded_locale,
data->result.requested_locale);

// If the language switch was triggered by enterprise policy, it is possible
// that the locale is not in the user's list of preferred languages yet,
// which would lead to an inconsistent state in the settings UI. Make sure
// to add it in that case.
locale_util::AddLocaleToPreferredLanguages(data->result.loaded_locale,
data->profile->GetPrefs());

if (data->enable_locale_keyboard_layouts) {
input_method::InputMethodManager* manager =
input_method::InputMethodManager::Get();
Expand Down Expand Up @@ -111,11 +106,20 @@ void FinishSwitchLanguage(std::unique_ptr<SwitchLanguageData> data) {
data->callback.Run(data->result);
}

// Get parsed list of preferred languages from the 'kLanguagePreferredLanguages'
// setting.
std::vector<std::string> GetPreferredLanguagesList(const PrefService* prefs) {
std::string preferred_languages_string =
prefs->GetString(prefs::kLanguagePreferredLanguages);
return base::SplitString(preferred_languages_string, ",",
base::TRIM_WHITESPACE, base::SPLIT_WANT_NONEMPTY);
}

} // namespace

namespace locale_util {

constexpr const char* kAllowedUILocalesFallbackLocale = "en-US";
constexpr const char* kAllowedUILanguageFallback = "en-US";

LanguageSwitchResult::LanguageSwitchResult(const std::string& requested_locale,
const std::string& loaded_locale,
Expand All @@ -141,56 +145,81 @@ void SwitchLanguage(const std::string& locale,
base::Bind(&FinishSwitchLanguage, base::Passed(std::move(data))));
}

bool IsAllowedUILocale(const std::string& locale, const PrefService* prefs) {
const base::Value::ListStorage& allowed_ui_locales =
prefs->GetList(prefs::kAllowedUILocales)->GetList();
bool IsAllowedLanguage(const std::string& language, const PrefService* prefs) {
const base::Value::ListStorage& allowed_languages =
prefs->GetList(prefs::kAllowedLanguages)->GetList();

// Empty list means all locales are allowed.
if (allowed_ui_locales.empty())
// Empty list means all languages are allowed.
if (allowed_languages.empty())
return true;

// Only locale codes with native UI support can be allowed.
if (!IsNativeUILocale(locale))
return false;

// Check if locale is in list of allowed UI locales.
return base::ContainsValue(allowed_ui_locales, base::Value(locale));
return base::ContainsValue(allowed_languages, base::Value(language));
}

bool IsNativeUILocale(const std::string& locale) {
std::string resolved_locale;
if (l10n_util::CheckAndResolveLocale(locale, &resolved_locale) &&
locale == resolved_locale) {
return true;
bool IsAllowedUILanguage(const std::string& language,
const PrefService* prefs) {
return IsAllowedLanguage(language, prefs) && IsNativeUILanguage(language);
}

bool IsNativeUILanguage(const std::string& locale) {
std::string resolved_locale = locale;

// The locale is a UI locale or can be converted to a UI locale.
if (base::FeatureList::IsEnabled(translate::kRegionalLocalesAsDisplayUI))
return language::ConvertToActualUILocale(&resolved_locale);
return language::ConvertToFallbackUILocale(&resolved_locale);
}

void RemoveDisallowedLanguagesFromPreferred(PrefService* prefs) {
// Do nothing if all languages are allowed
if (prefs->GetList(prefs::kAllowedLanguages)->GetList().empty())
return;

std::vector<std::string> preferred_languages =
GetPreferredLanguagesList(prefs);
std::vector<std::string> updated_preferred_languages;
bool have_ui_language = false;
for (const std::string& language : preferred_languages) {
if (IsAllowedLanguage(language, prefs)) {
updated_preferred_languages.push_back(language);
if (IsNativeUILanguage(language))
have_ui_language = true;
}
}
if (!have_ui_language)
updated_preferred_languages.push_back(GetAllowedFallbackUILanguage(prefs));

return false;
// Do not set setting if it did not change to not cause the update callback
if (preferred_languages != updated_preferred_languages) {
prefs->SetString(prefs::kLanguagePreferredLanguages,
base::JoinString(updated_preferred_languages, ","));
}
}

std::string GetAllowedFallbackUILocale(const PrefService* prefs) {
std::string GetAllowedFallbackUILanguage(const PrefService* prefs) {
// Check the user's preferred languages if one of them is an allowed UI
// locale.
std::string preferred_languages_string =
prefs->GetString(prefs::kLanguagePreferredLanguages);
std::vector<std::string> preferred_languages =
base::SplitString(preferred_languages_string, ",", base::TRIM_WHITESPACE,
base::SPLIT_WANT_NONEMPTY);
GetPreferredLanguagesList(prefs);
for (const std::string& language : preferred_languages) {
if (IsAllowedUILocale(language, prefs))
if (IsAllowedUILanguage(language, prefs))
return language;
}

// Check the allowed UI locales and return the first valid entry.
const base::Value::ListStorage& allowed_ui_locales =
prefs->GetList(prefs::kAllowedUILocales)->GetList();
for (const base::Value& value : allowed_ui_locales) {
const base::Value::ListStorage& allowed_languages =
prefs->GetList(prefs::kAllowedLanguages)->GetList();
for (const base::Value& value : allowed_languages) {
const std::string& locale = value.GetString();
if (IsAllowedUILocale(locale, prefs))
if (IsAllowedUILanguage(locale, prefs))
return locale;
}

// default fallback
return kAllowedUILocalesFallbackLocale;
return kAllowedUILanguageFallback;
}

bool AddLocaleToPreferredLanguages(const std::string& locale,
Expand Down
51 changes: 34 additions & 17 deletions chrome/browser/chromeos/base/locale_util.h
Original file line number Diff line number Diff line change
Expand Up @@ -52,23 +52,40 @@ void SwitchLanguage(const std::string& locale,
const SwitchLanguageCallback& callback,
Profile* profile);

// This function checks if the given locale is allowed according to the list of
// allowed UI locales (stored in |prefs|, managed by 'AllowedUILocales'
// policy). If the list is empty, every locale is allowed.
bool IsAllowedUILocale(const std::string& locale, const PrefService* prefs);

// This functions checks if the given locale is a native UI locale (e.g.,
// 'en-US', 'en-GB', 'fr', etc. are all valid, but 'en', 'en-WS' or 'fr-CH' are
// not)
bool IsNativeUILocale(const std::string& locale);

// This function returns an allowed UI locale based on the list of allowed UI
// locales (stored in |prefs|, managed by 'AllowedUILocales' policy). If none of
// the user's preferred languages is an allowed UI locale, the function returns
// the first valid entry in the allowed UI locales list. If the list contains no
// valid entries, the default fallback will be 'en-US'
// (kAllowedUILocalesFallbackLocale);
std::string GetAllowedFallbackUILocale(const PrefService* prefs);
// This function checks if the given language is allowed according to the list
// of allowed languages (stored in |prefs|, managed by 'AllowedLanguages'
// policy). If the list is empty, every language is allowed.
bool IsAllowedLanguage(const std::string& language, const PrefService* prefs);

// This function checks if the given language is allowed
// by 'AllowedLanguages' and also can be used as a UI locale.
// (see |IsAllowedLanguage|).
bool IsAllowedUILanguage(const std::string& language, const PrefService* prefs);

// This functions checks if the given language is a native UI language or can be
// converted to one. (e.g., 'en-US', 'fr', 'de', 'de-CH', 'fr-CH' etc. are all
// valid, but 'az' is not.
bool IsNativeUILanguage(const std::string& locale);

// This function removes languages that are disallowed by the
// 'AllowedLanguages' policy from the list of preferred languages.
// If no current preferred languages are allowed, this functions sets
// a language provided by GetAllowedFallbackLanguage() as the only preferred
// language.
void RemoveDisallowedLanguagesFromPreferred(PrefService* prefs);

// This function returns a fallback language that is allowed by the
// 'AllowedLanguages' policy and can be used as a UI language
// (see |IsNativeUILanguage|) as well. We check the user's preferred language
// for any of these conditions. If none of them match, we will take the first
// valid UI language in the list of allowed languages. If none of them are UI
// languages, we default to "en-US" (see kAllowedUILanguageFallback).
// languages (stored in |prefs|, managed by 'AllowedLanguages' policy). If none
// of the user's preferred languages is allowed, the function returns the first
// valid entry in the allowed languages list. If the list contains no valid
// entries, the default fallback will be 'en-US'
// (kAllowedLanguagesFallbackLocale);
std::string GetAllowedFallbackUILanguage(const PrefService* prefs);

// This function adds the |locale| to the list of preferred languages (pref
// |kLanguagePreferredLanguages|). Returns true if the locale was newly added
Expand Down
2 changes: 1 addition & 1 deletion chrome/browser/chromeos/locale_change_guard.cc
Original file line number Diff line number Diff line change
Expand Up @@ -168,7 +168,7 @@ void LocaleChangeGuard::Check() {

// Ensure that synchronization does not change the locale to a value not
// allowed by enterprise policy.
if (!chromeos::locale_util::IsAllowedUILocale(to_locale, prefs))
if (!chromeos::locale_util::IsAllowedUILanguage(to_locale, prefs))
prefs->SetString(language::prefs::kApplicationLocale, cur_locale);
return;
}
Expand Down
16 changes: 8 additions & 8 deletions chrome/browser/chromeos/login/session/user_session_manager.cc
Original file line number Diff line number Diff line change
Expand Up @@ -246,13 +246,13 @@ void InitLocaleAndInputMethodsForNewUser(
input_method_ids, &candidates);
for (size_t i = 0; i < candidates.size(); ++i) {
const std::string& candidate = candidates[i];
// Skip if it's already in language_codes.
// Add a candidate if it's not yet in language_codes and is allowed.
if (std::count(language_codes.begin(), language_codes.end(), candidate) ==
0) {
0 &&
locale_util::IsAllowedLanguage(candidate, prefs)) {
language_codes.push_back(candidate);
}
}

// Save the preferred languages in the user's preferences.
prefs->SetString(prefs::kLanguagePreferredLanguages,
base::JoinString(language_codes, ","));
Expand Down Expand Up @@ -798,7 +798,7 @@ bool UserSessionManager::RespectLocalePreference(
if (user_manager->GetLoggedInUsers().size() != 1)
return false;

const PrefService* prefs = profile->GetPrefs();
PrefService* prefs = profile->GetPrefs();
if (prefs == NULL)
return false;

Expand All @@ -814,7 +814,7 @@ bool UserSessionManager::RespectLocalePreference(

const std::string* account_locale = NULL;
if (pref_locale.empty() && user->has_gaia_account() &&
prefs->GetList(prefs::kAllowedUILocales)->GetList().empty()) {
prefs->GetList(prefs::kAllowedLanguages)->GetList().empty()) {
if (user->GetAccountLocale() == NULL)
return false; // wait until Account profile is loaded.
account_locale = user->GetAccountLocale();
Expand All @@ -839,9 +839,9 @@ bool UserSessionManager::RespectLocalePreference(
? Profile::APP_LOCALE_CHANGED_VIA_PUBLIC_SESSION_LOGIN
: Profile::APP_LOCALE_CHANGED_VIA_LOGIN;

// check if pref_locale is allowed by policy (AllowedUILocales)
if (!chromeos::locale_util::IsAllowedUILocale(pref_locale, prefs)) {
pref_locale = chromeos::locale_util::GetAllowedFallbackUILocale(prefs);
// check if pref_locale is allowed by policy (AllowedLanguages)
if (!chromeos::locale_util::IsAllowedUILanguage(pref_locale, prefs)) {
pref_locale = chromeos::locale_util::GetAllowedFallbackUILanguage(prefs);
app_locale_changed_via = Profile::APP_LOCALE_CHANGED_VIA_POLICY;
}

Expand Down
15 changes: 15 additions & 0 deletions chrome/browser/chromeos/preferences.cc
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
#include "chrome/browser/browser_process.h"
#include "chrome/browser/chrome_notification_types.h"
#include "chrome/browser/chromeos/accessibility/magnification_manager.h"
#include "chrome/browser/chromeos/base/locale_util.h"
#include "chrome/browser/chromeos/drive/file_system_util.h"
#include "chrome/browser/chromeos/input_method/input_method_syncer.h"
#include "chrome/browser/chromeos/login/session/user_session_manager.h"
Expand Down Expand Up @@ -336,6 +337,8 @@ void Preferences::RegisterProfilePrefs(
registry->RegisterStringPref(prefs::kLanguagePreviousInputMethod, "");
registry->RegisterListPref(prefs::kLanguageAllowedInputMethods,
std::make_unique<base::ListValue>());
registry->RegisterListPref(prefs::kAllowedLanguages,
std::make_unique<base::ListValue>());
registry->RegisterStringPref(prefs::kLanguagePreferredLanguages,
kFallbackInputMethodLocale);
registry->RegisterStringPref(prefs::kLanguagePreloadEngines,
Expand Down Expand Up @@ -551,6 +554,9 @@ void Preferences::InitUserPrefs(sync_preferences::PrefServiceSyncable* prefs) {
prefs, callback);
allowed_input_methods_.Init(prefs::kLanguageAllowedInputMethods, prefs,
callback);
allowed_languages_.Init(prefs::kAllowedLanguages, prefs, callback);
preferred_languages_.Init(prefs::kLanguagePreferredLanguages, prefs,
callback);
ime_menu_activated_.Init(prefs::kLanguageImeMenuActivated, prefs, callback);
// Notifies the system tray to remove the IME items.
if (base::FeatureList::IsEnabled(features::kOptInImeMenu) &&
Expand Down Expand Up @@ -821,6 +827,15 @@ void Preferences::ApplyPreferences(ApplyReason reason,
base::JoinString(ime_state_->GetActiveInputMethodIds(), ","));
}
}
if (reason != REASON_PREF_CHANGED || pref_name == prefs::kAllowedLanguages)
locale_util::RemoveDisallowedLanguagesFromPreferred(prefs_);

if (reason != REASON_PREF_CHANGED ||
pref_name == prefs::kLanguagePreferredLanguages) {
// In case setting has been changed with sync it can contain disallowed
// values.
locale_util::RemoveDisallowedLanguagesFromPreferred(prefs_);
}

if (reason == REASON_INITIALIZATION)
SetInputMethodList();
Expand Down
3 changes: 3 additions & 0 deletions chrome/browser/chromeos/preferences.h
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,9 @@ class Preferences : public sync_preferences::PrefServiceSyncableObserver,
BooleanPrefMember mouse_reverse_scroll_;
FilePathPrefMember download_default_directory_;

StringListPrefMember allowed_languages_;
StringPrefMember preferred_languages_;

// Input method preferences.
StringPrefMember preload_engines_;
StringPrefMember current_input_method_;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -87,13 +87,14 @@ std::unordered_set<std::string> GetIMEsFromPref(PrefService* prefs,
}

// Returns the set of allowed UI locales.
std::unordered_set<std::string> GetAllowedUILocales(PrefService* prefs) {
std::unordered_set<std::string> allowed_ui_locales;
std::unordered_set<std::string> GetAllowedLanguages(PrefService* prefs) {
std::unordered_set<std::string> allowed_languages;
const base::Value::ListStorage& pref_value =
prefs->GetList(prefs::kAllowedUILocales)->GetList();
prefs->GetList(prefs::kAllowedLanguages)->GetList();
for (const base::Value& locale_value : pref_value)
allowed_ui_locales.insert(locale_value.GetString());
return allowed_ui_locales;
allowed_languages.insert(locale_value.GetString());

return allowed_languages;
}

// Sorts the input methods by the order of their associated languages. For
Expand Down Expand Up @@ -215,7 +216,7 @@ LanguageSettingsPrivateGetLanguageListFunction::Run() {
std::unique_ptr<base::ListValue> language_list(new base::ListValue);
#if defined(OS_CHROMEOS)
const std::unordered_set<std::string> allowed_ui_locales(
GetAllowedUILocales(chrome_details_.GetProfile()->GetPrefs()));
GetAllowedLanguages(chrome_details_.GetProfile()->GetPrefs()));
#endif // defined(OS_CHROMEOS)
for (const auto& entry : languages) {
language_settings_private::Language language;
Expand All @@ -242,7 +243,7 @@ LanguageSettingsPrivateGetLanguageListFunction::Run() {
#if defined(OS_CHROMEOS)
if (!allowed_ui_locales.empty() &&
allowed_ui_locales.count(language.code) == 0) {
language.is_prohibited_ui_locale.reset(new bool(true));
language.is_prohibited_language.reset(new bool(true));
}
#endif // defined(OS_CHROMEOS)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -660,8 +660,8 @@ const PolicyToPreferenceMapEntry kSimplePolicyMap[] = {
{ key::kUserNativePrintersAllowed,
prefs::kUserNativePrintersAllowed,
base::Value::Type::BOOLEAN },
{ key::kAllowedUILocales,
prefs::kAllowedUILocales,
{ key::kAllowedLanguages,
prefs::kAllowedLanguages,
base::Value::Type::LIST },
{ key::kAllowedInputMethods,
prefs::kLanguageAllowedInputMethods,
Expand Down
Loading

0 comments on commit 1f16c5e

Please sign in to comment.