1 /* 2 * Licensed to the Apache Software Foundation (ASF) under one or more 3 * contributor license agreements. See the NOTICE file distributed with 4 * this work for additional information regarding copyright ownership. 5 * The ASF licenses this file to You under the Apache License, Version 2.0 6 * (the "License"); you may not use this file except in compliance with 7 * the License. You may obtain a copy of the License at 8 * 9 * http://www.apache.org/licenses/LICENSE-2.0 10 * 11 * Unless required by applicable law or agreed to in writing, software 12 * distributed under the License is distributed on an "AS IS" BASIS, 13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 * See the License for the specific language governing permissions and 15 * limitations under the License. 16 */ 17 18 package java.util; 19 20 import com.ibm.icu4jni.util.ICU; 21 import java.io.IOException; 22 import java.io.ObjectInputStream; 23 import java.io.ObjectOutputStream; 24 import java.io.ObjectStreamField; 25 import java.io.Serializable; 26 import java.security.AccessController; 27 import org.apache.harmony.luni.util.PriviAction; 28 import org.apache.harmony.luni.util.Util; 29 30 /** 31 * {@code Locale} represents a language/country/variant combination. Locales are used to 32 * alter the presentation of information such as numbers or dates to suit the conventions 33 * in the region they describe. 34 * 35 * <p>The language codes are two-letter lowercase ISO language codes (such as "en") as defined by 36 * <a href="http://en.wikipedia.org/wiki/ISO_639-1">ISO 639-1</a>. 37 * The country codes are two-letter uppercase ISO country codes (such as "US") as defined by 38 * <a href="http://en.wikipedia.org/wiki/ISO_3166-1_alpha-3">ISO 3166-1</a>. 39 * The variant codes are unspecified. 40 * 41 * <p>Note that Java uses several deprecated two-letter codes. The Hebrew ("he") language 42 * code is rewritten as "iw", Indonesian ("id") as "in", and Yiddish ("yi") as "ji". This 43 * rewriting happens even if you construct your own {@code Locale} object, not just for 44 * instances returned by the various lookup methods. 45 * 46 * <a name="available_locales"><h3>Available locales</h3></a> 47 * <p>This class' constructors do no error checking. You can create a {@code Locale} for languages 48 * and countries that don't exist, and you can create instances for combinations that don't 49 * exist (such as "de_US" for "German as spoken in the US"). 50 * 51 * <p>Note that locale data is not necessarily available for any of the locales pre-defined as 52 * constants in this class except for en_US, which is the only locale Java guarantees is always 53 * available. 54 * 55 * <p>It is also a mistake to assume that all devices have the same locales available. 56 * A device sold in the US will almost certainly support en_US and es_US, but not necessarily 57 * any locales with the same language but different countries (such as en_GB or es_ES), 58 * nor any locales for other languages (such as de_DE). The opposite may well be true for a device 59 * sold in Europe. 60 * 61 * <p>You can use {@code getDefault} to get an appropriate locale for the <i>user</i> of 62 * the device you're running on, or {@code getAvailableLocales} to get a list of all the locales 63 * available on the device you're running on. 64 * 65 * <a name="locale_data"><h3>Locale data</h3></a> 66 * <p>Note that locale data comes solely from ICU. User-supplied locale service providers (using 67 * the {@code java.text.spi} or {@code java.util.spi} mechanisms) are not supported. 68 * 69 * <p>Here are the versions of ICU (and the corresponding CLDR and Unicode versions) used in 70 * various Android releases: 71 * <table BORDER="1" WIDTH="100%" CELLPADDING="3" CELLSPACING="0" SUMMARY=""> 72 * <tr><td>cupcake/donut/eclair</td> <td>ICU 3.8</td> <td><a href="http://www.unicode.org/press/pr-cldr1.5.html">CLDR 1.5</a></td> <td><a href="http://www.unicode.org/versions/Unicode5.0.0/">Unicode 5.0</a></td></tr> 73 * <tr><td>froyo</td> <td>ICU 4.2</td> <td><a href="http://www.unicode.org/press/pr-cldr1.7.html">CLDR 1.7</a></td> <td><a href="http://www.unicode.org/versions/Unicode5.1.0/">Unicode 5.1</a></td></tr> 74 * <tr><td>gingerbread</td> <td>ICU 4.4</td> <td><a href="http://www.unicode.org/press/pr-cldr1.8.html">CLDR 1.8</a></td> <td><a href="http://www.unicode.org/versions/Unicode5.2.0/">Unicode 5.2</a></td></tr> 75 * </table> 76 * 77 * <a name="default_locale"><h3>Be wary of the default locale</h3></a> 78 * <p>Note that there are many convenience methods that automatically use the default locale, but 79 * these may not be as convenient as you imagine. The default locale is appropriate for anything 80 * that involves presenting data to the user. You should use the user's date/time formats, number 81 * formats, rules for conversion to lowercase, and so on. A common mistake is to implicitly use the 82 * default locale when producing output meant to be machine-readable. This tends to work on the 83 * developer's test devices but fail when run on a device whose user is in a less conventional 84 * locale. For example, if you're formatting integers some locales will use non-ASCII decimal 85 * digits. As another example, if you're formatting floating-point numbers some locales will use 86 * {@code ','} as the decimal point. That's correct for human-readable output, but likely to cause 87 * problems if presented to another computer ({@code Double.parseDouble} can't parse such a number, 88 * for example). The best choice for computer-readable output is usually {@code Locale.US}: this 89 * locale is guaranteed to be available on all devices, and the combination of no surprising 90 * behavior and frequent use (especially for computer-computer communication) means that it tends 91 * to be the most efficient choice too. 92 */ 93 public final class Locale implements Cloneable, Serializable { 94 95 private static final long serialVersionUID = 9149081749638150636L; 96 97 // Initialize a default which is used during static 98 // initialization of the default for the platform. 99 private static Locale defaultLocale = new Locale(); 100 101 /** 102 * Locale constant for en_CA. 103 */ 104 public static final Locale CANADA = new Locale("en", "CA"); 105 106 /** 107 * Locale constant for fr_CA. 108 */ 109 public static final Locale CANADA_FRENCH = new Locale("fr", "CA"); 110 111 /** 112 * Locale constant for zh_CN. 113 */ 114 public static final Locale CHINA = new Locale("zh", "CN"); 115 116 /** 117 * Locale constant for zh. 118 */ 119 public static final Locale CHINESE = new Locale("zh", ""); 120 121 /** 122 * Locale constant for en. 123 */ 124 public static final Locale ENGLISH = new Locale("en", ""); 125 126 /** 127 * Locale constant for fr_FR. 128 */ 129 public static final Locale FRANCE = new Locale("fr", "FR"); 130 131 /** 132 * Locale constant for fr. 133 */ 134 public static final Locale FRENCH = new Locale("fr", ""); 135 136 /** 137 * Locale constant for de. 138 */ 139 public static final Locale GERMAN = new Locale("de", ""); 140 141 /** 142 * Locale constant for de_DE. 143 */ 144 public static final Locale GERMANY = new Locale("de", "DE"); 145 146 /** 147 * Locale constant for it. 148 */ 149 public static final Locale ITALIAN = new Locale("it", ""); 150 151 /** 152 * Locale constant for it_IT. 153 */ 154 public static final Locale ITALY = new Locale("it", "IT"); 155 156 /** 157 * Locale constant for ja_JP. 158 */ 159 public static final Locale JAPAN = new Locale("ja", "JP"); 160 161 /** 162 * Locale constant for ja. 163 */ 164 public static final Locale JAPANESE = new Locale("ja", ""); 165 166 /** 167 * Locale constant for ko_KR. 168 */ 169 public static final Locale KOREA = new Locale("ko", "KR"); 170 171 /** 172 * Locale constant for ko. 173 */ 174 public static final Locale KOREAN = new Locale("ko", ""); 175 176 /** 177 * Locale constant for zh_CN. 178 */ 179 public static final Locale PRC = new Locale("zh", "CN"); 180 181 /** 182 * Locale constant for the root locale. The root locale has an empty language, 183 * country, and variant. 184 * 185 * @since 1.6 186 */ 187 public static final Locale ROOT = new Locale("", "", ""); 188 189 /** 190 * Locale constant for zh_CN. 191 */ 192 public static final Locale SIMPLIFIED_CHINESE = new Locale("zh", "CN"); 193 194 /** 195 * Locale constant for zh_TW. 196 */ 197 public static final Locale TAIWAN = new Locale("zh", "TW"); 198 199 /** 200 * Locale constant for zh_TW. 201 */ 202 public static final Locale TRADITIONAL_CHINESE = new Locale("zh", "TW"); 203 204 /** 205 * Locale constant for en_GB. 206 */ 207 public static final Locale UK = new Locale("en", "GB"); 208 209 /** 210 * Locale constant for en_US. 211 */ 212 public static final Locale US = new Locale("en", "US"); 213 214 private static final PropertyPermission setLocalePermission = new PropertyPermission( 215 "user.language", "write"); 216 217 static { 218 String language = AccessController.doPrivileged(new PriviAction<String>("user.language", "en")); 219 String region = AccessController.doPrivileged(new PriviAction<String>("user.region", "US")); 220 String variant = AccessController.doPrivileged(new PriviAction<String>("user.variant", "")); 221 defaultLocale = new Locale(language, region, variant); 222 } 223 224 private transient String countryCode; 225 private transient String languageCode; 226 private transient String variantCode; 227 private transient String cachedToStringResult; 228 229 /** 230 * Constructs a default which is used during static initialization of the 231 * default for the platform. 232 */ 233 private Locale() { 234 languageCode = "en"; 235 countryCode = "US"; 236 variantCode = ""; 237 } 238 239 /** 240 * Constructs a new {@code Locale} using the specified language. 241 */ 242 public Locale(String language) { 243 this(language, "", ""); 244 } 245 246 /** 247 * Constructs a new {@code Locale} using the specified language and country codes. 248 */ 249 public Locale(String language, String country) { 250 this(language, country, ""); 251 } 252 253 /** 254 * Constructs a new {@code Locale} using the specified language, country, 255 * and variant codes. 256 */ 257 public Locale(String language, String country, String variant) { 258 if (language == null || country == null || variant == null) { 259 throw new NullPointerException(); 260 } 261 if(language.isEmpty() && country.isEmpty()){ 262 languageCode = ""; 263 countryCode = ""; 264 variantCode = variant; 265 return; 266 } 267 // BEGIN android-changed 268 // this.uLocale = new ULocale(language, country, variant); 269 // languageCode = uLocale.getLanguage(); 270 languageCode = Util.toASCIILowerCase(language); 271 // END android-changed 272 // Map new language codes to the obsolete language 273 // codes so the correct resource bundles will be used. 274 if (languageCode.equals("he")) { 275 languageCode = "iw"; 276 } else if (languageCode.equals("id")) { 277 languageCode = "in"; 278 } else if (languageCode.equals("yi")) { 279 languageCode = "ji"; 280 } 281 282 // countryCode is defined in ASCII character set 283 // BEGIN android-changed 284 // countryCode = country.length()!=0?uLocale.getCountry():""; 285 countryCode = Util.toASCIIUpperCase(country); 286 // END android-changed 287 288 // Work around for be compatible with RI 289 variantCode = variant; 290 } 291 292 @Override public Object clone() { 293 try { 294 return super.clone(); 295 } catch (CloneNotSupportedException e) { 296 throw new AssertionError(e); 297 } 298 } 299 300 /** 301 * Returns true if {@code object} is a locale with the same language, 302 * country and variant. 303 */ 304 @Override public boolean equals(Object object) { 305 if (object == this) { 306 return true; 307 } 308 if (object instanceof Locale) { 309 Locale o = (Locale) object; 310 return languageCode.equals(o.languageCode) 311 && countryCode.equals(o.countryCode) 312 && variantCode.equals(o.variantCode); 313 } 314 return false; 315 } 316 317 /** 318 * Returns the system's installed locales. This array always includes {@code 319 * Locale.US}, and usually several others. Most locale-sensitive classes 320 * offer their own {@code getAvailableLocales} method, which should be 321 * preferred over this general purpose method. 322 * 323 * @see java.text.BreakIterator#getAvailableLocales() 324 * @see java.text.Collator#getAvailableLocales() 325 * @see java.text.DateFormat#getAvailableLocales() 326 * @see java.text.DateFormatSymbols#getAvailableLocales() 327 * @see java.text.DecimalFormatSymbols#getAvailableLocales() 328 * @see java.text.NumberFormat#getAvailableLocales() 329 * @see java.util.Calendar#getAvailableLocales() 330 */ 331 public static Locale[] getAvailableLocales() { 332 return ICU.getAvailableLocales(); 333 } 334 335 /** 336 * Returns the country code for this locale, or {@code ""} if this locale 337 * doesn't correspond to a specific country. 338 */ 339 public String getCountry() { 340 return countryCode; 341 } 342 343 /** 344 * Returns the user's preferred locale. This may have been overridden for 345 * this process with {@link #setDefault}. 346 * 347 * <p>Since the user's locale changes dynamically, avoid caching this value. 348 * Instead, use this method to look it up for each use. 349 */ 350 public static Locale getDefault() { 351 return defaultLocale; 352 } 353 354 /** 355 * Equivalent to {@code getDisplayCountry(Locale.getDefault())}. 356 */ 357 public final String getDisplayCountry() { 358 return getDisplayCountry(getDefault()); 359 } 360 361 /** 362 * Returns the name of this locale's country, localized to {@code locale}. 363 * Returns the empty string if this locale does not correspond to a specific 364 * country. 365 */ 366 public String getDisplayCountry(Locale locale) { 367 if (countryCode.isEmpty()) { 368 return ""; 369 } 370 String result = ICU.getDisplayCountryNative(toString(), locale.toString()); 371 if (result == null) { // TODO: do we need to do this, or does ICU do it for us? 372 result = ICU.getDisplayCountryNative(toString(), Locale.getDefault().toString()); 373 } 374 return result; 375 } 376 377 /** 378 * Equivalent to {@code getDisplayLanguage(Locale.getDefault())}. 379 */ 380 public final String getDisplayLanguage() { 381 return getDisplayLanguage(getDefault()); 382 } 383 384 /** 385 * Returns the name of this locale's language, localized to {@code locale}. 386 * If the language name is unknown, the language code is returned. 387 */ 388 public String getDisplayLanguage(Locale locale) { 389 if (languageCode.isEmpty()) { 390 return ""; 391 } 392 String result = ICU.getDisplayLanguageNative(toString(), locale.toString()); 393 if (result == null) { // TODO: do we need to do this, or does ICU do it for us? 394 result = ICU.getDisplayLanguageNative(toString(), Locale.getDefault().toString()); 395 } 396 return result; 397 } 398 399 /** 400 * Equivalent to {@code getDisplayName(Locale.getDefault())}. 401 */ 402 public final String getDisplayName() { 403 return getDisplayName(getDefault()); 404 } 405 406 /** 407 * Returns this locale's language name, country name, and variant, localized 408 * to {@code locale}. The exact output form depends on whether this locale 409 * corresponds to a specific language, country and variant, such as: 410 * {@code English}, {@code English (United States)}, {@code English (United 411 * States,Computer)}, {@code anglais (États-Unis)}, {@code anglais 412 * (États-Unis,informatique)}. 413 */ 414 public String getDisplayName(Locale locale) { 415 int count = 0; 416 StringBuilder buffer = new StringBuilder(); 417 if (!languageCode.isEmpty()) { 418 String displayLanguage = getDisplayLanguage(locale); 419 buffer.append(displayLanguage.isEmpty() ? languageCode : displayLanguage); 420 ++count; 421 } 422 if (!countryCode.isEmpty()) { 423 if (count == 1) { 424 buffer.append(" ("); 425 } 426 String displayCountry = getDisplayCountry(locale); 427 buffer.append(displayCountry.isEmpty() ? countryCode : displayCountry); 428 ++count; 429 } 430 if (!variantCode.isEmpty()) { 431 if (count == 1) { 432 buffer.append(" ("); 433 } else if (count == 2) { 434 buffer.append(","); 435 } 436 String displayVariant = getDisplayVariant(locale); 437 buffer.append(displayVariant.isEmpty() ? variantCode : displayVariant); 438 ++count; 439 } 440 if (count > 1) { 441 buffer.append(")"); 442 } 443 return buffer.toString(); 444 } 445 446 /** 447 * Gets the full variant name in the default {@code Locale} for the variant code of 448 * this {@code Locale}. If there is no matching variant name, the variant code is 449 * returned. 450 * 451 * @return a variant name. 452 */ 453 public final String getDisplayVariant() { 454 return getDisplayVariant(getDefault()); 455 } 456 457 /** 458 * Gets the full variant name in the specified {@code Locale} for the variant code 459 * of this {@code Locale}. If there is no matching variant name, the variant code is 460 * returned. 461 * 462 * @param locale 463 * the {@code Locale} for which the display name is retrieved. 464 * @return a variant name. 465 */ 466 public String getDisplayVariant(Locale locale) { 467 if (variantCode.length() == 0) { 468 return variantCode; 469 } 470 String result = ICU.getDisplayVariantNative(toString(), locale.toString()); 471 if (result == null) { // TODO: do we need to do this, or does ICU do it for us? 472 result = ICU.getDisplayVariantNative(toString(), Locale.getDefault().toString()); 473 } 474 return result; 475 } 476 477 /** 478 * Gets the three letter ISO country code which corresponds to the country 479 * code for this {@code Locale}. 480 * 481 * @return a three letter ISO language code. 482 * @throws MissingResourceException 483 * if there is no matching three letter ISO country code. 484 */ 485 public String getISO3Country() throws MissingResourceException { 486 if (countryCode.length() == 0) { 487 return countryCode; 488 } 489 return ICU.getISO3CountryNative(toString()); 490 } 491 492 /** 493 * Gets the three letter ISO language code which corresponds to the language 494 * code for this {@code Locale}. 495 * 496 * @return a three letter ISO language code. 497 * @throws MissingResourceException 498 * if there is no matching three letter ISO language code. 499 */ 500 public String getISO3Language() throws MissingResourceException { 501 if (languageCode.length() == 0) { 502 return languageCode; 503 } 504 return ICU.getISO3LanguageNative(toString()); 505 } 506 507 /** 508 * Gets the list of two letter ISO country codes which can be used as the 509 * country code for a {@code Locale}. 510 * 511 * @return an array of strings. 512 */ 513 public static String[] getISOCountries() { 514 return ICU.getISOCountries(); 515 } 516 517 /** 518 * Gets the list of two letter ISO language codes which can be used as the 519 * language code for a {@code Locale}. 520 * 521 * @return an array of strings. 522 */ 523 public static String[] getISOLanguages() { 524 return ICU.getISOLanguages(); 525 } 526 527 /** 528 * Gets the language code for this {@code Locale} or the empty string of no language 529 * was set. 530 * 531 * @return a language code. 532 */ 533 public String getLanguage() { 534 return languageCode; 535 } 536 537 /** 538 * Gets the variant code for this {@code Locale} or an empty {@code String} if no variant 539 * was set. 540 * 541 * @return a variant code. 542 */ 543 public String getVariant() { 544 return variantCode; 545 } 546 547 /** 548 * Returns an integer hash code for the receiver. Objects which are equal 549 * return the same value for this method. 550 * 551 * @return the receiver's hash. 552 * @see #equals 553 */ 554 @Override 555 public synchronized int hashCode() { 556 return countryCode.hashCode() + languageCode.hashCode() 557 + variantCode.hashCode(); 558 } 559 560 /** 561 * Overrides the default locale. This does not affect system configuration, 562 * and attempts to override the system-provided default locale may 563 * themselves be overridden by actual changes to the system configuration. 564 * Code that calls this method is usually incorrect, and should be fixed by 565 * passing the appropriate locale to each locale-sensitive method that's 566 * called. 567 */ 568 public synchronized static void setDefault(Locale locale) { 569 if (locale == null) { 570 throw new NullPointerException(); 571 } 572 573 SecurityManager security = System.getSecurityManager(); 574 if (security != null) { 575 security.checkPermission(setLocalePermission); 576 } 577 578 defaultLocale = locale; 579 } 580 581 /** 582 * Returns the string representation of this {@code Locale}. It consists of the 583 * language code, country code and variant separated by underscores. 584 * If the language is missing the string begins 585 * with an underscore. If the country is missing there are 2 underscores 586 * between the language and the variant. The variant cannot stand alone 587 * without a language and/or country code: in this case this method would 588 * return the empty string. 589 * 590 * <p>Examples: "en", "en_US", "_US", "en__POSIX", "en_US_POSIX" 591 * 592 * @return the string representation of this {@code Locale}. 593 */ 594 @Override 595 public final String toString() { 596 String result = cachedToStringResult; 597 return (result == null) ? (cachedToStringResult = toNewString()) : result; 598 } 599 600 private String toNewString() { 601 // The string form of a locale that only has a variant is the empty string. 602 if (languageCode.length() == 0 && countryCode.length() == 0) { 603 return ""; 604 } 605 // Otherwise, the output format is "ll_cc_variant", where language and country are always 606 // two letters, but the variant is an arbitrary length. A size of 11 characters has room 607 // for "en_US_POSIX", the largest "common" value. (In practice, the string form is almost 608 // always 5 characters: "ll_cc".) 609 StringBuilder result = new StringBuilder(11); 610 result.append(languageCode); 611 if (countryCode.length() > 0 || variantCode.length() > 0) { 612 result.append('_'); 613 } 614 result.append(countryCode); 615 if (variantCode.length() > 0) { 616 result.append('_'); 617 } 618 result.append(variantCode); 619 return result.toString(); 620 } 621 622 private static final ObjectStreamField[] serialPersistentFields = { 623 new ObjectStreamField("country", String.class), 624 new ObjectStreamField("hashcode", Integer.TYPE), 625 new ObjectStreamField("language", String.class), 626 new ObjectStreamField("variant", String.class) }; 627 628 private void writeObject(ObjectOutputStream stream) throws IOException { 629 ObjectOutputStream.PutField fields = stream.putFields(); 630 fields.put("country", countryCode); 631 fields.put("hashcode", -1); 632 fields.put("language", languageCode); 633 fields.put("variant", variantCode); 634 stream.writeFields(); 635 } 636 637 private void readObject(ObjectInputStream stream) throws IOException, ClassNotFoundException { 638 ObjectInputStream.GetField fields = stream.readFields(); 639 countryCode = (String) fields.get("country", ""); 640 languageCode = (String) fields.get("language", ""); 641 variantCode = (String) fields.get("variant", ""); 642 } 643 } 644