Globalização e localização no ASP.NET Core

Por Rick Anderson, Damien Bowden, Bart Calixto, Nadeem Afana e Hisham Bin Ateya

Um site multilíngue permite o alcance de um público mais amplo. O ASP.NET Core fornece serviços e middleware para localização em diferentes idiomas e culturas.

Termos

  • Globalização (G11N): o processo de fazer com que um aplicativo dê suporte a diferentes idiomas e regiões. A abreviação vem da primeira e última letras e do número de letras entre elas.
  • Localização (L10N): o processo de personalização de um aplicativo globalizado para idiomas e regiões específicos.
  • Internacionalização (I18N): descreve a globalização e a localização.
  • Cultura: um idioma e, opcionalmente, uma região.
  • Cultura neutra: uma cultura que tem um idioma especificado, mas não uma região (por exemplo "en", "es").
  • Cultura específica: uma cultura que tem um idioma e uma região especificados (por exemplo, "en-US", "en-GB", "es-CL").
  • Cultura pai: a cultura neutra que contém uma cultura específica (por exemplo, "en" é a cultura pai de "en-US" e "en-GB").
  • Localidade: uma localidade é o mesmo que uma cultura.

Idiomas e códigos de país/região

O formato RFC 4646 para o nome de cultura é <language code>-<country/region code>, em que <language code>identifica o idioma e <country/region code> identifica a subcultura. Por exemplo, es-CL para Espanhol (Chile), en-US para inglês (Estados Unidos) e en-AU para inglês (Austrália). O RFC 4646 é uma combinação de um código de cultura de duas letras minúsculas ISO 639 associado a um idioma e um código de subcultura de duas letras maiúsculas ISO 3166 associado a um país ou uma região. Para obter mais informações, consulte System.Globalization.CultureInfo.

Tarefas para localizar um aplicativo

A globalização e a localização de um aplicativo envolvem as seguintes tarefas:

Exibir ou baixar código de exemplo (como baixar)

Recursos adicionais

Por Rick Anderson, Damien Bowden, Bart Calixto, Nadeem Afana e Hisham Bin Ateya

Um site multilíngue permite o alcance de um público mais amplo. O ASP.NET Core fornece serviços e middleware para localização em diferentes idiomas e culturas.

Termos

  • Globalização (G11N): o processo de fazer com que um aplicativo dê suporte a diferentes idiomas e regiões. A abreviação vem da primeira e última letras e do número de letras entre elas.
  • Localização (L10N): o processo de personalização de um aplicativo globalizado para idiomas e regiões específicos.
  • Internacionalização (I18N): descreve a globalização e a localização.
  • Cultura: um idioma e, opcionalmente, uma região.
  • Cultura neutra: uma cultura que tem um idioma especificado, mas não uma região (por exemplo "en", "es").
  • Cultura específica: uma cultura que tem um idioma e uma região especificados (por exemplo, "en-US", "en-GB", "es-CL").
  • Cultura pai: a cultura neutra que contém uma cultura específica (por exemplo, "en" é a cultura pai de "en-US" e "en-GB").
  • Localidade: uma localidade é o mesmo que uma cultura.

Idiomas e códigos de país/região

O formato RFC 4646 para o nome de cultura é <language code>-<country/region code>, em que <language code>identifica o idioma e <country/region code> identifica a subcultura. Por exemplo, es-CL para Espanhol (Chile), en-US para inglês (Estados Unidos) e en-AU para inglês (Austrália). O RFC 4646 é uma combinação de um código de cultura de duas letras minúsculas ISO 639 associado a um idioma e um código de subcultura de duas letras maiúsculas ISO 3166 associado a um país ou uma região. Para obter mais informações, consulte System.Globalization.CultureInfo.

Tarefas para localizar um aplicativo

A globalização e a localização de um aplicativo envolvem as seguintes tarefas:

Exibir ou baixar código de exemplo (como baixar)

Recursos adicionais

