mirror of
https://repo.dactyloidae.xyz/Dactyloidae/UXP.git
synced 2026-10-27 01:27:30 +09:00
Issue #1969 - Implement Intl.RelativeTimeFormat.
Based on Mozilla bugs 1270140, 1504656, 1483545, and 1504334. Took note of Mozilla bug 1379222 which changed GetPrototypeFromCallableConstructor to GetPrototypeFromBuiltinConstructor. There are many other changes I did myself since the initial implementation by Mozilla wouldn't work with this codebase.
This commit is contained in:
parent
c090dd7ce8
commit
3e6cbc6af3
13 changed files with 669 additions and 20 deletions
|
|
@ -86,12 +86,14 @@ included_inclnames_to_ignore = set([
|
||||||
'unicode/ucol.h', # ICU
|
'unicode/ucol.h', # ICU
|
||||||
'unicode/udat.h', # ICU
|
'unicode/udat.h', # ICU
|
||||||
'unicode/udatpg.h', # ICU
|
'unicode/udatpg.h', # ICU
|
||||||
|
'unicode/udisplaycontext.h',# ICU
|
||||||
'unicode/uenum.h', # ICU
|
'unicode/uenum.h', # ICU
|
||||||
'unicode/uniset.h', # ICU
|
'unicode/uniset.h', # ICU
|
||||||
'unicode/unorm.h', # ICU
|
'unicode/unorm.h', # ICU
|
||||||
'unicode/unum.h', # ICU
|
'unicode/unum.h', # ICU
|
||||||
'unicode/unumsys.h', # ICU
|
'unicode/unumsys.h', # ICU
|
||||||
'unicode/upluralrules.h', # ICU
|
'unicode/upluralrules.h', # ICU
|
||||||
|
'unicode/ureldatefmt.h', # ICU
|
||||||
'unicode/ustring.h', # ICU
|
'unicode/ustring.h', # ICU
|
||||||
'unicode/utypes.h', # ICU
|
'unicode/utypes.h', # ICU
|
||||||
'vtune/VTuneWrapper.h' # VTune
|
'vtune/VTuneWrapper.h' # VTune
|
||||||
|
|
|
||||||
1
config/external/icu/defs.mozbuild
vendored
1
config/external/icu/defs.mozbuild
vendored
|
|
@ -14,7 +14,6 @@ DEFINES.update(
|
||||||
UCONFIG_NO_LEGACY_CONVERSION = True,
|
UCONFIG_NO_LEGACY_CONVERSION = True,
|
||||||
UCONFIG_NO_TRANSLITERATION = True,
|
UCONFIG_NO_TRANSLITERATION = True,
|
||||||
UCONFIG_NO_REGULAR_EXPRESSIONS = True,
|
UCONFIG_NO_REGULAR_EXPRESSIONS = True,
|
||||||
UCONFIG_NO_BREAK_ITERATION = True,
|
|
||||||
|
|
||||||
# We don't need to pass data to and from legacy char* APIs.
|
# We don't need to pass data to and from legacy char* APIs.
|
||||||
U_CHARSET_IS_UTF8 = True,
|
U_CHARSET_IS_UTF8 = True,
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,45 @@
|
||||||
|
Workaround for https://unicode-org.atlassian.net/browse/ICU-20253
|
||||||
|
|
||||||
|
https://bugzilla.mozilla.org/show_bug.cgi?id=1504656
|
||||||
|
|
||||||
|
diff --git a/intl/icu/source/i18n/reldatefmt.cpp b/intl/icu/source/i18n/reldatefmt.cpp
|
||||||
|
--- a/intl/icu/source/i18n/reldatefmt.cpp
|
||||||
|
+++ b/intl/icu/source/i18n/reldatefmt.cpp
|
||||||
|
@@ -157,24 +157,30 @@ const UnicodeString& RelativeDateTimeCac
|
||||||
|
}
|
||||||
|
|
||||||
|
// Use fallback cache for SimpleFormatter relativeUnits.
|
||||||
|
const SimpleFormatter* RelativeDateTimeCacheData::getRelativeDateTimeUnitFormatter(
|
||||||
|
int32_t fStyle,
|
||||||
|
URelativeDateTimeUnit unit,
|
||||||
|
int32_t pastFutureIndex,
|
||||||
|
int32_t pluralUnit) const {
|
||||||
|
- int32_t style = fStyle;
|
||||||
|
- do {
|
||||||
|
- if (relativeUnitsFormatters[style][unit][pastFutureIndex][pluralUnit] != nullptr) {
|
||||||
|
- return relativeUnitsFormatters[style][unit][pastFutureIndex][pluralUnit];
|
||||||
|
+ while (true) {
|
||||||
|
+ int32_t style = fStyle;
|
||||||
|
+ do {
|
||||||
|
+ if (relativeUnitsFormatters[style][unit][pastFutureIndex][pluralUnit] != nullptr) {
|
||||||
|
+ return relativeUnitsFormatters[style][unit][pastFutureIndex][pluralUnit];
|
||||||
|
+ }
|
||||||
|
+ style = fallBackCache[style];
|
||||||
|
+ } while (style != -1);
|
||||||
|
+
|
||||||
|
+ if (pluralUnit == StandardPlural::OTHER) {
|
||||||
|
+ return nullptr; // No formatter found.
|
||||||
|
}
|
||||||
|
- style = fallBackCache[style];
|
||||||
|
- } while (style != -1);
|
||||||
|
- return nullptr; // No formatter found.
|
||||||
|
+ pluralUnit = StandardPlural::OTHER;
|
||||||
|
+ }
|
||||||
|
}
|
||||||
|
|
||||||
|
static UBool getStringWithFallback(
|
||||||
|
const UResourceBundle *resource,
|
||||||
|
const char *key,
|
||||||
|
UnicodeString &result,
|
||||||
|
UErrorCode &status) {
|
||||||
|
int32_t len = 0;
|
||||||
|
|
@ -162,14 +162,20 @@ const UnicodeString& RelativeDateTimeCacheData::getAbsoluteUnitString(
|
||||||
URelativeDateTimeUnit unit,
|
URelativeDateTimeUnit unit,
|
||||||
int32_t pastFutureIndex,
|
int32_t pastFutureIndex,
|
||||||
int32_t pluralUnit) const {
|
int32_t pluralUnit) const {
|
||||||
int32_t style = fStyle;
|
while (true) {
|
||||||
do {
|
int32_t style = fStyle;
|
||||||
if (relativeUnitsFormatters[style][unit][pastFutureIndex][pluralUnit] != nullptr) {
|
do {
|
||||||
return relativeUnitsFormatters[style][unit][pastFutureIndex][pluralUnit];
|
if (relativeUnitsFormatters[style][unit][pastFutureIndex][pluralUnit] != nullptr) {
|
||||||
|
return relativeUnitsFormatters[style][unit][pastFutureIndex][pluralUnit];
|
||||||
|
}
|
||||||
|
style = fallBackCache[style];
|
||||||
|
} while (style != -1);
|
||||||
|
|
||||||
|
if (pluralUnit == StandardPlural::OTHER) {
|
||||||
|
return nullptr; // No formatter found.
|
||||||
}
|
}
|
||||||
style = fallBackCache[style];
|
pluralUnit = StandardPlural::OTHER;
|
||||||
} while (style != -1);
|
}
|
||||||
return nullptr; // No formatter found.
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static UBool getStringWithFallback(
|
static UBool getStringWithFallback(
|
||||||
|
|
|
||||||
2
intl/patch-icu.sh
Normal file → Executable file
2
intl/patch-icu.sh
Normal file → Executable file
|
|
@ -21,7 +21,9 @@ for patch in \
|
||||||
suppress-warnings.diff \
|
suppress-warnings.diff \
|
||||||
bug-1172609-timezone-recreateDefault.diff \
|
bug-1172609-timezone-recreateDefault.diff \
|
||||||
bug-1198952-workaround-make-3.82-bug.diff \
|
bug-1198952-workaround-make-3.82-bug.diff \
|
||||||
|
bug-1504656-relativetimeformat-plural-other-fallback.diff \
|
||||||
; do
|
; do
|
||||||
echo "Applying local patch $patch"
|
echo "Applying local patch $patch"
|
||||||
patch -d ${icu_dir}/../../ -p1 --no-backup-if-mismatch < ${icu_dir}/../icu-patches/$patch
|
patch -d ${icu_dir}/../../ -p1 --no-backup-if-mismatch < ${icu_dir}/../icu-patches/$patch
|
||||||
done
|
done
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -7,11 +7,11 @@ set -e
|
||||||
|
|
||||||
# Update to an ICU release:
|
# Update to an ICU release:
|
||||||
# Usage: update-icu.sh <URL of ICU GIT> <release tag name>
|
# Usage: update-icu.sh <URL of ICU GIT> <release tag name>
|
||||||
# E.g., for ICU 63.2: update-icu.sh https://github.com/unicode-org/icu.git release-63-2
|
# E.g., for ICU 62.2: update-icu.sh https://github.com/unicode-org/icu.git release-62-2
|
||||||
#
|
#
|
||||||
# Update to an ICU maintenance branch:
|
# Update to an ICU maintenance branch:
|
||||||
# Usage: update-icu.sh <URL of ICU GIT> <maintenance name>
|
# Usage: update-icu.sh <URL of ICU GIT> <maintenance name>
|
||||||
# E.g., for ICU 63.2: update-icu.sh https://github.com/unicode-org/icu.git maint/maint-63
|
# E.g., for ICU 62.2: update-icu.sh https://github.com/unicode-org/icu.git maint/maint-62
|
||||||
|
|
||||||
if [ $# -lt 2 ]; then
|
if [ $# -lt 2 ]; then
|
||||||
echo "Usage: update-icu.sh <URL of ICU GIT> <release tag name>"
|
echo "Usage: update-icu.sh <URL of ICU GIT> <release tag name>"
|
||||||
|
|
@ -86,6 +86,7 @@ for patch in \
|
||||||
suppress-warnings.diff \
|
suppress-warnings.diff \
|
||||||
bug-1172609-timezone-recreateDefault.diff \
|
bug-1172609-timezone-recreateDefault.diff \
|
||||||
bug-1198952-workaround-make-3.82-bug.diff \
|
bug-1198952-workaround-make-3.82-bug.diff \
|
||||||
|
bug-1504656-relativetimeformat-plural-other-fallback.diff \
|
||||||
; do
|
; do
|
||||||
echo "Applying local patch $patch"
|
echo "Applying local patch $patch"
|
||||||
patch -d ${icu_dir}/../../ -p1 --no-backup-if-mismatch < ${icu_dir}/../icu-patches/$patch
|
patch -d ${icu_dir}/../../ -p1 --no-backup-if-mismatch < ${icu_dir}/../icu-patches/$patch
|
||||||
|
|
|
||||||
|
|
@ -913,7 +913,7 @@ struct JSClass {
|
||||||
// application.
|
// application.
|
||||||
#define JSCLASS_GLOBAL_APPLICATION_SLOTS 5
|
#define JSCLASS_GLOBAL_APPLICATION_SLOTS 5
|
||||||
#define JSCLASS_GLOBAL_SLOT_COUNT \
|
#define JSCLASS_GLOBAL_SLOT_COUNT \
|
||||||
(JSCLASS_GLOBAL_APPLICATION_SLOTS + JSProto_LIMIT * 2 + 46)
|
(JSCLASS_GLOBAL_APPLICATION_SLOTS + JSProto_LIMIT * 2 + 47)
|
||||||
#define JSCLASS_GLOBAL_FLAGS_WITH_SLOTS(n) \
|
#define JSCLASS_GLOBAL_FLAGS_WITH_SLOTS(n) \
|
||||||
(JSCLASS_IS_GLOBAL | JSCLASS_HAS_RESERVED_SLOTS(JSCLASS_GLOBAL_SLOT_COUNT + (n)))
|
(JSCLASS_IS_GLOBAL | JSCLASS_HAS_RESERVED_SLOTS(JSCLASS_GLOBAL_SLOT_COUNT + (n)))
|
||||||
#define JSCLASS_GLOBAL_FLAGS \
|
#define JSCLASS_GLOBAL_FLAGS \
|
||||||
|
|
|
||||||
|
|
@ -11,6 +11,7 @@
|
||||||
#include "builtin/Intl.h"
|
#include "builtin/Intl.h"
|
||||||
|
|
||||||
#include "mozilla/Casting.h"
|
#include "mozilla/Casting.h"
|
||||||
|
#include "mozilla/FloatingPoint.h"
|
||||||
#include "mozilla/PodOperations.h"
|
#include "mozilla/PodOperations.h"
|
||||||
#include "mozilla/Range.h"
|
#include "mozilla/Range.h"
|
||||||
|
|
||||||
|
|
@ -28,10 +29,12 @@
|
||||||
#include "unicode/ucol.h"
|
#include "unicode/ucol.h"
|
||||||
#include "unicode/udat.h"
|
#include "unicode/udat.h"
|
||||||
#include "unicode/udatpg.h"
|
#include "unicode/udatpg.h"
|
||||||
|
#include "unicode/udisplaycontext.h"
|
||||||
#include "unicode/uenum.h"
|
#include "unicode/uenum.h"
|
||||||
#include "unicode/unum.h"
|
#include "unicode/unum.h"
|
||||||
#include "unicode/unumsys.h"
|
#include "unicode/unumsys.h"
|
||||||
#include "unicode/upluralrules.h"
|
#include "unicode/upluralrules.h"
|
||||||
|
#include "unicode/ureldatefmt.h"
|
||||||
#include "unicode/ustring.h"
|
#include "unicode/ustring.h"
|
||||||
#include "vm/DateTime.h"
|
#include "vm/DateTime.h"
|
||||||
#include "vm/GlobalObject.h"
|
#include "vm/GlobalObject.h"
|
||||||
|
|
@ -3205,6 +3208,303 @@ js::intl_GetPluralCategories(JSContext* cx, unsigned argc, Value* vp)
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**************** RelativeTimeFormat *****************/
|
||||||
|
|
||||||
|
static void relativeTimeFormat_finalize(FreeOp* fop, JSObject* obj);
|
||||||
|
|
||||||
|
static const uint32_t URELATIVE_TIME_FORMAT_SLOT = 0;
|
||||||
|
static const uint32_t RELATIVE_TIME_FORMAT_SLOTS_COUNT = 1;
|
||||||
|
|
||||||
|
static const ClassOps RelativeTimeFormatClassOps = {
|
||||||
|
nullptr, /* addProperty */
|
||||||
|
nullptr, /* delProperty */
|
||||||
|
nullptr, /* getProperty */
|
||||||
|
nullptr, /* enumerate */
|
||||||
|
nullptr, /* newEnumerate */
|
||||||
|
nullptr, /* resolve */
|
||||||
|
nullptr, /* mayResolve */
|
||||||
|
relativeTimeFormat_finalize
|
||||||
|
};
|
||||||
|
|
||||||
|
static const Class RelativeTimeFormatClass = {
|
||||||
|
js_Object_str,
|
||||||
|
JSCLASS_HAS_RESERVED_SLOTS(RELATIVE_TIME_FORMAT_SLOTS_COUNT) |
|
||||||
|
JSCLASS_FOREGROUND_FINALIZE,
|
||||||
|
&RelativeTimeFormatClassOps
|
||||||
|
};
|
||||||
|
|
||||||
|
#if JS_HAS_TOSOURCE
|
||||||
|
static bool
|
||||||
|
relativeTimeFormat_toSource(JSContext* cx, unsigned argc, Value* vp)
|
||||||
|
{
|
||||||
|
CallArgs args = CallArgsFromVp(argc, vp);
|
||||||
|
args.rval().setString(cx->names().RelativeTimeFormat);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static const JSFunctionSpec relativeTimeFormat_static_methods[] = {
|
||||||
|
JS_SELF_HOSTED_FN("supportedLocalesOf", "Intl_RelativeTimeFormat_supportedLocalesOf", 1, 0),
|
||||||
|
JS_FS_END
|
||||||
|
};
|
||||||
|
|
||||||
|
static const JSFunctionSpec relativeTimeFormat_methods[] = {
|
||||||
|
JS_SELF_HOSTED_FN("resolvedOptions", "Intl_RelativeTimeFormat_resolvedOptions", 0, 0),
|
||||||
|
JS_SELF_HOSTED_FN("format", "Intl_RelativeTimeFormat_format", 2, 0),
|
||||||
|
#if JS_HAS_TOSOURCE
|
||||||
|
JS_FN(js_toSource_str, relativeTimeFormat_toSource, 0, 0),
|
||||||
|
#endif
|
||||||
|
JS_FS_END
|
||||||
|
};
|
||||||
|
|
||||||
|
static const JSPropertySpec relativeTimeFormat_properties[] = {
|
||||||
|
JS_STRING_SYM_PS(toStringTag, "Intl.RelativeTimeFormat", JSPROP_READONLY),
|
||||||
|
JS_PS_END};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* RelativeTimeFormat constructor.
|
||||||
|
* Spec: ECMAScript 402 API, RelativeTimeFormat, 1.1
|
||||||
|
*/
|
||||||
|
static bool
|
||||||
|
RelativeTimeFormat(JSContext* cx, unsigned argc, Value* vp)
|
||||||
|
{
|
||||||
|
CallArgs args = CallArgsFromVp(argc, vp);
|
||||||
|
|
||||||
|
// Step 1.
|
||||||
|
if (!ThrowIfNotConstructing(cx, args, "Intl.RelativeTimeFormat"))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// Step 2 (Inlined 9.1.14, OrdinaryCreateFromConstructor).
|
||||||
|
RootedObject proto(cx);
|
||||||
|
if (args.isConstructing() && !GetPrototypeFromCallableConstructor(cx, args, &proto))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (!proto) {
|
||||||
|
proto = GlobalObject::getOrCreateRelativeTimeFormatPrototype(cx, cx->global());
|
||||||
|
if (!proto)
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
RootedObject relativeTimeFormat(cx);
|
||||||
|
relativeTimeFormat = NewObjectWithGivenProto(cx, &RelativeTimeFormatClass, proto);
|
||||||
|
if (!relativeTimeFormat)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
relativeTimeFormat->as<NativeObject>().setReservedSlot(URELATIVE_TIME_FORMAT_SLOT, PrivateValue(nullptr));
|
||||||
|
|
||||||
|
RootedValue locales(cx, args.get(0));
|
||||||
|
RootedValue options(cx, args.get(1));
|
||||||
|
|
||||||
|
// Step 3.
|
||||||
|
if (!IntlInitialize(cx, relativeTimeFormat, cx->names().InitializeRelativeTimeFormat, locales, options))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
args.rval().setObject(*relativeTimeFormat);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
relativeTimeFormat_finalize(FreeOp* fop, JSObject* obj)
|
||||||
|
{
|
||||||
|
MOZ_ASSERT(fop->onMainThread());
|
||||||
|
|
||||||
|
// This is-undefined check shouldn't be necessary, but for internal
|
||||||
|
// brokenness in object allocation code. For the moment, hack around it by
|
||||||
|
// explicitly guarding against the possibility of the reserved slot not
|
||||||
|
// containing a private. See bug 949220.
|
||||||
|
const Value& slot = obj->as<NativeObject>().getReservedSlot(URELATIVE_TIME_FORMAT_SLOT);
|
||||||
|
if (!slot.isUndefined()) {
|
||||||
|
if (URelativeDateTimeFormatter* rtf = static_cast<URelativeDateTimeFormatter*>(slot.toPrivate()))
|
||||||
|
ureldatefmt_close(rtf);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static JSObject*
|
||||||
|
CreateRelativeTimeFormatPrototype(JSContext* cx, HandleObject Intl, Handle<GlobalObject*> global)
|
||||||
|
{
|
||||||
|
RootedFunction ctor(cx);
|
||||||
|
ctor = global->createConstructor(cx, &RelativeTimeFormat, cx->names().RelativeTimeFormat, 0);
|
||||||
|
if (!ctor)
|
||||||
|
return nullptr;
|
||||||
|
|
||||||
|
RootedNativeObject proto(cx, GlobalObject::createBlankPrototype(cx, global, &RelativeTimeFormatClass));
|
||||||
|
if (!proto)
|
||||||
|
return nullptr;
|
||||||
|
proto->setReservedSlot(URELATIVE_TIME_FORMAT_SLOT, PrivateValue(nullptr));
|
||||||
|
|
||||||
|
if (!LinkConstructorAndPrototype(cx, ctor, proto))
|
||||||
|
return nullptr;
|
||||||
|
|
||||||
|
if (!JS_DefineFunctions(cx, ctor, relativeTimeFormat_static_methods))
|
||||||
|
return nullptr;
|
||||||
|
|
||||||
|
if (!JS_DefineFunctions(cx, proto, relativeTimeFormat_methods))
|
||||||
|
return nullptr;
|
||||||
|
|
||||||
|
if (!JS_DefineProperties(cx, proto, relativeTimeFormat_properties))
|
||||||
|
return nullptr;
|
||||||
|
|
||||||
|
RootedValue options(cx);
|
||||||
|
if (!CreateDefaultOptions(cx, &options))
|
||||||
|
return nullptr;
|
||||||
|
|
||||||
|
if (!IntlInitialize(cx, proto, cx->names().InitializeRelativeTimeFormat, UndefinedHandleValue,
|
||||||
|
options))
|
||||||
|
{
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
RootedValue ctorValue(cx, ObjectValue(*ctor));
|
||||||
|
if (!DefineProperty(cx, Intl, cx->names().RelativeTimeFormat, ctorValue, nullptr, nullptr, 0)) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
return proto;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
js::intl_RelativeTimeFormat_availableLocales(JSContext* cx, unsigned argc, Value* vp)
|
||||||
|
{
|
||||||
|
CallArgs args = CallArgsFromVp(argc, vp);
|
||||||
|
MOZ_ASSERT(args.length() == 0);
|
||||||
|
|
||||||
|
RootedValue result(cx);
|
||||||
|
// We're going to use ULocale availableLocales as per ICU recommendation:
|
||||||
|
// https://ssl.icu-project.org/trac/ticket/12756
|
||||||
|
if (!intl_availableLocales(cx, uloc_countAvailable, uloc_getAvailable, &result))
|
||||||
|
return false;
|
||||||
|
args.rval().set(result);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
enum class RelativeTimeNumeric
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Only strings with numeric components like `1 day ago`.
|
||||||
|
*/
|
||||||
|
Always,
|
||||||
|
/**
|
||||||
|
* Natural-language strings like `yesterday` when possible,
|
||||||
|
* otherwise strings with numeric components as in `7 months ago`.
|
||||||
|
*/
|
||||||
|
Auto,
|
||||||
|
};
|
||||||
|
|
||||||
|
bool
|
||||||
|
js::intl_FormatRelativeTime(JSContext* cx, unsigned argc, Value* vp)
|
||||||
|
{
|
||||||
|
CallArgs args = CallArgsFromVp(argc, vp);
|
||||||
|
MOZ_ASSERT(args.length() == 3);
|
||||||
|
|
||||||
|
RootedObject relativeTimeFormat(cx, &args[0].toObject());
|
||||||
|
|
||||||
|
RootedObject internals(cx, GetInternals(cx, relativeTimeFormat));
|
||||||
|
if (!internals)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
RootedValue value(cx);
|
||||||
|
|
||||||
|
if (!GetProperty(cx, internals, internals, cx->names().locale, &value))
|
||||||
|
return false;
|
||||||
|
JSAutoByteString locale(cx, value.toString());
|
||||||
|
if (!locale)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (!GetProperty(cx, internals, internals, cx->names().style, &value))
|
||||||
|
return false;
|
||||||
|
RootedLinearString style(cx, value.toString()->ensureLinear(cx));
|
||||||
|
if (!style)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
double t = args[1].toNumber();
|
||||||
|
|
||||||
|
UDateRelativeDateTimeFormatterStyle relDateTimeStyle;
|
||||||
|
|
||||||
|
if (StringEqualsAscii(style, "short")) {
|
||||||
|
relDateTimeStyle = UDAT_STYLE_SHORT;
|
||||||
|
} else if (StringEqualsAscii(style, "narrow")) {
|
||||||
|
relDateTimeStyle = UDAT_STYLE_NARROW;
|
||||||
|
} else {
|
||||||
|
MOZ_ASSERT(StringEqualsAscii(style, "long"));
|
||||||
|
relDateTimeStyle = UDAT_STYLE_LONG;
|
||||||
|
}
|
||||||
|
|
||||||
|
URelativeDateTimeUnit relDateTimeUnit;
|
||||||
|
{
|
||||||
|
JSLinearString* unit = args[2].toString()->ensureLinear(cx);
|
||||||
|
if (!unit) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (StringEqualsAscii(unit, "second") || StringEqualsAscii(unit, "seconds")) {
|
||||||
|
relDateTimeUnit = UDAT_REL_UNIT_SECOND;
|
||||||
|
} else if (StringEqualsAscii(unit, "minute") || StringEqualsAscii(unit, "minutes")) {
|
||||||
|
relDateTimeUnit = UDAT_REL_UNIT_MINUTE;
|
||||||
|
} else if (StringEqualsAscii(unit, "hour") || StringEqualsAscii(unit, "hours")) {
|
||||||
|
relDateTimeUnit = UDAT_REL_UNIT_HOUR;
|
||||||
|
} else if (StringEqualsAscii(unit, "day") || StringEqualsAscii(unit, "days")) {
|
||||||
|
relDateTimeUnit = UDAT_REL_UNIT_DAY;
|
||||||
|
} else if (StringEqualsAscii(unit, "week") || StringEqualsAscii(unit, "weeks")) {
|
||||||
|
relDateTimeUnit = UDAT_REL_UNIT_WEEK;
|
||||||
|
} else if (StringEqualsAscii(unit, "month") || StringEqualsAscii(unit, "months")) {
|
||||||
|
relDateTimeUnit = UDAT_REL_UNIT_MONTH;
|
||||||
|
} else if (StringEqualsAscii(unit, "quarter") || StringEqualsAscii(unit, "quarters")) {
|
||||||
|
relDateTimeUnit = UDAT_REL_UNIT_QUARTER;
|
||||||
|
} else {
|
||||||
|
MOZ_ASSERT(StringEqualsAscii(unit, "year") || StringEqualsAscii(unit, "years"));
|
||||||
|
relDateTimeUnit = UDAT_REL_UNIT_YEAR;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!GetProperty(cx, internals, internals, cx->names().numeric, &value))
|
||||||
|
return false;
|
||||||
|
RootedLinearString numeric(cx, value.toString()->ensureLinear(cx));
|
||||||
|
if (!numeric)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
RelativeTimeNumeric relDateTimeNumeric;
|
||||||
|
|
||||||
|
if (StringEqualsAscii(numeric, "auto")) {
|
||||||
|
relDateTimeNumeric = RelativeTimeNumeric::Auto;
|
||||||
|
} else {
|
||||||
|
MOZ_ASSERT(StringEqualsAscii(numeric, "always"));
|
||||||
|
relDateTimeNumeric = RelativeTimeNumeric::Always;
|
||||||
|
}
|
||||||
|
|
||||||
|
Vector<char16_t, INITIAL_CHAR_BUFFER_SIZE> chars(cx);
|
||||||
|
if (!chars.resize(INITIAL_CHAR_BUFFER_SIZE))
|
||||||
|
return false;
|
||||||
|
UErrorCode status = U_ZERO_ERROR;
|
||||||
|
URelativeDateTimeFormatter* rtf =
|
||||||
|
ureldatefmt_open(icuLocale(locale.ptr()), nullptr, relDateTimeStyle,
|
||||||
|
UDISPCTX_CAPITALIZATION_FOR_STANDALONE, &status);
|
||||||
|
if (U_FAILURE(status)) {
|
||||||
|
JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_INTERNAL_INTL_ERROR);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
int32_t size;
|
||||||
|
|
||||||
|
if (relDateTimeNumeric == RelativeTimeNumeric::Auto) {
|
||||||
|
size = ureldatefmt_format(rtf, t, relDateTimeUnit, Char16ToUChar(chars.begin()),
|
||||||
|
INITIAL_CHAR_BUFFER_SIZE, &status);
|
||||||
|
} else {
|
||||||
|
MOZ_ASSERT(relDateTimeNumeric == RelativeTimeNumeric::Always);
|
||||||
|
size = ureldatefmt_formatNumeric(rtf, t, relDateTimeUnit, Char16ToUChar(chars.begin()),
|
||||||
|
INITIAL_CHAR_BUFFER_SIZE, &status);
|
||||||
|
}
|
||||||
|
|
||||||
|
ScopedICUObject<URelativeDateTimeFormatter, ureldatefmt_close> closeRelativeTimeFormat(rtf);
|
||||||
|
|
||||||
|
JSString* str = NewStringCopyN<CanGC>(cx, chars.begin(), size);
|
||||||
|
if (!str)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
args.rval().setString(str);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
js::intl_GetCalendarInfo(JSContext* cx, unsigned argc, Value* vp)
|
js::intl_GetCalendarInfo(JSContext* cx, unsigned argc, Value* vp)
|
||||||
{
|
{
|
||||||
|
|
@ -3647,6 +3947,11 @@ GlobalObject::initIntlObject(JSContext* cx, Handle<GlobalObject*> global)
|
||||||
if (!pluralRulesProto)
|
if (!pluralRulesProto)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
RootedObject relativeTimeFmtProto(cx, CreateRelativeTimeFormatPrototype(cx, intl, global));
|
||||||
|
if (!relativeTimeFmtProto) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
// The |Intl| object is fully set up now, so define the global property.
|
// The |Intl| object is fully set up now, so define the global property.
|
||||||
RootedValue intlValue(cx, ObjectValue(*intl));
|
RootedValue intlValue(cx, ObjectValue(*intl));
|
||||||
if (!DefineProperty(cx, global, cx->names().Intl, intlValue, nullptr, nullptr,
|
if (!DefineProperty(cx, global, cx->names().Intl, intlValue, nullptr, nullptr,
|
||||||
|
|
@ -3668,6 +3973,7 @@ GlobalObject::initIntlObject(JSContext* cx, Handle<GlobalObject*> global)
|
||||||
global->setReservedSlot(DATE_TIME_FORMAT_PROTO, ObjectValue(*dateTimeFormatProto));
|
global->setReservedSlot(DATE_TIME_FORMAT_PROTO, ObjectValue(*dateTimeFormatProto));
|
||||||
global->setReservedSlot(NUMBER_FORMAT_PROTO, ObjectValue(*numberFormatProto));
|
global->setReservedSlot(NUMBER_FORMAT_PROTO, ObjectValue(*numberFormatProto));
|
||||||
global->setReservedSlot(PLURAL_RULES_PROTO, ObjectValue(*pluralRulesProto));
|
global->setReservedSlot(PLURAL_RULES_PROTO, ObjectValue(*pluralRulesProto));
|
||||||
|
global->setReservedSlot(RELATIVE_TIME_FORMAT_PROTO, ObjectValue(*relativeTimeFmtProto));
|
||||||
|
|
||||||
// Also cache |Intl| to implement spec language that conditions behavior
|
// Also cache |Intl| to implement spec language that conditions behavior
|
||||||
// based on values being equal to "the standard built-in |Intl| object".
|
// based on values being equal to "the standard built-in |Intl| object".
|
||||||
|
|
|
||||||
|
|
@ -406,6 +406,31 @@ intl_SelectPluralRule(JSContext* cx, unsigned argc, Value* vp);
|
||||||
extern MOZ_MUST_USE bool
|
extern MOZ_MUST_USE bool
|
||||||
intl_GetPluralCategories(JSContext* cx, unsigned argc, Value* vp);
|
intl_GetPluralCategories(JSContext* cx, unsigned argc, Value* vp);
|
||||||
|
|
||||||
|
/******************** RelativeTimeFormat ********************/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns an object indicating the supported locales for relative time format
|
||||||
|
* by having a true-valued property for each such locale with the
|
||||||
|
* canonicalized language tag as the property name. The object has no
|
||||||
|
* prototype.
|
||||||
|
*
|
||||||
|
* Usage: availableLocales = intl_RelativeTimeFormat_availableLocales()
|
||||||
|
*/
|
||||||
|
extern MOZ_MUST_USE bool
|
||||||
|
intl_RelativeTimeFormat_availableLocales(JSContext* cx, unsigned argc, Value* vp);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a relative time as a string formatted according to the effective
|
||||||
|
* locale and the formatting options of the given RelativeTimeFormat.
|
||||||
|
*
|
||||||
|
* t should be a number representing a number to be formatted.
|
||||||
|
* unit should be "second", "minute", "hour", "day", "week", "month", "quarter", or "year".
|
||||||
|
*
|
||||||
|
* Usage: formatted = intl_FormatRelativeTime(relativeTimeFormat, t, unit)
|
||||||
|
*/
|
||||||
|
extern MOZ_MUST_USE bool
|
||||||
|
intl_FormatRelativeTime(JSContext* cx, unsigned argc, Value* vp);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns a plain object with calendar information for a single valid locale
|
* Returns a plain object with calendar information for a single valid locale
|
||||||
* (callers must perform this validation). The object will have these
|
* (callers must perform this validation). The object will have these
|
||||||
|
|
|
||||||
|
|
@ -23,6 +23,7 @@
|
||||||
intl_FormatDateTime: false,
|
intl_FormatDateTime: false,
|
||||||
intl_SelectPluralRule: false,
|
intl_SelectPluralRule: false,
|
||||||
intl_GetPluralCategories: false,
|
intl_GetPluralCategories: false,
|
||||||
|
intl_FormatRelativeTime: false,
|
||||||
intl_GetCalendarInfo: false,
|
intl_GetCalendarInfo: false,
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
@ -1275,7 +1276,8 @@ function setLazyData(internals, type, lazyData)
|
||||||
{
|
{
|
||||||
assert(internals.type === "partial", "can't set lazy data for anything but a newborn");
|
assert(internals.type === "partial", "can't set lazy data for anything but a newborn");
|
||||||
assert(type === "Collator" || type === "DateTimeFormat" ||
|
assert(type === "Collator" || type === "DateTimeFormat" ||
|
||||||
type == "NumberFormat" || type === "PluralRules",
|
type === "NumberFormat" || type === "PluralRules" ||
|
||||||
|
type === "RelativeTimeFormat",
|
||||||
"bad type");
|
"bad type");
|
||||||
assert(IsObject(lazyData), "non-object lazy data");
|
assert(IsObject(lazyData), "non-object lazy data");
|
||||||
|
|
||||||
|
|
@ -1327,7 +1329,8 @@ function isInitializedIntlObject(obj) {
|
||||||
assert(callFunction(std_Object_hasOwnProperty, internals, "type"), "missing type");
|
assert(callFunction(std_Object_hasOwnProperty, internals, "type"), "missing type");
|
||||||
var type = internals.type;
|
var type = internals.type;
|
||||||
assert(type === "partial" || type === "Collator" ||
|
assert(type === "partial" || type === "Collator" ||
|
||||||
type === "DateTimeFormat" || type === "NumberFormat" || type === "PluralRules",
|
type === "DateTimeFormat" || type === "NumberFormat" ||
|
||||||
|
type === "PluralRules" || type === "RelativeTimeFormat",
|
||||||
"unexpected type");
|
"unexpected type");
|
||||||
assert(callFunction(std_Object_hasOwnProperty, internals, "lazyData"), "missing lazyData");
|
assert(callFunction(std_Object_hasOwnProperty, internals, "lazyData"), "missing lazyData");
|
||||||
assert(callFunction(std_Object_hasOwnProperty, internals, "internalProps"), "missing internalProps");
|
assert(callFunction(std_Object_hasOwnProperty, internals, "internalProps"), "missing internalProps");
|
||||||
|
|
@ -1381,14 +1384,24 @@ function getInternals(obj)
|
||||||
|
|
||||||
var internalProps;
|
var internalProps;
|
||||||
var type = internals.type;
|
var type = internals.type;
|
||||||
if (type === "Collator")
|
|
||||||
internalProps = resolveCollatorInternals(lazyData)
|
switch (type) {
|
||||||
else if (type === "DateTimeFormat")
|
case "Collator":
|
||||||
internalProps = resolveDateTimeFormatInternals(lazyData)
|
internalProps = resolveCollatorInternals(lazyData);
|
||||||
else if (type === "PluralRules")
|
break;
|
||||||
internalProps = resolvePluralRulesInternals(lazyData)
|
case "DateTimeFormat":
|
||||||
else
|
internalProps = resolveDateTimeFormatInternals(lazyData);
|
||||||
|
break;
|
||||||
|
case "PluralRules":
|
||||||
|
internalProps = resolvePluralRulesInternals(lazyData);
|
||||||
|
break;
|
||||||
|
case "RelativeTimeFormat":
|
||||||
|
internalProps = resolveRelativeTimeFormatInternals(lazyData);
|
||||||
|
break;
|
||||||
|
default: // type === "NumberFormat"
|
||||||
internalProps = resolveNumberFormatInternals(lazyData);
|
internalProps = resolveNumberFormatInternals(lazyData);
|
||||||
|
break;
|
||||||
|
}
|
||||||
setInternalProperties(internals, internalProps);
|
setInternalProperties(internals, internalProps);
|
||||||
return internalProps;
|
return internalProps;
|
||||||
}
|
}
|
||||||
|
|
@ -3252,6 +3265,244 @@ function Intl_PluralRules_resolvedOptions() {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/********** Intl.RelativeTimeFormat **********/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* RelativeTimeFormat internal properties.
|
||||||
|
*
|
||||||
|
* Spec: ECMAScript 402 API, RelativeTimeFormat, 1.3.3.
|
||||||
|
*/
|
||||||
|
var relativeTimeFormatInternalProperties = {
|
||||||
|
localeData: relativeTimeFormatLocaleData,
|
||||||
|
_availableLocales: null,
|
||||||
|
availableLocales: function() // eslint-disable-line object-shorthand
|
||||||
|
{
|
||||||
|
var locales = this._availableLocales;
|
||||||
|
if (locales)
|
||||||
|
return locales;
|
||||||
|
|
||||||
|
locales = intl_RelativeTimeFormat_availableLocales();
|
||||||
|
addSpecialMissingLanguageTags(locales);
|
||||||
|
return (this._availableLocales = locales);
|
||||||
|
},
|
||||||
|
relevantExtensionKeys: [],
|
||||||
|
};
|
||||||
|
|
||||||
|
function relativeTimeFormatLocaleData() {
|
||||||
|
// RelativeTimeFormat doesn't support any extension keys.
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Compute an internal properties object from |lazyRelativeTimeFormatData|.
|
||||||
|
*/
|
||||||
|
function resolveRelativeTimeFormatInternals(lazyRelativeTimeFormatData) {
|
||||||
|
assert(IsObject(lazyRelativeTimeFormatData), "lazy data not an object?");
|
||||||
|
|
||||||
|
var internalProps = std_Object_create(null);
|
||||||
|
|
||||||
|
var RelativeTimeFormat = relativeTimeFormatInternalProperties;
|
||||||
|
|
||||||
|
// Steps 7-8.
|
||||||
|
const r = ResolveLocale(callFunction(RelativeTimeFormat.availableLocales, RelativeTimeFormat),
|
||||||
|
lazyRelativeTimeFormatData.requestedLocales,
|
||||||
|
lazyRelativeTimeFormatData.opt,
|
||||||
|
RelativeTimeFormat.relevantExtensionKeys,
|
||||||
|
RelativeTimeFormat.localeData);
|
||||||
|
|
||||||
|
// Step 9-10.
|
||||||
|
internalProps.locale = r.locale;
|
||||||
|
|
||||||
|
// Step 11.
|
||||||
|
assert(r.locale === r.dataLocale,
|
||||||
|
"resolved locale matches the resolved data-locale when no extension-keys are present");
|
||||||
|
|
||||||
|
// Step 13.
|
||||||
|
internalProps.style = lazyRelativeTimeFormatData.style;
|
||||||
|
|
||||||
|
// Step 15.
|
||||||
|
internalProps.numeric = lazyRelativeTimeFormatData.numeric;
|
||||||
|
|
||||||
|
// Steps 16-20 (Not relevant in our implementation).
|
||||||
|
|
||||||
|
return internalProps;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns an object containing the RelativeTimeFormat internal properties of |obj|,
|
||||||
|
* or throws a TypeError if |obj| isn't RelativeTimeFormat-initialized.
|
||||||
|
*/
|
||||||
|
function getRelativeTimeFormatInternals(obj, methodName) {
|
||||||
|
var internals = getIntlObjectInternals(obj, "RelativeTimeFormat", methodName);
|
||||||
|
assert(internals.type === "RelativeTimeFormat", "bad type escaped getIntlObjectInternals");
|
||||||
|
|
||||||
|
var internalProps = maybeInternalProperties(internals);
|
||||||
|
if (internalProps)
|
||||||
|
return internalProps;
|
||||||
|
|
||||||
|
internalProps = resolveRelativeTimeFormatInternals(internals.lazyData);
|
||||||
|
setInternalProperties(internals, internalProps);
|
||||||
|
return internalProps;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initializes an object as a RelativeTimeFormat.
|
||||||
|
*
|
||||||
|
* 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 RelativeTimeFormat.
|
||||||
|
* This later work occurs in |resolveRelativeTimeFormatInternals|; steps not noted
|
||||||
|
* here occur there.
|
||||||
|
*
|
||||||
|
* Spec: ECMAScript 402 API, RelativeTimeFormat, 1.1.1.
|
||||||
|
*/
|
||||||
|
function InitializeRelativeTimeFormat(relativeTimeFormat, locales, options) {
|
||||||
|
assert(IsObject(relativeTimeFormat), "InitializeRelativeTimeFormat");
|
||||||
|
|
||||||
|
if (isInitializedIntlObject(relativeTimeFormat))
|
||||||
|
ThrowTypeError(JSMSG_INTL_OBJECT_REINITED);
|
||||||
|
|
||||||
|
let internals = initializeIntlObject(relativeTimeFormat);
|
||||||
|
|
||||||
|
// Lazy RelativeTimeFormat data has the following structure:
|
||||||
|
//
|
||||||
|
// {
|
||||||
|
// requestedLocales: List of locales,
|
||||||
|
// style: "long" / "short" / "narrow",
|
||||||
|
// numeric: "always" / "auto",
|
||||||
|
//
|
||||||
|
// opt: // opt object computed in InitializeRelativeTimeFormat
|
||||||
|
// {
|
||||||
|
// localeMatcher: "lookup" / "best fit",
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// Note that lazy data is only installed as a final step of initialization,
|
||||||
|
// so every RelativeTimeFormat lazy data object has *all* these properties, never a
|
||||||
|
// subset of them.
|
||||||
|
const lazyRelativeTimeFormatData = std_Object_create(null);
|
||||||
|
|
||||||
|
// Step 1.
|
||||||
|
let requestedLocales = CanonicalizeLocaleList(locales);
|
||||||
|
lazyRelativeTimeFormatData.requestedLocales = requestedLocales;
|
||||||
|
|
||||||
|
// Steps 2-3.
|
||||||
|
if (options === undefined)
|
||||||
|
options = std_Object_create(null);
|
||||||
|
else
|
||||||
|
options = ToObject(options);
|
||||||
|
|
||||||
|
// Step 4.
|
||||||
|
let opt = new Record();
|
||||||
|
|
||||||
|
// Steps 5-6.
|
||||||
|
let matcher = GetOption(options, "localeMatcher", "string", ["lookup", "best fit"], "best fit");
|
||||||
|
opt.localeMatcher = matcher;
|
||||||
|
|
||||||
|
lazyRelativeTimeFormatData.opt = opt;
|
||||||
|
|
||||||
|
// Steps 12-13.
|
||||||
|
const style = GetOption(options, "style", "string", ["long", "short", "narrow"], "long");
|
||||||
|
lazyRelativeTimeFormatData.style = style;
|
||||||
|
|
||||||
|
// Steps 14-15.
|
||||||
|
const numeric = GetOption(options, "numeric", "string", ["always", "auto"], "always");
|
||||||
|
lazyRelativeTimeFormatData.numeric = numeric;
|
||||||
|
|
||||||
|
setLazyData(internals, "RelativeTimeFormat", lazyRelativeTimeFormatData)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the subset of the given locale list for which this locale list has a
|
||||||
|
* matching (possibly fallback) locale. Locales appear in the same order in the
|
||||||
|
* returned list as in the input list.
|
||||||
|
*
|
||||||
|
* Spec: ECMAScript 402 API, RelativeTimeFormat, 1.3.2.
|
||||||
|
*/
|
||||||
|
function Intl_RelativeTimeFormat_supportedLocalesOf(locales /*, options*/) {
|
||||||
|
var options = arguments.length > 1 ? arguments[1] : undefined;
|
||||||
|
|
||||||
|
// Step 1.
|
||||||
|
var availableLocales = callFunction(relativeTimeFormatInternalProperties.availableLocales,
|
||||||
|
relativeTimeFormatInternalProperties);
|
||||||
|
// Step 2.
|
||||||
|
let requestedLocales = CanonicalizeLocaleList(locales);
|
||||||
|
|
||||||
|
// Step 3.
|
||||||
|
return SupportedLocales(availableLocales, requestedLocales, options);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a String value representing the written form of a relative date
|
||||||
|
* formatted according to the effective locale and the formatting options
|
||||||
|
* of this RelativeTimeFormat object.
|
||||||
|
*
|
||||||
|
* Spec: ECMAScript 402 API, RelativeTImeFormat, 1.4.3.
|
||||||
|
*/
|
||||||
|
function Intl_RelativeTimeFormat_format(value, unit) {
|
||||||
|
// Step 1.
|
||||||
|
let relativeTimeFormat = this;
|
||||||
|
|
||||||
|
// Step 2.
|
||||||
|
let internals = getRelativeTimeFormatInternals(relativeTimeFormat, "format");
|
||||||
|
|
||||||
|
// Step 3.
|
||||||
|
let t = ToNumber(value);
|
||||||
|
|
||||||
|
// Step 4.
|
||||||
|
let u = ToString(unit);
|
||||||
|
|
||||||
|
// PartitionRelativeTimePattern, step 4.
|
||||||
|
if (!Number_isFinite(t)) {
|
||||||
|
ThrowRangeError(JSMSG_DATE_NOT_FINITE, "RelativeTimeFormat");
|
||||||
|
}
|
||||||
|
|
||||||
|
// PartitionRelativeTimePattern, step 5.
|
||||||
|
switch (u) {
|
||||||
|
case "second":
|
||||||
|
case "seconds":
|
||||||
|
case "minute":
|
||||||
|
case "minutes":
|
||||||
|
case "hour":
|
||||||
|
case "hours":
|
||||||
|
case "day":
|
||||||
|
case "days":
|
||||||
|
case "week":
|
||||||
|
case "weeks":
|
||||||
|
case "month":
|
||||||
|
case "months":
|
||||||
|
case "quarter":
|
||||||
|
case "quarters":
|
||||||
|
case "year":
|
||||||
|
case "years":
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
ThrowRangeError(JSMSG_INVALID_OPTION_VALUE, "unit", u);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Step 5.
|
||||||
|
return intl_FormatRelativeTime(relativeTimeFormat, t, u, internals.numeric);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the resolved options for a PluralRules object.
|
||||||
|
*
|
||||||
|
* Spec: ECMAScript 402 API, RelativeTimeFormat, 1.4.4.
|
||||||
|
*/
|
||||||
|
function Intl_RelativeTimeFormat_resolvedOptions() {
|
||||||
|
var internals = getRelativeTimeFormatInternals(this, "resolvedOptions");
|
||||||
|
|
||||||
|
// Steps 4-5.
|
||||||
|
var result = {
|
||||||
|
locale: internals.locale,
|
||||||
|
style: internals.style,
|
||||||
|
numeric: internals.numeric,
|
||||||
|
};
|
||||||
|
|
||||||
|
// Step 6.
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
function Intl_getCanonicalLocales(locales) {
|
function Intl_getCanonicalLocales(locales) {
|
||||||
let codes = CanonicalizeLocaleList(locales);
|
let codes = CanonicalizeLocaleList(locales);
|
||||||
let result = [];
|
let result = [];
|
||||||
|
|
|
||||||
|
|
@ -182,6 +182,7 @@
|
||||||
macro(InitializeDateTimeFormat, InitializeDateTimeFormat, "InitializeDateTimeFormat") \
|
macro(InitializeDateTimeFormat, InitializeDateTimeFormat, "InitializeDateTimeFormat") \
|
||||||
macro(InitializeNumberFormat, InitializeNumberFormat, "InitializeNumberFormat") \
|
macro(InitializeNumberFormat, InitializeNumberFormat, "InitializeNumberFormat") \
|
||||||
macro(InitializePluralRules, InitializePluralRules, "InitializePluralRules") \
|
macro(InitializePluralRules, InitializePluralRules, "InitializePluralRules") \
|
||||||
|
macro(InitializeRelativeTimeFormat, InitializeRelativeTimeFormat, "InitializeRelativeTimeFormat") \
|
||||||
macro(innermost, innermost, "innermost") \
|
macro(innermost, innermost, "innermost") \
|
||||||
macro(inNursery, inNursery, "inNursery") \
|
macro(inNursery, inNursery, "inNursery") \
|
||||||
macro(input, input, "input") \
|
macro(input, input, "input") \
|
||||||
|
|
@ -297,6 +298,8 @@
|
||||||
macro(Reify, Reify, "Reify") \
|
macro(Reify, Reify, "Reify") \
|
||||||
macro(reject, reject, "reject") \
|
macro(reject, reject, "reject") \
|
||||||
macro(rejected, rejected, "rejected") \
|
macro(rejected, rejected, "rejected") \
|
||||||
|
macro(RelativeTimeFormat, RelativeTimeFormat, "RelativeTimeFormat") \
|
||||||
|
macro(RelativeTimeFormatFormat, RelativeTimeFormatFormat, "Intl_RelativeTimeFormat_Format") \
|
||||||
macro(RequireObjectCoercible, RequireObjectCoercible, "RequireObjectCoercible") \
|
macro(RequireObjectCoercible, RequireObjectCoercible, "RequireObjectCoercible") \
|
||||||
macro(resolve, resolve, "resolve") \
|
macro(resolve, resolve, "resolve") \
|
||||||
macro(resumeGenerator, resumeGenerator, "resumeGenerator") \
|
macro(resumeGenerator, resumeGenerator, "resumeGenerator") \
|
||||||
|
|
@ -364,6 +367,7 @@
|
||||||
macro(unescape, unescape, "unescape") \
|
macro(unescape, unescape, "unescape") \
|
||||||
macro(uneval, uneval, "uneval") \
|
macro(uneval, uneval, "uneval") \
|
||||||
macro(unicode, unicode, "unicode") \
|
macro(unicode, unicode, "unicode") \
|
||||||
|
macro(unit, unit, "unit") \
|
||||||
macro(uninitialized, uninitialized, "uninitialized") \
|
macro(uninitialized, uninitialized, "uninitialized") \
|
||||||
macro(unsized, unsized, "unsized") \
|
macro(unsized, unsized, "unsized") \
|
||||||
macro(unwatch, unwatch, "unwatch") \
|
macro(unwatch, unwatch, "unwatch") \
|
||||||
|
|
|
||||||
|
|
@ -110,6 +110,7 @@ class GlobalObject : public NativeObject
|
||||||
NUMBER_FORMAT_PROTO,
|
NUMBER_FORMAT_PROTO,
|
||||||
DATE_TIME_FORMAT_PROTO,
|
DATE_TIME_FORMAT_PROTO,
|
||||||
PLURAL_RULES_PROTO,
|
PLURAL_RULES_PROTO,
|
||||||
|
RELATIVE_TIME_FORMAT_PROTO,
|
||||||
MODULE_PROTO,
|
MODULE_PROTO,
|
||||||
IMPORT_ENTRY_PROTO,
|
IMPORT_ENTRY_PROTO,
|
||||||
EXPORT_ENTRY_PROTO,
|
EXPORT_ENTRY_PROTO,
|
||||||
|
|
@ -513,6 +514,11 @@ class GlobalObject : public NativeObject
|
||||||
return getOrCreateObject(cx, global, PLURAL_RULES_PROTO, initIntlObject);
|
return getOrCreateObject(cx, global, PLURAL_RULES_PROTO, initIntlObject);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static JSObject*
|
||||||
|
getOrCreateRelativeTimeFormatPrototype(JSContext* cx, Handle<GlobalObject*> global) {
|
||||||
|
return getOrCreateObject(cx, global, RELATIVE_TIME_FORMAT_PROTO, initIntlObject);
|
||||||
|
}
|
||||||
|
|
||||||
static bool ensureModulePrototypesCreated(JSContext *cx, Handle<GlobalObject*> global);
|
static bool ensureModulePrototypesCreated(JSContext *cx, Handle<GlobalObject*> global);
|
||||||
|
|
||||||
JSObject* maybeGetModulePrototype() {
|
JSObject* maybeGetModulePrototype() {
|
||||||
|
|
|
||||||
|
|
@ -2520,6 +2520,8 @@ static const JSFunctionSpec intrinsic_functions[] = {
|
||||||
JS_FN("intl_PluralRules_availableLocales", intl_PluralRules_availableLocales, 0,0),
|
JS_FN("intl_PluralRules_availableLocales", intl_PluralRules_availableLocales, 0,0),
|
||||||
JS_FN("intl_GetPluralCategories", intl_GetPluralCategories, 2, 0),
|
JS_FN("intl_GetPluralCategories", intl_GetPluralCategories, 2, 0),
|
||||||
JS_FN("intl_SelectPluralRule", intl_SelectPluralRule, 2,0),
|
JS_FN("intl_SelectPluralRule", intl_SelectPluralRule, 2,0),
|
||||||
|
JS_FN("intl_RelativeTimeFormat_availableLocales", intl_RelativeTimeFormat_availableLocales, 0,0),
|
||||||
|
JS_FN("intl_FormatRelativeTime", intl_FormatRelativeTime, 3,0),
|
||||||
|
|
||||||
JS_INLINABLE_FN("IsRegExpObject",
|
JS_INLINABLE_FN("IsRegExpObject",
|
||||||
intrinsic_IsInstanceOfBuiltin<RegExpObject>, 1,0,
|
intrinsic_IsInstanceOfBuiltin<RegExpObject>, 1,0,
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue