Add tests for "Fallback symbols displayed in formatted currency output when no currency is set in API" and for "Rounding behavior when no currency is set in API"

Description

This behavior difference was discovered between ICU4C and ICU4J.

Sample code, ICU4C:

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 #include "common.h" int main() { ErrorCode status; { LocalPointer<DecimalFormat> df(dynamic_cast<DecimalFormat*>( NumberFormat::createInstance("en", UNUM_CURRENCY, status))); UnicodeString result; df->format(1.23, result, status); std::cout << "symbol: " << result << std::endl; } { LocalPointer<DecimalFormat> df(dynamic_cast<DecimalFormat*>( NumberFormat::createInstance("en", UNUM_CURRENCY_ISO, status))); UnicodeString result; df->format(1.23, result, status); std::cout << "iso_code: " << result << std::endl; } { LocalPointer<DecimalFormat> df(dynamic_cast<DecimalFormat*>( NumberFormat::createInstance("en", UNUM_CURRENCY_PLURAL, status))); UnicodeString result; df->format(1.23, result, status); std::cout << "plural: " << result << std::endl; } { LocalPointer<DecimalFormat> df(dynamic_cast<DecimalFormat*>( NumberFormat::createInstance("en", UNUM_CURRENCY, status))); UnicodeString currencyCode = UnicodeString(df->getCurrency()); std::cout << "currency: \"" << currencyCode << "\"" << std::endl; } std::cout << u_errorName(status) << std::endl; u_cleanup(); return 0; }

ICU4J:

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 import java.text.ParsePosition; import com.ibm.icu.text.*; import com.ibm.icu.util.*; public class NoCurrencyBehavior { public static void main(String[] args) { DecimalFormatSymbols EN = DecimalFormatSymbols.getInstance(ULocale.ENGLISH); { DecimalFormat df = (DecimalFormat) NumberFormat.getInstance(ULocale.ENGLISH, NumberFormat.CURRENCYSTYLE); System.out.println("symbol: " + df.format(1.23)); } { DecimalFormat df = (DecimalFormat) NumberFormat.getInstance(ULocale.ENGLISH, NumberFormat.ISOCURRENCYSTYLE); System.out.println("iso_code: " + df.format(1.23)); } { DecimalFormat df = (DecimalFormat) NumberFormat.getInstance(ULocale.ENGLISH, NumberFormat.PLURALCURRENCYSTYLE); System.out.println("plural: " + df.format(1.23)); } { DecimalFormat df = (DecimalFormat) NumberFormat.getInstance(ULocale.ENGLISH, NumberFormat.CURRENCYSTYLE); System.out.print("currency: " + df.getCurrency()); } } }

Consensus opinion: we should use the unknown currency "XXX", like ICU4J and JDK are already doing in the ISO code format, with the following output:

1 2 3 4 XXX 1.23 XXX 1.23 1.23 (unknown currency) currency: XXX

The plural long-name string, "unknown currency", comes from locale data.

Follow up with CLDR to add the currency symbol.

In addition, one more behavior difference was discovered.

ICU4C sample code:

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 #include "common.h" int main() { ErrorCode status; const UChar pattern[] = {0xA4, u'0', u'.', u'#', u'#', 0}; const UChar XXX[] = {u'X', u'X', u'X', 0}; { DecimalFormat df(pattern, {"en", status}, status); UnicodeString result; df.format(1.1, result, status); std::cout << result << std::endl; } { DecimalFormat df(pattern, {"en", status}, status); df.setCurrency(XXX, status); UnicodeString result; df.format(1.1, result, status); std::cout << result << std::endl; } { LocalPointer<DecimalFormat> df(dynamic_cast<DecimalFormat*>( NumberFormat::createCurrencyInstance("en", status))); UnicodeString result; df->format(1.1, result, status); std::cout << result << std::endl; } std::cout << u_errorName(status) << std::endl; u_cleanup(); return 0; }

ICU4J:

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 import com.ibm.icu.text.*; import com.ibm.icu.util.*; public class RoundingNoCurrency { public static void main(String[] args) { { DecimalFormat df = new DecimalFormat("\u00A40.##", DecimalFormatSymbols.getInstance(ULocale.ENGLISH)); System.out.println(df.format(1.1)); } { DecimalFormat df = new DecimalFormat("\u00A40.##", DecimalFormatSymbols.getInstance(ULocale.ENGLISH)); df.setCurrency(Currency.getInstance("XXX")); System.out.println(df.format(1.1)); } { DecimalFormat df = (DecimalFormat) NumberFormat.getCurrencyInstance(ULocale.ENGLISH); System.out.println(df.format(1.1)); } } }

Consensus opinion: Since we should apply the default currency when no currency is set, as stated in row 10, we should also apply XXX's rounding rules, which are a fixed two fraction digits.

Desired output:

1 2 3 XXX 1.10 XXX 1.10 1.10 (unknown currency)

Status

Assignee

Shane Carr

Reporter

Shane Carr

Reviewer

Peter Edberg

Time Needed

Minutes

Start date

None

Components

Fix versions

Priority

major
Configure