在 Razor + Blazor 组件中使用 URL 路径进行本地化
Using URL path for localization in Razor + Blazor components
我想用 Razor 页面和一些 Blazor 组件构建一个 ASP.NET Razor 应用程序,网站内容根据 URL 中的语言进行本地化。
例如,/en/home
和 /fr/home
将有一个根据语言呈现内容的后备页面。
有什么方法可以做到这一点?
AspNetCore.Mvc.Localization
has what we need.
在_ViewImports.cshtml
中,我们可以注入一个IViewLocalizer
,它会抓取相应页面的.resx
个文件。
@using Microsoft.AspNetCore.Mvc.Localization
@inject IViewLocalizer Localizer
现在 Localizer
在我们的所有页面中都可用。
例如,Index.cshtml
@page
@model IndexModel
@{
ViewData["Title"] = @Localizer["Title"];
}
<h1>@Localizer["Header"]</h1>
<section>
<p>@Localizer["Welcome", User.Identity.Name]</p>
@Localizer["Learn"]
<a asp-page="Page1">@Localizer["SomePage"]</a>
<a asp-page="Dogs/Index">@Localizer["LinkDogs"]</a>
</section>
现在页面标题 header 和内容在创建 resx 文件后本地化。
Resources/Pages/Index.resx
和 Resources/Pages/Index.fr.resx
需要创建。有一个 VSCode 扩展名可用于此,因为这些文件非常丑陋 XML.
字符串可以参数化。在 Index.cshtml
示例中,"Welcome"="Howdy {0}"
被 @Localizer["Welcome", User.Identity.Name]
引用并且用户名将被替换为 {0}
.
在Startup.cs
里面,我们还需要添加一些设置。
services.AddLocalization(options =>
{
options.ResourcesPath = "Resources";
}); // new
services.AddRazorPages()
.AddRazorRuntimeCompilation()
.AddViewLocalization(); // new
services.AddServerSideBlazor();
但这只能访问我们 .cshtml
文件中的 Localizer
。我们的页面看起来仍然像 /home
而不是 /en/home
.
为了解决这个问题,我们将添加一个 IPageRouteModelConvention
来修改我们的页面模板,将 {culture}
添加到我们所有的页面。
在 Startup.cs
中,我们需要在 razor 配置中添加约定。
services.AddRazorPages(options =>
{
options.Conventions.Add(new CultureTemplatePageRouteModelConvention());
})
我在 Middleware/
文件夹下创建了 CultureTemplatePageRouteModelConvention.cs
,但是你可以把它放在任何地方(不确定它是否是“技术上”的中间件?)。
using System;
using Microsoft.AspNetCore.Mvc.ApplicationModels;
using Microsoft.Extensions.Logging;
namespace app.Middleware
{
public class CultureTemplatePageRouteModelConvention : IPageRouteModelConvention
{
public void Apply(PageRouteModel model)
{
// For each page Razor has detected
foreach (var selector in model.Selectors)
{
// Grab the template string
var template = selector.AttributeRouteModel.Template;
// Skip the MicrosoftIdentity pages
if (template.StartsWith("MicrosoftIdentity")) continue;
// Prepend the /{culture?}/ route value to allow for route-based localization
selector.AttributeRouteModel.Template = AttributeRouteModel.CombineTemplates("{culture?}", template);
}
}
}
}
现在去 /en/home
应该解决,而 /home
不应该。
但是,如果您转到 /fr/home
,您会注意到它仍在使用英文 resx 文件。这是因为未根据 URL.
更新区域性
要解决此问题,需要对 Startup.cs
进行更多修改。
在Configure
方法中,我们将添加
app.UseRequestLocalization();
在ConfigureServices
下,我们将配置请求本地化选项。
这将包括添加一个 RequestCultureProvider
,用于确定每个请求的 Culture
。
services.Configure<RequestLocalizationOptions>(options =>
{
options.SetDefaultCulture("en");
options.AddSupportedCultures("en", "fr");
options.AddSupportedUICultures("en", "fr");
options.FallBackToParentCultures = true;
options.RequestCultureProviders.Remove(typeof(AcceptLanguageHeaderRequestCultureProvider));
options.RequestCultureProviders.Insert(0, new Middleware.RouteDataRequestCultureProvider() { Options = options });
});
这使用扩展方法来删除默认的 accept-language header 文化提供者
using System;
using System.Collections.Generic;
using System.Linq;
namespace app.Extensions
{
public static class ListExtensions {
public static void Remove<T>(this IList<T> list, Type type)
{
var items = list.Where(x => x.GetType() == type).ToList();
items.ForEach(x => list.Remove(x));
}
}
}
更重要的是,我们需要创建我们刚刚添加到列表中的RouteDataRequestCultureProvider
。
Middleware/RouteDataRequestCultureProvider.cs
using System;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Localization;
namespace app.Middleware
{
public class RouteDataRequestCultureProvider : RequestCultureProvider
{
public override Task<ProviderCultureResult> DetermineProviderCultureResult(HttpContext httpContext)
{
string routeCulture = (string)httpContext.Request.RouteValues["culture"];
string urlCulture = httpContext.Request.Path.Value.Split('/')[1];
// Culture provided in route values
if (IsSupportedCulture(routeCulture))
{
return Task.FromResult(new ProviderCultureResult(routeCulture));
}
// Culture provided in URL
else if (IsSupportedCulture(urlCulture))
{
return Task.FromResult(new ProviderCultureResult(urlCulture));
}
else
// Use default culture
{
return Task.FromResult(new ProviderCultureResult(DefaultCulture));
}
}
/**
* Culture must be in the list of supported cultures
*/
private bool IsSupportedCulture(string lang) =>
!string.IsNullOrEmpty(lang)
&& Options.SupportedCultures.Any(x =>
x.TwoLetterISOLanguageName.Equals(
lang,
StringComparison.InvariantCultureIgnoreCase
)
);
private string DefaultCulture => Options.DefaultRequestCulture.Culture.TwoLetterISOLanguageName;
}
}
请注意,我们会在该提供程序中检查 RouteValues["culture"]
,但该值实际上尚未存在。这是因为我们需要另一个中间件来让 Blazor 正常工作。但是现在,至少我们的页面将应用来自 URL 的正确区域性,这将允许 /fr/
使用正确的 Index.fr.resx
而不是 Index.resx
.
另一个问题是 asp-page
标签助手不起作用,除非您还指定 asp-route-culture
用户的当前文化。这很糟糕,所以我们将使用每次只复制文化的标签助手来覆盖标签助手。
里面_ViewImports.cshtml
@* Override anchor tag helpers with our own to ensure URL culture is persisted *@
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers
@removeTagHelper Microsoft.AspNetCore.Mvc.TagHelpers.AnchorTagHelper, Microsoft.AspNetCore.Mvc.TagHelpers
@addTagHelper *, app
在 TagHelpders/CultureAnchorTagHelper.cs
下我们将添加
using System;
using app.Extensions;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc.TagHelpers;
using Microsoft.AspNetCore.Mvc.ViewFeatures;
using Microsoft.AspNetCore.Razor.TagHelpers;
// https://whosebug.com/a/59283426/11141271
// https://whosebug.com/questions/60397920/razorpages-anchortaghelper-does-not-remove-index-from-href
// https://talagozis.com/en/asp-net-core/razor-pages-localisation-seo-friendly-urls
namespace app.TagHelpers
{
[HtmlTargetElement("a", Attributes = ActionAttributeName)]
[HtmlTargetElement("a", Attributes = ControllerAttributeName)]
[HtmlTargetElement("a", Attributes = AreaAttributeName)]
[HtmlTargetElement("a", Attributes = PageAttributeName)]
[HtmlTargetElement("a", Attributes = PageHandlerAttributeName)]
[HtmlTargetElement("a", Attributes = FragmentAttributeName)]
[HtmlTargetElement("a", Attributes = HostAttributeName)]
[HtmlTargetElement("a", Attributes = ProtocolAttributeName)]
[HtmlTargetElement("a", Attributes = RouteAttributeName)]
[HtmlTargetElement("a", Attributes = RouteValuesDictionaryName)]
[HtmlTargetElement("a", Attributes = RouteValuesPrefix + "*")]
public class CultureAnchorTagHelper : AnchorTagHelper
{
private const string ActionAttributeName = "asp-action";
private const string ControllerAttributeName = "asp-controller";
private const string AreaAttributeName = "asp-area";
private const string PageAttributeName = "asp-page";
private const string PageHandlerAttributeName = "asp-page-handler";
private const string FragmentAttributeName = "asp-fragment";
private const string HostAttributeName = "asp-host";
private const string ProtocolAttributeName = "asp-protocol";
private const string RouteAttributeName = "asp-route";
private const string RouteValuesDictionaryName = "asp-all-route-data";
private const string RouteValuesPrefix = "asp-route-";
private readonly IHttpContextAccessor _contextAccessor;
public CultureAnchorTagHelper(IHttpContextAccessor contextAccessor, IHtmlGenerator generator) :
base(generator)
{
this._contextAccessor = contextAccessor;
}
public override void Process(TagHelperContext context, TagHelperOutput output)
{
var culture = _contextAccessor.HttpContext.Request.GetCulture();
RouteValues["culture"] = culture;
base.Process(context, output);
}
}
}
这使用扩展方法从 HttpRequest
获取当前文化
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Localization;
namespace app.Extensions
{
public static class HttpRequestExtensions
{
public static string GetCulture(this HttpRequest request)
{
return request.HttpContext.Features.Get<IRequestCultureFeature>()
.RequestCulture.Culture.TwoLetterISOLanguageName;
}
}
}
为了确保当前上下文的依赖注入有效,我们需要修改Startup.cs
// Used by the culture anchor tag helper
services.AddHttpContextAccessor();
现在我们可以正常使用标签助手了。
示例:
<a asp-page="Page1">@Localizer["SomePage"]</a>
在正常页面正常运行的情况下,现在我们可以着手翻译 Blazor 组件。
在_Imports.razor
里面,我们将添加
@using Microsoft.Extensions.Localization
在我们的 myComponent.razor
中,我们将添加
@inject IStringLocalizer<myComponent> Localizer
现在我们可以像在普通页面中一样使用 <h1>@Localizer["Header"]</h1>
。但现在还有另一个问题:我们的 Blazor 组件没有正确设置它们的文化。组件将 /_blazor
视为它们的 URL 而不是页面的 URL。注释掉 _Layout.cshtml
中 <head>
元素中的 <base href="~/">
以使 Blazor 尝试点击 /en/_blazor
而不是 /_blazor
。这将得到 404,但我们会解决这个问题。
在Startup.cs
里面,我们将注册另一个中间件。
app.Use(new BlazorCultureExtractor().Handle);
这个调用应该在 app.UseEndpoints
和 app.UseRequestLocalization()
调用之前。
Middleware/BlazorCultureExtractor.cs
using System;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using app.Extensions;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Localization;
namespace app.Middleware
{
public class BlazorCultureExtractor
{
private readonly Regex BlazorRequestPattern = new Regex("^/(.*?)(/_blazor.*)$");
public async Task Handle(HttpContext context, Func<Task> next)
{
var match = BlazorRequestPattern.Match(context.Request.Path.Value);
// If it's a request for a blazor endpoint
if (match.Success)
{
// Grab the culture from the URL and store it in RouteValues
// This allows IStringLocalizers to use the correct culture in Blazor components
context.Request.RouteValues["culture"] = match.Groups[1].Value;
// Remove the /culture/ from the URL so that Blazor works properly
context.Request.Path = match.Groups[2].Value;
}
await next();
}
}
}
中间件将检查路由是否试图命中 /en/_blazor
,将 RouteValues["culture"]
值设置为 en
,并将之前的路径重写为 /_blazor
进一步处理。这将 lang 放入我们 RequestCultureProvider
使用的路由值中,同时还修复了 blazor 试图访问我们本地化路由的 404。
里面_Layout.cshtml
我也用
<script src="~/_framework/blazor.server.js"></script>"
以确保对 blazor 脚本的请求命中正确的路径而不是 /en/_framework/...
。请注意 src
属性前面的 ~/
。
结束语
如果您想要纯粹的 URL-based 本地化而不是 MS 推广的奇怪的 cookie 东西,那么需要做很多工作。
我没有考虑使用 Blazor pages 来实现这一点,我只是暂时坚持使用 components。
例如,
<component>
@(await Html.RenderComponentAsync<MyCounterComponent>(RenderMode.Server))
</component>
我想用 Razor 页面和一些 Blazor 组件构建一个 ASP.NET Razor 应用程序,网站内容根据 URL 中的语言进行本地化。
例如,/en/home
和 /fr/home
将有一个根据语言呈现内容的后备页面。
有什么方法可以做到这一点?
AspNetCore.Mvc.Localization
has what we need.
在_ViewImports.cshtml
中,我们可以注入一个IViewLocalizer
,它会抓取相应页面的.resx
个文件。
@using Microsoft.AspNetCore.Mvc.Localization
@inject IViewLocalizer Localizer
现在 Localizer
在我们的所有页面中都可用。
例如,Index.cshtml
@page
@model IndexModel
@{
ViewData["Title"] = @Localizer["Title"];
}
<h1>@Localizer["Header"]</h1>
<section>
<p>@Localizer["Welcome", User.Identity.Name]</p>
@Localizer["Learn"]
<a asp-page="Page1">@Localizer["SomePage"]</a>
<a asp-page="Dogs/Index">@Localizer["LinkDogs"]</a>
</section>
现在页面标题 header 和内容在创建 resx 文件后本地化。
Resources/Pages/Index.resx
和 Resources/Pages/Index.fr.resx
需要创建。有一个 VSCode 扩展名可用于此,因为这些文件非常丑陋 XML.
字符串可以参数化。在 Index.cshtml
示例中,"Welcome"="Howdy {0}"
被 @Localizer["Welcome", User.Identity.Name]
引用并且用户名将被替换为 {0}
.
在Startup.cs
里面,我们还需要添加一些设置。
services.AddLocalization(options =>
{
options.ResourcesPath = "Resources";
}); // new
services.AddRazorPages()
.AddRazorRuntimeCompilation()
.AddViewLocalization(); // new
services.AddServerSideBlazor();
但这只能访问我们 .cshtml
文件中的 Localizer
。我们的页面看起来仍然像 /home
而不是 /en/home
.
为了解决这个问题,我们将添加一个 IPageRouteModelConvention
来修改我们的页面模板,将 {culture}
添加到我们所有的页面。
在 Startup.cs
中,我们需要在 razor 配置中添加约定。
services.AddRazorPages(options =>
{
options.Conventions.Add(new CultureTemplatePageRouteModelConvention());
})
我在 Middleware/
文件夹下创建了 CultureTemplatePageRouteModelConvention.cs
,但是你可以把它放在任何地方(不确定它是否是“技术上”的中间件?)。
using System;
using Microsoft.AspNetCore.Mvc.ApplicationModels;
using Microsoft.Extensions.Logging;
namespace app.Middleware
{
public class CultureTemplatePageRouteModelConvention : IPageRouteModelConvention
{
public void Apply(PageRouteModel model)
{
// For each page Razor has detected
foreach (var selector in model.Selectors)
{
// Grab the template string
var template = selector.AttributeRouteModel.Template;
// Skip the MicrosoftIdentity pages
if (template.StartsWith("MicrosoftIdentity")) continue;
// Prepend the /{culture?}/ route value to allow for route-based localization
selector.AttributeRouteModel.Template = AttributeRouteModel.CombineTemplates("{culture?}", template);
}
}
}
}
现在去 /en/home
应该解决,而 /home
不应该。
但是,如果您转到 /fr/home
,您会注意到它仍在使用英文 resx 文件。这是因为未根据 URL.
要解决此问题,需要对 Startup.cs
进行更多修改。
在Configure
方法中,我们将添加
app.UseRequestLocalization();
在ConfigureServices
下,我们将配置请求本地化选项。
这将包括添加一个 RequestCultureProvider
,用于确定每个请求的 Culture
。
services.Configure<RequestLocalizationOptions>(options =>
{
options.SetDefaultCulture("en");
options.AddSupportedCultures("en", "fr");
options.AddSupportedUICultures("en", "fr");
options.FallBackToParentCultures = true;
options.RequestCultureProviders.Remove(typeof(AcceptLanguageHeaderRequestCultureProvider));
options.RequestCultureProviders.Insert(0, new Middleware.RouteDataRequestCultureProvider() { Options = options });
});
这使用扩展方法来删除默认的 accept-language header 文化提供者
using System;
using System.Collections.Generic;
using System.Linq;
namespace app.Extensions
{
public static class ListExtensions {
public static void Remove<T>(this IList<T> list, Type type)
{
var items = list.Where(x => x.GetType() == type).ToList();
items.ForEach(x => list.Remove(x));
}
}
}
更重要的是,我们需要创建我们刚刚添加到列表中的RouteDataRequestCultureProvider
。
Middleware/RouteDataRequestCultureProvider.cs
using System;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Localization;
namespace app.Middleware
{
public class RouteDataRequestCultureProvider : RequestCultureProvider
{
public override Task<ProviderCultureResult> DetermineProviderCultureResult(HttpContext httpContext)
{
string routeCulture = (string)httpContext.Request.RouteValues["culture"];
string urlCulture = httpContext.Request.Path.Value.Split('/')[1];
// Culture provided in route values
if (IsSupportedCulture(routeCulture))
{
return Task.FromResult(new ProviderCultureResult(routeCulture));
}
// Culture provided in URL
else if (IsSupportedCulture(urlCulture))
{
return Task.FromResult(new ProviderCultureResult(urlCulture));
}
else
// Use default culture
{
return Task.FromResult(new ProviderCultureResult(DefaultCulture));
}
}
/**
* Culture must be in the list of supported cultures
*/
private bool IsSupportedCulture(string lang) =>
!string.IsNullOrEmpty(lang)
&& Options.SupportedCultures.Any(x =>
x.TwoLetterISOLanguageName.Equals(
lang,
StringComparison.InvariantCultureIgnoreCase
)
);
private string DefaultCulture => Options.DefaultRequestCulture.Culture.TwoLetterISOLanguageName;
}
}
请注意,我们会在该提供程序中检查 RouteValues["culture"]
,但该值实际上尚未存在。这是因为我们需要另一个中间件来让 Blazor 正常工作。但是现在,至少我们的页面将应用来自 URL 的正确区域性,这将允许 /fr/
使用正确的 Index.fr.resx
而不是 Index.resx
.
另一个问题是 asp-page
标签助手不起作用,除非您还指定 asp-route-culture
用户的当前文化。这很糟糕,所以我们将使用每次只复制文化的标签助手来覆盖标签助手。
里面_ViewImports.cshtml
@* Override anchor tag helpers with our own to ensure URL culture is persisted *@
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers
@removeTagHelper Microsoft.AspNetCore.Mvc.TagHelpers.AnchorTagHelper, Microsoft.AspNetCore.Mvc.TagHelpers
@addTagHelper *, app
在 TagHelpders/CultureAnchorTagHelper.cs
下我们将添加
using System;
using app.Extensions;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc.TagHelpers;
using Microsoft.AspNetCore.Mvc.ViewFeatures;
using Microsoft.AspNetCore.Razor.TagHelpers;
// https://whosebug.com/a/59283426/11141271
// https://whosebug.com/questions/60397920/razorpages-anchortaghelper-does-not-remove-index-from-href
// https://talagozis.com/en/asp-net-core/razor-pages-localisation-seo-friendly-urls
namespace app.TagHelpers
{
[HtmlTargetElement("a", Attributes = ActionAttributeName)]
[HtmlTargetElement("a", Attributes = ControllerAttributeName)]
[HtmlTargetElement("a", Attributes = AreaAttributeName)]
[HtmlTargetElement("a", Attributes = PageAttributeName)]
[HtmlTargetElement("a", Attributes = PageHandlerAttributeName)]
[HtmlTargetElement("a", Attributes = FragmentAttributeName)]
[HtmlTargetElement("a", Attributes = HostAttributeName)]
[HtmlTargetElement("a", Attributes = ProtocolAttributeName)]
[HtmlTargetElement("a", Attributes = RouteAttributeName)]
[HtmlTargetElement("a", Attributes = RouteValuesDictionaryName)]
[HtmlTargetElement("a", Attributes = RouteValuesPrefix + "*")]
public class CultureAnchorTagHelper : AnchorTagHelper
{
private const string ActionAttributeName = "asp-action";
private const string ControllerAttributeName = "asp-controller";
private const string AreaAttributeName = "asp-area";
private const string PageAttributeName = "asp-page";
private const string PageHandlerAttributeName = "asp-page-handler";
private const string FragmentAttributeName = "asp-fragment";
private const string HostAttributeName = "asp-host";
private const string ProtocolAttributeName = "asp-protocol";
private const string RouteAttributeName = "asp-route";
private const string RouteValuesDictionaryName = "asp-all-route-data";
private const string RouteValuesPrefix = "asp-route-";
private readonly IHttpContextAccessor _contextAccessor;
public CultureAnchorTagHelper(IHttpContextAccessor contextAccessor, IHtmlGenerator generator) :
base(generator)
{
this._contextAccessor = contextAccessor;
}
public override void Process(TagHelperContext context, TagHelperOutput output)
{
var culture = _contextAccessor.HttpContext.Request.GetCulture();
RouteValues["culture"] = culture;
base.Process(context, output);
}
}
}
这使用扩展方法从 HttpRequest
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Localization;
namespace app.Extensions
{
public static class HttpRequestExtensions
{
public static string GetCulture(this HttpRequest request)
{
return request.HttpContext.Features.Get<IRequestCultureFeature>()
.RequestCulture.Culture.TwoLetterISOLanguageName;
}
}
}
为了确保当前上下文的依赖注入有效,我们需要修改Startup.cs
// Used by the culture anchor tag helper
services.AddHttpContextAccessor();
现在我们可以正常使用标签助手了。
示例:
<a asp-page="Page1">@Localizer["SomePage"]</a>
在正常页面正常运行的情况下,现在我们可以着手翻译 Blazor 组件。
在_Imports.razor
里面,我们将添加
@using Microsoft.Extensions.Localization
在我们的 myComponent.razor
中,我们将添加
@inject IStringLocalizer<myComponent> Localizer
现在我们可以像在普通页面中一样使用 <h1>@Localizer["Header"]</h1>
。但现在还有另一个问题:我们的 Blazor 组件没有正确设置它们的文化。组件将 /_blazor
视为它们的 URL 而不是页面的 URL。注释掉 _Layout.cshtml
中 <head>
元素中的 <base href="~/">
以使 Blazor 尝试点击 /en/_blazor
而不是 /_blazor
。这将得到 404,但我们会解决这个问题。
在Startup.cs
里面,我们将注册另一个中间件。
app.Use(new BlazorCultureExtractor().Handle);
这个调用应该在 app.UseEndpoints
和 app.UseRequestLocalization()
调用之前。
Middleware/BlazorCultureExtractor.cs
using System;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using app.Extensions;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Localization;
namespace app.Middleware
{
public class BlazorCultureExtractor
{
private readonly Regex BlazorRequestPattern = new Regex("^/(.*?)(/_blazor.*)$");
public async Task Handle(HttpContext context, Func<Task> next)
{
var match = BlazorRequestPattern.Match(context.Request.Path.Value);
// If it's a request for a blazor endpoint
if (match.Success)
{
// Grab the culture from the URL and store it in RouteValues
// This allows IStringLocalizers to use the correct culture in Blazor components
context.Request.RouteValues["culture"] = match.Groups[1].Value;
// Remove the /culture/ from the URL so that Blazor works properly
context.Request.Path = match.Groups[2].Value;
}
await next();
}
}
}
中间件将检查路由是否试图命中 /en/_blazor
,将 RouteValues["culture"]
值设置为 en
,并将之前的路径重写为 /_blazor
进一步处理。这将 lang 放入我们 RequestCultureProvider
使用的路由值中,同时还修复了 blazor 试图访问我们本地化路由的 404。
里面_Layout.cshtml
我也用
<script src="~/_framework/blazor.server.js"></script>"
以确保对 blazor 脚本的请求命中正确的路径而不是 /en/_framework/...
。请注意 src
属性前面的 ~/
。
结束语
如果您想要纯粹的 URL-based 本地化而不是 MS 推广的奇怪的 cookie 东西,那么需要做很多工作。
我没有考虑使用 Blazor pages 来实现这一点,我只是暂时坚持使用 components。
例如,
<component>
@(await Html.RenderComponentAsync<MyCounterComponent>(RenderMode.Server))
</component>