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