Tornar localizável o conteúdo de um aplicativo ASP.NET Core
Observação
Esta não é a versão mais recente deste artigo. Para informações sobre a versão vigente, confira a Versão do .NET 8 deste artigo.
Aviso
Esta versão do ASP.NET Core não tem mais suporte. Para obter mais informações, confira .NET e a Política de Suporte do .NET Core. Para informações sobre a versão vigente, confira a Versão do .NET 8 deste artigo.
Importante
Essas informações relacionam-se ao produto de pré-lançamento, que poderá ser substancialmente modificado antes do lançamento comercial. A Microsoft não oferece nenhuma garantia, explícita ou implícita, quanto às informações fornecidas aqui.
Para informações sobre a versão vigente, confira a Versão do .NET 8 deste artigo.
Por Hisham Bin Ateya, Damien Bowden, Bart Calixto e Nadeem Afana
Uma tarefa para localizar um aplicativo é encapsular o conteúdo localizável com código que facilita a substituição desse conteúdo por diferentes culturas.
IStringLocalizer
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 exemplo de código a seguir mostra como encapsular a cadeia de caracteres "Sobre o Título" 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ê desenvolve um aplicativo com seu idioma padrão e o prepara 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 preferem o fluxo de trabalho tradicional, pois pode ser mais fácil de trabalhar com literais de cadeia de caracteres longas e mais fácil de atualizar cadeias de caracteres localizadas.
IHtmlLocalizer
Use a implementação IHtmlLocalizer<TResource> 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. No código realçado a seguir, somente 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: de modo geral, localize apenas texto, não HTML.
IStringLocalizerFactory
No nível mais baixo, IStringLocalizerFactory pode ser recuperado da 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."];
return View();
}
O código anterior demonstra cada um dos dois métodos de criação de fábrica.
Recursos compartilhados
Você pode particionar as cadeias de caracteres localizadas por controlador, área ou ter apenas um contêiner. Na amostra de aplicativo, uma classe de marcador chamada SharedResource
é usada para recursos compartilhados. A classe de marcador nunca é chamada:
// Dummy class to group shared resources
namespace Localization;
public class SharedResource
{
}
No exemplo a seguir, 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 caracteres 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 os seguintes valores:
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.
De modo geral, localize apenas 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
using System.ComponentModel.DataAnnotations;
namespace Localization.ViewModels.Account;
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.
Como usar 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:
services.AddMvc()
.AddDataAnnotationsLocalization(options => {
options.DataAnnotationLocalizerProvider = (type, factory) =>
factory.Create(typeof(SharedResource));
});
No código anterior, SharedResource
é a classe correspondente ao arquivo .resx, em que as mensagens de validação são armazenadas. Com essa abordagem, DataAnnotations usa apenas SharedResource
, em vez do recurso para cada classe.
Configurar os serviços de localização
Os serviços de localização estão configurados em Program.cs
:
builder.Services.AddLocalization(options => options.ResourcesPath = "Resources");
builder.Services.AddMvc()
.AddViewLocalization(LanguageViewLocationExpanderFormat.Suffix)
.AddDataAnnotationsLocalization();
AddLocalization adiciona os serviços de localização ao contêiner de serviços, incluindo implementações para
IStringLocalizer<T>
eIStringLocalizerFactory
. O código anterior também define o caminho de recursos como "Resources".AddViewLocalization adiciona suporte para os arquivos de exibição localizados. Nesse exemplo, 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çõesIStringLocalizer
.
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. Confira o comentário 4076 do GitHub para obter instruções sobre como adicionar casas decimais.
Próximas etapas
A localização de um aplicativo também envolve as seguintes tarefas:
- Fornecer recursos localizados para as culturas e os idiomas aos quais o aplicativo dá suporte
- Implementar uma estratégia para selecionar o idioma e a cultura para cada solicitação
Recursos adicionais
- Provedor de cultura de URL usando o middleware como filtros no ASP.NET Core
- Aplicando o CultureProvider do RouteDataRequest globalmente com middleware como filtros
- Globalização e localização no ASP.NET Core
- Fornecer recursos localizados para idiomas e culturas em um aplicativo ASP.NET Core
- Estratégias para selecionar idioma e cultura em um aplicativo ASP.NET Core localizado
- Solucionar problemas de Localização no ASP.NET Core
- Globalizando e localizando aplicativos do .NET
- O projeto Localization.StarterWeb usado no artigo.
- Recursos em arquivos .resx
- Kit de Ferramentas de Aplicativo Multilíngue da Microsoft
- Localização e genéricos
Por Rick Anderson, Damien Bowden, Bart Calixto, Nadeem Afana e Hisham Bin Ateya
Uma tarefa para localizar um aplicativo é encapsular o conteúdo localizável com código que facilita a substituição desse conteúdo por diferentes culturas.
IStringLocalizer
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 exemplo de código a seguir mostra como encapsular a cadeia de caracteres "Sobre o Título" 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ê desenvolve um aplicativo com seu idioma padrão e o prepara 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 preferem o fluxo de trabalho tradicional, pois pode ser mais fácil de trabalhar com literais de cadeia de caracteres longas e mais fácil de atualizar cadeias de caracteres localizadas.
IHtmlLocalizer
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. No código realçado a seguir, somente 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.
IStringLocalizerFactory
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 anterior demonstra cada um dos dois métodos de criação de fábrica.
Recursos compartilhados
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. No exemplo a seguir, 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 caracteres 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 os seguintes valores:
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; }
}
No ASP.NET Core MVC 1.1.0 e versões posteriores, atributos que não sejam de validação são localizados.
Como usar 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 arquivo .resx, em que as mensagens de validação são armazenadas. Com essa abordagem, DataAnnotations usa apenas SharedResource
, em vez do recurso para cada classe.
Configurar os serviços de localização
Os serviços de localização são configurados 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, incluindo implementações paraIStringLocalizer<T>
eIStringLocalizerFactory
. O código anterior também define o caminho de recursos como "Resources".AddViewLocalization
adiciona suporte para os arquivos de exibição localizados. Nesse exemplo, a localização de exibição se baseia no sufixo do arquivo de exibição. Por exemplo, "fr" no arquivoIndex.fr.cshtml
.AddDataAnnotationsLocalization
adiciona suporte para as mensagens de validaçãoDataAnnotations
localizadas por meio de abstraçõesIStringLocalizer
.
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. Confira o comentário 4076 do GitHub para obter instruções sobre como adicionar casas decimais.
Próximas etapas
A localização de um aplicativo também envolve as seguintes tarefas:
- Fornecer recursos localizados para as culturas e os idiomas aos quais o aplicativo dá suporte
- Implementar uma estratégia para selecionar o idioma e a cultura para cada solicitação
Recursos adicionais
- Globalização e localização no ASP.NET Core
- Fornecer recursos localizados para idiomas e culturas em um aplicativo ASP.NET Core
- Estratégias para selecionar idioma e cultura em um aplicativo ASP.NET Core localizado
- Solucionar problemas de Localização no ASP.NET Core
- Globalizando e localizando aplicativos do .NET
- O projeto Localization.StarterWeb usado no artigo.
- Recursos em arquivos .resx
- Kit de Ferramentas de Aplicativo Multilíngue da Microsoft
- Localização e genéricos