![JAR search and dependency download from the Maven repository](/logo.png)
com.ibm.icu.impl.number.LongNameHandler Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of icu4j Show documentation
Show all versions of icu4j Show documentation
International Component for Unicode for Java (ICU4J) is a mature, widely used Java library
providing Unicode and Globalization support
// © 2017 and later: Unicode, Inc. and others.
// License & terms of use: http://www.unicode.org/copyright.html#License
package com.ibm.icu.impl.number;
import java.util.EnumMap;
import java.util.Map;
import java.util.MissingResourceException;
import com.ibm.icu.impl.CurrencyData;
import com.ibm.icu.impl.ICUData;
import com.ibm.icu.impl.ICUResourceBundle;
import com.ibm.icu.impl.SimpleFormatterImpl;
import com.ibm.icu.impl.StandardPlural;
import com.ibm.icu.impl.UResource;
import com.ibm.icu.number.NumberFormatter.UnitWidth;
import com.ibm.icu.text.NumberFormat;
import com.ibm.icu.text.PluralRules;
import com.ibm.icu.util.Currency;
import com.ibm.icu.util.ICUException;
import com.ibm.icu.util.MeasureUnit;
import com.ibm.icu.util.ULocale;
import com.ibm.icu.util.UResourceBundle;
public class LongNameHandler implements MicroPropsGenerator, ModifierStore {
private static final int DNAM_INDEX = StandardPlural.COUNT;
private static final int PER_INDEX = StandardPlural.COUNT + 1;
private static final int ARRAY_LENGTH = StandardPlural.COUNT + 2;
private static int getIndex(String pluralKeyword) {
// pluralKeyword can also be "dnam" or "per"
if (pluralKeyword.equals("dnam")) {
return DNAM_INDEX;
} else if (pluralKeyword.equals("per")) {
return PER_INDEX;
} else {
return StandardPlural.fromString(pluralKeyword).ordinal();
}
}
private static String getWithPlural(String[] strings, StandardPlural plural) {
String result = strings[plural.ordinal()];
if (result == null) {
result = strings[StandardPlural.OTHER.ordinal()];
}
if (result == null) {
// There should always be data in the "other" plural variant.
throw new ICUException("Could not find data in 'other' plural variant");
}
return result;
}
//////////////////////////
/// BEGIN DATA LOADING ///
//////////////////////////
private static final class PluralTableSink extends UResource.Sink {
String[] outArray;
public PluralTableSink(String[] outArray) {
this.outArray = outArray;
}
@Override
public void put(UResource.Key key, UResource.Value value, boolean noFallback) {
UResource.Table pluralsTable = value.getTable();
for (int i = 0; pluralsTable.getKeyAndValue(i, key, value); ++i) {
int index = getIndex(key.toString());
if (outArray[index] != null) {
continue;
}
String formatString = value.getString();
outArray[index] = formatString;
}
}
}
// NOTE: outArray MUST have at least ARRAY_LENGTH entries. No bounds checking is performed.
private static void getMeasureData(
ULocale locale,
MeasureUnit unit,
UnitWidth width,
String[] outArray) {
PluralTableSink sink = new PluralTableSink(outArray);
ICUResourceBundle resource;
resource = (ICUResourceBundle) UResourceBundle.getBundleInstance(ICUData.ICU_UNIT_BASE_NAME,
locale);
StringBuilder key = new StringBuilder();
key.append("units");
if (width == UnitWidth.NARROW) {
key.append("Narrow");
} else if (width == UnitWidth.SHORT) {
key.append("Short");
}
key.append("/");
key.append(unit.getType());
key.append("/");
// Map duration-year-person, duration-week-person, etc. to duration-year, duration-week, ...
// TODO(ICU-20400): Get duration-*-person data properly with aliases.
if (unit.getSubtype().endsWith("-person")) {
key.append(unit.getSubtype(), 0, unit.getSubtype().length() - 7);
} else {
key.append(unit.getSubtype());
}
try {
resource.getAllItemsWithFallback(key.toString(), sink);
} catch (MissingResourceException e) {
throw new IllegalArgumentException("No data for unit " + unit + ", width " + width, e);
}
}
private static void getCurrencyLongNameData(ULocale locale, Currency currency, String[] outArray) {
// In ICU4J, this method gets a CurrencyData from CurrencyData.provider.
// TODO(ICU4J): Implement this without going through CurrencyData, like in ICU4C?
Map data = CurrencyData.provider.getInstance(locale, true).getUnitPatterns();
for (Map.Entry e : data.entrySet()) {
String pluralKeyword = e.getKey();
int index = getIndex(pluralKeyword);
String longName = currency.getName(locale, Currency.PLURAL_LONG_NAME, pluralKeyword, null);
String simpleFormat = e.getValue();
// Example pattern from data: "{0} {1}"
// Example output after find-and-replace: "{0} US dollars"
simpleFormat = simpleFormat.replace("{1}", longName);
// String compiled = SimpleFormatterImpl.compileToStringMinMaxArguments(simpleFormat, sb, 1,
// 1);
// SimpleModifier mod = new SimpleModifier(compiled, Field.CURRENCY, false);
outArray[index] = simpleFormat;
}
}
private static String getPerUnitFormat(ULocale locale, UnitWidth width) {
ICUResourceBundle resource;
resource = (ICUResourceBundle) UResourceBundle.getBundleInstance(ICUData.ICU_UNIT_BASE_NAME,
locale);
StringBuilder key = new StringBuilder();
key.append("units");
if (width == UnitWidth.NARROW) {
key.append("Narrow");
} else if (width == UnitWidth.SHORT) {
key.append("Short");
}
key.append("/compound/per");
try {
return resource.getStringWithFallback(key.toString());
} catch (MissingResourceException e) {
throw new IllegalArgumentException(
"Could not find x-per-y format for " + locale + ", width " + width);
}
}
////////////////////////
/// END DATA LOADING ///
////////////////////////
private final Map modifiers;
private final PluralRules rules;
private final MicroPropsGenerator parent;
private LongNameHandler(
Map modifiers,
PluralRules rules,
MicroPropsGenerator parent) {
this.modifiers = modifiers;
this.rules = rules;
this.parent = parent;
}
public static String getUnitDisplayName(ULocale locale, MeasureUnit unit, UnitWidth width) {
String[] measureData = new String[ARRAY_LENGTH];
getMeasureData(locale, unit, width, measureData);
return measureData[DNAM_INDEX];
}
public static LongNameHandler forCurrencyLongNames(
ULocale locale,
Currency currency,
PluralRules rules,
MicroPropsGenerator parent) {
String[] simpleFormats = new String[ARRAY_LENGTH];
getCurrencyLongNameData(locale, currency, simpleFormats);
// TODO(ICU4J): Reduce the number of object creations here?
Map modifiers = new EnumMap<>(
StandardPlural.class);
LongNameHandler result = new LongNameHandler(modifiers, rules, parent);
result.simpleFormatsToModifiers(simpleFormats, NumberFormat.Field.CURRENCY);
return result;
}
public static LongNameHandler forMeasureUnit(
ULocale locale,
MeasureUnit unit,
MeasureUnit perUnit,
UnitWidth width,
PluralRules rules,
MicroPropsGenerator parent) {
if (perUnit != null) {
// Compound unit: first try to simplify (e.g., meters per second is its own unit).
MeasureUnit simplified = MeasureUnit.resolveUnitPerUnit(unit, perUnit);
if (simplified != null) {
unit = simplified;
} else {
// No simplified form is available.
return forCompoundUnit(locale, unit, perUnit, width, rules, parent);
}
}
String[] simpleFormats = new String[ARRAY_LENGTH];
getMeasureData(locale, unit, width, simpleFormats);
// TODO(ICU4J): Reduce the number of object creations here?
Map modifiers = new EnumMap<>(
StandardPlural.class);
LongNameHandler result = new LongNameHandler(modifiers, rules, parent);
result.simpleFormatsToModifiers(simpleFormats, NumberFormat.Field.MEASURE_UNIT);
return result;
}
private static LongNameHandler forCompoundUnit(
ULocale locale,
MeasureUnit unit,
MeasureUnit perUnit,
UnitWidth width,
PluralRules rules,
MicroPropsGenerator parent) {
String[] primaryData = new String[ARRAY_LENGTH];
getMeasureData(locale, unit, width, primaryData);
String[] secondaryData = new String[ARRAY_LENGTH];
getMeasureData(locale, perUnit, width, secondaryData);
String perUnitFormat;
if (secondaryData[PER_INDEX] != null) {
perUnitFormat = secondaryData[PER_INDEX];
} else {
String rawPerUnitFormat = getPerUnitFormat(locale, width);
// rawPerUnitFormat is something like "{0}/{1}"; we need to substitute in the secondary unit.
// TODO: Lots of thrashing. Improve?
StringBuilder sb = new StringBuilder();
String compiled = SimpleFormatterImpl
.compileToStringMinMaxArguments(rawPerUnitFormat, sb, 2, 2);
String secondaryFormat = getWithPlural(secondaryData, StandardPlural.ONE);
String secondaryCompiled = SimpleFormatterImpl
.compileToStringMinMaxArguments(secondaryFormat, sb, 1, 1);
String secondaryString = SimpleFormatterImpl.getTextWithNoArguments(secondaryCompiled)
.trim();
perUnitFormat = SimpleFormatterImpl.formatCompiledPattern(compiled, "{0}", secondaryString);
}
Map modifiers = new EnumMap<>(
StandardPlural.class);
LongNameHandler result = new LongNameHandler(modifiers, rules, parent);
result.multiSimpleFormatsToModifiers(primaryData, perUnitFormat, NumberFormat.Field.MEASURE_UNIT);
return result;
}
private void simpleFormatsToModifiers(
String[] simpleFormats,
NumberFormat.Field field) {
StringBuilder sb = new StringBuilder();
for (StandardPlural plural : StandardPlural.VALUES) {
String simpleFormat = getWithPlural(simpleFormats, plural);
String compiled = SimpleFormatterImpl.compileToStringMinMaxArguments(simpleFormat, sb, 0, 1);
Modifier.Parameters parameters = new Modifier.Parameters();
parameters.obj = this;
parameters.signum = 0;
parameters.plural = plural;
modifiers.put(plural, new SimpleModifier(compiled, field, false, parameters));
}
}
private void multiSimpleFormatsToModifiers(
String[] leadFormats,
String trailFormat,
NumberFormat.Field field) {
StringBuilder sb = new StringBuilder();
String trailCompiled = SimpleFormatterImpl.compileToStringMinMaxArguments(trailFormat, sb, 1, 1);
for (StandardPlural plural : StandardPlural.VALUES) {
String leadFormat = getWithPlural(leadFormats, plural);
String compoundFormat = SimpleFormatterImpl.formatCompiledPattern(trailCompiled, leadFormat);
String compoundCompiled = SimpleFormatterImpl
.compileToStringMinMaxArguments(compoundFormat, sb, 0, 1);
Modifier.Parameters parameters = new Modifier.Parameters();
parameters.obj = this;
parameters.signum = 0;
parameters.plural = plural;
modifiers.put(plural, new SimpleModifier(compoundCompiled, field, false, parameters));
}
}
@Override
public MicroProps processQuantity(DecimalQuantity quantity) {
MicroProps micros = parent.processQuantity(quantity);
StandardPlural pluralForm = RoundingUtils.getPluralSafe(micros.rounder, rules, quantity);
micros.modOuter = modifiers.get(pluralForm);
return micros;
}
@Override
public Modifier getModifier(int signum, StandardPlural plural) {
return modifiers.get(plural);
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy