Search code examples
c#asp.net-corerazor-pages.net-8.0asp.net-core-localization

ASP.NET Core Razor Pages - How to set default culture other than en-US for request localization


I have a web application named WebApplication2 created using VS2022 template ”ASP.NET Core Web App (Razor Pages)” with the target framework .NET 8.0.

I can make the request localization to work with URL param like ?culture=fr-FR OR to set the app default language to fr-FR but not both. Here is a version where the default culture is en-US even though I try to set it to fr-FR.

Program.cs

var builder = WebApplication.CreateBuilder(args);

// Add services to the container.
builder.Services.AddControllersWithViews();
// Add localization services
builder.Services.AddLocalization(options => options.ResourcesPath = "Resources");


string[] supportedCultures = [ "fr-FR", "en-US", "es-ES" ];
builder.Services.Configure<RequestLocalizationOptions>(options =>
{
    options.DefaultRequestCulture = new RequestCulture("fr-FR");
    options.SetDefaultCulture("fr-FR")
           .AddSupportedCultures(supportedCultures)
           .AddSupportedUICultures(supportedCultures);
});

var app = builder.Build();

// Configure the HTTP request pipeline.
if (!app.Environment.IsDevelopment())
{
    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();
}

var localizationOptions = app.Services.GetService<IOptions<RequestLocalizationOptions>>()?.Value;
if (localizationOptions != null)
{
    localizationOptions.AddSupportedCultures(supportedCultures);
    localizationOptions.DefaultRequestCulture = new RequestCulture("fr-FR");
    app.UseRequestLocalization(localizationOptions);
}

app.UseHttpsRedirection();
app.UseStaticFiles();

app.UseRouting();

app.UseAuthorization();

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

app.Run();

Another option is to fix the culture to fr-FR but then URLs like ?culture=en-US don't work anymore. This can be done by following changes to the code example above:

/* Comment these lines and replace it with single app.UseRequestLocalization call */
var localizationOptions = app.Services.GetService<IOptions<RequestLocalizationOptions>>()?.Value;
if (localizationOptions != null)
{
    localizationOptions.AddSupportedCultures(supportedCultures);
    localizationOptions.DefaultRequestCulture = new RequestCulture("fr-FR");
    app.UseRequestLocalization(localizationOptions);
}
*/
/* This has effect but then URL like `?culture=en-US` doesn't work */
app.UseRequestLocalization("fr-FR");

Note that localization works in both cases. Correct translations are shown on the page. The problem is that I can't have a default language other than en-US if I want URLs with culture to work.

In project root, there's a Resources folder that contains 3 files with each having only 1 string StrLearnAbout:

  • Resources
    • SharedResource.en-US.resx
    • SharedResource.es-ES.resx
    • SharedResource.fr-FR.resx

I also have an empty class SharedResource in the root folder:

namespace WebApplication2
{
    public class SharedResource
    {
    }
}

Index.cshtml

@using Microsoft.Extensions.Localization
@inject IStringLocalizer<SharedResource> Localizer

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

<div class="text-center">
    <h1 class="display-4">Welcome</h1
    <p>@Localizer["StrLearnAbout"]</p>
    <p>Learn about <a href="https://learn.microsoft.com/aspnet/core">building Web apps with ASP.NET Core</a>.</p>
</div>

Solution

  • According to the docs,

    UseRequestLocalization initializes a RequestLocalizationOptions object. On every request the list of RequestCultureProvider in the RequestLocalizationOptions is enumerated and the first provider that can successfully determine the request culture is used. The default providers come from the RequestLocalizationOptions class:

    1. QueryStringRequestCultureProvider
    2. CookieRequestCultureProvider
    3. AcceptLanguageHeaderRequestCultureProvider

    By default, the browser sets the Accept-language:en-US in the request header, which results in the localization not working correctly when you set the default language other than EN.

    I would recommend that you provide the RequestCultureProviders by:

    1. Provide the needed request culture provider.
    2. Specify the order of the provider(s) in the RequestCultureProviders (provider execute by first-to-last sequence)
    3. Build your own Request Provider to handle the localization if the approaches 1 and 2 are not suitable in your scenario.

    For my case, I use approach 1:

    builder.Services.Configure<RequestLocalizationOptions>(options =>
    {
        options.DefaultRequestCulture = new RequestCulture("fr-FR");
        options.SetDefaultCulture("fr-FR")
               .AddSupportedCultures(supportedCultures)
               .AddSupportedUICultures(supportedCultures);
    
        options.RequestCultureProviders = new List<IRequestCultureProvider>
        {
            new QueryStringRequestCultureProvider(),
            new CookieRequestCultureProvider()
        };
    });
    

    Besides,

    For your app.UseRequestLocalization(); code, you can transform it into one line with:

    app.UseRequestLocalization(app.Services.GetService<IOptions<RequestLocalizationOptions>>().Value);
    

    You don't need to specify the default culture again which had been done in adding/registering the RequestLocalizationOptions instance.