19596a2c1Sopenharmony_ci/* 29596a2c1Sopenharmony_ci * Copyright (c) 2023 Huawei Device Co., Ltd. 39596a2c1Sopenharmony_ci * Licensed under the Apache License, Version 2.0 (the "License"); 49596a2c1Sopenharmony_ci * you may not use this file except in compliance with the License. 59596a2c1Sopenharmony_ci * You may obtain a copy of the License at 69596a2c1Sopenharmony_ci * 79596a2c1Sopenharmony_ci * http://www.apache.org/licenses/LICENSE-2.0 89596a2c1Sopenharmony_ci * 99596a2c1Sopenharmony_ci * Unless required by applicable law or agreed to in writing, software 109596a2c1Sopenharmony_ci * distributed under the License is distributed on an "AS IS" BASIS, 119596a2c1Sopenharmony_ci * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 129596a2c1Sopenharmony_ci * See the License for the specific language governing permissions and 139596a2c1Sopenharmony_ci * limitations under the License. 149596a2c1Sopenharmony_ci */ 159596a2c1Sopenharmony_ci 169596a2c1Sopenharmony_ci#include "i18n_hilog.h" 179596a2c1Sopenharmony_ci#include "locale_config.h" 189596a2c1Sopenharmony_ci#include "system_locale_manager.h" 199596a2c1Sopenharmony_ci#include "unicode/calendar.h" 209596a2c1Sopenharmony_ci#include "unicode/timezone.h" 219596a2c1Sopenharmony_ci#include "utils.h" 229596a2c1Sopenharmony_ci#include "i18n_timezone.h" 239596a2c1Sopenharmony_ci 249596a2c1Sopenharmony_cinamespace OHOS { 259596a2c1Sopenharmony_cinamespace Global { 269596a2c1Sopenharmony_cinamespace I18n { 279596a2c1Sopenharmony_ciconst char* SystemLocaleManager::SIM_COUNTRY_CODE_KEY = "telephony.sim.countryCode0"; 289596a2c1Sopenharmony_ci 299596a2c1Sopenharmony_ciSystemLocaleManager::SystemLocaleManager() 309596a2c1Sopenharmony_ci{ 319596a2c1Sopenharmony_ci tabooUtils = std::make_unique<TabooUtils>(); 329596a2c1Sopenharmony_ci} 339596a2c1Sopenharmony_ci 349596a2c1Sopenharmony_ciSystemLocaleManager::~SystemLocaleManager() 359596a2c1Sopenharmony_ci{ 369596a2c1Sopenharmony_ci} 379596a2c1Sopenharmony_ci 389596a2c1Sopenharmony_ci/** 399596a2c1Sopenharmony_ci * Language arrays are sorted according to the following steps: 409596a2c1Sopenharmony_ci * 1. Remove blocked languages. 419596a2c1Sopenharmony_ci * 2. Compute language locale displayName; If options.isUseLocalName is true, compute language local displayName. 429596a2c1Sopenharmony_ci * replace display name with taboo data. 439596a2c1Sopenharmony_ci * 3. Judge whether language is suggested with system region and sim card region. 449596a2c1Sopenharmony_ci * 4. Sort the languages use locale displayName, local displyName and suggestion infomation. 459596a2c1Sopenharmony_ci */ 469596a2c1Sopenharmony_cistd::vector<LocaleItem> SystemLocaleManager::GetLanguageInfoArray(const std::vector<std::string> &languages, 479596a2c1Sopenharmony_ci const SortOptions &options, I18nErrorCode &status) 489596a2c1Sopenharmony_ci{ 499596a2c1Sopenharmony_ci std::vector<LocaleItem> localeItemList; 509596a2c1Sopenharmony_ci status = I18nErrorCode::SUCCESS; 519596a2c1Sopenharmony_ci if (!CheckSystemPermission()) { 529596a2c1Sopenharmony_ci status = I18nErrorCode::NOT_SYSTEM_APP; 539596a2c1Sopenharmony_ci return localeItemList; 549596a2c1Sopenharmony_ci } 559596a2c1Sopenharmony_ci std::unordered_set<std::string> blockedLanguages = LocaleConfig::GetBlockedLanguages(); 569596a2c1Sopenharmony_ci for (auto it = languages.begin(); it != languages.end(); ++it) { 579596a2c1Sopenharmony_ci if (blockedLanguages.find(*it) != blockedLanguages.end()) { 589596a2c1Sopenharmony_ci continue; 599596a2c1Sopenharmony_ci } 609596a2c1Sopenharmony_ci std::string languageDisplayName = LocaleConfig::GetDisplayLanguage(*it, options.localeTag, true); 619596a2c1Sopenharmony_ci languageDisplayName = tabooUtils->ReplaceLanguageName(*it, options.localeTag, languageDisplayName); 629596a2c1Sopenharmony_ci std::string languageNativeName; 639596a2c1Sopenharmony_ci if (options.isUseLocalName) { 649596a2c1Sopenharmony_ci languageNativeName = LocaleConfig::GetDisplayLanguage(*it, *it, true); 659596a2c1Sopenharmony_ci languageNativeName = tabooUtils->ReplaceLanguageName(*it, *it, languageNativeName); 669596a2c1Sopenharmony_ci } 679596a2c1Sopenharmony_ci bool isSuggestedWithSystemRegion = LocaleConfig::IsSuggested(*it, LocaleConfig::GetSystemRegion()); 689596a2c1Sopenharmony_ci std::string simRegion = ReadSystemParameter(SIM_COUNTRY_CODE_KEY, CONFIG_LEN); 699596a2c1Sopenharmony_ci bool isSuggestedWithSimRegion = false; 709596a2c1Sopenharmony_ci if (simRegion.length() > 0) { 719596a2c1Sopenharmony_ci isSuggestedWithSimRegion = LocaleConfig::IsSuggested(*it, simRegion); 729596a2c1Sopenharmony_ci } 739596a2c1Sopenharmony_ci SuggestionType suggestionType = SuggestionType::SUGGESTION_TYPE_NONE; 749596a2c1Sopenharmony_ci if (isSuggestedWithSimRegion) { 759596a2c1Sopenharmony_ci suggestionType = SuggestionType::SUGGESTION_TYPE_SIM; 769596a2c1Sopenharmony_ci } else if (isSuggestedWithSystemRegion) { 779596a2c1Sopenharmony_ci suggestionType = SuggestionType::SUGGESTION_TYPE_RELATED; 789596a2c1Sopenharmony_ci } 799596a2c1Sopenharmony_ci LocaleItem item { *it, suggestionType, languageDisplayName, languageNativeName }; 809596a2c1Sopenharmony_ci localeItemList.push_back(item); 819596a2c1Sopenharmony_ci } 829596a2c1Sopenharmony_ci SortLocaleItemList(localeItemList, options); 839596a2c1Sopenharmony_ci return localeItemList; 849596a2c1Sopenharmony_ci} 859596a2c1Sopenharmony_ci 869596a2c1Sopenharmony_ci/** 879596a2c1Sopenharmony_ci * Region arrays are sorted according to the following steps: 889596a2c1Sopenharmony_ci * 1. Remove blocked regions and blocked regions under system Language. 899596a2c1Sopenharmony_ci * 2. Compute region locale displayName; replace display name with taboo data. 909596a2c1Sopenharmony_ci * 3. Judge whether region is suggested with system language. 919596a2c1Sopenharmony_ci * 4. Sort the regions use locale displayName and suggestion infomation. 929596a2c1Sopenharmony_ci */ 939596a2c1Sopenharmony_cistd::vector<LocaleItem> SystemLocaleManager::GetCountryInfoArray(const std::vector<std::string> &countries, 949596a2c1Sopenharmony_ci const SortOptions &options, I18nErrorCode &status) 959596a2c1Sopenharmony_ci{ 969596a2c1Sopenharmony_ci std::vector<LocaleItem> localeItemList; 979596a2c1Sopenharmony_ci status = I18nErrorCode::SUCCESS; 989596a2c1Sopenharmony_ci if (!CheckSystemPermission()) { 999596a2c1Sopenharmony_ci status = I18nErrorCode::NOT_SYSTEM_APP; 1009596a2c1Sopenharmony_ci return localeItemList; 1019596a2c1Sopenharmony_ci } 1029596a2c1Sopenharmony_ci std::unordered_set<std::string> blockedRegions = LocaleConfig::GetBlockedRegions(); 1039596a2c1Sopenharmony_ci std::unordered_set<std::string> blockedLanguageRegions = LocaleConfig::GetLanguageBlockedRegions(); 1049596a2c1Sopenharmony_ci std::string pseudoProcessedRegion = PseudoLocalizationProcessor(""); 1059596a2c1Sopenharmony_ci for (auto it = countries.begin(); it != countries.end(); ++it) { 1069596a2c1Sopenharmony_ci if (blockedRegions.find(*it) != blockedRegions.end() || blockedLanguageRegions.find(*it) != 1079596a2c1Sopenharmony_ci blockedLanguageRegions.end()) { 1089596a2c1Sopenharmony_ci continue; 1099596a2c1Sopenharmony_ci } 1109596a2c1Sopenharmony_ci std::string regionDisplayName = LocaleConfig::GetDisplayRegion(*it, options.localeTag, true); 1119596a2c1Sopenharmony_ci regionDisplayName = tabooUtils->ReplaceCountryName(*it, options.localeTag, regionDisplayName); 1129596a2c1Sopenharmony_ci bool isSuggestedRegion = LocaleConfig::IsSuggested(LocaleConfig::GetSystemLanguage(), *it); 1139596a2c1Sopenharmony_ci SuggestionType suggestionType = SuggestionType::SUGGESTION_TYPE_NONE; 1149596a2c1Sopenharmony_ci if (isSuggestedRegion) { 1159596a2c1Sopenharmony_ci suggestionType = SuggestionType::SUGGESTION_TYPE_RELATED; 1169596a2c1Sopenharmony_ci } 1179596a2c1Sopenharmony_ci LocaleItem item { *it, suggestionType, regionDisplayName, pseudoProcessedRegion }; 1189596a2c1Sopenharmony_ci localeItemList.push_back(item); 1199596a2c1Sopenharmony_ci } 1209596a2c1Sopenharmony_ci SortLocaleItemList(localeItemList, options); 1219596a2c1Sopenharmony_ci return localeItemList; 1229596a2c1Sopenharmony_ci} 1239596a2c1Sopenharmony_ci 1249596a2c1Sopenharmony_civoid SystemLocaleManager::SortLocaleItemList(std::vector<LocaleItem> &localeItemList, const SortOptions &options) 1259596a2c1Sopenharmony_ci{ 1269596a2c1Sopenharmony_ci std::vector<std::string> collatorLocaleTags { options.localeTag }; 1279596a2c1Sopenharmony_ci std::map<std::string, std::string> collatorOptions {}; 1289596a2c1Sopenharmony_ci Collator *collator = new (std::nothrow) Collator(collatorLocaleTags, collatorOptions); 1299596a2c1Sopenharmony_ci if (collator == nullptr) { 1309596a2c1Sopenharmony_ci return; 1319596a2c1Sopenharmony_ci } 1329596a2c1Sopenharmony_ci auto compareFunc = [collator, options](LocaleItem item1, LocaleItem item2) { 1339596a2c1Sopenharmony_ci if (options.isSuggestedFirst) { 1349596a2c1Sopenharmony_ci if (item1.suggestionType < item2.suggestionType) { 1359596a2c1Sopenharmony_ci return false; 1369596a2c1Sopenharmony_ci } else if (item1.suggestionType > item2.suggestionType) { 1379596a2c1Sopenharmony_ci return true; 1389596a2c1Sopenharmony_ci } 1399596a2c1Sopenharmony_ci } 1409596a2c1Sopenharmony_ci CompareResult result = CompareResult::INVALID; 1419596a2c1Sopenharmony_ci if (item1.localName.length() != 0) { 1429596a2c1Sopenharmony_ci result = collator->Compare(item1.localName, item2.localName); 1439596a2c1Sopenharmony_ci if (result == CompareResult::SMALLER) { 1449596a2c1Sopenharmony_ci return true; 1459596a2c1Sopenharmony_ci } 1469596a2c1Sopenharmony_ci if (result == CompareResult::INVALID) { 1479596a2c1Sopenharmony_ci HILOG_ERROR_I18N("SystemLocaleManager: invalid compare result for local name."); 1489596a2c1Sopenharmony_ci } 1499596a2c1Sopenharmony_ci return false; 1509596a2c1Sopenharmony_ci } 1519596a2c1Sopenharmony_ci result = collator->Compare(item1.displayName, item2.displayName); 1529596a2c1Sopenharmony_ci if (result == CompareResult::SMALLER) { 1539596a2c1Sopenharmony_ci return true; 1549596a2c1Sopenharmony_ci } 1559596a2c1Sopenharmony_ci if (result == CompareResult::INVALID) { 1569596a2c1Sopenharmony_ci HILOG_ERROR_I18N("SystemLocaleManager: invalid compare result for display name."); 1579596a2c1Sopenharmony_ci } 1589596a2c1Sopenharmony_ci return false; 1599596a2c1Sopenharmony_ci }; 1609596a2c1Sopenharmony_ci std::sort(localeItemList.begin(), localeItemList.end(), compareFunc); 1619596a2c1Sopenharmony_ci delete collator; 1629596a2c1Sopenharmony_ci} 1639596a2c1Sopenharmony_ci 1649596a2c1Sopenharmony_cistd::vector<TimeZoneCityItem> SystemLocaleManager::GetTimezoneCityInfoArray(I18nErrorCode& status) 1659596a2c1Sopenharmony_ci{ 1669596a2c1Sopenharmony_ci std::vector<TimeZoneCityItem> result; 1679596a2c1Sopenharmony_ci status = I18nErrorCode::SUCCESS; 1689596a2c1Sopenharmony_ci if (!CheckSystemPermission()) { 1699596a2c1Sopenharmony_ci status = I18nErrorCode::NOT_SYSTEM_APP; 1709596a2c1Sopenharmony_ci return result; 1719596a2c1Sopenharmony_ci } 1729596a2c1Sopenharmony_ci result = GetTimezoneCityInfoArray(); 1739596a2c1Sopenharmony_ci SortTimezoneCityItemList(LocaleConfig::GetSystemLocale(), result); 1749596a2c1Sopenharmony_ci return result; 1759596a2c1Sopenharmony_ci} 1769596a2c1Sopenharmony_ci 1779596a2c1Sopenharmony_cistd::vector<TimeZoneCityItem> SystemLocaleManager::GetTimezoneCityInfoArray() 1789596a2c1Sopenharmony_ci{ 1799596a2c1Sopenharmony_ci std::vector<TimeZoneCityItem> result; 1809596a2c1Sopenharmony_ci std::set<std::string> zoneCityIds = I18nTimeZone::GetAvailableZoneCityIDs(); 1819596a2c1Sopenharmony_ci std::string locale = LocaleConfig::GetSystemLocale(); 1829596a2c1Sopenharmony_ci std::string localeBaseName = I18nTimeZone::GetLocaleBaseName(locale); 1839596a2c1Sopenharmony_ci std::map<std::string, std::string> displayNameMap = I18nTimeZone::FindCityDisplayNameMap(localeBaseName); 1849596a2c1Sopenharmony_ci std::map<std::string, icu::TimeZone*> tzMap; 1859596a2c1Sopenharmony_ci bool ifEnforce = GetPseudoLocalizationEnforce(); 1869596a2c1Sopenharmony_ci for (auto it = zoneCityIds.begin(); it != zoneCityIds.end(); ++it) { 1879596a2c1Sopenharmony_ci std::string cityId = *it, cityDisplayName = ""; 1889596a2c1Sopenharmony_ci if (displayNameMap.find(cityId) != displayNameMap.end()) { 1899596a2c1Sopenharmony_ci cityDisplayName = displayNameMap.find(cityId)->second; 1909596a2c1Sopenharmony_ci } 1919596a2c1Sopenharmony_ci int32_t rawOffset = 0, dstOffset = 0; 1929596a2c1Sopenharmony_ci bool local = false; 1939596a2c1Sopenharmony_ci UErrorCode status = U_ZERO_ERROR; 1949596a2c1Sopenharmony_ci UDate date = icu::Calendar::getNow(); 1959596a2c1Sopenharmony_ci std::string timezoneId = I18nTimeZone::GetTimezoneIdByCityId(cityId); 1969596a2c1Sopenharmony_ci if (timezoneId.length() == 0) { 1979596a2c1Sopenharmony_ci continue; 1989596a2c1Sopenharmony_ci } 1999596a2c1Sopenharmony_ci if (tzMap.find(timezoneId) != tzMap.end()) { 2009596a2c1Sopenharmony_ci icu::TimeZone *icuTimeZone = tzMap.find(timezoneId)->second; 2019596a2c1Sopenharmony_ci icuTimeZone->getOffset(date, (UBool)local, rawOffset, dstOffset, status); 2029596a2c1Sopenharmony_ci } else { 2039596a2c1Sopenharmony_ci icu::UnicodeString unicodeString = icu::UnicodeString::fromUTF8(timezoneId); 2049596a2c1Sopenharmony_ci icu::TimeZone *icuTimeZone = icu::TimeZone::createTimeZone(unicodeString); 2059596a2c1Sopenharmony_ci if (icuTimeZone == nullptr) { 2069596a2c1Sopenharmony_ci continue; 2079596a2c1Sopenharmony_ci } 2089596a2c1Sopenharmony_ci icuTimeZone->getOffset(date, (UBool)local, rawOffset, dstOffset, status); 2099596a2c1Sopenharmony_ci tzMap.insert({timezoneId, icuTimeZone}); 2109596a2c1Sopenharmony_ci } 2119596a2c1Sopenharmony_ci struct TimeZoneCityItem tzCityItem = { 2129596a2c1Sopenharmony_ci timezoneId, cityId, PseudoLocalizationProcessor(cityDisplayName, ifEnforce), dstOffset + rawOffset, 2139596a2c1Sopenharmony_ci PseudoLocalizationProcessor("", ifEnforce), rawOffset 2149596a2c1Sopenharmony_ci }; 2159596a2c1Sopenharmony_ci result.push_back(tzCityItem); 2169596a2c1Sopenharmony_ci } 2179596a2c1Sopenharmony_ci for (auto it = tzMap.begin(); it != tzMap.end(); ++it) { 2189596a2c1Sopenharmony_ci delete it->second; 2199596a2c1Sopenharmony_ci it->second = nullptr; 2209596a2c1Sopenharmony_ci } 2219596a2c1Sopenharmony_ci return result; 2229596a2c1Sopenharmony_ci} 2239596a2c1Sopenharmony_ci 2249596a2c1Sopenharmony_civoid SystemLocaleManager::SortTimezoneCityItemList(const std::string &locale, 2259596a2c1Sopenharmony_ci std::vector<TimeZoneCityItem> &timezoneCityItemList) 2269596a2c1Sopenharmony_ci{ 2279596a2c1Sopenharmony_ci std::vector<std::string> collatorLocaleTags { locale }; 2289596a2c1Sopenharmony_ci std::map<std::string, std::string> collatorOptions {}; 2299596a2c1Sopenharmony_ci Collator *collator = new (std::nothrow) Collator(collatorLocaleTags, collatorOptions); 2309596a2c1Sopenharmony_ci if (collator == nullptr) { 2319596a2c1Sopenharmony_ci return; 2329596a2c1Sopenharmony_ci } 2339596a2c1Sopenharmony_ci auto sortFunc = [collator](TimeZoneCityItem item1, TimeZoneCityItem item2) { 2349596a2c1Sopenharmony_ci CompareResult result = CompareResult::INVALID; 2359596a2c1Sopenharmony_ci result = collator->Compare(item1.cityDisplayName, item2.cityDisplayName); 2369596a2c1Sopenharmony_ci if (result == CompareResult::SMALLER) { 2379596a2c1Sopenharmony_ci return true; 2389596a2c1Sopenharmony_ci } 2399596a2c1Sopenharmony_ci if (result == CompareResult::INVALID) { 2409596a2c1Sopenharmony_ci HILOG_ERROR_I18N("SystemLocaleManager: invalid compare result for city display name."); 2419596a2c1Sopenharmony_ci } 2429596a2c1Sopenharmony_ci return false; 2439596a2c1Sopenharmony_ci }; 2449596a2c1Sopenharmony_ci std::sort(timezoneCityItemList.begin(), timezoneCityItemList.end(), sortFunc); 2459596a2c1Sopenharmony_ci delete collator; 2469596a2c1Sopenharmony_ci} 2479596a2c1Sopenharmony_ci} // I18n 2489596a2c1Sopenharmony_ci} // Global 2499596a2c1Sopenharmony_ci} // OHOS