• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2021-2022 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 #include "locale_config.h"
16 
17 #include <cctype>
18 #include <cmath>
19 #include <sstream>
20 #include "i18n_hilog.h"
21 #include "ohos/init_data.h"
22 #include "parameter.h"
23 #include "unicode/ucurr.h"
24 #include "unicode/uenum.h"
25 #include "unicode/utypes.h"
26 #include "unicode/unumberformatter.h"
27 #include "utils.h"
28 #include "number_format.h"
29 
30 namespace OHOS {
31 namespace Global {
32 namespace I18n {
33 const char* NumberFormat::DEVICE_TYPE_NAME = "const.product.devicetype";
34 std::mutex NumberFormat::numToCurrencyMutex;
35 bool NumberFormat::initISO4217 = false;
36 std::unordered_map<std::string, std::string> NumberFormat::numToCurrency = {};
37 bool NumberFormat::icuInitialized = NumberFormat::Init();
38 
39 std::unordered_map<std::string, UNumberUnitWidth> NumberFormat::unitStyle = {
40     { "long", UNumberUnitWidth::UNUM_UNIT_WIDTH_FULL_NAME },
41     { "short", UNumberUnitWidth::UNUM_UNIT_WIDTH_SHORT },
42     { "narrow", UNumberUnitWidth::UNUM_UNIT_WIDTH_NARROW }
43 };
44 
45 std::unordered_map<std::string, UNumberUnitWidth> NumberFormat::currencyStyle = {
46     { "symbol", UNumberUnitWidth::UNUM_UNIT_WIDTH_SHORT },
47     { "code", UNumberUnitWidth::UNUM_UNIT_WIDTH_ISO_CODE },
48     { "name", UNumberUnitWidth::UNUM_UNIT_WIDTH_FULL_NAME },
49     { "narrowSymbol", UNumberUnitWidth::UNUM_UNIT_WIDTH_NARROW }
50 };
51 
52 std::unordered_map<std::string, UNumberSignDisplay> NumberFormat::signAutoStyle = {
53     { "auto", UNumberSignDisplay::UNUM_SIGN_AUTO },
54     { "never", UNumberSignDisplay::UNUM_SIGN_NEVER },
55     { "always", UNumberSignDisplay::UNUM_SIGN_ALWAYS },
56     { "exceptZero", UNumberSignDisplay::UNUM_SIGN_EXCEPT_ZERO }
57 };
58 
59 std::unordered_map<std::string, UNumberSignDisplay> NumberFormat::signAccountingStyle = {
60     { "auto", UNumberSignDisplay::UNUM_SIGN_ACCOUNTING },
61     { "never", UNumberSignDisplay::UNUM_SIGN_NEVER },
62     { "always", UNumberSignDisplay::UNUM_SIGN_ACCOUNTING_ALWAYS },
63     { "exceptZero", UNumberSignDisplay::UNUM_SIGN_ACCOUNTING_EXCEPT_ZERO }
64 };
65 
66 std::unordered_map<UMeasurementSystem, std::string> NumberFormat::measurementSystem = {
67     { UMeasurementSystem::UMS_SI, "SI" },
68     { UMeasurementSystem::UMS_US, "US" },
69     { UMeasurementSystem::UMS_UK, "UK" },
70 };
71 
72 std::unordered_map<std::string, UNumberUnitWidth> NumberFormat::defaultUnitStyle = {
73     { "tablet", UNumberUnitWidth::UNUM_UNIT_WIDTH_FULL_NAME },
74     { "2in1", UNumberUnitWidth::UNUM_UNIT_WIDTH_FULL_NAME },
75     { "tv", UNumberUnitWidth::UNUM_UNIT_WIDTH_FULL_NAME },
76     { "pc", UNumberUnitWidth::UNUM_UNIT_WIDTH_FULL_NAME },
77     { "wearable", UNumberUnitWidth::UNUM_UNIT_WIDTH_NARROW },
78     { "liteWearable", UNumberUnitWidth::UNUM_UNIT_WIDTH_NARROW },
79     { "watch", UNumberUnitWidth::UNUM_UNIT_WIDTH_NARROW }
80 };
81 
82 std::unordered_map<std::string, UNumberUnitWidth> NumberFormat::defaultCurrencyStyle = {
83     { "wearable", UNumberUnitWidth::UNUM_UNIT_WIDTH_NARROW },
84     { "liteWearable", UNumberUnitWidth::UNUM_UNIT_WIDTH_NARROW },
85     { "watch", UNumberUnitWidth::UNUM_UNIT_WIDTH_NARROW }
86 };
87 
88 std::unordered_map<std::string, UNumberRoundingPriority> NumberFormat::roundingPriorityStyle = {
89     { "auto", UNumberRoundingPriority::UNUM_ROUNDING_PRIORITY_STRICT },
90     { "morePrecision", UNumberRoundingPriority::UNUM_ROUNDING_PRIORITY_RELAXED },
91     { "lessPrecision", UNumberRoundingPriority::UNUM_ROUNDING_PRIORITY_STRICT }
92 };
93 
94 std::unordered_map<std::string, UNumberFormatRoundingMode> NumberFormat::roundingModeStyle = {
95     { "ceil", UNumberFormatRoundingMode::UNUM_ROUND_CEILING },
96     { "floor", UNumberFormatRoundingMode::UNUM_ROUND_FLOOR },
97     { "expand", UNumberFormatRoundingMode::UNUM_ROUND_UP },
98     { "trunc", UNumberFormatRoundingMode::UNUM_ROUND_DOWN },
99     { "halfCeil", UNumberFormatRoundingMode::UNUM_ROUND_HALF_CEILING },
100     { "halfFloor", UNumberFormatRoundingMode::UNUM_ROUND_HALF_FLOOR },
101     { "halfExpand", UNumberFormatRoundingMode::UNUM_ROUND_HALFUP },
102     { "halfTrunc", UNumberFormatRoundingMode::UNUM_ROUND_HALFDOWN },
103     { "halfEven", UNumberFormatRoundingMode::UNUM_ROUND_HALFEVEN },
104 };
105 
106 std::vector<size_t> NumberFormat::roundingIncrementList = {
107     1, 2, 5, 10, 20, 25, 50, 100, 200, 250, 500, 1000, 2000, 2500, 5000
108 };
109 
110 std::map<std::string, std::string> NumberFormat::RelativeTimeFormatConfigs = {
111     { "numeric", "auto" }
112 };
113 
NumberFormat(const std::vector<std::string> & localeTags,std::map<std::string,std::string> & configs)114 NumberFormat::NumberFormat(const std::vector<std::string> &localeTags, std::map<std::string, std::string> &configs)
115 {
116     SetDefaultStyle();
117     UErrorCode status = U_ZERO_ERROR;
118     std::unique_ptr<icu::LocaleBuilder> builder = nullptr;
119     builder = std::make_unique<icu::LocaleBuilder>();
120     ParseConfigs(configs);
121     for (size_t i = 0; i < localeTags.size(); i++) {
122         std::string curLocale = localeTags[i];
123         locale = icu::Locale::forLanguageTag(icu::StringPiece(curLocale), status);
124         if (U_FAILURE(status)) {
125             status = U_ZERO_ERROR;
126             continue;
127         }
128         if (LocaleInfo::allValidLocales.count(locale.getLanguage()) > 0) {
129             localeInfo = std::make_unique<LocaleInfo>(curLocale, configs);
130             CreateRelativeTimeFormat(curLocale);
131             if (!localeInfo->InitSuccess()) {
132                 continue;
133             }
134             locale = localeInfo->GetLocale();
135             localeBaseName = localeInfo->GetBaseName();
136             icu::MeasureUnit::getAvailable(unitArray, MAX_UNIT_NUM, status);
137             if (!U_SUCCESS(status)) {
138                 status = U_ZERO_ERROR;
139                 continue;
140             }
141             createSuccess = true;
142             break;
143         }
144     }
145     if (!createSuccess) {
146         std::string systemLocale = LocaleConfig::GetSystemLocale();
147         localeInfo = std::make_unique<LocaleInfo>(systemLocale, configs);
148         CreateRelativeTimeFormat(systemLocale);
149         if (localeInfo->InitSuccess()) {
150             locale = localeInfo->GetLocale();
151             localeBaseName = localeInfo->GetBaseName();
152             icu::MeasureUnit::getAvailable(unitArray, MAX_UNIT_NUM, status);
153             if (U_SUCCESS(status)) {
154                 createSuccess = true;
155             }
156         }
157     }
158     if (createSuccess) {
159         InitNumberFormat();
160     }
161 }
162 
~NumberFormat()163 NumberFormat::~NumberFormat()
164 {
165 }
166 
InitNumberFormat()167 void NumberFormat::InitNumberFormat()
168 {
169     icu::number::UnlocalizedNumberFormatter formatter = icu::number::NumberFormatter::with();
170     InitProperties(formatter);
171     numberFormat = formatter.locale(locale);
172     numberRangeFormat = icu::number::NumberRangeFormatter::with()
173         .numberFormatterBoth(formatter)
174         .locale(locale);
175 }
176 
CreateRelativeTimeFormat(const std::string & locale)177 void NumberFormat::CreateRelativeTimeFormat(const std::string& locale)
178 {
179     if (unitUsage == "elapsed-time-second") {
180         std::vector<std::string> locales = { locale };
181         relativeTimeFormat = std::make_unique<RelativeTimeFormat>(locales,
182             RelativeTimeFormatConfigs);
183     }
184 }
185 
InitProperties(icu::number::UnlocalizedNumberFormatter & formatter)186 void NumberFormat::InitProperties(icu::number::UnlocalizedNumberFormatter &formatter)
187 {
188     InitCurrencyProperties(formatter);
189     InitPercentStyleProperties(formatter);
190     InitUnitProperties(formatter);
191     InitUseGroupingProperties(formatter);
192     InitSignProperties(formatter);
193     InitNotationProperties(formatter);
194     InitDigitsProperties(formatter);
195 }
196 
InitCurrencyProperties(icu::number::UnlocalizedNumberFormatter & formatter)197 void NumberFormat::InitCurrencyProperties(icu::number::UnlocalizedNumberFormatter &formatter)
198 {
199     if (!currency.empty()) {
200         UErrorCode status = U_ZERO_ERROR;
201         icu::CurrencyUnit currencyUnit(icu::UnicodeString(currency.c_str()).getBuffer(), status);
202         formatter = formatter.unit(currencyUnit);
203         if (currencyDisplay != UNumberUnitWidth::UNUM_UNIT_WIDTH_SHORT) {
204             formatter = formatter.unitWidth(currencyDisplay);
205         }
206     }
207 }
208 
InitPercentStyleProperties(icu::number::UnlocalizedNumberFormatter & formatter)209 void NumberFormat::InitPercentStyleProperties(icu::number::UnlocalizedNumberFormatter &formatter)
210 {
211     if (!styleString.empty() && styleString == "percent") {
212         formatter = formatter.unit(icu::NoUnit::percent())
213             .scale(icu::number::Scale::powerOfTen(2)) // 2 is the power of ten
214             .precision(icu::number::Precision::fixedFraction(0));
215     }
216 }
217 
InitUseGroupingProperties(icu::number::UnlocalizedNumberFormatter & formatter)218 void NumberFormat::InitUseGroupingProperties(icu::number::UnlocalizedNumberFormatter &formatter)
219 {
220     if (!useGrouping.empty()) {
221         UNumberGroupingStrategy groupingStrategy = (useGrouping == "true") ?
222             UNumberGroupingStrategy::UNUM_GROUPING_AUTO : UNumberGroupingStrategy::UNUM_GROUPING_OFF;
223         formatter = formatter.grouping(groupingStrategy);
224     }
225 }
226 
InitNotationProperties(icu::number::UnlocalizedNumberFormatter & formatter)227 void NumberFormat::InitNotationProperties(icu::number::UnlocalizedNumberFormatter &formatter)
228 {
229     if (!notationString.empty()) {
230         formatter = formatter.notation(notation);
231     }
232 }
233 
InitSignProperties(icu::number::UnlocalizedNumberFormatter & formatter)234 void NumberFormat::InitSignProperties(icu::number::UnlocalizedNumberFormatter &formatter)
235 {
236     if (!currencySign.empty() || !signDisplayString.empty()) {
237         formatter = formatter.sign(signDisplay);
238     }
239 }
240 
InitUnitProperties(icu::number::UnlocalizedNumberFormatter & formatter)241 void NumberFormat::InitUnitProperties(icu::number::UnlocalizedNumberFormatter &formatter)
242 {
243     if (styleString.empty() || styleString.compare("unit") != 0) {
244         return;
245     }
246     for (icu::MeasureUnit curUnit : unitArray) {
247         if (!strcmp(curUnit.getSubtype(), unit.c_str())) {
248             formatter = formatter.unit(curUnit);
249             unitType = curUnit.getType();
250         }
251     }
252     UErrorCode status = U_ZERO_ERROR;
253     UMeasurementSystem measSys = ulocdata_getMeasurementSystem(localeBaseName.c_str(), &status);
254     bool isValidMeaSys = measurementSystem.find(measSys) != measurementSystem.end();
255     if (U_SUCCESS(status) && measSys >= 0 && isValidMeaSys) {
256         unitMeasSys = measurementSystem[measSys];
257     }
258     formatter = formatter.unitWidth(unitDisplay);
259     formatter = formatter.precision(icu::number::Precision::maxFraction(DEFAULT_FRACTION_DIGITS));
260 }
261 
InitDigitsProperties(icu::number::UnlocalizedNumberFormatter & formatter)262 void NumberFormat::InitDigitsProperties(icu::number::UnlocalizedNumberFormatter &formatter)
263 {
264     int32_t status = 0;
265     if (!maximumSignificantDigits.empty() || !minimumSignificantDigits.empty()) {
266         int32_t maxSignificantDigits = ConvertString2Int(maximumSignificantDigits, status);
267         if (status == 0) {
268             formatter = formatter.precision(icu::number::Precision::maxSignificantDigits(maxSignificantDigits));
269         }
270 
271         status = 0;
272         int32_t minSignificantDigits = ConvertString2Int(minimumSignificantDigits, status);
273         if (status == 0) {
274             formatter = formatter.precision(icu::number::Precision::minSignificantDigits(minSignificantDigits));
275         }
276     } else {
277         int32_t minIntegerDigits = ConvertString2Int(minimumIntegerDigits, status);
278         if (status == 0 && minIntegerDigits > 1) {
279             formatter = formatter.integerWidth(icu::number::IntegerWidth::zeroFillTo(minIntegerDigits));
280         }
281 
282         int32_t minFdStatus = 0;
283         int32_t minFractionDigits = ConvertString2Int(minimumFractionDigits, minFdStatus);
284         int32_t maxFdStatus = 0;
285         int32_t maxFractionDigits = ConvertString2Int(maximumFractionDigits, maxFdStatus);
286         if (minFdStatus == 0 || maxFdStatus == 0) {
287             isSetFraction = true;
288         }
289         if (minFdStatus == 0 && maxFdStatus != 0) {
290             formatter = formatter.precision(icu::number::Precision::minFraction(minFractionDigits));
291         } else if (minFdStatus != 0 && maxFdStatus == 0) {
292             formatter = formatter.precision(icu::number::Precision::maxFraction(maxFractionDigits));
293         } else if (minFdStatus == 0 && maxFdStatus == 0) {
294             formatter =
295                 formatter.precision(icu::number::Precision::minMaxFraction(minFractionDigits, maxFractionDigits));
296         }
297     }
298     SetRoundingProperties(formatter);
299     HandleRoundingPriority(formatter);
300 }
301 
SetRoundingProperties(icu::number::UnlocalizedNumberFormatter & formatter)302 void NumberFormat::SetRoundingProperties(icu::number::UnlocalizedNumberFormatter &formatter)
303 {
304     if (roundingIncrement != 1) {
305         int32_t maxFractionDigits = GetMaximumFractionDigitsValue();
306         double increment = pow(POW_BASE_NUMBER, -1.0 * maxFractionDigits) * roundingIncrement;
307         formatter = formatter.precision(icu::number::Precision::increment(increment));
308     }
309     if (!roundingModeStr.empty()) {
310         formatter = formatter.roundingMode(roundingMode);
311     }
312 }
313 
HandleRoundingPriority(icu::number::UnlocalizedNumberFormatter & formatter)314 void NumberFormat::HandleRoundingPriority(icu::number::UnlocalizedNumberFormatter &formatter)
315 {
316     if (roundingPriorityStr.empty()) {
317         return;
318     }
319     int32_t minFractionDigits = GetMinimumFractionDigitsValue();
320     int32_t maxFractionDigits = GetMaximumFractionDigitsValue();
321     int32_t maxSigDigits = GetMaximumSignificantDigitsIntValue();
322     int32_t minSigDigits = GetMinimumSignificantDigitsIntValue();
323     auto precision = icu::number::Precision::minMaxFraction(minFractionDigits, maxFractionDigits)
324         .withSignificantDigits(minSigDigits, maxSigDigits, roundingPriority);
325     formatter = formatter.precision(precision);
326 }
327 
GetMinimumSignificantDigitsIntValue()328 int32_t NumberFormat::GetMinimumSignificantDigitsIntValue()
329 {
330     int32_t minSignifDigits = 1;
331     if (!minimumSignificantDigits.empty()) {
332         int32_t status = 0;
333         int32_t minSignDigits = ConvertString2Int(minimumSignificantDigits, status);
334         minSignifDigits = (status == 0) ? minSignDigits : minSignifDigits;
335     }
336     return minSignifDigits;
337 }
338 
GetMaximumSignificantDigitsIntValue()339 int32_t NumberFormat::GetMaximumSignificantDigitsIntValue()
340 {
341     int32_t maxSign = DEFAULT_MAX_SIGNIFICANT_DIGITS;
342     if (!maximumSignificantDigits.empty()) {
343         int32_t status = 0;
344         int32_t maxSignDigits = ConvertString2Int(maximumSignificantDigits, status);
345         maxSign = (status == 0) ? maxSignDigits : maxSign;
346     }
347     return maxSign;
348 }
349 
GetMaximumFractionDigitsValue()350 int32_t NumberFormat::GetMaximumFractionDigitsValue()
351 {
352     int32_t maxFraction = DEFAULT_FRACTION_DIGITS;
353     if (!maximumFractionDigits.empty()) {
354         int32_t status = 0;
355         int32_t maxFractionDigits = ConvertString2Int(maximumFractionDigits, status);
356         maxFraction = (status == 0) ? maxFractionDigits : maxFraction;
357     }
358     return maxFraction;
359 }
360 
GetMinimumFractionDigitsValue()361 int32_t NumberFormat::GetMinimumFractionDigitsValue()
362 {
363     int32_t minFraction = 0;
364     if (!minimumFractionDigits.empty()) {
365         int32_t status = 0;
366         int32_t minFractionDigits = ConvertString2Int(minimumFractionDigits, status);
367         minFraction = (status == 0) ? minFractionDigits : minFraction;
368     }
369     return minFraction;
370 }
371 
ParseConfigs(std::map<std::string,std::string> & configs)372 void NumberFormat::ParseConfigs(std::map<std::string, std::string> &configs)
373 {
374     if (configs.count("signDisplay") > 0) {
375         signDisplayString = configs["signDisplay"];
376     }
377     if (signAutoStyle.count(signDisplayString) > 0) {
378         signDisplay = signAutoStyle[signDisplayString];
379     }
380     if (configs.count("style") > 0) {
381         styleString = configs["style"];
382     }
383     if (styleString == "unit" && configs.count("unit") > 0) {
384         unit = configs["unit"];
385         if (configs.count("unitDisplay") > 0) {
386             unitDisplayString = configs["unitDisplay"];
387             if (unitStyle.count(unitDisplayString) > 0) {
388                 unitDisplay = unitStyle[unitDisplayString];
389             }
390         }
391         if (configs.count("unitUsage") > 0) {
392             unitUsage = configs["unitUsage"];
393         }
394     }
395     if (styleString == "currency" && configs.count("currency") > 0) {
396         currency = GetCurrencyFromConfig(configs["currency"]);
397         if (configs.count("currencySign") > 0) {
398             currencySign = configs["currencySign"];
399         }
400         if (currencySign.compare("accounting") == 0 && signAccountingStyle.count(signDisplayString) > 0) {
401             signDisplay = signAccountingStyle[signDisplayString];
402         }
403         if (configs.count("currencyDisplay") > 0 && currencyStyle.count(configs["currencyDisplay"]) > 0) {
404             currencyDisplayString = configs["currencyDisplay"];
405             currencyDisplay = currencyStyle[currencyDisplayString];
406         }
407     }
408     ParseDigitsConfigs(configs);
409     ParseRoundingConfigs(configs);
410 }
411 
ParseDigitsConfigs(std::map<std::string,std::string> & configs)412 void NumberFormat::ParseDigitsConfigs(std::map<std::string, std::string> &configs)
413 {
414     if (configs.count("notation") > 0) {
415         notationString = configs["notation"];
416         if (notationString == "scientific") {
417             notation = icu::number::Notation::scientific();
418         } else if (notationString == "engineering") {
419             notation = icu::number::Notation::engineering();
420         }
421         if (notationString == "compact") {
422             if (configs.count("compactDisplay") > 0) {
423                 compactDisplay = configs["compactDisplay"];
424             }
425             if (compactDisplay == "long") {
426                 notation = icu::number::Notation::compactLong();
427             } else {
428                 notation = icu::number::Notation::compactShort();
429             }
430         }
431     }
432     if (configs.count("minimumIntegerDigits") > 0) {
433         minimumIntegerDigits = configs["minimumIntegerDigits"];
434     }
435     if (configs.count("minimumFractionDigits") > 0) {
436         minimumFractionDigits = configs["minimumFractionDigits"];
437     }
438     if (configs.count("maximumFractionDigits") > 0) {
439         maximumFractionDigits = configs["maximumFractionDigits"];
440     }
441     if (configs.count("minimumSignificantDigits") > 0) {
442         minimumSignificantDigits = configs["minimumSignificantDigits"];
443     }
444     if (configs.count("maximumSignificantDigits") > 0) {
445         maximumSignificantDigits = configs["maximumSignificantDigits"];
446     }
447     if (configs.count("numberingSystem") > 0) {
448         numberingSystem = configs["numberingSystem"];
449     }
450     if (configs.count("useGrouping") > 0) {
451         useGrouping = configs["useGrouping"];
452     }
453     if (configs.count("localeMatcher") > 0) {
454         localeMatcher = configs["localeMatcher"];
455     }
456 }
457 
ParseRoundingConfigs(std::map<std::string,std::string> & configs)458 void NumberFormat::ParseRoundingConfigs(std::map<std::string, std::string> &configs)
459 {
460     if (configs.count("roundingMode") > 0) {
461         std::string tempRoundingModeStr = configs["roundingMode"];
462         auto iter = roundingModeStyle.find(tempRoundingModeStr);
463         if (iter != roundingModeStyle.end()) {
464             roundingMode = iter->second;
465             roundingModeStr = tempRoundingModeStr;
466         }
467     }
468     if (configs.count("roundingPriority") > 0) {
469         std::string tempRoundingPriorityStr = configs["roundingPriority"];
470         auto iter = roundingPriorityStyle.find(tempRoundingPriorityStr);
471         if (iter != roundingPriorityStyle.end()) {
472             roundingPriorityStr = tempRoundingPriorityStr;
473             roundingPriority = iter->second;
474         }
475     }
476     if (configs.count("roundingIncrement") > 0) {
477         std::string increment = configs["roundingIncrement"];
478         int32_t status = 0;
479         int32_t incrementNum = ConvertString2Int(increment, status);
480         auto iter = std::find(roundingIncrementList.begin(), roundingIncrementList.end(),
481             static_cast<size_t>(incrementNum));
482         if (status == 0 && iter != roundingIncrementList.end()) {
483             roundingIncrement = *iter;
484         }
485     }
486 }
487 
SetUnit(std::string & preferredUnit)488 void NumberFormat::SetUnit(std::string &preferredUnit)
489 {
490     if (preferredUnit.empty()) {
491         return;
492     }
493     for (icu::MeasureUnit curUnit : unitArray) {
494         if (!strcmp(curUnit.getSubtype(), preferredUnit.c_str())) {
495             numberFormat = numberFormat.unit(curUnit);
496         }
497     }
498 }
499 
Format(double number)500 std::string NumberFormat::Format(double number)
501 {
502     std::string result;
503     UErrorCode status = U_ZERO_ERROR;
504     icu::UnicodeString formatResult;
505     if (IsRelativeTimeFormat(number)) {
506         icu::FormattedRelativeDateTime formattedTime = FormatToFormattedRelativeDateTime(number);
507         formatResult = formattedTime.toString(status);
508     } else {
509         icu::number::FormattedNumber formattedNumber = FormatToFormattedNumber(number);
510         formatResult = formattedNumber.toString(status);
511     }
512     if (U_FAILURE(status)) {
513         result = "";
514     } else {
515         formatResult.toUTF8String(result);
516     }
517     return PseudoLocalizationProcessor(result);
518 }
519 
IsRelativeTimeFormat(double number)520 bool NumberFormat::IsRelativeTimeFormat(double number)
521 {
522     double finalNumber = number;
523     std::string finalUnit = unit;
524     if (unitUsage.compare("elapsed-time-second") == 0 && ConvertDate(finalNumber, finalUnit) &&
525         relativeTimeFormat != nullptr) {
526         return true;
527     }
528     return false;
529 }
530 
FormatToFormattedNumber(double number)531 icu::number::FormattedNumber NumberFormat::FormatToFormattedNumber(double number)
532 {
533     if (!createSuccess) {
534         return {};
535     }
536     double finalNumber = number;
537     std::string finalUnit = unit;
538     if ((unitUsage.compare("size-file-byte") == 0 || unitUsage.compare("size-shortfile-byte") == 0) &&
539         ConvertByte(finalNumber, finalUnit)) {
540         SetUnit(finalUnit);
541         SetPrecisionWithByte(finalNumber, finalUnit);
542     } else if (!unitUsage.empty()) {
543         std::vector<std::string> preferredUnits;
544         if (unitUsage.compare("default") == 0) {
545             GetDefaultPreferredUnit(localeInfo->GetRegion(), unitType, preferredUnits);
546         } else {
547             GetPreferredUnit(localeInfo->GetRegion(), unitUsage, preferredUnits);
548         }
549         std::map<double, std::string> preferredValuesOverOne;
550         std::map<double, std::string> preferredValuesUnderOne;
551         double num = number;
552         for (size_t i = 0; i < preferredUnits.size(); i++) {
553             int status = Convert(num, unit, unitMeasSys, preferredUnits[i], unitMeasSys);
554             if (!status) {
555                 continue;
556             }
557             if (num >= 1) {
558                 preferredValuesOverOne.insert(std::make_pair(num, preferredUnits[i]));
559             } else {
560                 preferredValuesUnderOne.insert(std::make_pair(num, preferredUnits[i]));
561             }
562         }
563         std::string preferredUnit;
564         if (preferredValuesOverOne.size() > 0) {
565             finalNumber = preferredValuesOverOne.begin()->first;
566             preferredUnit = preferredValuesOverOne.begin()->second;
567         } else if (preferredValuesUnderOne.size() > 0) {
568             finalNumber = preferredValuesUnderOne.rbegin()->first;
569             preferredUnit = preferredValuesUnderOne.rbegin()->second;
570         }
571         SetUnit(preferredUnit);
572     }
573     UErrorCode icuStatus = U_ZERO_ERROR;
574     icu::number::FormattedNumber formattedNumber = numberFormat.formatDouble(finalNumber, icuStatus);
575     if (U_FAILURE(icuStatus)) {
576         return {};
577     }
578     return formattedNumber;
579 }
580 
FormatToFormattedRelativeDateTime(double number)581 icu::FormattedRelativeDateTime NumberFormat::FormatToFormattedRelativeDateTime(double number)
582 {
583     if (!createSuccess) {
584         return {};
585     }
586 
587     double finalNumber = number;
588     std::string finalUnit = unit;
589     if (unitUsage.compare("elapsed-time-second") == 0 && ConvertDate(finalNumber, finalUnit) &&
590         relativeTimeFormat != nullptr) {
591         return relativeTimeFormat->FormatToFormattedValue(finalNumber, finalUnit);
592     }
593     return {};
594 }
595 
FormatRange(double start,double end)596 std::string NumberFormat::FormatRange(double start, double end)
597 {
598     if (!createSuccess) {
599         HILOG_ERROR_I18N("FormatRange: init numberRangeFormat failed.");
600         return PseudoLocalizationProcessor("");
601     }
602     if (end < start) {
603         HILOG_ERROR_I18N("FormatRange: parameter:end less then parameter:start");
604         return PseudoLocalizationProcessor("");
605     }
606     UErrorCode status = U_ZERO_ERROR;
607     icu::number::FormattedNumberRange numberRange =
608         numberRangeFormat.formatFormattableRange(start, end, status);
609     if (U_FAILURE(status)) {
610         HILOG_ERROR_I18N("FormatRange: formatFormattableRange failed.");
611         return PseudoLocalizationProcessor("");
612     }
613     icu::UnicodeString res = numberRange.toString(status);
614     if (U_FAILURE(status)) {
615         HILOG_ERROR_I18N("FormatRange: icu::UnicodeString.toString() failed.");
616         return PseudoLocalizationProcessor("");
617     }
618     std::string result;
619     res.toUTF8String(result);
620     return PseudoLocalizationProcessor(result);
621 }
622 
GetResolvedOptions(std::map<std::string,std::string> & map)623 void NumberFormat::GetResolvedOptions(std::map<std::string, std::string> &map)
624 {
625     map.insert(std::make_pair("locale", localeBaseName));
626     if (!styleString.empty()) {
627         map.insert(std::make_pair("style", styleString));
628     }
629     if (!currency.empty()) {
630         map.insert(std::make_pair("currency", currency));
631     }
632     if (!currencySign.empty()) {
633         map.insert(std::make_pair("currencySign", currencySign));
634     }
635     if (!currencyDisplayString.empty()) {
636         map.insert(std::make_pair("currencyDisplay", currencyDisplayString));
637     }
638     if (!signDisplayString.empty()) {
639         map.insert(std::make_pair("signDisplay", signDisplayString));
640     }
641     if (!compactDisplay.empty()) {
642         map.insert(std::make_pair("compactDisplay", compactDisplay));
643     }
644     if (!unitDisplayString.empty()) {
645         map.insert(std::make_pair("unitDisplay", unitDisplayString));
646     }
647     if (!unitUsage.empty()) {
648         map.insert(std::make_pair("unitUsage", unitUsage));
649     }
650     if (!unit.empty()) {
651         map.insert(std::make_pair("unit", unit));
652     }
653     GetDigitsResolvedOptions(map);
654 }
655 
GetDigitsResolvedOptions(std::map<std::string,std::string> & map)656 void NumberFormat::GetDigitsResolvedOptions(std::map<std::string, std::string> &map)
657 {
658     if (!numberingSystem.empty()) {
659         map.insert(std::make_pair("numberingSystem", numberingSystem));
660     } else if (!(localeInfo->GetNumberingSystem()).empty()) {
661         map.insert(std::make_pair("numberingSystem", localeInfo->GetNumberingSystem()));
662     } else {
663         UErrorCode status = U_ZERO_ERROR;
664         auto numSys = std::unique_ptr<icu::NumberingSystem>(icu::NumberingSystem::createInstance(locale, status));
665         if (U_SUCCESS(status)) {
666             map.insert(std::make_pair("numberingSystem", numSys->getName()));
667         }
668     }
669     if (!useGrouping.empty()) {
670         map.insert(std::make_pair("useGrouping", useGrouping));
671     }
672     if (!minimumIntegerDigits.empty()) {
673         map.insert(std::make_pair("minimumIntegerDigits", minimumIntegerDigits));
674     }
675     if (!minimumFractionDigits.empty()) {
676         map.insert(std::make_pair("minimumFractionDigits", minimumFractionDigits));
677     }
678     if (!maximumFractionDigits.empty()) {
679         map.insert(std::make_pair("maximumFractionDigits", maximumFractionDigits));
680     }
681     if (!minimumSignificantDigits.empty()) {
682         map.insert(std::make_pair("minimumSignificantDigits", minimumSignificantDigits));
683     }
684     if (!maximumSignificantDigits.empty()) {
685         map.insert(std::make_pair("maximumSignificantDigits", maximumSignificantDigits));
686     }
687     if (!localeMatcher.empty()) {
688         map.insert(std::make_pair("localeMatcher", localeMatcher));
689     }
690     if (!notationString.empty()) {
691         map.insert(std::make_pair("notation", notationString));
692     }
693     if (!roundingModeStr.empty()) {
694         map.insert(std::make_pair("roundingMode", roundingModeStr));
695     }
696     if (!roundingPriorityStr.empty()) {
697         map.insert(std::make_pair("roundingPriority", roundingPriorityStr));
698     }
699     if (roundingIncrement != 1) {
700         map.insert(std::make_pair("roundingIncrement", std::to_string(roundingIncrement)));
701     }
702 }
703 
SetPrecisionWithByte(double number,const std::string & finalUnit)704 void NumberFormat::SetPrecisionWithByte(double number, const std::string& finalUnit)
705 {
706     if (isSetFraction) {
707         return;
708     }
709     int32_t FractionDigits = -1;
710     // 100 is the threshold between different decimal
711     if (finalUnit == "byte" || number >= 100) {
712         FractionDigits = 0;
713     } else if (number < 1) {
714         // 2 is the number of significant digits in the decimal
715         FractionDigits = 2;
716     // 10 is the threshold between different decimal
717     } else if (number < 10) {
718         if (unitUsage == "size-shortfile-byte") {
719             FractionDigits = 1;
720         } else {
721             // 2 is the number of significant digits in the decimal
722             FractionDigits = 2;
723         }
724     } else {
725         if (unitUsage == "size-shortfile-byte") {
726             FractionDigits = 0;
727         } else {
728             // 2 is the number of significant digits in the decimal
729             FractionDigits = 2;
730         }
731     }
732     if (FractionDigits != -1) {
733         numberFormat = numberFormat.precision(icu::number::Precision::minMaxFraction(FractionDigits, FractionDigits));
734     }
735 }
736 
GetCurrency() const737 std::string NumberFormat::GetCurrency() const
738 {
739     return currency;
740 }
741 
GetCurrencySign() const742 std::string NumberFormat::GetCurrencySign() const
743 {
744     return currencySign;
745 }
746 
GetStyle() const747 std::string NumberFormat::GetStyle() const
748 {
749     return styleString;
750 }
751 
GetNumberingSystem() const752 std::string NumberFormat::GetNumberingSystem() const
753 {
754     return numberingSystem;
755 }
756 
GetUseGrouping() const757 std::string NumberFormat::GetUseGrouping() const
758 {
759     return useGrouping;
760 }
761 
GetMinimumIntegerDigits() const762 std::string NumberFormat::GetMinimumIntegerDigits() const
763 {
764     return minimumIntegerDigits;
765 }
766 
GetMinimumFractionDigits() const767 std::string NumberFormat::GetMinimumFractionDigits() const
768 {
769     return minimumFractionDigits;
770 }
771 
GetMaximumFractionDigits() const772 std::string NumberFormat::GetMaximumFractionDigits() const
773 {
774     return maximumFractionDigits;
775 }
776 
GetMinimumSignificantDigits() const777 std::string NumberFormat::GetMinimumSignificantDigits() const
778 {
779     return minimumSignificantDigits;
780 }
781 
GetMaximumSignificantDigits() const782 std::string NumberFormat::GetMaximumSignificantDigits() const
783 {
784     return maximumSignificantDigits;
785 }
786 
GetLocaleMatcher() const787 std::string NumberFormat::GetLocaleMatcher() const
788 {
789     return localeMatcher;
790 }
791 
Init()792 bool NumberFormat::Init()
793 {
794     SetHwIcuDirectory();
795     return true;
796 }
797 
SetDefaultStyle()798 void NumberFormat::SetDefaultStyle()
799 {
800     char value[BUFFER_LEN];
801     int code = GetParameter(DEVICE_TYPE_NAME, "", value, BUFFER_LEN);
802     if (code > 0) {
803         std::string deviceType = value;
804         if (defaultUnitStyle.find(deviceType) != defaultUnitStyle.end()) {
805             unitDisplay = defaultUnitStyle[deviceType];
806         }
807         if (defaultCurrencyStyle.find(deviceType) != defaultCurrencyStyle.end()) {
808             currencyDisplay = defaultCurrencyStyle[deviceType];
809         }
810     }
811 }
812 
ReadISO4217Datas()813 bool NumberFormat::ReadISO4217Datas()
814 {
815     if (initISO4217) {
816         return true;
817     }
818     std::lock_guard<std::mutex> readDataLock(numToCurrencyMutex);
819     if (initISO4217) {
820         return true;
821     }
822     UErrorCode status = U_ZERO_ERROR;
823     const char *currentCurrency;
824     UEnumeration *currencies = ucurr_openISOCurrencies(UCURR_ALL, &status);
825     if (U_FAILURE(status)) {
826         return false;
827     }
828 
829     UChar code[CURRENCY_LEN + 1];  // +1 includes the NUL
830     int32_t length = 0;
831     while ((currentCurrency = uenum_next(currencies, &length, &status)) != NULL) {
832         u_charsToUChars(currentCurrency, code, length + 1);  // +1 includes the NUL
833         int32_t numCode = ucurr_getNumericCode(code);
834         if (numCode == 0) {
835             continue;
836         }
837         std::stringstream ss;
838         ss << std::setw(CURRENCY_LEN) << std::setfill('0') << numCode; // fill with '0'
839         numToCurrency.insert(std::make_pair<std::string, std::string>(ss.str(), currentCurrency));
840     }
841     uenum_close(currencies);
842     initISO4217 = true;
843     return !numToCurrency.empty();
844 }
845 
GetCurrencyFromConfig(const std::string & currency)846 std::string NumberFormat::GetCurrencyFromConfig(const std::string& currency)
847 {
848     if (currency.size() != CURRENCY_LEN) {
849         HILOG_ERROR_I18N("Invalid currency code : %{public}s", currency.c_str());
850         return "";
851     }
852     bool isAlpha = true;
853     for (auto c : currency) {
854         isAlpha = std::isalpha(c);
855         if (!isAlpha) {
856             break;
857         }
858     }
859     if (isAlpha) {
860         return currency;
861     }
862     if (ReadISO4217Datas() && numToCurrency.find(currency) != numToCurrency.end()) {
863         return numToCurrency[currency];
864     }
865     HILOG_ERROR_I18N("Invalid currency code : %{public}s", currency.c_str());
866     return "";
867 }
868 } // namespace I18n
869 } // namespace Global
870 } // namespace OHOS
871