Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(3)

Side by Side Diff: chrome/common/extensions/message_bundle.cc

Issue 10787002: Moved ExtensionMessage* into extensions namespace (Closed) Base URL: http://git.chromium.org/chromium/src.git@master
Patch Set: Latest master for cq Created 8 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
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/common/extensions/extension_message_bundle.h" 5 #include "chrome/common/extensions/message_bundle.h"
6 6
7 #include <string> 7 #include <string>
8 #include <vector> 8 #include <vector>
9 9
10 #include "base/hash_tables.h" 10 #include "base/hash_tables.h"
11 #include "base/i18n/rtl.h" 11 #include "base/i18n/rtl.h"
12 #include "base/lazy_instance.h" 12 #include "base/lazy_instance.h"
13 #include "base/memory/linked_ptr.h" 13 #include "base/memory/linked_ptr.h"
14 #include "base/memory/scoped_ptr.h" 14 #include "base/memory/scoped_ptr.h"
15 #include "base/stl_util.h" 15 #include "base/stl_util.h"
16 #include "base/stringprintf.h" 16 #include "base/stringprintf.h"
17 #include "base/utf_string_conversions.h" 17 #include "base/utf_string_conversions.h"
18 #include "base/values.h" 18 #include "base/values.h"
19 #include "chrome/common/extensions/extension_manifest_constants.h" 19 #include "chrome/common/extensions/extension_manifest_constants.h"
20 #include "chrome/common/extensions/extension_error_utils.h" 20 #include "chrome/common/extensions/extension_error_utils.h"
21 #include "chrome/common/extensions/extension_l10n_util.h" 21 #include "chrome/common/extensions/extension_l10n_util.h"
22 #include "ui/base/l10n/l10n_util.h" 22 #include "ui/base/l10n/l10n_util.h"
23 23
24 namespace errors = extension_manifest_errors; 24 namespace errors = extension_manifest_errors;
25 25
26 const char* ExtensionMessageBundle::kContentKey = "content"; 26 namespace extensions {
27 const char* ExtensionMessageBundle::kMessageKey = "message";
28 const char* ExtensionMessageBundle::kPlaceholdersKey = "placeholders";
29 27
30 const char* ExtensionMessageBundle::kPlaceholderBegin = "$"; 28 const char* MessageBundle::kContentKey = "content";
31 const char* ExtensionMessageBundle::kPlaceholderEnd = "$"; 29 const char* MessageBundle::kMessageKey = "message";
32 const char* ExtensionMessageBundle::kMessageBegin = "__MSG_"; 30 const char* MessageBundle::kPlaceholdersKey = "placeholders";
33 const char* ExtensionMessageBundle::kMessageEnd = "__"; 31
32 const char* MessageBundle::kPlaceholderBegin = "$";
33 const char* MessageBundle::kPlaceholderEnd = "$";
34 const char* MessageBundle::kMessageBegin = "__MSG_";
35 const char* MessageBundle::kMessageEnd = "__";
34 36
35 // Reserved messages names. 37 // Reserved messages names.
36 const char* ExtensionMessageBundle::kUILocaleKey = "@@ui_locale"; 38 const char* MessageBundle::kUILocaleKey = "@@ui_locale";
37 const char* ExtensionMessageBundle::kBidiDirectionKey = "@@bidi_dir"; 39 const char* MessageBundle::kBidiDirectionKey = "@@bidi_dir";
38 const char* ExtensionMessageBundle::kBidiReversedDirectionKey = 40 const char* MessageBundle::kBidiReversedDirectionKey =
39 "@@bidi_reversed_dir"; 41 "@@bidi_reversed_dir";
40 const char* ExtensionMessageBundle::kBidiStartEdgeKey = "@@bidi_start_edge"; 42 const char* MessageBundle::kBidiStartEdgeKey = "@@bidi_start_edge";
41 const char* ExtensionMessageBundle::kBidiEndEdgeKey = "@@bidi_end_edge"; 43 const char* MessageBundle::kBidiEndEdgeKey = "@@bidi_end_edge";
42 const char* ExtensionMessageBundle::kExtensionIdKey = "@@extension_id"; 44 const char* MessageBundle::kExtensionIdKey = "@@extension_id";
43 45
44 // Reserved messages values. 46 // Reserved messages values.
45 const char* ExtensionMessageBundle::kBidiLeftEdgeValue = "left"; 47 const char* MessageBundle::kBidiLeftEdgeValue = "left";
46 const char* ExtensionMessageBundle::kBidiRightEdgeValue = "right"; 48 const char* MessageBundle::kBidiRightEdgeValue = "right";
47 49
48 // Formats message in case we encounter a bad formed key in the JSON object. 50 // Formats message in case we encounter a bad formed key in the JSON object.
49 // Returns false and sets |error| to actual error message. 51 // Returns false and sets |error| to actual error message.
50 static bool BadKeyMessage(const std::string& name, std::string* error) { 52 static bool BadKeyMessage(const std::string& name, std::string* error) {
51 *error = base::StringPrintf( 53 *error = base::StringPrintf(
52 "Name of a key \"%s\" is invalid. Only ASCII [a-z], " 54 "Name of a key \"%s\" is invalid. Only ASCII [a-z], "
53 "[A-Z], [0-9] and \"_\" are allowed.", 55 "[A-Z], [0-9] and \"_\" are allowed.",
54 name.c_str()); 56 name.c_str());
55 return false; 57 return false;
56 } 58 }
57 59
58 // static 60 // static
59 ExtensionMessageBundle* ExtensionMessageBundle::Create( 61 MessageBundle* MessageBundle::Create(const CatalogVector& locale_catalogs,
60 const CatalogVector& locale_catalogs, 62 std::string* error) {
61 std::string* error) { 63 scoped_ptr<MessageBundle> message_bundle(new MessageBundle);
62 scoped_ptr<ExtensionMessageBundle> message_bundle(
63 new ExtensionMessageBundle);
64 if (!message_bundle->Init(locale_catalogs, error)) 64 if (!message_bundle->Init(locale_catalogs, error))
65 return NULL; 65 return NULL;
66 66
67 return message_bundle.release(); 67 return message_bundle.release();
68 } 68 }
69 69
70 bool ExtensionMessageBundle::Init(const CatalogVector& locale_catalogs, 70 bool MessageBundle::Init(const CatalogVector& locale_catalogs,
71 std::string* error) { 71 std::string* error) {
72 dictionary_.clear(); 72 dictionary_.clear();
73 73
74 for (CatalogVector::const_reverse_iterator it = locale_catalogs.rbegin(); 74 for (CatalogVector::const_reverse_iterator it = locale_catalogs.rbegin();
75 it != locale_catalogs.rend(); ++it) { 75 it != locale_catalogs.rend(); ++it) {
76 DictionaryValue* catalog = (*it).get(); 76 DictionaryValue* catalog = (*it).get();
77 for (DictionaryValue::key_iterator key_it = catalog->begin_keys(); 77 for (DictionaryValue::key_iterator key_it = catalog->begin_keys();
78 key_it != catalog->end_keys(); ++key_it) { 78 key_it != catalog->end_keys(); ++key_it) {
79 std::string key(StringToLowerASCII(*key_it)); 79 std::string key(StringToLowerASCII(*key_it));
80 if (!IsValidName(*key_it)) 80 if (!IsValidName(*key_it))
81 return BadKeyMessage(key, error); 81 return BadKeyMessage(key, error);
82 std::string value; 82 std::string value;
83 if (!GetMessageValue(*key_it, *catalog, &value, error)) 83 if (!GetMessageValue(*key_it, *catalog, &value, error))
84 return false; 84 return false;
85 // Keys are not case-sensitive. 85 // Keys are not case-sensitive.
86 dictionary_[key] = value; 86 dictionary_[key] = value;
87 } 87 }
88 } 88 }
89 89
90 if (!AppendReservedMessagesForLocale( 90 if (!AppendReservedMessagesForLocale(
91 extension_l10n_util::CurrentLocaleOrDefault(), error)) 91 extension_l10n_util::CurrentLocaleOrDefault(), error))
92 return false; 92 return false;
93 93
94 return true; 94 return true;
95 } 95 }
96 96
97 bool ExtensionMessageBundle::AppendReservedMessagesForLocale( 97 bool MessageBundle::AppendReservedMessagesForLocale(
98 const std::string& app_locale, std::string* error) { 98 const std::string& app_locale, std::string* error) {
99 SubstitutionMap append_messages; 99 SubstitutionMap append_messages;
100 append_messages[kUILocaleKey] = app_locale; 100 append_messages[kUILocaleKey] = app_locale;
101 101
102 // Calling base::i18n::GetTextDirection on non-UI threads doesn't seems safe, 102 // Calling base::i18n::GetTextDirection on non-UI threads doesn't seems safe,
103 // so we use GetTextDirectionForLocale instead. 103 // so we use GetTextDirectionForLocale instead.
104 if (base::i18n::GetTextDirectionForLocale(app_locale.c_str()) == 104 if (base::i18n::GetTextDirectionForLocale(app_locale.c_str()) ==
105 base::i18n::RIGHT_TO_LEFT) { 105 base::i18n::RIGHT_TO_LEFT) {
106 append_messages[kBidiDirectionKey] = "rtl"; 106 append_messages[kBidiDirectionKey] = "rtl";
107 append_messages[kBidiReversedDirectionKey] = "ltr"; 107 append_messages[kBidiReversedDirectionKey] = "ltr";
(...skipping 14 matching lines...) Expand all
122 errors::kReservedMessageFound, it->first); 122 errors::kReservedMessageFound, it->first);
123 return false; 123 return false;
124 } else { 124 } else {
125 dictionary_[it->first] = it->second; 125 dictionary_[it->first] = it->second;
126 } 126 }
127 } 127 }
128 128
129 return true; 129 return true;
130 } 130 }
131 131
132 bool ExtensionMessageBundle::GetMessageValue(const std::string& key, 132 bool MessageBundle::GetMessageValue(const std::string& key,
133 const DictionaryValue& catalog, 133 const DictionaryValue& catalog,
134 std::string* value, 134 std::string* value,
135 std::string* error) const { 135 std::string* error) const {
136 // Get the top level tree for given key (name part). 136 // Get the top level tree for given key (name part).
137 DictionaryValue* name_tree; 137 DictionaryValue* name_tree;
138 if (!catalog.GetDictionaryWithoutPathExpansion(key, &name_tree)) { 138 if (!catalog.GetDictionaryWithoutPathExpansion(key, &name_tree)) {
139 *error = base::StringPrintf("Not a valid tree for key %s.", key.c_str()); 139 *error = base::StringPrintf("Not a valid tree for key %s.", key.c_str());
140 return false; 140 return false;
141 } 141 }
142 // Extract message from it. 142 // Extract message from it.
143 if (!name_tree->GetString(kMessageKey, value)) { 143 if (!name_tree->GetString(kMessageKey, value)) {
144 *error = base::StringPrintf( 144 *error = base::StringPrintf(
145 "There is no \"%s\" element for key %s.", kMessageKey, key.c_str()); 145 "There is no \"%s\" element for key %s.", kMessageKey, key.c_str());
146 return false; 146 return false;
147 } 147 }
148 148
149 SubstitutionMap placeholders; 149 SubstitutionMap placeholders;
150 if (!GetPlaceholders(*name_tree, key, &placeholders, error)) 150 if (!GetPlaceholders(*name_tree, key, &placeholders, error))
151 return false; 151 return false;
152 152
153 if (!ReplacePlaceholders(placeholders, value, error)) 153 if (!ReplacePlaceholders(placeholders, value, error))
154 return false; 154 return false;
155 155
156 return true; 156 return true;
157 } 157 }
158 158
159 ExtensionMessageBundle::ExtensionMessageBundle() { 159 MessageBundle::MessageBundle() {
160 } 160 }
161 161
162 bool ExtensionMessageBundle::GetPlaceholders(const DictionaryValue& name_tree, 162 bool MessageBundle::GetPlaceholders(const DictionaryValue& name_tree,
163 const std::string& name_key, 163 const std::string& name_key,
164 SubstitutionMap* placeholders, 164 SubstitutionMap* placeholders,
165 std::string* error) const { 165 std::string* error) const {
166 if (!name_tree.HasKey(kPlaceholdersKey)) 166 if (!name_tree.HasKey(kPlaceholdersKey))
167 return true; 167 return true;
168 168
169 DictionaryValue* placeholders_tree; 169 DictionaryValue* placeholders_tree;
170 if (!name_tree.GetDictionary(kPlaceholdersKey, &placeholders_tree)) { 170 if (!name_tree.GetDictionary(kPlaceholdersKey, &placeholders_tree)) {
171 *error = base::StringPrintf("Not a valid \"%s\" element for key %s.", 171 *error = base::StringPrintf("Not a valid \"%s\" element for key %s.",
172 kPlaceholdersKey, name_key.c_str()); 172 kPlaceholdersKey, name_key.c_str());
173 return false; 173 return false;
174 } 174 }
175 175
(...skipping 15 matching lines...) Expand all
191 *error = base::StringPrintf("Invalid \"%s\" element for key %s.", 191 *error = base::StringPrintf("Invalid \"%s\" element for key %s.",
192 kContentKey, name_key.c_str()); 192 kContentKey, name_key.c_str());
193 return false; 193 return false;
194 } 194 }
195 (*placeholders)[StringToLowerASCII(content_key)] = content; 195 (*placeholders)[StringToLowerASCII(content_key)] = content;
196 } 196 }
197 197
198 return true; 198 return true;
199 } 199 }
200 200
201 bool ExtensionMessageBundle::ReplacePlaceholders( 201 bool MessageBundle::ReplacePlaceholders(const SubstitutionMap& placeholders,
202 const SubstitutionMap& placeholders, 202 std::string* message,
203 std::string* message, 203 std::string* error) const {
204 std::string* error) const {
205 return ReplaceVariables(placeholders, 204 return ReplaceVariables(placeholders,
206 kPlaceholderBegin, 205 kPlaceholderBegin,
207 kPlaceholderEnd, 206 kPlaceholderEnd,
208 message, 207 message,
209 error); 208 error);
210 } 209 }
211 210
212 bool ExtensionMessageBundle::ReplaceMessages(std::string* text, 211 bool MessageBundle::ReplaceMessages(std::string* text,
213 std::string* error) const { 212 std::string* error) const {
214 return ReplaceMessagesWithExternalDictionary(dictionary_, text, error); 213 return ReplaceMessagesWithExternalDictionary(dictionary_, text, error);
215 } 214 }
216 215
217 ExtensionMessageBundle::~ExtensionMessageBundle() { 216 MessageBundle::~MessageBundle() {
218 } 217 }
219 218
220 // static 219 // static
221 bool ExtensionMessageBundle::ReplaceMessagesWithExternalDictionary( 220 bool MessageBundle::ReplaceMessagesWithExternalDictionary(
222 const SubstitutionMap& dictionary, std::string* text, std::string* error) { 221 const SubstitutionMap& dictionary, std::string* text, std::string* error) {
223 return ReplaceVariables(dictionary, kMessageBegin, kMessageEnd, text, error); 222 return ReplaceVariables(dictionary, kMessageBegin, kMessageEnd, text, error);
224 } 223 }
225 224
226 // static 225 // static
227 bool ExtensionMessageBundle::ReplaceVariables( 226 bool MessageBundle::ReplaceVariables(const SubstitutionMap& variables,
228 const SubstitutionMap& variables, 227 const std::string& var_begin_delimiter,
229 const std::string& var_begin_delimiter, 228 const std::string& var_end_delimiter,
230 const std::string& var_end_delimiter, 229 std::string* message,
231 std::string* message, 230 std::string* error) {
232 std::string* error) {
233 std::string::size_type beg_index = 0; 231 std::string::size_type beg_index = 0;
234 const std::string::size_type var_begin_delimiter_size = 232 const std::string::size_type var_begin_delimiter_size =
235 var_begin_delimiter.size(); 233 var_begin_delimiter.size();
236 while (true) { 234 while (true) {
237 beg_index = message->find(var_begin_delimiter, beg_index); 235 beg_index = message->find(var_begin_delimiter, beg_index);
238 if (beg_index == message->npos) 236 if (beg_index == message->npos)
239 return true; 237 return true;
240 238
241 // Advance it immediately to the begining of possible variable name. 239 // Advance it immediately to the begining of possible variable name.
242 beg_index += var_begin_delimiter_size; 240 beg_index += var_begin_delimiter_size;
(...skipping 27 matching lines...) Expand all
270 value); 268 value);
271 269
272 // And position pointer to after the replacement. 270 // And position pointer to after the replacement.
273 beg_index += value.size() - var_begin_delimiter_size; 271 beg_index += value.size() - var_begin_delimiter_size;
274 } 272 }
275 273
276 return true; 274 return true;
277 } 275 }
278 276
279 // static 277 // static
280 bool ExtensionMessageBundle::IsValidName(const std::string& name) { 278 bool MessageBundle::IsValidName(const std::string& name) {
281 if (name.empty()) 279 if (name.empty())
282 return false; 280 return false;
283 281
284 std::string::const_iterator it = name.begin(); 282 std::string::const_iterator it = name.begin();
285 for (; it != name.end(); ++it) { 283 for (; it != name.end(); ++it) {
286 // Allow only ascii 0-9, a-z, A-Z, and _ in the name. 284 // Allow only ascii 0-9, a-z, A-Z, and _ in the name.
287 if (!IsAsciiAlpha(*it) && !IsAsciiDigit(*it) && *it != '_' && *it != '@') 285 if (!IsAsciiAlpha(*it) && !IsAsciiDigit(*it) && *it != '_' && *it != '@')
288 return false; 286 return false;
289 } 287 }
290 288
291 return true; 289 return true;
292 } 290 }
293 291
294 // Dictionary interface. 292 // Dictionary interface.
295 293
296 std::string ExtensionMessageBundle::GetL10nMessage( 294 std::string MessageBundle::GetL10nMessage(const std::string& name) const {
297 const std::string& name) const {
298 return GetL10nMessage(name, dictionary_); 295 return GetL10nMessage(name, dictionary_);
299 } 296 }
300 297
301 // static 298 // static
302 std::string ExtensionMessageBundle::GetL10nMessage( 299 std::string MessageBundle::GetL10nMessage(const std::string& name,
303 const std::string& name, const SubstitutionMap& dictionary) { 300 const SubstitutionMap& dictionary) {
304 SubstitutionMap::const_iterator it = 301 SubstitutionMap::const_iterator it =
305 dictionary.find(StringToLowerASCII(name)); 302 dictionary.find(StringToLowerASCII(name));
306 if (it != dictionary.end()) { 303 if (it != dictionary.end()) {
307 return it->second; 304 return it->second;
308 } 305 }
309 306
310 return ""; 307 return "";
311 } 308 }
312 309
313 /////////////////////////////////////////////////////////////////////////////// 310 ///////////////////////////////////////////////////////////////////////////////
(...skipping 23 matching lines...) Expand all
337 } 334 }
338 335
339 L10nMessagesMap* GetL10nMessagesMap(const std::string& extension_id) { 336 L10nMessagesMap* GetL10nMessagesMap(const std::string& extension_id) {
340 ExtensionToL10nMessagesMap::iterator it = 337 ExtensionToL10nMessagesMap::iterator it =
341 g_extension_to_messages_map.Get().messages_map.find(extension_id); 338 g_extension_to_messages_map.Get().messages_map.find(extension_id);
342 if (it != g_extension_to_messages_map.Get().messages_map.end()) 339 if (it != g_extension_to_messages_map.Get().messages_map.end())
343 return &(it->second); 340 return &(it->second);
344 341
345 return NULL; 342 return NULL;
346 } 343 }
344
345 } // namespace extensions
OLDNEW
« no previous file with comments | « chrome/common/extensions/message_bundle.h ('k') | chrome/common/extensions/message_bundle_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698