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