blob: 38d145ec638f4a1f430b71844eccebc7072385bf [file] [log] [blame]
// 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 <string>
#include <vector>
#include "base/feature_list.h"
#include "base/gtest_prod_util.h"
#include "base/macros.h"
#include "base/time/time.h"
#include "build/build_config.h"
#include "components/prefs/scoped_user_pref_update.h"
#include "url/gurl.h"
class PrefService;
namespace base {
class DictionaryValue;
class ListValue;
}
namespace user_prefs {
class PrefRegistrySyncable;
}
namespace translate {
// Enables or disables the regional locales as valid selection for the display
// UI.
extern const base::Feature kRegionalLocalesAsDisplayUI;
// Enables or disables using the most recent target language as the default
// target language option.
extern const base::Feature kTranslateRecentTarget;
// Enable or disable the Translate popup altogether.
extern const base::Feature kTranslateUI;
// Enable the "Translate" item in the overflow menu on Android.
extern const base::Feature kTranslateAndroidManualTrigger;
// Enables the new compact Translate infobar on iOS.
extern const base::Feature kCompactTranslateInfobarIOS;
// Minimum number of times the user must accept a translation before we show
// a shortcut to the "Always Translate" functionality.
#if defined(OS_ANDROID) || defined(OS_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 defined(OS_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 defined(OS_IOS)
constexpr int kNeverTranslateShortcutMinimumDenials = 2;
#else
constexpr int kNeverTranslateShortcutMinimumDenials = 3;
#endif
class TranslateAcceptLanguages;
// Allows updating denial times for a specific language while maintaining the
// maximum list size and ensuring PrefObservers are notified of change values.
class DenialTimeUpdate {
public:
DenialTimeUpdate(PrefService* prefs,
const std::string& language,
size_t max_denial_count);
~DenialTimeUpdate();
// Gets the list of timestamps when translation was denied. Guaranteed to
// be non-null, potentially inserts a new listvalue into the dictionary if
// necessary.
base::ListValue* GetDenialTimes();
// Gets the oldest denial time on record. Will return base::Time::max() if
// no denial time has been recorded yet.
base::Time GetOldestDenialTime();
// Records a new denial time. Does not ensure ordering of denial times - it is
// up to the user to ensure times are in monotonic order.
void AddDenialTime(base::Time denial_time);
private:
DictionaryPrefUpdate denial_time_dict_update_;
std::string language_;
size_t max_denial_count_;
base::ListValue* time_list_; // Weak, owned by the containing prefs service.
};
// This class holds various info about a language, that are related to Translate
// Preferences and Language Settings.
struct TranslateLanguageInfo {
TranslateLanguageInfo();
TranslateLanguageInfo(const TranslateLanguageInfo&);
// 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 kPrefTranslateSiteBlacklist after
// 3 milestones (M74).
static const char kPrefTranslateSiteBlacklistDeprecated[];
static const char kPrefTranslateSiteBlacklistWithTime[];
static const char kPrefTranslateWhitelists[];
static const char kPrefTranslateDeniedCount[];
static const char kPrefTranslateIgnoredCount[];
static const char kPrefTranslateAcceptedCount[];
static const char kPrefTranslateBlockedLanguages[];
static const char kPrefTranslateLastDeniedTimeForLanguage[];
static const char kPrefTranslateTooOftenDeniedForLanguage[];
static const char kPrefTranslateRecentTarget[];
#if defined(OS_ANDROID)
static const char kPrefTranslateAutoAlwaysCount[];
static const char kPrefTranslateAutoNeverCount[];
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
};
// |preferred_languages_pref| is only used on Chrome OS, other platforms must
// pass NULL.
TranslatePrefs(PrefService* user_prefs,
const char* accept_languages_pref,
const char* preferred_languages_pref);
// Checks if the "offer translate" (i.e. automatic translate bubble) feature
// is enabled.
bool IsOfferTranslateEnabled() const;
// Checks 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 sites blacklist, the languages
// whitelist, and the accepted/denied counts.
void ResetToDefaults();
bool IsBlockedLanguage(const std::string& original_language) const;
void BlockLanguage(const std::string& original_language);
void UnblockLanguage(const std::string& original_language);
// 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(const std::string& language, bool force_blocked);
// Removes the language from the language list at chrome://settings/languages.
void RemoveFromLanguageList(const std::string& 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(const std::string& language,
RearrangeSpecifier where,
const int offset,
const std::vector<std::string>& enabled_languages);
// 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);
bool IsSiteBlacklisted(const std::string& site) const;
void BlacklistSite(const std::string& site);
void RemoveSiteFromBlacklist(const std::string& site);
std::vector<std::string> GetBlacklistedSitesBetween(base::Time begin,
base::Time end) const;
void DeleteBlacklistedSitesBetween(base::Time begin, base::Time end);
bool HasWhitelistedLanguagePairs() const;
bool IsLanguagePairWhitelisted(const std::string& original_language,
const std::string& target_language);
void WhitelistLanguagePair(const std::string& original_language,
const std::string& target_language);
void RemoveLanguagePairFromWhitelist(const std::string& original_language,
const std::string& target_language);
// Will return true if at least one language has been blacklisted.
bool HasBlockedLanguages() const;
// Will return true if at least one site has been blacklisted.
bool HasBlacklistedSites() 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 black-list
// that language if the user keeps denying translations).
int GetTranslationDeniedCount(const std::string& language) const;
void IncrementTranslationDeniedCount(const std::string& language);
void ResetTranslationDeniedCount(const std::string& language);
// These methods are used to track how many times the user has ignored the
// translation bubble for a specific language.
int GetTranslationIgnoredCount(const std::string& language) const;
void IncrementTranslationIgnoredCount(const std::string& language);
void ResetTranslationIgnoredCount(const std::string& 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 white-list
// that language if the user keeps accepting translations).
int GetTranslationAcceptedCount(const std::string& language) const;
void IncrementTranslationAcceptedCount(const std::string& language);
void ResetTranslationAcceptedCount(const std::string& language);
#if defined(OS_ANDROID)
// These methods are used to track how many times the auto-always translation
// has been triggered for a specific language.
int GetTranslationAutoAlwaysCount(const std::string& language) const;
void IncrementTranslationAutoAlwaysCount(const std::string& language);
void ResetTranslationAutoAlwaysCount(const std::string& language);
// These methods are used to track how many times the auto-never translation
// has been triggered for a specific language.
int GetTranslationAutoNeverCount(const std::string& language) const;
void IncrementTranslationAutoNeverCount(const std::string& language);
void ResetTranslationAutoNeverCount(const std::string& language);
// 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);
#endif
// Update the last time on closing the Translate UI without translation.
void UpdateLastDeniedTime(const std::string& language);
// Returns true if translation is denied too often.
bool IsTooOftenDenied(const std::string& language) const;
// Resets the prefs of denial state. Only used internally for diagnostics.
void ResetDenialState();
// Gets the language list of the language settings.
void GetLanguageList(std::vector<std::string>* languages) const;
bool CanTranslateLanguage(TranslateAcceptLanguages* accept_languages,
const std::string& language);
bool ShouldAutoTranslate(const std::string& original_language,
std::string* target_language);
// Stores and retrieves the last-observed translate target language. Used to
// determine which target language to offer in future.
void SetRecentTargetLanguage(const std::string& target_language);
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 blacklist from a list to a dictionary that maps sites
// to a timestamp of the creation of this entry.
void MigrateSitesBlacklist();
static void RegisterProfilePrefs(user_prefs::PrefRegistrySyncable* registry);
private:
FRIEND_TEST_ALL_PREFIXES(TranslatePrefsTest, UpdateLanguageList);
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 class TranslatePrefsTest;
// Updates the language list of the language settings.
void UpdateLanguageList(const std::vector<std::string>& languages);
// Merges two language sets to migrate to the language setting UI.
static void CreateBlockedLanguages(
std::vector<std::string>* blocked_languages,
const std::vector<std::string>& blacklisted_languages,
const std::vector<std::string>& accept_languages);
void ClearBlockedLanguages();
void ClearBlacklistedSites();
void ClearWhitelistedLanguagePairs();
bool IsValueBlacklisted(const char* pref_id, const std::string& value) const;
void BlacklistValue(const char* pref_id, const std::string& value);
void RemoveValueFromBlacklist(const char* pref_id, const std::string& value);
bool IsValueInList(const base::ListValue* list,
const std::string& value) const;
bool IsListEmpty(const char* pref_id) const;
bool IsDictionaryEmpty(const char* pref_id) const;
// Removes from the language list any language that isn't supported as an
// Accept-Language (it's not in kAcceptLanguageList) if and only if there
// aren't any other languages from the same family in the list that are
// supported.
void PurgeUnsupportedLanguagesInLanguageFamily(
const std::string& language,
std::vector<std::string>* list);
// Path to the preference storing the accept languages.
const std::string accept_languages_pref_;
#if defined(OS_CHROMEOS)
// Path to the preference storing the preferred languages.
// Only used on ChromeOS.
std::string preferred_languages_pref_;
#endif
// 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;
PrefService* prefs_; // Weak.
std::string country_; // The country the app runs in.
DISALLOW_COPY_AND_ASSIGN(TranslatePrefs);
};
} // namespace translate
#endif // COMPONENTS_TRANSLATE_CORE_BROWSER_TRANSLATE_PREFS_H_