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