ICU-10268 MeasureFormat to format currencies correctly.

X-SVN-Rev: 34860
This commit is contained in:
Travis Keep 2014-01-10 18:53:53 +00:00
parent 2b6a24aebc
commit b2f94a75a8
2 changed files with 80 additions and 11 deletions

View file

@ -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<MeasureUnit, EnumMap<FormatWidth, Map<String, PatternData>>> unitToStyleToCountToFormat;
private final transient NumericFormatters numericFormatters;
private final transient ImmutableNumberFormat currencyFormat;
private static final SimpleCache<ULocale,Map<MeasureUnit, EnumMap<FormatWidth, Map<String, PatternData>>>> localeToUnitToStyleToCountToFormat
= new SimpleCache<ULocale,Map<MeasureUnit, EnumMap<FormatWidth, Map<String, PatternData>>>>();
@ -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<MeasureUnit, EnumMap<FormatWidth, Map<String, PatternData>>> 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 extends Appendable> 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);

View file

@ -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);