Bug 1421453 - Extend Intl.RelativeTimeFormat to support `type` option. r=Waldo

MozReview-Commit-ID: BUdmtVSF5La

--HG--
extra : rebase_source : 47f5dbc9111eede3b7cdf905cc207d8dcaded119
This commit is contained in:
Zibi Braniecki 2017-11-28 14:45:04 -08:00
Родитель 1ee2ce9a65
Коммит cc1a11fe27
3 изменённых файлов: 127 добавлений и 35 удалений

Просмотреть файл

@ -796,12 +796,20 @@ ureldatefmt_close(URelativeDateTimeFormatter *reldatefmt)
int32_t int32_t
ureldatefmt_format(const URelativeDateTimeFormatter* reldatefmt, double offset, ureldatefmt_format(const URelativeDateTimeFormatter* reldatefmt, double offset,
URelativeDateTimeUnit unit, UChar* result, int32_t resultCapacity, URelativeDateTimeUnit unit, UChar* result, int32_t resultCapacity,
UErrorCode* status) UErrorCode* status)
{ {
MOZ_CRASH("ureldatefmt_format: Intl API disabled"); MOZ_CRASH("ureldatefmt_format: Intl API disabled");
} }
int32_t
ureldatefmt_formatNumeric(const URelativeDateTimeFormatter* reldatefmt, double offset,
URelativeDateTimeUnit unit, UChar* result, int32_t resultCapacity,
UErrorCode* status)
{
MOZ_CRASH("ureldatefmt_formatNumeric: Intl API disabled");
}
#endif #endif
@ -4015,6 +4023,19 @@ js::intl_RelativeTimeFormat_availableLocales(JSContext* cx, unsigned argc, Value
return true; return true;
} }
enum class RelativeTimeType
{
/**
* Only strings with numeric components like `1 day ago`.
*/
Numeric,
/**
* Natural-language strings like `yesterday` when possible,
* otherwise strings with numeric components as in `7 months ago`.
*/
Text,
};
bool bool
js::intl_FormatRelativeTime(JSContext* cx, unsigned argc, Value* vp) js::intl_FormatRelativeTime(JSContext* cx, unsigned argc, Value* vp)
{ {
@ -4056,6 +4077,23 @@ js::intl_FormatRelativeTime(JSContext* cx, unsigned argc, Value* vp)
} }
} }
if (!GetProperty(cx, internals, internals, cx->names().type, &value))
return false;
RelativeTimeType relDateTimeType;
{
JSLinearString* type = value.toString()->ensureLinear(cx);
if (!type)
return false;
if (StringEqualsAscii(type, "text")) {
relDateTimeType = RelativeTimeType::Text;
} else {
MOZ_ASSERT(StringEqualsAscii(type, "numeric"));
relDateTimeType = RelativeTimeType::Numeric;
}
}
URelativeDateTimeUnit relDateTimeUnit; URelativeDateTimeUnit relDateTimeUnit;
{ {
JSLinearString* unit = args[2].toString()->ensureLinear(cx); JSLinearString* unit = args[2].toString()->ensureLinear(cx);
@ -4098,8 +4136,11 @@ js::intl_FormatRelativeTime(JSContext* cx, unsigned argc, Value* vp)
ScopedICUObject<URelativeDateTimeFormatter, ureldatefmt_close> closeRelativeTimeFormat(rtf); ScopedICUObject<URelativeDateTimeFormatter, ureldatefmt_close> closeRelativeTimeFormat(rtf);
JSString* str = Call(cx, [rtf, t, relDateTimeUnit](UChar* chars, int32_t size, UErrorCode* status) { JSString* str = Call(cx, [rtf, t, relDateTimeUnit, relDateTimeType](UChar* chars, int32_t size, UErrorCode* status) {
return ureldatefmt_format(rtf, t, relDateTimeUnit, chars, size, status); auto fmt = relDateTimeType == RelativeTimeType::Text
? ureldatefmt_format
: ureldatefmt_formatNumeric;
return fmt(rtf, t, relDateTimeUnit, chars, size, status);
}); });
if (!str) if (!str)
return false; return false;

Просмотреть файл

@ -3617,6 +3617,7 @@ function resolveRelativeTimeFormatInternals(lazyRelativeTimeFormatData) {
// Step 17. // Step 17.
internalProps.locale = r.locale; internalProps.locale = r.locale;
internalProps.style = lazyRelativeTimeFormatData.style; internalProps.style = lazyRelativeTimeFormatData.style;
internalProps.type = lazyRelativeTimeFormatData.type;
return internalProps; return internalProps;
} }
@ -3663,6 +3664,7 @@ function InitializeRelativeTimeFormat(relativeTimeFormat, locales, options) {
// { // {
// requestedLocales: List of locales, // requestedLocales: List of locales,
// style: "long" / "short" / "narrow", // style: "long" / "short" / "narrow",
// type: "numeric" / "text",
// //
// opt: // opt object computer in InitializeRelativeTimeFormat // opt: // opt object computer in InitializeRelativeTimeFormat
// { // {
@ -3698,6 +3700,11 @@ function InitializeRelativeTimeFormat(relativeTimeFormat, locales, options) {
const style = GetOption(options, "style", "string", ["long", "short", "narrow"], "long"); const style = GetOption(options, "style", "string", ["long", "short", "narrow"], "long");
lazyRelativeTimeFormatData.style = style; lazyRelativeTimeFormatData.style = style;
// This option is in the process of being added to the spec.
// See: https://github.com/tc39/proposal-intl-relative-time/issues/9
const type = GetOption(options, "type", "string", ["numeric", "text"], "numeric");
lazyRelativeTimeFormatData.type = type;
initializeIntlObject(relativeTimeFormat, "RelativeTimeFormat", lazyRelativeTimeFormatData); initializeIntlObject(relativeTimeFormat, "RelativeTimeFormat", lazyRelativeTimeFormatData);
} }
@ -3780,6 +3787,7 @@ function Intl_RelativeTimeFormat_resolvedOptions() {
var result = { var result = {
locale: internals.locale, locale: internals.locale,
style: internals.style, style: internals.style,
type: internals.type,
}; };
return result; return result;

Просмотреть файл

@ -9,48 +9,91 @@ var rtf;
addIntlExtras(Intl); addIntlExtras(Intl);
{
// Numeric format
rtf = new Intl.RelativeTimeFormat("en-US");
assertEq(rtf.format(0, "second"), "in 0 seconds");
assertEq(rtf.format(-0, "second"), "in 0 seconds");
assertEq(rtf.format(-1, "second"), "1 second ago");
assertEq(rtf.format(1, "second"), "in 1 second");
rtf = new Intl.RelativeTimeFormat("en-US"); assertEq(rtf.format(0, "minute"), "in 0 minutes");
assertEq(rtf.format(0, "second"), "now"); assertEq(rtf.format(-0, "minute"), "in 0 minutes");
assertEq(rtf.format(-0, "second"), "now"); assertEq(rtf.format(-1, "minute"), "1 minute ago");
assertEq(rtf.format(-1, "second"), "1 second ago"); assertEq(rtf.format(1, "minute"), "in 1 minute");
assertEq(rtf.format(1, "second"), "in 1 second");
assertEq(rtf.format(0, "minute"), "in 0 minutes"); assertEq(rtf.format(0, "hour"), "in 0 hours");
assertEq(rtf.format(-0, "minute"), "in 0 minutes"); assertEq(rtf.format(-0, "hour"), "in 0 hours");
assertEq(rtf.format(-1, "minute"), "1 minute ago"); assertEq(rtf.format(-1, "hour"), "1 hour ago");
assertEq(rtf.format(1, "minute"), "in 1 minute"); assertEq(rtf.format(1, "hour"), "in 1 hour");
assertEq(rtf.format(0, "hour"), "in 0 hours"); assertEq(rtf.format(0, "day"), "in 0 days");
assertEq(rtf.format(-0, "hour"), "in 0 hours"); assertEq(rtf.format(-0, "day"), "in 0 days");
assertEq(rtf.format(-1, "hour"), "1 hour ago"); assertEq(rtf.format(-1, "day"), "1 day ago");
assertEq(rtf.format(1, "hour"), "in 1 hour"); assertEq(rtf.format(1, "day"), "in 1 day");
assertEq(rtf.format(0, "day"), "today"); assertEq(rtf.format(0, "week"), "in 0 weeks");
assertEq(rtf.format(-0, "day"), "today"); assertEq(rtf.format(-0, "week"), "in 0 weeks");
assertEq(rtf.format(-1, "day"), "yesterday"); assertEq(rtf.format(-1, "week"), "1 week ago");
assertEq(rtf.format(1, "day"), "tomorrow"); assertEq(rtf.format(1, "week"), "in 1 week");
assertEq(rtf.format(0, "week"), "this week"); assertEq(rtf.format(0, "month"), "in 0 months");
assertEq(rtf.format(-0, "week"), "this week"); assertEq(rtf.format(-0, "month"), "in 0 months");
assertEq(rtf.format(-1, "week"), "last week"); assertEq(rtf.format(-1, "month"), "1 month ago");
assertEq(rtf.format(1, "week"), "next week"); assertEq(rtf.format(1, "month"), "in 1 month");
assertEq(rtf.format(0, "month"), "this month"); assertEq(rtf.format(0, "year"), "in 0 years");
assertEq(rtf.format(-0, "month"), "this month"); assertEq(rtf.format(-0, "year"), "in 0 years");
assertEq(rtf.format(-1, "month"), "last month"); assertEq(rtf.format(-1, "year"), "1 year ago");
assertEq(rtf.format(1, "month"), "next month"); assertEq(rtf.format(1, "year"), "in 1 year");
}
assertEq(rtf.format(0, "year"), "this year"); {
assertEq(rtf.format(-0, "year"), "this year"); // Text format
assertEq(rtf.format(-1, "year"), "last year"); rtf = new Intl.RelativeTimeFormat("en-US", {
assertEq(rtf.format(1, "year"), "next year"); type: "text"
});
assertEq(rtf.format(0, "second"), "now");
assertEq(rtf.format(-0, "second"), "now");
assertEq(rtf.format(-1, "second"), "1 second ago");
assertEq(rtf.format(1, "second"), "in 1 second");
rtf = new Intl.RelativeTimeFormat("de"); assertEq(rtf.format(0, "minute"), "in 0 minutes");
assertEq(rtf.format(-0, "minute"), "in 0 minutes");
assertEq(rtf.format(-1, "minute"), "1 minute ago");
assertEq(rtf.format(1, "minute"), "in 1 minute");
assertEq(rtf.format(0, "hour"), "in 0 hours");
assertEq(rtf.format(-0, "hour"), "in 0 hours");
assertEq(rtf.format(-1, "hour"), "1 hour ago");
assertEq(rtf.format(1, "hour"), "in 1 hour");
assertEq(rtf.format(0, "day"), "today");
assertEq(rtf.format(-0, "day"), "today");
assertEq(rtf.format(-1, "day"), "yesterday");
assertEq(rtf.format(1, "day"), "tomorrow");
assertEq(rtf.format(0, "week"), "this week");
assertEq(rtf.format(-0, "week"), "this week");
assertEq(rtf.format(-1, "week"), "last week");
assertEq(rtf.format(1, "week"), "next week");
assertEq(rtf.format(0, "month"), "this month");
assertEq(rtf.format(-0, "month"), "this month");
assertEq(rtf.format(-1, "month"), "last month");
assertEq(rtf.format(1, "month"), "next month");
assertEq(rtf.format(0, "year"), "this year");
assertEq(rtf.format(-0, "year"), "this year");
assertEq(rtf.format(-1, "year"), "last year");
assertEq(rtf.format(1, "year"), "next year");
}
rtf = new Intl.RelativeTimeFormat("de", {type: "text"});
assertEq(rtf.format(-1, "day"), "gestern"); assertEq(rtf.format(-1, "day"), "gestern");
assertEq(rtf.format(1, "day"), "morgen"); assertEq(rtf.format(1, "day"), "morgen");
rtf = new Intl.RelativeTimeFormat("ar"); rtf = new Intl.RelativeTimeFormat("ar", {type: "text"});
assertEq(rtf.format(-1, "day"), "أمس"); assertEq(rtf.format(-1, "day"), "أمس");
assertEq(rtf.format(1, "day"), "غدًا"); assertEq(rtf.format(1, "day"), "غدًا");