Author: j...@google.com Date: Wed May 20 21:41:21 2009 New Revision: 5450 Modified: trunk/user/src/com/google/gwt/i18n/client/NumberFormat.java trunk/user/test/com/google/gwt/i18n/client/NumberFormat_ar_Test.java
Log: Allow an app to force use of latin digits/separators instead of localized digits. Patch by: jat Review by: andreasst Modified: trunk/user/src/com/google/gwt/i18n/client/NumberFormat.java ============================================================================== --- trunk/user/src/com/google/gwt/i18n/client/NumberFormat.java (original) +++ trunk/user/src/com/google/gwt/i18n/client/NumberFormat.java Wed May 20 21:41:21 2009 @@ -306,29 +306,53 @@ */ public class NumberFormat { - // Sets of constants as defined for the default locale. - private static final NumberConstants defaultNumberConstants = LocaleInfo.getCurrentLocale().getNumberConstants(); + // Sets of constants as defined for the current locale from CLDR. + protected static final NumberConstants localizedNumberConstants = LocaleInfo.getCurrentLocale().getNumberConstants(); + + /** + * Current NumberConstants interface to use, see + * {...@link #setForcedLatinDigits(boolean)} for changing it. + */ + protected static NumberConstants defaultNumberConstants = localizedNumberConstants; + + // Cached instances of standard formatters. + private static NumberFormat cachedCurrencyFormat; + private static NumberFormat cachedDecimalFormat; + private static NumberFormat cachedPercentFormat; + private static NumberFormat cachedScientificFormat; + + // Number constants mapped to use latin digits/separators. + private static NumberConstants latinNumberConstants = null; + + // Localized characters for dot and comma in number patterns, used to produce + // the latin mapping for arbitrary locales. Any separator not in either of + // these strings will be mapped to non-breaking space (U+00A0). + private static final String LOCALIZED_COMMA_EQUIVALENTS = ".\u060C\u066B\u3001\uFE10\uFE11\uFE50\uFE51\uFF0C\uFF64"; + private static final String LOCALIZED_DOT_EQUIVALENTS = ".\u2024\u3002\uFE12\uFE52\uFF0E\uFF61"; // Constants for characters used in programmatic (unlocalized) patterns. - private static final char PATTERN_ZERO_DIGIT = '0'; - private static final char PATTERN_GROUPING_SEPARATOR = ','; + private static final char CURRENCY_SIGN = '\u00A4'; private static final char PATTERN_DECIMAL_SEPARATOR = '.'; - private static final char PATTERN_PER_MILLE = '\u2030'; - private static final char PATTERN_PERCENT = '%'; private static final char PATTERN_DIGIT = '#'; - private static final char PATTERN_SEPARATOR = ';'; private static final char PATTERN_EXPONENT = 'E'; + private static final char PATTERN_GROUPING_SEPARATOR = ','; private static final char PATTERN_MINUS = '-'; - private static final char CURRENCY_SIGN = '\u00A4'; - private static final char QUOTE = '\''; + private static final char PATTERN_PER_MILLE = '\u2030'; + private static final char PATTERN_PERCENT = '%'; + private static final char PATTERN_SEPARATOR = ';'; + private static final char PATTERN_ZERO_DIGIT = '0'; - // Cached instances of standard formatters. - private static NumberFormat cachedDecimalFormat; - private static NumberFormat cachedScientificFormat; - private static NumberFormat cachedPercentFormat; - private static NumberFormat cachedCurrencyFormat; + private static final char QUOTE = '\''; /** + * @return true if all new NumberFormat instances will use latin digits + * and related characters rather than the localized ones. + */ + public static boolean forcedLatinDigits() { + return defaultNumberConstants != localizedNumberConstants; + } + + /** * Provides the standard currency format for the default locale. * * @return a <code>NumberFormat</code> capable of producing and consuming @@ -341,7 +365,7 @@ } return cachedCurrencyFormat; } - + /** * Provides the standard currency format for the default locale using a * specified currency. @@ -427,49 +451,184 @@ return cachedScientificFormat; } - // Locale specific symbol collection. - private final NumberConstants numberConstants; + /** + * Specify whether all new NumberFormat instances will use latin digits + * and related characters rather than the localized ones. + * + * @param useLatinDigits true if latin digits/etc should be used, false if + * localized digits/etc should be used. + */ + public static void setForcedLatinDigits(boolean useLatinDigits) { + // Invalidate cached formats if changing + if (useLatinDigits != forcedLatinDigits()) { + cachedCurrencyFormat = null; + cachedDecimalFormat = null; + cachedPercentFormat = null; + cachedScientificFormat = null; + } + if (useLatinDigits) { + if (latinNumberConstants == null) { + latinNumberConstants = createLatinNumberConstants( + localizedNumberConstants); + } + defaultNumberConstants = latinNumberConstants; + } else { + defaultNumberConstants = localizedNumberConstants; + } + } - private int maximumIntegerDigits = 40; - private int minimumIntegerDigits = 1; - private int maximumFractionDigits = 3; // invariant, >= minFractionDigits. - private int minimumFractionDigits = 0; - private int minExponentDigits; + /** + * Create a delocalized NumberConstants instance from a localized one. + * + * @param orig localized NumberConstants instance + * @return NumberConstants instance using latin digits/etc + */ + protected static NumberConstants createLatinNumberConstants(final NumberConstants orig) { + final String groupingSeparator = remapSeparator( + orig.groupingSeparator()); + final String decimalSeparator = remapSeparator( + orig.decimalSeparator()); + final String monetaryGroupingSeparator = remapSeparator( + orig.monetaryGroupingSeparator()); + final String monetarySeparator = remapSeparator( + orig.monetarySeparator()); + return new NumberConstants() { + public String currencyPattern() { + return orig.currencyPattern(); + } + + public String decimalPattern() { + return orig.decimalPattern(); + } + + public String decimalSeparator() { + return decimalSeparator; + } + + public String defCurrencyCode() { + return orig.defCurrencyCode(); + } + + public String exponentialSymbol() { + return orig.exponentialSymbol(); + } + + public String groupingSeparator() { + return groupingSeparator; + } + + public String infinity() { + return orig.infinity(); + } + + public String minusSign() { + return orig.minusSign(); + } + + public String monetaryGroupingSeparator() { + return monetaryGroupingSeparator; + } + + public String monetarySeparator() { + return monetarySeparator; + } + + public String notANumber() { + return orig.notANumber(); + } + + public String percent() { + return orig.percent(); + } + + public String percentPattern() { + return orig.percentPattern(); + } + + public String perMill() { + return orig.perMill(); + } + + public String plusSign() { + return orig.plusSign(); + } + + public String scientificPattern() { + return orig.scientificPattern(); + } + + public String zeroDigit() { + return "0"; + } + }; + } - private String positivePrefix = ""; - private String positiveSuffix = ""; - private String negativePrefix = "-"; - private String negativeSuffix = ""; + /** + * Remap a localized separator to an equivalent latin one. + * + * @param separator + * @return delocalized separator character + */ + protected static String remapSeparator(String separator) { + char ch = separator.length() > 0 ? separator.charAt(0) : 0xFFFF; + if (LOCALIZED_DOT_EQUIVALENTS.indexOf(ch) >= 0) { + return "."; + } + if (LOCALIZED_COMMA_EQUIVALENTS.indexOf(ch) >= 0) { + return ","; + } + return "\u00A0"; + } - // The multiplier for use in percent, per mille, etc. - private int multiplier = 1; + // The currency code. + private final String currencyCode; - // The number of digits between grouping separators in the integer - // portion of a number. - private int groupingSize = 3; + // Currency setting. + private final String currencySymbol; // Forces the decimal separator to always appear in a formatted number. private boolean decimalSeparatorAlwaysShown = false; + // The number of digits between grouping separators in the integer + // portion of a number. + private int groupingSize = 3; + private boolean isCurrencyFormat = false; + + private int maximumFractionDigits = 3; // invariant, >= minFractionDigits. + private int maximumIntegerDigits = 40; + private int minExponentDigits; + private int minimumFractionDigits = 0; + private int minimumIntegerDigits = 1; - // True to force the use of exponential (i.e. scientific) notation. - private boolean useExponentialNotation = false; + // The multiplier for use in percent, per mille, etc. + private int multiplier = 1; - // Currency setting. - private final String currencySymbol; + private String negativePrefix = "-"; - // The currency code. - private final String currencyCode; + private String negativeSuffix = ""; + + // Locale specific symbol collection. + private final NumberConstants numberConstants; // The pattern to use for formatting and parsing. private final String pattern; + private String positivePrefix = ""; + + private String positiveSuffix = ""; + + // True to force the use of exponential (i.e. scientific) notation. + private boolean useExponentialNotation = false; + /** * Constructs a format object based on the specified settings. * * @param numberConstants the locale-specific number constants to use for this - * format + * format -- **NOTE** subclasses passing their own instance here + * should pay attention to {...@link #forcedLatinDigits()} and remap + * localized symbols using + * {...@link #createLatinNumberConstants(NumberConstants)} * @param pattern pattern that specify how number should be formatted * @param cdata currency data that should be used * @param userSuppliedPattern true if the pattern was supplied by the user Modified: trunk/user/test/com/google/gwt/i18n/client/NumberFormat_ar_Test.java ============================================================================== --- trunk/user/test/com/google/gwt/i18n/client/NumberFormat_ar_Test.java (original) +++ trunk/user/test/com/google/gwt/i18n/client/NumberFormat_ar_Test.java Wed May 20 21:41:21 2009 @@ -47,6 +47,20 @@ fmt.format(-314.0)); } + public void testForceLatin() { + assertFalse(NumberFormat.forcedLatinDigits()); + NumberFormat.setForcedLatinDigits(true); + assertTrue(NumberFormat.forcedLatinDigits()); + NumberFormat decLatin = NumberFormat.getDecimalFormat(); + assertEquals("1\u00A0003,14", decLatin.format(1003.14)); + assertEquals("1\u00A0003,14-", decLatin.format(-1003.14)); + NumberFormat.setForcedLatinDigits(false); + assertFalse(NumberFormat.forcedLatinDigits()); + assertEquals("3,14", decLatin.format(3.14)); + NumberFormat decArabic = NumberFormat.getDecimalFormat(); + assertEquals("\u0663\u066B\u0661\u0664", decArabic.format(3.14)); + } + public void testParse() { NumberFormat fmt = NumberFormat.getDecimalFormat(); assertEquals(3.14, fmt.parse("\u0663\u066B\u0661\u0664")); --~--~---------~--~----~------------~-------~--~----~ You received this message because you are subscribed to the Google Groups "Google Web Toolkit Contributors" group. To post to this group, send email to Google-Web-Toolkit-Contributors@googlegroups.com To unsubscribe from this group, send email to google-web-toolkit-contributors+unsubscr...@googlegroups.com For more options, visit this group at http://groups.google.com/group/Google-Web-Toolkit-Contributors?hl=en -~----------~----~----~----~------~----~------~--~---