• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2021-2024 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 #include <common_event_data.h>
22 #include <common_event_manager.h>
23 #include <common_event_publish_info.h>
24 #include <common_event_support.h>
25 #endif
26 #include <cctype>
27 #include "config_policy_utils.h"
28 #include "i18n_hilog.h"
29 #include "ipc_skeleton.h"
30 #include "libxml/parser.h"
31 #include "locale_info.h"
32 #include "locale_matcher.h"
33 #include "multi_users.h"
34 #include "unicode/localebuilder.h"
35 #include "unicode/locdspnm.h"
36 #include "unicode/locid.h"
37 #include "unicode/smpdtfmt.h"
38 #include "ohos/init_data.h"
39 #include "parameter.h"
40 #include "securec.h"
41 #include "string_ex.h"
42 #include "ucase.h"
43 #include "ulocimp.h"
44 #include "unicode/unistr.h"
45 #include "ureslocs.h"
46 #include "unicode/ustring.h"
47 #include "ustr_imp.h"
48 #include "utils.h"
49 #include "tokenid_kit.h"
50 #include "locale_config.h"
51 
52 namespace OHOS {
53 namespace Global {
54 namespace I18n {
55 using namespace std;
56 const std::string LocaleConfig::LANGUAGE_KEY = "persist.global.language";
57 const std::string LocaleConfig::LOCALE_KEY = "persist.global.locale";
58 const std::string LocaleConfig::HOUR_KEY = "persist.global.is24Hour";
59 const std::string LocaleConfig::HOUR_EVENT_DATA = "24HourChange";
60 const char *LocaleConfig::UPGRADE_LOCALE_KEY = "persist.global.upgrade_locale";
61 const char *LocaleConfig::DEFAULT_LOCALE_KEY = "const.global.locale";
62 const char *LocaleConfig::DEFAULT_LANGUAGE_KEY = "const.global.language";
63 const char *LocaleConfig::DEFAULT_REGION_KEY = "const.global.region";
64 const char *LocaleConfig::SIM_COUNTRY_CODE_KEY = "telephony.sim.countryCode0";
65 const char *LocaleConfig::SUPPORTED_LOCALES_NAME = "supported_locales";
66 const char *LocaleConfig::REGIONS_LANGUAGES_PATH = "etc/xml/i18n_param_config.xml";
67 const char *LocaleConfig::REGIONS_LANGUAGES_NAME = "i18n_param_config";
68 const char *LocaleConfig::SUPPORTED_REGIONS_NAME = "supported_regions";
69 const char *LocaleConfig::WHITE_LANGUAGES_NAME = "white_languages";
70 const char *LocaleConfig::SUPPORTED_LOCALES_PATH = "/system/usr/ohos_locale_config/supported_locales.xml";
71 const char *LocaleConfig::SUPPORTED_LOCALES_OLD_PATH = "/system/usr/ohos_locale_config/supported_locales_old.xml";
72 const char *LocaleConfig::SUPPORT_LOCALES_PATH = "/etc/ohos_lang_config/supported_locales.xml";
73 const char *LocaleConfig::SUPPORT_LOCALES_NAME = "supported_locales";
74 const char *LocaleConfig::DIALECT_LANGS_PATH = "/system/usr/ohos_locale_config/dialect_languages.xml";
75 const char *LocaleConfig::DIALECT_LANGS_NAME = "dialect_langs";
76 const char *LocaleConfig::OVERRIDE_SUPPORTED_REGIONS_NAME = "supported_regions";
77 const char *LocaleConfig::OVERRIDE_SUPPORTED_REGIONS_PATH =
78     "/system/usr/ohos_locale_config/region/supported_regions.xml";
79 const char *LocaleConfig::DEFAULT_LOCALE = "en-Latn";
80 const char *LocaleConfig::supportLocalesTag = "supported_locales";
81 const char *LocaleConfig::LANG_PATH = "/etc/ohos_lang_config/";
82 const char *LocaleConfig::REGION_PATH = "/system/usr/ohos_locale_config/region/";
83 const char *LocaleConfig::rootTag = "languages";
84 const char *LocaleConfig::secondRootTag = "lang";
85 const char *LocaleConfig::rootRegion = "regions";
86 const char *LocaleConfig::secondRootRegion = "region";
87 const std::string LocaleConfig::EXT_PARAM_KEY = "-u-";
88 const std::string LocaleConfig::NUMBER_SYSTEM_KEY = "nu";
89 const std::string LocaleConfig::TEMPERATURE_UNIT_KEY = "mu";
90 const std::string LocaleConfig::WEEK_DAY_KEY = "fw";
91 const std::string LocaleConfig::TIMEZONE_KEY = "persist.time.timezone";
92 const std::string LocaleConfig::DEFAULT_TIMEZONE = "GMT";
93 unordered_set<string> LocaleConfig::supportedLocales;
94 unordered_set<string> LocaleConfig::supportedLocalesV15;
95 unordered_set<string> LocaleConfig::supportLocales;
96 unordered_set<string> LocaleConfig::supportedRegions;
97 unordered_set<string> LocaleConfig::overrideSupportedRegions;
98 unordered_set<string> LocaleConfig::dialectLang;
99 unordered_set<string> LocaleConfig::whiteLanguages;
100 std::set<std::string> LocaleConfig::extendWhiteLanguageList;
101 std::set<std::string> LocaleConfig::extendWhiteLanguageListV15;
102 unordered_map<string, string> LocaleConfig::dialectMap {
103     { "es-Latn-419", "es-Latn-419" },
104     { "es-Latn-BO", "es-Latn-419" },
105     { "es-Latn-BR", "es-Latn-419" },
106     { "es-Latn-BZ", "es-Latn-419" },
107     { "es-Latn-CL", "es-Latn-419" },
108     { "es-Latn-CO", "es-Latn-419" },
109     { "es-Latn-CR", "es-Latn-419" },
110     { "es-Latn-CU", "es-Latn-419" },
111     { "es-Latn-DO", "es-Latn-419" },
112     { "es-Latn-EC", "es-Latn-419" },
113     { "es-Latn-GT", "es-Latn-419" },
114     { "es-Latn-HN", "es-Latn-419" },
115     { "es-Latn-MX", "es-Latn-419" },
116     { "es-Latn-NI", "es-Latn-419" },
117     { "es-Latn-PA", "es-Latn-419" },
118     { "es-Latn-PE", "es-Latn-419" },
119     { "es-Latn-PR", "es-Latn-419" },
120     { "es-Latn-PY", "es-Latn-419" },
121     { "es-Latn-SV", "es-Latn-419" },
122     { "es-Latn-US", "es-Latn-419" },
123     { "es-Latn-UY", "es-Latn-419" },
124     { "es-Latn-VE", "es-Latn-419" },
125     { "pt-Latn-PT", "pt-Latn-PT" }
126 };
127 
128 unordered_map<string, string> LocaleConfig::dialectMapV15 {
129     { "es-Latn-419", "es-Latn-419" },
130     { "es-Latn-BO", "es-Latn-419" },
131     { "es-Latn-BR", "es-Latn-419" },
132     { "es-Latn-BZ", "es-Latn-419" },
133     { "es-Latn-CL", "es-Latn-419" },
134     { "es-Latn-CO", "es-Latn-419" },
135     { "es-Latn-CR", "es-Latn-419" },
136     { "es-Latn-CU", "es-Latn-419" },
137     { "es-Latn-DO", "es-Latn-419" },
138     { "es-Latn-EC", "es-Latn-419" },
139     { "es-Latn-GT", "es-Latn-419" },
140     { "es-Latn-HN", "es-Latn-419" },
141     { "es-Latn-MX", "es-Latn-419" },
142     { "es-Latn-NI", "es-Latn-419" },
143     { "es-Latn-PA", "es-Latn-419" },
144     { "es-Latn-PE", "es-Latn-419" },
145     { "es-Latn-PR", "es-Latn-419" },
146     { "es-Latn-PY", "es-Latn-419" },
147     { "es-Latn-SV", "es-Latn-419" },
148     { "es-Latn-US", "es-Latn-419" },
149     { "es-Latn-UY", "es-Latn-419" },
150     { "es-Latn-VE", "es-Latn-419" },
151     { "pt-Latn-PT", "pt-Latn-PT" },
152     { "en-Latn-US", "en-Latn-US" }
153 };
154 
155 unordered_map<string, string> LocaleConfig::localDigitMap {
156     { "ar", "arab" },
157     { "as", "beng" },
158     { "bn", "beng" },
159     { "fa", "arabext" },
160     { "mr", "deva" },
161     { "my", "mymr" },
162     { "ne", "deva" },
163     { "ur", "latn" }
164 };
165 
166 std::unordered_map<std::string, std::vector<std::string>> LocaleConfig::dialectLanguages {
167     { "en-Latn", { "en-Latn-US", "en-Latn-GB" } },
168     { "pt-Latn", { "pt-Latn-PT", "pt-Latn-BR" } },
169     { "zh-Hant", { "zh-Hant-HK", "zh-Hant-TW" } },
170 };
171 
172 std::unordered_map<std::string, std::string> LocaleConfig::resourceIdMap {
173     { "zh", "zh-Hans" },
174     { "zh-HK", "zh-Hant-HK" },
175     { "zh-TW", "zh-Hant" },
176     { "az", "az-Latn" },
177     { "bs", "bs-Latn" },
178     { "jv", "jv-Latn" },
179     { "uz", "uz-Latn" },
180     { "mn", "mn-Cyrl" },
181 };
182 
183 std::unordered_map<TemperatureType, std::string> LocaleConfig::temperatureTypeToName {
184     { TemperatureType::CELSIUS, "celsius" },
185     { TemperatureType::FAHRENHEIT, "fahrenhe" },
186     { TemperatureType::KELVIN, "kelvin" }
187 };
188 
189 std::unordered_map<std::string, TemperatureType> LocaleConfig::nameToTemperatureType {
190     { "celsius", TemperatureType::CELSIUS },
191     { "fahrenhe", TemperatureType::FAHRENHEIT },
192     { "kelvin", TemperatureType::KELVIN }
193 };
194 
195 std::unordered_set<std::string> LocaleConfig::fahrenheitUsingRegions {
196     "BS",
197     "BZ",
198     "KY",
199     "PW",
200     "US"
201 };
202 
203 std::unordered_map<WeekDay, std::string> LocaleConfig::weekDayToName {
204     { WeekDay::MON, "mon" },
205     { WeekDay::TUE, "tue" },
206     { WeekDay::WED, "wed" },
207     { WeekDay::THU, "thu" },
208     { WeekDay::FRI, "fri" },
209     { WeekDay::SAT, "sat" },
210     { WeekDay::SUN, "sun" }
211 };
212 
213 std::unordered_map<std::string, WeekDay> LocaleConfig::nameToWeekDay {
214     { "mon", WeekDay::MON },
215     { "tue", WeekDay::TUE },
216     { "wed", WeekDay::WED },
217     { "thu", WeekDay::THU },
218     { "fri", WeekDay::FRI },
219     { "sat", WeekDay::SAT },
220     { "sun", WeekDay::SUN }
221 };
222 
223 std::unordered_map<icu::Calendar::EDaysOfWeek, WeekDay> LocaleConfig::eDaysOfWeekToWeekDay {
224     { icu::Calendar::EDaysOfWeek::MONDAY, WeekDay::MON },
225     { icu::Calendar::EDaysOfWeek::TUESDAY, WeekDay::TUE },
226     { icu::Calendar::EDaysOfWeek::WEDNESDAY, WeekDay::WED },
227     { icu::Calendar::EDaysOfWeek::THURSDAY, WeekDay::THU },
228     { icu::Calendar::EDaysOfWeek::FRIDAY, WeekDay::FRI },
229     { icu::Calendar::EDaysOfWeek::SATURDAY, WeekDay::SAT },
230     { icu::Calendar::EDaysOfWeek::SUNDAY, WeekDay::SUN }
231 };
232 
233 std::map<std::string, std::string> LocaleConfig::supportedDialectLocales;
234 std::map<string, string> LocaleConfig::locale2DisplayName {};
235 std::map<string, string> LocaleConfig::region2DisplayName {};
236 std::string LocaleConfig::currentDialectLocale = "";
237 std::string LocaleConfig::currentOverrideRegion = "";
238 std::mutex LocaleConfig::dialectLocaleMutex;
239 std::mutex LocaleConfig::region2DisplayNameMutex;
240 std::mutex LocaleConfig::locale2DisplayNameMutex;
241 
242 set<std::string> LocaleConfig::validCaTag {
243     "buddhist",
244     "chinese",
245     "coptic",
246     "dangi",
247     "ethioaa",
248     "ethiopic",
249     "gregory",
250     "hebrew",
251     "indian",
252     "islamic",
253     "islamic-umalqura",
254     "islamic-tbla",
255     "islamic-civil",
256     "islamic-rgsa",
257     "iso8601",
258     "japanese",
259     "persian",
260     "roc",
261     "islamicc",
262 };
263 set<std::string> LocaleConfig::validCoTag {
264     "big5han",
265     "compat",
266     "dict",
267     "direct",
268     "ducet",
269     "eor",
270     "gb2312",
271     "phonebk",
272     "phonetic",
273     "pinyin",
274     "reformed",
275     "searchjl",
276     "stroke",
277     "trad",
278     "unihan",
279     "zhuyin",
280 };
281 set<std::string> LocaleConfig::validKnTag {
282     "true",
283     "false",
284 };
285 set<std::string> LocaleConfig::validKfTag {
286     "upper",
287     "lower",
288     "false",
289 };
290 set<std::string> LocaleConfig::validNuTag {
291     "adlm", "ahom", "arab", "arabext", "bali", "beng",
292     "bhks", "brah", "cakm", "cham", "deva", "diak",
293     "fullwide", "gong", "gonm", "gujr", "guru", "hanidec",
294     "hmng", "hmnp", "java", "kali", "khmr", "knda",
295     "lana", "lanatham", "laoo", "latn", "lepc", "limb",
296     "mathbold", "mathdbl", "mathmono", "mathsanb", "mathsans", "mlym",
297     "modi", "mong", "mroo", "mtei", "mymr", "mymrshan",
298     "mymrtlng", "newa", "nkoo", "olck", "orya", "osma",
299     "rohg", "saur", "segment", "shrd", "sind", "sinh",
300     "sora", "sund", "takr", "talu", "tamldec", "telu",
301     "thai", "tibt", "tirh", "vaii", "wara", "wcho",
302 };
303 set<std::string> LocaleConfig::validHcTag {
304     "h12",
305     "h23",
306     "h11",
307     "h24",
308 };
309 
310 static unordered_map<string, string> g_languageMap = {
311     { "zh-Hans", "zh-Hans" },
312     { "zh-Hant-HK", "zh-Hant-HK" },
313     { "zh-Hant", "zh-Hant" },
314     { "my-Qaag", "my-Qaag" },
315     { "es-Latn-419", "es-419" },
316     { "es-Latn-US", "es-419" },
317     { "az-Latn", "az-Latn" },
318     { "bs-Latn", "bs-Latn" },
319     { "en-Latn-US", "en" },
320     { "en-Qaag", "en-Qaag" },
321     { "uz-Latn", "uz-Latn" },
322     { "sr-Latn", "sr-Latn" },
323     { "jv-Latn", "jv-Latn" },
324     { "pt-Latn-BR", "pt-BR" },
325     { "pa-Guru", "pa-Guru" },
326     { "mai-Deva", "mai-Deva" }
327 };
328 
Adjust(const string & origin)329 string Adjust(const string &origin)
330 {
331     auto iter = g_languageMap.find(origin);
332     if (iter != g_languageMap.end()) {
333         return iter->second;
334     }
335     for (iter = g_languageMap.begin(); iter != g_languageMap.end(); ++iter) {
336         string key = iter->first;
337         if (!origin.compare(0, key.length(), key)) {
338             return iter->second;
339         }
340     }
341     return origin;
342 }
343 
GetDisplayLanguageInner(const string & language,const string & displayLocaleTag,bool sentenceCase)344 string GetDisplayLanguageInner(const string &language, const string &displayLocaleTag, bool sentenceCase)
345 {
346     icu::UnicodeString unistr;
347     // 0 is the start position of language, 2 is the length of zh and fa
348     if (!language.compare(0, 2, "zh") || !language.compare(0, 2, "fa") || !language.compare(0, 2, "ro")) {
349         UErrorCode status = U_ZERO_ERROR;
350         icu::Locale displayLocale = icu::Locale::forLanguageTag(displayLocaleTag.c_str(), status);
351         if (U_FAILURE(status)) {
352             return "";
353         }
354         icu::Locale tempLocale = icu::Locale::forLanguageTag(language.c_str(), status);
355         if (U_FAILURE(status)) {
356             return "";
357         }
358         icu::LocaleDisplayNames *dspNames = icu::LocaleDisplayNames::createInstance(displayLocale,
359             UDialectHandling::ULDN_DIALECT_NAMES);
360         if (dspNames != nullptr) {
361             dspNames->localeDisplayName(tempLocale, unistr);
362             delete dspNames;
363         }
364     } else {
365         UErrorCode status = U_ZERO_ERROR;
366         icu::Locale displayLoc = icu::Locale::forLanguageTag(displayLocaleTag, status);
367         if (U_FAILURE(status)) {
368             return "";
369         }
370         icu::Locale locale = icu::Locale::forLanguageTag(language, status);
371         if (U_FAILURE(status)) {
372             return "";
373         }
374         locale.getDisplayName(displayLoc, unistr);
375     }
376     if (sentenceCase) {
377         UChar32 ch = ucase_toupper(unistr.char32At(0));
378         unistr.replace(0, 1, ch);
379     }
380     string out;
381     unistr.toUTF8String(out);
382     return out;
383 }
384 
385 bool LocaleConfig::listsInitialized = LocaleConfig::InitializeLists();
386 
GetEffectiveLanguage()387 std::string LocaleConfig::GetEffectiveLanguage()
388 {
389     std::string systemLocale = GetSystemLocale();
390     std::string systemLanguage = GetSystemLanguage();
391     return ComputeEffectiveLanguage(systemLocale, systemLanguage);
392 }
393 
GetSystemLanguage()394 string LocaleConfig::GetSystemLanguage()
395 {
396     std::string systemLanguage = ReadSystemParameter(LANGUAGE_KEY.c_str(), CONFIG_LEN);
397     if (!systemLanguage.empty()) {
398         return systemLanguage;
399     }
400     systemLanguage = ReadSystemParameter(DEFAULT_LANGUAGE_KEY, CONFIG_LEN);
401     if (systemLanguage.empty()) {
402         HILOG_ERROR_I18N("LocaleConfig::GetSystemLanguage: Read default system language failed.");
403         return "zh-Hans";
404     }
405     return systemLanguage;
406 }
407 
GetSystemRegion()408 string LocaleConfig::GetSystemRegion()
409 {
410     std::string systemRegion = GetCountry(LOCALE_KEY);
411     if (systemRegion.empty()) {
412         systemRegion = GetCountry(DEFAULT_LOCALE_KEY);
413     }
414     if (systemRegion.empty()) {
415         HILOG_ERROR_I18N("LocaleConfig::GetSystemRegion: system region is empty.");
416         return "CN";
417     }
418     return systemRegion;
419 }
420 
GetCountry(const string & parameter)421 string LocaleConfig::GetCountry(const string& parameter)
422 {
423     std::string systemRegion = ReadSystemParameter(parameter.c_str(), CONFIG_LEN);
424     if (systemRegion.empty()) {
425         HILOG_ERROR_I18N("LocaleConfig::GetCountry: ReadSystemParameter %{public}s failed.", parameter.c_str());
426         return systemRegion;
427     }
428     UErrorCode status = U_ZERO_ERROR;
429     icu::Locale origin = icu::Locale::forLanguageTag(systemRegion, status);
430     if (U_FAILURE(status)) {
431         HILOG_ERROR_I18N("LocaleConfig::GetCountry: Create icu::Locale failed.");
432         return "";
433     }
434     const char* country = origin.getCountry();
435     if (country == nullptr) {
436         HILOG_ERROR_I18N("LocaleConfig::GetCountry: Get country from icu::Locale failed.");
437         return "";
438     }
439     return country;
440 }
441 
GetSystemLocale()442 string LocaleConfig::GetSystemLocale()
443 {
444     std::string systemLocale = ReadSystemParameter(LOCALE_KEY.c_str(), CONFIG_LEN);
445     if (!systemLocale.empty()) {
446         return systemLocale;
447     }
448     HILOG_ERROR_I18N("LocaleConfig::GetSystemLocale: Read system locale failed.");
449     systemLocale = ReadSystemParameter(DEFAULT_LOCALE_KEY, CONFIG_LEN);
450     if (systemLocale.empty()) {
451         HILOG_ERROR_I18N("LocaleConfig::GetSystemLocale: Read default system locale failed.");
452         return "zh-Hans-CN";
453     }
454     return systemLocale;
455 }
456 
GetSystemTimezone()457 std::string LocaleConfig::GetSystemTimezone()
458 {
459     std::string systemTimezone = ReadSystemParameter(TIMEZONE_KEY.c_str(), CONFIG_LEN);
460     if (systemTimezone.empty()) {
461         HILOG_ERROR_I18N("LocaleConfig::GetSystemTimezone: Read system time zone failed.");
462         return DEFAULT_TIMEZONE;
463     }
464     return systemTimezone;
465 }
466 
IsValidLanguage(const string & language)467 bool LocaleConfig::IsValidLanguage(const string &language)
468 {
469     string::size_type size = language.size();
470     if ((size != LANGUAGE_LEN) && (size != LANGUAGE_LEN + 1)) {
471         return false;
472     }
473     for (size_t i = 0; i < size; ++i) {
474         if ((language[i] > 'z') || (language[i] < 'a')) {
475             return false;
476         }
477     }
478     return true;
479 }
480 
IsValidRegion(const string & region)481 bool LocaleConfig::IsValidRegion(const string &region)
482 {
483     string::size_type size = region.size();
484     if (size != LocaleInfo::REGION_LEN) {
485         return false;
486     }
487     for (size_t i = 0; i < LocaleInfo::REGION_LEN; ++i) {
488         if ((region[i] > 'Z') || (region[i] < 'A')) {
489             return false;
490         }
491     }
492     return true;
493 }
494 
IsValidTag(const string & tag)495 bool LocaleConfig::IsValidTag(const string &tag)
496 {
497     if (!tag.size()) {
498         return false;
499     }
500     vector<string> splits;
501     Split(tag, "-", splits);
502     if (!IsValidLanguage(splits[0])) {
503         return false;
504     }
505     return true;
506 }
507 
Split(const string & src,const string & sep,vector<string> & dest)508 void LocaleConfig::Split(const string &src, const string &sep, vector<string> &dest)
509 {
510     string::size_type begin = 0;
511     string::size_type end = src.find(sep);
512     while (end != string::npos) {
513         dest.push_back(src.substr(begin, end - begin));
514         begin = end + sep.size();
515         end = src.find(sep, begin);
516     }
517     if (begin != src.size()) {
518         dest.push_back(src.substr(begin));
519     }
520 }
521 
Split(const string & src,const string & sep,std::unordered_set<string> & dest)522 void LocaleConfig::Split(const string &src, const string &sep, std::unordered_set<string> &dest)
523 {
524     string::size_type begin = 0;
525     string::size_type end = src.find(sep);
526     while (end != string::npos) {
527         dest.insert(src.substr(begin, end - begin));
528         begin = end + sep.size();
529         end = src.find(sep, begin);
530     }
531     if (begin != src.size()) {
532         dest.insert(src.substr(begin));
533     }
534 }
535 
536 // language in white languages should have script.
GetSystemLanguages()537 std::unordered_set<std::string> LocaleConfig::GetSystemLanguages()
538 {
539     std::unordered_set<std::string> result(whiteLanguages);
540     std::unordered_set<string> blockedLanguages = GetBlockedLanguages();
541     Expunge(result, blockedLanguages);
542     return result;
543 }
544 
GetSupportedLocales()545 const unordered_set<string>& LocaleConfig::GetSupportedLocales()
546 {
547     return supportedLocales;
548 }
549 
GetSupportedLocalesV15()550 const unordered_set<string>& LocaleConfig::GetSupportedLocalesV15()
551 {
552     return supportedLocalesV15;
553 }
554 
GetSupportedRegions()555 const unordered_set<string>& LocaleConfig::GetSupportedRegions()
556 {
557     return supportedRegions;
558 }
559 
GetSystemCountries(const std::string & language)560 std::unordered_set<std::string> LocaleConfig::GetSystemCountries(const std::string& language)
561 {
562     std::unordered_set<std::string> result(supportedRegions);
563     std::unordered_set<std::string> blockedRegion = LocaleConfig::GetBlockedRegions(language);
564     Expunge(result, blockedRegion);
565     return result;
566 }
567 
IsSuggested(const string & language)568 bool LocaleConfig::IsSuggested(const string &language)
569 {
570     unordered_set<string> relatedLocales;
571     vector<string> simCountries;
572     GetCountriesFromSim(simCountries);
573     GetRelatedLocales(relatedLocales, simCountries);
574     for (auto iter = relatedLocales.begin(); iter != relatedLocales.end();) {
575         if (extendWhiteLanguageList.find(*iter) == extendWhiteLanguageList.end()) {
576             iter = relatedLocales.erase(iter);
577         } else {
578             ++iter;
579         }
580     }
581     string mainLanguage = GetMainLanguage(language, dialectMap);
582     return relatedLocales.find(mainLanguage) != relatedLocales.end();
583 }
584 
IsSuggested(const std::string & language,const std::string & region)585 bool LocaleConfig::IsSuggested(const std::string &language, const std::string &region)
586 {
587     unordered_set<string> relatedLocales;
588     vector<string> countries { region };
589     GetRelatedLocales(relatedLocales, countries);
590     for (auto iter = relatedLocales.begin(); iter != relatedLocales.end();) {
591         if (extendWhiteLanguageList.find(*iter) == extendWhiteLanguageList.end()) {
592             iter = relatedLocales.erase(iter);
593         } else {
594             ++iter;
595         }
596     }
597     string mainLanguage = GetMainLanguage(language, dialectMap);
598     return relatedLocales.find(mainLanguage) != relatedLocales.end();
599 }
600 
IsSuggestedV15(const string & language)601 bool LocaleConfig::IsSuggestedV15(const string &language)
602 {
603     unordered_set<string> relatedLocales;
604     vector<string> simCountries;
605     GetCountriesFromSim(simCountries);
606     GetRelatedLocalesV15(relatedLocales, simCountries);
607     auto iter = relatedLocales.begin();
608     while (iter != relatedLocales.end()) {
609         if (extendWhiteLanguageListV15.find(*iter) == extendWhiteLanguageListV15.end()) {
610             iter = relatedLocales.erase(iter);
611         } else {
612             ++iter;
613         }
614     }
615     string mainLanguage = GetMainLanguage(language, dialectMapV15);
616     return relatedLocales.find(mainLanguage) != relatedLocales.end();
617 }
618 
IsSuggestedV15(const std::string & language,const std::string & region)619 bool LocaleConfig::IsSuggestedV15(const std::string &language, const std::string &region)
620 {
621     unordered_set<string> relatedLocales;
622     vector<string> countries { region };
623     GetRelatedLocalesV15(relatedLocales, countries);
624     auto iter = relatedLocales.begin();
625     while (iter != relatedLocales.end()) {
626         if (extendWhiteLanguageListV15.find(*iter) == extendWhiteLanguageListV15.end()) {
627             iter = relatedLocales.erase(iter);
628         } else {
629             ++iter;
630         }
631     }
632     string mainLanguage = GetMainLanguage(language, dialectMapV15);
633     return relatedLocales.find(mainLanguage) != relatedLocales.end();
634 }
635 
ExtendWhiteLanguages()636 void LocaleConfig::ExtendWhiteLanguages()
637 {
638     UErrorCode status = U_ZERO_ERROR;
639     for (auto iter = whiteLanguages.begin(); iter != whiteLanguages.end(); ++iter) {
640         extendWhiteLanguageList.insert(*iter);
641         extendWhiteLanguageListV15.insert(*iter);
642         icu::Locale locale = icu::Locale::forLanguageTag((*iter).c_str(), status);
643         locale.addLikelySubtags(status);
644         if (U_FAILURE(status)) {
645             HILOG_INFO_I18N("create Locale object for %{public}s failed.", (*iter).c_str());
646             continue;
647         }
648         const char* baseName = locale.getBaseName();
649         if (baseName != nullptr) {
650             std::string baseNameStr(baseName);
651             std::replace(baseNameStr.begin(), baseNameStr.end(), '_', '-');
652             extendWhiteLanguageList.insert(baseNameStr);
653             extendWhiteLanguageListV15.insert(baseNameStr);
654         }
655         const char* language = locale.getLanguage();
656         if (language != nullptr) {
657             std::string languageStr(language);
658             ExtendLanguageWithScript(languageStr);
659         }
660     }
661 }
662 
ExtendLanguageWithScript(const std::string & languageStr)663 void LocaleConfig::ExtendLanguageWithScript(const std::string &languageStr)
664 {
665     if (languageStr.empty()) {
666         HILOG_INFO_I18N("ExtendLanguageWithScript languageStr is empty.");
667         return;
668     }
669     string mainLanguage = GetMainLanguage(languageStr, dialectMap);
670     if (!mainLanguage.empty()) {
671         extendWhiteLanguageList.insert(mainLanguage);
672     }
673 }
674 
GetRelatedLocales(unordered_set<string> & relatedLocales,vector<string> countries)675 void LocaleConfig::GetRelatedLocales(unordered_set<string> &relatedLocales, vector<string> countries)
676 {
677     // remove unsupported countries
678     const unordered_set<string> &regions = GetSupportedRegions();
679     auto iter = countries.begin();
680     while (iter != countries.end()) {
681         if (regions.find(*iter) == regions.end()) {
682             iter = countries.erase(iter);
683         } else {
684             ++iter;
685         }
686     }
687     const unordered_set<string> &locales = GetSupportedLocales();
688     for (const string &locale : locales) {
689         bool find = false;
690         for (string &country : countries) {
691             if (locale.find(country) != string::npos) {
692                 find = true;
693                 break;
694             }
695         }
696         if (!find) {
697             continue;
698         }
699         string mainLanguage = GetMainLanguage(locale, dialectMap);
700         if (!mainLanguage.empty()) {
701             relatedLocales.insert(mainLanguage);
702         }
703     }
704 }
705 
GetRelatedLocalesV15(unordered_set<string> & relatedLocales,vector<string> countries)706 void LocaleConfig::GetRelatedLocalesV15(unordered_set<string> &relatedLocales, vector<string> countries)
707 {
708     // remove unsupported countries
709     const unordered_set<string> &regions = GetSupportedRegions();
710     auto iter = countries.begin();
711     while (iter != countries.end()) {
712         if (regions.find(*iter) == regions.end()) {
713             iter = countries.erase(iter);
714         } else {
715             ++iter;
716         }
717     }
718     const unordered_set<string> &locales = GetSupportedLocalesV15();
719     for (const string &locale : locales) {
720         bool find = false;
721         for (const string &country : countries) {
722             if (locale.find(country) != string::npos) {
723                 find = true;
724                 break;
725             }
726         }
727         if (!find) {
728             continue;
729         }
730         string mainLanguage = GetMainLanguage(locale, dialectMapV15);
731         if (!mainLanguage.empty()) {
732             relatedLocales.insert(mainLanguage);
733         }
734     }
735 }
736 
GetCountriesFromSim(vector<string> & simCountries)737 void LocaleConfig::GetCountriesFromSim(vector<string> &simCountries)
738 {
739     simCountries.push_back(GetSystemRegion());
740     char value[CONFIG_LEN];
741     int code = GetParameter(SIM_COUNTRY_CODE_KEY, "", value, CONFIG_LEN);
742     if (code > 0) {
743         simCountries.push_back(value);
744     }
745 }
746 
GetListFromFile(const char * path,const char * resourceName,unordered_set<string> & ret)747 void LocaleConfig::GetListFromFile(const char *path, const char *resourceName, unordered_set<string> &ret)
748 {
749     xmlKeepBlanksDefault(0);
750     if (!path) {
751         return;
752     }
753     xmlDocPtr doc = xmlParseFile(path);
754     if (!doc) {
755         return;
756     }
757     xmlNodePtr cur = xmlDocGetRootElement(doc);
758     if (!cur || xmlStrcmp(cur->name, reinterpret_cast<const xmlChar *>(resourceName))) {
759         xmlFreeDoc(doc);
760         return;
761     }
762     cur = cur->xmlChildrenNode;
763     xmlChar *content = nullptr;
764     while (cur != nullptr) {
765         content = xmlNodeGetContent(cur);
766         if (content != nullptr) {
767             ret.insert(reinterpret_cast<const char*>(content));
768             xmlFree(content);
769             cur = cur->next;
770         } else {
771             break;
772         }
773     }
774     xmlFreeDoc(doc);
775 }
776 
Expunge(unordered_set<string> & src,const unordered_set<string> & another)777 void LocaleConfig::Expunge(unordered_set<string> &src, const unordered_set<string> &another)
778 {
779     for (auto iter = src.begin(); iter != src.end();) {
780         if (another.find(*iter) != another.end()) {
781             iter = src.erase(iter);
782         } else {
783             ++iter;
784         }
785     }
786 }
787 
InitializeLists()788 bool LocaleConfig::InitializeLists()
789 {
790     SetHwIcuDirectory();
791     LoadRegionsLanguages();
792     GetListFromFile(SUPPORTED_LOCALES_PATH, SUPPORTED_LOCALES_NAME, supportedLocales);
793     GetListFromFile(SUPPORTED_LOCALES_OLD_PATH, SUPPORTED_LOCALES_NAME, supportedLocalesV15);
794     GetListFromFile(SUPPORT_LOCALES_PATH, SUPPORT_LOCALES_NAME, supportLocales);
795     GetListFromFile(OVERRIDE_SUPPORTED_REGIONS_PATH, OVERRIDE_SUPPORTED_REGIONS_NAME, overrideSupportedRegions);
796     GetListFromFile(DIALECT_LANGS_PATH, DIALECT_LANGS_NAME, dialectLang);
797     ExtendWhiteLanguages();
798     return true;
799 }
800 
CleanupXmlResources()801 __attribute__((destructor)) void LocaleConfig::CleanupXmlResources()
802 {
803     if (listsInitialized) {
804         xmlCleanupParser();
805     }
806 }
807 
LoadRegionsLanguages()808 void LocaleConfig::LoadRegionsLanguages()
809 {
810     char buf[MAX_PATH_LEN] = {0};
811     char* path = GetOneCfgFile(REGIONS_LANGUAGES_PATH, buf, MAX_PATH_LEN);
812     xmlKeepBlanksDefault(0);
813     if (!path) {
814         return;
815     }
816     xmlDocPtr doc = xmlParseFile(path);
817     if (!doc) {
818         return;
819     }
820     xmlNodePtr cur = xmlDocGetRootElement(doc);
821     if (!cur || xmlStrcmp(cur->name, reinterpret_cast<const xmlChar *>(REGIONS_LANGUAGES_NAME))) {
822         xmlFreeDoc(doc);
823         return;
824     }
825     cur = cur->xmlChildrenNode;
826     xmlChar *content = nullptr;
827     while (cur != nullptr) {
828         content = xmlNodeGetContent(cur);
829         if (content != nullptr && !xmlStrcmp(cur->name, reinterpret_cast<const xmlChar *>(SUPPORTED_REGIONS_NAME))) {
830             Split(reinterpret_cast<const char*>(content), ",", supportedRegions);
831         } else if (content != nullptr && !xmlStrcmp(cur->name,
832             reinterpret_cast<const xmlChar *>(WHITE_LANGUAGES_NAME))) {
833             Split(reinterpret_cast<const char*>(content), ",", whiteLanguages);
834         }
835         if (content != nullptr) {
836             xmlFree(content);
837         }
838         cur = cur->next;
839     }
840     xmlFreeDoc(doc);
841 }
842 
GetMainLanguage(const string & language,std::unordered_map<std::string,std::string> selfDialectMap)843 string LocaleConfig::GetMainLanguage(const string &language,
844     std::unordered_map<std::string, std::string> selfDialectMap)
845 {
846     UErrorCode status = U_ZERO_ERROR;
847     icu::Locale origin = icu::Locale::forLanguageTag(language, status);
848     if (U_FAILURE(status)) {
849         return "";
850     }
851     origin.addLikelySubtags(status);
852     if (U_FAILURE(status)) {
853         return "";
854     }
855     icu::LocaleBuilder builder = icu::LocaleBuilder().setLanguage(origin.getLanguage()).
856         setScript(origin.getScript()).setRegion(origin.getCountry());
857     icu::Locale temp = builder.setExtension('u', "").build(status);
858     if (U_FAILURE(status)) {
859         return "";
860     }
861     string fullLanguage = temp.toLanguageTag<string>(status);
862     if (U_FAILURE(status)) {
863         return "";
864     }
865     if (selfDialectMap.find(fullLanguage) != selfDialectMap.end()) {
866         return selfDialectMap[fullLanguage];
867     }
868     builder.setRegion("");
869     temp = builder.build(status);
870     if (U_FAILURE(status)) {
871         return "";
872     }
873     fullLanguage = temp.toLanguageTag<string>(status);
874     if (U_FAILURE(status)) {
875         return "";
876     }
877     return fullLanguage;
878 }
879 
GetDisplayLanguage(const string & language,const string & displayLocale,bool sentenceCase)880 string LocaleConfig::GetDisplayLanguage(const string &language, const string &displayLocale, bool sentenceCase)
881 {
882     std::string result;
883     string adjust = Adjust(language);
884     if (adjust == language) {
885         UErrorCode status = U_ZERO_ERROR;
886         icu::Locale displayLoc = icu::Locale::forLanguageTag(displayLocale, status);
887         if (U_FAILURE(status)) {
888             return PseudoLocalizationProcessor("");
889         }
890         icu::Locale locale = icu::Locale::forLanguageTag(language, status);
891         if (U_FAILURE(status)) {
892             return PseudoLocalizationProcessor("");
893         }
894         icu::UnicodeString unistr;
895         std::string lang(locale.getLanguage());
896         if (dialectLang.find(lang) != dialectLang.end()) {
897             result = GetDisplayLanguageWithDialect(language, displayLocale);
898         }
899     }
900     if (result.empty()) {
901         result = GetDisplayLanguageInner(adjust, displayLocale, sentenceCase);
902     }
903     TabooUtils* tabooUtils = TabooUtils::GetInstance();
904     if (tabooUtils != nullptr) {
905         result = tabooUtils->ReplaceLanguageName(adjust, displayLocale, result);
906     } else {
907         HILOG_ERROR_I18N("LocaleConfig::GetDisplayLanguage: tabooUtils is nullptr.");
908     }
909     if (sentenceCase && !result.empty()) {
910         char ch = static_cast<char>(toupper(result[0]));
911         return PseudoLocalizationProcessor(result.replace(0, 1, 1, ch));
912     }
913     return PseudoLocalizationProcessor(result);
914 }
915 
ComputeLocale(const std::string & displayLocale)916 std::string LocaleConfig::ComputeLocale(const std::string &displayLocale)
917 {
918     if (supportedDialectLocales.size() == 0) {
919         xmlKeepBlanksDefault(0);
920         xmlDocPtr doc = xmlParseFile(SUPPORT_LOCALES_PATH);
921         if (!doc) {
922             return "";
923         }
924         xmlNodePtr cur = xmlDocGetRootElement(doc);
925         if (!cur || xmlStrcmp(cur->name, reinterpret_cast<const xmlChar *>(supportLocalesTag))) {
926             xmlFreeDoc(doc);
927             HILOG_INFO_I18N("can not parse language supported locale file");
928             return "";
929         }
930         cur = cur->xmlChildrenNode;
931         while (cur != nullptr) {
932             xmlChar *content = xmlNodeGetContent(cur);
933             if (content == nullptr) {
934                 HILOG_INFO_I18N("get xml node content failed");
935                 break;
936             }
937             std::map<std::string, std::string> localeInfoConfigs = {};
938             LocaleInfo localeinfo(reinterpret_cast<const char*>(content), localeInfoConfigs);
939             std::string maximizeLocale = localeinfo.Maximize();
940             const char* key = maximizeLocale.c_str();
941             const char* value = reinterpret_cast<const char*>(content);
942             SetSupportedDialectLocales(key, value);
943             xmlFree(content);
944             cur = cur->next;
945         }
946         xmlFreeDoc(doc);
947     }
948     std::map<std::string, std::string> configs = {};
949     LocaleInfo localeinfo(displayLocale, configs);
950     std::string maximizeLocale = localeinfo.Maximize();
951     if (supportedDialectLocales.find(maximizeLocale) != supportedDialectLocales.end()) {
952         return supportedDialectLocales.at(maximizeLocale);
953     }
954     return "";
955 }
956 
SetSupportedDialectLocales(const char * key,const char * value)957 void LocaleConfig::SetSupportedDialectLocales(const char* key, const char* value)
958 {
959     std::lock_guard<std::mutex> dialectLocaleLock(dialectLocaleMutex);
960     supportedDialectLocales.insert(
961         std::make_pair<std::string, std::string>(key, value));
962 }
963 
ReadLangData(const char * langDataPath)964 void LocaleConfig::ReadLangData(const char *langDataPath)
965 {
966     xmlKeepBlanksDefault(0);
967     if (langDataPath == nullptr) {
968         return;
969     }
970     xmlDocPtr doc = xmlParseFile(langDataPath);
971     if (!doc) {
972         HILOG_INFO_I18N("can not open language data file");
973         return;
974     }
975     xmlNodePtr cur = xmlDocGetRootElement(doc);
976     if (!cur || xmlStrcmp(cur->name, reinterpret_cast<const xmlChar *>(rootTag))) {
977         xmlFreeDoc(doc);
978         HILOG_INFO_I18N("parse language data file failed");
979         return;
980     }
981     cur = cur->xmlChildrenNode;
982     while (cur != nullptr && !xmlStrcmp(cur->name, reinterpret_cast<const xmlChar *>(secondRootTag))) {
983         xmlChar *langContents[ELEMENT_NUM] = { 0 }; // 2 represent langid, displayname;
984         xmlNodePtr langValue = cur->xmlChildrenNode;
985         bool xmlNodeNull = false;
986         for (size_t i = 0; i < ELEMENT_NUM && langValue != nullptr; i++) {
987             langContents[i] = xmlNodeGetContent(langValue);
988             langValue = langValue->next;
989             if (langContents[i] == nullptr) {
990                 xmlNodeNull = true;
991             }
992         }
993         if (!xmlNodeNull) {
994             // 0 represents langid index, 1 represents displayname index
995             const char* key = reinterpret_cast<const char *>(langContents[0]);
996             const char* value = reinterpret_cast<const char *>(langContents[1]);
997             SetLocale2DisplayName(key, value);
998         }
999         for (size_t i = 0; i < ELEMENT_NUM; i++) {
1000             if (langContents[i] != nullptr) {
1001                 xmlFree(langContents[i]);
1002             }
1003         }
1004         cur = cur->next;
1005     }
1006     xmlFreeDoc(doc);
1007 }
1008 
SetRegion2DisplayName(const char * key,const char * value)1009 void LocaleConfig::SetRegion2DisplayName(const char* key, const char* value)
1010 {
1011     std::lock_guard<std::mutex> regionDisplayLock(region2DisplayNameMutex);
1012     region2DisplayName.insert(
1013         std::make_pair<std::string, std::string>(key, value));
1014 }
1015 
SetLocale2DisplayName(const char * key,const char * value)1016 void LocaleConfig::SetLocale2DisplayName(const char* key, const char* value)
1017 {
1018     std::lock_guard<std::mutex> localeDisplayLock(locale2DisplayNameMutex);
1019     locale2DisplayName.insert(
1020         std::make_pair<std::string, std::string>(key, value));
1021 }
1022 
ReadRegionData(const char * regionDataPath)1023 void LocaleConfig::ReadRegionData(const char *regionDataPath)
1024 {
1025     xmlKeepBlanksDefault(0);
1026     if (regionDataPath == nullptr) {
1027         return;
1028     }
1029     xmlDocPtr doc = xmlParseFile(regionDataPath);
1030     if (!doc) {
1031         HILOG_INFO_I18N("can not open region data file");
1032         return;
1033     }
1034     xmlNodePtr cur = xmlDocGetRootElement(doc);
1035     if (cur) {
1036         HILOG_INFO_I18N("cur pointer is true");
1037     }
1038     if (!cur || xmlStrcmp(cur->name, reinterpret_cast<const xmlChar *>(rootRegion))) {
1039         xmlFreeDoc(doc);
1040         HILOG_INFO_I18N("parse region data file failed");
1041         return;
1042     }
1043     cur = cur->xmlChildrenNode;
1044     while (cur != nullptr && !xmlStrcmp(cur->name, reinterpret_cast<const xmlChar *>(secondRootRegion))) {
1045         xmlChar *regionContents[ELEMENT_NUM] = { 0 };
1046         xmlNodePtr regionValue = cur->xmlChildrenNode;
1047         bool xmlNodeNull = false;
1048         for (size_t i = 0; i < ELEMENT_NUM && regionValue != nullptr; i++) {
1049             regionContents[i] = xmlNodeGetContent(regionValue);
1050             regionValue = regionValue->next;
1051             if (regionContents[i] == nullptr) {
1052                 xmlNodeNull = true;
1053             }
1054         }
1055         if (!xmlNodeNull) {
1056             // 0 represents langid index, 1 represents displayname index
1057             const char* regionKey = reinterpret_cast<const char *>(regionContents[0]);
1058             const char* regionVal = reinterpret_cast<const char *>(regionContents[1]);
1059             SetRegion2DisplayName(regionKey, regionVal);
1060         }
1061         for (size_t i = 0; i < ELEMENT_NUM; i++) {
1062             if (regionContents[i] != nullptr) {
1063                 xmlFree(regionContents[i]);
1064             }
1065         }
1066         cur = cur->next;
1067     }
1068     xmlFreeDoc(doc);
1069 }
1070 
GetDisplayLanguageWithDialect(const std::string & localeStr,const std::string & displayLocale)1071 string LocaleConfig::GetDisplayLanguageWithDialect(const std::string &localeStr, const std::string &displayLocale)
1072 {
1073     std::string finalLocale = ComputeLocale(displayLocale);
1074     if (finalLocale.empty()) {
1075         return "";
1076     }
1077     if (finalLocale.compare(currentDialectLocale) != 0) {
1078         std::string xmlPath = LANG_PATH + finalLocale + ".xml";
1079         locale2DisplayName.clear();
1080         ReadLangData(xmlPath.c_str());
1081         currentDialectLocale = finalLocale;
1082     }
1083     if (locale2DisplayName.find(localeStr) != locale2DisplayName.end()) {
1084         return locale2DisplayName.at(localeStr);
1085     }
1086     std::map<std::string, std::string> configs = {};
1087     LocaleInfo locale(localeStr, configs);
1088     std::string language = locale.GetLanguage();
1089     std::string scripts = locale.GetScript();
1090     std::string region = locale.GetRegion();
1091     if (scripts.length() != 0) {
1092         std::string languageAndScripts = language + "-" + scripts;
1093         if (locale2DisplayName.find(languageAndScripts) != locale2DisplayName.end()) {
1094             return locale2DisplayName.at(languageAndScripts);
1095         }
1096     }
1097     if (region.length() != 0) {
1098         std::string languageAndRegion = language + "-" + region;
1099         if (locale2DisplayName.find(languageAndRegion) != locale2DisplayName.end()) {
1100             return locale2DisplayName.at(languageAndRegion);
1101         }
1102     }
1103     if (locale2DisplayName.find(language) != locale2DisplayName.end()) {
1104         return locale2DisplayName.at(language);
1105     }
1106     return "";
1107 }
1108 
GetDisplayOverrideRegion(const std::string & region,const std::string & displayLocale)1109 string LocaleConfig::GetDisplayOverrideRegion(const std::string &region, const std::string &displayLocale)
1110 {
1111     UErrorCode status = U_ZERO_ERROR;
1112     icu::Locale originLocale;
1113     icu::UnicodeString displayRegion;
1114     if (displayLocale.compare(currentOverrideRegion) != 0) {
1115         std::string xmlPath = REGION_PATH + displayLocale + ".xml";
1116         region2DisplayName.clear();
1117         ReadRegionData(xmlPath.c_str());
1118         currentOverrideRegion = displayLocale;
1119     }
1120     if (region2DisplayName.find(region) != region2DisplayName.end()) {
1121         return region2DisplayName.at(region);
1122     } else {
1123         icu::Locale locale = icu::Locale::forLanguageTag(displayLocale, status);
1124         if (U_FAILURE(status)) {
1125             return "";
1126         }
1127         if (IsValidRegion(region)) {
1128             icu::LocaleBuilder builder = icu::LocaleBuilder().setRegion(region);
1129             originLocale = builder.build(status);
1130         } else {
1131             originLocale = icu::Locale::forLanguageTag(region, status);
1132         }
1133         originLocale.getDisplayCountry(locale, displayRegion);
1134         std::string result;
1135         displayRegion.toUTF8String(result);
1136         return result;
1137     }
1138 }
1139 
GetDisplayRegion(const string & region,const string & displayLocale,bool sentenceCase)1140 string LocaleConfig::GetDisplayRegion(const string &region, const string &displayLocale, bool sentenceCase)
1141 {
1142     UErrorCode status = U_ZERO_ERROR;
1143     icu::Locale originLocale;
1144     if (IsValidRegion(region)) {
1145         icu::LocaleBuilder builder = icu::LocaleBuilder().setRegion(region);
1146         originLocale = builder.build(status);
1147     } else {
1148         originLocale = icu::Locale::forLanguageTag(region, status);
1149     }
1150     std::string country(originLocale.getCountry());
1151     if (country.length() == 0) {
1152         return PseudoLocalizationProcessor("");
1153     }
1154     if (U_FAILURE(status)) {
1155         return PseudoLocalizationProcessor("");
1156     }
1157     icu::Locale locale = icu::Locale::forLanguageTag(displayLocale, status);
1158     if (U_FAILURE(status)) {
1159         return PseudoLocalizationProcessor("");
1160     }
1161     icu::UnicodeString unistr;
1162     icu::UnicodeString displayRegion;
1163     std::string result;
1164     if (overrideSupportedRegions.find(displayLocale) != overrideSupportedRegions.end()) {
1165         result = GetDisplayOverrideRegion(region, displayLocale);
1166     } else {
1167         originLocale.getDisplayCountry(locale, displayRegion);
1168         displayRegion.toUTF8String(result);
1169     }
1170     TabooUtils* tabooUtils = TabooUtils::GetInstance();
1171     if (tabooUtils != nullptr) {
1172         result = tabooUtils->ReplaceCountryName(region, displayLocale, result);
1173     } else {
1174         HILOG_ERROR_I18N("LocaleConfig::GetDisplayRegion: tabooUtils is nullptr.");
1175     }
1176     if (sentenceCase) {
1177         char ch = static_cast<char>(toupper(result[0]));
1178         return PseudoLocalizationProcessor(result.replace(0, 1, 1, ch));
1179     }
1180     return PseudoLocalizationProcessor(result);
1181 }
1182 
IsRTL(const string & locale)1183 bool LocaleConfig::IsRTL(const string &locale)
1184 {
1185     icu::Locale curLocale(locale.c_str());
1186     return curLocale.isRightToLeft();
1187 }
1188 
parseExtension(const std::string & extension,std::map<std::string,std::string> & map)1189 void parseExtension(const std::string &extension, std::map<std::string, std::string> &map)
1190 {
1191     std::string pattern = "-..-";
1192     std::regex express(pattern);
1193 
1194     std::regex_token_iterator<std::string::const_iterator> begin1(extension.cbegin(), extension.cend(), express);
1195     std::regex_token_iterator<std::string::const_iterator> begin2(extension.cbegin(), extension.cend(), express, -1);
1196     begin2++;
1197     for (; begin1 != std::sregex_token_iterator() && begin2 != std::sregex_token_iterator(); begin1++, begin2++) {
1198         map.insert(std::pair<std::string, std::string>(begin1->str(), begin2->str()));
1199     }
1200 }
1201 
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)1202 void setExtension(std::string &extension, const std::string &tag, const std::set<string> &validValue,
1203     const std::map<std::string, std::string> &extensionMap,
1204     const std::map<std::string, std::string> &defaultExtensionMap)
1205 {
1206     std::string value;
1207     auto it = extensionMap.find(tag);
1208     if (it != extensionMap.end()) {
1209         value = it->second;
1210         if (validValue.find(value) == validValue.end()) {
1211             return;
1212         } else {
1213             extension += tag;
1214             extension += value;
1215         }
1216     } else {
1217         it = defaultExtensionMap.find(tag);
1218         if (it != defaultExtensionMap.end()) {
1219             value = it->second;
1220             if (validValue.find(value) == validValue.end()) {
1221                 return;
1222             } else {
1223                 extension += tag;
1224                 extension += value;
1225             }
1226         }
1227     }
1228 }
1229 
setOtherExtension(std::string & extension,std::map<std::string,std::string> & extensionMap,std::map<std::string,std::string> & defaultExtensionMap)1230 void setOtherExtension(std::string &extension, std::map<std::string, std::string> &extensionMap,
1231     std::map<std::string, std::string> &defaultExtensionMap)
1232 {
1233     std::set<std::string> tags;
1234     tags.insert("-ca-");
1235     tags.insert("-co-");
1236     tags.insert("-kn-");
1237     tags.insert("-kf-");
1238     tags.insert("-nu-");
1239     tags.insert("-hc-");
1240 
1241     for (auto it = tags.begin(); it != tags.end(); it++) {
1242         extensionMap.erase(*it);
1243         defaultExtensionMap.erase(*it);
1244     }
1245 
1246     for (auto it = defaultExtensionMap.begin(); it != defaultExtensionMap.end(); it++) {
1247         extensionMap.insert(std::pair<std::string, std::string>(it->first, it->second));
1248     }
1249 
1250     for (auto it = extensionMap.begin(); it != extensionMap.end(); it++) {
1251         extension += it->first;
1252         extension += it->second;
1253     }
1254 }
1255 
GetValidLocale(const std::string & localeTag)1256 std::string LocaleConfig::GetValidLocale(const std::string &localeTag)
1257 {
1258     std::string baseLocale = "";
1259     std::string extension = "";
1260     std::size_t found = localeTag.find(EXT_PARAM_KEY);
1261     baseLocale = localeTag.substr(0, found);
1262     if (found != std::string::npos) {
1263         extension = localeTag.substr(found);
1264     }
1265     std::map<std::string, std::string> extensionMap;
1266     if (extension != "") {
1267         parseExtension(extension, extensionMap);
1268     }
1269 
1270     std::string systemLocaleTag = GetSystemLocale();
1271     std::string defaultExtension = "";
1272     found = systemLocaleTag.find(EXT_PARAM_KEY);
1273     if (found != std::string::npos) {
1274         defaultExtension = systemLocaleTag.substr(found);
1275     }
1276     std::map<std::string, std::string> defaultExtensionMap;
1277     if (defaultExtension != "") {
1278         parseExtension(defaultExtension, defaultExtensionMap);
1279     }
1280 
1281     std::string ext = "";
1282     setExtension(ext, "-ca-", validCaTag, extensionMap, defaultExtensionMap);
1283     setExtension(ext, "-co-", validCoTag, extensionMap, defaultExtensionMap);
1284     setExtension(ext, "-kn-", validKnTag, extensionMap, defaultExtensionMap);
1285     setExtension(ext, "-kf-", validKfTag, extensionMap, defaultExtensionMap);
1286     setExtension(ext, "-nu-", validNuTag, extensionMap, defaultExtensionMap);
1287     setExtension(ext, "-hc-", validHcTag, extensionMap, defaultExtensionMap);
1288 
1289     std::string otherExt = "";
1290     setOtherExtension(otherExt, extensionMap, defaultExtensionMap);
1291     if (ext != "" || otherExt != "") {
1292         return baseLocale + "-u" + ext + otherExt;
1293     } else {
1294         return baseLocale;
1295     }
1296 }
1297 
IsEmpty24HourClock()1298 bool LocaleConfig::IsEmpty24HourClock()
1299 {
1300     std::string is24Hour = ReadSystemParameter(HOUR_KEY.c_str(), CONFIG_LEN);
1301     if (is24Hour.empty()) {
1302         HILOG_ERROR_I18N("LocaleConfig::IsEmpty24HourClock: Read system is24Hour failed.");
1303         return false;
1304     }
1305     if (is24Hour.compare("default") == 0) {
1306         return true;
1307     }
1308     return false;
1309 }
1310 
Is24HourClock()1311 bool LocaleConfig::Is24HourClock()
1312 {
1313     std::string is24Hour = ReadSystemParameter(HOUR_KEY.c_str(), CONFIG_LEN);
1314     if (is24Hour.empty()) {
1315         HILOG_ERROR_I18N("LocaleConfig::Is24HourClock: Read system is24Hour failed.");
1316         return false;
1317     }
1318     if (is24Hour.compare("default") == 0) {
1319         std::string systemLocale = GetSystemLocale();
1320         return Is24HourLocale(systemLocale);
1321     }
1322     if (is24Hour.compare("true") == 0) {
1323         return true;
1324     }
1325     return false;
1326 }
1327 
GetSystemHour()1328 std::string LocaleConfig::GetSystemHour()
1329 {
1330     std::string is24HourVal = ReadSystemParameter(HOUR_KEY.c_str(), CONFIG_LEN);
1331     HILOG_INFO_I18N("GetSystemHour: read from system param:%{public}s.", is24HourVal.c_str());
1332     bool is24Hour = Is24HourClock();
1333     return is24Hour ? "true" : "false";
1334 }
1335 
Is24HourLocale(const std::string & systemLocale)1336 bool LocaleConfig::Is24HourLocale(const std::string& systemLocale)
1337 {
1338     static std::unordered_map<std::string, bool> is24HourLocaleMap;
1339     if (is24HourLocaleMap.find(systemLocale) != is24HourLocaleMap.end()) {
1340         return is24HourLocaleMap[systemLocale];
1341     }
1342     UErrorCode status = U_ZERO_ERROR;
1343     icu::Locale locale = icu::Locale::forLanguageTag(icu::StringPiece(systemLocale), status);
1344     if (U_FAILURE(status)) {
1345         HILOG_INFO_I18N("Is24HourLocale: %{public}s create locale failed", systemLocale.c_str());
1346         return false;
1347     }
1348 
1349     icu::UnicodeString formatPattern;
1350     icu::DateFormat* dateFormat = icu::DateFormat::createTimeInstance(icu::DateFormat::EStyle::kLong, locale);
1351     if (dateFormat == nullptr) {
1352         HILOG_INFO_I18N("Is24HourLocale: createTimeInstance failed");
1353         return false;
1354     }
1355     icu::SimpleDateFormat* simDateFormat = static_cast<icu::SimpleDateFormat*>(dateFormat);
1356     if (simDateFormat == nullptr) {
1357         HILOG_INFO_I18N("Is24HourLocale: failed to convert dateFormat");
1358         return false;
1359     }
1360     simDateFormat->toPattern(formatPattern);
1361     delete dateFormat;
1362     std::string pattern;
1363     formatPattern.toUTF8String(pattern);
1364     bool result = HasDesignator(pattern, 'H');
1365     is24HourLocaleMap[systemLocale] = result;
1366     return result;
1367 }
1368 
HasDesignator(const std::string & pattern,const char designator)1369 bool LocaleConfig::HasDesignator(const std::string& pattern, const char designator)
1370 {
1371     if (pattern.empty()) {
1372         HILOG_INFO_I18N("HasDesignator: pattern is empty");
1373         return false;
1374     }
1375     bool insideQuote = false;
1376     for (const auto& c : pattern) {
1377         if (c == '\'') {
1378             insideQuote = !insideQuote;
1379         } else if (!insideQuote) {
1380             if (c == designator) {
1381                 return true;
1382             }
1383         }
1384     }
1385     return false;
1386 }
1387 
GetUsingLocalDigit()1388 bool LocaleConfig::GetUsingLocalDigit()
1389 {
1390     std::string locale = GetSystemLocale();
1391     LocaleInfo localeInfo(locale);
1392     std::string language = localeInfo.GetLanguage();
1393     if (localDigitMap.find(language) == localDigitMap.end()) {
1394         return false;
1395     }
1396     std::string localNumberSystem = localDigitMap.at(language);
1397     return localNumberSystem.compare(localeInfo.GetNumberingSystem()) == 0;
1398 }
1399 
GetBlockedLanguages()1400 std::unordered_set<std::string> LocaleConfig::GetBlockedLanguages()
1401 {
1402     TabooUtils* tabooUtils = TabooUtils::GetInstance();
1403     if (tabooUtils == nullptr) {
1404         HILOG_ERROR_I18N("LocaleConfig::GetBlockedLanguages: tabooUtils is nullptr.");
1405         return {};
1406     }
1407     return tabooUtils->GetBlockedLanguages();
1408 }
1409 
GetBlockedRegions(const std::string & language)1410 std::unordered_set<std::string> LocaleConfig::GetBlockedRegions(const std::string& language)
1411 {
1412     TabooUtils* tabooUtils = TabooUtils::GetInstance();
1413     if (tabooUtils == nullptr) {
1414         HILOG_ERROR_I18N("LocaleConfig::GetBlockedRegions: tabooUtils is nullptr.");
1415         return {};
1416     }
1417     return tabooUtils->GetBlockedRegions(language);
1418 }
1419 
SetSystemLanguage(const std::string & languageTag,int32_t userId)1420 I18nErrorCode LocaleConfig::SetSystemLanguage(const std::string &languageTag, int32_t userId)
1421 {
1422     if (!IsValidTag(languageTag)) {
1423         HILOG_ERROR_I18N("LocaleConfig::SetSystemLanguage %{public}s is not valid language tag.",
1424             languageTag.c_str());
1425         return I18nErrorCode::INVALID_LANGUAGE_TAG;
1426     }
1427     std::string languageCode = LocaleEncode(languageTag);
1428     HILOG_INFO_I18N("LocaleConfig::SetSystemLanguage: set language %{public}s.", languageCode.c_str());
1429     // save old language, reset system language to old language if update locale failed.
1430     std::string oldLanguageTag = GetSystemLanguage();
1431     if (SetParameter(LANGUAGE_KEY.c_str(), languageTag.data()) != 0) {
1432         HILOG_ERROR_I18N("LocaleConfig::SetSystemLanguage update system language failed.");
1433         return I18nErrorCode::UPDATE_SYSTEM_LANGUAGE_FAILED;
1434     }
1435     std::string newLocaleTag = UpdateLanguageOfLocale(languageTag);
1436     if (SetSystemLocale(newLocaleTag, userId) == I18nErrorCode::SUCCESS) {
1437 #ifdef SUPPORT_MULTI_USER
1438         std::string localId = (userId != -1) ? std::to_string(userId) : "";
1439         MultiUsers::SaveLanguage(localId, languageTag);
1440 #endif
1441         return I18nErrorCode::SUCCESS;
1442     }
1443     // reset system language to old language in case that system language is inconsist with system locale's lanuage.
1444     HILOG_ERROR_I18N("LocaleConfig::SetSystemLanguage update system locale failed.");
1445     SetParameter(LANGUAGE_KEY.c_str(), oldLanguageTag.data());
1446     return I18nErrorCode::UPDATE_SYSTEM_LANGUAGE_FAILED;
1447 }
1448 
SetSystemRegion(const std::string & regionTag,int32_t userId)1449 I18nErrorCode LocaleConfig::SetSystemRegion(const std::string &regionTag, int32_t userId)
1450 {
1451     QueryUpgradeLocale();
1452     if (!IsValidRegion(regionTag)) {
1453         HILOG_ERROR_I18N("LocaleConfig::SetSystemRegion %{public}s is not valid region tag.", regionTag.c_str());
1454         return I18nErrorCode::INVALID_REGION_TAG;
1455     }
1456     std::string regionCode = LocaleEncode(regionTag);
1457     HILOG_INFO_I18N("LocaleConfig::SetSystemRegion: set region %{public}s.", regionCode.c_str());
1458     return SetSystemLocale(UpdateRegionOfLocale(regionTag), userId);
1459 }
1460 
QueryUpgradeLocale()1461 void LocaleConfig::QueryUpgradeLocale()
1462 {
1463     std::string upgradeLocale = ReadSystemParameter(UPGRADE_LOCALE_KEY, CONFIG_LEN);
1464     if (!upgradeLocale.empty()) {
1465         HILOG_INFO_I18N("LocaleConfig::QueryUpgradeLocale: upgrade locale is %{public}s.", upgradeLocale.c_str());
1466     }
1467 }
1468 
ComputeEffectiveLanguage(const std::string & locale,const std::string & language)1469 std::string LocaleConfig::ComputeEffectiveLanguage(const std::string& locale, const std::string& language)
1470 {
1471     if (locale.empty()) {
1472         HILOG_ERROR_I18N("LocaleConfig::ComputeEffectiveLanguage: locale is empty.");
1473         return locale;
1474     }
1475     size_t prefixLength = 2;
1476     if (locale.compare(0, prefixLength, "es") != 0 && locale.compare(0, prefixLength, "pt") != 0) {
1477         return locale;
1478     }
1479     std::shared_ptr<LocaleInfo> esESLocale = std::make_shared<LocaleInfo>("es-ES");
1480     std::shared_ptr<LocaleInfo> esUSLocale = std::make_shared<LocaleInfo>("es-US");
1481     std::shared_ptr<LocaleInfo> ptPTLocale = std::make_shared<LocaleInfo>("pt-PT");
1482     std::shared_ptr<LocaleInfo> ptBRLocale = std::make_shared<LocaleInfo>("pt-BR");
1483     std::vector<LocaleInfo*> candidateLocales {
1484         esESLocale.get(),
1485         esUSLocale.get(),
1486         ptPTLocale.get(),
1487         ptBRLocale.get()
1488     };
1489     std::shared_ptr<LocaleInfo> requestLocale = std::make_shared<LocaleInfo>(locale);
1490     std::string bestMatchedLocale = LocaleMatcher::GetBestMatchedLocale(requestLocale.get(), candidateLocales);
1491     if (bestMatchedLocale.empty()) {
1492         HILOG_ERROR_I18N("LocaleConfig::ComputeEffectiveLanguage: Get best matched locale failed.");
1493         return locale;
1494     }
1495     if (language.empty()) {
1496         HILOG_ERROR_I18N("LocaleConfig::ComputeEffectiveLanguage: language is empty.");
1497         return locale;
1498     }
1499     std::string systemLanguage = language;
1500     if (language.compare("es") == 0) {
1501         systemLanguage = "es-ES";
1502     }
1503     if (bestMatchedLocale.compare(systemLanguage) == 0) {
1504         return locale;
1505     }
1506     return systemLanguage;
1507 }
1508 
SetSystemLocale(const std::string & localeTag,int32_t userId)1509 I18nErrorCode LocaleConfig::SetSystemLocale(const std::string &localeTag, int32_t userId)
1510 {
1511     if (!IsValidTag(localeTag)) {
1512         HILOG_ERROR_I18N("LocaleConfig::SetSystemLocale %{public}s is not a valid locale tag.", localeTag.c_str());
1513         return I18nErrorCode::INVALID_LOCALE_TAG;
1514     }
1515     std::string localeCode = LocaleEncode(localeTag);
1516     HILOG_INFO_I18N("LocaleConfig::SetSystemLocale: set locale %{public}s.", localeCode.c_str());
1517     if (SetParameter(LOCALE_KEY.c_str(), localeTag.data()) != 0) {
1518         return I18nErrorCode::UPDATE_SYSTEM_LOCALE_FAILED;
1519     }
1520     std::string systemLanguage = GetSystemLanguage();
1521     std::string effectiveLanguage = ComputeEffectiveLanguage(localeTag, systemLanguage);
1522 #ifdef SUPPORT_MULTI_USER
1523     std::string localId = (userId != -1) ? std::to_string(userId) : "";
1524     MultiUsers::SaveLocale(localId, localeTag);
1525 #endif
1526 #ifdef SUPPORT_GRAPHICS
1527     UpdateConfiguration(AAFwk::GlobalConfigurationKey::SYSTEM_LANGUAGE, effectiveLanguage, userId);
1528     return PublishCommonEvent(EventFwk::CommonEventSupport::COMMON_EVENT_LOCALE_CHANGED, userId);
1529 #else
1530     return I18nErrorCode::SUCCESS;
1531 #endif
1532 }
1533 
IsValid24HourClockValue(const std::string & tag)1534 bool LocaleConfig::IsValid24HourClockValue(const std::string &tag)
1535 {
1536     return (tag.compare("true") == 0 || tag.compare("false") == 0 || tag.compare("default") == 0);
1537 }
1538 
Set24HourClock(const std::string & option,int32_t userId)1539 I18nErrorCode LocaleConfig::Set24HourClock(const std::string &option, int32_t userId)
1540 {
1541     if (!IsValid24HourClockValue(option)) {
1542         HILOG_ERROR_I18N("LocaleConfig::Set24HourClock invalid 24 Hour clock tag: %{public}s", option.c_str());
1543         return I18nErrorCode::INVALID_24_HOUR_CLOCK_TAG;
1544     }
1545     HILOG_INFO_I18N("LocaleConfig::Set24HourClock: update 24 hour clock %{public}s", option.c_str());
1546     if (SetParameter(HOUR_KEY.c_str(), option.data()) != 0) {
1547         HILOG_ERROR_I18N("LocaleConfig::Set24HourClock update 24 hour clock failed with option=%{public}s",
1548             option.c_str());
1549         return I18nErrorCode::UPDATE_24_HOUR_CLOCK_FAILED;
1550     }
1551 #ifdef SUPPORT_MULTI_USER
1552     std::string localId;
1553     if (userId != -1) {
1554         localId = std::to_string(userId);
1555     }
1556     MultiUsers::SaveIs24Hour(localId, option);
1557 #endif
1558 #ifdef SUPPORT_GRAPHICS
1559     UpdateConfiguration(AAFwk::GlobalConfigurationKey::SYSTEM_HOUR, option, userId);
1560     return PublishCommonEvent(EventFwk::CommonEventSupport::COMMON_EVENT_TIME_CHANGED, userId);
1561 #else
1562     return I18nErrorCode::SUCCESS;
1563 #endif
1564 }
1565 
SetUsingLocalDigit(bool flag,int32_t userId)1566 I18nErrorCode LocaleConfig::SetUsingLocalDigit(bool flag, int32_t userId)
1567 {
1568     // check whether current language support local digit.
1569     std::string localeTag = GetSystemLocale();
1570     std::string languageTag = localeTag.substr(0, 2); // obtain 2 length language code.
1571     auto it = localDigitMap.find(languageTag);
1572     if (it == localDigitMap.end()) {
1573         HILOG_ERROR_I18N("LocaleConfig::SetUsingLocalDigit current system doesn't support set local digit");
1574         return I18nErrorCode::UPDATE_LOCAL_DIGIT_FAILED;
1575     }
1576     std::string localDigit = flag ? it->second : "";
1577     // update system locale.
1578     return SetSystemLocale(ModifyExtParam(localeTag, NUMBER_SYSTEM_KEY, localDigit), userId);
1579 }
1580 
SetTemperatureType(const TemperatureType & type,int32_t userId)1581 I18nErrorCode LocaleConfig::SetTemperatureType(const TemperatureType& type, int32_t userId)
1582 {
1583     if (temperatureTypeToName.find(type) == temperatureTypeToName.end()) {
1584         HILOG_ERROR_I18N("LocaleConfig::SetTemperatureType: temperature type failed.");
1585         return I18nErrorCode::INVALID_TEMPERATURE_TYPE;
1586     }
1587     std::string option = temperatureTypeToName[type];
1588     std::string localeTag = GetSystemLocale();
1589     if (localeTag.empty()) {
1590         HILOG_ERROR_I18N("LocaleConfig::SetTemperatureType: get system locale failed.");
1591         return I18nErrorCode::UPDATE_TEMPERATURE_TYPE_FAILED;
1592     }
1593     // update system locale.
1594     return SetSystemLocale(ModifyExtParam(localeTag, TEMPERATURE_UNIT_KEY, option), userId);
1595 }
1596 
GetTemperatureType()1597 TemperatureType LocaleConfig::GetTemperatureType()
1598 {
1599     std::string localeTag = GetSystemLocale();
1600     if (localeTag.empty()) {
1601         return TemperatureType::CELSIUS;
1602     }
1603     std::unordered_map<std::string, std::string> extParamMap = ParseExtParam(localeTag);
1604     std::string type;
1605     if (extParamMap.find(TEMPERATURE_UNIT_KEY) != extParamMap.end()) {
1606         type = extParamMap[TEMPERATURE_UNIT_KEY];
1607     }
1608     if (!type.empty() && nameToTemperatureType.find(type) != nameToTemperatureType.end()) {
1609         return nameToTemperatureType[type];
1610     }
1611     std::string regionTag = GetSystemRegion();
1612     if (fahrenheitUsingRegions.find(regionTag) != fahrenheitUsingRegions.end()) {
1613         return TemperatureType::FAHRENHEIT;
1614     }
1615     return TemperatureType::CELSIUS;
1616 }
1617 
GetTemperatureName(const TemperatureType & type)1618 std::string LocaleConfig::GetTemperatureName(const TemperatureType& type)
1619 {
1620     if (temperatureTypeToName.find(type) == temperatureTypeToName.end()) {
1621         HILOG_ERROR_I18N("LocaleConfig::GetTemperatureName: temperature type failed.");
1622         return "";
1623     }
1624     if (type == TemperatureType::FAHRENHEIT) {
1625         return "fahrenheit";
1626     }
1627     return temperatureTypeToName[type];
1628 }
1629 
SetFirstDayOfWeek(const WeekDay & type,int32_t userId)1630 I18nErrorCode LocaleConfig::SetFirstDayOfWeek(const WeekDay& type, int32_t userId)
1631 {
1632     if (weekDayToName.find(type) == weekDayToName.end()) {
1633         HILOG_ERROR_I18N("LocaleConfig::SetFirstDayOfWeek: week day failed.");
1634         return I18nErrorCode::INVALID_WEEK_DAY;
1635     }
1636     std::string option = weekDayToName[type];
1637     std::string localeTag = GetSystemLocale();
1638     if (localeTag.empty()) {
1639         HILOG_ERROR_I18N("LocaleConfig::SetFirstDayOfWeek: get system locale failed.");
1640         return I18nErrorCode::UPDATE_WEEK_DAY_FAILED;
1641     }
1642     // update system locale.
1643     return SetSystemLocale(ModifyExtParam(localeTag, WEEK_DAY_KEY, option), userId);
1644 }
1645 
GetFirstDayOfWeek()1646 WeekDay LocaleConfig::GetFirstDayOfWeek()
1647 {
1648     std::string localeTag = GetSystemLocale();
1649     if (localeTag.empty()) {
1650         HILOG_ERROR_I18N("LocaleConfig::GetFirstDayOfWeek: get system locale failed.");
1651         return WeekDay::MON;
1652     }
1653     std::unordered_map<std::string, std::string> extParamMap = ParseExtParam(localeTag);
1654     std::string type;
1655     if (extParamMap.find(WEEK_DAY_KEY) != extParamMap.end()) {
1656         type = extParamMap[WEEK_DAY_KEY];
1657     }
1658     if (!type.empty() && nameToWeekDay.find(type) != nameToWeekDay.end()) {
1659         return nameToWeekDay[type];
1660     }
1661     UErrorCode status = U_ZERO_ERROR;
1662     icu::Locale tempLocale = icu::Locale::forLanguageTag(localeTag, status);
1663     if (U_FAILURE(status)) {
1664         HILOG_ERROR_I18N("LocaleConfig::GetFirstDayOfWeek: create icu::Locale failed.");
1665         return WeekDay::MON;
1666     }
1667     icu::Calendar* calendar = icu::Calendar::createInstance(tempLocale, status);
1668     if (U_FAILURE(status)) {
1669         HILOG_ERROR_I18N("LocaleConfig::GetFirstDayOfWeek: create icu::Calendar failed.");
1670         return WeekDay::MON;
1671     }
1672     icu::Calendar::EDaysOfWeek firstDay = calendar->getFirstDayOfWeek();
1673     delete calendar;
1674     return eDaysOfWeekToWeekDay[firstDay];
1675 }
1676 
1677 #ifdef SUPPORT_GRAPHICS
UpdateConfiguration(const char * key,const std::string & value,int32_t userId)1678 void LocaleConfig::UpdateConfiguration(const char *key, const std::string &value, int32_t userId)
1679 {
1680     AppExecFwk::Configuration configuration;
1681     configuration.AddItem(key, value);
1682     auto appMgrClient = std::make_unique<AppExecFwk::AppMgrClient>();
1683 
1684     AppExecFwk::AppMgrResultCode status = appMgrClient->UpdateConfiguration(configuration, userId);
1685     if (status != AppExecFwk::AppMgrResultCode::RESULT_OK) {
1686         HILOG_ERROR_I18N("LocaleConfig::UpdateConfiguration: Update configuration userId %{public}d failed.", userId);
1687         return;
1688     }
1689     HILOG_INFO_I18N("LocaleConfig::UpdateLanguageConfiguration: update userId %{public}d.", userId);
1690 }
1691 
PublishCommonEvent(const std::string & eventType,int32_t userId)1692 I18nErrorCode LocaleConfig::PublishCommonEvent(const std::string &eventType, int32_t userId)
1693 {
1694     OHOS::AAFwk::Want localeChangeWant;
1695     localeChangeWant.SetAction(eventType);
1696     OHOS::EventFwk::CommonEventData event(localeChangeWant);
1697     if (EventFwk::CommonEventSupport::COMMON_EVENT_TIME_CHANGED.compare(eventType) == 0) {
1698         event.SetData(HOUR_EVENT_DATA);
1699     }
1700     if (userId == -1) {
1701         if (!OHOS::EventFwk::CommonEventManager::PublishCommonEvent(event)) {
1702             HILOG_ERROR_I18N("LocaleConfig::PublishCommonEvent Failed to Publish event %{public}s",
1703                 localeChangeWant.GetAction().c_str());
1704             return I18nErrorCode::PUBLISH_COMMON_EVENT_FAILED;
1705         }
1706         HILOG_INFO_I18N("LocaleConfig::PublishCommonEvent publish event finished.");
1707         return I18nErrorCode::SUCCESS;
1708     }
1709 
1710     if (!OHOS::EventFwk::CommonEventManager::PublishCommonEventAsUser(event, userId)) {
1711         HILOG_ERROR_I18N("LocaleConfig::PublishCommonEvent Failed to Publish event %{public}s, userId %{public}d.",
1712             localeChangeWant.GetAction().c_str(), userId);
1713         return I18nErrorCode::PUBLISH_COMMON_EVENT_FAILED;
1714     }
1715     HILOG_INFO_I18N("LocaleConfig::PublishCommonEvent publish event finished,  userId %{public}d.", userId);
1716     return I18nErrorCode::SUCCESS;
1717 }
1718 #endif
1719 
UpdateLanguageOfLocale(const std::string & languageTag)1720 std::string LocaleConfig::UpdateLanguageOfLocale(const std::string &languageTag)
1721 {
1722     // Compute language and script part from languageTag.
1723     UErrorCode status = U_ZERO_ERROR;
1724     icu::Locale languageLocale = icu::Locale::forLanguageTag(languageTag.c_str(), status);
1725     if (U_FAILURE(status)) {
1726         HILOG_ERROR_I18N("LocaleConfig::UpdateLanguageOfLocale init icu Locale for language %{public}s failed.",
1727             languageTag.c_str());
1728         return "";
1729     }
1730     std::string langTag = languageLocale.getLanguage();
1731     std::string scriptTag = languageLocale.getScript();
1732     // Compute region and extend param part from current system locale.
1733     std::string systemLocaleTag = GetSystemLocale();
1734     icu::Locale systemLocale = icu::Locale::forLanguageTag(systemLocaleTag.c_str(), status);
1735     if (U_FAILURE(status)) {
1736         HILOG_ERROR_I18N("LocaleConfig::UpdateSystemLocale init icu Locale for locale %{public}s failed.",
1737             systemLocaleTag.c_str());
1738         return systemLocaleTag;
1739     }
1740     std::string regionTag = systemLocale.getCountry();
1741     std::string extendParamTag;
1742     size_t pos = systemLocaleTag.find(EXT_PARAM_KEY);
1743     if (pos != std::string::npos) {
1744         extendParamTag = systemLocaleTag.substr(pos);
1745     }
1746     // Combine above elements.
1747     return CreateLocale(langTag, scriptTag, regionTag, extendParamTag);
1748 }
1749 
CreateLocale(const std::string & languageTag,const std::string & scriptTag,const std::string & regionTag,const std::string & extendParamTag)1750 std::string LocaleConfig::CreateLocale(const std::string &languageTag, const std::string &scriptTag,
1751     const std::string &regionTag, const std::string &extendParamTag)
1752 {
1753     // combine language, script, region and extend param with '-'
1754     std::string localeTag = languageTag;
1755     std::string splitor = "-";
1756     if (scriptTag.length() > 0) {
1757         localeTag += splitor + scriptTag;
1758     }
1759     if (regionTag.length() > 0) {
1760         localeTag += splitor + regionTag;
1761     }
1762     if (extendParamTag.length() > 0) {
1763         localeTag += extendParamTag;
1764     }
1765     return localeTag;
1766 }
1767 
UpdateRegionOfLocale(const std::string & regionTag)1768 std::string LocaleConfig::UpdateRegionOfLocale(const std::string &regionTag)
1769 {
1770     std::string localeTag = GetSystemLocale();
1771     // if current system locale is null, contruct a locale from region tag.
1772     if (localeTag.length() == 0) {
1773         return CreateLocaleFromRegion(regionTag);
1774     }
1775     std::string extParam;
1776     size_t pos = localeTag.find(EXT_PARAM_KEY);
1777     if (pos != std::string::npos) {
1778         extParam = localeTag.substr(pos);
1779     }
1780     // combine locale with origin locale's language and script with regionTag.
1781     UErrorCode status = U_ZERO_ERROR;
1782     const icu::Locale origin = icu::Locale::forLanguageTag(localeTag, status);
1783     if (U_FAILURE(status)) {
1784         HILOG_ERROR_I18N("LocaleConfig::UpdateRegionOfLocale init origin locale failed.");
1785         return localeTag;
1786     }
1787     icu::LocaleBuilder builder = icu::LocaleBuilder().setLanguage(origin.getLanguage()).
1788         setScript(origin.getScript()).setRegion(regionTag);
1789     icu::Locale temp = builder.build(status);
1790     if (U_FAILURE(status)) {
1791         HILOG_ERROR_I18N("LocaleConfig::UpdateRegionOfLocale: build locale failed.");
1792         return localeTag;
1793     }
1794     string ret = temp.toLanguageTag<string>(status);
1795     if (U_FAILURE(status)) {
1796         HILOG_ERROR_I18N("LocaleConfig::UpdateRegionOfLocale obtain new locale's tag failed.");
1797         return localeTag;
1798     }
1799     ret += extParam;
1800     ret = ModifyExtParam(ret, NUMBER_SYSTEM_KEY, "");
1801     return ret;
1802 }
1803 
CreateLocaleFromRegion(const std::string & regionTag)1804 std::string LocaleConfig::CreateLocaleFromRegion(const std::string &regionTag)
1805 {
1806     // fill locale with icu
1807     icu::Locale locale("", regionTag.c_str());
1808     UErrorCode status = U_ZERO_ERROR;
1809     locale.addLikelySubtags(status);
1810     if (U_FAILURE(status)) {
1811         HILOG_ERROR_I18N("LocaleConfig::CreateLocaleFromRegion init new locale failed.");
1812         return "";
1813     }
1814     std::string localeTag = locale.toLanguageTag<string>(status);
1815     if (U_FAILURE(status)) {
1816         HILOG_ERROR_I18N("LocaleConfig::CreateLocaleFromRegion obtain new locale's tag failed.");
1817         return "";
1818     }
1819     return localeTag;
1820 }
1821 
ModifyExtParam(const std::string & locale,const std::string & key,const std::string & value)1822 std::string LocaleConfig::ModifyExtParam(const std::string& locale, const std::string& key, const std::string& value)
1823 {
1824     if (locale.empty()) {
1825         HILOG_ERROR_I18N("LocaleConfig::ModifyExtParam: locale is empty.");
1826         return locale;
1827     }
1828     if (key.empty()) {
1829         HILOG_ERROR_I18N("LocaleConfig::ParseExtParam: key is empty.");
1830         return locale;
1831     }
1832     std::unordered_map<std::string, std::string> paramMap;
1833     std::string localeBase = locale;
1834     size_t pos = locale.find(EXT_PARAM_KEY);
1835     if (pos != std::string::npos) {
1836         localeBase = locale.substr(0, pos);
1837         std::string param = locale.substr(pos);
1838         paramMap = ParseExtParam(param);
1839     }
1840     paramMap[key] = value;
1841     std::string result = localeBase + GenerateExtParam(paramMap);
1842     return result;
1843 }
1844 
ParseExtParam(const std::string & param)1845 std::unordered_map<std::string, std::string> LocaleConfig::ParseExtParam(const std::string& param)
1846 {
1847     std::unordered_map<std::string, std::string> result;
1848     size_t pos = param.find(EXT_PARAM_KEY);
1849     if (pos == std::string::npos) {
1850         HILOG_INFO_I18N("LocaleConfig::ParseExtParam: param is invalid.");
1851         return result;
1852     }
1853     std::string extParam = param.substr(pos + EXT_PARAM_KEY.length());
1854     std::vector<std::string> paramArray;
1855     Split(extParam, "-", paramArray);
1856     size_t pairLen = 2;
1857     if (paramArray.size() % pairLen != 0) {
1858         HILOG_ERROR_I18N("LocaleConfig::ParseExtParam: parse ext param failed.");
1859         return result;
1860     }
1861     for (size_t pos = 0; pos + 1 < paramArray.size(); pos += pairLen) {
1862         std::string key = paramArray[pos];
1863         std::string value = paramArray[pos + 1];
1864         if (key.empty() || value.empty()) {
1865             HILOG_ERROR_I18N("LocaleConfig::ParseExtParam: key or value is empty.");
1866             continue;
1867         }
1868         auto status = result.insert({key, value});
1869         if (!status.second) {
1870             HILOG_ERROR_I18N("LocaleConfig::ParseExtParam: insert key (%{public}s) and value (%{public}s) failed.",
1871                 key.c_str(), value.c_str());
1872         }
1873     }
1874     return result;
1875 }
1876 
GenerateExtParam(const std::unordered_map<std::string,std::string> & paramMap)1877 std::string LocaleConfig::GenerateExtParam(const std::unordered_map<std::string, std::string>& paramMap)
1878 {
1879     std::string result;
1880     if (paramMap.size() == 0) {
1881         return result;
1882     }
1883     for (auto& param : paramMap) {
1884         std::string key = param.first;
1885         std::string value = param.second;
1886         if (value.empty()) {
1887             HILOG_INFO_I18N("LocaleConfig::GenerateExtParam: erase key (%{public}s) ", key.c_str());
1888             continue;
1889         }
1890         result += "-" + key + "-" + value;
1891     }
1892     if (!result.empty()) {
1893         result = "-u" + result;
1894     }
1895     return result;
1896 }
1897 
GetSimplifiedLanguage(const std::string & languageTag,int32_t & code)1898 std::string LocaleConfig::GetSimplifiedLanguage(const std::string& languageTag, int32_t &code)
1899 {
1900     std::string simplifiedLanguage = "";
1901     if (IsValidTag(languageTag)) {
1902         LocaleInfo localeInfo(languageTag);
1903         simplifiedLanguage = localeInfo.Minimize();
1904     } else {
1905         code = 1;
1906     }
1907     return simplifiedLanguage;
1908 }
1909 
GetSimplifiedSystemLanguage()1910 std::string LocaleConfig::GetSimplifiedSystemLanguage()
1911 {
1912     std::string locale = GetSystemLanguage();
1913     LocaleInfo localeInfo(locale);
1914     LocaleInfo localeInfoMax(localeInfo.Maximize());
1915     std::string language = localeInfoMax.GetLanguage();
1916     language = language + '-' + localeInfoMax.GetScript();
1917     if (dialectLanguages.find(language) != dialectLanguages.end()) {
1918         std::string systemRegion = localeInfo.GetRegion();
1919         if (!systemRegion.empty() && language.compare("en-Latn") != 0) {
1920             locale = language + '-' + systemRegion;
1921         } else {
1922             locale = GetSystemLocale();
1923         }
1924         LocaleInfo* requestLocale = new(std::nothrow) LocaleInfo(locale);
1925         if (requestLocale == nullptr) {
1926             HILOG_ERROR_I18N("GetSimplifiedLanguage: %{public}s failed to construct LocaleInfo.", locale.c_str());
1927             return "";
1928         }
1929         std::vector<LocaleInfo*> candidateLocales;
1930         for (auto& candidate : dialectLanguages[language]) {
1931             LocaleInfo* candidateInfo = new(std::nothrow) LocaleInfo(candidate);
1932             if (candidateInfo == nullptr) {
1933                 HILOG_ERROR_I18N("GetSimplifiedLanguage: %{public}s failed to construct LocaleInfo.",
1934                     candidate.c_str());
1935                 continue;
1936             }
1937             candidateLocales.push_back(candidateInfo);
1938         }
1939         locale = LocaleMatcher::GetBestMatchedLocale(requestLocale, candidateLocales);
1940 
1941         for (LocaleInfo* candidateInfo : candidateLocales) {
1942             delete candidateInfo;
1943             candidateInfo = nullptr;
1944         }
1945         delete requestLocale;
1946         requestLocale = nullptr;
1947     }
1948     LocaleInfo simplifiedLocale(locale);
1949     std::string ret = simplifiedLocale.Minimize();
1950     auto iter = resourceIdMap.find(ret);
1951     if (iter != resourceIdMap.end()) {
1952         ret = iter->second;
1953     }
1954     return ret;
1955 }
1956 
GetUnicodeWrappedFilePath(const std::string & path,const char delimiter,std::shared_ptr<LocaleInfo> localeInfo,std::string & invalidField)1957 std::string LocaleConfig::GetUnicodeWrappedFilePath(const std::string &path, const char delimiter,
1958     std::shared_ptr<LocaleInfo> localeInfo, std::string &invalidField)
1959 {
1960     if (delimiter == '\0') {
1961         invalidField = "delimiter";
1962         return path;
1963     }
1964     if (path.empty() || path.length() > PATH_MAX) {
1965         invalidField = "path";
1966         return path;
1967     }
1968     std::string locale;
1969     if (localeInfo != nullptr) {
1970         locale = localeInfo->GetBaseName();
1971     }
1972     if (!IsValidTag(locale)) {
1973         locale = GetSystemLocale();
1974     }
1975     if (!IsRTL(locale)) {
1976         return path;
1977     }
1978     std::string result;
1979     std::vector<string> dest;
1980     std::string sep(1, delimiter); // 1 is char count
1981     Split(path, sep, dest);
1982     if (dest.size() == 1) { // 1 is array's size
1983         return path;
1984     }
1985     for (size_t i = 0 ; i < dest.size(); i++) {
1986         if (dest[i].empty()) {
1987             continue;
1988         }
1989         if (i == 0 && dest[i].compare(sep) != 0) {
1990             dest[i] = "\u200f\u200e" + dest[i] + "\u200e";
1991             continue;
1992         }
1993         dest[i] = "\u200e" + dest[i] + "\u200e";
1994     }
1995     std::string newSep = "\u200f" + sep;
1996     Merge(dest, newSep, result);
1997     return result;
1998 }
1999 } // namespace I18n
2000 } // namespace Global
2001 } // namespace OHOS
2002