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:
Yoshito Umaoka 2011-08-31 07:02:05 +00:00
parent 451107e9e3
commit 7f0deb8734
22 changed files with 4707 additions and 333 deletions

1
.gitignore vendored
View file

@ -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

View file

@ -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);
}
}

View file

@ -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>

View file

@ -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);
}

View file

@ -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);
}
}
}

View file

@ -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();
}
}

View file

@ -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());
}
}
}

View file

@ -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();
}
}

View file

@ -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);
}
}

View file

@ -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;
}
}
}

View file

@ -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;
}
}

View file

@ -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;
}
}

View file

@ -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;
}
}

View file

@ -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);
}
}

View file

@ -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));
}
/**

View file

@ -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]);

View file

@ -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);
}
/**

View file

@ -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));
}
/**

View file

@ -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;
}
}

View file

@ -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));
}
/**

View file

@ -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>