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
26 namespace OHOS {
27 namespace Global {
28 namespace I18n {
29 static thread_local napi_ref *g_constructor = nullptr;
30
IntlAddon()31 IntlAddon::IntlAddon() : env_(nullptr) {}
32
~IntlAddon()33 IntlAddon::~IntlAddon()
34 {
35 }
36
Destructor(napi_env env, void *nativeObject, void *hint)37 void 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
SetProperty(napi_env env, napi_callback_info info)46 napi_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
InitLocale(napi_env env, napi_value exports)54 napi_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
InitDateTimeFormat(napi_env env, napi_value exports)99 napi_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
InitRelativeTimeFormat(napi_env env, napi_value exports)124 napi_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
InitNumberFormat(napi_env env, napi_value exports)149 napi_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
GetOptionValue(napi_env env, napi_value options, const std::string &optionName, std::map<std::string, std::string> &map)173 void 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
GetIntegerOptionValue(napi_env env, napi_value options, const std::string &optionName, std::map<std::string, std::string> &map)200 int64_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
GetBoolOptionValue(napi_env env, napi_value options, const std::string &optionName, std::map<std::string, std::string> &map)225 void 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
GetDateOptionValues(napi_env env, napi_value options, std::map<std::string, std::string> &map)248 void 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
GetRelativeTimeOptionValues(napi_env env, napi_value options, std::map<std::string, std::string> &map)271 void 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
GetLocaleTag(napi_env env, napi_value argv)278 std::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
LocaleConstructor(napi_env env, napi_callback_info info)308 napi_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
InitLocaleContext(napi_env env, napi_callback_info info, const std::string localeTag, std::map<std::string, std::string> &map)344 bool 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
GetLocaleTags(napi_env env, napi_value rawLocaleTag, std::vector<std::string> &localeTags)359 void 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
DateTimeFormatConstructor(napi_env env, napi_callback_info info)376 napi_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
InitDateTimeFormatContext(napi_env env, napi_callback_info info, std::vector<std::string> localeTags, std::map<std::string, std::string> &map)424 bool 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
RelativeTimeFormatConstructor(napi_env env, napi_callback_info info)439 napi_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
InitRelativeTimeFormatContext(napi_env env, napi_callback_info info, std::vector<std::string> localeTags, std::map<std::string, std::string> &map)487 bool 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
FormatDateTime(napi_env env, napi_callback_info info)496 napi_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
FormatDateTimeRange(napi_env env, napi_callback_info info)524 napi_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
GetNumberOptionValues(napi_env env, napi_value options, std::map<std::string, std::string> &map)556 void 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
NumberFormatConstructor(napi_env env, napi_callback_info info)582 napi_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
InitNumberFormatContext(napi_env env, napi_callback_info info, std::vector<std::string> localeTags, std::map<std::string, std::string> &map)631 bool 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
GetMilliseconds(napi_env env, napi_value *argv, int index)646 int64_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
GetLanguage(napi_env env, napi_callback_info info)669 napi_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
GetScript(napi_env env, napi_callback_info info)692 napi_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
GetRegion(napi_env env, napi_callback_info info)715 napi_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
GetBaseName(napi_env env, napi_callback_info info)738 napi_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
GetCalendar(napi_env env, napi_callback_info info)761 napi_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
GetCollation(napi_env env, napi_callback_info info)784 napi_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
GetHourCycle(napi_env env, napi_callback_info info)807 napi_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
GetNumberingSystem(napi_env env, napi_callback_info info)830 napi_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
GetNumeric(napi_env env, napi_callback_info info)853 napi_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
GetCaseFirst(napi_env env, napi_callback_info info)876 napi_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
ToString(napi_env env, napi_callback_info info)898 napi_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
Maximize(napi_env env, napi_callback_info info)921 napi_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
Minimize(napi_env env, napi_callback_info info)956 napi_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
SetOptionProperties(napi_env env, napi_value &result, std::map<std::string, std::string> &options, const std::string &option)991 void 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
SetIntegerOptionProperties(napi_env env, napi_value &result, std::map<std::string, std::string> &options, const std::string &option)1006 void 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
SetBooleanOptionProperties(napi_env env, napi_value &result, std::map<std::string, std::string> &options, const std::string &option)1025 void 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
GetRelativeTimeResolvedOptions(napi_env env, napi_callback_info info)1041 napi_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
GetDateTimeResolvedOptions(napi_env env, napi_callback_info info)1064 napi_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
GetNumberResolvedOptions(napi_env env, napi_callback_info info)1103 napi_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
FormatNumber(napi_env env, napi_callback_info info)1141 napi_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
GetCollatorLocaleMatcher(napi_env env, napi_value options, std::map<std::string, std::string> &map)1166 void 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
GetCollatorUsage(napi_env env, napi_value options, std::map<std::string, std::string> &map)1181 void 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
GetCollatorSensitivity(napi_env env, napi_value options, std::map<std::string, std::string> &map)1196 void 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
GetCollatorIgnorePunctuation(napi_env env, napi_value options, std::map<std::string, std::string> &map)1211 void 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
GetCollatorNumeric(napi_env env, napi_value options, std::map<std::string, std::string> &map)1226 void 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
GetCollatorCaseFirst(napi_env env, napi_value options, std::map<std::string, std::string> &map)1239 void 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
GetCollatorCollation(napi_env env, napi_value options, std::map<std::string, std::string> &map)1252 void 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
GetCollatorOptionValue(napi_env env, napi_value options, std::map<std::string, std::string> &map)1281 void 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
InitCollator(napi_env env, napi_value exports)1292 napi_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
CollatorConstructor(napi_env env, napi_callback_info info)1316 napi_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
InitCollatorContext(napi_env env, napi_callback_info info, std::vector<std::string> localeTags, std::map<std::string, std::string> &map)1364 bool 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
GetStringParameter(napi_env env, napi_value value, std::vector<char> &buf)1379 bool 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
FormatRelativeTime(napi_env env, napi_callback_info info)1403 napi_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
FillInArrayElement(napi_env env, napi_value &result, napi_status &status, const std::vector<std::vector<std::string>> &timeVector)1437 void 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
FormatToParts(napi_env env, napi_callback_info info)1481 napi_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
CompareString(napi_env env, napi_callback_info info)1512 napi_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
GetCollatorResolvedOptions(napi_env env, napi_callback_info info)1548 napi_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
GetPluralRulesType(napi_env env, napi_value options, std::map<std::string, std::string> &map)1575 void 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
GetPluralRulesInteger(napi_env env, napi_value options, std::map<std::string, std::string> &map)1590 void 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
GetPluralRulesFractions(napi_env env, napi_value options, std::map<std::string, std::string> &map)1607 void 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
GetPluralRulesSignificant(napi_env env, napi_value options, std::map<std::string, std::string> &map)1634 void 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
GetPluralRulesOptionValues(napi_env env, napi_value options, std::map<std::string, std::string> &map)1667 void 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
InitPluralRules(napi_env env, napi_value exports)1676 napi_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
PluralRulesConstructor(napi_env env, napi_callback_info info)1699 napi_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
InitPluralRulesContext(napi_env env, napi_callback_info info, std::vector<std::string> localeTags, std::map<std::string, std::string> &map)1747 bool 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
Select(napi_env env, napi_callback_info info)1762 napi_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
Init(napi_env env, napi_value exports)1800 napi_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
1810 static 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
AbilityRegister()1820 extern "C" __attribute__((constructor)) void AbilityRegister()
1821 {
1822 napi_module_register(&g_intlModule);
1823 }
1824 } // namespace I18n
1825 } // namespace Global
1826 } // namespace OHOS
1827