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