2 *******************************************************************************
\r
3 * Copyright (C) 2009, International Business Machines Corporation and *
\r
4 * others. All Rights Reserved. *
\r
5 *******************************************************************************
\r
7 package com.ibm.icu.impl.locale;
\r
9 import java.util.HashMap;
\r
10 import java.util.Iterator;
\r
11 import java.util.Map;
\r
12 import java.util.Set;
\r
13 import java.util.TreeMap;
\r
15 import com.ibm.icu.impl.Utility;
\r
17 public final class InternalLocaleBuilder {
\r
19 public static final char PRIVATEUSEKEY = 'x';
\r
21 private String _language = "";
\r
22 private String _script = "";
\r
23 private String _region = "";
\r
24 private String _variant = "";
\r
26 private FieldHandler _handler = FieldHandler.DEFAULT;
\r
28 // private HashMap<Character, String> _extMap;
\r
29 private HashMap _extMap;
\r
30 // private HashMap<String, String> _kwdMap;
\r
31 private HashMap _kwdMap;
\r
33 private static final char LDMLSINGLETON = 'u';
\r
35 private static final String LANGTAGSEP = "-";
\r
36 private static final String LOCALESEP = "_";
\r
38 private static final int DEFAULTMAPCAPACITY = 4;
\r
40 public InternalLocaleBuilder() {
\r
43 public InternalLocaleBuilder(FieldHandler handler) {
\r
47 public InternalLocaleBuilder setLanguage(String language) throws LocaleSyntaxException {
\r
49 if (language.length() > 0) {
\r
50 newval = _handler.process(FieldType.LANGUAGE, language);
\r
51 if (newval == null) {
\r
52 throw new LocaleSyntaxException("Ill-formed language: " + language);
\r
59 public InternalLocaleBuilder setScript(String script) throws LocaleSyntaxException {
\r
61 if (script.length() > 0) {
\r
62 newval = _handler.process(FieldType.SCRIPT, script);
\r
63 if (newval == null) {
\r
64 throw new LocaleSyntaxException("Ill-formed script: " + script);
\r
71 public InternalLocaleBuilder setRegion(String region) throws LocaleSyntaxException {
\r
73 if (region.length() > 0) {
\r
74 newval = _handler.process(FieldType.REGION, region);
\r
75 if (newval == null) {
\r
76 throw new LocaleSyntaxException("Ill-formed region: " + region);
\r
83 public InternalLocaleBuilder setVariant(String variant) throws LocaleSyntaxException {
\r
85 if (variant.length() > 0) {
\r
86 newval = _handler.process(FieldType.VARIANT, variant);
\r
87 if (newval == null) {
\r
88 throw new LocaleSyntaxException("Ill-formed variant: " + variant);
\r
95 public InternalLocaleBuilder setLDMLExtensionValue(String key, String type) throws LocaleSyntaxException {
\r
96 if (key.length() == 0) {
\r
97 throw new LocaleSyntaxException("Empty LDML extension key");
\r
99 String kwdkey = _handler.process(FieldType.LDMLKEY, key);
\r
100 if (kwdkey == null) {
\r
101 throw new LocaleSyntaxException("Ill-formed LDML extension key: " + key);
\r
104 if (type.length() == 0) {
\r
105 if (_kwdMap != null) {
\r
106 _kwdMap.remove(kwdkey);
\r
109 String kwdtype = _handler.process(FieldType.LDMLTYPE, type);
\r
110 if (kwdtype == null) {
\r
111 throw new LocaleSyntaxException("Ill-formed LDML extension value: " + type);
\r
113 if (_kwdMap == null) {
\r
114 // _kwdMap = new HashMap<String, String>(DEFAULTMAPCAPACITY);
\r
115 _kwdMap = new HashMap(DEFAULTMAPCAPACITY);
\r
117 _kwdMap.put(kwdkey, kwdtype);
\r
123 public InternalLocaleBuilder setExtension(char singleton, String value) throws LocaleSyntaxException {
\r
124 if (!LocaleExtensions.isValidExtensionKey(singleton)) {
\r
125 throw new LocaleSyntaxException("Ill-formed extension key: " + singleton);
\r
128 // singleton char to lower case
\r
129 singleton = AsciiUtil.toLower(singleton);
\r
131 if (singleton == LDMLSINGLETON) {
\r
132 // 'u' extension reserved for locale keywords
\r
133 if (_kwdMap != null) {
\r
134 // blow out the keywords currently set
\r
137 // parse locale keyword extension subtags
\r
138 // String[] kwdtags = (value.replaceAll(LOCALESEP, LANGTAGSEP)).split(LANGTAGSEP);
\r
139 String[] kwdtags = Utility.split(Utility.replaceAll(value, LOCALESEP, LANGTAGSEP), '-');
\r
140 if ((kwdtags.length % 2) != 0) {
\r
141 // number of keyword subtags must be even number
\r
142 throw new LocaleSyntaxException("Ill-formed LDML extension key/value pairs: " + value);
\r
145 while (idx < kwdtags.length) {
\r
146 String kwdkey = _handler.process(FieldType.LDMLKEY, kwdtags[idx++]);
\r
147 String kwdtype = _handler.process(FieldType.LDMLTYPE, kwdtags[idx++]);
\r
148 if (kwdkey == null || kwdkey.length() == 0
\r
149 || kwdtype == null || kwdtype.length() == 0) {
\r
150 throw new LocaleSyntaxException("Ill-formed LDML extension key/value pairs: " + value);
\r
152 if (_kwdMap == null) {
\r
153 // _kwdMap = new HashMap<String, String>(kwdtags.length / 2);
\r
154 _kwdMap = new HashMap(kwdtags.length / 2);
\r
156 _kwdMap.put(kwdkey, kwdtype);
\r
159 // other extensions including privateuse
\r
160 if (value.length() == 0) {
\r
161 if (_extMap != null) {
\r
162 // _extMap.remove(Character.valueOf(singleton));
\r
163 _extMap.remove(new Character(singleton));
\r
166 // FieldType ftype = (singleton == PRIVATEUSEKEY) ? FieldType.PRIVATEUSE : FieldType.EXTENSION;
\r
167 int ftype = (singleton == PRIVATEUSEKEY) ? FieldType.PRIVATEUSE : FieldType.EXTENSION;
\r
168 String extval = _handler.process(ftype, value);
\r
169 if (extval == null) {
\r
170 throw new LocaleSyntaxException("Ill-formed LDML extension value: " + value);
\r
172 if (_extMap == null) {
\r
173 // _extMap = new HashMap<Character, String>(DEFAULTMAPCAPACITY);
\r
174 _extMap = new HashMap(DEFAULTMAPCAPACITY);
\r
176 // _extMap.put(Character.valueOf(singleton), extval);
\r
177 _extMap.put(new Character(singleton), extval);
\r
183 public InternalLocaleBuilder clear() {
\r
188 removeLocaleExtensions();
\r
192 public InternalLocaleBuilder removeLocaleExtensions() {
\r
193 if (_extMap != null) {
\r
196 if (_kwdMap != null) {
\r
202 public BaseLocale getBaseLocale() {
\r
203 return BaseLocale.getInstance(_language, _script, _region, _variant);
\r
206 public LocaleExtensions getLocaleExtensions() {
\r
207 // TreeMap<Character, String> extMap = null;
\r
208 TreeMap extMap = null;
\r
209 // TreeMap<String, String> kwdMap = null;
\r
210 TreeMap kwdMap = null;
\r
212 // process keywords
\r
213 if (_kwdMap != null && _kwdMap.size() > 0) {
\r
214 // Set<Map.Entry<String, String>> kwds = _kwdMap.entrySet();
\r
215 // for (Map.Entry<String, String> kwd : kwds) {
\r
216 // String key = kwd.getKey();
\r
217 // String type = kwd.getValue();
\r
218 // if (kwdMap == null) {
\r
219 // kwdMap = new TreeMap<String, String>();
\r
221 // kwdMap.put(key.intern(), type.intern());
\r
223 Set kwds = _kwdMap.entrySet();
\r
224 Iterator itr = kwds.iterator();
\r
225 while (itr.hasNext()) {
\r
226 Map.Entry kwd = (Map.Entry)itr.next();
\r
227 String key = (String)kwd.getKey();
\r
228 String type = (String)kwd.getValue();
\r
229 if (kwdMap == null) {
\r
230 kwdMap = new TreeMap();
\r
232 kwdMap.put(key.intern(), type.intern());
\r
236 // process extensions and privateuse
\r
237 if (_extMap != null) {
\r
238 // Set<Map.Entry<Character, String>> exts = _extMap.entrySet();
\r
239 // for (Map.Entry<Character, String> ext : exts) {
\r
240 // Character key = ext.getKey();
\r
241 // String value = ext.getValue();
\r
242 // if (extMap == null) {
\r
243 // extMap = new TreeMap<Character, String>();
\r
245 // extMap.put(key, value.intern());
\r
247 Set exts = _extMap.entrySet();
\r
248 Iterator itr = exts.iterator();
\r
249 while (itr.hasNext()) {
\r
250 Map.Entry ext = (Map.Entry)itr.next();
\r
251 Character key = (Character)ext.getKey();
\r
252 String value = (String)ext.getValue();
\r
253 if (extMap == null) {
\r
254 extMap = new TreeMap();
\r
256 extMap.put(key, value.intern());
\r
260 // set canonical locale keyword extension string to the extension map
\r
261 if (kwdMap != null) {
\r
262 // StringBuilder buf = new StringBuilder();
\r
263 StringBuffer buf = new StringBuffer();
\r
264 LocaleExtensions.keywordsToString(kwdMap, buf);
\r
265 if (extMap == null) {
\r
266 // extMap = new TreeMap<Character, String>();
\r
267 extMap = new TreeMap();
\r
269 // extMap.put(Character.valueOf(LDMLSINGLETON), buf.toString().intern());
\r
270 extMap.put(new Character(LDMLSINGLETON), buf.toString().intern());
\r
273 return LocaleExtensions.getInstance(extMap, kwdMap);
\r
276 // protected enum FieldType {
\r
287 private static class FieldType {
\r
288 public static final int LANGUAGE = 0;
\r
289 public static final int SCRIPT = 1;
\r
290 public static final int REGION = 2;
\r
291 public static final int VARIANT = 3;
\r
292 public static final int LDMLKEY = 4;
\r
293 public static final int LDMLTYPE = 5;
\r
294 public static final int EXTENSION = 6;
\r
295 public static final int PRIVATEUSE = 7;
\r
298 public static class FieldHandler {
\r
299 public static FieldHandler DEFAULT = new FieldHandler();
\r
301 protected FieldHandler() {
\r
304 // public String process(FieldType type, String value) {
\r
305 public String process(int type, String value) {
\r
306 value = map(type, value);
\r
307 if (value.length() > 0 && !validate(type, value)) {
\r
313 // protected String map(FieldType type, String value) {
\r
314 protected String map(int type, String value) {
\r
316 case FieldType.LANGUAGE:
\r
317 value = AsciiUtil.toLowerString(value);
\r
319 case FieldType.SCRIPT:
\r
320 if (value.length() > 0) {
\r
321 // StringBuilder buf = new StringBuilder();
\r
322 StringBuffer buf = new StringBuffer();
\r
323 buf.append(AsciiUtil.toUpper(value.charAt(0)));
\r
324 for (int i = 1; i < value.length(); i++) {
\r
325 buf.append(AsciiUtil.toLower(value.charAt(i)));
\r
327 value = buf.toString();
\r
330 case FieldType.REGION:
\r
331 value = AsciiUtil.toUpperString(value);
\r
333 case FieldType.VARIANT:
\r
334 // Java variant is case sensitive - so no case mapping here
\r
335 // value = value.replaceAll(LANGTAGSEP, LOCALESEP);
\r
336 value = Utility.replaceAll(value, LANGTAGSEP, LOCALESEP);
\r
338 case FieldType.LDMLKEY:
\r
339 case FieldType.LDMLTYPE:
\r
340 case FieldType.EXTENSION:
\r
341 case FieldType.PRIVATEUSE:
\r
342 // value = AsciiUtil.toLowerString(value).replaceAll(LOCALESEP, LANGTAGSEP);
\r
343 value = Utility.replaceAll(AsciiUtil.toLowerString(value), LOCALESEP, LANGTAGSEP);
\r
349 // protected boolean validate(FieldType type, String value) {
\r
350 protected boolean validate(int type, String value) {
\r
351 boolean isValid = false;
\r
355 case FieldType.LANGUAGE:
\r
356 isValid = LanguageTag.isLanguageSubtag(value);
\r
358 case FieldType.SCRIPT:
\r
359 isValid = LanguageTag.isScriptSubtag(value);
\r
361 case FieldType.REGION:
\r
362 isValid = LanguageTag.isRegionSubtag(value);
\r
364 case FieldType.VARIANT:
\r
365 // variant field could have multiple subtags
\r
366 // subtags = value.split(LOCALESEP);
\r
367 subtags = Utility.split(value, '_');
\r
368 // for (String subtag : subtags) {
\r
369 for (int i = 0; i < subtags.length; i++) {
\r
370 String subtag = subtags[i];
\r
371 isValid = LanguageTag.isVariantSubtag(subtag);
\r
377 case FieldType.LDMLKEY:
\r
378 isValid = LocaleExtensions.isValidLDMLKey(value);
\r
380 case FieldType.LDMLTYPE:
\r
381 isValid = LocaleExtensions.isValidLDMLType(value);
\r
383 case FieldType.EXTENSION:
\r
384 // subtags = value.split(LANGTAGSEP);
\r
385 subtags = Utility.split(value, '-');
\r
386 // for (String subtag : subtags) {
\r
387 for (int i = 0; i < subtags.length; i++) {
\r
388 String subtag = subtags[i];
\r
389 isValid = LanguageTag.isExtensionSubtag(subtag);
\r
395 case FieldType.PRIVATEUSE:
\r
396 // subtags = value.split(LANGTAGSEP);
\r
397 subtags = Utility.split(value, '-');
\r
398 // for (String subtag : subtags) {
\r
399 for (int i = 0; i < subtags.length; i++) {
\r
400 String subtag = subtags[i];
\r
401 isValid = LanguageTag.isPrivateuseValueSubtag(subtag);
\r