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