Bulchsu
Bulchsu

Reputation: 710

How to properly use resource files with string localizer in .NET Core 3.1?

I have a project in which I use resource files to store some text, I am also trying to use StringLocalizer<> to obtain a desired message from resource files. I have already configured localization settings in Startup class as shown below:

internal static class LocalizationConfiguration
{
    private const string ResourcesPath = "Resources";
    private const string DefaultCulture = "en-US";

    internal static IServiceCollection ConfigureLocalizationSettings(this IServiceCollection services) =>
        services
            .AddLocalization(options =>
                options.ResourcesPath = ResourcesPath);

    internal static IApplicationBuilder UseRequestLocalizationMiddleware(this IApplicationBuilder builder) =>
        builder
            .UseRequestLocalization(new RequestLocalizationOptions
            {
                DefaultRequestCulture = new RequestCulture(DefaultCulture),
                SupportedCultures = new List<CultureInfo>
                {
                    new CultureInfo(DefaultCulture)
                }
            });
}

My solution consists of few projects. I need to use StringLocalizer in project which contains my business logic - xxx.Handlers. I have also created a project called xxx.Resources for storing resources which contains two directories: enter image description here

Here's my UserMessages class (it's empty, dummy class, following to https://learn.microsoft.com/pl-pl/aspnet/core/fundamentals/localization?view=aspnetcore-3.1):

public class UserMessages
{
}

I injected StringLocalizer to my command handler and then used it like below (UserConstants.UserNotFoundMessageKey is ok):

var userEntity = await _userRepository.GetUserByIdAsync(command.UserId);

if (userEntity is null)
{
    var message = _stringLocalizer[UserConstants.UserNotFoundMessageKey];
    var statusCode = (int) HttpStatusCode.NotFound;
                
    throw new CommandException(message, statusCode);
}

The problem is, my messages are not being localized in a proper way, and the expression "_stringLocalizer[UserConstants.UserNotFoundMessageKey]" actually returns value of UserNotFoundMessageKey instead of message located in resource file. What am I doing wrong?? How to localize those messages correctly?

Upvotes: 2

Views: 3355

Answers (1)

Rena
Rena

Reputation: 36715

Here is a whole working solution about how to create a shared resource in a separate project:

In ProjectA(It is SharedResource3_1 in my solution):

1.Create Shared folder with UserMessages class and Create Resources folder with Shared.UserMessages.en-US.resx file(Not sure why you create Shared.UserMessages.en-US.Designer.cs,but it seems to be not useful):

enter image description here

UserMessages.cs:

namespace SharedResource3_1.Shared
{
    public class UserMessages
    {
    }
}

Shared.UserMessages.en-US.resx:

enter image description here

In ProjectB(It is MvcCore3_1 in my solution):

1.Add Project Reference to ProjectA:

Right-click the ProjectB Dependencies and choose Add Project Reference then choose the ProjectA:

enter image description here

Then you could get the reference like below:

enter image description here

2.Startup.cs:

public class Startup
{
    public Startup(IConfiguration configuration)
    {
        Configuration = configuration;
    }

    public IConfiguration Configuration { get; }

    public void ConfigureServices(IServiceCollection services)
    {
        services.AddControllersWithViews();

        //add this...
        LocalizationConfiguration.ConfigureLocalizationSettings(services);
    }
   
    public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
    {
        //add this...
        LocalizationConfiguration.UseRequestLocalizationMiddleware(app);
        app.UseHttpsRedirection();
        app.UseStaticFiles();
        app.UseRouting();

        app.UseAuthorization();

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

internal static class LocalizationConfiguration
{
    private const string ResourcesPath = "Resources";
    private const string DefaultCulture = "en-US";

    internal static IServiceCollection ConfigureLocalizationSettings(this IServiceCollection services) =>
        services
            .AddLocalization(options =>
                options.ResourcesPath = ResourcesPath);

    internal static IApplicationBuilder UseRequestLocalizationMiddleware(this IApplicationBuilder builder) =>
        builder
            .UseRequestLocalization(new RequestLocalizationOptions
            {
                DefaultRequestCulture = new RequestCulture(DefaultCulture),
                SupportedCultures = new List<CultureInfo>
                {
                new CultureInfo(DefaultCulture)
                }
            });
}

3.HomeController:

using SharedResource3_1.Shared;  //add the reference for the UserMessages in ProjectA

public class HomeController : Controller
{
    private readonly IStringLocalizer<UserMessages> _stringLocalizer;
    public HomeController(IStringLocalizer<UserMessages> stringLocalizer)
    {
        _stringLocalizer = stringLocalizer;
    }

    public IActionResult Index()
    {
        ViewBag.data = _stringLocalizer["cześć"]; //the key name should be the Name in your resx file...
        return View();
    }
}

Result:

enter image description here

Upvotes: 5

Related Questions