diff --git a/browser/installer/package-manifest.in b/browser/installer/package-manifest.in index ff7b432c9bb1..de2eb78e04be 100644 --- a/browser/installer/package-manifest.in +++ b/browser/installer/package-manifest.in @@ -550,6 +550,11 @@ @RESPATH@/components/PresentationDataChannelSessionTransport.js @RESPATH@/components/PresentationDataChannelSessionTransport.manifest +#ifdef ENABLE_INTL_API +@RESPATH@/components/mozIntl.manifest +@RESPATH@/components/mozIntl.js +#endif + #if defined(ENABLE_TESTS) && defined(MOZ_DEBUG) @RESPATH@/components/TestInterfaceJS.js @RESPATH@/components/TestInterfaceJS.manifest diff --git a/mobile/android/installer/package-manifest.in b/mobile/android/installer/package-manifest.in index 539f0e3a070f..16478f010057 100644 --- a/mobile/android/installer/package-manifest.in +++ b/mobile/android/installer/package-manifest.in @@ -398,6 +398,11 @@ @BINPATH@/components/TVSimulatorService.js @BINPATH@/components/TVSimulatorService.manifest +#ifdef ENABLE_INTL_API +@BINPATH@/components/mozIntl.manifest +@BINPATH@/components/mozIntl.js +#endif + ; Modules @BINPATH@/modules/* diff --git a/toolkit/components/mozintl/MozIntl.cpp b/toolkit/components/mozintl/MozIntlHelper.cpp similarity index 62% rename from toolkit/components/mozintl/MozIntl.cpp rename to toolkit/components/mozintl/MozIntlHelper.cpp index 04d25ec67194..d305f1581df1 100644 --- a/toolkit/components/mozintl/MozIntl.cpp +++ b/toolkit/components/mozintl/MozIntlHelper.cpp @@ -3,20 +3,20 @@ * 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 "MozIntl.h" +#include "MozIntlHelper.h" #include "jswrapper.h" #include "mozilla/ModuleUtils.h" -#define MOZ_MOZINTL_CID \ - { 0x83f8f991, 0x6b81, 0x4dd8, { 0xa0, 0x93, 0x72, 0x0b, 0xfb, 0x67, 0x4d, 0x38 } } +#define MOZ_MOZINTLHELPER_CID \ + { 0xb43c96be, 0x2b3a, 0x4dc4, { 0x90, 0xe9, 0xb0, 0x6d, 0x34, 0x21, 0x9b, 0x68 } } using namespace mozilla; -NS_IMPL_ISUPPORTS(MozIntl, mozIMozIntl) +NS_IMPL_ISUPPORTS(MozIntlHelper, mozIMozIntlHelper) -MozIntl::MozIntl() = default; +MozIntlHelper::MozIntlHelper() = default; -MozIntl::~MozIntl() = default; +MozIntlHelper::~MozIntlHelper() = default; static nsresult AddFunctions(JSContext* cx, JS::Handle val, const JSFunctionSpec* funcs) @@ -40,7 +40,7 @@ AddFunctions(JSContext* cx, JS::Handle val, const JSFunctionSpec* fun } NS_IMETHODIMP -MozIntl::AddGetCalendarInfo(JS::Handle val, JSContext* cx) +MozIntlHelper::AddGetCalendarInfo(JS::Handle val, JSContext* cx) { static const JSFunctionSpec funcs[] = { JS_SELF_HOSTED_FN("getCalendarInfo", "Intl_getCalendarInfo", 1, 0), @@ -51,7 +51,7 @@ MozIntl::AddGetCalendarInfo(JS::Handle val, JSContext* cx) } NS_IMETHODIMP -MozIntl::AddGetDisplayNames(JS::Handle val, JSContext* cx) +MozIntlHelper::AddGetDisplayNames(JS::Handle val, JSContext* cx) { static const JSFunctionSpec funcs[] = { JS_SELF_HOSTED_FN("getDisplayNames", "Intl_getDisplayNames", 2, 0), @@ -62,7 +62,7 @@ MozIntl::AddGetDisplayNames(JS::Handle val, JSContext* cx) } NS_IMETHODIMP -MozIntl::AddPluralRulesConstructor(JS::Handle val, JSContext* cx) +MozIntlHelper::AddPluralRulesConstructor(JS::Handle val, JSContext* cx) { if (!val.isObject()) { return NS_ERROR_INVALID_ARG; @@ -83,7 +83,7 @@ MozIntl::AddPluralRulesConstructor(JS::Handle val, JSContext* cx) } NS_IMETHODIMP -MozIntl::AddGetLocaleInfo(JS::Handle val, JSContext* cx) +MozIntlHelper::AddGetLocaleInfo(JS::Handle val, JSContext* cx) { static const JSFunctionSpec funcs[] = { JS_SELF_HOSTED_FN("getLocaleInfo", "Intl_getLocaleInfo", 1, 0), @@ -93,27 +93,27 @@ MozIntl::AddGetLocaleInfo(JS::Handle val, JSContext* cx) return AddFunctions(cx, val, funcs); } -NS_GENERIC_FACTORY_CONSTRUCTOR(MozIntl) -NS_DEFINE_NAMED_CID(MOZ_MOZINTL_CID); +NS_GENERIC_FACTORY_CONSTRUCTOR(MozIntlHelper) +NS_DEFINE_NAMED_CID(MOZ_MOZINTLHELPER_CID); -static const Module::CIDEntry kMozIntlCIDs[] = { - { &kMOZ_MOZINTL_CID, false, nullptr, MozIntlConstructor }, +static const Module::CIDEntry kMozIntlHelperCIDs[] = { + { &kMOZ_MOZINTLHELPER_CID, false, nullptr, MozIntlHelperConstructor }, { nullptr } }; -static const mozilla::Module::ContractIDEntry kMozIntlContracts[] = { - { "@mozilla.org/mozintl;1", &kMOZ_MOZINTL_CID }, +static const mozilla::Module::ContractIDEntry kMozIntlHelperContracts[] = { + { "@mozilla.org/mozintlhelper;1", &kMOZ_MOZINTLHELPER_CID }, { nullptr } }; -static const mozilla::Module kMozIntlModule = { +static const mozilla::Module kMozIntlHelperModule = { mozilla::Module::kVersion, - kMozIntlCIDs, - kMozIntlContracts, + kMozIntlHelperCIDs, + kMozIntlHelperContracts, nullptr, nullptr, nullptr, nullptr }; -NSMODULE_DEFN(mozMozIntlModule) = &kMozIntlModule; +NSMODULE_DEFN(mozMozIntlHelperModule) = &kMozIntlHelperModule; diff --git a/toolkit/components/mozintl/MozIntl.h b/toolkit/components/mozintl/MozIntlHelper.h similarity index 71% rename from toolkit/components/mozintl/MozIntl.h rename to toolkit/components/mozintl/MozIntlHelper.h index 00c10ed1915e..ec791ae6b127 100644 --- a/toolkit/components/mozintl/MozIntl.h +++ b/toolkit/components/mozintl/MozIntlHelper.h @@ -3,20 +3,20 @@ * 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 "mozIMozIntl.h" +#include "mozIMozIntlHelper.h" namespace mozilla { -class MozIntl final : public mozIMozIntl +class MozIntlHelper final : public mozIMozIntlHelper { public: NS_DECL_ISUPPORTS - NS_DECL_MOZIMOZINTL + NS_DECL_MOZIMOZINTLHELPER - MozIntl(); + MozIntlHelper(); private: - ~MozIntl(); + ~MozIntlHelper(); }; } // namespace mozilla diff --git a/toolkit/components/mozintl/moz.build b/toolkit/components/mozintl/moz.build index a92ed50b7144..f22fb3166bc6 100644 --- a/toolkit/components/mozintl/moz.build +++ b/toolkit/components/mozintl/moz.build @@ -8,12 +8,18 @@ XPCSHELL_TESTS_MANIFESTS += ['test/xpcshell.ini'] XPIDL_SOURCES += [ 'mozIMozIntl.idl', + 'mozIMozIntlHelper.idl', ] XPIDL_MODULE = 'mozintl' SOURCES += [ - 'MozIntl.cpp', + 'MozIntlHelper.cpp', +] + +EXTRA_COMPONENTS += [ + 'mozIntl.js', + 'mozIntl.manifest', ] FINAL_LIBRARY = 'xul' diff --git a/toolkit/components/mozintl/mozIMozIntl.idl b/toolkit/components/mozintl/mozIMozIntl.idl index 31cbb71eceb3..fcf9c2fd4cd9 100644 --- a/toolkit/components/mozintl/mozIMozIntl.idl +++ b/toolkit/components/mozintl/mozIMozIntl.idl @@ -5,17 +5,41 @@ #include "nsISupports.idl" -[scriptable, uuid(9f9bc42e-54f4-11e6-9aed-4b1429ac0ba0)] +/** + * This is a set of APIs that are of general usefulness for user interface + * internationalization. + * + * They're all in various stages of the standardization process through + * ECMA402, so they are exposed to privileged content only but are written + * in the way to allow for easy migration to standard Intl object once + * the appropriate stage of the ECMA402 is achieved. + * + * The exact structure of the code is a little bit complex because of that: + * + * 1) The core is in SpiderMonkey together with other Intl APIs + * + * This allows us to write the code once, stick to the spec language + * of the proposal, reuse our ICU bindings in Spidermonkey and use + * the code to inform us on refining the spec proposal for the given API itself. + * + * 2) The MozIntlHelper API exposes the SpiderMonkey APIs + * + * This helper API allows attaching the new APIs on any regular object. + * + * 3) The MozIntl API provides the access to those APIs + * + * This API exposes the actual functionality and wraps around the MozIntlHelper + * lazily retrieving and setting the accessors. + * On top of that, the API also binds additional functionality like using + * current application locale by default, and fetching OS regional preferences + * for date time format. + */ +[scriptable, uuid(7f63279a-1a29-4ae6-9e7a-dc9684a23530)] interface mozIMozIntl : nsISupports { - [implicit_jscontext] void addGetCalendarInfo(in jsval intlObject); - [implicit_jscontext] void addGetDisplayNames(in jsval intlObject); - [implicit_jscontext] void addGetLocaleInfo(in jsval intlObject); + jsval getCalendarInfo([optional] in jsval locales); + jsval getDisplayNames([optional] in jsval locales, [optional] in jsval options); + jsval getLocaleInfo([optional] in jsval locales); - /** - * Adds a PluralRules constructor to the given object. This function may only - * be called once within a realm/global object: calling it multiple times will - * throw. - */ - [implicit_jscontext] void addPluralRulesConstructor(in jsval intlObject); + jsval createPluralRules([optional] in jsval locales, [optional] in jsval options); }; diff --git a/toolkit/components/mozintl/mozIMozIntlHelper.idl b/toolkit/components/mozintl/mozIMozIntlHelper.idl new file mode 100644 index 000000000000..18f6efbb490b --- /dev/null +++ b/toolkit/components/mozintl/mozIMozIntlHelper.idl @@ -0,0 +1,29 @@ +/* -*- 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" + +/** + * This is an internal helper for mozIMozIntl API. There should be virtually + * no reason for you to call this API except from mozIMozIntl implementation. + * + * This API helps accessing the SpiderMonkey Intl APIs, but it is mozIMozIntl + * that exposes the thin wrapper around them that binds the functionality + * to Gecko. + */ +[scriptable, uuid(189eaa7d-b29a-43a9-b1fb-7658990df940)] +interface mozIMozIntlHelper : nsISupports +{ + [implicit_jscontext] void addGetCalendarInfo(in jsval intlObject); + [implicit_jscontext] void addGetDisplayNames(in jsval intlObject); + [implicit_jscontext] void addGetLocaleInfo(in jsval intlObject); + + /** + * Adds a PluralRules constructor to the given object. This function may only + * be called once within a realm/global object: calling it multiple times will + * throw. + */ + [implicit_jscontext] void addPluralRulesConstructor(in jsval intlObject); +}; diff --git a/toolkit/components/mozintl/mozIntl.js b/toolkit/components/mozintl/mozIntl.js new file mode 100644 index 000000000000..25c60ffedb4f --- /dev/null +++ b/toolkit/components/mozintl/mozIntl.js @@ -0,0 +1,69 @@ +/* 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/. */ + +Components.utils.import("resource://gre/modules/XPCOMUtils.jsm"); + +const Cc = Components.classes; +const Ci = Components.interfaces; + +const mozIntlHelper = + Cc["@mozilla.org/mozintlhelper;1"].getService(Ci.mozIMozIntlHelper); +const localeSvc = + Cc["@mozilla.org/intl/localeservice;1"].getService(Ci.mozILocaleService); + +/** + * This helper function retrives currently used app locales, allowing + * all mozIntl APIs to use the current app locales unless called with + * explicitly listed locales. + */ +function getLocales(locales) { + if (!locales) { + return localeSvc.getAppLocales(); + } + return locales; +} + +class MozIntl { + constructor() { + this._cache = {}; + } + + getCalendarInfo(locales, ...args) { + if (!this._cache.hasOwnProperty("getCalendarInfo")) { + mozIntlHelper.addGetCalendarInfo(this._cache); + } + + return this._cache.getCalendarInfo(getLocales(locales), ...args); + } + + getDisplayNames(locales, ...args) { + if (!this._cache.hasOwnProperty("getDisplayNames")) { + mozIntlHelper.addGetDisplayNames(this._cache); + } + + return this._cache.getDisplayNames(getLocales(locales), ...args); + } + + getLocaleInfo(locales, ...args) { + if (!this._cache.hasOwnProperty("getLocaleInfo")) { + mozIntlHelper.addGetLocaleInfo(this._cache); + } + + return this._cache.getLocaleInfo(getLocales(locales), ...args); + } + + createPluralRules(locales, ...args) { + if (!this._cache.hasOwnProperty("PluralRules")) { + mozIntlHelper.addPluralRulesConstructor(this._cache); + } + + return new this._cache.PluralRules(getLocales(locales), ...args); + } +} + +MozIntl.prototype.classID = Components.ID("{35ec195a-e8d0-4300-83af-c8a2cc84b4a3}"); +MozIntl.prototype.QueryInterface = XPCOMUtils.generateQI([Ci.mozIMozIntl, Ci.nsISupports]); + +var components = [MozIntl]; +this.NSGetFactory = XPCOMUtils.generateNSGetFactory(components); diff --git a/toolkit/components/mozintl/mozIntl.manifest b/toolkit/components/mozintl/mozIntl.manifest new file mode 100644 index 000000000000..9ac9fed76724 --- /dev/null +++ b/toolkit/components/mozintl/mozIntl.manifest @@ -0,0 +1,2 @@ +component {35ec195a-e8d0-4300-83af-c8a2cc84b4a3} mozIntl.js +contract @mozilla.org/mozintl;1 {35ec195a-e8d0-4300-83af-c8a2cc84b4a3} diff --git a/toolkit/components/mozintl/test/test_mozintl.js b/toolkit/components/mozintl/test/test_mozintl.js index 2f58a44078b2..2a9049598516 100644 --- a/toolkit/components/mozintl/test/test_mozintl.js +++ b/toolkit/components/mozintl/test/test_mozintl.js @@ -5,46 +5,23 @@ function run_test() { const mozIntl = Components.classes["@mozilla.org/mozintl;1"] .getService(Components.interfaces.mozIMozIntl); - test_this_global(mozIntl); - test_cross_global(mozIntl); test_methods_presence(mozIntl); + test_methods_calling(mozIntl); ok(true); } -function test_this_global(mozIntl) { - let x = {}; - - mozIntl.addGetCalendarInfo(x); - equal(x.getCalendarInfo instanceof Function, true); - equal(x.getCalendarInfo() instanceof Object, true); -} - -function test_cross_global(mozIntl) { - var global = new Components.utils.Sandbox("https://example.com/"); - var x = global.Object(); - - mozIntl.addGetCalendarInfo(x); - var waivedX = Components.utils.waiveXrays(x); - equal(waivedX.getCalendarInfo instanceof Function, false); - equal(waivedX.getCalendarInfo instanceof global.Function, true); - equal(waivedX.getCalendarInfo() instanceof Object, false); - equal(waivedX.getCalendarInfo() instanceof global.Object, true); -} - function test_methods_presence(mozIntl) { - equal(mozIntl.addGetCalendarInfo instanceof Function, true); - equal(mozIntl.addGetDisplayNames instanceof Function, true); - equal(mozIntl.addGetLocaleInfo instanceof Function, true); - - let x = {}; - - mozIntl.addGetCalendarInfo(x); - equal(x.getCalendarInfo instanceof Function, true); - - mozIntl.addGetDisplayNames(x); - equal(x.getDisplayNames instanceof Function, true); - - mozIntl.addGetLocaleInfo(x); - equal(x.getLocaleInfo instanceof Function, true); + equal(mozIntl.getCalendarInfo instanceof Function, true); + equal(mozIntl.getDisplayNames instanceof Function, true); + equal(mozIntl.getLocaleInfo instanceof Function, true); + equal(mozIntl.createPluralRules instanceof Function, true); +} + +function test_methods_calling(mozIntl) { + let ci = mozIntl.getCalendarInfo('pl'); + let dn = mozIntl.getDisplayNames('ar'); + let li = mozIntl.getLocaleInfo('de'); + let pr = mozIntl.createPluralRules('fr'); + ok(true); } diff --git a/toolkit/components/mozintl/test/test_mozintlhelper.js b/toolkit/components/mozintl/test/test_mozintlhelper.js new file mode 100644 index 000000000000..0fb36ca68368 --- /dev/null +++ b/toolkit/components/mozintl/test/test_mozintlhelper.js @@ -0,0 +1,50 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +function run_test() { + const miHelper = Components.classes["@mozilla.org/mozintlhelper;1"] + .getService(Components.interfaces.mozIMozIntlHelper); + + test_this_global(miHelper); + test_cross_global(miHelper); + test_methods_presence(miHelper); + + ok(true); +} + +function test_this_global(miHelper) { + let x = {}; + + miHelper.addGetCalendarInfo(x); + equal(x.getCalendarInfo instanceof Function, true); + equal(x.getCalendarInfo() instanceof Object, true); +} + +function test_cross_global(miHelper) { + var global = new Components.utils.Sandbox("https://example.com/"); + var x = global.Object(); + + miHelper.addGetCalendarInfo(x); + var waivedX = Components.utils.waiveXrays(x); + equal(waivedX.getCalendarInfo instanceof Function, false); + equal(waivedX.getCalendarInfo instanceof global.Function, true); + equal(waivedX.getCalendarInfo() instanceof Object, false); + equal(waivedX.getCalendarInfo() instanceof global.Object, true); +} + +function test_methods_presence(miHelper) { + equal(miHelper.addGetCalendarInfo instanceof Function, true); + equal(miHelper.addGetDisplayNames instanceof Function, true); + equal(miHelper.addGetLocaleInfo instanceof Function, true); + + let x = {}; + + miHelper.addGetCalendarInfo(x); + equal(x.getCalendarInfo instanceof Function, true); + + miHelper.addGetDisplayNames(x); + equal(x.getDisplayNames instanceof Function, true); + + miHelper.addGetLocaleInfo(x); + equal(x.getLocaleInfo instanceof Function, true); +} diff --git a/toolkit/components/mozintl/test/xpcshell.ini b/toolkit/components/mozintl/test/xpcshell.ini index 2b897c6296be..2a6f6e8a3283 100644 --- a/toolkit/components/mozintl/test/xpcshell.ini +++ b/toolkit/components/mozintl/test/xpcshell.ini @@ -2,3 +2,4 @@ head = [test_mozintl.js] +[test_mozintlhelper.js] diff --git a/toolkit/content/widgets/datetimepopup.xml b/toolkit/content/widgets/datetimepopup.xml index e19d02550e44..35bf117c96ed 100644 --- a/toolkit/content/widgets/datetimepopup.xml +++ b/toolkit/content/widgets/datetimepopup.xml @@ -23,11 +23,8 @@ "23.1em" "20.7em" @@ -226,7 +223,7 @@ displayNames.values[key]); ]]>