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_infobar_delegate.h"
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_service.h"
14 #include "chrome/browser/profiles/profile.h"
15 #include "chrome/browser/translate/translate_accept_languages.h"
16 #include "chrome/browser/translate/translate_manager.h"
17 #include "chrome/browser/translate/translate_tab_helper.h"
18 #include "components/translate/common/translate_constants.h"
19 #include "content/public/browser/navigation_details.h"
20 #include "content/public/browser/navigation_entry.h"
21 #include "content/public/browser/web_contents.h"
22 #include "grit/generated_resources.h"
23 #include "grit/theme_resources.h"
24 #include "third_party/icu/source/i18n/unicode/coll.h"
25 #include "ui/base/l10n/l10n_util.h"
27 using content::NavigationEntry;
31 // TODO(hajimehoshi): Remove this after crbug/283720 is solved.
32 const char kDeclineTranslate[] = "Translate.DeclineTranslate";
34 const char kCloseInfobar[] = "Translate.DeclineTranslateCloseInfobar";
35 const char kShowErrorInfobar[] = "Translate.ShowErrorInfobar";
39 const size_t TranslateInfoBarDelegate::kNoIndex = TranslateUIDelegate::NO_INDEX;
41 TranslateInfoBarDelegate::~TranslateInfoBarDelegate() {
45 void TranslateInfoBarDelegate::Create(
46 bool replace_existing_infobar,
47 InfoBarService* infobar_service,
49 const std::string& original_language,
50 const std::string& target_language,
51 TranslateErrors::Type error_type,
53 const ShortcutConfiguration& shortcut_config) {
54 // Check preconditions.
55 if (infobar_type != TRANSLATION_ERROR) {
56 DCHECK(TranslateManager::IsSupportedLanguage(target_language));
57 if (!TranslateManager::IsSupportedLanguage(original_language)) {
58 // The original language can only be "unknown" for the "translating"
59 // infobar, which is the case when the user started a translation from the
61 DCHECK(infobar_type == TRANSLATING || infobar_type == AFTER_TRANSLATE);
62 DCHECK_EQ(translate::kUnknownLanguageCode, original_language);
66 // Find any existing translate infobar delegate.
67 TranslateInfoBarDelegate* old_delegate = NULL;
68 for (size_t i = 0; i < infobar_service->infobar_count(); ++i) {
69 old_delegate = infobar_service->infobar_at(i)->AsTranslateInfoBarDelegate();
71 if (!replace_existing_infobar)
77 // Create the new delegate.
78 scoped_ptr<TranslateInfoBarDelegate> infobar(
79 new TranslateInfoBarDelegate(infobar_service, infobar_type, old_delegate,
80 original_language, target_language,
81 error_type, prefs, shortcut_config));
83 // Do not create the after translate infobar if we are auto translating.
84 if ((infobar_type == TranslateInfoBarDelegate::AFTER_TRANSLATE) ||
85 (infobar_type == TranslateInfoBarDelegate::TRANSLATING)) {
86 TranslateTabHelper* translate_tab_helper =
87 TranslateTabHelper::FromWebContents(infobar_service->web_contents());
88 if (!translate_tab_helper ||
89 translate_tab_helper->language_state().InTranslateNavigation())
93 // Add the new delegate if necessary.
95 infobar_service->AddInfoBar(infobar.PassAs<InfoBarDelegate>());
97 DCHECK(replace_existing_infobar);
98 infobar_service->ReplaceInfoBar(old_delegate,
99 infobar.PassAs<InfoBarDelegate>());
104 void TranslateInfoBarDelegate::UpdateOriginalLanguageIndex(
105 size_t language_index) {
106 ui_delegate_.UpdateOriginalLanguageIndex(language_index);
109 void TranslateInfoBarDelegate::UpdateTargetLanguageIndex(
110 size_t language_index) {
111 ui_delegate_.UpdateTargetLanguageIndex(language_index);
114 void TranslateInfoBarDelegate::Translate() {
115 ui_delegate_.Translate();
118 void TranslateInfoBarDelegate::RevertTranslation() {
119 ui_delegate_.RevertTranslation();
123 void TranslateInfoBarDelegate::ReportLanguageDetectionError() {
124 TranslateManager::GetInstance()->ReportLanguageDetectionError(
128 void TranslateInfoBarDelegate::TranslationDeclined() {
129 // TODO(miguelg) switch this back to just calling web_contents()
130 // once we've diagnosed crbug/283720
131 // TODO(hajimehoshi): Replace this implementstion with calling ui_delegate_.
132 // TranslationDeclined() after miguelg's investigating.
133 content::WebContents* contents = owner()->web_contents();
134 content::BrowserContext* context = contents->GetBrowserContext();
135 if (!context->IsOffTheRecord()) {
136 prefs_.ResetTranslationAcceptedCount(original_language_code());
137 prefs_.IncrementTranslationDeniedCount(original_language_code());
140 // Remember that the user declined the translation so as to prevent showing a
141 // translate infobar for that page again. (TranslateManager initiates
142 // translations when getting a LANGUAGE_DETERMINED from the page, which
143 // happens when a load stops. That could happen multiple times, including
144 // after the user already declined the translation.)
145 TranslateTabHelper::FromWebContents(web_contents())->
146 language_state().set_translation_declined(true);
148 UMA_HISTOGRAM_BOOLEAN(kDeclineTranslate, true);
151 bool TranslateInfoBarDelegate::IsTranslatableLanguageByPrefs() {
153 Profile::FromBrowserContext(web_contents()->GetBrowserContext());
154 Profile* original_profile = profile->GetOriginalProfile();
155 return TranslatePrefs::CanTranslateLanguage(original_profile,
156 original_language_code());
159 void TranslateInfoBarDelegate::ToggleTranslatableLanguageByPrefs() {
160 if (ui_delegate_.IsLanguageBlocked()) {
161 ui_delegate_.SetLanguageBlocked(false);
163 ui_delegate_.SetLanguageBlocked(true);
168 bool TranslateInfoBarDelegate::IsSiteBlacklisted() {
169 return ui_delegate_.IsSiteBlacklisted();
172 void TranslateInfoBarDelegate::ToggleSiteBlacklist() {
173 if (ui_delegate_.IsSiteBlacklisted()) {
174 ui_delegate_.SetSiteBlacklist(false);
176 ui_delegate_.SetSiteBlacklist(true);
181 bool TranslateInfoBarDelegate::ShouldAlwaysTranslate() {
182 return ui_delegate_.ShouldAlwaysTranslate();
185 void TranslateInfoBarDelegate::ToggleAlwaysTranslate() {
186 ui_delegate_.SetAlwaysTranslate(!ui_delegate_.ShouldAlwaysTranslate());
189 void TranslateInfoBarDelegate::AlwaysTranslatePageLanguage() {
190 DCHECK(!ui_delegate_.ShouldAlwaysTranslate());
191 ui_delegate_.SetAlwaysTranslate(true);
195 void TranslateInfoBarDelegate::NeverTranslatePageLanguage() {
196 DCHECK(!ui_delegate_.IsLanguageBlocked());
197 ui_delegate_.SetLanguageBlocked(true);
201 string16 TranslateInfoBarDelegate::GetMessageInfoBarText() {
202 if (infobar_type_ == TRANSLATING) {
203 string16 target_language_name = language_name_at(target_language_index());
204 return l10n_util::GetStringFUTF16(IDS_TRANSLATE_INFOBAR_TRANSLATING_TO,
205 target_language_name);
208 DCHECK_EQ(TRANSLATION_ERROR, infobar_type_);
209 UMA_HISTOGRAM_ENUMERATION(kShowErrorInfobar,
211 TranslateErrors::TRANSLATE_ERROR_MAX);
212 switch (error_type_) {
213 case TranslateErrors::NETWORK:
214 return l10n_util::GetStringUTF16(
215 IDS_TRANSLATE_INFOBAR_ERROR_CANT_CONNECT);
216 case TranslateErrors::INITIALIZATION_ERROR:
217 case TranslateErrors::TRANSLATION_ERROR:
218 return l10n_util::GetStringUTF16(
219 IDS_TRANSLATE_INFOBAR_ERROR_CANT_TRANSLATE);
220 case TranslateErrors::UNKNOWN_LANGUAGE:
221 return l10n_util::GetStringUTF16(
222 IDS_TRANSLATE_INFOBAR_UNKNOWN_PAGE_LANGUAGE);
223 case TranslateErrors::UNSUPPORTED_LANGUAGE:
224 return l10n_util::GetStringFUTF16(
225 IDS_TRANSLATE_INFOBAR_UNSUPPORTED_PAGE_LANGUAGE,
226 language_name_at(target_language_index()));
227 case TranslateErrors::IDENTICAL_LANGUAGES:
228 return l10n_util::GetStringFUTF16(
229 IDS_TRANSLATE_INFOBAR_ERROR_SAME_LANGUAGE,
230 language_name_at(target_language_index()));
237 string16 TranslateInfoBarDelegate::GetMessageInfoBarButtonText() {
238 if (infobar_type_ != TRANSLATION_ERROR) {
239 DCHECK_EQ(TRANSLATING, infobar_type_);
240 } else if ((error_type_ != TranslateErrors::IDENTICAL_LANGUAGES) &&
241 (error_type_ != TranslateErrors::UNKNOWN_LANGUAGE)) {
242 return l10n_util::GetStringUTF16(
243 (error_type_ == TranslateErrors::UNSUPPORTED_LANGUAGE) ?
244 IDS_TRANSLATE_INFOBAR_REVERT : IDS_TRANSLATE_INFOBAR_RETRY);
249 void TranslateInfoBarDelegate::MessageInfoBarButtonPressed() {
250 DCHECK_EQ(TRANSLATION_ERROR, infobar_type_);
251 if (error_type_ == TranslateErrors::UNSUPPORTED_LANGUAGE) {
255 // This is the "Try again..." case.
256 TranslateManager::GetInstance()->TranslatePage(
257 web_contents(), original_language_code(), target_language_code());
260 bool TranslateInfoBarDelegate::ShouldShowMessageInfoBarButton() {
261 return !GetMessageInfoBarButtonText().empty();
264 bool TranslateInfoBarDelegate::ShouldShowNeverTranslateShortcut() {
265 DCHECK_EQ(BEFORE_TRANSLATE, infobar_type_);
266 return !web_contents()->GetBrowserContext()->IsOffTheRecord() &&
267 (prefs_.GetTranslationDeniedCount(original_language_code()) >=
268 shortcut_config_.never_translate_min_count);
271 bool TranslateInfoBarDelegate::ShouldShowAlwaysTranslateShortcut() {
272 DCHECK_EQ(BEFORE_TRANSLATE, infobar_type_);
273 return !web_contents()->GetBrowserContext()->IsOffTheRecord() &&
274 (prefs_.GetTranslationAcceptedCount(original_language_code()) >=
275 shortcut_config_.always_translate_min_count);
279 string16 TranslateInfoBarDelegate::GetLanguageDisplayableName(
280 const std::string& language_code) {
281 return l10n_util::GetDisplayNameForLocale(
282 language_code, g_browser_process->GetApplicationLocale(), true);
286 void TranslateInfoBarDelegate::GetAfterTranslateStrings(
287 std::vector<string16>* strings,
288 bool* swap_languages,
289 bool autodetermined_source_language) {
292 if (autodetermined_source_language) {
294 string16 text = l10n_util::GetStringFUTF16(
295 IDS_TRANSLATE_INFOBAR_AFTER_MESSAGE_AUTODETERMINED_SOURCE_LANGUAGE,
299 strings->push_back(text.substr(0, offset));
300 strings->push_back(text.substr(offset));
303 DCHECK(swap_languages);
305 std::vector<size_t> offsets;
306 string16 text = l10n_util::GetStringFUTF16(
307 IDS_TRANSLATE_INFOBAR_AFTER_MESSAGE, string16(), string16(), &offsets);
308 DCHECK_EQ(2U, offsets.size());
310 *swap_languages = (offsets[0] > offsets[1]);
312 std::swap(offsets[0], offsets[1]);
314 strings->push_back(text.substr(0, offsets[0]));
315 strings->push_back(text.substr(offsets[0], offsets[1] - offsets[0]));
316 strings->push_back(text.substr(offsets[1]));
319 TranslateInfoBarDelegate::TranslateInfoBarDelegate(
320 InfoBarService* infobar_service,
322 TranslateInfoBarDelegate* old_delegate,
323 const std::string& original_language,
324 const std::string& target_language,
325 TranslateErrors::Type error_type,
327 ShortcutConfiguration shortcut_config)
328 : InfoBarDelegate(infobar_service),
329 infobar_type_(infobar_type),
330 background_animation_(NONE),
331 ui_delegate_(web_contents(), original_language, target_language),
332 error_type_(error_type),
334 shortcut_config_(shortcut_config) {
335 DCHECK_NE((infobar_type_ == TRANSLATION_ERROR),
336 (error_type_ == TranslateErrors::NONE));
338 if (old_delegate && (old_delegate->is_error() != is_error()))
339 background_animation_ = is_error() ? NORMAL_TO_ERROR : ERROR_TO_NORMAL;
342 void TranslateInfoBarDelegate::InfoBarDismissed() {
343 if (infobar_type_ != BEFORE_TRANSLATE)
346 // The user closed the infobar without clicking the translate button.
347 TranslationDeclined();
348 UMA_HISTOGRAM_BOOLEAN(kCloseInfobar, true);
351 int TranslateInfoBarDelegate::GetIconID() const {
352 return IDR_INFOBAR_TRANSLATE;
355 InfoBarDelegate::Type TranslateInfoBarDelegate::GetInfoBarType() const {
356 return PAGE_ACTION_TYPE;
359 bool TranslateInfoBarDelegate::ShouldExpire(
360 const content::LoadCommittedDetails& details) const {
361 // Note: we allow closing this infobar even if the main frame navigation
362 // was programmatic and not initiated by the user - crbug.com/70261 .
363 if (!details.is_navigation_to_different_page() && !details.is_main_frame)
366 return InfoBarDelegate::ShouldExpireInternal(details);
369 TranslateInfoBarDelegate*
370 TranslateInfoBarDelegate::AsTranslateInfoBarDelegate() {