import com.ibm.icu.impl.number.DecimalQuantity;
import com.ibm.icu.impl.number.NumberStringBuilder;
+import com.ibm.icu.number.NumberRangeFormatter.RangeIdentityType;
import com.ibm.icu.util.ICUUncheckedIOException;
/**
* including a String, an AttributedCharacterIterator, and a BigDecimal.
*
* @author sffc
- * @draft ICU 62
+ * @draft ICU 63
* @provisional This API might change or be removed in a future release.
* @see NumberRangeFormatter
*/
final DecimalQuantity second;
final RangeIdentityType identityType;
- public static enum RangeIdentityType {
- EQUAL_BEFORE_ROUNDING, EQUAL_AFTER_ROUNDING, NOT_EQUAL
- }
-
FormattedNumberRange(NumberStringBuilder nsb, DecimalQuantity first, DecimalQuantity second,
RangeIdentityType identityType) {
this.nsb = nsb;
* multiple times, this method may be called repeatedly with the following pattern:
*
* <pre>
- * FieldPosition fpos = new FieldPosition(NumberFormat.Field.GROUPING_SEPARATOR);
- * while (formattedNumber.nextFieldPosition(fpos, status)) {
+ * FieldPosition fpos = new FieldPosition(NumberFormat.Field.INTEGER);
+ * while (formattedNumberRange.nextFieldPosition(fpos, status)) {
* // do something with fpos.
* }
* </pre>
* used. For example, if the first and second number were the same either before or after rounding occurred, an
* identity fallback was used.
*
- * @return A IdentityType indicating the resulting identity situation in the formatted number range.
+ * @return A RangeIdentityType indicating the resulting identity situation in the formatted number range.
* @draft ICU 63
* @provisional This API might change or be removed in a future release.
* @see NumberRangeFormatter
import com.ibm.icu.impl.number.DecimalQuantity_DualStorageBCD;
import com.ibm.icu.impl.number.NumberStringBuilder;
import com.ibm.icu.impl.number.range.RangeMacroProps;
-import com.ibm.icu.number.FormattedNumberRange.RangeIdentityType;
+import com.ibm.icu.number.NumberRangeFormatter.RangeIdentityType;
/**
* A NumberRangeFormatter that has a locale associated with it; this means .formatRange() methods are available.
* The first number in the range, usually to the left in LTR locales.
* @param second
* The second number in the range, usually to the right in LTR locales.
- * @return A FormattedNumber object; call .toString() to get the string.
+ * @return A FormattedNumberRange object; call .toString() to get the string.
* @draft ICU 63
* @provisional This API might change or be removed in a future release.
* @see NumberRangeFormatter
* The first number in the range, usually to the left in LTR locales.
* @param second
* The second number in the range, usually to the right in LTR locales.
- * @return A FormattedNumber object; call .toString() to get the string.
+ * @return A FormattedNumberRange object; call .toString() to get the string.
* @draft ICU 63
* @provisional This API might change or be removed in a future release.
* @see NumberRangeFormatter
* The first number in the range, usually to the left in LTR locales.
* @param second
* The second number in the range, usually to the right in LTR locales.
- * @return A FormattedNumber object; call .toString() to get the string.
+ * @return A FormattedNumberRange object; call .toString() to get the string.
* @draft ICU 63
* @provisional This API might change or be removed in a future release.
* @see NumberRangeFormatter
/**
* The main entrypoint to the formatting of ranges of numbers, including currencies and other units of measurement.
+ * <p>
+ * Usage example:
+ * <p>
+ *
+ * <pre>
+ * NumberRangeFormatter.with().identityFallback(RangeIdentityFallback.APPROXIMATELY_OR_SINGLE_VALUE)
+ * .numberFormatterFirst(NumberFormatter.with().unit(MeasureUnit.METER))
+ * .numberFormatterSecond(NumberFormatter.with().unit(MeasureUnit.KILOMETER)).locale(ULocale.UK)
+ * .formatRange(750, 1.2).toString();
+ * // => "750 m - 1.2 km"
+ * </pre>
+ * <p>
+ * Like NumberFormatter, NumberRangeFormatter instances are immutable and thread-safe. This API is based on the
+ * <em>fluent</em> design pattern popularized by libraries such as Google's Guava.
*
* @author sffc
* @draft ICU 63
* @provisional This API might change or be removed in a future release.
* @see NumberRangeFormatter
*/
- public enum IdentityFallback {
+ public static enum RangeIdentityFallback {
/**
* Show the number as a single value rather than a range. Example: "$5"
*
}
/**
- * Defines the behavior when the two numbers in the range are identical after rounding. To programmatically detect
- * when the identity fallback is used, compare the lower and upper BigDecimals via FormattedNumber.
+ * Used in the result class FormattedNumberRange to indicate to the user whether the numbers formatted in the range
+ * were equal or not, and whether or not the identity fallback was applied.
+ *
+ * @draft ICU 63
+ * @provisional This API might change or be removed in a future release.
+ * @see NumberRangeFormatter
*/
-
- public static enum RangeIdentityFallback {
- /**
- * Show the number as a single value rather than a range. Example: "$5"
- */
- SINGLE_VALUE,
-
+ public static enum RangeIdentityType {
/**
- * Show the number using a locale-sensitive approximation pattern. If the numbers were the same before rounding,
- * show the single value. Example: "~$5" or "$5"
+ * Used to indicate that the two numbers in the range were equal, even before any rounding rules were applied.
+ *
+ * @draft ICU 63
+ * @provisional This API might change or be removed in a future release.
+ * @see NumberRangeFormatter
*/
- APPROXIMATELY_OR_SINGLE_VALUE,
+ EQUAL_BEFORE_ROUNDING,
/**
- * Show the number using a locale-sensitive approximation pattern. Use the range pattern always, even if the
- * inputs are the same. Example: "~$5"
+ * Used to indicate that the two numbers in the range were equal, but only after rounding rules were applied.
+ *
+ * @draft ICU 63
+ * @provisional This API might change or be removed in a future release.
+ * @see NumberRangeFormatter
*/
- APPROXIMATELY,
+ EQUAL_AFTER_ROUNDING,
/**
- * Show the number as the range of two equal values. Use the range pattern always, even if the inputs are the
- * same. Example (with RangeCollapse.NONE): "$5 – $5"
+ * Used to indicate that the two numbers in the range were not equal, even after rounding rules were applied.
+ *
+ * @draft ICU 63
+ * @provisional This API might change or be removed in a future release.
+ * @see NumberRangeFormatter
*/
- RANGE
+ NOT_EQUAL
}
private static final UnlocalizedNumberRangeFormatter BASE = new UnlocalizedNumberRangeFormatter();
+ /**
+ * Call this method at the beginning of a NumberRangeFormatter fluent chain in which the locale is not currently
+ * known at the call site.
+ *
+ * @return An {@link UnlocalizedNumberRangeFormatter}, to be used for chaining.
+ * @draft ICU 63
+ */
public static UnlocalizedNumberRangeFormatter with() {
return BASE;
}
+ /**
+ * Call this method at the beginning of a NumberRangeFormatter fluent chain in which the locale is known at the call
+ * site.
+ *
+ * @param locale
+ * The locale from which to load formats and symbols for number range formatting.
+ * @return A {@link LocalizedNumberRangeFormatter}, to be used for chaining.
+ * @draft ICU 63
+ */
public static LocalizedNumberRangeFormatter withLocale(Locale locale) {
return BASE.locale(locale);
}
* @see NumberFormatter
* @see NumberRangeFormatter
*/
- public T numberFormatter(UnlocalizedNumberFormatter formatter) {
- return numberFormatters(formatter, formatter);
+ public T numberFormatterBoth(UnlocalizedNumberFormatter formatter) {
+ return (T) numberFormatterFirst(formatter).numberFormatterSecond(formatter);
}
/**
- * Sets the NumberFormatter instances to use for the numbers in the range. This method allows you to set a different
- * formatter for the first and second numbers.
+ * Sets the NumberFormatter instance to use for the first number in the range.
* <p>
- * The NumberFormatter instances must not have a locale applied yet; the locale specified on the
+ * The NumberFormatter instance must not have a locale applied yet; the locale specified on the
* NumberRangeFormatter will be used.
*
* @param formatterFirst
* The formatter to use for the first number in the range.
+ * @return The fluent chain.
+ * @draft ICU 63
+ * @provisional This API might change or be removed in a future release.
+ * @see NumberFormatter
+ * @see NumberRangeFormatter
+ */
+ public T numberFormatterFirst(UnlocalizedNumberFormatter formatterFirst) {
+ return create(KEY_FORMATTER_1, formatterFirst);
+ }
+
+ /**
+ * Sets the NumberFormatter instances to use for the numbers in the range. This method allows you to set a different
+ * formatter for the first and second numbers.
+ * <p>
+ * The NumberFormatter instance must not have a locale applied yet; the locale specified on the
+ * NumberRangeFormatter will be used.
+ *
* @param formatterSecond
* The formatter to use for the second number in the range.
* @return The fluent chain.
* @see NumberFormatter
* @see NumberRangeFormatter
*/
- public T numberFormatters(UnlocalizedNumberFormatter formatterFirst, UnlocalizedNumberFormatter formatterSecond) {
- T intermediate = create(KEY_FORMATTER_1, formatterFirst);
- return (T) intermediate.create(KEY_FORMATTER_2, formatterSecond);
+ public T numberFormatterSecond(UnlocalizedNumberFormatter formatterSecond) {
+ return create(KEY_FORMATTER_2, formatterSecond);
}
/**
* <li>APPROXIMATELY: "~5 miles"</li>
* <li>RANGE: "5-5 miles" (with collapse=UNIT)</li>
* <p>
- * The default value is AUTO.
+ * The default value is APPROXIMATELY.
*
* @param identityFallback
* The strategy to use when formatting two numbers that end up being the same.
public void testNullBehavior() {
assertFormatRange(
"Basic",
- NumberRangeFormatter.with().numberFormatter(null),
+ NumberRangeFormatter.with().numberFormatterBoth(null),
ULocale.US,
"1 --- 5",
"5 --- 5",
assertFormatRange(
"Basic",
- NumberRangeFormatter.with().numberFormatters(null, null),
+ NumberRangeFormatter.with().numberFormatterFirst(null),
ULocale.US,
"1 --- 5",
"5 --- 5",
assertFormatRange(
"Basic",
- NumberRangeFormatter.with().numberFormatters(
- NumberFormatter.with().grouping(GroupingStrategy.OFF),
- null
- ),
+ NumberRangeFormatter.with()
+ .numberFormatterFirst(NumberFormatter.with().grouping(GroupingStrategy.OFF))
+ .numberFormatterSecond(null),
ULocale.US,
"1 --- 5",
"5 --- 5",
assertFormatRange(
"Basic",
- NumberRangeFormatter.with().numberFormatters(
- null,
- NumberFormatter.with().grouping(GroupingStrategy.OFF)
- ),
+ NumberRangeFormatter.with()
+ .numberFormatterFirst(null)
+ .numberFormatterSecond(NumberFormatter.with().grouping(GroupingStrategy.OFF)),
ULocale.US,
"1 --- 5",
"5 --- 5",