diff options
Diffstat (limited to 'chrome/browser')
7 files changed, 135 insertions, 28 deletions
diff --git a/chrome/browser/extensions/content_script_apitest.cc b/chrome/browser/extensions/content_script_apitest.cc index c640eec..acd1a75 100644 --- a/chrome/browser/extensions/content_script_apitest.cc +++ b/chrome/browser/extensions/content_script_apitest.cc @@ -92,3 +92,8 @@ IN_PROC_BROWSER_TEST_F( &styles_injected)); ASSERT_TRUE(styles_injected); } + +IN_PROC_BROWSER_TEST_F(ExtensionApiTest, ContentScriptCSSLocalization) { + ASSERT_TRUE(StartTestServer()); + ASSERT_TRUE(RunExtensionTest("content_scripts/css_l10n")) << message_; +} diff --git a/chrome/browser/extensions/execute_code_in_tab_function.cc b/chrome/browser/extensions/execute_code_in_tab_function.cc index b5eb0d5..5c96195 100644 --- a/chrome/browser/extensions/execute_code_in_tab_function.cc +++ b/chrome/browser/extensions/execute_code_in_tab_function.cc @@ -4,7 +4,6 @@ #include "chrome/browser/extensions/execute_code_in_tab_function.h" -#include "base/callback.h" #include "base/string_util.h" #include "base/utf_string_conversions.h" #include "chrome/browser/extensions/extension_service.h" @@ -17,7 +16,10 @@ #include "chrome/common/extensions/extension.h" #include "chrome/common/extensions/extension_constants.h" #include "chrome/common/extensions/extension_error_utils.h" +#include "chrome/common/extensions/extension_file_util.h" +#include "chrome/common/extensions/extension_l10n_util.h" #include "chrome/common/extensions/extension_messages.h" +#include "chrome/common/extensions/extension_message_bundle.h" #include "content/browser/renderer_host/render_view_host.h" #include "content/browser/tab_contents/tab_contents.h" #include "content/browser/renderer_host/render_view_host.h" @@ -117,13 +119,60 @@ bool ExecuteCodeInTabFunction::RunImpl() { scoped_refptr<FileReader> file_reader(new FileReader( resource_, NewCallback(this, &ExecuteCodeInTabFunction::DidLoadFile))); file_reader->Start(); - AddRef(); // Keep us alive until DidLoadFile is called. + AddRef(); // Keep us alive until DidLoadAndLocalizeFile is called. return true; } void ExecuteCodeInTabFunction::DidLoadFile(bool success, const std::string& data) { + std::string function_name = name(); + const Extension* extension = GetExtension(); + + // Check if the file is CSS and needs localization. + if (success && + function_name == TabsInsertCSSFunction::function_name() && + extension != NULL && + data.find(ExtensionMessageBundle::kMessageBegin) != std::string::npos) { + BrowserThread::PostTask( + BrowserThread::FILE, FROM_HERE, + NewRunnableMethod(this, &ExecuteCodeInTabFunction::LocalizeCSS, + data, + extension->id(), + extension->path(), + extension->default_locale())); + } else { + DidLoadAndLocalizeFile(success, data); + } +} + +void ExecuteCodeInTabFunction::LocalizeCSS( + const std::string& data, + const std::string& extension_id, + const FilePath& extension_path, + const std::string& extension_default_locale) { + scoped_ptr<SubstitutionMap> localization_messages( + extension_file_util::LoadExtensionMessageBundleSubstitutionMap( + extension_path, extension_id, extension_default_locale)); + + // We need to do message replacement on the data, so it has to be mutable. + std::string css_data = data; + std::string error; + ExtensionMessageBundle::ReplaceMessagesWithExternalDictionary( + *localization_messages, &css_data, &error); + + // Call back DidLoadAndLocalizeFile on the UI thread. The success parameter + // is always true, because if loading had failed, we wouldn't have had + // anything to localize. + BrowserThread::PostTask( + BrowserThread::UI, FROM_HERE, + NewRunnableMethod(this, + &ExecuteCodeInTabFunction::DidLoadAndLocalizeFile, + true, css_data)); +} + +void ExecuteCodeInTabFunction::DidLoadAndLocalizeFile(bool success, + const std::string& data) { if (success) { Execute(data); } else { diff --git a/chrome/browser/extensions/execute_code_in_tab_function.h b/chrome/browser/extensions/execute_code_in_tab_function.h index 2dbc115..b57ad49 100644 --- a/chrome/browser/extensions/execute_code_in_tab_function.h +++ b/chrome/browser/extensions/execute_code_in_tab_function.h @@ -33,6 +33,17 @@ class ExecuteCodeInTabFunction : public AsyncExtensionFunction, // arguments has been loaded. void DidLoadFile(bool success, const std::string& data); + // Runs on FILE thread. Loads message bundles for the extension and + // localizes the CSS data. Calls back DidLoadAndLocalizeFile on the UI thread. + void LocalizeCSS( + const std::string& data, + const std::string& extension_id, + const FilePath& extension_path, + const std::string& extension_default_locale); + + // Called when contents from the loaded file have been localized. + void DidLoadAndLocalizeFile(bool success, const std::string& data); + // Run in UI thread. Code string contains the code to be executed. Returns // true on success. If true is returned, this does an AddRef. bool Execute(const std::string& code_string); diff --git a/chrome/browser/extensions/user_script_master.cc b/chrome/browser/extensions/user_script_master.cc index 5e68098..af2abe2 100644 --- a/chrome/browser/extensions/user_script_master.cc +++ b/chrome/browser/extensions/user_script_master.cc @@ -4,6 +4,7 @@ #include "chrome/browser/extensions/user_script_master.h" +#include <map> #include <string> #include <vector> @@ -18,8 +19,10 @@ #include "chrome/browser/profiles/profile.h" #include "chrome/common/chrome_notification_types.h" #include "chrome/common/extensions/extension.h" -#include "chrome/common/extensions/extension_messages.h" +#include "chrome/common/extensions/extension_file_util.h" +#include "chrome/common/extensions/extension_message_bundle.h" #include "chrome/common/extensions/extension_resource.h" +#include "chrome/common/extensions/extension_set.h" #include "content/browser/renderer_host/render_process_host.h" #include "content/common/notification_service.h" @@ -44,6 +47,12 @@ static bool GetDeclarationValue(const base::StringPiece& line, UserScriptMaster::ScriptReloader::ScriptReloader(UserScriptMaster* master) : master_(master) { CHECK(BrowserThread::GetCurrentThreadIdentifier(&master_thread_id_)); + + // Gather extensions information needed for localization. + if (master && master->profile_ && master->profile_->GetExtensionInfoMap()) { + const ExtensionInfoMap* info_map = master->profile_->GetExtensionInfoMap(); + info_map->extensions().GetExtensionsPathAndDefaultLocale(extensions_info_); + } } // static @@ -160,7 +169,8 @@ void UserScriptMaster::ScriptReloader::NotifyMaster( Release(); } -static bool LoadScriptContent(UserScript::File* script_file) { +static bool LoadScriptContent(UserScript::File* script_file, + const SubstitutionMap* localization_messages) { std::string content; const FilePath& path = ExtensionResource::GetFilePath( script_file->extension_root(), script_file->relative_path()); @@ -175,6 +185,16 @@ static bool LoadScriptContent(UserScript::File* script_file) { return false; } + // Localize the content. + if (localization_messages) { + std::string error; + ExtensionMessageBundle::ReplaceMessagesWithExternalDictionary( + *localization_messages, &content, &error); + if (!error.empty()) { + LOG(WARNING) << "Failed to replace messages in script: " << error; + } + } + // Remove BOM from the content. std::string::size_type index = content.find(kUtf8ByteOrderMark); if (index == 0) { @@ -186,24 +206,37 @@ static bool LoadScriptContent(UserScript::File* script_file) { return true; } -// static void UserScriptMaster::ScriptReloader::LoadUserScripts( UserScriptList* user_scripts) { for (size_t i = 0; i < user_scripts->size(); ++i) { UserScript& script = user_scripts->at(i); + scoped_ptr<SubstitutionMap> localization_messages( + GetLocalizationMessages(script.extension_id())); for (size_t k = 0; k < script.js_scripts().size(); ++k) { UserScript::File& script_file = script.js_scripts()[k]; if (script_file.GetContent().empty()) - LoadScriptContent(&script_file); + LoadScriptContent(&script_file, NULL); } for (size_t k = 0; k < script.css_scripts().size(); ++k) { UserScript::File& script_file = script.css_scripts()[k]; if (script_file.GetContent().empty()) - LoadScriptContent(&script_file); + LoadScriptContent(&script_file, localization_messages.get()); } } } +SubstitutionMap* UserScriptMaster::ScriptReloader::GetLocalizationMessages( + std::string extension_id) { + if (extensions_info_.find(extension_id) == extensions_info_.end()) { + return NULL; + } + + return extension_file_util::LoadExtensionMessageBundleSubstitutionMap( + extensions_info_[extension_id].first, + extension_id, + extensions_info_[extension_id].second); +} + // Pickle user scripts and return pointer to the shared memory. static base::SharedMemory* Serialize(const UserScriptList& scripts) { Pickle pickle; diff --git a/chrome/browser/extensions/user_script_master.h b/chrome/browser/extensions/user_script_master.h index 2df53d8..1ef6453 100644 --- a/chrome/browser/extensions/user_script_master.h +++ b/chrome/browser/extensions/user_script_master.h @@ -6,10 +6,15 @@ #define CHROME_BROWSER_EXTENSIONS_USER_SCRIPT_MASTER_H_ #pragma once +#include <map> +#include <string> + #include "base/file_path.h" #include "base/gtest_prod_util.h" #include "base/memory/scoped_ptr.h" #include "base/shared_memory.h" +#include "chrome/common/extensions/extension_messages.h" +#include "chrome/common/extensions/extension_set.h" #include "chrome/common/extensions/user_script.h" #include "content/browser/browser_thread.h" #include "content/common/notification_observer.h" @@ -75,7 +80,6 @@ class UserScriptMaster : public base::RefCountedThreadSafe<UserScriptMaster>, } private: - private: FRIEND_TEST_ALL_PREFIXES(UserScriptMasterTest, SkipBOMAtTheBeginning); FRIEND_TEST_ALL_PREFIXES(UserScriptMasterTest, LeaveBOMNotAtTheBeginning); friend class base::RefCountedThreadSafe<UserScriptMaster::ScriptReloader>; @@ -98,12 +102,20 @@ class UserScriptMaster : public base::RefCountedThreadSafe<UserScriptMaster>, // tied to the caller. void RunLoad(const UserScriptList& user_scripts); - static void LoadUserScripts(UserScriptList* user_scripts); + void LoadUserScripts(UserScriptList* user_scripts); + + // Uses extensions_info_ to build a map of localization messages. + // Returns NULL if |extension_id| is invalid. + SubstitutionMap* GetLocalizationMessages(std::string extension_id); // A pointer back to our master. // May be NULL if DisownMaster() is called. UserScriptMaster* master_; + // Maps extension info needed for localization to an extension ID. + std::map<std::string, ExtensionSet::ExtensionPathAndDefaultLocale> + extensions_info_; + // The message loop to call our master back on. // Expected to always outlive us. BrowserThread::ID master_thread_id_; diff --git a/chrome/browser/extensions/user_script_master_unittest.cc b/chrome/browser/extensions/user_script_master_unittest.cc index d1ea7ac..2637c28 100644 --- a/chrome/browser/extensions/user_script_master_unittest.cc +++ b/chrome/browser/extensions/user_script_master_unittest.cc @@ -220,7 +220,11 @@ TEST_F(UserScriptMasterTest, SkipBOMAtTheBeginning) { UserScriptList user_scripts; user_scripts.push_back(user_script); - UserScriptMaster::ScriptReloader::LoadUserScripts(&user_scripts); + UserScriptMaster::ScriptReloader* script_reloader = + new UserScriptMaster::ScriptReloader(NULL); + script_reloader->AddRef(); + script_reloader->LoadUserScripts(&user_scripts); + script_reloader->Release(); EXPECT_EQ(content.substr(3), user_scripts[0].js_scripts()[0].GetContent().as_string()); @@ -239,7 +243,11 @@ TEST_F(UserScriptMasterTest, LeaveBOMNotAtTheBeginning) { UserScriptList user_scripts; user_scripts.push_back(user_script); - UserScriptMaster::ScriptReloader::LoadUserScripts(&user_scripts); + UserScriptMaster::ScriptReloader* script_reloader = + new UserScriptMaster::ScriptReloader(NULL); + script_reloader->AddRef(); + script_reloader->LoadUserScripts(&user_scripts); + script_reloader->Release(); EXPECT_EQ(content, user_scripts[0].js_scripts()[0].GetContent().as_string()); } diff --git a/chrome/browser/renderer_host/chrome_render_message_filter.cc b/chrome/browser/renderer_host/chrome_render_message_filter.cc index 5cc1293..7486ebd 100644 --- a/chrome/browser/renderer_host/chrome_render_message_filter.cc +++ b/chrome/browser/renderer_host/chrome_render_message_filter.cc @@ -323,25 +323,14 @@ void ChromeRenderMessageFilter::OnGetExtensionMessageBundleOnFileThread( IPC::Message* reply_msg) { DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); - std::map<std::string, std::string> dictionary_map; - if (!default_locale.empty()) { - // Touch disk only if extension is localized. - std::string error; - scoped_ptr<ExtensionMessageBundle> bundle( - extension_file_util::LoadExtensionMessageBundle( - extension_path, default_locale, &error)); - - if (bundle.get()) - dictionary_map = *bundle->dictionary(); - } - - // Add @@extension_id reserved message here, so it's available to - // non-localized extensions too. - dictionary_map.insert( - std::make_pair(ExtensionMessageBundle::kExtensionIdKey, extension_id)); + scoped_ptr<ExtensionMessageBundle::SubstitutionMap> dictionary_map( + extension_file_util::LoadExtensionMessageBundleSubstitutionMap( + extension_path, + extension_id, + default_locale)); ExtensionHostMsg_GetMessageBundle::WriteReplyParams( - reply_msg, dictionary_map); + reply_msg, *dictionary_map); Send(reply_msg); } |