1 /*
2 * Copyright (c) 2023 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
16 #include "hilog/log.h"
17 #include "locale_config.h"
18 #include "system_locale_manager.h"
19 #include "unicode/calendar.h"
20 #include "unicode/timezone.h"
21 #include "utils.h"
22 #include "i18n_timezone.h"
23
24 namespace OHOS {
25 namespace Global {
26 namespace I18n {
27 static constexpr OHOS::HiviewDFX::HiLogLabel LABEL = { LOG_CORE, 0xD001E00, "SystemLocaleManager" };
28 using namespace OHOS::HiviewDFX;
29
30 const char* SystemLocaleManager::SIM_COUNTRY_CODE_KEY = "telephony.sim.countryCode0";
31
SystemLocaleManager()32 SystemLocaleManager::SystemLocaleManager()
33 {
34 tabooUtils = std::make_unique<TabooUtils>();
35 }
36
~SystemLocaleManager()37 SystemLocaleManager::~SystemLocaleManager()
38 {
39 }
40
41 /**
42 * Language arrays are sorted according to the following steps:
43 * 1. Remove blocked languages.
44 * 2. Compute language locale displayName; If options.isUseLocalName is true, compute language local displayName.
45 * replace display name with taboo data.
46 * 3. Judge whether language is suggested with system region and sim card region.
47 * 4. Sort the languages use locale displayName, local displyName and suggestion infomation.
48 */
GetLanguageInfoArray(const std::vector<std::string> & languages,const SortOptions & options)49 std::vector<LocaleItem> SystemLocaleManager::GetLanguageInfoArray(const std::vector<std::string> &languages,
50 const SortOptions &options)
51 {
52 std::unordered_set<std::string> blockedLanguages = LocaleConfig::GetBlockedLanguages();
53 std::vector<LocaleItem> localeItemList;
54 for (auto it = languages.begin(); it != languages.end(); ++it) {
55 if (blockedLanguages.find(*it) != blockedLanguages.end()) {
56 continue;
57 }
58 std::string languageDisplayName = LocaleConfig::GetDisplayLanguage(*it, options.localeTag, true);
59 languageDisplayName = tabooUtils->ReplaceLanguageName(*it, options.localeTag, languageDisplayName);
60 std::string languageNativeName;
61 if (options.isUseLocalName) {
62 languageNativeName = LocaleConfig::GetDisplayLanguage(*it, *it, true);
63 languageNativeName = tabooUtils->ReplaceLanguageName(*it, *it, languageNativeName);
64 }
65 bool isSuggestedWithSystemRegion = LocaleConfig::IsSuggested(*it, LocaleConfig::GetSystemRegion());
66 std::string simRegion = ReadSystemParameter(SIM_COUNTRY_CODE_KEY, CONFIG_LEN);
67 bool isSuggestedWithSimRegion = false;
68 if (simRegion.length() > 0) {
69 isSuggestedWithSimRegion = LocaleConfig::IsSuggested(*it, simRegion);
70 }
71 SuggestionType suggestionType = SuggestionType::SUGGESTION_TYPE_NONE;
72 if (isSuggestedWithSimRegion) {
73 suggestionType = SuggestionType::SUGGESTION_TYPE_SIM;
74 } else if (isSuggestedWithSystemRegion) {
75 suggestionType = SuggestionType::SUGGESTION_TYPE_RELATED;
76 }
77 LocaleItem item { *it, suggestionType, languageDisplayName, languageNativeName };
78 localeItemList.push_back(item);
79 }
80 SortLocaleItemList(localeItemList, options);
81 return localeItemList;
82 }
83
84 /**
85 * Region arrays are sorted according to the following steps:
86 * 1. Remove blocked regions and blocked regions under system Language.
87 * 2. Compute region locale displayName; replace display name with taboo data.
88 * 3. Judge whether region is suggested with system language.
89 * 4. Sort the regions use locale displayName and suggestion infomation.
90 */
GetCountryInfoArray(const std::vector<std::string> & countries,const SortOptions & options)91 std::vector<LocaleItem> SystemLocaleManager::GetCountryInfoArray(const std::vector<std::string> &countries,
92 const SortOptions &options)
93 {
94 std::unordered_set<std::string> blockedRegions = LocaleConfig::GetBlockedRegions();
95 std::unordered_set<std::string> blockedLanguageRegions = LocaleConfig::GetLanguageBlockedRegions();
96 std::vector<LocaleItem> localeItemList;
97 for (auto it = countries.begin(); it != countries.end(); ++it) {
98 if (blockedRegions.find(*it) != blockedRegions.end() || blockedLanguageRegions.find(*it) !=
99 blockedLanguageRegions.end()) {
100 continue;
101 }
102 std::string regionDisplayName = LocaleConfig::GetDisplayRegion(*it, options.localeTag, true);
103 regionDisplayName = tabooUtils->ReplaceCountryName(*it, options.localeTag, regionDisplayName);
104 bool isSuggestedRegion = LocaleConfig::IsSuggested(LocaleConfig::GetSystemLanguage(), *it);
105 SuggestionType suggestionType = SuggestionType::SUGGESTION_TYPE_NONE;
106 if (isSuggestedRegion) {
107 suggestionType = SuggestionType::SUGGESTION_TYPE_RELATED;
108 }
109 LocaleItem item { *it, suggestionType, regionDisplayName, "" };
110 localeItemList.push_back(item);
111 }
112 SortLocaleItemList(localeItemList, options);
113 return localeItemList;
114 }
115
SortLocaleItemList(std::vector<LocaleItem> & localeItemList,const SortOptions & options)116 void SystemLocaleManager::SortLocaleItemList(std::vector<LocaleItem> &localeItemList, const SortOptions &options)
117 {
118 std::vector<std::string> collatorLocaleTags { options.localeTag };
119 std::map<std::string, std::string> collatorOptions {};
120 Collator *collator = new Collator(collatorLocaleTags, collatorOptions);
121 auto compareFunc = [collator, options](LocaleItem item1, LocaleItem item2) {
122 if (options.isSuggestedFirst) {
123 if (item1.suggestionType < item2.suggestionType) {
124 return false;
125 } else if (item1.suggestionType > item2.suggestionType) {
126 return true;
127 }
128 }
129 CompareResult result = CompareResult::INVALID;
130 if (item1.localName.length() != 0) {
131 result = collator->Compare(item1.localName, item2.localName);
132 if (result == CompareResult::SMALLER) {
133 return true;
134 }
135 if (result == CompareResult::INVALID) {
136 HiLog::Error(LABEL, "SystemLocaleManager: invalid compare result for local name.");
137 }
138 return false;
139 }
140 result = collator->Compare(item1.displayName, item2.displayName);
141 if (result == CompareResult::SMALLER) {
142 return true;
143 }
144 if (result == CompareResult::INVALID) {
145 HiLog::Error(LABEL, "SystemLocaleManager: invalid compare result for display name.");
146 }
147 return false;
148 };
149 std::sort(localeItemList.begin(), localeItemList.end(), compareFunc);
150 delete collator;
151 }
152
GetTimezoneCityInfoArray()153 std::vector<TimeZoneCityItem> SystemLocaleManager::GetTimezoneCityInfoArray()
154 {
155 std::set<std::string> zoneCityIds = I18nTimeZone::GetAvailableZoneCityIDs();
156 std::string locale = LocaleConfig::GetSystemLocale();
157 std::vector<TimeZoneCityItem> result;
158 std::string localeBaseName = I18nTimeZone::GetLocaleBaseName(locale);
159 std::map<std::string, std::string> displayNameMap = I18nTimeZone::FindCityDisplayNameMap(localeBaseName);
160 std::map<std::string, icu::TimeZone*> tzMap;
161 for (auto it = zoneCityIds.begin(); it != zoneCityIds.end(); ++it) {
162 std::string cityId = *it;
163 std::string cityDisplayName = "";
164 if (displayNameMap.find(cityId) != displayNameMap.end()) {
165 cityDisplayName = displayNameMap.find(cityId)->second;
166 }
167 int32_t rawOffset = 0;
168 int32_t dstOffset = 0;
169 bool local = false;
170 UErrorCode status = U_ZERO_ERROR;
171 UDate date = icu::Calendar::getNow();
172 std::string timezoneId = I18nTimeZone::GetTimezoneIdByCityId(cityId);
173 if (timezoneId.length() == 0) {
174 continue;
175 }
176 if (tzMap.find(timezoneId) != tzMap.end()) {
177 icu::TimeZone *icuTimeZone = tzMap.find(timezoneId)->second;
178 icuTimeZone->getOffset(date, (UBool)local, rawOffset, dstOffset, status);
179 } else {
180 icu::UnicodeString unicodeString = icu::UnicodeString::fromUTF8(timezoneId);
181 icu::TimeZone *icuTimeZone = icu::TimeZone::createTimeZone(unicodeString);
182 icuTimeZone->getOffset(date, (UBool)local, rawOffset, dstOffset, status);
183 tzMap.insert({timezoneId, icuTimeZone});
184 }
185 struct TimeZoneCityItem tzCityItem = {
186 timezoneId, cityId, cityDisplayName, dstOffset + rawOffset, "", rawOffset
187 };
188 result.push_back(tzCityItem);
189 }
190 SortTimezoneCityItemList(locale, result);
191 return result;
192 }
193
SortTimezoneCityItemList(const std::string & locale,std::vector<TimeZoneCityItem> & timezoneCityItemList)194 void SystemLocaleManager::SortTimezoneCityItemList(const std::string &locale,
195 std::vector<TimeZoneCityItem> &timezoneCityItemList)
196 {
197 std::vector<std::string> collatorLocaleTags { locale };
198 std::map<std::string, std::string> collatorOptions {};
199 Collator *collator = new Collator(collatorLocaleTags, collatorOptions);
200 auto sortFunc = [collator](TimeZoneCityItem item1, TimeZoneCityItem item2) {
201 CompareResult result = CompareResult::INVALID;
202 result = collator->Compare(item1.cityDisplayName, item2.cityDisplayName);
203 if (result == CompareResult::SMALLER) {
204 return true;
205 }
206 if (result == CompareResult::INVALID) {
207 HiLog::Error(LABEL, "SystemLocaleManager: invalid compare result for city display name.");
208 }
209 return false;
210 };
211 std::sort(timezoneCityItemList.begin(), timezoneCityItemList.end(), sortFunc);
212 delete collator;
213 }
214 } // I18n
215 } // Global
216 } // OHOS