| Index: src/js/i18n.js
|
| diff --git a/src/js/i18n.js b/src/js/i18n.js
|
| index 803f55054de5c6673165f6965ba06f7f352496a7..15e87dfa7c1f26f1f6cf167e0221dd50ccd3f95c 100644
|
| --- a/src/js/i18n.js
|
| +++ b/src/js/i18n.js
|
| @@ -23,6 +23,7 @@ var GlobalDate = global.Date;
|
| var GlobalNumber = global.Number;
|
| var GlobalRegExp = global.RegExp;
|
| var GlobalString = global.String;
|
| +var IntlFallbackSymbol = utils.ImportNow("intl_fallback_symbol");
|
| var InstallFunctions = utils.InstallFunctions;
|
| var InstallGetter = utils.InstallGetter;
|
| var InternalArray = utils.InternalArray;
|
| @@ -57,7 +58,8 @@ function InstallConstructor(object, name, func) {
|
| /**
|
| * Adds bound method to the prototype of the given object.
|
| */
|
| -function AddBoundMethod(obj, methodName, implementation, length, type) {
|
| +function AddBoundMethod(obj, methodName, implementation, length, typename,
|
| + compat) {
|
| %CheckIsBootstrapping();
|
| var internalName = %CreatePrivateSymbol(methodName);
|
| // Making getter an anonymous function will cause
|
| @@ -66,32 +68,30 @@ function AddBoundMethod(obj, methodName, implementation, length, type) {
|
| // than (as utils.InstallGetter would) on the SharedFunctionInfo
|
| // associated with all functions returned from AddBoundMethod.
|
| var getter = ANONYMOUS_FUNCTION(function() {
|
| - if (!%IsInitializedIntlObjectOfType(this, type)) {
|
| - throw %make_type_error(kMethodCalledOnWrongObject, methodName);
|
| - }
|
| - if (IS_UNDEFINED(this[internalName])) {
|
| + var receiver = Unwrap(this, typename, obj, methodName, compat);
|
| + if (IS_UNDEFINED(receiver[internalName])) {
|
| var boundMethod;
|
| if (IS_UNDEFINED(length) || length === 2) {
|
| boundMethod =
|
| - ANONYMOUS_FUNCTION((fst, snd) => implementation(this, fst, snd));
|
| + ANONYMOUS_FUNCTION((fst, snd) => implementation(receiver, fst, snd));
|
| } else if (length === 1) {
|
| - boundMethod = ANONYMOUS_FUNCTION(fst => implementation(this, fst));
|
| + boundMethod = ANONYMOUS_FUNCTION(fst => implementation(receiver, fst));
|
| } else {
|
| boundMethod = ANONYMOUS_FUNCTION((...args) => {
|
| // DateTimeFormat.format needs to be 0 arg method, but can still
|
| // receive an optional dateValue param. If one was provided, pass it
|
| // along.
|
| if (args.length > 0) {
|
| - return implementation(this, args[0]);
|
| + return implementation(receiver, args[0]);
|
| } else {
|
| - return implementation(this);
|
| + return implementation(receiver);
|
| }
|
| });
|
| }
|
| %SetNativeFlag(boundMethod);
|
| - this[internalName] = boundMethod;
|
| + receiver[internalName] = boundMethod;
|
| }
|
| - return this[internalName];
|
| + return receiver[internalName];
|
| });
|
|
|
| %FunctionRemovePrototype(getter);
|
| @@ -99,6 +99,43 @@ function AddBoundMethod(obj, methodName, implementation, length, type) {
|
| %SetNativeFlag(getter);
|
| }
|
|
|
| +function IntlConstruct(receiver, constructor, initializer, newTarget, args,
|
| + compat) {
|
| + var locales = args[0];
|
| + var options = args[1];
|
| +
|
| + if (IS_UNDEFINED(newTarget)) {
|
| + if (compat && receiver instanceof constructor) {
|
| + let success = %object_define_property(receiver, IntlFallbackSymbol,
|
| + { value: new constructor(locales, options) });
|
| + if (!success) {
|
| + throw %make_type_error(kReinitializeIntl, constructor);
|
| + }
|
| + return receiver;
|
| + }
|
| +
|
| + return new constructor(locales, options);
|
| + }
|
| +
|
| + return initializer(receiver, locales, options);
|
| +}
|
| +
|
| +
|
| +
|
| +function Unwrap(receiver, typename, constructor, method, compat) {
|
| + if (!%IsInitializedIntlObjectOfType(receiver, typename)) {
|
| + if (compat && receiver instanceof constructor) {
|
| + let fallback = receiver[IntlFallbackSymbol];
|
| + if (%IsInitializedIntlObjectOfType(fallback, typename)) {
|
| + return fallback;
|
| + }
|
| + }
|
| + throw %make_type_error(kIncompatibleMethodReceiver, method, receiver);
|
| + }
|
| + return receiver;
|
| +}
|
| +
|
| +
|
| // -------------------------------------------------------------------
|
|
|
| var Intl = {};
|
| @@ -1029,29 +1066,18 @@ function initializeCollator(collator, locales, options) {
|
| *
|
| * @constructor
|
| */
|
| -InstallConstructor(Intl, 'Collator', function() {
|
| - var locales = arguments[0];
|
| - var options = arguments[1];
|
| -
|
| - if (!this || this === Intl) {
|
| - // Constructor is called as a function.
|
| - return new Intl.Collator(locales, options);
|
| - }
|
| -
|
| - return initializeCollator(TO_OBJECT(this), locales, options);
|
| - }
|
| -);
|
| +function Collator() {
|
| + return IntlConstruct(this, Collator, initializeCollator, new.target,
|
| + arguments);
|
| +}
|
| +InstallConstructor(Intl, 'Collator', Collator);
|
|
|
|
|
| /**
|
| * Collator resolvedOptions method.
|
| */
|
| InstallFunction(Intl.Collator.prototype, 'resolvedOptions', function() {
|
| - if (!%IsInitializedIntlObjectOfType(this, 'collator')) {
|
| - throw %make_type_error(kResolvedOptionsCalledOnNonObject, "Collator");
|
| - }
|
| -
|
| - var coll = this;
|
| + var coll = Unwrap(this, 'collator', Collator, 'resolvedOptions', false);
|
| var locale = getOptimalLanguageTag(coll[resolvedSymbol].requestedLocale,
|
| coll[resolvedSymbol].locale);
|
|
|
| @@ -1096,7 +1122,7 @@ function compare(collator, x, y) {
|
| };
|
|
|
|
|
| -AddBoundMethod(Intl.Collator, 'compare', compare, 2, 'collator');
|
| +AddBoundMethod(Intl.Collator, 'compare', compare, 2, 'collator', false);
|
|
|
| /**
|
| * Verifies that the input is a well-formed ISO 4217 currency code.
|
| @@ -1262,29 +1288,19 @@ function initializeNumberFormat(numberFormat, locales, options) {
|
| *
|
| * @constructor
|
| */
|
| -InstallConstructor(Intl, 'NumberFormat', function() {
|
| - var locales = arguments[0];
|
| - var options = arguments[1];
|
| -
|
| - if (!this || this === Intl) {
|
| - // Constructor is called as a function.
|
| - return new Intl.NumberFormat(locales, options);
|
| - }
|
| -
|
| - return initializeNumberFormat(TO_OBJECT(this), locales, options);
|
| - }
|
| -);
|
| +function NumberFormat() {
|
| + return IntlConstruct(this, NumberFormat, initializeNumberFormat, new.target,
|
| + arguments, true);
|
| +}
|
| +InstallConstructor(Intl, 'NumberFormat', NumberFormat);
|
|
|
|
|
| /**
|
| * NumberFormat resolvedOptions method.
|
| */
|
| InstallFunction(Intl.NumberFormat.prototype, 'resolvedOptions', function() {
|
| - if (!%IsInitializedIntlObjectOfType(this, 'numberformat')) {
|
| - throw %make_type_error(kResolvedOptionsCalledOnNonObject, "NumberFormat");
|
| - }
|
| -
|
| - var format = this;
|
| + var format = Unwrap(this, 'numberformat', NumberFormat,
|
| + 'resolvedOptions', true);
|
| var locale = getOptimalLanguageTag(format[resolvedSymbol].requestedLocale,
|
| format[resolvedSymbol].locale);
|
|
|
| @@ -1345,7 +1361,8 @@ function formatNumber(formatter, value) {
|
| }
|
|
|
|
|
| -AddBoundMethod(Intl.NumberFormat, 'format', formatNumber, 1, 'numberformat');
|
| +AddBoundMethod(Intl.NumberFormat, 'format', formatNumber, 1, 'numberformat',
|
| + true);
|
|
|
| /**
|
| * Returns a string that matches LDML representation of the options object.
|
| @@ -1638,27 +1655,19 @@ function initializeDateTimeFormat(dateFormat, locales, options) {
|
| *
|
| * @constructor
|
| */
|
| -InstallConstructor(Intl, 'DateTimeFormat', function() {
|
| - var locales = arguments[0];
|
| - var options = arguments[1];
|
| -
|
| - if (!this || this === Intl) {
|
| - // Constructor is called as a function.
|
| - return new Intl.DateTimeFormat(locales, options);
|
| - }
|
| -
|
| - return initializeDateTimeFormat(TO_OBJECT(this), locales, options);
|
| - }
|
| -);
|
| +function DateTimeFormat() {
|
| + return IntlConstruct(this, DateTimeFormat, initializeDateTimeFormat,
|
| + new.target, arguments, true);
|
| +}
|
| +InstallConstructor(Intl, 'DateTimeFormat', DateTimeFormat);
|
|
|
|
|
| /**
|
| * DateTimeFormat resolvedOptions method.
|
| */
|
| InstallFunction(Intl.DateTimeFormat.prototype, 'resolvedOptions', function() {
|
| - if (!%IsInitializedIntlObjectOfType(this, 'dateformat')) {
|
| - throw %make_type_error(kResolvedOptionsCalledOnNonObject, "DateTimeFormat");
|
| - }
|
| + var format = Unwrap(this, 'dateformat', DateTimeFormat,
|
| + 'resolvedOptions', true);
|
|
|
| /**
|
| * Maps ICU calendar names to LDML/BCP47 types for key 'ca'.
|
| @@ -1671,7 +1680,6 @@ InstallFunction(Intl.DateTimeFormat.prototype, 'resolvedOptions', function() {
|
| 'ethiopic-amete-alem': 'ethioaa'
|
| };
|
|
|
| - var format = this;
|
| var fromPattern = fromLDMLString(format[resolvedSymbol][patternSymbol]);
|
| var userCalendar = ICU_CALENDAR_MAP[format[resolvedSymbol].calendar];
|
| if (IS_UNDEFINED(userCalendar)) {
|
| @@ -1758,7 +1766,8 @@ function FormatDateToParts(dateValue) {
|
|
|
|
|
| // 0 because date is optional argument.
|
| -AddBoundMethod(Intl.DateTimeFormat, 'format', formatDate, 0, 'dateformat');
|
| +AddBoundMethod(Intl.DateTimeFormat, 'format', formatDate, 0, 'dateformat',
|
| + true);
|
|
|
|
|
| /**
|
| @@ -1847,18 +1856,11 @@ function initializeBreakIterator(iterator, locales, options) {
|
| *
|
| * @constructor
|
| */
|
| -InstallConstructor(Intl, 'v8BreakIterator', function() {
|
| - var locales = arguments[0];
|
| - var options = arguments[1];
|
| -
|
| - if (!this || this === Intl) {
|
| - // Constructor is called as a function.
|
| - return new Intl.v8BreakIterator(locales, options);
|
| - }
|
| -
|
| - return initializeBreakIterator(TO_OBJECT(this), locales, options);
|
| - }
|
| -);
|
| +function v8BreakIterator() {
|
| + return IntlConstruct(this, v8BreakIterator, initializeBreakIterator,
|
| + new.target, arguments);
|
| +}
|
| +InstallConstructor(Intl, 'v8BreakIterator', v8BreakIterator);
|
|
|
|
|
| /**
|
| @@ -1870,11 +1872,9 @@ InstallFunction(Intl.v8BreakIterator.prototype, 'resolvedOptions',
|
| throw %make_type_error(kOrdinaryFunctionCalledAsConstructor);
|
| }
|
|
|
| - if (!%IsInitializedIntlObjectOfType(this, 'breakiterator')) {
|
| - throw %make_type_error(kResolvedOptionsCalledOnNonObject, "v8BreakIterator");
|
| - }
|
| + var segmenter = Unwrap(this, 'breakiterator', v8BreakIterator,
|
| + 'resolvedOptions', false);
|
|
|
| - var segmenter = this;
|
| var locale =
|
| getOptimalLanguageTag(segmenter[resolvedSymbol].requestedLocale,
|
| segmenter[resolvedSymbol].locale);
|
|
|