19596a2c1Sopenharmony_ci/* 29596a2c1Sopenharmony_ci * Copyright (c) 2021-2022 Huawei Device Co., Ltd. 39596a2c1Sopenharmony_ci * Licensed under the Apache License, Version 2.0 (the "License"); 49596a2c1Sopenharmony_ci * you may not use this file except in compliance with the License. 59596a2c1Sopenharmony_ci * You may obtain a copy of the License at 69596a2c1Sopenharmony_ci * 79596a2c1Sopenharmony_ci * http://www.apache.org/licenses/LICENSE-2.0 89596a2c1Sopenharmony_ci * 99596a2c1Sopenharmony_ci * Unless required by applicable law or agreed to in writing, software 109596a2c1Sopenharmony_ci * distributed under the License is distributed on an "AS IS" BASIS, 119596a2c1Sopenharmony_ci * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 129596a2c1Sopenharmony_ci * See the License for the specific language governing permissions and 139596a2c1Sopenharmony_ci * limitations under the License. 149596a2c1Sopenharmony_ci */ 159596a2c1Sopenharmony_ci#include "plural_rules.h" 169596a2c1Sopenharmony_ci 179596a2c1Sopenharmony_ci#include <unicode/stringpiece.h> 189596a2c1Sopenharmony_ci 199596a2c1Sopenharmony_ci#include "algorithm" 209596a2c1Sopenharmony_ci#include "i18n_hilog.h" 219596a2c1Sopenharmony_ci#include "locale_config.h" 229596a2c1Sopenharmony_ci#include "unicode/locid.h" 239596a2c1Sopenharmony_ci#include "plural_rules.h" 249596a2c1Sopenharmony_ci#include "map" 259596a2c1Sopenharmony_ci#include "set" 269596a2c1Sopenharmony_ci#include "string" 279596a2c1Sopenharmony_ci#include "unicode/unistr.h" 289596a2c1Sopenharmony_ci#include "unicode/upluralrules.h" 299596a2c1Sopenharmony_ci#include "utility" 309596a2c1Sopenharmony_ci#include "utils.h" 319596a2c1Sopenharmony_ci#include "unicode/utypes.h" 329596a2c1Sopenharmony_ci#include "vector" 339596a2c1Sopenharmony_ci 349596a2c1Sopenharmony_cinamespace OHOS { 359596a2c1Sopenharmony_cinamespace Global { 369596a2c1Sopenharmony_cinamespace I18n { 379596a2c1Sopenharmony_cistd::string PluralRules::ParseOption(std::map<std::string, std::string> &options, const std::string &key) 389596a2c1Sopenharmony_ci{ 399596a2c1Sopenharmony_ci std::map<std::string, std::string>::iterator it = options.find(key); 409596a2c1Sopenharmony_ci if (it != options.end()) { 419596a2c1Sopenharmony_ci return it->second; 429596a2c1Sopenharmony_ci } else { 439596a2c1Sopenharmony_ci return ""; 449596a2c1Sopenharmony_ci } 459596a2c1Sopenharmony_ci} 469596a2c1Sopenharmony_ci 479596a2c1Sopenharmony_ciint PluralRules::GetValidInteger(std::string &integerStr, int minValue, int maxValue, int defaultValue) 489596a2c1Sopenharmony_ci{ 499596a2c1Sopenharmony_ci int status = 0; 509596a2c1Sopenharmony_ci int validInteger = ConvertString2Int(integerStr, status); 519596a2c1Sopenharmony_ci if (status < 0) { 529596a2c1Sopenharmony_ci validInteger = defaultValue; 539596a2c1Sopenharmony_ci } 549596a2c1Sopenharmony_ci if (validInteger < minValue) { 559596a2c1Sopenharmony_ci validInteger = minValue; 569596a2c1Sopenharmony_ci } 579596a2c1Sopenharmony_ci if (validInteger > maxValue) { 589596a2c1Sopenharmony_ci validInteger = maxValue; 599596a2c1Sopenharmony_ci } 609596a2c1Sopenharmony_ci return validInteger; 619596a2c1Sopenharmony_ci} 629596a2c1Sopenharmony_ci 639596a2c1Sopenharmony_civoid PluralRules::ParseAllOptions(std::map<std::string, std::string> &options) 649596a2c1Sopenharmony_ci{ 659596a2c1Sopenharmony_ci localeMatcher = ParseOption(options, "localeMatcher"); 669596a2c1Sopenharmony_ci localeMatcher = (localeMatcher == "") ? "best fit" : localeMatcher; 679596a2c1Sopenharmony_ci type = ParseOption(options, "type"); 689596a2c1Sopenharmony_ci type = (type == "") ? "cardinal" : type; 699596a2c1Sopenharmony_ci std::string minIntegerStr = ParseOption(options, "minimumIntegerDigits"); 709596a2c1Sopenharmony_ci // 1 is minValue and defaultValue, 21 is maxValue 719596a2c1Sopenharmony_ci minInteger = GetValidInteger(minIntegerStr, 1, 21, 1); 729596a2c1Sopenharmony_ci 739596a2c1Sopenharmony_ci minFraction = 0; 749596a2c1Sopenharmony_ci maxFraction = 0; 759596a2c1Sopenharmony_ci std::string minFractionStr = ParseOption(options, "minimumFractionDigits"); 769596a2c1Sopenharmony_ci std::string maxFractionStr = ParseOption(options, "maximumFractionDigits"); 779596a2c1Sopenharmony_ci std::string minSignificantStr = ParseOption(options, "minimumSignificantDigits"); 789596a2c1Sopenharmony_ci std::string maxSignificantStr = ParseOption(options, "maximumSignificantDigits"); 799596a2c1Sopenharmony_ci if (minSignificantStr != "" || maxSignificantStr != "") { 809596a2c1Sopenharmony_ci // 1 is minValue and defaultValue, 21 is maxValue 819596a2c1Sopenharmony_ci minSignificant = GetValidInteger(minSignificantStr, 1, 21, 1); 829596a2c1Sopenharmony_ci // 1 is minValue, 21 is maxValue and defaultValue 839596a2c1Sopenharmony_ci maxSignificant = GetValidInteger(maxSignificantStr, 1, 21, 21); 849596a2c1Sopenharmony_ci } else { 859596a2c1Sopenharmony_ci minSignificant = 0; 869596a2c1Sopenharmony_ci maxSignificant = 0; 879596a2c1Sopenharmony_ci 889596a2c1Sopenharmony_ci if (minFractionStr != "" || maxFractionStr != "") { 899596a2c1Sopenharmony_ci // 0 is minValue and defaultValue, 20 is maxValue 909596a2c1Sopenharmony_ci minFraction = GetValidInteger(minFractionStr, 0, 20, 0); 919596a2c1Sopenharmony_ci int maxFractionDefault = std::max(3, minFraction); // 3 is the default value of minFraction 929596a2c1Sopenharmony_ci int maxFractionMin = std::max(1, minFraction); // 1 is the min value of minFraction 939596a2c1Sopenharmony_ci // 21 is max value 949596a2c1Sopenharmony_ci maxFraction = GetValidInteger(maxFractionStr, maxFractionMin, 21, maxFractionDefault); 959596a2c1Sopenharmony_ci } else { 969596a2c1Sopenharmony_ci minFraction = 0; // 0 is the default value of minFraction. 979596a2c1Sopenharmony_ci maxFraction = 3; // 3 is the default value of maxFraction 989596a2c1Sopenharmony_ci } 999596a2c1Sopenharmony_ci } 1009596a2c1Sopenharmony_ci} 1019596a2c1Sopenharmony_ci 1029596a2c1Sopenharmony_civoid PluralRules::InitPluralRules(std::vector<std::string> &localeTags, 1039596a2c1Sopenharmony_ci std::map<std::string, std::string> &options) 1049596a2c1Sopenharmony_ci{ 1059596a2c1Sopenharmony_ci UPluralType uPluralType = (type == "cardinal") ? UPLURAL_TYPE_CARDINAL : UPLURAL_TYPE_ORDINAL; 1069596a2c1Sopenharmony_ci UErrorCode status = UErrorCode::U_ZERO_ERROR; 1079596a2c1Sopenharmony_ci localeTags.push_back(LocaleConfig::GetSystemLocale()); 1089596a2c1Sopenharmony_ci for (size_t i = 0; i < localeTags.size(); i++) { 1099596a2c1Sopenharmony_ci std::string curLocale = localeTags[i]; 1109596a2c1Sopenharmony_ci locale = icu::Locale::forLanguageTag(icu::StringPiece(curLocale), status); 1119596a2c1Sopenharmony_ci if (U_FAILURE(status)) { 1129596a2c1Sopenharmony_ci status = U_ZERO_ERROR; 1139596a2c1Sopenharmony_ci continue; 1149596a2c1Sopenharmony_ci } 1159596a2c1Sopenharmony_ci if (LocaleInfo::allValidLocales.count(locale.getLanguage()) > 0) { 1169596a2c1Sopenharmony_ci localeInfo = std::make_unique<LocaleInfo>(curLocale, options); 1179596a2c1Sopenharmony_ci if (!localeInfo->InitSuccess()) { 1189596a2c1Sopenharmony_ci continue; 1199596a2c1Sopenharmony_ci } 1209596a2c1Sopenharmony_ci locale = localeInfo->GetLocale(); 1219596a2c1Sopenharmony_ci localeStr = localeInfo->GetBaseName(); 1229596a2c1Sopenharmony_ci pluralRules = icu::PluralRules::forLocale(locale, uPluralType, status); 1239596a2c1Sopenharmony_ci if (status != UErrorCode::U_ZERO_ERROR || !pluralRules) { 1249596a2c1Sopenharmony_ci continue; 1259596a2c1Sopenharmony_ci } 1269596a2c1Sopenharmony_ci createSuccess = true; 1279596a2c1Sopenharmony_ci break; 1289596a2c1Sopenharmony_ci } 1299596a2c1Sopenharmony_ci } 1309596a2c1Sopenharmony_ci if (status != UErrorCode::U_ZERO_ERROR || !pluralRules) { 1319596a2c1Sopenharmony_ci HILOG_ERROR_I18N("PluralRules object created failed"); 1329596a2c1Sopenharmony_ci return; 1339596a2c1Sopenharmony_ci } 1349596a2c1Sopenharmony_ci} 1359596a2c1Sopenharmony_ci 1369596a2c1Sopenharmony_civoid PluralRules::InitNumberFormatter() 1379596a2c1Sopenharmony_ci{ 1389596a2c1Sopenharmony_ci numberFormatter = icu::number::NumberFormatter::withLocale(locale).roundingMode(UNUM_ROUND_HALFUP); 1399596a2c1Sopenharmony_ci if (minInteger > 1) { 1409596a2c1Sopenharmony_ci numberFormatter = numberFormatter.integerWidth(icu::number::IntegerWidth::zeroFillTo(minInteger)); 1419596a2c1Sopenharmony_ci } 1429596a2c1Sopenharmony_ci 1439596a2c1Sopenharmony_ci if (minSignificant >= 0) { 1449596a2c1Sopenharmony_ci if (minSignificant > 0) { 1459596a2c1Sopenharmony_ci icu::number::Precision precision = icu::number::Precision::minMaxSignificantDigits(minSignificant, 1469596a2c1Sopenharmony_ci maxSignificant); 1479596a2c1Sopenharmony_ci numberFormatter = numberFormatter.precision(precision); 1489596a2c1Sopenharmony_ci } else { 1499596a2c1Sopenharmony_ci icu::number::Precision precision = icu::number::Precision::minMaxFraction(minFraction, maxFraction); 1509596a2c1Sopenharmony_ci numberFormatter = numberFormatter.precision(precision); 1519596a2c1Sopenharmony_ci } 1529596a2c1Sopenharmony_ci } 1539596a2c1Sopenharmony_ci} 1549596a2c1Sopenharmony_ci 1559596a2c1Sopenharmony_ciPluralRules::PluralRules(std::vector<std::string> &localeTags, std::map<std::string, std::string> &options) 1569596a2c1Sopenharmony_ci{ 1579596a2c1Sopenharmony_ci ParseAllOptions(options); 1589596a2c1Sopenharmony_ci InitPluralRules(localeTags, options); 1599596a2c1Sopenharmony_ci InitNumberFormatter(); 1609596a2c1Sopenharmony_ci} 1619596a2c1Sopenharmony_ci 1629596a2c1Sopenharmony_ciPluralRules::~PluralRules() 1639596a2c1Sopenharmony_ci{ 1649596a2c1Sopenharmony_ci if (!pluralRules) { 1659596a2c1Sopenharmony_ci delete pluralRules; 1669596a2c1Sopenharmony_ci pluralRules = nullptr; 1679596a2c1Sopenharmony_ci } 1689596a2c1Sopenharmony_ci} 1699596a2c1Sopenharmony_ci 1709596a2c1Sopenharmony_cistd::string PluralRules::Select(double number) 1719596a2c1Sopenharmony_ci{ 1729596a2c1Sopenharmony_ci if (!createSuccess || pluralRules == nullptr) { 1739596a2c1Sopenharmony_ci return "other"; 1749596a2c1Sopenharmony_ci } 1759596a2c1Sopenharmony_ci UErrorCode status = UErrorCode::U_ZERO_ERROR; 1769596a2c1Sopenharmony_ci icu::number::FormattedNumber formattedNumber = numberFormatter.formatDouble(number, status); 1779596a2c1Sopenharmony_ci if (status != UErrorCode::U_ZERO_ERROR) { 1789596a2c1Sopenharmony_ci status = UErrorCode::U_ZERO_ERROR; 1799596a2c1Sopenharmony_ci formattedNumber = numberFormatter.formatDouble(number, status); 1809596a2c1Sopenharmony_ci } 1819596a2c1Sopenharmony_ci icu::UnicodeString unicodeString = pluralRules->select(formattedNumber, status); 1829596a2c1Sopenharmony_ci std::string result; 1839596a2c1Sopenharmony_ci unicodeString.toUTF8String(result); 1849596a2c1Sopenharmony_ci return result; 1859596a2c1Sopenharmony_ci} 1869596a2c1Sopenharmony_ci} // namespace I18n 1879596a2c1Sopenharmony_ci} // namespace Global 1889596a2c1Sopenharmony_ci} // namespace OHOS