• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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