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