1 /*
2 * Copyright (c) 2024 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 #include "locale_info_addon.h"
16
17 #include <vector>
18
19 #include "error_util.h"
20 #include "i18n_hilog.h"
21 #include "js_utils.h"
22
23 namespace OHOS {
24 namespace Global {
25 namespace I18n {
26 static thread_local napi_ref *g_constructor = nullptr;
27
LocaleInfoAddon()28 LocaleInfoAddon::LocaleInfoAddon() : env_(nullptr) {}
29
~LocaleInfoAddon()30 LocaleInfoAddon::~LocaleInfoAddon()
31 {
32 }
33
Destructor(napi_env env,void * nativeObject,void * hint)34 void LocaleInfoAddon::Destructor(napi_env env, void *nativeObject, void *hint)
35 {
36 if (!nativeObject) {
37 return;
38 }
39 delete reinterpret_cast<LocaleInfoAddon *>(nativeObject);
40 nativeObject = nullptr;
41 }
42
SetProperty(napi_env env,napi_callback_info info)43 napi_value LocaleInfoAddon::SetProperty(napi_env env, napi_callback_info info)
44 {
45 // do nothing but provided as an input parameter for DECLARE_NAPI_GETTER_SETTER;
46 napi_value result = nullptr;
47 NAPI_CALL(env, napi_get_undefined(env, &result));
48 return result;
49 }
50
InitLocale(napi_env env,napi_value exports)51 napi_value LocaleInfoAddon::InitLocale(napi_env env, napi_value exports)
52 {
53 napi_property_descriptor properties[] = {
54 DECLARE_NAPI_GETTER_SETTER("language", GetLanguage, SetProperty),
55 DECLARE_NAPI_GETTER_SETTER("baseName", GetBaseName, SetProperty),
56 DECLARE_NAPI_GETTER_SETTER("region", GetRegion, SetProperty),
57 DECLARE_NAPI_GETTER_SETTER("script", GetScript, SetProperty),
58 DECLARE_NAPI_GETTER_SETTER("calendar", GetCalendar, SetProperty),
59 DECLARE_NAPI_GETTER_SETTER("collation", GetCollation, SetProperty),
60 DECLARE_NAPI_GETTER_SETTER("hourCycle", GetHourCycle, SetProperty),
61 DECLARE_NAPI_GETTER_SETTER("numberingSystem", GetNumberingSystem, SetProperty),
62 DECLARE_NAPI_GETTER_SETTER("numeric", GetNumeric, SetProperty),
63 DECLARE_NAPI_GETTER_SETTER("caseFirst", GetCaseFirst, SetProperty),
64 DECLARE_NAPI_FUNCTION("toString", ToString),
65 DECLARE_NAPI_FUNCTION("minimize", Minimize),
66 DECLARE_NAPI_FUNCTION("maximize", Maximize),
67 };
68 napi_value constructor = nullptr;
69 napi_status status = napi_define_class(env, "Locale", NAPI_AUTO_LENGTH, LocaleConstructor, nullptr,
70 sizeof(properties) / sizeof(napi_property_descriptor), properties, &constructor);
71 if (status != napi_ok) {
72 HILOG_ERROR_I18N("Define class failed when InitLocale");
73 return nullptr;
74 }
75 status = napi_set_named_property(env, exports, "Locale", constructor);
76 if (status != napi_ok) {
77 HILOG_ERROR_I18N("Set property failed when InitLocale");
78 return nullptr;
79 }
80 g_constructor = new (std::nothrow) napi_ref;
81 if (!g_constructor) {
82 HILOG_ERROR_I18N("Failed to create ref at init");
83 return nullptr;
84 }
85 status = napi_create_reference(env, constructor, 1, g_constructor);
86 if (status != napi_ok) {
87 HILOG_ERROR_I18N("Failed to create reference at init");
88 return nullptr;
89 }
90 return exports;
91 }
92
LocaleConstructor(napi_env env,napi_callback_info info)93 napi_value LocaleInfoAddon::LocaleConstructor(napi_env env, napi_callback_info info)
94 {
95 size_t argc = 2;
96 napi_value argv[2] = { nullptr };
97 napi_value thisVar = nullptr;
98 void *data = nullptr;
99 napi_status status = napi_get_cb_info(env, info, &argc, argv, &thisVar, &data);
100 if (status != napi_ok) {
101 return nullptr;
102 }
103 std::string localeTag;
104 if (argc > 0) {
105 int32_t code = 0;
106 localeTag = JSUtils::GetString(env, argv[0], code);
107 if (code != 0) {
108 return nullptr;
109 }
110 }
111 std::map<std::string, std::string> map = {};
112 if (argc > 1) {
113 JSUtils::GetOptionValue(env, argv[1], "calendar", map);
114 JSUtils::GetOptionValue(env, argv[1], "collation", map);
115 JSUtils::GetOptionValue(env, argv[1], "hourCycle", map);
116 JSUtils::GetOptionValue(env, argv[1], "numberingSystem", map);
117 JSUtils::GetBoolOptionValue(env, argv[1], "numeric", map);
118 JSUtils::GetOptionValue(env, argv[1], "caseFirst", map);
119 }
120 std::unique_ptr<LocaleInfoAddon> obj = std::make_unique<LocaleInfoAddon>();
121 if (obj == nullptr) {
122 return nullptr;
123 }
124 status =
125 napi_wrap(env, thisVar, reinterpret_cast<void *>(obj.get()), LocaleInfoAddon::Destructor, nullptr, nullptr);
126 if (status != napi_ok) {
127 HILOG_ERROR_I18N("LocaleConstructor: Wrap LocaleInfoAddon failed");
128 return nullptr;
129 }
130 if (!obj->InitLocaleContext(env, info, localeTag, map)) {
131 return nullptr;
132 }
133 obj.release();
134 return thisVar;
135 }
136
InitLocaleContext(napi_env env,napi_callback_info info,const std::string localeTag,std::map<std::string,std::string> & map)137 bool LocaleInfoAddon::InitLocaleContext(napi_env env, napi_callback_info info, const std::string localeTag,
138 std::map<std::string, std::string> &map)
139 {
140 napi_value global = nullptr;
141 napi_status status = napi_get_global(env, &global);
142 if (status != napi_ok) {
143 HILOG_ERROR_I18N("InitLocaleContext: Get global failed");
144 return false;
145 }
146 env_ = env;
147 locale_ = std::make_unique<LocaleInfo>(localeTag, map);
148 return locale_ != nullptr;
149 }
150
IsLocaleInfo(napi_env env,napi_value argv)151 bool LocaleInfoAddon::IsLocaleInfo(napi_env env, napi_value argv)
152 {
153 napi_value constructor = nullptr;
154 if (g_constructor == nullptr) {
155 HILOG_ERROR_I18N("LocaleInfoAddon::IsLocaleInfo: g_constructor is nullptr.");
156 return false;
157 }
158
159 napi_status status = napi_get_reference_value(env, *g_constructor, &constructor);
160 if (status != napi_ok || constructor == nullptr) {
161 HILOG_ERROR_I18N("LocaleInfoAddon::IsLocaleInfo: Failed to create reference.");
162 return false;
163 }
164
165 bool isLocaleInfo = false;
166 status = napi_instanceof(env, argv, constructor, &isLocaleInfo);
167 if (status != napi_ok) {
168 HILOG_ERROR_I18N("LocaleInfoAddon::IsLocaleInfo: Failed to get instance of argv.");
169 return false;
170 }
171 return isLocaleInfo;
172 }
173
GetLanguageInner(std::shared_ptr<LocaleInfo> localeInfo)174 std::string LocaleInfoAddon::GetLanguageInner(std::shared_ptr<LocaleInfo> localeInfo)
175 {
176 if (localeInfo != nullptr) {
177 return localeInfo->GetLanguage();
178 }
179 return "";
180 }
181
GetScriptInner(std::shared_ptr<LocaleInfo> localeInfo)182 std::string LocaleInfoAddon::GetScriptInner(std::shared_ptr<LocaleInfo> localeInfo)
183 {
184 if (localeInfo != nullptr) {
185 return localeInfo->GetScript();
186 }
187 return "";
188 }
189
GetRegionInner(std::shared_ptr<LocaleInfo> localeInfo)190 std::string LocaleInfoAddon::GetRegionInner(std::shared_ptr<LocaleInfo> localeInfo)
191 {
192 if (localeInfo != nullptr) {
193 return localeInfo->GetRegion();
194 }
195 return "";
196 }
197
GetBaseNameInner(std::shared_ptr<LocaleInfo> localeInfo)198 std::string LocaleInfoAddon::GetBaseNameInner(std::shared_ptr<LocaleInfo> localeInfo)
199 {
200 if (localeInfo != nullptr) {
201 return localeInfo->GetBaseName();
202 }
203 return "";
204 }
205
GetCalendarInner(std::shared_ptr<LocaleInfo> localeInfo)206 std::string LocaleInfoAddon::GetCalendarInner(std::shared_ptr<LocaleInfo> localeInfo)
207 {
208 if (localeInfo != nullptr) {
209 return localeInfo->GetCalendar();
210 }
211 return "";
212 }
213
GetCollationInner(std::shared_ptr<LocaleInfo> localeInfo)214 std::string LocaleInfoAddon::GetCollationInner(std::shared_ptr<LocaleInfo> localeInfo)
215 {
216 if (localeInfo != nullptr) {
217 return localeInfo->GetCollation();
218 }
219 return "";
220 }
221
GetHourCycleInner(std::shared_ptr<LocaleInfo> localeInfo)222 std::string LocaleInfoAddon::GetHourCycleInner(std::shared_ptr<LocaleInfo> localeInfo)
223 {
224 if (localeInfo != nullptr) {
225 return localeInfo->GetHourCycle();
226 }
227 return "";
228 }
229
GetNumberingSystemInner(std::shared_ptr<LocaleInfo> localeInfo)230 std::string LocaleInfoAddon::GetNumberingSystemInner(std::shared_ptr<LocaleInfo> localeInfo)
231 {
232 if (localeInfo != nullptr) {
233 return localeInfo->GetNumberingSystem();
234 }
235 return "";
236 }
237
GetCaseFirstInner(std::shared_ptr<LocaleInfo> localeInfo)238 std::string LocaleInfoAddon::GetCaseFirstInner(std::shared_ptr<LocaleInfo> localeInfo)
239 {
240 if (localeInfo != nullptr) {
241 return localeInfo->GetCaseFirst();
242 }
243 return "";
244 }
245
ToStringInner(std::shared_ptr<LocaleInfo> localeInfo)246 std::string LocaleInfoAddon::ToStringInner(std::shared_ptr<LocaleInfo> localeInfo)
247 {
248 if (localeInfo != nullptr) {
249 return localeInfo->ToString();
250 }
251 return "";
252 }
253
MaximizeInner(std::shared_ptr<LocaleInfo> localeInfo)254 std::string LocaleInfoAddon::MaximizeInner(std::shared_ptr<LocaleInfo> localeInfo)
255 {
256 if (localeInfo != nullptr) {
257 return localeInfo->Maximize();
258 }
259 return "";
260 }
261
MinimizeInner(std::shared_ptr<LocaleInfo> localeInfo)262 std::string LocaleInfoAddon::MinimizeInner(std::shared_ptr<LocaleInfo> localeInfo)
263 {
264 if (localeInfo != nullptr) {
265 return localeInfo->Minimize();
266 }
267 return "";
268 }
269
GetLocaleInfoAttribute(napi_env env,napi_callback_info info,GetLocaleInfoProperty func)270 napi_value LocaleInfoAddon::GetLocaleInfoAttribute(napi_env env, napi_callback_info info,
271 GetLocaleInfoProperty func)
272 {
273 napi_value thisVar = nullptr;
274 void *data = nullptr;
275 napi_status status = napi_get_cb_info(env, info, nullptr, nullptr, &thisVar, &data);
276 if (status != napi_ok) {
277 return nullptr;
278 }
279 LocaleInfoAddon *obj = nullptr;
280 status = napi_unwrap(env, thisVar, reinterpret_cast<void **>(&obj));
281 if (status != napi_ok || !obj || !obj->locale_) {
282 HILOG_ERROR_I18N("GetLocaleInfoAttribute: Get Locale object failed");
283 return nullptr;
284 }
285 std::string value = func(obj->locale_);
286 napi_value result = nullptr;
287 status = napi_create_string_utf8(env, value.c_str(), NAPI_AUTO_LENGTH, &result);
288 if (status != napi_ok) {
289 HILOG_ERROR_I18N("GetLocaleInfoAttribute: Create attribute string failed");
290 return nullptr;
291 }
292 return result;
293 }
294
GetLanguage(napi_env env,napi_callback_info info)295 napi_value LocaleInfoAddon::GetLanguage(napi_env env, napi_callback_info info)
296 {
297 return GetLocaleInfoAttribute(env, info, GetLanguageInner);
298 }
299
GetScript(napi_env env,napi_callback_info info)300 napi_value LocaleInfoAddon::GetScript(napi_env env, napi_callback_info info)
301 {
302 return GetLocaleInfoAttribute(env, info, GetScriptInner);
303 }
304
GetRegion(napi_env env,napi_callback_info info)305 napi_value LocaleInfoAddon::GetRegion(napi_env env, napi_callback_info info)
306 {
307 return GetLocaleInfoAttribute(env, info, GetRegionInner);
308 }
309
GetBaseName(napi_env env,napi_callback_info info)310 napi_value LocaleInfoAddon::GetBaseName(napi_env env, napi_callback_info info)
311 {
312 return GetLocaleInfoAttribute(env, info, GetBaseNameInner);
313 }
314
GetCalendar(napi_env env,napi_callback_info info)315 napi_value LocaleInfoAddon::GetCalendar(napi_env env, napi_callback_info info)
316 {
317 return GetLocaleInfoAttribute(env, info, GetCalendarInner);
318 }
319
GetCollation(napi_env env,napi_callback_info info)320 napi_value LocaleInfoAddon::GetCollation(napi_env env, napi_callback_info info)
321 {
322 return GetLocaleInfoAttribute(env, info, GetCollationInner);
323 }
324
GetHourCycle(napi_env env,napi_callback_info info)325 napi_value LocaleInfoAddon::GetHourCycle(napi_env env, napi_callback_info info)
326 {
327 return GetLocaleInfoAttribute(env, info, GetHourCycleInner);
328 }
329
GetNumberingSystem(napi_env env,napi_callback_info info)330 napi_value LocaleInfoAddon::GetNumberingSystem(napi_env env, napi_callback_info info)
331 {
332 return GetLocaleInfoAttribute(env, info, GetNumberingSystemInner);
333 }
334
GetNumeric(napi_env env,napi_callback_info info)335 napi_value LocaleInfoAddon::GetNumeric(napi_env env, napi_callback_info info)
336 {
337 napi_value thisVar = nullptr;
338 void *data = nullptr;
339 napi_status status = napi_get_cb_info(env, info, nullptr, nullptr, &thisVar, &data);
340 if (status != napi_ok) {
341 return nullptr;
342 }
343 LocaleInfoAddon *obj = nullptr;
344 status = napi_unwrap(env, thisVar, reinterpret_cast<void **>(&obj));
345 if (status != napi_ok || !obj || !obj->locale_) {
346 HILOG_ERROR_I18N("GetNumeric: Get Locale object failed");
347 return nullptr;
348 }
349 std::string value = obj->locale_->GetNumeric();
350 bool optionBoolValue = (value == "true");
351 napi_value result = nullptr;
352 status = napi_get_boolean(env, optionBoolValue, &result);
353 if (status != napi_ok) {
354 HILOG_ERROR_I18N("Create numeric boolean value failed");
355 return nullptr;
356 }
357 return result;
358 }
359
GetCaseFirst(napi_env env,napi_callback_info info)360 napi_value LocaleInfoAddon::GetCaseFirst(napi_env env, napi_callback_info info)
361 {
362 return GetLocaleInfoAttribute(env, info, GetCaseFirstInner);
363 }
364
ToString(napi_env env,napi_callback_info info)365 napi_value LocaleInfoAddon::ToString(napi_env env, napi_callback_info info)
366 {
367 return GetLocaleInfoAttribute(env, info, ToStringInner);
368 }
369
GetMaximizeOrMinimize(napi_env env,napi_callback_info info,GetLocaleInfoProperty func)370 napi_value LocaleInfoAddon::GetMaximizeOrMinimize(napi_env env, napi_callback_info info,
371 GetLocaleInfoProperty func)
372 {
373 napi_value thisVar = nullptr;
374 void *data = nullptr;
375 napi_status status = napi_get_cb_info(env, info, nullptr, nullptr, &thisVar, &data);
376 if (status != napi_ok) {
377 return nullptr;
378 }
379 LocaleInfoAddon *obj = nullptr;
380 status = napi_unwrap(env, thisVar, reinterpret_cast<void **>(&obj));
381 if (status != napi_ok || !obj || !obj->locale_) {
382 HILOG_ERROR_I18N("Maximize: Get Locale object failed");
383 return nullptr;
384 }
385 std::string localeTag = func(obj->locale_);
386
387 napi_value constructor = nullptr;
388 if (g_constructor == nullptr) {
389 HILOG_ERROR_I18N("Maximize: g_constructor is nullptr.");
390 return nullptr;
391 }
392 status = napi_get_reference_value(env, *g_constructor, &constructor);
393 if (status != napi_ok) {
394 HILOG_ERROR_I18N("Maximize: Get locale constructor reference failed");
395 return nullptr;
396 }
397 napi_value result = nullptr;
398 napi_value arg = nullptr;
399 status = napi_create_string_utf8(env, localeTag.c_str(), NAPI_AUTO_LENGTH, &arg);
400 if (status != napi_ok) {
401 HILOG_ERROR_I18N("Maximize: Create localeTag string failed");
402 return nullptr;
403 }
404 status = napi_new_instance(env, constructor, 1, &arg, &result);
405 if (status != napi_ok) {
406 HILOG_ERROR_I18N("Maximize: Create new locale instance failed");
407 return nullptr;
408 }
409 return result;
410 }
411
Maximize(napi_env env,napi_callback_info info)412 napi_value LocaleInfoAddon::Maximize(napi_env env, napi_callback_info info)
413 {
414 return GetMaximizeOrMinimize(env, info, MaximizeInner);
415 }
416
Minimize(napi_env env,napi_callback_info info)417 napi_value LocaleInfoAddon::Minimize(napi_env env, napi_callback_info info)
418 {
419 return GetMaximizeOrMinimize(env, info, MinimizeInner);
420 }
421
GetLocaleInfo()422 std::shared_ptr<LocaleInfo> LocaleInfoAddon::GetLocaleInfo()
423 {
424 if (!this->locale_) {
425 return nullptr;
426 }
427 return this->locale_;
428 }
429 } // namespace I18n
430 } // namespace Global
431 } // namespace OHOS