Comparteix a través de


Globalización y localización de Blazor de ASP.NET Core

Nota

Esta no es la versión más reciente de este artículo. Para la versión actual, consulta la versión .NET 8 de este artículo.

Advertencia

Esta versión de ASP.NET Core ya no se admite. Para obtener más información, consulta la Directiva de soporte técnico de .NET y .NET Core. Para la versión actual, consulta la versión .NET 8 de este artículo.

Importante

Esta información hace referencia a un producto en versión preliminar, el cual puede sufrir importantes modificaciones antes de que se publique la versión comercial. Microsoft no proporciona ninguna garantía, expresa o implícita, con respecto a la información proporcionada aquí.

Para la versión actual, consulte la versión .NET 8 de este artículo.

En este artículo se explica cómo representar contenido globalizado y localizado a los usuarios de diferentes referencias culturales e idiomas.

Globalización y localización

Para la globalización, Blazor proporciona formato de número y fecha. Para la localización, Blazor representa el contenido mediante el sistema de recursos de .NET.

Se admite un conjunto limitado de características de localización de ASP.NET Core:

Se admite: IStringLocalizer y IStringLocalizer<T> se admiten en aplicaciones de Blazor.

No se admite: IHtmlLocalizer, IViewLocalizer y la localización de anotaciones de datos son características de ASP.NET Core MVC y no se admiten en aplicaciones de Blazor.

En este artículo se describe cómo usar las características de globalización y localización de Blazor basadas en:

  • El encabezado Accept-Language, que el explorador establece en función de las preferencias de idioma de un usuario en la configuración del explorador.
  • Una referencia cultural establecida por la aplicación que no se basa en el valor del encabezado Accept-Language. La configuración puede ser estática para todos los usuarios o dinámica en función de la lógica de la aplicación. Cuando la configuración se basa en las preferencias del usuario, esta normalmente se guarda para volver a cargarse en futuras visitas.

Para obtener información general adicional, consulte los recursos siguientes:

A menudo, los términos idioma y referencia cultural se usan indistintamente al hablar de los conceptos de globalización y localización.

En este artículo, el idioma hace referencia a las selecciones realizadas por un usuario en la configuración del explorador. Las selecciones de idioma del usuario se envían en las solicitudes del explorador en el encabezado Accept-Language. La configuración del explorador suele usar la palabra "idioma" en la interfaz de usuario.

La referencia cultural pertenece a los miembros de .NET y a la API Blazor. Por ejemplo, la solicitud de un usuario puede incluir el encabezado Accept-Language que especifica un idioma desde la perspectiva del usuario, pero la aplicación establece en última instancia la propiedad CurrentCulture ("referencia cultural") del idioma solicitado por el usuario. La API suele utilizar la palabra "referencia cultural" en los nombres de los miembros.

Las instrucciones de este artículo no cubren la configuración del atributo de lenguaje HTML de la página (<html lang="...">), que usan las herramientas de accessiblity. Puede establecer el valor estáticamente asignando un idioma al atributo lang de la etiqueta <html> o a document.documentElement.lang en JavaScript. Puede establecer dinámicamente el valor de document.documentElement.lang con JSde interoperabilidad.

Nota:

En los ejemplos de código de este artículo se adoptan tipos de referencia que admiten un valor NULL (NRT) y análisis estático de estado NULL del compilador de .NET, que se admiten en ASP.NET Core en .NET 6 o posterior. Al tener como destino ASP.NET Core 5.0 o versiones anteriores, quite la designación de tipo null (?) de los ejemplos del artículo.

Globalización

La directiva de atributo @bind aplica formatos y analiza los valores para mostrar en función del primer idioma preferido del usuario que admita la aplicación. @bind admite el parámetro @bind:culture para proporcionar un elemento System.Globalization.CultureInfo para analizar y dar formato a un valor.

Se puede acceder a la referencia cultural actual desde la propiedad System.Globalization.CultureInfo.CurrentCulture.

CultureInfo.InvariantCulture se usa para los siguientes tipos de campo (<input type="{TYPE}" />, donde el marcador de posición {TYPE} es el tipo):

  • date
  • number

Los tipos de campo anteriores:

  • Se muestran según sus reglas de formato basado en explorador correspondientes.
  • No pueden contener texto de forma libre.
  • Proporcionar características de interacción del usuario en función de la implementación del explorador.

Blazor proporciona compatibilidad integrada para representar valores en la referencia cultural actual. Por lo tanto, no se recomienda especificar una referencia cultural con @bind:culture cuando se usen los tipos de campo date y number.

Los siguientes tipos de campo tienen requisitos de formato específicos y no se admiten en Blazor, ya que no son compatibles con todos los exploradores principales:

  • datetime-local
  • month
  • week

Para obtener compatibilidad con el explorador actual de los tipos anteriores, consulta ¿Puedo usar ?

Compatibilidad con la globalización de .NET y los componentes internacionales para Unicode (ICU) (Blazor WebAssembly)

Blazor WebAssembly usa una API de globalización reducida y un conjunto de configuraciones regionales integradas de componentes internacionales para Unicode (ICU). Para obtener más información, consulta Globalización de .NET e ICU: ICU en WebAssembly.

Para cargar un archivo de datos de ICU personalizado para controlar las configuraciones regionales de la aplicación, consulta WASM Globalization Icu. Actualmente es necesario crear manualmente el archivo de datos de ICU personalizado. Las herramientas de .NET para facilitar el proceso de creación del archivo están previstas para .NET 9 en noviembre de 2024.

Blazor WebAssembly usa una API de globalización reducida y un conjunto de configuraciones regionales integradas de componentes internacionales para Unicode (ICU). Para obtener más información, consulta Globalización de .NET e ICU: ICU en WebAssembly.

La carga de un subconjunto personalizado de configuraciones regionales en una aplicación Blazor WebAssembly se admite en .NET 8 o versiones posteriores. Para obtener más información, ve a esta sección relativa a la versión 8.0 o posteriores de este artículo.

Globalización invariable

Esta sección solo se aplica a los escenarios Blazor del lado cliente.

Si la aplicación no requiere localización, configura la aplicación para que admita la referencia cultural invariable, que suele basarse en inglés de Estados Unidos (en-US). El uso de la globalización invariable reduce el tamaño de descarga de la aplicación y da como resultado un inicio de la aplicación más rápido. Establece la propiedad InvariantGlobalization en true en el archivo del proyecto de la aplicación (.csproj):

<PropertyGroup>
  <InvariantGlobalization>true</InvariantGlobalization>
</PropertyGroup>

Como alternativa, configura la globalización invariable con los enfoques siguientes:

  • En runtimeconfig.json:

    {
      "runtimeOptions": {
        "configProperties": {
          "System.Globalization.Invariant": true
        }
      }
    }
    
  • Con una variable de entorno:

    • Clave: DOTNET_SYSTEM_GLOBALIZATION_INVARIANT
    • Valor: true o 1

Para obtener más información, consulta Opciones de configuración de runtime para la globalización (documentación de .NET).

Información sobre zona horaria

Esta sección solo se aplica a los escenarios Blazor del lado cliente.

La adopción de la globalización invariable solo da como resultado el uso de nombres de zona horaria sin localizar. Para recortar el código y los datos de la zona horaria, lo que reduce el tamaño de descarga de la aplicación y da como resultado un inicio de la aplicación más rápido, aplica la propiedad MSBuild <InvariantTimezone> con un valor de true en el archivo del proyecto de la aplicación:

<PropertyGroup>
  <InvariantTimezone>true</InvariantTimezone>
</PropertyGroup>

Nota:

<BlazorEnableTimeZoneSupport> invalida una configuración <InvariantTimezone> anterior. Se recomienda quitar la configuración <BlazorEnableTimeZoneSupport>.

Se incluye un archivo de datos para que la información de zona horaria sea correcta. Si la aplicación no necesita esta característica, considera la posibilidad de deshabilitarla estableciendo la propiedad MSBuild <BlazorEnableTimeZoneSupport> en false en el archivo del proyecto de la aplicación:

<PropertyGroup>
  <BlazorEnableTimeZoneSupport>false</BlazorEnableTimeZoneSupport>
</PropertyGroup>

Componente de demostración

El componente CultureExample1 siguiente se puede usar para mostrar los conceptos de globalización y localización de Blazor que se tratan en este artículo.

