* Copyright (c) 2021-2026 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 "i18n_addon.h"
#include <algorithm>
#include <chrono>
#include <unordered_map>
#include <vector>
#include "character.h"
#include "entity_recognizer_addon.h"
#include "error_util.h"
#include "holiday_manager_addon.h"
#include "i18n_calendar.h"
#include "i18n_system_addon.h"
#include "i18n_timezone_addon.h"
#include "i18n_types.h"
#include "icu_data.h"
#include "locale_info.h"
#include "locale_matcher.h"
#include "log.h"
#include "napi_utils.h"
#include "node_api.h"
#include "number_format.h"
#include "plugin_utils.h"
#include "unicode/datefmt.h"
#include "unicode/locid.h"
#include "unicode/smpdtfmt.h"
#include "unicode/translit.h"
#include "utils.h"
#include "zone_offset_transition_addon.h"
#include "zone_rules_addon.h"
#ifdef ANDROID_PLATFORM
#include "plugins/i18n/android/java/jni/i18n_plugin_jni.h"
#endif
namespace OHOS {
namespace Global {
namespace I18n {
static thread_local napi_ref* g_constructor = nullptr;
static thread_local napi_ref* g_brkConstructor = nullptr;
static thread_local napi_ref* g_timezoneConstructor = nullptr;
static thread_local napi_ref g_indexUtilConstructor = nullptr;
static thread_local napi_ref* g_transConstructor = nullptr;
static thread_local napi_ref* g_normalizerConstructor = nullptr;
static std::unordered_map<std::string, UCalendarDateFields> g_fieldsMap {
{ "era", UCAL_ERA },
{ "year", UCAL_YEAR },
{ "month", UCAL_MONTH },
{ "week_of_year", UCAL_WEEK_OF_YEAR },
{ "week_of_month", UCAL_WEEK_OF_MONTH },
{ "date", UCAL_DATE },
{ "day_of_year", UCAL_DAY_OF_YEAR },
{ "day_of_week", UCAL_DAY_OF_WEEK },
{ "day_of_week_in_month", UCAL_DAY_OF_WEEK_IN_MONTH },
{ "ap_pm", UCAL_AM_PM },
{ "hour", UCAL_HOUR },
{ "hour_of_day", UCAL_HOUR_OF_DAY },
{ "minute", UCAL_MINUTE },
{ "second", UCAL_SECOND },
{ "millisecond", UCAL_MILLISECOND },
{ "zone_offset", UCAL_ZONE_OFFSET },
{ "dst_offset", UCAL_DST_OFFSET },
{ "year_woy", UCAL_YEAR_WOY },
{ "dow_local", UCAL_DOW_LOCAL },
{ "extended_year", UCAL_EXTENDED_YEAR },
{ "julian_day", UCAL_JULIAN_DAY },
{ "milliseconds_in_day", UCAL_MILLISECONDS_IN_DAY },
{ "is_leap_month", UCAL_IS_LEAP_MONTH },
};
static std::unordered_set<std::string> g_fieldsInFunctionAdd {
"year", "month", "date", "hour", "minute", "second", "millisecond",
"week_of_year", "week_of_month", "day_of_year", "day_of_week",
"day_of_week_in_month", "hour_of_day", "milliseconds_in_day",
};
static std::unordered_map<std::string, CalendarType> g_typeMap {
{ "buddhist", CalendarType::BUDDHIST },
{ "chinese", CalendarType::CHINESE },
{ "coptic", CalendarType::COPTIC },
{ "ethiopic", CalendarType::ETHIOPIC },
{ "hebrew", CalendarType::HEBREW },
{ "gregory", CalendarType::GREGORY },
{ "indian", CalendarType::INDIAN },
{ "islamic_civil", CalendarType::ISLAMIC_CIVIL },
{ "islamic_tbla", CalendarType::ISLAMIC_TBLA },
{ "islamic_umalqura", CalendarType::ISLAMIC_UMALQURA },
{ "japanese", CalendarType::JAPANESE },
{ "persion", CalendarType::PERSIAN },
};
const int TEMPERATURE_TYPE_CELSIUS = 1;
const int TEMPERATURE_TYPE_FAHRENHEIT = 2;
const int TEMPERATURE_TYPE_KELVIN = 3;
const int WEEK_DAY_MON = 1;
const int WEEK_DAY_TUE = 2;
const int WEEK_DAY_WED = 3;
const int WEEK_DAY_THU = 4;
const int WEEK_DAY_FRI = 5;
const int WEEK_DAY_SAT = 6;
const int WEEK_DAY_SUN = 7;
static std::unordered_map<std::string, int32_t> EnumTemperatureType {
{ "CELSIUS", TEMPERATURE_TYPE_CELSIUS },
{ "FAHRENHEIT", TEMPERATURE_TYPE_FAHRENHEIT },
{ "KELVIN", TEMPERATURE_TYPE_KELVIN }
};
static std::unordered_map<std::string, int32_t> EnumWeekDay {
{ "MON", WEEK_DAY_MON },
{ "TUE", WEEK_DAY_TUE },
{ "WED", WEEK_DAY_WED },
{ "THU", WEEK_DAY_THU },
{ "FRI", WEEK_DAY_FRI },
{ "SAT", WEEK_DAY_SAT },
{ "SUN", WEEK_DAY_SUN }
};
const char* I18nAddon::NORMALIZER_MODE_NFC_NAME = "NFC";
const char* I18nAddon::NORMALIZER_MODE_NFD_NAME = "NFD";
const char* I18nAddon::NORMALIZER_MODE_NFKC_NAME = "NFKC";
const char* I18nAddon::NORMALIZER_MODE_NFKD_NAME = "NFKD";
const int SIZE_TWO = 2;
const int SIZE_THREE = 3;
const int SIZE_FOUR = 4;
const int SIZE_FIVE = 5;
I18nAddon::I18nAddon() : env_(nullptr) {}
I18nAddon::~I18nAddon()
{
}
void I18nAddon::Destructor(napi_env env, void *nativeObject, void *hint)
{
if (!nativeObject) {
return;
}
reinterpret_cast<I18nAddon *>(nativeObject)->~I18nAddon();
}
napi_value I18nAddon::CreateUnicodeObject(napi_env env, napi_status &initStatus)
{
napi_status status = napi_ok;
napi_value character = nullptr;
status = napi_create_object(env, &character);
if (status != napi_ok) {
LOGE("Failed to create character object at init");
initStatus = napi_generic_failure;
return nullptr;
}
napi_property_descriptor characterProperties[] = {
DECLARE_NAPI_FUNCTION("isDigit", IsDigitAddon),
DECLARE_NAPI_FUNCTION("isSpaceChar", IsSpaceCharAddon),
DECLARE_NAPI_FUNCTION("isWhitespace", IsWhiteSpaceAddon),
DECLARE_NAPI_FUNCTION("isRTL", IsRTLCharacterAddon),
DECLARE_NAPI_FUNCTION("isIdeograph", IsIdeoGraphicAddon),
DECLARE_NAPI_FUNCTION("isLetter", IsLetterAddon),
DECLARE_NAPI_FUNCTION("isLowerCase", IsLowerCaseAddon),
DECLARE_NAPI_FUNCTION("isUpperCase", IsUpperCaseAddon),
DECLARE_NAPI_FUNCTION("getType", GetTypeAddon),
};
status = napi_define_properties(env, character,
sizeof(characterProperties) / sizeof(napi_property_descriptor),
characterProperties);
if (status != napi_ok) {
LOGE("Failed to set properties of character at init");
initStatus = napi_generic_failure;
return nullptr;
}
return character;
}
napi_value I18nAddon::CreateI18nUtilObject(napi_env env, napi_status &initStatus)
{
napi_value i18nUtil = nullptr;
napi_status status = napi_create_object(env, &i18nUtil);
if (status != napi_ok) {
LOGE("Failed to create I18nUtil object at init");
initStatus = napi_generic_failure;
return nullptr;
}
napi_property_descriptor i18nUtilProperties[] = {
DECLARE_NAPI_FUNCTION("unitConvert", UnitConvert),
DECLARE_NAPI_FUNCTION("getDateOrder", GetDateOrder),
DECLARE_NAPI_FUNCTION("getTimePeriodName", GetTimePeriodName),
DECLARE_NAPI_FUNCTION("getBestMatchLocale", GetBestMatchLocale),
DECLARE_NAPI_FUNCTION("getThreeLetterLanguage", GetThreeLetterLanguage),
DECLARE_NAPI_FUNCTION("getThreeLetterRegion", GetThreeLetterRegion),
DECLARE_NAPI_FUNCTION("getUnicodeWrappedFilePath", GetUnicodeWrappedFilePath),
};
status = napi_define_properties(env, i18nUtil, sizeof(i18nUtilProperties) / sizeof(napi_property_descriptor),
i18nUtilProperties);
if (status != napi_ok) {
LOGE("Failed to set properties of I18nUtil at init");
initStatus = napi_generic_failure;
return nullptr;
}
return i18nUtil;
}
napi_value I18nAddon::CreateI18nNormalizerObject(napi_env env, napi_status &initStatus)
{
napi_value i18nNormalizer = nullptr;
napi_status status = napi_create_object(env, &i18nNormalizer);
if (status != napi_ok) {
LOGE("Failed to create I18nNormalizer object at init");
initStatus = napi_generic_failure;
return nullptr;
}
napi_property_descriptor i18nNormalizerProperties[] = {
DECLARE_NAPI_FUNCTION("getInstance", GetI18nNormalizerInstance)
};
status = napi_define_properties(env, i18nNormalizer,
sizeof(i18nNormalizerProperties) / sizeof(napi_property_descriptor), i18nNormalizerProperties);
if (status != napi_ok) {
LOGE("Failed to set properties of I18nNormalizer at init");
initStatus = napi_generic_failure;
return nullptr;
}
return i18nNormalizer;
}
napi_status I18nAddon::SetEnumValue(napi_env env, napi_value enumObj, const char* enumName, int32_t enumVal)
{
napi_value name = nullptr;
napi_status status = napi_create_string_utf8(env, enumName, NAPI_AUTO_LENGTH, &name);
if (status != napi_ok) {
return status;
}
napi_value value = nullptr;
status = napi_create_int32(env, enumVal, &value);
if (status != napi_ok) {
return status;
}
status = napi_set_property(env, enumObj, name, value);
if (status != napi_ok) {
return status;
}
status = napi_set_property(env, enumObj, value, name);
if (status != napi_ok) {
return status;
}
return napi_ok;
}
napi_value I18nAddon::CreateI18NNormalizerModeEnum(napi_env env, napi_status &initStatus)
{
napi_value i18nNormalizerModel = nullptr;
napi_status status = napi_create_object(env, &i18nNormalizerModel);
if (status != napi_ok) {
initStatus = napi_generic_failure;
return nullptr;
}
status = SetEnumValue(env, i18nNormalizerModel, NORMALIZER_MODE_NFC_NAME, NORMALIZER_MODE_NFC);
if (status != napi_ok) {
initStatus = napi_generic_failure;
return nullptr;
}
status = SetEnumValue(env, i18nNormalizerModel, NORMALIZER_MODE_NFD_NAME, NORMALIZER_MODE_NFD);
if (status != napi_ok) {
initStatus = napi_generic_failure;
return nullptr;
}
status = SetEnumValue(env, i18nNormalizerModel, NORMALIZER_MODE_NFKC_NAME, NORMALIZER_MODE_NFKC);
if (status != napi_ok) {
initStatus = napi_generic_failure;
return nullptr;
}
status = SetEnumValue(env, i18nNormalizerModel, NORMALIZER_MODE_NFKD_NAME, NORMALIZER_MODE_NFKD);
if (status != napi_ok) {
initStatus = napi_generic_failure;
return nullptr;
}
return i18nNormalizerModel;
}
napi_value I18nAddon::CreateTemperatureTypeEnum(napi_env env)
{
napi_value temperatureType = nullptr;
napi_status status = napi_create_object(env, &temperatureType);
if (status != napi_ok) {
LOGE("I18nAddon::CreateTemperatureTypeEnum: Create temperatureType failed.");
return nullptr;
}
for (auto& nameToValue : EnumTemperatureType) {
std::string name = nameToValue.first;
int32_t value = static_cast<int32_t>(nameToValue.second);
status = NAPIUtils::SetEnumValue(env, temperatureType, name, value);
if (status != napi_ok) {
LOGE("I18nAddon::CreateTemperatureTypeEnum: set enum name %{public}s failed.",
name.c_str());
return nullptr;
}
}
return temperatureType;
}
napi_value I18nAddon::CreateWeekDayEnum(napi_env env)
{
napi_value weekDay = nullptr;
napi_status status = napi_create_object(env, &weekDay);
if (status != napi_ok) {
LOGE("I18nAddon::CreateWeekDayEnum: Create weekDay failed.");
return nullptr;
}
for (auto& nameToValue : EnumWeekDay) {
std::string name = nameToValue.first;
int32_t value = static_cast<int32_t>(nameToValue.second);
status = NAPIUtils::SetEnumValue(env, weekDay, name, value);
if (status != napi_ok) {
LOGE("I18nAddon::CreateWeekDayEnum: set enum name %{public}s failed.",
name.c_str());
return nullptr;
}
}
return weekDay;
}
napi_value I18nAddon::Init(napi_env env, napi_value exports)
{
napi_status initStatus = napi_ok;
napi_property_descriptor properties[] = {
DECLARE_NAPI_PROPERTY("I18NUtil", CreateI18nUtilObject(env, initStatus)),
DECLARE_NAPI_FUNCTION("getLineInstance", GetLineInstance),
DECLARE_NAPI_FUNCTION("getInstance", GetIndexUtil),
DECLARE_NAPI_PROPERTY("Unicode", CreateUnicodeObject(env, initStatus)),
DECLARE_NAPI_FUNCTION("is24HourClock", Is24HourClock),
DECLARE_NAPI_FUNCTION("getTimeZone", I18nTimeZoneAddon::GetI18nTimeZone),
DECLARE_NAPI_FUNCTION("getCalendar", GetCalendar),
DECLARE_NAPI_FUNCTION("isRTL", IsRTL),
DECLARE_NAPI_PROPERTY("Transliterator", CreateTransliteratorObject(env, initStatus)),
DECLARE_NAPI_PROPERTY("TimeZone", CreateTimeZoneObject(env, initStatus)),
DECLARE_NAPI_PROPERTY("System", CreateSystemObject(env, initStatus)),
DECLARE_NAPI_PROPERTY("Normalizer", CreateI18nNormalizerObject(env, initStatus)),
DECLARE_NAPI_PROPERTY("NormalizerMode", CreateI18NNormalizerModeEnum(env, initStatus)),
DECLARE_NAPI_FUNCTION("getSystemLanguage", GetSystemLanguage),
DECLARE_NAPI_PROPERTY("TemperatureType", CreateTemperatureTypeEnum(env)),
DECLARE_NAPI_PROPERTY("WeekDay", CreateWeekDayEnum(env)),
};
initStatus = napi_define_properties(env, exports, sizeof(properties) \
/ sizeof(napi_property_descriptor), properties);
if (initStatus != napi_ok) {
LOGE("Failed to set properties at init");
return nullptr;
}
return exports;
}
void GetOptionValue(napi_env env, napi_value options, const std::string &optionName,
std::string &value)
{
napi_value optionValue = nullptr;
napi_valuetype type = napi_undefined;
napi_status status = napi_typeof(env, options, &type);
if (status != napi_ok && type != napi_object) {
LOGE("Get option failed, option is not an object");
return;
}
bool hasProperty = false;
napi_status propStatus = napi_has_named_property(env, options, optionName.c_str(), &hasProperty);
if (propStatus == napi_ok && hasProperty) {
status = napi_get_named_property(env, options, optionName.c_str(), &optionValue);
if (status == napi_ok) {
size_t len;
napi_get_value_string_utf8(env, optionValue, nullptr, 0, &len);
std::vector<char> optionBuf(len + 1);
status = napi_get_value_string_utf8(env, optionValue, optionBuf.data(), len + 1, &len);
if (status != napi_ok) {
LOGE("Failed to get string item");
return;
}
value = optionBuf.data();
}
}
}
void GetOptionMap(napi_env env, napi_value option, std::map<std::string, std::string> &map)
{
if (option != nullptr) {
size_t len;
napi_get_value_string_utf8(env, option, nullptr, 0, &len);
std::vector<char> styleBuf(len + 1);
napi_status status = napi_get_value_string_utf8(env, option, styleBuf.data(), len + 1, &len);
if (status != napi_ok) {
LOGE("Failed to get string item");
return;
}
map.insert(std::make_pair("unitDisplay", styleBuf.data()));
}
}
napi_value I18nAddon::UnitConvert(napi_env env, napi_callback_info info)
{
size_t argc = SIZE_FIVE;
napi_value argv[SIZE_FIVE] = { 0 };
napi_status status = napi_get_cb_info(env, info, &argc, argv, nullptr, nullptr);
if (status != napi_ok) {
return nullptr;
}
std::string fromUnit;
GetOptionValue(env, argv[0], "unit", fromUnit);
std::string fromMeasSys;
GetOptionValue(env, argv[0], "measureSystem", fromMeasSys);
std::string toUnit;
GetOptionValue(env, argv[1], "unit", toUnit);
std::string toMeasSys;
GetOptionValue(env, argv[1], "measureSystem", toMeasSys);
double number = 0;
status = napi_get_value_double(env, argv[SIZE_TWO], &number);
if (status != napi_ok) {
return nullptr;
}
int convertStatus = Convert(number, fromUnit, fromMeasSys, toUnit, toMeasSys);
int code = 0;
std::string locale = NAPIUtils::GetString(env, argv[SIZE_THREE], code);
if (code != 0) {
return nullptr;
}
std::vector<std::string> localeTags;
localeTags.push_back(locale);
std::map<std::string, std::string> map = {};
map.insert(std::make_pair("style", "unit"));
if (!convertStatus) {
map.insert(std::make_pair("unit", fromUnit));
} else {
map.insert(std::make_pair("unit", toUnit));
}
GetOptionMap(env, argv[SIZE_FOUR], map);
std::unique_ptr<NumberFormat> numberFmt = nullptr;
numberFmt = std::make_unique<NumberFormat>(localeTags, map);
std::string value = numberFmt->Format(number);
napi_value result;
status = napi_create_string_utf8(env, value.c_str(), NAPI_AUTO_LENGTH, &result);
if (status != napi_ok) {
LOGE("UnitConvert: Failed to create string item");
return nullptr;
}
return result;
}
napi_value I18nAddon::GetTimePeriodName(napi_env env, napi_callback_info info)
{
int32_t hour;
std::string localeTag;
if (GetParamOfGetTimePeriodName(env, info, localeTag, hour) == -1) {
LOGE("GetTimePeriodName param error");
return NAPIUtils::CreateString(env, "");
}
UErrorCode icuStatus = U_ZERO_ERROR;
icu::Locale locale = icu::Locale::forLanguageTag(localeTag.data(), icuStatus);
if (U_FAILURE(icuStatus) || !IsValidLocaleTag(locale)) {
ErrorUtil::NapiThrow(env, I18N_NOT_VALID, "locale", "a valid locale", true);
return nullptr;
}
icu::SimpleDateFormat* formatter = static_cast<icu::SimpleDateFormat*>
(icu::DateFormat::createDateInstance(icu::DateFormat::EStyle::kDefault, locale));
if (formatter == nullptr) {
LOGE("GetTimePeriodName Failed to create SimpleDateFormat");
return NAPIUtils::CreateString(env, "");
}
formatter->applyPattern("B");
icu::UnicodeString name;
icu::Calendar* calendar = icu::Calendar::createInstance(locale, icuStatus);
if (calendar == nullptr) {
delete formatter;
return NAPIUtils::CreateString(env, "");
}
calendar->set(UCalendarDateFields::UCAL_HOUR_OF_DAY, hour);
formatter->format(calendar->getTime(icuStatus), name);
std::string result;
name.toUTF8String(result);
delete formatter;
delete calendar;
return NAPIUtils::CreateString(env, result);
}
int I18nAddon::GetParamOfGetTimePeriodName(napi_env env, napi_callback_info info, std::string& tag, int32_t& hour)
{
size_t argc = SIZE_TWO;
napi_value argv[SIZE_TWO] = { 0 };
napi_status status = napi_get_cb_info(env, info, &argc, argv, nullptr, nullptr);
if (status != napi_ok) {
LOGE("GetTimePeriodName can't get parameters from getTimePerioudName.");
return -1;
} else if (argc < 1) {
ErrorUtil::NapiNotFoundError(env, I18N_NOT_FOUND, "hour", true);
return -1;
}
napi_valuetype valueType = napi_valuetype::napi_undefined;
status = napi_typeof(env, argv[0], &valueType);
if (status != napi_ok) {
return -1;
}
if (valueType != napi_valuetype::napi_number) {
ErrorUtil::NapiThrow(env, I18N_NOT_FOUND, "hour", "number", true);
return -1;
}
status = napi_get_value_int32(env, argv[0], &hour);
if (status != napi_ok) {
LOGE("GetTimePeriodName can't get number from js param");
return -1;
}
valueType = napi_valuetype::napi_undefined;
status = napi_typeof(env, argv[1], &valueType);
if (status != napi_ok) {
return -1;
}
if (valueType == napi_valuetype::napi_null || valueType == napi_valuetype::napi_undefined) {
tag = LocaleConfig::GetSystemLocale();
} else if (valueType == napi_valuetype::napi_string) {
int code = 0;
tag = NAPIUtils::GetString(env, argv[1], code);
if (code) {
LOGE("GetTimePeriodName can't get string from js param");
return -1;
}
} else {
ErrorUtil::NapiThrow(env, I18N_NOT_FOUND, "locale", "string", true);
return -1;
}
return 0;
}
napi_value I18nAddon::GetThreeLetterRegion(napi_env env, napi_callback_info info)
{
size_t argc = 1;
napi_value argv[1] = { 0 };
napi_status status = napi_get_cb_info(env, info, &argc, argv, nullptr, nullptr);
if (status != napi_ok) {
LOGE("GetThreeLetterRegion: Failed to obtain the parameter.");
return nullptr;
} else if (argc < 1) {
ErrorUtil::NapiNotFoundError(env, I18N_NOT_FOUND, "locale", true);
return nullptr;
}
napi_valuetype valueType = napi_valuetype::napi_undefined;
status = napi_typeof(env, argv[0], &valueType);
if (status != napi_ok) {
return nullptr;
}
if (valueType != napi_valuetype::napi_string) {
ErrorUtil::NapiThrow(env, I18N_NOT_FOUND, "locale", "string", true);
return nullptr;
}
int32_t code = 0;
std::string regionTag = NAPIUtils::GetString(env, argv[0], code);
if (code != 0) {
LOGE("GetThreeLetterRegion: Failed to obtain the parameter.");
return nullptr;
}
std::string country = GetISO3Country(regionTag);
napi_value result;
status = napi_create_string_utf8(env, country.c_str(), NAPI_AUTO_LENGTH, &result);
if (status != napi_ok || country.empty()) {
LOGE("GetThreeLetterRegion create string fail or empty");
ErrorUtil::NapiThrow(env, I18N_NOT_VALID, "locale", "a valid locale", true);
return nullptr;
}
return result;
}
napi_value I18nAddon::GetThreeLetterLanguage(napi_env env, napi_callback_info info)
{
size_t argc = 1;
napi_value argv[1] = { 0 };
napi_status status = napi_get_cb_info(env, info, &argc, argv, nullptr, nullptr);
if (status != napi_ok) {
LOGE("GetThreeLetterLanguage napi get param error.");
return nullptr;
} else if (argc < 1) {
ErrorUtil::NapiNotFoundError(env, I18N_NOT_FOUND, "locale", true);
return nullptr;
}
napi_valuetype valueType = napi_valuetype::napi_undefined;
status = napi_typeof(env, argv[0], &valueType);
if (status != napi_ok) {
return nullptr;
}
if (valueType != napi_valuetype::napi_string) {
ErrorUtil::NapiThrow(env, I18N_NOT_FOUND, "locale", "string", true);
return nullptr;
}
int32_t code = 0;
std::string languageTag = NAPIUtils::GetString(env, argv[0], code);
if (code != 0) {
LOGE("GetThreeLetterLanguage: Failed to obtain the parameter.");
return nullptr;
}
std::string language = GetISO3Language(languageTag);
napi_value result;
status = napi_create_string_utf8(env, language.c_str(), NAPI_AUTO_LENGTH, &result);
if (status != napi_ok || language.empty()) {
LOGE("GetThreeLetterLanguage create string fail or empty");
ErrorUtil::NapiThrow(env, I18N_NOT_VALID, "locale", "a valid locale", true);
return nullptr;
}
return result;
}
napi_value I18nAddon::GetUnicodeWrappedFilePath(napi_env env, napi_callback_info info)
{
size_t argc = SIZE_THREE;
napi_value argv[SIZE_THREE] = { 0 };
napi_status status = napi_get_cb_info(env, info, &argc, argv, nullptr, nullptr);
if (status != napi_ok) {
LOGE("GetUnicodeWrappedFilePath: Get param info failed");
return nullptr;
}
if (argc < 1) {
ErrorUtil::NapiNotFoundError(env, I18N_NOT_FOUND, "path", true);
return nullptr;
}
NAPIUtils::VerifyType(env, "path", "string", argv[0]);
int32_t code = 0;
std::string path = NAPIUtils::GetString(env, argv[0], code);
if (code) {
LOGE("GetUnicodeWrappedFilePath: Get param string argv[0] failed");
return nullptr;
}
char delimiter = PATH_SEPARATOR;
if (argc >= SIZE_TWO) {
NAPIUtils::VerifyType(env, "delimiter", "string", argv[1]);
delimiter = GetDelimiter(env, argv[1]);
if (delimiter == '\0') {
LOGE("GetUnicodeWrappedFilePath: Second param is empty");
return nullptr;
}
}
std::string errorCode;
napi_value locale = (argc == SIZE_THREE) ? argv[SIZE_TWO] : nullptr;
std::string result = I18nAddon::GetUnicodeWrappedFilePathInner(env, locale, path, delimiter, errorCode);
if (!errorCode.empty()) {
ErrorUtil::NapiThrow(env, I18N_NOT_VALID, errorCode, "valid", true);
return nullptr;
}
return NAPIUtils::CreateString(env, result);
}
std::string I18nAddon::GetUnicodeWrappedFilePathInner(napi_env env, napi_value locale, const std::string& path,
const char delimiter, std::string& errorCode)
{
if (locale == nullptr) {
std::shared_ptr<LocaleInfo> localeInfo = nullptr;
return LocaleConfig::GetUnicodeWrappedFilePath(path, delimiter, localeInfo, errorCode);
}
if (NAPIUtils::GetLocaleType(env, locale) == LocaleType::BUILTINS_LOCALE) {
std::string localeTag = NAPIUtils::ParseBuiltinsLocale(env, locale);
return LocaleConfig::GetUnicodeWrappedFilePath(path, delimiter, localeTag, errorCode);
} else if (NAPIUtils::GetLocaleType(env, locale) == LocaleType::LOCALE_INFO) {
std::shared_ptr<LocaleInfo> localeInfo = NAPIUtils::ParseLocaleInfo(env, locale);
return LocaleConfig::GetUnicodeWrappedFilePath(path, delimiter, localeInfo, errorCode);
}
LOGE("I18nAddon::GetUnicodeWrappedFilePathInner: Get file path failed.");
return "";
}
char I18nAddon::GetDelimiter(napi_env env, napi_value argVal)
{
int32_t code = 0;
std::string result = NAPIUtils::GetString(env, argVal, code);
if (code) {
LOGE("GetDelimiter: Get string failed");
return '\0';
}
if (result.length() != 1) {
ErrorUtil::NapiThrow(env, I18N_NOT_VALID, "delimiter", "a valid delimiter", true);
return '\0';
}
return result.at(0);
}
napi_value I18nAddon::GetDateOrder(napi_env env, napi_callback_info info)
{
size_t argc = 1;
napi_value argv[1] = { 0 };
napi_status status = napi_get_cb_info(env, info, &argc, argv, nullptr, nullptr);
if (status != napi_ok) {
return nullptr;
}
size_t len = 0;
napi_get_value_string_utf8(env, argv[0], nullptr, 0, &len);
std::vector<char> languageBuf(len + 1);
status = napi_get_value_string_utf8(env, argv[0], languageBuf.data(), len + 1, &len);
if (status != napi_ok) {
LOGE("Failed to get locale string for GetDateOrder");
return nullptr;
}
UErrorCode icuStatus = U_ZERO_ERROR;
icu::Locale locale = icu::Locale::forLanguageTag(languageBuf.data(), icuStatus);
if (icuStatus != U_ZERO_ERROR) {
LOGE("Failed to create locale for GetDateOrder");
return nullptr;
}
icu::SimpleDateFormat* formatter = static_cast<icu::SimpleDateFormat*>
(icu::DateFormat::createDateInstance(icu::DateFormat::EStyle::kDefault, locale));
if (icuStatus != U_ZERO_ERROR || formatter == nullptr) {
LOGE("Failed to create SimpleDateFormat");
return nullptr;
}
std::string tempValue;
icu::UnicodeString unistr;
formatter->toPattern(unistr);
unistr.toUTF8String<std::string>(tempValue);
std::string value = ModifyOrder(tempValue);
napi_value result;
status = napi_create_string_utf8(env, value.c_str(), NAPI_AUTO_LENGTH, &result);
if (status != napi_ok) {
LOGE("Failed to create string item");
return nullptr;
}
return result;
}
LocaleInfo* ProcessJsParamLocale(napi_env env, napi_value argv)
{
int32_t code = 0;
std::string localeTag = NAPIUtils::GetString(env, argv, code);
if (code != 0) {
LOGE("GetBestMatchLocale get param locale failed.");
ErrorUtil::NapiThrow(env, I18N_NOT_FOUND, true);
return nullptr;
}
UErrorCode icuStatus = U_ZERO_ERROR;
icu::Locale locale = icu::Locale::forLanguageTag(localeTag.data(), icuStatus);
if (U_FAILURE(icuStatus) || !IsValidLocaleTag(locale)) {
LOGE("GetBestMatchLocale param locale Invalid.");
ErrorUtil::NapiThrow(env, I18N_NOT_VALID, true);
return nullptr;
}
return new (std::nothrow) LocaleInfo(localeTag);
}
bool ProcessJsParamLocaleList(napi_env env, napi_value argv, std::vector<LocaleInfo*> &candidateLocales,
LocaleInfo *requestLocale)
{
std::vector<std::string> localeTagList;
if (!NAPIUtils::GetStringArrayFromJsParam(env, argv, "localeList", localeTagList)) {
napi_throw_type_error(env, nullptr, "ProcessJsParamLocaleList: Failed to obtain the parameter.");
return false;
}
if (localeTagList.size() == 0) {
return true;
}
for (auto it = localeTagList.begin(); it != localeTagList.end(); ++it) {
UErrorCode icuStatus = U_ZERO_ERROR;
icu::Locale locale = icu::Locale::forLanguageTag(it->data(), icuStatus);
if (U_FAILURE(icuStatus) || !IsValidLocaleTag(locale)) {
LOGE("GetBestMatchLocale param localeList Invalid: %{public}s.", it->data());
ErrorUtil::NapiThrow(env, I18N_NOT_VALID, "locale of localeList", "a valid locale", true);
return false;
}
LocaleInfo *temp = new (std::nothrow) LocaleInfo(*it);
if (temp == nullptr) {
continue;
}
if (LocaleMatcher::Match(requestLocale, temp)) {
candidateLocales.push_back(temp);
} else {
delete temp;
}
}
return true;
}
void ReleaseParam(LocaleInfo *locale, std::vector<LocaleInfo*> &candidateLocales)
{
if (locale != nullptr) {
delete locale;
}
for (auto it = candidateLocales.begin(); it != candidateLocales.end(); ++it) {
if (*it != nullptr) {
delete *it;
}
}
}
napi_value I18nAddon::GetBestMatchLocale(napi_env env, napi_callback_info info)
{
size_t argc = SIZE_TWO;
napi_value argv[SIZE_TWO] = { nullptr };
napi_status status = napi_get_cb_info(env, info, &argc, argv, nullptr, nullptr);
if (status != napi_ok || argc < SIZE_TWO) {
ErrorUtil::NapiThrow(env, I18N_NOT_FOUND, "locale or localeList", "", true);
return nullptr;
}
LocaleInfo* requestLocale = ProcessJsParamLocale(env, argv[0]);
if (requestLocale == nullptr) {
return nullptr;
}
std::vector<LocaleInfo*> candidateLocales;
bool isValidParam = ProcessJsParamLocaleList(env, argv[1], candidateLocales, requestLocale);
if (!isValidParam) {
ReleaseParam(requestLocale, candidateLocales);
return nullptr;
}
std::string bestMatchLocaleTag = "";
if (candidateLocales.size() > 0) {
LocaleInfo* bestMatch = candidateLocales[0];
for (size_t i = 1; i < candidateLocales.size(); ++i) {
if (LocaleMatcher::IsMoreSuitable(bestMatch, candidateLocales[i], requestLocale) < 0) {
bestMatch = candidateLocales[i];
}
}
bestMatchLocaleTag = bestMatch->ToString();
}
ReleaseParam(requestLocale, candidateLocales);
napi_value result = nullptr;
status = napi_create_string_utf8(env, bestMatchLocaleTag.c_str(), NAPI_AUTO_LENGTH, &result);
if (status != napi_ok) {
LOGE("Create format stirng failed.");
return nullptr;
}
return result;
}
std::string I18nAddon::ModifyOrder(std::string &pattern)
{
int order[SIZE_THREE] = { 0 };
int lengths[SIZE_FOUR] = { 0 };
bool flag = true;
for (size_t i = 0; i < pattern.length(); ++i) {
char ch = pattern[i];
if (flag && std::isalpha(ch)) {
ProcessNormal(ch, order, 3, lengths, 4);
} else if (ch == '\'') {
flag = !flag;
}
}
std::unordered_map<char, int> pattern2index = {
{ 'y', 1 },
{ 'L', 2 },
{ 'd', 3 },
};
std::string ret;
for (int i = 0; i < 3; ++i) {
auto it = pattern2index.find(order[i]);
if (it == pattern2index.end()) {
continue;
}
int index = it->second;
if ((lengths[index] > 0) && (lengths[index] <= 6)) {
ret.append(lengths[index], order[i]);
}
if (i < 2) {
ret.append(1, '-');
}
}
return ret;
}
void I18nAddon::ProcessNormal(char ch, int *order, size_t orderSize, int *lengths, size_t lengsSize)
{
char adjust;
int index = -1;
if (ch == 'd') {
adjust = 'd';
index = 3;
} else if ((ch == 'L') || (ch == 'M')) {
adjust = 'L';
index = 2;
} else if (ch == 'y') {
adjust = 'y';
index = 1;
} else {
return;
}
if ((index < 0) || (index >= static_cast<int>(lengsSize))) {
return;
}
if (lengths[index] == 0) {
if (lengths[0] >= 3) {
return;
}
order[lengths[0]] = static_cast<int>(adjust);
++lengths[0];
lengths[index] = 1;
} else {
++lengths[index];
}
}
napi_value I18nAddon::InitTransliterator(napi_env env, napi_value exports)
{
napi_status status = napi_ok;
napi_property_descriptor properties[] = {
DECLARE_NAPI_FUNCTION("transform", Transform),
};
napi_value constructor = nullptr;
status = napi_define_class(env, "Transliterator", NAPI_AUTO_LENGTH, TransliteratorConstructor, nullptr,
sizeof(properties) / sizeof(napi_property_descriptor), properties, &constructor);
if (status != napi_ok) {
LOGE("Failed to define transliterator class at Init");
return nullptr;
}
g_transConstructor = new (std::nothrow) napi_ref;
if (!g_transConstructor) {
LOGE("Failed to create trans ref at init");
return nullptr;
}
status = napi_create_reference(env, constructor, 1, g_transConstructor);
if (status != napi_ok) {
LOGE("Failed to create trans reference at init");
return nullptr;
}
return exports;
}
napi_value I18nAddon::TransliteratorConstructor(napi_env env, napi_callback_info info)
{
size_t argc = 1;
napi_value argv[1] = { 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;
}
napi_valuetype valueType = napi_valuetype::napi_undefined;
napi_typeof(env, argv[0], &valueType);
if (valueType != napi_valuetype::napi_string) {
napi_throw_type_error(env, nullptr, "Parameter type does not match");
return nullptr;
}
int32_t code = 0;
std::string idTag = NAPIUtils::GetString(env, argv[0], code);
if (code) {
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) {
LOGE("TransliteratorConstructor: Wrap II18nAddon failed");
return nullptr;
}
if (!obj->InitTransliteratorContext(env, info, idTag)) {
obj.release();
return nullptr;
}
obj.release();
return thisVar;
}
bool I18nAddon::InitTransliteratorContext(napi_env env, napi_callback_info info, const std::string &idTag)
{
UErrorCode status = U_ZERO_ERROR;
icu::UnicodeString unistr = icu::UnicodeString::fromUTF8(idTag);
icu::Transliterator *trans = icu::Transliterator::createInstance(unistr, UTransDirection::UTRANS_FORWARD, status);
if ((status != U_ZERO_ERROR) || (trans == nullptr)) {
return false;
}
transliterator_ = std::unique_ptr<icu::Transliterator>(trans);
return transliterator_ != nullptr;
}
napi_value I18nAddon::CreateTransliteratorObject(napi_env env, napi_status &initStatus)
{
napi_status status = napi_ok;
napi_value transliterator = nullptr;
status = napi_create_object(env, &transliterator);
if (status != napi_ok) {
LOGE("Failed to create transliterator object at init");
initStatus = napi_generic_failure;
return nullptr;
}
napi_property_descriptor transProperties[] = {
DECLARE_NAPI_FUNCTION("getAvailableIDs", GetAvailableIDs),
DECLARE_NAPI_FUNCTION("getInstance", GetTransliteratorInstance)
};
status = napi_define_properties(env, transliterator,
sizeof(transProperties) / sizeof(napi_property_descriptor),
transProperties);
if (status != napi_ok) {
LOGE("Failed to set properties of transliterator at init");
initStatus = napi_generic_failure;
return nullptr;
}
return transliterator;
}
napi_value I18nAddon::Transform(napi_env env, napi_callback_info info)
{
size_t argc = 1;
napi_value argv[1] = { nullptr };
napi_value thisVar = nullptr;
void* data = nullptr;
napi_get_cb_info(env, info, &argc, argv, &thisVar, &data);
I18nAddon* obj = nullptr;
napi_status status = napi_unwrap(env, thisVar, reinterpret_cast<void **>(&obj));
if (status != napi_ok || !obj || !obj->transliterator_) {
LOGE("Get Transliterator object failed");
return nullptr;
}
if (argc < 1) {
return nullptr;
}
napi_valuetype valueType = napi_valuetype::napi_undefined;
napi_typeof(env, argv[0], &valueType);
if (valueType != napi_valuetype::napi_string) {
napi_throw_type_error(env, nullptr, "Parameter type does not match");
return nullptr;
}
size_t len = 0;
status = napi_get_value_string_utf8(env, argv[0], nullptr, 0, &len);
if (status != napi_ok) {
LOGE("Get field length failed");
return nullptr;
}
std::vector<char> buf(len + 1);
status = napi_get_value_string_utf8(env, argv[0], buf.data(), len + 1, &len);
if (status != napi_ok) {
LOGE("Get string value failed");
return nullptr;
}
icu::UnicodeString unistr = icu::UnicodeString::fromUTF8(buf.data());
obj->transliterator_->transliterate(unistr);
std::string temp;
unistr.toUTF8String(temp);
napi_value value;
status = napi_create_string_utf8(env, temp.c_str(), NAPI_AUTO_LENGTH, &value);
if (status != napi_ok) {
LOGE("Get field length failed");
return nullptr;
}
return value;
}
void SortAvailableIDs(icu::StringEnumeration* strenum, std::vector<std::string>& idList)
{
if (strenum == nullptr) {
return;
}
const char* tempId = nullptr;
UErrorCode icuStatus = U_ZERO_ERROR;
while ((tempId = strenum->next(nullptr, icuStatus)) != nullptr) {
if (icuStatus != U_ZERO_ERROR) {
break;
}
idList.push_back(std::string(tempId));
}
std::sort(idList.begin(), idList.end(), [](std::string& a, std::string& b) {
return a.compare(b) < 0;
});
}
napi_value I18nAddon::GetAvailableIDs(napi_env env, napi_callback_info info)
{
size_t argc = 0;
napi_value *argv = nullptr;
napi_status status = napi_get_cb_info(env, info, &argc, argv, nullptr, nullptr);
if (status != napi_ok) {
return nullptr;
}
UErrorCode icuStatus = U_ZERO_ERROR;
icu::StringEnumeration* strenum = icu::Transliterator::getAvailableIDs(icuStatus);
if (icuStatus != U_ZERO_ERROR) {
LOGE("Failed to get available ids");
if (strenum) {
delete strenum;
}
return nullptr;
}
if (strenum == nullptr) {
return nullptr;
}
std::vector<std::string> idList;
SortAvailableIDs(strenum, idList);
napi_value result = nullptr;
status = napi_create_array(env, &result);
if (status != napi_ok) {
delete strenum;
return nullptr;
}
uint32_t i = 0;
for (auto& id : idList) {
napi_value val = nullptr;
status = napi_create_string_utf8(env, id.c_str(), NAPI_AUTO_LENGTH, &val);
if (status != napi_ok) {
LOGE("GetAvailableIDs: Failed to create string item");
break;
}
status = napi_set_element(env, result, i, val);
if (status != napi_ok) {
LOGE("GetAvailableIDs: Failed to set item");
break;
}
++i;
}
delete strenum;
return result;
}
napi_value I18nAddon::GetTransliteratorInstance(napi_env env, napi_callback_info info)
{
size_t argc = 1;
napi_value argv[1] = { 0 };
napi_get_cb_info(env, info, &argc, argv, nullptr, nullptr);
napi_value constructor = nullptr;
napi_status status = napi_get_reference_value(env, *g_transConstructor, &constructor);
if (status != napi_ok) {
LOGE("Failed to create reference at GetTransliterator");
return nullptr;
}
napi_value result = nullptr;
status = napi_new_instance(env, constructor, 1, argv, &result);
if (status != napi_ok) {
LOGE("Get Transliterator create instance failed");
return nullptr;
}
return result;
}
napi_value I18nAddon::IsDigitAddon(napi_env env, napi_callback_info info)
{
size_t argc = 1;
napi_value argv[1] = { 0 };
napi_status status = napi_get_cb_info(env, info, &argc, argv, nullptr, nullptr);
if (status != napi_ok) {
return nullptr;
}
napi_valuetype valueType = napi_valuetype::napi_undefined;
napi_typeof(env, argv[0], &valueType);
if (valueType != napi_valuetype::napi_string) {
napi_throw_type_error(env, nullptr, "Parameter type does not match");
return nullptr;
}
int32_t code = 0;
std::string character = NAPIUtils::GetString(env, argv[0], code);
if (code) {
return nullptr;
}
bool isDigit = IsDigit(character);
napi_value result = nullptr;
status = napi_get_boolean(env, isDigit, &result);
if (status != napi_ok) {
LOGE("Create isDigit boolean value failed");
return nullptr;
}
return result;
}
napi_value I18nAddon::IsSpaceCharAddon(napi_env env, napi_callback_info info)
{
size_t argc = 1;
napi_value argv[1] = { 0 };
napi_status status = napi_get_cb_info(env, info, &argc, argv, nullptr, nullptr);
if (status != napi_ok) {
return nullptr;
}
napi_valuetype valueType = napi_valuetype::napi_undefined;
napi_typeof(env, argv[0], &valueType);
if (valueType != napi_valuetype::napi_string) {
napi_throw_type_error(env, nullptr, "Parameter type does not match");
return nullptr;
}
int32_t code = 0;
std::string character = NAPIUtils::GetString(env, argv[0], code);
if (code) {
return nullptr;
}
bool isSpaceChar = IsSpaceChar(character);
napi_value result = nullptr;
status = napi_get_boolean(env, isSpaceChar, &result);
if (status != napi_ok) {
LOGE("Create isSpaceChar boolean value failed");
return nullptr;
}
return result;
}
napi_value I18nAddon::IsWhiteSpaceAddon(napi_env env, napi_callback_info info)
{
size_t argc = 1;
napi_value argv[1] = { 0 };
napi_status status = napi_get_cb_info(env, info, &argc, argv, nullptr, nullptr);
if (status != napi_ok) {
return nullptr;
}
napi_valuetype valueType = napi_valuetype::napi_undefined;
napi_typeof(env, argv[0], &valueType);
if (valueType != napi_valuetype::napi_string) {
napi_throw_type_error(env, nullptr, "Parameter type does not match");
return nullptr;
}
int32_t code = 0;
std::string character = NAPIUtils::GetString(env, argv[0], code);
if (code) {
return nullptr;
}
bool isWhiteSpace = IsWhiteSpace(character);
napi_value result = nullptr;
status = napi_get_boolean(env, isWhiteSpace, &result);
if (status != napi_ok) {
LOGE("Create isWhiteSpace boolean value failed");
return nullptr;
}
return result;
}
napi_value I18nAddon::IsRTLCharacterAddon(napi_env env, napi_callback_info info)
{
size_t argc = 1;
napi_value argv[1] = { 0 };
napi_status status = napi_get_cb_info(env, info, &argc, argv, nullptr, nullptr);
if (status != napi_ok) {
return nullptr;
}
napi_valuetype valueType = napi_valuetype::napi_undefined;
napi_typeof(env, argv[0], &valueType);
if (valueType != napi_valuetype::napi_string) {
napi_throw_type_error(env, nullptr, "Parameter type does not match");
return nullptr;
}
int32_t code = 0;
std::string character = NAPIUtils::GetString(env, argv[0], code);
if (code) {
return nullptr;
}
bool isRTLCharacter = IsRTLCharacter(character);
napi_value result = nullptr;
status = napi_get_boolean(env, isRTLCharacter, &result);
if (status != napi_ok) {
LOGE("Create isRTLCharacter boolean value failed");
return nullptr;
}
return result;
}
napi_value I18nAddon::IsIdeoGraphicAddon(napi_env env, napi_callback_info info)
{
size_t argc = 1;
napi_value argv[1] = { 0 };
napi_status status = napi_get_cb_info(env, info, &argc, argv, nullptr, nullptr);
if (status != napi_ok) {
return nullptr;
}
napi_valuetype valueType = napi_valuetype::napi_undefined;
napi_typeof(env, argv[0], &valueType);
if (valueType != napi_valuetype::napi_string) {
napi_throw_type_error(env, nullptr, "Parameter type does not match");
return nullptr;
}
int32_t code = 0;
std::string character = NAPIUtils::GetString(env, argv[0], code);
if (code) {
return nullptr;
}
bool isIdeoGraphic = IsIdeoGraphic(character);
napi_value result = nullptr;
status = napi_get_boolean(env, isIdeoGraphic, &result);
if (status != napi_ok) {
LOGE("Create isIdeoGraphic boolean value failed");
return nullptr;
}
return result;
}
napi_value I18nAddon::IsLetterAddon(napi_env env, napi_callback_info info)
{
size_t argc = 1;
napi_value argv[1] = { 0 };
napi_status status = napi_get_cb_info(env, info, &argc, argv, nullptr, nullptr);
if (status != napi_ok) {
return nullptr;
}
napi_valuetype valueType = napi_valuetype::napi_undefined;
napi_typeof(env, argv[0], &valueType);
if (valueType != napi_valuetype::napi_string) {
napi_throw_type_error(env, nullptr, "Parameter type does not match");
return nullptr;
}
int32_t code = 0;
std::string character = NAPIUtils::GetString(env, argv[0], code);
if (code) {
return nullptr;
}
bool isLetter = IsLetter(character);
napi_value result = nullptr;
status = napi_get_boolean(env, isLetter, &result);
if (status != napi_ok) {
LOGE("Create isLetter boolean value failed");
return nullptr;
}
return result;
}
napi_value I18nAddon::IsLowerCaseAddon(napi_env env, napi_callback_info info)
{
size_t argc = 1;
napi_value argv[1] = { 0 };
napi_status status = napi_get_cb_info(env, info, &argc, argv, nullptr, nullptr);
if (status != napi_ok) {
return nullptr;
}
napi_valuetype valueType = napi_valuetype::napi_undefined;
napi_typeof(env, argv[0], &valueType);
if (valueType != napi_valuetype::napi_string) {
napi_throw_type_error(env, nullptr, "Parameter type does not match");
return nullptr;
}
int32_t code = 0;
std::string character = NAPIUtils::GetString(env, argv[0], code);
if (code) {
return nullptr;
}
bool isLowerCase = IsLowerCase(character);
napi_value result = nullptr;
status = napi_get_boolean(env, isLowerCase, &result);
if (status != napi_ok) {
LOGE("Create isLowerCase boolean value failed");
return nullptr;
}
return result;
}
napi_value I18nAddon::IsUpperCaseAddon(napi_env env, napi_callback_info info)
{
size_t argc = 1;
napi_value argv[1] = { 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;
}
napi_valuetype valueType = napi_valuetype::napi_undefined;
napi_typeof(env, argv[0], &valueType);
if (valueType != napi_valuetype::napi_string) {
napi_throw_type_error(env, nullptr, "Parameter type does not match");
return nullptr;
}
int32_t code = 0;
std::string character = NAPIUtils::GetString(env, argv[0], code);
if (code) {
return nullptr;
}
bool isUpperCase = IsUpperCase(character);
napi_value result = nullptr;
status = napi_get_boolean(env, isUpperCase, &result);
if (status != napi_ok) {
LOGE("Create isUpperCase boolean value failed");
return nullptr;
}
return result;
}
napi_value I18nAddon::GetTypeAddon(napi_env env, napi_callback_info info)
{
size_t argc = 1;
napi_value argv[1] = { 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;
}
napi_valuetype valueType = napi_valuetype::napi_undefined;
napi_typeof(env, argv[0], &valueType);
if (valueType != napi_valuetype::napi_string) {
napi_throw_type_error(env, nullptr, "Parameter type does not match");
return nullptr;
}
int32_t code = 0;
std::string character = NAPIUtils::GetString(env, argv[0], code);
if (code) {
return nullptr;
}
std::string type = GetType(character);
napi_value result = nullptr;
status = napi_create_string_utf8(env, type.c_str(), NAPI_AUTO_LENGTH, &result);
if (status != napi_ok) {
LOGE("Create getType string value failed");
return nullptr;
}
return result;
}
napi_value I18nAddon::GetSystemLanguage(napi_env env, napi_callback_info info)
{
std::string value = LocaleConfig::GetSystemLanguage();
napi_value result = nullptr;
napi_status status = napi_create_string_utf8(env, value.c_str(), NAPI_AUTO_LENGTH, &result);
if (status != napi_ok) {
LOGE("Failed to create string item");
return nullptr;
}
return result;
}
napi_value I18nAddon::GetSystemRegion(napi_env env, napi_callback_info info)
{
std::string value = LocaleConfig::GetSystemRegion();
napi_value result = nullptr;
napi_status status = napi_create_string_utf8(env, value.c_str(), NAPI_AUTO_LENGTH, &result);
if (status != napi_ok) {
LOGE("Failed to create string item");
return nullptr;
}
return result;
}
napi_value I18nAddon::GetSystemLocale(napi_env env, napi_callback_info info)
{
std::string value = LocaleConfig::GetSystemLocale();
napi_value result = nullptr;
napi_status status = napi_create_string_utf8(env, value.c_str(), NAPI_AUTO_LENGTH, &result);
if (status != napi_ok) {
LOGE("Failed to create string item");
return nullptr;
}
return result;
}
napi_value I18nAddon::GetDisplayLanguage(napi_env env, napi_callback_info info)
{
return I18nAddon::GetDisplayLanguageImpl(env, info, false);
}
napi_value I18nAddon::GetDisplayLanguageWithError(napi_env env, napi_callback_info info)
{
return I18nAddon::GetDisplayLanguageImpl(env, info, true);
}
napi_value I18nAddon::GetDisplayLanguageImpl(napi_env env, napi_callback_info info, bool throwError)
{
size_t argc = 3;
napi_value argv[3] = { nullptr };
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;
} else if (argc < FUNC_ARGS_COUNT) {
ErrorUtil::NapiThrow(env, I18N_NOT_FOUND, "language or locale", "", throwError);
return nullptr;
}
NAPIUtils::VerifyType(env, "language", "string", argv[0]);
size_t len = 0;
napi_get_value_string_utf8(env, argv[0], nullptr, 0, &len);
std::vector<char> localeBuf(len + 1);
if (!GetNapiStringValueWithError(env, argv[0], len, localeBuf.data(), "0")) {
return nullptr;
}
NAPIUtils::VerifyType(env, "locale", "string", argv[1]);
napi_get_value_string_utf8(env, argv[1], nullptr, 0, &len);
std::vector<char> displayLocaleBuf(len + 1);
if (!GetNapiStringValueWithError(env, argv[1], len, displayLocaleBuf.data(), "1")) {
return nullptr;
}
if (!LocaleConfig::IsValidTag(displayLocaleBuf.data())) {
ErrorUtil::NapiThrow(env, I18N_NOT_VALID, "locale", "a valid locale", throwError);
return nullptr;
}
bool sentenceCase = true;
if (argc > FUNC_ARGS_COUNT) {
napi_get_value_bool(env, argv[FUNC_ARGS_COUNT], &sentenceCase);
}
std::string value = LocaleConfig::GetDisplayLanguage(localeBuf.data(), displayLocaleBuf.data(), sentenceCase);
if (value.length() == 0) {
LOGE("GetDisplayLanguageImpl: result is empty.");
return nullptr;
}
napi_value result = nullptr;
status = napi_create_string_utf8(env, value.c_str(), NAPI_AUTO_LENGTH, &result);
if (status != napi_ok) {
LOGE("GetDisplayLanguageImpl: Failed to create string item");
return nullptr;
}
return result;
}
bool I18nAddon::GetNapiStringValueWithError(napi_env env, napi_value napiValue, size_t len, char* valueBuf,
std::string index)
{
napi_status status = napi_get_value_string_utf8(env, napiValue, valueBuf, len + 1, &len);
if (status != napi_ok) {
LOGE("GetNapiStringValueWithError: Failed to get string item argv[%{public}s]", index.c_str());
return false;
}
return true;
}
napi_value I18nAddon::GetDisplayCountry(napi_env env, napi_callback_info info)
{
return I18nAddon::GetDisplayCountryImpl(env, info, false);
}
napi_value I18nAddon::GetDisplayCountryWithError(napi_env env, napi_callback_info info)
{
return I18nAddon::GetDisplayCountryImpl(env, info, true);
}
napi_value I18nAddon::GetDisplayCountryImpl(napi_env env, napi_callback_info info, bool throwError)
{
size_t argc = SIZE_THREE;
napi_value argv[SIZE_THREE] = { nullptr };
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 NAPIUtils::CreateString(env, "");
} else if (argc < FUNC_ARGS_COUNT) {
ErrorUtil::NapiThrow(env, I18N_NOT_FOUND, "country or locale", "", throwError);
return NAPIUtils::CreateString(env, "");
}
size_t len = 0;
NAPIUtils::VerifyType(env, "country", "string", argv[0]);
napi_get_value_string_utf8(env, argv[0], nullptr, 0, &len);
std::vector<char> localeBuf(len + 1);
if (!GetCountryNapiValueWithError(env, argv[0], len, localeBuf.data(), "0")) {
return NAPIUtils::CreateString(env, "");
}
NAPIUtils::VerifyType(env, "locale", "string", argv[1]);
napi_get_value_string_utf8(env, argv[1], nullptr, 0, &len);
std::vector<char> displayLocaleBuf(len + 1);
if (!GetCountryNapiValueWithError(env, argv[1], len, displayLocaleBuf.data(), "1")) {
return NAPIUtils::CreateString(env, "");
}
LocaleInfo localeInfo(localeBuf.data());
if (!LocaleConfig::IsValidRegion(localeBuf.data()) && localeInfo.GetRegion() == "") {
ErrorUtil::NapiThrow(env, I18N_NOT_VALID, "country", "a valid region", throwError);
return NAPIUtils::CreateString(env, "");
} else if (!LocaleConfig::IsValidTag(displayLocaleBuf.data())) {
ErrorUtil::NapiThrow(env, I18N_NOT_VALID, "locale", "a valid locale", throwError);
return NAPIUtils::CreateString(env, "");
}
bool sentenceCase = true;
if (argc > FUNC_ARGS_COUNT) {
napi_get_value_bool(env, argv[FUNC_ARGS_COUNT], &sentenceCase);
}
std::string value = LocaleConfig::GetDisplayRegion(localeBuf.data(), displayLocaleBuf.data(), sentenceCase);
if (value.length() == 0) {
LOGE("GetDisplayCountryImpl: result is empty.");
return NAPIUtils::CreateString(env, "");
}
napi_value result = nullptr;
status = napi_create_string_utf8(env, value.c_str(), NAPI_AUTO_LENGTH, &result);
if (status != napi_ok) {
LOGE("GetDisplayCountryImpl: Failed to create string item");
return NAPIUtils::CreateString(env, "");
}
return result;
}
bool I18nAddon::GetCountryNapiValueWithError(napi_env env, napi_value napiValue, size_t len, char* valueBuf,
std::string index)
{
napi_status status = napi_get_value_string_utf8(env, napiValue, valueBuf, len + 1, &len);
if (status != napi_ok) {
LOGE("GetCountryNapiValueWithError: Failed to get string item argv[%{public}s]", index.c_str());
return false;
}
return true;
}
napi_value I18nAddon::IsRTL(napi_env env, napi_callback_info info)
{
size_t argc = 1;
napi_value argv[1] = { 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;
}
size_t len = 0;
napi_get_value_string_utf8(env, argv[0], nullptr, 0, &len);
std::vector<char> localeBuf(len + 1);
status = napi_get_value_string_utf8(env, argv[0], localeBuf.data(), len + 1, &len);
if (status != napi_ok) {
LOGE("Failed to get string item");
return nullptr;
}
bool isRTL = LocaleConfig::IsRTL(localeBuf.data());
napi_value result = nullptr;
status = napi_get_boolean(env, isRTL, &result);
if (status != napi_ok) {
LOGE("IsRTL failed");
return nullptr;
}
return result;
}
napi_value I18nAddon::InitPhoneNumberFormat(napi_env env, napi_value exports)
{
napi_status status = napi_ok;
napi_property_descriptor properties[] = {
DECLARE_NAPI_FUNCTION("isValidNumber", IsValidPhoneNumber),
DECLARE_NAPI_FUNCTION("format", FormatPhoneNumber),
};
napi_value constructor;
status = napi_define_class(env, "PhoneNumberFormat", NAPI_AUTO_LENGTH, PhoneNumberFormatConstructor, nullptr,
sizeof(properties) / sizeof(napi_property_descriptor), properties, &constructor);
if (status != napi_ok) {
LOGE("Define class failed when InitPhoneNumberFormat");
return nullptr;
}
status = napi_set_named_property(env, exports, "PhoneNumberFormat", constructor);
if (status != napi_ok) {
LOGE("Set property failed when InitPhoneNumberFormat");
return nullptr;
}
return exports;
}
void GetOptionValue(napi_env env, napi_value options, const std::string &optionName,
std::map<std::string, std::string> &map)
{
napi_value optionValue = nullptr;
napi_valuetype type = napi_undefined;
napi_status status = napi_typeof(env, options, &type);
if (status != napi_ok && type != napi_object) {
LOGE("Get option failed, option is not an object");
return;
}
bool hasProperty = false;
napi_status propStatus = napi_has_named_property(env, options, optionName.c_str(), &hasProperty);
if (propStatus == napi_ok && hasProperty) {
status = napi_get_named_property(env, options, optionName.c_str(), &optionValue);
if (status == napi_ok) {
size_t len = 0;
napi_get_value_string_utf8(env, optionValue, nullptr, 0, &len);
std::vector<char> optionBuf(len + 1);
status = napi_get_value_string_utf8(env, optionValue, optionBuf.data(), len + 1, &len);
if (status != napi_ok) {
return;
}
map.insert(make_pair(optionName, optionBuf.data()));
}
}
}
napi_value I18nAddon::PhoneNumberFormatConstructor(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) {
return nullptr;
}
napi_valuetype valueType = napi_valuetype::napi_undefined;
napi_typeof(env, argv[0], &valueType);
if (valueType != napi_valuetype::napi_string) {
napi_throw_type_error(env, nullptr, "Parameter type does not match");
return nullptr;
}
size_t len = 0;
status = napi_get_value_string_utf8(env, argv[0], nullptr, 0, &len);
if (status != napi_ok) {
LOGE("Get country tag length failed");
return nullptr;
}
std::vector<char> country (len + 1);
status = napi_get_value_string_utf8(env, argv[0], country.data(), len + 1, &len);
if (status != napi_ok) {
LOGE("Get country tag failed");
return nullptr;
}
std::map<std::string, std::string> options;
GetOptionValue(env, argv[1], "type", options);
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) {
LOGE("Wrap I18nAddon failed");
return nullptr;
}
if (!obj->InitPhoneNumberFormatContext(env, info, country.data(), options)) {
return nullptr;
}
obj.release();
return thisVar;
}
bool I18nAddon::InitPhoneNumberFormatContext(napi_env env, napi_callback_info info, const std::string &country,
const std::map<std::string, std::string> &options)
{
napi_value global = nullptr;
napi_status status = napi_get_global(env, &global);
if (status != napi_ok) {
LOGE("Get global failed");
return false;
}
env_ = env;
phonenumberfmt_ = PhoneNumberFormat::CreateInstance(country, options);
return phonenumberfmt_ != nullptr;
}
napi_value I18nAddon::IsValidPhoneNumber(napi_env env, napi_callback_info info)
{
size_t argc = 1;
napi_value argv[1] = { 0 };
napi_value thisVar = nullptr;
void *data = nullptr;
napi_get_cb_info(env, info, &argc, argv, &thisVar, &data);
napi_valuetype valueType = napi_valuetype::napi_undefined;
napi_typeof(env, argv[0], &valueType);
if (valueType != napi_valuetype::napi_string) {
napi_throw_type_error(env, nullptr, "Parameter type does not match");
return nullptr;
}
size_t len = 0;
napi_status status = napi_get_value_string_utf8(env, argv[0], nullptr, 0, &len);
if (status != napi_ok) {
LOGE("Get phone number length failed");
return nullptr;
}
std::vector<char> buf(len + 1);
status = napi_get_value_string_utf8(env, argv[0], buf.data(), len + 1, &len);
if (status != napi_ok) {
LOGE("Get phone number failed");
return nullptr;
}
I18nAddon *obj = nullptr;
status = napi_unwrap(env, thisVar, reinterpret_cast<void **>(&obj));
if (status != napi_ok || !obj || !obj->phonenumberfmt_) {
LOGE("GetPhoneNumberFormat object failed");
return nullptr;
}
bool isValid = obj->phonenumberfmt_->isValidPhoneNumber(buf.data());
napi_value result = nullptr;
status = napi_get_boolean(env, isValid, &result);
if (status != napi_ok) {
LOGE("Create boolean failed");
return nullptr;
}
return result;
}
napi_value I18nAddon::FormatPhoneNumber(napi_env env, napi_callback_info info)
{
size_t argc = 1;
napi_value argv[1] = { 0 };
napi_value thisVar = nullptr;
void *data = nullptr;
napi_get_cb_info(env, info, &argc, argv, &thisVar, &data);
napi_valuetype valueType = napi_valuetype::napi_undefined;
napi_typeof(env, argv[0], &valueType);
if (valueType != napi_valuetype::napi_string) {
napi_throw_type_error(env, nullptr, "Parameter type does not match");
return nullptr;
}
size_t len = 0;
napi_status status = napi_get_value_string_utf8(env, argv[0], nullptr, 0, &len);
if (status != napi_ok) {
LOGE("Get phone number length failed");
return nullptr;
}
std::vector<char> buf(len + 1);
status = napi_get_value_string_utf8(env, argv[0], buf.data(), len + 1, &len);
if (status != napi_ok) {
LOGE("Get phone number failed");
return nullptr;
}
I18nAddon *obj = nullptr;
status = napi_unwrap(env, thisVar, reinterpret_cast<void **>(&obj));
if (status != napi_ok || !obj || !obj->phonenumberfmt_) {
LOGE("Get PhoneNumberFormat object failed");
return nullptr;
}
std::string formattedPhoneNumber = obj->phonenumberfmt_->format(buf.data());
napi_value result = nullptr;
status = napi_create_string_utf8(env, formattedPhoneNumber.c_str(), NAPI_AUTO_LENGTH, &result);
if (status != napi_ok) {
LOGE("Create format phone number failed");
return nullptr;
}
return result;
}
bool I18nAddon::GetStringArrayFromJsParam(
napi_env env, napi_value &jsArray, const std::string& valueName, std::vector<std::string> &strArray)
{
if (jsArray == nullptr) {
ErrorUtil::NapiThrow(env, I18N_NOT_FOUND, valueName, "", true);
return false;
}
bool isArray = false;
napi_status status = napi_is_array(env, jsArray, &isArray);
if (status != napi_ok) {
return false;
} else if (!isArray) {
ErrorUtil::NapiThrow(env, I18N_NOT_FOUND, valueName, "an Array", true);
return false;
}
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 = NAPIUtils::GetString(env, element, code);
if (code != 0) {
napi_throw_type_error(env, nullptr, "GetStringArrayFromJsParam: Failed to obtain the parameter.");
return false;
}
strArray.push_back(str);
}
return true;
}
napi_value I18nAddon::InitI18nCalendar(napi_env env, napi_value exports)
{
napi_status status = napi_ok;
napi_property_descriptor properties[] = {
DECLARE_NAPI_FUNCTION("setTime", SetTime),
DECLARE_NAPI_FUNCTION("set", Set),
DECLARE_NAPI_FUNCTION("getTimeZone", GetTimeZone),
DECLARE_NAPI_FUNCTION("setTimeZone", SetTimeZone),
DECLARE_NAPI_FUNCTION("getFirstDayOfWeek", GetFirstDayOfWeek),
DECLARE_NAPI_FUNCTION("setFirstDayOfWeek", SetFirstDayOfWeek),
DECLARE_NAPI_FUNCTION("getMinimalDaysInFirstWeek", GetMinimalDaysInFirstWeek),
DECLARE_NAPI_FUNCTION("setMinimalDaysInFirstWeek", SetMinimalDaysInFirstWeek),
DECLARE_NAPI_FUNCTION("get", Get),
DECLARE_NAPI_FUNCTION("add", Add),
DECLARE_NAPI_FUNCTION("getDisplayName", GetDisplayName),
DECLARE_NAPI_FUNCTION("getTimeInMillis", GetTimeInMillis),
DECLARE_NAPI_FUNCTION("isWeekend", IsWeekend),
DECLARE_NAPI_FUNCTION("compareDays", CompareDays)
};
napi_value constructor = nullptr;
status = napi_define_class(env, "I18nCalendar", NAPI_AUTO_LENGTH, CalendarConstructor, nullptr,
sizeof(properties) / sizeof(napi_property_descriptor), properties, &constructor);
if (status != napi_ok) {
LOGE("Failed to define class at Init");
return nullptr;
}
g_constructor = new (std::nothrow) napi_ref;
if (!g_constructor) {
LOGE("Failed to create ref at init");
return nullptr;
}
status = napi_create_reference(env, constructor, 1, g_constructor);
if (status != napi_ok) {
LOGE("Failed to create reference at init");
return nullptr;
}
return exports;
}
napi_value I18nAddon::CalendarConstructor(napi_env env, napi_callback_info info)
{
size_t argc = 2;
napi_value argv[2] = { 0 };
argv[0] = nullptr;
argv[1] = nullptr;
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;
}
napi_valuetype valueType = napi_valuetype::napi_undefined;
napi_typeof(env, argv[0], &valueType);
if (valueType != napi_valuetype::napi_string) {
napi_throw_type_error(env, nullptr, "Parameter type does not match");
return nullptr;
}
int32_t code = 0;
std::string localeTag = NAPIUtils::GetString(env, argv[0], code);
if (code) {
return nullptr;
}
CalendarType type = GetCalendarType(env, argv[1]);
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) {
LOGE("CalendarConstructor: Wrap II18nAddon failed");
return nullptr;
}
if (!obj->InitCalendarContext(env, info, localeTag, type)) {
return nullptr;
}
obj.release();
return thisVar;
}
CalendarType I18nAddon::GetCalendarType(napi_env env, napi_value value)
{
CalendarType type = CalendarType::UNDEFINED;
if (value != nullptr) {
napi_valuetype valueType = napi_valuetype::napi_undefined;
napi_typeof(env, value, &valueType);
if (valueType != napi_valuetype::napi_string) {
napi_throw_type_error(env, nullptr, "Parameter type does not match");
return type;
}
int32_t code = 0;
std::string calendarType = NAPIUtils::GetString(env, value, code);
if (code) {
return type;
}
if (g_typeMap.find(calendarType) != g_typeMap.end()) {
type = g_typeMap[calendarType];
}
}
return type;
}
bool I18nAddon::InitCalendarContext(napi_env env, napi_callback_info info, const std::string &localeTag,
CalendarType type)
{
calendar_ = std::make_unique<I18nCalendar>(localeTag, type);
return calendar_ != nullptr;
}
napi_value I18nAddon::GetCalendar(napi_env env, napi_callback_info info)
{
size_t argc = 2;
napi_value argv[2] = { 0 };
argv[0] = nullptr;
argv[1] = nullptr;
napi_value thisVar = nullptr;
void *data = nullptr;
napi_get_cb_info(env, info, &argc, argv, &thisVar, &data);
napi_value constructor = nullptr;
napi_status status = napi_get_reference_value(env, *g_constructor, &constructor);
if (status != napi_ok) {
LOGE("Failed to create reference at GetCalendar");
return nullptr;
}
if (argc < FUNC_ARGS_COUNT) {
status = napi_create_string_utf8(env, "", NAPI_AUTO_LENGTH, argv + 1);
if (status != napi_ok) {
return nullptr;
}
}
napi_value result = nullptr;
status = napi_new_instance(env, constructor, 2, argv, &result);
if (status != napi_ok) {
LOGE("Get calendar create instance failed");
return nullptr;
}
return result;
}
napi_value I18nAddon::GetDate(napi_env env, napi_value value)
{
if (!value) {
return nullptr;
}
napi_value funcGetDateInfo = nullptr;
napi_status status = napi_get_named_property(env, value, "valueOf", &funcGetDateInfo);
if (status != napi_ok) {
LOGE("Get method valueOf failed");
return nullptr;
}
napi_value ret_value = nullptr;
status = napi_call_function(env, value, funcGetDateInfo, 0, nullptr, &ret_value);
if (status != napi_ok) {
LOGE("Get milliseconds failed");
return nullptr;
}
return ret_value;
}
void I18nAddon::SetMilliseconds(napi_env env, napi_value value)
{
if (!value) {
return;
}
double milliseconds = 0;
napi_valuetype valueType = napi_valuetype::napi_undefined;
napi_typeof(env, value, &valueType);
if (valueType != napi_valuetype::napi_number) {
napi_throw_type_error(env, nullptr, "Parameter type does not match");
return;
}
napi_status status = napi_get_value_double(env, value, &milliseconds);
if (status != napi_ok) {
LOGE("Retrieve milliseconds failed");
return;
}
if (calendar_ != nullptr) {
calendar_->SetTime(milliseconds);
}
}
napi_value I18nAddon::Set(napi_env env, napi_callback_info info)
{
size_t argc = 6;
napi_value argv[6] = { 0 };
for (size_t i = 0; i < argc; ++i) {
argv[i] = nullptr;
}
napi_value thisVar = nullptr;
void *data = nullptr;
napi_get_cb_info(env, info, &argc, argv, &thisVar, &data);
napi_valuetype valueType = napi_valuetype::napi_undefined;
napi_status status = napi_ok;
int32_t times[3] = { 0 };
for (int i = 0; i < 3; ++i) {
napi_typeof(env, argv[i], &valueType);
if (valueType != napi_valuetype::napi_number) {
napi_throw_type_error(env, nullptr, "Parameter type does not match");
return nullptr;
}
status = napi_get_value_int32(env, argv[i], times + i);
if (status != napi_ok) {
LOGE("Retrieve time value failed");
return nullptr;
}
}
I18nAddon *obj = nullptr;
status = napi_unwrap(env, thisVar, reinterpret_cast<void **>(&obj));
if (status != napi_ok || !obj || !obj->calendar_) {
LOGE("Get calendar object failed");
return nullptr;
}
obj->calendar_->Set(times[0], times[1], times[2]);
obj->SetField(env, argv[3], UCalendarDateFields::UCAL_HOUR_OF_DAY);
obj->SetField(env, argv[4], UCalendarDateFields::UCAL_MINUTE);
obj->SetField(env, argv[5], UCalendarDateFields::UCAL_SECOND);
return nullptr;
}
napi_value I18nAddon::SetTime(napi_env env, napi_callback_info info)
{
size_t argc = 1;
napi_value argv[1] = { 0 };
argv[0] = nullptr;
napi_value thisVar = nullptr;
void *data = nullptr;
napi_get_cb_info(env, info, &argc, argv, &thisVar, &data);
if (argc == 0) {
return nullptr;
}
I18nAddon *obj = nullptr;
napi_status status = napi_unwrap(env, thisVar, reinterpret_cast<void **>(&obj));
if (status != napi_ok || !obj || !obj->calendar_) {
LOGE("Get calendar object failed");
return nullptr;
}
napi_valuetype type = napi_valuetype::napi_undefined;
status = napi_typeof(env, argv[0], &type);
if (status != napi_ok) {
return nullptr;
}
if (type == napi_valuetype::napi_number) {
obj->SetMilliseconds(env, argv[0]);
return nullptr;
} else {
napi_value val = GetDate(env, argv[0]);
if (!val) {
return nullptr;
}
obj->SetMilliseconds(env, val);
return nullptr;
}
}
void I18nAddon::SetField(napi_env env, napi_value value, UCalendarDateFields field)
{
if (!value) {
return;
}
int32_t val = 0;
napi_valuetype valueType = napi_valuetype::napi_undefined;
napi_typeof(env, value, &valueType);
if (valueType == napi_valuetype::napi_undefined) {
return;
}
if (valueType != napi_valuetype::napi_number) {
napi_throw_type_error(env, nullptr, "Parameter type does not match");
return;
}
napi_status status = napi_get_value_int32(env, value, &val);
if (status != napi_ok) {
LOGE("Retrieve field failed");
return;
}
if (calendar_ != nullptr) {
calendar_->Set(field, val);
}
}
napi_value I18nAddon::SetTimeZone(napi_env env, napi_callback_info info)
{
size_t argc = 1;
napi_value argv[1] = { 0 };
argv[0] = nullptr;
napi_value thisVar = nullptr;
void *data = nullptr;
napi_get_cb_info(env, info, &argc, argv, &thisVar, &data);
napi_valuetype valueType = napi_valuetype::napi_undefined;
napi_typeof(env, argv[0], &valueType);
if (valueType != napi_valuetype::napi_string) {
napi_throw_type_error(env, nullptr, "Parameter type does not match");
return nullptr;
}
size_t len = 0;
napi_status status = napi_get_value_string_utf8(env, argv[0], nullptr, 0, &len);
if (status != napi_ok) {
LOGE("Get timezone length failed");
return nullptr;
}
std::vector<char> buf(len + 1);
status = napi_get_value_string_utf8(env, argv[0], buf.data(), len + 1, &len);
if (status != napi_ok) {
LOGE("Get timezone failed");
return nullptr;
}
std::string timezone(buf.data());
I18nAddon *obj = nullptr;
status = napi_unwrap(env, thisVar, reinterpret_cast<void **>(&obj));
if (status != napi_ok || !obj || !obj->calendar_) {
LOGE("Get calendar object failed");
return nullptr;
}
obj->calendar_->SetTimeZone(timezone);
return nullptr;
}
napi_value I18nAddon::GetTimeZone(napi_env env, napi_callback_info info)
{
size_t argc = 0;
napi_value *argv = nullptr;
napi_value thisVar = nullptr;
void *data = nullptr;
napi_get_cb_info(env, info, &argc, argv, &thisVar, &data);
I18nAddon *obj = nullptr;
napi_status status = napi_unwrap(env, thisVar, reinterpret_cast<void **>(&obj));
if (status != napi_ok || !obj || !obj->calendar_) {
LOGE("Get calendar object failed");
return nullptr;
}
std::string temp = obj->calendar_->GetTimeZone();
napi_value result = nullptr;
status = napi_create_string_utf8(env, temp.c_str(), NAPI_AUTO_LENGTH, &result);
if (status != napi_ok) {
LOGE("Create timezone string failed");
return nullptr;
}
return result;
}
napi_value I18nAddon::GetFirstDayOfWeek(napi_env env, napi_callback_info info)
{
size_t argc = 0;
napi_value *argv = nullptr;
napi_value thisVar = nullptr;
void *data = nullptr;
napi_get_cb_info(env, info, &argc, argv, &thisVar, &data);
I18nAddon *obj = nullptr;
napi_status status = napi_unwrap(env, thisVar, reinterpret_cast<void **>(&obj));
if (status != napi_ok || !obj || !obj->calendar_) {
LOGE("Get calendar object failed");
return nullptr;
}
int32_t temp = obj->calendar_->GetFirstDayOfWeek();
napi_value result = nullptr;
status = napi_create_int32(env, temp, &result);
if (status != napi_ok) {
LOGE("Create int32 failed");
return nullptr;
}
return result;
}
napi_value I18nAddon::GetMinimalDaysInFirstWeek(napi_env env, napi_callback_info info)
{
size_t argc = 0;
napi_value *argv = nullptr;
napi_value thisVar = nullptr;
void *data = nullptr;
napi_get_cb_info(env, info, &argc, argv, &thisVar, &data);
I18nAddon *obj = nullptr;
napi_status status = napi_unwrap(env, thisVar, reinterpret_cast<void **>(&obj));
if (status != napi_ok || !obj || !obj->calendar_) {
LOGE("Get calendar object failed");
return nullptr;
}
int32_t temp = obj->calendar_->GetMinimalDaysInFirstWeek();
napi_value result = nullptr;
status = napi_create_int32(env, temp, &result);
if (status != napi_ok) {
LOGE("Create int32 failed");
return nullptr;
}
return result;
}
napi_value I18nAddon::SetFirstDayOfWeek(napi_env env, napi_callback_info info)
{
size_t argc = 1;
napi_value argv[1] = { 0 };
argv[0] = nullptr;
napi_value thisVar = nullptr;
void *data = nullptr;
napi_get_cb_info(env, info, &argc, argv, &thisVar, &data);
napi_valuetype valueType = napi_valuetype::napi_undefined;
napi_typeof(env, argv[0], &valueType);
if (valueType != napi_valuetype::napi_number) {
napi_throw_type_error(env, nullptr, "Parameter type does not match");
return nullptr;
}
int32_t value = 0;
napi_status status = napi_get_value_int32(env, argv[0], &value);
if (status != napi_ok) {
LOGE("Get int32 failed");
return nullptr;
}
I18nAddon *obj = nullptr;
status = napi_unwrap(env, thisVar, reinterpret_cast<void **>(&obj));
if (status != napi_ok || !obj || !obj->calendar_) {
LOGE("Get calendar object failed");
return nullptr;
}
obj->calendar_->SetFirstDayOfWeek(value);
return nullptr;
}
napi_value I18nAddon::SetMinimalDaysInFirstWeek(napi_env env, napi_callback_info info)
{
size_t argc = 1;
napi_value argv[1] = { 0 };
argv[0] = nullptr;
napi_value thisVar = nullptr;
void *data = nullptr;
napi_get_cb_info(env, info, &argc, argv, &thisVar, &data);
napi_valuetype valueType = napi_valuetype::napi_undefined;
napi_typeof(env, argv[0], &valueType);
if (valueType != napi_valuetype::napi_number) {
napi_throw_type_error(env, nullptr, "Parameter type does not match");
return nullptr;
}
int32_t value = 0;
napi_status status = napi_get_value_int32(env, argv[0], &value);
if (status != napi_ok) {
LOGE("Get int32 failed");
return nullptr;
}
I18nAddon *obj = nullptr;
status = napi_unwrap(env, thisVar, reinterpret_cast<void **>(&obj));
if (status != napi_ok || !obj || !obj->calendar_) {
LOGE("Get calendar object failed");
return nullptr;
}
obj->calendar_->SetMinimalDaysInFirstWeek(value);
return nullptr;
}
napi_value I18nAddon::Get(napi_env env, napi_callback_info info)
{
size_t argc = 1;
napi_value argv[1] = { 0 };
argv[0] = nullptr;
napi_value thisVar = nullptr;
void *data = nullptr;
napi_get_cb_info(env, info, &argc, argv, &thisVar, &data);
napi_valuetype valueType = napi_valuetype::napi_undefined;
napi_typeof(env, argv[0], &valueType);
if (valueType != napi_valuetype::napi_string) {
napi_throw_type_error(env, nullptr, "Parameter type does not match");
return nullptr;
}
size_t len = 0;
napi_status status = napi_get_value_string_utf8(env, argv[0], nullptr, 0, &len);
if (status != napi_ok) {
LOGE("Get field length failed");
return nullptr;
}
std::vector<char> buf(len + 1);
status = napi_get_value_string_utf8(env, argv[0], buf.data(), len + 1, &len);
if (status != napi_ok) {
LOGE("Get field failed");
return nullptr;
}
std::string field(buf.data());
if (g_fieldsMap.find(field) == g_fieldsMap.end()) {
LOGE("Invalid field");
return nullptr;
}
I18nAddon *obj = nullptr;
status = napi_unwrap(env, thisVar, reinterpret_cast<void **>(&obj));
if (status != napi_ok || !obj || !obj->calendar_) {
LOGE("Get calendar object failed");
return nullptr;
}
int32_t value = obj->calendar_->Get(g_fieldsMap[field]);
napi_value result = nullptr;
status = napi_create_int32(env, value, &result);
if (status != napi_ok) {
LOGE("Create int32 failed");
return nullptr;
}
return result;
}
napi_value I18nAddon::Add(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) {
LOGE("can not obtain add function param.");
ErrorUtil::NapiThrow(env, I18N_NOT_FOUND, true);
return nullptr;
}
napi_valuetype valueType = napi_valuetype::napi_undefined;
napi_typeof(env, argv[0], &valueType);
if (valueType != napi_valuetype::napi_string) {
LOGE("Parameter type does not match");
ErrorUtil::NapiThrow(env, I18N_NOT_FOUND, true);
return nullptr;
}
int32_t code = 0;
std::string field = GetAddField(env, argv[0], code);
if (code) {
return nullptr;
}
napi_typeof(env, argv[1], &valueType);
if (valueType != napi_valuetype::napi_number) {
LOGE("Parameter type does not match");
ErrorUtil::NapiThrow(env, I18N_NOT_FOUND, true);
return nullptr;
}
int32_t amount;
status = napi_get_value_int32(env, argv[1], &amount);
if (status != napi_ok) {
LOGE("Can not obtain add function param.");
ErrorUtil::NapiThrow(env, I18N_NOT_VALID, true);
return nullptr;
}
I18nAddon *obj = nullptr;
status = napi_unwrap(env, thisVar, reinterpret_cast<void **>(&obj));
if (status != napi_ok || !obj || !obj->calendar_) {
LOGE("Get calendar object failed");
return nullptr;
}
obj->calendar_->Add(g_fieldsMap[field], amount);
return nullptr;
}
napi_value I18nAddon::GetDisplayName(napi_env env, napi_callback_info info)
{
size_t argc = 1;
napi_value argv[1] = { 0 };
argv[0] = nullptr;
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;
}
napi_valuetype valueType = napi_valuetype::napi_undefined;
status = napi_typeof(env, argv[0], &valueType);
if (status != napi_ok) {
return nullptr;
}
if (valueType != napi_valuetype::napi_string) {
LOGE("GetDisplayName: Parameter type does not match");
return nullptr;
}
int32_t code = 0;
std::string localeTag = NAPIUtils::GetString(env, argv[0], code);
if (code) {
return nullptr;
}
I18nAddon *obj = nullptr;
status = napi_unwrap(env, thisVar, reinterpret_cast<void **>(&obj));
if (status != napi_ok || !obj || !obj->calendar_) {
LOGE("Get calendar object failed");
return nullptr;
}
if (!obj->calendar_) {
return nullptr;
}
std::string name = obj->calendar_->GetDisplayName(localeTag);
napi_value result = nullptr;
status = napi_create_string_utf8(env, name.c_str(), NAPI_AUTO_LENGTH, &result);
if (status != napi_ok) {
LOGE("Create calendar name string failed");
return nullptr;
}
return result;
}
napi_value I18nAddon::GetTimeInMillis(napi_env env, napi_callback_info info)
{
bool flag = true;
size_t argc = 0;
napi_value *argv = nullptr;
napi_value thisVar = nullptr;
void *data = nullptr;
napi_get_cb_info(env, info, &argc, argv, &thisVar, &data);
I18nAddon *obj = nullptr;
napi_status status = napi_unwrap(env, thisVar, reinterpret_cast<void **>(&obj));
if (status != napi_ok || !obj || !obj->calendar_) {
LOGE("Get calendar object failed");
flag = false;
}
UDate temp = 0;
if (flag) {
temp = obj->calendar_->GetTimeInMillis();
}
napi_value result = nullptr;
status = napi_create_double(env, temp, &result);
if (status != napi_ok) {
LOGE("Create UDate failed");
napi_create_double(env, 0, &result);
}
return result;
}
napi_value I18nAddon::IsWeekend(napi_env env, napi_callback_info info)
{
size_t argc = 1;
napi_value argv[1] = { 0 };
argv[0] = nullptr;
napi_value thisVar = nullptr;
void *data = nullptr;
napi_get_cb_info(env, info, &argc, argv, &thisVar, &data);
I18nAddon *obj = nullptr;
bool isWeekEnd = false;
napi_status status = napi_unwrap(env, thisVar, reinterpret_cast<void **>(&obj));
do {
if (status != napi_ok || !obj || !obj->calendar_) {
LOGE("Get calendar object failed");
break;
}
if (argc == 0) {
isWeekEnd = obj->calendar_->IsWeekend();
} else {
napi_value funcGetDateInfo = nullptr;
status = napi_get_named_property(env, argv[0], "valueOf", &funcGetDateInfo);
if (status != napi_ok) {
LOGE("Get method now failed");
break;
}
napi_value value = nullptr;
status = napi_call_function(env, argv[0], funcGetDateInfo, 0, nullptr, &value);
if (status != napi_ok) {
LOGE("Get milliseconds failed");
break;
}
double milliseconds = 0;
status = napi_get_value_double(env, value, &milliseconds);
if (status != napi_ok) {
LOGE("Retrieve milliseconds failed");
break;
}
UErrorCode error = U_ZERO_ERROR;
isWeekEnd = obj->calendar_->IsWeekend(milliseconds, error);
}
} while (false);
napi_value result = nullptr;
status = napi_get_boolean(env, isWeekEnd, &result);
if (status != napi_ok) {
LOGE("Create boolean failed");
return nullptr;
}
return result;
}
napi_value I18nAddon::CompareDays(napi_env env, napi_callback_info info)
{
size_t argc = 1;
napi_value argv[1] = { 0 };
napi_value thisVar = nullptr;
void *data = nullptr;
napi_get_cb_info(env, info, &argc, argv, &thisVar, &data);
napi_value result = nullptr;
UDate milliseconds = 0;
napi_status status = napi_get_date_value(env, argv[0], &milliseconds);
if (status != napi_ok) {
LOGE("compareDays function param is not Date");
ErrorUtil::NapiThrow(env, I18N_NOT_FOUND, true);
return nullptr;
}
I18nAddon *obj = nullptr;
status = napi_unwrap(env, thisVar, reinterpret_cast<void **>(&obj));
if (status != napi_ok || !obj || !obj->calendar_) {
LOGE("Get calendar object failed");
status = napi_create_int32(env, 0, &result);
return result;
}
int32_t diff_date = obj->calendar_->CompareDays(milliseconds);
status = napi_create_int32(env, diff_date, &result);
return result;
}
std::string I18nAddon::GetAddField(napi_env &env, napi_value &value, int32_t &code)
{
std::string field = NAPIUtils::GetString(env, value, code);
if (code != 0) {
LOGE("can't get string from js array param.");
ErrorUtil::NapiThrow(env, I18N_NOT_VALID, true);
return field;
}
if (g_fieldsInFunctionAdd.find(field) == g_fieldsInFunctionAdd.end()) {
code = 1;
LOGE("Parameter rangs do not match");
ErrorUtil::NapiThrow(env, I18N_NOT_VALID, true);
return field;
}
return field;
}
napi_value I18nAddon::InitIndexUtil(napi_env env, napi_value exports)
{
napi_property_descriptor properties[] = {
DECLARE_NAPI_FUNCTION("getIndexList", GetIndexList),
DECLARE_NAPI_FUNCTION("addLocale", AddLocale),
DECLARE_NAPI_FUNCTION("getIndex", GetIndex)
};
napi_value constructor = nullptr;
napi_status status = napi_define_class(env, "IndexUtil", NAPI_AUTO_LENGTH, IndexUtilConstructor, nullptr,
sizeof(properties) / sizeof(napi_property_descriptor), properties, &constructor);
if (status != napi_ok) {
LOGE("Define class failed when InitIndexUtil");
return nullptr;
}
status = napi_create_reference(env, constructor, 1, &g_indexUtilConstructor);
if (status != napi_ok) {
LOGE("Failed to create reference at init");
return nullptr;
}
return exports;
}
napi_value I18nAddon::BreakIteratorConstructor(napi_env env, napi_callback_info info)
{
size_t argc = 1;
napi_value argv[1] = { nullptr };
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;
}
napi_valuetype valueType = napi_valuetype::napi_undefined;
status = napi_typeof(env, argv[0], &valueType);
if (status != napi_ok) {
return nullptr;
}
if (valueType != napi_valuetype::napi_string) {
LOGE("BreakIteratorConstructor: Parameter type does not match");
return nullptr;
}
int32_t code = 0;
std::string localeTag = NAPIUtils::GetString(env, argv[0], code);
if (code) {
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) {
LOGE("BreakIteratorConstructor: Wrap II18nAddon failed");
return nullptr;
}
obj->brkiter_ = std::make_unique<I18nBreakIterator>(localeTag);
if (!obj->brkiter_) {
LOGE("Wrap BreakIterator failed");
return nullptr;
}
obj.release();
return thisVar;
}
napi_value I18nAddon::InitBreakIterator(napi_env env, napi_value exports)
{
napi_status status = napi_ok;
napi_property_descriptor properties[] = {
DECLARE_NAPI_FUNCTION("current", Current),
DECLARE_NAPI_FUNCTION("first", First),
DECLARE_NAPI_FUNCTION("last", Last),
DECLARE_NAPI_FUNCTION("next", Next),
DECLARE_NAPI_FUNCTION("previous", Previous),
DECLARE_NAPI_FUNCTION("setLineBreakText", SetText),
DECLARE_NAPI_FUNCTION("following", Following),
DECLARE_NAPI_FUNCTION("getLineBreakText", GetText),
DECLARE_NAPI_FUNCTION("isBoundary", IsBoundary),
};
napi_value constructor = nullptr;
status = napi_define_class(env, "BreakIterator", NAPI_AUTO_LENGTH, BreakIteratorConstructor, nullptr,
sizeof(properties) / sizeof(napi_property_descriptor), properties, &constructor);
if (status != napi_ok) {
LOGE("Failed to define class BreakIterator at Init");
return nullptr;
}
g_brkConstructor = new (std::nothrow) napi_ref;
if (!g_brkConstructor) {
LOGE("Failed to create brkiterator ref at init");
return nullptr;
}
status = napi_create_reference(env, constructor, 1, g_brkConstructor);
if (status != napi_ok) {
LOGE("Failed to create reference g_brkConstructor at init");
return nullptr;
}
return exports;
}
napi_value I18nAddon::GetLineInstance(napi_env env, napi_callback_info info)
{
size_t argc = 1;
napi_value argv[1] = { nullptr };
napi_value thisVar = nullptr;
void *data = nullptr;
napi_get_cb_info(env, info, &argc, argv, &thisVar, &data);
napi_value constructor = nullptr;
napi_status status = napi_get_reference_value(env, *g_brkConstructor, &constructor);
if (status != napi_ok) {
LOGE("Failed to create reference at GetLineInstance");
return nullptr;
}
if (argc == 0) {
return nullptr;
}
napi_value result = nullptr;
status = napi_new_instance(env, constructor, 1, argv, &result);
if (status != napi_ok) {
LOGE("GetLineInstance create instance failed");
return nullptr;
}
return result;
}
napi_value I18nAddon::Current(napi_env env, napi_callback_info info)
{
size_t argc = 0;
napi_value *argv = nullptr;
napi_value thisVar = nullptr;
void *data = nullptr;
napi_get_cb_info(env, info, &argc, argv, &thisVar, &data);
I18nAddon *obj = nullptr;
napi_status status = napi_unwrap(env, thisVar, reinterpret_cast<void **>(&obj));
if (status != napi_ok || !obj || !obj->brkiter_) {
LOGE("Get BreakIterator object failed");
return nullptr;
}
int value = obj->brkiter_->Current();
napi_value result = nullptr;
status = napi_create_int32(env, value, &result);
if (status != napi_ok) {
LOGE("Create int32_t value failed");
return nullptr;
}
return result;
}
napi_value I18nAddon::First(napi_env env, napi_callback_info info)
{
size_t argc = 0;
napi_value *argv = nullptr;
napi_value thisVar = nullptr;
void *data = nullptr;
napi_get_cb_info(env, info, &argc, argv, &thisVar, &data);
I18nAddon *obj = nullptr;
napi_status status = napi_unwrap(env, thisVar, reinterpret_cast<void **>(&obj));
if (status != napi_ok || !obj || !obj->brkiter_) {
LOGE("Get BreakIterator object failed");
return nullptr;
}
int value = obj->brkiter_->First();
napi_value result = nullptr;
status = napi_create_int32(env, value, &result);
if (status != napi_ok) {
LOGE("Create int32_t value failed");
return nullptr;
}
return result;
}
napi_value I18nAddon::Last(napi_env env, napi_callback_info info)
{
size_t argc = 0;
napi_value *argv = nullptr;
napi_value thisVar = nullptr;
void *data = nullptr;
napi_get_cb_info(env, info, &argc, argv, &thisVar, &data);
I18nAddon *obj = nullptr;
napi_status status = napi_unwrap(env, thisVar, reinterpret_cast<void **>(&obj));
if (status != napi_ok || !obj || !obj->brkiter_) {
LOGE("Get BreakIterator object failed");
return nullptr;
}
int value = obj->brkiter_->Last();
napi_value result = nullptr;
status = napi_create_int32(env, value, &result);
if (status != napi_ok) {
LOGE("Create int32_t value failed");
return nullptr;
}
return result;
}
napi_value I18nAddon::Previous(napi_env env, napi_callback_info info)
{
size_t argc = 0;
napi_value *argv = nullptr;
napi_value thisVar = nullptr;
void *data = nullptr;
napi_get_cb_info(env, info, &argc, argv, &thisVar, &data);
I18nAddon *obj = nullptr;
napi_status status = napi_unwrap(env, thisVar, reinterpret_cast<void **>(&obj));
if (status != napi_ok || !obj || !obj->brkiter_) {
LOGE("Get BreakIterator object failed");
return nullptr;
}
int value = obj->brkiter_->Previous();
napi_value result = nullptr;
status = napi_create_int32(env, value, &result);
if (status != napi_ok) {
LOGE("Create int32_t value failed");
return nullptr;
}
return result;
}
napi_value I18nAddon::Next(napi_env env, napi_callback_info info)
{
size_t argc = 1;
napi_value argv[1] = { nullptr };
napi_value thisVar = nullptr;
void *data = nullptr;
napi_get_cb_info(env, info, &argc, argv, &thisVar, &data);
I18nAddon *obj = nullptr;
napi_status status = napi_unwrap(env, thisVar, reinterpret_cast<void **>(&obj));
if (status != napi_ok || !obj || !obj->brkiter_) {
LOGE("Get BreakIterator object failed");
return nullptr;
}
int value = 1;
if (argc > 0) {
napi_valuetype valueType = napi_valuetype::napi_undefined;
napi_typeof(env, argv[0], &valueType);
if (valueType != napi_valuetype::napi_number) {
napi_throw_type_error(env, nullptr, "Parameter type does not match");
return nullptr;
}
status = napi_get_value_int32(env, argv[0], &value);
if (status != napi_ok) {
LOGE("Retrieve next value failed");
return nullptr;
}
}
value = obj->brkiter_->Next(value);
napi_value result = nullptr;
status = napi_create_int32(env, value, &result);
if (status != napi_ok) {
LOGE("Create int32_t value failed");
return nullptr;
}
return result;
}
napi_value I18nAddon::SetText(napi_env env, napi_callback_info info)
{
size_t argc = 1;
napi_value argv[1] = { nullptr };
napi_value thisVar = nullptr;
void *data = nullptr;
napi_get_cb_info(env, info, &argc, argv, &thisVar, &data);
I18nAddon *obj = nullptr;
napi_status status = napi_unwrap(env, thisVar, reinterpret_cast<void **>(&obj));
if (status != napi_ok || !obj || !obj->brkiter_) {
LOGE("Get BreakIterator object failed");
return nullptr;
}
if (argc == 0) {
return nullptr;
}
napi_valuetype valueType = napi_valuetype::napi_undefined;
napi_typeof(env, argv[0], &valueType);
if (valueType != napi_valuetype::napi_string) {
napi_throw_type_error(env, nullptr, "Parameter type does not match");
return nullptr;
}
size_t len = 0;
status = napi_get_value_string_utf8(env, argv[0], nullptr, 0, &len);
if (status != napi_ok) {
LOGE("Get field length failed");
return nullptr;
}
std::vector<char> buf(len + 1);
status = napi_get_value_string_utf8(env, argv[0], buf.data(), len + 1, &len);
if (status != napi_ok) {
LOGE("Get string value failed");
return nullptr;
}
obj->brkiter_->SetText(buf.data());
return nullptr;
}
napi_value I18nAddon::GetText(napi_env env, napi_callback_info info)
{
size_t argc = 0;
napi_value *argv = nullptr;
napi_value thisVar = nullptr;
void *data = nullptr;
napi_get_cb_info(env, info, &argc, argv, &thisVar, &data);
I18nAddon *obj = nullptr;
napi_status status = napi_unwrap(env, thisVar, reinterpret_cast<void **>(&obj));
if (status != napi_ok || !obj || !obj->brkiter_) {
LOGE("Get BreakIterator object failed");
return nullptr;
}
napi_value value = nullptr;
std::string temp;
obj->brkiter_->GetText(temp);
status = napi_create_string_utf8(env, temp.c_str(), NAPI_AUTO_LENGTH, &value);
if (status != napi_ok) {
LOGE("Get field length failed");
return nullptr;
}
return value;
}
napi_value I18nAddon::Following(napi_env env, napi_callback_info info)
{
size_t argc = 1;
napi_value argv[1] = { nullptr };
napi_value thisVar = nullptr;
void *data = nullptr;
napi_get_cb_info(env, info, &argc, argv, &thisVar, &data);
I18nAddon *obj = nullptr;
napi_status status = napi_unwrap(env, thisVar, reinterpret_cast<void **>(&obj));
if (status != napi_ok || !obj || !obj->brkiter_) {
LOGE("Get BreakIterator object failed");
return nullptr;
}
if (argc == 0) {
return nullptr;
}
napi_valuetype valueType = napi_valuetype::napi_undefined;
napi_typeof(env, argv[0], &valueType);
if (valueType != napi_valuetype::napi_number) {
napi_throw_type_error(env, nullptr, "Parameter type does not match");
return nullptr;
}
int value;
status = napi_get_value_int32(env, argv[0], &value);
if (status != napi_ok) {
LOGE("Retrieve following value failed");
return nullptr;
}
value = obj->brkiter_->Following(value);
napi_value result = nullptr;
status = napi_create_int32(env, value, &result);
if (status != napi_ok) {
LOGE("Create int32_t value failed");
return nullptr;
}
return result;
}
napi_value I18nAddon::IsBoundary(napi_env env, napi_callback_info info)
{
size_t argc = 1;
napi_value argv[1] = { nullptr };
napi_value thisVar = nullptr;
void *data = nullptr;
napi_get_cb_info(env, info, &argc, argv, &thisVar, &data);
I18nAddon *obj = nullptr;
napi_status status = napi_unwrap(env, thisVar, reinterpret_cast<void **>(&obj));
if (status != napi_ok || !obj || !obj->brkiter_) {
LOGE("Get BreakIterator object failed");
return nullptr;
}
if (argc == 0) {
return nullptr;
}
napi_valuetype valueType = napi_valuetype::napi_undefined;
int value;
napi_typeof(env, argv[0], &valueType);
if (valueType != napi_valuetype::napi_number) {
napi_throw_type_error(env, nullptr, "Parameter type does not match");
return nullptr;
}
status = napi_get_value_int32(env, argv[0], &value);
if (status != napi_ok) {
LOGE("Retrieve following value failed");
return nullptr;
}
bool boundary = obj->brkiter_->IsBoundary(value);
napi_value result = nullptr;
status = napi_get_boolean(env, boundary, &result);
if (status != napi_ok) {
LOGE("Create boolean failed");
return nullptr;
}
return result;
}
napi_value I18nAddon::IndexUtilConstructor(napi_env env, napi_callback_info info)
{
size_t argc = 1;
napi_value argv[1] = { 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::string localeTag = "";
if (argc > 0) {
napi_valuetype valueType = napi_valuetype::napi_undefined;
napi_typeof(env, argv[0], &valueType);
if (valueType != napi_valuetype::napi_string) {
napi_throw_type_error(env, nullptr, "Parameter type does not match");
return nullptr;
}
size_t len = 0;
status = napi_get_value_string_utf8(env, argv[0], nullptr, 0, &len);
if (status != napi_ok) {
LOGE("Get locale length failed");
return nullptr;
}
std::vector<char> localeBuf(len + 1);
status = napi_get_value_string_utf8(env, argv[0], localeBuf.data(), len + 1, &len);
if (status != napi_ok) {
LOGE("Get locale failed");
return nullptr;
}
localeTag = localeBuf.data();
}
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) {
LOGE("IndexUtilConstructor: Wrap II18nAddon failed");
return nullptr;
}
if (!obj->InitIndexUtilContext(env, info, localeTag)) {
return nullptr;
}
obj.release();
return thisVar;
}
bool I18nAddon::InitIndexUtilContext(napi_env env, napi_callback_info info, const std::string &localeTag)
{
napi_value global = nullptr;
napi_status status = napi_get_global(env, &global);
if (status != napi_ok) {
LOGE("Get global failed");
return false;
}
env_ = env;
indexUtil_ = std::make_unique<IndexUtil>(localeTag);
return indexUtil_ != nullptr;
}
napi_value I18nAddon::GetIndexUtil(napi_env env, napi_callback_info info)
{
size_t argc = 1;
napi_value argv[1] = { 0 };
napi_value thisVar = nullptr;
void *data = nullptr;
napi_get_cb_info(env, info, &argc, argv, &thisVar, &data);
napi_value constructor = nullptr;
napi_status status = napi_get_reference_value(env, g_indexUtilConstructor, &constructor);
if (status != napi_ok) {
LOGE("Failed to create reference at GetIndexUtil");
return nullptr;
}
napi_value result = nullptr;
if (argc == 0) {
status = napi_new_instance(env, constructor, 0, argv, &result);
} else {
status = napi_new_instance(env, constructor, 1, argv, &result);
}
if (status != napi_ok) {
LOGE("Get calendar create instance failed");
return nullptr;
}
return result;
}
napi_value I18nAddon::GetIndexList(napi_env env, napi_callback_info info)
{
size_t argc = 0;
napi_value argv[0];
napi_value thisVar = nullptr;
void *data = nullptr;
napi_get_cb_info(env, info, &argc, argv, &thisVar, &data);
I18nAddon *obj = nullptr;
napi_status status = napi_unwrap(env, thisVar, reinterpret_cast<void **>(&obj));
if (status != napi_ok || !obj || !obj->indexUtil_) {
LOGE("GetPhoneNumberFormat object failed");
return nullptr;
}
std::vector<std::string> indexList = obj->indexUtil_->GetIndexList();
napi_value result = nullptr;
status = napi_create_array_with_length(env, indexList.size(), &result);
if (status != napi_ok) {
LOGE("Failed to create array");
return nullptr;
}
for (size_t i = 0; i < indexList.size(); i++) {
napi_value element = nullptr;
status = napi_create_string_utf8(env, indexList[i].c_str(), NAPI_AUTO_LENGTH, &element);
if (status != napi_ok) {
LOGE("Failed to create string item");
return nullptr;
}
status = napi_set_element(env, result, i, element);
if (status != napi_ok) {
LOGE("Failed to set array item");
return nullptr;
}
}
return result;
}
napi_value I18nAddon::AddLocale(napi_env env, napi_callback_info info)
{
size_t argc = 1;
napi_value argv[1] = { 0 };
napi_value thisVar = nullptr;
void *data = nullptr;
napi_get_cb_info(env, info, &argc, argv, &thisVar, &data);
napi_valuetype valueType = napi_valuetype::napi_undefined;
napi_typeof(env, argv[0], &valueType);
if (valueType != napi_valuetype::napi_string) {
napi_throw_type_error(env, nullptr, "Parameter type does not match");
return nullptr;
}
size_t len = 0;
napi_status status = napi_get_value_string_utf8(env, argv[0], nullptr, 0, &len);
if (status != napi_ok) {
LOGE("Get locale length failed");
return nullptr;
}
std::vector<char> buf(len + 1);
status = napi_get_value_string_utf8(env, argv[0], buf.data(), len + 1, &len);
if (status != napi_ok) {
LOGE("Get locale failed");
return nullptr;
}
I18nAddon *obj = nullptr;
status = napi_unwrap(env, thisVar, reinterpret_cast<void **>(&obj));
if (status != napi_ok || !obj || !obj->indexUtil_) {
LOGE("Get IndexUtil object failed");
return nullptr;
}
obj->indexUtil_->AddLocale(buf.data());
return nullptr;
}
napi_value I18nAddon::GetIndex(napi_env env, napi_callback_info info)
{
size_t argc = 1;
napi_value argv[1] = { 0 };
napi_value thisVar = nullptr;
void *data = nullptr;
napi_get_cb_info(env, info, &argc, argv, &thisVar, &data);
napi_valuetype valueType = napi_valuetype::napi_undefined;
napi_typeof(env, argv[0], &valueType);
if (valueType != napi_valuetype::napi_string) {
napi_throw_type_error(env, nullptr, "Parameter type does not match");
return nullptr;
}
size_t len = 0;
napi_status status = napi_get_value_string_utf8(env, argv[0], nullptr, 0, &len);
if (status != napi_ok) {
LOGE("Get String length failed");
return nullptr;
}
std::vector<char> buf(len + 1);
status = napi_get_value_string_utf8(env, argv[0], buf.data(), len + 1, &len);
if (status != napi_ok) {
LOGE("Get String failed");
return nullptr;
}
I18nAddon *obj = nullptr;
status = napi_unwrap(env, thisVar, reinterpret_cast<void **>(&obj));
if (status != napi_ok || !obj || !obj->indexUtil_) {
LOGE("Get IndexUtil object failed");
return nullptr;
}
std::string index = obj->indexUtil_->GetIndex(buf.data());
napi_value result = nullptr;
status = napi_create_string_utf8(env, index.c_str(), NAPI_AUTO_LENGTH, &result);
if (status != napi_ok) {
LOGE("GetIndex Failed");
return nullptr;
}
return result;
}
napi_value I18nAddon::Is24HourClock(napi_env env, napi_callback_info info)
{
bool is24HourClock = LocaleConfig::Is24HourClock();
napi_value result = nullptr;
napi_status status = napi_get_boolean(env, is24HourClock, &result);
if (status != napi_ok) {
LOGE("Failed to create boolean item");
return nullptr;
}
return result;
}
napi_value I18nAddon::SetAppPreferredLanguage(napi_env env, napi_callback_info info)
{
size_t argc = 1;
napi_value argv[1] = { 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;
}
napi_valuetype valueType = napi_valuetype::napi_undefined;
status = napi_typeof(env, argv[0], &valueType);
if (status != napi_ok) {
return nullptr;
}
if (valueType != napi_valuetype::napi_string) {
LOGE("SetAppPreferredLanguage Parameter type is not string");
ErrorUtil::NapiThrow(env, I18N_NOT_FOUND, "language", "string", true);
return nullptr;
}
size_t len = 0;
status = napi_get_value_string_utf8(env, argv[0], nullptr, 0, &len);
if (status != napi_ok) {
LOGE("SetAppPreferredLanguage: Get string failed");
return nullptr;
}
std::vector<char> buf(len + 1);
status = napi_get_value_string_utf8(env, argv[0], buf.data(), len + 1, &len);
if (status != napi_ok) {
LOGE("SetAppPreferredLanguage: Create string failed");
return nullptr;
}
std::string localeTag(buf.data());
UErrorCode icuStatus = U_ZERO_ERROR;
icu::Locale locale = icu::Locale::forLanguageTag(localeTag.data(), icuStatus);
if (U_FAILURE(icuStatus) || !(IsValidLocaleTag(locale) || localeTag.compare("default") == 0)) {
LOGE("SetAppPreferredLanguage does not support this locale");
ErrorUtil::NapiThrow(env, I18N_NOT_VALID, "language", "a valid language", true);
return nullptr;
}
LocaleConfig::SetAppPreferredLanguage(localeTag);
return nullptr;
}
napi_value I18nAddon::GetAppPreferredLanguage(napi_env env, napi_callback_info info)
{
std::string language = LocaleConfig::GetAppPreferredLanguage();
napi_value result = nullptr;
napi_status status = napi_create_string_utf8(env, language.c_str(), NAPI_AUTO_LENGTH, &result);
if (status != napi_ok) {
LOGE("getAppPreferredLanguage: create string result failed");
return nullptr;
}
return result;
}
bool I18nAddon::ParseStringParam(napi_env env, napi_value argv, bool throwError, std::string &strParam)
{
if (argv == nullptr) {
LOGE("Missing parameter");
ErrorUtil::NapiThrow(env, I18N_NOT_FOUND, throwError);
return false;
}
napi_valuetype valueType = napi_valuetype::napi_undefined;
napi_typeof(env, argv, &valueType);
if (valueType != napi_valuetype::napi_string) {
ErrorUtil::NapiThrow(env, I18N_NOT_VALID, throwError);
return false;
}
size_t len = 0;
napi_status status = napi_get_value_string_utf8(env, argv, nullptr, 0, &len);
if (status != napi_ok) {
LOGE("get string parameter length failed");
ErrorUtil::NapiThrow(env, I18N_NOT_VALID, throwError);
return false;
}
std::vector<char> res(len + 1);
status = napi_get_value_string_utf8(env, argv, res.data(), len + 1, &len);
if (status != napi_ok) {
LOGE("get string parameter failed");
return false;
}
strParam = res.data();
return true;
}
bool I18nAddon::GetStringFromJS(napi_env env, napi_value argv, std::string &jsString)
{
size_t len = 0;
napi_status status = napi_get_value_string_utf8(env, argv, nullptr, 0, &len);
if (status != napi_ok) {
LOGE("Failed to get string length");
return false;
}
std::vector<char> argvBuf(len + 1);
status = napi_get_value_string_utf8(env, argv, argvBuf.data(), len + 1, &len);
if (status != napi_ok) {
LOGE("Failed to get string item");
return false;
}
jsString = argvBuf.data();
return true;
}
int32_t I18nAddon::GetParameter(napi_env env, napi_value *argv, std::string &localeStr, bool &isDST)
{
if (!argv[0]) {
return 0;
}
napi_status status = napi_ok;
if (!argv[1]) {
napi_valuetype valueType = napi_valuetype::napi_undefined;
napi_typeof(env, argv[0], &valueType);
if (valueType == napi_valuetype::napi_string) {
bool valid = GetStringFromJS(env, argv[0], localeStr);
if (!valid) {
return -1;
}
return 1;
} else if (valueType == napi_valuetype::napi_boolean) {
status = napi_get_value_bool(env, argv[0], &isDST);
if (status != napi_ok) {
return -1;
}
return 2;
} else {
return -1;
}
}
napi_valuetype valueType0 = napi_valuetype::napi_undefined;
napi_valuetype valueType1 = napi_valuetype::napi_undefined;
napi_typeof(env, argv[0], &valueType0);
napi_typeof(env, argv[1], &valueType1);
if (valueType0 != napi_valuetype::napi_string || valueType1 != napi_valuetype::napi_boolean) {
return -1;
}
bool valid = GetStringFromJS(env, argv[0], localeStr);
if (!valid) {
return -1;
}
status = napi_get_value_bool(env, argv[1], &isDST);
if (status != napi_ok) {
return -1;
}
return 3;
}
napi_value I18nAddon::CreateTimeZoneObject(napi_env env, napi_status &initStatus)
{
napi_status status = napi_ok;
napi_value timezone = nullptr;
status = napi_create_object(env, &timezone);
if (status != napi_ok) {
LOGE("Failed to create timezone object at init");
initStatus = napi_generic_failure;
return nullptr;
}
napi_property_descriptor timezoneProperties[] = {
DECLARE_NAPI_STATIC_FUNCTION("getAvailableIDs", I18nTimeZoneAddon::GetAvailableTimezoneIDs),
};
status = napi_define_properties(env, timezone,
sizeof(timezoneProperties) / sizeof(napi_property_descriptor),
timezoneProperties);
if (status != napi_ok) {
LOGE("Failed to set properties of timezone at init");
initStatus = napi_generic_failure;
return nullptr;
}
return timezone;
}
napi_value I18nAddon::CreateSystemObject(napi_env env, napi_status &initStatus)
{
napi_status status = napi_ok;
napi_value system = nullptr;
status = napi_create_object(env, &system);
if (status != napi_ok) {
LOGE("Failed to create system object at init");
initStatus = napi_generic_failure;
return nullptr;
}
napi_property_descriptor systemProperties[] = {
DECLARE_NAPI_FUNCTION("getDisplayCountry", GetDisplayCountryWithError),
DECLARE_NAPI_FUNCTION("getDisplayLanguage", GetDisplayLanguageWithError),
DECLARE_NAPI_FUNCTION("getSystemLanguage", GetSystemLanguage),
DECLARE_NAPI_FUNCTION("getSystemRegion", GetSystemRegion),
DECLARE_NAPI_FUNCTION("getSystemLocale", GetSystemLocale),
DECLARE_NAPI_FUNCTION("is24HourClock", Is24HourClock),
DECLARE_NAPI_STATIC_FUNCTION("setAppPreferredLanguage", SetAppPreferredLanguage),
DECLARE_NAPI_STATIC_FUNCTION("getAppPreferredLanguage", GetAppPreferredLanguage),
DECLARE_NAPI_STATIC_FUNCTION("getSystemLanguages", I18nSystemAddon::GetSystemLanguages),
DECLARE_NAPI_STATIC_FUNCTION("getSystemCountries", I18nSystemAddon::GetSystemCountriesWithError),
DECLARE_NAPI_STATIC_FUNCTION("isSuggested", I18nSystemAddon::IsSuggestedWithError),
DECLARE_NAPI_STATIC_FUNCTION("getPreferredLanguageList", I18nSystemAddon::GetPreferredLanguageList),
DECLARE_NAPI_STATIC_FUNCTION("getFirstPreferredLanguage", I18nSystemAddon::GetFirstPreferredLanguage),
DECLARE_NAPI_STATIC_FUNCTION("getUsingLocalDigit", I18nSystemAddon::GetUsingLocalDigitAddon),
DECLARE_NAPI_STATIC_FUNCTION("getSimplifiedLanguage", I18nSystemAddon::GetSimplifiedLanguage),
DECLARE_NAPI_STATIC_FUNCTION("getTemperatureType", I18nSystemAddon::GetTemperatureType),
DECLARE_NAPI_STATIC_FUNCTION("getTemperatureName", I18nSystemAddon::GetTemperatureName),
DECLARE_NAPI_STATIC_FUNCTION("getFirstDayOfWeek", I18nSystemAddon::GetFirstDayOfWeek),
};
status = napi_define_properties(env, system,
sizeof(systemProperties) / sizeof(napi_property_descriptor),
systemProperties);
if (status != napi_ok) {
LOGE("Failed to set properties of system at init");
initStatus = napi_generic_failure;
return nullptr;
}
return system;
}
napi_value I18nAddon::InitCharacter(napi_env env, napi_value exports)
{
napi_status status = napi_ok;
napi_property_descriptor properties[] = {
DECLARE_NAPI_FUNCTION("isDigit", IsDigitAddon),
DECLARE_NAPI_FUNCTION("isSpaceChar", IsSpaceCharAddon),
DECLARE_NAPI_FUNCTION("isWhitespace", IsWhiteSpaceAddon),
DECLARE_NAPI_FUNCTION("isRTL", IsRTLCharacterAddon),
DECLARE_NAPI_FUNCTION("isIdeograph", IsIdeoGraphicAddon),
DECLARE_NAPI_FUNCTION("isLetter", IsLetterAddon),
DECLARE_NAPI_FUNCTION("isLowerCase", IsLowerCaseAddon),
DECLARE_NAPI_FUNCTION("isUpperCase", IsUpperCaseAddon),
DECLARE_NAPI_FUNCTION("getType", GetTypeAddon)
};
napi_value constructor = nullptr;
status = napi_define_class(env, "Character", NAPI_AUTO_LENGTH, ObjectConstructor, nullptr,
sizeof(properties) / sizeof(napi_property_descriptor), properties, &constructor);
if (status != napi_ok) {
LOGE("Define class failed when InitCharacter");
return nullptr;
}
status = napi_set_named_property(env, exports, "Character", constructor);
if (status != napi_ok) {
LOGE("Set property failed when InitCharacter");
return nullptr;
}
return exports;
}
napi_value I18nAddon::ObjectConstructor(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) {
LOGE("Wrap I18nAddon failed");
return nullptr;
}
obj.release();
return thisVar;
}
napi_value I18nAddon::GetI18nNormalizerInstance(napi_env env, napi_callback_info info)
{
size_t argc = 1;
napi_value argv[1] = { nullptr };
napi_value thisVar = nullptr;
void *data = nullptr;
napi_status status = napi_get_cb_info(env, info, &argc, argv, &thisVar, &data);
if (status != napi_ok) {
LOGE("Failed to get parameter of Normalizer.createInstance");
return nullptr;
}
napi_value constructor = nullptr;
status = napi_get_reference_value(env, *g_normalizerConstructor, &constructor);
if (status != napi_ok) {
LOGE("Failed to create reference of normalizer Constructor");
return nullptr;
}
napi_value result = nullptr;
status = napi_new_instance(env, constructor, argc, argv, &result);
if (status != napi_ok) {
LOGE("create normalizer instance failed");
return nullptr;
}
return result;
}
napi_value I18nAddon::InitI18nNormalizer(napi_env env, napi_value exports)
{
napi_property_descriptor properties[] = {
DECLARE_NAPI_FUNCTION("normalize", Normalize)
};
napi_value constructor = nullptr;
napi_status status = napi_define_class(env, "Normalizer", NAPI_AUTO_LENGTH, I18nNormalizerConstructor, nullptr,
sizeof(properties) / sizeof(napi_property_descriptor), properties, &constructor);
if (status != napi_ok) {
LOGE("Failed to define class Normalizer at Init");
return nullptr;
}
g_normalizerConstructor = new (std::nothrow) napi_ref;
if (!g_normalizerConstructor) {
LOGE("Failed to create Normalizer ref at init");
return nullptr;
}
status = napi_create_reference(env, constructor, 1, g_normalizerConstructor);
if (status != napi_ok) {
LOGE("Failed to create reference g_normalizerConstructor at init.");
return nullptr;
}
return exports;
}
napi_value I18nAddon::I18nNormalizerConstructor(napi_env env, napi_callback_info info)
{
size_t argc = 1;
napi_value argv[1] = { nullptr };
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;
}
if (argc == 0) {
ErrorUtil::NapiThrow(env, I18N_NOT_FOUND, true);
}
napi_valuetype valueType = napi_valuetype::napi_undefined;
napi_typeof(env, argv[0], &valueType);
if (valueType != napi_valuetype::napi_number) {
ErrorUtil::NapiThrow(env, I18N_NOT_FOUND, true);
}
int32_t normalizerMode;
status = napi_get_value_int32(env, argv[0], &normalizerMode);
if (status != napi_ok) {
return nullptr;
}
if (normalizerMode != NORMALIZER_MODE_NFC && normalizerMode != NORMALIZER_MODE_NFD &&
normalizerMode != NORMALIZER_MODE_NFKC && normalizerMode != NORMALIZER_MODE_NFKD) {
ErrorUtil::NapiThrow(env, I18N_NOT_FOUND, true);
}
std::unique_ptr<I18nAddon> obj = std::make_unique<I18nAddon>();
status =
napi_wrap(env, thisVar, reinterpret_cast<void *>(obj.get()), I18nAddon::Destructor, nullptr, nullptr);
if (status != napi_ok) {
return nullptr;
}
I18nNormalizerMode mode = I18nNormalizerMode(normalizerMode);
I18nErrorCode errorCode = I18nErrorCode::SUCCESS;
obj->normalizer_ = std::make_unique<I18nNormalizer>(mode, errorCode);
if (errorCode != I18nErrorCode::SUCCESS || !obj->normalizer_) {
return nullptr;
}
obj.release();
return thisVar;
}
napi_value I18nAddon::Normalize(napi_env env, napi_callback_info info)
{
size_t argc = 1;
napi_value argv[1] = { 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;
}
if (argc == 0) {
ErrorUtil::NapiThrow(env, I18N_NOT_FOUND, true);
}
napi_valuetype valueType = napi_valuetype::napi_undefined;
napi_typeof(env, argv[0], &valueType);
if (valueType != napi_valuetype::napi_string) {
LOGE("Invalid parameter type");
ErrorUtil::NapiThrow(env, I18N_NOT_FOUND, true);
}
int32_t code = 0;
std::string text = NAPIUtils::GetString(env, argv[0], code);
if (code != 0) {
return nullptr;
}
I18nAddon *obj = nullptr;
status = napi_unwrap(env, thisVar, reinterpret_cast<void **>(&obj));
if (status != napi_ok || obj == nullptr || obj->normalizer_ == nullptr) {
LOGE("Get Normalizer object failed");
return nullptr;
}
I18nErrorCode errorCode = I18nErrorCode::SUCCESS;
std::string normalizedText = obj->normalizer_->Normalize(text.c_str(), static_cast<int32_t>(text.length()),
errorCode);
if (errorCode != I18nErrorCode::SUCCESS) {
return nullptr;
}
napi_value result = nullptr;
status = napi_create_string_utf8(env, normalizedText.c_str(), NAPI_AUTO_LENGTH, &result);
if (status != napi_ok) {
LOGE("Create result failed");
return nullptr;
}
return result;
}
napi_value Init(napi_env env, napi_value exports)
{
napi_value val = I18nAddon::Init(env, exports);
val = I18nAddon::InitPhoneNumberFormat(env, val);
val = I18nAddon::InitBreakIterator(env, val);
val = I18nAddon::InitI18nCalendar(env, val);
val = I18nAddon::InitIndexUtil(env, val);
val = I18nAddon::InitTransliterator(env, val);
val = I18nAddon::InitCharacter(env, val);
val = I18nAddon::InitI18nNormalizer(env, val);
val = I18nTimeZoneAddon::InitI18nTimeZone(env, val);
val = EntityRecognizerAddon::InitEntityRecognizer(env, val);
val = HolidayManagerAddon::InitHolidayManager(env, val);
val = ZoneRulesAddon::InitI18nZoneRules(env, val);
val = ZoneOffsetTransitionAddon::InitZoneOffsetTransition(env, val);
return val;
}
static napi_module g_i18nModule = {
.nm_version = 1,
.nm_flags = 0,
.nm_filename = nullptr,
.nm_register_func = Init,
.nm_modname = "i18n",
.nm_priv = nullptr,
.reserved = { 0 }
};
#ifdef ANDROID_PLATFORM
static void I18NPluginJniRegister()
{
const char className[] = "ohos.ace.plugin.i18nplugin.I18NPlugin";
ARKUI_X_Plugin_RegisterJavaPlugin(&Plugin::I18NPluginJni::Register, className);
}
#endif
extern "C" __attribute__((constructor)) void I18nRegister()
{
#ifdef ANDROID_PLATFORM
I18NPluginJniRegister();
#else
InitIcuData();
#endif
napi_module_register(&g_i18nModule);
}
}
}
}