• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2021-2025 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 "locale_config.h"
16 #include "locale_config_ext.h"
17 
18 #include <algorithm>
19 #include <regex>
20 #include "accesstoken_kit.h"
21 #ifdef SUPPORT_GRAPHICS
22 #include "app_mgr_client.h"
23 #include "ability_manager_client.h"
24 #include "configuration.h"
25 #include <common_event_data.h>
26 #include <common_event_manager.h>
27 #include <common_event_publish_info.h>
28 #include <common_event_support.h>
29 #endif
30 #include <cctype>
31 #include "config_policy_utils.h"
32 #include "i18n_hilog.h"
33 #include "date_time_format.h"
34 #include "ipc_skeleton.h"
35 #include "libxml/parser.h"
36 #include "locale_info.h"
37 #include "locale_matcher.h"
38 #include "multi_users.h"
39 #include "number_format.h"
40 #include "unicode/dcfmtsym.h"
41 #include "unicode/localebuilder.h"
42 #include "unicode/locdspnm.h"
43 #include "unicode/locid.h"
44 #include <unicode/numsys.h>
45 #include "unicode/smpdtfmt.h"
46 #include "ohos/init_data.h"
47 #include "parameter.h"
48 #include "securec.h"
49 #include "string_ex.h"
50 #include "ucase.h"
51 #include "ulocimp.h"
52 #include "unicode/ulocdata.h"
53 #include "unicode/unistr.h"
54 #include "ureslocs.h"
55 #include "unicode/ustring.h"
56 #include "ustr_imp.h"
57 #include "utils.h"
58 #include "tokenid_kit.h"
59 
60 namespace OHOS {
61 namespace Global {
62 namespace I18n {
63 using namespace std;
64 const std::string LocaleConfig::LANGUAGE_KEY = "persist.global.language";
65 const std::string LocaleConfig::LOCALE_KEY = "persist.global.locale";
66 const std::string LocaleConfig::HOUR_KEY = "persist.global.is24Hour";
67 const std::string LocaleConfig::HOUR_EVENT_DATA = "24HourChange";
68 const char *LocaleConfig::UPGRADE_LOCALE_KEY = "persist.global.upgrade_locale";
69 const char *LocaleConfig::DEFAULT_LOCALE_KEY = "const.global.locale";
70 const char *LocaleConfig::DEFAULT_LANGUAGE_KEY = "const.global.language";
71 const char *LocaleConfig::DEFAULT_REGION_KEY = "const.global.region";
72 const char *LocaleConfig::DEVELOPER_MODE_KEY = "const.security.developermode.state";
73 const char *LocaleConfig::SIM_COUNTRY_CODE_KEY = "telephony.sim.countryCode0";
74 const char *LocaleConfig::SUPPORTED_LOCALES_NAME = "supported_locales";
75 const char *LocaleConfig::REGIONS_LANGUAGES_PATH = "etc/xml/i18n_param_config.xml";
76 const char *LocaleConfig::REGIONS_LANGUAGES_NAME = "i18n_param_config";
77 const char *LocaleConfig::SUPPORTED_REGIONS_NAME = "supported_regions";
78 const char *LocaleConfig::WHITE_LANGUAGES_NAME = "white_languages";
79 const char *LocaleConfig::SUPPORTED_LOCALES_PATH = "/system/usr/ohos_locale_config/supported_locales.xml";
80 const char *LocaleConfig::SUPPORTED_LOCALES_OLD_PATH = "/system/usr/ohos_locale_config/supported_locales_old.xml";
81 const char *LocaleConfig::SUPPORT_LOCALES_PATH = "/etc/ohos_lang_config/supported_locales.xml";
82 const char *LocaleConfig::SUPPORT_LOCALES_NAME = "supported_locales";
83 const char *LocaleConfig::DIALECT_LANGS_PATH = "/system/usr/ohos_locale_config/dialect_languages.xml";
84 const char *LocaleConfig::DIALECT_LANGS_NAME = "dialect_langs";
85 const char *LocaleConfig::OVERRIDE_SUPPORTED_REGIONS_NAME = "supported_regions";
86 const char *LocaleConfig::OVERRIDE_SUPPORTED_REGIONS_PATH =
87     "/system/usr/ohos_locale_config/region/supported_regions.xml";
88 const char *LocaleConfig::DEFAULT_LOCALE = "en-Latn";
89 const char *LocaleConfig::supportLocalesTag = "supported_locales";
90 const char *LocaleConfig::LANG_PATH = "/etc/ohos_lang_config/";
91 const char *LocaleConfig::REGION_PATH = "/system/usr/ohos_locale_config/region/";
92 const char *LocaleConfig::rootTag = "languages";
93 const char *LocaleConfig::secondRootTag = "lang";
94 const char *LocaleConfig::rootRegion = "regions";
95 const char *LocaleConfig::secondRootRegion = "region";
96 const std::string LocaleConfig::STANDARD_EXT_PARAM_KEY = "-u-";
97 const std::string LocaleConfig::CUST_EXT_PARAM_KEY = "-x-";
98 const std::string LocaleConfig::NUMBER_SYSTEM_KEY = "nu";
99 const std::string LocaleConfig::TEMPERATURE_UNIT_KEY = "mu";
100 const std::string LocaleConfig::WEEK_DAY_KEY = "fw";
101 const std::string LocaleConfig::CASE_FIRST_KEY = "kf";
102 const std::string LocaleConfig::COLLATION_KEY = "co";
103 const std::string LocaleConfig::NUNBER_PATTERN_KEY = "np";
104 const std::string LocaleConfig::MEASUREMENT_KEY = "ms";
105 const std::string LocaleConfig::NUMERIC_DATE_KEY = "nl";
106 const std::string LocaleConfig::TIMEZONE_KEY = "persist.time.timezone";
107 const std::string LocaleConfig::DEFAULT_TIMEZONE = "GMT";
108 const std::string LocaleConfig::DEFAULT_NUMBERING_SYSTEM_NAME = "latn";
109 unordered_set<string> LocaleConfig::supportedLocales;
110 unordered_set<string> LocaleConfig::supportedLocalesV15;
111 unordered_set<string> LocaleConfig::supportLocales;
112 unordered_set<string> LocaleConfig::supportedRegions;
113 unordered_set<string> LocaleConfig::overrideSupportedRegions;
114 unordered_set<string> LocaleConfig::dialectLang;
115 unordered_set<string> LocaleConfig::whiteLanguages;
116 std::set<std::string> LocaleConfig::extendWhiteLanguageList;
117 std::set<std::string> LocaleConfig::extendWhiteLanguageListV15;
118 unordered_map<string, string> LocaleConfig::dialectMap {
119     { "es-Latn-419", "es-Latn-419" },
120     { "es-Latn-BO", "es-Latn-419" },
121     { "es-Latn-BR", "es-Latn-419" },
122     { "es-Latn-BZ", "es-Latn-419" },
123     { "es-Latn-CL", "es-Latn-419" },
124     { "es-Latn-CO", "es-Latn-419" },
125     { "es-Latn-CR", "es-Latn-419" },
126     { "es-Latn-CU", "es-Latn-419" },
127     { "es-Latn-DO", "es-Latn-419" },
128     { "es-Latn-EC", "es-Latn-419" },
129     { "es-Latn-GT", "es-Latn-419" },
130     { "es-Latn-HN", "es-Latn-419" },
131     { "es-Latn-MX", "es-Latn-419" },
132     { "es-Latn-NI", "es-Latn-419" },
133     { "es-Latn-PA", "es-Latn-419" },
134     { "es-Latn-PE", "es-Latn-419" },
135     { "es-Latn-PR", "es-Latn-419" },
136     { "es-Latn-PY", "es-Latn-419" },
137     { "es-Latn-SV", "es-Latn-419" },
138     { "es-Latn-US", "es-Latn-419" },
139     { "es-Latn-UY", "es-Latn-419" },
140     { "es-Latn-VE", "es-Latn-419" },
141     { "pt-Latn-PT", "pt-Latn-PT" }
142 };
143 
144 unordered_map<string, string> LocaleConfig::dialectMapV15 {
145     { "es-Latn-419", "es-Latn-419" },
146     { "es-Latn-BO", "es-Latn-419" },
147     { "es-Latn-BR", "es-Latn-419" },
148     { "es-Latn-BZ", "es-Latn-419" },
149     { "es-Latn-CL", "es-Latn-419" },
150     { "es-Latn-CO", "es-Latn-419" },
151     { "es-Latn-CR", "es-Latn-419" },
152     { "es-Latn-CU", "es-Latn-419" },
153     { "es-Latn-DO", "es-Latn-419" },
154     { "es-Latn-EC", "es-Latn-419" },
155     { "es-Latn-GT", "es-Latn-419" },
156     { "es-Latn-HN", "es-Latn-419" },
157     { "es-Latn-MX", "es-Latn-419" },
158     { "es-Latn-NI", "es-Latn-419" },
159     { "es-Latn-PA", "es-Latn-419" },
160     { "es-Latn-PE", "es-Latn-419" },
161     { "es-Latn-PR", "es-Latn-419" },
162     { "es-Latn-PY", "es-Latn-419" },
163     { "es-Latn-SV", "es-Latn-419" },
164     { "es-Latn-US", "es-Latn-419" },
165     { "es-Latn-UY", "es-Latn-419" },
166     { "es-Latn-VE", "es-Latn-419" },
167     { "pt-Latn-PT", "pt-Latn-PT" },
168     { "en-Latn-US", "en-Latn-US" }
169 };
170 
171 unordered_map<string, string> LocaleConfig::localDigitMap {
172     { "ar", "arab" },
173     { "as", "beng" },
174     { "bn", "beng" },
175     { "fa", "arabext" },
176     { "mr", "deva" },
177     { "my", "mymr" },
178     { "ne", "deva" },
179     { "ur", "latn" }
180 };
181 
182 std::unordered_map<std::string, std::vector<std::string>> LocaleConfig::dialectLanguages {
183     { "en-Latn", { "en-Latn-US", "en-Latn-GB" } },
184     { "pt-Latn", { "pt-Latn-PT", "pt-Latn-BR" } },
185     { "zh-Hant", { "zh-Hant-HK", "zh-Hant-TW" } },
186 };
187 
188 std::unordered_map<std::string, std::string> LocaleConfig::resourceIdMap {
189     { "zh", "zh-Hans" },
190     { "zh-HK", "zh-Hant-HK" },
191     { "zh-TW", "zh-Hant" },
192     { "az", "az-Latn" },
193     { "bs", "bs-Latn" },
194     { "jv", "jv-Latn" },
195     { "uz", "uz-Latn" },
196     { "mn", "mn-Cyrl" },
197 };
198 
199 static std::unordered_map<TemperatureType, std::string> TEMPERATURE_TYPE_TO_NAME {
200     { TemperatureType::CELSIUS, "celsius" },
201     { TemperatureType::FAHRENHEIT, "fahrenhe" },
202     { TemperatureType::KELVIN, "kelvin" }
203 };
204 
205 static std::unordered_map<std::string, TemperatureType> NAME_TO_TEMPERATURE_TYPE {
206     { "celsius", TemperatureType::CELSIUS },
207     { "fahrenhe", TemperatureType::FAHRENHEIT },
208     { "kelvin", TemperatureType::KELVIN }
209 };
210 
211 static std::unordered_set<std::string> FAHRENHEIT_USING_REGIONS {
212     "BS",
213     "BZ",
214     "KY",
215     "PW",
216     "US"
217 };
218 
219 static std::unordered_map<WeekDay, std::string> WEEK_DAY_TO_NAME {
220     { WeekDay::MON, "mon" },
221     { WeekDay::TUE, "tue" },
222     { WeekDay::WED, "wed" },
223     { WeekDay::THU, "thu" },
224     { WeekDay::FRI, "fri" },
225     { WeekDay::SAT, "sat" },
226     { WeekDay::SUN, "sun" }
227 };
228 
229 static std::unordered_map<std::string, WeekDay> NAME_TO_WEEK_DAY {
230     { "mon", WeekDay::MON },
231     { "tue", WeekDay::TUE },
232     { "wed", WeekDay::WED },
233     { "thu", WeekDay::THU },
234     { "fri", WeekDay::FRI },
235     { "sat", WeekDay::SAT },
236     { "sun", WeekDay::SUN }
237 };
238 
239 std::unordered_map<icu::Calendar::EDaysOfWeek, WeekDay> LocaleConfigExt::eDaysOfWeekToWeekDay {
240     { icu::Calendar::EDaysOfWeek::MONDAY, WeekDay::MON },
241     { icu::Calendar::EDaysOfWeek::TUESDAY, WeekDay::TUE },
242     { icu::Calendar::EDaysOfWeek::WEDNESDAY, WeekDay::WED },
243     { icu::Calendar::EDaysOfWeek::THURSDAY, WeekDay::THU },
244     { icu::Calendar::EDaysOfWeek::FRIDAY, WeekDay::FRI },
245     { icu::Calendar::EDaysOfWeek::SATURDAY, WeekDay::SAT },
246     { icu::Calendar::EDaysOfWeek::SUNDAY, WeekDay::SUN }
247 };
248 
249 std::map<std::string, std::string> LocaleConfig::supportedDialectLocales;
250 std::map<string, string> LocaleConfig::locale2DisplayName {};
251 std::map<string, string> LocaleConfig::region2DisplayName {};
252 std::unordered_map<std::string, bool> LocaleConfig::is24HourLocaleMap {};
253 std::string LocaleConfig::currentDialectLocale = "";
254 std::string LocaleConfig::currentOverrideRegion = "";
255 std::mutex LocaleConfig::dialectLocaleMutex;
256 std::mutex LocaleConfig::region2DisplayNameMutex;
257 std::mutex LocaleConfig::locale2DisplayNameMutex;
258 std::shared_mutex LocaleConfig::is24HourLocaleMapMutex;
259 
260 set<std::string> LocaleConfig::validCaTag {
261     "buddhist",
262     "chinese",
263     "coptic",
264     "dangi",
265     "ethioaa",
266     "ethiopic",
267     "gregory",
268     "hebrew",
269     "indian",
270     "islamic",
271     "islamic-umalqura",
272     "islamic-tbla",
273     "islamic-civil",
274     "islamic-rgsa",
275     "iso8601",
276     "japanese",
277     "persian",
278     "roc",
279     "islamicc",
280 };
281 set<std::string> LocaleConfig::validCoTag {
282     "big5han",
283     "compat",
284     "dict",
285     "direct",
286     "ducet",
287     "eor",
288     "gb2312",
289     "phonebk",
290     "phonetic",
291     "pinyin",
292     "reformed",
293     "searchjl",
294     "stroke",
295     "trad",
296     "unihan",
297     "zhuyin",
298 };
299 set<std::string> LocaleConfig::validKnTag {
300     "true",
301     "false",
302 };
303 set<std::string> LocaleConfig::validKfTag {
304     "upper",
305     "lower",
306     "false",
307 };
308 set<std::string> LocaleConfig::validNuTag {
309     "adlm", "ahom", "arab", "arabext", "bali", "beng",
310     "bhks", "brah", "cakm", "cham", "deva", "diak",
311     "fullwide", "gong", "gonm", "gujr", "guru", "hanidec",
312     "hmng", "hmnp", "java", "kali", "khmr", "knda",
313     "lana", "lanatham", "laoo", "latn", "lepc", "limb",
314     "mathbold", "mathdbl", "mathmono", "mathsanb", "mathsans", "mlym",
315     "modi", "mong", "mroo", "mtei", "mymr", "mymrshan",
316     "mymrtlng", "newa", "nkoo", "olck", "orya", "osma",
317     "rohg", "saur", "segment", "shrd", "sind", "sinh",
318     "sora", "sund", "takr", "talu", "tamldec", "telu",
319     "thai", "tibt", "tirh", "vaii", "wara", "wcho",
320 };
321 set<std::string> LocaleConfig::validHcTag {
322     "h12",
323     "h23",
324     "h11",
325     "h24",
326 };
327 
328 static unordered_map<string, string> g_languageMap = {
329     { "zh-Hans", "zh-Hans" },
330     { "zh-Hant-HK", "zh-Hant-HK" },
331     { "zh-Hant", "zh-Hant" },
332     { "my-Qaag", "my-Qaag" },
333     { "es-Latn-419", "es-419" },
334     { "es-Latn-US", "es-419" },
335     { "az-Latn", "az-Latn" },
336     { "bs-Latn", "bs-Latn" },
337     { "en-Latn-US", "en" },
338     { "en-Qaag", "en-Qaag" },
339     { "uz-Latn", "uz-Latn" },
340     { "sr-Latn", "sr-Latn" },
341     { "jv-Latn", "jv-Latn" },
342     { "pt-Latn-BR", "pt-BR" },
343     { "pa-Guru", "pa-Guru" },
344     { "mai-Deva", "mai-Deva" }
345 };
346 
347 static const std::unordered_map<std::string, std::unordered_set<std::string>> LANGUAGE_TO_COLLATION_VALUES {
348     { "zh-Hant", { "zhuyin", "pinyin", "stroke" } },
349     { "en-Latn-US", { "upper", "lower" } }
350 };
351 
352 static const std::unordered_map<std::string, std::string> LANGUAGE_TO_COLLATION_KEY {
353     { "zh-Hant", "collation" },
354     { "en-Latn-US", "colCaseFirst" }
355 };
356 
357 static const std::unordered_map<std::string, std::string> LANGUAGE_TO_EXT_PARAM_KEY {
358     { "zh-Hant", "co" },
359     { "en-Latn-US", "kf" }
360 };
361 
362 static const std::unordered_map<std::string, std::string> LANGUAGE_TO_DEFAULT_COLLATION_VALUE {
363     { "zh-Hant", "stroke" },
364     { "en-Latn-US", "lower" }
365 };
366 
367 static const std::unordered_map<std::string, std::string> LANGUAGE_TO_NUMBERING_SYSTEM {
368     { "ar", "arab" },
369     { "as", "beng" },
370     { "bn", "beng" },
371     { "fa", "arabext" },
372     { "mr", "deva" },
373     { "my", "mymr" },
374     { "ne", "deva" },
375     { "ur", "arabext" }
376 };
377 
378 static const std::unordered_map<std::string, std::string> NUMBERING_SYSTEM_NAME_TO_DESCRIPTION {
379     { "arab", "٠١٢٣٤٥٦٧٨٩" },
380     { "beng", "০১২৩৪৫৬৭৮৯" },
381     { "arabext", "۰۱۲۳۴۵۶۷۸۹" },
382     { "deva", "०१२३४५६७८९" },
383     { "mymr", "၀၁၂၃၄၅၆၇၈၉" },
384     { "latn", "0123456789" }
385 };
386 
387 static const std::unordered_map<std::string, std::pair<std::string, std::string>> CODE_TO_NUMBER_PATTERN {
388     { "002c002e", { ",", "." } },
389     { "0000002e", { "", "." } },
390     { "002e002c", { ".", "," } },
391     { "0000002c", { "", "," } }
392 };
393 
394 static const std::unordered_map<UMeasurementSystem, std::string> UMEASUREMENT_SYSTEM_TO_VALUE {
395     { UMeasurementSystem::UMS_UK, "uksystem"},
396     { UMeasurementSystem::UMS_SI, "metric"},
397     { UMeasurementSystem::UMS_US, "ussystem"}
398 };
399 
Adjust(const string & origin)400 string Adjust(const string &origin)
401 {
402     auto iter = g_languageMap.find(origin);
403     if (iter != g_languageMap.end()) {
404         return iter->second;
405     }
406     for (iter = g_languageMap.begin(); iter != g_languageMap.end(); ++iter) {
407         string key = iter->first;
408         if (!origin.compare(0, key.length(), key)) {
409             return iter->second;
410         }
411     }
412     return origin;
413 }
414 
GetDisplayLanguageInner(const string & language,const string & displayLocaleTag,bool sentenceCase)415 string GetDisplayLanguageInner(const string &language, const string &displayLocaleTag, bool sentenceCase)
416 {
417     icu::UnicodeString unistr;
418     // 0 is the start position of language, 2 is the length of zh and fa
419     if (!language.compare(0, 2, "zh") || !language.compare(0, 2, "fa") || !language.compare(0, 2, "ro")) {
420         UErrorCode status = U_ZERO_ERROR;
421         icu::Locale displayLocale = icu::Locale::forLanguageTag(displayLocaleTag.c_str(), status);
422         if (U_FAILURE(status)) {
423             return "";
424         }
425         icu::Locale tempLocale = icu::Locale::forLanguageTag(language.c_str(), status);
426         if (U_FAILURE(status)) {
427             return "";
428         }
429         icu::LocaleDisplayNames *dspNames = icu::LocaleDisplayNames::createInstance(displayLocale,
430             UDialectHandling::ULDN_DIALECT_NAMES);
431         if (dspNames != nullptr) {
432             dspNames->localeDisplayName(tempLocale, unistr);
433             delete dspNames;
434         }
435     } else {
436         UErrorCode status = U_ZERO_ERROR;
437         icu::Locale displayLoc = icu::Locale::forLanguageTag(displayLocaleTag, status);
438         if (U_FAILURE(status)) {
439             return "";
440         }
441         icu::Locale locale = icu::Locale::forLanguageTag(language, status);
442         if (U_FAILURE(status)) {
443             return "";
444         }
445         locale.getDisplayName(displayLoc, unistr);
446     }
447     if (sentenceCase) {
448         UChar32 ch = ucase_toupper(unistr.char32At(0));
449         unistr.replace(0, 1, ch);
450     }
451     string out;
452     unistr.toUTF8String(out);
453     return out;
454 }
455 
456 bool LocaleConfig::listsInitialized = LocaleConfig::InitializeLists();
457 
GetEffectiveLanguage()458 std::string LocaleConfig::GetEffectiveLanguage()
459 {
460     std::string systemLocale = GetSystemLocale();
461     std::string systemLanguage = GetSystemLanguage();
462     return ComputeEffectiveLanguage(systemLocale, systemLanguage);
463 }
464 
GetEffectiveLocale()465 std::string LocaleConfig::GetEffectiveLocale()
466 {
467     std::string systemLocale = ReadSystemParameter(LOCALE_KEY.c_str(), CONFIG_LEN);
468     if (!systemLocale.empty()) {
469         return systemLocale;
470     }
471     systemLocale = ReadSystemParameter(DEFAULT_LOCALE_KEY, CONFIG_LEN);
472     if (systemLocale.empty()) {
473         HILOG_ERROR_I18N("LocaleConfig::GetEffectiveLocale: Read default system locale failed.");
474         return "zh-Hans-CN";
475     }
476     return systemLocale;
477 }
478 
GetSystemLanguage()479 string LocaleConfig::GetSystemLanguage()
480 {
481     std::string systemLanguage = ReadSystemParameter(LANGUAGE_KEY.c_str(), CONFIG_LEN);
482     if (!systemLanguage.empty()) {
483         return systemLanguage;
484     }
485     systemLanguage = ReadSystemParameter(DEFAULT_LANGUAGE_KEY, CONFIG_LEN);
486     if (systemLanguage.empty()) {
487         HILOG_ERROR_I18N("LocaleConfig::GetSystemLanguage: Read default system language failed.");
488         return "zh-Hans";
489     }
490     return systemLanguage;
491 }
492 
GetSystemRegion()493 string LocaleConfig::GetSystemRegion()
494 {
495     std::string systemRegion = GetCountry(LOCALE_KEY);
496     if (systemRegion.empty()) {
497         systemRegion = GetCountry(DEFAULT_LOCALE_KEY);
498     }
499     if (systemRegion.empty()) {
500         HILOG_ERROR_I18N("LocaleConfig::GetSystemRegion: system region is empty.");
501         return "CN";
502     }
503     return systemRegion;
504 }
505 
GetCountry(const string & parameter)506 string LocaleConfig::GetCountry(const string& parameter)
507 {
508     std::string systemRegion = ReadSystemParameter(parameter.c_str(), CONFIG_LEN);
509     if (systemRegion.empty()) {
510         HILOG_ERROR_I18N("LocaleConfig::GetCountry: ReadSystemParameter %{public}s failed.", parameter.c_str());
511         return systemRegion;
512     }
513     UErrorCode status = U_ZERO_ERROR;
514     icu::Locale origin = icu::Locale::forLanguageTag(systemRegion, status);
515     if (U_FAILURE(status)) {
516         HILOG_ERROR_I18N("LocaleConfig::GetCountry: Create icu::Locale failed.");
517         return "";
518     }
519     const char* country = origin.getCountry();
520     if (country == nullptr) {
521         HILOG_ERROR_I18N("LocaleConfig::GetCountry: Get country from icu::Locale failed.");
522         return "";
523     }
524     return country;
525 }
526 
GetSystemLocale()527 string LocaleConfig::GetSystemLocale()
528 {
529     std::string systemLocale = GetEffectiveLocale();
530     std::vector<std::pair<size_t, std::string>> positions = GetExtParamPositions(systemLocale);
531     if (positions[0].first != std::string::npos) {
532         systemLocale = systemLocale.substr(0, positions[0].first);
533     }
534     return systemLocale;
535 }
536 
GetSystemTimezone()537 std::string LocaleConfig::GetSystemTimezone()
538 {
539     std::string systemTimezone = ReadSystemParameter(TIMEZONE_KEY.c_str(), CONFIG_LEN);
540     if (systemTimezone.empty()) {
541         HILOG_ERROR_I18N("LocaleConfig::GetSystemTimezone: Read system time zone failed.");
542         return DEFAULT_TIMEZONE;
543     }
544     return systemTimezone;
545 }
546 
IsValidLanguage(const string & language)547 bool LocaleConfig::IsValidLanguage(const string &language)
548 {
549     string::size_type size = language.size();
550     if ((size != LANGUAGE_LEN) && (size != LANGUAGE_LEN + 1)) {
551         return false;
552     }
553     for (size_t i = 0; i < size; ++i) {
554         if ((language[i] > 'z') || (language[i] < 'a')) {
555             return false;
556         }
557     }
558     return true;
559 }
560 
IsValidRegion(const string & region)561 bool LocaleConfig::IsValidRegion(const string &region)
562 {
563     string::size_type size = region.size();
564     if (size != LocaleInfo::REGION_LEN) {
565         return false;
566     }
567     for (size_t i = 0; i < LocaleInfo::REGION_LEN; ++i) {
568         if ((region[i] > 'Z') || (region[i] < 'A')) {
569             return false;
570         }
571     }
572     return true;
573 }
574 
IsValidTag(const string & tag)575 bool LocaleConfig::IsValidTag(const string &tag)
576 {
577     if (!tag.size()) {
578         return false;
579     }
580     vector<string> splits;
581     Split(tag, "-", splits);
582     if (!IsValidLanguage(splits[0])) {
583         return false;
584     }
585     return true;
586 }
587 
Split(const string & src,const string & sep,vector<string> & dest)588 void LocaleConfig::Split(const string &src, const string &sep, vector<string> &dest)
589 {
590     string::size_type begin = 0;
591     string::size_type end = src.find(sep);
592     while (end != string::npos) {
593         dest.push_back(src.substr(begin, end - begin));
594         begin = end + sep.size();
595         end = src.find(sep, begin);
596     }
597     if (begin != src.size()) {
598         dest.push_back(src.substr(begin));
599     }
600 }
601 
Split(const string & src,const string & sep,std::unordered_set<string> & dest)602 void LocaleConfig::Split(const string &src, const string &sep, std::unordered_set<string> &dest)
603 {
604     string::size_type begin = 0;
605     string::size_type end = src.find(sep);
606     while (end != string::npos) {
607         dest.insert(src.substr(begin, end - begin));
608         begin = end + sep.size();
609         end = src.find(sep, begin);
610     }
611     if (begin != src.size()) {
612         dest.insert(src.substr(begin));
613     }
614 }
615 
616 // language in white languages should have script.
GetSystemLanguages()617 std::unordered_set<std::string> LocaleConfig::GetSystemLanguages()
618 {
619     std::unordered_set<std::string> result(whiteLanguages);
620     std::unordered_set<string> blockedLanguages = GetBlockedLanguages();
621     Expunge(result, blockedLanguages);
622     return result;
623 }
624 
GetSupportedLocales()625 const unordered_set<string>& LocaleConfig::GetSupportedLocales()
626 {
627     return supportedLocales;
628 }
629 
GetSupportedLocalesV15()630 const unordered_set<string>& LocaleConfig::GetSupportedLocalesV15()
631 {
632     return supportedLocalesV15;
633 }
634 
GetSupportedRegions()635 const unordered_set<string>& LocaleConfig::GetSupportedRegions()
636 {
637     return supportedRegions;
638 }
639 
GetSystemCountries(const std::string & language)640 std::unordered_set<std::string> LocaleConfig::GetSystemCountries(const std::string& language)
641 {
642     std::unordered_set<std::string> result(supportedRegions);
643     std::unordered_set<std::string> blockedRegion = LocaleConfig::GetBlockedRegions(language);
644     Expunge(result, blockedRegion);
645     return result;
646 }
647 
IsSuggested(const string & language)648 bool LocaleConfig::IsSuggested(const string &language)
649 {
650     unordered_set<string> relatedLocales;
651     vector<string> simCountries;
652     GetCountriesFromSim(simCountries);
653     GetRelatedLocales(relatedLocales, simCountries);
654     for (auto iter = relatedLocales.begin(); iter != relatedLocales.end();) {
655         if (extendWhiteLanguageList.find(*iter) == extendWhiteLanguageList.end()) {
656             iter = relatedLocales.erase(iter);
657         } else {
658             ++iter;
659         }
660     }
661     string mainLanguage = GetMainLanguage(language, dialectMap);
662     return relatedLocales.find(mainLanguage) != relatedLocales.end();
663 }
664 
IsSuggested(const std::string & language,const std::string & region)665 bool LocaleConfig::IsSuggested(const std::string &language, const std::string &region)
666 {
667     unordered_set<string> relatedLocales;
668     vector<string> countries { region };
669     GetRelatedLocales(relatedLocales, countries);
670     for (auto iter = relatedLocales.begin(); iter != relatedLocales.end();) {
671         if (extendWhiteLanguageList.find(*iter) == extendWhiteLanguageList.end()) {
672             iter = relatedLocales.erase(iter);
673         } else {
674             ++iter;
675         }
676     }
677     string mainLanguage = GetMainLanguage(language, dialectMap);
678     return relatedLocales.find(mainLanguage) != relatedLocales.end();
679 }
680 
IsSuggestedV15(const string & language)681 bool LocaleConfig::IsSuggestedV15(const string &language)
682 {
683     unordered_set<string> relatedLocales;
684     vector<string> simCountries;
685     GetCountriesFromSim(simCountries);
686     GetRelatedLocalesV15(relatedLocales, simCountries);
687     auto iter = relatedLocales.begin();
688     while (iter != relatedLocales.end()) {
689         if (extendWhiteLanguageListV15.find(*iter) == extendWhiteLanguageListV15.end()) {
690             iter = relatedLocales.erase(iter);
691         } else {
692             ++iter;
693         }
694     }
695     string mainLanguage = GetMainLanguage(language, dialectMapV15);
696     return relatedLocales.find(mainLanguage) != relatedLocales.end();
697 }
698 
IsSuggestedV15(const std::string & language,const std::string & region)699 bool LocaleConfig::IsSuggestedV15(const std::string &language, const std::string &region)
700 {
701     unordered_set<string> relatedLocales;
702     vector<string> countries { region };
703     GetRelatedLocalesV15(relatedLocales, countries);
704     auto iter = relatedLocales.begin();
705     while (iter != relatedLocales.end()) {
706         if (extendWhiteLanguageListV15.find(*iter) == extendWhiteLanguageListV15.end()) {
707             iter = relatedLocales.erase(iter);
708         } else {
709             ++iter;
710         }
711     }
712     string mainLanguage = GetMainLanguage(language, dialectMapV15);
713     return relatedLocales.find(mainLanguage) != relatedLocales.end();
714 }
715 
ExtendWhiteLanguages()716 void LocaleConfig::ExtendWhiteLanguages()
717 {
718     UErrorCode status = U_ZERO_ERROR;
719     for (auto iter = whiteLanguages.begin(); iter != whiteLanguages.end(); ++iter) {
720         extendWhiteLanguageList.insert(*iter);
721         extendWhiteLanguageListV15.insert(*iter);
722         icu::Locale locale = icu::Locale::forLanguageTag((*iter).c_str(), status);
723         locale.addLikelySubtags(status);
724         if (U_FAILURE(status)) {
725             continue;
726         }
727         const char* baseName = locale.getBaseName();
728         if (baseName != nullptr) {
729             std::string baseNameStr(baseName);
730             std::replace(baseNameStr.begin(), baseNameStr.end(), '_', '-');
731             extendWhiteLanguageList.insert(baseNameStr);
732             extendWhiteLanguageListV15.insert(baseNameStr);
733         }
734         const char* language = locale.getLanguage();
735         if (language != nullptr) {
736             std::string languageStr(language);
737             ExtendLanguageWithScript(languageStr);
738         }
739     }
740 }
741 
ExtendLanguageWithScript(const std::string & languageStr)742 void LocaleConfig::ExtendLanguageWithScript(const std::string &languageStr)
743 {
744     if (languageStr.empty()) {
745         HILOG_ERROR_I18N("ExtendLanguageWithScript languageStr is empty.");
746         return;
747     }
748     string mainLanguage = GetMainLanguage(languageStr, dialectMap);
749     if (!mainLanguage.empty()) {
750         extendWhiteLanguageList.insert(mainLanguage);
751     }
752 }
753 
GetRelatedLocales(unordered_set<string> & relatedLocales,vector<string> countries)754 void LocaleConfig::GetRelatedLocales(unordered_set<string> &relatedLocales, vector<string> countries)
755 {
756     // remove unsupported countries
757     const unordered_set<string> &regions = GetSupportedRegions();
758     auto iter = countries.begin();
759     while (iter != countries.end()) {
760         if (regions.find(*iter) == regions.end()) {
761             iter = countries.erase(iter);
762         } else {
763             ++iter;
764         }
765     }
766     const unordered_set<string> &locales = GetSupportedLocales();
767     for (const string &locale : locales) {
768         bool find = false;
769         for (string &country : countries) {
770             if (locale.find(country) != string::npos) {
771                 find = true;
772                 break;
773             }
774         }
775         if (!find) {
776             continue;
777         }
778         string mainLanguage = GetMainLanguage(locale, dialectMap);
779         if (!mainLanguage.empty()) {
780             relatedLocales.insert(mainLanguage);
781         }
782     }
783 }
784 
GetRelatedLocalesV15(unordered_set<string> & relatedLocales,vector<string> countries)785 void LocaleConfig::GetRelatedLocalesV15(unordered_set<string> &relatedLocales, vector<string> countries)
786 {
787     // remove unsupported countries
788     const unordered_set<string> &regions = GetSupportedRegions();
789     auto iter = countries.begin();
790     while (iter != countries.end()) {
791         if (regions.find(*iter) == regions.end()) {
792             iter = countries.erase(iter);
793         } else {
794             ++iter;
795         }
796     }
797     const unordered_set<string> &locales = GetSupportedLocalesV15();
798     for (const string &locale : locales) {
799         bool find = false;
800         for (const string &country : countries) {
801             if (locale.find(country) != string::npos) {
802                 find = true;
803                 break;
804             }
805         }
806         if (!find) {
807             continue;
808         }
809         string mainLanguage = GetMainLanguage(locale, dialectMapV15);
810         if (!mainLanguage.empty()) {
811             relatedLocales.insert(mainLanguage);
812         }
813     }
814 }
815 
GetCountriesFromSim(vector<string> & simCountries)816 void LocaleConfig::GetCountriesFromSim(vector<string> &simCountries)
817 {
818     simCountries.push_back(GetSystemRegion());
819     char value[CONFIG_LEN];
820     int code = GetParameter(SIM_COUNTRY_CODE_KEY, "", value, CONFIG_LEN);
821     if (code > 0) {
822         simCountries.push_back(value);
823     }
824 }
825 
GetListFromFile(const char * path,const char * resourceName,unordered_set<string> & ret)826 void LocaleConfig::GetListFromFile(const char *path, const char *resourceName, unordered_set<string> &ret)
827 {
828     xmlKeepBlanksDefault(0);
829     if (!path) {
830         return;
831     }
832     xmlDocPtr doc = xmlParseFile(path);
833     if (!doc) {
834         return;
835     }
836     xmlNodePtr cur = xmlDocGetRootElement(doc);
837     if (!cur || xmlStrcmp(cur->name, reinterpret_cast<const xmlChar *>(resourceName))) {
838         xmlFreeDoc(doc);
839         return;
840     }
841     cur = cur->xmlChildrenNode;
842     xmlChar *content = nullptr;
843     while (cur != nullptr) {
844         content = xmlNodeGetContent(cur);
845         if (content != nullptr) {
846             ret.insert(reinterpret_cast<const char*>(content));
847             xmlFree(content);
848             cur = cur->next;
849         } else {
850             break;
851         }
852     }
853     xmlFreeDoc(doc);
854 }
855 
Expunge(unordered_set<string> & src,const unordered_set<string> & another)856 void LocaleConfig::Expunge(unordered_set<string> &src, const unordered_set<string> &another)
857 {
858     for (auto iter = src.begin(); iter != src.end();) {
859         if (another.find(*iter) != another.end()) {
860             iter = src.erase(iter);
861         } else {
862             ++iter;
863         }
864     }
865 }
866 
InitializeLists()867 bool LocaleConfig::InitializeLists()
868 {
869     SetHwIcuDirectory();
870     LoadRegionsLanguages();
871     GetListFromFile(SUPPORTED_LOCALES_PATH, SUPPORTED_LOCALES_NAME, supportedLocales);
872     GetListFromFile(SUPPORTED_LOCALES_OLD_PATH, SUPPORTED_LOCALES_NAME, supportedLocalesV15);
873     GetListFromFile(SUPPORT_LOCALES_PATH, SUPPORT_LOCALES_NAME, supportLocales);
874     GetListFromFile(OVERRIDE_SUPPORTED_REGIONS_PATH, OVERRIDE_SUPPORTED_REGIONS_NAME, overrideSupportedRegions);
875     GetListFromFile(DIALECT_LANGS_PATH, DIALECT_LANGS_NAME, dialectLang);
876     ExtendWhiteLanguages();
877     return true;
878 }
879 
CleanupXmlResources()880 __attribute__((destructor)) void LocaleConfig::CleanupXmlResources()
881 {
882     if (listsInitialized) {
883         xmlCleanupParser();
884     }
885 }
886 
LoadRegionsLanguages()887 void LocaleConfig::LoadRegionsLanguages()
888 {
889     char buf[MAX_PATH_LEN] = {0};
890     char* path = GetOneCfgFile(REGIONS_LANGUAGES_PATH, buf, MAX_PATH_LEN);
891     xmlKeepBlanksDefault(0);
892     if (!path) {
893         return;
894     }
895     xmlDocPtr doc = xmlParseFile(path);
896     if (!doc) {
897         return;
898     }
899     xmlNodePtr cur = xmlDocGetRootElement(doc);
900     if (!cur || xmlStrcmp(cur->name, reinterpret_cast<const xmlChar *>(REGIONS_LANGUAGES_NAME))) {
901         xmlFreeDoc(doc);
902         return;
903     }
904     cur = cur->xmlChildrenNode;
905     xmlChar *content = nullptr;
906     while (cur != nullptr) {
907         content = xmlNodeGetContent(cur);
908         if (content != nullptr && !xmlStrcmp(cur->name, reinterpret_cast<const xmlChar *>(SUPPORTED_REGIONS_NAME))) {
909             Split(reinterpret_cast<const char*>(content), ",", supportedRegions);
910         } else if (content != nullptr && !xmlStrcmp(cur->name,
911             reinterpret_cast<const xmlChar *>(WHITE_LANGUAGES_NAME))) {
912             Split(reinterpret_cast<const char*>(content), ",", whiteLanguages);
913         }
914         if (content != nullptr) {
915             xmlFree(content);
916         }
917         cur = cur->next;
918     }
919     xmlFreeDoc(doc);
920 }
921 
GetMainLanguage(const string & language,std::unordered_map<std::string,std::string> selfDialectMap)922 string LocaleConfig::GetMainLanguage(const string &language,
923     std::unordered_map<std::string, std::string> selfDialectMap)
924 {
925     UErrorCode status = U_ZERO_ERROR;
926     icu::Locale origin = icu::Locale::forLanguageTag(language, status);
927     if (U_FAILURE(status)) {
928         return "";
929     }
930     origin.addLikelySubtags(status);
931     if (U_FAILURE(status)) {
932         return "";
933     }
934     icu::LocaleBuilder builder = icu::LocaleBuilder().setLanguage(origin.getLanguage()).
935         setScript(origin.getScript()).setRegion(origin.getCountry());
936     icu::Locale temp = builder.setExtension('u', "").build(status);
937     if (U_FAILURE(status)) {
938         return "";
939     }
940     string fullLanguage = temp.toLanguageTag<string>(status);
941     if (U_FAILURE(status)) {
942         return "";
943     }
944     if (selfDialectMap.find(fullLanguage) != selfDialectMap.end()) {
945         return selfDialectMap[fullLanguage];
946     }
947     builder.setRegion("");
948     temp = builder.build(status);
949     if (U_FAILURE(status)) {
950         return "";
951     }
952     fullLanguage = temp.toLanguageTag<string>(status);
953     if (U_FAILURE(status)) {
954         return "";
955     }
956     return fullLanguage;
957 }
958 
GetDisplayLanguage(const string & language,const string & displayLocale,bool sentenceCase)959 string LocaleConfig::GetDisplayLanguage(const string &language, const string &displayLocale, bool sentenceCase)
960 {
961     std::string result = GetPseudoDisplayLanguage(language);
962     if (!result.empty()) {
963         return result;
964     }
965     string adjust = Adjust(language);
966     if (adjust == language) {
967         UErrorCode status = U_ZERO_ERROR;
968         icu::Locale displayLoc = icu::Locale::forLanguageTag(displayLocale, status);
969         if (U_FAILURE(status)) {
970             return PseudoLocalizationProcessor("");
971         }
972         icu::Locale locale = icu::Locale::forLanguageTag(language, status);
973         if (U_FAILURE(status)) {
974             return PseudoLocalizationProcessor("");
975         }
976         icu::UnicodeString unistr;
977         std::string lang(locale.getLanguage());
978         if (dialectLang.find(lang) != dialectLang.end()) {
979             result = GetDisplayLanguageWithDialect(language, displayLocale);
980         }
981     }
982     if (result.empty()) {
983         result = GetDisplayLanguageInner(adjust, displayLocale, sentenceCase);
984     }
985     TabooUtils* tabooUtils = TabooUtils::GetInstance();
986     if (tabooUtils != nullptr) {
987         result = tabooUtils->ReplaceLanguageName(adjust, displayLocale, result);
988     } else {
989         HILOG_ERROR_I18N("LocaleConfig::GetDisplayLanguage: tabooUtils is nullptr.");
990     }
991     if (sentenceCase && !result.empty()) {
992         char ch = static_cast<char>(toupper(result[0]));
993         return PseudoLocalizationProcessor(result.replace(0, 1, 1, ch));
994     }
995     return PseudoLocalizationProcessor(result);
996 }
997 
GetPseudoDisplayLanguage(const std::string & language)998 std::string LocaleConfig::GetPseudoDisplayLanguage(const std::string &language)
999 {
1000     if (language.compare("en-XA") == 0) {
1001         return "[Pseudo locale]";
1002     }
1003     if (language.compare("ar-XB") == 0) {
1004         return "[Bidirection test locale]";
1005     }
1006     return "";
1007 }
1008 
ComputeLocale(const std::string & displayLocale)1009 std::string LocaleConfig::ComputeLocale(const std::string &displayLocale)
1010 {
1011     if (supportedDialectLocales.size() == 0) {
1012         xmlKeepBlanksDefault(0);
1013         xmlDocPtr doc = xmlParseFile(SUPPORT_LOCALES_PATH);
1014         if (!doc) {
1015             return "";
1016         }
1017         xmlNodePtr cur = xmlDocGetRootElement(doc);
1018         if (!cur || xmlStrcmp(cur->name, reinterpret_cast<const xmlChar *>(supportLocalesTag))) {
1019             xmlFreeDoc(doc);
1020             HILOG_ERROR_I18N("can not parse language supported locale file");
1021             return "";
1022         }
1023         cur = cur->xmlChildrenNode;
1024         while (cur != nullptr) {
1025             xmlChar *content = xmlNodeGetContent(cur);
1026             if (content == nullptr) {
1027                 HILOG_ERROR_I18N("get xml node content failed");
1028                 break;
1029             }
1030             std::map<std::string, std::string> localeInfoConfigs = {};
1031             LocaleInfo localeinfo(reinterpret_cast<const char*>(content), localeInfoConfigs);
1032             std::string maximizeLocale = localeinfo.Maximize();
1033             const char* key = maximizeLocale.c_str();
1034             const char* value = reinterpret_cast<const char*>(content);
1035             SetSupportedDialectLocales(key, value);
1036             xmlFree(content);
1037             cur = cur->next;
1038         }
1039         xmlFreeDoc(doc);
1040     }
1041     std::map<std::string, std::string> configs = {};
1042     LocaleInfo localeinfo(displayLocale, configs);
1043     std::string maximizeLocale = localeinfo.Maximize();
1044     if (supportedDialectLocales.find(maximizeLocale) != supportedDialectLocales.end()) {
1045         return supportedDialectLocales.at(maximizeLocale);
1046     }
1047     return "";
1048 }
1049 
SetSupportedDialectLocales(const char * key,const char * value)1050 void LocaleConfig::SetSupportedDialectLocales(const char* key, const char* value)
1051 {
1052     std::lock_guard<std::mutex> dialectLocaleLock(dialectLocaleMutex);
1053     supportedDialectLocales.insert(
1054         std::make_pair<std::string, std::string>(key, value));
1055 }
1056 
ReadLangData(const char * langDataPath)1057 void LocaleConfig::ReadLangData(const char *langDataPath)
1058 {
1059     xmlKeepBlanksDefault(0);
1060     if (langDataPath == nullptr) {
1061         return;
1062     }
1063     xmlDocPtr doc = xmlParseFile(langDataPath);
1064     if (!doc) {
1065         HILOG_ERROR_I18N("can not open language data file");
1066         return;
1067     }
1068     xmlNodePtr cur = xmlDocGetRootElement(doc);
1069     if (!cur || xmlStrcmp(cur->name, reinterpret_cast<const xmlChar *>(rootTag))) {
1070         xmlFreeDoc(doc);
1071         HILOG_ERROR_I18N("parse language data file failed");
1072         return;
1073     }
1074     cur = cur->xmlChildrenNode;
1075     while (cur != nullptr && !xmlStrcmp(cur->name, reinterpret_cast<const xmlChar *>(secondRootTag))) {
1076         xmlChar *langContents[ELEMENT_NUM] = { 0 }; // 2 represent langid, displayname;
1077         xmlNodePtr langValue = cur->xmlChildrenNode;
1078         bool xmlNodeNull = false;
1079         for (size_t i = 0; i < ELEMENT_NUM && langValue != nullptr; i++) {
1080             langContents[i] = xmlNodeGetContent(langValue);
1081             langValue = langValue->next;
1082             if (langContents[i] == nullptr) {
1083                 xmlNodeNull = true;
1084             }
1085         }
1086         if (!xmlNodeNull) {
1087             // 0 represents langid index, 1 represents displayname index
1088             const char* key = reinterpret_cast<const char *>(langContents[0]);
1089             const char* value = reinterpret_cast<const char *>(langContents[1]);
1090             SetLocale2DisplayName(key, value);
1091         }
1092         for (size_t i = 0; i < ELEMENT_NUM; i++) {
1093             if (langContents[i] != nullptr) {
1094                 xmlFree(langContents[i]);
1095             }
1096         }
1097         cur = cur->next;
1098     }
1099     xmlFreeDoc(doc);
1100 }
1101 
SetRegion2DisplayName(const char * key,const char * value)1102 void LocaleConfig::SetRegion2DisplayName(const char* key, const char* value)
1103 {
1104     std::lock_guard<std::mutex> regionDisplayLock(region2DisplayNameMutex);
1105     region2DisplayName.insert(
1106         std::make_pair<std::string, std::string>(key, value));
1107 }
1108 
SetLocale2DisplayName(const char * key,const char * value)1109 void LocaleConfig::SetLocale2DisplayName(const char* key, const char* value)
1110 {
1111     std::lock_guard<std::mutex> localeDisplayLock(locale2DisplayNameMutex);
1112     locale2DisplayName.insert(
1113         std::make_pair<std::string, std::string>(key, value));
1114 }
1115 
ReadRegionData(const char * regionDataPath)1116 void LocaleConfig::ReadRegionData(const char *regionDataPath)
1117 {
1118     xmlKeepBlanksDefault(0);
1119     if (regionDataPath == nullptr) {
1120         return;
1121     }
1122     xmlDocPtr doc = xmlParseFile(regionDataPath);
1123     if (!doc) {
1124         HILOG_ERROR_I18N("can not open region data file");
1125         return;
1126     }
1127     xmlNodePtr cur = xmlDocGetRootElement(doc);
1128     if (!cur || xmlStrcmp(cur->name, reinterpret_cast<const xmlChar *>(rootRegion))) {
1129         xmlFreeDoc(doc);
1130         HILOG_ERROR_I18N("parse region data file failed");
1131         return;
1132     }
1133     cur = cur->xmlChildrenNode;
1134     while (cur != nullptr && !xmlStrcmp(cur->name, reinterpret_cast<const xmlChar *>(secondRootRegion))) {
1135         xmlChar *regionContents[ELEMENT_NUM] = { 0 };
1136         xmlNodePtr regionValue = cur->xmlChildrenNode;
1137         bool xmlNodeNull = false;
1138         for (size_t i = 0; i < ELEMENT_NUM && regionValue != nullptr; i++) {
1139             regionContents[i] = xmlNodeGetContent(regionValue);
1140             regionValue = regionValue->next;
1141             if (regionContents[i] == nullptr) {
1142                 xmlNodeNull = true;
1143             }
1144         }
1145         if (!xmlNodeNull) {
1146             // 0 represents langid index, 1 represents displayname index
1147             const char* regionKey = reinterpret_cast<const char *>(regionContents[0]);
1148             const char* regionVal = reinterpret_cast<const char *>(regionContents[1]);
1149             SetRegion2DisplayName(regionKey, regionVal);
1150         }
1151         for (size_t i = 0; i < ELEMENT_NUM; i++) {
1152             if (regionContents[i] != nullptr) {
1153                 xmlFree(regionContents[i]);
1154             }
1155         }
1156         cur = cur->next;
1157     }
1158     xmlFreeDoc(doc);
1159 }
1160 
GetDisplayLanguageWithDialect(const std::string & localeStr,const std::string & displayLocale)1161 string LocaleConfig::GetDisplayLanguageWithDialect(const std::string &localeStr, const std::string &displayLocale)
1162 {
1163     std::string finalLocale = ComputeLocale(displayLocale);
1164     if (finalLocale.empty()) {
1165         return "";
1166     }
1167     if (finalLocale.compare(currentDialectLocale) != 0) {
1168         std::string xmlPath = LANG_PATH + finalLocale + ".xml";
1169         locale2DisplayName.clear();
1170         ReadLangData(xmlPath.c_str());
1171         currentDialectLocale = finalLocale;
1172     }
1173     if (locale2DisplayName.find(localeStr) != locale2DisplayName.end()) {
1174         return locale2DisplayName.at(localeStr);
1175     }
1176     std::map<std::string, std::string> configs = {};
1177     LocaleInfo locale(localeStr, configs);
1178     std::string language = locale.GetLanguage();
1179     std::string scripts = locale.GetScript();
1180     std::string region = locale.GetRegion();
1181     if (scripts.length() != 0) {
1182         std::string languageAndScripts = language + "-" + scripts;
1183         if (locale2DisplayName.find(languageAndScripts) != locale2DisplayName.end()) {
1184             return locale2DisplayName.at(languageAndScripts);
1185         }
1186     }
1187     if (region.length() != 0) {
1188         std::string languageAndRegion = language + "-" + region;
1189         if (locale2DisplayName.find(languageAndRegion) != locale2DisplayName.end()) {
1190             return locale2DisplayName.at(languageAndRegion);
1191         }
1192     }
1193     if (locale2DisplayName.find(language) != locale2DisplayName.end()) {
1194         return locale2DisplayName.at(language);
1195     }
1196     return "";
1197 }
1198 
GetDisplayOverrideRegion(const std::string & region,const std::string & displayLocale)1199 string LocaleConfig::GetDisplayOverrideRegion(const std::string &region, const std::string &displayLocale)
1200 {
1201     UErrorCode status = U_ZERO_ERROR;
1202     icu::Locale originLocale;
1203     icu::UnicodeString displayRegion;
1204     if (displayLocale.compare(currentOverrideRegion) != 0) {
1205         std::string xmlPath = REGION_PATH + displayLocale + ".xml";
1206         region2DisplayName.clear();
1207         ReadRegionData(xmlPath.c_str());
1208         currentOverrideRegion = displayLocale;
1209     }
1210     if (region2DisplayName.find(region) != region2DisplayName.end()) {
1211         return region2DisplayName.at(region);
1212     } else {
1213         icu::Locale locale = icu::Locale::forLanguageTag(displayLocale, status);
1214         if (U_FAILURE(status)) {
1215             return "";
1216         }
1217         if (IsValidRegion(region)) {
1218             icu::LocaleBuilder builder = icu::LocaleBuilder().setRegion(region);
1219             originLocale = builder.build(status);
1220         } else {
1221             originLocale = icu::Locale::forLanguageTag(region, status);
1222         }
1223         if (U_FAILURE(status)) {
1224             return "";
1225         }
1226         originLocale.getDisplayCountry(locale, displayRegion);
1227         std::string result;
1228         displayRegion.toUTF8String(result);
1229         return result;
1230     }
1231 }
1232 
GetDisplayRegion(const string & region,const string & displayLocale,bool sentenceCase)1233 string LocaleConfig::GetDisplayRegion(const string &region, const string &displayLocale, bool sentenceCase)
1234 {
1235     UErrorCode status = U_ZERO_ERROR;
1236     icu::Locale originLocale;
1237     if (IsValidRegion(region)) {
1238         icu::LocaleBuilder builder = icu::LocaleBuilder().setRegion(region);
1239         originLocale = builder.build(status);
1240     } else {
1241         originLocale = icu::Locale::forLanguageTag(region, status);
1242     }
1243     if (U_FAILURE(status)) {
1244         return PseudoLocalizationProcessor("");
1245     }
1246     std::string country(originLocale.getCountry());
1247     if (country.empty()) {
1248         return PseudoLocalizationProcessor("");
1249     }
1250     icu::Locale locale = icu::Locale::forLanguageTag(displayLocale, status);
1251     if (U_FAILURE(status)) {
1252         return PseudoLocalizationProcessor("");
1253     }
1254     icu::UnicodeString unistr;
1255     icu::UnicodeString displayRegion;
1256     std::string result;
1257     if (overrideSupportedRegions.find(displayLocale) != overrideSupportedRegions.end()) {
1258         result = GetDisplayOverrideRegion(region, displayLocale);
1259     } else {
1260         originLocale.getDisplayCountry(locale, displayRegion);
1261         displayRegion.toUTF8String(result);
1262     }
1263     TabooUtils* tabooUtils = TabooUtils::GetInstance();
1264     if (tabooUtils != nullptr) {
1265         result = tabooUtils->ReplaceCountryName(region, displayLocale, result);
1266     } else {
1267         HILOG_ERROR_I18N("LocaleConfig::GetDisplayRegion: tabooUtils is nullptr.");
1268     }
1269     if (sentenceCase) {
1270         char ch = static_cast<char>(toupper(result[0]));
1271         return PseudoLocalizationProcessor(result.replace(0, 1, 1, ch));
1272     }
1273     return PseudoLocalizationProcessor(result);
1274 }
1275 
IsRTL(const string & locale)1276 bool LocaleConfig::IsRTL(const string &locale)
1277 {
1278     icu::Locale curLocale(locale.c_str());
1279     return curLocale.isRightToLeft();
1280 }
1281 
parseExtension(const std::string & extension,std::map<std::string,std::string> & map)1282 void parseExtension(const std::string &extension, std::map<std::string, std::string> &map)
1283 {
1284     std::string pattern = "-..-";
1285     std::regex express(pattern);
1286 
1287     std::regex_token_iterator<std::string::const_iterator> begin1(extension.cbegin(), extension.cend(), express);
1288     std::regex_token_iterator<std::string::const_iterator> begin2(extension.cbegin(), extension.cend(), express, -1);
1289     begin2++;
1290     for (; begin1 != std::sregex_token_iterator() && begin2 != std::sregex_token_iterator(); begin1++, begin2++) {
1291         map.insert(std::pair<std::string, std::string>(begin1->str(), begin2->str()));
1292     }
1293 }
1294 
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)1295 void setExtension(std::string &extension, const std::string &tag, const std::set<string> &validValue,
1296     const std::map<std::string, std::string> &extensionMap,
1297     const std::map<std::string, std::string> &defaultExtensionMap)
1298 {
1299     std::string value;
1300     auto it = extensionMap.find(tag);
1301     if (it != extensionMap.end()) {
1302         value = it->second;
1303         if (validValue.find(value) == validValue.end()) {
1304             return;
1305         } else {
1306             extension += tag;
1307             extension += value;
1308         }
1309     } else {
1310         it = defaultExtensionMap.find(tag);
1311         if (it != defaultExtensionMap.end()) {
1312             value = it->second;
1313             if (validValue.find(value) == validValue.end()) {
1314                 return;
1315             } else {
1316                 extension += tag;
1317                 extension += value;
1318             }
1319         }
1320     }
1321 }
1322 
setOtherExtension(std::string & extension,std::map<std::string,std::string> & extensionMap,std::map<std::string,std::string> & defaultExtensionMap)1323 void setOtherExtension(std::string &extension, std::map<std::string, std::string> &extensionMap,
1324     std::map<std::string, std::string> &defaultExtensionMap)
1325 {
1326     std::set<std::string> tags;
1327     tags.insert("-ca-");
1328     tags.insert("-co-");
1329     tags.insert("-kn-");
1330     tags.insert("-kf-");
1331     tags.insert("-nu-");
1332     tags.insert("-hc-");
1333 
1334     for (auto it = tags.begin(); it != tags.end(); it++) {
1335         extensionMap.erase(*it);
1336         defaultExtensionMap.erase(*it);
1337     }
1338 
1339     for (auto it = defaultExtensionMap.begin(); it != defaultExtensionMap.end(); it++) {
1340         extensionMap.insert(std::pair<std::string, std::string>(it->first, it->second));
1341     }
1342 
1343     for (auto it = extensionMap.begin(); it != extensionMap.end(); it++) {
1344         extension += it->first;
1345         extension += it->second;
1346     }
1347 }
1348 
GetValidLocale(const std::string & localeTag)1349 std::string LocaleConfig::GetValidLocale(const std::string &localeTag)
1350 {
1351     std::string baseLocale = "";
1352     std::string extension = "";
1353     std::size_t found = localeTag.find(STANDARD_EXT_PARAM_KEY);
1354     baseLocale = localeTag.substr(0, found);
1355     if (found != std::string::npos) {
1356         extension = localeTag.substr(found);
1357     }
1358     std::map<std::string, std::string> extensionMap;
1359     if (extension != "") {
1360         parseExtension(extension, extensionMap);
1361     }
1362 
1363     std::string systemLocaleTag = GetEffectiveLocale();
1364     std::string defaultExtension = "";
1365     found = systemLocaleTag.find(STANDARD_EXT_PARAM_KEY);
1366     if (found != std::string::npos) {
1367         defaultExtension = systemLocaleTag.substr(found);
1368     }
1369     std::map<std::string, std::string> defaultExtensionMap;
1370     if (defaultExtension != "") {
1371         parseExtension(defaultExtension, defaultExtensionMap);
1372     }
1373 
1374     std::string ext = "";
1375     setExtension(ext, "-ca-", validCaTag, extensionMap, defaultExtensionMap);
1376     setExtension(ext, "-co-", validCoTag, extensionMap, defaultExtensionMap);
1377     setExtension(ext, "-kn-", validKnTag, extensionMap, defaultExtensionMap);
1378     setExtension(ext, "-kf-", validKfTag, extensionMap, defaultExtensionMap);
1379     setExtension(ext, "-nu-", validNuTag, extensionMap, defaultExtensionMap);
1380     setExtension(ext, "-hc-", validHcTag, extensionMap, defaultExtensionMap);
1381 
1382     std::string otherExt = "";
1383     setOtherExtension(otherExt, extensionMap, defaultExtensionMap);
1384     if (ext != "" || otherExt != "") {
1385         return baseLocale + "-u" + ext + otherExt;
1386     } else {
1387         return baseLocale;
1388     }
1389 }
1390 
IsEmpty24HourClock()1391 bool LocaleConfig::IsEmpty24HourClock()
1392 {
1393     std::string is24Hour = ReadSystemParameter(HOUR_KEY.c_str(), CONFIG_LEN);
1394     if (is24Hour.empty()) {
1395         HILOG_ERROR_I18N("LocaleConfig::IsEmpty24HourClock: Read system is24Hour failed.");
1396         return false;
1397     }
1398     if (is24Hour.compare("default") == 0) {
1399         return true;
1400     }
1401     return false;
1402 }
1403 
Is24HourClock()1404 bool LocaleConfig::Is24HourClock()
1405 {
1406     std::string is24Hour = ReadSystemParameter(HOUR_KEY.c_str(), CONFIG_LEN);
1407     if (is24Hour.empty()) {
1408         HILOG_ERROR_I18N("LocaleConfig::Is24HourClock: Read system is24Hour failed.");
1409         return false;
1410     }
1411     if (is24Hour.compare("default") == 0) {
1412         std::string systemLocale = GetEffectiveLocale();
1413         return Is24HourLocale(systemLocale);
1414     }
1415     if (is24Hour.compare("true") == 0) {
1416         return true;
1417     }
1418     return false;
1419 }
1420 
GetSystemHour()1421 std::string LocaleConfig::GetSystemHour()
1422 {
1423     std::string is24HourVal = ReadSystemParameter(HOUR_KEY.c_str(), CONFIG_LEN);
1424     HILOG_INFO_I18N("GetSystemHour: read from system param:%{public}s.", is24HourVal.c_str());
1425     bool is24Hour = Is24HourClock();
1426     return is24Hour ? "true" : "false";
1427 }
1428 
Is24HourLocale(const std::string & systemLocale)1429 bool LocaleConfig::Is24HourLocale(const std::string& systemLocale)
1430 {
1431     {
1432         std::shared_lock<std::shared_mutex> lock(is24HourLocaleMapMutex);
1433         if (is24HourLocaleMap.find(systemLocale) != is24HourLocaleMap.end()) {
1434             return is24HourLocaleMap[systemLocale];
1435         }
1436     }
1437     std::unique_lock<std::shared_mutex> lock(is24HourLocaleMapMutex);
1438     if (is24HourLocaleMap.find(systemLocale) != is24HourLocaleMap.end()) {
1439         return is24HourLocaleMap[systemLocale];
1440     }
1441     UErrorCode status = U_ZERO_ERROR;
1442     icu::Locale locale = icu::Locale::forLanguageTag(icu::StringPiece(systemLocale), status);
1443     if (U_FAILURE(status)) {
1444         HILOG_ERROR_I18N("Is24HourLocale: %{public}s create locale failed", systemLocale.c_str());
1445         return false;
1446     }
1447 
1448     icu::UnicodeString formatPattern;
1449     icu::DateFormat* dateFormat = icu::DateFormat::createTimeInstance(icu::DateFormat::EStyle::kLong, locale);
1450     if (dateFormat == nullptr) {
1451         HILOG_ERROR_I18N("Is24HourLocale: createTimeInstance failed");
1452         return false;
1453     }
1454     icu::SimpleDateFormat* simDateFormat = static_cast<icu::SimpleDateFormat*>(dateFormat);
1455     if (simDateFormat == nullptr) {
1456         HILOG_ERROR_I18N("Is24HourLocale: failed to convert dateFormat");
1457         return false;
1458     }
1459     simDateFormat->toPattern(formatPattern);
1460     delete dateFormat;
1461     std::string pattern;
1462     formatPattern.toUTF8String(pattern);
1463     bool result = HasDesignator(pattern, 'H');
1464     is24HourLocaleMap[systemLocale] = result;
1465     return result;
1466 }
1467 
HasDesignator(const std::string & pattern,const char designator)1468 bool LocaleConfig::HasDesignator(const std::string& pattern, const char designator)
1469 {
1470     if (pattern.empty()) {
1471         HILOG_ERROR_I18N("HasDesignator: pattern is empty");
1472         return false;
1473     }
1474     bool insideQuote = false;
1475     for (const auto& c : pattern) {
1476         if (c == '\'') {
1477             insideQuote = !insideQuote;
1478         } else if (!insideQuote) {
1479             if (c == designator) {
1480                 return true;
1481             }
1482         }
1483     }
1484     return false;
1485 }
1486 
GetUsingLocalDigit()1487 bool LocaleConfig::GetUsingLocalDigit()
1488 {
1489     std::string locale = GetEffectiveLocale();
1490     LocaleInfo localeInfo(locale);
1491     std::string language = localeInfo.GetLanguage();
1492     if (localDigitMap.find(language) == localDigitMap.end()) {
1493         return false;
1494     }
1495     std::string localNumberSystem = localDigitMap.at(language);
1496     return localNumberSystem.compare(localeInfo.GetNumberingSystem()) == 0;
1497 }
1498 
GetBlockedLanguages()1499 std::unordered_set<std::string> LocaleConfig::GetBlockedLanguages()
1500 {
1501     TabooUtils* tabooUtils = TabooUtils::GetInstance();
1502     if (tabooUtils == nullptr) {
1503         HILOG_ERROR_I18N("LocaleConfig::GetBlockedLanguages: tabooUtils is nullptr.");
1504         return {};
1505     }
1506     return tabooUtils->GetBlockedLanguages();
1507 }
1508 
GetBlockedRegions(const std::string & language)1509 std::unordered_set<std::string> LocaleConfig::GetBlockedRegions(const std::string& language)
1510 {
1511     TabooUtils* tabooUtils = TabooUtils::GetInstance();
1512     if (tabooUtils == nullptr) {
1513         HILOG_ERROR_I18N("LocaleConfig::GetBlockedRegions: tabooUtils is nullptr.");
1514         return {};
1515     }
1516     return tabooUtils->GetBlockedRegions(language);
1517 }
1518 
SetSystemLanguage(const std::string & languageTag,int32_t userId)1519 I18nErrorCode LocaleConfig::SetSystemLanguage(const std::string &languageTag, int32_t userId)
1520 {
1521     if (!IsValidTag(languageTag)) {
1522         HILOG_ERROR_I18N("LocaleConfig::SetSystemLanguage %{public}s is not valid language tag.",
1523             languageTag.c_str());
1524         return I18nErrorCode::INVALID_LANGUAGE_TAG;
1525     }
1526     std::string languageCode = LocaleEncode(languageTag);
1527     HILOG_INFO_I18N("LocaleConfig::SetSystemLanguage: set language %{public}s.", languageCode.c_str());
1528     // save old language, reset system language to old language if update locale failed.
1529     std::string oldLanguageTag = GetSystemLanguage();
1530     if (SetParameter(LANGUAGE_KEY.c_str(), languageTag.data()) != 0) {
1531         HILOG_ERROR_I18N("LocaleConfig::SetSystemLanguage update system language failed.");
1532         return I18nErrorCode::UPDATE_SYSTEM_LANGUAGE_FAILED;
1533     }
1534     std::string newLocaleTag = UpdateLanguageOfLocale(languageTag);
1535     if (SetSystemLocale(newLocaleTag, userId) == I18nErrorCode::SUCCESS) {
1536 #ifdef SUPPORT_MULTI_USER
1537         std::string localId = (userId != -1) ? std::to_string(userId) : "";
1538         MultiUsers::SaveLanguage(localId, languageTag);
1539 #endif
1540         return I18nErrorCode::SUCCESS;
1541     }
1542     // reset system language to old language in case that system language is inconsist with system locale's lanuage.
1543     HILOG_ERROR_I18N("LocaleConfig::SetSystemLanguage update system locale failed.");
1544     SetParameter(LANGUAGE_KEY.c_str(), oldLanguageTag.data());
1545     return I18nErrorCode::UPDATE_SYSTEM_LANGUAGE_FAILED;
1546 }
1547 
SetSystemRegion(const std::string & regionTag,int32_t userId)1548 I18nErrorCode LocaleConfig::SetSystemRegion(const std::string &regionTag, int32_t userId)
1549 {
1550     QueryUpgradeLocale();
1551     if (!IsValidRegion(regionTag)) {
1552         HILOG_ERROR_I18N("LocaleConfig::SetSystemRegion %{public}s is not valid region tag.", regionTag.c_str());
1553         return I18nErrorCode::INVALID_REGION_TAG;
1554     }
1555     std::string regionCode = LocaleEncode(regionTag);
1556     HILOG_INFO_I18N("LocaleConfig::SetSystemRegion: set region %{public}s.", regionCode.c_str());
1557     return SetSystemLocale(UpdateRegionOfLocale(regionTag), userId);
1558 }
1559 
QueryUpgradeLocale()1560 void LocaleConfig::QueryUpgradeLocale()
1561 {
1562     std::string upgradeLocale = ReadSystemParameter(UPGRADE_LOCALE_KEY, CONFIG_LEN);
1563     if (!upgradeLocale.empty()) {
1564         HILOG_INFO_I18N("LocaleConfig::QueryUpgradeLocale: upgrade locale is %{public}s.", upgradeLocale.c_str());
1565     }
1566 }
1567 
ComputeEffectiveLanguage(const std::string & localeTag,const std::string & language)1568 std::string LocaleConfig::ComputeEffectiveLanguage(const std::string& localeTag, const std::string& language)
1569 {
1570     if (localeTag.empty()) {
1571         HILOG_ERROR_I18N("LocaleConfig::ComputeEffectiveLanguage: locale is empty.");
1572         return localeTag;
1573     }
1574     std::string locale = localeTag;
1575     std::vector<std::pair<size_t, std::string>> positions = GetExtParamPositions(localeTag);
1576     if (positions[0].first != std::string::npos) {
1577         locale = localeTag.substr(0, positions[0].first);
1578     }
1579     size_t prefixLength = 2;
1580     if (locale.compare(0, prefixLength, "es") != 0 && locale.compare(0, prefixLength, "pt") != 0) {
1581         return locale;
1582     }
1583     std::shared_ptr<LocaleInfo> esESLocale = std::make_shared<LocaleInfo>("es-ES");
1584     std::shared_ptr<LocaleInfo> esUSLocale = std::make_shared<LocaleInfo>("es-US");
1585     std::shared_ptr<LocaleInfo> ptPTLocale = std::make_shared<LocaleInfo>("pt-PT");
1586     std::shared_ptr<LocaleInfo> ptBRLocale = std::make_shared<LocaleInfo>("pt-BR");
1587     std::vector<LocaleInfo*> candidateLocales {
1588         esESLocale.get(),
1589         esUSLocale.get(),
1590         ptPTLocale.get(),
1591         ptBRLocale.get()
1592     };
1593     std::shared_ptr<LocaleInfo> requestLocale = std::make_shared<LocaleInfo>(locale);
1594     std::string bestMatchedLocale = LocaleMatcher::GetBestMatchedLocale(requestLocale.get(), candidateLocales);
1595     if (bestMatchedLocale.empty()) {
1596         HILOG_ERROR_I18N("LocaleConfig::ComputeEffectiveLanguage: Get best matched locale failed.");
1597         return locale;
1598     }
1599     if (language.empty()) {
1600         HILOG_ERROR_I18N("LocaleConfig::ComputeEffectiveLanguage: language is empty.");
1601         return locale;
1602     }
1603     std::string systemLanguage = language;
1604     if (language.compare("es") == 0) {
1605         systemLanguage = "es-ES";
1606     }
1607     if (bestMatchedLocale.compare(systemLanguage) == 0) {
1608         return locale;
1609     }
1610     return systemLanguage;
1611 }
1612 
SetSystemLocale(const std::string & localeTag,int32_t userId)1613 I18nErrorCode LocaleConfig::SetSystemLocale(const std::string &localeTag, int32_t userId)
1614 {
1615     if (!IsValidTag(localeTag)) {
1616         HILOG_ERROR_I18N("LocaleConfig::SetSystemLocale %{public}s is not a valid locale tag.", localeTag.c_str());
1617         return I18nErrorCode::INVALID_LOCALE_TAG;
1618     }
1619     std::string localeCode = LocaleEncode(localeTag);
1620     HILOG_INFO_I18N("LocaleConfig::SetSystemLocale: set locale %{public}s.", localeCode.c_str());
1621     if (SetParameter(LOCALE_KEY.c_str(), localeTag.data()) != 0) {
1622         return I18nErrorCode::UPDATE_SYSTEM_LOCALE_FAILED;
1623     }
1624     std::string systemLanguage = GetSystemLanguage();
1625     std::string effectiveLanguage = ComputeEffectiveLanguage(localeTag, systemLanguage);
1626 #ifdef SUPPORT_MULTI_USER
1627     std::string localId = (userId != -1) ? std::to_string(userId) : "";
1628     MultiUsers::SaveLocale(localId, localeTag);
1629 #endif
1630 #ifdef SUPPORT_GRAPHICS
1631     UpdateConfigurationLocaleAndLanguage(localeTag, effectiveLanguage, userId);
1632     return PublishCommonEvent(EventFwk::CommonEventSupport::COMMON_EVENT_LOCALE_CHANGED, userId);
1633 #else
1634     return I18nErrorCode::SUCCESS;
1635 #endif
1636 }
1637 
IsValid24HourClockValue(const std::string & tag)1638 bool LocaleConfig::IsValid24HourClockValue(const std::string &tag)
1639 {
1640     if (tag.compare("true") == 0 || tag.compare("false") == 0 || tag.compare("default") == 0) {
1641         return true;
1642     }
1643     HILOG_ERROR_I18N("IsValid24HourClockValue invalid 24 Hour clock tag: %{public}s", tag.c_str());
1644     return false;
1645 }
1646 
Set24HourClock(const std::string & option,int32_t userId)1647 I18nErrorCode LocaleConfig::Set24HourClock(const std::string &option, int32_t userId)
1648 {
1649     if (!IsValid24HourClockValue(option)) {
1650         HILOG_ERROR_I18N("LocaleConfig::Set24HourClock invalid 24 Hour clock tag: %{public}s", option.c_str());
1651         return I18nErrorCode::INVALID_24_HOUR_CLOCK_TAG;
1652     }
1653     HILOG_INFO_I18N("LocaleConfig::Set24HourClock: update 24 hour clock %{public}s", option.c_str());
1654     if (SetParameter(HOUR_KEY.c_str(), option.data()) != 0) {
1655         HILOG_ERROR_I18N("LocaleConfig::Set24HourClock update 24 hour clock failed with option=%{public}s",
1656             option.c_str());
1657         return I18nErrorCode::UPDATE_24_HOUR_CLOCK_FAILED;
1658     }
1659 #ifdef SUPPORT_MULTI_USER
1660     std::string localId;
1661     if (userId != -1) {
1662         localId = std::to_string(userId);
1663     }
1664     MultiUsers::SaveIs24Hour(localId, option);
1665 #endif
1666 #ifdef SUPPORT_GRAPHICS
1667     UpdateConfiguration24Hour(option, userId);
1668     return PublishCommonEvent(EventFwk::CommonEventSupport::COMMON_EVENT_TIME_CHANGED, userId);
1669 #else
1670     return I18nErrorCode::SUCCESS;
1671 #endif
1672 }
1673 
SetUsingLocalDigit(bool flag,int32_t userId)1674 I18nErrorCode LocaleConfig::SetUsingLocalDigit(bool flag, int32_t userId)
1675 {
1676     // check whether current language support local digit.
1677     std::string localeTag = GetEffectiveLocale();
1678     std::string languageTag = localeTag.substr(0, 2); // obtain 2 length language code.
1679     auto it = localDigitMap.find(languageTag);
1680     if (it == localDigitMap.end()) {
1681         HILOG_ERROR_I18N("LocaleConfig::SetUsingLocalDigit current system doesn't support set local digit");
1682         return I18nErrorCode::UPDATE_LOCAL_DIGIT_FAILED;
1683     }
1684     std::string localDigit = flag ? it->second : "";
1685     // update system locale.
1686     return SetSystemLocale(ModifyExtParam(localeTag, NUMBER_SYSTEM_KEY, localDigit, STANDARD_EXT_PARAM_KEY), userId);
1687 }
1688 
SetTemperatureType(const TemperatureType & type,int32_t userId)1689 I18nErrorCode LocaleConfig::SetTemperatureType(const TemperatureType& type, int32_t userId)
1690 {
1691     if (TEMPERATURE_TYPE_TO_NAME.find(type) == TEMPERATURE_TYPE_TO_NAME.end()) {
1692         HILOG_ERROR_I18N("LocaleConfig::SetTemperatureType: temperature type failed.");
1693         return I18nErrorCode::INVALID_TEMPERATURE_TYPE;
1694     }
1695     std::string option = TEMPERATURE_TYPE_TO_NAME[type];
1696     std::string systemLocale = MultiUsers::GetSystemLocaleFromUserId(userId);
1697     // update system locale.
1698     return SetSystemLocale(ModifyExtParam(systemLocale, TEMPERATURE_UNIT_KEY, option, STANDARD_EXT_PARAM_KEY), userId);
1699 }
1700 
GetTemperatureType()1701 TemperatureType LocaleConfig::GetTemperatureType()
1702 {
1703     std::string localeTag = GetEffectiveLocale();
1704     return LocaleConfig::GetTemperatureTypeFromLocale(localeTag);
1705 }
1706 
GetTemperatureTypeFromLocale(const std::string & localeTag)1707 TemperatureType LocaleConfig::GetTemperatureTypeFromLocale(const std::string& localeTag)
1708 {
1709     if (localeTag.empty()) {
1710         return TemperatureType::CELSIUS;
1711     }
1712     std::unordered_map<std::string, std::unordered_map<std::string, std::string>> extParamMap =
1713         ParseAllExtParam(localeTag);
1714     std::unordered_map<std::string, std::string> stardardExtParamMap = extParamMap[STANDARD_EXT_PARAM_KEY];
1715     std::string type;
1716     if (stardardExtParamMap.find(TEMPERATURE_UNIT_KEY) != stardardExtParamMap.end()) {
1717         type = stardardExtParamMap[TEMPERATURE_UNIT_KEY];
1718     }
1719     if (!type.empty() && NAME_TO_TEMPERATURE_TYPE.find(type) != NAME_TO_TEMPERATURE_TYPE.end()) {
1720         return NAME_TO_TEMPERATURE_TYPE[type];
1721     }
1722     std::string regionTag = GetSystemRegion();
1723     if (FAHRENHEIT_USING_REGIONS.find(regionTag) != FAHRENHEIT_USING_REGIONS.end()) {
1724         return TemperatureType::FAHRENHEIT;
1725     }
1726     return TemperatureType::CELSIUS;
1727 }
1728 
GetTemperatureName(const TemperatureType & type)1729 std::string LocaleConfig::GetTemperatureName(const TemperatureType& type)
1730 {
1731     if (TEMPERATURE_TYPE_TO_NAME.find(type) == TEMPERATURE_TYPE_TO_NAME.end()) {
1732         HILOG_ERROR_I18N("LocaleConfig::GetTemperatureName: temperature type failed.");
1733         return "";
1734     }
1735     if (type == TemperatureType::FAHRENHEIT) {
1736         return "fahrenheit";
1737     }
1738     return TEMPERATURE_TYPE_TO_NAME[type];
1739 }
1740 
SetFirstDayOfWeek(const WeekDay & type,int32_t userId)1741 I18nErrorCode LocaleConfig::SetFirstDayOfWeek(const WeekDay& type, int32_t userId)
1742 {
1743     if (WEEK_DAY_TO_NAME.find(type) == WEEK_DAY_TO_NAME.end()) {
1744         HILOG_ERROR_I18N("LocaleConfig::SetFirstDayOfWeek: week day failed.");
1745         return I18nErrorCode::INVALID_WEEK_DAY;
1746     }
1747     std::string option = WEEK_DAY_TO_NAME[type];
1748     std::string systemLocale = MultiUsers::GetSystemLocaleFromUserId(userId);
1749     // update system locale.
1750     return SetSystemLocale(ModifyExtParam(systemLocale, WEEK_DAY_KEY, option, STANDARD_EXT_PARAM_KEY), userId);
1751 }
1752 
GetFirstDayOfWeek()1753 WeekDay LocaleConfig::GetFirstDayOfWeek()
1754 {
1755     std::string localeTag = GetEffectiveLocale();
1756     if (localeTag.empty()) {
1757         HILOG_ERROR_I18N("LocaleConfig::GetFirstDayOfWeek: get system locale failed.");
1758         return WeekDay::MON;
1759     }
1760     std::unordered_map<std::string, std::unordered_map<std::string, std::string>> extParamMap =
1761         ParseAllExtParam(localeTag);
1762     std::unordered_map<std::string, std::string> stardardExtParamMap = extParamMap[STANDARD_EXT_PARAM_KEY];
1763     std::string type;
1764     if (stardardExtParamMap.find(WEEK_DAY_KEY) != stardardExtParamMap.end()) {
1765         type = stardardExtParamMap[WEEK_DAY_KEY];
1766     }
1767     if (!type.empty() && NAME_TO_WEEK_DAY.find(type) != NAME_TO_WEEK_DAY.end()) {
1768         return NAME_TO_WEEK_DAY[type];
1769     }
1770     UErrorCode status = U_ZERO_ERROR;
1771     icu::Locale tempLocale = icu::Locale::forLanguageTag(localeTag, status);
1772     if (U_FAILURE(status)) {
1773         HILOG_ERROR_I18N("LocaleConfig::GetFirstDayOfWeek: create icu::Locale failed.");
1774         return WeekDay::MON;
1775     }
1776     icu::Calendar* calendar = icu::Calendar::createInstance(tempLocale, status);
1777     if (U_FAILURE(status)) {
1778         HILOG_ERROR_I18N("LocaleConfig::GetFirstDayOfWeek: create icu::Calendar failed.");
1779         return WeekDay::MON;
1780     }
1781     icu::Calendar::EDaysOfWeek firstDay = calendar->getFirstDayOfWeek();
1782     delete calendar;
1783     return LocaleConfigExt::GetDaysOfWeekMap()[firstDay];
1784 }
1785 
GetDaysOfWeekMap()1786 std::unordered_map<icu::Calendar::EDaysOfWeek, WeekDay> LocaleConfigExt::GetDaysOfWeekMap()
1787 {
1788     return eDaysOfWeekToWeekDay;
1789 }
1790 
GetSystemCollations(std::unordered_map<std::string,std::string> & systemCollations)1791 I18nErrorCode LocaleConfig::GetSystemCollations(std::unordered_map<std::string, std::string>& systemCollations)
1792 {
1793     systemCollations.clear();
1794     std::string systemLanguage = LocaleConfig::GetSystemLanguage();
1795     auto it = LANGUAGE_TO_COLLATION_VALUES.find(systemLanguage);
1796     if (it == LANGUAGE_TO_COLLATION_VALUES.end()) {
1797         return I18nErrorCode::SUCCESS;
1798     }
1799     std::string effectiveLanguage = LocaleConfig::GetEffectiveLanguage();
1800     UErrorCode status = U_ZERO_ERROR;
1801     icu::Locale locale = icu::Locale::forLanguageTag(icu::StringPiece(effectiveLanguage), status);
1802     if (U_FAILURE(status)) {
1803         HILOG_ERROR_I18N("LocaleConfig::GetSystemCollations: Create icu::Locale failed.");
1804         return I18nErrorCode::FAILED;
1805     }
1806     icu::LocaleDisplayNames* localeDisplayNames = icu::LocaleDisplayNames::createInstance(locale);
1807     if (localeDisplayNames == nullptr) {
1808         HILOG_ERROR_I18N("LocaleConfig::GetSystemCollations: Create icu::LocaleDisplayNames failed.");
1809         return I18nErrorCode::FAILED;
1810     }
1811 
1812     std::unordered_set<std::string> collationValues = it->second;
1813     std::string collationKey = LANGUAGE_TO_COLLATION_KEY.at(systemLanguage);
1814     for (const auto& collationValue : collationValues) {
1815         icu::UnicodeString displayName;
1816         localeDisplayNames->keyValueDisplayName(collationKey.c_str(), collationValue.c_str(), displayName);
1817         std::string value;
1818         displayName.toUTF8String(value);
1819         systemCollations.insert(std::make_pair(collationValue, value));
1820     }
1821     delete localeDisplayNames;
1822     return I18nErrorCode::SUCCESS;
1823 }
1824 
GetUsingCollation(std::string & usingCollation)1825 I18nErrorCode LocaleConfig::GetUsingCollation(std::string& usingCollation)
1826 {
1827     usingCollation.clear();
1828     std::string systemLanguage = LocaleConfig::GetSystemLanguage();
1829     auto it = LANGUAGE_TO_COLLATION_VALUES.find(systemLanguage);
1830     if (it == LANGUAGE_TO_COLLATION_VALUES.end()) {
1831         return I18nErrorCode::SUCCESS;
1832     }
1833     std::string effectiveLocale = LocaleConfig::GetEffectiveLocale();
1834     std::string key = LANGUAGE_TO_EXT_PARAM_KEY.at(systemLanguage);
1835     std::string value = LocaleConfig::QueryExtParam(effectiveLocale, key, STANDARD_EXT_PARAM_KEY);
1836     if (value.empty()) {
1837         usingCollation = LANGUAGE_TO_DEFAULT_COLLATION_VALUE.at(systemLanguage);
1838         return I18nErrorCode::SUCCESS;
1839     }
1840     std::unordered_set<std::string> collationValues = it->second;
1841     if (collationValues.find(value) == collationValues.end()) {
1842         HILOG_ERROR_I18N("LocaleConfig::GetUsingCollation: ExtParam value is invalid, key is %{public}s, "
1843             "value is %{public}s.", key.c_str(), value.c_str());
1844         return I18nErrorCode::FAILED;
1845     }
1846     usingCollation = value;
1847     return I18nErrorCode::SUCCESS;
1848 }
1849 
SetSystemCollation(const std::string & identifier,int32_t userId)1850 I18nErrorCode LocaleConfig::SetSystemCollation(const std::string& identifier, int32_t userId)
1851 {
1852     std::string systemLanguage = MultiUsers::GetSystemLanguageFromUserId(userId);
1853     auto it = LANGUAGE_TO_COLLATION_VALUES.find(systemLanguage);
1854     if (it == LANGUAGE_TO_COLLATION_VALUES.end()) {
1855         HILOG_ERROR_I18N("LocaleConfig::SetSystemCollation: Invalid language.");
1856         return I18nErrorCode::INVALID_PARAM;
1857     }
1858 
1859     std::unordered_set<std::string> collationValues = it->second;
1860     if (collationValues.find(identifier) == collationValues.end()) {
1861         HILOG_ERROR_I18N("LocaleConfig::SetSystemCollation: Invalid identifier %{public}s.",
1862             identifier.c_str());
1863         return I18nErrorCode::INVALID_PARAM;
1864     }
1865 
1866     std::string systemLocale = MultiUsers::GetSystemLocaleFromUserId(userId);
1867     std::string key = LANGUAGE_TO_EXT_PARAM_KEY.at(systemLanguage);
1868     return SetSystemLocale(ModifyExtParam(systemLocale, key, identifier, STANDARD_EXT_PARAM_KEY), userId);
1869 }
1870 
GetSystemNumberingSystems(std::unordered_map<std::string,std::string> & systemNumberingSystems)1871 I18nErrorCode LocaleConfig::GetSystemNumberingSystems(
1872     std::unordered_map<std::string, std::string>& systemNumberingSystems)
1873 {
1874     std::string systemLanguage = LocaleConfig::GetSystemLanguage();
1875     return GetSystemNumberingSystemsFromLanguage(systemLanguage, systemNumberingSystems);
1876 }
1877 
GetSystemNumberingSystemsFromLanguage(const std::string & language,std::unordered_map<std::string,std::string> & systemNumberingSystems)1878 I18nErrorCode LocaleConfig::GetSystemNumberingSystemsFromLanguage(const std::string& language,
1879     std::unordered_map<std::string, std::string>& systemNumberingSystems)
1880 {
1881     systemNumberingSystems.clear();
1882     auto iter = LANGUAGE_TO_NUMBERING_SYSTEM.find(language);
1883     if (iter == LANGUAGE_TO_NUMBERING_SYSTEM.end()) {
1884         return I18nErrorCode::SUCCESS;
1885     }
1886     std::string numberingSystemName = iter->second;
1887     std::string numberingSystemDescription = NUMBERING_SYSTEM_NAME_TO_DESCRIPTION.at(numberingSystemName);
1888     systemNumberingSystems.insert(std::make_pair(numberingSystemName, numberingSystemDescription));
1889     systemNumberingSystems.insert(std::make_pair(DEFAULT_NUMBERING_SYSTEM_NAME,
1890         NUMBERING_SYSTEM_NAME_TO_DESCRIPTION.at(DEFAULT_NUMBERING_SYSTEM_NAME)));
1891     return I18nErrorCode::SUCCESS;
1892 }
1893 
GetUsingNumberingSystem(std::string & usingNumberingSystem)1894 I18nErrorCode LocaleConfig::GetUsingNumberingSystem(std::string& usingNumberingSystem)
1895 {
1896     usingNumberingSystem.clear();
1897     std::unordered_map<std::string, std::string> systemNumberingSystems;
1898     I18nErrorCode errCode = LocaleConfig::GetSystemNumberingSystems(systemNumberingSystems);
1899     if (errCode == I18nErrorCode::FAILED) {
1900         HILOG_ERROR_I18N("LocaleConfig::GetUsingNumberingSystem: Get system numbering systems failed.");
1901         usingNumberingSystem = DEFAULT_NUMBERING_SYSTEM_NAME;
1902         return I18nErrorCode::FAILED;
1903     }
1904     if (systemNumberingSystems.size() == 0) {
1905         return I18nErrorCode::SUCCESS;
1906     }
1907 
1908     std::string effectiveLocale = LocaleConfig::GetEffectiveLocale();
1909     UErrorCode status = U_ZERO_ERROR;
1910     icu::NumberingSystem* numberingSystem = icu::NumberingSystem::createInstance(effectiveLocale.c_str(), status);
1911     if (U_FAILURE(status) || numberingSystem == nullptr) {
1912         HILOG_ERROR_I18N("LocaleConfig::GetUsingNumberingSystem: Create icu::NumberingSystem failed.");
1913         usingNumberingSystem = DEFAULT_NUMBERING_SYSTEM_NAME;
1914         return I18nErrorCode::FAILED;
1915     }
1916     usingNumberingSystem = numberingSystem->getName();
1917     delete numberingSystem;
1918     if (usingNumberingSystem.empty() ||
1919         systemNumberingSystems.find(usingNumberingSystem) == systemNumberingSystems.end()) {
1920         usingNumberingSystem = DEFAULT_NUMBERING_SYSTEM_NAME;
1921         HILOG_ERROR_I18N("LocaleConfig::GetUsingNumberingSystem: Get name failed.");
1922         return I18nErrorCode::FAILED;
1923     }
1924     return I18nErrorCode::SUCCESS;
1925 }
1926 
SetSystemNumberingSystem(const std::string & identifier,int32_t userId)1927 I18nErrorCode LocaleConfig::SetSystemNumberingSystem(const std::string& identifier, int32_t userId)
1928 {
1929     std::string language = MultiUsers::GetSystemLanguageFromUserId(userId);
1930     std::unordered_map<std::string, std::string> systemNumberingSystems;
1931     I18nErrorCode errCode = GetSystemNumberingSystemsFromLanguage(language, systemNumberingSystems);
1932     if (errCode != I18nErrorCode::SUCCESS) {
1933         HILOG_ERROR_I18N("LocaleConfig::SetSystemNumberingSystem: Get system numbering systems failed.");
1934         return I18nErrorCode::FAILED;
1935     }
1936     if (systemNumberingSystems.find(identifier) == systemNumberingSystems.end()) {
1937         HILOG_ERROR_I18N("LocaleConfig::SetSystemNumberingSystem: ExtParam value is invalid, "
1938             "value is %{public}s.", identifier.c_str());
1939         return I18nErrorCode::INVALID_PARAM;
1940     }
1941 
1942     std::string localeTag = MultiUsers::GetSystemLocaleFromUserId(userId);
1943     return SetSystemLocale(ModifyExtParam(localeTag, NUMBER_SYSTEM_KEY, identifier, STANDARD_EXT_PARAM_KEY), userId);
1944 }
1945 
GetNumberPatternFromLocale(const std::string & localeTag)1946 std::pair<std::string, std::string> LocaleConfig::GetNumberPatternFromLocale(const std::string& localeTag)
1947 {
1948     std::pair<std::string, std::string> numberPattern;
1949     std::string value = LocaleConfig::QueryExtParam(localeTag, NUNBER_PATTERN_KEY, CUST_EXT_PARAM_KEY);
1950     if (!value.empty()) {
1951         numberPattern = HexToNumberPattern(value);
1952         return numberPattern;
1953     }
1954 
1955     UErrorCode status = U_ZERO_ERROR;
1956     icu::Locale locale = icu::Locale::forLanguageTag(localeTag.c_str(), status);
1957     if (U_FAILURE(status)) {
1958         HILOG_ERROR_I18N("LocaleConfig::GetNumberPatternFromLocale: Create icu::Locale failed.");
1959         return numberPattern;
1960     }
1961     icu::DecimalFormatSymbols* decimalFormatSymbols = new icu::DecimalFormatSymbols(locale, status);
1962     if (U_FAILURE(status) || decimalFormatSymbols == nullptr) {
1963         delete decimalFormatSymbols;
1964         HILOG_ERROR_I18N("LocaleConfig::GetNumberPatternFromLocale: Create icu::DecimalFormatSymbols failed.");
1965         return numberPattern;
1966     }
1967     icu::UnicodeString groupingSeparatorSymbol
1968         = decimalFormatSymbols->getSymbol(icu::DecimalFormatSymbols::ENumberFormatSymbol::kGroupingSeparatorSymbol);
1969     icu::UnicodeString decimalSeparatorSymbol
1970         = decimalFormatSymbols->getSymbol(icu::DecimalFormatSymbols::ENumberFormatSymbol::kDecimalSeparatorSymbol);
1971     delete decimalFormatSymbols;
1972     std::string groupingPart;
1973     groupingSeparatorSymbol.toUTF8String(groupingPart);
1974     std::string decimalPart;
1975     decimalSeparatorSymbol.toUTF8String(decimalPart);
1976     numberPattern.first = groupingPart;
1977     numberPattern.second = decimalPart;
1978     return numberPattern;
1979 }
1980 
GetSystemNumberPatterns(std::unordered_map<std::string,std::string> & systemNumberPatterns)1981 I18nErrorCode LocaleConfig::GetSystemNumberPatterns(std::unordered_map<std::string, std::string>& systemNumberPatterns)
1982 {
1983     std::string effectiveLocale = LocaleConfig::GetEffectiveLocale();
1984     return GetSystemNumberPatternsFromLocale(systemNumberPatterns, effectiveLocale);
1985 }
1986 
GetSystemNumberPatternsFromLocale(std::unordered_map<std::string,std::string> & systemNumberPatterns,const std::string & locale)1987 I18nErrorCode LocaleConfig::GetSystemNumberPatternsFromLocale(
1988     std::unordered_map<std::string, std::string>& systemNumberPatterns, const std::string& locale)
1989 {
1990     systemNumberPatterns.clear();
1991     std::string localeWithoutCustParam = LocaleConfig::RemoveCustExtParam(locale);
1992     for (const auto& item : CODE_TO_NUMBER_PATTERN) {
1993         std::string sample = NumberFormat::GetNumberPatternSample(localeWithoutCustParam, item.second);
1994         if (sample.empty()) {
1995             HILOG_ERROR_I18N("LocaleConfig::GetSystemNumberPatternsFromLocale: Get sample failed.");
1996             continue;
1997         }
1998         systemNumberPatterns.insert(std::make_pair(item.first, sample));
1999     }
2000 
2001     std::string localeWithoutExtParam = LocaleConfig::RemoveAllExtParam(locale);
2002     std::pair<std::string, std::string> numberPattern = GetNumberPatternFromLocale(localeWithoutExtParam);
2003     std::string key = NumberPatternToHex(numberPattern.first, numberPattern.second);
2004     if (key.empty()) {
2005         HILOG_ERROR_I18N("LocaleConfig::GetSystemNumberPatternsFromLocale: Get key failed, groupingSymbol is "
2006             "%{public}s, decimalSymbol is %{public}s.", numberPattern.first.c_str(), numberPattern.second.c_str());
2007         return I18nErrorCode::FAILED;
2008     }
2009 
2010     if (systemNumberPatterns.find(key) == systemNumberPatterns.end()) {
2011         std::string sample = NumberFormat::GetNumberPatternSample(localeWithoutCustParam, numberPattern);
2012         if (sample.empty()) {
2013             HILOG_ERROR_I18N("LocaleConfig::GetSystemNumberPatternsFromLocale: Get sample failed.");
2014             return I18nErrorCode::FAILED;
2015         }
2016         systemNumberPatterns.insert(std::make_pair(key, sample));
2017     }
2018     return I18nErrorCode::SUCCESS;
2019 }
2020 
GetUsingNumberPattern(std::string & usingNumberPattern)2021 I18nErrorCode LocaleConfig::GetUsingNumberPattern(std::string& usingNumberPattern)
2022 {
2023     usingNumberPattern.clear();
2024     std::string effectiveLocale = LocaleConfig::GetEffectiveLocale();
2025     std::pair<std::string, std::string> numberPattern = GetNumberPatternFromLocale(effectiveLocale);
2026     std::string numberPatternHex = NumberPatternToHex(numberPattern.first, numberPattern.second);
2027     if (numberPatternHex.empty()) {
2028         HILOG_ERROR_I18N("LocaleConfig::GetUsingNumberPattern: Get numberPattern failed, groupingSymbol is %{public}s,"
2029             " decimalSymbol is %{public}s.", numberPattern.first.c_str(), numberPattern.second.c_str());
2030         return I18nErrorCode::FAILED;
2031     }
2032     usingNumberPattern = numberPatternHex;
2033     return I18nErrorCode::SUCCESS;
2034 }
2035 
SetSystemNumberPattern(const std::string & pattern,int32_t userId)2036 I18nErrorCode LocaleConfig::SetSystemNumberPattern(const std::string& pattern, int32_t userId)
2037 {
2038     std::string systemLocale = MultiUsers::GetSystemLocaleFromUserId(userId);
2039     std::unordered_map<std::string, std::string> systemNumberPatterns;
2040     I18nErrorCode errCode = GetSystemNumberPatternsFromLocale(systemNumberPatterns, systemLocale);
2041     if (errCode != I18nErrorCode::SUCCESS) {
2042         HILOG_ERROR_I18N("LocaleConfig::SetSystemNumberPattern: Get system number patterns failed.");
2043         return I18nErrorCode::FAILED;
2044     }
2045 
2046     if (systemNumberPatterns.find(pattern) == systemNumberPatterns.end()) {
2047         HILOG_ERROR_I18N("LocaleConfig::SetSystemNumberPattern: ExtParam value is invalid, locale is %{public}s, "
2048             "value is %{public}s.", systemLocale.c_str(), pattern.c_str());
2049         return I18nErrorCode::INVALID_PARAM;
2050     }
2051 
2052     return SetSystemLocale(ModifyExtParam(systemLocale, NUNBER_PATTERN_KEY, pattern, CUST_EXT_PARAM_KEY), userId);
2053 }
2054 
GetSystemMeasurements(std::unordered_map<std::string,std::string> & systemMeasurements)2055 I18nErrorCode LocaleConfig::GetSystemMeasurements(std::unordered_map<std::string, std::string>& systemMeasurements)
2056 {
2057     systemMeasurements.clear();
2058     std::string language = LocaleConfig::GetEffectiveLanguage();
2059     UErrorCode status = U_ZERO_ERROR;
2060     icu::Locale locale = icu::Locale::forLanguageTag(icu::StringPiece(language), status);
2061     if (U_FAILURE(status)) {
2062         HILOG_ERROR_I18N("LocaleConfig::GetSystemMeasurements: Create icu::Locale failed, language is %{public}s.",
2063             language.c_str());
2064         return I18nErrorCode::FAILED;
2065     }
2066     icu::LocaleDisplayNames* localeDisplayNames = icu::LocaleDisplayNames::createInstance(locale);
2067     if (localeDisplayNames == nullptr) {
2068         HILOG_ERROR_I18N("LocaleConfig::GetSystemMeasurements: Create icu::LocaleDisplayNames failed, language "
2069             "is %{public}s.", language.c_str());
2070         return I18nErrorCode::FAILED;
2071     }
2072     for (const auto& measurement : UMEASUREMENT_SYSTEM_TO_VALUE) {
2073         icu::UnicodeString displayName;
2074         localeDisplayNames->keyValueDisplayName(MEASUREMENT_KEY.c_str(), measurement.second.c_str(), displayName);
2075         std::string value;
2076         displayName.toUTF8String(value);
2077         systemMeasurements.insert(std::make_pair(measurement.second, value));
2078     }
2079     delete localeDisplayNames;
2080     return I18nErrorCode::SUCCESS;
2081 }
2082 
GetUsingMeasurement(std::string & identifier)2083 I18nErrorCode LocaleConfig::GetUsingMeasurement(std::string& identifier)
2084 {
2085     identifier.clear();
2086     std::string locale = LocaleConfig::GetEffectiveLocale();
2087     identifier = LocaleConfig::GetMeasurementFromLocale(locale);
2088     if (identifier.empty()) {
2089         HILOG_ERROR_I18N("LocaleConfig::GetUsingMeasurement: Get using measurement failed.");
2090         return I18nErrorCode::FAILED;
2091     }
2092     return I18nErrorCode::SUCCESS;
2093 }
2094 
GetMeasurementFromLocale(const std::string & localeTag)2095 std::string LocaleConfig::GetMeasurementFromLocale(const std::string& localeTag)
2096 {
2097     std::string extParam = LocaleConfig::QueryExtParam(localeTag, MEASUREMENT_KEY, STANDARD_EXT_PARAM_KEY);
2098     if (!extParam.empty() && LocaleConfig::IsValidMeasurement(extParam)) {
2099         return extParam;
2100     }
2101     UErrorCode status = U_ZERO_ERROR;
2102     std::string locale = LocaleConfig::RemoveAllExtParam(localeTag);
2103     UMeasurementSystem measurementSystem = ulocdata_getMeasurementSystem(locale.c_str(), &status);
2104     if (U_FAILURE(status)) {
2105         HILOG_ERROR_I18N("LocaleConfig::GetMeasurementFromLocale: Get measurementSystem failed");
2106         return "";
2107     }
2108     auto iter = UMEASUREMENT_SYSTEM_TO_VALUE.find(measurementSystem);
2109     if (iter == UMEASUREMENT_SYSTEM_TO_VALUE.end()) {
2110         HILOG_ERROR_I18N("LocaleConfig::GetMeasurementFromLocale: Invalid measurementSystem.");
2111         return "";
2112     }
2113     return iter->second;
2114 }
2115 
SetSystemMeasurement(const std::string & identifier,int32_t userId)2116 I18nErrorCode LocaleConfig::SetSystemMeasurement(const std::string& identifier, int32_t userId)
2117 {
2118     if (!LocaleConfig::IsValidMeasurement(identifier)) {
2119         HILOG_ERROR_I18N("LocaleConfig::SetSystemMeasurement: Invalid identifier %{public}s.", identifier.c_str());
2120         return I18nErrorCode::INVALID_PARAM;
2121     }
2122     std::string systemLocale = MultiUsers::GetSystemLocaleFromUserId(userId);
2123     return SetSystemLocale(ModifyExtParam(systemLocale, MEASUREMENT_KEY, identifier, STANDARD_EXT_PARAM_KEY), userId);
2124 }
2125 
IsValidMeasurement(const std::string & measurement)2126 bool LocaleConfig::IsValidMeasurement(const std::string& measurement)
2127 {
2128     for (const auto& item : UMEASUREMENT_SYSTEM_TO_VALUE) {
2129         if (item.second == measurement) {
2130             return true;
2131         }
2132     }
2133     return false;
2134 }
2135 
GetPatternNumberFromLocale(const std::string & locale)2136 std::string LocaleConfig::GetPatternNumberFromLocale(const std::string& locale)
2137 {
2138     std::string number = LocaleConfig::QueryExtParam(locale, NUMERIC_DATE_KEY, CUST_EXT_PARAM_KEY);
2139     if (DateTimeFormat::IsValidPatternNumber(number)) {
2140         return number;
2141     }
2142     return "";
2143 }
2144 
GetSystemNumericalDatePatterns(std::unordered_map<std::string,std::string> & systemNumericalDatePatterns)2145 I18nErrorCode LocaleConfig::GetSystemNumericalDatePatterns(
2146     std::unordered_map<std::string, std::string>& systemNumericalDatePatterns)
2147 {
2148     systemNumericalDatePatterns.clear();
2149     std::string systemLocale = LocaleConfig::GetSystemLocale();
2150     std::unordered_map<std::string, std::string> supportNumbers =
2151         DateTimeFormat::GetPatternsFromLocale(systemLocale);
2152     std::string effectiveLocale = LocaleConfig::GetEffectiveLocale();
2153     for (const auto& item : supportNumbers) {
2154         icu::UnicodeString pattern = item.first.c_str();
2155         std::string key;
2156         pattern.toUTF8String(key);
2157         std::string value = DateTimeFormat::GetDateSampleFromPattern(pattern, effectiveLocale);
2158         if (value.empty()) {
2159             continue;
2160         }
2161         systemNumericalDatePatterns.insert(std::make_pair(key, value));
2162     }
2163     return I18nErrorCode::SUCCESS;
2164 }
2165 
GetUsingNumericalDatePattern(std::string & identifier)2166 I18nErrorCode LocaleConfig::GetUsingNumericalDatePattern(std::string& identifier)
2167 {
2168     identifier.clear();
2169     std::string effectiveLocale = LocaleConfig::GetEffectiveLocale();
2170     std::string number = LocaleConfig::QueryExtParam(effectiveLocale, NUMERIC_DATE_KEY, CUST_EXT_PARAM_KEY);
2171     if (DateTimeFormat::IsValidPatternNumber(number)) {
2172         icu::UnicodeString pattern = DateTimeFormat::GetYMDPatternFromNumber(number);
2173         pattern.toUTF8String(identifier);
2174         return I18nErrorCode::SUCCESS;
2175     }
2176 
2177     std::vector<std::pair<size_t, std::string>> positions = GetExtParamPositions(effectiveLocale);
2178     std::string localeWithoutExtParam = effectiveLocale;
2179     if (positions[0].first != std::string::npos) {
2180         localeWithoutExtParam = effectiveLocale.substr(0, positions[0].first);
2181     }
2182 
2183     icu::UnicodeString pattern = DateTimeFormat::GetSingleDayPatternFromLocale(localeWithoutExtParam);
2184     pattern.toUTF8String(identifier);
2185     return I18nErrorCode::SUCCESS;
2186 }
2187 
SetSystemNumericalDatePattern(const std::string & identifier,int32_t userId)2188 I18nErrorCode LocaleConfig::SetSystemNumericalDatePattern(const std::string& identifier, int32_t userId)
2189 {
2190     std::string systemLocale = MultiUsers::GetSystemLocaleFromUserId(userId);
2191     std::vector<std::pair<size_t, std::string>> positions = GetExtParamPositions(systemLocale);
2192     std::string localeWithoutExtParam = systemLocale;
2193     if (positions[0].first != std::string::npos) {
2194         localeWithoutExtParam = systemLocale.substr(0, positions[0].first);
2195     }
2196     std::unordered_map<std::string, std::string> supportNumbers =
2197         DateTimeFormat::GetPatternsFromLocale(localeWithoutExtParam);
2198     auto iter = supportNumbers.find(identifier);
2199     if (iter == supportNumbers.end()) {
2200         HILOG_ERROR_I18N("LocaleConfig::SetSystemNumericalDatePattern: identifier %{public}s is invalid",
2201             identifier.c_str());
2202         return I18nErrorCode::INVALID_PARAM;
2203     }
2204     std::string extParam = iter->second;
2205     return SetSystemLocale(ModifyExtParam(systemLocale, NUMERIC_DATE_KEY, extParam, CUST_EXT_PARAM_KEY), userId);
2206 }
2207 
NumberPatternToHex(const std::string & groupingSymbol,const std::string & decimalSymbol)2208 std::string LocaleConfig::NumberPatternToHex(const std::string& groupingSymbol, const std::string& decimalSymbol)
2209 {
2210     std::string hex;
2211     if (groupingSymbol.empty()) {
2212         hex += "0000";
2213     } else {
2214         std::string groupingSymbolHex = StrToHex(groupingSymbol, SYMBOL_HEX_LEN);
2215         if (groupingSymbolHex.length() != SYMBOL_HEX_LEN) {
2216             HILOG_ERROR_I18N("LocaleConfig::NumberPatternToHex: Check groupingSymbolHex failed, "
2217                 "groupingSymbolHex is %{public}s.", groupingSymbolHex.c_str());
2218             return "";
2219         }
2220         hex += groupingSymbolHex;
2221     }
2222     if (decimalSymbol.empty()) {
2223         HILOG_ERROR_I18N("LocaleConfig::NumberPatternToHex: decimalSymbol is empty.");
2224         return "";
2225     }
2226     std::string decimalSymbolHex = StrToHex(decimalSymbol, SYMBOL_HEX_LEN);
2227     if (decimalSymbolHex.length() != SYMBOL_HEX_LEN) {
2228         HILOG_ERROR_I18N("LocaleConfig::NumberPatternToHex: Check decimalSymbolHex failed, "
2229             "decimalSymbolHex is %{public}s.", decimalSymbolHex.c_str());
2230         return "";
2231     }
2232     hex += decimalSymbolHex;
2233     return hex;
2234 }
2235 
HexToNumberPattern(const std::string & hex)2236 std::pair<std::string, std::string> LocaleConfig::HexToNumberPattern(const std::string& hex)
2237 {
2238     std::pair<std::string, std::string> numberPattern;
2239     if (hex.length() != SYMBOL_HEX_LEN * ELEMENT_NUM) {
2240         HILOG_ERROR_I18N("LocaleConfig::HexToNumberPattern: Check hex failed, hex is %{public}s.", hex.c_str());
2241         return numberPattern;
2242     }
2243     std::string groupingSymbolHex = hex.substr(0, SYMBOL_HEX_LEN);
2244     std::string groupingSymbol;
2245     if (groupingSymbolHex.compare("0000") != 0) {
2246         groupingSymbol = HexToStr(groupingSymbolHex);
2247         if (groupingSymbol.empty()) {
2248             HILOG_ERROR_I18N("LocaleConfig::HexToNumberPattern: Get groupingSymbol failed, "
2249                 "groupingSymbolHex is %{public}s.", groupingSymbolHex.c_str());
2250             return numberPattern;
2251         }
2252     }
2253 
2254     std::string decimalSymbolHex = hex.substr(SYMBOL_HEX_LEN);
2255     std::string decimalSymbol = HexToStr(decimalSymbolHex);
2256     if (decimalSymbol.empty()) {
2257         HILOG_ERROR_I18N("LocaleConfig::HexToNumberPattern: Get decimalSymbol failed, "
2258             "decimalSymbolHex is %{public}s.", decimalSymbolHex.c_str());
2259         return numberPattern;
2260     }
2261     numberPattern.first = groupingSymbol;
2262     numberPattern.second = decimalSymbol;
2263     return numberPattern;
2264 }
2265 
2266 #ifdef SUPPORT_GRAPHICS
UpdateConfigurationLocaleAndLanguage(const std::string & locale,const std::string & language,int32_t userId)2267 void LocaleConfig::UpdateConfigurationLocaleAndLanguage(const std::string& locale, const std::string& language,
2268     int32_t userId)
2269 {
2270     if (locale.empty() && language.empty()) {
2271         HILOG_ERROR_I18N("LocaleConfig::UpdateConfigurationLocaleAndLanguage: locale and language are empty.");
2272         return;
2273     }
2274     AppExecFwk::Configuration configuration;
2275     if (!locale.empty()) {
2276         configuration.AddItem(AAFwk::GlobalConfigurationKey::SYSTEM_LOCALE, locale);
2277     }
2278     if (!language.empty()) {
2279         configuration.AddItem(AAFwk::GlobalConfigurationKey::SYSTEM_LANGUAGE, language);
2280     }
2281     auto appMgrClient = std::make_unique<AppExecFwk::AppMgrClient>();
2282     if (appMgrClient == nullptr) {
2283         HILOG_ERROR_I18N("LocaleConfig::UpdateConfigurationLocaleAndLanguage: Get appMgrClient failed.");
2284         return;
2285     }
2286 
2287     AppExecFwk::AppMgrResultCode status = appMgrClient->UpdateConfiguration(configuration, userId);
2288     if (status != AppExecFwk::AppMgrResultCode::RESULT_OK) {
2289         HILOG_ERROR_I18N("LocaleConfig::UpdateConfigurationLocaleAndLanguage: Update configuration "
2290             "userId %{public}d failed.", userId);
2291         return;
2292     }
2293     HILOG_INFO_I18N("LocaleConfig::UpdateConfigurationLocaleAndLanguage: update userId %{public}d, locale %{public}s, "
2294         "language %{public}s.", userId, locale.c_str(), language.c_str());
2295 }
2296 
UpdateConfiguration24Hour(const std::string & is24Hour,int32_t userId)2297 void LocaleConfig::UpdateConfiguration24Hour(const std::string& is24Hour, int32_t userId)
2298 {
2299     AppExecFwk::Configuration configuration;
2300     configuration.AddItem(AAFwk::GlobalConfigurationKey::SYSTEM_HOUR, is24Hour);
2301     auto appMgrClient = std::make_unique<AppExecFwk::AppMgrClient>();
2302     if (appMgrClient == nullptr) {
2303         HILOG_ERROR_I18N("LocaleConfig::UpdateConfiguration24Hour: Get appMgrClient failed.");
2304         return;
2305     }
2306     AppExecFwk::AppMgrResultCode status = appMgrClient->UpdateConfiguration(configuration, userId);
2307     if (status != AppExecFwk::AppMgrResultCode::RESULT_OK) {
2308         HILOG_ERROR_I18N("LocaleConfig::UpdateConfiguration24Hour: Update configuration userId %{public}d failed.",
2309             userId);
2310         return;
2311     }
2312     HILOG_INFO_I18N("LocaleConfig::UpdateConfiguration24Hour: update userId %{public}d, is24Hour %{public}s.",
2313         userId, is24Hour.c_str());
2314 }
2315 
PublishCommonEvent(const std::string & eventType,int32_t userId)2316 I18nErrorCode LocaleConfig::PublishCommonEvent(const std::string &eventType, int32_t userId)
2317 {
2318     OHOS::AAFwk::Want localeChangeWant;
2319     localeChangeWant.SetAction(eventType);
2320     OHOS::EventFwk::CommonEventData event(localeChangeWant);
2321     if (EventFwk::CommonEventSupport::COMMON_EVENT_TIME_CHANGED.compare(eventType) == 0) {
2322         event.SetData(HOUR_EVENT_DATA);
2323     }
2324     if (userId == -1) {
2325         if (!OHOS::EventFwk::CommonEventManager::PublishCommonEvent(event)) {
2326             HILOG_ERROR_I18N("LocaleConfig::PublishCommonEvent Failed to Publish event %{public}s",
2327                 localeChangeWant.GetAction().c_str());
2328             return I18nErrorCode::PUBLISH_COMMON_EVENT_FAILED;
2329         }
2330         HILOG_INFO_I18N("LocaleConfig::PublishCommonEvent publish event finished.");
2331         return I18nErrorCode::SUCCESS;
2332     }
2333 
2334     if (!OHOS::EventFwk::CommonEventManager::PublishCommonEventAsUser(event, userId)) {
2335         HILOG_ERROR_I18N("LocaleConfig::PublishCommonEvent Failed to Publish event %{public}s, userId %{public}d.",
2336             localeChangeWant.GetAction().c_str(), userId);
2337         return I18nErrorCode::PUBLISH_COMMON_EVENT_FAILED;
2338     }
2339     HILOG_INFO_I18N("LocaleConfig::PublishCommonEvent publish event finished,  userId %{public}d.", userId);
2340     return I18nErrorCode::SUCCESS;
2341 }
2342 #endif
2343 
UpdateLanguageOfLocale(const std::string & languageTag)2344 std::string LocaleConfig::UpdateLanguageOfLocale(const std::string &languageTag)
2345 {
2346     // Compute language and script part from languageTag.
2347     UErrorCode status = U_ZERO_ERROR;
2348     icu::Locale languageLocale = icu::Locale::forLanguageTag(languageTag.c_str(), status);
2349     if (U_FAILURE(status)) {
2350         HILOG_ERROR_I18N("LocaleConfig::UpdateLanguageOfLocale init icu Locale for language %{public}s failed.",
2351             languageTag.c_str());
2352         return "";
2353     }
2354     std::string langTag = languageLocale.getLanguage();
2355     std::string scriptTag = languageLocale.getScript();
2356     // Compute region and extend param part from current system locale.
2357     std::string systemLocaleTag = GetEffectiveLocale();
2358     icu::Locale systemLocale = icu::Locale::forLanguageTag(systemLocaleTag.c_str(), status);
2359     if (U_FAILURE(status)) {
2360         HILOG_ERROR_I18N("LocaleConfig::UpdateSystemLocale init icu Locale for locale %{public}s failed.",
2361             systemLocaleTag.c_str());
2362         return systemLocaleTag;
2363     }
2364     std::string regionTag = systemLocale.getCountry();
2365     std::string extendParamTag;
2366     systemLocaleTag = LocaleConfig::ModifyExtParam(systemLocaleTag, CASE_FIRST_KEY, "", STANDARD_EXT_PARAM_KEY);
2367     systemLocaleTag = LocaleConfig::ModifyExtParam(systemLocaleTag, COLLATION_KEY, "", STANDARD_EXT_PARAM_KEY);
2368     systemLocaleTag = LocaleConfig::ModifyExtParam(systemLocaleTag, NUMBER_SYSTEM_KEY, "", STANDARD_EXT_PARAM_KEY);
2369     systemLocaleTag = LocaleConfig::ModifyExtParam(systemLocaleTag, NUMERIC_DATE_KEY, "", CUST_EXT_PARAM_KEY);
2370     systemLocaleTag = LocaleConfig::ModifyExtParam(systemLocaleTag, NUNBER_PATTERN_KEY, "", CUST_EXT_PARAM_KEY);
2371     std::vector<std::pair<size_t, std::string>> positions = GetExtParamPositions(systemLocaleTag);
2372     if (positions[0].first != std::string::npos) {
2373         extendParamTag = systemLocaleTag.substr(positions[0].first);
2374     }
2375     // Combine above elements.
2376     return CreateLocale(langTag, scriptTag, regionTag, extendParamTag);
2377 }
2378 
CreateLocale(const std::string & languageTag,const std::string & scriptTag,const std::string & regionTag,const std::string & extendParamTag)2379 std::string LocaleConfig::CreateLocale(const std::string &languageTag, const std::string &scriptTag,
2380     const std::string &regionTag, const std::string &extendParamTag)
2381 {
2382     // combine language, script, region and extend param with '-'
2383     std::string localeTag = languageTag;
2384     std::string splitor = "-";
2385     if (scriptTag.length() > 0) {
2386         localeTag += splitor + scriptTag;
2387     }
2388     if (regionTag.length() > 0) {
2389         localeTag += splitor + regionTag;
2390     }
2391     if (extendParamTag.length() > 0) {
2392         localeTag += extendParamTag;
2393     }
2394     return localeTag;
2395 }
2396 
UpdateRegionOfLocale(const std::string & regionTag)2397 std::string LocaleConfig::UpdateRegionOfLocale(const std::string &regionTag)
2398 {
2399     std::string localeTag = GetEffectiveLocale();
2400     // if current system locale is null, contruct a locale from region tag.
2401     if (localeTag.empty()) {
2402         return CreateLocaleFromRegion(regionTag);
2403     }
2404     std::string extParam;
2405     std::vector<std::pair<size_t, std::string>> positions = GetExtParamPositions(localeTag);
2406     if (positions[0].first != std::string::npos) {
2407         extParam = localeTag.substr(positions[0].first);
2408     }
2409     // combine locale with origin locale's language and script with regionTag.
2410     UErrorCode status = U_ZERO_ERROR;
2411     const icu::Locale origin = icu::Locale::forLanguageTag(localeTag, status);
2412     if (U_FAILURE(status)) {
2413         HILOG_ERROR_I18N("LocaleConfig::UpdateRegionOfLocale init origin locale failed.");
2414         return localeTag;
2415     }
2416     icu::LocaleBuilder builder = icu::LocaleBuilder().setLanguage(origin.getLanguage()).
2417         setScript(origin.getScript()).setRegion(regionTag);
2418     icu::Locale temp = builder.build(status);
2419     if (U_FAILURE(status)) {
2420         HILOG_ERROR_I18N("LocaleConfig::UpdateRegionOfLocale: build locale failed.");
2421         return localeTag;
2422     }
2423     string ret = temp.toLanguageTag<string>(status);
2424     if (U_FAILURE(status)) {
2425         HILOG_ERROR_I18N("LocaleConfig::UpdateRegionOfLocale obtain new locale's tag failed.");
2426         return localeTag;
2427     }
2428     ret += extParam;
2429     ret = LocaleConfig::ModifyExtParam(ret, NUNBER_PATTERN_KEY, "", CUST_EXT_PARAM_KEY);
2430     ret = LocaleConfig::ModifyExtParam(ret, NUMERIC_DATE_KEY, "", CUST_EXT_PARAM_KEY);
2431     return ret;
2432 }
2433 
CreateLocaleFromRegion(const std::string & regionTag)2434 std::string LocaleConfig::CreateLocaleFromRegion(const std::string &regionTag)
2435 {
2436     // fill locale with icu
2437     icu::Locale locale("", regionTag.c_str());
2438     UErrorCode status = U_ZERO_ERROR;
2439     locale.addLikelySubtags(status);
2440     if (U_FAILURE(status)) {
2441         HILOG_ERROR_I18N("LocaleConfig::CreateLocaleFromRegion init new locale failed.");
2442         return "";
2443     }
2444     std::string localeTag = locale.toLanguageTag<string>(status);
2445     if (U_FAILURE(status)) {
2446         HILOG_ERROR_I18N("LocaleConfig::CreateLocaleFromRegion obtain new locale's tag failed.");
2447         return "";
2448     }
2449     return localeTag;
2450 }
2451 
RemoveCustExtParam(const std::string & locale)2452 std::string LocaleConfig::RemoveCustExtParam(const std::string& locale)
2453 {
2454     std::string tempLocale = ModifyExtParam(locale, NUNBER_PATTERN_KEY, "", CUST_EXT_PARAM_KEY);
2455     return ModifyExtParam(tempLocale, NUMERIC_DATE_KEY, "", CUST_EXT_PARAM_KEY);
2456 }
2457 
RemoveAllExtParam(const std::string & locale)2458 std::string LocaleConfig::RemoveAllExtParam(const std::string& locale)
2459 {
2460     std::vector<std::pair<size_t, std::string>> positions = GetExtParamPositions(locale);
2461     std::string localeWithoutExtParam = locale;
2462     if (positions[0].first != std::string::npos) {
2463         localeWithoutExtParam = locale.substr(0, positions[0].first);
2464     }
2465     return localeWithoutExtParam;
2466 }
2467 
QueryExtParam(const std::string & locale,const std::string & key,const std::string & extParamKey)2468 std::string LocaleConfig::QueryExtParam(const std::string& locale, const std::string& key,
2469     const std::string& extParamKey)
2470 {
2471     if (locale.empty()) {
2472         HILOG_ERROR_I18N("LocaleConfig::QueryExtParam: locale is empty.");
2473         return "";
2474     }
2475     if (key.empty()) {
2476         HILOG_ERROR_I18N("LocaleConfig::QueryExtParam: key is empty.");
2477         return "";
2478     }
2479     std::unordered_map<std::string, std::unordered_map<std::string, std::string>> extParamMap =
2480         ParseAllExtParam(locale);
2481     std::unordered_map<std::string, std::string> paramMap = extParamMap[extParamKey];
2482     auto it = paramMap.find(key);
2483     if (it == paramMap.end()) {
2484         return "";
2485     }
2486     return it->second;
2487 }
2488 
ModifyExtParam(const std::string & locale,const std::string & key,const std::string & value,const std::string & extParamKey)2489 std::string LocaleConfig::ModifyExtParam(const std::string& locale, const std::string& key, const std::string& value,
2490     const std::string& extParamKey)
2491 {
2492     if (locale.empty()) {
2493         HILOG_ERROR_I18N("LocaleConfig::ModifyExtParam: locale is empty.");
2494         return locale;
2495     }
2496     if (key.empty()) {
2497         HILOG_ERROR_I18N("LocaleConfig::ModifyExtParam: key is empty.");
2498         return locale;
2499     }
2500     std::unordered_map<std::string, std::string> paramMap;
2501     std::string localeBase = locale;
2502     std::vector<std::pair<size_t, std::string>> positions = GetExtParamPositions(locale);
2503     if (positions[0].first != std::string::npos) {
2504         localeBase = locale.substr(0, positions[0].first);
2505     }
2506     std::unordered_map<std::string, std::unordered_map<std::string, std::string>> extParamMap =
2507         ParseAllExtParam(locale);
2508     extParamMap[extParamKey][key] = value;
2509     std::string result = localeBase + GenerateAllExtParam(extParamMap);
2510     return result;
2511 }
2512 
ParseAllExtParam(std::string locale)2513 std::unordered_map<std::string, std::unordered_map<std::string, std::string>> LocaleConfig::ParseAllExtParam(
2514     std::string locale)
2515 {
2516     std::unordered_map<std::string, std::unordered_map<std::string, std::string>> allExtParamMap;
2517     std::vector<std::pair<size_t, std::string>> positions = GetExtParamPositions(locale);
2518     std::reverse(positions.begin(), positions.end());
2519     for (size_t i = 0; i < positions.size(); i++) {
2520         size_t pos = positions[i].first;
2521         if (pos == std::string::npos) {
2522             continue;
2523         }
2524         std::string extParam = locale.substr(pos);
2525         locale = locale.substr(0, pos);
2526         std::string extParamKey = positions[i].second;
2527         std::unordered_map<std::string, std::string> extParamMap = ParseExtParam(extParam, extParamKey);
2528         allExtParamMap.insert(std::make_pair(extParamKey, extParamMap));
2529     }
2530     return allExtParamMap;
2531 }
2532 
ParseExtParam(const std::string & extParam,const std::string & extParamKey)2533 std::unordered_map<std::string, std::string> LocaleConfig::ParseExtParam(const std::string& extParam,
2534     const std::string& extParamKey)
2535 {
2536     std::unordered_map<std::string, std::string> result;
2537     size_t pos = extParam.find(extParamKey);
2538     if (pos == std::string::npos) {
2539         HILOG_ERROR_I18N("LocaleConfig::ParseExtParam: extParam is invalid.");
2540         return result;
2541     }
2542     std::string param = extParam.substr(pos + extParamKey.length());
2543     std::vector<std::string> paramArray;
2544     Split(param, "-", paramArray);
2545     size_t pairLen = 2;
2546     if (paramArray.size() % pairLen != 0) {
2547         HILOG_ERROR_I18N("LocaleConfig::ParseExtParam: parse ext param failed.");
2548         return result;
2549     }
2550     for (size_t pos = 0; pos + 1 < paramArray.size(); pos += pairLen) {
2551         std::string key = paramArray[pos];
2552         std::string value = paramArray[pos + 1];
2553         if (key.empty() || value.empty()) {
2554             HILOG_ERROR_I18N("LocaleConfig::ParseExtParam: key or value is empty.");
2555             continue;
2556         }
2557         auto status = result.insert({key, value});
2558         if (!status.second) {
2559             HILOG_ERROR_I18N("LocaleConfig::ParseExtParam: insert key (%{public}s) and value (%{public}s) failed.",
2560                 key.c_str(), value.c_str());
2561         }
2562     }
2563     return result;
2564 }
2565 
GenerateAllExtParam(const std::unordered_map<std::string,std::unordered_map<std::string,std::string>> & extParamMap)2566 std::string LocaleConfig::GenerateAllExtParam(
2567     const std::unordered_map<std::string, std::unordered_map<std::string, std::string>>& extParamMap)
2568 {
2569     std::string extParam;
2570     auto it = extParamMap.find(STANDARD_EXT_PARAM_KEY);
2571     if (it != extParamMap.end()) {
2572         std::string standardExtParam = GenerateExtParam(it->second, STANDARD_EXT_PARAM_KEY);
2573         extParam += standardExtParam;
2574     }
2575     it = extParamMap.find(CUST_EXT_PARAM_KEY);
2576     if (it != extParamMap.end()) {
2577         std::string custExtParam = GenerateExtParam(it->second, CUST_EXT_PARAM_KEY);
2578         extParam += custExtParam;
2579     }
2580     return extParam;
2581 }
2582 
GenerateExtParam(const std::unordered_map<std::string,std::string> & extParamMap,const std::string & extParamKey)2583 std::string LocaleConfig::GenerateExtParam(const std::unordered_map<std::string, std::string>& extParamMap,
2584     const std::string& extParamKey)
2585 {
2586     std::string extParam;
2587     for (auto& item : extParamMap) {
2588         std::string key = item.first;
2589         std::string value = item.second;
2590         if (value.empty()) {
2591             continue;
2592         }
2593         extParam += "-" + key + "-" + value;
2594     }
2595     if (!extParam.empty()) {
2596         extParam = extParamKey + extParam.substr(1);
2597     }
2598     return extParam;
2599 }
2600 
GetExtParamPositions(const std::string & locale)2601 std::vector<std::pair<size_t, std::string>> LocaleConfig::GetExtParamPositions(const std::string& locale)
2602 {
2603     std::vector<std::pair<size_t, std::string>> result;
2604     size_t standardPosition = locale.find(STANDARD_EXT_PARAM_KEY);
2605     size_t custPosition = locale.find(CUST_EXT_PARAM_KEY);
2606     if (standardPosition != std::string::npos && custPosition != std::string::npos) {
2607         if (standardPosition < custPosition) {
2608             result.emplace_back(std::make_pair(standardPosition, STANDARD_EXT_PARAM_KEY));
2609             result.emplace_back(std::make_pair(custPosition, CUST_EXT_PARAM_KEY));
2610         } else {
2611             result.emplace_back(std::make_pair(custPosition, CUST_EXT_PARAM_KEY));
2612             result.emplace_back(std::make_pair(standardPosition, STANDARD_EXT_PARAM_KEY));
2613         }
2614         return result;
2615     }
2616     if (standardPosition == std::string::npos) {
2617         result.emplace_back(std::make_pair(custPosition, CUST_EXT_PARAM_KEY));
2618         result.emplace_back(std::make_pair(standardPosition, STANDARD_EXT_PARAM_KEY));
2619         return result;
2620     }
2621     result.emplace_back(std::make_pair(standardPosition, STANDARD_EXT_PARAM_KEY));
2622     result.emplace_back(std::make_pair(custPosition, CUST_EXT_PARAM_KEY));
2623     return result;
2624 }
2625 
GetNumberingSystemDigit(const std::string & NumberingSystem)2626 std::string LocaleConfig::GetNumberingSystemDigit(const std::string& NumberingSystem)
2627 {
2628     auto it = NUMBERING_SYSTEM_NAME_TO_DESCRIPTION.find(NumberingSystem);
2629     if (it == NUMBERING_SYSTEM_NAME_TO_DESCRIPTION.end()) {
2630         HILOG_ERROR_I18N("LocaleConfig::GetNumberingSystemDigit: NumberingSystem is %{public}s.",
2631             NumberingSystem.c_str());
2632         return "";
2633     }
2634     return it->second;
2635 }
2636 
GetSimplifiedLanguage(const std::string & languageTag,int32_t & code)2637 std::string LocaleConfig::GetSimplifiedLanguage(const std::string& languageTag, int32_t &code)
2638 {
2639     std::string simplifiedLanguage = "";
2640     if (IsValidTag(languageTag)) {
2641         LocaleInfo localeInfo(languageTag);
2642         simplifiedLanguage = localeInfo.Minimize();
2643     } else {
2644         code = 1;
2645     }
2646     return simplifiedLanguage;
2647 }
2648 
GetSimplifiedSystemLanguage()2649 std::string LocaleConfig::GetSimplifiedSystemLanguage()
2650 {
2651     std::string locale = GetSystemLanguage();
2652     LocaleInfo localeInfo(locale);
2653     LocaleInfo localeInfoMax(localeInfo.Maximize());
2654     std::string language = localeInfoMax.GetLanguage();
2655     language = language + '-' + localeInfoMax.GetScript();
2656     if (dialectLanguages.find(language) != dialectLanguages.end()) {
2657         std::string systemRegion = localeInfo.GetRegion();
2658         if (!systemRegion.empty() && language.compare("en-Latn") != 0) {
2659             locale = language + '-' + systemRegion;
2660         } else {
2661             locale = GetSystemLocale();
2662         }
2663         LocaleInfo* requestLocale = new(std::nothrow) LocaleInfo(locale);
2664         if (requestLocale == nullptr) {
2665             HILOG_ERROR_I18N("GetSimplifiedLanguage: %{public}s failed to construct LocaleInfo.", locale.c_str());
2666             return "";
2667         }
2668         std::vector<LocaleInfo*> candidateLocales;
2669         for (auto& candidate : dialectLanguages[language]) {
2670             LocaleInfo* candidateInfo = new(std::nothrow) LocaleInfo(candidate);
2671             if (candidateInfo == nullptr) {
2672                 HILOG_ERROR_I18N("GetSimplifiedLanguage: %{public}s failed to construct LocaleInfo.",
2673                     candidate.c_str());
2674                 continue;
2675             }
2676             candidateLocales.push_back(candidateInfo);
2677         }
2678         locale = LocaleMatcher::GetBestMatchedLocale(requestLocale, candidateLocales);
2679 
2680         for (LocaleInfo* candidateInfo : candidateLocales) {
2681             delete candidateInfo;
2682             candidateInfo = nullptr;
2683         }
2684         delete requestLocale;
2685         requestLocale = nullptr;
2686     }
2687     LocaleInfo simplifiedLocale(locale);
2688     std::string ret = simplifiedLocale.Minimize();
2689     auto iter = resourceIdMap.find(ret);
2690     if (iter != resourceIdMap.end()) {
2691         ret = iter->second;
2692     }
2693     return ret;
2694 }
2695 
GetUnicodeWrappedFilePath(const std::string & path,const char delimiter,std::shared_ptr<LocaleInfo> localeInfo,std::string & invalidField)2696 std::string LocaleConfig::GetUnicodeWrappedFilePath(const std::string &path, const char delimiter,
2697     std::shared_ptr<LocaleInfo> localeInfo, std::string &invalidField)
2698 {
2699     std::string locale;
2700     if (localeInfo != nullptr) {
2701         locale = localeInfo->GetBaseName();
2702     }
2703     return LocaleConfig::GetUnicodeWrappedFilePathInner(path, delimiter, locale, invalidField);
2704 }
2705 
GetUnicodeWrappedFilePath(const std::string & path,const char delimiter,const std::string & localeTag,std::string & invalidField)2706 std::string LocaleConfig::GetUnicodeWrappedFilePath(const std::string &path, const char delimiter,
2707     const std::string& localeTag, std::string &invalidField)
2708 {
2709     std::string locale = LocaleConfig::RemoveAllExtParam(localeTag);
2710     return LocaleConfig::GetUnicodeWrappedFilePathInner(path, delimiter, locale, invalidField);
2711 }
2712 
GetUnicodeWrappedFilePathInner(const std::string & path,const char delimiter,const std::string & localeTag,std::string & invalidField)2713 std::string LocaleConfig::GetUnicodeWrappedFilePathInner(const std::string &path, const char delimiter,
2714     const std::string& localeTag, std::string &invalidField)
2715 {
2716     if (delimiter == '\0') {
2717         invalidField = "delimiter";
2718         return path;
2719     }
2720     if (path.empty() || path.length() > PATH_MAX) {
2721         invalidField = "path";
2722         return path;
2723     }
2724     std::string locale = localeTag;
2725     if (!IsValidTag(locale)) {
2726         locale = GetSystemLocale();
2727     }
2728     if (!IsRTL(locale)) {
2729         return path;
2730     }
2731     std::string result;
2732     std::vector<string> dest;
2733     std::string sep(1, delimiter); // 1 is char count
2734     Split(path, sep, dest);
2735     if (dest.size() == 1) { // 1 is array's size
2736         return path;
2737     }
2738     for (size_t i = 0 ; i < dest.size(); i++) {
2739         if (dest[i].empty()) {
2740             continue;
2741         }
2742         if (i == 0 && dest[i].compare(sep) != 0) {
2743             dest[i] = "\u200f\u200e" + dest[i] + "\u200e";
2744             continue;
2745         }
2746         dest[i] = "\u200e" + dest[i] + "\u200e";
2747     }
2748     std::string newSep = "\u200f" + sep;
2749     Merge(dest, newSep, result);
2750     return result;
2751 }
2752 
GetSystemLocaleInstanceTag()2753 std::string LocaleConfig::GetSystemLocaleInstanceTag()
2754 {
2755     return LocaleConfig::GetEffectiveLocale();
2756 }
2757 
GetIcuLocale(const std::string & localeTag)2758 icu::Locale LocaleConfigExt::GetIcuLocale(const std::string& localeTag)
2759 {
2760     if (!LocaleConfig::IsValidTag(localeTag)) {
2761         return LocaleConfigExt::GetSystemIcuLocale();
2762     }
2763     UErrorCode status = U_ZERO_ERROR;
2764     icu::Locale locale = icu::Locale::forLanguageTag(localeTag, status);
2765     if (U_FAILURE(status)) {
2766         HILOG_ERROR_I18N("LocaleConfig::GetIcuLocale: Create icu locale failed.");
2767         return LocaleConfigExt::GetSystemIcuLocale();
2768     }
2769     return locale;
2770 }
2771 
GetSystemIcuLocale()2772 icu::Locale LocaleConfigExt::GetSystemIcuLocale()
2773 {
2774     UErrorCode status = U_ZERO_ERROR;
2775     icu::Locale locale = icu::Locale::forLanguageTag(LocaleConfig::GetEffectiveLanguage(), status);
2776     if (U_FAILURE(status)) {
2777         HILOG_ERROR_I18N("LocaleConfigExt::GetSystemIcuLocale: Create icu locale failed.");
2778     }
2779     return locale;
2780 }
2781 } // namespace I18n
2782 } // namespace Global
2783 } // namespace OHOS
2784