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

Side by Side Diff: chrome/browser/extensions/extension_l10n_util.cc

Issue 293037: Implementing better fallback algorithm.... (Closed) Base URL: svn://chrome-svn/chrome/trunk/src/
Patch Set: '' Created 11 years, 2 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 | Annotate | Revision Log
OLDNEW
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/browser/extensions/extension_l10n_util.h" 5 #include "chrome/browser/extensions/extension_l10n_util.h"
6 6
7 #include <set> 7 #include <set>
8 #include <string> 8 #include <string>
9 #include <vector> 9 #include <vector>
10 10
11 #include "app/l10n_util.h" 11 #include "app/l10n_util.h"
12 #include "base/file_util.h" 12 #include "base/file_util.h"
13 #include "base/linked_ptr.h"
13 #include "base/string_util.h" 14 #include "base/string_util.h"
14 #include "base/values.h" 15 #include "base/values.h"
15 #include "chrome/common/extensions/extension.h" 16 #include "chrome/common/extensions/extension.h"
16 #include "chrome/common/extensions/extension_constants.h" 17 #include "chrome/common/extensions/extension_constants.h"
17 #include "chrome/common/extensions/extension_message_bundle.h" 18 #include "chrome/common/extensions/extension_message_bundle.h"
18 #include "chrome/common/json_value_serializer.h" 19 #include "chrome/common/json_value_serializer.h"
19 20
20 namespace errors = extension_manifest_errors; 21 namespace errors = extension_manifest_errors;
21 namespace keys = extension_manifest_keys; 22 namespace keys = extension_manifest_keys;
22 23
23 namespace extension_l10n_util { 24 namespace extension_l10n_util {
24 25
25 std::string GetDefaultLocaleFromManifest(const DictionaryValue& manifest, 26 std::string GetDefaultLocaleFromManifest(const DictionaryValue& manifest,
26 std::string* error) { 27 std::string* error) {
27 std::string default_locale; 28 std::string default_locale;
28 if (!manifest.GetString(keys::kDefaultLocale, &default_locale)) { 29 if (!manifest.GetString(keys::kDefaultLocale, &default_locale)) {
29 *error = errors::kInvalidDefaultLocale; 30 *error = errors::kInvalidDefaultLocale;
30 return ""; 31 return "";
31 } 32 }
32 // Normalize underscores to hyphens. 33
33 std::replace(default_locale.begin(), default_locale.end(), '_', '-');
34 return default_locale; 34 return default_locale;
35 } 35 }
36 36
37 bool AddLocale(const std::set<std::string>& chrome_locales, 37 bool AddLocale(const std::set<std::string>& chrome_locales,
38 const FilePath& locale_folder, 38 const FilePath& locale_folder,
39 const std::string& locale_name,
39 std::set<std::string>* valid_locales, 40 std::set<std::string>* valid_locales,
40 std::string* locale_name,
41 std::string* error) { 41 std::string* error) {
42 // Normalize underscores to hyphens because that's what our locale files use.
43 std::replace(locale_name->begin(), locale_name->end(), '_', '-');
44 // Accept name that starts with a . but don't add it to the list of supported 42 // Accept name that starts with a . but don't add it to the list of supported
45 // locales. 43 // locales.
46 if (locale_name->find(".") == 0) 44 if (locale_name.find(".") == 0)
47 return true; 45 return true;
48 if (chrome_locales.find(*locale_name) == chrome_locales.end()) { 46 if (chrome_locales.find(locale_name) == chrome_locales.end()) {
49 // Fail if there is an extension locale that's not in the Chrome list. 47 // Fail if there is an extension locale that's not in the Chrome list.
50 *error = StringPrintf("Supplied locale %s is not supported.", 48 *error = StringPrintf("Supplied locale %s is not supported.",
51 locale_name->c_str()); 49 locale_name.c_str());
52 return false; 50 return false;
53 } 51 }
54 // Check if messages file is actually present (but don't check content). 52 // Check if messages file is actually present (but don't check content).
55 if (file_util::PathExists( 53 if (file_util::PathExists(
56 locale_folder.AppendASCII(Extension::kMessagesFilename))) { 54 locale_folder.AppendASCII(Extension::kMessagesFilename))) {
57 valid_locales->insert(*locale_name); 55 valid_locales->insert(locale_name);
58 } else { 56 } else {
59 *error = StringPrintf("Catalog file is missing for locale %s.", 57 *error = StringPrintf("Catalog file is missing for locale %s.",
60 locale_name->c_str()); 58 locale_name.c_str());
61 return false; 59 return false;
62 } 60 }
63 61
64 return true; 62 return true;
65 } 63 }
66 64
65 // Converts all - into _, to be consistent with ICU and file system names.
66 static std::string NormalizeLocale(const std::string& locale) {
67 std::string normalized_locale(locale);
68 std::replace(normalized_locale.begin(), normalized_locale.end(), '-', '_');
69
70 return normalized_locale;
71 }
72
73 // Produce a vector of parent locales for given locale.
74 // It includes the current locale in the result.
75 // sr_Cyrl_RS generates sr_Cyrl_RS, sr_Cyrl and sr.
76 static void GetParentLocales(const std::string& current_locale,
77 std::vector<std::string>* parent_locales) {
78 std::string locale(NormalizeLocale(current_locale));
79
80 const int kNameCapacity = 256;
81 char parent[kNameCapacity];
82 strncpy(parent, locale.c_str(), kNameCapacity);
83 parent_locales->push_back(parent);
84 UErrorCode err = U_ZERO_ERROR;
85 while (uloc_getParent(parent, parent, kNameCapacity, &err) > 0) {
86 if (err != U_ZERO_ERROR)
87 break;
88 parent_locales->push_back(parent);
89 }
90 }
91
92 // Extends list of Chrome locales to them and their parents, so we can do
93 // proper fallback.
94 static void GetAllLocales(std::set<std::string>* all_locales) {
95 const std::vector<std::string>& available_locales =
96 l10n_util::GetAvailableLocales();
97 // Add all parents of the current locale to the available locales set.
98 // I.e. for sr_Cyrl_RS we add sr_Cyrl_RS, sr_Cyrl and sr.
99 for (size_t i = 0; i < available_locales.size(); ++i) {
100 std::vector<std::string> result;
101 GetParentLocales(available_locales[i], &result);
102 all_locales->insert(result.begin(), result.end());
103 }
104 }
105
67 bool GetValidLocales(const FilePath& locale_path, 106 bool GetValidLocales(const FilePath& locale_path,
68 std::set<std::string>* valid_locales, 107 std::set<std::string>* valid_locales,
69 std::string* error) { 108 std::string* error) {
70 // Get available chrome locales as a set. 109 static std::set<std::string> chrome_locales;
71 const std::vector<std::string>& available_locales = 110 GetAllLocales(&chrome_locales);
72 l10n_util::GetAvailableLocales(); 111
73 static std::set<std::string> chrome_locales(available_locales.begin(),
74 available_locales.end());
75 // Enumerate all supplied locales in the extension. 112 // Enumerate all supplied locales in the extension.
76 file_util::FileEnumerator locales(locale_path, 113 file_util::FileEnumerator locales(locale_path,
77 false, 114 false,
78 file_util::FileEnumerator::DIRECTORIES); 115 file_util::FileEnumerator::DIRECTORIES);
79 FilePath locale_folder; 116 FilePath locale_folder;
80 while (!(locale_folder = locales.Next()).empty()) { 117 while (!(locale_folder = locales.Next()).empty()) {
81 std::string locale_name = 118 std::string locale_name =
82 WideToASCII(locale_folder.BaseName().ToWStringHack()); 119 WideToASCII(locale_folder.BaseName().ToWStringHack());
83 if (!AddLocale(chrome_locales, 120 if (!AddLocale(chrome_locales,
84 locale_folder, 121 locale_folder,
122 locale_name,
85 valid_locales, 123 valid_locales,
86 &locale_name,
87 error)) { 124 error)) {
88 return false; 125 return false;
89 } 126 }
90 } 127 }
91 128
92 if (valid_locales->empty()) { 129 if (valid_locales->empty()) {
93 *error = extension_manifest_errors::kLocalesNoValidLocaleNamesListed; 130 *error = extension_manifest_errors::kLocalesNoValidLocaleNamesListed;
94 return false; 131 return false;
95 } 132 }
96 133
97 return true; 134 return true;
98 } 135 }
99 136
100 // Loads contents of the messages file for given locale. If file is not found, 137 // Loads contents of the messages file for given locale. If file is not found,
101 // or there was parsing error we return NULL and set |error|. 138 // or there was parsing error we return NULL and set |error|.
102 // Caller owns the returned object. 139 // Caller owns the returned object.
103 static DictionaryValue* LoadMessageFile(const FilePath& locale_path, 140 static DictionaryValue* LoadMessageFile(const FilePath& locale_path,
104 const std::string& locale, 141 const std::string& locale,
105 std::string* error) { 142 std::string* error) {
143
106 std::string extension_locale = locale; 144 std::string extension_locale = locale;
107 // Normalize hyphens to underscores because that's what our locale files use.
108 std::replace(extension_locale.begin(), extension_locale.end(), '-', '_');
109 FilePath file = locale_path.AppendASCII(extension_locale) 145 FilePath file = locale_path.AppendASCII(extension_locale)
110 .AppendASCII(Extension::kMessagesFilename); 146 .AppendASCII(Extension::kMessagesFilename);
111 JSONFileValueSerializer messages_serializer(file); 147 JSONFileValueSerializer messages_serializer(file);
112 Value *dictionary = messages_serializer.Deserialize(error); 148 Value *dictionary = messages_serializer.Deserialize(error);
113 if (!dictionary && error->empty()) { 149 if (!dictionary && error->empty()) {
114 // JSONFileValueSerializer just returns NULL if file cannot be found. It 150 // JSONFileValueSerializer just returns NULL if file cannot be found. It
115 // doesn't set the error, so we have to do it. 151 // doesn't set the error, so we have to do it.
116 *error = StringPrintf("Catalog file is missing for locale %s.", 152 *error = StringPrintf("Catalog file is missing for locale %s.",
117 extension_locale.c_str()); 153 extension_locale.c_str());
118 } 154 }
119 155
120 return static_cast<DictionaryValue*>(dictionary); 156 return static_cast<DictionaryValue*>(dictionary);
121 } 157 }
122 158
123 ExtensionMessageBundle* LoadMessageCatalogs( 159 ExtensionMessageBundle* LoadMessageCatalogs(
124 const FilePath& locale_path, 160 const FilePath& locale_path,
125 const std::string& default_locale, 161 const std::string& default_locale,
126 const std::string& application_locale, 162 const std::string& application_locale,
163 const std::set<std::string>& valid_locales,
127 std::string* error) { 164 std::string* error) {
128 scoped_ptr<DictionaryValue> default_catalog( 165 // Order locales to load as current_locale, first_parent, ..., default_locale.
129 LoadMessageFile(locale_path, default_locale, error)); 166 std::vector<std::string> all_fallback_locales;
130 if (!default_catalog.get()) { 167 if (!application_locale.empty() && application_locale != default_locale)
131 return false; 168 GetParentLocales(application_locale, &all_fallback_locales);
169 all_fallback_locales.push_back(default_locale);
170
171 std::vector<linked_ptr<DictionaryValue> > catalogs;
172 for (size_t i = 0; i < all_fallback_locales.size(); ++i) {
173 // Skip all parent locales that are not supplied.
174 if (valid_locales.find(all_fallback_locales[i]) == valid_locales.end())
175 continue;
176 linked_ptr<DictionaryValue> catalog(
177 LoadMessageFile(locale_path, all_fallback_locales[i], error));
178 if (!catalog.get()) {
179 // If locale is valid, but messages.json is corrupted or missing, return
180 // an error.
181 return false;
182 } else {
183 catalogs.push_back(catalog);
184 }
132 } 185 }
133 186
134 scoped_ptr<DictionaryValue> app_catalog( 187 return ExtensionMessageBundle::Create(catalogs, error);
135 LoadMessageFile(locale_path, application_locale, error));
136 if (!app_catalog.get()) {
137 // Only default catalog has to be present. This is not an error.
138 app_catalog.reset(new DictionaryValue);
139 error->clear();
140 }
141
142 return ExtensionMessageBundle::Create(*default_catalog,
143 *app_catalog,
144 error);
145 } 188 }
146 189
147 FilePath GetL10nRelativePath(const FilePath& relative_resource_path) { 190 FilePath GetL10nRelativePath(const FilePath& relative_resource_path) {
148 // Get locale relative path. 191 // Get locale relative path.
149 static std::string current_locale = l10n_util::GetApplicationLocale(L""); 192 static std::string current_locale = l10n_util::GetApplicationLocale(L"");
150 std::replace(current_locale.begin(), current_locale.end(), '-', '_'); 193 std::replace(current_locale.begin(), current_locale.end(), '-', '_');
151 194
152 FilePath locale_relative_path; 195 FilePath locale_relative_path;
153 return locale_relative_path 196 return locale_relative_path
154 .AppendASCII(Extension::kLocaleFolder) 197 .AppendASCII(Extension::kLocaleFolder)
155 .AppendASCII(current_locale) 198 .AppendASCII(current_locale)
156 .Append(relative_resource_path); 199 .Append(relative_resource_path);
157 } 200 }
158 201
159 } // namespace extension_l10n_util 202 } // namespace extension_l10n_util
OLDNEW
« no previous file with comments | « chrome/browser/extensions/extension_l10n_util.h ('k') | chrome/browser/extensions/extension_l10n_util_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698