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