ICU-12521 Updating DecimalFormatSymbols to data sink

X-SVN-Rev: 38676
This commit is contained in:
Shane Carr 2016-04-29 23:22:17 +00:00
parent 456857b494
commit ac7474e79f

View File

@ -24,6 +24,7 @@ import com.ibm.icu.util.Currency;
import com.ibm.icu.util.ICUCloneNotSupportedException;
import com.ibm.icu.util.ULocale;
import com.ibm.icu.util.ULocale.Category;
import com.ibm.icu.impl.UResource;
import com.ibm.icu.util.UResourceBundle;
/**
@ -840,6 +841,84 @@ public class DecimalFormatSymbols implements Cloneable, Serializable {
return (c=='\u200E' || c=='\u200F' || c=='\u061C');
}
/**
* List of field names to be loaded from the data files.
* The indices of each name into the array correspond to the position of that item in the
* numberElements array.
*/
private static final String[] SYMBOL_KEYS = {
"decimal",
"group",
"list",
"percentSign",
"minusSign",
"plusSign",
"exponential",
"perMille",
"infinity",
"nan",
"currencyDecimal",
"currencyGroup",
"superscriptingExponent"
};
/**
* List of default values for the symbols.
*/
private static final String[] SYMBOL_DEFAULTS = new String[] {
".", // decimal
",", // group
";", // list
"%", // percentSign
"-", // minusSign
"+", // plusSign
"E", // exponential
"\u2030", // perMille
"\u221e", // infinity
"NaN", // NaN
null, // currency decimal
null, // currency group
"\u00D7" // superscripting exponent
};
/**
* Constants for path names in the data bundles.
*/
private static final String LATIN_NUMBERING_SYSTEM = "latn";
private static final String NUMBER_ELEMENTS = "NumberElements";
private static final String SYMBOLS = "symbols";
/**
* Sink for enumerating all of the decimal format symbols (more specifically, anything
* under the "NumberElements.symbols" tree).
*
* More specific bundles (en_GB) are enumerated before their parents (en_001, en, root):
* Only store a value if it is still missing, that is, it has not been overridden.
*/
private static final class DecFmtDataSink extends UResource.Sink {
private String[] numberElements; // Array where to store the characters (set in constructor)
public DecFmtDataSink(String[] numberElements) {
this.numberElements = numberElements;
}
@Override
public void put(UResource.Key key, UResource.Value value, boolean noFallback) {
UResource.Table symbolsTable = value.getTable();
for (int j = 0; symbolsTable.getKeyAndValue(j, key, value); ++j) {
for (int i = 0; i < SYMBOL_KEYS.length; i++) {
if (key.contentEquals(SYMBOL_KEYS[i])) {
if (numberElements[i] == null) {
numberElements[i] = value.toString();
}
break;
}
}
}
}
}
/**
* Initializes the symbols from the LocaleElements resource bundle.
* Note: The organization of LocaleElements badly needs to be
@ -878,52 +957,67 @@ public class DecimalFormatSymbols implements Cloneable, Serializable {
digits[7] = DecimalFormat.PATTERN_SEVEN_DIGIT;
digits[8] = DecimalFormat.PATTERN_EIGHT_DIGIT;
digits[9] = DecimalFormat.PATTERN_NINE_DIGIT;
nsName = "latn"; // Default numbering system
nsName = LATIN_NUMBERING_SYSTEM; // Default numbering system
}
/* try the cache first */
// Open the resource bundle and get the locale IDs
// TODO: Is there a better way to get the locale than making an ICUResourceBundle instance?
ICUResourceBundle rb = (ICUResourceBundle)UResourceBundle.
getBundleInstance(ICUResourceBundle.ICU_BASE_NAME, locale);
// TODO: Determine actual and valid locale correctly.
ULocale uloc = rb.getULocale();
setLocale(uloc, uloc);
// Try loading from the cache
String[][] data = cachedLocaleData.get(locale);
String[] numberElements;
if (data == null) { /* cache miss */
data = new String[1][];
ICUResourceBundle rb = (ICUResourceBundle)UResourceBundle.
getBundleInstance(ICUResourceBundle.ICU_BASE_NAME, locale);
boolean isLatn = nsName.equals("latn");
String baseKey = "NumberElements/" + nsName + "/symbols/";
String latnKey = "NumberElements/latn/symbols/";
String[] symbolKeys = { "decimal", "group", "list", "percentSign", "minusSign", "plusSign", "exponential", "perMille", "infinity", "nan", "currencyDecimal", "currencyGroup", "superscriptingExponent" };
String[] fallbackElements = { ".", ",", ";", "%", "-", "+", "E", "\u2030", "\u221e", "NaN", null, null };
String[] symbolsArray = new String[symbolKeys.length];
for ( int i = 0 ; i < symbolKeys.length; i++ ) {
try {
symbolsArray[i] = rb.getStringWithFallback(baseKey+symbolKeys[i]);
} catch (MissingResourceException ex) {
if (!isLatn) { // Fall back to latn numbering system for symbols if desired symbol isn't found.
try {
symbolsArray[i] = rb.getStringWithFallback(latnKey+symbolKeys[i]);
} catch (MissingResourceException ex1) {
symbolsArray[i] = fallbackElements[i];
}
} else {
symbolsArray[i] = fallbackElements[i];
}
if (data == null) {
// Cache miss!
// TODO: There does not appear to be a good reason why the "data" array is 2-D.
data = new String[1][SYMBOL_KEYS.length];
// Load using a data sink
DecFmtDataSink sink = new DecFmtDataSink(data[0]);
try {
rb.getAllItemsWithFallback(NUMBER_ELEMENTS + "/" + nsName + "/" + SYMBOLS, sink);
} catch (MissingResourceException e) {
// The symbols don't exist for the given nsName and resource bundle.
// Silently ignore and fall back to Latin.
}
// Load the Latin fallback if necessary
boolean hasNull = false;
for (String entry : data[0]) {
if (entry == null) {
hasNull = true;
break;
}
}
if (hasNull && !nsName.equals(LATIN_NUMBERING_SYSTEM)) {
rb.getAllItemsWithFallback(NUMBER_ELEMENTS + "/" + LATIN_NUMBERING_SYSTEM + "/" + SYMBOLS, sink);
}
// If monetary decimal or grouping were not explicitly set, then set them to be the same as
// their non-monetary counterparts.
if (data[0][10] == null) {
data[0][10] = data[0][0];
}
if (data[0][11] == null) {
data[0][11] = data[0][1];
}
// Fill in any remaining missing values
for (int i = 0; i < SYMBOL_KEYS.length; i++) {
if (data[0][i] == null) {
data[0][i] = SYMBOL_DEFAULTS[i];
}
}
data[0] = symbolsArray;
/* update cache */
// Save in cache
cachedLocaleData.put(locale, data);
}
numberElements = data[0];
ICUResourceBundle r = (ICUResourceBundle)UResourceBundle.
getBundleInstance(ICUResourceBundle.ICU_BASE_NAME, locale);
// TODO: Determine actual and valid locale correctly.
ULocale uloc = r.getULocale();
setLocale(uloc, uloc);
String[] numberElements = data[0];
// Copy data from the numberElements map into instance fields
decimalSeparator = numberElements[0].charAt(0);
groupingSeparator = numberElements[1].charAt(0);
patternSeparator = numberElements[2].charAt(0);
@ -936,25 +1030,10 @@ public class DecimalFormatSymbols implements Cloneable, Serializable {
perMill = numberElements[7].charAt(0);
infinity = numberElements[8];
NaN = numberElements[9];
monetarySeparator = numberElements[10].charAt(0);
monetaryGroupingSeparator = numberElements[11].charAt(0);
exponentMultiplicationSign = numberElements[12];
if ( numberElements[10] != null) {
monetarySeparator = numberElements[10].charAt(0);
} else {
monetarySeparator = decimalSeparator;
}
if ( numberElements[11] != null) {
monetaryGroupingSeparator = numberElements[11].charAt(0);
} else {
monetaryGroupingSeparator = groupingSeparator;
}
if ( numberElements[12] != null) {
exponentMultiplicationSign = numberElements[12];
} else {
exponentMultiplicationSign = "\u00D7";
}
digit = DecimalFormat.PATTERN_DIGIT; // Localized pattern character no longer in CLDR
padEscape = DecimalFormat.PATTERN_PAD_ESCAPE;
sigDigit = DecimalFormat.PATTERN_SIGNIFICANT_DIGIT;