src/share/classes/java/util/Locale.java
Print this page
rev 5696 : 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 packaging changes. by Naoto Sato and Masayoshi Okutsu)
*** 1,7 ****
/*
! * Copyright (c) 1996, 2011, 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
--- 1,7 ----
/*
! * 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,68 ****
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.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.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
--- 48,67 ----
import java.security.AccessController;
import java.text.MessageFormat;
import java.util.spi.LocaleNameProvider;
import sun.security.action.GetPropertyAction;
! 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.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,973 ****
String[] result = new String[isoLanguages.length];
System.arraycopy(isoLanguages, 0, result, 0, isoLanguages.length);
return result;
}
! private static final 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);
}
--- 962,972 ----
String[] result = new String[isoLanguages.length];
System.arraycopy(isoLanguages, 0, result, 0, isoLanguages.length);
return result;
}
! 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,1041 ****
--- 1031,1064 ----
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,1060 ****
*/
public String getExtension(char key) {
if (!LocaleExtensions.isValidKey(key)) {
throw new IllegalArgumentException("Ill-formed extension key: " + key);
}
! return (localeExtensions == null) ? null : localeExtensions.getExtensionValue(key);
}
/**
* Returns the set of extension keys associated with this locale, or the
* empty set if it has no extensions. The returned set is unmodifiable.
--- 1073,1083 ----
*/
public String getExtension(char key) {
if (!LocaleExtensions.isValidKey(key)) {
throw new IllegalArgumentException("Ill-formed extension key: " + 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,1073 ****
* @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) {
return Collections.emptySet();
}
return localeExtensions.getKeys();
}
--- 1086,1096 ----
* @return The set of extension keys, or the empty set if this locale has
* no extensions.
* @since 1.7
*/
public Set<Character> getExtensionKeys() {
! if (!hasExtensions()) {
return Collections.emptySet();
}
return localeExtensions.getKeys();
}
*** 1078,1088 ****
*
* @return The set of attributes.
* @since 1.7
*/
public Set<String> getUnicodeLocaleAttributes() {
! if (localeExtensions == null) {
return Collections.emptySet();
}
return localeExtensions.getUnicodeLocaleAttributes();
}
--- 1101,1111 ----
*
* @return The set of attributes.
* @since 1.7
*/
public Set<String> getUnicodeLocaleAttributes() {
! if (!hasExtensions()) {
return Collections.emptySet();
}
return localeExtensions.getUnicodeLocaleAttributes();
}
*** 1099,1112 ****
* @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)) {
throw new IllegalArgumentException("Ill-formed Unicode locale key: " + key);
}
! return (localeExtensions == null) ? null : localeExtensions.getUnicodeLocaleType(key);
}
/**
* 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.
--- 1122,1135 ----
* @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 (!isUnicodeExtensionKey(key)) {
throw new IllegalArgumentException("Ill-formed Unicode locale key: " + 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,1292 ****
--- 1306,1319 ----
* @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,1337 ****
buf.append(LanguageTag.PRIVATEUSE).append(LanguageTag.SEP);
// preserve casing
buf.append(subtag);
}
! return buf.toString();
}
/**
* Returns a locale for the specified IETF BCP 47 language tag string.
*
* <p>If the specified language tag contains any ill-formed subtags,
--- 1353,1370 ----
buf.append(LanguageTag.PRIVATEUSE).append(LanguageTag.SEP);
// preserve casing
buf.append(subtag);
}
! 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,1522 ****
+ baseLocale.getRegion(), "FormatData_" + toString(), "ShortCountry");
}
return country3;
}
! private static final String getISO3Code(String iso2Code, String table) {
int codeLength = iso2Code.length();
if (codeLength == 0) {
return "";
}
--- 1545,1555 ----
+ baseLocale.getRegion(), "FormatData_" + toString(), "ShortCountry");
}
return country3;
}
! private static String getISO3Code(String iso2Code, String table) {
int codeLength = iso2Code.length();
if (codeLength == 0) {
return "";
}
*** 1638,1674 ****
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(
LocaleNameGetter.INSTANCE,
! inLocale, bundle, key,
! type, code);
! }
!
! if (result == null) {
! result = bundle.getString(key);
! }
!
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
--- 1671,1690 ----
if (inLocale == null) {
throw new NullPointerException();
}
LocaleServiceProviderPool pool =
LocaleServiceProviderPool.getPool(LocaleNameProvider.class);
! String key = (type == DISPLAY_VARIANT ? "%%"+code : code);
! String result = pool.getLocalizedObject(
LocaleNameGetter.INSTANCE,
! inLocale, key, type, code);
if (result != null) {
return result;
}
!
return code;
}
/**
* Returns a name for the locale's variant code that is appropriate for display to the
*** 1688,1698 ****
*/
public String getDisplayVariant(Locale inLocale) {
if (baseLocale.getVariant().length() == 0)
return "";
! OpenListResourceBundle bundle = LocaleData.getLocaleNames(inLocale);
String names[] = getDisplayVariantArray(bundle, inLocale);
// Get the localized patterns for formatting a list, and use
// them to format the list.
--- 1704,1714 ----
*/
public String getDisplayVariant(Locale inLocale) {
if (baseLocale.getVariant().length() == 0)
return "";
! 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,1756 ****
* 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);
String languageName = getDisplayLanguage(inLocale);
String scriptName = getDisplayScript(inLocale);
String countryName = getDisplayCountry(inLocale);
String[] variantNames = getDisplayVariantArray(bundle, inLocale);
--- 1762,1772 ----
* this function returns the empty string.
*
* @throws NullPointerException if <code>inLocale</code> is <code>null</code>
*/
public String getDisplayName(Locale 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,1805 ****
}
if (countryName.length() != 0) {
names.add(countryName);
}
if (variantNames.length != 0) {
! for (String var : variantNames) {
! names.add(var);
}
- }
// The first one in the main name
mainName = names.get(0);
// Others are qualifiers
--- 1808,1819 ----
}
if (countryName.length() != 0) {
names.add(countryName);
}
if (variantNames.length != 0) {
! names.addAll(Arrays.asList(variantNames));
}
// The first one in the main name
mainName = names.get(0);
// Others are qualifiers
*** 1841,1850 ****
--- 1855,1865 ----
}
/**
* Overrides Cloneable.
*/
+ @Override
public Object clone()
{
try {
Locale that = (Locale)super.clone();
return that;
*** 1908,1917 ****
--- 1923,1934 ----
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,1955 ****
*/
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(',');
result.append(stringList[i]);
}
return result.toString();
}
--- 1960,1974 ----
*/
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) {
! 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,2001 ****
--- 2011,2027 ----
// 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,2143 ****
--- 2160,2170 ----
*/
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;