🌐 Building Multilingual Blazor Apps Made Easy!
Ever struggled with dynamically translating resources in your Blazor Web Applications? You're not alone! At Clean Code Factory, we've successfully implemented seamless language switching in Blazor using built-in .NET localization and cookies and MudBlazor.
In this practical guide, we walk through a step-by-step approach to setting up dynamic resource translation in Blazor—from configuring localization services and managing culture settings, to building a user-friendly language switcher component.
Ready to get started? Let's dive deeper into the technical details. In this comprehensive step-by-step guide, we'll show you exactly how we implemented dynamic resource translation in our Blazor applications, complete with code snippets and clear explanations:
1. Server-Side Localization Setup (Program.cs)
In the server project, you need to register localization services and configure the supported cultures. This code snippet shows how to set up localization middleware, register controllers, and configure the default culture.
#region Localization
builder.Services.AddControllers();
// Define the supported cultures.
var supportedCultures = new[]
{
new CultureInfo("en"),
new CultureInfo("bg")
};
// Configure RequestLocalizationOptions
builder.Services.Configure<RequestLocalizationOptions>(options =>
{
options.DefaultRequestCulture = new RequestCulture("en");
options.SupportedCultures = supportedCultures;
options.SupportedUICultures = supportedCultures;
// Optionally, use cookies as one of the providers
options.RequestCultureProviders.Insert(0, new CookieRequestCultureProvider());
});
#endregion Localization
#region Localization
app.MapControllers();
// Enable localization middleware (this must be called before routing or endpoints)
var localizationOptions = app.Services.GetRequiredService<IOptions<RequestLocalizationOptions>>().Value;
app.UseRequestLocalization(localizationOptions);
#endregion Localization
Explanation:
2. Creating the Culture Controller (CultureController.cs)
This controller provides an API endpoint to change the current culture dynamically. It creates a cookie with the selected culture and sets an expiration.
using Microsoft.AspNetCore.Localization;
using Microsoft.AspNetCore.Mvc;
namespace WineCabinet7.Server.Controllers
{
[ApiController]
[Route("api/[controller]")]
public class CultureController : ControllerBase
{
[HttpPost("SetCulture")]
public IActionResult SetCulture([FromBody] string culture)
{
// Create a cookie value based on the provided culture.
var cookieValue = CookieRequestCultureProvider.MakeCookieValue(new RequestCulture(culture));
Response.Cookies.Append(
CookieRequestCultureProvider.DefaultCookieName,
cookieValue,
new CookieOptions { Expires = DateTimeOffset.UtcNow.AddYears(1) }
);
return Ok();
}
}
}
Explanation:
3. Client-Side Culture Detection via JavaScript (App.razor)
Include a JavaScript file that reads the current culture from the cookie:
<script src="js/culture.js"></script>
wwwroot/js/culture.js
This script retrieves the culture from the browser cookies. It scans the document cookies for the specific cookie name and extracts the culture code.
window.blazorCulture = {
get: function () {
const cookieName = ".AspNetCore.Culture=";
const decodedCookie = decodeURIComponent(document.cookie);
const cookies = decodedCookie.split(';');
for (let i = 0; i < cookies.length; i++) {
let cookie = cookies[i].trim();
if (cookie.indexOf(cookieName) === 0) {
// Get the cookie value
const value = cookie.substring(cookieName.length);
// Value format is "c=bg|uic=bg". Split by '|' to get parts.
const parts = value.split("|");
for (let j = 0; j < parts.length; j++) {
let part = parts[j].split("=");
if (part[0] === "c" && part[1]) {
return part[1];
}
}
}
}
return null;
}
};
window.getBrowserLocale = function () {
return navigator.language || navigator.userLanguage;
};
Explanation:
-Retrieve Locale: The code calls your JavaScript function to get the browser’s locale.
4. Client Project Configuration (Client.csproj)
Ensure that Blazor WebAssembly loads all globalization data by adding the following property:
<PropertyGroup>
<BlazorWebAssemblyLoadAllGlobalizationData>true</BlazorWebAssemblyLoadAllGlobalizationData>
</PropertyGroup>
Explanation:
5. Client-Side Localization Setup (Program.cs)
Register localization services in the Client project and read the current culture from JavaScript:
Recommended by LinkedIn
// Read the culture from JavaScript
var host = builder.Build();
var jsInterop = host.Services.GetRequiredService<IJSRuntime>();
var cultureName = await jsInterop.InvokeAsync<string>("blazorCulture.get");
if (!string.IsNullOrEmpty(cultureName))
{
var culture = new CultureInfo(cultureName);
CultureInfo.DefaultThreadCurrentCulture = culture;
CultureInfo.DefaultThreadCurrentUICulture = culture;
}
else
{
var browserLocale = await jsInterop.InvokeAsync<string>("getBrowserLocale");
CultureInfo culture;
try
{
// Create a CultureInfo from the browser locale
var browserCulture = new CultureInfo(browserLocale);
// Extract the two-letter ISO language name
var twoLetterCode = browserCulture.TwoLetterISOLanguageName.ToLower();
// Check if it is one of our allowed cultures ("en" or "bg")
if (twoLetterCode != "en" && twoLetterCode != "bg")
{
twoLetterCode = "en"; // Default to English if not supported
}
culture = new CultureInfo(twoLetterCode);
}
catch (Exception)
{
// If any error occurs, fallback to default "en"
culture = new CultureInfo("en");
}
// Apply the selected culture to the application
CultureInfo.DefaultThreadCurrentCulture = culture;
CultureInfo.DefaultThreadCurrentUICulture = culture;
}
#endregion Localization
Explanation:
6. Building the Language Switcher Component (LanguageSwitcher.razor)
This component uses MudBlazor to provide a UI menu for switching languages. When a language is selected, it posts the new culture to the server and reloads the page to apply the changes.
@using System.Globalization
@inject HttpClient Http
@inject NavigationManager Navigation
<MudMenu Class="IconDia">
<ActivatorContent>
<MudImage Src="@_SelectedFlag" Style="width: 32px" />
</ActivatorContent>
<ChildContent>
<MudMenuItem OnClick="@(async () => await SelectLanguage("en", "/en-us-circle.svg"))">
<MudImage Src="/en-us-circle.svg" Style="width: 24px" Class="me-2" /> English
</MudMenuItem>
<MudMenuItem OnClick="@(async () => await SelectLanguage("bg", "/bg-circle.svg"))">
<MudImage Src="/bg-circle.svg" Style="width: 24px" Class="me-2" /> Bulgarian
</MudMenuItem>
</ChildContent>
</MudMenu>
@code {
private string _SelectedLanguage = "en";
private string _SelectedFlag = "/en-us-circle.svg";
protected override void OnInitialized()
{
base.OnInitialized();
switch (CultureInfo.CurrentCulture.TwoLetterISOLanguageName)
{
case "en":
_SelectedFlag = "/en-us-circle.svg";
break;
default:
_SelectedFlag = "/bg-circle.svg";
break;
}
}
private async Task SelectLanguage(string lang, string flag)
{
if (!string.IsNullOrWhiteSpace(lang))
{
_SelectedFlag = flag;
// Post the new culture to the server.
await Http.PostAsJsonAsync("api/Culture/SetCulture", lang);
// Reload the page to apply the new culture.
Navigation.NavigateTo(Navigation.Uri, forceLoad: true);
}
}
}
Explanation:
7. Using Localized Resource Files (Resources and PublicResXFileCodeGenerator)
Place your resource file (e.g., UiTranslation.resx) in the Client project's Resources folder. To ensure that the auto-generated class for the resource file is public, use a custom tool like PublicResXFileCodeGenerator. This allows you to inject and use the resource file in your components.
Injecting and Using Localized Strings
In a component, inject the localizer and use it to retrieve localized strings. For example:
@inject IStringLocalizer<UiTranslation> _Localizer
<!-- Usage in a component -->
<p>@_Localizer[UiTranslation.Citation]</p>
Explanation:
Summary
This example demonstrates a complete solution for dynamic resource translation in a Blazor Web Application:
Server-Side Setup:
Client-Side Setup:
Localized Resources:
By following this structured approach, you can provide dynamic language switching and localized content in your Blazor application.
🎯 Did this guide help you simplify localization in Blazor? We’d love your feedback! Share your thoughts or questions below.
For more insights and tips, make sure to follow Clean Code Factory. Happy coding! 🚀
#Blazor #Localization #DotNet #MudBlazor #CleanCodeFactory #DeveloperCommunity