OSDN Git Service

* java/util/IdentityHashMap.java (put): Replace mistaken use of
[pf3gnuchains/gcc-fork.git] / libjava / java / util / Locale.java
1 /* Locale.java -- i18n locales
2    Copyright (C) 1998, 1999, 2001, 2002 Free Software Foundation, Inc.
3
4 This file is part of GNU Classpath.
5
6 GNU Classpath is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2, or (at your option)
9 any later version.
10
11 GNU Classpath is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14 General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with GNU Classpath; see the file COPYING.  If not, write to the
18 Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
19 02111-1307 USA.
20
21 Linking this library statically or dynamically with other modules is
22 making a combined work based on this library.  Thus, the terms and
23 conditions of the GNU General Public License cover the whole
24 combination.
25
26 As a special exception, the copyright holders of this library give you
27 permission to link this library with independent modules to produce an
28 executable, regardless of the license terms of these independent
29 modules, and to copy and distribute the resulting executable under
30 terms of your choice, provided that you also meet, for each linked
31 independent module, the terms and conditions of the license of that
32 module.  An independent module is a module which is not derived from
33 or based on this library.  If you modify this library, you may extend
34 this exception to your version of the library, but you are not
35 obligated to do so.  If you do not wish to do so, delete this
36 exception statement from your version. */
37
38 package java.util;
39
40 import java.io.IOException;
41 import java.io.ObjectInputStream;
42 import java.io.ObjectOutputStream;
43 import java.io.Serializable;
44
45 /**
46  * Locales represent a specific country and culture. Classes which can be
47  * passed a Locale object tailor their information for a given locale. For
48  * instance, currency number formatting is handled differently for the USA
49  * and France.
50  *
51  * <p>Locales are made up of a language code, a country code, and an optional
52  * set of variant strings. Language codes are represented by
53  * <a href="http://www.ics.uci.edu/pub/ietf/http/related/iso639.txt">
54  * ISO 639:1988</a> w/ additions from ISO 639/RA Newsletter No. 1/1989
55  * and a decision of the Advisory Committee of ISO/TC39 on August 8, 1997.
56  *
57  * <p>Country codes are represented by
58  * <a href="http://www.chemie.fu-berlin.de/diverse/doc/ISO_3166.html">
59  * ISO 3166</a>. Variant strings are vendor and browser specific. Standard
60  * variant strings include "POSIX" for POSIX, "WIN" for MS-Windows, and
61  * "MAC" for Macintosh. When there is more than one variant string, they must
62  * be separated by an underscore (U+005F).
63  *
64  * <p>The default locale is determined by the values of the system properties
65  * user.language, user.region, and user.variant, defaulting to "en". Note that
66  * the locale does NOT contain the conversion and formatting capabilities (for
67  * that, use ResourceBundle and java.text). Rather, it is an immutable tag
68  * object for identifying a given locale, which is referenced by these other
69  * classes when they must make locale-dependent decisions.
70  *
71  * @see ResourceBundle
72  * @see java.text.Format
73  * @see java.text.NumberFormat
74  * @see java.text.Collator
75  * @author Jochen Hoenicke
76  * @author Paul Fisher
77  * @author Eric Blake <ebb9@email.byu.edu>
78  * @since 1.1
79  * @status updated to 1.4
80  */
81 public final class Locale implements Serializable, Cloneable
82 {
83   /** Locale which represents the English language. */
84   public static final Locale ENGLISH = new Locale("en");
85
86   /** Locale which represents the French language. */
87   public static final Locale FRENCH = new Locale("fr");
88
89   /** Locale which represents the German language. */
90   public static final Locale GERMAN = new Locale("de");
91
92   /** Locale which represents the Italian language. */
93   public static final Locale ITALIAN = new Locale("it");
94
95   /** Locale which represents the Japanese language. */
96   public static final Locale JAPANESE = new Locale("ja");
97
98   /** Locale which represents the Korean language. */
99   public static final Locale KOREAN = new Locale("ko");
100
101   /** Locale which represents the Chinese language. */
102   public static final Locale CHINESE = new Locale("zh");
103
104   /** Locale which represents the Chinese language as used in China. */
105   public static final Locale SIMPLIFIED_CHINESE = new Locale("zh", "CN");
106
107   /**
108    * Locale which represents the Chinese language as used in Taiwan.
109    * Same as TAIWAN Locale.
110    */
111   public static final Locale TRADITIONAL_CHINESE = new Locale("zh", "TW");
112
113   /** Locale which represents France. */
114   public static final Locale FRANCE = new Locale("fr", "FR");
115
116   /** Locale which represents Germany. */
117   public static final Locale GERMANY = new Locale("de", "DE");
118
119   /** Locale which represents Italy. */
120   public static final Locale ITALY = new Locale("it", "IT");
121
122   /** Locale which represents Japan. */
123   public static final Locale JAPAN = new Locale("ja", "JP");
124
125   /** Locale which represents Korea. */
126   public static final Locale KOREA = new Locale("ko", "KR");
127
128   /**
129    * Locale which represents China.
130    * Same as SIMPLIFIED_CHINESE Locale.
131    */
132   public static final Locale CHINA = SIMPLIFIED_CHINESE;
133
134   /**
135    * Locale which represents the People's Republic of China.
136    * Same as CHINA Locale.
137    */
138   public static final Locale PRC = CHINA;
139
140   /**
141    * Locale which represents Taiwan.
142    * Same as TRADITIONAL_CHINESE Locale.
143    */
144   public static final Locale TAIWAN = TRADITIONAL_CHINESE;
145
146   /** Locale which represents the United Kingdom. */
147   public static final Locale UK = new Locale("en", "GB");
148
149   /** Locale which represents the United States. */
150   public static final Locale US = new Locale("en", "US");
151
152   /** Locale which represents the English speaking portion of Canada. */
153   public static final Locale CANADA = new Locale("en", "CA");
154
155   /** Locale which represents the French speaking portion of Canada. */
156   public static final Locale CANADA_FRENCH = new Locale("fr", "CA");
157
158   /**
159    * Compatible with JDK 1.1+.
160    */
161   private static final long serialVersionUID = 9149081749638150636L;
162
163   /**
164    * The language code, as returned by getLanguage().
165    *
166    * @serial the languange, possibly ""
167    */
168   private String language;
169
170   /**
171    * The country code, as returned by getCountry().
172    *
173    * @serial the country, possibly ""
174    */
175   private String country;
176
177   /**
178    * The variant code, as returned by getVariant().
179    *
180    * @serial the variant, possibly ""
181    */
182   private String variant;
183
184   /**
185    * This is the cached hashcode. When writing to stream, we write -1.
186    *
187    * @serial should be -1 in serial streams
188    */
189   private transient int hashcode;
190
191   /**
192    * The default locale. Except for during bootstrapping, this should never be
193    * null. Note the logic in the main constructor, to detect when
194    * bootstrapping has completed.
195    */
196   private static Locale defaultLocale =
197     new Locale(System.getProperty("user.language", "en"),
198                System.getProperty("user.region", ""),
199                System.getProperty("user.variant", ""));
200
201   /**
202    * Convert new iso639 codes to the old ones.
203    *
204    * @param language the language to check
205    * @return the appropriate code
206    */
207   private String convertLanguage(String language)
208   {
209     if (language.equals(""))
210       return language;
211     language = language.toLowerCase();
212     int index = "he,id,yi".indexOf(language);
213     if (index != -1)
214       return "iw,in,ji".substring(index, index + 2);
215     return language;
216   }
217
218   /**
219    * Creates a new locale for the given language and country.
220    *
221    * @param language lowercase two-letter ISO-639 A2 language code
222    * @param country uppercase two-letter ISO-3166 A2 contry code
223    * @param variant vendor and browser specific
224    * @throws NullPointerException if any argument is null
225    */
226   public Locale(String language, String country, String variant)
227   {
228     // During bootstrap, we already know the strings being passed in are
229     // the correct capitalization, and not null. We can't call
230     // String.toUpperCase during this time, since that depends on the
231     // default locale.
232     if (defaultLocale != null)
233       {
234         language = convertLanguage(language).intern();
235         country = country.toUpperCase().intern();
236         variant = variant.toUpperCase().intern();
237       }
238     this.language = language;
239     this.country = country;
240     this.variant = variant;
241     hashcode = language.hashCode() ^ country.hashCode() ^ variant.hashCode();
242   }
243
244   /**
245    * Creates a new locale for the given language and country.
246    *
247    * @param language lowercase two-letter ISO-639 A2 language code
248    * @param country uppercase two-letter ISO-3166 A2 country code
249    * @throws NullPointerException if either argument is null
250    */
251   public Locale(String language, String country)
252   {
253     this(language, country, "");
254   }
255
256   /**
257    * Creates a new locale for a language.
258    *
259    * @param language lowercase two-letter ISO-639 A2 language code
260    * @throws NullPointerException if either argument is null
261    * @since 1.4
262    */
263   public Locale(String language)
264   {
265     this(language, "", "");
266   }
267
268   /**
269    * Returns the default Locale. The default locale is generally once set
270    * on start up and then never changed. Normally you should use this locale
271    * for everywhere you need a locale. The initial setting matches the
272    * default locale, the user has chosen.
273    *
274    * @return the default locale for this virtual machine
275    */
276   public static Locale getDefault()
277   {
278     return defaultLocale;
279   }
280
281   /**
282    * Changes the default locale. Normally only called on program start up.
283    * Note that this doesn't change the locale for other programs. This has
284    * a security check,
285    * <code>PropertyPermission("user.language", "write")</code>, because of
286    * its potential impact to running code.
287    *
288    * @param newLocale the new default locale
289    * @throws NullPointerException if newLocale is null
290    * @throws SecurityException if permission is denied
291    */
292   public static void setDefault(Locale newLocale)
293   {
294     if (newLocale == null)
295       throw new NullPointerException();
296     SecurityManager sm = System.getSecurityManager();
297     if (sm != null)
298       sm.checkPermission(new PropertyPermission("user.language", "write"));
299     defaultLocale = newLocale;
300   }
301
302   /**
303    * Returns the list of available locales.
304    *
305    * @return the installed locales
306    */
307   public static Locale[] getAvailableLocales()
308   {
309     /* I only return those for which localized language
310      * or country information exists.
311      * XXX - remove hard coded list, and implement more locales (Sun's JDK 1.4
312      * has 148 installed locales!).
313      */
314     return new Locale[]
315     {
316       ENGLISH, FRENCH, GERMAN, new Locale("ga", "")
317     };
318   }
319
320   /**
321    * Returns a list of all 2-letter uppercase country codes as defined
322    * in ISO 3166.
323    *
324    * @return a list of acceptible country codes
325    */
326   public static String[] getISOCountries()
327   {
328     return new String[]
329     {
330       "AD", "AE", "AF", "AG", "AI", "AL", "AM", "AN", "AO", "AQ", "AR", "AS",
331       "AT", "AU", "AW", "AZ", "BA", "BB", "BD", "BE", "BF", "BG", "BH", "BI",
332       "BJ", "BM", "BN", "BO", "BR", "BS", "BT", "BV", "BW", "BY", "BZ", "CA",
333       "CC", "CF", "CG", "CH", "CI", "CK", "CL", "CM", "CN", "CO", "CR", "CU",
334       "CV", "CX", "CY", "CZ", "DE", "DJ", "DK", "DM", "DO", "DZ", "EC", "EE",
335       "EG", "EH", "ER", "ES", "ET", "FI", "FJ", "FK", "FM", "FO", "FR", "FX",
336       "GA", "GB", "GD", "GE", "GF", "GH", "GI", "GL", "GM", "GN", "GP", "GQ",
337       "GR", "GS", "GT", "GU", "GW", "GY", "HK", "HM", "HN", "HR", "HT", "HU",
338       "ID", "IE", "IL", "IN", "IO", "IQ", "IR", "IS", "IT", "JM", "JO", "JP",
339       "KE", "KG", "KH", "KI", "KM", "KN", "KP", "KR", "KW", "KY", "KZ", "LA",
340       "LB", "LC", "LI", "LK", "LR", "LS", "LT", "LU", "LV", "LY", "MA", "MC",
341       "MD", "MG", "MH", "MK", "ML", "MM", "MN", "MO", "MP", "MQ", "MR", "MS",
342       "MT", "MU", "MV", "MW", "MX", "MY", "MZ", "NA", "NC", "NE", "NF", "NG",
343       "NI", "NL", "NO", "NP", "NR", "NU", "NZ", "OM", "PA", "PE", "PF", "PG",
344       "PH", "PK", "PL", "PM", "PN", "PR", "PT", "PW", "PY", "QA", "RE", "RO",
345       "RU", "RW", "SA", "SB", "SC", "SD", "SE", "SG", "SH", "SI", "SJ", "SK",
346       "SL", "SM", "SN", "SO", "SR", "ST", "SV", "SY", "SZ", "TC", "TD", "TF",
347       "TG", "TH", "TJ", "TK", "TM", "TN", "TO", "TP", "TR", "TT", "TV", "TW",
348       "TZ", "UA", "UG", "UM", "US", "UY", "UZ", "VA", "VC", "VE", "VG", "VI",
349       "VN", "VU", "WF", "WS", "YE", "YT", "YU", "ZA", "ZM", "ZR", "ZW"
350     };
351   }
352
353   /**
354    * Returns a list of all 2-letter lowercase language codes as defined
355    * in ISO 639 (both old and new variant).
356    *
357    * @return a list of acceptable language codes
358    */
359   public static String[] getISOLanguages()
360   {
361     return new String[]
362     {
363       "aa", "ab", "af", "am", "ar", "as", "ay", "az", "ba", "be", "bg", "bh",
364       "bi", "bn", "bo", "br", "ca", "co", "cs", "cy", "da", "de", "dz", "el",
365       "en", "eo", "es", "et", "eu", "fa", "fi", "fj", "fo", "fr", "fy", "ga",
366       "gd", "gl", "gn", "gu", "ha", "he", "hi", "hr", "hu", "hy", "ia", "id",
367       "ie", "ik", "in", "is", "it", "iu", "iw", "ja", "ji", "jw", "ka", "kk",
368       "kl", "km", "kn", "ko", "ks", "ku", "ky", "la", "ln", "lo", "lt", "lv",
369       "mg", "mi", "mk", "ml", "mn", "mo", "mr", "ms", "mt", "my", "na", "ne",
370       "nl", "no", "oc", "om", "or", "pa", "pl", "ps", "pt", "qu", "rm", "rn",
371       "ro", "ru", "rw", "sa", "sd", "sg", "sh", "si", "sk", "sl", "sm", "sn",
372       "so", "sq", "sr", "ss", "st", "su", "sv", "sw", "ta", "te", "tg", "th",
373       "ti", "tk", "tl", "tn", "to", "tr", "ts", "tt", "tw", "ug", "uk", "ur",
374       "uz", "vi", "vo", "wo", "xh", "yi", "yo", "za", "zh", "zu"
375     };
376   }
377
378   /**
379    * Returns the language code of this locale. Some language codes have changed
380    * as ISO 639 has evolved; this returns the old name, even if you built
381    * the locale with the new one.
382    *
383    * @return language code portion of this locale, or an empty String
384    */
385   public String getLanguage()
386   {
387     return language;
388   }
389
390   /**
391    * Returns the country code of this locale.
392    *
393    * @return country code portion of this locale, or an empty String
394    */
395   public String getCountry()
396   {
397     return country;
398   }
399
400   /**
401    * Returns the variant code of this locale.
402    *
403    * @return the variant code portion of this locale, or an empty String
404    */
405   public String getVariant()
406   {
407     return variant;
408   }
409
410   /**
411    * Gets the string representation of the current locale. This consists of
412    * the language, the country, and the variant, separated by an underscore.
413    * The variant is listed only if there is a language or country. Examples:
414    * "en", "de_DE", "_GB", "en_US_WIN", "de__POSIX", "fr__MAC".
415    *
416    * @return the string representation of this Locale
417    * @see #getDisplayName()
418    */
419   public String toString()
420   {
421     if (language.length() == 0 && country.length() == 0)
422       return "";
423     else if (country.length() == 0 && variant.length() == 0)
424       return language;
425     StringBuffer result = new StringBuffer(language);
426     result.append('_').append(country);
427     if (variant.length() != 0)
428       result.append('_').append(variant);
429     return result.toString();
430   }
431
432   /**
433    * Returns the three-letter ISO language abbrevation of this locale.
434    *
435    * @throws MissingResourceException if the three-letter code is not known
436    */
437   public String getISO3Language()
438   {
439     // We know all strings are interned so we can use '==' for better performance.
440     if (language == "")
441       return "";
442     int index
443       = ("aa,ab,af,am,ar,as,ay,az,ba,be,bg,bh,bi,bn,bo,br,ca,co,cs,cy,da,"
444          + "de,dz,el,en,eo,es,et,eu,fa,fi,fj,fo,fr,fy,ga,gd,gl,gn,gu,ha,iw,"
445          + "hi,hr,hu,hy,ia,in,ie,ik,in,is,it,iu,iw,ja,ji,jw,ka,kk,kl,km,kn,"
446          + "ko,ks,ku,ky,la,ln,lo,lt,lv,mg,mi,mk,ml,mn,mo,mr,ms,mt,my,na,ne,"
447          + "nl,no,oc,om,or,pa,pl,ps,pt,qu,rm,rn,ro,ru,rw,sa,sd,sg,sh,si,sk,"
448          + "sl,sm,sn,so,sq,sr,ss,st,su,sv,sw,ta,te,tg,th,ti,tk,tl,tn,to,tr,"
449          + "ts,tt,tw,ug,uk,ur,uz,vi,vo,wo,xh,ji,yo,za,zh,zu")
450       .indexOf(language);
451
452     if (index % 3 != 0 || language.length() != 2)
453       throw new MissingResourceException
454         ("Can't find ISO3 language for " + language,
455          "java.util.Locale", language);
456
457     // Don't read this aloud. These are the three letter language codes.
458     return
459       ("aarabkaframharaasmaymazebakbelbulbihbisbenbodbrecatcoscescymdandeu"
460        + "dzoellengepospaesteusfasfinfijfaofrafrygaigdhglggrngujhauhebhinhrv"
461        + "hunhyeinaindileipkindislitaikuhebjpnyidjawkatkazkalkhmkankorkaskur"
462        + "kirlatlinlaolitlavmlgmrimkdmalmonmolmarmsamltmyanaunepnldnorociorm"
463        + "oripanpolpusporquerohrunronruskinsansndsagsrpsinslkslvsmosnasomsqi"
464        + "srpsswsotsunsweswatamteltgkthatirtuktgltsntonturtsotattwiuigukrurd"
465        + "uzbvievolwolxhoyidyorzhazhozul")
466       .substring(index, index + 3);
467   }
468
469   /**
470    * Returns the three-letter ISO country abbrevation of the locale.
471    *
472    * @throws MissingResourceException if the three-letter code is not known
473    */
474   public String getISO3Country()
475   {
476     // We know all strings are interned so we can use '==' for better performance.
477     if (country == "")
478       return "";
479     int index
480       = ("AD,AE,AF,AG,AI,AL,AM,AN,AO,AQ,AR,AS,AT,AU,AW,AZ,BA,BB,BD,BE,BF,"
481          + "BG,BH,BI,BJ,BM,BN,BO,BR,BS,BT,BV,BW,BY,BZ,CA,CC,CF,CG,CH,CI,CK,"
482          + "CL,CM,CN,CO,CR,CU,CV,CX,CY,CZ,DE,DJ,DK,DM,DO,DZ,EC,EE,EG,EH,ER,"
483          + "ES,ET,FI,FJ,FK,FM,FO,FR,FX,GA,GB,GD,GE,GF,GH,GI,GL,GM,GN,GP,GQ,"
484          + "GR,GS,GT,GU,GW,GY,HK,HM,HN,HR,HT,HU,ID,IE,IL,IN,IO,IQ,IR,IS,IT,"
485          + "JM,JO,JP,KE,KG,KH,KI,KM,KN,KP,KR,KW,KY,KZ,LA,LB,LC,LI,LK,LR,LS,"
486          + "LT,LU,LV,LY,MA,MC,MD,MG,MH,MK,ML,MM,MN,MO,MP,MQ,MR,MS,MT,MU,MV,"
487          + "MW,MX,MY,MZ,NA,NC,NE,NF,NG,NI,NL,NO,NP,NR,NU,NZ,OM,PA,PE,PF,PG,"
488          + "PH,PK,PL,PM,PN,PR,PT,PW,PY,QA,RE,RO,RU,RW,SA,SB,SC,SD,SE,SG,SH,"
489          + "SI,SJ,SK,SL,SM,SN,SO,SR,ST,SV,SY,SZ,TC,TD,TF,TG,TH,TJ,TK,TM,TN,"
490          + "TO,TP,TR,TT,TV,TW,TZ,UA,UG,UM,US,UY,UZ,VA,VC,VE,VG,VI,VN,VU,WF,"
491          + "WS,YE,YT,YU,ZA,ZM,ZR,ZW")
492       .indexOf(country);
493
494     if (index % 3 != 0 || country.length() != 2)
495       throw new MissingResourceException
496         ("Can't find ISO3 country for " + country,
497          "java.util.Locale", country);
498
499     // Don't read this aloud. These are the three letter country codes.
500     return
501       ("ANDAREAFGATGAIAALBARMANTAGOATAARGASMAUTAUSABWAZEBIHBRBBGDBELBFABGR"
502        + "BHRBDIBENBMUBRNBOLBRABHSBTNBVTBWABLRBLZCANCCKCAFCOGCHECIVCOKCHLCMR"
503        + "CHNCOLCRICUBCPVCXRCYPCZEDEUDJIDNKDMADOMDZAECUESTEGYESHERIESPETHFIN"
504        + "FJIFLKFSMFROFRAFXXGABGBRGRDGEOGUFGHAGIBGRLGMBGINGLPGNQGRCSGSGTMGUM"
505        + "GNBGUYHKGHMDHNDHRVHTIHUNIDNIRLISRINDIOTIRQIRNISLITAJAMJORJPNKENKGZ"
506        + "KHMKIRCOMKNAPRKKORKWTCYMKAZLAOLBNLCALIELKALBRLSOLTULUXLVALBYMARMCO"
507        + "MDAMDGMHLMKDMLIMMRMNGMACMNPMTQMRTMSRMLTMUSMDVMWIMEXMYSMOZNAMNCLNER"
508        + "NFKNGANICNLDNORNPLNRUNIUNZLOMNPANPERPYFPNGPHLPAKPOLSPMPCNPRIPRTPLW"
509        + "PRYQATREUROMRUSRWASAUSLBSYCSDNSWESGPSHNSVNSJMSVKSLESMRSENSOMSURSTP"
510        + "SLVSYRSWZTCATCDATFTGOTHATJKTKLTKMTUNTONTMPTURTTOTUVTWNTZAUKRUGAUMI"
511        + "USAURYUZBVATVCTVENVGBVIRVNMVUTWLFWSMYEMMYTYUGZAFZMBZARZWE")
512       .substring(index, index + 3);
513   }
514
515   /**
516    * Gets the country name suitable for display to the user, formatted
517    * for the default locale.  This has the same effect as
518    * <pre>
519    * getDisplayLanguage(Locale.getDefault());
520    * </pre>
521    *
522    * @return the language name of this locale localized to the default locale,
523    *         with the ISO code as backup
524    */
525   public String getDisplayLanguage()
526   {
527     return getDisplayLanguage(defaultLocale);
528   }
529
530   /**
531    * Gets the language name suitable for display to the user, formatted
532    * for a specified locale.
533    *
534    * @param locale locale to use for formatting
535    * @return the language name of this locale localized to the given locale,
536    *         with the ISO code as backup
537    */
538   public String getDisplayLanguage(Locale locale)
539   {
540     try
541       {
542         ResourceBundle bundle
543           = ResourceBundle.getBundle("gnu.java.locale.iso639", locale);
544         return bundle.getString(language);
545       }
546     catch (MissingResourceException ex)
547       {
548         return language;
549       }
550   }
551
552   /**
553    * Returns the country name of this locale localized to the
554    * default locale. If the localized is not found, the ISO code
555    * is returned. This has the same effect as
556    * <pre>
557    * getDisplayCountry(Locale.getDefault());
558    * </pre>
559    *
560    * @return the country name of this locale localized to the given locale,
561    *         with the ISO code as backup
562    */
563   public String getDisplayCountry()
564   {
565     return getDisplayCountry(defaultLocale);
566   }
567
568   /**
569    * Gets the country name suitable for display to the user, formatted
570    * for a specified locale.
571    *
572    * @param locale locale to use for formatting
573    * @return the country name of this locale localized to the given locale,
574    *         with the ISO code as backup
575    */
576   public String getDisplayCountry(Locale locale)
577   {
578     try
579       {
580         ResourceBundle bundle =
581           ResourceBundle.getBundle("gnu.java.locale.iso3166", locale);
582         return bundle.getString(country);
583       }
584     catch (MissingResourceException ex)
585       {
586         return country;
587       }
588   }
589
590   /**
591    * Returns the variant name of this locale localized to the
592    * default locale. If the localized is not found, the variant code
593    * itself is returned. This has the same effect as
594    * <pre>
595    * getDisplayVariant(Locale.getDefault());
596    * </pre>
597    *
598    * @return the variant code of this locale localized to the given locale,
599    *         with the ISO code as backup
600    */
601   public String getDisplayVariant()
602   {
603     return getDisplayVariant(defaultLocale);
604   }
605
606   /**
607    * Returns the variant name of this locale localized to the
608    * given locale. If the localized is not found, the variant code
609    * itself is returned.
610    *
611    * @param locale locale to use for formatting
612    * @return the variant code of this locale localized to the given locale,
613    *         with the ISO code as backup
614    */
615   public String getDisplayVariant(Locale locale)
616   {
617     // XXX - load a bundle?
618     return variant;
619   }
620
621   /**
622    * Gets all local components suitable for display to the user, formatted
623    * for the default locale. For the language component, getDisplayLanguage
624    * is called. For the country component, getDisplayCountry is called.
625    * For the variant set component, getDisplayVariant is called.
626    *
627    * <p>The returned String will be one of the following forms:<br>
628    * <pre>
629    * language (country, variant)
630    * language (country)
631    * language (variant)
632    * country (variant)
633    * language
634    * country
635    * variant
636    * </pre>
637    *
638    * @return String version of this locale, suitable for display to the user
639    */
640   public String getDisplayName()
641   {
642     return getDisplayName(defaultLocale);
643   }
644
645   /**
646    * Gets all local components suitable for display to the user, formatted
647    * for a specified locale. For the language component,
648    * getDisplayLanguage(Locale) is called. For the country component,
649    * getDisplayCountry(Locale) is called. For the variant set component,
650    * getDisplayVariant(Locale) is called.
651    *
652    * <p>The returned String will be one of the following forms:<br>
653    * <pre>
654    * language (country, variant)
655    * language (country)
656    * language (variant)
657    * country (variant)
658    * language
659    * country
660    * variant
661    * </pre>
662    *
663    * @param locale locale to use for formatting
664    * @return String version of this locale, suitable for display to the user
665    */
666   public String getDisplayName(Locale locale)
667   {
668     StringBuffer result = new StringBuffer();
669     int count = 0;
670     String[] delimiters = {"", " (", ","};
671     if (language.length() != 0)
672       {
673         result.append(delimiters[count++]);
674         result.append(getDisplayLanguage(locale));
675       }
676     if (country.length() != 0)
677       {
678         result.append(delimiters[count++]);
679         result.append(getDisplayCountry(locale));
680       }
681     if (variant.length() != 0)
682       {
683         result.append(delimiters[count++]);
684         result.append(getDisplayVariant(locale));
685       }
686     if (count > 1)
687       result.append(")");
688     return result.toString();
689   }
690
691   /**
692    * Does the same as <code>Object.clone()</code> but does not throw
693    * a <code>CloneNotSupportedException</code>. Why anyone would
694    * use this method is a secret to me, since this class is immutable.
695    *
696    * @return the clone
697    */
698   public Object clone()
699   {
700     // This class is final, so no need to use native super.clone().
701     return new Locale(language, country, variant);
702   }
703
704   /**
705    * Return the hash code for this locale. The hashcode is the logical
706    * xor of the hash codes of the language, the country and the variant.
707    * The hash code is precomputed, since <code>Locale</code>s are often
708    * used in hash tables.
709    *
710    * @return the hashcode
711    */
712   public int hashCode()
713   {
714     return hashcode;
715   }
716
717   /**
718    * Compares two locales. To be equal, obj must be a Locale with the same
719    * language, country, and variant code.
720    *
721    * @param obj the other locale
722    * @return true if obj is equal to this
723    */
724   public boolean equals(Object obj)
725   {
726     if (this == obj)
727       return true;
728     if (! (obj instanceof Locale))
729       return false;
730     Locale l = (Locale) obj;
731
732     return (language == l.language
733             && country == l.country
734             && variant == l.variant);
735   }
736
737   /**
738    * Write the locale to an object stream.
739    *
740    * @param output the stream to write to
741    * @throws IOException if the write fails
742    * @serialData The first three fields are Strings representing language,
743    *             country, and variant. The fourth field is a placeholder for 
744    *             the cached hashcode, but this is always written as -1, and 
745    *             recomputed when reading it back.
746    */
747   private void writeObject(ObjectOutputStream s)
748     throws IOException
749   {
750     s.writeObject(language);
751     s.writeObject(country);
752     s.writeObject(variant);
753     // Hashcode field is always written as -1.
754     s.writeInt(-1);
755   }
756
757   /**
758    * Reads a locale from the input stream.
759    *
760    * @param input the stream to read from
761    * @throws IOException if reading fails
762    * @throws ClassNotFoundException if reading fails
763    * @serialData the hashCode is always invalid and must be recomputed
764    */
765   private void readObject(ObjectInputStream s)
766     throws IOException, ClassNotFoundException
767   {
768     language = ((String) s.readObject()).intern();
769     country = ((String) s.readObject()).intern();
770     variant = ((String) s.readObject()).intern();
771     // Recompute hashcode.
772     hashcode = language.hashCode() ^ country.hashCode() ^ variant.hashCode();
773   }
774 } // class Locale