blob: 8085257d0baa38452c848e7b0ba7d4d185b67700 [file] [log] [blame]
/*
*******************************************************************************
* Copyright (C) 2009-2010, International Business Machines Corporation and *
* others. All Rights Reserved. *
*******************************************************************************
*/
package com.ibm.icu.impl;
import java.util.Iterator;
import java.util.Locale;
import com.ibm.icu.lang.UScript;
import com.ibm.icu.text.MessageFormat;
import com.ibm.icu.text.LocaleDisplayNames;
import com.ibm.icu.util.ULocale;
import com.ibm.icu.util.UResourceBundle;
public class LocaleDisplayNamesImpl extends LocaleDisplayNames {
private final ULocale locale;
private final DialectHandling dialectHandling;
private final DataTable langData;
private final DataTable regionData;
private final Appender appender;
private final MessageFormat format;
private static final Cache cache = new Cache();
public static LocaleDisplayNames getInstance(ULocale locale, DialectHandling dialectHandling) {
synchronized (cache) {
return cache.get(locale, dialectHandling);
}
}
public LocaleDisplayNamesImpl(ULocale locale, DialectHandling dialectHandling) {
this.dialectHandling = dialectHandling;
this.langData = LangDataTables.impl.get(locale);
this.regionData = RegionDataTables.impl.get(locale);
this.locale = ULocale.ROOT.equals(langData.getLocale()) ? regionData.getLocale() :
langData.getLocale();
// Note, by going through DataTable, this uses table lookup rather than straight lookup.
// That should get us the same data, I think. This way we don't have to explicitly
// load the bundle again. Using direct lookup didn't seem to make an appreciable
// difference in performance.
String sep = langData.get("localeDisplayPattern", "separator");
if ("separator".equals(sep)) {
sep = ", ";
}
this.appender = new Appender(sep);
String pattern = langData.get("localeDisplayPattern", "pattern");
if ("pattern".equals(pattern)) {
pattern = "{0} ({1})";
}
this.format = new MessageFormat(pattern);
}
@Override
public ULocale getLocale() {
return locale;
}
@Override
public DialectHandling getDialectHandling() {
return dialectHandling;
}
@Override
public String localeDisplayName(ULocale locale) {
return localeDisplayNameInternal(locale);
}
@Override
public String localeDisplayName(Locale locale) {
return localeDisplayNameInternal(ULocale.forLocale(locale));
}
@Override
public String localeDisplayName(String localeId) {
return localeDisplayNameInternal(new ULocale(localeId));
}
private String localeDisplayNameInternal(ULocale locale) {
// lang
// lang (script, country, variant, keyword=value, ...)
// script, country, variant, keyword=value, ...
String resultName = null;
String lang = locale.getLanguage();
// Empty basename indicates root locale (keywords are ignored for this).
// Our data uses 'root' to access display names for the root locale in the
// "Languages" table.
if (locale.getBaseName().length() == 0) {
lang = "root";
}
String script = locale.getScript();
String country = locale.getCountry();
String variant = locale.getVariant();
boolean hasScript = script.length() > 0;
boolean hasCountry = country.length() > 0;
boolean hasVariant = variant.length() > 0;
// always have a value for lang
if (dialectHandling == DialectHandling.DIALECT_NAMES) {
do { // loop construct is so we can break early out of search
if (hasScript && hasCountry) {
String langScriptCountry = lang + '_' + script + '_' + country;
String result = localeIdName(langScriptCountry);
if (!result.equals(langScriptCountry)) {
resultName = result;
hasScript = false;
hasCountry = false;
break;
}
}
if (hasScript) {
String langScript = lang + '_' + script;
String result = localeIdName(langScript);
if (!result.equals(langScript)) {
resultName = result;
hasScript = false;
break;
}
}
if (hasCountry) {
String langCountry = lang + '_' + country;
String result = localeIdName(langCountry);
if (!result.equals(langCountry)) {
resultName = result;
hasCountry = false;
break;
}
}
} while (false);
}
if (resultName == null) {
resultName = localeIdName(lang);
}
StringBuilder buf = new StringBuilder();
if (hasScript) {
// first element, don't need appender
buf.append(scriptDisplayName(script));
}
if (hasCountry) {
appender.append(regionDisplayName(country), buf);
}
if (hasVariant) {
appender.append(variantDisplayName(variant), buf);
}
Iterator<String> keys = locale.getKeywords();
if (keys != null) {
while (keys.hasNext()) {
String key = keys.next();
String value = locale.getKeywordValue(key);
appender.append(keyDisplayName(key), buf)
.append("=")
.append(keyValueDisplayName(key, value));
}
}
String resultRemainder = null;
if (buf.length() > 0) {
resultRemainder = buf.toString();
}
if (resultRemainder != null) {
return format.format(new Object[] {resultName, resultRemainder});
}
return resultName;
}
private String localeIdName(String localeId) {
return langData.get("Languages", localeId);
}
@Override
public String languageDisplayName(String lang) {
// Special case to eliminate non-languages, which pollute our data.
if (lang.equals("root") || lang.indexOf('_') != -1) {
return lang;
}
return langData.get("Languages", lang);
}
@Override
public String scriptDisplayName(String script) {
return langData.get("Scripts", script);
}
@Override
public String scriptDisplayName(int scriptCode) {
return scriptDisplayName(UScript.getShortName(scriptCode));
}
@Override
public String regionDisplayName(String region) {
return regionData.get("Countries", region);
}
@Override
public String variantDisplayName(String variant) {
return langData.get("Variants", variant);
}
@Override
public String keyDisplayName(String key) {
return langData.get("Keys", key);
}
@Override
public String keyValueDisplayName(String key, String value) {
return langData.get("Types", key, value);
}
public static class DataTable {
ULocale getLocale() {
return ULocale.ROOT;
}
String get(String tableName, String code) {
return get(tableName, null, code);
}
String get(String tableName, String subTableName, String code) {
return code;
}
}
static class ICUDataTable extends DataTable {
private final ICUResourceBundle bundle;
public ICUDataTable(String path, ULocale locale) {
this.bundle = (ICUResourceBundle) UResourceBundle.getBundleInstance(
path, locale.getBaseName());
}
public ULocale getLocale() {
return bundle.getULocale();
}
public String get(String tableName, String subTableName, String code) {
return ICUResourceTableAccess.getTableString(bundle, tableName, subTableName,
code);
}
}
static abstract class DataTables {
public abstract DataTable get(ULocale locale);
public static DataTables load(String className) {
try {
return (DataTables) Class.forName(className).newInstance();
} catch (Throwable t) {
final DataTable NO_OP = new DataTable();
return new DataTables() {
public DataTable get(ULocale locale) {
return NO_OP;
}
};
}
}
}
static abstract class ICUDataTables extends DataTables {
private final String path;
protected ICUDataTables(String path) {
this.path = path;
}
@Override
public DataTable get(ULocale locale) {
return new ICUDataTable(path, locale);
}
}
static class LangDataTables {
static final DataTables impl = DataTables.load("com.ibm.icu.impl.ICULangDataTables");
}
static class RegionDataTables {
static final DataTables impl = DataTables.load("com.ibm.icu.impl.ICURegionDataTables");
}
public static enum DataTableType {
LANG, REGION;
}
public static boolean haveData(DataTableType type) {
switch (type) {
case LANG: return LangDataTables.impl instanceof ICUDataTables;
case REGION: return RegionDataTables.impl instanceof ICUDataTables;
default:
throw new IllegalArgumentException("unknown type: " + type);
}
}
static class Appender {
private final String sep;
Appender(String sep) {
this.sep = sep;
}
StringBuilder append(String s, StringBuilder b) {
if (b.length() > 0) {
b.append(sep);
}
b.append(s);
return b;
}
}
private static class Cache {
private ULocale locale;
private DialectHandling dialectHandling;
private LocaleDisplayNames cache;
public LocaleDisplayNames get(ULocale locale, DialectHandling dialectHandling) {
if (!(dialectHandling == this.dialectHandling && locale.equals(this.locale))) {
this.locale = locale;
this.dialectHandling = dialectHandling;
this.cache = new LocaleDisplayNamesImpl(locale, dialectHandling);
}
return cache;
}
}
}