Por Rick Anderson, Damien Bowden, Bart Calixto, Nadeem Afana e Hisham Bin Ateya

Um site multilíngue permite o alcance de um público mais amplo. O ASP.NET Core fornece serviços e middleware para localização em diferentes idiomas e culturas.

A internacionalização envolve System.Globalization e Localização. Globalização é o processo de criação de aplicativos que dão suporte a diferentes culturas. A globalização adiciona suporte para entrada, exibição e saída de um conjunto definido de scripts de idiomas relacionados a áreas geográficas específicas.

Localização é o processo de adaptar um aplicativo globalizado, que você já processou para possibilidade de localização, a determinada cultura/localidade. Para obter mais informações, consulte Termos de globalização e localização próximo ao final deste documento.

A localização de aplicativos envolve o seguinte:

  1. Tornar o conteúdo do aplicativo localizável
  2. Fornecer recursos localizados para as culturas e os idiomas aos quais você dá suporte
  3. Implementar uma estratégia para selecionar o idioma e a cultura para cada solicitação

Exibir ou baixar código de exemplo (como baixar)

Tornar o conteúdo do aplicativo localizável

IStringLocalizer e IStringLocalizer<T> foram projetados para melhorar a produtividade ao desenvolver aplicativos localizados. IStringLocalizer usa o ResourceManager e ResourceReader para fornecer recursos específicos à cultura em tempo de execução. A interface tem um indexador e um IEnumerable para retornar cadeias de caracteres localizadas. IStringLocalizer não exige o armazenamento das cadeias de caracteres de idioma padrão em um arquivo de recurso. Você pode desenvolver um aplicativo direcionado à localização e não precisa criar arquivos de recurso no início do desenvolvimento. O código abaixo mostra como encapsular a cadeia de caracteres "About Title" para localização.

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"];
        }
    }
}

No código anterior, a implementação IStringLocalizer<T> é obtida da Injeção de Dependência. Se o valor localizado de "About Title" não é encontrado, a chave do indexador é retornada, ou seja, a cadeia de caracteres "About Title". Deixe as cadeias de caracteres literais de idioma padrão no aplicativo e encapsule-as no localizador, de modo que você possa se concentrar no desenvolvimento do aplicativo. Você pode desenvolve seu aplicativo com o idioma padrão e prepará-lo para a etapa de localização sem primeiro criar um arquivo de recurso padrão. Como alternativa, você pode usar a abordagem tradicional e fornecer uma chave para recuperar a cadeia de caracteres de idioma padrão. Para muitos desenvolvedores, o novo fluxo de trabalho de não ter um arquivo .resx de idioma padrão e simplesmente encapsular os literais de cadeia de caracteres pode reduzir a sobrecarga de localizar um aplicativo. Outros desenvolvedores preferirão o fluxo de trabalho tradicional, pois ele pode facilitar o trabalho com literais de cadeia de caracteres mais longas e a atualização de cadeias de caracteres localizadas.

Use a implementação IHtmlLocalizer<T> para recursos que contêm HTML. O IHtmlLocalizer codifica em HTML os argumentos que são formatados na cadeia de caracteres de recurso, mas não codifica em HTML a cadeia de caracteres de recurso em si. Na amostra realçada abaixo, apenas o valor do parâmetro name é codificado em HTML.

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

Observação

No geral, apenas localize texto, não HTML.

No nível mais baixo, você pode obter IStringLocalizerFactory com a Injeção de Dependência:

{
    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."];

O código acima demonstra cada um dos dois métodos Create de alocador.

Você pode particionar as cadeias de caracteres localizadas por controlador, área ou ter apenas um contêiner. No aplicativo de exemplo, uma classe fictícia chamada SharedResource é usada para recursos compartilhados.

// Dummy class to group shared resources

namespace Localization
{
    public class SharedResource
    {
    }
}

Alguns desenvolvedores usam a classe Startup para conter cadeias de caracteres globais ou compartilhadas. Na amostra abaixo, os localizadores InfoController e SharedResource são usados:

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;
    }

