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
28namespace OHOS {
29namespace Global {
30namespace I18n {
31const char* NumberFormat::DEVICE_TYPE_NAME = "const.product.devicetype";
32std::unordered_map<std::string, std::string> NumberFormat::numToCurrency = {};
33bool NumberFormat::icuInitialized = NumberFormat::Init();
34
35std::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
41std::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
48std::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
55std::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
62std::unordered_map<UMeasurementSystem, std::string> NumberFormat::measurementSystem = {
63    { UMeasurementSystem::UMS_SI, "SI" },
64    { UMeasurementSystem::UMS_US, "US" },
65    { UMeasurementSystem::UMS_UK, "UK" },
66};
67
68std::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
78std::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
84std::map<std::string, std::string> NumberFormat::RelativeTimeFormatConfigs = {
85    { "numeric", "auto" }
86};
87
88NumberFormat::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 (U_FAILURE(status)) {
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
139NumberFormat::~NumberFormat()
140{
141}
142
143void 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
152void 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
195void 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
236void 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
275void 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
321void 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
333std::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
383void 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
416void 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
455void 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
488std::string NumberFormat::GetCurrency() const
489{
490    return currency;
491}
492
493std::string NumberFormat::GetCurrencySign() const
494{
495    return currencySign;
496}
497
498std::string NumberFormat::GetStyle() const
499{
500    return styleString;
501}
502
503std::string NumberFormat::GetNumberingSystem() const
504{
505    return numberingSystem;
506}
507
508std::string NumberFormat::GetUseGrouping() const
509{
510    return useGrouping;
511}
512
513std::string NumberFormat::GetMinimumIntegerDigits() const
514{
515    return minimumIntegerDigits;
516}
517
518std::string NumberFormat::GetMinimumFractionDigits() const
519{
520    return minimumFractionDigits;
521}
522
523std::string NumberFormat::GetMaximumFractionDigits() const
524{
525    return maximumFractionDigits;
526}
527
528std::string NumberFormat::GetMinimumSignificantDigits() const
529{
530    return minimumSignificantDigits;
531}
532
533std::string NumberFormat::GetMaximumSignificantDigits() const
534{
535    return maximumSignificantDigits;
536}
537
538std::string NumberFormat::GetLocaleMatcher() const
539{
540    return localeMatcher;
541}
542
543bool NumberFormat::Init()
544{
545    SetHwIcuDirectory();
546    return true;
547}
548
549void 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
564bool 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        const UChar* currencyCode = code;
581        int32_t numCode = ucurr_getNumericCode(currencyCode);
582        if (numCode == 0) {
583            continue;
584        }
585        std::stringstream ss;
586        ss << std::setw(CURRENCY_LEN) << std::setfill('0') << numCode; // fill with '0'
587        numToCurrency.insert(std::make_pair<std::string, std::string>(ss.str(), currentCurrency));
588    }
589    uenum_close(currencies);
590    return !numToCurrency.empty();
591}
592
593std::string NumberFormat::GetCurrencyFromConfig(const std::string& currency)
594{
595    if (currency.size() != CURRENCY_LEN) {
596        HILOG_ERROR_I18N("Invalid currency code : %{public}s", currency.c_str());
597        return "";
598    }
599    bool isAlpha = true;
600    for (auto c : currency) {
601        isAlpha = std::isalpha(c);
602        if (!isAlpha) {
603            break;
604        }
605    }
606    if (isAlpha) {
607        return currency;
608    }
609    if (ReadISO4217Ddatas() && numToCurrency.find(currency) != numToCurrency.end()) {
610        return numToCurrency[currency];
611    }
612    HILOG_ERROR_I18N("Invalid currency code : %{public}s", currency.c_str());
613    return "";
614}
615} // namespace I18n
616} // namespace Global
617} // namespace OHOS
618