• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.
4 
5 #include "chrome/browser/translate/chrome_translate_client.h"
6 
7 #include <vector>
8 
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/common/cld_data_source.h"
28 #include "components/translate/content/common/translate_messages.h"
29 #include "components/translate/core/browser/language_state.h"
30 #include "components/translate/core/browser/page_translated_details.h"
31 #include "components/translate/core/browser/translate_accept_languages.h"
32 #include "components/translate/core/browser/translate_download_manager.h"
33 #include "components/translate/core/browser/translate_infobar_delegate.h"
34 #include "components/translate/core/browser/translate_manager.h"
35 #include "components/translate/core/browser/translate_prefs.h"
36 #include "components/translate/core/common/language_detection_details.h"
37 #include "content/public/browser/notification_service.h"
38 #include "content/public/browser/render_view_host.h"
39 #include "content/public/browser/web_contents.h"
40 #include "grit/theme_resources.h"
41 #include "url/gurl.h"
42 
43 namespace {
44 
45 // TODO(andrewhayden): Make the data file path into a gyp/gn define
46 // If you change this, also update standalone_cld_data_harness.cc
47 // accordingly!
48 const base::FilePath::CharType kCldDataFileName[] =
49     FILE_PATH_LITERAL("cld2_data.bin");
50 
51 bool g_cld_file_path_initialized_ = false;
52 
53 }  // namespace
54 
55 DEFINE_WEB_CONTENTS_USER_DATA_KEY(ChromeTranslateClient);
56 
ChromeTranslateClient(content::WebContents * web_contents)57 ChromeTranslateClient::ChromeTranslateClient(content::WebContents* web_contents)
58     : content::WebContentsObserver(web_contents),
59       translate_driver_(&web_contents->GetController()),
60       translate_manager_(
61           new translate::TranslateManager(this, prefs::kAcceptLanguages)),
62       cld_data_provider_(
63           translate::CreateBrowserCldDataProviderFor(web_contents)) {
64   translate_driver_.AddObserver(this);
65   translate_driver_.set_translate_manager(translate_manager_.get());
66   // Customization: for the standalone data source, we configure the path to
67   // CLD data immediately on startup.
68   if (translate::CldDataSource::ShouldUseStandaloneDataFile() &&
69       !g_cld_file_path_initialized_) {
70     VLOG(1) << "Initializing CLD file path for the first time.";
71     base::FilePath path;
72     if (!PathService::Get(chrome::DIR_USER_DATA, &path)) {
73       // Chrome isn't properly installed
74       LOG(WARNING) << "Unable to locate user data directory";
75     } else {
76       g_cld_file_path_initialized_ = true;
77       path = path.Append(kCldDataFileName);
78       VLOG(1) << "Setting CLD data file path: " << path.value();
79       translate::SetCldDataFilePath(path);
80     }
81   }
82 }
83 
~ChromeTranslateClient()84 ChromeTranslateClient::~ChromeTranslateClient() {
85   translate_driver_.RemoveObserver(this);
86 }
87 
GetLanguageState()88 translate::LanguageState& ChromeTranslateClient::GetLanguageState() {
89   return translate_manager_->GetLanguageState();
90 }
91 
92 // static
93 scoped_ptr<translate::TranslatePrefs>
CreateTranslatePrefs(PrefService * prefs)94 ChromeTranslateClient::CreateTranslatePrefs(PrefService* prefs) {
95 #if defined(OS_CHROMEOS)
96   const char* preferred_languages_prefs = prefs::kLanguagePreferredLanguages;
97 #else
98   const char* preferred_languages_prefs = NULL;
99 #endif
100   return scoped_ptr<translate::TranslatePrefs>(new translate::TranslatePrefs(
101       prefs, prefs::kAcceptLanguages, preferred_languages_prefs));
102 }
103 
104 // static
105 translate::TranslateAcceptLanguages*
GetTranslateAcceptLanguages(content::BrowserContext * browser_context)106 ChromeTranslateClient::GetTranslateAcceptLanguages(
107     content::BrowserContext* browser_context) {
108   return TranslateAcceptLanguagesFactory::GetForBrowserContext(browser_context);
109 }
110 
111 // static
GetManagerFromWebContents(content::WebContents * web_contents)112 translate::TranslateManager* ChromeTranslateClient::GetManagerFromWebContents(
113     content::WebContents* web_contents) {
114   ChromeTranslateClient* chrome_translate_client =
115       FromWebContents(web_contents);
116   if (!chrome_translate_client)
117     return NULL;
118   return chrome_translate_client->GetTranslateManager();
119 }
120 
121 // static
GetTranslateLanguages(content::WebContents * web_contents,std::string * source,std::string * target)122 void ChromeTranslateClient::GetTranslateLanguages(
123     content::WebContents* web_contents,
124     std::string* source,
125     std::string* target) {
126   DCHECK(source != NULL);
127   DCHECK(target != NULL);
128 
129   ChromeTranslateClient* chrome_translate_client =
130       FromWebContents(web_contents);
131   if (!chrome_translate_client)
132     return;
133 
134   *source = translate::TranslateDownloadManager::GetLanguageCode(
135       chrome_translate_client->GetLanguageState().original_language());
136 
137   Profile* profile =
138       Profile::FromBrowserContext(web_contents->GetBrowserContext());
139   Profile* original_profile = profile->GetOriginalProfile();
140   PrefService* prefs = original_profile->GetPrefs();
141   scoped_ptr<translate::TranslatePrefs> translate_prefs =
142       CreateTranslatePrefs(prefs);
143   if (!web_contents->GetBrowserContext()->IsOffTheRecord()) {
144     std::string auto_translate_language =
145         translate::TranslateManager::GetAutoTargetLanguage(
146             *source, translate_prefs.get());
147     if (!auto_translate_language.empty()) {
148       *target = auto_translate_language;
149       return;
150     }
151   }
152 
153   std::string accept_languages_str = prefs->GetString(prefs::kAcceptLanguages);
154   std::vector<std::string> accept_languages_list;
155   base::SplitString(accept_languages_str, ',', &accept_languages_list);
156   *target =
157       translate::TranslateManager::GetTargetLanguage(accept_languages_list);
158 }
159 
GetTranslateManager()160 translate::TranslateManager* ChromeTranslateClient::GetTranslateManager() {
161   return translate_manager_.get();
162 }
163 
ShowTranslateUI(translate::TranslateStep step,const std::string source_language,const std::string target_language,translate::TranslateErrors::Type error_type,bool triggered_from_menu)164 void ChromeTranslateClient::ShowTranslateUI(
165     translate::TranslateStep step,
166     const std::string source_language,
167     const std::string target_language,
168     translate::TranslateErrors::Type error_type,
169     bool triggered_from_menu) {
170   DCHECK(web_contents());
171   if (error_type != translate::TranslateErrors::NONE)
172     step = translate::TRANSLATE_STEP_TRANSLATE_ERROR;
173 
174   if (TranslateService::IsTranslateBubbleEnabled()) {
175     // Bubble UI.
176     if (step == translate::TRANSLATE_STEP_BEFORE_TRANSLATE) {
177       // TODO(droger): Move this logic out of UI code.
178       GetLanguageState().SetTranslateEnabled(true);
179       if (!GetLanguageState().HasLanguageChanged())
180         return;
181 
182       if (!triggered_from_menu) {
183         if (web_contents()->GetBrowserContext()->IsOffTheRecord())
184           return;
185         if (GetTranslatePrefs()->IsTooOftenDenied())
186           return;
187       }
188     }
189     ShowBubble(step, error_type);
190     return;
191   }
192 
193   // Infobar UI.
194   translate::TranslateInfoBarDelegate::Create(
195       step != translate::TRANSLATE_STEP_BEFORE_TRANSLATE,
196       translate_manager_->GetWeakPtr(),
197       InfoBarService::FromWebContents(web_contents()),
198       web_contents()->GetBrowserContext()->IsOffTheRecord(),
199       step,
200       source_language,
201       target_language,
202       error_type,
203       triggered_from_menu);
204 }
205 
GetTranslateDriver()206 translate::TranslateDriver* ChromeTranslateClient::GetTranslateDriver() {
207   return &translate_driver_;
208 }
209 
GetPrefs()210 PrefService* ChromeTranslateClient::GetPrefs() {
211   DCHECK(web_contents());
212   Profile* profile =
213       Profile::FromBrowserContext(web_contents()->GetBrowserContext());
214   return profile->GetOriginalProfile()->GetPrefs();
215 }
216 
217 scoped_ptr<translate::TranslatePrefs>
GetTranslatePrefs()218 ChromeTranslateClient::GetTranslatePrefs() {
219   DCHECK(web_contents());
220   Profile* profile =
221       Profile::FromBrowserContext(web_contents()->GetBrowserContext());
222   return CreateTranslatePrefs(profile->GetPrefs());
223 }
224 
225 translate::TranslateAcceptLanguages*
GetTranslateAcceptLanguages()226 ChromeTranslateClient::GetTranslateAcceptLanguages() {
227   DCHECK(web_contents());
228   return GetTranslateAcceptLanguages(web_contents()->GetBrowserContext());
229 }
230 
GetInfobarIconID() const231 int ChromeTranslateClient::GetInfobarIconID() const {
232   return IDR_INFOBAR_TRANSLATE;
233 }
234 
235 // ChromeTranslateClient::CreateInfoBar() is implemented in platform-specific
236 // files, except the TOOLKIT_VIEWS implementation, which has been removed. Note
237 // for Mac, Cocoa is still providing the infobar in a toolkit-views build.
238 #if defined(TOOLKIT_VIEWS) && !defined(OS_MACOSX)
CreateInfoBar(scoped_ptr<translate::TranslateInfoBarDelegate> delegate) const239 scoped_ptr<infobars::InfoBar> ChromeTranslateClient::CreateInfoBar(
240     scoped_ptr<translate::TranslateInfoBarDelegate> delegate) const {
241   return scoped_ptr<infobars::InfoBar>();
242 }
243 #endif
244 
IsTranslatableURL(const GURL & url)245 bool ChromeTranslateClient::IsTranslatableURL(const GURL& url) {
246   return TranslateService::IsTranslatableURL(url);
247 }
248 
ShowReportLanguageDetectionErrorUI(const GURL & report_url)249 void ChromeTranslateClient::ShowReportLanguageDetectionErrorUI(
250     const GURL& report_url) {
251 #if defined(OS_ANDROID)
252   // Android does not support reporting language detection errors.
253   NOTREACHED();
254 #else
255   // We'll open the URL in a new tab so that the user can tell us more.
256   Browser* browser = chrome::FindBrowserWithWebContents(web_contents());
257   if (!browser) {
258     NOTREACHED();
259     return;
260   }
261 
262   chrome::AddSelectedTabWithURL(
263       browser, report_url, ui::PAGE_TRANSITION_AUTO_BOOKMARK);
264 #endif  // defined(OS_ANDROID)
265 }
266 
OnMessageReceived(const IPC::Message & message)267 bool ChromeTranslateClient::OnMessageReceived(const IPC::Message& message) {
268   return cld_data_provider_->OnMessageReceived(message);
269 }
270 
WebContentsDestroyed()271 void ChromeTranslateClient::WebContentsDestroyed() {
272   // Translation process can be interrupted.
273   // Destroying the TranslateManager now guarantees that it never has to deal
274   // with NULL WebContents.
275   translate_manager_.reset();
276 }
277 
278 // ContentTranslateDriver::Observer implementation.
279 
OnLanguageDetermined(const translate::LanguageDetectionDetails & details)280 void ChromeTranslateClient::OnLanguageDetermined(
281     const translate::LanguageDetectionDetails& details) {
282   // TODO: Remove translate notifications and have the clients be
283   // ContentTranslateDriver::Observer directly instead.
284   content::NotificationService::current()->Notify(
285       chrome::NOTIFICATION_TAB_LANGUAGE_DETERMINED,
286       content::Source<content::WebContents>(web_contents()),
287       content::Details<const translate::LanguageDetectionDetails>(&details));
288 }
289 
OnPageTranslated(const std::string & original_lang,const std::string & translated_lang,translate::TranslateErrors::Type error_type)290 void ChromeTranslateClient::OnPageTranslated(
291     const std::string& original_lang,
292     const std::string& translated_lang,
293     translate::TranslateErrors::Type error_type) {
294   // TODO: Remove translate notifications and have the clients be
295   // ContentTranslateDriver::Observer directly instead.
296   DCHECK(web_contents());
297   translate::PageTranslatedDetails details;
298   details.source_language = original_lang;
299   details.target_language = translated_lang;
300   details.error_type = error_type;
301   content::NotificationService::current()->Notify(
302       chrome::NOTIFICATION_PAGE_TRANSLATED,
303       content::Source<content::WebContents>(web_contents()),
304       content::Details<translate::PageTranslatedDetails>(&details));
305 }
306 
ShowBubble(translate::TranslateStep step,translate::TranslateErrors::Type error_type)307 void ChromeTranslateClient::ShowBubble(
308     translate::TranslateStep step,
309     translate::TranslateErrors::Type error_type) {
310 // The bubble is implemented only on the desktop platforms.
311 #if !defined(OS_ANDROID) && !defined(OS_IOS)
312   Browser* browser = chrome::FindBrowserWithWebContents(web_contents());
313 
314   // |browser| might be NULL when testing. In this case, Show(...) should be
315   // called because the implementation for testing is used.
316   if (!browser) {
317     TranslateBubbleFactory::Show(NULL, web_contents(), step, error_type);
318     return;
319   }
320 
321   if (web_contents() != browser->tab_strip_model()->GetActiveWebContents())
322     return;
323 
324   // This ShowBubble function is also used for upating the existing bubble.
325   // However, with the bubble shown, any browser windows are NOT activated
326   // because the bubble takes the focus from the other widgets including the
327   // browser windows. So it is checked that |browser| is the last activated
328   // browser, not is now activated.
329   if (browser !=
330       chrome::FindLastActiveWithHostDesktopType(browser->host_desktop_type())) {
331     return;
332   }
333 
334   // During auto-translating, the bubble should not be shown.
335   if (step == translate::TRANSLATE_STEP_TRANSLATING ||
336       step == translate::TRANSLATE_STEP_AFTER_TRANSLATE) {
337     if (GetLanguageState().InTranslateNavigation())
338       return;
339   }
340 
341   TranslateBubbleFactory::Show(
342       browser->window(), web_contents(), step, error_type);
343 #else
344   NOTREACHED();
345 #endif
346 }
347