public InternalLocaleBuilder RemoveUnicodeLocaleAttribute(string attribute) { if (attribute == null || !UnicodeLocaleExtension.IsAttribute(attribute)) { throw new FormatException("Ill-formed Unicode locale attribute: " + attribute); } if (_uattributes != null) { _uattributes.Remove(new CaseInsensitiveString(attribute)); } return(this); }
static UnicodeLocaleExtension() { CA_JAPANESE = new UnicodeLocaleExtension(); CA_JAPANESE._keywords = new SortedDictionary <string, string>(StringComparer.Ordinal); CA_JAPANESE._keywords["ca"] = "japanese"; CA_JAPANESE._value = "ca-japanese"; NU_THAI = new UnicodeLocaleExtension(); NU_THAI._keywords = new SortedDictionary <string, string>(StringComparer.Ordinal); NU_THAI._keywords["nu"] = "thai"; NU_THAI._value = "nu-thai"; }
public InternalLocaleBuilder AddUnicodeLocaleAttribute(string attribute) { if (attribute == null || !UnicodeLocaleExtension.IsAttribute(attribute)) { throw new FormatException("Ill-formed Unicode locale attribute: " + attribute); } // Use case insensitive string to prevent duplication if (_uattributes == null) { _uattributes = new HashSet <CaseInsensitiveString>(/*4*/); } _uattributes.Add(new CaseInsensitiveString(attribute)); return(this); }
public InternalLocaleBuilder SetUnicodeLocaleKeyword(string key, string type) { if (!UnicodeLocaleExtension.IsKey(key)) { throw new FormatException("Ill-formed Unicode locale keyword key: " + key); } CaseInsensitiveString cikey = new CaseInsensitiveString(key); if (type == null) { if (_ukeywords != null) { // null type is used for remove the key _ukeywords.Remove(cikey); } } else { if (type.Length != 0) { // normalize separator to "-" string tp = type.Replace(BaseLocale.Separator, LanguageTag.Separator); // validate StringTokenEnumerator itr = new StringTokenEnumerator(tp, LanguageTag.Separator); while (itr.MoveNext()) { string s = itr.Current; if (!UnicodeLocaleExtension.IsTypeSubtag(s)) { throw new FormatException("Ill-formed Unicode locale keyword type: " + type /*, itr.CurrentStart*/); } } } if (_ukeywords == null) { _ukeywords = new Dictionary <CaseInsensitiveString, string>(4); } _ukeywords[cikey] = type; } return(this); }
/// <summary> /// Set a list of BCP47 extensions and private use subtags. /// BCP47 extensions are already validated and well-formed, but may contain duplicates. /// </summary> private InternalLocaleBuilder SetExtensions(IList <string> bcpExtensions, string privateuse) { ClearExtensions(); if (bcpExtensions != null && bcpExtensions.Count > 0) { HashSet <CaseInsensitiveChar> processedExtensions = new HashSet <CaseInsensitiveChar>(/*bcpExtensions.Count*/); foreach (string bcpExt in bcpExtensions) { CaseInsensitiveChar key = new CaseInsensitiveChar(bcpExt[0]); // ignore duplicates if (!processedExtensions.Contains(key)) { // each extension string contains singleton, e.g. "a-abc-def" if (UnicodeLocaleExtension.IsSingletonChar(key.Value)) { SetUnicodeLocaleExtension(bcpExt.Substring(2)); } else { if (_extensions == null) { _extensions = new Dictionary <CaseInsensitiveChar, string>(4); } _extensions[key] = bcpExt.Substring(2); } } } } if (privateuse != null && privateuse.Length > 0) { // privateuse string contains prefix, e.g. "x-abc-def" if (_extensions == null) { _extensions = new Dictionary <CaseInsensitiveChar, string>(1); } _extensions[new CaseInsensitiveChar(privateuse[0])] = privateuse.Substring(2); } return(this); }
/// <summary> /// Private methods parsing Unicode Locale Extension subtags. /// Duplicated attributes/keywords will be ignored. /// The input must be a valid extension subtags (excluding singleton). /// </summary> private void SetUnicodeLocaleExtension(string subtags) { // wipe out existing attributes/keywords if (_uattributes != null) { _uattributes.Clear(); } if (_ukeywords != null) { _ukeywords.Clear(); } StringTokenEnumerator itr = new StringTokenEnumerator(subtags, LanguageTag.Separator); // parse attributes while (itr.MoveNext()) { if (!UnicodeLocaleExtension.IsAttribute(itr.Current)) { break; } if (_uattributes == null) { _uattributes = new HashSet <CaseInsensitiveString>(/*4*/); } _uattributes.Add(new CaseInsensitiveString(itr.Current)); } // parse keywords CaseInsensitiveString key = null; string type; int typeStart = -1; int typeEnd = -1; while (!itr.IsDone) { if (key != null) { if (UnicodeLocaleExtension.IsKey(itr.Current)) { // next keyword - emit previous one Debug.Assert(typeStart == -1 || typeEnd != -1); type = (typeStart == -1) ? "" : subtags.Substring(typeStart, typeEnd - typeStart); // ICU4N: Corrected 2nd parameter if (_ukeywords == null) { _ukeywords = new Dictionary <CaseInsensitiveString, string>(4); } _ukeywords[key] = type; // reset keyword info CaseInsensitiveString tmpKey = new CaseInsensitiveString(itr.Current); key = _ukeywords.ContainsKey(tmpKey) ? null : tmpKey; typeStart = typeEnd = -1; } else { if (typeStart == -1) { typeStart = itr.CurrentStart; } typeEnd = itr.CurrentEnd; } } else if (UnicodeLocaleExtension.IsKey(itr.Current)) { // 1. first keyword or // 2. next keyword, but previous one was duplicate key = new CaseInsensitiveString(itr.Current); if (_ukeywords != null && _ukeywords.ContainsKey(key)) { // duplicate key = null; } } if (!itr.HasNext) { if (key != null) { // last keyword Debug.Assert(typeStart == -1 || typeEnd != -1); type = (typeStart == -1) ? "" : subtags.Substring(typeStart, typeEnd - typeStart); // ICU4N: Corrected 2nd parameter if (_ukeywords == null) { _ukeywords = new Dictionary <CaseInsensitiveString, string>(4); } _ukeywords[key] = type; } break; } itr.MoveNext(); } }
public InternalLocaleBuilder SetExtension(char singleton, string value) { // validate key bool isBcpPrivateuse = LanguageTag.IsPrivateusePrefixChar(singleton); if (!isBcpPrivateuse && !LanguageTag.IsExtensionSingletonChar(singleton)) { throw new FormatException("Ill-formed extension key: " + singleton); } bool remove = (value == null || value.Length == 0); CaseInsensitiveChar key = new CaseInsensitiveChar(singleton); if (remove) { if (UnicodeLocaleExtension.IsSingletonChar(key.Value)) { // clear entire Unicode locale extension if (_uattributes != null) { _uattributes.Clear(); } if (_ukeywords != null) { _ukeywords.Clear(); } } else { if (_extensions != null && _extensions.ContainsKey(key)) { _extensions.Remove(key); } } } else { // validate value string val = value.Replace(BaseLocale.Separator, LanguageTag.Separator); StringTokenEnumerator itr = new StringTokenEnumerator(val, LanguageTag.Separator); while (itr.MoveNext()) { string s = itr.Current; bool validSubtag; if (isBcpPrivateuse) { validSubtag = LanguageTag.IsPrivateuseSubtag(s); } else { validSubtag = LanguageTag.IsExtensionSubtag(s); } if (!validSubtag) { throw new FormatException("Ill-formed extension value: " + s /*, itr.CurrentStart*/); } } if (UnicodeLocaleExtension.IsSingletonChar(key.Value)) { SetUnicodeLocaleExtension(val); } else { if (_extensions == null) { _extensions = new Dictionary <CaseInsensitiveChar, string>(4); } _extensions[key] = val; } } return(this); }
public InternalLocaleBuilder SetLocale(BaseLocale @base, LocaleExtensions extensions) { string language = @base.GetLanguage(); string script = @base.GetScript(); string region = @base.GetRegion(); string variant = @base.GetVariant(); // ICU4N TODO: Remove ? if (JDKIMPL) { // Special backward compatibility support // Exception 1 - ja_JP_JP if (language.Equals("ja") && region.Equals("JP") && variant.Equals("JP")) { // When locale ja_JP_JP is created, ca-japanese is always there. // The builder ignores the variant "JP" Debug.Assert("japanese".Equals(extensions.GetUnicodeLocaleType("ca"))); variant = ""; } // Exception 2 - th_TH_TH else if (language.Equals("th") && region.Equals("TH") && variant.Equals("TH")) { // When locale th_TH_TH is created, nu-thai is always there. // The builder ignores the variant "TH" Debug.Assert("thai".Equals(extensions.GetUnicodeLocaleType("nu"))); variant = ""; } // Exception 3 - no_NO_NY else if (language.Equals("no") && region.Equals("NO") && variant.Equals("NY")) // ICU4N TODO: Fix this handling for .NET (no-NO is not reliable across platforms) { // no_NO_NY is a valid locale and used by Java 6 or older versions. // The build ignores the variant "NY" and change the language to "nn". language = "nn"; variant = ""; } } // Validate base locale fields before updating internal state. // LocaleExtensions always store validated/canonicalized values, // so no checks are necessary. if (language.Length > 0 && !LanguageTag.IsLanguage(language)) { throw new FormatException("Ill-formed language: " + language); } if (script.Length > 0 && !LanguageTag.IsScript(script)) { throw new FormatException("Ill-formed script: " + script); } if (region.Length > 0 && !LanguageTag.IsRegion(region)) { throw new FormatException("Ill-formed region: " + region); // ICU4N TODO: Port LocaleSyntaxException (instead of FormatException) } if (variant.Length > 0) { int errIdx = CheckVariants(variant, BaseLocale.SEP); if (errIdx != -1) { throw new FormatException("Ill-formed variant: " + variant /*, errIdx*/); } } // The input locale is validated at this point. // Now, updating builder's internal fields. _language = language; _script = script; _region = region; _variant = variant; ClearExtensions(); var extKeys = (extensions == null) ? null : extensions.Keys; if (extKeys != null) { // map extensions back to builder's internal format foreach (char key in extKeys) { Extension e = extensions.GetExtension(key); if (e is UnicodeLocaleExtension) { UnicodeLocaleExtension ue = (UnicodeLocaleExtension)e; foreach (string uatr in ue.GetUnicodeLocaleAttributes()) { if (_uattributes == null) { _uattributes = new HashSet <CaseInsensitiveString>(/*4*/); } _uattributes.Add(new CaseInsensitiveString(uatr)); } foreach (string ukey in ue.GetUnicodeLocaleKeys()) { if (_ukeywords == null) { _ukeywords = new Dictionary <CaseInsensitiveString, string>(4); } _ukeywords[new CaseInsensitiveString(ukey)] = ue.GetUnicodeLocaleType(ukey); } } else { if (_extensions == null) { _extensions = new Dictionary <CaseInsensitiveChar, string>(4); } _extensions[new CaseInsensitiveChar(key)] = e.Value; } } } return(this); }
/// <summary> /// Internal constructor, only used by <see cref="InternalLocaleBuilder"/>. /// </summary> internal LocaleExtensions(IDictionary <CaseInsensitiveChar, string> extensions, ISet <CaseInsensitiveString> uattributes, IDictionary <CaseInsensitiveString, string> ukeywords) { bool hasExtension = (extensions != null && extensions.Count > 0); bool hasUAttributes = (uattributes != null && uattributes.Count > 0); bool hasUKeywords = (ukeywords != null && ukeywords.Count > 0); if (!hasExtension && !hasUAttributes && !hasUKeywords) { _map = EmptyMap; _id = ""; return; } // Build extension map _map = new JCG.SortedDictionary <char, Extension>(); if (hasExtension) { foreach (var ext in extensions) { char key = AsciiUtil.ToLower(ext.Key.Value); string value = ext.Value; if (LanguageTag.IsPrivateusePrefixChar(key)) { // we need to exclude special variant in privuateuse, e.g. "x-abc-lvariant-DEF" value = InternalLocaleBuilder.RemovePrivateuseVariant(value); if (value == null) { continue; } } Extension e = new Extension(key, AsciiUtil.ToLower(value)); _map[key] = e; } } if (hasUAttributes || hasUKeywords) { JCG.SortedSet <string> uaset = null; JCG.SortedDictionary <string, string> ukmap = null; if (hasUAttributes) { uaset = new JCG.SortedSet <string>(StringComparer.Ordinal); foreach (CaseInsensitiveString cis in uattributes) { uaset.Add(AsciiUtil.ToLower(cis.Value)); } } if (hasUKeywords) { ukmap = new JCG.SortedDictionary <string, string>(StringComparer.Ordinal); foreach (var kwd in ukeywords) { string key = AsciiUtil.ToLower(kwd.Key.Value); string type = AsciiUtil.ToLower(kwd.Value); ukmap[key] = type; } } UnicodeLocaleExtension ule = new UnicodeLocaleExtension(uaset, ukmap); _map[UnicodeLocaleExtension.Singleton] = ule; } if (_map.Count == 0) { // this could happen when only privuateuse with special variant _map = EmptyMap; _id = ""; } else { _id = ToID(_map); } }
public static bool IsValidUnicodeLocaleKey(string ukey) { return(UnicodeLocaleExtension.IsKey(ukey)); }