!403 增加SystemLocaleManager接口

Merge pull request !403 from sunyaozu/master
This commit is contained in:
openharmony_ci 2023-05-04 03:45:35 +00:00 committed by Gitee
commit 6605abffaa
No known key found for this signature in database
GPG Key ID: 173E9B9CA92EEF8F
13 changed files with 1324 additions and 7 deletions

View File

@ -90,6 +90,7 @@ ohos_shared_library("intl_util") {
"src/i18n_normalizer.cpp",
"src/i18n_timezone.cpp",
"src/index_util.cpp",
"src/locale_compare.cpp",
"src/locale_config.cpp",
"src/locale_info.cpp",
"src/measure_data.cpp",
@ -97,6 +98,9 @@ ohos_shared_library("intl_util") {
"src/phone_number_format.cpp",
"src/plural_rules.cpp",
"src/relative_time_format.cpp",
"src/system_locale_manager.cpp",
"src/taboo.cpp",
"src/taboo_utils.cpp",
"src/utils.cpp",
]
version_script = "libintl_util.map"

View File

@ -0,0 +1,46 @@
/*
* Copyright (c) 2023 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef OHOS_GLOBAL_I18N_LOCALE_COMPARE_H
#define OHOS_GLOBAL_I18N_LOCALE_COMPARE_H
#include <map>
#include <set>
#include <string>
namespace OHOS {
namespace Global {
namespace I18n {
class LocaleCompare {
public:
static int32_t Compare(const std::string& localeTag1, const std::string& localeTag2);
private:
static bool IsSameLanguage(const std::string& langTag1, const std::string& langTag2);
static bool IsSameEnglishScript(const std::string& scriptTag1, const std::string& scriptTag2);
static bool HasMapRelation(const std::string& languageTag, const std::string& localeTag1,
const std::string& localeTag2);
static std::string hantSegment;
static std::string latnSegment;
static std::string qaagSegment;
static std::set<std::string> scriptLocales;
static std::map<std::string, std::string> hantParent;
static std::map<std::string, std::string> latnParent;
static std::map<std::string, std::string> extendedHantParent;
static std::map<std::string, std::string> extendedLatnParent;
};
} // namespace I18n
} // namespace Global
} // namespace OHOS
#endif

View File

@ -50,6 +50,9 @@ public:
static bool CheckPermission();
static bool SetUsingLocalDigit(bool flag);
static bool GetUsingLocalDigit();
static std::unordered_set<std::string> GetBlockedLanguages();
static std::unordered_set<std::string> GetBlockedRegions();
static std::unordered_set<std::string> GetLanguageBlockedRegions();
private:
static bool IsValidLanguage(const std::string &language);
@ -100,8 +103,12 @@ private:
static std::string GetDsiplayLanguageWithDialect(const std::string &language, const std::string &displayLocale);
static std::string ComputeLocale(const std::string &displayLocale);
static void ReadLangData(const char *langDataPath);
static void ProcessForbiddenRegions(const std::unordered_set<std::string> &forbiddenRegions);
static std::unordered_set<std::string> supportedLocales;
static std::unordered_set<std::string> supportedRegions;
static std::unordered_set<std::string> blockedLanguages;
static std::unordered_set<std::string> blockedRegions;
static std::unordered_map<std::string, std::unordered_set<std::string>> blockedLanguageRegions;
static std::unordered_set<std::string> whiteLanguages;
static std::map<std::string, std::string> supportedDialectLocales;
static std::unordered_map<std::string, std::string> dialectMap;

View File

@ -0,0 +1,96 @@
/*
* Copyright (c) 2023 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef OHOS_GLOBAL_SYSTEM_LOCALE_MANAGER_H
#define OHOS_GLOBAL_SYSTEM_LOCALE_MANAGER_H
#include <string>
#include <vector>
#include "collator.h"
#include "taboo_utils.h"
namespace OHOS {
namespace Global {
namespace I18n {
enum SuggestionType {
// language or region is not suggested with system region or system language.
SUGGESTION_TYPE_NONE = 0,
// language is suggested with system region or region is suggested with system language.
SUGGESTION_TYPE_RELATED = 1,
// language is suggested with sim card region.
SUGGESTION_TYPE_SIM = 2,
};
struct LocaleItem {
// language or region code.
std::string id;
// the suggestion type of language or region.
SuggestionType suggestionType;
// the name of language or region in specified language.
std::string displayName;
// the name of language or region in local language.
std::string localName;
};
struct SortOptions {
// locale use to sort language or region.
std::string localeTag;
// whether to use local name to sort language or region.
bool isUseLocalName;
// whether to put the suggested item at the top
bool isSuggestedFirst;
};
class SystemLocaleManager {
public:
SystemLocaleManager();
~SystemLocaleManager();
/**
* @brief sort input languages according to SortOptions and obtain sorted result.
*
* @param languages input language array to be sorted.
* @param options sort options.
* @return std::vector<LocaleItem> sort result.
*/
std::vector<LocaleItem> GetLanguageInfoArray(const std::vector<std::string> &languages,
const SortOptions &options);
/**
* @brief sort input countries according to SortOptions and obtain sorted result.
*
* @param regions input country array to be sorted.
* @param options sort options.
* @return std::vector<LocaleItem> sort result.
*/
std::vector<LocaleItem> GetCountryInfoArray(const std::vector<std::string> &countries, const SortOptions &options);
private:
void SortLocaleItemList(std::vector<LocaleItem> &localeItemList, const SortOptions &options);
std::unique_ptr<TabooUtils> tabooUtils;
static const char* SIM_COUNTRY_CODE_KEY;
static constexpr int CONFIG_LEN = 128;
};
} // namespace I18n
} // namespace Global
} // namespace OHOS
#endif

View File

