&& minimumFractionDigits == other.minimumFractionDigits
&& groupingUsed == other.groupingUsed
&& parseIntegerOnly == other.parseIntegerOnly
- && parseStrict == other.parseStrict;
+ && parseStrict == other.parseStrict
+ && capitalizationSetting == other.capitalizationSetting;
}
/**
maximumFractionDigits = maxFractionDigits;
minimumFractionDigits = minFractionDigits;
}
+ if (serialVersionOnStream < 2) {
+ // Didn't have capitalizationSetting, set it to default
+ capitalizationSetting = DisplayContext.CAPITALIZATION_NONE;
+ }
///CLOVER:ON
/*Bug 4185761
Validate the min and max fields [Richard/GCL]
*/
private Currency currency;
- static final int currentSerialVersion = 1;
+ static final int currentSerialVersion = 2;
/**
* Describes the version of <code>NumberFormat</code> present on the stream.
* <code>byte</code> fields such as <code>maxIntegerDigits</code> are ignored,
* and the <code>int</code> fields such as <code>maximumIntegerDigits</code>
* are used instead.
+ *
+ * <li><b>2</b>: adds capitalizationSetting.
* </ul>
* When streaming out a <code>NumberFormat</code>, the most recent format
* (corresponding to the highest allowable <code>serialVersionOnStream</code>)
private boolean parseStrict;
/*
- * Capitalization setting, new in ICU 53
+ * Capitalization context setting, new in ICU 53
+ * @serial
*/
- private transient DisplayContext capitalizationSetting = DisplayContext.CAPITALIZATION_NONE;
+ private DisplayContext capitalizationSetting = DisplayContext.CAPITALIZATION_NONE;
/**
* The instances of this inner class are used as attribute keys and values
import com.ibm.icu.impl.ICUDebug;
import com.ibm.icu.impl.ICUResourceBundle;
import com.ibm.icu.impl.PatternProps;
+import com.ibm.icu.lang.UCharacter;
+import com.ibm.icu.text.BreakIterator;
+import com.ibm.icu.text.DisplayContext;
import com.ibm.icu.util.ULocale;
import com.ibm.icu.util.ULocale.Category;
import com.ibm.icu.util.UResourceBundle;
*/
private String[] publicRuleSetNames;
+ /**
+ * Data for handling context-based capitalization
+ */
+ private boolean capitalizationInfoIsSet = false;
+ private boolean capitalizationForListOrMenu = false;
+ private boolean capitalizationForStandAlone = false;
+ private BreakIterator capitalizationBrkIter = null;
+
+
private static final boolean DEBUG = ICUDebug.enabled("rbnf");
//-----------------------------------------------------------------------
public boolean equals(Object that) {
// if the other object isn't a RuleBasedNumberFormat, that's
// all we need to know
+ // Test for capitalization info equality is adequately handled
+ // by the NumberFormat test for capitalizationSetting equality;
+ // the info here is just derived from that.
if (!(that instanceof RuleBasedNumberFormat)) {
return false;
} else {
if (ruleSet.startsWith("%%")) {
throw new IllegalArgumentException("Can't use internal rule set");
}
- return format(number, findRuleSet(ruleSet));
+ return adjustForContext(format(number, findRuleSet(ruleSet)));
}
/**
if (ruleSet.startsWith("%%")) {
throw new IllegalArgumentException("Can't use internal rule set");
}
- return format(number, findRuleSet(ruleSet));
+ return adjustForContext(format(number, findRuleSet(ruleSet)));
}
/**
// this is one of the inherited format() methods. Since it doesn't
// have a way to select the rule set to use, it just uses the
// default one
- toAppendTo.append(format(number, defaultRuleSet));
+ // Note, the BigInteger/BigDecimal methods below currently go through this.
+ if (toAppendTo.length() == 0) {
+ toAppendTo.append(adjustForContext(format(number, defaultRuleSet)));
+ } else {
+ // appending to other text, don't capitalize
+ toAppendTo.append(format(number, defaultRuleSet));
+ }
return toAppendTo;
}
// this is one of the inherited format() methods. Since it doesn't
// have a way to select the rule set to use, it just uses the
// default one
- toAppendTo.append(format(number, defaultRuleSet));
+ if (toAppendTo.length() == 0) {
+ toAppendTo.append(adjustForContext(format(number, defaultRuleSet)));
+ } else {
+ // appending to other text, don't capitalize
+ toAppendTo.append(format(number, defaultRuleSet));
+ }
return toAppendTo;
}
}
}
+ /**
+ * {@icu} Set a particular DisplayContext value in the formatter,
+ * such as CAPITALIZATION_FOR_STANDALONE. Note: For getContext, see
+ * NumberFormat.
+ *
+ * @param context The DisplayContext value to set.
+ * @draft ICU 53
+ * @provisional This API might change or be removed in a future release.
+ */
+ // Here we override the NumberFormat implementation in order to
+ // lazily initialize relevant items
+ public void setContext(DisplayContext context) {
+ super.setContext(context);
+ if (!capitalizationInfoIsSet &&
+ (context==DisplayContext.CAPITALIZATION_FOR_UI_LIST_OR_MENU || context==DisplayContext.CAPITALIZATION_FOR_STANDALONE)) {
+ initCapitalizationContextInfo(locale);
+ capitalizationInfoIsSet = true;
+ }
+ if (capitalizationBrkIter == null && (context==DisplayContext.CAPITALIZATION_FOR_BEGINNING_OF_SENTENCE ||
+ (context==DisplayContext.CAPITALIZATION_FOR_UI_LIST_OR_MENU && capitalizationForListOrMenu) ||
+ (context==DisplayContext.CAPITALIZATION_FOR_STANDALONE && capitalizationForStandAlone) )) {
+ capitalizationBrkIter = BreakIterator.getSentenceInstance(locale);
+ }
+ }
+
//-----------------------------------------------------------------------
// package-internal API
//-----------------------------------------------------------------------
}
}
+ /**
+ * Set capitalizationForListOrMenu, capitalizationForStandAlone
+ */
+ private void initCapitalizationContextInfo(ULocale theLocale) {
+ ICUResourceBundle rb = (ICUResourceBundle) UResourceBundle.getBundleInstance(ICUResourceBundle.ICU_BASE_NAME, theLocale);
+ try {
+ ICUResourceBundle rdb = rb.getWithFallback("contextTransforms/number-spellout");
+ int[] intVector = rdb.getIntVector();
+ if (intVector.length >= 2) {
+ capitalizationForListOrMenu = (intVector[0] != 0);
+ capitalizationForStandAlone = (intVector[1] != 0);
+ }
+ } catch (MissingResourceException e) {
+ // use default
+ }
+ }
+
/**
* This function is used by init() to strip whitespace between rules (i.e.,
* after semicolons).
}
}
+ /**
+ * Adjust capitalization of formatted result for display context
+ */
+ private String adjustForContext(String result) {
+ if (result != null && result.length() > 0 && UCharacter.isLowerCase(result.codePointAt(0)) &&
+ capitalizationBrkIter != null) {
+ DisplayContext capitalization = getContext(DisplayContext.Type.CAPITALIZATION);
+ if ( capitalization==DisplayContext.CAPITALIZATION_FOR_BEGINNING_OF_SENTENCE ||
+ (capitalization == DisplayContext.CAPITALIZATION_FOR_UI_LIST_OR_MENU && capitalizationForListOrMenu) ||
+ (capitalization == DisplayContext.CAPITALIZATION_FOR_STANDALONE && capitalizationForStandAlone) ) {
+ return UCharacter.toTitleCase(locale, result, capitalizationBrkIter,
+ UCharacter.TITLECASE_NO_LOWERCASE | UCharacter.TITLECASE_NO_BREAK_ADJUSTMENT);
+ }
+ }
+ return result;
+ }
+
/**
* Returns the named rule set. Throws an IllegalArgumentException
* if this formatter doesn't have a rule set with that name.
/*
*******************************************************************************
- * Copyright (C) 1996-2013, International Business Machines Corporation and *
+ * Copyright (C) 1996-2014, International Business Machines Corporation and *
* others. All Rights Reserved. *
*******************************************************************************
*/
import com.ibm.icu.dev.test.TestFmwk;
import com.ibm.icu.text.DecimalFormatSymbols;
+import com.ibm.icu.text.DisplayContext;
import com.ibm.icu.text.RuleBasedNumberFormat;
import com.ibm.icu.util.ULocale;
errln("Format Error - Got: " + result + " Expected: " + expected[1]);
}
}
+
+ public void TestContext() {
+ class TextContextItem {
+ public String locale;
+ public int format;
+ public DisplayContext context;
+ public double value;
+ public String expectedResult;
+ // Simple constructor
+ public TextContextItem(String loc, int fmt, DisplayContext ctxt, double val, String expRes) {
+ locale = loc;
+ format = fmt;
+ context = ctxt;
+ value = val;
+ expectedResult = expRes;
+ }
+ };
+ final TextContextItem[] items = {
+ new TextContextItem( "sv", RuleBasedNumberFormat.SPELLOUT, DisplayContext.CAPITALIZATION_FOR_MIDDLE_OF_SENTENCE, 123.45, "ett\u00ADhundra\u00ADtjugo\u00ADtre komma fyra fem" ),
+ new TextContextItem( "sv", RuleBasedNumberFormat.SPELLOUT, DisplayContext.CAPITALIZATION_FOR_BEGINNING_OF_SENTENCE, 123.45, "Ett\u00ADhundra\u00ADtjugo\u00ADtre komma fyra fem" ),
+ new TextContextItem( "sv", RuleBasedNumberFormat.SPELLOUT, DisplayContext.CAPITALIZATION_FOR_UI_LIST_OR_MENU, 123.45, "ett\u00ADhundra\u00ADtjugo\u00ADtre komma fyra fem" ),
+ new TextContextItem( "sv", RuleBasedNumberFormat.SPELLOUT, DisplayContext.CAPITALIZATION_FOR_STANDALONE, 123.45, "ett\u00ADhundra\u00ADtjugo\u00ADtre komma fyra fem" ),
+ new TextContextItem( "en", RuleBasedNumberFormat.SPELLOUT, DisplayContext.CAPITALIZATION_FOR_MIDDLE_OF_SENTENCE, 123.45, "one hundred twenty-three point four five" ),
+ new TextContextItem( "en", RuleBasedNumberFormat.SPELLOUT, DisplayContext.CAPITALIZATION_FOR_BEGINNING_OF_SENTENCE, 123.45, "One hundred twenty-three point four five" ),
+ new TextContextItem( "en", RuleBasedNumberFormat.SPELLOUT, DisplayContext.CAPITALIZATION_FOR_UI_LIST_OR_MENU, 123.45, "One hundred twenty-three point four five" ),
+ new TextContextItem( "en", RuleBasedNumberFormat.SPELLOUT, DisplayContext.CAPITALIZATION_FOR_STANDALONE, 123.45, "One hundred twenty-three point four five" ),
+ };
+ for (TextContextItem item: items) {
+ ULocale locale = new ULocale(item.locale);
+ RuleBasedNumberFormat rbnf = new RuleBasedNumberFormat(locale, item.format);
+ rbnf.setContext(item.context);
+ String result = rbnf.format(item.value, rbnf.getDefaultRuleSetName());
+ if (!result.equals(item.expectedResult)) {
+ errln("Error for locale " + item.locale + ", context " + item.context + ", expected " + item.expectedResult + ", got " + result);
+ }
+ RuleBasedNumberFormat rbnfClone = (RuleBasedNumberFormat)rbnf.clone();
+ if (!rbnfClone.equals(rbnf)) {
+ errln("Error for locale " + item.locale + ", context " + item.context + ", rbnf.clone() != rbnf");
+ } else {
+ result = rbnfClone.format(item.value, rbnfClone.getDefaultRuleSetName());
+ if (!result.equals(item.expectedResult)) {
+ errln("Error with clone for locale " + item.locale + ", context " + item.context + ", expected " + item.expectedResult + ", got " + result);
+ }
+ }
+ }
+ }
+
}