diff options
-rw-r--r-- | chrome/nsChromeRegistryChrome.cpp | 2 | ||||
-rw-r--r-- | dom/base/nsGlobalWindow.cpp | 12 | ||||
-rw-r--r-- | dom/base/nsGlobalWindow.h | 3 | ||||
-rw-r--r-- | dom/webidl/Window.webidl | 15 | ||||
-rw-r--r-- | intl/build/nsI18nModule.cpp | 3 | ||||
-rw-r--r-- | intl/locale/LocaleService.cpp | 105 | ||||
-rw-r--r-- | intl/locale/LocaleService.h | 88 | ||||
-rw-r--r-- | intl/locale/moz.build | 6 | ||||
-rw-r--r-- | intl/locale/mozILocaleService.idl | 48 | ||||
-rw-r--r-- | intl/locale/nsLocaleConstructors.h | 8 |
10 files changed, 290 insertions, 0 deletions
diff --git a/chrome/nsChromeRegistryChrome.cpp b/chrome/nsChromeRegistryChrome.cpp index 7678183fd3..2037e23d55 100644 --- a/chrome/nsChromeRegistryChrome.cpp +++ b/chrome/nsChromeRegistryChrome.cpp @@ -25,6 +25,7 @@ #include "mozilla/LookAndFeel.h" #include "mozilla/Unused.h" +#include "mozilla/intl/LocaleService.h" #include "nsICommandLine.h" #include "nsILocaleService.h" @@ -385,6 +386,7 @@ nsresult nsChromeRegistryChrome::UpdateSelectedLocale() NS_ASSERTION(obsSvc, "Couldn't get observer service."); obsSvc->NotifyObservers((nsIChromeRegistry*) this, "selected-locale-has-changed", nullptr); + mozilla::intl::LocaleService::GetInstance()->Refresh(); } } diff --git a/dom/base/nsGlobalWindow.cpp b/dom/base/nsGlobalWindow.cpp index c6b35a9bf0..be1c2463e5 100644 --- a/dom/base/nsGlobalWindow.cpp +++ b/dom/base/nsGlobalWindow.cpp @@ -49,6 +49,7 @@ #include "nsNetUtil.h" #include "nsVariant.h" #include "nsPrintfCString.h" +#include "mozilla/intl/LocaleService.h" // Helper Classes #include "nsJSUtils.h" @@ -14794,6 +14795,17 @@ nsGlobalWindow::CreateWorklet(ErrorResult& aRv) return worklet.forget(); } +void +nsGlobalWindow::GetAppLocales(nsTArray<nsString>& aLocales) +{ + nsTArray<nsCString> appLocales; + mozilla::intl::LocaleService::GetInstance()->GetAppLocales(appLocales); + + for (uint32_t i = 0; i < appLocales.Length(); i++) { + aLocales.AppendElement(NS_ConvertUTF8toUTF16(appLocales[i])); + } +} + template class nsPIDOMWindow<mozIDOMWindowProxy>; template class nsPIDOMWindow<mozIDOMWindow>; template class nsPIDOMWindow<nsISupports>; diff --git a/dom/base/nsGlobalWindow.h b/dom/base/nsGlobalWindow.h index e42835a0b2..43270e80d9 100644 --- a/dom/base/nsGlobalWindow.h +++ b/dom/base/nsGlobalWindow.h @@ -897,6 +897,9 @@ public: already_AddRefed<mozilla::dom::Worklet> CreateWorklet(mozilla::ErrorResult& aRv); + void + GetAppLocales(nsTArray<nsString>& aLocales); + protected: bool AlertOrConfirm(bool aAlert, const nsAString& aMessage, nsIPrincipal& aSubjectPrincipal, diff --git a/dom/webidl/Window.webidl b/dom/webidl/Window.webidl index 1b98042473..8a6b05a88e 100644 --- a/dom/webidl/Window.webidl +++ b/dom/webidl/Window.webidl @@ -486,3 +486,18 @@ callback IdleRequestCallback = void (IdleDeadline deadline); partial interface Window { [ChromeOnly] readonly attribute boolean isSecureContextIfOpenerIgnored; }; + +partial interface Window { +/** + * Returns a list of locales that the application should be localized to. + * + * The result is a sorted list of valid locale IDs and it should be + * used for all APIs that accept list of locales, like ECMA402 and L10n APIs. + * + * This API always returns at least one locale. + * + * Example: ["en-US", "de", "pl", "sr-Cyrl", "zh-Hans-HK"] + */ + [Func="IsChromeOrXBL"] + sequence<DOMString> getAppLocales(); +};
\ No newline at end of file diff --git a/intl/build/nsI18nModule.cpp b/intl/build/nsI18nModule.cpp index 9959d3d6fb..62ac7e47df 100644 --- a/intl/build/nsI18nModule.cpp +++ b/intl/build/nsI18nModule.cpp @@ -44,6 +44,7 @@ NS_GENERIC_FACTORY_CONSTRUCTOR(nsEntityConverter) NS_GENERIC_FACTORY_CONSTRUCTOR(nsSaveAsCharset) NS_GENERIC_FACTORY_CONSTRUCTOR(nsUnicodeNormalizer) +NS_DEFINE_NAMED_CID(MOZ_LOCALESERVICE_CID); NS_DEFINE_NAMED_CID(NS_LBRK_CID); NS_DEFINE_NAMED_CID(NS_WBRK_CID); NS_DEFINE_NAMED_CID(NS_SEMANTICUNITSCANNER_CID); @@ -73,6 +74,7 @@ NS_DEFINE_NAMED_CID(NS_DATETIMEFORMAT_CID); #endif static const mozilla::Module::CIDEntry kIntlCIDs[] = { + { &kMOZ_LOCALESERVICE_CID, false, nullptr, mozilla::intl::LocaleServiceConstructor }, { &kNS_LBRK_CID, false, nullptr, nsJISx4051LineBreakerConstructor }, { &kNS_WBRK_CID, false, nullptr, nsSampleWordBreakerConstructor }, { &kNS_SEMANTICUNITSCANNER_CID, false, nullptr, nsSemanticUnitScannerConstructor }, @@ -104,6 +106,7 @@ static const mozilla::Module::CIDEntry kIntlCIDs[] = { }; static const mozilla::Module::ContractIDEntry kIntlContracts[] = { + { MOZ_LOCALESERVICE_CONTRACTID, &kMOZ_LOCALESERVICE_CID }, { NS_LBRK_CONTRACTID, &kNS_LBRK_CID }, { NS_WBRK_CONTRACTID, &kNS_WBRK_CID }, { NS_SEMANTICUNITSCANNER_CONTRACTID, &kNS_SEMANTICUNITSCANNER_CID }, diff --git a/intl/locale/LocaleService.cpp b/intl/locale/LocaleService.cpp new file mode 100644 index 0000000000..7a84ae2449 --- /dev/null +++ b/intl/locale/LocaleService.cpp @@ -0,0 +1,105 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "LocaleService.h" + +#include "mozilla/ClearOnShutdown.h" +#include "mozilla/Services.h" +#include "nsIObserverService.h" +#include "nsIToolkitChromeRegistry.h" + +using namespace mozilla::intl; + +NS_IMPL_ISUPPORTS(LocaleService, mozILocaleService) + +mozilla::StaticRefPtr<LocaleService> LocaleService::sInstance; + +/** + * This function performs the actual language negotiation for the API. + * + * Currently it collects the locale ID used by nsChromeRegistry and + * adds hardcoded "en-US" locale as a fallback. + */ +static void +ReadAppLocales(nsTArray<nsCString>& aRetVal) +{ + nsAutoCString uaLangTag; + nsCOMPtr<nsIToolkitChromeRegistry> cr = + mozilla::services::GetToolkitChromeRegistryService(); + if (cr) { + cr->GetSelectedLocale(NS_LITERAL_CSTRING("global"), true, uaLangTag); + } + if (!uaLangTag.IsEmpty()) { + aRetVal.AppendElement(uaLangTag); + } + + if (!uaLangTag.EqualsLiteral("en-US")) { + aRetVal.AppendElement(NS_LITERAL_CSTRING("en-US")); + } +} + +LocaleService* +LocaleService::GetInstance() +{ + if (!sInstance) { + sInstance = new LocaleService(); + ClearOnShutdown(&sInstance); + } + return sInstance; +} + +void +LocaleService::GetAppLocales(nsTArray<nsCString>& aRetVal) +{ + if (mAppLocales.IsEmpty()) { + ReadAppLocales(mAppLocales); + } + aRetVal = mAppLocales; +} + +void +LocaleService::Refresh() +{ + nsTArray<nsCString> newLocales; + ReadAppLocales(newLocales); + + if (mAppLocales != newLocales) { + mAppLocales = Move(newLocales); + nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService(); + if (obs) { + obs->NotifyObservers(nullptr, "intl:app-locales-changed", nullptr); + } + } +} + +/** + * mozILocaleService methods + */ +NS_IMETHODIMP +LocaleService::GetAppLocales(uint32_t* aCount, char*** aOutArray) +{ + if (mAppLocales.IsEmpty()) { + ReadAppLocales(mAppLocales); + } + + *aCount = mAppLocales.Length(); + *aOutArray = static_cast<char**>(moz_xmalloc(*aCount * sizeof(char*))); + + for (uint32_t i = 0; i < *aCount; i++) { + (*aOutArray)[i] = moz_xstrdup(mAppLocales[i].get()); + } + + return NS_OK; +} + +NS_IMETHODIMP +LocaleService::GetAppLocale(nsACString& aRetVal) +{ + if (mAppLocales.IsEmpty()) { + ReadAppLocales(mAppLocales); + } + aRetVal = mAppLocales[0]; + return NS_OK; +}
\ No newline at end of file diff --git a/intl/locale/LocaleService.h b/intl/locale/LocaleService.h new file mode 100644 index 0000000000..e41e3c8d1e --- /dev/null +++ b/intl/locale/LocaleService.h @@ -0,0 +1,88 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode:nil; c-basic-offset: 2 -*- */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef mozilla_intl_LocaleService_h__ +#define mozilla_intl_LocaleService_h__ + +#include "mozilla/StaticPtr.h" +#include "nsString.h" +#include "nsTArray.h" + +#include "mozILocaleService.h" + +namespace mozilla { +namespace intl { + + +/** + * LocaleService is a manager of language negotiation in Gecko. + * + * It's intended to be the core place for collecting available and + * requested languages and negotiating them to produce a fallback + * chain of locales for the application. + */ +class LocaleService : public mozILocaleService +{ +public: + NS_DECL_ISUPPORTS + NS_DECL_MOZILOCALESERVICE + + /** + * Create (if necessary) and return a raw pointer to the singleton instance. + * Use this accessor in C++ code that just wants to call a method on the + * instance, but does not need to hold a reference, as in + * nsAutoCString str; + * LocaleService::GetInstance()->GetAppLocale(str); + */ + static LocaleService* GetInstance(); + + /** + * Return an addRef'd pointer to the singleton instance. This is used by the + * XPCOM constructor that exists to support usage from JS. + */ + static already_AddRefed<LocaleService> GetInstanceAddRefed() + { + return RefPtr<LocaleService>(GetInstance()).forget(); + } + + /** + * Returns a list of locales that the application should be localized to. + * + * The result is a sorted list of valid locale IDs and it should be + * used for all APIs that accept list of locales, like ECMA402 and L10n APIs. + * + * This API always returns at least one locale. + * + * Example: ["en-US", "de", "pl", "sr-Cyrl", "zh-Hans-HK"] + * + * Usage: + * nsTArray<nsCString> appLocales; + * LocaleService::GetInstance()->GetAppLocales(appLocales); + * + * (See mozILocaleService.idl for a JS-callable version of this.) + */ + void GetAppLocales(nsTArray<nsCString>& aRetVal); + + /** + * Triggers a refresh of the language negotiation process. + * + * If the result differs from the previous list, it will additionally + * trigger a global event "intl:app-locales-changed". + */ + void Refresh(); + +protected: + nsTArray<nsCString> mAppLocales; + +private: + virtual ~LocaleService() {}; + + static StaticRefPtr<LocaleService> sInstance; +}; + +} // intl +} // namespace mozilla + +#endif /* mozilla_intl_LocaleService_h__ */ diff --git a/intl/locale/moz.build b/intl/locale/moz.build index 94a30873ba..1f6d44253e 100644 --- a/intl/locale/moz.build +++ b/intl/locale/moz.build @@ -15,6 +15,7 @@ else: DIRS += ['unix'] XPIDL_SOURCES += [ + 'mozILocaleService.idl', 'nsICollation.idl', 'nsILocale.idl', 'nsILocaleService.idl', @@ -35,7 +36,12 @@ EXPORTS += [ 'nsWin32Locale.h', ] +EXPORTS.mozilla.intl += [ + 'LocaleService.h' +] + UNIFIED_SOURCES += [ + 'LocaleService.cpp', 'nsCollation.cpp', 'nsIDateTimeFormat.cpp', 'nsLanguageAtomService.cpp', diff --git a/intl/locale/mozILocaleService.idl b/intl/locale/mozILocaleService.idl new file mode 100644 index 0000000000..297ae7c063 --- /dev/null +++ b/intl/locale/mozILocaleService.idl @@ -0,0 +1,48 @@ +/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "nsISupports.idl" + +%{C++ +// Define Contractid and CID +#define MOZ_LOCALESERVICE_CID \ + { 0x92735ff4, 0x6384, 0x4ad6, { 0x85, 0x08, 0x75, 0x70, 0x10, 0xe1, 0x49, 0xee } } + +#define MOZ_LOCALESERVICE_CONTRACTID "@mozilla.org/intl/localeservice;1" +%} + +[scriptable, uuid(C27F8983-B48B-4D1A-92D7-FEB8106F212D)] +interface mozILocaleService : nsISupports +{ + /** + * Returns a list of locales that the application should be localized to. + * + * The result is a sorted list of valid locale IDs and it should be + * used for all APIs that accept list of locales, like ECMA402 and L10n APIs. + * + * This API always returns at least one locale. + * + * Example: ["en-US", "de", "pl", "sr-Cyrl", "zh-Hans-HK"] + * + * (See LocaleService.h for a more C++-friendly version of this.) + */ + void getAppLocales([optional] out unsigned long aCount, + [retval, array, size_is(aCount)] out string aLocales); + + /** + * Returns the best locale that the application should be localized to. + * + * The result is a valid locale ID and it should be + * used for all APIs that do not handle language negotiation. + * + * Where possible, getAppLocales() should be preferred over this API and + * all callsites should handle some form of "best effort" language + * negotiation to respect user preferences in case the use case does + * not have data for the first locale in the list. + * + * Example: "zh-Hans-HK" + */ + ACString getAppLocale(); +}; diff --git a/intl/locale/nsLocaleConstructors.h b/intl/locale/nsLocaleConstructors.h index 2d2e579740..8bf4ad6fe4 100644 --- a/intl/locale/nsLocaleConstructors.h +++ b/intl/locale/nsLocaleConstructors.h @@ -14,6 +14,7 @@ #include "nsIServiceManager.h" #include "nsLanguageAtomService.h" #include "nsPlatformCharset.h" +#include "LocaleService.h" #if defined(XP_MACOSX) #define USE_MAC_LOCALE @@ -61,6 +62,13 @@ NS_GENERIC_FACTORY_CONSTRUCTOR(nsCollationFactory) NS_GENERIC_FACTORY_CONSTRUCTOR(nsLanguageAtomService) NS_GENERIC_FACTORY_CONSTRUCTOR_INIT(nsPlatformCharset, Init) +namespace mozilla { +namespace intl { +NS_GENERIC_FACTORY_SINGLETON_CONSTRUCTOR(LocaleService, + LocaleService::GetInstanceAddRefed) +} +} + #ifdef XP_WIN NS_GENERIC_FACTORY_CONSTRUCTOR(nsCollationWin) NS_GENERIC_FACTORY_CONSTRUCTOR(nsDateTimeFormatWin) |