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

Los componentes de Razor pueden representar contenido globalizado y localizado a los usuarios de diferentes referencias culturales e idiomas. 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:

✔️ IStringLocalizer y IStringLocalizer<T> se admiten en aplicaciones de Blazor.

❌, IHtmlLocalizer, IViewLocalizer y la localización de anotaciones de datos son características de MVC de ASP.NET Core 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 más información general, vea Globalización y localización en ASP.NET Core.

Nota

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.

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.

Al usar los tipos de campo date y number, no se recomienda especificar una referencia cultural con @bind:culture porque Blazor proporciona compatibilidad integrada para representar valores en la referencia cultural actual.

Los siguientes tipos de campo tienen requisitos de formato específicos y no se admiten actualmente 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, vea ¿Puedo usar ?

Globalización invariable

Si la aplicación no requiere localización, configure la aplicación para que admita la referencia cultural invariable, que suele basarse en inglés de Estados Unidos (en-US). Establezca la propiedad InvariantGlobalization en true en el archivo del proyecto de la aplicación (.csproj):

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

Como alternativa, configure 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, vea Opciones de configuración del entorno de ejecución para la globalización (documentación de .NET).

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.

Pages/CultureExample1.razor:

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

<h1>Culture Example 1</h1>

<p>
    <b>CurrentCulture</b>: @CultureInfo.CurrentCulture
</p>

<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.

Agregue un elemento de lista al elemento <ul> del menú de navegación en Shared/NavMenu.razor para el componente CultureExample1:

<li class="nav-item px-3">
    <NavLink class="nav-link" href="culture-example-1">
        <span class="oi oi-list-rich" aria-hidden="true"></span> Culture Example 1
    </NavLink>
</li>

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

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 de Chile con una preferencia por inglés de Estados Unidos o inglés:

Accept-Language: en-US,en;q=0.9,es-CL;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.

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

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

Las aplicaciones Blazor Server se localizan usando un middleware de localización. Agregue servicios de localización a la aplicación con AddLocalization.

En Program.cs:

builder.Services.AddLocalization();

Especifique las referencia culturales admitidas de la aplicación en Program.cs inmediatamente después de agregar el middleware de enrutamiento 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 de Chile:

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

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

Use el componente CultureExample1 que se muestra en la sección Componente de demostración para estudiar cómo funciona la globalización. Emita una solicitud con inglés de Estados Unidos (en-US). Cambie a español de Chile (es-CL) en la configuración de idioma del explorador. Vuelva a solicitar la página web.

Nota

Algunos exploradores le 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 de Chile (es-CL), 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

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

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

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).

  • En wwwroot/index.html, evite el inicio automático de Blazor agregando autostart="false" a la etiqueta <script> de Blazor:

    <script src="_framework/blazor.webassembly.js" autostart="false"></script>
    
  • Agregue el siguiente bloque <script> después de la etiqueta <script> de Blazor y antes de la etiqueta </body> de cierre:

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

El valor de applicationCulture debe ajustarse al formato de etiqueta de idioma BCP-47. Para más información sobre el inicio de Blazor, vea 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#. Establezca CultureInfo.DefaultThreadCurrentCulture y CultureInfo.DefaultThreadCurrentUICulture en Program.cs.

Agregue el espacio de nombres System.Globalization a Program.cs:

using System.Globalization;

Agregue 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");

Las aplicaciones Blazor Server se localizan usando un middleware de localización. Agregue servicios de localización a la aplicación con AddLocalization.

En Program.cs:

builder.Services.AddLocalization();

Especifique la referencia cultural estática en Program.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 Program.cs, vea Middleware de ASP.NET Core.

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

Establecimiento dinámico de la referencia cultural 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 las aplicaciones Blazor WebAssembly), en una localización cookie o base de datos (común en las aplicaciones de Blazor Server) 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.

Agregue la referencia del proyecto del paquete Microsoft.Extensions.Localization al archivo del proyecto de la aplicación (.csproj):

<PackageReference Include="Microsoft.Extensions.Localization" Version="{VERSION}" />

El marcador de posición {VERSION} de la referencia del paquete anterior es la versión del paquete.

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

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

La referencia cultural de la aplicación en una aplicación Blazor WebAssembly se establece mediante la API del marco de Blazor. La selección de la referencia cultural de un usuario se puede conservar en el almacenamiento local del explorador.

En el archivo wwwroot/index.html después de la etiqueta <script> de Blazor y antes de la etiqueta de cierre </body>, proporcione funciones de JS 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

El ejemplo anterior contamina el cliente con métodos globales. Para obtener un mejor enfoque en las aplicaciones de producción, consulte Aislamiento de JavaScript en módulos de JavaScript.

