Guest Post: Localizzare una Universal Windows app


Questo post è stato scritto da Matteo Pagani, Windows AppConsult Engineer in Microsoft

Il supporto a più lingue è sicuramente uno dei modi migliori per incrementare la popolarità e la visibilità della nostra applicazione. Dobbiamo sempre ricordarci, infatti, che nella maggior parte dei casi l'utilizzatore finale del nostro lavoro non sarà una persona tecnica: non possiamo, perciò, dare per scontata la conoscenza della lingua inglese. Per questo motivo, la Universal Windows Platform supporta diversi meccanismi per gestire in maniera semplice la localizzazione delle applicazioni, le cui basi erano già state introdotte in Windows 8 con il Windows Runtime.

Se, in passato, con le applicazioni Silverlight si sfruttavano file in formato .resx, ora si è passati ad un nuovo formato, chiamato .resw. All'atto pratico, in realtà, poco o nulla è cambiato: in entrambi i casi, parliamo di file XML che contengono l'associazione tra una chiave (che identifica la risorsa) e il suo valore, ovvero il testo tradotto.

Un'applicazione avrà, perciò, un file di risorse per ognuna delle lingue supportate, ognuno dei quali conterrà lo stesso elenco di chiavi, ma con valore diverso, ovvero la traduzione del testo nella lingua corrente. Nello XAML o nel codice non andremo mai a includere direttamente un testo, ma faremo riferimento alla sua chiave: in questo modo, a runtime, il controllo sfrutterà il testo presente nel file di risorse legato alla lingua corrente del dispositivo.

Prima di vedere, nella pratica, come gestire i file di risorse, è bene ricordare che ad ogni applicazione è legata una lingua predefinita, che viene utilizzata nel caso in cui l'utente stia utilizzando il device in una lingua che non abbiamo supportato direttamente con una specifica traduzione. Tale lingua è impostata nel file di manifest (il file Package.appxmanifest presente nella radice del progetto), all'interno della sezione Application, alla voce Default language.

Il punto di partenza per gestire i file di risorse è aggiungere un nuovo file di tipo .resw all'interno della propria Universal Windows app. E' necessario, però, seguire una precisa convenzione, affinché venga correttamente riconosciuto. I file devono essere posizionati all'interno di una cartella di nome Strings, la quale deve contenere una sottocartella per ogni lingua supporta. Tale sottocartella dovrà avere, come nome, il codice corrispondente alla lingua: può essere relativo ad una cultura specifica (ad esempio, en-US) oppure generico (ad esempio, en). All'interno di ogni sottocartella, possiamo creare il nostro file di risorse: facciamo clic con il tasto destro in Visual Studio, scegliamo Add -> New Item e sfruttiamo il template Resources file (.resw).

In fase di creazione lasciamo il nome standard, ovvero Resources.resw. Ecco come appare la tipica struttura di un progetto che fa uso della localizzazione:

Facendo doppio clic su uno dei file Resources.resw si aprirà l'editor di file di risorse, che ci offre semplicemente una visualizzazione tabellare del file XML, facilitandoci il compito di definire chiavi e valori:

La chiave di una risorsa (la colonna Name) è identificata da due informazioni, separate da un punto:

  1. Il nome della chiave, che deve essere univoco.
  2. La proprietà del controllo a cui vogliamo applicare questa traduzione.

