Commit be1c8ead authored by Anthony Vallee-Dubois's avatar Anthony Vallee-Dubois Committed by Commit Bot

[Language] Experiment logic for Trigger in India

This CL adds the logic required to override (via Finch) the LanguageModel
and Triggering logic for Translate in India on English pages.

Bug: 840367
Change-Id: Id4e6e4af4359e8a880a53ce6b4a5915a11ee2ce3
Reviewed-on: https://chromium-review.googlesource.com/1068624
Commit-Queue: anthonyvd <anthonyvd@chromium.org>
Reviewed-by: default avatarMichael Martis <martis@chromium.org>
Cr-Commit-Position: refs/heads/master@{#561884}
parent 995c0235
......@@ -4,6 +4,11 @@
#include "components/language/core/common/language_experiments.h"
#include <map>
#include <string>
#include "base/metrics/field_trial_params.h"
namespace language {
const base::Feature kUseHeuristicLanguageModel{
......@@ -11,13 +16,39 @@ const base::Feature kUseHeuristicLanguageModel{
const base::Feature kOverrideTranslateTriggerInIndia{
"OverrideTranslateTriggerInIndia", base::FEATURE_DISABLED_BY_DEFAULT};
const char kOverrideModelKey[] = "override_model";
const char kEnforceRankerKey[] = "enforce_ranker";
const char kOverrideModelHeuristicValue[] = "heuristic";
const char kOverrideModelGeoValue[] = "geo";
OverrideLanguageModel GetOverrideLanguageModel() {
if (base::FeatureList::IsEnabled(kUseHeuristicLanguageModel))
std::map<std::string, std::string> params;
bool should_override_model = base::GetFieldTrialParamsByFeature(
kOverrideTranslateTriggerInIndia, &params);
if (base::FeatureList::IsEnabled(kUseHeuristicLanguageModel) ||
(should_override_model &&
params[kOverrideModelKey] == kOverrideModelHeuristicValue)) {
return OverrideLanguageModel::HEURISTIC;
// TODO(crbug.com/840367): Take the kOverrideTranslateTriggerInIndia params
// into account to decide which model to use.
}
if (should_override_model &&
params[kOverrideModelKey] == kOverrideModelGeoValue) {
return OverrideLanguageModel::GEO;
}
return OverrideLanguageModel::DEFAULT;
}
bool ShouldForceTriggerTranslateOnEnglishPages() {
return base::FeatureList::IsEnabled(kOverrideTranslateTriggerInIndia);
}
bool ShouldPreventRankerEnforcementInIndia() {
std::map<std::string, std::string> params;
return base::GetFieldTrialParamsByFeature(kOverrideTranslateTriggerInIndia,
&params) &&
params[kEnforceRankerKey] == "false";
}
} // namespace language
......@@ -26,8 +26,20 @@ enum class OverrideLanguageModel {
GEO,
};
// Returns which language model to use depending on the state of all Language
// experiments.
OverrideLanguageModel GetOverrideLanguageModel();
// Returns true if kOverrideTranslateTriggerInIndia is enabled, false otherwise.
// It should be interpreted as a signal to trigger translate UI on English
// pages, even when the UI language is English.
bool ShouldForceTriggerTranslateOnEnglishPages();
// Returns true if kOverrideTranslateTriggerInIndia is enabled and the current
// experiment group specifies the param to enforce Ranker decisions, false
// otherwise.
bool ShouldPreventRankerEnforcementInIndia();
} // namespace language
#endif // COMPONENTS_LANGUAGE_CORE_COMMON_LANGUAGE_EXPERIMENTS_H_
......@@ -113,6 +113,7 @@ source_set("unit_tests") {
"//components/assist_ranker/proto",
"//components/infobars/core",
"//components/language/core/browser",
"//components/language/core/common:common",
"//components/pref_registry:pref_registry",
"//components/prefs",
"//components/prefs:test_support",
......
......@@ -16,6 +16,7 @@
#include "base/strings/stringprintf.h"
#include "base/time/time.h"
#include "components/language/core/browser/language_model.h"
#include "components/language/core/common/language_experiments.h"
#include "components/prefs/pref_service.h"
#include "components/translate/core/browser/language_state.h"
#include "components/translate/core/browser/page_translated_details.h"
......@@ -58,6 +59,32 @@ const char kSourceLanguageQueryName[] = "sl";
// Used in kReportLanguageDetectionErrorURL to specify the page URL.
const char kUrlQueryName[] = "u";
std::set<std::string> GetSkippedLanguagesForExperiments(
std::string source_lang) {
// Under this experiment, skip english as the target language if possible so
// that Translate triggers on English pages.
std::set<std::string> skipped_languages;
if (language::ShouldForceTriggerTranslateOnEnglishPages() &&
source_lang == "en") {
skipped_languages.insert("en");
}
return skipped_languages;
}
// Moves any element in |languages| for which |lang_code| is found in
// |skipped_languages| to the end of |languages|. Otherwise preserves relative
// ordering of elements. Modifies |languages| in place.
void MoveSkippedLanguagesToEndIfNecessary(
std::vector<std::string>* languages,
const std::set<std::string>& skipped_languages) {
if (!skipped_languages.empty()) {
std::stable_partition(
languages->begin(), languages->end(), [&](const auto& lang) {
return skipped_languages.find(lang) == skipped_languages.end();
});
}
}
} // namespace
TranslateManager::~TranslateManager() {}
......@@ -147,10 +174,12 @@ void TranslateManager::InitiateTranslation(const std::string& page_lang) {
return;
}
std::string target_lang =
GetTargetLanguage(translate_prefs.get(), language_model_);
std::string language_code =
TranslateDownloadManager::GetLanguageCode(page_lang);
const std::set<std::string>& skipped_languages =
GetSkippedLanguagesForExperiments(language_code);
std::string target_lang = GetTargetLanguage(
translate_prefs.get(), language_model_, skipped_languages);
// Don't translate similar languages (ex: en-US to en).
if (language_code == target_lang) {
......@@ -163,7 +192,10 @@ void TranslateManager::InitiateTranslation(const std::string& page_lang) {
// Querying the ranker now, but not exiting immediately so that we may log
// other potential suppression reasons.
// Ignore Ranker's decision under triggering experiments since it wasn't
// trained appropriately under those scenarios.
bool should_offer_translation =
language::ShouldPreventRankerEnforcementInIndia() ||
translate_ranker_->ShouldOfferTranslation(translate_event_.get());
// Nothing to do if either the language Chrome is in or the language of
......@@ -395,7 +427,8 @@ void TranslateManager::OnTranslateScriptFetchComplete(
// static
std::string TranslateManager::GetTargetLanguage(
const TranslatePrefs* prefs,
language::LanguageModel* language_model) {
language::LanguageModel* language_model,
const std::set<std::string>& skipped_languages) {
DCHECK(prefs);
const std::string& recent_target = prefs->GetRecentTargetLanguage();
......@@ -406,14 +439,21 @@ std::string TranslateManager::GetTargetLanguage(
}
if (language_model) {
// Use the first language from the model that translate supports.
std::vector<std::string> language_codes;
for (const auto& lang : language_model->GetLanguages()) {
std::string lang_code =
TranslateDownloadManager::GetLanguageCode(lang.lang_code);
translate::ToTranslateLanguageSynonym(&lang_code);
if (TranslateDownloadManager::IsSupportedLanguage(lang_code))
return lang_code;
language_codes.push_back(lang_code);
}
// If some languages need to be skipped, move them to the end of the
// language vector so that any other eligible language takes priority.
MoveSkippedLanguagesToEndIfNecessary(&language_codes, skipped_languages);
// Use the first language from the model that translate supports.
if (!language_codes.empty())
return language_codes[0];
} else {
// Get the browser's user interface language.
std::string language = TranslateDownloadManager::GetLanguageCode(
......@@ -437,6 +477,13 @@ std::string TranslateManager::GetTargetLanguage(
return std::string();
}
// static
std::string TranslateManager::GetTargetLanguage(
const TranslatePrefs* prefs,
language::LanguageModel* language_model) {
return GetTargetLanguage(prefs, language_model, {});
}
// static
std::string TranslateManager::GetAutoTargetLanguage(
const std::string& original_language,
......
......@@ -7,6 +7,7 @@
#include <map>
#include <memory>
#include <set>
#include <string>
#include <vector>
......@@ -80,6 +81,15 @@ class TranslateManager {
static std::string GetTargetLanguage(const TranslatePrefs* prefs,
language::LanguageModel* language_model);
// Returns the language to translate to using the same logic as
// GetTargetLanguage but doesn't returned languages contained in
// |skipped_languages| if |language_model| is not null and there is at least
// one other suitable language.
static std::string GetTargetLanguage(
const TranslatePrefs* prefs,
language::LanguageModel* language_model,
const std::set<std::string>& skipped_languages);
// Returns the language to automatically translate to. |original_language| is
// the webpage's original language.
static std::string GetAutoTargetLanguage(const std::string& original_language,
......
......@@ -13,11 +13,13 @@
#include "build/build_config.h"
#include "components/infobars/core/infobar.h"
#include "components/language/core/browser/language_model.h"
#include "components/language/core/common/language_experiments.h"
#include "components/pref_registry/pref_registry_syncable.h"
#include "components/sync_preferences/testing_pref_service_syncable.h"
#include "components/translate/core/browser/mock_translate_client.h"
#include "components/translate/core/browser/mock_translate_driver.h"
#include "components/translate/core/browser/mock_translate_ranker.h"
#include "components/translate/core/browser/translate_accept_languages.h"
#include "components/translate/core/browser/translate_browser_metrics.h"
#include "components/translate/core/browser/translate_client.h"
#include "components/translate/core/browser/translate_download_manager.h"
......@@ -277,6 +279,152 @@ TEST_F(TranslateManagerTest, GetTargetLanguageFromModel) {
&mock_language_model_));
}
// Test that the language model is used if provided, and that languages that
// should be skipped actually are.
TEST_F(TranslateManagerTest, GetTargetLanguageFromModelWithSkippedLanguages) {
// Try with a single, supported language but request it to be skipped. It
// should still be chosen since there is no fallback.
ASSERT_TRUE(TranslateDownloadManager::IsSupportedLanguage("en"));
mock_language_model_.details = {
MockLanguageModel::LanguageDetails("en", 1.0)};
EXPECT_EQ("en", TranslateManager::GetTargetLanguage(
&translate_prefs_, &mock_language_model_, {"en"}));
// Try with two supported languages and skip the first one.
ASSERT_TRUE(TranslateDownloadManager::IsSupportedLanguage("de"));
mock_language_model_.details = {
MockLanguageModel::LanguageDetails("de", 1.0),
MockLanguageModel::LanguageDetails("en", 0.5)};
EXPECT_EQ("en", TranslateManager::GetTargetLanguage(
&translate_prefs_, &mock_language_model_, {"de"}));
// Try with first supported language lower in the list but request it to be
// skipped. It should still be chosen since there is no fallback.
ASSERT_FALSE(TranslateDownloadManager::IsSupportedLanguage("xx"));
mock_language_model_.details = {
MockLanguageModel::LanguageDetails("xx", 1.0),
MockLanguageModel::LanguageDetails("en", 0.5)};
EXPECT_EQ("en", TranslateManager::GetTargetLanguage(
&translate_prefs_, &mock_language_model_, {"en"}));
// Try non standard codes. Skipping should be specified using the supported
// language in pairs of synonyms.
// 'he', 'fil', 'nb' => 'iw', 'tl', 'no'
ASSERT_TRUE(TranslateDownloadManager::IsSupportedLanguage("iw"));
ASSERT_FALSE(TranslateDownloadManager::IsSupportedLanguage("he"));
mock_language_model_.details = {
MockLanguageModel::LanguageDetails("he", 1.0),
MockLanguageModel::LanguageDetails("en", 0.5)};
EXPECT_EQ("en", TranslateManager::GetTargetLanguage(
&translate_prefs_, &mock_language_model_, {"iw"}));
mock_language_model_.details = {
MockLanguageModel::LanguageDetails("iw", 1.0),
MockLanguageModel::LanguageDetails("en", 0.5)};
EXPECT_EQ("iw", TranslateManager::GetTargetLanguage(
&translate_prefs_, &mock_language_model_, {"he"}));
}
TEST_F(TranslateManagerTest, OverrideTriggerWithIndiaEnglishExperiment) {
scoped_feature_list_.InitAndEnableFeatureWithParameters(
language::kOverrideTranslateTriggerInIndia,
{{"override_model", "heuristic"}, {"enforce_ranker", "false"}});
TranslateManager::SetIgnoreMissingKeyForTesting(true);
mock_language_model_.details = {
MockLanguageModel::LanguageDetails("en", 1.0),
MockLanguageModel::LanguageDetails("hi", 0.5),
};
ON_CALL(mock_translate_client_, IsTranslatableURL(GURL::EmptyGURL()))
.WillByDefault(Return(true));
TranslateAcceptLanguages accept_langugages(&prefs_, accept_languages_prefs);
ON_CALL(mock_translate_client_, GetTranslateAcceptLanguages())
.WillByDefault(Return(&accept_langugages));
translate_manager_.reset(new translate::TranslateManager(
&mock_translate_client_, &mock_translate_ranker_, &mock_language_model_));
base::HistogramTester histogram_tester;
prefs_.SetBoolean(prefs::kOfferTranslateEnabled, true);
translate_manager_->GetLanguageState().LanguageDetermined("en", true);
network_notifier_.SimulateOnline();
EXPECT_EQ("hi", TranslateManager::GetTargetLanguage(
&translate_prefs_, &mock_language_model_, {"en"}));
translate_manager_->InitiateTranslation("en");
histogram_tester.ExpectUniqueSample(
kInitiationStatusName,
translate::TranslateBrowserMetrics::INITIATION_STATUS_SHOW_INFOBAR, 1);
}
TEST_F(TranslateManagerTest, ShouldHonorExperimentRankerEnforcement_Enforce) {
scoped_feature_list_.InitAndEnableFeatureWithParameters(
language::kOverrideTranslateTriggerInIndia,
{{"override_model", "heuristic"}, {"enforce_ranker", "true"}});
TranslateManager::SetIgnoreMissingKeyForTesting(true);
mock_language_model_.details = {
MockLanguageModel::LanguageDetails("en", 1.0),
MockLanguageModel::LanguageDetails("hi", 0.5),
};
ON_CALL(mock_translate_client_, IsTranslatableURL(GURL::EmptyGURL()))
.WillByDefault(Return(true));
TranslateAcceptLanguages accept_langugages(&prefs_, accept_languages_prefs);
ON_CALL(mock_translate_client_, GetTranslateAcceptLanguages())
.WillByDefault(Return(&accept_langugages));
// Simulate that Ranker decides to suppress the translation UI. This should be
// honored since "enforce_ranker" is "true" in the experiment params.
mock_translate_ranker_.set_should_offer_translation(false);
translate_manager_.reset(new translate::TranslateManager(
&mock_translate_client_, &mock_translate_ranker_, &mock_language_model_));
base::HistogramTester histogram_tester;
prefs_.SetBoolean(prefs::kOfferTranslateEnabled, true);
translate_manager_->GetLanguageState().LanguageDetermined("en", true);
network_notifier_.SimulateOnline();
EXPECT_EQ("hi", TranslateManager::GetTargetLanguage(
&translate_prefs_, &mock_language_model_, {"en"}));
translate_manager_->InitiateTranslation("en");
histogram_tester.ExpectUniqueSample(
kInitiationStatusName,
translate::TranslateBrowserMetrics::INITIATION_STATUS_ABORTED_BY_RANKER,
1);
}
TEST_F(TranslateManagerTest,
ShouldHonorExperimentRankerEnforcement_DontEnforce) {
scoped_feature_list_.InitAndEnableFeatureWithParameters(
language::kOverrideTranslateTriggerInIndia,
{{"override_model", "heuristic"}, {"enforce_ranker", "false"}});
TranslateManager::SetIgnoreMissingKeyForTesting(true);
mock_language_model_.details = {
MockLanguageModel::LanguageDetails("en", 1.0),
MockLanguageModel::LanguageDetails("hi", 0.5),
};
ON_CALL(mock_translate_client_, IsTranslatableURL(GURL::EmptyGURL()))
.WillByDefault(Return(true));
TranslateAcceptLanguages accept_langugages(&prefs_, accept_languages_prefs);
ON_CALL(mock_translate_client_, GetTranslateAcceptLanguages())
.WillByDefault(Return(&accept_langugages));
// Simulate that Ranker decides to suppress the translation UI. This should
// not be honored since "enforce_ranker" is "true" in the experiment params.
mock_translate_ranker_.set_should_offer_translation(false);
translate_manager_.reset(new translate::TranslateManager(
&mock_translate_client_, &mock_translate_ranker_, &mock_language_model_));
base::HistogramTester histogram_tester;
prefs_.SetBoolean(prefs::kOfferTranslateEnabled, true);
translate_manager_->GetLanguageState().LanguageDetermined("en", true);
network_notifier_.SimulateOnline();
EXPECT_EQ("hi", TranslateManager::GetTargetLanguage(
&translate_prefs_, &mock_language_model_, {"en"}));
translate_manager_->InitiateTranslation("en");
histogram_tester.ExpectUniqueSample(
kInitiationStatusName,
translate::TranslateBrowserMetrics::INITIATION_STATUS_SHOW_INFOBAR, 1);
}
TEST_F(TranslateManagerTest, DontTranslateOffline) {
TranslateManager::SetIgnoreMissingKeyForTesting(true);
translate_manager_.reset(new translate::TranslateManager(
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment