import com.ibm.icu.impl.PatternProps;
import com.ibm.icu.impl.StringSegment;
import com.ibm.icu.impl.number.MacroProps;
+import com.ibm.icu.number.NumberFormatter.DecimalSeparatorDisplay;
+import com.ibm.icu.number.NumberFormatter.GroupingStrategy;
+import com.ibm.icu.number.NumberFormatter.SignDisplay;
import com.ibm.icu.number.NumberFormatter.UnitWidth;
+import com.ibm.icu.text.NumberingSystem;
import com.ibm.icu.util.Currency;
import com.ibm.icu.util.Currency.CurrencyUsage;
import com.ibm.icu.util.MeasureUnit;
class NumberSkeletonImpl {
static enum StemType {
- OTHER, ROUNDER, FRACTION_ROUNDER, MAYBE_INCREMENT_ROUNDER, CURRENCY_ROUNDER, MEASURE_UNIT, UNIT_WIDTH
+ OTHER,
+ COMPACT_NOTATION,
+ SCIENTIFIC_NOTATION,
+ SIMPLE_NOTATION,
+ NO_UNIT,
+ CURRENCY,
+ MEASURE_UNIT,
+ PER_MEASURE_UNIT,
+ ROUNDER,
+ FRACTION_ROUNDER,
+ MAYBE_INCREMENT_ROUNDER,
+ CURRENCY_ROUNDER,
+ GROUPING,
+ INTEGER_WIDTH,
+ LATIN,
+ NUMBERING_SYSTEM,
+ UNIT_WIDTH,
+ SIGN_DISPLAY,
+ DECIMAL_DISPLAY
}
static class SkeletonDataStructure {
static final SkeletonDataStructure skeletonData = new SkeletonDataStructure();
static {
+ skeletonData.put(StemType.COMPACT_NOTATION, "compact-short", Notation.compactShort());
+ skeletonData.put(StemType.COMPACT_NOTATION, "compact-long", Notation.compactLong());
+ skeletonData.put(StemType.SCIENTIFIC_NOTATION, "scientific", Notation.scientific());
+ skeletonData.put(StemType.SCIENTIFIC_NOTATION, "engineering", Notation.engineering());
+ skeletonData.put(StemType.SIMPLE_NOTATION, "simple-notation", Notation.simple());
+
+ skeletonData.put(StemType.NO_UNIT, "base-unit", NoUnit.BASE);
+ skeletonData.put(StemType.NO_UNIT, "percent", NoUnit.PERCENT);
+ skeletonData.put(StemType.NO_UNIT, "permille", NoUnit.PERMILLE);
+
skeletonData.put(StemType.ROUNDER, "round-integer", Rounder.integer());
skeletonData.put(StemType.ROUNDER, "round-unlimited", Rounder.unlimited());
skeletonData.put(StemType.ROUNDER,
Rounder.currency(CurrencyUsage.STANDARD));
skeletonData.put(StemType.ROUNDER, "round-currency-cash", Rounder.currency(CurrencyUsage.CASH));
+ skeletonData.put(StemType.GROUPING, "group-off", GroupingStrategy.OFF);
+ skeletonData.put(StemType.GROUPING, "group-min2", GroupingStrategy.MIN2);
+ skeletonData.put(StemType.GROUPING, "group-auto", GroupingStrategy.AUTO);
+ skeletonData.put(StemType.GROUPING, "group-on-aligned", GroupingStrategy.ON_ALIGNED);
+ skeletonData.put(StemType.GROUPING, "group-thousands", GroupingStrategy.THOUSANDS);
+
+ skeletonData.put(StemType.LATIN, "latin", NumberingSystem.LATIN);
+
skeletonData.put(StemType.UNIT_WIDTH, "unit-width-narrow", UnitWidth.NARROW);
skeletonData.put(StemType.UNIT_WIDTH, "unit-width-short", UnitWidth.SHORT);
skeletonData.put(StemType.UNIT_WIDTH, "unit-width-full-name", UnitWidth.FULL_NAME);
skeletonData.put(StemType.UNIT_WIDTH, "unit-width-iso-code", UnitWidth.ISO_CODE);
skeletonData.put(StemType.UNIT_WIDTH, "unit-width-hidden", UnitWidth.HIDDEN);
+
+ skeletonData.put(StemType.SIGN_DISPLAY, "sign-auto", SignDisplay.AUTO);
+ skeletonData.put(StemType.SIGN_DISPLAY, "sign-always", SignDisplay.ALWAYS);
+ skeletonData.put(StemType.SIGN_DISPLAY, "sign-never", SignDisplay.NEVER);
+ skeletonData.put(StemType.SIGN_DISPLAY, "sign-accounting", SignDisplay.ACCOUNTING);
+ skeletonData.put(StemType.SIGN_DISPLAY, "sign-accounting-always", SignDisplay.ACCOUNTING_ALWAYS);
+ skeletonData.put(StemType.SIGN_DISPLAY, "sign-except-zero", SignDisplay.EXCEPT_ZERO);
+ skeletonData.put(StemType.SIGN_DISPLAY,
+ "sign-accounting-except-zero",
+ SignDisplay.ACCOUNTING_EXCEPT_ZERO);
+
+ skeletonData.put(StemType.DECIMAL_DISPLAY, "decimal-auto", DecimalSeparatorDisplay.AUTO);
+ skeletonData.put(StemType.DECIMAL_DISPLAY, "decimal-always", DecimalSeparatorDisplay.ALWAYS);
}
private static final Map<String, UnlocalizedNumberFormatter> cache = new ConcurrentHashMap<String, UnlocalizedNumberFormatter>();
switch (stem) {
case MAYBE_INCREMENT_ROUNDER:
case MEASURE_UNIT:
+ case PER_MEASURE_UNIT:
+ case CURRENCY:
+ case INTEGER_WIDTH:
+ case NUMBERING_SYSTEM:
throw new SkeletonSyntaxException("Stem requires an option", segment);
default:
break;
if (stem != null) {
Object value = skeletonData.stemToValue(content);
switch (stem) {
+ case COMPACT_NOTATION:
+ case SCIENTIFIC_NOTATION:
+ case SIMPLE_NOTATION:
+ checkNull(macros.notation, content);
+ macros.notation = (Notation) value;
+ break;
+ case NO_UNIT:
+ checkNull(macros.unit, content);
+ macros.unit = (NoUnit) value;
+ break;
case ROUNDER:
checkNull(macros.rounder, content);
macros.rounder = (Rounder) value;
break;
+ case GROUPING:
+ checkNull(macros.grouping, content);
+ macros.grouping = value;
+ break;
+ case LATIN:
+ checkNull(macros.symbols, content);
+ macros.symbols = value;
+ break;
case UNIT_WIDTH:
checkNull(macros.unitWidth, content);
macros.unitWidth = (UnitWidth) value;
break;
+ case SIGN_DISPLAY:
+ checkNull(macros.sign, content);
+ macros.sign = (SignDisplay) value;
+ break;
+ case DECIMAL_DISPLAY:
+ checkNull(macros.decimal, content);
+ macros.decimal = (DecimalSeparatorDisplay) value;
+ break;
default:
assert false;
}
// Second try: literal stems that require an option
if (content.equals("round-increment")) {
+ checkNull(macros.rounder, content);
return StemType.MAYBE_INCREMENT_ROUNDER;
} else if (content.equals("measure-unit")) {
+ checkNull(macros.unit, content);
return StemType.MEASURE_UNIT;
- }
-
- // Second try: stem "blueprint" syntax
+ } else if (content.equals("per-measure-unit")) {
+ checkNull(macros.perUnit, content);
+ return StemType.PER_MEASURE_UNIT;
+ } else if (content.equals("currency")) {
+ checkNull(macros.unit, content);
+ return StemType.CURRENCY;
+ } else if (content.equals("integer-width")) {
+ checkNull(macros.integerWidth, content);
+ return StemType.INTEGER_WIDTH;
+ } else if (content.equals("numbering-system")) {
+ checkNull(macros.symbols, content);
+ return StemType.NUMBERING_SYSTEM;
+ }
+
+ // Third try: stem "blueprint" syntax
switch (content.charAt(0)) {
case '.':
stem = StemType.FRACTION_ROUNDER;
+ checkNull(macros.rounder, content);
parseFractionStem(content, macros);
break;
case '@':
stem = StemType.ROUNDER;
+ checkNull(macros.rounder, content);
parseDigitsStem(content, macros);
break;
}
}
private static StemType parseOption(StemType stem, CharSequence content, MacroProps macros) {
+
+ ///// Required options: /////
+
+ switch (stem) {
+ case CURRENCY:
+ parseCurrencyOption(content, macros);
+ return StemType.OTHER;
+ case MEASURE_UNIT:
+ parseMeasureUnitOption(content, macros);
+ return StemType.OTHER;
+ case PER_MEASURE_UNIT:
+ parseMeasurePerUnitOption(content, macros);
+ return StemType.OTHER;
+ case MAYBE_INCREMENT_ROUNDER:
+ parseIncrementOption(content, macros);
+ return StemType.ROUNDER;
+ case INTEGER_WIDTH:
+ parseIntegerWidthOption(content, macros);
+ return StemType.OTHER;
+ case NUMBERING_SYSTEM:
+ parseNumberingSystemOption(content, macros);
+ return StemType.OTHER;
+ }
+
+ ///// Non-required options: /////
+
+ // Scientific options
+ switch (stem) {
+ case SCIENTIFIC_NOTATION:
+ if (parseExponentWidthOption(content, macros)) {
+ return StemType.SCIENTIFIC_NOTATION;
+ }
+ if (parseExponentSignOption(content, macros)) {
+ return StemType.SCIENTIFIC_NOTATION;
+ }
+ }
+
// Frac-sig option
switch (stem) {
case FRACTION_ROUNDER:
}
}
- // Increment option
- switch (stem) {
- case MAYBE_INCREMENT_ROUNDER:
- // The increment option is required.
- parseIncrementOption(content, macros);
- return StemType.ROUNDER;
- }
-
// Rounding mode option
switch (stem) {
case ROUNDER:
case FRACTION_ROUNDER:
case CURRENCY_ROUNDER:
if (parseRoundingModeOption(content, macros)) {
- break;
+ return StemType.ROUNDER;
}
}
- // Measure unit option
- switch (stem) {
- case MEASURE_UNIT:
- // The measure unit option is required.
- parseMeasureUnitOption(content, macros);
- return StemType.OTHER;
- }
-
// Unknown option
throw new SkeletonSyntaxException("Unknown option", content);
}
- /////
-
private static void generateSkeleton(MacroProps macros, StringBuilder sb) {
- if (macros.rounder != null) {
- generateRoundingValue(macros, sb);
+ if (macros.notation != null) {
+ generateNotationValue(macros, sb);
sb.append(' ');
}
if (macros.unit != null) {
generateUnitValue(macros, sb);
sb.append(' ');
}
+ if (macros.perUnit != null) {
+ generatePerUnitValue(macros, sb);
+ sb.append(' ');
+ }
+ if (macros.rounder != null) {
+ generateRoundingValue(macros, sb);
+ sb.append(' ');
+ }
+ if (macros.grouping != null) {
+ generateGroupingValue(macros, sb);
+ sb.append(' ');
+ }
+ if (macros.integerWidth != null) {
+ generateIntegerWidthValue(macros, sb);
+ sb.append(' ');
+ }
+ if (macros.symbols != null) {
+ generateSymbolsValue(macros, sb);
+ sb.append(' ');
+ }
if (macros.unitWidth != null) {
generateUnitWidthValue(macros, sb);
sb.append(' ');
}
+ if (macros.sign != null) {
+ generateSignValue(macros, sb);
+ sb.append(' ');
+ }
+ if (macros.decimal != null) {
+ generateDecimalValue(macros, sb);
+ sb.append(' ');
+ }
// Remove the trailing space
if (sb.length() > 0) {
/////
+ private static boolean parseExponentWidthOption(CharSequence content, MacroProps macros) {
+ if (content.charAt(0) != '+') {
+ return false;
+ }
+ int offset = 1;
+ int minExp = 0;
+ for (; offset < content.length(); offset++) {
+ if (content.charAt(offset) == 'e') {
+ minExp++;
+ } else {
+ break;
+ }
+ }
+ if (offset < content.length()) {
+ return false;
+ }
+ // Use the public APIs to enforce bounds checking
+ macros.notation = ((ScientificNotation) macros.notation).withMinExponentDigits(minExp);
+ return true;
+ }
+
+ private static void generateExponentWidthOption(int minInt, int maxInt, StringBuilder sb) {
+ sb.append('+');
+ appendMultiple(sb, 'e', minInt);
+ }
+
+ private static boolean parseExponentSignOption(CharSequence content, MacroProps macros) {
+ Object value = skeletonData.stemToValue(content);
+ if (value != null && value instanceof SignDisplay) {
+ macros.notation = ((ScientificNotation) macros.notation)
+ .withExponentSignDisplay((SignDisplay) value);
+ return true;
+ }
+ return false;
+ }
+
+ private static void generateCurrencyOption(Currency currency, StringBuilder sb) {
+ sb.append(currency.getCurrencyCode());
+ }
+
+ private static void parseCurrencyOption(CharSequence content, MacroProps macros) {
+ String currencyCode = content.subSequence(0, content.length()).toString();
+ try {
+ macros.unit = Currency.getInstance(currencyCode);
+ } catch (IllegalArgumentException e) {
+ throw new SkeletonSyntaxException("Invalid currency", content, e);
+ }
+ }
+
+ private static void parseMeasureUnitOption(CharSequence content, MacroProps macros) {
+ // NOTE: The category (type) of the unit is guaranteed to be a valid subtag (alphanumeric)
+ // http://unicode.org/reports/tr35/#Validity_Data
+ int firstHyphen = 0;
+ while (firstHyphen < content.length() && content.charAt(firstHyphen) != '-') {
+ firstHyphen++;
+ }
+ if (firstHyphen == content.length()) {
+ throw new SkeletonSyntaxException("Invalid measure unit option", content);
+ }
+ String type = content.subSequence(0, firstHyphen).toString();
+ String subType = content.subSequence(firstHyphen + 1, content.length()).toString();
+ Set<MeasureUnit> units = MeasureUnit.getAvailable(type);
+ for (MeasureUnit unit : units) {
+ if (subType.equals(unit.getSubtype())) {
+ macros.unit = unit;
+ return;
+ }
+ }
+ throw new SkeletonSyntaxException("Unknown measure unit", content);
+ }
+
+ private static void generateMeasureUnitOption(MeasureUnit unit, StringBuilder sb) {
+ sb.append(unit.getType() + "-" + unit.getSubtype());
+ }
+
+ private static void parseMeasurePerUnitOption(CharSequence content, MacroProps macros) {
+ // A little bit of a hack: safe the current unit (numerator), call the main measure unit parsing
+ // code, put back the numerator unit, and put the new unit into per-unit.
+ MeasureUnit numerator = macros.unit;
+ parseMeasureUnitOption(content, macros);
+ macros.perUnit = macros.unit;
+ macros.unit = numerator;
+ }
+
private static void parseFractionStem(CharSequence content, MacroProps macros) {
assert content.charAt(0) == '.';
int offset = 1;
}
FractionRounder oldRounder = (FractionRounder) macros.rounder;
// A little bit of a hack: parse the option as a digits stem, and extract the min/max sig from
- // the new Rounder saved into the macros
+ // the new Rounder saved into the macros.
parseDigitsStem(content, macros);
Rounder.SignificantRounderImpl intermediate = (Rounder.SignificantRounderImpl) macros.rounder;
if (intermediate.maxSig == -1) {
sb.append(mode.toString());
}
- private static void parseMeasureUnitOption(CharSequence content, MacroProps macros) {
- // NOTE: The category (type) of the unit is guaranteed to be a valid subtag (alphanumeric)
- // http://unicode.org/reports/tr35/#Validity_Data
- int firstHyphen = 0;
- while (firstHyphen < content.length() && content.charAt(firstHyphen) != '-') {
- firstHyphen++;
+ private static void parseIntegerWidthOption(CharSequence content, MacroProps macros) {
+ int offset = 0;
+ int minInt = 0;
+ int maxInt;
+ if (content.charAt(0) == '+') {
+ maxInt = -1;
+ offset++;
+ } else {
+ maxInt = 0;
}
- String type = content.subSequence(0, firstHyphen).toString();
- String subType = content.subSequence(firstHyphen + 1, content.length()).toString();
- Set<MeasureUnit> units = MeasureUnit.getAvailable(type);
- for (MeasureUnit unit : units) {
- if (subType.equals(unit.getSubtype())) {
- macros.unit = unit;
- return;
+ for (; offset < content.length(); offset++) {
+ if (content.charAt(offset) == '#') {
+ maxInt++;
+ } else {
+ break;
+ }
+ }
+ if (offset < content.length()) {
+ for (; offset < content.length(); offset++) {
+ if (content.charAt(offset) == '0') {
+ minInt++;
+ } else {
+ break;
+ }
}
}
- throw new SkeletonSyntaxException("Unknown unit", content);
+ if (maxInt != -1) {
+ maxInt += minInt;
+ }
+ if (offset < content.length()) {
+ throw new SkeletonSyntaxException("Invalid integer width stem", content);
+ }
+ // Use the public APIs to enforce bounds checking
+ if (maxInt == -1) {
+ macros.integerWidth = IntegerWidth.zeroFillTo(minInt);
+ } else {
+ macros.integerWidth = IntegerWidth.zeroFillTo(minInt).truncateAt(maxInt);
+ }
}
- private static void generateMeasureUnitOption(MeasureUnit unit, StringBuilder sb) {
- sb.append(unit.getType() + "-" + unit.getSubtype());
+ private static void generateIntegerWidthOption(int minInt, int maxInt, StringBuilder sb) {
+ if (maxInt == -1) {
+ sb.append('+');
+ } else {
+ appendMultiple(sb, '#', maxInt - minInt);
+ }
+ appendMultiple(sb, '0', minInt);
+ }
+
+ private static void parseNumberingSystemOption(CharSequence content, MacroProps macros) {
+ String nsName = content.subSequence(0, content.length()).toString();
+ NumberingSystem ns = NumberingSystem.getInstanceByName(nsName);
+ if (ns == null) {
+ throw new SkeletonSyntaxException("Unknown numbering system", content);
+ }
+ macros.symbols = ns;
+ }
+
+ private static void generateNumberingSystemOption(NumberingSystem ns, StringBuilder sb) {
+ sb.append(ns.getName());
}
/////
+ private static void generateNotationValue(MacroProps macros, StringBuilder sb) {
+ // Check for literals
+ String literal = skeletonData.valueToStem(macros.notation);
+ if (literal != null) {
+ sb.append(literal);
+ return;
+ }
+
+ // Generate the stem
+ if (macros.notation instanceof CompactNotation) {
+ // Compact notation generated from custom data (not supported in skeleton)
+ // The other compact notations are literals
+ } else if (macros.notation instanceof ScientificNotation) {
+ ScientificNotation impl = (ScientificNotation) macros.notation;
+ if (impl.engineeringInterval == 3) {
+ sb.append("engineering");
+ } else {
+ sb.append("scientific");
+ }
+ if (impl.minExponentDigits > 1) {
+ sb.append('/');
+ generateExponentWidthOption(impl.minExponentDigits, -1, sb);
+ }
+ if (impl.exponentSignDisplay != SignDisplay.AUTO) {
+ sb.append('/');
+ sb.append(skeletonData.valueToStem(impl.exponentSignDisplay));
+ }
+ } else {
+ assert macros.notation instanceof SimpleNotation;
+ sb.append("notation-simple");
+ }
+ }
+
+ private static void generateUnitValue(MacroProps macros, StringBuilder sb) {
+ // Check for literals
+ String literal = skeletonData.valueToStem(macros.unit);
+ if (literal != null) {
+ sb.append(literal);
+ return;
+ }
+
+ // Generate the stem
+ if (macros.unit instanceof Currency) {
+ sb.append("currency/");
+ generateCurrencyOption((Currency) macros.unit, sb);
+ } else if (macros.unit instanceof NoUnit) {
+ // This should be taken care of by the literals.
+ assert false;
+ } else {
+ sb.append("measure-unit/");
+ generateMeasureUnitOption(macros.unit, sb);
+ }
+ }
+
+ private static void generatePerUnitValue(MacroProps macros, StringBuilder sb) {
+ // Per-units are currently expected to be only MeasureUnits.
+ if (macros.unit instanceof Currency || macros.unit instanceof NoUnit) {
+ assert false;
+ } else {
+ sb.append("per-measure-unit/");
+ generateMeasureUnitOption(macros.perUnit, sb);
+ }
+ }
+
private static void generateRoundingValue(MacroProps macros, StringBuilder sb) {
// Check for literals
String literal = skeletonData.valueToStem(macros.rounder);
}
}
- private static void generateUnitValue(MacroProps macros, StringBuilder sb) {
- // Check for literals
- String literal = skeletonData.valueToStem(macros.unit);
- if (literal != null) {
- sb.append(literal);
- return;
- }
+ private static void generateGroupingValue(MacroProps macros, StringBuilder sb) {
+ appendExpectedLiteral(macros.grouping, sb);
+ }
- // Generate the stem
- if (macros.unit instanceof Currency) {
- // TODO
- } else if (macros.unit instanceof NoUnit) {
- // TODO
+ private static void generateIntegerWidthValue(MacroProps macros, StringBuilder sb) {
+ sb.append("integer-width/");
+ generateIntegerWidthOption(macros.integerWidth.minInt, macros.integerWidth.maxInt, sb);
+ }
+
+ private static void generateSymbolsValue(MacroProps macros, StringBuilder sb) {
+ if (macros.symbols instanceof NumberingSystem) {
+ NumberingSystem ns = (NumberingSystem) macros.symbols;
+ if (ns.getName().equals("latn")) {
+ sb.append("latin");
+ } else {
+ sb.append("numbering-system/");
+ generateNumberingSystemOption(ns, sb);
+ }
} else {
- sb.append("measure-unit/");
- generateMeasureUnitOption(macros.unit, sb);
+ // DecimalFormatSymbols (not supported in skeleton)
}
}
private static void generateUnitWidthValue(MacroProps macros, StringBuilder sb) {
- // There should be a literal.
- String literal = skeletonData.valueToStem(macros.unitWidth);
- assert literal != null;
- sb.append(literal);
+ appendExpectedLiteral(macros.unitWidth, sb);
+ }
+
+ private static void generateSignValue(MacroProps macros, StringBuilder sb) {
+ appendExpectedLiteral(macros.sign, sb);
+ }
+
+ private static void generateDecimalValue(MacroProps macros, StringBuilder sb) {
+ appendExpectedLiteral(macros.decimal, sb);
}
/////
sb.appendCodePoint(cp);
}
}
+
+ private static void appendExpectedLiteral(Object value, StringBuilder sb) {
+ String literal = skeletonData.valueToStem(value);
+ assert literal != null;
+ sb.append(literal);
+ }
}
assertFormatDescendingBig(
"Big Simple",
- "",
+ "simple-notation",
NumberFormatter.with().notation(Notation.simple()),
ULocale.ENGLISH,
"87,650,000",
public void notationScientific() {
assertFormatDescending(
"Scientific",
- "E",
+ "scientific",
NumberFormatter.with().notation(Notation.scientific()),
ULocale.ENGLISH,
"8.765E4",
assertFormatDescending(
"Engineering",
- "E3",
+ "engineering",
NumberFormatter.with().notation(Notation.engineering()),
ULocale.ENGLISH,
"87.65E3",
assertFormatDescending(
"Scientific sign always shown",
- "E+",
+ "scientific/sign-always",
NumberFormatter.with().notation(Notation.scientific().withExponentSignDisplay(SignDisplay.ALWAYS)),
ULocale.ENGLISH,
"8.765E+4",
assertFormatDescending(
"Scientific min exponent digits",
- "E00",
+ "scientific/+ee",
NumberFormatter.with().notation(Notation.scientific().withMinExponentDigits(2)),
ULocale.ENGLISH,
"8.765E04",
assertFormatSingle(
"Scientific Negative",
- "E",
+ "scientific",
NumberFormatter.with().notation(Notation.scientific()),
ULocale.ENGLISH,
-1000000,
public void notationCompact() {
assertFormatDescendingBig(
"Compact Short",
- "C",
+ "compact-short",
NumberFormatter.with().notation(Notation.compactShort()),
ULocale.ENGLISH,
"88M",
assertFormatDescendingBig(
"Compact Long",
- "CC",
+ "compact-long",
NumberFormatter.with().notation(Notation.compactLong()),
ULocale.ENGLISH,
"88 million",
assertFormatDescending(
"Compact Short Currency",
- "C $USD",
+ "compact-short currency/USD",
NumberFormatter.with().notation(Notation.compactShort()).unit(USD),
ULocale.ENGLISH,
"$88K",
assertFormatDescending(
"Compact Short with ISO Currency",
- "C $USD unit-width=ISO_CODE",
+ "compact-short currency/USD unit-width-iso-code",
NumberFormatter.with().notation(Notation.compactShort()).unit(USD).unitWidth(UnitWidth.ISO_CODE),
ULocale.ENGLISH,
"USD 88K",
assertFormatDescending(
"Compact Short with Long Name Currency",
- "C $USD unit-width=FULL_NAME",
+ "compact-short currency/USD unit-width-full-name",
NumberFormatter.with().notation(Notation.compactShort()).unit(USD).unitWidth(UnitWidth.FULL_NAME),
ULocale.ENGLISH,
"88K US dollars",
// This test case should be fixed when proper compact long currency patterns are added.
assertFormatDescending(
"Compact Long Currency",
- "CC $USD",
+ "compact-long currency/USD",
NumberFormatter.with().notation(Notation.compactLong()).unit(USD),
ULocale.ENGLISH,
"$88K", // should be something like "$88 thousand"
// This test case should be fixed when proper compact long currency patterns are added.
assertFormatDescending(
"Compact Long with ISO Currency",
- "CC $USD unit-width=ISO_CODE",
+ "compact-long currency/USD unit-width-iso-code",
NumberFormatter.with().notation(Notation.compactLong()).unit(USD).unitWidth(UnitWidth.ISO_CODE),
ULocale.ENGLISH,
"USD 88K", // should be something like "USD 88 thousand"
// TODO: This behavior could be improved and should be revisited.
assertFormatDescending(
"Compact Long with Long Name Currency",
- "CC $USD unit-width=FULL_NAME",
+ "compact-long currency/USD unit-width-full-name",
NumberFormatter.with().notation(Notation.compactLong()).unit(USD).unitWidth(UnitWidth.FULL_NAME),
ULocale.ENGLISH,
"88 thousand US dollars",
assertFormatSingle(
"Compact Plural One",
- "CC",
+ "compact-long",
NumberFormatter.with().notation(Notation.compactLong()),
ULocale.forLanguageTag("es"),
1000000,
assertFormatSingle(
"Compact Plural Other",
- "CC",
+ "compact-long",
NumberFormatter.with().notation(Notation.compactLong()),
ULocale.forLanguageTag("es"),
2000000,
assertFormatSingle(
"Compact with Negative Sign",
- "C",
+ "compact-short",
NumberFormatter.with().notation(Notation.compactShort()),
ULocale.ENGLISH,
-9876543.21,
assertFormatSingle(
"Compact Rounding",
- "C",
+ "compact-short",
NumberFormatter.with().notation(Notation.compactShort()),
ULocale.ENGLISH,
990000,
assertFormatSingle(
"Compact Rounding",
- "C",
+ "compact-short",
NumberFormatter.with().notation(Notation.compactShort()),
ULocale.ENGLISH,
999000,
assertFormatSingle(
"Compact Rounding",
- "C",
+ "compact-short",
NumberFormatter.with().notation(Notation.compactShort()),
ULocale.ENGLISH,
999900,
assertFormatSingle(
"Compact Rounding",
- "C",
+ "compact-short",
NumberFormatter.with().notation(Notation.compactShort()),
ULocale.ENGLISH,
9900000,
assertFormatSingle(
"Compact Rounding",
- "C",
+ "compact-short",
NumberFormatter.with().notation(Notation.compactShort()),
ULocale.ENGLISH,
9990000,
compactCustomData.put("1000", entry);
assertFormatSingle(
"Compact Somali No Figure",
- "",
+ null, // feature not supported in skeleton
NumberFormatter.with().notation(CompactNotation.forCustomData(compactCustomData)),
ULocale.ENGLISH,
1000,
assertFormatSingleMeasure(
"Meters with Measure Input",
- "unit-width=FULL_NAME",
+ "unit-width-full-name",
NumberFormatter.with().unitWidth(UnitWidth.FULL_NAME),
ULocale.ENGLISH,
new Measure(5.43, MeasureUnit.METER),
assertFormatSingleMeasure(
"Measure format method takes precedence over fluent chain",
- "U:length:meter",
+ "measure-unit/length-meter",
NumberFormatter.with().unit(MeasureUnit.METER),
ULocale.ENGLISH,
new Measure(5.43, USD),
assertFormatSingle(
"Meters with Negative Sign",
- "U:length:meter",
+ "measure-unit/length-meter",
NumberFormatter.with().unit(MeasureUnit.METER),
ULocale.ENGLISH,
-9876543.21,
// The locale string "सान" appears only in brx.txt:
assertFormatSingle(
"Interesting Data Fallback 1",
- "U:duration:day unit-width=FULL_NAME",
+ "measure-unit/duration-day unit-width-full-name",
NumberFormatter.with().unit(MeasureUnit.DAY).unitWidth(UnitWidth.FULL_NAME),
ULocale.forLanguageTag("brx"),
5.43,
// Requires following the alias from unitsNarrow to unitsShort:
assertFormatSingle(
"Interesting Data Fallback 2",
- "U:duration:day unit-width=NARROW",
+ "measure-unit/duration-day unit-width-narrow",
NumberFormatter.with().unit(MeasureUnit.DAY).unitWidth(UnitWidth.NARROW),
ULocale.forLanguageTag("brx"),
5.43,
// requiring fallback to the root.
assertFormatSingle(
"Interesting Data Fallback 3",
- "U:area:square-meter unit-width=NARROW",
+ "measure-unit/area-square-meter unit-width-narrow",
NumberFormatter.with().unit(MeasureUnit.SQUARE_METER).unitWidth(UnitWidth.NARROW),
ULocale.forLanguageTag("en-GB"),
5.43,
// NOTE: This example is in the documentation.
assertFormatSingle(
"MeasureUnit Difference between Narrow and Short (Narrow Version)",
- "",
+ "measure-unit/temperature-fahrenheit unit-width-narrow",
NumberFormatter.with().unit(MeasureUnit.FAHRENHEIT).unitWidth(UnitWidth.NARROW),
ULocale.forLanguageTag("es-US"),
5.43,
assertFormatSingle(
"MeasureUnit Difference between Narrow and Short (Short Version)",
- "",
+ "measure-unit/temperature-fahrenheit unit-width-short",
NumberFormatter.with().unit(MeasureUnit.FAHRENHEIT).unitWidth(UnitWidth.SHORT),
ULocale.forLanguageTag("es-US"),
5.43,
assertFormatSingle(
"MeasureUnit form without {0} in CLDR pattern",
- "",
+ "measure-unit/temperature-kelvin unit-width-full-name",
NumberFormatter.with().unit(MeasureUnit.KELVIN).unitWidth(UnitWidth.FULL_NAME),
ULocale.forLanguageTag("es-MX"),
1,
assertFormatSingle(
"MeasureUnit form without {0} in CLDR pattern and wide base form",
- "",
+ "measure-unit/temperature-kelvin .0000000000 unit-width-full-name",
NumberFormatter.with()
- .rounding(Rounder.fixedFraction(20))
+ .rounding(Rounder.fixedFraction(10))
.unit(MeasureUnit.KELVIN)
.unitWidth(UnitWidth.FULL_NAME),
ULocale.forLanguageTag("es-MX"),
public void unitCompoundMeasure() {
assertFormatDescending(
"Meters Per Second Short (unit that simplifies)",
- "",
+ "measure-unit/length-meter per-measure-unit/duration-second",
NumberFormatter.with().unit(MeasureUnit.METER).perUnit(MeasureUnit.SECOND),
ULocale.ENGLISH,
"87,650 m/s",
assertFormatDescending(
"Pounds Per Square Mile Short (secondary unit has per-format)",
- "",
+ "measure-unit/mass-pound per-measure-unit/area-square-mile",
NumberFormatter.with().unit(MeasureUnit.POUND).perUnit(MeasureUnit.SQUARE_MILE),
ULocale.ENGLISH,
"87,650 lb/mi²",
assertFormatDescending(
"Joules Per Furlong Short (unit with no simplifications or special patterns)",
- "",
+ "measure-unit/energy-joule per-measure-unit/length-furlong",
NumberFormatter.with().unit(MeasureUnit.JOULE).perUnit(MeasureUnit.FURLONG),
ULocale.ENGLISH,
"87,650 J/fur",
public void unitCurrency() {
assertFormatDescending(
"Currency",
- "$GBP",
+ "currency/GBP",
NumberFormatter.with().unit(GBP),
ULocale.ENGLISH,
"£87,650.00",
assertFormatDescending(
"Currency ISO",
- "$GBP unit-width=ISO_CODE",
+ "currency/GBP unit-width-iso-code",
NumberFormatter.with().unit(GBP).unitWidth(UnitWidth.ISO_CODE),
ULocale.ENGLISH,
"GBP 87,650.00",
assertFormatDescending(
"Currency Long Name",
- "$GBP unit-width=FULL_NAME",
+ "currency/GBP unit-width-full-name",
NumberFormatter.with().unit(GBP).unitWidth(UnitWidth.FULL_NAME),
ULocale.ENGLISH,
"87,650.00 British pounds",
assertFormatDescending(
"Currency Hidden",
- "$GBP unit-width=HIDDEN",
+ "currency/GBP unit-width-hidden",
NumberFormatter.with().unit(GBP).unitWidth(UnitWidth.HIDDEN),
ULocale.ENGLISH,
"87,650.00",
assertFormatSingle(
"Currency Long Name from Pattern Syntax",
- "$GBP F0 grouping=none integer-width=1- symbols=loc:en sign=AUTO decimal=AUTO",
+ null,
NumberFormatter.fromDecimalFormat(
PatternStringParser.parseToProperties("0 ¤¤¤"),
DecimalFormatSymbols.getInstance(ULocale.ENGLISH),
assertFormatSingle(
"Currency with Negative Sign",
- "$GBP",
+ "currency/GBP",
NumberFormatter.with().unit(GBP),
ULocale.ENGLISH,
-9876543.21,
// NOTE: This example is in the documentation.
assertFormatSingle(
"Currency Difference between Narrow and Short (Narrow Version)",
- "",
+ "currency/USD unit-width-narrow",
NumberFormatter.with().unit(USD).unitWidth(UnitWidth.NARROW),
ULocale.forLanguageTag("en-CA"),
5.43,
assertFormatSingle(
"Currency Difference between Narrow and Short (Short Version)",
- "",
+ "currency/USD unit-width-short",
NumberFormatter.with().unit(USD).unitWidth(UnitWidth.SHORT),
ULocale.forLanguageTag("en-CA"),
5.43,
assertFormatSingle(
"Currency-dependent format (Control)",
- "",
+ "currency/USD unit-width-short",
NumberFormatter.with().unit(USD).unitWidth(UnitWidth.SHORT),
ULocale.forLanguageTag("ca"),
444444.55,
assertFormatSingle(
"Currency-dependent format (Test)",
- "",
+ "currency/ESP unit-width-short",
NumberFormatter.with().unit(ESP).unitWidth(UnitWidth.SHORT),
ULocale.forLanguageTag("ca"),
444444.55,
assertFormatSingle(
"Currency-dependent symbols (Control)",
- "",
+ "currency/USD unit-width-short",
NumberFormatter.with().unit(USD).unitWidth(UnitWidth.SHORT),
ULocale.forLanguageTag("pt-PT"),
444444.55,
// width space), and they set the decimal separator to the $ symbol.
assertFormatSingle(
"Currency-dependent symbols (Test)",
- "",
+ "currency/PTE unit-width-short",
NumberFormatter.with().unit(PTE).unitWidth(UnitWidth.SHORT),
ULocale.forLanguageTag("pt-PT"),
444444.55,
assertFormatSingle(
"Currency-dependent symbols (Test)",
- "",
+ "currency/PTE unit-width-narrow",
NumberFormatter.with().unit(PTE).unitWidth(UnitWidth.NARROW),
ULocale.forLanguageTag("pt-PT"),
444444.55,
assertFormatSingle(
"Currency-dependent symbols (Test)",
- "",
+ "currency/PTE unit-width-iso-code",
NumberFormatter.with().unit(PTE).unitWidth(UnitWidth.ISO_CODE),
ULocale.forLanguageTag("pt-PT"),
444444.55,
public void unitPercent() {
assertFormatDescending(
"Percent",
- "%",
+ "percent",
NumberFormatter.with().unit(NoUnit.PERCENT),
ULocale.ENGLISH,
"87,650%",
assertFormatDescending(
"Permille",
- "%%",
+ "permille",
NumberFormatter.with().unit(NoUnit.PERMILLE),
ULocale.ENGLISH,
"87,650‰",
assertFormatSingle(
"NoUnit Base",
- "B",
+ "base-unit",
NumberFormatter.with().unit(NoUnit.BASE),
ULocale.ENGLISH,
51423,
assertFormatSingle(
"Percent with Negative Sign",
- "%",
+ "percent",
NumberFormatter.with().unit(NoUnit.PERCENT),
ULocale.ENGLISH,
-98.7654321,
assertFormatDescending(
"Currency Standard",
- "round-currency-standard",
+ "currency/CZK round-currency-standard",
NumberFormatter.with().rounding(Rounder.currency(CurrencyUsage.STANDARD)).unit(CZK),
ULocale.ENGLISH,
"CZK 87,650.00",
assertFormatDescending(
"Currency Cash",
- "round-currency-cash",
+ "currency/CZK round-currency-cash",
NumberFormatter.with().rounding(Rounder.currency(CurrencyUsage.CASH)).unit(CZK),
ULocale.ENGLISH,
"CZK 87,650",
assertFormatDescending(
"Currency Cash with Nickel Rounding",
- "round-currency-cash",
+ "currency/CAD round-currency-cash",
NumberFormatter.with().rounding(Rounder.currency(CurrencyUsage.CASH)).unit(CAD),
ULocale.ENGLISH,
"CA$87,650.00",
assertFormatDescending(
"Currency not in top-level fluent chain",
- "round-currency-cash/CZK",
+ "round-integer", // calling .withCurrency() applies currency rounding rules immediately
NumberFormatter.with().rounding(Rounder.currency(CurrencyUsage.CASH).withCurrency(CZK)),
ULocale.ENGLISH,
"87,650",
// NOTE: Other tests cover the behavior of the other rounding modes.
assertFormatDescending(
+ "Rounding Mode CEILING",
"round-integer/CEILING",
- "",
NumberFormatter.with().rounding(Rounder.integer().withMode(RoundingMode.CEILING)),
ULocale.ENGLISH,
"87,650",
public void grouping() {
assertFormatDescendingBig(
"Western Grouping",
- "grouping=defaults",
+ "group-auto",
NumberFormatter.with().grouping(GroupingStrategy.AUTO),
ULocale.ENGLISH,
"87,650,000",
assertFormatDescendingBig(
"Indic Grouping",
- "grouping=defaults",
+ "group-auto",
NumberFormatter.with().grouping(GroupingStrategy.AUTO),
new ULocale("en-IN"),
"8,76,50,000",
assertFormatDescendingBig(
"Western Grouping, Min 2",
- "grouping=min2",
+ "group-min2",
NumberFormatter.with().grouping(GroupingStrategy.MIN2),
ULocale.ENGLISH,
"87,650,000",
assertFormatDescendingBig(
"Indic Grouping, Min 2",
- "grouping=min2",
+ "group-min2",
NumberFormatter.with().grouping(GroupingStrategy.MIN2),
new ULocale("en-IN"),
"8,76,50,000",
assertFormatDescendingBig(
"No Grouping",
- "grouping=none",
+ "group-off",
NumberFormatter.with().grouping(GroupingStrategy.OFF),
new ULocale("en-IN"),
"87650000",
assertFormatDescendingBig(
"Indic locale with THOUSANDS grouping",
- "",
+ "group-thousands",
NumberFormatter.with().grouping(GroupingStrategy.THOUSANDS),
new ULocale("en-IN"),
"87,650,000",
// If this test breaks due to data changes, find another locale that has minimumGroupingDigits.
assertFormatDescendingBig(
"Hungarian Grouping",
- "",
+ "group-auto",
NumberFormatter.with().grouping(GroupingStrategy.AUTO),
new ULocale("hu"),
"87 650 000",
assertFormatDescendingBig(
"Hungarian Grouping, Min 2",
- "",
+ "group-min2",
NumberFormatter.with().grouping(GroupingStrategy.MIN2),
new ULocale("hu"),
"87 650 000",
assertFormatDescendingBig(
"Hungarian Grouping, Always",
- "",
+ "group-on-aligned",
NumberFormatter.with().grouping(GroupingStrategy.ON_ALIGNED),
new ULocale("hu"),
"87 650 000",
// If this test breaks due to data changes, find another locale that has no default grouping.
assertFormatDescendingBig(
"Bulgarian Currency Grouping",
- "",
+ "currency/USD group-auto",
NumberFormatter.with().grouping(GroupingStrategy.AUTO).unit(USD),
new ULocale("bg"),
"87650000,00 щ.д.",
assertFormatDescendingBig(
"Bulgarian Currency Grouping, Always",
- "",
+ "currency/USD group-on-aligned",
NumberFormatter.with().grouping(GroupingStrategy.ON_ALIGNED).unit(USD),
new ULocale("bg"),
"87 650 000,00 щ.д.",
macros.grouping = Grouper.getInstance((short) 4, (short) 1, (short) 3);
assertFormatDescendingBig(
"Custom Grouping via Internal API",
- "",
+ null,
NumberFormatter.with().macros(macros),
ULocale.ENGLISH,
"8,7,6,5,0000",
public void padding() {
assertFormatDescending(
"Padding",
- "",
+ null,
NumberFormatter.with().padding(Padder.none()),
ULocale.ENGLISH,
"87,650",
assertFormatDescending(
"Padding",
- "",
+ null,
NumberFormatter.with().padding(Padder.codePoints('*', 8, PadPosition.AFTER_PREFIX)),
ULocale.ENGLISH,
"**87,650",
assertFormatDescending(
"Padding with code points",
- "",
+ null,
NumberFormatter.with().padding(Padder.codePoints(0x101E4, 8, PadPosition.AFTER_PREFIX)),
ULocale.ENGLISH,
"𐇤𐇤87,650",
assertFormatDescending(
"Padding with wide digits",
- "symbols=ns:mathsanb",
+ null,
NumberFormatter.with().padding(Padder.codePoints('*', 8, PadPosition.AFTER_PREFIX))
.symbols(NumberingSystem.getInstanceByName("mathsanb")),
ULocale.ENGLISH,
assertFormatDescending(
"Padding with currency spacing",
- "$GBP unit-width=ISO_CODE",
+ null,
NumberFormatter.with().padding(Padder.codePoints('*', 10, PadPosition.AFTER_PREFIX)).unit(GBP)
.unitWidth(UnitWidth.ISO_CODE),
ULocale.ENGLISH,
assertFormatSingle(
"Pad Before Prefix",
- "",
+ null,
NumberFormatter.with().padding(Padder.codePoints('*', 8, PadPosition.BEFORE_PREFIX)),
ULocale.ENGLISH,
-88.88,
assertFormatSingle(
"Pad After Prefix",
- "",
+ null,
NumberFormatter.with().padding(Padder.codePoints('*', 8, PadPosition.AFTER_PREFIX)),
ULocale.ENGLISH,
-88.88,
assertFormatSingle(
"Pad Before Suffix",
- "%",
+ null,
NumberFormatter.with().padding(Padder.codePoints('*', 8, PadPosition.BEFORE_SUFFIX))
.unit(NoUnit.PERCENT),
ULocale.ENGLISH,
assertFormatSingle(
"Pad After Suffix",
- "%",
+ null,
NumberFormatter.with().padding(Padder.codePoints('*', 8, PadPosition.AFTER_SUFFIX))
.unit(NoUnit.PERCENT),
ULocale.ENGLISH,
assertFormatSingle(
"Currency Spacing with Zero Digit Padding Broken",
- "$GBP unit-width=ISO_CODE",
+ null,
NumberFormatter.with().padding(Padder.codePoints('0', 12, PadPosition.AFTER_PREFIX)).unit(GBP)
.unitWidth(UnitWidth.ISO_CODE),
ULocale.ENGLISH,
public void integerWidth() {
assertFormatDescending(
"Integer Width Default",
- "integer-width=1-",
+ "integer-width/+0",
NumberFormatter.with().integerWidth(IntegerWidth.zeroFillTo(1)),
ULocale.ENGLISH,
"87,650",
assertFormatDescending(
"Integer Width Zero Fill 0",
- "integer-width=0-",
+ "integer-width/+",
NumberFormatter.with().integerWidth(IntegerWidth.zeroFillTo(0)),
ULocale.ENGLISH,
"87,650",
assertFormatDescending(
"Integer Width Zero Fill 3",
- "integer-width=3-",
+ "integer-width/+000",
NumberFormatter.with().integerWidth(IntegerWidth.zeroFillTo(3)),
ULocale.ENGLISH,
"87,650",
assertFormatDescending(
"Integer Width Max 3",
- "integer-width=1-3",
+ "integer-width/##0",
NumberFormatter.with().integerWidth(IntegerWidth.zeroFillTo(1).truncateAt(3)),
ULocale.ENGLISH,
"650",
assertFormatDescending(
"Integer Width Fixed 2",
- "integer-width=2",
+ "integer-width/00",
NumberFormatter.with().integerWidth(IntegerWidth.zeroFillTo(2).truncateAt(2)),
ULocale.ENGLISH,
"50",
public void symbols() {
assertFormatDescending(
"French Symbols with Japanese Data 1",
- "symbols=loc:fr",
+ null,
NumberFormatter.with().symbols(DecimalFormatSymbols.getInstance(ULocale.FRENCH)),
ULocale.JAPAN,
"87 650",
assertFormatSingle(
"French Symbols with Japanese Data 2",
- "C symbols=loc:fr",
+ null,
NumberFormatter.with().notation(Notation.compactShort())
.symbols(DecimalFormatSymbols.getInstance(ULocale.FRENCH)),
ULocale.JAPAN,
assertFormatDescending(
"Latin Numbering System with Arabic Data",
- "$USD symbols=ns:latn",
+ "currency/USD latin",
NumberFormatter.with().symbols(NumberingSystem.LATIN).unit(USD),
new ULocale("ar"),
"US$ 87,650.00",
assertFormatDescending(
"Math Numbering System with French Data",
- "symbols=ns:mathsanb",
+ "numbering-system/mathsanb",
NumberFormatter.with().symbols(NumberingSystem.getInstanceByName("mathsanb")),
ULocale.FRENCH,
"𝟴𝟳 𝟲𝟱𝟬",
assertFormatSingle(
"Swiss Symbols (used in documentation)",
- "symbols=loc:de_CH",
+ null,
NumberFormatter.with().symbols(DecimalFormatSymbols.getInstance(new ULocale("de-CH"))),
ULocale.ENGLISH,
12345.67,
assertFormatSingle(
"Myanmar Symbols (used in documentation)",
- "symbols=loc:my_MY",
+ null,
NumberFormatter.with().symbols(DecimalFormatSymbols.getInstance(new ULocale("my_MY"))),
ULocale.ENGLISH,
12345.67,
assertFormatSingle(
"Currency symbol should precede number in ar with NS latn",
- "",
+ "currency/USD latin",
NumberFormatter.with().symbols(NumberingSystem.LATIN).unit(USD),
new ULocale("ar"),
12345.67,
assertFormatSingle(
"Currency symbol should precede number in ar@numbers=latn",
- "",
+ "currency/USD",
NumberFormatter.with().unit(USD),
new ULocale("ar@numbers=latn"),
12345.67,
assertFormatSingle(
"Currency symbol should follow number in ar-EG with NS arab",
- "",
+ "currency/USD",
NumberFormatter.with().unit(USD),
new ULocale("ar-EG"),
12345.67,
assertFormatSingle(
"Currency symbol should follow number in ar@numbers=arab",
- "",
+ "currency/USD",
NumberFormatter.with().unit(USD),
new ULocale("ar@numbers=arab"),
12345.67,
assertFormatSingle(
"NumberingSystem in API should win over @numbers keyword",
- "",
+ "currency/USD latin",
NumberFormatter.with().symbols(NumberingSystem.LATIN).unit(USD),
new ULocale("ar@numbers=arab"),
12345.67,
symbols.setGroupingSeparatorString("!");
assertFormatSingle(
"Symbols object should be copied",
- "symbols=loc:de_CH",
+ null,
f,
ULocale.ENGLISH,
12345.67,
assertFormatSingle(
"The last symbols setter wins",
- "symbols=ns:latn",
+ "latin",
NumberFormatter.with().symbols(symbols).symbols(NumberingSystem.LATIN),
ULocale.ENGLISH,
12345.67,
assertFormatSingle(
"The last symbols setter wins",
- "symbols=loc:de_CH",
+ null,
NumberFormatter.with().symbols(NumberingSystem.LATIN).symbols(symbols),
ULocale.ENGLISH,
12345.67,
public void sign() {
assertFormatSingle(
"Sign Auto Positive",
- "sign=AUTO",
+ "sign-auto",
NumberFormatter.with().sign(SignDisplay.AUTO),
ULocale.ENGLISH,
444444,
assertFormatSingle(
"Sign Auto Negative",
- "sign=AUTO",
+ "sign-auto",
NumberFormatter.with().sign(SignDisplay.AUTO),
ULocale.ENGLISH,
-444444,
assertFormatSingle(
"Sign Auto Zero",
- "",
+ "sign-auto",
NumberFormatter.with().sign(SignDisplay.AUTO),
ULocale.ENGLISH,
0,
assertFormatSingle(
"Sign Always Positive",
- "sign=ALWAYS",
+ "sign-always",
NumberFormatter.with().sign(SignDisplay.ALWAYS),
ULocale.ENGLISH,
444444,
assertFormatSingle(
"Sign Always Negative",
- "sign=ALWAYS",
+ "sign-always",
NumberFormatter.with().sign(SignDisplay.ALWAYS),
ULocale.ENGLISH,
-444444,
assertFormatSingle(
"Sign Always Zero",
- "",
+ "sign-always",
NumberFormatter.with().sign(SignDisplay.ALWAYS),
ULocale.ENGLISH,
0,
assertFormatSingle(
"Sign Never Positive",
- "sign=NEVER",
+ "sign-never",
NumberFormatter.with().sign(SignDisplay.NEVER),
ULocale.ENGLISH,
444444,
assertFormatSingle(
"Sign Never Negative",
- "sign=NEVER",
+ "sign-never",
NumberFormatter.with().sign(SignDisplay.NEVER),
ULocale.ENGLISH,
-444444,
assertFormatSingle(
"Sign Never Zero",
- "",
+ "sign-never",
NumberFormatter.with().sign(SignDisplay.NEVER),
ULocale.ENGLISH,
0,
assertFormatSingle(
"Sign Accounting Positive",
- "$USD sign=ACCOUNTING",
+ "currency/USD sign-accounting",
NumberFormatter.with().sign(SignDisplay.ACCOUNTING).unit(USD),
ULocale.ENGLISH,
444444,
assertFormatSingle(
"Sign Accounting Negative",
- "$USD sign=ACCOUNTING",
+ "currency/USD sign-accounting",
NumberFormatter.with().sign(SignDisplay.ACCOUNTING).unit(USD),
ULocale.ENGLISH,
-444444,
assertFormatSingle(
"Sign Accounting Zero",
- "",
+ "currency/USD sign-accounting",
NumberFormatter.with().sign(SignDisplay.ACCOUNTING).unit(USD),
ULocale.ENGLISH,
0,
assertFormatSingle(
"Sign Accounting-Always Positive",
- "$USD sign=ACCOUNTING_ALWAYS",
+ "currency/USD sign-accounting-always",
NumberFormatter.with().sign(SignDisplay.ACCOUNTING_ALWAYS).unit(USD),
ULocale.ENGLISH,
444444,
assertFormatSingle(
"Sign Accounting-Always Negative",
- "$USD sign=ACCOUNTING_ALWAYS",
+ "currency/USD sign-accounting-always",
NumberFormatter.with().sign(SignDisplay.ACCOUNTING_ALWAYS).unit(USD),
ULocale.ENGLISH,
-444444,
assertFormatSingle(
"Sign Accounting-Always Zero",
- "",
+ "currency/USD sign-accounting-always",
NumberFormatter.with().sign(SignDisplay.ACCOUNTING_ALWAYS).unit(USD),
ULocale.ENGLISH,
0,
assertFormatSingle(
"Sign Except-Zero Positive",
- "",
+ "sign-except-zero",
NumberFormatter.with().sign(SignDisplay.EXCEPT_ZERO),
ULocale.ENGLISH,
444444,
assertFormatSingle(
"Sign Always Negative",
- "",
+ "sign-except-zero",
NumberFormatter.with().sign(SignDisplay.EXCEPT_ZERO),
ULocale.ENGLISH,
-444444,
assertFormatSingle(
"Sign Except-Zero Zero",
- "",
+ "sign-except-zero",
NumberFormatter.with().sign(SignDisplay.EXCEPT_ZERO),
ULocale.ENGLISH,
0,
assertFormatSingle(
"Sign Accounting-Except-Zero Positive",
- "$USD sign=ACCOUNTING_ALWAYS",
+ "currency/USD sign-accounting-except-zero",
NumberFormatter.with().sign(SignDisplay.ACCOUNTING_EXCEPT_ZERO).unit(USD),
ULocale.ENGLISH,
444444,
assertFormatSingle(
"Sign Accounting-Except-Zero Negative",
- "$USD sign=ACCOUNTING_ALWAYS",
+ "currency/USD sign-accounting-except-zero",
NumberFormatter.with().sign(SignDisplay.ACCOUNTING_EXCEPT_ZERO).unit(USD),
ULocale.ENGLISH,
-444444,
assertFormatSingle(
"Sign Accounting-Except-Zero Zero",
- "",
+ "currency/USD sign-accounting-except-zero",
NumberFormatter.with().sign(SignDisplay.ACCOUNTING_EXCEPT_ZERO).unit(USD),
ULocale.ENGLISH,
0,
assertFormatSingle(
"Sign Accounting Negative Hidden",
- "$USD unit-width=HIDDEN sign=ACCOUNTING",
+ "currency/USD unit-width-hidden sign-accounting",
NumberFormatter.with().sign(SignDisplay.ACCOUNTING).unit(USD).unitWidth(UnitWidth.HIDDEN),
ULocale.ENGLISH,
-444444,
public void decimal() {
assertFormatDescending(
"Decimal Default",
- "decimal=AUTO",
+ "decimal-auto",
NumberFormatter.with().decimal(DecimalSeparatorDisplay.AUTO),
ULocale.ENGLISH,
"87,650",
assertFormatDescending(
"Decimal Always Shown",
- "decimal=ALWAYS",
+ "decimal-always",
NumberFormatter.with().decimal(DecimalSeparatorDisplay.ALWAYS),
ULocale.ENGLISH,
"87,650.",
assertFormatSingle(
"Plural 1",
- "$USD F0 unit-width=FULL_NAME",
+ "currency/USD round-integer unit-width-full-name",
NumberFormatter.with().unit(USD).unitWidth(UnitWidth.FULL_NAME).rounding(Rounder.fixedFraction(0)),
ULocale.ENGLISH,
1,
assertFormatSingle(
"Plural 1.00",
- "$USD F2 unit-width=FULL_NAME",
+ "currency/USD .00 unit-width-full-name",
NumberFormatter.with().unit(USD).unitWidth(UnitWidth.FULL_NAME).rounding(Rounder.fixedFraction(2)),
ULocale.ENGLISH,
1,
double[] inputs,
String... expected) {
assert expected.length == 9;
- assertEquals(message + ": Skeleton:", skeleton, f.toSkeleton());
LocalizedNumberFormatter l1 = f.threshold(0L).locale(locale); // no self-regulation
LocalizedNumberFormatter l2 = f.threshold(1L).locale(locale); // all self-regulation
- LocalizedNumberFormatter l3 = NumberFormatter.fromSkeleton(skeleton).locale(locale);
for (int i = 0; i < 9; i++) {
double d = inputs[i];
String actual1 = l1.format(d).toString();
assertEquals(message + ": Unsafe Path: " + d, expected[i], actual1);
String actual2 = l2.format(d).toString();
assertEquals(message + ": Safe Path: " + d, expected[i], actual2);
- String actual3 = l3.format(d).toString();
- assertEquals(message + ": Skeleton Path: " + d, expected[i], actual3);
+ }
+ if (skeleton != null) { // if null, skeleton is declared as undefined.
+ assertEquals(message + ": Skeleton:", skeleton, f.toSkeleton());
+ LocalizedNumberFormatter l3 = NumberFormatter.fromSkeleton(skeleton).locale(locale);
+ for (int i = 0; i < 9; i++) {
+ double d = inputs[i];
+ String actual3 = l3.format(d).toString();
+ assertEquals(message + ": Skeleton Path: " + d, expected[i], actual3);
+ }
}
}
ULocale locale,
Number input,
String expected) {
- assertEquals(message + ": Skeleton:", skeleton, f.toSkeleton());
LocalizedNumberFormatter l1 = f.threshold(0L).locale(locale); // no self-regulation
LocalizedNumberFormatter l2 = f.threshold(1L).locale(locale); // all self-regulation
- LocalizedNumberFormatter l3 = NumberFormatter.fromSkeleton(skeleton).locale(locale);
String actual1 = l1.format(input).toString();
assertEquals(message + ": Unsafe Path: " + input, expected, actual1);
String actual2 = l2.format(input).toString();
assertEquals(message + ": Safe Path: " + input, expected, actual2);
- String actual3 = l3.format(input).toString();
- assertEquals(message + ": Skeleton Path: " + input, expected, actual3);
+ if (skeleton != null) { // if null, skeleton is declared as undefined.
+ assertEquals(message + ": Skeleton:", skeleton, f.toSkeleton());
+ LocalizedNumberFormatter l3 = NumberFormatter.fromSkeleton(skeleton).locale(locale);
+ String actual3 = l3.format(input).toString();
+ assertEquals(message + ": Skeleton Path: " + input, expected, actual3);
+ }
}
private static void assertFormatSingleMeasure(
ULocale locale,
Measure input,
String expected) {
- assertEquals(message + ": Skeleton:", skeleton, f.toSkeleton());
LocalizedNumberFormatter l1 = f.threshold(0L).locale(locale); // no self-regulation
LocalizedNumberFormatter l2 = f.threshold(1L).locale(locale); // all self-regulation
- LocalizedNumberFormatter l3 = NumberFormatter.fromSkeleton(skeleton).locale(locale);
String actual1 = l1.format(input).toString();
assertEquals(message + ": Unsafe Path: " + input, expected, actual1);
String actual2 = l2.format(input).toString();
assertEquals(message + ": Safe Path: " + input, expected, actual2);
- String actual3 = l3.format(input).toString();
- assertEquals(message + ": Skeleton Path: " + input, expected, actual3);
+ if (skeleton != null) { // if null, skeleton is declared as undefined.
+ assertEquals(message + ": Skeleton:", skeleton, f.toSkeleton());
+ LocalizedNumberFormatter l3 = NumberFormatter.fromSkeleton(skeleton).locale(locale);
+ String actual3 = l3.format(input).toString();
+ assertEquals(message + ": Skeleton Path: " + input, expected, actual3);
+ }
}
}