• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.
4 
5 #include "chrome/browser/translate/translate_infobar_delegate.h"
6 
7 #include <algorithm>
8 
9 #include "base/i18n/string_compare.h"
10 #include "base/metrics/histogram.h"
11 #include "base/prefs/pref_service.h"
12 #include "chrome/browser/browser_process.h"
13 #include "chrome/browser/infobars/infobar.h"
14 #include "chrome/browser/infobars/infobar_service.h"
15 #include "chrome/browser/profiles/profile.h"
16 #include "chrome/browser/translate/translate_accept_languages.h"
17 #include "chrome/browser/translate/translate_manager.h"
18 #include "chrome/browser/translate/translate_tab_helper.h"
19 #include "components/translate/common/translate_constants.h"
20 #include "content/public/browser/navigation_details.h"
21 #include "content/public/browser/navigation_entry.h"
22 #include "content/public/browser/web_contents.h"
23 #include "grit/generated_resources.h"
24 #include "grit/theme_resources.h"
25 #include "third_party/icu/source/i18n/unicode/coll.h"
26 #include "ui/base/l10n/l10n_util.h"
27 
28 
29 const size_t TranslateInfoBarDelegate::kNoIndex = TranslateUIDelegate::NO_INDEX;
30 
~TranslateInfoBarDelegate()31 TranslateInfoBarDelegate::~TranslateInfoBarDelegate() {
32 }
33 
34 // static
Create(bool replace_existing_infobar,content::WebContents * web_contents,Type infobar_type,const std::string & original_language,const std::string & target_language,TranslateErrors::Type error_type,PrefService * prefs,const ShortcutConfiguration & shortcut_config)35 void TranslateInfoBarDelegate::Create(
36     bool replace_existing_infobar,
37     content::WebContents* web_contents,
38     Type infobar_type,
39     const std::string& original_language,
40     const std::string& target_language,
41     TranslateErrors::Type error_type,
42     PrefService* prefs,
43     const ShortcutConfiguration& shortcut_config) {
44   // Check preconditions.
45   if (infobar_type != TRANSLATION_ERROR) {
46     DCHECK(TranslateManager::IsSupportedLanguage(target_language));
47     if (!TranslateManager::IsSupportedLanguage(original_language)) {
48       // The original language can only be "unknown" for the "translating"
49       // infobar, which is the case when the user started a translation from the
50       // context menu.
51       DCHECK(infobar_type == TRANSLATING || infobar_type == AFTER_TRANSLATE);
52       DCHECK_EQ(translate::kUnknownLanguageCode, original_language);
53     }
54   }
55 
56   // Do not create the after translate infobar if we are auto translating.
57   if ((infobar_type == TranslateInfoBarDelegate::AFTER_TRANSLATE) ||
58       (infobar_type == TranslateInfoBarDelegate::TRANSLATING)) {
59     TranslateTabHelper* translate_tab_helper =
60         TranslateTabHelper::FromWebContents(web_contents);
61     if (!translate_tab_helper ||
62         translate_tab_helper->language_state().InTranslateNavigation())
63       return;
64   }
65 
66   // Find any existing translate infobar delegate.
67   InfoBar* old_infobar = NULL;
68   InfoBarService* infobar_service =
69       InfoBarService::FromWebContents(web_contents);
70   TranslateInfoBarDelegate* old_delegate = NULL;
71   for (size_t i = 0; i < infobar_service->infobar_count(); ++i) {
72     old_infobar = infobar_service->infobar_at(i);
73     old_delegate = old_infobar->delegate()->AsTranslateInfoBarDelegate();
74     if (old_delegate) {
75       if (!replace_existing_infobar)
76         return;
77       break;
78     }
79   }
80 
81   // Add the new delegate.
82   scoped_ptr<InfoBar> infobar(CreateInfoBar(
83       scoped_ptr<TranslateInfoBarDelegate>(new TranslateInfoBarDelegate(
84           web_contents, infobar_type, old_delegate, original_language,
85           target_language, error_type, prefs, shortcut_config))));
86   if (old_delegate)
87     infobar_service->ReplaceInfoBar(old_infobar, infobar.Pass());
88   else
89     infobar_service->AddInfoBar(infobar.Pass());
90 }
91 
92 
UpdateOriginalLanguageIndex(size_t language_index)93 void TranslateInfoBarDelegate::UpdateOriginalLanguageIndex(
94     size_t language_index) {
95   ui_delegate_.UpdateOriginalLanguageIndex(language_index);
96 }
97 
UpdateTargetLanguageIndex(size_t language_index)98 void TranslateInfoBarDelegate::UpdateTargetLanguageIndex(
99     size_t language_index) {
100   ui_delegate_.UpdateTargetLanguageIndex(language_index);
101 }
102 
Translate()103 void TranslateInfoBarDelegate::Translate() {
104   ui_delegate_.Translate();
105 }
106 
RevertTranslation()107 void TranslateInfoBarDelegate::RevertTranslation() {
108   ui_delegate_.RevertTranslation();
109   infobar()->RemoveSelf();
110 }
111 
ReportLanguageDetectionError()112 void TranslateInfoBarDelegate::ReportLanguageDetectionError() {
113   TranslateManager::GetInstance()->ReportLanguageDetectionError(
114       web_contents());
115 }
116 
TranslationDeclined()117 void TranslateInfoBarDelegate::TranslationDeclined() {
118   ui_delegate_.TranslationDeclined(false);
119 }
120 
IsTranslatableLanguageByPrefs()121 bool TranslateInfoBarDelegate::IsTranslatableLanguageByPrefs() {
122   Profile* profile =
123       Profile::FromBrowserContext(web_contents()->GetBrowserContext());
124   Profile* original_profile = profile->GetOriginalProfile();
125   return TranslatePrefs::CanTranslateLanguage(original_profile,
126                                               original_language_code());
127 }
128 
ToggleTranslatableLanguageByPrefs()129 void TranslateInfoBarDelegate::ToggleTranslatableLanguageByPrefs() {
130   if (ui_delegate_.IsLanguageBlocked()) {
131     ui_delegate_.SetLanguageBlocked(false);
132   } else {
133     ui_delegate_.SetLanguageBlocked(true);
134     infobar()->RemoveSelf();
135   }
136 }
137 
IsSiteBlacklisted()138 bool TranslateInfoBarDelegate::IsSiteBlacklisted() {
139   return ui_delegate_.IsSiteBlacklisted();
140 }
141 
ToggleSiteBlacklist()142 void TranslateInfoBarDelegate::ToggleSiteBlacklist() {
143   if (ui_delegate_.IsSiteBlacklisted()) {
144     ui_delegate_.SetSiteBlacklist(false);
145   } else {
146     ui_delegate_.SetSiteBlacklist(true);
147     infobar()->RemoveSelf();
148   }
149 }
150 
ShouldAlwaysTranslate()151 bool TranslateInfoBarDelegate::ShouldAlwaysTranslate() {
152   return ui_delegate_.ShouldAlwaysTranslate();
153 }
154 
ToggleAlwaysTranslate()155 void TranslateInfoBarDelegate::ToggleAlwaysTranslate() {
156   ui_delegate_.SetAlwaysTranslate(!ui_delegate_.ShouldAlwaysTranslate());
157 }
158 
AlwaysTranslatePageLanguage()159 void TranslateInfoBarDelegate::AlwaysTranslatePageLanguage() {
160   DCHECK(!ui_delegate_.ShouldAlwaysTranslate());
161   ui_delegate_.SetAlwaysTranslate(true);
162   Translate();
163 }
164 
NeverTranslatePageLanguage()165 void TranslateInfoBarDelegate::NeverTranslatePageLanguage() {
166   DCHECK(!ui_delegate_.IsLanguageBlocked());
167   ui_delegate_.SetLanguageBlocked(true);
168     infobar()->RemoveSelf();
169 }
170 
GetMessageInfoBarText()171 base::string16 TranslateInfoBarDelegate::GetMessageInfoBarText() {
172   if (infobar_type_ == TRANSLATING) {
173     base::string16 target_language_name =
174         language_name_at(target_language_index());
175     return l10n_util::GetStringFUTF16(IDS_TRANSLATE_INFOBAR_TRANSLATING_TO,
176                                       target_language_name);
177   }
178 
179   DCHECK_EQ(TRANSLATION_ERROR, infobar_type_);
180   UMA_HISTOGRAM_ENUMERATION("Translate.ShowErrorInfobar",
181                             error_type_,
182                             TranslateErrors::TRANSLATE_ERROR_MAX);
183   ui_delegate_.OnErrorShown(error_type_);
184   switch (error_type_) {
185     case TranslateErrors::NETWORK:
186       return l10n_util::GetStringUTF16(
187           IDS_TRANSLATE_INFOBAR_ERROR_CANT_CONNECT);
188     case TranslateErrors::INITIALIZATION_ERROR:
189     case TranslateErrors::TRANSLATION_ERROR:
190       return l10n_util::GetStringUTF16(
191           IDS_TRANSLATE_INFOBAR_ERROR_CANT_TRANSLATE);
192     case TranslateErrors::UNKNOWN_LANGUAGE:
193       return l10n_util::GetStringUTF16(
194           IDS_TRANSLATE_INFOBAR_UNKNOWN_PAGE_LANGUAGE);
195     case TranslateErrors::UNSUPPORTED_LANGUAGE:
196       return l10n_util::GetStringFUTF16(
197           IDS_TRANSLATE_INFOBAR_UNSUPPORTED_PAGE_LANGUAGE,
198           language_name_at(target_language_index()));
199     case TranslateErrors::IDENTICAL_LANGUAGES:
200       return l10n_util::GetStringFUTF16(
201           IDS_TRANSLATE_INFOBAR_ERROR_SAME_LANGUAGE,
202           language_name_at(target_language_index()));
203     default:
204       NOTREACHED();
205       return base::string16();
206   }
207 }
208 
GetMessageInfoBarButtonText()209 base::string16 TranslateInfoBarDelegate::GetMessageInfoBarButtonText() {
210   if (infobar_type_ != TRANSLATION_ERROR) {
211     DCHECK_EQ(TRANSLATING, infobar_type_);
212   } else if ((error_type_ != TranslateErrors::IDENTICAL_LANGUAGES) &&
213              (error_type_ != TranslateErrors::UNKNOWN_LANGUAGE)) {
214     return l10n_util::GetStringUTF16(
215         (error_type_ == TranslateErrors::UNSUPPORTED_LANGUAGE) ?
216         IDS_TRANSLATE_INFOBAR_REVERT : IDS_TRANSLATE_INFOBAR_RETRY);
217   }
218   return base::string16();
219 }
220 
MessageInfoBarButtonPressed()221 void TranslateInfoBarDelegate::MessageInfoBarButtonPressed() {
222   DCHECK_EQ(TRANSLATION_ERROR, infobar_type_);
223   if (error_type_ == TranslateErrors::UNSUPPORTED_LANGUAGE) {
224     RevertTranslation();
225     return;
226   }
227   // This is the "Try again..." case.
228   TranslateManager::GetInstance()->TranslatePage(
229       web_contents(), original_language_code(), target_language_code());
230 }
231 
ShouldShowMessageInfoBarButton()232 bool TranslateInfoBarDelegate::ShouldShowMessageInfoBarButton() {
233   return !GetMessageInfoBarButtonText().empty();
234 }
235 
ShouldShowNeverTranslateShortcut()236 bool TranslateInfoBarDelegate::ShouldShowNeverTranslateShortcut() {
237   DCHECK_EQ(BEFORE_TRANSLATE, infobar_type_);
238   return !web_contents()->GetBrowserContext()->IsOffTheRecord() &&
239       (prefs_.GetTranslationDeniedCount(original_language_code()) >=
240           shortcut_config_.never_translate_min_count);
241 }
242 
ShouldShowAlwaysTranslateShortcut()243 bool TranslateInfoBarDelegate::ShouldShowAlwaysTranslateShortcut() {
244   DCHECK_EQ(BEFORE_TRANSLATE, infobar_type_);
245   return !web_contents()->GetBrowserContext()->IsOffTheRecord() &&
246       (prefs_.GetTranslationAcceptedCount(original_language_code()) >=
247           shortcut_config_.always_translate_min_count);
248 }
249 
250 // static
GetLanguageDisplayableName(const std::string & language_code)251 base::string16 TranslateInfoBarDelegate::GetLanguageDisplayableName(
252     const std::string& language_code) {
253   return l10n_util::GetDisplayNameForLocale(
254       language_code, g_browser_process->GetApplicationLocale(), true);
255 }
256 
257 // static
GetAfterTranslateStrings(std::vector<base::string16> * strings,bool * swap_languages,bool autodetermined_source_language)258 void TranslateInfoBarDelegate::GetAfterTranslateStrings(
259     std::vector<base::string16>* strings,
260     bool* swap_languages,
261     bool autodetermined_source_language) {
262   DCHECK(strings);
263 
264   if (autodetermined_source_language) {
265     size_t offset;
266     base::string16 text = l10n_util::GetStringFUTF16(
267         IDS_TRANSLATE_INFOBAR_AFTER_MESSAGE_AUTODETERMINED_SOURCE_LANGUAGE,
268         base::string16(),
269         &offset);
270 
271     strings->push_back(text.substr(0, offset));
272     strings->push_back(text.substr(offset));
273     return;
274   }
275   DCHECK(swap_languages);
276 
277   std::vector<size_t> offsets;
278   base::string16 text = l10n_util::GetStringFUTF16(
279       IDS_TRANSLATE_INFOBAR_AFTER_MESSAGE, base::string16(), base::string16(),
280       &offsets);
281   DCHECK_EQ(2U, offsets.size());
282 
283   *swap_languages = (offsets[0] > offsets[1]);
284   if (*swap_languages)
285     std::swap(offsets[0], offsets[1]);
286 
287   strings->push_back(text.substr(0, offsets[0]));
288   strings->push_back(text.substr(offsets[0], offsets[1] - offsets[0]));
289   strings->push_back(text.substr(offsets[1]));
290 }
291 
TranslateInfoBarDelegate(content::WebContents * web_contents,Type infobar_type,TranslateInfoBarDelegate * old_delegate,const std::string & original_language,const std::string & target_language,TranslateErrors::Type error_type,PrefService * prefs,ShortcutConfiguration shortcut_config)292 TranslateInfoBarDelegate::TranslateInfoBarDelegate(
293     content::WebContents* web_contents,
294     Type infobar_type,
295     TranslateInfoBarDelegate* old_delegate,
296     const std::string& original_language,
297     const std::string& target_language,
298     TranslateErrors::Type error_type,
299     PrefService* prefs,
300     ShortcutConfiguration shortcut_config)
301     : InfoBarDelegate(),
302       infobar_type_(infobar_type),
303       background_animation_(NONE),
304       ui_delegate_(web_contents, original_language, target_language),
305       error_type_(error_type),
306       prefs_(prefs),
307       shortcut_config_(shortcut_config) {
308   DCHECK_NE((infobar_type_ == TRANSLATION_ERROR),
309             (error_type_ == TranslateErrors::NONE));
310 
311   if (old_delegate && (old_delegate->is_error() != is_error()))
312     background_animation_ = is_error() ? NORMAL_TO_ERROR : ERROR_TO_NORMAL;
313 }
314 
315 // TranslateInfoBarDelegate::CreateInfoBar() is implemented in platform-specific
316 // files.
317 
InfoBarDismissed()318 void TranslateInfoBarDelegate::InfoBarDismissed() {
319   if (infobar_type_ != BEFORE_TRANSLATE)
320     return;
321 
322   // The user closed the infobar without clicking the translate button.
323   TranslationDeclined();
324   UMA_HISTOGRAM_BOOLEAN("Translate.DeclineTranslateCloseInfobar", true);
325 }
326 
GetIconID() const327 int TranslateInfoBarDelegate::GetIconID() const {
328   return IDR_INFOBAR_TRANSLATE;
329 }
330 
GetInfoBarType() const331 InfoBarDelegate::Type TranslateInfoBarDelegate::GetInfoBarType() const {
332   return PAGE_ACTION_TYPE;
333 }
334 
ShouldExpire(const content::LoadCommittedDetails & details) const335 bool TranslateInfoBarDelegate::ShouldExpire(
336     const content::LoadCommittedDetails& details) const {
337   // Note: we allow closing this infobar even if the main frame navigation
338   // was programmatic and not initiated by the user - crbug.com/70261 .
339   if (!details.is_navigation_to_different_page() && !details.is_main_frame)
340     return false;
341 
342   return InfoBarDelegate::ShouldExpireInternal(details);
343 }
344 
345 TranslateInfoBarDelegate*
AsTranslateInfoBarDelegate()346     TranslateInfoBarDelegate::AsTranslateInfoBarDelegate() {
347   return this;
348 }
349