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 ®ion)
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 ®ion)
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 ®ion)
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> ®ions = 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 ®ion)
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 ®ion, 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