Ad esempio, ipotizziamo (come si vede nell'immagine) di avere una chiave di nome AppTitle.Text. Ciò significa che, da qualche parte nel codice, avremo un controllo identificato dalla chiave AppTitle, la cui proprietà Text sarà valorizzata con il valore che abbiamo specificato nella colonna Value.

Localizzare lo XAML

Per applicare una risorsa localizzata direttamente ad un controllo, lo XAML ci mette a disposizione la proprietà x:Uid, che deve essere valorizzata con l'identificativo della chiave (quindi la parte precedente al punto).

Ad esempio, ipotizziamo di avere nella nostra pagina XAML un controllo di tipo TextBlock, nel quale vogliamo mostrare il testo inserito in precedenza nel nostro file di risorse legato alla chiave AppTitle.Text. Ecco come dovremo definirlo:

<TextBlock x:Uid="AppTitle" Style="{StaticResource HeaderTextBlockStyle}" />

In automatic, il valore della risorsa AppTitle sarà applicato alla proprietà Text del controllo.

Accedere da codice

A volte può sorgere la necessità di accedere ad una risorsa da codice. Ipotizziamo, ad esempio, di voler mostrare una finestra di dialogo all'utente tramite la classe MessageDialog. In tal caso, non si tratta di un controllo XAML, ma di un oggetto che viene creato e gestito da codice. Di conseguenza, abbiamo bisogno di recuperare dal file di risorse il testo da mostra nella finestra. Ci aiutiamo con la classe ResourceLoader, come nell'esempio seguente:

public async Task ShowMessage()

{

ResourceLoader loader = new ResourceLoader();

string text = loader.GetString("AppTitle/Text");

 

MessageDialog dialog = new MessageDialog(text);

await dialog.ShowAsync();

}

Dopo aver creato una nuova istanza della classe ResourceLoader, chiamiamo il metodo GetString() che accetta, come parametro, il nome completo della chiave. Unica accortezza: al posto del punto, dobbiamo usare il simbolo / come separatore. Quindi, ad esempio, per accedere al valore della chiave AppTitle.Text, dobbiamo usare la sintassi AppTitle/Text.

Un modo più efficiente per gestire il codice

L'approccio appena introdotto è particolarmente suscettibile agli errori: è sufficiente sbagliare il nome della chiave o della proprietà per ottenere un errore in fase di esecuzione. Per migliorare l'esperienza di sviluppo possiamo sfruttare un'estensione di Visual Studio di terze parti chiamata ResW File Code Generator, scaricabile da https://reswcodegen.codeplex.com/

Questa estensione si fa carico di generare, per ogni file di risorse, una classe che, dietro le quinte, espone ogni chiave come proprietà statica. In questo modo, invece di dover specificare manualmente il nome della chiave come parametro del metodo GetString(), potremo usare un approccio simile a quello seguente:

public async Task ShowMessage()

{

string text = Library.LocalizedStrings.Resources.AppTitle;

MessageDialog dialog = new MessageDialog(text);

await dialog.ShowAsync();

}

Questo è reso possibile dal fatto che, dietro le quinte, il tool ha generato una classe che contiene a seguente definizione:

public static string AppTitle

{

get

{

return resourceLoader.GetString("AppTitle");

}

}

Ecco i passi da seguire per abilitare il tool:

  1. La prima operazione da compiere è installare l'apposita estensione di Visual Studio: https://visualstudiogallery.msdn.microsoft.com/3ab88efd-1afb-4ff5-9faf-8825a282596a
  2. Il secondo passaggio è identificare il file di risorse Resources.resw legato alla lingua di default della nostra applicazione, ovvero quella specificata nel file di manifest e che viene proposta all'utente nel caso in cui il suo dispositivo sia in una lingua che non supportiamo (tipicamente è l'inglese). Questo perché i passaggi successivi saranno da applicare solamente ad un file di risorse e non a tutti quelli inclusi nel progetto.
  3. Dopo averlo identificato, selezionatelo e, dalla finestra Properties di Visual Studio, impostate:
    1. La proprietà Custom Tool su ReswFileCodeGenerator
    2. Eventualmente, la proprietà Custom Tool Namespace su un valore a piacimento: sarà il namespace di default che il tool creerà per la classe.

A questo punto il gioco è fatto: se avete fatto tutto correttamente, dovreste vedere un nuovo file di nome Resources.cs all'interno di Visual Studio, come nell'immagine seguente.

Da questo momento in poi, potrete accedere da codice alle vostre risorse usando la sintassi vista in precedenza, molto più semplice e meno suscettibile ad errori.

Attenzione: il tool sopra citato funziona solo se la risorsa deve essere utilizzata via codice e viene inclusa all'interno del file solo con il nome della chiave, senza specificare la proprietà su cui agire. Ad esempio, una risorsa di nome AppTitle sarà correttamente convertita in una proprietà della classe; una risorsa, invece, di nome AppTitle.Text sarà ignorata.

Includere le risorse in una libreria

