1 /*
2 * Copyright (c) 2025 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_plural_rules_addon.h"
17 #include "i18n_hilog.h"
18 #include "js_utils.h"
19
20 namespace OHOS {
21 namespace Global {
22 namespace I18n {
Destructor(napi_env env,void * nativeObject,void * finalize_hint)23 void IntlPluralRulesAddon::Destructor(napi_env env, void* nativeObject, void* finalize_hint)
24 {
25 if (!nativeObject) {
26 return;
27 }
28 delete reinterpret_cast<IntlPluralRulesAddon *>(nativeObject);
29 nativeObject = nullptr;
30 }
31
InitIntlPluralRules(napi_env env,napi_value exports)32 napi_value IntlPluralRulesAddon::InitIntlPluralRules(napi_env env, napi_value exports)
33 {
34 napi_property_descriptor properties[] = {
35 DECLARE_NAPI_FUNCTION("select", Select),
36 DECLARE_NAPI_FUNCTION("resolvedOptions", ResolvedOptions),
37 DECLARE_NAPI_FUNCTION("toString", ToString),
38 DECLARE_NAPI_STATIC_FUNCTION("supportedLocalesOf", SupportedLocalesOf),
39 };
40
41 napi_value constructor;
42 napi_status status = napi_define_class(env, "PluralRules", NAPI_AUTO_LENGTH, IntlPluralRulesConstructor,
43 nullptr, sizeof(properties) / sizeof(napi_property_descriptor), properties, &constructor);
44 if (status != napi_ok) {
45 HILOG_ERROR_I18N("InitIntlPluralRules: Define class failed.");
46 return nullptr;
47 }
48
49 status = napi_set_named_property(env, exports, "PluralRules", constructor);
50 if (status != napi_ok) {
51 HILOG_ERROR_I18N("InitIntlPluralRules: Set property failed.");
52 return nullptr;
53 }
54 return exports;
55 }
56
IntlPluralRulesConstructor(napi_env env,napi_callback_info info)57 napi_value IntlPluralRulesAddon::IntlPluralRulesConstructor(napi_env env, napi_callback_info info)
58 {
59 size_t argc = 2;
60 napi_value argv[2] = { nullptr };
61 napi_value thisVar = nullptr;
62 void *data = nullptr;
63 napi_status status = napi_get_cb_info(env, info, &argc, argv, &thisVar, &data);
64 if (status != napi_ok) {
65 HILOG_ERROR_I18N("IntlPluralRulesConstructor: napi get callback info failed.");
66 return nullptr;
67 }
68
69 napi_value new_target;
70 status = napi_get_new_target(env, info, &new_target);
71 if (status == napi_pending_exception || new_target == nullptr) {
72 HILOG_ERROR_I18N("IntlPluralRulesConstructor: newTarget is undefined.");
73 napi_value exception;
74 napi_get_and_clear_last_exception(env, &exception);
75 napi_throw_type_error(env, nullptr, "newTarget is undefined");
76 return nullptr;
77 } else if (status != napi_ok) {
78 HILOG_ERROR_I18N("IntlPluralRulesConstructor: get newTarget failed.");
79 return nullptr;
80 }
81
82 std::vector<std::string> localeTags;
83 if (argc > 0) {
84 int32_t code = 0;
85 localeTags = JSUtils::GetLocaleArray(env, argv[0], code);
86 }
87 std::unordered_map<std::string, std::string> configs;
88 if (argc > 1) {
89 configs = ParseConfigs(env, argv[1]);
90 }
91 IntlPluralRulesAddon* obj = new (std::nothrow) IntlPluralRulesAddon();
92 if (obj == nullptr) {
93 HILOG_ERROR_I18N("IntlPluralRulesConstructor: Create obj failed.");
94 return nullptr;
95 }
96 status = napi_wrap(env, thisVar, reinterpret_cast<void *>(obj), IntlPluralRulesAddon::Destructor,
97 nullptr, nullptr);
98 if (status != napi_ok) {
99 delete obj;
100 HILOG_ERROR_I18N("IntlPluralRulesConstructor: Wrap IntlPluralRulesAddon failed.");
101 return nullptr;
102 }
103 if (!obj->InitIntlPluralRulesContext(env, localeTags, configs)) {
104 HILOG_ERROR_I18N("IntlPluralRulesConstructor: Init IntlPluralRules failed.");
105 return nullptr;
106 }
107 return thisVar;
108 }
109
InitIntlPluralRulesContext(napi_env env,const std::vector<std::string> & localeTags,const std::unordered_map<std::string,std::string> & configs)110 bool IntlPluralRulesAddon::InitIntlPluralRulesContext(napi_env env, const std::vector<std::string>& localeTags,
111 const std::unordered_map<std::string, std::string>& configs)
112 {
113 ErrorMessage errorMessage;
114 intlPluralRules = std::make_unique<IntlPluralRules>(localeTags, configs, errorMessage);
115 if (errorMessage.type != ErrorType::NO_ERROR) {
116 HILOG_ERROR_I18N("InitIntlPluralRulesContext: IntlPluralRules constructor failed.");
117 napi_throw_range_error(env, nullptr, errorMessage.message.c_str());
118 return false;
119 }
120 return intlPluralRules != nullptr;
121 }
122
Select(napi_env env,napi_callback_info info)123 napi_value IntlPluralRulesAddon::Select(napi_env env, napi_callback_info info)
124 {
125 size_t argc = 1;
126 napi_value argv[1] = { nullptr };
127 napi_value thisVar = nullptr;
128 void *data = nullptr;
129 napi_status status = napi_get_cb_info(env, info, &argc, argv, &thisVar, &data);
130 if (status != napi_ok) {
131 HILOG_ERROR_I18N("IntlPluralRulesAddon::Select: napi get callback info failed.");
132 return nullptr;
133 }
134 if (argc < 1) {
135 HILOG_ERROR_I18N("IntlPluralRulesAddon::Select: missing code param.");
136 return nullptr;
137 }
138 napi_valuetype valueType = napi_valuetype::napi_undefined;
139 status = napi_typeof(env, argv[0], &valueType);
140 if (status != napi_ok) {
141 HILOG_ERROR_I18N("IntlPluralRulesAddon::Select: Get parameter type failed.");
142 return nullptr;
143 }
144 int32_t errorCode = 0;
145 double number = JSUtils::GetDoubleFromNapiValue(env, argv[0], valueType, errorCode);
146 if (errorCode != 0) {
147 HILOG_ERROR_I18N("IntlPluralRulesAddon::Select: Get number value failed.");
148 return nullptr;
149 }
150
151 IntlPluralRulesAddon *obj = nullptr;
152 status = napi_unwrap(env, thisVar, reinterpret_cast<void **>(&obj));
153 if (status != napi_ok || !obj || !obj->intlPluralRules) {
154 HILOG_ERROR_I18N("IntlPluralRulesAddon::Select: Get IntlPluralRules object failed.");
155 return nullptr;
156 }
157
158 ErrorMessage errorMessage;
159 std::string formatedValue = obj->intlPluralRules->Select(number, errorMessage);
160 if (errorMessage.type != ErrorType::NO_ERROR) {
161 HILOG_ERROR_I18N("IntlPluralRulesAddon::Select: IntlPluralRules select failed.");
162 napi_throw_range_error(env, nullptr, errorMessage.message.c_str());
163 return nullptr;
164 }
165 return JSUtils::CreateString(env, formatedValue);
166 }
167
ResolvedOptions(napi_env env,napi_callback_info info)168 napi_value IntlPluralRulesAddon::ResolvedOptions(napi_env env, napi_callback_info info)
169 {
170 napi_value thisVar = nullptr;
171 void *data = nullptr;
172 napi_status status = napi_get_cb_info(env, info, nullptr, nullptr, &thisVar, &data);
173 if (status != napi_ok) {
174 HILOG_ERROR_I18N("IntlPluralRulesAddon::ResolvedOptions: get cb info failed.");
175 return nullptr;
176 }
177 IntlPluralRulesAddon *obj = nullptr;
178 status = napi_unwrap(env, thisVar, reinterpret_cast<void **>(&obj));
179 if (status != napi_ok || !obj || !obj->intlPluralRules) {
180 HILOG_ERROR_I18N("IntlPluralRulesAddon::ResolvedOptions: Get IntlPluralRules object failed.");
181 return nullptr;
182 }
183 IntlPluralRules::ResolvedValue resolvedValue = obj->intlPluralRules->ResolvedOptions();
184
185 napi_value result = nullptr;
186 status = napi_create_object(env, &result);
187 if (status != napi_ok) {
188 HILOG_ERROR_I18N("IntlPluralRulesAddon::ResolvedOptions: create object failed.");
189 return nullptr;
190 }
191 JSUtils::SetNamedStringProperties(env, result, "locale", resolvedValue.locale);
192 JSUtils::SetNamedStringProperties(env, result, "type", resolvedValue.type);
193 JSUtils::SetNamedIntegerProperties(env, result, "minimumIntegerDigits", resolvedValue.minimumIntegerDigits);
194 if (resolvedValue.roundingType == RoundingType::FRACTIONDIGITS) {
195 JSUtils::SetNamedIntegerProperties(env, result, "minimumFractionDigits", resolvedValue.minimumDigits);
196 JSUtils::SetNamedIntegerProperties(env, result, "maximumFractionDigits", resolvedValue.maximumDigits);
197 } else if (resolvedValue.roundingType == RoundingType::SIGNIFICANTDIGITS) {
198 JSUtils::SetNamedIntegerProperties(env, result, "minimumSignificantDigits", resolvedValue.minimumDigits);
199 JSUtils::SetNamedIntegerProperties(env, result, "maximumSignificantDigits", resolvedValue.maximumDigits);
200 }
201 JSUtils::SetNamedVectorProperties(env, result, "pluralCategories", resolvedValue.pluralCategories);
202 return result;
203 }
204
ToString(napi_env env,napi_callback_info info)205 napi_value IntlPluralRulesAddon::ToString(napi_env env, napi_callback_info info)
206 {
207 napi_value thisVar = nullptr;
208 void *data = nullptr;
209 napi_status status = napi_get_cb_info(env, info, nullptr, nullptr, &thisVar, &data);
210 if (status != napi_ok) {
211 HILOG_ERROR_I18N("IntlPluralRulesAddon::ToString: get cb info failed.");
212 return JSUtils::CreateEmptyString(env);
213 }
214 IntlPluralRulesAddon *obj = nullptr;
215 status = napi_unwrap(env, thisVar, reinterpret_cast<void **>(&obj));
216 if (status != napi_ok || !obj || !obj->intlPluralRules) {
217 HILOG_ERROR_I18N("IntlPluralRulesAddon::ToString: Get IntlPluralRules object failed.");
218 return JSUtils::CreateEmptyString(env);
219 }
220
221 return JSUtils::CreateString(env, "[object Intl.PluralRules]");
222 }
223
SupportedLocalesOf(napi_env env,napi_callback_info info)224 napi_value IntlPluralRulesAddon::SupportedLocalesOf(napi_env env, napi_callback_info info)
225 {
226 size_t argc = 2;
227 napi_value argv[2] = { nullptr };
228 napi_value thisVar = nullptr;
229 void *data = nullptr;
230 napi_status status = napi_get_cb_info(env, info, &argc, argv, &thisVar, &data);
231 if (status != napi_ok) {
232 HILOG_ERROR_I18N("IntlPluralRulesAddon::SupportedLocalesOf: napi get callback info failed.");
233 return JSUtils::CreateEmptyArray(env);
234 }
235 std::vector<std::string> localeTags;
236 if (argc > 0) {
237 int32_t code = 0;
238 localeTags = JSUtils::GetLocaleArray(env, argv[0], code);
239 }
240 std::unordered_map<std::string, std::string> options = {};
241 if (argc > 1) {
242 JSUtils::GetOptionValue(env, argv[1], "localeMatcher", options);
243 }
244 ErrorMessage errorMessage;
245 std::vector<std::string> supportedLocales =
246 IntlPluralRules::SupportedLocalesOf(localeTags, options, errorMessage);
247 if (errorMessage.type != ErrorType::NO_ERROR) {
248 HILOG_ERROR_I18N("IntlPluralRulesAddon::SupportedLocalesOf failed.");
249 napi_throw_range_error(env, nullptr, errorMessage.message.c_str());
250 return nullptr;
251 }
252 return JSUtils::CreateArray(env, supportedLocales);
253 }
254
ParseConfigs(napi_env env,napi_value options)255 std::unordered_map<std::string, std::string> IntlPluralRulesAddon::ParseConfigs(napi_env env, napi_value options)
256 {
257 std::unordered_map<std::string, std::string> configs;
258 JSUtils::GetOptionValue(env, options, "localeMatcher", configs);
259 JSUtils::GetOptionValue(env, options, "type", configs);
260 JSUtils::GetDoubleOptionValue(env, options, "minimumIntegerDigits", configs);
261 JSUtils::GetDoubleOptionValue(env, options, "minimumFractionDigits", configs);
262 JSUtils::GetDoubleOptionValue(env, options, "maximumFractionDigits", configs);
263 JSUtils::GetDoubleOptionValue(env, options, "minimumSignificantDigits", configs);
264 JSUtils::GetDoubleOptionValue(env, options, "maximumSignificantDigits", configs);
265 return configs;
266 }
267 } // namespace I18n
268 } // namespace Global
269 } // namespace OHOS