• 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_compare.h"
18 #include "ohos/init_data.h"
19 #include "unicode/locid.h"
20 
21 namespace OHOS {
22 namespace Global {
23 namespace I18n {
24 static constexpr OHOS::HiviewDFX::HiLogLabel LABEL = { LOG_CORE, 0xD001E00, "LocaleCompare" };
25 using namespace OHOS::HiviewDFX;
26 std::string LocaleCompare::hantSegment = "-Hant-";
27 std::string LocaleCompare::latnSegment = "-Latn-";
28 std::string LocaleCompare::qaagSegment = "-Qaag-";
29 std::set<std::string> LocaleCompare::scriptLocales {
30     "zh", "en", "es", "pt"
31 };
32 std::map<std::string, std::string> LocaleCompare::hantParent {
33     { "zh-MO", "zh-Hant-HK" }
34 };
35 std::map<std::string, std::string> LocaleCompare::latnParent {
36     { "en-150", "en-001" },
37     { "en-AG", "en-001" },
38     { "en-AI", "en-001" },
39     { "en-AU", "en-001" },
40     { "en-BB", "en-001" },
41     { "en-BE", "en-001" },
42     { "en-BM", "en-001" },
43     { "en-BS", "en-001" },
44     { "en-BZ", "en-001" },
45     { "en-CC", "en-001" },
46     { "en-CK", "en-001" },
47     { "en-CX", "en-001" },
48     { "en-DG", "en-001" },
49     { "en-ER", "en-001" },
50     { "en-FK", "en-001" },
51     { "en-FM", "en-001" },
52     { "en-GB", "en-001" },
53     { "en-GD", "en-001" },
54     { "en-GG", "en-001" },
55     { "en-GI", "en-001" },
56     { "en-GY", "en-001" },
57     { "en-HK", "en-001" },
58     { "en-IE", "en-001" },
59     { "en-IM", "en-001" },
60     { "en-IN", "en-001" },
61     { "en-IO", "en-001" },
62     { "en-JE", "en-001" },
63     { "en-KI", "en-001" },
64     { "en-KN", "en-001" },
65     { "en-KY", "en-001" },
66     { "en-LC", "en-001" },
67     { "en-LR", "en-001" },
68     { "en-LS", "en-001" },
69     { "en-MM", "en-001" },
70     { "en-MO", "en-001" },
71     { "en-MS", "en-001" },
72     { "en-MT", "en-001" },
73     { "en-MY", "en-001" },
74     { "en-NF", "en-001" },
75     { "en-NR", "en-001" },
76     { "en-NU", "en-001" },
77     { "en-NZ", "en-001" },
78     { "en-PG", "en-001" },
79     { "en-PK", "en-001" },
80     { "en-PN", "en-001" },
81     { "en-PW", "en-001" },
82     { "en-SB", "en-001" },
83     { "en-SC", "en-001" },
84     { "en-SD", "en-001" },
85     { "en-SG", "en-001" },
86     { "en-SH", "en-001" },
87     { "en-SL", "en-001" },
88     { "en-SS", "en-001" },
89     { "en-SX", "en-001" },
90     { "en-SZ", "en-001" },
91     { "en-TC", "en-001" },
92     { "en-TK", "en-001" },
93     { "en-TT", "en-001" },
94     { "en-TV", "en-001" },
95     { "en-VC", "en-001" },
96     { "en-VG", "en-001" },
97     { "en-WS", "en-001" },
98     { "en-ZG", "en-001" },
99     { "es-AR", "es-419" },
100     { "es-BO", "es-419" },
101     { "es-BR", "es-419" },
102     { "es-CL", "es-419" },
103     { "es-CO", "es-419" },
104     { "es-CR", "es-419" },
105     { "es-CU", "es-419" },
106     { "es-DO", "es-419" },
107     { "es-EC", "es-419" },
108     { "es-GT", "es-419" },
109     { "es-HN", "es-419" },
110     { "es-MX", "es-419" },
111     { "es-NI", "es-419" },
112     { "es-PA", "es-419" },
113     { "es-PE", "es-419" },
114     { "es-PR", "es-419" },
115     { "es-PY", "es-419" },
116     { "es-SV", "es-419" },
117     { "es-US", "es-419" },
118     { "es-UY", "es-419" },
119     { "es-VE", "es-419" },
120     { "pt-AO", "pt-PT" },
121     { "pt-CH", "pt-PT" },
122     { "pt-CV", "pt-PT" },
123     { "pt-GQ", "pt-PT" },
124     { "pt-GW", "pt-PT" },
125     { "pt-LU", "pt-PT" },
126     { "pt-MO", "pt-PT" },
127     { "pt-MZ", "pt-PT" },
128     { "pt-ST", "pt-PT" },
129     { "pt-TL", "pt-PT" }
130 };
131 std::map<std::string, std::string> LocaleCompare::extendedHantParent {};
132 std::map<std::string, std::string> LocaleCompare::extendedLatnParent {};
133 
Compare(const std::string & localeTag1,const std::string & localeTag2)134 int32_t LocaleCompare::Compare(const std::string& localeTag1, const std::string& localeTag2)
135 {
136     UErrorCode status = U_ZERO_ERROR;
137     icu::Locale locale1 = icu::Locale::forLanguageTag(icu::StringPiece(localeTag1), status);
138     icu::Locale locale2 = icu::Locale::forLanguageTag(icu::StringPiece(localeTag2), status);
139     int32_t segmentScore = 3;
140     const int32_t mapScore = 8;
141     int32_t score = 0;
142     std::string language1 = locale1.getLanguage();
143     std::string language2 = locale2.getLanguage();
144     if (IsSameLanguage(language1, language2)) {
145         score += segmentScore;
146     } else {
147         return -1;
148     }
149     std::string localeBaseName1 = locale1.getBaseName();
150     std::string localeBaseName2 = locale2.getBaseName();
151     std::replace(localeBaseName1.begin(), localeBaseName1.end(), '_', '-');
152     std::replace(localeBaseName2.begin(), localeBaseName2.end(), '_', '-');
153     if (HasMapRelation(language1, localeBaseName1, localeBaseName2)) {
154         return mapScore;
155     }
156     std::string region1 = locale1.getCountry();
157     std::string region2 = locale2.getCountry();
158     locale1.addLikelySubtags(status);
159     locale2.addLikelySubtags(status);
160     if (U_FAILURE(status)) {
161         HiLog::Error(LABEL, "LocaleCompare::Compare add likely subtags failed.");
162         return -1;
163     }
164     std::string script1 = locale1.getScript();
165     std::string script2 = locale2.getScript();
166     if (script1.compare(script2) == 0 || (language1.compare("en") == 0 && IsSameEnglishScript(script1, script2))) {
167         score += segmentScore;
168         if (region2.length() == 0) {
169             ++score;
170         }
171     } else {
172         return -1;
173     }
174     if (region1.length() != 0 && region1.compare(region2) == 0) {
175         score += segmentScore;
176     }
177     return score;
178 }
179 
IsSameLanguage(const std::string & langTag1,const std::string & langTag2)180 bool LocaleCompare::IsSameLanguage(const std::string& langTag1, const std::string& langTag2)
181 {
182     if (langTag1.compare(langTag2) == 0) {
183         return true;
184     }
185     if (langTag1.compare("tl") == 0 && langTag2.compare("fil") == 0) {
186         return true;
187     }
188     if (langTag1.compare("fil") == 0 && langTag2.compare("tl") == 0) {
189         return true;
190     }
191     return false;
192 }
193 
IsSameEnglishScript(const std::string & scriptTag1,const std::string & scriptTag2)194 bool LocaleCompare::IsSameEnglishScript(const std::string& scriptTag1, const std::string& scriptTag2)
195 {
196     if (scriptTag1.compare("Qaag") == 0 && scriptTag2.compare("Latn") == 0) {
197         return true;
198     }
199     if (scriptTag1.compare("Latn") == 0 && scriptTag2.compare("Qaag") == 0) {
200         return true;
201     }
202     return false;
203 }
204 
HasMapRelation(const std::string & languageTag,const std::string & localeTag1,const std::string & localeTag2)205 bool LocaleCompare::HasMapRelation(const std::string& languageTag, const std::string& localeTag1,
206         const std::string& localeTag2)
207 {
208     if (scriptLocales.find(languageTag) == scriptLocales.end()) {
209         return false;
210     }
211     if (hantParent.find(localeTag1) != hantParent.end()) {
212         if (localeTag2.compare(hantParent[localeTag1]) == 0) {
213             return true;
214         }
215     }
216     if (latnParent.find(localeTag1) != latnParent.end()) {
217         if (localeTag2.compare(latnParent[localeTag1]) == 0) {
218             return true;
219         }
220     }
221     if (extendedHantParent.size() == 0) {
222         for (auto it = hantParent.begin(); it != hantParent.end(); ++it) {
223             std::string key = it->first;
224             size_t languageLength = key.find("-");
225             std::string language = key.substr(0, languageLength);
226             std::string region = key.substr(languageLength + 1);
227             extendedHantParent[language + hantSegment + region] = it->second;
228         }
229     }
230     if (extendedHantParent.find(localeTag1) != extendedHantParent.end()) {
231         if (localeTag2.compare(extendedHantParent[localeTag1]) == 0) {
232             return true;
233         }
234     }
235     if (extendedLatnParent.size() == 0) {
236         for (auto it = latnParent.begin(); it != latnParent.end(); ++it) {
237             std::string key = it->first;
238             size_t languageLength = key.find("-");
239             std::string language = key.substr(0, languageLength);
240             std::string region = key.substr(languageLength + 1);
241             extendedLatnParent[language + latnSegment + region] = it->second;
242             if (language.compare("en") == 0) {
243                 extendedLatnParent[language + qaagSegment + region] = it->second;
244             }
245         }
246     }
247     if (extendedLatnParent.find(localeTag1) != extendedLatnParent.end()) {
248         if (localeTag2.compare(extendedLatnParent[localeTag1]) == 0) {
249             return true;
250         }
251     }
252     return false;
253 }
254 } // namespace I18n
255 } // namespace Global
256 } // OHOS
257