Localização de exibição

O serviço IViewLocalizer fornece cadeias de caracteres localizadas para uma exibição. A classe ViewLocalizer implementa essa interface e encontra o local do recurso no caminho do arquivo de exibição. O seguinte código mostra como usar a implementação padrão 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>

A implementação padrão de IViewLocalizer encontra o arquivo de recurso com base no nome de arquivo da exibição. Não há nenhuma opção para usar um arquivo de recurso compartilhado global. ViewLocalizer implementa o localizador usando IHtmlLocalizer, portanto, o Razor não codifica em HTML a cadeia de caracteres localizada. Parametrize cadeias de recurso e o IViewLocalizer codificará em HTML os parâmetros, mas não a cadeia de caracteres de recurso. Considere a seguinte marcação Razor:

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

Um arquivo de recurso em francês pode conter o seguinte:

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

A exibição renderizada contém a marcação HTML do arquivo de recurso.

Observação

No geral, apenas localize texto, não HTML.

Para usar um arquivo de recurso compartilhado em uma exibição, injete 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>

Localização de DataAnnotations

As mensagens de erro de DataAnnotations são localizadas com IStringLocalizer<T>. Usando a opção ResourcesPath = "Resources", as mensagens de erro em RegisterViewModel podem ser armazenadas em um dos seguintes caminhos:

  • 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; }
}

Os atributos de não validação são localizados.

Usando uma cadeia de caracteres de recurso para várias classes

O seguinte código mostra como usar uma cadeia de caracteres de recurso para atributos de validação com várias classes:

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

No código anterior, SharedResource é a classe correspondente ao resx em que as mensagens de validação são armazenadas. Com essa abordagem, DataAnnotations usará apenas SharedResource, em vez de o recurso para cada classe.

Fornecer recursos localizados para as culturas e os idiomas aos quais você dá suporte

SupportedCultures e SupportedUICultures

O ASP.NET Core permite que você especifique dois valores de cultura, SupportedCultures e SupportedUICultures. O objeto CultureInfo para SupportedCultures determina os resultados das funções dependentes de cultura, como data, hora, número e formatação de moeda. SupportedCultures também determina a ordem de classificação de texto, convenções de uso de maiúsculas e comparações de cadeia de caracteres. Para obter mais informações sobre como o servidor obtém a cultura, consulte CultureInfo.CurrentCulture e CultureInfo.CurrentUICulture. O SupportedUICultures determina quais cadeias de caracteres traduzidas (de arquivos .resx) são pesquisadas pelo ResourceManager. O ResourceManager pesquisa cadeias de caracteres específicas a uma cultura determinadas por CurrentUICulture. Cada thread no .NET tem objetos CurrentCulture e CurrentUICulture. A estrutura inspeciona esses valores durante a renderização de funções dependentes de cultura. Se a cultura do thread atual estiver definida como en-US (inglês, Estados Unidos), DateTime.Now.ToLongDateString() exibirá Thursday, February 18, 2016; mas se CurrentCulture estiver definido como es-ES (espanhol, Espanha), a saída será jueves, 18 de febrero de 2016.

Arquivos de recurso

Um arquivo de recurso é um mecanismo útil para separar cadeias de caracteres localizáveis do código. As cadeias de caracteres traduzidas para o idioma não padrão são isoladas nos arquivos de recurso .resx. Por exemplo, talvez você queira criar um arquivo de recurso em espanhol chamado Welcome.es.resx contendo cadeias de caracteres traduzidas. "es" são o código de idioma para o espanhol. Para criar esse arquivo de recurso no Visual Studio:

  1. No Gerenciador de Soluções, clique com o botão direito do mouse na pasta que contenha o arquivo de recurso >Adicionar>Novo Item.

    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. Na caixa Pesquisar modelos instalados, insira "recurso" e nomeie o arquivo.

    Add New Item dialog

  3. Insira o valor da chave (cadeia de caracteres nativa) na coluna Nome e a cadeia de caracteres traduzida na coluna 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

    O Visual Studio mostra o arquivo Welcome.es.resx.

    Solution Explorer showing the Welcome Spanish (es) resource file

