1 // Copyright 2019 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "components/language/core/browser/language_prefs.h"
6 
7 #include <algorithm>
8 #include <set>
9 #include <string>
10 #include <utility>
11 #include <vector>
12 
13 #include "base/stl_util.h"
14 #include "base/strings/string_piece.h"
15 #include "base/strings/string_split.h"
16 #include "base/strings/string_util.h"
17 #include "base/values.h"
18 #include "components/language/core/browser/pref_names.h"
19 #include "components/language/core/common/language_util.h"
20 #include "components/language/core/common/locale_util.h"
21 #include "components/pref_registry/pref_registry_syncable.h"
22 #include "components/prefs/pref_service.h"
23 #include "components/prefs/scoped_user_pref_update.h"
24 #include "components/strings/grit/components_locale_settings.h"
25 #include "ui/base/l10n/l10n_util.h"
26 
27 namespace language {
28 
29 const char kFallbackInputMethodLocale[] = "en-US";
30 
RegisterProfilePrefs(user_prefs::PrefRegistrySyncable * registry)31 void LanguagePrefs::RegisterProfilePrefs(
32     user_prefs::PrefRegistrySyncable* registry) {
33   registry->RegisterStringPref(language::prefs::kAcceptLanguages,
34                                l10n_util::GetStringUTF8(IDS_ACCEPT_LANGUAGES),
35                                user_prefs::PrefRegistrySyncable::SYNCABLE_PREF);
36 #if defined(OS_CHROMEOS)
37   registry->RegisterStringPref(language::prefs::kPreferredLanguages,
38                                kFallbackInputMethodLocale);
39 
40   registry->RegisterStringPref(
41       language::prefs::kPreferredLanguagesSyncable, "",
42       user_prefs::PrefRegistrySyncable::SYNCABLE_OS_PREF);
43 #endif
44   registry->RegisterListPref(language::prefs::kFluentLanguages,
45                              LanguagePrefs::GetDefaultFluentLanguages(),
46                              user_prefs::PrefRegistrySyncable::SYNCABLE_PREF);
47 }
48 
LanguagePrefs(PrefService * user_prefs)49 LanguagePrefs::LanguagePrefs(PrefService* user_prefs) : prefs_(user_prefs) {
50   ResetEmptyFluentLanguagesToDefault();
51 }
52 
IsFluent(const std::string & language) const53 bool LanguagePrefs::IsFluent(const std::string& language) const {
54   std::string canonical_lang = language;
55   language::ToTranslateLanguageSynonym(&canonical_lang);
56   const base::Value* fluents =
57       prefs_->GetList(language::prefs::kFluentLanguages);
58   return base::Contains(fluents->GetList(), base::Value(canonical_lang));
59 }
60 
SetFluent(const std::string & language)61 void LanguagePrefs::SetFluent(const std::string& language) {
62   if (IsFluent(language))
63     return;
64   std::string canonical_lang = language;
65   language::ToTranslateLanguageSynonym(&canonical_lang);
66   ListPrefUpdate update(prefs_, language::prefs::kFluentLanguages);
67   update->Append(std::move(canonical_lang));
68 }
69 
ClearFluent(const std::string & language)70 void LanguagePrefs::ClearFluent(const std::string& language) {
71   if (NumFluentLanguages() <= 1)  // Never remove last fluent language.
72     return;
73   std::string canonical_lang = language;
74   language::ToTranslateLanguageSynonym(&canonical_lang);
75   ListPrefUpdate update(prefs_, language::prefs::kFluentLanguages);
76   update->EraseListValue(base::Value(canonical_lang));
77 }
78 
ResetFluentLanguagesToDefaults()79 void LanguagePrefs::ResetFluentLanguagesToDefaults() {
80   // Reset pref to defaults.
81   prefs_->ClearPref(language::prefs::kFluentLanguages);
82 }
83 
ResetEmptyFluentLanguagesToDefault()84 void LanguagePrefs::ResetEmptyFluentLanguagesToDefault() {
85   if (NumFluentLanguages() == 0)
86     ResetFluentLanguagesToDefaults();
87 }
88 
GetDefaultFluentLanguages()89 base::Value LanguagePrefs::GetDefaultFluentLanguages() {
90   std::set<std::string> languages;
91 #if defined(OS_CHROMEOS)
92   // Preferred languages.
93   std::string language = language::kFallbackInputMethodLocale;
94   language::ToTranslateLanguageSynonym(&language);
95   languages.insert(std::move(language));
96 #else
97   // Accept languages.
98 #pragma GCC diagnostic push
99 // See comment above the |break;| in the loop just below for why.
100 #pragma GCC diagnostic ignored "-Wunreachable-code"
101   for (std::string language :
102        base::SplitString(l10n_util::GetStringUTF8(IDS_ACCEPT_LANGUAGES), ",",
103                          base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL)) {
104     language::ToTranslateLanguageSynonym(&language);
105     languages.insert(std::move(language));
106 
107     // crbug.com/958348: The default value for Accept-Language *should* be the
108     // same as the one for Fluent Languages. However, Accept-Language contains
109     // English (and more) in addition to the local language in most locales due
110     // to historical reasons. Exiting early from this loop is a temporary fix
111     // that allows Fluent Languages to be at least populated with the UI
112     // language while still allowing Translate to trigger on other languages,
113     // most importantly English.
114     // Once the change to remove English from Accept-Language defaults lands,
115     // this break should be removed to enable the Fluent Language List and the
116     // Accept-Language list to be initialized to the same values.
117     break;
118 #pragma GCC diagnostic pop
119   }
120 #endif
121   base::Value language_values(base::Value::Type::LIST);
122   for (const std::string& language : languages)
123     language_values.Append(language);
124 
125   return language_values;
126 }
127 
NumFluentLanguages() const128 size_t LanguagePrefs::NumFluentLanguages() const {
129   const base::Value* fluents =
130       prefs_->GetList(language::prefs::kFluentLanguages);
131   return fluents->GetList().size();
132 }
133 
ResetLanguagePrefs(PrefService * prefs)134 void ResetLanguagePrefs(PrefService* prefs) {
135   prefs->ClearPref(language::prefs::kAcceptLanguages);
136   prefs->ClearPref(language::prefs::kFluentLanguages);
137 #if defined(OS_CHROMEOS)
138   prefs->ClearPref(language::prefs::kPreferredLanguages);
139   prefs->ClearPref(language::prefs::kPreferredLanguagesSyncable);
140 #endif
141 }
142 
143 }  // namespace language
144