public static ErrorResource Parse(XElement errorXml) { Contracts.AssertValue(errorXml); var errorResource = new ErrorResource(); // Parse each sub-element into the TagToValues dictionary. foreach (var tag in errorXml.Elements()) { string tagName = tag.Name.LocalName; // Links are specialized because they are a two-part resource. if (tagName == LinkTag) { errorResource.AddHelpLink(tag); } else { if (!errorResource.TagToValues.ContainsKey(tagName)) { errorResource.TagToValues[tagName] = new List <string>(); } errorResource.TagToValues[tagName].Add(tag.Element("value").Value); } } return(errorResource); }
public static bool TryGetErrorResource(ErrorResourceKey resourceKey, out ErrorResource resourceValue, string locale = null) { Contracts.CheckValue(resourceKey.Key, "action"); Contracts.CheckValueOrNull(locale, "locale"); if (locale == null) { locale = CurrentLocaleInfo.CurrentUILanguageName; Contracts.CheckNonEmpty(locale, "currentLocale"); } Dictionary <string, ErrorResource> errorResources; if (!ErrorResources.TryGetValue(locale, out errorResources)) { lock (dictionaryLock) { Dictionary <string, string> strings; LoadFromResource(locale, ResourceNamePrefix, typeof(TypeFromThisAssembly), ResourceFileName, ResourceFormat.Resw, out strings, out errorResources); Strings[locale] = strings; ErrorResources[locale] = errorResources; } } return(errorResources.TryGetValue(resourceKey.Key, out resourceValue) || (ExternalStringResources?.TryGetErrorResource(resourceKey, out resourceValue, locale) ?? false)); }
private static Dictionary <string, ErrorResource> PostProcessErrorResources(Dictionary <string, string> separateResourceKeys) { // ErrorResource name -> ErrorResourceTag -> tag number -> value var errorResources = new Dictionary <string, Dictionary <string, Dictionary <int, string> > >(StringComparer.OrdinalIgnoreCase); foreach (var resource in separateResourceKeys) { if (!resource.Key.StartsWith(ErrorResource.ReswErrorResourcePrefix, StringComparison.OrdinalIgnoreCase)) { continue; } // Skip URLs, we'll handle that paired with the link tag if (resource.Key.EndsWith(ErrorResource.LinkTagUrlTag, StringComparison.OrdinalIgnoreCase)) { continue; } foreach (var tag in ErrorResource.ErrorResourceTagToReswSuffix) { if (!ErrorResource.IsTagMultivalue(tag.Key)) { if (!resource.Key.EndsWith(tag.Value, StringComparison.OrdinalIgnoreCase)) { continue; } // Single valued tag, we use index=0 here when inserting var resourceName = resource.Key.Substring(ErrorResource.ReswErrorResourcePrefix.Length, resource.Key.Length - (ErrorResource.ReswErrorResourcePrefix.Length + tag.Value.Length)); UpdateErrorResource(resourceName, resource.Value, tag.Key, 0, errorResources); break; } else { if (!TryGetMultiValueSuffix(resource.Key, tag.Value, out var suffix, out var index)) { continue; } var resourceName = resource.Key.Substring(ErrorResource.ReswErrorResourcePrefix.Length, resource.Key.Length - (ErrorResource.ReswErrorResourcePrefix.Length + suffix.Length)); UpdateErrorResource(resourceName, resource.Value, tag.Key, index, errorResources); // Also handle the URL for link resources if (tag.Key == ErrorResource.LinkTag) { // This must exist, and the .verify call will fail CI builds if the resource is incorrectly defined. separateResourceKeys.TryGetValue(resource.Key + "_url", out var urlValue).Verify(); UpdateErrorResource(resourceName, urlValue, ErrorResource.LinkTagUrlTag, index, errorResources); } break; } } } return(errorResources.ToDictionary(kvp => kvp.Key, kvp => ErrorResource.Reassemble(kvp.Value))); }
public static ErrorResource Reassemble(Dictionary <string, Dictionary <int, string> > members) { Contracts.AssertAllNonEmpty(members.Keys); Contracts.AssertAllValues(members.Values); var errorResource = new ErrorResource(); // Reassemble link 2-part resources first // They need to match up. Because these resources are loaded for almost all tests, // The asserts here will fail during unit tests if they're incorrectly defined if (members.TryGetValue(LinkTag, out var linkValues)) { members.TryGetValue(LinkTagUrlTag, out var urls).Verify(); Contracts.Assert(linkValues.Count == urls.Count); foreach (var kvp in linkValues) { urls.TryGetValue(kvp.Key, out var correspondingUrl).Verify(); errorResource.HelpLinks.Add(new ErrorHelpLink(kvp.Value, correspondingUrl)); } members.Remove(LinkTag); members.Remove(LinkTagUrlTag); } foreach (var tag in members) { if (!errorResource.TagToValues.ContainsKey(tag.Key)) { errorResource.TagToValues[tag.Key] = new List <string>(); } foreach (var value in tag.Value.OrderBy(kvp => kvp.Key).Select(kvp => kvp.Value)) { errorResource.TagToValues[tag.Key].Add(value); } } return(errorResource); }
internal static void LoadFromResource(string locale, string assemblyPrefix, Type typeFromAssembly, string resourceFileName, ResourceFormat resourceFormat, out Dictionary <string, string> strings, out Dictionary <string, ErrorResource> errorResources) { var assembly = typeFromAssembly.Assembly; // This is being done because the filename of the manifest is case sensitive e.g. given zh-CN it was returning English if (locale.Equals("zh-CN")) { locale = "zh-cn"; } else if (locale.Equals("zh-TW")) { locale = "zh-tw"; } else if (locale.Equals("ko-KR")) { locale = "ko-kr"; } using (var res = assembly.GetManifestResourceStream(assemblyPrefix + locale.Replace("-", "_") + "." + resourceFileName)) { if (res == null) { if (locale == FallbackLocale) { throw new InvalidProgramException(string.Format("[StringResources] Resources not found for locale '{0}' and failed to find fallback", locale)); } // Load the default ones (recursive, but not infinite due to check above) LoadFromResource(FallbackLocale, assemblyPrefix, typeFromAssembly, resourceFileName, resourceFormat, out strings, out errorResources); } else { var loadedStrings = XDocument.Load(res).Descendants(XName.Get("data")); strings = new Dictionary <string, string>(StringComparer.OrdinalIgnoreCase); errorResources = new Dictionary <string, ErrorResource>(StringComparer.OrdinalIgnoreCase); if (resourceFormat == ResourceFormat.Pares) { foreach (var item in loadedStrings) { string type; if (item.TryGetNonEmptyAttributeValue("type", out type) && type == ErrorResource.XmlType) { errorResources[item.Attribute("name").Value] = ErrorResource.Parse(item); } else { strings[item.Attribute("name").Value] = item.Element("value").Value; } } } else if (resourceFormat == ResourceFormat.Resw) { var separatedResourceKeys = new Dictionary <string, string>(StringComparer.OrdinalIgnoreCase); foreach (var item in loadedStrings) { var itemName = item.Attribute("name").Value; if (itemName.StartsWith(ErrorResource.ReswErrorResourcePrefix, StringComparison.OrdinalIgnoreCase)) { separatedResourceKeys[itemName] = item.Element("value").Value; } else { strings[itemName] = item.Element("value").Value; } } errorResources = PostProcessErrorResources(separatedResourceKeys); } else { Contracts.Assert(false, "Unknown Resource Format"); } } } }