Skip to content

Commit 6c1912f

Browse files
committed
Add request culture provider for request localization
1 parent 64086e6 commit 6c1912f

File tree

2 files changed

+68
-2
lines changed

2 files changed

+68
-2
lines changed

src/Framework/Framework/Hosting/Middlewares/DotvvmRoutingMiddleware.cs

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
using System;
44
using System.Collections.Generic;
55
using System.Linq;
6+
using System.Net.Http;
67
using System.Reflection;
78
using System.Threading.Tasks;
89
using DotVVM.Framework.Runtime.Tracing;
@@ -40,9 +41,14 @@ private static bool TryParseGooglebotHashbangEscapedFragment(string queryString,
4041

4142
public static string GetRouteMatchUrl(IDotvvmRequestContext context)
4243
{
43-
if (!TryParseGooglebotHashbangEscapedFragment(context.HttpContext.Request.Url.Query, out var url))
44+
return GetRouteMatchUrl(context.HttpContext.Request.Path.Value!, context.HttpContext.Request.Url.Query);
45+
}
46+
47+
public static string GetRouteMatchUrl(string requestPath, string queryString)
48+
{
49+
if (!TryParseGooglebotHashbangEscapedFragment(queryString, out var url))
4450
{
45-
url = context.HttpContext.Request.Path.Value;
51+
url = requestPath;
4652
}
4753
url = url?.Trim('/') ?? "";
4854

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
#nullable enable
2+
using System;
3+
using System.Collections;
4+
using System.Collections.Generic;
5+
using System.Linq;
6+
using System.Threading.Tasks;
7+
using DotVVM.Framework.Configuration;
8+
using DotVVM.Framework.Hosting.Middlewares;
9+
using DotVVM.Framework.Routing;
10+
using Microsoft.AspNetCore.Http;
11+
using Microsoft.AspNetCore.Localization;
12+
using Microsoft.Extensions.DependencyInjection;
13+
14+
namespace DotVVM.Framework.Hosting.AspNetCore.Localization;
15+
16+
public class DotvvmRoutingRequestCultureProvider : IRequestCultureProvider
17+
{
18+
private static readonly object locker = new();
19+
private static IReadOnlyList<LocalizedDotvvmRoute>? cachedRoutes;
20+
21+
public Task<ProviderCultureResult?> DetermineProviderCultureResult(HttpContext httpContext)
22+
{
23+
EnsureCachedRoutes(httpContext);
24+
25+
// find matching localizable route and extract culture from it
26+
var url = DotvvmRoutingMiddleware.GetRouteMatchUrl(httpContext.Request.Path.Value!, httpContext.Request.QueryString.Value!);
27+
foreach (var route in cachedRoutes!)
28+
{
29+
if (route.IsPartialMatch(url, out _, out var values, out var matchedCulture))
30+
{
31+
return Task.FromResult<ProviderCultureResult?>(new ProviderCultureResult(matchedCulture));
32+
}
33+
}
34+
35+
return Task.FromResult<ProviderCultureResult?>(null);
36+
}
37+
38+
private void EnsureCachedRoutes(HttpContext httpContext)
39+
{
40+
if (cachedRoutes == null)
41+
{
42+
lock (locker)
43+
{
44+
if (cachedRoutes == null)
45+
{
46+
// try to obtain DotVVM configuration
47+
if (httpContext.RequestServices.GetService<DotvvmConfiguration>() is not { } config)
48+
{
49+
throw new InvalidOperationException("DotVVM configuration not found in the service provider.");
50+
}
51+
52+
// try to obtain DotVVM routes
53+
cachedRoutes = config.RouteTable
54+
.OfType<LocalizedDotvvmRoute>()
55+
.ToArray();
56+
}
57+
}
58+
}
59+
}
60+
}

0 commit comments

Comments
 (0)