v8
V8 is Google’s open source high-performance JavaScript and WebAssembly engine, written in C++.
Loading...
Searching...
No Matches
js-locale.cc
Go to the documentation of this file.
1// Copyright 2018 the V8 project authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#ifndef V8_INTL_SUPPORT
6#error Internationalization is expected to be enabled.
7#endif // V8_INTL_SUPPORT
8
10
11#include <map>
12#include <memory>
13#include <string>
14#include <vector>
15
16#include "src/api/api.h"
18#include "src/heap/factory.h"
24#include "unicode/calendar.h"
25#include "unicode/char16ptr.h"
26#include "unicode/coll.h"
27#include "unicode/dtptngen.h"
28#include "unicode/localebuilder.h"
29#include "unicode/locid.h"
30#include "unicode/ucal.h"
31#include "unicode/uloc.h"
32#include "unicode/ulocdata.h"
33#include "unicode/unistr.h"
34
35namespace v8 {
36namespace internal {
37
38namespace {
39
40struct OptionData {
41 const char* name;
42 const char* key;
43 const std::vector<const char*>* possible_values;
45};
46struct ValueAndType {
47 const char* value;
48 const char* type;
49};
50
51// Inserts tags from options into locale string.
52Maybe<bool> InsertOptionsIntoLocale(Isolate* isolate,
53 DirectHandle<JSReceiver> options,
54 icu::LocaleBuilder* builder) {
55 DCHECK(isolate);
56
57 const std::vector<const char*> hour_cycle_values = {"h11", "h12", "h23",
58 "h24"};
59 const std::vector<const char*> case_first_values = {"upper", "lower",
60 "false"};
61 const std::vector<const char*> empty_values = {};
62 const std::array<OptionData, 7> kOptionToUnicodeTagMap = {
63 {{"calendar", "ca", &empty_values, false},
64 {"collation", "co", &empty_values, false},
65 {"firstDayOfWeek", "fw", &empty_values, false},
66 {"hourCycle", "hc", &hour_cycle_values, false},
67 {"caseFirst", "kf", &case_first_values, false},
68 {"numeric", "kn", &empty_values, true},
69 {"numberingSystem", "nu", &empty_values, false}}};
70
71 // TODO(cira): Pass in values as per the spec to make this to be
72 // spec compliant.
73
74 for (const auto& option_to_bcp47 : kOptionToUnicodeTagMap) {
75 std::unique_ptr<char[]> value_str = nullptr;
76 bool value_bool = false;
77 Maybe<bool> maybe_found =
78 option_to_bcp47.is_bool_value
79 ? GetBoolOption(isolate, options, option_to_bcp47.name, "locale",
80 &value_bool)
81 : GetStringOption(isolate, options, option_to_bcp47.name,
82 *(option_to_bcp47.possible_values), "locale",
83 &value_str);
84 MAYBE_RETURN(maybe_found, Nothing<bool>());
85
86 // TODO(cira): Use fallback value if value is not found to make
87 // this spec compliant.
88 if (!maybe_found.FromJust()) continue;
89
90 const char* type = value_str.get();
91 if (strcmp(option_to_bcp47.key, "fw") == 0) {
92 const std::array<ValueAndType, 8> kFirstDayValuesAndTypes = {
93 {{"0", "sun"},
94 {"1", "mon"},
95 {"2", "tue"},
96 {"3", "wed"},
97 {"4", "thu"},
98 {"5", "fri"},
99 {"6", "sat"},
100 {"7", "sun"}}};
101 for (const auto& value_to_type : kFirstDayValuesAndTypes) {
102 if (std::strcmp(type, value_to_type.value) == 0) {
103 type = value_to_type.type;
104 break;
105 }
106 }
107 } else if (option_to_bcp47.is_bool_value) {
108 value_str = value_bool ? isolate->factory()->true_string()->ToCString()
109 : isolate->factory()->false_string()->ToCString();
110 type = value_str.get();
111 }
112 DCHECK_NOT_NULL(type);
113
114 // Overwrite existing, or insert new key-value to the locale string.
115 if (!uloc_toLegacyType(uloc_toLegacyKey(option_to_bcp47.key), type)) {
116 return Just(false);
117 }
118 builder->setUnicodeLocaleKeyword(option_to_bcp47.key, type);
119 }
120 return Just(true);
121}
122
123DirectHandle<Object> UnicodeKeywordValue(Isolate* isolate,
124 DirectHandle<JSLocale> locale,
125 const char* key) {
126 icu::Locale* icu_locale = locale->icu_locale()->raw();
127 UErrorCode status = U_ZERO_ERROR;
128 std::string value =
129 icu_locale->getUnicodeKeywordValue<std::string>(key, status);
130 if (status == U_ILLEGAL_ARGUMENT_ERROR || value.empty()) {
131 return isolate->factory()->undefined_value();
132 }
133 if (value == "yes") {
134 value = "true";
135 }
136 if (value == "true" && strcmp(key, "kf") == 0) {
137 return isolate->factory()->NewStringFromStaticChars("");
138 }
139 return isolate->factory()->NewStringFromAsciiChecked(value.c_str());
140}
141
142bool IsCheckRange(const std::string& str, size_t min, size_t max,
143 bool(range_check_func)(char)) {
144 if (!base::IsInRange(str.length(), min, max)) return false;
145 for (size_t i = 0; i < str.length(); i++) {
146 if (!range_check_func(str[i])) return false;
147 }
148 return true;
149}
150bool IsAlpha(const std::string& str, size_t min, size_t max) {
151 return IsCheckRange(str, min, max, [](char c) -> bool {
152 return base::IsInRange(c, 'a', 'z') || base::IsInRange(c, 'A', 'Z');
153 });
154}
155
156bool IsDigit(const std::string& str, size_t min, size_t max) {
157 return IsCheckRange(str, min, max, [](char c) -> bool {
158 return base::IsInRange(c, '0', '9');
159 });
160}
161
162bool IsAlphanum(const std::string& str, size_t min, size_t max) {
163 return IsCheckRange(str, min, max, [](char c) -> bool {
164 return base::IsInRange(c, 'a', 'z') || base::IsInRange(c, 'A', 'Z') ||
165 base::IsInRange(c, '0', '9');
166 });
167}
168
169bool IsUnicodeLanguageSubtag(const std::string& value) {
170 // unicode_language_subtag = alpha{2,3} | alpha{5,8};
171 return IsAlpha(value, 2, 3) || IsAlpha(value, 5, 8);
172}
173
174bool IsUnicodeScriptSubtag(const std::string& value) {
175 // unicode_script_subtag = alpha{4} ;
176 return IsAlpha(value, 4, 4);
177}
178
179bool IsUnicodeRegionSubtag(const std::string& value) {
180 // unicode_region_subtag = (alpha{2} | digit{3});
181 return IsAlpha(value, 2, 2) || IsDigit(value, 3, 3);
182}
183
184bool IsDigitAlphanum3(const std::string& value) {
185 return value.length() == 4 && base::IsInRange(value[0], '0', '9') &&
186 IsAlphanum(value.substr(1), 3, 3);
187}
188
189bool IsUnicodeVariantSubtag(const std::string& value) {
190 // unicode_variant_subtag = (alphanum{5,8} | digit alphanum{3}) ;
191 return IsAlphanum(value, 5, 8) || IsDigitAlphanum3(value);
192}
193
194bool IsExtensionSingleton(const std::string& value) {
195 return IsAlphanum(value, 1, 1);
196}
197
198int32_t weekdayFromEDaysOfWeek(icu::Calendar::EDaysOfWeek eDaysOfWeek) {
199 return (eDaysOfWeek == icu::Calendar::SUNDAY) ? 7 : eDaysOfWeek - 1;
200}
201
202} // namespace
203
204// Implemented as iteration instead of recursion to avoid stack overflow for
205// very long input strings.
206bool JSLocale::Is38AlphaNumList(const std::string& in) {
207 std::string value = in;
208 while (true) {
209 std::size_t found_dash = value.find('-');
210 if (found_dash == std::string::npos) {
211 return IsAlphanum(value, 3, 8);
212 }
213 if (!IsAlphanum(value.substr(0, found_dash), 3, 8)) return false;
214 value = value.substr(found_dash + 1);
215 }
216}
217
218bool JSLocale::Is3Alpha(const std::string& value) {
219 return IsAlpha(value, 3, 3);
220}
221
222// TODO(ftang) Replace the following check w/ icu::LocaleBuilder
223// once ICU64 land in March 2019.
224bool JSLocale::StartsWithUnicodeLanguageId(const std::string& value) {
225 // unicode_language_id =
226 // unicode_language_subtag (sep unicode_script_subtag)?
227 // (sep unicode_region_subtag)? (sep unicode_variant_subtag)* ;
228 std::vector<std::string> tokens;
229 std::string token;
230 std::istringstream token_stream(value);
231 while (std::getline(token_stream, token, '-')) {
232 tokens.push_back(token);
233 }
234 if (tokens.empty()) return false;
235
236 // length >= 1
237 if (!IsUnicodeLanguageSubtag(tokens[0])) return false;
238
239 if (tokens.size() == 1) return true;
240
241 // length >= 2
242 if (IsExtensionSingleton(tokens[1])) return true;
243
244 size_t index = 1;
245 if (IsUnicodeScriptSubtag(tokens[index])) {
246 index++;
247 if (index == tokens.size()) return true;
248 }
249 if (IsUnicodeRegionSubtag(tokens[index])) {
250 index++;
251 }
252 while (index < tokens.size()) {
253 if (IsExtensionSingleton(tokens[index])) return true;
254 if (!IsUnicodeVariantSubtag(tokens[index])) return false;
255 index++;
256 }
257 return true;
258}
259
260namespace {
261Maybe<bool> ApplyOptionsToTag(Isolate* isolate, DirectHandle<String> tag,
263 icu::LocaleBuilder* builder) {
264 v8::Isolate* v8_isolate = reinterpret_cast<v8::Isolate*>(isolate);
265 if (tag->length() == 0) {
267 isolate, NewRangeError(MessageTemplate::kLocaleNotEmpty),
268 Nothing<bool>());
269 }
270
271 v8::String::Utf8Value bcp47_tag(v8_isolate, v8::Utils::ToLocal(tag));
272 builder->setLanguageTag(
273 {*bcp47_tag, static_cast<int32_t>(bcp47_tag.length())});
274 DCHECK_LT(0, bcp47_tag.length());
275 DCHECK_NOT_NULL(*bcp47_tag);
276 // 2. If IsStructurallyValidLanguageTag(tag) is false, throw a RangeError
277 // exception.
278 if (!JSLocale::StartsWithUnicodeLanguageId(*bcp47_tag)) {
279 return Just(false);
280 }
281 UErrorCode status = U_ZERO_ERROR;
282 icu::Locale canonicalized = builder->build(status);
283 canonicalized.canonicalize(status);
284 if (U_FAILURE(status)) {
285 return Just(false);
286 }
287 builder->setLocale(canonicalized);
288
289 // 3. Let language be ? GetOption(options, "language", "string", undefined,
290 // undefined).
291 const std::vector<const char*> empty_values = {};
292 std::unique_ptr<char[]> language_str = nullptr;
293 Maybe<bool> maybe_language =
294 GetStringOption(isolate, options, "language", empty_values,
295 "ApplyOptionsToTag", &language_str);
296 MAYBE_RETURN(maybe_language, Nothing<bool>());
297 // 4. If language is not undefined, then
298 if (maybe_language.FromJust()) {
299 builder->setLanguage(language_str.get());
300 builder->build(status);
301 // a. If language does not match the unicode_language_subtag production,
302 // throw a RangeError exception.
303 if (U_FAILURE(status) || language_str[0] == '\0' ||
304 IsAlpha(language_str.get(), 4, 4)) {
305 return Just(false);
306 }
307 }
308 // 5. Let script be ? GetOption(options, "script", "string", undefined,
309 // undefined).
310 std::unique_ptr<char[]> script_str = nullptr;
311 Maybe<bool> maybe_script =
312 GetStringOption(isolate, options, "script", empty_values,
313 "ApplyOptionsToTag", &script_str);
314 MAYBE_RETURN(maybe_script, Nothing<bool>());
315 // 6. If script is not undefined, then
316 if (maybe_script.FromJust()) {
317 builder->setScript(script_str.get());
318 builder->build(status);
319 // a. If script does not match the unicode_script_subtag production, throw
320 // a RangeError exception.
321 if (U_FAILURE(status) || script_str[0] == '\0') {
322 return Just(false);
323 }
324 }
325 // 7. Let region be ? GetOption(options, "region", "string", undefined,
326 // undefined).
327 std::unique_ptr<char[]> region_str = nullptr;
328 Maybe<bool> maybe_region =
329 GetStringOption(isolate, options, "region", empty_values,
330 "ApplyOptionsToTag", &region_str);
331 MAYBE_RETURN(maybe_region, Nothing<bool>());
332 // 8. If region is not undefined, then
333 if (maybe_region.FromJust()) {
334 // a. If region does not match the region production, throw a RangeError
335 // exception.
336 builder->setRegion(region_str.get());
337 builder->build(status);
338 if (U_FAILURE(status) || region_str[0] == '\0') {
339 return Just(false);
340 }
341 }
342
343 // 9. Set tag to CanonicalizeLanguageTag(tag).
344 // 10. If language is not undefined,
345 // a. Assert: tag matches the unicode_locale_id production.
346 // b. Set tag to tag with the substring corresponding to the
347 // unicode_language_subtag production replaced by the string language.
348 // 11. If script is not undefined, then
349 // a. If tag does not contain a unicode_script_subtag production, then
350 // i. Set tag to the concatenation of the unicode_language_subtag
351 // production of tag, "-", script, and the rest of tag.
352 // b. Else,
353 // i. Set tag to tag with the substring corresponding to the
354 // unicode_script_subtag production replaced by the string script.
355 // 12. If region is not undefined, then
356 // a. If tag does not contain a unicode_region_subtag production, then
357 // i. Set tag to the concatenation of the unicode_language_subtag
358 // production of tag, the substring corresponding to the "-"
359 // unicode_script_subtag production if present, "-", region, and
360 // the rest of tag.
361 // b. Else,
362 // i. Set tag to tag with the substring corresponding to the
363 // unicode_region_subtag production replaced by the string region.
364 // 13. Return CanonicalizeLanguageTag(tag).
365 return Just(true);
366}
367
368} // namespace
369
372 DirectHandle<String> locale_str,
373 DirectHandle<JSReceiver> options) {
374 icu::LocaleBuilder builder;
375 Maybe<bool> maybe_apply =
376 ApplyOptionsToTag(isolate, locale_str, options, &builder);
378 if (!maybe_apply.FromJust()) {
379 THROW_NEW_ERROR(isolate,
380 NewRangeError(MessageTemplate::kLocaleBadParameters));
381 }
382
383 Maybe<bool> maybe_insert =
384 InsertOptionsIntoLocale(isolate, options, &builder);
386 UErrorCode status = U_ZERO_ERROR;
387 icu::Locale icu_locale = builder.build(status);
388
389 icu_locale.canonicalize(status);
390
391 if (!maybe_insert.FromJust() || U_FAILURE(status)) {
392 THROW_NEW_ERROR(isolate,
393 NewRangeError(MessageTemplate::kLocaleBadParameters));
394 }
395
396 // 31. Set locale.[[Locale]] to r.[[locale]].
397 DirectHandle<Managed<icu::Locale>> managed_locale =
399 isolate, 0, std::shared_ptr<icu::Locale>{icu_locale.clone()});
400
401 // Now all properties are ready, so we can allocate the result object.
403 Cast<JSLocale>(isolate->factory()->NewFastOrSlowJSObjectFromMap(map));
405 locale->set_icu_locale(*managed_locale);
406 return locale;
407}
408
409namespace {
410
411MaybeDirectHandle<JSLocale> Construct(Isolate* isolate,
412 const icu::Locale& icu_locale) {
413 DirectHandle<Managed<icu::Locale>> managed_locale =
415 isolate, 0, std::shared_ptr<icu::Locale>{icu_locale.clone()});
416
417 DirectHandle<JSFunction> constructor(
418 isolate->native_context()->intl_locale_function(), isolate);
419
420 DirectHandle<Map> map;
422 isolate, map,
423 JSFunction::GetDerivedMap(isolate, constructor, constructor));
424
425 DirectHandle<JSLocale> locale =
426 Cast<JSLocale>(isolate->factory()->NewFastOrSlowJSObjectFromMap(map));
428 locale->set_icu_locale(*managed_locale);
429 return locale;
430}
431
432} // namespace
433
435 DirectHandle<JSLocale> locale) {
436 // ICU has limitation on the length of the locale while addLikelySubtags
437 // is called. Work around the issue by only perform addLikelySubtags
438 // on the base locale and merge the extension if needed.
439 icu::Locale source(*(locale->icu_locale()->raw()));
440 icu::Locale result = icu::Locale::createFromName(source.getBaseName());
441 UErrorCode status = U_ZERO_ERROR;
442 result.addLikelySubtags(status);
443 if (strlen(source.getBaseName()) != strlen(result.getBaseName())) {
444 // Base name is changed
445 if (strlen(source.getBaseName()) != strlen(source.getName())) {
446 // the source has extensions, get the extensions from the source.
447 result = icu::LocaleBuilder()
448 .setLocale(source)
449 .setLanguage(result.getLanguage())
450 .setRegion(result.getCountry())
451 .setScript(result.getScript())
452 .setVariant(result.getVariant())
453 .build(status);
454 }
455 } else {
456 // Base name is not changed
457 result = source;
458 }
459 if (U_FAILURE(status) || result.isBogus()) {
460 // Due to https://unicode-org.atlassian.net/browse/ICU-21639
461 // Valid but super long locale will fail. Just throw here for now.
462 THROW_NEW_ERROR(isolate,
463 NewRangeError(MessageTemplate::kLocaleBadParameters));
464 }
465 return Construct(isolate, result);
466}
467
469 DirectHandle<JSLocale> locale) {
470 // ICU has limitation on the length of the locale while minimizeSubtags
471 // is called. Work around the issue by only perform addLikelySubtags
472 // on the base locale and merge the extension if needed.
473 icu::Locale source(*(locale->icu_locale()->raw()));
474 icu::Locale result = icu::Locale::createFromName(source.getBaseName());
475 UErrorCode status = U_ZERO_ERROR;
476 result.minimizeSubtags(status);
477 if (strlen(source.getBaseName()) != strlen(result.getBaseName())) {
478 // Base name is changed
479 if (strlen(source.getBaseName()) != strlen(source.getName())) {
480 // the source has extensions, get the extensions from the source.
481 result = icu::LocaleBuilder()
482 .setLocale(source)
483 .setLanguage(result.getLanguage())
484 .setRegion(result.getCountry())
485 .setScript(result.getScript())
486 .setVariant(result.getVariant())
487 .build(status);
488 }
489 } else {
490 // Base name is not changed
491 result = source;
492 }
493 if (U_FAILURE(status) || result.isBogus()) {
494 // Due to https://unicode-org.atlassian.net/browse/ICU-21639
495 // Valid but super long locale will fail. Just throw here for now.
496 THROW_NEW_ERROR(isolate,
497 NewRangeError(MessageTemplate::kLocaleBadParameters));
498 }
499 return Construct(isolate, result);
500}
501
502template <typename T>
504 Isolate* isolate, const char* key, const char* unicode_key,
505 const icu::Locale& locale, bool (*removes)(const char*), bool commonly_used,
506 bool sort) {
507 Factory* factory = isolate->factory();
508 UErrorCode status = U_ZERO_ERROR;
509 std::string ext =
510 locale.getUnicodeKeywordValue<std::string>(unicode_key, status);
511 if (!ext.empty()) {
512 DirectHandle<FixedArray> fixed_array = factory->NewFixedArray(1);
513 DirectHandle<String> str = factory->NewStringFromAsciiChecked(ext.c_str());
514 fixed_array->set(0, *str);
515 return factory->NewJSArrayWithElements(fixed_array);
516 }
517 status = U_ZERO_ERROR;
518 std::unique_ptr<icu::StringEnumeration> enumeration(
519 T::getKeywordValuesForLocale(key, locale, commonly_used, status));
520 if (U_FAILURE(status)) {
521 THROW_NEW_ERROR(isolate, NewRangeError(MessageTemplate::kIcuError));
522 }
523 return Intl::ToJSArray(isolate, unicode_key, enumeration.get(), removes,
524 sort);
525}
526
527namespace {
528
529MaybeDirectHandle<JSArray> CalendarsForLocale(Isolate* isolate,
530 const icu::Locale& icu_locale,
531 bool commonly_used, bool sort) {
533 isolate, "calendar", "ca", icu_locale, nullptr, commonly_used, sort);
534}
535
536} // namespace
537
539 Isolate* isolate, DirectHandle<JSLocale> locale) {
540 icu::Locale icu_locale(*(locale->icu_locale()->raw()));
541 return CalendarsForLocale(isolate, icu_locale, true, false);
542}
543
545 icu::Locale icu_locale("und");
546 return CalendarsForLocale(isolate, icu_locale, false, true);
547}
548
550 Isolate* isolate, DirectHandle<JSLocale> locale) {
551 icu::Locale icu_locale(*(locale->icu_locale()->raw()));
553 isolate, "collations", "co", icu_locale, Intl::RemoveCollation, true,
554 true);
555}
556
558 Isolate* isolate, DirectHandle<JSLocale> locale) {
559 // Let preferred be loc.[[HourCycle]].
560 // Let locale be loc.[[Locale]].
561 icu::Locale icu_locale(*(locale->icu_locale()->raw()));
562 Factory* factory = isolate->factory();
563
564 // Assert: locale matches the unicode_locale_id production.
565
566 // Let list be a List of 1 or more hour cycle identifiers, which must be
567 // String values indicating either the 12-hour format ("h11", "h12") or the
568 // 24-hour format ("h23", "h24"), sorted in descending preference of those in
569 // common use in the locale for date and time formatting.
570
571 // Return CreateArrayFromListAndPreferred( list, preferred ).
572 DirectHandle<FixedArray> fixed_array = factory->NewFixedArray(1);
573 UErrorCode status = U_ZERO_ERROR;
574 std::string ext =
575 icu_locale.getUnicodeKeywordValue<std::string>("hc", status);
576 if (!ext.empty()) {
577 DirectHandle<String> str = factory->NewStringFromAsciiChecked(ext.c_str());
578 fixed_array->set(0, *str);
579 return factory->NewJSArrayWithElements(fixed_array);
580 }
581 status = U_ZERO_ERROR;
582 std::unique_ptr<icu::DateTimePatternGenerator> generator(
583 icu::DateTimePatternGenerator::createInstance(icu_locale, status));
584 if (U_FAILURE(status)) {
585 THROW_NEW_ERROR(isolate, NewRangeError(MessageTemplate::kIcuError));
586 }
587
588 UDateFormatHourCycle hc = generator->getDefaultHourCycle(status);
589 if (U_FAILURE(status)) {
590 THROW_NEW_ERROR(isolate, NewRangeError(MessageTemplate::kIcuError));
591 }
592 DirectHandle<String> hour_cycle;
593
594 switch (hc) {
595 case UDAT_HOUR_CYCLE_11:
596 hour_cycle = factory->h11_string();
597 break;
598 case UDAT_HOUR_CYCLE_12:
599 hour_cycle = factory->h12_string();
600 break;
601 case UDAT_HOUR_CYCLE_23:
602 hour_cycle = factory->h23_string();
603 break;
604 case UDAT_HOUR_CYCLE_24:
605 hour_cycle = factory->h24_string();
606 break;
607 default:
608 break;
609 }
610 fixed_array->set(0, *hour_cycle);
611 return factory->NewJSArrayWithElements(fixed_array);
612}
613
615 Isolate* isolate, DirectHandle<JSLocale> locale) {
616 // Let preferred be loc.[[NumberingSystem]].
617
618 // Let locale be loc.[[Locale]].
619 icu::Locale icu_locale(*(locale->icu_locale()->raw()));
620 Factory* factory = isolate->factory();
621
622 // Assert: locale matches the unicode_locale_id production.
623
624 // Let list be a List of 1 or more numbering system identifiers, which must be
625 // String values conforming to the type sequence from UTS 35 Unicode Locale
626 // Identifier, section 3.2, sorted in descending preference of those in common
627 // use in the locale for formatting numeric values.
628
629 // Return CreateArrayFromListAndPreferred( list, preferred ).
630 UErrorCode status = U_ZERO_ERROR;
631 DirectHandle<FixedArray> fixed_array = factory->NewFixedArray(1);
632 std::string numbering_system =
633 icu_locale.getUnicodeKeywordValue<std::string>("nu", status);
634 if (numbering_system.empty()) {
635 numbering_system = Intl::GetNumberingSystem(icu_locale);
636 }
638 factory->NewStringFromAsciiChecked(numbering_system.c_str());
639
640 fixed_array->set(0, *str);
641 return factory->NewJSArrayWithElements(fixed_array);
642}
643
645 Isolate* isolate, DirectHandle<JSLocale> locale) {
646 // Let loc be the this value.
647
648 // Perform ? RequireInternalSlot(loc, [[InitializedLocale]])
649
650 // Let locale be loc.[[Locale]].
651 icu::Locale icu_locale(*(locale->icu_locale()->raw()));
652 Factory* factory = isolate->factory();
653
654 // If the unicode_language_id production of locale does not contain the
655 // ["-" unicode_region_subtag] sequence, return undefined.
656 const char* region = icu_locale.getCountry();
657 if (region == nullptr || strlen(region) == 0) {
658 return factory->undefined_value();
659 }
660
661 // Return TimeZonesOfLocale(loc).
662
663 // Let locale be loc.[[Locale]].
664
665 // Assert: locale matches the unicode_locale_id production.
666
667 // Let region be the substring of locale corresponding to the
668 // unicode_region_subtag production of the unicode_language_id.
669
670 // Let list be a List of 1 or more time zone identifiers, which must be String
671 // values indicating a Zone or Link name of the IANA Time Zone Database,
672 // sorted in descending preference of those in common use in region.
673 UErrorCode status = U_ZERO_ERROR;
674 std::unique_ptr<icu::StringEnumeration> enumeration(
675 icu::TimeZone::createTimeZoneIDEnumeration(UCAL_ZONE_TYPE_CANONICAL,
676 region, nullptr, status));
677 if (U_FAILURE(status)) {
678 THROW_NEW_ERROR(isolate, NewRangeError(MessageTemplate::kIcuError));
679 }
680 return Intl::ToJSArray(isolate, nullptr, enumeration.get(), nullptr, true);
681}
682
684 Isolate* isolate, DirectHandle<JSLocale> locale) {
685 // Let loc be the this value.
686
687 // Perform ? RequireInternalSlot(loc, [[InitializedLocale]]).
688
689 // Let locale be loc.[[Locale]].
690
691 // Assert: locale matches the unicode_locale_id production.
692
693 Factory* factory = isolate->factory();
694 // Let info be ! ObjectCreate(%Object.prototype%).
696 factory->NewJSObject(isolate->object_function());
697
698 // Let dir be "ltr".
699 DirectHandle<String> dir = locale->icu_locale()->raw()->isRightToLeft()
700 ? factory->rtl_string()
701 : factory->ltr_string();
702
703 // Perform ! CreateDataPropertyOrThrow(info, "direction", dir).
705 isolate, info, factory->direction_string(), dir, Just(kDontThrow))
706 .FromJust());
707
708 // Return info.
709 return info;
710}
711
713 Isolate* isolate, DirectHandle<JSLocale> locale) {
714 // Let loc be the this value.
715
716 // Perform ? RequireInternalSlot(loc, [[InitializedLocale]]).
717
718 // Let locale be loc.[[Locale]].
719
720 // Assert: locale matches the unicode_locale_id production.
721 Factory* factory = isolate->factory();
722
723 // Let info be ! ObjectCreate(%Object.prototype%).
725 factory->NewJSObject(isolate->object_function());
726 UErrorCode status = U_ZERO_ERROR;
727 std::unique_ptr<icu::Calendar> calendar(
728 icu::Calendar::createInstance(*(locale->icu_locale()->raw()), status));
729 if (U_FAILURE(status)) {
730 THROW_NEW_ERROR(isolate, NewRangeError(MessageTemplate::kIcuError));
731 }
732
733 // Let fd be the weekday value indicating which day of the week is considered
734 // the 'first' day, for calendar purposes, in the locale.
735 int32_t fd = weekdayFromEDaysOfWeek(calendar->getFirstDayOfWeek());
736
737 // Let wi be ! WeekInfoOfLocale(loc).
738 // Let we be ! CreateArrayFromList( wi.[[Weekend]] ).
740 int32_t length = 0;
741 for (int32_t i = 1; i <= 7; i++) {
742 UCalendarDaysOfWeek day =
743 (i == 7) ? UCAL_SUNDAY : static_cast<UCalendarDaysOfWeek>(i + 1);
744 if (UCAL_WEEKDAY != calendar->getDayOfWeekType(day, status)) {
745 wi->set(length++, Smi::FromInt(i));
746 CHECK_LE(length, 2);
747 }
748 }
749 if (length != 2) {
750 wi = wi->RightTrimOrEmpty(isolate, wi, length);
751 }
753
754 if (U_FAILURE(status)) {
755 THROW_NEW_ERROR(isolate, NewRangeError(MessageTemplate::kIcuError));
756 }
757
758 // Perform ! CreateDataPropertyOrThrow(info, "firstDay", fd).
760 isolate, info, factory->firstDay_string(),
761 factory->NewNumberFromInt(fd), Just(kDontThrow))
762 .FromJust());
763
764 // Perform ! CreateDataPropertyOrThrow(info, "weekend", we).
765 CHECK(JSReceiver::CreateDataProperty(isolate, info, factory->weekend_string(),
766 we, Just(kDontThrow))
767 .FromJust());
768
769 // Return info.
770 return info;
771}
772
774 DirectHandle<JSLocale> locale) {
775 Factory* factory = isolate->factory();
776 const char* language = locale->icu_locale()->raw()->getLanguage();
777 constexpr const char kUnd[] = "und";
778 if (strlen(language) == 0) {
779 language = kUnd;
780 }
781 return factory->NewStringFromAsciiChecked(language);
782}
783
785 DirectHandle<JSLocale> locale) {
786 Factory* factory = isolate->factory();
787 const char* script = locale->icu_locale()->raw()->getScript();
788 if (strlen(script) == 0) return factory->undefined_value();
789 return factory->NewStringFromAsciiChecked(script);
790}
791
793 DirectHandle<JSLocale> locale) {
794 Factory* factory = isolate->factory();
795 const char* region = locale->icu_locale()->raw()->getCountry();
796 if (strlen(region) == 0) return factory->undefined_value();
797 return factory->NewStringFromAsciiChecked(region);
798}
799
801 DirectHandle<JSLocale> locale) {
802 icu::Locale icu_locale =
803 icu::Locale::createFromName(locale->icu_locale()->raw()->getBaseName());
804 std::string base_name = Intl::ToLanguageTag(icu_locale).FromJust();
805 return isolate->factory()->NewStringFromAsciiChecked(base_name.c_str());
806}
807
809 DirectHandle<JSLocale> locale) {
810 return UnicodeKeywordValue(isolate, locale, "ca");
811}
812
814 DirectHandle<JSLocale> locale) {
815 return UnicodeKeywordValue(isolate, locale, "kf");
816}
817
819 DirectHandle<JSLocale> locale) {
820 return UnicodeKeywordValue(isolate, locale, "co");
821}
822
824 DirectHandle<JSLocale> locale) {
825 return UnicodeKeywordValue(isolate, locale, "fw");
826}
828 DirectHandle<JSLocale> locale) {
829 return UnicodeKeywordValue(isolate, locale, "hc");
830}
831
833 DirectHandle<JSLocale> locale) {
834 Factory* factory = isolate->factory();
835 icu::Locale* icu_locale = locale->icu_locale()->raw();
836 UErrorCode status = U_ZERO_ERROR;
837 std::string numeric =
838 icu_locale->getUnicodeKeywordValue<std::string>("kn", status);
839 return factory->ToBoolean(numeric == "true");
840}
841
843 DirectHandle<JSLocale> locale) {
844 return UnicodeKeywordValue(isolate, locale, "nu");
845}
846
848 icu::Locale* icu_locale = locale->icu_locale()->raw();
849 return Intl::ToLanguageTag(*icu_locale).FromJust();
850}
851
853 DirectHandle<JSLocale> locale) {
854 std::string locale_str = JSLocale::ToString(locale);
855 return isolate->factory()->NewStringFromAsciiChecked(locale_str.c_str());
856}
857
858} // namespace internal
859} // namespace v8
V8_INLINE T FromJust() const &
Definition v8-maybe.h:64
Handle< Boolean > ToBoolean(bool value)
Handle< Number > NewNumberFromInt(int32_t value)
Handle< String > NewStringFromAsciiChecked(const char *str, AllocationType allocation=AllocationType::kYoung)
Handle< FixedArray > NewFixedArray(int length, AllocationType allocation=AllocationType::kYoung)
Handle< JSObject > NewJSObject(DirectHandle< JSFunction > constructor, AllocationType allocation=AllocationType::kYoung, NewJSObjectType=NewJSObjectType::kNoAPIWrapper)
Definition factory.cc:2985
Handle< JSArray > NewJSArrayWithElements(DirectHandle< FixedArrayBase > elements, ElementsKind elements_kind, int length, AllocationType allocation=AllocationType::kYoung)
Definition factory.cc:3228
static std::string GetNumberingSystem(const icu::Locale &icu_locale)
static bool RemoveCollation(const char *collation)
static V8_WARN_UNUSED_RESULT MaybeDirectHandle< JSArray > ToJSArray(Isolate *isolate, const char *unicode_key, icu::StringEnumeration *enumeration, const std::function< bool(const char *)> &removes, bool sort)
static V8_WARN_UNUSED_RESULT MaybeDirectHandle< JSArray > AvailableCalendars(Isolate *isolate)
Definition js-locale.cc:544
static Maybe< std::string > ToLanguageTag(const icu::Locale &locale)
static V8_EXPORT_PRIVATE V8_WARN_UNUSED_RESULT MaybeHandle< Map > GetDerivedMap(Isolate *isolate, DirectHandle< JSFunction > constructor, DirectHandle< JSReceiver > new_target)
static DirectHandle< String > BaseName(Isolate *isolate, DirectHandle< JSLocale > locale)
Definition js-locale.cc:800
static DirectHandle< Object > Region(Isolate *isolate, DirectHandle< JSLocale > locale)
Definition js-locale.cc:792
static bool Is38AlphaNumList(const std::string &value)
Definition js-locale.cc:206
static DirectHandle< Object > HourCycle(Isolate *isolate, DirectHandle< JSLocale > locale)
Definition js-locale.cc:827
static DirectHandle< Object > Calendar(Isolate *isolate, DirectHandle< JSLocale > locale)
Definition js-locale.cc:808
static bool StartsWithUnicodeLanguageId(const std::string &value)
Definition js-locale.cc:224
static MaybeDirectHandle< JSLocale > Maximize(Isolate *isolate, DirectHandle< JSLocale > locale)
Definition js-locale.cc:434
static DirectHandle< Object > Language(Isolate *isolate, DirectHandle< JSLocale > locale)
Definition js-locale.cc:773
static DirectHandle< String > ToString(Isolate *isolate, DirectHandle< JSLocale > locale)
Definition js-locale.cc:852
static V8_WARN_UNUSED_RESULT MaybeDirectHandle< JSObject > GetTextInfo(Isolate *isolate, DirectHandle< JSLocale > locale)
Definition js-locale.cc:683
static bool Is3Alpha(const std::string &value)
Definition js-locale.cc:218
static V8_WARN_UNUSED_RESULT MaybeDirectHandle< Object > GetTimeZones(Isolate *isolate, DirectHandle< JSLocale > locale)
Definition js-locale.cc:644
static DirectHandle< Object > NumberingSystem(Isolate *isolate, DirectHandle< JSLocale > locale)
Definition js-locale.cc:842
static MaybeDirectHandle< JSLocale > New(Isolate *isolate, DirectHandle< Map > map, DirectHandle< String > locale, DirectHandle< JSReceiver > options)
Definition js-locale.cc:370
static V8_WARN_UNUSED_RESULT MaybeDirectHandle< JSArray > GetNumberingSystems(Isolate *isolate, DirectHandle< JSLocale > locale)
Definition js-locale.cc:614
static V8_WARN_UNUSED_RESULT MaybeDirectHandle< JSObject > GetWeekInfo(Isolate *isolate, DirectHandle< JSLocale > locale)
Definition js-locale.cc:712
static DirectHandle< Object > Script(Isolate *isolate, DirectHandle< JSLocale > locale)
Definition js-locale.cc:784
static V8_WARN_UNUSED_RESULT MaybeDirectHandle< JSArray > GetCalendars(Isolate *isolate, DirectHandle< JSLocale > locale)
Definition js-locale.cc:538
static MaybeDirectHandle< JSLocale > Minimize(Isolate *isolate, DirectHandle< JSLocale > locale)
Definition js-locale.cc:468
static V8_WARN_UNUSED_RESULT MaybeDirectHandle< JSArray > GetHourCycles(Isolate *isolate, DirectHandle< JSLocale > locale)
Definition js-locale.cc:557
static DirectHandle< Object > FirstDayOfWeek(Isolate *isolate, DirectHandle< JSLocale > locale)
Definition js-locale.cc:823
static DirectHandle< Object > Collation(Isolate *isolate, DirectHandle< JSLocale > locale)
Definition js-locale.cc:818
static V8_WARN_UNUSED_RESULT MaybeDirectHandle< JSArray > GetCollations(Isolate *isolate, DirectHandle< JSLocale > locale)
Definition js-locale.cc:549
static DirectHandle< Object > CaseFirst(Isolate *isolate, DirectHandle< JSLocale > locale)
Definition js-locale.cc:813
static DirectHandle< Object > Numeric(Isolate *isolate, DirectHandle< JSLocale > locale)
Definition js-locale.cc:832
static V8_WARN_UNUSED_RESULT Maybe< bool > CreateDataProperty(Isolate *isolate, DirectHandle< JSReceiver > object, DirectHandle< Name > key, DirectHandle< Object > value, Maybe< ShouldThrow > should_throw)
static DirectHandle< Managed< CppType > > From(Isolate *isolate, size_t estimated_size, std::shared_ptr< CppType > shared_ptr, AllocationType allocation_type=AllocationType::kYoung)
Definition managed-inl.h:27
static constexpr Tagged< Smi > FromInt(int value)
Definition smi.h:38
Handle< SharedFunctionInfo > info
#define THROW_NEW_ERROR_RETURN_VALUE(isolate, call, value)
Definition isolate.h:300
#define ASSIGN_RETURN_ON_EXCEPTION(isolate, dst, call)
Definition isolate.h:291
#define THROW_NEW_ERROR(isolate, call)
Definition isolate.h:307
#define MAYBE_RETURN(call, value)
Definition isolate.h:408
Isolate * isolate
std::map< const std::string, const std::string > map
bool is_bool_value
Definition js-locale.cc:44
const std::vector< const char * > * possible_values
Definition js-locale.cc:43
DirectHandle< Object > calendar
ZoneVector< RpoNumber > & result
InstructionOperand source
int int32_t
Definition unicode.cc:40
constexpr bool IsInRange(T value, U lower_limit, U higher_limit)
Definition bounds.h:20
PerThreadAssertScopeDebugOnly< false, SAFEPOINTS_ASSERT, HEAP_ALLOCATION_ASSERT > DisallowGarbageCollection
V8_WARN_UNUSED_RESULT Maybe< bool > GetBoolOption(Isolate *isolate, DirectHandle< JSReceiver > options, const char *property, const char *method_name, bool *result)
Maybe< bool > GetStringOption(Isolate *isolate, DirectHandle< JSReceiver > options, const char *property, const std::vector< const char * > &values, const char *method_name, std::unique_ptr< char[]> *result)
MaybeDirectHandle< JSArray > GetKeywordValuesFromLocale(Isolate *isolate, const char *key, const char *unicode_key, const icu::Locale &locale, bool(*removes)(const char *), bool commonly_used, bool sort)
Definition js-locale.cc:503
Tagged< To > Cast(Tagged< From > value, const v8::SourceLocation &loc=INIT_SOURCE_LOCATION_IN_DEBUG)
Definition casting.h:150
Maybe< T > Nothing()
Definition v8-maybe.h:112
Maybe< T > Just(const T &t)
Definition v8-maybe.h:117
#define CHECK(condition)
Definition logging.h:124
#define CHECK_LE(lhs, rhs)
#define DCHECK_NOT_NULL(val)
Definition logging.h:492
#define DCHECK(condition)
Definition logging.h:482
#define DCHECK_LT(v1, v2)
Definition logging.h:489