diff options
author | cira@chromium.org <cira@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-09-28 19:38:49 +0000 |
---|---|---|
committer | cira@chromium.org <cira@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-09-28 19:38:49 +0000 |
commit | 75e126b937df6fcf5590f607adb460099211fb5a (patch) | |
tree | dea2e8c33b6777b36df3435179fd9e6840b77710 /chrome/renderer | |
parent | 99a19b7411d408c7471b3ee2c452f06f4d09259d (diff) | |
download | chromium_src-75e126b937df6fcf5590f607adb460099211fb5a.zip chromium_src-75e126b937df6fcf5590f607adb460099211fb5a.tar.gz chromium_src-75e126b937df6fcf5590f607adb460099211fb5a.tar.bz2 |
Implementing chrome.i18n.getMessage call, that loads message from the extension catalog, and if necessary replaces placeholders (up to 9).
I have 3 forms of getMessage call:
getMessage("name") for simple messages without placeholders.
getMessage("name", "one param") for messages with only one placeholder.
getMessage("name", ["one", "two"]) for messages with only one or more placeholders.
getMessage returns string.
BUG=12131
TEST=Load samples/i18n extension (switch Chrome to sr locale) and observe ext. name, description and toolstrip texts should be in Serbian.
Review URL: http://codereview.chromium.org/225009
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@27393 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome/renderer')
-rw-r--r-- | chrome/renderer/extensions/extension_api_client_unittest.cc | 18 | ||||
-rw-r--r-- | chrome/renderer/extensions/extension_process_bindings.cc | 87 | ||||
-rw-r--r-- | chrome/renderer/extensions/extension_process_bindings.h | 5 | ||||
-rw-r--r-- | chrome/renderer/render_thread.cc | 9 | ||||
-rw-r--r-- | chrome/renderer/render_thread.h | 13 | ||||
-rw-r--r-- | chrome/renderer/resources/extension_process_bindings.js | 6 |
6 files changed, 132 insertions, 6 deletions
diff --git a/chrome/renderer/extensions/extension_api_client_unittest.cc b/chrome/renderer/extensions/extension_api_client_unittest.cc index 14ab617..1a06889 100644 --- a/chrome/renderer/extensions/extension_api_client_unittest.cc +++ b/chrome/renderer/extensions/extension_api_client_unittest.cc @@ -605,3 +605,21 @@ TEST_F(ExtensionAPIClientTest, GetAcceptLanguages) { ExpectJsPass("chrome.i18n.getAcceptLanguages(function(){})", "i18n.getAcceptLanguages", "null"); } + +TEST_F(ExtensionAPIClientTest, GetL10nMessage) { + ExpectJsFail("chrome.i18n.getMessage()", + "Uncaught Error: Parameter 0 is required."); + + ExpectJsFail("chrome.i18n.getMessage(1)", + "Uncaught Error: Invalid value for argument 0. " + "Expected 'string' but got 'integer'."); + + ExpectJsFail("chrome.i18n.getMessage('name', [])", + "Uncaught Error: Invalid value for argument 1. Value does not " + "match any valid type choices."); + + ExpectJsFail("chrome.i18n.getMessage('name', ['p1', 'p2', 'p3', 'p4', 'p5', " + "'p6', 'p7', 'p8', 'p9', 'p10'])", + "Uncaught Error: Invalid value for argument 1. Value does not " + "match any valid type choices."); +} diff --git a/chrome/renderer/extensions/extension_process_bindings.cc b/chrome/renderer/extensions/extension_process_bindings.cc index 0fc9438..1a461a8 100644 --- a/chrome/renderer/extensions/extension_process_bindings.cc +++ b/chrome/renderer/extensions/extension_process_bindings.cc @@ -2,10 +2,16 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +#include <map> +#include <set> +#include <string> +#include <vector> + #include "chrome/renderer/extensions/extension_process_bindings.h" #include "base/singleton.h" #include "chrome/common/extensions/extension.h" +#include "chrome/common/extensions/extension_message_bundle.h" #include "chrome/common/extensions/url_pattern.h" #include "chrome/common/render_messages.h" #include "chrome/common/url_constants.h" @@ -41,6 +47,13 @@ typedef std::map<std::string, bool> PermissionsMap; // A map of extension ID to permissions map. typedef std::map<std::string, PermissionsMap> ExtensionPermissionsMap; +// A map of message name to message. +typedef std::map<std::string, std::string> L10nMessagesMap; + +// A map of extension ID to l10n message map. +typedef std::map<std::string, L10nMessagesMap > + ExtensionToL10nMessagesMap; + const char kExtensionName[] = "chrome/ExtensionProcessBindings"; const char* kExtensionDeps[] = { BaseJsV8Extension::kName, @@ -54,6 +67,7 @@ struct SingletonData { std::set<std::string> function_names_; PageActionIdMap page_action_ids_; ExtensionPermissionsMap permissions_; + ExtensionToL10nMessagesMap extension_l10n_messages_map_; }; static std::set<std::string>* GetFunctionNameSet() { @@ -68,6 +82,20 @@ static PermissionsMap* GetPermissionsMap(const std::string& extension_id) { return &Singleton<SingletonData>()->permissions_[extension_id]; } +static ExtensionToL10nMessagesMap* GetExtensionToL10nMessagesMap() { + return &Singleton<SingletonData>()->extension_l10n_messages_map_; +} + +static L10nMessagesMap* GetL10nMessagesMap(const std::string extension_id) { + ExtensionToL10nMessagesMap::iterator it = + Singleton<SingletonData>()->extension_l10n_messages_map_.find(extension_id); + if (it != Singleton<SingletonData>()->extension_l10n_messages_map_.end()) { + return &(it->second); + } else { + return NULL; + } +} + class ExtensionImpl : public ExtensionBase { public: ExtensionImpl() : ExtensionBase( @@ -109,6 +137,8 @@ class ExtensionImpl : public ExtensionBase { return v8::FunctionTemplate::New(StartRequest); } else if (name->Equals(v8::String::New("GetRenderViewId"))) { return v8::FunctionTemplate::New(GetRenderViewId); + } else if (name->Equals(v8::String::New("GetL10nMessage"))) { + return v8::FunctionTemplate::New(GetL10nMessage); } return ExtensionBase::GetNativeFunction(name); @@ -131,7 +161,7 @@ class ExtensionImpl : public ExtensionBase { // TODO(erikkay) for now, special case mole as a type of toolstrip. // Perhaps this isn't the right long-term thing to do. - if (match == ViewType::EXTENSION_TOOLSTRIP && + if (match == ViewType::EXTENSION_TOOLSTRIP && type == ViewType::EXTENSION_MOLE) { return true; } @@ -255,6 +285,50 @@ class ExtensionImpl : public ExtensionBase { return page_action_vector; } + static v8::Handle<v8::Value> GetL10nMessage(const v8::Arguments& args) { + if (args.Length() != 2 || !args[0]->IsString()) { + NOTREACHED() << "Bad arguments"; + return v8::Undefined(); + } + + L10nMessagesMap* l10n_messages = + GetL10nMessagesMap(ExtensionIdForCurrentContext()); + if (!l10n_messages) + return v8::Undefined(); + + std::string message_name = *v8::String::AsciiValue(args[0]); + std::string message = + ExtensionMessageBundle::GetL10nMessage(message_name, *l10n_messages); + + std::vector<string16> substitutions; + if (args[1]->IsNull() || args[1]->IsUndefined()) { + // chrome.i18n.getMessage("message_name"); + // chrome.i18n.getMessage("message_name", null); + return v8::String::New(message.c_str()); + } else if (args[1]->IsString()) { + // chrome.i18n.getMessage("message_name", "one param"); + std::string substitute = *v8::String::Utf8Value(args[1]->ToString()); + substitutions.push_back(UTF8ToUTF16(substitute)); + } else if (args[1]->IsArray()) { + // chrome.i18n.getMessage("message_name", ["more", "params"]); + v8::Array* placeholders = static_cast<v8::Array*>(*args[1]); + uint32_t count = placeholders->Length(); + DCHECK(count > 0 && count <= 9); + for (uint32_t i = 0; i < count; ++i) { + std::string substitute = + *v8::String::Utf8Value( + placeholders->Get(v8::Integer::New(i))->ToString()); + substitutions.push_back(UTF8ToUTF16(substitute)); + } + } else { + NOTREACHED() << "Couldn't parse second parameter."; + return v8::Undefined(); + } + + return v8::String::New(UTF16ToUTF8(ReplaceStringPlaceholders( + UTF8ToUTF16(message), substitutions, NULL)).c_str()); + } + // Starts an API request to the browser, with an optional callback. The // callback will be dispatched to EventBindings::HandleResponse. static v8::Handle<v8::Value> StartRequest(const v8::Arguments& args) { @@ -331,7 +405,7 @@ void ExtensionProcessBindings::HandleResponse(int request_id, bool success, argv[4] = v8::String::New(error.c_str()); v8::Handle<v8::Value> retval = bindings_utils::CallFunctionInContext( request->second->context, "handleResponse", arraysize(argv), argv); - // In debug, the js will validate the callback parameters and return a + // In debug, the js will validate the callback parameters and return a // string if a validation error has occured. #ifdef _DEBUG if (!retval.IsEmpty() && !retval->IsUndefined()) { @@ -357,6 +431,15 @@ void ExtensionProcessBindings::SetPageActions( } // static +void ExtensionProcessBindings::SetL10nMessages( + const std::string& extension_id, + const std::map<std::string, std::string>& l10n_messages) { + ExtensionToL10nMessagesMap& l10n_messages_map = + *GetExtensionToL10nMessagesMap(); + l10n_messages_map[extension_id] = l10n_messages; +} + +// static void ExtensionProcessBindings::SetAPIPermissions( const std::string& extension_id, const std::vector<std::string>& permissions) { diff --git a/chrome/renderer/extensions/extension_process_bindings.h b/chrome/renderer/extensions/extension_process_bindings.h index 1777658..77e5854 100644 --- a/chrome/renderer/extensions/extension_process_bindings.h +++ b/chrome/renderer/extensions/extension_process_bindings.h @@ -40,6 +40,11 @@ class ExtensionProcessBindings { static void SetHostPermissions(const GURL& extension_url, const std::vector<URLPattern>& permissions); + // Set l10n messages for a particular extension. + static void SetL10nMessages( + const std::string& extension_id, + const std::map<std::string, std::string>& l10n_messages); + // Check if the extension in the currently running context has permission to // access the given extension function. Must be called with a valid V8 // context in scope. diff --git a/chrome/renderer/render_thread.cc b/chrome/renderer/render_thread.cc index 788b852..d753556 100644 --- a/chrome/renderer/render_thread.cc +++ b/chrome/renderer/render_thread.cc @@ -5,6 +5,7 @@ #include "chrome/renderer/render_thread.h" #include <algorithm> +#include <map> #include <vector> #include "base/command_line.h" @@ -238,6 +239,12 @@ void RenderThread::OnExtensionSetHostPermissions( ExtensionProcessBindings::SetHostPermissions(extension_url, permissions); } +void RenderThread::OnExtensionSetL10nMessages( + const std::string& extension_id, + const std::map<std::string, std::string>& l10n_messages) { + ExtensionProcessBindings::SetL10nMessages(extension_id, l10n_messages); +} + void RenderThread::OnControlMessageReceived(const IPC::Message& msg) { // App cache messages are handled by a delegate. if (appcache_dispatcher_->OnMessageReceived(msg)) @@ -273,6 +280,8 @@ void RenderThread::OnControlMessageReceived(const IPC::Message& msg) { OnExtensionSetAPIPermissions) IPC_MESSAGE_HANDLER(ViewMsg_Extension_SetHostPermissions, OnExtensionSetHostPermissions) + IPC_MESSAGE_HANDLER(ViewMsg_Extension_SetL10nMessages, + OnExtensionSetL10nMessages) IPC_END_MESSAGE_MAP() } diff --git a/chrome/renderer/render_thread.h b/chrome/renderer/render_thread.h index ab9a0b2..9fa7203 100644 --- a/chrome/renderer/render_thread.h +++ b/chrome/renderer/render_thread.h @@ -140,10 +140,15 @@ class RenderThread : public RenderThreadBase, void OnSetExtensionFunctionNames(const std::vector<std::string>& names); void OnPageActionsUpdated(const std::string& extension_id, const std::vector<std::string>& page_actions); - void OnExtensionSetAPIPermissions(const std::string& extension_id, - const std::vector<std::string>& permissions); - void OnExtensionSetHostPermissions(const GURL& extension_url, - const std::vector<URLPattern>& permissions); + void OnExtensionSetAPIPermissions( + const std::string& extension_id, + const std::vector<std::string>& permissions); + void OnExtensionSetHostPermissions( + const GURL& extension_url, + const std::vector<URLPattern>& permissions); + void OnExtensionSetL10nMessages( + const std::string& extension_id, + const std::map<std::string, std::string>& l10n_messages); void OnSetNextPageID(int32 next_page_id); void OnSetCSSColors(const std::vector<CSSColors::CSSColorMapping>& colors); void OnCreateNewView(gfx::NativeViewId parent_hwnd, diff --git a/chrome/renderer/resources/extension_process_bindings.js b/chrome/renderer/resources/extension_process_bindings.js index ff2fddd..710dad8 100644 --- a/chrome/renderer/resources/extension_process_bindings.js +++ b/chrome/renderer/resources/extension_process_bindings.js @@ -20,6 +20,7 @@ var chrome = chrome || {}; native function GetNextRequestId(); native function OpenChannelToTab(); native function GetRenderViewId(); + native function GetL10nMessage(); if (!chrome) chrome = {}; @@ -323,6 +324,11 @@ var chrome = chrome || {}; return tabIdProxy; } + apiFunctions["i18n.getMessage"].handleRequest = + function(message_name, placeholders) { + return GetL10nMessage(message_name, placeholders); + } + setupPageActionEvents(extensionId); setupBrowserActionEvent(extensionId); setupToolstripEvents(GetRenderViewId()); |