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.Separator); 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 ue) { foreach (string uatr in ue.UnicodeLocaleAttributes) { if (_uattributes == null) { _uattributes = new HashSet <CaseInsensitiveString>(/*4*/); } _uattributes.Add(new CaseInsensitiveString(uatr)); } foreach (string ukey in ue.UnicodeLocaleKeys) { 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); }
public static LanguageTag ParseLocale(BaseLocale baseLocale, LocaleExtensions localeExtensions) { LanguageTag tag = new LanguageTag(); string language = baseLocale.GetLanguage(); string script = baseLocale.GetScript(); string region = baseLocale.GetRegion(); string variant = baseLocale.GetVariant(); bool hasSubtag = false; string privuseVar = null; // store ill-formed variant subtags if (language.Length > 0 && IsLanguage(language)) { // Convert a deprecated language code used by Java to // a new code if (language.Equals("iw")) { language = "he"; } else if (language.Equals("ji")) { language = "yi"; } else if (language.Equals("in")) { language = "id"; } tag._language = language; } if (script.Length > 0 && IsScript(script)) { tag._script = CanonicalizeScript(script); hasSubtag = true; } if (region.Length > 0 && IsRegion(region)) { tag._region = CanonicalizeRegion(region); hasSubtag = true; } // ICU4N TODO: Remove ? if (JDKIMPL) { // Special handling for no_NO_NY - use nn_NO for language tag if (tag._language.Equals("no") && tag._region.Equals("NO") && variant.Equals("NY")) // ICU4N TODO: Fix this handling for .NET (no-NO is not reliable across platforms) { tag._language = "nn"; variant = ""; } } if (variant.Length > 0) { List <string> variants = null; StringTokenEnumerator varitr = new StringTokenEnumerator(variant, BaseLocale.SEP); while (varitr.MoveNext()) { string var = varitr.Current; if (!IsVariant(var)) { break; } if (variants == null) { variants = new List <string>(); } if (JDKIMPL) { variants.Add(var); // Do not canonicalize! } else { variants.Add(CanonicalizeVariant(var)); } } if (variants != null) { tag._variants = variants; hasSubtag = true; } if (!varitr.IsDone) { // ill-formed variant subtags StringBuilder buf = new StringBuilder(); while (!varitr.IsDone) { string prvv = varitr.Current; if (!IsPrivateuseSubtag(prvv)) { // cannot use private use subtag - truncated break; } if (buf.Length > 0) { buf.Append(SEP); } if (!JDKIMPL) { prvv = AsciiUtil.ToLowerString(prvv); } buf.Append(prvv); varitr.MoveNext(); } if (buf.Length > 0) { privuseVar = buf.ToString(); } } } List <string> extensions = null; string privateuse = null; var locextKeys = localeExtensions.Keys; foreach (char locextKey in locextKeys) { Extension ext = localeExtensions.GetExtension(locextKey); if (IsPrivateusePrefixChar(locextKey)) { privateuse = ext.Value; } else { if (extensions == null) { extensions = new List <string>(); } extensions.Add(locextKey.ToString() + SEP + ext.Value); } } if (extensions != null) { tag._extensions = extensions; hasSubtag = true; } // append ill-formed variant subtags to private use if (privuseVar != null) { if (privateuse == null) { privateuse = PRIVUSE_VARIANT_PREFIX + SEP + privuseVar; } else { privateuse = privateuse + SEP + PRIVUSE_VARIANT_PREFIX + SEP + privuseVar.Replace(BaseLocale.SEP, SEP); } } if (privateuse != null) { tag._privateuse = privateuse; } if (tag._language.Length == 0 && (hasSubtag || privateuse == null)) { // use lang "und" when 1) no language is available AND // 2) any of other subtags other than private use are available or // no private use tag is available tag._language = UNDETERMINED; } return(tag); }