• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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::DEFAULT_LOCALE_KEY = "const.global.locale";
56 const char *LocaleConfig::DEFAULT_LANGUAGE_KEY = "const.global.language";
57 const char *LocaleConfig::DEFAULT_REGION_KEY = "const.global.region";
58 const char *LocaleConfig::SIM_COUNTRY_CODE_KEY = "telephony.sim.countryCode0";
59 const char *LocaleConfig::SUPPORTED_LOCALES_NAME = "supported_locales";
60 const char *LocaleConfig::REGIONS_LANGUAGES_PATH = "etc/xml/i18n_param_config.xml";
61 const char *LocaleConfig::REGIONS_LANGUAGES_NAME = "i18n_param_config";
62 const char *LocaleConfig::SUPPORTED_REGIONS_NAME = "supported_regions";
63 const char *LocaleConfig::WHITE_LANGUAGES_NAME = "white_languages";
64 const char *LocaleConfig::FORBIDDEN_LANGUAGES_NAME = "forbidden_languages";
65 const char *LocaleConfig::FORBIDDEN_REGIONS_NAME = "forbidden_regions";
66 const char *LocaleConfig::SUPPORTED_LOCALES_PATH = "/system/usr/ohos_locale_config/supported_locales.xml";
67 const char *LocaleConfig::SUPPORT_LOCALES_PATH = "/etc/ohos_lang_config/supported_locales.xml";
68 const char *LocaleConfig::SUPPORT_LOCALES_NAME = "supported_locales";
69 const char *LocaleConfig::DIALECT_LANGS_PATH = "/system/usr/ohos_locale_config/dialect_languages.xml";
70 const char *LocaleConfig::DIALECT_LANGS_NAME = "dialect_langs";
71 const char *LocaleConfig::OVERRIDE_SUPPORTED_REGIONS_NAME = "supported_regions";
72 const char *LocaleConfig::OVERRIDE_SUPPORTED_REGIONS_PATH =
73     "/system/usr/ohos_locale_config/region/supported_regions.xml";
74 const char *LocaleConfig::DEFAULT_LOCALE = "en-Latn";
75 const char *LocaleConfig::supportLocalesTag = "supported_locales";
76 const char *LocaleConfig::LANG_PATH = "/etc/ohos_lang_config/";
77 const char *LocaleConfig::REGION_PATH = "/system/usr/ohos_locale_config/region/";
78 const char *LocaleConfig::rootTag = "languages";
79 const char *LocaleConfig::secondRootTag = "lang";
80 const char *LocaleConfig::rootRegion = "regions";
81 const char *LocaleConfig::secondRootRegion = "region";
82 const char *LocaleConfig::NUMBER_SYSTEM_KEY = "-nu-";
83 const std::string LocaleConfig::HOUR_EVENT_DATA = "24HourChange";
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 (status != U_ZERO_ERROR) {
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 (status != U_ZERO_ERROR) {
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 (status != U_ZERO_ERROR) {
267             return "";
268         }
269         icu::Locale locale = icu::Locale::forLanguageTag(language, status);
270         if (status != U_ZERO_ERROR) {
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 (status != U_ZERO_ERROR) {
641         return "";
642     }
643     origin.addLikelySubtags(status);
644     if (status != U_ZERO_ERROR) {
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 (status != U_ZERO_ERROR) {
651         return "";
652     }
653     string fullLanguage = temp.toLanguageTag<string>(status);
654     if (status != U_ZERO_ERROR) {
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 (status != U_ZERO_ERROR) {
663         return "";
664     }
665     fullLanguage = temp.toLanguageTag<string>(status);
666     if (status != U_ZERO_ERROR) {
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 (status != U_ZERO_ERROR) {
680             return PseudoLocalizationProcessor("");
681         }
682         icu::Locale locale = icu::Locale::forLanguageTag(language, status);
683         if (status != U_ZERO_ERROR) {
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 (status != U_ZERO_ERROR) {
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 (status != U_ZERO_ERROR) {
941         return PseudoLocalizationProcessor("");
942     }
943     icu::Locale locale = icu::Locale::forLanguageTag(displayLocale, status);
944     if (status != U_ZERO_ERROR) {
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     return is24Hour.empty();
1082 }
1083 
Is24HourClock()1084 bool LocaleConfig::Is24HourClock()
1085 {
1086     std::string is24Hour = ReadSystemParameter(HOUR_KEY, CONFIG_LEN);
1087     if (is24Hour.empty()) {
1088         std::string systemLocale = GetSystemLocale();
1089         return Is24HourLocale(systemLocale);
1090     }
1091     if (is24Hour.compare("true") == 0) {
1092         return true;
1093     }
1094     return false;
1095 }
1096 
GetSystemHour()1097 std::string LocaleConfig::GetSystemHour()
1098 {
1099     bool is24Hour = Is24HourClock();
1100     return is24Hour ? "true" : "false";
1101 }
1102 
Is24HourLocale(const std::string & systemLocale)1103 bool LocaleConfig::Is24HourLocale(const std::string& systemLocale)
1104 {
1105     static std::unordered_map<std::string, bool> is24HourLocaleMap;
1106     if (is24HourLocaleMap.find(systemLocale) != is24HourLocaleMap.end()) {
1107         return is24HourLocaleMap[systemLocale];
1108     }
1109     UErrorCode status = U_ZERO_ERROR;
1110     icu::Locale locale = icu::Locale::forLanguageTag(icu::StringPiece(systemLocale), status);
1111     if (U_FAILURE(status)) {
1112         HILOG_INFO_I18N("Is24HourLocale: %{public}s create locale failed", systemLocale.c_str());
1113         return false;
1114     }
1115 
1116     icu::UnicodeString formatPattern;
1117     icu::DateFormat* dateFormat = icu::DateFormat::createTimeInstance(icu::DateFormat::EStyle::kLong, locale);
1118     if (dateFormat == nullptr) {
1119         HILOG_INFO_I18N("Is24HourLocale: createTimeInstance failed");
1120         return false;
1121     }
1122     icu::SimpleDateFormat* simDateFormat = static_cast<icu::SimpleDateFormat*>(dateFormat);
1123     if (simDateFormat == nullptr) {
1124         HILOG_INFO_I18N("Is24HourLocale: failed to convert dateFormat");
1125         return false;
1126     }
1127     simDateFormat->toPattern(formatPattern);
1128     delete dateFormat;
1129     std::string pattern;
1130     formatPattern.toUTF8String(pattern);
1131     bool result = HasDesignator(pattern, 'H');
1132     is24HourLocaleMap[systemLocale] = result;
1133     return result;
1134 }
1135 
HasDesignator(const std::string & pattern,const char designator)1136 bool LocaleConfig::HasDesignator(const std::string& pattern, const char designator)
1137 {
1138     if (pattern.empty()) {
1139         HILOG_INFO_I18N("HasDesignator: pattern is empty");
1140         return false;
1141     }
1142     bool insideQuote = false;
1143     for (const auto& c : pattern) {
1144         if (c == '\'') {
1145             insideQuote = !insideQuote;
1146         } else if (!insideQuote) {
1147             if (c == designator) {
1148                 return true;
1149             }
1150         }
1151     }
1152     return false;
1153 }
1154 
GetUsingLocalDigit()1155 bool LocaleConfig::GetUsingLocalDigit()
1156 {
1157     std::string locale = GetSystemLocale();
1158     LocaleInfo localeInfo(locale);
1159     std::string language = localeInfo.GetLanguage();
1160     if (localDigitMap.find(language) == localDigitMap.end()) {
1161         return false;
1162     }
1163     std::string localNumberSystem = localDigitMap.at(language);
1164     if (localNumberSystem.compare(localeInfo.GetNumberingSystem()) != 0) {
1165         return false;
1166     }
1167     return true;
1168 }
1169 
GetBlockedLanguages()1170 std::unordered_set<std::string> LocaleConfig::GetBlockedLanguages()
1171 {
1172     return blockedLanguages;
1173 }
1174 
GetBlockedRegions()1175 std::unordered_set<std::string> LocaleConfig::GetBlockedRegions()
1176 {
1177     return blockedRegions;
1178 }
1179 
GetLanguageBlockedRegions()1180 std::unordered_set<std::string> LocaleConfig::GetLanguageBlockedRegions()
1181 {
1182     std::string systemLanguage = LocaleConfig::GetSystemLanguage();
1183     if (blockedLanguageRegions.find(systemLanguage) != blockedLanguageRegions.end()) {
1184         return blockedLanguageRegions[systemLanguage];
1185     }
1186     std::unordered_set<std::string> emptyResult;
1187     return emptyResult;
1188 }
1189 
SetSystemLanguage(const std::string & languageTag)1190 I18nErrorCode LocaleConfig::SetSystemLanguage(const std::string &languageTag)
1191 {
1192     if (!IsValidTag(languageTag)) {
1193         HILOG_ERROR_I18N("LocaleConfig::SetSystemLanguage %{public}s is not valid language tag.",
1194             languageTag.c_str());
1195         return I18nErrorCode::INVALID_LANGUAGE_TAG;
1196     }
1197     // save old language, reset system language to old language if update locale failed.
1198     std::string oldLanguageTag = GetSystemLanguage();
1199     if (SetParameter(LANGUAGE_KEY, languageTag.data()) != 0) {
1200         HILOG_ERROR_I18N("LocaleConfig::SetSystemLanguage update system language failed.");
1201         return I18nErrorCode::UPDATE_SYSTEM_LANGUAGE_FAILED;
1202     }
1203     std::string newLocaleTag = UpdateLanguageOfLocale(languageTag);
1204     if (SetSystemLocale(newLocaleTag) == I18nErrorCode::SUCCESS) {
1205         return I18nErrorCode::SUCCESS;
1206     }
1207     // reset system language to old language in case that system language is inconsist with system locale's lanuage.
1208     HILOG_ERROR_I18N("LocaleConfig::SetSystemLanguage update system locale failed.");
1209     SetParameter(LANGUAGE_KEY, oldLanguageTag.data());
1210     return I18nErrorCode::UPDATE_SYSTEM_LANGUAGE_FAILED;
1211 }
1212 
SetSystemRegion(const std::string & regionTag)1213 I18nErrorCode LocaleConfig::SetSystemRegion(const std::string &regionTag)
1214 {
1215     if (!IsValidRegion(regionTag)) {
1216         HILOG_ERROR_I18N("LocaleConfig::SetSystemRegion %{public}s is not valid region tag.", regionTag.c_str());
1217         return I18nErrorCode::INVALID_REGION_TAG;
1218     }
1219     return SetSystemLocale(UpdateRegionOfLocale(regionTag));
1220 }
1221 
SetSystemLocale(const std::string & localeTag)1222 I18nErrorCode LocaleConfig::SetSystemLocale(const std::string &localeTag)
1223 {
1224     if (!IsValidTag(localeTag)) {
1225         HILOG_ERROR_I18N("LocaleConfig::SetSystemLocale %{public}s is not a valid locale tag.", localeTag.c_str());
1226         return I18nErrorCode::INVALID_LOCALE_TAG;
1227     }
1228     if (SetParameter(LOCALE_KEY, localeTag.data()) != 0) {
1229         return I18nErrorCode::UPDATE_SYSTEM_LOCALE_FAILED;
1230     }
1231 #ifdef SUPPORT_GRAPHICS
1232     UpdateConfiguration(AAFwk::GlobalConfigurationKey::SYSTEM_LANGUAGE, localeTag);
1233     return PublishCommonEvent(EventFwk::CommonEventSupport::COMMON_EVENT_LOCALE_CHANGED);
1234 #else
1235     return I18nErrorCode::SUCCESS;
1236 #endif
1237 }
1238 
IsValid24HourClockValue(const std::string & tag)1239 bool LocaleConfig::IsValid24HourClockValue(const std::string &tag)
1240 {
1241     if (tag.compare("true") == 0 || tag.compare("false") == 0 || tag.length() == 0) {
1242         return true;
1243     }
1244     return false;
1245 }
1246 
Set24HourClock(const std::string & option)1247 I18nErrorCode LocaleConfig::Set24HourClock(const std::string &option)
1248 {
1249     if (!IsValid24HourClockValue(option)) {
1250         HILOG_ERROR_I18N("LocaleConfig::Set24HourClock invalid 24 Hour clock tag: %{public}s", option.c_str());
1251         return I18nErrorCode::INVALID_24_HOUR_CLOCK_TAG;
1252     }
1253     if (SetParameter(HOUR_KEY, option.data()) != 0) {
1254         HILOG_ERROR_I18N("LocaleConfig::Set24HourClock update 24 hour clock failed with option=%{public}s",
1255             option.c_str());
1256         return I18nErrorCode::UPDATE_24_HOUR_CLOCK_FAILED;
1257     }
1258 #ifdef SUPPORT_GRAPHICS
1259     UpdateConfiguration(AAFwk::GlobalConfigurationKey::SYSTEM_HOUR, option);
1260     return PublishCommonEvent(EventFwk::CommonEventSupport::COMMON_EVENT_TIME_CHANGED);
1261 #else
1262     return I18nErrorCode::SUCCESS;
1263 #endif
1264 }
1265 
SetUsingLocalDigit(bool flag)1266 I18nErrorCode LocaleConfig::SetUsingLocalDigit(bool flag)
1267 {
1268     // check whether current language support local digit.
1269     std::string localeTag = GetSystemLocale();
1270     std::string languageTag = localeTag.substr(0, 2); // obtain 2 length language code.
1271     auto it = localDigitMap.find(languageTag);
1272     if (it == localDigitMap.end()) {
1273         HILOG_ERROR_I18N("LocaleConfig::SetUsingLocalDigit current system doesn't support set local digit");
1274         return I18nErrorCode::UPDATE_LOCAL_DIGIT_FAILED;
1275     }
1276     // update system locale.
1277     return SetSystemLocale(UpdateNumberSystemOfLocale(it->second, flag));
1278 }
1279 
UpdateNumberSystemOfLocale(const std::string & localDigitTag,bool flag)1280 std::string LocaleConfig::UpdateNumberSystemOfLocale(const std::string &localDigitTag, bool flag)
1281 {
1282     if (flag) {
1283         // add local digit tag to number system param of locale
1284         return AddLocalDigitToLocale(localDigitTag);
1285     }
1286     // remove local digit tag to number system param of locale
1287     return RemoveLocalDigitFromLocale(localDigitTag);
1288 }
1289 
AddLocalDigitToLocale(const std::string & localDigitTag)1290 std::string LocaleConfig::AddLocalDigitToLocale(const std::string &localDigitTag)
1291 {
1292     std::string localeTag = GetSystemLocale();
1293     // Case: no extend param, add '-u-' and number system tag.
1294     if (localeTag.find("-u-") == std::string::npos) {
1295         localeTag += "-u" + std::string(NUMBER_SYSTEM_KEY) + localDigitTag;
1296         return localeTag;
1297     }
1298     // Case: has extend param but doesn't hava number system param, add number system tag.
1299     if (localeTag.find(NUMBER_SYSTEM_KEY) == std::string::npos) {
1300         localeTag += std::string(NUMBER_SYSTEM_KEY) + localDigitTag;
1301         return localeTag;
1302     }
1303     // Case: has number system param, replace local digit tag to localDigitTag.
1304     LocaleInfo localeInfo(localeTag);
1305     std::string oldNumberSystem = localeInfo.GetNumberingSystem();
1306     localeTag.replace(localeTag.find(oldNumberSystem), oldNumberSystem.length(), localDigitTag);
1307     return localeTag;
1308 }
1309 
RemoveLocalDigitFromLocale(const std::string & localDigitTag)1310 std::string LocaleConfig::RemoveLocalDigitFromLocale(const std::string &localDigitTag)
1311 {
1312     // remove number system tag from locale
1313     std::string localeTag = GetSystemLocale();
1314     std::string numberSystemTag = NUMBER_SYSTEM_KEY + localDigitTag;
1315     size_t pos = localeTag.find(numberSystemTag);
1316     if (pos != std::string::npos) {
1317         localeTag.replace(pos, numberSystemTag.length(), "");
1318     }
1319     // remove "-u" if localeTag ends with "-u"
1320     size_t uLength = 2;
1321     if (localeTag.find("-u") == (localeTag.length() - uLength)) {
1322         localeTag.resize(localeTag.length() - uLength);
1323     }
1324     return localeTag;
1325 }
1326 
1327 #ifdef SUPPORT_GRAPHICS
UpdateConfiguration(const char * key,const std::string & value)1328 void LocaleConfig::UpdateConfiguration(const char *key, const std::string &value)
1329 {
1330     AppExecFwk::Configuration configuration;
1331     configuration.AddItem(key, value);
1332     auto appMgrClient = std::make_unique<AppExecFwk::AppMgrClient>();
1333     appMgrClient->UpdateConfiguration(configuration);
1334     HILOG_INFO_I18N("LocaleConfig::UpdateLanguageConfiguration update configuration finished.");
1335 }
1336 
PublishCommonEvent(const std::string & eventType)1337 I18nErrorCode LocaleConfig::PublishCommonEvent(const std::string &eventType)
1338 {
1339     OHOS::AAFwk::Want localeChangeWant;
1340     localeChangeWant.SetAction(eventType);
1341     OHOS::EventFwk::CommonEventData event(localeChangeWant);
1342     if (EventFwk::CommonEventSupport::COMMON_EVENT_TIME_CHANGED.compare(eventType) == 0) {
1343         event.SetData(HOUR_EVENT_DATA);
1344     }
1345     if (!OHOS::EventFwk::CommonEventManager::PublishCommonEvent(event)) {
1346         HILOG_ERROR_I18N("LocaleConfig::PublishCommonEvent Failed to Publish event %{public}s",
1347             localeChangeWant.GetAction().c_str());
1348         return I18nErrorCode::PUBLISH_COMMON_EVENT_FAILED;
1349     }
1350     HILOG_INFO_I18N("LocaleConfig::PublishCommonEvent publish event finished.");
1351     return I18nErrorCode::SUCCESS;
1352 }
1353 #endif
1354 
UpdateLanguageOfLocale(const std::string & languageTag)1355 std::string LocaleConfig::UpdateLanguageOfLocale(const std::string &languageTag)
1356 {
1357     // Compute language and script part from languageTag.
1358     UErrorCode status = U_ZERO_ERROR;
1359     icu::Locale languageLocale = icu::Locale::forLanguageTag(languageTag.c_str(), status);
1360     if (U_FAILURE(status)) {
1361         HILOG_ERROR_I18N("LocaleConfig::UpdateLanguageOfLocale init icu Locale for language %{public}s failed.",
1362             languageTag.c_str());
1363         return "";
1364     }
1365     std::string langTag = languageLocale.getLanguage();
1366     std::string scriptTag = languageLocale.getScript();
1367     // Compute region and extend param part from current system locale.
1368     std::string systemLocaleTag = GetSystemLocale();
1369     icu::Locale systemLocale = icu::Locale::forLanguageTag(systemLocaleTag.c_str(), status);
1370     if (U_FAILURE(status)) {
1371         HILOG_ERROR_I18N("LocaleConfig::UpdateSystemLocale init icu Locale for locale %{public}s failed.",
1372             systemLocaleTag.c_str());
1373         return "";
1374     }
1375     std::string regionTag = systemLocale.getCountry();
1376     std::string extendParamTag;
1377     size_t pos = systemLocaleTag.find("-u-");
1378     if (pos != std::string::npos) {
1379         extendParamTag = systemLocaleTag.substr(pos);
1380     }
1381     // Combine above elements.
1382     return CreateLocale(langTag, scriptTag, regionTag, extendParamTag);
1383 }
1384 
CreateLocale(const std::string & languageTag,const std::string & scriptTag,const std::string & regionTag,const std::string & extendParamTag)1385 std::string LocaleConfig::CreateLocale(const std::string &languageTag, const std::string &scriptTag,
1386     const std::string &regionTag, const std::string &extendParamTag)
1387 {
1388     // combine language, script, region and extend param with '-'
1389     std::string localeTag = languageTag;
1390     std::string splitor = "-";
1391     if (scriptTag.length() > 0) {
1392         localeTag += splitor + scriptTag;
1393     }
1394     if (regionTag.length() > 0) {
1395         localeTag += splitor + regionTag;
1396     }
1397     if (extendParamTag.length() > 0) {
1398         localeTag += extendParamTag;
1399     }
1400     return localeTag;
1401 }
1402 
UpdateRegionOfLocale(const std::string & regionTag)1403 std::string LocaleConfig::UpdateRegionOfLocale(const std::string &regionTag)
1404 {
1405     std::string localeTag = GetSystemLocale();
1406     // if current system locale is null, contruct a locale from region tag.
1407     if (localeTag.length() == 0) {
1408         return CreateLocaleFromRegion(regionTag);
1409     }
1410     // combine locale with origin locale's language and script with regionTag.
1411     UErrorCode status = U_ZERO_ERROR;
1412     const icu::Locale origin = icu::Locale::forLanguageTag(localeTag, status);
1413     if (U_FAILURE(status)) {
1414         HILOG_ERROR_I18N("LocaleConfig::UpdateRegionOfLocale init origin locale failed.");
1415         return "";
1416     }
1417     icu::LocaleBuilder builder = icu::LocaleBuilder().setLanguage(origin.getLanguage()).
1418         setScript(origin.getScript()).setRegion(regionTag);
1419     icu::Locale temp = builder.setExtension('u', "").build(status);
1420     string ret = temp.toLanguageTag<string>(status);
1421     if (U_FAILURE(status)) {
1422         HILOG_ERROR_I18N("LocaleConfig::UpdateRegionOfLocale obtain new locale's tag failed.");
1423         return "";
1424     }
1425     return ret;
1426 }
1427 
CreateLocaleFromRegion(const std::string & regionTag)1428 std::string LocaleConfig::CreateLocaleFromRegion(const std::string &regionTag)
1429 {
1430     // fill locale with icu
1431     icu::Locale locale("", regionTag.c_str());
1432     UErrorCode status = U_ZERO_ERROR;
1433     locale.addLikelySubtags(status);
1434     if (U_FAILURE(status)) {
1435         HILOG_ERROR_I18N("LocaleConfig::CreateLocaleFromRegion init new locale failed.");
1436         return "";
1437     }
1438     std::string localeTag = locale.toLanguageTag<string>(status);
1439     if (U_FAILURE(status)) {
1440         HILOG_ERROR_I18N("LocaleConfig::CreateLocaleFromRegion obtain new locale's tag failed.");
1441         return "";
1442     }
1443     return localeTag;
1444 }
1445 } // namespace I18n
1446 } // namespace Global
1447 } // namespace OHOS
1448