CultureExample1.razor:

@page "/culture-example-1"
@using System.Globalization

<h1>Culture Example 1</h1>

<ul>
    <li><b>CurrentCulture</b>: @CultureInfo.CurrentCulture</li>
    <li><b>CurrentUICulture</b>: @CultureInfo.CurrentUICulture</li>
</ul>

<h2>Rendered values</h2>

<ul>
    <li><b>Date</b>: @dt</li>
    <li><b>Number</b>: @number.ToString("N2")</li>
</ul>

<h2><code>&lt;input&gt;</code> elements that don't set a <code>type</code></h2>

<p>
    The following <code>&lt;input&gt;</code> elements use
    <code>CultureInfo.CurrentCulture</code>.
</p>

<ul>
    <li><label><b>Date:</b> <input @bind="dt" /></label></li>
    <li><label><b>Number:</b> <input @bind="number" /></label></li>
</ul>

<h2><code>&lt;input&gt;</code> elements that set a <code>type</code></h2>

<p>
    The following <code>&lt;input&gt;</code> elements use
    <code>CultureInfo.InvariantCulture</code>.
</p>

<ul>
    <li><label><b>Date:</b> <input type="date" @bind="dt" /></label></li>
    <li><label><b>Number:</b> <input type="number" @bind="number" /></label></li>
</ul>

@code {
    private DateTime dt = DateTime.Now;
    private double number = 1999.69;
}

El formato de cadena de número (N2) del ejemplo anterior (.ToString("N2")) es un especificador de formato numérico de .NET estándar. El formato N2 es compatible con todos los tipos numéricos, incluye un separador de grupo y representa hasta dos posiciones decimales.

Opcionalmente, agrega un elemento de menú a la navegación en el componente NavMenu (NavMenu.razor) para el componente CultureExample1.

Establecimiento dinámico de la referencia cultural desde el encabezado Accept-Language

Agrega el paquete Microsoft.Extensions.Localization al proyecto.

El encabezado Accept-Language lo establece el explorador y se controla mediante las preferencias de idioma del usuario en la configuración del explorador. En la configuración del explorador, un usuario establece uno o varios idiomas preferidos en orden de preferencia. El explorador usa el orden de preferencia para establecer los valores de calidad (q, 0-1) para cada idioma del encabezado. En el ejemplo siguiente se especifica inglés de Estados Unidos, inglés y español costarriqueño con una preferencia por inglés de Estados Unidos o inglés:

Accept-Language: en-US,en; q=0.9,es-CR; q=0.8

La referencia cultural de la aplicación se establece al asociar el primer idioma solicitado que coincida con una referencia cultural admitida de la aplicación.

En el desarrollo del lado cliente, establece la propiedad BlazorWebAssemblyLoadAllGlobalizationData en true en el archivo de proyecto de la aplicación del lado cliente (.csproj):

<PropertyGroup>
  <BlazorWebAssemblyLoadAllGlobalizationData>true</BlazorWebAssemblyLoadAllGlobalizationData>
</PropertyGroup>

En el desarrollo del lado cliente, no se admite la configuración dinámica de la referencia cultural desde el encabezado Accept-Language.

Nota

Si la especificación de la aplicación requiere limitar las referencias culturales admitidas a una lista explícita, consulta la sección Establecimiento dinámico de la referencia cultural del lado cliente según las preferencias del usuario de este artículo.

Las aplicaciones se localizan utilizando Middleware de Localización. Agrega servicios de localización a la aplicación con AddLocalization.

Agrega la siguiente línea al archivo Program donde se registran los servicios:

builder.Services.AddLocalization();

En el desarrollo del lado servidor, especifique las referencias culturales admitidas de la aplicación antes de cualquier middleware que pueda comprobar la referencia cultural de la solicitud. Por lo general, coloque el middleware de localización de solicitudes inmediatamente antes de llamar a MapRazorComponents. En el ejemplo siguiente se configuran las referencia culturales admitidas para inglés de Estados Unidos y español costarriqueño:

En el desarrollo del lado servidor, especifique las referencias culturales admitidas de la aplicación inmediatamente después de agregar middleware de enrutamiento (UseRouting) a la canalización de procesamiento. En el ejemplo siguiente se configuran las referencia culturales admitidas para inglés de Estados Unidos y español costarriqueño:

app.UseRequestLocalization(new RequestLocalizationOptions()
    .AddSupportedCultures(new[] { "en-US", "es-CR" })
    .AddSupportedUICultures(new[] { "en-US", "es-CR" }));

Para obtener información sobre cómo ordenar el middleware de localización en la canalización de middleware del archivo Program, consulta Middleware de ASP.NET Core.

Usa el componente CultureExample1 que se muestra en la sección Componente de demostración para estudiar cómo funciona la globalización. Emite una solicitud con inglés de Estados Unidos (en-US). Cambia a español costarriqueño (es-CR) en la configuración de idioma del explorador. Vuelve a solicitar la página web.

Nota

Algunos exploradores te obligan a usar la configuración de idioma predeterminada tanto para las solicitudes como para la propia configuración de la interfaz de usuario del explorador. Esto puede complicar el cambio a un idioma que se entienda, ya que todas las pantallas de la interfaz de usuario de configuración pueden acabar en un idioma que no se puede leer. Un explorador como Opera es una buena opción para realizar pruebas, ya que permite establecer un idioma predeterminado para las solicitudes de páginas web, pero deje la interfaz de usuario de configuración del explorador en su idioma.

Cuando la referencia cultural es inglés de Estados Unidos (en-US), el componente representado usa el formato de fecha mes/día (6/7), el formato de 12 horas (AM/PM) y separadores de coma en números con un punto para el valor decimal (1,999.69):

  • Fecha: 6/7/2021 6:45:22 AM
  • Número: 1,999.69

Cuando la referencia cultural es español costarriqueño (es-CR), el componente representado usa el formato de fecha día/mes (7/6), el formato de 24 horas y separadores de punto en números con una coma para el valor decimal (1.999,69):

  • Fecha: 7/6/2021 6:49:38
  • Número: 1.999,69

Establecimiento estático de la referencia cultural del lado cliente

Establece la propiedad BlazorWebAssemblyLoadAllGlobalizationData en true en el archivo del proyecto de la aplicación (.csproj):

<PropertyGroup>
  <BlazorWebAssemblyLoadAllGlobalizationData>true</BlazorWebAssemblyLoadAllGlobalizationData>
</PropertyGroup>

La configuración del enlazador de lenguaje intermedio (IL) para la representación en el lado del cliente elimina la información de internacionalización excepto para las configuraciones regionales solicitadas explícitamente. Para obtener más información, consulta Configuración del enlazador de ASP.NET Core Blazor.

La referencia cultural de la aplicación se puede establecer en JavaScript cuando Blazor comienza con la opción de inicio applicationCulture de Blazor. En el ejemplo siguiente se configura la aplicación para que se inicie con la referencia cultural de inglés de Estados Unidos (en-US).

Evita el inicio automático de Blazor agregando autostart="false" a a la Blazoretiqueta <script>:

<script src="{BLAZOR SCRIPT}" autostart="false"></script>

En el ejemplo anterior, el marcador de posición {BLAZOR SCRIPT} es la ruta de acceso del script y el nombre de archivo Blazor. Para obtener la ubicación del script, consulta la estructura del proyecto ASP.NET CoreBlazor.

Agrega el siguiente bloque <script> después de la etiqueta <script> de Blazor y antes de la etiqueta de cierre </body>:

Blazor Web App:

<script>
  Blazor.start({
    webAssembly: {
      applicationCulture: 'en-US'
    }
  });
</script>

Blazor WebAssembly independiente:

<script>
  Blazor.start({
    applicationCulture: 'en-US'
  });
</script>

El valor de applicationCulture debe ajustarse al formato de etiqueta de idioma BCP-47. Para obtener más información sobre el inicio de Blazor, consulta Inicio de Blazor en ASP.NET Core.

Una alternativa a establecer la opción de inicio Blazor de la referencia cultural es definir la referencia cultural en código de C#. Establece CultureInfo.DefaultThreadCurrentCulture y CultureInfo.DefaultThreadCurrentUICulture en el archivo Program en la misma referencia cultural.

