19596a2c1Sopenharmony_ci/*
29596a2c1Sopenharmony_ci * Copyright (c) 2021-2022 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#ifdef SUPPORT_APP_PREFERRED_LANGUAGE
169596a2c1Sopenharmony_ci#include <regex>
179596a2c1Sopenharmony_ci#include "application_context.h"
189596a2c1Sopenharmony_ci#include "bundle_info.h"
199596a2c1Sopenharmony_ci#include "bundle_mgr_interface.h"
209596a2c1Sopenharmony_ci#include "iservice_registry.h"
219596a2c1Sopenharmony_ci#include "system_ability_definition.h"
229596a2c1Sopenharmony_ci#endif
239596a2c1Sopenharmony_ci#include "i18n_hilog.h"
249596a2c1Sopenharmony_ci#include "locale_config.h"
259596a2c1Sopenharmony_ci#include "locale_info.h"
269596a2c1Sopenharmony_ci#include "locale_matcher.h"
279596a2c1Sopenharmony_ci#include "parameter.h"
289596a2c1Sopenharmony_ci#include "preferred_language.h"
299596a2c1Sopenharmony_ci#include "utils.h"
309596a2c1Sopenharmony_ci#include "vector"
319596a2c1Sopenharmony_ci
329596a2c1Sopenharmony_cinamespace OHOS {
339596a2c1Sopenharmony_cinamespace Global {
349596a2c1Sopenharmony_cinamespace I18n {
359596a2c1Sopenharmony_ciconst char *PreferredLanguage::RESOURCE_PATH_HEAD = "/data/accounts/account_0/applications/";
369596a2c1Sopenharmony_ciconst char *PreferredLanguage::RESOURCE_PATH_TAILOR = "/assets/entry/resources.index";
379596a2c1Sopenharmony_ciconst char *PreferredLanguage::RESOURCE_PATH_SPLITOR = "/";
389596a2c1Sopenharmony_ciconst char *PreferredLanguage::PREFERRED_LANGUAGES = "persist.global.preferredLanguages";
399596a2c1Sopenharmony_ciconst char *PreferredLanguage::APP_LANGUAGE_KEY = "app_language";
409596a2c1Sopenharmony_ciconst char *PreferredLanguage::I18N_PREFERENCES_FILE_NAME = "/i18n";
419596a2c1Sopenharmony_ciconst char *PreferredLanguage::DEFAULT_PREFERRED_LANGUAGE = "en-Latn-US";
429596a2c1Sopenharmony_cistd::vector<std::string> PreferredLanguage::supportLanguageListExt = { "it", "ko", "th", "zz" };
439596a2c1Sopenharmony_ci
449596a2c1Sopenharmony_cistd::vector<std::string> PreferredLanguage::GetPreferredLanguageList()
459596a2c1Sopenharmony_ci{
469596a2c1Sopenharmony_ci    char preferredLanguageValue[CONFIG_LEN];
479596a2c1Sopenharmony_ci    GetParameter(PREFERRED_LANGUAGES, "", preferredLanguageValue, CONFIG_LEN);
489596a2c1Sopenharmony_ci    std::string systemLanguage = GetMatchedLanguage(LocaleConfig::GetSystemLanguage());
499596a2c1Sopenharmony_ci    std::vector<std::string> list;
509596a2c1Sopenharmony_ci    Split(preferredLanguageValue, ";", list);
519596a2c1Sopenharmony_ci    list = FilterLanguages(list);
529596a2c1Sopenharmony_ci    if (!list.size()) {
539596a2c1Sopenharmony_ci        if (systemLanguage != "") {
549596a2c1Sopenharmony_ci            list.push_back(systemLanguage);
559596a2c1Sopenharmony_ci        }
569596a2c1Sopenharmony_ci        return list;
579596a2c1Sopenharmony_ci    }
589596a2c1Sopenharmony_ci    if (list[0] == systemLanguage || systemLanguage == "") {
599596a2c1Sopenharmony_ci        return list;
609596a2c1Sopenharmony_ci    }
619596a2c1Sopenharmony_ci    int systemLanguageIdx = -1;
629596a2c1Sopenharmony_ci    for (size_t i = 0; i < list.size(); i++) {
639596a2c1Sopenharmony_ci        if (list[i] == systemLanguage) {
649596a2c1Sopenharmony_ci            systemLanguageIdx = (int)i;
659596a2c1Sopenharmony_ci        }
669596a2c1Sopenharmony_ci    }
679596a2c1Sopenharmony_ci    if (systemLanguageIdx == -1) {
689596a2c1Sopenharmony_ci        list.insert(list.begin(), systemLanguage);
699596a2c1Sopenharmony_ci    } else {
709596a2c1Sopenharmony_ci        for (size_t i = (size_t)systemLanguageIdx; i > 0; i--) {
719596a2c1Sopenharmony_ci            list[i] = list[i - 1];
729596a2c1Sopenharmony_ci        }
739596a2c1Sopenharmony_ci        list[0] = systemLanguage;
749596a2c1Sopenharmony_ci    }
759596a2c1Sopenharmony_ci    return list;
769596a2c1Sopenharmony_ci}
779596a2c1Sopenharmony_ci
789596a2c1Sopenharmony_cistd::vector<std::string> PreferredLanguage::FilterLanguages(std::vector<std::string>& preferredLanguagesList)
799596a2c1Sopenharmony_ci{
809596a2c1Sopenharmony_ci    std::vector<std::string> matchedLanguagesList;
819596a2c1Sopenharmony_ci    std::unordered_set<std::string> matchedSet;
829596a2c1Sopenharmony_ci    for (auto& preferredLanguage : preferredLanguagesList) {
839596a2c1Sopenharmony_ci        std::string matchedLanguage = GetMatchedLanguage(preferredLanguage);
849596a2c1Sopenharmony_ci        if (matchedLanguage.empty()) {
859596a2c1Sopenharmony_ci            HILOG_ERROR_I18N("FilterLanguages: the matching result of %{public}s is empty.",
869596a2c1Sopenharmony_ci                preferredLanguage.c_str());
879596a2c1Sopenharmony_ci            matchedLanguage = DEFAULT_PREFERRED_LANGUAGE;
889596a2c1Sopenharmony_ci        }
899596a2c1Sopenharmony_ci        if (matchedSet.find(matchedLanguage) == matchedSet.end()) {
909596a2c1Sopenharmony_ci            matchedLanguagesList.push_back(matchedLanguage);
919596a2c1Sopenharmony_ci            matchedSet.insert(matchedLanguage);
929596a2c1Sopenharmony_ci            HILOG_ERROR_I18N("FilterLanguages: the matching result is %{public}s.", matchedLanguage.c_str());
939596a2c1Sopenharmony_ci        }
949596a2c1Sopenharmony_ci    }
959596a2c1Sopenharmony_ci    return matchedLanguagesList;
969596a2c1Sopenharmony_ci}
979596a2c1Sopenharmony_ci
989596a2c1Sopenharmony_cistd::string PreferredLanguage::GetMatchedLanguage(const std::string& language)
999596a2c1Sopenharmony_ci{
1009596a2c1Sopenharmony_ci    UErrorCode status = U_ZERO_ERROR;
1019596a2c1Sopenharmony_ci    icu::Locale locale = icu::Locale::forLanguageTag(language.c_str(), status);
1029596a2c1Sopenharmony_ci    if (U_FAILURE(status) || !IsValidLocaleTag(locale)) {
1039596a2c1Sopenharmony_ci        HILOG_ERROR_I18N("GetMatchedLanguage: %{public}s is an invalid locale.", language.c_str());
1049596a2c1Sopenharmony_ci        return "";
1059596a2c1Sopenharmony_ci    }
1069596a2c1Sopenharmony_ci    LocaleInfo* requestLocale = new LocaleInfo(language);
1079596a2c1Sopenharmony_ci    if (requestLocale == nullptr) {
1089596a2c1Sopenharmony_ci        HILOG_ERROR_I18N("GetMatchedLanguage: %{public}s failed to construct LocaleInfo.", language.c_str());
1099596a2c1Sopenharmony_ci        return "";
1109596a2c1Sopenharmony_ci    }
1119596a2c1Sopenharmony_ci    std::vector<LocaleInfo*> candidateLocales;
1129596a2c1Sopenharmony_ci    std::vector<std::string> supportLanguageList;
1139596a2c1Sopenharmony_ci    LocaleConfig::GetSystemLanguages(supportLanguageList);
1149596a2c1Sopenharmony_ci    supportLanguageList.insert(supportLanguageList.end(), supportLanguageListExt.begin(),
1159596a2c1Sopenharmony_ci        supportLanguageListExt.end());
1169596a2c1Sopenharmony_ci    for (auto& supportLanguage : supportLanguageList) {
1179596a2c1Sopenharmony_ci        LocaleInfo* supportLocaleInfo = new LocaleInfo(supportLanguage);
1189596a2c1Sopenharmony_ci        if (supportLocaleInfo == nullptr) {
1199596a2c1Sopenharmony_ci            HILOG_ERROR_I18N("GetMatchedLanguage: %{public}s failed to construct LocaleInfo.",
1209596a2c1Sopenharmony_ci                supportLanguage.c_str());
1219596a2c1Sopenharmony_ci            continue;
1229596a2c1Sopenharmony_ci        }
1239596a2c1Sopenharmony_ci        if (LocaleMatcher::Match(requestLocale, supportLocaleInfo)) {
1249596a2c1Sopenharmony_ci            candidateLocales.push_back(supportLocaleInfo);
1259596a2c1Sopenharmony_ci        } else {
1269596a2c1Sopenharmony_ci            delete supportLocaleInfo;
1279596a2c1Sopenharmony_ci        }
1289596a2c1Sopenharmony_ci    }
1299596a2c1Sopenharmony_ci    std::string matchedLanguage = LocaleMatcher::GetBestMatchedLocale(requestLocale, candidateLocales);
1309596a2c1Sopenharmony_ci    for (LocaleInfo* supportLocaleInfo : candidateLocales) {
1319596a2c1Sopenharmony_ci        delete supportLocaleInfo;
1329596a2c1Sopenharmony_ci    }
1339596a2c1Sopenharmony_ci    delete requestLocale;
1349596a2c1Sopenharmony_ci    return matchedLanguage;
1359596a2c1Sopenharmony_ci}
1369596a2c1Sopenharmony_ci
1379596a2c1Sopenharmony_cistd::string PreferredLanguage::GetFirstPreferredLanguage()
1389596a2c1Sopenharmony_ci{
1399596a2c1Sopenharmony_ci    std::vector<std::string> preferredLanguageList = GetPreferredLanguageList();
1409596a2c1Sopenharmony_ci    return preferredLanguageList[0];
1419596a2c1Sopenharmony_ci}
1429596a2c1Sopenharmony_ci
1439596a2c1Sopenharmony_ci#ifdef SUPPORT_APP_PREFERRED_LANGUAGE
1449596a2c1Sopenharmony_cistd::shared_ptr<NativePreferences::Preferences> PreferredLanguage::GetI18nAppPreferences()
1459596a2c1Sopenharmony_ci{
1469596a2c1Sopenharmony_ci    std::shared_ptr<AbilityRuntime::ApplicationContext> appContext = AbilityRuntime::ApplicationContext::GetInstance();
1479596a2c1Sopenharmony_ci    std::string preferencesDirPath = appContext->GetPreferencesDir();
1489596a2c1Sopenharmony_ci    std::string i18nPreferencesFilePath = preferencesDirPath + I18N_PREFERENCES_FILE_NAME;
1499596a2c1Sopenharmony_ci    int status;
1509596a2c1Sopenharmony_ci    NativePreferences::Options options(i18nPreferencesFilePath);
1519596a2c1Sopenharmony_ci    std::shared_ptr<NativePreferences::Preferences> preferences =
1529596a2c1Sopenharmony_ci        NativePreferences::PreferencesHelper::GetPreferences(options, status);
1539596a2c1Sopenharmony_ci    if (status != 0) {
1549596a2c1Sopenharmony_ci        HILOG_ERROR_I18N("PreferredLanguage::GetAppPreferredLanguage get i18n app preferences failed.");
1559596a2c1Sopenharmony_ci        return nullptr;
1569596a2c1Sopenharmony_ci    }
1579596a2c1Sopenharmony_ci    return preferences;
1589596a2c1Sopenharmony_ci}
1599596a2c1Sopenharmony_ci
1609596a2c1Sopenharmony_cibool PreferredLanguage::IsSetAppPreferredLanguage()
1619596a2c1Sopenharmony_ci{
1629596a2c1Sopenharmony_ci    std::shared_ptr<NativePreferences::Preferences> preferences = GetI18nAppPreferences();
1639596a2c1Sopenharmony_ci    if (preferences == nullptr) {
1649596a2c1Sopenharmony_ci        HILOG_ERROR_I18N(
1659596a2c1Sopenharmony_ci            "PreferredLanguage::IsSetAppPreferredLanguage get i18n preferences failed, return system language.");
1669596a2c1Sopenharmony_ci        return false;
1679596a2c1Sopenharmony_ci    }
1689596a2c1Sopenharmony_ci    std::string res = preferences->GetString(PreferredLanguage::APP_LANGUAGE_KEY, "");
1699596a2c1Sopenharmony_ci    if (res.length() == 0 || res.compare("default") == 0) {
1709596a2c1Sopenharmony_ci        return false;
1719596a2c1Sopenharmony_ci    }
1729596a2c1Sopenharmony_ci    return true;
1739596a2c1Sopenharmony_ci}
1749596a2c1Sopenharmony_ci
1759596a2c1Sopenharmony_cistd::string PreferredLanguage::GetAppPreferredLanguage()
1769596a2c1Sopenharmony_ci{
1779596a2c1Sopenharmony_ci    std::shared_ptr<NativePreferences::Preferences> preferences = GetI18nAppPreferences();
1789596a2c1Sopenharmony_ci    if (preferences == nullptr) {
1799596a2c1Sopenharmony_ci        HILOG_ERROR_I18N(
1809596a2c1Sopenharmony_ci            "PreferredLanguage::GetAppPreferredLanguage get i18n preferences failed, return system language.");
1819596a2c1Sopenharmony_ci        return LocaleConfig::GetSystemLocale();
1829596a2c1Sopenharmony_ci    }
1839596a2c1Sopenharmony_ci    std::string res = preferences->GetString(PreferredLanguage::APP_LANGUAGE_KEY, "");
1849596a2c1Sopenharmony_ci    if (res.length() == 0 || res.compare("default") == 0) {
1859596a2c1Sopenharmony_ci        return LocaleConfig::GetSystemLocale();
1869596a2c1Sopenharmony_ci    }
1879596a2c1Sopenharmony_ci    return res;
1889596a2c1Sopenharmony_ci}
1899596a2c1Sopenharmony_ci
1909596a2c1Sopenharmony_civoid PreferredLanguage::SetAppPreferredLanguage(const std::string &language, I18nErrorCode &errCode)
1919596a2c1Sopenharmony_ci{
1929596a2c1Sopenharmony_ci    std::shared_ptr<AbilityRuntime::ApplicationContext> appContext = AbilityRuntime::ApplicationContext::GetInstance();
1939596a2c1Sopenharmony_ci    if (language.compare("default") != 0) {
1949596a2c1Sopenharmony_ci        appContext->SetLanguage(language);
1959596a2c1Sopenharmony_ci    }
1969596a2c1Sopenharmony_ci    std::shared_ptr<NativePreferences::Preferences> preferences = GetI18nAppPreferences();
1979596a2c1Sopenharmony_ci    if (preferences == nullptr) {
1989596a2c1Sopenharmony_ci        errCode = I18nErrorCode::FAILED;
1999596a2c1Sopenharmony_ci        HILOG_ERROR_I18N("PreferredLanguage::SetAppPreferredLanguage get i18n preferences failed.");
2009596a2c1Sopenharmony_ci        return;
2019596a2c1Sopenharmony_ci    }
2029596a2c1Sopenharmony_ci    int32_t status = preferences->PutString(PreferredLanguage::APP_LANGUAGE_KEY, language);
2039596a2c1Sopenharmony_ci    if (status != 0) {
2049596a2c1Sopenharmony_ci        errCode = I18nErrorCode::FAILED;
2059596a2c1Sopenharmony_ci        HILOG_ERROR_I18N(
2069596a2c1Sopenharmony_ci            "PreferredLanguage::SetAppPreferredLanguage set app language to i18n preferences failed.");
2079596a2c1Sopenharmony_ci        return;
2089596a2c1Sopenharmony_ci    }
2099596a2c1Sopenharmony_ci    preferences->Flush();
2109596a2c1Sopenharmony_ci}
2119596a2c1Sopenharmony_ci#endif
2129596a2c1Sopenharmony_ci
2139596a2c1Sopenharmony_cistd::string PreferredLanguage::GetPreferredLocale()
2149596a2c1Sopenharmony_ci{
2159596a2c1Sopenharmony_ci    std::string systemLocale = LocaleConfig::GetSystemLocale();
2169596a2c1Sopenharmony_ci    LocaleInfo systemLocaleInfo(systemLocale);
2179596a2c1Sopenharmony_ci    std::string systemRegion = systemLocaleInfo.GetRegion();
2189596a2c1Sopenharmony_ci    std::string preferredLanguageLocale = GetFirstPreferredLanguage();
2199596a2c1Sopenharmony_ci    LocaleInfo preferredLanguageLocaleInfo(preferredLanguageLocale);
2209596a2c1Sopenharmony_ci    std::string preferredLanguage = preferredLanguageLocaleInfo.GetLanguage();
2219596a2c1Sopenharmony_ci    std::string preferredLocale = preferredLanguage + "-" + systemRegion;
2229596a2c1Sopenharmony_ci    return preferredLocale;
2239596a2c1Sopenharmony_ci}
2249596a2c1Sopenharmony_ci
2259596a2c1Sopenharmony_cibool PreferredLanguage::IsValidLanguage(const std::string &language)
2269596a2c1Sopenharmony_ci{
2279596a2c1Sopenharmony_ci    std::string::size_type size = language.size();
2289596a2c1Sopenharmony_ci    if ((size != LANGUAGE_LEN) && (size != LANGUAGE_LEN + 1)) {
2299596a2c1Sopenharmony_ci        return false;
2309596a2c1Sopenharmony_ci    }
2319596a2c1Sopenharmony_ci    for (size_t i = 0; i < size; ++i) {
2329596a2c1Sopenharmony_ci        if ((language[i] > 'z') || (language[i] < 'a')) {
2339596a2c1Sopenharmony_ci            return false;
2349596a2c1Sopenharmony_ci        }
2359596a2c1Sopenharmony_ci    }
2369596a2c1Sopenharmony_ci    return true;
2379596a2c1Sopenharmony_ci}
2389596a2c1Sopenharmony_ci
2399596a2c1Sopenharmony_cibool PreferredLanguage::IsValidTag(const std::string &tag)
2409596a2c1Sopenharmony_ci{
2419596a2c1Sopenharmony_ci    if (!tag.size()) {
2429596a2c1Sopenharmony_ci        return false;
2439596a2c1Sopenharmony_ci    }
2449596a2c1Sopenharmony_ci    std::vector<std::string> splits;
2459596a2c1Sopenharmony_ci    Split(tag, "-", splits);
2469596a2c1Sopenharmony_ci    if (!IsValidLanguage(splits[0])) {
2479596a2c1Sopenharmony_ci        return false;
2489596a2c1Sopenharmony_ci    }
2499596a2c1Sopenharmony_ci    return true;
2509596a2c1Sopenharmony_ci}
2519596a2c1Sopenharmony_ci
2529596a2c1Sopenharmony_civoid PreferredLanguage::Split(const std::string &src, const std::string &sep, std::vector<std::string> &dest)
2539596a2c1Sopenharmony_ci{
2549596a2c1Sopenharmony_ci    std::string::size_type begin = 0;
2559596a2c1Sopenharmony_ci    std::string::size_type end = src.find(sep);
2569596a2c1Sopenharmony_ci    while (end != std::string::npos) {
2579596a2c1Sopenharmony_ci        dest.push_back(src.substr(begin, end - begin));
2589596a2c1Sopenharmony_ci        begin = end + sep.size();
2599596a2c1Sopenharmony_ci        end = src.find(sep, begin);
2609596a2c1Sopenharmony_ci    }
2619596a2c1Sopenharmony_ci    if (begin != src.size()) {
2629596a2c1Sopenharmony_ci        dest.push_back(src.substr(begin));
2639596a2c1Sopenharmony_ci    }
2649596a2c1Sopenharmony_ci}
2659596a2c1Sopenharmony_ci
2669596a2c1Sopenharmony_ciI18nErrorCode PreferredLanguage::AddPreferredLanguage(const std::string &language, int32_t index)
2679596a2c1Sopenharmony_ci{
2689596a2c1Sopenharmony_ci    if (!IsValidTag(language)) {
2699596a2c1Sopenharmony_ci        HILOG_ERROR_I18N("PreferredLanguage::AddPreferredLanguage %{public}s is not valid language tag.",
2709596a2c1Sopenharmony_ci            language.c_str());
2719596a2c1Sopenharmony_ci        return I18nErrorCode::INVALID_LANGUAGE_TAG;
2729596a2c1Sopenharmony_ci    }
2739596a2c1Sopenharmony_ci    std::vector<std::string> preferredLanguages;
2749596a2c1Sopenharmony_ci    I18nErrorCode status = I18nErrorCode::SUCCESS;
2759596a2c1Sopenharmony_ci    if (FindLanguage(language) == -1) {
2769596a2c1Sopenharmony_ci        // Case: language not in current preferred language list.
2779596a2c1Sopenharmony_ci        AddNonExistPreferredLanguage(language, index, preferredLanguages, status);
2789596a2c1Sopenharmony_ci    } else {
2799596a2c1Sopenharmony_ci        // Case: language in current preferred language list.
2809596a2c1Sopenharmony_ci        AddExistPreferredLanguage(language, index, preferredLanguages, status);
2819596a2c1Sopenharmony_ci    }
2829596a2c1Sopenharmony_ci    if (status != I18nErrorCode::SUCCESS) {
2839596a2c1Sopenharmony_ci        HILOG_ERROR_I18N("PreferredLanguage::AddPreferredLanguage failed.");
2849596a2c1Sopenharmony_ci        return status;
2859596a2c1Sopenharmony_ci    }
2869596a2c1Sopenharmony_ci    return SetPreferredLanguages(JoinPreferredLanguages(preferredLanguages));
2879596a2c1Sopenharmony_ci}
2889596a2c1Sopenharmony_ci
2899596a2c1Sopenharmony_ciI18nErrorCode PreferredLanguage::RemovePreferredLanguage(int32_t index)
2909596a2c1Sopenharmony_ci{
2919596a2c1Sopenharmony_ci    std::vector<std::string> preferredLanguages = GetPreferredLanguageList();
2929596a2c1Sopenharmony_ci    if (preferredLanguages.size() == 1) {
2939596a2c1Sopenharmony_ci        HILOG_ERROR_I18N("PreferredLanguage::RemovePreferredLanguage can't remove the only language.");
2949596a2c1Sopenharmony_ci        return I18nErrorCode::REMOVE_PREFERRED_LANGUAGE_FAILED;
2959596a2c1Sopenharmony_ci    }
2969596a2c1Sopenharmony_ci    // valid index is [0, preferredLanguages.size() - 1] for Remove
2979596a2c1Sopenharmony_ci    int32_t validIndex = NormalizeIndex(index, preferredLanguages.size() - 1);
2989596a2c1Sopenharmony_ci    preferredLanguages.erase(preferredLanguages.begin() + validIndex);
2999596a2c1Sopenharmony_ci    // The first language in preferred language list is system language, therefor when first language changed
3009596a2c1Sopenharmony_ci    // in preferred language list, we need to reset system language.
3019596a2c1Sopenharmony_ci    if (validIndex == 0) {
3029596a2c1Sopenharmony_ci        if (LocaleConfig::SetSystemLanguage(preferredLanguages[0]) != I18nErrorCode::SUCCESS) {
3039596a2c1Sopenharmony_ci            HILOG_ERROR_I18N("PreferredLanguage::RemovePreferredLanguage update system language failed.");
3049596a2c1Sopenharmony_ci            return I18nErrorCode::REMOVE_PREFERRED_LANGUAGE_FAILED;
3059596a2c1Sopenharmony_ci        }
3069596a2c1Sopenharmony_ci    }
3079596a2c1Sopenharmony_ci    return SetPreferredLanguages(JoinPreferredLanguages(preferredLanguages));
3089596a2c1Sopenharmony_ci}
3099596a2c1Sopenharmony_ci
3109596a2c1Sopenharmony_civoid PreferredLanguage::AddNonExistPreferredLanguage(const std::string& language, int32_t index,
3119596a2c1Sopenharmony_ci    std::vector<std::string> &preferredLanguages, I18nErrorCode &errCode)
3129596a2c1Sopenharmony_ci{
3139596a2c1Sopenharmony_ci    // valid index is [0, GetPreferredLanguageList().size()] for add non-exist language.
3149596a2c1Sopenharmony_ci    int32_t validIndex = NormalizeIndex(index, GetPreferredLanguageList().size());
3159596a2c1Sopenharmony_ci    preferredLanguages = GetPreferredLanguageList();
3169596a2c1Sopenharmony_ci    preferredLanguages.insert(preferredLanguages.begin() + validIndex, language);
3179596a2c1Sopenharmony_ci    // The first language in preferred language list is system language, therefor when first language changed
3189596a2c1Sopenharmony_ci    // in preferred language list, we need to reset system language.
3199596a2c1Sopenharmony_ci    if (validIndex == 0) {
3209596a2c1Sopenharmony_ci        if (LocaleConfig::SetSystemLanguage(preferredLanguages[0]) != I18nErrorCode::SUCCESS) {
3219596a2c1Sopenharmony_ci            HILOG_ERROR_I18N("PreferredLanguage::AddNonExistPreferredLanguage update system language failed.");
3229596a2c1Sopenharmony_ci            errCode = I18nErrorCode::ADD_PREFERRED_LANGUAGE_NON_EXIST_FAILED;
3239596a2c1Sopenharmony_ci            return;
3249596a2c1Sopenharmony_ci        }
3259596a2c1Sopenharmony_ci    }
3269596a2c1Sopenharmony_ci    errCode = I18nErrorCode::SUCCESS;
3279596a2c1Sopenharmony_ci}
3289596a2c1Sopenharmony_ci
3299596a2c1Sopenharmony_civoid PreferredLanguage::AddExistPreferredLanguage(const std::string& language, int32_t index,
3309596a2c1Sopenharmony_ci    std::vector<std::string> &preferredLanguages, I18nErrorCode &errCode)
3319596a2c1Sopenharmony_ci{
3329596a2c1Sopenharmony_ci    // throw error when current index is same with target index.
3339596a2c1Sopenharmony_ci    // valid index is [0, GetPreferredLanguageList().size() - 1] for add exist language.
3349596a2c1Sopenharmony_ci    int32_t validIndex = NormalizeIndex(index, GetPreferredLanguageList().size() - 1);
3359596a2c1Sopenharmony_ci    int32_t languageIdx = FindLanguage(language);
3369596a2c1Sopenharmony_ci    if (languageIdx == validIndex) {
3379596a2c1Sopenharmony_ci        errCode = I18nErrorCode::ADD_PREFERRED_LANGUAGE_EXIST_FAILED;
3389596a2c1Sopenharmony_ci        return;
3399596a2c1Sopenharmony_ci    }
3409596a2c1Sopenharmony_ci    // Move language from languageIdx to validIdx.
3419596a2c1Sopenharmony_ci    preferredLanguages = GetPreferredLanguageList();
3429596a2c1Sopenharmony_ci    preferredLanguages.erase(preferredLanguages.begin() + languageIdx);
3439596a2c1Sopenharmony_ci    preferredLanguages.insert(preferredLanguages.begin() + validIndex, language);
3449596a2c1Sopenharmony_ci    // The first language in preferred language list is system language, therefor when first language changed
3459596a2c1Sopenharmony_ci    // in preferred language list, we need to reset system language.
3469596a2c1Sopenharmony_ci    if (languageIdx == 0 || validIndex == 0) {
3479596a2c1Sopenharmony_ci        if (LocaleConfig::SetSystemLanguage(preferredLanguages[0]) != I18nErrorCode::SUCCESS) {
3489596a2c1Sopenharmony_ci            HILOG_ERROR_I18N("PreferredLanguage::AddExistPreferredLanguage update system language failed.");
3499596a2c1Sopenharmony_ci            errCode = I18nErrorCode::ADD_PREFERRED_LANGUAGE_EXIST_FAILED;
3509596a2c1Sopenharmony_ci            return;
3519596a2c1Sopenharmony_ci        }
3529596a2c1Sopenharmony_ci    }
3539596a2c1Sopenharmony_ci    errCode = I18nErrorCode::SUCCESS;
3549596a2c1Sopenharmony_ci}
3559596a2c1Sopenharmony_ci
3569596a2c1Sopenharmony_ciint32_t PreferredLanguage::NormalizeIndex(int32_t index, int32_t max)
3579596a2c1Sopenharmony_ci{
3589596a2c1Sopenharmony_ci    if (index <= 0) {
3599596a2c1Sopenharmony_ci        return 0;
3609596a2c1Sopenharmony_ci    }
3619596a2c1Sopenharmony_ci    if (index >= max) {
3629596a2c1Sopenharmony_ci        return max;
3639596a2c1Sopenharmony_ci    }
3649596a2c1Sopenharmony_ci    return index;
3659596a2c1Sopenharmony_ci}
3669596a2c1Sopenharmony_ci
3679596a2c1Sopenharmony_ci// Query the index of language in system preferred language list.
3689596a2c1Sopenharmony_ciint32_t PreferredLanguage::FindLanguage(const std::string &language)
3699596a2c1Sopenharmony_ci{
3709596a2c1Sopenharmony_ci    std::vector<std::string> preferredLanguageList = GetPreferredLanguageList();
3719596a2c1Sopenharmony_ci    for (size_t i = 0; i < preferredLanguageList.size(); ++i) {
3729596a2c1Sopenharmony_ci        if (preferredLanguageList[i] == language) {
3739596a2c1Sopenharmony_ci            return static_cast<int32_t>(i);
3749596a2c1Sopenharmony_ci        }
3759596a2c1Sopenharmony_ci    }
3769596a2c1Sopenharmony_ci    return -1;
3779596a2c1Sopenharmony_ci}
3789596a2c1Sopenharmony_ci
3799596a2c1Sopenharmony_ci// Join preferred language tags to string with ';'
3809596a2c1Sopenharmony_cistd::string PreferredLanguage::JoinPreferredLanguages(const std::vector<std::string> preferredLanguages)
3819596a2c1Sopenharmony_ci{
3829596a2c1Sopenharmony_ci    std::string result = "";
3839596a2c1Sopenharmony_ci    for (size_t i = 0; i < preferredLanguages.size(); ++i) {
3849596a2c1Sopenharmony_ci        result += preferredLanguages[i];
3859596a2c1Sopenharmony_ci        result += ";";
3869596a2c1Sopenharmony_ci    }
3879596a2c1Sopenharmony_ci    // delete the last ';'
3889596a2c1Sopenharmony_ci    result.pop_back();
3899596a2c1Sopenharmony_ci    return result;
3909596a2c1Sopenharmony_ci}
3919596a2c1Sopenharmony_ci
3929596a2c1Sopenharmony_ci// Set PREFERRED_LANGUAGES system parameter with preferredLanguages.
3939596a2c1Sopenharmony_ciI18nErrorCode PreferredLanguage::SetPreferredLanguages(const std::string &preferredLanguages)
3949596a2c1Sopenharmony_ci{
3959596a2c1Sopenharmony_ci    // System parameter value's length can't beyong CONFIG_LEN
3969596a2c1Sopenharmony_ci    if (preferredLanguages.length() > CONFIG_LEN) {
3979596a2c1Sopenharmony_ci        HILOG_ERROR_I18N("PreferredLanguage::SetPreferredLanguage preferred language list is too long.");
3989596a2c1Sopenharmony_ci        return I18nErrorCode::UPDATE_SYSTEM_PREFERRED_LANGUAGE_FAILED;
3999596a2c1Sopenharmony_ci    }
4009596a2c1Sopenharmony_ci    if (SetParameter(PREFERRED_LANGUAGES, preferredLanguages.data()) != 0) {
4019596a2c1Sopenharmony_ci        HILOG_ERROR_I18N("PreferredLanguage::AddPreferredLanguage udpate preferred language param failed.");
4029596a2c1Sopenharmony_ci        return I18nErrorCode::UPDATE_SYSTEM_PREFERRED_LANGUAGE_FAILED;
4039596a2c1Sopenharmony_ci    }
4049596a2c1Sopenharmony_ci    return I18nErrorCode::SUCCESS;
4059596a2c1Sopenharmony_ci}
4069596a2c1Sopenharmony_ci} // namespace I18n
4079596a2c1Sopenharmony_ci} // namespace Global
4089596a2c1Sopenharmony_ci} // namespace OHOS