Skip to content

Commit 3119d14

Browse files
committed
Fixes in route localization
1 parent 0e0c11a commit 3119d14

File tree

4 files changed

+94
-4
lines changed

4 files changed

+94
-4
lines changed

src/Framework/Framework/Routing/DotvvmRouteTable.cs

Lines changed: 26 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,8 @@ public void AddGroup(string groupName,
6464
string urlPrefix,
6565
string virtualPathPrefix,
6666
Action<DotvvmRouteTable> content,
67-
Func<IServiceProvider, IDotvvmPresenter>? presenterFactory = null)
67+
Func<IServiceProvider, IDotvvmPresenter>? presenterFactory = null,
68+
LocalizedRouteUrl[]? localizedUrls = null)
6869
{
6970
ThrowIfFrozen();
7071
if (string.IsNullOrEmpty(groupName))
@@ -77,6 +78,7 @@ public void AddGroup(string groupName,
7778
}
7879
urlPrefix = CombinePath(group?.UrlPrefix, urlPrefix);
7980
virtualPathPrefix = CombinePath(group?.VirtualPathPrefix, virtualPathPrefix);
81+
localizedUrls = CombineLocalizedUrls(group, urlPrefix, localizedUrls);
8082

8183
var newGroup = new DotvvmRouteTable(configuration);
8284
newGroup.group = new RouteTableGroup(
@@ -85,7 +87,8 @@ public void AddGroup(string groupName,
8587
urlPrefix,
8688
virtualPathPrefix,
8789
addToParentRouteTable: Add,
88-
presenterFactory);
90+
presenterFactory,
91+
localizedUrls);
8992

9093
content(newGroup);
9194
routeTableGroups.Add(groupName, newGroup);
@@ -142,14 +145,15 @@ public void Add(string routeName, string? url, Func<IServiceProvider, IDotvvmPre
142145

143146
private void AddCore(string routeName, string? url, string virtualPath, object? defaultValues, Func<IServiceProvider, IDotvvmPresenter>? presenterFactory, LocalizedRouteUrl[]? localizedUrls)
144147
{
148+
localizedUrls = CombineLocalizedUrls(group, url ?? string.Empty, localizedUrls);
145149
url = CombinePath(group?.UrlPrefix, url);
146150
presenterFactory ??= GetDefaultPresenter;
147151
routeName = group?.RouteNamePrefix + routeName;
148152

149153
RouteBase route = localizedUrls == null
150154
? new DotvvmRoute(url, virtualPath, defaultValues, presenterFactory, configuration)
151155
: new LocalizedDotvvmRoute(url,
152-
localizedUrls.Select(l => new LocalizedRouteUrl(l.CultureIdentifier, CombinePath(group?.UrlPrefix, l.RouteUrl))).ToArray(),
156+
localizedUrls.Select(l => new LocalizedRouteUrl(l.CultureIdentifier, l.RouteUrl)).ToArray(),
153157
virtualPath, defaultValues, presenterFactory, configuration);
154158
Add(routeName, route);
155159
}
@@ -324,6 +328,25 @@ private string CombinePath(string? prefix, string? appendedPath)
324328
return $"{prefix}/{appendedPath}";
325329
}
326330

331+
private LocalizedRouteUrl[]? CombineLocalizedUrls(RouteTableGroup? group, string routeUrl, LocalizedRouteUrl[]? localizedUrls)
332+
{
333+
if (group == null)
334+
{
335+
return localizedUrls;
336+
}
337+
338+
var groupCultures = group.LocalizedUrls?.ToDictionary(u => u.CultureIdentifier, u => u.RouteUrl) ?? new();
339+
var routeCultures = localizedUrls?.ToDictionary(u => u.CultureIdentifier, u => u.RouteUrl) ?? new();
340+
341+
return groupCultures.Keys.Union(routeCultures.Keys)
342+
.Select(c =>
343+
new LocalizedRouteUrl(c, CombinePath(
344+
groupCultures.TryGetValue(c, out var localizedGroupUrl) ? localizedGroupUrl : group.UrlPrefix,
345+
routeCultures.TryGetValue(c, out var localizedRouteUrl) ? localizedRouteUrl : routeUrl)
346+
))
347+
.ToArray();
348+
}
349+
327350
private bool isFrozen = false;
328351

329352
private void ThrowIfFrozen()

src/Framework/Framework/Routing/LocalizedDotvvmRoute.cs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -119,9 +119,15 @@ public static void ValidateCultureName(string cultureIdentifier)
119119
public override bool IsMatch(string url, [MaybeNullWhen(false)] out IDictionary<string, object?> values) => GetRouteForCulture(CultureInfo.CurrentCulture).IsMatch(url, out values);
120120

121121
public bool IsPartialMatch(string url, [MaybeNullWhen(false)] out RouteBase matchedRoute, [MaybeNullWhen(false)] out IDictionary<string, object?> values)
122+
{
123+
return IsPartialMatch(url, out matchedRoute, out values, out _);
124+
}
125+
126+
public bool IsPartialMatch(string url, [MaybeNullWhen(false)] out RouteBase matchedRoute, [MaybeNullWhen(false)] out IDictionary<string, object?> values, [MaybeNullWhen(false)] out string? matchedCulture)
122127
{
123128
RouteBase? twoLetterCultureMatch = null;
124129
IDictionary<string, object?>? twoLetterCultureMatchValues = null;
130+
matchedCulture = null;
125131

126132
foreach (var route in localizedRoutes)
127133
{
@@ -131,13 +137,15 @@ public bool IsPartialMatch(string url, [MaybeNullWhen(false)] out RouteBase matc
131137
{
132138
// exact culture match - return immediately
133139
matchedRoute = route.Value;
140+
matchedCulture = route.Key;
134141
return true;
135142
}
136143
else if (route.Key.Length > 0 && twoLetterCultureMatch == null)
137144
{
138145
// match for two-letter culture - continue searching if there is a better match
139146
twoLetterCultureMatch = route.Value;
140147
twoLetterCultureMatchValues = values;
148+
matchedCulture = route.Key;
141149
}
142150
else
143151
{

src/Framework/Framework/Routing/RouteTableGroup.cs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
using System;
22
using System.Collections.Generic;
3+
using System.Collections.Immutable;
34
using System.Text;
45
using DotVVM.Framework.Hosting;
56

@@ -15,15 +16,17 @@ public class RouteTableGroup
1516
public string RouteNamePrefix { get; private set; }
1617
public string UrlPrefix { get; private set; }
1718
public string VirtualPathPrefix { get; private set; }
19+
public ImmutableArray<LocalizedRouteUrl>? LocalizedUrls { get; private set; }
1820

19-
public RouteTableGroup(string groupName, string routeNamePrefix, string urlPrefix, string virtualPathPrefix, Action<string, RouteBase> addToParentRouteTable, Func<IServiceProvider, IDotvvmPresenter>? presenterFactory)
21+
public RouteTableGroup(string groupName, string routeNamePrefix, string urlPrefix, string virtualPathPrefix, Action<string, RouteBase> addToParentRouteTable, Func<IServiceProvider, IDotvvmPresenter>? presenterFactory, LocalizedRouteUrl[]? localizedUrls = null)
2022
{
2123
GroupName = groupName;
2224
RouteNamePrefix = routeNamePrefix;
2325
UrlPrefix = urlPrefix;
2426
VirtualPathPrefix = virtualPathPrefix;
2527
AddToParentRouteTable = addToParentRouteTable;
2628
PresenterFactory = presenterFactory;
29+
LocalizedUrls = localizedUrls?.ToImmutableArray();
2730
}
2831
}
2932
}

src/Tests/Routing/RouteTableGroupTests.cs

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -185,5 +185,61 @@ public void RouteTableGroup_DefaultPresenterFactory()
185185
}, p => p.GetRequiredService<TestPresenter>());
186186
Assert.IsInstanceOfType(table.First().GetPresenter(configuration.ServiceProvider), typeof(TestPresenter));
187187
}
188+
189+
[TestMethod]
190+
public void RouteTableGroup_LocalizedUrls_RouteOnly()
191+
{
192+
var table = new DotvvmRouteTable(configuration);
193+
table.AddGroup("Group", "group", null, opt => {
194+
opt.Add("Route", "route", null, null, null, [
195+
new LocalizedRouteUrl("cs-CZ", "cesta")
196+
]);
197+
});
198+
199+
var route = table["Group_Route"];
200+
Assert.IsInstanceOfType(route, typeof(LocalizedDotvvmRoute));
201+
var csCzRoute = ((LocalizedDotvvmRoute)route).GetRouteForCulture("cs-CZ");
202+
203+
Assert.AreEqual("group/route", route.Url);
204+
Assert.AreEqual("group/cesta", csCzRoute.Url);
205+
}
206+
207+
[TestMethod]
208+
public void RouteTableGroup_LocalizedUrls_GroupOnly()
209+
{
210+
var table = new DotvvmRouteTable(configuration);
211+
table.AddGroup("Group", "group", null, opt => {
212+
opt.Add("Route", "route", null, null, null, null);
213+
}, localizedUrls: [
214+
new LocalizedRouteUrl("cs-CZ", "skupina")
215+
]);
216+
217+
var route = table["Group_Route"];
218+
Assert.IsInstanceOfType(route, typeof(LocalizedDotvvmRoute));
219+
var csCzRoute = ((LocalizedDotvvmRoute)route).GetRouteForCulture("cs-CZ");
220+
221+
Assert.AreEqual("group/route", route.Url);
222+
Assert.AreEqual("skupina/route", csCzRoute.Url);
223+
}
224+
225+
[TestMethod]
226+
public void RouteTableGroup_LocalizedUrls()
227+
{
228+
var table = new DotvvmRouteTable(configuration);
229+
table.AddGroup("Group", "group", null, opt => {
230+
opt.Add("Route", "route", null, null, null, [
231+
new LocalizedRouteUrl("cs-CZ", "cesta")
232+
]);
233+
}, localizedUrls: [
234+
new LocalizedRouteUrl("cs-CZ", "skupina")
235+
]);
236+
237+
var route = table["Group_Route"];
238+
Assert.IsInstanceOfType(route, typeof(LocalizedDotvvmRoute));
239+
var csCzRoute = ((LocalizedDotvvmRoute)route).GetRouteForCulture("cs-CZ");
240+
241+
Assert.AreEqual("group/route", route.Url);
242+
Assert.AreEqual("skupina/cesta", csCzRoute.Url);
243+
}
188244
}
189245
}

0 commit comments

Comments
 (0)