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