Moving blocked languages to language component.

Change-Id: Idc8bcb92d4ca17532df631fba64a24412cf75265
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1508776
Commit-Queue: Alexandre Frechette <[email protected]>
Reviewed-by: Dominic Battré <[email protected]>
Reviewed-by: Eugene But <[email protected]>
Reviewed-by: Avi Drissman <[email protected]>
Reviewed-by: anthonyvd <[email protected]>
Reviewed-by: Moe Ahmadi <[email protected]>
Cr-Commit-Position: refs/heads/master@{#641966}
diff --git a/chrome/browser/extensions/api/settings_private/prefs_util.cc b/chrome/browser/extensions/api/settings_private/prefs_util.cc
index 37c4bb0..57bac8d 100644
--- a/chrome/browser/extensions/api/settings_private/prefs_util.cc
+++ b/chrome/browser/extensions/api/settings_private/prefs_util.cc
@@ -236,7 +236,7 @@
       settings_api::PrefType::PREF_TYPE_BOOLEAN;
   (*s_whitelist)[::prefs::kOfferTranslateEnabled] =
       settings_api::PrefType::PREF_TYPE_BOOLEAN;
-  (*s_whitelist)[translate::TranslatePrefs::kPrefTranslateBlockedLanguages] =
+  (*s_whitelist)[language::prefs::kFluentLanguages] =
       settings_api::PrefType::PREF_TYPE_LIST;
 #if defined(OS_CHROMEOS)
   (*s_whitelist)[::prefs::kLanguageImeMenuActivated] =
diff --git a/chrome/browser/prefs/browser_prefs.cc b/chrome/browser/prefs/browser_prefs.cc
index a1cf6d1..dba030d 100644
--- a/chrome/browser/prefs/browser_prefs.cc
+++ b/chrome/browser/prefs/browser_prefs.cc
@@ -610,7 +610,7 @@
   image_fetcher::ImageCache::RegisterProfilePrefs(registry);
   ImportantSitesUtil::RegisterProfilePrefs(registry);
   IncognitoModePrefs::RegisterProfilePrefs(registry);
-  language::RegisterProfilePrefs(registry);
+  language::LanguagePrefs::RegisterProfilePrefs(registry);
   MediaCaptureDevicesDispatcher::RegisterProfilePrefs(registry);
   MediaDeviceIDSalt::RegisterProfilePrefs(registry);
   MediaEngagementService::RegisterProfilePrefs(registry);
diff --git a/chrome/browser/ui/webui/translate_internals/translate_internals_handler.cc b/chrome/browser/ui/webui/translate_internals/translate_internals_handler.cc
index a6b21762..9a9d1b2 100644
--- a/chrome/browser/ui/webui/translate_internals/translate_internals_handler.cc
+++ b/chrome/browser/ui/webui/translate_internals/translate_internals_handler.cc
@@ -215,9 +215,9 @@
   base::DictionaryValue dict;
 
   static const char* const keys[] = {
+      language::prefs::kFluentLanguages,
       prefs::kOfferTranslateEnabled,
       translate::TranslatePrefs::kPrefTranslateRecentTarget,
-      translate::TranslatePrefs::kPrefTranslateBlockedLanguages,
       translate::TranslatePrefs::kPrefTranslateSiteBlacklistDeprecated,
       translate::TranslatePrefs::kPrefTranslateSiteBlacklistWithTime,
       translate::TranslatePrefs::kPrefTranslateWhitelists,
diff --git a/components/language/DEPS b/components/language/DEPS
index fcb6de9..5ab36a5 100644
--- a/components/language/DEPS
+++ b/components/language/DEPS
@@ -2,6 +2,7 @@
   "+components/pref_registry",
   "+components/prefs",
   "+components/strings/grit/components_locale_settings.h",
+  "+components/sync_preferences",
   "+third_party/s2cellid",
 
   "-components/language/content",
diff --git a/components/language/core/browser/BUILD.gn b/components/language/core/browser/BUILD.gn
index bd59d2b..45e6786 100644
--- a/components/language/core/browser/BUILD.gn
+++ b/components/language/core/browser/BUILD.gn
@@ -25,6 +25,7 @@
   deps = [
     "//base",
     "//components/keyed_service/core",
+    "//components/language/core/common",
     "//components/pref_registry",
     "//components/prefs",
     "//components/strings",
@@ -37,6 +38,7 @@
   sources = [
     "baseline_language_model_unittest.cc",
     "heuristic_language_model_unittest.cc",
+    "language_prefs_unittest.cc",
     "url_language_histogram_unittest.cc",
   ]
   deps = [
@@ -45,6 +47,7 @@
     "//components/pref_registry:pref_registry",
     "//components/prefs",
     "//components/prefs:test_support",
+    "//components/sync_preferences:test_support",
     "//net:test_support",
     "//testing/gmock",
     "//testing/gtest",
diff --git a/components/language/core/browser/language_prefs.cc b/components/language/core/browser/language_prefs.cc
index bc2dc11..317aa1d 100644
--- a/components/language/core/browser/language_prefs.cc
+++ b/components/language/core/browser/language_prefs.cc
@@ -4,8 +4,22 @@
 
 #include "components/language/core/browser/language_prefs.h"
 
+#include <algorithm>
+#include <set>
+#include <utility>
+#include <vector>
+
+#include "base/stl_util.h"
+#include "base/strings/string_piece.h"
+#include "base/strings/string_split.h"
+#include "base/strings/string_util.h"
+#include "base/values.h"
 #include "components/language/core/browser/pref_names.h"
+#include "components/language/core/common/language_util.h"
+#include "components/language/core/common/locale_util.h"
 #include "components/pref_registry/pref_registry_syncable.h"
+#include "components/prefs/pref_service.h"
+#include "components/prefs/scoped_user_pref_update.h"
 #include "components/strings/grit/components_locale_settings.h"
 #include "ui/base/l10n/l10n_util.h"
 
@@ -13,7 +27,8 @@
 
 const char kFallbackInputMethodLocale[] = "en-US";
 
-void RegisterProfilePrefs(user_prefs::PrefRegistrySyncable* registry) {
+void LanguagePrefs::RegisterProfilePrefs(
+    user_prefs::PrefRegistrySyncable* registry) {
   registry->RegisterStringPref(language::prefs::kAcceptLanguages,
                                l10n_util::GetStringUTF8(IDS_ACCEPT_LANGUAGES),
                                user_prefs::PrefRegistrySyncable::SYNCABLE_PREF);
@@ -24,6 +39,77 @@
   registry->RegisterStringPref(language::prefs::kPreferredLanguagesSyncable, "",
                                user_prefs::PrefRegistrySyncable::SYNCABLE_PREF);
 #endif
+  registry->RegisterListPref(language::prefs::kFluentLanguages,
+                             LanguagePrefs::GetDefaultFluentLanguages(),
+                             user_prefs::PrefRegistrySyncable::SYNCABLE_PREF);
+}
+
+LanguagePrefs::LanguagePrefs(PrefService* user_prefs) : prefs_(user_prefs) {
+  ResetEmptyFluentLanguagesToDefault();
+}
+
+bool LanguagePrefs::IsFluent(const std::string& language) const {
+  std::string canonical_lang = language;
+  language::ToTranslateLanguageSynonym(&canonical_lang);
+  const base::Value* fluents =
+      prefs_->GetList(language::prefs::kFluentLanguages);
+  return base::ContainsValue(fluents->GetList(), base::Value(canonical_lang));
+}
+
+void LanguagePrefs::SetFluent(const std::string& language) {
+  if (IsFluent(language))
+    return;
+  std::string canonical_lang = language;
+  language::ToTranslateLanguageSynonym(&canonical_lang);
+  ListPrefUpdate update(prefs_, language::prefs::kFluentLanguages);
+  update->GetList().emplace_back(std::move(canonical_lang));
+}
+
+void LanguagePrefs::ClearFluent(const std::string& language) {
+  if (NumFluentLanguages() <= 1)  // Never remove last fluent language.
+    return;
+  std::string canonical_lang = language;
+  language::ToTranslateLanguageSynonym(&canonical_lang);
+  ListPrefUpdate update(prefs_, language::prefs::kFluentLanguages);
+  base::Erase(update->GetList(), base::Value(canonical_lang));
+}
+
+void LanguagePrefs::ResetFluentLanguagesToDefaults() {
+  // Reset pref to defaults.
+  prefs_->ClearPref(language::prefs::kFluentLanguages);
+}
+
+void LanguagePrefs::ResetEmptyFluentLanguagesToDefault() {
+  if (NumFluentLanguages() == 0)
+    ResetFluentLanguagesToDefaults();
+}
+
+base::Value LanguagePrefs::GetDefaultFluentLanguages() {
+  std::set<const std::string> languages;
+#if defined(OS_CHROMEOS)
+  // Preferred languages.
+  std::string language = language::kFallbackInputMethodLocale;
+  language::ToTranslateLanguageSynonym(&language);
+  languages.insert(std::move(language));
+#else
+  // Accept languages.
+  for (std::string language :
+       base::SplitString(l10n_util::GetStringUTF8(IDS_ACCEPT_LANGUAGES), ",",
+                         base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL)) {
+    language::ToTranslateLanguageSynonym(&language);
+    languages.insert(std::move(language));
+  }
+#endif
+  base::Value language_values(base::Value::Type::LIST);
+  for (const std::string& language : languages)
+    language_values.GetList().emplace_back(language);
+  return language_values;
+}
+
+size_t LanguagePrefs::NumFluentLanguages() const {
+  const base::Value* fluents =
+      prefs_->GetList(language::prefs::kFluentLanguages);
+  return fluents->GetList().size();
 }
 
 }  // namespace language
diff --git a/components/language/core/browser/language_prefs.h b/components/language/core/browser/language_prefs.h
index 296ed932..fb32a8c 100644
--- a/components/language/core/browser/language_prefs.h
+++ b/components/language/core/browser/language_prefs.h
@@ -5,6 +5,16 @@
 #ifndef COMPONENTS_LANGUAGE_CORE_BROWSER_LANGUAGE_PREFS_H_
 #define COMPONENTS_LANGUAGE_CORE_BROWSER_LANGUAGE_PREFS_H_
 
+#include <string>
+
+#include "base/macros.h"
+
+class PrefService;
+
+namespace base {
+class Value;
+}  // namespace base
+
 namespace user_prefs {
 class PrefRegistrySyncable;
 }
@@ -13,7 +23,36 @@
 
 extern const char kFallbackInputMethodLocale[];
 
-void RegisterProfilePrefs(user_prefs::PrefRegistrySyncable* registry);
+class LanguagePrefs {
+ public:
+  static void RegisterProfilePrefs(user_prefs::PrefRegistrySyncable* registry);
+
+  LanguagePrefs(PrefService* user_prefs);
+
+  // Return true iff the user is fluent in the given |language|.
+  bool IsFluent(const std::string& language) const;
+  // Mark that the user is fluent in the given |language|.
+  void SetFluent(const std::string& language);
+  // Remove the given |language| from the user's fluent languages.
+  void ClearFluent(const std::string& language);
+  // Reset the fluent languages to their defaults.
+  void ResetFluentLanguagesToDefaults();
+  // Get the default fluent languages for the user.
+  static base::Value GetDefaultFluentLanguages();
+  // If the list of fluent languages is empty, reset it to defaults.
+  void ResetEmptyFluentLanguagesToDefault();
+
+ private:
+  base::Value* GetFluentLanguages();
+
+  const base::Value* GetFluentLanguages() const;
+
+  size_t NumFluentLanguages() const;
+
+  PrefService* prefs_;  // Weak.
+
+  DISALLOW_COPY_AND_ASSIGN(LanguagePrefs);
+};
 
 }  // namespace language
 
diff --git a/components/language/core/browser/language_prefs_unittest.cc b/components/language/core/browser/language_prefs_unittest.cc
new file mode 100644
index 0000000..1b8be62
--- /dev/null
+++ b/components/language/core/browser/language_prefs_unittest.cc
@@ -0,0 +1,155 @@
+// Copyright 2014 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 "components/language/core/browser/language_prefs.h"
+
+#include <algorithm>
+#include <memory>
+#include <string>
+#include <utility>
+#include <vector>
+
+#include "base/json/json_reader.h"
+#include "base/test/scoped_feature_list.h"
+#include "base/test/test_timeouts.h"
+#include "base/values.h"
+#include "build/build_config.h"
+#include "components/language/core/browser/pref_names.h"
+#include "components/prefs/scoped_user_pref_update.h"
+#include "components/sync_preferences/testing_pref_service_syncable.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace language {
+
+static void ExpectEqualLanguageLists(
+    const base::Value* language_values,
+    const std::vector<std::string>& languages) {
+  const int input_size = languages.size();
+  ASSERT_EQ(input_size, static_cast<int>(language_values->GetList().size()));
+  for (int i = 0; i < input_size; ++i) {
+    std::string value = language_values->GetList().at(i).GetString();
+    EXPECT_EQ(languages[i], value);
+  }
+}
+
+class LanguagePrefsTest : public testing::Test {
+ protected:
+  LanguagePrefsTest()
+      : prefs_(new sync_preferences::TestingPrefServiceSyncable()) {
+    LanguagePrefs::RegisterProfilePrefs(prefs_->registry());
+    language_prefs_.reset(new language::LanguagePrefs(prefs_.get()));
+  }
+
+  void ExpectFluentLanguageListContent(
+      const std::vector<std::string>& list) const {
+    const base::Value* values = prefs_->Get(language::prefs::kFluentLanguages);
+    DCHECK(values);
+    ExpectEqualLanguageLists(values, list);
+  }
+
+  std::unique_ptr<sync_preferences::TestingPrefServiceSyncable> prefs_;
+  std::unique_ptr<language::LanguagePrefs> language_prefs_;
+};
+
+TEST_F(LanguagePrefsTest, SetFluentTest) {
+  // `en` is a default fluent language, it should be present already.
+  ExpectFluentLanguageListContent({"en"});
+
+  // One language.
+  language_prefs_->SetFluent("fr-CA");
+  ExpectFluentLanguageListContent({"en", "fr"});
+
+  // Add a few more.
+  language_prefs_->SetFluent("es-AR");
+  language_prefs_->SetFluent("de-de");
+  ExpectFluentLanguageListContent({"en", "fr", "es", "de"});
+
+  // Add a duplicate.
+  language_prefs_->ResetFluentLanguagesToDefaults();
+  ExpectFluentLanguageListContent({"en"});
+  language_prefs_->SetFluent("es-AR");
+  language_prefs_->SetFluent("es-AR");
+  ExpectFluentLanguageListContent({"en", "es"});
+
+  // Two languages with the same base.
+  language_prefs_->ResetFluentLanguagesToDefaults();
+  language_prefs_->SetFluent("fr-CA");
+  language_prefs_->SetFluent("fr-FR");
+  ExpectFluentLanguageListContent({"en", "fr"});
+
+  // Chinese is a special case.
+  language_prefs_->ResetFluentLanguagesToDefaults();
+  language_prefs_->SetFluent("zh-MO");
+  language_prefs_->SetFluent("zh-CN");
+  ExpectFluentLanguageListContent({"en", "zh-TW", "zh-CN"});
+
+  language_prefs_->ResetFluentLanguagesToDefaults();
+  language_prefs_->SetFluent("zh-TW");
+  language_prefs_->SetFluent("zh-HK");
+  ExpectFluentLanguageListContent({"en", "zh-TW"});
+}
+
+TEST_F(LanguagePrefsTest, ClearFluentTest) {
+  // Language in the list.
+  // Should not clear fluent for last language.
+  language_prefs_->ClearFluent("en-UK");
+  ExpectFluentLanguageListContent({"en"});
+
+  // Language in the list but with different region.
+  // Should not clear fluent for last language.
+  language_prefs_->ClearFluent("en-AU");
+  ExpectFluentLanguageListContent({"en"});
+
+  // Language in the list.
+  language_prefs_->ResetFluentLanguagesToDefaults();
+  language_prefs_->SetFluent("fr");
+  language_prefs_->ClearFluent("en-UK");
+  ExpectFluentLanguageListContent({"fr"});
+
+  // Language in the list but with different region.
+  language_prefs_->ResetFluentLanguagesToDefaults();
+  language_prefs_->SetFluent("fr");
+  language_prefs_->ClearFluent("en-AU");
+  ExpectFluentLanguageListContent({"fr"});
+
+  // Multiple languages.
+  language_prefs_->ResetFluentLanguagesToDefaults();
+  language_prefs_->SetFluent("fr-CA");
+  language_prefs_->SetFluent("fr-FR");
+  language_prefs_->SetFluent("es-AR");
+  language_prefs_->ClearFluent("fr-FR");
+  ExpectFluentLanguageListContent({"en", "es"});
+
+  // Chinese is a special case.
+  language_prefs_->ResetFluentLanguagesToDefaults();
+  language_prefs_->SetFluent("zh-MO");
+  language_prefs_->SetFluent("zh-CN");
+  language_prefs_->ClearFluent("zh-TW");
+  ExpectFluentLanguageListContent({"en", "zh-CN"});
+
+  language_prefs_->ResetFluentLanguagesToDefaults();
+  language_prefs_->SetFluent("zh-MO");
+  language_prefs_->SetFluent("zh-CN");
+  language_prefs_->ClearFluent("zh-CN");
+  ExpectFluentLanguageListContent({"en", "zh-TW"});
+}
+
+TEST_F(LanguagePrefsTest, ResetEmptyFluentLanguagesToDefaultTest) {
+  ExpectFluentLanguageListContent({"en"});
+
+  language_prefs_->ResetEmptyFluentLanguagesToDefault();
+  ExpectFluentLanguageListContent({"en"});
+
+  language_prefs_->SetFluent("fr");
+  language_prefs_->ResetEmptyFluentLanguagesToDefault();
+  ExpectFluentLanguageListContent({"en", "fr"});
+
+  prefs_->Set(language::prefs::kFluentLanguages, base::ListValue());
+  ExpectFluentLanguageListContent({});
+  language_prefs_->ResetEmptyFluentLanguagesToDefault();
+  ExpectFluentLanguageListContent({"en"});
+}
+
+}  // namespace language
diff --git a/components/language/core/browser/pref_names.cc b/components/language/core/browser/pref_names.cc
index f2c821ec..fe340274 100644
--- a/components/language/core/browser/pref_names.cc
+++ b/components/language/core/browser/pref_names.cc
@@ -25,5 +25,8 @@
 // Important: Refer to header file for how to use this.
 const char kApplicationLocale[] = "intl.app_locale";
 
+// Originally translate blocked languages from TranslatePrefs.
+const char kFluentLanguages[] = "translate_blocked_languages";
+
 }  // namespace prefs
 }  // namespace language
