diff --git a/src/Microsoft.Extensions.Localization/Properties/Resources.Designer.cs b/src/Microsoft.Extensions.Localization/Properties/Resources.Designer.cs
new file mode 100644
index 0000000000..1123d648ad
--- /dev/null
+++ b/src/Microsoft.Extensions.Localization/Properties/Resources.Designer.cs
@@ -0,0 +1,62 @@
+//
+namespace Microsoft.Extensions.Localization
+{
+ using System.Globalization;
+ using System.Reflection;
+ using System.Resources;
+
+ internal static class Resources
+ {
+ private static readonly ResourceManager _resourceManager
+ = new ResourceManager("Microsoft.Extensions.Localization.Resources", typeof(Resources).GetTypeInfo().Assembly);
+
+ ///
+ /// The manifest '{0}' was not found.
+ ///
+ internal static string Localization_MissingManifest
+ {
+ get { return GetString("Localization_MissingManifest"); }
+ }
+
+ ///
+ /// The manifest '{0}' was not found.
+ ///
+ internal static string FormatLocalization_MissingManifest(object p0)
+ {
+ return string.Format(CultureInfo.CurrentCulture, GetString("Localization_MissingManifest"), p0);
+ }
+
+ ///
+ /// No manifests exist for the current culture.
+ ///
+ internal static string Localization_MissingManifest_Parent
+ {
+ get { return GetString("Localization_MissingManifest_Parent"); }
+ }
+
+ ///
+ /// No manifests exist for the current culture.
+ ///
+ internal static string FormatLocalization_MissingManifest_Parent()
+ {
+ return GetString("Localization_MissingManifest_Parent");
+ }
+
+ private static string GetString(string name, params string[] formatterNames)
+ {
+ var value = _resourceManager.GetString(name);
+
+ System.Diagnostics.Debug.Assert(value != null);
+
+ if (formatterNames != null)
+ {
+ for (var i = 0; i < formatterNames.Length; i++)
+ {
+ value = value.Replace("{" + formatterNames[i] + "}", "{" + i + "}");
+ }
+ }
+
+ return value;
+ }
+ }
+}
diff --git a/src/Microsoft.Extensions.Localization/ResourceManagerStringLocalizer.cs b/src/Microsoft.Extensions.Localization/ResourceManagerStringLocalizer.cs
index 47d4884bd6..80a6af7d6d 100644
--- a/src/Microsoft.Extensions.Localization/ResourceManagerStringLocalizer.cs
+++ b/src/Microsoft.Extensions.Localization/ResourceManagerStringLocalizer.cs
@@ -153,6 +153,13 @@ namespace Microsoft.Extensions.Localization
? GetResourceNamesFromCultureHierarchy(culture)
: GetResourceNamesForCulture(culture);
+ if (resourceNames == null && !includeParentCultures)
+ {
+ var resourceStreamName = GetResourceStreamName(culture);
+ throw new MissingManifestResourceException(
+ Resources.FormatLocalization_MissingManifest(resourceStreamName));
+ }
+
foreach (var name in resourceNames)
{
var value = GetStringSafely(name, culture);
@@ -197,17 +204,21 @@ namespace Microsoft.Extensions.Localization
var currentCulture = startingCulture;
var resourceNames = new HashSet();
+ var hasAnyCultures = false;
+
while (true)
{
- try
+
+ var cultureResourceNames = GetResourceNamesForCulture(currentCulture);
+
+ if (cultureResourceNames != null)
{
- var cultureResourceNames = GetResourceNamesForCulture(currentCulture);
foreach (var resourceName in cultureResourceNames)
{
resourceNames.Add(resourceName);
}
+ hasAnyCultures = true;
}
- catch (MissingManifestResourceException) { }
if (currentCulture == currentCulture.Parent)
{
@@ -218,10 +229,15 @@ namespace Microsoft.Extensions.Localization
currentCulture = currentCulture.Parent;
}
+ if (!hasAnyCultures)
+ {
+ throw new MissingManifestResourceException(Resources.Localization_MissingManifest_Parent);
+ }
+
return resourceNames;
}
- private IList GetResourceNamesForCulture(CultureInfo culture)
+ private string GetResourceStreamName(CultureInfo culture)
{
var resourceStreamName = _resourceBaseName;
if (!string.IsNullOrEmpty(culture.Name))
@@ -230,22 +246,36 @@ namespace Microsoft.Extensions.Localization
}
resourceStreamName += ".resources";
+ return resourceStreamName;
+ }
+
+ private IList GetResourceNamesForCulture(CultureInfo culture)
+ {
+ var resourceStreamName = GetResourceStreamName(culture);
+
var cacheKey = $"assembly={_resourceAssemblyWrapper.FullName};resourceStreamName={resourceStreamName}";
var cultureResourceNames = _resourceNamesCache.GetOrAdd(cacheKey, _ =>
{
- var names = new List();
using (var cultureResourceStream = _resourceAssemblyWrapper.GetManifestResourceStream(resourceStreamName))
- using (var resources = new ResourceReader(cultureResourceStream))
{
- foreach (DictionaryEntry entry in resources)
+ if (cultureResourceStream == null)
{
- var resourceName = (string)entry.Key;
- names.Add(resourceName);
+ return null;
+ }
+
+ using (var resources = new ResourceReader(cultureResourceStream))
+ {
+ var names = new List();
+ foreach (DictionaryEntry entry in resources)
+ {
+ var resourceName = (string)entry.Key;
+ names.Add(resourceName);
+ }
+ return names;
}
}
- return names;
});
return cultureResourceNames;
diff --git a/src/Microsoft.Extensions.Localization/Resources.resx b/src/Microsoft.Extensions.Localization/Resources.resx
new file mode 100644
index 0000000000..b679f04664
--- /dev/null
+++ b/src/Microsoft.Extensions.Localization/Resources.resx
@@ -0,0 +1,126 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ text/microsoft-resx
+
+
+ 2.0
+
+
+ System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
+ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
+ The manifest '{0}' was not found.
+
+
+ No manifests exist for the current culture.
+
+
\ No newline at end of file
diff --git a/test/Microsoft.Extensions.Localization.Tests/ResourceManagerStringLocalizerTest.cs b/test/Microsoft.Extensions.Localization.Tests/ResourceManagerStringLocalizerTest.cs
index 0ec5a69dfa..ef8a6f074c 100644
--- a/test/Microsoft.Extensions.Localization.Tests/ResourceManagerStringLocalizerTest.cs
+++ b/test/Microsoft.Extensions.Localization.Tests/ResourceManagerStringLocalizerTest.cs
@@ -59,10 +59,60 @@ namespace Microsoft.Extensions.Localization.Tests
Assert.Equal(expectedCallCount, resourceAssembly2.GetManifestResourceStreamCallCount);
}
+ [Theory]
+ [InlineData(true)]
+ [InlineData(false)]
+ public void ResourceManagerStringLocalizer_GetAllStrings_ReturnsExpectedValue(bool includeParentCultures)
+ {
+ // Arrange
+ var baseName = "test";
+ var resourceNamesCache = new ResourceNamesCache();
+ var resourceAssembly = new TestAssemblyWrapper();
+ var resourceManager = new TestResourceManager(baseName, resourceAssembly.Assembly);
+ var localizer = new ResourceManagerStringLocalizer(resourceManager, resourceAssembly, baseName, resourceNamesCache);
+
+ // Act
+ // We have to access the result so it evaluates.
+ var strings = localizer.GetAllStrings(includeParentCultures).ToList();
+
+ // Assert
+ var value = Assert.Single(strings);
+ Assert.Equal("TestName", value.Value);
+ }
+
+ [Theory]
+ [InlineData(true)]
+ [InlineData(false)]
+ public void ResourceManagerStringLocalizer_GetAllStrings_MissingResourceThrows(bool includeParentCultures)
+ {
+ // Arrange
+ var resourceNamesCache = new ResourceNamesCache();
+ var baseName = "testington";
+ var resourceAssembly = new TestAssemblyWrapper("Assembly1");
+ var resourceManager = new TestResourceManager(baseName, resourceAssembly.Assembly);
+ var localizer = new ResourceManagerWithCultureStringLocalizer(
+ resourceManager,
+ resourceAssembly.Assembly,
+ baseName,
+ resourceNamesCache,
+ CultureInfo.CurrentCulture);
+
+ // Act & Assert
+ var exception = Assert.Throws(() =>
+ {
+ // We have to access the result so it evaluates.
+ localizer.GetAllStrings(includeParentCultures).ToArray();
+ });
+ var expected = includeParentCultures
+ ? "No manifests exist for the current culture."
+ : "The manifest 'testington.en-US.resources' was not found.";
+ Assert.Equal(expected, exception.Message);
+ }
+
private static Stream MakeResourceStream()
{
var stream = new MemoryStream();
- var resourceWriter = new ResourceWriter(stream);
+ var resourceWriter = new ResourceWriter(stream);
resourceWriter.AddResource("TestName", "value");
resourceWriter.Generate();
stream.Position = 0;