arkui_ace_engine/frameworks/base/i18n/localization.cpp
yhpeng a3adf3b62c revert: resolve conflict
Signed-off-by: yhpeng <pengyuhao1@huawei.com>
2024-07-18 19:45:29 +08:00

1015 lines
32 KiB
C++

/*
* Copyright (c) 2021-2022 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 "base/i18n/localization.h"
#include <cstddef>
#include <cstring>
#include <map>
#include <type_traits>
#include <unordered_map>
#include <utility>
#include "chnsecal.h"
#include "unicode/calendar.h"
#include "unicode/datefmt.h"
#include "unicode/dtfmtsym.h"
#include "unicode/dtptngen.h"
#include "unicode/fieldpos.h"
#include "unicode/fmtable.h"
#include "unicode/locid.h"
#include "unicode/measfmt.h"
#include "unicode/measunit.h"
#include "unicode/measure.h"
#include "unicode/numberformatter.h"
#include "unicode/plurrule.h"
#include "unicode/reldatefmt.h"
#include "unicode/smpdtfmt.h"
#include "unicode/stringpiece.h"
#include "unicode/ucal.h"
#include "unicode/unistr.h"
#include "unicode/upluralrules.h"
#include "unicode/ureldatefmt.h"
#include "unicode/utypes.h"
#include "unicode/uversion.h"
#include "date_time_sequence.h"
#include "base/json/json_util.h"
#include "base/log/log.h"
#include "base/resource/internal_resource.h"
#include "base/utils/linear_map.h"
#include "base/utils/string_utils.h"
#include "base/utils/utils.h"
namespace OHOS::Ace {
using namespace icu;
struct LocaleProxy final {
LocaleProxy(const char* language, const char* countryOrRegion, const char* variant, const char* keywordsAndValues)
: instance(language, countryOrRegion, variant, keywordsAndValues)
{}
~LocaleProxy() = default;
Locale instance;
};
namespace {
#define CHECK_RETURN(status, ret) \
do { \
if ((status) > U_ZERO_ERROR) { \
LOGW("status = %{public}d", static_cast<int32_t>(status)); \
return (ret); \
} \
} while (0)
#define CHECK_NO_RETURN(status) \
do { \
if ((status) > U_ZERO_ERROR) { \
LOGW("status = %{public}d", static_cast<int32_t>(status)); \
} \
} while (0)
const char JSON_PATH_CARVE = '.';
const char DEFAULT_LANGUAGE[] = "en-US";
constexpr uint32_t SEXAGENARY_CYCLE_SIZE = 60;
constexpr uint32_t GUIHAI_YEAR_RECENT = 3;
constexpr uint32_t SECONDS_IN_HOUR = 3600;
const char CHINESE_LEAP[] = u8"\u95f0";
const char CHINESE_FIRST[] = u8"\u521d";
const char CHINESE_TEN[] = u8"\u5341";
const char CHINESE_TWENTY[] = u8"\u5eff";
const char* g_chineseOneToNine[] = { u8"\u4e00", u8"\u4e8c", u8"\u4e09", u8"\u56db", u8"\u4e94", u8"\u516d", u8"\u4e03",
u8"\u516b", u8"\u4e5d" };
const std::unordered_map<std::string, std::string> LANGUAGE_CODE_MAP {
{ "he", "iw" },
{ "fil", "tl" },
{ "id", "in" },
};
inline void UnicodeString2String(const UnicodeString& source, std::string& result)
{
source.toUTF8String(result);
}
DateFormat::EStyle DateTimeStyle2EStyle(DateTimeStyle dateTimeStyle)
{
switch (dateTimeStyle) {
case DateTimeStyle::NONE:
return DateFormat::EStyle::kNone;
case DateTimeStyle::FULL:
return DateFormat::EStyle::kFull;
case DateTimeStyle::LONG:
return DateFormat::EStyle::kLong;
case DateTimeStyle::MEDIUM:
return DateFormat::EStyle::kMedium;
case DateTimeStyle::SHORT:
return DateFormat::EStyle::kShort;
default:
return DateFormat::EStyle::kNone;
}
}
UMeasureFormatWidth GetMeasureFormatWidth(MeasureFormatStyle formatStyle)
{
switch (formatStyle) {
case MeasureFormatStyle::WIDTH_WIDE:
return UMeasureFormatWidth::UMEASFMT_WIDTH_WIDE;
case MeasureFormatStyle::WIDTH_SHORT:
return UMeasureFormatWidth::UMEASFMT_WIDTH_SHORT;
case MeasureFormatStyle::WIDTH_NARROW:
return UMeasureFormatWidth::UMEASFMT_WIDTH_NARROW;
case MeasureFormatStyle::WIDTH_NUMERIC:
return UMeasureFormatWidth::UMEASFMT_WIDTH_NUMERIC;
case MeasureFormatStyle::WIDTH_COUNT:
return UMeasureFormatWidth::UMEASFMT_WIDTH_COUNT;
default:
return UMeasureFormatWidth::UMEASFMT_WIDTH_WIDE;
}
}
MeasureUnit* GetMeasureUnit(TimeUnitStyle timeUnitStyle, UErrorCode& status)
{
switch (timeUnitStyle) {
case TimeUnitStyle::YEAR:
return MeasureUnit::createYear(status);
case TimeUnitStyle::MONTH:
return MeasureUnit::createMonth(status);
case TimeUnitStyle::DAY:
return MeasureUnit::createDay(status);
case TimeUnitStyle::HOUR:
return MeasureUnit::createHour(status);
case TimeUnitStyle::MINUTE:
return MeasureUnit::createMinute(status);
case TimeUnitStyle::SECOND:
return MeasureUnit::createSecond(status);
case TimeUnitStyle::MILLISECOND:
return MeasureUnit::createMillisecond(status);
default:
return MeasureUnit::createYear(status);
}
}
void GetLocalJsonObject(InternalResource::ResourceId id, std::string language, std::unique_ptr<JsonValue>& indexJson,
std::unique_ptr<JsonValue>& json)
{
if (indexJson == nullptr) {
size_t size = 0;
const uint8_t* buf = InternalResource::GetInstance().GetResource(id, size);
if (buf == nullptr) {
return;
}
std::string jsonStr(reinterpret_cast<const char*>(buf), size);
const char* endMsg = nullptr;
indexJson = JsonUtil::ParseJsonString(jsonStr, &endMsg);
if (indexJson == nullptr) {
LOGE("read indexletter json failed. reason: %{private}s.", endMsg);
return;
}
}
if (indexJson->Contains(language) && indexJson->GetValue(language)->IsObject()) {
json = indexJson->GetValue(language);
} else if (indexJson->Contains(DEFAULT_LANGUAGE) && indexJson->GetValue(DEFAULT_LANGUAGE)->IsObject()) {
json = indexJson->GetValue(DEFAULT_LANGUAGE);
}
}
} // namespace
// for entry.json
static std::unique_ptr<JsonValue> g_indexJsonEntry = nullptr;
static std::unique_ptr<JsonValue> g_indexJsonError = nullptr;
Localization::~Localization() = default;
void Localization::SetLocaleImpl(const std::string& language, const std::string& countryOrRegion,
const std::string& script, const std::string& selectLanguage, const std::string& keywordsAndValues)
{
locale_ = std::make_unique<LocaleProxy>(language.c_str(), countryOrRegion.c_str(), "", keywordsAndValues.c_str());
UErrorCode status = U_ZERO_ERROR;
std::vector<std::string> keyValuePairs;
StringUtils::StringSplitter(keywordsAndValues, ';', keyValuePairs);
for (const auto& pair : keyValuePairs) {
// [pair] is like "nu=arab" or "nu=" for most occasions, but may be "=" under extreme scenarios
std::vector<std::string> res;
StringUtils::StringSplitter(pair, '=', res);
if (res.size() == 0) {
continue;
}
auto value = (res.size() == 2) ? res[1] : "";
locale_->instance.setUnicodeKeywordValue(res[0], value, status);
CHECK_NO_RETURN(status);
}
languageTag_ = language;
if (!script.empty()) {
languageTag_.append("-").append(script);
}
languageTag_.append("-").append(countryOrRegion);
fontLocale_ = languageTag_;
// Simple chinese
if (languageTag_ == "zh-Hans-CN") {
languageTag_ = "zh-CN";
fontLocale_ = "";
}
selectLanguage_ = selectLanguage;
// match json of latin
if (selectLanguage_ == "jv-Latn") {
selectLanguage_ = "b+jv+Latn";
} else if (selectLanguage_ == "sr-Latn") {
selectLanguage_ = "b+sr+Latn";
}
LOGI("SetLocale language tag: %{public}s, select language: %{public}s", languageTag_.c_str(),
selectLanguage_.c_str());
if (!isPromiseUsed_) {
promise_.set_value(true);
isPromiseUsed_ = true;
}
}
std::string Localization::GetLanguage()
{
WaitingForInit();
if (locale_) {
return locale_->instance.getLanguage();
}
return "";
}
std::string Localization::GetLanguageTag()
{
WaitingForInit();
return languageTag_;
}
std::string Localization::GetFontLocale()
{
WaitingForInit();
return fontLocale_;
}
const std::string Localization::FormatDuration(uint32_t duration, bool needShowHour)
{
WaitingForInit();
UErrorCode status = U_ZERO_ERROR;
// duration greater than 1 hour, use HH:mm:ss;
if (!needShowHour && duration > SECONDS_IN_HOUR) {
needShowHour = true;
}
const char* engTimeFormat = needShowHour ? "HH:mm:ss" : "mm:ss";
auto simpleDateFormat = std::make_unique<SimpleDateFormat>(UnicodeString(engTimeFormat), locale_->instance, status);
CHECK_RETURN(status, "");
TimeZone* timeZone = TimeZone::createTimeZone("GMT+0:00");
simpleDateFormat->setTimeZone(*timeZone);
UnicodeString simpleStr;
simpleDateFormat->format(1000.0 * duration, simpleStr, status);
delete(timeZone);
CHECK_RETURN(status, "");
std::string ret;
UnicodeString2String(simpleStr, ret);
return ret;
}
std::string Localization::FormatDuration(uint32_t duration, const std::string& format)
{
WaitingForInit();
UErrorCode status = U_ZERO_ERROR;
const char* engTimeFormat = format.c_str();
auto simpleDateFormat = std::make_unique<SimpleDateFormat>(UnicodeString(engTimeFormat), locale_->instance, status);
CHECK_RETURN(status, "");
TimeZone* timeZone = TimeZone::createTimeZone("GMT+0:00");
simpleDateFormat->setTimeZone(*timeZone);
UnicodeString simpleStr;
simpleDateFormat->format(1.0 * duration, simpleStr, status);
CHECK_RETURN(status, "");
std::string ret;
UnicodeString2String(simpleStr, ret);
delete(timeZone);
return ret;
}
const std::string Localization::FormatDateTime(DateTime dateTime, const std::string& format)
{
WaitingForInit();
UErrorCode status = U_ZERO_ERROR;
auto cal = Calendar::createInstance(locale_->instance, status);
CHECK_RETURN(status, "");
cal->set(dateTime.year, dateTime.month, dateTime.day, dateTime.hour, dateTime.minute, dateTime.second);
UDate date = cal->getTime(status);
delete cal;
CHECK_RETURN(status, "");
auto patternGenerator = DateTimePatternGenerator::createInstance(locale_->instance, status);
CHECK_RETURN(status, "");
UnicodeString pattern = patternGenerator->getBestPattern(UnicodeString(format.c_str()), status);
delete patternGenerator;
CHECK_RETURN(status, "");
auto dateFormat = std::make_unique<SimpleDateFormat>(pattern, locale_->instance, status);
CHECK_RETURN(status, "");
UnicodeString dateTimeStr;
dateFormat->format(date, dateTimeStr, status);
CHECK_RETURN(status, "");
std::string ret;
UnicodeString2String(dateTimeStr, ret);
return ret;
}
bool Localization::GetDateColumnFormatOrder(std::vector<std::string>& outOrder)
{
outOrder.clear();
WaitingForInit();
UErrorCode status = U_ZERO_ERROR;
auto patternGenerator = DateTimePatternGenerator::createInstance(locale_->instance, status);
CHECK_RETURN(status, false);
std::string format = "yyyyMMdd";
UnicodeString pattern = patternGenerator->getBestPattern(UnicodeString(format.c_str()), status);
delete patternGenerator;
CHECK_RETURN(status, false);
std::string result;
UnicodeString2String(pattern, result);
std::map<std::size_t, std::string> order;
std::size_t position = result.find("yyyy");
if (position == std::string::npos) {
return false;
}
order[position] = "year";
position = result.find("MM");
if (position == std::string::npos) {
return false;
}
order[position] = "month";
position = result.find("dd");
if (position == std::string::npos) {
return false;
}
order[position] = "day";
for (auto it = order.begin(); it != order.end(); ++it) {
outOrder.emplace_back(it->second);
}
return true;
}
bool Localization::GetDateOrder(std::vector<std::string>& outOrder)
{
std::string dateOrder;
DateTimeSequence sequence;
std::string language = locale_->instance.getLanguage();
OrderResult orderResult = sequence.GetDateOrder(language);
dateOrder = orderResult.dateOrder;
std::map<std::size_t, std::string> order;
std::size_t position = dateOrder.find("y");
if (position == std::string::npos) {
return false;
}
order[position] = "year";
position = dateOrder.find("M");
if (position == std::string::npos) {
return false;
}
order[position] = "month";
position = dateOrder.find("d");
if (position == std::string::npos) {
return false;
}
order[position] = "day";
for (auto it = order.begin(); it != order.end(); ++it) {
outOrder.emplace_back(it->second);
}
return true;
}
bool Localization::Contain(const std::string& str, const std::string& tag)
{
auto pos = str.find(tag);
return (pos != std::string::npos);
}
bool Localization::GetHourFormat(bool& isAmPm, bool& hasZero)
{
WaitingForInit();
UErrorCode status = U_ZERO_ERROR;
auto patternGenerator = DateTimePatternGenerator::createInstance(locale_->instance, status);
CHECK_RETURN(status, false);
std::string format = "J:mm";
UnicodeString pattern = patternGenerator->getBestPattern(UnicodeString(format.c_str()), status);
delete patternGenerator;
CHECK_RETURN(status, false);
std::string result;
UnicodeString2String(pattern, result);
if (Contain(result, "hh") || Contain(result, "KK")) {
isAmPm = true;
hasZero = true;
return true;
}
if (Contain(result, "h") || Contain(result, "K")) {
isAmPm = true;
hasZero = false;
return true;
}
if (Contain(result, "HH") || Contain(result, "kk")) {
isAmPm = false;
hasZero = true;
return true;
}
if (Contain(result, "H") || Contain(result, "k")) {
isAmPm = false;
hasZero = false;
return true;
}
return false;
}
const std::string Localization::FormatDateTime(DateTime dateTime, DateTimeStyle dateStyle, DateTimeStyle timeStyle)
{
WaitingForInit();
UErrorCode status = U_ZERO_ERROR;
auto cal = Calendar::createInstance(locale_->instance, status);
CHECK_RETURN(status, "");
cal->set(dateTime.year, dateTime.month, dateTime.day, dateTime.hour, dateTime.minute, dateTime.second);
UDate date = cal->getTime(status);
delete cal;
CHECK_RETURN(status, "");
auto dateFormat = DateFormat::createDateTimeInstance(
DateTimeStyle2EStyle(dateStyle), DateTimeStyle2EStyle(timeStyle), locale_->instance);
if (dateFormat == nullptr) {
return "";
}
UnicodeString dateTimeStr;
dateFormat->format(date, dateTimeStr, status);
delete dateFormat;
CHECK_RETURN(status, "");
std::string ret;
UnicodeString2String(dateTimeStr, ret);
return ret;
}
std::vector<std::string> Localization::GetMonths(bool isShortType, const std::string& calendarType)
{
WaitingForInit();
std::vector<std::string> months;
UErrorCode status = U_ZERO_ERROR;
DateFormatSymbols dateformat(locale_->instance, calendarType.c_str(), status);
CHECK_RETURN(status, months);
int32_t count = 0;
auto monthsUniStr = dateformat.getMonths(count, DateFormatSymbols::DtContextType::STANDALONE,
isShortType ? DateFormatSymbols::DtWidthType::SHORT : DateFormatSymbols::DtWidthType::WIDE);
if (count > 0) {
std::string month;
for (int32_t i = 0; i < count; i++) {
month.clear();
UnicodeString2String(monthsUniStr[i], month);
months.push_back(month);
}
}
return months;
}
std::vector<std::string> Localization::GetWeekdays(bool isShortType)
{
WaitingForInit();
std::vector<std::string> weekdays;
UErrorCode status = U_ZERO_ERROR;
DateFormatSymbols dateformat(locale_->instance, status);
CHECK_RETURN(status, weekdays);
int32_t count = 0;
auto language = locale_->instance.getLanguage();
auto widthType = isShortType ? (strcmp(language, "zh") == 0 || strcmp(language, "bo") == 0)
? DateFormatSymbols::DtWidthType::NARROW
: DateFormatSymbols::DtWidthType::ABBREVIATED
: DateFormatSymbols::DtWidthType::WIDE;
auto weekdaysUniStr = dateformat.getWeekdays(count, DateFormatSymbols::DtContextType::STANDALONE, widthType);
if (count > 0) {
std::string weekday;
for (int32_t i = 0; i < count; i++) {
weekday.clear();
UnicodeString2String(weekdaysUniStr[i], weekday);
if (!weekday.empty()) {
weekdays.push_back(weekday);
}
}
}
return weekdays;
}
std::vector<std::string> Localization::GetAmPmStrings()
{
WaitingForInit();
std::vector<std::string> amPms;
UErrorCode status = U_ZERO_ERROR;
DateFormatSymbols dateformat(locale_->instance, status);
CHECK_RETURN(status, amPms);
int32_t count = 0;
auto amPmUniStr = dateformat.getAmPmStrings(count);
if (count > 0) {
std::string amPm;
for (int32_t i = 0; i < count; i++) {
amPm.clear();
UnicodeString2String(amPmUniStr[i], amPm);
amPms.push_back(amPm);
}
}
return amPms;
}
std::string Localization::GetRelativeDateTime(double offset)
{
WaitingForInit();
UErrorCode status = U_ZERO_ERROR;
RelativeDateTimeFormatter relativeDateformat(locale_->instance, status);
CHECK_RETURN(status, "");
UnicodeString relativeDate;
relativeDateformat.format(offset, URelativeDateTimeUnit::UDAT_REL_UNIT_DAY, relativeDate, status);
CHECK_RETURN(status, "");
std::string ret;
UnicodeString2String(relativeDate, ret);
return ret;
}
LunarDate Localization::GetLunarDate(Date date)
{
WaitingForInit();
LunarDate dateRet;
UErrorCode status = U_ZERO_ERROR;
Locale locale("zh", "CN");
auto cal = Calendar::createInstance(locale, status);
CHECK_RETURN(status, dateRet);
// 0 means January, 1 means February, so month - 1
if (date.month == 0u) {
date.month = 11u;
cal->set(date.year, date.month, date.day);
} else {
cal->set(date.year, date.month - 1u, date.day);
}
UDate udate = cal->getTime(status);
delete cal;
CHECK_RETURN(status, dateRet);
ChineseCalendar chineseCalendar(locale, status);
CHECK_RETURN(status, dateRet);
chineseCalendar.setTime(udate, status);
CHECK_RETURN(status, dateRet);
int32_t lunarYear = chineseCalendar.get(UCalendarDateFields::UCAL_YEAR, status);
CHECK_RETURN(status, dateRet);
int32_t lunarMonth = chineseCalendar.get(UCalendarDateFields::UCAL_MONTH, status);
CHECK_RETURN(status, dateRet);
int32_t lunarDate = chineseCalendar.get(UCalendarDateFields::UCAL_DATE, status);
CHECK_RETURN(status, dateRet);
int32_t isLeapMonth = chineseCalendar.get(UCalendarDateFields::UCAL_IS_LEAP_MONTH, status);
CHECK_RETURN(status, dateRet);
// Sexagenary cycle years convert to Western years
dateRet.year = static_cast<uint32_t>(lunarYear) + GUIHAI_YEAR_RECENT;
dateRet.year +=
((static_cast<uint32_t>(date.year) - GUIHAI_YEAR_RECENT) / SEXAGENARY_CYCLE_SIZE) * SEXAGENARY_CYCLE_SIZE;
// 0 means January, 1 means February, so month + 1
dateRet.month = static_cast<uint32_t>(lunarMonth) + 1;
dateRet.day = static_cast<uint32_t>(lunarDate);
dateRet.isLeapMonth = !(isLeapMonth == 0);
return dateRet;
}
std::string Localization::GetLunarMonth(uint32_t month, bool isLeapMonth)
{
WaitingForInit();
std::vector<std::string> months = Localization::GetInstance()->GetMonths(false, "chinese");
if (month <= months.size() && month > 0) {
std::string leap;
if (isLeapMonth) {
leap += std::string(CHINESE_LEAP);
}
return leap + months[month - 1];
} else {
return "";
}
}
std::string Localization::GetLunarDay(uint32_t dayOfMonth)
{
WaitingForInit();
if (dayOfMonth > 30 || dayOfMonth == 0) {
return "";
}
std::string ret;
if (dayOfMonth < 10) {
ret = std::string(CHINESE_FIRST) + std::string(g_chineseOneToNine[dayOfMonth - 1]);
} else if (dayOfMonth == 10) {
ret = std::string(CHINESE_FIRST) + std::string(CHINESE_TEN);
} else if (dayOfMonth < 20) {
ret = std::string(CHINESE_TEN) + std::string(g_chineseOneToNine[dayOfMonth - 11]);
} else if (dayOfMonth == 20) {
ret = std::string(CHINESE_TWENTY) + std::string(CHINESE_TEN);
} else if (dayOfMonth == 30) {
ret = g_chineseOneToNine[2] + std::string(CHINESE_TEN);
} else {
ret = std::string(CHINESE_TWENTY) + std::string(g_chineseOneToNine[dayOfMonth - 21]);
}
return ret;
}
std::string Localization::TimeUnitFormat(double timeValue, TimeUnitStyle timeStyle, MeasureFormatStyle formatStyle)
{
WaitingForInit();
UErrorCode status = U_ZERO_ERROR;
MeasureFormat measureFormat(locale_->instance, GetMeasureFormatWidth(formatStyle), status);
CHECK_RETURN(status, "");
MeasureUnit* minuteUnit = GetMeasureUnit(timeStyle, status);
CHECK_RETURN(status, "");
Formattable formattable(timeValue);
Measure measure(formattable, minuteUnit, status);
CHECK_RETURN(status, "");
UnicodeString timeUnit;
FieldPosition fieldPosition;
measureFormat.formatMeasures(&measure, 1, timeUnit, fieldPosition, status);
CHECK_RETURN(status, "");
std::string ret;
UnicodeString2String(timeUnit, ret);
return ret;
}
std::string Localization::PluralRulesFormat(double number, bool isCardinal)
{
WaitingForInit();
UErrorCode status = U_ZERO_ERROR;
UPluralType pluralType = isCardinal ? UPluralType::UPLURAL_TYPE_CARDINAL : UPluralType::UPLURAL_TYPE_ORDINAL;
PluralRules* pluralRules = PluralRules::forLocale(locale_->instance, pluralType, status);
CHECK_RETURN(status, "");
UnicodeString numberFormat = pluralRules->select(number);
delete pluralRules;
std::string ret;
UnicodeString2String(numberFormat, ret);
return ret;
}
std::string Localization::NumberFormat(double number)
{
WaitingForInit();
UErrorCode status = U_ZERO_ERROR;
icu::number::LocalizedNumberFormatter formatter = icu::number::NumberFormatter::withLocale(locale_->instance);
icu::number::FormattedNumber formattedNumber = formatter.formatDouble(number, status);
CHECK_RETURN(status, "");
UnicodeString numberFormat = formattedNumber.toString(status);
CHECK_RETURN(status, "");
std::string ret;
UnicodeString2String(numberFormat, ret);
return ret;
}
std::vector<std::u16string> Localization::GetLetters(bool alphabet)
{
WaitingForInit();
std::vector<std::u16string> letters;
size_t size = 0;
const uint8_t* buf =
InternalResource::GetInstance().GetResource(InternalResource::ResourceId::INDEXLETTER_BAR_JSON, size);
if (buf == nullptr) {
return letters;
}
std::string jsonStr(reinterpret_cast<const char*>(buf), size);
const char* endMsg = nullptr;
auto indexLetterJson = JsonUtil::ParseJsonString(jsonStr, &endMsg);
if (indexLetterJson == nullptr) {
return letters;
}
std::string language = locale_->instance.getLanguage();
if (language == "zh") {
language = language + "-" + std::string(locale_->instance.getCountry());
}
auto iter = LANGUAGE_CODE_MAP.find(language);
if (iter != LANGUAGE_CODE_MAP.end()) {
language = iter->second;
}
LOGI("[alphabet] Localization::GetLetters. language: %{private}s", language.c_str());
std::unique_ptr<JsonValue> lettersSet;
if (!indexLetterJson->Contains(language) || !indexLetterJson->GetValue(language)->IsObject()) {
lettersSet = indexLetterJson->GetValue("default");
} else {
lettersSet = indexLetterJson->GetValue(language);
}
std::string letterType = alphabet ? "alphabet" : "index";
std::unique_ptr<JsonValue> lettersArray;
if (!lettersSet->Contains(letterType) || !lettersSet->GetValue(letterType)->IsArray()) {
return letters;
} else {
lettersArray = lettersSet->GetValue(letterType)->GetChild();
}
while (lettersArray->IsValid()) {
letters.push_back(StringUtils::Str8ToStr16(lettersArray->GetString()));
lettersArray = lettersArray->GetNext();
}
return letters;
}
std::vector<std::u16string> Localization::GetIndexLetter()
{
return GetLetters(false);
}
std::vector<std::u16string> Localization::GetIndexAlphabet()
{
return GetLetters(true);
}
std::string Localization::GetEntryLetters(const std::string& lettersIndex)
{
WaitingForInit();
if (lettersIndex.empty()) {
return "";
}
std::unique_ptr<JsonValue> localJsonEntry;
auto language = selectLanguage_;
auto iter = LANGUAGE_CODE_MAP.find(language);
if (iter != LANGUAGE_CODE_MAP.end()) {
language = iter->second;
}
GetLocalJsonObject(InternalResource::ResourceId::ENTRY_JSON, language, g_indexJsonEntry, localJsonEntry);
if (localJsonEntry == nullptr) {
LOGW("read JsonObject fail. language: %{public}s.", selectLanguage_.c_str());
return "";
}
std::vector<std::string> jsonLetterIndex;
StringUtils::StringSplitter(lettersIndex, JSON_PATH_CARVE, jsonLetterIndex);
for (const auto& letter : jsonLetterIndex) {
if (localJsonEntry && localJsonEntry->Contains(letter)) {
localJsonEntry = localJsonEntry->GetValue(letter);
} else {
return "";
}
}
if (localJsonEntry->IsString()) {
return localJsonEntry->GetString();
}
return "";
}
std::string Localization::GetErrorDescription(const std::string& errorIndex)
{
WaitingForInit();
if (errorIndex.empty()) {
return "";
}
std::unique_ptr<JsonValue> localJsonError;
auto language = selectLanguage_;
auto iter = LANGUAGE_CODE_MAP.find(language);
if (iter != LANGUAGE_CODE_MAP.end()) {
language = iter->second;
}
GetLocalJsonObject(InternalResource::ResourceId::ERRORINFO_JSON, language, g_indexJsonError, localJsonError);
if (localJsonError == nullptr) {
LOGW("read JsonObject fail. language: %{public}s.", selectLanguage_.c_str());
return "";
}
if (localJsonError->Contains(errorIndex)) {
localJsonError = localJsonError->GetValue(errorIndex);
} else {
LOGW("read error json failed. error path: %{private}s.", errorIndex.c_str());
return "";
}
if (localJsonError->IsString()) {
return localJsonError->GetString();
}
return "";
}
const std::vector<std::string>& Localization::GetLanguageList(const std::string& language)
{
static const LinearMapNode<std::vector<std::string>> multiLanguageMap[] = {
{ "am", { "am" } },
{ "ar", { "ar" } },
{ "as", { "as" } },
{ "az", { "az-AZ" } },
{ "be", { "be" } },
{ "bg", { "bg" } },
{ "bn", { "bn" } },
{ "bo", { "bo-CN" } },
{ "bs", { "bs" } },
{ "ca", { "ca" } },
{ "cs", { "cs" } },
{ "da", { "da" } },
{ "de", { "de" } },
{ "el", { "el" } },
{ "en", { "en-US", "en-GB" } },
{ "es", { "es,es-US" } },
{ "et", { "et" } },
{ "fa", { "fa" } },
{ "fi", { "fi" } },
{ "fil", { "fil" } },
{ "fr", { "fr" } },
{ "gl", { "gl-ES" } },
{ "he", { "he" } },
{ "hi", { "hi" } },
{ "hr", { "hr" } },
{ "hu", { "hu" } },
{ "id", { "id" } },
{ "in", { "in" } },
{ "it", { "it" } },
{ "iw", { "iw" } },
{ "ja", { "ja" } },
{ "jv", { "jv-Latn" } },
{ "ka", { "ka-GE" } },
{ "kk", { "kk-KZ" } },
{ "km", { "km-KH" } },
{ "kn", { "kn" } },
{ "ko", { "ko" } },
{ "lo", { "lo-LA" } },
{ "lt", { "lt" } },
{ "lv", { "lv" } },
{ "mai", { "mai" } },
{ "mi", { "mi" } },
{ "mk", { "mk" } },
{ "ml", { "ml" } },
{ "mn", { "mn" } },
{ "mr", { "mr" } },
{ "ms", { "ms" } },
{ "my", { "my-ZG", "my-MM" } },
{ "nb", { "nb" } },
{ "ne", { "ne" } },
{ "nl", { "nl" } },
{ "or", { "or" } },
{ "pa", { "pa" } },
{ "pl", { "pl" } },
{ "pt", { "pt", "pt-PT" } },
{ "ro", { "ro" } },
{ "ru", { "ru" } },
{ "si", { "si-LK" } },
{ "sk", { "sk" } },
{ "sl", { "sl" } },
{ "sr", { "sr-Latn" } },
{ "sv", { "sv" } },
{ "sw", { "sw" } },
{ "ta", { "ta" } },
{ "te", { "te" } },
{ "th", { "th" } },
{ "tl", { "tl" } },
{ "tr", { "tr" } },
{ "ug", { "ug" } },
{ "uk", { "uk" } },
{ "ur", { "ur" } },
{ "uz", { "uz-UZ" } },
{ "vi", { "vi" } },
{ "zh", { "zh-CN", "zh-HK", "zh-TW" } },
{ "zz", { "zz-ZX" } },
};
int64_t list = BinarySearchFindIndex(multiLanguageMap, ArraySize(multiLanguageMap), language.c_str());
if (list == -1) {
static const std::vector<std::string> defaultLanguage = { "en-US" };
return defaultLanguage;
}
return multiLanguageMap[list].value;
}
std::mutex Localization::mutex_;
std::shared_ptr<Localization> Localization::instance_;
bool Localization::firstInstance_ = true;
std::shared_ptr<Localization> Localization::GetInstance()
{
std::lock_guard<std::mutex> lock(mutex_);
if (!instance_) {
instance_ = std::make_shared<Localization>();
}
return instance_;
}
void Localization::SetLocale(const std::string& language, const std::string& countryOrRegion, const std::string& script,
const std::string& selectLanguage, const std::string& keywordsAndValues)
{
std::lock_guard<std::mutex> lock(mutex_);
if (instance_) {
instance_->HandleOnChange();
instance_->HandleOnMymrChange(script == "Qaag");
}
std::shared_ptr<Localization> instance;
if (!firstInstance_ || !instance_) {
if (instance_) {
auto onMymrChange = instance_->GetOnMymrChange();
instance_ = std::make_shared<Localization>();
instance_->SetOnMymrChange(onMymrChange);
} else {
instance_ = std::make_shared<Localization>();
}
}
firstInstance_ = false;
instance = instance_;
instance->SetLocaleImpl(language, countryOrRegion, script, selectLanguage, keywordsAndValues);
}
std::string Localization::ComputeScript(const std::string& language, const std::string& region)
{
icu::Locale locale(language.c_str(), region.c_str());
UErrorCode status = U_ZERO_ERROR;
locale.addLikelySubtags(status);
if (status != U_ZERO_ERROR) {
return std::string();
}
return locale.getScript();
}
void Localization::ParseLocaleTag(
const std::string& localeTag, std::string& language, std::string& script, std::string& region, bool needAddSubtags)
{
UErrorCode status = U_ZERO_ERROR;
icu::Locale locale = icu::Locale::forLanguageTag(icu::StringPiece(localeTag.c_str()), status);
if (needAddSubtags) {
locale.addLikelySubtags(status);
}
if (status != U_ZERO_ERROR) {
return;
}
language = locale.getLanguage();
script = locale.getScript();
region = locale.getCountry();
}
} // namespace OHOS::Ace