Question

IViewLocalizer only show key instead of value from .resx file

I have a problem with ASP.NET Core localization. I want to use the method with IViewLocalizer. I have this Program.cs:

using xxx.Data;
using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Localization;
using Microsoft.EntityFrameworkCore;
using System.Globalization;
using Microsoft.AspNetCore.Localization;
using static System.Runtime.InteropServices.JavaScript.JSType;
using Microsoft.Extensions.Options;

var builder = WebApplication.CreateBuilder(args);

// Add services to the container.
var connectionString = builder.Configuration.GetConnectionString("DefaultConnection") ?? throw new InvalidOperationException("Connection string 'DefaultConnection' not found.");
builder.Services.AddDbContext<ApplicationDbContext>(options =>
    options.UseSqlServer(connectionString));

builder.Services.AddDatabaseDeveloperPageExceptionFilter();
builder.Services.AddDbContext<XXX>(options =>
{
    options.UseSqlServer(builder.Configuration.GetConnectionString("XXX"));
});

builder.Services.AddIdentity<IdentityUser, IdentityRole>(options => options.SignIn.RequireConfirmedAccount = true)
                .AddEntityFrameworkStores<ApplicationDbContext>()
                .AddDefaultTokenProviders()
                .AddDefaultUI();

builder.Services.AddControllersWithViews();

builder.Services.AddLocalization(options => options.ResourcesPath = "Resources");

// Přidání podpory pro lokalizaci pohledů a datových anotací
builder.Services.AddControllersWithViews()
    .AddViewLocalization()
    .AddDataAnnotationsLocalization();

var app = builder.Build();

var supportedCultures = new[] { "en-US", "cs-CZ" };

app.UseRequestLocalization(new RequestLocalizationOptions
{
    DefaultRequestCulture = new RequestCulture("cs-CZ"),
    SupportedCultures = new[] { new CultureInfo("en-US"), new CultureInfo("cs-CZ") },
    SupportedUICultures = new[] { new CultureInfo("en-US"), new CultureInfo("cs-CZ") }
});

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

using (var scope = app.Services.CreateScope())
{
    var roleManager = scope.ServiceProvider.GetRequiredService<RoleManager<IdentityRole>>();
    var roles = new[] { "Admin", "Redaktor", "Member" };
 
    foreach (var role in roles)
    {
        if (!await roleManager.RoleExistsAsync(role))
        {
            await roleManager.CreateAsync(new IdentityRole(role));
        }
    }
}

// Configure the HTTP request pipeline.
if (app.Environment.IsDevelopment())
{
    app.UseMigrationsEndPoint();
}
else
{
    app.UseExceptionHandler("/Home/Error");
    app.UseHsts();
}

app.Use(async (context, next) =>
{
    await next();

    if (context.Response.StatusCode == 404)
    {
        context.Request.Path = "/NotFound";
        await next();
    }
});

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

app.UseRouting();

app.UseAuthorization();

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

app.Run();

My resources folder structure (at this moment I'm trying only on _Layout.cshtml):

Resources folder

And header of _Layout.cshtml:

@using Microsoft.AspNetCore.Identity
@inject SignInManager<IdentityUser> SignInManager
@inject UserManager<IdentityUser> UserManager
@using Microsoft.AspNetCore.Mvc.Localization
@inject IViewLocalizer Localizer
@using System.Globalization

<!DOCTYPE html>
<html lang="cs">
<head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>@ViewData["Title"] - xxx</title>
    <link rel="stylesheet" href="~/lib/bootstrap/dist/css/bootstrap.css" />
    <link rel="stylesheet" href="~/css/site.css" asp-append-version="true" />
    <link rel="stylesheet" href="~/xxx.styles.css" asp-append-version="true" />
    <link rel="stylesheet" href="/css/bootsrap-custo-var.css" />
    <link href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.15.4/css/all.min.css" rel="stylesheet">
    @RenderSection("Styles", required: false)
</head>`
<body>
   <span>@Localizer["CookieSpanHeader"]</span>
</body>
</html>

The output of this code is, that instead of text from .resx (value), it shows only the key.

I looked for solutions to my problem, but without any better result.

 2  31  2
1 Jan 1970

Solution

 1

Your resource file names for the _Layout.cshtml are incorrect. According to Resource file name, the file name should be:

_Layout.resx
_Layout.cs-CZ.resx

which the extension .cshtml should be excluded.

Also, you are incorrectly configuring for the RequestLocalizationOptions

Add the code below:

builder.Services.Configure<RequestLocalizationOptions>(options =>
{
   options.DefaultRequestCulture = new RequestCulture("cs-CZ");
   options.SupportedCultures = new[] { new CultureInfo("en-US"), new CultureInfo("cs-CZ") };
   options.SupportedUICultures = new[] { new CultureInfo("en-US"), new CultureInfo("cs-CZ") };
   options.RequestCultureProviders = new List<IRequestCultureProvider>
   {
       new UrlRequestCultureProvider()
   };
});

before the line:

builder.Services.AddLocalization(options => options.ResourcesPath = "Resources");

Reference: Use a custom provider

And work with:

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

Your Program.cs should be as below:

var builder = WebApplication.CreateBuilder(args);

// Add services to the container.
var connectionString = builder.Configuration.GetConnectionString("DefaultConnection") ?? throw new InvalidOperationException("Connection string 'DefaultConnection' not found.");
builder.Services.AddDbContext<ApplicationDbContext>(options =>
    options.UseSqlServer(connectionString));

builder.Services.AddDatabaseDeveloperPageExceptionFilter();
builder.Services.AddDbContext<XXX>(options =>
{
    options.UseSqlServer(builder.Configuration.GetConnectionString("XXX"));
});

builder.Services.AddIdentity<IdentityUser, IdentityRole>(options => options.SignIn.RequireConfirmedAccount = true)
                .AddEntityFrameworkStores<ApplicationDbContext>()
                .AddDefaultTokenProviders()
                .AddDefaultUI();

builder.Services.AddControllersWithViews();

builder.Services.Configure<RequestLocalizationOptions>(options =>
{
   options.DefaultRequestCulture = new RequestCulture("cs-CZ");
   options.SupportedCultures = new[] { new CultureInfo("en-US"), new CultureInfo("cs-CZ") };
   options.SupportedUICultures = new[] { new CultureInfo("en-US"), new CultureInfo("cs-CZ") };
   options.RequestCultureProviders = new List<IRequestCultureProvider>
   {
       new UrlRequestCultureProvider()
   };
});

builder.Services.AddLocalization(options => options.ResourcesPath = "Resources");

// Přidání podpory pro lokalizaci pohledů a datových anotací
builder.Services.AddControllersWithViews()
    .AddViewLocalization()
    .AddDataAnnotationsLocalization();

var app = builder.Build();

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

using (var scope = app.Services.CreateScope())
{
    var roleManager = scope.ServiceProvider.GetRequiredService<RoleManager<IdentityRole>>();
    var roles = new[] { "Admin", "Redaktor", "Member" };
 
    foreach (var role in roles)
    {
        if (!await roleManager.RoleExistsAsync(role))
        {
            await roleManager.CreateAsync(new IdentityRole(role));
        }
    }
}
2024-07-20
Yong Shun