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