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