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