[Xamarin.Forms] Localización de Aplicaciones

Introducción

Cuando desarrollamos nuestras aplicaciones, un factor importante a tener en cuenta es el público objetivo de la misma. Analizando este punto debemos determinar si distribuimos nuestra aplicación a nivel nacional, en multiples países o a nivel mundial. Si decidimos la última opción debemos de tener en cuenta que aunque las probabilidades de llegar a una mayor cantidad de público aumentan considerablemente, no todo el mundo habla español por lo que seguimos restringidos.

¿Qué podemos hacer?

En este artículo vamos a realizar los pasos necesarios para localizar una aplicación Xamarin.Forms , ¿te apuntas?.

Globalización en Apps Xamarin.Forms

El proceso de globalización consiste en preparar nuestra aplicación para «todo el mundo». La aplicación debe estar preparada para mostrar la información en diferentes idiomas. Los textos y recursos de nuestra aplicación deben ser diferentes en base al idioma configurado por el dispositivo.

Archivos RESX

Para la gestión de textos en cada idioma utilizaremos archivos RESX. Tendremos un archivo de recursos diferente por cada idioma soportado. Cada archivo se basa en clave-valor. Las claves se repetirán en cada archivo mientras que el valor será la cadena localizada al idioma correspondiente.

Creando los archivos RESX

En la librería portable, comenzamos creando una carpeta Resources con el objetivo de mantener todos los archivos organizados. A continuación, crearemos un archivo de recursos por cada idioma soportado. Para crear el archivo de recursos, hacemos clic derecho sobre la recien creada carpeta Resources, Añadir > Nuevo archivo > General > Resource File.

Nuevo archivo de recursos

Nombra al archivo como Resources o AppResources (nombres habituales) para el idioma por defecto, inglés. Por cada idioma soportado, se debe repetir el proceso llamando al archivo AppResources.{nombre cultura}.resx.

NOTA: Puedes ver un listado completo de países, idiomas y su cultura en este enlace.

Añadiendo soporte al idioma español:

Español

Tras ambos archivos, si abrimos un archivo de recurso veremos algo como lo siguiente:

RESX

Añadiremos las claves en la comuna Nombre y el valor localizado a cada idioma en la columna Valor. Posteriormente, accederemos a cada valor localizado utilizando la clave. En base al idioma, se accederá a un archivo de recursos u otro. De esta forma, podremos mantener de forma sencilla los textos localizados y ofecer una aplicación localizada a diferentes idiomas.

Utilizando los archivos desde C#

Tras añadir un valor:

Añadimos valores

Podemos acceder al valor desde código C# de forma sumamente sencilla:

Label label = new Label()
{
     Text = AppResources.LanguageText
};

Si se lanza la aplicación en español y en inglés el valor estará localizado en cada idioma.

Y ahora desde XAML

Utilizar valores localizados utillizando archivos de recursos es rápido y directo desde código C#. Sin embargo, desde XAML necesitamos «algo más». Por defecto, no tenemos ninguna extensión de marcado que nos permita indicar el valor de la clave que buscamos en el archivo de recursos para permitir localizar la aplicación. Sin embargo, si podemos crear extensiones de marcado personalizadas utilizando la interfaz IMarkupExtension:

[ContentProperty("Text")]
public class TranslateExtension : IMarkupExtension
{
     const string ResourceId = "XamarinFormsLocalization.Resources.AppResources";

     public string Text { get; set; }

     public object ProvideValue(IServiceProvider serviceProvider)
     {
          if (Text == null)
               return null;

          ResourceManager resourceManager = new ResourceManager(ResourceId, typeof(TranslateExtension).GetTypeInfo().Assembly);

          return resourceManager.GetString(Text, CultureInfo.CurrentCulture);
     }
}

Utilizamos la clase ResourceManager para acceder al archivo de recurso correspondiente. A continuación, se utiliza el método GetString para obtener el valor asociado a la clave pasada como parámetro en la propiedad Text.

