14514f5e3Sopenharmony_ci/*
24514f5e3Sopenharmony_ci * Copyright (c) 2021 Huawei Device Co., Ltd.
34514f5e3Sopenharmony_ci * Licensed under the Apache License, Version 2.0 (the "License");
44514f5e3Sopenharmony_ci * you may not use this file except in compliance with the License.
54514f5e3Sopenharmony_ci * You may obtain a copy of the License at
64514f5e3Sopenharmony_ci *
74514f5e3Sopenharmony_ci *     http://www.apache.org/licenses/LICENSE-2.0
84514f5e3Sopenharmony_ci *
94514f5e3Sopenharmony_ci * Unless required by applicable law or agreed to in writing, software
104514f5e3Sopenharmony_ci * distributed under the License is distributed on an "AS IS" BASIS,
114514f5e3Sopenharmony_ci * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
124514f5e3Sopenharmony_ci * See the License for the specific language governing permissions and
134514f5e3Sopenharmony_ci * limitations under the License.
144514f5e3Sopenharmony_ci */
154514f5e3Sopenharmony_ci
164514f5e3Sopenharmony_ci#include "ecmascript/js_locale.h"
174514f5e3Sopenharmony_ci
184514f5e3Sopenharmony_ci#include "ecmascript/intl/locale_helper.h"
194514f5e3Sopenharmony_ci#include "ecmascript/object_factory-inl.h"
204514f5e3Sopenharmony_ci#include "ecmascript/checkpoint/thread_state_transition.h"
214514f5e3Sopenharmony_ci
224514f5e3Sopenharmony_ci#if defined(__clang__)
234514f5e3Sopenharmony_ci#pragma clang diagnostic push
244514f5e3Sopenharmony_ci#pragma clang diagnostic ignored "-Wshadow"
254514f5e3Sopenharmony_ci#elif defined(__GNUC__)
264514f5e3Sopenharmony_ci#pragma GCC diagnostic push
274514f5e3Sopenharmony_ci#pragma GCC diagnostic ignored "-Wshadow"
284514f5e3Sopenharmony_ci#endif
294514f5e3Sopenharmony_ci#include "unicode/localebuilder.h"
304514f5e3Sopenharmony_ci#if defined(__clang__)
314514f5e3Sopenharmony_ci#pragma clang diagnostic pop
324514f5e3Sopenharmony_ci#elif defined(__GNUC__)
334514f5e3Sopenharmony_ci#pragma GCC diagnostic pop
344514f5e3Sopenharmony_ci#endif
354514f5e3Sopenharmony_ci
364514f5e3Sopenharmony_cinamespace panda::ecmascript {
374514f5e3Sopenharmony_ciconst std::string JSLocale::LATN_STRING = "latn";
384514f5e3Sopenharmony_ci
394514f5e3Sopenharmony_ciconst std::vector<LocaleMatcherOption> JSLocale::LOCALE_MATCHER_OPTION = {
404514f5e3Sopenharmony_ci    LocaleMatcherOption::LOOKUP, LocaleMatcherOption::BEST_FIT
414514f5e3Sopenharmony_ci};
424514f5e3Sopenharmony_ciconst std::vector<std::string> JSLocale::LOCALE_MATCHER_OPTION_NAME = {
434514f5e3Sopenharmony_ci    "lookup", "best fit"
444514f5e3Sopenharmony_ci};
454514f5e3Sopenharmony_ci
464514f5e3Sopenharmony_ciconst std::map<std::string, std::set<std::string>> JSLocale::LOCALE_MAP = {
474514f5e3Sopenharmony_ci    {"hc", {"h11", "h12", "h23", "h24"}},
484514f5e3Sopenharmony_ci    {"lb", {"strict", "normal", "loose"}},
494514f5e3Sopenharmony_ci    {"kn", {"true", "false"}},
504514f5e3Sopenharmony_ci    {"kf", {"upper", "lower", "false"}}
514514f5e3Sopenharmony_ci};
524514f5e3Sopenharmony_ci
534514f5e3Sopenharmony_ciconst std::vector<std::string> JSLocale::HOUR_CYCLE = {"h11", "h12", "h23", "h24"};
544514f5e3Sopenharmony_ciconst std::vector<std::string> JSLocale::CASE_FIRST = {"upper", "lower", "false"};
554514f5e3Sopenharmony_ci
564514f5e3Sopenharmony_ciconst std::set<std::string> JSLocale::WELL_NUMBER_SYSTEM = {"native", "traditio", "finance"};
574514f5e3Sopenharmony_ciconst std::set<std::string> JSLocale::WELL_COLLATION = {"standard", "search"};
584514f5e3Sopenharmony_ci// 6.4.1 IsValidTimeZoneName ( timeZone )
594514f5e3Sopenharmony_cibool JSLocale::IsValidTimeZoneName(const icu::TimeZone &tz)
604514f5e3Sopenharmony_ci{
614514f5e3Sopenharmony_ci    UErrorCode status = U_ZERO_ERROR;
624514f5e3Sopenharmony_ci    icu::UnicodeString id;
634514f5e3Sopenharmony_ci    tz.getID(id);
644514f5e3Sopenharmony_ci    icu::UnicodeString canonical;
654514f5e3Sopenharmony_ci    icu::TimeZone::getCanonicalID(id, canonical, status);
664514f5e3Sopenharmony_ci    UBool canonicalFlag = (canonical != icu::UnicodeString("Etc/Unknown", -1, US_INV));
674514f5e3Sopenharmony_ci    return (U_SUCCESS(status) != 0) && (canonicalFlag != 0);
684514f5e3Sopenharmony_ci}
694514f5e3Sopenharmony_ci
704514f5e3Sopenharmony_ci// 9.2.3 LookupMatcher ( availableLocales, requestedLocales )
714514f5e3Sopenharmony_ciJSHandle<EcmaString> JSLocale::LookupMatcher(JSThread *thread, const JSHandle<TaggedArray> &availableLocales,
724514f5e3Sopenharmony_ci                                             const JSHandle<TaggedArray> &requestedLocales)
734514f5e3Sopenharmony_ci{
744514f5e3Sopenharmony_ci    MatcherResult result = {std::string(), std::string()};
754514f5e3Sopenharmony_ci    ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
764514f5e3Sopenharmony_ci    // 1. Let result be a new Record.
774514f5e3Sopenharmony_ci    // 2. For each element locale of requestedLocales in List order, do
784514f5e3Sopenharmony_ci    std::vector<std::string> availableStringLocales = GetAvailableStringLocales(thread, availableLocales);
794514f5e3Sopenharmony_ci    uint32_t length = requestedLocales->GetLength();
804514f5e3Sopenharmony_ci    JSMutableHandle<EcmaString> locale(thread, JSTaggedValue::Undefined());
814514f5e3Sopenharmony_ci    for (uint32_t i = 0; i < length; ++i) {
824514f5e3Sopenharmony_ci        locale.Update(requestedLocales->Get(thread, i));
834514f5e3Sopenharmony_ci        // 2. a. Let noExtensionsLocale be the String value that is locale
844514f5e3Sopenharmony_ci        //       with all Unicode locale extension sequences removed.
854514f5e3Sopenharmony_ci        intl::LocaleHelper::ParsedLocale parsedResult = intl::LocaleHelper::HandleLocale(locale);
864514f5e3Sopenharmony_ci        // 2. b. Let availableLocale be BestAvailableLocale(availableLocales, noExtensionsLocale).
874514f5e3Sopenharmony_ci        std::string availableLocale =
884514f5e3Sopenharmony_ci            intl::LocaleHelper::BestAvailableLocale(availableStringLocales, parsedResult.base);
894514f5e3Sopenharmony_ci        // 2. c. If availableLocale is not undefined, append locale to the end of subset.
904514f5e3Sopenharmony_ci        if (!availableLocale.empty()) {
914514f5e3Sopenharmony_ci            result = {std::string(), std::string()};
924514f5e3Sopenharmony_ci            // 2. c. i. Set result.[[locale]] to availableLocale.
934514f5e3Sopenharmony_ci            result.locale = availableLocale;
944514f5e3Sopenharmony_ci            // 2. c. ii. If locale and noExtensionsLocale are not the same String value, then
954514f5e3Sopenharmony_ci            // 2. c. ii. 1. Let extension be the String value consisting of  the first substring of locale that is a
964514f5e3Sopenharmony_ci            //              Unicode locale extension sequence.
974514f5e3Sopenharmony_ci            if (!parsedResult.extension.empty()) {
984514f5e3Sopenharmony_ci                result.extension = parsedResult.extension;
994514f5e3Sopenharmony_ci            }
1004514f5e3Sopenharmony_ci            // 2. c. ii. 2. Set result.[[extension]] to extension.
1014514f5e3Sopenharmony_ci            std::string res = result.locale + result.extension;
1024514f5e3Sopenharmony_ci            // 2. c. iii. Return result.
1034514f5e3Sopenharmony_ci            return factory->NewFromStdString(res);
1044514f5e3Sopenharmony_ci        }
1054514f5e3Sopenharmony_ci    }
1064514f5e3Sopenharmony_ci
1074514f5e3Sopenharmony_ci    // 3. Let defLocale be DefaultLocale();
1084514f5e3Sopenharmony_ci    // 4. Set result.[[locale]] to defLocale.
1094514f5e3Sopenharmony_ci    // 5. Return result.
1104514f5e3Sopenharmony_ci    auto defLocale = intl::LocaleHelper::StdStringDefaultLocale(thread);
1114514f5e3Sopenharmony_ci    result.locale = defLocale;
1124514f5e3Sopenharmony_ci    return factory->NewFromStdString(result.locale);
1134514f5e3Sopenharmony_ci}
1144514f5e3Sopenharmony_ci
1154514f5e3Sopenharmony_ciicu::LocaleMatcher BuildLocaleMatcher(JSThread *thread, uint32_t *availableLength, UErrorCode *status,
1164514f5e3Sopenharmony_ci                                      const JSHandle<TaggedArray> &availableLocales)
1174514f5e3Sopenharmony_ci{
1184514f5e3Sopenharmony_ci    std::string locale = intl::LocaleHelper::StdStringDefaultLocale(thread);
1194514f5e3Sopenharmony_ci    icu::Locale defaultLocale = icu::Locale::forLanguageTag(locale, *status);
1204514f5e3Sopenharmony_ci    ASSERT_PRINT(U_SUCCESS(*status), "icu::Locale::forLanguageTag failed");
1214514f5e3Sopenharmony_ci    icu::LocaleMatcher::Builder builder;
1224514f5e3Sopenharmony_ci    builder.setDefaultLocale(&defaultLocale);
1234514f5e3Sopenharmony_ci    uint32_t length = availableLocales->GetLength();
1244514f5e3Sopenharmony_ci
1254514f5e3Sopenharmony_ci    JSMutableHandle<EcmaString> item(thread, JSTaggedValue::Undefined());
1264514f5e3Sopenharmony_ci    for (*availableLength = 0; *availableLength < length; ++(*availableLength)) {
1274514f5e3Sopenharmony_ci        item.Update(availableLocales->Get(thread, *availableLength));
1284514f5e3Sopenharmony_ci        std::string itemStr = intl::LocaleHelper::ConvertToStdString(item);
1294514f5e3Sopenharmony_ci        icu::Locale localeForLanguageTag = icu::Locale::forLanguageTag(itemStr, *status);
1304514f5e3Sopenharmony_ci        if (U_SUCCESS(*status) != 0) {
1314514f5e3Sopenharmony_ci            builder.addSupportedLocale(localeForLanguageTag);
1324514f5e3Sopenharmony_ci        } else {
1334514f5e3Sopenharmony_ci            break;
1344514f5e3Sopenharmony_ci        }
1354514f5e3Sopenharmony_ci    }
1364514f5e3Sopenharmony_ci    *status = U_ZERO_ERROR;
1374514f5e3Sopenharmony_ci    return builder.build(*status);
1384514f5e3Sopenharmony_ci}
1394514f5e3Sopenharmony_ci
1404514f5e3Sopenharmony_ci// 9.2.4 BestFitMatcher ( availableLocales, requestedLocales )
1414514f5e3Sopenharmony_ciJSHandle<EcmaString> JSLocale::BestFitMatcher(JSThread *thread, const JSHandle<TaggedArray> &availableLocales,
1424514f5e3Sopenharmony_ci                                              const JSHandle<TaggedArray> &requestedLocales)
1434514f5e3Sopenharmony_ci{
1444514f5e3Sopenharmony_ci    ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
1454514f5e3Sopenharmony_ci    UErrorCode status = U_ZERO_ERROR;
1464514f5e3Sopenharmony_ci    uint32_t availableLength = availableLocales->GetLength();
1474514f5e3Sopenharmony_ci    icu::LocaleMatcher matcher = BuildLocaleMatcher(thread, &availableLength, &status, availableLocales);
1484514f5e3Sopenharmony_ci    ASSERT(U_SUCCESS(status));
1494514f5e3Sopenharmony_ci
1504514f5e3Sopenharmony_ci    uint32_t requestedLocalesLength = requestedLocales->GetLength();
1514514f5e3Sopenharmony_ci    JSIntlIterator iter(requestedLocales, requestedLocalesLength);
1524514f5e3Sopenharmony_ci    auto bestFit = matcher.getBestMatch(iter, status)->toLanguageTag<std::string>(status);
1534514f5e3Sopenharmony_ci
1544514f5e3Sopenharmony_ci    if (U_FAILURE(status) != 0) {
1554514f5e3Sopenharmony_ci        return intl::LocaleHelper::DefaultLocale(thread);
1564514f5e3Sopenharmony_ci    }
1574514f5e3Sopenharmony_ci
1584514f5e3Sopenharmony_ci    for (uint32_t i = 0; i < requestedLocalesLength; ++i) {
1594514f5e3Sopenharmony_ci        if (iter[i] == bestFit) {
1604514f5e3Sopenharmony_ci            return JSHandle<EcmaString>(thread, requestedLocales->Get(thread, i));
1614514f5e3Sopenharmony_ci        }
1624514f5e3Sopenharmony_ci    }
1634514f5e3Sopenharmony_ci    return factory->NewFromStdString(bestFit);
1644514f5e3Sopenharmony_ci}
1654514f5e3Sopenharmony_ci
1664514f5e3Sopenharmony_ci// 9.2.8 LookupSupportedLocales ( availableLocales, requestedLocales )
1674514f5e3Sopenharmony_ciJSHandle<TaggedArray> JSLocale::LookupSupportedLocales(JSThread *thread, const JSHandle<TaggedArray> &availableLocales,
1684514f5e3Sopenharmony_ci                                                       const JSHandle<TaggedArray> &requestedLocales)
1694514f5e3Sopenharmony_ci{
1704514f5e3Sopenharmony_ci    ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
1714514f5e3Sopenharmony_ci    uint32_t length = requestedLocales->GetLength();
1724514f5e3Sopenharmony_ci    JSMutableHandle<EcmaString> item(thread, JSTaggedValue::Undefined());
1734514f5e3Sopenharmony_ci    std::vector<std::string> availableStringLocales = GetAvailableStringLocales(thread, availableLocales);
1744514f5e3Sopenharmony_ci    std::vector<std::string> convertedLocales;
1754514f5e3Sopenharmony_ci    convertedLocales.reserve(length);
1764514f5e3Sopenharmony_ci    std::vector<uint32_t> indexAvailableLocales;
1774514f5e3Sopenharmony_ci    indexAvailableLocales.reserve(length);
1784514f5e3Sopenharmony_ci    for (uint32_t i = 0; i < length; ++i) {
1794514f5e3Sopenharmony_ci        item.Update(requestedLocales->Get(thread, i));
1804514f5e3Sopenharmony_ci        convertedLocales.push_back(intl::LocaleHelper::ConvertToStdString(item));
1814514f5e3Sopenharmony_ci    }
1824514f5e3Sopenharmony_ci    // 1. For each element locale of requestedLocales in List order, do
1834514f5e3Sopenharmony_ci    //    a. Let noExtensionsLocale be the String value that is locale with all Unicode locale extension sequences
1844514f5e3Sopenharmony_ci    //       removed.
1854514f5e3Sopenharmony_ci    //    b. Let availableLocale be BestAvailableLocale(availableLocales, noExtensionsLocale).
1864514f5e3Sopenharmony_ci    //    c. If availableLocale is not undefined, append locale to the end of subset.
1874514f5e3Sopenharmony_ci    {
1884514f5e3Sopenharmony_ci        ThreadNativeScope nativeScope(thread);
1894514f5e3Sopenharmony_ci        for (uint32_t i = 0; i < length; ++i) {
1904514f5e3Sopenharmony_ci            intl::LocaleHelper::ParsedLocale foundationResult = intl::LocaleHelper::HandleLocale(convertedLocales[i]);
1914514f5e3Sopenharmony_ci            std::string availableLocale =
1924514f5e3Sopenharmony_ci                intl::LocaleHelper::BestAvailableLocale(availableStringLocales, foundationResult.base);
1934514f5e3Sopenharmony_ci            if (!availableLocale.empty()) {
1944514f5e3Sopenharmony_ci                indexAvailableLocales.push_back(i);
1954514f5e3Sopenharmony_ci            }
1964514f5e3Sopenharmony_ci        }
1974514f5e3Sopenharmony_ci    }
1984514f5e3Sopenharmony_ci    // 2. Let subset be a new empty List.
1994514f5e3Sopenharmony_ci    JSHandle<TaggedArray> subset = factory->NewTaggedArray(indexAvailableLocales.size());
2004514f5e3Sopenharmony_ci    uint32_t index = 0;
2014514f5e3Sopenharmony_ci    for (uint32_t i = 0; i < indexAvailableLocales.size(); ++i) {
2024514f5e3Sopenharmony_ci        subset->Set(thread, index++, requestedLocales->Get(thread, indexAvailableLocales[i]));
2034514f5e3Sopenharmony_ci    }
2044514f5e3Sopenharmony_ci    // 3. Return subset.
2054514f5e3Sopenharmony_ci    return subset;
2064514f5e3Sopenharmony_ci}
2074514f5e3Sopenharmony_ci
2084514f5e3Sopenharmony_ci// 9.2.9 BestFitSupportedLocales ( availableLocales, requestedLocales )
2094514f5e3Sopenharmony_ciJSHandle<TaggedArray> JSLocale::BestFitSupportedLocales(JSThread *thread, const JSHandle<TaggedArray> &availableLocales,
2104514f5e3Sopenharmony_ci                                                        const JSHandle<TaggedArray> &requestedLocales)
2114514f5e3Sopenharmony_ci{
2124514f5e3Sopenharmony_ci    UErrorCode status = U_ZERO_ERROR;
2134514f5e3Sopenharmony_ci    uint32_t requestLength = requestedLocales->GetLength();
2144514f5e3Sopenharmony_ci    uint32_t availableLength = availableLocales->GetLength();
2154514f5e3Sopenharmony_ci    icu::LocaleMatcher matcher = BuildLocaleMatcher(thread, &availableLength, &status, availableLocales);
2164514f5e3Sopenharmony_ci    ASSERT(U_SUCCESS(status));
2174514f5e3Sopenharmony_ci
2184514f5e3Sopenharmony_ci    ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
2194514f5e3Sopenharmony_ci    JSHandle<EcmaString> defaultLocale = intl::LocaleHelper::DefaultLocale(thread);
2204514f5e3Sopenharmony_ci    JSHandle<TaggedArray> result = factory->NewTaggedArray(requestLength);
2214514f5e3Sopenharmony_ci
2224514f5e3Sopenharmony_ci    uint32_t index = 0;
2234514f5e3Sopenharmony_ci    JSMutableHandle<EcmaString> locale(thread, JSTaggedValue::Undefined());
2244514f5e3Sopenharmony_ci    for (uint32_t i = 0; i < requestLength; ++i) {
2254514f5e3Sopenharmony_ci        locale.Update(requestedLocales->Get(thread, i));
2264514f5e3Sopenharmony_ci        if (EcmaStringAccessor::StringsAreEqual(thread->GetEcmaVM(), locale, defaultLocale)) {
2274514f5e3Sopenharmony_ci            result->Set(thread, index++, locale.GetTaggedValue());
2284514f5e3Sopenharmony_ci        } else {
2294514f5e3Sopenharmony_ci            status = U_ZERO_ERROR;
2304514f5e3Sopenharmony_ci            std::string localeStr = intl::LocaleHelper::ConvertToStdString(locale);
2314514f5e3Sopenharmony_ci            icu::Locale desired = icu::Locale::forLanguageTag(localeStr, status);
2324514f5e3Sopenharmony_ci            auto bestFit = matcher.getBestMatch(desired, status)->toLanguageTag<std::string>(status);
2334514f5e3Sopenharmony_ci            if ((U_SUCCESS(status) != 0) &&
2344514f5e3Sopenharmony_ci                EcmaStringAccessor::StringsAreEqual(thread->GetEcmaVM(), locale, factory->NewFromStdString(bestFit))) {
2354514f5e3Sopenharmony_ci                result->Set(thread, index++, locale.GetTaggedValue());
2364514f5e3Sopenharmony_ci            }
2374514f5e3Sopenharmony_ci        }
2384514f5e3Sopenharmony_ci    }
2394514f5e3Sopenharmony_ci    result = TaggedArray::SetCapacity(thread, result, index);
2404514f5e3Sopenharmony_ci    return result;
2414514f5e3Sopenharmony_ci}
2424514f5e3Sopenharmony_ci
2434514f5e3Sopenharmony_ci// 9.2.10 SupportedLocales ( availableLocales, requestedLocales, options )
2444514f5e3Sopenharmony_ciJSHandle<JSArray> JSLocale::SupportedLocales(JSThread *thread, const JSHandle<TaggedArray> &availableLocales,
2454514f5e3Sopenharmony_ci                                             const JSHandle<TaggedArray> &requestedLocales,
2464514f5e3Sopenharmony_ci                                             const JSHandle<JSTaggedValue> &options)
2474514f5e3Sopenharmony_ci{
2484514f5e3Sopenharmony_ci    const GlobalEnvConstants *globalConst = thread->GlobalConstants();
2494514f5e3Sopenharmony_ci    // 1. If options is not undefined, then
2504514f5e3Sopenharmony_ci    //    a. Let options be ? ToObject(options).
2514514f5e3Sopenharmony_ci    //    b. Let matcher be ? GetOption(options, "localeMatcher", "string", « "lookup", "best fit" », "best fit").
2524514f5e3Sopenharmony_ci    // 2. Else, let matcher be "best fit".
2534514f5e3Sopenharmony_ci    if (!options->IsUndefined()) {
2544514f5e3Sopenharmony_ci        JSHandle<JSObject> obj = JSTaggedValue::ToObject(thread, options);
2554514f5e3Sopenharmony_ci        RETURN_HANDLE_IF_ABRUPT_COMPLETION(JSArray, thread);
2564514f5e3Sopenharmony_ci
2574514f5e3Sopenharmony_ci        [[maybe_unused]] LocaleMatcherOption matcher = GetOptionOfString<LocaleMatcherOption>(thread,
2584514f5e3Sopenharmony_ci            obj, globalConst->GetHandledLocaleMatcherString(),
2594514f5e3Sopenharmony_ci            JSLocale::LOCALE_MATCHER_OPTION, JSLocale::LOCALE_MATCHER_OPTION_NAME,
2604514f5e3Sopenharmony_ci            LocaleMatcherOption::BEST_FIT);
2614514f5e3Sopenharmony_ci        RETURN_HANDLE_IF_ABRUPT_COMPLETION(JSArray, thread);
2624514f5e3Sopenharmony_ci    }
2634514f5e3Sopenharmony_ci
2644514f5e3Sopenharmony_ci    // 3. If matcher is "best fit", then
2654514f5e3Sopenharmony_ci    //    a. Let supportedLocales be BestFitSupportedLocales(availableLocales, requestedLocales).
2664514f5e3Sopenharmony_ci    // 4. Else,
2674514f5e3Sopenharmony_ci    //    a. Let supportedLocales be LookupSupportedLocales(availableLocales, requestedLocales).
2684514f5e3Sopenharmony_ci    JSMutableHandle<TaggedArray> supportedLocales(thread, JSTaggedValue::Undefined());
2694514f5e3Sopenharmony_ci    supportedLocales.Update(LookupSupportedLocales(thread, availableLocales, requestedLocales).GetTaggedValue());
2704514f5e3Sopenharmony_ci
2714514f5e3Sopenharmony_ci    JSHandle<JSArray> subset = JSArray::CreateArrayFromList(thread, supportedLocales);
2724514f5e3Sopenharmony_ci    // 5. Return CreateArrayFromList(supportedLocales).
2734514f5e3Sopenharmony_ci    return subset;
2744514f5e3Sopenharmony_ci}
2754514f5e3Sopenharmony_ci
2764514f5e3Sopenharmony_ci// 9.2.11 GetOption ( options, property, type, values, fallback )
2774514f5e3Sopenharmony_ciJSHandle<JSTaggedValue> JSLocale::GetOption(JSThread *thread, const JSHandle<JSObject> &options,
2784514f5e3Sopenharmony_ci                                            const JSHandle<JSTaggedValue> &property, OptionType type,
2794514f5e3Sopenharmony_ci                                            const JSHandle<JSTaggedValue> &values,
2804514f5e3Sopenharmony_ci                                            const JSHandle<JSTaggedValue> &fallback)
2814514f5e3Sopenharmony_ci{
2824514f5e3Sopenharmony_ci    // 1. Let value be ? Get(options, property).
2834514f5e3Sopenharmony_ci    JSHandle<JSTaggedValue> value = JSObject::GetProperty(thread, options, property).GetValue();
2844514f5e3Sopenharmony_ci    RETURN_HANDLE_IF_ABRUPT_COMPLETION(JSTaggedValue, thread);
2854514f5e3Sopenharmony_ci
2864514f5e3Sopenharmony_ci    // 2. If value is not undefined, then
2874514f5e3Sopenharmony_ci    if (!value->IsUndefined()) {
2884514f5e3Sopenharmony_ci        // a. Assert: type is "boolean" or "string".
2894514f5e3Sopenharmony_ci        ASSERT_PRINT(type == OptionType::BOOLEAN || type == OptionType::STRING, "type is not boolean or string");
2904514f5e3Sopenharmony_ci
2914514f5e3Sopenharmony_ci        // b. If type is "boolean", then
2924514f5e3Sopenharmony_ci        //    i. Let value be ToBoolean(value).
2934514f5e3Sopenharmony_ci        if (type == OptionType::BOOLEAN) {
2944514f5e3Sopenharmony_ci            value = JSHandle<JSTaggedValue>(thread, JSTaggedValue(value->ToBoolean()));
2954514f5e3Sopenharmony_ci        }
2964514f5e3Sopenharmony_ci        // c. If type is "string", then
2974514f5e3Sopenharmony_ci        //    i. Let value be ? ToString(value).
2984514f5e3Sopenharmony_ci        if (type == OptionType::STRING) {
2994514f5e3Sopenharmony_ci            JSHandle<EcmaString> str = JSTaggedValue::ToString(thread, value);
3004514f5e3Sopenharmony_ci            RETURN_HANDLE_IF_ABRUPT_COMPLETION(JSTaggedValue, thread);
3014514f5e3Sopenharmony_ci            value = JSHandle<JSTaggedValue>(thread, str.GetTaggedValue());
3024514f5e3Sopenharmony_ci        }
3034514f5e3Sopenharmony_ci
3044514f5e3Sopenharmony_ci        // d. If values is not undefined, then
3054514f5e3Sopenharmony_ci        //    i. If values does not contain an element equal to value, throw a RangeError exception.
3064514f5e3Sopenharmony_ci        if (!values->IsUndefined()) {
3074514f5e3Sopenharmony_ci            bool isExist = false;
3084514f5e3Sopenharmony_ci            JSHandle<TaggedArray> valuesArray = JSHandle<TaggedArray>::Cast(values);
3094514f5e3Sopenharmony_ci            uint32_t length = valuesArray->GetLength();
3104514f5e3Sopenharmony_ci            for (uint32_t i = 0; i < length; i++) {
3114514f5e3Sopenharmony_ci                if (JSTaggedValue::SameValue(valuesArray->Get(thread, i), value.GetTaggedValue())) {
3124514f5e3Sopenharmony_ci                    isExist = true;
3134514f5e3Sopenharmony_ci                }
3144514f5e3Sopenharmony_ci            }
3154514f5e3Sopenharmony_ci            if (!isExist) {
3164514f5e3Sopenharmony_ci                JSHandle<JSTaggedValue> exception(thread, JSTaggedValue::Exception());
3174514f5e3Sopenharmony_ci                THROW_RANGE_ERROR_AND_RETURN(thread, "values does not contain an element equal to value", exception);
3184514f5e3Sopenharmony_ci            }
3194514f5e3Sopenharmony_ci        }
3204514f5e3Sopenharmony_ci        // e. Return value.
3214514f5e3Sopenharmony_ci        return value;
3224514f5e3Sopenharmony_ci    }
3234514f5e3Sopenharmony_ci    // 3. Else, return fallback.
3244514f5e3Sopenharmony_ci    return fallback;
3254514f5e3Sopenharmony_ci}
3264514f5e3Sopenharmony_ci
3274514f5e3Sopenharmony_cibool JSLocale::GetOptionOfString(JSThread *thread, const JSHandle<JSObject> &options,
3284514f5e3Sopenharmony_ci                                 const JSHandle<JSTaggedValue> &property, const std::vector<std::string> &values,
3294514f5e3Sopenharmony_ci                                 std::string *optionValue)
3304514f5e3Sopenharmony_ci{
3314514f5e3Sopenharmony_ci    // 1. Let value be ? Get(options, property).
3324514f5e3Sopenharmony_ci    OperationResult operationResult = JSObject::GetProperty(thread, options, property);
3334514f5e3Sopenharmony_ci    RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, false);
3344514f5e3Sopenharmony_ci    JSHandle<JSTaggedValue> value = operationResult.GetValue();
3354514f5e3Sopenharmony_ci    // 2. If value is not undefined, then
3364514f5e3Sopenharmony_ci    if (value->IsUndefined()) {
3374514f5e3Sopenharmony_ci        return false;
3384514f5e3Sopenharmony_ci    }
3394514f5e3Sopenharmony_ci    //    c. If type is "string" "string", then
3404514f5e3Sopenharmony_ci    //       i. Let value be ? ToString(value).
3414514f5e3Sopenharmony_ci    JSHandle<EcmaString> valueEStr = JSTaggedValue::ToString(thread, value);
3424514f5e3Sopenharmony_ci    RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, false);
3434514f5e3Sopenharmony_ci    if (EcmaStringAccessor(valueEStr).IsUtf16()) {
3444514f5e3Sopenharmony_ci        THROW_RANGE_ERROR_AND_RETURN(thread, "Value out of range for locale options property", false);
3454514f5e3Sopenharmony_ci    }
3464514f5e3Sopenharmony_ci    *optionValue = intl::LocaleHelper::ConvertToStdString(valueEStr);
3474514f5e3Sopenharmony_ci    if (values.empty()) {
3484514f5e3Sopenharmony_ci        return true;
3494514f5e3Sopenharmony_ci    }
3504514f5e3Sopenharmony_ci    // d. If values is not undefined, then
3514514f5e3Sopenharmony_ci    //    i. If values does not contain an element equal to value, throw a RangeError exception.
3524514f5e3Sopenharmony_ci    for (const auto &item : values) {
3534514f5e3Sopenharmony_ci        if (item == *optionValue) {
3544514f5e3Sopenharmony_ci            return true;
3554514f5e3Sopenharmony_ci        }
3564514f5e3Sopenharmony_ci    }
3574514f5e3Sopenharmony_ci    THROW_RANGE_ERROR_AND_RETURN(thread, "Value out of range for locale options property", false);
3584514f5e3Sopenharmony_ci}
3594514f5e3Sopenharmony_ci
3604514f5e3Sopenharmony_ci// 9.2.12 DefaultNumberOption ( value, minimum, maximum, fallback )
3614514f5e3Sopenharmony_ciint JSLocale::DefaultNumberOption(JSThread *thread, const JSHandle<JSTaggedValue> &value, int minimum, int maximum,
3624514f5e3Sopenharmony_ci                                  int fallback)
3634514f5e3Sopenharmony_ci{
3644514f5e3Sopenharmony_ci    // 1. If value is not undefined, then
3654514f5e3Sopenharmony_ci    if (!value->IsUndefined()) {
3664514f5e3Sopenharmony_ci        // a. Let value be ? ToNumber(value).
3674514f5e3Sopenharmony_ci        JSTaggedNumber number = JSTaggedValue::ToNumber(thread, value);
3684514f5e3Sopenharmony_ci        RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, fallback);
3694514f5e3Sopenharmony_ci        // b. If value is NaN or less than minimum or greater than maximum, throw a RangeError exception.
3704514f5e3Sopenharmony_ci        double num = JSTaggedValue(number).GetNumber();
3714514f5e3Sopenharmony_ci        if (std::isnan(num) || num < minimum || num > maximum) {
3724514f5e3Sopenharmony_ci            THROW_RANGE_ERROR_AND_RETURN(thread, "", fallback);
3734514f5e3Sopenharmony_ci        }
3744514f5e3Sopenharmony_ci        // c. Return floor(value).
3754514f5e3Sopenharmony_ci        return std::floor(num);
3764514f5e3Sopenharmony_ci    }
3774514f5e3Sopenharmony_ci    // 2. Else, return fallback.
3784514f5e3Sopenharmony_ci    return fallback;
3794514f5e3Sopenharmony_ci}
3804514f5e3Sopenharmony_ci
3814514f5e3Sopenharmony_ci// 9.2.13 GetNumberOption ( options, property, minimum, maximum, fallback )
3824514f5e3Sopenharmony_ciint JSLocale::GetNumberOption(JSThread *thread, const JSHandle<JSObject> &options,
3834514f5e3Sopenharmony_ci                              const JSHandle<JSTaggedValue> &property, int min, int max, int fallback)
3844514f5e3Sopenharmony_ci{
3854514f5e3Sopenharmony_ci    // 1. Let value be ? Get(options, property).
3864514f5e3Sopenharmony_ci    JSHandle<JSTaggedValue> value = JSObject::GetProperty(thread, options, property).GetValue();
3874514f5e3Sopenharmony_ci    RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, fallback);
3884514f5e3Sopenharmony_ci
3894514f5e3Sopenharmony_ci    // 2. Return ? DefaultNumberOption(value, minimum, maximum, fallback).
3904514f5e3Sopenharmony_ci    int result = DefaultNumberOption(thread, value, min, max, fallback);
3914514f5e3Sopenharmony_ci    RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, fallback);
3924514f5e3Sopenharmony_ci    return result;
3934514f5e3Sopenharmony_ci}
3944514f5e3Sopenharmony_ci
3954514f5e3Sopenharmony_ci// 9.2.5 UnicodeExtensionValue ( extension, key )
3964514f5e3Sopenharmony_cistd::string JSLocale::UnicodeExtensionValue(const std::string extension, const std::string key)
3974514f5e3Sopenharmony_ci{
3984514f5e3Sopenharmony_ci    // 1. Assert: The number of elements in key is 2.
3994514f5e3Sopenharmony_ci    // 2. Let size be the number of elements in extension.
4004514f5e3Sopenharmony_ci    ASSERT(key.size() == INTL_INDEX_TWO || key.size() == INTL_INDEX_ZERO);
4014514f5e3Sopenharmony_ci    size_t size = extension.size();
4024514f5e3Sopenharmony_ci    // 3. Let searchValue be the concatenation of "-" , key, and "-".
4034514f5e3Sopenharmony_ci    std::string searchValue = "-" + key + "-";
4044514f5e3Sopenharmony_ci    // 4. Let pos be Call(%StringProto_indexOf%, extension, « searchValue »).
4054514f5e3Sopenharmony_ci    size_t pos = extension.find(searchValue);
4064514f5e3Sopenharmony_ci    // 5. If pos ≠ -1, then
4074514f5e3Sopenharmony_ci    if (pos != std::string::npos) {
4084514f5e3Sopenharmony_ci        // a. Let start be pos + 4.
4094514f5e3Sopenharmony_ci        size_t start = pos + INTL_INDEX_FOUR;
4104514f5e3Sopenharmony_ci        // b. Let end be start.
4114514f5e3Sopenharmony_ci        size_t end = start;
4124514f5e3Sopenharmony_ci        // c. Let k be start.
4134514f5e3Sopenharmony_ci        size_t k = start;
4144514f5e3Sopenharmony_ci        // d. Let done be false.
4154514f5e3Sopenharmony_ci        bool done = false;
4164514f5e3Sopenharmony_ci        // e. Repeat, while done is false
4174514f5e3Sopenharmony_ci        while (!done) {
4184514f5e3Sopenharmony_ci            // i. Let e be Call(%StringProto_indexOf%, extension, « "-", k »).
4194514f5e3Sopenharmony_ci            size_t e = extension.find("-", k);
4204514f5e3Sopenharmony_ci            size_t len;
4214514f5e3Sopenharmony_ci            // ii. If e = -1, let len be size - k; else let len be e - k.
4224514f5e3Sopenharmony_ci            if (e == std::string::npos) {
4234514f5e3Sopenharmony_ci                len = size - k;
4244514f5e3Sopenharmony_ci            } else {
4254514f5e3Sopenharmony_ci                len = e - k;
4264514f5e3Sopenharmony_ci            }
4274514f5e3Sopenharmony_ci            // iii. If len = 2, then
4284514f5e3Sopenharmony_ci            //     1. Let done be true.
4294514f5e3Sopenharmony_ci            if (len == INTL_INDEX_TWO) {
4304514f5e3Sopenharmony_ci                done = true;
4314514f5e3Sopenharmony_ci            // iv. Else if e = -1, then
4324514f5e3Sopenharmony_ci            //    1. Let end be size.
4334514f5e3Sopenharmony_ci            //    2. Let done be true.
4344514f5e3Sopenharmony_ci            } else if (e == std::string::npos) {
4354514f5e3Sopenharmony_ci                end = size;
4364514f5e3Sopenharmony_ci                done = true;
4374514f5e3Sopenharmony_ci            // v. Else,
4384514f5e3Sopenharmony_ci            //   1. Let end be e.
4394514f5e3Sopenharmony_ci            //   2. Let k be e + 1.
4404514f5e3Sopenharmony_ci            } else {
4414514f5e3Sopenharmony_ci                end = e;
4424514f5e3Sopenharmony_ci                k = e + INTL_INDEX_ONE;
4434514f5e3Sopenharmony_ci            }
4444514f5e3Sopenharmony_ci        }
4454514f5e3Sopenharmony_ci        // f. Return the String value equal to the substring of extension consisting of the code units at indices.
4464514f5e3Sopenharmony_ci        // start (inclusive) through end (exclusive).
4474514f5e3Sopenharmony_ci        std::string result = extension.substr(start, end - start);
4484514f5e3Sopenharmony_ci        return result;
4494514f5e3Sopenharmony_ci    }
4504514f5e3Sopenharmony_ci    // 6. Let searchValue be the concatenation of "-" and key.
4514514f5e3Sopenharmony_ci    searchValue = "-" + key;
4524514f5e3Sopenharmony_ci    // 7. Let pos be Call(%StringProto_indexOf%, extension, « searchValue »).
4534514f5e3Sopenharmony_ci    pos = extension.find(searchValue);
4544514f5e3Sopenharmony_ci    // 8. If pos ≠ -1 and pos + 3 = size, then
4554514f5e3Sopenharmony_ci    //    a. Return the empty String.
4564514f5e3Sopenharmony_ci    if (pos != std::string::npos && pos + INTL_INDEX_THREE == size) {
4574514f5e3Sopenharmony_ci        return "";
4584514f5e3Sopenharmony_ci    }
4594514f5e3Sopenharmony_ci    // 9. Return undefined.
4604514f5e3Sopenharmony_ci    return "undefined";
4614514f5e3Sopenharmony_ci}
4624514f5e3Sopenharmony_ci
4634514f5e3Sopenharmony_ciResolvedLocale JSLocale::ResolveLocale(JSThread *thread, const JSHandle<TaggedArray> &availableLocales,
4644514f5e3Sopenharmony_ci                                       const JSHandle<TaggedArray> &requestedLocales,
4654514f5e3Sopenharmony_ci                                       [[maybe_unused]] LocaleMatcherOption matcher,
4664514f5e3Sopenharmony_ci                                       const std::set<std::string> &relevantExtensionKeys)
4674514f5e3Sopenharmony_ci{
4684514f5e3Sopenharmony_ci    // 1. Let matcher be options.[[localeMatcher]].
4694514f5e3Sopenharmony_ci    // 2. If matcher is "lookup" "lookup", then
4704514f5e3Sopenharmony_ci    //    a. Let r be LookupMatcher(availableLocales, requestedLocales).
4714514f5e3Sopenharmony_ci    // 3. Else,
4724514f5e3Sopenharmony_ci    //    a. Let r be BestFitMatcher(availableLocales, requestedLocales).
4734514f5e3Sopenharmony_ci    JSMutableHandle<EcmaString> locale(thread, JSTaggedValue::Undefined());
4744514f5e3Sopenharmony_ci    if (availableLocales->GetLength() == 0 && requestedLocales->GetLength() == 0) {
4754514f5e3Sopenharmony_ci        locale.Update(intl::LocaleHelper::DefaultLocale(thread).GetTaggedValue());
4764514f5e3Sopenharmony_ci    } else {
4774514f5e3Sopenharmony_ci        locale.Update(LookupMatcher(thread, availableLocales, requestedLocales).GetTaggedValue());
4784514f5e3Sopenharmony_ci    }
4794514f5e3Sopenharmony_ci
4804514f5e3Sopenharmony_ci    // 4. Let foundLocale be r.[[locale]].
4814514f5e3Sopenharmony_ci    // 5. Let result be a new Record.
4824514f5e3Sopenharmony_ci    // 6. Set result.[[dataLocale]] to foundLocale.
4834514f5e3Sopenharmony_ci    // 7. Let supportedExtension be "-u".
4844514f5e3Sopenharmony_ci    std::string foundLocale = intl::LocaleHelper::ConvertToStdString(locale);
4854514f5e3Sopenharmony_ci    icu::Locale foundLocaleData = BuildICULocale(foundLocale);
4864514f5e3Sopenharmony_ci    ResolvedLocale result;
4874514f5e3Sopenharmony_ci    result.localeData = foundLocaleData;
4884514f5e3Sopenharmony_ci    JSHandle<EcmaString> tag = intl::LocaleHelper::ToLanguageTag(thread, foundLocaleData);
4894514f5e3Sopenharmony_ci    result.locale = intl::LocaleHelper::ConvertToStdString(tag);
4904514f5e3Sopenharmony_ci    std::string supportedExtension = "-u";
4914514f5e3Sopenharmony_ci    icu::LocaleBuilder localeBuilder;
4924514f5e3Sopenharmony_ci    localeBuilder.setLocale(foundLocaleData).clearExtensions();
4934514f5e3Sopenharmony_ci    // 8. For each element key of relevantExtensionKeys in List order, do
4944514f5e3Sopenharmony_ci    for (auto &key : relevantExtensionKeys) {
4954514f5e3Sopenharmony_ci        auto doubleMatch = foundLocale.find(key);
4964514f5e3Sopenharmony_ci        if (doubleMatch == std::string::npos) {
4974514f5e3Sopenharmony_ci            continue;
4984514f5e3Sopenharmony_ci        }
4994514f5e3Sopenharmony_ci        UErrorCode status = U_ZERO_ERROR;
5004514f5e3Sopenharmony_ci        std::set<std::string> keyLocaleData;
5014514f5e3Sopenharmony_ci        std::unique_ptr<icu::StringEnumeration> wellFormKey(foundLocaleData.createKeywords(status));
5024514f5e3Sopenharmony_ci        if (U_FAILURE(status) != 0) {
5034514f5e3Sopenharmony_ci            return result;
5044514f5e3Sopenharmony_ci        }
5054514f5e3Sopenharmony_ci        if (!wellFormKey) {
5064514f5e3Sopenharmony_ci            return result;
5074514f5e3Sopenharmony_ci        }
5084514f5e3Sopenharmony_ci        std::string value;
5094514f5e3Sopenharmony_ci
5104514f5e3Sopenharmony_ci        // c. Let keyLocaleData be foundLocaleData.[[<key>]].
5114514f5e3Sopenharmony_ci        // e. Let value be keyLocaleData[0].
5124514f5e3Sopenharmony_ci        if ((key != "ca") && (key != "co") && (key != "nu")) {
5134514f5e3Sopenharmony_ci            auto find = JSLocale::LOCALE_MAP.find(key);
5144514f5e3Sopenharmony_ci            if (find != JSLocale::LOCALE_MAP.end()) {
5154514f5e3Sopenharmony_ci                keyLocaleData = find->second;
5164514f5e3Sopenharmony_ci            }
5174514f5e3Sopenharmony_ci            if (key == "") {
5184514f5e3Sopenharmony_ci                keyLocaleData = JSLocale::LOCALE_MAP.at("lb");
5194514f5e3Sopenharmony_ci            }
5204514f5e3Sopenharmony_ci            value = *keyLocaleData.begin();
5214514f5e3Sopenharmony_ci        }
5224514f5e3Sopenharmony_ci
5234514f5e3Sopenharmony_ci        // g. Let supportedExtensionAddition be "".
5244514f5e3Sopenharmony_ci        // h. If r has an [[extension]] field, then
5254514f5e3Sopenharmony_ci        std::string supportedExtensionAddition;
5264514f5e3Sopenharmony_ci        size_t found = foundLocale.find("-u-");
5274514f5e3Sopenharmony_ci        if (found != std::string::npos) {
5284514f5e3Sopenharmony_ci            std::string extension = foundLocale.substr(found + INTL_INDEX_ONE);
5294514f5e3Sopenharmony_ci
5304514f5e3Sopenharmony_ci            // i. Let requestedValue be UnicodeExtensionValue(r.[[extension]], key).
5314514f5e3Sopenharmony_ci            std::string requestedValue = UnicodeExtensionValue(extension, key);
5324514f5e3Sopenharmony_ci            if (key == "kn" && requestedValue.empty()) {
5334514f5e3Sopenharmony_ci                requestedValue = "true";
5344514f5e3Sopenharmony_ci            }
5354514f5e3Sopenharmony_ci
5364514f5e3Sopenharmony_ci            // ii. If requestedValue is not undefined, then
5374514f5e3Sopenharmony_ci            if (requestedValue != "undefined") {
5384514f5e3Sopenharmony_ci                // 1. If requestedValue is not the empty String, then
5394514f5e3Sopenharmony_ci                if (!requestedValue.empty()) {
5404514f5e3Sopenharmony_ci                    // a. If keyLocaleData contains requestedValue, then
5414514f5e3Sopenharmony_ci                    //    i. Let value be requestedValue.
5424514f5e3Sopenharmony_ci                    //    ii. Let supportedExtensionAddition be the concatenation of "-", key, "-", and value.
5434514f5e3Sopenharmony_ci                    if (key == "ca" || key == "co") {
5444514f5e3Sopenharmony_ci                        if (key == "co") {
5454514f5e3Sopenharmony_ci                            bool isValidValue = IsWellCollation(foundLocaleData, requestedValue);
5464514f5e3Sopenharmony_ci                            if (!isValidValue) {
5474514f5e3Sopenharmony_ci                                continue;
5484514f5e3Sopenharmony_ci                            }
5494514f5e3Sopenharmony_ci                            value = requestedValue;
5504514f5e3Sopenharmony_ci                            supportedExtensionAddition = "-" + key + "-" + value;
5514514f5e3Sopenharmony_ci                            localeBuilder.setUnicodeLocaleKeyword(key, requestedValue);
5524514f5e3Sopenharmony_ci                        } else {
5534514f5e3Sopenharmony_ci                            bool isValidValue = IsWellCalendar(foundLocaleData, requestedValue);
5544514f5e3Sopenharmony_ci                            if (!isValidValue) {
5554514f5e3Sopenharmony_ci                                continue;
5564514f5e3Sopenharmony_ci                            }
5574514f5e3Sopenharmony_ci                            value = requestedValue;
5584514f5e3Sopenharmony_ci                            supportedExtensionAddition = "-" + key + "-" + value;
5594514f5e3Sopenharmony_ci                            localeBuilder.setUnicodeLocaleKeyword(key, requestedValue);
5604514f5e3Sopenharmony_ci                        }
5614514f5e3Sopenharmony_ci                    } else if (key == "nu") {
5624514f5e3Sopenharmony_ci                        bool isValidValue = IsWellNumberingSystem(requestedValue);
5634514f5e3Sopenharmony_ci                        if (!isValidValue) {
5644514f5e3Sopenharmony_ci                            continue;
5654514f5e3Sopenharmony_ci                        }
5664514f5e3Sopenharmony_ci                        value = requestedValue;
5674514f5e3Sopenharmony_ci                        supportedExtensionAddition = "-" + key + "-" + value;
5684514f5e3Sopenharmony_ci                        localeBuilder.setUnicodeLocaleKeyword(key, requestedValue);
5694514f5e3Sopenharmony_ci                    } else if (keyLocaleData.find(requestedValue) != keyLocaleData.end()) {
5704514f5e3Sopenharmony_ci                        value = requestedValue;
5714514f5e3Sopenharmony_ci                        supportedExtensionAddition = "-" + key + "-" + value;
5724514f5e3Sopenharmony_ci                        localeBuilder.setUnicodeLocaleKeyword(key, requestedValue);
5734514f5e3Sopenharmony_ci                    }
5744514f5e3Sopenharmony_ci                }
5754514f5e3Sopenharmony_ci            }
5764514f5e3Sopenharmony_ci        }
5774514f5e3Sopenharmony_ci        result.extensions.emplace(key, value);
5784514f5e3Sopenharmony_ci        supportedExtension += supportedExtensionAddition;
5794514f5e3Sopenharmony_ci    }
5804514f5e3Sopenharmony_ci    size_t found = foundLocale.find("-u-");
5814514f5e3Sopenharmony_ci    if (found != std::string::npos) {
5824514f5e3Sopenharmony_ci        foundLocale = foundLocale.substr(0, found);
5834514f5e3Sopenharmony_ci    }
5844514f5e3Sopenharmony_ci
5854514f5e3Sopenharmony_ci    // 9. If the number of elements in supportedExtension is greater than 2, then
5864514f5e3Sopenharmony_ci    if (supportedExtension.size() > 2) {
5874514f5e3Sopenharmony_ci        // a. Let privateIndex be Call(%StringProto_indexOf%, foundLocale, « "-x-" »).
5884514f5e3Sopenharmony_ci        size_t privateIndex = foundLocale.find("-x-");
5894514f5e3Sopenharmony_ci        // b. If privateIndex = -1, then
5904514f5e3Sopenharmony_ci        //    i. Let foundLocale be the concatenation of foundLocale and supportedExtension.
5914514f5e3Sopenharmony_ci        if (privateIndex == std::string::npos) {
5924514f5e3Sopenharmony_ci            foundLocale = foundLocale + supportedExtension;
5934514f5e3Sopenharmony_ci        } else {
5944514f5e3Sopenharmony_ci            std::string preExtension = foundLocale.substr(0, privateIndex);
5954514f5e3Sopenharmony_ci            std::string postExtension = foundLocale.substr(privateIndex);
5964514f5e3Sopenharmony_ci            foundLocale = preExtension + supportedExtension + postExtension;
5974514f5e3Sopenharmony_ci        }
5984514f5e3Sopenharmony_ci
5994514f5e3Sopenharmony_ci        tag = intl::LocaleHelper::ToLanguageTag(thread, foundLocaleData);
6004514f5e3Sopenharmony_ci        if (!intl::LocaleHelper::IsStructurallyValidLanguageTag(tag)) {
6014514f5e3Sopenharmony_ci            result.extensions.erase(result.extensions.begin(), result.extensions.end());
6024514f5e3Sopenharmony_ci            result.locale = foundLocale;
6034514f5e3Sopenharmony_ci        }
6044514f5e3Sopenharmony_ci        tag = intl::LocaleHelper::CanonicalizeUnicodeLocaleId(thread, tag);
6054514f5e3Sopenharmony_ci        foundLocale = intl::LocaleHelper::ConvertToStdString(tag);
6064514f5e3Sopenharmony_ci    }
6074514f5e3Sopenharmony_ci
6084514f5e3Sopenharmony_ci    // 10. Set result.[[locale]] to foundLocale.
6094514f5e3Sopenharmony_ci    result.locale = foundLocale;
6104514f5e3Sopenharmony_ci    UErrorCode status = U_ZERO_ERROR;
6114514f5e3Sopenharmony_ci    foundLocaleData = localeBuilder.build(status);
6124514f5e3Sopenharmony_ci    result.localeData = foundLocaleData;
6134514f5e3Sopenharmony_ci
6144514f5e3Sopenharmony_ci    // 11. Return result.
6154514f5e3Sopenharmony_ci    return result;
6164514f5e3Sopenharmony_ci}
6174514f5e3Sopenharmony_ci
6184514f5e3Sopenharmony_ciicu::Locale JSLocale::BuildICULocale(const std::string &bcp47Locale)
6194514f5e3Sopenharmony_ci{
6204514f5e3Sopenharmony_ci    UErrorCode status = U_ZERO_ERROR;
6214514f5e3Sopenharmony_ci    icu::Locale icuLocale = icu::Locale::forLanguageTag(bcp47Locale, status);
6224514f5e3Sopenharmony_ci    return icuLocale;
6234514f5e3Sopenharmony_ci}
6244514f5e3Sopenharmony_ci
6254514f5e3Sopenharmony_ciJSHandle<TaggedArray> JSLocale::ConstructLocaleList(JSThread *thread,
6264514f5e3Sopenharmony_ci                                                    const std::vector<std::string> &icuAvailableLocales)
6274514f5e3Sopenharmony_ci{
6284514f5e3Sopenharmony_ci    EcmaVM *ecmaVm = thread->GetEcmaVM();
6294514f5e3Sopenharmony_ci    ObjectFactory *factory = ecmaVm->GetFactory();
6304514f5e3Sopenharmony_ci    JSHandle<TaggedArray> locales = factory->NewTaggedArray(icuAvailableLocales.size());
6314514f5e3Sopenharmony_ci    int32_t index = 0;
6324514f5e3Sopenharmony_ci    for (const std::string &locale : icuAvailableLocales) {
6334514f5e3Sopenharmony_ci        JSHandle<EcmaString> localeStr = factory->NewFromStdString(locale);
6344514f5e3Sopenharmony_ci        locales->Set(thread, index++, localeStr);
6354514f5e3Sopenharmony_ci    }
6364514f5e3Sopenharmony_ci    return locales;
6374514f5e3Sopenharmony_ci}
6384514f5e3Sopenharmony_ci
6394514f5e3Sopenharmony_cistd::string JSLocale::GetNumberingSystem(const icu::Locale &icuLocale)
6404514f5e3Sopenharmony_ci{
6414514f5e3Sopenharmony_ci    UErrorCode status = U_ZERO_ERROR;
6424514f5e3Sopenharmony_ci    std::unique_ptr<icu::NumberingSystem> numberingSystem(icu::NumberingSystem::createInstance(icuLocale, status));
6434514f5e3Sopenharmony_ci    if (U_SUCCESS(status) != 0) {
6444514f5e3Sopenharmony_ci        return numberingSystem->getName();
6454514f5e3Sopenharmony_ci    }
6464514f5e3Sopenharmony_ci    return JSLocale::LATN_STRING;
6474514f5e3Sopenharmony_ci}
6484514f5e3Sopenharmony_ci
6494514f5e3Sopenharmony_cibool JSLocale::IsWellFormedCurrencyCode(const std::string &currency)
6504514f5e3Sopenharmony_ci{
6514514f5e3Sopenharmony_ci    if (currency.length() != INTL_INDEX_THREE) {
6524514f5e3Sopenharmony_ci        return false;
6534514f5e3Sopenharmony_ci    }
6544514f5e3Sopenharmony_ci    return (IsAToZ(currency[INTL_INDEX_ZERO]) && IsAToZ(currency[INTL_INDEX_ONE]) && IsAToZ(currency[INTL_INDEX_TWO]));
6554514f5e3Sopenharmony_ci}
6564514f5e3Sopenharmony_ci
6574514f5e3Sopenharmony_cibool JSLocale::IsWellFormedCalendarCode(const std::string& calendar)
6584514f5e3Sopenharmony_ci{
6594514f5e3Sopenharmony_ci    std::string value = calendar;
6604514f5e3Sopenharmony_ci    while (true) {
6614514f5e3Sopenharmony_ci        std::size_t found_dash = value.find('-');
6624514f5e3Sopenharmony_ci        if (found_dash == std::string::npos) {
6634514f5e3Sopenharmony_ci            return IsAlphanum(value, INTL_INDEX_THREE, INTL_INDEX_EIGHT);
6644514f5e3Sopenharmony_ci        }
6654514f5e3Sopenharmony_ci        if (!IsAlphanum(value.substr(0, found_dash), INTL_INDEX_THREE, INTL_INDEX_EIGHT)) {
6664514f5e3Sopenharmony_ci            return false;
6674514f5e3Sopenharmony_ci        }
6684514f5e3Sopenharmony_ci        value = value.substr(found_dash + 1);
6694514f5e3Sopenharmony_ci    }
6704514f5e3Sopenharmony_ci}
6714514f5e3Sopenharmony_ci
6724514f5e3Sopenharmony_ciJSHandle<JSObject> JSLocale::PutElement(JSThread *thread, int index, const JSHandle<JSArray> &array,
6734514f5e3Sopenharmony_ci                                        const JSHandle<JSTaggedValue> &fieldTypeString,
6744514f5e3Sopenharmony_ci                                        const JSHandle<JSTaggedValue> &value)
6754514f5e3Sopenharmony_ci{
6764514f5e3Sopenharmony_ci    auto ecmaVm = thread->GetEcmaVM();
6774514f5e3Sopenharmony_ci    ObjectFactory *factory = ecmaVm->GetFactory();
6784514f5e3Sopenharmony_ci
6794514f5e3Sopenharmony_ci    // Let record be ! ObjectCreate(%ObjectPrototype%).
6804514f5e3Sopenharmony_ci    JSHandle<JSObject> record = factory->NewEmptyJSObject();
6814514f5e3Sopenharmony_ci
6824514f5e3Sopenharmony_ci    auto globalConst = thread->GlobalConstants();
6834514f5e3Sopenharmony_ci    // obj.type = field_type_string
6844514f5e3Sopenharmony_ci    JSObject::CreateDataPropertyOrThrow(thread, record, globalConst->GetHandledTypeString(), fieldTypeString);
6854514f5e3Sopenharmony_ci    RETURN_HANDLE_IF_ABRUPT_COMPLETION(JSObject, thread);
6864514f5e3Sopenharmony_ci    // obj.value = value
6874514f5e3Sopenharmony_ci    JSObject::CreateDataPropertyOrThrow(thread, record, globalConst->GetHandledValueString(), value);
6884514f5e3Sopenharmony_ci    RETURN_HANDLE_IF_ABRUPT_COMPLETION(JSObject, thread);
6894514f5e3Sopenharmony_ci
6904514f5e3Sopenharmony_ci    JSTaggedValue::SetProperty(thread, JSHandle<JSTaggedValue>::Cast(array), index,
6914514f5e3Sopenharmony_ci                               JSHandle<JSTaggedValue>::Cast(record), true);
6924514f5e3Sopenharmony_ci    RETURN_HANDLE_IF_ABRUPT_COMPLETION(JSObject, thread);
6934514f5e3Sopenharmony_ci    return record;
6944514f5e3Sopenharmony_ci}
6954514f5e3Sopenharmony_ci
6964514f5e3Sopenharmony_ci// 9.2.11 GetOption ( options, property, type, values, fallback )
6974514f5e3Sopenharmony_cibool JSLocale::GetOptionOfBool(JSThread *thread, const JSHandle<JSObject> &options,
6984514f5e3Sopenharmony_ci                               const JSHandle<JSTaggedValue> &property, bool fallback, bool *res)
6994514f5e3Sopenharmony_ci{
7004514f5e3Sopenharmony_ci    // 1. Let value be ? Get(options, property).
7014514f5e3Sopenharmony_ci    OperationResult operationResult = JSObject::GetProperty(thread, options, property);
7024514f5e3Sopenharmony_ci    RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, false);
7034514f5e3Sopenharmony_ci    JSHandle<JSTaggedValue> value = operationResult.GetValue();
7044514f5e3Sopenharmony_ci    *res = fallback;
7054514f5e3Sopenharmony_ci    // 2. If value is not undefined, then
7064514f5e3Sopenharmony_ci    if (!value->IsUndefined()) {
7074514f5e3Sopenharmony_ci        // b. Let value be ToBoolean(value).
7084514f5e3Sopenharmony_ci        *res = value->ToBoolean();
7094514f5e3Sopenharmony_ci        return true;
7104514f5e3Sopenharmony_ci    }
7114514f5e3Sopenharmony_ci    // 3. not found
7124514f5e3Sopenharmony_ci    return false;
7134514f5e3Sopenharmony_ci}
7144514f5e3Sopenharmony_ci
7154514f5e3Sopenharmony_ciJSHandle<JSTaggedValue> JSLocale::GetNumberFieldType(JSThread *thread, JSTaggedValue x, int32_t fieldId)
7164514f5e3Sopenharmony_ci{
7174514f5e3Sopenharmony_ci    ASSERT(x.IsNumber() || x.IsBigInt());
7184514f5e3Sopenharmony_ci    double number = 0;
7194514f5e3Sopenharmony_ci    auto globalConst = thread->GlobalConstants();
7204514f5e3Sopenharmony_ci    if (static_cast<UNumberFormatFields>(fieldId) == UNUM_INTEGER_FIELD) {
7214514f5e3Sopenharmony_ci        number = x.IsBigInt() ? number : x.GetNumber();
7224514f5e3Sopenharmony_ci        if (x.IsBigInt() || std::isfinite(number)) {
7234514f5e3Sopenharmony_ci            return globalConst->GetHandledIntegerString();
7244514f5e3Sopenharmony_ci        }
7254514f5e3Sopenharmony_ci        if (std::isnan(number)) {
7264514f5e3Sopenharmony_ci            return globalConst->GetHandledNanString();
7274514f5e3Sopenharmony_ci        }
7284514f5e3Sopenharmony_ci        return globalConst->GetHandledInfinityString();
7294514f5e3Sopenharmony_ci    } else if (static_cast<UNumberFormatFields>(fieldId) == UNUM_FRACTION_FIELD) {
7304514f5e3Sopenharmony_ci        return globalConst->GetHandledFractionString();
7314514f5e3Sopenharmony_ci    } else if (static_cast<UNumberFormatFields>(fieldId) == UNUM_DECIMAL_SEPARATOR_FIELD) {
7324514f5e3Sopenharmony_ci        return globalConst->GetHandledDecimalString();
7334514f5e3Sopenharmony_ci    } else if (static_cast<UNumberFormatFields>(fieldId) == UNUM_GROUPING_SEPARATOR_FIELD) {
7344514f5e3Sopenharmony_ci        return globalConst->GetHandledGroupString();
7354514f5e3Sopenharmony_ci    } else if (static_cast<UNumberFormatFields>(fieldId) == UNUM_CURRENCY_FIELD) {
7364514f5e3Sopenharmony_ci        return globalConst->GetHandledCurrencyString();
7374514f5e3Sopenharmony_ci    } else if (static_cast<UNumberFormatFields>(fieldId) == UNUM_PERCENT_FIELD) {
7384514f5e3Sopenharmony_ci        return globalConst->GetHandledPercentSignString();
7394514f5e3Sopenharmony_ci    } else if (static_cast<UNumberFormatFields>(fieldId) == UNUM_SIGN_FIELD) {
7404514f5e3Sopenharmony_ci        if (x.IsBigInt()) {
7414514f5e3Sopenharmony_ci            JSHandle<JSTaggedValue> bigint(thread, x);
7424514f5e3Sopenharmony_ci            JSHandle<BigInt> value(thread, JSTaggedValue::ToBigInt(thread, bigint));
7434514f5e3Sopenharmony_ci            RETURN_HANDLE_IF_ABRUPT_COMPLETION(JSTaggedValue, thread);
7444514f5e3Sopenharmony_ci            return value->GetSign() ? globalConst->GetHandledMinusSignString()
7454514f5e3Sopenharmony_ci                                    : globalConst->GetHandledPlusSignString();
7464514f5e3Sopenharmony_ci        }
7474514f5e3Sopenharmony_ci        number = x.GetNumber();
7484514f5e3Sopenharmony_ci        return std::signbit(number) ? globalConst->GetHandledMinusSignString()
7494514f5e3Sopenharmony_ci                                    : globalConst->GetHandledPlusSignString();
7504514f5e3Sopenharmony_ci    } else if (static_cast<UNumberFormatFields>(fieldId) == UNUM_EXPONENT_SYMBOL_FIELD) {
7514514f5e3Sopenharmony_ci        return globalConst->GetHandledExponentSeparatorString();
7524514f5e3Sopenharmony_ci    } else if (static_cast<UNumberFormatFields>(fieldId) == UNUM_EXPONENT_SIGN_FIELD) {
7534514f5e3Sopenharmony_ci        return globalConst->GetHandledExponentMinusSignString();
7544514f5e3Sopenharmony_ci    } else if (static_cast<UNumberFormatFields>(fieldId) == UNUM_EXPONENT_FIELD) {
7554514f5e3Sopenharmony_ci        return globalConst->GetHandledExponentIntegerString();
7564514f5e3Sopenharmony_ci    } else if (static_cast<UNumberFormatFields>(fieldId) == UNUM_COMPACT_FIELD) {
7574514f5e3Sopenharmony_ci        return globalConst->GetHandledCompactString();
7584514f5e3Sopenharmony_ci    } else if (static_cast<UNumberFormatFields>(fieldId) == UNUM_MEASURE_UNIT_FIELD) {
7594514f5e3Sopenharmony_ci        return globalConst->GetHandledUnitString();
7604514f5e3Sopenharmony_ci    } else {
7614514f5e3Sopenharmony_ci        LOG_ECMA(FATAL) << "this branch is unreachable";
7624514f5e3Sopenharmony_ci        UNREACHABLE();
7634514f5e3Sopenharmony_ci    }
7644514f5e3Sopenharmony_ci}
7654514f5e3Sopenharmony_ci
7664514f5e3Sopenharmony_ci// 10.1.1 ApplyOptionsToTag( tag, options )
7674514f5e3Sopenharmony_cibool JSLocale::ApplyOptionsToTag(JSThread *thread, const JSHandle<EcmaString> &tag, const JSHandle<JSObject> &options,
7684514f5e3Sopenharmony_ci                                 TagElements &tagElements)
7694514f5e3Sopenharmony_ci{
7704514f5e3Sopenharmony_ci    EcmaVM *ecmaVm = thread->GetEcmaVM();
7714514f5e3Sopenharmony_ci    const GlobalEnvConstants *globalConst = thread->GlobalConstants();
7724514f5e3Sopenharmony_ci    ObjectFactory *factory = ecmaVm->GetFactory();
7734514f5e3Sopenharmony_ci    if (*tag == *(factory->GetEmptyString())) {
7744514f5e3Sopenharmony_ci        return false;
7754514f5e3Sopenharmony_ci    }
7764514f5e3Sopenharmony_ci    // 2. If intl::LocaleHelper::IsStructurallyValidLanguageTag(tag) is false, throw a RangeError exception.
7774514f5e3Sopenharmony_ci    if (!intl::LocaleHelper::IsStructurallyValidLanguageTag(tag)) {
7784514f5e3Sopenharmony_ci        return false;
7794514f5e3Sopenharmony_ci    }
7804514f5e3Sopenharmony_ci
7814514f5e3Sopenharmony_ci    tagElements.language =
7824514f5e3Sopenharmony_ci        GetOption(thread, options, globalConst->GetHandledLanguageString(), OptionType::STRING,
7834514f5e3Sopenharmony_ci                  globalConst->GetHandledUndefined(), globalConst->GetHandledUndefined());
7844514f5e3Sopenharmony_ci    RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, false);
7854514f5e3Sopenharmony_ci
7864514f5e3Sopenharmony_ci    // 4. If language is not undefined, then
7874514f5e3Sopenharmony_ci    //    a. If language does not match the unicode_language_subtag production, throw a RangeError exception.
7884514f5e3Sopenharmony_ci    if (!tagElements.language->IsUndefined()) {
7894514f5e3Sopenharmony_ci        std::string languageStr =
7904514f5e3Sopenharmony_ci            intl::LocaleHelper::ConvertToStdString(JSHandle<EcmaString>::Cast(tagElements.language));
7914514f5e3Sopenharmony_ci        if (languageStr[INTL_INDEX_ZERO] == '\0' ||
7924514f5e3Sopenharmony_ci            IsAlpha(languageStr, INTL_INDEX_FOUR, INTL_INDEX_FOUR)) {
7934514f5e3Sopenharmony_ci            return false;
7944514f5e3Sopenharmony_ci        }
7954514f5e3Sopenharmony_ci    }
7964514f5e3Sopenharmony_ci
7974514f5e3Sopenharmony_ci    // 5. Let script be ? GetOption(options, "script", "string", undefined, undefined).
7984514f5e3Sopenharmony_ci    tagElements.script =
7994514f5e3Sopenharmony_ci        GetOption(thread, options, globalConst->GetHandledScriptString(), OptionType::STRING,
8004514f5e3Sopenharmony_ci                  globalConst->GetHandledUndefined(), globalConst->GetHandledUndefined());
8014514f5e3Sopenharmony_ci    RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, false);
8024514f5e3Sopenharmony_ci
8034514f5e3Sopenharmony_ci    // 6. If script is not undefined, then
8044514f5e3Sopenharmony_ci    //    a. If script does not match the unicode_script_subtag production, throw a RangeError exception.
8054514f5e3Sopenharmony_ci    if (!tagElements.script->IsUndefined()) {
8064514f5e3Sopenharmony_ci        std::string scriptStr =
8074514f5e3Sopenharmony_ci            intl::LocaleHelper::ConvertToStdString((JSHandle<EcmaString>::Cast(tagElements.script)));
8084514f5e3Sopenharmony_ci        if (scriptStr[INTL_INDEX_ZERO] == '\0') {
8094514f5e3Sopenharmony_ci            return false;
8104514f5e3Sopenharmony_ci        }
8114514f5e3Sopenharmony_ci    }
8124514f5e3Sopenharmony_ci
8134514f5e3Sopenharmony_ci    // 7. Let region be ? GetOption(options, "region", "string", undefined, undefined).
8144514f5e3Sopenharmony_ci    // 8. If region is not undefined, then
8154514f5e3Sopenharmony_ci    //    a. If region does not match the unicode_region_subtag production, throw a RangeError exception.
8164514f5e3Sopenharmony_ci    tagElements.region =
8174514f5e3Sopenharmony_ci        GetOption(thread, options, globalConst->GetHandledRegionString(), OptionType::STRING,
8184514f5e3Sopenharmony_ci                  globalConst->GetHandledUndefined(), globalConst->GetHandledUndefined());
8194514f5e3Sopenharmony_ci    RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, false);
8204514f5e3Sopenharmony_ci
8214514f5e3Sopenharmony_ci    if (!tagElements.region->IsUndefined()) {
8224514f5e3Sopenharmony_ci        std::string regionStr = intl::LocaleHelper::ConvertToStdString(JSHandle<EcmaString>::Cast(tagElements.region));
8234514f5e3Sopenharmony_ci        if (regionStr[INTL_INDEX_ZERO] == '\0') {
8244514f5e3Sopenharmony_ci            return false;
8254514f5e3Sopenharmony_ci        }
8264514f5e3Sopenharmony_ci    }
8274514f5e3Sopenharmony_ci    return true;
8284514f5e3Sopenharmony_ci}
8294514f5e3Sopenharmony_ci
8304514f5e3Sopenharmony_cibool BuildOptionsTags(const JSHandle<EcmaString> &tag, icu::LocaleBuilder *builder, JSHandle<JSTaggedValue> language,
8314514f5e3Sopenharmony_ci                      JSHandle<JSTaggedValue> script, JSHandle<JSTaggedValue> region)
8324514f5e3Sopenharmony_ci{
8334514f5e3Sopenharmony_ci    std::string tagStr = intl::LocaleHelper::ConvertToStdString(tag);
8344514f5e3Sopenharmony_ci    int32_t len = static_cast<int32_t>(tagStr.length());
8354514f5e3Sopenharmony_ci    ASSERT(len > 0);
8364514f5e3Sopenharmony_ci    builder->setLanguageTag({ tagStr.c_str(), len });
8374514f5e3Sopenharmony_ci    UErrorCode status = U_ZERO_ERROR;
8384514f5e3Sopenharmony_ci    icu::Locale locale = builder->build(status);
8394514f5e3Sopenharmony_ci    locale.canonicalize(status);
8404514f5e3Sopenharmony_ci    if (U_FAILURE(status) != 0) {
8414514f5e3Sopenharmony_ci        return false;
8424514f5e3Sopenharmony_ci    }
8434514f5e3Sopenharmony_ci    builder->setLocale(locale);
8444514f5e3Sopenharmony_ci
8454514f5e3Sopenharmony_ci    if (!language->IsUndefined()) {
8464514f5e3Sopenharmony_ci        std::string languageStr = intl::LocaleHelper::ConvertToStdString(JSHandle<EcmaString>::Cast(language));
8474514f5e3Sopenharmony_ci        builder->setLanguage(languageStr);
8484514f5e3Sopenharmony_ci        builder->build(status);
8494514f5e3Sopenharmony_ci        if ((U_FAILURE(status) != 0)) {
8504514f5e3Sopenharmony_ci            return false;
8514514f5e3Sopenharmony_ci        }
8524514f5e3Sopenharmony_ci    }
8534514f5e3Sopenharmony_ci
8544514f5e3Sopenharmony_ci    if (!script->IsUndefined()) {
8554514f5e3Sopenharmony_ci        std::string scriptStr = intl::LocaleHelper::ConvertToStdString((JSHandle<EcmaString>::Cast(script)));
8564514f5e3Sopenharmony_ci        builder->setScript(scriptStr);
8574514f5e3Sopenharmony_ci        builder->build(status);
8584514f5e3Sopenharmony_ci        if ((U_FAILURE(status) != 0)) {
8594514f5e3Sopenharmony_ci            return false;
8604514f5e3Sopenharmony_ci        }
8614514f5e3Sopenharmony_ci    }
8624514f5e3Sopenharmony_ci
8634514f5e3Sopenharmony_ci    if (!region->IsUndefined()) {
8644514f5e3Sopenharmony_ci        std::string regionStr = intl::LocaleHelper::ConvertToStdString(JSHandle<EcmaString>::Cast(region));
8654514f5e3Sopenharmony_ci        builder->setRegion(regionStr);
8664514f5e3Sopenharmony_ci        builder->build(status);
8674514f5e3Sopenharmony_ci        if ((U_FAILURE(status) != 0)) {
8684514f5e3Sopenharmony_ci            return false;
8694514f5e3Sopenharmony_ci        }
8704514f5e3Sopenharmony_ci    }
8714514f5e3Sopenharmony_ci    return true;
8724514f5e3Sopenharmony_ci}
8734514f5e3Sopenharmony_ci
8744514f5e3Sopenharmony_cibool InsertOptions(JSThread *thread, const JSHandle<JSObject> &options, icu::LocaleBuilder *builder)
8754514f5e3Sopenharmony_ci{
8764514f5e3Sopenharmony_ci    const std::vector<std::string> emptyValues = {};
8774514f5e3Sopenharmony_ci    const GlobalEnvConstants *globalConst = thread->GlobalConstants();
8784514f5e3Sopenharmony_ci    std::string strResult;
8794514f5e3Sopenharmony_ci    bool findca =
8804514f5e3Sopenharmony_ci        JSLocale::GetOptionOfString(thread, options, globalConst->GetHandledCalendarString(), emptyValues, &strResult);
8814514f5e3Sopenharmony_ci    RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, false);
8824514f5e3Sopenharmony_ci    if (findca) {
8834514f5e3Sopenharmony_ci        if (!uloc_toLegacyType(uloc_toLegacyKey("ca"), strResult.c_str())) {
8844514f5e3Sopenharmony_ci            return false;
8854514f5e3Sopenharmony_ci        }
8864514f5e3Sopenharmony_ci        ThreadNativeScope nativeScope(thread);
8874514f5e3Sopenharmony_ci        builder->setUnicodeLocaleKeyword("ca", strResult.c_str());
8884514f5e3Sopenharmony_ci    }
8894514f5e3Sopenharmony_ci
8904514f5e3Sopenharmony_ci    bool findco =
8914514f5e3Sopenharmony_ci        JSLocale::GetOptionOfString(thread, options, globalConst->GetHandledCollationString(), emptyValues, &strResult);
8924514f5e3Sopenharmony_ci    RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, false);
8934514f5e3Sopenharmony_ci    if (findco) {
8944514f5e3Sopenharmony_ci        if (!uloc_toLegacyType(uloc_toLegacyKey("co"), strResult.c_str())) {
8954514f5e3Sopenharmony_ci            return false;
8964514f5e3Sopenharmony_ci        }
8974514f5e3Sopenharmony_ci        ThreadNativeScope nativeScope(thread);
8984514f5e3Sopenharmony_ci        builder->setUnicodeLocaleKeyword("co", strResult.c_str());
8994514f5e3Sopenharmony_ci    }
9004514f5e3Sopenharmony_ci
9014514f5e3Sopenharmony_ci    bool findhc = JSLocale::GetOptionOfString(thread, options, globalConst->GetHandledHourCycleString(),
9024514f5e3Sopenharmony_ci                                              JSLocale::HOUR_CYCLE, &strResult);
9034514f5e3Sopenharmony_ci    RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, false);
9044514f5e3Sopenharmony_ci    if (findhc) {
9054514f5e3Sopenharmony_ci        if (!uloc_toLegacyType(uloc_toLegacyKey("hc"), strResult.c_str())) {
9064514f5e3Sopenharmony_ci            return false;
9074514f5e3Sopenharmony_ci        }
9084514f5e3Sopenharmony_ci        ThreadNativeScope nativeScope(thread);
9094514f5e3Sopenharmony_ci        builder->setUnicodeLocaleKeyword("hc", strResult.c_str());
9104514f5e3Sopenharmony_ci    }
9114514f5e3Sopenharmony_ci
9124514f5e3Sopenharmony_ci    bool findkf = JSLocale::GetOptionOfString(thread, options, globalConst->GetHandledCaseFirstString(),
9134514f5e3Sopenharmony_ci                                              JSLocale::CASE_FIRST, &strResult);
9144514f5e3Sopenharmony_ci    RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, false);
9154514f5e3Sopenharmony_ci    if (findkf) {
9164514f5e3Sopenharmony_ci        if (!uloc_toLegacyType(uloc_toLegacyKey("kf"), strResult.c_str())) {
9174514f5e3Sopenharmony_ci            return false;
9184514f5e3Sopenharmony_ci        }
9194514f5e3Sopenharmony_ci        ThreadNativeScope nativeScope(thread);
9204514f5e3Sopenharmony_ci        builder->setUnicodeLocaleKeyword("kf", strResult.c_str());
9214514f5e3Sopenharmony_ci    }
9224514f5e3Sopenharmony_ci
9234514f5e3Sopenharmony_ci    bool boolResult = false;
9244514f5e3Sopenharmony_ci    bool findkn =
9254514f5e3Sopenharmony_ci        JSLocale::GetOptionOfBool(thread, options, globalConst->GetHandledNumericString(), false, &boolResult);
9264514f5e3Sopenharmony_ci    if (findkn) {
9274514f5e3Sopenharmony_ci        strResult = boolResult ? "true" : "false";
9284514f5e3Sopenharmony_ci        if (!uloc_toLegacyType(uloc_toLegacyKey("kn"), strResult.c_str())) {
9294514f5e3Sopenharmony_ci            return false;
9304514f5e3Sopenharmony_ci        }
9314514f5e3Sopenharmony_ci        ThreadNativeScope nativeScope(thread);
9324514f5e3Sopenharmony_ci        builder->setUnicodeLocaleKeyword("kn", strResult.c_str());
9334514f5e3Sopenharmony_ci    }
9344514f5e3Sopenharmony_ci
9354514f5e3Sopenharmony_ci    bool findnu =
9364514f5e3Sopenharmony_ci        JSLocale::GetOptionOfString(thread, options, globalConst->GetHandledNumberingSystemString(), emptyValues,
9374514f5e3Sopenharmony_ci                                    &strResult);
9384514f5e3Sopenharmony_ci    RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, false);
9394514f5e3Sopenharmony_ci    if (findnu) {
9404514f5e3Sopenharmony_ci        if (!uloc_toLegacyType(uloc_toLegacyKey("nu"), strResult.c_str())) {
9414514f5e3Sopenharmony_ci            return false;
9424514f5e3Sopenharmony_ci        }
9434514f5e3Sopenharmony_ci        ThreadNativeScope nativeScope(thread);
9444514f5e3Sopenharmony_ci        builder->setUnicodeLocaleKeyword("nu", strResult.c_str());
9454514f5e3Sopenharmony_ci    }
9464514f5e3Sopenharmony_ci    return true;
9474514f5e3Sopenharmony_ci}
9484514f5e3Sopenharmony_ci
9494514f5e3Sopenharmony_ciJSHandle<JSLocale> JSLocale::InitializeLocale(JSThread *thread, const JSHandle<JSLocale> &locale,
9504514f5e3Sopenharmony_ci                                              const JSHandle<EcmaString> &localeString,
9514514f5e3Sopenharmony_ci                                              const JSHandle<JSObject> &options)
9524514f5e3Sopenharmony_ci{
9534514f5e3Sopenharmony_ci    icu::LocaleBuilder builder;
9544514f5e3Sopenharmony_ci    TagElements tagElements;
9554514f5e3Sopenharmony_ci    if (!ApplyOptionsToTag(thread, localeString, options, tagElements)) {
9564514f5e3Sopenharmony_ci        THROW_RANGE_ERROR_AND_RETURN(thread, "apply option to tag failed", locale);
9574514f5e3Sopenharmony_ci    }
9584514f5e3Sopenharmony_ci
9594514f5e3Sopenharmony_ci    bool res = BuildOptionsTags(localeString, &builder, tagElements.language, tagElements.script, tagElements.region);
9604514f5e3Sopenharmony_ci    if (!res) {
9614514f5e3Sopenharmony_ci        THROW_RANGE_ERROR_AND_RETURN(thread, "apply option to tag failed", locale);
9624514f5e3Sopenharmony_ci    }
9634514f5e3Sopenharmony_ci    bool insertResult = InsertOptions(thread, options, &builder);
9644514f5e3Sopenharmony_ci    RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, locale);
9654514f5e3Sopenharmony_ci    UErrorCode status = U_ZERO_ERROR;
9664514f5e3Sopenharmony_ci    icu::Locale icuLocale = builder.build(status);
9674514f5e3Sopenharmony_ci    icuLocale.canonicalize(status);
9684514f5e3Sopenharmony_ci
9694514f5e3Sopenharmony_ci    if (!insertResult || (U_FAILURE(status) != 0)) {
9704514f5e3Sopenharmony_ci        THROW_RANGE_ERROR_AND_RETURN(thread, "insert or build failed", locale);
9714514f5e3Sopenharmony_ci    }
9724514f5e3Sopenharmony_ci    ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
9734514f5e3Sopenharmony_ci    factory->NewJSIntlIcuData(locale, icuLocale, JSLocale::FreeIcuLocale);
9744514f5e3Sopenharmony_ci    return locale;
9754514f5e3Sopenharmony_ci}
9764514f5e3Sopenharmony_ci
9774514f5e3Sopenharmony_ciint ConvertValue(const UErrorCode &status, std::string &value, const std::string &key)
9784514f5e3Sopenharmony_ci{
9794514f5e3Sopenharmony_ci    if (status == U_ILLEGAL_ARGUMENT_ERROR || value.empty()) {
9804514f5e3Sopenharmony_ci        return 1;
9814514f5e3Sopenharmony_ci    }
9824514f5e3Sopenharmony_ci
9834514f5e3Sopenharmony_ci    if (value == "yes") {
9844514f5e3Sopenharmony_ci        value = "true";
9854514f5e3Sopenharmony_ci    }
9864514f5e3Sopenharmony_ci
9874514f5e3Sopenharmony_ci    if (key == "kf" && value == "true") {
9884514f5e3Sopenharmony_ci        return 2;  // 2: in this case normalizedKeyword is empty string
9894514f5e3Sopenharmony_ci    }
9904514f5e3Sopenharmony_ci    return 0;
9914514f5e3Sopenharmony_ci}
9924514f5e3Sopenharmony_ci
9934514f5e3Sopenharmony_ciJSTaggedValue JSLocale::NormalizeKeywordValue(JSThread *thread, const JSHandle<JSLocale> &locale,
9944514f5e3Sopenharmony_ci                                              const std::string &key)
9954514f5e3Sopenharmony_ci{
9964514f5e3Sopenharmony_ci    icu::Locale *icuLocale = locale->GetIcuLocale();
9974514f5e3Sopenharmony_ci    UErrorCode status = U_ZERO_ERROR;
9984514f5e3Sopenharmony_ci    auto value = icuLocale->getUnicodeKeywordValue<std::string>(key, status);
9994514f5e3Sopenharmony_ci
10004514f5e3Sopenharmony_ci    EcmaVM *ecmaVm = thread->GetEcmaVM();
10014514f5e3Sopenharmony_ci    ObjectFactory *factory = ecmaVm->GetFactory();
10024514f5e3Sopenharmony_ci
10034514f5e3Sopenharmony_ci    int result = ConvertValue(status, value, key);
10044514f5e3Sopenharmony_ci    if (result == 1) {
10054514f5e3Sopenharmony_ci        return JSTaggedValue::Undefined();
10064514f5e3Sopenharmony_ci    }
10074514f5e3Sopenharmony_ci    if (result == 2) {  // 2: in this case normalizedKeyword is empty string
10084514f5e3Sopenharmony_ci        return factory->GetEmptyString().GetTaggedValue();
10094514f5e3Sopenharmony_ci    }
10104514f5e3Sopenharmony_ci    return factory->NewFromStdString(value).GetTaggedValue();
10114514f5e3Sopenharmony_ci}
10124514f5e3Sopenharmony_ci
10134514f5e3Sopenharmony_ciJSHandle<EcmaString> JSLocale::ToString(JSThread *thread, const JSHandle<JSLocale> &locale)
10144514f5e3Sopenharmony_ci{
10154514f5e3Sopenharmony_ci    icu::Locale *icuLocale = locale->GetIcuLocale();
10164514f5e3Sopenharmony_ci    if (icuLocale == nullptr) {
10174514f5e3Sopenharmony_ci        ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
10184514f5e3Sopenharmony_ci        return factory->GetEmptyString();
10194514f5e3Sopenharmony_ci    }
10204514f5e3Sopenharmony_ci    JSHandle<EcmaString> result = intl::LocaleHelper::ToLanguageTag(thread, *icuLocale);
10214514f5e3Sopenharmony_ci    RETURN_HANDLE_IF_ABRUPT_COMPLETION(EcmaString, thread);
10224514f5e3Sopenharmony_ci    return result;
10234514f5e3Sopenharmony_ci}
10244514f5e3Sopenharmony_ci
10254514f5e3Sopenharmony_cistd::vector<std::string> JSLocale::GetAvailableStringLocales(JSThread *thread,
10264514f5e3Sopenharmony_ci                                                             const JSHandle<TaggedArray> &availableLocales)
10274514f5e3Sopenharmony_ci{
10284514f5e3Sopenharmony_ci    std::vector<std::string> availableStringLocales;
10294514f5e3Sopenharmony_ci    JSMutableHandle<EcmaString> availableItem(thread, JSTaggedValue::Undefined());
10304514f5e3Sopenharmony_ci    uint32_t availablecalesLength = availableLocales->GetLength();
10314514f5e3Sopenharmony_ci    for (uint32_t i = 0; i < availablecalesLength; i++) {
10324514f5e3Sopenharmony_ci        availableItem.Update(availableLocales->Get(thread, i));
10334514f5e3Sopenharmony_ci        availableStringLocales.emplace_back(intl::LocaleHelper::ConvertToStdString(availableItem));
10344514f5e3Sopenharmony_ci    }
10354514f5e3Sopenharmony_ci    return availableStringLocales;
10364514f5e3Sopenharmony_ci}
10374514f5e3Sopenharmony_ci
10384514f5e3Sopenharmony_ci}  // namespace panda::ecmascript
1039