[Windows Phone 7.5] Localización de aplicaciones

Hola a todos!

Tras algo más de un año de vida de la plataforma Windows Phone, empezamos a poder ver que estrategias funcionan mejor a la hora de monetizar nuestras aplicaciones. En concreto existen dos parámetros importantes, que destacan sobre los demás a la hora de realizar esta monetización: las actualizaciones constantes y la localización de aplicaciones.

En este artículo vamos a centrarnos en el segundo, la localización de aplicaciones. En estos momentos los potenciales usuarios de nuestra aplicación en castellano es muy limitado. Sin embargo, el número de usuarios en otros idiomas como Inglés, Francés, Alemán o incluso Chino es mucho más alto.

La mayor ventaja de un marketplace como el de Windows Phone es el disponer de un canal de distribución internacional y amplio de nuestras aplicaciones. Pero si estas se encuentran solo en castellano, estamos eliminando esta ventaja. Además, en Windows Phone, es realmente sencillo internacionalizar nuestras aplicaciones. Vamos a ver como llevarlo a cabo.

Para empezar hemos creado una nueva aplicación muy simple: al iniciarse muestra un texto en pantalla:

<StackPanel>
    <TextBlock TextWrapping="Wrap"
                FontSize="{StaticResource PhoneFontSizeLarge}">
        <TextBlock.Text>
            Este es un ejemplo de texto no localizado, 
            el usuario que no sepa castellano no podrá
            disfrutar de nuestra aplicación al 100% y es
            muy probable que la descarte y use cualquier 
            otra en su idioma nativo.
        </TextBlock.Text>
    </TextBlock>
</StackPanel>

Que nos ofrece el siguiente resultado al ejecutarla:

image

Hemos escrito el texto directamente en XAML, por lo que nos encontramos con dos desventajas: en primer lugar, si ese texto exacto se necesita en varias partes de nuestra aplicación, deberemos escribirlo varias veces. Si necesitamos cambiar o corregir algo, tendremos que ir por todos los sitios donde se use haciéndolo. La segunda desventaja es que traducir el texto dentro del control directamente es más complicado y nos implica controlar por código el idioma y el texto a usar. En general, aunque no queramos tener múltiples idiomas, se considera una mala práctica usar texto directamente dentro de los controles de UI.

¿Como remediamos esto? En primer lugar vamos a añadir una nueva carpeta a nuestra solución llamada “Languages” y dentro de ella vamos a crear un archivo de recursos (resx) llamado Language.resx y otro llamado language.es-ES.resx:

image

Una vez hecho esto, vamos a abrir cada uno de los archivos y a establecer su Access Modifier a Public :

image

Dentro de cada archivo de recursos podemos crear una colección de Clave/Valor. En este caso, Name sería la clave para acceder al recurso y Value, obviamente, el valor del recurso. en la última columna Comment, podemos indicar un comentario para nosotros.

El truco a la hora de internacionalizar nuestra aplicación es crear un archivo de recursos neutral (Language.resx) que será usado siempre que no se encuentre un archivo de recursos para un idioma concreto. Para definir el resto de idiomas, creamos archivos de recursos que se llamen igual que el neutral, añadiendo el código ISO del idioma al final (por ejemplo Language.es-ES.resx para el castellano). En este ejemplo hemos decidido no usar castellano como idioma neutral, nuestro idioma neutral será ingles, por lo que no necesitamos crear un archivo de recursos Language.en-US.resx y los textos escritos en Language.resx estarán en inglés:

image

Es muy importante que el Nombre de cada recurso de texto sea igual en todos los archivos de recursos, en tiempo de ejecución pediremos un recurso por nombre y el sistema nos devolverá el valor dependiendo del idioma del sistema.

Ahora necesitamos una forma de acceder a estos recursos desde nuestro XAML para poder presentar el texto al usuario, para ello, necesitamos crear una clase que haga de wrapper y exponga nuestros recursos:

public class LanguageProvider
{
    public LanguageProvider()
    {
    }

    private Language actualLanguage;

    public Language ActualLanguage 
    { 
        get 
        {
            if (actualLanguage == null)
                actualLanguage = new Language();
            return actualLanguage; 
        }
    }
}

Simplemente tenemos un constructor público y una propiedad ActualLanguage que nos devuelve una instancia de Language desde la cual poder acceder al recurso deseado.

Ahora, vamos a referenciar nuestros archivos de recursos en los namespace de App.xaml:

xmlns:lang="clr-namespace:WP75Localization.Languages"

Y a crear un nuevo recurso, también en App.xaml:

<Application.Resources>
    <lang:LanguageProvider x:Key="Language"></lang:LanguageProvider>
</Application.Resources>

De esta forma, desde nuestra página, podremos usar una expresión de enlace a datos para acceder a una clave de nuestros archivos de recursos:

<StackPanel>
    <TextBlock TextWrapping="Wrap"
                FontSize="{StaticResource PhoneFontSizeLarge}"
                Text="{Binding ActualLanguage.Localized_hello, Source={StaticResource Language}}">
    </TextBlock>
</StackPanel>

Si nos fijamos en el atributo Text, veremos que simplemente hacemos un Binding al nombre de la clave que deseamos mostrar desde los recursos y a continuación le indicamos que la fuente será el resource que hemos creado en App.xaml.

Pero, si ejecutamos la aplicación, ya sea en un dispositivo en castellano o en el emulador en castellano, veremos que el texto aparece en inglés ¿Por qué?

Esto se debe a que debemos indicar en nuestra aplicación que idiomas soportamos. Para ello debemos editar el archivo de proyecto de la aplicación, haciendo click derecho sobre el nombre de proyecto y escogiendo la opción “Unload Project”:

