• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /* GENERATED SOURCE. DO NOT MODIFY. */
2 // © 2017 and later: Unicode, Inc. and others.
3 // License & terms of use: http://www.unicode.org/copyright.html#License
4 package ohos.global.icu.impl.number;
5 
6 import java.util.EnumMap;
7 import java.util.Map;
8 import java.util.MissingResourceException;
9 
10 import ohos.global.icu.impl.CurrencyData;
11 import ohos.global.icu.impl.ICUData;
12 import ohos.global.icu.impl.ICUResourceBundle;
13 import ohos.global.icu.impl.SimpleFormatterImpl;
14 import ohos.global.icu.impl.StandardPlural;
15 import ohos.global.icu.impl.UResource;
16 import ohos.global.icu.impl.number.Modifier.Signum;
17 import ohos.global.icu.number.NumberFormatter.UnitWidth;
18 import ohos.global.icu.text.NumberFormat;
19 import ohos.global.icu.text.PluralRules;
20 import ohos.global.icu.util.Currency;
21 import ohos.global.icu.util.ICUException;
22 import ohos.global.icu.util.MeasureUnit;
23 import ohos.global.icu.util.ULocale;
24 import ohos.global.icu.util.UResourceBundle;
25 
26 /**
27  * @hide exposed on OHOS
28  */
29 public class LongNameHandler implements MicroPropsGenerator, ModifierStore {
30 
31     private static final int DNAM_INDEX = StandardPlural.COUNT;
32     private static final int PER_INDEX = StandardPlural.COUNT + 1;
33     private static final int ARRAY_LENGTH = StandardPlural.COUNT + 2;
34 
getIndex(String pluralKeyword)35     private static int getIndex(String pluralKeyword) {
36         // pluralKeyword can also be "dnam" or "per"
37         if (pluralKeyword.equals("dnam")) {
38             return DNAM_INDEX;
39         } else if (pluralKeyword.equals("per")) {
40             return PER_INDEX;
41         } else {
42             return StandardPlural.fromString(pluralKeyword).ordinal();
43         }
44     }
45 
getWithPlural(String[] strings, StandardPlural plural)46     private static String getWithPlural(String[] strings, StandardPlural plural) {
47         String result = strings[plural.ordinal()];
48         if (result == null) {
49             result = strings[StandardPlural.OTHER.ordinal()];
50         }
51         if (result == null) {
52             // There should always be data in the "other" plural variant.
53             throw new ICUException("Could not find data in 'other' plural variant");
54         }
55         return result;
56     }
57 
58     //////////////////////////
59     /// BEGIN DATA LOADING ///
60     //////////////////////////
61 
62     private static final class PluralTableSink extends UResource.Sink {
63 
64         String[] outArray;
65 
PluralTableSink(String[] outArray)66         public PluralTableSink(String[] outArray) {
67             this.outArray = outArray;
68         }
69 
70         @Override
put(UResource.Key key, UResource.Value value, boolean noFallback)71         public void put(UResource.Key key, UResource.Value value, boolean noFallback) {
72             UResource.Table pluralsTable = value.getTable();
73             for (int i = 0; pluralsTable.getKeyAndValue(i, key, value); ++i) {
74                 int index = getIndex(key.toString());
75                 if (outArray[index] != null) {
76                     continue;
77                 }
78                 String formatString = value.getString();
79                 outArray[index] = formatString;
80             }
81         }
82     }
83 
84     // NOTE: outArray MUST have at least ARRAY_LENGTH entries. No bounds checking is performed.
85 
getMeasureData( ULocale locale, MeasureUnit unit, UnitWidth width, String[] outArray)86     private static void getMeasureData(
87             ULocale locale,
88             MeasureUnit unit,
89             UnitWidth width,
90             String[] outArray) {
91         PluralTableSink sink = new PluralTableSink(outArray);
92         ICUResourceBundle resource;
93         resource = (ICUResourceBundle) UResourceBundle.getBundleInstance(ICUData.ICU_UNIT_BASE_NAME,
94                 locale);
95         StringBuilder key = new StringBuilder();
96         key.append("units");
97         if (width == UnitWidth.NARROW) {
98             key.append("Narrow");
99         } else if (width == UnitWidth.SHORT) {
100             key.append("Short");
101         }
102         key.append("/");
103         key.append(unit.getType());
104         key.append("/");
105 
106         // Map duration-year-person, duration-week-person, etc. to duration-year, duration-week, ...
107         // TODO(ICU-20400): Get duration-*-person data properly with aliases.
108         if (unit.getSubtype().endsWith("-person")) {
109             key.append(unit.getSubtype(), 0, unit.getSubtype().length() - 7);
110         } else {
111             key.append(unit.getSubtype());
112         }
113 
114         try {
115             resource.getAllItemsWithFallback(key.toString(), sink);
116         } catch (MissingResourceException e) {
117             throw new IllegalArgumentException("No data for unit " + unit + ", width " + width, e);
118         }
119     }
120 
getCurrencyLongNameData(ULocale locale, Currency currency, String[] outArray)121     private static void getCurrencyLongNameData(ULocale locale, Currency currency, String[] outArray) {
122         // In ICU4J, this method gets a CurrencyData from CurrencyData.provider.
123         // TODO(ICU4J): Implement this without going through CurrencyData, like in ICU4C?
124         Map<String, String> data = CurrencyData.provider.getInstance(locale, true).getUnitPatterns();
125         for (Map.Entry<String, String> e : data.entrySet()) {
126             String pluralKeyword = e.getKey();
127             int index = getIndex(pluralKeyword);
128             String longName = currency.getName(locale, Currency.PLURAL_LONG_NAME, pluralKeyword, null);
129             String simpleFormat = e.getValue();
130             // Example pattern from data: "{0} {1}"
131             // Example output after find-and-replace: "{0} US dollars"
132             simpleFormat = simpleFormat.replace("{1}", longName);
133             // String compiled = SimpleFormatterImpl.compileToStringMinMaxArguments(simpleFormat, sb, 1,
134             // 1);
135             // SimpleModifier mod = new SimpleModifier(compiled, Field.CURRENCY, false);
136             outArray[index] = simpleFormat;
137         }
138     }
139 
getPerUnitFormat(ULocale locale, UnitWidth width)140     private static String getPerUnitFormat(ULocale locale, UnitWidth width) {
141         ICUResourceBundle resource;
142         resource = (ICUResourceBundle) UResourceBundle.getBundleInstance(ICUData.ICU_UNIT_BASE_NAME,
143                 locale);
144         StringBuilder key = new StringBuilder();
145         key.append("units");
146         if (width == UnitWidth.NARROW) {
147             key.append("Narrow");
148         } else if (width == UnitWidth.SHORT) {
149             key.append("Short");
150         }
151         key.append("/compound/per");
152         try {
153             return resource.getStringWithFallback(key.toString());
154         } catch (MissingResourceException e) {
155             throw new IllegalArgumentException(
156                     "Could not find x-per-y format for " + locale + ", width " + width);
157         }
158     }
159 
160     ////////////////////////
161     /// END DATA LOADING ///
162     ////////////////////////
163 
164     private final Map<StandardPlural, SimpleModifier> modifiers;
165     private final PluralRules rules;
166     private final MicroPropsGenerator parent;
167 
LongNameHandler( Map<StandardPlural, SimpleModifier> modifiers, PluralRules rules, MicroPropsGenerator parent)168     private LongNameHandler(
169             Map<StandardPlural, SimpleModifier> modifiers,
170             PluralRules rules,
171             MicroPropsGenerator parent) {
172         this.modifiers = modifiers;
173         this.rules = rules;
174         this.parent = parent;
175     }
176 
getUnitDisplayName(ULocale locale, MeasureUnit unit, UnitWidth width)177     public static String getUnitDisplayName(ULocale locale, MeasureUnit unit, UnitWidth width) {
178         String[] measureData = new String[ARRAY_LENGTH];
179         getMeasureData(locale, unit, width, measureData);
180         return measureData[DNAM_INDEX];
181     }
182 
forCurrencyLongNames( ULocale locale, Currency currency, PluralRules rules, MicroPropsGenerator parent)183     public static LongNameHandler forCurrencyLongNames(
184             ULocale locale,
185             Currency currency,
186             PluralRules rules,
187             MicroPropsGenerator parent) {
188         String[] simpleFormats = new String[ARRAY_LENGTH];
189         getCurrencyLongNameData(locale, currency, simpleFormats);
190         // TODO(ICU4J): Reduce the number of object creations here?
191         Map<StandardPlural, SimpleModifier> modifiers = new EnumMap<>(
192                 StandardPlural.class);
193         LongNameHandler result = new LongNameHandler(modifiers, rules, parent);
194         result.simpleFormatsToModifiers(simpleFormats, NumberFormat.Field.CURRENCY);
195         return result;
196     }
197 
forMeasureUnit( ULocale locale, MeasureUnit unit, MeasureUnit perUnit, UnitWidth width, PluralRules rules, MicroPropsGenerator parent)198     public static LongNameHandler forMeasureUnit(
199             ULocale locale,
200             MeasureUnit unit,
201             MeasureUnit perUnit,
202             UnitWidth width,
203             PluralRules rules,
204             MicroPropsGenerator parent) {
205         if (perUnit != null) {
206             // Compound unit: first try to simplify (e.g., meters per second is its own unit).
207             MeasureUnit simplified = MeasureUnit.resolveUnitPerUnit(unit, perUnit);
208             if (simplified != null) {
209                 unit = simplified;
210             } else {
211                 // No simplified form is available.
212                 return forCompoundUnit(locale, unit, perUnit, width, rules, parent);
213             }
214         }
215 
216         String[] simpleFormats = new String[ARRAY_LENGTH];
217         getMeasureData(locale, unit, width, simpleFormats);
218         // TODO(ICU4J): Reduce the number of object creations here?
219         Map<StandardPlural, SimpleModifier> modifiers = new EnumMap<>(
220                 StandardPlural.class);
221         LongNameHandler result = new LongNameHandler(modifiers, rules, parent);
222         result.simpleFormatsToModifiers(simpleFormats, NumberFormat.Field.MEASURE_UNIT);
223         return result;
224     }
225 
forCompoundUnit( ULocale locale, MeasureUnit unit, MeasureUnit perUnit, UnitWidth width, PluralRules rules, MicroPropsGenerator parent)226     private static LongNameHandler forCompoundUnit(
227             ULocale locale,
228             MeasureUnit unit,
229             MeasureUnit perUnit,
230             UnitWidth width,
231             PluralRules rules,
232             MicroPropsGenerator parent) {
233         String[] primaryData = new String[ARRAY_LENGTH];
234         getMeasureData(locale, unit, width, primaryData);
235         String[] secondaryData = new String[ARRAY_LENGTH];
236         getMeasureData(locale, perUnit, width, secondaryData);
237         String perUnitFormat;
238         if (secondaryData[PER_INDEX] != null) {
239             perUnitFormat = secondaryData[PER_INDEX];
240         } else {
241             String rawPerUnitFormat = getPerUnitFormat(locale, width);
242             // rawPerUnitFormat is something like "{0}/{1}"; we need to substitute in the secondary unit.
243             // TODO: Lots of thrashing. Improve?
244             StringBuilder sb = new StringBuilder();
245             String compiled = SimpleFormatterImpl
246                     .compileToStringMinMaxArguments(rawPerUnitFormat, sb, 2, 2);
247             String secondaryFormat = getWithPlural(secondaryData, StandardPlural.ONE);
248 
249             // Some "one" pattern may not contain "{0}". For example in "ar" or "ne" locale.
250             String secondaryCompiled = SimpleFormatterImpl
251                     .compileToStringMinMaxArguments(secondaryFormat, sb, 0, 1);
252             String secondaryString = SimpleFormatterImpl.getTextWithNoArguments(secondaryCompiled)
253                     .trim();
254             perUnitFormat = SimpleFormatterImpl.formatCompiledPattern(compiled, "{0}", secondaryString);
255         }
256         Map<StandardPlural, SimpleModifier> modifiers = new EnumMap<>(
257                 StandardPlural.class);
258         LongNameHandler result = new LongNameHandler(modifiers, rules, parent);
259         result.multiSimpleFormatsToModifiers(primaryData, perUnitFormat, NumberFormat.Field.MEASURE_UNIT);
260         return result;
261     }
262 
simpleFormatsToModifiers( String[] simpleFormats, NumberFormat.Field field)263     private void simpleFormatsToModifiers(
264             String[] simpleFormats,
265             NumberFormat.Field field) {
266         StringBuilder sb = new StringBuilder();
267         for (StandardPlural plural : StandardPlural.VALUES) {
268             String simpleFormat = getWithPlural(simpleFormats, plural);
269             String compiled = SimpleFormatterImpl.compileToStringMinMaxArguments(simpleFormat, sb, 0, 1);
270             Modifier.Parameters parameters = new Modifier.Parameters();
271             parameters.obj = this;
272             parameters.signum = null;// Signum ignored
273             parameters.plural = plural;
274             modifiers.put(plural, new SimpleModifier(compiled, field, false, parameters));
275         }
276     }
277 
multiSimpleFormatsToModifiers( String[] leadFormats, String trailFormat, NumberFormat.Field field)278     private void multiSimpleFormatsToModifiers(
279             String[] leadFormats,
280             String trailFormat,
281             NumberFormat.Field field) {
282         StringBuilder sb = new StringBuilder();
283         String trailCompiled = SimpleFormatterImpl.compileToStringMinMaxArguments(trailFormat, sb, 1, 1);
284         for (StandardPlural plural : StandardPlural.VALUES) {
285             String leadFormat = getWithPlural(leadFormats, plural);
286             String compoundFormat = SimpleFormatterImpl.formatCompiledPattern(trailCompiled, leadFormat);
287             String compoundCompiled = SimpleFormatterImpl
288                     .compileToStringMinMaxArguments(compoundFormat, sb, 0, 1);
289             Modifier.Parameters parameters = new Modifier.Parameters();
290             parameters.obj = this;
291             parameters.signum = null; // Signum ignored
292             parameters.plural = plural;
293             modifiers.put(plural, new SimpleModifier(compoundCompiled, field, false, parameters));
294         }
295     }
296 
297     @Override
processQuantity(DecimalQuantity quantity)298     public MicroProps processQuantity(DecimalQuantity quantity) {
299         MicroProps micros = parent.processQuantity(quantity);
300         StandardPlural pluralForm = RoundingUtils.getPluralSafe(micros.rounder, rules, quantity);
301         micros.modOuter = modifiers.get(pluralForm);
302         return micros;
303     }
304 
305     @Override
getModifier(Signum signum, StandardPlural plural)306     public Modifier getModifier(Signum signum, StandardPlural plural) {
307         // Signum ignored
308         return modifiers.get(plural);
309     }
310 }
311