Globalización y localización en ASP.NET Core

By Rick Anderson, Damien Bowden, Bart Calixto, Nadeem Afana y Hisham Bin Ateya

Con un sitio web multilingüe se puede llegar a un público más amplio. ASP.NET Core proporciona servicios y software intermedio para la localización en diferentes idiomas y referencias culturales.

Términos

  • Globalización (G11N): es el proceso de hacer que una aplicación admita diferentes idiomas y regiones. La abreviatura procede de la primera y la última letra y el número de letras entre ellas.
  • Localización (L10N): proceso de personalización de una aplicación globalizada para regiones e idiomas específicos.
  • Internacionalización (I18N): la globalización y la localización.
  • Referencia cultural: un idioma y, opcionalmente, una región.
  • Referencia cultural neutra: se trata de una referencia cultural que tiene un idioma especificado, pero no una región (por ejemplo, "en", "es").
  • Referencia cultural específica: referencia cultural que tiene un idioma y una región especificados (por ejemplo, "en-US", "en-GB", "es-CL").
  • Referencia cultural primaria: referencia cultural neutra que contiene una referencia cultural específica (por ejemplo, "en" es la referencia cultural primaria de "en-US" y "en-GB").
  • Configuración regional: la configuración regional es lo mismo que la referencia cultural.

Códigos de idioma y de país o región

El formato RFC 4646 para el nombre de la referencia cultural es <language code>-<country/region code>, donde <language code> identifica el idioma y <country/region code> identifica la referencia cultural secundaria. Por ejemplo, es-CL para español (Chile), en-US para inglés (Estados Unidos) y en-AU para inglés (Australia). RFC 4646 es una combinación de un código de referencia cultural ISO 639 de dos letras en minúsculas asociado con un idioma y un código de referencia cultural secundaria ISO 3166 de dos letras en mayúsculas asociado con un país o región. Para más información, consulte System.Globalization.CultureInfo.

Tareas para localizar una aplicación

La globalización y la localización de una aplicación implica las tareas siguientes:

Vea o descargue el código de ejemplo (cómo descargarlo)

Recursos adicionales

By Rick Anderson, Damien Bowden, Bart Calixto, Nadeem Afana y Hisham Bin Ateya

Con un sitio web multilingüe se puede llegar a un público más amplio. ASP.NET Core proporciona servicios y software intermedio para la localización en diferentes idiomas y referencias culturales.

Términos

  • Globalización (G11N): es el proceso de hacer que una aplicación admita diferentes idiomas y regiones. La abreviatura procede de la primera y la última letra y el número de letras entre ellas.
  • Localización (L10N): proceso de personalización de una aplicación globalizada para regiones e idiomas específicos.
  • Internacionalización (I18N): la globalización y la localización.
  • Referencia cultural: un idioma y, opcionalmente, una región.
  • Referencia cultural neutra: se trata de una referencia cultural que tiene un idioma especificado, pero no una región (por ejemplo, "en", "es").
  • Referencia cultural específica: referencia cultural que tiene un idioma y una región especificados (por ejemplo, "en-US", "en-GB", "es-CL").
  • Referencia cultural primaria: referencia cultural neutra que contiene una referencia cultural específica (por ejemplo, "en" es la referencia cultural primaria de "en-US" y "en-GB").
  • Configuración regional: la configuración regional es lo mismo que la referencia cultural.

Códigos de idioma y de país o región

El formato RFC 4646 para el nombre de la referencia cultural es <language code>-<country/region code>, donde <language code> identifica el idioma y <country/region code> identifica la referencia cultural secundaria. Por ejemplo, es-CL para español (Chile), en-US para inglés (Estados Unidos) y en-AU para inglés (Australia). RFC 4646 es una combinación de un código de referencia cultural ISO 639 de dos letras en minúsculas asociado con un idioma y un código de referencia cultural secundaria ISO 3166 de dos letras en mayúsculas asociado con un país o región. Para más información, consulte System.Globalization.CultureInfo.

Tareas para localizar una aplicación

La globalización y la localización de una aplicación implica las tareas siguientes:

Vea o descargue el código de ejemplo (cómo descargarlo)

Recursos adicionales

By Rick Anderson, Damien Bowden, Bart Calixto, Nadeem Afana y Hisham Bin Ateya

Con un sitio web multilingüe, se puede llegar a un público más amplio. ASP.NET Core proporciona servicios y software intermedio para la localización en diferentes idiomas y referencias culturales.

