Commit 40e34e3a authored by Frank Tang's avatar Frank Tang Committed by Commit Bot

Add "collation" option to Intl.Collator

Per change in https://github.com/tc39/ecma402/pull/459/

Bug: v8:10732
Change-Id: I2ef21e8b450cbf9c61f987c61f3ba7d6959db81a
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2309149Reviewed-by: 's avatarJakob Kummerow <jkummerow@chromium.org>
Commit-Queue: Frank Tang <ftang@chromium.org>
Cr-Commit-Position: refs/heads/master@{#68976}
parent 8a06685d
......@@ -1687,14 +1687,15 @@ bool IsValidExtension(const icu::Locale& locale, const char* key,
return false;
}
bool IsValidCollation(const icu::Locale& locale, const std::string& value) {
} // namespace
bool Intl::IsValidCollation(const icu::Locale& locale,
const std::string& value) {
std::set<std::string> invalid_values = {"standard", "search"};
if (invalid_values.find(value) != invalid_values.end()) return false;
return IsValidExtension<icu::Collator>(locale, "collation", value);
}
} // namespace
bool Intl::IsWellFormedCalendar(const std::string& value) {
return JSLocale::Is38AlphaNumList(value);
}
......@@ -1769,7 +1770,7 @@ std::map<std::string, std::string> LookupAndValidateUnicodeExtensions(
if (strcmp("ca", bcp47_key) == 0) {
is_valid_value = Intl::IsValidCalendar(*icu_locale, bcp47_value);
} else if (strcmp("co", bcp47_key) == 0) {
is_valid_value = IsValidCollation(*icu_locale, bcp47_value);
is_valid_value = Intl::IsValidCollation(*icu_locale, bcp47_value);
} else if (strcmp("hc", bcp47_key) == 0) {
// https://www.unicode.org/repos/cldr/tags/latest/common/bcp47/calendar.xml
std::set<std::string> valid_values = {"h11", "h12", "h23", "h24"};
......
......@@ -243,6 +243,10 @@ class Intl {
static bool IsValidCalendar(const icu::Locale& locale,
const std::string& value);
// Check the collation is valid or not for that locale.
static bool IsValidCollation(const icu::Locale& locale,
const std::string& value);
// Check the numberingSystem is valid.
static bool IsValidNumberingSystem(const std::string& value);
......
......@@ -10,6 +10,7 @@
#include "src/execution/isolate.h"
#include "src/objects/js-collator-inl.h"
#include "src/objects/js-locale.h"
#include "src/objects/objects-inl.h"
#include "unicode/coll.h"
#include "unicode/locid.h"
......@@ -293,6 +294,29 @@ MaybeHandle<JSCollator> JSCollator::New(Isolate* isolate, Handle<Map> map,
MAYBE_RETURN(maybe_locale_matcher, MaybeHandle<JSCollator>());
Intl::MatcherOption matcher = maybe_locale_matcher.FromJust();
// x. Let _collation_ be ? GetOption(_options_, *"collation"*, *"string"*,
// *undefined*, *undefined*).
std::unique_ptr<char[]> collation_str = nullptr;
const std::vector<const char*> empty_values = {};
Maybe<bool> maybe_collation = Intl::GetStringOption(
isolate, options, "collation", empty_values, service, &collation_str);
MAYBE_RETURN(maybe_collation, MaybeHandle<JSCollator>());
// x. If _collation_ is not *undefined*, then
if (maybe_collation.FromJust() && collation_str != nullptr) {
// 1. If _collation_ does not match the Unicode Locale Identifier `type`
// nonterminal, throw a *RangeError* exception.
if (!JSLocale::Is38AlphaNumList(collation_str.get())) {
THROW_NEW_ERROR_RETURN_VALUE(
isolate,
NewRangeError(MessageTemplate::kInvalid,
isolate->factory()->collation_string(),
isolate->factory()->NewStringFromAsciiChecked(
collation_str.get())),
MaybeHandle<JSCollator>());
}
}
// x. Set _opt_.[[co]] to _collation_.
// 11. Let numeric be ? GetOption(options, "numeric", "boolean",
// undefined, undefined).
// 12. If numeric is not undefined, then
......@@ -337,6 +361,15 @@ MaybeHandle<JSCollator> JSCollator::New(Isolate* isolate, Handle<Map> map,
DCHECK(!icu_locale.isBogus());
// 19. Let collation be r.[[co]].
UErrorCode status = U_ZERO_ERROR;
if (collation_str != nullptr) {
auto co_extension_it = r.extensions.find("co");
if (co_extension_it != r.extensions.end() &&
co_extension_it->second != collation_str.get()) {
icu_locale.setUnicodeKeywordValue("co", nullptr, status);
CHECK(U_SUCCESS(status));
}
}
// 5. Set collator.[[Usage]] to usage.
//
......@@ -358,6 +391,12 @@ MaybeHandle<JSCollator> JSCollator::New(Isolate* isolate, Handle<Map> map,
UErrorCode status = U_ZERO_ERROR;
icu_locale.setUnicodeKeywordValue("co", "search", status);
CHECK(U_SUCCESS(status));
} else {
if (collation_str != nullptr &&
Intl::IsValidCollation(icu_locale, collation_str.get())) {
icu_locale.setUnicodeKeywordValue("co", collation_str.get(), status);
CHECK(U_SUCCESS(status));
}
}
// 20. If collation is null, let collation be "default".
......@@ -367,7 +406,6 @@ MaybeHandle<JSCollator> JSCollator::New(Isolate* isolate, Handle<Map> map,
// here. The collation value can be looked up from icu::Collator on
// demand, as part of Intl.Collator.prototype.resolvedOptions.
UErrorCode status = U_ZERO_ERROR;
std::unique_ptr<icu::Collator> icu_collator(
icu::Collator::createInstance(icu_locale, status));
if (U_FAILURE(status) || icu_collator.get() == nullptr) {
......
......@@ -20,6 +20,17 @@ let valid_locales = [
"ja-u-co-unihan",
];
let valid_co = [
["zh", "zhuyin"],
["zh", "stroke"],
["ar", "compat"],
["en", "emoji"],
["en", "eor"],
["zh-Hant", "pinyin"],
["ko", "searchjl"],
["ja", "unihan"],
];
invalid_co.forEach(function(co) {
let col = new Intl.Collator(["en-u-co-" + co]);
assertEquals("en", col.resolvedOptions().locale);
......@@ -31,3 +42,11 @@ valid_locales.forEach(function(l) {
assertEquals(l, col.resolvedOptions().locale);
}
);
valid_co.forEach(function([locale, collation]) {
let col = new Intl.Collator([locale + "-u-co-" + collation]);
assertEquals(collation, col.resolvedOptions().collation);
let col2 = new Intl.Collator([locale], {collation});
assertEquals(collation, col2.resolvedOptions().collation);
}
);
......@@ -14,17 +14,20 @@ new Intl.Collator(['en-US'], {
get localeMatcher() {
assertEquals(1, getCount++);
},
get numeric() {
get collation() {
assertEquals(2, getCount++);
},
get caseFirst() {
get numeric() {
assertEquals(3, getCount++);
},
get sensitivity() {
get caseFirst() {
assertEquals(4, getCount++);
},
get ignorePunctuation() {
get sensitivity() {
assertEquals(5, getCount++);
},
get ignorePunctuation() {
assertEquals(6, getCount++);
},
});
assertEquals(6, getCount);
assertEquals(7, getCount);
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment