Deferred translation is an approach where Blazor Server forces the user to refresh the website to see the translated content. Simple and effective, but it does not provide much customization. In this tutorial, we are going to learn more about deferred translation with the following topics:
You can download the example code used in this topic on GitHub.
There are 2 approaches when making a multilingual website, deferred translation is one of the approaches. When a user selects a language, the translation process will be deferred until the next load of the web page, which means the user need to refresh the web page to see the new language. This downside is easily workaround by forcing Blazor Server to refresh the website.
Deferred Translation | Instant Translation | |
User experience | Bad | Good |
Language selection strategy | Not customizable: only supports cookies, browser settings, and URL. Cannot change the priority of the strategies. | Customizable: support cookies, browser settings, URL, and custom strategies. Can change the priority of the strategies. |
Resource type | .resx files only. |
Support any file extensions and database. |
Implement effort | Low | High |
For deferred translation, there are 3 language selection strategies available: cookies, browser settings, and URL with the following priority:
The URL strategy takes the highest priority, then cookies, then browser settings.
Let's assume your website are using all those 3 strategies, and the user has the following environment:
Blazor Server will display the Taiwanese language (zh-TW) despite the cookies and the browser settings differences.
The user preferred language is stored in cookies, as the following image illustrates:
This is a continuation of the previous tutorial, begins at step 7.
Program.cs
.builder.Services.AddControllers(); builder.Services.AddLocalization(...); builder.Services.Configure<RequestLocalizationOptions>(options => { // You can set the default language using the following method: // options.SetDefaultCulture("fr"); options.AddSupportedCultures(new[] { "en", "fr" }); options.AddSupportedUICultures(new[] { "en", "fr" }); options.RequestCultureProviders = new List<IRequestCultureProvider>() { new CookieRequestCultureProvider() }; });
Blazor is an SPA framework, and there will be only 1 request, the cookies are attached to the request. When changing the cookies, it requires a new request. Introducing controllers allows you to interpret the request, allows the Blazor Server able to access the cookies.
[Route("[controller]/[action]")] public class CultureController : Controller { public IActionResult Set(string culture, string redirectUri) { if (culture is not null) { HttpContext.Response.Cookies.Append(CookieRequestCultureProvider.DefaultCookieName, CookieRequestCultureProvider.MakeCookieValue(new(culture, culture))); } return LocalRedirect(redirectUri); } }
@inject NavigationManager NavigationManager <select @onchange="OnChangeLanguage"> <option value="">Select</option> <option value="en">English</option> <option value="fr">France</option> </select> @code { private void OnChangeLanguage(ChangeEventArgs e) { var uri = new Uri(NavigationManager.Uri).GetComponents(UriComponents.PathAndQuery, UriFormat.Unescaped); var culture = CultureInfo.GetCultureInfo(e.Value as string); var cultureEscaped = Uri.EscapeDataString(culture.Name); var uriEscaped = Uri.EscapeDataString(uri); NavigationManager.NavigateTo($"Culture/Set?culture={cultureEscaped}&redirectUri={uriEscaped}", forceLoad: true); } }
When changing the language, you need to navigate to the controller created at step 8, pass the parameters and force refresh the website.
The user preferred language is embedded in the URL, as the following image illustrates:
This is a continuation of the previous tutorial, begins at step 7.
Program.cs
.builder.Services.Configure<RequestLocalizationOptions>(options => { // You can set the default language using the following method: // options.SetDefaultCulture("fr"); options.AddSupportedCultures(new[] { "fr", "en" }); options.AddSupportedUICultures(new[] { "fr", "en" }); options.RequestCultureProviders = new List<IRequestCultureProvider>() { new QueryStringRequestCultureProvider() }; });;
App.razor
and set the respective language. For example:@inject NavigationManager NavigationManager @inject IOptions<RequestLocalizationOptions> RequestLocalizationOptions ... @code { protected override void OnInitialized() { var uri = new Uri(NavigationManager.Uri); var urlParameters = HttpUtility.ParseQueryString(uri.Query); var defaultCulture = RequestLocalizationOptions.Value.DefaultRequestCulture.Culture; var cultureProvider = RequestLocalizationOptions.Value.RequestCultureProviders.First(p => p is QueryStringRequestCultureProvider) as QueryStringRequestCultureProvider; CultureInfo.CurrentCulture = CultureInfo.GetCultureInfo(urlParameters[cultureProvider.QueryStringKey] ?? defaultCulture.Name); CultureInfo.CurrentUICulture = CultureInfo.GetCultureInfo(urlParameters[cultureProvider.UIQueryStringKey] ?? CultureInfo.CurrentCulture.Name); } }
@inject NavigationManager NavigationManager <select @onchange="OnChangeLanguage"> <option value="">Select</option> <option value="en">English</option> <option value="fr">France</option> </select> @code { private void OnChangeLanguage(ChangeEventArgs e) { var uri = new Uri(NavigationManager.Uri); var culture = CultureInfo.GetCultureInfo(e.Value as string); var cultureEscaped = Uri.EscapeDataString(culture.Name); var urlParameters = HttpUtility.ParseQueryString(uri.Query); urlParameters["culture"] = cultureEscaped; string urlWithoutQuery = uri.GetComponents(UriComponents.Path, UriFormat.Unescaped); NavigationManager.NavigateTo($"{urlWithoutQuery}?{urlParameters.ToString()}", forceLoad: true); } }
When changing the language, you need to add or replace the culture
parameter in the URL and force refresh the website.
The user preferred language is embedded in the request, as the following image illustrates:
This is a continuation of the previous tutorial, begins at step 7.
Program.cs
.builder.Services.Configure<RequestLocalizationOptions>(options => { options.AddSupportedCultures(new[] { "en", "fr" }); options.AddSupportedUICultures(new[] { "en", "fr" }); options.RequestCultureProviders = new List<IRequestCultureProvider>() { new AcceptLanguageHeaderRequestCultureProvider() }; });