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 <sstream>
19 #include "i18n_hilog.h"
20 #include "ohos/init_data.h"
21 #include "parameter.h"
22 #include "unicode/ucurr.h"
23 #include "unicode/uenum.h"
24 #include "unicode/utypes.h"
25 #include "utils.h"
26 #include "number_format.h"
27
28 namespace OHOS {
29 namespace Global {
30 namespace I18n {
31 const char* NumberFormat::DEVICE_TYPE_NAME = "const.product.devicetype";
32 std::unordered_map<std::string, std::string> NumberFormat::numToCurrency = {};
33 bool NumberFormat::icuInitialized = NumberFormat::Init();
34
35 std::unordered_map<std::string, UNumberUnitWidth> NumberFormat::unitStyle = {
36 { "long", UNumberUnitWidth::UNUM_UNIT_WIDTH_FULL_NAME },
37 { "short", UNumberUnitWidth::UNUM_UNIT_WIDTH_SHORT },
38 { "narrow", UNumberUnitWidth::UNUM_UNIT_WIDTH_NARROW }
39 };
40
41 std::unordered_map<std::string, UNumberUnitWidth> NumberFormat::currencyStyle = {
42 { "symbol", UNumberUnitWidth::UNUM_UNIT_WIDTH_SHORT },
43 { "code", UNumberUnitWidth::UNUM_UNIT_WIDTH_ISO_CODE },
44 { "name", UNumberUnitWidth::UNUM_UNIT_WIDTH_FULL_NAME },
45 { "narrowSymbol", UNumberUnitWidth::UNUM_UNIT_WIDTH_NARROW }
46 };
47
48 std::unordered_map<std::string, UNumberSignDisplay> NumberFormat::signAutoStyle = {
49 { "auto", UNumberSignDisplay::UNUM_SIGN_AUTO },
50 { "never", UNumberSignDisplay::UNUM_SIGN_NEVER },
51 { "always", UNumberSignDisplay::UNUM_SIGN_ALWAYS },
52 { "exceptZero", UNumberSignDisplay::UNUM_SIGN_EXCEPT_ZERO }
53 };
54
55 std::unordered_map<std::string, UNumberSignDisplay> NumberFormat::signAccountingStyle = {
56 { "auto", UNumberSignDisplay::UNUM_SIGN_ACCOUNTING },
57 { "never", UNumberSignDisplay::UNUM_SIGN_NEVER },
58 { "always", UNumberSignDisplay::UNUM_SIGN_ACCOUNTING_ALWAYS },
59 { "exceptZero", UNumberSignDisplay::UNUM_SIGN_ACCOUNTING_EXCEPT_ZERO }
60 };
61
62 std::unordered_map<UMeasurementSystem, std::string> NumberFormat::measurementSystem = {
63 { UMeasurementSystem::UMS_SI, "SI" },
64 { UMeasurementSystem::UMS_US, "US" },
65 { UMeasurementSystem::UMS_UK, "UK" },
66 };
67
68 std::unordered_map<std::string, UNumberUnitWidth> NumberFormat::defaultUnitStyle = {
69 { "tablet", UNumberUnitWidth::UNUM_UNIT_WIDTH_FULL_NAME },
70 { "2in1", UNumberUnitWidth::UNUM_UNIT_WIDTH_FULL_NAME },
71 { "tv", UNumberUnitWidth::UNUM_UNIT_WIDTH_FULL_NAME },
72 { "pc", UNumberUnitWidth::UNUM_UNIT_WIDTH_FULL_NAME },
73 { "wearable", UNumberUnitWidth::UNUM_UNIT_WIDTH_NARROW },
74 { "liteWearable", UNumberUnitWidth::UNUM_UNIT_WIDTH_NARROW },
75 { "watch", UNumberUnitWidth::UNUM_UNIT_WIDTH_NARROW }
76 };
77
78 std::unordered_map<std::string, UNumberUnitWidth> NumberFormat::defaultCurrencyStyle = {
79 { "wearable", UNumberUnitWidth::UNUM_UNIT_WIDTH_NARROW },
80 { "liteWearable", UNumberUnitWidth::UNUM_UNIT_WIDTH_NARROW },
81 { "watch", UNumberUnitWidth::UNUM_UNIT_WIDTH_NARROW }
82 };
83
84 std::map<std::string, std::string> NumberFormat::RelativeTimeFormatConfigs = {
85 { "numeric", "auto" }
86 };
87
NumberFormat(const std::vector<std::string> & localeTags,std::map<std::string,std::string> & configs)88 NumberFormat::NumberFormat(const std::vector<std::string> &localeTags, std::map<std::string, std::string> &configs)
89 {
90 SetDefaultStyle();
91 UErrorCode status = U_ZERO_ERROR;
92 std::unique_ptr<icu::LocaleBuilder> builder = nullptr;
93 builder = std::make_unique<icu::LocaleBuilder>();
94 ParseConfigs(configs);
95 for (size_t i = 0; i < localeTags.size(); i++) {
96 std::string curLocale = localeTags[i];
97 locale = icu::Locale::forLanguageTag(icu::StringPiece(curLocale), status);
98 if (status != U_ZERO_ERROR) {
99 status = U_ZERO_ERROR;
100 continue;
101 }
102 if (LocaleInfo::allValidLocales.count(locale.getLanguage()) > 0) {
103 localeInfo = std::make_unique<LocaleInfo>(curLocale, configs);
104 CreateRelativeTimeFormat(curLocale);
105 if (!localeInfo->InitSuccess()) {
106 continue;
107 }
108 locale = localeInfo->GetLocale();
109 localeBaseName = localeInfo->GetBaseName();
110 numberFormat = icu::number::NumberFormatter::withLocale(locale);
111 icu::MeasureUnit::getAvailable(unitArray, MAX_UNIT_NUM, status);
112 if (!U_SUCCESS(status)) {
113 status = U_ZERO_ERROR;
114 continue;
115 }
116 createSuccess = true;
117 break;
118 }
119 }
120 if (!createSuccess) {
121 std::string systemLocale = LocaleConfig::GetSystemLocale();
122 localeInfo = std::make_unique<LocaleInfo>(systemLocale, configs);
123 CreateRelativeTimeFormat(systemLocale);
124 if (localeInfo->InitSuccess()) {
125 locale = localeInfo->GetLocale();
126 localeBaseName = localeInfo->GetBaseName();
127 numberFormat = icu::number::NumberFormatter::withLocale(locale);
128 icu::MeasureUnit::getAvailable(unitArray, MAX_UNIT_NUM, status);
129 if (U_SUCCESS(status)) {
130 createSuccess = true;
131 }
132 }
133 }
134 if (createSuccess) {
135 InitProperties();
136 }
137 }
138
~NumberFormat()139 NumberFormat::~NumberFormat()
140 {
141 }
142
CreateRelativeTimeFormat(const std::string & locale)143 void NumberFormat::CreateRelativeTimeFormat(const std::string& locale)
144 {
145 if (unitUsage == "elapsed-time-second") {
146 std::vector<std::string> locales = { locale };
147 relativeTimeFormat = std::make_unique<RelativeTimeFormat>(locales,
148 RelativeTimeFormatConfigs);
149 }
150 }
151
InitProperties()152 void NumberFormat::InitProperties()
153 {
154 if (!currency.empty()) {
155 UErrorCode status = U_ZERO_ERROR;
156 numberFormat =
157 numberFormat.unit(icu::CurrencyUnit(icu::UnicodeString(currency.c_str()).getBuffer(), status));
158 if (currencyDisplay != UNumberUnitWidth::UNUM_UNIT_WIDTH_SHORT) {
159 numberFormat = numberFormat.unitWidth(currencyDisplay);
160 }
161 }
162 if (!styleString.empty() && styleString == "percent") {
163 // 2 is the power of ten
164 numberFormat = numberFormat.unit(icu::NoUnit::percent()).scale(icu::number::Scale::powerOfTen(2)).precision(
165 icu::number::Precision::fixedFraction(0));
166 }
167 if (!styleString.empty() && styleString == "unit") {
168 for (icu::MeasureUnit curUnit : unitArray) {
169 if (!strcmp(curUnit.getSubtype(), unit.c_str())) {
170 numberFormat = numberFormat.unit(curUnit);
171 unitType = curUnit.getType();
172 }
173 }
174 UErrorCode status = U_ZERO_ERROR;
175 UMeasurementSystem measSys = ulocdata_getMeasurementSystem(localeBaseName.c_str(), &status);
176 if (U_SUCCESS(status) && measSys >= 0) {
177 unitMeasSys = measurementSystem[measSys];
178 }
179 numberFormat = numberFormat.unitWidth(unitDisplay);
180 numberFormat = numberFormat.precision(icu::number::Precision::maxFraction(DEFAULT_FRACTION_DIGITS));
181 }
182 if (!useGrouping.empty()) {
183 numberFormat = numberFormat.grouping((useGrouping == "true") ?
184 UNumberGroupingStrategy::UNUM_GROUPING_AUTO : UNumberGroupingStrategy::UNUM_GROUPING_OFF);
185 }
186 if (!currencySign.empty() || !signDisplayString.empty()) {
187 numberFormat = numberFormat.sign(signDisplay);
188 }
189 if (!notationString.empty()) {
190 numberFormat = numberFormat.notation(notation);
191 }
192 InitDigitsProperties();
193 }
194
InitDigitsProperties()195 void NumberFormat::InitDigitsProperties()
196 {
197 int32_t status = 0;
198 if (!maximumSignificantDigits.empty() || !minimumSignificantDigits.empty()) {
199 int32_t maxSignificantDigits = ConvertString2Int(maximumSignificantDigits, status);
200 if (status == 0) {
201 numberFormat = numberFormat.precision(icu::number::Precision::maxSignificantDigits(maxSignificantDigits));
202 }
203
204 status = 0;
205 int32_t minSignificantDigits = ConvertString2Int(minimumSignificantDigits, status);
206 if (status == 0) {
207 numberFormat = numberFormat.precision(icu::number::Precision::minSignificantDigits(minSignificantDigits));
208 }
209 } else {
210 int32_t minIntegerDigits = ConvertString2Int(minimumIntegerDigits, status);
211 if (status == 0 && minIntegerDigits > 1) {
212 numberFormat =
213 numberFormat.integerWidth(icu::number::IntegerWidth::zeroFillTo(minIntegerDigits));
214 }
215
216 int32_t minFdStatus = 0;
217 int32_t minFractionDigits = ConvertString2Int(minimumFractionDigits, minFdStatus);
218 int32_t maxFdStatus = 0;
219 int32_t maxFractionDigits = ConvertString2Int(maximumFractionDigits, maxFdStatus);
220 if (minFdStatus == 0 || maxFdStatus == 0) {
221 isSetFraction = true;
222 }
223 if (minFdStatus == 0 && maxFdStatus != 0) {
224 numberFormat =
225 numberFormat.precision(icu::number::Precision::minFraction(minFractionDigits));
226 } else if (minFdStatus != 0 && maxFdStatus == 0) {
227 numberFormat =
228 numberFormat.precision(icu::number::Precision::maxFraction(maxFractionDigits));
229 } else if (minFdStatus == 0 && maxFdStatus == 0) {
230 numberFormat =
231 numberFormat.precision(icu::number::Precision::minMaxFraction(minFractionDigits, maxFractionDigits));
232 }
233 }
234 }
235
ParseConfigs(std::map<std::string,std::string> & configs)236 void NumberFormat::ParseConfigs(std::map<std::string, std::string> &configs)
237 {
238 if (configs.count("signDisplay") > 0) {
239 signDisplayString = configs["signDisplay"];
240 }
241 if (signAutoStyle.count(signDisplayString) > 0) {
242 signDisplay = signAutoStyle[signDisplayString];
243 }
244 if (configs.count("style") > 0) {
245 styleString = configs["style"];
246 }
247 if (styleString == "unit" && configs.count("unit") > 0) {
248 unit = configs["unit"];
249 if (configs.count("unitDisplay") > 0) {
250 unitDisplayString = configs["unitDisplay"];
251 if (unitStyle.count(unitDisplayString) > 0) {
252 unitDisplay = unitStyle[unitDisplayString];
253 }
254 }
255 if (configs.count("unitUsage") > 0) {
256 unitUsage = configs["unitUsage"];
257 }
258 }
259 if (styleString == "currency" && configs.count("currency") > 0) {
260 currency = GetCurrencyFromConfig(configs["currency"]);
261 if (configs.count("currencySign") > 0) {
262 currencySign = configs["currencySign"];
263 }
264 if (currencySign.compare("accounting") == 0 && signAccountingStyle.count(signDisplayString) > 0) {
265 signDisplay = signAccountingStyle[signDisplayString];
266 }
267 if (configs.count("currencyDisplay") > 0 && currencyStyle.count(configs["currencyDisplay"]) > 0) {
268 currencyDisplayString = configs["currencyDisplay"];
269 currencyDisplay = currencyStyle[currencyDisplayString];
270 }
271 }
272 ParseDigitsConfigs(configs);
273 }
274
ParseDigitsConfigs(std::map<std::string,std::string> & configs)275 void NumberFormat::ParseDigitsConfigs(std::map<std::string, std::string> &configs)
276 {
277 if (configs.count("notation") > 0) {
278 notationString = configs["notation"];
279 if (notationString == "scientific") {
280 notation = icu::number::Notation::scientific();
281 } else if (notationString == "engineering") {
282 notation = icu::number::Notation::engineering();
283 }
284 if (notationString == "compact") {
285 if (configs.count("compactDisplay") > 0) {
286 compactDisplay = configs["compactDisplay"];
287 }
288 if (compactDisplay == "long") {
289 notation = icu::number::Notation::compactLong();
290 } else {
291 notation = icu::number::Notation::compactShort();
292 }
293 }
294 }
295 if (configs.count("minimumIntegerDigits") > 0) {
296 minimumIntegerDigits = configs["minimumIntegerDigits"];
297 }
298 if (configs.count("minimumFractionDigits") > 0) {
299 minimumFractionDigits = configs["minimumFractionDigits"];
300 }
301 if (configs.count("maximumFractionDigits") > 0) {
302 maximumFractionDigits = configs["maximumFractionDigits"];
303 }
304 if (configs.count("minimumSignificantDigits") > 0) {
305 minimumSignificantDigits = configs["minimumSignificantDigits"];
306 }
307 if (configs.count("maximumSignificantDigits") > 0) {
308 maximumSignificantDigits = configs["maximumSignificantDigits"];
309 }
310 if (configs.count("numberingSystem") > 0) {
311 numberingSystem = configs["numberingSystem"];
312 }
313 if (configs.count("useGrouping") > 0) {
314 useGrouping = configs["useGrouping"];
315 }
316 if (configs.count("localeMatcher") > 0) {
317 localeMatcher = configs["localeMatcher"];
318 }
319 }
320
SetUnit(std::string & preferredUnit)321 void NumberFormat::SetUnit(std::string &preferredUnit)
322 {
323 if (preferredUnit.empty()) {
324 return;
325 }
326 for (icu::MeasureUnit curUnit : unitArray) {
327 if (!strcmp(curUnit.getSubtype(), preferredUnit.c_str())) {
328 numberFormat = numberFormat.unit(curUnit);
329 }
330 }
331 }
332
Format(double number)333 std::string NumberFormat::Format(double number)
334 {
335 if (!createSuccess) {
336 return PseudoLocalizationProcessor("");
337 }
338 double finalNumber = number;
339 std::string finalUnit = unit;
340 if ((unitUsage == "size-file-byte" || unitUsage == "size-shortfile-byte") && ConvertByte(finalNumber, finalUnit)) {
341 SetUnit(finalUnit);
342 SetPrecisionWithByte(finalNumber, finalUnit);
343 } else if (unitUsage == "elapsed-time-second" && ConvertDate(finalNumber, finalUnit) &&
344 relativeTimeFormat != nullptr) {
345 return relativeTimeFormat->Format(finalNumber, finalUnit);
346 } else if (!unitUsage.empty()) {
347 std::vector<std::string> preferredUnits;
348 if (unitUsage == "default") {
349 GetDefaultPreferredUnit(localeInfo->GetRegion(), unitType, preferredUnits);
350 } else {
351 GetPreferredUnit(localeInfo->GetRegion(), unitUsage, preferredUnits);
352 }
353 std::map<double, std::string> preferredValuesOverOne;
354 std::map<double, std::string> preferredValuesUnderOne;
355 double num = number;
356 for (size_t i = 0; i < preferredUnits.size(); i++) {
357 int status = Convert(num, unit, unitMeasSys, preferredUnits[i], unitMeasSys);
358 if (!status) {
359 continue;
360 }
361 if (num >= 1) {
362 preferredValuesOverOne.insert(std::make_pair(num, preferredUnits[i]));
363 } else {
364 preferredValuesUnderOne.insert(std::make_pair(num, preferredUnits[i]));
365 }
366 }
367 std::string preferredUnit;
368 if (preferredValuesOverOne.size() > 0) {
369 finalNumber = preferredValuesOverOne.begin()->first;
370 preferredUnit = preferredValuesOverOne.begin()->second;
371 } else if (preferredValuesUnderOne.size() > 0) {
372 finalNumber = preferredValuesUnderOne.rbegin()->first;
373 preferredUnit = preferredValuesUnderOne.rbegin()->second;
374 }
375 SetUnit(preferredUnit);
376 }
377 std::string result;
378 UErrorCode status = U_ZERO_ERROR;
379 numberFormat.formatDouble(finalNumber, status).toString(status).toUTF8String(result);
380 return PseudoLocalizationProcessor(result);
381 }
382
GetResolvedOptions(std::map<std::string,std::string> & map)383 void NumberFormat::GetResolvedOptions(std::map<std::string, std::string> &map)
384 {
385 map.insert(std::make_pair("locale", localeBaseName));
386 if (!styleString.empty()) {
387 map.insert(std::make_pair("style", styleString));
388 }
389 if (!currency.empty()) {
390 map.insert(std::make_pair("currency", currency));
391 }
392 if (!currencySign.empty()) {
393 map.insert(std::make_pair("currencySign", currencySign));
394 }
395 if (!currencyDisplayString.empty()) {
396 map.insert(std::make_pair("currencyDisplay", currencyDisplayString));
397 }
398 if (!signDisplayString.empty()) {
399 map.insert(std::make_pair("signDisplay", signDisplayString));
400 }
401 if (!compactDisplay.empty()) {
402 map.insert(std::make_pair("compactDisplay", compactDisplay));
403 }
404 if (!unitDisplayString.empty()) {
405 map.insert(std::make_pair("unitDisplay", unitDisplayString));
406 }
407 if (!unitUsage.empty()) {
408 map.insert(std::make_pair("unitUsage", unitUsage));
409 }
410 if (!unit.empty()) {
411 map.insert(std::make_pair("unit", unit));
412 }
413 GetDigitsResolvedOptions(map);
414 }
415
GetDigitsResolvedOptions(std::map<std::string,std::string> & map)416 void NumberFormat::GetDigitsResolvedOptions(std::map<std::string, std::string> &map)
417 {
418 if (!numberingSystem.empty()) {
419 map.insert(std::make_pair("numberingSystem", numberingSystem));
420 } else if (!(localeInfo->GetNumberingSystem()).empty()) {
421 map.insert(std::make_pair("numberingSystem", localeInfo->GetNumberingSystem()));
422 } else {
423 UErrorCode status = U_ZERO_ERROR;
424 auto numSys = std::unique_ptr<icu::NumberingSystem>(icu::NumberingSystem::createInstance(locale, status));
425 if (U_SUCCESS(status)) {
426 map.insert(std::make_pair("numberingSystem", numSys->getName()));
427 }
428 }
429 if (!useGrouping.empty()) {
430 map.insert(std::make_pair("useGrouping", useGrouping));
431 }
432 if (!minimumIntegerDigits.empty()) {
433 map.insert(std::make_pair("minimumIntegerDigits", minimumIntegerDigits));
434 }
435 if (!minimumFractionDigits.empty()) {
436 map.insert(std::make_pair("minimumFractionDigits", minimumFractionDigits));
437 }
438 if (!maximumFractionDigits.empty()) {
439 map.insert(std::make_pair("maximumFractionDigits", maximumFractionDigits));
440 }
441 if (!minimumSignificantDigits.empty()) {
442 map.insert(std::make_pair("minimumSignificantDigits", minimumSignificantDigits));
443 }
444 if (!maximumSignificantDigits.empty()) {
445 map.insert(std::make_pair("maximumSignificantDigits", maximumSignificantDigits));
446 }
447 if (!localeMatcher.empty()) {
448 map.insert(std::make_pair("localeMatcher", localeMatcher));
449 }
450 if (!notationString.empty()) {
451 map.insert(std::make_pair("notation", notationString));
452 }
453 }
454
SetPrecisionWithByte(double number,const std::string & finalUnit)455 void NumberFormat::SetPrecisionWithByte(double number, const std::string& finalUnit)
456 {
457 if (isSetFraction) {
458 return;
459 }
460 int32_t FractionDigits = -1;
461 // 100 is the threshold between different decimal
462 if (finalUnit == "byte" || number >= 100) {
463 FractionDigits = 0;
464 } else if (number < 1) {
465 // 2 is the number of significant digits in the decimal
466 FractionDigits = 2;
467 // 10 is the threshold between different decimal
468 } else if (number < 10) {
469 if (unitUsage == "size-shortfile-byte") {
470 FractionDigits = 1;
471 } else {
472 // 2 is the number of significant digits in the decimal
473 FractionDigits = 2;
474 }
475 } else {
476 if (unitUsage == "size-shortfile-byte") {
477 FractionDigits = 0;
478 } else {
479 // 2 is the number of significant digits in the decimal
480 FractionDigits = 2;
481 }
482 }
483 if (FractionDigits != -1) {
484 numberFormat = numberFormat.precision(icu::number::Precision::minMaxFraction(FractionDigits, FractionDigits));
485 }
486 }
487
GetCurrency() const488 std::string NumberFormat::GetCurrency() const
489 {
490 return currency;
491 }
492
GetCurrencySign() const493 std::string NumberFormat::GetCurrencySign() const
494 {
495 return currencySign;
496 }
497
GetStyle() const498 std::string NumberFormat::GetStyle() const
499 {
500 return styleString;
501 }
502
GetNumberingSystem() const503 std::string NumberFormat::GetNumberingSystem() const
504 {
505 return numberingSystem;
506 }
507
GetUseGrouping() const508 std::string NumberFormat::GetUseGrouping() const
509 {
510 return useGrouping;
511 }
512
GetMinimumIntegerDigits() const513 std::string NumberFormat::GetMinimumIntegerDigits() const
514 {
515 return minimumIntegerDigits;
516 }
517
GetMinimumFractionDigits() const518 std::string NumberFormat::GetMinimumFractionDigits() const
519 {
520 return minimumFractionDigits;
521 }
522
GetMaximumFractionDigits() const523 std::string NumberFormat::GetMaximumFractionDigits() const
524 {
525 return maximumFractionDigits;
526 }
527
GetMinimumSignificantDigits() const528 std::string NumberFormat::GetMinimumSignificantDigits() const
529 {
530 return minimumSignificantDigits;
531 }
532
GetMaximumSignificantDigits() const533 std::string NumberFormat::GetMaximumSignificantDigits() const
534 {
535 return maximumSignificantDigits;
536 }
537
GetLocaleMatcher() const538 std::string NumberFormat::GetLocaleMatcher() const
539 {
540 return localeMatcher;
541 }
542
Init()543 bool NumberFormat::Init()
544 {
545 SetHwIcuDirectory();
546 return true;
547 }
548
SetDefaultStyle()549 void NumberFormat::SetDefaultStyle()
550 {
551 char value[BUFFER_LEN];
552 int code = GetParameter(DEVICE_TYPE_NAME, "", value, BUFFER_LEN);
553 if (code > 0) {
554 std::string deviceType = value;
555 if (defaultUnitStyle.find(deviceType) != defaultUnitStyle.end()) {
556 unitDisplay = defaultUnitStyle[deviceType];
557 }
558 if (defaultCurrencyStyle.find(deviceType) != defaultCurrencyStyle.end()) {
559 currencyDisplay = defaultCurrencyStyle[deviceType];
560 }
561 }
562 }
563
ReadISO4217Ddatas()564 bool NumberFormat::ReadISO4217Ddatas()
565 {
566 if (numToCurrency.size()) {
567 return true;
568 }
569 UErrorCode status = U_ZERO_ERROR;
570 const char *currentCurrency;
571 UEnumeration *currencies = ucurr_openISOCurrencies(UCURR_ALL, &status);
572 if (U_FAILURE(status)) {
573 return false;
574 }
575
576 UChar code[CURRENCY_LEN + 1]; // +1 includes the NUL
577 int32_t length = 0;
578 while ((currentCurrency = uenum_next(currencies, &length, &status)) != NULL) {
579 u_charsToUChars(currentCurrency, code, length + 1); // +1 includes the NUL
580 int32_t numCode = ucurr_getNumericCode(code);
581 if (numCode == 0) {
582 continue;
583 }
584 std::stringstream ss;
585 ss << std::setw(CURRENCY_LEN) << std::setfill('0') << numCode; // fill with '0'
586 numToCurrency.insert(std::make_pair<std::string, std::string>(ss.str(), currentCurrency));
587 }
588 uenum_close(currencies);
589 return !numToCurrency.empty();
590 }
591
GetCurrencyFromConfig(const std::string & currency)592 std::string NumberFormat::GetCurrencyFromConfig(const std::string& currency)
593 {
594 if (currency.size() != CURRENCY_LEN) {
595 HILOG_ERROR_I18N("Invalid currency code : %{public}s", currency.c_str());
596 return "";
597 }
598 bool isAlpha = true;
599 for (auto c : currency) {
600 isAlpha = std::isalpha(c);
601 if (!isAlpha) {
602 break;
603 }
604 }
605 if (isAlpha) {
606 return currency;
607 }
608 if (ReadISO4217Ddatas() && numToCurrency.find(currency) != numToCurrency.end()) {
609 return numToCurrency[currency];
610 }
611 HILOG_ERROR_I18N("Invalid currency code : %{public}s", currency.c_str());
612 return "";
613 }
614 } // namespace I18n
615 } // namespace Global
616 } // namespace OHOS
617