Localization works when culture is set via QuerySt

2020-07-22 18:37发布

This is my route:

        app.UseMvc(routes =>
        {
            routes.MapRoute(
     name: "defaultWithCulture",
     template: "{culture=fa-IR}/{controller}/{action=Index}/{id?}");
        });

but localization works when I use the link:

http://localhost:1776/fa-IR/Home/About?culture=fa-ir

but not when

http://localhost:1776/fa-IR/Home/About

why doesn't the culture in the route apply?

2条回答
萌系小妹纸
2楼-- · 2020-07-22 19:12

As far as I know, asp.net core has following RequestCultureProviders, in order. First non-null will be used.

QueryStringRequestCultureProvider
CookieRequestCultureProvider
AcceptLanguageHeaderRequestCultureProvider

and you need to add RouteDataRequestCultureProvider to support culture from route data.

taking an example from here:

public void ConfigureServices(IServiceCollection services)  
{
    // Add framework services.
    services.AddMvc();

    var supportedCultures = new[]
    {
        new CultureInfo("en-US"),
        new CultureInfo("en-GB"),
        new CultureInfo("de"),
        new CultureInfo("fr-FR"),
    };

    var options = new RequestLocalizationOptions()
    {
        DefaultRequestCulture = new RequestCulture(culture: "en-GB", uiCulture: "en-GB"),
        SupportedCultures = supportedCultures,
        SupportedUICultures = supportedCultures
    };
    options.RequestCultureProviders = new[] 
    { 
         new RouteDataRequestCultureProvider() { Options = options } 
    };

    services.AddSingleton(options);
}
查看更多
够拽才男人
3楼-- · 2020-07-22 19:26

SSA's answer didn't solve my problem but gave me a big clue, and finally I got it to work.

The thing to do is:

  1. As SSA said asp.net core has following RequestCultureProviders, in order. First non-null will be used.
QueryStringRequestCultureProvider
CookieRequestCultureProvider
AcceptLanguageHeaderRequestCultureProvider

So we must change the order of them and add the Routing to be the first:

services.Configure<RequestLocalizationOptions>(
    options =>
    {
        var supportedCultures = new List<CultureInfo>
        {
           new CultureInfo("en-US"),
           new CultureInfo("fa-IR"),
        };
        options.DefaultRequestCulture = new RequestCulture(culture: "fa-IR", uiCulture: "fa-IR");
        options.SupportedCultures = supportedCultures;
        options.SupportedUICultures = supportedCultures;
        options.RequestCultureProviders.Clear();
        options.RequestCultureProviders.Insert(0, new RouteDataRequestCultureProvider();
        options.RequestCultureProviders.Insert(1, new QueryStringRequestCultureProvider());
        options.RequestCultureProviders.Insert(2, new CookieRequestCultureProvider());
        options.RequestCultureProviders.Insert(3, new AcceptLanguageHeaderRequestCultureProvider());                    
        services.AddSingleton(options);
    });

2- When RouteDataRequestCultureProvider Task executed, still the RoutingData is null and is not given a value yet, so it will always return null, so I changed it like Below to use the Url.Path instead of RoutingData:

public class RouteDataRequestCultureProvider : RequestCultureProvider
{

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

        string culture = null;
        string uiCulture = null;
         uiCulture =  culture = httpContext.Request.Path.Value.Split('/')[1]?.ToString();
        if (culture == null)
        {
            return TaskCache<ProviderCultureResult>.DefaultCompletedTask;
        }
        var providerResultCulture = new ProviderCultureResult(culture, uiCulture);

        return Task.FromResult(providerResultCulture);
    }
} 
查看更多
登录 后发表回答