1 /*
2 * Copyright (c) 2021-2025 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 <new>
20 #include <sstream>
21 #include <tuple>
22 #include "format_utils.h"
23 #include "i18n_hilog.h"
24 #include "locale_helper.h"
25 #include "ohos/init_data.h"
26 #include "parameter.h"
27 #include "unicode/ucurr.h"
28 #include "unicode/uenum.h"
29 #include "unicode/utypes.h"
30 #include "unicode/unumberformatter.h"
31 #include "unicode/stringpiece.h"
32 #include "utils.h"
33 #include "number_format.h"
34
35 namespace OHOS {
36 namespace Global {
37 namespace I18n {
38 const char* NumberFormat::DEVICE_TYPE_NAME = "const.product.devicetype";
39 std::mutex NumberFormat::numToCurrencyMutex;
40 bool NumberFormat::initISO4217 = false;
41 std::unordered_map<std::string, std::string> NumberFormat::numToCurrency = {};
42 bool NumberFormat::icuInitialized = NumberFormat::Init();
43 static const double DEFAULT_SAMPLE_NUMBER = 12345.67;
44
45 std::unordered_map<std::string, UNumberUnitWidth> NumberFormat::unitStyle = {
46 { "long", UNumberUnitWidth::UNUM_UNIT_WIDTH_FULL_NAME },
47 { "short", UNumberUnitWidth::UNUM_UNIT_WIDTH_SHORT },
48 { "narrow", UNumberUnitWidth::UNUM_UNIT_WIDTH_NARROW }
49 };
50
51 std::unordered_map<std::string, UNumberUnitWidth> NumberFormat::currencyStyle = {
52 { "symbol", UNumberUnitWidth::UNUM_UNIT_WIDTH_SHORT },
53 { "code", UNumberUnitWidth::UNUM_UNIT_WIDTH_ISO_CODE },
54 { "name", UNumberUnitWidth::UNUM_UNIT_WIDTH_FULL_NAME },
55 { "narrowSymbol", UNumberUnitWidth::UNUM_UNIT_WIDTH_NARROW }
56 };
57
58 std::unordered_map<std::string, UNumberSignDisplay> NumberFormat::signAutoStyle = {
59 { "auto", UNumberSignDisplay::UNUM_SIGN_AUTO },
60 { "never", UNumberSignDisplay::UNUM_SIGN_NEVER },
61 { "always", UNumberSignDisplay::UNUM_SIGN_ALWAYS },
62 { "exceptZero", UNumberSignDisplay::UNUM_SIGN_EXCEPT_ZERO }
63 };
64
65 std::unordered_map<std::string, UNumberSignDisplay> NumberFormat::signAccountingStyle = {
66 { "auto", UNumberSignDisplay::UNUM_SIGN_ACCOUNTING },
67 { "never", UNumberSignDisplay::UNUM_SIGN_NEVER },
68 { "always", UNumberSignDisplay::UNUM_SIGN_ACCOUNTING_ALWAYS },
69 { "exceptZero", UNumberSignDisplay::UNUM_SIGN_ACCOUNTING_EXCEPT_ZERO }
70 };
71
72 std::unordered_map<std::string, std::string> NumberFormat::measurementSystem = {
73 { "metric", "SI" },
74 { "ussystem", "US" },
75 { "uksystem", "UK" },
76 };
77
78 std::unordered_map<std::string, UNumberUnitWidth> NumberFormat::defaultUnitStyle = {
79 { "tablet", UNumberUnitWidth::UNUM_UNIT_WIDTH_FULL_NAME },
80 { "2in1", UNumberUnitWidth::UNUM_UNIT_WIDTH_FULL_NAME },
81 { "tv", UNumberUnitWidth::UNUM_UNIT_WIDTH_FULL_NAME },
82 { "pc", UNumberUnitWidth::UNUM_UNIT_WIDTH_FULL_NAME },
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, UNumberUnitWidth> NumberFormat::defaultCurrencyStyle = {
89 { "wearable", UNumberUnitWidth::UNUM_UNIT_WIDTH_NARROW },
90 { "liteWearable", UNumberUnitWidth::UNUM_UNIT_WIDTH_NARROW },
91 { "watch", UNumberUnitWidth::UNUM_UNIT_WIDTH_NARROW }
92 };
93
94 std::unordered_map<std::string, UNumberRoundingPriority> NumberFormat::roundingPriorityStyle = {
95 { "auto", UNumberRoundingPriority::UNUM_ROUNDING_PRIORITY_STRICT },
96 { "morePrecision", UNumberRoundingPriority::UNUM_ROUNDING_PRIORITY_RELAXED },
97 { "lessPrecision", UNumberRoundingPriority::UNUM_ROUNDING_PRIORITY_STRICT }
98 };
99
100 std::unordered_map<std::string, UNumberFormatRoundingMode> NumberFormat::roundingModeStyle = {
101 { "ceil", UNumberFormatRoundingMode::UNUM_ROUND_CEILING },
102 { "floor", UNumberFormatRoundingMode::UNUM_ROUND_FLOOR },
103 { "expand", UNumberFormatRoundingMode::UNUM_ROUND_UP },
104 { "trunc", UNumberFormatRoundingMode::UNUM_ROUND_DOWN },
105 { "halfCeil", UNumberFormatRoundingMode::UNUM_ROUND_HALF_CEILING },
106 { "halfFloor", UNumberFormatRoundingMode::UNUM_ROUND_HALF_FLOOR },
107 { "halfExpand", UNumberFormatRoundingMode::UNUM_ROUND_HALFUP },
108 { "halfTrunc", UNumberFormatRoundingMode::UNUM_ROUND_HALFDOWN },
109 { "halfEven", UNumberFormatRoundingMode::UNUM_ROUND_HALFEVEN },
110 };
111
112 std::vector<size_t> NumberFormat::roundingIncrementList = {
113 1, 2, 5, 10, 20, 25, 50, 100, 200, 250, 500, 1000, 2000, 2500, 5000
114 };
115
116 std::map<std::string, std::string> NumberFormat::RelativeTimeFormatConfigs = {
117 { "numeric", "auto" }
118 };
119
120 std::unordered_map<std::string, int> NumberFormat::defaultCurrencyFractionMap = {
121 { "BHD", 3 },
122 { "XOF", 0 },
123 { "BIF", 0 },
124 { "XAF", 0 },
125 { "CLP", 0 },
126 { "CLF", 4 },
127 { "KMF", 0 },
128 { "DJF", 0 },
129 { "XPF", 0 },
130 { "GNF", 0 },
131 { "ISK", 0 },
132 { "IQD", 3 },
133 { "JPY", 0 },
134 { "JOD", 3 },
135 { "KRW", 0 },
136 { "KWD", 3 },
137 { "LYD", 3 },
138 { "OMR", 3 },
139 { "PYG", 0 },
140 { "RWF", 0 },
141 { "TND", 3 },
142 { "UGX", 0 },
143 { "UYI", 0 },
144 { "UYW", 4 },
145 { "VUV", 0 },
146 { "VND", 0 },
147 };
148
149 static std::unordered_set<std::string> UNIT_USAGE_FILE = {
150 "size-file-byte",
151 "size-shortfile-byte"
152 };
153
154 static std::unordered_set<std::string> UNIT_USAGE_TEMPERATURE = {
155 "temperature",
156 "temperature-person",
157 "temperature-weather"
158 };
159
NumberFormat(const std::vector<std::string> & localeTags,std::map<std::string,std::string> & configs)160 NumberFormat::NumberFormat(const std::vector<std::string> &localeTags, std::map<std::string, std::string> &configs)
161 {
162 SetDefaultStyle();
163 ResolveLocaleTags(localeTags, configs);
164 std::string systemLocale = LocaleConfig::GetEffectiveLocale();
165 CreateNumberFormatWithDefaultLocale(systemLocale, configs);
166 }
167
NumberFormat(const std::vector<std::string> & localeTags,std::map<std::string,std::string> & configs,bool flag)168 NumberFormat::NumberFormat(const std::vector<std::string> &localeTags,
169 std::map<std::string, std::string> &configs, bool flag)
170 {
171 fromArkTs = flag;
172 ResolveLocaleTags(localeTags, configs);
173 std::string defaultLocale = LocaleHelper::DefaultLocale();
174 CreateNumberFormatWithDefaultLocale(defaultLocale, configs);
175 }
176
ResolveLocaleTags(const std::vector<std::string> & localeTags,std::map<std::string,std::string> & configs)177 void NumberFormat::ResolveLocaleTags(const std::vector<std::string> &localeTags,
178 std::map<std::string, std::string> &configs)
179 {
180 UErrorCode status = U_ZERO_ERROR;
181 std::unique_ptr<icu::LocaleBuilder> builder = nullptr;
182 builder = std::make_unique<icu::LocaleBuilder>();
183 ParseConfigs(configs);
184 for (size_t i = 0; i < localeTags.size(); i++) {
185 std::string curLocale = LocaleConfig::RemoveCustExtParam(localeTags[i]);
186 locale = icu::Locale::forLanguageTag(icu::StringPiece(curLocale), status);
187 if (U_FAILURE(status)) {
188 status = U_ZERO_ERROR;
189 continue;
190 }
191 if (LocaleInfo::allValidLocales.count(locale.getLanguage()) > 0) {
192 localeInfo = std::make_unique<LocaleInfo>(curLocale, configs);
193 CreateRelativeTimeFormat(localeTags[i]);
194 if (!localeInfo->InitSuccess()) {
195 continue;
196 }
197 locale = localeInfo->GetLocale();
198 localeBaseName = localeInfo->GetBaseName();
199 icu::MeasureUnit::getAvailable(unitArray, MAX_UNIT_NUM, status);
200 if (U_FAILURE(status)) {
201 status = U_ZERO_ERROR;
202 continue;
203 }
204 createSuccess = true;
205 ParseExtParam(localeTags[i]);
206 break;
207 }
208 }
209 }
210
CreateNumberFormatWithDefaultLocale(const std::string & systemLocale,std::map<std::string,std::string> & configs)211 void NumberFormat::CreateNumberFormatWithDefaultLocale(const std::string &systemLocale,
212 std::map<std::string, std::string> &configs)
213 {
214 if (!createSuccess) {
215 std::string curLocale = LocaleConfig::RemoveCustExtParam(systemLocale);
216 localeInfo = std::make_unique<LocaleInfo>(curLocale, configs);
217 CreateRelativeTimeFormat(systemLocale);
218 if (localeInfo != nullptr && localeInfo->InitSuccess()) {
219 locale = localeInfo->GetLocale();
220 localeBaseName = localeInfo->GetBaseName();
221 UErrorCode status = U_ZERO_ERROR;
222 icu::MeasureUnit::getAvailable(unitArray, MAX_UNIT_NUM, status);
223 if (U_SUCCESS(status)) {
224 createSuccess = true;
225 ParseExtParam(systemLocale);
226 }
227 }
228 }
229 if (createSuccess) {
230 InitNumberFormat();
231 }
232 }
233
~NumberFormat()234 NumberFormat::~NumberFormat()
235 {
236 }
237
InitNumberFormat()238 void NumberFormat::InitNumberFormat()
239 {
240 icu::number::UnlocalizedNumberFormatter tempFormatter = icu::number::NumberFormatter::with();
241 InitProperties(tempFormatter);
242 styleFormatter = tempFormatter;
243 numberFormat = tempFormatter.locale(locale);
244 numberRangeFormat = icu::number::NumberRangeFormatter::with()
245 .numberFormatterBoth(tempFormatter)
246 .locale(locale);
247 }
248
CreateRelativeTimeFormat(const std::string & locale)249 void NumberFormat::CreateRelativeTimeFormat(const std::string& locale)
250 {
251 if (unitUsage == "elapsed-time-second") {
252 std::vector<std::string> locales = { locale };
253 relativeTimeFormat = std::make_unique<RelativeTimeFormat>(locales,
254 RelativeTimeFormatConfigs);
255 }
256 }
257
InitProperties(icu::number::UnlocalizedNumberFormatter & formatter)258 void NumberFormat::InitProperties(icu::number::UnlocalizedNumberFormatter &formatter)
259 {
260 InitNumberPattern(formatter);
261 InitCurrencyProperties(formatter);
262 InitPercentStyleProperties(formatter);
263 InitUnitProperties(formatter);
264 InitUseGroupingProperties(formatter);
265 InitSignProperties(formatter);
266 InitNotationProperties(formatter);
267 InitDigitsProperties(formatter);
268 }
269
InitNumberPattern(icu::number::UnlocalizedNumberFormatter & formatter)270 void NumberFormat::InitNumberPattern(icu::number::UnlocalizedNumberFormatter &formatter)
271 {
272 UErrorCode status = U_ZERO_ERROR;
273 icu::Locale icuLocale = icu::Locale::forLanguageTag(effectiveLocale.c_str(), status);
274 if (U_FAILURE(status)) {
275 HILOG_ERROR_I18N("NumberFormat::InitNumberPattern: Create icu::Locale failed.");
276 return;
277 }
278 icu::DecimalFormatSymbols* decimalFormatSymbols = new icu::DecimalFormatSymbols(icuLocale, status);
279 if (U_FAILURE(status) || decimalFormatSymbols == nullptr) {
280 delete decimalFormatSymbols;
281 HILOG_ERROR_I18N("NumberFormat::InitNumberPattern: Create icu::DecimalFormatSymbols failed.");
282 return;
283 }
284 if (groupingSymbol.empty()) {
285 formatter = formatter.grouping(UNumberGroupingStrategy::UNUM_GROUPING_OFF);
286 } else {
287 decimalFormatSymbols->setSymbol(icu::DecimalFormatSymbols::ENumberFormatSymbol::kGroupingSeparatorSymbol,
288 groupingSymbol.c_str());
289 }
290 if (!decimalSymbol.empty()) {
291 decimalFormatSymbols->setSymbol(icu::DecimalFormatSymbols::ENumberFormatSymbol::kDecimalSeparatorSymbol,
292 decimalSymbol.c_str());
293 }
294 formatter = formatter.symbols(*decimalFormatSymbols);
295 delete decimalFormatSymbols;
296 }
297
InitCurrencyProperties(icu::number::UnlocalizedNumberFormatter & formatter)298 void NumberFormat::InitCurrencyProperties(icu::number::UnlocalizedNumberFormatter &formatter)
299 {
300 if (!currency.empty()) {
301 UErrorCode status = U_ZERO_ERROR;
302 icu::CurrencyUnit currencyUnit(icu::UnicodeString(currency.c_str()).getBuffer(), status);
303 if (U_FAILURE(status)) {
304 HILOG_ERROR_I18N("NumberFormat::InitCurrencyProperties: Create currency unit failed.");
305 return;
306 }
307 formatter = formatter.unit(currencyUnit);
308 if (currencyDisplay != UNumberUnitWidth::UNUM_UNIT_WIDTH_SHORT) {
309 formatter = formatter.unitWidth(currencyDisplay);
310 }
311 }
312 }
313
InitPercentStyleProperties(icu::number::UnlocalizedNumberFormatter & formatter)314 void NumberFormat::InitPercentStyleProperties(icu::number::UnlocalizedNumberFormatter &formatter)
315 {
316 if (!styleString.empty() && styleString == "percent") {
317 formatter = formatter.unit(icu::NoUnit::percent())
318 .scale(icu::number::Scale::powerOfTen(2)) // 2 is the power of ten
319 .precision(icu::number::Precision::fixedFraction(0));
320 }
321 }
322
InitUseGroupingProperties(icu::number::UnlocalizedNumberFormatter & formatter)323 void NumberFormat::InitUseGroupingProperties(icu::number::UnlocalizedNumberFormatter &formatter)
324 {
325 if (!useGrouping.empty()) {
326 UNumberGroupingStrategy groupingStrategy = (useGrouping == "true") ?
327 UNumberGroupingStrategy::UNUM_GROUPING_AUTO : UNumberGroupingStrategy::UNUM_GROUPING_OFF;
328 formatter = formatter.grouping(groupingStrategy);
329 }
330 }
331
InitNotationProperties(icu::number::UnlocalizedNumberFormatter & formatter)332 void NumberFormat::InitNotationProperties(icu::number::UnlocalizedNumberFormatter &formatter)
333 {
334 if (!notationString.empty()) {
335 formatter = formatter.notation(notation);
336 }
337 }
338
InitSignProperties(icu::number::UnlocalizedNumberFormatter & formatter)339 void NumberFormat::InitSignProperties(icu::number::UnlocalizedNumberFormatter &formatter)
340 {
341 if (!currencySign.empty() || !signDisplayString.empty()) {
342 formatter = formatter.sign(signDisplay);
343 }
344 }
345
InitUnitProperties(icu::number::UnlocalizedNumberFormatter & formatter)346 void NumberFormat::InitUnitProperties(icu::number::UnlocalizedNumberFormatter &formatter)
347 {
348 if (styleString.empty() || styleString.compare("unit") != 0) {
349 return;
350 }
351 bool foundUnit = false;
352 for (icu::MeasureUnit curUnit : unitArray) {
353 if (!strcmp(curUnit.getSubtype(), unit.c_str())) {
354 formatter = formatter.unit(curUnit);
355 foundUnit = true;
356 unitType = curUnit.getType();
357 }
358 }
359 if (!foundUnit && fromArkTs) {
360 SetPerUnit(formatter);
361 }
362
363 auto iter = measurementSystem.find(measurement);
364 if (iter != measurementSystem.end()) {
365 unitMeasSys = iter->second;
366 }
367
368 formatter = formatter.unitWidth(unitDisplay);
369 formatter = formatter.precision(icu::number::Precision::maxFraction(DEFAULT_FRACTION_DIGITS));
370 }
371
SetPerUnit(icu::number::UnlocalizedNumberFormatter & formatter)372 void NumberFormat::SetPerUnit(icu::number::UnlocalizedNumberFormatter &formatter)
373 {
374 icu::MeasureUnit icuUnit;
375 icu::MeasureUnit icuPerUnit;
376 if (!IsWellFormedUnitIdentifier(icuUnit, icuPerUnit)) {
377 HILOG_ERROR_I18N("NumberFormat::SetPerUnit: Get unit failed");
378 return;
379 }
380 icu::MeasureUnit emptyUnit = icu::MeasureUnit();
381 if (icuUnit != emptyUnit) {
382 formatter = formatter.unit(icuUnit);
383 }
384 if (icuPerUnit != emptyUnit) {
385 formatter = formatter.perUnit(icuPerUnit);
386 }
387 }
388
InitDigitsProperties(icu::number::UnlocalizedNumberFormatter & formatter)389 void NumberFormat::InitDigitsProperties(icu::number::UnlocalizedNumberFormatter &formatter)
390 {
391 int32_t status = 0;
392 if (!maximumSignificantDigits.empty() || !minimumSignificantDigits.empty()) {
393 int32_t maxSignificantDigits = ConvertString2Int(maximumSignificantDigits, status);
394 if (status == 0) {
395 formatter = formatter.precision(icu::number::Precision::maxSignificantDigits(maxSignificantDigits));
396 }
397
398 status = 0;
399 int32_t minSignificantDigits = ConvertString2Int(minimumSignificantDigits, status);
400 if (status == 0) {
401 formatter = formatter.precision(icu::number::Precision::minSignificantDigits(minSignificantDigits));
402 }
403 } else {
404 int32_t minIntegerDigits = ConvertString2Int(minimumIntegerDigits, status);
405 if (status == 0 && minIntegerDigits > 1) {
406 formatter = formatter.integerWidth(icu::number::IntegerWidth::zeroFillTo(minIntegerDigits));
407 }
408
409 int32_t minFdStatus = 0;
410 int32_t minFractionDigits = ConvertString2Int(minimumFractionDigits, minFdStatus);
411 int32_t maxFdStatus = 0;
412 int32_t maxFractionDigits = ConvertString2Int(maximumFractionDigits, maxFdStatus);
413 if (minFdStatus == 0 || maxFdStatus == 0) {
414 isSetFraction = true;
415 }
416 if (minFdStatus == 0 && maxFdStatus != 0) {
417 formatter = formatter.precision(icu::number::Precision::minFraction(minFractionDigits));
418 } else if (minFdStatus != 0 && maxFdStatus == 0) {
419 formatter = formatter.precision(icu::number::Precision::maxFraction(maxFractionDigits));
420 } else if (minFdStatus == 0 && maxFdStatus == 0) {
421 formatter =
422 formatter.precision(icu::number::Precision::minMaxFraction(minFractionDigits, maxFractionDigits));
423 }
424 }
425 SetRoundingProperties(formatter);
426 HandleRoundingPriority(formatter);
427 }
428
SetRoundingProperties(icu::number::UnlocalizedNumberFormatter & formatter)429 void NumberFormat::SetRoundingProperties(icu::number::UnlocalizedNumberFormatter &formatter)
430 {
431 if (roundingIncrement != 1) {
432 int32_t maxFractionDigits = GetMaximumFractionDigitsValue();
433 double increment = pow(POW_BASE_NUMBER, -1.0 * maxFractionDigits) * roundingIncrement;
434 formatter = formatter.precision(icu::number::Precision::increment(increment));
435 }
436 if (!roundingModeStr.empty()) {
437 formatter = formatter.roundingMode(roundingMode);
438 }
439 }
440
HandleRoundingPriority(icu::number::UnlocalizedNumberFormatter & formatter)441 void NumberFormat::HandleRoundingPriority(icu::number::UnlocalizedNumberFormatter &formatter)
442 {
443 if (roundingPriorityStr.empty()) {
444 return;
445 }
446 int32_t minFractionDigits = GetMinimumFractionDigitsValue();
447 int32_t maxFractionDigits = GetMaximumFractionDigitsValue();
448 int32_t maxSigDigits = GetMaximumSignificantDigitsIntValue();
449 int32_t minSigDigits = GetMinimumSignificantDigitsIntValue();
450 auto precision = icu::number::Precision::minMaxFraction(minFractionDigits, maxFractionDigits)
451 .withSignificantDigits(minSigDigits, maxSigDigits, roundingPriority);
452 formatter = formatter.precision(precision);
453 }
454
GetMinimumSignificantDigitsIntValue()455 int32_t NumberFormat::GetMinimumSignificantDigitsIntValue()
456 {
457 int32_t minSignifDigits = 1;
458 if (!minimumSignificantDigits.empty()) {
459 int32_t status = 0;
460 int32_t minSignDigits = ConvertString2Int(minimumSignificantDigits, status);
461 minSignifDigits = (status == 0) ? minSignDigits : minSignifDigits;
462 }
463 return minSignifDigits;
464 }
465
GetMaximumSignificantDigitsIntValue()466 int32_t NumberFormat::GetMaximumSignificantDigitsIntValue()
467 {
468 int32_t maxSign = DEFAULT_MAX_SIGNIFICANT_DIGITS;
469 if (!maximumSignificantDigits.empty()) {
470 int32_t status = 0;
471 int32_t maxSignDigits = ConvertString2Int(maximumSignificantDigits, status);
472 maxSign = (status == 0) ? maxSignDigits : maxSign;
473 }
474 return maxSign;
475 }
476
GetMaximumFractionDigitsValue()477 int32_t NumberFormat::GetMaximumFractionDigitsValue()
478 {
479 int32_t maxFraction = DEFAULT_FRACTION_DIGITS;
480 if (!maximumFractionDigits.empty()) {
481 int32_t status = 0;
482 int32_t maxFractionDigits = ConvertString2Int(maximumFractionDigits, status);
483 maxFraction = (status == 0) ? maxFractionDigits : maxFraction;
484 }
485 return maxFraction;
486 }
487
GetMinimumFractionDigitsValue()488 int32_t NumberFormat::GetMinimumFractionDigitsValue()
489 {
490 int32_t minFraction = 0;
491 if (!minimumFractionDigits.empty()) {
492 int32_t status = 0;
493 int32_t minFractionDigits = ConvertString2Int(minimumFractionDigits, status);
494 minFraction = (status == 0) ? minFractionDigits : minFraction;
495 }
496 return minFraction;
497 }
498
ParseConfigs(std::map<std::string,std::string> & configs)499 void NumberFormat::ParseConfigs(std::map<std::string, std::string> &configs)
500 {
501 if (configs.count("signDisplay") > 0) {
502 signDisplayString = configs["signDisplay"];
503 }
504 if (signAutoStyle.count(signDisplayString) > 0) {
505 signDisplay = signAutoStyle[signDisplayString];
506 }
507 if (configs.count("style") > 0) {
508 styleString = configs["style"];
509 }
510 if (styleString == "unit" && configs.count("unit") > 0) {
511 unit = configs["unit"];
512 if (configs.count("unitDisplay") > 0) {
513 unitDisplayString = configs["unitDisplay"];
514 if (unitStyle.count(unitDisplayString) > 0) {
515 unitDisplay = unitStyle[unitDisplayString];
516 }
517 }
518 if (configs.count("unitUsage") > 0) {
519 unitUsage = configs["unitUsage"];
520 }
521 }
522 if (styleString == "currency" && configs.count("currency") > 0) {
523 currency = GetCurrencyFromConfig(configs["currency"]);
524 if (configs.count("currencySign") > 0) {
525 currencySign = configs["currencySign"];
526 }
527 if (currencySign.compare("accounting") == 0 && signAccountingStyle.count(signDisplayString) > 0) {
528 signDisplay = signAccountingStyle[signDisplayString];
529 }
530 if (configs.count("currencyDisplay") > 0 && currencyStyle.count(configs["currencyDisplay"]) > 0) {
531 currencyDisplayString = configs["currencyDisplay"];
532 currencyDisplay = currencyStyle[currencyDisplayString];
533 }
534 }
535 ParseDigitsConfigs(configs);
536 ParseRoundingConfigs(configs);
537 }
538
ParseDigitsConfigs(std::map<std::string,std::string> & configs)539 void NumberFormat::ParseDigitsConfigs(std::map<std::string, std::string> &configs)
540 {
541 if (configs.count("notation") > 0) {
542 notationString = configs["notation"];
543 if (notationString == "scientific") {
544 notation = icu::number::Notation::scientific();
545 } else if (notationString == "engineering") {
546 notation = icu::number::Notation::engineering();
547 }
548 if (notationString == "compact") {
549 if (configs.count("compactDisplay") > 0) {
550 compactDisplay = configs["compactDisplay"];
551 }
552 if (compactDisplay == "long") {
553 notation = icu::number::Notation::compactLong();
554 } else {
555 notation = icu::number::Notation::compactShort();
556 }
557 }
558 }
559 if (configs.count("minimumIntegerDigits") > 0) {
560 minimumIntegerDigits = configs["minimumIntegerDigits"];
561 }
562 if (configs.count("minimumFractionDigits") > 0) {
563 minimumFractionDigits = configs["minimumFractionDigits"];
564 }
565 if (configs.count("maximumFractionDigits") > 0) {
566 maximumFractionDigits = configs["maximumFractionDigits"];
567 }
568 if (configs.count("minimumSignificantDigits") > 0) {
569 minimumSignificantDigits = configs["minimumSignificantDigits"];
570 }
571 if (configs.count("maximumSignificantDigits") > 0) {
572 maximumSignificantDigits = configs["maximumSignificantDigits"];
573 }
574 if (configs.count("numberingSystem") > 0) {
575 numberingSystem = configs["numberingSystem"];
576 }
577 if (configs.count("useGrouping") > 0) {
578 useGrouping = configs["useGrouping"];
579 }
580 if (configs.count("localeMatcher") > 0) {
581 localeMatcher = configs["localeMatcher"];
582 }
583 }
584
ParseRoundingConfigs(std::map<std::string,std::string> & configs)585 void NumberFormat::ParseRoundingConfigs(std::map<std::string, std::string> &configs)
586 {
587 if (configs.count("roundingMode") > 0) {
588 std::string tempRoundingModeStr = configs["roundingMode"];
589 auto iter = roundingModeStyle.find(tempRoundingModeStr);
590 if (iter != roundingModeStyle.end()) {
591 roundingMode = iter->second;
592 roundingModeStr = tempRoundingModeStr;
593 }
594 }
595 if (configs.count("roundingPriority") > 0) {
596 std::string tempRoundingPriorityStr = configs["roundingPriority"];
597 auto iter = roundingPriorityStyle.find(tempRoundingPriorityStr);
598 if (iter != roundingPriorityStyle.end()) {
599 roundingPriorityStr = tempRoundingPriorityStr;
600 roundingPriority = iter->second;
601 }
602 }
603 if (configs.count("roundingIncrement") > 0) {
604 std::string increment = configs["roundingIncrement"];
605 int32_t status = 0;
606 int32_t incrementNum = ConvertString2Int(increment, status);
607 if (status != 0) {
608 HILOG_ERROR_I18N("NumberFormat::ParseRoundingConfigs: Convert string to int failed.");
609 return;
610 }
611 auto iter = std::find(roundingIncrementList.begin(), roundingIncrementList.end(),
612 static_cast<size_t>(incrementNum));
613 if (iter != roundingIncrementList.end()) {
614 roundingIncrement = *iter;
615 }
616 }
617 }
618
ParseExtParam(const std::string & localeTag)619 void NumberFormat::ParseExtParam(const std::string& localeTag)
620 {
621 std::pair<std::string, std::string> numberPattern = LocaleConfig::GetNumberPatternFromLocale(localeTag);
622 if (numberPattern.second.empty()) {
623 return;
624 }
625 groupingSymbol = numberPattern.first;
626 decimalSymbol = numberPattern.second;
627 preferredTemperature =
628 LocaleConfig::GetTemperatureName(LocaleConfig::GetTemperatureTypeFromLocale(localeTag));
629 effectiveLocale = LocaleConfig::RemoveCustExtParam(localeTag);
630 if (!numberingSystem.empty()) {
631 effectiveLocale = LocaleConfig::ModifyExtParam(effectiveLocale, "nu", numberingSystem, "-u-");
632 }
633 measurement = LocaleConfig::GetMeasurementFromLocale(localeTag);
634 }
635
SetUnit(std::string & preferredUnit)636 void NumberFormat::SetUnit(std::string &preferredUnit)
637 {
638 if (preferredUnit.empty()) {
639 return;
640 }
641 for (icu::MeasureUnit curUnit : unitArray) {
642 if (!strcmp(curUnit.getSubtype(), preferredUnit.c_str())) {
643 numberFormat = numberFormat.unit(curUnit);
644 styleFormatter = styleFormatter.unit(curUnit);
645 }
646 }
647 }
648
Format(double number)649 std::string NumberFormat::Format(double number)
650 {
651 std::string result;
652 UErrorCode status = U_ZERO_ERROR;
653 icu::UnicodeString formatResult;
654 if (IsRelativeTimeFormat(number)) {
655 icu::FormattedRelativeDateTime formattedTime = FormatToFormattedRelativeDateTime(number);
656 formatResult = formattedTime.toString(status);
657 } else {
658 icu::number::FormattedNumber formattedNumber = FormatToFormattedNumber(number);
659 formatResult = formattedNumber.toString(status);
660 }
661 if (U_FAILURE(status)) {
662 result = "";
663 } else {
664 formatResult.toUTF8String(result);
665 }
666 return PseudoLocalizationProcessor(result);
667 }
668
FormatBigInt(const std::string & number)669 std::string NumberFormat::FormatBigInt(const std::string &number)
670 {
671 std::string result;
672 icu::number::FormattedNumber formattedNumber = FormatDecimalToFormattedNumber(number);
673 UErrorCode status = U_ZERO_ERROR;
674 icu::UnicodeString formatResult = formattedNumber.toString(status);
675 if (U_SUCCESS(status)) {
676 formatResult.toUTF8String(result);
677 }
678 return PseudoLocalizationProcessor(result);
679 }
680
FormatToParts(std::vector<std::vector<std::string>> & result)681 void NumberFormat::FormatToParts(std::vector<std::vector<std::string>> &result)
682 {
683 double number = uprv_getNaN();
684 icu::number::FormattedNumber formattedNumber = FormatToFormattedNumber(number);
685 FormattedNumberParts(formattedNumber, result, "nan", number);
686 }
687
FormatBigIntToParts(std::string & number,std::vector<std::vector<std::string>> & result)688 void NumberFormat::FormatBigIntToParts(std::string &number, std::vector<std::vector<std::string>> &result)
689 {
690 icu::number::FormattedNumber formattedNumber = FormatDecimalToFormattedNumber(number);
691 double numDouble = GetBigIntFieldType(number);
692 FormattedNumberParts(formattedNumber, result, "bigint", numDouble);
693 }
694
GetBigIntFieldType(const std::string & bigIntStr)695 double NumberFormat::GetBigIntFieldType(const std::string &bigIntStr)
696 {
697 double numDouble = 0;
698 if (!bigIntStr.empty() && bigIntStr.at(0) == '-') {
699 numDouble = -1.0; // -1 just means number is negative
700 }
701 return numDouble;
702 }
703
FormatToParts(double number,std::vector<std::vector<std::string>> & result)704 void NumberFormat::FormatToParts(double number, std::vector<std::vector<std::string>> &result)
705 {
706 std::string finalUnit = unit;
707 if (IsRelativeTimeFormat(number, finalUnit)) {
708 RelativeDateTimeFormatToParts(number, finalUnit, result);
709 return;
710 }
711 icu::number::FormattedNumber formattedNumber = FormatToFormattedNumber(number);
712 FormattedNumberParts(formattedNumber, result, "number", number);
713 }
714
FormattedNumberParts(icu::number::FormattedNumber & formattedNumber,std::vector<std::vector<std::string>> & result,const std::string & napiType,const double & number)715 void NumberFormat::FormattedNumberParts(icu::number::FormattedNumber &formattedNumber,
716 std::vector<std::vector<std::string>> &result, const std::string &napiType,
717 const double &number)
718 {
719 UErrorCode status = U_ZERO_ERROR;
720 icu::UnicodeString formatResult = formattedNumber.toString(status);
721 if (U_FAILURE(status)) {
722 HILOG_ERROR_I18N("NumberFormat::FormatToParts: UnicodeString toString failed.");
723 return;
724 }
725 FindAllFormatParts(formattedNumber, result, number, napiType, formatResult);
726 }
727
FindAllFormatParts(icu::FormattedValue & formattedNumber,std::vector<std::vector<std::string>> & result,double number,const std::string & napiType,icu::UnicodeString & formatResult)728 void NumberFormat::FindAllFormatParts(icu::FormattedValue &formattedNumber,
729 std::vector<std::vector<std::string>> &result, double number,
730 const std::string &napiType, icu::UnicodeString &formatResult)
731 {
732 icu::ConstrainedFieldPosition cfpo;
733 int previousLimit = 0;
734 bool lastFieldGroup = false;
735 int groupLeapLength = 0;
736 UErrorCode status = U_ZERO_ERROR;
737 struct FormatPartParam param = {previousLimit, lastFieldGroup, groupLeapLength, number, napiType};
738 while (formattedNumber.nextPosition(cfpo, status)) {
739 if (U_FAILURE(status)) {
740 HILOG_ERROR_I18N("NumberFormat::FindAllFormatParts: Get next position failed.");
741 result.clear();
742 return;
743 }
744 SetEveryFormatPartItem(cfpo, formatResult, result, param);
745 }
746 if (formatResult.length() > param.previousLimit) {
747 std::string typeString = "literal";
748 AddFormatParts(typeString, result, formatResult, param.previousLimit, formatResult.length());
749 }
750 }
751
FindAllFormatParts(icu::FormattedValue & formattedNumber,std::vector<std::vector<std::string>> & result,const double & first,const double & second,icu::UnicodeString & formatResult)752 void NumberFormat::FindAllFormatParts(icu::FormattedValue &formattedNumber,
753 std::vector<std::vector<std::string>> &result, const double &first,
754 const double &second, icu::UnicodeString &formatResult)
755 {
756 icu::ConstrainedFieldPosition cfpo;
757 int previousLimit = 0;
758 bool lastFieldGroup = false;
759 int groupLeapLength = 0;
760 size_t rangeSpanCount = 0;
761 struct FormatPartParam param = {previousLimit, lastFieldGroup, groupLeapLength, first, "number"};
762 UErrorCode status = U_ZERO_ERROR;
763 while (formattedNumber.nextPosition(cfpo, status)) {
764 if (U_FAILURE(status)) {
765 HILOG_ERROR_I18N("NumberFormat::FindAllFormatParts: Get next position failed.");
766 result.clear();
767 return;
768 }
769 if (static_cast<UFieldCategory>(cfpo.getCategory()) == UFIELD_CATEGORY_NUMBER_RANGE_SPAN) {
770 ++rangeSpanCount;
771 }
772 if (rangeSpanCount > 1) {
773 param.number = second;
774 }
775 SetEveryFormatPartItem(cfpo, formatResult, result, param);
776 }
777 if (formatResult.length() > param.previousLimit) {
778 std::string typeString = "literal";
779 AddFormatParts(typeString, result, formatResult, param.previousLimit, formatResult.length());
780 }
781 }
782
SetEveryFormatPartItem(icu::ConstrainedFieldPosition & cfpo,icu::UnicodeString & formatResult,std::vector<std::vector<std::string>> & result,FormatPartParam & param)783 void NumberFormat::SetEveryFormatPartItem(icu::ConstrainedFieldPosition &cfpo, icu::UnicodeString &formatResult,
784 std::vector<std::vector<std::string>> &result, FormatPartParam ¶m)
785 {
786 int32_t fieldId = cfpo.getField();
787 int32_t start = cfpo.getStart();
788 int32_t limit = cfpo.getLimit();
789 std::string typeString = "literal";
790 if (static_cast<UFieldCategory>(cfpo.getCategory()) == UFIELD_CATEGORY_NUMBER_RANGE_SPAN) {
791 if (param.previousLimit < start) {
792 AddFormatParts(typeString, result, formatResult, param.previousLimit, start);
793 param.previousLimit = start;
794 }
795 return;
796 }
797 if (static_cast<UNumberFormatFields>(fieldId) == UNUM_GROUPING_SEPARATOR_FIELD) {
798 typeString = "integer";
799 AddFormatParts(typeString, result, formatResult, param.previousLimit, start);
800 {
801 typeString = FormatUtils::GetNumberFieldType(param.napiType, fieldId, param.number);
802 AddFormatParts(typeString, result, formatResult, start, limit);
803 }
804 param.lastFieldGroup = true;
805 param.groupLeapLength = start - param.previousLimit + 1;
806 param.previousLimit = limit;
807 return;
808 } else if (start > param.previousLimit) {
809 AddFormatParts(typeString, result, formatResult, param.previousLimit, start);
810 }
811 if (param.lastFieldGroup) {
812 start = start + param.groupLeapLength;
813 param.lastFieldGroup = false;
814 }
815 if (styleString.compare("unit") == 0 && static_cast<UNumberFormatFields>(fieldId) == UNUM_PERCENT_FIELD) {
816 typeString = "unit";
817 } else {
818 typeString = FormatUtils::GetNumberFieldType(param.napiType, fieldId, param.number);
819 }
820 if (start < param.previousLimit && param.previousLimit < limit) {
821 AddFormatParts(typeString, result, formatResult, param.previousLimit, limit);
822 } else {
823 AddFormatParts(typeString, result, formatResult, start, limit);
824 }
825 param.previousLimit = limit;
826 }
827
AddFormatParts(std::string typeString,std::vector<std::vector<std::string>> & result,icu::UnicodeString & formatResult,int32_t start,int32_t end)828 void NumberFormat::AddFormatParts(std::string typeString, std::vector<std::vector<std::string>> &result,
829 icu::UnicodeString &formatResult, int32_t start, int32_t end)
830 {
831 std::string value = GetSubString(formatResult, start, end);
832 std::vector<std::string> info;
833 info.push_back(typeString);
834 info.push_back(value);
835 result.push_back(info);
836 }
837
GetSubString(icu::UnicodeString & formatResult,int32_t start,int32_t end)838 std::string NumberFormat::GetSubString(icu::UnicodeString &formatResult, int32_t start, int32_t end)
839 {
840 icu::UnicodeString substring = formatResult.tempSubStringBetween(start, end);
841 std::string val;
842 substring.toUTF8String(val);
843 return val;
844 }
845
RelativeDateTimeFormatToParts(double number,std::string & finalUnit,std::vector<std::vector<std::string>> & result)846 void NumberFormat::RelativeDateTimeFormatToParts(double number, std::string &finalUnit,
847 std::vector<std::vector<std::string>> &result)
848 {
849 if (!createSuccess) {
850 return;
851 }
852 double finalNumber = number;
853 if (relativeTimeFormat == nullptr) {
854 return;
855 }
856 relativeTimeFormat->FormatToParts(finalNumber, finalUnit, result);
857 }
858
IsRelativeTimeFormat(double number)859 bool NumberFormat::IsRelativeTimeFormat(double number)
860 {
861 double finalNumber = number;
862 std::string finalUnit = unit;
863 return IsRelativeTimeFormat(finalNumber, finalUnit);
864 }
865
IsRelativeTimeFormat(double number,std::string & unitForConvert)866 bool NumberFormat::IsRelativeTimeFormat(double number, std::string &unitForConvert)
867 {
868 double finalNumber = number;
869 if (unitUsage.compare("elapsed-time-second") == 0 && ConvertDate(finalNumber, unitForConvert) &&
870 relativeTimeFormat != nullptr) {
871 return true;
872 }
873 return false;
874 }
875
FormatDecimalToFormattedNumber(const std::string & number)876 icu::number::FormattedNumber NumberFormat::FormatDecimalToFormattedNumber(const std::string &number)
877 {
878 if (!createSuccess) {
879 return {};
880 }
881 UErrorCode status = U_ZERO_ERROR;
882 icu::number::FormattedNumber formattedNumber =
883 numberFormat.formatDecimal(icu::StringPiece(number), status);
884 if (U_FAILURE(status)) {
885 HILOG_ERROR_I18N("FormatDecimalToFormattedNumber: format %{public}s failed.", number.c_str());
886 return {};
887 }
888 return formattedNumber;
889 }
890
FormatToFormattedNumber(double number)891 icu::number::FormattedNumber NumberFormat::FormatToFormattedNumber(double number)
892 {
893 if (!createSuccess) {
894 return {};
895 }
896 double temp = 0;
897 NumberFormat::DealWithUnitUsage(false, number, temp);
898 UErrorCode icuStatus = U_ZERO_ERROR;
899 icu::number::FormattedNumber formattedNumber = numberFormat.formatDouble(number, icuStatus);
900 if (U_FAILURE(icuStatus)) {
901 return {};
902 }
903 return formattedNumber;
904 }
905
FormatToFormattedRelativeDateTime(double number)906 icu::FormattedRelativeDateTime NumberFormat::FormatToFormattedRelativeDateTime(double number)
907 {
908 if (!createSuccess) {
909 return {};
910 }
911
912 double finalNumber = number;
913 std::string finalUnit = unit;
914 if (unitUsage.compare("elapsed-time-second") == 0 && ConvertDate(finalNumber, finalUnit) &&
915 relativeTimeFormat != nullptr) {
916 return relativeTimeFormat->FormatToFormattedValue(finalNumber, finalUnit);
917 }
918 return {};
919 }
920
FormatRange(double start,double end)921 std::string NumberFormat::FormatRange(double start, double end)
922 {
923 if (!createSuccess) {
924 HILOG_ERROR_I18N("FormatRange: init numberRangeFormat failed.");
925 return PseudoLocalizationProcessor("");
926 }
927 if (end < start) {
928 HILOG_ERROR_I18N("FormatRange: parameter:end less then parameter:start");
929 return PseudoLocalizationProcessor("");
930 }
931 NumberFormat::DealWithUnitUsage(true, start, end);
932 icu::number::LocalizedNumberRangeFormatter tempNumberRangeFormat = icu::number::NumberRangeFormatter::with()
933 .numberFormatterBoth(styleFormatter)
934 .locale(locale);
935 UErrorCode status = U_ZERO_ERROR;
936 icu::number::FormattedNumberRange numberRange = tempNumberRangeFormat.formatFormattableRange(start, end, status);
937 if (U_FAILURE(status)) {
938 HILOG_ERROR_I18N("FormatRange: formatFormattableRange failed.");
939 return PseudoLocalizationProcessor("");
940 }
941 icu::UnicodeString res = numberRange.toString(status);
942 if (U_FAILURE(status)) {
943 HILOG_ERROR_I18N("FormatRange: icu::UnicodeString.toString() failed.");
944 return PseudoLocalizationProcessor("");
945 }
946 std::string result;
947 res.toUTF8String(result);
948 return PseudoLocalizationProcessor(result);
949 }
950
FormatJsRange(double first,double second)951 std::string NumberFormat::FormatJsRange(double first, double second)
952 {
953 if (!createSuccess) {
954 HILOG_ERROR_I18N("FormatRange: init numberRangeFormat failed.");
955 return PseudoLocalizationProcessor("");
956 }
957 icu::number::LocalizedNumberRangeFormatter tempNumberRangeFormat = icu::number::NumberRangeFormatter::with()
958 .numberFormatterBoth(styleFormatter)
959 .locale(locale);
960 UErrorCode status = U_ZERO_ERROR;
961 icu::number::FormattedNumberRange numberRange =
962 tempNumberRangeFormat.formatFormattableRange(first, second, status);
963 if (U_FAILURE(status)) {
964 HILOG_ERROR_I18N("FormatRange: formatFormattableRange failed.");
965 return PseudoLocalizationProcessor("");
966 }
967 icu::UnicodeString unicodeStr = numberRange.toString(status);
968 if (U_FAILURE(status)) {
969 HILOG_ERROR_I18N("FormatRange: icu::UnicodeString.toString() failed.");
970 return PseudoLocalizationProcessor("");
971 }
972 std::string result;
973 unicodeStr.toUTF8String(result);
974 return PseudoLocalizationProcessor(result);
975 }
976
FormatRangeToParts(const double & first,const double & second,std::vector<std::vector<std::string>> & result)977 void NumberFormat::FormatRangeToParts(const double &first, const double &second,
978 std::vector<std::vector<std::string>> &result)
979 {
980 FormatableRangeToParts(first, second, result);
981 }
982
FormatableRangeToParts(double first,double second,std::vector<std::vector<std::string>> & result)983 void NumberFormat::FormatableRangeToParts(double first, double second,
984 std::vector<std::vector<std::string>> &result)
985 {
986 if (!createSuccess) {
987 HILOG_ERROR_I18N("NumberFormat::FormatableRangeToParts: init numberRangeFormat failed.");
988 return;
989 }
990 icu::number::LocalizedNumberRangeFormatter tempNumberRangeFormat = icu::number::NumberRangeFormatter::with()
991 .numberFormatterBoth(styleFormatter)
992 .locale(locale);
993 UErrorCode status = U_ZERO_ERROR;
994 icu::number::FormattedNumberRange numberRange =
995 tempNumberRangeFormat.formatFormattableRange(first, second, status);
996 if (U_FAILURE(status)) {
997 HILOG_ERROR_I18N("NumberFormat::FormatableRangeToParts: formatFormattableRange failed.");
998 return;
999 }
1000 icu::UnicodeString res = numberRange.toString(status);
1001 if (U_FAILURE(status)) {
1002 HILOG_ERROR_I18N("NumberFormat::FormatableRangeToParts: icu::UnicodeString.toString() failed.");
1003 return;
1004 }
1005 FindAllFormatParts(numberRange, result, first, second, res);
1006 }
1007
GetResolvedOptions(std::map<std::string,std::string> & map,bool setDefault)1008 void NumberFormat::GetResolvedOptions(std::map<std::string, std::string> &map, bool setDefault)
1009 {
1010 map.insert(std::make_pair("locale", localeBaseName));
1011 if (!styleString.empty()) {
1012 map.insert(std::make_pair("style", styleString));
1013 } else {
1014 if (setDefault) {
1015 map.insert(std::make_pair("style", "decimal"));
1016 }
1017 }
1018 if (!currency.empty()) {
1019 map.insert(std::make_pair("currency", currency));
1020 }
1021 if (!currencySign.empty()) {
1022 map.insert(std::make_pair("currencySign", currencySign));
1023 } else if (setDefault) {
1024 map.insert(std::make_pair("currencySign", "standard"));
1025 }
1026 if (!currencyDisplayString.empty()) {
1027 map.insert(std::make_pair("currencyDisplay", currencyDisplayString));
1028 } else if (setDefault) {
1029 map.insert(std::make_pair("currencyDisplay", "symbol"));
1030 }
1031 if (!signDisplayString.empty()) {
1032 map.insert(std::make_pair("signDisplay", signDisplayString));
1033 } else if (setDefault) {
1034 map.insert(std::make_pair("signDisplay", "auto"));
1035 }
1036 if (!compactDisplay.empty()) {
1037 map.insert(std::make_pair("compactDisplay", compactDisplay));
1038 }
1039 if (!unitDisplayString.empty()) {
1040 map.insert(std::make_pair("unitDisplay", unitDisplayString));
1041 }
1042 if (!unitUsage.empty()) {
1043 map.insert(std::make_pair("unitUsage", unitUsage));
1044 }
1045 if (!unit.empty()) {
1046 map.insert(std::make_pair("unit", unit));
1047 }
1048 GetDigitsResolvedOptions(map, setDefault);
1049 GetDigitsResolvedOptionsExt(map, setDefault);
1050 }
1051
SupportedLocalesOf(const std::vector<std::string> & requestLocales,const std::map<std::string,std::string> & configs,I18nErrorCode & status)1052 std::vector<std::string> NumberFormat::SupportedLocalesOf(const std::vector<std::string> &requestLocales,
1053 const std::map<std::string, std::string> &configs, I18nErrorCode &status)
1054 {
1055 return LocaleHelper::SupportedLocalesOf(requestLocales, configs, status);
1056 }
1057
GetDigitsResolvedOptions(std::map<std::string,std::string> & map,bool setDefault)1058 void NumberFormat::GetDigitsResolvedOptions(std::map<std::string, std::string> &map, bool setDefault)
1059 {
1060 if (!numberingSystem.empty()) {
1061 map.insert(std::make_pair("numberingSystem", numberingSystem));
1062 } else if (!(localeInfo->GetNumberingSystem()).empty()) {
1063 map.insert(std::make_pair("numberingSystem", localeInfo->GetNumberingSystem()));
1064 } else {
1065 UErrorCode status = U_ZERO_ERROR;
1066 auto numSys = std::unique_ptr<icu::NumberingSystem>(icu::NumberingSystem::createInstance(locale, status));
1067 if (U_SUCCESS(status)) {
1068 map.insert(std::make_pair("numberingSystem", numSys->getName()));
1069 }
1070 }
1071 if (!useGrouping.empty()) {
1072 map.insert(std::make_pair("useGrouping", useGrouping));
1073 } else if (setDefault) {
1074 map.insert(std::make_pair("useGrouping", "true"));
1075 }
1076 if (!minimumIntegerDigits.empty()) {
1077 map.insert(std::make_pair("minimumIntegerDigits", minimumIntegerDigits));
1078 } else if (setDefault) {
1079 map.insert(std::make_pair("minimumIntegerDigits", "1"));
1080 }
1081 if (!minimumFractionDigits.empty()) {
1082 map.insert(std::make_pair("minimumFractionDigits", minimumFractionDigits));
1083 } else if (setDefault) {
1084 GetMinimumFractionDigitsOption(map);
1085 }
1086 if (!maximumFractionDigits.empty()) {
1087 map.insert(std::make_pair("maximumFractionDigits", maximumFractionDigits));
1088 } else if (setDefault) {
1089 GetMaximumFractionDigitsOption(map);
1090 }
1091 if (!minimumSignificantDigits.empty()) {
1092 map.insert(std::make_pair("minimumSignificantDigits", minimumSignificantDigits));
1093 }
1094 if (!maximumSignificantDigits.empty()) {
1095 map.insert(std::make_pair("maximumSignificantDigits", maximumSignificantDigits));
1096 }
1097 }
1098
GetDigitsResolvedOptionsExt(std::map<std::string,std::string> & map,bool setDefault)1099 void NumberFormat::GetDigitsResolvedOptionsExt(std::map<std::string, std::string> &map, bool setDefault)
1100 {
1101 if (!localeMatcher.empty()) {
1102 map.insert(std::make_pair("localeMatcher", localeMatcher));
1103 }
1104 if (!notationString.empty()) {
1105 map.insert(std::make_pair("notation", notationString));
1106 } else if (setDefault) {
1107 map.insert(std::make_pair("notation", "standard"));
1108 }
1109 if (!roundingModeStr.empty()) {
1110 map.insert(std::make_pair("roundingMode", roundingModeStr));
1111 }
1112 if (!roundingPriorityStr.empty()) {
1113 map.insert(std::make_pair("roundingPriority", roundingPriorityStr));
1114 }
1115 if (roundingIncrement != 1) {
1116 map.insert(std::make_pair("roundingIncrement", std::to_string(roundingIncrement)));
1117 }
1118 }
1119
GetMinimumFractionDigitsOption(std::map<std::string,std::string> & map)1120 void NumberFormat::GetMinimumFractionDigitsOption(std::map<std::string, std::string> &map)
1121 {
1122 std::string style = "decimal";
1123 if (map.find("style") != map.end()) {
1124 style = map["style"];
1125 }
1126 if (style == "decimal" || style == "percent") {
1127 map.insert(std::make_pair("minimumFractionDigits", "0"));
1128 } else if (style == "currency") {
1129 int fraction = GetCurrencyFractionDigits(map);
1130 map.insert(std::make_pair("minimumFractionDigits", std::to_string(fraction)));
1131 }
1132 }
1133
GetMaximumFractionDigitsOption(std::map<std::string,std::string> & map)1134 void NumberFormat::GetMaximumFractionDigitsOption(std::map<std::string, std::string> &map)
1135 {
1136 std::string style = "decimal";
1137 if (map.find("style") != map.end()) {
1138 style = map["style"];
1139 }
1140 if (style == "decimal") {
1141 map.insert(std::make_pair("maximumFractionDigits", "3"));
1142 } else if (style == "percent") {
1143 map.insert(std::make_pair("maximumFractionDigits", "0"));
1144 } else if (style == "currency") {
1145 int fraction = GetCurrencyFractionDigits(map);
1146 map.insert(std::make_pair("maximumFractionDigits", std::to_string(fraction)));
1147 }
1148 }
1149
GetCurrencyFractionDigits(std::map<std::string,std::string> & map)1150 int NumberFormat::GetCurrencyFractionDigits(std::map<std::string, std::string> &map)
1151 {
1152 int result = 2; // 2 is default value
1153 std::string currency;
1154 if (map.find("currency") != map.end()) {
1155 currency = map["currency"];
1156 currency = GetCurrencyFromConfig(currency);
1157 }
1158 if (defaultCurrencyFractionMap.find(currency) != defaultCurrencyFractionMap.end()) {
1159 result = defaultCurrencyFractionMap[currency];
1160 }
1161 return result;
1162 }
1163
SetPrecisionWithByte(double number,const std::string & finalUnit)1164 void NumberFormat::SetPrecisionWithByte(double number, const std::string& finalUnit)
1165 {
1166 if (isSetFraction) {
1167 return;
1168 }
1169 int32_t FractionDigits = -1;
1170 // 100 is the threshold between different decimal
1171 if (finalUnit == "byte" || number >= 100) {
1172 FractionDigits = 0;
1173 } else if (number < 1) {
1174 // 2 is the number of significant digits in the decimal
1175 FractionDigits = 2;
1176 // 10 is the threshold between different decimal
1177 } else if (number < 10) {
1178 if (unitUsage == "size-shortfile-byte") {
1179 FractionDigits = 1;
1180 } else {
1181 // 2 is the number of significant digits in the decimal
1182 FractionDigits = 2;
1183 }
1184 } else {
1185 if (unitUsage == "size-shortfile-byte") {
1186 FractionDigits = 0;
1187 } else {
1188 // 2 is the number of significant digits in the decimal
1189 FractionDigits = 2;
1190 }
1191 }
1192 if (FractionDigits != -1) {
1193 numberFormat = numberFormat.precision(icu::number::Precision::minMaxFraction(FractionDigits, FractionDigits));
1194 styleFormatter =
1195 styleFormatter.precision(icu::number::Precision::minMaxFraction(FractionDigits, FractionDigits));
1196 }
1197 }
1198
GetCurrency() const1199 std::string NumberFormat::GetCurrency() const
1200 {
1201 return currency;
1202 }
1203
GetCurrencySign() const1204 std::string NumberFormat::GetCurrencySign() const
1205 {
1206 return currencySign;
1207 }
1208
GetStyle() const1209 std::string NumberFormat::GetStyle() const
1210 {
1211 return styleString;
1212 }
1213
GetNumberingSystem() const1214 std::string NumberFormat::GetNumberingSystem() const
1215 {
1216 return numberingSystem;
1217 }
1218
GetUseGrouping() const1219 std::string NumberFormat::GetUseGrouping() const
1220 {
1221 return useGrouping;
1222 }
1223
GetMinimumIntegerDigits() const1224 std::string NumberFormat::GetMinimumIntegerDigits() const
1225 {
1226 return minimumIntegerDigits;
1227 }
1228
GetMinimumFractionDigits() const1229 std::string NumberFormat::GetMinimumFractionDigits() const
1230 {
1231 return minimumFractionDigits;
1232 }
1233
GetMaximumFractionDigits() const1234 std::string NumberFormat::GetMaximumFractionDigits() const
1235 {
1236 return maximumFractionDigits;
1237 }
1238
GetMinimumSignificantDigits() const1239 std::string NumberFormat::GetMinimumSignificantDigits() const
1240 {
1241 return minimumSignificantDigits;
1242 }
1243
GetMaximumSignificantDigits() const1244 std::string NumberFormat::GetMaximumSignificantDigits() const
1245 {
1246 return maximumSignificantDigits;
1247 }
1248
GetLocaleMatcher() const1249 std::string NumberFormat::GetLocaleMatcher() const
1250 {
1251 return localeMatcher;
1252 }
1253
Init()1254 bool NumberFormat::Init()
1255 {
1256 SetHwIcuDirectory();
1257 return true;
1258 }
1259
SetDefaultStyle()1260 void NumberFormat::SetDefaultStyle()
1261 {
1262 char value[LocaleConfig::CONFIG_LEN];
1263 int code = GetParameter(DEVICE_TYPE_NAME, "", value, LocaleConfig::CONFIG_LEN);
1264 if (code > 0) {
1265 std::string deviceType = value;
1266 if (defaultUnitStyle.find(deviceType) != defaultUnitStyle.end()) {
1267 unitDisplay = defaultUnitStyle[deviceType];
1268 }
1269 if (defaultCurrencyStyle.find(deviceType) != defaultCurrencyStyle.end()) {
1270 currencyDisplay = defaultCurrencyStyle[deviceType];
1271 }
1272 }
1273 }
1274
ReadISO4217Datas()1275 bool NumberFormat::ReadISO4217Datas()
1276 {
1277 if (initISO4217) {
1278 return true;
1279 }
1280 std::lock_guard<std::mutex> readDataLock(numToCurrencyMutex);
1281 if (initISO4217) {
1282 return true;
1283 }
1284 UErrorCode status = U_ZERO_ERROR;
1285 const char *currentCurrency;
1286 UEnumeration *currencies = ucurr_openISOCurrencies(UCURR_ALL, &status);
1287 if (U_FAILURE(status)) {
1288 return false;
1289 }
1290
1291 UChar code[CURRENCY_LEN + 1]; // +1 includes the NUL
1292 int32_t length = 0;
1293 while ((currentCurrency = uenum_next(currencies, &length, &status)) != NULL) {
1294 u_charsToUChars(currentCurrency, code, length + 1); // +1 includes the NUL
1295 int32_t numCode = ucurr_getNumericCode(code);
1296 if (numCode == 0) {
1297 continue;
1298 }
1299 std::stringstream ss;
1300 ss << std::setw(CURRENCY_LEN) << std::setfill('0') << numCode; // fill with '0'
1301 numToCurrency.insert(std::make_pair<std::string, std::string>(ss.str(), currentCurrency));
1302 }
1303 uenum_close(currencies);
1304 initISO4217 = true;
1305 return !numToCurrency.empty();
1306 }
1307
GetCurrencyFromConfig(const std::string & currency)1308 std::string NumberFormat::GetCurrencyFromConfig(const std::string& currency)
1309 {
1310 if (currency.size() != CURRENCY_LEN) {
1311 HILOG_ERROR_I18N("Invalid currency code : %{public}s", currency.c_str());
1312 return "";
1313 }
1314 bool isAlpha = true;
1315 for (auto c : currency) {
1316 isAlpha = std::isalpha(c);
1317 if (!isAlpha) {
1318 break;
1319 }
1320 }
1321 if (isAlpha) {
1322 return currency;
1323 }
1324 if (ReadISO4217Datas() && numToCurrency.find(currency) != numToCurrency.end()) {
1325 return numToCurrency[currency];
1326 }
1327 HILOG_ERROR_I18N("Invalid currency code : %{public}s", currency.c_str());
1328 return "";
1329 }
1330
GetIcuDefaultLocale()1331 std::string NumberFormat::GetIcuDefaultLocale()
1332 {
1333 return "en-US";
1334 }
1335
CheckNumberFormatOptions(std::map<std::string,std::string> & map,int32_t & code)1336 std::string NumberFormat::CheckNumberFormatOptions(std::map<std::string, std::string> &map, int32_t &code)
1337 {
1338 std::string message = CheckFormatOptions(map, code);
1339 if (!message.empty()) {
1340 return message;
1341 }
1342 std::vector<std::tuple<std::string, int, int>> vect = {
1343 {"minimumIntegerDigits", 1, 21}, // 21 is maximum of minimumIntegerDigits
1344 {"minimumFractionDigits", 0, 20}, // 20 is maximum of minimumFractionDigits
1345 {"maximumFractionDigits", 0, 20}, // 20 is maximum of maximumFractionDigits
1346 {"minimumSignificantDigits", 1, 21}, // 21 is maximum of minimumSignificantDigits
1347 {"maximumSignificantDigits", 1, 21}, // 21 is maximum of maximumSignificantDigits
1348 };
1349 for (auto iter = vect.begin(); iter != vect.end(); ++iter) {
1350 std::string optionName = std::get<0>(*iter);
1351 int min = std::get<1>(*iter); // 1 is item index
1352 int max = std::get<2>(*iter); // 2 is item index
1353 CheckNumberFormatOptionsExt(map, code, optionName, min, max);
1354 if (code != 0) {
1355 return "";
1356 }
1357 }
1358 return "";
1359 }
1360
CheckFormatOptions(std::map<std::string,std::string> & map,int32_t & code)1361 std::string NumberFormat::CheckFormatOptions(std::map<std::string, std::string> &map, int32_t &code)
1362 {
1363 if (map.find("style") != map.end()) {
1364 std::string style = map["style"];
1365 if (style.compare("currency") == 0 && map.find("currency") == map.end()) {
1366 code = -1;
1367 return "style is currency but currency is undefined";
1368 }
1369 if (style.compare("unit") == 0 && map.find("unit") == map.end()) {
1370 code = -1;
1371 return "style is unit but unit is undefined";
1372 }
1373 }
1374 if (map.find("currency") != map.end()) {
1375 std::string currency = map["currency"];
1376 std::string checkCurr = GetCurrencyFromConfig(currency);
1377 if (checkCurr.empty()) {
1378 code = -1;
1379 return "not a wellformed code";
1380 }
1381 }
1382 if (map.find("localeMatcher") != map.end()) {
1383 I18nErrorCode status = I18nErrorCode::SUCCESS;
1384 std::string localeMatcher = LocaleHelper::ParseOption(map, "localeMatcher", "best fit", false, status);
1385 if (status != I18nErrorCode::SUCCESS) {
1386 code = -1;
1387 return "getStringOption failed";
1388 }
1389 }
1390 if (map.find("currencySign") != map.end()) {
1391 std::string currencySign = map["currencySign"];
1392 if (currencySign.compare("standard") != 0 && currencySign.compare("accounting") != 0) {
1393 code = -1;
1394 return "getStringOption failed";
1395 }
1396 }
1397 return "";
1398 }
1399
CheckNumberFormatOptionsExt(std::map<std::string,std::string> & map,int32_t & code,const std::string & optionName,int min,int max)1400 void NumberFormat::CheckNumberFormatOptionsExt(std::map<std::string, std::string> &map, int32_t &code,
1401 const std::string &optionName, int min, int max)
1402 {
1403 if (map.find(optionName) != map.end()) {
1404 std::string optionNameStr = map[optionName];
1405 int32_t status = 0;
1406 int32_t optionValue = ConvertString2Int(optionNameStr, status);
1407 if (status != 0) {
1408 code = -1;
1409 return;
1410 }
1411 if (optionValue < min || optionValue > max) {
1412 code = -1;
1413 }
1414 }
1415 }
1416
DealWithUnitUsage(bool isFormatRange,double & firstNumber,double & secondNumber)1417 void NumberFormat::DealWithUnitUsage(bool isFormatRange, double& firstNumber, double& secondNumber)
1418 {
1419 if (!createSuccess) {
1420 HILOG_ERROR_I18N("NumberFormat::DealWithUnitUsage: init numberRangeFormat failed.");
1421 return;
1422 }
1423 if (unitUsage.empty()) {
1424 return;
1425 }
1426 double finalNumber = firstNumber;
1427 std::string finalUnit = unit;
1428 if (!NumberFormat::DealWithUnitConvert(finalNumber, finalUnit)) {
1429 HILOG_ERROR_I18N("NumberFormat::DealWithUnitUsage: Deal with unit convert failed.");
1430 return;
1431 }
1432 if (isFormatRange) {
1433 if (!Convert(secondNumber, unit, unitMeasSys, finalUnit, unitMeasSys)) {
1434 HILOG_ERROR_I18N("NumberFormat::DealWithUnitUsage: Convert secondNumber failed.");
1435 return;
1436 }
1437 }
1438 firstNumber = finalNumber;
1439 SetUnit(finalUnit);
1440 }
1441
DealWithUnitConvert(double & finalNumber,std::string & finalUnit)1442 bool NumberFormat::DealWithUnitConvert(double& finalNumber, std::string& finalUnit)
1443 {
1444 if (UNIT_USAGE_FILE.find(unitUsage) != UNIT_USAGE_FILE.end()) {
1445 if (!ConvertByte(finalNumber, finalUnit)) {
1446 HILOG_ERROR_I18N("NumberFormat::DealWithUnitConvert: Convert byte failed.");
1447 return false;
1448 }
1449 SetPrecisionWithByte(finalNumber, finalUnit);
1450 } else if (UNIT_USAGE_TEMPERATURE.find(unitUsage) != UNIT_USAGE_TEMPERATURE.end()) {
1451 if (preferredTemperature.empty() ||
1452 Convert(finalNumber, unit, unitMeasSys, preferredTemperature, unitMeasSys) == 0) {
1453 return false;
1454 }
1455 finalUnit = preferredTemperature;
1456 } else {
1457 if (localeInfo == nullptr) {
1458 HILOG_ERROR_I18N("NumberFormat::DealWithUnitConvert: localeInfo is nullptr.");
1459 return false;
1460 }
1461 std::vector<std::string> preferredUnits;
1462 if (unitUsage == "default") {
1463 GetDefaultPreferredUnit(localeInfo->GetRegion(), unitType, preferredUnits);
1464 } else {
1465 GetPreferredUnit(localeInfo->GetRegion(), unitUsage, preferredUnits);
1466 }
1467 std::map<double, std::string> preferredValuesOverOne;
1468 std::map<double, std::string> preferredValuesUnderOne;
1469 double num = finalNumber;
1470 for (size_t i = 0; i < preferredUnits.size(); i++) {
1471 if (!Convert(num, unit, unitMeasSys, preferredUnits[i], unitMeasSys)) {
1472 HILOG_ERROR_I18N("NumberFormat::DealWithUnitConvert: Convert %{public}s failed.", unit.c_str());
1473 continue;
1474 }
1475 if (num >= 1) {
1476 preferredValuesOverOne.insert(std::make_pair(num, preferredUnits[i]));
1477 } else {
1478 preferredValuesUnderOne.insert(std::make_pair(num, preferredUnits[i]));
1479 }
1480 }
1481 if (preferredValuesOverOne.empty() && preferredValuesUnderOne.empty()) {
1482 return false;
1483 }
1484 if (preferredValuesOverOne.size() > 0) {
1485 std::tie(finalNumber, finalUnit) = *preferredValuesOverOne.begin();
1486 } else if (preferredValuesUnderOne.size() > 0) {
1487 std::tie(finalNumber, finalUnit) = *preferredValuesUnderOne.begin();
1488 }
1489 }
1490 return true;
1491 }
1492
ToMeasureUnit(const std::string & sanctionedUnit,icu::MeasureUnit & measureUnit)1493 bool NumberFormat::ToMeasureUnit(const std::string &sanctionedUnit,
1494 icu::MeasureUnit &measureUnit)
1495 {
1496 for (auto &unitItem : unitArray) {
1497 if (std::strcmp(sanctionedUnit.c_str(), unitItem.getSubtype()) == 0) {
1498 measureUnit = unitItem;
1499 return true;
1500 }
1501 }
1502 return false;
1503 }
1504
IsWellFormedUnitIdentifier(icu::MeasureUnit & icuUnit,icu::MeasureUnit & icuPerUnit)1505 bool NumberFormat::IsWellFormedUnitIdentifier(icu::MeasureUnit &icuUnit,
1506 icu::MeasureUnit &icuPerUnit)
1507 {
1508 icu::MeasureUnit emptyUnit = icu::MeasureUnit();
1509 auto pos = unit.find("-per-");
1510 if (ToMeasureUnit(unit, icuUnit) && pos == std::string::npos) {
1511 icuPerUnit = emptyUnit;
1512 return true;
1513 }
1514 size_t afterPos = pos + NumberFormat::PERUNIT_STRING;
1515 if (pos == std::string::npos || unit.find("-per-", afterPos) != std::string::npos) {
1516 HILOG_ERROR_I18N("IsWellFormedUnitIdentifier: invalid unit: %{public}s", unit.c_str());
1517 return false;
1518 }
1519 std::string numerator = unit.substr(0, pos);
1520 if (!ToMeasureUnit(numerator, icuUnit)) {
1521 HILOG_ERROR_I18N("IsWellFormedUnitIdentifier: before unit: %{public}s invalid", numerator.c_str());
1522 return false;
1523 }
1524 std::string denominator = unit.substr(pos + NumberFormat::PERUNIT_STRING);
1525 if (!ToMeasureUnit(denominator, icuPerUnit)) {
1526 HILOG_ERROR_I18N("IsWellFormedUnitIdentifier: after unit: %{public}s invalid", denominator.c_str());
1527 return false;
1528 }
1529 return true;
1530 }
1531
GetNumberPatternSample(const std::string & localeTag,const std::pair<std::string,std::string> & numberPattern)1532 std::string NumberFormat::GetNumberPatternSample(const std::string& localeTag,
1533 const std::pair<std::string, std::string>& numberPattern)
1534 {
1535 UErrorCode status = U_ZERO_ERROR;
1536 icu::Locale icuLocale = icu::Locale::forLanguageTag(icu::StringPiece(localeTag), status);
1537 if (U_FAILURE(status)) {
1538 HILOG_ERROR_I18N("NumberFormat::GetNumberPatternSample: Create icu::Locale failed.");
1539 return "";
1540 }
1541
1542 icu::DecimalFormatSymbols* decimalFormatSymbols = new icu::DecimalFormatSymbols(icuLocale, status);
1543 if (U_FAILURE(status) || decimalFormatSymbols == nullptr) {
1544 delete decimalFormatSymbols;
1545 HILOG_ERROR_I18N("NumberFormat::GetNumberPatternSample: Create icu::DecimalFormatSymbols failed.");
1546 return "";
1547 }
1548 icu::number::UnlocalizedNumberFormatter tempFormatter = icu::number::NumberFormatter::with();
1549 std::string groupingSymbol = numberPattern.first;
1550 if (groupingSymbol.empty()) {
1551 tempFormatter = tempFormatter.grouping(UNumberGroupingStrategy::UNUM_GROUPING_OFF);
1552 } else {
1553 decimalFormatSymbols->setSymbol(icu::DecimalFormatSymbols::ENumberFormatSymbol::kGroupingSeparatorSymbol,
1554 groupingSymbol.c_str());
1555 }
1556 std::string decimalSymbol = numberPattern.second;
1557 if (!decimalSymbol.empty()) {
1558 decimalFormatSymbols->setSymbol(icu::DecimalFormatSymbols::ENumberFormatSymbol::kDecimalSeparatorSymbol,
1559 decimalSymbol.c_str());
1560 }
1561 tempFormatter = tempFormatter.symbols(*decimalFormatSymbols);
1562 delete decimalFormatSymbols;
1563 icu::number::LocalizedNumberFormatter numberFormat = tempFormatter.locale(icuLocale);
1564 icu::number::FormattedNumber formattedNumber = numberFormat.formatDouble(DEFAULT_SAMPLE_NUMBER, status);
1565 if (U_FAILURE(status)) {
1566 HILOG_ERROR_I18N("NumberFormat::GetNumberPatternSample: Format double failed.");
1567 return "";
1568 }
1569 icu::UnicodeString formatResult = formattedNumber.toString(status);
1570 if (U_FAILURE(status)) {
1571 HILOG_ERROR_I18N("NumberFormat::GetNumberPatternSample: ToString failed.");
1572 return "";
1573 }
1574 std::string result;
1575 formatResult.toUTF8String(result);
1576 return result;
1577 }
1578 } // namespace I18n
1579 } // namespace Global
1580 } // namespace OHOS
1581