--- a/js/src/builtin/Intl.cpp
+++ b/js/src/builtin/Intl.cpp
@@ -7,16 +7,17 @@
/*
* The Intl module specified by standard ECMA-402,
* ECMAScript Internationalization API Specification.
*/
#include "builtin/Intl.h"
#include "mozilla/Casting.h"
+#include "mozilla/Maybe.h"
#include "mozilla/PodOperations.h"
#include "mozilla/Range.h"
#include <string.h>
#include "jsapi.h"
#include "jsatom.h"
#include "jscntxt.h"
@@ -643,16 +644,17 @@ enum UDateFormatField {
};
enum UDateFormatStyle {
UDAT_FULL,
UDAT_LONG,
UDAT_MEDIUM,
UDAT_SHORT,
UDAT_DEFAULT = UDAT_MEDIUM,
+ UDAT_NONE = -1,
UDAT_PATTERN = -2,
UDAT_IGNORE = UDAT_PATTERN
};
enum UDateFormatSymbolType {
UDAT_ERAS,
UDAT_MONTHS,
UDAT_SHORT_MONTHS,
@@ -812,24 +814,28 @@ IntlInitialize(JSContext* cx, HandleObje
MOZ_ASSERT(ignored.isUndefined(),
"Unexpected return value from non-legacy Intl object initializer");
return true;
}
static bool
LegacyIntlInitialize(JSContext* cx, HandleObject obj, Handle<PropertyName*> initializer,
HandleValue thisValue, HandleValue locales, HandleValue options,
- MutableHandleValue result)
+ mozilla::Maybe<bool> mozExtensions, MutableHandleValue result)
{
- FixedInvokeArgs<4> args(cx);
+ InvokeArgs args(cx);
+ if (!args.init(cx, mozExtensions ? 5 : 4))
+ return false;
args[0].setObject(*obj);
args[1].set(thisValue);
args[2].set(locales);
args[3].set(options);
+ if (mozExtensions)
+ args[4].setBoolean(mozExtensions.value());
RootedValue thisv(cx, NullValue());
if (!js::CallSelfHostedFunction(cx, initializer, thisv, args, result))
return false;
MOZ_ASSERT(result.isObject(), "Legacy Intl object initializer must return an object");
return true;
}
@@ -1448,17 +1454,17 @@ NumberFormat(JSContext* cx, const CallAr
numberFormat->setReservedSlot(NumberFormatObject::UNUMBER_FORMAT_SLOT, PrivateValue(nullptr));
RootedValue thisValue(cx, construct ? ObjectValue(*numberFormat) : args.thisv());
RootedValue locales(cx, args.get(0));
RootedValue options(cx, args.get(1));
// Step 3.
return LegacyIntlInitialize(cx, numberFormat, cx->names().InitializeNumberFormat, thisValue,
- locales, options, args.rval());
+ locales, options, mozilla::Nothing(), args.rval());
}
static bool
NumberFormat(JSContext* cx, unsigned argc, Value* vp)
{
CallArgs args = CallArgsFromVp(argc, vp);
return NumberFormat(cx, args, args.isConstructing());
}
@@ -2357,17 +2363,17 @@ static const JSPropertySpec dateTimeForm
};
/**
* 12.2.1 Intl.DateTimeFormat([ locales [, options]])
*
* ES2017 Intl draft rev 94045d234762ad107a3d09bb6f7381a65f1a2f9b
*/
static bool
-DateTimeFormat(JSContext* cx, const CallArgs& args, bool construct)
+DateTimeFormat(JSContext* cx, const CallArgs& args, bool construct, bool mozExtensions = false)
{
// Step 1 (Handled by OrdinaryCreateFromConstructor fallback code).
// Step 2 (Inlined 9.1.14, OrdinaryCreateFromConstructor).
RootedObject proto(cx);
if (args.isConstructing() && !GetPrototypeFromCallableConstructor(cx, args, &proto))
return false;
@@ -2387,26 +2393,41 @@ DateTimeFormat(JSContext* cx, const Call
PrivateValue(nullptr));
RootedValue thisValue(cx, construct ? ObjectValue(*dateTimeFormat) : args.thisv());
RootedValue locales(cx, args.get(0));
RootedValue options(cx, args.get(1));
// Step 3.
return LegacyIntlInitialize(cx, dateTimeFormat, cx->names().InitializeDateTimeFormat,
- thisValue, locales, options, args.rval());
+ thisValue, locales, options, mozilla::Some(mozExtensions),
+ args.rval());
}
static bool
DateTimeFormat(JSContext* cx, unsigned argc, Value* vp)
{
CallArgs args = CallArgsFromVp(argc, vp);
return DateTimeFormat(cx, args, args.isConstructing());
}
+static bool
+MozDateTimeFormat(JSContext* cx, unsigned argc, Value* vp)
+{
+ CallArgs args = CallArgsFromVp(argc, vp);
+
+ // Don't allow to call mozIntl.DateTimeFormat as a function. That way we
+ // don't need to worry how to handle the legacy initialization semantics
+ // when applied on mozIntl.DateTimeFormat.
+ if (!ThrowIfNotConstructing(cx, args, "mozIntl.DateTimeFormat"))
+ return false;
+
+ return DateTimeFormat(cx, args, true, true);
+}
+
bool
js::intl_DateTimeFormat(JSContext* cx, unsigned argc, Value* vp)
{
CallArgs args = CallArgsFromVp(argc, vp);
MOZ_ASSERT(args.length() == 2);
MOZ_ASSERT(!args.isConstructing());
// intl_DateTimeFormat is an intrinsic for self-hosted JavaScript, so it
// cannot be used with "new", but it still has to be treated as a
@@ -2422,20 +2443,22 @@ DateTimeFormatObject::finalize(FreeOp* f
const Value& slot =
obj->as<DateTimeFormatObject>().getReservedSlot(DateTimeFormatObject::UDATE_FORMAT_SLOT);
if (UDateFormat* df = static_cast<UDateFormat*>(slot.toPrivate()))
udat_close(df);
}
static JSObject*
CreateDateTimeFormatPrototype(JSContext* cx, HandleObject Intl, Handle<GlobalObject*> global,
- MutableHandleObject constructor)
+ MutableHandleObject constructor, bool mozExtensions = false)
{
RootedFunction ctor(cx);
- ctor = GlobalObject::createConstructor(cx, &DateTimeFormat, cx->names().DateTimeFormat, 0);
+ ctor = mozExtensions
+ ? GlobalObject::createConstructor(cx, &MozDateTimeFormat, cx->names().DateTimeFormat, 0)
+ : GlobalObject::createConstructor(cx, &DateTimeFormat, cx->names().DateTimeFormat, 0);
if (!ctor)
return nullptr;
RootedObject proto(cx, GlobalObject::createBlankPrototype<PlainObject>(cx, global));
if (!proto)
return nullptr;
if (!LinkConstructorAndPrototype(cx, ctor, proto))
@@ -2458,16 +2481,28 @@ CreateDateTimeFormatPrototype(JSContext*
if (!DefineProperty(cx, Intl, cx->names().DateTimeFormat, ctorValue, nullptr, nullptr, 0))
return nullptr;
constructor.set(ctor);
return proto;
}
bool
+js::AddDateTimeFormatConstructor(JSContext* cx, JS::Handle<JSObject*> intl)
+{
+ Handle<GlobalObject*> global = cx->global();
+
+ RootedObject dummy(cx);
+ if (!CreateDateTimeFormatPrototype(cx, intl, global, &dummy, true))
+ return false;
+
+ return true;
+}
+
+bool
js::intl_DateTimeFormat_availableLocales(JSContext* cx, unsigned argc, Value* vp)
{
CallArgs args = CallArgsFromVp(argc, vp);
MOZ_ASSERT(args.length() == 0);
RootedValue result(cx);
if (!intl_availableLocales(cx, udat_countAvailable, udat_getAvailable, &result))
return false;
@@ -3028,16 +3063,100 @@ js::intl_patternForSkeleton(JSContext* c
MOZ_ASSERT(size >= 0);
JSString* str = NewStringCopyN<CanGC>(cx, chars.begin(), size);
if (!str)
return false;
args.rval().setString(str);
return true;
}
+bool
+js::intl_patternForStyle(JSContext* cx, unsigned argc, Value* vp)
+{
+ CallArgs args = CallArgsFromVp(argc, vp);
+ MOZ_ASSERT(args.length() == 3);
+ MOZ_ASSERT(args[0].isString());
+
+ JSAutoByteString locale(cx, args[0].toString());
+ if (!locale)
+ return false;
+
+ UDateFormatStyle dateStyle = UDAT_NONE;
+ UDateFormatStyle timeStyle = UDAT_NONE;
+
+ if (args[1].isString()) {
+ JSLinearString* dateStyleStr = args[1].toString()->ensureLinear(cx);
+
+ if (StringEqualsAscii(dateStyleStr, "full")) {
+ dateStyle = UDAT_FULL;
+ } else if (StringEqualsAscii(dateStyleStr, "long")) {
+ dateStyle = UDAT_LONG;
+ } else if (StringEqualsAscii(dateStyleStr, "medium")) {
+ dateStyle = UDAT_MEDIUM;
+ } else if (StringEqualsAscii(dateStyleStr, "short")) {
+ dateStyle = UDAT_SHORT;
+ }
+ }
+
+ if (args[2].isString()) {
+ JSLinearString* timeStyleStr = args[2].toString()->ensureLinear(cx);
+
+ if (StringEqualsAscii(timeStyleStr, "full")) {
+ timeStyle = UDAT_FULL;
+ } else if (StringEqualsAscii(timeStyleStr, "long")) {
+ timeStyle = UDAT_LONG;
+ } else if (StringEqualsAscii(timeStyleStr, "medium")) {
+ timeStyle = UDAT_MEDIUM;
+ } else if (StringEqualsAscii(timeStyleStr, "short")) {
+ timeStyle = UDAT_SHORT;
+ }
+ }
+
+ UErrorCode status = U_ZERO_ERROR;
+ UDateFormat* df = udat_open(
+ timeStyle,
+ dateStyle,
+ icuLocale(locale.ptr()),
+ nullptr,
+ -1,
+ nullptr,
+ -1,
+ &status);
+ if (U_FAILURE(status)) {
+ JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_INTERNAL_INTL_ERROR);
+ return false;
+ }
+ ScopedICUObject<UDateFormat, udat_close> toClose(df);
+
+ Vector<char16_t, INITIAL_CHAR_BUFFER_SIZE> chars(cx);
+ if (!chars.resize(INITIAL_CHAR_BUFFER_SIZE))
+ return false;
+
+ int32_t size = udat_toPattern(df, false, Char16ToUChar(chars.begin()), INITIAL_CHAR_BUFFER_SIZE, &status);
+
+ if (status == U_BUFFER_OVERFLOW_ERROR) {
+ MOZ_ASSERT(size >= 0);
+ if (!chars.resize(size))
+ return false;
+ status = U_ZERO_ERROR;
+ udat_toPattern(df, false, Char16ToUChar(chars.begin()), size, &status);
+ }
+ if (U_FAILURE(status)) {
+ JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_INTERNAL_INTL_ERROR);
+ return false;
+ }
+
+ MOZ_ASSERT(size >= 0);
+ JSString* str = NewStringCopyN<CanGC>(cx, chars.begin(), size);
+ if (!str)
+ return false;
+ args.rval().setString(str);
+ return true;
+}
+
/**
* Returns a new UDateFormat with the locale and date-time formatting options
* of the given DateTimeFormat.
*/
static UDateFormat*
NewUDateFormat(JSContext* cx, Handle<DateTimeFormatObject*> dateTimeFormat)
{
RootedValue value(cx);
--- a/js/src/builtin/Intl.h
+++ b/js/src/builtin/Intl.h
@@ -407,16 +407,26 @@ intl_defaultTimeZoneOffset(JSContext* cx
* given locale.
*
* Usage: pattern = intl_patternForSkeleton(locale, skeleton)
*/
extern MOZ_MUST_USE bool
intl_patternForSkeleton(JSContext* cx, unsigned argc, Value* vp);
/**
+ * Return a pattern in the date-time format pattern language of Unicode
+ * Technical Standard 35, Unicode Locale Data Markup Language, for the
+ * best-fit date-time style for the given locale.
+ *
+ * Usage: pattern = intl_patternForStyle(locale, dateStyle, timeStyle)
+ */
+extern MOZ_MUST_USE bool
+intl_patternForStyle(JSContext* cx, unsigned argc, Value* vp);
+
+/**
* Returns a String value representing x (which must be a Number value)
* according to the effective locale and the formatting options of the
* given DateTimeFormat.
*
* Spec: ECMAScript Internationalization API Specification, 12.3.2.
*
* Usage: formatted = intl_FormatDateTime(dateTimeFormat, x, formatToParts)
*/
--- a/js/src/builtin/Intl.js
+++ b/js/src/builtin/Intl.js
@@ -2227,17 +2227,35 @@ function resolveDateTimeFormatInternals(
// Steps 15-17.
internalProps.timeZone = lazyDateTimeFormatData.timeZone;
// Step 18.
var formatOpt = lazyDateTimeFormatData.formatOpt;
// Steps 27-28, more or less - see comment after this function.
- var pattern = toBestICUPattern(dataLocale, formatOpt);
+ var pattern;
+
+ if (lazyDateTimeFormatData.mozExtensions) {
+ var pattern;
+ if (lazyDateTimeFormatData.patternOption) {
+ pattern = lazyDateTimeFormatData.patternOption;
+ } else if (lazyDateTimeFormatData.dateStyle || lazyDateTimeFormatData.timeStyle) {
+ pattern = intl_patternForStyle(dataLocale,
+ lazyDateTimeFormatData.dateStyle, lazyDateTimeFormatData.timeStyle);
+
+ internalProps.dateStyle = lazyDateTimeFormatData.dateStyle;
+ internalProps.timeStyle = lazyDateTimeFormatData.timeStyle;
+ } else {
+ pattern = toBestICUPattern(dataLocale, formatOpt);
+ }
+ internalProps.mozExtensions = true;
+ } else {
+ pattern = toBestICUPattern(dataLocale, formatOpt);
+ }
// Step 29.
internalProps.pattern = pattern;
// Step 30.
internalProps.boundFormat = undefined;
// The caller is responsible for associating |internalProps| with the right
@@ -2296,17 +2314,17 @@ function UnwrapDateTimeFormat(dtf, metho
* This method is complicated a moderate bit by its implementing initialization
* as a *lazy* concept. Everything that must happen now, does -- but we defer
* all the work we can until the object is actually used as a DateTimeFormat.
* This later work occurs in |resolveDateTimeFormatInternals|; steps not noted
* here occur there.
*
* Spec: ECMAScript Internationalization API Specification, 12.1.1.
*/
-function InitializeDateTimeFormat(dateTimeFormat, thisValue, locales, options) {
+function InitializeDateTimeFormat(dateTimeFormat, thisValue, locales, options, mozExtensions) {
assert(IsObject(dateTimeFormat), "InitializeDateTimeFormat called with non-Object");
assert(IsDateTimeFormat(dateTimeFormat),
"InitializeDateTimeFormat called with non-DateTimeFormat");
// Steps 1-2 (These steps are no longer required and should be removed
// from the spec; https://github.com/tc39/ecma402/issues/115).
// Lazy DateTimeFormat data has the following structure:
@@ -2373,16 +2391,28 @@ function InitializeDateTimeFormat(dateTi
tz = DefaultTimeZone();
}
lazyDateTimeFormatData.timeZone = tz;
// Step 18.
var formatOpt = new Record();
lazyDateTimeFormatData.formatOpt = formatOpt;
+ if (mozExtensions) {
+ lazyDateTimeFormatData.mozExtensions = true;
+
+ let pattern = GetOption(options, "pattern", "string", undefined, undefined);
+ lazyDateTimeFormatData.patternOption = pattern;
+
+ let dateStyle = GetOption(options, "dateStyle", "string", ["full", "long", "medium", "short"], undefined);
+ lazyDateTimeFormatData.dateStyle = dateStyle;
+ let timeStyle = GetOption(options, "timeStyle", "string", ["full", "long", "medium", "short"], undefined);
+ lazyDateTimeFormatData.timeStyle = timeStyle;
+ }
+
// Step 19.
// 12.1, Table 4: Components of date and time formats.
formatOpt.weekday = GetOption(options, "weekday", "string", ["narrow", "short", "long"],
undefined);
formatOpt.era = GetOption(options, "era", "string", ["narrow", "short", "long"], undefined);
formatOpt.year = GetOption(options, "year", "string", ["2-digit", "numeric"], undefined);
formatOpt.month = GetOption(options, "month", "string",
["2-digit", "numeric", "narrow", "short", "long"], undefined);
@@ -2478,18 +2508,18 @@ function InitializeDateTimeFormat(dateTi
// have to be mapped to patterns before processing.
//
// The options of DateTimeFormat most closely correspond to ICU skeletons. This
// implementation therefore, in the toBestICUPattern function, converts
// DateTimeFormat options to ICU skeletons, and then lets ICU map skeletons to
// actual ICU patterns. The pattern may not directly correspond to what the
// skeleton requests, as the mapper (UDateTimePatternGenerator) is constrained
// by the available locale data for the locale. The resulting ICU pattern is
-// kept as the DateTimeFormat's [[pattern]] internal property and passed to ICU
-// in the format method.
+// kept as the DateTimeFormat's [[pattern]] internal property and
+// passed to ICU in the format method.
//
// An ICU pattern represents the information of the following DateTimeFormat
// internal properties described in the specification, which therefore don't
// exist separately in the implementation:
// - [[weekday]], [[era]], [[year]], [[month]], [[day]], [[hour]], [[minute]],
// [[second]], [[timeZoneName]]
// - [[hour12]]
// - [[hourNo0]]
@@ -2887,18 +2917,30 @@ function Intl_DateTimeFormat_resolvedOpt
var dtf = UnwrapDateTimeFormat(this, "resolvedOptions");
var internals = getDateTimeFormatInternals(dtf);
var result = {
locale: internals.locale,
calendar: internals.calendar,
numberingSystem: internals.numberingSystem,
- timeZone: internals.timeZone
+ timeZone: internals.timeZone,
};
+
+ if (internals.mozExtensions) {
+ result.pattern = internals.pattern;
+
+ if (internals.dateStyle) {
+ result.dateStyle = internals.dateStyle;
+ }
+ if (internals.timeStyle) {
+ result.timeStyle = internals.timeStyle;
+ }
+ }
+
resolveICUPattern(internals.pattern, result);
return result;
}
// Table mapping ICU pattern characters back to the corresponding date-time
// components of DateTimeFormat. See
// http://unicode.org/reports/tr35/tr35-dates.html#Date_Field_Symbol_Table
--- a/js/src/jsfriendapi.h
+++ b/js/src/jsfriendapi.h
@@ -2860,16 +2860,21 @@ extern JS_FRIEND_API(JSObject*)
ToWindowIfWindowProxy(JSObject* obj);
// Create and add the Intl.PluralRules constructor function to the provided
// object. This function throws if called more than once per realm/global
// object.
extern bool
AddPluralRulesConstructor(JSContext* cx, JS::Handle<JSObject*> intl);
+// Create and add the Intl.DateTimeFormat constructor function to the provided
+// object.
+extern bool
+AddDateTimeFormatConstructor(JSContext* cx, JS::Handle<JSObject*> intl);
+
class MOZ_STACK_CLASS JS_FRIEND_API(AutoAssertNoContentJS)
{
public:
explicit AutoAssertNoContentJS(JSContext* cx);
~AutoAssertNoContentJS();
private:
JSContext* context_;
--- a/js/src/shell/js.cpp
+++ b/js/src/shell/js.cpp
@@ -908,16 +908,19 @@ AddIntlExtras(JSContext* cx, unsigned ar
};
if (!JS_DefineFunctions(cx, intl, funcs))
return false;
if (!js::AddPluralRulesConstructor(cx, intl))
return false;
+ if (!js::AddDateTimeFormatConstructor(cx, intl))
+ return false;
+
args.rval().setUndefined();
return true;
}
#endif // ENABLE_INTL_API
static bool
EvalAndPrint(JSContext* cx, const char* bytes, size_t length,
int lineno, bool compileOnly)
new file mode 100644
--- /dev/null
+++ b/js/src/tests/Intl/DateTimeFormat/mozExtensions.js
@@ -0,0 +1,58 @@
+// |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 format function with a diverse set of locales and options.
+// Always use UTC to avoid dependencies on test environment.
+
+let mozIntl = {};
+addIntlExtras(mozIntl);
+
+// Pattern
+
+var dtf = new Intl.DateTimeFormat("en-US", {pattern: "HH:mm MM/dd/YYYY"});
+var mozDtf = new mozIntl.DateTimeFormat("en-US", {pattern: "HH:mm MM/dd/YYYY"});
+
+assertEq(dtf.resolvedOptions().hasOwnProperty('pattern'), false);
+assertEq(mozDtf.resolvedOptions().pattern, "HH:mm MM/dd/YYYY");
+
+// Date style
+
+var dtf = new Intl.DateTimeFormat("en-US", {dateStyle: 'long'});
+assertEq(mozDtf.resolvedOptions().hasOwnProperty('dateStyle'), false);
+
+var mozDtf = new mozIntl.DateTimeFormat("en-US", {dateStyle: 'long'});
+assertEq(mozDtf.resolvedOptions().dateStyle, 'long');
+assertEq(mozDtf.resolvedOptions().hasOwnProperty('year'), true);
+assertEq(mozDtf.resolvedOptions().hasOwnProperty('month'), true);
+assertEq(mozDtf.resolvedOptions().hasOwnProperty('day'), true);
+
+// Time style
+
+var dtf = new Intl.DateTimeFormat("en-US", {timeStyle: 'long'});
+assertEq(dtf.resolvedOptions().hasOwnProperty('dateStyle'), false);
+
+var mozDtf = new mozIntl.DateTimeFormat("en-US", {timeStyle: 'long'});
+assertEq(mozDtf.resolvedOptions().timeStyle, 'long');
+assertEq(mozDtf.resolvedOptions().hasOwnProperty('hour'), true);
+assertEq(mozDtf.resolvedOptions().hasOwnProperty('minute'), true);
+assertEq(mozDtf.resolvedOptions().hasOwnProperty('second'), true);
+
+// Date/Time style
+
+var dtf = new Intl.DateTimeFormat("en-US", {timeStyle: 'medium', dateStyle: 'medium'});
+assertEq(dtf.resolvedOptions().hasOwnProperty('dateStyle'), false);
+assertEq(dtf.resolvedOptions().hasOwnProperty('timeStyle'), false);
+
+var mozDtf = new mozIntl.DateTimeFormat("en-US", {dateStyle: 'medium', timeStyle: 'medium'});
+assertEq(mozDtf.resolvedOptions().timeStyle, 'medium');
+assertEq(mozDtf.resolvedOptions().dateStyle, 'medium');
+assertEq(mozDtf.resolvedOptions().hasOwnProperty('hour'), true);
+assertEq(mozDtf.resolvedOptions().hasOwnProperty('minute'), true);
+assertEq(mozDtf.resolvedOptions().hasOwnProperty('second'), true);
+assertEq(mozDtf.resolvedOptions().hasOwnProperty('year'), true);
+assertEq(mozDtf.resolvedOptions().hasOwnProperty('month'), true);
+assertEq(mozDtf.resolvedOptions().hasOwnProperty('day'), true);
+
+reportCompare(0, 0, 'ok');
--- a/js/src/vm/SelfHosting.cpp
+++ b/js/src/vm/SelfHosting.cpp
@@ -2490,16 +2490,17 @@ static const JSFunctionSpec intrinsic_fu
JS_FN("intl_FormatNumber", intl_FormatNumber, 2,0),
JS_FN("intl_GetCalendarInfo", intl_GetCalendarInfo, 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_patternForStyle", intl_patternForStyle, 3,0),
JS_FN("intl_PluralRules_availableLocales", intl_PluralRules_availableLocales, 0,0),
JS_FN("intl_GetPluralCategories", intl_GetPluralCategories, 2, 0),
JS_FN("intl_SelectPluralRule", intl_SelectPluralRule, 2,0),
JS_INLINABLE_FN("IsCollator",
intrinsic_IsInstanceOfBuiltin<CollatorObject>, 1,0,
IntlIsCollator),
JS_INLINABLE_FN("IsDateTimeFormat",