15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved. 25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be 35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file. 45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/common/extensions/extension_l10n_util.h" 65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <algorithm> 85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <set> 95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <string> 105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <vector> 115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/file_util.h" 13868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "base/files/file_enumerator.h" 145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/json/json_file_value_serializer.h" 155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/logging.h" 165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/memory/linked_ptr.h" 17868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "base/strings/stringprintf.h" 185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/values.h" 195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/common/extensions/extension_file_util.h" 20868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "chrome/common/extensions/extension_manifest_constants.h" 215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/common/extensions/message_bundle.h" 225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/common/url_constants.h" 232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "extensions/common/constants.h" 24ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch#include "third_party/icu/source/common/unicode/uloc.h" 255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/base/l10n/l10n_util.h" 265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace errors = extension_manifest_errors; 285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace keys = extension_manifest_keys; 295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static std::string& GetProcessLocale() { 315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) CR_DEFINE_STATIC_LOCAL(std::string, locale, ()); 325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return locale; 335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace extension_l10n_util { 365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void SetProcessLocale(const std::string& locale) { 385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) GetProcessLocale() = locale; 395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 417d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)std::string GetDefaultLocaleFromManifest(const base::DictionaryValue& manifest, 425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::string* error) { 435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::string default_locale; 445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (manifest.GetString(keys::kDefaultLocale, &default_locale)) 455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return default_locale; 465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *error = errors::kInvalidDefaultLocale; 48c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) return std::string(); 495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 527d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)bool ShouldRelocalizeManifest(const base::DictionaryValue* manifest) { 535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!manifest) 545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!manifest->HasKey(keys::kDefaultLocale)) 575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::string manifest_current_locale; 605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) manifest->GetString(keys::kCurrentLocale, &manifest_current_locale); 615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return manifest_current_locale != CurrentLocaleOrDefault(); 625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Localizes manifest value for a given key. 655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static bool LocalizeManifestValue(const std::string& key, 665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const extensions::MessageBundle& messages, 677d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) base::DictionaryValue* manifest, 685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::string* error) { 695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::string result; 705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!manifest->GetString(key, &result)) 715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return true; 725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!messages.ReplaceMessages(&result, error)) 745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) manifest->SetString(key, result); 775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return true; 785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool LocalizeManifest(const extensions::MessageBundle& messages, 817d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) base::DictionaryValue* manifest, 825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::string* error) { 835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Initialize name. 845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::string result; 855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!manifest->GetString(keys::kName, &result)) { 865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *error = errors::kInvalidName; 875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!LocalizeManifestValue(keys::kName, messages, manifest, error)) { 905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Initialize description. 945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!LocalizeManifestValue(keys::kDescription, messages, manifest, error)) 955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Initialize browser_action.default_title 985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::string key(keys::kBrowserAction); 995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) key.append("."); 1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) key.append(keys::kPageActionDefaultTitle); 1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!LocalizeManifestValue(key, messages, manifest, error)) 1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Initialize page_action.default_title 1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) key.assign(keys::kPageAction); 1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) key.append("."); 1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) key.append(keys::kPageActionDefaultTitle); 1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!LocalizeManifestValue(key, messages, manifest, error)) 1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Initialize omnibox.keyword. 1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!LocalizeManifestValue(keys::kOmniboxKeyword, messages, manifest, error)) 1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1157d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) base::ListValue* file_handlers = NULL; 1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (manifest->GetList(keys::kFileBrowserHandlers, &file_handlers)) { 1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) key.assign(keys::kFileBrowserHandlers); 1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (size_t i = 0; i < file_handlers->GetSize(); i++) { 1197d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) base::DictionaryValue* handler = NULL; 1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!file_handlers->GetDictionary(i, &handler)) { 1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *error = errors::kInvalidFileBrowserHandler; 1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!LocalizeManifestValue(keys::kPageActionDefaultTitle, messages, 1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) handler, error)) 1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1307d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) base::ListValue* media_galleries_handlers = NULL; 1312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (manifest->GetList(keys::kMediaGalleriesHandlers, 1322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) &media_galleries_handlers)) { 1332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) key.assign(keys::kMediaGalleriesHandlers); 1342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) for (size_t i = 0; i < media_galleries_handlers->GetSize(); i++) { 1357d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) base::DictionaryValue* handler = NULL; 1362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (!media_galleries_handlers->GetDictionary(i, &handler)) { 1372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) *error = errors::kInvalidMediaGalleriesHandler; 1382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return false; 1392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 1402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (!LocalizeManifestValue(keys::kPageActionDefaultTitle, messages, 1412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) handler, error)) 1422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return false; 1432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 1442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 1452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 146c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) // Initialize all input_components 1477d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) base::ListValue* input_components = NULL; 148c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) if (manifest->GetList(keys::kInputComponents, &input_components)) { 149c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) for (size_t i = 0; i < input_components->GetSize(); ++i) { 1507d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) base::DictionaryValue* module = NULL; 151c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) if (!input_components->GetDictionary(i, &module)) { 152c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) *error = errors::kInvalidInputComponents; 153c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) return false; 154c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) } 155c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) if (!LocalizeManifestValue(keys::kName, messages, module, error)) 156c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) return false; 157c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) if (!LocalizeManifestValue(keys::kDescription, messages, module, error)) 158c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) return false; 159c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) } 160c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) } 161c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Initialize app.launch.local_path. 1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!LocalizeManifestValue(keys::kLaunchLocalPath, messages, manifest, error)) 1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 1655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Initialize app.launch.web_url. 1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!LocalizeManifestValue(keys::kLaunchWebURL, messages, manifest, error)) 1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Add current locale key to the manifest, so we can overwrite prefs 1715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // with new manifest when chrome locale changes. 1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) manifest->SetString(keys::kCurrentLocale, CurrentLocaleOrDefault()); 1735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return true; 1745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)bool LocalizeExtension(const base::FilePath& extension_path, 1777d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) base::DictionaryValue* manifest, 1785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::string* error) { 1795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(manifest); 1805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::string default_locale = GetDefaultLocaleFromManifest(*manifest, error); 1825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) scoped_ptr<extensions::MessageBundle> message_bundle( 1845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) extension_file_util::LoadMessageBundle( 1855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) extension_path, default_locale, error)); 1865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!message_bundle.get() && !error->empty()) 1885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 1895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (message_bundle.get() && 1915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) !LocalizeManifest(*message_bundle, manifest, error)) 1925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 1935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return true; 1955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool AddLocale(const std::set<std::string>& chrome_locales, 1982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) const base::FilePath& locale_folder, 1995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const std::string& locale_name, 2005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::set<std::string>* valid_locales, 2015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::string* error) { 2025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Accept name that starts with a . but don't add it to the list of supported 2035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // locales. 2045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (locale_name.find(".") == 0) 2055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return true; 2065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (chrome_locales.find(locale_name) == chrome_locales.end()) { 2075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Warn if there is an extension locale that's not in the Chrome list, 2085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // but don't fail. 2095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DLOG(WARNING) << base::StringPrintf("Supplied locale %s is not supported.", 2105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) locale_name.c_str()); 2115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return true; 2125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Check if messages file is actually present (but don't check content). 2147dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch if (base::PathExists( 2152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) locale_folder.Append(extensions::kMessagesFilename))) { 2165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) valid_locales->insert(locale_name); 2175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 2185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *error = base::StringPrintf("Catalog file is missing for locale %s.", 2195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) locale_name.c_str()); 2205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 2215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return true; 2245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)std::string CurrentLocaleOrDefault() { 2275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::string current_locale = l10n_util::NormalizeLocale(GetProcessLocale()); 2285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (current_locale.empty()) 2295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) current_locale = "en"; 2305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return current_locale; 2325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void GetAllLocales(std::set<std::string>* all_locales) { 2355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const std::vector<std::string>& available_locales = 2365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) l10n_util::GetAvailableLocales(); 2375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Add all parents of the current locale to the available locales set. 2385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // I.e. for sr_Cyrl_RS we add sr_Cyrl_RS, sr_Cyrl and sr. 2395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (size_t i = 0; i < available_locales.size(); ++i) { 2405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::vector<std::string> result; 2415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) l10n_util::GetParentLocales(available_locales[i], &result); 2425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) all_locales->insert(result.begin(), result.end()); 2435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void GetAllFallbackLocales(const std::string& application_locale, 2475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const std::string& default_locale, 2485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::vector<std::string>* all_fallback_locales) { 2495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(all_fallback_locales); 2505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!application_locale.empty() && application_locale != default_locale) 2515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) l10n_util::GetParentLocales(application_locale, all_fallback_locales); 2525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) all_fallback_locales->push_back(default_locale); 2535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)bool GetValidLocales(const base::FilePath& locale_path, 2565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::set<std::string>* valid_locales, 2575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::string* error) { 2585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::set<std::string> chrome_locales; 2595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) GetAllLocales(&chrome_locales); 2605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Enumerate all supplied locales in the extension. 262868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) base::FileEnumerator locales(locale_path, 263868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) false, 264868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) base::FileEnumerator::DIRECTORIES); 2652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) base::FilePath locale_folder; 2665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) while (!(locale_folder = locales.Next()).empty()) { 2675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::string locale_name = locale_folder.BaseName().MaybeAsASCII(); 2685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (locale_name.empty()) { 2695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) NOTREACHED(); 2705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) continue; // Not ASCII. 2715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!AddLocale(chrome_locales, 2735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) locale_folder, 2745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) locale_name, 2755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) valid_locales, 2765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) error)) { 2775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 2785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (valid_locales->empty()) { 2825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *error = extension_manifest_errors::kLocalesNoValidLocaleNamesListed; 2835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 2845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return true; 2875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Loads contents of the messages file for given locale. If file is not found, 2905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// or there was parsing error we return NULL and set |error|. 2915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Caller owns the returned object. 2927d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)static base::DictionaryValue* LoadMessageFile( 2937d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) const base::FilePath& locale_path, 2947d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) const std::string& locale, 2957d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) std::string* error) { 2965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::string extension_locale = locale; 2972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) base::FilePath file = locale_path.AppendASCII(extension_locale) 2982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) .Append(extensions::kMessagesFilename); 2995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) JSONFileValueSerializer messages_serializer(file); 3007d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) base::Value *dictionary = messages_serializer.Deserialize(NULL, error); 3015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!dictionary && error->empty()) { 3025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // JSONFileValueSerializer just returns NULL if file cannot be found. It 3035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // doesn't set the error, so we have to do it. 3045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *error = base::StringPrintf("Catalog file is missing for locale %s.", 3055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) extension_locale.c_str()); 3065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3087d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) return static_cast<base::DictionaryValue*>(dictionary); 3095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 3105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)extensions::MessageBundle* LoadMessageCatalogs( 3122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) const base::FilePath& locale_path, 3135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const std::string& default_locale, 3145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const std::string& application_locale, 3155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const std::set<std::string>& valid_locales, 3165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::string* error) { 3175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::vector<std::string> all_fallback_locales; 3185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) GetAllFallbackLocales(application_locale, default_locale, 3195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) &all_fallback_locales); 3205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3217d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) std::vector<linked_ptr<base::DictionaryValue> > catalogs; 3225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (size_t i = 0; i < all_fallback_locales.size(); ++i) { 3235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Skip all parent locales that are not supplied. 3245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (valid_locales.find(all_fallback_locales[i]) == valid_locales.end()) 3255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) continue; 3267d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) linked_ptr<base::DictionaryValue> catalog( 3275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) LoadMessageFile(locale_path, all_fallback_locales[i], error)); 3285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!catalog.get()) { 3295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // If locale is valid, but messages.json is corrupted or missing, return 3305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // an error. 3315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return NULL; 3325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 3335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) catalogs.push_back(catalog); 3345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return extensions::MessageBundle::Create(catalogs, error); 3385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 3395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)bool ShouldSkipValidation(const base::FilePath& locales_path, 3412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) const base::FilePath& locale_path, 3425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const std::set<std::string>& all_locales) { 3435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Since we use this string as a key in a DictionaryValue, be paranoid about 3445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // skipping any strings with '.'. This happens sometimes, for example with 3455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // '.svn' directories. 3462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) base::FilePath relative_path; 3475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!locales_path.AppendRelativePath(locale_path, &relative_path)) { 3485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) NOTREACHED(); 3495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return true; 3505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::string subdir = relative_path.MaybeAsASCII(); 3525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (subdir.empty()) 3535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return true; // Non-ASCII. 3545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (std::find(subdir.begin(), subdir.end(), '.') != subdir.end()) 3565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return true; 3575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (all_locales.find(subdir) == all_locales.end()) 3595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return true; 3605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 3625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 3635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)ScopedLocaleForTest::ScopedLocaleForTest() 3655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) : locale_(extension_l10n_util::CurrentLocaleOrDefault()) {} 3665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)ScopedLocaleForTest::ScopedLocaleForTest(const std::string& locale) 3685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) : locale_(extension_l10n_util::CurrentLocaleOrDefault()) { 3695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) extension_l10n_util::SetProcessLocale(locale); 3705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 3715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)ScopedLocaleForTest::~ScopedLocaleForTest() { 3735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) extension_l10n_util::SetProcessLocale(locale_); 3745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 3755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} // namespace extension_l10n_util 377