Search code examples
c#blazor-webassembly

Blazor WASM displaying resource key instead of localized value


I'm trying to implement localization in my Blazor WebAssembly app, by following one of tutorials found on internet, such as: Localization in Blazor

I have set up everything described in tutorials, but I cannot get a localized value for a specific key, I get a KEY displayed as text I want to localize.

Here is my code: Program.cs - hardcoded culture, to make sure i choose the right one:

builder.Services.AddLocalization(opts => { opts.ResourcesPath = "Localization"; });
var culture = new CultureInfo("sr");
CultureInfo.DefaultThreadCurrentCulture = culture;
CultureInfo.DefaultThreadCurrentUICulture = culture;

In my .razor file I injected a IStringLocalizer:

@inject IStringLocalizer<General> localizer

And I use a localizer like this: <MudTooltip Text="@localizer["Open"]">

My Class generated from .resx is called General. Here is my resources setup: Added a resx as Embedded resource and code gen tool PublicResXFileCodeGenerator Main resources file for 'en'

My localized resx for Serbian language is set as EmbeddedResource and with no code generation tool.


Solution

  • The IStringLocalizer<T> doesn't rely on a generated class from the .resx file. During the build process, the ResourceManagerembeds the resource in the main dll and creates satellite dlls. The default implementation of IStringLocalizer<T> rely on the ResourceManager to read the files inside the assembly or satellite assembly. So turn off the code generation should solve your problem.

    Properties of a .resx files

    Update:

    The <T> is referring to any possible class. There is no constraint enforce. However, there should be a link between the namespace of the class and the file location.

    Assume you have the file Pages/Users/AddUserPage.razor

    @inject IStringLocalizer<AddUser> Localizer
    

    If you don't specify a namespace manually, AddUserPage class will end up in the namespace <ProjectRootNamespace>.Pages.Users.

    So, you need to create a .resx file reflecting the folder structure. Your root is specified as Localization so you need to create the file Localization/Pages/Users/AddUserPage.resx or and their locazied counterparts like Localization/Pages/Users/AddUserPage.sr.resx

    In some cases, it makes sense to group certain localization, like the caption of buttons (Ok, Close, Yes, No, etc.). To avoid having these keys in each .resx file, you can create an empty class. I like to name it SharedRessources. However, the name is not important as long as you name your .resx file accordingly.

    
    namespace <ProjectRootNamespace>
    {
        public class SharedRessources
        {
        }
    }
    
    

    Because the class is in the root namespace of your project, the .resx file should be placed inside the root folder of your .resx file. In your case, Localization. So, the name should be Localization/SharedRessources.resx and Localization/SharedRessources.sr.resx

    Now, you can this can be injected too.

    @inject IStringLocalizer<AddUser> Localizer
    @inject IStringLocalizer<SharedRessources> SharedLocalizer
    
    <p> Hi from @Localizer["KeyLocalToAddUser"] </p>
    <p> Do you want to delete the user? <span> @SharedLocalizer["No"] or SharedLocalizer["Yes"]