6875847: Java Locale Enhancement
Co-authored-by: Doug Felt <dougfelt@google.com> Co-authored-by: Mark Davis <markdavis@google.com> Reviewed-by: srl
This commit is contained in:
parent
7640dd5bee
commit
fbca39ee5d
@ -183,10 +183,22 @@ JAVA_JAVA_java = \
|
||||
java/util/MissingFormatWidthException.java \
|
||||
java/util/UnknownFormatConversionException.java \
|
||||
java/util/UnknownFormatFlagsException.java \
|
||||
java/util/IllformedLocaleException.java \
|
||||
java/util/FormatterClosedException.java \
|
||||
java/util/ListResourceBundle.java \
|
||||
sun/util/EmptyListResourceBundle.java \
|
||||
java/util/Locale.java \
|
||||
sun/util/locale/AsciiUtil.java \
|
||||
sun/util/locale/BaseLocale.java \
|
||||
sun/util/locale/Extension.java \
|
||||
sun/util/locale/InternalLocaleBuilder.java \
|
||||
sun/util/locale/LanguageTag.java \
|
||||
sun/util/locale/LocaleExtensions.java \
|
||||
sun/util/locale/LocaleObjectCache.java \
|
||||
sun/util/locale/LocaleSyntaxException.java \
|
||||
sun/util/locale/ParseStatus.java \
|
||||
sun/util/locale/StringTokenIterator.java \
|
||||
sun/util/locale/UnicodeLocaleExtension.java \
|
||||
java/util/LocaleISOData.java \
|
||||
sun/util/LocaleServiceProviderPool.java \
|
||||
sun/util/LocaleDataMetaInfo.java \
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 1996, 2006, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 1996, 2010, 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
|
||||
@ -43,10 +43,10 @@ import java.io.ObjectInputStream;
|
||||
import java.io.Serializable;
|
||||
import java.text.spi.DecimalFormatSymbolsProvider;
|
||||
import java.util.Currency;
|
||||
import java.util.Hashtable;
|
||||
import java.util.Locale;
|
||||
import java.util.ResourceBundle;
|
||||
import java.util.spi.LocaleServiceProvider;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
import sun.util.LocaleServiceProviderPool;
|
||||
import sun.util.resources.LocaleData;
|
||||
|
||||
@ -527,10 +527,17 @@ public class DecimalFormatSymbols implements Cloneable, Serializable {
|
||||
|
||||
// get resource bundle data - try the cache first
|
||||
boolean needCacheUpdate = false;
|
||||
Object[] data = (Object[]) cachedLocaleData.get(locale);
|
||||
Object[] data = cachedLocaleData.get(locale);
|
||||
if (data == null) { /* cache miss */
|
||||
// When numbering system is thai (Locale's extension contains u-nu-thai),
|
||||
// we read the data from th_TH_TH.
|
||||
Locale lookupLocale = locale;
|
||||
String numberType = locale.getUnicodeLocaleType("nu");
|
||||
if (numberType != null && numberType.equals("thai")) {
|
||||
lookupLocale = new Locale("th", "TH", "TH");
|
||||
}
|
||||
data = new Object[3];
|
||||
ResourceBundle rb = LocaleData.getNumberFormatData(locale);
|
||||
ResourceBundle rb = LocaleData.getNumberFormatData(lookupLocale);
|
||||
data[0] = rb.getStringArray("NumberElements");
|
||||
needCacheUpdate = true;
|
||||
}
|
||||
@ -586,7 +593,7 @@ public class DecimalFormatSymbols implements Cloneable, Serializable {
|
||||
monetarySeparator = decimalSeparator;
|
||||
|
||||
if (needCacheUpdate) {
|
||||
cachedLocaleData.put(locale, data);
|
||||
cachedLocaleData.putIfAbsent(locale, data);
|
||||
}
|
||||
}
|
||||
|
||||
@ -806,7 +813,7 @@ public class DecimalFormatSymbols implements Cloneable, Serializable {
|
||||
* cache to hold the NumberElements and the Currency
|
||||
* of a Locale.
|
||||
*/
|
||||
private static final Hashtable cachedLocaleData = new Hashtable(3);
|
||||
private static final ConcurrentHashMap<Locale, Object[]> cachedLocaleData = new ConcurrentHashMap<Locale, Object[]>(3);
|
||||
|
||||
/**
|
||||
* Obtains a DecimalFormatSymbols instance from a DecimalFormatSymbolsProvider
|
||||
|
@ -1013,19 +1013,30 @@ public abstract class Calendar implements Serializable, Cloneable, Comparable<Ca
|
||||
private static Calendar createCalendar(TimeZone zone,
|
||||
Locale aLocale)
|
||||
{
|
||||
// If the specified locale is a Thai locale, returns a BuddhistCalendar
|
||||
// instance.
|
||||
if ("th".equals(aLocale.getLanguage())
|
||||
&& ("TH".equals(aLocale.getCountry()))) {
|
||||
return new sun.util.BuddhistCalendar(zone, aLocale);
|
||||
} else if ("JP".equals(aLocale.getVariant())
|
||||
&& "JP".equals(aLocale.getCountry())
|
||||
&& "ja".equals(aLocale.getLanguage())) {
|
||||
return new JapaneseImperialCalendar(zone, aLocale);
|
||||
Calendar cal = null;
|
||||
|
||||
String caltype = aLocale.getUnicodeLocaleType("ca");
|
||||
if (caltype == null) {
|
||||
// Calendar type is not specified.
|
||||
// If the specified locale is a Thai locale,
|
||||
// returns a BuddhistCalendar instance.
|
||||
if ("th".equals(aLocale.getLanguage())
|
||||
&& ("TH".equals(aLocale.getCountry()))) {
|
||||
cal = new BuddhistCalendar(zone, aLocale);
|
||||
} else {
|
||||
cal = new GregorianCalendar(zone, aLocale);
|
||||
}
|
||||
} else if (caltype.equals("japanese")) {
|
||||
cal = new JapaneseImperialCalendar(zone, aLocale);
|
||||
} else if (caltype.equals("buddhist")) {
|
||||
cal = new BuddhistCalendar(zone, aLocale);
|
||||
} else {
|
||||
// Unsupported calendar type.
|
||||
// Use Gregorian calendar as a fallback.
|
||||
cal = new GregorianCalendar(zone, aLocale);
|
||||
}
|
||||
|
||||
// else create the default calendar
|
||||
return new GregorianCalendar(zone, aLocale);
|
||||
return cal;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -0,0 +1,90 @@
|
||||
/*
|
||||
* Copyright (c) 2010, 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
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
/*
|
||||
*******************************************************************************
|
||||
* Copyright (C) 2009-2010, International Business Machines Corporation and *
|
||||
* others. All Rights Reserved. *
|
||||
*******************************************************************************
|
||||
*/
|
||||
|
||||
package java.util;
|
||||
|
||||
/**
|
||||
* Thrown by methods in {@link Locale} and {@link Locale.Builder} to
|
||||
* indicate that an argument is not a well-formed BCP 47 tag.
|
||||
*
|
||||
* @see Locale
|
||||
* @since 1.7
|
||||
*/
|
||||
public class IllformedLocaleException extends RuntimeException {
|
||||
|
||||
private static final long serialVersionUID = -5245986824925681401L;
|
||||
|
||||
private int _errIdx = -1;
|
||||
|
||||
/**
|
||||
* Constructs a new <code>IllformedLocaleException</code> with no
|
||||
* detail message and -1 as the error index.
|
||||
*/
|
||||
public IllformedLocaleException() {
|
||||
super();
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a new <code>IllformedLocaleException</code> with the
|
||||
* given message and -1 as the error index.
|
||||
*
|
||||
* @param message the message
|
||||
*/
|
||||
public IllformedLocaleException(String message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a new <code>IllformedLocaleException</code> with the
|
||||
* given message and the error index. The error index is the approximate
|
||||
* offset from the start of the ill-formed value to the point where the
|
||||
* parse first detected an error. A negative error index value indicates
|
||||
* either the error index is not applicable or unknown.
|
||||
*
|
||||
* @param message the message
|
||||
* @param errorIndex the index
|
||||
*/
|
||||
public IllformedLocaleException(String message, int errorIndex) {
|
||||
super(message + ((errorIndex < 0) ? "" : " [at index " + errorIndex + "]"));
|
||||
_errIdx = errorIndex;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the index where the error was found. A negative value indicates
|
||||
* either the error index is not applicable or unknown.
|
||||
*
|
||||
* @return the error index
|
||||
*/
|
||||
public int getErrorIndex() {
|
||||
return _errIdx;
|
||||
}
|
||||
}
|
File diff suppressed because it is too large
Load Diff
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 1996, 2006, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 1996, 2010, 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
|
||||
@ -56,16 +56,18 @@ import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.ConcurrentMap;
|
||||
import java.util.jar.JarEntry;
|
||||
|
||||
import sun.util.locale.BaseLocale;
|
||||
import sun.util.locale.LocaleExtensions;
|
||||
import sun.util.locale.LocaleObjectCache;
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
* Resource bundles contain locale-specific objects.
|
||||
* When your program needs a locale-specific resource,
|
||||
* a <code>String</code> for example, your program can load it
|
||||
* from the resource bundle that is appropriate for the
|
||||
* current user's locale. In this way, you can write
|
||||
* program code that is largely independent of the user's
|
||||
* locale isolating most, if not all, of the locale-specific
|
||||
* Resource bundles contain locale-specific objects. When your program needs a
|
||||
* locale-specific resource, a <code>String</code> for example, your program can
|
||||
* load it from the resource bundle that is appropriate for the current user's
|
||||
* locale. In this way, you can write program code that is largely independent
|
||||
* of the user's locale isolating most, if not all, of the locale-specific
|
||||
* information in resource bundles.
|
||||
*
|
||||
* <p>
|
||||
@ -854,87 +856,140 @@ public abstract class ResourceBundle {
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a resource bundle using the specified base name, locale, and class loader.
|
||||
* Gets a resource bundle using the specified base name, locale, and class
|
||||
* loader.
|
||||
*
|
||||
* <p><a name="default_behavior"/>
|
||||
* Conceptually, <code>getBundle</code> uses the following strategy for locating and instantiating
|
||||
* resource bundles:
|
||||
* <p>
|
||||
* <code>getBundle</code> uses the base name, the specified locale, and the default
|
||||
* locale (obtained from {@link java.util.Locale#getDefault() Locale.getDefault})
|
||||
* to generate a sequence of <a name="candidates"><em>candidate bundle names</em></a>.
|
||||
* If the specified locale's language, country, and variant are all empty
|
||||
* strings, then the base name is the only candidate bundle name.
|
||||
* Otherwise, the following sequence is generated from the attribute
|
||||
* values of the specified locale (language1, country1, and variant1)
|
||||
* and of the default locale (language2, country2, and variant2):
|
||||
* <ul>
|
||||
* <li> baseName + "_" + language1 + "_" + country1 + "_" + variant1
|
||||
* <li> baseName + "_" + language1 + "_" + country1
|
||||
* <li> baseName + "_" + language1
|
||||
* <li> baseName + "_" + language2 + "_" + country2 + "_" + variant2
|
||||
* <li> baseName + "_" + language2 + "_" + country2
|
||||
* <li> baseName + "_" + language2
|
||||
* <li> baseName
|
||||
* </ul>
|
||||
* <p>
|
||||
* Candidate bundle names where the final component is an empty string are omitted.
|
||||
* For example, if country1 is an empty string, the second candidate bundle name is omitted.
|
||||
* <p><a name="default_behavior"/>This method behaves the same as calling
|
||||
* {@link #getBundle(String, Locale, ClassLoader, Control)} passing a
|
||||
* default instance of {@link Control}. The following describes this behavior.
|
||||
*
|
||||
* <p>
|
||||
* <code>getBundle</code> then iterates over the candidate bundle names to find the first
|
||||
* one for which it can <em>instantiate</em> an actual resource bundle. For each candidate
|
||||
* bundle name, it attempts to create a resource bundle:
|
||||
* <ul>
|
||||
* <li>
|
||||
* First, it attempts to load a class using the candidate bundle name.
|
||||
* If such a class can be found and loaded using the specified class loader, is assignment
|
||||
* compatible with ResourceBundle, is accessible from ResourceBundle, and can be instantiated,
|
||||
* <code>getBundle</code> creates a new instance of this class and uses it as the <em>result
|
||||
* resource bundle</em>.
|
||||
* <li>
|
||||
* Otherwise, <code>getBundle</code> attempts to locate a property resource file.
|
||||
* It generates a path name from the candidate bundle name by replacing all "." characters
|
||||
* with "/" and appending the string ".properties".
|
||||
* It attempts to find a "resource" with this name using
|
||||
* {@link java.lang.ClassLoader#getResource(java.lang.String) ClassLoader.getResource}.
|
||||
* (Note that a "resource" in the sense of <code>getResource</code> has nothing to do with
|
||||
* the contents of a resource bundle, it is just a container of data, such as a file.)
|
||||
* If it finds a "resource", it attempts to create a new
|
||||
* {@link PropertyResourceBundle} instance from its contents.
|
||||
* If successful, this instance becomes the <em>result resource bundle</em>.
|
||||
* </ul>
|
||||
* <p><code>getBundle</code> uses the base name, the specified locale, and
|
||||
* the default locale (obtained from {@link java.util.Locale#getDefault()
|
||||
* Locale.getDefault}) to generate a sequence of <a
|
||||
* name="candidates"><em>candidate bundle names</em></a>. If the specified
|
||||
* locale's language, script, country, and variant are all empty strings,
|
||||
* then the base name is the only candidate bundle name. Otherwise, a list
|
||||
* of candidate locales is generated from the attribute values of the
|
||||
* specified locale (language, script, country and variant) and appended to
|
||||
* the base name. Typically, this will look like the following:
|
||||
*
|
||||
* <p>
|
||||
* If no result resource bundle has been found, a <code>MissingResourceException</code>
|
||||
* is thrown.
|
||||
* <pre>
|
||||
* baseName + "_" + language + "_" + script + "_" + country + "_" + variant
|
||||
* baseName + "_" + language + "_" + script + "_" + country
|
||||
* baseName + "_" + language + "_" + script
|
||||
* baseName + "_" + language + "_" + country + "_" + variant
|
||||
* baseName + "_" + language + "_" + country
|
||||
* baseName + "_" + language
|
||||
* </pre>
|
||||
*
|
||||
* <p><a name="parent_chain"/>
|
||||
* Once a result resource bundle has been found, its <em>parent chain</em> is instantiated.
|
||||
* <code>getBundle</code> iterates over the candidate bundle names that can be
|
||||
* obtained by successively removing variant, country, and language
|
||||
* (each time with the preceding "_") from the bundle name of the result resource bundle.
|
||||
* As above, candidate bundle names where the final component is an empty string are omitted.
|
||||
* With each of the candidate bundle names it attempts to instantiate a resource bundle, as
|
||||
* described above.
|
||||
* Whenever it succeeds, it calls the previously instantiated resource
|
||||
* <p>Candidate bundle names where the final component is an empty string
|
||||
* are omitted, along with the underscore. For example, if country is an
|
||||
* empty string, the second and the fifth candidate bundle names above
|
||||
* would be omitted. Also, if script is an empty string, the candidate names
|
||||
* including script are omitted. For example, a locale with language "de"
|
||||
* and variant "JAVA" will produce candidate names with base name
|
||||
* "MyResource" below.
|
||||
*
|
||||
* <pre>
|
||||
* MyResource_de__JAVA
|
||||
* MyResource_de
|
||||
* </pre>
|
||||
*
|
||||
* In the case that the variant contains one or more underscores ('_'), a
|
||||
* sequence of bundle names generated by truncating the last underscore and
|
||||
* the part following it is inserted after a candidate bundle name with the
|
||||
* original variant. For example, for a locale with language "en", script
|
||||
* "Latn, country "US" and variant "WINDOWS_VISTA", and bundle base name
|
||||
* "MyResource", the list of candidate bundle names below is generated:
|
||||
*
|
||||
* <pre>
|
||||
* MyResource_en_Latn_US_WINDOWS_VISTA
|
||||
* MyResource_en_Latn_US_WINDOWS
|
||||
* MyResource_en_Latn_US
|
||||
* MyResource_en_Latn
|
||||
* MyResource_en_US_WINDOWS_VISTA
|
||||
* MyResource_en_US_WINDOWS
|
||||
* MyResource_en_US
|
||||
* MyResource_en
|
||||
* </pre>
|
||||
*
|
||||
* <blockquote><b>Note:</b> For some <code>Locale</code>s, the list of
|
||||
* candidate bundle names contains extra names, or the order of bundle names
|
||||
* is slightly modified. See the description of the default implementation
|
||||
* of {@link Control#getCandidateLocales(String, Locale)
|
||||
* getCandidateLocales} for details.</blockquote>
|
||||
*
|
||||
* <p><code>getBundle</code> then iterates over the candidate bundle names
|
||||
* to find the first one for which it can <em>instantiate</em> an actual
|
||||
* resource bundle. It uses the default controls' {@link Control#getFormats
|
||||
* getFormats} method, which generates two bundle names for each generated
|
||||
* name, the first a class name and the second a properties file name. For
|
||||
* each candidate bundle name, it attempts to create a resource bundle:
|
||||
*
|
||||
* <ul><li>First, it attempts to load a class using the generated class name.
|
||||
* If such a class can be found and loaded using the specified class
|
||||
* loader, is assignment compatible with ResourceBundle, is accessible from
|
||||
* ResourceBundle, and can be instantiated, <code>getBundle</code> creates a
|
||||
* new instance of this class and uses it as the <em>result resource
|
||||
* bundle</em>.
|
||||
*
|
||||
* <li>Otherwise, <code>getBundle</code> attempts to locate a property
|
||||
* resource file using the generated properties file name. It generates a
|
||||
* path name from the candidate bundle name by replacing all "." characters
|
||||
* with "/" and appending the string ".properties". It attempts to find a
|
||||
* "resource" with this name using {@link
|
||||
* java.lang.ClassLoader#getResource(java.lang.String)
|
||||
* ClassLoader.getResource}. (Note that a "resource" in the sense of
|
||||
* <code>getResource</code> has nothing to do with the contents of a
|
||||
* resource bundle, it is just a container of data, such as a file.) If it
|
||||
* finds a "resource", it attempts to create a new {@link
|
||||
* PropertyResourceBundle} instance from its contents. If successful, this
|
||||
* instance becomes the <em>result resource bundle</em>. </ul>
|
||||
*
|
||||
* <p>This continues until a result resource bundle is instantiated or the
|
||||
* list of candidate bundle names is exhausted. If no matching resource
|
||||
* bundle is found, the default control's {@link Control#getFallbackLocale
|
||||
* getFallbackLocale} method is called, which returns the current default
|
||||
* locale. A new sequence of candidate locale names is generated using this
|
||||
* locale and and searched again, as above.
|
||||
*
|
||||
* <p>If still no result bundle is found, the base name alone is looked up. If
|
||||
* this still fails, a <code>MissingResourceException</code> is thrown.
|
||||
*
|
||||
* <p><a name="parent_chain"/> Once a result resource bundle has been found,
|
||||
* its <em>parent chain</em> is instantiated. If the result bundle already
|
||||
* has a parent (perhaps because it was returned from a cache) the chain is
|
||||
* complete.
|
||||
*
|
||||
* <p>Otherwise, <code>getBundle</code> examines the remainder of the
|
||||
* candidate locale list that was used during the pass that generated the
|
||||
* result resource bundle. (As before, candidate bundle names where the
|
||||
* final component is an empty string are omitted.) When it comes to the
|
||||
* end of the candidate list, it tries the plain bundle name. With each of the
|
||||
* candidate bundle names it attempts to instantiate a resource bundle (first
|
||||
* looking for a class and then a properties file, as described above).
|
||||
*
|
||||
* <p>Whenever it succeeds, it calls the previously instantiated resource
|
||||
* bundle's {@link #setParent(java.util.ResourceBundle) setParent} method
|
||||
* with the new resource bundle, unless the previously instantiated resource
|
||||
* bundle already has a non-null parent.
|
||||
* with the new resource bundle. This continues until the list of names
|
||||
* is exhausted or the current bundle already has a non-null parent.
|
||||
*
|
||||
* <p>
|
||||
* <code>getBundle</code> caches instantiated resource bundles and
|
||||
* may return the same resource bundle instance multiple
|
||||
* times.
|
||||
* <p>Once the parent chain is complete, the bundle is returned.
|
||||
*
|
||||
* <p>
|
||||
* The <code>baseName</code> argument should be a fully qualified class name. However, for
|
||||
* compatibility with earlier versions, Sun's Java SE Runtime Environments do not verify this,
|
||||
* and so it is possible to access <code>PropertyResourceBundle</code>s by specifying a
|
||||
* path name (using "/") instead of a fully qualified class name (using ".").
|
||||
* <p><b>Note:</b> <code>getBundle</code> caches instantiated resource
|
||||
* bundles and might return the same resource bundle instance multiple times.
|
||||
*
|
||||
* <p><b>Note:</b>The <code>baseName</code> argument should be a fully
|
||||
* qualified class name. However, for compatibility with earlier versions,
|
||||
* Sun's Java SE Runtime Environments do not verify this, and so it is
|
||||
* possible to access <code>PropertyResourceBundle</code>s by specifying a
|
||||
* path name (using "/") instead of a fully qualified class name (using
|
||||
* ".").
|
||||
*
|
||||
* <p><a name="default_behavior_example"/>
|
||||
* <strong>Example:</strong><br>The following class and property files are provided:
|
||||
* <strong>Example:</strong>
|
||||
* <p>
|
||||
* The following class and property files are provided:
|
||||
* <pre>
|
||||
* MyResources.class
|
||||
* MyResources.properties
|
||||
@ -944,22 +999,26 @@ public abstract class ResourceBundle {
|
||||
* MyResources_en.properties
|
||||
* MyResources_es_ES.class
|
||||
* </pre>
|
||||
* The contents of all files are valid (that is, public non-abstract subclasses of <code>ResourceBundle</code> for
|
||||
* the ".class" files, syntactically correct ".properties" files).
|
||||
* The default locale is <code>Locale("en", "GB")</code>.
|
||||
* <p>
|
||||
* Calling <code>getBundle</code> with the shown locale argument values instantiates
|
||||
* resource bundles from the following sources:
|
||||
* <ul>
|
||||
* <li>Locale("fr", "CH"): result MyResources_fr_CH.class, parent MyResources_fr.properties, parent MyResources.class
|
||||
* <li>Locale("fr", "FR"): result MyResources_fr.properties, parent MyResources.class
|
||||
* <li>Locale("de", "DE"): result MyResources_en.properties, parent MyResources.class
|
||||
* <li>Locale("en", "US"): result MyResources_en.properties, parent MyResources.class
|
||||
* <li>Locale("es", "ES"): result MyResources_es_ES.class, parent MyResources.class
|
||||
* </ul>
|
||||
* <p>The file MyResources_fr_CH.properties is never used because it is hidden by
|
||||
* MyResources_fr_CH.class. Likewise, MyResources.properties is also hidden by
|
||||
* MyResources.class.
|
||||
*
|
||||
* The contents of all files are valid (that is, public non-abstract
|
||||
* subclasses of <code>ResourceBundle</code> for the ".class" files,
|
||||
* syntactically correct ".properties" files). The default locale is
|
||||
* <code>Locale("en", "GB")</code>.
|
||||
*
|
||||
* <p>Calling <code>getBundle</code> with the locale arguments below will
|
||||
* instantiate resource bundles as follows:
|
||||
*
|
||||
* <table>
|
||||
* <tr><td>Locale("fr", "CH")</td><td>MyResources_fr_CH.class, parent MyResources_fr.properties, parent MyResources.class</td></tr>
|
||||
* <tr><td>Locale("fr", "FR")</td><td>MyResources_fr.properties, parent MyResources.class</td></tr>
|
||||
* <tr><td>Locale("de", "DE")</td><td>MyResources_en.properties, parent MyResources.class</td></tr>
|
||||
* <tr><td>Locale("en", "US")</td><td>MyResources_en.properties, parent MyResources.class</td></tr>
|
||||
* <tr><td>Locale("es", "ES")</td><td>MyResources_es_ES.class, parent MyResources.class</td></tr>
|
||||
* </table>
|
||||
*
|
||||
* <p>The file MyResources_fr_CH.properties is never used because it is
|
||||
* hidden by the MyResources_fr_CH.class. Likewise, MyResources.properties
|
||||
* is also hidden by MyResources.class.
|
||||
*
|
||||
* @param baseName the base name of the resource bundle, a fully qualified class name
|
||||
* @param locale the locale for which a resource bundle is desired
|
||||
@ -1095,8 +1154,6 @@ public abstract class ResourceBundle {
|
||||
* href="./ResourceBundle.html#parent_chain">parent chain</a> is
|
||||
* instantiated based on the list of candidate locales from which it was
|
||||
* found. Finally, the bundle is returned to the caller.</li>
|
||||
*
|
||||
*
|
||||
* </ol>
|
||||
*
|
||||
* <p>During the resource bundle loading process above, this factory
|
||||
@ -1119,7 +1176,6 @@ public abstract class ResourceBundle {
|
||||
* {@link Control#getTimeToLive(String,Locale)
|
||||
* control.getTimeToLive} for details.
|
||||
*
|
||||
*
|
||||
* <p>The following is an example of the bundle loading process with the
|
||||
* default <code>ResourceBundle.Control</code> implementation.
|
||||
*
|
||||
@ -1131,7 +1187,6 @@ public abstract class ResourceBundle {
|
||||
* <li>Available resource bundles:
|
||||
* <code>foo/bar/Messages_fr.properties</code> and
|
||||
* <code>foo/bar/Messages.properties</code></li>
|
||||
*
|
||||
* </ul>
|
||||
*
|
||||
* <p>First, <code>getBundle</code> tries loading a resource bundle in
|
||||
@ -1811,8 +1866,8 @@ public abstract class ResourceBundle {
|
||||
* handleGetObject} method returns <code>null</code>. Once the
|
||||
* <code>Set</code> has been created, the value is kept in this
|
||||
* <code>ResourceBundle</code> in order to avoid producing the
|
||||
* same <code>Set</code> in the next calls. Override this method
|
||||
* in subclass implementations for faster handling.
|
||||
* same <code>Set</code> in subsequent calls. Subclasses can
|
||||
* override this method for faster handling.
|
||||
*
|
||||
* @return a <code>Set</code> of the keys contained only in this
|
||||
* <code>ResourceBundle</code>
|
||||
@ -2177,24 +2232,133 @@ public abstract class ResourceBundle {
|
||||
* <code>ResourceBundle.getBundle</code> factory method loads only
|
||||
* the base bundle as the resulting resource bundle.
|
||||
*
|
||||
* <p>It is not a requirement to return an immutable
|
||||
* (unmodifiable) <code>List</code>. However, the returned
|
||||
* <code>List</code> must not be mutated after it has been
|
||||
* returned by <code>getCandidateLocales</code>.
|
||||
* <p>It is not a requirement to return an immutable (unmodifiable)
|
||||
* <code>List</code>. However, the returned <code>List</code> must not
|
||||
* be mutated after it has been returned by
|
||||
* <code>getCandidateLocales</code>.
|
||||
*
|
||||
* <p>The default implementation returns a <code>List</code> containing
|
||||
* <code>Locale</code>s in the following sequence:
|
||||
* <pre>
|
||||
* Locale(language, country, variant)
|
||||
* Locale(language, country)
|
||||
* Locale(language)
|
||||
* Locale.ROOT
|
||||
* </pre>
|
||||
* where <code>language</code>, <code>country</code> and
|
||||
* <code>variant</code> are the language, country and variant values
|
||||
* of the given <code>locale</code>, respectively. Locales where the
|
||||
* <code>Locale</code>s using the rules described below. In the
|
||||
* description below, <em>L</em>, <em>S</em>, <em>C</em> and <em>V</em>
|
||||
* respectively represent non-empty language, script, country, and
|
||||
* variant. For example, [<em>L</em>, <em>C</em>] represents a
|
||||
* <code>Locale</code> that has non-empty values only for language and
|
||||
* country. The form <em>L</em>("xx") represents the (non-empty)
|
||||
* language value is "xx". For all cases, <code>Locale</code>s whose
|
||||
* final component values are empty strings are omitted.
|
||||
*
|
||||
* <ol><li>For an input <code>Locale</code> with an empty script value,
|
||||
* append candidate <code>Locale</code>s by omitting the final component
|
||||
* one by one as below:
|
||||
*
|
||||
* <ul>
|
||||
* <li> [<em>L</em>, <em>C</em>, <em>V</em>]
|
||||
* <li> [<em>L</em>, <em>C</em>]
|
||||
* <li> [<em>L</em>]
|
||||
* <li> <code>Locale.ROOT</code>
|
||||
* </ul>
|
||||
*
|
||||
* <li>For an input <code>Locale</code> with a non-empty script value,
|
||||
* append candidate <code>Locale</code>s by omitting the final component
|
||||
* up to language, then append candidates generated from the
|
||||
* <code>Locale</code> with country and variant restored:
|
||||
*
|
||||
* <ul>
|
||||
* <li> [<em>L</em>, <em>S</em>, <em>C</em>, <em>V</em>]
|
||||
* <li> [<em>L</em>, <em>S</em>, <em>C</em>]
|
||||
* <li> [<em>L</em>, <em>S</em>]
|
||||
* <li> [<em>L</em>, <em>C</em>, <em>V</em>]
|
||||
* <li> [<em>L</em>, <em>C</em>]
|
||||
* <li> [<em>L</em>]
|
||||
* <li> <code>Locale.ROOT</code>
|
||||
* </ul>
|
||||
*
|
||||
* <li>For an input <code>Locale</code> with a variant value consisting
|
||||
* of multiple subtags separated by underscore, generate candidate
|
||||
* <code>Locale</code>s by omitting the variant subtags one by one, then
|
||||
* insert them after every occurence of <code> Locale</code>s with the
|
||||
* full variant value in the original list. For example, if the
|
||||
* the variant consists of two subtags <em>V1</em> and <em>V2</em>:
|
||||
*
|
||||
* <ul>
|
||||
* <li> [<em>L</em>, <em>S</em>, <em>C</em>, <em>V1</em>, <em>V2</em>]
|
||||
* <li> [<em>L</em>, <em>S</em>, <em>C</em>, <em>V1</em>]
|
||||
* <li> [<em>L</em>, <em>S</em>, <em>C</em>]
|
||||
* <li> [<em>L</em>, <em>S</em>]
|
||||
* <li> [<em>L</em>, <em>C</em>, <em>V1</em>, <em>V2</em>]
|
||||
* <li> [<em>L</em>, <em>C</em>, <em>V1</em>]
|
||||
* <li> [<em>L</em>, <em>C</em>]
|
||||
* <li> [<em>L</em>]
|
||||
* <li> <code>Locale.ROOT</code>
|
||||
* </ul>
|
||||
*
|
||||
* <li>Special cases for Chinese. When an input <code>Locale</code> has the
|
||||
* language "zh" (Chinese) and an empty script value, either "Hans" (Simplified) or
|
||||
* "Hant" (Traditional) might be supplied, depending on the country.
|
||||
* When the country is "CN" (China) or "SG" (Singapore), "Hans" is supplied.
|
||||
* When the country is "HK" (Hong Kong SAR China), "MO" (Macau SAR China),
|
||||
* or "TW" (Taiwan), "Hant" is supplied. For all other countries or when the country
|
||||
* is empty, no script is supplied. For example, for <code>Locale("zh", "CN")
|
||||
* </code>, the candidate list will be:
|
||||
* <ul>
|
||||
* <li> [<em>L</em>("zh"), <em>S</em>("Hans"), <em>C</em>("CN")]
|
||||
* <li> [<em>L</em>("zh"), <em>S</em>("Hans")]
|
||||
* <li> [<em>L</em>("zh"), <em>C</em>("CN")]
|
||||
* <li> [<em>L</em>("zh")]
|
||||
* <li> <code>Locale.ROOT</code>
|
||||
* </ul>
|
||||
*
|
||||
* For <code>Locale("zh", "TW")</code>, the candidate list will be:
|
||||
* <ul>
|
||||
* <li> [<em>L</em>("zh"), <em>S</em>("Hant"), <em>C</em>("TW")]
|
||||
* <li> [<em>L</em>("zh"), <em>S</em>("Hant")]
|
||||
* <li> [<em>L</em>("zh"), <em>C</em>("TW")]
|
||||
* <li> [<em>L</em>("zh")]
|
||||
* <li> <code>Locale.ROOT</code>
|
||||
* </ul>
|
||||
*
|
||||
* <li>Special cases for Norwegian. Both <code>Locale("no", "NO",
|
||||
* "NY")</code> and <code>Locale("nn", "NO")</code> represent Norwegian
|
||||
* Nynorsk. When a locale's language is "nn", the standard candidate
|
||||
* list is generated up to [<em>L</em>("nn")], and then the following
|
||||
* candidates are added:
|
||||
*
|
||||
* <ul><li> [<em>L</em>("no"), <em>C</em>("NO"), <em>V</em>("NY")]
|
||||
* <li> [<em>L</em>("no"), <em>C</em>("NO")]
|
||||
* <li> [<em>L</em>("no")]
|
||||
* <li> <code>Locale.ROOT</code>
|
||||
* </ul>
|
||||
*
|
||||
* If the locale is exactly <code>Locale("no", "NO", "NY")</code>, it is first
|
||||
* converted to <code>Locale("nn", "NO")</code> and then the above procedure is
|
||||
* followed.
|
||||
*
|
||||
* <p>Also, Java treats the language "no" as a synonym of Norwegian
|
||||
* Bokmål "nb". Except for the single case <code>Locale("no",
|
||||
* "NO", "NY")</code> (handled above), when an input <code>Locale</code>
|
||||
* has language "no" or "nb", candidate <code>Locale</code>s with
|
||||
* language code "no" and "nb" are interleaved, first using the
|
||||
* requested language, then using its synonym. For example,
|
||||
* <code>Locale("nb", "NO", "POSIX")</code> generates the following
|
||||
* candidate list:
|
||||
*
|
||||
* <ul>
|
||||
* <li> [<em>L</em>("nb"), <em>C</em>("NO"), <em>V</em>("POSIX")]
|
||||
* <li> [<em>L</em>("no"), <em>C</em>("NO"), <em>V</em>("POSIX")]
|
||||
* <li> [<em>L</em>("nb"), <em>C</em>("NO")]
|
||||
* <li> [<em>L</em>("no"), <em>C</em>("NO")]
|
||||
* <li> [<em>L</em>("nb")]
|
||||
* <li> [<em>L</em>("no")]
|
||||
* <li> <code>Locale.ROOT</code>
|
||||
* </ul>
|
||||
*
|
||||
* <code>Locale("no", "NO", "POSIX")</code> would generate the same list
|
||||
* except that locales with "no" would appear before the corresponding
|
||||
* locales with "nb".</li>
|
||||
*
|
||||
* </li>
|
||||
* </ol>
|
||||
*
|
||||
* <p>The default implementation uses an {@link ArrayList} that
|
||||
* overriding implementations may modify before returning it to the
|
||||
* caller. However, a subclass must not modify it after it has
|
||||
@ -2231,24 +2395,119 @@ public abstract class ResourceBundle {
|
||||
if (baseName == null) {
|
||||
throw new NullPointerException();
|
||||
}
|
||||
String language = locale.getLanguage();
|
||||
String country = locale.getCountry();
|
||||
String variant = locale.getVariant();
|
||||
return new ArrayList<Locale>(CANDIDATES_CACHE.get(locale.getBaseLocale()));
|
||||
}
|
||||
|
||||
List<Locale> locales = new ArrayList<Locale>(4);
|
||||
if (variant.length() > 0) {
|
||||
locales.add(locale);
|
||||
private static final CandidateListCache CANDIDATES_CACHE = new CandidateListCache();
|
||||
|
||||
private static class CandidateListCache extends LocaleObjectCache<BaseLocale, List<Locale>> {
|
||||
protected List<Locale> createObject(BaseLocale base) {
|
||||
String language = base.getLanguage();
|
||||
String script = base.getScript();
|
||||
String region = base.getRegion();
|
||||
String variant = base.getVariant();
|
||||
|
||||
// Special handling for Norwegian
|
||||
boolean isNorwegianBokmal = false;
|
||||
boolean isNorwegianNynorsk = false;
|
||||
if (language.equals("no")) {
|
||||
if (region.equals("NO") && variant.equals("NY")) {
|
||||
variant = "";
|
||||
isNorwegianNynorsk = true;
|
||||
} else {
|
||||
isNorwegianBokmal = true;
|
||||
}
|
||||
}
|
||||
if (language.equals("nb") || isNorwegianBokmal) {
|
||||
List<Locale> tmpList = getDefaultList("nb", script, region, variant);
|
||||
// Insert a locale replacing "nb" with "no" for every list entry
|
||||
List<Locale> bokmalList = new LinkedList<Locale>();
|
||||
for (Locale l : tmpList) {
|
||||
bokmalList.add(l);
|
||||
if (l.getLanguage().length() == 0) {
|
||||
break;
|
||||
}
|
||||
bokmalList.add(Locale.getInstance("no", l.getScript(), l.getCountry(),
|
||||
l.getVariant(), LocaleExtensions.EMPTY_EXTENSIONS));
|
||||
}
|
||||
return bokmalList;
|
||||
} else if (language.equals("nn") || isNorwegianNynorsk) {
|
||||
// Insert no_NO_NY, no_NO, no after nn
|
||||
List<Locale> nynorskList = getDefaultList("nn", script, region, variant);
|
||||
int idx = nynorskList.size() - 1;
|
||||
nynorskList.add(idx++, Locale.getInstance("no", "NO", "NY"));
|
||||
nynorskList.add(idx++, Locale.getInstance("no", "NO", ""));
|
||||
nynorskList.add(idx++, Locale.getInstance("no", "", ""));
|
||||
return nynorskList;
|
||||
}
|
||||
// Special handling for Chinese
|
||||
else if (language.equals("zh")) {
|
||||
if (script.length() == 0 && region.length() > 0) {
|
||||
// Supply script for users who want to use zh_Hans/zh_Hant
|
||||
// as bundle names (recommended for Java7+)
|
||||
if (region.equals("TW") || region.equals("HK") || region.equals("MO")) {
|
||||
script = "Hant";
|
||||
} else if (region.equals("CN") || region.equals("SG")) {
|
||||
script = "Hans";
|
||||
}
|
||||
} else if (script.length() > 0 && region.length() == 0) {
|
||||
// Supply region(country) for users who still package Chinese
|
||||
// bundles using old convension.
|
||||
if (script.equals("Hans")) {
|
||||
region = "CN";
|
||||
} else if (script.equals("Hant")) {
|
||||
region = "TW";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return getDefaultList(language, script, region, variant);
|
||||
}
|
||||
if (country.length() > 0) {
|
||||
locales.add((locales.size() == 0) ?
|
||||
locale : Locale.getInstance(language, country, ""));
|
||||
|
||||
private static List<Locale> getDefaultList(String language, String script, String region, String variant) {
|
||||
List<String> variants = null;
|
||||
|
||||
if (variant.length() > 0) {
|
||||
variants = new LinkedList<String>();
|
||||
int idx = variant.length();
|
||||
while (idx != -1) {
|
||||
variants.add(variant.substring(0, idx));
|
||||
idx = variant.lastIndexOf('_', --idx);
|
||||
}
|
||||
}
|
||||
|
||||
LinkedList<Locale> list = new LinkedList<Locale>();
|
||||
|
||||
if (variants != null) {
|
||||
for (String v : variants) {
|
||||
list.add(Locale.getInstance(language, script, region, v, LocaleExtensions.EMPTY_EXTENSIONS));
|
||||
}
|
||||
}
|
||||
if (region.length() > 0) {
|
||||
list.add(Locale.getInstance(language, script, region, "", LocaleExtensions.EMPTY_EXTENSIONS));
|
||||
}
|
||||
if (script.length() > 0) {
|
||||
list.add(Locale.getInstance(language, script, "", "", LocaleExtensions.EMPTY_EXTENSIONS));
|
||||
|
||||
// With script, after truncating variant, region and script,
|
||||
// start over without script.
|
||||
if (variants != null) {
|
||||
for (String v : variants) {
|
||||
list.add(Locale.getInstance(language, "", region, v, LocaleExtensions.EMPTY_EXTENSIONS));
|
||||
}
|
||||
}
|
||||
if (region.length() > 0) {
|
||||
list.add(Locale.getInstance(language, "", region, "", LocaleExtensions.EMPTY_EXTENSIONS));
|
||||
}
|
||||
}
|
||||
if (language.length() > 0) {
|
||||
list.add(Locale.getInstance(language, "", "", "", LocaleExtensions.EMPTY_EXTENSIONS));
|
||||
}
|
||||
// Add root locale at the end
|
||||
list.add(Locale.ROOT);
|
||||
|
||||
return list;
|
||||
}
|
||||
if (language.length() > 0) {
|
||||
locales.add((locales.size() == 0) ?
|
||||
locale : Locale.getInstance(language, "", ""));
|
||||
}
|
||||
locales.add(Locale.ROOT);
|
||||
return locales;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -2606,13 +2865,14 @@ public abstract class ResourceBundle {
|
||||
*
|
||||
* <p>This implementation returns the following value:
|
||||
* <pre>
|
||||
* baseName + "_" + language + "_" + country + "_" + variant
|
||||
* baseName + "_" + language + "_" + script + "_" + country + "_" + variant
|
||||
* </pre>
|
||||
* where <code>language</code>, <code>country</code> and
|
||||
* <code>variant</code> are the language, country and variant values
|
||||
* of <code>locale</code>, respectively. Final component values that
|
||||
* are empty Strings are omitted along with the preceding '_'. If
|
||||
* all of the values are empty strings, then <code>baseName</code>
|
||||
* where <code>language</code>, <code>script</code>, <code>country</code>,
|
||||
* and <code>variant</code> are the language, script, country, and variant
|
||||
* values of <code>locale</code>, respectively. Final component values that
|
||||
* are empty Strings are omitted along with the preceding '_'. When the
|
||||
* script is empty, the script value is ommitted along with the preceding '_'.
|
||||
* If all of the values are empty strings, then <code>baseName</code>
|
||||
* is returned.
|
||||
*
|
||||
* <p>For example, if <code>baseName</code> is
|
||||
@ -2643,6 +2903,7 @@ public abstract class ResourceBundle {
|
||||
}
|
||||
|
||||
String language = locale.getLanguage();
|
||||
String script = locale.getScript();
|
||||
String country = locale.getCountry();
|
||||
String variant = locale.getVariant();
|
||||
|
||||
@ -2652,12 +2913,22 @@ public abstract class ResourceBundle {
|
||||
|
||||
StringBuilder sb = new StringBuilder(baseName);
|
||||
sb.append('_');
|
||||
if (variant != "") {
|
||||
sb.append(language).append('_').append(country).append('_').append(variant);
|
||||
} else if (country != "") {
|
||||
sb.append(language).append('_').append(country);
|
||||
if (script != "") {
|
||||
if (variant != "") {
|
||||
sb.append(language).append('_').append(script).append('_').append(country).append('_').append(variant);
|
||||
} else if (country != "") {
|
||||
sb.append(language).append('_').append(script).append('_').append(country);
|
||||
} else {
|
||||
sb.append(language).append('_').append(script);
|
||||
}
|
||||
} else {
|
||||
sb.append(language);
|
||||
if (variant != "") {
|
||||
sb.append(language).append('_').append(country).append('_').append(variant);
|
||||
} else if (country != "") {
|
||||
sb.append(language).append('_').append(country);
|
||||
} else {
|
||||
sb.append(language);
|
||||
}
|
||||
}
|
||||
return sb.toString();
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2005, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2005, 2010, 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
|
||||
@ -44,22 +44,23 @@ public abstract class LocaleNameProvider extends LocaleServiceProvider {
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a localized name for the given ISO 639 language code and the
|
||||
* given locale that is appropriate for display to the user.
|
||||
* Returns a localized name for the given <a href="http://www.rfc-editor.org/rfc/bcp/bcp47.txt">
|
||||
* IETF BCP47</a> language code and the given locale that is appropriate for
|
||||
* display to the user.
|
||||
* For example, if <code>languageCode</code> is "fr" and <code>locale</code>
|
||||
* is en_US, getDisplayLanguage() will return "French"; if <code>languageCode</code>
|
||||
* is "en" and <code>locale</code> is fr_FR, getDisplayLanguage() will return "anglais".
|
||||
* If the name returned cannot be localized according to <code>locale</code>,
|
||||
* (say, the provider does not have a Japanese name for Croatian),
|
||||
* this method returns null.
|
||||
* @param languageCode the ISO 639 language code string in the form of two
|
||||
* @param languageCode the language code string in the form of two to eight
|
||||
* lower-case letters between 'a' (U+0061) and 'z' (U+007A)
|
||||
* @param locale the desired locale
|
||||
* @return the name of the given language code for the specified locale, or null if it's not
|
||||
* available.
|
||||
* @exception NullPointerException if <code>languageCode</code> or <code>locale</code> is null
|
||||
* @exception IllegalArgumentException if <code>languageCode</code> is not in the form of
|
||||
* two lower-case letters, or <code>locale</code> isn't
|
||||
* two or three lower-case letters, or <code>locale</code> isn't
|
||||
* one of the locales returned from
|
||||
* {@link java.util.spi.LocaleServiceProvider#getAvailableLocales()
|
||||
* getAvailableLocales()}.
|
||||
@ -68,22 +69,52 @@ public abstract class LocaleNameProvider extends LocaleServiceProvider {
|
||||
public abstract String getDisplayLanguage(String languageCode, Locale locale);
|
||||
|
||||
/**
|
||||
* Returns a localized name for the given ISO 3166 country code and the
|
||||
* given locale that is appropriate for display to the user.
|
||||
* Returns a localized name for the given <a href="http://www.rfc-editor.org/rfc/bcp/bcp47.txt">
|
||||
* IETF BCP47</a> script code and the given locale that is appropriate for
|
||||
* display to the user.
|
||||
* For example, if <code>scriptCode</code> is "Latn" and <code>locale</code>
|
||||
* is en_US, getDisplayScript() will return "Latin"; if <code>scriptCode</code>
|
||||
* is "Cyrl" and <code>locale</code> is fr_FR, getDisplayScript() will return "cyrillique".
|
||||
* If the name returned cannot be localized according to <code>locale</code>,
|
||||
* (say, the provider does not have a Japanese name for Cyrillic),
|
||||
* this method returns null.
|
||||
* @param scriptCode the four letter script code string in the form of title-case
|
||||
* letters (the first letter is upper-case character between 'A' (U+0041) and
|
||||
* 'Z' (U+005A) followed by three lower-case character between 'a' (U+0061)
|
||||
* and 'z' (U+007A)).
|
||||
* @param locale the desired locale
|
||||
* @return the name of the given script code for the specified locale, or null if it's not
|
||||
* available.
|
||||
* @exception NullPointerException if <code>scriptCode</code> or <code>locale</code> is null
|
||||
* @exception IllegalArgumentException if <code>scriptCode</code> is not in the form of
|
||||
* four title case letters, or <code>locale</code> isn't
|
||||
* one of the locales returned from
|
||||
* {@link java.util.spi.LocaleServiceProvider#getAvailableLocales()
|
||||
* getAvailableLocales()}.
|
||||
* @see java.util.Locale#getDisplayScript(java.util.Locale)
|
||||
* @since 1.7
|
||||
*/
|
||||
public abstract String getDisplayScript(String scriptCode, Locale locale);
|
||||
|
||||
/**
|
||||
* Returns a localized name for the given <a href="http://www.rfc-editor.org/rfc/bcp/bcp47.txt">
|
||||
* IETF BCP47</a> region code (either ISO 3166 country code or UN M.49 area
|
||||
* codes) and the given locale that is appropriate for display to the user.
|
||||
* For example, if <code>countryCode</code> is "FR" and <code>locale</code>
|
||||
* is en_US, getDisplayCountry() will return "France"; if <code>countryCode</code>
|
||||
* is "US" and <code>locale</code> is fr_FR, getDisplayCountry() will return "Etats-Unis".
|
||||
* If the name returned cannot be localized according to <code>locale</code>,
|
||||
* (say, the provider does not have a Japanese name for Croatia),
|
||||
* this method returns null.
|
||||
* @param countryCode the ISO 3166 country code string in the form of two
|
||||
* upper-case letters between 'A' (U+0041) and 'Z' (U+005A)
|
||||
* @param countryCode the country(region) code string in the form of two
|
||||
* upper-case letters between 'A' (U+0041) and 'Z' (U+005A) or the UN M.49 area code
|
||||
* in the form of three digit letters between '0' (U+0030) and '9' (U+0039).
|
||||
* @param locale the desired locale
|
||||
* @return the name of the given country code for the specified locale, or null if it's not
|
||||
* available.
|
||||
* @exception NullPointerException if <code>countryCode</code> or <code>locale</code> is null
|
||||
* @exception IllegalArgumentException if <code>countryCode</code> is not in the form of
|
||||
* two upper-case letters, or <code>locale</code> isn't
|
||||
* two upper-case letters or three digit letters, or <code>locale</code> isn't
|
||||
* one of the locales returned from
|
||||
* {@link java.util.spi.LocaleServiceProvider#getAvailableLocales()
|
||||
* getAvailableLocales()}.
|
||||
|
@ -86,18 +86,19 @@ import java.util.Locale;
|
||||
* Otherwise, they call the <code>getAvailableLocales()</code> methods of
|
||||
* installed providers for the appropriate interface to find one that
|
||||
* supports the requested locale. If such a provider is found, its other
|
||||
* methods are called to obtain the requested object or name. If neither
|
||||
* the Java runtime environment itself nor an installed provider supports
|
||||
* the requested locale, a fallback locale is constructed by replacing the
|
||||
* first of the variant, country, or language strings of the locale that's
|
||||
* not an empty string with an empty string, and the lookup process is
|
||||
* restarted. In the case that the variant contains one or more '_'s, the
|
||||
* fallback locale is constructed by replacing the variant with a new variant
|
||||
* which eliminates the last '_' and the part following it. Even if a
|
||||
* fallback occurs, methods that return requested objects or name are
|
||||
* invoked with the original locale before the fallback.The Java runtime
|
||||
* environment must support the root locale for all locale sensitive services
|
||||
* in order to guarantee that this process terminates.
|
||||
* methods are called to obtain the requested object or name. When checking
|
||||
* whether a locale is supported, the locale's extensions are ignored.
|
||||
* If neither the Java runtime environment itself nor an installed provider
|
||||
* supports the requested locale, the methods go through a list of candidate
|
||||
* locales and repeat the availability check for each until a match is found.
|
||||
* The algorithm used for creating a list of candidate locales is same as
|
||||
* the one used by <code>ResourceBunlde</code> by default (see
|
||||
* {@link java.util.ResourceBundle.Control#getCandidateLocales getCandidateLocales}
|
||||
* for the details). Even if a locale is resolved from the candidate list,
|
||||
* methods that return requested objects or names are invoked with the original
|
||||
* requested locale including extensions. The Java runtime environment must
|
||||
* support the root locale for all locale sensitive services in order to
|
||||
* guarantee that this process terminates.
|
||||
* <p>
|
||||
* Providers of names (but not providers of other objects) are allowed to
|
||||
* return null for some name requests even for locales that they claim to
|
||||
@ -124,6 +125,11 @@ public abstract class LocaleServiceProvider {
|
||||
/**
|
||||
* Returns an array of all locales for which this locale service provider
|
||||
* can provide localized objects or names.
|
||||
* <p>
|
||||
* <b>Note:</b> Extensions in a <code>Locale</code> are ignored during
|
||||
* service provider lookup. So the array returned by this method should
|
||||
* not include two or more <code>Locale</code> objects only differing in
|
||||
* their extensions.
|
||||
*
|
||||
* @return An array of all locales for which this locale service provider
|
||||
* can provide localized objects or names.
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2005, 2006, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2005, 2010, 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
|
||||
@ -28,18 +28,20 @@ package sun.util;
|
||||
import java.security.AccessController;
|
||||
import java.security.PrivilegedActionException;
|
||||
import java.security.PrivilegedExceptionAction;
|
||||
import java.util.Arrays;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
import java.util.IllformedLocaleException;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Locale.Builder;
|
||||
import java.util.Map;
|
||||
import java.util.ResourceBundle.Control;
|
||||
import java.util.ServiceLoader;
|
||||
import java.util.ServiceConfigurationError;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.spi.LocaleServiceProvider;
|
||||
|
||||
import sun.util.logging.PlatformLogger;
|
||||
import sun.util.resources.LocaleData;
|
||||
import sun.util.resources.OpenListResourceBundle;
|
||||
@ -89,6 +91,16 @@ public final class LocaleServiceProviderPool {
|
||||
*/
|
||||
private Set<Locale> providerLocales = null;
|
||||
|
||||
/**
|
||||
* Special locale for ja_JP with Japanese calendar
|
||||
*/
|
||||
private static Locale locale_ja_JP_JP = new Locale("ja", "JP", "JP");
|
||||
|
||||
/**
|
||||
* Special locale for th_TH with Thai numbering system
|
||||
*/
|
||||
private static Locale locale_th_TH_TH = new Locale("th", "TH", "TH");
|
||||
|
||||
/**
|
||||
* A factory method that returns a singleton instance
|
||||
*/
|
||||
@ -153,14 +165,20 @@ public final class LocaleServiceProviderPool {
|
||||
java.util.spi.CurrencyNameProvider.class,
|
||||
java.util.spi.LocaleNameProvider.class,
|
||||
java.util.spi.TimeZoneNameProvider.class };
|
||||
Set<Locale> all = new HashSet<Locale>(Arrays.asList(
|
||||
LocaleData.getAvailableLocales())
|
||||
);
|
||||
|
||||
// Normalize locales for look up
|
||||
Locale[] allLocales = LocaleData.getAvailableLocales();
|
||||
Set<Locale> all = new HashSet<Locale>(allLocales.length);
|
||||
for (Locale locale : allLocales) {
|
||||
all.add(getLookupLocale(locale));
|
||||
}
|
||||
|
||||
for (Class providerClass : providerClasses) {
|
||||
LocaleServiceProviderPool pool =
|
||||
LocaleServiceProviderPool.getPool(providerClass);
|
||||
all.addAll(pool.getProviderLocales());
|
||||
}
|
||||
|
||||
allAvailableLocales = all.toArray(new Locale[0]);
|
||||
}
|
||||
}
|
||||
@ -196,7 +214,8 @@ public final class LocaleServiceProviderPool {
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an array of available locales from providers.
|
||||
* Returns an array of available locales (already normalized
|
||||
* for service lookup) from providers.
|
||||
* Note that this method does not return a defensive copy.
|
||||
*
|
||||
* @return list of the provider locales
|
||||
@ -208,7 +227,7 @@ public final class LocaleServiceProviderPool {
|
||||
for (LocaleServiceProvider lsp : providers) {
|
||||
Locale[] locales = lsp.getAvailableLocales();
|
||||
for (Locale locale: locales) {
|
||||
providerLocales.add(locale);
|
||||
providerLocales.add(getLookupLocale(locale));
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -227,15 +246,19 @@ public final class LocaleServiceProviderPool {
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an array of available locales supported by the JRE.
|
||||
* Returns an array of available locales (already normalized for
|
||||
* service lookup) supported by the JRE.
|
||||
* Note that this method does not return a defensive copy.
|
||||
*
|
||||
* @return list of the available JRE locales
|
||||
*/
|
||||
private synchronized List<Locale> getJRELocales() {
|
||||
if (availableJRELocales == null) {
|
||||
availableJRELocales =
|
||||
Arrays.asList(LocaleData.getAvailableLocales());
|
||||
Locale[] allLocales = LocaleData.getAvailableLocales();
|
||||
availableJRELocales = new ArrayList<Locale>(allLocales.length);
|
||||
for (Locale locale : allLocales) {
|
||||
availableJRELocales.add(getLookupLocale(locale));
|
||||
}
|
||||
}
|
||||
return availableJRELocales;
|
||||
}
|
||||
@ -249,7 +272,7 @@ public final class LocaleServiceProviderPool {
|
||||
*/
|
||||
private boolean isJRESupported(Locale locale) {
|
||||
List<Locale> locales = getJRELocales();
|
||||
return locales.contains(locale);
|
||||
return locales.contains(getLookupLocale(locale));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -325,7 +348,7 @@ public final class LocaleServiceProviderPool {
|
||||
bundleKey = key;
|
||||
}
|
||||
Locale bundleLocale = (bundle != null ? bundle.getLocale() : null);
|
||||
Locale requested = locale;
|
||||
List<Locale> lookupLocales = getLookupLocales(locale);
|
||||
P lsp;
|
||||
S providersObj = null;
|
||||
|
||||
@ -333,21 +356,30 @@ public final class LocaleServiceProviderPool {
|
||||
// to the requested locale than the bundle we've found (for
|
||||
// localized names), or Java runtime's supported locale
|
||||
// (for localized objects)
|
||||
while ((locale = findProviderLocale(locale, bundleLocale)) != null) {
|
||||
|
||||
lsp = (P)findProvider(locale);
|
||||
|
||||
if (lsp != null) {
|
||||
providersObj = getter.getObject(lsp, requested, key, params);
|
||||
if (providersObj != null) {
|
||||
return providersObj;
|
||||
} else if (isObjectProvider) {
|
||||
config(
|
||||
"A locale sensitive service provider returned null for a localized objects, which should not happen. provider: " + lsp + " locale: " + requested);
|
||||
Set<Locale> provLoc = getProviderLocales();
|
||||
for (int i = 0; i < lookupLocales.size(); i++) {
|
||||
Locale current = lookupLocales.get(i);
|
||||
if (bundleLocale != null) {
|
||||
if (current.equals(bundleLocale)) {
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
if (isJRESupported(current)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (provLoc.contains(current)) {
|
||||
lsp = (P)findProvider(current);
|
||||
if (lsp != null) {
|
||||
providersObj = getter.getObject(lsp, locale, key, params);
|
||||
if (providersObj != null) {
|
||||
return providersObj;
|
||||
} else if (isObjectProvider) {
|
||||
config(
|
||||
"A locale sensitive service provider returned null for a localized objects, which should not happen. provider: " + lsp + " locale: " + locale);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
locale = getParentLocale(locale);
|
||||
}
|
||||
|
||||
// look up the JRE bundle and its parent chain. Only
|
||||
@ -361,7 +393,7 @@ public final class LocaleServiceProviderPool {
|
||||
} else {
|
||||
lsp = (P)findProvider(bundleLocale);
|
||||
if (lsp != null) {
|
||||
providersObj = getter.getObject(lsp, requested, key, params);
|
||||
providersObj = getter.getObject(lsp, locale, key, params);
|
||||
if (providersObj != null) {
|
||||
return providersObj;
|
||||
}
|
||||
@ -399,6 +431,8 @@ public final class LocaleServiceProviderPool {
|
||||
for (LocaleServiceProvider lsp : providers) {
|
||||
Locale[] locales = lsp.getAvailableLocales();
|
||||
for (Locale available: locales) {
|
||||
// normalize
|
||||
available = getLookupLocale(available);
|
||||
if (locale.equals(available)) {
|
||||
LocaleServiceProvider providerInCache =
|
||||
providersCache.put(locale, lsp);
|
||||
@ -414,66 +448,51 @@ public final class LocaleServiceProviderPool {
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the provider's locale that is the most appropriate
|
||||
* within the range
|
||||
*
|
||||
* @param start the given locale that is used as the starting one
|
||||
* @param end the given locale that is used as the end one (exclusive),
|
||||
* or null if it reaching any of the JRE supported locale should
|
||||
* terminate the look up.
|
||||
* @return the most specific locale within the range, or null
|
||||
* if no provider locale found in that range.
|
||||
* Returns a list of candidate locales for service look up.
|
||||
* @param locale the input locale
|
||||
* @return the list of candiate locales for the given locale
|
||||
*/
|
||||
private Locale findProviderLocale(Locale start, Locale end) {
|
||||
Set<Locale> provLoc = getProviderLocales();
|
||||
Locale current = start;
|
||||
|
||||
while (current != null) {
|
||||
if (end != null) {
|
||||
if (current.equals(end)) {
|
||||
current = null;
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
if (isJRESupported(current)) {
|
||||
current = null;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (provLoc.contains(current)) {
|
||||
break;
|
||||
}
|
||||
|
||||
current = getParentLocale(current);
|
||||
}
|
||||
|
||||
return current;
|
||||
private static List<Locale> getLookupLocales(Locale locale) {
|
||||
// Note: We currently use the default implementation of
|
||||
// ResourceBundle.Control.getCandidateLocales. The result
|
||||
// returned by getCandidateLocales are already normalized
|
||||
// (no extensions) for service look up.
|
||||
List<Locale> lookupLocales = new Control(){}.getCandidateLocales("", locale);
|
||||
return lookupLocales;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the parent locale.
|
||||
* Returns an instance of Locale used for service look up.
|
||||
* The result Locale has no extensions except for ja_JP_JP
|
||||
* and th_TH_TH
|
||||
*
|
||||
* @param locale the locale
|
||||
* @return the parent locale
|
||||
* @return the locale used for service look up
|
||||
*/
|
||||
private static Locale getParentLocale(Locale locale) {
|
||||
String variant = locale.getVariant();
|
||||
if (variant != "") {
|
||||
int underscoreIndex = variant.lastIndexOf('_');
|
||||
if (underscoreIndex != (-1)) {
|
||||
return new Locale(locale.getLanguage(), locale.getCountry(),
|
||||
variant.substring(0, underscoreIndex));
|
||||
} else {
|
||||
return new Locale(locale.getLanguage(), locale.getCountry());
|
||||
private static Locale getLookupLocale(Locale locale) {
|
||||
Locale lookupLocale = locale;
|
||||
Set<Character> extensions = locale.getExtensionKeys();
|
||||
if (!extensions.isEmpty()
|
||||
&& !locale.equals(locale_ja_JP_JP)
|
||||
&& !locale.equals(locale_th_TH_TH)) {
|
||||
// remove extensions
|
||||
Builder locbld = new Builder();
|
||||
try {
|
||||
locbld.setLocale(locale);
|
||||
locbld.clearExtensions();
|
||||
lookupLocale = locbld.build();
|
||||
} catch (IllformedLocaleException e) {
|
||||
// A Locale with non-empty extensions
|
||||
// should have well-formed fields except
|
||||
// for ja_JP_JP and th_TH_TH. Therefore,
|
||||
// it should never enter in this catch clause.
|
||||
config("A locale(" + locale + ") has non-empty extensions, but has illformed fields.");
|
||||
|
||||
// Fallback - script field will be lost.
|
||||
lookupLocale = new Locale(locale.getLanguage(), locale.getCountry(), locale.getVariant());
|
||||
}
|
||||
} else if (locale.getCountry() != "") {
|
||||
return new Locale(locale.getLanguage());
|
||||
} else if (locale.getLanguage() != "") {
|
||||
return Locale.ROOT;
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
return lookupLocale;
|
||||
}
|
||||
|
||||
/**
|
||||
|
208
jdk/src/share/classes/sun/util/locale/AsciiUtil.java
Normal file
208
jdk/src/share/classes/sun/util/locale/AsciiUtil.java
Normal file
@ -0,0 +1,208 @@
|
||||
/*
|
||||
* Copyright (c) 2010, 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
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
/*
|
||||
*******************************************************************************
|
||||
* Copyright (C) 2009, International Business Machines Corporation and *
|
||||
* others. All Rights Reserved. *
|
||||
*******************************************************************************
|
||||
*/
|
||||
package sun.util.locale;
|
||||
|
||||
public final class AsciiUtil {
|
||||
public static boolean caseIgnoreMatch(String s1, String s2) {
|
||||
if (s1 == s2) {
|
||||
return true;
|
||||
}
|
||||
int len = s1.length();
|
||||
if (len != s2.length()) {
|
||||
return false;
|
||||
}
|
||||
int i = 0;
|
||||
while (i < len) {
|
||||
char c1 = s1.charAt(i);
|
||||
char c2 = s2.charAt(i);
|
||||
if (c1 != c2 && toLower(c1) != toLower(c2)) {
|
||||
break;
|
||||
}
|
||||
i++;
|
||||
}
|
||||
return (i == len);
|
||||
}
|
||||
|
||||
public static int caseIgnoreCompare(String s1, String s2) {
|
||||
if (s1 == s2) {
|
||||
return 0;
|
||||
}
|
||||
return AsciiUtil.toLowerString(s1).compareTo(AsciiUtil.toLowerString(s2));
|
||||
}
|
||||
|
||||
|
||||
public static char toUpper(char c) {
|
||||
if (c >= 'a' && c <= 'z') {
|
||||
c -= 0x20;
|
||||
}
|
||||
return c;
|
||||
}
|
||||
|
||||
public static char toLower(char c) {
|
||||
if (c >= 'A' && c <= 'Z') {
|
||||
c += 0x20;
|
||||
}
|
||||
return c;
|
||||
}
|
||||
|
||||
public static String toLowerString(String s) {
|
||||
int idx = 0;
|
||||
for (; idx < s.length(); idx++) {
|
||||
char c = s.charAt(idx);
|
||||
if (c >= 'A' && c <= 'Z') {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (idx == s.length()) {
|
||||
return s;
|
||||
}
|
||||
StringBuilder buf = new StringBuilder(s.substring(0, idx));
|
||||
for (; idx < s.length(); idx++) {
|
||||
buf.append(toLower(s.charAt(idx)));
|
||||
}
|
||||
return buf.toString();
|
||||
}
|
||||
|
||||
public static String toUpperString(String s) {
|
||||
int idx = 0;
|
||||
for (; idx < s.length(); idx++) {
|
||||
char c = s.charAt(idx);
|
||||
if (c >= 'a' && c <= 'z') {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (idx == s.length()) {
|
||||
return s;
|
||||
}
|
||||
StringBuilder buf = new StringBuilder(s.substring(0, idx));
|
||||
for (; idx < s.length(); idx++) {
|
||||
buf.append(toUpper(s.charAt(idx)));
|
||||
}
|
||||
return buf.toString();
|
||||
}
|
||||
|
||||
public static String toTitleString(String s) {
|
||||
if (s.length() == 0) {
|
||||
return s;
|
||||
}
|
||||
int idx = 0;
|
||||
char c = s.charAt(idx);
|
||||
if (!(c >= 'a' && c <= 'z')) {
|
||||
for (idx = 1; idx < s.length(); idx++) {
|
||||
if (c >= 'A' && c <= 'Z') {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (idx == s.length()) {
|
||||
return s;
|
||||
}
|
||||
StringBuilder buf = new StringBuilder(s.substring(0, idx));
|
||||
if (idx == 0) {
|
||||
buf.append(toUpper(s.charAt(idx)));
|
||||
idx++;
|
||||
}
|
||||
for (; idx < s.length(); idx++) {
|
||||
buf.append(toLower(s.charAt(idx)));
|
||||
}
|
||||
return buf.toString();
|
||||
}
|
||||
|
||||
public static boolean isAlpha(char c) {
|
||||
return (c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z');
|
||||
}
|
||||
|
||||
public static boolean isAlphaString(String s) {
|
||||
boolean b = true;
|
||||
for (int i = 0; i < s.length(); i++) {
|
||||
if (!isAlpha(s.charAt(i))) {
|
||||
b = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return b;
|
||||
}
|
||||
|
||||
public static boolean isNumeric(char c) {
|
||||
return (c >= '0' && c <= '9');
|
||||
}
|
||||
|
||||
public static boolean isNumericString(String s) {
|
||||
boolean b = true;
|
||||
for (int i = 0; i < s.length(); i++) {
|
||||
if (!isNumeric(s.charAt(i))) {
|
||||
b = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return b;
|
||||
}
|
||||
|
||||
public static boolean isAlphaNumeric(char c) {
|
||||
return isAlpha(c) || isNumeric(c);
|
||||
}
|
||||
|
||||
public static boolean isAlphaNumericString(String s) {
|
||||
boolean b = true;
|
||||
for (int i = 0; i < s.length(); i++) {
|
||||
if (!isAlphaNumeric(s.charAt(i))) {
|
||||
b = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return b;
|
||||
}
|
||||
|
||||
public static class CaseInsensitiveKey {
|
||||
private String _key;
|
||||
private int _hash;
|
||||
|
||||
public CaseInsensitiveKey(String key) {
|
||||
_key = key;
|
||||
_hash = AsciiUtil.toLowerString(key).hashCode();
|
||||
}
|
||||
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) {
|
||||
return true;
|
||||
}
|
||||
if (o instanceof CaseInsensitiveKey) {
|
||||
return AsciiUtil.caseIgnoreMatch(_key, ((CaseInsensitiveKey)o)._key);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public int hashCode() {
|
||||
return _hash;
|
||||
}
|
||||
}
|
||||
}
|
253
jdk/src/share/classes/sun/util/locale/BaseLocale.java
Normal file
253
jdk/src/share/classes/sun/util/locale/BaseLocale.java
Normal file
@ -0,0 +1,253 @@
|
||||
/*
|
||||
* Copyright (c) 2010, 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
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
/*
|
||||
*******************************************************************************
|
||||
* Copyright (C) 2009-2010, International Business Machines Corporation and *
|
||||
* others. All Rights Reserved. *
|
||||
*******************************************************************************
|
||||
*/
|
||||
|
||||
package sun.util.locale;
|
||||
|
||||
|
||||
public final class BaseLocale {
|
||||
|
||||
public static final String SEP = "_";
|
||||
|
||||
private static final Cache CACHE = new Cache();
|
||||
public static final BaseLocale ROOT = BaseLocale.getInstance("", "", "", "");
|
||||
|
||||
private String _language = "";
|
||||
private String _script = "";
|
||||
private String _region = "";
|
||||
private String _variant = "";
|
||||
|
||||
private transient volatile int _hash = 0;
|
||||
|
||||
private BaseLocale(String language, String script, String region, String variant) {
|
||||
if (language != null) {
|
||||
_language = AsciiUtil.toLowerString(language).intern();
|
||||
}
|
||||
if (script != null) {
|
||||
_script = AsciiUtil.toTitleString(script).intern();
|
||||
}
|
||||
if (region != null) {
|
||||
_region = AsciiUtil.toUpperString(region).intern();
|
||||
}
|
||||
if (variant != null) {
|
||||
_variant = variant.intern();
|
||||
}
|
||||
}
|
||||
|
||||
public static BaseLocale getInstance(String language, String script, String region, String variant) {
|
||||
// JDK uses deprecated ISO639.1 language codes for he, yi and id
|
||||
if (AsciiUtil.caseIgnoreMatch(language, "he")) {
|
||||
language = "iw";
|
||||
} else if (AsciiUtil.caseIgnoreMatch(language, "yi")) {
|
||||
language = "ji";
|
||||
} else if (AsciiUtil.caseIgnoreMatch(language, "id")) {
|
||||
language = "in";
|
||||
}
|
||||
|
||||
Key key = new Key(language, script, region, variant);
|
||||
BaseLocale baseLocale = CACHE.get(key);
|
||||
return baseLocale;
|
||||
}
|
||||
|
||||
public String getLanguage() {
|
||||
return _language;
|
||||
}
|
||||
|
||||
public String getScript() {
|
||||
return _script;
|
||||
}
|
||||
|
||||
public String getRegion() {
|
||||
return _region;
|
||||
}
|
||||
|
||||
public String getVariant() {
|
||||
return _variant;
|
||||
}
|
||||
|
||||
public boolean equals(Object obj) {
|
||||
if (this == obj) {
|
||||
return true;
|
||||
}
|
||||
if (!(obj instanceof BaseLocale)) {
|
||||
return false;
|
||||
}
|
||||
BaseLocale other = (BaseLocale)obj;
|
||||
return hashCode() == other.hashCode()
|
||||
&& _language.equals(other._language)
|
||||
&& _script.equals(other._script)
|
||||
&& _region.equals(other._region)
|
||||
&& _variant.equals(other._variant);
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
StringBuilder buf = new StringBuilder();
|
||||
if (_language.length() > 0) {
|
||||
buf.append("language=");
|
||||
buf.append(_language);
|
||||
}
|
||||
if (_script.length() > 0) {
|
||||
if (buf.length() > 0) {
|
||||
buf.append(", ");
|
||||
}
|
||||
buf.append("script=");
|
||||
buf.append(_script);
|
||||
}
|
||||
if (_region.length() > 0) {
|
||||
if (buf.length() > 0) {
|
||||
buf.append(", ");
|
||||
}
|
||||
buf.append("region=");
|
||||
buf.append(_region);
|
||||
}
|
||||
if (_variant.length() > 0) {
|
||||
if (buf.length() > 0) {
|
||||
buf.append(", ");
|
||||
}
|
||||
buf.append("variant=");
|
||||
buf.append(_variant);
|
||||
}
|
||||
return buf.toString();
|
||||
}
|
||||
|
||||
public int hashCode() {
|
||||
int h = _hash;
|
||||
if (h == 0) {
|
||||
// Generating a hash value from language, script, region and variant
|
||||
for (int i = 0; i < _language.length(); i++) {
|
||||
h = 31*h + _language.charAt(i);
|
||||
}
|
||||
for (int i = 0; i < _script.length(); i++) {
|
||||
h = 31*h + _script.charAt(i);
|
||||
}
|
||||
for (int i = 0; i < _region.length(); i++) {
|
||||
h = 31*h + _region.charAt(i);
|
||||
}
|
||||
for (int i = 0; i < _variant.length(); i++) {
|
||||
h = 31*h + _variant.charAt(i);
|
||||
}
|
||||
_hash = h;
|
||||
}
|
||||
return h;
|
||||
}
|
||||
|
||||
private static class Key implements Comparable<Key> {
|
||||
private String _lang = "";
|
||||
private String _scrt = "";
|
||||
private String _regn = "";
|
||||
private String _vart = "";
|
||||
|
||||
private volatile int _hash; // Default to 0
|
||||
|
||||
public Key(String language, String script, String region, String variant) {
|
||||
if (language != null) {
|
||||
_lang = language;
|
||||
}
|
||||
if (script != null) {
|
||||
_scrt = script;
|
||||
}
|
||||
if (region != null) {
|
||||
_regn = region;
|
||||
}
|
||||
if (variant != null) {
|
||||
_vart = variant;
|
||||
}
|
||||
}
|
||||
|
||||
public boolean equals(Object obj) {
|
||||
return (this == obj) ||
|
||||
(obj instanceof Key)
|
||||
&& AsciiUtil.caseIgnoreMatch(((Key)obj)._lang, this._lang)
|
||||
&& AsciiUtil.caseIgnoreMatch(((Key)obj)._scrt, this._scrt)
|
||||
&& AsciiUtil.caseIgnoreMatch(((Key)obj)._regn, this._regn)
|
||||
&& ((Key)obj)._vart.equals(_vart); // variant is case sensitive in JDK!
|
||||
}
|
||||
|
||||
public int compareTo(Key other) {
|
||||
int res = AsciiUtil.caseIgnoreCompare(this._lang, other._lang);
|
||||
if (res == 0) {
|
||||
res = AsciiUtil.caseIgnoreCompare(this._scrt, other._scrt);
|
||||
if (res == 0) {
|
||||
res = AsciiUtil.caseIgnoreCompare(this._regn, other._regn);
|
||||
if (res == 0) {
|
||||
res = this._vart.compareTo(other._vart);
|
||||
}
|
||||
}
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
public int hashCode() {
|
||||
int h = _hash;
|
||||
if (h == 0) {
|
||||
// Generating a hash value from language, script, region and variant
|
||||
for (int i = 0; i < _lang.length(); i++) {
|
||||
h = 31*h + AsciiUtil.toLower(_lang.charAt(i));
|
||||
}
|
||||
for (int i = 0; i < _scrt.length(); i++) {
|
||||
h = 31*h + AsciiUtil.toLower(_scrt.charAt(i));
|
||||
}
|
||||
for (int i = 0; i < _regn.length(); i++) {
|
||||
h = 31*h + AsciiUtil.toLower(_regn.charAt(i));
|
||||
}
|
||||
for (int i = 0; i < _vart.length(); i++) {
|
||||
h = 31*h + _vart.charAt(i);
|
||||
}
|
||||
_hash = h;
|
||||
}
|
||||
return h;
|
||||
}
|
||||
|
||||
public static Key normalize(Key key) {
|
||||
String lang = AsciiUtil.toLowerString(key._lang).intern();
|
||||
String scrt = AsciiUtil.toTitleString(key._scrt).intern();
|
||||
String regn = AsciiUtil.toUpperString(key._regn).intern();
|
||||
String vart = key._vart.intern(); // preserve upper/lower cases
|
||||
|
||||
return new Key(lang, scrt, regn, vart);
|
||||
}
|
||||
}
|
||||
|
||||
private static class Cache extends LocaleObjectCache<Key, BaseLocale> {
|
||||
|
||||
public Cache() {
|
||||
}
|
||||
|
||||
protected Key normalizeKey(Key key) {
|
||||
return Key.normalize(key);
|
||||
}
|
||||
|
||||
protected BaseLocale createObject(Key key) {
|
||||
return new BaseLocale(key._lang, key._scrt, key._regn, key._vart);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
63
jdk/src/share/classes/sun/util/locale/Extension.java
Normal file
63
jdk/src/share/classes/sun/util/locale/Extension.java
Normal file
@ -0,0 +1,63 @@
|
||||
/*
|
||||
* Copyright (c) 2010, 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
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
/*
|
||||
*******************************************************************************
|
||||
* Copyright (C) 2009-2010, International Business Machines Corporation and *
|
||||
* others. All Rights Reserved. *
|
||||
*******************************************************************************
|
||||
*/
|
||||
package sun.util.locale;
|
||||
|
||||
|
||||
public class Extension {
|
||||
private char _key;
|
||||
protected String _value;
|
||||
|
||||
protected Extension(char key) {
|
||||
_key = key;
|
||||
}
|
||||
|
||||
Extension(char key, String value) {
|
||||
_key = key;
|
||||
_value = value;
|
||||
}
|
||||
|
||||
public char getKey() {
|
||||
return _key;
|
||||
}
|
||||
|
||||
public String getValue() {
|
||||
return _value;
|
||||
}
|
||||
|
||||
public String getID() {
|
||||
return _key + LanguageTag.SEP + _value;
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return getID();
|
||||
}
|
||||
}
|
705
jdk/src/share/classes/sun/util/locale/InternalLocaleBuilder.java
Normal file
705
jdk/src/share/classes/sun/util/locale/InternalLocaleBuilder.java
Normal file
@ -0,0 +1,705 @@
|
||||
/*
|
||||
* Copyright (c) 2010, 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
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
/*
|
||||
*******************************************************************************
|
||||
* Copyright (C) 2009-2010, International Business Machines Corporation and *
|
||||
* others. All Rights Reserved. *
|
||||
*******************************************************************************
|
||||
*/
|
||||
package sun.util.locale;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
public final class InternalLocaleBuilder {
|
||||
|
||||
private String _language = "";
|
||||
private String _script = "";
|
||||
private String _region = "";
|
||||
private String _variant = "";
|
||||
|
||||
private static final CaseInsensitiveChar PRIVUSE_KEY = new CaseInsensitiveChar(LanguageTag.PRIVATEUSE.charAt(0));
|
||||
|
||||
private HashMap<CaseInsensitiveChar, String> _extensions;
|
||||
private HashSet<CaseInsensitiveString> _uattributes;
|
||||
private HashMap<CaseInsensitiveString, String> _ukeywords;
|
||||
|
||||
|
||||
public InternalLocaleBuilder() {
|
||||
}
|
||||
|
||||
public InternalLocaleBuilder setLanguage(String language) throws LocaleSyntaxException {
|
||||
if (language == null || language.length() == 0) {
|
||||
_language = "";
|
||||
} else {
|
||||
if (!LanguageTag.isLanguage(language)) {
|
||||
throw new LocaleSyntaxException("Ill-formed language: " + language, 0);
|
||||
}
|
||||
_language = language;
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
public InternalLocaleBuilder setScript(String script) throws LocaleSyntaxException {
|
||||
if (script == null || script.length() == 0) {
|
||||
_script = "";
|
||||
} else {
|
||||
if (!LanguageTag.isScript(script)) {
|
||||
throw new LocaleSyntaxException("Ill-formed script: " + script, 0);
|
||||
}
|
||||
_script = script;
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
public InternalLocaleBuilder setRegion(String region) throws LocaleSyntaxException {
|
||||
if (region == null || region.length() == 0) {
|
||||
_region = "";
|
||||
} else {
|
||||
if (!LanguageTag.isRegion(region)) {
|
||||
throw new LocaleSyntaxException("Ill-formed region: " + region, 0);
|
||||
}
|
||||
_region = region;
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
public InternalLocaleBuilder setVariant(String variant) throws LocaleSyntaxException {
|
||||
if (variant == null || variant.length() == 0) {
|
||||
_variant = "";
|
||||
} else {
|
||||
// normalize separators to "_"
|
||||
String var = variant.replaceAll(LanguageTag.SEP, BaseLocale.SEP);
|
||||
int errIdx = checkVariants(var, BaseLocale.SEP);
|
||||
if (errIdx != -1) {
|
||||
throw new LocaleSyntaxException("Ill-formed variant: " + variant, errIdx);
|
||||
}
|
||||
_variant = var;
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
public InternalLocaleBuilder addUnicodeLocaleAttribute(String attribute) throws LocaleSyntaxException {
|
||||
if (!UnicodeLocaleExtension.isAttribute(attribute)) {
|
||||
throw new LocaleSyntaxException("Ill-formed Unicode locale attribute: " + attribute);
|
||||
}
|
||||
// Use case insensitive string to prevent duplication
|
||||
if (_uattributes == null) {
|
||||
_uattributes = new HashSet<CaseInsensitiveString>(4);
|
||||
}
|
||||
_uattributes.add(new CaseInsensitiveString(attribute));
|
||||
return this;
|
||||
}
|
||||
|
||||
public InternalLocaleBuilder removeUnicodeLocaleAttribute(String attribute) throws LocaleSyntaxException {
|
||||
if (attribute == null || !UnicodeLocaleExtension.isAttribute(attribute)) {
|
||||
throw new LocaleSyntaxException("Ill-formed Unicode locale attribute: " + attribute);
|
||||
}
|
||||
if (_uattributes != null) {
|
||||
_uattributes.remove(new CaseInsensitiveString(attribute));
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
public InternalLocaleBuilder setUnicodeLocaleKeyword(String key, String type) throws LocaleSyntaxException {
|
||||
if (!UnicodeLocaleExtension.isKey(key)) {
|
||||
throw new LocaleSyntaxException("Ill-formed Unicode locale keyword key: " + key);
|
||||
}
|
||||
|
||||
CaseInsensitiveString cikey = new CaseInsensitiveString(key);
|
||||
if (type == null) {
|
||||
if (_ukeywords != null) {
|
||||
// null type is used for remove the key
|
||||
_ukeywords.remove(cikey);
|
||||
}
|
||||
} else {
|
||||
if (type.length() != 0) {
|
||||
// normalize separator to "-"
|
||||
String tp = type.replaceAll(BaseLocale.SEP, LanguageTag.SEP);
|
||||
// validate
|
||||
StringTokenIterator itr = new StringTokenIterator(tp, LanguageTag.SEP);
|
||||
while (!itr.isDone()) {
|
||||
String s = itr.current();
|
||||
if (!UnicodeLocaleExtension.isTypeSubtag(s)) {
|
||||
throw new LocaleSyntaxException("Ill-formed Unicode locale keyword type: " + type, itr.currentStart());
|
||||
}
|
||||
itr.next();
|
||||
}
|
||||
}
|
||||
if (_ukeywords == null) {
|
||||
_ukeywords = new HashMap<CaseInsensitiveString, String>(4);
|
||||
}
|
||||
_ukeywords.put(cikey, type);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
public InternalLocaleBuilder setExtension(char singleton, String value) throws LocaleSyntaxException {
|
||||
// validate key
|
||||
boolean isBcpPrivateuse = LanguageTag.isPrivateusePrefixChar(singleton);
|
||||
if (!isBcpPrivateuse && !LanguageTag.isExtensionSingletonChar(singleton)) {
|
||||
throw new LocaleSyntaxException("Ill-formed extension key: " + singleton);
|
||||
}
|
||||
|
||||
boolean remove = (value == null || value.length() == 0);
|
||||
CaseInsensitiveChar key = new CaseInsensitiveChar(singleton);
|
||||
|
||||
if (remove) {
|
||||
if (UnicodeLocaleExtension.isSingletonChar(key.value())) {
|
||||
// clear entire Unicode locale extension
|
||||
if (_uattributes != null) {
|
||||
_uattributes.clear();
|
||||
}
|
||||
if (_ukeywords != null) {
|
||||
_ukeywords.clear();
|
||||
}
|
||||
} else {
|
||||
if (_extensions != null && _extensions.containsKey(key)) {
|
||||
_extensions.remove(key);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// validate value
|
||||
String val = value.replaceAll(BaseLocale.SEP, LanguageTag.SEP);
|
||||
StringTokenIterator itr = new StringTokenIterator(val, LanguageTag.SEP);
|
||||
while (!itr.isDone()) {
|
||||
String s = itr.current();
|
||||
boolean validSubtag;
|
||||
if (isBcpPrivateuse) {
|
||||
validSubtag = LanguageTag.isPrivateuseSubtag(s);
|
||||
} else {
|
||||
validSubtag = LanguageTag.isExtensionSubtag(s);
|
||||
}
|
||||
if (!validSubtag) {
|
||||
throw new LocaleSyntaxException("Ill-formed extension value: " + s, itr.currentStart());
|
||||
}
|
||||
itr.next();
|
||||
}
|
||||
|
||||
if (UnicodeLocaleExtension.isSingletonChar(key.value())) {
|
||||
setUnicodeLocaleExtension(val);
|
||||
} else {
|
||||
if (_extensions == null) {
|
||||
_extensions = new HashMap<CaseInsensitiveChar, String>(4);
|
||||
}
|
||||
_extensions.put(key, val);
|
||||
}
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
/*
|
||||
* Set extension/private subtags in a single string representation
|
||||
*/
|
||||
public InternalLocaleBuilder setExtensions(String subtags) throws LocaleSyntaxException {
|
||||
if (subtags == null || subtags.length() == 0) {
|
||||
clearExtensions();
|
||||
return this;
|
||||
}
|
||||
subtags = subtags.replaceAll(BaseLocale.SEP, LanguageTag.SEP);
|
||||
StringTokenIterator itr = new StringTokenIterator(subtags, LanguageTag.SEP);
|
||||
|
||||
List<String> extensions = null;
|
||||
String privateuse = null;
|
||||
|
||||
int parsed = 0;
|
||||
int start;
|
||||
|
||||
// Make a list of extension subtags
|
||||
while (!itr.isDone()) {
|
||||
String s = itr.current();
|
||||
if (LanguageTag.isExtensionSingleton(s)) {
|
||||
start = itr.currentStart();
|
||||
String singleton = s;
|
||||
StringBuilder sb = new StringBuilder(singleton);
|
||||
|
||||
itr.next();
|
||||
while (!itr.isDone()) {
|
||||
s = itr.current();
|
||||
if (LanguageTag.isExtensionSubtag(s)) {
|
||||
sb.append(LanguageTag.SEP).append(s);
|
||||
parsed = itr.currentEnd();
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
itr.next();
|
||||
}
|
||||
|
||||
if (parsed < start) {
|
||||
throw new LocaleSyntaxException("Incomplete extension '" + singleton + "'", start);
|
||||
}
|
||||
|
||||
if (extensions == null) {
|
||||
extensions = new ArrayList<String>(4);
|
||||
}
|
||||
extensions.add(sb.toString());
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!itr.isDone()) {
|
||||
String s = itr.current();
|
||||
if (LanguageTag.isPrivateusePrefix(s)) {
|
||||
start = itr.currentStart();
|
||||
StringBuilder sb = new StringBuilder(s);
|
||||
|
||||
itr.next();
|
||||
while (!itr.isDone()) {
|
||||
s = itr.current();
|
||||
if (!LanguageTag.isPrivateuseSubtag(s)) {
|
||||
break;
|
||||
}
|
||||
sb.append(LanguageTag.SEP).append(s);
|
||||
parsed = itr.currentEnd();
|
||||
|
||||
itr.next();
|
||||
}
|
||||
if (parsed <= start) {
|
||||
throw new LocaleSyntaxException("Incomplete privateuse:" + subtags.substring(start), start);
|
||||
} else {
|
||||
privateuse = sb.toString();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!itr.isDone()) {
|
||||
throw new LocaleSyntaxException("Ill-formed extension subtags:" + subtags.substring(itr.currentStart()), itr.currentStart());
|
||||
}
|
||||
|
||||
return setExtensions(extensions, privateuse);
|
||||
}
|
||||
|
||||
/*
|
||||
* Set a list of BCP47 extensions and private use subtags
|
||||
* BCP47 extensions are already validated and well-formed, but may contain duplicates
|
||||
*/
|
||||
private InternalLocaleBuilder setExtensions(List<String> bcpExtensions, String privateuse) {
|
||||
clearExtensions();
|
||||
|
||||
if (bcpExtensions != null && bcpExtensions.size() > 0) {
|
||||
HashSet<CaseInsensitiveChar> processedExntensions = new HashSet<CaseInsensitiveChar>(bcpExtensions.size());
|
||||
for (String bcpExt : bcpExtensions) {
|
||||
CaseInsensitiveChar key = new CaseInsensitiveChar(bcpExt.charAt(0));
|
||||
// ignore duplicates
|
||||
if (!processedExntensions.contains(key)) {
|
||||
// each extension string contains singleton, e.g. "a-abc-def"
|
||||
if (UnicodeLocaleExtension.isSingletonChar(key.value())) {
|
||||
setUnicodeLocaleExtension(bcpExt.substring(2));
|
||||
} else {
|
||||
if (_extensions == null) {
|
||||
_extensions = new HashMap<CaseInsensitiveChar, String>(4);
|
||||
}
|
||||
_extensions.put(key, bcpExt.substring(2));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (privateuse != null && privateuse.length() > 0) {
|
||||
// privateuse string contains prefix, e.g. "x-abc-def"
|
||||
if (_extensions == null) {
|
||||
_extensions = new HashMap<CaseInsensitiveChar, String>(1);
|
||||
}
|
||||
_extensions.put(new CaseInsensitiveChar(privateuse.charAt(0)), privateuse.substring(2));
|
||||
}
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
/*
|
||||
* Reset Builder's internal state with the given language tag
|
||||
*/
|
||||
public InternalLocaleBuilder setLanguageTag(LanguageTag langtag) {
|
||||
clear();
|
||||
if (langtag.getExtlangs().size() > 0) {
|
||||
_language = langtag.getExtlangs().get(0);
|
||||
} else {
|
||||
String language = langtag.getLanguage();
|
||||
if (!language.equals(LanguageTag.UNDETERMINED)) {
|
||||
_language = language;
|
||||
}
|
||||
}
|
||||
_script = langtag.getScript();
|
||||
_region = langtag.getRegion();
|
||||
|
||||
List<String> bcpVariants = langtag.getVariants();
|
||||
if (bcpVariants.size() > 0) {
|
||||
StringBuilder var = new StringBuilder(bcpVariants.get(0));
|
||||
for (int i = 1; i < bcpVariants.size(); i++) {
|
||||
var.append(BaseLocale.SEP).append(bcpVariants.get(i));
|
||||
}
|
||||
_variant = var.toString();
|
||||
}
|
||||
|
||||
setExtensions(langtag.getExtensions(), langtag.getPrivateuse());
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
public InternalLocaleBuilder setLocale(BaseLocale base, LocaleExtensions extensions) throws LocaleSyntaxException {
|
||||
String language = base.getLanguage();
|
||||
String script = base.getScript();
|
||||
String region = base.getRegion();
|
||||
String variant = base.getVariant();
|
||||
|
||||
// Special backward compatibility support
|
||||
|
||||
// Exception 1 - ja_JP_JP
|
||||
if (language.equals("ja") && region.equals("JP") && variant.equals("JP")) {
|
||||
// When locale ja_JP_JP is created, ca-japanese is always there.
|
||||
// The builder ignores the variant "JP"
|
||||
assert("japanese".equals(extensions.getUnicodeLocaleType("ca")));
|
||||
variant = "";
|
||||
}
|
||||
// Exception 2 - th_TH_TH
|
||||
else if (language.equals("th") && region.equals("TH") && variant.equals("TH")) {
|
||||
// When locale th_TH_TH is created, nu-thai is always there.
|
||||
// The builder ignores the variant "TH"
|
||||
assert("thai".equals(extensions.getUnicodeLocaleType("nu")));
|
||||
variant = "";
|
||||
}
|
||||
// Exception 3 - no_NO_NY
|
||||
else if (language.equals("no") && region.equals("NO") && variant.equals("NY")) {
|
||||
// no_NO_NY is a valid locale and used by Java 6 or older versions.
|
||||
// The build ignores the variant "NY" and change the language to "nn".
|
||||
language = "nn";
|
||||
variant = "";
|
||||
}
|
||||
|
||||
// Validate base locale fields before updating internal state.
|
||||
// LocaleExtensions always store validated/canonicalized values,
|
||||
// so no checks are necessary.
|
||||
if (language.length() > 0 && !LanguageTag.isLanguage(language)) {
|
||||
throw new LocaleSyntaxException("Ill-formed language: " + language);
|
||||
}
|
||||
|
||||
if (script.length() > 0 && !LanguageTag.isScript(script)) {
|
||||
throw new LocaleSyntaxException("Ill-formed script: " + script);
|
||||
}
|
||||
|
||||
if (region.length() > 0 && !LanguageTag.isRegion(region)) {
|
||||
throw new LocaleSyntaxException("Ill-formed region: " + region);
|
||||
}
|
||||
|
||||
if (variant.length() > 0) {
|
||||
int errIdx = checkVariants(variant, BaseLocale.SEP);
|
||||
if (errIdx != -1) {
|
||||
throw new LocaleSyntaxException("Ill-formed variant: " + variant, errIdx);
|
||||
}
|
||||
}
|
||||
|
||||
// The input locale is validated at this point.
|
||||
// Now, updating builder's internal fields.
|
||||
_language = language;
|
||||
_script = script;
|
||||
_region = region;
|
||||
_variant = variant;
|
||||
clearExtensions();
|
||||
|
||||
Set<Character> extKeys = (extensions == null) ? null : extensions.getKeys();
|
||||
if (extKeys != null) {
|
||||
// map extensions back to builder's internal format
|
||||
for (Character key : extKeys) {
|
||||
Extension e = extensions.getExtension(key);
|
||||
if (e instanceof UnicodeLocaleExtension) {
|
||||
UnicodeLocaleExtension ue = (UnicodeLocaleExtension)e;
|
||||
for (String uatr : ue.getUnicodeLocaleAttributes()) {
|
||||
if (_uattributes == null) {
|
||||
_uattributes = new HashSet<CaseInsensitiveString>(4);
|
||||
}
|
||||
_uattributes.add(new CaseInsensitiveString(uatr));
|
||||
}
|
||||
for (String ukey : ue.getUnicodeLocaleKeys()) {
|
||||
if (_ukeywords == null) {
|
||||
_ukeywords = new HashMap<CaseInsensitiveString, String>(4);
|
||||
}
|
||||
_ukeywords.put(new CaseInsensitiveString(ukey), ue.getUnicodeLocaleType(ukey));
|
||||
}
|
||||
} else {
|
||||
if (_extensions == null) {
|
||||
_extensions = new HashMap<CaseInsensitiveChar, String>(4);
|
||||
}
|
||||
_extensions.put(new CaseInsensitiveChar(key.charValue()), e.getValue());
|
||||
}
|
||||
}
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
public InternalLocaleBuilder clear() {
|
||||
_language = "";
|
||||
_script = "";
|
||||
_region = "";
|
||||
_variant = "";
|
||||
clearExtensions();
|
||||
return this;
|
||||
}
|
||||
|
||||
public InternalLocaleBuilder clearExtensions() {
|
||||
if (_extensions != null) {
|
||||
_extensions.clear();
|
||||
}
|
||||
if (_uattributes != null) {
|
||||
_uattributes.clear();
|
||||
}
|
||||
if (_ukeywords != null) {
|
||||
_ukeywords.clear();
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
public BaseLocale getBaseLocale() {
|
||||
String language = _language;
|
||||
String script = _script;
|
||||
String region = _region;
|
||||
String variant = _variant;
|
||||
|
||||
// Special private use subtag sequence identified by "lvariant" will be
|
||||
// interpreted as Java variant.
|
||||
if (_extensions != null) {
|
||||
String privuse = _extensions.get(PRIVUSE_KEY);
|
||||
if (privuse != null) {
|
||||
StringTokenIterator itr = new StringTokenIterator(privuse, LanguageTag.SEP);
|
||||
boolean sawPrefix = false;
|
||||
int privVarStart = -1;
|
||||
while (!itr.isDone()) {
|
||||
if (sawPrefix) {
|
||||
privVarStart = itr.currentStart();
|
||||
break;
|
||||
}
|
||||
if (AsciiUtil.caseIgnoreMatch(itr.current(), LanguageTag.PRIVUSE_VARIANT_PREFIX)) {
|
||||
sawPrefix = true;
|
||||
}
|
||||
itr.next();
|
||||
}
|
||||
if (privVarStart != -1) {
|
||||
StringBuilder sb = new StringBuilder(variant);
|
||||
if (sb.length() != 0) {
|
||||
sb.append(BaseLocale.SEP);
|
||||
}
|
||||
sb.append(privuse.substring(privVarStart).replaceAll(LanguageTag.SEP, BaseLocale.SEP));
|
||||
variant = sb.toString();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return BaseLocale.getInstance(language, script, region, variant);
|
||||
}
|
||||
|
||||
public LocaleExtensions getLocaleExtensions() {
|
||||
if ((_extensions == null || _extensions.size() == 0)
|
||||
&& (_uattributes == null || _uattributes.size() == 0)
|
||||
&& (_ukeywords == null || _ukeywords.size() == 0)) {
|
||||
return LocaleExtensions.EMPTY_EXTENSIONS;
|
||||
}
|
||||
|
||||
return new LocaleExtensions(_extensions, _uattributes, _ukeywords);
|
||||
}
|
||||
|
||||
/*
|
||||
* Remove special private use subtag sequence identified by "lvariant"
|
||||
* and return the rest. Only used by LocaleExtensions
|
||||
*/
|
||||
static String removePrivateuseVariant(String privuseVal) {
|
||||
StringTokenIterator itr = new StringTokenIterator(privuseVal, LanguageTag.SEP);
|
||||
|
||||
// Note: privateuse value "abc-lvariant" is unchanged
|
||||
// because no subtags after "lvariant".
|
||||
|
||||
int prefixStart = -1;
|
||||
boolean sawPrivuseVar = false;
|
||||
while (!itr.isDone()) {
|
||||
if (prefixStart != -1) {
|
||||
// Note: privateuse value "abc-lvariant" is unchanged
|
||||
// because no subtags after "lvariant".
|
||||
sawPrivuseVar = true;
|
||||
break;
|
||||
}
|
||||
if (AsciiUtil.caseIgnoreMatch(itr.current(), LanguageTag.PRIVUSE_VARIANT_PREFIX)) {
|
||||
prefixStart = itr.currentStart();
|
||||
}
|
||||
itr.next();
|
||||
}
|
||||
if (!sawPrivuseVar) {
|
||||
return privuseVal;
|
||||
}
|
||||
|
||||
assert(prefixStart == 0 || prefixStart > 1);
|
||||
return (prefixStart == 0) ? null : privuseVal.substring(0, prefixStart -1);
|
||||
}
|
||||
|
||||
/*
|
||||
* Check if the given variant subtags separated by the given
|
||||
* separator(s) are valid
|
||||
*/
|
||||
private int checkVariants(String variants, String sep) {
|
||||
StringTokenIterator itr = new StringTokenIterator(variants, sep);
|
||||
while (!itr.isDone()) {
|
||||
String s = itr.current();
|
||||
if (!LanguageTag.isVariant(s)) {
|
||||
return itr.currentStart();
|
||||
}
|
||||
itr.next();
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Private methods parsing Unicode Locale Extension subtags.
|
||||
* Duplicated attributes/keywords will be ignored.
|
||||
* The input must be a valid extension subtags (excluding singleton).
|
||||
*/
|
||||
private void setUnicodeLocaleExtension(String subtags) {
|
||||
// wipe out existing attributes/keywords
|
||||
if (_uattributes != null) {
|
||||
_uattributes.clear();
|
||||
}
|
||||
if (_ukeywords != null) {
|
||||
_ukeywords.clear();
|
||||
}
|
||||
|
||||
StringTokenIterator itr = new StringTokenIterator(subtags, LanguageTag.SEP);
|
||||
|
||||
// parse attributes
|
||||
while (!itr.isDone()) {
|
||||
if (!UnicodeLocaleExtension.isAttribute(itr.current())) {
|
||||
break;
|
||||
}
|
||||
if (_uattributes == null) {
|
||||
_uattributes = new HashSet<CaseInsensitiveString>(4);
|
||||
}
|
||||
_uattributes.add(new CaseInsensitiveString(itr.current()));
|
||||
itr.next();
|
||||
}
|
||||
|
||||
// parse keywords
|
||||
CaseInsensitiveString key = null;
|
||||
String type;
|
||||
int typeStart = -1;
|
||||
int typeEnd = -1;
|
||||
while (!itr.isDone()) {
|
||||
if (key != null) {
|
||||
if (UnicodeLocaleExtension.isKey(itr.current())) {
|
||||
// next keyword - emit previous one
|
||||
assert(typeStart == -1 || typeEnd != -1);
|
||||
type = (typeStart == -1) ? "" : subtags.substring(typeStart, typeEnd);
|
||||
if (_ukeywords == null) {
|
||||
_ukeywords = new HashMap<CaseInsensitiveString, String>(4);
|
||||
}
|
||||
_ukeywords.put(key, type);
|
||||
|
||||
// reset keyword info
|
||||
CaseInsensitiveString tmpKey = new CaseInsensitiveString(itr.current());
|
||||
key = _ukeywords.containsKey(tmpKey) ? null : tmpKey;
|
||||
typeStart = typeEnd = -1;
|
||||
} else {
|
||||
if (typeStart == -1) {
|
||||
typeStart = itr.currentStart();
|
||||
}
|
||||
typeEnd = itr.currentEnd();
|
||||
}
|
||||
} else if (UnicodeLocaleExtension.isKey(itr.current())) {
|
||||
// 1. first keyword or
|
||||
// 2. next keyword, but previous one was duplicate
|
||||
key = new CaseInsensitiveString(itr.current());
|
||||
if (_ukeywords != null && _ukeywords.containsKey(key)) {
|
||||
// duplicate
|
||||
key = null;
|
||||
}
|
||||
}
|
||||
|
||||
if (!itr.hasNext()) {
|
||||
if (key != null) {
|
||||
// last keyword
|
||||
assert(typeStart == -1 || typeEnd != -1);
|
||||
type = (typeStart == -1) ? "" : subtags.substring(typeStart, typeEnd);
|
||||
if (_ukeywords == null) {
|
||||
_ukeywords = new HashMap<CaseInsensitiveString, String>(4);
|
||||
}
|
||||
_ukeywords.put(key, type);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
itr.next();
|
||||
}
|
||||
}
|
||||
|
||||
static class CaseInsensitiveString {
|
||||
private String _s;
|
||||
|
||||
CaseInsensitiveString(String s) {
|
||||
_s = s;
|
||||
}
|
||||
|
||||
public String value() {
|
||||
return _s;
|
||||
}
|
||||
|
||||
public int hashCode() {
|
||||
return AsciiUtil.toLowerString(_s).hashCode();
|
||||
}
|
||||
|
||||
public boolean equals(Object obj) {
|
||||
if (this == obj) {
|
||||
return true;
|
||||
}
|
||||
if (!(obj instanceof CaseInsensitiveString)) {
|
||||
return false;
|
||||
}
|
||||
return AsciiUtil.caseIgnoreMatch(_s, ((CaseInsensitiveString)obj).value());
|
||||
}
|
||||
}
|
||||
|
||||
static class CaseInsensitiveChar {
|
||||
private char _c;
|
||||
|
||||
CaseInsensitiveChar(char c) {
|
||||
_c = c;
|
||||
}
|
||||
|
||||
public char value() {
|
||||
return _c;
|
||||
}
|
||||
|
||||
public int hashCode() {
|
||||
return AsciiUtil.toLower(_c);
|
||||
}
|
||||
|
||||
public boolean equals(Object obj) {
|
||||
if (this == obj) {
|
||||
return true;
|
||||
}
|
||||
if (!(obj instanceof CaseInsensitiveChar)) {
|
||||
return false;
|
||||
}
|
||||
return _c == AsciiUtil.toLower(((CaseInsensitiveChar)obj).value());
|
||||
}
|
||||
|
||||
}
|
||||
}
|
726
jdk/src/share/classes/sun/util/locale/LanguageTag.java
Normal file
726
jdk/src/share/classes/sun/util/locale/LanguageTag.java
Normal file
@ -0,0 +1,726 @@
|
||||
/*
|
||||
* Copyright (c) 2010, 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
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
/*
|
||||
*******************************************************************************
|
||||
* Copyright (C) 2010, International Business Machines Corporation and *
|
||||
* others. All Rights Reserved. *
|
||||
*******************************************************************************
|
||||
*/
|
||||
package sun.util.locale;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
public class LanguageTag {
|
||||
//
|
||||
// static fields
|
||||
//
|
||||
public static final String SEP = "-";
|
||||
public static final String PRIVATEUSE = "x";
|
||||
public static String UNDETERMINED = "und";
|
||||
public static final String PRIVUSE_VARIANT_PREFIX = "lvariant";
|
||||
|
||||
//
|
||||
// Language subtag fields
|
||||
//
|
||||
private String _language = ""; // language subtag
|
||||
private String _script = ""; // script subtag
|
||||
private String _region = ""; // region subtag
|
||||
private String _privateuse = ""; // privateuse
|
||||
|
||||
private List<String> _extlangs = Collections.emptyList(); // extlang subtags
|
||||
private List<String> _variants = Collections.emptyList(); // variant subtags
|
||||
private List<String> _extensions = Collections.emptyList(); // extensions
|
||||
|
||||
// Map contains grandfathered tags and its preferred mappings from
|
||||
// http://www.ietf.org/rfc/rfc5646.txt
|
||||
private static final Map<AsciiUtil.CaseInsensitiveKey, String[]> GRANDFATHERED =
|
||||
new HashMap<AsciiUtil.CaseInsensitiveKey, String[]>();
|
||||
|
||||
static {
|
||||
// grandfathered = irregular ; non-redundant tags registered
|
||||
// / regular ; during the RFC 3066 era
|
||||
//
|
||||
// irregular = "en-GB-oed" ; irregular tags do not match
|
||||
// / "i-ami" ; the 'langtag' production and
|
||||
// / "i-bnn" ; would not otherwise be
|
||||
// / "i-default" ; considered 'well-formed'
|
||||
// / "i-enochian" ; These tags are all valid,
|
||||
// / "i-hak" ; but most are deprecated
|
||||
// / "i-klingon" ; in favor of more modern
|
||||
// / "i-lux" ; subtags or subtag
|
||||
// / "i-mingo" ; combination
|
||||
// / "i-navajo"
|
||||
// / "i-pwn"
|
||||
// / "i-tao"
|
||||
// / "i-tay"
|
||||
// / "i-tsu"
|
||||
// / "sgn-BE-FR"
|
||||
// / "sgn-BE-NL"
|
||||
// / "sgn-CH-DE"
|
||||
//
|
||||
// regular = "art-lojban" ; these tags match the 'langtag'
|
||||
// / "cel-gaulish" ; production, but their subtags
|
||||
// / "no-bok" ; are not extended language
|
||||
// / "no-nyn" ; or variant subtags: their meaning
|
||||
// / "zh-guoyu" ; is defined by their registration
|
||||
// / "zh-hakka" ; and all of these are deprecated
|
||||
// / "zh-min" ; in favor of a more modern
|
||||
// / "zh-min-nan" ; subtag or sequence of subtags
|
||||
// / "zh-xiang"
|
||||
|
||||
final String[][] entries = {
|
||||
//{"tag", "preferred"},
|
||||
{"art-lojban", "jbo"},
|
||||
{"cel-gaulish", "xtg-x-cel-gaulish"}, // fallback
|
||||
{"en-GB-oed", "en-GB-x-oed"}, // fallback
|
||||
{"i-ami", "ami"},
|
||||
{"i-bnn", "bnn"},
|
||||
{"i-default", "en-x-i-default"}, // fallback
|
||||
{"i-enochian", "und-x-i-enochian"}, // fallback
|
||||
{"i-hak", "hak"},
|
||||
{"i-klingon", "tlh"},
|
||||
{"i-lux", "lb"},
|
||||
{"i-mingo", "see-x-i-mingo"}, // fallback
|
||||
{"i-navajo", "nv"},
|
||||
{"i-pwn", "pwn"},
|
||||
{"i-tao", "tao"},
|
||||
{"i-tay", "tay"},
|
||||
{"i-tsu", "tsu"},
|
||||
{"no-bok", "nb"},
|
||||
{"no-nyn", "nn"},
|
||||
{"sgn-BE-FR", "sfb"},
|
||||
{"sgn-BE-NL", "vgt"},
|
||||
{"sgn-CH-DE", "sgg"},
|
||||
{"zh-guoyu", "cmn"},
|
||||
{"zh-hakka", "hak"},
|
||||
{"zh-min", "nan-x-zh-min"}, // fallback
|
||||
{"zh-min-nan", "nan"},
|
||||
{"zh-xiang", "hsn"},
|
||||
};
|
||||
for (String[] e : entries) {
|
||||
GRANDFATHERED.put(new AsciiUtil.CaseInsensitiveKey(e[0]), e);
|
||||
}
|
||||
}
|
||||
|
||||
private LanguageTag() {
|
||||
}
|
||||
|
||||
/*
|
||||
* BNF in RFC5464
|
||||
*
|
||||
* Language-Tag = langtag ; normal language tags
|
||||
* / privateuse ; private use tag
|
||||
* / grandfathered ; grandfathered tags
|
||||
*
|
||||
*
|
||||
* langtag = language
|
||||
* ["-" script]
|
||||
* ["-" region]
|
||||
* *("-" variant)
|
||||
* *("-" extension)
|
||||
* ["-" privateuse]
|
||||
*
|
||||
* language = 2*3ALPHA ; shortest ISO 639 code
|
||||
* ["-" extlang] ; sometimes followed by
|
||||
* ; extended language subtags
|
||||
* / 4ALPHA ; or reserved for future use
|
||||
* / 5*8ALPHA ; or registered language subtag
|
||||
*
|
||||
* extlang = 3ALPHA ; selected ISO 639 codes
|
||||
* *2("-" 3ALPHA) ; permanently reserved
|
||||
*
|
||||
* script = 4ALPHA ; ISO 15924 code
|
||||
*
|
||||
* region = 2ALPHA ; ISO 3166-1 code
|
||||
* / 3DIGIT ; UN M.49 code
|
||||
*
|
||||
* variant = 5*8alphanum ; registered variants
|
||||
* / (DIGIT 3alphanum)
|
||||
*
|
||||
* extension = singleton 1*("-" (2*8alphanum))
|
||||
*
|
||||
* ; Single alphanumerics
|
||||
* ; "x" reserved for private use
|
||||
* singleton = DIGIT ; 0 - 9
|
||||
* / %x41-57 ; A - W
|
||||
* / %x59-5A ; Y - Z
|
||||
* / %x61-77 ; a - w
|
||||
* / %x79-7A ; y - z
|
||||
*
|
||||
* privateuse = "x" 1*("-" (1*8alphanum))
|
||||
*
|
||||
*/
|
||||
public static LanguageTag parse(String languageTag, ParseStatus sts) {
|
||||
if (sts == null) {
|
||||
sts = new ParseStatus();
|
||||
} else {
|
||||
sts.reset();
|
||||
}
|
||||
|
||||
StringTokenIterator itr;
|
||||
|
||||
// Check if the tag is grandfathered
|
||||
String[] gfmap = GRANDFATHERED.get(new AsciiUtil.CaseInsensitiveKey(languageTag));
|
||||
if (gfmap != null) {
|
||||
// use preferred mapping
|
||||
itr = new StringTokenIterator(gfmap[1], SEP);
|
||||
} else {
|
||||
itr = new StringTokenIterator(languageTag, SEP);
|
||||
}
|
||||
|
||||
LanguageTag tag = new LanguageTag();
|
||||
|
||||
// langtag must start with either language or privateuse
|
||||
if (tag.parseLanguage(itr, sts)) {
|
||||
tag.parseExtlangs(itr, sts);
|
||||
tag.parseScript(itr, sts);
|
||||
tag.parseRegion(itr, sts);
|
||||
tag.parseVariants(itr, sts);
|
||||
tag.parseExtensions(itr, sts);
|
||||
}
|
||||
tag.parsePrivateuse(itr, sts);
|
||||
|
||||
if (!itr.isDone() && !sts.isError()) {
|
||||
String s = itr.current();
|
||||
sts._errorIndex = itr.currentStart();
|
||||
if (s.length() == 0) {
|
||||
sts._errorMsg = "Empty subtag";
|
||||
} else {
|
||||
sts._errorMsg = "Invalid subtag: " + s;
|
||||
}
|
||||
}
|
||||
|
||||
return tag;
|
||||
}
|
||||
|
||||
//
|
||||
// Language subtag parsers
|
||||
//
|
||||
|
||||
private boolean parseLanguage(StringTokenIterator itr, ParseStatus sts) {
|
||||
if (itr.isDone() || sts.isError()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
boolean found = false;
|
||||
|
||||
String s = itr.current();
|
||||
if (isLanguage(s)) {
|
||||
found = true;
|
||||
_language = s;
|
||||
sts._parseLength = itr.currentEnd();
|
||||
itr.next();
|
||||
}
|
||||
|
||||
return found;
|
||||
}
|
||||
|
||||
private boolean parseExtlangs(StringTokenIterator itr, ParseStatus sts) {
|
||||
if (itr.isDone() || sts.isError()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
boolean found = false;
|
||||
|
||||
while (!itr.isDone()) {
|
||||
String s = itr.current();
|
||||
if (!isExtlang(s)) {
|
||||
break;
|
||||
}
|
||||
found = true;
|
||||
if (_extlangs.isEmpty()) {
|
||||
_extlangs = new ArrayList<String>(3);
|
||||
}
|
||||
_extlangs.add(s);
|
||||
sts._parseLength = itr.currentEnd();
|
||||
itr.next();
|
||||
|
||||
if (_extlangs.size() == 3) {
|
||||
// Maximum 3 extlangs
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return found;
|
||||
}
|
||||
|
||||
private boolean parseScript(StringTokenIterator itr, ParseStatus sts) {
|
||||
if (itr.isDone() || sts.isError()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
boolean found = false;
|
||||
|
||||
String s = itr.current();
|
||||
if (isScript(s)) {
|
||||
found = true;
|
||||
_script = s;
|
||||
sts._parseLength = itr.currentEnd();
|
||||
itr.next();
|
||||
}
|
||||
|
||||
return found;
|
||||
}
|
||||
|
||||
private boolean parseRegion(StringTokenIterator itr, ParseStatus sts) {
|
||||
if (itr.isDone() || sts.isError()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
boolean found = false;
|
||||
|
||||
String s = itr.current();
|
||||
if (isRegion(s)) {
|
||||
found = true;
|
||||
_region = s;
|
||||
sts._parseLength = itr.currentEnd();
|
||||
itr.next();
|
||||
}
|
||||
|
||||
return found;
|
||||
}
|
||||
|
||||
private boolean parseVariants(StringTokenIterator itr, ParseStatus sts) {
|
||||
if (itr.isDone() || sts.isError()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
boolean found = false;
|
||||
|
||||
while (!itr.isDone()) {
|
||||
String s = itr.current();
|
||||
if (!isVariant(s)) {
|
||||
break;
|
||||
}
|
||||
found = true;
|
||||
if (_variants.isEmpty()) {
|
||||
_variants = new ArrayList<String>(3);
|
||||
}
|
||||
_variants.add(s);
|
||||
sts._parseLength = itr.currentEnd();
|
||||
itr.next();
|
||||
}
|
||||
|
||||
return found;
|
||||
}
|
||||
|
||||
private boolean parseExtensions(StringTokenIterator itr, ParseStatus sts) {
|
||||
if (itr.isDone() || sts.isError()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
boolean found = false;
|
||||
|
||||
while (!itr.isDone()) {
|
||||
String s = itr.current();
|
||||
if (isExtensionSingleton(s)) {
|
||||
int start = itr.currentStart();
|
||||
String singleton = s;
|
||||
StringBuilder sb = new StringBuilder(singleton);
|
||||
|
||||
itr.next();
|
||||
while (!itr.isDone()) {
|
||||
s = itr.current();
|
||||
if (isExtensionSubtag(s)) {
|
||||
sb.append(SEP).append(s);
|
||||
sts._parseLength = itr.currentEnd();
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
itr.next();
|
||||
}
|
||||
|
||||
if (sts._parseLength <= start) {
|
||||
sts._errorIndex = start;
|
||||
sts._errorMsg = "Incomplete extension '" + singleton + "'";
|
||||
break;
|
||||
}
|
||||
|
||||
if (_extensions.size() == 0) {
|
||||
_extensions = new ArrayList<String>(4);
|
||||
}
|
||||
_extensions.add(sb.toString());
|
||||
found = true;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
return found;
|
||||
}
|
||||
|
||||
private boolean parsePrivateuse(StringTokenIterator itr, ParseStatus sts) {
|
||||
if (itr.isDone() || sts.isError()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
boolean found = false;
|
||||
|
||||
String s = itr.current();
|
||||
if (isPrivateusePrefix(s)) {
|
||||
int start = itr.currentStart();
|
||||
StringBuilder sb = new StringBuilder(s);
|
||||
|
||||
itr.next();
|
||||
while (!itr.isDone()) {
|
||||
s = itr.current();
|
||||
if (!isPrivateuseSubtag(s)) {
|
||||
break;
|
||||
}
|
||||
sb.append(SEP).append(s);
|
||||
sts._parseLength = itr.currentEnd();
|
||||
|
||||
itr.next();
|
||||
}
|
||||
|
||||
if (sts._parseLength <= start) {
|
||||
// need at least 1 private subtag
|
||||
sts._errorIndex = start;
|
||||
sts._errorMsg = "Incomplete privateuse";
|
||||
} else {
|
||||
_privateuse = sb.toString();
|
||||
found = true;
|
||||
}
|
||||
}
|
||||
|
||||
return found;
|
||||
}
|
||||
|
||||
public static LanguageTag parseLocale(BaseLocale baseLocale, LocaleExtensions localeExtensions) {
|
||||
LanguageTag tag = new LanguageTag();
|
||||
|
||||
String language = baseLocale.getLanguage();
|
||||
String script = baseLocale.getScript();
|
||||
String region = baseLocale.getRegion();
|
||||
String variant = baseLocale.getVariant();
|
||||
|
||||
String privuseVar = null; // store ill-formed variant subtags
|
||||
|
||||
if (language.length() == 0 || !isLanguage(language)) {
|
||||
tag._language = UNDETERMINED;
|
||||
} else {
|
||||
// Convert a deprecated language code used by Java to
|
||||
// a new code
|
||||
if (language.equals("iw")) {
|
||||
language = "he";
|
||||
} else if (language.equals("ji")) {
|
||||
language = "yi";
|
||||
} else if (language.equals("in")) {
|
||||
language = "id";
|
||||
}
|
||||
tag._language = language;
|
||||
}
|
||||
|
||||
if (script.length() > 0 && isScript(script)) {
|
||||
tag._script = canonicalizeScript(script);
|
||||
}
|
||||
|
||||
if (region.length() > 0 && isRegion(region)) {
|
||||
tag._region = canonicalizeRegion(region);
|
||||
}
|
||||
|
||||
// Special handling for no_NO_NY - use nn_NO for language tag
|
||||
if (tag._language.equals("no") && tag._region.equals("NO") && variant.equals("NY")) {
|
||||
tag._language = "nn";
|
||||
variant = "";
|
||||
}
|
||||
|
||||
if (variant.length() > 0) {
|
||||
List<String> variants = null;
|
||||
StringTokenIterator varitr = new StringTokenIterator(variant, BaseLocale.SEP);
|
||||
while (!varitr.isDone()) {
|
||||
String var = varitr.current();
|
||||
if (!isVariant(var)) {
|
||||
break;
|
||||
}
|
||||
if (variants == null) {
|
||||
variants = new ArrayList<String>();
|
||||
}
|
||||
variants.add(var); // Do not canonicalize!
|
||||
varitr.next();
|
||||
}
|
||||
if (variants != null) {
|
||||
tag._variants = variants;
|
||||
}
|
||||
if (!varitr.isDone()) {
|
||||
// ill-formed variant subtags
|
||||
StringBuilder buf = new StringBuilder();
|
||||
while (!varitr.isDone()) {
|
||||
String prvv = varitr.current();
|
||||
if (!isPrivateuseSubtag(prvv)) {
|
||||
// cannot use private use subtag - truncated
|
||||
break;
|
||||
}
|
||||
if (buf.length() > 0) {
|
||||
buf.append(SEP);
|
||||
}
|
||||
buf.append(prvv);
|
||||
varitr.next();
|
||||
}
|
||||
if (buf.length() > 0) {
|
||||
privuseVar = buf.toString();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
List<String> extensions = null;
|
||||
String privateuse = null;
|
||||
|
||||
Set<Character> locextKeys = localeExtensions.getKeys();
|
||||
for (Character locextKey : locextKeys) {
|
||||
Extension ext = localeExtensions.getExtension(locextKey);
|
||||
if (isPrivateusePrefixChar(locextKey.charValue())) {
|
||||
privateuse = ext.getValue();
|
||||
} else {
|
||||
if (extensions == null) {
|
||||
extensions = new ArrayList<String>();
|
||||
}
|
||||
extensions.add(locextKey.toString() + SEP + ext.getValue());
|
||||
}
|
||||
}
|
||||
|
||||
if (extensions != null) {
|
||||
tag._extensions = extensions;
|
||||
}
|
||||
|
||||
// append ill-formed variant subtags to private use
|
||||
if (privuseVar != null) {
|
||||
if (privateuse == null) {
|
||||
privateuse = PRIVUSE_VARIANT_PREFIX + SEP + privuseVar;
|
||||
} else {
|
||||
privateuse = privateuse + SEP + PRIVUSE_VARIANT_PREFIX + SEP + privuseVar.replace(BaseLocale.SEP, SEP);
|
||||
}
|
||||
}
|
||||
|
||||
if (privateuse != null) {
|
||||
tag._privateuse = privateuse;
|
||||
} else if (tag._language.length() == 0) {
|
||||
// use "und" if neither language nor privateuse is available
|
||||
tag._language = UNDETERMINED;
|
||||
}
|
||||
|
||||
return tag;
|
||||
}
|
||||
|
||||
//
|
||||
// Getter methods for language subtag fields
|
||||
//
|
||||
|
||||
public String getLanguage() {
|
||||
return _language;
|
||||
}
|
||||
|
||||
public List<String> getExtlangs() {
|
||||
return Collections.unmodifiableList(_extlangs);
|
||||
}
|
||||
|
||||
public String getScript() {
|
||||
return _script;
|
||||
}
|
||||
|
||||
public String getRegion() {
|
||||
return _region;
|
||||
}
|
||||
|
||||
public List<String> getVariants() {
|
||||
return Collections.unmodifiableList(_variants);
|
||||
}
|
||||
|
||||
public List<String> getExtensions() {
|
||||
return Collections.unmodifiableList(_extensions);
|
||||
}
|
||||
|
||||
public String getPrivateuse() {
|
||||
return _privateuse;
|
||||
}
|
||||
|
||||
//
|
||||
// Language subtag syntax checking methods
|
||||
//
|
||||
|
||||
public static boolean isLanguage(String s) {
|
||||
// language = 2*3ALPHA ; shortest ISO 639 code
|
||||
// ["-" extlang] ; sometimes followed by
|
||||
// ; extended language subtags
|
||||
// / 4ALPHA ; or reserved for future use
|
||||
// / 5*8ALPHA ; or registered language subtag
|
||||
return (s.length() >= 2) && (s.length() <= 8) && AsciiUtil.isAlphaString(s);
|
||||
}
|
||||
|
||||
public static boolean isExtlang(String s) {
|
||||
// extlang = 3ALPHA ; selected ISO 639 codes
|
||||
// *2("-" 3ALPHA) ; permanently reserved
|
||||
return (s.length() == 3) && AsciiUtil.isAlphaString(s);
|
||||
}
|
||||
|
||||
public static boolean isScript(String s) {
|
||||
// script = 4ALPHA ; ISO 15924 code
|
||||
return (s.length() == 4) && AsciiUtil.isAlphaString(s);
|
||||
}
|
||||
|
||||
public static boolean isRegion(String s) {
|
||||
// region = 2ALPHA ; ISO 3166-1 code
|
||||
// / 3DIGIT ; UN M.49 code
|
||||
return ((s.length() == 2) && AsciiUtil.isAlphaString(s))
|
||||
|| ((s.length() == 3) && AsciiUtil.isNumericString(s));
|
||||
}
|
||||
|
||||
public static boolean isVariant(String s) {
|
||||
// variant = 5*8alphanum ; registered variants
|
||||
// / (DIGIT 3alphanum)
|
||||
int len = s.length();
|
||||
if (len >= 5 && len <= 8) {
|
||||
return AsciiUtil.isAlphaNumericString(s);
|
||||
}
|
||||
if (len == 4) {
|
||||
return AsciiUtil.isNumeric(s.charAt(0))
|
||||
&& AsciiUtil.isAlphaNumeric(s.charAt(1))
|
||||
&& AsciiUtil.isAlphaNumeric(s.charAt(2))
|
||||
&& AsciiUtil.isAlphaNumeric(s.charAt(3));
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public static boolean isExtensionSingleton(String s) {
|
||||
// singleton = DIGIT ; 0 - 9
|
||||
// / %x41-57 ; A - W
|
||||
// / %x59-5A ; Y - Z
|
||||
// / %x61-77 ; a - w
|
||||
// / %x79-7A ; y - z
|
||||
|
||||
return (s.length() == 1)
|
||||
&& AsciiUtil.isAlphaString(s)
|
||||
&& !AsciiUtil.caseIgnoreMatch(PRIVATEUSE, s);
|
||||
}
|
||||
|
||||
public static boolean isExtensionSingletonChar(char c) {
|
||||
return isExtensionSingleton(String.valueOf(c));
|
||||
}
|
||||
|
||||
public static boolean isExtensionSubtag(String s) {
|
||||
// extension = singleton 1*("-" (2*8alphanum))
|
||||
return (s.length() >= 2) && (s.length() <= 8) && AsciiUtil.isAlphaNumericString(s);
|
||||
}
|
||||
|
||||
public static boolean isPrivateusePrefix(String s) {
|
||||
// privateuse = "x" 1*("-" (1*8alphanum))
|
||||
return (s.length() == 1)
|
||||
&& AsciiUtil.caseIgnoreMatch(PRIVATEUSE, s);
|
||||
}
|
||||
|
||||
public static boolean isPrivateusePrefixChar(char c) {
|
||||
return (AsciiUtil.caseIgnoreMatch(PRIVATEUSE, String.valueOf(c)));
|
||||
}
|
||||
|
||||
public static boolean isPrivateuseSubtag(String s) {
|
||||
// privateuse = "x" 1*("-" (1*8alphanum))
|
||||
return (s.length() >= 1) && (s.length() <= 8) && AsciiUtil.isAlphaNumericString(s);
|
||||
}
|
||||
|
||||
//
|
||||
// Language subtag canonicalization methods
|
||||
//
|
||||
|
||||
public static String canonicalizeLanguage(String s) {
|
||||
return AsciiUtil.toLowerString(s);
|
||||
}
|
||||
|
||||
public static String canonicalizeExtlang(String s) {
|
||||
return AsciiUtil.toLowerString(s);
|
||||
}
|
||||
|
||||
public static String canonicalizeScript(String s) {
|
||||
return AsciiUtil.toTitleString(s);
|
||||
}
|
||||
|
||||
public static String canonicalizeRegion(String s) {
|
||||
return AsciiUtil.toUpperString(s);
|
||||
}
|
||||
|
||||
public static String canonicalizeVariant(String s) {
|
||||
return AsciiUtil.toLowerString(s);
|
||||
}
|
||||
|
||||
public static String canonicalizeExtension(String s) {
|
||||
return AsciiUtil.toLowerString(s);
|
||||
}
|
||||
|
||||
public static String canonicalizeExtensionSingleton(String s) {
|
||||
return AsciiUtil.toLowerString(s);
|
||||
}
|
||||
|
||||
public static String canonicalizeExtensionSubtag(String s) {
|
||||
return AsciiUtil.toLowerString(s);
|
||||
}
|
||||
|
||||
public static String canonicalizePrivateuse(String s) {
|
||||
return AsciiUtil.toLowerString(s);
|
||||
}
|
||||
|
||||
public static String canonicalizePrivateuseSubtag(String s) {
|
||||
return AsciiUtil.toLowerString(s);
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
|
||||
if (_language.length() > 0) {
|
||||
sb.append(_language);
|
||||
|
||||
for (String extlang : _extlangs) {
|
||||
sb.append(SEP).append(extlang);
|
||||
}
|
||||
|
||||
if (_script.length() > 0) {
|
||||
sb.append(SEP).append(_script);
|
||||
}
|
||||
|
||||
if (_region.length() > 0) {
|
||||
sb.append(SEP).append(_region);
|
||||
}
|
||||
|
||||
for (String variant : _extlangs) {
|
||||
sb.append(SEP).append(variant);
|
||||
}
|
||||
|
||||
for (String extension : _extensions) {
|
||||
sb.append(SEP).append(extension);
|
||||
}
|
||||
}
|
||||
if (_privateuse.length() > 0) {
|
||||
if (sb.length() > 0) {
|
||||
sb.append(SEP);
|
||||
}
|
||||
sb.append(_privateuse);
|
||||
}
|
||||
|
||||
return sb.toString();
|
||||
}
|
||||
}
|
246
jdk/src/share/classes/sun/util/locale/LocaleExtensions.java
Normal file
246
jdk/src/share/classes/sun/util/locale/LocaleExtensions.java
Normal file
@ -0,0 +1,246 @@
|
||||
/*
|
||||
* Copyright (c) 2010, 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
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
/*
|
||||
*******************************************************************************
|
||||
* Copyright (C) 2009-2010, International Business Machines Corporation and *
|
||||
* others. All Rights Reserved. *
|
||||
*******************************************************************************
|
||||
*/
|
||||
package sun.util.locale;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.Set;
|
||||
import java.util.SortedMap;
|
||||
import java.util.TreeMap;
|
||||
import java.util.TreeSet;
|
||||
|
||||
import sun.util.locale.InternalLocaleBuilder.CaseInsensitiveChar;
|
||||
import sun.util.locale.InternalLocaleBuilder.CaseInsensitiveString;
|
||||
|
||||
|
||||
public class LocaleExtensions {
|
||||
|
||||
private SortedMap<Character, Extension> _map;
|
||||
private String _id;
|
||||
|
||||
private static final SortedMap<Character, Extension> EMPTY_MAP =
|
||||
Collections.unmodifiableSortedMap(new TreeMap<Character, Extension>());
|
||||
|
||||
public static final LocaleExtensions EMPTY_EXTENSIONS;
|
||||
public static final LocaleExtensions CALENDAR_JAPANESE;
|
||||
public static final LocaleExtensions NUMBER_THAI;
|
||||
|
||||
static {
|
||||
EMPTY_EXTENSIONS = new LocaleExtensions();
|
||||
EMPTY_EXTENSIONS._id = "";
|
||||
EMPTY_EXTENSIONS._map = EMPTY_MAP;
|
||||
|
||||
CALENDAR_JAPANESE = new LocaleExtensions();
|
||||
CALENDAR_JAPANESE._id = "u-ca-japanese";
|
||||
CALENDAR_JAPANESE._map = new TreeMap<Character, Extension>();
|
||||
CALENDAR_JAPANESE._map.put(Character.valueOf(UnicodeLocaleExtension.SINGLETON), UnicodeLocaleExtension.CA_JAPANESE);
|
||||
|
||||
NUMBER_THAI = new LocaleExtensions();
|
||||
NUMBER_THAI._id = "u-nu-thai";
|
||||
NUMBER_THAI._map = new TreeMap<Character, Extension>();
|
||||
NUMBER_THAI._map.put(Character.valueOf(UnicodeLocaleExtension.SINGLETON), UnicodeLocaleExtension.NU_THAI);
|
||||
}
|
||||
|
||||
private LocaleExtensions() {
|
||||
}
|
||||
|
||||
/*
|
||||
* Package local constructor, only used by InternalLocaleBuilder.
|
||||
*/
|
||||
LocaleExtensions(Map<CaseInsensitiveChar, String> extensions,
|
||||
Set<CaseInsensitiveString> uattributes, Map<CaseInsensitiveString, String> ukeywords) {
|
||||
boolean hasExtension = (extensions != null && extensions.size() > 0);
|
||||
boolean hasUAttributes = (uattributes != null && uattributes.size() > 0);
|
||||
boolean hasUKeywords = (ukeywords != null && ukeywords.size() > 0);
|
||||
|
||||
if (!hasExtension && !hasUAttributes && !hasUKeywords) {
|
||||
_map = EMPTY_MAP;
|
||||
_id = "";
|
||||
return;
|
||||
}
|
||||
|
||||
// Build extension map
|
||||
_map = new TreeMap<Character, Extension>();
|
||||
if (hasExtension) {
|
||||
for (Entry<CaseInsensitiveChar, String> ext : extensions.entrySet()) {
|
||||
char key = AsciiUtil.toLower(ext.getKey().value());
|
||||
String value = ext.getValue();
|
||||
|
||||
if (LanguageTag.isPrivateusePrefixChar(key)) {
|
||||
// we need to exclude special variant in privuateuse, e.g. "x-abc-lvariant-DEF"
|
||||
value = InternalLocaleBuilder.removePrivateuseVariant(value);
|
||||
if (value == null) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
Extension e = new Extension(key, AsciiUtil.toLowerString(value));
|
||||
_map.put(Character.valueOf(key), e);
|
||||
}
|
||||
}
|
||||
|
||||
if (hasUAttributes || hasUKeywords) {
|
||||
TreeSet<String> uaset = null;
|
||||
TreeMap<String, String> ukmap = null;
|
||||
|
||||
if (hasUAttributes) {
|
||||
uaset = new TreeSet<String>();
|
||||
for (CaseInsensitiveString cis : uattributes) {
|
||||
uaset.add(AsciiUtil.toLowerString(cis.value()));
|
||||
}
|
||||
}
|
||||
|
||||
if (hasUKeywords) {
|
||||
ukmap = new TreeMap<String, String>();
|
||||
for (Entry<CaseInsensitiveString, String> kwd : ukeywords.entrySet()) {
|
||||
String key = AsciiUtil.toLowerString(kwd.getKey().value());
|
||||
String type = AsciiUtil.toLowerString(kwd.getValue());
|
||||
ukmap.put(key, type);
|
||||
}
|
||||
}
|
||||
|
||||
UnicodeLocaleExtension ule = new UnicodeLocaleExtension(uaset, ukmap);
|
||||
_map.put(Character.valueOf(UnicodeLocaleExtension.SINGLETON), ule);
|
||||
}
|
||||
|
||||
if (_map.size() == 0) {
|
||||
// this could happen when only privuateuse with special variant
|
||||
_map = EMPTY_MAP;
|
||||
_id = "";
|
||||
} else {
|
||||
_id = toID(_map);
|
||||
}
|
||||
}
|
||||
|
||||
public Set<Character> getKeys() {
|
||||
return Collections.unmodifiableSet(_map.keySet());
|
||||
}
|
||||
|
||||
public Extension getExtension(Character key) {
|
||||
return _map.get(Character.valueOf(AsciiUtil.toLower(key.charValue())));
|
||||
}
|
||||
|
||||
public String getExtensionValue(Character key) {
|
||||
Extension ext = _map.get(Character.valueOf(AsciiUtil.toLower(key.charValue())));
|
||||
if (ext == null) {
|
||||
return null;
|
||||
}
|
||||
return ext.getValue();
|
||||
}
|
||||
|
||||
public Set<String> getUnicodeLocaleAttributes() {
|
||||
Extension ext = _map.get(Character.valueOf(UnicodeLocaleExtension.SINGLETON));
|
||||
if (ext == null) {
|
||||
return Collections.emptySet();
|
||||
}
|
||||
assert (ext instanceof UnicodeLocaleExtension);
|
||||
return ((UnicodeLocaleExtension)ext).getUnicodeLocaleAttributes();
|
||||
}
|
||||
|
||||
public Set<String> getUnicodeLocaleKeys() {
|
||||
Extension ext = _map.get(Character.valueOf(UnicodeLocaleExtension.SINGLETON));
|
||||
if (ext == null) {
|
||||
return Collections.emptySet();
|
||||
}
|
||||
assert (ext instanceof UnicodeLocaleExtension);
|
||||
return ((UnicodeLocaleExtension)ext).getUnicodeLocaleKeys();
|
||||
}
|
||||
|
||||
public String getUnicodeLocaleType(String unicodeLocaleKey) {
|
||||
Extension ext = _map.get(Character.valueOf(UnicodeLocaleExtension.SINGLETON));
|
||||
if (ext == null) {
|
||||
return null;
|
||||
}
|
||||
assert (ext instanceof UnicodeLocaleExtension);
|
||||
return ((UnicodeLocaleExtension)ext).getUnicodeLocaleType(AsciiUtil.toLowerString(unicodeLocaleKey));
|
||||
}
|
||||
|
||||
public boolean isEmpty() {
|
||||
return _map.isEmpty();
|
||||
}
|
||||
|
||||
public static boolean isValidKey(char c) {
|
||||
return LanguageTag.isExtensionSingletonChar(c) || LanguageTag.isPrivateusePrefixChar(c);
|
||||
}
|
||||
|
||||
public static boolean isValidUnicodeLocaleKey(String ukey) {
|
||||
return UnicodeLocaleExtension.isKey(ukey);
|
||||
}
|
||||
|
||||
private static String toID(SortedMap<Character, Extension> map) {
|
||||
StringBuilder buf = new StringBuilder();
|
||||
Extension privuse = null;
|
||||
for (Entry<Character, Extension> entry : map.entrySet()) {
|
||||
char singleton = entry.getKey().charValue();
|
||||
Extension extension = entry.getValue();
|
||||
if (LanguageTag.isPrivateusePrefixChar(singleton)) {
|
||||
privuse = extension;
|
||||
} else {
|
||||
if (buf.length() > 0) {
|
||||
buf.append(LanguageTag.SEP);
|
||||
}
|
||||
buf.append(extension);
|
||||
}
|
||||
}
|
||||
if (privuse != null) {
|
||||
if (buf.length() > 0) {
|
||||
buf.append(LanguageTag.SEP);
|
||||
}
|
||||
buf.append(privuse);
|
||||
}
|
||||
return buf.toString();
|
||||
}
|
||||
|
||||
|
||||
public String toString() {
|
||||
return _id;
|
||||
}
|
||||
|
||||
public String getID() {
|
||||
return _id;
|
||||
}
|
||||
|
||||
public int hashCode() {
|
||||
return _id.hashCode();
|
||||
}
|
||||
|
||||
public boolean equals(Object other) {
|
||||
if (this == other) {
|
||||
return true;
|
||||
}
|
||||
if (!(other instanceof LocaleExtensions)) {
|
||||
return false;
|
||||
}
|
||||
return this._id.equals(((LocaleExtensions)other)._id);
|
||||
}
|
||||
}
|
108
jdk/src/share/classes/sun/util/locale/LocaleObjectCache.java
Normal file
108
jdk/src/share/classes/sun/util/locale/LocaleObjectCache.java
Normal file
@ -0,0 +1,108 @@
|
||||
/*
|
||||
* Copyright (c) 2010, 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
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
/*
|
||||
*******************************************************************************
|
||||
* Copyright (C) 2009-2010, International Business Machines Corporation and *
|
||||
* others. All Rights Reserved. *
|
||||
*******************************************************************************
|
||||
*/
|
||||
package sun.util.locale;
|
||||
|
||||
import java.lang.ref.ReferenceQueue;
|
||||
import java.lang.ref.SoftReference;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
public abstract class LocaleObjectCache<K, V> {
|
||||
private ConcurrentHashMap<K, CacheEntry<K, V>> _map;
|
||||
private ReferenceQueue<V> _queue = new ReferenceQueue<V>();
|
||||
|
||||
public LocaleObjectCache() {
|
||||
this(16, 0.75f, 16);
|
||||
}
|
||||
|
||||
public LocaleObjectCache(int initialCapacity, float loadFactor, int concurrencyLevel) {
|
||||
_map = new ConcurrentHashMap<K, CacheEntry<K, V>>(initialCapacity, loadFactor, concurrencyLevel);
|
||||
}
|
||||
|
||||
public V get(K key) {
|
||||
V value = null;
|
||||
|
||||
cleanStaleEntries();
|
||||
CacheEntry<K, V> entry = _map.get(key);
|
||||
if (entry != null) {
|
||||
value = entry.get();
|
||||
}
|
||||
if (value == null) {
|
||||
key = normalizeKey(key);
|
||||
V newVal = createObject(key);
|
||||
if (key == null || newVal == null) {
|
||||
// subclass must return non-null key/value object
|
||||
return null;
|
||||
}
|
||||
|
||||
CacheEntry<K, V> newEntry = new CacheEntry<K, V>(key, newVal, _queue);
|
||||
|
||||
while (value == null) {
|
||||
cleanStaleEntries();
|
||||
entry = _map.putIfAbsent(key, newEntry);
|
||||
if (entry == null) {
|
||||
value = newVal;
|
||||
break;
|
||||
} else {
|
||||
value = entry.get();
|
||||
}
|
||||
}
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private void cleanStaleEntries() {
|
||||
CacheEntry<K, V> entry;
|
||||
while ((entry = (CacheEntry<K, V>)_queue.poll()) != null) {
|
||||
_map.remove(entry.getKey());
|
||||
}
|
||||
}
|
||||
|
||||
protected abstract V createObject(K key);
|
||||
|
||||
protected K normalizeKey(K key) {
|
||||
return key;
|
||||
}
|
||||
|
||||
private static class CacheEntry<K, V> extends SoftReference<V> {
|
||||
private K _key;
|
||||
|
||||
CacheEntry(K key, V value, ReferenceQueue<V> queue) {
|
||||
super(value, queue);
|
||||
_key = key;
|
||||
}
|
||||
|
||||
K getKey() {
|
||||
return _key;
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,52 @@
|
||||
/*
|
||||
* Copyright (c) 2010, 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
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
/*
|
||||
*******************************************************************************
|
||||
* Copyright (C) 2009, International Business Machines Corporation and *
|
||||
* others. All Rights Reserved. *
|
||||
*******************************************************************************
|
||||
*/
|
||||
package sun.util.locale;
|
||||
|
||||
public class LocaleSyntaxException extends Exception {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private int _index = -1;
|
||||
|
||||
public LocaleSyntaxException(String msg) {
|
||||
this(msg, 0);
|
||||
}
|
||||
|
||||
public LocaleSyntaxException(String msg, int errorIndex) {
|
||||
super(msg);
|
||||
_index = errorIndex;
|
||||
}
|
||||
|
||||
public int getErrorIndex() {
|
||||
return _index;
|
||||
}
|
||||
}
|
60
jdk/src/share/classes/sun/util/locale/ParseStatus.java
Normal file
60
jdk/src/share/classes/sun/util/locale/ParseStatus.java
Normal file
@ -0,0 +1,60 @@
|
||||
/*
|
||||
* Copyright (c) 2010, 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
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
/*
|
||||
*******************************************************************************
|
||||
* Copyright (C) 2010, International Business Machines Corporation and *
|
||||
* others. All Rights Reserved. *
|
||||
*******************************************************************************
|
||||
*/
|
||||
package sun.util.locale;
|
||||
|
||||
public class ParseStatus {
|
||||
int _parseLength = 0;
|
||||
int _errorIndex = -1;
|
||||
String _errorMsg = null;
|
||||
|
||||
public void reset() {
|
||||
_parseLength = 0;
|
||||
_errorIndex = -1;
|
||||
_errorMsg = null;
|
||||
}
|
||||
|
||||
public boolean isError() {
|
||||
return (_errorIndex >= 0);
|
||||
}
|
||||
|
||||
public int getErrorIndex() {
|
||||
return _errorIndex;
|
||||
}
|
||||
|
||||
public int getParseLength() {
|
||||
return _parseLength;
|
||||
}
|
||||
|
||||
public String getErrorMessage() {
|
||||
return _errorMsg;
|
||||
}
|
||||
}
|
117
jdk/src/share/classes/sun/util/locale/StringTokenIterator.java
Normal file
117
jdk/src/share/classes/sun/util/locale/StringTokenIterator.java
Normal file
@ -0,0 +1,117 @@
|
||||
/*
|
||||
* Copyright (c) 2010, 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
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
/*
|
||||
*******************************************************************************
|
||||
* Copyright (C) 2009, International Business Machines Corporation and *
|
||||
* others. All Rights Reserved. *
|
||||
*******************************************************************************
|
||||
*/
|
||||
package sun.util.locale;
|
||||
|
||||
public class StringTokenIterator {
|
||||
private String _text;
|
||||
private String _dlms;
|
||||
|
||||
private String _token;
|
||||
private int _start;
|
||||
private int _end;
|
||||
private boolean _done;
|
||||
|
||||
public StringTokenIterator(String text, String dlms) {
|
||||
_text = text;
|
||||
_dlms = dlms;
|
||||
setStart(0);
|
||||
}
|
||||
|
||||
public String first() {
|
||||
setStart(0);
|
||||
return _token;
|
||||
}
|
||||
|
||||
public String current() {
|
||||
return _token;
|
||||
}
|
||||
|
||||
public int currentStart() {
|
||||
return _start;
|
||||
}
|
||||
|
||||
public int currentEnd() {
|
||||
return _end;
|
||||
}
|
||||
|
||||
public boolean isDone() {
|
||||
return _done;
|
||||
}
|
||||
|
||||
public String next() {
|
||||
if (hasNext()) {
|
||||
_start = _end + 1;
|
||||
_end = nextDelimiter(_start);
|
||||
_token = _text.substring(_start, _end);
|
||||
} else {
|
||||
_start = _end;
|
||||
_token = null;
|
||||
_done = true;
|
||||
}
|
||||
return _token;
|
||||
}
|
||||
|
||||
public boolean hasNext() {
|
||||
return (_end < _text.length());
|
||||
}
|
||||
|
||||
public StringTokenIterator setStart(int offset) {
|
||||
if (offset > _text.length()) {
|
||||
throw new IndexOutOfBoundsException();
|
||||
}
|
||||
_start = offset;
|
||||
_end = nextDelimiter(_start);
|
||||
_token = _text.substring(_start, _end);
|
||||
_done = false;
|
||||
return this;
|
||||
}
|
||||
|
||||
public StringTokenIterator setText(String text) {
|
||||
_text = text;
|
||||
setStart(0);
|
||||
return this;
|
||||
}
|
||||
|
||||
private int nextDelimiter(int start) {
|
||||
int idx = start;
|
||||
outer: while (idx < _text.length()) {
|
||||
char c = _text.charAt(idx);
|
||||
for (int i = 0; i < _dlms.length(); i++) {
|
||||
if (c == _dlms.charAt(i)) {
|
||||
break outer;
|
||||
}
|
||||
}
|
||||
idx++;
|
||||
}
|
||||
return idx;
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,127 @@
|
||||
/*
|
||||
* Copyright (c) 2010, 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
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
/*
|
||||
*******************************************************************************
|
||||
* Copyright (C) 2009-2010, International Business Machines Corporation and *
|
||||
* others. All Rights Reserved. *
|
||||
*******************************************************************************
|
||||
*/
|
||||
package sun.util.locale;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.Set;
|
||||
import java.util.SortedMap;
|
||||
import java.util.SortedSet;
|
||||
import java.util.TreeMap;
|
||||
import java.util.TreeSet;
|
||||
|
||||
public class UnicodeLocaleExtension extends Extension {
|
||||
public static final char SINGLETON = 'u';
|
||||
|
||||
private static final SortedSet<String> EMPTY_SORTED_SET = new TreeSet<String>();
|
||||
private static final SortedMap<String, String> EMPTY_SORTED_MAP = new TreeMap<String, String>();
|
||||
|
||||
private SortedSet<String> _attributes = EMPTY_SORTED_SET;
|
||||
private SortedMap<String, String> _keywords = EMPTY_SORTED_MAP;
|
||||
|
||||
public static final UnicodeLocaleExtension CA_JAPANESE;
|
||||
public static final UnicodeLocaleExtension NU_THAI;
|
||||
|
||||
static {
|
||||
CA_JAPANESE = new UnicodeLocaleExtension();
|
||||
CA_JAPANESE._keywords = new TreeMap<String, String>();
|
||||
CA_JAPANESE._keywords.put("ca", "japanese");
|
||||
CA_JAPANESE._value = "ca-japanese";
|
||||
|
||||
NU_THAI = new UnicodeLocaleExtension();
|
||||
NU_THAI._keywords = new TreeMap<String, String>();
|
||||
NU_THAI._keywords.put("nu", "thai");
|
||||
NU_THAI._value = "nu-thai";
|
||||
}
|
||||
|
||||
private UnicodeLocaleExtension() {
|
||||
super(SINGLETON);
|
||||
}
|
||||
|
||||
UnicodeLocaleExtension(SortedSet<String> attributes, SortedMap<String, String> keywords) {
|
||||
this();
|
||||
if (attributes != null && attributes.size() > 0) {
|
||||
_attributes = attributes;
|
||||
}
|
||||
if (keywords != null && keywords.size() > 0) {
|
||||
_keywords = keywords;
|
||||
}
|
||||
|
||||
if (_attributes.size() > 0 || _keywords.size() > 0) {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
for (String attribute : _attributes) {
|
||||
sb.append(LanguageTag.SEP).append(attribute);
|
||||
}
|
||||
for (Entry<String, String> keyword : _keywords.entrySet()) {
|
||||
String key = keyword.getKey();
|
||||
String value = keyword.getValue();
|
||||
|
||||
sb.append(LanguageTag.SEP).append(key);
|
||||
if (value.length() > 0) {
|
||||
sb.append(LanguageTag.SEP).append(value);
|
||||
}
|
||||
}
|
||||
_value = sb.substring(1); // skip leading '-'
|
||||
}
|
||||
}
|
||||
|
||||
public Set<String> getUnicodeLocaleAttributes() {
|
||||
return Collections.unmodifiableSet(_attributes);
|
||||
}
|
||||
|
||||
public Set<String> getUnicodeLocaleKeys() {
|
||||
return Collections.unmodifiableSet(_keywords.keySet());
|
||||
}
|
||||
|
||||
public String getUnicodeLocaleType(String unicodeLocaleKey) {
|
||||
return _keywords.get(unicodeLocaleKey);
|
||||
}
|
||||
|
||||
public static boolean isSingletonChar(char c) {
|
||||
return (SINGLETON == AsciiUtil.toLower(c));
|
||||
}
|
||||
|
||||
public static boolean isAttribute(String s) {
|
||||
// 3*8alphanum
|
||||
return (s.length() >= 3) && (s.length() <= 8) && AsciiUtil.isAlphaNumericString(s);
|
||||
}
|
||||
|
||||
public static boolean isKey(String s) {
|
||||
// 2alphanum
|
||||
return (s.length() == 2) && AsciiUtil.isAlphaNumericString(s);
|
||||
}
|
||||
|
||||
public static boolean isTypeSubtag(String s) {
|
||||
// 3*8alphanum
|
||||
return (s.length() >= 3) && (s.length() <= 8) && AsciiUtil.isAlphaNumericString(s);
|
||||
}
|
||||
}
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 1996, 2005, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 1996, 2010, 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
|
||||
@ -177,6 +177,11 @@ public class LocaleData {
|
||||
|
||||
for (Iterator<Locale> l = candidates.iterator(); l.hasNext(); ) {
|
||||
String lstr = l.next().toString();
|
||||
/* truncate extra segment introduced by Java 7 for script and extesions */
|
||||
int idx = lstr.indexOf("_#");
|
||||
if (idx >= 0) {
|
||||
lstr = lstr.substring(0, idx);
|
||||
}
|
||||
/* Every locale string in the locale string list returned from
|
||||
the above getSupportedLocaleString is enclosed
|
||||
within two white spaces so that we could check some locale
|
||||
|
@ -228,6 +228,157 @@ za=Zhuang
|
||||
zh=Chinese
|
||||
zu=Zulu
|
||||
|
||||
# script names
|
||||
# key is ISO 15924 script code
|
||||
|
||||
Arab=Arabic
|
||||
Armi=Imperial Aramaic
|
||||
Armn=Armenian
|
||||
Avst=Avestan
|
||||
Bali=Balinese
|
||||
Bamu=Bamum
|
||||
Bass=Bassa Vah
|
||||
Batk=Batak
|
||||
Beng=Bengali
|
||||
Blis=Blissymbols
|
||||
Bopo=Bopomofo
|
||||
Brah=Brahmi
|
||||
Brai=Braille
|
||||
Bugi=Buginese
|
||||
Buhd=Buhid
|
||||
Cakm=Chakma
|
||||
Cans=Unified Canadian Aboriginal Syllabics
|
||||
Cari=Carian
|
||||
Cham=Cham
|
||||
Cher=Cherokee
|
||||
Cirt=Cirth
|
||||
Copt=Coptic
|
||||
Cprt=Cypriot
|
||||
Cyrl=Cyrillic
|
||||
Cyrs=Old Church Slavonic Cyrillic
|
||||
Deva=Devanagari
|
||||
Dsrt=Deseret
|
||||
Dupl=Duployan shorthand
|
||||
Egyd=Egyptian demotic
|
||||
Egyh=Egyptian hieratic
|
||||
Egyp=Egyptian hieroglyphs
|
||||
Elba=Elbasan
|
||||
Ethi=Ethiopic
|
||||
Geok=Khutsuri
|
||||
Geor=Georgian
|
||||
Glag=Glagolitic
|
||||
Goth=Gothic
|
||||
Gran=Grantha
|
||||
Grek=Greek
|
||||
Gujr=Gujarati
|
||||
Guru=Gurmukhi
|
||||
Hang=Hangul
|
||||
Hani=Han
|
||||
Hano=Hanunoo
|
||||
Hans=Simplified Han
|
||||
Hant=Traditional Han
|
||||
Hebr=Hebrew
|
||||
Hira=Hiragana
|
||||
Hmng=Pahawh Hmong
|
||||
Hrkt=Katakana or Hiragana
|
||||
Hung=Old Hungarian
|
||||
Inds=Indus
|
||||
Ital=Old Italic
|
||||
Java=Javanese
|
||||
Jpan=Japanese
|
||||
Kali=Kayah Li
|
||||
Kana=Katakana
|
||||
Khar=Kharoshthi
|
||||
Khmr=Khmer
|
||||
Knda=Kannada
|
||||
Kore=Korean
|
||||
Kpel=Kpelle
|
||||
Kthi=Kaithi
|
||||
Lana=Tai Tham
|
||||
Laoo=Lao
|
||||
Latf=Fraktur Latin
|
||||
Latg=Gaelic Latin
|
||||
Latn=Latin
|
||||
Lepc=Lepcha
|
||||
Limb=Limbu
|
||||
Lina=Linear A
|
||||
Linb=Linear B
|
||||
Lisu=Lisu
|
||||
Loma=Loma
|
||||
Lyci=Lycian
|
||||
Lydi=Lydian
|
||||
Mand=Mandaic
|
||||
Mani=Manichaean
|
||||
Maya=Mayan hieroglyphs
|
||||
Mend=Mende
|
||||
Merc=Meroitic Cursive
|
||||
Mero=Meroitic
|
||||
Mlym=Malayalam
|
||||
Mong=Mongolian
|
||||
Moon=Moon
|
||||
Mtei=Meitei Mayek
|
||||
Mymr=Myanmar
|
||||
Narb=Old North Arabian
|
||||
Nbat=Nabataean
|
||||
Nkgb=Nakhi Geba
|
||||
Nkoo=N\u2019Ko
|
||||
Ogam=Ogham
|
||||
Olck=Ol Chiki
|
||||
Orkh=Orkhon
|
||||
Orya=Oriya
|
||||
Osma=Osmanya
|
||||
Palm=Palmyrene
|
||||
Perm=Old Permic
|
||||
Phag=Phags-pa
|
||||
Phli=Inscriptional Pahlavi
|
||||
Phlp=Psalter Pahlavi
|
||||
Phlv=Book Pahlavi
|
||||
Phnx=Phoenician
|
||||
Plrd=Miao
|
||||
Prti=Inscriptional Parthian
|
||||
Rjng=Rejang
|
||||
Roro=Rongorongo
|
||||
Runr=Runic
|
||||
Samr=Samaritan
|
||||
Sara=Sarati
|
||||
Sarb=Old South Arabian
|
||||
Saur=Saurashtra
|
||||
Sgnw=SignWriting
|
||||
Shaw=Shavian
|
||||
Sind=Sindhi
|
||||
Sinh=Sinhala
|
||||
Sund=Sundanese
|
||||
Sylo=Syloti Nagri
|
||||
Syrc=Syriac
|
||||
Syre=Estrangelo Syriac
|
||||
Syrj=Western Syriac
|
||||
Syrn=Eastern Syriac
|
||||
Tagb=Tagbanwa
|
||||
Tale=Tai Le
|
||||
Talu=New Tai Lue
|
||||
Taml=Tamil
|
||||
Tavt=Tai Viet
|
||||
Telu=Telugu
|
||||
Teng=Tengwar
|
||||
Tfng=Tifinagh
|
||||
Tglg=Tagalog
|
||||
Thaa=Thaana
|
||||
Thai=Thai
|
||||
Tibt=Tibetan
|
||||
Ugar=Ugaritic
|
||||
Vaii=Vai
|
||||
Visp=Visible Speech
|
||||
Wara=Warang Citi
|
||||
Xpeo=Old Persian
|
||||
Xsux=Sumero-Akkadian Cuneiform
|
||||
Yiii=Yi
|
||||
Zinh=Inherited script
|
||||
Zmth=Mathematical Notation
|
||||
Zsym=Symbols
|
||||
Zxxx=Unwritten
|
||||
Zyyy=Undetermined script
|
||||
Zzzz=Uncoded script
|
||||
|
||||
# country names
|
||||
# key is ISO 3166 country code
|
||||
|
||||
@ -479,6 +630,39 @@ ZA=South Africa
|
||||
ZM=Zambia
|
||||
ZW=Zimbabwe
|
||||
|
||||
# territory names
|
||||
# key is UN M.49 country and area code
|
||||
|
||||
001=World
|
||||
002=Africa
|
||||
003=North America
|
||||
005=South America
|
||||
009=Oceania
|
||||
011=Western Africa
|
||||
013=Central America
|
||||
014=Eastern Africa
|
||||
015=Northern Africa
|
||||
017=Middle Africa
|
||||
018=Southern Africa
|
||||
019=Americas
|
||||
021=Northern America
|
||||
029=Caribbean
|
||||
030=Eastern Asia
|
||||
034=Southern Asia
|
||||
035=South-Eastern Asia
|
||||
039=Southern Europe
|
||||
053=Australia and New Zealand
|
||||
054=Melanesia
|
||||
057=Micronesian Region
|
||||
061=Polynesia
|
||||
142=Asia
|
||||
143=Central Asia
|
||||
145=Western Asia
|
||||
150=Europe
|
||||
151=Eastern Europe
|
||||
154=Northern Europe
|
||||
155=Western Europe
|
||||
419=Latin America and the Caribbean
|
||||
|
||||
# variant names
|
||||
# key is %%variant
|
||||
|
@ -227,6 +227,12 @@ za=\u85cf\u6587
|
||||
zh=\u4e2d\u6587
|
||||
zu=\u7956\u9c81\u6587
|
||||
|
||||
# script names
|
||||
# key is ISO 15924 script code
|
||||
|
||||
Hans=\u7b80\u4f53\u4e2d\u6587
|
||||
Hant=\u7e41\u4f53\u4e2d\u6587
|
||||
|
||||
# country names
|
||||
# key is ISO 3166 country code
|
||||
|
||||
|
@ -227,6 +227,12 @@ za=\u58ef\u6587
|
||||
zh=\u4e2d\u6587
|
||||
zu=\u7956\u9b6f\u6587
|
||||
|
||||
# script names
|
||||
# key is ISO 15924 script code
|
||||
|
||||
Hans=\u7c21\u9ad4\u4e2d\u6587
|
||||
Hant=\u7e41\u9ad4\u4e2d\u6587
|
||||
|
||||
# country names
|
||||
# key is ISO 3166 country code
|
||||
|
||||
|
1293
jdk/test/java/util/Locale/LocaleEnhanceTest.java
Normal file
1293
jdk/test/java/util/Locale/LocaleEnhanceTest.java
Normal file
File diff suppressed because it is too large
Load Diff
@ -1,10 +1,12 @@
|
||||
/*
|
||||
* Copyright (c) 2007, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2010, 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.
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
@ -20,6 +22,7 @@
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
/*
|
||||
*
|
||||
*
|
||||
@ -112,6 +115,8 @@ public class LocaleTestFmwk {
|
||||
prompt = true;
|
||||
} else if (args[i].equals("-nothrow")) {
|
||||
nothrow = true;
|
||||
} else if (args[i].equals("-exitcode")) {
|
||||
exitcode = true;
|
||||
} else {
|
||||
Object m = testMethods.get( args[i] );
|
||||
if( m != null ) {
|
||||
@ -165,7 +170,12 @@ public class LocaleTestFmwk {
|
||||
}
|
||||
}
|
||||
if (nothrow) {
|
||||
System.exit(errorCount);
|
||||
if (exitcode) {
|
||||
System.exit(errorCount);
|
||||
}
|
||||
if (errorCount > 0) {
|
||||
throw new IllegalArgumentException("encountered " + errorCount + " errors");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -235,7 +245,7 @@ public class LocaleTestFmwk {
|
||||
*/
|
||||
void usage() {
|
||||
System.out.println(getClass().getName() +
|
||||
": [-verbose] [-nothrow] [-prompt] [test names]");
|
||||
": [-verbose] [-nothrow] [-exitcode] [-prompt] [test names]");
|
||||
|
||||
System.out.println("test names:");
|
||||
Enumeration methodNames = testMethods.keys();
|
||||
@ -246,6 +256,7 @@ public class LocaleTestFmwk {
|
||||
|
||||
private boolean prompt = false;
|
||||
private boolean nothrow = false;
|
||||
private boolean exitcode = false;
|
||||
protected boolean verbose = false;
|
||||
|
||||
private PrintWriter log;
|
||||
|
292
jdk/test/java/util/Locale/icuLocales.txt
Normal file
292
jdk/test/java/util/Locale/icuLocales.txt
Normal file
@ -0,0 +1,292 @@
|
||||
af
|
||||
af-NA
|
||||
af-ZA
|
||||
am
|
||||
am-ET
|
||||
ar
|
||||
ar-AE
|
||||
ar-BH
|
||||
ar-DZ
|
||||
ar-EG
|
||||
ar-IQ
|
||||
ar-JO
|
||||
ar-KW
|
||||
ar-LB
|
||||
ar-LY
|
||||
ar-MA
|
||||
ar-OM
|
||||
ar-QA
|
||||
ar-SA
|
||||
ar-SD
|
||||
ar-SY
|
||||
ar-TN
|
||||
ar-YE
|
||||
as
|
||||
as-IN
|
||||
az
|
||||
az-Cyrl
|
||||
az-Cyrl-AZ
|
||||
az-Latn
|
||||
az-Latn-AZ
|
||||
be
|
||||
be-BY
|
||||
bg
|
||||
bg-BG
|
||||
bn
|
||||
bn-BD
|
||||
bn-IN
|
||||
bo
|
||||
bo-CN
|
||||
bo-IN
|
||||
ca
|
||||
ca-ES
|
||||
cs
|
||||
cs-CZ
|
||||
cy
|
||||
cy-GB
|
||||
da
|
||||
da-DK
|
||||
de
|
||||
de-AT
|
||||
de-BE
|
||||
de-CH
|
||||
de-DE
|
||||
de-LI
|
||||
de-LU
|
||||
el
|
||||
el-CY
|
||||
el-GR
|
||||
en
|
||||
en-AU
|
||||
en-BE
|
||||
en-BW
|
||||
en-BZ
|
||||
en-CA
|
||||
en-GB
|
||||
en-HK
|
||||
en-IE
|
||||
en-IN
|
||||
en-JM
|
||||
en-MH
|
||||
en-MT
|
||||
en-NA
|
||||
en-NZ
|
||||
en-PH
|
||||
en-PK
|
||||
en-SG
|
||||
en-TT
|
||||
en-US
|
||||
en-US-posix
|
||||
en-VI
|
||||
en-ZA
|
||||
en-ZW
|
||||
eo
|
||||
es
|
||||
es-AR
|
||||
es-BO
|
||||
es-CL
|
||||
es-CO
|
||||
es-CR
|
||||
es-DO
|
||||
es-EC
|
||||
es-ES
|
||||
es-GT
|
||||
es-HN
|
||||
es-MX
|
||||
es-NI
|
||||
es-PA
|
||||
es-PE
|
||||
es-PR
|
||||
es-PY
|
||||
es-SV
|
||||
es-US
|
||||
es-UY
|
||||
es-VE
|
||||
et
|
||||
et-EE
|
||||
eu
|
||||
eu-ES
|
||||
fa
|
||||
fa-AF
|
||||
fa-IR
|
||||
fi
|
||||
fi-FI
|
||||
fo
|
||||
fo-FO
|
||||
fr
|
||||
fr-BE
|
||||
fr-CA
|
||||
fr-CH
|
||||
fr-FR
|
||||
fr-LU
|
||||
fr-MC
|
||||
fr-SN
|
||||
ga
|
||||
ga-IE
|
||||
gl
|
||||
gl-ES
|
||||
gsw
|
||||
gsw-CH
|
||||
gu
|
||||
gu-IN
|
||||
gv
|
||||
gv-GB
|
||||
ha
|
||||
ha-Latn
|
||||
ha-Latn-GH
|
||||
ha-Latn-NE
|
||||
ha-Latn-NG
|
||||
haw
|
||||
haw-US
|
||||
he
|
||||
he-IL
|
||||
hi
|
||||
hi-IN
|
||||
hr
|
||||
hr-HR
|
||||
hu
|
||||
hu-HU
|
||||
hy
|
||||
hy-AM
|
||||
hy-AM-revised
|
||||
id
|
||||
id-ID
|
||||
ii
|
||||
ii-CN
|
||||
is
|
||||
is-IS
|
||||
it
|
||||
it-CH
|
||||
it-IT
|
||||
ja
|
||||
ja-JP
|
||||
ka
|
||||
ka-GE
|
||||
kk
|
||||
kk-Cyrl
|
||||
kk-Cyrl-KZ
|
||||
kl
|
||||
kl-GL
|
||||
km
|
||||
km-KH
|
||||
kn
|
||||
kn-IN
|
||||
ko
|
||||
ko-KR
|
||||
kok
|
||||
kok-IN
|
||||
kw
|
||||
kw-GB
|
||||
lt
|
||||
lt-LT
|
||||
lv
|
||||
lv-LV
|
||||
mk
|
||||
mk-MK
|
||||
ml
|
||||
ml-IN
|
||||
mr
|
||||
mr-IN
|
||||
ms
|
||||
ms-BN
|
||||
ms-MY
|
||||
mt
|
||||
mt-MT
|
||||
nb
|
||||
nb-NO
|
||||
ne
|
||||
ne-IN
|
||||
ne-NP
|
||||
nl
|
||||
nl-BE
|
||||
nl-NL
|
||||
nn
|
||||
nn-NO
|
||||
om
|
||||
om-ET
|
||||
om-KE
|
||||
or
|
||||
or-IN
|
||||
pa
|
||||
pa-Arab
|
||||
pa-Arab-PK
|
||||
pa-Guru
|
||||
pa-Guru-IN
|
||||
pl
|
||||
pl-PL
|
||||
ps
|
||||
ps-AF
|
||||
pt
|
||||
pt-BR
|
||||
pt-PT
|
||||
ro
|
||||
ro-MD
|
||||
ro-RO
|
||||
ru
|
||||
ru-RU
|
||||
ru-UA
|
||||
si
|
||||
si-LK
|
||||
sk
|
||||
sk-SK
|
||||
sl
|
||||
sl-SI
|
||||
so
|
||||
so-DJ
|
||||
so-ET
|
||||
so-KE
|
||||
so-SO
|
||||
sq
|
||||
sq-AL
|
||||
sr
|
||||
sr-Cyrl
|
||||
sr-Cyrl-BA
|
||||
sr-Cyrl-ME
|
||||
sr-Cyrl-RS
|
||||
sr-Latn
|
||||
sr-Latn-BA
|
||||
sr-Latn-ME
|
||||
sr-Latn-RS
|
||||
sv
|
||||
sv-FI
|
||||
sv-SE
|
||||
sw
|
||||
sw-KE
|
||||
sw-TZ
|
||||
ta
|
||||
ta-IN
|
||||
te
|
||||
te-IN
|
||||
th
|
||||
th-TH
|
||||
ti
|
||||
ti-ER
|
||||
ti-ET
|
||||
tr
|
||||
tr-TR
|
||||
uk
|
||||
uk-UA
|
||||
ur
|
||||
ur-IN
|
||||
ur-PK
|
||||
uz
|
||||
uz-Arab
|
||||
uz-Arab-AF
|
||||
uz-Cyrl
|
||||
uz-Cyrl-UZ
|
||||
uz-Latn
|
||||
uz-Latn-UZ
|
||||
vi
|
||||
vi-VN
|
||||
zh
|
||||
zh-Hans
|
||||
zh-Hans-CN
|
||||
zh-Hans-HK
|
||||
zh-Hans-MO
|
||||
zh-Hans-SG
|
||||
zh-Hant
|
||||
zh-Hant-HK
|
||||
zh-Hant-MO
|
||||
zh-Hant-TW
|
||||
zu
|
||||
zu-ZA
|
BIN
jdk/test/java/util/Locale/serialized/java6locale_ROOT
Normal file
BIN
jdk/test/java/util/Locale/serialized/java6locale_ROOT
Normal file
Binary file not shown.
BIN
jdk/test/java/util/Locale/serialized/java6locale__US
Normal file
BIN
jdk/test/java/util/Locale/serialized/java6locale__US
Normal file
Binary file not shown.
BIN
jdk/test/java/util/Locale/serialized/java6locale___Java
Normal file
BIN
jdk/test/java/util/Locale/serialized/java6locale___Java
Normal file
Binary file not shown.
BIN
jdk/test/java/util/Locale/serialized/java6locale_en
Normal file
BIN
jdk/test/java/util/Locale/serialized/java6locale_en
Normal file
Binary file not shown.
BIN
jdk/test/java/util/Locale/serialized/java6locale_en_US
Normal file
BIN
jdk/test/java/util/Locale/serialized/java6locale_en_US
Normal file
Binary file not shown.
BIN
jdk/test/java/util/Locale/serialized/java6locale_en_US_Java
Normal file
BIN
jdk/test/java/util/Locale/serialized/java6locale_en_US_Java
Normal file
Binary file not shown.
BIN
jdk/test/java/util/Locale/serialized/java6locale_iw_IL
Normal file
BIN
jdk/test/java/util/Locale/serialized/java6locale_iw_IL
Normal file
Binary file not shown.
BIN
jdk/test/java/util/Locale/serialized/java6locale_ja_JP_JP
Normal file
BIN
jdk/test/java/util/Locale/serialized/java6locale_ja_JP_JP
Normal file
Binary file not shown.
BIN
jdk/test/java/util/Locale/serialized/java6locale_no_NO_NY
Normal file
BIN
jdk/test/java/util/Locale/serialized/java6locale_no_NO_NY
Normal file
Binary file not shown.
BIN
jdk/test/java/util/Locale/serialized/java6locale_th_TH_TH
Normal file
BIN
jdk/test/java/util/Locale/serialized/java6locale_th_TH_TH
Normal file
Binary file not shown.
Loading…
Reference in New Issue
Block a user