14514f5e3Sopenharmony_ci/* 24514f5e3Sopenharmony_ci * Copyright (c) 2021-2024 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_relative_time_format.h" 174514f5e3Sopenharmony_ci#include "ecmascript/js_function.h" 184514f5e3Sopenharmony_ci#include "ecmascript/object_factory-inl.h" 194514f5e3Sopenharmony_ci 204514f5e3Sopenharmony_cinamespace panda::ecmascript { 214514f5e3Sopenharmony_ci// 14.1.1 InitializeRelativeTimeFormat ( relativeTimeFormat, locales, options ) 224514f5e3Sopenharmony_ciJSHandle<JSRelativeTimeFormat> JSRelativeTimeFormat::InitializeRelativeTimeFormat( 234514f5e3Sopenharmony_ci JSThread *thread, const JSHandle<JSRelativeTimeFormat> &relativeTimeFormat, const JSHandle<JSTaggedValue> &locales, 244514f5e3Sopenharmony_ci const JSHandle<JSTaggedValue> &options) 254514f5e3Sopenharmony_ci{ 264514f5e3Sopenharmony_ci EcmaVM *ecmaVm = thread->GetEcmaVM(); 274514f5e3Sopenharmony_ci ObjectFactory *factory = ecmaVm->GetFactory(); 284514f5e3Sopenharmony_ci 294514f5e3Sopenharmony_ci // 1.Let requestedLocales be ? CanonicalizeLocaleList(locales). 304514f5e3Sopenharmony_ci JSHandle<TaggedArray> requestedLocales = intl::LocaleHelper::CanonicalizeLocaleList(thread, locales); 314514f5e3Sopenharmony_ci RETURN_HANDLE_IF_ABRUPT_COMPLETION(JSRelativeTimeFormat, thread); 324514f5e3Sopenharmony_ci 334514f5e3Sopenharmony_ci // 2&3. If options is undefined, then Let options be ObjectCreate(null). else Let options be ? ToObject(options). 344514f5e3Sopenharmony_ci JSHandle<JSObject> rtfOptions; 354514f5e3Sopenharmony_ci if (!options->IsUndefined()) { 364514f5e3Sopenharmony_ci rtfOptions = JSTaggedValue::ToObject(thread, options); 374514f5e3Sopenharmony_ci RETURN_HANDLE_IF_ABRUPT_COMPLETION(JSRelativeTimeFormat, thread); 384514f5e3Sopenharmony_ci } else { 394514f5e3Sopenharmony_ci rtfOptions = factory->CreateNullJSObject(); 404514f5e3Sopenharmony_ci } 414514f5e3Sopenharmony_ci 424514f5e3Sopenharmony_ci // 5. Let matcher be ? GetOption(options, "localeMatcher", "string", «"lookup", "best fit"», "best fit"). 434514f5e3Sopenharmony_ci auto globalConst = thread->GlobalConstants(); 444514f5e3Sopenharmony_ci LocaleMatcherOption matcher = 454514f5e3Sopenharmony_ci JSLocale::GetOptionOfString(thread, rtfOptions, globalConst->GetHandledLocaleMatcherString(), 464514f5e3Sopenharmony_ci {LocaleMatcherOption::LOOKUP, LocaleMatcherOption::BEST_FIT}, 474514f5e3Sopenharmony_ci {"lookup", "best fit"}, LocaleMatcherOption::BEST_FIT); 484514f5e3Sopenharmony_ci RETURN_HANDLE_IF_ABRUPT_COMPLETION(JSRelativeTimeFormat, thread); 494514f5e3Sopenharmony_ci 504514f5e3Sopenharmony_ci // 7. Let numberingSystem be ? GetOption(options, "numberingSystem", "string", undefined, undefined). 514514f5e3Sopenharmony_ci JSHandle<JSTaggedValue> property = globalConst->GetHandledNumberingSystemString(); 524514f5e3Sopenharmony_ci JSHandle<JSTaggedValue> undefinedValue(thread, JSTaggedValue::Undefined()); 534514f5e3Sopenharmony_ci JSHandle<JSTaggedValue> numberingSystemValue = 544514f5e3Sopenharmony_ci JSLocale::GetOption(thread, rtfOptions, property, OptionType::STRING, undefinedValue, undefinedValue); 554514f5e3Sopenharmony_ci RETURN_HANDLE_IF_ABRUPT_COMPLETION(JSRelativeTimeFormat, thread); 564514f5e3Sopenharmony_ci 574514f5e3Sopenharmony_ci // Check whether numberingSystem is well formed and set to %RelativeTimeFormat%.[[numberingSystem]] 584514f5e3Sopenharmony_ci std::string numberingSystemStdStr; 594514f5e3Sopenharmony_ci if (!numberingSystemValue->IsUndefined()) { 604514f5e3Sopenharmony_ci JSHandle<EcmaString> numberingSystemString = JSHandle<EcmaString>::Cast(numberingSystemValue); 614514f5e3Sopenharmony_ci if (EcmaStringAccessor(numberingSystemString).IsUtf16()) { 624514f5e3Sopenharmony_ci THROW_RANGE_ERROR_AND_RETURN(thread, "invalid numberingSystem", relativeTimeFormat); 634514f5e3Sopenharmony_ci } 644514f5e3Sopenharmony_ci numberingSystemStdStr = intl::LocaleHelper::ConvertToStdString(numberingSystemString); 654514f5e3Sopenharmony_ci if (!JSLocale::IsNormativeNumberingSystem(numberingSystemStdStr)) { 664514f5e3Sopenharmony_ci THROW_RANGE_ERROR_AND_RETURN(thread, "invalid numberingSystem", relativeTimeFormat); 674514f5e3Sopenharmony_ci } 684514f5e3Sopenharmony_ci } 694514f5e3Sopenharmony_ci 704514f5e3Sopenharmony_ci // 10. Let localeData be %RelativeTimeFormat%.[[LocaleData]]. 714514f5e3Sopenharmony_ci // 11. Let r be ResolveLocale(%RelativeTimeFormat%.[[AvailableLocales]], requestedLocales, opt, 724514f5e3Sopenharmony_ci // %RelativeTimeFormat%.[[RelevantExtensionKeys]], localeData). 734514f5e3Sopenharmony_ci JSHandle<TaggedArray> availableLocales; 744514f5e3Sopenharmony_ci if (requestedLocales->GetLength() == 0) { 754514f5e3Sopenharmony_ci availableLocales = factory->EmptyArray(); 764514f5e3Sopenharmony_ci } else { 774514f5e3Sopenharmony_ci std::vector<std::string> availableStringLocales = 784514f5e3Sopenharmony_ci intl::LocaleHelper::GetAvailableLocales(thread, "calendar", nullptr); 794514f5e3Sopenharmony_ci availableLocales = JSLocale::ConstructLocaleList(thread, availableStringLocales); 804514f5e3Sopenharmony_ci } 814514f5e3Sopenharmony_ci std::set<std::string> relevantExtensionKeys{"nu"}; 824514f5e3Sopenharmony_ci ResolvedLocale r = 834514f5e3Sopenharmony_ci JSLocale::ResolveLocale(thread, availableLocales, requestedLocales, matcher, relevantExtensionKeys); 844514f5e3Sopenharmony_ci RETURN_HANDLE_IF_ABRUPT_COMPLETION(JSRelativeTimeFormat, thread); 854514f5e3Sopenharmony_ci icu::Locale icuLocale = r.localeData; 864514f5e3Sopenharmony_ci 874514f5e3Sopenharmony_ci // 12. Let locale be r.[[Locale]]. 884514f5e3Sopenharmony_ci JSHandle<EcmaString> localeStr = intl::LocaleHelper::ToLanguageTag(thread, icuLocale); 894514f5e3Sopenharmony_ci RETURN_HANDLE_IF_ABRUPT_COMPLETION(JSRelativeTimeFormat, thread); 904514f5e3Sopenharmony_ci 914514f5e3Sopenharmony_ci // 13. Set relativeTimeFormat.[[Locale]] to locale. 924514f5e3Sopenharmony_ci relativeTimeFormat->SetLocale(thread, localeStr.GetTaggedValue()); 934514f5e3Sopenharmony_ci 944514f5e3Sopenharmony_ci // 15. Set relativeTimeFormat.[[NumberingSystem]] to r.[[nu]]. 954514f5e3Sopenharmony_ci UErrorCode status = U_ZERO_ERROR; 964514f5e3Sopenharmony_ci if (!numberingSystemStdStr.empty()) { 974514f5e3Sopenharmony_ci if (JSLocale::IsWellNumberingSystem(numberingSystemStdStr)) { 984514f5e3Sopenharmony_ci icuLocale.setUnicodeKeywordValue("nu", numberingSystemStdStr, status); 994514f5e3Sopenharmony_ci ASSERT(U_SUCCESS(status)); 1004514f5e3Sopenharmony_ci } 1014514f5e3Sopenharmony_ci } 1024514f5e3Sopenharmony_ci 1034514f5e3Sopenharmony_ci // 16. Let s be ? GetOption(options, "style", "string", «"long", "short", "narrow"», "long"). 1044514f5e3Sopenharmony_ci property = globalConst->GetHandledStyleString(); 1054514f5e3Sopenharmony_ci RelativeStyleOption styleOption = JSLocale::GetOptionOfString(thread, rtfOptions, property, 1064514f5e3Sopenharmony_ci {RelativeStyleOption::LONG, RelativeStyleOption::SHORT, RelativeStyleOption::NARROW}, 1074514f5e3Sopenharmony_ci {"long", "short", "narrow"}, RelativeStyleOption::LONG); 1084514f5e3Sopenharmony_ci RETURN_HANDLE_IF_ABRUPT_COMPLETION(JSRelativeTimeFormat, thread); 1094514f5e3Sopenharmony_ci 1104514f5e3Sopenharmony_ci // 17. Set relativeTimeFormat.[[Style]] to s. 1114514f5e3Sopenharmony_ci relativeTimeFormat->SetStyle(styleOption); 1124514f5e3Sopenharmony_ci 1134514f5e3Sopenharmony_ci // 18. Let numeric be ? GetOption(options, "numeric", "string", ?"always", "auto"?, "always"). 1144514f5e3Sopenharmony_ci property = globalConst->GetHandledNumericString(); 1154514f5e3Sopenharmony_ci NumericOption numericOption = 1164514f5e3Sopenharmony_ci JSLocale::GetOptionOfString(thread, rtfOptions, property, {NumericOption::ALWAYS, NumericOption::AUTO}, 1174514f5e3Sopenharmony_ci {"always", "auto"}, NumericOption::ALWAYS); 1184514f5e3Sopenharmony_ci RETURN_HANDLE_IF_ABRUPT_COMPLETION(JSRelativeTimeFormat, thread); 1194514f5e3Sopenharmony_ci 1204514f5e3Sopenharmony_ci // 19. Set relativeTimeFormat.[[Numeric]] to numeric. 1214514f5e3Sopenharmony_ci relativeTimeFormat->SetNumeric(numericOption); 1224514f5e3Sopenharmony_ci 1234514f5e3Sopenharmony_ci // 20. Let relativeTimeFormat.[[NumberFormat]] be ! Construct(%NumberFormat%, « locale »). 1244514f5e3Sopenharmony_ci icu::NumberFormat *icuNumberFormat = icu::NumberFormat::createInstance(icuLocale, UNUM_DECIMAL, status); 1254514f5e3Sopenharmony_ci if (U_FAILURE(status) != 0) { 1264514f5e3Sopenharmony_ci delete icuNumberFormat; 1274514f5e3Sopenharmony_ci if (status == UErrorCode::U_MISSING_RESOURCE_ERROR) { 1284514f5e3Sopenharmony_ci THROW_REFERENCE_ERROR_AND_RETURN(thread, "can not find icu data resources", relativeTimeFormat); 1294514f5e3Sopenharmony_ci } 1304514f5e3Sopenharmony_ci THROW_RANGE_ERROR_AND_RETURN(thread, "create icu::NumberFormat failed", relativeTimeFormat); 1314514f5e3Sopenharmony_ci } 1324514f5e3Sopenharmony_ci // Display grouping using the default strategy for all locales 1334514f5e3Sopenharmony_ci if (icuNumberFormat->getDynamicClassID() == icu::DecimalFormat::getStaticClassID()) { 1344514f5e3Sopenharmony_ci icu::DecimalFormat* icuDecimalFormat = static_cast<icu::DecimalFormat*>(icuNumberFormat); 1354514f5e3Sopenharmony_ci icuDecimalFormat->setMinimumGroupingDigits(UNUM_MINIMUM_GROUPING_DIGITS_AUTO); 1364514f5e3Sopenharmony_ci } 1374514f5e3Sopenharmony_ci 1384514f5e3Sopenharmony_ci // Trans RelativeStyleOption to ICU Style 1394514f5e3Sopenharmony_ci UDateRelativeDateTimeFormatterStyle uStyle; 1404514f5e3Sopenharmony_ci switch (styleOption) { 1414514f5e3Sopenharmony_ci case RelativeStyleOption::LONG: 1424514f5e3Sopenharmony_ci uStyle = UDAT_STYLE_LONG; 1434514f5e3Sopenharmony_ci break; 1444514f5e3Sopenharmony_ci case RelativeStyleOption::SHORT: 1454514f5e3Sopenharmony_ci uStyle = UDAT_STYLE_SHORT; 1464514f5e3Sopenharmony_ci break; 1474514f5e3Sopenharmony_ci case RelativeStyleOption::NARROW: 1484514f5e3Sopenharmony_ci uStyle = UDAT_STYLE_NARROW; 1494514f5e3Sopenharmony_ci break; 1504514f5e3Sopenharmony_ci default: 1514514f5e3Sopenharmony_ci LOG_ECMA(FATAL) << "this branch is unreachable"; 1524514f5e3Sopenharmony_ci UNREACHABLE(); 1534514f5e3Sopenharmony_ci } 1544514f5e3Sopenharmony_ci icu::RelativeDateTimeFormatter rtfFormatter(icuLocale, icuNumberFormat, uStyle, UDISPCTX_CAPITALIZATION_NONE, 1554514f5e3Sopenharmony_ci status); 1564514f5e3Sopenharmony_ci if (U_FAILURE(status) != 0) { 1574514f5e3Sopenharmony_ci THROW_RANGE_ERROR_AND_RETURN(thread, "icu Formatter Error", relativeTimeFormat); 1584514f5e3Sopenharmony_ci } 1594514f5e3Sopenharmony_ci 1604514f5e3Sopenharmony_ci std::string numberingSystem = JSLocale::GetNumberingSystem(icuLocale); 1614514f5e3Sopenharmony_ci auto result = factory->NewFromStdString(numberingSystem); 1624514f5e3Sopenharmony_ci relativeTimeFormat->SetNumberingSystem(thread, result); 1634514f5e3Sopenharmony_ci 1644514f5e3Sopenharmony_ci // Set RelativeTimeFormat.[[IcuRelativeTimeFormatter]] 1654514f5e3Sopenharmony_ci factory->NewJSIntlIcuData(relativeTimeFormat, rtfFormatter, JSRelativeTimeFormat::FreeIcuRTFFormatter); 1664514f5e3Sopenharmony_ci 1674514f5e3Sopenharmony_ci // 22. Return relativeTimeFormat. 1684514f5e3Sopenharmony_ci return relativeTimeFormat; 1694514f5e3Sopenharmony_ci} 1704514f5e3Sopenharmony_ci 1714514f5e3Sopenharmony_ci// 14.1.2 SingularRelativeTimeUnit ( unit ) 1724514f5e3Sopenharmony_cibool SingularUnitToIcuUnit(JSThread *thread, const JSHandle<EcmaString> &unit, URelativeDateTimeUnit *unitEnum) 1734514f5e3Sopenharmony_ci{ 1744514f5e3Sopenharmony_ci // 1. Assert: Type(unit) is String. 1754514f5e3Sopenharmony_ci ASSERT(JSHandle<JSTaggedValue>::Cast(unit)->IsString()); 1764514f5e3Sopenharmony_ci 1774514f5e3Sopenharmony_ci // 2. If unit is "seconds" or "second", return "second". 1784514f5e3Sopenharmony_ci // 3. If unit is "minutes" or "minute", return "minute". 1794514f5e3Sopenharmony_ci // 4. If unit is "hours" or "hour", return "hour". 1804514f5e3Sopenharmony_ci // 5. If unit is "days" or "day", return "day". 1814514f5e3Sopenharmony_ci // 6. If unit is "weeks" or "week", return "week". 1824514f5e3Sopenharmony_ci // 7. If unit is "months" or "month", return "month". 1834514f5e3Sopenharmony_ci // 8. If unit is "quarters" or "quarter", return "quarter". 1844514f5e3Sopenharmony_ci // 9. If unit is "years" or "year", return "year". 1854514f5e3Sopenharmony_ci auto globalConst = thread->GlobalConstants(); 1864514f5e3Sopenharmony_ci JSHandle<EcmaString> second = JSHandle<EcmaString>::Cast(globalConst->GetHandledSecondString()); 1874514f5e3Sopenharmony_ci JSHandle<EcmaString> minute = JSHandle<EcmaString>::Cast(globalConst->GetHandledMinuteString()); 1884514f5e3Sopenharmony_ci JSHandle<EcmaString> hour = JSHandle<EcmaString>::Cast(globalConst->GetHandledHourString()); 1894514f5e3Sopenharmony_ci JSHandle<EcmaString> day = JSHandle<EcmaString>::Cast(globalConst->GetHandledDayString()); 1904514f5e3Sopenharmony_ci JSHandle<EcmaString> week = JSHandle<EcmaString>::Cast(globalConst->GetHandledWeekString()); 1914514f5e3Sopenharmony_ci JSHandle<EcmaString> month = JSHandle<EcmaString>::Cast(globalConst->GetHandledMonthString()); 1924514f5e3Sopenharmony_ci JSHandle<EcmaString> quarter = JSHandle<EcmaString>::Cast(globalConst->GetHandledQuarterString()); 1934514f5e3Sopenharmony_ci JSHandle<EcmaString> year = JSHandle<EcmaString>::Cast(globalConst->GetHandledYearString()); 1944514f5e3Sopenharmony_ci 1954514f5e3Sopenharmony_ci JSHandle<EcmaString> seconds = JSHandle<EcmaString>::Cast(globalConst->GetHandledSecondsString()); 1964514f5e3Sopenharmony_ci JSHandle<EcmaString> minutes = JSHandle<EcmaString>::Cast(globalConst->GetHandledMinutesString()); 1974514f5e3Sopenharmony_ci JSHandle<EcmaString> hours = JSHandle<EcmaString>::Cast(globalConst->GetHandledHoursString()); 1984514f5e3Sopenharmony_ci JSHandle<EcmaString> days = JSHandle<EcmaString>::Cast(globalConst->GetHandledDaysString()); 1994514f5e3Sopenharmony_ci JSHandle<EcmaString> weeks = JSHandle<EcmaString>::Cast(globalConst->GetHandledWeeksString()); 2004514f5e3Sopenharmony_ci JSHandle<EcmaString> months = JSHandle<EcmaString>::Cast(globalConst->GetHandledMonthsString()); 2014514f5e3Sopenharmony_ci JSHandle<EcmaString> quarters = JSHandle<EcmaString>::Cast(globalConst->GetHandledQuartersString()); 2024514f5e3Sopenharmony_ci JSHandle<EcmaString> years = JSHandle<EcmaString>::Cast(globalConst->GetHandledYearsString()); 2034514f5e3Sopenharmony_ci 2044514f5e3Sopenharmony_ci if (EcmaStringAccessor::StringsAreEqual(*second, *unit) || 2054514f5e3Sopenharmony_ci EcmaStringAccessor::StringsAreEqual(*seconds, *unit)) { 2064514f5e3Sopenharmony_ci *unitEnum = UDAT_REL_UNIT_SECOND; 2074514f5e3Sopenharmony_ci } else if (EcmaStringAccessor::StringsAreEqual(*minute, *unit) || 2084514f5e3Sopenharmony_ci EcmaStringAccessor::StringsAreEqual(*minutes, *unit)) { 2094514f5e3Sopenharmony_ci *unitEnum = UDAT_REL_UNIT_MINUTE; 2104514f5e3Sopenharmony_ci } else if (EcmaStringAccessor::StringsAreEqual(*hour, *unit) || 2114514f5e3Sopenharmony_ci EcmaStringAccessor::StringsAreEqual(*hours, *unit)) { 2124514f5e3Sopenharmony_ci *unitEnum = UDAT_REL_UNIT_HOUR; 2134514f5e3Sopenharmony_ci } else if (EcmaStringAccessor::StringsAreEqual(*day, *unit) || 2144514f5e3Sopenharmony_ci EcmaStringAccessor::StringsAreEqual(*days, *unit)) { 2154514f5e3Sopenharmony_ci *unitEnum = UDAT_REL_UNIT_DAY; 2164514f5e3Sopenharmony_ci } else if (EcmaStringAccessor::StringsAreEqual(*week, *unit) || 2174514f5e3Sopenharmony_ci EcmaStringAccessor::StringsAreEqual(*weeks, *unit)) { 2184514f5e3Sopenharmony_ci *unitEnum = UDAT_REL_UNIT_WEEK; 2194514f5e3Sopenharmony_ci } else if (EcmaStringAccessor::StringsAreEqual(*month, *unit) || 2204514f5e3Sopenharmony_ci EcmaStringAccessor::StringsAreEqual(*months, *unit)) { 2214514f5e3Sopenharmony_ci *unitEnum = UDAT_REL_UNIT_MONTH; 2224514f5e3Sopenharmony_ci } else if (EcmaStringAccessor::StringsAreEqual(*quarter, *unit) || 2234514f5e3Sopenharmony_ci EcmaStringAccessor::StringsAreEqual(*quarters, *unit)) { 2244514f5e3Sopenharmony_ci *unitEnum = UDAT_REL_UNIT_QUARTER; 2254514f5e3Sopenharmony_ci } else if (EcmaStringAccessor::StringsAreEqual(*year, *unit) || 2264514f5e3Sopenharmony_ci EcmaStringAccessor::StringsAreEqual(*years, *unit)) { 2274514f5e3Sopenharmony_ci *unitEnum = UDAT_REL_UNIT_YEAR; 2284514f5e3Sopenharmony_ci } else { 2294514f5e3Sopenharmony_ci return false; 2304514f5e3Sopenharmony_ci } 2314514f5e3Sopenharmony_ci // 11. else return unit. 2324514f5e3Sopenharmony_ci return true; 2334514f5e3Sopenharmony_ci} 2344514f5e3Sopenharmony_ci 2354514f5e3Sopenharmony_ci// Unwrap RelativeTimeFormat 2364514f5e3Sopenharmony_ciJSHandle<JSTaggedValue> JSRelativeTimeFormat::UnwrapRelativeTimeFormat(JSThread *thread, 2374514f5e3Sopenharmony_ci const JSHandle<JSTaggedValue> &rtf) 2384514f5e3Sopenharmony_ci{ 2394514f5e3Sopenharmony_ci ASSERT_PRINT(rtf->IsJSObject(), "rtf is not a JSObject"); 2404514f5e3Sopenharmony_ci 2414514f5e3Sopenharmony_ci JSHandle<GlobalEnv> env = thread->GetEcmaVM()->GetGlobalEnv(); 2424514f5e3Sopenharmony_ci bool isInstanceOf = JSFunction::InstanceOf(thread, rtf, env->GetRelativeTimeFormatFunction()); 2434514f5e3Sopenharmony_ci RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, rtf); 2444514f5e3Sopenharmony_ci if (!rtf->IsJSRelativeTimeFormat() && isInstanceOf) { 2454514f5e3Sopenharmony_ci JSHandle<JSTaggedValue> key(thread, JSHandle<JSIntl>::Cast(env->GetIntlFunction())->GetFallbackSymbol()); 2464514f5e3Sopenharmony_ci OperationResult operationResult = JSTaggedValue::GetProperty(thread, rtf, key); 2474514f5e3Sopenharmony_ci RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, rtf); 2484514f5e3Sopenharmony_ci return operationResult.GetValue(); 2494514f5e3Sopenharmony_ci } 2504514f5e3Sopenharmony_ci 2514514f5e3Sopenharmony_ci // Perform ? RequireInternalSlot(relativeTimeFormat, [[InitializedRelativeTimeFormat]]). 2524514f5e3Sopenharmony_ci if (!rtf->IsJSRelativeTimeFormat()) { 2534514f5e3Sopenharmony_ci RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, rtf); 2544514f5e3Sopenharmony_ci } 2554514f5e3Sopenharmony_ci return rtf; 2564514f5e3Sopenharmony_ci} 2574514f5e3Sopenharmony_ci 2584514f5e3Sopenharmony_ci// CommonFormat 2594514f5e3Sopenharmony_ciicu::FormattedRelativeDateTime GetIcuFormatted(JSThread *thread, 2604514f5e3Sopenharmony_ci const JSHandle<JSRelativeTimeFormat> &relativeTimeFormat, 2614514f5e3Sopenharmony_ci double value, const JSHandle<EcmaString> &unit) 2624514f5e3Sopenharmony_ci{ 2634514f5e3Sopenharmony_ci icu::RelativeDateTimeFormatter *formatter = relativeTimeFormat->GetIcuRTFFormatter(); 2644514f5e3Sopenharmony_ci ASSERT_PRINT(formatter != nullptr, "rtfFormatter is null"); 2654514f5e3Sopenharmony_ci 2664514f5e3Sopenharmony_ci // If isFinite(value) is false, then throw a RangeError exception. 2674514f5e3Sopenharmony_ci if (!std::isfinite(value)) { 2684514f5e3Sopenharmony_ci THROW_RANGE_ERROR_AND_RETURN(thread, "", icu::FormattedRelativeDateTime()); 2694514f5e3Sopenharmony_ci } 2704514f5e3Sopenharmony_ci 2714514f5e3Sopenharmony_ci // 10. If unit is not one of "second", "minute", "hour", "day", "week", "month", "quarter", or "year", throw a 2724514f5e3Sopenharmony_ci // RangeError exception. 2734514f5e3Sopenharmony_ci URelativeDateTimeUnit unitEnum; 2744514f5e3Sopenharmony_ci if (!SingularUnitToIcuUnit(thread, unit, &unitEnum)) { 2754514f5e3Sopenharmony_ci THROW_RANGE_ERROR_AND_RETURN(thread, "", icu::FormattedRelativeDateTime()); 2764514f5e3Sopenharmony_ci } 2774514f5e3Sopenharmony_ci UErrorCode status = U_ZERO_ERROR; 2784514f5e3Sopenharmony_ci NumericOption numeric = relativeTimeFormat->GetNumeric(); 2794514f5e3Sopenharmony_ci 2804514f5e3Sopenharmony_ci icu::FormattedRelativeDateTime formatted; 2814514f5e3Sopenharmony_ci switch (numeric) { 2824514f5e3Sopenharmony_ci case NumericOption::ALWAYS: 2834514f5e3Sopenharmony_ci formatted = formatter->formatNumericToValue(value, unitEnum, status); 2844514f5e3Sopenharmony_ci ASSERT_PRINT(U_SUCCESS(status), "icu format to value error"); 2854514f5e3Sopenharmony_ci break; 2864514f5e3Sopenharmony_ci case NumericOption::AUTO: 2874514f5e3Sopenharmony_ci formatted = formatter->formatToValue(value, unitEnum, status); 2884514f5e3Sopenharmony_ci ASSERT_PRINT(U_SUCCESS(status), "icu format to value error"); 2894514f5e3Sopenharmony_ci break; 2904514f5e3Sopenharmony_ci default: 2914514f5e3Sopenharmony_ci LOG_ECMA(FATAL) << "this branch is unreachable"; 2924514f5e3Sopenharmony_ci UNREACHABLE(); 2934514f5e3Sopenharmony_ci } 2944514f5e3Sopenharmony_ci return formatted; 2954514f5e3Sopenharmony_ci} 2964514f5e3Sopenharmony_ci 2974514f5e3Sopenharmony_ci// 14.1.2 SingularRelativeTimeUnit ( unit ) 2984514f5e3Sopenharmony_ciJSHandle<EcmaString> SingularUnitString(JSThread *thread, const JSHandle<EcmaString> &unit) 2994514f5e3Sopenharmony_ci{ 3004514f5e3Sopenharmony_ci auto globalConst = thread->GlobalConstants(); 3014514f5e3Sopenharmony_ci JSHandle<EcmaString> second = JSHandle<EcmaString>::Cast(globalConst->GetHandledSecondString()); 3024514f5e3Sopenharmony_ci JSHandle<EcmaString> minute = JSHandle<EcmaString>::Cast(globalConst->GetHandledMinuteString()); 3034514f5e3Sopenharmony_ci JSHandle<EcmaString> hour = JSHandle<EcmaString>::Cast(globalConst->GetHandledHourString()); 3044514f5e3Sopenharmony_ci JSHandle<EcmaString> day = JSHandle<EcmaString>::Cast(globalConst->GetHandledDayString()); 3054514f5e3Sopenharmony_ci JSHandle<EcmaString> week = JSHandle<EcmaString>::Cast(globalConst->GetHandledWeekString()); 3064514f5e3Sopenharmony_ci JSHandle<EcmaString> month = JSHandle<EcmaString>::Cast(globalConst->GetHandledMonthString()); 3074514f5e3Sopenharmony_ci JSHandle<EcmaString> quarter = JSHandle<EcmaString>::Cast(globalConst->GetHandledQuarterString()); 3084514f5e3Sopenharmony_ci JSHandle<EcmaString> year = JSHandle<EcmaString>::Cast(globalConst->GetHandledYearString()); 3094514f5e3Sopenharmony_ci JSHandle<EcmaString> seconds = JSHandle<EcmaString>::Cast(globalConst->GetHandledSecondsString()); 3104514f5e3Sopenharmony_ci JSHandle<EcmaString> minutes = JSHandle<EcmaString>::Cast(globalConst->GetHandledMinutesString()); 3114514f5e3Sopenharmony_ci JSHandle<EcmaString> hours = JSHandle<EcmaString>::Cast(globalConst->GetHandledHoursString()); 3124514f5e3Sopenharmony_ci JSHandle<EcmaString> days = JSHandle<EcmaString>::Cast(globalConst->GetHandledDaysString()); 3134514f5e3Sopenharmony_ci JSHandle<EcmaString> weeks = JSHandle<EcmaString>::Cast(globalConst->GetHandledWeeksString()); 3144514f5e3Sopenharmony_ci JSHandle<EcmaString> months = JSHandle<EcmaString>::Cast(globalConst->GetHandledMonthsString()); 3154514f5e3Sopenharmony_ci JSHandle<EcmaString> quarters = JSHandle<EcmaString>::Cast(globalConst->GetHandledQuartersString()); 3164514f5e3Sopenharmony_ci JSHandle<EcmaString> years = JSHandle<EcmaString>::Cast(globalConst->GetHandledYearsString()); 3174514f5e3Sopenharmony_ci 3184514f5e3Sopenharmony_ci // 2. If unit is "seconds" or "second", return "second". 3194514f5e3Sopenharmony_ci if (EcmaStringAccessor::StringsAreEqual(*second, *unit) || EcmaStringAccessor::StringsAreEqual(*seconds, *unit)) { 3204514f5e3Sopenharmony_ci return second; 3214514f5e3Sopenharmony_ci } 3224514f5e3Sopenharmony_ci // 3. If unit is "minutes" or "minute", return "minute". 3234514f5e3Sopenharmony_ci if (EcmaStringAccessor::StringsAreEqual(*minute, *unit) || EcmaStringAccessor::StringsAreEqual(*minutes, *unit)) { 3244514f5e3Sopenharmony_ci return minute; 3254514f5e3Sopenharmony_ci } 3264514f5e3Sopenharmony_ci // 4. If unit is "hours" or "hour", return "hour". 3274514f5e3Sopenharmony_ci if (EcmaStringAccessor::StringsAreEqual(*hour, *unit) || EcmaStringAccessor::StringsAreEqual(*hours, *unit)) { 3284514f5e3Sopenharmony_ci return hour; 3294514f5e3Sopenharmony_ci } 3304514f5e3Sopenharmony_ci // 5. If unit is "days" or "day", return "day". 3314514f5e3Sopenharmony_ci if (EcmaStringAccessor::StringsAreEqual(*day, *unit) || EcmaStringAccessor::StringsAreEqual(*days, *unit)) { 3324514f5e3Sopenharmony_ci return day; 3334514f5e3Sopenharmony_ci } 3344514f5e3Sopenharmony_ci // 6. If unit is "weeks" or "week", return "week". 3354514f5e3Sopenharmony_ci if (EcmaStringAccessor::StringsAreEqual(*week, *unit) || EcmaStringAccessor::StringsAreEqual(*weeks, *unit)) { 3364514f5e3Sopenharmony_ci return week; 3374514f5e3Sopenharmony_ci } 3384514f5e3Sopenharmony_ci // 7. If unit is "months" or "month", return "month". 3394514f5e3Sopenharmony_ci if (EcmaStringAccessor::StringsAreEqual(*month, *unit) || EcmaStringAccessor::StringsAreEqual(*months, *unit)) { 3404514f5e3Sopenharmony_ci return month; 3414514f5e3Sopenharmony_ci } 3424514f5e3Sopenharmony_ci // 8. If unit is "quarters" or "quarter", return "quarter". 3434514f5e3Sopenharmony_ci if (EcmaStringAccessor::StringsAreEqual(*quarter, *unit) || EcmaStringAccessor::StringsAreEqual(*quarters, *unit)) { 3444514f5e3Sopenharmony_ci return quarter; 3454514f5e3Sopenharmony_ci } 3464514f5e3Sopenharmony_ci // 9. If unit is "years" or "year", return "year". 3474514f5e3Sopenharmony_ci if (EcmaStringAccessor::StringsAreEqual(*year, *unit) || EcmaStringAccessor::StringsAreEqual(*years, *unit)) { 3484514f5e3Sopenharmony_ci return year; 3494514f5e3Sopenharmony_ci } 3504514f5e3Sopenharmony_ci 3514514f5e3Sopenharmony_ci JSHandle<JSTaggedValue> undefinedValue(thread, JSTaggedValue::Undefined()); 3524514f5e3Sopenharmony_ci return JSHandle<EcmaString>::Cast(undefinedValue); 3534514f5e3Sopenharmony_ci} 3544514f5e3Sopenharmony_ci 3554514f5e3Sopenharmony_ci// 14.1.5 FormatRelativeTime ( relativeTimeFormat, value, unit ) 3564514f5e3Sopenharmony_ciJSHandle<EcmaString> JSRelativeTimeFormat::Format(JSThread *thread, double value, const JSHandle<EcmaString> &unit, 3574514f5e3Sopenharmony_ci const JSHandle<JSRelativeTimeFormat> &relativeTimeFormat) 3584514f5e3Sopenharmony_ci{ 3594514f5e3Sopenharmony_ci ObjectFactory *factory = thread->GetEcmaVM()->GetFactory(); 3604514f5e3Sopenharmony_ci icu::FormattedRelativeDateTime formatted = GetIcuFormatted(thread, relativeTimeFormat, value, unit); 3614514f5e3Sopenharmony_ci RETURN_HANDLE_IF_ABRUPT_COMPLETION(EcmaString, thread); 3624514f5e3Sopenharmony_ci UErrorCode status = U_ZERO_ERROR; 3634514f5e3Sopenharmony_ci icu::UnicodeString uString = formatted.toString(status); 3644514f5e3Sopenharmony_ci if (U_FAILURE(status) != 0) { 3654514f5e3Sopenharmony_ci THROW_RANGE_ERROR_AND_RETURN(thread, "icu formatted toString error", factory->GetEmptyString()); 3664514f5e3Sopenharmony_ci } 3674514f5e3Sopenharmony_ci JSHandle<EcmaString> string = 3684514f5e3Sopenharmony_ci factory->NewFromUtf16(reinterpret_cast<const uint16_t *>(uString.getBuffer()), uString.length()); 3694514f5e3Sopenharmony_ci return string; 3704514f5e3Sopenharmony_ci} 3714514f5e3Sopenharmony_ci 3724514f5e3Sopenharmony_civoid FormatToArray(JSThread *thread, const JSHandle<JSArray> &array, 3734514f5e3Sopenharmony_ci const icu::FormattedRelativeDateTime &formatted, double value, 3744514f5e3Sopenharmony_ci const JSHandle<EcmaString> &unit) 3754514f5e3Sopenharmony_ci{ 3764514f5e3Sopenharmony_ci UErrorCode status = U_ZERO_ERROR; 3774514f5e3Sopenharmony_ci icu::UnicodeString formattedText = formatted.toString(status); 3784514f5e3Sopenharmony_ci if (U_FAILURE(status)) { 3794514f5e3Sopenharmony_ci THROW_TYPE_ERROR(thread, "formattedRelativeDateTime toString failed"); 3804514f5e3Sopenharmony_ci } 3814514f5e3Sopenharmony_ci 3824514f5e3Sopenharmony_ci icu::ConstrainedFieldPosition cfpo; 3834514f5e3Sopenharmony_ci // Set constrainCategory to UFIELD_CATEGORY_NUMBER which is specified for UNumberFormatFields 3844514f5e3Sopenharmony_ci cfpo.constrainCategory(UFIELD_CATEGORY_NUMBER); 3854514f5e3Sopenharmony_ci int32_t index = 0; 3864514f5e3Sopenharmony_ci int32_t previousLimit = 0; 3874514f5e3Sopenharmony_ci auto globalConst = thread->GlobalConstants(); 3884514f5e3Sopenharmony_ci JSHandle<JSTaggedValue> taggedValue(thread, JSTaggedValue(value)); 3894514f5e3Sopenharmony_ci JSMutableHandle<JSTaggedValue> typeString(thread, JSTaggedValue::Undefined()); 3904514f5e3Sopenharmony_ci JSHandle<JSTaggedValue> unitString = globalConst->GetHandledUnitString(); 3914514f5e3Sopenharmony_ci std::vector<std::pair<int32_t, int32_t>> separatorFields; 3924514f5e3Sopenharmony_ci /** 3934514f5e3Sopenharmony_ci * From ICU header file document @unumberformatter.h 3944514f5e3Sopenharmony_ci * Sets a constraint on the field category. 3954514f5e3Sopenharmony_ci * 3964514f5e3Sopenharmony_ci * When this instance of ConstrainedFieldPosition is passed to FormattedValue#nextPosition, 3974514f5e3Sopenharmony_ci * positions are skipped unless they have the given category. 3984514f5e3Sopenharmony_ci * 3994514f5e3Sopenharmony_ci * Any previously set constraints are cleared. 4004514f5e3Sopenharmony_ci * 4014514f5e3Sopenharmony_ci * For example, to loop over only the number-related fields: 4024514f5e3Sopenharmony_ci * 4034514f5e3Sopenharmony_ci * ConstrainedFieldPosition cfpo; 4044514f5e3Sopenharmony_ci * cfpo.constrainCategory(UFIELDCATEGORY_NUMBER_FORMAT); 4054514f5e3Sopenharmony_ci * while (fmtval.nextPosition(cfpo, status)) { 4064514f5e3Sopenharmony_ci * // handle the number-related field position 4074514f5e3Sopenharmony_ci * } 4084514f5e3Sopenharmony_ci */ 4094514f5e3Sopenharmony_ci while ((formatted.nextPosition(cfpo, status) != 0)) { 4104514f5e3Sopenharmony_ci int32_t fieldId = cfpo.getField(); 4114514f5e3Sopenharmony_ci int32_t start = cfpo.getStart(); 4124514f5e3Sopenharmony_ci int32_t limit = cfpo.getLimit(); 4134514f5e3Sopenharmony_ci // Special case when fieldId is UNUM_GROUPING_SEPARATOR_FIELD 4144514f5e3Sopenharmony_ci if (static_cast<UNumberFormatFields>(fieldId) == UNUM_GROUPING_SEPARATOR_FIELD) { 4154514f5e3Sopenharmony_ci separatorFields.push_back(std::pair<int32_t, int32_t>(start, limit)); 4164514f5e3Sopenharmony_ci continue; 4174514f5e3Sopenharmony_ci } 4184514f5e3Sopenharmony_ci // If start greater than previousLimit, means a literal type exists before number fields 4194514f5e3Sopenharmony_ci // so add a literal type with value of formattedText.sub(0, start) 4204514f5e3Sopenharmony_ci if (start > previousLimit) { 4214514f5e3Sopenharmony_ci typeString.Update(globalConst->GetLiteralString()); 4224514f5e3Sopenharmony_ci JSHandle<EcmaString> substring = 4234514f5e3Sopenharmony_ci intl::LocaleHelper::UStringToString(thread, formattedText, previousLimit, start); 4244514f5e3Sopenharmony_ci JSLocale::PutElement(thread, index++, array, typeString, JSHandle<JSTaggedValue>::Cast(substring)); 4254514f5e3Sopenharmony_ci RETURN_IF_ABRUPT_COMPLETION(thread); 4264514f5e3Sopenharmony_ci } 4274514f5e3Sopenharmony_ci // Add part when type is unit 4284514f5e3Sopenharmony_ci // Iterate former grouping separator vector and add unit element to array 4294514f5e3Sopenharmony_ci for (auto it = separatorFields.begin(); it != separatorFields.end(); it++) { 4304514f5e3Sopenharmony_ci if (it->first > start) { 4314514f5e3Sopenharmony_ci // Add Integer type element 4324514f5e3Sopenharmony_ci JSHandle<EcmaString> resString = 4334514f5e3Sopenharmony_ci intl::LocaleHelper::UStringToString(thread, formattedText, start, it->first); 4344514f5e3Sopenharmony_ci typeString.Update( 4354514f5e3Sopenharmony_ci JSLocale::GetNumberFieldType(thread, taggedValue.GetTaggedValue(), fieldId).GetTaggedValue()); 4364514f5e3Sopenharmony_ci JSHandle<JSObject> record = 4374514f5e3Sopenharmony_ci JSLocale::PutElement(thread, index++, array, typeString, JSHandle<JSTaggedValue>::Cast(resString)); 4384514f5e3Sopenharmony_ci RETURN_IF_ABRUPT_COMPLETION(thread); 4394514f5e3Sopenharmony_ci JSObject::CreateDataPropertyOrThrow(thread, record, unitString, JSHandle<JSTaggedValue>::Cast(unit)); 4404514f5e3Sopenharmony_ci RETURN_IF_ABRUPT_COMPLETION(thread); 4414514f5e3Sopenharmony_ci // Add Group type element 4424514f5e3Sopenharmony_ci resString = intl::LocaleHelper::UStringToString(thread, formattedText, it->first, it->second); 4434514f5e3Sopenharmony_ci typeString.Update(JSLocale::GetNumberFieldType(thread, taggedValue.GetTaggedValue(), 4444514f5e3Sopenharmony_ci UNUM_GROUPING_SEPARATOR_FIELD).GetTaggedValue()); 4454514f5e3Sopenharmony_ci record = 4464514f5e3Sopenharmony_ci JSLocale::PutElement(thread, index++, array, typeString, JSHandle<JSTaggedValue>::Cast(resString)); 4474514f5e3Sopenharmony_ci RETURN_IF_ABRUPT_COMPLETION(thread); 4484514f5e3Sopenharmony_ci JSObject::CreateDataPropertyOrThrow(thread, record, unitString, JSHandle<JSTaggedValue>::Cast(unit)); 4494514f5e3Sopenharmony_ci RETURN_IF_ABRUPT_COMPLETION(thread); 4504514f5e3Sopenharmony_ci start = it->second; 4514514f5e3Sopenharmony_ci } 4524514f5e3Sopenharmony_ci } 4534514f5e3Sopenharmony_ci // Add current field unit 4544514f5e3Sopenharmony_ci JSHandle<EcmaString> subString = intl::LocaleHelper::UStringToString(thread, formattedText, start, limit); 4554514f5e3Sopenharmony_ci typeString.Update(JSLocale::GetNumberFieldType(thread, taggedValue.GetTaggedValue(), fieldId).GetTaggedValue()); 4564514f5e3Sopenharmony_ci JSHandle<JSObject> record = 4574514f5e3Sopenharmony_ci JSLocale::PutElement(thread, index++, array, typeString, JSHandle<JSTaggedValue>::Cast(subString)); 4584514f5e3Sopenharmony_ci RETURN_IF_ABRUPT_COMPLETION(thread); 4594514f5e3Sopenharmony_ci JSObject::CreateDataPropertyOrThrow(thread, record, unitString, JSHandle<JSTaggedValue>::Cast(unit)); 4604514f5e3Sopenharmony_ci RETURN_IF_ABRUPT_COMPLETION(thread); 4614514f5e3Sopenharmony_ci previousLimit = limit; 4624514f5e3Sopenharmony_ci } 4634514f5e3Sopenharmony_ci // If iterated length is smaller than formattedText.length, means a literal type exists after number fields 4644514f5e3Sopenharmony_ci // so add a literal type with value of formattedText.sub(previousLimit, formattedText.length) 4654514f5e3Sopenharmony_ci if (formattedText.length() > previousLimit) { 4664514f5e3Sopenharmony_ci typeString.Update(globalConst->GetLiteralString()); 4674514f5e3Sopenharmony_ci JSHandle<EcmaString> substring = 4684514f5e3Sopenharmony_ci intl::LocaleHelper::UStringToString(thread, formattedText, previousLimit, formattedText.length()); 4694514f5e3Sopenharmony_ci JSLocale::PutElement(thread, index, array, typeString, JSHandle<JSTaggedValue>::Cast(substring)); 4704514f5e3Sopenharmony_ci RETURN_IF_ABRUPT_COMPLETION(thread); 4714514f5e3Sopenharmony_ci } 4724514f5e3Sopenharmony_ci} 4734514f5e3Sopenharmony_ci 4744514f5e3Sopenharmony_ci// 14.1.6 FormatRelativeTimeToParts ( relativeTimeFormat, value, unit ) 4754514f5e3Sopenharmony_ciJSHandle<JSArray> JSRelativeTimeFormat::FormatToParts(JSThread *thread, double value, const JSHandle<EcmaString> &unit, 4764514f5e3Sopenharmony_ci const JSHandle<JSRelativeTimeFormat> &relativeTimeFormat) 4774514f5e3Sopenharmony_ci{ 4784514f5e3Sopenharmony_ci icu::FormattedRelativeDateTime formatted = GetIcuFormatted(thread, relativeTimeFormat, value, unit); 4794514f5e3Sopenharmony_ci RETURN_HANDLE_IF_ABRUPT_COMPLETION(JSArray, thread); 4804514f5e3Sopenharmony_ci JSHandle<EcmaString> singularUnit = SingularUnitString(thread, unit); 4814514f5e3Sopenharmony_ci JSHandle<JSArray> array = JSHandle<JSArray>::Cast(JSArray::ArrayCreate(thread, JSTaggedNumber(0))); 4824514f5e3Sopenharmony_ci RETURN_HANDLE_IF_ABRUPT_COMPLETION(JSArray, thread); 4834514f5e3Sopenharmony_ci FormatToArray(thread, array, formatted, value, singularUnit); 4844514f5e3Sopenharmony_ci return array; 4854514f5e3Sopenharmony_ci} 4864514f5e3Sopenharmony_ci 4874514f5e3Sopenharmony_civoid JSRelativeTimeFormat::ResolvedOptions(JSThread *thread, const JSHandle<JSRelativeTimeFormat> &relativeTimeFormat, 4884514f5e3Sopenharmony_ci const JSHandle<JSObject> &options) 4894514f5e3Sopenharmony_ci{ 4904514f5e3Sopenharmony_ci if (relativeTimeFormat->GetIcuRTFFormatter() != nullptr) { 4914514f5e3Sopenharmony_ci [[maybe_unused]] icu::RelativeDateTimeFormatter *formatter = relativeTimeFormat->GetIcuRTFFormatter(); 4924514f5e3Sopenharmony_ci } else { 4934514f5e3Sopenharmony_ci THROW_ERROR(thread, ErrorType::RANGE_ERROR, "rtf is not initialized"); 4944514f5e3Sopenharmony_ci } 4954514f5e3Sopenharmony_ci 4964514f5e3Sopenharmony_ci auto globalConst = thread->GlobalConstants(); 4974514f5e3Sopenharmony_ci // [[locale]] 4984514f5e3Sopenharmony_ci JSHandle<JSTaggedValue> property = globalConst->GetHandledLocaleString(); 4994514f5e3Sopenharmony_ci JSHandle<EcmaString> locale(thread, relativeTimeFormat->GetLocale()); 5004514f5e3Sopenharmony_ci PropertyDescriptor localeDesc(thread, JSHandle<JSTaggedValue>::Cast(locale), true, true, true); 5014514f5e3Sopenharmony_ci JSObject::DefineOwnProperty(thread, options, property, localeDesc); 5024514f5e3Sopenharmony_ci 5034514f5e3Sopenharmony_ci // [[Style]] 5044514f5e3Sopenharmony_ci property = globalConst->GetHandledStyleString(); 5054514f5e3Sopenharmony_ci RelativeStyleOption style = relativeTimeFormat->GetStyle(); 5064514f5e3Sopenharmony_ci JSHandle<JSTaggedValue> styleValue; 5074514f5e3Sopenharmony_ci if (style == RelativeStyleOption::LONG) { 5084514f5e3Sopenharmony_ci styleValue = globalConst->GetHandledLongString(); 5094514f5e3Sopenharmony_ci } else if (style == RelativeStyleOption::SHORT) { 5104514f5e3Sopenharmony_ci styleValue = globalConst->GetHandledShortString(); 5114514f5e3Sopenharmony_ci } else if (style == RelativeStyleOption::NARROW) { 5124514f5e3Sopenharmony_ci styleValue = globalConst->GetHandledNarrowString(); 5134514f5e3Sopenharmony_ci } 5144514f5e3Sopenharmony_ci PropertyDescriptor styleDesc(thread, styleValue, true, true, true); 5154514f5e3Sopenharmony_ci JSObject::DefineOwnProperty(thread, options, property, styleDesc); 5164514f5e3Sopenharmony_ci 5174514f5e3Sopenharmony_ci // [[Numeric]] 5184514f5e3Sopenharmony_ci property = globalConst->GetHandledNumericString(); 5194514f5e3Sopenharmony_ci NumericOption numeric = relativeTimeFormat->GetNumeric(); 5204514f5e3Sopenharmony_ci JSHandle<JSTaggedValue> numericValue; 5214514f5e3Sopenharmony_ci if (numeric == NumericOption::ALWAYS) { 5224514f5e3Sopenharmony_ci numericValue = globalConst->GetHandledAlwaysString(); 5234514f5e3Sopenharmony_ci } else if (numeric == NumericOption::AUTO) { 5244514f5e3Sopenharmony_ci numericValue = globalConst->GetHandledAutoString(); 5254514f5e3Sopenharmony_ci } else { 5264514f5e3Sopenharmony_ci THROW_ERROR(thread, ErrorType::RANGE_ERROR, "numeric is exception"); 5274514f5e3Sopenharmony_ci } 5284514f5e3Sopenharmony_ci PropertyDescriptor numericDesc(thread, numericValue, true, true, true); 5294514f5e3Sopenharmony_ci JSObject::DefineOwnProperty(thread, options, property, numericDesc); 5304514f5e3Sopenharmony_ci 5314514f5e3Sopenharmony_ci // [[NumberingSystem]] 5324514f5e3Sopenharmony_ci property = JSHandle<JSTaggedValue>::Cast(globalConst->GetHandledNumberingSystemString()); 5334514f5e3Sopenharmony_ci JSHandle<JSTaggedValue> numberingSystem(thread, relativeTimeFormat->GetNumberingSystem()); 5344514f5e3Sopenharmony_ci PropertyDescriptor numberingSystemDesc(thread, numberingSystem, true, true, true); 5354514f5e3Sopenharmony_ci JSObject::DefineOwnProperty(thread, options, property, numberingSystemDesc); 5364514f5e3Sopenharmony_ci} 5374514f5e3Sopenharmony_ci} // namespace panda::ecmascript