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