/// <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); }