Search code examples
c#asp.net-corelocalizationasp.net-core-mvcasp.net-core-mvc-2.0

Localization in Asp.Net Core


I have been following the instructions on this page to setup Localization:

https://learn.microsoft.com/en-us/aspnet/core/fundamentals/localization

However, for me it just doesn't seem to work. Here is what I have done:

Startup.cs:

public class Startup
{
    public IConfigurationRoot Configuration { get; }

    public Startup(IHostingEnvironment env)
    {
        var builder = new ConfigurationBuilder()
            .SetBasePath(env.ContentRootPath)
            .AddJsonFile("appsettings.json", true, true);

        builder.AddEnvironmentVariables();
        Configuration = builder.Build();
    }

    public void ConfigureServices(IServiceCollection services)
    {
        services.AddLocalization(o => o.ResourcesPath = "Resources");
        services.AddMvc(o =>
        {
            o.Filters.Add(typeof(GlobalExceptionFilter));
        }
        ).AddViewLocalization(LanguageViewLocationExpanderFormat.Suffix).AddDataAnnotationsLocalization();
    }

    public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
    {
        var supportedCultures = new[]
        {
            new CultureInfo("es-MX"),
            new CultureInfo("en-US")
        };

        app.UseRequestLocalization(new RequestLocalizationOptions
        {
            DefaultRequestCulture = new RequestCulture("es-MX"),
            SupportedCultures = supportedCultures,
            SupportedUICultures = supportedCultures
        });

        if (env.IsDevelopment())
        {
            app.UseDeveloperExceptionPage();
        }
        else
        {
            app.UseExceptionHandler("/Error");
        }

        app.UseStaticFiles();
        app.UseAuthentication();

        app.UseMvcWithDefaultRoute();
        //app.UseMvc(routes =>
        //{
        //    routes.MapRoute(
        //        "default", "{controller=Home}/{action=Index}/{id?}");
        //});

        app.UseRewriter(new RewriteOptions().AddRedirectToHttps());
    }
}

My Layout.cshtml contains the following:

@await Html.PartialAsync("_SelectLanguagePartial")

and my _SelectLanguagePartial.cshtml contains:

@using Microsoft.AspNetCore.Builder
@using Microsoft.AspNetCore.Localization
@using Microsoft.AspNetCore.Mvc.Localization
@using Microsoft.Extensions.Options

@inject IViewLocalizer Localizer
@inject IOptions<RequestLocalizationOptions> LocOptions

@{
    var requestCulture = Context.Features.Get<IRequestCultureFeature>();
    var cultureItems = LocOptions.Value.SupportedUICultures
        .Select(c => new SelectListItem { Value = c.Name, Text = c.DisplayName })
        .ToList();
    var returnUrl = string.IsNullOrEmpty(Context.Request.Path) ? "~/" : $"~{Context.Request.Path.Value}";
}

<div title="@Localizer["Request culture provider:"] @requestCulture?.Provider?.GetType().Name">
    <form id="selectLanguage" asp-controller="Home" asp-action="SetLanguage" asp-route-returnUrl="@returnUrl" 
          method="post" role="form">
        <label asp-for="@requestCulture.RequestCulture.UICulture.Name">@Localizer["Language:"]</label> <select name="culture"
            onchange="this.form.submit();"
            asp-for="@requestCulture.RequestCulture.UICulture.Name" asp-items="cultureItems">
        </select>
    </form>
</div>

In addition to this, I have created 2 resource files, ErrorMessages.ex-MX.resx and ErrorMessages.resx.

In my HomeController I have added this line ViewBag.Test = ErrorMessages.Test; and in the Index view I added <p>@ViewBag.Test</p>

When I look at the page I see the drop down with languages and it only has English listed there. The text that I displayed on the page is the one coming from ErrorMessages.resx.

Am I missing a step? How come Spanish is not getting picked up anywhere? As you will see below, I even tried setting spanish as the main culture, yet no difference.

EDIT:

I tried removing eglish from the list and the result that I got the dropdown was still there and this time it had Spanish listed. However, the text was still in English.

Then I tried adding English back as a second list in the item and setting english as the main language and the dropdown only displayed 1 language and spanish was now gone.


Solution

  • I had this same problem around a week ago. I solved it with this:

    public void ConfigureServices(IServiceCollection services)
    {
        services.AddLocalization(options => options.ResourcesPath = "Resources");
    
        services.AddMvc()
            .AddViewLocalization(LanguageViewLocationExpanderFormat.Suffix)
            .AddDataAnnotationsLocalization();
    
        services.Configure<RequestLocalizationOptions>(options =>
        {
            var supportedCultures = new[] { new CultureInfo("en"), new CultureInfo("es") };
    
            options.DefaultRequestCulture = new RequestCulture(culture: "en", uiCulture: "en");
            options.SupportedCultures = supportedCultures;
            options.SupportedUICultures = supportedCultures;
        });
    }
    
    public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
    {
        var locOptions = app.ApplicationServices.GetService<IOptions<RequestLocalizationOptions>>();
        app.UseRequestLocalization(locOptions.Value);
    
        if (env.IsDevelopment())
        {
            app.UseDeveloperExceptionPage();
            app.UseBrowserLink();
        }
        else
        {
            app.UseExceptionHandler("/Home/Error");
        }
    
        app.UseStaticFiles();
        app.UseMvcWithDefaultRoute();
    }
    

    One more comment, though. In ASP.NET Core, the default culture resource should not be created, only specific ones:

    So, given

    Views/Shared/Layout.cshtml
    

    Only create

    Resources/Views/Shared/Layout.es-MX.resx
    

    Do notice, also, that you are limiting Spanish to Mexican by this, so you should either have a es fallback, or add both es and es-MX.