La internacionalización implica el uso de System.Globalization y localización. La globalización es el proceso de diseñar aplicaciones que admiten diferentes referencias culturales. La globalización agrega compatibilidad con la entrada, la visualización y la salida de un conjunto definido de scripts de lenguaje relacionados con áreas geográficas específicas.

La localización es el proceso de adaptar una aplicación globalizada, que ya se ha procesado para la localizabilidad, a una determinada referencia cultural o configuración regional. Para más información, vea Términos relacionados con la globalización y la localización al final de este documento.

La localización de la aplicación implica lo siguiente:

  1. Hacer que el contenido de la aplicación sea localizable
  2. Proporcionar recursos localizados para los idiomas y las referencias culturales admitidos
  3. Implementar una estrategia para seleccionar el idioma o la referencia cultural de cada solicitud

Vea o descargue el código de ejemplo (cómo descargarlo)

Preparación del contenido de la aplicación para su localización

IStringLocalizer y IStringLocalizer<T> se diseñaron para mejorar la productividad al desarrollar aplicaciones localizadas. IStringLocalizer usa ResourceManager y ResourceReader para proporcionar recursos específicos de la referencia cultural en tiempo de ejecución. La interfaz tiene un indizador y un IEnumerable para devolver las cadenas localizadas. IStringLocalizer no necesita que se almacenen las cadenas de idioma predeterminado en un archivo de recursos. Puede desarrollar una aplicación destinada a la localización sin necesidad de crear archivos de recursos al principio de la fase de desarrollo. En el código siguiente se muestra cómo ajustar la cadena "About Title" para la localización.

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

namespace Localization.Controllers
{
    [Route("api/[controller]")]
    public class AboutController : Controller
    {
        private readonly IStringLocalizer<AboutController> _localizer;

        public AboutController(IStringLocalizer<AboutController> localizer)
        {
            _localizer = localizer;
        }

        [HttpGet]
        public string Get()
        {
            return _localizer["About Title"];
        }
    }
}

En el código anterior, la implementación de IStringLocalizer<T> procede de la inserción de dependencias. Si no se encuentra el valor localizado de "About Title, se devuelve la clave de indizador, es decir, la cadena "About Title". Puede dejar las cadenas literales del idioma predeterminado en la aplicación y ajustarlas en el localizador, de modo que se pueda centrar en el desarrollo de la aplicación. Desarrolle la aplicación con el idioma predeterminado y prepárela para el proceso de localización sin necesidad de crear primero un archivo de recursos predeterminado. También puede seguir el método tradicional y proporcionar una clave para recuperar la cadena de idioma predeterminado. El nuevo flujo de trabajo, que carece de archivo .resx de idioma predeterminado y simplemente ajusta los literales de cadena, puede ahorrar a muchos desarrolladores la sobrecarga de localizar una aplicación. Otros desarrolladores preferirán el flujo de trabajo tradicional, ya que facilita el trabajo con literales de cadena más largos, así como la actualización de las cadenas localizadas.

Use la implementación de IHtmlLocalizer<T> para los recursos que contienen HTML. El HTML de IHtmlLocalizer codifica los argumentos a los que se da formato en la cadena de recursos, pero no codifica como HTML la cadena de recursos en sí misma. En el ejemplo que se muestra a continuación, solo está codificado en HTML el valor del parámetro name.

using System;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Localization;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Localization;

namespace Localization.Controllers
{
    public class BookController : Controller
    {
        private readonly IHtmlLocalizer<BookController> _localizer;

        public BookController(IHtmlLocalizer<BookController> localizer)
        {
            _localizer = localizer;
        }

