diff --git a/samples/MvcSample.Web/LanguageViewLocationExpander.cs b/samples/MvcSample.Web/LanguageViewLocationExpander.cs
deleted file mode 100644
index 026034c04d..0000000000
--- a/samples/MvcSample.Web/LanguageViewLocationExpander.cs
+++ /dev/null
@@ -1,69 +0,0 @@
-// Copyright (c) .NET Foundation. All rights reserved.
-// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
-
-using System;
-using System.Collections.Generic;
-using Microsoft.AspNet.Mvc;
-using Microsoft.AspNet.Mvc.Razor;
-
-namespace MvcSample.Web
-{
- ///
- /// A that replaces adds the language as an extension prefix to view names.
- ///
- ///
- /// For the default case with no areas, views are generated with the following patterns (assuming controller is
- /// "Home", action is "Index" and language is "en")
- /// Views/Home/en/Action
- /// Views/Home/Action
- /// Views/Shared/en/Action
- /// Views/Shared/Action
- ///
- public class LanguageViewLocationExpander : IViewLocationExpander
- {
- private const string ValueKey = "language";
- private readonly Func _valueFactory;
-
- ///
- /// Initializes a new instance of .
- ///
- /// A factory that provides tbe language to use for expansion.
- public LanguageViewLocationExpander(Func valueFactory)
- {
- _valueFactory = valueFactory;
- }
-
- ///
- public void PopulateValues(ViewLocationExpanderContext context)
- {
- var value = _valueFactory(context.ActionContext);
- if (!string.IsNullOrEmpty(value))
- {
- context.Values[ValueKey] = value;
- }
- }
-
- ///
- public virtual IEnumerable ExpandViewLocations(ViewLocationExpanderContext context,
- IEnumerable viewLocations)
- {
- string value;
- if (context.Values.TryGetValue(ValueKey, out value))
- {
- return ExpandViewLocationsCore(viewLocations, value);
- }
-
- return viewLocations;
- }
-
- private IEnumerable ExpandViewLocationsCore(IEnumerable viewLocations,
- string value)
- {
- foreach (var location in viewLocations)
- {
- yield return location.Replace("{0}", value + "/{0}");
- yield return location;
- }
- }
- }
-}
\ No newline at end of file
diff --git a/samples/MvcSample.Web/Startup.cs b/samples/MvcSample.Web/Startup.cs
index 13c775c228..2a0c067af1 100644
--- a/samples/MvcSample.Web/Startup.cs
+++ b/samples/MvcSample.Web/Startup.cs
@@ -46,6 +46,8 @@ namespace MvcSample.Web
options.Filters.Add(new FormatFilterAttribute());
});
+ services.AddMvcLocalization();
+
#if DNX451
// Fully-qualify configuration path to avoid issues in functional tests. Just "config.json" would be fine
// but Configuration uses CallContextServiceLocator.Locator.ServiceProvider to get IApplicationEnvironment.
@@ -63,12 +65,6 @@ namespace MvcSample.Web
diSystem.Equals("AutoFac", StringComparison.OrdinalIgnoreCase))
{
_autoFac = true;
- services.ConfigureRazorViewEngine(options =>
- {
- var expander = new LanguageViewLocationExpander(
- context => context.HttpContext.Request.Query["language"]);
- options.ViewLocationExpanders.Insert(0, expander);
- });
// Create the autofac container
var builder = new ContainerBuilder();
@@ -102,6 +98,7 @@ namespace MvcSample.Web
app.UseMiddleware();
}
#endif
+ app.UseRequestLocalization();
app.UseInMemorySession();
app.UseMvc(routes =>
diff --git a/samples/MvcSample.Web/project.json b/samples/MvcSample.Web/project.json
index 75301e7a2d..4da7f577a7 100644
--- a/samples/MvcSample.Web/project.json
+++ b/samples/MvcSample.Web/project.json
@@ -9,6 +9,7 @@
"dependencies": {
"Kestrel": "1.0.0-*",
"Microsoft.AspNet.Diagnostics": "1.0.0-*",
+ "Microsoft.AspNet.Localization": "1.0.0-*",
"Microsoft.AspNet.Mvc": "6.0.0-*",
"Microsoft.AspNet.Mvc.Xml": "6.0.0-*",
"Microsoft.AspNet.Mvc.WebApiCompatShim": "6.0.0-*",
diff --git a/src/Microsoft.AspNet.Mvc.Razor/LanguageViewLocationExpander.cs b/src/Microsoft.AspNet.Mvc.Razor/LanguageViewLocationExpander.cs
new file mode 100644
index 0000000000..4b5c4c5aef
--- /dev/null
+++ b/src/Microsoft.AspNet.Mvc.Razor/LanguageViewLocationExpander.cs
@@ -0,0 +1,83 @@
+// Copyright (c) .NET Foundation. All rights reserved.
+// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+
+using System;
+using System.Collections.Generic;
+using System.Globalization;
+using System.Linq;
+using System.Threading;
+using Microsoft.Framework.Internal;
+
+namespace Microsoft.AspNet.Mvc.Razor
+{
+ ///
+ /// A that adds the language as an extension prefix to view names. Language
+ /// that is getting added as extension prefix comes from .
+ ///
+ ///
+ /// For the default case with no areas, views are generated with the following patterns (assuming controller is
+ /// "Home", action is "Index" and language is "en")
+ /// Views/Home/en/Action
+ /// Views/Home/Action
+ /// Views/Shared/en/Action
+ /// Views/Shared/Action
+ ///
+ public class LanguageViewLocationExpander : IViewLocationExpander
+ {
+ private const string ValueKey = "language";
+
+ ///
+ public void PopulateValues([NotNull] ViewLocationExpanderContext context)
+ {
+ // Using CurrentUICulture so it loads the locale specific resources for the views.
+#if DNX451
+ context.Values[ValueKey] = Thread.CurrentThread.CurrentUICulture.Name;
+#else
+ context.Values[ValueKey] = CultureInfo.CurrentUICulture.Name;
+#endif
+ }
+
+ ///
+ public virtual IEnumerable ExpandViewLocations(
+ [NotNull] ViewLocationExpanderContext context,
+ [NotNull] IEnumerable viewLocations)
+ {
+ string value;
+ context.Values.TryGetValue(ValueKey, out value);
+
+ if (!string.IsNullOrEmpty(value))
+ {
+ CultureInfo culture;
+ try
+ {
+ culture = new CultureInfo(value);
+ }
+ catch (CultureNotFoundException)
+ {
+ return viewLocations;
+ }
+
+ return ExpandViewLocationsCore(viewLocations, culture);
+ }
+
+ return viewLocations;
+ }
+
+ private IEnumerable ExpandViewLocationsCore(IEnumerable viewLocations, CultureInfo cultureInfo)
+ {
+ foreach (var location in viewLocations)
+ {
+ var temporaryCultureInfo = cultureInfo;
+
+ while (temporaryCultureInfo != temporaryCultureInfo.Parent)
+ {
+ yield return location.Replace("{0}", temporaryCultureInfo.Name + "/{0}");
+
+ temporaryCultureInfo = temporaryCultureInfo.Parent;
+ }
+
+ yield return location;
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/Microsoft.AspNet.Mvc/MvcServiceCollectionExtensions.cs b/src/Microsoft.AspNet.Mvc/MvcServiceCollectionExtensions.cs
index 851889f04e..147bad8336 100644
--- a/src/Microsoft.AspNet.Mvc/MvcServiceCollectionExtensions.cs
+++ b/src/Microsoft.AspNet.Mvc/MvcServiceCollectionExtensions.cs
@@ -254,6 +254,16 @@ namespace Microsoft.Framework.DependencyInjection
return WithControllersAsServices(services, controllerTypes.Select(type => type.AsType()));
}
+ public static IServiceCollection AddMvcLocalization([NotNull] this IServiceCollection services)
+ {
+ services.ConfigureRazorViewEngine(options =>
+ {
+ options.ViewLocationExpanders.Add(new LanguageViewLocationExpander());
+ });
+
+ return services;
+ }
+
private static void ConfigureDefaultServices(IServiceCollection services)
{
services.AddOptions();
diff --git a/test/Microsoft.AspNet.Mvc.FunctionalTests/HtmlHelperOptionsTest.cs b/test/Microsoft.AspNet.Mvc.FunctionalTests/HtmlHelperOptionsTest.cs
index 9e16cbc932..529b5bb145 100644
--- a/test/Microsoft.AspNet.Mvc.FunctionalTests/HtmlHelperOptionsTest.cs
+++ b/test/Microsoft.AspNet.Mvc.FunctionalTests/HtmlHelperOptionsTest.cs
@@ -60,7 +60,7 @@ False";
An error occurred.
-
+
True
@@ -70,7 +70,7 @@ True
An error occurred.
-
+
True";
diff --git a/test/Microsoft.AspNet.Mvc.FunctionalTests/ViewEngineTests.cs b/test/Microsoft.AspNet.Mvc.FunctionalTests/ViewEngineTests.cs
index f92ef73bbb..6224b3d6a3 100644
--- a/test/Microsoft.AspNet.Mvc.FunctionalTests/ViewEngineTests.cs
+++ b/test/Microsoft.AspNet.Mvc.FunctionalTests/ViewEngineTests.cs
@@ -7,6 +7,7 @@ using System.Reflection;
using System.Threading.Tasks;
using Microsoft.AspNet.Builder;
using Microsoft.Framework.DependencyInjection;
+using Microsoft.Net.Http.Headers;
using RazorWebSite;
using Xunit;
@@ -138,7 +139,7 @@ component-content";
var expected1 = string.Join(Environment.NewLine,
"expander-index",
"gb-partial");
- yield return new[] { "gb", expected1 };
+ yield return new[] { "en-GB", expected1 };
var expected2 = string.Join(Environment.NewLine,
"fr-index",
@@ -159,10 +160,13 @@ component-content";
// Arrange
var server = TestHelper.CreateServer(_app, SiteName, _configureServices);
var client = server.CreateClient();
+ var cultureCookie = "c=" + value + "|uic=" + value;
+ client.DefaultRequestHeaders.Add(
+ "Cookie",
+ new CookieHeaderValue("ASPNET_CULTURE", cultureCookie).ToString());
// Act
- var body = await client.GetStringAsync("http://localhost/TemplateExpander?language-expander-value=" +
- value);
+ var body = await client.GetStringAsync("http://localhost/TemplateExpander");
// Assert
Assert.Equal(expected, body.Trim());
@@ -288,7 +292,7 @@ ViewWithNestedLayout-Content
View With Layout
";
- yield return new[] { "gb", expected1 };
+ yield return new[] { "en-GB", expected1 };
yield return new[] { "na", expected1 };
var expected2 =
@@ -307,10 +311,13 @@ View With Layout
// Arrange
var server = TestHelper.CreateServer(_app, SiteName, _configureServices);
var client = server.CreateClient();
+ var cultureCookie = "c=" + value + "|uic=" + value;
+ client.DefaultRequestHeaders.Add(
+ "Cookie",
+ new CookieHeaderValue("ASPNET_CULTURE", cultureCookie).ToString());
// Act
- var body = await client.GetStringAsync("http://localhost/TemplateExpander/ViewWithLayout?language-expander-value=" +
- value);
+ var body = await client.GetStringAsync("http://localhost/TemplateExpander/ViewWithLayout");
// Assert
Assert.Equal(expected, body.Trim());
diff --git a/test/Microsoft.AspNet.Mvc.Razor.Test/LanguageViewLocationExpanderTest.cs b/test/Microsoft.AspNet.Mvc.Razor.Test/LanguageViewLocationExpanderTest.cs
new file mode 100644
index 0000000000..2b7dbd6a28
--- /dev/null
+++ b/test/Microsoft.AspNet.Mvc.Razor.Test/LanguageViewLocationExpanderTest.cs
@@ -0,0 +1,140 @@
+// Copyright (c) .NET Foundation. All rights reserved.
+// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+
+using System.Collections.Generic;
+using Xunit;
+
+namespace Microsoft.AspNet.Mvc.Razor
+{
+ public class LanguageViewLocationExpanderTest
+ {
+ public static IEnumerable