summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--chrome/browser/extensions/extension_file_util.cc60
-rw-r--r--chrome/browser/extensions/extension_file_util.h7
-rw-r--r--chrome/browser/extensions/extension_file_util_unittest.cc109
-rw-r--r--chrome/browser/extensions/extension_l10n_util.cc90
-rw-r--r--chrome/browser/extensions/extension_l10n_util.h46
-rw-r--r--chrome/browser/extensions/extension_l10n_util_unittest.cc135
-rw-r--r--chrome/chrome.gyp3
-rw-r--r--chrome/common/extensions/extension.cc14
-rw-r--r--chrome/common/extensions/extension.h26
-rw-r--r--chrome/common/extensions/extension_constants.cc7
-rw-r--r--chrome/common/extensions/extension_constants.h6
-rw-r--r--chrome/common/extensions/extension_unittest.cc6
12 files changed, 508 insertions, 1 deletions
diff --git a/chrome/browser/extensions/extension_file_util.cc b/chrome/browser/extensions/extension_file_util.cc
index 07ef77f..bf6cd9c 100644
--- a/chrome/browser/extensions/extension_file_util.cc
+++ b/chrome/browser/extensions/extension_file_util.cc
@@ -8,6 +8,7 @@
#include "base/logging.h"
#include "base/scoped_temp_dir.h"
#include "base/string_util.h"
+#include "chrome/browser/extensions/extension_l10n_util.h"
#include "chrome/common/extensions/extension.h"
#include "chrome/common/extensions/extension_constants.h"
#include "chrome/common/json_value_serializer.h"
@@ -276,6 +277,27 @@ Extension* LoadExtension(const FilePath& extension_path, bool require_key,
}
}
+ // Load locale information if available.
+ FilePath locale_path = extension_path.AppendASCII(Extension::kLocaleFolder);
+ if (file_util::PathExists(locale_path)) {
+ if (!extension_l10n_util::AddValidLocales(locale_path,
+ extension.get(),
+ error)) {
+ return NULL;
+ }
+
+ if (!extension_l10n_util::ValidateDefaultLocale(extension.get())) {
+ *error = extension_manifest_errors::kLocalesNoDefaultLocaleSpecified;
+ return NULL;
+ }
+ }
+
+ // Check children of extension root to see if any of them start with _ and is
+ // not on the reserved list.
+ if (!CheckForIllegalFilenames(extension_path, error)) {
+ return NULL;
+ }
+
return extension.release();
}
@@ -349,4 +371,42 @@ void GarbageCollectExtensions(const FilePath& install_directory) {
}
}
+bool CheckForIllegalFilenames(const FilePath& extension_path,
+ std::string* error) {
+ // Reserved underscore names.
+ static const char* reserved_names[] = {
+ Extension::kLocaleFolder
+ };
+ static std::set<std::string> reserved_underscore_names(
+ reserved_names, reserved_names + arraysize(reserved_names));
+
+ // Enumerate all files and directories in the extension root.
+ // There is a problem when using pattern "_*" with FileEnumerator, so we have
+ // to cheat with find_first_of and match all.
+ file_util::FileEnumerator all_files(
+ extension_path,
+ false,
+ static_cast<file_util::FileEnumerator::FILE_TYPE>(
+ file_util::FileEnumerator::DIRECTORIES |
+ file_util::FileEnumerator::FILES));
+
+ FilePath files;
+ while (!(files = all_files.Next()).empty()) {
+ std::string filename =
+ WideToASCII(files.BaseName().ToWStringHack());
+ // Skip all that don't start with "_".
+ if (filename.find_first_of("_") != 0) continue;
+ if (reserved_underscore_names.find(filename) ==
+ reserved_underscore_names.end()) {
+ *error = StringPrintf(
+ "Cannot load extension with file or directory name %s."
+ "Filenames starting with \"_\" are reserved for use by the system",
+ filename.c_str());
+ return false;
+ }
+ }
+
+ return true;
+}
+
} // extensionfile_util
diff --git a/chrome/browser/extensions/extension_file_util.h b/chrome/browser/extensions/extension_file_util.h
index 45d0b30..c2eb5c9 100644
--- a/chrome/browser/extensions/extension_file_util.h
+++ b/chrome/browser/extensions/extension_file_util.h
@@ -78,6 +78,13 @@ void UninstallExtension(const std::string& id, const FilePath& extensions_dir);
// removing others?
void GarbageCollectExtensions(const FilePath& extensions_dir);
+// We need to reserve the namespace of entries that start with "_" for future
+// use by Chrome.
+// If any files or directories are found using "_" prefix and are not on
+// reserved list we return false, and set error message.
+bool CheckForIllegalFilenames(const FilePath& extension_path,
+ std::string* error);
+
} // extension_file_util
#endif // CHROME_BROWSER_EXTENSIONS_EXTENSION_FILE_UTIL_H_
diff --git a/chrome/browser/extensions/extension_file_util_unittest.cc b/chrome/browser/extensions/extension_file_util_unittest.cc
index 6e9b2dc..73dfb46 100644
--- a/chrome/browser/extensions/extension_file_util_unittest.cc
+++ b/chrome/browser/extensions/extension_file_util_unittest.cc
@@ -8,8 +8,13 @@
#include "base/scoped_temp_dir.h"
#include "base/path_service.h"
#include "chrome/common/chrome_paths.h"
+#include "chrome/common/extensions/extension.h"
+#include "chrome/common/extensions/extension_constants.h"
+#include "chrome/common/json_value_serializer.h"
#include "testing/gtest/include/gtest/gtest.h"
+namespace keys = extension_manifest_keys;
+
TEST(ExtensionFileUtil, MoveDirSafely) {
// Create a test directory structure with some data in it.
ScopedTempDir temp;
@@ -162,6 +167,110 @@ TEST(ExtensionFileUtil, CompareToInstalledVersion) {
ASSERT_EQ("", version_out);
}
+// Creates minimal manifest, with or without default_locale section.
+bool CreateMinimalManifest(const std::string& locale,
+ const FilePath& manifest_path) {
+ DictionaryValue manifest;
+
+ manifest.SetString(keys::kVersion, "1.0.0.0");
+ manifest.SetString(keys::kName, "my extension");
+ if (!locale.empty()) {
+ manifest.SetString(keys::kDefaultLocale, locale);
+ }
+
+ JSONFileValueSerializer serializer(manifest_path);
+ return serializer.Serialize(manifest);
+}
+
+TEST(ExtensionFileUtil, LoadExtensionWithValidLocales) {
+ ScopedTempDir temp;
+ ASSERT_TRUE(temp.CreateUniqueTempDir());
+ ASSERT_TRUE(CreateMinimalManifest(
+ "en_US", temp.path().AppendASCII(Extension::kManifestFilename)));
+
+ FilePath src_path = temp.path().AppendASCII(Extension::kLocaleFolder);
+ ASSERT_TRUE(file_util::CreateDirectory(src_path));
+
+ FilePath locale_1 = src_path.AppendASCII("sr");
+ ASSERT_TRUE(file_util::CreateDirectory(locale_1));
+
+ std::string data = "foobar";
+ ASSERT_TRUE(
+ file_util::WriteFile(locale_1.AppendASCII(Extension::kMessagesFilename),
+ data.c_str(), data.length()));
+
+ FilePath locale_2 = src_path.AppendASCII("en_US");
+ ASSERT_TRUE(file_util::CreateDirectory(locale_2));
+
+ ASSERT_TRUE(
+ file_util::WriteFile(locale_2.AppendASCII(Extension::kMessagesFilename),
+ data.c_str(), data.length()));
+
+ std::string error;
+ scoped_ptr<Extension> extension(
+ extension_file_util::LoadExtension(temp.path(), false, &error));
+ ASSERT_FALSE(extension == NULL);
+ EXPECT_EQ(static_cast<unsigned int>(2),
+ extension->supported_locales().size());
+ EXPECT_EQ("en-US", extension->default_locale());
+}
+
+TEST(ExtensionFileUtil, LoadExtensionWithoutLocalesFolder) {
+ ScopedTempDir temp;
+ ASSERT_TRUE(temp.CreateUniqueTempDir());
+ ASSERT_TRUE(CreateMinimalManifest(
+ "", temp.path().AppendASCII(Extension::kManifestFilename)));
+
+ std::string error;
+ scoped_ptr<Extension> extension(
+ extension_file_util::LoadExtension(temp.path(), false, &error));
+ ASSERT_FALSE(extension == NULL);
+ EXPECT_TRUE(extension->supported_locales().empty());
+ EXPECT_TRUE(extension->default_locale().empty());
+}
+
+TEST(ExtensionFileUtil, CheckIllegalFilenamesNoUnderscores) {
+ ScopedTempDir temp;
+ ASSERT_TRUE(temp.CreateUniqueTempDir());
+
+ FilePath src_path = temp.path().AppendASCII("some_dir");
+ ASSERT_TRUE(file_util::CreateDirectory(src_path));
+
+ std::string data = "foobar";
+ ASSERT_TRUE(file_util::WriteFile(src_path.AppendASCII("some_file.txt"),
+ data.c_str(), data.length()));
+ std::string error;
+ EXPECT_TRUE(extension_file_util::CheckForIllegalFilenames(temp.path(),
+ &error));
+}
+
+TEST(ExtensionFileUtil, CheckIllegalFilenamesOnlyReserved) {
+ ScopedTempDir temp;
+ ASSERT_TRUE(temp.CreateUniqueTempDir());
+
+ FilePath src_path = temp.path().AppendASCII(Extension::kLocaleFolder);
+ ASSERT_TRUE(file_util::CreateDirectory(src_path));
+
+ std::string error;
+ EXPECT_TRUE(extension_file_util::CheckForIllegalFilenames(temp.path(),
+ &error));
+}
+
+TEST(ExtensionFileUtil, CheckIllegalFilenamesReservedAndIllegal) {
+ ScopedTempDir temp;
+ ASSERT_TRUE(temp.CreateUniqueTempDir());
+
+ FilePath src_path = temp.path().AppendASCII(Extension::kLocaleFolder);
+ ASSERT_TRUE(file_util::CreateDirectory(src_path));
+
+ src_path = temp.path().AppendASCII("_some_dir");
+ ASSERT_TRUE(file_util::CreateDirectory(src_path));
+
+ std::string error;
+ EXPECT_FALSE(extension_file_util::CheckForIllegalFilenames(temp.path(),
+ &error));
+}
+
// TODO(aa): More tests as motivation allows. Maybe steal some from
// ExtensionsService? Many of them could probably be tested here without the
// MessageLoop shenanigans.
diff --git a/chrome/browser/extensions/extension_l10n_util.cc b/chrome/browser/extensions/extension_l10n_util.cc
new file mode 100644
index 0000000..77fddba
--- /dev/null
+++ b/chrome/browser/extensions/extension_l10n_util.cc
@@ -0,0 +1,90 @@
+// Copyright (c) 2009 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/extensions/extension_l10n_util.h"
+
+#include <set>
+#include <string>
+#include <vector>
+
+#include "app/l10n_util.h"
+#include "base/file_util.h"
+#include "base/string_util.h"
+#include "base/values.h"
+#include "chrome/common/extensions/extension.h"
+#include "chrome/common/extensions/extension_constants.h"
+
+namespace keys = extension_manifest_keys;
+
+namespace extension_l10n_util {
+
+bool ValidateDefaultLocale(const Extension* extension) {
+ std::string default_locale = extension->default_locale();
+
+ if (extension->supported_locales().find(default_locale) !=
+ extension->supported_locales().end()) {
+ return true;
+ } else {
+ return false;
+ }
+}
+
+
+bool AddLocale(const std::set<std::string>& chrome_locales,
+ const FilePath& locale_folder,
+ Extension* extension,
+ 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(), '_', '-');
+ 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());
+ return false;
+ }
+ // Check if messages file is actually present (but don't check content).
+ if (file_util::PathExists(
+ locale_folder.AppendASCII(Extension::kMessagesFilename))) {
+ extension->AddSupportedLocale(*locale_name);
+ } else {
+ *error = StringPrintf("Catalog file is missing for locale %s.",
+ locale_name->c_str());
+ return false;
+ }
+
+ return true;
+}
+
+bool AddValidLocales(const FilePath& locale_path,
+ Extension* extension,
+ 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());
+ // Enumerate all supplied locales in the extension.
+ file_util::FileEnumerator locales(locale_path,
+ false,
+ file_util::FileEnumerator::DIRECTORIES);
+ FilePath locale_folder;
+ while (!(locale_folder = locales.Next()).empty()) {
+ std::string locale_name =
+ WideToASCII(locale_folder.BaseName().ToWStringHack());
+ if (!AddLocale(chrome_locales, locale_folder,
+ extension, &locale_name, error)) {
+ return false;
+ }
+ }
+
+ if (extension->supported_locales().empty()) {
+ *error = extension_manifest_errors::kLocalesNoValidLocaleNamesListed;
+ return false;
+ }
+
+ return true;
+}
+
+} // namespace extension_l10n_util
diff --git a/chrome/browser/extensions/extension_l10n_util.h b/chrome/browser/extensions/extension_l10n_util.h
new file mode 100644
index 0000000..d964566
--- /dev/null
+++ b/chrome/browser/extensions/extension_l10n_util.h
@@ -0,0 +1,46 @@
+// Copyright (c) 2009 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+// This file declares extension specific l10n utils.
+
+#ifndef CHROME_BROWSER_EXTENSIONS_EXTENSION_L10N_UTIL_H_
+#define CHROME_BROWSER_EXTENSIONS_EXTENSION_L10N_UTIL_H_
+
+#include <set>
+#include <string>
+
+class DictionaryValue;
+class Extension;
+class FilePath;
+
+namespace extension_l10n_util {
+
+// Returns true if default_locale was set to valid locale
+// (supported by the extension).
+bool ValidateDefaultLocale(const Extension* extension);
+
+// Adds locale_name to the extension if it's in chrome_locales, and
+// if messages file is present (we don't check content of messages file here).
+// Returns false if locale_name was not found in chrome_locales, and sets
+// error with locale_name.
+bool AddLocale(const std::set<std::string>& chrome_locales,
+ const FilePath& locale_folder,
+ Extension* extension,
+ std::string* locale_name,
+ std::string* error);
+
+// Adds valid locales to the extension.
+// 1. Do nothing if _locales directory is missing (not an error).
+// 2. Get list of Chrome locales.
+// 3. Enumerate all subdirectories of _locales directory.
+// 4. Intersect both lists, and add intersection to the extension.
+// Returns false if any of supplied locales don't match chrome list of locales.
+// Fills out error with offending locale name.
+bool AddValidLocales(const FilePath& locale_path,
+ Extension* extension,
+ std::string* error);
+
+} // namespace extension_l10n_util
+
+#endif // CHROME_BROWSER_EXTENSIONS_EXTENSION_L10N_UTIL_H_
diff --git a/chrome/browser/extensions/extension_l10n_util_unittest.cc b/chrome/browser/extensions/extension_l10n_util_unittest.cc
new file mode 100644
index 0000000..04f1ac0
--- /dev/null
+++ b/chrome/browser/extensions/extension_l10n_util_unittest.cc
@@ -0,0 +1,135 @@
+// Copyright (c) 2009 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/extensions/extension_l10n_util.h"
+
+#include "base/file_path.h"
+#include "base/file_util.h"
+#include "base/scoped_ptr.h"
+#include "base/scoped_temp_dir.h"
+#include "base/values.h"
+#include "chrome/common/extensions/extension.h"
+#include "chrome/common/extensions/extension_constants.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace keys = extension_manifest_keys;
+
+namespace {
+
+ Extension* CreateMinimalExtension(const std::string& default_locale) {
+#if defined(OS_WIN)
+ FilePath path(FILE_PATH_LITERAL("C:\\foo"));
+#elif defined(OS_POSIX)
+ FilePath path(FILE_PATH_LITERAL("/foo"));
+#endif
+ Extension* extension = new Extension(path);
+ std::string error;
+ DictionaryValue input_value;
+
+ // Test minimal extension
+ input_value.SetString(keys::kVersion, "1.0.0.0");
+ input_value.SetString(keys::kName, "my extension");
+ if (!default_locale.empty()) {
+ input_value.SetString(keys::kDefaultLocale, default_locale);
+ }
+ EXPECT_TRUE(extension->InitFromValue(input_value, false, &error));
+
+ return extension;
+}
+
+TEST(ExtensionL10nUtil, AddValidLocalesEmptyLocaleFolder) {
+ ScopedTempDir temp;
+ ASSERT_TRUE(temp.CreateUniqueTempDir());
+
+ FilePath src_path = temp.path().AppendASCII(Extension::kLocaleFolder);
+ ASSERT_TRUE(file_util::CreateDirectory(src_path));
+
+ scoped_ptr<Extension> extension(CreateMinimalExtension(""));
+
+ std::string error;
+ EXPECT_FALSE(extension_l10n_util::AddValidLocales(src_path,
+ extension.get(),
+ &error));
+
+ EXPECT_TRUE(extension->supported_locales().empty());
+}
+
+TEST(ExtensionL10nUtil, AddValidLocalesWithValidLocaleNoMessagesFile) {
+ ScopedTempDir temp;
+ ASSERT_TRUE(temp.CreateUniqueTempDir());
+
+ FilePath src_path = temp.path().AppendASCII(Extension::kLocaleFolder);
+ ASSERT_TRUE(file_util::CreateDirectory(src_path));
+
+ ASSERT_TRUE(file_util::CreateDirectory(src_path.AppendASCII("sr")));
+
+ scoped_ptr<Extension> extension(CreateMinimalExtension(""));
+
+ std::string error;
+ EXPECT_FALSE(extension_l10n_util::AddValidLocales(src_path,
+ extension.get(),
+ &error));
+
+ EXPECT_TRUE(extension->supported_locales().empty());
+}
+
+TEST(ExtensionL10nUtil, AddValidLocalesWithValidLocalesAndMessagesFile) {
+ ScopedTempDir temp;
+ ASSERT_TRUE(temp.CreateUniqueTempDir());
+
+ FilePath src_path = temp.path().AppendASCII(Extension::kLocaleFolder);
+ ASSERT_TRUE(file_util::CreateDirectory(src_path));
+
+ FilePath locale_1 = src_path.AppendASCII("sr");
+ ASSERT_TRUE(file_util::CreateDirectory(locale_1));
+
+ std::string data = "foobar";
+ ASSERT_TRUE(
+ file_util::WriteFile(locale_1.AppendASCII(Extension::kMessagesFilename),
+ data.c_str(), data.length()));
+
+ FilePath locale_2 = src_path.AppendASCII("en_US");
+ ASSERT_TRUE(file_util::CreateDirectory(locale_2));
+
+ ASSERT_TRUE(
+ file_util::WriteFile(locale_2.AppendASCII(Extension::kMessagesFilename),
+ data.c_str(), data.length()));
+
+ scoped_ptr<Extension> extension(CreateMinimalExtension(""));
+
+ std::string error;
+ EXPECT_TRUE(extension_l10n_util::AddValidLocales(src_path,
+ extension.get(),
+ &error));
+
+ EXPECT_EQ(static_cast<unsigned int>(2),
+ extension->supported_locales().size());
+}
+
+TEST(ExtensionL10nUtil, SetDefaultLocaleGoodDefaultLocaleInManifest) {
+ scoped_ptr<Extension> extension(CreateMinimalExtension("sr"));
+ extension->AddSupportedLocale("sr");
+ extension->AddSupportedLocale("en-US");
+
+ EXPECT_TRUE(extension_l10n_util::ValidateDefaultLocale(extension.get()));
+ EXPECT_EQ("sr", extension->default_locale());
+}
+
+TEST(ExtensionL10nUtil, SetDefaultLocaleNoDefaultLocaleInManifest) {
+ scoped_ptr<Extension> extension(CreateMinimalExtension(""));
+ extension->AddSupportedLocale("sr");
+ extension->AddSupportedLocale("en-US");
+
+ EXPECT_FALSE(extension_l10n_util::ValidateDefaultLocale(extension.get()));
+}
+
+TEST(ExtensionL10nUtil, SetDefaultLocaleWrongDefaultLocaleInManifest) {
+ scoped_ptr<Extension> extension(CreateMinimalExtension("ko"));
+ extension->AddSupportedLocale("sr");
+ extension->AddSupportedLocale("en-US");
+
+ EXPECT_FALSE(extension_l10n_util::ValidateDefaultLocale(extension.get()));
+}
+
+} // namespace
diff --git a/chrome/chrome.gyp b/chrome/chrome.gyp
index ac30fbb..d6d6e9f 100644
--- a/chrome/chrome.gyp
+++ b/chrome/chrome.gyp
@@ -1046,6 +1046,8 @@
'browser/extensions/extension_host.h',
'browser/extensions/extension_install_ui.cc',
'browser/extensions/extension_install_ui.h',
+ 'browser/extensions/extension_l10n_util.cc',
+ 'browser/extensions/extension_l10n_util.h',
'browser/extensions/extension_message_service.cc',
'browser/extensions/extension_message_service.h',
'browser/extensions/extension_browser_event_router.cc',
@@ -3864,6 +3866,7 @@
'browser/download/save_package_unittest.cc',
'browser/encoding_menu_controller_unittest.cc',
'browser/extensions/extension_file_util_unittest.cc',
+ 'browser/extensions/extension_l10n_util_unittest.cc',
'browser/extensions/extension_messages_unittest.cc',
'browser/extensions/extension_process_manager_unittest.cc',
'browser/extensions/extension_ui_unittest.cc',
diff --git a/chrome/common/extensions/extension.cc b/chrome/common/extensions/extension.cc
index 08b77bb..5ceee67 100644
--- a/chrome/common/extensions/extension.cc
+++ b/chrome/common/extensions/extension.cc
@@ -67,6 +67,8 @@ static bool IsAPIPermission(const std::string& str) {
int Extension::id_counter_ = 0;
const char Extension::kManifestFilename[] = "manifest.json";
+const char Extension::kLocaleFolder[] = "_locales";
+const char Extension::kMessagesFilename[] = "messages";
// A list of all the keys allowed by themes.
static const wchar_t* kValidThemeKeys[] = {
@@ -935,6 +937,18 @@ bool Extension::InitFromValue(const DictionaryValue& source, bool require_id,
}
}
+ // Initialize default locale (if present).
+ if (source.HasKey(keys::kDefaultLocale)) {
+ std::string default_locale;
+ if (!source.GetString(keys::kDefaultLocale, &default_locale)) {
+ *error = errors::kInvalidDefaultLocale;
+ return false;
+ }
+ // Normalize underscores to hyphens.
+ std::replace(default_locale.begin(), default_locale.end(), '_', '-');
+ set_default_locale(default_locale);
+ }
+
return true;
}
diff --git a/chrome/common/extensions/extension.h b/chrome/common/extensions/extension.h
index afd62c1..f3acd1c 100644
--- a/chrome/common/extensions/extension.h
+++ b/chrome/common/extensions/extension.h
@@ -5,6 +5,7 @@
#ifndef CHROME_COMMON_EXTENSIONS_EXTENSION_H_
#define CHROME_COMMON_EXTENSIONS_EXTENSION_H_
+#include <map>
#include <set>
#include <string>
#include <vector>
@@ -95,6 +96,12 @@ class Extension {
// The name of the manifest inside an extension.
static const char kManifestFilename[];
+ // The name of locale folder inside an extension.
+ static const char kLocaleFolder[];
+
+ // The name of the messages file inside an extension.
+ static const char kMessagesFilename[];
+
#if defined(OS_WIN)
static const char* kExtensionRegistryPath;
#endif
@@ -230,6 +237,20 @@ class Extension {
// an empty FilePath if the extension does not have that icon.
FilePath GetIconPath(Icons icon);
+ // Returns a list of all locales supported by the extension.
+ const std::set<std::string>& supported_locales() const {
+ return supported_locales_;
+ }
+ // Add locale to the list of supported locales.
+ void AddSupportedLocale(const std::string& supported_locale) {
+ supported_locales_.insert(supported_locale);
+ }
+
+ // Getter/setter for a default_locale_.
+ const std::string& default_locale() const { return default_locale_; }
+ void set_default_locale(const std::string& default_locale) {
+ default_locale_ = default_locale;
+ }
// Runtime data:
// Put dynamic data about the state of a running extension below.
@@ -342,6 +363,11 @@ class Extension {
// URL for fetching an update manifest
GURL update_url_;
+ // List of all locales extension supports.
+ std::set<std::string> supported_locales_;
+
+ // Default locale, used for fallback.
+ std::string default_locale_;
// Runtime data:
diff --git a/chrome/common/extensions/extension_constants.cc b/chrome/common/extensions/extension_constants.cc
index f1b8783..d887678 100644
--- a/chrome/common/extensions/extension_constants.cc
+++ b/chrome/common/extensions/extension_constants.cc
@@ -9,6 +9,7 @@ namespace extension_manifest_keys {
const wchar_t* kBackground = L"background_page";
const wchar_t* kContentScripts = L"content_scripts";
const wchar_t* kCss = L"css";
+const wchar_t* kDefaultLocale = L"default_locale";
const wchar_t* kDescription = L"description";
const wchar_t* kIcons = L"icons";
const wchar_t* kJs = L"js";
@@ -142,6 +143,12 @@ const char* kInvalidThemeTints =
"Invalid value for theme images - tints must be decimal numbers.";
const char* kInvalidUpdateURL =
"Invalid value for update url: '[*]'.";
+const char* kInvalidDefaultLocale =
+ "Invalid value for default locale - locale name must be a string.";
const char* kThemesCannotContainExtensions =
"A theme cannot contain extensions code.";
+const char* kLocalesNoDefaultLocaleSpecified =
+ "Localization used, but default_locale wasn't specified in the manifest.";
+const char* kLocalesNoValidLocaleNamesListed =
+ "No valid locale name could be found in _locales directory.";
} // namespace extension_manifest_errors
diff --git a/chrome/common/extensions/extension_constants.h b/chrome/common/extensions/extension_constants.h
index 2785b28..b808665 100644
--- a/chrome/common/extensions/extension_constants.h
+++ b/chrome/common/extensions/extension_constants.h
@@ -10,6 +10,7 @@ namespace extension_manifest_keys {
extern const wchar_t* kBackground;
extern const wchar_t* kContentScripts;
extern const wchar_t* kCss;
+ extern const wchar_t* kDefaultLocale;
extern const wchar_t* kDescription;
extern const wchar_t* kIcons;
extern const wchar_t* kJs;
@@ -38,7 +39,7 @@ namespace extension_manifest_keys {
extern const wchar_t* kType;
extern const wchar_t* kVersion;
extern const wchar_t* kUpdateURL;
-} // namespace extension_manifest_keys
+} // namespace extension_manifest_keys
// Some values expected in manifests.
namespace extension_manifest_values {
@@ -96,6 +97,9 @@ namespace extension_manifest_errors {
extern const char* kThemesCannotContainExtensions;
extern const char* kMissingFile;
extern const char* kInvalidUpdateURL;
+ extern const char* kInvalidDefaultLocale;
+ extern const char* kLocalesNoDefaultLocaleSpecified;
+ extern const char* kLocalesNoValidLocaleNamesListed;
} // namespace extension_manifest_errors
#endif // CHROME_COMMON_EXTENSIONS_EXTENSION_CONSTANTS_H_
diff --git a/chrome/common/extensions/extension_unittest.cc b/chrome/common/extensions/extension_unittest.cc
index fc97cc1..10edbbb 100644
--- a/chrome/common/extensions/extension_unittest.cc
+++ b/chrome/common/extensions/extension_unittest.cc
@@ -231,6 +231,12 @@ TEST(ExtensionTest, InitFromValueInvalid) {
privacy_blacklists->Set(0, Value::CreateIntegerValue(42));
EXPECT_FALSE(extension.InitFromValue(*input_value, true, &error));
EXPECT_TRUE(MatchPattern(error, errors::kInvalidPrivacyBlacklistsPath));
+
+ // Test invalid default locale.
+ input_value.reset(static_cast<DictionaryValue*>(valid_value->DeepCopy()));
+ input_value->SetInteger(keys::kDefaultLocale, 42);
+ EXPECT_FALSE(extension.InitFromValue(*input_value, true, &error));
+ EXPECT_EQ(errors::kInvalidDefaultLocale, error);
}
TEST(ExtensionTest, InitFromValueValid) {