1 /*
2  * Copyright (c) 2023 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 "error_util.h"
17 #include "i18n_hilog.h"
18 #include "locale_config.h"
19 #include "utils.h"
20 #include "variable_convertor.h"
21 #include "system_locale_manager_addon.h"
22 
23 namespace OHOS {
24 namespace Global {
25 namespace I18n {
SystemLocaleManagerAddon()26 SystemLocaleManagerAddon::SystemLocaleManagerAddon() : env_(nullptr) {}
27 
~SystemLocaleManagerAddon()28 SystemLocaleManagerAddon::~SystemLocaleManagerAddon()
29 {
30 }
31 
Destructor(napi_env env,void * nativeObject,void * hint)32 void SystemLocaleManagerAddon::Destructor(napi_env env, void *nativeObject, void *hint)
33 {
34     if (!nativeObject) {
35         return;
36     }
37     delete reinterpret_cast<SystemLocaleManagerAddon *>(nativeObject);
38     nativeObject = nullptr;
39 }
40 
InitSystemLocaleManager(napi_env env,napi_value exports)41 napi_value SystemLocaleManagerAddon::InitSystemLocaleManager(napi_env env, napi_value exports)
42 {
43     napi_status status = napi_ok;
44     napi_property_descriptor properties[] = {
45         DECLARE_NAPI_FUNCTION("getLanguageInfoArray", GetLanguageInfoArray),
46         DECLARE_NAPI_FUNCTION("getRegionInfoArray", GetCountryInfoArray),
47         DECLARE_NAPI_STATIC_FUNCTION("getTimeZoneCityItemArray", GetTimeZoneCityInfoArray)
48     };
49 
50     napi_value constructor = nullptr;
51     status = napi_define_class(env, "SystemLocaleManager", NAPI_AUTO_LENGTH, SystemLocaleManagerConstructor, nullptr,
52         sizeof(properties) / sizeof(napi_property_descriptor), properties, &constructor);
53     if (status != napi_ok) {
54         HILOG_ERROR_I18N("Define class failed when InitSystemLocaleManager");
55         return nullptr;
56     }
57 
58     status = napi_set_named_property(env, exports, "SystemLocaleManager", constructor);
59     if (status != napi_ok) {
60         HILOG_ERROR_I18N("Set property failed when InitSystemLocaleManager");
61         return nullptr;
62     }
63     return exports;
64 }
65 
SystemLocaleManagerConstructor(napi_env env,napi_callback_info info)66 napi_value SystemLocaleManagerAddon::SystemLocaleManagerConstructor(napi_env env, napi_callback_info info)
67 {
68     if (!CheckSystemPermission()) {
69         HILOG_ERROR_I18N("Permission verification failed. A non-system application calls a system API.");
70         return nullptr;
71     }
72     napi_value thisVar = nullptr;
73     void *data = nullptr;
74     napi_status status = napi_get_cb_info(env, info, nullptr, nullptr, &thisVar, &data);
75     if (status != napi_ok) {
76         return nullptr;
77     }
78     std::unique_ptr<SystemLocaleManagerAddon> obj = std::make_unique<SystemLocaleManagerAddon>();
79     status = napi_wrap(env, thisVar, reinterpret_cast<void *>(obj.get()), SystemLocaleManagerAddon::Destructor,
80         nullptr, nullptr);
81     if (status != napi_ok) {
82         HILOG_ERROR_I18N("Wrap SystemLocaleManagerAddon failed");
83         return nullptr;
84     }
85     if (!obj->InitSystemLocaleManagerContext(env, info)) {
86         HILOG_ERROR_I18N("Init SystemLocaleManager failed");
87         return nullptr;
88     }
89     obj.release();
90     return thisVar;
91 }
92 
InitSystemLocaleManagerContext(napi_env env,napi_callback_info info)93 bool SystemLocaleManagerAddon::InitSystemLocaleManagerContext(napi_env env, napi_callback_info info)
94 {
95     napi_value global = nullptr;
96     napi_status status = napi_get_global(env, &global);
97     if (status != napi_ok) {
98         HILOG_ERROR_I18N("Get global failed");
99         return false;
100     }
101     env_ = env;
102     systemLocaleManager_ = std::make_unique<SystemLocaleManager>();
103 
104     return systemLocaleManager_ != nullptr;
105 }
106 
GetLanguageInfoArray(napi_env env,napi_callback_info info)107 napi_value SystemLocaleManagerAddon::GetLanguageInfoArray(napi_env env, napi_callback_info info)
108 {
109     size_t argc = 2;
110     napi_value argv[2] = { 0 };
111     napi_value thisVar = nullptr;
112     void *data = nullptr;
113     napi_status status = napi_get_cb_info(env, info, &argc, argv, &thisVar, &data);
114     if (status != napi_ok) {
115         HILOG_ERROR_I18N("can not obtain getLanguageInfoArray function param.");
116         return nullptr;
117     }
118     if (argc < 1) {
119         ErrorUtil::NapiThrow(env, I18N_NOT_FOUND, "languages", "", true);
120         return nullptr;
121     }
122     std::vector<std::string> languageList;
123     bool isSuccess = VariableConvertor::GetStringArrayFromJsParam(env, argv[0], "languages", languageList);
124     if (!isSuccess) {
125         return nullptr;
126     }
127     SortOptions options;
128     GetSortOptionsFromJsParam(env, argv[1], options, false);
129     SystemLocaleManagerAddon *obj = nullptr;
130     status = napi_unwrap(env, thisVar, reinterpret_cast<void **>(&obj));
131     if (status != napi_ok || !obj || !obj->systemLocaleManager_) {
132         HILOG_ERROR_I18N("GetLanguageInfoArray: Get SystemLocaleManager object failed");
133         return nullptr;
134     }
135     I18nErrorCode err;
136     std::vector<LocaleItem> localeItemList =
137         obj->systemLocaleManager_->GetLanguageInfoArray(languageList, options, err);
138     if (err == I18nErrorCode::NOT_SYSTEM_APP) {
139         ErrorUtil::NapiThrow(env, I18N_NOT_SYSTEM_APP, "", "", true);
140         return nullptr;
141     }
142     napi_value result = CreateLocaleItemArray(env, localeItemList);
143     return result;
144 }
145 
GetCountryInfoArray(napi_env env,napi_callback_info info)146 napi_value SystemLocaleManagerAddon::GetCountryInfoArray(napi_env env, napi_callback_info info)
147 {
148     size_t argc = 2;
149     napi_value argv[2] = { 0 };
150     napi_value thisVar = nullptr;
151     void *data = nullptr;
152     napi_status status = napi_get_cb_info(env, info, &argc, argv, &thisVar, &data);
153     if (status != napi_ok) {
154         HILOG_ERROR_I18N("can not obtain getCountryInfoArray function param.");
155         return nullptr;
156     }
157     if (argc < 1) {
158         ErrorUtil::NapiThrow(env, I18N_NOT_FOUND, "regions", "", true);
159         return nullptr;
160     }
161     std::vector<std::string> countryList;
162     bool isSuccess = VariableConvertor::GetStringArrayFromJsParam(env, argv[0], "regions", countryList);
163     if (!isSuccess) {
164         return nullptr;
165     }
166     SortOptions options;
167     GetSortOptionsFromJsParam(env, argv[1], options, true);
168     SystemLocaleManagerAddon *obj = nullptr;
169     status = napi_unwrap(env, thisVar, reinterpret_cast<void **>(&obj));
170     if (status != napi_ok || !obj || !obj->systemLocaleManager_) {
171         HILOG_ERROR_I18N("GetCountryInfoArray: Get SystemLocaleManager object failed");
172         return nullptr;
173     }
174     I18nErrorCode err;
175     std::vector<LocaleItem> localeItemList = obj->systemLocaleManager_->GetCountryInfoArray(countryList, options, err);
176     if (err == I18nErrorCode::NOT_SYSTEM_APP) {
177         ErrorUtil::NapiThrow(env, I18N_NOT_SYSTEM_APP, "", "", true);
178         return nullptr;
179     }
180     napi_value result = CreateLocaleItemArray(env, localeItemList);
181     return result;
182 }
183 
GetTimeZoneCityInfoArray(napi_env env,napi_callback_info info)184 napi_value SystemLocaleManagerAddon::GetTimeZoneCityInfoArray(napi_env env, napi_callback_info info)
185 {
186     I18nErrorCode err;
187     std::vector<TimeZoneCityItem> timezoneCityItemList = SystemLocaleManager::GetTimezoneCityInfoArray(err);
188     if (err == I18nErrorCode::NOT_SYSTEM_APP) {
189         ErrorUtil::NapiThrow(env, I18N_NOT_SYSTEM_APP, "", "", true);
190         return nullptr;
191     }
192     napi_value result = nullptr;
193     napi_status status = napi_create_array_with_length(env, timezoneCityItemList.size(), &result);
194     if (status != napi_ok) {
195         HILOG_ERROR_I18N("create TimeZoneCityItem array failed.");
196         return nullptr;
197     }
198     for (size_t i = 0; i < timezoneCityItemList.size(); ++i) {
199         napi_value item = CreateTimeZoneCityItem(env, timezoneCityItemList[i]);
200         status = napi_set_element(env, result, i, item);
201         if (status != napi_ok) {
202             HILOG_ERROR_I18N("Failed to set TimeZoneCityItem element.");
203             return nullptr;
204         }
205     }
206     return result;
207 }
208 
CreateTimeZoneCityItem(napi_env env,const TimeZoneCityItem & timezoneCityItem)209 napi_value SystemLocaleManagerAddon::CreateTimeZoneCityItem(napi_env env, const TimeZoneCityItem &timezoneCityItem)
210 {
211     napi_value result;
212     napi_status status = napi_create_object(env, &result);
213     if (status != napi_ok) {
214         HILOG_ERROR_I18N("CreateTimeZoneCityItem: Create Locale Item object failed.");
215         return nullptr;
216     }
217     status = napi_set_named_property(env, result, "zoneId",
218         VariableConvertor::CreateString(env, timezoneCityItem.zoneId));
219     if (status != napi_ok) {
220         HILOG_ERROR_I18N("Failed to set element zoneId.");
221         return nullptr;
222     }
223     status = napi_set_named_property(env, result, "cityId",
224         VariableConvertor::CreateString(env, timezoneCityItem.cityId));
225     if (status != napi_ok) {
226         HILOG_ERROR_I18N("Failed to set element cityId.");
227         return nullptr;
228     }
229     status = napi_set_named_property(env, result, "cityDisplayName",
230         VariableConvertor::CreateString(env, timezoneCityItem.cityDisplayName));
231     if (status != napi_ok) {
232         HILOG_ERROR_I18N("Failed to set element cityDisplayName.");
233         return nullptr;
234     }
235     status = napi_set_named_property(env, result, "offset",
236         VariableConvertor::CreateNumber(env, timezoneCityItem.offset));
237     if (status != napi_ok) {
238         HILOG_ERROR_I18N("Failed to set element offset.");
239         return nullptr;
240     }
241     status = napi_set_named_property(env, result, "zoneDisplayName",
242         VariableConvertor::CreateString(env, timezoneCityItem.zoneDisplayName));
243     if (status != napi_ok) {
244         HILOG_ERROR_I18N("Failed to set element zoneDisplayName.");
245         return nullptr;
246     }
247     if (timezoneCityItem.rawOffset != 0) {
248         status = napi_set_named_property(env, result, "rawOffset",
249             VariableConvertor::CreateNumber(env, timezoneCityItem.rawOffset));
250         if (status != napi_ok) {
251             HILOG_ERROR_I18N("Failed to set element rawOffset.");
252             return nullptr;
253         }
254     }
255     return result;
256 }
257 
GetSortOptionsFromJsParam(napi_env env,napi_value & jsOptions,SortOptions & options,bool isRegion)258 void SystemLocaleManagerAddon::GetSortOptionsFromJsParam(napi_env env, napi_value &jsOptions, SortOptions &options,
259     bool isRegion)
260 {
261     std::string localeTag;
262     bool isUseLocalName = true;
263     bool isSuggestedFirst = true;
264     if (jsOptions == nullptr) {
265         localeTag = LocaleConfig::GetSystemLocale();
266         if (isRegion) {
267             isUseLocalName = false;
268         }
269     } else {
270         VariableConvertor::GetOptionValue(env, jsOptions, "locale", localeTag);
271         if (localeTag.length() == 0) {
272             localeTag = LocaleConfig::GetSystemLocale();
273         }
274         bool isSuccess = VariableConvertor::GetBoolOptionValue(env, jsOptions, "isUseLocalName", isUseLocalName);
275         if (!isSuccess && isRegion) {
276             isUseLocalName = false;
277         }
278         VariableConvertor::GetBoolOptionValue(env, jsOptions, "isSuggestedFirst", isSuggestedFirst);
279     }
280     options.localeTag = localeTag;
281     options.isUseLocalName = isUseLocalName;
282     options.isSuggestedFirst = isSuggestedFirst;
283 }
284 
CreateLocaleItemArray(napi_env env,const std::vector<LocaleItem> & localeItemList)285 napi_value SystemLocaleManagerAddon::CreateLocaleItemArray(napi_env env, const std::vector<LocaleItem> &localeItemList)
286 {
287     napi_value result = nullptr;
288     napi_status status = napi_create_array_with_length(env, localeItemList.size(), &result);
289     if (status != napi_ok) {
290         HILOG_ERROR_I18N("create LocaleItem array failed.");
291         return nullptr;
292     }
293     for (size_t i = 0; i < localeItemList.size(); ++i) {
294         napi_value item = CreateLocaleItem(env, localeItemList[i]);
295         status = napi_set_element(env, result, i, item);
296         if (status != napi_ok) {
297             HILOG_ERROR_I18N("Failed to set LocaleItem element.");
298             return nullptr;
299         }
300     }
301     return result;
302 }
303 
CreateLocaleItem(napi_env env,const LocaleItem & localeItem)304 napi_value SystemLocaleManagerAddon::CreateLocaleItem(napi_env env, const LocaleItem &localeItem)
305 {
306     napi_value result;
307     napi_status status = napi_create_object(env, &result);
308     if (status != napi_ok) {
309         HILOG_ERROR_I18N("CreateLocaleItem: Create Locale Item object failed.");
310         return nullptr;
311     }
312     status = napi_set_named_property(env, result, "id", VariableConvertor::CreateString(env, localeItem.id));
313     if (status != napi_ok) {
314         HILOG_ERROR_I18N("Failed to set element id.");
315         return nullptr;
316     }
317     status = napi_set_named_property(env, result, "displayName",
318         VariableConvertor::CreateString(env, localeItem.displayName));
319     if (status != napi_ok) {
320         HILOG_ERROR_I18N("Failed to set element displayName.");
321         return nullptr;
322     }
323     if (localeItem.localName.length() != 0) {
324         status = napi_set_named_property(env, result, "localName",
325             VariableConvertor::CreateString(env, localeItem.localName));
326         if (status != napi_ok) {
327             HILOG_ERROR_I18N("Failed to set element localName.");
328             return nullptr;
329         }
330     }
331     status = napi_set_named_property(env, result, "suggestionType", CreateSuggestionType(env,
332         localeItem.suggestionType));
333     if (status != napi_ok) {
334         HILOG_ERROR_I18N("Failed to set element suggestionType.");
335         return nullptr;
336     }
337     return result;
338 }
339 
CreateSuggestionType(napi_env env,SuggestionType suggestionType)340 napi_value SystemLocaleManagerAddon::CreateSuggestionType(napi_env env, SuggestionType suggestionType)
341 {
342     napi_value result;
343     napi_status status = napi_create_int32(env, static_cast<int32_t>(suggestionType), &result);
344     if (status != napi_ok) {
345         HILOG_ERROR_I18N("create SuggestionType failed.");
346         return nullptr;
347     }
348     return result;
349 }
350 } // namespace I18n
351 } // namespace Global
352 } // namespace OHOS