@ -0,0 +1,77 @@
/*
* Copyright (c) 2023 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef OHOS_GLOBAL_I18N_TABOO_H
#define OHOS_GLOBAL_I18N_TABOO_H
#include <map>
#include <set>
#include <string>
#include <vector>
namespace OHOS {
namespace Global {
namespace I18n {
enum DataFileType {
CONFIG_FILE,
DATA_FILE
};
class Taboo {
public:
Taboo();
Taboo(const std::string& path);
~Taboo();
std::string ReplaceCountryName(const std::string& region, const std::string& displayLanguage,
const std::string& name);
std::string ReplaceLanguageName(const std::string& language, const std::string& displayLanguage,
const std::string& name);
private:
void ParseTabooData(const std::string& path, DataFileType fileType, const std::string& Locale = "");
void ProcessTabooConfigData(const std::string& name, const std::string& value);
void ProcessTabooLocaleData(const std::string& locale, const std::string& name, const std::string& value);
void SplitValue(const std::string& value, std::set<std::string>& collation);
std::vector<std::string> QueryKeyFallBack(const std::string& key);
std::tuple<std::string, std::string> LanguageFallBack(const std::string& language);
void ReadResourceList();
std::string GetLanguageFromFileName(const std::string& fileName);
std::set<std::string> supportedRegions; // Indicates which regions support name replacement using taboo data.
std::set<std::string> supportedLanguages; // Indicates which languages support name replacement using taboo data.
// cache the name replacement taboo data of different locale.
std::map<std::string, std::map<std::string, std::string>> localeTabooData;
std::map<std::string, std::string> resources; // Indicates which locales are supported to find taboo data.
std::string tabooDataPath = "";
std::string tabooConfigFileName = "taboo-config.xml";
std::string tabooLocaleDataFileName = "taboo-data.xml";
std::string filePathSplitor = "/";
std::string supportedRegionsTag = "regions"; // supported regions key in taboo-config.xml
std::string supportedLanguagesTag = "languages"; // supported languages key in taboo-config.xml
std::string regionKey = "region_"; // start part of region name replacement data key.
std::string languageKey = "language_"; // start part of language name replacement data key.
bool isTabooDataExist = false;
static const char* ROOT_TAG;
static const char* ITEM_TAG;
static const char* NAME_TAG;
static const char* VALUE_TAG;
char tabooDataSplitor = ',';
};
} // namespace I18n
} // namespace Global
} // namespace OHOS
#endif

View File

@ -0,0 +1,41 @@
/*
* Copyright (c) 2023 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef OHOS_GLOBAL_I18N_TABOO_UTILS_H
#define OHOS_GLOBAL_I18N_TABOO_UTILS_H
#include "taboo.h"
namespace OHOS {
namespace Global {
namespace I18n {
class TabooUtils {
public:
TabooUtils();
~TabooUtils();
std::string ReplaceCountryName(const std::string& region, const std::string& displayLanguage,
const std::string& name);
std::string ReplaceLanguageName(const std::string& language, const std::string& displayLanguage,
const std::string& name);
private:
std::shared_ptr<Taboo> GetLatestTaboo();
std::shared_ptr<Taboo> systemTaboo;
std::string systemTabooDataPath = "/system/etc/taboo/";
};
} // namespace I18n
} // namespace Global
} // namespace OHOS
#endif

View File

@ -0,0 +1,254 @@
/*
* Copyright (c) 2023 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "hilog/log.h"
#include "locale_compare.h"
#include "ohos/init_data.h"
#include "unicode/locid.h"
namespace OHOS {
namespace Global {
namespace I18n {
static constexpr OHOS::HiviewDFX::HiLogLabel LABEL = { LOG_CORE, 0xD001E00, "LocaleCompare" };
using namespace OHOS::HiviewDFX;
std::string LocaleCompare::hantSegment = "-Hant-";
std::string LocaleCompare::latnSegment = "-Latn-";
std::string LocaleCompare::qaagSegment = "-Qaag-";
std::set<std::string> LocaleCompare::scriptLocales {
"zh", "en", "es", "pt"
};
std::map<std::string, std::string> LocaleCompare::hantParent {
{ "zh-MO", "zh-Hant-HK" }
};
std::map<std::string, std::string> LocaleCompare::latnParent {
{ "en-150", "en-001" },
{ "en-AG", "en-001" },
{ "en-AI", "en-001" },
{ "en-AU", "en-001" },
{ "en-BB", "en-001" },
{ "en-BE", "en-001" },
{ "en-BM", "en-001" },
{ "en-BS", "en-001" },
{ "en-BZ", "en-001" },
{ "en-CC", "en-001" },
{ "en-CK", "en-001" },
{ "en-CX", "en-001" },
{ "en-DG", "en-001" },
{ "en-ER", "en-001" },
{ "en-FK", "en-001" },
{ "en-FM", "en-001" },
{ "en-GB", "en-001" },
{ "en-GD", "en-001" },
{ "en-GG", "en-001" },
{ "en-GI", "en-001" },
{ "en-GY", "en-001" },
{ "en-HK", "en-001" },
{ "en-IE", "en-001" },
{ "en-IM", "en-001" },
{ "en-IN", "en-001" },
{ "en-IO", "en-001" },
{ "en-JE", "en-001" },
{ "en-KI", "en-001" },
{ "en-KN", "en-001" },
{ "en-KY", "en-001" },
{ "en-LC", "en-001" },
{ "en-LR", "en-001" },
{ "en-LS", "en-001" },
{ "en-MM", "en-001" },
{ "en-MO", "en-001" },
{ "en-MS", "en-001" },
{ "en-MT", "en-001" },
{ "en-MY", "en-001" },
{ "en-NF", "en-001" },
{ "en-NR", "en-001" },
{ "en-NU", "en-001" },
{ "en-NZ", "en-001" },
{ "en-PG", "en-001" },
{ "en-PK", "en-001" },
{ "en-PN", "en-001" },
{ "en-PW", "en-001" },
{ "en-SB", "en-001" },
{ "en-SC", "en-001" },
{ "en-SD", "en-001" },
{ "en-SG", "en-001" },
{ "en-SH", "en-001" },
{ "en-SL", "en-001" },
{ "en-SS", "en-001" },
{ "en-SX", "en-001" },
{ "en-SZ", "en-001" },
{ "en-TC", "en-001" },
{ "en-TK", "en-001" },
{ "en-TT", "en-001" },
{ "en-TV", "en-001" },
{ "en-VC", "en-001" },
{ "en-VG", "en-001" },
{ "en-WS", "en-001" },
{ "en-ZG", "en-001" },
{ "es-AR", "es-419" },
{ "es-BO", "es-419" },
{ "es-BR", "es-419" },
{ "es-CL", "es-419" },
{ "es-CO", "es-419" },
{ "es-CR", "es-419" },
{ "es-CU", "es-419" },
{ "es-DO", "es-419" },
{ "es-EC", "es-419" },
{ "es-GT", "es-419" },
{ "es-HN", "es-419" },
{ "es-MX", "es-419" },
{ "es-NI", "es-419" },
{ "es-PA", "es-419" },
{ "es-PE", "es-419" },
{ "es-PR", "es-419" },
{ "es-PY", "es-419" },
{ "es-SV", "es-419" },
{ "es-US", "es-419" },
{ "es-UY", "es-419" },
{ "es-VE", "es-419" },
{ "pt-AO", "pt-PT" },
{ "pt-CH", "pt-PT" },
{ "pt-CV", "pt-PT" },
{ "pt-GQ", "pt-PT" },
{ "pt-GW", "pt-PT" },
{ "pt-LU", "pt-PT" },
{ "pt-MO", "pt-PT" },
{ "pt-MZ", "pt-PT" },
{ "pt-ST", "pt-PT" },
{ "pt-TL", "pt-PT" }
};
std::map<std::string, std::string> LocaleCompare::extendedHantParent {};
std::map<std::string, std::string> LocaleCompare::extendedLatnParent {};
int32_t LocaleCompare::Compare(const std::string& localeTag1, const std::string& localeTag2)
{
UErrorCode status = U_ZERO_ERROR;
icu::Locale locale1 = icu::Locale::forLanguageTag(icu::StringPiece(localeTag1), status);
icu::Locale locale2 = icu::Locale::forLanguageTag(icu::StringPiece(localeTag2), status);
int32_t segmentScore = 3;
int32_t mapScore = 0;
int32_t score = 0;
std::string language1 = locale1.getLanguage();
std::string language2 = locale2.getLanguage();
if (IsSameLanguage(language1, language2)) {
score += segmentScore;
} else {
return -1;
}
std::string localeBaseName1 = locale1.getBaseName();
std::string localeBaseName2 = locale2.getBaseName();
if (HasMapRelation(language1, localeBaseName1, localeBaseName2)) {
return mapScore;
}
std::string region1 = locale1.getCountry();
std::string region2 = locale2.getCountry();
locale1.addLikelySubtags(status);
locale2.addLikelySubtags(status);
if (U_FAILURE(status)) {
HiLog::Error(LABEL, "LocaleCompare::Compare add likely subtags failed.");
return -1;
}
std::string script1 = locale1.getScript();
std::string script2 = locale2.getScript();
if (script1.compare(script2) == 0 || (language1.compare("en") == 0 && IsSameEnglishScript(script1, script2))) {
score += segmentScore;
if (region2.length() == 0) {
++score;
}
} else {
return -1;
}
if (region1.length() != 0 && region1.compare(region2) == 0) {
score += segmentScore;
}
return score;
}
bool LocaleCompare::IsSameLanguage(const std::string& langTag1, const std::string& langTag2)
{
if (langTag1.compare(langTag2) == 0) {
return true;
}
if (langTag1.compare("tl") == 0 && langTag2.compare("fil") == 0) {
return true;
}
if (langTag1.compare("fil") == 0 && langTag2.compare("tl") == 0) {
return true;
}
return false;
}
bool LocaleCompare::IsSameEnglishScript(const std::string& scriptTag1, const std::string& scriptTag2)
{
if (scriptTag1.compare("Qaag") == 0 && scriptTag2.compare("Latn") == 0) {
return true;
}
if (scriptTag1.compare("Latn") == 0 && scriptTag2.compare("Qaag") == 0) {
return true;
}
return false;
}
bool LocaleCompare::HasMapRelation(const std::string& languageTag, const std::string& localeTag1,
const std::string& localeTag2)
{
if (scriptLocales.find(languageTag) == scriptLocales.end()) {
return false;
}
if (hantParent.find(localeTag1) != hantParent.end()) {
if (localeTag2.compare(hantParent[localeTag1]) == 0) {
return true;
}
}
if (latnParent.find(localeTag1) != latnParent.end()) {
if (localeTag2.compare(hantParent[localeTag1]) == 0) {
return true;
}
}
if (extendedHantParent.size() == 0) {
for (auto it = hantParent.begin(); it != hantParent.end(); ++it) {
std::string key = it->first;
size_t languageLength = key.find("-");
std::string language = key.substr(0, languageLength);
std::string region = key.substr(languageLength + 1);
extendedHantParent[language + hantSegment + region] = it->second;
}
}
if (extendedHantParent.find(localeTag1) != extendedHantParent.end()) {
if (localeTag2.compare(extendedHantParent[localeTag1]) == 0) {
return true;
}
}
if (extendedLatnParent.size() == 0) {
for (auto it = latnParent.begin(); it != latnParent.end(); ++it) {
std::string key = it->first;
size_t languageLength = key.find("-");
std::string language = key.substr(0, languageLength);
std::string region = key.substr(languageLength + 1);
extendedHantParent[language + latnSegment + region] = it->second;
if (language.compare("en") == 0) {
extendedLatnParent[language + qaagSegment + region] = it->second;
}
}
}
if (extendedLatnParent.find(localeTag1) != extendedLatnParent.end()) {
if (localeTag2.compare(extendedLatnParent[localeTag1]) == 0) {
return true;
}
}
return false;
}
} // namespace I18n
} // namespace Global
} // OHOS

View File

@ -73,6 +73,9 @@ const char *LocaleConfig::rootTag = "languages";
const char *LocaleConfig::secondRootTag = "lang";
unordered_set<string> LocaleConfig::supportedLocales;
unordered_set<string> LocaleConfig::supportedRegions;
unordered_set<string> LocaleConfig::blockedLanguages;
unordered_set<string> LocaleConfig::blockedRegions;
unordered_map<string, unordered_set<string>> LocaleConfig::blockedLanguageRegions;
unordered_set<string> LocaleConfig::whiteLanguages;
unordered_map<string, string> LocaleConfig::dialectMap {
{ "es-Latn-419", "es-Latn-419" },
@ -371,7 +374,7 @@ bool LocaleConfig::SetSystemLanguage(const string &language)
std::string oldLanguage = GetSystemLanguage();
if (SetParameter(LANGUAGE_KEY, language.data()) == 0) {
bool isUpdateSuccess = UpdateSystemLocale(language);
if(isUpdateSuccess) {
if (isUpdateSuccess) {
#ifdef SUPPORT_GRAPHICS
auto appMgrClient = std::make_unique<AppExecFwk::AppMgrClient>();
AppExecFwk::Configuration configuration;
@ -627,6 +630,24 @@ void LocaleConfig::GetListFromFile(const char *path, const char *resourceName, u
xmlFreeDoc(doc);
}
void LocaleConfig::ProcessForbiddenRegions(const unordered_set<string> &forbiddenRegions)
{
for (auto it = forbiddenRegions.begin(); it != forbiddenRegions.end(); ++it) {
size_t pos = it->rfind("-");
std::string language = it->substr(0, pos);
std::string region = it->substr(pos + 1);
if (language.compare("*") == 0) {
blockedRegions.insert(region);
} else {
if (blockedLanguageRegions.find(language) == blockedLanguageRegions.end()) {
blockedLanguageRegions[language] = { region };
} else {
blockedLanguageRegions[language].insert(region);
}
}
}
}
void LocaleConfig::Expunge(unordered_set<string> &src, const unordered_set<string> &another)
{
for (auto iter = src.begin(); iter != src.end();) {
@ -644,11 +665,11 @@ bool LocaleConfig::InitializeLists()
GetListFromFile(SUPPORTED_REGIONS_PATH, SUPPORTED_REGIONS_NAME, supportedRegions);
unordered_set<string> forbiddenRegions;
GetListFromFile(FORBIDDEN_REGIONS_PATH, FORBIDDEN_REGIONS_NAME, forbiddenRegions);
Expunge(supportedRegions, forbiddenRegions);
ProcessForbiddenRegions(forbiddenRegions);
Expunge(supportedRegions, blockedRegions);
GetListFromFile(WHITE_LANGUAGES_PATH, WHITE_LANGUAGES_NAME, whiteLanguages);
unordered_set<string> forbiddenLanguages;
GetListFromFile(FORBIDDEN_LANGUAGES_PATH, FORBIDDEN_LANGUAGES_NAME, forbiddenLanguages);
Expunge(whiteLanguages, forbiddenLanguages);
GetListFromFile(FORBIDDEN_LANGUAGES_PATH, FORBIDDEN_LANGUAGES_NAME, blockedLanguages);
Expunge(whiteLanguages, blockedLanguages);
GetListFromFile(SUPPORTED_LOCALES_PATH, SUPPORTED_LOCALES_NAME, supportedLocales);
return true;
}
@ -1114,7 +1135,7 @@ bool LocaleConfig::UpdateSystemLocale(const std::string &language)
return false;
}
std::string region = systemLocale.getCountry();
std::string extendParam;
size_t pos = systemLocaleTag.find("-u-");
if (pos < systemLocaleTag.length()) {
@ -1134,6 +1155,26 @@ bool LocaleConfig::UpdateSystemLocale(const std::string &language)
}
return SetSystemLocale(finalLocaleTag);
}
std::unordered_set<std::string> LocaleConfig::GetBlockedLanguages()
{
return blockedLanguages;
}
std::unordered_set<std::string> LocaleConfig::GetBlockedRegions()
{
return blockedRegions;
}
std::unordered_set<std::string> LocaleConfig::GetLanguageBlockedRegions()
{
std::string systemLanguage = LocaleConfig::GetSystemLanguage();
if (blockedLanguageRegions.find(systemLanguage) != blockedLanguageRegions.end()) {
return blockedLanguageRegions[systemLanguage];
}
std::unordered_set<std::string> emptyResult;
return emptyResult;
}
} // namespace I18n
} // namespace Global
} // namespace OHOS

View File

@ -0,0 +1,153 @@
/*
* Copyright (c) 2023 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "hilog/log.h"
#include "locale_config.h"
#include "system_locale_manager.h"
#include "utils.h"
namespace OHOS {
namespace Global {
namespace I18n {
static constexpr OHOS::HiviewDFX::HiLogLabel LABEL = { LOG_CORE, 0xD001E00, "SystemLocaleManager" };
using namespace OHOS::HiviewDFX;
const char* SystemLocaleManager::SIM_COUNTRY_CODE_KEY = "telephony.sim.countryCode0";
SystemLocaleManager::SystemLocaleManager()
{
tabooUtils = std::make_unique<TabooUtils>();
}
SystemLocaleManager::~SystemLocaleManager()
{
}
/**
* Language arrays are sorted according to the following steps:
* 1. Remove blocked languages.
* 2. Compute language locale displayName; If options.isUseLocalName is true, compute language local displayName.
* replace display name with taboo data.
* 3. Judge whether language is suggested with system region and sim card region.
* 4. Sort the languages use locale displayName, local displyName and suggestion infomation.
*/
std::vector<LocaleItem> SystemLocaleManager::GetLanguageInfoArray(const std::vector<std::string> &languages,
const SortOptions &options)
{
std::unordered_set<std::string> blockedLanguages = LocaleConfig::GetBlockedLanguages();
std::vector<LocaleItem> localeItemList;
for (auto it = languages.begin(); it != languages.end(); ++it) {
if (blockedLanguages.find(*it) != blockedLanguages.end()) {
continue;
}
std::string languageDisplayName = LocaleConfig::GetDisplayLanguage(*it, options.localeTag, true);
languageDisplayName = tabooUtils->ReplaceLanguageName(*it, options.localeTag, languageDisplayName);
std::string languageNativeName;
if (options.isUseLocalName) {
languageNativeName = LocaleConfig::GetDisplayLanguage(*it, *it, true);
languageNativeName = tabooUtils->ReplaceLanguageName(*it, *it, languageNativeName);
}
bool isSuggestedWithSystemRegion = LocaleConfig::IsSuggested(*it, LocaleConfig::GetSystemRegion());
std::string simRegion = ReadSystemParameter(SIM_COUNTRY_CODE_KEY, CONFIG_LEN);
bool isSuggestedWithSimRegion = false;
if (simRegion.length() > 0) {
isSuggestedWithSimRegion = LocaleConfig::IsSuggested(*it, simRegion);
}
SuggestionType suggestionType = SuggestionType::SUGGESTION_TYPE_NONE;
if (isSuggestedWithSimRegion) {
suggestionType = SuggestionType::SUGGESTION_TYPE_SIM;
} else if (isSuggestedWithSystemRegion) {
suggestionType = SuggestionType::SUGGESTION_TYPE_RELATED;
}
LocaleItem item { *it, suggestionType, languageDisplayName, languageNativeName };
localeItemList.push_back(item);
}
SortLocaleItemList(localeItemList, options);
return localeItemList;
}
/**
* Region arrays are sorted according to the following steps:
* 1. Remove blocked regions and blocked regions under system Language.
* 2. Compute region locale displayName; replace display name with taboo data.
* 3. Judge whether region is suggested with system language.
* 4. Sort the regions use locale displayName and suggestion infomation.
*/
std::vector<LocaleItem> SystemLocaleManager::GetCountryInfoArray(const std::vector<std::string> &countries,
const SortOptions &options)
{
std::unordered_set<std::string> blockedRegions = LocaleConfig::GetBlockedRegions();
std::unordered_set<std::string> blockedLanguageRegions = LocaleConfig::GetLanguageBlockedRegions();
std::vector<LocaleItem> localeItemList;
for (auto it = countries.begin(); it != countries.end(); ++it) {
if (blockedRegions.find(*it) != blockedRegions.end() || blockedLanguageRegions.find(*it) !=
blockedLanguageRegions.end()) {
continue;
}
std::string regionDisplayName = LocaleConfig::GetDisplayRegion(*it, options.localeTag, true);
regionDisplayName = tabooUtils->ReplaceCountryName(*it, options.localeTag, regionDisplayName);
bool isSuggestedRegion = LocaleConfig::IsSuggested(LocaleConfig::GetSystemLanguage(), *it);
SuggestionType suggestionType = SuggestionType::SUGGESTION_TYPE_NONE;
if (isSuggestedRegion) {
suggestionType = SuggestionType::SUGGESTION_TYPE_RELATED;
}
LocaleItem item { *it, suggestionType, regionDisplayName, "" };
localeItemList.push_back(item);
}
SortLocaleItemList(localeItemList, options);
return localeItemList;
}
void SystemLocaleManager::SortLocaleItemList(std::vector<LocaleItem> &localeItemList, const SortOptions &options)
{
std::vector<std::string> collatorLocaleTags { options.localeTag };
std::map<std::string, std::string> collatorOptions {};
Collator *collator = new Collator(collatorLocaleTags, collatorOptions);
auto compareFunc = [collator](LocaleItem item1, LocaleItem item2) {
if (item1.suggestionType < item2.suggestionType) {
return false;
} else if (item1.suggestionType > item2.suggestionType) {
return true;
}
CompareResult result = CompareResult::INVALID;
if (item1.localName.length() != 0) {
result = collator->Compare(item1.localName, item2.localName);
if (result == CompareResult::SMALLER) {
return true;
}
if (result == CompareResult::INVALID) {
HiLog::Error(LABEL, "SystemLocaleManager: invalid compare result for local name.");
}
return false;
}
result = collator->Compare(item1.displayName, item2.displayName);
if (result == CompareResult::SMALLER) {
return true;
}
if (result == CompareResult::INVALID) {
HiLog::Error(LABEL, "SystemLocaleManager: invalid compare result for display name.");
}
return false;
};
if (options.isSuggestedFirst) {
std::sort(localeItemList.begin(), localeItemList.end(), compareFunc);
} else {
std::sort(localeItemList.begin(), localeItemList.end(), compareFunc);
}
delete collator;
}
} // I18n
} // Global
} // OHOS

