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 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 */ convertLanguage(String language)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 */ Locale(String language, String country, String variant)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 */ Locale(String language, String country)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 */ Locale(String language)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 */ getDefault()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 */ setDefault(Locale newLocale)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 */ getAvailableLocales()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 */ getISOCountries()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 */ getISOLanguages()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 */ getLanguage()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 */ getCountry()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 */ getVariant()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 */ toString()419 public final 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 */ getISO3Language()437 public String getISO3Language() 438 { 439 if (language == "") 440 return ""; 441 int index 442 = ("aa,ab,af,am,ar,as,ay,az,ba,be,bg,bh,bi,bn,bo,br,ca,co,cs,cy,da," 443 + "de,dz,el,en,eo,es,et,eu,fa,fi,fj,fo,fr,fy,ga,gd,gl,gn,gu,ha,iw," 444 + "hi,hr,hu,hy,ia,in,ie,ik,in,is,it,iu,iw,ja,ji,jw,ka,kk,kl,km,kn," 445 + "ko,ks,ku,ky,la,ln,lo,lt,lv,mg,mi,mk,ml,mn,mo,mr,ms,mt,my,na,ne," 446 + "nl,no,oc,om,or,pa,pl,ps,pt,qu,rm,rn,ro,ru,rw,sa,sd,sg,sh,si,sk," 447 + "sl,sm,sn,so,sq,sr,ss,st,su,sv,sw,ta,te,tg,th,ti,tk,tl,tn,to,tr," 448 + "ts,tt,tw,ug,uk,ur,uz,vi,vo,wo,xh,ji,yo,za,zh,zu") 449 .indexOf(language); 450 451 if (index % 3 != 0 || language.length() != 2) 452 throw new MissingResourceException 453 ("Can't find ISO3 language for " + language, 454 "java.util.Locale", language); 455 456 // Don't read this aloud. These are the three letter language codes. 457 return 458 ("aarabkaframharaasmaymazebakbelbulbihbisbenbodbrecatcoscescymdandeu" 459 + "dzoellengepospaesteusfasfinfijfaofrafrygaigdhglggrngujhauhebhinhrv" 460 + "hunhyeinaindileipkindislitaikuhebjpnyidjawkatkazkalkhmkankorkaskur" 461 + "kirlatlinlaolitlavmlgmrimkdmalmonmolmarmsamltmyanaunepnldnorociorm" 462 + "oripanpolpusporquerohrunronruskinsansndsagsrpsinslkslvsmosnasomsqi" 463 + "srpsswsotsunsweswatamteltgkthatirtuktgltsntonturtsotattwiuigukrurd" 464 + "uzbvievolwolxhoyidyorzhazhozul") 465 .substring(index, index + 3); 466 } 467 468 /** 469 * Returns the three-letter ISO country abbrevation of the locale. 470 * 471 * @throws MissingResourceException if the three-letter code is not known 472 */ getISO3Country()473 public String getISO3Country() 474 { 475 if (country == "") 476 return ""; 477 int index 478 = ("AD,AE,AF,AG,AI,AL,AM,AN,AO,AQ,AR,AS,AT,AU,AW,AZ,BA,BB,BD,BE,BF," 479 + "BG,BH,BI,BJ,BM,BN,BO,BR,BS,BT,BV,BW,BY,BZ,CA,CC,CF,CG,CH,CI,CK," 480 + "CL,CM,CN,CO,CR,CU,CV,CX,CY,CZ,DE,DJ,DK,DM,DO,DZ,EC,EE,EG,EH,ER," 481 + "ES,ET,FI,FJ,FK,FM,FO,FR,FX,GA,GB,GD,GE,GF,GH,GI,GL,GM,GN,GP,GQ," 482 + "GR,GS,GT,GU,GW,GY,HK,HM,HN,HR,HT,HU,ID,IE,IL,IN,IO,IQ,IR,IS,IT," 483 + "JM,JO,JP,KE,KG,KH,KI,KM,KN,KP,KR,KW,KY,KZ,LA,LB,LC,LI,LK,LR,LS," 484 + "LT,LU,LV,LY,MA,MC,MD,MG,MH,MK,ML,MM,MN,MO,MP,MQ,MR,MS,MT,MU,MV," 485 + "MW,MX,MY,MZ,NA,NC,NE,NF,NG,NI,NL,NO,NP,NR,NU,NZ,OM,PA,PE,PF,PG," 486 + "PH,PK,PL,PM,PN,PR,PT,PW,PY,QA,RE,RO,RU,RW,SA,SB,SC,SD,SE,SG,SH," 487 + "SI,SJ,SK,SL,SM,SN,SO,SR,ST,SV,SY,SZ,TC,TD,TF,TG,TH,TJ,TK,TM,TN," 488 + "TO,TP,TR,TT,TV,TW,TZ,UA,UG,UM,US,UY,UZ,VA,VC,VE,VG,VI,VN,VU,WF," 489 + "WS,YE,YT,YU,ZA,ZM,ZR,ZW") 490 .indexOf(country); 491 492 if (index % 3 != 0 || country.length() != 2) 493 throw new MissingResourceException 494 ("Can't find ISO3 country for " + country, 495 "java.util.Locale", country); 496 497 // Don't read this aloud. These are the three letter country codes. 498 return 499 ("ANDAREAFGATGAIAALBARMANTAGOATAARGASMAUTAUSABWAZEBIHBRBBGDBELBFABGR" 500 + "BHRBDIBENBMUBRNBOLBRABHSBTNBVTBWABLRBLZCANCCKCAFCOGCHECIVCOKCHLCMR" 501 + "CHNCOLCRICUBCPVCXRCYPCZEDEUDJIDNKDMADOMDZAECUESTEGYESHERIESPETHFIN" 502 + "FJIFLKFSMFROFRAFXXGABGBRGRDGEOGUFGHAGIBGRLGMBGINGLPGNQGRCSGSGTMGUM" 503 + "GNBGUYHKGHMDHNDHRVHTIHUNIDNIRLISRINDIOTIRQIRNISLITAJAMJORJPNKENKGZ" 504 + "KHMKIRCOMKNAPRKKORKWTCYMKAZLAOLBNLCALIELKALBRLSOLTULUXLVALBYMARMCO" 505 + "MDAMDGMHLMKDMLIMMRMNGMACMNPMTQMRTMSRMLTMUSMDVMWIMEXMYSMOZNAMNCLNER" 506 + "NFKNGANICNLDNORNPLNRUNIUNZLOMNPANPERPYFPNGPHLPAKPOLSPMPCNPRIPRTPLW" 507 + "PRYQATREUROMRUSRWASAUSLBSYCSDNSWESGPSHNSVNSJMSVKSLESMRSENSOMSURSTP" 508 + "SLVSYRSWZTCATCDATFTGOTHATJKTKLTKMTUNTONTMPTURTTOTUVTWNTZAUKRUGAUMI" 509 + "USAURYUZBVATVCTVENVGBVIRVNMVUTWLFWSMYEMMYTYUGZAFZMBZARZWE") 510 .substring(index, index + 3); 511 } 512 513 /** 514 * Gets the country name suitable for display to the user, formatted 515 * for the default locale. This has the same effect as 516 * <pre> 517 * getDisplayLanguage(Locale.getDefault()); 518 * </pre> 519 * 520 * @return the language name of this locale localized to the default locale, 521 * with the ISO code as backup 522 */ getDisplayLanguage()523 public final String getDisplayLanguage() 524 { 525 return getDisplayLanguage(defaultLocale); 526 } 527 528 /** 529 * Gets the language name suitable for display to the user, formatted 530 * for a specified locale. 531 * 532 * @param locale locale to use for formatting 533 * @return the language name of this locale localized to the given locale, 534 * with the ISO code as backup 535 */ getDisplayLanguage(Locale locale)536 public String getDisplayLanguage(Locale locale) 537 { 538 try 539 { 540 ResourceBundle bundle 541 = ResourceBundle.getBundle("gnu.java.locale.iso639", locale); 542 return bundle.getString(language); 543 } 544 catch (MissingResourceException ex) 545 { 546 return language; 547 } 548 } 549 550 /** 551 * Returns the country name of this locale localized to the 552 * default locale. If the localized is not found, the ISO code 553 * is returned. This has the same effect as 554 * <pre> 555 * getDisplayCountry(Locale.getDefault()); 556 * </pre> 557 * 558 * @return the country name of this locale localized to the given locale, 559 * with the ISO code as backup 560 */ getDisplayCountry()561 public final String getDisplayCountry() 562 { 563 return getDisplayCountry(defaultLocale); 564 } 565 566 /** 567 * Gets the country name suitable for display to the user, formatted 568 * for a specified locale. 569 * 570 * @param locale locale to use for formatting 571 * @return the country name of this locale localized to the given locale, 572 * with the ISO code as backup 573 */ getDisplayCountry(Locale locale)574 public String getDisplayCountry(Locale locale) 575 { 576 try 577 { 578 ResourceBundle bundle = 579 ResourceBundle.getBundle("gnu.java.locale.iso3166", locale); 580 return bundle.getString(country); 581 } 582 catch (MissingResourceException ex) 583 { 584 return country; 585 } 586 } 587 588 /** 589 * Returns the variant name of this locale localized to the 590 * default locale. If the localized is not found, the variant code 591 * itself is returned. This has the same effect as 592 * <pre> 593 * getDisplayVariant(Locale.getDefault()); 594 * </pre> 595 * 596 * @return the variant code of this locale localized to the given locale, 597 * with the ISO code as backup 598 */ getDisplayVariant()599 public final String getDisplayVariant() 600 { 601 return getDisplayVariant(defaultLocale); 602 } 603 604 /** 605 * Returns the variant name of this locale localized to the 606 * given locale. If the localized is not found, the variant code 607 * itself is returned. 608 * 609 * @param locale locale to use for formatting 610 * @return the variant code of this locale localized to the given locale, 611 * with the ISO code as backup 612 */ getDisplayVariant(Locale locale)613 public String getDisplayVariant(Locale locale) 614 { 615 // XXX - load a bundle? 616 return variant; 617 } 618 619 /** 620 * Gets all local components suitable for display to the user, formatted 621 * for the default locale. For the language component, getDisplayLanguage 622 * is called. For the country component, getDisplayCountry is called. 623 * For the variant set component, getDisplayVariant is called. 624 * 625 * <p>The returned String will be one of the following forms:<br> 626 * <pre> 627 * language (country, variant) 628 * language (country) 629 * language (variant) 630 * country (variant) 631 * language 632 * country 633 * variant 634 * </pre> 635 * 636 * @return String version of this locale, suitable for display to the user 637 */ getDisplayName()638 public final String getDisplayName() 639 { 640 return getDisplayName(defaultLocale); 641 } 642 643 /** 644 * Gets all local components suitable for display to the user, formatted 645 * for a specified locale. For the language component, 646 * getDisplayLanguage(Locale) is called. For the country component, 647 * getDisplayCountry(Locale) is called. For the variant set component, 648 * getDisplayVariant(Locale) is called. 649 * 650 * <p>The returned String will be one of the following forms:<br> 651 * <pre> 652 * language (country, variant) 653 * language (country) 654 * language (variant) 655 * country (variant) 656 * language 657 * country 658 * variant 659 * </pre> 660 * 661 * @param locale locale to use for formatting 662 * @return String version of this locale, suitable for display to the user 663 */ getDisplayName(Locale locale)664 public String getDisplayName(Locale locale) 665 { 666 StringBuffer result = new StringBuffer(); 667 int count = 0; 668 String[] delimiters = {"", " (", ","}; 669 if (language.length() != 0) 670 { 671 result.append(delimiters[count++]); 672 result.append(getDisplayLanguage(locale)); 673 } 674 if (country.length() != 0) 675 { 676 result.append(delimiters[count++]); 677 result.append(getDisplayCountry(locale)); 678 } 679 if (variant.length() != 0) 680 { 681 result.append(delimiters[count++]); 682 result.append(getDisplayVariant(locale)); 683 } 684 if (count > 1) 685 result.append(")"); 686 return result.toString(); 687 } 688 689 /** 690 * Does the same as <code>Object.clone()</code> but does not throw 691 * a <code>CloneNotSupportedException</code>. Why anyone would 692 * use this method is a secret to me, since this class is immutable. 693 * 694 * @return the clone 695 */ clone()696 public Object clone() 697 { 698 // This class is final, so no need to use native super.clone(). 699 return new Locale(language, country, variant); 700 } 701 702 /** 703 * Return the hash code for this locale. The hashcode is the logical 704 * xor of the hash codes of the language, the country and the variant. 705 * The hash code is precomputed, since <code>Locale</code>s are often 706 * used in hash tables. 707 * 708 * @return the hashcode 709 */ hashCode()710 public synchronized int hashCode() 711 { 712 // This method is synchronized because writeObject() might reset 713 // the hashcode. 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 */ equals(Object obj)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 // ??? We might also want to add: 733 // hashCode() == l.hashCode() 734 // But this is a synchronized method. Is the overhead worth it? 735 // Measure this to make a decision. 736 return (language == l.language 737 && country == l.country 738 && variant == l.variant); 739 } 740 741 /** 742 * Write the locale to an object stream. 743 * 744 * @param output the stream to write to 745 * @throws IOException if the write fails 746 * @serialData the hashcode should always be written as -1, and recomputed 747 * when reading it back 748 */ writeObject(ObjectOutputStream output)749 private synchronized void writeObject(ObjectOutputStream output) 750 throws IOException 751 { 752 // Synchronized so that hashCode() doesn't get wrong value. 753 int tmpHashcode = hashcode; 754 hashcode = -1; 755 output.defaultWriteObject(); 756 hashcode = tmpHashcode; 757 } 758 759 /** 760 * Reads a locale from the input stream. 761 * 762 * @param input the stream to read from 763 * @throws IOException if reading fails 764 * @throws ClassNotFoundException if reading fails 765 * @serialData the hashCode is always invalid and must be recomputed 766 */ readObject(ObjectInputStream input)767 private void readObject(ObjectInputStream input) 768 throws IOException, ClassNotFoundException 769 { 770 input.defaultReadObject(); 771 hashcode = language.hashCode() ^ country.hashCode() ^ variant.hashCode(); 772 } 773 } // class Locale 774