[Cleanup] Fix pronouns in comments.
[chromium-blink-merge.git] / components / translate / core / browser / translate_manager.cc
blobe97fd49fe99ebad094ebf296b42890aa0f1cf43e
1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "components/translate/core/browser/translate_manager.h"
7 #include "base/bind.h"
8 #include "base/command_line.h"
9 #include "base/metrics/field_trial.h"
10 #include "base/metrics/histogram.h"
11 #include "base/prefs/pref_service.h"
12 #include "base/strings/string_split.h"
13 #include "base/strings/stringprintf.h"
14 #include "base/time/time.h"
15 #include "components/translate/core/browser/language_state.h"
16 #include "components/translate/core/browser/page_translated_details.h"
17 #include "components/translate/core/browser/translate_accept_languages.h"
18 #include "components/translate/core/browser/translate_browser_metrics.h"
19 #include "components/translate/core/browser/translate_client.h"
20 #include "components/translate/core/browser/translate_download_manager.h"
21 #include "components/translate/core/browser/translate_driver.h"
22 #include "components/translate/core/browser/translate_error_details.h"
23 #include "components/translate/core/browser/translate_language_list.h"
24 #include "components/translate/core/browser/translate_prefs.h"
25 #include "components/translate/core/browser/translate_script.h"
26 #include "components/translate/core/browser/translate_url_util.h"
27 #include "components/translate/core/common/language_detection_details.h"
28 #include "components/translate/core/common/translate_constants.h"
29 #include "components/translate/core/common/translate_pref_names.h"
30 #include "components/translate/core/common/translate_switches.h"
31 #include "components/translate/core/common/translate_util.h"
32 #include "net/base/url_util.h"
33 #include "net/http/http_status_code.h"
35 namespace translate {
37 namespace {
39 // Callbacks for translate errors.
40 TranslateManager::TranslateErrorCallbackList* g_callback_list_ = NULL;
42 const char kReportLanguageDetectionErrorURL[] =
43 "https://translate.google.com/translate_error?client=cr&action=langidc";
45 // Used in kReportLanguageDetectionErrorURL to specify the original page
46 // language.
47 const char kSourceLanguageQueryName[] = "sl";
49 // Used in kReportLanguageDetectionErrorURL to specify the page URL.
50 const char kUrlQueryName[] = "u";
52 // Notifies |g_callback_list_| of translate errors.
53 void NotifyTranslateError(const TranslateErrorDetails& details) {
54 if (!g_callback_list_)
55 return;
57 g_callback_list_->Notify(details);
60 } // namespace
62 TranslateManager::~TranslateManager() {}
64 // static
65 scoped_ptr<TranslateManager::TranslateErrorCallbackList::Subscription>
66 TranslateManager::RegisterTranslateErrorCallback(
67 const TranslateManager::TranslateErrorCallback& callback) {
68 if (!g_callback_list_)
69 g_callback_list_ = new TranslateErrorCallbackList;
70 return g_callback_list_->Add(callback);
73 TranslateManager::TranslateManager(
74 TranslateClient* translate_client,
75 const std::string& accept_languages_pref_name)
76 : page_seq_no_(0),
77 accept_languages_pref_name_(accept_languages_pref_name),
78 translate_client_(translate_client),
79 translate_driver_(translate_client_->GetTranslateDriver()),
80 language_state_(translate_driver_),
81 weak_method_factory_(this) {
84 base::WeakPtr<TranslateManager> TranslateManager::GetWeakPtr() {
85 return weak_method_factory_.GetWeakPtr();
88 void TranslateManager::InitiateTranslation(const std::string& page_lang) {
89 // Short-circuit out if not in a state where initiating translation makes
90 // sense (this method may be called muhtiple times for a given page).
91 if (!language_state_.page_needs_translation() ||
92 language_state_.translation_pending() ||
93 language_state_.translation_declined() ||
94 language_state_.IsPageTranslated()) {
95 return;
98 PrefService* prefs = translate_client_->GetPrefs();
99 if (!prefs->GetBoolean(prefs::kEnableTranslate)) {
100 TranslateBrowserMetrics::ReportInitiationStatus(
101 TranslateBrowserMetrics::INITIATION_STATUS_DISABLED_BY_PREFS);
102 const std::string& locale =
103 TranslateDownloadManager::GetInstance()->application_locale();
104 TranslateBrowserMetrics::ReportLocalesOnDisabledByPrefs(locale);
105 return;
108 // Allow disabling of translate from the command line to assist with
109 // automated browser testing.
110 if (base::CommandLine::ForCurrentProcess()->HasSwitch(
111 translate::switches::kDisableTranslate)) {
112 TranslateBrowserMetrics::ReportInitiationStatus(
113 TranslateBrowserMetrics::INITIATION_STATUS_DISABLED_BY_SWITCH);
114 return;
117 // MHTML pages currently cannot be translated.
118 // See bug: 217945.
119 if (translate_driver_->GetContentsMimeType() == "multipart/related") {
120 TranslateBrowserMetrics::ReportInitiationStatus(
121 TranslateBrowserMetrics::INITIATION_STATUS_MIME_TYPE_IS_NOT_SUPPORTED);
122 return;
125 // Don't translate any Chrome specific page, e.g., New Tab Page, Download,
126 // History, and so on.
127 const GURL& page_url = translate_driver_->GetVisibleURL();
128 if (!translate_client_->IsTranslatableURL(page_url)) {
129 TranslateBrowserMetrics::ReportInitiationStatus(
130 TranslateBrowserMetrics::INITIATION_STATUS_URL_IS_NOT_SUPPORTED);
131 return;
134 // Get the accepted languages list.
135 std::vector<std::string> accept_languages_list;
136 base::SplitString(prefs->GetString(accept_languages_pref_name_.c_str()), ',',
137 &accept_languages_list);
139 std::string target_lang = GetTargetLanguage(accept_languages_list);
140 std::string language_code =
141 TranslateDownloadManager::GetLanguageCode(page_lang);
143 // Don't translate similar languages (ex: en-US to en).
144 if (language_code == target_lang) {
145 TranslateBrowserMetrics::ReportInitiationStatus(
146 TranslateBrowserMetrics::INITIATION_STATUS_SIMILAR_LANGUAGES);
147 return;
150 // Nothing to do if either the language Chrome is in or the language of the
151 // page is not supported by the translation server.
152 if (target_lang.empty() ||
153 !TranslateDownloadManager::IsSupportedLanguage(language_code)) {
154 TranslateBrowserMetrics::ReportInitiationStatus(
155 TranslateBrowserMetrics::INITIATION_STATUS_LANGUAGE_IS_NOT_SUPPORTED);
156 TranslateBrowserMetrics::ReportUnsupportedLanguageAtInitiation(
157 language_code);
158 return;
161 scoped_ptr<TranslatePrefs> translate_prefs(
162 translate_client_->GetTranslatePrefs());
164 TranslateAcceptLanguages* accept_languages =
165 translate_client_->GetTranslateAcceptLanguages();
166 // Don't translate any user black-listed languages.
167 if (!translate_prefs->CanTranslateLanguage(accept_languages,
168 language_code)) {
169 TranslateBrowserMetrics::ReportInitiationStatus(
170 TranslateBrowserMetrics::INITIATION_STATUS_DISABLED_BY_CONFIG);
171 return;
174 // Don't translate any user black-listed URLs.
175 if (translate_prefs->IsSiteBlacklisted(page_url.HostNoBrackets())) {
176 TranslateBrowserMetrics::ReportInitiationStatus(
177 TranslateBrowserMetrics::INITIATION_STATUS_DISABLED_BY_CONFIG);
178 return;
181 // If the user has previously selected "always translate" for this language we
182 // automatically translate. Note that in incognito mode we disable that
183 // feature; the user will get an infobar, so they can control whether the
184 // page's text is sent to the translate server.
185 if (!translate_driver_->IsOffTheRecord()) {
186 scoped_ptr<TranslatePrefs> translate_prefs =
187 translate_client_->GetTranslatePrefs();
188 std::string auto_target_lang =
189 GetAutoTargetLanguage(language_code, translate_prefs.get());
190 if (!auto_target_lang.empty()) {
191 TranslateBrowserMetrics::ReportInitiationStatus(
192 TranslateBrowserMetrics::INITIATION_STATUS_AUTO_BY_CONFIG);
193 TranslatePage(language_code, auto_target_lang, false);
194 return;
198 std::string auto_translate_to = language_state_.AutoTranslateTo();
199 if (!auto_translate_to.empty()) {
200 // This page was navigated through a click from a translated page.
201 TranslateBrowserMetrics::ReportInitiationStatus(
202 TranslateBrowserMetrics::INITIATION_STATUS_AUTO_BY_LINK);
203 TranslatePage(language_code, auto_translate_to, false);
204 return;
207 TranslateBrowserMetrics::ReportInitiationStatus(
208 TranslateBrowserMetrics::INITIATION_STATUS_SHOW_INFOBAR);
210 // Prompts the user if they want the page translated.
211 translate_client_->ShowTranslateUI(translate::TRANSLATE_STEP_BEFORE_TRANSLATE,
212 language_code,
213 target_lang,
214 TranslateErrors::NONE,
215 false);
218 void TranslateManager::TranslatePage(const std::string& original_source_lang,
219 const std::string& target_lang,
220 bool triggered_from_menu) {
221 if (!translate_driver_->HasCurrentPage()) {
222 NOTREACHED();
223 return;
226 // Translation can be kicked by context menu against unsupported languages.
227 // Unsupported language strings should be replaced with
228 // kUnknownLanguageCode in order to send a translation request with enabling
229 // server side auto language detection.
230 std::string source_lang(original_source_lang);
231 if (!TranslateDownloadManager::IsSupportedLanguage(source_lang))
232 source_lang = std::string(translate::kUnknownLanguageCode);
234 translate_client_->ShowTranslateUI(translate::TRANSLATE_STEP_TRANSLATING,
235 source_lang,
236 target_lang,
237 TranslateErrors::NONE,
238 triggered_from_menu);
240 TranslateScript* script = TranslateDownloadManager::GetInstance()->script();
241 DCHECK(script != NULL);
243 const std::string& script_data = script->data();
244 if (!script_data.empty()) {
245 DoTranslatePage(script_data, source_lang, target_lang);
246 return;
249 // The script is not available yet. Queue that request and query for the
250 // script. Once it is downloaded we'll do the translate.
251 TranslateScript::RequestCallback callback = base::Bind(
252 &TranslateManager::OnTranslateScriptFetchComplete, GetWeakPtr(),
253 source_lang, target_lang);
255 script->Request(callback);
258 void TranslateManager::RevertTranslation() {
259 translate_driver_->RevertTranslation(page_seq_no_);
260 language_state_.SetCurrentLanguage(language_state_.original_language());
263 void TranslateManager::ReportLanguageDetectionError() {
264 TranslateBrowserMetrics::ReportLanguageDetectionError();
266 GURL report_error_url = GURL(kReportLanguageDetectionErrorURL);
268 report_error_url =
269 net::AppendQueryParameter(report_error_url,
270 kUrlQueryName,
271 translate_driver_->GetActiveURL().spec());
273 report_error_url =
274 net::AppendQueryParameter(report_error_url,
275 kSourceLanguageQueryName,
276 language_state_.original_language());
278 report_error_url = translate::AddHostLocaleToUrl(report_error_url);
279 report_error_url = translate::AddApiKeyToUrl(report_error_url);
281 translate_client_->ShowReportLanguageDetectionErrorUI(report_error_url);
284 void TranslateManager::DoTranslatePage(const std::string& translate_script,
285 const std::string& source_lang,
286 const std::string& target_lang) {
287 language_state_.set_translation_pending(true);
288 translate_driver_->TranslatePage(
289 page_seq_no_, translate_script, source_lang, target_lang);
292 void TranslateManager::PageTranslated(const std::string& source_lang,
293 const std::string& target_lang,
294 TranslateErrors::Type error_type) {
295 language_state_.SetCurrentLanguage(target_lang);
296 language_state_.set_translation_pending(false);
298 if ((error_type == TranslateErrors::NONE) &&
299 source_lang != translate::kUnknownLanguageCode &&
300 !TranslateDownloadManager::IsSupportedLanguage(source_lang)) {
301 error_type = TranslateErrors::UNSUPPORTED_LANGUAGE;
304 translate_client_->ShowTranslateUI(translate::TRANSLATE_STEP_AFTER_TRANSLATE,
305 source_lang,
306 target_lang,
307 error_type,
308 false);
310 if (error_type != TranslateErrors::NONE &&
311 !translate_driver_->IsOffTheRecord()) {
312 TranslateErrorDetails error_details;
313 error_details.time = base::Time::Now();
314 error_details.url = translate_driver_->GetLastCommittedURL();
315 error_details.error = error_type;
316 NotifyTranslateError(error_details);
320 void TranslateManager::OnTranslateScriptFetchComplete(
321 const std::string& source_lang,
322 const std::string& target_lang,
323 bool success,
324 const std::string& data) {
325 if (!translate_driver_->HasCurrentPage())
326 return;
328 if (success) {
329 // Translate the page.
330 TranslateScript* translate_script =
331 TranslateDownloadManager::GetInstance()->script();
332 DCHECK(translate_script);
333 DoTranslatePage(translate_script->data(), source_lang, target_lang);
334 } else {
335 translate_client_->ShowTranslateUI(
336 translate::TRANSLATE_STEP_TRANSLATE_ERROR,
337 source_lang,
338 target_lang,
339 TranslateErrors::NETWORK,
340 false);
341 if (!translate_driver_->IsOffTheRecord()) {
342 TranslateErrorDetails error_details;
343 error_details.time = base::Time::Now();
344 error_details.url = translate_driver_->GetActiveURL();
345 error_details.error = TranslateErrors::NETWORK;
346 NotifyTranslateError(error_details);
351 // static
352 std::string TranslateManager::GetTargetLanguage(
353 const std::vector<std::string>& accept_languages_list) {
354 std::string ui_lang = TranslateDownloadManager::GetLanguageCode(
355 TranslateDownloadManager::GetInstance()->application_locale());
356 translate::ToTranslateLanguageSynonym(&ui_lang);
358 if (TranslateDownloadManager::IsSupportedLanguage(ui_lang))
359 return ui_lang;
361 // Will translate to the first supported language on the Accepted Language
362 // list or not at all if no such candidate exists
363 std::vector<std::string>::const_iterator iter;
364 for (iter = accept_languages_list.begin();
365 iter != accept_languages_list.end(); ++iter) {
366 std::string lang_code = TranslateDownloadManager::GetLanguageCode(*iter);
367 if (TranslateDownloadManager::IsSupportedLanguage(lang_code))
368 return lang_code;
370 return std::string();
373 // static
374 std::string TranslateManager::GetAutoTargetLanguage(
375 const std::string& original_language,
376 TranslatePrefs* translate_prefs) {
377 std::string auto_target_lang;
378 if (translate_prefs->ShouldAutoTranslate(original_language,
379 &auto_target_lang)) {
380 // We need to confirm that the saved target language is still supported.
381 // Also, GetLanguageCode will take care of removing country code if any.
382 auto_target_lang =
383 TranslateDownloadManager::GetLanguageCode(auto_target_lang);
384 if (TranslateDownloadManager::IsSupportedLanguage(auto_target_lang))
385 return auto_target_lang;
387 return std::string();
390 LanguageState& TranslateManager::GetLanguageState() {
391 return language_state_;
394 } // namespace translate