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:
jshin 2016-08-18 16:26:56 -07:00 committed by Commit bot
parent 2d3a53c9c8
commit 520f38fce7
4 changed files with 74 additions and 10 deletions

View File

@ -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.

View File

@ -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;

View 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);

View File

@ -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],