Nomenclatura do arquivo de recurso

Os recursos são nomeados com o nome completo do tipo de sua classe menos o nome do assembly. Por exemplo, um recurso em francês em um projeto cujo assembly principal é LocalizationWebsite.Web.dll para a classe LocalizationWebsite.Web.Startup será nomeado Startup.fr.resx. Um recurso para a classe LocalizationWebsite.Web.Controllers.HomeController será nomeado Controllers.HomeController.fr.resx. Se o namespace da classe de destino não for o mesmo que o nome do assembly, você precisará do nome completo do tipo. Por exemplo, no projeto de exemplo, um recurso para o tipo ExtraNamespace.Tools será nomeado ExtraNamespace.Tools.fr.resx.

No projeto de exemplo, o método ConfigureServices define o ResourcesPath como "Resources", de modo que o caminho relativo do projeto para o arquivo de recurso em francês do controlador principal seja Resources/Controllers.HomeController.fr.resx. Como alternativa, você pode usar pastas para organizar arquivos de recurso. Para o controlador principal, o caminho será Resources/Controllers/HomeController.fr.resx. Se você não usar a opção ResourcesPath, o arquivo .resx entrará no diretório base do projeto. O arquivo de recurso para HomeController será nomeado Controllers.HomeController.fr.resx. A opção de usar a convenção de nomenclatura de ponto ou caminho depende de como você deseja organizar os arquivos de recurso.

Nome do recurso Nomenclatura de ponto ou caminho
Resources/Controllers.HomeController.fr.resx Ponto
Resources/Controllers/HomeController.fr.resx Caminho

Os arquivos de recurso que usam @inject IViewLocalizer em exibições do Razor seguem um padrão semelhante. O arquivo de recurso de uma exibição pode ser nomeado usando a nomenclatura de ponto ou de caminho. Os arquivos de recurso da exibição do Razor simulam o caminho de seu arquivo de exibição associado. Supondo que definimos o ResourcesPath como "Resources", o arquivo de recurso em francês associado à exibição Views/Home/About.cshtml pode ser um dos seguintes:

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

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

Se você não usar a opção ResourcesPath, o arquivo .resx de uma exibição estará localizado na mesma pasta da exibição.

RootNamespaceAttribute

O atributo RootNamespaceAttribute fornece o namespace raiz de um assembly quando o namespace raiz de um assembly é diferente do nome do assembly.

Aviso

Isso pode ocorrer quando o nome de um projeto não for um identificador .NET válido. Por exemplo, my-project-name.csproj usará o namespace raiz my_project_name e o nome do assembly my-project-name que gera esse erro.

Se o namespace raiz de um assembly é diferente do nome do assembly:

  • A localização não funciona por padrão.
  • A localização falha devido à maneira como os recursos são pesquisados dentro do assembly. RootNamespace é um valor de tempo de build que não está disponível para o processo em execução.

Se o RootNamespace é diferente de AssemblyName, inclua o seguinte no AssemblyInfo.cs (com valores de parâmetro substituídos pelos valores reais):

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

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

O código anterior permite a resolução bem-sucedida de arquivos resx.

Comportamento de fallback da cultura

Ao procurar por um recurso, a localização participa do "fallback de cultura". Começando com a cultura solicitada, se ela não for encontrada, ela será revertida para a cultura pai dessa cultura. Além disso, a propriedade CultureInfo.Parent representa a cultura pai. Isso normalmente (mas nem sempre) significa a remoção do significante do ISO. Por exemplo, o dialeto do espanhol falado no México é "es-MX". Ele tem o pai "es", ou seja, espanhol, não específico de nenhum país.

Imagine que seu site receba uma solicitação de um recurso “Boas-vindas" usando a cultura"fr-CA". O sistema de localização procura os seguintes recursos, em ordem, e seleciona a primeira correspondência:

  • Welcome.fr-CA.resx
  • Welcome.fr.resx
  • Welcome.resx (se o NeutralResourcesLanguage for "fr-CA")

