#include "chrome/browser/extensions/api/language_settings_private/language_settings_private_api.h"
#include <map>
#include <memory>
#include <set>
#include <string>
#include <string_view>
#include <utility>
#include <vector>
#include "base/containers/contains.h"
#include "base/containers/flat_set.h"
#include "base/feature_list.h"
#include "base/ranges/algorithm.h"
#include "base/strings/string_split.h"
#include "base/strings/string_util.h"
#include "base/strings/utf_string_conversions.h"
#include "base/values.h"
#include "build/build_config.h"
#include "build/chromeos_buildflags.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/extensions/api/language_settings_private/language_settings_private_delegate.h"
#include "chrome/browser/extensions/api/language_settings_private/language_settings_private_delegate_factory.h"
#include "chrome/browser/language/language_model_manager_factory.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/spellchecker/spellcheck_factory.h"
#include "chrome/browser/spellchecker/spellcheck_service.h"
#include "chrome/browser/translate/chrome_translate_client.h"
#include "chrome/browser/translate/translate_service.h"
#include "chrome/common/extensions/api/language_settings_private.h"
#include "chrome/common/pref_names.h"
#include "components/language/core/browser/language_model_manager.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/spellcheck/browser/spellcheck_platform.h"
#include "components/spellcheck/common/spellcheck_common.h"
#include "components/spellcheck/common/spellcheck_features.h"
#include "components/spellcheck/spellcheck_buildflags.h"
#include "components/translate/core/browser/translate_download_manager.h"
#include "components/translate/core/browser/translate_prefs.h"
#include "third_party/icu/source/i18n/unicode/coll.h"
#include "ui/base/l10n/l10n_util.h"
#include "ui/base/l10n/l10n_util_collator.h"
#if BUILDFLAG(IS_CHROMEOS_ASH)
#include "ash/constants/ash_features.h"
#include "chrome/grit/generated_resources.h"
#include "ui/base/ime/ash/component_extension_ime_manager.h"
#include "ui/base/ime/ash/extension_ime_util.h"
#include "ui/base/ime/ash/input_method_descriptor.h"
#include "ui/base/ime/ash/input_method_manager.h"
#include "ui/base/ime/ash/input_method_util.h"
#endif
namespace extensions {
language_settings_private;
namespace {
#if BUILDFLAG(IS_CHROMEOS_ASH)
using ::ash::input_method::InputMethodDescriptor;
using ::ash::input_method::InputMethodDescriptors;
using ::ash::input_method::InputMethodManager;
using ::ash::input_method::InputMethodUtil;
const size_t kNumImesToAutoEnableImeMenu = 2;
base::flat_set<std::string> GetIMEsFromPref(PrefService* prefs,
const char* pref_name) {
return base::SplitString(prefs->GetString(pref_name), ",",
base::TRIM_WHITESPACE, base::SPLIT_WANT_NONEMPTY);
}
base::flat_set<std::string> GetAllowedLanguages(PrefService* prefs) {
const auto& allowed_languages_values =
prefs->GetList(prefs::kAllowedLanguages);
return base::MakeFlatSet<std::string>(
allowed_languages_values, {},
[](const auto& locale_value) { return locale_value.GetString(); });
}
std::vector<std::string> GetSortedComponentIMEs(
InputMethodManager* manager,
scoped_refptr<InputMethodManager::State> ime_state,
const base::flat_set<std::string>& component_ime_set,
PrefService* prefs) {
std::vector<std::string> enabled_languages =
base::SplitString(prefs->GetString(language::prefs::kPreferredLanguages),
",", base::TRIM_WHITESPACE, base::SPLIT_WANT_NONEMPTY);
std::set<std::string> available_component_imes(component_ime_set.begin(),
component_ime_set.end());
std::vector<std::string> component_ime_list;
for (const auto& language_code : enabled_languages) {
std::vector<std::string> input_method_ids;
manager->GetInputMethodUtil()->GetInputMethodIdsFromLanguageCode(
language_code, ash::input_method::kAllInputMethods, &input_method_ids);
for (const auto& input_method_id : input_method_ids) {
if (base::Contains(available_component_imes, input_method_id)) {
component_ime_list.push_back(input_method_id);
available_component_imes.erase(input_method_id);
}
}
}
for (const auto& input_method_id : available_component_imes) {
component_ime_list.push_back(input_method_id);
}
return component_ime_list;
}
std::vector<std::string> GetSortedThirdPartyIMEs(
scoped_refptr<InputMethodManager::State> ime_state,
const base::flat_set<std::string>& third_party_ime_set,
PrefService* prefs) {
std::vector<std::string> ime_list;
std::string preferred_languages =
prefs->GetString(language::prefs::kPreferredLanguages);
std::vector<std::string_view> enabled_languages =
base::SplitStringPiece(preferred_languages, ",", base::TRIM_WHITESPACE,
base::SPLIT_WANT_NONEMPTY);
enabled_languages.push_back(ash::extension_ime_util::kArcImeLanguage);
InputMethodDescriptors descriptors;
ime_state->GetInputMethodExtensions(&descriptors);
std::erase_if(descriptors, [&third_party_ime_set](
const InputMethodDescriptor& descriptor) {
return !third_party_ime_set.contains(descriptor.id());
});
std::set<std::string> ime_set;
for (const auto& language : enabled_languages) {
for (const InputMethodDescriptor& descriptor : descriptors) {
const std::string& id = descriptor.id();
if (!base::Contains(ime_set, id) &&
base::Contains(descriptor.language_codes(), language)) {
ime_list.push_back(id);
ime_set.insert(id);
}
}
}
for (const InputMethodDescriptor& descriptor : descriptors) {
const std::string& id = descriptor.id();
if (!base::Contains(ime_set, id)) {
ime_list.push_back(id);
}
}
return ime_list;
}
std::vector<std::string> GetInputMethodTags(
language_settings_private::InputMethod* input_method) {
std::vector<std::string> tags = {input_method->display_name};
const std::string app_locale = g_browser_process->GetApplicationLocale();
for (const auto& language_code : input_method->language_codes) {
tags.push_back(base::UTF16ToUTF8(l10n_util::GetDisplayNameForLocale(
language_code, app_locale, true)));
}
return tags;
}
#endif
std::unique_ptr<translate::TranslatePrefs>
CreateTranslatePrefsForBrowserContext(
content::BrowserContext* browser_context) { … }
}
LanguageSettingsPrivateGetLanguageListFunction::
LanguageSettingsPrivateGetLanguageListFunction() = default;
LanguageSettingsPrivateGetLanguageListFunction::
~LanguageSettingsPrivateGetLanguageListFunction() = default;
ExtensionFunction::ResponseAction
LanguageSettingsPrivateGetLanguageListFunction::Run() { … }
#if BUILDFLAG(IS_WIN)
void LanguageSettingsPrivateGetLanguageListFunction::
OnDictionariesInitialized() {
UpdateSupportedPlatformDictionaries();
Respond(WithArguments(std::move(language_list_)));
Release();
}
void LanguageSettingsPrivateGetLanguageListFunction::
UpdateSupportedPlatformDictionaries() {
SpellcheckService* service =
SpellcheckServiceFactory::GetForContext(browser_context());
for (auto& language_val : language_list_) {
base::Value::Dict& language_val_dict = language_val.GetDict();
const std::string* str = language_val_dict.FindString("code");
if (str && service->UsesWindowsDictionary(*str)) {
language_val_dict.Set("supportsSpellcheck", true);
}
}
}
#endif
LanguageSettingsPrivateEnableLanguageFunction::
LanguageSettingsPrivateEnableLanguageFunction() = default;
LanguageSettingsPrivateEnableLanguageFunction::
~LanguageSettingsPrivateEnableLanguageFunction() = default;
ExtensionFunction::ResponseAction
LanguageSettingsPrivateEnableLanguageFunction::Run() { … }
LanguageSettingsPrivateDisableLanguageFunction::
LanguageSettingsPrivateDisableLanguageFunction() = default;
LanguageSettingsPrivateDisableLanguageFunction::
~LanguageSettingsPrivateDisableLanguageFunction() = default;
ExtensionFunction::ResponseAction
LanguageSettingsPrivateDisableLanguageFunction::Run() { … }
LanguageSettingsPrivateSetEnableTranslationForLanguageFunction::
LanguageSettingsPrivateSetEnableTranslationForLanguageFunction() = default;
LanguageSettingsPrivateSetEnableTranslationForLanguageFunction::
~LanguageSettingsPrivateSetEnableTranslationForLanguageFunction() = default;
ExtensionFunction::ResponseAction
LanguageSettingsPrivateSetEnableTranslationForLanguageFunction::Run() { … }
LanguageSettingsPrivateGetAlwaysTranslateLanguagesFunction::
LanguageSettingsPrivateGetAlwaysTranslateLanguagesFunction() = default;
LanguageSettingsPrivateGetAlwaysTranslateLanguagesFunction::
~LanguageSettingsPrivateGetAlwaysTranslateLanguagesFunction() = default;
ExtensionFunction::ResponseAction
LanguageSettingsPrivateGetAlwaysTranslateLanguagesFunction::Run() { … }
LanguageSettingsPrivateSetLanguageAlwaysTranslateStateFunction::
LanguageSettingsPrivateSetLanguageAlwaysTranslateStateFunction() = default;
LanguageSettingsPrivateSetLanguageAlwaysTranslateStateFunction::
~LanguageSettingsPrivateSetLanguageAlwaysTranslateStateFunction() = default;
ExtensionFunction::ResponseAction
LanguageSettingsPrivateSetLanguageAlwaysTranslateStateFunction::Run() { … }
LanguageSettingsPrivateGetNeverTranslateLanguagesFunction::
LanguageSettingsPrivateGetNeverTranslateLanguagesFunction() = default;
LanguageSettingsPrivateGetNeverTranslateLanguagesFunction::
~LanguageSettingsPrivateGetNeverTranslateLanguagesFunction() = default;
ExtensionFunction::ResponseAction
LanguageSettingsPrivateGetNeverTranslateLanguagesFunction::Run() { … }
LanguageSettingsPrivateMoveLanguageFunction::
LanguageSettingsPrivateMoveLanguageFunction() = default;
LanguageSettingsPrivateMoveLanguageFunction::
~LanguageSettingsPrivateMoveLanguageFunction() = default;
ExtensionFunction::ResponseAction
LanguageSettingsPrivateMoveLanguageFunction::Run() { … }
LanguageSettingsPrivateGetSpellcheckDictionaryStatusesFunction::
LanguageSettingsPrivateGetSpellcheckDictionaryStatusesFunction() = default;
LanguageSettingsPrivateGetSpellcheckDictionaryStatusesFunction::
~LanguageSettingsPrivateGetSpellcheckDictionaryStatusesFunction() = default;
ExtensionFunction::ResponseAction
LanguageSettingsPrivateGetSpellcheckDictionaryStatusesFunction::Run() { … }
LanguageSettingsPrivateGetSpellcheckWordsFunction::
LanguageSettingsPrivateGetSpellcheckWordsFunction() = default;
LanguageSettingsPrivateGetSpellcheckWordsFunction::
~LanguageSettingsPrivateGetSpellcheckWordsFunction() = default;
ExtensionFunction::ResponseAction
LanguageSettingsPrivateGetSpellcheckWordsFunction::Run() { … }
void LanguageSettingsPrivateGetSpellcheckWordsFunction::
OnCustomDictionaryLoaded() { … }
void LanguageSettingsPrivateGetSpellcheckWordsFunction::
OnCustomDictionaryChanged(
const SpellcheckCustomDictionary::Change& dictionary_change) { … }
base::Value::List
LanguageSettingsPrivateGetSpellcheckWordsFunction::GetSpellcheckWords() const { … }
LanguageSettingsPrivateAddSpellcheckWordFunction::
LanguageSettingsPrivateAddSpellcheckWordFunction() = default;
LanguageSettingsPrivateAddSpellcheckWordFunction::
~LanguageSettingsPrivateAddSpellcheckWordFunction() = default;
ExtensionFunction::ResponseAction
LanguageSettingsPrivateAddSpellcheckWordFunction::Run() { … }
LanguageSettingsPrivateRemoveSpellcheckWordFunction::
LanguageSettingsPrivateRemoveSpellcheckWordFunction() = default;
LanguageSettingsPrivateRemoveSpellcheckWordFunction::
~LanguageSettingsPrivateRemoveSpellcheckWordFunction() = default;
ExtensionFunction::ResponseAction
LanguageSettingsPrivateRemoveSpellcheckWordFunction::Run() { … }
LanguageSettingsPrivateGetTranslateTargetLanguageFunction::
LanguageSettingsPrivateGetTranslateTargetLanguageFunction() = default;
LanguageSettingsPrivateGetTranslateTargetLanguageFunction::
~LanguageSettingsPrivateGetTranslateTargetLanguageFunction() = default;
ExtensionFunction::ResponseAction
LanguageSettingsPrivateGetTranslateTargetLanguageFunction::Run() { … }
LanguageSettingsPrivateSetTranslateTargetLanguageFunction::
LanguageSettingsPrivateSetTranslateTargetLanguageFunction() = default;
LanguageSettingsPrivateSetTranslateTargetLanguageFunction::
~LanguageSettingsPrivateSetTranslateTargetLanguageFunction() = default;
ExtensionFunction::ResponseAction
LanguageSettingsPrivateSetTranslateTargetLanguageFunction::Run() { … }
#if BUILDFLAG(IS_CHROMEOS_ASH)
void PopulateInputMethodListFromDescriptors(
const InputMethodDescriptors& descriptors,
std::vector<language_settings_private::InputMethod>* input_methods) {
InputMethodManager* manager = InputMethodManager::Get();
InputMethodUtil* util = manager->GetInputMethodUtil();
scoped_refptr<InputMethodManager::State> ime_state =
manager->GetActiveIMEState();
if (!ime_state.get())
return;
const base::flat_set<std::string> enabled_ids(
ime_state->GetEnabledInputMethodIds());
const base::flat_set<std::string> allowed_ids(
ime_state->GetAllowedInputMethodIds());
UErrorCode error = U_ZERO_ERROR;
std::unique_ptr<icu::Collator> collator(
icu::Collator::createInstance(error));
DCHECK(U_SUCCESS(error));
std::map<std::u16string, language_settings_private::InputMethod,
l10n_util::StringComparator<std::u16string>>
input_map(l10n_util::StringComparator<std::u16string>(collator.get()));
for (const auto& descriptor : descriptors) {
language_settings_private::InputMethod input_method;
input_method.id = descriptor.id();
input_method.display_name = util->GetLocalizedDisplayName(descriptor);
input_method.language_codes = descriptor.language_codes();
input_method.tags = GetInputMethodTags(&input_method);
if (base::Contains(enabled_ids, input_method.id))
input_method.enabled = true;
if (descriptor.options_page_url().is_valid())
input_method.has_options_page = true;
if (!allowed_ids.empty() && !base::Contains(allowed_ids, input_method.id)) {
input_method.is_prohibited_by_policy = true;
}
input_map[base::UTF8ToUTF16(util->GetLocalizedDisplayName(descriptor))] =
std::move(input_method);
}
for (auto& entry : input_map) {
input_methods->push_back(std::move(entry.second));
}
}
#endif
LanguageSettingsPrivateGetInputMethodListsFunction::
LanguageSettingsPrivateGetInputMethodListsFunction() = default;
LanguageSettingsPrivateGetInputMethodListsFunction::
~LanguageSettingsPrivateGetInputMethodListsFunction() = default;
ExtensionFunction::ResponseAction
LanguageSettingsPrivateGetInputMethodListsFunction::Run() { … }
LanguageSettingsPrivateAddInputMethodFunction::
LanguageSettingsPrivateAddInputMethodFunction() = default;
LanguageSettingsPrivateAddInputMethodFunction::
~LanguageSettingsPrivateAddInputMethodFunction() = default;
ExtensionFunction::ResponseAction
LanguageSettingsPrivateAddInputMethodFunction::Run() { … }
LanguageSettingsPrivateRemoveInputMethodFunction::
LanguageSettingsPrivateRemoveInputMethodFunction() = default;
LanguageSettingsPrivateRemoveInputMethodFunction::
~LanguageSettingsPrivateRemoveInputMethodFunction() = default;
ExtensionFunction::ResponseAction
LanguageSettingsPrivateRemoveInputMethodFunction::Run() { … }
LanguageSettingsPrivateRetryDownloadDictionaryFunction::
LanguageSettingsPrivateRetryDownloadDictionaryFunction() = default;
LanguageSettingsPrivateRetryDownloadDictionaryFunction::
~LanguageSettingsPrivateRetryDownloadDictionaryFunction() = default;
ExtensionFunction::ResponseAction
LanguageSettingsPrivateRetryDownloadDictionaryFunction::Run() { … }
}