Localizacion y globalizacion en .Net Core

Utilizando un solo archivo de recursos.

El nuevo esquema de localización y globalización que propone Microsoft en .Net Core, es muy robusto y relativamente fácil de utilizar, sin embargo, crea una gran cantidad de archivos de recursos (*.resx), ya que crea un archivo por cada clase o componente por cada cultura soportada; esto nos indica que si se tienen 2 vistas y se manejan 2 culturas (ingles y español, por ejemplo) se crearán 4 archivos de recursos adicionales a las vistas.

Lo anterior nos provoca una gran fragmentación de los recursos de localización y globalización, y en caso de no saberlo manejar adecuadamente un gran repetición de frases en distintos idiomas.

También nos genera mayor cantidad de trabajo al momento de tener una aplicación publicada y desear el agregar una nueva cultura.

El paquete nuget JCTools.I18N que he desarrollado nos brinda dos ventajas:

  1. Facilita el proceso de configuración de los paquetes requeridos para la localización y globalización
  2. Permite la utilización de un solo archivo para todos los recursos de localización y globalización, sin perder la posibilidad de utilizar múltiples archivos en aquellos componentes que se desee tener por separado.

El proceso de configuración es el siguiente:

  1. Agregar el paquete nuget antes mencionado:

    PM> Install-Package JCTools.I18N

  2. Agregar un nuevo campo privado en la clase Startup.

    private readonly IHostingEnvironment _enviroment;

  3. Establecer el valor al campo creado en el paso anterior en el constructor de la clase:
    _enviroment = env;
  4. Crear un clase nueva vacía que será utilizada como referencia para obtener el archivo de recursos unico.
    namespace JCTools.I18N.Test
    {
        /// <summary>
        /// Uses with ends of localization and globalization of this app
        /// </summary>
        public class I18N { }
    }
    
    Nota: Se puede utilizar la clase Startup.cs.
  5. Crear una nueva carpeta en el proyecto para almacenar los archivos de recursos, y agregar un nuevo archivo de recursos, el cual deberá ser nombrado igual que la clase creada en el paso anterior y no deberá contar con el postfijo de la cultura representada:

    Nota 1: Este archivo será utilizado para la cultura default.

    Nota 2: Este archivo deberá tener su modificador de acceso configurado como Public.

  6. Cree los archivos necesarios para representar el resto de las culturas soportadas.

  7. Reemplace la siguiente línea del método Startup.ConfigureServices, especificando las culturas soportadas y la cultura default:
    services.AddMvc();

    Por:

    services.AddLocalizationServices(
    	// The supported cultures
    	new List<CultureInfo>
    		{
    			new CultureInfo("en"),
    			new CultureInfo("en-US"),
    			new CultureInfo("es"),
    			new CultureInfo("es-MX")
    		},
    	// the default culture
    	defaultCulture: "es-MX"
    )
    .AddSingleLocalizationFile<I18N, Resources.I18N>(_enviroment);
  8. Agrege lo siguiente en el método Startup.Configure:
    app.UseLocalization();

    Nota: Debe ser agregado antes de:

    app.UseStaticFiles();
    
    app.UseMvc(routes =>
    {
    	routes.MapRoute(
    		name: "default",
    		template: "{controller=Home}/{action=Index}/{id?}");
    });

Lo anterior agrega el soporte necesario para la localización y globalización de componentes, así como, la posibilidad de utilizar un solo archivo de recursos.

Ahora la utilización en los diversos recursos es muy similar a como se realiza la opción oficial.

En los controladores:

  1. Agregue un campo privado que almacenará la instancia de la clase que permite el acceso a los recurso:
    private readonly SingleLocalizer _localizer;
  2. Agregue a su constructor un nuevo argumento, el cual será inicializado mediante la inyección de dependencias.
    public HomeController(SingleLocalizer localizer)
  3. Estableca el valor al campo creado en paso 1 con el valor del argumento del paso dos.
    _localizer = localizer; 
  4. Utilice el campo como se muestra a continuación:
    ViewData["Message"] = _localizer["About_Message"];

En las vistas:

  1. Agregue en su archivo _ViewImports.cshtml la siguiente dependencia, lo que permitirá que se encuentre disponible en todas las vistas:
    @inject JCTools.I18N.Services.SingleHtmlLocalizer Localizer
  2. Utilice los recursos como se muestra a continuación:
    <strong>@Localizer["Support"]:</strong> <a href="mailto:Support@example.com">Support@example.com</a>

En los modelos utilice los atributos del namespace System.ComponentModel.DataAnnotations, como se muestra a continuación:

using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations;

namespace JCTools.I18N.Test.ViewModels
{
    public class ContactViewModel
    {
        [Display(Name = "ContactViewModel_Email", ResourceType = typeof(Resources.I18N))]
        [EmailAddress(ErrorMessageResourceName = "ContactViewModel_EmailError", ErrorMessageResourceType = typeof(Resources.I18N))]
        public string Email { get; set; }
        [Display(Name = "ContactViewModel_Message", ResourceType = typeof(Resources.I18N))]
        public string Message { get; set; }
    }
}

Lo anterior permitirá que se puedan generar páginas traducidas a múltiples idiomas:

En ingles:

En español:

Por último les dejo el codigo fuente en GitHub.

Jean Carlo

Entusiasta de la programacion, freelance intermitente, lector asiduo, cinefilo, y recientemente editor en esta pagina.

0 comentarios

Agregar un comentario

;