/// <summary> /// Initializes a new instance of the <see cref="T:VariantSubtag"/> class. /// </summary> /// <param name="subtag">The subtag.</param> /// <param name="name">The name.</param> public VariantSubtag(VariantSubtag subtag, string name) : this(subtag.Code, name, subtag.IsPrivateUse, subtag._prefixes) { }
/// <summary> /// Gets the subtags of the specified language tag. /// </summary> /// <param name="langTag">The language tag.</param> /// <param name="languageSubtag">The language subtag.</param> /// <param name="scriptSubtag">The script subtag.</param> /// <param name="regionSubtag">The region subtag.</param> /// <param name="variantSubtags">The variant and private-use subtags.</param> /// <returns></returns> public static bool TryGetSubtags(string langTag, out LanguageSubtag languageSubtag, out ScriptSubtag scriptSubtag, out RegionSubtag regionSubtag, out IEnumerable<VariantSubtag> variantSubtags) { if (langTag == null) throw new ArgumentNullException("langTag"); languageSubtag = null; scriptSubtag = null; regionSubtag = null; variantSubtags = null; Match match = LangTagPattern.Match(langTag); if (!match.Success) return false; var privateUseCodes = new List<string>(); Group privateUseGroup = match.Groups["privateuse"]; if (privateUseGroup.Success) privateUseCodes.AddRange(privateUseGroup.Value.Split(new[] {'-'}, StringSplitOptions.RemoveEmptyEntries).Skip(1)); Group languageGroup = match.Groups["language"]; if (languageGroup.Success) { string languageCode = languageGroup.Value; if (languageCode.Equals(WellKnownSubtags.UnlistedLanguage, StringComparison.OrdinalIgnoreCase)) { // In our own WS dialog, we don't allow no language, but if it isn't a standard one, a language like xkal // produces an identifier like qaa-x-kal, and we interepret the first thing after the x as a private // language code (not allowed as the first three characters according to the standard). // If it's NOT a valid language code (e.g., too many characters), probably came from some other // program. Treating it as a language code will fail if we try to create such a writing system, // since we will detect the invalid language code. So only interpret the first element // after the x as a language code if it is a valid one. Otherwise, we just let qaa be the language. if (privateUseCodes.Count > 0 && LangPattern.IsMatch(privateUseCodes[0]) && !StandardSubtags.CommonPrivateUseVariants.Contains(privateUseCodes[0])) { languageSubtag = new LanguageSubtag(privateUseCodes[0]); privateUseCodes.RemoveAt(0); } else { languageSubtag = WellKnownSubtags.UnlistedLanguage; // We do allow just plain qaa. } } else { if (!StandardSubtags.IsValidIso639LanguageCode(languageCode)) return false; languageSubtag = languageCode; } } Group scriptGroup = match.Groups["script"]; if (scriptGroup.Success) { string scriptCode = scriptGroup.Value; if (scriptCode.Equals("Qaaa", StringComparison.OrdinalIgnoreCase) && privateUseCodes.Count > 0 && ScriptPattern.IsMatch(privateUseCodes[0])) { scriptSubtag = new ScriptSubtag(privateUseCodes[0]); privateUseCodes.RemoveAt(0); } else { if (!StandardSubtags.IsValidIso15924ScriptCode(scriptCode)) return false; scriptSubtag = scriptCode; } } Group regionGroup = match.Groups["region"]; if (regionGroup.Success) { string regionCode = regionGroup.Value; if (regionCode.Equals("QM", StringComparison.OrdinalIgnoreCase) && privateUseCodes.Count > 0 && RegionPattern.IsMatch(privateUseCodes[0])) { regionSubtag = new RegionSubtag(privateUseCodes[0]); privateUseCodes.RemoveAt(0); } else { if (!StandardSubtags.IsValidIso3166RegionCode(regionCode)) return false; regionSubtag = regionCode; } } if (scriptSubtag == null) scriptSubtag = GetImplicitScriptCode(languageSubtag, regionSubtag); var variants = new HashSet<string>(StringComparer.InvariantCultureIgnoreCase); var variantSubtagsList = new List<VariantSubtag>(); Group variantGroup = match.Groups["variant"]; if (variantGroup.Success) { foreach (string variantCode in variantGroup.Value.Split(new[] {'-'}, StringSplitOptions.RemoveEmptyEntries)) { if (variants.Contains(variantCode)) return false; VariantSubtag variantSubtag; if (!StandardSubtags.RegisteredVariants.TryGet(variantCode, out variantSubtag)) return false; variantSubtagsList.Add(variantSubtag); variants.Add(variantCode); } } variants.Clear(); foreach (string privateUseCode in privateUseCodes) { if (variants.Contains(privateUseCode) || privateUseCode.Equals("x", StringComparison.InvariantCultureIgnoreCase)) return false; VariantSubtag variantSubtag; if (!StandardSubtags.CommonPrivateUseVariants.TryGet(privateUseCode, out variantSubtag)) variantSubtag = new VariantSubtag(privateUseCode); variantSubtagsList.Add(variantSubtag); variants.Add(privateUseCode); } variantSubtags = variantSubtagsList; return true; }
/// <summary> /// This method will make the IetfLanguageTag unique compared to list of language tags passed in by /// appending dupl# where # is a digit that increases with the number of duplicates found. /// </summary> /// <param name="ietfLanguageTag"></param> /// <param name="otherLangTags"></param> public static string ToUniqueLanguageTag(string ietfLanguageTag, IEnumerable<string> otherLangTags) { // Parse for variants LanguageSubtag languageSubtag; ScriptSubtag scriptSubtag; RegionSubtag regionSubtag; IEnumerable<VariantSubtag> variantSubtags; if (!TryGetSubtags(ietfLanguageTag, out languageSubtag, out scriptSubtag, out regionSubtag, out variantSubtags)) throw new ArgumentException("The IETF language tag is invalid.", "ietfLanguageTag"); List<VariantSubtag> variants = variantSubtags.ToList(); VariantSubtag lastDuplSubtag = null; int duplicateNumber = 0; var wsLangTags = new HashSet<string>(otherLangTags, StringComparer.InvariantCultureIgnoreCase); while (wsLangTags.Contains(ietfLanguageTag)) { if (lastDuplSubtag != null) variants.Remove(lastDuplSubtag); var curDuplStubtag = new VariantSubtag(string.Format("dupl{0}", duplicateNumber)); if (!variants.Contains(curDuplStubtag)) { variants.Add(curDuplStubtag); lastDuplSubtag = curDuplStubtag; } duplicateNumber++; ietfLanguageTag = Create(languageSubtag, scriptSubtag, regionSubtag, variants); } return ietfLanguageTag; }
public static bool TryGetVariantSubtags(string variantCodes, out IEnumerable<VariantSubtag> variantSubtags) { if (string.IsNullOrEmpty(variantCodes)) { variantSubtags = Enumerable.Empty<VariantSubtag>(); return true; } string standardVariantCodes, privateUseVariantCodes; SplitVariantAndPrivateUse(variantCodes, out standardVariantCodes, out privateUseVariantCodes); var variantSubtagsList = new List<VariantSubtag>(); foreach (string standardCode in standardVariantCodes.Split(new[] {'-'}, StringSplitOptions.RemoveEmptyEntries)) { VariantSubtag variantSubtag; if (StandardSubtags.RegisteredVariants.TryGet(standardCode, out variantSubtag)) { variantSubtagsList.Add(variantSubtag); } else { variantSubtags = null; return false; } } foreach (string privateUseCode in privateUseVariantCodes.Split(new[] { '-' }, StringSplitOptions.RemoveEmptyEntries)) { VariantSubtag variantSubtag; if (!StandardSubtags.CommonPrivateUseVariants.TryGet(privateUseCode, out variantSubtag)) variantSubtag = new VariantSubtag(privateUseCode); variantSubtagsList.Add(variantSubtag); } variantSubtags = variantSubtagsList; return true; }
/// <summary> /// Initializes a new instance of the <see cref="T:VariantSubtag"/> class. /// </summary> /// <param name="subtag">The subtag.</param> /// <param name="name">The name.</param> public VariantSubtag(VariantSubtag subtag, string name) : this(subtag.Code, name, subtag.IsPrivateUse, subtag.IsDeprecated, subtag._prefixes) { }