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