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, ...@@ -1687,14 +1687,15 @@ bool IsValidExtension(const icu::Locale& locale, const char* key,
return false; 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"}; std::set<std::string> invalid_values = {"standard", "search"};
if (invalid_values.find(value) != invalid_values.end()) return false; if (invalid_values.find(value) != invalid_values.end()) return false;
return IsValidExtension<icu::Collator>(locale, "collation", value); return IsValidExtension<icu::Collator>(locale, "collation", value);
} }
} // namespace
bool Intl::IsWellFormedCalendar(const std::string& value) { bool Intl::IsWellFormedCalendar(const std::string& value) {
return JSLocale::Is38AlphaNumList(value); return JSLocale::Is38AlphaNumList(value);
} }
...@@ -1769,7 +1770,7 @@ std::map<std::string, std::string> LookupAndValidateUnicodeExtensions( ...@@ -1769,7 +1770,7 @@ std::map<std::string, std::string> LookupAndValidateUnicodeExtensions(
if (strcmp("ca", bcp47_key) == 0) { if (strcmp("ca", bcp47_key) == 0) {
is_valid_value = Intl::IsValidCalendar(*icu_locale, bcp47_value); is_valid_value = Intl::IsValidCalendar(*icu_locale, bcp47_value);
} else if (strcmp("co", bcp47_key) == 0) { } 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) { } else if (strcmp("hc", bcp47_key) == 0) {
// https://www.unicode.org/repos/cldr/tags/latest/common/bcp47/calendar.xml // https://www.unicode.org/repos/cldr/tags/latest/common/bcp47/calendar.xml
std::set<std::string> valid_values = {"h11", "h12", "h23", "h24"}; std::set<std::string> valid_values = {"h11", "h12", "h23", "h24"};
......
...@@ -243,6 +243,10 @@ class Intl { ...@@ -243,6 +243,10 @@ class Intl {
static bool IsValidCalendar(const icu::Locale& locale, static bool IsValidCalendar(const icu::Locale& locale,
const std::string& value); 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. // Check the numberingSystem is valid.
static bool IsValidNumberingSystem(const std::string& value); static bool IsValidNumberingSystem(const std::string& value);
......
...@@ -10,6 +10,7 @@ ...@@ -10,6 +10,7 @@
#include "src/execution/isolate.h" #include "src/execution/isolate.h"
#include "src/objects/js-collator-inl.h" #include "src/objects/js-collator-inl.h"
#include "src/objects/js-locale.h"
#include "src/objects/objects-inl.h" #include "src/objects/objects-inl.h"
#include "unicode/coll.h" #include "unicode/coll.h"
#include "unicode/locid.h" #include "unicode/locid.h"
...@@ -293,6 +294,29 @@ MaybeHandle<JSCollator> JSCollator::New(Isolate* isolate, Handle<Map> map, ...@@ -293,6 +294,29 @@ MaybeHandle<JSCollator> JSCollator::New(Isolate* isolate, Handle<Map> map,
MAYBE_RETURN(maybe_locale_matcher, MaybeHandle<JSCollator>()); MAYBE_RETURN(maybe_locale_matcher, MaybeHandle<JSCollator>());
Intl::MatcherOption matcher = maybe_locale_matcher.FromJust(); 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", // 11. Let numeric be ? GetOption(options, "numeric", "boolean",
// undefined, undefined). // undefined, undefined).
// 12. If numeric is not undefined, then // 12. If numeric is not undefined, then
...@@ -337,6 +361,15 @@ MaybeHandle<JSCollator> JSCollator::New(Isolate* isolate, Handle<Map> map, ...@@ -337,6 +361,15 @@ MaybeHandle<JSCollator> JSCollator::New(Isolate* isolate, Handle<Map> map,
DCHECK(!icu_locale.isBogus()); DCHECK(!icu_locale.isBogus());
// 19. Let collation be r.[[co]]. // 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. // 5. Set collator.[[Usage]] to usage.
// //
...@@ -358,6 +391,12 @@ MaybeHandle<JSCollator> JSCollator::New(Isolate* isolate, Handle<Map> map, ...@@ -358,6 +391,12 @@ MaybeHandle<JSCollator> JSCollator::New(Isolate* isolate, Handle<Map> map,
UErrorCode status = U_ZERO_ERROR; UErrorCode status = U_ZERO_ERROR;
icu_locale.setUnicodeKeywordValue("co", "search", status); icu_locale.setUnicodeKeywordValue("co", "search", status);
CHECK(U_SUCCESS(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". // 20. If collation is null, let collation be "default".
...@@ -367,7 +406,6 @@ MaybeHandle<JSCollator> JSCollator::New(Isolate* isolate, Handle<Map> map, ...@@ -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 // here. The collation value can be looked up from icu::Collator on
// demand, as part of Intl.Collator.prototype.resolvedOptions. // demand, as part of Intl.Collator.prototype.resolvedOptions.
UErrorCode status = U_ZERO_ERROR;
std::unique_ptr<icu::Collator> icu_collator( std::unique_ptr<icu::Collator> icu_collator(
icu::Collator::createInstance(icu_locale, status)); icu::Collator::createInstance(icu_locale, status));
if (U_FAILURE(status) || icu_collator.get() == nullptr) { if (U_FAILURE(status) || icu_collator.get() == nullptr) {
......
...@@ -20,6 +20,17 @@ let valid_locales = [ ...@@ -20,6 +20,17 @@ let valid_locales = [
"ja-u-co-unihan", "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) { invalid_co.forEach(function(co) {
let col = new Intl.Collator(["en-u-co-" + co]); let col = new Intl.Collator(["en-u-co-" + co]);
assertEquals("en", col.resolvedOptions().locale); assertEquals("en", col.resolvedOptions().locale);
...@@ -31,3 +42,11 @@ valid_locales.forEach(function(l) { ...@@ -31,3 +42,11 @@ valid_locales.forEach(function(l) {
assertEquals(l, col.resolvedOptions().locale); 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'], { ...@@ -14,17 +14,20 @@ new Intl.Collator(['en-US'], {
get localeMatcher() { get localeMatcher() {
assertEquals(1, getCount++); assertEquals(1, getCount++);
}, },
get numeric() { get collation() {
assertEquals(2, getCount++); assertEquals(2, getCount++);
}, },
get caseFirst() { get numeric() {
assertEquals(3, getCount++); assertEquals(3, getCount++);
}, },
get sensitivity() { get caseFirst() {
assertEquals(4, getCount++); assertEquals(4, getCount++);
}, },
get ignorePunctuation() { get sensitivity() {
assertEquals(5, getCount++); 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