Por exemplo, se você remover o designador de cultura ".fr" e tiver a cultura definida como francês, o arquivo de recurso padrão será lido e as cadeias de caracteres serão localizadas. O Gerenciador de Recursos designa um padrão ou um recurso de fallback para quando nenhuma opção atende à cultura solicitada. Se você deseja apenas retornar a chave quando um recurso está ausente para a cultura solicitada, não deve ter um arquivo de recurso padrão.

Gerar arquivos de recurso com o Visual Studio

Se você criar um arquivo de recurso no Visual Studio sem uma cultura no nome do arquivo (por exemplo, Welcome.resx), o Visual Studio criará uma classe do C# com uma propriedade para cada cadeia de caracteres. Geralmente isso não é o desejado com o ASP.NET Core. Normalmente você não tem um arquivo de recurso .resx padrão (um arquivo .resx sem o nome de cultura). Sugerimos que você crie o arquivo .resx com um nome de cultura (por exemplo Welcome.fr.resx). Quando você criar um arquivo .resx com um nome de cultura, o Visual Studio não gerará o arquivo de classe.

Adicionar outras culturas

Cada combinação de idioma e cultura (que não seja o idioma padrão) exige um arquivo de recurso exclusivo. Crie arquivos de recurso para diferentes culturas e localidades criando novos arquivos de recurso, nos quais os códigos ISO e de idioma fazem parte do nome do arquivo (por exemplo, en-us, fr-ca e en-gb). Esses códigos ISO são colocados entre o nome do arquivo e a extensão de arquivo .resx, como em Welcome.es-MX.resx (espanhol/México).

Implementar uma estratégia para selecionar o idioma e a cultura para cada solicitação

Configurar a localização

A localização é configurada no método Startup.ConfigureServices:

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

services.AddMvc()
    .AddViewLocalization(LanguageViewLocationExpanderFormat.Suffix)
    .AddDataAnnotationsLocalization();
  • AddLocalization adiciona os serviços de localização ao contêiner de serviços. O código acima também define o caminho de recursos como "Resources".

  • AddViewLocalization Adiciona suporte para os arquivos de exibição localizados. Nesta amostra, a localização de exibição se baseia no sufixo do arquivo de exibição. Por exemplo, "fr" no arquivo Index.fr.cshtml.

  • AddDataAnnotationsLocalization Adiciona suporte para as mensagens de validação DataAnnotations localizadas por meio de abstrações IStringLocalizer.

Middleware de localização

A cultura atual em uma solicitação é definida no Middleware de localização. O middleware de localização é habilitado no método Startup.Configure. O middleware de localização precisa ser configurado antes de qualquer middleware que possa verificar a cultura de solicitação (por exemplo, app.UseMvcWithDefaultRoute()). O middleware de localização deve aparecer após o Middleware de Roteamento se estiver usando RouteDataRequestCultureProvider. Para obter mais informações a ordem do middleware, veja Middleware do ASP.NET Core.

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

app.UseRequestLocalization(localizationOptions);

Se você quiser ver os comentários de código traduzidos para idiomas diferentes do inglês, informe-nos neste problema de discussão do GitHub.

UseRequestLocalization inicializa um objeto RequestLocalizationOptions. Em cada solicitação, a lista de RequestCultureProvider em RequestLocalizationOptions é enumerada e o primeiro provedor que pode determinar com êxito a cultura de solicitação é usado. Os provedores padrão são obtidos da classe RequestLocalizationOptions:

  1. QueryStringRequestCultureProvider
  2. CookieRequestCultureProvider
  3. AcceptLanguageHeaderRequestCultureProvider

A lista padrão é apresentada do mais específico ao menos específico. Mais adiante neste artigo, veremos como você pode alterar a ordem e até mesmo adicionar um provedor de cultura personalizado. Se nenhum dos provedores pode determinar a cultura de solicitação, o DefaultRequestCulture é usado.

