| // 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. |
| |
| #ifndef COMPONENTS_TRANSLATE_CORE_BROWSER_TRANSLATE_PREFS_H_ |
| #define COMPONENTS_TRANSLATE_CORE_BROWSER_TRANSLATE_PREFS_H_ |
| |
| #include <stddef.h> |
| |
| #include <memory> |
| #include <string> |
| #include <vector> |
| |
| #include "base/feature_list.h" |
| #include "base/gtest_prod_util.h" |
| #include "base/memory/raw_ptr.h" |
| #include "base/strings/string_piece.h" |
| #include "base/time/time.h" |
| #include "build/build_config.h" |
| #include "components/prefs/pref_service.h" |
| #include "components/prefs/scoped_user_pref_update.h" |
| #include "url/gurl.h" |
| |
| class PrefService; |
| |
| namespace base { |
| class DictionaryValue; |
| } // namespace base |
| |
| namespace user_prefs { |
| class PrefRegistrySyncable; |
| } |
| |
| namespace language { |
| class LanguagePrefs; |
| } |
| |
| namespace translate { |
| |
| // Enables or disables using the most recent target language as the default |
| // target language option. |
| extern const base::Feature kTranslateRecentTarget; |
| |
| // This allows the user to disable translate by using the |
| // `--disable-features=Translate` command-line flag. |
| extern const base::Feature kTranslate; |
| |
| // Whether to migrate the obsolete always-translate languages pref to the new |
| // pref during object construction as a fix for crbug/1291356, which had |
| // previously not been migrated at all on iOS. This also enables a more |
| // conservative pref merging process that aims to merge in old always-translate |
| // language values from the obsolete pref without conflicting with any values in |
| // the new pref that may have been added. |
| // |
| // TODO(crbug/1291356): This base::Feature only exists to allow a less risky |
| // merge into iOS M98. This base::Feature should be removed once it's no longer |
| // relevant and the enabled behavior should become the only behavior. |
| extern const base::Feature kMigrateAlwaysTranslateLanguagesFix; |
| |
| // Minimum number of times the user must accept a translation before we show |
| // a shortcut to the "Always Translate" functionality. |
| #if BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_IOS) |
| // The "Always Translate" shortcut is always shown on iOS and Android. |
| constexpr int kAlwaysTranslateShortcutMinimumAccepts = 1; |
| #else |
| constexpr int kAlwaysTranslateShortcutMinimumAccepts = 3; |
| #endif |
| |
| // Minimum number of times the user must deny a translation before we show |
| // a shortcut to the "Never Translate" functionality. |
| // Android and iOS implementations do not offer a drop down (for space reasons), |
| // so we are more aggressive about showing this shortcut. |
| #if BUILDFLAG(IS_ANDROID) |
| // On Android, this shows the "Never Translate" shortcut after two denials just |
| // like on iOS. However, the last event is not counted so we must subtract one |
| // to get the same behavior. |
| constexpr int kNeverTranslateShortcutMinimumDenials = 1; |
| #elif BUILDFLAG(IS_IOS) |
| constexpr int kNeverTranslateShortcutMinimumDenials = 2; |
| #else |
| constexpr int kNeverTranslateShortcutMinimumDenials = 3; |
| #endif |
| |
| // This class holds various info about a language, that are related to Translate |
| // Preferences and Language Settings. |
| struct TranslateLanguageInfo { |
| TranslateLanguageInfo(); |
| |
| TranslateLanguageInfo(const TranslateLanguageInfo&); |
| TranslateLanguageInfo(TranslateLanguageInfo&&) noexcept; |
| TranslateLanguageInfo& operator=(const TranslateLanguageInfo&); |
| TranslateLanguageInfo& operator=(TranslateLanguageInfo&&) noexcept; |
| |
| // This ISO code of the language. |
| std::string code; |
| // The display name of the language in the current locale. |
| std::string display_name; |
| // The display name of the language in the language locale. |
| std::string native_display_name; |
| // Whether we support translate for this language. |
| bool supports_translate = false; |
| }; |
| |
| // The wrapper of PrefService object for Translate. |
| // |
| // It is assumed that |prefs_| is alive while this instance is alive. |
| class TranslatePrefs { |
| public: |
| static const char kPrefLanguageProfile[]; |
| static const char kPrefForceTriggerTranslateCount[]; |
| // TODO(crbug.com/524927): Remove kPrefNeverPromptSites after |
| // 3 milestones (M74). |
| static const char kPrefNeverPromptSitesDeprecated[]; |
| static const char kPrefNeverPromptSitesWithTime[]; |
| static const char kPrefTranslateDeniedCount[]; |
| static const char kPrefTranslateIgnoredCount[]; |
| static const char kPrefTranslateAcceptedCount[]; |
| // Deprecated 10/2021. |
| static const char kPrefAlwaysTranslateListDeprecated[]; |
| #if BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_IOS) |
| static const char kPrefTranslateAutoAlwaysCount[]; |
| static const char kPrefTranslateAutoNeverCount[]; |
| #endif |
| #if BUILDFLAG(IS_ANDROID) |
| static const char kPrefExplicitLanguageAskShown[]; |
| #endif |
| |
| // This parameter specifies how the language should be moved within the list. |
| enum RearrangeSpecifier { |
| // No-op enumerator. |
| kNone, |
| // Move the language to the very top of the list. |
| kTop, |
| // Move the language up towards the front of the list. |
| kUp, |
| // Move the language down towards the back of the list. |
| kDown |
| }; |
| |
| explicit TranslatePrefs(PrefService* user_prefs); |
| |
| TranslatePrefs(const TranslatePrefs&) = delete; |
| TranslatePrefs& operator=(const TranslatePrefs&) = delete; |
| |
| ~TranslatePrefs(); |
| |
| // Some existing preferences do not follow inclusive naming. Existing |
| // preference names cannot be renamed since values are saved client side. |
| // Map these to inclusive alternatives to reduce references to those names in |
| // the rest of the code. |
| static std::string MapPreferenceName(const std::string& pref_name); |
| |
| // Returns true if the "offer translate" pref is enabled (i.e. allowing for |
| // automatic Full Page Translate bubbles). |
| bool IsOfferTranslateEnabled() const; |
| |
| // Returns true if Translate is allowed by policy. |
| bool IsTranslateAllowedByPolicy() const; |
| |
| // Sets the country that the application is run in. Determined by the |
| // VariationsService, can be left empty. Used by the TranslateRanker. |
| void SetCountry(const std::string& country); |
| std::string GetCountry() const; |
| |
| // Resets the blocked languages list, the never-translate site list, the |
| // always-translate languages list, the accepted/denied counts, and whether |
| // Translate is enabled. |
| void ResetToDefaults(); |
| |
| // Before adding to, removing from, or checking the block list the source |
| // language is converted to its translate synonym. |
| // A blocked language will not be offered to be translated. All blocked |
| // languages form the "Never translate" list. |
| bool IsBlockedLanguage(base::StringPiece source_language) const; |
| void BlockLanguage(base::StringPiece source_language); |
| void UnblockLanguage(base::StringPiece source_language); |
| // Returns the languages that should be blocked by default as a |
| // base::Value::List. |
| static base::Value::List GetDefaultBlockedLanguages(); |
| void ResetBlockedLanguagesToDefault(); |
| // Prevent empty blocked languages by resetting them to the default value. |
| // (crbug.com/902354) |
| void ResetEmptyBlockedLanguagesToDefaults(); |
| // Get the languages that for which translation should never be prompted |
| // formatted as Chrome language codes. |
| std::vector<std::string> GetNeverTranslateLanguages() const; |
| |
| // Adds the language to the language list at chrome://settings/languages. |
| // If the param |force_blocked| is set to true, the language is added to the |
| // blocked list. |
| // If force_blocked is set to false, the language is added to the blocked list |
| // if the language list does not already contain another language with the |
| // same base language. |
| void AddToLanguageList(base::StringPiece language, bool force_blocked); |
| // Removes the language from the language list at chrome://settings/languages. |
| void RemoveFromLanguageList(base::StringPiece language); |
| |
| // Rearranges the given language inside the language list. |
| // The direction of the move is specified as a RearrangeSpecifier. |
| // |offset| is ignored unless the RearrangeSpecifier is kUp or kDown: in |
| // which case it needs to be positive for any change to be made. |
| // The param |enabled_languages| is a list of languages that are enabled in |
| // the current UI. This is required because the full language list contains |
| // some languages that might not be enabled in the current UI and we need to |
| // skip those languages while rearranging the list. |
| void RearrangeLanguage(base::StringPiece language, |
| RearrangeSpecifier where, |
| int offset, |
| const std::vector<std::string>& enabled_languages); |
| |
| // Sets the language order to the provided order. |
| // This function is called from the language preference manager in Chrome for |
| // Android. |
| void SetLanguageOrder(const std::vector<std::string>& new_order); |
| |
| // Returns the list of TranslateLanguageInfo for all languages that are |
| // available in the given locale. |
| // The list returned in |languages| is sorted alphabetically based on the |
| // display names in the given locale. |
| // May cause a supported language list fetch unless |translate_allowed| is |
| // false. |
| static void GetLanguageInfoList( |
| const std::string& app_locale, |
| bool translate_allowed, |
| std::vector<TranslateLanguageInfo>* languages); |
| |
| // Returns a list of language codes representing content language set by the |
| // user that are translatable for given app_language. The list returned in |
| // |codes| is ordered based on the user's ordering. In case user has |
| // country variants for a specific language set, the language main |
| // translatable language is returned, e.g. if a user has "de" and "de-CH", the |
| // result is "de", if a user only has "de-CH" content language set, "de" is |
| // returned. |
| void GetTranslatableContentLanguages(const std::string& app_locale, |
| std::vector<std::string>* codes); |
| |
| bool IsSiteOnNeverPromptList(base::StringPiece site) const; |
| void AddSiteToNeverPromptList(base::StringPiece site); |
| void RemoveSiteFromNeverPromptList(base::StringPiece site); |
| |
| std::vector<std::string> GetNeverPromptSitesBetween(base::Time begin, |
| base::Time end) const; |
| void DeleteNeverPromptSitesBetween(base::Time begin, base::Time end); |
| |
| bool HasLanguagePairsToAlwaysTranslate() const; |
| |
| bool IsLanguagePairOnAlwaysTranslateList(base::StringPiece source_language, |
| base::StringPiece target_language); |
| // Converts the source and target language to their translate synonym and |
| // adds the pair to the always translate dict. |
| void AddLanguagePairToAlwaysTranslateList(base::StringPiece source_language, |
| base::StringPiece target_language); |
| // Removes the translate synonym of source_language from the always |
| // translate dict. |
| void RemoveLanguagePairFromAlwaysTranslateList( |
| base::StringPiece source_language, |
| base::StringPiece target_language); |
| |
| // Sets the always translate state for a language. |
| // The always translate language list is actually a dict mapping |
| // source_language -> target_language. We use the current target language |
| // when adding |language| to the dict. |
| void SetLanguageAlwaysTranslateState(base::StringPiece source_language, |
| bool always_translate); |
| |
| // Gets the languages that are set to always translate formatted as Chrome |
| // language codes. |
| std::vector<std::string> GetAlwaysTranslateLanguages() const; |
| |
| // These methods are used to track how many times the user has denied the |
| // translation for a specific language. (So we can present a UI to blocklist |
| // that language if the user keeps denying translations). |
| int GetTranslationDeniedCount(base::StringPiece language) const; |
| void IncrementTranslationDeniedCount(base::StringPiece language); |
| void ResetTranslationDeniedCount(base::StringPiece language); |
| |
| // These methods are used to track how many times the user has ignored the |
| // translation bubble for a specific language. |
| int GetTranslationIgnoredCount(base::StringPiece language) const; |
| void IncrementTranslationIgnoredCount(base::StringPiece language); |
| void ResetTranslationIgnoredCount(base::StringPiece language); |
| |
| // These methods are used to track how many times the user has accepted the |
| // translation for a specific language. (So we can present a UI to allowlist |
| // that language if the user keeps accepting translations). |
| int GetTranslationAcceptedCount(base::StringPiece language) const; |
| void IncrementTranslationAcceptedCount(base::StringPiece language); |
| void ResetTranslationAcceptedCount(base::StringPiece language); |
| |
| #if BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_IOS) |
| // These methods are used to track how many times the auto-always translation |
| // has been triggered for a specific language. |
| int GetTranslationAutoAlwaysCount(base::StringPiece language) const; |
| void IncrementTranslationAutoAlwaysCount(base::StringPiece language); |
| void ResetTranslationAutoAlwaysCount(base::StringPiece language); |
| |
| // These methods are used to track how many times the auto-never translation |
| // has been triggered for a specific language. |
| int GetTranslationAutoNeverCount(base::StringPiece language) const; |
| void IncrementTranslationAutoNeverCount(base::StringPiece language); |
| void ResetTranslationAutoNeverCount(base::StringPiece language); |
| #endif |
| |
| #if BUILDFLAG(IS_ANDROID) |
| // These methods are used to determine whether the explicit language ask |
| // prompt was displayed to the user already. |
| bool GetExplicitLanguageAskPromptShown() const; |
| void SetExplicitLanguageAskPromptShown(bool shown); |
| |
| // These methods are used to determine whether the app language prompt was |
| // displayed to the user already. Once shown it can not be unset. |
| bool GetAppLanguagePromptShown() const; |
| void SetAppLanguagePromptShown(); |
| #endif |
| |
| // Gets the full (policy-forced and user selected) language list from language |
| // settings. |
| void GetLanguageList(std::vector<std::string>* languages) const; |
| |
| // Gets the user selected language list from language settings. |
| void GetUserSelectedLanguageList(std::vector<std::string>* languages) const; |
| |
| bool CanTranslateLanguage(base::StringPiece language); |
| bool ShouldAutoTranslate(base::StringPiece source_language, |
| std::string* target_language); |
| // True if the detailed language settings are enabled for this user. |
| static bool IsDetailedLanguageSettingsEnabled(); |
| |
| // Stores and retrieves the last-observed translate target language. Used to |
| // determine which target language to offer in future. The translate target |
| // is converted to a translate synonym before it is set. |
| void SetRecentTargetLanguage(const std::string& target_language); |
| void ResetRecentTargetLanguage(); |
| std::string GetRecentTargetLanguage() const; |
| |
| // Gets the value for the pref that represents how often the |
| // kOverrideTranslateTriggerInIndia experiment made translate trigger on an |
| // English page when it otherwise wouldn't have. This pref is used to |
| // determine whether the experiment should be suppressed for a particular user |
| int GetForceTriggerOnEnglishPagesCount() const; |
| // Increments the pref that represents how often the |
| // kOverrideTranslateTriggerInIndia experiment made translate trigger on an |
| // English page when it otherwise wouldn't have. |
| void ReportForceTriggerOnEnglishPages(); |
| // Sets to -1 the pref that represents how often the |
| // kOverrideTranslateTriggerInIndia experiment made translate trigger on an |
| // English page when it otherwise wouldn't have. This is a special value that |
| // signals that the backoff should not happen for that user. |
| void ReportAcceptedAfterForceTriggerOnEnglishPages(); |
| |
| // Migrate the sites to never translate from a list to a dictionary that maps |
| // sites to a timestamp of the creation of this entry. |
| void MigrateNeverPromptSites(); |
| |
| static void RegisterProfilePrefs(user_prefs::PrefRegistrySyncable* registry); |
| |
| static void RegisterProfilePrefsForMigration( |
| user_prefs::PrefRegistrySyncable* registry); |
| |
| static void MigrateObsoleteProfilePrefs(PrefService* pref_service); |
| |
| static void ClearObsoleteProfilePrefs(PrefService* pref_service); |
| |
| private: |
| FRIEND_TEST_ALL_PREFIXES(TranslatePrefsTest, |
| UpdateLanguageListFeatureEnabled); |
| FRIEND_TEST_ALL_PREFIXES(TranslatePrefsTest, BlockLanguage); |
| FRIEND_TEST_ALL_PREFIXES(TranslatePrefsTest, UnblockLanguage); |
| FRIEND_TEST_ALL_PREFIXES(TranslatePrefsTest, AddToLanguageList); |
| FRIEND_TEST_ALL_PREFIXES(TranslatePrefsTest, RemoveFromLanguageList); |
| FRIEND_TEST_ALL_PREFIXES(TranslatePrefsTest, |
| RemoveFromLanguageListRemovesRemainingUnsupported); |
| FRIEND_TEST_ALL_PREFIXES(TranslatePrefsTest, |
| RemoveFromLanguageListClearsRecentLanguage); |
| FRIEND_TEST_ALL_PREFIXES(TranslatePrefsTest, AddToLanguageList); |
| FRIEND_TEST_ALL_PREFIXES(TranslatePrefsTest, RemoveFromLanguageList); |
| FRIEND_TEST_ALL_PREFIXES(TranslatePrefsTest, MoveLanguageToTheTop); |
| FRIEND_TEST_ALL_PREFIXES(TranslatePrefsTest, MoveLanguageUp); |
| FRIEND_TEST_ALL_PREFIXES(TranslatePrefsTest, MoveLanguageDown); |
| FRIEND_TEST_ALL_PREFIXES(TranslatePrefsTest, ResetBlockedLanguagesToDefault); |
| FRIEND_TEST_ALL_PREFIXES(TranslatePrefsTest, MigrateNeverPromptSites); |
| friend class TranslatePrefsTest; |
| |
| void ClearNeverPromptSiteList(); |
| void ClearAlwaysTranslateLanguagePairs(); |
| |
| // |pref_id| is the name of a list pref. |
| bool IsValueOnNeverPromptList(const char* pref_id, |
| base::StringPiece value) const; |
| void AddValueToNeverPromptList(const char* pref_id, base::StringPiece value); |
| void RemoveValueFromNeverPromptList(const char* pref_id, |
| base::StringPiece value); |
| size_t GetListSize(const char* pref_id) const; |
| |
| bool IsDictionaryEmpty(const char* pref_id) const; |
| |
| // Retrieves the dictionary mapping the number of times translation has been |
| // denied for a language, creating it if necessary. |
| base::DictionaryValue* GetTranslationDeniedCountDictionary(); |
| |
| // Retrieves the dictionary mapping the number of times translation has been |
| // accepted for a language, creating it if necessary. |
| base::DictionaryValue* GetTranslationAcceptedCountDictionary() const; |
| |
| raw_ptr<PrefService> prefs_; // Weak. |
| |
| std::string country_; // The country the app runs in. |
| |
| std::unique_ptr<language::LanguagePrefs> language_prefs_; |
| }; |
| |
| } // namespace translate |
| |
| #endif // COMPONENTS_TRANSLATE_CORE_BROWSER_TRANSLATE_PREFS_H_ |