1/*
2 * Copyright (c) 2021-2022 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 *     http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16#include "intl_addon.h"
17
18#include <vector>
19#include <set>
20#include "error_util.h"
21#include "i18n_hilog.h"
22#include "js_utils.h"
23#include "node_api.h"
24#include "utils.h"
25
26namespace OHOS {
27namespace Global {
28namespace I18n {
29static thread_local napi_ref *g_constructor = nullptr;
30
31IntlAddon::IntlAddon() : env_(nullptr) {}
32
33IntlAddon::~IntlAddon()
34{
35}
36
37void IntlAddon::Destructor(napi_env env, void *nativeObject, void *hint)
38{
39    if (!nativeObject) {
40        return;
41    }
42    delete reinterpret_cast<IntlAddon *>(nativeObject);
43    nativeObject = nullptr;
44}
45
46napi_value IntlAddon::SetProperty(napi_env env, napi_callback_info info)
47{
48    // do nothing but provided as an input parameter for DECLARE_NAPI_GETTER_SETTER;
49    napi_value result = nullptr;
50    NAPI_CALL(env, napi_get_undefined(env, &result));
51    return result;
52}
53
54napi_value IntlAddon::InitLocale(napi_env env, napi_value exports)
55{
56    napi_status status = napi_ok;
57    napi_property_descriptor properties[] = {
58        DECLARE_NAPI_GETTER_SETTER("language", GetLanguage, SetProperty),
59        DECLARE_NAPI_GETTER_SETTER("baseName", GetBaseName, SetProperty),
60        DECLARE_NAPI_GETTER_SETTER("region", GetRegion, SetProperty),
61        DECLARE_NAPI_GETTER_SETTER("script", GetScript, SetProperty),
62        DECLARE_NAPI_GETTER_SETTER("calendar", GetCalendar, SetProperty),
63        DECLARE_NAPI_GETTER_SETTER("collation", GetCollation, SetProperty),
64        DECLARE_NAPI_GETTER_SETTER("hourCycle", GetHourCycle, SetProperty),
65        DECLARE_NAPI_GETTER_SETTER("numberingSystem", GetNumberingSystem, SetProperty),
66        DECLARE_NAPI_GETTER_SETTER("numeric", GetNumeric, SetProperty),
67        DECLARE_NAPI_GETTER_SETTER("caseFirst", GetCaseFirst, SetProperty),
68        DECLARE_NAPI_FUNCTION("toString", ToString),
69        DECLARE_NAPI_FUNCTION("minimize", Minimize),
70        DECLARE_NAPI_FUNCTION("maximize", Maximize),
71    };
72
73    napi_value constructor = nullptr;
74    status = napi_define_class(env, "Locale", NAPI_AUTO_LENGTH, LocaleConstructor, nullptr,
75        sizeof(properties) / sizeof(napi_property_descriptor), properties, &constructor);
76    if (status != napi_ok) {
77        HILOG_ERROR_I18N("Define class failed when InitLocale");
78        return nullptr;
79    }
80
81    status = napi_set_named_property(env, exports, "Locale", constructor);
82    if (status != napi_ok) {
83        HILOG_ERROR_I18N("Set property failed when InitLocale");
84        return nullptr;
85    }
86    g_constructor = new (std::nothrow) napi_ref;
87    if (!g_constructor) {
88        HILOG_ERROR_I18N("Failed to create ref at init");
89        return nullptr;
90    }
91    status = napi_create_reference(env, constructor, 1, g_constructor);
92    if (status != napi_ok) {
93        HILOG_ERROR_I18N("Failed to create reference at init");
94        return nullptr;
95    }
96    return exports;
97}
98
99napi_value IntlAddon::InitDateTimeFormat(napi_env env, napi_value exports)
100{
101    napi_status status = napi_ok;
102    napi_property_descriptor properties[] = {
103        DECLARE_NAPI_FUNCTION("format", FormatDateTime),
104        DECLARE_NAPI_FUNCTION("formatRange", FormatDateTimeRange),
105        DECLARE_NAPI_FUNCTION("resolvedOptions", GetDateTimeResolvedOptions)
106    };
107
108    napi_value constructor = nullptr;
109    status = napi_define_class(env, "DateTimeFormat", NAPI_AUTO_LENGTH, DateTimeFormatConstructor, nullptr,
110        sizeof(properties) / sizeof(napi_property_descriptor), properties, &constructor);
111    if (status != napi_ok) {
112        HILOG_ERROR_I18N("Define class failed when InitDateTimeFormat");
113        return nullptr;
114    }
115
116    status = napi_set_named_property(env, exports, "DateTimeFormat", constructor);
117    if (status != napi_ok) {
118        HILOG_ERROR_I18N("Set property failed when InitDateTimeFormat");
119        return nullptr;
120    }
121    return exports;
122}
123
124napi_value IntlAddon::InitRelativeTimeFormat(napi_env env, napi_value exports)
125{
126    napi_status status = napi_ok;
127    napi_property_descriptor properties[] = {
128        DECLARE_NAPI_FUNCTION("format", FormatRelativeTime),
129        DECLARE_NAPI_FUNCTION("formatToParts", FormatToParts),
130        DECLARE_NAPI_FUNCTION("resolvedOptions", GetRelativeTimeResolvedOptions)
131    };
132
133    napi_value constructor = nullptr;
134    status = napi_define_class(env, "RelativeTimeFormat", NAPI_AUTO_LENGTH, RelativeTimeFormatConstructor, nullptr,
135        sizeof(properties) / sizeof(napi_property_descriptor), properties, &constructor);
136    if (status != napi_ok) {
137        HILOG_ERROR_I18N("Define class failed when InitRelativeTimeFormat");
138        return nullptr;
139    }
140
141    status = napi_set_named_property(env, exports, "RelativeTimeFormat", constructor);
142    if (status != napi_ok) {
143        HILOG_ERROR_I18N("Set property failed when InitRelativeTimeFormat");
144        return nullptr;
145    }
146    return exports;
147}
148
149napi_value IntlAddon::InitNumberFormat(napi_env env, napi_value exports)
150{
151    napi_status status = napi_ok;
152    napi_property_descriptor properties[] = {
153        DECLARE_NAPI_FUNCTION("format", FormatNumber),
154        DECLARE_NAPI_FUNCTION("resolvedOptions", GetNumberResolvedOptions)
155    };
156
157    napi_value constructor = nullptr;
158    status = napi_define_class(env, "NumberFormat", NAPI_AUTO_LENGTH, NumberFormatConstructor, nullptr,
159        sizeof(properties) / sizeof(napi_property_descriptor), properties, &constructor);
160    if (status != napi_ok) {
161        HILOG_ERROR_I18N("Define class failed when InitNumberFormat");
162        return nullptr;
163    }
164
165    status = napi_set_named_property(env, exports, "NumberFormat", constructor);
166    if (status != napi_ok) {
167        HILOG_ERROR_I18N("Set property failed when InitNumberFormat");
168        return nullptr;
169    }
170    return exports;
171}
172
173void GetOptionValue(napi_env env, napi_value options, const std::string &optionName,
174    std::map<std::string, std::string> &map)
175{
176    napi_value optionValue = nullptr;
177    napi_valuetype type = napi_undefined;
178    napi_status status = napi_typeof(env, options, &type);
179    if (status != napi_ok && type != napi_object) {
180        HILOG_ERROR_I18N("Get option failed, option is not an object");
181        return;
182    }
183    bool hasProperty = false;
184    napi_status propStatus = napi_has_named_property(env, options, optionName.c_str(), &hasProperty);
185    if (propStatus == napi_ok && hasProperty) {
186        status = napi_get_named_property(env, options, optionName.c_str(), &optionValue);
187        if (status == napi_ok) {
188            size_t len = 0;
189            napi_get_value_string_utf8(env, optionValue, nullptr, 0, &len);
190            std::vector<char> optionBuf(len + 1);
191            status = napi_get_value_string_utf8(env, optionValue, optionBuf.data(), len + 1, &len);
192            if (status != napi_ok) {
193                return;
194            }
195            map.insert(make_pair(optionName, optionBuf.data()));
196        }
197    }
198}
199
200int64_t GetIntegerOptionValue(napi_env env, napi_value options, const std::string &optionName,
201    std::map<std::string, std::string> &map)
202{
203    napi_value optionValue = nullptr;
204    int64_t integerValue = -1;
205    napi_valuetype type = napi_undefined;
206    napi_status status = napi_typeof(env, options, &type);
207    if (status != napi_ok && type != napi_object) {
208        HILOG_ERROR_I18N("GetIntegerOptionValue: Set option failed, option is not an object");
209        return integerValue;
210    }
211    bool hasProperty = false;
212    napi_status propStatus = napi_has_named_property(env, options, optionName.c_str(), &hasProperty);
213    if (propStatus == napi_ok && hasProperty) {
214        status = napi_get_named_property(env, options, optionName.c_str(), &optionValue);
215        if (status == napi_ok) {
216            status = napi_get_value_int64(env, optionValue, &integerValue);
217            if (status == napi_ok) {
218                map.insert(make_pair(optionName, std::to_string(integerValue)));
219            }
220        }
221    }
222    return integerValue;
223}
224
225void GetBoolOptionValue(napi_env env, napi_value options, const std::string &optionName,
226    std::map<std::string, std::string> &map)
227{
228    napi_value optionValue = nullptr;
229    napi_valuetype type = napi_undefined;
230    napi_status status = napi_typeof(env, options, &type);
231    if (status != napi_ok && type != napi_object) {
232        HILOG_ERROR_I18N("GetBoolOptionValue: Set option failed, option is not an object");
233        return;
234    }
235    bool hasProperty = false;
236    napi_status propStatus = napi_has_named_property(env, options, optionName.c_str(), &hasProperty);
237    if (propStatus == napi_ok && hasProperty) {
238        status = napi_get_named_property(env, options, optionName.c_str(), &optionValue);
239        if (status == napi_ok) {
240            bool boolValue = false;
241            napi_get_value_bool(env, optionValue, &boolValue);
242            std::string value = boolValue ? "true" : "false";
243            map.insert(make_pair(optionName, value));
244        }
245    }
246}
247
248void GetDateOptionValues(napi_env env, napi_value options, std::map<std::string, std::string> &map)
249{
250    GetOptionValue(env, options, "calendar", map);
251    GetOptionValue(env, options, "dateStyle", map);
252    GetOptionValue(env, options, "timeStyle", map);
253    GetOptionValue(env, options, "hourCycle", map);
254    GetOptionValue(env, options, "timeZone", map);
255    GetOptionValue(env, options, "timeZoneName", map);
256    GetOptionValue(env, options, "numberingSystem", map);
257    GetBoolOptionValue(env, options, "hour12", map);
258    GetOptionValue(env, options, "weekday", map);
259    GetOptionValue(env, options, "era", map);
260    GetOptionValue(env, options, "year", map);
261    GetOptionValue(env, options, "month", map);
262    GetOptionValue(env, options, "day", map);
263    GetOptionValue(env, options, "hour", map);
264    GetOptionValue(env, options, "minute", map);
265    GetOptionValue(env, options, "second", map);
266    GetOptionValue(env, options, "localeMatcher", map);
267    GetOptionValue(env, options, "formatMatcher", map);
268    GetOptionValue(env, options, "dayPeriod", map);
269}
270
271void GetRelativeTimeOptionValues(napi_env env, napi_value options, std::map<std::string, std::string> &map)
272{
273    GetOptionValue(env, options, "localeMatcher", map);
274    GetOptionValue(env, options, "numeric", map);
275    GetOptionValue(env, options, "style", map);
276}
277
278std::string GetLocaleTag(napi_env env, napi_value argv)
279{
280    std::string localeTag = "";
281    std::vector<char> buf;
282    if (argv != nullptr) {
283        napi_valuetype valueType = napi_valuetype::napi_undefined;
284        napi_typeof(env, argv, &valueType);
285        if (valueType != napi_valuetype::napi_string) {
286            HILOG_ERROR_I18N("GetLocaleTag: Parameter type does not match");
287            return "";
288        }
289        size_t len = 0;
290        napi_status status = napi_get_value_string_utf8(env, argv, nullptr, 0, &len);
291        if (status != napi_ok) {
292            HILOG_ERROR_I18N("GetLocaleTag -> string: Get locale tag length failed");
293            return "";
294        }
295        buf.resize(len + 1);
296        status = napi_get_value_string_utf8(env, argv, buf.data(), len + 1, &len);
297        if (status != napi_ok) {
298            HILOG_ERROR_I18N("GetLocaleTag: Get locale tag failed");
299            return "";
300        }
301        localeTag = buf.data();
302    } else {
303        localeTag = "";
304    }
305    return localeTag;
306}
307
308napi_value IntlAddon::LocaleConstructor(napi_env env, napi_callback_info info)
309{
310    size_t argc = 2;
311    napi_value argv[2] = { nullptr };
312    napi_value thisVar = nullptr;
313    void *data = nullptr;
314    napi_status status = napi_get_cb_info(env, info, &argc, argv, &thisVar, &data);
315    if (status != napi_ok) {
316        return nullptr;
317    }
318    std::string localeTag = GetLocaleTag(env, argc > 0 ? argv[0] : nullptr);
319
320    std::map<std::string, std::string> map = {};
321    if (argc > 1) {
322        GetOptionValue(env, argv[1], "calendar", map);
323        GetOptionValue(env, argv[1], "collation", map);
324        GetOptionValue(env, argv[1], "hourCycle", map);
325        GetOptionValue(env, argv[1], "numberingSystem", map);
326        GetBoolOptionValue(env, argv[1], "numeric", map);
327        GetOptionValue(env, argv[1], "caseFirst", map);
328    }
329    std::unique_ptr<IntlAddon> obj = nullptr;
330    obj = std::make_unique<IntlAddon>();
331    status =
332        napi_wrap(env, thisVar, reinterpret_cast<void *>(obj.get()), IntlAddon::Destructor, nullptr, nullptr);
333    if (status != napi_ok) {
334        HILOG_ERROR_I18N("LocaleConstructor: Wrap IntlAddon failed");
335        return nullptr;
336    }
337    if (!obj->InitLocaleContext(env, info, localeTag, map)) {
338        return nullptr;
339    }
340    obj.release();
341    return thisVar;
342}
343
344bool IntlAddon::InitLocaleContext(napi_env env, napi_callback_info info, const std::string localeTag,
345    std::map<std::string, std::string> &map)
346{
347    napi_value global = nullptr;
348    napi_status status = napi_get_global(env, &global);
349    if (status != napi_ok) {
350        HILOG_ERROR_I18N("InitLocaleContext: Get global failed");
351        return false;
352    }
353    env_ = env;
354    locale_ = std::make_unique<LocaleInfo>(localeTag, map);
355
356    return locale_ != nullptr;
357}
358
359void GetLocaleTags(napi_env env, napi_value rawLocaleTag, std::vector<std::string> &localeTags)
360{
361    size_t len = 0;
362    napi_status status = napi_get_value_string_utf8(env, rawLocaleTag, nullptr, 0, &len);
363    if (status != napi_ok) {
364        HILOG_ERROR_I18N("GetLocaleTag -> void: Get locale tag length failed");
365        return;
366    }
367    std::vector<char> buf(len + 1);
368    status = napi_get_value_string_utf8(env, rawLocaleTag, buf.data(), len + 1, &len);
369    if (status != napi_ok) {
370        HILOG_ERROR_I18N("GetLocaleTags: Get locale tag failed");
371        return;
372    }
373    localeTags.push_back(buf.data());
374}
375
376napi_value IntlAddon::DateTimeFormatConstructor(napi_env env, napi_callback_info info)
377{
378    size_t argc = 2;
379    napi_value argv[2] = { nullptr };
380    napi_value thisVar = nullptr;
381    void *data = nullptr;
382    napi_status status = napi_get_cb_info(env, info, &argc, argv, &thisVar, &data);
383    if (status != napi_ok) {
384        return nullptr;
385    }
386    std::vector<std::string> localeTags;
387    if (argc > 0) {
388        napi_valuetype valueType = napi_valuetype::napi_undefined;
389        napi_typeof(env, argv[0], &valueType);
390        bool isArray = false;
391        napi_is_array(env, argv[0], &isArray);
392        if (valueType == napi_valuetype::napi_string) {
393            GetLocaleTags(env, argv[0], localeTags);
394        } else if (isArray) {
395            uint32_t arrayLength = 0;
396            napi_get_array_length(env, argv[0], &arrayLength);
397            napi_value element = nullptr;
398            for (uint32_t i = 0; i < arrayLength; i++) {
399                napi_get_element(env, argv[0], i, &element);
400                GetLocaleTags(env, element, localeTags);
401            }
402        }
403    }
404    std::map<std::string, std::string> map = {};
405    if (argc > 1) {
406        GetDateOptionValues(env, argv[1], map);
407    }
408    std::unique_ptr<IntlAddon> obj = nullptr;
409    obj = std::make_unique<IntlAddon>();
410    status =
411        napi_wrap(env, thisVar, reinterpret_cast<void *>(obj.get()), IntlAddon::Destructor, nullptr, nullptr);
412    if (status != napi_ok) {
413        HILOG_ERROR_I18N("DateTimeFormatConstructor: Wrap IntlAddon failed");
414        return nullptr;
415    }
416    if (!obj->InitDateTimeFormatContext(env, info, localeTags, map)) {
417        HILOG_ERROR_I18N("DateTimeFormatConstructor: Init DateTimeFormat failed");
418        return nullptr;
419    }
420    obj.release();
421    return thisVar;
422}
423
424bool IntlAddon::InitDateTimeFormatContext(napi_env env, napi_callback_info info, std::vector<std::string> localeTags,
425    std::map<std::string, std::string> &map)
426{
427    napi_value global = nullptr;
428    napi_status status = napi_get_global(env, &global);
429    if (status != napi_ok) {
430        HILOG_ERROR_I18N("InitDateTimeFormatContext: Get global failed");
431        return false;
432    }
433    env_ = env;
434    datefmt_ = DateTimeFormat::CreateInstance(localeTags, map);
435
436    return datefmt_ != nullptr;
437}
438
439napi_value IntlAddon::RelativeTimeFormatConstructor(napi_env env, napi_callback_info info)
440{
441    size_t argc = 2;
442    napi_value argv[2] = { nullptr };
443    napi_value thisVar = nullptr;
444    void *data = nullptr;
445    napi_status status = napi_get_cb_info(env, info, &argc, argv, &thisVar, &data);
446    if (status != napi_ok) {
447        return nullptr;
448    }
449    std::vector<std::string> localeTags;
450    if (argc > 0) {
451        napi_valuetype valueType = napi_valuetype::napi_undefined;
452        napi_typeof(env, argv[0], &valueType);
453        bool isArray = false;
454        napi_is_array(env, argv[0], &isArray);
455        if (valueType == napi_valuetype::napi_string) {
456            GetLocaleTags(env, argv[0], localeTags);
457        } else if (isArray) {
458            uint32_t arrayLength = 0;
459            napi_get_array_length(env, argv[0], &arrayLength);
460            napi_value element = nullptr;
461            for (uint32_t i = 0; i < arrayLength; i++) {
462                napi_get_element(env, argv[0], i, &element);
463                GetLocaleTags(env, element, localeTags);
464            }
465        }
466    }
467    std::map<std::string, std::string> map = {};
468    if (argc > 1) {
469        GetRelativeTimeOptionValues(env, argv[1], map);
470    }
471    std::unique_ptr<IntlAddon> obj = nullptr;
472    obj = std::make_unique<IntlAddon>();
473    status =
474        napi_wrap(env, thisVar, reinterpret_cast<void *>(obj.get()), IntlAddon::Destructor, nullptr, nullptr);
475    if (status != napi_ok) {
476        HILOG_ERROR_I18N("RelativeTimeFormatConstructor: Wrap IntlAddon failed");
477        return nullptr;
478    }
479    if (!obj->InitRelativeTimeFormatContext(env, info, localeTags, map)) {
480        HILOG_ERROR_I18N("Init RelativeTimeFormat failed");
481        return nullptr;
482    }
483    obj.release();
484    return thisVar;
485}
486
487bool IntlAddon::InitRelativeTimeFormatContext(napi_env env, napi_callback_info info,
488    std::vector<std::string> localeTags, std::map<std::string, std::string> &map)
489{
490    env_ = env;
491    relativetimefmt_ = std::make_unique<RelativeTimeFormat>(localeTags, map);
492
493    return relativetimefmt_ != nullptr;
494}
495
496napi_value IntlAddon::FormatDateTime(napi_env env, napi_callback_info info)
497{
498    size_t argc = 1;
499    napi_value argv[1] = { 0 };
500    napi_value thisVar = nullptr;
501    void *data = nullptr;
502    napi_get_cb_info(env, info, &argc, argv, &thisVar, &data);
503
504    int64_t milliseconds = GetMilliseconds(env, argv, 0);
505    if (milliseconds == -1) {
506        return nullptr;
507    }
508    IntlAddon *obj = nullptr;
509    napi_status status = napi_unwrap(env, thisVar, reinterpret_cast<void **>(&obj));
510    if (status != napi_ok || !obj || !obj->datefmt_) {
511        HILOG_ERROR_I18N("FormatDateTime: Get DateTimeFormat object failed");
512        return nullptr;
513    }
514    std::string value = obj->datefmt_->Format(milliseconds);
515    napi_value result = nullptr;
516    status = napi_create_string_utf8(env, value.c_str(), NAPI_AUTO_LENGTH, &result);
517    if (status != napi_ok) {
518        HILOG_ERROR_I18N("FormatDateTime: Create format string failed");
519        return nullptr;
520    }
521    return result;
522}
523
524napi_value IntlAddon::FormatDateTimeRange(napi_env env, napi_callback_info info)
525{
526    size_t argc = 2;
527    napi_value argv[2] = { nullptr };
528    napi_value thisVar = nullptr;
529    void *data = nullptr;
530    napi_get_cb_info(env, info, &argc, argv, &thisVar, &data);
531    if (argc < FUNC_ARGS_COUNT) {
532        HILOG_ERROR_I18N("Parameter wrong");
533        return nullptr;
534    }
535    int64_t firstMilliseconds = GetMilliseconds(env, argv, 0);
536    int64_t secondMilliseconds = GetMilliseconds(env, argv, 1);
537    if (firstMilliseconds == -1 || secondMilliseconds == -1) {
538        return nullptr;
539    }
540    IntlAddon *obj = nullptr;
541    napi_status status = napi_unwrap(env, thisVar, reinterpret_cast<void **>(&obj));
542    if (status != napi_ok || !obj || !obj->datefmt_) {
543        HILOG_ERROR_I18N("FormatDateTimeRange: Get DateTimeFormat object failed");
544        return nullptr;
545    }
546    std::string value = obj->datefmt_->FormatRange(firstMilliseconds, secondMilliseconds);
547    napi_value result = nullptr;
548    status = napi_create_string_utf8(env, value.c_str(), NAPI_AUTO_LENGTH, &result);
549    if (status != napi_ok) {
550        HILOG_ERROR_I18N("FormatDateTimeRange: Create format string failed");
551        return nullptr;
552    }
553    return result;
554}
555
556void GetNumberOptionValues(napi_env env, napi_value options, std::map<std::string, std::string> &map)
557{
558    GetOptionValue(env, options, "currency", map);
559    GetOptionValue(env, options, "currencySign", map);
560    GetOptionValue(env, options, "currencyDisplay", map);
561    GetOptionValue(env, options, "unit", map);
562    GetOptionValue(env, options, "unitDisplay", map);
563    GetOptionValue(env, options, "compactDisplay", map);
564    GetOptionValue(env, options, "signDisplay", map);
565    GetOptionValue(env, options, "localeMatcher", map);
566    GetOptionValue(env, options, "style", map);
567    GetOptionValue(env, options, "numberingSystem", map);
568    GetOptionValue(env, options, "notation", map);
569    GetOptionValue(env, options, "unitUsage", map);
570    GetBoolOptionValue(env, options, "useGrouping", map);
571    GetIntegerOptionValue(env, options, "minimumIntegerDigits", map);
572    int64_t minFd = GetIntegerOptionValue(env, options, "minimumFractionDigits", map);
573    int64_t maxFd = GetIntegerOptionValue(env, options, "maximumFractionDigits", map);
574    if (minFd != -1 && maxFd != -1 && minFd > maxFd) {
575        HILOG_ERROR_I18N(
576            "GetNumberOptionValues: Invalid parameter value: minimumFractionDigits > maximumFractionDigits");
577    }
578    GetIntegerOptionValue(env, options, "minimumSignificantDigits", map);
579    GetIntegerOptionValue(env, options, "maximumSignificantDigits", map);
580}
581
582napi_value IntlAddon::NumberFormatConstructor(napi_env env, napi_callback_info info)
583{
584    size_t argc = 2;
585    napi_value argv[2] = { nullptr };
586    napi_value thisVar = nullptr;
587    void *data = nullptr;
588    napi_status status = napi_get_cb_info(env, info, &argc, argv, &thisVar, &data);
589    if (status != napi_ok) {
590        return nullptr;
591    }
592    std::vector<std::string> localeTags;
593    if (argc > 0) {
594        napi_valuetype valueType = napi_valuetype::napi_undefined;
595        napi_typeof(env, argv[0], &valueType);
596        bool isArray = false;
597        napi_is_array(env, argv[0], &isArray);
598
599        if (valueType == napi_valuetype::napi_string) {
600            GetLocaleTags(env, argv[0], localeTags);
601        } else if (isArray) {
602            uint32_t arrayLength = 0;
603            napi_get_array_length(env, argv[0], &arrayLength);
604            napi_value element = nullptr;
605            for (uint32_t i = 0; i < arrayLength; i++) {
606                napi_get_element(env, argv[0], i, &element);
607                GetLocaleTags(env, element, localeTags);
608            }
609        }
610    }
611    std::map<std::string, std::string> map = {};
612    if (argc > 1) {
613        GetNumberOptionValues(env, argv[1], map);
614    }
615    std::unique_ptr<IntlAddon> obj = nullptr;
616    obj = std::make_unique<IntlAddon>();
617    status =
618        napi_wrap(env, thisVar, reinterpret_cast<void *>(obj.get()), IntlAddon::Destructor, nullptr, nullptr);
619    if (status != napi_ok) {
620        HILOG_ERROR_I18N("NumberFormatConstructor: Wrap IntlAddon failed");
621        return nullptr;
622    }
623    if (!obj->InitNumberFormatContext(env, info, localeTags, map)) {
624        HILOG_ERROR_I18N("Init NumberFormat failed");
625        return nullptr;
626    }
627    obj.release();
628    return thisVar;
629}
630
631bool IntlAddon::InitNumberFormatContext(napi_env env, napi_callback_info info, std::vector<std::string> localeTags,
632    std::map<std::string, std::string> &map)
633{
634    napi_value global = nullptr;
635    napi_status status = napi_get_global(env, &global);
636    if (status != napi_ok) {
637        HILOG_ERROR_I18N("InitNumberFormatContext: Get global failed");
638        return false;
639    }
640    env_ = env;
641    numberfmt_ = std::make_unique<NumberFormat>(localeTags, map);
642
643    return numberfmt_ != nullptr;
644}
645
646int64_t IntlAddon::GetMilliseconds(napi_env env, napi_value *argv, int index)
647{
648    napi_value funcGetDateInfo = nullptr;
649    napi_status status = napi_get_named_property(env, argv[index], "getTime", &funcGetDateInfo);
650    if (status != napi_ok) {
651        HILOG_ERROR_I18N("Get Milliseconds property failed");
652        return -1;
653    }
654    napi_value ret_value = nullptr;
655    status = napi_call_function(env, argv[index], funcGetDateInfo, 0, nullptr, &ret_value);
656    if (status != napi_ok) {
657        HILOG_ERROR_I18N("Get Milliseconds function failed");
658        return -1;
659    }
660    int64_t milliseconds = 0;
661    status = napi_get_value_int64(env, ret_value, &milliseconds);
662    if (status != napi_ok) {
663        HILOG_ERROR_I18N("Get Milliseconds failed");
664        return -1;
665    }
666    return milliseconds;
667}
668
669napi_value IntlAddon::GetLanguage(napi_env env, napi_callback_info info)
670{
671    napi_value thisVar = nullptr;
672    void *data = nullptr;
673    napi_get_cb_info(env, info, nullptr, nullptr, &thisVar, &data);
674
675    IntlAddon *obj = nullptr;
676    napi_status status = napi_unwrap(env, thisVar, reinterpret_cast<void **>(&obj));
677    if (status != napi_ok || !obj || !obj->locale_) {
678        HILOG_ERROR_I18N("GetLanguage: Get Locale object failed");
679        return nullptr;
680    }
681    std::string value = obj->locale_->GetLanguage();
682
683    napi_value result = nullptr;
684    status = napi_create_string_utf8(env, value.c_str(), NAPI_AUTO_LENGTH, &result);
685    if (status != napi_ok) {
686        HILOG_ERROR_I18N("GetLanguage: Create language string failed");
687        return nullptr;
688    }
689    return result;
690}
691
692napi_value IntlAddon::GetScript(napi_env env, napi_callback_info info)
693{
694    napi_value thisVar = nullptr;
695    void *data = nullptr;
696    napi_get_cb_info(env, info, nullptr, nullptr, &thisVar, &data);
697
698    IntlAddon *obj = nullptr;
699    napi_status status = napi_unwrap(env, thisVar, reinterpret_cast<void **>(&obj));
700    if (status != napi_ok || !obj || !obj->locale_) {
701        HILOG_ERROR_I18N("GetScript: Get Locale object failed");
702        return nullptr;
703    }
704    std::string value = obj->locale_->GetScript();
705
706    napi_value result = nullptr;
707    status = napi_create_string_utf8(env, value.c_str(), NAPI_AUTO_LENGTH, &result);
708    if (status != napi_ok) {
709        HILOG_ERROR_I18N("Create script string failed");
710        return nullptr;
711    }
712    return result;
713}
714
715napi_value IntlAddon::GetRegion(napi_env env, napi_callback_info info)
716{
717    napi_value thisVar = nullptr;
718    void *data = nullptr;
719    napi_get_cb_info(env, info, nullptr, nullptr, &thisVar, &data);
720
721    IntlAddon *obj = nullptr;
722    napi_status status = napi_unwrap(env, thisVar, reinterpret_cast<void **>(&obj));
723    if (status != napi_ok || !obj || !obj->locale_) {
724        HILOG_ERROR_I18N("GetRegion: Get Locale object failed");
725        return nullptr;
726    }
727    std::string value = obj->locale_->GetRegion();
728
729    napi_value result = nullptr;
730    status = napi_create_string_utf8(env, value.c_str(), NAPI_AUTO_LENGTH, &result);
731    if (status != napi_ok) {
732        HILOG_ERROR_I18N("Create region string failed");
733        return nullptr;
734    }
735    return result;
736}
737
738napi_value IntlAddon::GetBaseName(napi_env env, napi_callback_info info)
739{
740    napi_value thisVar = nullptr;
741    void *data = nullptr;
742    napi_get_cb_info(env, info, nullptr, nullptr, &thisVar, &data);
743
744    IntlAddon *obj = nullptr;
745    napi_status status = napi_unwrap(env, thisVar, reinterpret_cast<void **>(&obj));
746    if (status != napi_ok || !obj || !obj->locale_) {
747        HILOG_ERROR_I18N("GetBaseName: Get Locale object failed");
748        return nullptr;
749    }
750    std::string value = obj->locale_->GetBaseName();
751
752    napi_value result = nullptr;
753    status = napi_create_string_utf8(env, value.c_str(), NAPI_AUTO_LENGTH, &result);
754    if (status != napi_ok) {
755        HILOG_ERROR_I18N("GetBaseName: Create base name string failed");
756        return nullptr;
757    }
758    return result;
759}
760
761napi_value IntlAddon::GetCalendar(napi_env env, napi_callback_info info)
762{
763    napi_value thisVar = nullptr;
764    void *data = nullptr;
765    napi_get_cb_info(env, info, nullptr, nullptr, &thisVar, &data);
766
767    IntlAddon *obj = nullptr;
768    napi_status status = napi_unwrap(env, thisVar, reinterpret_cast<void **>(&obj));
769    if (status != napi_ok || !obj || !obj->locale_) {
770        HILOG_ERROR_I18N("GetCalendar: Get Locale object failed");
771        return nullptr;
772    }
773    std::string value = obj->locale_->GetCalendar();
774
775    napi_value result = nullptr;
776    status = napi_create_string_utf8(env, value.c_str(), NAPI_AUTO_LENGTH, &result);
777    if (status != napi_ok) {
778        HILOG_ERROR_I18N("GetCalendar: Create base name string failed");
779        return nullptr;
780    }
781    return result;
782}
783
784napi_value IntlAddon::GetCollation(napi_env env, napi_callback_info info)
785{
786    napi_value thisVar = nullptr;
787    void *data = nullptr;
788    napi_get_cb_info(env, info, nullptr, nullptr, &thisVar, &data);
789
790    IntlAddon *obj = nullptr;
791    napi_status status = napi_unwrap(env, thisVar, reinterpret_cast<void **>(&obj));
792    if (status != napi_ok || !obj || !obj->locale_) {
793        HILOG_ERROR_I18N("GetCollation: Get Locale object failed");
794        return nullptr;
795    }
796    std::string value = obj->locale_->GetCollation();
797
798    napi_value result = nullptr;
799    status = napi_create_string_utf8(env, value.c_str(), NAPI_AUTO_LENGTH, &result);
800    if (status != napi_ok) {
801        HILOG_ERROR_I18N("GetCollation: Create base name string failed");
802        return nullptr;
803    }
804    return result;
805}
806
807napi_value IntlAddon::GetHourCycle(napi_env env, napi_callback_info info)
808{
809    napi_value thisVar = nullptr;
810    void *data = nullptr;
811    napi_get_cb_info(env, info, nullptr, nullptr, &thisVar, &data);
812
813    IntlAddon *obj = nullptr;
814    napi_status status = napi_unwrap(env, thisVar, reinterpret_cast<void **>(&obj));
815    if (status != napi_ok || !obj || !obj->locale_) {
816        HILOG_ERROR_I18N("GetHourCycle: Get Locale object failed");
817        return nullptr;
818    }
819    std::string value = obj->locale_->GetHourCycle();
820
821    napi_value result = nullptr;
822    status = napi_create_string_utf8(env, value.c_str(), NAPI_AUTO_LENGTH, &result);
823    if (status != napi_ok) {
824        HILOG_ERROR_I18N("GetHourCycle: Create base name string failed");
825        return nullptr;
826    }
827    return result;
828}
829
830napi_value IntlAddon::GetNumberingSystem(napi_env env, napi_callback_info info)
831{
832    napi_value thisVar = nullptr;
833    void *data = nullptr;
834    napi_get_cb_info(env, info, nullptr, nullptr, &thisVar, &data);
835
836    IntlAddon *obj = nullptr;
837    napi_status status = napi_unwrap(env, thisVar, reinterpret_cast<void **>(&obj));
838    if (status != napi_ok || !obj || !obj->locale_) {
839        HILOG_ERROR_I18N("GetNumberingSystem: Get Locale object failed");
840        return nullptr;
841    }
842    std::string value = obj->locale_->GetNumberingSystem();
843
844    napi_value result = nullptr;
845    status = napi_create_string_utf8(env, value.c_str(), NAPI_AUTO_LENGTH, &result);
846    if (status != napi_ok) {
847        HILOG_ERROR_I18N("GetNumberingSystem: Create base name string failed");
848        return nullptr;
849    }
850    return result;
851}
852
853napi_value IntlAddon::GetNumeric(napi_env env, napi_callback_info info)
854{
855    napi_value thisVar = nullptr;
856    void *data = nullptr;
857    napi_get_cb_info(env, info, nullptr, nullptr, &thisVar, &data);
858
859    IntlAddon *obj = nullptr;
860    napi_status status = napi_unwrap(env, thisVar, reinterpret_cast<void **>(&obj));
861    if (status != napi_ok || !obj || !obj->locale_) {
862        HILOG_ERROR_I18N("GetNumeric: Get Locale object failed");
863        return nullptr;
864    }
865    std::string value = obj->locale_->GetNumeric();
866    bool optionBoolValue = (value == "true");
867    napi_value result = nullptr;
868    status = napi_get_boolean(env, optionBoolValue, &result);
869    if (status != napi_ok) {
870        HILOG_ERROR_I18N("Create numeric boolean value failed");
871        return nullptr;
872    }
873    return result;
874}
875
876napi_value IntlAddon::GetCaseFirst(napi_env env, napi_callback_info info)
877{
878    napi_value thisVar = nullptr;
879    void *data = nullptr;
880    napi_get_cb_info(env, info, nullptr, nullptr, &thisVar, &data);
881
882    IntlAddon *obj = nullptr;
883    napi_status status = napi_unwrap(env, thisVar, reinterpret_cast<void **>(&obj));
884    if (status != napi_ok || !obj || !obj->locale_) {
885        HILOG_ERROR_I18N("GetCaseFirst: Get Locale object failed");
886        return nullptr;
887    }
888    std::string value = obj->locale_->GetCaseFirst();
889    napi_value result = nullptr;
890    status = napi_create_string_utf8(env, value.c_str(), NAPI_AUTO_LENGTH, &result);
891    if (status != napi_ok) {
892        HILOG_ERROR_I18N("Create caseFirst string failed");
893        return nullptr;
894    }
895    return result;
896}
897
898napi_value IntlAddon::ToString(napi_env env, napi_callback_info info)
899{
900    napi_value thisVar = nullptr;
901    void *data = nullptr;
902    napi_get_cb_info(env, info, nullptr, nullptr, &thisVar, &data);
903
904    IntlAddon *obj = nullptr;
905    napi_status status = napi_unwrap(env, thisVar, reinterpret_cast<void **>(&obj));
906    if (status != napi_ok || !obj || !obj->locale_) {
907        HILOG_ERROR_I18N("ToString: Get Locale object failed");
908        return nullptr;
909    }
910    std::string value = obj->locale_->ToString();
911
912    napi_value result = nullptr;
913    status = napi_create_string_utf8(env, value.c_str(), NAPI_AUTO_LENGTH, &result);
914    if (status != napi_ok) {
915        HILOG_ERROR_I18N("ToString: Create language string failed");
916        return nullptr;
917    }
918    return result;
919}
920
921napi_value IntlAddon::Maximize(napi_env env, napi_callback_info info)
922{
923    napi_value thisVar = nullptr;
924    void *data = nullptr;
925    napi_get_cb_info(env, info, nullptr, nullptr, &thisVar, &data);
926
927    IntlAddon *obj = nullptr;
928    napi_status status = napi_unwrap(env, thisVar, reinterpret_cast<void **>(&obj));
929    if (status != napi_ok || !obj || !obj->locale_) {
930        HILOG_ERROR_I18N("Maximize: Get Locale object failed");
931        return nullptr;
932    }
933    std::string localeTag = obj->locale_->Maximize();
934
935    napi_value constructor = nullptr;
936    status = napi_get_reference_value(env, *g_constructor, &constructor);
937    if (status != napi_ok) {
938        HILOG_ERROR_I18N("Maximize: Get locale constructor reference failed");
939        return nullptr;
940    }
941    napi_value result = nullptr;
942    napi_value arg = nullptr;
943    status = napi_create_string_utf8(env, localeTag.c_str(), NAPI_AUTO_LENGTH, &arg);
944    if (status != napi_ok) {
945        HILOG_ERROR_I18N("Maximize: Create localeTag string failed");
946        return nullptr;
947    }
948    status = napi_new_instance(env, constructor, 1, &arg, &result);
949    if (status != napi_ok) {
950        HILOG_ERROR_I18N("Maximize: Create new locale instance failed");
951        return nullptr;
952    }
953    return result;
954}
955
956napi_value IntlAddon::Minimize(napi_env env, napi_callback_info info)
957{
958    napi_value thisVar = nullptr;
959    void *data = nullptr;
960    napi_get_cb_info(env, info, nullptr, nullptr, &thisVar, &data);
961
962    IntlAddon *obj = nullptr;
963    napi_status status = napi_unwrap(env, thisVar, reinterpret_cast<void **>(&obj));
964    if (status != napi_ok || !obj || !obj->locale_) {
965        HILOG_ERROR_I18N("Minimize: Get Locale object failed");
966        return nullptr;
967    }
968    std::string localeTag = obj->locale_->Minimize();
969
970    napi_value constructor = nullptr;
971    status = napi_get_reference_value(env, *g_constructor, &constructor);
972    if (status != napi_ok) {
973        HILOG_ERROR_I18N("Minimize: Get locale constructor reference failed");
974        return nullptr;
975    }
976    napi_value result = nullptr;
977    napi_value arg = nullptr;
978    status = napi_create_string_utf8(env, localeTag.c_str(), NAPI_AUTO_LENGTH, &arg);
979    if (status != napi_ok) {
980        HILOG_ERROR_I18N("Minimize: Create localeTag string failed");
981        return nullptr;
982    }
983    status = napi_new_instance(env, constructor, 1, &arg, &result);
984    if (status != napi_ok) {
985        HILOG_ERROR_I18N("Minimize: Create new locale instance failed");
986        return nullptr;
987    }
988    return result;
989}
990
991void SetOptionProperties(napi_env env, napi_value &result, std::map<std::string, std::string> &options,
992    const std::string &option)
993{
994    if (options.count(option) > 0) {
995        std::string optionValue = options[option];
996        napi_value optionJsValue = nullptr;
997        napi_create_string_utf8(env, optionValue.c_str(), NAPI_AUTO_LENGTH, &optionJsValue);
998        napi_set_named_property(env, result, option.c_str(), optionJsValue);
999    } else {
1000        napi_value undefined = nullptr;
1001        napi_get_undefined(env, &undefined);
1002        napi_set_named_property(env, result, option.c_str(), undefined);
1003    }
1004}
1005
1006void SetIntegerOptionProperties(napi_env env, napi_value &result, std::map<std::string, std::string> &options,
1007    const std::string &option)
1008{
1009    if (options.count(option) > 0) {
1010        std::string optionValue = options[option];
1011        napi_value optionJsValue = nullptr;
1012        int32_t status = 0;
1013        int64_t integerValue = ConvertString2Int(optionValue, status);
1014        if (status != -1) {
1015            napi_create_int64(env, integerValue, &optionJsValue);
1016            napi_set_named_property(env, result, option.c_str(), optionJsValue);
1017            return;
1018        }
1019    }
1020    napi_value undefined = nullptr;
1021    napi_get_undefined(env, &undefined);
1022    napi_set_named_property(env, result, option.c_str(), undefined);
1023}
1024
1025void SetBooleanOptionProperties(napi_env env, napi_value &result, std::map<std::string, std::string> &options,
1026    const std::string &option)
1027{
1028    if (options.count(option) > 0) {
1029        std::string optionValue = options[option];
1030        bool optionBoolValue = (optionValue == "true");
1031        napi_value optionJsValue = nullptr;
1032        napi_get_boolean(env, optionBoolValue, &optionJsValue);
1033        napi_set_named_property(env, result, option.c_str(), optionJsValue);
1034    } else {
1035        napi_value undefined = nullptr;
1036        napi_get_undefined(env, &undefined);
1037        napi_set_named_property(env, result, option.c_str(), undefined);
1038    }
1039}
1040
1041napi_value IntlAddon::GetRelativeTimeResolvedOptions(napi_env env, napi_callback_info info)
1042{
1043    napi_value thisVar = nullptr;
1044    void *data = nullptr;
1045    napi_get_cb_info(env, info, nullptr, nullptr, &thisVar, &data);
1046
1047    IntlAddon *obj = nullptr;
1048    napi_status status = napi_unwrap(env, thisVar, reinterpret_cast<void **>(&obj));
1049    if (status != napi_ok || !obj || !obj->relativetimefmt_) {
1050        HILOG_ERROR_I18N("GetRelativeTimeResolvedOptions: Get RelativeTimeFormat object failed");
1051        return nullptr;
1052    }
1053    napi_value result = nullptr;
1054    napi_create_object(env, &result);
1055    std::map<std::string, std::string> options = {};
1056    obj->relativetimefmt_->GetResolvedOptions(options);
1057    SetOptionProperties(env, result, options, "locale");
1058    SetOptionProperties(env, result, options, "style");
1059    SetOptionProperties(env, result, options, "numeric");
1060    SetOptionProperties(env, result, options, "numberingSystem");
1061    return result;
1062}
1063
1064napi_value IntlAddon::GetDateTimeResolvedOptions(napi_env env, napi_callback_info info)
1065{
1066    napi_value thisVar = nullptr;
1067    void *data = nullptr;
1068    napi_get_cb_info(env, info, nullptr, nullptr, &thisVar, &data);
1069
1070    IntlAddon *obj = nullptr;
1071    napi_status status = napi_unwrap(env, thisVar, reinterpret_cast<void **>(&obj));
1072    if (status != napi_ok || !obj || !obj->datefmt_) {
1073        HILOG_ERROR_I18N("GetDateTimeResolvedOptions: Get DateTimeFormat object failed");
1074        return nullptr;
1075    }
1076    napi_value result = nullptr;
1077    napi_create_object(env, &result);
1078    std::map<std::string, std::string> options = {};
1079    obj->datefmt_->GetResolvedOptions(options);
1080    SetOptionProperties(env, result, options, "locale");
1081    SetOptionProperties(env, result, options, "calendar");
1082    SetOptionProperties(env, result, options, "dateStyle");
1083    SetOptionProperties(env, result, options, "timeStyle");
1084    SetOptionProperties(env, result, options, "hourCycle");
1085    SetOptionProperties(env, result, options, "timeZone");
1086    SetOptionProperties(env, result, options, "timeZoneName");
1087    SetOptionProperties(env, result, options, "numberingSystem");
1088    SetBooleanOptionProperties(env, result, options, "hour12");
1089    SetOptionProperties(env, result, options, "weekday");
1090    SetOptionProperties(env, result, options, "era");
1091    SetOptionProperties(env, result, options, "year");
1092    SetOptionProperties(env, result, options, "month");
1093    SetOptionProperties(env, result, options, "day");
1094    SetOptionProperties(env, result, options, "hour");
1095    SetOptionProperties(env, result, options, "minute");
1096    SetOptionProperties(env, result, options, "second");
1097    SetOptionProperties(env, result, options, "dayPeriod");
1098    SetOptionProperties(env, result, options, "localeMatcher");
1099    SetOptionProperties(env, result, options, "formatMatcher");
1100    return result;
1101}
1102
1103napi_value IntlAddon::GetNumberResolvedOptions(napi_env env, napi_callback_info info)
1104{
1105    napi_value thisVar = nullptr;
1106    void *data = nullptr;
1107    napi_get_cb_info(env, info, nullptr, nullptr, &thisVar, &data);
1108
1109    IntlAddon *obj = nullptr;
1110    napi_status status = napi_unwrap(env, thisVar, reinterpret_cast<void **>(&obj));
1111    if (status != napi_ok || !obj || !obj->numberfmt_) {
1112        HILOG_ERROR_I18N("GetNumberResolvedOptions: Get NumberFormat object failed");
1113        return nullptr;
1114    }
1115    napi_value result = nullptr;
1116    napi_create_object(env, &result);
1117    std::map<std::string, std::string> options = {};
1118    obj->numberfmt_->GetResolvedOptions(options);
1119    SetOptionProperties(env, result, options, "locale");
1120    SetOptionProperties(env, result, options, "currency");
1121    SetOptionProperties(env, result, options, "currencySign");
1122    SetOptionProperties(env, result, options, "currencyDisplay");
1123    SetOptionProperties(env, result, options, "unit");
1124    SetOptionProperties(env, result, options, "unitDisplay");
1125    SetOptionProperties(env, result, options, "signDisplay");
1126    SetOptionProperties(env, result, options, "compactDisplay");
1127    SetOptionProperties(env, result, options, "notation");
1128    SetOptionProperties(env, result, options, "style");
1129    SetOptionProperties(env, result, options, "numberingSystem");
1130    SetOptionProperties(env, result, options, "unitUsage");
1131    SetBooleanOptionProperties(env, result, options, "useGrouping");
1132    SetIntegerOptionProperties(env, result, options, "minimumIntegerDigits");
1133    SetIntegerOptionProperties(env, result, options, "minimumFractionDigits");
1134    SetIntegerOptionProperties(env, result, options, "maximumFractionDigits");
1135    SetIntegerOptionProperties(env, result, options, "minimumSignificantDigits");
1136    SetIntegerOptionProperties(env, result, options, "maximumSignificantDigits");
1137    SetOptionProperties(env, result, options, "localeMatcher");
1138    return result;
1139}
1140
1141napi_value IntlAddon::FormatNumber(napi_env env, napi_callback_info info)
1142{
1143    size_t argc = 1;
1144    napi_value argv[1] = { 0 };
1145    napi_value thisVar = nullptr;
1146    void *data = nullptr;
1147    napi_get_cb_info(env, info, &argc, argv, &thisVar, &data);
1148    double number = 0;
1149    napi_get_value_double(env, argv[0], &number);
1150    IntlAddon *obj = nullptr;
1151    napi_status status = napi_unwrap(env, thisVar, reinterpret_cast<void **>(&obj));
1152    if (status != napi_ok || !obj || !obj->numberfmt_) {
1153        HILOG_ERROR_I18N("FormatNumber: Get NumberFormat object failed");
1154        return nullptr;
1155    }
1156    std::string value = obj->numberfmt_->Format(number);
1157    napi_value result = nullptr;
1158    status = napi_create_string_utf8(env, value.c_str(), NAPI_AUTO_LENGTH, &result);
1159    if (status != napi_ok) {
1160        HILOG_ERROR_I18N("FormatNumber: Create format string failed");
1161        return nullptr;
1162    }
1163    return result;
1164}
1165
1166void GetCollatorLocaleMatcher(napi_env env, napi_value options, std::map<std::string, std::string> &map)
1167{
1168    GetOptionValue(env, options, "localeMatcher", map);
1169    auto it = map.find("localeMatcher");
1170    if (it != map.end()) {
1171        std::string localeMatcher = it->second;
1172        if (localeMatcher != "lookup" && localeMatcher != "best fit") {
1173            HILOG_ERROR_I18N("invalid localeMatcher");
1174            return;
1175        }
1176    } else {
1177        map.insert(std::make_pair("localeMatcher", "best fit"));
1178    }
1179}
1180
1181void GetCollatorUsage(napi_env env, napi_value options, std::map<std::string, std::string> &map)
1182{
1183    GetOptionValue(env, options, "usage", map);
1184    auto it = map.find("usage");
1185    if (it != map.end()) {
1186        std::string usage = it->second;
1187        if (usage != "sort" && usage != "search") {
1188            HILOG_ERROR_I18N("invalid usage");
1189            return;
1190        }
1191    } else {
1192        map.insert(std::make_pair("usage", "sort"));
1193    }
1194}
1195
1196void GetCollatorSensitivity(napi_env env, napi_value options, std::map<std::string, std::string> &map)
1197{
1198    GetOptionValue(env, options, "sensitivity", map);
1199    auto it = map.find("sensitivity");
1200    if (it != map.end()) {
1201        std::string sensitivity = it->second;
1202        if (sensitivity != "base" && sensitivity != "accent" && sensitivity != "case" && sensitivity != "variant") {
1203            HILOG_ERROR_I18N("invalid sensitivity");
1204            return;
1205        }
1206    } else {
1207        map.insert(std::make_pair("sensitivity", "variant"));
1208    }
1209}
1210
1211void GetCollatorIgnorePunctuation(napi_env env, napi_value options, std::map<std::string, std::string> &map)
1212{
1213    GetBoolOptionValue(env, options, "ignorePunctuation", map);
1214    auto it = map.find("ignorePunctuation");
1215    if (it != map.end()) {
1216        std::string ignorePunctuation = it->second;
1217        if (ignorePunctuation != "true" && ignorePunctuation != "false") {
1218            HILOG_ERROR_I18N("invalid ignorePunctuation");
1219            return;
1220        }
1221    } else {
1222        map.insert(std::make_pair("ignorePunctuation", "false"));
1223    }
1224}
1225
1226void GetCollatorNumeric(napi_env env, napi_value options, std::map<std::string, std::string> &map)
1227{
1228    GetBoolOptionValue(env, options, "numeric", map);
1229    auto it = map.find("numeric");
1230    if (it != map.end()) {
1231        std::string numeric = it->second;
1232        if (numeric != "true" && numeric != "false") {
1233            HILOG_ERROR_I18N("invalid numeric");
1234            return;
1235        }
1236    }
1237}
1238
1239void GetCollatorCaseFirst(napi_env env, napi_value options, std::map<std::string, std::string> &map)
1240{
1241    GetOptionValue(env, options, "caseFirst", map);
1242    auto it = map.find("caseFirst");
1243    if (it != map.end()) {
1244        std::string caseFirst = it->second;
1245        if (caseFirst != "upper" && caseFirst != "lower" && caseFirst != "false") {
1246            HILOG_ERROR_I18N("invalid caseFirst");
1247            return;
1248        }
1249    }
1250}
1251
1252void GetCollatorCollation(napi_env env, napi_value options, std::map<std::string, std::string> &map)
1253{
1254    GetOptionValue(env, options, "collation", map);
1255    auto it = map.find("collation");
1256    if (it != map.end()) {
1257        std::string collation = it->second;
1258        std::set<std::string> validCollation;
1259        validCollation.insert("big5han");
1260        validCollation.insert("compat");
1261        validCollation.insert("dict");
1262        validCollation.insert("direct");
1263        validCollation.insert("ducet");
1264        validCollation.insert("eor");
1265        validCollation.insert("gb2312");
1266        validCollation.insert("phonebk");
1267        validCollation.insert("phonetic");
1268        validCollation.insert("pinyin");
1269        validCollation.insert("reformed");
1270        validCollation.insert("searchjl");
1271        validCollation.insert("stroke");
1272        validCollation.insert("trad");
1273        validCollation.insert("unihan");
1274        validCollation.insert("zhuyin");
1275        if (validCollation.find(collation) == validCollation.end()) {
1276            map["collation"] = "default";
1277        }
1278    }
1279}
1280
1281void GetCollatorOptionValue(napi_env env, napi_value options, std::map<std::string, std::string> &map)
1282{
1283    GetCollatorLocaleMatcher(env, options, map);
1284    GetCollatorUsage(env, options, map);
1285    GetCollatorSensitivity(env, options, map);
1286    GetCollatorIgnorePunctuation(env, options, map);
1287    GetCollatorNumeric(env, options, map);
1288    GetCollatorCaseFirst(env, options, map);
1289    GetCollatorCollation(env, options, map);
1290}
1291
1292napi_value IntlAddon::InitCollator(napi_env env, napi_value exports)
1293{
1294    napi_status status = napi_ok;
1295    napi_property_descriptor properties[] = {
1296        DECLARE_NAPI_FUNCTION("compare", CompareString),
1297        DECLARE_NAPI_FUNCTION("resolvedOptions", GetCollatorResolvedOptions)
1298    };
1299
1300    napi_value constructor;
1301    status = napi_define_class(env, "Collator", NAPI_AUTO_LENGTH, CollatorConstructor, nullptr,
1302        sizeof(properties) / sizeof(napi_property_descriptor), properties, &constructor);
1303    if (status != napi_ok) {
1304        HILOG_ERROR_I18N("Define class failed when InitCollator");
1305        return nullptr;
1306    }
1307
1308    status = napi_set_named_property(env, exports, "Collator", constructor);
1309    if (status != napi_ok) {
1310        HILOG_ERROR_I18N("Set property failed when InitCollator");
1311        return nullptr;
1312    }
1313    return exports;
1314}
1315
1316napi_value IntlAddon::CollatorConstructor(napi_env env, napi_callback_info info)
1317{
1318    size_t argc = 2;
1319    napi_value argv[2] = { nullptr };
1320    napi_value thisVar = nullptr;
1321    void *data = nullptr;
1322    napi_status status = napi_get_cb_info(env, info, &argc, argv, &thisVar, &data);
1323    if (status != napi_ok) {
1324        return nullptr;
1325    }
1326    std::vector<std::string> localeTags;
1327    if (argc > 0) {
1328        napi_valuetype valueType = napi_valuetype::napi_undefined;
1329        napi_typeof(env, argv[0], &valueType);
1330        bool isArray = false;
1331        napi_is_array(env, argv[0], &isArray);
1332        if (valueType == napi_valuetype::napi_string) {
1333            GetLocaleTags(env, argv[0], localeTags);
1334        } else if (isArray) {
1335            uint32_t arrayLength = 0;
1336            napi_get_array_length(env, argv[0], &arrayLength);
1337            napi_value element = nullptr;
1338            for (uint32_t i = 0; i < arrayLength; i++) {
1339                napi_get_element(env, argv[0], i, &element);
1340                GetLocaleTags(env, element, localeTags);
1341            }
1342        }
1343    }
1344    std::map<std::string, std::string> map = {};
1345    if (argc > 1) {
1346        GetCollatorOptionValue(env, argv[1], map);
1347    }
1348    std::unique_ptr<IntlAddon> obj = nullptr;
1349    obj = std::make_unique<IntlAddon>();
1350    status =
1351        napi_wrap(env, thisVar, reinterpret_cast<void *>(obj.get()), IntlAddon::Destructor, nullptr, nullptr);
1352    if (status != napi_ok) {
1353        HILOG_ERROR_I18N("CollatorConstructor: Wrap IntlAddon failed");
1354        return nullptr;
1355    }
1356    if (!obj->InitCollatorContext(env, info, localeTags, map)) {
1357        HILOG_ERROR_I18N("CollatorConstructor: Init DateTimeFormat failed");
1358        return nullptr;
1359    }
1360    obj.release();
1361    return thisVar;
1362}
1363
1364bool IntlAddon::InitCollatorContext(napi_env env, napi_callback_info info, std::vector<std::string> localeTags,
1365    std::map<std::string, std::string> &map)
1366{
1367    napi_value global = nullptr;
1368    napi_status status = napi_get_global(env, &global);
1369    if (status != napi_ok) {
1370        HILOG_ERROR_I18N("InitCollatorContext: Get global failed");
1371        return false;
1372    }
1373    env_ = env;
1374    collator_ = std::make_unique<Collator>(localeTags, map);
1375
1376    return collator_ != nullptr;
1377}
1378
1379bool GetStringParameter(napi_env env, napi_value value, std::vector<char> &buf)
1380{
1381    napi_valuetype valueType = napi_valuetype::napi_undefined;
1382    napi_typeof(env, value, &valueType);
1383    if (valueType != napi_valuetype::napi_string) {
1384        HILOG_ERROR_I18N("Parameter type does not match");
1385        return false;
1386    }
1387    size_t len = 0;
1388    napi_status status = napi_get_value_string_utf8(env, value, nullptr, 0, &len);
1389    if (status != napi_ok) {
1390        HILOG_ERROR_I18N("Get first length failed");
1391        return false;
1392    }
1393    buf.resize(len + 1);
1394    status = napi_get_value_string_utf8(env, value, buf.data(), len + 1, &len);
1395    if (status != napi_ok) {
1396        HILOG_ERROR_I18N("Get first failed");
1397        return false;
1398    }
1399
1400    return true;
1401}
1402
1403napi_value IntlAddon::FormatRelativeTime(napi_env env, napi_callback_info info)
1404{
1405    size_t argc = 2;
1406    napi_value argv[2] = { 0 };
1407    napi_value thisVar = nullptr;
1408    void *data = nullptr;
1409    napi_get_cb_info(env, info, &argc, argv, &thisVar, &data);
1410    napi_status status;
1411    double number;
1412    status = napi_get_value_double(env, argv[0], &number);
1413    if (status != napi_ok) {
1414        HILOG_ERROR_I18N("FormatRelativeTime: Get number failed");
1415        return nullptr;
1416    }
1417    std::vector<char> unit;
1418    if (!GetStringParameter(env, argv[1], unit)) {
1419        return nullptr;
1420    }
1421    IntlAddon *obj = nullptr;
1422    status = napi_unwrap(env, thisVar, reinterpret_cast<void **>(&obj));
1423    if (status != napi_ok || !obj || !obj->relativetimefmt_) {
1424        HILOG_ERROR_I18N("FormatRelativeTime: Get RelativeTimeFormat object failed");
1425        return nullptr;
1426    }
1427    std::string value = obj->relativetimefmt_->Format(number, unit.data());
1428    napi_value result = nullptr;
1429    status = napi_create_string_utf8(env, value.c_str(), NAPI_AUTO_LENGTH, &result);
1430    if (status != napi_ok) {
1431        HILOG_ERROR_I18N("FormatRelativeTime: Create format string failed");
1432        return nullptr;
1433    }
1434    return result;
1435}
1436
1437void IntlAddon::FillInArrayElement(napi_env env, napi_value &result, napi_status &status,
1438    const std::vector<std::vector<std::string>> &timeVector)
1439{
1440    for (size_t i = 0; i < timeVector.size(); i++) {
1441        napi_value value = nullptr;
1442        status = napi_create_string_utf8(env, timeVector[i][1].c_str(), NAPI_AUTO_LENGTH, &value);
1443        if (status != napi_ok) {
1444            HILOG_ERROR_I18N("Failed to create string item imeVector[i][1].");
1445            return;
1446        }
1447        napi_value type = nullptr;
1448        status = napi_create_string_utf8(env, timeVector[i][0].c_str(), NAPI_AUTO_LENGTH, &type);
1449        if (status != napi_ok) {
1450            HILOG_ERROR_I18N("Failed to create string item timeVector[i][0].");
1451            return;
1452        }
1453        napi_value unit = nullptr;
1454        size_t unitIndex = 2;
1455        if (timeVector[i].size() > unitIndex) {
1456            status = napi_create_string_utf8(env, timeVector[i][unitIndex].c_str(), NAPI_AUTO_LENGTH, &unit);
1457            if (status != napi_ok) {
1458                HILOG_ERROR_I18N("Failed to create string item timeVector[i][unitIndex].");
1459                return;
1460            }
1461        } else {
1462            napi_get_undefined(env, &unit);
1463        }
1464        napi_value formatInfo;
1465        status = napi_create_object(env, &formatInfo);
1466        if (status != napi_ok) {
1467            HILOG_ERROR_I18N("Failed to create format info object.");
1468            return;
1469        }
1470        napi_set_named_property(env, formatInfo, "type", type);
1471        napi_set_named_property(env, formatInfo, "value", value);
1472        napi_set_named_property(env, formatInfo, "unit", unit);
1473        status = napi_set_element(env, result, i, formatInfo);
1474        if (status != napi_ok) {
1475            HILOG_ERROR_I18N("Failed to set array item");
1476            return;
1477        }
1478    }
1479}
1480
1481napi_value IntlAddon::FormatToParts(napi_env env, napi_callback_info info)
1482{
1483    size_t argc = 2;
1484    napi_value argv[2] = { 0 };
1485    napi_value thisVar = nullptr;
1486    void *data = nullptr;
1487    napi_get_cb_info(env, info, &argc, argv, &thisVar, &data);
1488    double number = 0;
1489    napi_get_value_double(env, argv[0], &number);
1490    std::vector<char> unit;
1491    if (!GetStringParameter(env, argv[1], unit)) {
1492        return nullptr;
1493    }
1494    IntlAddon *obj = nullptr;
1495    napi_status status = napi_unwrap(env, thisVar, reinterpret_cast<void **>(&obj));
1496    if (status != napi_ok || !obj || !obj->relativetimefmt_) {
1497        HILOG_ERROR_I18N("FormatToParts: Get RelativeTimeFormat object failed");
1498        return nullptr;
1499    }
1500    std::vector<std::vector<std::string>> timeVector;
1501    obj->relativetimefmt_->FormatToParts(number, unit.data(), timeVector);
1502    napi_value result = nullptr;
1503    status = napi_create_array_with_length(env, timeVector.size(), &result);
1504    if (status != napi_ok) {
1505        HILOG_ERROR_I18N("Failed to create array");
1506        return nullptr;
1507    }
1508    FillInArrayElement(env, result, status, timeVector);
1509    return result;
1510}
1511
1512napi_value IntlAddon::CompareString(napi_env env, napi_callback_info info)
1513{
1514    size_t argc = 2;
1515    napi_value argv[2] = { 0 };
1516    napi_value thisVar = nullptr;
1517    void *data = nullptr;
1518    napi_get_cb_info(env, info, &argc, argv, &thisVar, &data);
1519
1520    std::vector<char> first;
1521    if (!GetStringParameter(env, argv[0], first)) {
1522        return nullptr;
1523    }
1524
1525    std::vector<char> second;
1526    if (!GetStringParameter(env, argv[1], second)) {
1527        return nullptr;
1528    }
1529
1530    IntlAddon *obj = nullptr;
1531    napi_status status = napi_unwrap(env, thisVar, reinterpret_cast<void **>(&obj));
1532    if (status != napi_ok || !obj || !obj->collator_) {
1533        HILOG_ERROR_I18N("CompareString: Get Collator object failed");
1534        return nullptr;
1535    }
1536
1537    CompareResult compareResult = obj->collator_->Compare(first.data(), second.data());
1538    napi_value result = nullptr;
1539    status = napi_create_int32(env, compareResult, &result);
1540    if (status != napi_ok) {
1541        HILOG_ERROR_I18N("Create compare result failed");
1542        return nullptr;
1543    }
1544
1545    return result;
1546}
1547
1548napi_value IntlAddon::GetCollatorResolvedOptions(napi_env env, napi_callback_info info)
1549{
1550    napi_value thisVar = nullptr;
1551    void *data = nullptr;
1552    napi_get_cb_info(env, info, nullptr, nullptr, &thisVar, &data);
1553
1554    IntlAddon *obj = nullptr;
1555    napi_status status = napi_unwrap(env, thisVar, reinterpret_cast<void **>(&obj));
1556    if (status != napi_ok || !obj || !obj->collator_) {
1557        HILOG_ERROR_I18N("GetCollatorResolvedOptions: Get Collator object failed");
1558        return nullptr;
1559    }
1560    napi_value result = nullptr;
1561    napi_create_object(env, &result);
1562    std::map<std::string, std::string> options = {};
1563    obj->collator_->ResolvedOptions(options);
1564    SetOptionProperties(env, result, options, "localeMatcher");
1565    SetOptionProperties(env, result, options, "locale");
1566    SetOptionProperties(env, result, options, "usage");
1567    SetOptionProperties(env, result, options, "sensitivity");
1568    SetBooleanOptionProperties(env, result, options, "ignorePunctuation");
1569    SetBooleanOptionProperties(env, result, options, "numeric");
1570    SetOptionProperties(env, result, options, "caseFirst");
1571    SetOptionProperties(env, result, options, "collation");
1572    return result;
1573}
1574
1575void GetPluralRulesType(napi_env env, napi_value options, std::map<std::string, std::string> &map)
1576{
1577    GetOptionValue(env, options, "type", map);
1578    auto it = map.find("type");
1579    if (it != map.end()) {
1580        std::string type = it->second;
1581        if (type != "cardinal" && type != "ordinal") {
1582            HILOG_ERROR_I18N("invalid type");
1583            return;
1584        }
1585    } else {
1586        map.insert(std::make_pair("type", "cardinal"));
1587    }
1588}
1589
1590void GetPluralRulesInteger(napi_env env, napi_value options, std::map<std::string, std::string> &map)
1591{
1592    GetIntegerOptionValue(env, options, "minimumIntegerDigits", map);
1593    auto it = map.find("minimumIntegerDigits");
1594    if (it != map.end()) {
1595        std::string minimumIntegerDigits = it->second;
1596        int32_t status = 0;
1597        int n = ConvertString2Int(minimumIntegerDigits, status);
1598        if (status == -1 || n < 1 || n > 21) {  // the valid range of minimumIntegerDigits is [1, 21]
1599            HILOG_ERROR_I18N("invalid minimumIntegerDigits");
1600            return;
1601        }
1602    } else {
1603        map.insert(std::make_pair("minimumIntegerDigits", std::to_string(1)));
1604    }
1605}
1606
1607void GetPluralRulesFractions(napi_env env, napi_value options, std::map<std::string, std::string> &map)
1608{
1609    GetIntegerOptionValue(env, options, "minimumFractionDigits", map);
1610    auto it = map.find("minimumFractionDigits");
1611    if (it != map.end()) {
1612        std::string minimumFractionDigits = it->second;
1613        int32_t status = 0;
1614        int n = ConvertString2Int(minimumFractionDigits, status);
1615        if (status == -1 || n < 0 || n > 20) {  // the valid range of minimumFractionDigits is [0, 20]
1616            HILOG_ERROR_I18N("invalid minimumFractionDigits");
1617            return;
1618        }
1619    }
1620
1621    GetIntegerOptionValue(env, options, "maximumFractionDigits", map);
1622    it = map.find("maximumFractionDigits");
1623    if (it != map.end()) {
1624        std::string maximumFractionDigits = it->second;
1625        int32_t status = 0;
1626        int n = ConvertString2Int(maximumFractionDigits, status);
1627        if (status == -1 || n < 0 || n > 20) {  // the valid range of maximumFractionDigits is [0, 20]
1628            HILOG_ERROR_I18N("invalid maximumFractionDigits");
1629            return;
1630        }
1631    }
1632}
1633
1634void GetPluralRulesSignificant(napi_env env, napi_value options, std::map<std::string, std::string> &map)
1635{
1636    int minSignificant = -1;
1637    GetIntegerOptionValue(env, options, "minimumSignificantDigits", map);
1638    auto it = map.find("minimumSignificantDigits");
1639    if (it != map.end()) {
1640        std::string minSignificantStr = it->second;
1641        int32_t status = 0;
1642        int minSignificantInt = ConvertString2Int(minSignificantStr, status);
1643        // the valid range of minSignificantInt is [1, 21]
1644        if (status == -1 || minSignificantInt < 1 || minSignificantInt > 21) {
1645            HILOG_ERROR_I18N("invalid minimumSignificantDigits");
1646            return;
1647        }
1648        minSignificant = minSignificantInt;
1649    } else {
1650        minSignificant = 1;
1651    }
1652
1653    GetIntegerOptionValue(env, options, "maximumSignificantDigits", map);
1654    it = map.find("maximumSignificantDigits");
1655    if (it != map.end()) {
1656        std::string maxSignificantStr = it->second;
1657        int32_t status = 0;
1658        int maxSignificant = ConvertString2Int(maxSignificantStr, status);
1659        // the valid range of minSignificant is [minSignificant, 21]
1660        if (status == -1 || maxSignificant < minSignificant || maxSignificant > 21) {
1661            HILOG_ERROR_I18N("invalid maximumSignificantDigits");
1662            return;
1663        }
1664    }
1665}
1666
1667void GetPluralRulesOptionValues(napi_env env, napi_value options, std::map<std::string, std::string> &map)
1668{
1669    GetCollatorLocaleMatcher(env, options, map);
1670    GetPluralRulesType(env, options, map);
1671    GetPluralRulesInteger(env, options, map);
1672    GetPluralRulesFractions(env, options, map);
1673    GetPluralRulesSignificant(env, options, map);
1674}
1675
1676napi_value IntlAddon::InitPluralRules(napi_env env, napi_value exports)
1677{
1678    napi_status status = napi_ok;
1679    napi_property_descriptor properties[] = {
1680        DECLARE_NAPI_FUNCTION("select", Select)
1681    };
1682
1683    napi_value constructor = nullptr;
1684    status = napi_define_class(env, "PluralRules", NAPI_AUTO_LENGTH, PluralRulesConstructor, nullptr,
1685        sizeof(properties) / sizeof(napi_property_descriptor), properties, &constructor);
1686    if (status != napi_ok) {
1687        HILOG_ERROR_I18N("Define class failed when InitPluralRules");
1688        return nullptr;
1689    }
1690
1691    status = napi_set_named_property(env, exports, "PluralRules", constructor);
1692    if (status != napi_ok) {
1693        HILOG_ERROR_I18N("Set property failed when InitPluralRules");
1694        return nullptr;
1695    }
1696    return exports;
1697}
1698
1699napi_value IntlAddon::PluralRulesConstructor(napi_env env, napi_callback_info info)
1700{
1701    size_t argc = 2;
1702    napi_value argv[2] = { nullptr };
1703    napi_value thisVar = nullptr;
1704    void *data = nullptr;
1705    napi_status status = napi_get_cb_info(env, info, &argc, argv, &thisVar, &data);
1706    if (status != napi_ok) {
1707        return nullptr;
1708    }
1709    napi_valuetype valueType = napi_valuetype::napi_undefined;
1710    std::vector<std::string> localeTags;
1711    if (argc > 0) {
1712        napi_typeof(env, argv[0], &valueType);
1713        bool isArray = false;
1714        napi_is_array(env, argv[0], &isArray);
1715        if (valueType == napi_valuetype::napi_string) {
1716            GetLocaleTags(env, argv[0], localeTags);
1717        } else if (isArray) {
1718            uint32_t arrayLength = 0;
1719            napi_get_array_length(env, argv[0], &arrayLength);
1720            napi_value element = nullptr;
1721            for (uint32_t i = 0; i < arrayLength; i++) {
1722                napi_get_element(env, argv[0], i, &element);
1723                GetLocaleTags(env, element, localeTags);
1724            }
1725        }
1726    }
1727    std::map<std::string, std::string> map = {};
1728    if (argc > 1) {
1729        GetPluralRulesOptionValues(env, argv[1], map);
1730    }
1731    std::unique_ptr<IntlAddon> obj = nullptr;
1732    obj = std::make_unique<IntlAddon>();
1733    status =
1734        napi_wrap(env, thisVar, reinterpret_cast<void *>(obj.get()), IntlAddon::Destructor, nullptr, nullptr);
1735    if (status != napi_ok) {
1736        HILOG_ERROR_I18N("PluralRulesConstructor: Wrap IntlAddon failed");
1737        return nullptr;
1738    }
1739    if (!obj->InitPluralRulesContext(env, info, localeTags, map)) {
1740        HILOG_ERROR_I18N("PluralRulesConstructor: Init DateTimeFormat failed");
1741        return nullptr;
1742    }
1743    obj.release();
1744    return thisVar;
1745}
1746
1747bool IntlAddon::InitPluralRulesContext(napi_env env, napi_callback_info info, std::vector<std::string> localeTags,
1748    std::map<std::string, std::string> &map)
1749{
1750    napi_value global = nullptr;
1751    napi_status status = napi_get_global(env, &global);
1752    if (status != napi_ok) {
1753        HILOG_ERROR_I18N("InitPluralRulesContext: Get global failed");
1754        return false;
1755    }
1756    env_ = env;
1757    pluralrules_ = std::make_unique<PluralRules>(localeTags, map);
1758
1759    return pluralrules_ != nullptr;
1760}
1761
1762napi_value IntlAddon::Select(napi_env env, napi_callback_info info)
1763{
1764    size_t argc = 1;
1765    napi_value argv[1] = { 0 };
1766    napi_value thisVar = nullptr;
1767    void *data = nullptr;
1768    napi_get_cb_info(env, info, &argc, argv, &thisVar, &data);
1769    napi_valuetype valueType = napi_valuetype::napi_undefined;
1770    napi_typeof(env, argv[0], &valueType);
1771    if (valueType != napi_valuetype::napi_number) {
1772        HILOG_ERROR_I18N("Select: Parameter type does not match");
1773        return nullptr;
1774    }
1775
1776    double number = 0;
1777    napi_status status = napi_get_value_double(env, argv[0], &number);
1778    if (status != napi_ok) {
1779        HILOG_ERROR_I18N("Select: Get number failed");
1780        return nullptr;
1781    }
1782
1783    IntlAddon *obj = nullptr;
1784    status = napi_unwrap(env, thisVar, reinterpret_cast<void **>(&obj));
1785    if (status != napi_ok || !obj || !obj->pluralrules_) {
1786        HILOG_ERROR_I18N("Get PluralRules object failed");
1787        return nullptr;
1788    }
1789
1790    std::string res = obj->pluralrules_->Select(number);
1791    napi_value result = nullptr;
1792    status = napi_create_string_utf8(env, res.c_str(), NAPI_AUTO_LENGTH, &result);
1793    if (status != napi_ok) {
1794        HILOG_ERROR_I18N("get select result failed");
1795        return nullptr;
1796    }
1797    return result;
1798}
1799
1800napi_value Init(napi_env env, napi_value exports)
1801{
1802    napi_value val = IntlAddon::InitLocale(env, exports);
1803    val = IntlAddon::InitDateTimeFormat(env, val);
1804    val = IntlAddon::InitNumberFormat(env, val);
1805    val = IntlAddon::InitCollator(env, val);
1806    val = IntlAddon::InitRelativeTimeFormat(env, val);
1807    return IntlAddon::InitPluralRules(env, val);
1808}
1809
1810static napi_module g_intlModule = {
1811    .nm_version = 1,
1812    .nm_flags = 0,
1813    .nm_filename = nullptr,
1814    .nm_register_func = Init,
1815    .nm_modname = "intl",
1816    .nm_priv = nullptr,
1817    .reserved = { 0 }
1818};
1819
1820extern "C" __attribute__((constructor)) void AbilityRegister()
1821{
1822    napi_module_register(&g_intlModule);
1823}
1824} // namespace I18n
1825} // namespace Global
1826} // namespace OHOS
1827