image

A continuación volvemos a hacer click derecho y escogemos la opción “Edit [NombreProyecto.csproj]” lo que nos mostrará el XML de definición de nuestro proyecto. En este XML al principio, sobre la línea 19-20 encontraremos un nodo llamado SupportedCultures. Es aquí donde debemos indicar todos los idiomas adicionales que soportamos. En nuestro ejemplo, el archivo de recursos por defecto está en ingles y hemos añadido otro para soportar español, por lo que debemos incluir español como una cultura soportada:

<SupportedCultures>
  es-ES
</SupportedCultures>

Ahora solo tenemos que guardar los cambios, cerrar la edición y volver a hacer click derecho sobre el proyecto, esta vez escogiendo la opción “Reload Project” que volverá a cargar nuestro proyecto. Si ahora ejecutamos la aplicación sobre el emulador configurado en castellano o en un dispositivo en castellano, veremos que nuestro texto aparece con el idioma correcto:

image

Al indicar las culturas soportadas y crear archivos de recursos con esas culturas, automáticamente obtendremos el texto a mostrar en el idioma correcto, por lo que es muy sencillo traducir nuestras aplicaciones y un “must have” si queremos triunfar en el marketplace.

Idiomas no soportados

Aunque tenemos soporte para los principales idiomas del mundo, en España encontramos una situación peculiar. No tenemos una sola lengua, existen regiones con su propio idioma muy utilizado como son Cataluña con el Catalán, País Vasco con el Euskera o Galicia con el Galego. Estos idiomas NO ESTAN soportados en el sistema, por lo que este proceso de internacionalización automático que hemos visto, no nos sirve, el usuario nunca podrá configurar el Euskera como idioma de su dispositivo por lo que, aunque lo incluyamos entre los idiomas soportados y añadamos un archivo de recursos con los textos en Euskera, nunca se mostrarán.

Pero no todo está perdido. Esta falta de idiomas no es un desprecio de Microsoft hacia los mismos. El proceso de añadir idiomas a una plataforma es complejo y debe estar perfectamente realizado, lo cual lleva tiempo. Es muy probable que en próximas versiones del sistema operativo veamos aparecer estos idiomas y podamos usarlos. Mientras tanto, nos toca esperar a la aparición oficial.

¿Y si no queremos esperar?

Bueno, si no queremos esperar Guiño, podemos usar un pequeño workaround para que al menos nuestra aplicación esté traducida a idiomas no soportados. para ello vamos a modificar la pantalla principal para que nos permita indicar que deseamos usar un idioma elegido por el usuario, no el del sistema. Vamos a realizar el ejemplo con Catalán. Lo primero que necesitamos hacer es modificar nuestra clase LanguageProvider para que podamos indicarle que deseamos usar un idioma forzado. También implementaremos el interface INotifyPropertyChanged para forzar el redibujado de la interface de usuario cuando forcemos el idioma:

public class LanguageProvider : INotifyPropertyChanged
{
    public LanguageProvider()
    {
    }

    private bool useCustomLanguage;
    public bool UseCustomLanguage 
    {
        get { return useCustomLanguage; }
        set
        {
            useCustomLanguage = value;
            RaiseChange("ActualLanguage");
        }
    }


    private Language actualLanguage;

    public Language ActualLanguage 
    { 
        get 
        {
            if (actualLanguage == null)
                actualLanguage = new Language();

            if (UseCustomLanguage)
            {
                System.Threading.Thread.CurrentThread.CurrentUICulture = new System.Globalization.CultureInfo("ca-ES");
                actualLanguage = new Language();
            }

            return actualLanguage; 
        }
    }

    public event PropertyChangedEventHandler PropertyChanged;

    public void RaiseChange(string propertyName)
    {
        if (PropertyChanged != null)
            PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
    }
}

A continuación, modificaremos la UI para permitir establecer este valor:

<StackPanel>
    <TextBlock TextWrapping="Wrap"
                FontSize="{StaticResource PhoneFontSizeLarge}"
                Text="{Binding ActualLanguage.Localized_hello, Source={StaticResource Language}}">
    </TextBlock>
    <CheckBox Content="Forzar idioma"
                IsChecked="{Binding UseCustomLanguage, Mode=TwoWay, Source={StaticResource Language}}"></CheckBox>
</StackPanel>

Ahora solo necesitamos añadir el idioma catalán a la lista de idiomas soportados en el archivo de proyecto como hicimos antes con el Castellano:

<SupportedCultures>
  es-ES;ca-ES
</SupportedCultures>

Y por último tenemos que crear un archivo de recursos para los textos en catalán, al igual que ya hicimos para los textos en castellano e inglés:

image

Con todo este trabajo realizado, si ejecutamos la aplicación en el emulador o dispositivo en castellano obtendremos este resultado:

image

Y si marcamos el check “Forzar Idioma” obtendremos este resultado:

image

Ya tenemos nuestra aplicación localizada al Catalán, y nuestros usuarios pueden beneficiarse de usarla en su idioma nativo.

¿Que pasa con la certificación?

En las reglas de certificación de idiomas de Microsoft nos dicen que debemos establecer un idioma neutral, el que se usará si el resto de idiomas que soportamos no coinciden con el usado por el sistema (Ver aquí, punto 4.4 Language Validation) por lo que nada nos impide añadir idiomas a nuestra aplicación aunque no estén directamente soportados por el sistema.

Y hasta aquí el artículo de hoy. Os dejo el código fuente del ejemplo a continuación.

Un saludo y Happy Coding!

2 comentarios sobre “[Windows Phone 7.5] Localización de aplicaciones”

Deja un comentario

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *