Quando dobbiamo realizzare un'applicazione multilingua, è importante sfruttare al meglio i servizi offerti da ASP.NET Core così che il nostro codice applicativo non si complichi inutilmente a causa di questo requisito.
Per prima cosa, vediamo come consentire all'utente di selezionare una lingua o, per meglio dire, una Culture, cioè l'insieme delle convezioni (date, numeri, idioma) che differenziano ogni regione del mondo dall'altra.
A questo scopo, ASP.NET Core mette a disposizione il RequestLocalizationMiddleware che si occupa di selezionare una Culture in maniera coerente con le informazioni incluse nella richiesta HTTP. Per usarlo, aggiungiamo quanto segue nel metodo Configure della classe Startup.
//L'ordine dei middleware è importante //Mettiamo questo PRIMA di app.UseMvc o app.UseEndpoints app.UseRequestLocalization(options => { //Impostiamo l'italiano come Culture predefinita options.DefaultRequestCulture = new RequestCulture("it"); //Indichiamo quali altre Culture sono supportate dalla nostra applicazione //Qui l'elenco delle Culture con Regione: https://github.com/dotnet/corefx/blob/33e31f98b69bc34e3022f2f4c886251c685b3289/src/Common/src/CoreLib/System/Globalization/CultureData.cs#L171 options.SupportedCultures = options.SupportedUICultures = new [] { new CultureInfo("en-US"), //inglese americano new CultureInfo("fr"), //francese (senza indicare la Regione) new CultureInfo("it") //italiano (senza indicare la Regione) }; });
In queste opzioni è importante impostare sia la proprietà SupportedCultures che la proprietà SupportedUICultures: la prima è responsabile delle convenzioni usate per la formattazione e il parsing di date e numeri, mentre la seconda determina quali file di risorse saranno selezionati per la localizzazione dei testi dell'applicazione.
Il RequestLocalizationMiddleware fa affidamento su 3 provider predefiniti che sono in grado di selezionare una Culture in base a 3 differenti tipi di informazione presenti nella richiesta HTTP:
- La query string, dalle chiavi culture e ui-culture. Fornendo solo una di esse, anche l'altra verrà impostata con lo stesso valore;
- Un cookie chiamato .AspNetCore.Culture il cui valore va impostato ad esempio su c=it|uic=it;
- L'intestazione Accept-Language inviata dal browser, che ci aiuta a preselezionare una Culture quando non è stata espressa alcuna preferenza con le altre due fonti.
Ad esempio, se volessimo consentire all'utente di selezionare una delle lingue supportate dalla nostra applicazione, potremmo preparare dei link come i seguenti, che sfruttano la query string per passare l'informazione sulla Culture desiderata.
<a href="?culture=en-US">English (US)</a> <a href="?culture=it">Italiano</a> <a href="?culture=fr">Français</a>
Data la natura estendibile di ASP.NET Core, il middleware può comunque avvalersi di provider personalizzati, che determineranno la Culture in base ad altre fonti. Nella documentazione ufficiale si trova un esempio: https://docs.microsoft.com/it-it/aspnet/core/fundamentals/localization?view=aspnetcore-2.2#use-a-custom-provider.
A questo punto, per conoscere qual è la Culture selezionata da un'action di ASP.NET Core MVC, possiamo usare il codice del seguente esempio.
public IActionResult Index() { string culture = CultureInfo.CurrentCulture.Name; //Qui uso il valore di culture, che sarà en-US oppure it oppure fr, //cioè il nome di una delle Culture che stiamo supportando return View(); }
Possiamo recuperare il valore della Culture selezionata anche da una view Razor. L'informazione ci potrebbe essere utile per aggiungere una classe CSS al link attivo, così da evidenziarlo.
@using Microsoft.AspNetCore.Localization @{ string culture = CultureInfo.CurrentCulture.Name; } @* TODO: potremmo generare questi link con un tag helper personalizzato, per migliorare la leggibilità *@ <a href="?culture=en-US" class="@(culture == "en-US" ? "active" : "")">English (US)</a> <a href="?culture=it" class="@(culture == "it" ? "active" : "")">Italiano</a> <a href="?culture=fr" class="@(culture == "fr" ? "active" : "")">Français</a>
Il nome della Culture selezionata lo possiamo ottenere anche dagli altri componenti della nostra applicazione, come per esempio da un servizio applicativo o da un tag helper personalizzato, che ci permetta di generare i link per la selezione della Culture in maniera più leggibile.
[HtmlTargetElement("culture-link", TagStructure = TagStructure.NormalOrSelfClosing)] public class CultureLinkTagHelper : TagHelper { [HtmlAttributeName("for")] public string For { get; set; } public override void Process(TagHelperContext context, TagHelperOutput output) { //Leggo la Culture attualmente selezionata string culture = CultureInfo.CurrentCulture.Name; //Genero il link output.TagName = "a"; output.TagMode = TagMode.StartTagAndEndTag; output.Attributes.Add("href", $"?culture={For}"); //Il link avrà la classe "active" solo il suo attributo For corrisponde alla Culture selezionata if (culture == For) { output.Attributes.Add("class", "active"); } } }
Infine, ecco un esempio di come usare il tag helper che abbiamo appena realizzato all'interno di una view Razor.
@addTagHelper *, NomeDellAssemblyDelNostroProgetto <culture-link for="en-US">English (US)</culture-link> <culture-link for="it">Italiano</culture-link> <culture-link for="fr">Français</culture-link>
In un prossimo script vedremo come localizzare i testi, ovvero come presentare all'utente i contenuti nella sua lingua, in base alla Culture selezionata.
Commenti
Per inserire un commento, devi avere un account.
Fai il login e torna a questa pagina, oppure registrati alla nostra community.
Approfondimenti
Gestione degli stili CSS con le regole @layer
Aprire una finestra di dialogo per selezionare una directory in WPF e .NET 8
Creazione di componenti personalizzati in React.js con Tailwind CSS
Registrare servizi multipli tramite chiavi in ASP.NET Core 8
Referenziare un @layer più alto in CSS
Utilizzare QuickGrid di Blazor con Entity Framework
Inference di dati strutturati da testo con Semantic Kernel e ASP.NET Core Web API
Eseguire query verso tipi non mappati in Entity Framework Core
Configurare il nome della run di un workflow di GitHub in base al contesto di esecuzione
Migliorare i tempi di risposta di GPT tramite lo streaming endpoint in ASP.NET Core
Routing statico e PreRendering in una Blazor Web App