2 *******************************************************************************
\r
3 * Copyright (C) 1996-2009, International Business Machines Corporation and *
\r
4 * others. All Rights Reserved. *
\r
5 *******************************************************************************
\r
7 package com.ibm.icu.text;
\r
9 import com.ibm.icu.impl.ICUResourceBundle;
\r
10 import com.ibm.icu.util.Currency;
\r
11 import com.ibm.icu.util.ULocale;
\r
12 import com.ibm.icu.util.UResourceBundle;
\r
14 import java.io.IOException;
\r
15 import java.io.ObjectInputStream;
\r
16 import java.io.Serializable;
\r
17 import java.text.ChoiceFormat;
\r
18 import java.util.Hashtable;
\r
19 import java.util.Locale;
\r
20 import java.util.MissingResourceException;
\r
23 * This class represents the set of symbols (such as the decimal separator, the
\r
24 * grouping separator, and so on) needed by <code>DecimalFormat</code> to format
\r
25 * numbers. <code>DecimalFormat</code> creates for itself an instance of
\r
26 * <code>DecimalFormatSymbols</code> from its locale data. If you need to
\r
27 * change any of these symbols, you can get the
\r
28 * <code>DecimalFormatSymbols</code> object from your <code>DecimalFormat</code>
\r
31 * <p><strong>This is an enhanced version of <code>DecimalFormatSymbols</code> that
\r
32 * is based on the standard version in the JDK. New or changed functionality
\r
34 * <strong><font face=helvetica color=red>NEW</font></strong>.</strong>
\r
36 * @see java.util.Locale
\r
37 * @see DecimalFormat
\r
38 * @author Mark Davis
\r
43 public class DecimalFormatSymbols implements Cloneable, Serializable {
\r
46 * Create a DecimalFormatSymbols object for the default locale.
\r
49 public DecimalFormatSymbols() {
\r
50 initialize( ULocale.getDefault() );
\r
54 * Create a DecimalFormatSymbols object for the given locale.
\r
55 * @param locale the locale
\r
58 public DecimalFormatSymbols( Locale locale ) {
\r
59 initialize( ULocale.forLocale(locale) );
\r
63 * Create a DecimalFormatSymbols object for the given locale.
\r
64 * @param locale the locale
\r
67 public DecimalFormatSymbols( ULocale locale ) {
\r
68 initialize( locale );
\r
72 * Gets a DecimalFormatSymbols instance for the default locale.
\r
74 * <b>Note:</b> Unlike <code>java.text.DecimalFormatSymbols#getInstance</code>,
\r
75 * this method simply returns <code>new com.ibm.icu.text.DecimalFormatSymbols()</code>.
\r
76 * ICU does not support <code>DecimalFormatSymbolsProvider</code> introduced in Java 6
\r
77 * or its equivalent implementation for now.
\r
79 * @return A DecimalFormatSymbols instance.
\r
82 public static DecimalFormatSymbols getInstance() {
\r
83 return new DecimalFormatSymbols();
\r
87 * Gets a DecimalFormatSymbols instance for the given locale.
\r
89 * <b>Note:</b> Unlike <code>java.text.DecimalFormatSymbols#getInstance</code>,
\r
90 * this method simply returns <code>new com.ibm.icu.text.DecimalFormatSymbols(locale)</code>.
\r
91 * ICU does not support <code>DecimalFormatSymbolsProvider</code> introduced in Java 6
\r
92 * or its equivalent implementation for now.
\r
94 * @param locale the locale.
\r
95 * @return A DecimalFormatSymbols instance.
\r
98 public static DecimalFormatSymbols getInstance(Locale locale) {
\r
99 return new DecimalFormatSymbols(locale);
\r
103 * Gets a DecimalFormatSymbols instance for the given locale.
\r
105 * <b>Note:</b> Unlike <code>java.text.DecimalFormatSymbols#getInstance</code>,
\r
106 * this method simply returns <code>new com.ibm.icu.text.DecimalFormatSymbols(locale)</code>.
\r
107 * ICU does not support <code>DecimalFormatSymbolsProvider</code> introduced in Java 6
\r
108 * or its equivalent implementation for now.
\r
110 * @param locale the locale.
\r
111 * @return A DecimalFormatSymbols instance.
\r
114 public static DecimalFormatSymbols getInstance(ULocale locale) {
\r
115 return new DecimalFormatSymbols(locale);
\r
119 * Returns an array of all locales for which the <code>getInstance</code> methods of this
\r
120 * class can return localized instances.
\r
122 * <b>Note:</b> Unlike <code>java.text.DecimalFormatSymbols#getAvailableLocales</code>,
\r
123 * this method simply returns the array of <code>Locale</code>s available for this class.
\r
124 * ICU does not support <code>DecimalFormatSymbolsProvider</code> introduced in Java 6
\r
125 * or its equivalent implementation for now.
\r
127 * @return An array of <code>Locale</code>s for which localized <code>DecimalFormatSymbols</code> instances are available.
\r
130 public static Locale[] getAvailableLocales() {
\r
131 return ICUResourceBundle.getAvailableLocales(ICUResourceBundle.ICU_BASE_NAME);
\r
135 * Returns an array of all locales for which the <code>getInstance</code> methods of this
\r
136 * class can return localized instances.
\r
138 * <b>Note:</b> Unlike <code>java.text.DecimalFormatSymbols#getAvailableLocales</code>,
\r
139 * this method simply returns the array of <code>ULocale</code>s available in this class.
\r
140 * ICU does not support <code>DecimalFormatSymbolsProvider</code> introduced in Java 6
\r
141 * or its equivalent implementation for now.
\r
143 * @return An array of <code>ULocale</code>s for which localized <code>DecimalFormatSymbols</code> instances are available.
\r
144 * @stable ICU 3.8 (retain)
\r
145 * @provisional This API might change or be removed in a future release.
\r
147 public static ULocale[] getAvailableULocales() {
\r
148 return ICUResourceBundle.getAvailableULocales(ICUResourceBundle.ICU_BASE_NAME);
\r
153 * Return the character used for zero. Different for Arabic, etc.
\r
154 * @return the character
\r
157 public char getZeroDigit() {
\r
162 * Set the character used for zero.
\r
163 * @param zeroDigit the zero character.
\r
166 public void setZeroDigit(char zeroDigit) {
\r
167 this.zeroDigit = zeroDigit;
\r
171 * Return the character used to represent a significant digit in a pattern.
\r
172 * @return the significant digit pattern character
\r
175 public char getSignificantDigit() {
\r
180 * Set the character used to represent a significant digit in a pattern.
\r
181 * @param sigDigit the significant digit pattern character
\r
184 public void setSignificantDigit(char sigDigit) {
\r
185 this.sigDigit = sigDigit;
\r
189 * Return the character used for thousands separator. Different for French, etc.
\r
190 * @return the thousands character
\r
193 public char getGroupingSeparator() {
\r
194 return groupingSeparator;
\r
198 * Set the character used for thousands separator. Different for French, etc.
\r
199 * @param groupingSeparator the thousands character
\r
202 public void setGroupingSeparator(char groupingSeparator) {
\r
203 this.groupingSeparator = groupingSeparator;
\r
207 * Return the character used for decimal sign. Different for French, etc.
\r
208 * @return the decimal character
\r
211 public char getDecimalSeparator() {
\r
212 return decimalSeparator;
\r
216 * Set the character used for decimal sign. Different for French, etc.
\r
217 * @param decimalSeparator the decimal character
\r
220 public void setDecimalSeparator(char decimalSeparator) {
\r
221 this.decimalSeparator = decimalSeparator;
\r
225 * Return the character used for mille percent sign. Different for Arabic, etc.
\r
226 * @return the mille percent character
\r
229 public char getPerMill() {
\r
234 * Set the character used for mille percent sign. Different for Arabic, etc.
\r
235 * @param perMill the mille percent character
\r
238 public void setPerMill(char perMill) {
\r
239 this.perMill = perMill;
\r
243 * Return the character used for percent sign. Different for Arabic, etc.
\r
244 * @return the percent character
\r
247 public char getPercent() {
\r
252 * Set the character used for percent sign. Different for Arabic, etc.
\r
253 * @param percent the percent character
\r
256 public void setPercent(char percent) {
\r
257 this.percent = percent;
\r
261 * Return the character used for a digit in a pattern.
\r
262 * @return the digit pattern character
\r
265 public char getDigit() {
\r
270 * Set the character used for a digit in a pattern.
\r
271 * @param digit the digit pattern character
\r
274 public void setDigit(char digit) {
\r
275 this.digit = digit;
\r
279 * Return the character used to separate positive and negative subpatterns
\r
281 * @return the pattern separator character
\r
284 public char getPatternSeparator() {
\r
285 return patternSeparator;
\r
289 * Set the character used to separate positive and negative subpatterns
\r
291 * @param patternSeparator the pattern separator character
\r
294 public void setPatternSeparator(char patternSeparator) {
\r
295 this.patternSeparator = patternSeparator;
\r
299 * Return the String used to represent infinity. Almost always left
\r
301 * @return the Infinity string
\r
304 //Bug 4194173 [Richard/GCL]
\r
306 public String getInfinity() {
\r
311 * Set the String used to represent infinity. Almost always left
\r
313 * @param infinity the Infinity String
\r
316 public void setInfinity(String infinity) {
\r
317 this.infinity = infinity;
\r
321 * Return the String used to represent NaN. Almost always left
\r
323 * @return the NaN String
\r
326 //Bug 4194173 [Richard/GCL]
\r
327 public String getNaN() {
\r
332 * Set the String used to represent NaN. Almost always left
\r
334 * @param NaN the NaN String
\r
337 public void setNaN(String NaN) {
\r
342 * Return the character used to represent minus sign. If no explicit
\r
343 * negative format is specified, one is formed by prefixing
\r
344 * minusSign to the positive format.
\r
345 * @return the minus sign character
\r
348 public char getMinusSign() {
\r
353 * Set the character used to represent minus sign. If no explicit
\r
354 * negative format is specified, one is formed by prefixing
\r
355 * minusSign to the positive format.
\r
356 * @param minusSign the minus sign character
\r
359 public void setMinusSign(char minusSign) {
\r
360 this.minusSign = minusSign;
\r
364 * Return the string denoting the local currency.
\r
365 * @return the local currency String.
\r
368 public String getCurrencySymbol()
\r
370 return currencySymbol;
\r
374 * Set the string denoting the local currency.
\r
375 * @param currency the local currency String.
\r
378 public void setCurrencySymbol(String currency)
\r
380 currencySymbol = currency;
\r
384 * Return the international string denoting the local currency.
\r
385 * @return the international string denoting the local currency
\r
388 public String getInternationalCurrencySymbol()
\r
390 return intlCurrencySymbol;
\r
394 * Set the international string denoting the local currency.
\r
395 * @param currency the international string denoting the local currency.
\r
398 public void setInternationalCurrencySymbol(String currency)
\r
400 intlCurrencySymbol = currency;
\r
404 * Returns the currency symbol, for JDK 1.4 compatibility only.
\r
405 * ICU clients should use the Currency API directly.
\r
406 * @return the currency used, or null
\r
409 public Currency getCurrency() {
\r
414 * ICU does not use the DecimalFormatSymbols for the
\r
415 * currency any more. This API is present
\r
416 * for API compatibility only.
\r
418 * This also sets the currency symbol attribute to the currency's symbol
\r
419 * in the DecimalFormatSymbols' locale, and the international currency
\r
420 * symbol attribute to the currency's ISO 4217 currency code.
\r
422 * @param currency the new currency to be used
\r
423 * @throws NullPointerException if <code>currency</code> is null
\r
424 * @see #setCurrencySymbol
\r
425 * @see #setInternationalCurrencySymbol
\r
429 public void setCurrency(Currency currency) {
\r
430 if (currency == null) {
\r
431 throw new NullPointerException();
\r
433 this.currency = currency;
\r
434 intlCurrencySymbol = currency.getCurrencyCode();
\r
435 currencySymbol = currency.getSymbol(requestedLocale);
\r
439 * Return the monetary decimal separator.
\r
440 * @return the monetary decimal separator character
\r
443 public char getMonetaryDecimalSeparator()
\r
445 return monetarySeparator;
\r
449 * Return the monetary decimal separator.
\r
450 * @return the monetary decimal separator character
\r
453 public char getMonetaryGroupingSeparator()
\r
455 return monetaryGroupingSeparator;
\r
459 * Internal API for NumberFormat
\r
460 * @return String currency pattern string
\r
463 String getCurrencyPattern(){
\r
464 return currencyPattern;
\r
467 * Set the monetary decimal separator.
\r
468 * @param sep the monetary decimal separator character
\r
471 public void setMonetaryDecimalSeparator(char sep)
\r
473 monetarySeparator = sep;
\r
476 * Set the monetary decimal separator.
\r
477 * @param sep the monetary decimal separator character
\r
480 public void setMonetaryGroupingSeparator(char sep)
\r
482 monetaryGroupingSeparator = sep;
\r
486 * <strong><font face=helvetica color=red>NEW</font></strong>
\r
487 * Return the string used to separate the mantissa from the exponent.
\r
488 * Examples: "x10^" for 1.23x10^4, "E" for 1.23E4.
\r
489 * @return the localized exponent symbol, used in localized patterns
\r
490 * and formatted strings
\r
491 * @see #setExponentSeparator
\r
494 public String getExponentSeparator()
\r
496 return exponentSeparator;
\r
500 * <strong><font face=helvetica color=red>NEW</font></strong>
\r
501 * Set the string used to separate the mantissa from the exponent.
\r
502 * Examples: "x10^" for 1.23x10^4, "E" for 1.23E4.
\r
503 * @param exp the localized exponent symbol, used in localized patterns
\r
504 * and formatted strings
\r
505 * @see #getExponentSeparator
\r
508 public void setExponentSeparator(String exp)
\r
510 exponentSeparator = exp;
\r
514 * <strong><font face=helvetica color=red>NEW</font></strong>
\r
515 * Return the localized plus sign.
\r
516 * @return the plus sign, used in localized patterns and formatted
\r
518 * @see #setPlusSign
\r
519 * @see #setMinusSign
\r
520 * @see #getMinusSign
\r
523 public char getPlusSign() {
\r
528 * <strong><font face=helvetica color=red>NEW</font></strong>
\r
529 * Set the localized plus sign.
\r
530 * @param plus the plus sign, used in localized patterns and formatted
\r
532 * @see #getPlusSign
\r
533 * @see #setMinusSign
\r
534 * @see #getMinusSign
\r
537 public void setPlusSign(char plus) {
\r
542 * <strong><font face=helvetica color=red>NEW</font></strong>
\r
543 * Return the character used to pad numbers out to a specified width. This
\r
544 * is not the pad character itself; rather, it is the special pattern
\r
545 * character <em>preceding</em> the pad character. In the pattern
\r
546 * "*_#,##0", '*' is the pad escape, and '_' is the pad character.
\r
547 * @return the character
\r
548 * @see #setPadEscape
\r
549 * @see DecimalFormat#getFormatWidth
\r
550 * @see DecimalFormat#getPadPosition
\r
551 * @see DecimalFormat#getPadCharacter
\r
554 public char getPadEscape() {
\r
559 * <strong><font face=helvetica color=red>NEW</font></strong>
\r
560 * Set the character used to pad numbers out to a specified width. This is
\r
561 * not the pad character itself; rather, it is the special pattern character
\r
562 * <em>preceding</em> the pad character. In the pattern "*_#,##0", '*' is
\r
563 * the pad escape, and '_' is the pad character.
\r
564 * @see #getPadEscape
\r
565 * @see DecimalFormat#setFormatWidth
\r
566 * @see DecimalFormat#setPadPosition
\r
567 * @see DecimalFormat#setPadCharacter
\r
570 public void setPadEscape(char c) {
\r
574 public static final int CURRENCY_SPC_CURRENCY_MATCH = 0;
\r
575 public static final int CURRENCT_SPC_SURROUNDING_MATCH = 1;
\r
576 public static final int CURRENCY_SPC_INSERT = 2;
\r
578 private static final String CURRENCY_SPACING = "currencySpacing";
\r
579 private static final String BEFORE_CURRENCY = "beforeCurrency";
\r
580 private static final String AFTER_CURRENCY = "afterCurrency";
\r
581 private static final String[] CURRENCY_SPACING_KEYS =
\r
582 { "currencyMatch", "surroundingMatch" ,"insertBetween"};
\r
583 private static final String DEFAULT_SPC_MATCH = "[:letter:]";
\r
584 private static final String DEFAULT_SPC_INSERT = " ";
\r
585 private static final String DEFAULT_SPC_SUR_MATCH = "[:digit:]";
\r
587 private String[] currencySpcBeforeSym; // before currency symbol.
\r
588 private String[] currencySpcAfterSym; // after currency symbol.
\r
590 * Get pattern string for 'CurrencySpacing' that can be applied to
\r
592 * This API gets the CurrencySpacing data from ResourceBundle. The pattern can
\r
593 * be null if there is no data from current locale and its parent locales.
\r
595 * @param itemType : CURRENCY_SPC_CURRENCY_MATCH, CURRENCY_SPC_SURROUNDING_MATCH
\r
596 * or CURRENCY_SPC_INSERT
\r
597 * @param beforeCurrency : true if the pattern is for before currency symbol.
\r
598 * false if the pattern is for after currency symbol.
\r
599 * @return pattern string for currencyMatch, surroundingMatch or spaceInsert.
\r
600 * Return null of there is no data for this locale and its parent locales.
\r
602 public String getPatternForCurrencySpacing(int itemType, boolean beforeCurrency) {
\r
603 if (itemType < CURRENCY_SPC_CURRENCY_MATCH ||
\r
604 itemType > CURRENCY_SPC_INSERT ) {
\r
605 return null; // invalid itemType.
\r
607 if (beforeCurrency) {
\r
608 return currencySpcBeforeSym[itemType];
\r
610 return currencySpcAfterSym[itemType];
\r
616 * Set pattern string for 'CurrencySpacing' that can be applied to
\r
619 * @param itemType : CURRENCY_SPC_CURRENCY_MATCH, CURRENCY_SPC_SURROUNDING_MATCH
\r
620 * or CURRENCY_SPC_INSERT
\r
621 * @param beforeCurrency : true if the pattern is for before currency symbol.
\r
622 * false if the pattern is for after currency symbol.
\r
623 * @param pattern string to override current setting.
\r
625 public void setPatternForCurrencySpacing(int itemType, boolean beforeCurrency, String pattern) {
\r
627 if (itemType < CURRENCY_SPC_CURRENCY_MATCH ||
\r
628 itemType > CURRENCY_SPC_INSERT ) {
\r
629 return; // invalid itemType.
\r
631 if (beforeCurrency) {
\r
632 currencySpcBeforeSym[itemType] = pattern;
\r
634 currencySpcAfterSym[itemType] = pattern;
\r
639 * Returns the locale for which this object was constructed.
\r
640 * @return the locale for which this object was constructed
\r
643 public Locale getLocale() {
\r
644 return requestedLocale;
\r
648 * Returns the locale for which this object was constructed.
\r
649 * @return the locale for which this object was constructed
\r
652 public ULocale getULocale() {
\r
657 * Standard override.
\r
660 public Object clone() {
\r
662 return (DecimalFormatSymbols) super.clone();
\r
663 // other fields are bit-copied
\r
664 } catch (CloneNotSupportedException e) {
\r
666 throw new IllegalStateException();
\r
675 public boolean equals(Object obj) {
\r
676 if (obj == null) return false;
\r
677 if (this == obj) return true;
\r
678 DecimalFormatSymbols other = (DecimalFormatSymbols) obj;
\r
679 for (int i = 0; i <= CURRENCY_SPC_INSERT; i++) {
\r
680 if (!currencySpcBeforeSym[i].equals(other.currencySpcBeforeSym[i])) {
\r
683 if (!currencySpcAfterSym[i].equals(other.currencySpcAfterSym[i])) {
\r
688 return (zeroDigit == other.zeroDigit &&
\r
689 groupingSeparator == other.groupingSeparator &&
\r
690 decimalSeparator == other.decimalSeparator &&
\r
691 percent == other.percent &&
\r
692 perMill == other.perMill &&
\r
693 digit == other.digit &&
\r
694 minusSign == other.minusSign &&
\r
695 patternSeparator == other.patternSeparator &&
\r
696 infinity.equals(other.infinity) &&
\r
697 NaN.equals(other.NaN) &&
\r
698 currencySymbol.equals(other.currencySymbol) &&
\r
699 intlCurrencySymbol.equals(other.intlCurrencySymbol) &&
\r
700 padEscape == other.padEscape && // [NEW]
\r
701 plusSign == other.plusSign && // [NEW]
\r
702 exponentSeparator.equals(other.exponentSeparator) && // [NEW]
\r
703 monetarySeparator == other.monetarySeparator);
\r
707 * Override hashCode
\r
710 public int hashCode() {
\r
711 int result = zeroDigit;
\r
712 result = result * 37 + groupingSeparator;
\r
713 result = result * 37 + decimalSeparator;
\r
718 * Initializes the symbols from the LocaleElements resource bundle.
\r
719 * Note: The organization of LocaleElements badly needs to be
\r
722 private void initialize( ULocale locale ) {
\r
723 this.requestedLocale = locale.toLocale();
\r
724 this.ulocale = locale;
\r
726 /* try the cache first */
\r
727 String[][] data = (String[][]) cachedLocaleData.get(locale);
\r
728 String[] numberElements;
\r
729 if (data == null) { /* cache miss */
\r
730 data = new String[1][];
\r
731 ICUResourceBundle rb = (ICUResourceBundle)UResourceBundle.
\r
732 getBundleInstance(ICUResourceBundle.ICU_BASE_NAME, locale);
\r
733 data[0] = rb.getStringArray("NumberElements");
\r
735 cachedLocaleData.put(locale, data);
\r
737 numberElements = data[0];
\r
739 ICUResourceBundle r = (ICUResourceBundle)UResourceBundle.
\r
740 getBundleInstance(ICUResourceBundle.ICU_BASE_NAME, locale);
\r
742 // TODO: Determine actual and valid locale correctly.
\r
743 ULocale uloc = r.getULocale();
\r
744 setLocale(uloc, uloc);
\r
746 // {dlf} clean up below now that we have our own resource data
\r
747 decimalSeparator = numberElements[0].charAt(0);
\r
748 groupingSeparator = numberElements[1].charAt(0);
\r
749 // Temporary hack to support old JDK 1.1 resources
\r
750 // patternSeparator = numberElements[2].length() > 0 ?
\r
751 // numberElements[2].charAt(0) : ';';
\r
752 patternSeparator = numberElements[2].charAt(0);
\r
753 percent = numberElements[3].charAt(0);
\r
754 zeroDigit = numberElements[4].charAt(0); //different for Arabic,etc.
\r
755 digit = numberElements[5].charAt(0);
\r
756 minusSign = numberElements[6].charAt(0);
\r
758 // Temporary hack to support JDK versions before 1.1.6 (?)
\r
759 // exponentSeparator = numberElements.length >= 9 ?
\r
760 // numberElements[7] : DecimalFormat.PATTERN_EXPONENT;
\r
761 // perMill = numberElements.length >= 9 ?
\r
762 // numberElements[8].charAt(0) : '\u2030';
\r
763 // infinity = numberElements.length >= 10 ?
\r
764 // numberElements[9] : "\u221e";
\r
765 // NaN = numberElements.length >= 11 ?
\r
766 // numberElements[10] : "\ufffd";
\r
767 exponentSeparator = numberElements[7];
\r
768 perMill = numberElements[8].charAt(0);
\r
769 infinity = numberElements[9];
\r
770 NaN = numberElements[10];
\r
772 plusSign =numberElements[11].charAt(0);
\r
773 padEscape = DecimalFormat.PATTERN_PAD_ESCAPE;
\r
774 sigDigit = DecimalFormat.PATTERN_SIGNIFICANT_DIGIT;
\r
776 // Attempt to set the zero digit based on the numbering system for the locale requested
\r
778 NumberingSystem ns = NumberingSystem.getInstance(locale);
\r
779 if ( ns != null && ns.getRadix() == 10 && !ns.isAlgorithmic()) {
\r
780 zeroDigit = ns.getDescription().charAt(0);
\r
783 // Obtain currency data from the currency API. This is strictly
\r
784 // for backward compatibility; we don't use DecimalFormatSymbols
\r
785 // for currency data anymore.
\r
786 String currname = null;
\r
787 currency = Currency.getInstance(locale);
\r
788 if (currency != null) {
\r
789 intlCurrencySymbol = currency.getCurrencyCode();
\r
790 boolean[] isChoiceFormat = new boolean[1];
\r
791 currname = currency.getName(locale,
\r
792 Currency.SYMBOL_NAME,
\r
794 // If this is a ChoiceFormat currency, then format an
\r
795 // arbitrary value; pick something != 1; more common.
\r
796 currencySymbol = isChoiceFormat[0]
\r
797 ? new ChoiceFormat(currname).format(2.0)
\r
800 intlCurrencySymbol = "XXX";
\r
801 currencySymbol = "\u00A4"; // 'OX' currency symbol
\r
803 // If there is a currency decimal, use it.
\r
804 monetarySeparator = decimalSeparator;
\r
805 monetaryGroupingSeparator = groupingSeparator;
\r
806 Currency curr = Currency.getInstance(locale);
\r
808 String currencyCode = curr.getCurrencyCode();
\r
809 if(currencyCode != null) {
\r
810 /* An explicit currency was requested */
\r
811 ICUResourceBundle resource = (ICUResourceBundle)UResourceBundle.getBundleInstance(ICUResourceBundle.ICU_BASE_NAME, locale);
\r
812 ICUResourceBundle currencyRes = resource.getWithFallback("Currencies");
\r
814 currencyRes = currencyRes.getWithFallback(currencyCode);
\r
815 if(currencyRes.getSize()>2) {
\r
816 currencyRes = (ICUResourceBundle)currencyRes.get(2);
\r
817 currencyPattern = currencyRes.getString(0);
\r
818 monetarySeparator = currencyRes.getString(1).charAt(0);
\r
819 monetaryGroupingSeparator = currencyRes.getString(2).charAt(0);
\r
821 }catch(MissingResourceException ex){
\r
822 /* else An explicit currency was requested and is unknown or locale data is malformed. */
\r
823 /* decimal format API will get the correct value later on. */
\r
826 /* else no currency keyword used. */
\r
828 //monetarySeparator = numberElements[11].charAt(0);
\r
830 // Get Currency Spacing data.
\r
831 currencySpcBeforeSym = new String[CURRENCY_SPC_INSERT+1];
\r
832 currencySpcAfterSym = new String[CURRENCY_SPC_INSERT+1];
\r
833 ICUResourceBundle curSpcBundle = (ICUResourceBundle)r.get(CURRENCY_SPACING);
\r
834 if (curSpcBundle != null) {
\r
835 ICUResourceBundle beforeCurBundle = (ICUResourceBundle)curSpcBundle.get(BEFORE_CURRENCY);
\r
836 ICUResourceBundle afterCurBundle = (ICUResourceBundle)curSpcBundle.get(AFTER_CURRENCY);
\r
837 for (int i = CURRENCY_SPC_CURRENCY_MATCH; i <= CURRENCY_SPC_INSERT; i++) {
\r
838 currencySpcBeforeSym[i] = beforeCurBundle.getStringWithFallback(CURRENCY_SPACING_KEYS[i]);
\r
839 currencySpcAfterSym[i] = afterCurBundle.getStringWithFallback(CURRENCY_SPACING_KEYS[i]);
\r
846 * Read the default serializable fields, then if <code>serialVersionOnStream</code>
\r
847 * is less than 1, initialize <code>monetarySeparator</code> to be
\r
848 * the same as <code>decimalSeparator</code> and <code>exponential</code>
\r
850 * Finally, set serialVersionOnStream back to the maximum allowed value so that
\r
851 * default serialization will work properly if this object is streamed out again.
\r
853 private void readObject(ObjectInputStream stream)
\r
854 throws IOException, ClassNotFoundException {
\r
856 // TODO: it looks to me {dlf} that the serialization code was never updated
\r
857 // to handle the actual/valid ulocale fields.
\r
859 stream.defaultReadObject();
\r
861 // we don't have data for these old serialized forms any more
\r
862 if (serialVersionOnStream < 1) {
\r
863 // Didn't have monetarySeparator or exponential field;
\r
865 monetarySeparator = decimalSeparator;
\r
868 if (serialVersionOnStream < 2) {
\r
869 padEscape = DecimalFormat.PATTERN_PAD_ESCAPE;
\r
870 plusSign = DecimalFormat.PATTERN_PLUS_SIGN;
\r
871 exponentSeparator = String.valueOf(exponential);
\r
872 // Although we read the exponential field on stream to create the
\r
873 // exponentSeparator, we don't do the reverse, since scientific
\r
874 // notation isn't supported by the old classes, even though the
\r
875 // symbol is there.
\r
878 if (serialVersionOnStream < 3) {
\r
879 // Resurrected objects from old streams will have no
\r
880 // locale. There is no 100% fix for this. A
\r
881 // 90% fix is to construct a mapping of data back to
\r
882 // locale, perhaps a hash of all our members. This is
\r
883 // expensive and doesn't seem worth it.
\r
884 requestedLocale = Locale.getDefault();
\r
886 if (serialVersionOnStream < 4) {
\r
887 // use same default behavior as for versions with no Locale
\r
888 ulocale = ULocale.forLocale(requestedLocale);
\r
890 if (serialVersionOnStream < 5) {
\r
891 // use the same one for groupingSeparator
\r
892 monetaryGroupingSeparator = groupingSeparator;
\r
894 if (serialVersionOnStream < 6) {
\r
895 // Set null to CurrencySpacing related fields.
\r
896 if (currencySpcBeforeSym == null) {
\r
897 currencySpcBeforeSym = new String[CURRENCY_SPC_INSERT+1];
\r
899 if (currencySpcAfterSym == null) {
\r
900 currencySpcAfterSym = new String[CURRENCY_SPC_INSERT+1];
\r
902 currencySpcBeforeSym[CURRENCY_SPC_CURRENCY_MATCH] =
\r
903 currencySpcAfterSym[CURRENCY_SPC_CURRENCY_MATCH] = DEFAULT_SPC_MATCH;
\r
904 currencySpcBeforeSym[CURRENCT_SPC_SURROUNDING_MATCH] =
\r
905 currencySpcAfterSym[CURRENCT_SPC_SURROUNDING_MATCH] = DEFAULT_SPC_SUR_MATCH;
\r
906 currencySpcBeforeSym[CURRENCY_SPC_INSERT] =
\r
907 currencySpcAfterSym[CURRENCY_SPC_INSERT] = DEFAULT_SPC_INSERT;
\r
909 serialVersionOnStream = currentSerialVersion;
\r
912 currency = Currency.getInstance(intlCurrencySymbol);
\r
916 * Character used for zero.
\r
919 * @see #getZeroDigit
\r
921 private char zeroDigit;
\r
924 * Character used for thousands separator.
\r
927 * @see #getGroupingSeparator
\r
929 private char groupingSeparator;
\r
932 * Character used for decimal sign.
\r
935 * @see #getDecimalSeparator
\r
937 private char decimalSeparator;
\r
940 * Character used for mille percent sign.
\r
945 private char perMill;
\r
948 * Character used for percent sign.
\r
952 private char percent;
\r
955 * Character used for a digit in a pattern.
\r
960 private char digit;
\r
963 * Character used for a significant digit in a pattern.
\r
966 * @see #getSignificantDigit
\r
968 private char sigDigit;
\r
971 * Character used to separate positive and negative subpatterns
\r
975 * @see #getPatternSeparator
\r
977 private char patternSeparator;
\r
980 * Character used to represent infinity.
\r
982 * @see #getInfinity
\r
984 private String infinity;
\r
987 * Character used to represent NaN.
\r
991 private String NaN;
\r
994 * Character used to represent minus sign.
\r
996 * @see #getMinusSign
\r
998 private char minusSign;
\r
1001 * String denoting the local currency, e.g. "$".
\r
1003 * @see #getCurrencySymbol
\r
1005 private String currencySymbol;
\r
1008 * International string denoting the local currency, e.g. "USD".
\r
1010 * @see #getInternationalCurrencySymbol
\r
1012 private String intlCurrencySymbol;
\r
1015 * The decimal separator used when formatting currency values.
\r
1017 * @see #getMonetaryDecimalSeparator
\r
1019 private char monetarySeparator; // Field new in JDK 1.1.6
\r
1022 * The decimal separator used when formatting currency values.
\r
1024 * @see #getMonetaryGroupingSeparator
\r
1026 private char monetaryGroupingSeparator; // Field new in JDK 1.1.6
\r
1029 * The character used to distinguish the exponent in a number formatted
\r
1030 * in exponential notation, e.g. 'E' for a number such as "1.23E45".
\r
1032 * Note that this field has been superseded by <code>exponentSeparator</code>.
\r
1033 * It is retained for backward compatibility.
\r
1037 private char exponential; // Field new in JDK 1.1.6
\r
1040 * The string used to separate the mantissa from the exponent.
\r
1041 * Examples: "x10^" for 1.23x10^4, "E" for 1.23E4.
\r
1043 * Note that this supersedes the <code>exponential</code> field.
\r
1046 * @since AlphaWorks
\r
1048 private String exponentSeparator;
\r
1051 * <strong><font face=helvetica color=red>NEW</font></strong>
\r
1052 * The character used to indicate a padding character in a format,
\r
1053 * e.g., '*' in a pattern such as "$*_#,##0.00".
\r
1055 * @since AlphaWorks
\r
1057 private char padEscape;
\r
1060 * <strong><font face=helvetica color=red>NEW</font></strong>
\r
1061 * The character used to indicate a plus sign.
\r
1063 * @since AlphaWorks
\r
1065 private char plusSign;
\r
1068 * The locale for which this object was constructed. Set to the
\r
1069 * default locale for objects resurrected from old streams.
\r
1072 private Locale requestedLocale;
\r
1075 * The requested ULocale. We keep the old locale for serialization compatibility.
\r
1078 private ULocale ulocale;
\r
1080 // Proclaim JDK 1.1 FCS compatibility
\r
1081 private static final long serialVersionUID = 5772796243397350300L;
\r
1083 // The internal serial version which says which version was written
\r
1084 // - 0 (default) for version up to JDK 1.1.5
\r
1085 // - 1 for version from JDK 1.1.6, which includes two new fields:
\r
1086 // monetarySeparator and exponential.
\r
1087 // - 2 for version from AlphaWorks, which includes 3 new fields:
\r
1088 // padEscape, exponentSeparator, and plusSign.
\r
1089 // - 3 for ICU 2.2, which includes the locale field
\r
1090 // - 4 for ICU 3.2, which includes the ULocale field
\r
1091 // - 5 for ICU 3.6, which includes the monetaryGroupingSeparator field
\r
1092 // - 6 for ICU 4.2, which includes the currencySpc* fields
\r
1093 private static final int currentSerialVersion = 6;
\r
1096 * Describes the version of <code>DecimalFormatSymbols</code> present on the stream.
\r
1097 * Possible values are:
\r
1099 * <li><b>0</b> (or uninitialized): versions prior to JDK 1.1.6.
\r
1101 * <li><b>1</b>: Versions written by JDK 1.1.6 or later, which includes
\r
1102 * two new fields: <code>monetarySeparator</code> and <code>exponential</code>.
\r
1103 * <li><b>2</b>: Version for AlphaWorks. Adds padEscape, exponentSeparator,
\r
1106 * When streaming out a <code>DecimalFormatSymbols</code>, the most recent format
\r
1107 * (corresponding to the highest allowable <code>serialVersionOnStream</code>)
\r
1108 * is always written.
\r
1112 private int serialVersionOnStream = currentSerialVersion;
\r
1115 * cache to hold the NumberElements of a Locale.
\r
1117 private static final Hashtable cachedLocaleData = new Hashtable(3);
\r
1122 private String currencyPattern = null;
\r
1124 // -------- BEGIN ULocale boilerplate --------
\r
1127 * Return the locale that was used to create this object, or null.
\r
1128 * This may may differ from the locale requested at the time of
\r
1129 * this object's creation. For example, if an object is created
\r
1130 * for locale <tt>en_US_CALIFORNIA</tt>, the actual data may be
\r
1131 * drawn from <tt>en</tt> (the <i>actual</i> locale), and
\r
1132 * <tt>en_US</tt> may be the most specific locale that exists (the
\r
1133 * <i>valid</i> locale).
\r
1135 * <p>Note: This method will be implemented in ICU 3.0; ICU 2.8
\r
1136 * contains a partial preview implementation. The * <i>actual</i>
\r
1137 * locale is returned correctly, but the <i>valid</i> locale is
\r
1138 * not, in most cases.
\r
1139 * @param type type of information requested, either {@link
\r
1140 * com.ibm.icu.util.ULocale#VALID_LOCALE} or {@link
\r
1141 * com.ibm.icu.util.ULocale#ACTUAL_LOCALE}.
\r
1142 * @return the information specified by <i>type</i>, or null if
\r
1143 * this object was not constructed from locale data.
\r
1144 * @see com.ibm.icu.util.ULocale
\r
1145 * @see com.ibm.icu.util.ULocale#VALID_LOCALE
\r
1146 * @see com.ibm.icu.util.ULocale#ACTUAL_LOCALE
\r
1147 * @draft ICU 2.8 (retain)
\r
1148 * @provisional This API might change or be removed in a future release.
\r
1150 public final ULocale getLocale(ULocale.Type type) {
\r
1151 return type == ULocale.ACTUAL_LOCALE ?
\r
1152 this.actualLocale : this.validLocale;
\r
1156 * Set information about the locales that were used to create this
\r
1157 * object. If the object was not constructed from locale data,
\r
1158 * both arguments should be set to null. Otherwise, neither
\r
1159 * should be null. The actual locale must be at the same level or
\r
1160 * less specific than the valid locale. This method is intended
\r
1161 * for use by factories or other entities that create objects of
\r
1163 * @param valid the most specific locale containing any resource
\r
1165 * @param actual the locale containing data used to construct this
\r
1167 * @see com.ibm.icu.util.ULocale
\r
1168 * @see com.ibm.icu.util.ULocale#VALID_LOCALE
\r
1169 * @see com.ibm.icu.util.ULocale#ACTUAL_LOCALE
\r
1172 final void setLocale(ULocale valid, ULocale actual) {
\r
1173 // Change the following to an assertion later
\r
1174 if ((valid == null) != (actual == null)) {
\r
1176 throw new IllegalArgumentException();
\r
1179 // Another check we could do is that the actual locale is at
\r
1180 // the same level or less specific than the valid locale.
\r
1181 this.validLocale = valid;
\r
1182 this.actualLocale = actual;
\r
1186 * The most specific locale containing any resource data, or null.
\r
1187 * @see com.ibm.icu.util.ULocale
\r
1190 private ULocale validLocale;
\r
1193 * The locale containing data used to construct this object, or
\r
1195 * @see com.ibm.icu.util.ULocale
\r
1198 private ULocale actualLocale;
\r
1200 // not serialized, reconstructed from intlCurrencyCode
\r
1201 private transient Currency currency;
\r
1203 // -------- END ULocale boilerplate --------
\r