From: Travis Keep Date: Thu, 30 Jan 2014 01:16:05 +0000 (+0000) Subject: ICU-10640 Change MeasureFormat to use QuantityFormatter. X-Git-Tag: milestone-59-0-1~2203 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=b50eda33411a142192c861a6652cfd7c6ce3d2d3;p=icu ICU-10640 Change MeasureFormat to use QuantityFormatter. X-SVN-Rev: 35030 --- 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 50ce7d14a2d..5e2550e6674 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 @@ -25,13 +25,13 @@ import java.util.Date; import java.util.EnumMap; import java.util.HashMap; import java.util.Map; -import java.util.Map.Entry; import java.util.MissingResourceException; import java.util.Set; import com.ibm.icu.impl.DontCareFieldPosition; import com.ibm.icu.impl.ICUResourceBundle; import com.ibm.icu.impl.SimpleCache; +import com.ibm.icu.impl.SimplePatternFormatter; import com.ibm.icu.util.Currency; import com.ibm.icu.util.CurrencyAmount; import com.ibm.icu.util.Measure; @@ -117,14 +117,14 @@ public class MeasureFormat extends UFormat { private final transient PluralRules rules; // Measure unit -> format width -> plural form -> pattern ("{0} meters") - private final transient Map>> unitToStyleToCountToFormat; + private final transient Map> unitToStyleToCountToFormat; private final transient NumericFormatters numericFormatters; private final transient ImmutableNumberFormat currencyFormat; - private static final SimpleCache>>> localeToUnitToStyleToCountToFormat - = new SimpleCache>>>(); + private static final SimpleCache>> localeToUnitToStyleToCountToFormat + = new SimpleCache>>(); private static final SimpleCache localeToNumericDurationFormatters = new SimpleCache(); @@ -234,7 +234,7 @@ public class MeasureFormat extends UFormat { */ public static MeasureFormat getInstance(ULocale locale, FormatWidth formatWidth, NumberFormat format) { PluralRules rules = PluralRules.forLocale(locale); - Map>> unitToStyleToCountToFormat; + Map> unitToStyleToCountToFormat; NumericFormatters formatters = null; unitToStyleToCountToFormat = localeToUnitToStyleToCountToFormat.get(locale); if (unitToStyleToCountToFormat == null) { @@ -482,7 +482,7 @@ public class MeasureFormat extends UFormat { FormatWidth formatWidth, ImmutableNumberFormat format, PluralRules rules, - Map>> unitToStyleToCountToFormat, + Map> unitToStyleToCountToFormat, NumericFormatters formatters, ImmutableNumberFormat currencyFormat) { setLocale(locale, locale); @@ -536,56 +536,38 @@ public class MeasureFormat extends UFormat { /** * Returns formatting data for all MeasureUnits except for currency ones. */ - private static Map>> loadLocaleData( + private static Map> loadLocaleData( ULocale locale, PluralRules rules) { - Set keywords = rules.getKeywords(); - Map>> unitToStyleToCountToFormat - = new HashMap>>(); + QuantityFormatter.Builder builder = new QuantityFormatter.Builder(); + Map> unitToStyleToCountToFormat + = new HashMap>(); ICUResourceBundle resource = (ICUResourceBundle)UResourceBundle.getBundleInstance(ICUResourceBundle.ICU_BASE_NAME, locale); for (MeasureUnit unit : MeasureUnit.getAvailable()) { // Currency data cannot be found here. Skip. if (unit instanceof Currency) { continue; } - EnumMap> styleToCountToFormat = unitToStyleToCountToFormat.get(unit); + EnumMap styleToCountToFormat = unitToStyleToCountToFormat.get(unit); if (styleToCountToFormat == null) { - unitToStyleToCountToFormat.put(unit, styleToCountToFormat = new EnumMap>(FormatWidth.class)); + unitToStyleToCountToFormat.put(unit, styleToCountToFormat = new EnumMap(FormatWidth.class)); } for (FormatWidth styleItem : FormatWidth.values()) { try { ICUResourceBundle unitTypeRes = resource.getWithFallback(styleItem.resourceKey); ICUResourceBundle unitsRes = unitTypeRes.getWithFallback(unit.getType()); ICUResourceBundle oneUnitRes = unitsRes.getWithFallback(unit.getSubtype()); - Map countToFormat = styleToCountToFormat.get(styleItem); - if (countToFormat == null) { - styleToCountToFormat.put(styleItem, countToFormat = new HashMap()); - } - // TODO(rocketman): Seems like we should be iterating over the bundles in - // oneUnitRes instead of all the plural key words since most languages have - // just 1 or 2 forms. - for (String keyword : keywords) { + builder.reset(); + int len = oneUnitRes.getSize(); + for (int i = 0; i < len; i++) { UResourceBundle countBundle; try { - countBundle = oneUnitRes.get(keyword); + countBundle = oneUnitRes.get(i); } catch (MissingResourceException e) { continue; } - String pattern = countBundle.getString(); - // System.out.println(styleItem.resourceKey + "/" - // + unit.getType() + "/" - // + unit.getCode() + "/" - // + keyword + "=" + pattern); - PatternData format = new PatternData(pattern); - countToFormat.put(keyword, format); - // System.out.println(styleToCountToFormat); - } - // fill in 'other' for any missing values - PatternData other = countToFormat.get("other"); - for (String keyword : keywords) { - if (!countToFormat.containsKey(keyword)) { - countToFormat.put(keyword, other); - } + builder.add(countBundle.getKey(), countBundle.getString()); } + styleToCountToFormat.put(styleItem, builder.build()); } catch (MissingResourceException e) { continue; } @@ -593,7 +575,7 @@ public class MeasureFormat extends UFormat { // now fill in the holes fillin: if (styleToCountToFormat.size() != FormatWidth.values().length) { - Map fallback = styleToCountToFormat.get(FormatWidth.SHORT); + QuantityFormatter fallback = styleToCountToFormat.get(FormatWidth.SHORT); if (fallback == null) { fallback = styleToCountToFormat.get(FormatWidth.WIDE); } @@ -601,12 +583,9 @@ public class MeasureFormat extends UFormat { break fillin; // TODO use root } for (FormatWidth styleItem : FormatWidth.values()) { - Map countToFormat = styleToCountToFormat.get(styleItem); + QuantityFormatter countToFormat = styleToCountToFormat.get(styleItem); if (countToFormat == null) { - styleToCountToFormat.put(styleItem, countToFormat = new HashMap()); - for (Entry entry : fallback.entrySet()) { - countToFormat.put(entry.getKey(), entry.getValue()); - } + styleToCountToFormat.put(styleItem, fallback); } } } @@ -636,18 +615,18 @@ public class MeasureFormat extends UFormat { StringBuffer formattedNumber = numberFormat.format(n, new StringBuffer(), fpos); String keyword = rules.select(new PluralRules.FixedDecimal(n.doubleValue(), fpos.getCountVisibleFractionDigits(), fpos.getFractionDigits())); - Map> styleToCountToFormat = unitToStyleToCountToFormat.get(unit); - Map countToFormat = styleToCountToFormat.get(formatWidth); - PatternData messagePatternData = countToFormat.get(keyword); - appendTo.append(messagePatternData.prefix); - if (messagePatternData.suffix != null) { // there is a number (may not happen with, say, Arabic dual) + Map styleToCountToFormat = unitToStyleToCountToFormat.get(unit); + QuantityFormatter countToFormat = styleToCountToFormat.get(formatWidth); + SimplePatternFormatter formatter = countToFormat.getByVariant(keyword); + SimplePatternFormatter.Formatted result = formatter.formatValues(new Object[] {formattedNumber}); + appendTo.append(result.toString()); + int offset = result.getOffset(0); + if (offset != -1) { // there is a number (may not happen with, say, Arabic dual) // Fix field position if (fpos.getBeginIndex() != 0 || fpos.getEndIndex() != 0) { - fieldPosition.setBeginIndex(fpos.getBeginIndex() + messagePatternData.prefix.length()); - fieldPosition.setEndIndex(fpos.getEndIndex() + messagePatternData.prefix.length()); + fieldPosition.setBeginIndex(fpos.getBeginIndex() + offset); + fieldPosition.setEndIndex(fpos.getEndIndex() + offset); } - appendTo.append(formattedNumber); - appendTo.append(messagePatternData.suffix); } return appendTo; } diff --git a/icu4j/main/classes/core/src/com/ibm/icu/text/QuantityFormatter.java b/icu4j/main/classes/core/src/com/ibm/icu/text/QuantityFormatter.java index 9f04fc5aeac..af6e3fab273 100644 --- a/icu4j/main/classes/core/src/com/ibm/icu/text/QuantityFormatter.java +++ b/icu4j/main/classes/core/src/com/ibm/icu/text/QuantityFormatter.java @@ -82,12 +82,10 @@ class QuantityFormatter { * Builds the new QuantityFormatter and resets this Builder to its initial state. * @return the new QuantityFormatter object. * @throws IllegalStateException if no template is specified for the "other" variant. - * When throwing this exception, build() still resets this Builder to its initial - * state. + * When throwing this exception, build leaves this builder in its current state. */ public QuantityFormatter build() { if (templates == null || templates[0] == null) { - templates = null; throw new IllegalStateException("At least other variant must be set."); } QuantityFormatter result = new QuantityFormatter(templates); @@ -95,6 +93,15 @@ class QuantityFormatter { return result; } + /** + * Resets this builder to its intitial state. + */ + public Builder reset() { + templates = null; + return this; + + } + } private final SimplePatternFormatter[] templates; @@ -113,18 +120,27 @@ class QuantityFormatter { */ public String format(double quantity, NumberFormat numberFormat, PluralRules pluralRules) { String formatStr = numberFormat.format(quantity); - String variant; - if (numberFormat instanceof DecimalFormat) { - variant = pluralRules.select(((DecimalFormat) numberFormat).getFixedDecimal(quantity)); - } else { - variant = pluralRules.select(quantity); - } + String variant = computeVariant(quantity, numberFormat, pluralRules); return getByVariant(variant).format(formatStr); } - - private SimplePatternFormatter getByVariant(String variant) { + + /** + * Gets the SimplePatternFormatter for a particular variant. + * @param variant "zero", "one", "two", "few", "many", "other" + * @return the SimplePatternFormatter + */ + public SimplePatternFormatter getByVariant(String variant) { Integer idxObj = INDEX_MAP.get(variant); SimplePatternFormatter template = templates[idxObj == null ? 0 : idxObj.intValue()]; return template == null ? templates[0] : template; } + + private String computeVariant(double quantity, NumberFormat numberFormat, PluralRules pluralRules) { + if (numberFormat instanceof DecimalFormat) { + return pluralRules.select(((DecimalFormat) numberFormat).getFixedDecimal(quantity)); + } + return pluralRules.select(quantity); + } + + }