ICU-20484 Narrow currency symbol should fall back to short symbol, C and J.
- Includes fixes to tests.
diff --git a/icu4c/source/common/ucurr.cpp b/icu4c/source/common/ucurr.cpp
index 7871601..802eafb 100644
--- a/icu4c/source/common/ucurr.cpp
+++ b/icu4c/source/common/ucurr.cpp
@@ -690,7 +690,13 @@
key.append("/", ec2);
key.append(buf, ec2);
s = ures_getStringByKeyWithFallback(rb.getAlias(), key.data(), len, &ec2);
- } else {
+ if (ec2 == U_MISSING_RESOURCE_ERROR) {
+ *ec = U_USING_FALLBACK_WARNING;
+ ec2 = U_ZERO_ERROR;
+ choice = UCURR_SYMBOL_NAME;
+ }
+ }
+ if (s == NULL) {
ures_getByKey(rb.getAlias(), CURRENCIES, rb.getAlias(), &ec2);
ures_getByKeyWithFallback(rb.getAlias(), buf, rb.getAlias(), &ec2);
s = ures_getStringByIndex(rb.getAlias(), choice, len, &ec2);
diff --git a/icu4c/source/test/intltest/numbertest_api.cpp b/icu4c/source/test/intltest/numbertest_api.cpp
index 2d925ee..f27292f 100644
--- a/icu4c/source/test/intltest/numbertest_api.cpp
+++ b/icu4c/source/test/intltest/numbertest_api.cpp
@@ -779,7 +779,7 @@
NumberFormatter::with().unit(PTE).unitWidth(UNUM_UNIT_WIDTH_NARROW),
Locale("pt-PT"),
444444.55,
- u"444,444$55 PTE");
+ u"444,444$55 \u200B");
assertFormatSingle(
u"Currency-dependent symbols (Test ISO Code)",
diff --git a/icu4c/source/test/intltest/numfmtst.cpp b/icu4c/source/test/intltest/numfmtst.cpp
index 26ae404..4625b13 100644
--- a/icu4c/source/test/intltest/numfmtst.cpp
+++ b/icu4c/source/test/intltest/numfmtst.cpp
@@ -123,6 +123,7 @@
TESTCASE_AUTO(TestCases);
TESTCASE_AUTO(TestCurrencyNames);
+ TESTCASE_AUTO(Test20484_NarrowSymbolFallback);
TESTCASE_AUTO(TestCurrencyAmount);
TESTCASE_AUTO(TestCurrencyUnit);
TESTCASE_AUTO(TestCoverage);
@@ -2097,6 +2098,50 @@
// TODO add more tests later
}
+void NumberFormatTest::Test20484_NarrowSymbolFallback(){
+ IcuTestErrorCode status(*this, "Test20484_NarrowSymbolFallback");
+
+ struct TestCase {
+ const char* locale;
+ const char16_t* isoCode;
+ const char16_t* expectedShort;
+ const char16_t* expectedNarrow;
+ UErrorCode expectedNarrowError;
+ } cases[] = {
+ {"en-US", u"CAD", u"CA$", u"$", U_USING_DEFAULT_WARNING}, // narrow: fallback to root
+ {"en-US", u"CDF", u"CDF", u"CDF", U_USING_FALLBACK_WARNING}, // narrow: fallback to short
+ {"sw-CD", u"CDF", u"FC", u"FC", U_USING_FALLBACK_WARNING}, // narrow: fallback to short
+ {"en-US", u"GEL", u"GEL", u"₾", U_USING_DEFAULT_WARNING}, // narrow: fallback to root
+ {"ka-GE", u"GEL", u"₾", u"₾", U_USING_FALLBACK_WARNING}, // narrow: fallback to ka
+ {"ka", u"GEL", u"₾", u"₾", U_ZERO_ERROR}, // no fallback on narrow
+ };
+ for (const auto& cas : cases) {
+ status.setScope(cas.isoCode);
+ UBool choiceFormatIgnored;
+ int32_t lengthIgnored;
+ const UChar* actualShort = ucurr_getName(
+ cas.isoCode,
+ cas.locale,
+ UCURR_SYMBOL_NAME,
+ &choiceFormatIgnored,
+ &lengthIgnored,
+ status);
+ status.errIfFailureAndReset();
+ const UChar* actualNarrow = ucurr_getName(
+ cas.isoCode,
+ cas.locale,
+ UCURR_NARROW_SYMBOL_NAME,
+ &choiceFormatIgnored,
+ &lengthIgnored,
+ status);
+ status.expectErrorAndReset(cas.expectedNarrowError);
+ assertEquals(UnicodeString("Short symbol: ") + cas.locale + u": " + cas.isoCode,
+ cas.expectedShort, actualShort);
+ assertEquals(UnicodeString("Narrow symbol: ") + cas.locale + ": " + cas.isoCode,
+ cas.expectedNarrow, actualNarrow);
+ }
+}
+
void NumberFormatTest::TestCurrencyUnit(void){
UErrorCode ec = U_ZERO_ERROR;
static const UChar USD[] = u"USD";
diff --git a/icu4c/source/test/intltest/numfmtst.h b/icu4c/source/test/intltest/numfmtst.h
index 0451067..b62cde5 100644
--- a/icu4c/source/test/intltest/numfmtst.h
+++ b/icu4c/source/test/intltest/numfmtst.h
@@ -153,6 +153,8 @@
void TestCurrencyNames(void);
+ void Test20484_NarrowSymbolFallback(void);
+
void TestCurrencyAmount(void);
void TestCurrencyUnit(void);
diff --git a/icu4j/main/classes/core/src/com/ibm/icu/text/CurrencyDisplayNames.java b/icu4j/main/classes/core/src/com/ibm/icu/text/CurrencyDisplayNames.java
index 9bdd00d..21297aa 100644
--- a/icu4j/main/classes/core/src/com/ibm/icu/text/CurrencyDisplayNames.java
+++ b/icu4j/main/classes/core/src/com/ibm/icu/text/CurrencyDisplayNames.java
@@ -122,8 +122,8 @@
/**
* Returns the narrow symbol for the currency with the provided ISO code.
- * If there is no data for narrow symbol, substitutes isoCode, or returns
- * null if noSubstitute was set in the factory method.
+ * If there is no data for narrow symbol, substitutes the default symbol,
+ * or returns null if noSubstitute was set in the factory method.
*
* @param isoCode the three-letter ISO code.
* @return the narrow symbol.
diff --git a/icu4j/main/classes/currdata/src/com/ibm/icu/impl/ICUCurrencyDisplayInfoProvider.java b/icu4j/main/classes/currdata/src/com/ibm/icu/impl/ICUCurrencyDisplayInfoProvider.java
index b0fe8de..9fb70c5 100644
--- a/icu4j/main/classes/currdata/src/com/ibm/icu/impl/ICUCurrencyDisplayInfoProvider.java
+++ b/icu4j/main/classes/currdata/src/com/ibm/icu/impl/ICUCurrencyDisplayInfoProvider.java
@@ -95,7 +95,7 @@
/**
* Cache for symbolMap() and nameMap().
*/
- private volatile SoftReference<ParsingData> parsingDataCache = new SoftReference<ParsingData>(null);
+ private volatile SoftReference<ParsingData> parsingDataCache = new SoftReference<>(null);
/**
* Cache for getUnitPatterns().
@@ -124,8 +124,8 @@
}
static class ParsingData {
- Map<String, String> symbolToIsoCode = new HashMap<String, String>();
- Map<String, String> nameToIsoCode = new HashMap<String, String>();
+ Map<String, String> symbolToIsoCode = new HashMap<>();
+ Map<String, String> nameToIsoCode = new HashMap<>();
}
////////////////////////
@@ -170,9 +170,8 @@
NarrowSymbol narrowSymbol = fetchNarrowSymbol(isoCode);
// Fall back to ISO Code
- // TODO: Should this fall back to the regular symbol instead of the ISO code?
if (narrowSymbol.narrowSymbol == null && fallback) {
- return isoCode;
+ return getSymbol(isoCode);
}
return narrowSymbol.narrowSymbol;
}
@@ -289,7 +288,7 @@
CurrencySink sink = new CurrencySink(!fallback, CurrencySink.EntrypointTable.TOP);
sink.parsingData = result;
rb.getAllItemsWithFallback("", sink);
- parsingDataCache = new SoftReference<ParsingData>(result);
+ parsingDataCache = new SoftReference<>(result);
}
return result;
}
@@ -297,7 +296,7 @@
Map<String, String> fetchUnitPatterns() {
Map<String, String> result = unitPatternsCache;
if (result == null) {
- result = new HashMap<String, String>();
+ result = new HashMap<>();
CurrencySink sink = new CurrencySink(!fallback, CurrencySink.EntrypointTable.CURRENCY_UNIT_PATTERNS);
sink.unitPatterns = result;
rb.getAllItemsWithFallback("CurrencyUnitPatterns", sink);
diff --git a/icu4j/main/tests/core/src/com/ibm/icu/dev/test/number/NumberFormatterApiTest.java b/icu4j/main/tests/core/src/com/ibm/icu/dev/test/number/NumberFormatterApiTest.java
index 69f3e6b..3d655af 100644
--- a/icu4j/main/tests/core/src/com/ibm/icu/dev/test/number/NumberFormatterApiTest.java
+++ b/icu4j/main/tests/core/src/com/ibm/icu/dev/test/number/NumberFormatterApiTest.java
@@ -741,7 +741,7 @@
NumberFormatter.with().unit(PTE).unitWidth(UnitWidth.NARROW),
ULocale.forLanguageTag("pt-PT"),
444444.55,
- "444,444$55 PTE");
+ "444,444$55 \u200B");
assertFormatSingle(
"Currency-dependent symbols (Test)",
diff --git a/icu4j/main/tests/core/src/com/ibm/icu/dev/test/util/CurrencyTest.java b/icu4j/main/tests/core/src/com/ibm/icu/dev/test/util/CurrencyTest.java
index 0e8de68..7c8a3cc 100644
--- a/icu4j/main/tests/core/src/com/ibm/icu/dev/test/util/CurrencyTest.java
+++ b/icu4j/main/tests/core/src/com/ibm/icu/dev/test/util/CurrencyTest.java
@@ -239,6 +239,30 @@
}
@Test
+ public void test20484_NarrowSymbolFallback() {
+ Object[][] cases = new Object[][] {
+ {"en-US", "CAD", "CA$", "$"},
+ {"en-US", "CDF", "CDF", "CDF"},
+ {"sw-CD", "CDF", "FC", "FC"},
+ {"en-US", "GEL", "GEL", "₾"},
+ {"ka-GE", "GEL", "₾", "₾"},
+ {"ka", "GEL", "₾", "₾"},
+ };
+ for (Object[] cas : cases) {
+ ULocale locale = new ULocale((String) cas[0]);
+ String isoCode = (String) cas[1];
+ String expectedShort = (String) cas[2];
+ String expectedNarrow = (String) cas[3];
+
+ CurrencyDisplayNames cdn = CurrencyDisplayNames.getInstance(locale);
+ assertEquals("Short symbol: " + locale + ": " + isoCode,
+ expectedShort, cdn.getSymbol(isoCode));
+ assertEquals("Narrow symbol: " + locale + ": " + isoCode,
+ expectedNarrow, cdn.getNarrowSymbol(isoCode));
+ }
+ }
+
+ @Test
public void testGetName_Locale_Int_String_BooleanArray() {
Currency currency = Currency.getInstance(ULocale.CHINA);
boolean[] isChoiceFormat = new boolean[1];