numparse_stringsegment.o numparse_unisets.o numparse_parsednumber.o \
numparse_impl.o numparse_symbols.o numparse_decimal.o numparse_scientific.o \
numparse_currency.o numparse_affixes.o numparse_compositions.o \
-number_mapper.o number_multiplier.o
+number_mapper.o number_multiplier.o number_currencysymbols.o
## Header files to install
CompactDecimalFormat::CompactDecimalFormat(const Locale& inLocale, UNumberCompactStyle style,
UErrorCode& status)
: DecimalFormat(new DecimalFormatSymbols(inLocale, status), status) {
+ if (U_FAILURE(status)) return;
// Minimal properties: let the non-shim code path do most of the logic for us.
fProperties->compactStyle = style;
fProperties->groupingSize = -2; // do not forward grouping information
UErrorCode& status)
: DecimalFormat(symbolsToAdopt, status) {
setPropertiesFromPattern(pattern, IGNORE_ROUNDING_IF_CURRENCY, status);
+ refreshFormatter(status);
}
DecimalFormat::DecimalFormat(const UnicodeString& pattern, DecimalFormatSymbols* symbolsToAdopt,
// The only time when this happens is during legacy deserialization.
return;
}
- Locale locale = getLocale(ULOC_ACTUAL_LOCALE, status);
- if (U_FAILURE(status)) {
- // Constructor
- locale = fSymbols->getLocale(ULOC_ACTUAL_LOCALE, status);
- }
- if (U_FAILURE(status)) {
- // Deserialization
- locale = fSymbols->getLocale();
- }
- if (U_FAILURE(status)) {
- return;
- }
+
+ // In C++, fSymbols is the source of truth for the locale.
+ Locale locale = fSymbols->getLocale();
fFormatter.adoptInsteadAndCheckErrorCode(
new LocalizedNumberFormatter(
--- /dev/null
+// © 2018 and later: Unicode, Inc. and others.
+// License & terms of use: http://www.unicode.org/copyright.html
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_FORMATTING && !UPRV_INCOMPLETE_CPP11_SUPPORT
+
+// Allow implicit conversion from char16_t* to UnicodeString for this file:
+// Helpful in toString methods and elsewhere.
+#define UNISTR_FROM_STRING_EXPLICIT
+
+#include "numparse_types.h"
+#include "number_currencysymbols.h"
+
+using namespace icu;
+using namespace icu::number;
+using namespace icu::number::impl;
+
+
+CurrencySymbols::CurrencySymbols(CurrencyUnit currency, const Locale& locale, UErrorCode& status)
+ : fCurrency(currency), fLocaleName(locale.getName(), status) {}
+
+UnicodeString CurrencySymbols::getNarrowCurrencySymbol(UErrorCode& status) const {
+ return loadSymbol(UCURR_NARROW_SYMBOL_NAME, status);
+}
+
+UnicodeString CurrencySymbols::loadSymbol(UCurrNameStyle selector, UErrorCode& status) const {
+ UBool ignoredIsChoiceFormatFillIn = FALSE;
+ int32_t symbolLen = 0;
+ const char16_t* symbol = ucurr_getName(
+ fCurrency.getISOCurrency(),
+ fLocaleName.data(),
+ selector,
+ &ignoredIsChoiceFormatFillIn,
+ &symbolLen,
+ &status);
+ // Readonly-aliasing char16_t* constructor:
+ return UnicodeString(TRUE, symbol, symbolLen);
+}
+
+UnicodeString CurrencySymbols::getPluralName(StandardPlural::Form plural, UErrorCode& status) const {
+ UBool isChoiceFormat = FALSE;
+ int32_t symbolLen = 0;
+ const char16_t* symbol = ucurr_getPluralName(
+ fCurrency.getISOCurrency(),
+ fLocaleName.data(),
+ &isChoiceFormat,
+ StandardPlural::getKeyword(plural),
+ &symbolLen,
+ &status);
+ // Readonly-aliasing char16_t* constructor:
+ return UnicodeString(TRUE, symbol, symbolLen);
+}
+
+
+CurrencyDataSymbols::CurrencyDataSymbols(CurrencyUnit currency, const Locale& locale, UErrorCode& status)
+ : CurrencySymbols(currency, locale, status) {}
+
+UnicodeString CurrencyDataSymbols::getCurrencySymbol(UErrorCode& status) const {
+ return loadSymbol(UCURR_SYMBOL_NAME, status);
+}
+
+UnicodeString CurrencyDataSymbols::getIntlCurrencySymbol(UErrorCode&) const {
+ // Readonly-aliasing char16_t* constructor:
+ return UnicodeString(TRUE, fCurrency.getISOCurrency(), 3);
+}
+
+
+CurrencyCustomSymbols::CurrencyCustomSymbols(CurrencyUnit currency, const Locale& locale,
+ const DecimalFormatSymbols& symbols, UErrorCode& status)
+ : CurrencySymbols(currency, locale, status) {
+ // Hit the data bundle if the DecimalFormatSymbols version is not custom.
+ // Note: the CurrencyDataSymbols implementation waits to hit the data bundle until requested.
+ if (symbols.isCustomCurrencySymbol()) {
+ fCurrencySymbol = symbols.getConstSymbol(DecimalFormatSymbols::kCurrencySymbol);
+ } else {
+ fCurrencySymbol = loadSymbol(UCURR_SYMBOL_NAME, status);
+ }
+ if (symbols.isCustomIntlCurrencySymbol()) {
+ fIntlCurrencySymbol = symbols.getConstSymbol(DecimalFormatSymbols::kIntlCurrencySymbol);
+ } else {
+ // UnicodeString copy constructor since we don't know about the lifetime of the CurrencyUnit
+ fIntlCurrencySymbol = UnicodeString(currency.getISOCurrency(), 3);
+ }
+}
+
+UnicodeString CurrencyCustomSymbols::getCurrencySymbol(UErrorCode&) const {
+ return fCurrencySymbol;
+}
+
+UnicodeString CurrencyCustomSymbols::getIntlCurrencySymbol(UErrorCode&) const {
+ return fIntlCurrencySymbol;
+}
+
+
+CurrencyUnit
+icu::number::impl::resolveCurrency(const DecimalFormatProperties& properties, const Locale& locale,
+ UErrorCode& status) {
+ if (!properties.currency.isNull()) {
+ return properties.currency.getNoError();
+ } else {
+ UErrorCode localStatus = U_ZERO_ERROR;
+ char16_t buf[4] = {};
+ ucurr_forLocale(locale.getName(), buf, 4, &localStatus);
+ if (U_SUCCESS(localStatus)) {
+ return CurrencyUnit(buf, status);
+ } else {
+ // Default currency (XXX)
+ return CurrencyUnit();
+ }
+ }
+}
+
+
+#endif /* #if !UCONFIG_NO_FORMATTING */
--- /dev/null
+// © 2018 and later: Unicode, Inc. and others.
+// License & terms of use: http://www.unicode.org/copyright.html
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_FORMATTING && !UPRV_INCOMPLETE_CPP11_SUPPORT
+#ifndef __SOURCE_NUMBER_CURRENCYSYMBOLS_H__
+#define __SOURCE_NUMBER_CURRENCYSYMBOLS_H__
+
+#include "numparse_types.h"
+#include "charstr.h"
+#include "number_decimfmtprops.h"
+
+U_NAMESPACE_BEGIN namespace number {
+namespace impl {
+
+
+class CurrencySymbols {
+ public:
+ CurrencySymbols() = default; // default constructor: leaves class in valid but undefined state
+
+ explicit CurrencySymbols(CurrencyUnit currency, const Locale& locale, UErrorCode& status);
+
+ virtual UnicodeString getCurrencySymbol(UErrorCode& status) const = 0;
+
+ virtual UnicodeString getIntlCurrencySymbol(UErrorCode& status) const = 0;
+
+ // Put narrow and plural symbols in the base class since there is no API for overriding them
+ UnicodeString getNarrowCurrencySymbol(UErrorCode& status) const;
+
+ UnicodeString getPluralName(StandardPlural::Form plural, UErrorCode& status) const;
+
+ protected:
+ CurrencyUnit fCurrency;
+ CharString fLocaleName;
+
+ UnicodeString loadSymbol(UCurrNameStyle selector, UErrorCode& status) const;
+};
+
+
+class CurrencyDataSymbols : public CurrencySymbols, public UMemory {
+ public:
+ CurrencyDataSymbols() = default; // default constructor: leaves class in valid but undefined state
+
+ CurrencyDataSymbols(CurrencyUnit currency, const Locale& locale, UErrorCode& status);
+
+ UnicodeString getCurrencySymbol(UErrorCode& status) const U_OVERRIDE;
+
+ UnicodeString getIntlCurrencySymbol(UErrorCode& status) const U_OVERRIDE;
+};
+
+
+class CurrencyCustomSymbols : public CurrencySymbols, public UMemory {
+ public:
+ CurrencyCustomSymbols() = default; // default constructor: leaves class in valid but undefined state
+
+ CurrencyCustomSymbols(CurrencyUnit currency, const Locale& locale, const DecimalFormatSymbols& symbols,
+ UErrorCode& status);
+
+ UnicodeString getCurrencySymbol(UErrorCode& status) const U_OVERRIDE;
+
+ UnicodeString getIntlCurrencySymbol(UErrorCode& status) const U_OVERRIDE;
+
+ private:
+ UnicodeString fCurrencySymbol;
+ UnicodeString fIntlCurrencySymbol;
+};
+
+
+/**
+ * Resolves the effective currency from the property bag.
+ */
+CurrencyUnit
+resolveCurrency(const DecimalFormatProperties& properties, const Locale& locale, UErrorCode& status);
+
+
+} // namespace impl
+} // namespace numparse
+U_NAMESPACE_END
+
+#endif //__SOURCE_NUMBER_CURRENCYSYMBOLS_H__
+#endif /* #if !UCONFIG_NO_FORMATTING */
CurrencyFormatInfoResult
getCurrencyFormatInfo(const Locale& locale, const char* isoCode, UErrorCode& status) {
// TODO: Load this data in a centralized location like ICU4J?
+ // TODO: Move this into the CurrencySymbols class?
// TODO: Parts of this same data are loaded in dcfmtsym.cpp; should clean up.
CurrencyFormatInfoResult result = {false, nullptr, nullptr, nullptr};
if (U_FAILURE(status)) { return result; }
if (isCurrency) {
currency = CurrencyUnit(macros.unit, status); // Restore CurrencyUnit from MeasureUnit
}
+ CurrencySymbols* currencySymbols;
+ if (macros.currencySymbols != nullptr) {
+ // Used by the DecimalFormat code path
+ currencySymbols = macros.currencySymbols;
+ } else {
+ fWarehouse.fCurrencyDataSymbols = {currency, macros.locale, status};
+ currencySymbols = &fWarehouse.fCurrencyDataSymbols;
+ }
UNumberUnitWidth unitWidth = UNUM_UNIT_WIDTH_SHORT;
if (macros.unitWidth != UNUM_UNIT_WIDTH_COUNT) {
unitWidth = macros.unitWidth;
if (patternModifier->needsPlurals()) {
patternModifier->setSymbols(
fMicros.symbols,
- currency,
+ currencySymbols,
unitWidth,
resolvePluralRules(macros.rules, macros.locale, status));
} else {
- patternModifier->setSymbols(fMicros.symbols, currency, unitWidth, nullptr);
+ patternModifier->setSymbols(fMicros.symbols, currencySymbols, unitWidth, nullptr);
}
if (safe) {
fImmutablePatternModifier.adoptInstead(patternModifier->createImmutableAndChain(chain, status));
MicroProps fMicros;
// Other fields possibly used by the number formatting pipeline:
- // TODO: Convert some of these LocalPointers to value objects to reduce the number of news?
+ // TODO: Convert more of these LocalPointers to value objects to reduce the number of news?
LocalPointer<const DecimalFormatSymbols> fSymbols;
LocalPointer<const PluralRules> fRules;
LocalPointer<const ParsedPatternInfo> fPatternInfo;
LocalPointer<const LongNameHandler> fLongNameHandler;
LocalPointer<const CompactHandler> fCompactHandler;
+ // Value objects possibly used by the number formatting pipeline:
+ struct Warehouse {
+ CurrencyDataSymbols fCurrencyDataSymbols;
+ } fWarehouse;
+
NumberFormatterImpl(const MacroProps ¯os, bool safe, UErrorCode &status);
#include "number_patternstring.h"
#include "unicode/errorcode.h"
#include "number_utils.h"
+#include "number_currencysymbols.h"
using namespace icu;
using namespace icu::number;
bool useCurrency = (
!properties.currency.isNull() || !properties.currencyPluralInfo.fPtr.isNull() ||
!properties.currencyUsage.isNull() || affixProvider->hasCurrencySign());
- // TODO: CustomSymbolCurrency
- CurrencyUnit currency = {u"USD", status};
+ CurrencyUnit currency = resolveCurrency(properties, locale, status);
UCurrencyUsage currencyUsage = properties.currencyUsage.getOrDefault(UCURR_USAGE_STANDARD);
if (useCurrency) {
// NOTE: Slicing is OK.
macros.unit = currency; // NOLINT
}
+ if (symbols.isCustomCurrencySymbol() || symbols.isCustomIntlCurrencySymbol()) {
+ warehouse.currencyCustomSymbols = {currency, locale, symbols, status};
+ macros.currencySymbols = &warehouse.currencyCustomSymbols;
+ }
///////////////////////
// ROUNDING STRATEGY //
#include "unicode/currpinf.h"
#include "standardplural.h"
#include "number_patternstring.h"
+#include "number_currencysymbols.h"
U_NAMESPACE_BEGIN namespace number {
namespace impl {
struct DecimalFormatWarehouse {
PropertiesAffixPatternProvider propertiesAPP;
CurrencyPluralInfoAffixProvider currencyPluralInfoAPP;
+ CurrencyCustomSymbols currencyCustomSymbols;
};
this->perMilleReplacesPercent = perMille;
}
-void MutablePatternModifier::setSymbols(const DecimalFormatSymbols* symbols, const CurrencyUnit& currency,
+void MutablePatternModifier::setSymbols(const DecimalFormatSymbols* symbols,
+ const CurrencySymbols* currencySymbols,
const UNumberUnitWidth unitWidth, const PluralRules* rules) {
U_ASSERT((rules != nullptr) == needsPlurals());
this->symbols = symbols;
- uprv_memcpy(static_cast<char16_t*>(this->currencyCode),
- currency.getISOCurrency(),
- sizeof(char16_t) * 4);
+ this->currencySymbols = currencySymbols;
this->unitWidth = unitWidth;
this->rules = rules;
}
}
UnicodeString MutablePatternModifier::getSymbol(AffixPatternType type) const {
+ UErrorCode localStatus = U_ZERO_ERROR;
switch (type) {
case AffixPatternType::TYPE_MINUS_SIGN:
return symbols->getSymbol(DecimalFormatSymbols::ENumberFormatSymbol::kMinusSignSymbol);
case AffixPatternType::TYPE_CURRENCY_SINGLE: {
// UnitWidth ISO and HIDDEN overrides the singular currency symbol.
if (unitWidth == UNumberUnitWidth::UNUM_UNIT_WIDTH_ISO_CODE) {
- return UnicodeString(currencyCode, 3);
+ return currencySymbols->getIntlCurrencySymbol(localStatus);
} else if (unitWidth == UNumberUnitWidth::UNUM_UNIT_WIDTH_HIDDEN) {
return UnicodeString();
+ } else if (unitWidth == UNumberUnitWidth::UNUM_UNIT_WIDTH_NARROW) {
+ return currencySymbols->getNarrowCurrencySymbol(localStatus);
} else {
- UCurrNameStyle selector = (unitWidth == UNumberUnitWidth::UNUM_UNIT_WIDTH_NARROW)
- ? UCurrNameStyle::UCURR_NARROW_SYMBOL_NAME
- : UCurrNameStyle::UCURR_SYMBOL_NAME;
- UErrorCode status = U_ZERO_ERROR;
- UBool isChoiceFormat = FALSE;
- int32_t symbolLen = 0;
- const char16_t* symbol = ucurr_getName(
- currencyCode,
- symbols->getLocale().getName(),
- selector,
- &isChoiceFormat,
- &symbolLen,
- &status);
- return UnicodeString(symbol, symbolLen);
+ return currencySymbols->getCurrencySymbol(localStatus);
}
}
case AffixPatternType::TYPE_CURRENCY_DOUBLE:
- return UnicodeString(currencyCode, 3);
- case AffixPatternType::TYPE_CURRENCY_TRIPLE: {
+ return currencySymbols->getIntlCurrencySymbol(localStatus);
+ case AffixPatternType::TYPE_CURRENCY_TRIPLE:
// NOTE: This is the code path only for patterns containing "¤¤¤".
// Plural currencies set via the API are formatted in LongNameHandler.
// This code path is used by DecimalFormat via CurrencyPluralInfo.
U_ASSERT(plural != StandardPlural::Form::COUNT);
- UErrorCode status = U_ZERO_ERROR;
- UBool isChoiceFormat = FALSE;
- int32_t symbolLen = 0;
- const char16_t* symbol = ucurr_getPluralName(
- currencyCode,
- symbols->getLocale().getName(),
- &isChoiceFormat,
- StandardPlural::getKeyword(plural),
- &symbolLen,
- &status);
- return UnicodeString(symbol, symbolLen);
- }
+ return currencySymbols->getPluralName(plural, localStatus);
case AffixPatternType::TYPE_CURRENCY_QUAD:
return UnicodeString(u"\uFFFD");
case AffixPatternType::TYPE_CURRENCY_QUINT:
#include "number_types.h"
#include "number_modifiers.h"
#include "number_utils.h"
+#include "number_currencysymbols.h"
U_NAMESPACE_BEGIN
*
* @param symbols
* The desired instance of DecimalFormatSymbols.
- * @param currency
- * The currency to be used when substituting currency values into the affixes.
+ * @param currencySymbols
+ * The currency symbols to be used when substituting currency values into the affixes.
* @param unitWidth
* The width used to render currencies.
* @param rules
* Required if the triple currency sign, "¤¤¤", appears in the pattern, which can be determined from the
* convenience method {@link #needsPlurals()}.
*/
- void
- setSymbols(const DecimalFormatSymbols *symbols, const CurrencyUnit ¤cy, UNumberUnitWidth unitWidth,
- const PluralRules *rules);
+ void setSymbols(const DecimalFormatSymbols* symbols, const CurrencySymbols* currencySymbols,
+ UNumberUnitWidth unitWidth, const PluralRules* rules);
/**
* Sets attributes of the current number being processed.
// Symbol details (initialized in setSymbols)
const DecimalFormatSymbols *symbols;
UNumberUnitWidth unitWidth;
- char16_t currencyCode[4];
+ const CurrencySymbols *currencySymbols;
const PluralRules *rules;
// Number details (initialized in setNumberProperties)
mod.setPatternInfo(&patternInfo);
mod.setPatternAttributes(UNUM_SIGN_AUTO, false);
DecimalFormatSymbols symbols(Locale::getEnglish(), status);
- CurrencyUnit currency(u"USD", status);
+ CurrencyDataSymbols currencySymbols({u"USD", status}, "en", status);
assertSuccess("Spot 2", status);
- mod.setSymbols(&symbols, currency, UNUM_UNIT_WIDTH_SHORT, nullptr);
+ mod.setSymbols(&symbols, ¤cySymbols, UNUM_UNIT_WIDTH_SHORT, nullptr);
mod.setNumberProperties(1, StandardPlural::Form::COUNT);
assertEquals("Pattern a0b", u"a", getPrefix(mod, status));
mod.setPatternInfo(&patternInfo);
mod.setPatternAttributes(UNUM_SIGN_AUTO, false);
DecimalFormatSymbols symbols(Locale::getEnglish(), status);
- CurrencyUnit currency(u"USD", status);
+ CurrencyDataSymbols currencySymbols({u"USD", status}, "en", status);
assertSuccess("Spot 2", status);
- mod.setSymbols(&symbols, currency, UNUM_UNIT_WIDTH_SHORT, nullptr);
+ mod.setSymbols(&symbols, ¤cySymbols, UNUM_UNIT_WIDTH_SHORT, nullptr);
mod.setNumberProperties(1, StandardPlural::Form::COUNT);
// Unsafe Code Path
mod.setPatternInfo(&patternInfo);
mod.setPatternAttributes(UNUM_SIGN_AUTO, false);
DecimalFormatSymbols symbols(Locale::getEnglish(), status);
- CurrencyUnit currency(u"USD", status);
+ CurrencyDataSymbols currencySymbols({u"USD", status}, "en", status);
assertSuccess("Spot 2", status);
if (U_FAILURE(status)) { return; }
- mod.setSymbols(&symbols, currency, UNUM_UNIT_WIDTH_SHORT, nullptr);
+ mod.setSymbols(&symbols, ¤cySymbols, UNUM_UNIT_WIDTH_SHORT, nullptr);
DecimalQuantity fq;
fq.setToInt(1);
UnicodeString s; currencyFmt->format(1.50, s);
logln((UnicodeString)"Un pauvre ici a..........." + s);
if (!(s==CharsToUnicodeString("1,50\\u00A0$")))
- errln((UnicodeString)"FAIL: Expected 1,50<nbsp>$");
+ errln((UnicodeString)"FAIL: Expected 1,50<nbsp>$ but got " + s);
delete currencyFmt;
s.truncate(0);
char loc[256]={0};
currencyFmt->format(1.50, s);
logln((UnicodeString)"Un pauvre en Allemagne a.." + s);
if (!(s==CharsToUnicodeString("1,50\\u00A0DM")))
- errln((UnicodeString)"FAIL: Expected 1,50<nbsp>DM");
+ errln((UnicodeString)"FAIL: Expected 1,50<nbsp>DM but got " + s);
delete currencyFmt;
s.truncate(0);
len = uloc_canonicalize("fr_FR_PREEURO", loc, 256, &status);