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 &region)351 bool LocaleConfig::IsValidRegion(const string &region)
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 &region)444 bool LocaleConfig::IsSuggested(const std::string &language, const std::string &region)
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> &regions = 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 &region, const std::string &displayLocale)895 string LocaleConfig::GetDisplayOverrideRegion(const std::string &region, 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 &region, const string &displayLocale, bool sentenceCase)926 string LocaleConfig::GetDisplayRegion(const string &region, 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 &regionTag)1219 I18nErrorCode LocaleConfig::SetSystemRegion(const std::string &regionTag)
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 &regionTag, const std::string &extendParamTag)1394 std::string LocaleConfig::CreateLocale(const std::string &languageTag, const std::string &scriptTag,
1395     const std::string &regionTag, 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 &regionTag)1412 std::string LocaleConfig::UpdateRegionOfLocale(const std::string &regionTag)
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 &regionTag)1437 std::string LocaleConfig::CreateLocaleFromRegion(const std::string &regionTag)
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