diff options
author | droger@chromium.org <droger@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2014-02-07 08:18:09 +0000 |
---|---|---|
committer | droger@chromium.org <droger@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2014-02-07 08:18:09 +0000 |
commit | 8bb49f306e67620b70e8a8114223879a3b6521ea (patch) | |
tree | 1ff60b9d87b7c323d0fc201888bc98d4d6b55168 /components/translate | |
parent | d9a7cf7a118a3369c17095277b3f605bd9c36d04 (diff) | |
download | chromium_src-8bb49f306e67620b70e8a8114223879a3b6521ea.zip chromium_src-8bb49f306e67620b70e8a8114223879a3b6521ea.tar.gz chromium_src-8bb49f306e67620b70e8a8114223879a3b6521ea.tar.bz2 |
Move the translate script to the Translate component
This CL moves the TranslateScript class and the translate.js script.
A new translate_resources target is created.
BUG=335074
TBR=jochen
Review URL: https://codereview.chromium.org/138933006
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@249620 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'components/translate')
9 files changed, 718 insertions, 3 deletions
diff --git a/components/translate/DEPS b/components/translate/DEPS index 64ab5b8..21d3161 100644 --- a/components/translate/DEPS +++ b/components/translate/DEPS @@ -1,6 +1,7 @@ include_rules = [ "+components/language_usage_metrics", "+google_apis", + "+grit", # For generated headers. "+net", "+ui", diff --git a/components/translate/core/browser/resources/translate.js b/components/translate/core/browser/resources/translate.js new file mode 100644 index 0000000..fb59e66 --- /dev/null +++ b/components/translate/core/browser/resources/translate.js @@ -0,0 +1,314 @@ +// Copyright 2014 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. + +// This code is used in conjunction with the Google Translate Element script. +// It is executed in an isolated world of a page to translate it from one +// language to another. +// It should be included in the page before the Translate Element script. + +var cr = cr || {}; + +/** + * An object to provide functions to interact with the Translate library. + * @type {object} + */ +cr.googleTranslate = (function() { + /** + * The Translate Element library's instance. + * @type {object} + */ + var lib; + + /** + * A flag representing if the Translate Element library is initialized. + * @type {boolean} + */ + var libReady = false; + + /** + * Error definitions for |errorCode|. See chrome/common/translate_errors.h + * to modify the definition. + * @const + */ + var ERROR = { + 'NONE': 0, + 'INITIALIZATION_ERROR': 2, + 'UNSUPPORTED_LANGUAGE': 4, + 'TRANSLATION_ERROR': 6, + 'TRANSLATION_TIMEOUT': 7, + 'UNEXPECTED_SCRIPT_ERROR': 8, + 'BAD_ORIGIN': 9, + 'SCRIPT_LOAD_ERROR': 10 + }; + + /** + * Error code map from te.dom.DomTranslator.Error to |errorCode|. + * See also go/dom_translator.js in google3. + * @const + */ + var TRANSLATE_ERROR_TO_ERROR_CODE_MAP = { + 0: ERROR['NONE'], + 1: ERROR['TRANSLATION_ERROR'], + 2: ERROR['UNSUPPORTED_LANGUAGE'] + }; + + /** + * An error code happened in translate.js and the Translate Element library. + */ + var errorCode = ERROR['NONE']; + + /** + * A flag representing if the Translate Element has finished a translation. + * @type {boolean} + */ + var finished = false; + + /** + * Counts how many times the checkLibReady function is called. The function + * is called in every 100 msec and counted up to 6. + * @type {number} + */ + var checkReadyCount = 0; + + /** + * Time in msec when this script is injected. + * @type {number} + */ + var injectedTime = performance.now(); + + /** + * Time in msec when the Translate Element library is loaded completely. + * @type {number} + */ + var loadedTime = 0.0; + + /** + * Time in msec when the Translate Element library is initialized and ready + * for performing translation. + * @type {number} + */ + var readyTime = 0.0; + + /** + * Time in msec when the Translate Element library starts a translation. + * @type {number} + */ + var startTime = 0.0; + + /** + * Time in msec when the Translate Element library ends a translation. + * @type {number} + */ + var endTime = 0.0; + + function checkLibReady() { + if (lib.isAvailable()) { + readyTime = performance.now(); + libReady = true; + return; + } + if (checkReadyCount++ > 5) { + errorCode = ERROR['TRANSLATION_TIMEOUT']; + return; + } + setTimeout(checkLibReady, 100); + } + + function onTranslateProgress(progress, opt_finished, opt_error) { + finished = opt_finished; + // opt_error can be 'undefined'. + if (typeof opt_error == 'boolean' && opt_error) { + // TODO(toyoshim): Remove boolean case once a server is updated. + errorCode = ERROR['TRANSLATION_ERROR']; + // We failed to translate, restore so the page is in a consistent state. + lib.restore(); + } else if (typeof opt_error == 'number' && opt_error != 0) { + errorCode = TRANSLATE_ERROR_TO_ERROR_CODE_MAP[opt_error]; + lib.restore(); + } + if (finished) + endTime = performance.now(); + } + + // Public API. + return { + /** + * Whether the library is ready. + * The translate function should only be called when |libReady| is true. + * @type {boolean} + */ + get libReady() { + return libReady; + }, + + /** + * Whether the current translate has finished successfully. + * @type {boolean} + */ + get finished() { + return finished; + }, + + /** + * Whether an error occured initializing the library of translating the + * page. + * @type {boolean} + */ + get error() { + return errorCode != ERROR['NONE']; + }, + + /** + * Returns a number to represent error type. + * @type {number} + */ + get errorCode() { + return errorCode; + }, + + /** + * The language the page translated was in. Is valid only after the page + * has been successfully translated and the original language specified to + * the translate function was 'auto'. Is empty otherwise. + * Some versions of Element library don't provide |getDetectedLanguage| + * function. In that case, this function returns 'und'. + * @type {boolean} + */ + get sourceLang() { + if (!libReady || !finished || errorCode != ERROR['NONE']) + return ''; + if (!lib.getDetectedLanguage) + return 'und'; // Defined as translate::kUnknownLanguageCode in C++. + return lib.getDetectedLanguage(); + }, + + /** + * Time in msec from this script being injected to all server side scripts + * being loaded. + * @type {number} + */ + get loadTime() { + if (loadedTime == 0) + return 0; + return loadedTime - injectedTime; + }, + + /** + * Time in msec from this script being injected to the Translate Element + * library being ready. + * @type {number} + */ + get readyTime() { + if (!libReady) + return 0; + return readyTime - injectedTime; + }, + + /** + * Time in msec to perform translation. + * @type {number} + */ + get translationTime() { + if (!finished) + return 0; + return endTime - startTime; + }, + + /** + * Translate the page contents. Note that the translation is asynchronous. + * You need to regularly check the state of |finished| and |errorCode| to + * know if the translation finished or if there was an error. + * @param {string} originalLang The language the page is in. + * @param {string} targetLang The language the page should be translated to. + * @return {boolean} False if the translate library was not ready, in which + * case the translation is not started. True otherwise. + */ + translate: function(originalLang, targetLang) { + finished = false; + errorCode = ERROR['NONE']; + if (!libReady) + return false; + startTime = performance.now(); + try { + lib.translatePage(originalLang, targetLang, onTranslateProgress); + } catch (err) { + console.error('Translate: ' + err); + errorCode = ERROR['UNEXPECTED_SCRIPT_ERROR']; + return false; + } + return true; + }, + + /** + * Reverts the page contents to its original value, effectively reverting + * any performed translation. Does nothing if the page was not translated. + */ + revert: function() { + lib.restore(); + }, + + /** + * Entry point called by the Translate Element once it has been injected in + * the page. + */ + onTranslateElementLoad: function() { + loadedTime = performance.now(); + try { + lib = google.translate.TranslateService({ + // translateApiKey is predefined by translate_script.cc. + 'key': translateApiKey, + 'useSecureConnection': true + }); + translateApiKey = undefined; + } catch (err) { + errorCode = ERROR['INITIALIZATION_ERROR']; + translateApiKey = undefined; + return; + } + // The TranslateService is not available immediately as it needs to start + // Flash. Let's wait until it is ready. + checkLibReady(); + }, + + /** + * Entry point called by the Translate Element when it want to load an + * external CSS resource into the page. + * @param {string} url URL of an external CSS resource to load. + */ + onLoadCSS: function(url) { + var element = document.createElement('link'); + element.type = 'text/css'; + element.rel = 'stylesheet'; + element.charset = 'UTF-8'; + element.href = url; + document.head.appendChild(element); + }, + + /** + * Entry point called by the Translate Element when it want to load and run + * an external JavaScript on the page. + * @param {string} url URL of an external JavaScript to load. + */ + onLoadJavascript: function(url) { + // securityOrigin is predefined by translate_script.cc. + if (url.indexOf(securityOrigin) != 0) { + console.error('Translate: ' + url + ' is not allowed to load.'); + errorCode = ERROR['BAD_ORIGIN']; + return; + } + var xhr = new XMLHttpRequest(); + xhr.open('GET', url, true); + xhr.onreadystatechange = function() { + if (this.readyState != this.DONE) + return; + if (this.status != 200) { + errorCode = ERROR['SCRIPT_LOAD_ERROR']; + return; + } + eval(this.responseText); + } + xhr.send(); + } + }; +})(); diff --git a/components/translate/core/browser/translate_download_manager.cc b/components/translate/core/browser/translate_download_manager.cc index 4542d20..9d1898c 100644 --- a/components/translate/core/browser/translate_download_manager.cc +++ b/components/translate/core/browser/translate_download_manager.cc @@ -16,12 +16,14 @@ TranslateDownloadManager* TranslateDownloadManager::GetInstance() { } TranslateDownloadManager::TranslateDownloadManager() - : language_list_(new TranslateLanguageList) {} + : language_list_(new TranslateLanguageList), + script_(new TranslateScript) {} TranslateDownloadManager::~TranslateDownloadManager() {} void TranslateDownloadManager::Shutdown() { language_list_.reset(); + script_.reset(); request_context_ = NULL; } @@ -106,3 +108,19 @@ bool TranslateDownloadManager::IsAlphaLanguage(const std::string& language) { return language_list->IsAlphaLanguage(language); } + +void TranslateDownloadManager::ClearTranslateScriptForTesting() { + if (script_.get() == NULL) { + NOTREACHED(); + return; + } + script_->Clear(); +} + +void TranslateDownloadManager::SetTranslateScriptExpirationDelay(int delay_ms) { + if (script_.get() == NULL) { + NOTREACHED(); + return; + } + script_->set_expiration_delay(delay_ms); +} diff --git a/components/translate/core/browser/translate_download_manager.h b/components/translate/core/browser/translate_download_manager.h index 6cffd27..f8dcae5 100644 --- a/components/translate/core/browser/translate_download_manager.h +++ b/components/translate/core/browser/translate_download_manager.h @@ -11,6 +11,7 @@ #include "base/memory/ref_counted.h" #include "base/memory/scoped_ptr.h" #include "components/translate/core/browser/translate_language_list.h" +#include "components/translate/core/browser/translate_script.h" #include "net/url_request/url_request_context_getter.h" template <typename T> struct DefaultSingletonTraits; @@ -19,8 +20,6 @@ class PrefService; // Manages the downloaded resources for Translate, such as the translate script // and the language list. -// TODO(droger): TranslateDownloadManager should own TranslateScript. -// See http://crbug.com/335074. class TranslateDownloadManager { public: // Returns the singleton instance. @@ -46,6 +45,9 @@ class TranslateDownloadManager { // The language list. TranslateLanguageList* language_list() { return language_list_.get(); } + // The translate script. + TranslateScript* script() { return script_.get(); } + // Let the caller decide if and when we should fetch the language list from // the translate server. This is a NOOP if switches::kDisableTranslate is set // or if prefs::kEnableTranslate is set to false. @@ -77,12 +79,25 @@ class TranslateDownloadManager { // Must be called to shut Translate down. Cancels any pending fetches. void Shutdown(); + // Clears the translate script, so it will be fetched next time we translate. + void ClearTranslateScriptForTesting(); + + // Used by unit-tests to override some defaults: + // Delay after which the translate script is fetched again from the + // translation server. + void SetTranslateScriptExpirationDelay(int delay_ms); + private: friend struct DefaultSingletonTraits<TranslateDownloadManager>; TranslateDownloadManager(); virtual ~TranslateDownloadManager(); scoped_ptr<TranslateLanguageList> language_list_; + + // An instance of TranslateScript which manages JavaScript source for + // Translate. + scoped_ptr<TranslateScript> script_; + std::string application_locale_; scoped_refptr<net::URLRequestContextGetter> request_context_; }; diff --git a/components/translate/core/browser/translate_script.cc b/components/translate/core/browser/translate_script.cc new file mode 100644 index 0000000..a83f499 --- /dev/null +++ b/components/translate/core/browser/translate_script.cc @@ -0,0 +1,149 @@ +// Copyright 2014 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 "components/translate/core/browser/translate_script.h" + +#include "base/bind.h" +#include "base/command_line.h" +#include "base/logging.h" +#include "base/message_loop/message_loop.h" +#include "base/strings/string_piece.h" +#include "base/strings/string_util.h" +#include "base/strings/stringprintf.h" +#include "components/translate/core/browser/translate_url_fetcher.h" +#include "components/translate/core/browser/translate_url_util.h" +#include "components/translate/core/common/translate_switches.h" +#include "components/translate/core/common/translate_util.h" +#include "google_apis/google_api_keys.h" +#include "grit/component_resources.h" +#include "net/base/escape.h" +#include "net/base/url_util.h" +#include "ui/base/resource/resource_bundle.h" + +namespace { + +const int kExpirationDelayDays = 1; + +} // namespace + +const char TranslateScript::kScriptURL[] = + "https://translate.google.com/translate_a/element.js"; +const char TranslateScript::kRequestHeader[] = + "Google-Translate-Element-Mode: library"; +const char TranslateScript::kAlwaysUseSslQueryName[] = "aus"; +const char TranslateScript::kAlwaysUseSslQueryValue[] = "true"; +const char TranslateScript::kCallbackQueryName[] = "cb"; +const char TranslateScript::kCallbackQueryValue[] = + "cr.googleTranslate.onTranslateElementLoad"; +const char TranslateScript::kCssLoaderCallbackQueryName[] = "clc"; +const char TranslateScript::kCssLoaderCallbackQueryValue[] = + "cr.googleTranslate.onLoadCSS"; +const char TranslateScript::kJavascriptLoaderCallbackQueryName[] = "jlc"; +const char TranslateScript::kJavascriptLoaderCallbackQueryValue[] = + "cr.googleTranslate.onLoadJavascript"; + +TranslateScript::TranslateScript() + : expiration_delay_(base::TimeDelta::FromDays(kExpirationDelayDays)), + weak_method_factory_(this) { +} + +TranslateScript::~TranslateScript() { +} + +void TranslateScript::Request(const Callback& callback) { + if (fetcher_.get() != NULL) { + NOTREACHED(); + return; + } + + callback_ = callback; + + GURL translate_script_url; + // Check if command-line contains an alternative URL for translate service. + const CommandLine& command_line = *CommandLine::ForCurrentProcess(); + if (command_line.HasSwitch(translate::switches::kTranslateScriptURL)) { + translate_script_url = GURL(command_line.GetSwitchValueASCII( + translate::switches::kTranslateScriptURL)); + if (!translate_script_url.is_valid() || + !translate_script_url.query().empty()) { + LOG(WARNING) << "The following translate URL specified at the " + << "command-line is invalid: " + << translate_script_url.spec(); + translate_script_url = GURL(); + } + } + + // Use default URL when command-line argument is not specified, or specified + // URL is invalid. + if (translate_script_url.is_empty()) + translate_script_url = GURL(kScriptURL); + + translate_script_url = net::AppendQueryParameter( + translate_script_url, + kCallbackQueryName, + kCallbackQueryValue); + translate_script_url = net::AppendQueryParameter( + translate_script_url, + kAlwaysUseSslQueryName, + kAlwaysUseSslQueryValue); +#if !defined(OS_IOS) + // iOS doesn't need to use specific loaders for the isolated world. + translate_script_url = net::AppendQueryParameter( + translate_script_url, + kCssLoaderCallbackQueryName, + kCssLoaderCallbackQueryValue); + translate_script_url = net::AppendQueryParameter( + translate_script_url, + kJavascriptLoaderCallbackQueryName, + kJavascriptLoaderCallbackQueryValue); +#endif // !defined(OS_IOS) + + translate_script_url = + TranslateURLUtil::AddHostLocaleToUrl(translate_script_url); + translate_script_url = + TranslateURLUtil::AddApiKeyToUrl(translate_script_url); + + fetcher_.reset(new TranslateURLFetcher(kFetcherId)); + fetcher_->set_extra_request_header(kRequestHeader); + fetcher_->Request( + translate_script_url, + base::Bind(&TranslateScript::OnScriptFetchComplete, + base::Unretained(this))); +} + + +void TranslateScript::OnScriptFetchComplete( + int id, bool success, const std::string& data) { + DCHECK_EQ(kFetcherId, id); + + scoped_ptr<const TranslateURLFetcher> delete_ptr(fetcher_.release()); + + if (success) { + DCHECK(data_.empty()); + // Insert variable definitions on API Key and security origin. + data_ = base::StringPrintf("var translateApiKey = '%s';\n", + google_apis::GetAPIKey().c_str()); + + GURL security_origin = translate::GetTranslateSecurityOrigin(); + base::StringAppendF( + &data_, "var securityOrigin = '%s';", security_origin.spec().c_str()); + + // Append embedded translate.js and a remote element library. + base::StringPiece str = ResourceBundle::GetSharedInstance(). + GetRawDataResource(IDR_TRANSLATE_JS); + str.AppendToString(&data_); + data_ += data; + + // We'll expire the cached script after some time, to make sure long + // running browsers still get fixes that might get pushed with newer + // scripts. + base::MessageLoop::current()->PostDelayedTask( + FROM_HERE, + base::Bind(&TranslateScript::Clear, + weak_method_factory_.GetWeakPtr()), + expiration_delay_); + } + + callback_.Run(success, data); +} diff --git a/components/translate/core/browser/translate_script.h b/components/translate/core/browser/translate_script.h new file mode 100644 index 0000000..552daee --- /dev/null +++ b/components/translate/core/browser/translate_script.h @@ -0,0 +1,94 @@ +// Copyright 2014 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. + +#ifndef COMPONENTS_TRANSLATE_CORE_BROWSER_TRANSLATE_SCRIPT_H_ +#define COMPONENTS_TRANSLATE_CORE_BROWSER_TRANSLATE_SCRIPT_H_ + +#include <string> + +#include "base/callback.h" +#include "base/gtest_prod_util.h" +#include "base/memory/scoped_ptr.h" +#include "base/memory/weak_ptr.h" +#include "base/time/time.h" + +class TranslateScriptTest; +class TranslateURLFetcher; + +class TranslateScript { + public: + typedef base::Callback<void(bool, const std::string&)> Callback; + + static const int kFetcherId = 0; + + TranslateScript(); + virtual ~TranslateScript(); + + // Returns the feched the translate script. + const std::string& data() { return data_; } + + // Used by unit-tests to override some defaults: + // Delay after which the translate script is fetched again from the + // translation server. + void set_expiration_delay(int delay_ms) { + expiration_delay_ = base::TimeDelta::FromMilliseconds(delay_ms); + } + + // Clears the translate script, so it will be fetched next time we translate. + void Clear() { data_.clear(); } + + // Fetches the JS translate script (the script that is injected in the page + // to translate it). + void Request(const Callback& callback); + + // Returns true if this has a pending request. + bool HasPendingRequest() const { return fetcher_.get() != NULL; } + + private: + friend class TranslateScriptTest; + FRIEND_TEST_ALL_PREFIXES(TranslateScriptTest, CheckScriptParameters); + FRIEND_TEST_ALL_PREFIXES(TranslateScriptTest, CheckScriptURL); + + static const char kScriptURL[]; + static const char kRequestHeader[]; + + // Used in kTranslateScriptURL to specify using always ssl to load resources. + static const char kAlwaysUseSslQueryName[]; + static const char kAlwaysUseSslQueryValue[]; + + // Used in kTranslateScriptURL to specify a callback function name. + static const char kCallbackQueryName[]; + static const char kCallbackQueryValue[]; + + // Used in kTranslateScriptURL to specify a CSS loader callback function name. + static const char kCssLoaderCallbackQueryName[]; + static const char kCssLoaderCallbackQueryValue[]; + + // Used in kTranslateScriptURL to specify a JavaScript loader callback + // function name. + static const char kJavascriptLoaderCallbackQueryName[]; + static const char kJavascriptLoaderCallbackQueryValue[]; + + // The callback when the script is fetched or a server error occured. + void OnScriptFetchComplete(int id, bool success, const std::string& data); + + // URL fetcher to fetch the translate script. + scoped_ptr<TranslateURLFetcher> fetcher_; + + // The JS injected in the page to do the translation. + std::string data_; + + // Delay after which the translate script is fetched again from the translate + // server. + base::TimeDelta expiration_delay_; + + // The callback called when the server sends a response. + Callback callback_; + + base::WeakPtrFactory<TranslateScript> weak_method_factory_; + + DISALLOW_COPY_AND_ASSIGN(TranslateScript); +}; + +#endif // COMPONENTS_TRANSLATE_CORE_BROWSER_TRANSLATE_SCRIPT_H_ diff --git a/components/translate/core/browser/translate_script_unittest.cc b/components/translate/core/browser/translate_script_unittest.cc new file mode 100644 index 0000000..c8e3316 --- /dev/null +++ b/components/translate/core/browser/translate_script_unittest.cc @@ -0,0 +1,120 @@ +// Copyright 2014 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 "components/translate/core/browser/translate_script.h" + +#include "base/bind.h" +#include "base/command_line.h" +#include "base/strings/stringprintf.h" +#include "components/translate/core/browser/translate_download_manager.h" +#include "components/translate/core/common/translate_switches.h" +#include "net/base/load_flags.h" +#include "net/base/url_util.h" +#include "net/http/http_request_headers.h" +#include "net/url_request/test_url_fetcher_factory.h" +#include "testing/gtest/include/gtest/gtest.h" +#include "url/gurl.h" + +class TranslateScriptTest : public testing::Test { + public: + TranslateScriptTest() : testing::Test() {} + + protected: + virtual void SetUp() { + script_.reset(new TranslateScript); + DCHECK(script_.get()); + TranslateDownloadManager::GetInstance()->set_application_locale("en"); + } + + virtual void TearDown() { + script_.reset(); + } + + void Request() { + script_->Request( + base::Bind(&TranslateScriptTest::OnComplete, base::Unretained(this))); + } + + net::TestURLFetcher* GetTestURLFetcher() { + return url_fetcher_factory_.GetFetcherByID(TranslateScript::kFetcherId); + } + + private: + void OnComplete(bool success, const std::string& script) { + } + + scoped_ptr<TranslateScript> script_; + net::TestURLFetcherFactory url_fetcher_factory_; + + DISALLOW_COPY_AND_ASSIGN(TranslateScriptTest); +}; + +TEST_F(TranslateScriptTest, CheckScriptParameters) { + Request(); + net::TestURLFetcher* fetcher = GetTestURLFetcher(); + ASSERT_TRUE(fetcher); + + GURL expected_url(TranslateScript::kScriptURL); + GURL url = fetcher->GetOriginalURL(); + EXPECT_TRUE(url.is_valid()); + EXPECT_EQ(expected_url.GetOrigin().spec(), url.GetOrigin().spec()); + EXPECT_EQ(expected_url.path(), url.path()); + + int load_flags = fetcher->GetLoadFlags(); + EXPECT_EQ(net::LOAD_DO_NOT_SEND_COOKIES, + load_flags & net::LOAD_DO_NOT_SEND_COOKIES); + EXPECT_EQ(net::LOAD_DO_NOT_SAVE_COOKIES, + load_flags & net::LOAD_DO_NOT_SAVE_COOKIES); + + std::string expected_extra_headers = + base::StringPrintf("%s\r\n\r\n", TranslateScript::kRequestHeader); + net::HttpRequestHeaders extra_headers; + fetcher->GetExtraRequestHeaders(&extra_headers); + EXPECT_EQ(expected_extra_headers, extra_headers.ToString()); + + std::string always_use_ssl; + net::GetValueForKeyInQuery( + url, TranslateScript::kAlwaysUseSslQueryName, &always_use_ssl); + EXPECT_EQ(std::string(TranslateScript::kAlwaysUseSslQueryValue), + always_use_ssl); + + std::string callback; + net::GetValueForKeyInQuery( + url, TranslateScript::kCallbackQueryName, &callback); + EXPECT_EQ(std::string(TranslateScript::kCallbackQueryValue), callback); + +#if !defined(OS_IOS) + // iOS does not have specific loaders for the isolated world. + std::string css_loader_callback; + net::GetValueForKeyInQuery( + url, TranslateScript::kCssLoaderCallbackQueryName, &css_loader_callback); + EXPECT_EQ(std::string(TranslateScript::kCssLoaderCallbackQueryValue), + css_loader_callback); + + std::string javascript_loader_callback; + net::GetValueForKeyInQuery( + url, + TranslateScript::kJavascriptLoaderCallbackQueryName, + &javascript_loader_callback); + EXPECT_EQ(std::string(TranslateScript::kJavascriptLoaderCallbackQueryValue), + javascript_loader_callback); +#endif // !defined(OS_IOS) +} + +TEST_F(TranslateScriptTest, CheckScriptURL) { + const std::string script_url("http://www.tamurayukari.com/mero-n.js"); + CommandLine* command_line = CommandLine::ForCurrentProcess(); + command_line->AppendSwitchASCII(translate::switches::kTranslateScriptURL, + script_url); + + Request(); + net::TestURLFetcher* fetcher = GetTestURLFetcher(); + ASSERT_TRUE(fetcher); + + GURL expected_url(script_url); + GURL url = fetcher->GetOriginalURL(); + EXPECT_TRUE(url.is_valid()); + EXPECT_EQ(expected_url.GetOrigin().spec(), url.GetOrigin().spec()); + EXPECT_EQ(expected_url.path(), url.path()); +} diff --git a/components/translate/core/common/translate_switches.cc b/components/translate/core/common/translate_switches.cc index 71fdf12..1ac6f33 100644 --- a/components/translate/core/common/translate_switches.cc +++ b/components/translate/core/common/translate_switches.cc @@ -12,6 +12,9 @@ namespace switches { // disable translate with the preference. const char kDisableTranslate[] = "disable-translate"; +// Overrides the default server used for Google Translate. +const char kTranslateScriptURL[] = "translate-script-url"; + // Overrides security-origin with which Translate runs in an isolated world. const char kTranslateSecurityOrigin[] = "translate-security-origin"; diff --git a/components/translate/core/common/translate_switches.h b/components/translate/core/common/translate_switches.h index 4ab971f..ace4f3a 100644 --- a/components/translate/core/common/translate_switches.h +++ b/components/translate/core/common/translate_switches.h @@ -9,6 +9,7 @@ namespace translate { namespace switches { extern const char kDisableTranslate[]; +extern const char kTranslateScriptURL[]; extern const char kTranslateSecurityOrigin[]; } // namespace switches |