19596a2c1Sopenharmony_ci/* 29596a2c1Sopenharmony_ci * Copyright (c) 2024 Huawei Device Co., Ltd. 39596a2c1Sopenharmony_ci * Licensed under the Apache License, Version 2.0 (the "License"); 49596a2c1Sopenharmony_ci * you may not use this file except in compliance with the License. 59596a2c1Sopenharmony_ci * You may obtain a copy of the License at 69596a2c1Sopenharmony_ci * 79596a2c1Sopenharmony_ci * http://www.apache.org/licenses/LICENSE-2.0 89596a2c1Sopenharmony_ci * 99596a2c1Sopenharmony_ci * Unless required by applicable law or agreed to in writing, software 109596a2c1Sopenharmony_ci * distributed under the License is distributed on an "AS IS" BASIS, 119596a2c1Sopenharmony_ci * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 129596a2c1Sopenharmony_ci * See the License for the specific language governing permissions and 139596a2c1Sopenharmony_ci * limitations under the License. 149596a2c1Sopenharmony_ci */ 159596a2c1Sopenharmony_ci 169596a2c1Sopenharmony_ci#include "locale_data.h" 179596a2c1Sopenharmony_ci#include "locale_matcher.h" 189596a2c1Sopenharmony_ci#include "locale_util.h" 199596a2c1Sopenharmony_ci 209596a2c1Sopenharmony_cinamespace OHOS { 219596a2c1Sopenharmony_cinamespace Global { 229596a2c1Sopenharmony_cinamespace I18n { 239596a2c1Sopenharmony_ciuint64_t LocaleMatcher::EN_GB_ENCODE = LocaleUtil::EncodeLocale("en", nullptr, "GB"); 249596a2c1Sopenharmony_ciuint64_t LocaleMatcher::EN_QAAG_ENCODE = LocaleUtil::EncodeLocale("en", "Qaag", nullptr); 259596a2c1Sopenharmony_ciuint64_t LocaleMatcher::ZH_HANT_MO_ENCODE = LocaleUtil::EncodeLocale("zh", "Hant", "MO"); 269596a2c1Sopenharmony_ciuint64_t LocaleMatcher::ZH_HK_ENCODE = LocaleUtil::EncodeLocale("zh", nullptr, "HK"); 279596a2c1Sopenharmony_ciuint32_t LocaleMatcher::HANT_ENCODE = LocaleUtil::EncodeScript("Hant"); 289596a2c1Sopenharmony_ci 299596a2c1Sopenharmony_cistd::string LocaleMatcher::GetBestMatchedLocale(const LocaleInfo* requestLocale, 309596a2c1Sopenharmony_ci const std::vector<LocaleInfo*>& candidateLocales) 319596a2c1Sopenharmony_ci{ 329596a2c1Sopenharmony_ci if (candidateLocales.size() == 0) { 339596a2c1Sopenharmony_ci return ""; 349596a2c1Sopenharmony_ci } 359596a2c1Sopenharmony_ci LocaleInfo* bestMatch = candidateLocales[0]; 369596a2c1Sopenharmony_ci for (size_t i = 1; i < candidateLocales.size(); ++i) { 379596a2c1Sopenharmony_ci if (IsMoreSuitable(bestMatch, candidateLocales[i], requestLocale) < 0) { 389596a2c1Sopenharmony_ci bestMatch = candidateLocales[i]; 399596a2c1Sopenharmony_ci } 409596a2c1Sopenharmony_ci } 419596a2c1Sopenharmony_ci return bestMatch->ToString(); 429596a2c1Sopenharmony_ci} 439596a2c1Sopenharmony_ci 449596a2c1Sopenharmony_ciint8_t LocaleMatcher::IsMoreSuitable(const LocaleInfo *current, const LocaleInfo *other, const LocaleInfo *request) 459596a2c1Sopenharmony_ci{ 469596a2c1Sopenharmony_ci if (request == nullptr) { 479596a2c1Sopenharmony_ci // if request ResLocale is nullptr, the candidate is also nullptr will be more suitable 489596a2c1Sopenharmony_ci if (current != nullptr && other == nullptr) { 499596a2c1Sopenharmony_ci // -1 means other is more suitable 509596a2c1Sopenharmony_ci return -1; 519596a2c1Sopenharmony_ci } 529596a2c1Sopenharmony_ci if (current == nullptr && other != nullptr) { 539596a2c1Sopenharmony_ci // 1 means current is more suitable 549596a2c1Sopenharmony_ci return 1; 559596a2c1Sopenharmony_ci } 569596a2c1Sopenharmony_ci return 0; 579596a2c1Sopenharmony_ci } 589596a2c1Sopenharmony_ci if (current == nullptr && other == nullptr) { 599596a2c1Sopenharmony_ci return 0; 609596a2c1Sopenharmony_ci } 619596a2c1Sopenharmony_ci bool isLangEqual = CompareLanguage(current, other); 629596a2c1Sopenharmony_ci if (!isLangEqual) { 639596a2c1Sopenharmony_ci // current or other language is null, not null language is better 649596a2c1Sopenharmony_ci bool result = CompareRegionWhenLangIsNotEqual(current, other, request); 659596a2c1Sopenharmony_ci return result ? 1 : -1; 669596a2c1Sopenharmony_ci } 679596a2c1Sopenharmony_ci uint16_t currentEncodedRegion = 689596a2c1Sopenharmony_ci LocaleUtil::EncodeRegionByLocaleInfo(current); 699596a2c1Sopenharmony_ci uint16_t otherEncodedRegion = 709596a2c1Sopenharmony_ci LocaleUtil::EncodeRegionByLocaleInfo(other); 719596a2c1Sopenharmony_ci if (currentEncodedRegion == otherEncodedRegion) { 729596a2c1Sopenharmony_ci // same language,same script,same region 739596a2c1Sopenharmony_ci return CompareLanguageIgnoreOldNewCode(current, other, request); 749596a2c1Sopenharmony_ci } 759596a2c1Sopenharmony_ci // equal request region is better 769596a2c1Sopenharmony_ci uint16_t requestEncodedRegion = LocaleUtil::EncodeRegionByLocaleInfo(request); 779596a2c1Sopenharmony_ci if (currentEncodedRegion == requestEncodedRegion) { 789596a2c1Sopenharmony_ci return 1; 799596a2c1Sopenharmony_ci } 809596a2c1Sopenharmony_ci if (otherEncodedRegion == requestEncodedRegion) { 819596a2c1Sopenharmony_ci return -1; 829596a2c1Sopenharmony_ci } 839596a2c1Sopenharmony_ci int8_t isRegionEqual = CompareRegion(current, other, request); 849596a2c1Sopenharmony_ci if (isRegionEqual == 0) { 859596a2c1Sopenharmony_ci return CompareLanguageIgnoreOldNewCode(current, other, request); 869596a2c1Sopenharmony_ci } 879596a2c1Sopenharmony_ci return isRegionEqual; 889596a2c1Sopenharmony_ci} 899596a2c1Sopenharmony_ci 909596a2c1Sopenharmony_cibool LocaleMatcher::CompareLanguage(const LocaleInfo *current, const LocaleInfo *other) 919596a2c1Sopenharmony_ci{ 929596a2c1Sopenharmony_ci uint16_t currentEncodedLanguage = LocaleUtil::EncodeLanguageByLocaleInfo(current); 939596a2c1Sopenharmony_ci uint16_t otherEncodedLanguage = LocaleUtil::EncodeLanguageByLocaleInfo(other); 949596a2c1Sopenharmony_ci // 1, 2, 3, 4 is the index. 959596a2c1Sopenharmony_ci return ((currentEncodedLanguage == otherEncodedLanguage) || 969596a2c1Sopenharmony_ci ((currentEncodedLanguage == LocaleData::NEW_LANGUAGES_CODES[0]) && 979596a2c1Sopenharmony_ci (otherEncodedLanguage == LocaleData::OLD_LANGUAGES_CODES[0])) || 989596a2c1Sopenharmony_ci ((otherEncodedLanguage == LocaleData::NEW_LANGUAGES_CODES[0]) && 999596a2c1Sopenharmony_ci (currentEncodedLanguage == LocaleData::OLD_LANGUAGES_CODES[0])) || 1009596a2c1Sopenharmony_ci ((currentEncodedLanguage == LocaleData::NEW_LANGUAGES_CODES[1]) && 1019596a2c1Sopenharmony_ci (otherEncodedLanguage == LocaleData::OLD_LANGUAGES_CODES[1])) || 1029596a2c1Sopenharmony_ci ((otherEncodedLanguage == LocaleData::NEW_LANGUAGES_CODES[1]) && 1039596a2c1Sopenharmony_ci (currentEncodedLanguage == LocaleData::OLD_LANGUAGES_CODES[1])) || 1049596a2c1Sopenharmony_ci ((currentEncodedLanguage == LocaleData::NEW_LANGUAGES_CODES[2]) && // 2 is index 1059596a2c1Sopenharmony_ci (otherEncodedLanguage == LocaleData::OLD_LANGUAGES_CODES[2])) || // 2 is index 1069596a2c1Sopenharmony_ci ((otherEncodedLanguage == LocaleData::NEW_LANGUAGES_CODES[2]) && // 2 is index 1079596a2c1Sopenharmony_ci (currentEncodedLanguage == LocaleData::OLD_LANGUAGES_CODES[2])) || // 2 is index 1089596a2c1Sopenharmony_ci ((currentEncodedLanguage == LocaleData::NEW_LANGUAGES_CODES[3]) && // 3 is index 1099596a2c1Sopenharmony_ci (otherEncodedLanguage == LocaleData::OLD_LANGUAGES_CODES[3])) || // 3 is index 1109596a2c1Sopenharmony_ci ((otherEncodedLanguage == LocaleData::NEW_LANGUAGES_CODES[3]) && // 3 is index 1119596a2c1Sopenharmony_ci (currentEncodedLanguage == LocaleData::OLD_LANGUAGES_CODES[3])) || // 3 is index 1129596a2c1Sopenharmony_ci ((currentEncodedLanguage == LocaleData::NEW_LANGUAGES_CODES[4]) && // 4 is index 1139596a2c1Sopenharmony_ci (otherEncodedLanguage == LocaleData::OLD_LANGUAGES_CODES[4])) || // 4 is index 1149596a2c1Sopenharmony_ci ((otherEncodedLanguage == LocaleData::NEW_LANGUAGES_CODES[4]) && // 4 is index 1159596a2c1Sopenharmony_ci (currentEncodedLanguage == LocaleData::OLD_LANGUAGES_CODES[4]))); // 4 is index 1169596a2c1Sopenharmony_ci} 1179596a2c1Sopenharmony_ci 1189596a2c1Sopenharmony_cibool LocaleMatcher::CompareRegionWhenLangIsNotEqual(const LocaleInfo *current, const LocaleInfo *other, 1199596a2c1Sopenharmony_ci const LocaleInfo *request) 1209596a2c1Sopenharmony_ci{ 1219596a2c1Sopenharmony_ci int8_t qaagResult = CompareRegionWhenQaag(current, other, request); 1229596a2c1Sopenharmony_ci if (qaagResult != 0) { 1239596a2c1Sopenharmony_ci return qaagResult; 1249596a2c1Sopenharmony_ci } 1259596a2c1Sopenharmony_ci if (request != nullptr && 1269596a2c1Sopenharmony_ci (LocaleUtil::EncodeLanguage(request->GetLanguage().c_str())) == LocaleUtil::EncodeLanguage("en")) { 1279596a2c1Sopenharmony_ci // when request is en-us,empty region is better 1289596a2c1Sopenharmony_ci if ((LocaleUtil::EncodeRegion(request->GetRegion().c_str())) == LocaleUtil::EncodeRegion("US")) { 1299596a2c1Sopenharmony_ci if (current != nullptr) { 1309596a2c1Sopenharmony_ci return (current->GetRegion().length() == 0) || 1319596a2c1Sopenharmony_ci ((LocaleUtil::EncodeRegion(current->GetRegion().c_str())) == LocaleUtil::EncodeRegion("US")); 1329596a2c1Sopenharmony_ci } else { 1339596a2c1Sopenharmony_ci return !(other->GetRegion().length() == 0 || 1349596a2c1Sopenharmony_ci ((LocaleUtil::EncodeRegion(other->GetRegion().c_str())) == LocaleUtil::EncodeRegion("US"))); 1359596a2c1Sopenharmony_ci } 1369596a2c1Sopenharmony_ci } else if (IsSimilarToUsEnglish(request)) { 1379596a2c1Sopenharmony_ci if (current != nullptr) { 1389596a2c1Sopenharmony_ci return IsSimilarToUsEnglish(current); 1399596a2c1Sopenharmony_ci } else { 1409596a2c1Sopenharmony_ci return !IsSimilarToUsEnglish(other); 1419596a2c1Sopenharmony_ci } 1429596a2c1Sopenharmony_ci } 1439596a2c1Sopenharmony_ci } 1449596a2c1Sopenharmony_ci return current != nullptr; 1459596a2c1Sopenharmony_ci} 1469596a2c1Sopenharmony_ci 1479596a2c1Sopenharmony_ciint8_t LocaleMatcher::CompareRegionWhenQaag(const LocaleInfo *current, const LocaleInfo *other, 1489596a2c1Sopenharmony_ci const LocaleInfo *request) 1499596a2c1Sopenharmony_ci{ 1509596a2c1Sopenharmony_ci if ((request != nullptr) && (LocaleUtil::EncodeLocale(request->GetLanguage().c_str(), request->GetScript().c_str(), 1519596a2c1Sopenharmony_ci nullptr) == LocaleMatcher::EN_QAAG_ENCODE)) { 1529596a2c1Sopenharmony_ci if ((current != nullptr) && (LocaleUtil::EncodeLocale(current->GetLanguage().c_str(), nullptr, 1539596a2c1Sopenharmony_ci current->GetRegion().c_str()) == LocaleMatcher::EN_GB_ENCODE)) { 1549596a2c1Sopenharmony_ci return 1; 1559596a2c1Sopenharmony_ci } 1569596a2c1Sopenharmony_ci if ((other != nullptr) && (LocaleUtil::EncodeLocale(other->GetLanguage().c_str(), nullptr, 1579596a2c1Sopenharmony_ci other->GetRegion().c_str()) == LocaleMatcher::EN_GB_ENCODE)) { 1589596a2c1Sopenharmony_ci return -1; 1599596a2c1Sopenharmony_ci } 1609596a2c1Sopenharmony_ci } 1619596a2c1Sopenharmony_ci return 0; 1629596a2c1Sopenharmony_ci} 1639596a2c1Sopenharmony_ci 1649596a2c1Sopenharmony_cibool LocaleMatcher::IsSimilarToUsEnglish(const LocaleInfo *localeInfo) 1659596a2c1Sopenharmony_ci{ 1669596a2c1Sopenharmony_ci uint64_t localeEncode = LocaleUtil::EncodeLocale("en", nullptr, 1679596a2c1Sopenharmony_ci (localeInfo == nullptr) ? nullptr : localeInfo->GetRegion().c_str()); 1689596a2c1Sopenharmony_ci uint64_t loclaeEncodedTrackPath[LocaleMatcher::TRACKPATH_ARRAY_SIZE] = {0, 0, 0, 0, 0}; 1699596a2c1Sopenharmony_ci FindTrackPath(nullptr, LocaleMatcher::TRACKPATH_ARRAY_SIZE, localeEncode, loclaeEncodedTrackPath); 1709596a2c1Sopenharmony_ci uint8_t len = LocaleMatcher::TRACKPATH_ARRAY_SIZE; 1719596a2c1Sopenharmony_ci for (uint8_t i = 0; i < len; ++i) { 1729596a2c1Sopenharmony_ci if (loclaeEncodedTrackPath[i] == LocaleUtil::EncodeLocale("en", nullptr, nullptr)) { 1739596a2c1Sopenharmony_ci return true; 1749596a2c1Sopenharmony_ci } 1759596a2c1Sopenharmony_ci if (loclaeEncodedTrackPath[i] == LocaleUtil::EncodeLocale("en", nullptr, "001")) { 1769596a2c1Sopenharmony_ci return false; 1779596a2c1Sopenharmony_ci } 1789596a2c1Sopenharmony_ci } 1799596a2c1Sopenharmony_ci return false; 1809596a2c1Sopenharmony_ci} 1819596a2c1Sopenharmony_ci 1829596a2c1Sopenharmony_civoid LocaleMatcher::FindTrackPath(const LocaleInfo *request, size_t len, uint64_t encodedLocale, uint64_t *result) 1839596a2c1Sopenharmony_ci{ 1849596a2c1Sopenharmony_ci uint64_t currentEncodedLocale = encodedLocale; 1859596a2c1Sopenharmony_ci size_t i = 0; 1869596a2c1Sopenharmony_ci do { 1879596a2c1Sopenharmony_ci result[i] = currentEncodedLocale; 1889596a2c1Sopenharmony_ci currentEncodedLocale = SearchParentLocale(currentEncodedLocale, request); 1899596a2c1Sopenharmony_ci ++i; 1909596a2c1Sopenharmony_ci } while (currentEncodedLocale != LocaleMatcher::ROOT_LOCALE); 1919596a2c1Sopenharmony_ci if (i < len) { 1929596a2c1Sopenharmony_ci result[i] = LocaleMatcher::ROOT_LOCALE; 1939596a2c1Sopenharmony_ci } 1949596a2c1Sopenharmony_ci} 1959596a2c1Sopenharmony_ci 1969596a2c1Sopenharmony_ciuint64_t LocaleMatcher::SearchParentLocale(uint64_t encodedLocale, const LocaleInfo *request) 1979596a2c1Sopenharmony_ci{ 1989596a2c1Sopenharmony_ci uint64_t tempEncodedLocale = encodedLocale; 1999596a2c1Sopenharmony_ci if (LocaleUtil::EncodeScriptByLocaleInfo(request) == LocaleMatcher::HANT_ENCODE) { 2009596a2c1Sopenharmony_ci tempEncodedLocale = AddScript(encodedLocale, LocaleMatcher::HANT_ENCODE); 2019596a2c1Sopenharmony_ci if (tempEncodedLocale == LocaleMatcher::ZH_HANT_MO_ENCODE) { 2029596a2c1Sopenharmony_ci return LocaleMatcher::ZH_HK_ENCODE; 2039596a2c1Sopenharmony_ci } 2049596a2c1Sopenharmony_ci } 2059596a2c1Sopenharmony_ci if (IsContainRegion(encodedLocale)) { 2069596a2c1Sopenharmony_ci for (size_t i = 0; i < LocaleData::LOCALE_PARENTS_KEY.size(); i++) { 2079596a2c1Sopenharmony_ci if (LocaleData::LOCALE_PARENTS_KEY[i] == tempEncodedLocale) { 2089596a2c1Sopenharmony_ci return LocaleData::LOCALE_PARENTS_VALUE[i]; 2099596a2c1Sopenharmony_ci } 2109596a2c1Sopenharmony_ci } 2119596a2c1Sopenharmony_ci return ClearRegion(encodedLocale); 2129596a2c1Sopenharmony_ci } 2139596a2c1Sopenharmony_ci return LocaleMatcher::ROOT_LOCALE; 2149596a2c1Sopenharmony_ci} 2159596a2c1Sopenharmony_ci 2169596a2c1Sopenharmony_ciuint64_t LocaleMatcher::AddScript(uint64_t encodedLocale, uint32_t encodedScript) 2179596a2c1Sopenharmony_ci{ 2189596a2c1Sopenharmony_ci // 16 is the offset of script 2199596a2c1Sopenharmony_ci return (encodedLocale | ((static_cast<uint64_t>(encodedScript) & 0x00000000FFFFFFFFLU) << 16)); 2209596a2c1Sopenharmony_ci} 2219596a2c1Sopenharmony_ci 2229596a2c1Sopenharmony_cibool LocaleMatcher::IsContainRegion(uint64_t encodedLocale) 2239596a2c1Sopenharmony_ci{ 2249596a2c1Sopenharmony_ci return (encodedLocale & 0x000000000000FFFFLU) != 0; 2259596a2c1Sopenharmony_ci} 2269596a2c1Sopenharmony_ci 2279596a2c1Sopenharmony_ciuint64_t LocaleMatcher::ClearRegion(uint64_t encodedLocale) 2289596a2c1Sopenharmony_ci{ 2299596a2c1Sopenharmony_ci return encodedLocale & 0xFFFFFFFFFFFF0000LU; 2309596a2c1Sopenharmony_ci} 2319596a2c1Sopenharmony_ci 2329596a2c1Sopenharmony_ciint8_t LocaleMatcher::CompareRegion(const LocaleInfo *current, const LocaleInfo *other, const LocaleInfo *request) 2339596a2c1Sopenharmony_ci{ 2349596a2c1Sopenharmony_ci uint16_t currentEncodedRegion = LocaleUtil::EncodeRegionByLocaleInfo(current); 2359596a2c1Sopenharmony_ci uint16_t otherEncodedRegion = LocaleUtil::EncodeRegionByLocaleInfo(other); 2369596a2c1Sopenharmony_ci if (request == nullptr || request->GetRegion().size() == 0) { 2379596a2c1Sopenharmony_ci return CompareWhenRegionIsNull(currentEncodedRegion, otherEncodedRegion, current, other, request); 2389596a2c1Sopenharmony_ci } 2399596a2c1Sopenharmony_ci uint64_t requestEncodedLocale = LocaleUtil::EncodeLocale(request->GetLanguage().c_str(), nullptr, 2409596a2c1Sopenharmony_ci request->GetRegion().c_str()); 2419596a2c1Sopenharmony_ci uint64_t requestEncodedTrackPath[LocaleMatcher::TRACKPATH_ARRAY_SIZE] = {0, 0, 0, 0, 0}; 2429596a2c1Sopenharmony_ci FindTrackPath(request, LocaleMatcher::TRACKPATH_ARRAY_SIZE, requestEncodedLocale, requestEncodedTrackPath); 2439596a2c1Sopenharmony_ci uint64_t currentEncodedLocale = LocaleUtil::EncodeLocale(request->GetLanguage().c_str(), nullptr, 2449596a2c1Sopenharmony_ci (current == nullptr) ? nullptr : current->GetRegion().c_str()); 2459596a2c1Sopenharmony_ci uint64_t otherEncodedLocale = LocaleUtil::EncodeLocale(request->GetLanguage().c_str(), nullptr, 2469596a2c1Sopenharmony_ci (other == nullptr) ? nullptr : other->GetRegion().c_str()); 2479596a2c1Sopenharmony_ci int8_t currentMatchDistance = SearchTrackPathDistance(requestEncodedTrackPath, LocaleMatcher::TRACKPATH_ARRAY_SIZE, 2489596a2c1Sopenharmony_ci currentEncodedLocale); 2499596a2c1Sopenharmony_ci int8_t otherMatchDistance = SearchTrackPathDistance(requestEncodedTrackPath, LocaleMatcher::TRACKPATH_ARRAY_SIZE, 2509596a2c1Sopenharmony_ci otherEncodedLocale); 2519596a2c1Sopenharmony_ci if (currentMatchDistance < otherMatchDistance) { 2529596a2c1Sopenharmony_ci return 1; 2539596a2c1Sopenharmony_ci } 2549596a2c1Sopenharmony_ci if (currentMatchDistance > otherMatchDistance) { 2559596a2c1Sopenharmony_ci return -1; 2569596a2c1Sopenharmony_ci } 2579596a2c1Sopenharmony_ci int8_t result = CompareDistance(currentEncodedLocale, otherEncodedLocale, requestEncodedTrackPath, request); 2589596a2c1Sopenharmony_ci if (result != 0) { 2599596a2c1Sopenharmony_ci return result; 2609596a2c1Sopenharmony_ci } 2619596a2c1Sopenharmony_ci result = CompareDefaultRegion(current, other, request); 2629596a2c1Sopenharmony_ci if (result != 0) { 2639596a2c1Sopenharmony_ci return result; 2649596a2c1Sopenharmony_ci } 2659596a2c1Sopenharmony_ci uint16_t requestDefaultRegion = 2669596a2c1Sopenharmony_ci FindDefaultRegionEncode(request->GetLanguage().c_str(), request->GetScript().c_str()); 2679596a2c1Sopenharmony_ci if (requestDefaultRegion == currentEncodedRegion) { 2689596a2c1Sopenharmony_ci return 1; 2699596a2c1Sopenharmony_ci } 2709596a2c1Sopenharmony_ci if (requestDefaultRegion == otherEncodedRegion) { 2719596a2c1Sopenharmony_ci return -1; 2729596a2c1Sopenharmony_ci } 2739596a2c1Sopenharmony_ci return AlphabeticallyCompare(current, currentEncodedLocale, other, otherEncodedLocale); 2749596a2c1Sopenharmony_ci} 2759596a2c1Sopenharmony_ci 2769596a2c1Sopenharmony_ciint8_t LocaleMatcher::CompareWhenRegionIsNull(uint16_t currentEncodedRegion, uint16_t otherEncodedRegion, 2779596a2c1Sopenharmony_ci const LocaleInfo *current, const LocaleInfo *other, const LocaleInfo *request) 2789596a2c1Sopenharmony_ci{ 2799596a2c1Sopenharmony_ci if (current == nullptr || current->GetRegion().length() == 0) { 2809596a2c1Sopenharmony_ci return 1; 2819596a2c1Sopenharmony_ci } 2829596a2c1Sopenharmony_ci if (other == nullptr || other->GetRegion().length() == 0) { 2839596a2c1Sopenharmony_ci return -1; 2849596a2c1Sopenharmony_ci } 2859596a2c1Sopenharmony_ci int8_t qaagResult = CompareRegionWhenQaag(current, other, request); 2869596a2c1Sopenharmony_ci if (qaagResult != 0) { 2879596a2c1Sopenharmony_ci return qaagResult; 2889596a2c1Sopenharmony_ci } 2899596a2c1Sopenharmony_ci // get request default region 2909596a2c1Sopenharmony_ci uint16_t requestDefaultRegion = 2919596a2c1Sopenharmony_ci FindDefaultRegionEncode((request == nullptr) ? nullptr : request->GetLanguage().c_str(), 2929596a2c1Sopenharmony_ci (request == nullptr) ? nullptr : request->GetScript().c_str()); 2939596a2c1Sopenharmony_ci if (requestDefaultRegion == currentEncodedRegion) { 2949596a2c1Sopenharmony_ci return 1; 2959596a2c1Sopenharmony_ci } 2969596a2c1Sopenharmony_ci if (requestDefaultRegion == otherEncodedRegion) { 2979596a2c1Sopenharmony_ci return -1; 2989596a2c1Sopenharmony_ci } 2999596a2c1Sopenharmony_ci // current and other region is not null.alphabetically 3009596a2c1Sopenharmony_ci uint64_t currentEncodedLocale = LocaleUtil::EncodeLocale( 3019596a2c1Sopenharmony_ci (request == nullptr) ? nullptr : request->GetLanguage().c_str(), nullptr, 3029596a2c1Sopenharmony_ci (current == nullptr) ? nullptr : current->GetRegion().c_str()); 3039596a2c1Sopenharmony_ci uint64_t otherEncodedLocale = LocaleUtil::EncodeLocale( 3049596a2c1Sopenharmony_ci (request == nullptr) ? nullptr : request->GetLanguage().c_str(), nullptr, other->GetRegion().c_str()); 3059596a2c1Sopenharmony_ci return AlphabeticallyCompare(current, currentEncodedLocale, other, otherEncodedLocale); 3069596a2c1Sopenharmony_ci} 3079596a2c1Sopenharmony_ci 3089596a2c1Sopenharmony_ciuint16_t LocaleMatcher::FindDefaultRegionEncode(const char *language, const char *script) 3099596a2c1Sopenharmony_ci{ 3109596a2c1Sopenharmony_ci /* first try language and script */ 3119596a2c1Sopenharmony_ci uint64_t encodedLocale = LocaleUtil::EncodeLocale(language, script, nullptr); 3129596a2c1Sopenharmony_ci if (encodedLocale == LocaleUtil::EncodeLocale("en", "Qaag", nullptr)) { 3139596a2c1Sopenharmony_ci encodedLocale = LocaleUtil::EncodeLocale("en", "Latn", nullptr); 3149596a2c1Sopenharmony_ci } 3159596a2c1Sopenharmony_ci for (size_t i = 0; i < LocaleData::LIKELY_TAGS_CODES_KEY.size(); i++) { 3169596a2c1Sopenharmony_ci if (LocaleData::LIKELY_TAGS_CODES_KEY[i] == encodedLocale) { 3179596a2c1Sopenharmony_ci return static_cast<uint16_t>((LocaleData::LIKELY_TAGS_CODES_VALUE[i] & 0x000000000000ffff)); 3189596a2c1Sopenharmony_ci } 3199596a2c1Sopenharmony_ci } 3209596a2c1Sopenharmony_ci /* if not found and script is not null,try language */ 3219596a2c1Sopenharmony_ci if (script != nullptr) { 3229596a2c1Sopenharmony_ci encodedLocale = LocaleUtil::EncodeLocale(language, nullptr, nullptr); 3239596a2c1Sopenharmony_ci for (size_t i = 0; i < LocaleData::LIKELY_TAGS_CODES_KEY.size(); i++) { 3249596a2c1Sopenharmony_ci if (LocaleData::LIKELY_TAGS_CODES_KEY[i] == encodedLocale) { 3259596a2c1Sopenharmony_ci return static_cast<uint16_t>((LocaleData::LIKELY_TAGS_CODES_VALUE[i] & 0x000000000000ffff)); 3269596a2c1Sopenharmony_ci } 3279596a2c1Sopenharmony_ci } 3289596a2c1Sopenharmony_ci } 3299596a2c1Sopenharmony_ci return LocaleMatcher::NULL_REGION; 3309596a2c1Sopenharmony_ci} 3319596a2c1Sopenharmony_ci 3329596a2c1Sopenharmony_ciint8_t LocaleMatcher::AlphabeticallyCompare(const LocaleInfo *current, uint64_t currentEncodedLocale, 3339596a2c1Sopenharmony_ci const LocaleInfo *other, uint64_t otherEncodedLocale) 3349596a2c1Sopenharmony_ci{ 3359596a2c1Sopenharmony_ci if (currentEncodedLocale == otherEncodedLocale) { 3369596a2c1Sopenharmony_ci return 0; 3379596a2c1Sopenharmony_ci } 3389596a2c1Sopenharmony_ci if (current == nullptr || current->GetRegion().length() == 0) { 3399596a2c1Sopenharmony_ci return -1; 3409596a2c1Sopenharmony_ci } 3419596a2c1Sopenharmony_ci if (other == nullptr || other->GetRegion().length() == 0) { 3429596a2c1Sopenharmony_ci return 1; 3439596a2c1Sopenharmony_ci } 3449596a2c1Sopenharmony_ci // be here region is not null 3459596a2c1Sopenharmony_ci char currentFirstChar = (current->GetRegion())[0]; 3469596a2c1Sopenharmony_ci char otherFirstChar = (other->GetRegion())[0]; 3479596a2c1Sopenharmony_ci if (currentFirstChar >= '0' && currentFirstChar <= '9') { 3489596a2c1Sopenharmony_ci if (otherFirstChar < '0' || otherFirstChar > '9') { 3499596a2c1Sopenharmony_ci return -1; 3509596a2c1Sopenharmony_ci } 3519596a2c1Sopenharmony_ci } else { 3529596a2c1Sopenharmony_ci if (otherFirstChar >= '0' && otherFirstChar <= '9') { 3539596a2c1Sopenharmony_ci return 1; 3549596a2c1Sopenharmony_ci } 3559596a2c1Sopenharmony_ci } 3569596a2c1Sopenharmony_ci if (currentEncodedLocale > otherEncodedLocale) { 3579596a2c1Sopenharmony_ci return -1; 3589596a2c1Sopenharmony_ci } 3599596a2c1Sopenharmony_ci if (otherEncodedLocale > currentEncodedLocale) { 3609596a2c1Sopenharmony_ci return 1; 3619596a2c1Sopenharmony_ci } 3629596a2c1Sopenharmony_ci return 0; 3639596a2c1Sopenharmony_ci} 3649596a2c1Sopenharmony_ci 3659596a2c1Sopenharmony_ciint8_t LocaleMatcher::SearchTrackPathDistance(const uint64_t *paths, size_t len, uint64_t encodedLocale) 3669596a2c1Sopenharmony_ci{ 3679596a2c1Sopenharmony_ci size_t i = 0; 3689596a2c1Sopenharmony_ci for (i = 0; i < len; ++i) { 3699596a2c1Sopenharmony_ci if (paths[i] == LocaleMatcher::ROOT_LOCALE) { 3709596a2c1Sopenharmony_ci return i; 3719596a2c1Sopenharmony_ci } 3729596a2c1Sopenharmony_ci if (paths[i] == encodedLocale) { 3739596a2c1Sopenharmony_ci return i; 3749596a2c1Sopenharmony_ci } 3759596a2c1Sopenharmony_ci } 3769596a2c1Sopenharmony_ci return static_cast<int8_t>(i); 3779596a2c1Sopenharmony_ci} 3789596a2c1Sopenharmony_ci 3799596a2c1Sopenharmony_ciint8_t LocaleMatcher::CompareDistance(uint64_t currentEncodedLocale, uint64_t otherEncodedLocale, 3809596a2c1Sopenharmony_ci const uint64_t *requestEncodedTrackPath, const LocaleInfo *request) 3819596a2c1Sopenharmony_ci{ 3829596a2c1Sopenharmony_ci uint64_t currentEncodedTrackPath[LocaleMatcher::TRACKPATH_ARRAY_SIZE] = {0, 0, 0, 0, 0}; 3839596a2c1Sopenharmony_ci FindTrackPath(request, LocaleMatcher::TRACKPATH_ARRAY_SIZE, currentEncodedLocale, currentEncodedTrackPath); 3849596a2c1Sopenharmony_ci uint64_t otherEncodedTrackPath[LocaleMatcher::TRACKPATH_ARRAY_SIZE] = {0, 0, 0, 0, 0}; 3859596a2c1Sopenharmony_ci FindTrackPath(request, LocaleMatcher::TRACKPATH_ARRAY_SIZE, otherEncodedLocale, otherEncodedTrackPath); 3869596a2c1Sopenharmony_ci const size_t currentDistance = ComputeTrackPathDistance(requestEncodedTrackPath, currentEncodedTrackPath, 3879596a2c1Sopenharmony_ci LocaleMatcher::TRACKPATH_ARRAY_SIZE); 3889596a2c1Sopenharmony_ci const size_t targetDistance = ComputeTrackPathDistance(requestEncodedTrackPath, otherEncodedTrackPath, 3899596a2c1Sopenharmony_ci LocaleMatcher::TRACKPATH_ARRAY_SIZE); 3909596a2c1Sopenharmony_ci if (currentDistance < targetDistance) { 3919596a2c1Sopenharmony_ci return 1; 3929596a2c1Sopenharmony_ci } 3939596a2c1Sopenharmony_ci if (currentDistance > targetDistance) { 3949596a2c1Sopenharmony_ci return -1; 3959596a2c1Sopenharmony_ci } 3969596a2c1Sopenharmony_ci return 0; 3979596a2c1Sopenharmony_ci} 3989596a2c1Sopenharmony_ci 3999596a2c1Sopenharmony_cisize_t LocaleMatcher::ComputeTrackPathDistance(const uint64_t *requestPaths, const uint64_t *targetPaths, size_t len) 4009596a2c1Sopenharmony_ci{ 4019596a2c1Sopenharmony_ci for (size_t i = 0; i < len; ++i) { 4029596a2c1Sopenharmony_ci if (targetPaths[i] == LocaleMatcher::ROOT_LOCALE) { 4039596a2c1Sopenharmony_ci // targetpath not in request path,so distance is 2*len 4049596a2c1Sopenharmony_ci return len * 2; 4059596a2c1Sopenharmony_ci } 4069596a2c1Sopenharmony_ci for (size_t j = 0; j < len; ++j) { 4079596a2c1Sopenharmony_ci if (requestPaths[j] == targetPaths[i]) { 4089596a2c1Sopenharmony_ci return i + j; 4099596a2c1Sopenharmony_ci } 4109596a2c1Sopenharmony_ci } 4119596a2c1Sopenharmony_ci } 4129596a2c1Sopenharmony_ci return len * 2; // targetpath not in request path,so distance is 2*len 4139596a2c1Sopenharmony_ci} 4149596a2c1Sopenharmony_ci 4159596a2c1Sopenharmony_ciint8_t LocaleMatcher::CompareDefaultRegion(const LocaleInfo *current, const LocaleInfo *other, 4169596a2c1Sopenharmony_ci const LocaleInfo *request) 4179596a2c1Sopenharmony_ci{ 4189596a2c1Sopenharmony_ci int8_t qaagResult = CompareRegionWhenQaag(current, other, request); 4199596a2c1Sopenharmony_ci if (qaagResult != 0) { 4209596a2c1Sopenharmony_ci return qaagResult; 4219596a2c1Sopenharmony_ci } else { 4229596a2c1Sopenharmony_ci bool isCurrentDefaultRegion = IsDefaultLocale((request == nullptr) ? nullptr : request->GetLanguage().c_str(), 4239596a2c1Sopenharmony_ci (request == nullptr) ? nullptr : request->GetScript().c_str(), 4249596a2c1Sopenharmony_ci (current == nullptr) ? nullptr : current->GetRegion().c_str()); 4259596a2c1Sopenharmony_ci bool isOtherDefaultRegion = IsDefaultLocale((request == nullptr) ? nullptr : request->GetLanguage().c_str(), 4269596a2c1Sopenharmony_ci (request == nullptr) ? nullptr : request->GetScript().c_str(), 4279596a2c1Sopenharmony_ci (other == nullptr) ? nullptr : other->GetRegion().c_str()); 4289596a2c1Sopenharmony_ci if (isCurrentDefaultRegion != isOtherDefaultRegion) { 4299596a2c1Sopenharmony_ci if (isCurrentDefaultRegion) { 4309596a2c1Sopenharmony_ci return 1; 4319596a2c1Sopenharmony_ci } else { 4329596a2c1Sopenharmony_ci return -1; 4339596a2c1Sopenharmony_ci } 4349596a2c1Sopenharmony_ci } 4359596a2c1Sopenharmony_ci } 4369596a2c1Sopenharmony_ci return 0; 4379596a2c1Sopenharmony_ci} 4389596a2c1Sopenharmony_ci 4399596a2c1Sopenharmony_cibool LocaleMatcher::IsDefaultLocale(const char *language, const char *script, const char *region) 4409596a2c1Sopenharmony_ci{ 4419596a2c1Sopenharmony_ci uint64_t encodedLocale = LocaleUtil::EncodeLocale(language, script, region); 4429596a2c1Sopenharmony_ci if (ClearRegion(encodedLocale) == LocaleMatcher::EN_QAAG_ENCODE) { 4439596a2c1Sopenharmony_ci encodedLocale = LocaleUtil::EncodeLocale("en", "Latn", region); 4449596a2c1Sopenharmony_ci } 4459596a2c1Sopenharmony_ci for (size_t i = 0; i < LocaleData::TYPICAL_CODES_VALUE.size(); i++) { 4469596a2c1Sopenharmony_ci if (LocaleData::TYPICAL_CODES_VALUE[i] == encodedLocale) { 4479596a2c1Sopenharmony_ci return true; 4489596a2c1Sopenharmony_ci } 4499596a2c1Sopenharmony_ci } 4509596a2c1Sopenharmony_ci return false; 4519596a2c1Sopenharmony_ci} 4529596a2c1Sopenharmony_ci 4539596a2c1Sopenharmony_ciint8_t LocaleMatcher::CompareLanguageIgnoreOldNewCode(const LocaleInfo *current, const LocaleInfo *other, 4549596a2c1Sopenharmony_ci const LocaleInfo *request) 4559596a2c1Sopenharmony_ci{ 4569596a2c1Sopenharmony_ci uint16_t currentLanguageEncode = LocaleUtil::EncodeLanguageByLocaleInfo(current); 4579596a2c1Sopenharmony_ci uint16_t otherLanguageEncode = LocaleUtil::EncodeLanguageByLocaleInfo(other); 4589596a2c1Sopenharmony_ci uint16_t requestLanguageEncode = LocaleUtil::EncodeLanguageByLocaleInfo(request); 4599596a2c1Sopenharmony_ci if ((currentLanguageEncode == requestLanguageEncode) && (otherLanguageEncode != requestLanguageEncode)) { 4609596a2c1Sopenharmony_ci return 1; 4619596a2c1Sopenharmony_ci } 4629596a2c1Sopenharmony_ci if ((otherLanguageEncode == requestLanguageEncode) && (currentLanguageEncode != requestLanguageEncode)) { 4639596a2c1Sopenharmony_ci return -1; 4649596a2c1Sopenharmony_ci } 4659596a2c1Sopenharmony_ci return 0; 4669596a2c1Sopenharmony_ci} 4679596a2c1Sopenharmony_ci 4689596a2c1Sopenharmony_cibool LocaleMatcher::Match(const LocaleInfo *current, const LocaleInfo *other) 4699596a2c1Sopenharmony_ci{ 4709596a2c1Sopenharmony_ci if (current == nullptr || other == nullptr) { 4719596a2c1Sopenharmony_ci return true; 4729596a2c1Sopenharmony_ci } 4739596a2c1Sopenharmony_ci // language is not null. 4749596a2c1Sopenharmony_ci bool isLanguageEqual = CompareLanguage(current, other); 4759596a2c1Sopenharmony_ci if (!isLanguageEqual) { 4769596a2c1Sopenharmony_ci return false; 4779596a2c1Sopenharmony_ci } 4789596a2c1Sopenharmony_ci return CompareScript(current, other); 4799596a2c1Sopenharmony_ci} 4809596a2c1Sopenharmony_ci 4819596a2c1Sopenharmony_cibool LocaleMatcher::CompareScript(const LocaleInfo *current, const LocaleInfo *other) 4829596a2c1Sopenharmony_ci{ 4839596a2c1Sopenharmony_ci uint32_t currentEncodedScript = 0; 4849596a2c1Sopenharmony_ci uint32_t otherEncodedScript = 0; 4859596a2c1Sopenharmony_ci if ((current != nullptr) && (current->GetScript().length() == 0)) { 4869596a2c1Sopenharmony_ci currentEncodedScript = FindDefaultScriptEncode(current->GetLanguage().c_str(), current->GetRegion().c_str()); 4879596a2c1Sopenharmony_ci } else { 4889596a2c1Sopenharmony_ci currentEncodedScript = LocaleUtil::EncodeScriptByLocaleInfo(current); 4899596a2c1Sopenharmony_ci } 4909596a2c1Sopenharmony_ci if ((other != nullptr) && (other->GetScript().length() == 0)) { 4919596a2c1Sopenharmony_ci otherEncodedScript = FindDefaultScriptEncode(other->GetLanguage().c_str(), other->GetRegion().c_str()); 4929596a2c1Sopenharmony_ci } else { 4939596a2c1Sopenharmony_ci otherEncodedScript = LocaleUtil::EncodeScriptByLocaleInfo(other); 4949596a2c1Sopenharmony_ci } 4959596a2c1Sopenharmony_ci if (current != nullptr && other != nullptr) { 4969596a2c1Sopenharmony_ci // when current locale is en-Qaag is equal en-Latn 4979596a2c1Sopenharmony_ci if (LocaleUtil::EncodeLocale(current->GetLanguage().c_str(), current->GetScript().c_str(), nullptr) == 4989596a2c1Sopenharmony_ci LocaleUtil::EncodeLocale("en", "Qaag", nullptr)) { 4999596a2c1Sopenharmony_ci if (LocaleUtil::EncodeLocale(other->GetLanguage().c_str(), other->GetScript().c_str(), nullptr) == 5009596a2c1Sopenharmony_ci LocaleUtil::EncodeLocale("en", "Latn", nullptr)) { 5019596a2c1Sopenharmony_ci return true; 5029596a2c1Sopenharmony_ci } 5039596a2c1Sopenharmony_ci } 5049596a2c1Sopenharmony_ci } 5059596a2c1Sopenharmony_ci bool compareRegion = false; 5069596a2c1Sopenharmony_ci if ((currentEncodedScript == LocaleMatcher::NULL_SCRIPT) || (otherEncodedScript == LocaleMatcher::NULL_SCRIPT)) { 5079596a2c1Sopenharmony_ci // if request script is null, region must be same 5089596a2c1Sopenharmony_ci compareRegion = true; 5099596a2c1Sopenharmony_ci } 5109596a2c1Sopenharmony_ci if (compareRegion) { 5119596a2c1Sopenharmony_ci uint16_t currentRegionEncode = LocaleUtil::EncodeRegionByLocaleInfo(current); 5129596a2c1Sopenharmony_ci uint16_t otherRegionEncode = LocaleUtil::EncodeRegionByLocaleInfo(other); 5139596a2c1Sopenharmony_ci return (otherRegionEncode == LocaleMatcher::NULL_REGION) || (currentRegionEncode == otherRegionEncode); 5149596a2c1Sopenharmony_ci } 5159596a2c1Sopenharmony_ci return currentEncodedScript == otherEncodedScript; 5169596a2c1Sopenharmony_ci} 5179596a2c1Sopenharmony_ci 5189596a2c1Sopenharmony_ciuint32_t LocaleMatcher::FindDefaultScriptEncode(const char *language, const char *region) 5199596a2c1Sopenharmony_ci{ 5209596a2c1Sopenharmony_ci uint64_t encodedLocale = LocaleUtil::EncodeLocale(language, nullptr, region); 5219596a2c1Sopenharmony_ci for (size_t i = 0; i < LocaleData::LIKELY_TAGS_CODES_KEY.size(); i++) { 5229596a2c1Sopenharmony_ci if (LocaleData::LIKELY_TAGS_CODES_KEY[i] == encodedLocale) { 5239596a2c1Sopenharmony_ci // 16 is the offset of script 5249596a2c1Sopenharmony_ci return static_cast<uint32_t>((LocaleData::LIKELY_TAGS_CODES_VALUE[i] & 0x0000ffffffff0000) >> 16); 5259596a2c1Sopenharmony_ci } 5269596a2c1Sopenharmony_ci } 5279596a2c1Sopenharmony_ci if (region != nullptr) { 5289596a2c1Sopenharmony_ci encodedLocale = LocaleUtil::EncodeLocale(language, nullptr, nullptr); 5299596a2c1Sopenharmony_ci for (size_t i = 0; i < LocaleData::LIKELY_TAGS_CODES_KEY.size(); i++) { 5309596a2c1Sopenharmony_ci if (LocaleData::LIKELY_TAGS_CODES_KEY[i] == encodedLocale) { 5319596a2c1Sopenharmony_ci // 16 is the offset of script 5329596a2c1Sopenharmony_ci return static_cast<uint32_t>((LocaleData::LIKELY_TAGS_CODES_VALUE[i] & 0x0000ffffffff0000) >> 16); 5339596a2c1Sopenharmony_ci } 5349596a2c1Sopenharmony_ci } 5359596a2c1Sopenharmony_ci } 5369596a2c1Sopenharmony_ci return LocaleMatcher::NULL_SCRIPT; 5379596a2c1Sopenharmony_ci} 5389596a2c1Sopenharmony_ci} // namespace I18n 5399596a2c1Sopenharmony_ci} // namespace Global 5409596a2c1Sopenharmony_ci} // namespace OHOS