OLD | NEW |
1 // Copyright (c) 2009 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2009 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/extension_message_bundle.h" |
6 | 6 |
7 #include <string> | 7 #include <string> |
8 #include <vector> | 8 #include <vector> |
9 | 9 |
| 10 #include "app/l10n_util.h" |
10 #include "base/hash_tables.h" | 11 #include "base/hash_tables.h" |
11 #include "base/linked_ptr.h" | 12 #include "base/linked_ptr.h" |
12 #include "base/scoped_ptr.h" | 13 #include "base/scoped_ptr.h" |
| 14 #include "base/stl_util-inl.h" |
13 #include "base/string_util.h" | 15 #include "base/string_util.h" |
14 #include "base/values.h" | 16 #include "base/values.h" |
| 17 #include "chrome/common/extensions/extension_constants.h" |
| 18 #include "chrome/common/extensions/extension_error_utils.h" |
| 19 #include "chrome/common/extensions/extension_l10n_util.h" |
| 20 |
| 21 namespace errors = extension_manifest_errors; |
15 | 22 |
16 const wchar_t* ExtensionMessageBundle::kContentKey = L"content"; | 23 const wchar_t* ExtensionMessageBundle::kContentKey = L"content"; |
17 const wchar_t* ExtensionMessageBundle::kMessageKey = L"message"; | 24 const wchar_t* ExtensionMessageBundle::kMessageKey = L"message"; |
18 const wchar_t* ExtensionMessageBundle::kPlaceholdersKey = L"placeholders"; | 25 const wchar_t* ExtensionMessageBundle::kPlaceholdersKey = L"placeholders"; |
19 | 26 |
20 const char* ExtensionMessageBundle::kPlaceholderBegin = "$"; | 27 const char* ExtensionMessageBundle::kPlaceholderBegin = "$"; |
21 const char* ExtensionMessageBundle::kPlaceholderEnd = "$"; | 28 const char* ExtensionMessageBundle::kPlaceholderEnd = "$"; |
22 const char* ExtensionMessageBundle::kMessageBegin = "__MSG_"; | 29 const char* ExtensionMessageBundle::kMessageBegin = "__MSG_"; |
23 const char* ExtensionMessageBundle::kMessageEnd = "__"; | 30 const char* ExtensionMessageBundle::kMessageEnd = "__"; |
24 | 31 |
| 32 // Reserved messages names. |
| 33 const char* ExtensionMessageBundle::kUILocaleKey = "@@ui_locale"; |
| 34 const char* ExtensionMessageBundle::kBidiDirectionKey = "@@bidi_dir"; |
| 35 const char* ExtensionMessageBundle::kBidiReversedDirectionKey = |
| 36 "@@bidi_reversed_dir"; |
| 37 const char* ExtensionMessageBundle::kBidiStartEdgeKey = "@@bidi_start_edge"; |
| 38 const char* ExtensionMessageBundle::kBidiEndEdgeKey = "@@bidi_end_edge"; |
| 39 |
| 40 // Reserved messages values. |
| 41 const char* ExtensionMessageBundle::kBidiLeftEdgeValue = "left"; |
| 42 const char* ExtensionMessageBundle::kBidiRightEdgeValue = "right"; |
| 43 |
25 // Formats message in case we encounter a bad formed key in the JSON object. | 44 // Formats message in case we encounter a bad formed key in the JSON object. |
26 // Returns false and sets |error| to actual error message. | 45 // Returns false and sets |error| to actual error message. |
27 static bool BadKeyMessage(const std::string& name, std::string* error) { | 46 static bool BadKeyMessage(const std::string& name, std::string* error) { |
28 *error = StringPrintf("Name of a key \"%s\" is invalid. Only ASCII [a-z], " | 47 *error = StringPrintf("Name of a key \"%s\" is invalid. Only ASCII [a-z], " |
29 "[A-Z], [0-9] and \"_\" are allowed.", name.c_str()); | 48 "[A-Z], [0-9] and \"_\" are allowed.", name.c_str()); |
30 return false; | 49 return false; |
31 } | 50 } |
32 | 51 |
33 // static | 52 // static |
34 ExtensionMessageBundle* ExtensionMessageBundle::Create( | 53 ExtensionMessageBundle* ExtensionMessageBundle::Create( |
(...skipping 20 matching lines...) Expand all Loading... |
55 if (!IsValidName(*key_it)) | 74 if (!IsValidName(*key_it)) |
56 return BadKeyMessage(key, error); | 75 return BadKeyMessage(key, error); |
57 std::string value; | 76 std::string value; |
58 if (!GetMessageValue(*key_it, *catalog, &value, error)) | 77 if (!GetMessageValue(*key_it, *catalog, &value, error)) |
59 return false; | 78 return false; |
60 // Keys are not case-sensitive. | 79 // Keys are not case-sensitive. |
61 dictionary_[key] = value; | 80 dictionary_[key] = value; |
62 } | 81 } |
63 } | 82 } |
64 | 83 |
| 84 if (!AppendReservedMessages(extension_l10n_util::CurrentLocaleOrDefault(), |
| 85 error)) |
| 86 return false; |
| 87 |
| 88 return true; |
| 89 } |
| 90 |
| 91 bool ExtensionMessageBundle::AppendReservedMessages( |
| 92 const std::string& app_locale, std::string* error) { |
| 93 SubstitutionMap append_messages; |
| 94 append_messages[kUILocaleKey] = app_locale; |
| 95 |
| 96 // Calling l10n_util::GetTextDirection on non-UI threads doesn't seems safe, |
| 97 // so we use GetTextDirectionForLocale instead. |
| 98 if (l10n_util::GetTextDirectionForLocale(app_locale.c_str()) == |
| 99 l10n_util::RIGHT_TO_LEFT) { |
| 100 append_messages[kBidiDirectionKey] = "rtl"; |
| 101 append_messages[kBidiReversedDirectionKey] = "ltr"; |
| 102 append_messages[kBidiStartEdgeKey] = kBidiRightEdgeValue; |
| 103 append_messages[kBidiEndEdgeKey] = kBidiLeftEdgeValue; |
| 104 } else { |
| 105 append_messages[kBidiDirectionKey] = "ltr"; |
| 106 append_messages[kBidiReversedDirectionKey] = "rtl"; |
| 107 append_messages[kBidiStartEdgeKey] = kBidiLeftEdgeValue; |
| 108 append_messages[kBidiEndEdgeKey] = kBidiRightEdgeValue; |
| 109 } |
| 110 |
| 111 // Add all reserved messages to the dictionary, but check for collisions. |
| 112 SubstitutionMap::iterator it = append_messages.begin(); |
| 113 for (; it != append_messages.end(); ++it) { |
| 114 if (ContainsKey(dictionary_, it->first)) { |
| 115 *error = ExtensionErrorUtils::FormatErrorMessage( |
| 116 errors::kReservedMessageFound, it->first); |
| 117 return false; |
| 118 } else { |
| 119 dictionary_[it->first] = it->second; |
| 120 } |
| 121 } |
| 122 |
65 return true; | 123 return true; |
66 } | 124 } |
67 | 125 |
68 bool ExtensionMessageBundle::GetMessageValue(const std::wstring& wkey, | 126 bool ExtensionMessageBundle::GetMessageValue(const std::wstring& wkey, |
69 const DictionaryValue& catalog, | 127 const DictionaryValue& catalog, |
70 std::string* value, | 128 std::string* value, |
71 std::string* error) const { | 129 std::string* error) const { |
72 std::string key(WideToUTF8(wkey)); | 130 std::string key(WideToUTF8(wkey)); |
73 // Get the top level tree for given key (name part). | 131 // Get the top level tree for given key (name part). |
74 DictionaryValue* name_tree; | 132 DictionaryValue* name_tree; |
(...skipping 133 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
208 } | 266 } |
209 | 267 |
210 // static | 268 // static |
211 template <typename str> | 269 template <typename str> |
212 bool ExtensionMessageBundle::IsValidName(const str& name) { | 270 bool ExtensionMessageBundle::IsValidName(const str& name) { |
213 if (name.empty()) | 271 if (name.empty()) |
214 return false; | 272 return false; |
215 | 273 |
216 for (typename str::const_iterator it = name.begin(); it != name.end(); ++it) { | 274 for (typename str::const_iterator it = name.begin(); it != name.end(); ++it) { |
217 // Allow only ascii 0-9, a-z, A-Z, and _ in the name. | 275 // Allow only ascii 0-9, a-z, A-Z, and _ in the name. |
218 if (!IsAsciiAlpha(*it) && !IsAsciiDigit(*it) && *it != '_') | 276 if (!IsAsciiAlpha(*it) && !IsAsciiDigit(*it) && *it != '_' && *it != '@') |
219 return false; | 277 return false; |
220 } | 278 } |
221 | 279 |
222 return true; | 280 return true; |
223 } | 281 } |
224 | 282 |
225 // Dictionary interface. | 283 // Dictionary interface. |
226 | 284 |
227 std::string ExtensionMessageBundle::GetL10nMessage( | 285 std::string ExtensionMessageBundle::GetL10nMessage( |
228 const std::string& name) const { | 286 const std::string& name) const { |
229 return GetL10nMessage(name, dictionary_); | 287 return GetL10nMessage(name, dictionary_); |
230 } | 288 } |
231 | 289 |
232 // static | 290 // static |
233 std::string ExtensionMessageBundle::GetL10nMessage( | 291 std::string ExtensionMessageBundle::GetL10nMessage( |
234 const std::string& name, const SubstitutionMap& dictionary) { | 292 const std::string& name, const SubstitutionMap& dictionary) { |
235 SubstitutionMap::const_iterator it = | 293 SubstitutionMap::const_iterator it = |
236 dictionary.find(StringToLowerASCII(name)); | 294 dictionary.find(StringToLowerASCII(name)); |
237 if (it != dictionary.end()) { | 295 if (it != dictionary.end()) { |
238 return it->second; | 296 return it->second; |
239 } | 297 } |
240 | 298 |
241 return ""; | 299 return ""; |
242 } | 300 } |
OLD | NEW |