Nello sviluppare le nostre app dobbiamo ricordare che grazie al Windows Store possiamo raggiungere un'ampia e variegata audience. Tuttavia, se decidiamo di sviluppare app esclusivamente in italiano, il numero dei potenziali utenti sarà decisamente inferiore.
Ovviamente, se la user interface viene progettata interamente in inglese, il numero di utenti cresce esponenzialmente, ma in ogni caso, nel mondo esistono diverse formattazioni per date e numeri e in molti paesi, Italia compresa, l'inglese non è ancora diffuso nelle masse.
Per fortuna, WinRT espone una serie di funzionalità che semplificano notevolmente la "globalizzazione" della tua applicazione. Il concetto di "globalizzazione" di un'app significa che questa può essere fruita in culture diverse; non deve essere confuso con la "localizzazione", che rappresenta invece il processo di personalizzazione di un'app per una lingua e/o una cultura specifiche.
La globalizzazione di un'app non riguarda unicamente la traduzione degli elementi testuali della tua app in linguaggi differenti. A seconda della cultura, infatti, cambiano anche i modi di rappresentare le date, il calendario, i sistemi di misura, le valute, ecc.
Perché sia possibile globalizzare un'app è necessario che nessuno degli elementi che dipendono dalla cultura e dalla lingua di un paese siano fissati direttamente all'interno del codice HTML o JavaScript: piuttosto che visualizzare una data direttamente a schermo, ad esempio, questa dovrebbe essere formattata in base alle impostazioni correnti dell'utente.
In realtà, la globalizzazione di un'app richiede che venga prestata grande attenzione non solo alla lingua, alla formattazione di una data o alla scelta della giusta valuta, ma investe molti altri elementi dell'app. Per semplificare l'internazionalizzazione delle app, Microsoft ha messo a punto un ricco elenco di linee guida, la cui lettura è caldamente consigliata.
Le Globalization API
In Windows è possibile impostare una o più lingue da usare, specificando anche l'ordine di preferenza. Per accedere alle impostazioni, è sufficiente aprire la Charm Bar, selezionare Change PC Settings e quindi cliccare su Time and Language per aprire il relativo pannello, mostrato nella prossima immagine.
È anche possibile impostare il formato della data e dell'ora, come mostrato nella prossima immagine.
Le preferenze impostate nel pannello Time and Language possono essere recuperate da codice grazie alle Globalization API, esposte dalla classe statica Windows.System.UserProfile.GlobalizationPreferences
. Questa classe espone le seguenti proprietà (in sola lettura):
Proprietà | Descrizione |
---|---|
Calendars | recupera i calendari selezionati dall'utente, nell'ordine di preferenza. |
Clocks | recupera gli orologi definiti dall'utente, nell'ordine di preferenza. |
Currencies | recupera le valute preferite dell'utente. |
HomeGeographicRegion | indica la regione geografica dell'utente. |
Languages | recupera le lingue selezionate dall'utente, nell'ordine di preferenza. |
WeekStartsOn | indica il primo giorno della settimana. |
Attraverso queste proprietà, è decisamente facile accedere alle preferenze dell'utente, come mostrato qui di seguito:
var globalization = Windows.System.UserProfile.GlobalizationPreferences;
var preferredLanguage = globalization.languages[0];
var preferredCalendar = globalization.calendars[0];
var preferredClock = globalization.clocks[0];
var userHomeRegion = globalization.homeGeographicRegion;
var userFirstDayOfWeek = globalization.weekStartsOn;
Queste informazioni potranno essere poi utilizzate per decidere in quale lingua tradurre i testi dell'applicazione, o quale calendario usare, in quale valuta calcolare i prezzi, come formattare le date, ecc. Nelle prossime pagine vedremo come globalizzare gli elementi più comuni della nostra app, in modo da potersi adattare alle impostazioni e alle preferenze dell'utente.
Localizzare i testi della UI
Come si è detto, globalizzare un'app significa innanzitutto non codificare gli elementi testuali della UI direttamente nel codice HTML o JavaScript. Per quanto riguarda in particolare le stringhe di testo, puoi spostarle direttamente in file dedicati di risorse, uno per ciascun linguaggio supportato dall'app. Un file di risorse presenta l'estensione ".resjson" (come il nome suggerisce, si tratta di un file in formato JSON) e deve essere collocato in una speciale cartella all'interno del progetto denominata, per convenzione, "string".
Questa cartella deve contenere una sottodirectory per ciascun linguaggio. Il nome di ciascuna di queste sotto-directory segue il pattern denominato "BCP-47 language tag". La struttura di un tag di questo tipo prevede l'indicazione del linguaggio e, opzionalmente, della regione (ed eventualmente della variante, se presente). Ad esempio, la sottocartella che ospita il file di risorse per i testi in italiano sarà denominata "it-IT
" (o anche solo "it
"), mentre quella per i testi in inglese sarà "en-US
", "en-GB
", "en-AU
", etc., se vogliamo differenziare anche in base alla regione, oppure solo "en" se vogliamo usare la stessa risorsa per le varie regioni.
Ciascuna sotto-directory è destinata a ospitare il file di risorse per la lingua corrispondente. La prossima immagine mostra la struttura di un progetto Windows Store localizzato in italiano e inglese:
Il prossimo snippet mostra la definizione dei due file di risorse che contengono le stringhe localizzate, in inglese...
// For details on localizing a Windows app, see: http://go.microsoft.com/fwlink/?LinkId=212836
{
"greeting" : "Greetings from Html.it",
"_greeting.comment" : "This is a comment",
"sampleText" : "English sample text",
"_sampleText.comment" : "Other comment"
}
...e in italiano:
// For details on localizing a Windows app, see: http://go.microsoft.com/fwlink/?LinkId=212836
{
"greeting" : "Ciao da Html.it",
"_greeting.comment" : "Questo è un commento",
"sampleText" : "Testo d’esempio in italiano",
"_sampleText.comment" : "Altro commento"
}
I file JSON sopra riportati contengono due stringhe localizzate, greeting
e sampleText
, mentre le risorse _greeting
.comment
e _sampleText.comment
rappresentano dei commenti che possono essere utilizzati per fornire informazioni utili per chi è chiamato a operare la traduzione (le risorse precedute dal carattere di underscore vengono infatti ignorate a runtime, avendo uno scopo puramente informativo).
Per accedere via codice JavaScript alle risorse localizzate, un modo è quello di istanziare un nuovo oggetto ResourceLoader
e invocare il metodo GetString
, come illustrato nel seguente snippet:
app.onloaded = function () {
var loader = new Windows.ApplicationModel.Resources.ResourceLoader.getForCurrentView();
WelcomeMessage.innerText = loader.getString("greeting");
SampleText.innerText = loader.getString("sampleText");
}
Il codice HTML da usare in questo caso è assolutamente lineare:
<div id="WelcomeMessage" />
<div id="SampleText" />
Un'alternativa è rappresentata dal metodo WinJS.Resources.getString, il quale restituisce un oggetto con due proprietà, value
e lang
, le quali contengono, rispettivamente, il testo localizzato e il linguaggio a cui la risorsa fa riferimento:
app.onloaded = function () {
WelcomeMessage.innerText = WinJS.Resources.getString("greeting").value;
SampleText.innerText = WinJS.Resources.getString("sampleText").value;
}
Eseguendo l'applicazione, il testo verrà visualizzato nella lingua selezionata dall'utente o, se l'utente ha selezionato una lingua non supportata dall'applicazione, direttamente nel linguaggio di default indicato nell'application manifest. Cambiando l'ordine delle lingue nelle impostazioni di Windows (Control panel Clock, Language and Region Language), il testo cambierà in base alle nuove preferenze dell'utente.
È inoltre possibile accedere alle stringhe localizzate via HTML tramite la proprietà data-win-res
, come mostrato nel prossimo snippet:
<div data-win-res="{textContent: 'greeting'}" />
<div data-win-res="{textContent: 'sampleText'}" />
In questo caso, da codice JavaScript è sufficiente invocare il metodo WinJS.Resources.processAll
non appena la pagina è stata caricata:
app.onloaded = function () {
WinJS.Resources.processAll();
}
È anche possibile localizzare attributi specifici, come ad esempio l'attributo alt
di un elemento img
, utilizzando la sintassi data-win-res="{attributes: {'<attribute>' : '<identifier>'}}"
, come mostrato nel prossimo snippet:
<img data-win-res="{attributes: {'alt': 'imageLabel'}}" />
..dove la risorsa imageLabel
è definita come segue:
en-US:
"imageLabel" : "Image caption"
It-IT:
"imageLabel" : "Didascalia immagine"
Infine, è importante ricordare come in un'applicazione Windows Store, è l'application manifest a indicare il linguaggio di default, ossia il linguaggio da utilizzare nel caso in cui l'utente abbia scelto nelle impostazioni del Control Panel un linguaggio non supportato dall'applicazione. La prossima immagine mostra il file Package.appxmanifest
nel designer di Visual Studio con l'indicazione della lingua di default (en-US, in questo caso):
La localizzazione delle immagini
A volte può essere necessario localizzare non solo stringhe, ma anche immagini, ad esempio perché contengono testo o caratteri, o altre informazioni correlate a una specifica cultura. Un classico esempio possono essere i segnali stradali. In questo caso, possiamo suddividere le immagini in sotto-cartelle specifiche, utilizzando gli stessi language tag visti per le stringhe. Ad esempio, puoi collocare un'immagine nella cartella images/en-US
e un'immagine con lo stesso nome, ma localizzata per una diversa lingua o cultura, nella cartella images/it-IT
. La prossima immagine mostra la struttura del progetto già visto nel precedente paragrafo, con le nuove cartelle localizzate per le immagini:
Nel codice HTML possiamo quindi referenziare l'immagine semplicemente come images/sample.png
, lasciando al sistema il compito di selezionare l'immagine appropriata in base alle preferenze dell'utente.
<img src="images/sample.png" />
Il risultato è mostrato nella prossima illustrazione:
Teniamo inoltre presente che è possibile specificare, sfruttando la denominazione stessa del file, informazioni aggiuntive (qualifier), come fattori di scala e modalità di contrasto. Ecco un esempio di utilizzo di un'immagine a contrasto elevato con sfondo bianco e colore di primo piano nero:
images/en-US/sample.scale-100_contrast-white.png
Formattare date e orari
Quando si ha a che fare con date e orari, le possibili impostazioni sono molteplici. Per questo motivo sarebbe bene non mostrare mai una data o un orario a schermo senza tenere conto delle preferenze dell'utente.
A questo fine puoi utilizzare la classe Windows.Globalization.DateTimeFormatting.DateTimeFormatter
. Questa classe semplifica la localizzazione di date e orari in base alle preferenze dell'utente. Quel che serve, una volta istanziato un nuovo oggetto di tipo DateTimeFormatter
, è una stringa che descriva il tipo di formattazione desiderata. A questo punto è sufficiente invocare il metodo Format
e passare come parametro la data da formattare, come mostrato nel prossimo snippet:
app.onloaded = function () {
WelcomeMessage.innerText = WinJS.Resources.getString("greeting").value;
SampleText.innerText = WinJS.Resources.getString("sampleText").value;
// formattare la data
var shortDateformatter = new Windows.Globalization.DateTimeFormatting.DateTimeFormatter("shortdate");
LocalizedDate.innerText = shortDateformatter.format(new Date());
}
Per visualizzare il risultato, possiamo usare il seguente codice HTML come riferimento per l'app:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>Demo.Html.it.GlobalizationSample.JS</title>
<!-- WinJS references -->
<link href="//Microsoft.WinJS.2.0/css/ui-dark.css" rel="stylesheet" />
<script src="//Microsoft.WinJS.2.0/js/base.js"></script>
<script src="//Microsoft.WinJS.2.0/js/ui.js"></script>
<!-- Demo.Html.it.GlobalizationSample.JS references -->
<link href="/css/default.css" rel="stylesheet" />
<script src="/js/default.js"></script>
</head>
<body>
<div id="WelcomeMessage" ></div>
<div id="SampleText"></div>
<div id="LocalizedDate"></div>
</body>
</html>
Windows.Globalization.DateTimeFormatting
mette a disposizione svariati template per formattare date e orari in base alla lingua e alla cultura dell'utente, come "shortdate", "shorttime", "dayofweek", e così via. La data verrà quindi formattata sulla base delle preferenze dell'utente, grazie al fatto che ciascun template si basa su una serie di pattern specifici per la cultura e la lingua dell'utente. È possibile ispezionare gli elementi costitutivi utilizzati per costruire i vari pattern, grazie alla proprietà Patterns
esposta dalla classe DateTimeFormatting
. Prendiamo ad esempio il template "month day":
var monthDayformatter = new Windows.Globalization.DateTimeFormatting.DateTimeFormatter("month day");
var monthDayPattern = monthDayformatter.patterns;
A seconda della lingua e della cultura dell'utente, i pattern utilizzati per localizzare la data saranno diversi:
En-US: "{month.full} {day.integer}"
it-IT: "{day.integer} {month.full}"
È anche possibile utilizzare gli elementi costitutivi di un template direttamente, come mostrato nel seguente snippet.
var monthDayformatter = new Windows.Globalization.DateTimeFormatting.DateTimeFormatter("{month.full} {day.integer}");
Per una carrellata completa dei template e relativi costituenti, si rinvia alla documentazione MSDN
Numeri e valute
Quando si ha a che fare con numeri e valute, il namespace Windows.Globalization.NumberFormatting
mette a disposizione una serie di classi helper per formattare questi valori tenendo conto della lingua e della cultura. Le classi sono le seguenti:
Classe | Descrizione |
---|---|
CurrencyFormatter | per formattare valute monetarie |
DecimalFormatter | per formattare numeri decimali |
PercentFormatter | per formattare percentuali |
PermilleFormatter | per formattare numeri con tre o più cifre |
Il seguente snippet mostra un esempio di come formattare un importo nella valuta corrispondente alla cultura dell'utente:
app.onloaded = function () {
WelcomeMessage.innerText = WinJS.Resources.getString("greeting").value;
SampleText.innerText = WinJS.Resources.getString("sampleText").value;
var shortDateformatter = new Windows.Globalization.DateTimeFormatting.DateTimeFormatter("shortdate");
LocalizedDate.innerText = shortDateformatter.format(new Date());
// formattazione in base alla cultura
var userCurrency = Windows.System.UserProfile.GlobalizationPreferences.currencies[0];
var currencyFormat = new Windows.Globalization.NumberFormatting.CurrencyFormatter(userCurrency);
var currencyValue = 1234.567;
currencyFormat.applyRoundingForCurrency(Windows.Globalization.NumberFormatting.RoundingAlgorithm.roundHalfUp);
LocalizedCurrency.innerText = currencyFormat.format(currencyValue);
}
Il codice recupera le informazioni sulla valuta dalle preferenze dell'utente, quindi istanzia un nuovo formato passando come parametro la stringa che rappresenta la valuta stessa. Il metodo ApplyRoundingForCurrency
permette infine di arrotondare la cifra utilizzando uno degli algoritmi indicate dall'enum RoundingAlgorithm.
Per testare questo codice, aggiungiamo un nuovo elemento div
, come mostrato qui di seguito:
<body>
<div id="WelcomeMessage" ></div>
<div id="SampleText"></div>
<div id="LocalizedDate"></div>
<!-- aggiungiamo questo elemento -->
<div id="LocalizedCurrency"></div>
</body>
Localizzare i calendari
Quando si lavora con date e orari, la classe Windows.Globalization.Calendar
si fa carico delle conversioni tra un calendario e l'altro (tieni presente che calendari diversi da quello gregoriano calcolano diversamente giorni e mesi), nonché degli aggiustamenti derivanti dall'ora legale o dagli anni bisestili.
Il seguente codice mostra alcune informazioni relative al calendario sulla base delle preferenze dell'utente:
app.onloaded = function () {
//...
var userCalendar = Windows.System.UserProfile.GlobalizationPreferences.calendars[0];
var userClock = Windows.System.UserProfile.GlobalizationPreferences.clocks[0];
var userLanguages = Windows.System.UserProfile.GlobalizationPreferences.languages;
var cal = new Windows.Globalization.Calendar(userLanguages, userCalendar, userClock);
cal.setToNow();
LocalizedCalendar.innerText = cal.dayOfWeekAsString() + " " + cal.dayAsPaddedString(2) + " " + cal.monthAsString() + " " + cal.yearAsString();
}
Una volta creata un'istanza della classe Calendar
, è possibile compiere qualunque operazione sulle date, come aggiungere secondi, minuti, ore, giorni, mesi o anni. Espone anche informazioni su quanti giorni ci sono in un anno e quante ore in un giorno. Ad esempio, il seguente snippet mostra come aggiungere un mese a una data (ad esempio per calcolare una scadenza),
var cal = new Windows.Globalization.Calendar();
var endDate = cal.clone();
endDate.addMonths(1);
Il Multilingual App Toolkit
Per finire, merita di essere accennato il Multilingual App Toolkit, una estensione per Visual Studio messa a punto da Microsoft per facilitare la globalizzazione di un'applicazione Windows Store e gestire le traduzioni.
Dopo aver creato un file di risorse di default per l'applicazione, possiamo utilizzare il toolkit per tradurre la nostra app in altre lingue. Una volta installato il toolkit e selezionato il progetto per cui si vuole adoprare lo strumento nel Solution Explorer, nel menu di Visual Studio occorre andare su Tools e selezionare Enable Multilingual App Toolkit, come mostrato nella prossima immagine:
Una volta abilitato lo strumento per il progetto corrente, Visual Studio aggiungerà una nuova cartella, con all'interno un file denominato <NomeApp>_qps-ploc.xfl, come mostrato nella seguente immagine.
A questo punto, per aggiungere una traduzione occorre cliccare con il tasto destro sul progetto nella Solution Explorer e, nel relativo menu contestuale, selezionare la voce di menu Add translation languages, evidenziato nella prossima immagine:
Si aprirà quindi un dialog con un elenco di lingue/regioni tra cui selezionare quelle per le quali vogliamo aggiungere una traduzione. Una volta ricompilato il progetto, il toolkit è pronto per essere usato. La prossima immagine mostra la relativa interfaccia:
I vantaggi derivanti dall'uso del Multilingual App Toolkit sono molteplici:
- Facilita la gestione delle modifiche relative alle risorse e lo stato della traduzione durante lo sviluppo.
- Offre un'interfaccia utente per la scelta delle lingue in base ai provider di servizi di traduzione configurati.
- Supporta il formato di file XLIFF standard nel campo della localizzazione.
- Offre un motore per le pseudo lingue che agevola l'individuazione dei problemi di traduzione durante lo sviluppo.
- Si connette a Microsoft Language Portal per accedere facilmente alle stringhe tradotte e alla terminologia.
Puoi trovare tutti i dettagli sulla configurazione e sull'utilizzo delle varie feature dello strumento su MSDN