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