chromium/chrome/browser/ui/webui/ash/settings/pages/languages/languages_section.cc

// Copyright 2020 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chrome/browser/ui/webui/ash/settings/pages/languages/languages_section.h"

#include "ash/constants/ash_features.h"
#include "ash/webui/settings/public/constants/routes.mojom-forward.h"
#include "base/no_destructor.h"
#include "base/strings/utf_string_conversions.h"
#include "chrome/browser/ash/input_method/editor_mediator_factory.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/ui/ash/keyboard/chrome_keyboard_controller_client.h"
#include "chrome/browser/ui/webui/ash/settings/os_settings_features_util.h"
#include "chrome/browser/ui/webui/ash/settings/pages/device/inputs_section.h"
#include "chrome/browser/ui/webui/ash/settings/search/search_tag_registry.h"
#include "chrome/browser/ui/webui/settings/languages_handler.h"
#include "chrome/browser/ui/webui/webui_util.h"
#include "chrome/common/url_constants.h"
#include "chrome/grit/generated_resources.h"
#include "chromeos/components/quick_answers/public/cpp/quick_answers_state.h"
#include "chromeos/constants/chromeos_features.h"
#include "components/prefs/pref_service.h"
#include "content/public/browser/web_ui_data_source.h"
#include "net/base/url_util.h"
#include "ui/base/l10n/l10n_util.h"
#include "ui/base/webui/web_ui_util.h"
#include "url/gurl.h"