QueryStringRequestCultureProvider

Alguns aplicativos usarão uma cadeia de caracteres de consulta para definir a CultureInfo. Para aplicativos que usam a abordagem do cabeçalho Accept-Language ou cookie, a adição de uma cadeia de caracteres de consulta à URL é útil para depurar e testar o código. Por padrão, o QueryStringRequestCultureProvider é registrado como o primeiro provedor de localização na lista RequestCultureProvider. Passe os parâmetros culture e ui-culture da cadeia de caracteres de consulta. O seguinte exemplo define a cultura específica (idioma e região) como espanhol/México:

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

Se você passar somente uma das duas (culture ou ui-culture), o provedor da cadeia de caracteres de consulta definirá os dois valores usando aquela que foi passada. Por exemplo, a definição apenas da cultura definirá a Culture e a UICulture:

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

CookieRequestCultureProvider

Em geral, aplicativos de produção fornecerão um mecanismo para definir a cultura com cookie de cultura do ASP.NET Core. Use o método MakeCookieValue para criar um cookie.

O CookieRequestCultureProviderDefaultCookieName retorna o nome padrão do cookieusado para acompanhar as informações de cultura preferencial do usuário. O nome padrão cookie é .AspNetCore.Culture.

O formato do cookie é c=%LANGCODE%|uic=%LANGCODE%, em que c é Culture e uic é UICulture, por exemplo:

c=en-UK|uic=en-US

Se você especificar apenas as informações de cultura e a cultura da interface do usuário, a cultura especificada será usada para as informações de cultura e para a cultura da interface do usuário.

O cabeçalho HTTP Accept-Language

O cabeçalho Accept-Language é configurável na maioria dos navegadores e originalmente foi criado para especificar o idioma do usuário. Essa configuração indica que o navegador foi definido para enviar ou herdou do sistema operacional subjacente. O cabeçalho HTTP Accept-Language de uma solicitação do navegador não é uma maneira infalível de detectar o idioma preferencial do usuário (consulte Definindo preferências de idioma em um navegador). Um aplicativo de produção deve incluir uma maneira para que um usuário personalize sua opção de cultura.

Definir o cabeçalho HTTP Accept-Language no IE

  1. No ícone de engrenagem, toque em Opções da Internet.

  2. Toque em Idiomas.

    Internet Options

  3. Toque em Definir Preferências de Idioma.

  4. Toque em Adicionar um idioma.

  5. Adicione o idioma.

  6. Toque no idioma e, em seguida, em Mover Para Cima.

Usar um provedor personalizado

Suponha que você deseje permitir que os clientes armazenem seus idiomas e culturas nos bancos de dados. Você pode escrever um provedor para pesquisar esses valores para o usuário. O seguinte código mostra como adicionar um provedor 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 adicionar ou remover provedores de localização.

Alterar a ordem dos provedores de cultura de solicitação

RequestLocalizationOptions tem três provedores de cultura de solicitação padrão: QueryStringRequestCultureProvider, CookieRequestCultureProvider e AcceptLanguageHeaderRequestCultureProvider. Use a propriedade [RequestLocalizationOptions.RequestCultureProviders]](xref:Microsoft.AspNetCore.Builder.RequestLocalizationOptions.RequestCultureProviders) para alterar a ordem desses provedores, conforme mostrado abaixo:

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

No exemplo anterior, a ordem de QueryStringRequestCultureProvider e CookieRequestCultureProvider é trocada, portanto, o RequestLocalizationMiddleware procura as culturas dos cookies primeiros e, em seguida, a cadeia de caracteres de consulta.

Como mencionado anteriormente, adicione um provedor personalizado por meio do AddInitialRequestCultureProvider, que define a ordem para 0, para esse provedor tenha precedência sobre os outros.

Definir a cultura de forma programática

Este projeto de exemplo Localization.StarterWeb no GitHub contém a interface do usuário para definir a Culture. O arquivo Views/Shared/_SelectLanguagePartial.cshtml permite que você selecione a cultura na lista de culturas compatíveis:

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

O arquivo Views/Shared/_SelectLanguagePartial.cshtml é adicionado à seção footer do arquivo de layout para que ele fique disponível para todos os exibições:

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

O método SetLanguage define o cookie de cultura.

[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);
}

Não é possível conectar o _SelectLanguagePartial.cshtml ao código de exemplo para este projeto. O projeto Localization.StarterWeb no GitHub contém o código para o fluxo do RequestLocalizationOptions para uma parcial do Razor por meio do contêiner de Injeção de Dependência.

Dados de rota de dados e cadeias de caracteres de consulta

Confira Comportamento de globalização de dados de rota e cadeias de caracteres de consulta de model binding.

Termos de globalização e localização

O processo de localização do aplicativo também exige uma compreensão básica dos conjuntos de caracteres relevantes geralmente usados no desenvolvimento moderno de software e uma compreensão dos problemas associados a eles. Embora todos os computadores armazenem texto como números (códigos), diferentes sistemas armazenam o mesmo texto usando números diferentes. O processo de localização se refere à tradução da interface do usuário do aplicativo para uma cultura/localidade específica.

Possibilidade de localização é um processo intermediário usado para verificar se um aplicativo globalizado está pronto para localização.

O formato RFC 4646 para o nome de cultura é <languagecode2>-<country/regioncode2>, em que <languagecode2> é o código de idioma e <country/regioncode2> é o código de subcultura. Por exemplo, es-CL para Espanhol (Chile), en-US para inglês (Estados Unidos) e en-AU para inglês (Austrália). O RFC 4646 é uma combinação de um código de cultura de duas letras minúsculas ISO 639 associado a um idioma e um código de subcultura de duas letras maiúsculas ISO 3166 associado a um país ou uma região. Para obter mais informações, consulte System.Globalization.CultureInfo.

Muitas vezes, internacionalização é abreviada como "I18N". A abreviação usa a primeira e última letras e o número de letras entre elas e, portanto, 18 significa o número de letras entre o primeiro "I" e o último "N". O mesmo se aplica a Globalização (G11N) e Localização (L10N).

Termos:

  • Globalização (G11N): o processo de fazer com que um aplicativo dê suporte a diferentes idiomas e regiões.
  • Localização (L10N): o processo de personalizar um aplicativo para determinado idioma e região.
  • Internacionalização (I18N): descreve a globalização e a localização.
  • Cultura: um idioma e, opcionalmente, uma região.
  • Cultura neutra: uma cultura que tem um idioma especificado, mas não uma região. (por exemplo, "en", "es")
  • Cultura específica: uma cultura que tem um idioma e uma região especificados. (por exemplo, "en-US", "en-GB", "es-CL")
  • Cultura pai: a cultura neutra que contém uma cultura específica. (por exemplo, "en" é a cultura pai de "en-US" e "en-GB")
  • Localidade: uma localidade é o mesmo que uma cultura.

Observação

Talvez você não consiga inserir vírgulas decimais em campos decimais. Para dar suporte à validação do jQuery para localidades de idiomas diferentes do inglês que usam uma vírgula (“,”) para um ponto decimal e formatos de data diferentes do inglês dos EUA, você deve tomar medidas para globalizar o aplicativo. Consulte o comentário 4076 do GitHub para obter instruções sobre como adicionar casas decimais.

Observação

Nas versões anteriores do ASP.NET Core 3.0, os aplicativos Web gravam um log do tipo LogLevel.Warning por solicitação se a cultura solicitada não tiver suporte. Registrar um LogLevel.Warning por solicitação pode aumentar demasiadamente os arquivos de log com informações redundantes. Esse comportamento foi alterado no ASP.NET 3.0. O RequestLocalizationMiddleware grava um log do tipo LogLevel.Debug, que reduz o tamanho dos logs de produção.

Recursos adicionais