ASP.NET Core 5.0 RouteDataRequestCultureProvider удалить культуру по умолчанию в URL-адресе

Я попытался добавить многоязычную функцию в свой проект asp.net-core, но есть некоторые изменения между .net 3.1 и 5.0 в RequestLocalization, и я не смог получить то, что хочу. Я добавил файлы ресурсов для каждого языка и использовал ресурс на своих страницах бритвы, он работает, но есть одна нежелательная ошибка маршрута по умолчанию, и я хочу, чтобы моя маршрутизация работала в соответствии с культурой по умолчанию.

Это то, что я хочу,

Для культуры по умолчанию (турецкий):

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 и изменению культуры

Файлы ресурсов

Как это решить или что я делаю не так?

РЕДАКТИРОВАТЬ

Я нашел этот подход. Он использует CookieRequestCultureProvider, и в URL-адресе нет информации о культуре, но, по крайней мере, нет поврежденных URL-адресов. Я не знаю, подходит ли это для SEO.


person Eren Peksen    schedule 19.01.2021    source источник


Ответы (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.
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>

Результаты вы можете увидеть на скриншотах.

По умолчанию –› По умолчанию

Английский –› English

Французский –› Французский

Вы можете задавать мне вопросы и получать удовольствие от локализации :)

person DarkSideMoon    schedule 19.01.2021
comment
Спасибо за ваш подробный ответ :), есть проблемы и с этим подходом, если вы попробуете другую страницу контроллеров, вы также можете получить проблему «недружественного маршрута», его работа с домашним контроллером вызывает его по умолчанию (я думаю... ), но маршрут других контроллеров поврежден, и они не работают для культуры по умолчанию. Другая проблема заключается в том, что если вы попробуете site.com/Home/Home, он все еще работает, это приводит к созданию сложных URL-адресов. И я не могу просто использовать один файл ресурсов для каждого языка, как старый asp.net, с этим новым именованием файлов, что затрудняет перевод и управление многократно используемыми словами. - person Eren Peksen; 20.01.2021
comment
Я провел некоторое исследование и думаю, что CookieRequestCultureProvider больше подходит для моего дружественного шаблона маршрута. В URL-адресе не будет информации о культуре (только URL-адреса сеттера будут иметь параметр), но это намного безопаснее и не будет поврежденных URL-адресов. Если я что-то упустил, хотелось бы услышать и ваше мнение. - person Eren Peksen; 20.01.2021
comment
Итак, я создаю новую страницу просмотра и добавляю новую Resources. У меня все работает нормально. Что для вас значит не дружественный маршрут? URL-адреса: http://localhost:56889/en/home/privacy и http://localhost:56889/fr/home/privacy. Я думаю, что у меня есть home в имени URL, не так ли? А для вас это не дружественно, я прав? - person DarkSideMoon; 20.01.2021
comment
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. - person Eren Peksen; 21.01.2021
comment
Я понял тебя. Я нашел похожие ответы на ваш вопрос, но с более старой версией сетевого ядра. Это и это. Я рассмотрю эти ответы и попытаюсь создать аналогичное решение. - person DarkSideMoon; 21.01.2021
comment
Привет @Eren Pekşen, я изменил ответ. Я изменил только MapControllerRoute по умолчанию, и он начал работать правильно. endpoints.MapControllerRoute(name: "default", pattern: "{controller=Home}/{action=Index}/{id?}"); язык по умолчанию и другой язык. Я думаю, что это работает так, как ожидалось. - person DarkSideMoon; 24.01.2021
comment
Если мой ответ решит вашу проблему, не могли бы вы принять его. Большое спасибо! - person DarkSideMoon; 25.01.2021
comment
Я создал новый проект и попробовал, но все еще принимаю такие URL-адреса, как this , теперь я использую поставщика файлов cookie в своем проекте и Считаю его более надежным и простым в использовании. - person Eren Peksen; 29.01.2021