| // © 2016 and later: Unicode, Inc. and others. |
| // License & terms of use: http://www.unicode.org/copyright.html |
| /* |
| ******************************************************************************* |
| * Copyright (C) 2013-2016, International Business Machines Corporation and |
| * others. All Rights Reserved. |
| ******************************************************************************* |
| */ |
| package com.ibm.icu.text; |
| |
| import java.text.FieldPosition; |
| |
| import com.ibm.icu.impl.SimpleFormatterImpl; |
| import com.ibm.icu.impl.StandardPlural; |
| |
| /** |
| * QuantityFormatter represents an unknown quantity of something and formats a known quantity |
| * in terms of that something. For example, a QuantityFormatter that represents X apples may |
| * format 1 as "1 apple" and 3 as "3 apples" |
| * <p> |
| * QuanitityFormatter appears here instead of in com.ibm.icu.impl because it depends on |
| * PluralRules and DecimalFormat. It is package-protected as it is not meant for public use. |
| */ |
| class QuantityFormatter { |
| private final SimpleFormatter[] templates = |
| new SimpleFormatter[StandardPlural.COUNT]; |
| |
| public QuantityFormatter() {} |
| |
| /** |
| * Adds a template if there is none 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, String template) { |
| int idx = StandardPlural.indexFromString(variant); |
| if (templates[idx] != null) { |
| return; |
| } |
| templates[idx] = SimpleFormatter.compileMinMaxArguments(template, 0, 1); |
| } |
| |
| /** |
| * @return true if this object has at least the "other" variant |
| */ |
| public boolean isValid() { |
| return templates[StandardPlural.OTHER_INDEX] != null; |
| } |
| |
| /** |
| * Format formats a number with this object. |
| * @param number the number to be formatted |
| * @param numberFormat used to actually format the number. |
| * @param pluralRules uses the number and the numberFormat to determine what plural |
| * variant to use for fetching the formatting template. |
| * @return the formatted string e.g '3 apples' |
| */ |
| public String format(double number, NumberFormat numberFormat, PluralRules pluralRules) { |
| String formatStr = numberFormat.format(number); |
| StandardPlural p = selectPlural(number, numberFormat, pluralRules); |
| SimpleFormatter formatter = templates[p.ordinal()]; |
| if (formatter == null) { |
| formatter = templates[StandardPlural.OTHER_INDEX]; |
| assert formatter != null; |
| } |
| return formatter.format(formatStr); |
| } |
| |
| /** |
| * Gets the SimpleFormatter for a particular variant. |
| * @param variant "zero", "one", "two", "few", "many", "other" |
| * @return the SimpleFormatter |
| */ |
| public SimpleFormatter getByVariant(CharSequence variant) { |
| assert isValid(); |
| int idx = StandardPlural.indexOrOtherIndexFromString(variant); |
| SimpleFormatter template = templates[idx]; |
| return (template == null && idx != StandardPlural.OTHER_INDEX) ? |
| templates[StandardPlural.OTHER_INDEX] : template; |
| } |
| |
| // The following methods live here so that class PluralRules does not depend on number formatting, |
| // and the SimpleFormatter does not depend on FieldPosition. |
| |
| /** |
| * Selects the standard plural form for the number/formatter/rules. |
| */ |
| public static StandardPlural selectPlural(double number, NumberFormat numberFormat, PluralRules rules) { |
| String pluralKeyword; |
| if (numberFormat instanceof DecimalFormat) { |
| pluralKeyword = rules.select(((DecimalFormat) numberFormat).getFixedDecimal(number)); |
| } else { |
| pluralKeyword = rules.select(number); |
| } |
| return StandardPlural.orOtherFromString(pluralKeyword); |
| } |
| |
| /** |
| * Formats the pattern with the value and adjusts the FieldPosition. |
| */ |
| public static StringBuilder format(String compiledPattern, CharSequence value, |
| StringBuilder appendTo, FieldPosition pos) { |
| int[] offsets = new int[1]; |
| SimpleFormatterImpl.formatAndAppend(compiledPattern, appendTo, offsets, value); |
| if (pos.getBeginIndex() != 0 || pos.getEndIndex() != 0) { |
| if (offsets[0] >= 0) { |
| pos.setBeginIndex(pos.getBeginIndex() + offsets[0]); |
| pos.setEndIndex(pos.getEndIndex() + offsets[0]); |
| } else { |
| pos.setBeginIndex(0); |
| pos.setEndIndex(0); |
| } |
| } |
| return appendTo; |
| } |
| } |