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.
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:
Tras ambos archivos, si abrimos un archivo de recurso veremos algo como lo siguiente:
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:
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.
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.
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.
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:
Y en español:
Puedes descargar el código del ejemplo desde 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
- Documentación Xamarin: Localizing Xamarin.Forms Apps with RESX Resource Files
- Ejemplo: UsingResxLocalization
- Ejemplo: TodoLocalized