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