1 /*
2 * Copyright (c) 2021-2022 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include "intl_addon.h"
17
18 #include <vector>
19 #include <set>
20 #include "error_util.h"
21 #include "i18n_hilog.h"
22 #include "js_utils.h"
23 #include "node_api.h"
24
25 namespace OHOS {
26 namespace Global {
27 namespace I18n {
28 static thread_local napi_ref *g_constructor = nullptr;
29
IntlAddon()30 IntlAddon::IntlAddon() : env_(nullptr) {}
31
~IntlAddon()32 IntlAddon::~IntlAddon()
33 {
34 }
35
Destructor(napi_env env,void * nativeObject,void * hint)36 void IntlAddon::Destructor(napi_env env, void *nativeObject, void *hint)
37 {
38 if (!nativeObject) {
39 return;
40 }
41 delete reinterpret_cast<IntlAddon *>(nativeObject);
42 nativeObject = nullptr;
43 }
44
SetProperty(napi_env env,napi_callback_info info)45 napi_value IntlAddon::SetProperty(napi_env env, napi_callback_info info)
46 {
47 // do nothing but provided as an input parameter for DECLARE_NAPI_GETTER_SETTER;
48 napi_value result = nullptr;
49 NAPI_CALL(env, napi_get_undefined(env, &result));
50 return result;
51 }
52
InitLocale(napi_env env,napi_value exports)53 napi_value IntlAddon::InitLocale(napi_env env, napi_value exports)
54 {
55 napi_status status = napi_ok;
56 napi_property_descriptor properties[] = {
57 DECLARE_NAPI_GETTER_SETTER("language", GetLanguage, SetProperty),
58 DECLARE_NAPI_GETTER_SETTER("baseName", GetBaseName, SetProperty),
59 DECLARE_NAPI_GETTER_SETTER("region", GetRegion, SetProperty),
60 DECLARE_NAPI_GETTER_SETTER("script", GetScript, SetProperty),
61 DECLARE_NAPI_GETTER_SETTER("calendar", GetCalendar, SetProperty),
62 DECLARE_NAPI_GETTER_SETTER("collation", GetCollation, SetProperty),
63 DECLARE_NAPI_GETTER_SETTER("hourCycle", GetHourCycle, SetProperty),
64 DECLARE_NAPI_GETTER_SETTER("numberingSystem", GetNumberingSystem, SetProperty),
65 DECLARE_NAPI_GETTER_SETTER("numeric", GetNumeric, SetProperty),
66 DECLARE_NAPI_GETTER_SETTER("caseFirst", GetCaseFirst, SetProperty),
67 DECLARE_NAPI_FUNCTION("toString", ToString),
68 DECLARE_NAPI_FUNCTION("minimize", Minimize),
69 DECLARE_NAPI_FUNCTION("maximize", Maximize),
70 };
71
72 napi_value constructor = nullptr;
73 status = napi_define_class(env, "Locale", NAPI_AUTO_LENGTH, LocaleConstructor, nullptr,
74 sizeof(properties) / sizeof(napi_property_descriptor), properties, &constructor);
75 if (status != napi_ok) {
76 HILOG_ERROR_I18N("Define class failed when InitLocale");
77 return nullptr;
78 }
79
80 status = napi_set_named_property(env, exports, "Locale", constructor);
81 if (status != napi_ok) {
82 HILOG_ERROR_I18N("Set property failed when InitLocale");
83 return nullptr;
84 }
85 g_constructor = new (std::nothrow) napi_ref;
86 if (!g_constructor) {
87 HILOG_ERROR_I18N("Failed to create ref at init");
88 return nullptr;
89 }
90 status = napi_create_reference(env, constructor, 1, g_constructor);
91 if (status != napi_ok) {
92 HILOG_ERROR_I18N("Failed to create reference at init");
93 return nullptr;
94 }
95 return exports;
96 }
97
InitDateTimeFormat(napi_env env,napi_value exports)98 napi_value IntlAddon::InitDateTimeFormat(napi_env env, napi_value exports)
99 {
100 napi_status status = napi_ok;
101 napi_property_descriptor properties[] = {
102 DECLARE_NAPI_FUNCTION("format", FormatDateTime),
103 DECLARE_NAPI_FUNCTION("formatRange", FormatDateTimeRange),
104 DECLARE_NAPI_FUNCTION("resolvedOptions", GetDateTimeResolvedOptions)
105 };
106
107 napi_value constructor = nullptr;
108 status = napi_define_class(env, "DateTimeFormat", NAPI_AUTO_LENGTH, DateTimeFormatConstructor, nullptr,
109 sizeof(properties) / sizeof(napi_property_descriptor), properties, &constructor);
110 if (status != napi_ok) {
111 HILOG_ERROR_I18N("Define class failed when InitDateTimeFormat");
112 return nullptr;
113 }
114
115 status = napi_set_named_property(env, exports, "DateTimeFormat", constructor);
116 if (status != napi_ok) {
117 HILOG_ERROR_I18N("Set property failed when InitDateTimeFormat");
118 return nullptr;
119 }
120 return exports;
121 }
122
InitRelativeTimeFormat(napi_env env,napi_value exports)123 napi_value IntlAddon::InitRelativeTimeFormat(napi_env env, napi_value exports)
124 {
125 napi_status status = napi_ok;
126 napi_property_descriptor properties[] = {
127 DECLARE_NAPI_FUNCTION("format", FormatRelativeTime),
128 DECLARE_NAPI_FUNCTION("formatToParts", FormatToParts),
129 DECLARE_NAPI_FUNCTION("resolvedOptions", GetRelativeTimeResolvedOptions)
130 };
131
132 napi_value constructor = nullptr;
133 status = napi_define_class(env, "RelativeTimeFormat", NAPI_AUTO_LENGTH, RelativeTimeFormatConstructor, nullptr,
134 sizeof(properties) / sizeof(napi_property_descriptor), properties, &constructor);
135 if (status != napi_ok) {
136 HILOG_ERROR_I18N("Define class failed when InitRelativeTimeFormat");
137 return nullptr;
138 }
139
140 status = napi_set_named_property(env, exports, "RelativeTimeFormat", constructor);
141 if (status != napi_ok) {
142 HILOG_ERROR_I18N("Set property failed when InitRelativeTimeFormat");
143 return nullptr;
144 }
145 return exports;
146 }
147
InitNumberFormat(napi_env env,napi_value exports)148 napi_value IntlAddon::InitNumberFormat(napi_env env, napi_value exports)
149 {
150 napi_status status = napi_ok;
151 napi_property_descriptor properties[] = {
152 DECLARE_NAPI_FUNCTION("format", FormatNumber),
153 DECLARE_NAPI_FUNCTION("resolvedOptions", GetNumberResolvedOptions)
154 };
155
156 napi_value constructor = nullptr;
157 status = napi_define_class(env, "NumberFormat", NAPI_AUTO_LENGTH, NumberFormatConstructor, nullptr,
158 sizeof(properties) / sizeof(napi_property_descriptor), properties, &constructor);
159 if (status != napi_ok) {
160 HILOG_ERROR_I18N("Define class failed when InitNumberFormat");
161 return nullptr;
162 }
163
164 status = napi_set_named_property(env, exports, "NumberFormat", constructor);
165 if (status != napi_ok) {
166 HILOG_ERROR_I18N("Set property failed when InitNumberFormat");
167 return nullptr;
168 }
169 return exports;
170 }
171
GetOptionValue(napi_env env,napi_value options,const std::string & optionName,std::map<std::string,std::string> & map)172 void GetOptionValue(napi_env env, napi_value options, const std::string &optionName,
173 std::map<std::string, std::string> &map)
174 {
175 napi_value optionValue = nullptr;
176 napi_valuetype type = napi_undefined;
177 napi_status status = napi_typeof(env, options, &type);
178 if (status != napi_ok && type != napi_object) {
179 HILOG_ERROR_I18N("Get option failed, option is not an object");
180 return;
181 }
182 bool hasProperty = false;
183 napi_status propStatus = napi_has_named_property(env, options, optionName.c_str(), &hasProperty);
184 if (propStatus == napi_ok && hasProperty) {
185 status = napi_get_named_property(env, options, optionName.c_str(), &optionValue);
186 if (status == napi_ok) {
187 size_t len = 0;
188 napi_get_value_string_utf8(env, optionValue, nullptr, 0, &len);
189 std::vector<char> optionBuf(len + 1);
190 status = napi_get_value_string_utf8(env, optionValue, optionBuf.data(), len + 1, &len);
191 if (status != napi_ok) {
192 return;
193 }
194 map.insert(make_pair(optionName, optionBuf.data()));
195 }
196 }
197 }
198
GetIntegerOptionValue(napi_env env,napi_value options,const std::string & optionName,std::map<std::string,std::string> & map)199 int64_t GetIntegerOptionValue(napi_env env, napi_value options, const std::string &optionName,
200 std::map<std::string, std::string> &map)
201 {
202 napi_value optionValue = nullptr;
203 int64_t integerValue = -1;
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_I18N("GetIntegerOptionValue: Set option failed, option is not an object");
208 return integerValue;
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 status = napi_get_value_int64(env, optionValue, &integerValue);
216 if (status == napi_ok) {
217 map.insert(make_pair(optionName, std::to_string(integerValue)));
218 }
219 }
220 }
221 return integerValue;
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_I18N("GetBoolOptionValue: 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 HILOG_ERROR_I18N("GetLocaleTag: 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_I18N("GetLocaleTag -> string: 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_I18N("GetLocaleTag: 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] = { nullptr };
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, argc > 0 ? argv[0] : nullptr);
318
319 std::map<std::string, std::string> map = {};
320 if (argc > 1) {
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_I18N("LocaleConstructor: 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_I18N("InitLocaleContext: 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_I18N("GetLocaleTag -> void: 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_I18N("GetLocaleTags: 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] = { nullptr };
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 (argc > 0) {
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 (argc > 1) {
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_I18N("DateTimeFormatConstructor: Wrap IntlAddon failed");
413 return nullptr;
414 }
415 if (!obj->InitDateTimeFormatContext(env, info, localeTags, map)) {
416 HILOG_ERROR_I18N("DateTimeFormatConstructor: 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_I18N("InitDateTimeFormatContext: 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] = { nullptr };
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 (argc > 0) {
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 (argc > 1) {
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_I18N("RelativeTimeFormatConstructor: Wrap IntlAddon failed");
476 return nullptr;
477 }
478 if (!obj->InitRelativeTimeFormatContext(env, info, localeTags, map)) {
479 HILOG_ERROR_I18N("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_I18N("FormatDateTime: 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_I18N("FormatDateTime: 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] = { nullptr };
527 napi_value thisVar = nullptr;
528 void *data = nullptr;
529 napi_get_cb_info(env, info, &argc, argv, &thisVar, &data);
530 if (argc < FUNC_ARGS_COUNT) {
531 HILOG_ERROR_I18N("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_I18N("FormatDateTimeRange: 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_I18N("FormatDateTimeRange: 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 int64_t minFd = GetIntegerOptionValue(env, options, "minimumFractionDigits", map);
572 int64_t maxFd = GetIntegerOptionValue(env, options, "maximumFractionDigits", map);
573 if (minFd != -1 && maxFd != -1 && minFd > maxFd) {
574 HILOG_ERROR_I18N(
575 "GetNumberOptionValues: Invalid parameter value: minimumFractionDigits > maximumFractionDigits");
576 }
577 GetIntegerOptionValue(env, options, "minimumSignificantDigits", map);
578 GetIntegerOptionValue(env, options, "maximumSignificantDigits", map);
579 }
580
NumberFormatConstructor(napi_env env,napi_callback_info info)581 napi_value IntlAddon::NumberFormatConstructor(napi_env env, napi_callback_info info)
582 {
583 size_t argc = 2;
584 napi_value argv[2] = { nullptr };
585 napi_value thisVar = nullptr;
586 void *data = nullptr;
587 napi_status status = napi_get_cb_info(env, info, &argc, argv, &thisVar, &data);
588 if (status != napi_ok) {
589 return nullptr;
590 }
591 std::vector<std::string> localeTags;
592 if (argc > 0) {
593 napi_valuetype valueType = napi_valuetype::napi_undefined;
594 napi_typeof(env, argv[0], &valueType);
595 bool isArray = false;
596 napi_is_array(env, argv[0], &isArray);
597
598 if (valueType == napi_valuetype::napi_string) {
599 GetLocaleTags(env, argv[0], localeTags);
600 } else if (isArray) {
601 uint32_t arrayLength = 0;
602 napi_get_array_length(env, argv[0], &arrayLength);
603 napi_value element = nullptr;
604 for (uint32_t i = 0; i < arrayLength; i++) {
605 napi_get_element(env, argv[0], i, &element);
606 GetLocaleTags(env, element, localeTags);
607 }
608 }
609 }
610 std::map<std::string, std::string> map = {};
611 if (argc > 1) {
612 GetNumberOptionValues(env, argv[1], map);
613 }
614 std::unique_ptr<IntlAddon> obj = nullptr;
615 obj = std::make_unique<IntlAddon>();
616 status =
617 napi_wrap(env, thisVar, reinterpret_cast<void *>(obj.get()), IntlAddon::Destructor, nullptr, nullptr);
618 if (status != napi_ok) {
619 HILOG_ERROR_I18N("NumberFormatConstructor: Wrap IntlAddon failed");
620 return nullptr;
621 }
622 if (!obj->InitNumberFormatContext(env, info, localeTags, map)) {
623 HILOG_ERROR_I18N("Init NumberFormat failed");
624 return nullptr;
625 }
626 obj.release();
627 return thisVar;
628 }
629
InitNumberFormatContext(napi_env env,napi_callback_info info,std::vector<std::string> localeTags,std::map<std::string,std::string> & map)630 bool IntlAddon::InitNumberFormatContext(napi_env env, napi_callback_info info, std::vector<std::string> localeTags,
631 std::map<std::string, std::string> &map)
632 {
633 napi_value global = nullptr;
634 napi_status status = napi_get_global(env, &global);
635 if (status != napi_ok) {
636 HILOG_ERROR_I18N("InitNumberFormatContext: Get global failed");
637 return false;
638 }
639 env_ = env;
640 numberfmt_ = std::make_unique<NumberFormat>(localeTags, map);
641
642 return numberfmt_ != nullptr;
643 }
644
GetMilliseconds(napi_env env,napi_value * argv,int index)645 int64_t IntlAddon::GetMilliseconds(napi_env env, napi_value *argv, int index)
646 {
647 napi_value funcGetDateInfo = nullptr;
648 napi_status status = napi_get_named_property(env, argv[index], "getTime", &funcGetDateInfo);
649 if (status != napi_ok) {
650 HILOG_ERROR_I18N("Get Milliseconds property failed");
651 return -1;
652 }
653 napi_value ret_value = nullptr;
654 status = napi_call_function(env, argv[index], funcGetDateInfo, 0, nullptr, &ret_value);
655 if (status != napi_ok) {
656 HILOG_ERROR_I18N("Get Milliseconds function failed");
657 return -1;
658 }
659 int64_t milliseconds = 0;
660 status = napi_get_value_int64(env, ret_value, &milliseconds);
661 if (status != napi_ok) {
662 HILOG_ERROR_I18N("Get Milliseconds failed");
663 return -1;
664 }
665 return milliseconds;
666 }
667
GetLanguage(napi_env env,napi_callback_info info)668 napi_value IntlAddon::GetLanguage(napi_env env, napi_callback_info info)
669 {
670 napi_value thisVar = nullptr;
671 void *data = nullptr;
672 napi_get_cb_info(env, info, nullptr, nullptr, &thisVar, &data);
673
674 IntlAddon *obj = nullptr;
675 napi_status status = napi_unwrap(env, thisVar, reinterpret_cast<void **>(&obj));
676 if (status != napi_ok || !obj || !obj->locale_) {
677 HILOG_ERROR_I18N("GetLanguage: Get Locale object failed");
678 return nullptr;
679 }
680 std::string value = obj->locale_->GetLanguage();
681
682 napi_value result = nullptr;
683 status = napi_create_string_utf8(env, value.c_str(), NAPI_AUTO_LENGTH, &result);
684 if (status != napi_ok) {
685 HILOG_ERROR_I18N("GetLanguage: Create language string failed");
686 return nullptr;
687 }
688 return result;
689 }
690
GetScript(napi_env env,napi_callback_info info)691 napi_value IntlAddon::GetScript(napi_env env, napi_callback_info info)
692 {
693 napi_value thisVar = nullptr;
694 void *data = nullptr;
695 napi_get_cb_info(env, info, nullptr, nullptr, &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_I18N("GetScript: 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_I18N("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 napi_value thisVar = nullptr;
717 void *data = nullptr;
718 napi_get_cb_info(env, info, nullptr, nullptr, &thisVar, &data);
719
720 IntlAddon *obj = nullptr;
721 napi_status status = napi_unwrap(env, thisVar, reinterpret_cast<void **>(&obj));
722 if (status != napi_ok || !obj || !obj->locale_) {
723 HILOG_ERROR_I18N("GetRegion: Get Locale object failed");
724 return nullptr;
725 }
726 std::string value = obj->locale_->GetRegion();
727
728 napi_value result = nullptr;
729 status = napi_create_string_utf8(env, value.c_str(), NAPI_AUTO_LENGTH, &result);
730 if (status != napi_ok) {
731 HILOG_ERROR_I18N("Create region string failed");
732 return nullptr;
733 }
734 return result;
735 }
736
GetBaseName(napi_env env,napi_callback_info info)737 napi_value IntlAddon::GetBaseName(napi_env env, napi_callback_info info)
738 {
739 napi_value thisVar = nullptr;
740 void *data = nullptr;
741 napi_get_cb_info(env, info, nullptr, nullptr, &thisVar, &data);
742
743 IntlAddon *obj = nullptr;
744 napi_status status = napi_unwrap(env, thisVar, reinterpret_cast<void **>(&obj));
745 if (status != napi_ok || !obj || !obj->locale_) {
746 HILOG_ERROR_I18N("GetBaseName: Get Locale object failed");
747 return nullptr;
748 }
749 std::string value = obj->locale_->GetBaseName();
750
751 napi_value result = nullptr;
752 status = napi_create_string_utf8(env, value.c_str(), NAPI_AUTO_LENGTH, &result);
753 if (status != napi_ok) {
754 HILOG_ERROR_I18N("GetBaseName: Create base name string failed");
755 return nullptr;
756 }
757 return result;
758 }
759
GetCalendar(napi_env env,napi_callback_info info)760 napi_value IntlAddon::GetCalendar(napi_env env, napi_callback_info info)
761 {
762 napi_value thisVar = nullptr;
763 void *data = nullptr;
764 napi_get_cb_info(env, info, nullptr, nullptr, &thisVar, &data);
765
766 IntlAddon *obj = nullptr;
767 napi_status status = napi_unwrap(env, thisVar, reinterpret_cast<void **>(&obj));
768 if (status != napi_ok || !obj || !obj->locale_) {
769 HILOG_ERROR_I18N("GetCalendar: Get Locale object failed");
770 return nullptr;
771 }
772 std::string value = obj->locale_->GetCalendar();
773
774 napi_value result = nullptr;
775 status = napi_create_string_utf8(env, value.c_str(), NAPI_AUTO_LENGTH, &result);
776 if (status != napi_ok) {
777 HILOG_ERROR_I18N("GetCalendar: Create base name string failed");
778 return nullptr;
779 }
780 return result;
781 }
782
GetCollation(napi_env env,napi_callback_info info)783 napi_value IntlAddon::GetCollation(napi_env env, napi_callback_info info)
784 {
785 napi_value thisVar = nullptr;
786 void *data = nullptr;
787 napi_get_cb_info(env, info, nullptr, nullptr, &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_I18N("GetCollation: 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_I18N("GetCollation: 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 napi_value thisVar = nullptr;
809 void *data = nullptr;
810 napi_get_cb_info(env, info, nullptr, nullptr, &thisVar, &data);
811
812 IntlAddon *obj = nullptr;
813 napi_status status = napi_unwrap(env, thisVar, reinterpret_cast<void **>(&obj));
814 if (status != napi_ok || !obj || !obj->locale_) {
815 HILOG_ERROR_I18N("GetHourCycle: Get Locale object failed");
816 return nullptr;
817 }
818 std::string value = obj->locale_->GetHourCycle();
819
820 napi_value result = nullptr;
821 status = napi_create_string_utf8(env, value.c_str(), NAPI_AUTO_LENGTH, &result);
822 if (status != napi_ok) {
823 HILOG_ERROR_I18N("GetHourCycle: Create base name string failed");
824 return nullptr;
825 }
826 return result;
827 }
828
GetNumberingSystem(napi_env env,napi_callback_info info)829 napi_value IntlAddon::GetNumberingSystem(napi_env env, napi_callback_info info)
830 {
831 napi_value thisVar = nullptr;
832 void *data = nullptr;
833 napi_get_cb_info(env, info, nullptr, nullptr, &thisVar, &data);
834
835 IntlAddon *obj = nullptr;
836 napi_status status = napi_unwrap(env, thisVar, reinterpret_cast<void **>(&obj));
837 if (status != napi_ok || !obj || !obj->locale_) {
838 HILOG_ERROR_I18N("GetNumberingSystem: Get Locale object failed");
839 return nullptr;
840 }
841 std::string value = obj->locale_->GetNumberingSystem();
842
843 napi_value result = nullptr;
844 status = napi_create_string_utf8(env, value.c_str(), NAPI_AUTO_LENGTH, &result);
845 if (status != napi_ok) {
846 HILOG_ERROR_I18N("GetNumberingSystem: Create base name string failed");
847 return nullptr;
848 }
849 return result;
850 }
851
GetNumeric(napi_env env,napi_callback_info info)852 napi_value IntlAddon::GetNumeric(napi_env env, napi_callback_info info)
853 {
854 napi_value thisVar = nullptr;
855 void *data = nullptr;
856 napi_get_cb_info(env, info, nullptr, nullptr, &thisVar, &data);
857
858 IntlAddon *obj = nullptr;
859 napi_status status = napi_unwrap(env, thisVar, reinterpret_cast<void **>(&obj));
860 if (status != napi_ok || !obj || !obj->locale_) {
861 HILOG_ERROR_I18N("GetNumeric: Get Locale object failed");
862 return nullptr;
863 }
864 std::string value = obj->locale_->GetNumeric();
865 bool optionBoolValue = (value == "true");
866 napi_value result = nullptr;
867 status = napi_get_boolean(env, optionBoolValue, &result);
868 if (status != napi_ok) {
869 HILOG_ERROR_I18N("Create numeric boolean value failed");
870 return nullptr;
871 }
872 return result;
873 }
874
GetCaseFirst(napi_env env,napi_callback_info info)875 napi_value IntlAddon::GetCaseFirst(napi_env env, napi_callback_info info)
876 {
877 napi_value thisVar = nullptr;
878 void *data = nullptr;
879 napi_get_cb_info(env, info, nullptr, nullptr, &thisVar, &data);
880
881 IntlAddon *obj = nullptr;
882 napi_status status = napi_unwrap(env, thisVar, reinterpret_cast<void **>(&obj));
883 if (status != napi_ok || !obj || !obj->locale_) {
884 HILOG_ERROR_I18N("GetCaseFirst: Get Locale object failed");
885 return nullptr;
886 }
887 std::string value = obj->locale_->GetCaseFirst();
888 napi_value result = nullptr;
889 status = napi_create_string_utf8(env, value.c_str(), NAPI_AUTO_LENGTH, &result);
890 if (status != napi_ok) {
891 HILOG_ERROR_I18N("Create caseFirst string failed");
892 return nullptr;
893 }
894 return result;
895 }
896
ToString(napi_env env,napi_callback_info info)897 napi_value IntlAddon::ToString(napi_env env, napi_callback_info info)
898 {
899 napi_value thisVar = nullptr;
900 void *data = nullptr;
901 napi_get_cb_info(env, info, nullptr, nullptr, &thisVar, &data);
902
903 IntlAddon *obj = nullptr;
904 napi_status status = napi_unwrap(env, thisVar, reinterpret_cast<void **>(&obj));
905 if (status != napi_ok || !obj || !obj->locale_) {
906 HILOG_ERROR_I18N("ToString: Get Locale object failed");
907 return nullptr;
908 }
909 std::string value = obj->locale_->ToString();
910
911 napi_value result = nullptr;
912 status = napi_create_string_utf8(env, value.c_str(), NAPI_AUTO_LENGTH, &result);
913 if (status != napi_ok) {
914 HILOG_ERROR_I18N("ToString: Create language string failed");
915 return nullptr;
916 }
917 return result;
918 }
919
Maximize(napi_env env,napi_callback_info info)920 napi_value IntlAddon::Maximize(napi_env env, napi_callback_info info)
921 {
922 napi_value thisVar = nullptr;
923 void *data = nullptr;
924 napi_get_cb_info(env, info, nullptr, nullptr, &thisVar, &data);
925
926 IntlAddon *obj = nullptr;
927 napi_status status = napi_unwrap(env, thisVar, reinterpret_cast<void **>(&obj));
928 if (status != napi_ok || !obj || !obj->locale_) {
929 HILOG_ERROR_I18N("Maximize: Get Locale object failed");
930 return nullptr;
931 }
932 std::string localeTag = obj->locale_->Maximize();
933
934 napi_value constructor = nullptr;
935 status = napi_get_reference_value(env, *g_constructor, &constructor);
936 if (status != napi_ok) {
937 HILOG_ERROR_I18N("Maximize: Get locale constructor reference failed");
938 return nullptr;
939 }
940 napi_value result = nullptr;
941 napi_value arg = nullptr;
942 status = napi_create_string_utf8(env, localeTag.c_str(), NAPI_AUTO_LENGTH, &arg);
943 if (status != napi_ok) {
944 HILOG_ERROR_I18N("Maximize: Create localeTag string failed");
945 return nullptr;
946 }
947 status = napi_new_instance(env, constructor, 1, &arg, &result);
948 if (status != napi_ok) {
949 HILOG_ERROR_I18N("Maximize: Create new locale instance failed");
950 return nullptr;
951 }
952 return result;
953 }
954
Minimize(napi_env env,napi_callback_info info)955 napi_value IntlAddon::Minimize(napi_env env, napi_callback_info info)
956 {
957 napi_value thisVar = nullptr;
958 void *data = nullptr;
959 napi_get_cb_info(env, info, nullptr, nullptr, &thisVar, &data);
960
961 IntlAddon *obj = nullptr;
962 napi_status status = napi_unwrap(env, thisVar, reinterpret_cast<void **>(&obj));
963 if (status != napi_ok || !obj || !obj->locale_) {
964 HILOG_ERROR_I18N("Minimize: Get Locale object failed");
965 return nullptr;
966 }
967 std::string localeTag = obj->locale_->Minimize();
968
969 napi_value constructor = nullptr;
970 status = napi_get_reference_value(env, *g_constructor, &constructor);
971 if (status != napi_ok) {
972 HILOG_ERROR_I18N("Minimize: Get locale constructor reference failed");
973 return nullptr;
974 }
975 napi_value result = nullptr;
976 napi_value arg = nullptr;
977 status = napi_create_string_utf8(env, localeTag.c_str(), NAPI_AUTO_LENGTH, &arg);
978 if (status != napi_ok) {
979 HILOG_ERROR_I18N("Minimize: Create localeTag string failed");
980 return nullptr;
981 }
982 status = napi_new_instance(env, constructor, 1, &arg, &result);
983 if (status != napi_ok) {
984 HILOG_ERROR_I18N("Minimize: Create new locale instance failed");
985 return nullptr;
986 }
987 return result;
988 }
989
SetOptionProperties(napi_env env,napi_value & result,std::map<std::string,std::string> & options,const std::string & option)990 void SetOptionProperties(napi_env env, napi_value &result, std::map<std::string, std::string> &options,
991 const std::string &option)
992 {
993 if (options.count(option) > 0) {
994 std::string optionValue = options[option];
995 napi_value optionJsValue = nullptr;
996 napi_create_string_utf8(env, optionValue.c_str(), NAPI_AUTO_LENGTH, &optionJsValue);
997 napi_set_named_property(env, result, option.c_str(), optionJsValue);
998 } else {
999 napi_value undefined = nullptr;
1000 napi_get_undefined(env, &undefined);
1001 napi_set_named_property(env, result, option.c_str(), undefined);
1002 }
1003 }
1004
SetIntegerOptionProperties(napi_env env,napi_value & result,std::map<std::string,std::string> & options,const std::string & option)1005 void SetIntegerOptionProperties(napi_env env, napi_value &result, std::map<std::string, std::string> &options,
1006 const std::string &option)
1007 {
1008 if (options.count(option) > 0) {
1009 std::string optionValue = options[option];
1010 napi_value optionJsValue = nullptr;
1011 int64_t integerValue = std::stoi(optionValue);
1012 napi_create_int64(env, integerValue, &optionJsValue);
1013 napi_set_named_property(env, result, option.c_str(), optionJsValue);
1014 } else {
1015 napi_value undefined = nullptr;
1016 napi_get_undefined(env, &undefined);
1017 napi_set_named_property(env, result, option.c_str(), undefined);
1018 }
1019 }
1020
SetBooleanOptionProperties(napi_env env,napi_value & result,std::map<std::string,std::string> & options,const std::string & option)1021 void SetBooleanOptionProperties(napi_env env, napi_value &result, std::map<std::string, std::string> &options,
1022 const std::string &option)
1023 {
1024 if (options.count(option) > 0) {
1025 std::string optionValue = options[option];
1026 bool optionBoolValue = (optionValue == "true");
1027 napi_value optionJsValue = nullptr;
1028 napi_get_boolean(env, optionBoolValue, &optionJsValue);
1029 napi_set_named_property(env, result, option.c_str(), optionJsValue);
1030 } else {
1031 napi_value undefined = nullptr;
1032 napi_get_undefined(env, &undefined);
1033 napi_set_named_property(env, result, option.c_str(), undefined);
1034 }
1035 }
1036
GetRelativeTimeResolvedOptions(napi_env env,napi_callback_info info)1037 napi_value IntlAddon::GetRelativeTimeResolvedOptions(napi_env env, napi_callback_info info)
1038 {
1039 napi_value thisVar = nullptr;
1040 void *data = nullptr;
1041 napi_get_cb_info(env, info, nullptr, nullptr, &thisVar, &data);
1042
1043 IntlAddon *obj = nullptr;
1044 napi_status status = napi_unwrap(env, thisVar, reinterpret_cast<void **>(&obj));
1045 if (status != napi_ok || !obj || !obj->relativetimefmt_) {
1046 HILOG_ERROR_I18N("GetRelativeTimeResolvedOptions: Get RelativeTimeFormat object failed");
1047 return nullptr;
1048 }
1049 napi_value result = nullptr;
1050 napi_create_object(env, &result);
1051 std::map<std::string, std::string> options = {};
1052 obj->relativetimefmt_->GetResolvedOptions(options);
1053 SetOptionProperties(env, result, options, "locale");
1054 SetOptionProperties(env, result, options, "style");
1055 SetOptionProperties(env, result, options, "numeric");
1056 SetOptionProperties(env, result, options, "numberingSystem");
1057 return result;
1058 }
1059
GetDateTimeResolvedOptions(napi_env env,napi_callback_info info)1060 napi_value IntlAddon::GetDateTimeResolvedOptions(napi_env env, napi_callback_info info)
1061 {
1062 napi_value thisVar = nullptr;
1063 void *data = nullptr;
1064 napi_get_cb_info(env, info, nullptr, nullptr, &thisVar, &data);
1065
1066 IntlAddon *obj = nullptr;
1067 napi_status status = napi_unwrap(env, thisVar, reinterpret_cast<void **>(&obj));
1068 if (status != napi_ok || !obj || !obj->datefmt_) {
1069 HILOG_ERROR_I18N("GetDateTimeResolvedOptions: Get DateTimeFormat object failed");
1070 return nullptr;
1071 }
1072 napi_value result = nullptr;
1073 napi_create_object(env, &result);
1074 std::map<std::string, std::string> options = {};
1075 obj->datefmt_->GetResolvedOptions(options);
1076 SetOptionProperties(env, result, options, "locale");
1077 SetOptionProperties(env, result, options, "calendar");
1078 SetOptionProperties(env, result, options, "dateStyle");
1079 SetOptionProperties(env, result, options, "timeStyle");
1080 SetOptionProperties(env, result, options, "hourCycle");
1081 SetOptionProperties(env, result, options, "timeZone");
1082 SetOptionProperties(env, result, options, "timeZoneName");
1083 SetOptionProperties(env, result, options, "numberingSystem");
1084 SetBooleanOptionProperties(env, result, options, "hour12");
1085 SetOptionProperties(env, result, options, "weekday");
1086 SetOptionProperties(env, result, options, "era");
1087 SetOptionProperties(env, result, options, "year");
1088 SetOptionProperties(env, result, options, "month");
1089 SetOptionProperties(env, result, options, "day");
1090 SetOptionProperties(env, result, options, "hour");
1091 SetOptionProperties(env, result, options, "minute");
1092 SetOptionProperties(env, result, options, "second");
1093 SetOptionProperties(env, result, options, "dayPeriod");
1094 SetOptionProperties(env, result, options, "localeMatcher");
1095 SetOptionProperties(env, result, options, "formatMatcher");
1096 return result;
1097 }
1098
GetNumberResolvedOptions(napi_env env,napi_callback_info info)1099 napi_value IntlAddon::GetNumberResolvedOptions(napi_env env, napi_callback_info info)
1100 {
1101 napi_value thisVar = nullptr;
1102 void *data = nullptr;
1103 napi_get_cb_info(env, info, nullptr, nullptr, &thisVar, &data);
1104
1105 IntlAddon *obj = nullptr;
1106 napi_status status = napi_unwrap(env, thisVar, reinterpret_cast<void **>(&obj));
1107 if (status != napi_ok || !obj || !obj->numberfmt_) {
1108 HILOG_ERROR_I18N("GetNumberResolvedOptions: Get NumberFormat object failed");
1109 return nullptr;
1110 }
1111 napi_value result = nullptr;
1112 napi_create_object(env, &result);
1113 std::map<std::string, std::string> options = {};
1114 obj->numberfmt_->GetResolvedOptions(options);
1115 SetOptionProperties(env, result, options, "locale");
1116 SetOptionProperties(env, result, options, "currency");
1117 SetOptionProperties(env, result, options, "currencySign");
1118 SetOptionProperties(env, result, options, "currencyDisplay");
1119 SetOptionProperties(env, result, options, "unit");
1120 SetOptionProperties(env, result, options, "unitDisplay");
1121 SetOptionProperties(env, result, options, "signDisplay");
1122 SetOptionProperties(env, result, options, "compactDisplay");
1123 SetOptionProperties(env, result, options, "notation");
1124 SetOptionProperties(env, result, options, "style");
1125 SetOptionProperties(env, result, options, "numberingSystem");
1126 SetOptionProperties(env, result, options, "unitUsage");
1127 SetBooleanOptionProperties(env, result, options, "useGrouping");
1128 SetIntegerOptionProperties(env, result, options, "minimumIntegerDigits");
1129 SetIntegerOptionProperties(env, result, options, "minimumFractionDigits");
1130 SetIntegerOptionProperties(env, result, options, "maximumFractionDigits");
1131 SetIntegerOptionProperties(env, result, options, "minimumSignificantDigits");
1132 SetIntegerOptionProperties(env, result, options, "maximumSignificantDigits");
1133 SetOptionProperties(env, result, options, "localeMatcher");
1134 return result;
1135 }
1136
FormatNumber(napi_env env,napi_callback_info info)1137 napi_value IntlAddon::FormatNumber(napi_env env, napi_callback_info info)
1138 {
1139 size_t argc = 1;
1140 napi_value argv[1] = { 0 };
1141 napi_value thisVar = nullptr;
1142 void *data = nullptr;
1143 napi_get_cb_info(env, info, &argc, argv, &thisVar, &data);
1144 double number = 0;
1145 napi_get_value_double(env, argv[0], &number);
1146 IntlAddon *obj = nullptr;
1147 napi_status status = napi_unwrap(env, thisVar, reinterpret_cast<void **>(&obj));
1148 if (status != napi_ok || !obj || !obj->numberfmt_) {
1149 HILOG_ERROR_I18N("FormatNumber: Get NumberFormat object failed");
1150 return nullptr;
1151 }
1152 std::string value = obj->numberfmt_->Format(number);
1153 napi_value result = nullptr;
1154 status = napi_create_string_utf8(env, value.c_str(), NAPI_AUTO_LENGTH, &result);
1155 if (status != napi_ok) {
1156 HILOG_ERROR_I18N("FormatNumber: Create format string failed");
1157 return nullptr;
1158 }
1159 return result;
1160 }
1161
GetCollatorLocaleMatcher(napi_env env,napi_value options,std::map<std::string,std::string> & map)1162 void GetCollatorLocaleMatcher(napi_env env, napi_value options, std::map<std::string, std::string> &map)
1163 {
1164 GetOptionValue(env, options, "localeMatcher", map);
1165 auto it = map.find("localeMatcher");
1166 if (it != map.end()) {
1167 std::string localeMatcher = it->second;
1168 if (localeMatcher != "lookup" && localeMatcher != "best fit") {
1169 HILOG_ERROR_I18N("invalid localeMatcher");
1170 return;
1171 }
1172 } else {
1173 map.insert(std::make_pair("localeMatcher", "best fit"));
1174 }
1175 }
1176
GetCollatorUsage(napi_env env,napi_value options,std::map<std::string,std::string> & map)1177 void GetCollatorUsage(napi_env env, napi_value options, std::map<std::string, std::string> &map)
1178 {
1179 GetOptionValue(env, options, "usage", map);
1180 auto it = map.find("usage");
1181 if (it != map.end()) {
1182 std::string usage = it->second;
1183 if (usage != "sort" && usage != "search") {
1184 HILOG_ERROR_I18N("invalid usage");
1185 return;
1186 }
1187 } else {
1188 map.insert(std::make_pair("usage", "sort"));
1189 }
1190 }
1191
GetCollatorSensitivity(napi_env env,napi_value options,std::map<std::string,std::string> & map)1192 void GetCollatorSensitivity(napi_env env, napi_value options, std::map<std::string, std::string> &map)
1193 {
1194 GetOptionValue(env, options, "sensitivity", map);
1195 auto it = map.find("sensitivity");
1196 if (it != map.end()) {
1197 std::string sensitivity = it->second;
1198 if (sensitivity != "base" && sensitivity != "accent" && sensitivity != "case" && sensitivity != "variant") {
1199 HILOG_ERROR_I18N("invalid sensitivity");
1200 return;
1201 }
1202 } else {
1203 map.insert(std::make_pair("sensitivity", "variant"));
1204 }
1205 }
1206
GetCollatorIgnorePunctuation(napi_env env,napi_value options,std::map<std::string,std::string> & map)1207 void GetCollatorIgnorePunctuation(napi_env env, napi_value options, std::map<std::string, std::string> &map)
1208 {
1209 GetBoolOptionValue(env, options, "ignorePunctuation", map);
1210 auto it = map.find("ignorePunctuation");
1211 if (it != map.end()) {
1212 std::string ignorePunctuation = it->second;
1213 if (ignorePunctuation != "true" && ignorePunctuation != "false") {
1214 HILOG_ERROR_I18N("invalid ignorePunctuation");
1215 return;
1216 }
1217 } else {
1218 map.insert(std::make_pair("ignorePunctuation", "false"));
1219 }
1220 }
1221
GetCollatorNumeric(napi_env env,napi_value options,std::map<std::string,std::string> & map)1222 void GetCollatorNumeric(napi_env env, napi_value options, std::map<std::string, std::string> &map)
1223 {
1224 GetBoolOptionValue(env, options, "numeric", map);
1225 auto it = map.find("numeric");
1226 if (it != map.end()) {
1227 std::string numeric = it->second;
1228 if (numeric != "true" && numeric != "false") {
1229 HILOG_ERROR_I18N("invalid numeric");
1230 return;
1231 }
1232 }
1233 }
1234
GetCollatorCaseFirst(napi_env env,napi_value options,std::map<std::string,std::string> & map)1235 void GetCollatorCaseFirst(napi_env env, napi_value options, std::map<std::string, std::string> &map)
1236 {
1237 GetOptionValue(env, options, "caseFirst", map);
1238 auto it = map.find("caseFirst");
1239 if (it != map.end()) {
1240 std::string caseFirst = it->second;
1241 if (caseFirst != "upper" && caseFirst != "lower" && caseFirst != "false") {
1242 HILOG_ERROR_I18N("invalid caseFirst");
1243 return;
1244 }
1245 }
1246 }
1247
GetCollatorCollation(napi_env env,napi_value options,std::map<std::string,std::string> & map)1248 void GetCollatorCollation(napi_env env, napi_value options, std::map<std::string, std::string> &map)
1249 {
1250 GetOptionValue(env, options, "collation", map);
1251 auto it = map.find("collation");
1252 if (it != map.end()) {
1253 std::string collation = it->second;
1254 std::set<std::string> validCollation;
1255 validCollation.insert("big5han");
1256 validCollation.insert("compat");
1257 validCollation.insert("dict");
1258 validCollation.insert("direct");
1259 validCollation.insert("ducet");
1260 validCollation.insert("eor");
1261 validCollation.insert("gb2312");
1262 validCollation.insert("phonebk");
1263 validCollation.insert("phonetic");
1264 validCollation.insert("pinyin");
1265 validCollation.insert("reformed");
1266 validCollation.insert("searchjl");
1267 validCollation.insert("stroke");
1268 validCollation.insert("trad");
1269 validCollation.insert("unihan");
1270 validCollation.insert("zhuyin");
1271 if (validCollation.find(collation) == validCollation.end()) {
1272 map["collation"] = "default";
1273 }
1274 }
1275 }
1276
GetCollatorOptionValue(napi_env env,napi_value options,std::map<std::string,std::string> & map)1277 void GetCollatorOptionValue(napi_env env, napi_value options, std::map<std::string, std::string> &map)
1278 {
1279 GetCollatorLocaleMatcher(env, options, map);
1280 GetCollatorUsage(env, options, map);
1281 GetCollatorSensitivity(env, options, map);
1282 GetCollatorIgnorePunctuation(env, options, map);
1283 GetCollatorNumeric(env, options, map);
1284 GetCollatorCaseFirst(env, options, map);
1285 GetCollatorCollation(env, options, map);
1286 }
1287
InitCollator(napi_env env,napi_value exports)1288 napi_value IntlAddon::InitCollator(napi_env env, napi_value exports)
1289 {
1290 napi_status status = napi_ok;
1291 napi_property_descriptor properties[] = {
1292 DECLARE_NAPI_FUNCTION("compare", CompareString),
1293 DECLARE_NAPI_FUNCTION("resolvedOptions", GetCollatorResolvedOptions)
1294 };
1295
1296 napi_value constructor;
1297 status = napi_define_class(env, "Collator", NAPI_AUTO_LENGTH, CollatorConstructor, nullptr,
1298 sizeof(properties) / sizeof(napi_property_descriptor), properties, &constructor);
1299 if (status != napi_ok) {
1300 HILOG_ERROR_I18N("Define class failed when InitCollator");
1301 return nullptr;
1302 }
1303
1304 status = napi_set_named_property(env, exports, "Collator", constructor);
1305 if (status != napi_ok) {
1306 HILOG_ERROR_I18N("Set property failed when InitCollator");
1307 return nullptr;
1308 }
1309 return exports;
1310 }
1311
CollatorConstructor(napi_env env,napi_callback_info info)1312 napi_value IntlAddon::CollatorConstructor(napi_env env, napi_callback_info info)
1313 {
1314 size_t argc = 2;
1315 napi_value argv[2] = { nullptr };
1316 napi_value thisVar = nullptr;
1317 void *data = nullptr;
1318 napi_status status = napi_get_cb_info(env, info, &argc, argv, &thisVar, &data);
1319 if (status != napi_ok) {
1320 return nullptr;
1321 }
1322 std::vector<std::string> localeTags;
1323 if (argc > 0) {
1324 napi_valuetype valueType = napi_valuetype::napi_undefined;
1325 napi_typeof(env, argv[0], &valueType);
1326 bool isArray = false;
1327 napi_is_array(env, argv[0], &isArray);
1328 if (valueType == napi_valuetype::napi_string) {
1329 GetLocaleTags(env, argv[0], localeTags);
1330 } else if (isArray) {
1331 uint32_t arrayLength = 0;
1332 napi_get_array_length(env, argv[0], &arrayLength);
1333 napi_value element = nullptr;
1334 for (uint32_t i = 0; i < arrayLength; i++) {
1335 napi_get_element(env, argv[0], i, &element);
1336 GetLocaleTags(env, element, localeTags);
1337 }
1338 }
1339 }
1340 std::map<std::string, std::string> map = {};
1341 if (argc > 1) {
1342 GetCollatorOptionValue(env, argv[1], map);
1343 }
1344 std::unique_ptr<IntlAddon> obj = nullptr;
1345 obj = std::make_unique<IntlAddon>();
1346 status =
1347 napi_wrap(env, thisVar, reinterpret_cast<void *>(obj.get()), IntlAddon::Destructor, nullptr, nullptr);
1348 if (status != napi_ok) {
1349 HILOG_ERROR_I18N("CollatorConstructor: Wrap IntlAddon failed");
1350 return nullptr;
1351 }
1352 if (!obj->InitCollatorContext(env, info, localeTags, map)) {
1353 HILOG_ERROR_I18N("CollatorConstructor: Init DateTimeFormat failed");
1354 return nullptr;
1355 }
1356 obj.release();
1357 return thisVar;
1358 }
1359
InitCollatorContext(napi_env env,napi_callback_info info,std::vector<std::string> localeTags,std::map<std::string,std::string> & map)1360 bool IntlAddon::InitCollatorContext(napi_env env, napi_callback_info info, std::vector<std::string> localeTags,
1361 std::map<std::string, std::string> &map)
1362 {
1363 napi_value global = nullptr;
1364 napi_status status = napi_get_global(env, &global);
1365 if (status != napi_ok) {
1366 HILOG_ERROR_I18N("InitCollatorContext: Get global failed");
1367 return false;
1368 }
1369 env_ = env;
1370 collator_ = std::make_unique<Collator>(localeTags, map);
1371
1372 return collator_ != nullptr;
1373 }
1374
GetStringParameter(napi_env env,napi_value value,std::vector<char> & buf)1375 bool GetStringParameter(napi_env env, napi_value value, std::vector<char> &buf)
1376 {
1377 napi_valuetype valueType = napi_valuetype::napi_undefined;
1378 napi_typeof(env, value, &valueType);
1379 if (valueType != napi_valuetype::napi_string) {
1380 HILOG_ERROR_I18N("Parameter type does not match");
1381 return false;
1382 }
1383 size_t len = 0;
1384 napi_status status = napi_get_value_string_utf8(env, value, nullptr, 0, &len);
1385 if (status != napi_ok) {
1386 HILOG_ERROR_I18N("Get first length failed");
1387 return false;
1388 }
1389 buf.resize(len + 1);
1390 status = napi_get_value_string_utf8(env, value, buf.data(), len + 1, &len);
1391 if (status != napi_ok) {
1392 HILOG_ERROR_I18N("Get first failed");
1393 return false;
1394 }
1395
1396 return true;
1397 }
1398
FormatRelativeTime(napi_env env,napi_callback_info info)1399 napi_value IntlAddon::FormatRelativeTime(napi_env env, napi_callback_info info)
1400 {
1401 size_t argc = 2;
1402 napi_value argv[2] = { 0 };
1403 napi_value thisVar = nullptr;
1404 void *data = nullptr;
1405 napi_get_cb_info(env, info, &argc, argv, &thisVar, &data);
1406 napi_status status;
1407 double number;
1408 status = napi_get_value_double(env, argv[0], &number);
1409 if (status != napi_ok) {
1410 HILOG_ERROR_I18N("FormatRelativeTime: Get number failed");
1411 return nullptr;
1412 }
1413 std::vector<char> unit;
1414 if (!GetStringParameter(env, argv[1], unit)) {
1415 return nullptr;
1416 }
1417 IntlAddon *obj = nullptr;
1418 status = napi_unwrap(env, thisVar, reinterpret_cast<void **>(&obj));
1419 if (status != napi_ok || !obj || !obj->relativetimefmt_) {
1420 HILOG_ERROR_I18N("FormatRelativeTime: Get RelativeTimeFormat object failed");
1421 return nullptr;
1422 }
1423 std::string value = obj->relativetimefmt_->Format(number, unit.data());
1424 napi_value result = nullptr;
1425 status = napi_create_string_utf8(env, value.c_str(), NAPI_AUTO_LENGTH, &result);
1426 if (status != napi_ok) {
1427 HILOG_ERROR_I18N("FormatRelativeTime: Create format string failed");
1428 return nullptr;
1429 }
1430 return result;
1431 }
1432
FillInArrayElement(napi_env env,napi_value & result,napi_status & status,const std::vector<std::vector<std::string>> & timeVector)1433 void IntlAddon::FillInArrayElement(napi_env env, napi_value &result, napi_status &status,
1434 const std::vector<std::vector<std::string>> &timeVector)
1435 {
1436 for (size_t i = 0; i < timeVector.size(); i++) {
1437 napi_value value = nullptr;
1438 status = napi_create_string_utf8(env, timeVector[i][1].c_str(), NAPI_AUTO_LENGTH, &value);
1439 if (status != napi_ok) {
1440 HILOG_ERROR_I18N("Failed to create string item imeVector[i][1].");
1441 return;
1442 }
1443 napi_value type = nullptr;
1444 status = napi_create_string_utf8(env, timeVector[i][0].c_str(), NAPI_AUTO_LENGTH, &type);
1445 if (status != napi_ok) {
1446 HILOG_ERROR_I18N("Failed to create string item timeVector[i][0].");
1447 return;
1448 }
1449 napi_value unit = nullptr;
1450 size_t unitIndex = 2;
1451 if (timeVector[i].size() > unitIndex) {
1452 status = napi_create_string_utf8(env, timeVector[i][unitIndex].c_str(), NAPI_AUTO_LENGTH, &unit);
1453 if (status != napi_ok) {
1454 HILOG_ERROR_I18N("Failed to create string item timeVector[i][unitIndex].");
1455 return;
1456 }
1457 } else {
1458 napi_get_undefined(env, &unit);
1459 }
1460 napi_value formatInfo;
1461 status = napi_create_object(env, &formatInfo);
1462 if (status != napi_ok) {
1463 HILOG_ERROR_I18N("Failed to create format info object.");
1464 return;
1465 }
1466 napi_set_named_property(env, formatInfo, "type", type);
1467 napi_set_named_property(env, formatInfo, "value", value);
1468 napi_set_named_property(env, formatInfo, "unit", unit);
1469 status = napi_set_element(env, result, i, formatInfo);
1470 if (status != napi_ok) {
1471 HILOG_ERROR_I18N("Failed to set array item");
1472 return;
1473 }
1474 }
1475 }
1476
FormatToParts(napi_env env,napi_callback_info info)1477 napi_value IntlAddon::FormatToParts(napi_env env, napi_callback_info info)
1478 {
1479 size_t argc = 2;
1480 napi_value argv[2] = { 0 };
1481 napi_value thisVar = nullptr;
1482 void *data = nullptr;
1483 napi_get_cb_info(env, info, &argc, argv, &thisVar, &data);
1484 double number = 0;
1485 napi_get_value_double(env, argv[0], &number);
1486 std::vector<char> unit;
1487 if (!GetStringParameter(env, argv[1], unit)) {
1488 return nullptr;
1489 }
1490 IntlAddon *obj = nullptr;
1491 napi_status status = napi_unwrap(env, thisVar, reinterpret_cast<void **>(&obj));
1492 if (status != napi_ok || !obj || !obj->relativetimefmt_) {
1493 HILOG_ERROR_I18N("FormatToParts: Get RelativeTimeFormat object failed");
1494 return nullptr;
1495 }
1496 std::vector<std::vector<std::string>> timeVector;
1497 obj->relativetimefmt_->FormatToParts(number, unit.data(), timeVector);
1498 napi_value result = nullptr;
1499 status = napi_create_array_with_length(env, timeVector.size(), &result);
1500 if (status != napi_ok) {
1501 HILOG_ERROR_I18N("Failed to create array");
1502 return nullptr;
1503 }
1504 FillInArrayElement(env, result, status, timeVector);
1505 return result;
1506 }
1507
CompareString(napi_env env,napi_callback_info info)1508 napi_value IntlAddon::CompareString(napi_env env, napi_callback_info info)
1509 {
1510 size_t argc = 2;
1511 napi_value argv[2] = { 0 };
1512 napi_value thisVar = nullptr;
1513 void *data = nullptr;
1514 napi_get_cb_info(env, info, &argc, argv, &thisVar, &data);
1515
1516 std::vector<char> first;
1517 if (!GetStringParameter(env, argv[0], first)) {
1518 return nullptr;
1519 }
1520
1521 std::vector<char> second;
1522 if (!GetStringParameter(env, argv[1], second)) {
1523 return nullptr;
1524 }
1525
1526 IntlAddon *obj = nullptr;
1527 napi_status status = napi_unwrap(env, thisVar, reinterpret_cast<void **>(&obj));
1528 if (status != napi_ok || !obj || !obj->collator_) {
1529 HILOG_ERROR_I18N("CompareString: Get Collator object failed");
1530 return nullptr;
1531 }
1532
1533 CompareResult compareResult = obj->collator_->Compare(first.data(), second.data());
1534 napi_value result = nullptr;
1535 status = napi_create_int32(env, compareResult, &result);
1536 if (status != napi_ok) {
1537 HILOG_ERROR_I18N("Create compare result failed");
1538 return nullptr;
1539 }
1540
1541 return result;
1542 }
1543
GetCollatorResolvedOptions(napi_env env,napi_callback_info info)1544 napi_value IntlAddon::GetCollatorResolvedOptions(napi_env env, napi_callback_info info)
1545 {
1546 napi_value thisVar = nullptr;
1547 void *data = nullptr;
1548 napi_get_cb_info(env, info, nullptr, nullptr, &thisVar, &data);
1549
1550 IntlAddon *obj = nullptr;
1551 napi_status status = napi_unwrap(env, thisVar, reinterpret_cast<void **>(&obj));
1552 if (status != napi_ok || !obj || !obj->collator_) {
1553 HILOG_ERROR_I18N("GetCollatorResolvedOptions: Get Collator object failed");
1554 return nullptr;
1555 }
1556 napi_value result = nullptr;
1557 napi_create_object(env, &result);
1558 std::map<std::string, std::string> options = {};
1559 obj->collator_->ResolvedOptions(options);
1560 SetOptionProperties(env, result, options, "localeMatcher");
1561 SetOptionProperties(env, result, options, "locale");
1562 SetOptionProperties(env, result, options, "usage");
1563 SetOptionProperties(env, result, options, "sensitivity");
1564 SetBooleanOptionProperties(env, result, options, "ignorePunctuation");
1565 SetBooleanOptionProperties(env, result, options, "numeric");
1566 SetOptionProperties(env, result, options, "caseFirst");
1567 SetOptionProperties(env, result, options, "collation");
1568 return result;
1569 }
1570
GetPluralRulesType(napi_env env,napi_value options,std::map<std::string,std::string> & map)1571 void GetPluralRulesType(napi_env env, napi_value options, std::map<std::string, std::string> &map)
1572 {
1573 GetOptionValue(env, options, "type", map);
1574 auto it = map.find("type");
1575 if (it != map.end()) {
1576 std::string type = it->second;
1577 if (type != "cardinal" && type != "ordinal") {
1578 HILOG_ERROR_I18N("invalid type");
1579 return;
1580 }
1581 } else {
1582 map.insert(std::make_pair("type", "cardinal"));
1583 }
1584 }
1585
GetPluralRulesInteger(napi_env env,napi_value options,std::map<std::string,std::string> & map)1586 void GetPluralRulesInteger(napi_env env, napi_value options, std::map<std::string, std::string> &map)
1587 {
1588 GetIntegerOptionValue(env, options, "minimumIntegerDigits", map);
1589 auto it = map.find("minimumIntegerDigits");
1590 if (it != map.end()) {
1591 std::string minimumIntegerDigits = it->second;
1592 int n = std::stoi(minimumIntegerDigits);
1593 if (n < 1 || n > 21) { // the valid range of minimumIntegerDigits is [1, 21]
1594 HILOG_ERROR_I18N("invalid minimumIntegerDigits");
1595 return;
1596 }
1597 } else {
1598 map.insert(std::make_pair("minimumIntegerDigits", std::to_string(1)));
1599 }
1600 }
1601
GetPluralRulesFractions(napi_env env,napi_value options,std::map<std::string,std::string> & map)1602 void GetPluralRulesFractions(napi_env env, napi_value options, std::map<std::string, std::string> &map)
1603 {
1604 GetIntegerOptionValue(env, options, "minimumFractionDigits", map);
1605 auto it = map.find("minimumFractionDigits");
1606 if (it != map.end()) {
1607 std::string minimumFractionDigits = it->second;
1608 int n = std::stoi(minimumFractionDigits);
1609 if (n < 0 || n > 20) { // the valid range of minimumFractionDigits is [0, 20]
1610 HILOG_ERROR_I18N("invalid minimumFractionDigits");
1611 return;
1612 }
1613 }
1614
1615 GetIntegerOptionValue(env, options, "maximumFractionDigits", map);
1616 it = map.find("maximumFractionDigits");
1617 if (it != map.end()) {
1618 std::string maximumFractionDigits = it->second;
1619 int n = std::stoi(maximumFractionDigits);
1620 if (n < 0 || n > 20) { // the valid range of maximumFractionDigits is [0, 20]
1621 HILOG_ERROR_I18N("invalid maximumFractionDigits");
1622 return;
1623 }
1624 }
1625 }
1626
GetPluralRulesSignificant(napi_env env,napi_value options,std::map<std::string,std::string> & map)1627 void GetPluralRulesSignificant(napi_env env, napi_value options, std::map<std::string, std::string> &map)
1628 {
1629 int minSignificant = -1;
1630 GetIntegerOptionValue(env, options, "minimumSignificantDigits", map);
1631 auto it = map.find("minimumSignificantDigits");
1632 if (it != map.end()) {
1633 std::string minSignificantStr = it->second;
1634 int minSignificantInt = std::stoi(minSignificantStr);
1635 // the valid range of minSignificantInt is [1, 21]
1636 if (minSignificantInt < 1 || minSignificantInt > 21) {
1637 HILOG_ERROR_I18N("invalid minimumSignificantDigits");
1638 return;
1639 }
1640 minSignificant = minSignificantInt;
1641 } else {
1642 minSignificant = 1;
1643 }
1644
1645 GetIntegerOptionValue(env, options, "maximumSignificantDigits", map);
1646 it = map.find("maximumSignificantDigits");
1647 if (it != map.end()) {
1648 std::string maxSignificantStr = it->second;
1649 int maxSignificant = std::stoi(maxSignificantStr);
1650 // the valid range of minSignificant is [minSignificant, 21]
1651 if (maxSignificant < minSignificant || maxSignificant > 21) {
1652 HILOG_ERROR_I18N("invalid maximumSignificantDigits");
1653 return;
1654 }
1655 }
1656 }
1657
GetPluralRulesOptionValues(napi_env env,napi_value options,std::map<std::string,std::string> & map)1658 void GetPluralRulesOptionValues(napi_env env, napi_value options, std::map<std::string, std::string> &map)
1659 {
1660 GetCollatorLocaleMatcher(env, options, map);
1661 GetPluralRulesType(env, options, map);
1662 GetPluralRulesInteger(env, options, map);
1663 GetPluralRulesFractions(env, options, map);
1664 GetPluralRulesSignificant(env, options, map);
1665 }
1666
InitPluralRules(napi_env env,napi_value exports)1667 napi_value IntlAddon::InitPluralRules(napi_env env, napi_value exports)
1668 {
1669 napi_status status = napi_ok;
1670 napi_property_descriptor properties[] = {
1671 DECLARE_NAPI_FUNCTION("select", Select)
1672 };
1673
1674 napi_value constructor = nullptr;
1675 status = napi_define_class(env, "PluralRules", NAPI_AUTO_LENGTH, PluralRulesConstructor, nullptr,
1676 sizeof(properties) / sizeof(napi_property_descriptor), properties, &constructor);
1677 if (status != napi_ok) {
1678 HILOG_ERROR_I18N("Define class failed when InitPluralRules");
1679 return nullptr;
1680 }
1681
1682 status = napi_set_named_property(env, exports, "PluralRules", constructor);
1683 if (status != napi_ok) {
1684 HILOG_ERROR_I18N("Set property failed when InitPluralRules");
1685 return nullptr;
1686 }
1687 return exports;
1688 }
1689
PluralRulesConstructor(napi_env env,napi_callback_info info)1690 napi_value IntlAddon::PluralRulesConstructor(napi_env env, napi_callback_info info)
1691 {
1692 size_t argc = 2;
1693 napi_value argv[2] = { nullptr };
1694 napi_value thisVar = nullptr;
1695 void *data = nullptr;
1696 napi_status status = napi_get_cb_info(env, info, &argc, argv, &thisVar, &data);
1697 if (status != napi_ok) {
1698 return nullptr;
1699 }
1700 napi_valuetype valueType = napi_valuetype::napi_undefined;
1701 std::vector<std::string> localeTags;
1702 if (argc > 0) {
1703 napi_typeof(env, argv[0], &valueType);
1704 bool isArray = false;
1705 napi_is_array(env, argv[0], &isArray);
1706 if (valueType == napi_valuetype::napi_string) {
1707 GetLocaleTags(env, argv[0], localeTags);
1708 } else if (isArray) {
1709 uint32_t arrayLength = 0;
1710 napi_get_array_length(env, argv[0], &arrayLength);
1711 napi_value element = nullptr;
1712 for (uint32_t i = 0; i < arrayLength; i++) {
1713 napi_get_element(env, argv[0], i, &element);
1714 GetLocaleTags(env, element, localeTags);
1715 }
1716 }
1717 }
1718 std::map<std::string, std::string> map = {};
1719 if (argc > 1) {
1720 GetPluralRulesOptionValues(env, argv[1], map);
1721 }
1722 std::unique_ptr<IntlAddon> obj = nullptr;
1723 obj = std::make_unique<IntlAddon>();
1724 status =
1725 napi_wrap(env, thisVar, reinterpret_cast<void *>(obj.get()), IntlAddon::Destructor, nullptr, nullptr);
1726 if (status != napi_ok) {
1727 HILOG_ERROR_I18N("PluralRulesConstructor: Wrap IntlAddon failed");
1728 return nullptr;
1729 }
1730 if (!obj->InitPluralRulesContext(env, info, localeTags, map)) {
1731 HILOG_ERROR_I18N("PluralRulesConstructor: Init DateTimeFormat failed");
1732 return nullptr;
1733 }
1734 obj.release();
1735 return thisVar;
1736 }
1737
InitPluralRulesContext(napi_env env,napi_callback_info info,std::vector<std::string> localeTags,std::map<std::string,std::string> & map)1738 bool IntlAddon::InitPluralRulesContext(napi_env env, napi_callback_info info, std::vector<std::string> localeTags,
1739 std::map<std::string, std::string> &map)
1740 {
1741 napi_value global = nullptr;
1742 napi_status status = napi_get_global(env, &global);
1743 if (status != napi_ok) {
1744 HILOG_ERROR_I18N("InitPluralRulesContext: Get global failed");
1745 return false;
1746 }
1747 env_ = env;
1748 pluralrules_ = std::make_unique<PluralRules>(localeTags, map);
1749
1750 return pluralrules_ != nullptr;
1751 }
1752
Select(napi_env env,napi_callback_info info)1753 napi_value IntlAddon::Select(napi_env env, napi_callback_info info)
1754 {
1755 size_t argc = 1;
1756 napi_value argv[1] = { 0 };
1757 napi_value thisVar = nullptr;
1758 void *data = nullptr;
1759 napi_get_cb_info(env, info, &argc, argv, &thisVar, &data);
1760 napi_valuetype valueType = napi_valuetype::napi_undefined;
1761 napi_typeof(env, argv[0], &valueType);
1762 if (valueType != napi_valuetype::napi_number) {
1763 HILOG_ERROR_I18N("Select: Parameter type does not match");
1764 return nullptr;
1765 }
1766
1767 double number = 0;
1768 napi_status status = napi_get_value_double(env, argv[0], &number);
1769 if (status != napi_ok) {
1770 HILOG_ERROR_I18N("Select: Get number failed");
1771 return nullptr;
1772 }
1773
1774 IntlAddon *obj = nullptr;
1775 status = napi_unwrap(env, thisVar, reinterpret_cast<void **>(&obj));
1776 if (status != napi_ok || !obj || !obj->pluralrules_) {
1777 HILOG_ERROR_I18N("Get PluralRules object failed");
1778 return nullptr;
1779 }
1780
1781 std::string res = obj->pluralrules_->Select(number);
1782 napi_value result = nullptr;
1783 status = napi_create_string_utf8(env, res.c_str(), NAPI_AUTO_LENGTH, &result);
1784 if (status != napi_ok) {
1785 HILOG_ERROR_I18N("get select result failed");
1786 return nullptr;
1787 }
1788 return result;
1789 }
1790
Init(napi_env env,napi_value exports)1791 napi_value Init(napi_env env, napi_value exports)
1792 {
1793 napi_value val = IntlAddon::InitLocale(env, exports);
1794 val = IntlAddon::InitDateTimeFormat(env, val);
1795 val = IntlAddon::InitNumberFormat(env, val);
1796 val = IntlAddon::InitCollator(env, val);
1797 val = IntlAddon::InitRelativeTimeFormat(env, val);
1798 return IntlAddon::InitPluralRules(env, val);
1799 }
1800
1801 static napi_module g_intlModule = {
1802 .nm_version = 1,
1803 .nm_flags = 0,
1804 .nm_filename = nullptr,
1805 .nm_register_func = Init,
1806 .nm_modname = "intl",
1807 .nm_priv = nullptr,
1808 .reserved = { 0 }
1809 };
1810
AbilityRegister()1811 extern "C" __attribute__((constructor)) void AbilityRegister()
1812 {
1813 napi_module_register(&g_intlModule);
1814 }
1815 } // namespace I18n
1816 } // namespace Global
1817 } // namespace OHOS
1818