        public IActionResult Hello(string name)
        {
            ViewData["Message"] = _localizer["<b>Hello</b><i> {0}</i>", name];

            return View();
        }

Nota

Por lo general, solo se localiza texto, no HTML.

En el nivel más bajo, puede obtener IStringLocalizerFactory de la inserción de dependencias:

{
    public class TestController : Controller
    {
        private readonly IStringLocalizer _localizer;
        private readonly IStringLocalizer _localizer2;

        public TestController(IStringLocalizerFactory factory)
        {
            var type = typeof(SharedResource);
            var assemblyName = new AssemblyName(type.GetTypeInfo().Assembly.FullName);
            _localizer = factory.Create(type);
            _localizer2 = factory.Create("SharedResource", assemblyName.Name);
        }       

        public IActionResult About()
        {
            ViewData["Message"] = _localizer["Your application description page."] 
                + " loc 2: " + _localizer2["Your application description page."];

En el código anterior se muestran los dos métodos factory.Create.

Puede dividir las cadenas localizadas por controlador o por área, o bien tener un solo contenedor. En la aplicación de ejemplo, se usa una clase ficticia denominada SharedResource para los recursos compartidos.

// Dummy class to group shared resources

namespace Localization
{
    public class SharedResource
    {
    }
}

Algunos programadores usan la clase Startup para contener cadenas globales o compartidas. En el ejemplo siguiente, se usan los localizadores InfoController y SharedResource:

public class InfoController : Controller
{
    private readonly IStringLocalizer<InfoController> _localizer;
    private readonly IStringLocalizer<SharedResource> _sharedLocalizer;

    public InfoController(IStringLocalizer<InfoController> localizer,
                   IStringLocalizer<SharedResource> sharedLocalizer)
    {
        _localizer = localizer;
        _sharedLocalizer = sharedLocalizer;
    }

    public string TestLoc()
    {
        string msg = "Shared resx: " + _sharedLocalizer["Hello!"] +
                     " Info resx " + _localizer["Hello!"];
        return msg;
    }

Localización de vista

El servicio IViewLocalizer proporciona cadenas localizadas para una vista. La clase ViewLocalizer implementa esta interfaz y busca la ubicación del recurso en la ruta de acceso del archivo de vista. En el código siguiente se muestra cómo usar la implementación predeterminada de IViewLocalizer:

@using Microsoft.AspNetCore.Mvc.Localization

@inject IViewLocalizer Localizer

@{
    ViewData["Title"] = Localizer["About"];
}
<h2>@ViewData["Title"].</h2>
<h3>@ViewData["Message"]</h3>

<p>@Localizer["Use this area to provide additional information."]</p>

La implementación predeterminada de IViewLocalizer busca el archivo de recursos según el nombre del archivo de vista. No se puede usar un archivo de recursos compartidos global. ViewLocalizer implementa el localizador mediante IHtmlLocalizer, por lo que Razor no codifica como HTML la cadena localizada. Puede parametrizar las cadenas de recursos y IViewLocalizer codificará como HTML los parámetros, pero no la cadena de recursos. Observe el siguiente marcado Razor:

@Localizer["<i>Hello</i> <b>{0}!</b>", UserManager.GetUserName(User)]

Un archivo de recursos en francés podría contener lo siguiente:

Key Valor
<i>Hello</i> <b>{0}!</b> <i>Bonjour</i> <b>{0} !</b>

La vista representada contendría el marcado HTML del archivo de recursos.

Nota

Por lo general, solo se localiza texto, no HTML.

Para usar un archivo de recursos compartido en una vista, inserte IHtmlLocalizer<T>:

@using Microsoft.AspNetCore.Mvc.Localization
@using Localization.Services

@inject IViewLocalizer Localizer
@inject IHtmlLocalizer<SharedResource> SharedLocalizer

@{
    ViewData["Title"] = Localizer["About"];
}
<h2>@ViewData["Title"].</h2>

<h1>@SharedLocalizer["Hello!"]</h1>

Localización de DataAnnotations

Los mensajes de error de DataAnnotations se localizan con IStringLocalizer<T>. Mediante la opción ResourcesPath = "Resources", es posible almacenar los mensajes de error en RegisterViewModel en cualquiera de las rutas de acceso siguientes:

  • Resources/ViewModels.Account.RegisterViewModel.fr.resx
  • Resources/ViewModels/Account/RegisterViewModel.fr.resx
public class RegisterViewModel
{
    [Required(ErrorMessage = "The Email field is required.")]
    [EmailAddress(ErrorMessage = "The Email field is not a valid email address.")]
    [Display(Name = "Email")]
    public string Email { get; set; }

    [Required(ErrorMessage = "The Password field is required.")]
    [StringLength(8, ErrorMessage = "The {0} must be at least {2} characters long.", MinimumLength = 6)]
    [DataType(DataType.Password)]
    [Display(Name = "Password")]
    public string Password { get; set; }

    [DataType(DataType.Password)]
    [Display(Name = "Confirm password")]
    [Compare("Password", ErrorMessage = "The password and confirmation password do not match.")]
    public string ConfirmPassword { get; set; }
}

Los atributos que no son de validación están localizados.

Uso de una cadena de recursos para varias clases

En el código siguiente se muestra cómo usar una cadena de recursos para atributos de validación con varias clases:

public void ConfigureServices(IServiceCollection services)
{
    services.AddMvc()
        .AddDataAnnotationsLocalization(options => {
            options.DataAnnotationLocalizerProvider = (type, factory) =>
                factory.Create(typeof(SharedResource));
        });
}

En el código anterior, SharedResource es la clase correspondiente al archivo resx donde se almacenan los mensajes de validación. Según este método, DataAnnotations solo usará SharedResource, en lugar del recurso de cada clase.

Proporcionar recursos localizados para los idiomas y las referencias culturales admitidos

SupportedCultures y SupportedUICultures

ASP.NET Core permite especificar dos valores de referencia cultural, SupportedCultures y SupportedUICultures. El objeto CultureInfo para SupportedCultures determina los resultados de funciones dependientes de la referencia cultural, como el formato de fecha, hora, número y moneda. SupportedCultures también determina el criterio de ordenación del texto, las convenciones sobre el uso de mayúsculas y minúsculas, y las comparaciones de cadenas. Para obtener más información sobre cómo el servidor obtiene la referencia cultural, vea CultureInfo.CurrentCulture y CultureInfo.CurrentUICulture. SupportedUICultures determina qué cadenas traducidas buscará ResourceManager (en archivos .resx). ResourceManager busca cadenas específicas de referencias culturales determinadas por CurrentUICulture. Todos los subprocesos de .NET tienen objetos CurrentCulture y CurrentUICulture. El marco inspecciona estos valores al representar funciones dependientes de la referencia cultural. Si la referencia cultural del subproceso actual está configurada como en-US (inglés, Estados Unidos), DateTime.Now.ToLongDateString() muestra Thursday, February 18, 2016; pero si CurrentCulture está configurada como es-ES (español, España), la salida es jueves, 18 de febrero de 2016.

Archivos de recursos

Un archivo de recursos es un mecanismo útil para separar del código las cadenas localizables. Las cadenas traducidas para el idioma no predeterminado están aisladas en archivos de recursos .resx. Pongamos por caso que quiere crear un archivo de recursos de español denominado Welcome.es.resx que contenga cadenas traducidas. "es" es el código de idioma para español. Para crear este archivo de recursos en Visual Studio:

  1. En el Explorador de soluciones, haga clic con el botón derecho en la carpeta que contendrá el archivo de recursos >Agregar>Nuevo elemento.

    Nested contextual menu: In Solution Explorer, a contextual menu is open for Resources. A second contextual menu is open for Add showing the New Item command highlighted.

  2. En el cuadro para buscar plantillas instaladas, escriba "recurso" y asigne un nombre al archivo.

    Add New Item dialog

  3. Escriba el valor de clave (cadena nativa) en la columna Nombre y la cadena traducida en la columna Valor.

    Welcome.es.resx file (the Welcome resource file for Spanish) with the word Hello in the Name column and the word Hola (Hello in Spanish) in the Value column

    El archivo Welcome.es.resx aparece en Visual Studio.

    Solution Explorer showing the Welcome Spanish (es) resource file

Nomenclatura de los archivos de recursos

El nombre de los recursos es el nombre del tipo completo de su clase menos el nombre del ensamblado. Por ejemplo, un recurso francés de un proyecto cuyo ensamblado principal sea LocalizationWebsite.Web.dll para la clase LocalizationWebsite.Web.Startup se denominará Startup.fr.resx. Un recurso para la clase LocalizationWebsite.Web.Controllers.HomeController se denominará Controllers.HomeController.fr.resx. Si el espacio de nombres de la clase de destino no es igual que el nombre del ensamblado, necesitará el nombre de tipo completo. Por ejemplo, en el proyecto de ejemplo, un recurso para el tipo ExtraNamespace.Tools se denominará ExtraNamespace.Tools.fr.resx.

En el proyecto de ejemplo, el método ConfigureServices establece ResourcesPath en "Resources", por lo que la ruta de acceso relativa del proyecto para el archivo de recursos en francés del controlador de inicio es Resources/Controllers.HomeController.fr.resx. También puede usar carpetas para organizar los archivos de recursos. Para el controlador de inicio, la ruta de acceso sería Resources/Controllers/HomeController.fr.resx. Si no usa la opción ResourcesPath, el archivo .resx estará en el directorio base del proyecto. El archivo de recursos para HomeController se denominará Controllers.HomeController.fr.resx. La opción de usar la convención de nomenclatura de punto o ruta de acceso depende de la manera en que quiera organizar los archivos de recursos.

Nombre del recurso Nomenclatura de punto o ruta de acceso
Resources/Controllers.HomeController.fr.resx Punto
Resources/Controllers/HomeController.fr.resx Ruta de acceso

Los archivos de recursos que usan @inject IViewLocalizer en las vistas de Razor siguen un patrón similar. Para asignar un nombre al archivo de recursos de una vista, se puede usar la nomenclatura de punto o de ruta de acceso. Los archivos de recursos de una vista de Razor imitan la ruta de acceso de su archivo de vista asociado. Supongamos que establecemos ResourcesPath en "Resources". En ese caso, el archivo de recursos de francés asociado a la vista Views/Home/About.cshtml podría ser uno de los siguientes:

  • Resources/Views/Home/About.fr.resx

  • Resources/Views.Home.About.fr.resx

Si no usa la opción ResourcesPath, el archivo .resx de una vista se ubicará en la misma carpeta que la vista.

RootNamespaceAttribute

El atributo RootNamespaceAttribute proporciona el espacio de nombres raíz de un ensamblado cuando el espacio de nombres raíz del ensamblado es diferente del nombre de ensamblado.

Advertencia

Esto puede ocurrir cuando el nombre de un proyecto no es un identificador de .NET válido. Por ejemplo my-project-name.csproj usará el espacio de nombres raíz my_project_name y el nombre de ensamblado my-project-name, lo que lleva a este error.

Si el espacio de nombres raíz de un ensamblado es diferente del nombre de ensamblado:

  • La localización no funciona de forma predeterminada.
  • Se produce un error en la localización debido a la manera en que se buscan los recursos dentro del ensamblado. RootNamespace es un valor en tiempo de compilación que no está disponible para el proceso en ejecución.

Si RootNamespace es diferente de AssemblyName, incluya lo siguiente en AssemblyInfo.cs (con los valores de parámetro reemplazados por los valores reales):

using System.Reflection;
using Microsoft.Extensions.Localization;

[assembly: ResourceLocation("Resource Folder Name")]
[assembly: RootNamespace("App Root Namespace")]

El código anterior permite la resolución correcta de los archivos resx.

Comportamiento de reserva de la referencia cultural

Cuando se busca un recurso, la localización entra en un proceso conocido como "reserva de la referencia cultural". Partiendo de la referencia cultural solicitada, si esta no se encuentra, se revierte a su referencia cultural principal correspondiente. Como inciso, decir que la propiedad CultureInfo.Parent representa la referencia cultural principal. Eso suele conllevar (aunque no siempre) la eliminación del significante nacional del código ISO. Así, por ejemplo, el dialecto de español hablado en México es "es-MX". Contiene el elemento principal "es", que corresponde a español no específico de ningún país en concreto.

Imagine que su sitio recibe una solicitud sobre un recurso "Welcome" donde se emplea la referencia cultural "fr-CA". El sistema de localización busca los recursos siguientes (en orden) y selecciona la primera coincidencia:

  • Welcome.fr-CA.resx
  • Welcome.fr.resx
  • Welcome.resx (si NeutralResourcesLanguage es "fr-CA")

Consideremos, por ejemplo, que quita el designador de referencia cultural ".fr" y la referencia cultural está establecida en francés. En ese caso, se lee el archivo de recursos predeterminado y se localizan las cadenas. El Administrador de recursos designa un recurso predeterminado o de reserva para los casos en que nada coincida con la referencia cultural solicitada. Si quiere simplemente devolver la clave cuando falte un recurso para la referencia cultural solicitada, no debe tener un archivo de recursos predeterminado.

Generar archivos de recursos con Visual Studio

Si crea un archivo de recursos en Visual Studio sin una referencia cultural en el nombre de archivo (por ejemplo, Welcome.resx), Visual Studio creará una clase de C# con una propiedad para cada cadena. Normalmente esto no interesa con ASP.NET Core; por lo general, no tendrá un archivo de recursos .resx predeterminado (un archivo .resx sin el nombre de la referencia cultural). Se recomienda que cree el archivo .resx con un nombre de referencia cultural (por ejemplo, Welcome.fr.resx). Cuando cree un archivo .resx con un nombre de referencia cultural, Visual Studio no generará el archivo de clase.

Agregar otras referencias culturales

Cada combinación de idioma y referencia cultural (que no sea el idioma predeterminado) requiere un archivo de recursos único. Para crear archivos de recursos para otras referencias culturales y configuraciones regionales, debe crear archivos de recursos en los que los códigos de idioma ISO formen parte del nombre de archivo (por ejemplo, en-us, fr-ca y en-gb). Estos códigos ISO se colocan entre el nombre de archivo y la extensión de archivo .resx, como en Welcome.es-MX.resx (español [México]).

Implementar una estrategia para seleccionar el idioma o la referencia cultural de cada solicitud

Configurar la localización

La localización se configura en el método Startup.ConfigureServices:

services.AddLocalization(options => options.ResourcesPath = "Resources");

services.AddMvc()
    .AddViewLocalization(LanguageViewLocationExpanderFormat.Suffix)
    .AddDataAnnotationsLocalization();
  • AddLocalization agrega los servicios de localización al contenedor de servicios. El código anterior también establece la ruta de acceso a los recursos en "Resources".

  • AddViewLocalization agrega compatibilidad con los archivos de vista localizados. En este ejemplo, la localización de vista se basa en el sufijo del archivo de vista. Por ejemplo, "fr" en el archivo Index.fr.cshtml.

  • AddDataAnnotationsLocalization agrega compatibilidad con mensajes de validación de DataAnnotations localizados mediante abstracciones IStringLocalizer.

Software intermedio de localización

La referencia cultural actual de una solicitud se establece en el software intermedio de localización. El software intermedio de localización se habilita en el método Startup.Configure. El middleware de localización debe configurarse antes que cualquier software intermedio que pueda comprobar la referencia cultural de la solicitud (por ejemplo, app.UseMvcWithDefaultRoute()). El middleware de localización debe aparecer después del middleware de enrutamiento si se usa RouteDataRequestCultureProvider. Para obtener más información sobre el orden del middleware, vea Middleware de ASP.NET Core.

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

app.UseRequestLocalization(localizationOptions);

Si quiere que los comentarios de código se traduzcan en más idiomas además del inglés, háganoslo saber en este problema de debate de GitHub.

UseRequestLocalization inicializa un objeto RequestLocalizationOptions. En todas las solicitudes, se enumera la lista de RequestCultureProvider en RequestLocalizationOptions y se usa el primer proveedor que puede determinar correctamente la referencia cultural de la solicitud. Los proveedores predeterminados proceden de la clase RequestLocalizationOptions:

  1. QueryStringRequestCultureProvider
  2. CookieRequestCultureProvider
  3. AcceptLanguageHeaderRequestCultureProvider

La lista predeterminada va de más específico a menos específico. Más adelante en el artículo veremos cómo puede cambiar el orden e incluso agregar un proveedor de referencia cultural personalizado. Si ninguno de los proveedores puede determinar la referencia cultural de la solicitud, se usa DefaultRequestCulture.

QueryStringRequestCultureProvider

Algunas aplicaciones usarán una cadena de consulta para establecer CultureInfo. Para las aplicaciones que usan el método de cookie o de encabezado Accept-Language, es útil agregar una cadena de consulta a la dirección URL para depurar y probar el código. De forma predeterminada, QueryStringRequestCultureProvider está registrado como primer proveedor de localización en la lista RequestCultureProvider. Debe pasar los parámetros de cadena de consulta culture y ui-culture. En el ejemplo siguiente, la referencia cultural específica (idioma y región) se establece en español (México):

http://localhost:5000/?culture=es-MX&ui-culture=es-MX

Si solo pasa uno de los dos parámetros (culture o ui-culture), el proveedor de la cadena de consulta usará el valor que usted ha pasado para establecer ambos valores. Por ejemplo, si solo establece la referencia cultural, se establecerán Culture y UICulture:

http://localhost:5000/?culture=es-MX

CookieRequestCultureProvider

Las aplicaciones de producción suelen proporcionar un mecanismo para establecer la referencia cultural con la cookie de la referencia cultural de ASP.NET Core. Use el método MakeCookieValue para crear una cookie.

CookieRequestCultureProviderDefaultCookieName devuelve el nombre de cookie predeterminado usado para realizar un seguimiento de la información de la referencia cultural preferida del usuario. El nombre de cookie predeterminado es .AspNetCore.Culture.

El formato de la cookie es c=%LANGCODE%|uic=%LANGCODE%, donde c es Culture y uic es UICulture, por ejemplo:

c=en-UK|uic=en-US

Si solo especifica uno de los dos valores, ya sea la información de la referencia cultural o la referencia cultural de la interfaz de usuario, la referencia cultural especificada se usará tanto para la información de la referencia cultural como para la referencia cultural de la interfaz de usuario.

Encabezado HTTP Accept-Language

El encabezado Accept-Language se puede establecer en la mayoría de los exploradores y está diseñado inicialmente para especificar el idioma del usuario. Este valor indica qué debe enviar el explorador o qué ha heredado del sistema operativo subyacente. El encabezado HTTP Accept-Language de una solicitud del explorador no es un método infalible para detectar el idioma preferido del usuario (vea Setting language preferences in a browser [Establecer las preferencias de idioma en un explorador]). Una aplicación de producción debe ofrecer al usuario una manera de personalizar su opción de referencia cultural.

Establecer el encabezado HTTP Accept-Language en Internet Explorer

  1. En el icono de engranaje, pulse Opciones de Internet.

  2. Haga clic en Lenguajes.

    Internet Options

  3. Haga clic en Establecer preferencias de idioma.

  4. Haga clic en Agregar un idioma.

  5. Agregue el idioma.

  6. Haga clic en el idioma y, después, en Subir.

Usar un proveedor personalizado

Imagine que quiere permitir que los clientes almacenen su idioma y su referencia cultural en las bases de datos. Puede escribir un proveedor para que busque estos valores para el usuario. En el código siguiente se muestra cómo agregar un proveedor personalizado:

private const string enUSCulture = "en-US";

services.Configure<RequestLocalizationOptions>(options =>
{
    var supportedCultures = new[]
    {
        new CultureInfo(enUSCulture),
        new CultureInfo("fr")
    };

    options.DefaultRequestCulture = new RequestCulture(culture: enUSCulture, uiCulture: enUSCulture);
    options.SupportedCultures = supportedCultures;
    options.SupportedUICultures = supportedCultures;

    options.AddInitialRequestCultureProvider(new CustomRequestCultureProvider(async context =>
    {
        // My custom request culture logic
        return await Task.FromResult(new ProviderCultureResult("en"));
    }));
});

Use RequestLocalizationOptions para agregar o quitar proveedores de localización.

Cambio del orden de los proveedores de referencia cultural de la solicitud

RequestLocalizationOptions tiene tres proveedores de referencia cultural para las solicitudes: QueryStringRequestCultureProvider, CookieRequestCultureProvider y AcceptLanguageHeaderRequestCultureProvider. Use la propiedad [RequestLocalizationOptions.RequestCultureProviders]](xref:Microsoft.AspNetCore.Builder.RequestLocalizationOptions.RequestCultureProviders) para cambiar el orden de estos proveedores, como se muestra a continuación:

    app.UseRequestLocalization(options =>
    {
        var questStringCultureProvider = options.RequestCultureProviders[0];    
        options.RequestCultureProviders.RemoveAt(0);
        options.RequestCultureProviders.Insert(1, questStringCultureProvider);
    });

En el ejemplo anterior, el orden de QueryStringRequestCultureProvider y CookieRequestCultureProvider está intercambiado, por lo que RequestLocalizationMiddleware busca primero las referencias culturales de cookie y, después, la cadena de consulta.

Como se mencionó anteriormente, la adición de un proveedor personalizado a través de AddInitialRequestCultureProvider establece el orden en 0, por lo que este proveedor tiene prioridad sobre los demás.

Establecer la referencia cultural mediante programación

Este proyecto Localization.StarterWeb de ejemplo de GitHub contiene una interfaz de usuario para establecer el valor Culture. El archivo Views/Shared/_SelectLanguagePartial.cshtml le permite seleccionar la referencia cultural de la lista de referencias culturales admitidas:

@using Microsoft.AspNetCore.Builder
@using Microsoft.AspNetCore.Http.Features
@using Microsoft.AspNetCore.Localization
@using Microsoft.AspNetCore.Mvc.Localization
@using Microsoft.Extensions.Options

@inject IViewLocalizer Localizer
@inject IOptions<RequestLocalizationOptions> LocOptions

@{
    var requestCulture = Context.Features.Get<IRequestCultureFeature>();
    var cultureItems = LocOptions.Value.SupportedUICultures
        .Select(c => new SelectListItem { Value = c.Name, Text = c.DisplayName })
        .ToList();
    var returnUrl = string.IsNullOrEmpty(Context.Request.Path) ? "~/" : $"~{Context.Request.Path.Value}";
}

<div title="@Localizer["Request culture provider:"] @requestCulture?.Provider?.GetType().Name">
    <form id="selectLanguage" asp-controller="Home" 
          asp-action="SetLanguage" asp-route-returnUrl="@returnUrl" 
          method="post" class="form-horizontal" role="form">
        <label asp-for="@requestCulture.RequestCulture.UICulture.Name">@Localizer["Language:"]</label> <select name="culture"
          onchange="this.form.submit();"
          asp-for="@requestCulture.RequestCulture.UICulture.Name" asp-items="cultureItems">
        </select>
    </form>
</div>

El archivo Views/Shared/_SelectLanguagePartial.cshtml se agrega a la sección footer del archivo de diseño para que esté disponible para todas las vistas:

<div class="container body-content" style="margin-top:60px">
    @RenderBody()
    <hr>
    <footer>
        <div class="row">
            <div class="col-md-6">
                <p>&copy; @System.DateTime.Now.Year - Localization</p>
            </div>
            <div class="col-md-6 text-right">
                @await Html.PartialAsync("_SelectLanguagePartial")
            </div>
        </div>
    </footer>
</div>

El método SetLanguage establece la cookie de la referencia cultural.

[HttpPost]
public IActionResult SetLanguage(string culture, string returnUrl)
{
    Response.Cookies.Append(
        CookieRequestCultureProvider.DefaultCookieName,
        CookieRequestCultureProvider.MakeCookieValue(new RequestCulture(culture)),
        new CookieOptions { Expires = DateTimeOffset.UtcNow.AddYears(1) }
    );

    return LocalRedirect(returnUrl);
}

No se puede conectar el archivo _SelectLanguagePartial.cshtml con código de ejemplo para este proyecto. El proyecto Localization.StarterWeb de GitHub tiene código para enviar RequestLocalizationOptions a una vista parcial de Razor a través del contenedor de inserción de dependencias.

Datos de ruta y cadenas de consulta de enlace de modelos

Vea Comportamiento de globalización de los datos de ruta de enlace de modelos y las cadenas de consulta.

Términos relacionados con la globalización y la localización

Para localizar una aplicación también es necesario contar con unos conocimientos básicos sobre los juegos de caracteres pertinentes que se usan en el desarrollo de software moderno y sobre los problemas asociados. Aunque todos los equipos almacenan texto como números (códigos), cada sistema almacena el mismo texto con números diferentes. El proceso de localización consiste en traducir la interfaz de usuario (IU) de la aplicación a una referencia cultural o configuración regional específica.

La localizabilidad es un proceso intermedio para comprobar que una aplicación globalizada está preparada para la localización.

El formato RFC 4646 para el nombre de la referencia cultural es <languagecode2>-<country/regioncode2>, donde <languagecode2> es el código de idioma y <country/regioncode2> es el código de la referencia cultural secundaria. Por ejemplo, es-CL para español (Chile), en-US para inglés (Estados Unidos) y en-AU para inglés (Australia). RFC 4646 es una combinación de un código de referencia cultural ISO 639 de dos letras en minúsculas asociado con un idioma y un código de referencia cultural secundaria ISO 3166 de dos letras en mayúsculas asociado con un país o región. Para más información, consulte System.Globalization.CultureInfo.

"Internacionalización" suele abreviarse como "I18N". La abreviatura toma la primera y la última letra de la palabra, y el número de letras que hay entre ellas, es decir, el 18 representa el número de letras que hay entre la "I" inicial y la "N" final. Lo mismo se puede decir de "globalización" (G11N) y "localización" (L10N).

Términos:

  • Globalización (G11N): es el proceso de hacer que una aplicación admita diferentes idiomas y regiones.
  • Localización (L10N): es el proceso de personalizar una aplicación para un idioma y región determinados.
  • Internacionalización (I18N): hace referencia a la globalización y la localización.
  • Referencia cultural: es un idioma y, opcionalmente, una región.
  • Referencia cultural neutra: se trata de una referencia cultural que tiene un idioma especificado, pero no una región. (por ejemplo, "en" y "es").
  • Referencia cultural específica: es una referencia cultural que tiene un idioma y una región especificados (por ejemplo, "en-US", "en-GB" y "es-CL").
  • Referencia cultural principal: se trata de la referencia cultural neutra que contiene una referencia cultural específica. (por ejemplo, "en" es la referencia cultural principal de "en-US" y "en-GB").
  • Configuración regional: la configuración regional es lo mismo que la referencia cultural.

Nota

Es posible que no pueda escribir comas decimales en campos decimales. Para que la validación de jQuery sea compatible con configuraciones regionales distintas del inglés que usan una coma (",") en lugar de un punto decimal y formatos de fecha distintos del de Estados Unidos, debe seguir unos pasos para globalizar la aplicación. Consulte este comentario 4076 de GitHub para instrucciones sobre cómo agregar la coma decimal.

Nota

Antes de ASP.NET Core 3.0, las aplicaciones escribían un registro de tipo LogLevel.Warning por solicitud si no se admitía la referencia cultural solicitada. El registro de un valor LogLevel.Warning por solicitud puede crear archivos de registro de gran tamaño con información redundante. Este comportamiento ha cambiado en ASP.NET 3.0. RequestLocalizationMiddleware escribe un registro de tipo LogLevel.Debug, lo que reduce el tamaño de los registros de producción.

Recursos adicionales