Il tool ResW File Code Generator può essere utilizzato anche per un altro scopo: darci la possibilità di includere le risorse in una libreria, anziché direttamente nel progetto dell'applicazione. Ci sono diversi scenari in cui questo approccio può essere utile: ad esempio, vogliamo condividere delle risorse tra più progetti; oppure alcune delle risorse devono essere sfruttate non solo dall'applicazione, ma anche da un background task, ovvero un progetto di tipo Windows Runtime Component separato da quello che invece contiene l'applicazione vera e propria.

Per raggiungere questo scopo, dobbiamo innanzitutto seguire i passaggi descritti in precedenza solo che, invece di applicarli al progetto Windows 10, li eseguiamo sulla libreria. Andremo perciò a:

  1. Includere la cartella Strings con i vari file Resources.resw all'interno della libreria.
  2. Abilitare la generazione del file di codice, impostando la proprietà Custom Tool del file Resources.resw principale su ReswFileCodeGenerator.

Ora siamo pronti per iniziare ad utilizzarle, ovviamente dopo aver aggiunto al progetto principale un riferimento (tramite il menu Add reference) alla libreria. Dal punto di vista dell'accesso tramite codice, non ci sono differenze: dato che il tool genera semplicemente una classe, potremo semplicemente accedervi dal progetto principale sfruttando il namespace che abbiamo specificato nella proprietà Custom Tool Namespace del file di risorse.

Per quanto riguarda lo XAML, invece, c'è un accorgimento in più: non dovremo semplicemente valorizzare la proprietà x:Uid con il nome della chiave, ma dovremo farlo precedere dal nome dell'assembly della libreria. Ad esempio, ipotizziamo che la nostra libreria sia contenuta all'interno di un progetto chiamato ResourcesSample.Library. Ciò significa che nello XAML dovremo usare la seguente sintassi:

<TextBlock x:Uid="/ResourcesSample.Library/Resources/AppDescription"

Style="{StaticResource HeaderTextBlockStyle}" />

Al nome della libreria facciamo seguire il nome della classe generata dal tool (ovvero Resources) e, infine, la chiave vera e propria.

Attenzione: l'applicazione e lo Store sfruttano i file di risorse inclusi nel progetto principale per identificare quali sono le lingue supportate dall'applicazione. Non sono in grado, perciò, di recuperare questa informazione dalla libreria. Di conseguenza, dovremo comunque includere nel progetto principale dei file di risorse, speculari rispetto a quelli della libreria. Fortunatamente, però, la specularità si ferma solo all'elenco dei file. Ciò significa che se nella libreria abbiamo 10 file di risorse per 10 differenti lingue, l'applicazione dovrà contenere i medesimi file, ma vuoti: le risorse vere e proprio rimarranno comunque memorizzate solamente all'interno della libreria.

Il Multilingual App Toolkit

La gestione della localizzazione apre una nuova serie di sfide da risolvere. Ad esempio, un testo che in inglese ha un certo ingombro potrebbe averne uno completamente differente in italiano e non adattarsi bene al layout che abbiamo progettato. Oppure sorge la necessità, ogni volta che aggiungiamo una nuova risorsa, di replicarla per ognuna delle lingue supportate.

Per semplificare questi scenari possiamo utilizzare un tool di Microsoft chiamato Multilingual App Toolkit: la versione 4.0, recentemente rilasciata in versione finale, ha aggiunto, tra le altre cose, il supporto alla Universal Windows Platform.

Il primo passo, perciò, è installarlo: si tratta di un'estensione di Visual Studio, disponibile all'indirizzo https://visualstudiogallery.msdn.microsoft.com/6dab9154-a7e1-46e4-bbfa-18b5e81df520. Dopodiché, all'interno del nostro progetto Visual Studio che contiene dei file di risorse, potremo abilitarlo tramite l'apposito menu presente nella sezione Tools di Visual Studio: dalla sezione Multilingual App Toolkit scegliamo la voce Enable selection.

A questo punto, abbiamo la facoltà di aggiungere nuovi file di risorse semplicemente facendo clic con il tasto destro sul progetto e scegliendo, dal menu Multilingual App Toolkit, la voce Add translation languages. Tale operazione genererà in automatico un nuovo file Resources.resw nella cartella Strings e un file con estensione .xlf all'interno della cartella MultilingualResources, creata dal tool all'interno del progetto. Il file XLF è quello con cui dovremo andare ad agire per gestire le traduzioni: utilizzando il toolkit, infatti, non dovremo più andare a lavorare direttamente con i file .resw delle lingue aggiuntive, ma lo farà il tool per noi.

