Nello script precedente (https://www.aspitalia.com/script/1332/Gestire-Localizzazione-ASP.NET-Core.aspx) abbiamo visto come impostare la Culture della richiesta, in maniera coerente con le preferenze dell'utente. In questo modo, l'applicazione è già predisposta a fornire testi localizzati, con il minimo sforzo richiesto da parte nostra.
Creare i file di risorse
ASP.NET Core dispone di un meccanismo di localizzazione basato su file di risorse, ovvero dei file XML con estensione .resx che vengono compilati su propri assembly nel momento in cui si compila l'applicazione. All'interno di ogni file di risorse si trovano i testi e altri contenuti localizzati per una specifica Culture.Iniziamo creando nel progetto una directory /Resources. Per aggiungere un file di risorse al suo interno, rechiamoci nel riquadro Solution Explorer di Visual Studio e clicchiamo la directory col tasto destro. Poi, selezioniamo la voce di menu Add -> Add new item -> Resources File.
Aprendo il file di risorse, verrà mostrata una comoda interfaccia grafica per la gestione dei testi localizzati. Come si vede, il file contiene più coppie chiave-valore, eventualmente accompagnate da un commento che può essere usato per spiegare il loro ambito di utilizzo.
In questo esempio abbiamo creato tre file di risorse: uno per ciascuna Culture (en-US, fr e it) che intendiamo supportare nell'applicazione.
Il nome "Shared" non è obbligatorio perché siamo liberi di chiamare i file di risorse come preferiamo, pur mantenendo il suffisso .lingua-regione.resx.
Ovviamente, ciascuno di questi file conterrà le stesse chiavi ma con valori differenti, tradotti nelle rispettive lingue. Ecco un esempio di contenuto XML di un file di risorse.
https://aspit.co/bwk
Come si vede, il file non offre il massimo della leggibilità. Coloro che usano Visual Studio Code, soprattutto su Linux o su Mac, potrebbero avere più difficoltà nel modificare direttamente questi file rispetto a chi ha Visual Studio installato. Microsoft, infatti, non ha ancora fornito uno strumento di gestione multipiattaforma. Una issue è stata aperta su GitHub (https://github.com/aspnet/AspNetCore.Docs/issues/2501) ma, ad oggi, è disponibile solo uno strumento da riga di comando chiamato LocalizationResourceGenerator (https://github.com/hishamco/LocalizationResourceGenerator) realizzato da un membro della community.
Ottenere i testi localizzati
Per recuperare i testi dai file di risorse che abbiamo creato, useremo un servizio offerto da ASP.NET Core. Come prerequisito, andiamo quindi ad abilitarlo per la dependency injection scrivendo quando segue nel metodo ConfigureServices della classe Startup.services.AddLocalization(options => { //Indichiamo la cartella in cui si trovano i nostri file resx options.ResourcesPath = "Resources"; });
Ora siamo pronti per usare il suddetto servizio, l'IStringLocalizerFactory. Nell'esempio seguente lo riceviamo nell'action di un controller grazie all'attributo [FromServices] ma, in alternativa, potremmo riceverlo come parametro del costruttore di un qualsiasi componente della nostra applicazione.
public IActionResult Index([FromServices] IStringLocalizerFactory localizerFactory) { //Usiamo la factory per ottenere un IStringLocalizer, indicando il nome del file di risorse da cui attingere //Il nome "Shared" è quello che avevamo dato ai file di risorse //Mentre "NomeAssembly" va sostituito con quello del progetto che stiamo sviluppando IStringLocalizer localizer = localizerFactory.Create("Shared", "NomeAssembly"); //A questo punto, usiamo l'IStringLocalizer per ottenere il valore della chiave "Title" string title = localizer["Title"]; //E la usiamo qui, ad esempio per impostare il titolo di pagina ViewData["Title"] = title; return View(); }
Creare un servizio di localizzazione riutilizzabile
Il codice che abbiamo scritto nel controller potrebbe essere incapsulato in un nostro servizio personalizzato, così eviteremo di duplicare lo stesso codice in vari punti della nostra applicazione. Quindi creiamo una nuova classe CustomLocalizer.cs con questo contenuto, in una directory che preferiamo (ad esempio in /Models/Services).public class CustomLocalizer : IStringLocalizer { private readonly IStringLocalizer localizer; public CustomLocalizer(IStringLocalizerFactory localizerFactory) { this.localizer = localizerFactory.Create("Shared", "NomeAssembly"); } //Il nostro CustomLocalizer è di fatto un wrapper attorno all'IStringLocalizer creato dalla factory public LocalizedString this[string name] => localizer[name]; public LocalizedString this[string name, params object[] arguments] => localizer[name, arguments]; public IEnumerable<LocalizedString> GetAllStrings(bool includeParentCultures) => localizer.GetAllStrings(includeParentCultures); public IStringLocalizer WithCulture(CultureInfo culture) => localizer.WithCulture(culture); }
Ora registriamo anche questo nostro servizio per la dependency injection. Quindi torniamo nella classe Startup e nel metodo ConfigureServices aggiungiamo quanto segue.
services.AddTransient<IStringLocalizer, CustomLocalizer>();
Fatto questo, possiamo semplificare così il codice che avevamo scritto nell'action.
public IActionResult Index([FromServices] IStringLocalizer localizer) { string title = localizer["Title"]; ViewData["Title"] = title; return View(); }
Localizzare le data annotation
Le data annotation sono attributi che posizioniamo sulle proprietà dei nostri viewmodel, così che possano verificare la validità dell'input dell'utente e restituirgli dei messaggi di errore in caso di dati non validi. Anche questi messaggi, ovviamente, dovrebbero essere localizzati.Quindi nella classe Startup aggiungiamo quanto segue nel metodo ConfigureServices.
//AddMvc già lo abbiamo //Se stiamo usando ASP.NET Core 3.0 o superiore si chiamerebbe AddEndpoints services.AddMvc() //Di seguito aggiungiamo questo .AddDataAnnotationsLocalization(options => { options.DataAnnotationLocalizerProvider = (type, factory) => { //Qui forniamo il nostro CustomLocalizer per l'ottenimento dei testi localizzati return new CustomLocalizer(factory); }; });
Ora tutte le data annotation che abbiamo usato nei nostri viewmodel potranno sfruttare il servizio di localizzazione. Impostiamo semplicemente la loro proprietà ErrorMessage su una delle chiavi che abbiamo definito nel file di risorse.
public class SubscribeViewModel { [Required(ErrorMessage = "EmailRequired")] //EmailRequired verrà cercato nel file di risorse [EmailAddress(ErrorMessage = "EmailInvalid")] //EmailInvalid verrà cercato nel file di risorse public string Email { get; set; } }
Localizzare una View
Le tecniche che abbiamo visto sono già sufficienti per estrarre testi in lingua da visualizzare all'utente. Tuttavia, se per preferenza personale volessimo ottenere tali testi direttamente da una View Razor, dovremmo anche in questo caso sfruttare la dependency injection per ricevere il servizio IStringLocalizer.@using Microsoft.Extensions.Localization @inject IStringLocalizer localizer <h1>@localizer["Title"]</h1>
Commenti
Per inserire un commento, devi avere un account.
Fai il login e torna a questa pagina, oppure registrati alla nostra community.
Approfondimenti
Aggiungere interattività lato server in Blazor 8
Generare velocemente pagine CRUD in Blazor con QuickGrid
Creare alias per tipi generici e tuple in C#
Miglioramenti nelle performance di Angular 16
Migliorare i tempi di risposta di GPT tramite lo streaming endpoint in ASP.NET Core
Usare i servizi di Azure OpenAI e ChatGPT in ASP.NET Core con Semantic Kernel
Hosting di componenti WebAssembly in un'applicazione Blazor static
Eseguire script pre e post esecuzione di un workflow di GitHub
Creazione di plugin per Tailwind CSS: espandere le funzionalità del framework dinamicamente
Ottimizzazione dei block template in Angular 17
Sfruttare lo stream rendering per le pagine statiche di Blazor 8
Gestione dell'annidamento delle regole dei layer in CSS