Changeset 206837 in webkit


Ignore:
Timestamp:
Oct 5, 2016 5:07:21 PM (7 years ago)
Author:
commit-queue@webkit.org
Message:

[INTL] Implement Intl.getCanonicalLocales
https://bugs.webkit.org/show_bug.cgi?id=162768

Patch by Andy VanWagoner <thetalecrafter@gmail.com> on 2016-10-05
Reviewed by Benjamin Poulain.

Source/JavaScriptCore:

Implement Intl.getCanonicalLocales from ECMA 402 (3rd edition)
http://ecma-international.org/ecma-402/3.0/index.html#sec-intl.getcanonicallocales

Reuse canonicalizeLocaleList and copy the results into a new JSArray.

  • runtime/IntlObject.cpp:

(JSC::IntlObject::finishCreation):
(JSC::intlObjectFuncGetCanonicalLocales):

LayoutTests:

  • js/intl-expected.txt: Added tests for Intl.getCanonicalLocales
  • js/script-tests/intl.js: Added test for Intl.getCanonicalLocales
Location:
trunk
Files:
5 edited

Legend:

Unmodified
Added
Removed
  • trunk/LayoutTests/ChangeLog

    r206835 r206837  
     12016-10-05  Andy VanWagoner  <thetalecrafter@gmail.com>
     2
     3        [INTL] Implement Intl.getCanonicalLocales
     4        https://bugs.webkit.org/show_bug.cgi?id=162768
     5
     6        Reviewed by Benjamin Poulain.
     7
     8        * js/intl-expected.txt: Added tests for Intl.getCanonicalLocales
     9        * js/script-tests/intl.js: Added test for Intl.getCanonicalLocales
     10
    1112016-10-05  Ryan Haddad  <ryanhaddad@apple.com>
    212
  • trunk/LayoutTests/js/intl-expected.txt

    r187575 r206837  
    1313PASS delete Intl; is true
    1414PASS 'Intl' in global() is false
     15PASS Intl.getCanonicalLocales.length is 1
     16PASS Intl.getCanonicalLocales() is an instance of Array
     17PASS Intl.getCanonicalLocales.call(null, 'en') is [ 'en' ]
     18PASS Intl.getCanonicalLocales.call({}, 'en') is [ 'en' ]
     19PASS Intl.getCanonicalLocales.call(1, 'en') is [ 'en' ]
     20PASS Intl.getCanonicalLocales(9) is []
     21PASS Intl.getCanonicalLocales('en') is [ 'en' ]
     22PASS Intl.getCanonicalLocales({ length: 4, 1: 'en', 0: 'es', 3: 'de' }) is [ 'es', 'en', 'de' ]
     23PASS Intl.getCanonicalLocales([ 'en', 'pt', 'en', 'es' ]) is [ 'en', 'pt', 'es' ]
     24PASS Intl.getCanonicalLocales('En-laTn-us-variant2-variant1-1abc-U-ko-tRue-A-aa-aaa-x-RESERVED') is [ 'en-Latn-US-variant2-variant1-1abc-a-aa-aaa-u-ko-true-x-reserved' ]
     25PASS Intl.getCanonicalLocales('no-bok') is [ 'nb' ]
     26PASS Intl.getCanonicalLocales('X-some-thing') is [ 'x-some-thing' ]
     27PASS Intl.getCanonicalLocales(Object.create(null, { length: { get() { throw Error('a') } } })) threw exception Error: a.
     28PASS Intl.getCanonicalLocales(Object.create(null, { length: { value: 1 }, 0: { get() { throw Error('b') } } })) threw exception Error: b.
     29PASS Intl.getCanonicalLocales([ { toString() { throw Error('c') } } ]) threw exception Error: c.
     30PASS Intl.getCanonicalLocales([ 5 ]) threw exception TypeError: locale value must be a string or object.
     31PASS Intl.getCanonicalLocales('') threw exception RangeError: invalid language tag: .
     32PASS Intl.getCanonicalLocales('a') threw exception RangeError: invalid language tag: a.
     33PASS Intl.getCanonicalLocales('abcdefghij') threw exception RangeError: invalid language tag: abcdefghij.
     34PASS Intl.getCanonicalLocales('#$') threw exception RangeError: invalid language tag: #$.
     35PASS Intl.getCanonicalLocales('en-@-abc') threw exception RangeError: invalid language tag: en-@-abc.
     36PASS Intl.getCanonicalLocales('en-u') threw exception RangeError: invalid language tag: en-u.
     37PASS Intl.getCanonicalLocales('en-u-kn-true-u-ko-true') threw exception RangeError: invalid language tag: en-u-kn-true-u-ko-true.
     38PASS Intl.getCanonicalLocales('en-x') threw exception RangeError: invalid language tag: en-x.
     39PASS Intl.getCanonicalLocales('en-*') threw exception RangeError: invalid language tag: en-*.
     40PASS Intl.getCanonicalLocales('en-') threw exception RangeError: invalid language tag: en-.
     41PASS Intl.getCanonicalLocales('en--US') threw exception RangeError: invalid language tag: en--US.
     42PASS Intl.getCanonicalLocales('de') did not throw exception.
     43PASS Intl.getCanonicalLocales('de-DE') did not throw exception.
     44PASS Intl.getCanonicalLocales('DE-de') did not throw exception.
     45PASS Intl.getCanonicalLocales('cmn') did not throw exception.
     46PASS Intl.getCanonicalLocales('cmn-Hans') did not throw exception.
     47PASS Intl.getCanonicalLocales('CMN-hANS') did not throw exception.
     48PASS Intl.getCanonicalLocales('cmn-hans-cn') did not throw exception.
     49PASS Intl.getCanonicalLocales('es-419') did not throw exception.
     50PASS Intl.getCanonicalLocales('es-419-u-nu-latn-cu-bob') did not throw exception.
     51PASS Intl.getCanonicalLocales('i-klingon') did not throw exception.
     52PASS Intl.getCanonicalLocales('cmn-hans-cn-t-ca-u-ca-x-t-u') did not throw exception.
     53PASS Intl.getCanonicalLocales('enochian-enochian') did not throw exception.
     54PASS Intl.getCanonicalLocales('de-gregory-u-ca-gregory') did not throw exception.
     55PASS Intl.getCanonicalLocales('aa-a-foo-x-a-foo-bar') did not throw exception.
     56PASS Intl.getCanonicalLocales('x-en-US-12345') did not throw exception.
     57PASS Intl.getCanonicalLocales('x-12345-12345-en-US') did not throw exception.
     58PASS Intl.getCanonicalLocales('x-en-US-12345-12345') did not throw exception.
     59PASS Intl.getCanonicalLocales('x-en-u-foo') did not throw exception.
     60PASS Intl.getCanonicalLocales('x-en-u-foo-u-bar') did not throw exception.
    1561PASS successfullyParsed is true
    1662
  • trunk/LayoutTests/js/script-tests/intl.js

    r198926 r206837  
    3131Intl = __Intl;
    3232
     33// 8.2.1 Intl.getCanonicalLocales(locales)
     34
     35// The value of the length property of the getCanonicalLocales method is 1.
     36shouldBe("Intl.getCanonicalLocales.length", "1");
     37
     38// Returns Locales
     39shouldBeType("Intl.getCanonicalLocales()", "Array");
     40// Doesn't care about `this`.
     41shouldBe("Intl.getCanonicalLocales.call(null, 'en')", "[ 'en' ]");
     42shouldBe("Intl.getCanonicalLocales.call({}, 'en')", "[ 'en' ]");
     43shouldBe("Intl.getCanonicalLocales.call(1, 'en')", "[ 'en' ]");
     44// Ignores non-object, non-string list.
     45shouldBe("Intl.getCanonicalLocales(9)", "[]");
     46// Makes an array of tags.
     47shouldBe("Intl.getCanonicalLocales('en')", "[ 'en' ]");
     48// Handles array-like objects with holes.
     49shouldBe("Intl.getCanonicalLocales({ length: 4, 1: 'en', 0: 'es', 3: 'de' })", "[ 'es', 'en', 'de' ]");
     50// Deduplicates tags.
     51shouldBe("Intl.getCanonicalLocales([ 'en', 'pt', 'en', 'es' ])", "[ 'en', 'pt', 'es' ]");
     52// Canonicalizes tags.
     53shouldBe("Intl.getCanonicalLocales('En-laTn-us-variant2-variant1-1abc-U-ko-tRue-A-aa-aaa-x-RESERVED')", "[ 'en-Latn-US-variant2-variant1-1abc-a-aa-aaa-u-ko-true-x-reserved' ]");
     54// Replaces outdated tags.
     55shouldBe("Intl.getCanonicalLocales('no-bok')", "[ 'nb' ]");
     56// Canonicalizes private tags.
     57shouldBe("Intl.getCanonicalLocales('X-some-thing')", "[ 'x-some-thing' ]");
     58// Throws on problems with length, get, or toString.
     59shouldThrow("Intl.getCanonicalLocales(Object.create(null, { length: { get() { throw Error('a') } } }))", "'Error: a'");
     60shouldThrow("Intl.getCanonicalLocales(Object.create(null, { length: { value: 1 }, 0: { get() { throw Error('b') } } }))", "'Error: b'");
     61shouldThrow("Intl.getCanonicalLocales([ { toString() { throw Error('c') } } ])", "'Error: c'");
     62// Throws on bad tags.
     63shouldThrow("Intl.getCanonicalLocales([ 5 ])", "'TypeError: locale value must be a string or object'");
     64shouldThrow("Intl.getCanonicalLocales('')", "'RangeError: invalid language tag: '");
     65shouldThrow("Intl.getCanonicalLocales('a')", "'RangeError: invalid language tag: a'");
     66shouldThrow("Intl.getCanonicalLocales('abcdefghij')", "'RangeError: invalid language tag: abcdefghij'");
     67shouldThrow("Intl.getCanonicalLocales('#$')", "'RangeError: invalid language tag: #$'");
     68shouldThrow("Intl.getCanonicalLocales('en-@-abc')", "'RangeError: invalid language tag: en-@-abc'");
     69shouldThrow("Intl.getCanonicalLocales('en-u')", "'RangeError: invalid language tag: en-u'");
     70shouldThrow("Intl.getCanonicalLocales('en-u-kn-true-u-ko-true')", "'RangeError: invalid language tag: en-u-kn-true-u-ko-true'");
     71shouldThrow("Intl.getCanonicalLocales('en-x')", "'RangeError: invalid language tag: en-x'");
     72shouldThrow("Intl.getCanonicalLocales('en-*')", "'RangeError: invalid language tag: en-*'");
     73shouldThrow("Intl.getCanonicalLocales('en-')", "'RangeError: invalid language tag: en-'");
     74shouldThrow("Intl.getCanonicalLocales('en--US')", "'RangeError: invalid language tag: en--US'");
     75// Accepts valid tags
     76var validLanguageTags = [
     77    "de", // ISO 639 language code
     78    "de-DE", // + ISO 3166-1 country code
     79    "DE-de", // tags are case-insensitive
     80    "cmn", // ISO 639 language code
     81    "cmn-Hans", // + script code
     82    "CMN-hANS", // tags are case-insensitive
     83    "cmn-hans-cn", // + ISO 3166-1 country code
     84    "es-419", // + UN M.49 region code
     85    "es-419-u-nu-latn-cu-bob", // + Unicode locale extension sequence
     86    "i-klingon", // grandfathered tag
     87    "cmn-hans-cn-t-ca-u-ca-x-t-u", // singleton subtags can also be used as private use subtags
     88    "enochian-enochian", // language and variant subtags may be the same
     89    "de-gregory-u-ca-gregory", // variant and extension subtags may be the same
     90    "aa-a-foo-x-a-foo-bar", // variant subtags can also be used as private use subtags
     91    "x-en-US-12345", // anything goes in private use tags
     92    "x-12345-12345-en-US",
     93    "x-en-US-12345-12345",
     94    "x-en-u-foo",
     95    "x-en-u-foo-u-bar"
     96];
     97for (var validLanguageTag of validLanguageTags) {
     98    shouldNotThrow("Intl.getCanonicalLocales('" + validLanguageTag + "')");
     99}
     100
  • trunk/Source/JavaScriptCore/ChangeLog

    r206836 r206837  
     12016-10-05  Andy VanWagoner  <thetalecrafter@gmail.com>
     2
     3        [INTL] Implement Intl.getCanonicalLocales
     4        https://bugs.webkit.org/show_bug.cgi?id=162768
     5
     6        Reviewed by Benjamin Poulain.
     7
     8        Implement Intl.getCanonicalLocales from ECMA 402 (3rd edition)
     9        http://ecma-international.org/ecma-402/3.0/index.html#sec-intl.getcanonicallocales
     10
     11        Reuse canonicalizeLocaleList and copy the results into a new JSArray.
     12
     13        * runtime/IntlObject.cpp:
     14        (JSC::IntlObject::finishCreation):
     15        (JSC::intlObjectFuncGetCanonicalLocales):
     16
    1172016-10-05  Michael Saboff  <msaboff@apple.com>
    218
  • trunk/Source/JavaScriptCore/runtime/IntlObject.cpp

    r206386 r206837  
    5757STATIC_ASSERT_IS_TRIVIALLY_DESTRUCTIBLE(IntlObject);
    5858
     59static EncodedJSValue JSC_HOST_CALL intlObjectFuncGetCanonicalLocales(ExecState*);
     60
    5961}
    6062
     
    111113    putDirectWithoutTransition(vm, vm.propertyNames->NumberFormat, numberFormatConstructor, DontEnum);
    112114    putDirectWithoutTransition(vm, vm.propertyNames->DateTimeFormat, dateTimeFormatConstructor, DontEnum);
     115
     116    // 8.2 Function Properties of the Intl Object
     117    // https://tc39.github.io/ecma402/#sec-function-properties-of-the-intl-object
     118    putDirectNativeFunction(vm, globalObject, Identifier::fromString(&vm, "getCanonicalLocales"), 1, intlObjectFuncGetCanonicalLocales, NoIntrinsic, DontEnum);
    113119}
    114120
     
    10111017}
    10121018
     1019EncodedJSValue JSC_HOST_CALL intlObjectFuncGetCanonicalLocales(ExecState* state)
     1020{
     1021    VM& vm = state->vm();
     1022    auto scope = DECLARE_THROW_SCOPE(vm);
     1023    // https://tc39.github.io/ecma402/#sec-intl.getcanonicallocales
     1024    // 8.2.1 Intl.getCanonicalLocales(locales) (ECMA-402 4.0)
     1025
     1026    // 1. Let ll be ? CanonicalizeLocaleList(locales).
     1027    Vector<String> localeList = canonicalizeLocaleList(*state, state->argument(0));
     1028    RETURN_IF_EXCEPTION(scope, encodedJSValue());
     1029
     1030    // 2. Return CreateArrayFromList(ll).
     1031    JSGlobalObject* globalObject = state->callee()->globalObject();
     1032    JSArray* localeArray = JSArray::tryCreateUninitialized(vm, globalObject->arrayStructureForIndexingTypeDuringAllocation(ArrayWithContiguous), localeList.size());
     1033    if (!localeArray) {
     1034        throwOutOfMemoryError(state, scope);
     1035        return encodedJSValue();
     1036    }
     1037
     1038    auto length = localeList.size();
     1039    for (size_t i = 0; i < length; ++i) {
     1040        localeArray->initializeIndex(vm, i, jsString(state, localeList[i]));
     1041        RETURN_IF_EXCEPTION(scope, encodedJSValue());
     1042    }
     1043    return JSValue::encode(localeArray);
     1044}
     1045
    10131046} // namespace JSC
    10141047
Note: See TracChangeset for help on using the changeset viewer.