Agrega el espacio de nombres System.Globalization al archivo Program :

using System.Globalization;

Agrega la configuración de la referencia cultural antes de la línea que compila y ejecuta WebAssemblyHostBuilder (await builder.Build().RunAsync();):

CultureInfo.DefaultThreadCurrentCulture = new CultureInfo("en-US");
CultureInfo.DefaultThreadCurrentUICulture = new CultureInfo("en-US");

Nota:

Actualmente las aplicaciones de Blazor WebAssembly solo cargan recursos basados en DefaultThreadCurrentCulture. Para obtener más información, consulta Blazor WASM solo se basa en la referencia cultural actual (no se respeta la referencia cultural actual de la interfaz de usuario) (dotnet/aspnetcore #56824).

Usa el componente CultureExample1 que se muestra en la sección Componente de demostración para estudiar cómo funciona la globalización. Emite una solicitud con inglés de Estados Unidos (en-US). Cambia a español costarriqueño (es-CR) en la configuración de idioma del explorador. Vuelve a solicitar la página web. Cuando el idioma solicitado es Español costarriqueño, la referencia cultural de la aplicación se mantiene como inglés de Estados Unidos (en-US).

Establecimiento estático de la referencia cultural del lado servidor

Las aplicaciones del lado servidor se localizan mediante un middleware de localización. Agrega servicios de localización a la aplicación con AddLocalization.

En el archivo Program:

builder.Services.AddLocalization();

Especifique la referencia cultural estática en el Program archivo antes de cualquier middleware que pueda comprobar la referencia cultural de la solicitud. Por lo general, coloque el middleware de localización de solicitudes inmediatamente antes de MapRazorComponents. En el ejemplo siguiente se configura inglés de Estados Unidos:

Especifique la referencia cultural estática en el Program archivo inmediatamente después de agregar middleware de enrutamiento (UseRouting) a la canalización de procesamiento. En el ejemplo siguiente se configura inglés de Estados Unidos:

app.UseRequestLocalization("en-US");

El valor de la referencia cultural de UseRequestLocalization debe ajustarse al formato de etiqueta de idioma BCP-47.

Para obtener información sobre cómo ordenar el middleware de localización en la canalización de middleware del archivo Program, consulta Middleware de ASP.NET Core.

Las aplicaciones del lado servidor se localizan mediante un middleware de localización. Agrega servicios de localización a la aplicación con AddLocalization.

En Startup.ConfigureServices (Startup.cs):

services.AddLocalization();

Especifica la referencia cultural estática en Startup.Configure (Startup.cs) inmediatamente después de agregar el middleware de enrutamiento a la canalización de procesamiento. En el ejemplo siguiente se configura inglés de Estados Unidos:

app.UseRequestLocalization("en-US");

El valor de la referencia cultural de UseRequestLocalization debe ajustarse al formato de etiqueta de idioma BCP-47.

Para obtener información sobre cómo ordenar el middleware de localización en la canalización de middleware de Startup.Configure, consulta Middleware de ASP.NET Core.

Usa el componente CultureExample1 que se muestra en la sección Componente de demostración para estudiar cómo funciona la globalización. Emite una solicitud con inglés de Estados Unidos (en-US). Cambia a español costarriqueño (es-CR) en la configuración de idioma del explorador. Vuelve a solicitar la página web. Cuando el idioma solicitado es Español costarriqueño, la referencia cultural de la aplicación se mantiene como inglés de Estados Unidos (en-US).

Establecimiento dinámico de la referencia cultural del lado cliente según las preferencias del usuario

Entre los ejemplos de ubicaciones en las que una aplicación podría almacenar las preferencias de un usuario se incluyen el almacenamiento local del explorador (común en escenarios del lado cliente), en una localización cookie o base de datos (común en escenarios del lado servidor) o en un servicio externo asociado a una base de datos externa y al que tiene acceso una API web. En el ejemplo siguiente se muestra cómo usar el almacenamiento local del explorador.

Agrega el paquete Microsoft.Extensions.Localization al proyecto:

Nota

Para obtener instrucciones sobre cómo agregar paquetes a aplicaciones .NET, consulta los artículos de Instalación y administración de paquetes en Flujo de trabajo de consumo de paquetes (documentación de NuGet). Confirma las versiones correctas del paquete en NuGet.org.

Establece la propiedad BlazorWebAssemblyLoadAllGlobalizationData en true en el archivo del proyecto:

<PropertyGroup>
  <BlazorWebAssemblyLoadAllGlobalizationData>true</BlazorWebAssemblyLoadAllGlobalizationData>
</PropertyGroup>

La referencia cultural de la aplicación para la representación del lado cliente (CSR) se establece mediante la API del marco Blazor. La selección de la referencia cultural de un usuario se puede conservar en el almacenamiento local del explorador.

Proporciona funciones de JS después de la etiqueta Blazor de <script> para obtener y establecer la selección de la referencia cultural del usuario con el almacenamiento local del explorador:

<script>
  window.blazorCulture = {
    get: () => window.localStorage['BlazorCulture'],
    set: (value) => window.localStorage['BlazorCulture'] = value
  };
</script>

Nota:

En el ejemplo anterior se contamina el cliente con funciones globales. Para obtener un mejor enfoque en las aplicaciones de producción, consulta Aislamiento de JavaScript en módulos de JavaScript.

Agrega los espacios de nombres para System.Globalization y Microsoft.JSInterop al principio del archivo Program:

using System.Globalization;
using Microsoft.JSInterop;

Quita las siguientes líneas:

- await builder.Build().RunAsync();

Reemplaza la línea anterior por el código siguiente. El código agrega el servicio de localización de Blazor a la colección de servicios de la aplicación con AddLocalization y usa la interoperabilidad de JS para llamar a JS y recuperar la selección de referencia cultural del usuario del almacenamiento local. Si el almacenamiento local no contiene ninguna referencia cultural para el usuario, el código establece un valor predeterminado de inglés de Estados Unidos (en-US).

builder.Services.AddLocalization();

var host = builder.Build();

const string defaultCulture = "en-US";

var js = host.Services.GetRequiredService<IJSRuntime>();
var result = await js.InvokeAsync<string>("blazorCulture.get");
var culture = CultureInfo.GetCultureInfo(result ?? defaultCulture);

if (result == null)
{
    await js.InvokeVoidAsync("blazorCulture.set", defaultCulture);
}

CultureInfo.DefaultThreadCurrentCulture = culture;
CultureInfo.DefaultThreadCurrentUICulture = culture;

await host.RunAsync();

Nota:

Actualmente las aplicaciones de Blazor WebAssembly solo cargan recursos basados en DefaultThreadCurrentCulture. Para obtener más información, consulta Blazor WASM solo se basa en la referencia cultural actual (no se respeta la referencia cultural actual de la interfaz de usuario) (dotnet/aspnetcore #56824).

El componente CultureSelector siguiente muestra cómo realizar las siguientes acciones:

  • Establece la selección de la referencia cultural del usuario en el almacenamiento local del explorador a través de la interoperabilidad de JS.
  • Vuelve a cargar el componente que solicitaste (forceLoad: true), que usa la referencia cultural actualizada.

CultureSelector.razor:

@using System.Globalization
@inject IJSRuntime JS
@inject NavigationManager Navigation

<p>
    <label>
        Select your locale:
        <select @bind="selectedCulture" @bind:after="ApplySelectedCultureAsync">
            @foreach (var culture in supportedCultures)
            {
                <option value="@culture">@culture.DisplayName</option>
            }
        </select>
    </label>
</p>

@code
{
    private CultureInfo[] supportedCultures = new[]
    {
        new CultureInfo("en-US"),
        new CultureInfo("es-CR"),
    };

    private CultureInfo? selectedCulture;

    protected override void OnInitialized()
    {
        selectedCulture = CultureInfo.CurrentCulture;
    }

    private async Task ApplySelectedCultureAsync()
    {
        if (CultureInfo.CurrentCulture != selectedCulture)
        {
            await JS.InvokeVoidAsync("blazorCulture.set", selectedCulture!.Name);

            Navigation.NavigateTo(Navigation.Uri, forceLoad: true);
        }
    }
}
@using System.Globalization
@inject IJSRuntime JS
@inject NavigationManager Navigation

<p>
    <label>
        Select your locale:
        <select value="@selectedCulture" @onchange="HandleSelectedCultureChanged">
            @foreach (var culture in supportedCultures)
            {
                <option value="@culture">@culture.DisplayName</option>
            }
        </select>
    </label>
</p>

@code
{
    private CultureInfo[] supportedCultures = new[]
    {
        new CultureInfo("en-US"),
        new CultureInfo("es-CR"),
    };

    private CultureInfo? selectedCulture;

    protected override void OnInitialized()
    {
        selectedCulture = CultureInfo.CurrentCulture;
    }

    private async Task HandleSelectedCultureChanged(ChangeEventArgs args)
    {
        selectedCulture = CultureInfo.GetCultureInfo((string)args.Value!);

        if (CultureInfo.CurrentCulture != selectedCulture)
        {
            await JS.InvokeVoidAsync("blazorCulture.set", selectedCulture!.Name);

            Navigation.NavigateTo(Navigation.Uri, forceLoad: true);
        }
    }
}

Dentro de la etiqueta de cierre del elemento </main> del componente MainLayout (MainLayout.razor), agrega el componente CultureSelector:

<article class="bottom-row px-4">
    <CultureSelector />
</article>

Usa el componente CultureExample1 que se muestra en la sección Componente de demostración para estudiar cómo funciona el ejemplo anterior.

Establecimiento dinámico de la referencia cultural del lado servidor según las preferencias del usuario

Entre los ejemplos de ubicaciones en las que una aplicación podría almacenar las preferencias de un usuario se incluyen el almacenamiento local del explorador (común en escenarios del lado cliente), en una localización cookie o base de datos (común en escenarios del lado servidor) o en un servicio externo asociado a una base de datos externa y al que tiene acceso una API web. En el siguiente ejemplo se muestra cómo usar una cookie de localización.

Nota:

En el ejemplo siguiente se supone que la aplicación adopta la interactividad global especificando la representación interactiva del lado del servidor en el componente Routes del componente App (Components/App.razor):

<Routes @rendermode="InteractiveServer" />

Si la aplicación adopta la interactividad por página o componente, consulta los comentarios al final de esta sección para modificar los modos de representación de los componentes del ejemplo.

Agrega el paquete Microsoft.Extensions.Localization al proyecto.

Nota

Para obtener instrucciones sobre cómo agregar paquetes a aplicaciones .NET, consulta los artículos de Instalación y administración de paquetes en Flujo de trabajo de consumo de paquetes (documentación de NuGet). Confirma las versiones correctas del paquete en NuGet.org.

Las aplicaciones del lado servidor se localizan mediante un middleware de localización. Agrega servicios de localización a la aplicación con AddLocalization.

En el archivo Program:

builder.Services.AddLocalization();

Establece las referencia culturales predeterminadas y admitidas de la aplicación con RequestLocalizationOptions.

Antes de llamar a MapRazorComponents en la canalización de procesamiento de solicitudes, coloca el código siguiente:

Después de agregar middleware de enrutamiento (UseRouting) a la canalización de procesamiento de solicitudes, coloque el código siguiente:

var supportedCultures = new[] { "en-US", "es-CR" };
var localizationOptions = new RequestLocalizationOptions()
    .SetDefaultCulture(supportedCultures[0])
    .AddSupportedCultures(supportedCultures)
    .AddSupportedUICultures(supportedCultures);

app.UseRequestLocalization(localizationOptions);

Para obtener información sobre cómo ordenar el middleware de localización en la canalización de middleware, consulta Middleware de ASP.NET Core.

En el siguiente ejemplo se muestra cómo establecer la referencia cultural actual en una cookie que el middleware de localización puede leer.

Los siguientes espacios de nombres son necesarios para el componente App:

Agrega lo siguiente a la parte superior del archivo de componente de App (Components/App.razor):

@using System.Globalization
@using Microsoft.AspNetCore.Localization

Agrega el siguiente bloque @code a la parte inferior del archivo de componente App:

@code {
    [CascadingParameter]
    public HttpContext? HttpContext { get; set; }

    protected override void OnInitialized()
    {
        HttpContext?.Response.Cookies.Append(
            CookieRequestCultureProvider.DefaultCookieName,
            CookieRequestCultureProvider.MakeCookieValue(
                new RequestCulture(
                    CultureInfo.CurrentCulture,
                    CultureInfo.CurrentUICulture)));
    }
}

Las modificaciones en el archivo Pages/_Host.cshtml requieren los siguientes espacios de nombres:

Agrega el siguiente código al archivo:

@using System.Globalization
@using Microsoft.AspNetCore.Localization
@{
    this.HttpContext.Response.Cookies.Append(
        CookieRequestCultureProvider.DefaultCookieName,
        CookieRequestCultureProvider.MakeCookieValue(
            new RequestCulture(
                CultureInfo.CurrentCulture,
                CultureInfo.CurrentUICulture)));
}

Para obtener información sobre cómo ordenar el middleware de localización en la canalización de middleware, consulta Middleware de ASP.NET Core.

Si la aplicación no está configurada para procesar acciones del controlador:

  • Agrega servicios de MVC mediante una llamada a AddControllers en la colección de servicios en el archivo Program:

    builder.Services.AddControllers();
    
  • Agrega el enrutamiento del punto de conexión del controlador en el archivo de Program llamando a MapControllers en el IEndpointRouteBuilder (app):

    app.MapControllers();
    

Para especificar una interfaz de usuario que permita a un usuario seleccionar una referencia cultural, usa un método basado en el redireccionamiento con una cookie de localización. La aplicación conserva la referencia cultural seleccionada por el usuario a través de un redireccionamiento a un controlador. Este controlador establece la referencia cultural seleccionada del usuario en una cookie y redirige al usuario de nuevo al URI original. El proceso es similar a lo que ocurre en una aplicación web cuando un usuario intenta acceder a un recurso seguro, donde se redirige al usuario a una página de inicio de sesión y, después, se le redirige nuevamente de vuelta al recurso original.

Controllers/CultureController.cs:

using Microsoft.AspNetCore.Localization;
using Microsoft.AspNetCore.Mvc;

[Route("[controller]/[action]")]
public class CultureController : Controller
{
    public IActionResult Set(string culture, string redirectUri)
    {
        if (culture != null)
        {
            HttpContext.Response.Cookies.Append(
                CookieRequestCultureProvider.DefaultCookieName,
                CookieRequestCultureProvider.MakeCookieValue(
                    new RequestCulture(culture, culture)));
        }

        return LocalRedirect(redirectUri);
    }
}

Advertencia

Usa el resultado de la acción LocalRedirect, como se muestra en el ejemplo anterior, para evitar ataques de redirección abiertos. Para obtener más información, consulta Prevención de ataques de redireccionamiento abierto en ASP.NET Core.

El componente CultureSelector siguiente muestra cómo llamar al método Set con la nueva referencia cultural CultureController. El componente se coloca en la carpeta Shared para su uso en toda la aplicación.

CultureSelector.razor:

@using System.Globalization
@inject IJSRuntime JS
@inject NavigationManager Navigation

<p>
    <label>
        Select your locale:
        <select @bind="selectedCulture" @bind:after="ApplySelectedCultureAsync">
            @foreach (var culture in supportedCultures)
            {
                <option value="@culture">@culture.DisplayName</option>
            }
        </select>
    </label>
</p>

@code
{
    private CultureInfo[] supportedCultures = new[]
    {
        new CultureInfo("en-US"),
        new CultureInfo("es-CR"),
    };

    private CultureInfo? selectedCulture;

    protected override void OnInitialized()
    {
        selectedCulture = CultureInfo.CurrentCulture;
    }

    private async Task ApplySelectedCultureAsync()
    {
        if (CultureInfo.CurrentCulture != selectedCulture)
        {
            var uri = new Uri(Navigation.Uri)
                .GetComponents(UriComponents.PathAndQuery, UriFormat.Unescaped);
            var cultureEscaped = Uri.EscapeDataString(selectedCulture.Name);
            var uriEscaped = Uri.EscapeDataString(uri);

            Navigation.NavigateTo(
                $"Culture/Set?culture={cultureEscaped}&redirectUri={uriEscaped}",
                forceLoad: true);
        }
    }
}
@using System.Globalization
@inject IJSRuntime JS
@inject NavigationManager Navigation

<p>
    <label>
        Select your locale:
        <select value="@selectedCulture" @onchange="HandleSelectedCultureChanged">
            @foreach (var culture in supportedCultures)
            {
                <option value="@culture">@culture.DisplayName</option>
            }
        </select>
    </label>
</p>

@code
{
    private CultureInfo[] supportedCultures = new[]
    {
        new CultureInfo("en-US"),
        new CultureInfo("es-CR"),
    };

    private CultureInfo? selectedCulture;

    protected override void OnInitialized()
    {
        selectedCulture = CultureInfo.CurrentCulture;
    }

    private async Task HandleSelectedCultureChanged(ChangeEventArgs args)
    {
        selectedCulture = CultureInfo.GetCultureInfo((string)args.Value!);

        if (CultureInfo.CurrentCulture != selectedCulture)
        {
            var uri = new Uri(Navigation.Uri)
                .GetComponents(UriComponents.PathAndQuery, UriFormat.Unescaped);
            var cultureEscaped = Uri.EscapeDataString(selectedCulture.Name);
            var uriEscaped = Uri.EscapeDataString(uri);

            Navigation.NavigateTo(
                $"Culture/Set?culture={cultureEscaped}&redirectUri={uriEscaped}",
                forceLoad: true);
        }
    }
}

Agrega el componente CultureSelector al componente MainLayout. Coloca el siguiente marcado dentro de la etiqueta de cierre </main> en el archivo Components/Layout/MainLayout.razor:

Agrega el componente CultureSelector al componente MainLayout. Coloca el siguiente marcado dentro de la etiqueta de cierre </main> en el archivo Shared/MainLayout.razor:

<article class="bottom-row px-4">
    <CultureSelector />
</article>

Usa el componente CultureExample1 que se muestra en la sección Componente de demostración para estudiar cómo funciona el ejemplo anterior.

En el ejemplo anterior se supone que la aplicación adopta la interactividad global especificando el modo de representación del Servidor interactivo en el componente Routes del componente App (Components/App.razor):

<Routes @rendermode="InteractiveServer" />

Si la aplicación adopta la interactividad por página o componente, realice los cambios siguientes:

  • Agrega el modo de representación interactiva del lado del servidor en la parte superior del archivo de componente de CultureExample1 (Components/Pages/CultureExample1.razor):

    @rendermode InteractiveServer
    
  • En el diseño principal de la aplicación (Components/Layout/MainLayout.razor), aplica el modo de representación interactiva del lado del servidor al componente CultureSelector:

    <CultureSelector @rendermode="InteractiveServer" />
    

Establecimiento dinámico de la referencia cultural en una Blazor Web App por preferencia de usuario

Esta sección se aplica a Blazor Web App que adoptan la interactividad automática (servidor y WebAssembly).

Entre los ejemplos de ubicaciones en las que una aplicación puede almacenar las preferencias de un usuario se incluyen el almacenamiento local del navegador (habitual en escenarios del lado cliente), en un objeto cookie de localización o base de datos (habitual en escenarios del lado servidor), tanto el almacenamiento local como un objeto cookie de localización (Blazor Web App con componentes de servidor y WebAssembly), o en un servicio externo conectado a una base de datos externa y al que se accede mediante una API web. En el siguiente ejemplo se muestra cómo usar el almacenamiento local del explorador para los componentes representados en el lado cliente (CSR) y un cookie de localización para los componentes representados en el lado servidor (SSR).

Actualizaciones del proyecto de .Client

Agrega el paquete Microsoft.Extensions.Localization al proyecto de .Client.

Nota:

Para obtener instrucciones sobre cómo agregar paquetes a aplicaciones .NET, consulta los artículos de Instalación y administración de paquetes en Flujo de trabajo de consumo de paquetes (documentación de NuGet). Confirma las versiones correctas del paquete en NuGet.org.

Establece la propiedad BlazorWebAssemblyLoadAllGlobalizationData en true en el archivo de proyecto de .Client:

<PropertyGroup>
  <BlazorWebAssemblyLoadAllGlobalizationData>true</BlazorWebAssemblyLoadAllGlobalizationData>
</PropertyGroup>

Agrega los espacios de nombres para System.Globalization y Microsoft.JSInterop a la parte superior del archivo Program del proyecto de .Client:

using System.Globalization;
using Microsoft.JSInterop;

Quita las siguientes líneas:

- await builder.Build().RunAsync();

Reemplaza la línea anterior por el código siguiente. El código agrega el servicio de localización de Blazor a la colección de servicios de la aplicación con AddLocalization y usa la interoperabilidad de JS para llamar a JS y recuperar la selección de referencia cultural del usuario del almacenamiento local. Si el almacenamiento local no contiene ninguna referencia cultural para el usuario, el código establece un valor predeterminado de inglés de Estados Unidos (en-US).

builder.Services.AddLocalization();

var host = builder.Build();

const string defaultCulture = "en-US";

var js = host.Services.GetRequiredService<IJSRuntime>();
var result = await js.InvokeAsync<string>("blazorCulture.get");
var culture = CultureInfo.GetCultureInfo(result ?? defaultCulture);

if (result == null)
{
    await js.InvokeVoidAsync("blazorCulture.set", defaultCulture);
}

CultureInfo.DefaultThreadCurrentCulture = culture;
CultureInfo.DefaultThreadCurrentUICulture = culture;

await host.RunAsync();

Nota:

Actualmente las aplicaciones de Blazor WebAssembly solo cargan recursos basados en DefaultThreadCurrentCulture. Para obtener más información, consulta Blazor WASM solo se basa en la referencia cultural actual (no se respeta la referencia cultural actual de la interfaz de usuario) (dotnet/aspnetcore #56824).

Agrega el siguiente componente CultureSelector al proyecto de .Client.

El componente adopta los siguientes enfoques para trabajar con componentes de SSR o CSR:

  • Un diccionario proporciona el nombre para mostrar de cada referencia cultural disponible en la lista desplegable, ya que los datos de globalización del lado cliente incluyen texto localizado de la referencia cultural que proporcionan los datos de globalización del lado servidor. Por ejemplo, la localización del lado servidor muestra English (United States) cuando en-US es la referencia cultural y Ingles () cuando se usa una referencia cultural diferente. Dado que la localización de los nombres para mostrar de la referencia cultural no está disponible con globalización Blazor WebAssembly, el nombre para mostrar del inglés de Estados Unidos en el cliente para cualquier referencia cultural cargada es simplemente en-US. El uso de un diccionario personalizado permite que el componente muestre al menos nombres de referencia cultural en inglés completos.
  • Cuando el usuario cambia la referencia cultural, la interoperabilidad JS establece la referencia cultural en el almacenamiento del explorador local y una acción del controlador actualiza la localización de cookie con la referencia cultural. El controlador se añade a la aplicación más adelante, en la sección Actualizaciones del proyecto de servidor.

Pages/CultureSelector.razor:

@using System.Globalization
@inject IJSRuntime JS
@inject NavigationManager Navigation

<p>
    <label>
        Select your locale:
        <select @bind="@selectedCulture" @bind:after="ApplySelectedCultureAsync">
            @foreach (var culture in supportedCultures)
            {
                <option value="@culture">@cultureDict[culture.Name]</option>
            }
        </select>
    </label>
</p>

@code
{
    private Dictionary<string, string> cultureDict = 
        new()
        {
            { "en-US", "English (United States)" },
            { "es-CR", "Spanish (Costa Rica)" }
        };

    private CultureInfo[] supportedCultures = new[]
    {
        new CultureInfo("en-US"),
        new CultureInfo("es-CR"),
    };

    private CultureInfo? selectedCulture;

    protected override void OnInitialized()
    {
        selectedCulture = CultureInfo.CurrentCulture;
    }

    private async Task ApplySelectedCultureAsync()
    {
        if (CultureInfo.CurrentCulture != selectedCulture)
        {
            await JS.InvokeVoidAsync("blazorCulture.set", selectedCulture!.Name);

            var uri = new Uri(Navigation.Uri)
                .GetComponents(UriComponents.PathAndQuery, UriFormat.Unescaped);
            var cultureEscaped = Uri.EscapeDataString(selectedCulture.Name);
            var uriEscaped = Uri.EscapeDataString(uri);

            Navigation.NavigateTo(
                $"Culture/Set?culture={cultureEscaped}&redirectUri={uriEscaped}",
                forceLoad: true);
        }
    }
}

En el proyecto .Client, coloca el siguiente componente de CultureClient para estudiar cómo funciona la globalización para los componentes de CSR.

Pages/CultureClient.razor:

@page "/culture-client"
@rendermode InteractiveWebAssembly
@using System.Globalization

<PageTitle>Culture Client</PageTitle>

<h1>Culture Client</h1>

<ul>
    <li><b>CurrentCulture</b>: @CultureInfo.CurrentCulture</li>
    <li><b>CurrentUICulture</b>: @CultureInfo.CurrentUICulture</li>
</ul>

<h2>Rendered values</h2>

<ul>
    <li><b>Date</b>: @dt</li>
    <li><b>Number</b>: @number.ToString("N2")</li>
</ul>

<h2><code>&lt;input&gt;</code> elements that don't set a <code>type</code></h2>

<p>
    The following <code>&lt;input&gt;</code> elements use
    <code>CultureInfo.CurrentCulture</code>.
</p>

<ul>
    <li><label><b>Date:</b> <input @bind="dt" /></label></li>
    <li><label><b>Number:</b> <input @bind="number" /></label></li>
</ul>

<h2><code>&lt;input&gt;</code> elements that set a <code>type</code></h2>

<p>
    The following <code>&lt;input&gt;</code> elements use
    <code>CultureInfo.InvariantCulture</code>.
</p>

<ul>
    <li><label><b>Date:</b> <input type="date" @bind="dt" /></label></li>
    <li><label><b>Number:</b> <input type="number" @bind="number" /></label></li>
</ul>

@code {
    private DateTime dt = DateTime.Now;
    private double number = 1999.69;
}

Actualizaciones del proyecto de servidor

Agrega el paquete Microsoft.Extensions.Localization al proyecto de servidor.

Nota:

Para obtener instrucciones sobre cómo agregar paquetes a aplicaciones .NET, consulta los artículos de Instalación y administración de paquetes en Flujo de trabajo de consumo de paquetes (documentación de NuGet). Confirma las versiones correctas del paquete en NuGet.org.

Las aplicaciones del lado servidor se localizan mediante un middleware de localización. Agrega servicios de localización a la aplicación con AddLocalization.

En el archivo Program del proyecto de servidor donde se registran los servicios:

builder.Services.AddLocalization();

Establece las referencia culturales predeterminadas y admitidas de la aplicación con RequestLocalizationOptions.

Antes de llamar a MapRazorComponents en la canalización de procesamiento de solicitudes, coloca el código siguiente:

var supportedCultures = new[] { "en-US", "es-CR" };
var localizationOptions = new RequestLocalizationOptions()
    .SetDefaultCulture(supportedCultures[0])
    .AddSupportedCultures(supportedCultures)
    .AddSupportedUICultures(supportedCultures);

app.UseRequestLocalization(localizationOptions);

En el siguiente ejemplo se muestra cómo establecer la referencia cultural actual en una cookie que el middleware de localización puede leer.

Los siguientes espacios de nombres son necesarios para el componente App:

Agrega lo siguiente a la parte superior del archivo de componente de App (Components/App.razor):

@using System.Globalization
@using Microsoft.AspNetCore.Localization

La referencia cultural de la aplicación para la representación del lado cliente (CSR) se establece mediante la API del marco Blazor. La selección de referencia cultural de un usuario se puede conservar en el almacenamiento local del explorador para los componentes de CSR.

Después de la etiqueta <script> de Blazor, proporciona funciones JS para obtener y establecer la selección de referencia cultural del usuario con el almacenamiento local del explorador:

<script>
  window.blazorCulture = {
    get: () => window.localStorage['BlazorCulture'],
    set: (value) => window.localStorage['BlazorCulture'] = value
  };
</script>

Nota:

En el ejemplo anterior se contamina el cliente con funciones globales. Para obtener un mejor enfoque en las aplicaciones de producción, consulta Aislamiento de JavaScript en módulos de JavaScript.

Agrega el siguiente bloque @code a la parte inferior del archivo de componente de App :

@code {
    [CascadingParameter]
    public HttpContext? HttpContext { get; set; }

    protected override void OnInitialized()
    {
        HttpContext?.Response.Cookies.Append(
            CookieRequestCultureProvider.DefaultCookieName,
            CookieRequestCultureProvider.MakeCookieValue(
                new RequestCulture(
                    CultureInfo.CurrentCulture,
                    CultureInfo.CurrentUICulture)));
    }
}

Si el proyecto de servidor no está configurado para procesar las acciones del controlador:

  • Agrega servicios de MVC mediante una llamada a AddControllers en la colección de servicios en el archivo Program:

    builder.Services.AddControllers();
    
  • Agrega el enrutamiento del punto de conexión del controlador en el archivo de Program llamando a MapControllers en el IEndpointRouteBuilder (app):

    app.MapControllers();
    

Para permitir que un usuario seleccione una referencia cultural para los componentes de SSR, usa un enfoque basado en redireccionamiento con un cookie de localización. La aplicación conserva la referencia cultural seleccionada por el usuario a través de un redireccionamiento a un controlador. Este controlador establece la referencia cultural seleccionada del usuario en una cookie y redirige al usuario de nuevo al URI original. El proceso es similar a lo que ocurre en una aplicación web cuando un usuario intenta acceder a un recurso seguro, donde se redirige al usuario a una página de inicio de sesión y, después, se le redirige nuevamente de vuelta al recurso original.

Controllers/CultureController.cs:

using Microsoft.AspNetCore.Localization;
using Microsoft.AspNetCore.Mvc;

[Route("[controller]/[action]")]
public class CultureController : Controller
{
    public IActionResult Set(string culture, string redirectUri)
    {
        if (culture != null)
        {
            HttpContext.Response.Cookies.Append(
                CookieRequestCultureProvider.DefaultCookieName,
                CookieRequestCultureProvider.MakeCookieValue(
                    new RequestCulture(culture, culture)));
        }

        return LocalRedirect(redirectUri);
    }
}

Advertencia

Usa el resultado de la acción LocalRedirect, como se muestra en el ejemplo anterior, para evitar ataques de redirección abiertos. Para obtener más información, consulta Prevención de ataques de redireccionamiento abierto en ASP.NET Core.

Agrega el componente CultureSelector al componente MainLayout. Coloca el siguiente marcado dentro de la etiqueta de cierre </main> en el archivo Components/Layout/MainLayout.razor:

<article class="bottom-row px-4">
    <CultureSelector @rendermode="InteractiveAuto" />
</article>

Usa el componente CultureExample1 que se muestra en la sección Componente de demostración para estudiar cómo funciona el ejemplo anterior.

En el proyecto de servidor, coloca el siguiente componente de CultureServer para estudiar cómo funciona la globalización para los componentes de SSR.

Components/Pages/CultureServer.razor:

@page "/culture-server"
@rendermode InteractiveServer
@using System.Globalization

<PageTitle>Culture Server</PageTitle>

<h1>Culture Server</h1>

<ul>
    <li><b>CurrentCulture</b>: @CultureInfo.CurrentCulture</li>
    <li><b>CurrentUICulture</b>: @CultureInfo.CurrentUICulture</li>
</ul>

<h2>Rendered values</h2>

<ul>
    <li><b>Date</b>: @dt</li>
    <li><b>Number</b>: @number.ToString("N2")</li>
</ul>

<h2><code>&lt;input&gt;</code> elements that don't set a <code>type</code></h2>

<p>
    The following <code>&lt;input&gt;</code> elements use
    <code>CultureInfo.CurrentCulture</code>.
</p>

<ul>
    <li><label><b>Date:</b> <input @bind="dt" /></label></li>
    <li><label><b>Number:</b> <input @bind="number" /></label></li>
</ul>

<h2><code>&lt;input&gt;</code> elements that set a <code>type</code></h2>

<p>
    The following <code>&lt;input&gt;</code> elements use
    <code>CultureInfo.InvariantCulture</code>.
</p>

<ul>
    <li><label><b>Date:</b> <input type="date" @bind="dt" /></label></li>
    <li><label><b>Number:</b> <input type="number" @bind="number" /></label></li>
</ul>

@code {
    private DateTime dt = DateTime.Now;
    private double number = 1999.69;
}

Agrega los componentes CultureClient y CultureServer a la navegación de la barra lateral en Components/Layout/NavMenu.razor:

<div class="nav-item px-3">
    <NavLink class="nav-link" href="culture-server">
        <span class="bi bi-list-nested-nav-menu" aria-hidden="true"></span> Culture (Server)
    </NavLink>
</div>
<div class="nav-item px-3">
    <NavLink class="nav-link" href="culture-client">
        <span class="bi bi-list-nested-nav-menu" aria-hidden="true"></span> Culture (Client)
    </NavLink>
</div>

Componentes automáticos interactivos

Las instrucciones de esta sección también funcionan para los componentes que adoptan el modo de representación automática interactiva:

@rendermode InteractiveAuto

Localización

Si la aplicación aún no admite la selección de referencia cultural dinámica, agregue el paquete Microsoft.Extensions.Localization a la aplicación.

Nota

Para obtener instrucciones sobre cómo agregar paquetes a aplicaciones .NET, consulta los artículos de Instalación y administración de paquetes en Flujo de trabajo de consumo de paquetes (documentación de NuGet). Confirma las versiones correctas del paquete en NuGet.org.

Localización del lado cliente

Establece la propiedad BlazorWebAssemblyLoadAllGlobalizationData en true en el archivo del proyecto de la aplicación (.csproj):

<PropertyGroup>
  <BlazorWebAssemblyLoadAllGlobalizationData>true</BlazorWebAssemblyLoadAllGlobalizationData>
</PropertyGroup>

En el archivo Program, agrega el espacio de nombres para System.Globalization en la parte superior del archivo:

using System.Globalization;

Agrega el servicio de localización de Blazor a la colección de servicios de la aplicación con AddLocalization:

builder.Services.AddLocalization();

Localización del lado servidor

Usa el middleware de localización para establecer la referencia cultural de la aplicación.

Si la aplicación aún no admite la selección de referencia cultural dinámica:

  • Agrega servicios de localización a la aplicación con AddLocalization.
  • Especifica las referencia culturales predeterminadas y admitidas de la aplicación en el archivo Program. En el ejemplo siguiente se configuran las referencia culturales admitidas para inglés de Estados Unidos y español costarriqueño.
builder.Services.AddLocalization();

Coloque el middleware de localización de solicitudes antes de cualquier middleware que pueda comprobar la referencia cultural de la solicitud. Por lo general, coloque el middleware inmediatamente antes de llamar a MapRazorComponents:

Inmediatamente después de agregar middleware de enrutamiento (UseRouting) a la canalización de procesamiento:

var supportedCultures = new[] { "en-US", "es-CR" };
var localizationOptions = new RequestLocalizationOptions()
    .SetDefaultCulture(supportedCultures[0])
    .AddSupportedCultures(supportedCultures)
    .AddSupportedUICultures(supportedCultures);

app.UseRequestLocalization(localizationOptions);

Para obtener información sobre cómo ordenar el middleware de localización en la canalización de middleware, consulta Middleware de ASP.NET Core.

  • Agrega servicios de localización a la aplicación con AddLocalization.
  • Especifica las referencia culturales predeterminadas y admitidas de la aplicación en Startup.Configure (Startup.cs). En el ejemplo siguiente se configuran las referencia culturales admitidas para inglés de Estados Unidos y español costarriqueño.

En Startup.ConfigureServices (Startup.cs):

services.AddLocalization();

Inmediatamente Startup.Configure después de agregar middleware de enrutamiento (UseRouting) a la canalización de procesamiento:

var supportedCultures = new[] { "en-US", "es-CR" };
var localizationOptions = new RequestLocalizationOptions()
    .SetDefaultCulture(supportedCultures[0])
    .AddSupportedCultures(supportedCultures)
    .AddSupportedUICultures(supportedCultures);

app.UseRequestLocalization(localizationOptions);

Para obtener información sobre cómo ordenar el middleware de localización en la canalización de middleware de Startup.Configure, consulta Middleware de ASP.NET Core.

Si la aplicación debe localizar los recursos en función del almacenamiento de la configuración de referencia cultural de un usuario, usa una referencia cultural de localización cookie. El uso de una cookie garantiza que la conexión WebSocket puede propagar correctamente la referencia cultural. Si los esquemas de localización se basan en la ruta de acceso URL o en la cadena de consulta, puede que el esquema no funcione con WebSockets, por lo que no se podrá conservar la referencia cultural. Por lo tanto, el enfoque recomendado es usar una cookie de referencia cultural de localización. Consulta la sección Establecimiento dinámico de la referencia cultural del lado servidor según las preferencias del usuario de este artículo para ver una expresión Razor de ejemplo que conserva la selección de referencia cultural del usuario.

Ejemplo de recursos localizados

El ejemplo de recursos localizados de esta sección funciona con los ejemplos anteriores de este artículo, donde las referencia culturales admitidas de la aplicación son inglés (en) como configuración regional predeterminada y español (es) como configuración regional alternativa que el usuario puede seleccionar o que el explorador puede especificar.

Crea un archivo de recursos para cada configuración regional. En el ejemplo siguiente, se crean recursos para una cadena Greeting en inglés y español:

  • Inglés (en): Hello, World!
  • Español (es): ¡Hola, Mundo!

Nota:

El siguiente archivo de recursos se puede agregar en Visual Studio; para ello, haz clic con el botón derecho en la carpeta Pages y selecciona Agregar>Nuevo elemento>Archivo de recursos. Asigna al archivo el nombre CultureExample2.resx. Cuando aparezca el editor, proporciona datos para una nueva entrada. Establece el Nombre en Greeting y el Valor en Hello, World!. Guarda el archivo.

Si usas Visual Studio Code, se recomienda instalar el Visor y editor ResX de Tim Heuer. Agrega un archivo CultureExample2.resx vacío a la carpeta Pages. La extensión se encarga automáticamente de administrar el archivo en la interfaz de usuario. Selecciona el botón Agregar nuevo recurso. Sigue las instrucciones a fin de agregar una entrada para Greeting (clave), Hello, World! (valor) y None (comentario). Guarda el archivo. Si cierras y vuelves a abrir el archivo, podrás ver el recurso Greeting.

El visor y editor ResX de Tim Heuer no es propiedad de Microsoft ni está cubierto por ningún contrato ni licencia de Soporte técnico de Microsoft.

A continuación se muestra un archivo de recursos típico. Puedes colocar manualmente los archivos de recursos en la carpeta Pages de la aplicación si prefieres no usar herramientas integradas con un entorno de desarrollo integrado (IDE), como el editor de archivos de recursos integrado de Visual Studio o Visual Studio Code con una extensión para crear y editar archivos de recursos.

Pages/CultureExample2.resx:

<?xml version="1.0" encoding="utf-8"?>
<root>
  <xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
    <xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
    <xsd:element name="root" msdata:IsDataSet="true">
      <xsd:complexType>
        <xsd:choice maxOccurs="unbounded">
          <xsd:element name="metadata">
            <xsd:complexType>
              <xsd:sequence>
                <xsd:element name="value" type="xsd:string" minOccurs="0" />
              </xsd:sequence>
              <xsd:attribute name="name" use="required" type="xsd:string" />
              <xsd:attribute name="type" type="xsd:string" />
              <xsd:attribute name="mimetype" type="xsd:string" />
              <xsd:attribute ref="xml:space" />
            </xsd:complexType>
          </xsd:element>
          <xsd:element name="assembly">
            <xsd:complexType>
              <xsd:attribute name="alias" type="xsd:string" />
              <xsd:attribute name="name" type="xsd:string" />
            </xsd:complexType>
          </xsd:element>
          <xsd:element name="data">
            <xsd:complexType>
              <xsd:sequence>
                <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
                <xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
              </xsd:sequence>
              <xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
              <xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
              <xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
              <xsd:attribute ref="xml:space" />
            </xsd:complexType>
          </xsd:element>
          <xsd:element name="resheader">
            <xsd:complexType>
              <xsd:sequence>
                <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
              </xsd:sequence>
              <xsd:attribute name="name" type="xsd:string" use="required" />
            </xsd:complexType>
          </xsd:element>
        </xsd:choice>
      </xsd:complexType>
    </xsd:element>
  </xsd:schema>
  <resheader name="resmimetype">
    <value>text/microsoft-resx</value>
  </resheader>
  <resheader name="version">
    <value>2.0</value>
  </resheader>
  <resheader name="reader">
    <value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
  </resheader>
  <resheader name="writer">
    <value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
  </resheader>
  <data name="Greeting" xml:space="preserve">
    <value>Hello, World!</value>
  </data>
</root>

Nota:

El siguiente archivo de recursos se puede agregar en Visual Studio; para ello, haz clic con el botón derecho en la carpeta Pages y selecciona Agregar>Nuevo elemento>Archivo de recursos. Asigna al archivo el nombre CultureExample2.es.resx. Cuando aparezca el editor, proporciona datos para una nueva entrada. Establece el Nombre en Greeting y el Valor en ¡Hola, Mundo!. Guarda el archivo.

Si usas Visual Studio Code, se recomienda instalar el Visor y editor ResX de Tim Heuer. Agrega un archivo CultureExample2.resx vacío a la carpeta Pages. La extensión se encarga automáticamente de administrar el archivo en la interfaz de usuario. Selecciona el botón Agregar nuevo recurso. Sigue las instrucciones a fin de agregar una entrada para Greeting (clave), ¡Hola, Mundo! (valor) y None (comentario). Guarda el archivo. Si cierras y vuelves a abrir el archivo, podrás ver el recurso Greeting.

A continuación se muestra un archivo de recursos típico. Puedes colocar manualmente los archivos de recursos en la carpeta Pages de la aplicación si prefieres no usar herramientas integradas con un entorno de desarrollo integrado (IDE), como el editor de archivos de recursos integrado de Visual Studio o Visual Studio Code con una extensión para crear y editar archivos de recursos.

Pages/CultureExample2.es.resx:

<?xml version="1.0" encoding="utf-8"?>
<root>
  <xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
    <xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
    <xsd:element name="root" msdata:IsDataSet="true">
      <xsd:complexType>
        <xsd:choice maxOccurs="unbounded">
          <xsd:element name="metadata">
            <xsd:complexType>
              <xsd:sequence>
                <xsd:element name="value" type="xsd:string" minOccurs="0" />
              </xsd:sequence>
              <xsd:attribute name="name" use="required" type="xsd:string" />
              <xsd:attribute name="type" type="xsd:string" />
              <xsd:attribute name="mimetype" type="xsd:string" />
              <xsd:attribute ref="xml:space" />
            </xsd:complexType>
          </xsd:element>
          <xsd:element name="assembly">
            <xsd:complexType>
              <xsd:attribute name="alias" type="xsd:string" />
              <xsd:attribute name="name" type="xsd:string" />
            </xsd:complexType>
          </xsd:element>
          <xsd:element name="data">
            <xsd:complexType>
              <xsd:sequence>
                <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
                <xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
              </xsd:sequence>
              <xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
              <xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
              <xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
              <xsd:attribute ref="xml:space" />
            </xsd:complexType>
          </xsd:element>
          <xsd:element name="resheader">
            <xsd:complexType>
              <xsd:sequence>
                <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
              </xsd:sequence>
              <xsd:attribute name="name" type="xsd:string" use="required" />
            </xsd:complexType>
          </xsd:element>
        </xsd:choice>
      </xsd:complexType>
    </xsd:element>
  </xsd:schema>
  <resheader name="resmimetype">
    <value>text/microsoft-resx</value>
  </resheader>
  <resheader name="version">
    <value>2.0</value>
  </resheader>
  <resheader name="reader">
    <value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
  </resheader>
  <resheader name="writer">
    <value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
  </resheader>
  <data name="Greeting" xml:space="preserve">
    <value>¡Hola, Mundo!</value>
  </data>
</root>

El componente siguiente muestra el uso de la cadena Greeting localizada con IStringLocalizer<T>. El Razormarcado@Loc["Greeting"] del ejemplo siguiente localiza la cadena con clave en el valor Greeting, que se establece en los archivos de recursos anteriores.

Agrega el espacio de nombres para Microsoft.Extensions.Localization al archivo _Imports.razor de la aplicación:

@using Microsoft.Extensions.Localization

CultureExample2.razor:

@page "/culture-example-2"
@using System.Globalization
@inject IStringLocalizer<CultureExample2> Loc

<h1>Culture Example 2</h1>

<ul>
    <li><b>CurrentCulture</b>: @CultureInfo.CurrentCulture</li>
    <li><b>CurrentUICulture</b>: @CultureInfo.CurrentUICulture</li>
</ul>

<h2>Greeting</h2>

<p>
    @Loc["Greeting"]
</p>

<p>
    @greeting
</p>

@code {
    private string? greeting;

    protected override void OnInitialized()
    {
        greeting = Loc["Greeting"];
    }
}

Opcionalmente, agrega un elemento de menú para el componente CultureExample2 a la navegación en el componente NavMenu (NavMenu.razor).

Origen de referencia del proveedor de referencia cultural de WebAssembly

Para comprender mejor cómo procesa el marco Blazor la localización de procesos, consulta la clase WebAssemblyCultureProvider en el código fuente de referencia de ASP.NET Core.

Nota

Los vínculos de la documentación al origen de referencia de .NET cargan normalmente la rama predeterminada del repositorio, que representa el desarrollo actual para la próxima versión de .NET. Para seleccionar una etiqueta de una versión específica, usa la lista desplegable Cambiar ramas o etiquetas. Para obtener más información, consulta Procedimientos para seleccionar una etiqueta de versión de código fuente de ASP.NET Core (dotnet/AspNetCore.Docs #26205).

Recursos compartidos

Para crear recursos compartidos de localización, adopta el siguiente enfoque.

  • Crea una clase ficticia con un nombre de clase arbitrario. En el ejemplo siguiente:

    • La aplicación usa el espacio de nombres BlazorSample y los recursos de localización usan el espacio de nombres BlazorSample.Localization.
    • La clase ficticia se denomina SharedResource.
    • El archivo de clase se coloca en una carpeta Localization en la raíz de la aplicación.

    Localization/SharedResource.cs:

    namespace BlazorSample.Localization;
    
    public class SharedResource
    {
    }
    
  • Crea los archivos de recursos compartidos con una acción de compilación de Embedded resource. En el ejemplo siguiente:

    • Los archivos se colocan en la carpeta Localization con la clase SharedResource ficticia (Localization/SharedResource.cs).

    • Asigna un nombre a los archivos de recursos para que coincida con el nombre de la clase ficticia. En los siguientes archivos de ejemplo se incluyen un archivo de localización predeterminado y un archivo para la localización en español (es).

    • Localization/SharedResource.resx

    • Localization/SharedResource.es.resx

    Advertencia

    Si sigues el planteamiento de esta sección, no podrás establecer LocalizationOptions.ResourcesPath y usar IStringLocalizerFactory.Create simultáneamente para cargar recursos.

  • Para hacer referencia a la clase ficticia para un elemento IStringLocalizer<T> insertado en un componente Razor, coloca una directiva @using para el espacio de nombres de localización o incluye el espacio de nombres de localización en la referencia de clase ficticia. En los siguientes ejemplos:

    • En el primer ejemplo se indica el espacio de nombres Localization para la clase ficticia SharedResource con una directiva @using.
    • En el segundo ejemplo se indica el espacio de nombres de la clase ficticia SharedResource explícitamente.

    En un componente Razor, usa cualquiera de los enfoques siguientes:

    @using Localization
    @inject IStringLocalizer<SharedResource> Loc
    
    @inject IStringLocalizer<Localization.SharedResource> Loc
    

Para obtener orientación adicional, consulta Globalización y localización en ASP.NET Core.

Anulación de ubicación mediante el panel "Sensores" en las herramientas de desarrollo

Al usar la invalidación de ubicación mediante el panel Sensores en Google Chrome o las herramientas de desarrollo de Microsoft Edge, el idioma alternativo se restablece después de la representación previa. Evita establecer el idioma mediante el panel Sensores al realizar pruebas. Establece el idioma mediante la configuración de idioma del explorador.

Para obtener más información, consulta Localización Blazor no funciona con InteractiveServer (dotnet/aspnetcore #53707).

Recursos adicionales