diff --git a/samples/LocalizationSample.Web/Resources/Views.Home.Locpage.cshtml.en-GB.resx b/samples/LocalizationSample.Web/Resources/Views.Home.Locpage.en-GB.resx
similarity index 100%
rename from samples/LocalizationSample.Web/Resources/Views.Home.Locpage.cshtml.en-GB.resx
rename to samples/LocalizationSample.Web/Resources/Views.Home.Locpage.en-GB.resx
diff --git a/samples/LocalizationSample.Web/Resources/Views.Home.Locpage.cshtml.fr.resx b/samples/LocalizationSample.Web/Resources/Views.Home.Locpage.fr.resx
similarity index 100%
rename from samples/LocalizationSample.Web/Resources/Views.Home.Locpage.cshtml.fr.resx
rename to samples/LocalizationSample.Web/Resources/Views.Home.Locpage.fr.resx
diff --git a/samples/LocalizationSample.Web/Resources/Views.Shared._LocalizationLayout.cshtml.fr.resx b/samples/LocalizationSample.Web/Resources/Views.Shared._LocalizationLayout.fr.resx
similarity index 100%
rename from samples/LocalizationSample.Web/Resources/Views.Shared._LocalizationLayout.cshtml.fr.resx
rename to samples/LocalizationSample.Web/Resources/Views.Shared._LocalizationLayout.fr.resx
diff --git a/src/Microsoft.AspNet.Mvc.Localization/IViewLocalizer.cs b/src/Microsoft.AspNet.Mvc.Localization/IViewLocalizer.cs
index 8204e3205a..9f586d7f52 100644
--- a/src/Microsoft.AspNet.Mvc.Localization/IViewLocalizer.cs
+++ b/src/Microsoft.AspNet.Mvc.Localization/IViewLocalizer.cs
@@ -4,7 +4,7 @@
namespace Microsoft.AspNet.Mvc.Localization
{
///
- /// A service that provides localized strings for views.
+ /// Represents a type that provides HTML-aware localization for views.
///
public interface IViewLocalizer : IHtmlLocalizer
{
diff --git a/src/Microsoft.AspNet.Mvc.Localization/ViewLocalizer.cs b/src/Microsoft.AspNet.Mvc.Localization/ViewLocalizer.cs
index c45b038d38..657a98623d 100644
--- a/src/Microsoft.AspNet.Mvc.Localization/ViewLocalizer.cs
+++ b/src/Microsoft.AspNet.Mvc.Localization/ViewLocalizer.cs
@@ -3,7 +3,9 @@
using System;
using System.Collections.Generic;
+using System.Diagnostics;
using System.Globalization;
+using System.IO;
using Microsoft.AspNet.Mvc.Rendering;
using Microsoft.AspNet.Mvc.ViewFeatures.Internal;
using Microsoft.Extensions.Localization;
@@ -12,7 +14,8 @@ using Microsoft.Extensions.PlatformAbstractions;
namespace Microsoft.AspNet.Mvc.Localization
{
///
- /// A implementation that provides localized strings for views.
+ /// An implementation that derives the resource location from the executing view's
+ /// file path.
///
public class ViewLocalizer : IViewLocalizer, ICanHasViewContext
{
@@ -93,12 +96,30 @@ namespace Microsoft.AspNet.Mvc.Localization
throw new ArgumentNullException(nameof(viewContext));
}
- var baseName = viewContext.View.Path.Replace('/', '.').Replace('\\', '.');
- if (baseName.StartsWith(".", StringComparison.OrdinalIgnoreCase))
+ // Given a view path "/Views/Home/Index.cshtml" we want a baseName like "MyApplication.Views.Home.Index"
+
+ var path = viewContext.ExecutingFilePath;
+
+ if (string.IsNullOrEmpty(path))
{
- baseName = baseName.Substring(1);
+ path = viewContext.View.Path;
}
+ // Trim the file extension from the end of the path
+ if (!string.IsNullOrEmpty(path) && Path.HasExtension(path))
+ {
+ var extension = Path.GetExtension(path);
+ path = path.Substring(0, path.Length - extension.Length);
+ }
+
+ Debug.Assert(!string.IsNullOrEmpty(path), "Couldn't determine a path for the view");
+
+ var baseName = path.Replace('/', '.').Replace('\\', '.');
+ baseName = baseName.TrimStart('.');
+
+ // Prepend the application name
+ baseName = _applicationName + "." + baseName;
+
_localizer = _localizerFactory.Create(baseName, _applicationName);
}
}
diff --git a/test/Microsoft.AspNet.Mvc.Localization.Test/ViewLocalizerTest.cs b/test/Microsoft.AspNet.Mvc.Localization.Test/ViewLocalizerTest.cs
index 5b30ad9752..d695cd0b06 100644
--- a/test/Microsoft.AspNet.Mvc.Localization.Test/ViewLocalizerTest.cs
+++ b/test/Microsoft.AspNet.Mvc.Localization.Test/ViewLocalizerTest.cs
@@ -16,6 +16,39 @@ namespace Microsoft.AspNet.Mvc.Localization.Test
{
public class ViewLocalizerTest
{
+ [Theory]
+ [InlineData("TestApplication", "Views/Home/Index.cshtml", "Views/Home/Index.cshtml", "TestApplication.Views.Home.Index")]
+ [InlineData("TestApplication.Web", "Views/Home/Index.cshtml", "Views/Home/Index.cshtml", "TestApplication.Web.Views.Home.Index")]
+ [InlineData("TestApplication", "Views/Home/Index.cshtml", "Views/Shared/_Layout.cshtml", "TestApplication.Views.Shared._Layout")]
+ [InlineData("TestApplication", "Views/Home/Index.cshtml", "Views/Shared/_MyPartial.cshtml", "TestApplication.Views.Shared._MyPartial")]
+ [InlineData("TestApplication", "Views/Home/Index.cshtml", "Views/Home/_HomePartial.cshtml", "TestApplication.Views.Home._HomePartial")]
+ [InlineData("TestApplication", "Views/Home/Index.cshtml", null, "TestApplication.Views.Home.Index")]
+ [InlineData("TestApplication", "Views/Home/Index.txt", null, "TestApplication.Views.Home.Index")]
+ [InlineData("TestApplication", "Views/Home/Index.cshtml", "", "TestApplication.Views.Home.Index")]
+ [InlineData("TestApplication", "Views/Home/Index.txt", "", "TestApplication.Views.Home.Index")]
+ public void ViewLocalizer_LooksForCorrectResourceBaseNameLocation(string appName, string viewPath, string executingPath, string expectedBaseName)
+ {
+ // Arrange
+ var applicationEnvironment = new Mock();
+ applicationEnvironment.Setup(a => a.ApplicationName).Returns(appName);
+ var htmlLocalizerFactory = new Mock(MockBehavior.Loose);
+ var view = new Mock();
+ view.Setup(v => v.Path).Returns(viewPath);
+ var viewContext = new ViewContext();
+ viewContext.ExecutingFilePath = executingPath;
+ viewContext.View = view.Object;
+ var viewLocalizer = new ViewLocalizer(htmlLocalizerFactory.Object, applicationEnvironment.Object);
+
+ // Act
+ viewLocalizer.Contextualize(viewContext);
+
+ // Assert
+ htmlLocalizerFactory.Verify(h => h.Create(
+ It.Is(baseName => baseName == expectedBaseName),
+ It.Is(location => location == appName)
+ ));
+ }
+
[Fact]
public void ViewLocalizer_UseIndexer_ReturnsLocalizedHtmlString()
{
@@ -29,7 +62,7 @@ namespace Microsoft.AspNet.Mvc.Localization.Test
htmlLocalizer.Setup(h => h["Hello"]).Returns(localizedString);
var htmlLocalizerFactory = new Mock();
- htmlLocalizerFactory.Setup(h => h.Create("example", "TestApplication"))
+ htmlLocalizerFactory.Setup(h => h.Create("TestApplication.example", "TestApplication"))
.Returns(htmlLocalizer.Object);
var viewLocalizer = new ViewLocalizer(htmlLocalizerFactory.Object, applicationEnvironment.Object);
@@ -62,7 +95,7 @@ namespace Microsoft.AspNet.Mvc.Localization.Test
var htmlLocalizerFactory = new Mock();
htmlLocalizerFactory.Setup(
- h => h.Create("example", "TestApplication")).Returns(htmlLocalizer.Object);
+ h => h.Create("TestApplication.example", "TestApplication")).Returns(htmlLocalizer.Object);
var viewLocalizer = new ViewLocalizer(htmlLocalizerFactory.Object, applicationEnvironment.Object);