src/share/classes/java/util/Locale.java
Print this page
rev 5615 : 6336885: RFE: Locale Data Deployment Enhancements
4609153: Provide locale data for Indic locales
5104387: Support for gl_ES locale (galician language)
6337471: desktop/system locale preferences support
7056139: (cal) SPI support for locale-dependent Calendar parameters
7058206: Provide CalendarData SPI for week params and display field value names
7073852: Support multiple scripts for digits and decimal symbols per locale
7079560: [Fmt-Da] Context dependent month names support in SimpleDateFormat
7171324: getAvailableLocales() of locale sensitive services should return the actual availability of locales
7151414: (cal) Support calendar type identification
7168528: LocaleServiceProvider needs to be aware of Locale extensions
7171372: (cal) locale's default Calendar should be created if unknown calendar is specified
Summary: JEP 127: Improve Locale Data Packaging and Adopt Unicode CLDR Data (part 1 w/o Jigsaw. by Naoto Sato and Masayoshi Okutsu)
@@ -1,7 +1,7 @@
/*
- * Copyright (c) 1996, 2011, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1996, 2012, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
@@ -48,21 +48,20 @@
import java.security.AccessController;
import java.text.MessageFormat;
import java.util.spi.LocaleNameProvider;
import sun.security.action.GetPropertyAction;
-import sun.util.LocaleServiceProviderPool;
+import sun.util.locale.provider.LocaleServiceProviderPool;
import sun.util.locale.BaseLocale;
import sun.util.locale.InternalLocaleBuilder;
import sun.util.locale.LanguageTag;
import sun.util.locale.LocaleExtensions;
import sun.util.locale.LocaleObjectCache;
import sun.util.locale.LocaleSyntaxException;
import sun.util.locale.LocaleUtils;
import sun.util.locale.ParseStatus;
-import sun.util.locale.UnicodeLocaleExtension;
-import sun.util.resources.LocaleData;
+import sun.util.locale.provider.LocaleProviderAdapter;
import sun.util.resources.OpenListResourceBundle;
/**
* A <code>Locale</code> object represents a specific geographical, political,
* or cultural region. An operation that requires a <code>Locale</code> to perform
@@ -963,11 +962,11 @@
String[] result = new String[isoLanguages.length];
System.arraycopy(isoLanguages, 0, result, 0, isoLanguages.length);
return result;
}
- private static final String[] getISO2Table(String table) {
+ private static String[] getISO2Table(String table) {
int len = table.length() / 5;
String[] isoTable = new String[len];
for (int i = 0, j = 0; i < len; i++, j += 5) {
isoTable[i] = table.substring(j, j + 2);
}
@@ -1032,10 +1031,34 @@
public String getVariant() {
return baseLocale.getVariant();
}
/**
+ * Returns {@code true} if this {@code Locale} has any <a href="#def_extensions">
+ * extensions</a>.
+ *
+ * @return {@code true} if this {@code Locale} has any extensions
+ * @since 1.8
+ */
+ public boolean hasExtensions() {
+ return localeExtensions != null;
+ }
+
+ /**
+ * Returns a copy of this {@code Locale} with no <a href="#def_extensions">
+ * extensions</a>. If this {@code Locale} has no extensions, this {@code Locale}
+ * is returned.
+ *
+ * @return a copy of this {@code Locale} with no extensions, or {@code this}
+ * if {@code this} has no extensions
+ * @since 1.8
+ */
+ public Locale stripExtensions() {
+ return hasExtensions() ? Locale.getInstance(baseLocale, null) : this;
+ }
+
+ /**
* Returns the extension (or private use) value associated with
* the specified key, or null if there is no extension
* associated with the key. To be well-formed, the key must be one
* of <code>[0-9A-Za-z]</code>. Keys are case-insensitive, so
* for example 'z' and 'Z' represent the same extension.
@@ -1050,11 +1073,11 @@
*/
public String getExtension(char key) {
if (!LocaleExtensions.isValidKey(key)) {
throw new IllegalArgumentException("Ill-formed extension key: " + key);
}
- return (localeExtensions == null) ? null : localeExtensions.getExtensionValue(key);
+ return hasExtensions() ? localeExtensions.getExtensionValue(key) : null;
}
/**
* Returns the set of extension keys associated with this locale, or the
* empty set if it has no extensions. The returned set is unmodifiable.
@@ -1063,11 +1086,11 @@
* @return The set of extension keys, or the empty set if this locale has
* no extensions.
* @since 1.7
*/
public Set<Character> getExtensionKeys() {
- if (localeExtensions == null) {
+ if (!hasExtensions()) {
return Collections.emptySet();
}
return localeExtensions.getKeys();
}
@@ -1078,11 +1101,11 @@
*
* @return The set of attributes.
* @since 1.7
*/
public Set<String> getUnicodeLocaleAttributes() {
- if (localeExtensions == null) {
+ if (!hasExtensions()) {
return Collections.emptySet();
}
return localeExtensions.getUnicodeLocaleAttributes();
}
@@ -1099,14 +1122,14 @@
* @throws IllegalArgumentException if the key is not well-formed
* @throws NullPointerException if <code>key</code> is null
* @since 1.7
*/
public String getUnicodeLocaleType(String key) {
- if (!UnicodeLocaleExtension.isKey(key)) {
+ if (!isUnicodeExtensionKey(key)) {
throw new IllegalArgumentException("Ill-formed Unicode locale key: " + key);
}
- return (localeExtensions == null) ? null : localeExtensions.getUnicodeLocaleType(key);
+ return hasExtensions() ? localeExtensions.getUnicodeLocaleType(key) : null;
}
/**
* Returns the set of Unicode locale keys defined by this locale, or the empty set if
* this locale has none. The returned set is immutable. Keys are all lower case.
@@ -1283,10 +1306,14 @@
* @return a BCP47 language tag representing the locale
* @see #forLanguageTag(String)
* @since 1.7
*/
public String toLanguageTag() {
+ if (languageTag != null) {
+ return languageTag;
+ }
+
LanguageTag tag = LanguageTag.parseLocale(baseLocale, localeExtensions);
StringBuilder buf = new StringBuilder();
String subtag = tag.getLanguage();
if (subtag.length() > 0) {
@@ -1326,12 +1353,18 @@
buf.append(LanguageTag.PRIVATEUSE).append(LanguageTag.SEP);
// preserve casing
buf.append(subtag);
}
- return buf.toString();
+ String langTag = buf.toString();
+ synchronized (this) {
+ if (languageTag == null) {
+ languageTag = langTag;
}
+ }
+ return languageTag;
+ }
/**
* Returns a locale for the specified IETF BCP 47 language tag string.
*
* <p>If the specified language tag contains any ill-formed subtags,
@@ -1512,11 +1545,11 @@
+ baseLocale.getRegion(), "FormatData_" + toString(), "ShortCountry");
}
return country3;
}
- private static final String getISO3Code(String iso2Code, String table) {
+ private static String getISO3Code(String iso2Code, String table) {
int codeLength = iso2Code.length();
if (codeLength == 0) {
return "";
}
@@ -1638,37 +1671,20 @@
if (inLocale == null) {
throw new NullPointerException();
}
- try {
- OpenListResourceBundle bundle = LocaleData.getLocaleNames(inLocale);
- String key = (type == DISPLAY_VARIANT ? "%%"+code : code);
- String result = null;
-
- // Check whether a provider can provide an implementation that's closer
- // to the requested locale than what the Java runtime itself can provide.
LocaleServiceProviderPool pool =
LocaleServiceProviderPool.getPool(LocaleNameProvider.class);
- if (pool.hasProviders()) {
- result = pool.getLocalizedObject(
+ String key = (type == DISPLAY_VARIANT ? "%%"+code : code);
+ String result = pool.getLocalizedObject(
LocaleNameGetter.INSTANCE,
- inLocale, bundle, key,
- type, code);
- }
-
- if (result == null) {
- result = bundle.getString(key);
- }
-
+ inLocale, key, type, code);
if (result != null) {
return result;
}
- }
- catch (Exception e) {
- // just fall through
- }
+
return code;
}
/**
* Returns a name for the locale's variant code that is appropriate for display to the
@@ -1688,11 +1704,11 @@
*/
public String getDisplayVariant(Locale inLocale) {
if (baseLocale.getVariant().length() == 0)
return "";
- OpenListResourceBundle bundle = LocaleData.getLocaleNames(inLocale);
+ OpenListResourceBundle bundle = LocaleProviderAdapter.forJRE().getLocaleData().getLocaleNames(inLocale);
String names[] = getDisplayVariantArray(bundle, inLocale);
// Get the localized patterns for formatting a list, and use
// them to format the list.
@@ -1746,11 +1762,11 @@
* this function returns the empty string.
*
* @throws NullPointerException if <code>inLocale</code> is <code>null</code>
*/
public String getDisplayName(Locale inLocale) {
- OpenListResourceBundle bundle = LocaleData.getLocaleNames(inLocale);
+ OpenListResourceBundle bundle = LocaleProviderAdapter.forJRE().getLocaleData().getLocaleNames(inLocale);
String languageName = getDisplayLanguage(inLocale);
String scriptName = getDisplayScript(inLocale);
String countryName = getDisplayCountry(inLocale);
String[] variantNames = getDisplayVariantArray(bundle, inLocale);
@@ -1792,14 +1808,12 @@
}
if (countryName.length() != 0) {
names.add(countryName);
}
if (variantNames.length != 0) {
- for (String var : variantNames) {
- names.add(var);
+ names.addAll(Arrays.asList(variantNames));
}
- }
// The first one in the main name
mainName = names.get(0);
// Others are qualifiers
@@ -1841,10 +1855,11 @@
}
/**
* Overrides Cloneable.
*/
+ @Override
public Object clone()
{
try {
Locale that = (Locale)super.clone();
return that;
@@ -1908,10 +1923,12 @@
private volatile static Locale defaultLocale = initDefault();
private volatile static Locale defaultDisplayLocale = null;
private volatile static Locale defaultFormatLocale = null;
+ private transient volatile String languageTag;
+
/**
* Return an array of the display names of the variant.
* @param bundle the ResourceBundle to use to get the display names
* @return an array of display names, possible of zero length.
*/
@@ -1943,13 +1960,15 @@
*/
private static String formatList(String[] stringList, String listPattern, String listCompositionPattern) {
// If we have no list patterns, compose the list in a simple,
// non-localized way.
if (listPattern == null || listCompositionPattern == null) {
- StringBuffer result = new StringBuffer();
- for (int i=0; i<stringList.length; ++i) {
- if (i>0) result.append(',');
+ StringBuilder result = new StringBuilder();
+ for (int i = 0; i < stringList.length; ++i) {
+ if (i > 0) {
+ result.append(',');
+ }
result.append(stringList[i]);
}
return result.toString();
}
@@ -1992,10 +2011,17 @@
// Recurse
return composeList(format, newList);
}
+ // Duplicate of sun.util.locale.UnicodeLocaleExtension.isKey in order to
+ // avoid its class loading.
+ private static boolean isUnicodeExtensionKey(String s) {
+ // 2alphanum
+ return (s.length() == 2) && LocaleUtils.isAlphaNumericString(s);
+ }
+
/**
* @serialField language String
* language subtag in lower case. (See <a href="java/util/Locale.html#getLanguage()">getLanguage()</a>)
* @serialField country String
* country subtag in upper case. (See <a href="java/util/Locale.html#getCountry()">getCountry()</a>)
@@ -2134,10 +2160,11 @@
*/
private static class LocaleNameGetter
implements LocaleServiceProviderPool.LocalizedObjectGetter<LocaleNameProvider, String> {
private static final LocaleNameGetter INSTANCE = new LocaleNameGetter();
+ @Override
public String getObject(LocaleNameProvider localeNameProvider,
Locale locale,
String key,
Object... params) {
assert params.length == 2;