зеркало из https://github.com/mozilla/gecko-dev.git
Bug 837957 - Implement ICU dependent functions of Intl.Collator, Intl.NumberFormat, Intl.DateTimeFormat (part 9). r=jwalden
--HG-- extra : rebase_source : 26a601e1ee905437403c3005d932e6f9fd9dc9c9
This commit is contained in:
Родитель
12cb6e942b
Коммит
7c83e480e3
|
@ -1616,52 +1616,22 @@ function InitializeDateTimeFormat(dateTimeFormat, locales, options) {
|
||||||
opt[prop] = value;
|
opt[prop] = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Step 20.
|
// Steps 20-21 provided by ICU - see comment after this function.
|
||||||
var dataLocaleData = localeData(dataLocale);
|
|
||||||
|
|
||||||
// Step 21.
|
// Step 22.
|
||||||
var formats = dataLocaleData.formats;
|
|
||||||
|
|
||||||
// Steps 22-24.
|
|
||||||
matcher = GetOption(options, "formatMatcher", "string", ["basic", "best fit"], "best fit");
|
matcher = GetOption(options, "formatMatcher", "string", ["basic", "best fit"], "best fit");
|
||||||
var bestFormat = (matcher === "basic")
|
|
||||||
? BasicFormatMatcher(opt, formats)
|
|
||||||
: BestFitFormatMatcher(opt, formats);
|
|
||||||
|
|
||||||
// Step 25.
|
// Steps 23-25 provided by ICU, more or less - see comment after this function.
|
||||||
for (i = 0; i < dateTimeComponents.length; i++) {
|
|
||||||
prop = dateTimeComponents[i];
|
|
||||||
if (callFunction(std_Object_hasOwnProperty, bestFormat, prop)) {
|
|
||||||
var p = bestFormat[prop];
|
|
||||||
internals[prop] = p;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Step 26.
|
// Step 26.
|
||||||
var hr12 = GetOption(options, "hour12", "boolean", undefined, undefined);
|
var hr12 = GetOption(options, "hour12", "boolean", undefined, undefined);
|
||||||
|
|
||||||
// Step 27.
|
// Pass hr12 on to ICU.
|
||||||
var pattern;
|
if (hr12 !== undefined)
|
||||||
if (callFunction(std_Object_hasOwnProperty, internals, "hour")) {
|
opt.hour12 = hr12;
|
||||||
// Steps 27.a-b.
|
|
||||||
if (hr12 === undefined)
|
|
||||||
hr12 = dataLocaleData.hour12;
|
|
||||||
assert(typeof hr12 === "boolean");
|
|
||||||
internals.hour12 = hr12;
|
|
||||||
|
|
||||||
if (hr12) {
|
// Steps 27-28, more or less - see comment after this function.
|
||||||
// Step 27.c.
|
var pattern = toBestICUPattern(dataLocale, opt);
|
||||||
var hourNo0 = dataLocaleData.hourNo0;
|
|
||||||
internals.hourNo0 = hourNo0;
|
|
||||||
pattern = bestFormat.pattern12;
|
|
||||||
} else {
|
|
||||||
// Step 27.d.
|
|
||||||
pattern = bestFormat.pattern;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// Step 28.
|
|
||||||
pattern = bestFormat.pattern;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Step 29.
|
// Step 29.
|
||||||
internals.pattern = pattern;
|
internals.pattern = pattern;
|
||||||
|
@ -1674,6 +1644,182 @@ function InitializeDateTimeFormat(dateTimeFormat, locales, options) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Intl.DateTimeFormat and ICU skeletons and patterns
|
||||||
|
// ==================================================
|
||||||
|
//
|
||||||
|
// Different locales have different ways to display dates using the same
|
||||||
|
// basic components. For example, en-US might use "Sept. 24, 2012" while
|
||||||
|
// fr-FR might use "24 Sept. 2012". The intent of Intl.DateTimeFormat is to
|
||||||
|
// permit production of a format for the locale that best matches the
|
||||||
|
// set of date-time components and their desired representation as specified
|
||||||
|
// by the API client.
|
||||||
|
//
|
||||||
|
// ICU supports specification of date and time formats in three ways:
|
||||||
|
//
|
||||||
|
// 1) A style is just one of the identifiers FULL, LONG, MEDIUM, or SHORT.
|
||||||
|
// The date-time components included in each style and their representation
|
||||||
|
// are defined by ICU using CLDR locale data (CLDR is the Unicode
|
||||||
|
// Consortium's Common Locale Data Repository).
|
||||||
|
//
|
||||||
|
// 2) A skeleton is a string specifying which date-time components to include,
|
||||||
|
// and which representations to use for them. For example, "yyyyMMMMdd"
|
||||||
|
// specifies a year with at least four digits, a full month name, and a
|
||||||
|
// two-digit day. It does not specify in which order the components appear,
|
||||||
|
// how they are separated, the localized strings for textual components
|
||||||
|
// (such as weekday or month), whether the month is in format or
|
||||||
|
// stand-alone form¹, or the numbering system used for numeric components.
|
||||||
|
// All that information is filled in by ICU using CLDR locale data.
|
||||||
|
// ¹ The format form is the one used in formatted strings that include a
|
||||||
|
// day; the stand-alone form is used when not including days, e.g., in
|
||||||
|
// calendar headers. The two forms differ at least in some Slavic languages,
|
||||||
|
// e.g. Russian: "22 марта 2013 г." vs. "Март 2013".
|
||||||
|
//
|
||||||
|
// 3) A pattern is a string specifying which date-time components to include,
|
||||||
|
// in which order, with which separators, in which grammatical case. For
|
||||||
|
// example, "EEEE, d MMMM y" specifies the full localized weekday name,
|
||||||
|
// followed by comma and space, followed by the day, followed by space,
|
||||||
|
// followed by the full month name in format form, followed by space,
|
||||||
|
// followed by the full year. It
|
||||||
|
// still does not specify localized strings for textual components and the
|
||||||
|
// numbering system - these are determined by ICU using CLDR locale data or
|
||||||
|
// possibly API parameters.
|
||||||
|
//
|
||||||
|
// All actual formatting in ICU is done with patterns; styles and skeletons
|
||||||
|
// 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.
|
||||||
|
//
|
||||||
|
// 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]]
|
||||||
|
// When needed for the resolvedOptions method, the resolveICUPattern function
|
||||||
|
// maps the instance's ICU pattern back to the specified properties of the
|
||||||
|
// object returned by resolvedOptions.
|
||||||
|
//
|
||||||
|
// ICU date-time skeletons and patterns aren't fully documented in the ICU
|
||||||
|
// documentation (see http://bugs.icu-project.org/trac/ticket/9627). The best
|
||||||
|
// documentation at this point is in UTR 35:
|
||||||
|
// http://unicode.org/reports/tr35/tr35-dates.html#Date_Format_Patterns
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns an ICU pattern string for the given locale and representing the
|
||||||
|
* specified options as closely as possible given available locale data.
|
||||||
|
*/
|
||||||
|
function toBestICUPattern(locale, options) {
|
||||||
|
// Create an ICU skeleton representing the specified options. See
|
||||||
|
// http://unicode.org/reports/tr35/tr35-dates.html#Date_Field_Symbol_Table
|
||||||
|
var skeleton = "";
|
||||||
|
switch (options.weekday) {
|
||||||
|
case "narrow":
|
||||||
|
skeleton += "EEEEE";
|
||||||
|
break;
|
||||||
|
case "short":
|
||||||
|
skeleton += "E";
|
||||||
|
break;
|
||||||
|
case "long":
|
||||||
|
skeleton += "EEEE";
|
||||||
|
}
|
||||||
|
switch (options.era) {
|
||||||
|
case "narrow":
|
||||||
|
skeleton += "GGGGG";
|
||||||
|
break;
|
||||||
|
case "short":
|
||||||
|
skeleton += "G";
|
||||||
|
break;
|
||||||
|
case "long":
|
||||||
|
skeleton += "GGGG";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
switch (options.year) {
|
||||||
|
case "2-digit":
|
||||||
|
skeleton += "yy";
|
||||||
|
break;
|
||||||
|
case "numeric":
|
||||||
|
skeleton += "y";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
switch (options.month) {
|
||||||
|
case "2-digit":
|
||||||
|
skeleton += "MM";
|
||||||
|
break;
|
||||||
|
case "numeric":
|
||||||
|
skeleton += "M";
|
||||||
|
break;
|
||||||
|
case "narrow":
|
||||||
|
skeleton += "MMMMM";
|
||||||
|
break;
|
||||||
|
case "short":
|
||||||
|
skeleton += "MMM";
|
||||||
|
break;
|
||||||
|
case "long":
|
||||||
|
skeleton += "MMMM";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
switch (options.day) {
|
||||||
|
case "2-digit":
|
||||||
|
skeleton += "dd";
|
||||||
|
break;
|
||||||
|
case "numeric":
|
||||||
|
skeleton += "d";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
var hourSkeletonChar = "j";
|
||||||
|
if (options.hour12 !== undefined) {
|
||||||
|
if (options.hour12)
|
||||||
|
hourSkeletonChar = "h";
|
||||||
|
else
|
||||||
|
hourSkeletonChar = "H";
|
||||||
|
}
|
||||||
|
switch (options.hour) {
|
||||||
|
case "2-digit":
|
||||||
|
skeleton += hourSkeletonChar + hourSkeletonChar;
|
||||||
|
break;
|
||||||
|
case "numeric":
|
||||||
|
skeleton += hourSkeletonChar;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
switch (options.minute) {
|
||||||
|
case "2-digit":
|
||||||
|
skeleton += "mm";
|
||||||
|
break;
|
||||||
|
case "numeric":
|
||||||
|
skeleton += "m";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
switch (options.second) {
|
||||||
|
case "2-digit":
|
||||||
|
skeleton += "ss";
|
||||||
|
break;
|
||||||
|
case "numeric":
|
||||||
|
skeleton += "s";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
switch (options.timeZoneName) {
|
||||||
|
case "short":
|
||||||
|
skeleton += "z";
|
||||||
|
break;
|
||||||
|
case "long":
|
||||||
|
skeleton += "zzzz";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Let ICU convert the ICU skeleton to an ICU pattern for the given locale.
|
||||||
|
return intl_patternForSkeleton(locale, skeleton);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns a new options object that includes the provided options (if any)
|
* Returns a new options object that includes the provided options (if any)
|
||||||
* and fills in default components if required components are not defined.
|
* and fills in default components if required components are not defined.
|
||||||
|
@ -1859,43 +2005,16 @@ function Intl_DateTimeFormat_supportedLocalesOf(locales /*, options*/) {
|
||||||
*/
|
*/
|
||||||
var dateTimeFormatInternalProperties = {
|
var dateTimeFormatInternalProperties = {
|
||||||
localeData: dateTimeFormatLocaleData,
|
localeData: dateTimeFormatLocaleData,
|
||||||
availableLocales: runtimeAvailableLocales, // stub
|
availableLocales: addOldStyleLanguageTags(intl_DateTimeFormat_availableLocales()),
|
||||||
relevantExtensionKeys: ["ca", "nu"]
|
relevantExtensionKeys: ["ca", "nu"]
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
function dateTimeFormatLocaleData(locale) {
|
function dateTimeFormatLocaleData(locale) {
|
||||||
// the following data may or may not match any actual locale support
|
return {
|
||||||
var localeData = {
|
ca: intl_availableCalendars(locale),
|
||||||
ca: ["gregory"],
|
nu: getNumberingSystems(locale)
|
||||||
nu: ["latn"],
|
|
||||||
hour12: false,
|
|
||||||
hourNo0: false
|
|
||||||
};
|
};
|
||||||
|
|
||||||
var formatDate = {
|
|
||||||
weekday: "short",
|
|
||||||
year: "numeric",
|
|
||||||
month: "short",
|
|
||||||
day: "numeric"
|
|
||||||
};
|
|
||||||
var formatTime = {
|
|
||||||
hour: "numeric",
|
|
||||||
minute: "numeric",
|
|
||||||
second: "numeric"
|
|
||||||
};
|
|
||||||
var formatFull = {
|
|
||||||
weekday: "short",
|
|
||||||
year: "numeric",
|
|
||||||
month: "short",
|
|
||||||
day: "numeric",
|
|
||||||
hour: "numeric",
|
|
||||||
minute: "numeric",
|
|
||||||
second: "numeric"
|
|
||||||
};
|
|
||||||
localeData.formats = [formatDate, formatTime, formatFull];
|
|
||||||
|
|
||||||
return localeData;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -1910,7 +2029,7 @@ function dateTimeFormatFormatToBind() {
|
||||||
var x = (date === undefined) ? std_Date_now() : ToNumber(date);
|
var x = (date === undefined) ? std_Date_now() : ToNumber(date);
|
||||||
|
|
||||||
// Step 1.a.iii.
|
// Step 1.a.iii.
|
||||||
return FormatDateTime(this, x);
|
return intl_FormatDateTime(this, x);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -1940,35 +2059,6 @@ function Intl_DateTimeFormat_format_get() {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns a String value representing the result of calling ToNumber(date)
|
|
||||||
* according to the effective locale and the formatting options of this
|
|
||||||
* DateTimeFormat.
|
|
||||||
*
|
|
||||||
* Spec: ECMAScript Internationalization API Specification, 12.3.2.
|
|
||||||
*/
|
|
||||||
function FormatDateTime(dateTimeFormat, x) {
|
|
||||||
// ??? stub
|
|
||||||
if (!std_isFinite(x))
|
|
||||||
ThrowError(JSMSG_DATE_NOT_FINITE);
|
|
||||||
var X = new Std_Date(x);
|
|
||||||
var internals = getInternals(dateTimeFormat);
|
|
||||||
var wantDate = callFunction(std_Object_hasOwnProperty, internals, "weekday") ||
|
|
||||||
callFunction(std_Object_hasOwnProperty, internals, "year") ||
|
|
||||||
callFunction(std_Object_hasOwnProperty, internals, "month") ||
|
|
||||||
callFunction(std_Object_hasOwnProperty, internals, "day");
|
|
||||||
var wantTime = callFunction(std_Object_hasOwnProperty, internals, "hour") ||
|
|
||||||
callFunction(std_Object_hasOwnProperty, internals, "minute") ||
|
|
||||||
callFunction(std_Object_hasOwnProperty, internals, "second");
|
|
||||||
if (wantDate) {
|
|
||||||
if (wantTime)
|
|
||||||
return X.toLocaleString();
|
|
||||||
return X.toLocaleDateString();
|
|
||||||
}
|
|
||||||
return X.toLocaleTimeString();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the resolved options for a DateTimeFormat object.
|
* Returns the resolved options for a DateTimeFormat object.
|
||||||
*
|
*
|
||||||
|
@ -1984,12 +2074,107 @@ function Intl_DateTimeFormat_resolvedOptions() {
|
||||||
numberingSystem: internals.numberingSystem,
|
numberingSystem: internals.numberingSystem,
|
||||||
timeZone: internals.timeZone
|
timeZone: internals.timeZone
|
||||||
};
|
};
|
||||||
for (var i = 0; i < dateTimeComponents.length; i++) {
|
resolveICUPattern(internals.pattern, result);
|
||||||
var p = dateTimeComponents[i];
|
|
||||||
if (callFunction(std_Object_hasOwnProperty, internals, p))
|
|
||||||
defineProperty(result, p, internals[p]);
|
|
||||||
}
|
|
||||||
if (callFunction(std_Object_hasOwnProperty, internals, "hour12"))
|
|
||||||
defineProperty(result, "hour12", internals.hour12);
|
|
||||||
return 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
|
||||||
|
var icuPatternCharToComponent = {
|
||||||
|
E: "weekday",
|
||||||
|
G: "era",
|
||||||
|
y: "year",
|
||||||
|
M: "month",
|
||||||
|
L: "month",
|
||||||
|
d: "day",
|
||||||
|
h: "hour",
|
||||||
|
H: "hour",
|
||||||
|
k: "hour",
|
||||||
|
K: "hour",
|
||||||
|
m: "minute",
|
||||||
|
s: "second",
|
||||||
|
z: "timeZoneName",
|
||||||
|
v: "timeZoneName",
|
||||||
|
V: "timeZoneName"
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Maps an ICU pattern string to a corresponding set of date-time components
|
||||||
|
* and their values, and adds properties for these components to the result
|
||||||
|
* object, which will be returned by the resolvedOptions method. For the
|
||||||
|
* interpretation of ICU pattern characters, see
|
||||||
|
* http://unicode.org/reports/tr35/tr35-dates.html#Date_Field_Symbol_Table
|
||||||
|
*/
|
||||||
|
function resolveICUPattern(pattern, result) {
|
||||||
|
assert(IsObject(result), "resolveICUPattern");
|
||||||
|
var i = 0;
|
||||||
|
while (i < pattern.length) {
|
||||||
|
var c = pattern[i++];
|
||||||
|
if (c === "'") {
|
||||||
|
while (i < pattern.length && pattern[i] !== "'")
|
||||||
|
i++;
|
||||||
|
i++;
|
||||||
|
} else {
|
||||||
|
var count = 1;
|
||||||
|
while (i < pattern.length && pattern[i] === c) {
|
||||||
|
i++;
|
||||||
|
count++;
|
||||||
|
}
|
||||||
|
var value;
|
||||||
|
switch (c) {
|
||||||
|
// "text" cases
|
||||||
|
case "G":
|
||||||
|
case "E":
|
||||||
|
case "z":
|
||||||
|
case "v":
|
||||||
|
case "V":
|
||||||
|
if (count <= 3)
|
||||||
|
value = "short";
|
||||||
|
else if (count === 4)
|
||||||
|
value = "long";
|
||||||
|
else
|
||||||
|
value = "narrow";
|
||||||
|
break;
|
||||||
|
// "number" cases
|
||||||
|
case "y":
|
||||||
|
case "d":
|
||||||
|
case "h":
|
||||||
|
case "H":
|
||||||
|
case "m":
|
||||||
|
case "s":
|
||||||
|
case "k":
|
||||||
|
case "K":
|
||||||
|
if (count === 2)
|
||||||
|
value = "2-digit";
|
||||||
|
else
|
||||||
|
value = "numeric";
|
||||||
|
break;
|
||||||
|
// "text & number" cases
|
||||||
|
case "M":
|
||||||
|
case "L":
|
||||||
|
if (count === 1)
|
||||||
|
value = "numeric";
|
||||||
|
else if (count === 2)
|
||||||
|
value = "2-digit";
|
||||||
|
else if (count === 3)
|
||||||
|
value = "short";
|
||||||
|
else if (count === 4)
|
||||||
|
value = "long";
|
||||||
|
else
|
||||||
|
value = "narrow";
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
// skip other pattern characters and literal text
|
||||||
|
}
|
||||||
|
if (callFunction(std_Object_hasOwnProperty, icuPatternCharToComponent, c))
|
||||||
|
defineProperty(result, icuPatternCharToComponent[c], value);
|
||||||
|
if (c === "h" || c === "K")
|
||||||
|
defineProperty(result, "hour12", true);
|
||||||
|
else if (c === "H" || c === "k")
|
||||||
|
defineProperty(result, "hour12", false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
Загрузка…
Ссылка в новой задаче