001 /* Locale.java -- i18n locales 002 Copyright (C) 1998, 1999, 2001, 2002, 2005, 2006 Free Software Foundation, Inc. 003 004 This file is part of GNU Classpath. 005 006 GNU Classpath is free software; you can redistribute it and/or modify 007 it under the terms of the GNU General Public License as published by 008 the Free Software Foundation; either version 2, or (at your option) 009 any later version. 010 011 GNU Classpath is distributed in the hope that it will be useful, but 012 WITHOUT ANY WARRANTY; without even the implied warranty of 013 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 014 General Public License for more details. 015 016 You should have received a copy of the GNU General Public License 017 along with GNU Classpath; see the file COPYING. If not, write to the 018 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 019 02110-1301 USA. 020 021 Linking this library statically or dynamically with other modules is 022 making a combined work based on this library. Thus, the terms and 023 conditions of the GNU General Public License cover the whole 024 combination. 025 026 As a special exception, the copyright holders of this library give you 027 permission to link this library with independent modules to produce an 028 executable, regardless of the license terms of these independent 029 modules, and to copy and distribute the resulting executable under 030 terms of your choice, provided that you also meet, for each linked 031 independent module, the terms and conditions of the license of that 032 module. An independent module is a module which is not derived from 033 or based on this library. If you modify this library, you may extend 034 this exception to your version of the library, but you are not 035 obligated to do so. If you do not wish to do so, delete this 036 exception statement from your version. */ 037 038 039 package java.util; 040 041 import gnu.classpath.SystemProperties; 042 043 import gnu.java.lang.CPStringBuilder; 044 045 import gnu.java.locale.LocaleHelper; 046 047 import java.io.IOException; 048 import java.io.ObjectInputStream; 049 import java.io.ObjectOutputStream; 050 import java.io.Serializable; 051 052 import java.util.spi.LocaleNameProvider; 053 054 /** 055 * Locales represent a specific country and culture. Classes which can be 056 * passed a Locale object tailor their information for a given locale. For 057 * instance, currency number formatting is handled differently for the USA 058 * and France. 059 * 060 * <p>Locales are made up of a language code, a country code, and an optional 061 * set of variant strings. Language codes are represented by 062 * <a href="http://www.ics.uci.edu/pub/ietf/http/related/iso639.txt"> 063 * ISO 639:1988</a> w/ additions from ISO 639/RA Newsletter No. 1/1989 064 * and a decision of the Advisory Committee of ISO/TC39 on August 8, 1997. 065 * 066 * <p>Country codes are represented by 067 * <a href="http://www.chemie.fu-berlin.de/diverse/doc/ISO_3166.html"> 068 * ISO 3166</a>. Variant strings are vendor and browser specific. Standard 069 * variant strings include "POSIX" for POSIX, "WIN" for MS-Windows, and 070 * "MAC" for Macintosh. When there is more than one variant string, they must 071 * be separated by an underscore (U+005F). 072 * 073 * <p>The default locale is determined by the values of the system properties 074 * user.language, user.country (or user.region), and user.variant, defaulting 075 * to "en_US". Note that the locale does NOT contain the conversion and 076 * formatting capabilities (for that, use ResourceBundle and java.text). 077 * Rather, it is an immutable tag object for identifying a given locale, which 078 * is referenced by these other classes when they must make locale-dependent 079 * decisions. 080 * 081 * @see ResourceBundle 082 * @see java.text.Format 083 * @see java.text.NumberFormat 084 * @see java.text.Collator 085 * @author Jochen Hoenicke 086 * @author Paul Fisher 087 * @author Eric Blake (ebb9@email.byu.edu) 088 * @author Andrew John Hughes (gnu_andrew@member.fsf.org) 089 * @since 1.1 090 * @status updated to 1.4 091 */ 092 public final class Locale implements Serializable, Cloneable 093 { 094 /** Locale which represents the English language. */ 095 public static final Locale ENGLISH = getLocale("en"); 096 097 /** Locale which represents the French language. */ 098 public static final Locale FRENCH = getLocale("fr"); 099 100 /** Locale which represents the German language. */ 101 public static final Locale GERMAN = getLocale("de"); 102 103 /** Locale which represents the Italian language. */ 104 public static final Locale ITALIAN = getLocale("it"); 105 106 /** Locale which represents the Japanese language. */ 107 public static final Locale JAPANESE = getLocale("ja"); 108 109 /** Locale which represents the Korean language. */ 110 public static final Locale KOREAN = getLocale("ko"); 111 112 /** Locale which represents the Chinese language. */ 113 public static final Locale CHINESE = getLocale("zh"); 114 115 /** Locale which represents the Chinese language as used in China. */ 116 public static final Locale SIMPLIFIED_CHINESE = getLocale("zh", "CN"); 117 118 /** 119 * Locale which represents the Chinese language as used in Taiwan. 120 * Same as TAIWAN Locale. 121 */ 122 public static final Locale TRADITIONAL_CHINESE = getLocale("zh", "TW"); 123 124 /** Locale which represents France. */ 125 public static final Locale FRANCE = getLocale("fr", "FR"); 126 127 /** Locale which represents Germany. */ 128 public static final Locale GERMANY = getLocale("de", "DE"); 129 130 /** Locale which represents Italy. */ 131 public static final Locale ITALY = getLocale("it", "IT"); 132 133 /** Locale which represents Japan. */ 134 public static final Locale JAPAN = getLocale("ja", "JP"); 135 136 /** Locale which represents Korea. */ 137 public static final Locale KOREA = getLocale("ko", "KR"); 138 139 /** 140 * Locale which represents China. 141 * Same as SIMPLIFIED_CHINESE Locale. 142 */ 143 public static final Locale CHINA = SIMPLIFIED_CHINESE; 144 145 /** 146 * Locale which represents the People's Republic of China. 147 * Same as CHINA Locale. 148 */ 149 public static final Locale PRC = CHINA; 150 151 /** 152 * Locale which represents Taiwan. 153 * Same as TRADITIONAL_CHINESE Locale. 154 */ 155 public static final Locale TAIWAN = TRADITIONAL_CHINESE; 156 157 /** Locale which represents the United Kingdom. */ 158 public static final Locale UK = getLocale("en", "GB"); 159 160 /** Locale which represents the United States. */ 161 public static final Locale US = getLocale("en", "US"); 162 163 /** Locale which represents the English speaking portion of Canada. */ 164 public static final Locale CANADA = getLocale("en", "CA"); 165 166 /** Locale which represents the French speaking portion of Canada. */ 167 public static final Locale CANADA_FRENCH = getLocale("fr", "CA"); 168 169 /** The root locale, used as the base case in lookups by 170 * locale-sensitive operations. 171 */ 172 public static final Locale ROOT = new Locale("","",""); 173 174 /** 175 * Compatible with JDK 1.1+. 176 */ 177 private static final long serialVersionUID = 9149081749638150636L; 178 179 /** 180 * The language code, as returned by getLanguage(). 181 * 182 * @serial the languange, possibly "" 183 */ 184 private final String language; 185 186 /** 187 * The country code, as returned by getCountry(). 188 * 189 * @serial the country, possibly "" 190 */ 191 private final String country; 192 193 /** 194 * The variant code, as returned by getVariant(). 195 * 196 * @serial the variant, possibly "" 197 */ 198 private final String variant; 199 200 /** 201 * This is the cached hashcode. When writing to stream, we write -1. 202 * 203 * @serial should be -1 in serial streams 204 */ 205 private int hashcode; 206 207 /** 208 * Array storing all available locales. 209 */ 210 private static transient Locale[] availableLocales; 211 212 /** 213 * Locale cache. Only created locale objects are stored. 214 * Contains all supported locales when getAvailableLocales() 215 * got called. 216 */ 217 private static transient HashMap localeMap; 218 219 /** 220 * The default locale. Except for during bootstrapping, this should never be 221 * null. Note the logic in the main constructor, to detect when 222 * bootstrapping has completed. 223 */ 224 private static Locale defaultLocale; 225 226 static { 227 String language = SystemProperties.getProperty("user.language", "en"); 228 String country = SystemProperties.getProperty("user.country", "US"); 229 String region = SystemProperties.getProperty("user.region", null); 230 String variant = SystemProperties.getProperty("user.variant", ""); 231 232 defaultLocale = getLocale(language, 233 (region != null) ? region : country, 234 variant); 235 } 236 237 /** 238 * Array storing all the available two-letter ISO639 languages. 239 */ 240 private static transient String[] languageCache; 241 242 /** 243 * Array storing all the available two-letter ISO3166 country codes. 244 */ 245 private static transient String[] countryCache; 246 247 /** 248 * Retrieves the locale with the specified language from the cache. 249 * 250 * @param language the language of the locale to retrieve. 251 * @return the locale. 252 */ 253 private static Locale getLocale(String language) 254 { 255 return getLocale(language, "", ""); 256 } 257 258 /** 259 * Retrieves the locale with the specified language and country 260 * from the cache. 261 * 262 * @param language the language of the locale to retrieve. 263 * @param country the country of the locale to retrieve. 264 * @return the locale. 265 */ 266 private static Locale getLocale(String language, String country) 267 { 268 return getLocale(language, country, ""); 269 } 270 271 /** 272 * Retrieves the locale with the specified language, country 273 * and variant from the cache. 274 * 275 * @param language the language of the locale to retrieve. 276 * @param country the country of the locale to retrieve. 277 * @param variant the variant of the locale to retrieve. 278 * @return the locale. 279 */ 280 private static Locale getLocale(String language, String country, String variant) 281 { 282 if (localeMap == null) 283 localeMap = new HashMap(256); 284 285 String name = language + "_" + country + "_" + variant; 286 Locale locale = (Locale) localeMap.get(name); 287 288 if (locale == null) 289 { 290 locale = new Locale(language, country, variant); 291 localeMap.put(name, locale); 292 } 293 294 return locale; 295 } 296 297 /** 298 * Convert new iso639 codes to the old ones. 299 * 300 * @param language the language to check 301 * @return the appropriate code 302 */ 303 private String convertLanguage(String language) 304 { 305 if (language.equals("")) 306 return language; 307 language = language.toLowerCase(); 308 int index = "he,id,yi".indexOf(language); 309 if (index != -1) 310 return "iw,in,ji".substring(index, index + 2); 311 return language; 312 } 313 314 /** 315 * Creates a new locale for the given language and country. 316 * 317 * @param language lowercase two-letter ISO-639 A2 language code 318 * @param country uppercase two-letter ISO-3166 A2 contry code 319 * @param variant vendor and browser specific 320 * @throws NullPointerException if any argument is null 321 */ 322 public Locale(String language, String country, String variant) 323 { 324 // During bootstrap, we already know the strings being passed in are 325 // the correct capitalization, and not null. We can't call 326 // String.toUpperCase during this time, since that depends on the 327 // default locale. 328 if (defaultLocale != null) 329 { 330 language = convertLanguage(language); 331 country = country.toUpperCase(); 332 } 333 this.language = language.intern(); 334 this.country = country.intern(); 335 this.variant = variant.intern(); 336 hashcode = language.hashCode() ^ country.hashCode() ^ variant.hashCode(); 337 } 338 339 /** 340 * Creates a new locale for the given language and country. 341 * 342 * @param language lowercase two-letter ISO-639 A2 language code 343 * @param country uppercase two-letter ISO-3166 A2 country code 344 * @throws NullPointerException if either argument is null 345 */ 346 public Locale(String language, String country) 347 { 348 this(language, country, ""); 349 } 350 351 /** 352 * Creates a new locale for a language. 353 * 354 * @param language lowercase two-letter ISO-639 A2 language code 355 * @throws NullPointerException if either argument is null 356 * @since 1.4 357 */ 358 public Locale(String language) 359 { 360 this(language, "", ""); 361 } 362 363 /** 364 * Returns the default Locale. The default locale is generally once set 365 * on start up and then never changed. Normally you should use this locale 366 * for everywhere you need a locale. The initial setting matches the 367 * default locale, the user has chosen. 368 * 369 * @return the default locale for this virtual machine 370 */ 371 public static Locale getDefault() 372 { 373 return defaultLocale; 374 } 375 376 /** 377 * Changes the default locale. Normally only called on program start up. 378 * Note that this doesn't change the locale for other programs. This has 379 * a security check, 380 * <code>PropertyPermission("user.language", "write")</code>, because of 381 * its potential impact to running code. 382 * 383 * @param newLocale the new default locale 384 * @throws NullPointerException if newLocale is null 385 * @throws SecurityException if permission is denied 386 */ 387 public static void setDefault(Locale newLocale) 388 { 389 if (newLocale == null) 390 throw new NullPointerException(); 391 SecurityManager sm = System.getSecurityManager(); 392 if (sm != null) 393 sm.checkPermission(new PropertyPermission("user.language", "write")); 394 defaultLocale = newLocale; 395 } 396 397 /** 398 * Returns the list of available locales. 399 * 400 * @return the installed locales 401 */ 402 public static synchronized Locale[] getAvailableLocales() 403 { 404 if (availableLocales == null) 405 { 406 int len = LocaleHelper.getLocaleCount(); 407 availableLocales = new Locale[len]; 408 409 for (int i = 0; i < len; i++) 410 { 411 String language; 412 String country = ""; 413 String variant = ""; 414 String name = LocaleHelper.getLocaleName(i); 415 416 language = name.substring(0, 2); 417 418 if (name.length() > 2) 419 country = name.substring(3); 420 421 int index = country.indexOf("_"); 422 if (index > 0) 423 { 424 variant = country.substring(index + 1); 425 country = country.substring(0, index - 1); 426 } 427 428 availableLocales[i] = getLocale(language, country, variant); 429 } 430 } 431 432 return (Locale[]) availableLocales.clone(); 433 } 434 435 /** 436 * Returns a list of all 2-letter uppercase country codes as defined 437 * in ISO 3166. 438 * 439 * @return a list of acceptable country codes 440 */ 441 public static String[] getISOCountries() 442 { 443 if (countryCache == null) 444 { 445 countryCache = getISOStrings("territories"); 446 } 447 448 return (String[]) countryCache.clone(); 449 } 450 451 /** 452 * Returns a list of all 2-letter lowercase language codes as defined 453 * in ISO 639 (both old and new variant). 454 * 455 * @return a list of acceptable language codes 456 */ 457 public static String[] getISOLanguages() 458 { 459 if (languageCache == null) 460 { 461 languageCache = getISOStrings("languages"); 462 } 463 return (String[]) languageCache.clone(); 464 } 465 466 /** 467 * Returns the set of keys from the specified resource hashtable, filtered 468 * so that only two letter strings are returned. 469 * 470 * @param tableName the name of the table from which to retrieve the keys. 471 * @return an array of two-letter strings. 472 */ 473 private static String[] getISOStrings(String tableName) 474 { 475 int count = 0; 476 ResourceBundle bundle = 477 ResourceBundle.getBundle("gnu.java.locale.LocaleInformation"); 478 Enumeration e = bundle.getKeys(); 479 ArrayList tempList = new ArrayList(); 480 481 while (e.hasMoreElements()) 482 { 483 String key = (String) e.nextElement(); 484 485 if (key.startsWith(tableName + ".")) 486 { 487 String str = key.substring(tableName.length() + 1); 488 489 if (str.length() == 2 490 && Character.isLetter(str.charAt(0)) 491 && Character.isLetter(str.charAt(1))) 492 { 493 tempList.add(str); 494 ++count; 495 } 496 } 497 } 498 499 String[] strings = new String[count]; 500 501 for (int a = 0; a < count; ++a) 502 strings[a] = (String) tempList.get(a); 503 504 return strings; 505 } 506 507 /** 508 * Returns the language code of this locale. Some language codes have changed 509 * as ISO 639 has evolved; this returns the old name, even if you built 510 * the locale with the new one. 511 * 512 * @return language code portion of this locale, or an empty String 513 */ 514 public String getLanguage() 515 { 516 return language; 517 } 518 519 /** 520 * Returns the country code of this locale. 521 * 522 * @return country code portion of this locale, or an empty String 523 */ 524 public String getCountry() 525 { 526 return country; 527 } 528 529 /** 530 * Returns the variant code of this locale. 531 * 532 * @return the variant code portion of this locale, or an empty String 533 */ 534 public String getVariant() 535 { 536 return variant; 537 } 538 539 /** 540 * Gets the string representation of the current locale. This consists of 541 * the language, the country, and the variant, separated by an underscore. 542 * The variant is listed only if there is a language or country. Examples: 543 * "en", "de_DE", "_GB", "en_US_WIN", "de__POSIX", "fr__MAC". 544 * 545 * @return the string representation of this Locale 546 * @see #getDisplayName() 547 */ 548 public String toString() 549 { 550 if (language.length() == 0 && country.length() == 0) 551 return ""; 552 else if (country.length() == 0 && variant.length() == 0) 553 return language; 554 CPStringBuilder result = new CPStringBuilder(language); 555 result.append('_').append(country); 556 if (variant.length() != 0) 557 result.append('_').append(variant); 558 return result.toString(); 559 } 560 561 /** 562 * Returns the three-letter ISO language abbrevation of this locale. 563 * 564 * @throws MissingResourceException if the three-letter code is not known 565 */ 566 public String getISO3Language() 567 { 568 // We know all strings are interned so we can use '==' for better performance. 569 if (language == "") 570 return ""; 571 int index 572 = ("aa,ab,af,am,ar,as,ay,az,ba,be,bg,bh,bi,bn,bo,br,ca,co,cs,cy,da," 573 + "de,dz,el,en,eo,es,et,eu,fa,fi,fj,fo,fr,fy,ga,gd,gl,gn,gu,ha,iw," 574 + "hi,hr,hu,hy,ia,in,ie,ik,in,is,it,iu,iw,ja,ji,jw,ka,kk,kl,km,kn," 575 + "ko,ks,ku,ky,la,ln,lo,lt,lv,mg,mi,mk,ml,mn,mo,mr,ms,mt,my,na,ne," 576 + "nl,no,oc,om,or,pa,pl,ps,pt,qu,rm,rn,ro,ru,rw,sa,sd,sg,sh,si,sk," 577 + "sl,sm,sn,so,sq,sr,ss,st,su,sv,sw,ta,te,tg,th,ti,tk,tl,tn,to,tr," 578 + "ts,tt,tw,ug,uk,ur,uz,vi,vo,wo,xh,ji,yo,za,zh,zu") 579 .indexOf(language); 580 581 if (index % 3 != 0 || language.length() != 2) 582 throw new MissingResourceException 583 ("Can't find ISO3 language for " + language, 584 "java.util.Locale", language); 585 586 // Don't read this aloud. These are the three letter language codes. 587 return 588 ("aarabkaframharaasmaymazebakbelbulbihbisbenbodbrecatcoscescymdandeu" 589 + "dzoellengepospaesteusfasfinfijfaofrafrygaigdhglggrngujhauhebhinhrv" 590 + "hunhyeinaindileipkindislitaikuhebjpnyidjawkatkazkalkhmkankorkaskur" 591 + "kirlatlinlaolitlavmlgmrimkdmalmonmolmarmsamltmyanaunepnldnorociorm" 592 + "oripanpolpusporquerohrunronruskinsansndsagsrpsinslkslvsmosnasomsqi" 593 + "srpsswsotsunsweswatamteltgkthatirtuktgltsntonturtsotattwiuigukrurd" 594 + "uzbvievolwolxhoyidyorzhazhozul") 595 .substring(index, index + 3); 596 } 597 598 /** 599 * Returns the three-letter ISO country abbrevation of the locale. 600 * 601 * @throws MissingResourceException if the three-letter code is not known 602 */ 603 public String getISO3Country() 604 { 605 // We know all strings are interned so we can use '==' for better performance. 606 if (country == "") 607 return ""; 608 int index 609 = ("AD,AE,AF,AG,AI,AL,AM,AN,AO,AQ,AR,AS,AT,AU,AW,AZ,BA,BB,BD,BE,BF," 610 + "BG,BH,BI,BJ,BM,BN,BO,BR,BS,BT,BV,BW,BY,BZ,CA,CC,CF,CG,CH,CI,CK," 611 + "CL,CM,CN,CO,CR,CU,CV,CX,CY,CZ,DE,DJ,DK,DM,DO,DZ,EC,EE,EG,EH,ER," 612 + "ES,ET,FI,FJ,FK,FM,FO,FR,FX,GA,GB,GD,GE,GF,GH,GI,GL,GM,GN,GP,GQ," 613 + "GR,GS,GT,GU,GW,GY,HK,HM,HN,HR,HT,HU,ID,IE,IL,IN,IO,IQ,IR,IS,IT," 614 + "JM,JO,JP,KE,KG,KH,KI,KM,KN,KP,KR,KW,KY,KZ,LA,LB,LC,LI,LK,LR,LS," 615 + "LT,LU,LV,LY,MA,MC,MD,MG,MH,MK,ML,MM,MN,MO,MP,MQ,MR,MS,MT,MU,MV," 616 + "MW,MX,MY,MZ,NA,NC,NE,NF,NG,NI,NL,NO,NP,NR,NU,NZ,OM,PA,PE,PF,PG," 617 + "PH,PK,PL,PM,PN,PR,PT,PW,PY,QA,RE,RO,RU,RW,SA,SB,SC,SD,SE,SG,SH," 618 + "SI,SJ,SK,SL,SM,SN,SO,SR,ST,SV,SY,SZ,TC,TD,TF,TG,TH,TJ,TK,TM,TN," 619 + "TO,TP,TR,TT,TV,TW,TZ,UA,UG,UM,US,UY,UZ,VA,VC,VE,VG,VI,VN,VU,WF," 620 + "WS,YE,YT,YU,ZA,ZM,ZR,ZW") 621 .indexOf(country); 622 623 if (index % 3 != 0 || country.length() != 2) 624 throw new MissingResourceException 625 ("Can't find ISO3 country for " + country, 626 "java.util.Locale", country); 627 628 // Don't read this aloud. These are the three letter country codes. 629 return 630 ("ANDAREAFGATGAIAALBARMANTAGOATAARGASMAUTAUSABWAZEBIHBRBBGDBELBFABGR" 631 + "BHRBDIBENBMUBRNBOLBRABHSBTNBVTBWABLRBLZCANCCKCAFCOGCHECIVCOKCHLCMR" 632 + "CHNCOLCRICUBCPVCXRCYPCZEDEUDJIDNKDMADOMDZAECUESTEGYESHERIESPETHFIN" 633 + "FJIFLKFSMFROFRAFXXGABGBRGRDGEOGUFGHAGIBGRLGMBGINGLPGNQGRCSGSGTMGUM" 634 + "GNBGUYHKGHMDHNDHRVHTIHUNIDNIRLISRINDIOTIRQIRNISLITAJAMJORJPNKENKGZ" 635 + "KHMKIRCOMKNAPRKKORKWTCYMKAZLAOLBNLCALIELKALBRLSOLTULUXLVALBYMARMCO" 636 + "MDAMDGMHLMKDMLIMMRMNGMACMNPMTQMRTMSRMLTMUSMDVMWIMEXMYSMOZNAMNCLNER" 637 + "NFKNGANICNLDNORNPLNRUNIUNZLOMNPANPERPYFPNGPHLPAKPOLSPMPCNPRIPRTPLW" 638 + "PRYQATREUROMRUSRWASAUSLBSYCSDNSWESGPSHNSVNSJMSVKSLESMRSENSOMSURSTP" 639 + "SLVSYRSWZTCATCDATFTGOTHATJKTKLTKMTUNTONTMPTURTTOTUVTWNTZAUKRUGAUMI" 640 + "USAURYUZBVATVCTVENVGBVIRVNMVUTWLFWSMYEMMYTYUGZAFZMBZARZWE") 641 .substring(index, index + 3); 642 } 643 644 /** 645 * Gets the country name suitable for display to the user, formatted 646 * for the default locale. This has the same effect as 647 * <pre> 648 * getDisplayLanguage(Locale.getDefault()); 649 * </pre> 650 * 651 * @return the language name of this locale localized to the default locale, 652 * with the ISO code as backup 653 */ 654 public String getDisplayLanguage() 655 { 656 return getDisplayLanguage(defaultLocale); 657 } 658 659 /** 660 * <p> 661 * Gets the name of the language specified by this locale, in a form suitable 662 * for display to the user. If possible, the display name will be localized 663 * to the specified locale. For example, if the locale instance is 664 * <code>Locale.GERMANY</code>, and the specified locale is <code>Locale.UK</code>, 665 * the result would be 'German'. Using the German locale would instead give 666 * 'Deutsch'. If the display name can not be localized to the supplied 667 * locale, it will fall back on other output in the following order: 668 * </p> 669 * <ul> 670 * <li>the display name in the default locale</li> 671 * <li>the display name in English</li> 672 * <li>the ISO code</li> 673 * </ul> 674 * <p> 675 * If the language is unspecified by this locale, then the empty string is 676 * returned. 677 * </p> 678 * 679 * @param inLocale the locale to use for formatting the display string. 680 * @return the language name of this locale localized to the given locale, 681 * with the default locale, English and the ISO code as backups. 682 * @throws NullPointerException if the supplied locale is null. 683 */ 684 public String getDisplayLanguage(Locale inLocale) 685 { 686 if (language.isEmpty()) 687 return ""; 688 try 689 { 690 ResourceBundle res = 691 ResourceBundle.getBundle("gnu.java.locale.LocaleInformation", 692 inLocale, 693 ClassLoader.getSystemClassLoader()); 694 695 return res.getString("languages." + language); 696 } 697 catch (MissingResourceException e) 698 { 699 /* This means runtime support for the locale 700 * is not available, so we check providers. */ 701 } 702 for (LocaleNameProvider p : 703 ServiceLoader.load(LocaleNameProvider.class)) 704 { 705 for (Locale loc : p.getAvailableLocales()) 706 { 707 if (loc.equals(inLocale)) 708 { 709 String locLang = p.getDisplayLanguage(language, 710 inLocale); 711 if (locLang != null) 712 return locLang; 713 break; 714 } 715 } 716 } 717 if (inLocale.equals(Locale.ROOT)) // Base case 718 return language; 719 return getDisplayLanguage(LocaleHelper.getFallbackLocale(inLocale)); 720 } 721 722 /** 723 * Returns the country name of this locale localized to the 724 * default locale. If the localized is not found, the ISO code 725 * is returned. This has the same effect as 726 * <pre> 727 * getDisplayCountry(Locale.getDefault()); 728 * </pre> 729 * 730 * @return the country name of this locale localized to the given locale, 731 * with the ISO code as backup 732 */ 733 public String getDisplayCountry() 734 { 735 return getDisplayCountry(defaultLocale); 736 } 737 738 /** 739 * <p> 740 * Gets the name of the country specified by this locale, in a form suitable 741 * for display to the user. If possible, the display name will be localized 742 * to the specified locale. For example, if the locale instance is 743 * <code>Locale.GERMANY</code>, and the specified locale is <code>Locale.UK</code>, 744 * the result would be 'Germany'. Using the German locale would instead give 745 * 'Deutschland'. If the display name can not be localized to the supplied 746 * locale, it will fall back on other output in the following order: 747 * </p> 748 * <ul> 749 * <li>the display name in the default locale</li> 750 * <li>the display name in English</li> 751 * <li>the ISO code</li> 752 * </ul> 753 * <p> 754 * If the country is unspecified by this locale, then the empty string is 755 * returned. 756 * </p> 757 * 758 * @param inLocale the locale to use for formatting the display string. 759 * @return the country name of this locale localized to the given locale, 760 * with the default locale, English and the ISO code as backups. 761 * @throws NullPointerException if the supplied locale is null. 762 */ 763 public String getDisplayCountry(Locale inLocale) 764 { 765 if (country.isEmpty()) 766 return ""; 767 try 768 { 769 ResourceBundle res = 770 ResourceBundle.getBundle("gnu.java.locale.LocaleInformation", 771 inLocale, 772 ClassLoader.getSystemClassLoader()); 773 774 return res.getString("territories." + country); 775 } 776 catch (MissingResourceException e) 777 { 778 /* This means runtime support for the locale 779 * is not available, so we check providers. */ 780 } 781 for (LocaleNameProvider p : 782 ServiceLoader.load(LocaleNameProvider.class)) 783 { 784 for (Locale loc : p.getAvailableLocales()) 785 { 786 if (loc.equals(inLocale)) 787 { 788 String locCountry = p.getDisplayCountry(country, 789 inLocale); 790 if (locCountry != null) 791 return locCountry; 792 break; 793 } 794 } 795 } 796 if (inLocale.equals(Locale.ROOT)) // Base case 797 return country; 798 return getDisplayCountry(LocaleHelper.getFallbackLocale(inLocale)); 799 } 800 801 /** 802 * Returns the variant name of this locale localized to the 803 * default locale. If the localized is not found, the variant code 804 * itself is returned. This has the same effect as 805 * <pre> 806 * getDisplayVariant(Locale.getDefault()); 807 * </pre> 808 * 809 * @return the variant code of this locale localized to the given locale, 810 * with the ISO code as backup 811 */ 812 public String getDisplayVariant() 813 { 814 return getDisplayVariant(defaultLocale); 815 } 816 817 818 /** 819 * <p> 820 * Gets the name of the variant specified by this locale, in a form suitable 821 * for display to the user. If possible, the display name will be localized 822 * to the specified locale. For example, if the locale instance is a revised 823 * variant, and the specified locale is <code>Locale.UK</code>, the result 824 * would be 'REVISED'. Using the German locale would instead give 825 * 'Revidiert'. If the display name can not be localized to the supplied 826 * locale, it will fall back on other output in the following order: 827 * </p> 828 * <ul> 829 * <li>the display name in the default locale</li> 830 * <li>the display name in English</li> 831 * <li>the ISO code</li> 832 * </ul> 833 * <p> 834 * If the variant is unspecified by this locale, then the empty string is 835 * returned. 836 * </p> 837 * 838 * @param inLocale the locale to use for formatting the display string. 839 * @return the variant name of this locale localized to the given locale, 840 * with the default locale, English and the ISO code as backups. 841 * @throws NullPointerException if the supplied locale is null. 842 */ 843 public String getDisplayVariant(Locale inLocale) 844 { 845 if (variant.isEmpty()) 846 return ""; 847 try 848 { 849 ResourceBundle res = 850 ResourceBundle.getBundle("gnu.java.locale.LocaleInformation", 851 inLocale, 852 ClassLoader.getSystemClassLoader()); 853 854 return res.getString("variants." + variant); 855 } 856 catch (MissingResourceException e) 857 { 858 /* This means runtime support for the locale 859 * is not available, so we check providers. */ 860 } 861 for (LocaleNameProvider p : 862 ServiceLoader.load(LocaleNameProvider.class)) 863 { 864 for (Locale loc : p.getAvailableLocales()) 865 { 866 if (loc.equals(inLocale)) 867 { 868 String locVar = p.getDisplayVariant(variant, 869 inLocale); 870 if (locVar != null) 871 return locVar; 872 break; 873 } 874 } 875 } 876 if (inLocale.equals(Locale.ROOT)) // Base case 877 return country; 878 return getDisplayVariant(LocaleHelper.getFallbackLocale(inLocale)); 879 } 880 881 /** 882 * Gets all local components suitable for display to the user, formatted 883 * for the default locale. For the language component, getDisplayLanguage 884 * is called. For the country component, getDisplayCountry is called. 885 * For the variant set component, getDisplayVariant is called. 886 * 887 * <p>The returned String will be one of the following forms:<br> 888 * <pre> 889 * language (country, variant) 890 * language (country) 891 * language (variant) 892 * country (variant) 893 * language 894 * country 895 * variant 896 * </pre> 897 * 898 * @return String version of this locale, suitable for display to the user 899 */ 900 public String getDisplayName() 901 { 902 return getDisplayName(defaultLocale); 903 } 904 905 /** 906 * Gets all local components suitable for display to the user, formatted 907 * for a specified locale. For the language component, 908 * getDisplayLanguage(Locale) is called. For the country component, 909 * getDisplayCountry(Locale) is called. For the variant set component, 910 * getDisplayVariant(Locale) is called. 911 * 912 * <p>The returned String will be one of the following forms:<br> 913 * <pre> 914 * language (country, variant) 915 * language (country) 916 * language (variant) 917 * country (variant) 918 * language 919 * country 920 * variant 921 * </pre> 922 * 923 * @param locale locale to use for formatting 924 * @return String version of this locale, suitable for display to the user 925 */ 926 public String getDisplayName(Locale locale) 927 { 928 CPStringBuilder result = new CPStringBuilder(); 929 int count = 0; 930 String[] delimiters = {"", " (", ","}; 931 if (language.length() != 0) 932 { 933 result.append(delimiters[count++]); 934 result.append(getDisplayLanguage(locale)); 935 } 936 if (country.length() != 0) 937 { 938 result.append(delimiters[count++]); 939 result.append(getDisplayCountry(locale)); 940 } 941 if (variant.length() != 0) 942 { 943 result.append(delimiters[count++]); 944 result.append(getDisplayVariant(locale)); 945 } 946 if (count > 1) 947 result.append(")"); 948 return result.toString(); 949 } 950 951 /** 952 * Does the same as <code>Object.clone()</code> but does not throw 953 * a <code>CloneNotSupportedException</code>. Why anyone would 954 * use this method is a secret to me, since this class is immutable. 955 * 956 * @return the clone 957 */ 958 public Object clone() 959 { 960 // This class is final, so no need to use native super.clone(). 961 return new Locale(language, country, variant); 962 } 963 964 /** 965 * Return the hash code for this locale. The hashcode is the logical 966 * xor of the hash codes of the language, the country and the variant. 967 * The hash code is precomputed, since <code>Locale</code>s are often 968 * used in hash tables. 969 * 970 * @return the hashcode 971 */ 972 public int hashCode() 973 { 974 return hashcode; 975 } 976 977 /** 978 * Compares two locales. To be equal, obj must be a Locale with the same 979 * language, country, and variant code. 980 * 981 * @param obj the other locale 982 * @return true if obj is equal to this 983 */ 984 public boolean equals(Object obj) 985 { 986 if (this == obj) 987 return true; 988 if (! (obj instanceof Locale)) 989 return false; 990 Locale l = (Locale) obj; 991 992 return (language == l.language 993 && country == l.country 994 && variant == l.variant); 995 } 996 997 /** 998 * Write the locale to an object stream. 999 * 1000 * @param s the stream to write to 1001 * @throws IOException if the write fails 1002 * @serialData The first three fields are Strings representing language, 1003 * country, and variant. The fourth field is a placeholder for 1004 * the cached hashcode, but this is always written as -1, and 1005 * recomputed when reading it back. 1006 */ 1007 private void writeObject(ObjectOutputStream s) 1008 throws IOException 1009 { 1010 ObjectOutputStream.PutField fields = s.putFields(); 1011 fields.put("hashcode", -1); 1012 s.defaultWriteObject(); 1013 } 1014 1015 /** 1016 * Reads a locale from the input stream. 1017 * 1018 * @param s the stream to read from 1019 * @throws IOException if reading fails 1020 * @throws ClassNotFoundException if reading fails 1021 * @serialData the hashCode is always invalid and must be recomputed 1022 */ 1023 private void readObject(ObjectInputStream s) 1024 throws IOException, ClassNotFoundException 1025 { 1026 s.defaultReadObject(); 1027 hashcode = language.hashCode() ^ country.hashCode() ^ variant.hashCode(); 1028 } 1029 } // class Locale