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 #include <regex>
16 #include "accesstoken_kit.h"
17 #ifdef SUPPORT_GRAPHICS
18 #include "app_mgr_client.h"
19 #include "ability_manager_client.h"
20 #include <common_event_manager.h>
21 #include <common_event_publish_info.h>
22 #include <common_event_support.h>
23 #endif
24 #include <cctype>
25 #include "config_policy_utils.h"
26 #include "i18n_hilog.h"
27 #include "ipc_skeleton.h"
28 #include "libxml/parser.h"
29 #include "locale_info.h"
30 #include "multi_users.h"
31 #include "unicode/localebuilder.h"
32 #include "unicode/locdspnm.h"
33 #include "unicode/locid.h"
34 #include "unicode/smpdtfmt.h"
35 #include "ohos/init_data.h"
36 #include "parameter.h"
37 #include "securec.h"
38 #include "string_ex.h"
39 #include "ucase.h"
40 #include "ulocimp.h"
41 #include "unicode/unistr.h"
42 #include "ureslocs.h"
43 #include "unicode/ustring.h"
44 #include "ustr_imp.h"
45 #include "utils.h"
46 #include "tokenid_kit.h"
47 #include "locale_config.h"
48
49 namespace OHOS {
50 namespace Global {
51 namespace I18n {
52 using namespace std;
53 const char *LocaleConfig::LANGUAGE_KEY = "persist.global.language";
54 const char *LocaleConfig::LOCALE_KEY = "persist.global.locale";
55 const char *LocaleConfig::HOUR_KEY = "persist.global.is24Hour";
56 const char *LocaleConfig::DEFAULT_LOCALE_KEY = "const.global.locale";
57 const char *LocaleConfig::DEFAULT_LANGUAGE_KEY = "const.global.language";
58 const char *LocaleConfig::DEFAULT_REGION_KEY = "const.global.region";
59 const char *LocaleConfig::SIM_COUNTRY_CODE_KEY = "telephony.sim.countryCode0";
60 const char *LocaleConfig::SUPPORTED_LOCALES_NAME = "supported_locales";
61 const char *LocaleConfig::REGIONS_LANGUAGES_PATH = "etc/xml/i18n_param_config.xml";
62 const char *LocaleConfig::REGIONS_LANGUAGES_NAME = "i18n_param_config";
63 const char *LocaleConfig::SUPPORTED_REGIONS_NAME = "supported_regions";
64 const char *LocaleConfig::WHITE_LANGUAGES_NAME = "white_languages";
65 const char *LocaleConfig::FORBIDDEN_LANGUAGES_NAME = "forbidden_languages";
66 const char *LocaleConfig::FORBIDDEN_REGIONS_NAME = "forbidden_regions";
67 const char *LocaleConfig::SUPPORTED_LOCALES_PATH = "/system/usr/ohos_locale_config/supported_locales.xml";
68 const char *LocaleConfig::SUPPORT_LOCALES_PATH = "/etc/ohos_lang_config/supported_locales.xml";
69 const char *LocaleConfig::SUPPORT_LOCALES_NAME = "supported_locales";
70 const char *LocaleConfig::DIALECT_LANGS_PATH = "/system/usr/ohos_locale_config/dialect_languages.xml";
71 const char *LocaleConfig::DIALECT_LANGS_NAME = "dialect_langs";
72 const char *LocaleConfig::OVERRIDE_SUPPORTED_REGIONS_NAME = "supported_regions";
73 const char *LocaleConfig::OVERRIDE_SUPPORTED_REGIONS_PATH =
74 "/system/usr/ohos_locale_config/region/supported_regions.xml";
75 const char *LocaleConfig::DEFAULT_LOCALE = "en-Latn";
76 const char *LocaleConfig::supportLocalesTag = "supported_locales";
77 const char *LocaleConfig::LANG_PATH = "/etc/ohos_lang_config/";
78 const char *LocaleConfig::REGION_PATH = "/system/usr/ohos_locale_config/region/";
79 const char *LocaleConfig::rootTag = "languages";
80 const char *LocaleConfig::secondRootTag = "lang";
81 const char *LocaleConfig::rootRegion = "regions";
82 const char *LocaleConfig::secondRootRegion = "region";
83 const char *LocaleConfig::NUMBER_SYSTEM_KEY = "-nu-";
84 unordered_set<string> LocaleConfig::supportedLocales;
85 unordered_set<string> LocaleConfig::supportLocales;
86 unordered_set<string> LocaleConfig::supportedRegions;
87 unordered_set<string> LocaleConfig::overrideSupportedRegions;
88 unordered_set<string> LocaleConfig::dialectLang;
89 unordered_set<string> LocaleConfig::blockedLanguages;
90 unordered_set<string> LocaleConfig::blockedRegions;
91 unordered_map<string, unordered_set<string>> LocaleConfig::blockedLanguageRegions;
92 unordered_set<string> LocaleConfig::whiteLanguages;
93 std::set<std::string> LocaleConfig::extendWhiteLanguageList;
94 unordered_map<string, string> LocaleConfig::dialectMap {
95 { "es-Latn-419", "es-Latn-419" },
96 { "es-Latn-BO", "es-Latn-419" },
97 { "es-Latn-BR", "es-Latn-419" },
98 { "es-Latn-BZ", "es-Latn-419" },
99 { "es-Latn-CL", "es-Latn-419" },
100 { "es-Latn-CO", "es-Latn-419" },
101 { "es-Latn-CR", "es-Latn-419" },
102 { "es-Latn-CU", "es-Latn-419" },
103 { "es-Latn-DO", "es-Latn-419" },
104 { "es-Latn-EC", "es-Latn-419" },
105 { "es-Latn-GT", "es-Latn-419" },
106 { "es-Latn-HN", "es-Latn-419" },
107 { "es-Latn-MX", "es-Latn-419" },
108 { "es-Latn-NI", "es-Latn-419" },
109 { "es-Latn-PA", "es-Latn-419" },
110 { "es-Latn-PE", "es-Latn-419" },
111 { "es-Latn-PR", "es-Latn-419" },
112 { "es-Latn-PY", "es-Latn-419" },
113 { "es-Latn-SV", "es-Latn-419" },
114 { "es-Latn-US", "es-Latn-419" },
115 { "es-Latn-UY", "es-Latn-419" },
116 { "es-Latn-VE", "es-Latn-419" },
117 { "pt-Latn-PT", "pt-Latn-PT" },
118 { "en-Latn-US", "en-Latn-US" }
119 };
120
121 unordered_map<string, string> LocaleConfig::localDigitMap {
122 { "ar", "arab" },
123 { "as", "beng" },
124 { "bn", "beng" },
125 { "fa", "arabext" },
126 { "mr", "deva" },
127 { "my", "mymr" },
128 { "ne", "deva" },
129 { "ur", "latn" }
130 };
131
132 std::map<std::string, std::string> LocaleConfig::supportedDialectLocales;
133 std::map<string, string> LocaleConfig::locale2DisplayName {};
134 std::map<string, string> LocaleConfig::region2DisplayName {};
135 std::string LocaleConfig::currentDialectLocale = "";
136 std::string LocaleConfig::currentOverrideRegion = "";
137 std::mutex LocaleConfig::dialectLocaleMutex;
138 std::mutex LocaleConfig::region2DisplayNameMutex;
139 std::mutex LocaleConfig::locale2DisplayNameMutex;
140
141 set<std::string> LocaleConfig::validCaTag {
142 "buddhist",
143 "chinese",
144 "coptic",
145 "dangi",
146 "ethioaa",
147 "ethiopic",
148 "gregory",
149 "hebrew",
150 "indian",
151 "islamic",
152 "islamic-umalqura",
153 "islamic-tbla",
154 "islamic-civil",
155 "islamic-rgsa",
156 "iso8601",
157 "japanese",
158 "persian",
159 "roc",
160 "islamicc",
161 };
162 set<std::string> LocaleConfig::validCoTag {
163 "big5han",
164 "compat",
165 "dict",
166 "direct",
167 "ducet",
168 "eor",
169 "gb2312",
170 "phonebk",
171 "phonetic",
172 "pinyin",
173 "reformed",
174 "searchjl",
175 "stroke",
176 "trad",
177 "unihan",
178 "zhuyin",
179 };
180 set<std::string> LocaleConfig::validKnTag {
181 "true",
182 "false",
183 };
184 set<std::string> LocaleConfig::validKfTag {
185 "upper",
186 "lower",
187 "false",
188 };
189 set<std::string> LocaleConfig::validNuTag {
190 "adlm", "ahom", "arab", "arabext", "bali", "beng",
191 "bhks", "brah", "cakm", "cham", "deva", "diak",
192 "fullwide", "gong", "gonm", "gujr", "guru", "hanidec",
193 "hmng", "hmnp", "java", "kali", "khmr", "knda",
194 "lana", "lanatham", "laoo", "latn", "lepc", "limb",
195 "mathbold", "mathdbl", "mathmono", "mathsanb", "mathsans", "mlym",
196 "modi", "mong", "mroo", "mtei", "mymr", "mymrshan",
197 "mymrtlng", "newa", "nkoo", "olck", "orya", "osma",
198 "rohg", "saur", "segment", "shrd", "sind", "sinh",
199 "sora", "sund", "takr", "talu", "tamldec", "telu",
200 "thai", "tibt", "tirh", "vaii", "wara", "wcho",
201 };
202 set<std::string> LocaleConfig::validHcTag {
203 "h12",
204 "h23",
205 "h11",
206 "h24",
207 };
208
209 static unordered_map<string, string> g_languageMap = {
210 { "zh-Hans", "zh-Hans" },
211 { "zh-Hant-HK", "zh-Hant-HK" },
212 { "zh-Hant", "zh-Hant" },
213 { "my-Qaag", "my-Qaag" },
214 { "es-Latn-419", "es-419" },
215 { "es-Latn-US", "es-419" },
216 { "az-Latn", "az-Latn" },
217 { "bs-Latn", "bs-Latn" },
218 { "en-Latn-US", "en" },
219 { "en-Qaag", "en-Qaag" },
220 { "uz-Latn", "uz-Latn" },
221 { "sr-Latn", "sr-Latn" },
222 { "jv-Latn", "jv-Latn" },
223 { "pt-Latn-BR", "pt-BR" },
224 { "pa-Guru", "pa-Guru" },
225 { "mai-Deva", "mai-Deva" }
226 };
227
Adjust(const string &origin)228 string Adjust(const string &origin)
229 {
230 auto iter = g_languageMap.find(origin);
231 if (iter != g_languageMap.end()) {
232 return iter->second;
233 }
234 for (iter = g_languageMap.begin(); iter != g_languageMap.end(); ++iter) {
235 string key = iter->first;
236 if (!origin.compare(0, key.length(), key)) {
237 return iter->second;
238 }
239 }
240 return origin;
241 }
242
GetDisplayLanguageInner(const string &language, const string &displayLocaleTag, bool sentenceCase)243 string GetDisplayLanguageInner(const string &language, const string &displayLocaleTag, bool sentenceCase)
244 {
245 icu::UnicodeString unistr;
246 // 0 is the start position of language, 2 is the length of zh and fa
247 if (!language.compare(0, 2, "zh") || !language.compare(0, 2, "fa") || !language.compare(0, 2, "ro")) {
248 UErrorCode status = U_ZERO_ERROR;
249 icu::Locale displayLocale = icu::Locale::forLanguageTag(displayLocaleTag.c_str(), status);
250 if (U_FAILURE(status)) {
251 return "";
252 }
253 icu::LocaleDisplayNames *dspNames = icu::LocaleDisplayNames::createInstance(displayLocale,
254 UDialectHandling::ULDN_DIALECT_NAMES);
255 icu::Locale tempLocale = icu::Locale::forLanguageTag(language.c_str(), status);
256 if (U_FAILURE(status)) {
257 return "";
258 }
259 if (dspNames != nullptr) {
260 dspNames->localeDisplayName(tempLocale, unistr);
261 delete dspNames;
262 }
263 } else {
264 UErrorCode status = U_ZERO_ERROR;
265 icu::Locale displayLoc = icu::Locale::forLanguageTag(displayLocaleTag, status);
266 if (U_FAILURE(status)) {
267 return "";
268 }
269 icu::Locale locale = icu::Locale::forLanguageTag(language, status);
270 if (U_FAILURE(status)) {
271 return "";
272 }
273 locale.getDisplayName(displayLoc, unistr);
274 }
275 if (sentenceCase) {
276 UChar32 ch = ucase_toupper(unistr.char32At(0));
277 unistr.replace(0, 1, ch);
278 }
279 string out;
280 unistr.toUTF8String(out);
281 return out;
282 }
283
284 bool LocaleConfig::listsInitialized = LocaleConfig::InitializeLists();
285
GetSystemLanguage()286 string LocaleConfig::GetSystemLanguage()
287 {
288 std::string systemLanguage = ReadSystemParameter(LANGUAGE_KEY, CONFIG_LEN);
289 if (systemLanguage.empty()) {
290 systemLanguage = ReadSystemParameter(DEFAULT_LANGUAGE_KEY, CONFIG_LEN);
291 }
292 return systemLanguage;
293 }
294
GetSystemRegion()295 string LocaleConfig::GetSystemRegion()
296 {
297 std::string systemRegion = GetCountry(LOCALE_KEY);
298 if (systemRegion.empty()) {
299 systemRegion = GetCountry(DEFAULT_LOCALE_KEY);
300 }
301 if (systemRegion.empty()) {
302 return "CN";
303 }
304 return systemRegion;
305 }
306
GetCountry(const string& parameter)307 string LocaleConfig::GetCountry(const string& parameter)
308 {
309 std::string systemRegion = ReadSystemParameter(parameter.c_str(), CONFIG_LEN);
310 if (systemRegion.empty()) {
311 HILOG_INFO_I18N("GetCountry: ReadSystemParameter %{public}s failed", parameter.c_str());
312 return systemRegion;
313 }
314 UErrorCode status = U_ZERO_ERROR;
315 icu::Locale origin = icu::Locale::forLanguageTag(systemRegion, status);
316 if (U_SUCCESS(status)) {
317 const char* country = origin.getCountry();
318 if (country != nullptr) {
319 return country;
320 }
321 HILOG_INFO_I18N("GetCountry: %{public}s get failed, country is nullptr", parameter.c_str());
322 } else {
323 HILOG_INFO_I18N("GetCountry: %{public}s get failed, U_SUCCESS is false", parameter.c_str());
324 }
325 return "";
326 }
327
GetSystemLocale()328 string LocaleConfig::GetSystemLocale()
329 {
330 std::string systemLocale = ReadSystemParameter(LOCALE_KEY, CONFIG_LEN);
331 if (systemLocale.empty()) {
332 systemLocale = ReadSystemParameter(DEFAULT_LOCALE_KEY, CONFIG_LEN);
333 }
334 return systemLocale;
335 }
336
IsValidLanguage(const string &language)337 bool LocaleConfig::IsValidLanguage(const string &language)
338 {
339 string::size_type size = language.size();
340 if ((size != LANGUAGE_LEN) && (size != LANGUAGE_LEN + 1)) {
341 return false;
342 }
343 for (size_t i = 0; i < size; ++i) {
344 if ((language[i] > 'z') || (language[i] < 'a')) {
345 return false;
346 }
347 }
348 return true;
349 }
350
IsValidRegion(const string ®ion)351 bool LocaleConfig::IsValidRegion(const string ®ion)
352 {
353 string::size_type size = region.size();
354 if (size != LocaleInfo::REGION_LEN) {
355 return false;
356 }
357 for (size_t i = 0; i < LocaleInfo::REGION_LEN; ++i) {
358 if ((region[i] > 'Z') || (region[i] < 'A')) {
359 return false;
360 }
361 }
362 return true;
363 }
364
IsValidTag(const string &tag)365 bool LocaleConfig::IsValidTag(const string &tag)
366 {
367 if (!tag.size()) {
368 return false;
369 }
370 vector<string> splits;
371 Split(tag, "-", splits);
372 if (!IsValidLanguage(splits[0])) {
373 return false;
374 }
375 return true;
376 }
377
Split(const string &src, const string &sep, vector<string> &dest)378 void LocaleConfig::Split(const string &src, const string &sep, vector<string> &dest)
379 {
380 string::size_type begin = 0;
381 string::size_type end = src.find(sep);
382 while (end != string::npos) {
383 dest.push_back(src.substr(begin, end - begin));
384 begin = end + sep.size();
385 end = src.find(sep, begin);
386 }
387 if (begin != src.size()) {
388 dest.push_back(src.substr(begin));
389 }
390 }
391
Split(const string &src, const string &sep, std::unordered_set<string> &dest)392 void LocaleConfig::Split(const string &src, const string &sep, std::unordered_set<string> &dest)
393 {
394 string::size_type begin = 0;
395 string::size_type end = src.find(sep);
396 while (end != string::npos) {
397 dest.insert(src.substr(begin, end - begin));
398 begin = end + sep.size();
399 end = src.find(sep, begin);
400 }
401 if (begin != src.size()) {
402 dest.insert(src.substr(begin));
403 }
404 }
405
406 // language in white languages should have script.
GetSystemLanguages(vector<string> &ret)407 void LocaleConfig::GetSystemLanguages(vector<string> &ret)
408 {
409 std::copy(whiteLanguages.begin(), whiteLanguages.end(), std::back_inserter(ret));
410 }
411
GetSupportedLocales()412 const unordered_set<string>& LocaleConfig::GetSupportedLocales()
413 {
414 return supportedLocales;
415 }
416
GetSupportedRegions()417 const unordered_set<string>& LocaleConfig::GetSupportedRegions()
418 {
419 return supportedRegions;
420 }
421
GetSystemCountries(vector<string> &ret)422 void LocaleConfig::GetSystemCountries(vector<string> &ret)
423 {
424 std::copy(supportedRegions.begin(), supportedRegions.end(), std::back_inserter(ret));
425 }
426
IsSuggested(const string &language)427 bool LocaleConfig::IsSuggested(const string &language)
428 {
429 unordered_set<string> relatedLocales;
430 vector<string> simCountries;
431 GetCountriesFromSim(simCountries);
432 GetRelatedLocales(relatedLocales, simCountries);
433 for (auto iter = relatedLocales.begin(); iter != relatedLocales.end();) {
434 if (extendWhiteLanguageList.find(*iter) == extendWhiteLanguageList.end()) {
435 iter = relatedLocales.erase(iter);
436 } else {
437 ++iter;
438 }
439 }
440 string mainLanguage = GetMainLanguage(language);
441 return relatedLocales.find(mainLanguage) != relatedLocales.end();
442 }
443
IsSuggested(const std::string &language, const std::string ®ion)444 bool LocaleConfig::IsSuggested(const std::string &language, const std::string ®ion)
445 {
446 unordered_set<string> relatedLocales;
447 vector<string> countries { region };
448 GetRelatedLocales(relatedLocales, countries);
449 for (auto iter = relatedLocales.begin(); iter != relatedLocales.end();) {
450 if (extendWhiteLanguageList.find(*iter) == extendWhiteLanguageList.end()) {
451 iter = relatedLocales.erase(iter);
452 } else {
453 ++iter;
454 }
455 }
456 string mainLanguage = GetMainLanguage(language);
457 return relatedLocales.find(mainLanguage) != relatedLocales.end();
458 }
459
ExtendWhiteLanguages()460 void LocaleConfig::ExtendWhiteLanguages()
461 {
462 UErrorCode status = U_ZERO_ERROR;
463 for (auto iter = whiteLanguages.begin(); iter != whiteLanguages.end(); ++iter) {
464 extendWhiteLanguageList.insert(*iter);
465 icu::Locale locale = icu::Locale::forLanguageTag((*iter).c_str(), status);
466 locale.addLikelySubtags(status);
467 if (U_FAILURE(status)) {
468 HILOG_INFO_I18N("create Locale object for %{public}s failed.", (*iter).c_str());
469 continue;
470 }
471 const char* baseName = locale.getBaseName();
472 if (baseName != nullptr) {
473 std::string baseNameStr(baseName);
474 std::replace(baseNameStr.begin(), baseNameStr.end(), '_', '-');
475 extendWhiteLanguageList.insert(baseNameStr);
476 }
477 }
478 }
479
GetRelatedLocales(unordered_set<string> &relatedLocales, vector<string> countries)480 void LocaleConfig::GetRelatedLocales(unordered_set<string> &relatedLocales, vector<string> countries)
481 {
482 // remove unsupported countries
483 const unordered_set<string> ®ions = GetSupportedRegions();
484 for (auto iter = countries.begin(); iter != countries.end();) {
485 if (regions.find(*iter) == regions.end()) {
486 iter = countries.erase(iter);
487 } else {
488 ++iter;
489 }
490 }
491 const unordered_set<string> &locales = GetSupportedLocales();
492 for (string locale : locales) {
493 bool find = false;
494 for (string country : countries) {
495 if (locale.find(country) != string::npos) {
496 find = true;
497 break;
498 }
499 }
500 if (!find) {
501 continue;
502 }
503 string mainLanguage = GetMainLanguage(locale);
504 if (mainLanguage != "") {
505 relatedLocales.insert(mainLanguage);
506 }
507 }
508 }
509
GetCountriesFromSim(vector<string> &simCountries)510 void LocaleConfig::GetCountriesFromSim(vector<string> &simCountries)
511 {
512 simCountries.push_back(GetSystemRegion());
513 char value[CONFIG_LEN];
514 int code = GetParameter(SIM_COUNTRY_CODE_KEY, "", value, CONFIG_LEN);
515 if (code > 0) {
516 simCountries.push_back(value);
517 }
518 }
519
GetListFromFile(const char *path, const char *resourceName, unordered_set<string> &ret)520 void LocaleConfig::GetListFromFile(const char *path, const char *resourceName, unordered_set<string> &ret)
521 {
522 xmlKeepBlanksDefault(0);
523 if (!path) {
524 return;
525 }
526 xmlDocPtr doc = xmlParseFile(path);
527 if (!doc) {
528 return;
529 }
530 xmlNodePtr cur = xmlDocGetRootElement(doc);
531 if (!cur || xmlStrcmp(cur->name, reinterpret_cast<const xmlChar *>(resourceName))) {
532 xmlFreeDoc(doc);
533 return;
534 }
535 cur = cur->xmlChildrenNode;
536 xmlChar *content = nullptr;
537 while (cur != nullptr) {
538 content = xmlNodeGetContent(cur);
539 if (content != nullptr) {
540 ret.insert(reinterpret_cast<const char*>(content));
541 xmlFree(content);
542 cur = cur->next;
543 } else {
544 break;
545 }
546 }
547 xmlFreeDoc(doc);
548 }
549
ProcessForbiddenRegions(const unordered_set<string> &forbiddenRegions)550 void LocaleConfig::ProcessForbiddenRegions(const unordered_set<string> &forbiddenRegions)
551 {
552 for (auto it = forbiddenRegions.begin(); it != forbiddenRegions.end(); ++it) {
553 size_t pos = it->rfind("-");
554 std::string language = it->substr(0, pos);
555 std::string region = it->substr(pos + 1);
556 if (language.compare("*") == 0) {
557 blockedRegions.insert(region);
558 } else {
559 if (blockedLanguageRegions.find(language) == blockedLanguageRegions.end()) {
560 blockedLanguageRegions[language] = { region };
561 } else {
562 blockedLanguageRegions[language].insert(region);
563 }
564 }
565 }
566 }
567
Expunge(unordered_set<string> &src, const unordered_set<string> &another)568 void LocaleConfig::Expunge(unordered_set<string> &src, const unordered_set<string> &another)
569 {
570 for (auto iter = src.begin(); iter != src.end();) {
571 if (another.find(*iter) != another.end()) {
572 iter = src.erase(iter);
573 } else {
574 ++iter;
575 }
576 }
577 }
578
InitializeLists()579 bool LocaleConfig::InitializeLists()
580 {
581 SetHwIcuDirectory();
582 unordered_set<string> forbiddenRegions;
583 LoadRegionsLanguages(forbiddenRegions);
584 ProcessForbiddenRegions(forbiddenRegions);
585 Expunge(supportedRegions, blockedRegions);
586 Expunge(whiteLanguages, blockedLanguages);
587 GetListFromFile(SUPPORTED_LOCALES_PATH, SUPPORTED_LOCALES_NAME, supportedLocales);
588 GetListFromFile(SUPPORT_LOCALES_PATH, SUPPORT_LOCALES_NAME, supportLocales);
589 GetListFromFile(OVERRIDE_SUPPORTED_REGIONS_PATH, OVERRIDE_SUPPORTED_REGIONS_NAME, overrideSupportedRegions);
590 GetListFromFile(DIALECT_LANGS_PATH, DIALECT_LANGS_NAME, dialectLang);
591 ExtendWhiteLanguages();
592 return true;
593 }
594
LoadRegionsLanguages(unordered_set<std::string>& forbiddenRegions)595 void LocaleConfig::LoadRegionsLanguages(unordered_set<std::string>& forbiddenRegions)
596 {
597 char buf[MAX_PATH_LEN] = {0};
598 char* path = GetOneCfgFile(REGIONS_LANGUAGES_PATH, buf, MAX_PATH_LEN);
599 xmlKeepBlanksDefault(0);
600 if (!path) {
601 return;
602 }
603 xmlDocPtr doc = xmlParseFile(path);
604 if (!doc) {
605 return;
606 }
607 xmlNodePtr cur = xmlDocGetRootElement(doc);
608 if (!cur || xmlStrcmp(cur->name, reinterpret_cast<const xmlChar *>(REGIONS_LANGUAGES_NAME))) {
609 xmlFreeDoc(doc);
610 return;
611 }
612 cur = cur->xmlChildrenNode;
613 xmlChar *content = nullptr;
614 while (cur != nullptr) {
615 content = xmlNodeGetContent(cur);
616 if (content != nullptr && !xmlStrcmp(cur->name, reinterpret_cast<const xmlChar *>(SUPPORTED_REGIONS_NAME))) {
617 Split(reinterpret_cast<const char*>(content), ",", supportedRegions);
618 } else if (content != nullptr && !xmlStrcmp(cur->name,
619 reinterpret_cast<const xmlChar *>(WHITE_LANGUAGES_NAME))) {
620 Split(reinterpret_cast<const char*>(content), ",", whiteLanguages);
621 } else if (content != nullptr && !xmlStrcmp(cur->name,
622 reinterpret_cast<const xmlChar *>(FORBIDDEN_REGIONS_NAME))) {
623 Split(reinterpret_cast<const char*>(content), ",", forbiddenRegions);
624 } else if (content != nullptr && !xmlStrcmp(cur->name,
625 reinterpret_cast<const xmlChar *>(FORBIDDEN_LANGUAGES_NAME))) {
626 Split(reinterpret_cast<const char*>(content), ",", blockedLanguages);
627 }
628 if (content != nullptr) {
629 xmlFree(content);
630 }
631 cur = cur->next;
632 }
633 xmlFreeDoc(doc);
634 }
635
GetMainLanguage(const string &language)636 string LocaleConfig::GetMainLanguage(const string &language)
637 {
638 UErrorCode status = U_ZERO_ERROR;
639 icu::Locale origin = icu::Locale::forLanguageTag(language, status);
640 if (U_FAILURE(status)) {
641 return "";
642 }
643 origin.addLikelySubtags(status);
644 if (U_FAILURE(status)) {
645 return "";
646 }
647 icu::LocaleBuilder builder = icu::LocaleBuilder().setLanguage(origin.getLanguage()).
648 setScript(origin.getScript()).setRegion(origin.getCountry());
649 icu::Locale temp = builder.setExtension('u', "").build(status);
650 if (U_FAILURE(status)) {
651 return "";
652 }
653 string fullLanguage = temp.toLanguageTag<string>(status);
654 if (U_FAILURE(status)) {
655 return "";
656 }
657 if (dialectMap.find(fullLanguage) != dialectMap.end()) {
658 return dialectMap[fullLanguage];
659 }
660 builder.setRegion("");
661 temp = builder.build(status);
662 if (U_FAILURE(status)) {
663 return "";
664 }
665 fullLanguage = temp.toLanguageTag<string>(status);
666 if (U_FAILURE(status)) {
667 return "";
668 }
669 return fullLanguage;
670 }
671
GetDisplayLanguage(const string &language, const string &displayLocale, bool sentenceCase)672 string LocaleConfig::GetDisplayLanguage(const string &language, const string &displayLocale, bool sentenceCase)
673 {
674 std::string result;
675 string adjust = Adjust(language);
676 if (adjust == language) {
677 UErrorCode status = U_ZERO_ERROR;
678 icu::Locale displayLoc = icu::Locale::forLanguageTag(displayLocale, status);
679 if (U_FAILURE(status)) {
680 return PseudoLocalizationProcessor("");
681 }
682 icu::Locale locale = icu::Locale::forLanguageTag(language, status);
683 if (U_FAILURE(status)) {
684 return PseudoLocalizationProcessor("");
685 }
686 icu::UnicodeString unistr;
687 std::string lang(locale.getLanguage());
688 if (dialectLang.find(lang) != dialectLang.end()) {
689 result = GetDisplayLanguageWithDialect(language, displayLocale);
690 }
691 }
692 if (result.empty()) {
693 result = GetDisplayLanguageInner(adjust, displayLocale, sentenceCase);
694 }
695 if (sentenceCase && !result.empty()) {
696 char ch = static_cast<char>(toupper(result[0]));
697 return PseudoLocalizationProcessor(result.replace(0, 1, 1, ch));
698 }
699 return PseudoLocalizationProcessor(result);
700 }
701
ComputeLocale(const std::string &displayLocale)702 std::string LocaleConfig::ComputeLocale(const std::string &displayLocale)
703 {
704 if (supportedDialectLocales.size() == 0) {
705 xmlKeepBlanksDefault(0);
706 xmlDocPtr doc = xmlParseFile(SUPPORT_LOCALES_PATH);
707 if (!doc) {
708 return "";
709 }
710 xmlNodePtr cur = xmlDocGetRootElement(doc);
711 if (!cur || xmlStrcmp(cur->name, reinterpret_cast<const xmlChar *>(supportLocalesTag))) {
712 xmlFreeDoc(doc);
713 HILOG_INFO_I18N("can not parse language supported locale file");
714 return "";
715 }
716 cur = cur->xmlChildrenNode;
717 while (cur != nullptr) {
718 xmlChar *content = xmlNodeGetContent(cur);
719 if (content == nullptr) {
720 HILOG_INFO_I18N("get xml node content failed");
721 break;
722 }
723 std::map<std::string, std::string> localeInfoConfigs = {};
724 LocaleInfo localeinfo(reinterpret_cast<const char*>(content), localeInfoConfigs);
725 std::string maximizeLocale = localeinfo.Maximize();
726 const char* key = maximizeLocale.c_str();
727 const char* value = reinterpret_cast<const char*>(content);
728 SetSupportedDialectLocales(key, value);
729 xmlFree(content);
730 cur = cur->next;
731 }
732 xmlFreeDoc(doc);
733 }
734 std::map<std::string, std::string> configs = {};
735 LocaleInfo localeinfo(displayLocale, configs);
736 std::string maximizeLocale = localeinfo.Maximize();
737 if (supportedDialectLocales.find(maximizeLocale) != supportedDialectLocales.end()) {
738 return supportedDialectLocales.at(maximizeLocale);
739 }
740 return "";
741 }
742
SetSupportedDialectLocales(const char* key, const char* value)743 void LocaleConfig::SetSupportedDialectLocales(const char* key, const char* value)
744 {
745 std::lock_guard<std::mutex> dialectLocaleLock(dialectLocaleMutex);
746 supportedDialectLocales.insert(
747 std::make_pair<std::string, std::string>(key, value));
748 }
749
ReadLangData(const char *langDataPath)750 void LocaleConfig::ReadLangData(const char *langDataPath)
751 {
752 xmlKeepBlanksDefault(0);
753 if (langDataPath == nullptr) {
754 return;
755 }
756 xmlDocPtr doc = xmlParseFile(langDataPath);
757 if (!doc) {
758 HILOG_INFO_I18N("can not open language data file");
759 return;
760 }
761 xmlNodePtr cur = xmlDocGetRootElement(doc);
762 if (!cur || xmlStrcmp(cur->name, reinterpret_cast<const xmlChar *>(rootTag))) {
763 xmlFreeDoc(doc);
764 HILOG_INFO_I18N("parse language data file failed");
765 return;
766 }
767 cur = cur->xmlChildrenNode;
768 while (cur != nullptr && !xmlStrcmp(cur->name, reinterpret_cast<const xmlChar *>(secondRootTag))) {
769 xmlChar *langContents[ELEMENT_NUM] = { 0 }; // 2 represent langid, displayname;
770 xmlNodePtr langValue = cur->xmlChildrenNode;
771 bool xmlNodeNull = false;
772 for (size_t i = 0; i < ELEMENT_NUM && langValue != nullptr; i++) {
773 langContents[i] = xmlNodeGetContent(langValue);
774 langValue = langValue->next;
775 if (langContents[i] == nullptr) {
776 xmlNodeNull = true;
777 }
778 }
779 if (!xmlNodeNull) {
780 // 0 represents langid index, 1 represents displayname index
781 const char* key = reinterpret_cast<const char *>(langContents[0]);
782 const char* value = reinterpret_cast<const char *>(langContents[1]);
783 SetLocale2DisplayName(key, value);
784 }
785 for (size_t i = 0; i < ELEMENT_NUM; i++) {
786 if (langContents[i] != nullptr) {
787 xmlFree(langContents[i]);
788 }
789 }
790 cur = cur->next;
791 }
792 xmlFreeDoc(doc);
793 }
794
SetRegion2DisplayName(const char* key, const char* value)795 void LocaleConfig::SetRegion2DisplayName(const char* key, const char* value)
796 {
797 std::lock_guard<std::mutex> regionDisplayLock(region2DisplayNameMutex);
798 region2DisplayName.insert(
799 std::make_pair<std::string, std::string>(key, value));
800 }
801
SetLocale2DisplayName(const char* key, const char* value)802 void LocaleConfig::SetLocale2DisplayName(const char* key, const char* value)
803 {
804 std::lock_guard<std::mutex> localeDisplayLock(locale2DisplayNameMutex);
805 locale2DisplayName.insert(
806 std::make_pair<std::string, std::string>(key, value));
807 }
808
ReadRegionData(const char *regionDataPath)809 void LocaleConfig::ReadRegionData(const char *regionDataPath)
810 {
811 xmlKeepBlanksDefault(0);
812 if (regionDataPath == nullptr) {
813 return;
814 }
815 xmlDocPtr doc = xmlParseFile(regionDataPath);
816 if (!doc) {
817 HILOG_INFO_I18N("can not open region data file");
818 return;
819 }
820 xmlNodePtr cur = xmlDocGetRootElement(doc);
821 if (cur) {
822 HILOG_INFO_I18N("cur pointer is true");
823 }
824 if (!cur || xmlStrcmp(cur->name, reinterpret_cast<const xmlChar *>(rootRegion))) {
825 xmlFreeDoc(doc);
826 HILOG_INFO_I18N("parse region data file failed");
827 return;
828 }
829 cur = cur->xmlChildrenNode;
830 while (cur != nullptr && !xmlStrcmp(cur->name, reinterpret_cast<const xmlChar *>(secondRootRegion))) {
831 xmlChar *regionContents[ELEMENT_NUM] = { 0 };
832 xmlNodePtr regionValue = cur->xmlChildrenNode;
833 bool xmlNodeNull = false;
834 for (size_t i = 0; i < ELEMENT_NUM && regionValue != nullptr; i++) {
835 regionContents[i] = xmlNodeGetContent(regionValue);
836 regionValue = regionValue->next;
837 if (regionContents[i] == nullptr) {
838 xmlNodeNull = true;
839 }
840 }
841 if (!xmlNodeNull) {
842 // 0 represents langid index, 1 represents displayname index
843 const char* regionKey = reinterpret_cast<const char *>(regionContents[0]);
844 const char* regionVal = reinterpret_cast<const char *>(regionContents[1]);
845 SetRegion2DisplayName(regionKey, regionVal);
846 }
847 for (size_t i = 0; i < ELEMENT_NUM; i++) {
848 if (regionContents[i] != nullptr) {
849 xmlFree(regionContents[i]);
850 }
851 }
852 cur = cur->next;
853 }
854 xmlFreeDoc(doc);
855 }
856
GetDisplayLanguageWithDialect(const std::string &localeStr, const std::string &displayLocale)857 string LocaleConfig::GetDisplayLanguageWithDialect(const std::string &localeStr, const std::string &displayLocale)
858 {
859 std::string finalLocale = ComputeLocale(displayLocale);
860 if (finalLocale.empty()) {
861 return "";
862 }
863 if (finalLocale.compare(currentDialectLocale) != 0) {
864 std::string xmlPath = LANG_PATH + finalLocale + ".xml";
865 locale2DisplayName.clear();
866 ReadLangData(xmlPath.c_str());
867 currentDialectLocale = finalLocale;
868 }
869 if (locale2DisplayName.find(localeStr) != locale2DisplayName.end()) {
870 return locale2DisplayName.at(localeStr);
871 }
872 std::map<std::string, std::string> configs = {};
873 LocaleInfo locale(localeStr, configs);
874 std::string language = locale.GetLanguage();
875 std::string scripts = locale.GetScript();
876 std::string region = locale.GetRegion();
877 if (scripts.length() != 0) {
878 std::string languageAndScripts = language + "-" + scripts;
879 if (locale2DisplayName.find(languageAndScripts) != locale2DisplayName.end()) {
880 return locale2DisplayName.at(languageAndScripts);
881 }
882 }
883 if (region.length() != 0) {
884 std::string languageAndRegion = language + "-" + region;
885 if (locale2DisplayName.find(languageAndRegion) != locale2DisplayName.end()) {
886 return locale2DisplayName.at(languageAndRegion);
887 }
888 }
889 if (locale2DisplayName.find(language) != locale2DisplayName.end()) {
890 return locale2DisplayName.at(language);
891 }
892 return "";
893 }
894
GetDisplayOverrideRegion(const std::string ®ion, const std::string &displayLocale)895 string LocaleConfig::GetDisplayOverrideRegion(const std::string ®ion, const std::string &displayLocale)
896 {
897 UErrorCode status = U_ZERO_ERROR;
898 icu::Locale originLocale;
899 icu::UnicodeString displayRegion;
900 if (displayLocale.compare(currentOverrideRegion) != 0) {
901 std::string xmlPath = REGION_PATH + displayLocale + ".xml";
902 region2DisplayName.clear();
903 ReadRegionData(xmlPath.c_str());
904 currentOverrideRegion = displayLocale;
905 }
906 if (region2DisplayName.find(region) != region2DisplayName.end()) {
907 return region2DisplayName.at(region);
908 } else {
909 icu::Locale locale = icu::Locale::forLanguageTag(displayLocale, status);
910 if (U_FAILURE(status)) {
911 return "";
912 }
913 if (IsValidRegion(region)) {
914 icu::LocaleBuilder builder = icu::LocaleBuilder().setRegion(region);
915 originLocale = builder.build(status);
916 } else {
917 originLocale = icu::Locale::forLanguageTag(region, status);
918 }
919 originLocale.getDisplayCountry(locale, displayRegion);
920 std::string result;
921 displayRegion.toUTF8String(result);
922 return result;
923 }
924 }
925
GetDisplayRegion(const string ®ion, const string &displayLocale, bool sentenceCase)926 string LocaleConfig::GetDisplayRegion(const string ®ion, const string &displayLocale, bool sentenceCase)
927 {
928 UErrorCode status = U_ZERO_ERROR;
929 icu::Locale originLocale;
930 if (IsValidRegion(region)) {
931 icu::LocaleBuilder builder = icu::LocaleBuilder().setRegion(region);
932 originLocale = builder.build(status);
933 } else {
934 originLocale = icu::Locale::forLanguageTag(region, status);
935 }
936 std::string country(originLocale.getCountry());
937 if (country.length() == 0) {
938 return PseudoLocalizationProcessor("");
939 }
940 if (U_FAILURE(status)) {
941 return PseudoLocalizationProcessor("");
942 }
943 icu::Locale locale = icu::Locale::forLanguageTag(displayLocale, status);
944 if (U_FAILURE(status)) {
945 return PseudoLocalizationProcessor("");
946 }
947 icu::UnicodeString unistr;
948 icu::UnicodeString displayRegion;
949 std::string result;
950 if (overrideSupportedRegions.find(displayLocale) != overrideSupportedRegions.end()) {
951 result = GetDisplayOverrideRegion(region, displayLocale);
952 } else {
953 originLocale.getDisplayCountry(locale, displayRegion);
954 displayRegion.toUTF8String(result);
955 }
956 if (sentenceCase) {
957 char ch = static_cast<char>(toupper(result[0]));
958 return PseudoLocalizationProcessor(result.replace(0, 1, 1, ch));
959 }
960 return PseudoLocalizationProcessor(result);
961 }
962
IsRTL(const string &locale)963 bool LocaleConfig::IsRTL(const string &locale)
964 {
965 icu::Locale curLocale(locale.c_str());
966 return curLocale.isRightToLeft();
967 }
968
parseExtension(const std::string &extension, std::map<std::string, std::string> &map)969 void parseExtension(const std::string &extension, std::map<std::string, std::string> &map)
970 {
971 std::string pattern = "-..-";
972 std::regex express(pattern);
973
974 std::regex_token_iterator<std::string::const_iterator> begin1(extension.cbegin(), extension.cend(), express);
975 std::regex_token_iterator<std::string::const_iterator> begin2(extension.cbegin(), extension.cend(), express, -1);
976 begin2++;
977 for (; begin1 != std::sregex_token_iterator() && begin2 != std::sregex_token_iterator(); begin1++, begin2++) {
978 map.insert(std::pair<std::string, std::string>(begin1->str(), begin2->str()));
979 }
980 }
981
setExtension(std::string &extension, const std::string &tag, const std::set<string> &validValue, const std::map<std::string, std::string> &extensionMap, const std::map<std::string, std::string> &defaultExtensionMap)982 void setExtension(std::string &extension, const std::string &tag, const std::set<string> &validValue,
983 const std::map<std::string, std::string> &extensionMap,
984 const std::map<std::string, std::string> &defaultExtensionMap)
985 {
986 std::string value;
987 auto it = extensionMap.find(tag);
988 if (it != extensionMap.end()) {
989 value = it->second;
990 if (validValue.find(value) == validValue.end()) {
991 return;
992 } else {
993 extension += tag;
994 extension += value;
995 }
996 } else {
997 it = defaultExtensionMap.find(tag);
998 if (it != defaultExtensionMap.end()) {
999 value = it->second;
1000 if (validValue.find(value) == validValue.end()) {
1001 return;
1002 } else {
1003 extension += tag;
1004 extension += value;
1005 }
1006 }
1007 }
1008 }
1009
setOtherExtension(std::string &extension, std::map<std::string, std::string> &extensionMap, std::map<std::string, std::string> &defaultExtensionMap)1010 void setOtherExtension(std::string &extension, std::map<std::string, std::string> &extensionMap,
1011 std::map<std::string, std::string> &defaultExtensionMap)
1012 {
1013 std::set<std::string> tags;
1014 tags.insert("-ca-");
1015 tags.insert("-co-");
1016 tags.insert("-kn-");
1017 tags.insert("-kf-");
1018 tags.insert("-nu-");
1019 tags.insert("-hc-");
1020
1021 for (auto it = tags.begin(); it != tags.end(); it++) {
1022 extensionMap.erase(*it);
1023 defaultExtensionMap.erase(*it);
1024 }
1025
1026 for (auto it = defaultExtensionMap.begin(); it != defaultExtensionMap.end(); it++) {
1027 extensionMap.insert(std::pair<std::string, std::string>(it->first, it->second));
1028 }
1029
1030 for (auto it = extensionMap.begin(); it != extensionMap.end(); it++) {
1031 extension += it->first;
1032 extension += it->second;
1033 }
1034 }
1035
GetValidLocale(const std::string &localeTag)1036 std::string LocaleConfig::GetValidLocale(const std::string &localeTag)
1037 {
1038 std::string baseLocale = "";
1039 std::string extension = "";
1040 std::size_t found = localeTag.find("-u-");
1041 baseLocale = localeTag.substr(0, found);
1042 if (found != std::string::npos) {
1043 extension = localeTag.substr(found);
1044 }
1045 std::map<std::string, std::string> extensionMap;
1046 if (extension != "") {
1047 parseExtension(extension, extensionMap);
1048 }
1049
1050 std::string systemLocaleTag = GetSystemLocale();
1051 std::string defaultExtension = "";
1052 found = systemLocaleTag.find("-u-");
1053 if (found != std::string::npos) {
1054 defaultExtension = systemLocaleTag.substr(found);
1055 }
1056 std::map<std::string, std::string> defaultExtensionMap;
1057 if (defaultExtension != "") {
1058 parseExtension(defaultExtension, defaultExtensionMap);
1059 }
1060
1061 std::string ext = "";
1062 setExtension(ext, "-ca-", validCaTag, extensionMap, defaultExtensionMap);
1063 setExtension(ext, "-co-", validCoTag, extensionMap, defaultExtensionMap);
1064 setExtension(ext, "-kn-", validKnTag, extensionMap, defaultExtensionMap);
1065 setExtension(ext, "-kf-", validKfTag, extensionMap, defaultExtensionMap);
1066 setExtension(ext, "-nu-", validNuTag, extensionMap, defaultExtensionMap);
1067 setExtension(ext, "-hc-", validHcTag, extensionMap, defaultExtensionMap);
1068
1069 std::string otherExt = "";
1070 setOtherExtension(otherExt, extensionMap, defaultExtensionMap);
1071 if (ext != "" || otherExt != "") {
1072 return baseLocale + "-u" + ext + otherExt;
1073 } else {
1074 return baseLocale;
1075 }
1076 }
1077
IsEmpty24HourClock()1078 bool LocaleConfig::IsEmpty24HourClock()
1079 {
1080 std::string is24Hour = ReadSystemParameter(HOUR_KEY, CONFIG_LEN);
1081 if (is24Hour.compare("default") == 0) {
1082 return true;
1083 }
1084 return false;
1085 }
1086
Is24HourClock()1087 bool LocaleConfig::Is24HourClock()
1088 {
1089 std::string is24Hour = ReadSystemParameter(HOUR_KEY, CONFIG_LEN);
1090 if (is24Hour.compare("default") == 0) {
1091 std::string systemLocale = GetSystemLocale();
1092 return Is24HourLocale(systemLocale);
1093 }
1094 if (is24Hour.compare("true") == 0) {
1095 return true;
1096 }
1097 return false;
1098 }
1099
GetSystemHour()1100 std::string LocaleConfig::GetSystemHour()
1101 {
1102 bool is24Hour = Is24HourClock();
1103 return is24Hour ? "true" : "false";
1104 }
1105
Is24HourLocale(const std::string& systemLocale)1106 bool LocaleConfig::Is24HourLocale(const std::string& systemLocale)
1107 {
1108 static std::unordered_map<std::string, bool> is24HourLocaleMap;
1109 if (is24HourLocaleMap.find(systemLocale) != is24HourLocaleMap.end()) {
1110 return is24HourLocaleMap[systemLocale];
1111 }
1112 UErrorCode status = U_ZERO_ERROR;
1113 icu::Locale locale = icu::Locale::forLanguageTag(icu::StringPiece(systemLocale), status);
1114 if (U_FAILURE(status)) {
1115 HILOG_INFO_I18N("Is24HourLocale: %{public}s create locale failed", systemLocale.c_str());
1116 return false;
1117 }
1118
1119 icu::UnicodeString formatPattern;
1120 icu::DateFormat* dateFormat = icu::DateFormat::createTimeInstance(icu::DateFormat::EStyle::kLong, locale);
1121 if (dateFormat == nullptr) {
1122 HILOG_INFO_I18N("Is24HourLocale: createTimeInstance failed");
1123 return false;
1124 }
1125 icu::SimpleDateFormat* simDateFormat = static_cast<icu::SimpleDateFormat*>(dateFormat);
1126 if (simDateFormat == nullptr) {
1127 HILOG_INFO_I18N("Is24HourLocale: failed to convert dateFormat");
1128 return false;
1129 }
1130 simDateFormat->toPattern(formatPattern);
1131 delete dateFormat;
1132 std::string pattern;
1133 formatPattern.toUTF8String(pattern);
1134 bool result = HasDesignator(pattern, 'H');
1135 is24HourLocaleMap[systemLocale] = result;
1136 return result;
1137 }
1138
HasDesignator(const std::string& pattern, const char designator)1139 bool LocaleConfig::HasDesignator(const std::string& pattern, const char designator)
1140 {
1141 if (pattern.empty()) {
1142 HILOG_INFO_I18N("HasDesignator: pattern is empty");
1143 return false;
1144 }
1145 bool insideQuote = false;
1146 for (const auto& c : pattern) {
1147 if (c == '\'') {
1148 insideQuote = !insideQuote;
1149 } else if (!insideQuote) {
1150 if (c == designator) {
1151 return true;
1152 }
1153 }
1154 }
1155 return false;
1156 }
1157
GetUsingLocalDigit()1158 bool LocaleConfig::GetUsingLocalDigit()
1159 {
1160 std::string locale = GetSystemLocale();
1161 LocaleInfo localeInfo(locale);
1162 std::string language = localeInfo.GetLanguage();
1163 if (localDigitMap.find(language) == localDigitMap.end()) {
1164 return false;
1165 }
1166 std::string localNumberSystem = localDigitMap.at(language);
1167 if (localNumberSystem.compare(localeInfo.GetNumberingSystem()) != 0) {
1168 return false;
1169 }
1170 return true;
1171 }
1172
GetBlockedLanguages()1173 std::unordered_set<std::string> LocaleConfig::GetBlockedLanguages()
1174 {
1175 return blockedLanguages;
1176 }
1177
GetBlockedRegions()1178 std::unordered_set<std::string> LocaleConfig::GetBlockedRegions()
1179 {
1180 return blockedRegions;
1181 }
1182
GetLanguageBlockedRegions()1183 std::unordered_set<std::string> LocaleConfig::GetLanguageBlockedRegions()
1184 {
1185 std::string systemLanguage = LocaleConfig::GetSystemLanguage();
1186 if (blockedLanguageRegions.find(systemLanguage) != blockedLanguageRegions.end()) {
1187 return blockedLanguageRegions[systemLanguage];
1188 }
1189 std::unordered_set<std::string> emptyResult;
1190 return emptyResult;
1191 }
1192
SetSystemLanguage(const std::string &languageTag)1193 I18nErrorCode LocaleConfig::SetSystemLanguage(const std::string &languageTag)
1194 {
1195 if (!IsValidTag(languageTag)) {
1196 HILOG_ERROR_I18N("LocaleConfig::SetSystemLanguage %{public}s is not valid language tag.",
1197 languageTag.c_str());
1198 return I18nErrorCode::INVALID_LANGUAGE_TAG;
1199 }
1200 // save old language, reset system language to old language if update locale failed.
1201 std::string oldLanguageTag = GetSystemLanguage();
1202 if (SetParameter(LANGUAGE_KEY, languageTag.data()) != 0) {
1203 HILOG_ERROR_I18N("LocaleConfig::SetSystemLanguage update system language failed.");
1204 return I18nErrorCode::UPDATE_SYSTEM_LANGUAGE_FAILED;
1205 }
1206 std::string newLocaleTag = UpdateLanguageOfLocale(languageTag);
1207 if (SetSystemLocale(newLocaleTag) == I18nErrorCode::SUCCESS) {
1208 #ifdef SUPPORT_MULTI_USER
1209 MultiUsers::SaveLanguage("", languageTag);
1210 #endif
1211 return I18nErrorCode::SUCCESS;
1212 }
1213 // reset system language to old language in case that system language is inconsist with system locale's lanuage.
1214 HILOG_ERROR_I18N("LocaleConfig::SetSystemLanguage update system locale failed.");
1215 SetParameter(LANGUAGE_KEY, oldLanguageTag.data());
1216 return I18nErrorCode::UPDATE_SYSTEM_LANGUAGE_FAILED;
1217 }
1218
SetSystemRegion(const std::string ®ionTag)1219 I18nErrorCode LocaleConfig::SetSystemRegion(const std::string ®ionTag)
1220 {
1221 if (!IsValidRegion(regionTag)) {
1222 HILOG_ERROR_I18N("LocaleConfig::SetSystemRegion %{public}s is not valid region tag.", regionTag.c_str());
1223 return I18nErrorCode::INVALID_REGION_TAG;
1224 }
1225 return SetSystemLocale(UpdateRegionOfLocale(regionTag));
1226 }
1227
SetSystemLocale(const std::string &localeTag)1228 I18nErrorCode LocaleConfig::SetSystemLocale(const std::string &localeTag)
1229 {
1230 if (!IsValidTag(localeTag)) {
1231 HILOG_ERROR_I18N("LocaleConfig::SetSystemLocale %{public}s is not a valid locale tag.", localeTag.c_str());
1232 return I18nErrorCode::INVALID_LOCALE_TAG;
1233 }
1234 if (SetParameter(LOCALE_KEY, localeTag.data()) != 0) {
1235 return I18nErrorCode::UPDATE_SYSTEM_LOCALE_FAILED;
1236 }
1237 #ifdef SUPPORT_MULTI_USER
1238 MultiUsers::SaveLocale("", localeTag);
1239 #endif
1240 #ifdef SUPPORT_GRAPHICS
1241 UpdateConfiguration(AAFwk::GlobalConfigurationKey::SYSTEM_LANGUAGE, localeTag);
1242 return PublishCommonEvent(EventFwk::CommonEventSupport::COMMON_EVENT_LOCALE_CHANGED);
1243 #else
1244 return I18nErrorCode::SUCCESS;
1245 #endif
1246 }
1247
IsValid24HourClockValue(const std::string &tag)1248 bool LocaleConfig::IsValid24HourClockValue(const std::string &tag)
1249 {
1250 if (tag.compare("true") == 0 || tag.compare("false") == 0 || tag.compare("default") == 0) {
1251 return true;
1252 }
1253 return false;
1254 }
1255
Set24HourClock(const std::string &option)1256 I18nErrorCode LocaleConfig::Set24HourClock(const std::string &option)
1257 {
1258 if (!IsValid24HourClockValue(option)) {
1259 HILOG_ERROR_I18N("LocaleConfig::Set24HourClock invalid 24 Hour clock tag: %{public}s", option.c_str());
1260 return I18nErrorCode::INVALID_24_HOUR_CLOCK_TAG;
1261 }
1262 if (SetParameter(HOUR_KEY, option.data()) != 0) {
1263 HILOG_ERROR_I18N("LocaleConfig::Set24HourClock update 24 hour clock failed with option=%{public}s",
1264 option.c_str());
1265 return I18nErrorCode::UPDATE_24_HOUR_CLOCK_FAILED;
1266 }
1267 #ifdef SUPPORT_MULTI_USER
1268 MultiUsers::SaveIs24Hour("", option);
1269 #endif
1270 #ifdef SUPPORT_GRAPHICS
1271 UpdateConfiguration(AAFwk::GlobalConfigurationKey::SYSTEM_HOUR, option);
1272 return PublishCommonEvent(EventFwk::CommonEventSupport::COMMON_EVENT_TIME_CHANGED);
1273 #else
1274 return I18nErrorCode::SUCCESS;
1275 #endif
1276 }
1277
SetUsingLocalDigit(bool flag)1278 I18nErrorCode LocaleConfig::SetUsingLocalDigit(bool flag)
1279 {
1280 // check whether current language support local digit.
1281 std::string localeTag = GetSystemLocale();
1282 std::string languageTag = localeTag.substr(0, 2); // obtain 2 length language code.
1283 auto it = localDigitMap.find(languageTag);
1284 if (it == localDigitMap.end()) {
1285 HILOG_ERROR_I18N("LocaleConfig::SetUsingLocalDigit current system doesn't support set local digit");
1286 return I18nErrorCode::UPDATE_LOCAL_DIGIT_FAILED;
1287 }
1288 // update system locale.
1289 return SetSystemLocale(UpdateNumberSystemOfLocale(it->second, flag));
1290 }
1291
UpdateNumberSystemOfLocale(const std::string &localDigitTag, bool flag)1292 std::string LocaleConfig::UpdateNumberSystemOfLocale(const std::string &localDigitTag, bool flag)
1293 {
1294 if (flag) {
1295 // add local digit tag to number system param of locale
1296 return AddLocalDigitToLocale(localDigitTag);
1297 }
1298 // remove local digit tag to number system param of locale
1299 return RemoveLocalDigitFromLocale(localDigitTag);
1300 }
1301
AddLocalDigitToLocale(const std::string &localDigitTag)1302 std::string LocaleConfig::AddLocalDigitToLocale(const std::string &localDigitTag)
1303 {
1304 std::string localeTag = GetSystemLocale();
1305 // Case: no extend param, add '-u-' and number system tag.
1306 if (localeTag.find("-u-") == std::string::npos) {
1307 localeTag += "-u" + std::string(NUMBER_SYSTEM_KEY) + localDigitTag;
1308 return localeTag;
1309 }
1310 // Case: has extend param but doesn't hava number system param, add number system tag.
1311 if (localeTag.find(NUMBER_SYSTEM_KEY) == std::string::npos) {
1312 localeTag += std::string(NUMBER_SYSTEM_KEY) + localDigitTag;
1313 return localeTag;
1314 }
1315 // Case: has number system param, replace local digit tag to localDigitTag.
1316 LocaleInfo localeInfo(localeTag);
1317 std::string oldNumberSystem = localeInfo.GetNumberingSystem();
1318 localeTag.replace(localeTag.find(oldNumberSystem), oldNumberSystem.length(), localDigitTag);
1319 return localeTag;
1320 }
1321
RemoveLocalDigitFromLocale(const std::string &localDigitTag)1322 std::string LocaleConfig::RemoveLocalDigitFromLocale(const std::string &localDigitTag)
1323 {
1324 // remove number system tag from locale
1325 std::string localeTag = GetSystemLocale();
1326 std::string numberSystemTag = NUMBER_SYSTEM_KEY + localDigitTag;
1327 size_t pos = localeTag.find(numberSystemTag);
1328 if (pos != std::string::npos) {
1329 localeTag.replace(pos, numberSystemTag.length(), "");
1330 }
1331 // remove "-u" if localeTag ends with "-u"
1332 size_t uLength = 2;
1333 if (localeTag.find("-u") == (localeTag.length() - uLength)) {
1334 localeTag.resize(localeTag.length() - uLength);
1335 }
1336 return localeTag;
1337 }
1338
1339 #ifdef SUPPORT_GRAPHICS
UpdateConfiguration(const char *key, const std::string &value)1340 void LocaleConfig::UpdateConfiguration(const char *key, const std::string &value)
1341 {
1342 AppExecFwk::Configuration configuration;
1343 configuration.AddItem(key, value);
1344 auto appMgrClient = std::make_unique<AppExecFwk::AppMgrClient>();
1345 appMgrClient->UpdateConfiguration(configuration);
1346 HILOG_INFO_I18N("LocaleConfig::UpdateLanguageConfiguration update configuration finished.");
1347 }
1348
PublishCommonEvent(const std::string &eventType)1349 I18nErrorCode LocaleConfig::PublishCommonEvent(const std::string &eventType)
1350 {
1351 OHOS::AAFwk::Want localeChangeWant;
1352 localeChangeWant.SetAction(eventType);
1353 OHOS::EventFwk::CommonEventData event(localeChangeWant);
1354 if (!OHOS::EventFwk::CommonEventManager::PublishCommonEvent(event)) {
1355 HILOG_ERROR_I18N("LocaleConfig::PublishCommonEvent Failed to Publish event %{public}s",
1356 localeChangeWant.GetAction().c_str());
1357 return I18nErrorCode::PUBLISH_COMMON_EVENT_FAILED;
1358 }
1359 HILOG_INFO_I18N("LocaleConfig::PublishCommonEvent publish event finished.");
1360 return I18nErrorCode::SUCCESS;
1361 }
1362 #endif
1363
UpdateLanguageOfLocale(const std::string &languageTag)1364 std::string LocaleConfig::UpdateLanguageOfLocale(const std::string &languageTag)
1365 {
1366 // Compute language and script part from languageTag.
1367 UErrorCode status = U_ZERO_ERROR;
1368 icu::Locale languageLocale = icu::Locale::forLanguageTag(languageTag.c_str(), status);
1369 if (U_FAILURE(status)) {
1370 HILOG_ERROR_I18N("LocaleConfig::UpdateLanguageOfLocale init icu Locale for language %{public}s failed.",
1371 languageTag.c_str());
1372 return "";
1373 }
1374 std::string langTag = languageLocale.getLanguage();
1375 std::string scriptTag = languageLocale.getScript();
1376 // Compute region and extend param part from current system locale.
1377 std::string systemLocaleTag = GetSystemLocale();
1378 icu::Locale systemLocale = icu::Locale::forLanguageTag(systemLocaleTag.c_str(), status);
1379 if (U_FAILURE(status)) {
1380 HILOG_ERROR_I18N("LocaleConfig::UpdateSystemLocale init icu Locale for locale %{public}s failed.",
1381 systemLocaleTag.c_str());
1382 return "";
1383 }
1384 std::string regionTag = systemLocale.getCountry();
1385 std::string extendParamTag;
1386 size_t pos = systemLocaleTag.find("-u-");
1387 if (pos != std::string::npos) {
1388 extendParamTag = systemLocaleTag.substr(pos);
1389 }
1390 // Combine above elements.
1391 return CreateLocale(langTag, scriptTag, regionTag, extendParamTag);
1392 }
1393
CreateLocale(const std::string &languageTag, const std::string &scriptTag, const std::string ®ionTag, const std::string &extendParamTag)1394 std::string LocaleConfig::CreateLocale(const std::string &languageTag, const std::string &scriptTag,
1395 const std::string ®ionTag, const std::string &extendParamTag)
1396 {
1397 // combine language, script, region and extend param with '-'
1398 std::string localeTag = languageTag;
1399 std::string splitor = "-";
1400 if (scriptTag.length() > 0) {
1401 localeTag += splitor + scriptTag;
1402 }
1403 if (regionTag.length() > 0) {
1404 localeTag += splitor + regionTag;
1405 }
1406 if (extendParamTag.length() > 0) {
1407 localeTag += extendParamTag;
1408 }
1409 return localeTag;
1410 }
1411
UpdateRegionOfLocale(const std::string ®ionTag)1412 std::string LocaleConfig::UpdateRegionOfLocale(const std::string ®ionTag)
1413 {
1414 std::string localeTag = GetSystemLocale();
1415 // if current system locale is null, contruct a locale from region tag.
1416 if (localeTag.length() == 0) {
1417 return CreateLocaleFromRegion(regionTag);
1418 }
1419 // combine locale with origin locale's language and script with regionTag.
1420 UErrorCode status = U_ZERO_ERROR;
1421 const icu::Locale origin = icu::Locale::forLanguageTag(localeTag, status);
1422 if (U_FAILURE(status)) {
1423 HILOG_ERROR_I18N("LocaleConfig::UpdateRegionOfLocale init origin locale failed.");
1424 return "";
1425 }
1426 icu::LocaleBuilder builder = icu::LocaleBuilder().setLanguage(origin.getLanguage()).
1427 setScript(origin.getScript()).setRegion(regionTag);
1428 icu::Locale temp = builder.setExtension('u', "").build(status);
1429 string ret = temp.toLanguageTag<string>(status);
1430 if (U_FAILURE(status)) {
1431 HILOG_ERROR_I18N("LocaleConfig::UpdateRegionOfLocale obtain new locale's tag failed.");
1432 return "";
1433 }
1434 return ret;
1435 }
1436
CreateLocaleFromRegion(const std::string ®ionTag)1437 std::string LocaleConfig::CreateLocaleFromRegion(const std::string ®ionTag)
1438 {
1439 // fill locale with icu
1440 icu::Locale locale("", regionTag.c_str());
1441 UErrorCode status = U_ZERO_ERROR;
1442 locale.addLikelySubtags(status);
1443 if (U_FAILURE(status)) {
1444 HILOG_ERROR_I18N("LocaleConfig::CreateLocaleFromRegion init new locale failed.");
1445 return "";
1446 }
1447 std::string localeTag = locale.toLanguageTag<string>(status);
1448 if (U_FAILURE(status)) {
1449 HILOG_ERROR_I18N("LocaleConfig::CreateLocaleFromRegion obtain new locale's tag failed.");
1450 return "";
1451 }
1452 return localeTag;
1453 }
1454
GetLanguageKey()1455 std::string LocaleConfig::GetLanguageKey()
1456 {
1457 return LANGUAGE_KEY;
1458 }
1459
GetLocaleKey()1460 std::string LocaleConfig::GetLocaleKey()
1461 {
1462 return LOCALE_KEY;
1463 }
1464
GetHourKey()1465 std::string LocaleConfig::GetHourKey()
1466 {
1467 return HOUR_KEY;
1468 }
1469 } // namespace I18n
1470 } // namespace Global
1471 } // namespace OHOS
1472