diff --git a/chrome/browser/chromeos/base/locale_util.cc b/chrome/browser/chromeos/base/locale_util.cc index 2d05f8b5c6bccb..54dc8bb7d3f881 100644 --- a/chrome/browser/chromeos/base/locale_util.cc +++ b/chrome/browser/chromeos/base/locale_util.cc @@ -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" @@ -63,13 +65,6 @@ void FinishSwitchLanguage(std::unique_ptr 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(); @@ -111,11 +106,20 @@ void FinishSwitchLanguage(std::unique_ptr data) { data->callback.Run(data->result); } +// Get parsed list of preferred languages from the 'kLanguagePreferredLanguages' +// setting. +std::vector 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, @@ -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 preferred_languages = + GetPreferredLanguagesList(prefs); + std::vector 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 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, diff --git a/chrome/browser/chromeos/base/locale_util.h b/chrome/browser/chromeos/base/locale_util.h index 2d01fac692f37d..fdb6cc14a003b6 100644 --- a/chrome/browser/chromeos/base/locale_util.h +++ b/chrome/browser/chromeos/base/locale_util.h @@ -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 diff --git a/chrome/browser/chromeos/locale_change_guard.cc b/chrome/browser/chromeos/locale_change_guard.cc index 8e1dae93b0729d..d5a76b3ad47f99 100644 --- a/chrome/browser/chromeos/locale_change_guard.cc +++ b/chrome/browser/chromeos/locale_change_guard.cc @@ -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; } diff --git a/chrome/browser/chromeos/login/session/user_session_manager.cc b/chrome/browser/chromeos/login/session/user_session_manager.cc index 37c14be133fbba..3e7124b4809110 100644 --- a/chrome/browser/chromeos/login/session/user_session_manager.cc +++ b/chrome/browser/chromeos/login/session/user_session_manager.cc @@ -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, ",")); @@ -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; @@ -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(); @@ -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; } diff --git a/chrome/browser/chromeos/preferences.cc b/chrome/browser/chromeos/preferences.cc index e6ab8e34860373..94c05e73e9469d 100644 --- a/chrome/browser/chromeos/preferences.cc +++ b/chrome/browser/chromeos/preferences.cc @@ -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" @@ -336,6 +337,8 @@ void Preferences::RegisterProfilePrefs( registry->RegisterStringPref(prefs::kLanguagePreviousInputMethod, ""); registry->RegisterListPref(prefs::kLanguageAllowedInputMethods, std::make_unique()); + registry->RegisterListPref(prefs::kAllowedLanguages, + std::make_unique()); registry->RegisterStringPref(prefs::kLanguagePreferredLanguages, kFallbackInputMethodLocale); registry->RegisterStringPref(prefs::kLanguagePreloadEngines, @@ -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) && @@ -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(); diff --git a/chrome/browser/chromeos/preferences.h b/chrome/browser/chromeos/preferences.h index 931d0d50a9d6e0..5b5f683b36b6bd 100644 --- a/chrome/browser/chromeos/preferences.h +++ b/chrome/browser/chromeos/preferences.h @@ -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_; diff --git a/chrome/browser/extensions/api/language_settings_private/language_settings_private_api.cc b/chrome/browser/extensions/api/language_settings_private/language_settings_private_api.cc index 19df4358af60ff..804e993345f810 100644 --- a/chrome/browser/extensions/api/language_settings_private/language_settings_private_api.cc +++ b/chrome/browser/extensions/api/language_settings_private/language_settings_private_api.cc @@ -87,13 +87,14 @@ std::unordered_set GetIMEsFromPref(PrefService* prefs, } // Returns the set of allowed UI locales. -std::unordered_set GetAllowedUILocales(PrefService* prefs) { - std::unordered_set allowed_ui_locales; +std::unordered_set GetAllowedLanguages(PrefService* prefs) { + std::unordered_set 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 @@ -215,7 +216,7 @@ LanguageSettingsPrivateGetLanguageListFunction::Run() { std::unique_ptr language_list(new base::ListValue); #if defined(OS_CHROMEOS) const std::unordered_set 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; @@ -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) diff --git a/chrome/browser/policy/configuration_policy_handler_list_factory.cc b/chrome/browser/policy/configuration_policy_handler_list_factory.cc index 0fc986465ce93f..d1b76af2c75236 100644 --- a/chrome/browser/policy/configuration_policy_handler_list_factory.cc +++ b/chrome/browser/policy/configuration_policy_handler_list_factory.cc @@ -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, diff --git a/chrome/browser/policy/policy_browsertest.cc b/chrome/browser/policy/policy_browsertest.cc index c49c9a7bf1ac10..5b1bb7bba07743 100644 --- a/chrome/browser/policy/policy_browsertest.cc +++ b/chrome/browser/policy/policy_browsertest.cc @@ -1234,7 +1234,7 @@ IN_PROC_BROWSER_TEST_F(LocalePolicyTest, ApplicationLocaleValue) { #endif #if defined(OS_CHROMEOS) -IN_PROC_BROWSER_TEST_F(LoginPolicyTestBase, PRE_AllowedUILocales) { +IN_PROC_BROWSER_TEST_F(LoginPolicyTestBase, PRE_AllowedLanguages) { SkipToLoginScreen(); LogIn(kAccountId, kAccountPassword, kEmptyServices); @@ -1251,13 +1251,13 @@ IN_PROC_BROWSER_TEST_F(LoginPolicyTestBase, PRE_AllowedUILocales) { // Set policy to only allow "fr" as locale. std::unique_ptr policy = std::make_unique(); - base::ListValue allowed_ui_locales; - allowed_ui_locales.AppendString("fr"); - policy->SetKey(key::kAllowedUILocales, std::move(allowed_ui_locales)); + base::ListValue allowed_languages; + allowed_languages.AppendString("fr"); + policy->SetKey(key::kAllowedLanguages, std::move(allowed_languages)); user_policy_helper()->UpdatePolicy(*policy, base::DictionaryValue(), profile); } -IN_PROC_BROWSER_TEST_F(LoginPolicyTestBase, AllowedUILocales) { +IN_PROC_BROWSER_TEST_F(LoginPolicyTestBase, AllowedLanguages) { LogIn(kAccountId, kAccountPassword, kEmptyServices); const user_manager::User* const user = @@ -1286,7 +1286,7 @@ IN_PROC_BROWSER_TEST_F(LoginPolicyTestBase, AllowedUILocales) { // Verifiy that the enforced locale is added into the list of // preferred languages. - EXPECT_EQ("en-US,fr", prefs->GetString(prefs::kLanguagePreferredLanguages)); + EXPECT_EQ("fr", prefs->GetString(prefs::kLanguagePreferredLanguages)); } IN_PROC_BROWSER_TEST_F(LoginPolicyTestBase, AllowedInputMethods) { diff --git a/chrome/browser/profiles/profile.cc b/chrome/browser/profiles/profile.cc index 3bb5207dc4e666..2913a5c4669915 100644 --- a/chrome/browser/profiles/profile.cc +++ b/chrome/browser/profiles/profile.cc @@ -181,8 +181,6 @@ void Profile::RegisterProfilePrefs(user_prefs::PrefRegistrySyncable* registry) { registry->RegisterStringPref(prefs::kApplicationLocaleBackup, std::string()); registry->RegisterStringPref(prefs::kApplicationLocaleAccepted, std::string()); - registry->RegisterListPref(prefs::kAllowedUILocales, - std::make_unique()); #endif registry->RegisterBooleanPref(prefs::kDataSaverEnabled, false); diff --git a/chrome/browser/profiles/profile.h b/chrome/browser/profiles/profile.h index 9b651ce8ff5973..c01dfe0e024168 100644 --- a/chrome/browser/profiles/profile.h +++ b/chrome/browser/profiles/profile.h @@ -232,7 +232,7 @@ class Profile : public content::BrowserContext { APP_LOCALE_CHANGED_VIA_LOGIN, // From login to a public session. APP_LOCALE_CHANGED_VIA_PUBLIC_SESSION_LOGIN, - // From AllowedUILocales policy. + // From AllowedLanguages policy APP_LOCALE_CHANGED_VIA_POLICY, // From demo session. APP_LOCALE_CHANGED_VIA_DEMO_SESSION, diff --git a/chrome/browser/profiles/profile_impl.cc b/chrome/browser/profiles/profile_impl.cc index b975e29fbe180b..2d4347e474b329 100644 --- a/chrome/browser/profiles/profile_impl.cc +++ b/chrome/browser/profiles/profile_impl.cc @@ -308,6 +308,17 @@ std::string ExitTypeToSessionTypePrefValue(Profile::ExitType type) { return std::string(); } +#if defined(OS_CHROMEOS) +// Checks if |new_locale| is the same as |pref_locale| or |pref_locale| is used +// to show UI translation for |new_locale|. (e.g. "it" is used for "it-CH") +bool LocaleNotChanged(const std::string& pref_locale, + const std::string& new_locale) { + std::string new_locale_converted = new_locale; + language::ConvertToActualUILocale(&new_locale_converted); + return pref_locale == new_locale_converted; +} +#endif // defined(OS_CHROMEOS) + #if !defined(OS_ANDROID) std::unique_ptr CreateAppService(Profile* profile) { // TODO(crbug.com/826982): use |profile| to fetch existing registries. @@ -1295,7 +1306,7 @@ void ProfileImpl::ChangeAppLocale(const std::string& new_locale, case APP_LOCALE_CHANGED_VIA_LOGIN: case APP_LOCALE_CHANGED_VIA_PUBLIC_SESSION_LOGIN: { if (!pref_locale.empty()) { - DCHECK(pref_locale == new_locale); + DCHECK(LocaleNotChanged(pref_locale, new_locale)); std::string accepted_locale = GetPrefs()->GetString(prefs::kApplicationLocaleAccepted); if (accepted_locale == new_locale) { diff --git a/chrome/browser/resources/settings/languages_page/add_languages_dialog.js b/chrome/browser/resources/settings/languages_page/add_languages_dialog.js index 77c6b94a5212e0..610e3d758ce690 100644 --- a/chrome/browser/resources/settings/languages_page/add_languages_dialog.js +++ b/chrome/browser/resources/settings/languages_page/add_languages_dialog.js @@ -84,15 +84,9 @@ Polymer({ const filterValue = this.filterValue_ ? this.filterValue_.toLowerCase() : null; return this.languages.supported.filter(language => { - const isAvailableLanguage = - !this.languageHelper.isLanguageEnabled(language.code); - - if (!isAvailableLanguage) + if (!this.languageHelper.canEnableLanguage(language)) return false; - if (this.languageHelper.isLanguageCodeForArcIme(language.code)) - return false; // internal use only - if (filterValue === null) return true; diff --git a/chrome/browser/resources/settings/languages_page/languages.js b/chrome/browser/resources/settings/languages_page/languages.js index 6c81d0d59f5775..50a2d02521d687 100644 --- a/chrome/browser/resources/settings/languages_page/languages.js +++ b/chrome/browser/resources/settings/languages_page/languages.js @@ -427,7 +427,7 @@ Polymer({ language.supportsUI = !!language.supportsUI; language.supportsTranslate = !!language.supportsTranslate; language.supportsSpellcheck = !!language.supportsSpellcheck; - language.isProhibitedUILocale = !!language.isProhibitedUILocale; + language.isProhibitedLanguage = !!language.isProhibitedLanguage; this.supportedLanguageMap_.set(language.code, language); } @@ -810,6 +810,17 @@ Polymer({ return otherInputMethodsEnabled; }, + /** + * @param {!chrome.languageSettingsPrivate.Language} language + * @return {boolean} true if the given language can be enabled + */ + canEnableLanguage(language) { + return !( + this.isLanguageEnabled(language.code) || + language.isProhibitedLanguage || + this.isLanguageCodeForArcIme(language.code) /* internal use only */); + }, + /** * Moves the language in the list of enabled languages either up (toward the * front of the list) or down (toward the back). diff --git a/chrome/browser/resources/settings/languages_page/languages_page.html b/chrome/browser/resources/settings/languages_page/languages_page.html index a979b391e5536d..948ac4ecd1b65d 100644 --- a/chrome/browser/resources/settings/languages_page/languages_page.html +++ b/chrome/browser/resources/settings/languages_page/languages_page.html @@ -177,6 +177,7 @@
$i18n{addLanguages} @@ -333,7 +334,7 @@ detailLanguage_, languages.prospectiveUILanguage)]]"> $i18n{displayInThisLanguage} + !detailLanguage_.language.isProhibitedLanguage]]"> diff --git a/chrome/browser/resources/settings/languages_page/languages_page.js b/chrome/browser/resources/settings/languages_page/languages_page.js index 7928445d2a3160..008a432547d2f0 100644 --- a/chrome/browser/resources/settings/languages_page/languages_page.js +++ b/chrome/browser/resources/settings/languages_page/languages_page.js @@ -154,6 +154,19 @@ Polymer({ cr.ui.focusWithoutInk(assert(this.$.addLanguages)); }, + /** + * Checks if there are supported languages that are not enabled but can be + * enabled. + * @param {LanguagesModel|undefined} languages + * @return {boolean} True if there is at least one available language. + * @private + */ + canEnableSomeSupportedLanguage_: function(languages) { + return languages == undefined || languages.supported.some(language => { + return this.languageHelper.canEnableLanguage(language); + }); + }, + /** * Used to determine which "Move" buttons to show for ordering enabled * languages. @@ -306,9 +319,9 @@ Polymer({ if (languageState.language.code == prospectiveUILanguage) return true; - // Check if the language is prohibited by the current "AllowedUILocales" + // Check if the language is prohibited by the current "AllowedLanguages" // policy. - if (languageState.language.isProhibitedUILocale) + if (languageState.language.isProhibitedLanguage) return true; // Otherwise, the prospective language can be changed to this language. diff --git a/chrome/browser/resources/settings/languages_page/languages_types.js b/chrome/browser/resources/settings/languages_page/languages_types.js index 2186c699bfcdde..e86905dd7f1dbc 100644 --- a/chrome/browser/resources/settings/languages_page/languages_types.js +++ b/chrome/browser/resources/settings/languages_page/languages_types.js @@ -131,6 +131,12 @@ class LanguageHelper { */ canDisableLanguage(languageCode) {} + /** + * @param {!chrome.languageSettingsPrivate.Language} language + * @return {boolean} true if the given language can be enabled + */ + canEnableLanguage(language) {} + /** * Moves the language in the list of enabled languages by the given offset. * @param {string} languageCode diff --git a/chrome/browser/ui/webui/settings/languages_handler.cc b/chrome/browser/ui/webui/settings/languages_handler.cc index f7ef878a97c3d6..94fbcf148ab720 100644 --- a/chrome/browser/ui/webui/settings/languages_handler.cc +++ b/chrome/browser/ui/webui/settings/languages_handler.cc @@ -71,14 +71,6 @@ void LanguagesHandler::HandleSetProspectiveUILanguage( std::string language_code; CHECK(args->GetString(0, &language_code)); -#if defined(OS_CHROMEOS) - // check if prospectiveUILanguage is allowed by policy (AllowedUILocales) - if (!chromeos::locale_util::IsAllowedUILocale(language_code, - profile_->GetPrefs())) { - return; - } -#endif - #if defined(OS_WIN) PrefService* prefs = g_browser_process->local_state(); prefs->SetString(language::prefs::kApplicationLocale, language_code); diff --git a/chrome/common/extensions/api/language_settings_private.idl b/chrome/common/extensions/api/language_settings_private.idl index 3a30cb0406bbbb..e0492c4a21f259 100644 --- a/chrome/common/extensions/api/language_settings_private.idl +++ b/chrome/common/extensions/api/language_settings_private.idl @@ -33,8 +33,8 @@ namespace languageSettingsPrivate { boolean? supportsTranslate; // Whether this language is prohibited as a UI locale (not in the list of - // the 'AllowedUILocales' policy). Defaults to false. - boolean? isProhibitedUILocale; + // the 'AllowedLanguages' policy). Defaults to false. + boolean? isProhibitedLanguage; }; dictionary SpellcheckDictionaryStatus { diff --git a/chrome/common/pref_names.cc b/chrome/common/pref_names.cc index c4e7758ba1dbee..edbb847115a6c2 100644 --- a/chrome/common/pref_names.cc +++ b/chrome/common/pref_names.cc @@ -231,7 +231,7 @@ const char kApplicationLocaleBackup[] = "intl.app_locale_backup"; // List of locales the UI is allowed to be displayed in by policy. The list is // empty if no restriction is being enforced. -const char kAllowedUILocales[] = "intl.allowed_ui_locales"; +const char kAllowedLanguages[] = "intl.allowed_languages"; #endif // The default character encoding to assume for a web page in the diff --git a/chrome/common/pref_names.h b/chrome/common/pref_names.h index 582cde5f2751e0..d20ec03d26a417 100644 --- a/chrome/common/pref_names.h +++ b/chrome/common/pref_names.h @@ -70,7 +70,7 @@ extern const char kRlzPingDelaySeconds[]; extern const char kApplicationLocaleBackup[]; extern const char kApplicationLocaleAccepted[]; extern const char kOwnerLocale[]; -extern const char kAllowedUILocales[]; +extern const char kAllowedLanguages[]; #endif extern const char kDefaultCharset[]; diff --git a/chrome/test/data/policy/policy_test_cases.json b/chrome/test/data/policy/policy_test_cases.json index 57120bb7d493b4..528e11e4684182 100644 --- a/chrome/test/data/policy/policy_test_cases.json +++ b/chrome/test/data/policy/policy_test_cases.json @@ -3303,12 +3303,12 @@ ] }, - "AllowedUILocales": { + "AllowedLanguages": { "os": ["chromeos"], "can_be_recommended": false, - "test_policy": { "AllowedUILocales": ["en-US", "de"] }, + "test_policy": { "AllowedLanguages": ["en-US", "de"] }, "pref_mappings": [ - { "pref": "intl.allowed_ui_locales" } + { "pref": "intl.allowed_languages" } ] }, diff --git a/components/language/core/common/locale_util.cc b/components/language/core/common/locale_util.cc index f2ccb366379a81..4bf0a92cc761e2 100644 --- a/components/language/core/common/locale_util.cc +++ b/components/language/core/common/locale_util.cc @@ -52,6 +52,13 @@ bool GetUIFallbackLocale(const std::string& input, std::string* const output) { return false; } +// Checks if |locale| is one of the actual locales supported as a UI languages. +bool IsAvailableUILocale(const std::string& locale) { + const std::vector& ui_locales = l10n_util::GetAvailableLocales(); + return std::find(ui_locales.begin(), ui_locales.end(), locale) != + ui_locales.end(); +} + } // namespace void SplitIntoMainAndTail(const std::string& locale, @@ -88,23 +95,27 @@ bool ContainsSameBaseLanguage(const std::vector& list, return false; } -bool ConvertToActualUILocale(std::string* input_locale) { - const std::vector& ui_locales = l10n_util::GetAvailableLocales(); - const std::set ui_set(ui_locales.begin(), ui_locales.end()); - +bool ConvertToFallbackUILocale(std::string* input_locale) { // 1) Convert input to a fallback, if available. std::string fallback; GetUIFallbackLocale(*input_locale, &fallback); // 2) Check if input is part of the UI languages. - if (ui_set.count(fallback) > 0) { + if (IsAvailableUILocale(fallback)) { *input_locale = fallback; return true; } - // 3) Check if the base language of the input is part of the UI languages. + return false; +} + +bool ConvertToActualUILocale(std::string* input_locale) { + if (ConvertToFallbackUILocale(input_locale)) + return true; + + // Check if the base language of the input is part of the UI languages. const std::string base = ExtractBaseLanguage(*input_locale); - if (base != *input_locale && ui_set.count(base) > 0) { + if (base != *input_locale && IsAvailableUILocale(base)) { *input_locale = base; return true; } diff --git a/components/language/core/common/locale_util.h b/components/language/core/common/locale_util.h index 067d0f862cc507..bac62cecb8c049 100644 --- a/components/language/core/common/locale_util.h +++ b/components/language/core/common/locale_util.h @@ -26,6 +26,10 @@ std::string ExtractBaseLanguage(const std::string& language_code); bool ContainsSameBaseLanguage(const std::vector& list, const std::string& language_code); +// Converts |input_locale| to a fallback if needed and checks that the +// resulting locale is supported as a UI locale. +bool ConvertToFallbackUILocale(std::string* input_locale); + // Converts the input locale into its corresponding actual UI locale that // Chrome should use for display and returns whether such locale exist. // This method must be called whenever the display locale preference is diff --git a/components/policy/resources/policy_templates.json b/components/policy/resources/policy_templates.json index 0cc1e1c92ea21d..44d86b2b4341fe 100644 --- a/components/policy/resources/policy_templates.json +++ b/components/policy/resources/policy_templates.json @@ -12588,13 +12588,13 @@ This policy is not available on Windows instances that are not joined to a Microsoft® Active Directory® domain.''', }, { - 'name': 'AllowedUILocales', + 'name': 'AllowedLanguages', 'type': 'list', 'schema': { 'type': 'array', 'items': { 'type': 'string' }, }, - 'supported_on': ['chrome_os:68-'], + 'supported_on': ['chrome_os:72-'], 'device_only': False, 'features': { 'dynamic_refresh': False, @@ -12603,11 +12603,11 @@ 'example_value': [ 'en-US' ], 'max_size': 16777216, 'id': 444, - 'caption': '''Configure the allowed UI locales in a user session''', + 'caption': '''Configure the allowed languages in a user session''', 'tags': [], - 'desc': '''Configures the locales $2Google Chrome OS may be displayed in. + 'desc': '''Configures the languages that can be used as the preferred languages by $2Google Chrome OS. - If this policy is set, the user can only configure $2Google Chrome OS to be displayed in one of the locales specified by this policy. If this policy is not set or set to an empty list, $2Google Chrome OS can be displayed in all supported UI locales. If this policy is set to a list with invalid values, all invalid values will be ignored. If a user previously configured $2Google Chrome OS to be displayed in a locale that is not allowed by this policy, the display locale will be switched to an allowed UI locale the next time the user signs in. If the user had configured preferred locales and one of the preferred locales is allowed by this policy, $2Google Chrome OS will switch to this locale. Otherwise, $2Google Chrome OS will switch to the first valid value specified by this policy, or to a fallback locale (currently en-US), if this policy only contains invalid entries.''' + If this policy is set, the user can only add one of the languages listed in this policy to the list of preferred languages. If this policy is not set or set to an empty list, user can specify any languages as preferred. If this policy is set to a list with invalid values, all invalid values will be ignored. If a user previously added some languages that are not allowed by this policy to the list of preferred languages they will be removed. If the user had previously configured $2Google Chrome OS to be displayed in one of the languages not allowed by this policy, the display language will be switched to an allowed UI language next time user signs in. Otherwise, $2Google Chrome OS will switch to the first valid value specified by this policy, or to a fallback locale (currently en-US), if this policy only contains invalid entries.''' }, { 'name': 'AllowedInputMethods', diff --git a/third_party/closure_compiler/externs/language_settings_private.js b/third_party/closure_compiler/externs/language_settings_private.js index f82fa01d46ebcd..a656d4203052ea 100644 --- a/third_party/closure_compiler/externs/language_settings_private.js +++ b/third_party/closure_compiler/externs/language_settings_private.js @@ -34,7 +34,7 @@ chrome.languageSettingsPrivate.MoveType = { * supportsUI: (boolean|undefined), * supportsSpellcheck: (boolean|undefined), * supportsTranslate: (boolean|undefined), - * isProhibitedUILocale: (boolean|undefined) + * isProhibitedLanguage: (boolean|undefined) * }} */ chrome.languageSettingsPrivate.Language; diff --git a/tools/metrics/histograms/enums.xml b/tools/metrics/histograms/enums.xml index b6223c645c5afc..e1217481f4334c 100644 --- a/tools/metrics/histograms/enums.xml +++ b/tools/metrics/histograms/enums.xml @@ -14741,7 +14741,7 @@ Called by update_net_error_codes.py.--> - +