Bug 1336281 - Expose mozILocaleService. r?jfkthame
MozReview-Commit-ID: 3fTtad7tAg6
--- a/intl/build/nsI18nModule.cpp
+++ b/intl/build/nsI18nModule.cpp
@@ -39,16 +39,17 @@ NS_GENERIC_FACTORY_CONSTRUCTOR_INIT(nsSt
NS_GENERIC_FACTORY_CONSTRUCTOR(nsCaseConversionImp2)
NS_GENERIC_FACTORY_SINGLETON_CONSTRUCTOR(nsCategoryImp,
nsCategoryImp::GetInstance)
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);
NS_DEFINE_NAMED_CID(NS_UNICHARUTIL_CID);
NS_DEFINE_NAMED_CID(NS_UNICHARCATEGORY_CID);
NS_DEFINE_NAMED_CID(NS_ENTITYCONVERTER_CID);
NS_DEFINE_NAMED_CID(NS_SAVEASCHARSET_CID);
NS_DEFINE_NAMED_CID(NS_UNICODE_NORMALIZER_CID);
@@ -65,16 +66,17 @@ NS_DEFINE_NAMED_CID(NS_COLLATION_CID);
#ifdef USE_UNIX_LOCALE
NS_DEFINE_NAMED_CID(NS_COLLATION_CID);
#endif
#ifdef USE_MAC_LOCALE
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 },
{ &kNS_UNICHARUTIL_CID, false, nullptr, nsCaseConversionImp2Constructor },
{ &kNS_UNICHARCATEGORY_CID, false, nullptr, nsCategoryImpConstructor },
{ &kNS_ENTITYCONVERTER_CID, false, nullptr, nsEntityConverterConstructor },
{ &kNS_SAVEASCHARSET_CID, false, nullptr, nsSaveAsCharsetConstructor },
{ &kNS_UNICODE_NORMALIZER_CID, false, nullptr, nsUnicodeNormalizerConstructor },
@@ -93,16 +95,17 @@ static const mozilla::Module::CIDEntry k
#endif
#ifdef USE_MAC_LOCALE
{ &kNS_COLLATION_CID, false, nullptr, nsCollationMacUCConstructor },
#endif
{ nullptr }
};
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 },
{ NS_UNICHARUTIL_CONTRACTID, &kNS_UNICHARUTIL_CID },
{ NS_UNICHARCATEGORY_CONTRACTID, &kNS_UNICHARCATEGORY_CID },
{ NS_ENTITYCONVERTER_CONTRACTID, &kNS_ENTITYCONVERTER_CID },
{ NS_SAVEASCHARSET_CONTRACTID, &kNS_SAVEASCHARSET_CID },
{ NS_UNICODE_NORMALIZER_CONTRACTID, &kNS_UNICODE_NORMALIZER_CID },
--- a/intl/locale/LocaleService.cpp
+++ b/intl/locale/LocaleService.cpp
@@ -1,21 +1,27 @@
/* -*- 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 "jsapi.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)
@@ -30,19 +36,18 @@ ReadAppLocales(nsTArray<nsCString>& aRet
aRetVal.AppendElement(uaLangTag);
}
if (!uaLangTag.EqualsLiteral("en-US")) {
aRetVal.AppendElement(NS_LITERAL_CSTRING("en-US"));
}
}
-mozilla::StaticAutoPtr<LocaleService> LocaleService::sInstance;
-
-LocaleService* LocaleService::GetInstance()
+LocaleService*
+LocaleService::GetInstance()
{
if (!sInstance) {
sInstance = new LocaleService();
ClearOnShutdown(&sInstance);
}
return sInstance;
}
@@ -73,8 +78,41 @@ LocaleService::Refresh()
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(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<JS::Value> 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;
+}
--- a/intl/locale/LocaleService.h
+++ b/intl/locale/LocaleService.h
@@ -5,33 +5,53 @@
#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
+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"]
@@ -68,15 +88,17 @@ public:
* trigger a global event "intl:app-locales-changed".
*/
void Refresh();
protected:
nsTArray<nsCString> mAppLocales;
private:
- static StaticAutoPtr<LocaleService> sInstance;
+ virtual ~LocaleService() {};
+
+ static StaticRefPtr<LocaleService> sInstance;
};
} // intl
} // namespace mozilla
#endif /* mozilla_intl_LocaleService_h__ */
--- a/intl/locale/moz.build
+++ b/intl/locale/moz.build
@@ -11,16 +11,17 @@ toolkit = CONFIG['MOZ_WIDGET_TOOLKIT']
if toolkit == 'windows':
DIRS += ['windows']
elif toolkit == 'cocoa':
DIRS += ['mac']
else:
DIRS += ['unix']
XPIDL_SOURCES += [
+ 'mozILocaleService.idl',
'nsICollation.idl',
'nsILocale.idl',
'nsILocaleService.idl',
'nsIScriptableDateFormat.idl',
]
XPIDL_MODULE = 'locale'
new file mode 100644
--- /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();
+};
--- a/intl/locale/nsLocaleConstructors.h
+++ b/intl/locale/nsLocaleConstructors.h
@@ -8,16 +8,17 @@
#include "nsCollationCID.h"
#include "mozilla/ModuleUtils.h"
#include "nsILocaleService.h"
#include "nsIScriptableDateFormat.h"
#include "nsIServiceManager.h"
#include "nsLanguageAtomService.h"
#include "nsPlatformCharset.h"
+#include "LocaleService.h"
#if defined(XP_MACOSX)
#define USE_MAC_LOCALE
#endif
#if defined(XP_UNIX) && !defined(XP_MACOSX)
#define USE_UNIX_LOCALE
#endif
@@ -52,16 +53,23 @@ ctor_(nsISupports* aOuter, REFNSIID aIID
NSLOCALE_MAKE_CTOR(CreateLocaleService, nsILocaleService, NS_NewLocaleService)
NS_GENERIC_FACTORY_CONSTRUCTOR(nsCollationFactory)
//NS_GENERIC_FACTORY_CONSTRUCTOR(nsScriptableDateTimeFormat)
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
#ifdef USE_UNIX_LOCALE
NS_GENERIC_FACTORY_CONSTRUCTOR(nsCollationUnix)
#endif
new file mode 100644
--- /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");
+}
--- a/intl/locale/tests/unit/xpcshell.ini
+++ b/intl/locale/tests/unit/xpcshell.ini
@@ -16,8 +16,10 @@ skip-if = toolkit != "cocoa"
[test_bug1086527.js]
[test_intl_on_workers.js]
skip-if = toolkit == "android" # bug 1309447
[test_pluralForm.js]
[test_pluralForm_english.js]
[test_pluralForm_makeGetter.js]
+
+[test_localeService.js]