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 ¤cy) 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