diff --git a/intl/build/nsI18nModule.cpp b/intl/build/nsI18nModule.cpp index 7512763917bd..ac9ec84bc1a7 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); @@ -70,6 +71,7 @@ NS_DEFINE_NAMED_CID(NS_COLLATION_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 }, @@ -98,6 +100,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 index 430ff954cd78..36f3c261e6a0 100644 --- a/intl/locale/LocaleService.cpp +++ b/intl/locale/LocaleService.cpp @@ -4,6 +4,8 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #include "LocaleService.h" + +#include "jsapi.h" #include "mozilla/ClearOnShutdown.h" #include "mozilla/Services.h" #include "nsIObserverService.h" @@ -11,6 +13,10 @@ using namespace mozilla::intl; +NS_IMPL_ISUPPORTS(LocaleService, mozILocaleService) + +mozilla::StaticRefPtr LocaleService::sInstance; + /** * This function performs the actual language negotiation for the API. * @@ -35,9 +41,8 @@ ReadAppLocales(nsTArray& aRetVal) } } -mozilla::StaticAutoPtr LocaleService::sInstance; - -LocaleService* LocaleService::GetInstance() +LocaleService* +LocaleService::GetInstance() { if (!sInstance) { sInstance = new LocaleService(); @@ -78,3 +83,36 @@ LocaleService::Refresh() } } } + +/** + * mozILocaleService methods + */ +NS_IMETHODIMP +LocaleService::GetAppLocales(JSContext* aCtx, JS::MutableHandleValue aRetVal) +{ + if (mAppLocales.IsEmpty()) { + ReadAppLocales(mAppLocales); + } + + uint32_t appLocalesNum = mAppLocales.Length(); + + JS::RootedObject locales(aCtx, JS_NewArrayObject(aCtx, appLocalesNum)); + JS::Rooted value(aCtx); + + for (size_t i = 0; i < appLocalesNum; i++) { + const nsCString& loc = mAppLocales[i]; + JSString* str = JS_NewStringCopyN(aCtx, loc.get(), loc.Length()); + value.setString(str); + JS_DefineElement(aCtx, locales, i, value, JSPROP_ENUMERATE); + } + + aRetVal.setObject(*locales); + return NS_OK; +} + +NS_IMETHODIMP +LocaleService::GetAppLocale(JSContext* aCtx, nsACString& aRetVal) +{ + GetAppLocale(aRetVal); + return NS_OK; +} diff --git a/intl/locale/LocaleService.h b/intl/locale/LocaleService.h index e5228418c41a..2de7673ed4e5 100644 --- a/intl/locale/LocaleService.h +++ b/intl/locale/LocaleService.h @@ -10,10 +10,11 @@ #include "nsString.h" #include "nsTArray.h" +#include "mozILocaleService.h" + namespace mozilla { namespace intl { - /** * LocaleService is a manager of language negotiation in Gecko. * @@ -21,11 +22,30 @@ namespace intl { * requested languages and negotiating them to produce a fallback * chain of locales for the application. */ -class LocaleService +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 GetInstanceAddRefed() + { + return RefPtr(GetInstance()).forget(); + } + /** * Returns a list of locales that the application should be localized to. * @@ -73,7 +93,9 @@ protected: nsTArray mAppLocales; private: - static StaticAutoPtr sInstance; + virtual ~LocaleService() {}; + + static StaticRefPtr sInstance; }; } // intl diff --git a/intl/locale/moz.build b/intl/locale/moz.build index 3d72bdd98b2b..9a03810c1f4b 100644 --- a/intl/locale/moz.build +++ b/intl/locale/moz.build @@ -19,6 +19,7 @@ else: DIRS += ['unix'] XPIDL_SOURCES += [ + 'mozILocaleService.idl', 'nsICollation.idl', 'nsILocale.idl', 'nsILocaleService.idl', diff --git a/intl/locale/mozILocaleService.idl b/intl/locale/mozILocaleService.idl new file mode 100644 index 000000000000..9e517bcb7053 --- /dev/null +++ b/intl/locale/mozILocaleService.idl @@ -0,0 +1,21 @@ +/* -*- 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 +{ + [implicit_jscontext] jsval getAppLocales(); + [implicit_jscontext] ACString getAppLocale(); +}; diff --git a/intl/locale/nsLocaleConstructors.h b/intl/locale/nsLocaleConstructors.h index a4443ab10db7..ce9d3b0a533d 100644 --- a/intl/locale/nsLocaleConstructors.h +++ b/intl/locale/nsLocaleConstructors.h @@ -13,6 +13,7 @@ #include "nsIServiceManager.h" #include "nsLanguageAtomService.h" #include "nsPlatformCharset.h" +#include "LocaleService.h" #if defined(XP_MACOSX) #define USE_MAC_LOCALE @@ -57,6 +58,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) #endif diff --git a/intl/locale/tests/unit/test_localeService.js b/intl/locale/tests/unit/test_localeService.js new file mode 100644 index 000000000000..4cd9c1742fad --- /dev/null +++ b/intl/locale/tests/unit/test_localeService.js @@ -0,0 +1,27 @@ +/* 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/. */ + +/** + * Make sure the locale service can be instantiated, + * and returns something plausible for getAppLocale and getAppLocales. + */ + +function run_test() +{ + var localeService = + Components.classes["@mozilla.org/intl/localeservice;1"] + .getService(Components.interfaces.mozILocaleService); + + var appLocale = localeService.getAppLocale(); + do_check_true(appLocale != "", "appLocale is non-empty"); + + var appLocales = localeService.getAppLocales(); + do_check_true(Array.isArray(appLocales), "appLocales returns an array"); + + do_check_true(appLocale == appLocales[0], "appLocale matches first entry in appLocales"); + + var enUScount = 0; + appLocales.forEach(function(loc) { if (loc == "en-US") { enUScount++; } }); + do_check_true(enUScount == 1, "en-US is present exactly one time"); +} diff --git a/intl/locale/tests/unit/xpcshell.ini b/intl/locale/tests/unit/xpcshell.ini index e8af701b9a0e..ade64253e511 100644 --- a/intl/locale/tests/unit/xpcshell.ini +++ b/intl/locale/tests/unit/xpcshell.ini @@ -21,3 +21,5 @@ skip-if = toolkit == "android" # bug 1309447 [test_pluralForm.js] [test_pluralForm_english.js] [test_pluralForm_makeGetter.js] + +[test_localeService.js]