ICU-10633 Implement context-sensitive number formatting (RBNF for J), handle serialization/equals for NumberFormat capitalizationSetting
X-SVN-Rev: 35301
This commit is contained in:
parent
22316fe74f
commit
62c9048bc0
@ -1047,7 +1047,8 @@ public abstract class NumberFormat extends UFormat {
|
||||
&& minimumFractionDigits == other.minimumFractionDigits
|
||||
&& groupingUsed == other.groupingUsed
|
||||
&& parseIntegerOnly == other.parseIntegerOnly
|
||||
&& parseStrict == other.parseStrict;
|
||||
&& parseStrict == other.parseStrict
|
||||
&& capitalizationSetting == other.capitalizationSetting;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1528,6 +1529,10 @@ public abstract class NumberFormat extends UFormat {
|
||||
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]
|
||||
@ -1714,7 +1719,7 @@ public abstract class NumberFormat extends UFormat {
|
||||
*/
|
||||
private Currency currency;
|
||||
|
||||
static final int currentSerialVersion = 1;
|
||||
static final int currentSerialVersion = 2;
|
||||
|
||||
/**
|
||||
* Describes the version of <code>NumberFormat</code> present on the stream.
|
||||
@ -1729,6 +1734,8 @@ public abstract class NumberFormat extends UFormat {
|
||||
* <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>)
|
||||
@ -1755,9 +1762,10 @@ public abstract class NumberFormat extends UFormat {
|
||||
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
|
||||
|
@ -20,6 +20,9 @@ import java.util.Set;
|
||||
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;
|
||||
@ -600,6 +603,15 @@ public class RuleBasedNumberFormat extends NumberFormat {
|
||||
*/
|
||||
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");
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
@ -833,6 +845,9 @@ public class RuleBasedNumberFormat extends NumberFormat {
|
||||
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 {
|
||||
@ -1061,7 +1076,7 @@ public class RuleBasedNumberFormat extends NumberFormat {
|
||||
if (ruleSet.startsWith("%%")) {
|
||||
throw new IllegalArgumentException("Can't use internal rule set");
|
||||
}
|
||||
return format(number, findRuleSet(ruleSet));
|
||||
return adjustForContext(format(number, findRuleSet(ruleSet)));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1080,7 +1095,7 @@ public class RuleBasedNumberFormat extends NumberFormat {
|
||||
if (ruleSet.startsWith("%%")) {
|
||||
throw new IllegalArgumentException("Can't use internal rule set");
|
||||
}
|
||||
return format(number, findRuleSet(ruleSet));
|
||||
return adjustForContext(format(number, findRuleSet(ruleSet)));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1098,7 +1113,13 @@ public class RuleBasedNumberFormat extends NumberFormat {
|
||||
// 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;
|
||||
}
|
||||
|
||||
@ -1121,7 +1142,12 @@ public class RuleBasedNumberFormat extends NumberFormat {
|
||||
// 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;
|
||||
}
|
||||
|
||||
@ -1381,6 +1407,31 @@ public class RuleBasedNumberFormat extends NumberFormat {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@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
|
||||
//-----------------------------------------------------------------------
|
||||
@ -1653,6 +1704,23 @@ public class RuleBasedNumberFormat extends NumberFormat {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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).
|
||||
@ -1805,6 +1873,23 @@ public class RuleBasedNumberFormat extends NumberFormat {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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.
|
||||
|
@ -1,6 +1,6 @@
|
||||
/*
|
||||
*******************************************************************************
|
||||
* Copyright (C) 1996-2013, International Business Machines Corporation and *
|
||||
* Copyright (C) 1996-2014, International Business Machines Corporation and *
|
||||
* others. All Rights Reserved. *
|
||||
*******************************************************************************
|
||||
*/
|
||||
@ -15,6 +15,7 @@ import java.util.Random;
|
||||
|
||||
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;
|
||||
|
||||
@ -1302,4 +1303,51 @@ public class RbnfTest extends TestFmwk {
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user