From: Travis Keep Date: Fri, 10 Jan 2014 18:53:53 +0000 (+0000) Subject: ICU-10268 MeasureFormat to format currencies correctly. X-Git-Tag: milestone-59-0-1~2286 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=b2f94a75a8ca68e5119a40f96b4934a0f8656df1;p=icu ICU-10268 MeasureFormat to format currencies correctly. X-SVN-Rev: 34860 --- diff --git a/icu4j/main/classes/core/src/com/ibm/icu/text/MeasureFormat.java b/icu4j/main/classes/core/src/com/ibm/icu/text/MeasureFormat.java index 85bee39a52d..d8cb676cdf2 100644 --- a/icu4j/main/classes/core/src/com/ibm/icu/text/MeasureFormat.java +++ b/icu4j/main/classes/core/src/com/ibm/icu/text/MeasureFormat.java @@ -32,6 +32,7 @@ import com.ibm.icu.impl.DontCareFieldPosition; import com.ibm.icu.impl.ICUResourceBundle; import com.ibm.icu.impl.SimpleCache; import com.ibm.icu.util.Currency; +import com.ibm.icu.util.CurrencyAmount; import com.ibm.icu.util.Measure; import com.ibm.icu.util.MeasureUnit; import com.ibm.icu.util.TimeZone; @@ -110,6 +111,8 @@ public class MeasureFormat extends UFormat { private final transient Map>> unitToStyleToCountToFormat; private final transient NumericFormatters numericFormatters; + + private final transient ImmutableNumberFormat currencyFormat; private static final SimpleCache>>> localeToUnitToStyleToCountToFormat = new SimpleCache>>>(); @@ -137,7 +140,7 @@ public class MeasureFormat extends UFormat { * @draft ICU 53 * @provisional */ - // Be sure to update the toFormatWidth and fromFormatWidth() functions + // Be sure to update MeasureUnitTest.TestSerialFormatWidthEnum // when adding an enum value. public enum FormatWidth { @@ -147,7 +150,7 @@ public class MeasureFormat extends UFormat { * @draft ICU 53 * @provisional */ - WIDE("units", ListFormatter.Style.DURATION), + WIDE("units", ListFormatter.Style.DURATION, NumberFormat.PLURALCURRENCYSTYLE), /** * Abbreviate when possible. @@ -155,7 +158,7 @@ public class MeasureFormat extends UFormat { * @draft ICU 53 * @provisional */ - SHORT("unitsShort", ListFormatter.Style.DURATION_SHORT), + SHORT("unitsShort", ListFormatter.Style.DURATION_SHORT, NumberFormat.ISOCURRENCYSTYLE), /** * Brief. Use only a symbol for the unit when possible. @@ -163,7 +166,7 @@ public class MeasureFormat extends UFormat { * @draft ICU 53 * @provisional */ - NARROW("unitsNarrow", ListFormatter.Style.DURATION_SHORT), + NARROW("unitsNarrow", ListFormatter.Style.DURATION_SHORT, NumberFormat.CURRENCYSTYLE), /** * Identical to NARROW except when formatMeasures is called with @@ -173,22 +176,28 @@ public class MeasureFormat extends UFormat { * @draft ICU 53 * @provisional */ - NUMERIC("unitsNarrow", ListFormatter.Style.DURATION_SHORT); + NUMERIC("unitsNarrow", ListFormatter.Style.DURATION_SHORT, NumberFormat.CURRENCYSTYLE); // Be sure to update the toFormatWidth and fromFormatWidth() functions // when adding an enum value. final String resourceKey; private final ListFormatter.Style listFormatterStyle; + private final int currencyStyle; - private FormatWidth(String resourceKey, ListFormatter.Style style) { + private FormatWidth(String resourceKey, ListFormatter.Style style, int currencyStyle) { this.resourceKey = resourceKey; this.listFormatterStyle = style; + this.currencyStyle = currencyStyle; } ListFormatter.Style getListFormatterStyle() { return listFormatterStyle; } + + int getCurrencyStyle() { + return currencyStyle; + } } /** @@ -230,13 +239,16 @@ public class MeasureFormat extends UFormat { localeToNumericDurationFormatters.put(locale, formatters); } } + return new MeasureFormat( locale, formatWidth, new ImmutableNumberFormat(format), rules, unitToStyleToCountToFormat, - formatters); + formatters, + new ImmutableNumberFormat( + NumberFormat.getInstance(locale, formatWidth.getCurrencyStyle()))); } /** @@ -463,7 +475,8 @@ public class MeasureFormat extends UFormat { new ImmutableNumberFormat(format), this.rules, this.unitToStyleToCountToFormat, - this.numericFormatters); + this.numericFormatters, + this.currencyFormat); } private MeasureFormat( @@ -472,13 +485,15 @@ public class MeasureFormat extends UFormat { ImmutableNumberFormat format, PluralRules rules, Map>> unitToStyleToCountToFormat, - NumericFormatters formatters) { + NumericFormatters formatters, + ImmutableNumberFormat currencyFormat) { setLocale(locale, locale); this.formatWidth = formatWidth; this.numberFormat = format; this.rules = rules; this.unitToStyleToCountToFormat = unitToStyleToCountToFormat; this.numericFormatters = formatters; + this.currencyFormat = currencyFormat; } MeasureFormat() { @@ -488,6 +503,7 @@ public class MeasureFormat extends UFormat { this.rules = null; this.unitToStyleToCountToFormat = null; this.numericFormatters = null; + this.currencyFormat = null; } static class NumericFormatters { @@ -608,8 +624,20 @@ public class MeasureFormat extends UFormat { private T formatMeasure( Measure measure, T appendable, FieldPosition fieldPosition) { + if (measure.getUnit() instanceof Currency) { + try { + appendable.append( + currencyFormat.format( + new CurrencyAmount(measure.getNumber(), (Currency) measure.getUnit()), + new StringBuffer(), + fieldPosition)); + return appendable; + } catch (IOException e) { + throw new RuntimeException(e); + } + } Number n = measure.getNumber(); - MeasureUnit unit = measure.getUnit(); + MeasureUnit unit = measure.getUnit(); UFieldPosition fpos = new UFieldPosition(fieldPosition.getFieldAttribute(), fieldPosition.getField()); StringBuffer formattedNumber = numberFormat.format(n, new StringBuffer(), fpos); String keyword = rules.select(new PluralRules.FixedDecimal(n.doubleValue(), fpos.getCountVisibleFractionDigits(), fpos.getFractionDigits())); @@ -650,6 +678,11 @@ public class MeasureFormat extends UFormat { Number n, StringBuffer buffer, FieldPosition pos) { return nf.format(n, buffer, pos); } + + public synchronized StringBuffer format( + CurrencyAmount n, StringBuffer buffer, FieldPosition pos) { + return nf.format(n, buffer, pos); + } public synchronized String format(Number number) { return nf.format(number); diff --git a/icu4j/main/tests/core/src/com/ibm/icu/dev/test/format/MeasureUnitTest.java b/icu4j/main/tests/core/src/com/ibm/icu/dev/test/format/MeasureUnitTest.java index e09aec1a5bf..cb1902ac9dd 100644 --- a/icu4j/main/tests/core/src/com/ibm/icu/dev/test/format/MeasureUnitTest.java +++ b/icu4j/main/tests/core/src/com/ibm/icu/dev/test/format/MeasureUnitTest.java @@ -122,6 +122,13 @@ public class MeasureUnitTest extends TestFmwk { {_0h_0m_17s, "0:00:17"}, {_6h_56_92m, "6:56.92"}, {_3h_5h, "3h, 5h"}}; + Object[][] fullDataDe = { + {_1m_59_9996s, "1 Minute und 59.9996 Sekunden"}, + {_19m, "19 Minuten"}, + {_1h_23_5s, "1 Stunde und 23.5 Sekunden"}, + {_1h_23_5m, "1 Stunde und 23.5 Minuten"}, + {_1h_0m_23s, "1 Stunde, 0 Minuten und 23 Sekunden"}, + {_2y_5M_3w_4d, "2 Jahre, 5 Monate, 3 Wochen und 4 Tage"}}; NumberFormat nf = NumberFormat.getNumberInstance(ULocale.ENGLISH); nf.setMaximumFractionDigits(4); @@ -130,7 +137,9 @@ public class MeasureUnitTest extends TestFmwk { mf = MeasureFormat.getInstance(ULocale.ENGLISH, FormatWidth.SHORT, nf); verifyFormatPeriod("en SHORT", mf, abbrevData); mf = MeasureFormat.getInstance(ULocale.ENGLISH, FormatWidth.NUMERIC, nf); - verifyFormatPeriod("en NUMERIC", mf, numericData); + verifyFormatPeriod("en NUMERIC", mf, numericData); + mf = MeasureFormat.getInstance(ULocale.GERMAN, FormatWidth.WIDE, nf); + verifyFormatPeriod("de FULL", mf, fullDataDe); } @@ -215,6 +224,33 @@ public class MeasureUnitTest extends TestFmwk { "1 G", mf.format(new Measure(1, MeasureUnit.G_FORCE))); } + + public void testCurrencies() { + Measure USD_1 = new Measure(1.0, Currency.getInstance("USD")); + Measure USD_2 = new Measure(2.0, Currency.getInstance("USD")); + Measure USD_NEG_1 = new Measure(-1.0, Currency.getInstance("USD")); + MeasureFormat mf = MeasureFormat.getInstance(ULocale.ENGLISH, FormatWidth.WIDE); + assertEquals("Wide currency", "-1.00 US dollars", mf.format(USD_NEG_1)); + assertEquals("Wide currency", "1.00 US dollars", mf.format(USD_1)); + assertEquals("Wide currency", "2.00 US dollars", mf.format(USD_2)); + mf = MeasureFormat.getInstance(ULocale.ENGLISH, FormatWidth.SHORT); + assertEquals("short currency", "-USD1.00", mf.format(USD_NEG_1)); + assertEquals("short currency", "USD1.00", mf.format(USD_1)); + assertEquals("short currency", "USD2.00", mf.format(USD_2)); + mf = MeasureFormat.getInstance(ULocale.ENGLISH, FormatWidth.NARROW); + assertEquals("narrow currency", "-$1.00", mf.format(USD_NEG_1)); + assertEquals("narrow currency", "$1.00", mf.format(USD_1)); + assertEquals("narrow currency", "$2.00", mf.format(USD_2)); + mf = MeasureFormat.getInstance(ULocale.ENGLISH, FormatWidth.NUMERIC); + assertEquals("numeric currency", "-$1.00", mf.format(USD_NEG_1)); + assertEquals("numeric currency", "$1.00", mf.format(USD_1)); + assertEquals("numeric currency", "$2.00", mf.format(USD_2)); + + mf = MeasureFormat.getInstance(ULocale.JAPAN, FormatWidth.WIDE); + assertEquals("Wide currency", "-1.00 \u7C73\u30C9\u30EB", mf.format(USD_NEG_1)); + assertEquals("Wide currency", "1.00 \u7C73\u30C9\u30EB", mf.format(USD_1)); + assertEquals("Wide currency", "2.00 \u7C73\u30C9\u30EB", mf.format(USD_2)); + } public void testExamples() { MeasureFormat fmtFr = MeasureFormat.getInstance(ULocale.FRENCH, FormatWidth.SHORT);