Implementación de Localización en Blazor WebAssembly

Aquí tienes un artículo completo que explica cómo implementar localización en una aplicación Blazor WebAssembly, con ejemplos de código y una explicación detallada de cada parte.


La localización permite a las aplicaciones mostrar contenido en diferentes idiomas, dependiendo de la preferencia del usuario. En una aplicación Blazor WebAssembly, implementar localización implica cargar archivos de recursos de idioma y acceder a ellos dinámicamente. En este artículo, te mostraré cómo configurar y utilizar la localización en Blazor, con ejemplos paso a paso.

1. Crear Archivos de Recursos de Idioma

El primer paso para implementar la localización es definir archivos JSON que contengan las traducciones. Estos archivos deben estar organizados por idioma. Cada archivo contiene pares clave-valor, donde la clave es un identificador único y el valor es la traducción.

Estructura de Archivos JSON

En la carpeta wwwroot/locales, crearemos archivos para cada idioma. Por ejemplo:

  • es.json (para español)
  • en.json (para inglés)

Archivo es.json (español):

{
    "RegisterTitle": "Registro de Usuario",
    "UsernameLabel": "Nombre de Usuario",
    "EmailLabel": "Correo Electrónico",
    "PasswordLabel": "Contraseña",
    "RegisterButton": "Registrarse",
    "AlreadyHaveAccountMessage": "¿Ya tienes una cuenta?",
    "LoginLinkText": "Iniciar Sesión",
    "RegisterErrorMessage": "Error al registrarse, inténtalo de nuevo.",
    "LoadingMessage": "Cargando..."
}

Archivo en.json (inglés):

{
    "RegisterTitle": "User Registration",
    "UsernameLabel": "Username",
    "EmailLabel": "Email",
    "PasswordLabel": "Password",
    "RegisterButton": "Register",
    "AlreadyHaveAccountMessage": "Already have an account?",
    "LoginLinkText": "Log In",
    "RegisterErrorMessage": "Error registering, please try again.",
    "LoadingMessage": "Loading..."
}

2. Crear el Servicio de Localización

Necesitamos un servicio que se encargue de cargar el archivo JSON adecuado según el idioma seleccionado por el usuario. Este servicio se encargará de gestionar las traducciones y proporcionar los textos localizados.

Código del Servicio de Localización

using System.Text.Json;

public class LocalizationService
{
    private readonly HttpClient _httpClient;
    private Dictionary<string, string> _translations;

    public LocalizationService(HttpClient httpClient)
    {
        _httpClient = httpClient;
    }

    // Método para cargar el archivo JSON correspondiente al idioma
    public async Task LoadLocalizationAsync(string lang)
    {
        var response = await _httpClient.GetStringAsync($"locales/{lang}.json");
        _translations = JsonSerializer.Deserialize<Dictionary<string, string>>(response);
    }

    // Indexador que devuelve la traducción o la clave si no encuentra el valor
    public string this[string key]
    {
        get => _translations != null && _translations.TryGetValue(key, out var value) ? value : key;
    }
}

Explicación:

  • El método LoadLocalizationAsync carga el archivo JSON de traducción desde la carpeta locales.
  • Utilizamos Dictionary<string, string> para almacenar las claves y sus respectivas traducciones.
  • El indexador this[string key] permite acceder fácilmente a una traducción usando la clave.

3. Registrar el Servicio en Program.cs

Debemos registrar el LocalizationService como un servicio Scoped en Program.cs, lo que significa que cada sesión de usuario mantendrá su propio estado de localización.

Registro del Servicio

var builder = WebAssemblyHostBuilder.CreateDefault(args);
builder.Services.AddScoped<LocalizationService>();

4. Crear el Estado Global para Manejar el Idioma

Para manejar el idioma seleccionado por el usuario, podemos crear un servicio de estado global. Este servicio se encargará de almacenar el idioma actual y permitirá que todos los componentes accedan a él.

Código del Servicio de Estado Global

public class AppState
{
    public string Lang { get; private set; } = "es"; // Idioma por defecto

    // Método para actualizar el idioma
    public void SetLang(string lang)
    {
        Lang = lang;
        NotifyStateChanged();
    }

    // Evento para notificar a los componentes que el idioma ha cambiado
    public event Action OnChange;

    private void NotifyStateChanged() => OnChange?.Invoke();
}

