mirror of
https://github.com/unicode-org/icu.git
synced 2025-04-13 17:01:16 +00:00
ICU-8774 Support locale category in com.ibm.icu.base plug-in. Also fixed a Java 5 support problem in DateFormatSymbols in com.ibm.icu.base.
X-SVN-Rev: 30602
This commit is contained in:
parent
451107e9e3
commit
7f0deb8734
22 changed files with 4707 additions and 333 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -920,6 +920,7 @@ icu4j/*.jar
|
|||
icu4j/.project
|
||||
icu4j/demos/out
|
||||
icu4j/doc
|
||||
icu4j/eclipse-build/out
|
||||
icu4j/main/classes/charset/out
|
||||
icu4j/main/classes/collate/out
|
||||
icu4j/main/classes/core/out
|
||||
|
|
|
@ -11,6 +11,7 @@ import java.util.Iterator;
|
|||
import java.util.Locale;
|
||||
|
||||
import com.ibm.icu.util.ULocale;
|
||||
import com.ibm.icu.util.ULocale.Category;
|
||||
|
||||
public class ULocaleTest extends ICUTestCase {
|
||||
private String sampleName;
|
||||
|
@ -745,4 +746,102 @@ public class ULocaleTest extends ICUTestCase {
|
|||
assertNotNull(result); // actual result depends on jdk
|
||||
assertTrue(fallback[0]);
|
||||
}
|
||||
|
||||
/*
|
||||
* Test method for 'com.ibm.icu.x.util.ULocale.toLanguageTag()'
|
||||
*/
|
||||
public void testToLanguageTag() {
|
||||
ULocale[] test_ulocales = {
|
||||
new ULocale("en_US"),
|
||||
new ULocale(""),
|
||||
new ULocale("de_DE@collation=phonebook"),
|
||||
new ULocale("en_Latn_US_POSIX"),
|
||||
new ULocale("th_TH@numbers=thai;calendar=buddhist"),
|
||||
new ULocale("und_CN@timezone=PRC"),
|
||||
new ULocale("iw_IL"),
|
||||
};
|
||||
|
||||
String[] expected = {
|
||||
"en-US",
|
||||
"und",
|
||||
"de-DE-u-co-phonebk",
|
||||
"en-Latn-US-u-va-posix",
|
||||
"th-TH-u-ca-buddhist-nu-thai",
|
||||
"und-CN-u-tz-cnsha",
|
||||
"he-IL",
|
||||
};
|
||||
|
||||
for (int i = 0; i < test_ulocales.length; i++) {
|
||||
String result = test_ulocales[i].toLanguageTag();
|
||||
assertEquals(expected[i], result);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Test method for 'com.ibm.icu.x.util.ULocale.forLanguageTag()'
|
||||
*/
|
||||
public void testForLanguageTag() {
|
||||
String[] test_tags = {
|
||||
"en-us",
|
||||
"Und-Us",
|
||||
"ja-jp-u-ca-japanese",
|
||||
"fr-FR-u-tz-frpar-ca-gregory",
|
||||
};
|
||||
|
||||
ULocale[] expected = {
|
||||
new ULocale("en_US"),
|
||||
new ULocale("und_US"),
|
||||
new ULocale("ja_JP@calendar=japanese"),
|
||||
new ULocale("fr_FR@calendar=gregorian;timezone=Europe/Paris"),
|
||||
};
|
||||
|
||||
for (int i = 0; i < test_tags.length; i++) {
|
||||
ULocale result = ULocale.forLanguageTag(test_tags[i]);
|
||||
assertEquals(expected[i], result);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Test method for 'com.ibm.icu.x.util.ULocale.getDefault(Category)'
|
||||
*/
|
||||
public void testGetDefaultCategory() {
|
||||
ULocale dispLoc = ULocale.getDefault(Category.DISPLAY);
|
||||
assertNotNull(dispLoc);
|
||||
ULocale formLoc = ULocale.getDefault(Category.FORMAT);
|
||||
assertNotNull(formLoc);
|
||||
}
|
||||
|
||||
/*
|
||||
* Test method for 'com.ibm.icu.x.util.ULocale.setDefault(Category, ULocale)'
|
||||
*/
|
||||
public void testSetDefaultCategoryULocale() {
|
||||
ULocale orgDefault = ULocale.getDefault();
|
||||
ULocale orgDisplay = ULocale.getDefault(Category.DISPLAY);
|
||||
ULocale orgFormat = ULocale.getDefault(Category.FORMAT);
|
||||
|
||||
ULocale jaUS = new ULocale("ja_US");
|
||||
ULocale.setDefault(jaUS);
|
||||
|
||||
// setDefault(ULocale) updates category defaults
|
||||
assertEquals(ULocale.getDefault(), jaUS);
|
||||
assertEquals(ULocale.getDefault(Category.DISPLAY), jaUS);
|
||||
assertEquals(ULocale.getDefault(Category.FORMAT), jaUS);
|
||||
|
||||
ULocale frDE = new ULocale("fr_DE");
|
||||
ULocale.setDefault(Category.DISPLAY, frDE);
|
||||
|
||||
// setDefault(Category, ULocale) only updates the category default
|
||||
assertEquals(ULocale.getDefault(), jaUS);
|
||||
assertEquals(ULocale.getDefault(Category.DISPLAY), frDE);
|
||||
assertEquals(ULocale.getDefault(Category.FORMAT), jaUS);
|
||||
|
||||
// restore the original
|
||||
ULocale.setDefault(orgDefault);
|
||||
ULocale.setDefault(Category.DISPLAY, orgDisplay);
|
||||
ULocale.setDefault(Category.FORMAT, orgFormat);
|
||||
|
||||
assertEquals(ULocale.getDefault(), orgDefault);
|
||||
assertEquals(ULocale.getDefault(Category.DISPLAY), orgDisplay);
|
||||
assertEquals(ULocale.getDefault(Category.FORMAT), orgFormat);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<classpath>
|
||||
<classpathentry kind="src" path="src"/>
|
||||
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/>
|
||||
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/J2SE-1.5"/>
|
||||
<classpathentry kind="con" path="org.eclipse.pde.core.requiredPlugins"/>
|
||||
<classpathentry kind="output" path="bin"/>
|
||||
</classpath>
|
||||
|
|
|
@ -167,6 +167,9 @@ public final class AsciiUtil {
|
|||
}
|
||||
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) {
|
||||
return true;
|
||||
}
|
||||
if (o instanceof CaseInsensitiveKey) {
|
||||
return AsciiUtil.caseIgnoreMatch(_key, ((CaseInsensitiveKey)o)._key);
|
||||
}
|
||||
|
|
|
@ -0,0 +1,257 @@
|
|||
/*
|
||||
*******************************************************************************
|
||||
* Copyright (C) 2009-2011, International Business Machines Corporation and *
|
||||
* others. All Rights Reserved. *
|
||||
*******************************************************************************
|
||||
*/
|
||||
|
||||
package com.ibm.icu.impl.locale;
|
||||
|
||||
|
||||
public final class BaseLocale {
|
||||
|
||||
private static final boolean JDKIMPL = false;
|
||||
|
||||
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) {
|
||||
if (JDKIMPL) {
|
||||
// preserve upper/lower cases
|
||||
_variant = variant.intern();
|
||||
} else {
|
||||
_variant = AsciiUtil.toUpperString(variant).intern();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static BaseLocale getInstance(String language, String script, String region, String variant) {
|
||||
if (JDKIMPL) {
|
||||
// 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) {
|
||||
if (JDKIMPL) {
|
||||
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!
|
||||
}
|
||||
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)
|
||||
&& AsciiUtil.caseIgnoreMatch(((Key)obj)._vart, this._vart);
|
||||
}
|
||||
|
||||
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) {
|
||||
if (JDKIMPL) {
|
||||
res = this._vart.compareTo(other._vart);
|
||||
} else {
|
||||
res = AsciiUtil.caseIgnoreCompare(this._vart, 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++) {
|
||||
if (JDKIMPL) {
|
||||
h = 31*h + _vart.charAt(i);
|
||||
} else {
|
||||
h = 31*h + AsciiUtil.toLower(_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;
|
||||
if (JDKIMPL) {
|
||||
// preserve upper/lower cases
|
||||
vart = key._vart.intern();
|
||||
} else {
|
||||
vart = AsciiUtil.toUpperString(key._vart).intern();
|
||||
}
|
||||
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);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -0,0 +1,38 @@
|
|||
/*
|
||||
*******************************************************************************
|
||||
* Copyright (C) 2009-2011, International Business Machines Corporation and *
|
||||
* others. All Rights Reserved. *
|
||||
*******************************************************************************
|
||||
*/
|
||||
package com.ibm.icu.impl.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();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,684 @@
|
|||
/*
|
||||
*******************************************************************************
|
||||
* Copyright (C) 2009-2011, International Business Machines Corporation and *
|
||||
* others. All Rights Reserved. *
|
||||
*******************************************************************************
|
||||
*/
|
||||
package com.ibm.icu.impl.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 static final boolean JDKIMPL = false;
|
||||
|
||||
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 (attribute == null || !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> processedExtensions = new HashSet<CaseInsensitiveChar>(bcpExtensions.size());
|
||||
for (String bcpExt : bcpExtensions) {
|
||||
CaseInsensitiveChar key = new CaseInsensitiveChar(bcpExt.charAt(0));
|
||||
// ignore duplicates
|
||||
if (!processedExtensions.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();
|
||||
|
||||
if (JDKIMPL) {
|
||||
// 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());
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -0,0 +1,720 @@
|
|||
/*
|
||||
*******************************************************************************
|
||||
* Copyright (C) 2010-2011, International Business Machines Corporation and *
|
||||
* others. All Rights Reserved. *
|
||||
*******************************************************************************
|
||||
*/
|
||||
package com.ibm.icu.impl.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 {
|
||||
private static final boolean JDKIMPL = false;
|
||||
|
||||
//
|
||||
// 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();
|
||||
|
||||
boolean hasSubtag = false;
|
||||
|
||||
String privuseVar = null; // store ill-formed variant subtags
|
||||
|
||||
if (language.length() > 0 && isLanguage(language)) {
|
||||
// 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);
|
||||
hasSubtag = true;
|
||||
}
|
||||
|
||||
if (region.length() > 0 && isRegion(region)) {
|
||||
tag._region = canonicalizeRegion(region);
|
||||
hasSubtag = true;
|
||||
}
|
||||
|
||||
if (JDKIMPL) {
|
||||
// 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>();
|
||||
}
|
||||
if (JDKIMPL) {
|
||||
variants.add(var); // Do not canonicalize!
|
||||
} else {
|
||||
variants.add(canonicalizeVariant(var));
|
||||
}
|
||||
varitr.next();
|
||||
}
|
||||
if (variants != null) {
|
||||
tag._variants = variants;
|
||||
hasSubtag = true;
|
||||
}
|
||||
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);
|
||||
}
|
||||
if (!JDKIMPL) {
|
||||
prvv = AsciiUtil.toLowerString(prvv);
|
||||
}
|
||||
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;
|
||||
hasSubtag = true;
|
||||
}
|
||||
|
||||
// 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;
|
||||
}
|
||||
|
||||
if (tag._language.length() == 0 && (hasSubtag || privateuse == null)) {
|
||||
// use lang "und" when 1) no language is available AND
|
||||
// 2) any of other subtags other than private use are available or
|
||||
// no private use tag 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();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,221 @@
|
|||
/*
|
||||
*******************************************************************************
|
||||
* Copyright (C) 2009-2011, International Business Machines Corporation and *
|
||||
* others. All Rights Reserved. *
|
||||
*******************************************************************************
|
||||
*/
|
||||
package com.ibm.icu.impl.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 com.ibm.icu.impl.locale.InternalLocaleBuilder.CaseInsensitiveChar;
|
||||
import com.ibm.icu.impl.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);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,83 @@
|
|||
/*
|
||||
*******************************************************************************
|
||||
* Copyright (C) 2009-2011, International Business Machines Corporation and *
|
||||
* others. All Rights Reserved. *
|
||||
*******************************************************************************
|
||||
*/
|
||||
package com.ibm.icu.impl.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,27 @@
|
|||
/*
|
||||
*******************************************************************************
|
||||
* Copyright (C) 2009-2011, International Business Machines Corporation and *
|
||||
* others. All Rights Reserved. *
|
||||
*******************************************************************************
|
||||
*/
|
||||
package com.ibm.icu.impl.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;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,35 @@
|
|||
/*
|
||||
*******************************************************************************
|
||||
* Copyright (C) 2010-2011, International Business Machines Corporation and *
|
||||
* others. All Rights Reserved. *
|
||||
*******************************************************************************
|
||||
*/
|
||||
package com.ibm.icu.impl.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;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,93 @@
|
|||
/*
|
||||
*******************************************************************************
|
||||
* Copyright (C) 2009-2011, International Business Machines Corporation and *
|
||||
* others. All Rights Reserved. *
|
||||
*******************************************************************************
|
||||
*/
|
||||
package com.ibm.icu.impl.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,102 @@
|
|||
/*
|
||||
*******************************************************************************
|
||||
* Copyright (C) 2009-2011, International Business Machines Corporation and *
|
||||
* others. All Rights Reserved. *
|
||||
*******************************************************************************
|
||||
*/
|
||||
package com.ibm.icu.impl.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);
|
||||
}
|
||||
}
|
|
@ -18,6 +18,7 @@ import java.util.Map;
|
|||
import com.ibm.icu.util.Calendar;
|
||||
import com.ibm.icu.util.TimeZone;
|
||||
import com.ibm.icu.util.ULocale;
|
||||
import com.ibm.icu.util.ULocale.Category;
|
||||
|
||||
/**
|
||||
* {@icuenhanced java.text.DateFormat}.{@icu _usage_}
|
||||
|
@ -1417,7 +1418,7 @@ public class DateFormat extends Format {
|
|||
* @stable ICU 2.0
|
||||
*/
|
||||
static final public DateFormat getInstance(Calendar cal) {
|
||||
return getInstance(cal, ULocale.getDefault());
|
||||
return getInstance(cal, ULocale.getDefault(Category.FORMAT));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1425,7 +1426,7 @@ public class DateFormat extends Format {
|
|||
* @stable ICU 2.0
|
||||
*/
|
||||
static final public DateFormat getDateInstance(Calendar cal, int dateStyle) {
|
||||
return getDateInstance(cal, dateStyle, ULocale.getDefault());
|
||||
return getDateInstance(cal, dateStyle, ULocale.getDefault(Category.FORMAT));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1433,7 +1434,7 @@ public class DateFormat extends Format {
|
|||
* @stable ICU 2.0
|
||||
*/
|
||||
static final public DateFormat getTimeInstance(Calendar cal, int timeStyle) {
|
||||
return getTimeInstance(cal, timeStyle, ULocale.getDefault());
|
||||
return getTimeInstance(cal, timeStyle, Locale.getDefault());
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1441,7 +1442,7 @@ public class DateFormat extends Format {
|
|||
* @stable ICU 2.0
|
||||
*/
|
||||
static final public DateFormat getDateTimeInstance(Calendar cal, int dateStyle, int timeStyle) {
|
||||
return getDateTimeInstance(cal, dateStyle, timeStyle, ULocale.getDefault());
|
||||
return getDateTimeInstance(cal, dateStyle, timeStyle, ULocale.getDefault(Category.FORMAT));
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -8,6 +8,8 @@
|
|||
package com.ibm.icu.text;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.Locale;
|
||||
import java.util.MissingResourceException;
|
||||
import java.util.ResourceBundle;
|
||||
|
@ -174,7 +176,7 @@ public class DateFormatSymbols implements Serializable, Cloneable {
|
|||
* @stable ICU 3.8
|
||||
*/
|
||||
public static DateFormatSymbols getInstance() {
|
||||
return new DateFormatSymbols(java.text.DateFormatSymbols.getInstance());
|
||||
return new DateFormatSymbols(new java.text.DateFormatSymbols());
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -190,7 +192,7 @@ public class DateFormatSymbols implements Serializable, Cloneable {
|
|||
* @stable ICU 3.8
|
||||
*/
|
||||
public static DateFormatSymbols getInstance(Locale locale) {
|
||||
return new DateFormatSymbols(java.text.DateFormatSymbols.getInstance(locale));
|
||||
return new DateFormatSymbols(new java.text.DateFormatSymbols(locale));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -206,7 +208,7 @@ public class DateFormatSymbols implements Serializable, Cloneable {
|
|||
* @stable ICU 3.8
|
||||
*/
|
||||
public static DateFormatSymbols getInstance(ULocale locale) {
|
||||
return new DateFormatSymbols(java.text.DateFormatSymbols.getInstance(locale.toLocale()));
|
||||
return new DateFormatSymbols(new java.text.DateFormatSymbols(locale.toLocale()));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -223,7 +225,26 @@ public class DateFormatSymbols implements Serializable, Cloneable {
|
|||
* @stable ICU 3.8
|
||||
*/
|
||||
public static Locale[] getAvailableLocales() {
|
||||
return java.text.DateFormatSymbols.getAvailableLocales();
|
||||
Locale[] avlocs = null;
|
||||
boolean isJava5 = true;
|
||||
try {
|
||||
Method mGetAvailableLocales = java.text.DateFormatSymbols.class.getMethod("getAvailableLocales", (Class[])null);
|
||||
avlocs = (Locale[]) mGetAvailableLocales.invoke(null, (Object[]) null);
|
||||
isJava5 = false;
|
||||
} catch (NoSuchMethodException nsme) {
|
||||
// fall through
|
||||
} catch (InvocationTargetException ite) {
|
||||
// fall through
|
||||
} catch (IllegalAccessException iae) {
|
||||
// fall through
|
||||
}
|
||||
|
||||
if (isJava5) {
|
||||
// Use DateFormat's getAvailableLocales as fallback
|
||||
avlocs = DateFormat.getAvailableLocales();
|
||||
}
|
||||
|
||||
return avlocs;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -241,7 +262,7 @@ public class DateFormatSymbols implements Serializable, Cloneable {
|
|||
* @provisional This API might change or be removed in a future release.
|
||||
*/
|
||||
public static ULocale[] getAvailableULocales() {
|
||||
Locale[] locales = java.text.DateFormatSymbols.getAvailableLocales();
|
||||
Locale[] locales = getAvailableLocales();
|
||||
ULocale[] ulocales = new ULocale[locales.length];
|
||||
for (int i = 0; i < locales.length; ++i) {
|
||||
ulocales[i] = ULocale.forLocale(locales[i]);
|
||||
|
|
|
@ -19,6 +19,7 @@ import java.util.Set;
|
|||
import com.ibm.icu.util.Currency;
|
||||
import com.ibm.icu.util.CurrencyAmount;
|
||||
import com.ibm.icu.util.ULocale;
|
||||
import com.ibm.icu.util.ULocale.Category;
|
||||
|
||||
/**
|
||||
* {@icuenhanced java.text.NumberFormat}.{@icu _usage_}
|
||||
|
@ -514,7 +515,7 @@ public class NumberFormat extends Format {
|
|||
*/
|
||||
//Bug 4408066 [Richard/GCL]
|
||||
public final static NumberFormat getInstance() {
|
||||
return getInstance(ULocale.getDefault(), NUMBERSTYLE);
|
||||
return getInstance(ULocale.getDefault(Category.FORMAT), NUMBERSTYLE);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -545,7 +546,7 @@ public class NumberFormat extends Format {
|
|||
* @stable ICU 4.2
|
||||
*/
|
||||
public final static NumberFormat getInstance(int style) {
|
||||
return getInstance(ULocale.getDefault(), style);
|
||||
return getInstance(ULocale.getDefault(Category.FORMAT), style);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -564,7 +565,7 @@ public class NumberFormat extends Format {
|
|||
* @stable ICU 2.0
|
||||
*/
|
||||
public final static NumberFormat getNumberInstance() {
|
||||
return getInstance(ULocale.getDefault(), NUMBERSTYLE);
|
||||
return getInstance(ULocale.getDefault(Category.FORMAT), NUMBERSTYLE);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -596,7 +597,7 @@ public class NumberFormat extends Format {
|
|||
*/
|
||||
//Bug 4408066 [Richard/GCL]
|
||||
public final static NumberFormat getIntegerInstance() {
|
||||
return getInstance(ULocale.getDefault(), INTEGERSTYLE);
|
||||
return getInstance(ULocale.getDefault(Category.FORMAT), INTEGERSTYLE);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -638,7 +639,7 @@ public class NumberFormat extends Format {
|
|||
* @stable ICU 2.0
|
||||
*/
|
||||
public final static NumberFormat getCurrencyInstance() {
|
||||
return getInstance(ULocale.getDefault(), CURRENCYSTYLE);
|
||||
return getInstance(ULocale.getDefault(Category.FORMAT), CURRENCYSTYLE);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -665,7 +666,7 @@ public class NumberFormat extends Format {
|
|||
* @stable ICU 2.0
|
||||
*/
|
||||
public final static NumberFormat getPercentInstance() {
|
||||
return getInstance(ULocale.getDefault(), PERCENTSTYLE);
|
||||
return getInstance(ULocale.getDefault(Category.FORMAT), PERCENTSTYLE);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -692,7 +693,7 @@ public class NumberFormat extends Format {
|
|||
* @stable ICU 2.0
|
||||
*/
|
||||
public final static NumberFormat getScientificInstance() {
|
||||
return getInstance(ULocale.getDefault(), SCIENTIFICSTYLE);
|
||||
return getInstance(ULocale.getDefault(Category.FORMAT), SCIENTIFICSTYLE);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -11,6 +11,7 @@ import java.util.GregorianCalendar;
|
|||
import java.util.Locale;
|
||||
|
||||
import com.ibm.icu.text.DateFormat;
|
||||
import com.ibm.icu.util.ULocale.Category;
|
||||
|
||||
/**
|
||||
* {@icuenhanced java.util.Calendar}.{@icu _usage_}
|
||||
|
@ -1139,7 +1140,7 @@ public class Calendar implements Serializable, Cloneable, Comparable<Calendar> {
|
|||
*/
|
||||
protected Calendar()
|
||||
{
|
||||
this(TimeZone.getDefault(), ULocale.getDefault());
|
||||
this(TimeZone.getDefault(), ULocale.getDefault(Category.FORMAT));
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -0,0 +1,73 @@
|
|||
/*
|
||||
*******************************************************************************
|
||||
* Copyright (C) 2009-2011, International Business Machines Corporation and *
|
||||
* others. All Rights Reserved. *
|
||||
*******************************************************************************
|
||||
*/
|
||||
package com.ibm.icu.util;
|
||||
|
||||
/**
|
||||
* Thrown by methods in {@link ULocale} and {@link ULocale.Builder} to
|
||||
* indicate that an argument is not a well-formed BCP 47 tag.
|
||||
*
|
||||
* @see ULocale
|
||||
* @draft ICU 4.2
|
||||
* @provisional This API might change or be removed in a future release.
|
||||
*/
|
||||
public class IllformedLocaleException extends RuntimeException {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private int _errIdx = -1;
|
||||
|
||||
/**
|
||||
* Constructs a new <code>IllformedLocaleException</code> with no
|
||||
* detail message and -1 as the error index.
|
||||
* @draft ICU 4.6
|
||||
* @provisional This API might change or be removed in a future release.
|
||||
*/
|
||||
public IllformedLocaleException() {
|
||||
super();
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a new <code>IllformedLocaleException</code> with the
|
||||
* given message and -1 as the error index.
|
||||
*
|
||||
* @param message the message
|
||||
* @draft ICU 4.2
|
||||
* @provisional This API might change or be removed in a future release.
|
||||
*/
|
||||
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
|
||||
* @draft ICU 4.2
|
||||
* @provisional This API might change or be removed in a future release.
|
||||
*/
|
||||
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
|
||||
* @draft ICU 4.2
|
||||
* @provisional This API might change or be removed in a future release.
|
||||
*/
|
||||
public int getErrorIndex() {
|
||||
return _errIdx;
|
||||
}
|
||||
}
|
|
@ -12,6 +12,8 @@ import java.util.Date;
|
|||
import java.util.Locale;
|
||||
import java.util.MissingResourceException;
|
||||
|
||||
import com.ibm.icu.util.ULocale.Category;
|
||||
|
||||
/**
|
||||
* {@icuenhanced java.util.TimeZone}.{@icu _usage_}
|
||||
*
|
||||
|
@ -368,7 +370,7 @@ public class TimeZone implements Serializable, Cloneable {
|
|||
* @stable ICU 2.0
|
||||
*/
|
||||
public final String getDisplayName(boolean daylight, int style) {
|
||||
return getDisplayName(daylight, style, ULocale.getDefault());
|
||||
return getDisplayName(daylight, style, ULocale.getDefault(Category.DISPLAY));
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -1,7 +1,7 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<classpath>
|
||||
<classpathentry kind="src" path="src"/>
|
||||
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/>
|
||||
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/J2SE-1.5"/>
|
||||
<classpathentry kind="con" path="org.eclipse.pde.core.requiredPlugins"/>
|
||||
<classpathentry kind="output" path="bin"/>
|
||||
</classpath>
|
||||
|
|
Loading…
Add table
Reference in a new issue