1 // Copyright (c) 2012 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 "chrome/browser/translate/translate_manager.h"
8 #include "base/command_line.h"
9 #include "base/memory/singleton.h"
10 #include "base/metrics/field_trial.h"
11 #include "base/metrics/histogram.h"
12 #include "base/prefs/pref_service.h"
13 #include "base/strings/string_split.h"
14 #include "base/strings/stringprintf.h"
15 #include "base/time/time.h"
16 #include "chrome/browser/browser_process.h"
17 #include "chrome/browser/chrome_notification_types.h"
18 #include "chrome/browser/profiles/profile.h"
19 #include "chrome/browser/tab_contents/tab_util.h"
20 #include "chrome/browser/translate/translate_tab_helper.h"
21 #include "chrome/browser/ui/browser.h"
22 #include "chrome/browser/ui/browser_finder.h"
23 #include "chrome/browser/ui/browser_tabstrip.h"
24 #include "chrome/browser/ui/tabs/tab_strip_model.h"
25 #include "chrome/common/pref_names.h"
26 #include "chrome/common/render_messages.h"
27 #include "chrome/common/url_constants.h"
28 #include "components/translate/core/browser/language_state.h"
29 #include "components/translate/core/browser/page_translated_details.h"
30 #include "components/translate/core/browser/translate_accept_languages.h"
31 #include "components/translate/core/browser/translate_browser_metrics.h"
32 #include "components/translate/core/browser/translate_download_manager.h"
33 #include "components/translate/core/browser/translate_error_details.h"
34 #include "components/translate/core/browser/translate_language_list.h"
35 #include "components/translate/core/browser/translate_prefs.h"
36 #include "components/translate/core/browser/translate_script.h"
37 #include "components/translate/core/browser/translate_url_util.h"
38 #include "components/translate/core/common/language_detection_details.h"
39 #include "components/translate/core/common/translate_constants.h"
40 #include "components/translate/core/common/translate_pref_names.h"
41 #include "components/translate/core/common/translate_switches.h"
42 #include "content/public/browser/navigation_controller.h"
43 #include "content/public/browser/navigation_details.h"
44 #include "content/public/browser/navigation_entry.h"
45 #include "content/public/browser/notification_details.h"
46 #include "content/public/browser/notification_service.h"
47 #include "content/public/browser/notification_source.h"
48 #include "content/public/browser/notification_types.h"
49 #include "content/public/browser/render_process_host.h"
50 #include "content/public/browser/render_view_host.h"
51 #include "content/public/browser/web_contents.h"
52 #include "net/base/url_util.h"
53 #include "net/http/http_status_code.h"
55 #if defined(OS_CHROMEOS)
56 #include "chrome/browser/chromeos/file_manager/app_id.h"
57 #include "extensions/common/constants.h"
60 using content::NavigationController
;
61 using content::NavigationEntry
;
62 using content::WebContents
;
66 const char kReportLanguageDetectionErrorURL
[] =
67 "https://translate.google.com/translate_error?client=cr&action=langidc";
69 // Used in kReportLanguageDetectionErrorURL to specify the original page
71 const char kSourceLanguageQueryName
[] = "sl";
73 // Used in kReportLanguageDetectionErrorURL to specify the page URL.
74 const char kUrlQueryName
[] = "u";
76 // The maximum number of attempts we'll do to see if the page has finshed
77 // loading before giving up the translation
78 const int kMaxTranslateLoadCheckAttempts
= 20;
82 TranslateManager::~TranslateManager() {
86 TranslateManager
* TranslateManager::GetInstance() {
87 return Singleton
<TranslateManager
>::get();
91 bool TranslateManager::IsTranslatableURL(const GURL
& url
) {
92 // A URLs is translatable unless it is one of the following:
93 // - empty (can happen for popups created with window.open(""))
94 // - an internal URL (chrome:// and others)
95 // - the devtools (which is considered UI)
96 // - Chrome OS file manager extension
97 // - an FTP page (as FTP pages tend to have long lists of filenames that may
99 return !url
.is_empty() &&
100 !url
.SchemeIs(content::kChromeUIScheme
) &&
101 !url
.SchemeIs(chrome::kChromeDevToolsScheme
) &&
102 #if defined(OS_CHROMEOS)
103 !(url
.SchemeIs(extensions::kExtensionScheme
) &&
104 url
.DomainIs(file_manager::kFileManagerAppId
)) &&
106 !url
.SchemeIs(content::kFtpScheme
);
109 void TranslateManager::Observe(int type
,
110 const content::NotificationSource
& source
,
111 const content::NotificationDetails
& details
) {
113 case content::NOTIFICATION_NAV_ENTRY_COMMITTED
: {
114 NavigationController
* controller
=
115 content::Source
<NavigationController
>(source
).ptr();
116 content::LoadCommittedDetails
* load_details
=
117 content::Details
<content::LoadCommittedDetails
>(details
).ptr();
118 NavigationEntry
* entry
= controller
->GetActiveEntry();
124 TranslateTabHelper
* translate_tab_helper
=
125 TranslateTabHelper::FromWebContents(controller
->GetWebContents());
126 if (!translate_tab_helper
)
129 // If the navigation happened while offline don't show the translate
130 // bar since there will be nothing to translate.
131 if (load_details
->http_status_code
== 0 ||
132 load_details
->http_status_code
== net::HTTP_INTERNAL_SERVER_ERROR
) {
136 if (!load_details
->is_main_frame
&&
137 translate_tab_helper
->GetLanguageState().translation_declined()) {
138 // Some sites (such as Google map) may trigger sub-frame navigations
139 // when the user interacts with the page. We don't want to show a new
140 // infobar if the user already dismissed one in that case.
143 if (entry
->GetTransitionType() != content::PAGE_TRANSITION_RELOAD
&&
144 load_details
->type
!= content::NAVIGATION_TYPE_SAME_PAGE
) {
148 // When doing a page reload, TAB_LANGUAGE_DETERMINED is not sent,
149 // so the translation needs to be explicitly initiated, but only when the
150 // page needs translation.
151 if (!translate_tab_helper
->GetLanguageState().page_needs_translation())
153 // Note that we delay it as the TranslateManager gets this notification
154 // before the WebContents and the WebContents processing might remove the
155 // current infobars. Since InitTranslation might add an infobar, it must
156 // be done after that.
157 base::MessageLoop::current()->PostTask(FROM_HERE
,
159 &TranslateManager::InitiateTranslationPosted
,
160 weak_method_factory_
.GetWeakPtr(),
161 controller
->GetWebContents()->GetRenderProcessHost()->GetID(),
162 controller
->GetWebContents()->GetRenderViewHost()->GetRoutingID(),
163 translate_tab_helper
->GetLanguageState().original_language(), 0));
166 case chrome::NOTIFICATION_TAB_LANGUAGE_DETERMINED
: {
167 const LanguageDetectionDetails
* lang_det_details
=
168 content::Details
<const LanguageDetectionDetails
>(details
).ptr();
170 WebContents
* tab
= content::Source
<WebContents
>(source
).ptr();
171 if (!tab
->GetBrowserContext()->IsOffTheRecord())
172 NotifyLanguageDetection(*lang_det_details
);
174 // We may get this notifications multiple times. Make sure to translate
176 TranslateTabHelper
* translate_tab_helper
=
177 TranslateTabHelper::FromWebContents(tab
);
178 if (!translate_tab_helper
)
181 LanguageState
& language_state
= translate_tab_helper
->GetLanguageState();
182 if (language_state
.page_needs_translation() &&
183 !language_state
.translation_pending() &&
184 !language_state
.translation_declined() &&
185 !language_state
.IsPageTranslated()) {
186 std::string language
= lang_det_details
->adopted_language
;
187 InitiateTranslation(tab
, language
);
191 case chrome::NOTIFICATION_PAGE_TRANSLATED
: {
192 // Only add translate infobar if it doesn't exist; if it already exists,
193 // just update the state, the actual infobar would have received the same
194 // notification and update the visual display accordingly.
195 WebContents
* tab
= content::Source
<WebContents
>(source
).ptr();
196 PageTranslatedDetails
* page_translated_details
=
197 content::Details
<PageTranslatedDetails
>(details
).ptr();
198 PageTranslated(tab
, page_translated_details
);
206 void TranslateManager::AddObserver(Observer
* obs
) {
207 observer_list_
.AddObserver(obs
);
210 void TranslateManager::RemoveObserver(Observer
* obs
) {
211 observer_list_
.RemoveObserver(obs
);
214 void TranslateManager::NotifyLanguageDetection(
215 const LanguageDetectionDetails
& details
) {
216 FOR_EACH_OBSERVER(Observer
, observer_list_
, OnLanguageDetection(details
));
219 void TranslateManager::NotifyTranslateError(
220 const TranslateErrorDetails
& details
) {
221 FOR_EACH_OBSERVER(Observer
, observer_list_
, OnTranslateError(details
));
224 TranslateManager::TranslateManager()
225 : max_reload_check_attempts_(kMaxTranslateLoadCheckAttempts
),
226 weak_method_factory_(this) {
227 notification_registrar_
.Add(this, content::NOTIFICATION_NAV_ENTRY_COMMITTED
,
228 content::NotificationService::AllSources());
229 notification_registrar_
.Add(this,
230 chrome::NOTIFICATION_TAB_LANGUAGE_DETERMINED
,
231 content::NotificationService::AllSources());
232 notification_registrar_
.Add(this, chrome::NOTIFICATION_PAGE_TRANSLATED
,
233 content::NotificationService::AllSources());
236 void TranslateManager::InitiateTranslation(WebContents
* web_contents
,
237 const std::string
& page_lang
) {
238 TranslateTabHelper
* translate_tab_helper
=
239 TranslateTabHelper::FromWebContents(web_contents
);
240 if (!translate_tab_helper
)
244 Profile::FromBrowserContext(web_contents
->GetBrowserContext());
245 Profile
* original_profile
= profile
->GetOriginalProfile();
246 PrefService
* prefs
= original_profile
->GetPrefs();
247 if (!prefs
->GetBoolean(prefs::kEnableTranslate
)) {
248 TranslateBrowserMetrics::ReportInitiationStatus(
249 TranslateBrowserMetrics::INITIATION_STATUS_DISABLED_BY_PREFS
);
250 const std::string
& locale
= g_browser_process
->GetApplicationLocale();
251 TranslateBrowserMetrics::ReportLocalesOnDisabledByPrefs(locale
);
255 // Allow disabling of translate from the command line to assist with
256 // automated browser testing.
257 if (CommandLine::ForCurrentProcess()->HasSwitch(
258 translate::switches::kDisableTranslate
)) {
259 TranslateBrowserMetrics::ReportInitiationStatus(
260 TranslateBrowserMetrics::INITIATION_STATUS_DISABLED_BY_SWITCH
);
264 // MHTML pages currently cannot be translated.
266 if (web_contents
->GetContentsMimeType() == "multipart/related") {
267 TranslateBrowserMetrics::ReportInitiationStatus(
268 TranslateBrowserMetrics::INITIATION_STATUS_MIME_TYPE_IS_NOT_SUPPORTED
);
272 // Don't translate any Chrome specific page, e.g., New Tab Page, Download,
273 // History, and so on.
274 GURL page_url
= web_contents
->GetURL();
275 if (!IsTranslatableURL(page_url
)) {
276 TranslateBrowserMetrics::ReportInitiationStatus(
277 TranslateBrowserMetrics::INITIATION_STATUS_URL_IS_NOT_SUPPORTED
);
281 std::string target_lang
= GetTargetLanguage(prefs
);
282 std::string language_code
=
283 TranslateDownloadManager::GetLanguageCode(page_lang
);
285 // Don't translate similar languages (ex: en-US to en).
286 if (language_code
== target_lang
) {
287 TranslateBrowserMetrics::ReportInitiationStatus(
288 TranslateBrowserMetrics::INITIATION_STATUS_SIMILAR_LANGUAGES
);
292 // Nothing to do if either the language Chrome is in or the language of the
293 // page is not supported by the translation server.
294 if (target_lang
.empty() ||
295 !TranslateDownloadManager::IsSupportedLanguage(language_code
)) {
296 TranslateBrowserMetrics::ReportInitiationStatus(
297 TranslateBrowserMetrics::INITIATION_STATUS_LANGUAGE_IS_NOT_SUPPORTED
);
298 TranslateBrowserMetrics::ReportUnsupportedLanguageAtInitiation(
303 scoped_ptr
<TranslatePrefs
> translate_prefs(
304 TranslateTabHelper::CreateTranslatePrefs(profile
->GetPrefs()));
306 TranslateAcceptLanguages
* accept_languages
=
307 TranslateTabHelper::GetTranslateAcceptLanguages(profile
);
308 // Don't translate any user black-listed languages.
309 if (!translate_prefs
->CanTranslateLanguage(accept_languages
,
311 TranslateBrowserMetrics::ReportInitiationStatus(
312 TranslateBrowserMetrics::INITIATION_STATUS_DISABLED_BY_CONFIG
);
316 // Don't translate any user black-listed URLs.
317 if (translate_prefs
->IsSiteBlacklisted(page_url
.HostNoBrackets())) {
318 TranslateBrowserMetrics::ReportInitiationStatus(
319 TranslateBrowserMetrics::INITIATION_STATUS_DISABLED_BY_CONFIG
);
323 // If the user has previously selected "always translate" for this language we
324 // automatically translate. Note that in incognito mode we disable that
325 // feature; the user will get an infobar, so they can control whether the
326 // page's text is sent to the translate server.
327 if (!web_contents
->GetBrowserContext()->IsOffTheRecord()) {
328 std::string auto_target_lang
= GetAutoTargetLanguage(language_code
, prefs
);
329 if (!auto_target_lang
.empty()) {
330 TranslateBrowserMetrics::ReportInitiationStatus(
331 TranslateBrowserMetrics::INITIATION_STATUS_AUTO_BY_CONFIG
);
332 TranslatePage(web_contents
, language_code
, auto_target_lang
);
337 LanguageState
& language_state
= translate_tab_helper
->GetLanguageState();
338 std::string auto_translate_to
= language_state
.AutoTranslateTo();
339 if (!auto_translate_to
.empty()) {
340 // This page was navigated through a click from a translated page.
341 TranslateBrowserMetrics::ReportInitiationStatus(
342 TranslateBrowserMetrics::INITIATION_STATUS_AUTO_BY_LINK
);
343 TranslatePage(web_contents
, language_code
, auto_translate_to
);
347 TranslateBrowserMetrics::ReportInitiationStatus(
348 TranslateBrowserMetrics::INITIATION_STATUS_SHOW_INFOBAR
);
350 // Prompts the user if he/she wants the page translated.
351 translate_tab_helper
->ShowTranslateUI(TranslateTabHelper::BEFORE_TRANSLATE
,
355 TranslateErrors::NONE
);
358 void TranslateManager::InitiateTranslationPosted(int process_id
,
360 const std::string
& page_lang
,
362 // The tab might have been closed.
363 WebContents
* web_contents
=
364 tab_util::GetWebContentsByID(process_id
, render_id
);
368 TranslateTabHelper
* translate_tab_helper
=
369 TranslateTabHelper::FromWebContents(web_contents
);
370 if (translate_tab_helper
->GetLanguageState().translation_pending())
373 // During a reload we need web content to be available before the
374 // translate script is executed. Otherwise we will run the translate script on
375 // an empty DOM which will fail. Therefore we wait a bit to see if the page
377 if ((web_contents
->IsLoading()) && attempt
< kMaxTranslateLoadCheckAttempts
) {
378 int backoff
= attempt
* max_reload_check_attempts_
;
379 base::MessageLoop::current()->PostDelayedTask(
380 FROM_HERE
, base::Bind(&TranslateManager::InitiateTranslationPosted
,
381 weak_method_factory_
.GetWeakPtr(), process_id
,
382 render_id
, page_lang
, ++attempt
),
383 base::TimeDelta::FromMilliseconds(backoff
));
387 InitiateTranslation(web_contents
,
388 TranslateDownloadManager::GetLanguageCode(page_lang
));
391 void TranslateManager::TranslatePage(WebContents
* web_contents
,
392 const std::string
& original_source_lang
,
393 const std::string
& target_lang
) {
394 NavigationEntry
* entry
= web_contents
->GetController().GetActiveEntry();
400 // Translation can be kicked by context menu against unsupported languages.
401 // Unsupported language strings should be replaced with
402 // kUnknownLanguageCode in order to send a translation request with enabling
403 // server side auto language detection.
404 std::string
source_lang(original_source_lang
);
405 if (!TranslateDownloadManager::IsSupportedLanguage(source_lang
))
406 source_lang
= std::string(translate::kUnknownLanguageCode
);
408 TranslateTabHelper
* translate_tab_helper
=
409 TranslateTabHelper::FromWebContents(web_contents
);
410 DCHECK(translate_tab_helper
);
411 translate_tab_helper
->ShowTranslateUI(TranslateTabHelper::TRANSLATING
,
415 TranslateErrors::NONE
);
417 TranslateScript
* script
= TranslateDownloadManager::GetInstance()->script();
418 DCHECK(script
!= NULL
);
420 const std::string
& script_data
= script
->data();
421 if (!script_data
.empty()) {
422 DoTranslatePage(web_contents
, script_data
, source_lang
, target_lang
);
426 // The script is not available yet. Queue that request and query for the
427 // script. Once it is downloaded we'll do the translate.
428 content::RenderViewHost
* rvh
= web_contents
->GetRenderViewHost();
429 PendingRequest request
;
430 request
.render_process_id
= rvh
->GetProcess()->GetID();
431 request
.render_view_id
= rvh
->GetRoutingID();
432 request
.page_id
= entry
->GetPageID();
433 request
.source_lang
= source_lang
;
434 request
.target_lang
= target_lang
;
435 pending_requests_
.push_back(request
);
437 if (script
->HasPendingRequest())
440 script
->Request(base::Bind(&TranslateManager::OnTranslateScriptFetchComplete
,
441 base::Unretained(this)));
444 void TranslateManager::RevertTranslation(WebContents
* web_contents
) {
445 NavigationEntry
* entry
= web_contents
->GetController().GetActiveEntry();
450 web_contents
->GetRenderViewHost()->Send(new ChromeViewMsg_RevertTranslation(
451 web_contents
->GetRenderViewHost()->GetRoutingID(), entry
->GetPageID()));
453 TranslateTabHelper
* translate_tab_helper
=
454 TranslateTabHelper::FromWebContents(web_contents
);
455 translate_tab_helper
->GetLanguageState().SetCurrentLanguage(
456 translate_tab_helper
->GetLanguageState().original_language());
459 void TranslateManager::ReportLanguageDetectionError(WebContents
* web_contents
) {
460 TranslateBrowserMetrics::ReportLanguageDetectionError();
461 // We'll open the URL in a new tab so that the user can tell us more.
462 Browser
* browser
= chrome::FindBrowserWithWebContents(web_contents
);
468 GURL report_error_url
= GURL(kReportLanguageDetectionErrorURL
);
470 GURL page_url
= web_contents
->GetController().GetActiveEntry()->GetURL();
471 report_error_url
= net::AppendQueryParameter(
476 TranslateTabHelper
* translate_tab_helper
=
477 TranslateTabHelper::FromWebContents(web_contents
);
478 report_error_url
= net::AppendQueryParameter(
480 kSourceLanguageQueryName
,
481 translate_tab_helper
->GetLanguageState().original_language());
483 report_error_url
= TranslateURLUtil::AddHostLocaleToUrl(report_error_url
);
484 report_error_url
= TranslateURLUtil::AddApiKeyToUrl(report_error_url
);
486 chrome::AddSelectedTabWithURL(browser
, report_error_url
,
487 content::PAGE_TRANSITION_AUTO_BOOKMARK
);
490 void TranslateManager::DoTranslatePage(WebContents
* web_contents
,
491 const std::string
& translate_script
,
492 const std::string
& source_lang
,
493 const std::string
& target_lang
) {
494 NavigationEntry
* entry
= web_contents
->GetController().GetActiveEntry();
500 TranslateTabHelper
* translate_tab_helper
=
501 TranslateTabHelper::FromWebContents(web_contents
);
502 if (!translate_tab_helper
)
505 translate_tab_helper
->GetLanguageState().set_translation_pending(true);
506 web_contents
->GetRenderViewHost()->Send(new ChromeViewMsg_TranslatePage(
507 web_contents
->GetRenderViewHost()->GetRoutingID(), entry
->GetPageID(),
508 translate_script
, source_lang
, target_lang
));
511 void TranslateManager::PageTranslated(WebContents
* web_contents
,
512 PageTranslatedDetails
* details
) {
513 if ((details
->error_type
== TranslateErrors::NONE
) &&
514 details
->source_language
!= translate::kUnknownLanguageCode
&&
515 !TranslateDownloadManager::IsSupportedLanguage(
516 details
->source_language
)) {
517 details
->error_type
= TranslateErrors::UNSUPPORTED_LANGUAGE
;
520 TranslateTabHelper
* translate_tab_helper
=
521 TranslateTabHelper::FromWebContents(web_contents
);
522 DCHECK(translate_tab_helper
);
523 translate_tab_helper
->ShowTranslateUI(TranslateTabHelper::AFTER_TRANSLATE
,
525 details
->source_language
,
526 details
->target_language
,
527 details
->error_type
);
529 if (details
->error_type
!= TranslateErrors::NONE
&&
530 !web_contents
->GetBrowserContext()->IsOffTheRecord()) {
531 TranslateErrorDetails error_details
;
532 error_details
.time
= base::Time::Now();
533 error_details
.url
= web_contents
->GetLastCommittedURL();
534 error_details
.error
= details
->error_type
;
535 NotifyTranslateError(error_details
);
539 void TranslateManager::OnTranslateScriptFetchComplete(
540 bool success
, const std::string
& data
) {
541 std::vector
<PendingRequest
>::const_iterator iter
;
542 for (iter
= pending_requests_
.begin(); iter
!= pending_requests_
.end();
544 const PendingRequest
& request
= *iter
;
545 WebContents
* web_contents
=
546 tab_util::GetWebContentsByID(request
.render_process_id
,
547 request
.render_view_id
);
549 // The tab went away while we were retrieving the script.
552 NavigationEntry
* entry
= web_contents
->GetController().GetActiveEntry();
553 if (!entry
|| entry
->GetPageID() != request
.page_id
) {
554 // We navigated away from the page the translation was triggered on.
559 // Translate the page.
560 TranslateScript
* translate_script
=
561 TranslateDownloadManager::GetInstance()->script();
562 DCHECK(translate_script
);
563 DoTranslatePage(web_contents
, translate_script
->data(),
564 request
.source_lang
, request
.target_lang
);
566 TranslateTabHelper
* translate_tab_helper
=
567 TranslateTabHelper::FromWebContents(web_contents
);
568 DCHECK(translate_tab_helper
);
569 translate_tab_helper
->ShowTranslateUI(TranslateTabHelper::TRANSLATE_ERROR
,
573 TranslateErrors::NETWORK
);
575 if (!web_contents
->GetBrowserContext()->IsOffTheRecord()) {
576 TranslateErrorDetails error_details
;
577 error_details
.time
= base::Time::Now();
578 error_details
.url
= entry
->GetURL();
579 error_details
.error
= TranslateErrors::NETWORK
;
580 NotifyTranslateError(error_details
);
584 pending_requests_
.clear();
588 std::string
TranslateManager::GetTargetLanguage(PrefService
* prefs
) {
589 std::string ui_lang
= TranslatePrefs::ConvertLangCodeForTranslation(
590 TranslateDownloadManager::GetLanguageCode(
591 g_browser_process
->GetApplicationLocale()));
593 if (TranslateDownloadManager::IsSupportedLanguage(ui_lang
))
596 // Getting the accepted languages list
597 std::string accept_langs_str
= prefs
->GetString(prefs::kAcceptLanguages
);
599 std::vector
<std::string
> accept_langs_list
;
600 base::SplitString(accept_langs_str
, ',', &accept_langs_list
);
602 // Will translate to the first supported language on the Accepted Language
603 // list or not at all if no such candidate exists
604 std::vector
<std::string
>::iterator iter
;
605 for (iter
= accept_langs_list
.begin();
606 iter
!= accept_langs_list
.end(); ++iter
) {
607 std::string lang_code
= TranslateDownloadManager::GetLanguageCode(*iter
);
608 if (TranslateDownloadManager::IsSupportedLanguage(lang_code
))
611 return std::string();
615 std::string
TranslateManager::GetAutoTargetLanguage(
616 const std::string
& original_language
,
617 PrefService
* prefs
) {
618 std::string auto_target_lang
;
619 scoped_ptr
<TranslatePrefs
> translate_prefs(
620 TranslateTabHelper::CreateTranslatePrefs(prefs
));
621 if (translate_prefs
->ShouldAutoTranslate(original_language
,
622 &auto_target_lang
)) {
623 // We need to confirm that the saved target language is still supported.
624 // Also, GetLanguageCode will take care of removing country code if any.
626 TranslateDownloadManager::GetLanguageCode(auto_target_lang
);
627 if (TranslateDownloadManager::IsSupportedLanguage(auto_target_lang
))
628 return auto_target_lang
;
630 return std::string();