ICU-20923 Fix compact notation with percent.
diff --git a/icu4c/source/i18n/number_formatimpl.cpp b/icu4c/source/i18n/number_formatimpl.cpp
index e6b1c5b..875f71b 100644
--- a/icu4c/source/i18n/number_formatimpl.cpp
+++ b/icu4c/source/i18n/number_formatimpl.cpp
@@ -133,6 +133,7 @@
bool isBaseUnit = utils::unitIsBaseUnit(macros.unit);
bool isPercent = utils::unitIsPercent(macros.unit);
bool isPermille = utils::unitIsPermille(macros.unit);
+ bool isCompactNotation = macros.notation.fType == Notation::NTN_COMPACT;
bool isAccounting =
macros.sign == UNUM_SIGN_ACCOUNTING || macros.sign == UNUM_SIGN_ACCOUNTING_ALWAYS ||
macros.sign == UNUM_SIGN_ACCOUNTING_EXCEPT_ZERO;
@@ -144,8 +145,18 @@
if (macros.unitWidth != UNUM_UNIT_WIDTH_COUNT) {
unitWidth = macros.unitWidth;
}
- bool isCldrUnit = !isCurrency && !isBaseUnit &&
- (unitWidth == UNUM_UNIT_WIDTH_FULL_NAME || !(isPercent || isPermille));
+ // Use CLDR unit data for all MeasureUnits (not currency and not
+ // no-unit), except use the dedicated percent pattern for percent and
+ // permille. However, use the CLDR unit data for percent/permille if a
+ // long name was requested OR if compact notation is being used, since
+ // compact notation overrides the middle modifier (micros.modMiddle)
+ // normally used for the percent pattern.
+ bool isCldrUnit = !isCurrency
+ && !isBaseUnit
+ && (unitWidth == UNUM_UNIT_WIDTH_FULL_NAME
+ || !(isPercent || isPermille)
+ || isCompactNotation
+ );
// Select the numbering system.
LocalPointer<const NumberingSystem> nsLocal;
@@ -232,7 +243,7 @@
Precision precision;
if (!macros.precision.isBogus()) {
precision = macros.precision;
- } else if (macros.notation.fType == Notation::NTN_COMPACT) {
+ } else if (isCompactNotation) {
precision = Precision::integer().withMinDigits(2);
} else if (isCurrency) {
precision = Precision::currency(UCURR_USAGE_STANDARD);
@@ -254,7 +265,7 @@
// Grouping strategy
if (!macros.grouper.isBogus()) {
fMicros.grouping = macros.grouper;
- } else if (macros.notation.fType == Notation::NTN_COMPACT) {
+ } else if (isCompactNotation) {
// Compact notation uses minGrouping by default since ICU 59
fMicros.grouping = Grouper::forStrategy(UNUM_GROUPING_MIN2);
} else {
@@ -366,7 +377,7 @@
}
// Compact notation
- if (macros.notation.fType == Notation::NTN_COMPACT) {
+ if (isCompactNotation) {
CompactType compactType = (isCurrency && unitWidth != UNUM_UNIT_WIDTH_FULL_NAME)
? CompactType::TYPE_CURRENCY : CompactType::TYPE_DECIMAL;
auto newCompactHandler = new CompactHandler(
diff --git a/icu4c/source/test/intltest/numbertest_api.cpp b/icu4c/source/test/intltest/numbertest_api.cpp
index 75b0d00..b0e1015 100644
--- a/icu4c/source/test/intltest/numbertest_api.cpp
+++ b/icu4c/source/test/intltest/numbertest_api.cpp
@@ -1014,6 +1014,65 @@
-98.7654321,
u"-98.765432%");
+ // ICU-20923
+ assertFormatDescendingBig(
+ u"Compact Percent",
+ u"compact-short percent",
+ u"K %",
+ NumberFormatter::with()
+ .notation(Notation::compactShort())
+ .unit(NoUnit::percent()),
+ Locale::getEnglish(),
+ u"88M%",
+ u"8.8M%",
+ u"876K%",
+ u"88K%",
+ u"8.8K%",
+ u"876%",
+ u"88%",
+ u"8.8%",
+ u"0%");
+
+ // ICU-20923
+ assertFormatDescendingBig(
+ u"Compact Percent with Scale",
+ u"compact-short percent scale/100",
+ u"K %x100",
+ NumberFormatter::with()
+ .notation(Notation::compactShort())
+ .unit(NoUnit::percent())
+ .scale(Scale::powerOfTen(2)),
+ Locale::getEnglish(),
+ u"8.8B%",
+ u"876M%",
+ u"88M%",
+ u"8.8M%",
+ u"876K%",
+ u"88K%",
+ u"8.8K%",
+ u"876%",
+ u"0%");
+
+ // ICU-20923
+ assertFormatDescendingBig(
+ u"Compact Percent Long Name",
+ u"compact-short percent unit-width-full-name",
+ u"K % unit-width-full-name",
+ NumberFormatter::with()
+ .notation(Notation::compactShort())
+ .unit(NoUnit::percent())
+ .unitWidth(UNUM_UNIT_WIDTH_FULL_NAME),
+ Locale::getEnglish(),
+ u"88M percent",
+ u"8.8M percent",
+ u"876K percent",
+ u"88K percent",
+ u"8.8K percent",
+ u"876 percent",
+ u"88 percent",
+ u"8.8 percent",
+ u"0 percent");
+
assertFormatSingle(
u"Per Percent",
u"measure-unit/length-meter per-measure-unit/concentr-percent unit-width-full-name",
diff --git a/icu4c/source/test/intltest/numbertest_permutation.cpp b/icu4c/source/test/intltest/numbertest_permutation.cpp
index 85f32d5..a96dd75 100644
--- a/icu4c/source/test/intltest/numbertest_permutation.cpp
+++ b/icu4c/source/test/intltest/numbertest_permutation.cpp
@@ -71,7 +71,11 @@
* Test permutations of 3 orthogonal skeleton parts from the list above.
* Compare the results against the golden data file:
* numberpermutationtest.txt
- * To regenerate that file, run intltest with the -G option.
+ * To regenerate that file, run intltest with the -e and -G options.
+ * On Linux, from icu4c/source:
+ * make -j8 tests && (cd test/intltest && LD_LIBRARY_PATH=../../lib:../../tools/ctestfw ./intltest -e -G format/NumberTest/NumberPermutationTest)
+ * After re-generating the file, copy it into icu4j:
+ * cp test/testdata/numberpermutationtest.txt ../../icu4j/main/tests/core/src/com/ibm/icu/dev/data/numberpermutationtest.txt
*/
void NumberPermutationTest::testPermutations() {
IcuTestErrorCode status(*this, "testPermutations");
diff --git a/icu4c/source/test/testdata/numberpermutationtest.txt b/icu4c/source/test/testdata/numberpermutationtest.txt
index e5f0b78..b63df7d 100644
--- a/icu4c/source/test/testdata/numberpermutationtest.txt
+++ b/icu4c/source/test/testdata/numberpermutationtest.txt
@@ -4,15 +4,15 @@
compact-short percent unit-width-narrow
es-MX
0 %
- 92 k
+ 92 k %
-0.22 %
zh-TW
0%
- 9.2萬
+ 9.2萬%
-0.22%
bn-BD
০%
- ৯২ হা
+ ৯২ হা%
-০.২২%
compact-short percent unit-width-full-name
@@ -172,57 +172,57 @@
compact-short percent precision-integer
es-MX
0 %
- 92 k
+ 92 k %
-0 %
zh-TW
0%
- 9萬
+ 9萬%
-0%
bn-BD
০%
- ৯২ হা
+ ৯২ হা%
-০%
compact-short percent .000
es-MX
0.000 %
- 91.827 k
+ 91.827 k %
-0.222 %
zh-TW
0.000%
- 9.183萬
+ 9.183萬%
-0.222%
bn-BD
০.০০০%
- ৯১.৮২৭ হা
+ ৯১.৮২৭ হা%
-০.২২২%
compact-short percent .##/@@@+
es-MX
0 %
- 91.83 k
+ 91.83 k %
-0.222 %
zh-TW
0%
- 9.18萬
+ 9.18萬%
-0.222%
bn-BD
০%
- ৯১.৮৩ হা
+ ৯১.৮৩ হা%
-০.২২২%
compact-short percent @@
es-MX
0.0 %
- 92 k
+ 92 k %
-0.22 %
zh-TW
0.0%
- 9.2萬
+ 9.2萬%
-0.22%
bn-BD
০.০%
- ৯২ হা
+ ৯২ হা%
-০.২২%
compact-short currency/EUR precision-integer
@@ -508,15 +508,15 @@
compact-short percent rounding-mode-floor
es-MX
0 %
- 91 k
+ 91 k %
-0.23 %
zh-TW
0%
- 9.1萬
+ 9.1萬%
-0.23%
bn-BD
০%
- ৯১ হা
+ ৯১ হা%
-০.২৩%
compact-short currency/EUR rounding-mode-floor
@@ -592,15 +592,15 @@
compact-short percent integer-width/##00
es-MX
00 %
- 92 k
+ 92 k %
-00.22 %
zh-TW
00%
- 09.2萬
+ 09.2萬%
-00.22%
bn-BD
০০%
- ৯২ হা
+ ৯২ হা%
-০০.২২%
compact-short currency/EUR integer-width/##00
@@ -676,15 +676,15 @@
compact-short percent scale/0.5
es-MX
0 %
- 46 k
+ 46 k %
-0.11 %
zh-TW
0%
- 4.6萬
+ 4.6萬%
-0.11%
bn-BD
০%
- ৪৬ হা
+ ৪৬ হা%
-০.১১%
compact-short currency/EUR scale/0.5
@@ -760,15 +760,15 @@
compact-short percent group-on-aligned
es-MX
0 %
- 92 k
+ 92 k %
-0.22 %
zh-TW
0%
- 9.2萬
+ 9.2萬%
-0.22%
bn-BD
০%
- ৯২ হা
+ ৯২ হা%
-০.২২%
compact-short currency/EUR group-on-aligned
@@ -844,15 +844,15 @@
compact-short percent latin
es-MX
0 %
- 92 k
+ 92 k %
-0.22 %
zh-TW
0%
- 9.2萬
+ 9.2萬%
-0.22%
bn-BD
0%
- 92 হা
+ 92 হা%
-0.22%
compact-short currency/EUR latin
@@ -928,15 +928,15 @@
compact-short percent sign-accounting-except-zero
es-MX
0 %
- +92 k
+ +92 k %
-0.22 %
zh-TW
0%
- +9.2萬
+ +9.2萬%
-0.22%
bn-BD
০%
- +৯২ হা
+ +৯২ হা%
-০.২২%
compact-short currency/EUR sign-accounting-except-zero
@@ -1012,15 +1012,15 @@
compact-short percent decimal-always
es-MX
0. %
- 92. k
+ 92. k %
-0.22 %
zh-TW
0.%
- 9.2萬
+ 9.2萬%
-0.22%
bn-BD
০.%
- ৯২. হা
+ ৯২. হা%
-০.২২%
compact-short currency/EUR decimal-always
diff --git a/icu4j/main/classes/core/src/com/ibm/icu/number/NumberFormatterImpl.java b/icu4j/main/classes/core/src/com/ibm/icu/number/NumberFormatterImpl.java
index 629732e..fa483ef 100644
--- a/icu4j/main/classes/core/src/com/ibm/icu/number/NumberFormatterImpl.java
+++ b/icu4j/main/classes/core/src/com/ibm/icu/number/NumberFormatterImpl.java
@@ -182,6 +182,7 @@
boolean isBaseUnit = unitIsBaseUnit(macros.unit);
boolean isPercent = unitIsPercent(macros.unit);
boolean isPermille = unitIsPermille(macros.unit);
+ boolean isCompactNotation = (macros.notation instanceof CompactNotation);
boolean isAccounting = macros.sign == SignDisplay.ACCOUNTING
|| macros.sign == SignDisplay.ACCOUNTING_ALWAYS
|| macros.sign == SignDisplay.ACCOUNTING_EXCEPT_ZERO;
@@ -190,8 +191,18 @@
if (macros.unitWidth != null) {
unitWidth = macros.unitWidth;
}
- boolean isCldrUnit = !isCurrency && !isBaseUnit &&
- (unitWidth == UnitWidth.FULL_NAME || !(isPercent || isPermille));
+ // Use CLDR unit data for all MeasureUnits (not currency and not
+ // no-unit), except use the dedicated percent pattern for percent and
+ // permille. However, use the CLDR unit data for percent/permille if a
+ // long name was requested OR if compact notation is being used, since
+ // compact notation overrides the middle modifier (micros.modMiddle)
+ // normally used for the percent pattern.
+ boolean isCldrUnit = !isCurrency
+ && !isBaseUnit
+ && (unitWidth == UnitWidth.FULL_NAME
+ || !(isPercent || isPermille)
+ || isCompactNotation
+ );
PluralRules rules = macros.rules;
// Select the numbering system.
@@ -252,7 +263,7 @@
// Rounding strategy
if (macros.precision != null) {
micros.rounder = macros.precision;
- } else if (macros.notation instanceof CompactNotation) {
+ } else if (isCompactNotation) {
micros.rounder = Precision.COMPACT_STRATEGY;
} else if (isCurrency) {
micros.rounder = Precision.MONETARY_STANDARD;
@@ -270,7 +281,7 @@
micros.grouping = (Grouper) macros.grouping;
} else if (macros.grouping instanceof GroupingStrategy) {
micros.grouping = Grouper.forStrategy((GroupingStrategy) macros.grouping);
- } else if (macros.notation instanceof CompactNotation) {
+ } else if (isCompactNotation) {
// Compact notation uses minGrouping by default since ICU 59
micros.grouping = Grouper.forStrategy(GroupingStrategy.MIN2);
} else {
@@ -356,7 +367,7 @@
}
// Compact notation
- if (macros.notation instanceof CompactNotation) {
+ if (isCompactNotation) {
if (rules == null) {
// Lazily create PluralRules
rules = PluralRules.forLocale(macros.loc);
diff --git a/icu4j/main/tests/core/src/com/ibm/icu/dev/data/numberpermutationtest.txt b/icu4j/main/tests/core/src/com/ibm/icu/dev/data/numberpermutationtest.txt
index e5f0b78..b63df7d 100644
--- a/icu4j/main/tests/core/src/com/ibm/icu/dev/data/numberpermutationtest.txt
+++ b/icu4j/main/tests/core/src/com/ibm/icu/dev/data/numberpermutationtest.txt
@@ -4,15 +4,15 @@
compact-short percent unit-width-narrow
es-MX
0 %
- 92 k
+ 92 k %
-0.22 %
zh-TW
0%
- 9.2萬
+ 9.2萬%
-0.22%
bn-BD
০%
- ৯২ হা
+ ৯২ হা%
-০.২২%
compact-short percent unit-width-full-name
@@ -172,57 +172,57 @@
compact-short percent precision-integer
es-MX
0 %
- 92 k
+ 92 k %
-0 %
zh-TW
0%
- 9萬
+ 9萬%
-0%
bn-BD
০%
- ৯২ হা
+ ৯২ হা%
-০%
compact-short percent .000
es-MX
0.000 %
- 91.827 k
+ 91.827 k %
-0.222 %
zh-TW
0.000%
- 9.183萬
+ 9.183萬%
-0.222%
bn-BD
০.০০০%
- ৯১.৮২৭ হা
+ ৯১.৮২৭ হা%
-০.২২২%
compact-short percent .##/@@@+
es-MX
0 %
- 91.83 k
+ 91.83 k %
-0.222 %
zh-TW
0%
- 9.18萬
+ 9.18萬%
-0.222%
bn-BD
০%
- ৯১.৮৩ হা
+ ৯১.৮৩ হা%
-০.২২২%
compact-short percent @@
es-MX
0.0 %
- 92 k
+ 92 k %
-0.22 %
zh-TW
0.0%
- 9.2萬
+ 9.2萬%
-0.22%
bn-BD
০.০%
- ৯২ হা
+ ৯২ হা%
-০.২২%
compact-short currency/EUR precision-integer
@@ -508,15 +508,15 @@
compact-short percent rounding-mode-floor
es-MX
0 %
- 91 k
+ 91 k %
-0.23 %
zh-TW
0%
- 9.1萬
+ 9.1萬%
-0.23%
bn-BD
০%
- ৯১ হা
+ ৯১ হা%
-০.২৩%
compact-short currency/EUR rounding-mode-floor
@@ -592,15 +592,15 @@
compact-short percent integer-width/##00
es-MX
00 %
- 92 k
+ 92 k %
-00.22 %
zh-TW
00%
- 09.2萬
+ 09.2萬%
-00.22%
bn-BD
০০%
- ৯২ হা
+ ৯২ হা%
-০০.২২%
compact-short currency/EUR integer-width/##00
@@ -676,15 +676,15 @@
compact-short percent scale/0.5
es-MX
0 %
- 46 k
+ 46 k %
-0.11 %
zh-TW
0%
- 4.6萬
+ 4.6萬%
-0.11%
bn-BD
০%
- ৪৬ হা
+ ৪৬ হা%
-০.১১%
compact-short currency/EUR scale/0.5
@@ -760,15 +760,15 @@
compact-short percent group-on-aligned
es-MX
0 %
- 92 k
+ 92 k %
-0.22 %
zh-TW
0%
- 9.2萬
+ 9.2萬%
-0.22%
bn-BD
০%
- ৯২ হা
+ ৯২ হা%
-০.২২%
compact-short currency/EUR group-on-aligned
@@ -844,15 +844,15 @@
compact-short percent latin
es-MX
0 %
- 92 k
+ 92 k %
-0.22 %
zh-TW
0%
- 9.2萬
+ 9.2萬%
-0.22%
bn-BD
0%
- 92 হা
+ 92 হা%
-0.22%
compact-short currency/EUR latin
@@ -928,15 +928,15 @@
compact-short percent sign-accounting-except-zero
es-MX
0 %
- +92 k
+ +92 k %
-0.22 %
zh-TW
0%
- +9.2萬
+ +9.2萬%
-0.22%
bn-BD
০%
- +৯২ হা
+ +৯২ হা%
-০.২২%
compact-short currency/EUR sign-accounting-except-zero
@@ -1012,15 +1012,15 @@
compact-short percent decimal-always
es-MX
0. %
- 92. k
+ 92. k %
-0.22 %
zh-TW
0.%
- 9.2萬
+ 9.2萬%
-0.22%
bn-BD
০.%
- ৯২. হা
+ ৯২. হা%
-০.২২%
compact-short currency/EUR decimal-always
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 d3bbc13..73df02c 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
@@ -967,6 +967,65 @@
-98.7654321,
"-98.765432%");
+ // ICU-20923
+ assertFormatDescendingBig(
+ "Compact Percent",
+ "compact-short percent",
+ "K %",
+ NumberFormatter.with()
+ .notation(Notation.compactShort())
+ .unit(NoUnit.PERCENT),
+ ULocale.ENGLISH,
+ "88M%",
+ "8.8M%",
+ "876K%",
+ "88K%",
+ "8.8K%",
+ "876%",
+ "88%",
+ "8.8%",
+ "0%");
+
+ // ICU-20923
+ assertFormatDescendingBig(
+ "Compact Percent with Scale",
+ "compact-short percent scale/100",
+ "K %x100",
+ NumberFormatter.with()
+ .notation(Notation.compactShort())
+ .unit(NoUnit.PERCENT)
+ .scale(Scale.powerOfTen(2)),
+ ULocale.ENGLISH,
+ "8.8B%",
+ "876M%",
+ "88M%",
+ "8.8M%",
+ "876K%",
+ "88K%",
+ "8.8K%",
+ "876%",
+ "0%");
+
+ // ICU-20923
+ assertFormatDescendingBig(
+ "Compact Percent Long Name",
+ "compact-short percent unit-width-full-name",
+ "K % unit-width-full-name",
+ NumberFormatter.with()
+ .notation(Notation.compactShort())
+ .unit(NoUnit.PERCENT)
+ .unitWidth(UnitWidth.FULL_NAME),
+ ULocale.ENGLISH,
+ "88M percent",
+ "8.8M percent",
+ "876K percent",
+ "88K percent",
+ "8.8K percent",
+ "876 percent",
+ "88 percent",
+ "8.8 percent",
+ "0 percent");
+
assertFormatSingle(
"Per Percent",
"measure-unit/length-meter per-measure-unit/concentr-percent unit-width-full-name",