2 *******************************************************************************
\r
3 * Copyright (C) 2009-2010, International Business Machines Corporation and *
\r
4 * others. All Rights Reserved. *
\r
5 *******************************************************************************
\r
7 package com.ibm.icu.impl;
\r
9 import java.util.Iterator;
\r
10 import java.util.Locale;
\r
12 import com.ibm.icu.lang.UScript;
\r
13 import com.ibm.icu.text.LocaleDisplayNames;
\r
14 import com.ibm.icu.text.MessageFormat;
\r
15 import com.ibm.icu.util.ULocale;
\r
16 import com.ibm.icu.util.UResourceBundle;
\r
18 public class LocaleDisplayNamesImpl extends LocaleDisplayNames {
\r
19 private final ULocale locale;
\r
20 private final DialectHandling dialectHandling;
\r
21 private final DataTable langData;
\r
22 private final DataTable regionData;
\r
23 private final Appender appender;
\r
24 private final MessageFormat format;
\r
26 private static final Cache cache = new Cache();
\r
28 public static LocaleDisplayNames getInstance(ULocale locale, DialectHandling dialectHandling) {
\r
29 synchronized (cache) {
\r
30 return cache.get(locale, dialectHandling);
\r
34 public LocaleDisplayNamesImpl(ULocale locale, DialectHandling dialectHandling) {
\r
35 this.dialectHandling = dialectHandling;
\r
36 this.langData = LangDataTables.impl.get(locale);
\r
37 this.regionData = RegionDataTables.impl.get(locale);
\r
38 this.locale = ULocale.ROOT.equals(langData.getLocale()) ? regionData.getLocale() :
\r
39 langData.getLocale();
\r
41 // Note, by going through DataTable, this uses table lookup rather than straight lookup.
\r
42 // That should get us the same data, I think. This way we don't have to explicitly
\r
43 // load the bundle again. Using direct lookup didn't seem to make an appreciable
\r
44 // difference in performance.
\r
45 String sep = langData.get("localeDisplayPattern", "separator");
\r
46 if ("separator".equals(sep)) {
\r
49 this.appender = new Appender(sep);
\r
51 String pattern = langData.get("localeDisplayPattern", "pattern");
\r
52 if ("pattern".equals(pattern)) {
\r
53 pattern = "{0} ({1})";
\r
55 this.format = new MessageFormat(pattern);
\r
59 public ULocale getLocale() {
\r
64 public DialectHandling getDialectHandling() {
\r
65 return dialectHandling;
\r
69 public String localeDisplayName(ULocale locale) {
\r
70 return localeDisplayNameInternal(locale);
\r
74 public String localeDisplayName(Locale locale) {
\r
75 return localeDisplayNameInternal(ULocale.forLocale(locale));
\r
79 public String localeDisplayName(String localeId) {
\r
80 return localeDisplayNameInternal(new ULocale(localeId));
\r
83 private String localeDisplayNameInternal(ULocale locale) {
\r
85 // lang (script, country, variant, keyword=value, ...)
\r
86 // script, country, variant, keyword=value, ...
\r
88 String resultName = null;
\r
90 String lang = locale.getLanguage();
\r
92 // Empty basename indicates root locale (keywords are ignored for this).
\r
93 // Our data uses 'root' to access display names for the root locale in the
\r
94 // "Languages" table.
\r
95 if (locale.getBaseName().length() == 0) {
\r
98 String script = locale.getScript();
\r
99 String country = locale.getCountry();
\r
100 String variant = locale.getVariant();
\r
102 boolean hasScript = script.length() > 0;
\r
103 boolean hasCountry = country.length() > 0;
\r
104 boolean hasVariant = variant.length() > 0;
\r
106 // always have a value for lang
\r
107 if (dialectHandling == DialectHandling.DIALECT_NAMES) {
\r
108 do { // loop construct is so we can break early out of search
\r
109 if (hasScript && hasCountry) {
\r
110 String langScriptCountry = lang + '_' + script + '_' + country;
\r
111 String result = localeIdName(langScriptCountry);
\r
112 if (!result.equals(langScriptCountry)) {
\r
113 resultName = result;
\r
115 hasCountry = false;
\r
120 String langScript = lang + '_' + script;
\r
121 String result = localeIdName(langScript);
\r
122 if (!result.equals(langScript)) {
\r
123 resultName = result;
\r
129 String langCountry = lang + '_' + country;
\r
130 String result = localeIdName(langCountry);
\r
131 if (!result.equals(langCountry)) {
\r
132 resultName = result;
\r
133 hasCountry = false;
\r
140 if (resultName == null) {
\r
141 resultName = localeIdName(lang);
\r
144 StringBuilder buf = new StringBuilder();
\r
146 // first element, don't need appender
\r
147 buf.append(scriptDisplayName(script));
\r
150 appender.append(regionDisplayName(country), buf);
\r
153 appender.append(variantDisplayName(variant), buf);
\r
156 Iterator<String> keys = locale.getKeywords();
\r
157 if (keys != null) {
\r
158 while (keys.hasNext()) {
\r
159 String key = keys.next();
\r
160 String value = locale.getKeywordValue(key);
\r
161 appender.append(keyDisplayName(key), buf)
\r
163 .append(keyValueDisplayName(key, value));
\r
167 String resultRemainder = null;
\r
168 if (buf.length() > 0) {
\r
169 resultRemainder = buf.toString();
\r
172 if (resultRemainder != null) {
\r
173 return format.format(new Object[] {resultName, resultRemainder});
\r
179 private String localeIdName(String localeId) {
\r
180 return langData.get("Languages", localeId);
\r
184 public String languageDisplayName(String lang) {
\r
185 // Special case to eliminate non-languages, which pollute our data.
\r
186 if (lang.equals("root") || lang.indexOf('_') != -1) {
\r
189 return langData.get("Languages", lang);
\r
193 public String scriptDisplayName(String script) {
\r
194 return langData.get("Scripts", script);
\r
198 public String scriptDisplayName(int scriptCode) {
\r
199 return scriptDisplayName(UScript.getShortName(scriptCode));
\r
203 public String regionDisplayName(String region) {
\r
204 return regionData.get("Countries", region);
\r
208 public String variantDisplayName(String variant) {
\r
209 return langData.get("Variants", variant);
\r
213 public String keyDisplayName(String key) {
\r
214 return langData.get("Keys", key);
\r
218 public String keyValueDisplayName(String key, String value) {
\r
219 return langData.get("Types", key, value);
\r
222 public static class DataTable {
\r
223 ULocale getLocale() {
\r
224 return ULocale.ROOT;
\r
227 String get(String tableName, String code) {
\r
228 return get(tableName, null, code);
\r
231 String get(String tableName, String subTableName, String code) {
\r
236 static class ICUDataTable extends DataTable {
\r
237 private final ICUResourceBundle bundle;
\r
239 public ICUDataTable(String path, ULocale locale) {
\r
240 this.bundle = (ICUResourceBundle) UResourceBundle.getBundleInstance(
\r
241 path, locale.getBaseName());
\r
244 public ULocale getLocale() {
\r
245 return bundle.getULocale();
\r
248 public String get(String tableName, String subTableName, String code) {
\r
249 return ICUResourceTableAccess.getTableString(bundle, tableName, subTableName,
\r
254 static abstract class DataTables {
\r
255 public abstract DataTable get(ULocale locale);
\r
256 public static DataTables load(String className) {
\r
258 return (DataTables) Class.forName(className).newInstance();
\r
259 } catch (Throwable t) {
\r
260 final DataTable NO_OP = new DataTable();
\r
261 return new DataTables() {
\r
262 public DataTable get(ULocale locale) {
\r
270 static abstract class ICUDataTables extends DataTables {
\r
271 private final String path;
\r
273 protected ICUDataTables(String path) {
\r
278 public DataTable get(ULocale locale) {
\r
279 return new ICUDataTable(path, locale);
\r
283 static class LangDataTables {
\r
284 static final DataTables impl = DataTables.load("com.ibm.icu.impl.ICULangDataTables");
\r
287 static class RegionDataTables {
\r
288 static final DataTables impl = DataTables.load("com.ibm.icu.impl.ICURegionDataTables");
\r
291 public static enum DataTableType {
\r
295 public static boolean haveData(DataTableType type) {
\r
297 case LANG: return LangDataTables.impl instanceof ICUDataTables;
\r
298 case REGION: return RegionDataTables.impl instanceof ICUDataTables;
\r
300 throw new IllegalArgumentException("unknown type: " + type);
\r
304 static class Appender {
\r
305 private final String sep;
\r
307 Appender(String sep) {
\r
310 StringBuilder append(String s, StringBuilder b) {
\r
311 if (b.length() > 0) {
\r
319 private static class Cache {
\r
320 private ULocale locale;
\r
321 private DialectHandling dialectHandling;
\r
322 private LocaleDisplayNames cache;
\r
323 public LocaleDisplayNames get(ULocale locale, DialectHandling dialectHandling) {
\r
324 if (!(dialectHandling == this.dialectHandling && locale.equals(this.locale))) {
\r
325 this.locale = locale;
\r
326 this.dialectHandling = dialectHandling;
\r
327 this.cache = new LocaleDisplayNamesImpl(locale, dialectHandling);
\r