diff --git a/frameworks/intl/BUILD.gn b/frameworks/intl/BUILD.gn index 7c7e626d..15dc49d6 100755 --- a/frameworks/intl/BUILD.gn +++ b/frameworks/intl/BUILD.gn @@ -46,6 +46,7 @@ ohos_shared_library("intl_util") { "src/number_format.cpp", "src/phone_number_format.cpp", "src/plural_rules.cpp", + "src/relative_time_format.cpp", "src/str_util.cpp", ] cflags_cc = [ diff --git a/frameworks/intl/include/measure_data.h b/frameworks/intl/include/measure_data.h index a1117a33..1daf4702 100644 --- a/frameworks/intl/include/measure_data.h +++ b/frameworks/intl/include/measure_data.h @@ -17,6 +17,7 @@ #include #include +#include "unicode/measunit.h" namespace OHOS { namespace Global { diff --git a/frameworks/intl/include/relative_time_format.h b/frameworks/intl/include/relative_time_format.h new file mode 100644 index 00000000..6b0e285b --- /dev/null +++ b/frameworks/intl/include/relative_time_format.h @@ -0,0 +1,77 @@ +/* + * Copyright (c) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#ifndef OHOS_GLOBAL_I18N_RELATIVE_TIME_FORMAT_H +#define OHOS_GLOBAL_I18N_RELATIVE_TIME_FORMAT_H + +#include +#include +#include +#include +#include "unicode/numberformatter.h" +#include "unicode/locid.h" +#include "unicode/numfmt.h" +#include "unicode/unum.h" +#include "unicode/decimfmt.h" +#include "unicode/localebuilder.h" +#include "unicode/numsys.h" +#include "unicode/measfmt.h" +#include "unicode/measunit.h" +#include "unicode/measure.h" +#include "unicode/currunit.h" +#include "unicode/fmtable.h" +#include "unicode/reldatefmt.h" +#include "unicode/uformattedvalue.h" +#include "unicode/ures.h" +#include "unicode/unum.h" +#include "unicode/ulocdata.h" +#include "unicode/ureldatefmt.h" +#include "number_utils.h" +#include "number_utypes.h" +#include "locale_info.h" +#include "measure_data.h" + +namespace OHOS { +namespace Global { +namespace I18n { +class RelativeTimeFormat { +public: + RelativeTimeFormat(const std::vector &localeTag, std::map &configs); + virtual ~RelativeTimeFormat(); + std::string Format(double number, const std::string &unit); + void FormatToParts(double number, const std::string &unit, std::vector> &timeVector); + void GetResolvedOptions(std::map &map); + +private: + icu::Locale locale; + std::string localeBaseName; + std::string styleString = "long"; + std::string numeric = "always"; + std::string numberingSystem; + LocaleInfo *localeInfo = nullptr; + icu::NumberFormat *numberFormat = nullptr; + icu::RelativeDateTimeFormatter *relativeTimeFormat = nullptr; + UDateRelativeDateTimeFormatterStyle style = UDAT_STYLE_LONG; + static std::unordered_map relativeUnits; + static std::unordered_map relativeFormatStyle; + void InsertInfo(std::vector> &timeVector, const std::string &unit, bool isInteger, + const std::string &value); + void ProcessIntegerField(const std::map &indexMap, std::vector> &timeVector, + int &startIndex, const std::string &unit, const std::string &result); + void ParseConfigs(std::map &configs); +}; +} // namespace I18n +} // namespace Global +} // namespace OHOS +#endif \ No newline at end of file diff --git a/frameworks/intl/src/measure_data.cpp b/frameworks/intl/src/measure_data.cpp index a54df401..86c992be 100644 --- a/frameworks/intl/src/measure_data.cpp +++ b/frameworks/intl/src/measure_data.cpp @@ -32,6 +32,7 @@ const int REGION_OFFSET = 7; const int BASE_VALUE_SIZE = 2; const int FACTOR_SIZE = 2; const int CHAR_OFFSET = 48; +const int MAX_UNIT_NUM = 500; const std::unordered_map> USAGE_001 { { "area-land-agricult", { "hectare" } }, @@ -550,6 +551,22 @@ int Convert(double &value, const string &fromUnit, const string &fromMeasSys, co double baseResult = 0.0; double result = 0.0; vector fromFactors = {0.0, 0.0}; + string fromUnitType; + string toUnitType; + icu::MeasureUnit unitArray[MAX_UNIT_NUM]; + UErrorCode icuStatus = U_ZERO_ERROR; + icu::MeasureUnit::getAvailable(unitArray, MAX_UNIT_NUM, icuStatus); + for (icu::MeasureUnit curUnit : unitArray) { + if (strcmp(curUnit.getSubtype(), fromUnit.c_str()) == 0) { + fromUnitType = curUnit.getType(); + } + if (strcmp(curUnit.getSubtype(), toUnit.c_str()) == 0) { + toUnitType = curUnit.getType(); + } + } + if (fromUnitType.empty() || toUnitType.empty() || strcmp(fromUnitType.c_str(), toUnitType.c_str()) != 0) { + return 0; + } int status = ComputeValue(fromUnit, fromMeasSys, fromFactors); if (status == 0) { return 0; diff --git a/frameworks/intl/src/relative_time_format.cpp b/frameworks/intl/src/relative_time_format.cpp new file mode 100644 index 00000000..e9fed803 --- /dev/null +++ b/frameworks/intl/src/relative_time_format.cpp @@ -0,0 +1,213 @@ +/* + * Copyright (c) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include +#include +#include "locale_config.h" +#include "ohos/init_data.h" +#include "relative_time_format.h" + +namespace OHOS { +namespace Global { +namespace I18n { +std::unordered_map RelativeTimeFormat::relativeFormatStyle = { + { "long", UDAT_STYLE_LONG }, + { "short", UDAT_STYLE_SHORT }, + { "narrow", UDAT_STYLE_NARROW } +}; + +std::unordered_map RelativeTimeFormat::relativeUnits = { + { "second", UDAT_REL_UNIT_SECOND }, + { "seconds", UDAT_REL_UNIT_SECOND }, + { "minute", UDAT_REL_UNIT_MINUTE }, + { "minutes", UDAT_REL_UNIT_MINUTE }, + { "hour", UDAT_REL_UNIT_HOUR }, + { "hours", UDAT_REL_UNIT_HOUR }, + { "day", UDAT_REL_UNIT_DAY }, + { "days", UDAT_REL_UNIT_DAY }, + { "week", UDAT_REL_UNIT_WEEK }, + { "weeks", UDAT_REL_UNIT_WEEK }, + { "month", UDAT_REL_UNIT_MONTH }, + { "months", UDAT_REL_UNIT_MONTH }, + { "quarter", UDAT_REL_UNIT_QUARTER }, + { "quarters", UDAT_REL_UNIT_QUARTER }, + { "year", UDAT_REL_UNIT_YEAR }, + { "years", UDAT_REL_UNIT_YEAR }, +}; + +RelativeTimeFormat::RelativeTimeFormat(const std::vector &localeTags, std::map &configs) +{ + UErrorCode status = U_ZERO_ERROR; + auto builder = std::make_unique(); + ParseConfigs(configs); + for (size_t i = 0; i < localeTags.size(); i++) { + std::string curLocale = localeTags[i]; + locale = builder->setLanguageTag(icu::StringPiece(curLocale)).build(status); + if (LocaleInfo::allValidLocales.count(locale.getLanguage()) > 0) { + localeInfo = new LocaleInfo(curLocale, configs); + locale = localeInfo->GetLocale(); + localeBaseName = localeInfo->GetBaseName(); + numberFormat = icu::NumberFormat::createInstance(locale, UNUM_DECIMAL, status); + if (numberFormat == nullptr) { + continue; + } + relativeTimeFormat = new icu::RelativeDateTimeFormatter(locale, numberFormat, style, + UDISPCTX_CAPITALIZATION_NONE, status); + break; + } + } + if (localeInfo == nullptr || relativeTimeFormat == nullptr) { + localeInfo = new LocaleInfo(LocaleConfig::GetSystemLocale(), configs); + locale = localeInfo->GetLocale(); + localeBaseName = localeInfo->GetBaseName(); + numberFormat = icu::NumberFormat::createInstance(locale, UNUM_DECIMAL, status); + relativeTimeFormat = new icu::RelativeDateTimeFormatter(locale, numberFormat, style, + UDISPCTX_CAPITALIZATION_NONE, status); + } + numberingSystem = localeInfo->GetNumberingSystem(); +} + +RelativeTimeFormat::~RelativeTimeFormat() +{ + if (localeInfo != nullptr) { + delete localeInfo; + localeInfo = nullptr; + } + if (numberFormat != nullptr) { + delete numberFormat; + numberFormat = nullptr; + } + if (relativeTimeFormat != nullptr) { + delete relativeTimeFormat; + relativeTimeFormat = nullptr; + } +} + +void RelativeTimeFormat::ParseConfigs(std::map &configs) +{ + if (configs.count("style") > 0) { + styleString = configs["style"]; + if (relativeFormatStyle.count(styleString) > 0) { + style = relativeFormatStyle[styleString]; + } + } + if (configs.count("numeric") > 0) { + numeric = configs["numeric"]; + } +} + +std::string RelativeTimeFormat::Format(double number, const std::string &unit) +{ + if (relativeUnits.count(unit) == 0) { + return ""; + } + UErrorCode status = U_ZERO_ERROR; + icu::UnicodeString formattedTime; + std::string result; + if (strcmp(numeric.c_str(), "always") == 0) { + formattedTime = relativeTimeFormat->formatNumericToValue(number, relativeUnits[unit], status).toString(status); + } else { + formattedTime = relativeTimeFormat->formatToValue(number, relativeUnits[unit], status).toString(status); + } + formattedTime.toUTF8String(result); + return result; +} + +void RelativeTimeFormat::InsertInfo(std::vector> &timeVector, + const std::string &unit, bool isInteger, const std::string &value) +{ + std::vector info; + if (isInteger) { + info.push_back("integer"); + info.push_back(value); + info.push_back(unit); + } else { + info.push_back("literal"); + info.push_back(value); + } + timeVector.push_back(info); +} + +void RelativeTimeFormat::ProcessIntegerField(const std::map &indexMap, + std::vector> &timeVector, int &startIndex, const std::string &unit, + const std::string &result) +{ + for (auto iter = indexMap.begin(); iter != indexMap.end(); iter++) { + if (iter->first > startIndex) { + InsertInfo(timeVector, unit, true, result.substr(startIndex, iter->first - startIndex)); + InsertInfo(timeVector, unit, true, result.substr(iter->first, iter->second - iter->first)); + startIndex = iter->second; + } + } +} + +void RelativeTimeFormat::FormatToParts(double number, const std::string &unit, + std::vector> &timeVector) +{ + if (relativeUnits.count(unit) == 0) { + return; + } + UErrorCode status = U_ZERO_ERROR; + std::string result; + icu::FormattedRelativeDateTime fmtRelativeTime; + if (numeric.empty() || strcmp(numeric.c_str(), "always") == 0) { + fmtRelativeTime = relativeTimeFormat->formatNumericToValue(number, relativeUnits[unit], status); + } else { + fmtRelativeTime = relativeTimeFormat->formatToValue(number, relativeUnits[unit], status); + } + fmtRelativeTime.toString(status).toUTF8String(result); + icu::ConstrainedFieldPosition constrainedPos; + constrainedPos.constrainCategory(UFIELD_CATEGORY_NUMBER); + int prevIndex = 0; + int length = result.length(); + std::map indexMap; + while (fmtRelativeTime.nextPosition(constrainedPos, status)) { + int startIndex = constrainedPos.getStart(); + if (constrainedPos.getCategory() == UFIELD_CATEGORY_NUMBER) { + if (constrainedPos.getField() == UNUM_GROUPING_SEPARATOR_FIELD) { + indexMap.insert(std::make_pair(startIndex, constrainedPos.getLimit())); + continue; + } + if (startIndex > prevIndex) { + InsertInfo(timeVector, unit, false, result.substr(prevIndex, startIndex - prevIndex)); + } + if (constrainedPos.getField() == UNUM_INTEGER_FIELD) { + ProcessIntegerField(indexMap, timeVector, startIndex, unit, result); + } + InsertInfo(timeVector, unit, true, result.substr(startIndex, constrainedPos.getLimit() - startIndex)); + prevIndex = constrainedPos.getLimit(); + } + } + if (prevIndex < length) { + InsertInfo(timeVector, unit, false, result.substr(prevIndex, length - prevIndex)); + } +} + +void RelativeTimeFormat::GetResolvedOptions(std::map &map) +{ + map.insert(std::make_pair("locale", localeBaseName)); + if (!styleString.empty()) { + map.insert(std::make_pair("style", styleString)); + } + if (!numeric.empty()) { + map.insert(std::make_pair("numeric", numeric)); + } + if (!numberingSystem.empty()) { + map.insert(std::make_pair("numberingSystem", numberingSystem)); + } +} +} // namespace I18n +} // namespace Global +} // namespace OHOS \ No newline at end of file diff --git a/interfaces/js/kits/include/intl_addon.h b/interfaces/js/kits/include/intl_addon.h index 98f92ab9..04317721 100644 --- a/interfaces/js/kits/include/intl_addon.h +++ b/interfaces/js/kits/include/intl_addon.h @@ -23,6 +23,7 @@ #include "locale_info.h" #include "date_time_format.h" #include "number_format.h" +#include "relative_time_format.h" #include "collator.h" #include "plural_rules.h" @@ -46,6 +47,7 @@ void SetIntegerOptionProperties(napi_env env, napi_value &result, std::map &options, const std::string &option); void SetBooleanOptionProperties(napi_env env, napi_value &result, std::map &options, const std::string &option); +void GetRelativeTimeOptionValues(napi_env env, napi_value options, std::map &map); class IntlAddon { public: @@ -53,6 +55,7 @@ public: static napi_value InitDateTimeFormat(napi_env env, napi_value exports); static napi_value InitNumberFormat(napi_env env, napi_value exports); static napi_value InitCollator(napi_env env, napi_value exports); + static napi_value InitRelativeTimeFormat(napi_env env, napi_value exports); static napi_value InitPluralRules(napi_env env, napi_value exports); static void Destructor(napi_env env, void *nativeObject, void *finalize_hint); @@ -63,6 +66,7 @@ private: static napi_value DateTimeFormatConstructor(napi_env env, napi_callback_info info); static napi_value NumberFormatConstructor(napi_env env, napi_callback_info info); static napi_value LocaleConstructor(napi_env env, napi_callback_info info); + static napi_value RelativeTimeFormatConstructor(napi_env env, napi_callback_info info); static napi_value GetLanguage(napi_env env, napi_callback_info info); static napi_value GetScript(napi_env env, napi_callback_info info); static napi_value GetRegion(napi_env env, napi_callback_info info); @@ -81,6 +85,12 @@ private: static napi_value FormatDateTimeRange(napi_env env, napi_callback_info info); static napi_value GetDateTimeResolvedOptions(napi_env env, napi_callback_info info); + static napi_value FormatRelativeTime(napi_env env, napi_callback_info info); + static napi_value FormatToParts(napi_env env, napi_callback_info info); + static void FillInArrayElement(napi_env env, napi_value &result, napi_status &status, + const std::vector> &timeVector); + static napi_value GetRelativeTimeResolvedOptions(napi_env env, napi_callback_info info); + static napi_value GetNumberResolvedOptions(napi_env env, napi_callback_info info); static napi_value FormatNumber(napi_env env, napi_callback_info info); @@ -105,6 +115,8 @@ private: std::map &map); bool InitCollatorContext(napi_env env, napi_callback_info info, std::vector localeTags, std::map &map); + bool InitRelativeTimeFormatContext(napi_env env, napi_callback_info info, std::vector localeTags, + std::map &map); bool InitPluralRulesContext(napi_env env, napi_callback_info info, std::vector localeTags, std::map &map); @@ -113,6 +125,7 @@ private: std::unique_ptr locale_; std::unique_ptr datefmt_; std::unique_ptr numberfmt_; + std::unique_ptr relativetimefmt_; std::unique_ptr collator_; std::unique_ptr pluralrules_; }; diff --git a/interfaces/js/kits/src/intl_addon.cpp b/interfaces/js/kits/src/intl_addon.cpp index 6dba79ef..cd549f2d 100644 --- a/interfaces/js/kits/src/intl_addon.cpp +++ b/interfaces/js/kits/src/intl_addon.cpp @@ -113,6 +113,31 @@ napi_value IntlAddon::InitDateTimeFormat(napi_env env, napi_value exports) return exports; } +napi_value IntlAddon::InitRelativeTimeFormat(napi_env env, napi_value exports) +{ + napi_status status = napi_ok; + napi_property_descriptor properties[] = { + DECLARE_NAPI_FUNCTION("format", FormatRelativeTime), + DECLARE_NAPI_FUNCTION("formatToParts", FormatToParts), + DECLARE_NAPI_FUNCTION("resolvedOptions", GetRelativeTimeResolvedOptions) + }; + + napi_value constructor = nullptr; + status = napi_define_class(env, "RelativeTimeFormat", NAPI_AUTO_LENGTH, RelativeTimeFormatConstructor, nullptr, + sizeof(properties) / sizeof(napi_property_descriptor), properties, &constructor); + if (status != napi_ok) { + HiLog::Error(LABEL, "Define class failed when InitRelativeTimeFormat"); + return nullptr; + } + + status = napi_set_named_property(env, exports, "RelativeTimeFormat", constructor); + if (status != napi_ok) { + HiLog::Error(LABEL, "Set property failed when InitRelativeTimeFormat"); + return nullptr; + } + return exports; +} + napi_value IntlAddon::InitNumberFormat(napi_env env, napi_value exports) { napi_status status = napi_ok; @@ -231,6 +256,13 @@ void GetDateOptionValues(napi_env env, napi_value options, std::map &map) +{ + GetOptionValue(env, options, "localeMatcher", map); + GetOptionValue(env, options, "numeric", map); + GetOptionValue(env, options, "style", map); +} + std::string GetLocaleTag(napi_env env, napi_value argv) { std::string localeTag = ""; @@ -399,6 +431,70 @@ bool IntlAddon::InitDateTimeFormatContext(napi_env env, napi_callback_info info, return datefmt_ != nullptr; } +napi_value IntlAddon::RelativeTimeFormatConstructor(napi_env env, napi_callback_info info) +{ + // Need to get one parameter of a locale in string format to create DateTimeFormat object. + size_t argc = 2; + napi_value argv[2] = { 0 }; + napi_value thisVar = nullptr; + void *data = nullptr; + napi_status status = napi_get_cb_info(env, info, &argc, argv, &thisVar, &data); + + std::vector localeTags; + if (argv[0] != nullptr) { + napi_valuetype valueType = napi_valuetype::napi_undefined; + napi_typeof(env, argv[0], &valueType); + bool isArray = false; + napi_is_array(env, argv[0], &isArray); + if (valueType == napi_valuetype::napi_string) { + GetLocaleTags(env, argv[0], localeTags); + } else if (isArray) { + uint32_t arrayLength = 0; + napi_get_array_length(env, argv[0], &arrayLength); + napi_value element = nullptr; + for (uint32_t i = 0; i < arrayLength; i++) { + napi_get_element(env, argv[0], i, &element); + GetLocaleTags(env, element, localeTags); + } + } + } + + std::map map = {}; + if (argv[1] != nullptr) { + GetRelativeTimeOptionValues(env, argv[1], map); + } + + std::unique_ptr obj = std::make_unique(); + if (obj == nullptr) { + HiLog::Error(LABEL, "Create IntlAddon failed"); + return nullptr; + } + + status = + napi_wrap(env, thisVar, reinterpret_cast(obj.get()), IntlAddon::Destructor, nullptr, &obj->wrapper_); + if (status != napi_ok) { + HiLog::Error(LABEL, "Wrap IntlAddon failed"); + return nullptr; + } + + if (!obj->InitRelativeTimeFormatContext(env, info, localeTags, map)) { + HiLog::Error(LABEL, "Init RelativeTimeFormat failed"); + return nullptr; + } + + obj.release(); + return thisVar; +} + +bool IntlAddon::InitRelativeTimeFormatContext(napi_env env, napi_callback_info info, + std::vector localeTags, std::map &map) +{ + env_ = env; + relativetimefmt_ = std::make_unique(localeTags, map); + + return relativetimefmt_ != nullptr; +} + napi_value IntlAddon::FormatDateTime(napi_env env, napi_callback_info info) { size_t argc = 1; @@ -1100,6 +1196,31 @@ void SetBooleanOptionProperties(napi_env env, napi_value &result, std::map(&obj)); + if (status != napi_ok || obj == nullptr || obj->relativetimefmt_ == nullptr) { + HiLog::Error(LABEL, "Get RelativeTimeFormat object failed"); + return nullptr; + } + napi_value result = nullptr; + napi_create_object(env, &result); + std::map options = {}; + obj->relativetimefmt_->GetResolvedOptions(options); + SetOptionProperties(env, result, options, "locale"); + SetOptionProperties(env, result, options, "style"); + SetOptionProperties(env, result, options, "numeric"); + SetOptionProperties(env, result, options, "numberingSystem"); + return result; +} + napi_value IntlAddon::GetDateTimeResolvedOptions(napi_env env, napi_callback_info info) { size_t argc = 0; @@ -1445,6 +1566,115 @@ bool GetStringParameter(napi_env env, napi_value value, std::vector &buf) return true; } +napi_value IntlAddon::FormatRelativeTime(napi_env env, napi_callback_info info) +{ + size_t argc = 2; + napi_value argv[2] = { 0 }; + napi_value thisVar = nullptr; + void *data = nullptr; + napi_get_cb_info(env, info, &argc, argv, &thisVar, &data); + napi_status status; + double number; + status = napi_get_value_double(env, argv[0], &number); + if (status != napi_ok) { + HiLog::Error(LABEL, "Get number failed"); + return nullptr; + } + std::vector unit; + if (!GetStringParameter(env, argv[1], unit)) { + return nullptr; + } + IntlAddon *obj = nullptr; + status = napi_unwrap(env, thisVar, reinterpret_cast(&obj)); + if (status != napi_ok || obj == nullptr || obj->relativetimefmt_ == nullptr) { + HiLog::Error(LABEL, "Get RelativeTimeFormat object failed"); + return nullptr; + } + std::string value = obj->relativetimefmt_->Format(number, unit.data()); + napi_value result = nullptr; + status = napi_create_string_utf8(env, value.c_str(), NAPI_AUTO_LENGTH, &result); + if (status != napi_ok) { + HiLog::Error(LABEL, "Create format string failed"); + return nullptr; + } + return result; +} + +void IntlAddon::FillInArrayElement(napi_env env, napi_value &result, napi_status &status, + const std::vector> &timeVector) +{ + for (size_t i = 0; i < timeVector.size(); i++) { + napi_value value = nullptr; + status = napi_create_string_utf8(env, timeVector[i][1].c_str(), NAPI_AUTO_LENGTH, &value); + if (status != napi_ok) { + HiLog::Error(LABEL, "Failed to create string item."); + return; + } + napi_value type = nullptr; + status = napi_create_string_utf8(env, timeVector[i][0].c_str(), NAPI_AUTO_LENGTH, &type); + if (status != napi_ok) { + HiLog::Error(LABEL, "Failed to create string item."); + return; + } + napi_value unit = nullptr; + int unitIndex = 2; + if (timeVector[i].size() > unitIndex) { + status = napi_create_string_utf8(env, timeVector[i][unitIndex].c_str(), NAPI_AUTO_LENGTH, &unit); + if (status != napi_ok) { + HiLog::Error(LABEL, "Failed to create string item."); + return; + } + } else { + napi_get_undefined(env, &unit); + } + napi_value formatInfo; + status = napi_create_object(env, &formatInfo); + if (status != napi_ok) { + HiLog::Error(LABEL, "Failed to create format info object."); + return; + } + napi_set_named_property(env, formatInfo, "type", type); + napi_set_named_property(env, formatInfo, "value", value); + napi_set_named_property(env, formatInfo, "unit", unit); + status = napi_set_element(env, result, i, formatInfo); + if (status != napi_ok) { + HiLog::Error(LABEL, "Failed to set array item"); + return; + } + } +} + +napi_value IntlAddon::FormatToParts(napi_env env, napi_callback_info info) +{ + size_t argc = 2; + napi_value argv[2] = { 0 }; + napi_value thisVar = nullptr; + void *data = nullptr; + napi_get_cb_info(env, info, &argc, argv, &thisVar, &data); + double number = 0; + napi_get_value_double(env, argv[0], &number); + std::vector unit; + if (!GetStringParameter(env, argv[1], unit)) { + return nullptr; + } + IntlAddon *obj = nullptr; + napi_status status = napi_unwrap(env, thisVar, reinterpret_cast(&obj)); + if (status != napi_ok || obj == nullptr || obj->relativetimefmt_ == nullptr) { + HiLog::Error(LABEL, "Get RelativeTimeFormat object failed"); + return nullptr; + } + std::vector> timeVector; + obj->relativetimefmt_->FormatToParts(number, unit.data(), timeVector); + napi_value result = nullptr; + status = napi_create_array_with_length(env, timeVector.size(), &result); + if (status != napi_ok) { + HiLog::Error(LABEL, "Failed to create array"); + return nullptr; + } + FillInArrayElement(env, result, status, timeVector); + return result; +} + napi_value IntlAddon::CompareString(napi_env env, napi_callback_info info) { size_t argc = 2; @@ -1735,6 +1965,7 @@ napi_value Init(napi_env env, napi_value exports) val = IntlAddon::InitDateTimeFormat(env, val); val = IntlAddon::InitNumberFormat(env, val); val = IntlAddon::InitCollator(env, val); + val = IntlAddon::InitRelativeTimeFormat(env, val); return IntlAddon::InitPluralRules(env, val); }