diff --git a/components/language/core/browser/pref_names.h b/components/language/core/browser/pref_names.h
index a15a8b9..b878cfee 100644
--- a/components/language/core/browser/pref_names.h
+++ b/components/language/core/browser/pref_names.h
@@ -21,6 +21,8 @@
 // the user selected, if applicable.
 extern const char kApplicationLocale[];
 
+extern const char kFluentLanguages[];
+
 }  // namespace prefs
 }  // namespace language
 
diff --git a/components/translate/core/browser/mock_translate_infobar_delegate.cc b/components/translate/core/browser/mock_translate_infobar_delegate.cc
index 9b67068..16fa1d4 100644
--- a/components/translate/core/browser/mock_translate_infobar_delegate.cc
+++ b/components/translate/core/browser/mock_translate_infobar_delegate.cc
@@ -36,6 +36,7 @@
     const std::string& target_language) {
   pref_service_ =
       std::make_unique<sync_preferences::TestingPrefServiceSyncable>();
+  language::LanguagePrefs::RegisterProfilePrefs(pref_service_->registry());
   translate::TranslatePrefs::RegisterProfilePrefs(pref_service_->registry());
   pref_service_->registry()->RegisterBooleanPref(prefs::kOfferTranslateEnabled,
                                                  true);
diff --git a/components/translate/core/browser/mock_translate_infobar_delegate.h b/components/translate/core/browser/mock_translate_infobar_delegate.h
index 3f736f90..3e8154f 100644
--- a/components/translate/core/browser/mock_translate_infobar_delegate.h
+++ b/components/translate/core/browser/mock_translate_infobar_delegate.h
@@ -10,6 +10,7 @@
 #include <vector>
 
 #include "components/language/core/browser/language_model.h"
+#include "components/language/core/browser/language_prefs.h"
 #include "components/sync_preferences/testing_pref_service_syncable.h"
 #include "components/translate/core/browser/mock_translate_client.h"
 #include "components/translate/core/browser/mock_translate_driver.h"
diff --git a/components/translate/core/browser/translate_manager_unittest.cc b/components/translate/core/browser/translate_manager_unittest.cc
index f24d0171..47d39e5 100644
--- a/components/translate/core/browser/translate_manager_unittest.cc
+++ b/components/translate/core/browser/translate_manager_unittest.cc
@@ -14,6 +14,7 @@
 #include "build/build_config.h"
 #include "components/infobars/core/infobar.h"
 #include "components/language/core/browser/language_model.h"
+#include "components/language/core/browser/language_prefs.h"
 #include "components/language/core/common/language_experiments.h"
 #include "components/pref_registry/pref_registry_syncable.h"
 #include "components/sync_preferences/testing_pref_service_syncable.h"
@@ -114,11 +115,10 @@
 // TranslatePrefs gets created.
 struct ProfilePrefRegistration {
   ProfilePrefRegistration(sync_preferences::TestingPrefServiceSyncable* prefs) {
-    prefs->registry()->RegisterStringPref(accept_languages_prefs,
-                                          std::string());
+    language::LanguagePrefs::RegisterProfilePrefs(prefs->registry());
+    prefs->SetString(accept_languages_prefs, std::string());
 #if defined(OS_CHROMEOS)
-    prefs->registry()->RegisterStringPref(preferred_languages_prefs,
-                                          std::string());
+    prefs->SetString(preferred_languages_prefs, std::string());
 #endif
     TranslatePrefs::RegisterProfilePrefs(prefs->registry());
     // TODO(groby): Figure out RegisterProfilePrefs() should register this.
diff --git a/components/translate/core/browser/translate_prefs.cc b/components/translate/core/browser/translate_prefs.cc
index 6d52f86..8863d28 100644
--- a/components/translate/core/browser/translate_prefs.cc
+++ b/components/translate/core/browser/translate_prefs.cc
@@ -50,8 +50,6 @@
     "translate_ignored_count_for_language";
 const char TranslatePrefs::kPrefTranslateAcceptedCount[] =
     "translate_accepted_count";
-const char TranslatePrefs::kPrefTranslateBlockedLanguages[] =
-    "translate_blocked_languages";
 const char TranslatePrefs::kPrefTranslateLastDeniedTimeForLanguage[] =
     "translate_last_denied_time_for_language";
 const char TranslatePrefs::kPrefTranslateTooOftenDeniedForLanguage[] =
@@ -155,7 +153,9 @@
 TranslatePrefs::TranslatePrefs(PrefService* user_prefs,
                                const char* accept_languages_pref,
                                const char* preferred_languages_pref)
-    : accept_languages_pref_(accept_languages_pref), prefs_(user_prefs) {
+    : accept_languages_pref_(accept_languages_pref),
+      prefs_(user_prefs),
+      language_prefs_(std::make_unique<language::LanguagePrefs>(user_prefs)) {
 #if defined(OS_CHROMEOS)
   preferred_languages_pref_ = preferred_languages_pref;
 #else
@@ -165,6 +165,8 @@
   ResetEmptyBlockedLanguagesToDefaults();
 }
 
+TranslatePrefs::~TranslatePrefs() = default;
+
 bool TranslatePrefs::IsOfferTranslateEnabled() const {
   return prefs_->GetBoolean(prefs::kOfferTranslateEnabled);
 }
@@ -187,7 +189,7 @@
 }
 
 void TranslatePrefs::ResetToDefaults() {
-  ClearBlockedLanguages();
+  ResetBlockedLanguagesToDefault();
   ClearBlacklistedSites();
   ClearWhitelistedLanguagePairs();
   prefs_->ClearPref(kPrefTranslateDeniedCount);
@@ -205,8 +207,8 @@
 }
 
 bool TranslatePrefs::IsBlockedLanguage(
-    const std::string& original_language) const {
-  return IsValueBlacklisted(kPrefTranslateBlockedLanguages, original_language);
+    const std::string& input_language) const {
+  return language_prefs_->IsFluent(input_language);
 }
 
 // Note: the language codes used in the language settings list have the Chrome
@@ -451,22 +453,12 @@
 
 void TranslatePrefs::BlockLanguage(const std::string& input_language) {
   DCHECK(!input_language.empty());
-
-  std::string translate_language = input_language;
-  language::ToTranslateLanguageSynonym(&translate_language);
-
-  BlacklistValue(kPrefTranslateBlockedLanguages, translate_language);
+  language_prefs_->SetFluent(input_language);
 }
 
 void TranslatePrefs::UnblockLanguage(const std::string& input_language) {
   DCHECK(!input_language.empty());
-
-  std::string translate_language = input_language;
-  language::ToTranslateLanguageSynonym(&translate_language);
-  if (GetListSize(kPrefTranslateBlockedLanguages) > 1) {
-    RemoveValueFromBlacklist(kPrefTranslateBlockedLanguages,
-                             translate_language);
-  }
+  language_prefs_->ClearFluent(input_language);
 }
 
 bool TranslatePrefs::IsSiteBlacklisted(const std::string& site) const {
@@ -549,12 +541,8 @@
   dict->Remove(original_language, nullptr);
 }
 
-bool TranslatePrefs::HasBlockedLanguages() const {
-  return GetListSize(kPrefTranslateBlockedLanguages) != 0;
-}
-
-void TranslatePrefs::ClearBlockedLanguages() {
-  prefs_->ClearPref(kPrefTranslateBlockedLanguages);
+void TranslatePrefs::ResetBlockedLanguagesToDefault() {
+  language_prefs_->ResetFluentLanguagesToDefaults();
 }
 
 bool TranslatePrefs::HasBlacklistedSites() const {
@@ -841,9 +829,6 @@
   registry->RegisterDictionaryPref(
       kPrefTranslateAcceptedCount,
       user_prefs::PrefRegistrySyncable::SYNCABLE_PREF);
-  registry->RegisterListPref(kPrefTranslateBlockedLanguages,
-                             GetDefaultBlockedLanguages(),
-                             user_prefs::PrefRegistrySyncable::SYNCABLE_PREF);
   registry->RegisterDictionaryPref(kPrefTranslateLastDeniedTimeForLanguage);
   registry->RegisterDictionaryPref(
       kPrefTranslateTooOftenDeniedForLanguage,
@@ -893,8 +878,7 @@
 }
 
 void TranslatePrefs::ResetEmptyBlockedLanguagesToDefaults() {
-  if (!HasBlockedLanguages())
-    ClearBlockedLanguages();
+  language_prefs_->ResetEmptyFluentLanguagesToDefault();
 }
 
 bool TranslatePrefs::IsValueInList(const base::ListValue* list,
@@ -974,25 +958,4 @@
   }
 }
 
-base::Value TranslatePrefs::GetDefaultBlockedLanguages() {
-#if defined(OS_CHROMEOS)
-  // Preferred languages.
-  std::vector<std::string> languages = {language::kFallbackInputMethodLocale};
-#else
-  // Accept languages.
-  std::vector<std::string> languages =
-      base::SplitString(l10n_util::GetStringUTF8(IDS_ACCEPT_LANGUAGES), ",",
-                        base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL);
-#endif
-  base::ListValue language_values;
-  for (std::string& language : languages) {
-    language::ToTranslateLanguageSynonym(&language);
-    if (std::find(language_values.GetList().begin(),
-                  language_values.GetList().end(),
-                  base::Value(language)) == language_values.GetList().end())
-      language_values.GetList().emplace_back(language);
-  }
-  return std::move(language_values);
-}
-
 }  // namespace translate
diff --git a/components/translate/core/browser/translate_prefs.h b/components/translate/core/browser/translate_prefs.h
index 6051301..c4d3efd3 100644
--- a/components/translate/core/browser/translate_prefs.h
+++ b/components/translate/core/browser/translate_prefs.h
@@ -30,6 +30,10 @@
 class PrefRegistrySyncable;
 }
 
+namespace language {
+class LanguagePrefs;
+}
+
 namespace translate {
 
 // Enables or disables the regional locales as valid selection for the display
@@ -135,7 +139,6 @@
   static const char kPrefTranslateDeniedCount[];
   static const char kPrefTranslateIgnoredCount[];
   static const char kPrefTranslateAcceptedCount[];
-  static const char kPrefTranslateBlockedLanguages[];
   static const char kPrefTranslateLastDeniedTimeForLanguage[];
   static const char kPrefTranslateTooOftenDeniedForLanguage[];
   static const char kPrefTranslateRecentTarget[];
@@ -165,6 +168,8 @@
                  const char* accept_languages_pref,
                  const char* preferred_languages_pref);
 
+  ~TranslatePrefs();
+
   // Checks if the "offer translate" (i.e. automatic translate bubble) feature
   // is enabled.
   bool IsOfferTranslateEnabled() const;
@@ -349,16 +354,7 @@
   // Updates the language list of the language settings.
   void UpdateLanguageList(const std::vector<std::string>& languages);
 
-  // Will return true if at least one language has been blocked.
-  bool HasBlockedLanguages() const;
-
-  // Merges two language sets to migrate to the language setting UI.
-  static void CreateBlockedLanguages(
-      std::vector<std::string>* blocked_languages,
-      const std::vector<std::string>& blacklisted_languages,
-      const std::vector<std::string>& accept_languages);
-
-  void ClearBlockedLanguages();
+  void ResetBlockedLanguagesToDefault();
   void ClearBlacklistedSites();
   void ClearWhitelistedLanguagePairs();
 
@@ -403,6 +399,8 @@
 
   std::string country_;  // The country the app runs in.
 
+  std::unique_ptr<language::LanguagePrefs> language_prefs_;
+
   DISALLOW_COPY_AND_ASSIGN(TranslatePrefs);
 };
 
diff --git a/components/translate/core/browser/translate_prefs_unittest.cc b/components/translate/core/browser/translate_prefs_unittest.cc
index b4b5d80..a65c965f 100644
--- a/components/translate/core/browser/translate_prefs_unittest.cc
+++ b/components/translate/core/browser/translate_prefs_unittest.cc
@@ -61,6 +61,7 @@
  protected:
   TranslatePrefsTest()
       : prefs_(new sync_preferences::TestingPrefServiceSyncable()) {
+    language::LanguagePrefs::RegisterProfilePrefs(prefs_->registry());
     TranslatePrefs::RegisterProfilePrefs(prefs_->registry());
     translate_prefs_.reset(new translate::TranslatePrefs(
         prefs_.get(), kAcceptLanguagesPref, kPreferredLanguagesPref));
@@ -69,10 +70,9 @@
   }
 
   void SetUp() override {
-    prefs_->registry()->RegisterStringPref(kAcceptLanguagesPref, std::string());
+    prefs_->SetString(kAcceptLanguagesPref, std::string());
 #if defined(OS_CHROMEOS)
-    prefs_->registry()->RegisterStringPref(kPreferredLanguagesPref,
-                                           std::string());
+    prefs_->SetString(kPreferredLanguagesPref, std::string());
 #endif
   }
 
@@ -403,24 +403,24 @@
   ExpectBlockedLanguageListContent({"en", "fr", "es", "de"});
 
   // Add a duplicate.
-  translate_prefs_->ClearBlockedLanguages();
+  translate_prefs_->ResetBlockedLanguagesToDefault();
   translate_prefs_->BlockLanguage("es-AR");
   translate_prefs_->BlockLanguage("es-AR");
   ExpectBlockedLanguageListContent({"en", "es"});
 
   // Two languages with the same base.
-  translate_prefs_->ClearBlockedLanguages();
+  translate_prefs_->ResetBlockedLanguagesToDefault();
   translate_prefs_->BlockLanguage("fr-CA");
   translate_prefs_->BlockLanguage("fr-FR");
   ExpectBlockedLanguageListContent({"en", "fr"});
 
   // Chinese is a special case.
-  translate_prefs_->ClearBlockedLanguages();
+  translate_prefs_->ResetBlockedLanguagesToDefault();
   translate_prefs_->BlockLanguage("zh-MO");
   translate_prefs_->BlockLanguage("zh-CN");
   ExpectBlockedLanguageListContent({"en", "zh-TW", "zh-CN"});
 
-  translate_prefs_->ClearBlockedLanguages();
+  translate_prefs_->ResetBlockedLanguagesToDefault();
   translate_prefs_->BlockLanguage("zh-TW");
   translate_prefs_->BlockLanguage("zh-HK");
   ExpectBlockedLanguageListContent({"en", "zh-TW"});
@@ -438,19 +438,19 @@
   ExpectBlockedLanguageListContent({"en"});
 
   // Language in the list.
-  translate_prefs_->ClearBlockedLanguages();
+  translate_prefs_->ResetBlockedLanguagesToDefault();
   translate_prefs_->BlockLanguage("fr");
   translate_prefs_->UnblockLanguage("en-UK");
   ExpectBlockedLanguageListContent({"fr"});
 
   // Language in the list but with different region.
-  translate_prefs_->ClearBlockedLanguages();
+  translate_prefs_->ResetBlockedLanguagesToDefault();
   translate_prefs_->BlockLanguage("fr");
   translate_prefs_->UnblockLanguage("en-AU");
   ExpectBlockedLanguageListContent({"fr"});
 
   // Multiple languages.
-  translate_prefs_->ClearBlockedLanguages();
+  translate_prefs_->ResetBlockedLanguagesToDefault();
   translate_prefs_->BlockLanguage("fr-CA");
   translate_prefs_->BlockLanguage("fr-FR");
   translate_prefs_->BlockLanguage("es-AR");
@@ -458,13 +458,13 @@
   ExpectBlockedLanguageListContent({"en", "es"});
 
   // Chinese is a special case.
-  translate_prefs_->ClearBlockedLanguages();
+  translate_prefs_->ResetBlockedLanguagesToDefault();
   translate_prefs_->BlockLanguage("zh-MO");
   translate_prefs_->BlockLanguage("zh-CN");
   translate_prefs_->UnblockLanguage("zh-TW");
   ExpectBlockedLanguageListContent({"en", "zh-CN"});
 
-  translate_prefs_->ClearBlockedLanguages();
+  translate_prefs_->ResetBlockedLanguagesToDefault();
   translate_prefs_->BlockLanguage("zh-MO");
   translate_prefs_->BlockLanguage("zh-CN");
   translate_prefs_->UnblockLanguage("zh-CN");
@@ -477,7 +477,7 @@
   // Force blocked false, language not already in list.
   languages = {"en"};
   translate_prefs_->UpdateLanguageList(languages);
-  translate_prefs_->ClearBlockedLanguages();
+  translate_prefs_->ResetBlockedLanguagesToDefault();
   translate_prefs_->AddToLanguageList("it-IT", /*force_blocked=*/false);
   ExpectLanguagePrefs("en,it-IT");
   ExpectBlockedLanguageListContent({"en", "it"});
@@ -485,7 +485,7 @@
   // Force blocked false, language from same family already in list.
   languages = {"en", "es-AR"};
   translate_prefs_->UpdateLanguageList(languages);
-  translate_prefs_->ClearBlockedLanguages();
+  translate_prefs_->ResetBlockedLanguagesToDefault();
   translate_prefs_->AddToLanguageList("es-ES", /*force_blocked=*/false);
   ExpectLanguagePrefs("en,es-AR,es-ES");
   ExpectBlockedLanguageListContent({"en"});
@@ -497,7 +497,7 @@
   // Unblock last language of a family.
   languages = {"en-US", "es-AR"};
   translate_prefs_->UpdateLanguageList(languages);
-  translate_prefs_->ClearBlockedLanguages();
+  translate_prefs_->ResetBlockedLanguagesToDefault();
   translate_prefs_->BlockLanguage("en-US");
   translate_prefs_->BlockLanguage("es-AR");
   translate_prefs_->RemoveFromLanguageList("es-AR");
@@ -507,7 +507,7 @@
   // Do not unblock if not the last language of a family.
   languages = {"en-US", "es-AR", "es-ES"};
   translate_prefs_->UpdateLanguageList(languages);
-  translate_prefs_->ClearBlockedLanguages();
+  translate_prefs_->ResetBlockedLanguagesToDefault();
   translate_prefs_->BlockLanguage("en-US");
   translate_prefs_->BlockLanguage("es-AR");
   translate_prefs_->RemoveFromLanguageList("es-AR");
@@ -529,23 +529,6 @@
   ExpectLanguagePrefs("");
 }
 
