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