Localization of a Blazor component

Xavier Solau
YounitedTech

--

This Blazor article shows how to implement localization in your Blazor component.

You can find the Github source repository this article series is based on here.

The Blazor article series

In the previous articles

We have seen in the previous articles how to write and unit test a component with Blazor. Today, we will continue to enhance our shared component with localization support.

Install dependencies

First of all we need to install the Microsoft.Extensions.Localization dependency in the projects (application and libraries).

Install with the Nuget package manager:

Or with dotnet command line tool:

dotnet add package Microsoft.Extensions.Localization

Create your resources

Our localized string are going to be defined in resource files (*.resx). So the first thing we need to do is to create our resx files.

In this article we are going to base our localization string on resx files but this is actually up to you because we could also use json files. It will be the object of a next article….

First add a “Resources” folder and add the resource file:

In our example we named the resource file with the name of our component. The idea here is to have a set of resource file for each component.

In this article we are using Visual Studio but if you are using Visual Studio Code you can use the ResExpress or ResX Editor extension to edit your resource files.

It gives us two files: Component1.resx and Component1.Designer.cs.

Actually we don’t need the Designer file and it is using a Generator ResXFileCodeGenerator that will work only with Visual Studio.

In addition we won’t get the Designer file if we use Visual Studio Code for example.

We can safely remove the Component1.Designer.cs file and reset the Custom Tool in the properties view:

With ResXFileCodeGenerator custom tool.

In order to get this:

No Custom Tool specified.

As you can see the resx files are automatically detected as “Embedded resource” even if the csproj file doesn’t specify it.

Once everything is clean we can add our translated resource files like Component1.fr.resx for a French translation.

Now we can add our translations:

Base resource values in English.
The French translation.

In order to be able to easily access the resource keys we can also create constant values in our Component1:

public const string Body = nameof(Body);
public const string ClickMe = nameof(ClickMe);
public const string EnterSomeText = nameof(EnterSomeText);

It is also possible to use a code generator to create the constant properties but I will leave that for an other article.

Use localized string values

IStringLocalizer

In order to get the localized resources in our component we need to use a dedicated service: IStringLocalizer<Component>.

 [Inject]
private IStringLocalizer<Component1> L { get; set; }

Note that the localizer is using the name of the given type to find what resources must be loaded.

Once it is injected in the component, we can use it to get localized string values. It provides an indexed access using the resource key:

var localizedText = L["ResourceKey"];

Or the same using string format parameters:

var localizedText = L["ResourceKey", "Arg1", "Arg2"];

In this case, you need to define your resource using the “{n}” with n the index of the argument like this for example: “Here is my first {0} argument followed with my second {1} argument”.

Use in razor component

To use the localizer un the razor component view code, this is prefixed with “@” as usual when you use C# code:

<button>@L[ClickMe]</button>

Handle HTML in the resources

Sometime it may be useful to define your resources as HTML text and the naive approach would be to directly use the result from the localizer in you razor code like this:

<div>
@L[Body, “MySharedComponents”, ElementIds.ParentNameId, ParentName]
</div>

But unfortunately, it won’t give you exactly what we could expect:

Thanks to the MarkupString struct, we can display the HTML as we are expecting:

<div>
@((MarkupString)L[Body, “MySharedComponents”,
ElementIds.ParentNameId, ParentName].ToString())
</div>

Giving us:

As the code is a bit ugly, we can write an helper functions like this:

public static class StringLocalizerHelper
{
public static MarkupString Html<T>(
this IStringLocalizer<T> localizer,
string key,
params object[] arguments)
{
return new MarkupString(localizer[key, arguments]);
}
}

Resulting in something prettier in the razor code:

<div>
@L.Html(Body, “MySharedComponents”, ElementIds.ParentNameId,
ParentName)
</div>

Setting up the application project

Server-side hosting model

Now that our component is localized we can set up our application. Let’s start with the server side hosting model. Once the dependency to Microsoft.Extensions.Localization is added we need to set up the localization services in the Startup.cs file.

In the ConfigureServices method we need to add the localization services with AddLocalization. Optionally you can specify where to get the resources, in our case it is “Resources” (since we put the resx files in the “Resources” folder).

services.AddLocalization(options =>
{
options.ResourcesPath = “Resources”;
});

And we also need to add the RequestLocalizationOptions options:

var supportedCultures = new List<CultureInfo>
{
new CultureInfo(“en”),
new CultureInfo(“fr”)
};
services.Configure<RequestLocalizationOptions>(options =>
{
options.DefaultRequestCulture =
new Microsoft.AspNetCore.Localization.RequestCulture(“en”);
options.SupportedUICultures = supportedCultures;
});

One last step is required in the Configure method:

app.UseRequestLocalization();

And that’s it! The users will see our application localized in the language specified in their browser.

That said, we can also override the browser language by code with the options of the RequestLocalizationMiddleware options:

options.AddInitialRequestCultureProvider(
new CustomRequestCultureProvider(
async ctx => new ProviderCultureResult(“fr”)));

Web Assembly hosting model

For Web Assembly application, we just need to update the Main method in the Program.cs file in order to setup the service.

builder.Services.AddLocalization(options=>
{
options.ResourcesPath = “Resources”;
});

We also can override the browser language settings specifying the : DefaultThreadCurrentCulture and DefaultThreadCurrentUICulture in CultureInfo:

var culture = new CultureInfo(“en”);
CultureInfo.DefaultThreadCurrentCulture = culture;
CultureInfo.DefaultThreadCurrentUICulture = culture;

Check the Microsoft documentation for more information.

Next we are going to talk about a localization based on Json file.

--

--