-TEST_F(TranslatePrefsTest, ResetEmptyBlockedLanguagesToDefaults) {
-  ExpectBlockedLanguageListContent({"en"});
-
-  translate_prefs_->ResetEmptyBlockedLanguagesToDefaults();
-  ExpectBlockedLanguageListContent({"en"});
-
-  translate_prefs_->BlockLanguage("fr");
-  translate_prefs_->ResetEmptyBlockedLanguagesToDefaults();
-  ExpectBlockedLanguageListContent({"en", "fr"});
-
-  prefs_->Set(TranslatePrefs::kPrefTranslateBlockedLanguages,
-              base::ListValue());
-  ExpectBlockedLanguageListContent({});
-  translate_prefs_->ResetEmptyBlockedLanguagesToDefaults();
-  ExpectBlockedLanguageListContent({"en"});
-}
-
 TEST_F(TranslatePrefsTest, RemoveFromLanguageListClearsRecentLanguage) {
   std::vector<std::string> languages;
 
diff --git a/components/translate/core/browser/translate_ui_delegate_unittest.cc b/components/translate/core/browser/translate_ui_delegate_unittest.cc
index 5d2724e..1e48ee8 100644
--- a/components/translate/core/browser/translate_ui_delegate_unittest.cc
+++ b/components/translate/core/browser/translate_ui_delegate_unittest.cc
@@ -12,6 +12,8 @@
 #include "build/build_config.h"
 #include "components/infobars/core/infobar.h"
 #include "components/language/core/browser/language_model.h"
+#include "components/language/core/browser/language_prefs.h"
+#include "components/language/core/browser/pref_names.h"
 #include "components/pref_registry/pref_registry_syncable.h"
 #include "components/sync_preferences/testing_pref_service_syncable.h"
 #include "components/translate/core/browser/mock_translate_client.h"
@@ -20,6 +22,7 @@
 #include "components/translate/core/browser/translate_client.h"
 #include "components/translate/core/browser/translate_infobar_delegate.h"
 #include "components/translate/core/browser/translate_manager.h"
+#include "components/translate/core/browser/translate_pref_names.h"
 #include "components/translate/core/browser/translate_prefs.h"
 #include "components/variations/variations_associated_data.h"
 #include "testing/gmock/include/gmock/gmock.h"
@@ -48,11 +51,16 @@
 
   void SetUp() override {
     pref_service_.reset(new sync_preferences::TestingPrefServiceSyncable());
-    pref_service_->registry()->RegisterStringPref(
-        "settings.language.preferred_languages", std::string());
-    pref_service_->registry()->RegisterStringPref("intl.accept_languages",
-                                                  std::string());
-    pref_service_->registry()->RegisterBooleanPref("translate.enabled", true);
+
+    language::LanguagePrefs::RegisterProfilePrefs(pref_service_->registry());
+    pref_service_->SetString(language::prefs::kAcceptLanguages, std::string());
+#if defined(OS_CHROMEOS)
+    pref_service_->SetString(language::prefs::kPreferredLanguages,
+                             std::string());
+#endif
+
+    pref_service_->registry()->RegisterBooleanPref(
+        prefs::kOfferTranslateEnabled, true);
     TranslatePrefs::RegisterProfilePrefs(pref_service_->registry());
 
     client_.reset(new MockTranslateClient(&driver_, pref_service_.get()));
diff --git a/ios/chrome/browser/prefs/browser_prefs.mm b/ios/chrome/browser/prefs/browser_prefs.mm
index fe7b911..73a6320 100644
--- a/ios/chrome/browser/prefs/browser_prefs.mm
+++ b/ios/chrome/browser/prefs/browser_prefs.mm
@@ -110,7 +110,7 @@
   FirstRun::RegisterProfilePrefs(registry);
   gcm::GCMChannelStatusSyncer::RegisterProfilePrefs(registry);
   HostContentSettingsMap::RegisterProfilePrefs(registry);
-  language::RegisterProfilePrefs(registry);
+  language::LanguagePrefs::RegisterProfilePrefs(registry);
   ntp_snippets::ClickBasedCategoryRanker::RegisterProfilePrefs(registry);
   ntp_snippets::ContentSuggestionsService::RegisterProfilePrefs(registry);
   ntp_snippets::RemoteSuggestionsProviderImpl::RegisterProfilePrefs(registry);
diff --git a/ios/chrome/browser/translate/BUILD.gn b/ios/chrome/browser/translate/BUILD.gn
index 112d99e..82b4c7bf8 100644
--- a/ios/chrome/browser/translate/BUILD.gn
+++ b/ios/chrome/browser/translate/BUILD.gn
@@ -80,6 +80,7 @@
     ":translate",
     "//base",
     "//base/test:test_support",
+    "//components/language/core/browser",
     "//components/translate/core/browser:test_support",
     "//components/translate/ios/browser",
     "//ios/chrome/browser",
diff --git a/ios/chrome/browser/ui/settings/translate_table_view_controller_unittest.mm b/ios/chrome/browser/ui/settings/translate_table_view_controller_unittest.mm
index 1dd6faa..de0270b 100644
--- a/ios/chrome/browser/ui/settings/translate_table_view_controller_unittest.mm
+++ b/ios/chrome/browser/ui/settings/translate_table_view_controller_unittest.mm
@@ -10,7 +10,7 @@
 #include "base/files/file_path.h"
 #include "base/test/scoped_task_environment.h"
 #include "base/threading/thread_task_runner_handle.h"
-#include "components/language/core/browser/pref_names.h"
+#include "components/language/core/browser/language_prefs.h"
 #include "components/pref_registry/pref_registry_syncable.h"
 #include "components/prefs/pref_member.h"
 #include "components/prefs/pref_service.h"
@@ -59,10 +59,8 @@
     scoped_refptr<PrefRegistrySyncable> registry = new PrefRegistrySyncable();
     registry->RegisterBooleanPref(prefs::kOfferTranslateEnabled, false,
                                   PrefRegistrySyncable::SYNCABLE_PREF);
+    language::LanguagePrefs::RegisterProfilePrefs(registry.get());
     translate::TranslatePrefs::RegisterProfilePrefs(registry.get());
-    registry->RegisterStringPref(
-        language::prefs::kAcceptLanguages,
-        l10n_util::GetStringUTF8(IDS_ACCEPT_LANGUAGES));
     base::FilePath path("TranslateTableViewControllerTest.pref");
     sync_preferences::PrefServiceMockFactory factory;
     factory.SetUserPrefsFile(path, base::ThreadTaskRunnerHandle::Get().get());
diff --git a/ios/web_view/internal/web_view_browser_state.mm b/ios/web_view/internal/web_view_browser_state.mm
index 934ddf2..365c8e38 100644
--- a/ios/web_view/internal/web_view_browser_state.mm
+++ b/ios/web_view/internal/web_view_browser_state.mm
@@ -166,10 +166,10 @@
 
 void WebViewBrowserState::RegisterPrefs(
     user_prefs::PrefRegistrySyncable* pref_registry) {
-  language::RegisterProfilePrefs(pref_registry);
   pref_registry->RegisterBooleanPref(prefs::kOfferTranslateEnabled, true);
   pref_registry->RegisterBooleanPref(prefs::kSavingBrowserHistoryDisabled,
                                      true);
+  language::LanguagePrefs::RegisterProfilePrefs(pref_registry);
   translate::TranslatePrefs::RegisterProfilePrefs(pref_registry);
 
 #if BUILDFLAG(IOS_WEB_VIEW_ENABLE_AUTOFILL)