Ejemplo:

export function getBlazorCulture() {
  return window.localStorage['BlazorCulture'];
};
export function setBlazorCulture(value) {
  window.localStorage['BlazorCulture'] = value;
};

Si usa las funciones anteriores, cambie las llamadas de interoperabilidad de JS de esta sección de blazorCulture.get a getBlazorCulture y de blazorCulture.set a setBlazorCulture.

Agregue los espacios de nombres para System.Globalization y Microsoft.JSInterop en la parte superior de Program.cs:

using System.Globalization;
using Microsoft.JSInterop;

Quite las siguientes líneas de Program.cs:

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

Reemplace 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();

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

if (result != null)
{
    culture = new CultureInfo(result);
}
else
{
    culture = new CultureInfo("en-US");
    await js.InvokeVoidAsync("blazorCulture.set", "en-US");
}

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

await host.RunAsync();

El componente CultureSelector siguiente muestra cómo establecer la selección de referencia cultural del usuario en el almacenamiento local del explorador mediante la interoperabilidad de JS. El componente se coloca en la carpeta Shared para su uso en toda la aplicación.

Shared/CultureSelector.razor:

@using  System.Globalization
@inject IJSRuntime JSRuntime
@inject NavigationManager Nav

<p>
    <label>
        Select your locale:
        <select @bind="Culture">
            @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-CL"),
    };

    private CultureInfo Culture
    {
        get => CultureInfo.CurrentCulture;
        set
        {
            if (CultureInfo.CurrentCulture != value)
            {
                var js = (IJSInProcessRuntime)JSRuntime;
                js.InvokeVoid("blazorCulture.set", value.Name);

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

Dentro de la etiqueta de cierre </div> del elemento <div class="main"> en Shared/MainLayout.razor, agregue el componente CultureSelector:

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

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 las aplicaciones Blazor WebAssembly), en una localización cookie o base de datos (común en las aplicaciones de Blazor Server) 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.

Agregue la referencia del proyecto del paquete Microsoft.Extensions.Localization al archivo del proyecto de la aplicación (.csproj):

<ItemGroup>
  <PackageReference Include="Microsoft.Extensions.Localization" Version="{VERSION}" />
</ItemGroup>

El marcador de posición {VERSION} de la referencia del paquete anterior es la versión del paquete.

Las aplicaciones Blazor Server se localizan usando un middleware de localización. Agregue servicios de localización a la aplicación con AddLocalization.

En Program.cs:

builder.Services.AddLocalization();

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

En Program.cs, inmediatamente después de agregar el middleware de enrutamiento a la canalización de procesamiento:

var supportedCultures = new[] { "en-US", "es-CL" };
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 Program.cs, vea 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.

Agregue los siguientes espacios de nombres en la parte superior del archivo Pages/_Layout.cshtml:

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

Inmediatamente después de la etiqueta de apertura <body> de Pages/_Layout.cshtml, agregue la siguiente expresión Razor:

@{
    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 de Program.cs, vea Middleware de ASP.NET Core.

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

  • Agregue servicios de MVC mediante una llamada a AddControllers en la colección de servicios en Program.cs:

    builder.Services.AddControllers();
    
  • Agregue el enrutamiento del punto de conexión del controlador en Program.cs mediante una llamada a MapControllers en IEndpointRouteBuilder:

    app.MapControllers();
    

    En el ejemplo siguiente se muestra la llamada a UseEndpoints después de agregar la línea:

    app.MapControllers();
    app.MapBlazorHub();
    app.MapFallbackToPage("/_Host");
    

Para especificar una interfaz de usuario que permita a un usuario seleccionar una referencia cultural, se use 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

Use el resultado de la acción LocalRedirect para evitar ataques de redireccionamiento abierto. Para obtener más información, vea Evitar ataques de redireccionamiento abierto en ASP.NET Core.

El siguiente componente CultureSelector muestra cómo realizar el redireccionamiento inicial cuando el usuario selecciona una referencia cultural. El componente se coloca en la carpeta Shared para su uso en toda la aplicación.

Shared/CultureSelector.razor:

@using  System.Globalization
@inject NavigationManager Nav

<p>
    <label>
        Select your locale:
        <select @bind="Culture">
            @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-CL"),
    };

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

    private CultureInfo Culture
    {
        get => CultureInfo.CurrentCulture;
        set
        {
            if (CultureInfo.CurrentCulture != value)
            {
                var uri = new Uri(Nav.Uri)
                    .GetComponents(UriComponents.PathAndQuery, UriFormat.Unescaped);
                var cultureEscaped = Uri.EscapeDataString(value.Name);
                var uriEscaped = Uri.EscapeDataString(uri);

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

Dentro de la etiqueta de cierre </div> del elemento <div class="main"> en Shared/MainLayout.razor, agregue el componente CultureSelector:

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

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

Localización

Si la aplicación aún no admite la selección de referencia cultural tratada en la sección Establecimiento dinámico de la referencia cultural según las preferencias del usuario de este artículo, agregue una referencia de paquete para el paquete Microsoft.Extensions.Localization al archivo de proyecto de la aplicación (.csproj):

<PackageReference Include="Microsoft.Extensions.Localization" Version="{VERSION}" />

El marcador de posición {VERSION} de la referencia del paquete anterior es la versión del paquete.

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

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

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

using System.Globalization;

Agregue el servicio de localización de Blazor a la colección de servicios de la aplicación con AddLocalization en Program.cs:

builder.Services.AddLocalization();

Use 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 tratada en la sección Establecimiento dinámico de la referencia cultural según las preferencias del usuario de este artículo:

  • Agregue servicios de localización a la aplicación con AddLocalization.
  • Especifique las referencia culturales predeterminadas y admitidas de la aplicación en Program.cs. En el ejemplo siguiente se configuran las referencia culturales admitidas para inglés de Estados Unidos y español de Chile.

En Program.cs:

builder.Services.AddLocalization();

En Program.cs, inmediatamente después de agregar el middleware de enrutamiento a la canalización de procesamiento:

var supportedCultures = new[] { "en-US", "es-CL" };
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 Program.cs, vea 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, use 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. Consulte la sección Establecimiento dinámico de la referencia cultural según las preferencias del usuario de este artículo para ver una expresión Razor de ejemplo para el archivo Pages/_Layout.cshtml que conserva la selección de referencia cultural del usuario.

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.

Cree recursos para cada configuración regional. En el ejemplo siguiente, se crean recursos para una cadena Greeting predeterminada:

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

Nota

El siguiente archivo de recursos se puede agregar en Visual Studio; para ello, haga clic con el botón derecho en la carpeta Pages del proyecto y seleccione Agregar > Nuevo elemento > Archivo de recursos. Ponga al archivo el nombre CultureExample2.resx. Cuando aparezca el editor, proporcione datos para una nueva entrada. Establezca el Nombre en Greeting y el Valor en Hello, World!. Guarde el archivo.

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, haga clic con el botón derecho en la carpeta Pages del proyecto y seleccione Agregar > Nuevo elemento > Archivo de recursos. Ponga al archivo el nombre CultureExample2.es.resx. Cuando aparezca el editor, proporcione datos para una nueva entrada. Establezca el Nombre en Greeting y el Valor en ¡Hola, Mundo!. Guarde el archivo.

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>.

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

@using Microsoft.Extensions.Localization

Pages/CultureExample2.razor:

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

<h1>Culture Example 2</h1>

<p>
    <b>CurrentCulture</b>: @CultureInfo.CurrentCulture
</p>

<h2>Greeting</h2>

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

<p>
    @greeting
</p>

@code {
    private string greeting;

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

Agregue un elemento de lista al elemento <ul> del menú de navegación en Shared/NavMenu.razor para el componente CultureExample2:

<li class="nav-item px-3">
    <NavLink class="nav-link" href="culture-example-2">
        <span class="oi oi-list-rich" aria-hidden="true"></span> Culture Example 2
    </NavLink>
</li>

Recursos adicionales

Los componentes de Razor pueden representar contenido globalizado y localizado a los usuarios de diferentes referencias culturales e idiomas. 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:

✔️ IStringLocalizer y IStringLocalizer<T> se admiten en aplicaciones de Blazor.

❌, IHtmlLocalizer, IViewLocalizer y la localización de anotaciones de datos son características de MVC de ASP.NET Core 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 más información general, vea Globalización y localización en ASP.NET Core.

Nota

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.

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.

Al usar los tipos de campo date y number, no se recomienda especificar una referencia cultural con @bind:culture porque Blazor proporciona compatibilidad integrada para representar valores en la referencia cultural actual.

Los siguientes tipos de campo tienen requisitos de formato específicos y no se admiten actualmente 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, vea ¿Puedo usar ?

Globalización invariable

Si la aplicación no requiere localización, configure la aplicación para que admita la referencia cultural invariable, que suele basarse en inglés de Estados Unidos (en-US). Establezca la propiedad InvariantGlobalization en true en el archivo del proyecto de la aplicación (.csproj):

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

Como alternativa, configure 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, vea Opciones de configuración del entorno de ejecución para la globalización (documentación de .NET).

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.

Pages/CultureExample1.razor:

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

<h1>Culture Example 1</h1>

<p>
    <b>CurrentCulture</b>: @CultureInfo.CurrentCulture
</p>

<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.

Agregue un elemento de lista al elemento <ul> del menú de navegación en Shared/NavMenu.razor para el componente CultureExample1:

<li class="nav-item px-3">
    <NavLink class="nav-link" href="culture-example-1">
        <span class="oi oi-list-rich" aria-hidden="true"></span> Culture Example 1
    </NavLink>
</li>

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

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 de Chile con una preferencia por inglés de Estados Unidos o inglés:

Accept-Language: en-US,en;q=0.9,es-CL;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.

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

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

Las aplicaciones Blazor Server se localizan usando un middleware de localización. Agregue servicios de localización a la aplicación con AddLocalization.

En Startup.ConfigureServices (Startup.cs):

services.AddLocalization();

Especifique las referencia culturales admitidas de la aplicación 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 configuran las referencia culturales admitidas para inglés de Estados Unidos y español de Chile:

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

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

Use el componente CultureExample1 que se muestra en la sección Componente de demostración para estudiar cómo funciona la globalización. Emita una solicitud con inglés de Estados Unidos (en-US). Cambie a español de Chile (es-CL) en la configuración de idioma del explorador. Vuelva a solicitar la página web.

Nota

Algunos exploradores le 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 de Chile (es-CL), 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

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

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

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).

  • En wwwroot/index.html, evite el inicio automático de Blazor agregando autostart="false" a la etiqueta <script> de Blazor:

    <script src="_framework/blazor.webassembly.js" autostart="false"></script>
    
  • Agregue el siguiente bloque <script> después de la etiqueta <script> de Blazor y antes de la etiqueta </body> de cierre:

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

El valor de applicationCulture debe ajustarse al formato de etiqueta de idioma BCP-47. Para más información sobre el inicio de Blazor, vea 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#. Establezca CultureInfo.DefaultThreadCurrentCulture y CultureInfo.DefaultThreadCurrentUICulture en Program.cs.

Agregue el espacio de nombres System.Globalization a Program.cs:

using System.Globalization;

Agregue 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");

Las aplicaciones Blazor Server se localizan usando un middleware de localización. Agregue servicios de localización a la aplicación con AddLocalization.

En Startup.ConfigureServices (Startup.cs):

services.AddLocalization();

Especifique 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, vea Middleware de ASP.NET Core.

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

Establecimiento dinámico de la referencia cultural 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 las aplicaciones Blazor WebAssembly), en una localización cookie o base de datos (común en las aplicaciones de Blazor Server) 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.

Agregue la referencia del proyecto del paquete Microsoft.Extensions.Localization al archivo del proyecto de la aplicación (.csproj):

<PackageReference Include="Microsoft.Extensions.Localization" Version="{VERSION}" />

El marcador de posición {VERSION} de la referencia del paquete anterior es la versión del paquete.

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

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

La referencia cultural de la aplicación en una aplicación Blazor WebAssembly se establece mediante la API del marco de Blazor. La selección de la referencia cultural de un usuario se puede conservar en el almacenamiento local del explorador.

En el archivo wwwroot/index.html después de la etiqueta <script> de Blazor y antes de la etiqueta de cierre </body>, proporcione funciones de JS 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

El ejemplo anterior contamina el cliente con métodos globales. Para obtener un mejor enfoque en las aplicaciones de producción, consulte Aislamiento de JavaScript en módulos de JavaScript.

Ejemplo:

export function getBlazorCulture() {
  return window.localStorage['BlazorCulture'];
};
export function setBlazorCulture(value) {
  window.localStorage['BlazorCulture'] = value;
};

Si usa las funciones anteriores, cambie las llamadas de interoperabilidad de JS de esta sección de blazorCulture.get a getBlazorCulture y de blazorCulture.set a setBlazorCulture.

Agregue los espacios de nombres para System.Globalization y Microsoft.JSInterop en la parte superior de Program.cs:

using System.Globalization;
using Microsoft.JSInterop;

Quite las siguientes líneas de Program.cs:

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

Reemplace 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();

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

if (result != null)
{
    culture = new CultureInfo(result);
}
else
{
    culture = new CultureInfo("en-US");
    await js.InvokeVoidAsync("blazorCulture.set", "en-US");
}

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

await host.RunAsync();

El componente CultureSelector siguiente muestra cómo establecer la selección de referencia cultural del usuario en el almacenamiento local del explorador mediante la interoperabilidad de JS. El componente se coloca en la carpeta Shared para su uso en toda la aplicación.

Shared/CultureSelector.razor:

@using  System.Globalization
@inject IJSRuntime JSRuntime
@inject NavigationManager Nav

<p>
    <label>
        Select your locale:
        <select @bind="Culture">
            @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-CL"),
    };

    private CultureInfo Culture
    {
        get => CultureInfo.CurrentCulture;
        set
        {
            if (CultureInfo.CurrentCulture != value)
            {
                var js = (IJSInProcessRuntime)JSRuntime;
                js.InvokeVoid("blazorCulture.set", value.Name);

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

Dentro de la etiqueta de cierre </div> del elemento <div class="main"> en Shared/MainLayout.razor, agregue el componente CultureSelector:

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

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 las aplicaciones Blazor WebAssembly), en una localización cookie o base de datos (común en las aplicaciones de Blazor Server) 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.

Agregue la referencia del proyecto del paquete Microsoft.Extensions.Localization al archivo del proyecto de la aplicación (.csproj):

<ItemGroup>
  <PackageReference Include="Microsoft.Extensions.Localization" Version="{VERSION}" />
</ItemGroup>

El marcador de posición {VERSION} de la referencia del paquete anterior es la versión del paquete.

Las aplicaciones Blazor Server se localizan usando un middleware de localización. Agregue servicios de localización a la aplicación con AddLocalization.

En Startup.ConfigureServices (Startup.cs):

services.AddLocalization();

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

En Startup.Configure, inmediatamente después de agregar el middleware de enrutamiento a la canalización de procesamiento:

var supportedCultures = new[] { "en-US", "es-CL" };
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, vea 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.

Agregue los siguientes espacios de nombres en la parte superior del archivo Pages/_Host.cshtml:

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

Inmediatamente después de la etiqueta de apertura <body> de Pages/_Host.cshtml, agregue la siguiente expresión Razor:

@{
    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 de Startup.Configure, vea Middleware de ASP.NET Core.

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

  • Agregue servicios de MVC mediante una llamada a AddControllers en la colección de servicios en Startup.ConfigureServices:

    services.AddControllers();
    
  • Agregue el enrutamiento del punto de conexión del controlador en Startup.Configure mediante una llamada a MapControllers en IEndpointRouteBuilder:

    endpoints.MapControllers();
    

    En el ejemplo siguiente se muestra la llamada a UseEndpoints después de agregar la línea:

    app.UseEndpoints(endpoints =>
    {
    +   endpoints.MapControllers();
        endpoints.MapBlazorHub();
        endpoints.MapFallbackToPage("/_Host");
    });
    

Para especificar una interfaz de usuario que permita a un usuario seleccionar una referencia cultural, se use 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

Use el resultado de la acción LocalRedirect para evitar ataques de redireccionamiento abierto. Para obtener más información, vea Evitar ataques de redireccionamiento abierto en ASP.NET Core.

El siguiente componente CultureSelector muestra cómo realizar el redireccionamiento inicial cuando el usuario selecciona una referencia cultural. El componente se coloca en la carpeta Shared para su uso en toda la aplicación.

Shared/CultureSelector.razor:

@using  System.Globalization
@inject NavigationManager Nav

<p>
    <label>
        Select your locale:
        <select @bind="Culture">
            @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-CL"),
    };

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

    private CultureInfo Culture
    {
        get => CultureInfo.CurrentCulture;
        set
        {
            if (CultureInfo.CurrentCulture != value)
            {
                var uri = new Uri(Nav.Uri)
                    .GetComponents(UriComponents.PathAndQuery, UriFormat.Unescaped);
                var cultureEscaped = Uri.EscapeDataString(value.Name);
                var uriEscaped = Uri.EscapeDataString(uri);

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

Dentro de la etiqueta de cierre </div> del elemento <div class="main"> en Shared/MainLayout.razor, agregue el componente CultureSelector:

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

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

Localización

Si la aplicación aún no admite la selección de referencia cultural tratada en la sección Establecimiento dinámico de la referencia cultural según las preferencias del usuario de este artículo, agregue una referencia de paquete para el paquete Microsoft.Extensions.Localization al archivo de proyecto de la aplicación (.csproj):

<PackageReference Include="Microsoft.Extensions.Localization" Version="{VERSION}" />

El marcador de posición {VERSION} de la referencia del paquete anterior es la versión del paquete.

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

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

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

using System.Globalization;

Agregue el servicio de localización de Blazor a la colección de servicios de la aplicación con AddLocalization en Program.cs:

builder.Services.AddLocalization();

Use 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 tratada en la sección Establecimiento dinámico de la referencia cultural según las preferencias del usuario de este artículo:

  • Agregue servicios de localización a la aplicación con AddLocalization.
  • Especifique 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 de Chile.

En Startup.ConfigureServices (Startup.cs):

services.AddLocalization();

En Startup.Configure, inmediatamente después de agregar el middleware de enrutamiento a la canalización de procesamiento:

var supportedCultures = new[] { "en-US", "es-CL" };
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, vea 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, use 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. Consulte la sección Establecimiento dinámico de la referencia cultural según las preferencias del usuario de este artículo para ver una expresión Razor de ejemplo para el archivo Pages/_Host.cshtml que conserva la selección de referencia cultural del usuario.

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.

Cree recursos para cada configuración regional. En el ejemplo siguiente, se crean recursos para una cadena Greeting predeterminada:

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

Nota

El siguiente archivo de recursos se puede agregar en Visual Studio; para ello, haga clic con el botón derecho en la carpeta Pages del proyecto y seleccione Agregar > Nuevo elemento > Archivo de recursos. Ponga al archivo el nombre CultureExample2.resx. Cuando aparezca el editor, proporcione datos para una nueva entrada. Establezca el Nombre en Greeting y el Valor en Hello, World!. Guarde el archivo.

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, haga clic con el botón derecho en la carpeta Pages del proyecto y seleccione Agregar > Nuevo elemento > Archivo de recursos. Ponga al archivo el nombre CultureExample2.es.resx. Cuando aparezca el editor, proporcione datos para una nueva entrada. Establezca el Nombre en Greeting y el Valor en ¡Hola, Mundo!. Guarde el archivo.

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>.

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

@using Microsoft.Extensions.Localization

Pages/CultureExample2.razor:

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

<h1>Culture Example 2</h1>

<p>
    <b>CurrentCulture</b>: @CultureInfo.CurrentCulture
</p>

<h2>Greeting</h2>

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

<p>
    @greeting
</p>

@code {
    private string greeting;

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

Agregue un elemento de lista al elemento <ul> del menú de navegación en Shared/NavMenu.razor para el componente CultureExample2:

<li class="nav-item px-3">
    <NavLink class="nav-link" href="culture-example-2">
        <span class="oi oi-list-rich" aria-hidden="true"></span> Culture Example 2
    </NavLink>
</li>

Recursos adicionales

Los componentes de Razor pueden representar contenido globalizado y localizado a los usuarios de diferentes referencias culturales e idiomas. 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:

✔️ IStringLocalizer y IStringLocalizer<T> se admiten en aplicaciones de Blazor.

❌, IHtmlLocalizer, IViewLocalizer y la localización de anotaciones de datos son características de MVC de ASP.NET Core 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 más información general, vea Globalización y localización en ASP.NET Core.

Nota

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.

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.

Al usar los tipos de campo date y number, no se recomienda especificar una referencia cultural con @bind:culture porque Blazor proporciona compatibilidad integrada para representar valores en la referencia cultural actual.

Los siguientes tipos de campo tienen requisitos de formato específicos y no se admiten actualmente 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, vea ¿Puedo usar ?

Globalización invariable

Si la aplicación no requiere localización, configure la aplicación para que admita la referencia cultural invariable, que suele basarse en inglés de Estados Unidos (en-US). Establezca la propiedad InvariantGlobalization en true en el archivo del proyecto de la aplicación (.csproj):

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

Como alternativa, configure 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, vea Opciones de configuración del entorno de ejecución para la globalización (documentación de .NET).

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.

Pages/CultureExample1.razor:

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

<h1>Culture Example 1</h1>

<p>
    <b>CurrentCulture</b>: @CultureInfo.CurrentCulture
</p>

<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.

Agregue un elemento de lista al elemento <ul> del menú de navegación en Shared/NavMenu.razor para el componente CultureExample1:

<li class="nav-item px-3">
    <NavLink class="nav-link" href="culture-example-1">
        <span class="oi oi-list-rich" aria-hidden="true"></span> Culture Example 1
    </NavLink>
</li>

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

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 de Chile con una preferencia por inglés de Estados Unidos o inglés:

Accept-Language: en-US,en;q=0.9,es-CL;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.

Las aplicaciones Blazor Server se localizan usando un middleware de localización. Agregue servicios de localización a la aplicación con AddLocalization.

En Startup.ConfigureServices (Startup.cs):

services.AddLocalization();

Especifique las referencia culturales admitidas de la aplicación 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 configuran las referencia culturales admitidas para inglés de Estados Unidos y español de Chile:

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

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

Use el componente CultureExample1 que se muestra en la sección Componente de demostración para estudiar cómo funciona la globalización. Emita una solicitud con inglés de Estados Unidos (en-US). Cambie a español de Chile (es-CL) en la configuración de idioma del explorador. Vuelva a solicitar la página web.

Nota

Algunos exploradores le 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 de Chile (es-CL), 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

De forma predeterminada, la configuración del enlazador de lenguaje intermedio (IL) para aplicaciones de Blazor WebAssembly quita la información de internacionalización, excepto para las configuraciones regionales solicitadas de forma explícita. Para obtener más información, vea Configuración del enlazador de ASP.NET Core Blazor.

Las aplicaciones Blazor Server se localizan usando un middleware de localización. Agregue servicios de localización a la aplicación con AddLocalization.

En Startup.ConfigureServices (Startup.cs):

services.AddLocalization();

Especifique 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, vea Middleware de ASP.NET Core.

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

Establecimiento dinámico de la referencia cultural 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 las aplicaciones Blazor WebAssembly), en una localización cookie o base de datos (común en las aplicaciones de Blazor Server) 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.

Agregue la referencia del proyecto del paquete Microsoft.Extensions.Localization al archivo del proyecto de la aplicación (.csproj):

<PackageReference Include="Microsoft.Extensions.Localization" Version="{VERSION}" />

El marcador de posición {VERSION} de la referencia del paquete anterior es la versión del paquete.

La referencia cultural de la aplicación en una aplicación Blazor WebAssembly se establece mediante la API del marco de Blazor. La selección de la referencia cultural de un usuario se puede conservar en el almacenamiento local del explorador.

En el archivo wwwroot/index.html después de la etiqueta <script> de Blazor y antes de la etiqueta de cierre </body>, proporcione funciones de JS 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>

Agregue los espacios de nombres para System.Globalization y Microsoft.JSInterop en la parte superior de Program.cs:

using System.Globalization;
using Microsoft.JSInterop;

Quite las siguientes líneas de Program.cs:

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

Reemplace 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();

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

if (result != null)
{
    culture = new CultureInfo(result);
}
else
{
    culture = new CultureInfo("en-US");
    await js.InvokeVoidAsync("blazorCulture.set", "en-US");
}

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

await host.RunAsync();

El componente CultureSelector siguiente muestra cómo establecer la selección de referencia cultural del usuario en el almacenamiento local del explorador mediante la interoperabilidad de JS. El componente se coloca en la carpeta Shared para su uso en toda la aplicación.

Shared/CultureSelector.razor:

@using  System.Globalization
@inject IJSRuntime JSRuntime
@inject NavigationManager Nav

<p>
    <label>
        Select your locale:
        <select @bind="Culture">
            @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-CL"),
    };

    private CultureInfo Culture
    {
        get => CultureInfo.CurrentCulture;
        set
        {
            if (CultureInfo.CurrentCulture != value)
            {
                var js = (IJSInProcessRuntime)JSRuntime;
                js.InvokeVoid("blazorCulture.set", value.Name);

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

Dentro de la etiqueta de cierre </div> del elemento <div class="main"> en Shared/MainLayout.razor, agregue el componente CultureSelector:

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

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 las aplicaciones Blazor WebAssembly), en una localización cookie o base de datos (común en las aplicaciones de Blazor Server) 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.

Agregue la referencia del proyecto del paquete Microsoft.Extensions.Localization al archivo del proyecto de la aplicación (.csproj):

<ItemGroup>
  <PackageReference Include="Microsoft.Extensions.Localization" Version="{VERSION}" />
</ItemGroup>

El marcador de posición {VERSION} de la referencia del paquete anterior es la versión del paquete.

Las aplicaciones Blazor Server se localizan usando un middleware de localización. Agregue servicios de localización a la aplicación con AddLocalization.

En Startup.ConfigureServices (Startup.cs):

services.AddLocalization();

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

En Startup.Configure, inmediatamente después de agregar el middleware de enrutamiento a la canalización de procesamiento:

var supportedCultures = new[] { "en-US", "es-CL" };
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, vea 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.

Agregue los siguientes espacios de nombres en la parte superior del archivo Pages/_Host.cshtml:

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

Inmediatamente después de la etiqueta de apertura <body> de Pages/_Host.cshtml, agregue la siguiente expresión Razor:

@{
    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 de Startup.Configure, vea Middleware de ASP.NET Core.

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

  • Agregue servicios de MVC mediante una llamada a AddControllers en la colección de servicios en Startup.ConfigureServices:

    services.AddControllers();
    
  • Agregue el enrutamiento del punto de conexión del controlador en Startup.Configure mediante una llamada a MapControllers en IEndpointRouteBuilder:

    endpoints.MapControllers();
    

    En el ejemplo siguiente se muestra la llamada a UseEndpoints después de agregar la línea:

    app.UseEndpoints(endpoints =>
    {
    +   endpoints.MapControllers();
        endpoints.MapBlazorHub();
        endpoints.MapFallbackToPage("/_Host");
    });
    

Para especificar una interfaz de usuario que permita a un usuario seleccionar una referencia cultural, se use 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

Use el resultado de la acción LocalRedirect para evitar ataques de redireccionamiento abierto. Para obtener más información, vea Evitar ataques de redireccionamiento abierto en ASP.NET Core.

El siguiente componente CultureSelector muestra cómo realizar el redireccionamiento inicial cuando el usuario selecciona una referencia cultural. El componente se coloca en la carpeta Shared para su uso en toda la aplicación.

Shared/CultureSelector.razor:

@using  System.Globalization
@inject NavigationManager Nav

<p>
    <label>
        Select your locale:
        <select @bind="Culture">
            @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-CL"),
    };

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

    private CultureInfo Culture
    {
        get => CultureInfo.CurrentCulture;
        set
        {
            if (CultureInfo.CurrentCulture != value)
            {
                var uri = new Uri(Nav.Uri)
                    .GetComponents(UriComponents.PathAndQuery, UriFormat.Unescaped);
                var cultureEscaped = Uri.EscapeDataString(value.Name);
                var uriEscaped = Uri.EscapeDataString(uri);

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

Dentro de la etiqueta de cierre </div> del elemento <div class="main"> en Shared/MainLayout.razor, agregue el componente CultureSelector:

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

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

Localización

Si la aplicación aún no admite la selección de referencia cultural tratada en la sección Establecimiento dinámico de la referencia cultural según las preferencias del usuario de este artículo, agregue una referencia de paquete para el paquete Microsoft.Extensions.Localization al archivo de proyecto de la aplicación (.csproj):

<PackageReference Include="Microsoft.Extensions.Localization" Version="{VERSION}" />

El marcador de posición {VERSION} de la referencia del paquete anterior es la versión del paquete.

De forma predeterminada, la configuración del enlazador de lenguaje intermedio (IL) para aplicaciones de Blazor WebAssembly quita la información de internacionalización, excepto para las configuraciones regionales solicitadas de forma explícita. Para obtener más información, vea Configuración del enlazador de ASP.NET Core Blazor.

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

using System.Globalization;

Agregue el servicio de localización de Blazor a la colección de servicios de la aplicación con AddLocalization en Program.cs:

builder.Services.AddLocalization();

Use 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 tratada en la sección Establecimiento dinámico de la referencia cultural según las preferencias del usuario de este artículo:

  • Agregue servicios de localización a la aplicación con AddLocalization.
  • Especifique 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 de Chile.

En Startup.ConfigureServices (Startup.cs):

services.AddLocalization();

En Startup.Configure, inmediatamente después de agregar el middleware de enrutamiento a la canalización de procesamiento:

var supportedCultures = new[] { "en-US", "es-CL" };
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, vea 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, use 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. Consulte la sección Establecimiento dinámico de la referencia cultural según las preferencias del usuario de este artículo para ver una expresión Razor de ejemplo para el archivo Pages/_Host.cshtml que conserva la selección de referencia cultural del usuario.

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.

Cree recursos para cada configuración regional. En el ejemplo siguiente, se crean recursos para una cadena Greeting predeterminada:

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

Nota

El siguiente archivo de recursos se puede agregar en Visual Studio; para ello, haga clic con el botón derecho en la carpeta Pages del proyecto y seleccione Agregar > Nuevo elemento > Archivo de recursos. Ponga al archivo el nombre CultureExample2.resx. Cuando aparezca el editor, proporcione datos para una nueva entrada. Establezca el Nombre en Greeting y el Valor en Hello, World!. Guarde el archivo.

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, haga clic con el botón derecho en la carpeta Pages del proyecto y seleccione Agregar > Nuevo elemento > Archivo de recursos. Ponga al archivo el nombre CultureExample2.es.resx. Cuando aparezca el editor, proporcione datos para una nueva entrada. Establezca el Nombre en Greeting y el Valor en ¡Hola, Mundo!. Guarde el archivo.

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>.

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

@using Microsoft.Extensions.Localization

Pages/CultureExample2.razor:

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

<h1>Culture Example 2</h1>

<p>
    <b>CurrentCulture</b>: @CultureInfo.CurrentCulture
</p>

<h2>Greeting</h2>

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

<p>
    @greeting
</p>

@code {
    private string greeting;

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

Agregue un elemento de lista al elemento <ul> del menú de navegación en Shared/NavMenu.razor para el componente CultureExample2:

<li class="nav-item px-3">
    <NavLink class="nav-link" href="culture-example-2">
        <span class="oi oi-list-rich" aria-hidden="true"></span> Culture Example 2
    </NavLink>
</li>

Recursos adicionales