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 "chrome/browser/translate/chrome_translate_client.h"
9 #include "base/logging.h"
10 #include "base/path_service.h"
11 #include "base/prefs/pref_service.h"
12 #include "base/strings/string_split.h"
13 #include "chrome/browser/chrome_notification_types.h"
14 #include "chrome/browser/infobars/infobar_service.h"
15 #include "chrome/browser/profiles/profile.h"
16 #include "chrome/browser/translate/translate_accept_languages_factory.h"
17 #include "chrome/browser/translate/translate_service.h"
18 #include "chrome/browser/ui/browser.h"
19 #include "chrome/browser/ui/browser_finder.h"
20 #include "chrome/browser/ui/browser_tabstrip.h"
21 #include "chrome/browser/ui/browser_window.h"
22 #include "chrome/browser/ui/tabs/tab_strip_model.h"
23 #include "chrome/browser/ui/translate/translate_bubble_factory.h"
24 #include "chrome/common/chrome_paths.h"
25 #include "chrome/common/pref_names.h"
26 #include "components/infobars/core/infobar.h"
27 #include "components/translate/content/browser/browser_cld_data_provider_factory.h"
28 #include "components/translate/content/common/cld_data_source.h"
29 #include "components/translate/content/common/translate_messages.h"
30 #include "components/translate/core/browser/language_state.h"
31 #include "components/translate/core/browser/page_translated_details.h"
32 #include "components/translate/core/browser/translate_accept_languages.h"
33 #include "components/translate/core/browser/translate_download_manager.h"
34 #include "components/translate/core/browser/translate_infobar_delegate.h"
35 #include "components/translate/core/browser/translate_manager.h"
36 #include "components/translate/core/browser/translate_prefs.h"
37 #include "components/translate/core/common/language_detection_details.h"
38 #include "content/public/browser/notification_service.h"
39 #include "content/public/browser/render_view_host.h"
40 #include "content/public/browser/web_contents.h"
41 #include "grit/theme_resources.h"
46 // TODO(andrewhayden): Make the data file path into a gyp/gn define
47 // If you change this, also update standalone_cld_data_harness.cc
49 const base::FilePath::CharType kCldDataFileName
[] =
50 FILE_PATH_LITERAL("cld2_data.bin");
52 bool g_cld_file_path_initialized_
= false;
56 DEFINE_WEB_CONTENTS_USER_DATA_KEY(ChromeTranslateClient
);
58 ChromeTranslateClient::ChromeTranslateClient(content::WebContents
* web_contents
)
59 : content::WebContentsObserver(web_contents
),
60 translate_driver_(&web_contents
->GetController()),
62 new translate::TranslateManager(this, prefs::kAcceptLanguages
)),
64 translate::BrowserCldDataProviderFactory::Get()->
65 CreateBrowserCldDataProvider(web_contents
)) {
66 translate_driver_
.AddObserver(this);
67 translate_driver_
.set_translate_manager(translate_manager_
.get());
68 // Customization: for the standalone data source, we configure the path to
69 // CLD data immediately on startup.
70 if (translate::CldDataSource::IsUsingStandaloneDataSource() &&
71 !g_cld_file_path_initialized_
) {
72 DVLOG(1) << "Initializing CLD file path for the first time.";
74 if (!PathService::Get(chrome::DIR_USER_DATA
, &path
)) {
75 // Chrome isn't properly installed
76 LOG(WARNING
) << "Unable to locate user data directory";
78 g_cld_file_path_initialized_
= true;
79 path
= path
.Append(kCldDataFileName
);
80 DVLOG(1) << "Setting CLD data file path: " << path
.value();
81 translate::CldDataSource::Get()->SetCldDataFilePath(path
);
86 ChromeTranslateClient::~ChromeTranslateClient() {
87 translate_driver_
.RemoveObserver(this);
90 translate::LanguageState
& ChromeTranslateClient::GetLanguageState() {
91 return translate_manager_
->GetLanguageState();
95 scoped_ptr
<translate::TranslatePrefs
>
96 ChromeTranslateClient::CreateTranslatePrefs(PrefService
* prefs
) {
97 #if defined(OS_CHROMEOS)
98 const char* preferred_languages_prefs
= prefs::kLanguagePreferredLanguages
;
100 const char* preferred_languages_prefs
= NULL
;
102 return scoped_ptr
<translate::TranslatePrefs
>(new translate::TranslatePrefs(
103 prefs
, prefs::kAcceptLanguages
, preferred_languages_prefs
));
107 translate::TranslateAcceptLanguages
*
108 ChromeTranslateClient::GetTranslateAcceptLanguages(
109 content::BrowserContext
* browser_context
) {
110 return TranslateAcceptLanguagesFactory::GetForBrowserContext(browser_context
);
114 translate::TranslateManager
* ChromeTranslateClient::GetManagerFromWebContents(
115 content::WebContents
* web_contents
) {
116 ChromeTranslateClient
* chrome_translate_client
=
117 FromWebContents(web_contents
);
118 if (!chrome_translate_client
)
120 return chrome_translate_client
->GetTranslateManager();
124 void ChromeTranslateClient::GetTranslateLanguages(
125 content::WebContents
* web_contents
,
127 std::string
* target
) {
128 DCHECK(source
!= NULL
);
129 DCHECK(target
!= NULL
);
131 ChromeTranslateClient
* chrome_translate_client
=
132 FromWebContents(web_contents
);
133 if (!chrome_translate_client
)
136 *source
= translate::TranslateDownloadManager::GetLanguageCode(
137 chrome_translate_client
->GetLanguageState().original_language());
140 Profile::FromBrowserContext(web_contents
->GetBrowserContext());
141 Profile
* original_profile
= profile
->GetOriginalProfile();
142 PrefService
* prefs
= original_profile
->GetPrefs();
143 scoped_ptr
<translate::TranslatePrefs
> translate_prefs
=
144 CreateTranslatePrefs(prefs
);
145 if (!web_contents
->GetBrowserContext()->IsOffTheRecord()) {
146 std::string auto_translate_language
=
147 translate::TranslateManager::GetAutoTargetLanguage(
148 *source
, translate_prefs
.get());
149 if (!auto_translate_language
.empty()) {
150 *target
= auto_translate_language
;
155 std::string accept_languages_str
= prefs
->GetString(prefs::kAcceptLanguages
);
156 std::vector
<std::string
> accept_languages_list
;
157 base::SplitString(accept_languages_str
, ',', &accept_languages_list
);
159 translate::TranslateManager::GetTargetLanguage(accept_languages_list
);
162 translate::TranslateManager
* ChromeTranslateClient::GetTranslateManager() {
163 return translate_manager_
.get();
166 void ChromeTranslateClient::ShowTranslateUI(
167 translate::TranslateStep step
,
168 const std::string source_language
,
169 const std::string target_language
,
170 translate::TranslateErrors::Type error_type
,
171 bool triggered_from_menu
) {
172 DCHECK(web_contents());
173 if (error_type
!= translate::TranslateErrors::NONE
)
174 step
= translate::TRANSLATE_STEP_TRANSLATE_ERROR
;
176 if (TranslateService::IsTranslateBubbleEnabled()) {
178 if (step
== translate::TRANSLATE_STEP_BEFORE_TRANSLATE
) {
179 // TODO(droger): Move this logic out of UI code.
180 GetLanguageState().SetTranslateEnabled(true);
181 if (!GetLanguageState().HasLanguageChanged())
184 if (!triggered_from_menu
) {
185 if (web_contents()->GetBrowserContext()->IsOffTheRecord())
187 if (GetTranslatePrefs()->IsTooOftenDenied())
191 ShowBubble(step
, error_type
);
196 translate::TranslateInfoBarDelegate::Create(
197 step
!= translate::TRANSLATE_STEP_BEFORE_TRANSLATE
,
198 translate_manager_
->GetWeakPtr(),
199 InfoBarService::FromWebContents(web_contents()),
200 web_contents()->GetBrowserContext()->IsOffTheRecord(),
205 triggered_from_menu
);
208 translate::TranslateDriver
* ChromeTranslateClient::GetTranslateDriver() {
209 return &translate_driver_
;
212 PrefService
* ChromeTranslateClient::GetPrefs() {
213 DCHECK(web_contents());
215 Profile::FromBrowserContext(web_contents()->GetBrowserContext());
216 return profile
->GetOriginalProfile()->GetPrefs();
219 scoped_ptr
<translate::TranslatePrefs
>
220 ChromeTranslateClient::GetTranslatePrefs() {
221 DCHECK(web_contents());
223 Profile::FromBrowserContext(web_contents()->GetBrowserContext());
224 return CreateTranslatePrefs(profile
->GetPrefs());
227 translate::TranslateAcceptLanguages
*
228 ChromeTranslateClient::GetTranslateAcceptLanguages() {
229 DCHECK(web_contents());
230 return GetTranslateAcceptLanguages(web_contents()->GetBrowserContext());
233 int ChromeTranslateClient::GetInfobarIconID() const {
234 return IDR_INFOBAR_TRANSLATE
;
237 // ChromeTranslateClient::CreateInfoBar() is implemented in platform-specific
238 // files, except the TOOLKIT_VIEWS implementation, which has been removed. Note
239 // for Mac, Cocoa is still providing the infobar in a toolkit-views build.
240 #if defined(TOOLKIT_VIEWS) && !defined(OS_MACOSX)
241 scoped_ptr
<infobars::InfoBar
> ChromeTranslateClient::CreateInfoBar(
242 scoped_ptr
<translate::TranslateInfoBarDelegate
> delegate
) const {
243 return scoped_ptr
<infobars::InfoBar
>();
247 bool ChromeTranslateClient::IsTranslatableURL(const GURL
& url
) {
248 return TranslateService::IsTranslatableURL(url
);
251 void ChromeTranslateClient::ShowReportLanguageDetectionErrorUI(
252 const GURL
& report_url
) {
253 #if defined(OS_ANDROID)
254 // Android does not support reporting language detection errors.
257 // We'll open the URL in a new tab so that the user can tell us more.
258 Browser
* browser
= chrome::FindBrowserWithWebContents(web_contents());
264 chrome::AddSelectedTabWithURL(
265 browser
, report_url
, ui::PAGE_TRANSITION_AUTO_BOOKMARK
);
266 #endif // defined(OS_ANDROID)
269 bool ChromeTranslateClient::OnMessageReceived(const IPC::Message
& message
) {
270 return cld_data_provider_
->OnMessageReceived(message
);
273 void ChromeTranslateClient::WebContentsDestroyed() {
274 // Translation process can be interrupted.
275 // Destroying the TranslateManager now guarantees that it never has to deal
276 // with NULL WebContents.
277 translate_manager_
.reset();
280 // ContentTranslateDriver::Observer implementation.
282 void ChromeTranslateClient::OnLanguageDetermined(
283 const translate::LanguageDetectionDetails
& details
) {
284 // TODO: Remove translate notifications and have the clients be
285 // ContentTranslateDriver::Observer directly instead.
286 content::NotificationService::current()->Notify(
287 chrome::NOTIFICATION_TAB_LANGUAGE_DETERMINED
,
288 content::Source
<content::WebContents
>(web_contents()),
289 content::Details
<const translate::LanguageDetectionDetails
>(&details
));
292 void ChromeTranslateClient::OnPageTranslated(
293 const std::string
& original_lang
,
294 const std::string
& translated_lang
,
295 translate::TranslateErrors::Type error_type
) {
296 // TODO: Remove translate notifications and have the clients be
297 // ContentTranslateDriver::Observer directly instead.
298 DCHECK(web_contents());
299 translate::PageTranslatedDetails details
;
300 details
.source_language
= original_lang
;
301 details
.target_language
= translated_lang
;
302 details
.error_type
= error_type
;
303 content::NotificationService::current()->Notify(
304 chrome::NOTIFICATION_PAGE_TRANSLATED
,
305 content::Source
<content::WebContents
>(web_contents()),
306 content::Details
<translate::PageTranslatedDetails
>(&details
));
309 void ChromeTranslateClient::ShowBubble(
310 translate::TranslateStep step
,
311 translate::TranslateErrors::Type error_type
) {
312 // The bubble is implemented only on the desktop platforms.
313 #if !defined(OS_ANDROID) && !defined(OS_IOS)
314 Browser
* browser
= chrome::FindBrowserWithWebContents(web_contents());
316 // |browser| might be NULL when testing. In this case, Show(...) should be
317 // called because the implementation for testing is used.
319 TranslateBubbleFactory::Show(NULL
, web_contents(), step
, error_type
);
323 if (web_contents() != browser
->tab_strip_model()->GetActiveWebContents())
326 // This ShowBubble function is also used for upating the existing bubble.
327 // However, with the bubble shown, any browser windows are NOT activated
328 // because the bubble takes the focus from the other widgets including the
329 // browser windows. So it is checked that |browser| is the last activated
330 // browser, not is now activated.
332 chrome::FindLastActiveWithHostDesktopType(browser
->host_desktop_type())) {
336 // During auto-translating, the bubble should not be shown.
337 if (step
== translate::TRANSLATE_STEP_TRANSLATING
||
338 step
== translate::TRANSLATE_STEP_AFTER_TRANSLATE
) {
339 if (GetLanguageState().InTranslateNavigation())
343 TranslateBubbleFactory::Show(
344 browser
->window(), web_contents(), step
, error_type
);