/* ******************************************************************************* * Copyright (C) 2009, International Business Machines Corporation and * * others. All Rights Reserved. * ******************************************************************************* */ package com.ibm.icu.impl.locale; import java.util.List; import java.util.Set; import java.util.SortedMap; import java.util.TreeMap; import com.ibm.icu.impl.locale.LanguageTag.ParseStatus; public final class InternalLocaleBuilder { private String _language = ""; private String _script = ""; private String _region = ""; private String _variant = ""; private SortedMap _extMap; private final boolean _lenientVariant; private static final String LOCALESEP = "_"; public InternalLocaleBuilder() { this(false); } public InternalLocaleBuilder(boolean lenientVariant) { _lenientVariant = lenientVariant; } public boolean isLenientVariant() { return _lenientVariant; } public InternalLocaleBuilder setLanguage(String language) throws LocaleSyntaxException { String newval = ""; if (language.length() > 0) { if (!LanguageTag.isLanguage(language)) { throw new LocaleSyntaxException("Ill-formed language: " + language, 0); } newval = LanguageTag.canonicalizeLanguage(language); } _language = newval; return this; } public InternalLocaleBuilder setScript(String script) throws LocaleSyntaxException { String newval = ""; if (script.length() > 0) { if (!LanguageTag.isScript(script)) { throw new LocaleSyntaxException("Ill-formed script: " + script, 0); } newval = LanguageTag.canonicalizeScript(script); } _script = newval; return this; } public InternalLocaleBuilder setRegion(String region) throws LocaleSyntaxException { String newval = ""; if (region.length() > 0) { if (!LanguageTag.isRegion(region)) { throw new LocaleSyntaxException("Ill-formed region: " + region); } newval = LanguageTag.canonicalizeRegion(region); } _region = newval; return this; } public InternalLocaleBuilder setVariant(String variant) throws LocaleSyntaxException { String newval = ""; if (variant.length() > 0) { if (_lenientVariant) { newval = variant; } else { newval = processVariant(variant); } } _variant = newval; return this; } public InternalLocaleBuilder setUnicodeLocaleExtension(String key, String type) throws LocaleSyntaxException { if (key.length() == 0) { throw new LocaleSyntaxException("Empty Unicode locale extension key"); } if (!UnicodeLocaleExtension.isKey(key)) { throw new LocaleSyntaxException("Ill-formed Unicode locale extension key: " + key, 0); } key = UnicodeLocaleExtension.canonicalizeKey(key); UnicodeLocaleExtension ulext = null; if (_extMap != null) { ulext = (UnicodeLocaleExtension)_extMap.get(Character.valueOf(UnicodeLocaleExtension.SINGLETON)); } if (type.length() == 0) { if (ulext != null) { ulext.remove(key); if (ulext.isEmpty()) { _extMap.remove(Character.valueOf(UnicodeLocaleExtension.SINGLETON)); } } } else { StringBuilder buf = new StringBuilder(); StringTokenIterator sti = new StringTokenIterator(type, LanguageTag.SEP); for (String subtag = sti.first(); !sti.isDone(); subtag = sti.next()) { if (!UnicodeLocaleExtension.isTypeSubtag(subtag)) { throw new LocaleSyntaxException("Ill-formed Unicode locale extension type: " + type, sti.currentStart()); } if (buf.length() > 0) { buf.append(LanguageTag.SEP); } buf.append(UnicodeLocaleExtension.canonicalizeTypeSubtag(subtag)); } if (ulext == null) { SortedMap ktmap = new TreeMap(); ktmap.put(key, buf.toString()); ulext = new UnicodeLocaleExtension(ktmap); if (_extMap == null) { _extMap = new TreeMap(); } _extMap.put(Character.valueOf(UnicodeLocaleExtension.SINGLETON), ulext); } else { ulext.put(key, buf.toString()); } } return this; } public InternalLocaleBuilder setExtension(char singleton, String value) throws LocaleSyntaxException { String strSingleton = String.valueOf(singleton); if (!LanguageTag.isExtensionSingleton(strSingleton) && !LanguageTag.isPrivateuseSingleton(strSingleton)) { throw new LocaleSyntaxException("Ill-formed extension key: " + singleton); } strSingleton = LanguageTag.canonicalizeExtensionSingleton(strSingleton); Character key = Character.valueOf(strSingleton.charAt(0)); if (value.length() == 0) { if (_extMap != null) { _extMap.remove(key); } } else { StringTokenIterator sti = new StringTokenIterator(value, LanguageTag.SEP); ParseStatus sts = new ParseStatus(); Extension ext = Extension.create(key.charValue(), sti, sts); if (sts.isError()) { throw new LocaleSyntaxException(sts.errorMsg, sts.errorIndex); } if (sts.parseLength != value.length() || ext == null) { throw new LocaleSyntaxException("Ill-formed extension value: " + value, sti.currentStart()); } if (_extMap == null) { _extMap = new TreeMap(); } _extMap.put(key, ext); } 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(); // Validate base locale fields before updating internal state. // LocaleExtensions always store validated/canonicalized values, // so no checks are necessary. if (language.length() > 0) { if (!LanguageTag.isLanguage(language)) { throw new LocaleSyntaxException("Ill-formed language: " + language); } language = LanguageTag.canonicalizeLanguage(language); } if (script.length() > 0) { if (!LanguageTag.isScript(script)) { throw new LocaleSyntaxException("Ill-formed script: " + script); } script = LanguageTag.canonicalizeScript(script); } if (region.length() > 0) { if (!LanguageTag.isRegion(region)) { throw new LocaleSyntaxException("Ill-formed region: " + region); } region = LanguageTag.canonicalizeRegion(region); } if (_lenientVariant) { // In lenient variant mode, parse special private use value // reserved for Java Locale. String privuse = extensions.getExtensionValue(Character.valueOf(LanguageTag.PRIVATEUSE.charAt(0))); if (privuse != null) { variant = LanguageTag.getJavaCompatibleVariant(variant, privuse); } } else { if (variant.length() > 0) { variant = processVariant(variant); } } // update builder's internal fields _language = language; _script = script; _region = region; _variant = variant; // empty extensions if (_extMap == null) { _extMap = new TreeMap(); } else { _extMap.clear(); } Set extKeys = extensions.getKeys(); for (Character key : extKeys) { Extension ext = extensions.getExtension(key); if (_lenientVariant && (ext instanceof PrivateuseExtension)) { String modPrivuse = LanguageTag.getJavaCompatiblePrivateuse(ext.getValue()); if (!modPrivuse.equals(ext.getValue())) { ext = new PrivateuseExtension(modPrivuse); } } _extMap.put(key, ext); } return this; } public InternalLocaleBuilder clear() { _language = ""; _script = ""; _region = ""; _variant = ""; removeLocaleExtensions(); return this; } public InternalLocaleBuilder removeLocaleExtensions() { if (_extMap != null) { _extMap.clear(); } return this; } public BaseLocale getBaseLocale() { return BaseLocale.getInstance(_language, _script, _region, _variant); } public LocaleExtensions getLocaleExtensions() { if (_extMap != null && _extMap.size() > 0) { return LocaleExtensions.getInstance(_extMap); } return LocaleExtensions.EMPTY_EXTENSIONS; } private String processVariant(String variant) throws LocaleSyntaxException { StringTokenIterator sti = new StringTokenIterator(variant, LOCALESEP); ParseStatus sts = new ParseStatus(); List variants = LanguageTag.DEFAULT_PARSER.parseVariants(sti, sts); if (sts.parseLength != variant.length()) { throw new LocaleSyntaxException("Ill-formed variant: " + variant, sti.currentStart()); } StringBuilder buf = new StringBuilder(); for (String var : variants) { if (buf.length() != 0) { buf.append(LOCALESEP); } buf.append(var); } return buf.toString(); } }