| Index: chrome/browser/extensions/extension_l10n_util.cc
|
| ===================================================================
|
| --- chrome/browser/extensions/extension_l10n_util.cc (revision 29587)
|
| +++ chrome/browser/extensions/extension_l10n_util.cc (working copy)
|
| @@ -10,6 +10,7 @@
|
|
|
| #include "app/l10n_util.h"
|
| #include "base/file_util.h"
|
| +#include "base/linked_ptr.h"
|
| #include "base/string_util.h"
|
| #include "base/values.h"
|
| #include "chrome/common/extensions/extension.h"
|
| @@ -29,49 +30,85 @@
|
| *error = errors::kInvalidDefaultLocale;
|
| return "";
|
| }
|
| - // Normalize underscores to hyphens.
|
| - std::replace(default_locale.begin(), default_locale.end(), '_', '-');
|
| +
|
| return default_locale;
|
| }
|
|
|
| bool AddLocale(const std::set<std::string>& chrome_locales,
|
| const FilePath& locale_folder,
|
| + const std::string& locale_name,
|
| std::set<std::string>* valid_locales,
|
| - std::string* locale_name,
|
| std::string* error) {
|
| - // Normalize underscores to hyphens because that's what our locale files use.
|
| - std::replace(locale_name->begin(), locale_name->end(), '_', '-');
|
| // Accept name that starts with a . but don't add it to the list of supported
|
| // locales.
|
| - if (locale_name->find(".") == 0)
|
| + if (locale_name.find(".") == 0)
|
| return true;
|
| - if (chrome_locales.find(*locale_name) == chrome_locales.end()) {
|
| + if (chrome_locales.find(locale_name) == chrome_locales.end()) {
|
| // Fail if there is an extension locale that's not in the Chrome list.
|
| *error = StringPrintf("Supplied locale %s is not supported.",
|
| - locale_name->c_str());
|
| + locale_name.c_str());
|
| return false;
|
| }
|
| // Check if messages file is actually present (but don't check content).
|
| if (file_util::PathExists(
|
| locale_folder.AppendASCII(Extension::kMessagesFilename))) {
|
| - valid_locales->insert(*locale_name);
|
| + valid_locales->insert(locale_name);
|
| } else {
|
| *error = StringPrintf("Catalog file is missing for locale %s.",
|
| - locale_name->c_str());
|
| + locale_name.c_str());
|
| return false;
|
| }
|
|
|
| return true;
|
| }
|
|
|
| +// Converts all - into _, to be consistent with ICU and file system names.
|
| +static std::string NormalizeLocale(const std::string& locale) {
|
| + std::string normalized_locale(locale);
|
| + std::replace(normalized_locale.begin(), normalized_locale.end(), '-', '_');
|
| +
|
| + return normalized_locale;
|
| +}
|
| +
|
| +// Produce a vector of parent locales for given locale.
|
| +// It includes the current locale in the result.
|
| +// sr_Cyrl_RS generates sr_Cyrl_RS, sr_Cyrl and sr.
|
| +static void GetParentLocales(const std::string& current_locale,
|
| + std::vector<std::string>* parent_locales) {
|
| + std::string locale(NormalizeLocale(current_locale));
|
| +
|
| + const int kNameCapacity = 256;
|
| + char parent[kNameCapacity];
|
| + strncpy(parent, locale.c_str(), kNameCapacity);
|
| + parent_locales->push_back(parent);
|
| + UErrorCode err = U_ZERO_ERROR;
|
| + while (uloc_getParent(parent, parent, kNameCapacity, &err) > 0) {
|
| + if (err != U_ZERO_ERROR)
|
| + break;
|
| + parent_locales->push_back(parent);
|
| + }
|
| +}
|
| +
|
| +// Extends list of Chrome locales to them and their parents, so we can do
|
| +// proper fallback.
|
| +static void GetAllLocales(std::set<std::string>* all_locales) {
|
| + const std::vector<std::string>& available_locales =
|
| + l10n_util::GetAvailableLocales();
|
| + // Add all parents of the current locale to the available locales set.
|
| + // I.e. for sr_Cyrl_RS we add sr_Cyrl_RS, sr_Cyrl and sr.
|
| + for (size_t i = 0; i < available_locales.size(); ++i) {
|
| + std::vector<std::string> result;
|
| + GetParentLocales(available_locales[i], &result);
|
| + all_locales->insert(result.begin(), result.end());
|
| + }
|
| +}
|
| +
|
| bool GetValidLocales(const FilePath& locale_path,
|
| std::set<std::string>* valid_locales,
|
| std::string* error) {
|
| - // Get available chrome locales as a set.
|
| - const std::vector<std::string>& available_locales =
|
| - l10n_util::GetAvailableLocales();
|
| - static std::set<std::string> chrome_locales(available_locales.begin(),
|
| - available_locales.end());
|
| + static std::set<std::string> chrome_locales;
|
| + GetAllLocales(&chrome_locales);
|
| +
|
| // Enumerate all supplied locales in the extension.
|
| file_util::FileEnumerator locales(locale_path,
|
| false,
|
| @@ -82,8 +119,8 @@
|
| WideToASCII(locale_folder.BaseName().ToWStringHack());
|
| if (!AddLocale(chrome_locales,
|
| locale_folder,
|
| + locale_name,
|
| valid_locales,
|
| - &locale_name,
|
| error)) {
|
| return false;
|
| }
|
| @@ -103,9 +140,8 @@
|
| static DictionaryValue* LoadMessageFile(const FilePath& locale_path,
|
| const std::string& locale,
|
| std::string* error) {
|
| +
|
| std::string extension_locale = locale;
|
| - // Normalize hyphens to underscores because that's what our locale files use.
|
| - std::replace(extension_locale.begin(), extension_locale.end(), '-', '_');
|
| FilePath file = locale_path.AppendASCII(extension_locale)
|
| .AppendASCII(Extension::kMessagesFilename);
|
| JSONFileValueSerializer messages_serializer(file);
|
| @@ -124,24 +160,31 @@
|
| const FilePath& locale_path,
|
| const std::string& default_locale,
|
| const std::string& application_locale,
|
| + const std::set<std::string>& valid_locales,
|
| std::string* error) {
|
| - scoped_ptr<DictionaryValue> default_catalog(
|
| - LoadMessageFile(locale_path, default_locale, error));
|
| - if (!default_catalog.get()) {
|
| - return false;
|
| - }
|
| + // Order locales to load as current_locale, first_parent, ..., default_locale.
|
| + std::vector<std::string> all_fallback_locales;
|
| + if (!application_locale.empty() && application_locale != default_locale)
|
| + GetParentLocales(application_locale, &all_fallback_locales);
|
| + all_fallback_locales.push_back(default_locale);
|
|
|
| - scoped_ptr<DictionaryValue> app_catalog(
|
| - LoadMessageFile(locale_path, application_locale, error));
|
| - if (!app_catalog.get()) {
|
| - // Only default catalog has to be present. This is not an error.
|
| - app_catalog.reset(new DictionaryValue);
|
| - error->clear();
|
| + std::vector<linked_ptr<DictionaryValue> > catalogs;
|
| + for (size_t i = 0; i < all_fallback_locales.size(); ++i) {
|
| + // Skip all parent locales that are not supplied.
|
| + if (valid_locales.find(all_fallback_locales[i]) == valid_locales.end())
|
| + continue;
|
| + linked_ptr<DictionaryValue> catalog(
|
| + LoadMessageFile(locale_path, all_fallback_locales[i], error));
|
| + if (!catalog.get()) {
|
| + // If locale is valid, but messages.json is corrupted or missing, return
|
| + // an error.
|
| + return false;
|
| + } else {
|
| + catalogs.push_back(catalog);
|
| + }
|
| }
|
|
|
| - return ExtensionMessageBundle::Create(*default_catalog,
|
| - *app_catalog,
|
| - error);
|
| + return ExtensionMessageBundle::Create(catalogs, error);
|
| }
|
|
|
| FilePath GetL10nRelativePath(const FilePath& relative_resource_path) {
|
|
|