ASP.NET Core 5.0 RouteDataRequestCultureProvider 删除 url 中的默认区域性

Ere*_*sen 5 c# .net-core asp.net-core asp.net-core-localization asp.net-core-5.0

我尝试向我的 asp.net-core 项目添加多语言功能,但 RequestLocalization 中的 .net 3.1 和 5.0 之间存在一些变化,我无法得到我想要的。我为每种语言添加了资源文件,并在我的剃刀页面中使用了资源,它可以工作,但有一个不需要的默认路由错误,我希望我的路由能够对默认文化友好地工作。

这就是我要的,

对于默认文化(土耳其语):

site.com/foo
site.com/foo/bar
site.com/foo/bar/5
Run Code Online (Sandbox Code Playgroud)

对于非默认区域性(英语):

site.com/en/foo
site.com/en/foo/bar
site.com/en/foo/bar/5
Run Code Online (Sandbox Code Playgroud)

我的另一个问题是;我的项目呈现 site.com/foo/foo/bar 这个网址就像 site.com/tr/foo/bar 一样,这是不行的,我想它应该重定向到 404 页面。

我的启动示例代码如下:

public void ConfigureServices(IServiceCollection services)
{
    services.AddResponseCompression();
    services.AddLocalization(opts => opts.ResourcesPath = "Resources");
    services.Configure<RequestLocalizationOptions>(options =>
    {
        var supportedCultures = new[]
        {
            new CultureInfo("tr-TR"),
            new CultureInfo("en")
        };

        options.DefaultRequestCulture = new RequestCulture("tr");
        options.SupportedCultures = supportedCultures;
        options.SupportedUICultures = supportedCultures;
        options.RequestCultureProviders.Insert(0, new RouteDataRequestCultureProvider());
    });

    services.AddControllersWithViews();
    services.AddRazorPages();
    services.AddRouting(options => options.LowercaseUrls = true);
}

public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
    app.UseResponseCompression();

    if (env.IsDevelopment())
        app.UseDeveloperExceptionPage();
    else
    {
        app.UseExceptionHandler("/Home/Error");
        // The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
        app.UseHsts();
    }

    app.UseHttpsRedirection();
    app.UseStaticFiles();
    app.UseRouting();
    var supportedCultures = new string[] { "tr-TR", "en" };
    app.UseRequestLocalization(options =>
                options
                .AddSupportedCultures(supportedCultures)
                .AddSupportedUICultures(supportedCultures)
                .SetDefaultCulture("tr-TR")
                .RequestCultureProviders.Insert(0, new CustomRequestCultureProvider(context => Task.FromResult(new ProviderCultureResult("tr-TR"))))
    );

    app.UseAuthorization();
    app.UseEndpoints(endpoints =>
    {
        endpoints.MapControllerRoute(name: "culture-route", pattern: "{culture}/{controller=Home}/{action=Index}/{id?}");
        endpoints.MapControllerRoute(name: "default", "{culture=tr}/{controller=Home}/{action=Index}/{id?}");
    });
}
Run Code Online (Sandbox Code Playgroud)

Razor 资源使用和文化变革导航

资源文件

我该如何解决这个问题或者我做错了什么?

编辑

我发现了这个方法。它使用 CookieRequestCultureProvider 并且 url 中没有文化信息,但至少没有损坏的 url。我不知道这是否适合 SEO。

Dar*_*oon 2

为此,您需要在 ASP.Net Core 中配置稍微不同的本地化。

我创建了新ASP.Net Core MVC项目并执行以下步骤:

  1. 首先,您需要创建自定义UrlRequestCultureProvider
    public class UrlRequestCultureProvider : RequestCultureProvider
    {
        private static readonly Regex PartLocalePattern = new Regex(@"^[a-z]{2}(-[a-z]{2,4})?$", RegexOptions.IgnoreCase);
        private static readonly Regex FullLocalePattern = new Regex(@"^[a-z]{2}-[A-Z]{2}$", RegexOptions.IgnoreCase);

        private static readonly Dictionary<string, string> LanguageMap = new Dictionary<string, string>
        {
            { "en", "en-US" },
            { "fr", "fr-FR" }
        };

        public override Task<ProviderCultureResult> DetermineProviderCultureResult(HttpContext httpContext)
        {
            if (httpContext == null)
            {
                throw new ArgumentNullException(nameof(httpContext));
            }

            var parts = httpContext.Request.Path.Value.Split('/');
            // Get culture from path
            var culture = parts[1];

            if (parts.Length < 3)
            {
                return Task.FromResult<ProviderCultureResult>(null);
            }

            // For full languages fr-FR or en-US pattern
            if (FullLocalePattern.IsMatch(culture))
            {
                return Task.FromResult(new ProviderCultureResult(culture));
            }

            // For part languages fr or en pattern
            if (PartLocalePattern.IsMatch(culture))
            {
                var fullCulture = LanguageMap[culture];
                return Task.FromResult(new ProviderCultureResult(fullCulture));
            }

            return Task.FromResult<ProviderCultureResult>(null);
        }
    }
Run Code Online (Sandbox Code Playgroud)
  1. 添加ConfigureServices()这段代码:
            services.AddControllersWithViews().AddViewLocalization();
            services.AddLocalization(options => options.ResourcesPath = "Resources");

            services.Configure<RequestLocalizationOptions>(options =>
            {
                var supportedCulters = new List<CultureInfo>()
                {
                    new CultureInfo("en-US"),
                    new CultureInfo("fr-FR")
                };

                options.DefaultRequestCulture = new RequestCulture(supportedCulters.FirstOrDefault());
                options.SupportedCultures = supportedCulters;
                options.SupportedUICultures = supportedCulters;

                options.RequestCultureProviders.Insert(0, new UrlRequestCultureProvider() 
                { 
                    Options = options 
                });
            });
Run Code Online (Sandbox Code Playgroud)
  1. 添加Configure()这段代码:
            var requestLocalizationOptions = app.ApplicationServices.GetRequiredService<IOptions<RequestLocalizationOptions>>();
            app.UseRequestLocalization(requestLocalizationOptions.Value);

            app.UseRouting();

            app.UseAuthorization();

            app.UseEndpoints(endpoints =>
            {
                endpoints.MapControllerRoute(
                    name: "default",
                    pattern: "{controller=Home}/{action=Index}/{id?}");

                endpoints.MapControllerRoute(
                    name: "culture",
                    pattern: "{culture}/{controller=Home}/{action=Index}/{id?}");
            });
Run Code Online (Sandbox Code Playgroud)
  1. 另外,我还添加Resources了 en-US 和 fr-FR 本地化。有关资源文件命名的更多信息,请参阅 Microsoft 文档。
Views.Home.Index.en-US.resx
Views.Home.Index.fr-FR.resx
Run Code Online (Sandbox Code Playgroud)
  1. 最后,这是我的主页视图
@using Microsoft.AspNetCore.Mvc.Localization
@inject IViewLocalizer Localizer

@{
    ViewData["Title"] = "Home Page";
}

<div class="text-center">
    <h1 class="display-4">@Localizer["Welcome"]</h1>
</div>
Run Code Online (Sandbox Code Playgroud)

您可以在屏幕截图中看到结果。

默认-> 默认

英语-> 英语

法语-> 法语

您可以向我提问并享受本地化的乐趣:)

  • 我理解你。我找到了与您的问题类似的答案,但使用的是旧版本的网络核心。[这个](/sf/answers/2298785751/)和[这个](/sf/answers/2517947351/)。我将调查这个答案并尝试创建类似的解决方案。 (2认同)