¿Y cómo lo utilizamos?.

Sencillo, primero declaramos el espacio de nombres en XAML necesario:

xmlns:extensions="clr-namespace:XamarinFormsLocalization.MarkupExtensions"

Y a continuación:

 <Label 
      Text="{extensions:TranslateExtension Text=LanguageText}" />

Utillizamos la extensión pasando como parámetro la clave deseada en la propiedad Text. También podemos utilizar la extensión de marcado de forma menos verbosa:

<Label 
     Text="{extensions:Translate LanguageText}" />

Otros recursos

Una aplicación móvil no se compone exclusivamente de textos. Existen otra serie completa de recursos muy utilizados. Entre los recursos más utilizados, imágenes.

Normalmente se cuentan con imágenes que se pueden ver exactamente igual en diferentes idiomas, pero no así con todas.

¿Cómo gestionamos la localización de imágenes por idioma?

Es una tarea que debemos realizar en cada plataforma de forma específica.

Android

Utilizamos la carpeta drawable dentro de Resources para la gestión de imágenes. Para contar con imágenes diferentes por idioma, podemos crear carpetas con el nombre drawable-{código del idioma}. Android se basa en esta estructura de carpetas con sufijos para localizar imágenes.

Imágenes localizadas en Android

NOTA: Para soportar diferentes imágenes para resoluciones diferentes y además basándonos en el idioma, seguimos utilizando la misma estructura de sufijos en carpetas. Por ejemplo: drawable-es-xdpi.

iOS

En este caso, iOS, utiliza Localization Projects o .lproj para contener imágenes por idioma junto con recursos de cadenas. Dentro de la carpeta Resources debemos crear {códido de idioma}.lproj por cada idioma soportado.

Localización de imágenes en iOS

Cada carpeta correspondiente a un idioma contará con sus versiones de imágenes. En caso de que una carpeta de un idioma no cuenta con imágenes, se utilizarán las correspondientes del idioma por defecto.

NOTA: Para pantallas retina se pueden añadir imágenes @2x y @3x.

UWP

En el caso de aplicaciones universales, organizaremos dentro de la carpeta Assets los recursos por idioma en carpetas con el nombre de la cultura.

Localización de imágenes en UWP

No tenemos un mecanismo que automáticamente seleccione la imagen correspondiente a cada idioma. Por este motivo, vamos a crear un sencillo Custom Renderer.

xmlns:extensions="clr-namespace:XamarinFormsLocalization.MarkupExtensions"
[assembly: ExportRenderer(typeof(Image), typeof(XamarinFormsLocalization.UWP.Renderers.LocalizedImageRenderer))]
namespace XamarinFormsLocalization.UWP.Renderers
{
     public class LocalizedImageRenderer : ImageRenderer
     {
          protected override void OnElementChanged(ElementChangedEventArgs<Image> e)
          {
               base.OnElementChanged(e);

               if (e.NewElement != null)
               {
                    var fileImageSource = e.NewElement.Source as FileImageSource;

                    if (fileImageSource != null)
                    {
                         var fileName = fileImageSource.File;
                         string currentUICulture = CultureInfo.CurrentUICulture.ToString();
                         e.NewElement.Source = Path.Combine("Assets/" + currentUICulture + "/" + fileName);
                    }
               }
          }
     }
}

Creamos un Custom Render en UWP del control Image. Se obtiene la ruta de la imágen a la que se añade la ruta correcta utilizando CurrentUICulture. De esta forma, automáticamente, en base al idioma se accederá a una ruta u otra.

El resultado de la aplicación en inglés:

Inglés

Y en español:

Español

Puedes descargar el código del ejemplo desde GitHub:

Ver GitHub

Existen otra serie de puntos interesantes relacionados con la localización de aplicaciones como por ejemplo la localización del nombre de la aplicación que veremos en otro artículo.

Recuerda, cualquier duda o comentario es bienvenido!

Más información