diff options
author | jcivelli@google.com <jcivelli@google.com@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-04-06 22:21:02 +0000 |
---|---|---|
committer | jcivelli@google.com <jcivelli@google.com@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-04-06 22:21:02 +0000 |
commit | 85d252e22b6bec161873a0b5656d59c8ebe04e30 (patch) | |
tree | 937f8add8eac344f93d6a8ec6604796f371c761c /chrome/renderer/translate_helper.cc | |
parent | d41661b5e24c8d774acea07c05ef2e5896587e56 (diff) | |
download | chromium_src-85d252e22b6bec161873a0b5656d59c8ebe04e30.zip chromium_src-85d252e22b6bec161873a0b5656d59c8ebe04e30.tar.gz chromium_src-85d252e22b6bec161873a0b5656d59c8ebe04e30.tar.bz2 |
Changing the translate back-end to use the Google Translate element.
When the user indicates that a page should be translated, the browser first fetches the Google Translate Element JS code.
It then sends it to the renderer, which injects the script in the page, waits for the Translate element to be initialized and then calls the translate method on it.
The TranslationService class previously used to translate text chunks is now unused and has been removed. Some of its static methods that are still used have been moved to the TranslateManager class.
This CL also implements the "revert" translation behavior.
BUG=35474,37778,35553,39375
TEST=Test the translation feature extensively.
Review URL: http://codereview.chromium.org/1599016
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@43768 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome/renderer/translate_helper.cc')
-rw-r--r-- | chrome/renderer/translate_helper.cc | 230 |
1 files changed, 230 insertions, 0 deletions
diff --git a/chrome/renderer/translate_helper.cc b/chrome/renderer/translate_helper.cc new file mode 100644 index 0000000..f2a3f66 --- /dev/null +++ b/chrome/renderer/translate_helper.cc @@ -0,0 +1,230 @@ +// Copyright (c) 2010 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/renderer/translate_helper.h" + +#include "base/compiler_specific.h" +#include "chrome/renderer/render_view.h" +#include "third_party/WebKit/WebKit/chromium/public/WebFrame.h" +#include "third_party/WebKit/WebKit/chromium/public/WebScriptSource.h" + +using WebKit::WebFrame; +using WebKit::WebScriptSource; + +// The delay in millliseconds that we'll wait before checking to see if the +// translate library injected in the page is ready. +static const int kTranslateInitCheckDelayMs = 150; + +// The maximum number of times we'll check to see if the translate library +// injected in the page is ready. +static const int kMaxTranslateInitCheckAttempts = 5; + +// The delay we wait in milliseconds before checking whether the translation has +// finished. +static const int kTranslateStatusCheckDelayMs = 400; + +//////////////////////////////////////////////////////////////////////////////// +// TranslateHelper, public: +// +TranslateHelper::TranslateHelper(RenderView* render_view) + : render_view_(render_view), + ALLOW_THIS_IN_INITIALIZER_LIST(method_factory_(this)) { +} + +void TranslateHelper::TranslatePage(int page_id, + const std::string& source_lang, + const std::string& target_lang, + const std::string& translate_script) { + if (render_view_->page_id() != page_id) + return; // We navigated away, nothing to do. + + if (!IsTranslateLibAvailable()) { + // Evaluate the script to add the translation related method to the global + // context of the page. + ExecuteScript(translate_script); + DCHECK(IsTranslateLibAvailable()); + } + + // Cancel any pending tasks related to a previous translation, they are now + // obsolete. + method_factory_.RevokeAll(); + + TranslatePageImpl(page_id, source_lang, target_lang, 0); +} + +void TranslateHelper::RevertTranslation(int page_id) { + if (render_view_->page_id() != page_id) + return; // We navigated away, nothing to do. + + if (!IsTranslateLibAvailable()) { + NOTREACHED(); + return; + } + + WebFrame* main_frame = render_view_->webview()->mainFrame(); + if (!main_frame) + return; + + main_frame->executeScript( + WebScriptSource(ASCIIToUTF16("cr.googleTranslate.revert()"))); +} + +//////////////////////////////////////////////////////////////////////////////// +// TranslateHelper, protected: +// +bool TranslateHelper::IsTranslateLibAvailable() { + bool lib_available = false; + if (!ExecuteScriptAndGetBoolResult( + "typeof cr != 'undefined' && typeof cr.googleTranslate != 'undefined' && " + "typeof cr.googleTranslate.translate == 'function'", &lib_available)) { + NOTREACHED(); + return false; + } + return lib_available; +} + +bool TranslateHelper::IsTranslateLibReady() { + bool lib_ready = false; + if (!ExecuteScriptAndGetBoolResult("cr.googleTranslate.libReady", + &lib_ready)) { + NOTREACHED(); + return false; + } + return lib_ready; +} + +bool TranslateHelper::HasTranslationFinished() { + bool translation_finished = false; + if (!ExecuteScriptAndGetBoolResult("cr.googleTranslate.finished", + &translation_finished)) { + NOTREACHED() << "crGoogleTranslateGetFinished returned unexpected value."; + return true; + } + + return translation_finished; +} + +bool TranslateHelper::HasTranslationFailed() { + bool translation_failed = false; + if (!ExecuteScriptAndGetBoolResult("cr.googleTranslate.error", + &translation_failed)) { + NOTREACHED() << "crGoogleTranslateGetError returned unexpected value."; + return true; + } + + return translation_failed; +} + +bool TranslateHelper::StartTranslation(const std::string& source_lang, + const std::string& target_lang) { + bool translate_success = false; + if (!ExecuteScriptAndGetBoolResult("cr.googleTranslate.translate('" + + source_lang + "','" + target_lang + "')", + &translate_success)) { + NOTREACHED(); + return false; + } + return translate_success; +} + +//////////////////////////////////////////////////////////////////////////////// +// TranslateHelper, private: +// +void TranslateHelper::CheckTranslateStatus(int page_id, + const std::string& source_lang, + const std::string& target_lang) { + if (page_id != render_view_->page_id()) + return; // This is not the same page, the translation has been canceled. + + // First check if there was an error. + if (HasTranslationFailed()) { + NotifyBrowserTranslationFailed(source_lang, target_lang, + TranslateErrors::TRANSLATION_ERROR); + return; // There was an error. + } + + if (HasTranslationFinished()) { + // Translation was successfull, notify the browser. + render_view_->Send(new ViewHostMsg_PageTranslated( + render_view_->routing_id(), render_view_->page_id(), + source_lang, target_lang, TranslateErrors::NONE)); + return; + } + + // The translation is still pending, check again later. + MessageLoop::current()->PostDelayedTask(FROM_HERE, + method_factory_.NewRunnableMethod(&TranslateHelper::CheckTranslateStatus, + page_id, source_lang, target_lang), + DontDelayTasks() ? 0 : kTranslateStatusCheckDelayMs); +} + +bool TranslateHelper::ExecuteScript(const std::string& script) { + WebFrame* main_frame = render_view_->webview()->mainFrame(); + if (!main_frame) + return false; + main_frame->executeScript(WebScriptSource(ASCIIToUTF16(script))); + return true; +} + +bool TranslateHelper::ExecuteScriptAndGetBoolResult(const std::string& script, + bool* value) { + DCHECK(value); + WebFrame* main_frame = render_view_->webview()->mainFrame(); + if (!main_frame) + return false; + + v8::Handle<v8::Value> v = main_frame->executeScriptAndReturnValue( + WebScriptSource(ASCIIToUTF16(script))); + if (v.IsEmpty() || !v->IsBoolean()) + return false; + + *value = v->BooleanValue(); + return true; +} + +void TranslateHelper::TranslatePageImpl(int page_id, + const std::string& source_lang, + const std::string& target_lang, + int count) { + DCHECK_LT(count, kMaxTranslateInitCheckAttempts); + if (page_id != render_view_->page_id()) + return; + + if (!IsTranslateLibReady()) { + // The library is not ready, try again later, unless we have tried several + // times unsucessfully already. + if (++count >= kMaxTranslateInitCheckAttempts) { + NotifyBrowserTranslationFailed(source_lang, target_lang, + TranslateErrors::INITIALIZATION_ERROR); + return; + } + MessageLoop::current()->PostDelayedTask(FROM_HERE, + method_factory_.NewRunnableMethod(&TranslateHelper::TranslatePageImpl, + page_id, source_lang, target_lang, + count), + DontDelayTasks() ? 0 : count * kTranslateInitCheckDelayMs); + return; + } + + if (!StartTranslation(source_lang, target_lang)) { + NotifyBrowserTranslationFailed(source_lang, target_lang, + TranslateErrors::TRANSLATION_ERROR); + return; + } + // Check the status of the translation. + MessageLoop::current()->PostDelayedTask(FROM_HERE, + method_factory_.NewRunnableMethod(&TranslateHelper::CheckTranslateStatus, + page_id, source_lang, target_lang), + DontDelayTasks() ? 0 : kTranslateStatusCheckDelayMs); +} + +void TranslateHelper::NotifyBrowserTranslationFailed( + const std::string& source_lang, + const std::string& target_lang, + TranslateErrors::Type error) { + // Notify the browser there was an error. + render_view_->Send(new ViewHostMsg_PageTranslated( + render_view_->routing_id(), render_view_->page_id(), + source_lang, target_lang, error)); +} |