Expose getCanonicalLocales() for Intl object.
Also add a test for the return object of getCanonicalLocaleList(). See https://github.com/tc39/test262/issues/745 for more details. BUG=v8:5012 TEST=test262/intl402/Intl/getCanonicalLocales/* TEST=intl/general/getCanonicalLocales Review-Url: https://codereview.chromium.org/2239523002 Cr-Commit-Position: refs/heads/master@{#38733}
This commit is contained in:
parent
2d3a53c9c8
commit
520f38fce7
@ -587,6 +587,7 @@ function setOptions(inOptions, extensionMap, keyValues, getOption, outOptions) {
|
||||
* Given an array-like, outputs an Array with the numbered
|
||||
* properties copied over and defined
|
||||
* configurable: false, writable: false, enumerable: true.
|
||||
* When |expandable| is true, the result array can be expanded.
|
||||
*/
|
||||
function freezeArray(input) {
|
||||
var array = [];
|
||||
@ -604,6 +605,12 @@ function freezeArray(input) {
|
||||
return array;
|
||||
}
|
||||
|
||||
/* Make JS array[] out of InternalArray */
|
||||
function makeArray(input) {
|
||||
var array = [];
|
||||
%MoveArrayContents(input, array);
|
||||
return array;
|
||||
}
|
||||
|
||||
/**
|
||||
* It's sometimes desireable to leave user requested locale instead of ICU
|
||||
@ -738,6 +745,7 @@ function toTitleCaseTimezoneLocation(location) {
|
||||
|
||||
/**
|
||||
* Canonicalizes the language tag, or throws in case the tag is invalid.
|
||||
* ECMA 402 9.2.1 steps 7.c ii ~ v.
|
||||
*/
|
||||
function canonicalizeLanguageTag(localeID) {
|
||||
// null is typeof 'object' so we have to do extra check.
|
||||
@ -755,11 +763,14 @@ function canonicalizeLanguageTag(localeID) {
|
||||
|
||||
var localeString = TO_STRING(localeID);
|
||||
|
||||
if (isValidLanguageTag(localeString) === false) {
|
||||
if (isStructuallyValidLanguageTag(localeString) === false) {
|
||||
throw %make_range_error(kInvalidLanguageTag, localeString);
|
||||
}
|
||||
|
||||
// ECMA 402 6.2.3
|
||||
var tag = %CanonicalizeLanguageTag(localeString);
|
||||
// TODO(jshin): This should not happen because the structual validity
|
||||
// is already checked. If that's the case, remove this.
|
||||
if (tag === 'invalid-tag') {
|
||||
throw %make_range_error(kInvalidLanguageTag, localeString);
|
||||
}
|
||||
@ -769,20 +780,22 @@ function canonicalizeLanguageTag(localeID) {
|
||||
|
||||
|
||||
/**
|
||||
* Returns an array where all locales are canonicalized and duplicates removed.
|
||||
* Returns an InternalArray where all locales are canonicalized and duplicates
|
||||
* removed.
|
||||
* Throws on locales that are not well formed BCP47 tags.
|
||||
* ECMA 402 8.2.1 steps 1 (ECMA 402 9.2.1) and 2.
|
||||
*/
|
||||
function initializeLocaleList(locales) {
|
||||
function canonicalizeLocaleList(locales) {
|
||||
var seen = new InternalArray();
|
||||
if (!IS_UNDEFINED(locales)) {
|
||||
// We allow single string localeID.
|
||||
if (typeof locales === 'string') {
|
||||
%_Call(ArrayPush, seen, canonicalizeLanguageTag(locales));
|
||||
return freezeArray(seen);
|
||||
return seen;
|
||||
}
|
||||
|
||||
var o = TO_OBJECT(locales);
|
||||
var len = TO_UINT32(o.length);
|
||||
var len = TO_LENGTH(o.length);
|
||||
|
||||
for (var k = 0; k < len; k++) {
|
||||
if (k in o) {
|
||||
@ -797,20 +810,30 @@ function initializeLocaleList(locales) {
|
||||
}
|
||||
}
|
||||
|
||||
return freezeArray(seen);
|
||||
return seen;
|
||||
}
|
||||
|
||||
function initializeLocaleList(locales) {
|
||||
return freezeArray(canonicalizeLocaleList(locales));
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates the language tag. Section 2.2.9 of the bcp47 spec
|
||||
* defines a valid tag.
|
||||
* Check the structual Validity of the language tag per ECMA 402 6.2.2:
|
||||
* - Well-formed per RFC 5646 2.1
|
||||
* - There are no duplicate variant subtags
|
||||
* - There are no duplicate singletion (extension) subtags
|
||||
*
|
||||
* One extra-check is done (from RFC 5646 2.2.9): the tag is compared
|
||||
* against the list of grandfathered tags. However, subtags for
|
||||
* primary/extended language, script, region, variant are not checked
|
||||
* against the IANA language subtag registry.
|
||||
*
|
||||
* ICU is too permissible and lets invalid tags, like
|
||||
* hant-cmn-cn, through.
|
||||
*
|
||||
* Returns false if the language tag is invalid.
|
||||
*/
|
||||
function isValidLanguageTag(locale) {
|
||||
function isStructuallyValidLanguageTag(locale) {
|
||||
// Check if it's well-formed, including grandfadered tags.
|
||||
if (IS_NULL(InternalRegExpMatch(GetLanguageTagRE(), locale))) {
|
||||
return false;
|
||||
@ -905,6 +928,16 @@ var resolvedAccessor = {
|
||||
}
|
||||
};
|
||||
|
||||
// ECMA 402 section 8.2.1
|
||||
InstallFunction(Intl, 'getCanonicalLocales', function(locales) {
|
||||
if (!IS_UNDEFINED(new.target)) {
|
||||
throw %make_type_error(kOrdinaryFunctionCalledAsConstructor);
|
||||
}
|
||||
|
||||
return makeArray(canonicalizeLocaleList(locales));
|
||||
}
|
||||
);
|
||||
|
||||
/**
|
||||
* Initializes the given object so it's a valid Collator instance.
|
||||
* Useful for subclassing.
|
||||
|
@ -63,6 +63,7 @@ const UChar* GetUCharBufferFromFlat(const String::FlatContent& flat,
|
||||
|
||||
} // namespace
|
||||
|
||||
// ECMA 402 6.2.3
|
||||
RUNTIME_FUNCTION(Runtime_CanonicalizeLanguageTag) {
|
||||
HandleScope scope(isolate);
|
||||
Factory* factory = isolate->factory();
|
||||
@ -73,6 +74,8 @@ RUNTIME_FUNCTION(Runtime_CanonicalizeLanguageTag) {
|
||||
v8::String::Utf8Value locale_id(v8::Utils::ToLocal(locale_id_str));
|
||||
|
||||
// Return value which denotes invalid language tag.
|
||||
// TODO(jshin): Can uloc_{for,to}TanguageTag fail even for structually valid
|
||||
// language tags? If not, just add CHECK instead of returning 'invalid-tag'.
|
||||
const char* const kInvalidTag = "invalid-tag";
|
||||
|
||||
UErrorCode error = U_ZERO_ERROR;
|
||||
|
25
test/intl/general/getCanonicalLocales.js
Normal file
25
test/intl/general/getCanonicalLocales.js
Normal file
@ -0,0 +1,25 @@
|
||||
// Copyright 2016 the V8 project authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
var locales = ['en-US', 'fr'];
|
||||
var result = Intl.getCanonicalLocales(locales);
|
||||
var len = result.length
|
||||
|
||||
// TODO(jshin): Remove the following when
|
||||
// https://github.com/tc39/test262/issues/745 is resolved and
|
||||
// test262 in v8 is updated.
|
||||
|
||||
assertEquals(Object.getPrototypeOf(result), Array.prototype);
|
||||
assertEquals(result.constructor, Array);
|
||||
|
||||
for (var key in result) {
|
||||
var desc = Object.getOwnPropertyDescriptor(result, key);
|
||||
assertTrue(desc.writable);
|
||||
assertTrue(desc.configurable);
|
||||
assertTrue(desc.enumerable);
|
||||
}
|
||||
|
||||
var desc = Object.getOwnPropertyDescriptor(result, 'length');
|
||||
assertTrue(desc.writable);
|
||||
assertEquals(result.push('de'), desc.value + 1);
|
@ -330,7 +330,10 @@
|
||||
'language/module-code/*': [SKIP],
|
||||
|
||||
# https://bugs.chromium.org/p/v8/issues/detail?id=5012
|
||||
'intl402/Intl/getCanonicalLocales/*': [FAIL],
|
||||
# http://bugs.icu-project.org/trac/ticket/12671
|
||||
'intl402/Intl/getCanonicalLocales/weird-cases': [FAIL],
|
||||
# https://github.com/tc39/test262/issues/743
|
||||
'intl402/Intl/getCanonicalLocales/main': [FAIL],
|
||||
|
||||
# https://bugs.chromium.org/p/v8/issues/detail?id=5115
|
||||
'language/statements/class/subclass/class-definition-null-proto-missing-return-override': [FAIL],
|
||||
|
Loading…
Reference in New Issue
Block a user