diff --git a/Mvc.sln b/Mvc.sln
index 485f478ec9..12b6171467 100644
--- a/Mvc.sln
+++ b/Mvc.sln
@@ -1,7 +1,7 @@
Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 14
-VisualStudioVersion = 14.0.22808.1
+VisualStudioVersion = 14.0.22823.1
MinimumVisualStudioVersion = 10.0.40219.1
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "samples", "samples", "{DAAE4C74-D06F-4874-A166-33305D2643CE}"
EndProject
@@ -168,6 +168,8 @@ Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Microsoft.AspNet.Mvc.ApiExp
EndProject
Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Microsoft.AspNet.Mvc.Abstractions.Test", "test\Microsoft.AspNet.Mvc.Abstractions.Test\Microsoft.AspNet.Mvc.Abstractions.Test.xproj", "{DA000953-7532-4DF5-8DB9-8143DF98D999}"
EndProject
+Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "LocalizationWebSite", "test\WebSites\LocalizationWebSite\LocalizationWebSite.xproj", "{FCFE6024-2720-49B4-8257-9DBC6114F0F1}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -1010,6 +1012,18 @@ Global
{DA000953-7532-4DF5-8DB9-8143DF98D999}.Release|Mixed Platforms.Build.0 = Release|Any CPU
{DA000953-7532-4DF5-8DB9-8143DF98D999}.Release|x86.ActiveCfg = Release|Any CPU
{DA000953-7532-4DF5-8DB9-8143DF98D999}.Release|x86.Build.0 = Release|Any CPU
+ {FCFE6024-2720-49B4-8257-9DBC6114F0F1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {FCFE6024-2720-49B4-8257-9DBC6114F0F1}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {FCFE6024-2720-49B4-8257-9DBC6114F0F1}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
+ {FCFE6024-2720-49B4-8257-9DBC6114F0F1}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
+ {FCFE6024-2720-49B4-8257-9DBC6114F0F1}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {FCFE6024-2720-49B4-8257-9DBC6114F0F1}.Debug|x86.Build.0 = Debug|Any CPU
+ {FCFE6024-2720-49B4-8257-9DBC6114F0F1}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {FCFE6024-2720-49B4-8257-9DBC6114F0F1}.Release|Any CPU.Build.0 = Release|Any CPU
+ {FCFE6024-2720-49B4-8257-9DBC6114F0F1}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
+ {FCFE6024-2720-49B4-8257-9DBC6114F0F1}.Release|Mixed Platforms.Build.0 = Release|Any CPU
+ {FCFE6024-2720-49B4-8257-9DBC6114F0F1}.Release|x86.ActiveCfg = Release|Any CPU
+ {FCFE6024-2720-49B4-8257-9DBC6114F0F1}.Release|x86.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@@ -1092,5 +1106,6 @@ Global
{A2B72833-5D70-4C42-AE85-E0319926FB8A} = {32285FA4-6B46-4D6B-A840-2B13E4C8B58E}
{4C2AD8AB-8AC0-46C4-80C6-C5577C7255F6} = {3BA657BF-28B1-42DA-B5B0-1C4601FCF7B1}
{DA000953-7532-4DF5-8DB9-8143DF98D999} = {3BA657BF-28B1-42DA-B5B0-1C4601FCF7B1}
+ {FCFE6024-2720-49B4-8257-9DBC6114F0F1} = {16703B76-C9F7-4C75-AE6C-53D92E308E3C}
EndGlobalSection
EndGlobal
diff --git a/samples/MvcSample.Web/Startup.cs b/samples/MvcSample.Web/Startup.cs
index dc2a6feb9f..7106abd18c 100644
--- a/samples/MvcSample.Web/Startup.cs
+++ b/samples/MvcSample.Web/Startup.cs
@@ -46,7 +46,7 @@ namespace MvcSample.Web
options.Filters.Add(new FormatFilterAttribute());
});
- services.AddMvcLocalization();
+ services.AddMvcLocalization(LanguageViewLocationExpanderOption.SubFolder);
#if DNX451
// Fully-qualify configuration path to avoid issues in functional tests. Just "config.json" would be fine
@@ -59,7 +59,9 @@ namespace MvcSample.Web
var configBuilder = new ConfigurationBuilder()
.AddJsonFile(configurationPath)
.AddEnvironmentVariables();
+
var configuration = configBuilder.Build();
+
string diSystem;
if (configuration.TryGet("DependencyInjection", out diSystem) &&
diSystem.Equals("AutoFac", StringComparison.OrdinalIgnoreCase))
diff --git a/src/Microsoft.AspNet.Mvc.Razor/LanguageViewLocationExpander.cs b/src/Microsoft.AspNet.Mvc.Razor/LanguageViewLocationExpander.cs
index 4b5c4c5aef..3fcc576e6d 100644
--- a/src/Microsoft.AspNet.Mvc.Razor/LanguageViewLocationExpander.cs
+++ b/src/Microsoft.AspNet.Mvc.Razor/LanguageViewLocationExpander.cs
@@ -25,6 +25,24 @@ namespace Microsoft.AspNet.Mvc.Razor
public class LanguageViewLocationExpander : IViewLocationExpander
{
private const string ValueKey = "language";
+ private LanguageViewLocationExpanderOption _option;
+
+ ///
+ /// Instantiates a new instance.
+ ///
+ public LanguageViewLocationExpander()
+ : this(LanguageViewLocationExpanderOption.Suffix)
+ {
+ }
+
+ ///
+ /// Instantiates a new instance.
+ ///
+ /// The .
+ public LanguageViewLocationExpander(LanguageViewLocationExpanderOption option)
+ {
+ _option = option;
+ }
///
public void PopulateValues([NotNull] ViewLocationExpanderContext context)
@@ -71,7 +89,14 @@ namespace Microsoft.AspNet.Mvc.Razor
while (temporaryCultureInfo != temporaryCultureInfo.Parent)
{
- yield return location.Replace("{0}", temporaryCultureInfo.Name + "/{0}");
+ if (_option == LanguageViewLocationExpanderOption.SubFolder)
+ {
+ yield return location.Replace("{0}", temporaryCultureInfo.Name + "/{0}");
+ }
+ else
+ {
+ yield return location.Replace("{0}", "{0}." + temporaryCultureInfo.Name);
+ }
temporaryCultureInfo = temporaryCultureInfo.Parent;
}
diff --git a/src/Microsoft.AspNet.Mvc.Razor/LanguageViewLocationExpanderOption.cs b/src/Microsoft.AspNet.Mvc.Razor/LanguageViewLocationExpanderOption.cs
new file mode 100644
index 0000000000..71f663e959
--- /dev/null
+++ b/src/Microsoft.AspNet.Mvc.Razor/LanguageViewLocationExpanderOption.cs
@@ -0,0 +1,27 @@
+// 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.
+
+namespace Microsoft.AspNet.Mvc.Razor
+{
+ ///
+ /// Specifies the localized view format for .
+ ///
+ public enum LanguageViewLocationExpanderOption
+ {
+ ///
+ /// Locale is a subfolder under which the view exisits.
+ ///
+ ///
+ /// Home/Views/en-US/Index.chtml
+ ///
+ SubFolder,
+
+ ///
+ /// Locale is part of the view name as a suffix.
+ ///
+ ///
+ /// Home/Views/Index.en-US.chtml
+ ///
+ Suffix
+ }
+}
diff --git a/src/Microsoft.AspNet.Mvc/MvcServiceCollectionExtensions.cs b/src/Microsoft.AspNet.Mvc/MvcServiceCollectionExtensions.cs
index 1d1a60b254..cf55c99f7b 100644
--- a/src/Microsoft.AspNet.Mvc/MvcServiceCollectionExtensions.cs
+++ b/src/Microsoft.AspNet.Mvc/MvcServiceCollectionExtensions.cs
@@ -263,11 +263,29 @@ namespace Microsoft.Framework.DependencyInjection
services.TryAdd(ServiceDescriptor.Singleton());
}
+ ///
+ /// Adds Mvc localization to the application.
+ ///
+ /// The .
+ /// The .
public static IServiceCollection AddMvcLocalization([NotNull] this IServiceCollection services)
+ {
+ return AddMvcLocalization(services, LanguageViewLocationExpanderOption.Suffix);
+ }
+
+ ///
+ /// Adds Mvc localization to the application.
+ ///
+ /// The .
+ /// The view format for localized views.
+ /// The .
+ public static IServiceCollection AddMvcLocalization(
+ [NotNull] this IServiceCollection services,
+ LanguageViewLocationExpanderOption option)
{
services.ConfigureRazorViewEngine(options =>
{
- options.ViewLocationExpanders.Add(new LanguageViewLocationExpander());
+ options.ViewLocationExpanders.Add(new LanguageViewLocationExpander(option));
});
return services;
diff --git a/test/Microsoft.AspNet.Mvc.FunctionalTests/LocalizationTest.cs b/test/Microsoft.AspNet.Mvc.FunctionalTests/LocalizationTest.cs
new file mode 100644
index 0000000000..19eb80bd5d
--- /dev/null
+++ b/test/Microsoft.AspNet.Mvc.FunctionalTests/LocalizationTest.cs
@@ -0,0 +1,75 @@
+// 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.Reflection;
+using System.Threading.Tasks;
+using LocalizationWebSite;
+using Microsoft.AspNet.Builder;
+using Microsoft.Framework.DependencyInjection;
+using Microsoft.Net.Http.Headers;
+using Xunit;
+
+namespace Microsoft.AspNet.Mvc.FunctionalTests
+{
+ public class LocalizationTest
+ {
+ private const string SiteName = nameof(LocalizationWebSite);
+ private static readonly Assembly _assembly = typeof(LocalizationTest).GetTypeInfo().Assembly;
+
+ private readonly Action _app = new Startup().Configure;
+ private readonly Action _configureServices = new Startup().ConfigureServices;
+
+ public static IEnumerable