/// <summary> /// A new locale identifier with the all the empty subtags filled in /// with a likely value. /// </summary> /// <returns> /// A new locale identifier with all subtags filled in. /// </returns> public LocaleIdentifier MostLikelySubtags() { var result = (LocaleIdentifier)this.MemberwiseClone(); // Remove the script code 'Zzzz' and the region code 'ZZ' if they occur. if (result.Script == "Zzzz") { result.Script = String.Empty; } if (result.Region == "ZZ") { result.Region = String.Empty; } // Short cut if all subtags have a value. if (result.Language != "" && result.Script != "" && result.Region != "") { return(result); } // Find the language in likely subtags. var likely = new[] { $"{result.Language}_{result.Script}_{result.Region}", $"{result.Language}_{result.Region}", $"{result.Language}_{result.Script}", $"{result.Language}", $"und_{result.Script}", } .Select(k => k.Replace("__", "_").Trim('_')) .Where(k => k != String.Empty) .Distinct() .Select(k => Cldr.Instance .GetDocuments("common/supplemental/likelySubtags.xml") .FirstElementOrDefault($"supplementalData/likelySubtags/likelySubtag[@from='{k}']") ) .FirstOrDefault(e => e != null); if (likely != null) { var defaults = LocaleIdentifier.ParseBcp47(likely.GetAttribute("to", "")); if (result.Language == "") { result.Language = defaults.Language; } if (result.Script == "") { result.Script = defaults.Script; } if (result.Region == "") { result.Region = defaults.Region; } } return(result); }
/// <summary> /// A new locale idenyifer with empty subtags that <see cref="MostLikelySubtags"/> would fill. /// </summary> /// <returns> /// A new locale identifier. /// </returns> public LocaleIdentifier RemoveMostLikelySubtags() { var max = this.MostLikelySubtags(); max.Variants = new string[0]; var trials = new[] { max.Language, $"{max.Language}-{max.Region}", $"{max.Language}-{max.Script}" }; foreach (var trial in trials) { var id = LocaleIdentifier.ParseBcp47(trial); if (max.ToUnicodeLanguage() == id.MostLikelySubtags().ToUnicodeLanguage()) { id.Variants = this.Variants; return(id); } } max.Variants = this.Variants; return(max); }
/// <summary> /// Convert BCP 47 tag to a valid Unicode locale identifier /// </summary> string TransformFromBcp47() { // 1. Canonicalize the language tag (afterwards, there will be no extlang subtag) // 2. Replace the BCP 47 primary language subtag "und" with "root" if no script, region, // or variant subtags are present if (Language == "und" && Script == "" && Region == "" && Variants.Count() == 0) { Language = "root"; } // 3. If the BCP 47 primary language subtag matches the type attribute of a languageAlias // element in Supplemental Data, replace the language subtag with the replacement value. // 3.1 If there are additional subtags in the replacement value, add them to the result, but only // if there is no corresponding subtag already in the tag. var languageAlias = Cldr.Instance .GetDocuments("common/supplemental/supplementalMetadata.xml") .FirstElementOrDefault($"supplementalData/metadata/alias/languageAlias[@type='{Language}']"); if (languageAlias != null) { var replacement = LocaleIdentifier.ParseBcp47(languageAlias.GetAttribute("replacement", "")); Language = replacement.Language; if (Script == "") { Script = replacement.Script; } if (Region == "") { Region = replacement.Region; } } // 4. If the BCP 47 region subtag matches the type attribute of a territoryAlias // element in Supplemental Data, replace the language subtag with the replacement value, as follows: var territoryAlias = Cldr.Instance .GetDocuments("common/supplemental/supplementalMetadata.xml") .FirstElementOrDefault($"supplementalData/metadata/alias/territoryAlias[@type='{Region}']"); if (territoryAlias != null) { var replacements = territoryAlias.GetAttribute("replacement", "").Split(' '); // 4.1 If there is a single territory in the replacement, use it. var replacementValue = replacements[0]; // 4.2 If there are multiple territories: // 4.2.1 Look up the most likely territory for the base language code(and script, if there is one). // 4.2.2 If that likely territory is in the list, use it. // 4.2.3 Otherwise, use the first territory in the list. if (replacements.Length > 1) { var best = Cldr.Instance .GetDocuments("common/supplemental/likelySubtags.xml") .FirstElementOrDefault($"supplementalData/likelySubtags/likelySubtag[@from='{Language}']"); if (best != null) { var to = LocaleIdentifier.ParseBcp47(best.GetAttribute("to", "")); if (replacements.Contains(to.Region)) { replacementValue = to.Region; } } } Region = replacementValue; } // Verify that the subtags are defined. // TODO: Need StringRanges, see https://github.com/richardschneider/net-cldr/issues/2 if (Language != "" && !Cldr.Instance.IsLanguageDefined(Language)) { return($"Language '{Language}' is not defined."); } if (Script != "" && !Cldr.Instance.IsScriptDefined(Script)) { return($"Script '{Script}' is not defined."); } if (Region != "" && !Cldr.Instance.IsRegionDefined(Region)) { return($"Region '{Region}' is not defined."); } foreach (var variant in Variants) { if (!Cldr.Instance.IsVariantDefined(variant)) { return($"Language variant '{variant}' is not defined."); } } // TODO: U extensions // TODO: T extensions return(null); }