6#error Internationalization is expected to be enabled.
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"
52Maybe<bool> InsertOptionsIntoLocale(Isolate* isolate,
53 DirectHandle<JSReceiver> options,
54 icu::LocaleBuilder* builder) {
57 const std::vector<const char*> hour_cycle_values = {
"h11",
"h12",
"h23",
59 const std::vector<const char*> case_first_values = {
"upper",
"lower",
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}}};
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",
88 if (!maybe_found.FromJust())
continue;
90 const char* type = value_str.get();
91 if (strcmp(option_to_bcp47.key,
"fw") == 0) {
92 const std::array<ValueAndType, 8> kFirstDayValuesAndTypes = {
101 for (
const auto& value_to_type : kFirstDayValuesAndTypes) {
102 if (std::strcmp(type, value_to_type.value) == 0) {
103 type = value_to_type.type;
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();
115 if (!uloc_toLegacyType(uloc_toLegacyKey(option_to_bcp47.key), type)) {
118 builder->setUnicodeLocaleKeyword(option_to_bcp47.key, type);
123DirectHandle<Object> UnicodeKeywordValue(Isolate* isolate,
124 DirectHandle<JSLocale> locale,
126 icu::Locale* icu_locale = locale->icu_locale()->raw();
127 UErrorCode status = U_ZERO_ERROR;
129 icu_locale->getUnicodeKeywordValue<std::string>(
key,
status);
130 if (status == U_ILLEGAL_ARGUMENT_ERROR || value.empty()) {
131 return isolate->factory()->undefined_value();
133 if (value ==
"yes") {
136 if (value ==
"true" && strcmp(
key,
"kf") == 0) {
137 return isolate->factory()->NewStringFromStaticChars(
"");
139 return isolate->factory()->NewStringFromAsciiChecked(value.c_str());
142bool IsCheckRange(
const std::string& str,
size_t min,
size_t max,
143 bool(range_check_func)(
char)) {
145 for (
size_t i = 0;
i < str.length();
i++) {
146 if (!range_check_func(str[
i]))
return false;
150bool IsAlpha(
const std::string& str,
size_t min,
size_t max) {
151 return IsCheckRange(str, min, max, [](
char c) ->
bool {
156bool IsDigit(
const std::string& str,
size_t min,
size_t max) {
157 return IsCheckRange(str, min, max, [](
char c) ->
bool {
162bool IsAlphanum(
const std::string& str,
size_t min,
size_t max) {
163 return IsCheckRange(str, min, max, [](
char c) ->
bool {
169bool IsUnicodeLanguageSubtag(
const std::string& value) {
171 return IsAlpha(value, 2, 3) || IsAlpha(value, 5, 8);
174bool IsUnicodeScriptSubtag(
const std::string& value) {
176 return IsAlpha(value, 4, 4);
179bool IsUnicodeRegionSubtag(
const std::string& value) {
181 return IsAlpha(value, 2, 2) || IsDigit(value, 3, 3);
184bool IsDigitAlphanum3(
const std::string& value) {
186 IsAlphanum(value.substr(1), 3, 3);
189bool IsUnicodeVariantSubtag(
const std::string& value) {
191 return IsAlphanum(value, 5, 8) || IsDigitAlphanum3(value);
194bool IsExtensionSingleton(
const std::string& value) {
195 return IsAlphanum(value, 1, 1);
198int32_t weekdayFromEDaysOfWeek(icu::Calendar::EDaysOfWeek eDaysOfWeek) {
199 return (eDaysOfWeek == icu::Calendar::SUNDAY) ? 7 : eDaysOfWeek - 1;
207 std::string value = in;
209 std::size_t found_dash = value.find(
'-');
210 if (found_dash == std::string::npos) {
211 return IsAlphanum(value, 3, 8);
213 if (!IsAlphanum(value.substr(0, found_dash), 3, 8))
return false;
214 value = value.substr(found_dash + 1);
219 return IsAlpha(value, 3, 3);
228 std::vector<std::string> tokens;
230 std::istringstream token_stream(value);
231 while (std::getline(token_stream, token,
'-')) {
232 tokens.push_back(token);
234 if (tokens.empty())
return false;
237 if (!IsUnicodeLanguageSubtag(tokens[0]))
return false;
239 if (tokens.size() == 1)
return true;
242 if (IsExtensionSingleton(tokens[1]))
return true;
245 if (IsUnicodeScriptSubtag(tokens[index])) {
247 if (index == tokens.size())
return true;
249 if (IsUnicodeRegionSubtag(tokens[index])) {
252 while (index < tokens.size()) {
253 if (IsExtensionSingleton(tokens[index]))
return true;
254 if (!IsUnicodeVariantSubtag(tokens[index]))
return false;
263 icu::LocaleBuilder* builder) {
265 if (tag->length() == 0) {
267 isolate, NewRangeError(MessageTemplate::kLocaleNotEmpty),
272 builder->setLanguageTag(
273 {*bcp47_tag,
static_cast<int32_t
>(bcp47_tag.length())});
281 UErrorCode status = U_ZERO_ERROR;
282 icu::Locale canonicalized = builder->build(status);
283 canonicalized.canonicalize(status);
284 if (U_FAILURE(status)) {
287 builder->setLocale(canonicalized);
291 const std::vector<const char*> empty_values = {};
292 std::unique_ptr<char[]> language_str =
nullptr;
293 Maybe<bool> maybe_language =
295 "ApplyOptionsToTag", &language_str);
298 if (maybe_language.FromJust()) {
299 builder->setLanguage(language_str.get());
300 builder->build(status);
303 if (U_FAILURE(status) || language_str[0] ==
'\0' ||
304 IsAlpha(language_str.get(), 4, 4)) {
310 std::unique_ptr<char[]> script_str =
nullptr;
311 Maybe<bool> maybe_script =
313 "ApplyOptionsToTag", &script_str);
316 if (maybe_script.FromJust()) {
317 builder->setScript(script_str.get());
318 builder->build(status);
321 if (U_FAILURE(status) || script_str[0] ==
'\0') {
327 std::unique_ptr<char[]> region_str =
nullptr;
328 Maybe<bool> maybe_region =
330 "ApplyOptionsToTag", ®ion_str);
333 if (maybe_region.FromJust()) {
336 builder->setRegion(region_str.get());
337 builder->build(status);
338 if (U_FAILURE(status) || region_str[0] ==
'\0') {
374 icu::LocaleBuilder builder;
376 ApplyOptionsToTag(isolate, locale_str, options, &builder);
380 NewRangeError(MessageTemplate::kLocaleBadParameters));
384 InsertOptionsIntoLocale(isolate, options, &builder);
386 UErrorCode status = U_ZERO_ERROR;
387 icu::Locale icu_locale = builder.build(status);
389 icu_locale.canonicalize(status);
391 if (!maybe_insert.
FromJust() || U_FAILURE(status)) {
393 NewRangeError(MessageTemplate::kLocaleBadParameters));
399 isolate, 0, std::shared_ptr<icu::Locale>{icu_locale.clone()});
403 Cast<JSLocale>(isolate->factory()->NewFastOrSlowJSObjectFromMap(map));
405 locale->set_icu_locale(*managed_locale);
412 const icu::Locale& icu_locale) {
415 isolate, 0, std::shared_ptr<icu::Locale>{icu_locale.clone()});
417 DirectHandle<JSFunction> constructor(
418 isolate->native_context()->intl_locale_function(), isolate);
420 DirectHandle<Map>
map;
425 DirectHandle<JSLocale> locale =
426 Cast<JSLocale>(isolate->factory()->NewFastOrSlowJSObjectFromMap(map));
428 locale->set_icu_locale(*managed_locale);
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())) {
445 if (strlen(source.getBaseName()) != strlen(source.getName())) {
447 result = icu::LocaleBuilder()
449 .setLanguage(
result.getLanguage())
450 .setRegion(
result.getCountry())
451 .setScript(
result.getScript())
452 .setVariant(
result.getVariant())
459 if (U_FAILURE(status) ||
result.isBogus()) {
463 NewRangeError(MessageTemplate::kLocaleBadParameters));
465 return Construct(isolate,
result);
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())) {
479 if (strlen(source.getBaseName()) != strlen(source.getName())) {
481 result = icu::LocaleBuilder()
483 .setLanguage(
result.getLanguage())
484 .setRegion(
result.getCountry())
485 .setScript(
result.getScript())
486 .setVariant(
result.getVariant())
493 if (U_FAILURE(status) ||
result.isBogus()) {
497 NewRangeError(MessageTemplate::kLocaleBadParameters));
499 return Construct(isolate,
result);
504 Isolate* isolate,
const char*
key,
const char* unicode_key,
505 const icu::Locale& locale,
bool (*removes)(
const char*),
bool commonly_used,
507 Factory* factory = isolate->factory();
508 UErrorCode status = U_ZERO_ERROR;
510 locale.getUnicodeKeywordValue<std::string>(unicode_key,
status);
514 fixed_array->set(0, *str);
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)) {
523 return Intl::ToJSArray(isolate, unicode_key, enumeration.get(), removes,
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);
540 icu::Locale icu_locale(*(locale->icu_locale()->raw()));
541 return CalendarsForLocale(isolate, icu_locale,
true,
false);
545 icu::Locale icu_locale(
"und");
546 return CalendarsForLocale(isolate, icu_locale,
false,
true);
551 icu::Locale icu_locale(*(locale->icu_locale()->raw()));
561 icu::Locale icu_locale(*(locale->icu_locale()->raw()));
562 Factory* factory = isolate->factory();
573 UErrorCode status = U_ZERO_ERROR;
575 icu_locale.getUnicodeKeywordValue<std::string>(
"hc",
status);
578 fixed_array->set(0, *str);
581 status = U_ZERO_ERROR;
582 std::unique_ptr<icu::DateTimePatternGenerator> generator(
583 icu::DateTimePatternGenerator::createInstance(icu_locale, status));
584 if (U_FAILURE(status)) {
588 UDateFormatHourCycle hc = generator->getDefaultHourCycle(status);
589 if (U_FAILURE(status)) {
595 case UDAT_HOUR_CYCLE_11:
596 hour_cycle = factory->h11_string();
598 case UDAT_HOUR_CYCLE_12:
599 hour_cycle = factory->h12_string();
601 case UDAT_HOUR_CYCLE_23:
602 hour_cycle = factory->h23_string();
604 case UDAT_HOUR_CYCLE_24:
605 hour_cycle = factory->h24_string();
610 fixed_array->set(0, *hour_cycle);
619 icu::Locale icu_locale(*(locale->icu_locale()->raw()));
620 Factory* factory = isolate->factory();
630 UErrorCode status = U_ZERO_ERROR;
632 std::string numbering_system =
633 icu_locale.getUnicodeKeywordValue<std::string>(
"nu",
status);
634 if (numbering_system.empty()) {
640 fixed_array->set(0, *str);
651 icu::Locale icu_locale(*(locale->icu_locale()->raw()));
652 Factory* factory = isolate->factory();
656 const char* region = icu_locale.getCountry();
657 if (region ==
nullptr || strlen(region) == 0) {
658 return factory->undefined_value();
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)) {
680 return Intl::ToJSArray(isolate,
nullptr, enumeration.get(),
nullptr,
true);
693 Factory* factory = isolate->factory();
700 ? factory->rtl_string()
701 : factory->ltr_string();
705 isolate, info, factory->direction_string(), dir,
Just(
kDontThrow))
721 Factory* factory = isolate->factory();
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)) {
735 int32_t fd = weekdayFromEDaysOfWeek(
calendar->getFirstDayOfWeek());
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)) {
750 wi = wi->RightTrimOrEmpty(isolate, wi, length);
754 if (U_FAILURE(status)) {
760 isolate, info, factory->firstDay_string(),
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) {
786 Factory* factory = isolate->factory();
787 const char* script = locale->icu_locale()->raw()->getScript();
788 if (strlen(script) == 0)
return factory->undefined_value();
794 Factory* factory = isolate->factory();
795 const char* region = locale->icu_locale()->raw()->getCountry();
796 if (strlen(region) == 0)
return factory->undefined_value();
802 icu::Locale icu_locale =
803 icu::Locale::createFromName(locale->icu_locale()->raw()->getBaseName());
805 return isolate->factory()->NewStringFromAsciiChecked(base_name.c_str());
810 return UnicodeKeywordValue(isolate, locale,
"ca");
815 return UnicodeKeywordValue(isolate, locale,
"kf");
820 return UnicodeKeywordValue(isolate, locale,
"co");
825 return UnicodeKeywordValue(isolate, locale,
"fw");
829 return UnicodeKeywordValue(isolate, locale,
"hc");
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");
844 return UnicodeKeywordValue(isolate, locale,
"nu");
848 icu::Locale* icu_locale = locale->icu_locale()->raw();
855 return isolate->factory()->NewStringFromAsciiChecked(locale_str.c_str());
V8_INLINE T FromJust() const &
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)
Handle< JSArray > NewJSArrayWithElements(DirectHandle< FixedArrayBase > elements, ElementsKind elements_kind, int length, AllocationType allocation=AllocationType::kYoung)
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)
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)
static DirectHandle< Object > Region(Isolate *isolate, DirectHandle< JSLocale > locale)
static bool Is38AlphaNumList(const std::string &value)
static DirectHandle< Object > HourCycle(Isolate *isolate, DirectHandle< JSLocale > locale)
static DirectHandle< Object > Calendar(Isolate *isolate, DirectHandle< JSLocale > locale)
static bool StartsWithUnicodeLanguageId(const std::string &value)
static MaybeDirectHandle< JSLocale > Maximize(Isolate *isolate, DirectHandle< JSLocale > locale)
static DirectHandle< Object > Language(Isolate *isolate, DirectHandle< JSLocale > locale)
static DirectHandle< String > ToString(Isolate *isolate, DirectHandle< JSLocale > locale)
static V8_WARN_UNUSED_RESULT MaybeDirectHandle< JSObject > GetTextInfo(Isolate *isolate, DirectHandle< JSLocale > locale)
static bool Is3Alpha(const std::string &value)
static V8_WARN_UNUSED_RESULT MaybeDirectHandle< Object > GetTimeZones(Isolate *isolate, DirectHandle< JSLocale > locale)
static DirectHandle< Object > NumberingSystem(Isolate *isolate, DirectHandle< JSLocale > locale)
static MaybeDirectHandle< JSLocale > New(Isolate *isolate, DirectHandle< Map > map, DirectHandle< String > locale, DirectHandle< JSReceiver > options)
static V8_WARN_UNUSED_RESULT MaybeDirectHandle< JSArray > GetNumberingSystems(Isolate *isolate, DirectHandle< JSLocale > locale)
static V8_WARN_UNUSED_RESULT MaybeDirectHandle< JSObject > GetWeekInfo(Isolate *isolate, DirectHandle< JSLocale > locale)
static DirectHandle< Object > Script(Isolate *isolate, DirectHandle< JSLocale > locale)
static V8_WARN_UNUSED_RESULT MaybeDirectHandle< JSArray > GetCalendars(Isolate *isolate, DirectHandle< JSLocale > locale)
static MaybeDirectHandle< JSLocale > Minimize(Isolate *isolate, DirectHandle< JSLocale > locale)
static V8_WARN_UNUSED_RESULT MaybeDirectHandle< JSArray > GetHourCycles(Isolate *isolate, DirectHandle< JSLocale > locale)
static DirectHandle< Object > FirstDayOfWeek(Isolate *isolate, DirectHandle< JSLocale > locale)
static DirectHandle< Object > Collation(Isolate *isolate, DirectHandle< JSLocale > locale)
static V8_WARN_UNUSED_RESULT MaybeDirectHandle< JSArray > GetCollations(Isolate *isolate, DirectHandle< JSLocale > locale)
static DirectHandle< Object > CaseFirst(Isolate *isolate, DirectHandle< JSLocale > locale)
static DirectHandle< Object > Numeric(Isolate *isolate, DirectHandle< JSLocale > locale)
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)
static constexpr Tagged< Smi > FromInt(int value)
Handle< SharedFunctionInfo > info
#define THROW_NEW_ERROR_RETURN_VALUE(isolate, call, value)
#define ASSIGN_RETURN_ON_EXCEPTION(isolate, dst, call)
#define THROW_NEW_ERROR(isolate, call)
#define MAYBE_RETURN(call, value)
const std::vector< const char * > * possible_values
DirectHandle< Object > calendar
ZoneVector< RpoNumber > & result
InstructionOperand source
constexpr bool IsInRange(T value, U lower_limit, U higher_limit)
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)
Tagged< To > Cast(Tagged< From > value, const v8::SourceLocation &loc=INIT_SOURCE_LOCATION_IN_DEBUG)
Maybe< T > Just(const T &t)
#define CHECK_LE(lhs, rhs)
#define DCHECK_NOT_NULL(val)
#define DCHECK(condition)
#define DCHECK_LT(v1, v2)