View File

@ -0,0 +1,272 @@
/*
* Copyright (c) 2023 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <filesystem>
#include <sys/stat.h>
#include <string.h>
#include "hilog/log.h"
#include "libxml/globals.h"
#include "libxml/tree.h"
#include "libxml/xmlstring.h"
#include "locale_compare.h"
#include "taboo.h"
namespace OHOS {
namespace Global {
namespace I18n {
static constexpr OHOS::HiviewDFX::HiLogLabel LABEL = { LOG_CORE, 0xD001E00, "Taboo" };
using namespace OHOS::HiviewDFX;
const char* Taboo::ROOT_TAG = "taboo";
const char* Taboo::ITEM_TAG = "item";
const char* Taboo::NAME_TAG = "name";
const char* Taboo::VALUE_TAG = "value";
Taboo::Taboo()
{
}
Taboo::Taboo(const std::string& path) : tabooDataPath(path)
{
using std::filesystem::directory_iterator;
std::string tabooConfigFilePath = tabooDataPath + tabooConfigFileName;
struct stat s;
isTabooDataExist = stat(tabooConfigFilePath.c_str(), &s) == 0;
if (isTabooDataExist) {
// parse taboo-config.xml to obtain supported regions and languages for name replacement.
ParseTabooData(tabooConfigFilePath, DataFileType::CONFIG_FILE);
ReadResourceList();
}
}
Taboo::~Taboo()
{
}
std::string Taboo::ReplaceCountryName(const std::string& region, const std::string& displayLanguage,
const std::string& name)
{
if (!isTabooDataExist) {
HiLog::Info(LABEL, "Taboo::ReplaceCountryName Taboo data not exist.");
return name;
}
if (supportedRegions.find(region) == supportedRegions.end()) {
HiLog::Info(LABEL, "Taboo::ReplaceCountryName taboo data don't support region %{public}s", region.c_str());
return name;
}
std::string key = regionKey + region;
std::vector<std::string> fallbackRegionKeys = QueryKeyFallBack(key);
std::string fallbackLanguage;
std::string fileName;
std::tie(fallbackLanguage, fileName) = LanguageFallBack(displayLanguage);
if (fallbackLanguage.length() == 0) {
HiLog::Info(LABEL, "Taboo::ReplaceCountryName language %{public}s fallback failed", displayLanguage.c_str());
return name;
}
if (localeTabooData.find(fallbackLanguage) == localeTabooData.end()) {
localeTabooData[fallbackLanguage] = {};
std::string localeTabooDataFilePath = tabooDataPath + fileName + filePathSplitor + tabooLocaleDataFileName;
ParseTabooData(localeTabooDataFilePath, DataFileType::DATA_FILE, fallbackLanguage);
}
auto tabooData = localeTabooData[fallbackLanguage];
for (auto it = fallbackRegionKeys.begin(); it != fallbackRegionKeys.end(); ++it) {
if (tabooData.find(*it) != tabooData.end()) {
return tabooData[*it];
}
}
HiLog::Info(LABEL, "Taboo::ReplaceCountryName not find taboo data correspond to region %{public}s",
region.c_str());
return name;
}
std::string Taboo::ReplaceLanguageName(const std::string& language, const std::string& displayLanguage,
const std::string& name)
{
if (!isTabooDataExist) {
HiLog::Info(LABEL, "Taboo::ReplaceLanguageName Taboo data not exist.");
return name;
}
if (supportedLanguages.find(language) == supportedLanguages.end()) {
HiLog::Error(LABEL, "Taboo::ReplaceLanguageName taboo data don't support language %{public}s",
language.c_str());
return name;
}
std::string key = languageKey + language;
std::vector<std::string> fallbackLanguageKeys = QueryKeyFallBack(key);
std::string fallbackLanguage;
std::string fileName;
std::tie(fallbackLanguage, fileName) = LanguageFallBack(displayLanguage);
if (fallbackLanguage.size() == 0) {
HiLog::Error(LABEL, "Taboo::ReplaceLanguageName language %{public}s fallback failed", displayLanguage.c_str());
return name;
}
if (localeTabooData.find(fallbackLanguage) == localeTabooData.end()) {
localeTabooData[fallbackLanguage] = {};
std::string localeTabooDataFilePath = tabooDataPath + fileName + filePathSplitor + tabooLocaleDataFileName;
ParseTabooData(localeTabooDataFilePath, DataFileType::DATA_FILE, fallbackLanguage);
}
auto tabooData = localeTabooData[fallbackLanguage];
for (auto it = fallbackLanguageKeys.begin(); it != fallbackLanguageKeys.end(); ++it) {
if (tabooData.find(*it) != tabooData.end()) {
return tabooData[*it];
}
}
HiLog::Error(LABEL, "Taboo::ReplaceLanguageName not find taboo data correspond to language %{public}s",
language.c_str());
return name;
}
void Taboo::ParseTabooData(const std::string& path, DataFileType fileType, const std::string& locale)
{
xmlKeepBlanksDefault(0);
xmlDocPtr doc = xmlParseFile(path.c_str());
if (doc == nullptr) {
HiLog::Error(LABEL, "Taboo parse taboo data file failed: %{public}s", path.c_str());
return;
}
xmlNodePtr cur = xmlDocGetRootElement(doc);
if (cur == nullptr || xmlStrcmp(cur->name, reinterpret_cast<const xmlChar*>(ROOT_TAG)) != 0) {
xmlFreeDoc(doc);
HiLog::Error(LABEL, "Taboo get root tag from taboo data file failed: %{public}s", path.c_str());
return;
}
cur = cur->xmlChildrenNode;
const xmlChar* nameTag = reinterpret_cast<const xmlChar*>(NAME_TAG);
const xmlChar* valueTag = reinterpret_cast<const xmlChar*>(VALUE_TAG);
while (cur != nullptr && xmlStrcmp(cur->name, reinterpret_cast<const xmlChar*>(ITEM_TAG)) == 0) {
xmlChar* name = xmlGetProp(cur, nameTag);
xmlChar* value = xmlGetProp(cur, valueTag);
if (name == nullptr || value == nullptr) {
HiLog::Error(LABEL, "Taboo get name and value property failed: %{public}s", path.c_str());
cur = cur->next;
continue;
}
std::string nameStr = reinterpret_cast<const char*>(name);
std::string valueStr = reinterpret_cast<const char*>(value);
switch (fileType) {
case DataFileType::CONFIG_FILE:
ProcessTabooConfigData(nameStr, valueStr);
case DataFileType::DATA_FILE:
ProcessTabooLocaleData(locale, nameStr, valueStr);
}
xmlFree(name);
xmlFree(value);
cur = cur->next;
}
}
void Taboo::ProcessTabooConfigData(const std::string& name, const std::string& value)
{
if (name.compare(supportedRegionsTag) == 0) {
SplitValue(value, supportedRegions);
} else if (name.compare(supportedLanguagesTag) == 0) {
SplitValue(value, supportedLanguages);
}
}
void Taboo::ProcessTabooLocaleData(const std::string& locale, const std::string& name, const std::string& value)
{
if (localeTabooData.find(locale) != localeTabooData.end()) {
localeTabooData[locale][name] = value;
} else {
std::map<std::string, std::string> data;
data[name] = value;
localeTabooData[locale] = data;
}
}
void Taboo::SplitValue(const std::string& value, std::set<std::string>& collation)
{
size_t startPos = 0;
while (startPos < value.length()) {
size_t endPos = value.find(tabooDataSplitor, startPos);
if (endPos == std::string::npos) {
collation.insert(value.substr(startPos));
endPos = value.length();
} else {
collation.insert(value.substr(startPos, endPos - startPos));
}
startPos = endPos + 1;
}
}
std::vector<std::string> Taboo::QueryKeyFallBack(const std::string& key)
{
std::vector<std::string> fallback;
fallback.push_back(key + "_r_all");
return fallback;
}
std::tuple<std::string, std::string> Taboo::LanguageFallBack(const std::string& language)
{
std::string bestMatch;
std::string fileName;
int32_t bestScore = -1;
for (auto it = resources.begin(); it != resources.end(); ++it) {
std::string resLanguage = it->first;
int32_t score = LocaleCompare::Compare(language, resLanguage);
if (score > bestScore) {
bestMatch = resLanguage;
fileName = it->second;
bestScore = score;
}
}
if (bestScore < 0) {
return std::make_tuple("", "");
}
return std::make_tuple(bestMatch, fileName);
}
void Taboo::ReadResourceList()
{
using std::filesystem::directory_iterator;
struct stat s;
for (const auto &dirEntry : directory_iterator{tabooDataPath}) {
std::string path = dirEntry.path();
if (stat(path.c_str(), &s) != 0) {
HiLog::Error(LABEL, "get path status failed");
continue;
}
if (s.st_mode & S_IFDIR) {
std::string fileName = path.substr(tabooDataPath.length());
std::string language = GetLanguageFromFileName(fileName);
resources[language] = fileName;
}
}
}
std::string Taboo::GetLanguageFromFileName(const std::string& fileName)
{
if (fileName.length() == 3) {
return "en";
}
std::string language = fileName.substr(4);
if (language[0] == 'b' && language[1] == '+') {
language = language.substr(2);
}
size_t pos = language.find("+");
if (pos != std::string::npos) {
language = language.replace(pos, 1, "-");
}
pos = language.find("-r");
if (pos != std::string::npos) {
language = language.replace(pos, 2, "-");
}
return language;
}
} // namespace I18n
} // namespace Global
} // namespace OHOS

View File

@ -0,0 +1,50 @@
/*
* Copyright (c) 2023 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "taboo_utils.h"
namespace OHOS {
namespace Global {
namespace I18n {
TabooUtils::TabooUtils()
{
systemTaboo = std::make_shared<Taboo>(systemTabooDataPath);
}
TabooUtils::~TabooUtils()
{
}
std::string TabooUtils::ReplaceCountryName(const std::string& region, const std::string& displayLanguage,
const std::string& name)
{
std::shared_ptr<Taboo> taboo = GetLatestTaboo();
return taboo->ReplaceCountryName(region, displayLanguage, name);
}
std::string TabooUtils::ReplaceLanguageName(const std::string& language, const std::string& displayLanguage,
const std::string& name)
{
std::shared_ptr<Taboo> taboo = GetLatestTaboo();
return taboo->ReplaceLanguageName(language, displayLanguage, name);
}
std::shared_ptr<Taboo> TabooUtils::GetLatestTaboo()
{
return systemTaboo;
}
} // namespace I18n
} // namespace Global
} // namespace OHOS

View File

@ -29,6 +29,7 @@
#include "number_format.h"
#include "phone_number_format.h"
#include "preferred_language.h"
#include "system_locale_manager.h"
namespace OHOS {
namespace Global {
@ -104,6 +105,7 @@ public:
static napi_value InitUtil(napi_env env, napi_value exports);
static napi_value System(napi_env env, napi_value exports);
static napi_value InitI18nNormalizer(napi_env env, napi_value exports);
static napi_value InitSystemLocaleManager(napi_env env, napi_value exports);
private:
static napi_value PhoneNumberFormatConstructor(napi_env env, napi_callback_info info);
@ -195,6 +197,18 @@ private:
static napi_value I18nNormalizerConstructor(napi_env env, napi_callback_info info);
static napi_value Normalize(napi_env env, napi_callback_info info);
static napi_value SystemLocaleManagerConstructor(napi_env env, napi_callback_info info);
bool InitSystemLocaleManagerContext(napi_env env, napi_callback_info info);
static napi_value GetLanguageInfoArray(napi_env env, napi_callback_info info);
static napi_value getCountryInfoArray(napi_env env, napi_callback_info info);
static void GetStringArrayFromJsParam(napi_env env, napi_value &jsArray, std::vector<std::string> &strArray);
static void GetSortOptionsFromJsParam(napi_env env, napi_value &jsOptions, SortOptions &options);
static void GetBoolOptionValue(napi_env env, napi_value &options, const std::string &optionName, bool &boolVal);
static napi_value CreateLocaleItemArray(napi_env env, const std::vector<LocaleItem> &localeItemList);
static napi_value CreateLocaleItem(napi_env env, const LocaleItem &localeItem);
static napi_value CreateString(napi_env env, const std::string &str);
static napi_value CreateSuggestionType(napi_env env, SuggestionType suggestionType);
static const int32_t NORMALIZER_MODE_NFC = 1;
static const int32_t NORMALIZER_MODE_NFD = 2;
static const int32_t NORMALIZER_MODE_NFKC = 3;
@ -212,6 +226,7 @@ private:
std::unique_ptr<IndexUtil> indexUtil_ = nullptr;
std::unique_ptr<I18nTimeZone> timezone_ = nullptr;
std::unique_ptr<I18nNormalizer> normalizer_ = nullptr;
std::unique_ptr<SystemLocaleManager> systemLocaleManager_ = nullptr;
};
} // namespace I18n
} // namespace Global

View File

@ -267,7 +267,8 @@ napi_value I18nAddon::Init(napi_env env, napi_value exports)
DECLARE_NAPI_PROPERTY("Normalizer", CreateI18nNormalizerObject(env, initStatus)),
DECLARE_NAPI_PROPERTY("NormalizerMode", CreateI18NNormalizerModeEnum(env, initStatus))
};
initStatus = napi_define_properties(env, exports, sizeof(properties) / sizeof(napi_property_descriptor), properties);
initStatus = napi_define_properties(env, exports, sizeof(properties) / sizeof(napi_property_descriptor),
properties);
if (initStatus != napi_ok) {
HiLog::Error(LABEL, "Failed to set properties at init");
return nullptr;
@ -3921,6 +3922,265 @@ napi_value I18nAddon::Normalize(napi_env env, napi_callback_info info)
return result;
}
napi_value I18nAddon::InitSystemLocaleManager(napi_env env, napi_value exports)
{
napi_status status = napi_ok;
napi_property_descriptor properties[] = {
DECLARE_NAPI_FUNCTION("getLanguageInfoArray", GetLanguageInfoArray),
DECLARE_NAPI_FUNCTION("getCountryInfoArray", getCountryInfoArray)
};
napi_value constructor = nullptr;
status = napi_define_class(env, "SystemLocaleManager", NAPI_AUTO_LENGTH, SystemLocaleManagerConstructor, nullptr,
sizeof(properties) / sizeof(napi_property_descriptor), properties, &constructor);
if (status != napi_ok) {
HiLog::Error(LABEL, "Define class failed when InitSystemLocaleManager");
return nullptr;
}
status = napi_set_named_property(env, exports, "SystemLocaleManager", constructor);
if (status != napi_ok) {
HiLog::Error(LABEL, "Set property failed when InitSystemLocaleManager");
return nullptr;
}
return exports;
}
napi_value I18nAddon::SystemLocaleManagerConstructor(napi_env env, napi_callback_info info)
{
size_t argc = 0;
napi_value argv[0];
napi_value thisVar = nullptr;
void *data = nullptr;
napi_status status = napi_get_cb_info(env, info, &argc, argv, &thisVar, &data);
if (status != napi_ok) {
return nullptr;
}
std::unique_ptr<I18nAddon> obj = nullptr;
obj = std::make_unique<I18nAddon>();
status =
napi_wrap(env, thisVar, reinterpret_cast<void *>(obj.get()), I18nAddon::Destructor, nullptr, nullptr);
if (status != napi_ok) {
HiLog::Error(LABEL, "Wrap I18nAddon failed");
return nullptr;
}
if (!obj->InitSystemLocaleManagerContext(env, info)) {
HiLog::Error(LABEL, "Init SystemLocaleManager failed");
return nullptr;
}
obj.release();
return thisVar;
}
bool I18nAddon::InitSystemLocaleManagerContext(napi_env env, napi_callback_info info)
{
napi_value global = nullptr;
napi_status status = napi_get_global(env, &global);
if (status != napi_ok) {
HiLog::Error(LABEL, "Get global failed");
return false;
}
env_ = env;
systemLocaleManager_ = std::make_unique<SystemLocaleManager>();
return systemLocaleManager_ != nullptr;
}
napi_value I18nAddon::GetLanguageInfoArray(napi_env env, napi_callback_info info)
{
size_t argc = 2;
napi_value argv[2] = { 0 };
napi_value thisVar = nullptr;
void *data = nullptr;
napi_status status = napi_get_cb_info(env, info, &argc, argv, &thisVar, &data);
if (status != napi_ok) {
HiLog::Error(LABEL, "can not obtain getLanguageInfoArray function param.");
ErrorUtil::NapiThrow(env, I18N_NOT_FOUND, true);
}
std::vector<std::string> languageList;
GetStringArrayFromJsParam(env, argv[0], languageList);
SortOptions options;
GetSortOptionsFromJsParam(env, argv[1], options);
I18nAddon *obj = nullptr;
status = napi_unwrap(env, thisVar, reinterpret_cast<void **>(&obj));
if (status != napi_ok || !obj || !obj->systemLocaleManager_) {
HiLog::Error(LABEL, "Get SystemLocaleManager object failed");
return nullptr;
}
std::vector<LocaleItem> localeItemList = obj->systemLocaleManager_->GetLanguageInfoArray(languageList, options);
napi_value result = CreateLocaleItemArray(env, localeItemList);
return result;
}
napi_value I18nAddon::getCountryInfoArray(napi_env env, napi_callback_info info)
{
size_t argc = 2;
napi_value argv[2] = { 0 };
napi_value thisVar = nullptr;
void *data = nullptr;
napi_status status = napi_get_cb_info(env, info, &argc, argv, &thisVar, &data);
if (status != napi_ok) {
HiLog::Error(LABEL, "can not obtain getCountryInfoArray function param.");
ErrorUtil::NapiThrow(env, I18N_NOT_FOUND, true);
}
std::vector<std::string> countryList;
GetStringArrayFromJsParam(env, argv[0], countryList);
SortOptions options;
GetSortOptionsFromJsParam(env, argv[1], options);
I18nAddon *obj = nullptr;
status = napi_unwrap(env, thisVar, reinterpret_cast<void **>(&obj));
if (status != napi_ok || !obj || !obj->systemLocaleManager_) {
HiLog::Error(LABEL, "Get SystemLocaleManager object failed");
return nullptr;
}
std::vector<LocaleItem> localeItemList = obj->systemLocaleManager_->GetCountryInfoArray(countryList, options);
napi_value result = CreateLocaleItemArray(env, localeItemList);
return result;
}
void I18nAddon::GetStringArrayFromJsParam(napi_env env, napi_value &jsArray, std::vector<std::string> &strArray)
{
if (jsArray == nullptr) {
HiLog::Error(LABEL, "js string array param not found.");
ErrorUtil::NapiThrow(env, I18N_NOT_FOUND, true);
}
bool isArray = false;
napi_status status = napi_is_array(env, jsArray, &isArray);
if (status != napi_ok || !isArray) {
HiLog::Error(LABEL, "js string array is not an Array.");
ErrorUtil::NapiThrow(env, I18N_NOT_VALID, true);
}
uint32_t arrayLength = 0;
napi_get_array_length(env, jsArray, &arrayLength);
napi_value element = nullptr;
int32_t code = 0;
for (uint32_t i = 0; i < arrayLength; ++i) {
napi_get_element(env, jsArray, i, &element);
std::string str = GetString(env, element, code);
if (code != 0) {
HiLog::Error(LABEL, "can't get string from js array param.");
ErrorUtil::NapiThrow(env, I18N_NOT_VALID, true);
}
strArray.push_back(str);
}
}
void I18nAddon::GetSortOptionsFromJsParam(napi_env env, napi_value &jsOptions, SortOptions &options)
{
if (jsOptions == nullptr) {
HiLog::Error(LABEL, "SortOptions js param not found.");
ErrorUtil::NapiThrow(env, I18N_NOT_FOUND, true);
}
std::string localeTag;
GetOptionValue(env, jsOptions, "locale", localeTag);
options.localeTag = localeTag;
bool isUseLocalName;
GetBoolOptionValue(env, jsOptions, "isUseLocalName", isUseLocalName);
options.isUseLocalName = isUseLocalName;
bool isSuggestedFirst;
GetBoolOptionValue(env, jsOptions, "isSuggestedFirst", isSuggestedFirst);
options.isSuggestedFirst = isSuggestedFirst;
}
void I18nAddon::GetBoolOptionValue(napi_env env, napi_value &options, const std::string &optionName, bool &boolVal)
{
napi_valuetype type = napi_undefined;
napi_status status = napi_typeof(env, options, &type);
if (status != napi_ok && type != napi_object) {
HiLog::Error(LABEL, "option is not an object");
ErrorUtil::NapiThrow(env, I18N_NOT_VALID, true);
}
bool hasProperty = false;
status = napi_has_named_property(env, options, optionName.c_str(), &hasProperty);
if (status != napi_ok || !hasProperty) {
HiLog::Error(LABEL, "option don't have property %{public}s", optionName.c_str());
ErrorUtil::NapiThrow(env, I18N_NOT_VALID, true);
}
napi_value optionValue = nullptr;
status = napi_get_named_property(env, options, optionName.c_str(), &optionValue);
if (status != napi_ok) {
HiLog::Error(LABEL, "get option %{public}s failed", optionName.c_str());
ErrorUtil::NapiThrow(env, I18N_NOT_VALID, true);
}
napi_get_value_bool(env, optionValue, &boolVal);
}
napi_value I18nAddon::CreateLocaleItemArray(napi_env env, const std::vector<LocaleItem> &localeItemList)
{
napi_value result = nullptr;
napi_status status = napi_create_array_with_length(env, localeItemList.size(), &result);
if (status != napi_ok) {
HiLog::Error(LABEL, "create LocaleItem array failed.");
return nullptr;
}
for (size_t i = 0; i < localeItemList.size(); ++i) {
napi_value item = CreateLocaleItem(env, localeItemList[i]);
status = napi_set_element(env, result, i, item);
if (status != napi_ok) {
HiLog::Error(LABEL, "Failed to set LocaleItem element.");
return nullptr;
}
}
return result;
}
napi_value I18nAddon::CreateLocaleItem(napi_env env, const LocaleItem &localeItem)
{
napi_value result;
napi_status status = napi_create_object(env, &result);
if (status != napi_ok) {
HiLog::Error(LABEL, "Create Locale Item object failed.");
return nullptr;
}
status = napi_set_named_property(env, result, "id", CreateString(env, localeItem.id));
if (status != napi_ok) {
HiLog::Error(LABEL, "Failed to set element id.");
return nullptr;
}
status = napi_set_named_property(env, result, "displayName", CreateString(env, localeItem.displayName));
if (status != napi_ok) {
HiLog::Error(LABEL, "Failed to set element displayName.");
return nullptr;
}
if (localeItem.localName.length() != 0) {
status = napi_set_named_property(env, result, "localName", CreateString(env, localeItem.localName));
if (status != napi_ok) {
HiLog::Error(LABEL, "Failed to set element localName.");
return nullptr;
}
}
status = napi_set_named_property(env, result, "suggestionType", CreateSuggestionType(env, localeItem.suggestionType));
if (status != napi_ok) {
HiLog::Error(LABEL, "Failed to set element suggestionType.");
return nullptr;
}
return result;
}
napi_value I18nAddon::CreateString(napi_env env, const std::string &str)
{
napi_value result;
napi_status status = napi_create_string_utf8(env, str.c_str(), NAPI_AUTO_LENGTH, &result);
if (status != napi_ok) {
HiLog::Error(LABEL, "create string js variable failed.");
return nullptr;
}
return result;
}
napi_value I18nAddon::CreateSuggestionType(napi_env env, SuggestionType suggestionType)
{
napi_value result;
napi_status status = napi_create_int32(env, static_cast<int32_t>(suggestionType), &result);
if (status != napi_ok) {
HiLog::Error(LABEL, "create SuggestionType failed.");
return nullptr;
}
return result;
}
napi_value Init(napi_env env, napi_value exports)
{
napi_value val = I18nAddon::Init(env, exports);
@ -3933,6 +4193,7 @@ napi_value Init(napi_env env, napi_value exports)
val = I18nAddon::InitCharacter(env, val);
val = I18nAddon::InitUtil(env, val);
val = I18nAddon::InitI18nNormalizer(env, val);
val = I18nAddon::InitSystemLocaleManager(env, val);
return val;
}