mirror of
https://repo.dactyloidae.xyz/Dactyloidae/UXP.git
synced 2026-10-26 17:17:31 +09:00
Issue #2195 - Add support for hourCycle to Intl.DateTimeFormat
Based-on: m-c 1386146, 1430809
This commit is contained in:
parent
e923c48f4f
commit
cf7bd82328
1 changed files with 140 additions and 37 deletions
|
|
@ -21,6 +21,8 @@ function resolveDateTimeFormatInternals(lazyDateTimeFormatData) {
|
||||||
// localeMatcher: "lookup" / "best fit",
|
// localeMatcher: "lookup" / "best fit",
|
||||||
//
|
//
|
||||||
// hour12: true / false, // optional
|
// hour12: true / false, // optional
|
||||||
|
//
|
||||||
|
// hourCycle: "h11" / "h12" / "h23" / "h24", // optional
|
||||||
// }
|
// }
|
||||||
//
|
//
|
||||||
// timeZone: IANA time zone name,
|
// timeZone: IANA time zone name,
|
||||||
|
|
@ -53,40 +55,41 @@ function resolveDateTimeFormatInternals(lazyDateTimeFormatData) {
|
||||||
var internalProps = std_Object_create(null);
|
var internalProps = std_Object_create(null);
|
||||||
|
|
||||||
// Compute effective locale.
|
// Compute effective locale.
|
||||||
// Step 8.
|
|
||||||
var DateTimeFormat = dateTimeFormatInternalProperties;
|
var DateTimeFormat = dateTimeFormatInternalProperties;
|
||||||
|
|
||||||
// Step 9.
|
// Step 10.
|
||||||
var localeData = DateTimeFormat.localeData;
|
var localeData = DateTimeFormat.localeData;
|
||||||
|
|
||||||
// Step 10.
|
// Step 11.
|
||||||
var r = ResolveLocale(callFunction(DateTimeFormat.availableLocales, DateTimeFormat),
|
var r = ResolveLocale(callFunction(DateTimeFormat.availableLocales, DateTimeFormat),
|
||||||
lazyDateTimeFormatData.requestedLocales,
|
lazyDateTimeFormatData.requestedLocales,
|
||||||
lazyDateTimeFormatData.localeOpt,
|
lazyDateTimeFormatData.localeOpt,
|
||||||
DateTimeFormat.relevantExtensionKeys,
|
DateTimeFormat.relevantExtensionKeys,
|
||||||
localeData);
|
localeData);
|
||||||
|
|
||||||
// Steps 11-13.
|
// Steps 12-13, 15.
|
||||||
internalProps.locale = r.locale;
|
internalProps.locale = r.locale;
|
||||||
internalProps.calendar = r.ca;
|
internalProps.calendar = r.ca;
|
||||||
internalProps.numberingSystem = r.nu;
|
internalProps.numberingSystem = r.nu;
|
||||||
|
|
||||||
// Compute formatting options.
|
// Compute formatting options.
|
||||||
// Step 14.
|
// Step 16.
|
||||||
var dataLocale = r.dataLocale;
|
var dataLocale = r.dataLocale;
|
||||||
|
|
||||||
// Steps 15-17.
|
// Steps 20.
|
||||||
var tz = lazyDateTimeFormatData.timeZone;
|
internalProps.timeZone = lazyDateTimeFormatData.timeZone;
|
||||||
if (tz === undefined) {
|
|
||||||
// Step 16.
|
|
||||||
tz = DefaultTimeZone();
|
|
||||||
}
|
|
||||||
internalProps.timeZone = tz;
|
|
||||||
|
|
||||||
// Step 18.
|
// Step 21.
|
||||||
var formatOpt = lazyDateTimeFormatData.formatOpt;
|
var formatOpt = lazyDateTimeFormatData.formatOpt;
|
||||||
|
|
||||||
// Steps 27-28, more or less - see comment after this function.
|
// Step 16.
|
||||||
|
// Copy the hourCycle setting, if present, to the format options. But
|
||||||
|
// only do this if no hour12 option is present, because the latter takes
|
||||||
|
// precedence over hourCycle.
|
||||||
|
if (r.hc !== null && formatOpt.hour12 === undefined)
|
||||||
|
formatOpt.hourCycle = r.hc;
|
||||||
|
|
||||||
|
// Steps 26-30, more or less - see comment after this function.
|
||||||
var pattern;
|
var pattern;
|
||||||
if (lazyDateTimeFormatData.mozExtensions) {
|
if (lazyDateTimeFormatData.mozExtensions) {
|
||||||
if (lazyDateTimeFormatData.patternOption !== undefined) {
|
if (lazyDateTimeFormatData.patternOption !== undefined) {
|
||||||
|
|
@ -108,10 +111,14 @@ function resolveDateTimeFormatInternals(lazyDateTimeFormatData) {
|
||||||
pattern = toBestICUPattern(dataLocale, formatOpt);
|
pattern = toBestICUPattern(dataLocale, formatOpt);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Step 29.
|
// If the hourCycle option was set, adjust the resolved pattern to use the
|
||||||
|
// requested hour cycle representation.
|
||||||
|
if (formatOpt.hourCycle !== undefined)
|
||||||
|
pattern = replaceHourRepresentation(pattern, formatOpt.hourCycle);
|
||||||
|
|
||||||
|
// Step 31.
|
||||||
internalProps.pattern = pattern;
|
internalProps.pattern = pattern;
|
||||||
|
|
||||||
// Step 30.
|
|
||||||
internalProps.boundFormat = undefined;
|
internalProps.boundFormat = undefined;
|
||||||
|
|
||||||
// The caller is responsible for associating |internalProps| with the right
|
// The caller is responsible for associating |internalProps| with the right
|
||||||
|
|
@ -120,6 +127,47 @@ function resolveDateTimeFormatInternals(lazyDateTimeFormatData) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Replaces all hour pattern characters in |pattern| to use the matching hour
|
||||||
|
* representation for |hourCycle|.
|
||||||
|
*/
|
||||||
|
function replaceHourRepresentation(pattern, hourCycle) {
|
||||||
|
var hour;
|
||||||
|
switch (hourCycle) {
|
||||||
|
case "h11":
|
||||||
|
hour = "K";
|
||||||
|
break;
|
||||||
|
case "h12":
|
||||||
|
hour = "h";
|
||||||
|
break;
|
||||||
|
case "h23":
|
||||||
|
hour = "H";
|
||||||
|
break;
|
||||||
|
case "h24":
|
||||||
|
hour = "k";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
assert(hour !== undefined, "Unexpected hourCycle requested: " + hourCycle);
|
||||||
|
|
||||||
|
// Parse the pattern according to the format specified in
|
||||||
|
// https://unicode.org/reports/tr35/tr35-dates.html#Date_Format_Patterns
|
||||||
|
// and replace all hour symbols with |hour|.
|
||||||
|
var resultPattern = "";
|
||||||
|
var inQuote = false;
|
||||||
|
for (var i = 0; i < pattern.length; i++) {
|
||||||
|
var ch = pattern[i];
|
||||||
|
if (ch === "'") {
|
||||||
|
inQuote = !inQuote;
|
||||||
|
} else if (!inQuote && (ch === "h" || ch === "H" || ch === "k" || ch === "K")) {
|
||||||
|
ch = hour;
|
||||||
|
}
|
||||||
|
resultPattern += ch;
|
||||||
|
}
|
||||||
|
|
||||||
|
return resultPattern;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns an object containing the DateTimeFormat internal properties of |obj|.
|
* Returns an object containing the DateTimeFormat internal properties of |obj|.
|
||||||
*/
|
*/
|
||||||
|
|
@ -306,7 +354,8 @@ function InitializeDateTimeFormat(dateTimeFormat, thisValue, locales, options, m
|
||||||
// // all the properties/values listed in Table 3
|
// // all the properties/values listed in Table 3
|
||||||
// // (weekday, era, year, month, day, &c.)
|
// // (weekday, era, year, month, day, &c.)
|
||||||
//
|
//
|
||||||
// hour12: true / false // optional
|
// hour12: true / false, // optional
|
||||||
|
// hourCycle: "h11" / "h12" / "h23" / "h24", // optional
|
||||||
// }
|
// }
|
||||||
//
|
//
|
||||||
// formatMatcher: "basic" / "best fit",
|
// formatMatcher: "basic" / "best fit",
|
||||||
|
|
@ -317,41 +366,61 @@ function InitializeDateTimeFormat(dateTimeFormat, thisValue, locales, options, m
|
||||||
// never a subset of them.
|
// never a subset of them.
|
||||||
var lazyDateTimeFormatData = std_Object_create(null);
|
var lazyDateTimeFormatData = std_Object_create(null);
|
||||||
|
|
||||||
// Step 3.
|
// Step 1.
|
||||||
var requestedLocales = CanonicalizeLocaleList(locales);
|
var requestedLocales = CanonicalizeLocaleList(locales);
|
||||||
lazyDateTimeFormatData.requestedLocales = requestedLocales;
|
lazyDateTimeFormatData.requestedLocales = requestedLocales;
|
||||||
|
|
||||||
// Step 4.
|
// Step24.
|
||||||
options = ToDateTimeOptions(options, "any", "date");
|
options = ToDateTimeOptions(options, "any", "date");
|
||||||
|
|
||||||
// Compute options that impact interpretation of locale.
|
// Compute options that impact interpretation of locale.
|
||||||
// Step 5.
|
// Step 3.
|
||||||
var localeOpt = new Record();
|
var localeOpt = new Record();
|
||||||
lazyDateTimeFormatData.localeOpt = localeOpt;
|
lazyDateTimeFormatData.localeOpt = localeOpt;
|
||||||
|
|
||||||
// Steps 6-7.
|
// Steps 4-5.
|
||||||
var localeMatcher =
|
var localeMatcher =
|
||||||
GetOption(options, "localeMatcher", "string", ["lookup", "best fit"],
|
GetOption(options, "localeMatcher", "string", ["lookup", "best fit"],
|
||||||
"best fit");
|
"best fit");
|
||||||
localeOpt.localeMatcher = localeMatcher;
|
localeOpt.localeMatcher = localeMatcher;
|
||||||
|
|
||||||
// Steps 15-17.
|
// Step 6.
|
||||||
|
var hr12 = GetOption(options, "hour12", "boolean", undefined, undefined);
|
||||||
|
|
||||||
|
// Step 7.
|
||||||
|
var hc = GetOption(options, "hourCycle", "string", ["h11", "h12", "h23", "h24"], undefined);
|
||||||
|
|
||||||
|
// Step 8.
|
||||||
|
if (hr12 !== undefined) {
|
||||||
|
// The "hourCycle" option is ignored if "hr12" is also present.
|
||||||
|
hc = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Step 9.
|
||||||
|
localeOpt.hc = hc;
|
||||||
|
|
||||||
|
// Steps 10-16 (see resolveDateTimeFormatInternals).
|
||||||
|
|
||||||
|
// Steps 17-20.
|
||||||
var tz = options.timeZone;
|
var tz = options.timeZone;
|
||||||
if (tz !== undefined) {
|
if (tz !== undefined) {
|
||||||
// Step 15.a.
|
// Step 18.a.
|
||||||
tz = ToString(tz);
|
tz = ToString(tz);
|
||||||
|
|
||||||
// Step 15.b.
|
// Step 18.b.
|
||||||
var timeZone = intl_IsValidTimeZoneName(tz);
|
var timeZone = intl_IsValidTimeZoneName(tz);
|
||||||
if (timeZone === null)
|
if (timeZone === null)
|
||||||
ThrowRangeError(JSMSG_INVALID_TIME_ZONE, tz);
|
ThrowRangeError(JSMSG_INVALID_TIME_ZONE, tz);
|
||||||
|
|
||||||
// Step 15.c.
|
// Step 18.c.
|
||||||
tz = CanonicalizeTimeZoneName(timeZone);
|
tz = CanonicalizeTimeZoneName(timeZone);
|
||||||
|
} else {
|
||||||
|
// Step 19.
|
||||||
|
tz = DefaultTimeZone();
|
||||||
}
|
}
|
||||||
lazyDateTimeFormatData.timeZone = tz;
|
lazyDateTimeFormatData.timeZone = tz;
|
||||||
|
|
||||||
// Step 18.
|
// Step 21.
|
||||||
var formatOpt = new Record();
|
var formatOpt = new Record();
|
||||||
lazyDateTimeFormatData.formatOpt = formatOpt;
|
lazyDateTimeFormatData.formatOpt = formatOpt;
|
||||||
|
|
||||||
|
|
@ -367,7 +436,8 @@ function InitializeDateTimeFormat(dateTimeFormat, thisValue, locales, options, m
|
||||||
lazyDateTimeFormatData.timeStyle = timeStyle;
|
lazyDateTimeFormatData.timeStyle = timeStyle;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Step 19.
|
// Step 22.
|
||||||
|
// 12.1, Table 5: Components of date and time formats.
|
||||||
var i, prop;
|
var i, prop;
|
||||||
for (i = 0; i < dateTimeComponents.length; i++) {
|
for (i = 0; i < dateTimeComponents.length; i++) {
|
||||||
prop = dateTimeComponents[i];
|
prop = dateTimeComponents[i];
|
||||||
|
|
@ -375,9 +445,9 @@ function InitializeDateTimeFormat(dateTimeFormat, thisValue, locales, options, m
|
||||||
formatOpt[prop] = value;
|
formatOpt[prop] = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Steps 20-21 provided by ICU - see comment after this function.
|
// Steps 23-24 provided by ICU - see comment after this function.
|
||||||
|
|
||||||
// Step 22.
|
// Step 25.
|
||||||
//
|
//
|
||||||
// For some reason (ICU not exposing enough interface?) we drop the
|
// For some reason (ICU not exposing enough interface?) we drop the
|
||||||
// requested format matcher on the floor after this. In any case, even if
|
// requested format matcher on the floor after this. In any case, even if
|
||||||
|
|
@ -387,21 +457,20 @@ function InitializeDateTimeFormat(dateTimeFormat, thisValue, locales, options, m
|
||||||
GetOption(options, "formatMatcher", "string", ["basic", "best fit"],
|
GetOption(options, "formatMatcher", "string", ["basic", "best fit"],
|
||||||
"best fit");
|
"best fit");
|
||||||
|
|
||||||
// Steps 23-25 provided by ICU, more or less - see comment after this function.
|
// Steps 26-28 provided by ICU, more or less - see comment after this function.
|
||||||
|
|
||||||
// Step 26.
|
|
||||||
var hr12 = GetOption(options, "hour12", "boolean", undefined, undefined);
|
|
||||||
|
|
||||||
|
// Steps 29-30.
|
||||||
// Pass hr12 on to ICU.
|
// Pass hr12 on to ICU.
|
||||||
if (hr12 !== undefined)
|
if (hr12 !== undefined)
|
||||||
formatOpt.hour12 = hr12;
|
formatOpt.hour12 = hr12;
|
||||||
|
|
||||||
// Step 31.
|
// Step 32.
|
||||||
//
|
//
|
||||||
// We've done everything that must be done now: mark the lazy data as fully
|
// We've done everything that must be done now: mark the lazy data as fully
|
||||||
// computed and install it.
|
// computed and install it.
|
||||||
initializeIntlObject(dateTimeFormat, "DateTimeFormat", lazyDateTimeFormatData);
|
initializeIntlObject(dateTimeFormat, "DateTimeFormat", lazyDateTimeFormatData);
|
||||||
|
|
||||||
|
// 12.2.1, steps 4-5.
|
||||||
if (dateTimeFormat !== thisValue && thisValue instanceof GetDateTimeFormatConstructor()) {
|
if (dateTimeFormat !== thisValue && thisValue instanceof GetDateTimeFormatConstructor()) {
|
||||||
if (!IsObject(thisValue))
|
if (!IsObject(thisValue))
|
||||||
ThrowTypeError(JSMSG_NOT_NONNULL_OBJECT, typeof thisValue);
|
ThrowTypeError(JSMSG_NOT_NONNULL_OBJECT, typeof thisValue);
|
||||||
|
|
@ -412,6 +481,7 @@ function InitializeDateTimeFormat(dateTimeFormat, thisValue, locales, options, m
|
||||||
return thisValue;
|
return thisValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 12.2.1, step 6.
|
||||||
return dateTimeFormat;
|
return dateTimeFormat;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -474,6 +544,7 @@ function InitializeDateTimeFormat(dateTimeFormat, thisValue, locales, options, m
|
||||||
// - [[weekday]], [[era]], [[year]], [[month]], [[day]], [[hour]], [[minute]],
|
// - [[weekday]], [[era]], [[year]], [[month]], [[day]], [[hour]], [[minute]],
|
||||||
// [[second]], [[timeZoneName]]
|
// [[second]], [[timeZoneName]]
|
||||||
// - [[hour12]]
|
// - [[hour12]]
|
||||||
|
// - [[hourCycle]]
|
||||||
// - [[hourNo0]]
|
// - [[hourNo0]]
|
||||||
// When needed for the resolvedOptions method, the resolveICUPattern function
|
// When needed for the resolvedOptions method, the resolveICUPattern function
|
||||||
// maps the instance's ICU pattern back to the specified properties of the
|
// maps the instance's ICU pattern back to the specified properties of the
|
||||||
|
|
@ -547,12 +618,24 @@ function toBestICUPattern(locale, options) {
|
||||||
skeleton += "d";
|
skeleton += "d";
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
// If hour12 and hourCycle are both present, hour12 takes precedence.
|
||||||
var hourSkeletonChar = "j";
|
var hourSkeletonChar = "j";
|
||||||
if (options.hour12 !== undefined) {
|
if (options.hour12 !== undefined) {
|
||||||
if (options.hour12)
|
if (options.hour12)
|
||||||
hourSkeletonChar = "h";
|
hourSkeletonChar = "h";
|
||||||
else
|
else
|
||||||
hourSkeletonChar = "H";
|
hourSkeletonChar = "H";
|
||||||
|
} else {
|
||||||
|
switch (options.hourCycle) {
|
||||||
|
case "h11":
|
||||||
|
case "h12":
|
||||||
|
hourSkeletonChar = "h";
|
||||||
|
break;
|
||||||
|
case "h23":
|
||||||
|
case "h24":
|
||||||
|
hourSkeletonChar = "H";
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
switch (options.hour) {
|
switch (options.hour) {
|
||||||
case "2-digit":
|
case "2-digit":
|
||||||
|
|
@ -789,7 +872,7 @@ var dateTimeFormatInternalProperties = {
|
||||||
addSpecialMissingLanguageTags(locales);
|
addSpecialMissingLanguageTags(locales);
|
||||||
return (this._availableLocales = locales);
|
return (this._availableLocales = locales);
|
||||||
},
|
},
|
||||||
relevantExtensionKeys: ["ca", "nu"]
|
relevantExtensionKeys: ["ca", "nu", "hc"]
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -797,9 +880,15 @@ function dateTimeFormatLocaleData() {
|
||||||
return {
|
return {
|
||||||
ca: intl_availableCalendars,
|
ca: intl_availableCalendars,
|
||||||
nu: getNumberingSystems,
|
nu: getNumberingSystems,
|
||||||
|
hc: () => {
|
||||||
|
return [null, "h11", "h12", "h23", "h24"];
|
||||||
|
},
|
||||||
default: {
|
default: {
|
||||||
ca: intl_defaultCalendar,
|
ca: intl_defaultCalendar,
|
||||||
nu: intl_numberingSystem,
|
nu: intl_numberingSystem,
|
||||||
|
hc: () => {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
@ -988,10 +1077,24 @@ function resolveICUPattern(pattern, result) {
|
||||||
}
|
}
|
||||||
if (hasOwn(c, icuPatternCharToComponent))
|
if (hasOwn(c, icuPatternCharToComponent))
|
||||||
_DefineDataProperty(result, icuPatternCharToComponent[c], value);
|
_DefineDataProperty(result, icuPatternCharToComponent[c], value);
|
||||||
if (c === "h" || c === "K")
|
switch (c) {
|
||||||
|
case "h":
|
||||||
|
_DefineDataProperty(result, "hourCycle", "h12");
|
||||||
_DefineDataProperty(result, "hour12", true);
|
_DefineDataProperty(result, "hour12", true);
|
||||||
else if (c === "H" || c === "k")
|
break;
|
||||||
|
case "K":
|
||||||
|
_DefineDataProperty(result, "hourCycle", "h11");
|
||||||
|
_DefineDataProperty(result, "hour12", true);
|
||||||
|
break;
|
||||||
|
case "H":
|
||||||
|
_DefineDataProperty(result, "hourCycle", "h23");
|
||||||
_DefineDataProperty(result, "hour12", false);
|
_DefineDataProperty(result, "hour12", false);
|
||||||
|
break;
|
||||||
|
case "k":
|
||||||
|
_DefineDataProperty(result, "hourCycle", "h24");
|
||||||
|
_DefineDataProperty(result, "hour12", false);
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue