| Index: src/js/i18n.js
|
| diff --git a/src/js/i18n.js b/src/js/i18n.js
|
| index cbb664b526973beb6bb7df7d1fc256b31a4e511d..78e2fb5492449978c469203b5370aba2d8794bbb 100644
|
| --- a/src/js/i18n.js
|
| +++ b/src/js/i18n.js
|
| @@ -29,6 +29,7 @@ var GlobalDate = global.Date;
|
| var GlobalNumber = global.Number;
|
| var GlobalRegExp = global.RegExp;
|
| var GlobalString = global.String;
|
| +var GlobalSymbol = global.Symbol;
|
| var MakeError;
|
| var MakeRangeError;
|
| var MakeTypeError;
|
| @@ -84,31 +85,31 @@ function InstallConstructor(object, name, func) {
|
| %ToFastProperties(object);
|
| }
|
|
|
| +var fallbackSymbol = GlobalSymbol("intl fallback");
|
| +
|
| /**
|
| * Adds bound method to the prototype of the given object.
|
| */
|
| -function AddBoundMethod(obj, methodName, implementation, length) {
|
| +function AddBoundMethod(obj, methodName, implementation, length, typename, compat) {
|
| %CheckIsBootstrapping();
|
| var internalName = %CreatePrivateSymbol(methodName);
|
| var getter = function() {
|
| - if (!%IsInitializedIntlObject(this)) {
|
| - throw MakeTypeError(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 = (x, y) => implementation(this, x, y);
|
| + boundMethod = (x, y) => implementation(receiver, x, y);
|
| } else if (length === 1) {
|
| - boundMethod = x => implementation(this, x);
|
| + boundMethod = x => implementation(receiver, x);
|
| } else {
|
| boundMethod = (...args) => {
|
| // DateTimeFormat.format needs to be 0 arg method, but can stil
|
| // receive 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);
|
| }
|
| }
|
| }
|
| @@ -118,14 +119,51 @@ function AddBoundMethod(obj, methodName, implementation, length) {
|
| %FunctionSetName(boundMethod, '__bound' + methodName + '__');
|
| %FunctionRemovePrototype(boundMethod);
|
| %SetNativeFlag(boundMethod);
|
| - this[internalName] = boundMethod;
|
| + receiver[internalName] = boundMethod;
|
| }
|
| - return this[internalName];
|
| + return receiver[internalName];
|
| };
|
|
|
| InstallGetter(obj.prototype, methodName, getter, DONT_ENUM);
|
| }
|
|
|
| +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 = ObjectDefineProperty(receiver, fallbackSymbol,
|
| + { value: new constructor(locales, options) });
|
| + if (!success) {
|
| + throw MakeTypeError(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[fallbackSymbol];
|
| + if (%IsInitializedIntlObjectOfType(fallback, typename)) {
|
| + return fallback;
|
| + }
|
| + }
|
| + throw MakeTypeError(kIncompatibleMethodReceiver, method, receiver);
|
| + }
|
| + return receiver;
|
| +}
|
| +
|
| +
|
| // -------------------------------------------------------------------
|
|
|
| var Intl = {};
|
| @@ -1002,18 +1040,11 @@ 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);
|
|
|
|
|
| /**
|
| @@ -1024,11 +1055,7 @@ InstallFunction(Intl.Collator.prototype, 'resolvedOptions', function() {
|
| throw MakeTypeError(kOrdinaryFunctionCalledAsConstructor);
|
| }
|
|
|
| - if (!%IsInitializedIntlObjectOfType(this, 'collator')) {
|
| - throw MakeTypeError(kResolvedOptionsCalledOnNonObject, "Collator");
|
| - }
|
| -
|
| - var coll = this;
|
| + var coll = Unwrap(this, 'collator', Collator, 'resolvedOptions', true);
|
| var locale = getOptimalLanguageTag(coll[resolvedSymbol].requestedLocale,
|
| coll[resolvedSymbol].locale);
|
|
|
| @@ -1077,7 +1104,7 @@ function compare(collator, x, y) {
|
| };
|
|
|
|
|
| -AddBoundMethod(Intl.Collator, 'compare', compare, 2);
|
| +AddBoundMethod(Intl.Collator, 'compare', compare, 2, 'collator', Collator);
|
|
|
| /**
|
| * Verifies that the input is a well-formed ISO 4217 currency code.
|
| @@ -1246,18 +1273,11 @@ 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);
|
|
|
|
|
| /**
|
| @@ -1268,11 +1288,8 @@ InstallFunction(Intl.NumberFormat.prototype, 'resolvedOptions', function() {
|
| throw MakeTypeError(kOrdinaryFunctionCalledAsConstructor);
|
| }
|
|
|
| - if (!%IsInitializedIntlObjectOfType(this, 'numberformat')) {
|
| - throw MakeTypeError(kResolvedOptionsCalledOnNonObject, "NumberFormat");
|
| - }
|
| -
|
| - var format = this;
|
| + var format = Unwrap(this, 'numberformat', NumberFormat,
|
| + 'resolvedOptions', true);
|
| var locale = getOptimalLanguageTag(format[resolvedSymbol].requestedLocale,
|
| format[resolvedSymbol].locale);
|
|
|
| @@ -1346,8 +1363,8 @@ function parseNumber(formatter, value) {
|
| }
|
|
|
|
|
| -AddBoundMethod(Intl.NumberFormat, 'format', formatNumber, 1);
|
| -AddBoundMethod(Intl.NumberFormat, 'v8Parse', parseNumber, 1);
|
| +AddBoundMethod(Intl.NumberFormat, 'format', formatNumber, 1, 'numberformat', true);
|
| +AddBoundMethod(Intl.NumberFormat, 'v8Parse', parseNumber, 1, 'numberformat');
|
|
|
| /**
|
| * Returns a string that matches LDML representation of the options object.
|
| @@ -1640,18 +1657,11 @@ 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);
|
|
|
|
|
| /**
|
| @@ -1662,9 +1672,8 @@ InstallFunction(Intl.DateTimeFormat.prototype, 'resolvedOptions', function() {
|
| throw MakeTypeError(kOrdinaryFunctionCalledAsConstructor);
|
| }
|
|
|
| - if (!%IsInitializedIntlObjectOfType(this, 'dateformat')) {
|
| - throw MakeTypeError(kResolvedOptionsCalledOnNonObject, "DateTimeFormat");
|
| - }
|
| + var format = Unwrap(this, 'dateformat', DateTimeFormat,
|
| + 'resolvedOptions', true);
|
|
|
| /**
|
| * Maps ICU calendar names into LDML type.
|
| @@ -1769,8 +1778,8 @@ function parseDate(formatter, value) {
|
|
|
|
|
| // 0 because date is optional argument.
|
| -AddBoundMethod(Intl.DateTimeFormat, 'format', formatDate, 0);
|
| -AddBoundMethod(Intl.DateTimeFormat, 'v8Parse', parseDate, 1);
|
| +AddBoundMethod(Intl.DateTimeFormat, 'format', formatDate, 0, 'dateformat', true);
|
| +AddBoundMethod(Intl.DateTimeFormat, 'v8Parse', parseDate, 1, 'dateformat');
|
|
|
|
|
| /**
|
| @@ -1857,18 +1866,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);
|
|
|
|
|
| /**
|
| @@ -1880,9 +1882,7 @@ InstallFunction(Intl.v8BreakIterator.prototype, 'resolvedOptions',
|
| throw MakeTypeError(kOrdinaryFunctionCalledAsConstructor);
|
| }
|
|
|
| - if (!%IsInitializedIntlObjectOfType(this, 'breakiterator')) {
|
| - throw MakeTypeError(kResolvedOptionsCalledOnNonObject, "v8BreakIterator");
|
| - }
|
| + var format = Unwrap(this, 'breakiterator', v8BreakIterator, 'resolvedOptions');
|
|
|
| var segmenter = this;
|
| var locale =
|
| @@ -1956,11 +1956,11 @@ function breakType(iterator) {
|
| }
|
|
|
|
|
| -AddBoundMethod(Intl.v8BreakIterator, 'adoptText', adoptText, 1);
|
| -AddBoundMethod(Intl.v8BreakIterator, 'first', first, 0);
|
| -AddBoundMethod(Intl.v8BreakIterator, 'next', next, 0);
|
| -AddBoundMethod(Intl.v8BreakIterator, 'current', current, 0);
|
| -AddBoundMethod(Intl.v8BreakIterator, 'breakType', breakType, 0);
|
| +AddBoundMethod(Intl.v8BreakIterator, 'adoptText', adoptText, 1, 'breakiterator');
|
| +AddBoundMethod(Intl.v8BreakIterator, 'first', first, 0, 'breakiterator');
|
| +AddBoundMethod(Intl.v8BreakIterator, 'next', next, 0, 'breakiterator');
|
| +AddBoundMethod(Intl.v8BreakIterator, 'current', current, 0, 'breakiterator');
|
| +AddBoundMethod(Intl.v8BreakIterator, 'breakType', breakType, 0, 'breakiterator');
|
|
|
| // Save references to Intl objects and methods we use, for added security.
|
| var savedObjects = {
|
|
|