namespace ash::settings {

namespace mojom {
using ::chromeos::settings::mojom::kAppLanguagesSubpagePath;
using ::chromeos::settings::mojom::kLanguagesAndInputSectionPath;
using ::chromeos::settings::mojom::kLanguagesSubpagePath;
using ::chromeos::settings::mojom::kSystemPreferencesSectionPath;
using ::chromeos::settings::mojom::Section;
using ::chromeos::settings::mojom::Setting;
using ::chromeos::settings::mojom::Subpage;
}  // namespace mojom

namespace {

const std::vector<SearchConcept>& GetLanguagesPageSearchConceptsV2() {
  static const base::NoDestructor<std::vector<SearchConcept>> tags({
      {IDS_OS_SETTINGS_TAG_LANGUAGES,
       mojom::kLanguagesSubpagePath,
       mojom::SearchResultIcon::kLanguage,
       mojom::SearchResultDefaultRank::kMedium,
       mojom::SearchResultType::kSubpage,
       {.subpage = mojom::Subpage::kLanguages}},
      {IDS_OS_SETTINGS_TAG_LANGUAGES_CHANGE_DEVICE_LANGUAGE,
       mojom::kLanguagesSubpagePath,
       mojom::SearchResultIcon::kLanguage,
       mojom::SearchResultDefaultRank::kMedium,
       mojom::SearchResultType::kSetting,
       {.setting = mojom::Setting::kChangeDeviceLanguage}},
      {IDS_OS_SETTINGS_TAG_LANGUAGES_INPUT_ADD_LANGUAGE,
       mojom::kLanguagesSubpagePath,
       mojom::SearchResultIcon::kLanguage,
       mojom::SearchResultDefaultRank::kMedium,
       mojom::SearchResultType::kSetting,
       {.setting = mojom::Setting::kAddLanguage}},
      {IDS_OS_SETTINGS_TAG_LANGUAGES_OFFER_TRANSLATION,
       mojom::kLanguagesSubpagePath,
       mojom::SearchResultIcon::kLanguage,
       mojom::SearchResultDefaultRank::kMedium,
       mojom::SearchResultType::kSetting,
       {.setting = mojom::Setting::kOfferTranslation}},
  });
  return *tags;
}

const std::vector<SearchConcept>& GetAppLanguagesPageSearchConcepts() {
  static const base::NoDestructor<std::vector<SearchConcept>> tags({
      {IDS_OS_SETTINGS_TAG_LANGUAGES_APP_LANGUAGES,
       mojom::kAppLanguagesSubpagePath,
       mojom::SearchResultIcon::kLanguage,
       mojom::SearchResultDefaultRank::kMedium,
       mojom::SearchResultType::kSubpage,
       {.subpage = mojom::Subpage::kAppLanguages}},
  });
  return *tags;
}

void AddLanguagesPageStringsV2(content::WebUIDataSource* html_source) {
  static constexpr webui::LocalizedString kLocalizedStrings[] = {
      {"deviceLanguageTitle", IDS_OS_SETTINGS_LANGUAGES_DEVICE_LANGUAGE_TITLE},
      {"changeDeviceLanguageLabel",
       IDS_OS_SETTINGS_LANGUAGES_CHANGE_DEVICE_LANGUAGE_BUTTON_LABEL},
      {"changeDeviceLanguageButtonDescription",
       IDS_OS_SETTINGS_LANGUAGES_CHANGE_DEVICE_LANGUAGE_BUTTON_DESCRIPTION},
      {"languagesPreferenceTitle",
       IDS_OS_SETTINGS_LANGUAGES_LANGUAGES_PREFERENCE_TITLE},
      {"websiteLanguagesTitle",
       IDS_OS_SETTINGS_LANGUAGES_WEBSITE_LANGUAGES_TITLE},
      {"offerToTranslateThisLanguage",
       IDS_OS_SETTINGS_LANGUAGES_OFFER_TO_TRANSLATE_THIS_LANGUAGE},
      {"offerTranslationLabel",
       IDS_OS_SETTINGS_LANGUAGES_OFFER_TRANSLATION_LABEL},
      {"offerTranslationSublabel",
       IDS_OS_SETTINGS_LANGUAGES_OFFER_TRANSLATION_SUBLABEL},
      {"offerGoogleTranslateLabel",
       IDS_OS_SETTINGS_LANGUAGES_OFFER_GOOGLE_TRANSLATE_LABEL},
      {"changeDeviceLanguageDialogTitle",
       IDS_OS_SETTINGS_LANGUAGES_CHANGE_DEVICE_LANGUAGE_DIALOG_TITLE},
      {"selectedDeviceLanguageInstruction",
       IDS_OS_SETTINGS_LANGUAGES_SELECTED_DEVICE_LANGUAGE_INSTRUCTION},
      {"notSelectedDeviceLanguageInstruction",
       IDS_OS_SETTINGS_LANGUAGES_NOT_SELECTED_DEVICE_LANGUAGE_INSTRUCTION},
      {"changeDeviceLanguageConfirmButtonLabel",
       IDS_OS_SETTINGS_LANGUAGES_CHANGE_DEVICE_LANGUAGE_CONFIRM_BUTTON_LABEL},
      {"googleAccountLanguageTitle",
       IDS_OS_SETTINGS_LANGUAGES_GOOGLE_ACCOUNT_LANGUAGE_TITLE},
      {"googleAccountLanguageDescription",
       IDS_OS_SETTINGS_LANGUAGES_GOOGLE_ACCOUNT_LANGUAGE_DESCRIPTION},
      {"manageGoogleAccountLanguageLabel",
       IDS_OS_SETTINGS_LANGUAGES_MANAGE_GOOGLE_ACCOUNT_LANGUAGE_LABEL},
      {"appLanguagesTitle", IDS_OS_SETTINGS_LANGUAGES_APP_LANGUAGES_TITLE},
      {"appLanguagesDescription",
       IDS_OS_SETTINGS_LANGUAGES_APP_LANGUAGES_DESCRIPTION},
      {"appLanguagesSupportedAppsDescription",
       IDS_OS_SETTINGS_LANGUAGES_APP_LANGUAGES_SUPPORTED_APPS_DESCRIPTION},
      {"appLanguagesNoAppsSupportedDescription",
       IDS_OS_SETTINGS_LANGUAGES_APP_LANGUAGES_NO_APPS_SUPPORTED_DESCRIPTION},
      {"appLanguagesEditSelectionLabel",
       IDS_OS_SETTINGS_LANGUAGES_APP_LANGUAGES_EDIT_SELECTION_LABEL},
      {"appLanguagesResetSelectionLabel",
       IDS_OS_SETTINGS_LANGUAGES_APP_LANGUAGES_RESET_SELECTION_LABEL},
      {"appLanguagesChangeLanguageButtonDescription",
       IDS_OS_SETTINGS_LANGUAGES_APP_LANGUAGES_CHANGE_LANGUAGE_BUTTON_DESCRIPTION},
  };
  html_source->AddLocalizedStrings(kLocalizedStrings);

  html_source->AddString(
      "languagesPreferenceDescription",
      l10n_util::GetStringFUTF16(
          IDS_OS_SETTINGS_LANGUAGES_LANGUAGES_PREFERENCE_DESCRIPTION,
          chrome::kLanguageSettingsLearnMoreUrl));
  html_source->AddString(
      "websiteLanguagesDescription",
      l10n_util::GetStringFUTF16(
          IDS_OS_SETTINGS_LANGUAGES_WEBSITE_LANGUAGES_DESCRIPTION,
          chrome::kLanguageSettingsLearnMoreUrl));
  html_source->AddString(
      "translateTargetLabel",
      l10n_util::GetStringUTF16(
          QuickAnswersState::IsEligibleAs(
              QuickAnswersState::FeatureType::kQuickAnswers)
              ? IDS_OS_SETTINGS_LANGUAGES_TRANSLATE_TARGET_LABEL_WITH_QUICK_ANSWERS
              : IDS_OS_SETTINGS_LANGUAGES_TRANSLATE_TARGET_LABEL));
  html_source->AddString(
      "changeDeviceLanguageDialogDescription",
      l10n_util::GetStringFUTF16(
          IDS_OS_SETTINGS_LANGUAGES_CHANGE_DEVICE_LANGUAGE_DIALOG_DESCRIPTION,
          chrome::kLanguageSettingsLearnMoreUrl));

  html_source->AddString(
      "googleAccountLanguagesURL",
      net::AppendQueryParameter(GURL(chrome::kGoogleAccountLanguagesURL),
                                "utm_source", "chrome-settings")
          .spec());
}

}  // namespace

LanguagesSection::LanguagesSection(Profile* profile,
                                   SearchTagRegistry* search_tag_registry,
                                   PrefService* pref_service)
    : OsSettingsSection(profile, search_tag_registry),
      inputs_subsection_(
          !ash::features::IsOsSettingsRevampWayfindingEnabled()
              ? std::make_optional<InputsSection>(
                    profile,
                    search_tag_registry,
                    pref_service,
                    chromeos::features::IsOrcaEnabled()
                        ? input_method::EditorMediatorFactory::GetInstance()
                              ->GetForProfile(profile)
                        : nullptr)
              : std::nullopt) {
  SearchTagRegistry::ScopedTagUpdater updater = registry()->StartUpdate();
  updater.AddSearchTags(GetLanguagesPageSearchConceptsV2());
  if (IsPerAppLanguageEnabled(profile)) {
    updater.AddSearchTags(GetAppLanguagesPageSearchConcepts());
  }
}

LanguagesSection::~LanguagesSection() = default;

void LanguagesSection::AddLoadTimeData(content::WebUIDataSource* html_source) {
  webui::LocalizedString kLocalizedStrings[] = {
      {"osLanguagesPageTitle", IDS_OS_SETTINGS_LANGUAGES_AND_INPUT_PAGE_TITLE},
      {"languagesPageTitle", IDS_OS_SETTINGS_LANGUAGES_LANGUAGES_PAGE_TITLE},
      {"moveDown", IDS_SETTINGS_LANGUAGES_LANGUAGES_LIST_MOVE_DOWN},
      {"searchLanguages", IDS_SETTINGS_LANGUAGE_SEARCH},
      {"addLanguagesDialogTitle",
       IDS_SETTINGS_LANGUAGES_MANAGE_LANGUAGES_TITLE},
      {"moveToTop", IDS_SETTINGS_LANGUAGES_LANGUAGES_LIST_MOVE_TO_TOP},
      {"removeLanguage", IDS_SETTINGS_LANGUAGES_LANGUAGES_LIST_REMOVE},
      {"addLanguages", IDS_SETTINGS_LANGUAGES_LANGUAGES_ADD},
      {"moveUp", IDS_SETTINGS_LANGUAGES_LANGUAGES_LIST_MOVE_UP},
      {"noSearchResults", IDS_SEARCH_NO_RESULTS},
  };
  html_source->AddLocalizedStrings(kLocalizedStrings);
  html_source->AddBoolean("isPerAppLanguageEnabled",
                          IsPerAppLanguageEnabled(profile()));

  AddLanguagesPageStringsV2(html_source);

  // Inputs subsection exists only when the OsSettingsRevampWayfinding feature
  // is disabled. It is part of the Device section when the feature is enabled.
  if (!ash::features::IsOsSettingsRevampWayfindingEnabled()) {
    CHECK(inputs_subsection_);
    inputs_subsection_->AddLoadTimeData(html_source);
  }
}

void LanguagesSection::AddHandlers(content::WebUI* web_ui) {
  web_ui->AddMessageHandler(
      std::make_unique<::settings::LanguagesHandler>(profile()));
}

int LanguagesSection::GetSectionNameMessageId() const {
  return IDS_OS_SETTINGS_LANGUAGES_AND_INPUT_PAGE_TITLE;
}

mojom::Section LanguagesSection::GetSection() const {
  return ash::features::IsOsSettingsRevampWayfindingEnabled()
             ? mojom::Section::kSystemPreferences
             : mojom::Section::kLanguagesAndInput;
}

mojom::SearchResultIcon LanguagesSection::GetSectionIcon() const {
  return mojom::SearchResultIcon::kLanguage;
}

const char* LanguagesSection::GetSectionPath() const {
  return ash::features::IsOsSettingsRevampWayfindingEnabled()
             ? mojom::kSystemPreferencesSectionPath
             : mojom::kLanguagesAndInputSectionPath;
}

bool LanguagesSection::LogMetric(mojom::Setting setting,
                                 base::Value& value) const {
  // No metrics are logged.
  return false;
}

void LanguagesSection::RegisterHierarchy(HierarchyGenerator* generator) const {
  // Languages.
  generator->RegisterTopLevelSubpage(
      IDS_OS_SETTINGS_LANGUAGES_LANGUAGES_PAGE_TITLE,
      mojom::Subpage::kLanguages, mojom::SearchResultIcon::kLanguage,
      mojom::SearchResultDefaultRank::kMedium, mojom::kLanguagesSubpagePath);
  static constexpr mojom::Setting kLanguagesPageSettings[] = {
      mojom::Setting::kAddLanguage,
      mojom::Setting::kChangeDeviceLanguage,
      mojom::Setting::kOfferTranslation,
      mojom::Setting::kRemoveLanguage,
      mojom::Setting::kMoveLanguageToFront,
      mojom::Setting::kMoveLanguageUp,
      mojom::Setting::kMoveLanguageDown,
      mojom::Setting::kEnableTranslateLanguage,
      mojom::Setting::kDisableTranslateLanguage,
  };
  RegisterNestedSettingBulk(mojom::Subpage::kLanguages, kLanguagesPageSettings,
                            generator);

  if (IsPerAppLanguageEnabled(profile())) {
    // App language subpage.
    generator->RegisterNestedSubpage(
        IDS_OS_SETTINGS_LANGUAGES_APP_LANGUAGES_TITLE,
        mojom::Subpage::kAppLanguages, mojom::Subpage::kLanguages,
        mojom::SearchResultIcon::kLanguage,
        mojom::SearchResultDefaultRank::kMedium,
        mojom::kAppLanguagesSubpagePath);
  }

  // Inputs subsection exists only when the OsSettingsRevampWayfinding feature
  // is disabled. It is part of the Device section when the feature is enabled.
  if (!ash::features::IsOsSettingsRevampWayfindingEnabled()) {
    CHECK(inputs_subsection_);
    inputs_subsection_->RegisterHierarchy(generator);
  }
}

}  // namespace ash::settings