1 /*
2 * Copyright (c) 2024 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 "locale_data.h"
17 #include "locale_matcher.h"
18 #include "locale_util.h"
19
20 namespace OHOS {
21 namespace Global {
22 namespace I18n {
23 uint64_t LocaleMatcher::EN_GB_ENCODE = LocaleUtil::EncodeLocale("en", nullptr, "GB");
24 uint64_t LocaleMatcher::EN_QAAG_ENCODE = LocaleUtil::EncodeLocale("en", "Qaag", nullptr);
25 uint64_t LocaleMatcher::ZH_HANT_MO_ENCODE = LocaleUtil::EncodeLocale("zh", "Hant", "MO");
26 uint64_t LocaleMatcher::ZH_HK_ENCODE = LocaleUtil::EncodeLocale("zh", nullptr, "HK");
27 uint32_t LocaleMatcher::HANT_ENCODE = LocaleUtil::EncodeScript("Hant");
28
GetBestMatchedLocale(const LocaleInfo * requestLocale,const std::vector<LocaleInfo * > & candidateLocales)29 std::string LocaleMatcher::GetBestMatchedLocale(const LocaleInfo* requestLocale,
30 const std::vector<LocaleInfo*>& candidateLocales)
31 {
32 if (candidateLocales.size() == 0) {
33 return "";
34 }
35 LocaleInfo* bestMatch = candidateLocales[0];
36 for (size_t i = 1; i < candidateLocales.size(); ++i) {
37 if (IsMoreSuitable(bestMatch, candidateLocales[i], requestLocale) < 0) {
38 bestMatch = candidateLocales[i];
39 }
40 }
41 return bestMatch->ToString();
42 }
43
IsMoreSuitable(const LocaleInfo * current,const LocaleInfo * other,const LocaleInfo * request)44 int8_t LocaleMatcher::IsMoreSuitable(const LocaleInfo *current, const LocaleInfo *other, const LocaleInfo *request)
45 {
46 if (request == nullptr) {
47 // if request ResLocale is nullptr, the candidate is also nullptr will be more suitable
48 if (current != nullptr && other == nullptr) {
49 // -1 means other is more suitable
50 return -1;
51 }
52 if (current == nullptr && other != nullptr) {
53 // 1 means current is more suitable
54 return 1;
55 }
56 return 0;
57 }
58 if (current == nullptr && other == nullptr) {
59 return 0;
60 }
61 bool isLangEqual = CompareLanguage(current, other);
62 if (!isLangEqual) {
63 // current or other language is null, not null language is better
64 bool result = CompareRegionWhenLangIsNotEqual(current, other, request);
65 return result ? 1 : -1;
66 }
67 uint16_t currentEncodedRegion =
68 LocaleUtil::EncodeRegionByLocaleInfo(current);
69 uint16_t otherEncodedRegion =
70 LocaleUtil::EncodeRegionByLocaleInfo(other);
71 if (currentEncodedRegion == otherEncodedRegion) {
72 // same language,same script,same region
73 return CompareLanguageIgnoreOldNewCode(current, other, request);
74 }
75 // equal request region is better
76 uint16_t requestEncodedRegion = LocaleUtil::EncodeRegionByLocaleInfo(request);
77 if (currentEncodedRegion == requestEncodedRegion) {
78 return 1;
79 }
80 if (otherEncodedRegion == requestEncodedRegion) {
81 return -1;
82 }
83 int8_t isRegionEqual = CompareRegion(current, other, request);
84 if (isRegionEqual == 0) {
85 return CompareLanguageIgnoreOldNewCode(current, other, request);
86 }
87 return isRegionEqual;
88 }
89
CompareLanguage(const LocaleInfo * current,const LocaleInfo * other)90 bool LocaleMatcher::CompareLanguage(const LocaleInfo *current, const LocaleInfo *other)
91 {
92 uint16_t currentEncodedLanguage = LocaleUtil::EncodeLanguageByLocaleInfo(current);
93 uint16_t otherEncodedLanguage = LocaleUtil::EncodeLanguageByLocaleInfo(other);
94 // 1, 2, 3, 4 is the index.
95 return ((currentEncodedLanguage == otherEncodedLanguage) ||
96 ((currentEncodedLanguage == LocaleData::NEW_LANGUAGES_CODES[0]) &&
97 (otherEncodedLanguage == LocaleData::OLD_LANGUAGES_CODES[0])) ||
98 ((otherEncodedLanguage == LocaleData::NEW_LANGUAGES_CODES[0]) &&
99 (currentEncodedLanguage == LocaleData::OLD_LANGUAGES_CODES[0])) ||
100 ((currentEncodedLanguage == LocaleData::NEW_LANGUAGES_CODES[1]) &&
101 (otherEncodedLanguage == LocaleData::OLD_LANGUAGES_CODES[1])) ||
102 ((otherEncodedLanguage == LocaleData::NEW_LANGUAGES_CODES[1]) &&
103 (currentEncodedLanguage == LocaleData::OLD_LANGUAGES_CODES[1])) ||
104 ((currentEncodedLanguage == LocaleData::NEW_LANGUAGES_CODES[2]) && // 2 is index
105 (otherEncodedLanguage == LocaleData::OLD_LANGUAGES_CODES[2])) || // 2 is index
106 ((otherEncodedLanguage == LocaleData::NEW_LANGUAGES_CODES[2]) && // 2 is index
107 (currentEncodedLanguage == LocaleData::OLD_LANGUAGES_CODES[2])) || // 2 is index
108 ((currentEncodedLanguage == LocaleData::NEW_LANGUAGES_CODES[3]) && // 3 is index
109 (otherEncodedLanguage == LocaleData::OLD_LANGUAGES_CODES[3])) || // 3 is index
110 ((otherEncodedLanguage == LocaleData::NEW_LANGUAGES_CODES[3]) && // 3 is index
111 (currentEncodedLanguage == LocaleData::OLD_LANGUAGES_CODES[3])) || // 3 is index
112 ((currentEncodedLanguage == LocaleData::NEW_LANGUAGES_CODES[4]) && // 4 is index
113 (otherEncodedLanguage == LocaleData::OLD_LANGUAGES_CODES[4])) || // 4 is index
114 ((otherEncodedLanguage == LocaleData::NEW_LANGUAGES_CODES[4]) && // 4 is index
115 (currentEncodedLanguage == LocaleData::OLD_LANGUAGES_CODES[4]))); // 4 is index
116 }
117
CompareRegionWhenLangIsNotEqual(const LocaleInfo * current,const LocaleInfo * other,const LocaleInfo * request)118 bool LocaleMatcher::CompareRegionWhenLangIsNotEqual(const LocaleInfo *current, const LocaleInfo *other,
119 const LocaleInfo *request)
120 {
121 int8_t qaagResult = CompareRegionWhenQaag(current, other, request);
122 if (qaagResult != 0) {
123 return qaagResult;
124 }
125 if (request != nullptr &&
126 (LocaleUtil::EncodeLanguage(request->GetLanguage().c_str())) == LocaleUtil::EncodeLanguage("en")) {
127 // when request is en-us,empty region is better
128 if ((LocaleUtil::EncodeRegion(request->GetRegion().c_str())) == LocaleUtil::EncodeRegion("US")) {
129 if (current != nullptr) {
130 return (current->GetRegion().length() == 0) ||
131 ((LocaleUtil::EncodeRegion(current->GetRegion().c_str())) == LocaleUtil::EncodeRegion("US"));
132 } else {
133 return !(other->GetRegion().length() == 0 ||
134 ((LocaleUtil::EncodeRegion(other->GetRegion().c_str())) == LocaleUtil::EncodeRegion("US")));
135 }
136 } else if (IsSimilarToUsEnglish(request)) {
137 if (current != nullptr) {
138 return IsSimilarToUsEnglish(current);
139 } else {
140 return !IsSimilarToUsEnglish(other);
141 }
142 }
143 }
144 return current != nullptr;
145 }
146
CompareRegionWhenQaag(const LocaleInfo * current,const LocaleInfo * other,const LocaleInfo * request)147 int8_t LocaleMatcher::CompareRegionWhenQaag(const LocaleInfo *current, const LocaleInfo *other,
148 const LocaleInfo *request)
149 {
150 if ((request != nullptr) && (LocaleUtil::EncodeLocale(request->GetLanguage().c_str(), request->GetScript().c_str(),
151 nullptr) == LocaleMatcher::EN_QAAG_ENCODE)) {
152 if ((current != nullptr) && (LocaleUtil::EncodeLocale(current->GetLanguage().c_str(), nullptr,
153 current->GetRegion().c_str()) == LocaleMatcher::EN_GB_ENCODE)) {
154 return 1;
155 }
156 if ((other != nullptr) && (LocaleUtil::EncodeLocale(other->GetLanguage().c_str(), nullptr,
157 other->GetRegion().c_str()) == LocaleMatcher::EN_GB_ENCODE)) {
158 return -1;
159 }
160 }
161 return 0;
162 }
163
IsSimilarToUsEnglish(const LocaleInfo * localeInfo)164 bool LocaleMatcher::IsSimilarToUsEnglish(const LocaleInfo *localeInfo)
165 {
166 uint64_t localeEncode = LocaleUtil::EncodeLocale("en", nullptr,
167 (localeInfo == nullptr) ? nullptr : localeInfo->GetRegion().c_str());
168 uint64_t loclaeEncodedTrackPath[LocaleMatcher::TRACKPATH_ARRAY_SIZE] = {0, 0, 0, 0, 0};
169 FindTrackPath(nullptr, LocaleMatcher::TRACKPATH_ARRAY_SIZE, localeEncode, loclaeEncodedTrackPath);
170 uint8_t len = LocaleMatcher::TRACKPATH_ARRAY_SIZE;
171 for (uint8_t i = 0; i < len; ++i) {
172 if (loclaeEncodedTrackPath[i] == LocaleUtil::EncodeLocale("en", nullptr, nullptr)) {
173 return true;
174 }
175 if (loclaeEncodedTrackPath[i] == LocaleUtil::EncodeLocale("en", nullptr, "001")) {
176 return false;
177 }
178 }
179 return false;
180 }
181
FindTrackPath(const LocaleInfo * request,size_t len,uint64_t encodedLocale,uint64_t * result)182 void LocaleMatcher::FindTrackPath(const LocaleInfo *request, size_t len, uint64_t encodedLocale, uint64_t *result)
183 {
184 uint64_t currentEncodedLocale = encodedLocale;
185 size_t i = 0;
186 do {
187 result[i] = currentEncodedLocale;
188 currentEncodedLocale = SearchParentLocale(currentEncodedLocale, request);
189 ++i;
190 } while (currentEncodedLocale != LocaleMatcher::ROOT_LOCALE);
191 if (i < len) {
192 result[i] = LocaleMatcher::ROOT_LOCALE;
193 }
194 }
195
SearchParentLocale(uint64_t encodedLocale,const LocaleInfo * request)196 uint64_t LocaleMatcher::SearchParentLocale(uint64_t encodedLocale, const LocaleInfo *request)
197 {
198 uint64_t tempEncodedLocale = encodedLocale;
199 if (LocaleUtil::EncodeScriptByLocaleInfo(request) == LocaleMatcher::HANT_ENCODE) {
200 tempEncodedLocale = AddScript(encodedLocale, LocaleMatcher::HANT_ENCODE);
201 if (tempEncodedLocale == LocaleMatcher::ZH_HANT_MO_ENCODE) {
202 return LocaleMatcher::ZH_HK_ENCODE;
203 }
204 }
205 if (IsContainRegion(encodedLocale)) {
206 for (size_t i = 0; i < LocaleData::LOCALE_PARENTS_KEY.size(); i++) {
207 if (LocaleData::LOCALE_PARENTS_KEY[i] == tempEncodedLocale) {
208 return LocaleData::LOCALE_PARENTS_VALUE[i];
209 }
210 }
211 return ClearRegion(encodedLocale);
212 }
213 return LocaleMatcher::ROOT_LOCALE;
214 }
215
AddScript(uint64_t encodedLocale,uint32_t encodedScript)216 uint64_t LocaleMatcher::AddScript(uint64_t encodedLocale, uint32_t encodedScript)
217 {
218 // 16 is the offset of script
219 return (encodedLocale | ((static_cast<uint64_t>(encodedScript) & 0x00000000FFFFFFFFLU) << 16));
220 }
221
IsContainRegion(uint64_t encodedLocale)222 bool LocaleMatcher::IsContainRegion(uint64_t encodedLocale)
223 {
224 return (encodedLocale & 0x000000000000FFFFLU) != 0;
225 }
226
ClearRegion(uint64_t encodedLocale)227 uint64_t LocaleMatcher::ClearRegion(uint64_t encodedLocale)
228 {
229 return encodedLocale & 0xFFFFFFFFFFFF0000LU;
230 }
231
CompareRegion(const LocaleInfo * current,const LocaleInfo * other,const LocaleInfo * request)232 int8_t LocaleMatcher::CompareRegion(const LocaleInfo *current, const LocaleInfo *other, const LocaleInfo *request)
233 {
234 uint16_t currentEncodedRegion = LocaleUtil::EncodeRegionByLocaleInfo(current);
235 uint16_t otherEncodedRegion = LocaleUtil::EncodeRegionByLocaleInfo(other);
236 if (request == nullptr || request->GetRegion().size() == 0) {
237 return CompareWhenRegionIsNull(currentEncodedRegion, otherEncodedRegion, current, other, request);
238 }
239 uint64_t requestEncodedLocale = LocaleUtil::EncodeLocale(request->GetLanguage().c_str(), nullptr,
240 request->GetRegion().c_str());
241 uint64_t requestEncodedTrackPath[LocaleMatcher::TRACKPATH_ARRAY_SIZE] = {0, 0, 0, 0, 0};
242 FindTrackPath(request, LocaleMatcher::TRACKPATH_ARRAY_SIZE, requestEncodedLocale, requestEncodedTrackPath);
243 uint64_t currentEncodedLocale = LocaleUtil::EncodeLocale(request->GetLanguage().c_str(), nullptr,
244 (current == nullptr) ? nullptr : current->GetRegion().c_str());
245 uint64_t otherEncodedLocale = LocaleUtil::EncodeLocale(request->GetLanguage().c_str(), nullptr,
246 (other == nullptr) ? nullptr : other->GetRegion().c_str());
247 int8_t currentMatchDistance = SearchTrackPathDistance(requestEncodedTrackPath, LocaleMatcher::TRACKPATH_ARRAY_SIZE,
248 currentEncodedLocale);
249 int8_t otherMatchDistance = SearchTrackPathDistance(requestEncodedTrackPath, LocaleMatcher::TRACKPATH_ARRAY_SIZE,
250 otherEncodedLocale);
251 if (currentMatchDistance < otherMatchDistance) {
252 return 1;
253 }
254 if (currentMatchDistance > otherMatchDistance) {
255 return -1;
256 }
257 int8_t result = CompareDistance(currentEncodedLocale, otherEncodedLocale, requestEncodedTrackPath, request);
258 if (result != 0) {
259 return result;
260 }
261 result = CompareDefaultRegion(current, other, request);
262 if (result != 0) {
263 return result;
264 }
265 uint16_t requestDefaultRegion =
266 FindDefaultRegionEncode(request->GetLanguage().c_str(), request->GetScript().c_str());
267 if (requestDefaultRegion == currentEncodedRegion) {
268 return 1;
269 }
270 if (requestDefaultRegion == otherEncodedRegion) {
271 return -1;
272 }
273 return AlphabeticallyCompare(current, currentEncodedLocale, other, otherEncodedLocale);
274 }
275
CompareWhenRegionIsNull(uint16_t currentEncodedRegion,uint16_t otherEncodedRegion,const LocaleInfo * current,const LocaleInfo * other,const LocaleInfo * request)276 int8_t LocaleMatcher::CompareWhenRegionIsNull(uint16_t currentEncodedRegion, uint16_t otherEncodedRegion,
277 const LocaleInfo *current, const LocaleInfo *other, const LocaleInfo *request)
278 {
279 if (current == nullptr || current->GetRegion().length() == 0) {
280 return 1;
281 }
282 if (other == nullptr || other->GetRegion().length() == 0) {
283 return -1;
284 }
285 int8_t qaagResult = CompareRegionWhenQaag(current, other, request);
286 if (qaagResult != 0) {
287 return qaagResult;
288 }
289 // get request default region
290 uint16_t requestDefaultRegion =
291 FindDefaultRegionEncode((request == nullptr) ? nullptr : request->GetLanguage().c_str(),
292 (request == nullptr) ? nullptr : request->GetScript().c_str());
293 if (requestDefaultRegion == currentEncodedRegion) {
294 return 1;
295 }
296 if (requestDefaultRegion == otherEncodedRegion) {
297 return -1;
298 }
299 // current and other region is not null.alphabetically
300 uint64_t currentEncodedLocale = LocaleUtil::EncodeLocale(
301 (request == nullptr) ? nullptr : request->GetLanguage().c_str(), nullptr,
302 (current == nullptr) ? nullptr : current->GetRegion().c_str());
303 uint64_t otherEncodedLocale = LocaleUtil::EncodeLocale(
304 (request == nullptr) ? nullptr : request->GetLanguage().c_str(), nullptr, other->GetRegion().c_str());
305 return AlphabeticallyCompare(current, currentEncodedLocale, other, otherEncodedLocale);
306 }
307
FindDefaultRegionEncode(const char * language,const char * script)308 uint16_t LocaleMatcher::FindDefaultRegionEncode(const char *language, const char *script)
309 {
310 /* first try language and script */
311 uint64_t encodedLocale = LocaleUtil::EncodeLocale(language, script, nullptr);
312 if (encodedLocale == LocaleUtil::EncodeLocale("en", "Qaag", nullptr)) {
313 encodedLocale = LocaleUtil::EncodeLocale("en", "Latn", nullptr);
314 }
315 for (size_t i = 0; i < LocaleData::LIKELY_TAGS_CODES_KEY.size(); i++) {
316 if (LocaleData::LIKELY_TAGS_CODES_KEY[i] == encodedLocale) {
317 return static_cast<uint16_t>((LocaleData::LIKELY_TAGS_CODES_VALUE[i] & 0x000000000000ffff));
318 }
319 }
320 /* if not found and script is not null,try language */
321 if (script != nullptr) {
322 encodedLocale = LocaleUtil::EncodeLocale(language, nullptr, nullptr);
323 for (size_t i = 0; i < LocaleData::LIKELY_TAGS_CODES_KEY.size(); i++) {
324 if (LocaleData::LIKELY_TAGS_CODES_KEY[i] == encodedLocale) {
325 return static_cast<uint16_t>((LocaleData::LIKELY_TAGS_CODES_VALUE[i] & 0x000000000000ffff));
326 }
327 }
328 }
329 return LocaleMatcher::NULL_REGION;
330 }
331
AlphabeticallyCompare(const LocaleInfo * current,uint64_t currentEncodedLocale,const LocaleInfo * other,uint64_t otherEncodedLocale)332 int8_t LocaleMatcher::AlphabeticallyCompare(const LocaleInfo *current, uint64_t currentEncodedLocale,
333 const LocaleInfo *other, uint64_t otherEncodedLocale)
334 {
335 if (currentEncodedLocale == otherEncodedLocale) {
336 return 0;
337 }
338 if (current == nullptr || current->GetRegion().length() == 0) {
339 return -1;
340 }
341 if (other == nullptr || other->GetRegion().length() == 0) {
342 return 1;
343 }
344 // be here region is not null
345 char currentFirstChar = (current->GetRegion())[0];
346 char otherFirstChar = (other->GetRegion())[0];
347 if (currentFirstChar >= '0' && currentFirstChar <= '9') {
348 if (otherFirstChar < '0' || otherFirstChar > '9') {
349 return -1;
350 }
351 } else {
352 if (otherFirstChar >= '0' && otherFirstChar <= '9') {
353 return 1;
354 }
355 }
356 if (currentEncodedLocale > otherEncodedLocale) {
357 return -1;
358 }
359 if (otherEncodedLocale > currentEncodedLocale) {
360 return 1;
361 }
362 return 0;
363 }
364
SearchTrackPathDistance(const uint64_t * paths,size_t len,uint64_t encodedLocale)365 int8_t LocaleMatcher::SearchTrackPathDistance(const uint64_t *paths, size_t len, uint64_t encodedLocale)
366 {
367 size_t i = 0;
368 for (i = 0; i < len; ++i) {
369 if (paths[i] == LocaleMatcher::ROOT_LOCALE) {
370 return i;
371 }
372 if (paths[i] == encodedLocale) {
373 return i;
374 }
375 }
376 return static_cast<int8_t>(i);
377 }
378
CompareDistance(uint64_t currentEncodedLocale,uint64_t otherEncodedLocale,const uint64_t * requestEncodedTrackPath,const LocaleInfo * request)379 int8_t LocaleMatcher::CompareDistance(uint64_t currentEncodedLocale, uint64_t otherEncodedLocale,
380 const uint64_t *requestEncodedTrackPath, const LocaleInfo *request)
381 {
382 uint64_t currentEncodedTrackPath[LocaleMatcher::TRACKPATH_ARRAY_SIZE] = {0, 0, 0, 0, 0};
383 FindTrackPath(request, LocaleMatcher::TRACKPATH_ARRAY_SIZE, currentEncodedLocale, currentEncodedTrackPath);
384 uint64_t otherEncodedTrackPath[LocaleMatcher::TRACKPATH_ARRAY_SIZE] = {0, 0, 0, 0, 0};
385 FindTrackPath(request, LocaleMatcher::TRACKPATH_ARRAY_SIZE, otherEncodedLocale, otherEncodedTrackPath);
386 const size_t currentDistance = ComputeTrackPathDistance(requestEncodedTrackPath, currentEncodedTrackPath,
387 LocaleMatcher::TRACKPATH_ARRAY_SIZE);
388 const size_t targetDistance = ComputeTrackPathDistance(requestEncodedTrackPath, otherEncodedTrackPath,
389 LocaleMatcher::TRACKPATH_ARRAY_SIZE);
390 if (currentDistance < targetDistance) {
391 return 1;
392 }
393 if (currentDistance > targetDistance) {
394 return -1;
395 }
396 return 0;
397 }
398
ComputeTrackPathDistance(const uint64_t * requestPaths,const uint64_t * targetPaths,size_t len)399 size_t LocaleMatcher::ComputeTrackPathDistance(const uint64_t *requestPaths, const uint64_t *targetPaths, size_t len)
400 {
401 for (size_t i = 0; i < len; ++i) {
402 if (targetPaths[i] == LocaleMatcher::ROOT_LOCALE) {
403 // targetpath not in request path,so distance is 2*len
404 return len * 2;
405 }
406 for (size_t j = 0; j < len; ++j) {
407 if (requestPaths[j] == targetPaths[i]) {
408 return i + j;
409 }
410 }
411 }
412 return len * 2; // targetpath not in request path,so distance is 2*len
413 }
414
CompareDefaultRegion(const LocaleInfo * current,const LocaleInfo * other,const LocaleInfo * request)415 int8_t LocaleMatcher::CompareDefaultRegion(const LocaleInfo *current, const LocaleInfo *other,
416 const LocaleInfo *request)
417 {
418 int8_t qaagResult = CompareRegionWhenQaag(current, other, request);
419 if (qaagResult != 0) {
420 return qaagResult;
421 } else {
422 bool isCurrentDefaultRegion = IsDefaultLocale((request == nullptr) ? nullptr : request->GetLanguage().c_str(),
423 (request == nullptr) ? nullptr : request->GetScript().c_str(),
424 (current == nullptr) ? nullptr : current->GetRegion().c_str());
425 bool isOtherDefaultRegion = IsDefaultLocale((request == nullptr) ? nullptr : request->GetLanguage().c_str(),
426 (request == nullptr) ? nullptr : request->GetScript().c_str(),
427 (other == nullptr) ? nullptr : other->GetRegion().c_str());
428 if (isCurrentDefaultRegion != isOtherDefaultRegion) {
429 if (isCurrentDefaultRegion) {
430 return 1;
431 } else {
432 return -1;
433 }
434 }
435 }
436 return 0;
437 }
438
IsDefaultLocale(const char * language,const char * script,const char * region)439 bool LocaleMatcher::IsDefaultLocale(const char *language, const char *script, const char *region)
440 {
441 uint64_t encodedLocale = LocaleUtil::EncodeLocale(language, script, region);
442 if (ClearRegion(encodedLocale) == LocaleMatcher::EN_QAAG_ENCODE) {
443 encodedLocale = LocaleUtil::EncodeLocale("en", "Latn", region);
444 }
445 for (size_t i = 0; i < LocaleData::TYPICAL_CODES_VALUE.size(); i++) {
446 if (LocaleData::TYPICAL_CODES_VALUE[i] == encodedLocale) {
447 return true;
448 }
449 }
450 return false;
451 }
452
CompareLanguageIgnoreOldNewCode(const LocaleInfo * current,const LocaleInfo * other,const LocaleInfo * request)453 int8_t LocaleMatcher::CompareLanguageIgnoreOldNewCode(const LocaleInfo *current, const LocaleInfo *other,
454 const LocaleInfo *request)
455 {
456 uint16_t currentLanguageEncode = LocaleUtil::EncodeLanguageByLocaleInfo(current);
457 uint16_t otherLanguageEncode = LocaleUtil::EncodeLanguageByLocaleInfo(other);
458 uint16_t requestLanguageEncode = LocaleUtil::EncodeLanguageByLocaleInfo(request);
459 if ((currentLanguageEncode == requestLanguageEncode) && (otherLanguageEncode != requestLanguageEncode)) {
460 return 1;
461 }
462 if ((otherLanguageEncode == requestLanguageEncode) && (currentLanguageEncode != requestLanguageEncode)) {
463 return -1;
464 }
465 return 0;
466 }
467
Match(const LocaleInfo * current,const LocaleInfo * other)468 bool LocaleMatcher::Match(const LocaleInfo *current, const LocaleInfo *other)
469 {
470 if (current == nullptr || other == nullptr) {
471 return true;
472 }
473 // language is not null.
474 bool isLanguageEqual = CompareLanguage(current, other);
475 if (!isLanguageEqual) {
476 return false;
477 }
478 return CompareScript(current, other);
479 }
480
CompareScript(const LocaleInfo * current,const LocaleInfo * other)481 bool LocaleMatcher::CompareScript(const LocaleInfo *current, const LocaleInfo *other)
482 {
483 uint32_t currentEncodedScript = 0;
484 uint32_t otherEncodedScript = 0;
485 if ((current != nullptr) && (current->GetScript().length() == 0)) {
486 currentEncodedScript = FindDefaultScriptEncode(current->GetLanguage().c_str(), current->GetRegion().c_str());
487 } else {
488 currentEncodedScript = LocaleUtil::EncodeScriptByLocaleInfo(current);
489 }
490 if ((other != nullptr) && (other->GetScript().length() == 0)) {
491 otherEncodedScript = FindDefaultScriptEncode(other->GetLanguage().c_str(), other->GetRegion().c_str());
492 } else {
493 otherEncodedScript = LocaleUtil::EncodeScriptByLocaleInfo(other);
494 }
495 if (current != nullptr && other != nullptr) {
496 // when current locale is en-Qaag is equal en-Latn
497 if (LocaleUtil::EncodeLocale(current->GetLanguage().c_str(), current->GetScript().c_str(), nullptr) ==
498 LocaleUtil::EncodeLocale("en", "Qaag", nullptr)) {
499 if (LocaleUtil::EncodeLocale(other->GetLanguage().c_str(), other->GetScript().c_str(), nullptr) ==
500 LocaleUtil::EncodeLocale("en", "Latn", nullptr)) {
501 return true;
502 }
503 }
504 }
505 bool compareRegion = false;
506 if ((currentEncodedScript == LocaleMatcher::NULL_SCRIPT) || (otherEncodedScript == LocaleMatcher::NULL_SCRIPT)) {
507 // if request script is null, region must be same
508 compareRegion = true;
509 }
510 if (compareRegion) {
511 uint16_t currentRegionEncode = LocaleUtil::EncodeRegionByLocaleInfo(current);
512 uint16_t otherRegionEncode = LocaleUtil::EncodeRegionByLocaleInfo(other);
513 return (otherRegionEncode == LocaleMatcher::NULL_REGION) || (currentRegionEncode == otherRegionEncode);
514 }
515 return currentEncodedScript == otherEncodedScript;
516 }
517
FindDefaultScriptEncode(const char * language,const char * region)518 uint32_t LocaleMatcher::FindDefaultScriptEncode(const char *language, const char *region)
519 {
520 uint64_t encodedLocale = LocaleUtil::EncodeLocale(language, nullptr, region);
521 for (size_t i = 0; i < LocaleData::LIKELY_TAGS_CODES_KEY.size(); i++) {
522 if (LocaleData::LIKELY_TAGS_CODES_KEY[i] == encodedLocale) {
523 // 16 is the offset of script
524 return static_cast<uint32_t>((LocaleData::LIKELY_TAGS_CODES_VALUE[i] & 0x0000ffffffff0000) >> 16);
525 }
526 }
527 if (region != nullptr) {
528 encodedLocale = LocaleUtil::EncodeLocale(language, nullptr, nullptr);
529 for (size_t i = 0; i < LocaleData::LIKELY_TAGS_CODES_KEY.size(); i++) {
530 if (LocaleData::LIKELY_TAGS_CODES_KEY[i] == encodedLocale) {
531 // 16 is the offset of script
532 return static_cast<uint32_t>((LocaleData::LIKELY_TAGS_CODES_VALUE[i] & 0x0000ffffffff0000) >> 16);
533 }
534 }
535 }
536 return LocaleMatcher::NULL_SCRIPT;
537 }
538 } // namespace I18n
539 } // namespace Global
540 } // namespace OHOS