--- a/config/check_spidermonkey_style.py
+++ b/config/check_spidermonkey_style.py
@@ -83,16 +83,17 @@ included_inclnames_to_ignore = set([
'unicode/timezone.h', # ICU
'unicode/plurrule.h', # ICU
'unicode/ucal.h', # ICU
'unicode/uclean.h', # ICU
'unicode/ucol.h', # ICU
'unicode/udat.h', # ICU
'unicode/udatpg.h', # ICU
'unicode/uenum.h', # ICU
+ 'unicode/uloc.h', # ICU
'unicode/unorm2.h', # ICU
'unicode/unum.h', # ICU
'unicode/unumsys.h', # ICU
'unicode/upluralrules.h', # ICU
'unicode/ustring.h', # ICU
'unicode/utypes.h', # ICU
'vtune/VTuneWrapper.h' # VTune
])
--- a/js/src/builtin/Intl.cpp
+++ b/js/src/builtin/Intl.cpp
@@ -28,16 +28,17 @@
#include "ds/Sort.h"
#if ENABLE_INTL_API
#include "unicode/plurrule.h"
#include "unicode/ucal.h"
#include "unicode/ucol.h"
#include "unicode/udat.h"
#include "unicode/udatpg.h"
#include "unicode/uenum.h"
+#include "unicode/uloc.h"
#include "unicode/unum.h"
#include "unicode/unumsys.h"
#include "unicode/upluralrules.h"
#include "unicode/ustring.h"
#endif
#include "vm/DateTime.h"
#include "vm/GlobalObject.h"
#include "vm/Interpreter.h"
@@ -162,16 +163,22 @@ uloc_getAvailable(int32_t n)
}
int32_t
uloc_countAvailable()
{
MOZ_CRASH("uloc_countAvailable: Intl API disabled");
}
+UBool
+uloc_isRightToLeft(const char* locale)
+{
+ MOZ_CRASH("uloc_isRightToLeft: Intl API disabled");
+}
+
struct UFormattable;
void
ufmt_close(UFormattable* fmt)
{
MOZ_CRASH("ufmt_close: Intl API disabled");
}
@@ -4168,16 +4175,44 @@ js::intl_ComputeDisplayNames(JSContext*
return false;
}
// 6. Return result.
args.rval().setObject(*result);
return true;
}
+bool
+js::intl_GetLocaleInfo(JSContext* cx, unsigned argc, Value* vp)
+{
+ CallArgs args = CallArgsFromVp(argc, vp);
+ MOZ_ASSERT(args.length() == 1);
+
+ JSAutoByteString locale(cx, args[0].toString());
+ if (!locale)
+ return false;
+
+ RootedObject info(cx, NewBuiltinClassInstance<PlainObject>(cx));
+ if (!info)
+ return false;
+
+ if (!DefineProperty(cx, info, cx->names().locale, args[0]))
+ return false;
+
+ bool rtl = uloc_isRightToLeft(icuLocale(locale.ptr()));
+
+ RootedValue dir(cx, StringValue(rtl ? cx->names().rtl : cx->names().ltr));
+
+ if (!DefineProperty(cx, info, cx->names().direction, dir))
+ return false;
+
+ args.rval().setObject(*info);
+ return true;
+}
+
const Class js::IntlClass = {
js_Object_str,
JSCLASS_HAS_CACHED_PROTO(JSProto_Intl)
};
#if JS_HAS_TOSOURCE
static bool
intl_toSource(JSContext* cx, unsigned argc, Value* vp)
--- a/js/src/builtin/Intl.h
+++ b/js/src/builtin/Intl.h
@@ -505,16 +505,30 @@ intl_GetPluralCategories(JSContext* cx,
* 1 for bn-IN (note that "weekend" is *not* necessarily two days)
*
* NOTE: "calendar" and "locale" properties are *not* added to the object.
*/
extern MOZ_MUST_USE bool
intl_GetCalendarInfo(JSContext* cx, unsigned argc, Value* vp);
/**
+ * Returns a plain object with locale information for a single valid locale
+ * (callers must perform this validation). The object will have these
+ * properties:
+ *
+ * direction
+ * a string with a value "ltr" for left-to-right locale, and "rtl" for
+ * right-to-left locale.
+ * locale
+ * a BCP47 compilant locale string for the resolved locale.
+ */
+extern MOZ_MUST_USE bool
+intl_GetLocaleInfo(JSContext* cx, unsigned argc, Value* vp);
+
+/**
* Returns an Array with CLDR-based fields display names.
* The function takes three arguments:
*
* locale
* BCP47 compliant locale string
* style
* A string with values: long or short or narrow
* keys
--- a/js/src/builtin/Intl.js
+++ b/js/src/builtin/Intl.js
@@ -3332,8 +3332,27 @@ function Intl_getDisplayNames(locales, o
// 22. Perform ! DefinePropertyOrThrow(result, "style", style).
// 23. Perform ! DefinePropertyOrThrow(result, "values", values).
const result = { locale: r.locale, style, values };
// 24. Return result.
return result;
}
+function Intl_getLocaleInfo(locales) {
+ const requestedLocales = CanonicalizeLocaleList(locales);
+
+ // In the future, we may want to expose uloc_getAvailable and use it here.
+ const DateTimeFormat = dateTimeFormatInternalProperties;
+ const localeData = DateTimeFormat.localeData;
+
+ const localeOpt = new Record();
+ localeOpt.localeMatcher = "best fit";
+
+ const r = ResolveLocale(callFunction(DateTimeFormat.availableLocales, DateTimeFormat),
+ requestedLocales,
+ localeOpt,
+ DateTimeFormat.relevantExtensionKeys,
+ localeData);
+
+ return intl_GetLocaleInfo(r.locale);
+}
+
--- a/js/src/shell/js.cpp
+++ b/js/src/shell/js.cpp
@@ -934,16 +934,17 @@ AddIntlExtras(JSContext* cx, unsigned ar
if (!args.get(0).isObject()) {
JS_ReportErrorASCII(cx, "addIntlExtras must be passed an object");
return false;
}
JS::RootedObject intl(cx, &args[0].toObject());
static const JSFunctionSpec funcs[] = {
JS_SELF_HOSTED_FN("getCalendarInfo", "Intl_getCalendarInfo", 1, 0),
+ JS_SELF_HOSTED_FN("getLocaleInfo", "Intl_getLocaleInfo", 1, 0),
JS_SELF_HOSTED_FN("getDisplayNames", "Intl_getDisplayNames", 2, 0),
JS_FS_END
};
if (!JS_DefineFunctions(cx, intl, funcs))
return false;
if (!js::AddPluralRulesConstructor(cx, intl))
new file mode 100644
--- /dev/null
+++ b/js/src/tests/Intl/getLocaleInfo.js
@@ -0,0 +1,38 @@
+// |reftest| skip-if(!this.hasOwnProperty("Intl")||!this.hasOwnProperty("addIntlExtras"))
+/* 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/. */
+
+// Tests the getCalendarInfo function with a diverse set of arguments.
+
+function checkLocaleInfo(info, expected)
+{
+ assertEq(Object.getPrototypeOf(info), Object.prototype);
+
+ assertEq(info.direction, expected.direction);
+ assertEq(info.locale, expected.locale);
+}
+
+addIntlExtras(Intl);
+
+let gLI = Intl.getLocaleInfo;
+
+assertEq(gLI.length, 1);
+
+checkLocaleInfo(gLI('en-US'), {
+ direction: "ltr",
+ locale: "en-US"
+});
+
+checkLocaleInfo(gLI('fr'), {
+ direction: "ltr",
+ locale: "fr"
+});
+
+checkLocaleInfo(gLI('ar'), {
+ direction: "rtl",
+ locale: "ar"
+});
+
+if (typeof reportCompare === 'function')
+ reportCompare(0, 0);
--- a/js/src/vm/CommonPropertyNames.h
+++ b/js/src/vm/CommonPropertyNames.h
@@ -86,16 +86,17 @@
macro(DefaultBaseClassConstructor, DefaultBaseClassConstructor, "DefaultBaseClassConstructor") \
macro(DefaultDerivedClassConstructor, DefaultDerivedClassConstructor, "DefaultDerivedClassConstructor") \
macro(default, default_, "default") \
macro(defineGetter, defineGetter, "__defineGetter__") \
macro(defineProperty, defineProperty, "defineProperty") \
macro(defineSetter, defineSetter, "__defineSetter__") \
macro(delete, delete_, "delete") \
macro(deleteProperty, deleteProperty, "deleteProperty") \
+ macro(direction, direction, "direction") \
macro(displayURL, displayURL, "displayURL") \
macro(do, do_, "do") \
macro(done, done, "done") \
macro(dotGenerator, dotGenerator, ".generator") \
macro(dotThis, dotThis, ".this") \
macro(each, each, "each") \
macro(elementType, elementType, "elementType") \
macro(else, else_, "else") \
@@ -205,16 +206,17 @@
macro(let, let, "let") \
macro(line, line, "line") \
macro(lineNumber, lineNumber, "lineNumber") \
macro(literal, literal, "literal") \
macro(loc, loc, "loc") \
macro(locale, locale, "locale") \
macro(lookupGetter, lookupGetter, "__lookupGetter__") \
macro(lookupSetter, lookupSetter, "__lookupSetter__") \
+ macro(ltr, ltr, "ltr") \
macro(MapConstructorInit, MapConstructorInit, "MapConstructorInit") \
macro(MapIterator, MapIterator, "Map Iterator") \
macro(maximumFractionDigits, maximumFractionDigits, "maximumFractionDigits") \
macro(maximumSignificantDigits, maximumSignificantDigits, "maximumSignificantDigits") \
macro(message, message, "message") \
macro(minDays, minDays, "minDays") \
macro(minimumFractionDigits, minimumFractionDigits, "minimumFractionDigits") \
macro(minimumIntegerDigits, minimumIntegerDigits, "minimumIntegerDigits") \
@@ -293,16 +295,17 @@
macro(Reify, Reify, "Reify") \
macro(reject, reject, "reject") \
macro(rejected, rejected, "rejected") \
macro(RequireObjectCoercible, RequireObjectCoercible, "RequireObjectCoercible") \
macro(resolve, resolve, "resolve") \
macro(resumeGenerator, resumeGenerator, "resumeGenerator") \
macro(return, return_, "return") \
macro(revoke, revoke, "revoke") \
+ macro(rtl, rtl, "rtl") \
macro(script, script, "script") \
macro(scripts, scripts, "scripts") \
macro(second, second, "second") \
macro(selfHosted, selfHosted, "self-hosted") \
macro(sensitivity, sensitivity, "sensitivity") \
macro(set, set, "set") \
macro(SetConstructorInit, SetConstructorInit, "SetConstructorInit") \
macro(SetIterator, SetIterator, "Set Iterator") \
--- a/js/src/vm/SelfHosting.cpp
+++ b/js/src/vm/SelfHosting.cpp
@@ -2610,16 +2610,17 @@ static const JSFunctionSpec intrinsic_fu
JS_FN("intl_CompareStrings", intl_CompareStrings, 3,0),
JS_FN("intl_DateTimeFormat", intl_DateTimeFormat, 2,0),
JS_FN("intl_DateTimeFormat_availableLocales", intl_DateTimeFormat_availableLocales, 0,0),
JS_FN("intl_defaultTimeZone", intl_defaultTimeZone, 0,0),
JS_FN("intl_defaultTimeZoneOffset", intl_defaultTimeZoneOffset, 0,0),
JS_FN("intl_FormatDateTime", intl_FormatDateTime, 2,0),
JS_FN("intl_FormatNumber", intl_FormatNumber, 2,0),
JS_FN("intl_GetCalendarInfo", intl_GetCalendarInfo, 1,0),
+ JS_FN("intl_GetLocaleInfo", intl_GetLocaleInfo, 1,0),
JS_FN("intl_ComputeDisplayNames", intl_ComputeDisplayNames, 3,0),
JS_FN("intl_IsValidTimeZoneName", intl_IsValidTimeZoneName, 1,0),
JS_FN("intl_NumberFormat", intl_NumberFormat, 2,0),
JS_FN("intl_NumberFormat_availableLocales", intl_NumberFormat_availableLocales, 0,0),
JS_FN("intl_numberingSystem", intl_numberingSystem, 1,0),
JS_FN("intl_patternForSkeleton", intl_patternForSkeleton, 2,0),
JS_FN("intl_PluralRules_availableLocales", intl_PluralRules_availableLocales, 0,0),
JS_FN("intl_GetPluralCategories", intl_GetPluralCategories, 2, 0),
--- a/toolkit/components/mozintl/MozIntl.cpp
+++ b/toolkit/components/mozintl/MozIntl.cpp
@@ -77,16 +77,27 @@ MozIntl::AddPluralRulesConstructor(JS::H
if (!js::AddPluralRulesConstructor(cx, realIntlObj)) {
return NS_ERROR_FAILURE;
}
return NS_OK;
}
+NS_IMETHODIMP
+MozIntl::AddGetLocaleInfo(JS::Handle<JS::Value> val, JSContext* cx)
+{
+ static const JSFunctionSpec funcs[] = {
+ JS_SELF_HOSTED_FN("getLocaleInfo", "Intl_getLocaleInfo", 1, 0),
+ JS_FS_END
+ };
+
+ return AddFunctions(cx, val, funcs);
+}
+
NS_GENERIC_FACTORY_CONSTRUCTOR(MozIntl)
NS_DEFINE_NAMED_CID(MOZ_MOZINTL_CID);
static const Module::CIDEntry kMozIntlCIDs[] = {
{ &kMOZ_MOZINTL_CID, false, nullptr, MozIntlConstructor },
{ nullptr }
};
--- a/toolkit/components/mozintl/mozIMozIntl.idl
+++ b/toolkit/components/mozintl/mozIMozIntl.idl
@@ -5,16 +5,17 @@
#include "nsISupports.idl"
[scriptable, uuid(9f9bc42e-54f4-11e6-9aed-4b1429ac0ba0)]
interface mozIMozIntl : 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);
};
--- a/toolkit/components/mozintl/test/test_mozintl.js
+++ b/toolkit/components/mozintl/test/test_mozintl.js
@@ -30,17 +30,21 @@ function test_cross_global(mozIntl) {
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);
}