Possiamo mettere alla prova questo approccio semplicemente provando ad aggiungere una nuova risorsa nel file Resources.resw della lingua predefinita. Ricompilando, ci accorgeremo di come questa nuova risorsa sarà stata automaticamente aggiunta anche in tutte le altre lingue, senza bisogno da parte nostra di intervenire manualmente. Come valore predefinito sarà assegnato quello della lingua predefinita, così da avere un termine di riferimento. Se ora vogliamo modificare la traduzione di tale risorsa per le varie lingue, possiamo fare semplicemente doppio clic sul file .xbf corrispondente: ciò aprirà l'interfaccia del Multilingual App Toolkit, come da immagine seguente.

Come vedete, rispetto all'editor standard dei file .resw, il toolkit ci offre molte più opzioni, tra cui:

  1. Premendo il pulsante Translate, possiamo affidarci ai servizi di Bing per avere una traduzione automatica del testo nella lingua corrispondente. Non si tratta sicuramente della scelta ideale per la versione finale dell'applicazione da pubblicare sullo Store, dato che le traduzioni automatiche non sono mai affidabili al 100%, ma può essere un valido aiuto per verificare gli ingombri e farsi un'idea.
  2. Tramite il campo State possiamo stabilire lo stato della traduzione della singola risorsa e, quindi, determinare a colpo d'occhio quanti testi sono già stati tradotti, quanti richiedono ancora una revisione, ecc. Sulla base di questa informazione il toolkit permette anche di generare un report.

Tramite il menu contestuale presente facendo clic con il tasto destro sul progetto abbiamo, inoltre, una serie di utili opzioni, come la possibilità di esportare i file XLF per poterli condividere con eventuali traduttori.

Lo pseudo linguaggio

Il Multilingual App Toolkit supporta lo pseudo linguaggio, ovvero una lingua particolare che viene utilizzata in fase di testing per valutare gli ingombri di un testo. Rispetto al testo base, infatti, aggiunge una serie di caratteri particolari che permettono di simulare la lunghezza che potrebbe avere quel testo nelle varie lingue.

Ad esempio, la stringa Hello world viene rappresentata dal testo [ED371][!!_Нéłĺò ẅòŕĺď_!!]. Per quanto riguarda la gestione delle risorse, non vi è alcuna differenza con le altre lingue: dovremo aggiungere una nuova traduzione tramite il menu Add translations del Multilingual App Toolkit. La troveremo in cima alla lista, dal nome Pseudo language, identificata dal codice qps-ploc.

Una volta aggiunta, possiamo cliccare con il tasto destro sul corrispondente file .xlf generato e scegliere, sempre dal menu Multilingual App Toolkit, l'opzione Generate machine translations. In questo modo, il tool genererà in automatico una traduzione per tutte le risorse in pseudo linguaggio.

L'unica differenza rispetto ad una lingua tradizionale è che i vari device non includono, per ovvi motivi, lo pseudo linguaggio tra le lingue configurabili dall'utente. Dovremo, perciò, forzare l'utilizzo di questa lingua direttamente dall'applicazione, all'interno del costruttore della classe App, sfruttando la proprietà PrimaryLanguageOverride della classe ApplicationLanguages:

public App()

{

this.InitializeComponent();

this.Suspending += OnSuspending;

ApplicationLanguages.PrimaryLanguageOverride = "qps-ploc";

}

Se ora avviamo l'applicazione, noteremo che al posto della lingua corrente del device sarà usato lo pseudo linguaggio.

In conclusione

Nel corso di questo post abbiamo imparato come gestire la localizzazione in una Universal Windows app. In realtà, il Multilingual App Toolkit può essere un valido aiuto anche nella localizzazione di applicazioni per le altre piattaforme: la versione 4.0, infatti, supporta anche le applicazioni Android e iOS sviluppate con Xamarin. Trovate il progetto di esempio descritto in questo post su GitHub all'indirizzo https://github.com/qmatteoq/UWPLocalization Happy coding!


Comments (0)

Skip to main content