• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // © 2016 and later: Unicode, Inc. and others.
2 // License & terms of use: http://www.unicode.org/copyright.html
3 /*
4  *******************************************************************************
5  * Copyright (C) 2013-2016, International Business Machines Corporation and
6  * others. All Rights Reserved.
7  *******************************************************************************
8  */
9 package com.ibm.icu.text;
10 
11 import java.text.FieldPosition;
12 
13 import com.ibm.icu.impl.SimpleFormatterImpl;
14 import com.ibm.icu.impl.StandardPlural;
15 
16 /**
17  * QuantityFormatter represents an unknown quantity of something and formats a known quantity
18  * in terms of that something. For example, a QuantityFormatter that represents X apples may
19  * format 1 as "1 apple" and 3 as "3 apples"
20  * <p>
21  * QuanitityFormatter appears here instead of in com.ibm.icu.impl because it depends on
22  * PluralRules and DecimalFormat. It is package-protected as it is not meant for public use.
23  */
24 class QuantityFormatter {
25     private final SimpleFormatter[] templates =
26             new SimpleFormatter[StandardPlural.COUNT];
27 
QuantityFormatter()28     public QuantityFormatter() {}
29 
30     /**
31      * Adds a template if there is none yet for the plural form.
32      *
33      * @param variant the plural variant, e.g "zero", "one", "two", "few", "many", "other"
34      * @param template the text for that plural variant with "{0}" as the quantity. For
35      * example, in English, the template for the "one" variant may be "{0} apple" while the
36      * template for the "other" variant may be "{0} apples"
37      * @throws IllegalArgumentException if variant is not recognized or
38      *  if template has more than just the {0} placeholder.
39      */
addIfAbsent(CharSequence variant, String template)40     public void addIfAbsent(CharSequence variant, String template) {
41         int idx = StandardPlural.indexFromString(variant);
42         if (templates[idx] != null) {
43             return;
44         }
45         templates[idx] = SimpleFormatter.compileMinMaxArguments(template, 0, 1);
46     }
47 
48     /**
49      * @return true if this object has at least the "other" variant
50      */
isValid()51     public boolean isValid() {
52         return templates[StandardPlural.OTHER_INDEX] != null;
53     }
54 
55     /**
56      * Format formats a number with this object.
57      * @param number the number to be formatted
58      * @param numberFormat used to actually format the number.
59      * @param pluralRules uses the number and the numberFormat to determine what plural
60      *  variant to use for fetching the formatting template.
61      * @return the formatted string e.g '3 apples'
62      */
format(double number, NumberFormat numberFormat, PluralRules pluralRules)63     public String format(double number, NumberFormat numberFormat, PluralRules pluralRules) {
64         String formatStr = numberFormat.format(number);
65         StandardPlural p = selectPlural(number, numberFormat, pluralRules);
66         SimpleFormatter formatter = templates[p.ordinal()];
67         if (formatter == null) {
68             formatter = templates[StandardPlural.OTHER_INDEX];
69             assert formatter != null;
70         }
71         return formatter.format(formatStr);
72     }
73 
74     /**
75      * Gets the SimpleFormatter for a particular variant.
76      * @param variant "zero", "one", "two", "few", "many", "other"
77      * @return the SimpleFormatter
78      */
getByVariant(CharSequence variant)79     public SimpleFormatter getByVariant(CharSequence variant) {
80         assert isValid();
81         int idx = StandardPlural.indexOrOtherIndexFromString(variant);
82         SimpleFormatter template = templates[idx];
83         return (template == null && idx != StandardPlural.OTHER_INDEX) ?
84                 templates[StandardPlural.OTHER_INDEX] : template;
85     }
86 
87     // The following methods live here so that class PluralRules does not depend on number formatting,
88     // and the SimpleFormatter does not depend on FieldPosition.
89 
90     /**
91      * Selects the standard plural form for the number/formatter/rules.
92      */
selectPlural(double number, NumberFormat numberFormat, PluralRules rules)93     public static StandardPlural selectPlural(double number, NumberFormat numberFormat, PluralRules rules) {
94         String pluralKeyword;
95         if (numberFormat instanceof DecimalFormat) {
96             pluralKeyword = rules.select(((DecimalFormat) numberFormat).getFixedDecimal(number));
97         } else {
98             pluralKeyword = rules.select(number);
99         }
100         return StandardPlural.orOtherFromString(pluralKeyword);
101     }
102 
103     /**
104      * Formats the pattern with the value and adjusts the FieldPosition.
105      */
format(String compiledPattern, CharSequence value, StringBuilder appendTo, FieldPosition pos)106     public static StringBuilder format(String compiledPattern, CharSequence value,
107             StringBuilder appendTo, FieldPosition pos) {
108         int[] offsets = new int[1];
109         SimpleFormatterImpl.formatAndAppend(compiledPattern, appendTo, offsets, value);
110         if (pos.getBeginIndex() != 0 || pos.getEndIndex() != 0) {
111             if (offsets[0] >= 0) {
112                 pos.setBeginIndex(pos.getBeginIndex() + offsets[0]);
113                 pos.setEndIndex(pos.getEndIndex() + offsets[0]);
114             } else {
115                 pos.setBeginIndex(0);
116                 pos.setEndIndex(0);
117             }
118         }
119         return appendTo;
120     }
121 }
122