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.List;
\r
10 import java.util.Set;
\r
11 import java.util.SortedMap;
\r
12 import java.util.TreeMap;
\r
14 import com.ibm.icu.impl.locale.LanguageTag.ParseStatus;
\r
16 public final class InternalLocaleBuilder {
\r
18 private String _language = "";
\r
19 private String _script = "";
\r
20 private String _region = "";
\r
21 private String _variant = "";
\r
22 private SortedMap<Character, Extension> _extMap;
\r
24 private final boolean _lenientVariant;
\r
26 private static final String LOCALESEP = "_";
\r
28 public InternalLocaleBuilder() {
\r
32 public InternalLocaleBuilder(boolean lenientVariant) {
\r
33 _lenientVariant = lenientVariant;
\r
36 public boolean isLenientVariant() {
\r
37 return _lenientVariant;
\r
40 public InternalLocaleBuilder setLanguage(String language) throws LocaleSyntaxException {
\r
42 if (language.length() > 0) {
\r
43 if (!LanguageTag.isLanguage(language)) {
\r
44 throw new LocaleSyntaxException("Ill-formed language: " + language, 0);
\r
46 newval = LanguageTag.canonicalizeLanguage(language);
\r
52 public InternalLocaleBuilder setScript(String script) throws LocaleSyntaxException {
\r
54 if (script.length() > 0) {
\r
55 if (!LanguageTag.isScript(script)) {
\r
56 throw new LocaleSyntaxException("Ill-formed script: " + script, 0);
\r
58 newval = LanguageTag.canonicalizeScript(script);
\r
64 public InternalLocaleBuilder setRegion(String region) throws LocaleSyntaxException {
\r
66 if (region.length() > 0) {
\r
67 if (!LanguageTag.isRegion(region)) {
\r
68 throw new LocaleSyntaxException("Ill-formed region: " + region);
\r
70 newval = LanguageTag.canonicalizeRegion(region);
\r
76 public InternalLocaleBuilder setVariant(String variant) throws LocaleSyntaxException {
\r
78 if (variant.length() > 0) {
\r
79 if (_lenientVariant) {
\r
82 newval = processVariant(variant);
\r
89 public InternalLocaleBuilder setUnicodeLocaleExtension(String key, String type) throws LocaleSyntaxException {
\r
90 if (key.length() == 0) {
\r
91 throw new LocaleSyntaxException("Empty Unicode locale extension key");
\r
93 if (!UnicodeLocaleExtension.isKey(key)) {
\r
94 throw new LocaleSyntaxException("Ill-formed Unicode locale extension key: " + key, 0);
\r
97 key = UnicodeLocaleExtension.canonicalizeKey(key);
\r
99 UnicodeLocaleExtension ulext = null;
\r
100 if (_extMap != null) {
\r
101 ulext = (UnicodeLocaleExtension)_extMap.get(Character.valueOf(UnicodeLocaleExtension.SINGLETON));
\r
104 if (type.length() == 0) {
\r
105 if (ulext != null) {
\r
107 if (ulext.isEmpty()) {
\r
108 _extMap.remove(Character.valueOf(UnicodeLocaleExtension.SINGLETON));
\r
112 StringBuilder buf = new StringBuilder();
\r
113 StringTokenIterator sti = new StringTokenIterator(type, LanguageTag.SEP);
\r
114 for (String subtag = sti.first(); !sti.isDone(); subtag = sti.next()) {
\r
115 if (!UnicodeLocaleExtension.isTypeSubtag(subtag)) {
\r
116 throw new LocaleSyntaxException("Ill-formed Unicode locale extension type: " + type, sti.currentStart());
\r
118 if (buf.length() > 0) {
\r
119 buf.append(LanguageTag.SEP);
\r
121 buf.append(UnicodeLocaleExtension.canonicalizeTypeSubtag(subtag));
\r
123 if (ulext == null) {
\r
124 SortedMap<String, String> ktmap = new TreeMap<String, String>();
\r
125 ktmap.put(key, buf.toString());
\r
126 ulext = new UnicodeLocaleExtension(ktmap);
\r
127 if (_extMap == null) {
\r
128 _extMap = new TreeMap<Character, Extension>();
\r
130 _extMap.put(Character.valueOf(UnicodeLocaleExtension.SINGLETON), ulext);
\r
132 ulext.put(key, buf.toString());
\r
139 public InternalLocaleBuilder setExtension(char singleton, String value) throws LocaleSyntaxException {
\r
140 String strSingleton = String.valueOf(singleton);
\r
141 if (!LanguageTag.isExtensionSingleton(strSingleton) && !LanguageTag.isPrivateuseSingleton(strSingleton)) {
\r
142 throw new LocaleSyntaxException("Ill-formed extension key: " + singleton);
\r
145 strSingleton = LanguageTag.canonicalizeExtensionSingleton(strSingleton);
\r
146 Character key = Character.valueOf(strSingleton.charAt(0));
\r
148 if (value.length() == 0) {
\r
149 if (_extMap != null) {
\r
150 _extMap.remove(key);
\r
153 StringTokenIterator sti = new StringTokenIterator(value, LanguageTag.SEP);
\r
154 ParseStatus sts = new ParseStatus();
\r
156 Extension ext = Extension.create(key.charValue(), sti, sts);
\r
157 if (sts.isError()) {
\r
158 throw new LocaleSyntaxException(sts.errorMsg, sts.errorIndex);
\r
160 if (sts.parseLength != value.length() || ext == null) {
\r
161 throw new LocaleSyntaxException("Ill-formed extension value: " + value, sti.currentStart());
\r
163 if (_extMap == null) {
\r
164 _extMap = new TreeMap<Character, Extension>();
\r
166 _extMap.put(key, ext);
\r
171 public InternalLocaleBuilder setLocale(BaseLocale base, LocaleExtensions extensions) throws LocaleSyntaxException {
\r
172 String language = base.getLanguage();
\r
173 String script = base.getScript();
\r
174 String region = base.getRegion();
\r
175 String variant = base.getVariant();
\r
177 // Validate base locale fields before updating internal state.
\r
178 // LocaleExtensions always store validated/canonicalized values,
\r
179 // so no checks are necessary.
\r
180 if (language.length() > 0) {
\r
181 if (!LanguageTag.isLanguage(language)) {
\r
182 throw new LocaleSyntaxException("Ill-formed language: " + language);
\r
184 language = LanguageTag.canonicalizeLanguage(language);
\r
186 if (script.length() > 0) {
\r
187 if (!LanguageTag.isScript(script)) {
\r
188 throw new LocaleSyntaxException("Ill-formed script: " + script);
\r
190 script = LanguageTag.canonicalizeScript(script);
\r
192 if (region.length() > 0) {
\r
193 if (!LanguageTag.isRegion(region)) {
\r
194 throw new LocaleSyntaxException("Ill-formed region: " + region);
\r
196 region = LanguageTag.canonicalizeRegion(region);
\r
198 if (_lenientVariant) {
\r
199 // In lenient variant mode, parse special private use value
\r
200 // reserved for Java Locale.
\r
201 String privuse = extensions.getExtensionValue(Character.valueOf(LanguageTag.PRIVATEUSE.charAt(0)));
\r
202 if (privuse != null) {
\r
203 variant = LanguageTag.getJavaCompatibleVariant(variant, privuse);
\r
206 if (variant.length() > 0) {
\r
207 variant = processVariant(variant);
\r
211 // update builder's internal fields
\r
212 _language = language;
\r
215 _variant = variant;
\r
217 // empty extensions
\r
218 if (_extMap == null) {
\r
219 _extMap = new TreeMap<Character, Extension>();
\r
224 Set<Character> extKeys = extensions.getKeys();
\r
225 for (Character key : extKeys) {
\r
226 Extension ext = extensions.getExtension(key);
\r
227 if (_lenientVariant && (ext instanceof PrivateuseExtension)) {
\r
228 String modPrivuse = LanguageTag.getJavaCompatiblePrivateuse(ext.getValue());
\r
229 if (!modPrivuse.equals(ext.getValue())) {
\r
230 ext = new PrivateuseExtension(modPrivuse);
\r
233 _extMap.put(key, ext);
\r
239 public InternalLocaleBuilder clear() {
\r
244 removeLocaleExtensions();
\r
248 public InternalLocaleBuilder removeLocaleExtensions() {
\r
249 if (_extMap != null) {
\r
255 public BaseLocale getBaseLocale() {
\r
256 return BaseLocale.getInstance(_language, _script, _region, _variant);
\r
259 public LocaleExtensions getLocaleExtensions() {
\r
260 if (_extMap != null && _extMap.size() > 0) {
\r
261 return LocaleExtensions.getInstance(_extMap);
\r
263 return LocaleExtensions.EMPTY_EXTENSIONS;
\r
266 private String processVariant(String variant) throws LocaleSyntaxException {
\r
267 StringTokenIterator sti = new StringTokenIterator(variant, LOCALESEP);
\r
268 ParseStatus sts = new ParseStatus();
\r
270 List<String> variants = LanguageTag.DEFAULT_PARSER.parseVariants(sti, sts);
\r
271 if (sts.parseLength != variant.length()) {
\r
272 throw new LocaleSyntaxException("Ill-formed variant: " + variant, sti.currentStart());
\r
275 StringBuilder buf = new StringBuilder();
\r
276 for (String var : variants) {
\r
277 if (buf.length() != 0) {
\r
278 buf.append(LOCALESEP);
\r
282 return buf.toString();
\r