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