OLD | NEW |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "chrome/renderer/translate/translate_helper.h" | 5 #include "chrome/renderer/translate/translate_helper.h" |
6 | 6 |
7 #include "base/bind.h" | 7 #include "base/bind.h" |
8 #include "base/compiler_specific.h" | 8 #include "base/compiler_specific.h" |
9 #include "base/logging.h" | 9 #include "base/logging.h" |
10 #include "base/message_loop.h" | 10 #include "base/message_loop.h" |
(...skipping 75 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
86 void TranslateHelper::PageCaptured(const string16& contents) { | 86 void TranslateHelper::PageCaptured(const string16& contents) { |
87 // Get the document language as set by WebKit from the http-equiv | 87 // Get the document language as set by WebKit from the http-equiv |
88 // meta tag for "content-language". This may or may not also | 88 // meta tag for "content-language". This may or may not also |
89 // have a value derived from the actual Content-Language HTTP | 89 // have a value derived from the actual Content-Language HTTP |
90 // header. The two actually have different meanings (despite the | 90 // header. The two actually have different meanings (despite the |
91 // original intent of http-equiv to be an equivalent) with the former | 91 // original intent of http-equiv to be an equivalent) with the former |
92 // being the language of the document and the latter being the | 92 // being the language of the document and the latter being the |
93 // language of the intended audience (a distinction really only | 93 // language of the intended audience (a distinction really only |
94 // relevant for things like langauge textbooks). This distinction | 94 // relevant for things like langauge textbooks). This distinction |
95 // shouldn't affect translation. | 95 // shouldn't affect translation. |
96 WebFrame* main_frame = GetMainFrame(); | 96 WebDocument document = GetMainFrame()->document(); |
97 if (!main_frame) | |
98 return; | |
99 WebDocument document = main_frame->document(); | |
100 std::string content_language = document.contentLanguage().utf8(); | 97 std::string content_language = document.contentLanguage().utf8(); |
101 std::string html_lang = | |
102 document.documentElement().getAttribute("lang").utf8(); | |
103 std::string cld_language; | 98 std::string cld_language; |
104 bool is_cld_reliable; | 99 bool is_cld_reliable; |
105 std::string language = DeterminePageLanguage( | 100 std::string language = DeterminePageLanguage( |
106 content_language, html_lang, contents, &cld_language, &is_cld_reliable); | 101 content_language, contents, &cld_language, &is_cld_reliable); |
107 | 102 |
108 if (language.empty()) | 103 if (language.empty()) |
109 return; | 104 return; |
110 | 105 |
111 language_determined_time_ = base::TimeTicks::Now(); | 106 language_determined_time_ = base::TimeTicks::Now(); |
112 | 107 |
113 // TODO(toyoshim): Add |html_lang| to LanguageDetectionDetails. | |
114 GURL url(document.url()); | 108 GURL url(document.url()); |
115 LanguageDetectionDetails details; | 109 LanguageDetectionDetails details; |
116 details.time = base::Time::Now(); | 110 details.time = base::Time::Now(); |
117 details.url = url; | 111 details.url = url; |
118 details.content_language = content_language; | 112 details.content_language = content_language; |
119 details.cld_language = cld_language; | 113 details.cld_language = cld_language; |
120 details.is_cld_reliable = is_cld_reliable; | 114 details.is_cld_reliable = is_cld_reliable; |
121 details.adopted_language = language; | 115 details.adopted_language = language; |
122 | 116 |
123 Send(new ChromeViewHostMsg_TranslateLanguageDetermined( | 117 Send(new ChromeViewHostMsg_TranslateLanguageDetermined( |
(...skipping 194 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
318 // Roughly check if the language code follows [a-z][a-z](-[A-Z][A-Z]). | 312 // Roughly check if the language code follows [a-z][a-z](-[A-Z][A-Z]). |
319 size_t dash_index = code->find('-'); | 313 size_t dash_index = code->find('-'); |
320 if (!(dash_index == 2 && code->size() == 5) && | 314 if (!(dash_index == 2 && code->size() == 5) && |
321 !(dash_index == std::string::npos && code->size() == 2)) { | 315 !(dash_index == std::string::npos && code->size() == 2)) { |
322 // Reset |language| to ignore the invalid code. | 316 // Reset |language| to ignore the invalid code. |
323 *code = std::string(); | 317 *code = std::string(); |
324 } | 318 } |
325 } | 319 } |
326 | 320 |
327 // static | 321 // static |
328 void TranslateHelper::ApplyLanguageCodeCorrection(std::string* code) { | |
329 // Correct well-known format errors. | |
330 CorrectLanguageCodeTypo(code); | |
331 | |
332 // Convert language code synonym firstly because sometime synonym code is in | |
333 // invalid format, e.g. 'fil'. After validation, such a 3 characters language | |
334 // gets converted to an empty string. | |
335 ConvertLanguageCodeSynonym(code); | |
336 ResetInvalidLanguageCode(code); | |
337 } | |
338 | |
339 // static | |
340 std::string TranslateHelper::DeterminePageLanguage(const std::string& code, | 322 std::string TranslateHelper::DeterminePageLanguage(const std::string& code, |
341 const std::string& html_lang, | |
342 const string16& contents, | 323 const string16& contents, |
343 std::string* cld_language_p, | 324 std::string* cld_language_p, |
344 bool* is_cld_reliable_p) { | 325 bool* is_cld_reliable_p) { |
345 #if defined(ENABLE_LANGUAGE_DETECTION) | 326 #if defined(ENABLE_LANGUAGE_DETECTION) |
346 base::TimeTicks begin_time = base::TimeTicks::Now(); | 327 base::TimeTicks begin_time = base::TimeTicks::Now(); |
347 bool is_cld_reliable; | 328 bool is_cld_reliable; |
348 std::string cld_language = DetermineTextLanguage(contents, &is_cld_reliable); | 329 std::string cld_language = DetermineTextLanguage(contents, &is_cld_reliable); |
349 TranslateHelperMetrics::ReportLanguageDetectionTime(begin_time, | 330 TranslateHelperMetrics::ReportLanguageDetectionTime(begin_time, |
350 base::TimeTicks::Now()); | 331 base::TimeTicks::Now()); |
351 | 332 |
352 if (cld_language_p != NULL) | 333 if (cld_language_p != NULL) |
353 *cld_language_p = cld_language; | 334 *cld_language_p = cld_language; |
354 if (is_cld_reliable_p != NULL) | 335 if (is_cld_reliable_p != NULL) |
355 *is_cld_reliable_p = is_cld_reliable; | 336 *is_cld_reliable_p = is_cld_reliable; |
356 ConvertLanguageCodeSynonym(&cld_language); | 337 ConvertLanguageCodeSynonym(&cld_language); |
357 #endif // defined(ENABLE_LANGUAGE_DETECTION) | 338 #endif // defined(ENABLE_LANGUAGE_DETECTION) |
358 | 339 |
359 // Check if html lang attribute is valid. | 340 // Correct well-known format errors. |
360 std::string modified_html_lang; | 341 std::string language = code; |
361 if (!html_lang.empty()) { | 342 CorrectLanguageCodeTypo(&language); |
362 modified_html_lang = html_lang; | |
363 ApplyLanguageCodeCorrection(&modified_html_lang); | |
364 TranslateHelperMetrics::ReportHtmlLang(html_lang, modified_html_lang); | |
365 VLOG(9) << "html lang based language code: " << modified_html_lang; | |
366 } | |
367 | 343 |
368 // Check if Content-Language is valid. | 344 // Convert language code synonym firstly because sometime synonym code is in |
369 std::string modified_code; | 345 // invalid format, e.g. 'fil'. After validation, such a 3 characters language |
370 if (!code.empty()) { | 346 // gets converted to an empty string. |
371 modified_code = code; | 347 ConvertLanguageCodeSynonym(&language); |
372 ApplyLanguageCodeCorrection(&modified_code); | 348 ResetInvalidLanguageCode(&language); |
373 TranslateHelperMetrics::ReportContentLanguage(code, modified_code); | |
374 } | |
375 | 349 |
376 // Adopt |modified_html_lang| if it is valid. Otherwise, adopt | 350 TranslateHelperMetrics::ReportContentLanguage(code, language); |
377 // |modified_code|. | |
378 std::string language = modified_html_lang.empty() ? modified_code : | |
379 modified_html_lang; | |
380 | 351 |
381 #if defined(ENABLE_LANGUAGE_DETECTION) | 352 #if defined(ENABLE_LANGUAGE_DETECTION) |
382 // If |language| is empty, just use CLD result even though it might be | 353 // If |language| is empty, just use CLD result even though it might be |
383 // chrome::kUnknownLanguageCode. | 354 // chrome::kUnknownLanguageCode. |
384 if (language.empty()) { | 355 if (language.empty()) { |
385 TranslateHelperMetrics::ReportLanguageVerification( | 356 TranslateHelperMetrics::ReportLanguageVerification( |
386 TranslateHelperMetrics::LANGUAGE_VERIFICATION_CLD_ONLY); | 357 TranslateHelperMetrics::LANGUAGE_VERIFICATION_CLD_ONLY); |
387 return cld_language; | 358 return cld_language; |
388 } | 359 } |
389 | 360 |
(...skipping 65 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
455 IPC_MESSAGE_HANDLER(ChromeViewMsg_RevertTranslation, OnRevertTranslation) | 426 IPC_MESSAGE_HANDLER(ChromeViewMsg_RevertTranslation, OnRevertTranslation) |
456 IPC_MESSAGE_UNHANDLED(handled = false) | 427 IPC_MESSAGE_UNHANDLED(handled = false) |
457 IPC_END_MESSAGE_MAP() | 428 IPC_END_MESSAGE_MAP() |
458 return handled; | 429 return handled; |
459 } | 430 } |
460 | 431 |
461 void TranslateHelper::OnTranslatePage(int page_id, | 432 void TranslateHelper::OnTranslatePage(int page_id, |
462 const std::string& translate_script, | 433 const std::string& translate_script, |
463 const std::string& source_lang, | 434 const std::string& source_lang, |
464 const std::string& target_lang) { | 435 const std::string& target_lang) { |
465 WebFrame* main_frame = GetMainFrame(); | 436 if (render_view()->GetPageId() != page_id) |
466 if (!main_frame || render_view()->GetPageId() != page_id) | |
467 return; // We navigated away, nothing to do. | 437 return; // We navigated away, nothing to do. |
468 | 438 |
469 if (translation_pending_ && page_id == page_id_ && | 439 if (translation_pending_ && page_id == page_id_ && |
470 target_lang_ == target_lang) { | 440 target_lang_ == target_lang) { |
471 // A similar translation is already under way, nothing to do. | 441 // A similar translation is already under way, nothing to do. |
472 return; | 442 return; |
473 } | 443 } |
474 | 444 |
475 // Any pending translation is now irrelevant. | 445 // Any pending translation is now irrelevant. |
476 CancelPendingTranslation(); | 446 CancelPendingTranslation(); |
477 | 447 |
478 // Set our states. | 448 // Set our states. |
479 translation_pending_ = true; | 449 translation_pending_ = true; |
480 page_id_ = page_id; | 450 page_id_ = page_id; |
481 // If the source language is undetermined, we'll let the translate element | 451 // If the source language is undetermined, we'll let the translate element |
482 // detect it. | 452 // detect it. |
483 source_lang_ = (source_lang != chrome::kUnknownLanguageCode) ? | 453 source_lang_ = (source_lang != chrome::kUnknownLanguageCode) ? |
484 source_lang : kAutoDetectionLanguage; | 454 source_lang : kAutoDetectionLanguage; |
485 target_lang_ = target_lang; | 455 target_lang_ = target_lang; |
486 | 456 |
487 TranslateHelperMetrics::ReportUserActionDuration(language_determined_time_, | 457 TranslateHelperMetrics::ReportUserActionDuration(language_determined_time_, |
488 base::TimeTicks::Now()); | 458 base::TimeTicks::Now()); |
489 | 459 |
490 GURL url(main_frame->document().url()); | 460 GURL url(GetMainFrame()->document().url()); |
491 TranslateHelperMetrics::ReportPageScheme(url.scheme()); | 461 TranslateHelperMetrics::ReportPageScheme(url.scheme()); |
492 | 462 |
493 if (!IsTranslateLibAvailable()) { | 463 if (!IsTranslateLibAvailable()) { |
494 // Evaluate the script to add the translation related method to the global | 464 // Evaluate the script to add the translation related method to the global |
495 // context of the page. | 465 // context of the page. |
496 ExecuteScript(translate_script); | 466 ExecuteScript(translate_script); |
497 DCHECK(IsTranslateLibAvailable()); | 467 DCHECK(IsTranslateLibAvailable()); |
498 } | 468 } |
499 | 469 |
500 TranslatePageImpl(0); | 470 TranslatePageImpl(0); |
(...skipping 112 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
613 TranslateErrors::Type error) { | 583 TranslateErrors::Type error) { |
614 translation_pending_ = false; | 584 translation_pending_ = false; |
615 // Notify the browser there was an error. | 585 // Notify the browser there was an error. |
616 render_view()->Send(new ChromeViewHostMsg_PageTranslated( | 586 render_view()->Send(new ChromeViewHostMsg_PageTranslated( |
617 render_view()->GetRoutingID(), page_id_, source_lang_, | 587 render_view()->GetRoutingID(), page_id_, source_lang_, |
618 target_lang_, error)); | 588 target_lang_, error)); |
619 } | 589 } |
620 | 590 |
621 WebFrame* TranslateHelper::GetMainFrame() { | 591 WebFrame* TranslateHelper::GetMainFrame() { |
622 WebView* web_view = render_view()->GetWebView(); | 592 WebView* web_view = render_view()->GetWebView(); |
623 | 593 if (!web_view) { |
624 // When the tab is going to be closed, the web_view can be NULL. | 594 // When the WebView is going away, the render view should have called |
625 if (!web_view) | 595 // CancelPendingTranslation() which should have stopped any pending work, so |
| 596 // that case should not happen. |
| 597 NOTREACHED(); |
626 return NULL; | 598 return NULL; |
627 | 599 } |
628 return web_view->mainFrame(); | 600 return web_view->mainFrame(); |
629 } | 601 } |
OLD | NEW |