【问题标题】:ASP.NET Core 5.0 RouteDataRequestCultureProvider remove default culture in urlASP.NET Core 5.0 RouteDataRequestCultureProvider 删除 url 中的默认区域性
【发布时间】:2021-01-24 17:18:17
【问题描述】:

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

这就是我想要的,

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

site.com/foo
site.com/foo/bar
site.com/foo/bar/5

对于非默认文化(英语):

site.com/en/foo
site.com/en/foo/bar
site.com/en/foo/bar/5

我的另一个问题是;我的项目将 site.com/foo/foo/bar 这个 url 呈现为 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?}");
    });
}

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

资源文件

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

编辑

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

【问题讨论】:

    标签: c# asp.net-core .net-core asp.net-core-localization asp.net-core-5.0


    【解决方案1】:

    为此,您需要在 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);
            }
        }
    
    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 
                    });
                });
    
    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?}");
                });
    
    1. 另外,我添加了 Resources 用于 en-US 和 fr-FR 本地化。 Microsoft 文档中有关Resource file naming 的更多信息。
    Views.Home.Index.en-US.resx
    Views.Home.Index.fr-FR.resx
    
    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>
    

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

    默认 ->

    英语 ->

    法语 ->

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

    【讨论】:

    • 谢谢你的详细回答:),这个方法也有问题,如果你尝试另一个控制器页面,你也会得到“不友好的路由”问题,它与 Home 控制器一起使用导致它的默认值(我认为......)但其他控制器路由已损坏,并且它们不适用于默认区域性。另一个问题是,如果您尝试使用 site.com/Home/Home 它仍然有效,这会导致创建复杂的 url。我不能只为每种语言使用一个资源文件,比如旧的 asp.net,这种新的文件命名使得翻译和可重复使用的单词管理变得困难。
    • 我做了一些研究,我认为 CookieRequestCultureProvider 更适合我的友好路由模式。 url 中不会有文化信息(只有 setter url 会有参数),但它更安全,也没有损坏的 url。如果我遗漏了任何一点,我也想听听您的意见。
    • 好吧,我创建新的查看页面并添加新的Resources。一切对我来说都很好。 不友好的路线对您意味着什么?网址是:http://localhost:56889/en/home/privacyhttp://localhost:56889/fr/home/privacy。我想我有 home 以 url 的名义,不是吗?对你来说,这并不友好,我是对的?
    • site.com/en/home/privacy 对我来说完全没问题,但我希望默认文化作品在 url 上没有定义,如果你在你的项目中调用 site.com/dummyCultureOrAnythingHere/home/privacy 这个 url它会像site.com/en/home/privacy一样呈现,我猜这不友好,它应该重定向到主页或显示404页面。您的新视图是否绑定到另一个控制器?因为如果您尝试打开另一个控制器索引页面会导致上述“虚拟 404”示例,请尝试打开 site.com/newController 但它会呈现 site.com/en/home/index 并且 url 将保留 site.com/newController .
    • 我理解你。我找到了与您的问题类似的答案,但使用的是旧版本的 net core。 Thisthis。我将调查这个答案并尝试创建类似的解决方案。
    猜你喜欢
    • 2021-05-04
    • 1970-01-01
    • 1970-01-01
    • 2020-06-14
    • 2018-06-30
    • 2020-02-14
    • 1970-01-01
    • 2019-06-09
    • 2021-12-29
    相关资源
    最近更新 更多