This article is currently in the process of being translated into Italian (~99% done).
The CultureInfo class
Negli ultimi due articoli abbiamo parlato dell'utilità della classe CultureInfo quando si ha bisogno di un controllo completo sulla visualizzazione di numeri e date nell'applicazione. Abbiamo anche parlato di come sia possibile verificare e modificare la cultura che l'applicazione deve utilizzare come fallback. Dopo aver messo a punto tutto questo, è il momento di scavare più a fondo nella classe CultureInfo vera e propria, per vedere come sfruttarla appieno.
Un breve promemoria prima di iniziare: La classe CultureInfo fa parte dello spazio dei nomi System.Globalization, quindi assicuratevi di importarla ogni volta che provate gli esempi:
using System.Globalization;
Culture neutre e specifiche
Negli esempi precedenti di questo capitolo, abbiamo utilizzato solo culture specifiche, ovvero culture che specificano sia una lingua che un Paese/regione. Un esempio è la cultura en-US, che indica chiaramente che la lingua desiderata deve essere l'inglese e la regione gli Stati Uniti. Un'alternativa è la cultura en-GB, che prevede la stessa lingua (inglese) ma con la Gran Bretagna come regione invece degli Stati Uniti.
In alcuni casi, queste differenze sono importanti per l'utente, nel qual caso si dovrebbero usare le versioni specifiche per regione della classe CultureInfo. D'altra parte, ci saranno anche situazioni in cui l'inglese è solo una lingua e non si vuole legare questa lingua a un paese o a una regione specifici. Per questo, il framework .NET definisce le cosiddette culture neutrali, che specificano solo una lingua. In effetti, sia en-US che en-GB ereditano da questa cultura neutrale (il che ha perfettamente senso, dato che condividono la stessa lingua!) e vi si può accedere dalla proprietà Parent. Lasciami illustrare con un esempio:
CultureInfo enGb = new CultureInfo("en-GB");
CultureInfo enUs = new CultureInfo("en-US");
Console.WriteLine(enGb.DisplayName);
Console.WriteLine(enUs.DisplayName);
Console.WriteLine(enGb.Parent.DisplayName);
Console.WriteLine(enUs.Parent.DisplayName);
Non è un esempio molto utile, ma dovrebbe dare un'idea della struttura interna della classe CultureInfo. L'output dovrebbe essere simile a questo:
English (United Kingdom)
English (United States)
English
English
Ottenere il giusto CultureInfo
Dagli esempi precedenti, si è visto che si può ottenere la classe CultureInfo desiderata passando l'identificatore della lingua/paese/regione al costruttore della classe. Ma poiché si potrebbe cercare una cultura neutrale, come descritto sopra, si potrebbe anche passare solo l'identificatore della lingua:
CultureInfo en = new CultureInfo("en");
Il framework .NET restituirà quindi un'istanza CultureInfo inglese, neutrale rispetto alla regione. Per un elenco completo dei possibili identificatori di lingua e/o paese/regione, si consiglia di consultare la documentazione MSDN.
Un altro modo per identificare una cultura specifica è il cosiddetto LCID (LoCale ID). Lo si trova come proprietà nelle istanze CultureInfo esistenti, ma se si conosce l'ID, lo si può usare anche per istanziare un oggetto CultureInfo. Ad esempio, l'LCID per en-US è 1033:
CultureInfo enUs = new CultureInfo(1033);
Comunque, nella maggior parte delle situazioni, è molto più semplice usare lo specificatore di lingua/paese/regione, come dimostrato in precedenza.
Ottenere un elenco delle Culture disponibili
Ora possiamo ottenere una cultura specifica e utilizzarla per vari scopi, ma forse avete bisogno di un elenco delle culture disponibili, ad esempio per consentire all'utente di selezionare una lingua e/o un paese/regione. Fortunatamente, il framework .NET ci facilita anche questo compito: ecco un esempio:
CultureInfo[] specificCultures = CultureInfo.GetCultures(CultureTypes.SpecificCultures);
foreach (CultureInfo ci in specificCultures)
Console.WriteLine(ci.DisplayName);
Console.WriteLine("Total: " + specificCultures.Length);
Come si può intuire dalla prima riga di codice, uso il metodo statico GetCultures della classe CultureInfo per ottenere un elenco di culture. Il metodo richiede il parametro CultureTypes, che specifica quale tipo di cultura si sta cercando. In questo caso, ho chiesto le culture specifiche che, come abbiamo detto in precedenza, sono quelle legate a una lingua e a un paese/regione. Si tratta di un elenco piuttosto lungo: su questo computer, ho un totale di 563 culture disponibili!
Ma forse siete più interessati alle culture neutrali? Questo avrebbe perfettamente senso, ad esempio, se si stesse costruendo un elenco di lingue disponibili, senza preoccuparsi di quale paese o regione siano collegati. Per farlo è sufficiente modificare il parametro CultureTypes:
CultureInfo[] neutralCultures = CultureInfo.GetCultures(CultureTypes.NeutralCultures);
foreach (CultureInfo ci in neutralCultures)
Console.WriteLine(ci.DisplayName);
Console.WriteLine("Total: " + neutralCultures.Length);
Così facendo, si noterà che non ci sono tante culture neutre quante culture specifiche: sul mio computer/versione del framework .NET, il risultato è un totale di 280 culture neutre.
Proprietà e metodi importanti di CultureInfo
Una volta creata un'istanza della classe CultureInfo, si ha immediatamente accesso a una vasta gamma di proprietà e metodi utilizzabili. Questi membri possono aiutare a realizzare molte cose utili per quanto riguarda la cultura: vediamone alcuni!
DateTimeFormat
Con la proprietà DateTimeFormat si ha accesso alle informazioni su come devono essere formattate la data e l'ora, oltre a molte informazioni utili sul calendario per la cultura data. Un buon esempio sono le proprietà FirstDayOfWeek e CalendarWeekRule, che permettono di sapere in quale giorno inizia la settimana (di solito domenica o lunedì) e come viene decisa la prima settimana di calendario dell'anno (ad esempio, solo il primo giorno o la prima settimana intera):
CultureInfo enUs = new CultureInfo("en-US");
Console.WriteLine("First day of the: " + enUs.DateTimeFormat.FirstDayOfWeek.ToString());
Console.WriteLine("First calendar week starts with: " + enUs.DateTimeFormat.CalendarWeekRule.ToString());
Provate a cambiare l'istanza di CultureInfo con la vostra cultura o con un'altra cultura che conoscete, per vedere come variano queste proprietà!
Un'altra cosa interessante è che si possono ottenere informazioni sui nomi dei mesi e dei giorni per la cultura specifica, utilizzando proprietà come MonthNames e metodi come GetMonthName(). Ecco un rapido esempio:
CultureInfo enUs = new CultureInfo("en-US");
foreach (string monthName in enUs.DateTimeFormat.MonthNames)
Console.WriteLine(monthName);
Console.WriteLine("Current month: " + enUs.DateTimeFormat.GetMonthName(DateTime.Now.Month));
La stessa cosa si può fare per i giorni, utilizzando la proprietà DayNamese il metodo GetDayName():
CultureInfo enUs = new CultureInfo("en-US");
foreach (string dayName in enUs.DateTimeFormat.DayNames)
Console.WriteLine(dayName);
Console.WriteLine("Today is: " + enUs.DateTimeFormat.GetDayName(DateTime.Now.DayOfWeek));
Ci sono molte altre proprietà e metodi utili sulla proprietà DateTimeFormat, ad esempio DateSeparator, YearMonthPatterne così via. Date un'occhiata: potrebbe esserci una soluzione al vostro problema di data/ora nascosta lì dentro: Documentazione di DateTimeFormatInfo.
NumberFormat
Proprio come DateTimeFormat contiene informazioni sulle date, è possibile accedere alle informazioni su come la cultura specifica tratta i numeri dalla proprietà NumberFormat. Queste informazioni vengono utilizzate ogni volta che si richiede una rappresentazione visiva di un numero, ad esempio quando lo si converte in una stringa e lo si scrive nella console, ma è anche possibile accedere alle informazioni da soli, utilizzando le proprietà e i metodi della proprietà NumberFormat (ecco un esempio):
CultureInfo enUs = new CultureInfo("en-US");
Console.WriteLine(enUs.DisplayName + ":");
Console.WriteLine("NumberGroupSeparator: " + enUs.NumberFormat.NumberGroupSeparator);
Console.WriteLine("NumberDecimalSeparator: " + enUs.NumberFormat.NumberDecimalSeparator);
CultureInfo deDe = new CultureInfo("de-DE");
Console.WriteLine(deDe.DisplayName + ":");
Console.WriteLine("NumberGroupSeparator: " + deDe.NumberFormat.NumberGroupSeparator);
Console.WriteLine("NumberDecimalSeparator: " + deDe.NumberFormat.NumberDecimalSeparator);
Utilizziamo le proprietà NumberGroupSeparator e NumberDecimalSeparator per ottenere informazioni su come viene visualizzato un numero (ad esempio 1.000,00 o 1.000,00) per le culture inglese e tedesca. Se si dà un'occhiata, si troveranno proprietà corrispondenti per le valute (CurrencyGroupSeparator e CurrencyDecimalSeparator) e per le percentuali (PercentGroupSeparator e PercentDecimalSeparator).
A proposito di valuta, la proprietà NumberFormat può anche indicare il simbolo utilizzato da una determinata cultura per visualizzare un importo monetario: basta utilizzare la proprietà CurrencySymbol:
CultureInfo enUs = new CultureInfo("en-US");
Console.WriteLine(enUs.DisplayName + " - currency symbol: " + enUs.NumberFormat.CurrencySymbol);
CultureInfo deDe = new CultureInfo("de-DE");
Console.WriteLine(deDe.DisplayName + " - currency symbol: " + deDe.NumberFormat.CurrencySymbol);
CultureInfo ruRu = new CultureInfo("ru-RU");
Console.WriteLine(ruRu.DisplayName + " - currency symbol: " + ruRu.NumberFormat.CurrencySymbol);
Tutte queste proprietà sono utili da conoscere, ma nella maggior parte dei casi non è necessario utilizzarle, poiché C# utilizzerà silenziosamente le informazioni per formattare numeri, percentuali e valute, a condizione che si specifichi la stringa di formato corretta quando si trasforma il numero in stringa.
Nomi e identificatori
Infine, diamo un'occhiata alle proprietà che rappresentano l'istanza di CultureInfo. Alcune di esse sono già state utilizzate, come Name e DisplayName, ma come funzionano effettivamente? Innanzitutto, ecco un elenco delle proprietà disponibili utilizzate per identificare un CultureInfo:
- Name identificherà un CultureInfo nel formato languagecode-country/region-code, ad esempio "en-US" per l'inglese negli Stati Uniti, en-GB per l'inglese in Gran Bretagna e così via. Se non viene specificata alcuna nazione/regione, verrà restituita solo la prima parte, ad esempio "en" per l'inglese.
- TwoLetterISOLanguageName ha più o meno la stessa funzione di Name, ma restituisce solo il codice della lingua, indipendentemente dal fatto che sia stato specificato o meno un paese o una regione. Ad esempio, "en" verrà restituito sia per "en-US" che per "en-GB". Le lettere restituite sono specificate nello standard ISO 639-1.
- ThreeLetterISOLanguageName funziona in modo simile a TwoLetterISOLanguageName, ma restituisce tre lettere invece di due, come specificato dallo standard ISO 639-2.
- EnglishName restituirà il nome della lingua (in inglese). Se è stato specificato un paese/regione, questo verrà aggiunto al risultato, all'interno di una serie di parentesi.
- NativeName restituirà il nome della lingua (nella lingua specificata dall'istanza CultureInfo). Se è stato specificato un paese/regione, questo verrà aggiunto al risultato, all'interno di una serie di parentesi.
Riepilogo
Come si può intuire dalla lunghezza di questo articolo, trattare la cultura in generale non è un compito semplice. Fortunatamente, il framework .NET rende tutto molto più semplice con la classe CultureInfo. Viene utilizzata silenziosamente in tutte le applicazioni quando si formattano numeri e date, ma è bene sapere come funziona, in modo da poterne modificare il comportamento se necessario. Speriamo che questo articolo vi abbia insegnato la maggior parte delle cose da sapere sulla classe CultureInfo.