Explicación:

  • La propiedad Lang almacena el idioma actual. Por defecto está en es (español).
  • SetLang actualiza el idioma y notifica a los componentes que el estado ha cambiado, lo que permite que los componentes se vuelvan a renderizar con el nuevo idioma.

Registrar el Servicio en Program.cs

También registramos el AppState en Program.cs:

builder.Services.AddScoped<AppState>();

5. Utilizar la Localización en los Componentes

Ahora podemos utilizar el servicio de localización en nuestros componentes para mostrar los textos traducidos.

Componente de Registro (Register.razor)

@page "/register"
@using AuthServices.Models
@inject NavigationManager Navigation
@inject LocalizationService Localizer
@inject AppState AppState

<div class="row justify-content-center w-100">
    <div class="col-md-8 col-lg-6 col-xxl-3">
        <div class="card mb-0">
            @if (registerError)
            {
                <div class="alert alert-warning" role="alert">
                    @Localizer["RegisterErrorMessage"]
                </div>
            }

            <div class="card-body">
                <div class="text-center">
                    <img width="150px" src="/logo.png" alt="Logo" class="logo mb-4" />
                    <h3 class="mb-4">@Localizer["RegisterTitle"]</h3>
                </div>
                <form @onsubmit="RegisterFunction">
                    <div class="mb-3">
                        <label for="username" class="form-label">@Localizer["UsernameLabel"]</label>
                        <input @bind="userCredentials.Username" type="text" id="username" class="form-control" required />
                    </div>
                    <div class="mb-3">
                        <label for="email" class="form-label">@Localizer["EmailLabel"]</label>
                        <input @bind="userCredentials.Email" type="email" id="email" class="form-control" required />
                    </div>
                    <div class="mb-3">
                        <label for="password" class="form-label">@Localizer["PasswordLabel"]</label>
                        <input @bind="userCredentials.Password" type="password" id="password" class="form-control" required />
                    </div>
                    <button type="submit" class="btn btn-primary w-100">@Localizer["RegisterButton"]</button>
                    <div class="d-flex align-items-center justify-content-center">
                        <p class="fs-4 mb-0 fw-bold">@Localizer["AlreadyHaveAccountMessage"]</p>
                        <a class="text-primary fw-bold ms-2" href="/">@Localizer["LoginLinkText"]</a>
                    </div>
                </form>
            </div>
        </div>
    </div>
</div>

@code
{
    private UserCredentials userCredentials = new();
    private bool registerError = false;

    protected override async Task OnInitializedAsync()
    {
        await Localizer.LoadLocalizationAsync(AppState.Lang);
    }

    private async void RegisterFunction()
    {
        // Lógica para registrar al usuario
    }
}

Explicación:

  • El servicio de localización Localizer está inyectado en el componente para acceder a los textos localizados.
  • Los textos como el título, etiquetas, y botones se obtienen usando claves (RegisterTitle, UsernameLabel, etc.).
  • La llamada a Localizer.LoadLocalizationAsync(AppState.Lang) asegura que las traducciones correctas estén cargadas antes de mostrar el contenido.

6. Cambio de Idioma en Tiempo Real

Puedes permitir a los usuarios cambiar el idioma en cualquier momento. Para ello, basta con llamar al método SetLang del AppState.

Ejemplo de Cambio de Idioma:

<button @onclick="ChangeLanguageToEnglish">Change to English</button>
<button @onclick="ChangeLanguageToSpanish">Cambiar a Español</button>

@code {
    private async Task ChangeLanguageToEnglish()
    {
        AppState.SetLang("en");
        await Localizer.LoadLocalizationAsync(AppState.Lang);
    }

    private async Task ChangeLanguageToSpanish()
    {
        AppState.SetLang("es");
        await Localizer.LoadLocalizationAsync(AppState.Lang);
    }
}

Explicación:

  • Cuando el usuario hace clic en uno de los botones, el idioma se actualiza y se recarga el archivo de traducción correspondiente.
  • Todos los componentes que estén suscritos al evento OnChange del AppState se volverán a renderizar automáticamente cuando el idioma cambie.

Conclusión

La localización en Blazor WebAssembly se implementa mediante la carga dinámica de archivos de traducción y el uso de un servicio que gestiona las traducciones. Con los pasos descritos en este artículo, puedes fácilmente configurar un sistema