mirror of
https://github.com/unicode-org/icu.git
synced 2025-04-08 06:53:45 +00:00
ICU-12030 MeasureFormat handle by-plural-form sideways-aliasing, by not bundling plural forms into a QuantityFormatter, reintegrate from ^/icu4j/branches/markus/sideways
X-SVN-Rev: 38122
This commit is contained in:
parent
ad6035c5c2
commit
fa027da0f7
6 changed files with 256 additions and 222 deletions
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
*******************************************************************************
|
||||
* Copyright (C) 2014, International Business Machines Corporation and *
|
||||
* others. All Rights Reserved. *
|
||||
* Copyright (C) 2014-2015, International Business Machines Corporation and
|
||||
* others. All Rights Reserved.
|
||||
*******************************************************************************
|
||||
*/
|
||||
package com.ibm.icu.impl;
|
||||
|
@ -55,6 +55,17 @@ public class SimplePatternFormatter {
|
|||
* @return the new SimplePatternFormatter object.
|
||||
*/
|
||||
public static SimplePatternFormatter compile(String pattern) {
|
||||
return compileMinMaxPlaceholders(pattern, 0, Integer.MAX_VALUE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Compiles a string.
|
||||
* @param pattern The string.
|
||||
* @param min The pattern must have at least this many placeholders.
|
||||
* @param max The pattern must have at most this many placeholders.
|
||||
* @return the new SimplePatternFormatter object.
|
||||
*/
|
||||
public static SimplePatternFormatter compileMinMaxPlaceholders(String pattern, int min, int max) {
|
||||
PlaceholdersBuilder placeholdersBuilder = new PlaceholdersBuilder();
|
||||
PlaceholderIdBuilder idBuilder = new PlaceholderIdBuilder();
|
||||
StringBuilder newPattern = new StringBuilder();
|
||||
|
@ -113,8 +124,15 @@ public class SimplePatternFormatter {
|
|||
default:
|
||||
throw new IllegalStateException();
|
||||
}
|
||||
if (placeholdersBuilder.getPlaceholderCount() < min) {
|
||||
throw new IllegalArgumentException(
|
||||
"Fewer than minimum " + min + " placeholders in pattern \"" + pattern + "\"");
|
||||
}
|
||||
if (placeholdersBuilder.getPlaceholderCount() > max) {
|
||||
throw new IllegalArgumentException(
|
||||
"More than maximum " + max + " placeholders in pattern \"" + pattern + "\"");
|
||||
}
|
||||
return new SimplePatternFormatter(newPattern.toString(), placeholdersBuilder);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/*
|
||||
*******************************************************************************
|
||||
* Copyright (C) 2012-2014, Google, International Business Machines Corporation and
|
||||
* Copyright (C) 2012-2015, Google, International Business Machines Corporation and
|
||||
* others. All Rights Reserved.
|
||||
*******************************************************************************
|
||||
*/
|
||||
|
@ -9,10 +9,8 @@ package com.ibm.icu.text;
|
|||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
|
||||
import com.ibm.icu.impl.ICUCache;
|
||||
import com.ibm.icu.impl.ICUResourceBundle;
|
||||
|
@ -109,14 +107,13 @@ final public class ListFormatter {
|
|||
@Deprecated
|
||||
public ListFormatter(String two, String start, String middle, String end) {
|
||||
this(
|
||||
SimplePatternFormatter.compile(two),
|
||||
SimplePatternFormatter.compile(start),
|
||||
SimplePatternFormatter.compile(middle),
|
||||
SimplePatternFormatter.compile(end),
|
||||
compilePattern(two),
|
||||
compilePattern(start),
|
||||
compilePattern(middle),
|
||||
compilePattern(end),
|
||||
null);
|
||||
|
||||
}
|
||||
|
||||
|
||||
private ListFormatter(SimplePatternFormatter two, SimplePatternFormatter start, SimplePatternFormatter middle, SimplePatternFormatter end, ULocale locale) {
|
||||
this.two = two;
|
||||
this.start = start;
|
||||
|
@ -125,6 +122,10 @@ final public class ListFormatter {
|
|||
this.locale = locale;
|
||||
}
|
||||
|
||||
private static SimplePatternFormatter compilePattern(String pattern) {
|
||||
return SimplePatternFormatter.compileMinMaxPlaceholders(pattern, 2, 2);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a list formatter that is appropriate for a locale.
|
||||
*
|
||||
|
@ -301,16 +302,6 @@ final public class ListFormatter {
|
|||
}
|
||||
}
|
||||
|
||||
/** JUST FOR DEVELOPMENT */
|
||||
// For use with the hard-coded data
|
||||
// TODO Replace by use of RB
|
||||
// Verify in building that all of the patterns contain {0}, {1}.
|
||||
|
||||
static Map<ULocale, ListFormatter> localeToData = new HashMap<ULocale, ListFormatter>();
|
||||
static void add(String locale, String...data) {
|
||||
localeToData.put(new ULocale(locale), new ListFormatter(data[0], data[1], data[2], data[3]));
|
||||
}
|
||||
|
||||
private static class Cache {
|
||||
private final ICUCache<String, ListFormatter> cache =
|
||||
new SimpleCache<String, ListFormatter>();
|
||||
|
@ -330,10 +321,10 @@ final public class ListFormatter {
|
|||
getBundleInstance(ICUResourceBundle.ICU_BASE_NAME, ulocale);
|
||||
|
||||
return new ListFormatter(
|
||||
SimplePatternFormatter.compile(r.getWithFallback("listPattern/" + style + "/2").getString()),
|
||||
SimplePatternFormatter.compile(r.getWithFallback("listPattern/" + style + "/start").getString()),
|
||||
SimplePatternFormatter.compile(r.getWithFallback("listPattern/" + style + "/middle").getString()),
|
||||
SimplePatternFormatter.compile(r.getWithFallback("listPattern/" + style + "/end").getString()),
|
||||
compilePattern(r.getWithFallback("listPattern/" + style + "/2").getString()),
|
||||
compilePattern(r.getWithFallback("listPattern/" + style + "/start").getString()),
|
||||
compilePattern(r.getWithFallback("listPattern/" + style + "/middle").getString()),
|
||||
compilePattern(r.getWithFallback("listPattern/" + style + "/end").getString()),
|
||||
ulocale);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -448,8 +448,8 @@ public class MeasureFormat extends UFormat {
|
|||
// FieldPosition pos2 = new FieldPosition(0);
|
||||
// currencyFormat.format(currencyHigh, buffer2, pos2);
|
||||
} else {
|
||||
QuantityFormatter countToFormat = getQuantityFormatter(lowValue.getUnit(), formatWidth);
|
||||
SimplePatternFormatter formatter = countToFormat.getByVariant(resolvedCategory.toString());
|
||||
SimplePatternFormatter formatter =
|
||||
getPluralFormatter(lowValue.getUnit(), formatWidth, resolvedCategory.ordinal());
|
||||
return formatter.format(formattedNumber);
|
||||
}
|
||||
}
|
||||
|
@ -746,7 +746,29 @@ public class MeasureFormat extends UFormat {
|
|||
* unitsShort/duration/hour contains other{"{0} hrs"}.
|
||||
*/
|
||||
class UnitPatternSink extends UResource.TableSink {
|
||||
QuantityFormatter countToFormat;
|
||||
SimplePatternFormatter[] patterns;
|
||||
|
||||
void setFormatterIfAbsent(int index, UResource.Value value, int minPlaceholders) {
|
||||
if (patterns == null) {
|
||||
EnumMap<FormatWidth, SimplePatternFormatter[]> styleToPatterns =
|
||||
cacheData.unitToStyleToPatterns.get(unit);
|
||||
if (styleToPatterns == null) {
|
||||
styleToPatterns =
|
||||
new EnumMap<FormatWidth, SimplePatternFormatter[]>(FormatWidth.class);
|
||||
cacheData.unitToStyleToPatterns.put(unit, styleToPatterns);
|
||||
} else {
|
||||
patterns = styleToPatterns.get(width);
|
||||
}
|
||||
if (patterns == null) {
|
||||
patterns = new SimplePatternFormatter[MeasureFormatData.PATTERN_COUNT];
|
||||
styleToPatterns.put(width, patterns);
|
||||
}
|
||||
}
|
||||
if (patterns[index] == null) {
|
||||
patterns[index] = SimplePatternFormatter.
|
||||
compileMinMaxPlaceholders(value.getString(), minPlaceholders, 1);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void put(UResource.Key key, UResource.Value value) {
|
||||
|
@ -754,27 +776,14 @@ public class MeasureFormat extends UFormat {
|
|||
// Skip the unit display name for now.
|
||||
} else if (key.contentEquals("per")) {
|
||||
// For example, "{0}/h".
|
||||
cacheData.setPerUnitFormatterIfAbsent(unit, width, value);
|
||||
// TODO: Set minPlaceholders=1
|
||||
// after http://unicode.org/cldr/trac/ticket/9129 is fixed.
|
||||
setFormatterIfAbsent(MeasureFormatData.PER_UNIT_INDEX, value, 0);
|
||||
} else {
|
||||
// The key must be one of the plural form strings. For example:
|
||||
// one{"{0} hr"}
|
||||
// other{"{0} hrs"}
|
||||
if (countToFormat == null) {
|
||||
EnumMap<FormatWidth, QuantityFormatter> styleToCountToFormat =
|
||||
cacheData.unitToStyleToCountToFormat.get(unit);
|
||||
if (styleToCountToFormat == null) {
|
||||
styleToCountToFormat =
|
||||
new EnumMap<FormatWidth, QuantityFormatter>(FormatWidth.class);
|
||||
cacheData.unitToStyleToCountToFormat.put(unit, styleToCountToFormat);
|
||||
} else {
|
||||
countToFormat = styleToCountToFormat.get(width);
|
||||
}
|
||||
if (countToFormat == null) {
|
||||
countToFormat = new QuantityFormatter();
|
||||
styleToCountToFormat.put(width, countToFormat);
|
||||
}
|
||||
}
|
||||
countToFormat.addIfAbsent(key, value);
|
||||
setFormatterIfAbsent(StandardPluralCategories.getIndex(key), value, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -789,8 +798,8 @@ public class MeasureFormat extends UFormat {
|
|||
public UResource.TableSink getOrCreateTableSink(UResource.Key key, int initialSize) {
|
||||
// Should we ignore or reject unknown units?
|
||||
unit = MeasureUnit.internalGetInstance(type, key.toString()); // never null
|
||||
// Trigger a fresh lookup of the QuantityFormatter for this unit+width.
|
||||
patternSink.countToFormat = null;
|
||||
// Trigger a fresh lookup of the patterns for this unit+width.
|
||||
patternSink.patterns = null;
|
||||
return patternSink;
|
||||
}
|
||||
}
|
||||
|
@ -805,7 +814,7 @@ public class MeasureFormat extends UFormat {
|
|||
public void put(UResource.Key key, UResource.Value value) {
|
||||
if (key.contentEquals("per")) {
|
||||
cacheData.styleToPerPattern.put(width,
|
||||
SimplePatternFormatter.compile(value.getString()));
|
||||
SimplePatternFormatter.compileMinMaxPlaceholders(value.getString(), 2, 2));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -925,45 +934,44 @@ public class MeasureFormat extends UFormat {
|
|||
return width;
|
||||
}
|
||||
|
||||
private QuantityFormatter getQuantityFormatter(MeasureUnit unit, FormatWidth width) {
|
||||
private SimplePatternFormatter getFormatterOrNull(MeasureUnit unit, FormatWidth width, int index) {
|
||||
width = getRegularWidth(width);
|
||||
Map<FormatWidth, QuantityFormatter> styleToCountToFormat =
|
||||
cache.unitToStyleToCountToFormat.get(unit);
|
||||
QuantityFormatter countToFormat = styleToCountToFormat.get(width);
|
||||
if (countToFormat != null) {
|
||||
return countToFormat;
|
||||
Map<FormatWidth, SimplePatternFormatter[]> styleToPatterns =
|
||||
cache.unitToStyleToPatterns.get(unit);
|
||||
SimplePatternFormatter[] patterns = styleToPatterns.get(width);
|
||||
if (patterns != null && patterns[index] != null) {
|
||||
return patterns[index];
|
||||
}
|
||||
FormatWidth fallbackWidth = cache.widthFallback[width.ordinal()];
|
||||
if (fallbackWidth != null) {
|
||||
countToFormat = styleToCountToFormat.get(fallbackWidth);
|
||||
if (countToFormat != null) {
|
||||
return countToFormat;
|
||||
}
|
||||
}
|
||||
throw new MissingResourceException("no formatting patterns for " + unit + " and width " + width, null, null);
|
||||
}
|
||||
|
||||
private SimplePatternFormatter getPerUnitFormatter(MeasureUnit unit, FormatWidth width) {
|
||||
width = getRegularWidth(width);
|
||||
Map<FormatWidth, SimplePatternFormatter> styleToPerUnitPattern =
|
||||
cache.unitToStyleToPerUnitPattern.get(unit);
|
||||
if (styleToPerUnitPattern == null) {
|
||||
return null;
|
||||
}
|
||||
SimplePatternFormatter perUnitPattern = styleToPerUnitPattern.get(width);
|
||||
if (perUnitPattern != null) {
|
||||
return perUnitPattern;
|
||||
}
|
||||
FormatWidth fallbackWidth = cache.widthFallback[width.ordinal()];
|
||||
if (fallbackWidth != null) {
|
||||
perUnitPattern = styleToPerUnitPattern.get(fallbackWidth);
|
||||
if (perUnitPattern != null) {
|
||||
return perUnitPattern;
|
||||
patterns = styleToPatterns.get(fallbackWidth);
|
||||
if (patterns != null && patterns[index] != null) {
|
||||
return patterns[index];
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private SimplePatternFormatter getFormatter(MeasureUnit unit, FormatWidth width, int index) {
|
||||
SimplePatternFormatter pattern = getFormatterOrNull(unit, width, index);
|
||||
if (pattern == null) {
|
||||
throw new MissingResourceException(
|
||||
"no formatting pattern for " + unit + ", width " + width + ", index " + index,
|
||||
null, null);
|
||||
}
|
||||
return pattern;
|
||||
}
|
||||
|
||||
private SimplePatternFormatter getPluralFormatter(MeasureUnit unit, FormatWidth width, int index) {
|
||||
if (index != StandardPluralCategories.OTHER_INDEX) {
|
||||
SimplePatternFormatter pattern = getFormatterOrNull(unit, width, index);
|
||||
if (pattern != null) {
|
||||
return pattern;
|
||||
}
|
||||
}
|
||||
return getFormatter(unit, width, StandardPluralCategories.OTHER_INDEX);
|
||||
}
|
||||
|
||||
private SimplePatternFormatter getPerFormatter(FormatWidth width) {
|
||||
width = getRegularWidth(width);
|
||||
SimplePatternFormatter perPattern = cache.styleToPerPattern.get(width);
|
||||
|
@ -983,14 +991,16 @@ public class MeasureFormat extends UFormat {
|
|||
private int withPerUnitAndAppend(
|
||||
CharSequence formatted, MeasureUnit perUnit, StringBuilder appendTo) {
|
||||
int[] offsets = new int[1];
|
||||
SimplePatternFormatter perUnitPattern = getPerUnitFormatter(perUnit, formatWidth);
|
||||
SimplePatternFormatter perUnitPattern =
|
||||
getFormatterOrNull(perUnit, formatWidth, MeasureFormatData.PER_UNIT_INDEX);
|
||||
if (perUnitPattern != null) {
|
||||
perUnitPattern.formatAndAppend(appendTo, offsets, formatted);
|
||||
return offsets[0];
|
||||
}
|
||||
SimplePatternFormatter perPattern = getPerFormatter(formatWidth);
|
||||
QuantityFormatter countToFormat = getQuantityFormatter(perUnit, formatWidth);
|
||||
String perUnitString = countToFormat.getByVariant("one").getPatternWithNoPlaceholders().trim();
|
||||
SimplePatternFormatter pattern =
|
||||
getPluralFormatter(perUnit, formatWidth, StandardPluralCategories.one.ordinal());
|
||||
String perUnitString = pattern.getPatternWithNoPlaceholders().trim();
|
||||
perPattern.formatAndAppend(appendTo, offsets, formatted, perUnitString);
|
||||
return offsets[0];
|
||||
}
|
||||
|
@ -1020,8 +1030,8 @@ public class MeasureFormat extends UFormat {
|
|||
StringBuffer formattedNumber = nf.format(n, new StringBuffer(), fpos);
|
||||
String keyword = rules.select(new PluralRules.FixedDecimal(n.doubleValue(), fpos.getCountVisibleFractionDigits(), fpos.getFractionDigits()));
|
||||
|
||||
QuantityFormatter countToFormat = getQuantityFormatter(unit, formatWidth);
|
||||
SimplePatternFormatter formatter = countToFormat.getByVariant(keyword);
|
||||
int pluralForm = StandardPluralCategories.getIndexOrOtherIndex(keyword);
|
||||
SimplePatternFormatter formatter = getPluralFormatter(unit, formatWidth, pluralForm);
|
||||
int[] offsets = new int[1];
|
||||
formatter.formatAndAppend(appendTo, offsets, formattedNumber);
|
||||
if (offsets[0] != -1) { // there is a number (may not happen with, say, Arabic dual)
|
||||
|
@ -1046,34 +1056,22 @@ public class MeasureFormat extends UFormat {
|
|||
* TODO: Maybe store more sparsely in general, with pointers rather than potentially-empty objects.
|
||||
*/
|
||||
private static final class MeasureFormatData {
|
||||
static final int PER_UNIT_INDEX = StandardPluralCategories.COUNT;
|
||||
static final int PATTERN_COUNT = PER_UNIT_INDEX + 1;
|
||||
|
||||
boolean hasPerFormatter(FormatWidth width) {
|
||||
return styleToPerPattern.containsKey(width);
|
||||
}
|
||||
|
||||
void setPerUnitFormatterIfAbsent(MeasureUnit unit, FormatWidth width, UResource.Value value) {
|
||||
EnumMap<FormatWidth, SimplePatternFormatter> styleToPerUnitPattern =
|
||||
unitToStyleToPerUnitPattern.get(unit);
|
||||
if (styleToPerUnitPattern == null) {
|
||||
styleToPerUnitPattern =
|
||||
new EnumMap<FormatWidth, SimplePatternFormatter>(FormatWidth.class);
|
||||
unitToStyleToPerUnitPattern.put(unit, styleToPerUnitPattern);
|
||||
}
|
||||
if (!styleToPerUnitPattern.containsKey(width)) {
|
||||
styleToPerUnitPattern.put(width, SimplePatternFormatter.compile(value.getString()));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Redirection data from root-bundle, top-level sideways aliases.
|
||||
* - null: initial value, just fall back to root
|
||||
* - FormatWidth.WIDE/SHORT/NARROW: sideways alias for missing data
|
||||
*/
|
||||
final FormatWidth widthFallback[] = new FormatWidth[FormatWidth.INDEX_COUNT];
|
||||
/** Measure unit -> format width -> plural form -> pattern ("{0} meters") */
|
||||
final Map<MeasureUnit, EnumMap<FormatWidth, QuantityFormatter>> unitToStyleToCountToFormat =
|
||||
new HashMap<MeasureUnit, EnumMap<FormatWidth, QuantityFormatter>>();
|
||||
final Map<MeasureUnit, EnumMap<FormatWidth, SimplePatternFormatter>> unitToStyleToPerUnitPattern =
|
||||
new HashMap<MeasureUnit, EnumMap<FormatWidth, SimplePatternFormatter>>();
|
||||
/** Measure unit -> format width -> array of patterns ("{0} meters") (plurals + PER_UNIT_INDEX) */
|
||||
final Map<MeasureUnit, EnumMap<FormatWidth, SimplePatternFormatter[]>> unitToStyleToPatterns =
|
||||
new HashMap<MeasureUnit, EnumMap<FormatWidth, SimplePatternFormatter[]>>();
|
||||
final EnumMap<FormatWidth, SimplePatternFormatter> styleToPerPattern =
|
||||
new EnumMap<FormatWidth, SimplePatternFormatter>(FormatWidth.class);;
|
||||
}
|
||||
|
@ -1463,7 +1461,7 @@ public class MeasureFormat extends UFormat {
|
|||
} catch ( MissingResourceException ex ) {
|
||||
resultString = rb.getStringWithFallback("NumberElements/latn/patterns/range");
|
||||
}
|
||||
result = SimplePatternFormatter.compile(resultString);
|
||||
result = SimplePatternFormatter.compileMinMaxPlaceholders(resultString, 2, 2);
|
||||
localeIdToRangeFormat.put(forLocale, result);
|
||||
if (!forLocale.equals(realLocale)) {
|
||||
localeIdToRangeFormat.put(realLocale, result);
|
||||
|
|
|
@ -1787,6 +1787,14 @@ public class PluralRules implements Serializable {
|
|||
*/
|
||||
@Deprecated
|
||||
public enum StandardPluralCategories {
|
||||
// TODO: An enum name is more commonly singular, e.g., StandardPluralCategory.
|
||||
// TODO: Consider changing it to StandardPluralForm(s) which is shorter, and easier to say.
|
||||
// We use "plural category" and "plural form" interchangeably in
|
||||
// http://www.unicode.org/reports/tr35/tr35-numbers.html#Language_Plural_Rules
|
||||
// Maybe even just StandardPlural?!
|
||||
// TODO: Make the constants uppercase, and change code that relies on lowercase names,
|
||||
// such as by calling .valueOf(String).
|
||||
// TODO: Move this into its own file, in impl package?
|
||||
/**
|
||||
* @internal
|
||||
* @deprecated This API is ICU internal only.
|
||||
|
@ -1823,28 +1831,119 @@ public class PluralRules implements Serializable {
|
|||
*/
|
||||
@Deprecated
|
||||
other;
|
||||
/**
|
||||
* @internal
|
||||
* @deprecated This API is ICU internal only.
|
||||
*/
|
||||
@Deprecated
|
||||
public static final List<StandardPluralCategories> VALUES
|
||||
= Collections.unmodifiableList(Arrays.asList(values()));
|
||||
/**
|
||||
* @internal
|
||||
* @deprecated This API is ICU internal only.
|
||||
*/
|
||||
@Deprecated
|
||||
public static final int COUNT = values().length;
|
||||
|
||||
static StandardPluralCategories forString(String s) {
|
||||
StandardPluralCategories a;
|
||||
try {
|
||||
a = valueOf(s);
|
||||
} catch (Exception e) {
|
||||
return null;
|
||||
/**
|
||||
* @internal
|
||||
* @deprecated This API is ICU internal only.
|
||||
*/
|
||||
@Deprecated
|
||||
public static final int OTHER_INDEX = other.ordinal();
|
||||
|
||||
/**
|
||||
* @internal
|
||||
* @deprecated This API is ICU internal only.
|
||||
*/
|
||||
@Deprecated
|
||||
public static final List<StandardPluralCategories> VALUES =
|
||||
Collections.unmodifiableList(Arrays.asList(values()));
|
||||
|
||||
/**
|
||||
* @internal
|
||||
* @deprecated This API is ICU internal only.
|
||||
*/
|
||||
@Deprecated
|
||||
public static final int COUNT = VALUES.size();
|
||||
|
||||
/**
|
||||
* @internal
|
||||
* @deprecated This API is ICU internal only.
|
||||
*/
|
||||
@Deprecated
|
||||
public static final StandardPluralCategories getCategoryOrNull(CharSequence keyword) {
|
||||
switch (keyword.length()) {
|
||||
case 3:
|
||||
if ("one".contentEquals(keyword)) {
|
||||
return one;
|
||||
} else if ("two".contentEquals(keyword)) {
|
||||
return two;
|
||||
} else if ("few".contentEquals(keyword)) {
|
||||
return few;
|
||||
}
|
||||
break;
|
||||
case 4:
|
||||
if ("many".contentEquals(keyword)) {
|
||||
return many;
|
||||
} else if ("zero".contentEquals(keyword)) {
|
||||
return zero;
|
||||
}
|
||||
break;
|
||||
case 5:
|
||||
if ("other".contentEquals(keyword)) {
|
||||
return other;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal
|
||||
* @deprecated This API is ICU internal only.
|
||||
*/
|
||||
@Deprecated
|
||||
public static final StandardPluralCategories getCategoryOrOther(CharSequence keyword) {
|
||||
StandardPluralCategories cat = getCategoryOrNull(keyword);
|
||||
return cat != null ? cat : other;
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal
|
||||
* @deprecated This API is ICU internal only.
|
||||
*/
|
||||
@Deprecated
|
||||
public static final StandardPluralCategories getCategory(CharSequence keyword) {
|
||||
StandardPluralCategories cat = getCategoryOrNull(keyword);
|
||||
if (cat != null) {
|
||||
return cat;
|
||||
} else {
|
||||
throw new IllegalArgumentException(keyword.toString());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal
|
||||
* @deprecated This API is ICU internal only.
|
||||
*/
|
||||
@Deprecated
|
||||
public static final int getIndexOrNegative(CharSequence keyword) {
|
||||
StandardPluralCategories cat = getCategoryOrNull(keyword);
|
||||
return cat != null ? cat.ordinal() : -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal
|
||||
* @deprecated This API is ICU internal only.
|
||||
*/
|
||||
@Deprecated
|
||||
public static final int getIndexOrOtherIndex(CharSequence keyword) {
|
||||
StandardPluralCategories cat = getCategoryOrNull(keyword);
|
||||
return cat != null ? cat.ordinal() : other.ordinal();
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal
|
||||
* @deprecated This API is ICU internal only.
|
||||
*/
|
||||
@Deprecated
|
||||
public static final int getIndex(CharSequence keyword) {
|
||||
StandardPluralCategories cat = getCategoryOrNull(keyword);
|
||||
if (cat != null) {
|
||||
return cat.ordinal();
|
||||
} else {
|
||||
throw new IllegalArgumentException(keyword.toString());
|
||||
}
|
||||
return a;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2012,16 +2111,27 @@ public class PluralRules implements Serializable {
|
|||
* Given a number information, returns the keyword of the first rule that applies to
|
||||
* the number.
|
||||
*
|
||||
* @param sample The number information for which the rule has to be determined.
|
||||
* @param number The number information for which the rule has to be determined.
|
||||
* @return The keyword of the selected rule.
|
||||
* @internal
|
||||
* @deprecated This API is ICU internal only.
|
||||
*/
|
||||
@Deprecated
|
||||
public String select(FixedDecimal sample) {
|
||||
return rules.select(sample);
|
||||
public String select(FixedDecimal number) {
|
||||
return rules.select(number);
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal
|
||||
* @deprecated This API is ICU internal only.
|
||||
*/
|
||||
@Deprecated
|
||||
public String select(double number, NumberFormat numberFormat) {
|
||||
if (numberFormat instanceof DecimalFormat) {
|
||||
return select(((DecimalFormat) numberFormat).getFixedDecimal(number));
|
||||
}
|
||||
return select(number);
|
||||
}
|
||||
|
||||
/**
|
||||
* Given a number information, and keyword, return whether the keyword would match the number.
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
*******************************************************************************
|
||||
* Copyright (C) 2013-2014, International Business Machines Corporation and *
|
||||
* others. All Rights Reserved. *
|
||||
* Copyright (C) 2013-2015, International Business Machines Corporation and
|
||||
* others. All Rights Reserved.
|
||||
*******************************************************************************
|
||||
*/
|
||||
package com.ibm.icu.text;
|
||||
|
@ -9,7 +9,6 @@ package com.ibm.icu.text;
|
|||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.LinkedHashSet;
|
||||
|
@ -21,7 +20,6 @@ import java.util.TreeSet;
|
|||
|
||||
import com.ibm.icu.text.PluralRules.FixedDecimal;
|
||||
import com.ibm.icu.text.PluralRules.KeywordStatus;
|
||||
import com.ibm.icu.text.PluralRules.StandardPluralCategories;
|
||||
import com.ibm.icu.util.Output;
|
||||
|
||||
/**
|
||||
|
@ -237,17 +235,6 @@ public class PluralSamples {
|
|||
return 37;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
private static final Comparator<String> KEYWORD_COMPARATOR = new Comparator<String> () {
|
||||
public int compare(String arg0, String arg1) {
|
||||
StandardPluralCategories a = StandardPluralCategories.forString(arg0);
|
||||
StandardPluralCategories b = StandardPluralCategories.forString(arg1);
|
||||
return a == null
|
||||
? (b == null ? arg0.compareTo(arg1) : -1)
|
||||
: (b == null ? 1 : a.compareTo(b));
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* @internal
|
||||
* @deprecated This API is ICU internal only.
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
package com.ibm.icu.text;
|
||||
|
||||
import com.ibm.icu.impl.SimplePatternFormatter;
|
||||
import com.ibm.icu.impl.UResource;
|
||||
import com.ibm.icu.text.PluralRules.StandardPluralCategories;
|
||||
|
||||
/**
|
||||
* QuantityFormatter represents an unknown quantity of something and formats a known quantity
|
||||
|
@ -18,41 +18,8 @@ import com.ibm.icu.impl.UResource;
|
|||
* PluralRules and DecimalFormat. It is package-protected as it is not meant for public use.
|
||||
*/
|
||||
class QuantityFormatter {
|
||||
/**
|
||||
* Plural forms in index order: "other", "zero", "one", "two", "few", "many"
|
||||
* "other" must be first.
|
||||
*/
|
||||
private static final int getPluralIndex(CharSequence pluralForm) {
|
||||
switch (pluralForm.length()) {
|
||||
case 3:
|
||||
if ("one".contentEquals(pluralForm)) {
|
||||
return 2;
|
||||
} else if ("two".contentEquals(pluralForm)) {
|
||||
return 3;
|
||||
} else if ("few".contentEquals(pluralForm)) {
|
||||
return 4;
|
||||
}
|
||||
break;
|
||||
case 4:
|
||||
if ("many".contentEquals(pluralForm)) {
|
||||
return 5;
|
||||
} else if ("zero".contentEquals(pluralForm)) {
|
||||
return 1;
|
||||
}
|
||||
break;
|
||||
case 5:
|
||||
if ("other".contentEquals(pluralForm)) {
|
||||
return 0;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
private static final int INDEX_COUNT = 6;
|
||||
|
||||
private final SimplePatternFormatter[] templates = new SimplePatternFormatter[INDEX_COUNT];
|
||||
private final SimplePatternFormatter[] templates =
|
||||
new SimplePatternFormatter[StandardPluralCategories.COUNT];
|
||||
|
||||
public QuantityFormatter() {}
|
||||
|
||||
|
@ -67,49 +34,18 @@ class QuantityFormatter {
|
|||
* if template has more than just the {0} placeholder.
|
||||
*/
|
||||
public void addIfAbsent(CharSequence variant, String template) {
|
||||
addIfAbsent(variant, template, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a template if there is none yet for the plural form.
|
||||
* This version only calls UResource.Value.getString()
|
||||
* if there is no template yet for the plural form.
|
||||
*
|
||||
* @param variant the plural variant, e.g "zero", "one", "two", "few", "many", "other"
|
||||
* @param template the text for that plural variant with "{0}" as the quantity. For
|
||||
* example, in English, the template for the "one" variant may be "{0} apple" while the
|
||||
* template for the "other" variant may be "{0} apples"
|
||||
* @throws IllegalArgumentException if variant is not recognized or
|
||||
* if template has more than just the {0} placeholder.
|
||||
*/
|
||||
public void addIfAbsent(CharSequence variant, UResource.Value template) {
|
||||
addIfAbsent(variant, null, template);
|
||||
}
|
||||
|
||||
private void addIfAbsent(CharSequence variant, String template, UResource.Value templateValue) {
|
||||
int idx = getPluralIndex(variant);
|
||||
if (idx < 0) {
|
||||
throw new IllegalArgumentException(variant.toString());
|
||||
}
|
||||
int idx = StandardPluralCategories.getIndex(variant);
|
||||
if (templates[idx] != null) {
|
||||
return;
|
||||
}
|
||||
if (template == null) {
|
||||
template = templateValue.getString();
|
||||
}
|
||||
SimplePatternFormatter newT = SimplePatternFormatter.compile(template);
|
||||
if (newT.getPlaceholderCount() > 1) {
|
||||
throw new IllegalArgumentException(
|
||||
"Extra placeholders: " + template);
|
||||
}
|
||||
templates[idx] = newT;
|
||||
templates[idx] = SimplePatternFormatter.compileMinMaxPlaceholders(template, 0, 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return true if this object has at least the "other" variant
|
||||
*/
|
||||
public boolean isValid() {
|
||||
return templates[0] != null;
|
||||
return templates[StandardPluralCategories.OTHER_INDEX] != null;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -122,7 +58,7 @@ class QuantityFormatter {
|
|||
*/
|
||||
public String format(double quantity, NumberFormat numberFormat, PluralRules pluralRules) {
|
||||
String formatStr = numberFormat.format(quantity);
|
||||
String variant = computeVariant(quantity, numberFormat, pluralRules);
|
||||
String variant = pluralRules.select(quantity, numberFormat);
|
||||
return getByVariant(variant).format(formatStr);
|
||||
}
|
||||
|
||||
|
@ -133,15 +69,9 @@ class QuantityFormatter {
|
|||
*/
|
||||
public SimplePatternFormatter getByVariant(CharSequence variant) {
|
||||
assert isValid();
|
||||
int idx = getPluralIndex(variant);
|
||||
SimplePatternFormatter template = templates[idx < 0 ? 0 : idx];
|
||||
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);
|
||||
int idx = StandardPluralCategories.getIndexOrOtherIndex(variant);
|
||||
SimplePatternFormatter template = templates[idx];
|
||||
return (template == null && idx != StandardPluralCategories.OTHER_INDEX) ?
|
||||
templates[StandardPluralCategories.OTHER_INDEX] : template;
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue