Skip to content
This repository was archived by the owner on Feb 23, 2021. It is now read-only.

Commit 7a53120

Browse files
committed
Add a sample demonstrating culture based selection for Razor Pages
1 parent 2fcbabe commit 7a53120

File tree

9 files changed

+213
-1
lines changed

9 files changed

+213
-1
lines changed

Entropy.sln

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
Microsoft Visual Studio Solution File, Format Version 12.00
1+
Microsoft Visual Studio Solution File, Format Version 12.00
22
# Visual Studio 15
33
VisualStudioVersion = 15.0.26730.12
44
MinimumVisualStudioVersion = 10.0.40219.1
@@ -131,6 +131,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Mvc.CustomRazorPageHandlers
131131
EndProject
132132
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Mvc.RazorPagePartial", "samples\Mvc.RazorPagePartial\Mvc.RazorPagePartial.csproj", "{D98E6BE8-F1A8-47E7-BC34-017825DCF24E}"
133133
EndProject
134+
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Mvc.LocalizedRazorPages", "samples\Mvc.LocalizedRazorPages\Mvc.LocalizedRazorPages.csproj", "{507E3F7C-DB1A-4674-B542-BA33BAD419D8}"
135+
EndProject
134136
Global
135137
GlobalSection(SolutionConfigurationPlatforms) = preSolution
136138
Debug|Any CPU = Debug|Any CPU
@@ -729,6 +731,18 @@ Global
729731
{D98E6BE8-F1A8-47E7-BC34-017825DCF24E}.Release|x64.Build.0 = Release|Any CPU
730732
{D98E6BE8-F1A8-47E7-BC34-017825DCF24E}.Release|x86.ActiveCfg = Release|Any CPU
731733
{D98E6BE8-F1A8-47E7-BC34-017825DCF24E}.Release|x86.Build.0 = Release|Any CPU
734+
{507E3F7C-DB1A-4674-B542-BA33BAD419D8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
735+
{507E3F7C-DB1A-4674-B542-BA33BAD419D8}.Debug|Any CPU.Build.0 = Debug|Any CPU
736+
{507E3F7C-DB1A-4674-B542-BA33BAD419D8}.Debug|x64.ActiveCfg = Debug|Any CPU
737+
{507E3F7C-DB1A-4674-B542-BA33BAD419D8}.Debug|x64.Build.0 = Debug|Any CPU
738+
{507E3F7C-DB1A-4674-B542-BA33BAD419D8}.Debug|x86.ActiveCfg = Debug|Any CPU
739+
{507E3F7C-DB1A-4674-B542-BA33BAD419D8}.Debug|x86.Build.0 = Debug|Any CPU
740+
{507E3F7C-DB1A-4674-B542-BA33BAD419D8}.Release|Any CPU.ActiveCfg = Release|Any CPU
741+
{507E3F7C-DB1A-4674-B542-BA33BAD419D8}.Release|Any CPU.Build.0 = Release|Any CPU
742+
{507E3F7C-DB1A-4674-B542-BA33BAD419D8}.Release|x64.ActiveCfg = Release|Any CPU
743+
{507E3F7C-DB1A-4674-B542-BA33BAD419D8}.Release|x64.Build.0 = Release|Any CPU
744+
{507E3F7C-DB1A-4674-B542-BA33BAD419D8}.Release|x86.ActiveCfg = Release|Any CPU
745+
{507E3F7C-DB1A-4674-B542-BA33BAD419D8}.Release|x86.Build.0 = Release|Any CPU
732746
EndGlobalSection
733747
GlobalSection(SolutionProperties) = preSolution
734748
HideSolutionNode = FALSE
@@ -794,6 +808,7 @@ Global
794808
{8A61FA46-3FD4-42BE-80C6-E5931387590C} = {5BCA2B8A-37DA-4A88-A221-3D5B4796B07F}
795809
{C673D327-412E-45E6-A12F-A8D37551793F} = {8B204FB8-31A6-4559-AE7F-0412F504983C}
796810
{D98E6BE8-F1A8-47E7-BC34-017825DCF24E} = {5BCA2B8A-37DA-4A88-A221-3D5B4796B07F}
811+
{507E3F7C-DB1A-4674-B542-BA33BAD419D8} = {8B204FB8-31A6-4559-AE7F-0412F504983C}
797812
EndGlobalSection
798813
GlobalSection(ExtensibilityGlobals) = postSolution
799814
SolutionGuid = {5DF584CA-249D-432C-BBA9-4498414C8E97}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
<Project Sdk="Microsoft.NET.Sdk.Web">
2+
3+
<PropertyGroup>
4+
<TargetFramework>netcoreapp2.1</TargetFramework>
5+
</PropertyGroup>
6+
7+
<ItemGroup>
8+
<PackageReference Include="Microsoft.AspNetCore.App" />
9+
</ItemGroup>
10+
11+
</Project>
Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
using System;
2+
using System.Diagnostics;
3+
using System.Globalization;
4+
using Microsoft.AspNetCore.Localization;
5+
using Microsoft.AspNetCore.Mvc.ActionConstraints;
6+
using Microsoft.AspNetCore.Mvc.ApplicationModels;
7+
8+
namespace LocalizedRazorPages
9+
{
10+
public class PageCultureConvention : IPageRouteModelConvention
11+
{
12+
public void Apply(PageRouteModel model)
13+
{
14+
var path = model.ViewEnginePath;
15+
var lastSeparator = path.LastIndexOf('/');
16+
Debug.Assert(lastSeparator != -1);
17+
var lastDot = path.LastIndexOf('.', path.Length - 1, path.Length - lastSeparator);
18+
19+
// /SomeFolder/MyPage.fr-FR -> fr-FR
20+
if (lastDot != -1)
21+
{
22+
var cultureName = path.Substring(lastDot + 1);
23+
var constraint = new CultureConstraint(new CultureInfo(cultureName));
24+
for (var i = model.Selectors.Count - 1; i >= 0; i--)
25+
{
26+
var selector = model.Selectors[i];
27+
28+
selector.ActionConstraints.Add(constraint);
29+
var template = selector.AttributeRouteModel.Template;
30+
template = template.Substring(0, lastDot - 1);
31+
32+
selector.AttributeRouteModel.Template = template;
33+
var fileName = template.Substring(lastSeparator);
34+
35+
if (fileName == "Index")
36+
{
37+
selector.AttributeRouteModel.SuppressLinkGeneration = true;
38+
39+
var indexSelector = new SelectorModel(selector);
40+
41+
template = selector.AttributeRouteModel.Template.Substring(0, lastSeparator);
42+
indexSelector.AttributeRouteModel.Template = template;
43+
model.Selectors.Add(indexSelector);
44+
}
45+
}
46+
}
47+
}
48+
49+
private class CultureConstraint : IActionConstraint
50+
{
51+
private readonly CultureInfo _culture;
52+
53+
public CultureConstraint(CultureInfo culture)
54+
{
55+
_culture = culture;
56+
}
57+
58+
public int Order => 0;
59+
60+
public bool Accept(ActionConstraintContext context)
61+
{
62+
var feature = context.RouteContext.HttpContext.Features.Get<IRequestCultureFeature>();
63+
if (feature == null)
64+
{
65+
// The page is associated with a culture but the request is not.
66+
return false;
67+
}
68+
69+
return string.Equals(feature.RequestCulture.Culture.Name, _culture.Name, StringComparison.OrdinalIgnoreCase);
70+
}
71+
}
72+
}
73+
}
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
@page
2+
@model IndexModel
3+
4+
Neutral culture
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Linq;
4+
using System.Threading.Tasks;
5+
using Microsoft.AspNetCore.Mvc;
6+
using Microsoft.AspNetCore.Mvc.RazorPages;
7+
8+
namespace LocalizedRazorPages.Pages
9+
{
10+
public class IndexModel : PageModel
11+
{
12+
public void OnGet()
13+
{
14+
15+
}
16+
}
17+
}
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
@page
2+
@model IndexModel
3+
4+
French culture
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
@using LocalizedRazorPages
2+
@namespace LocalizedRazorPages.Pages
3+
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.IO;
4+
using System.Linq;
5+
using System.Threading.Tasks;
6+
using Microsoft.AspNetCore;
7+
using Microsoft.AspNetCore.Hosting;
8+
using Microsoft.Extensions.Configuration;
9+
using Microsoft.Extensions.Logging;
10+
11+
namespace LocalizedRazorPages
12+
{
13+
public class Program
14+
{
15+
public static void Main(string[] args)
16+
{
17+
CreateWebHostBuilder(args).Build().Run();
18+
}
19+
20+
public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
21+
WebHost.CreateDefaultBuilder(args)
22+
.UseStartup<Startup>();
23+
}
24+
}
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Linq;
4+
using System.Threading.Tasks;
5+
using Microsoft.AspNetCore.Builder;
6+
using Microsoft.AspNetCore.Hosting;
7+
using Microsoft.AspNetCore.Http;
8+
using Microsoft.AspNetCore.HttpsPolicy;
9+
using Microsoft.AspNetCore.Mvc;
10+
using Microsoft.Extensions.Configuration;
11+
using Microsoft.Extensions.DependencyInjection;
12+
13+
namespace LocalizedRazorPages
14+
{
15+
public class Startup
16+
{
17+
public Startup(IConfiguration configuration)
18+
{
19+
Configuration = configuration;
20+
}
21+
22+
public IConfiguration Configuration { get; }
23+
24+
// This method gets called by the runtime. Use this method to add services to the container.
25+
public void ConfigureServices(IServiceCollection services)
26+
{
27+
services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1)
28+
.AddRazorPagesOptions(options =>
29+
{
30+
options.Conventions.Add(new PageCultureConvention());
31+
});
32+
}
33+
34+
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
35+
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
36+
{
37+
if (env.IsDevelopment())
38+
{
39+
app.UseDeveloperExceptionPage();
40+
}
41+
else
42+
{
43+
app.UseExceptionHandler("/Error");
44+
app.UseHsts();
45+
}
46+
47+
app.UseRequestLocalization(options =>
48+
{
49+
var supportedCultures = new[] { "en-US", "fr-FR" };
50+
options.AddSupportedCultures(supportedCultures);
51+
options.AddSupportedUICultures(supportedCultures);
52+
});
53+
54+
app.UseHttpsRedirection();
55+
app.UseStaticFiles();
56+
app.UseCookiePolicy();
57+
58+
app.UseMvc();
59+
}
60+
}
61+
}

0 commit comments

Comments
 (0)