Partilhar via


Tornar o conteúdo de um aplicativo ASP.NET Core localizável

Observação

Esta não é a versão mais recente deste artigo. Para a versão atual, consulte a versão .NET 10 deste artigo.

Advertência

Esta versão do ASP.NET Core não é mais suportada. Para obter mais informações, consulte a Política de suporte do .NET e do .NET Core. Para a versão atual, consulte a versão .NET 10 deste artigo.

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

Uma tarefa para localizar um aplicativo é encapsular conteúdo localizável com código que facilite a substituição desse conteúdo por diferentes culturas.

IStringLocalizer

IStringLocalizer e IStringLocalizer<T> foram arquitetados para melhorar a produtividade ao desenvolver aplicativos localizados. IStringLocalizer usa o ResourceManager e o ResourceReader para fornecer recursos da cultura específicos em tempo de execução. A interface tem um indexador e um IEnumerable para retornar cadeias de caracteres localizadas. IStringLocalizer não requer o armazenamento das cadeias de caracteres de idioma padrão em um arquivo de recurso. Você pode desenvolver um aplicativo direcionado para localização e não precisa criar arquivos de recursos no início do desenvolvimento.

O exemplo de código a seguir 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 IStringLocalizer<T> implementação vem de Injeção de dependência. Se o valor localizado de "About Title" não for encontrado, a chave do indexador será retornada, ou seja, a string "About Title".

Você pode deixar as cadeias de caracteres literais de idioma padrão no aplicativo e envolvê-las no localizador, para 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 programadores, o novo processo de trabalho de não ter um ficheiro .resx de idioma padrão e simplesmente encapsular as strings pode reduzir a sobrecarga de traduzir uma aplicação. Outros desenvolvedores preferem o fluxo de trabalho tradicional, pois pode ser mais fácil trabalhar com literais de texto longos e atualizar cadeias de texto localizadas.

IHtmlLocalizer

Use a IHtmlLocalizer<TResource> implementação para recursos que contêm HTML. IHtmlLocalizer Codifica em HTML os argumentos formatados na string de recurso, mas não codifica em HTML a própria string de recurso. No código realçado a seguir, somente o name valor do parâmetro é 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: Geralmente, localize apenas texto, não HTML.

IStringLocalizerFactory

No nível mais baixo, IStringLocalizerFactory pode ser obtido de 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 partilhados

Você pode particionar suas cadeias de caracteres localizadas por controlador ou área, ou ter apenas um contêiner. No aplicativo de exemplo, uma classe de marcador nomeada 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;
    }

Ver localização

O IViewLocalizer serviço fornece cadeias de caracteres localizadas para uma vista. A ViewLocalizer classe implementa essa interface e localiza o local do recurso a partir do caminho do arquivo de exibição. O código a seguir 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 ficheiro de recursos com base no nome do ficheiro da vista. Não há opção para usar um arquivo de recurso compartilhado global. ViewLocalizer implementa o localizador usando IHtmlLocalizer, portanto, Razor não codifica a cadeia de caracteres localizada em HTML. Você pode parametrizar cadeias de caracteres de recursos e IViewLocalizer HTML codifica os parâmetros, mas não a cadeia de caracteres de recurso. Considere a seguinte Razor marcação:

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

Um arquivo de recurso 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 conteria a marcação HTML do arquivo de recurso.

Geralmente, localize apenas texto, não HTML.

Para usar um arquivo de recurso compartilhado em um modo de 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 DataAnnotations são localizadas através de IStringLocalizer<T>. Usando a opção ResourcesPath = "Resources", as mensagens de erro em RegisterViewModel podem ser armazenadas em qualquer um dos seguintes caminhos:

  • Recursos/ViewModels.Account.RegisterViewModel.fr.resx
  • Recursos/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 não relacionados à validação são localizados.

Como usar uma cadeia de caracteres de recurso para várias classes

O código a seguir 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 onde as mensagens de validação são armazenadas. Com essa abordagem, DataAnnotations usa SharedResourceapenas , em vez do recurso para cada classe.

Configurar serviços de localização

Os serviços de localização sã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> e IStringLocalizerFactory. O código anterior também define o caminho de recursos como "Recursos".

  • AddViewLocalization Adiciona suporte para arquivos de exibição localizados. Neste exemplo, a localização da exibição é baseada no sufixo do arquivo de exibição. Por exemplo, "fr" no Index.fr.cshtml arquivo.

  • AddDataAnnotationsLocalization adiciona suporte a mensagens de validação localizadas DataAnnotations por meio de IStringLocalizer abstrações.

Observação

Talvez não seja possível inserir vírgulas decimais em campos decimais. Para dar suporte à validação do jQuery para localidades diferentes do inglês que usam uma vírgula (",") para um ponto decimal e formatos de data não US-English, você deve tomar medidas para globalizar seu aplicativo. Consulte este comentário 4076 do GitHub para obter instruções sobre como adicionar vírgula decimal.

Próximos passos

A localização de um aplicativo também envolve as seguintes tarefas:

Recursos adicionais

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

Uma tarefa para localizar um aplicativo é encapsular conteúdo localizável com código que facilite a substituição desse conteúdo por diferentes culturas.

IStringLocalizer

IStringLocalizer e IStringLocalizer<T> foram arquitetados para melhorar a produtividade ao desenvolver aplicativos localizados. IStringLocalizer usa o ResourceManager e o ResourceReader para fornecer recursos da cultura específicos em tempo de execução. A interface tem um indexador e um IEnumerable para retornar cadeias de caracteres localizadas. IStringLocalizer não requer o armazenamento das cadeias de caracteres de idioma padrão em um arquivo de recurso. Você pode desenvolver um aplicativo direcionado para localização e não precisa criar arquivos de recursos no início do desenvolvimento.

O exemplo de código a seguir 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 IStringLocalizer<T> implementação vem de Injeção de dependência. Se o valor localizado de "About Title" não for encontrado, a chave do indexador será retornada, ou seja, a string "About Title".

Você pode deixar as cadeias de caracteres literais de idioma padrão no aplicativo e envolvê-las no localizador, para 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 programadores, o novo processo de trabalho de não ter um ficheiro .resx de idioma padrão e simplesmente encapsular as strings pode reduzir a sobrecarga de traduzir uma aplicação. Outros desenvolvedores preferem o fluxo de trabalho tradicional, pois pode ser mais fácil trabalhar com literais de texto longos e atualizar cadeias de texto localizadas.

IHtmlLocalizer

Use a IHtmlLocalizer<T> implementação para recursos que contêm HTML. IHtmlLocalizer Codifica em HTML os argumentos formatados na string de recurso, mas não codifica em HTML a própria string de recurso. No código realçado a seguir, somente o name valor do parâmetro é 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

Geralmente, localize apenas texto, não HTML.

IStringLocalizerFactory

No nível mais baixo, você pode sair IStringLocalizerFactory 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."];

O código anterior demonstra cada um dos dois métodos de criação de fábrica.

Recursos partilhados

Você pode particionar suas cadeias de caracteres localizadas por controlador ou á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 Startup classe 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;
    }

Ver localização

O IViewLocalizer serviço fornece cadeias de caracteres localizadas para uma vista. A ViewLocalizer classe implementa essa interface e localiza o local do recurso a partir do caminho do arquivo de exibição. O código a seguir 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 ficheiro de recursos com base no nome do ficheiro da vista. Não há opção para usar um arquivo de recurso compartilhado global. ViewLocalizer implementa o localizador usando IHtmlLocalizer, portanto, Razor não codifica a cadeia de caracteres localizada em HTML. Você pode parametrizar cadeias de caracteres de recursos e IViewLocalizer HTML codifica os parâmetros, mas não a cadeia de caracteres de recurso. Considere a seguinte Razor marcação:

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

Um arquivo de recurso 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 conteria a marcação HTML do arquivo de recurso.

Observação

Geralmente, localize apenas texto, não HTML.

Para usar um arquivo de recurso compartilhado em um modo de 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 DataAnnotations são localizadas através de IStringLocalizer<T>. Usando a opção ResourcesPath = "Resources", as mensagens de erro em RegisterViewModel podem ser armazenadas em qualquer um dos seguintes caminhos:

  • Recursos/ViewModels.Account.RegisterViewModel.fr.resx
  • Recursos/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 ou posterior, os atributos não validados são localizados.

Como usar uma cadeia de caracteres de recurso para várias classes

O código a seguir 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 onde as mensagens de validação são armazenadas. Com essa abordagem, DataAnnotations usa SharedResourceapenas , em vez do recurso para cada classe.

Configurar serviços de localização

Os serviços de localização são configurados no Startup.ConfigureServices método:

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 para IStringLocalizer<T> e IStringLocalizerFactory. O código anterior também define o caminho de recursos como "Recursos".

  • AddViewLocalization Adiciona suporte para arquivos de exibição localizados. Neste exemplo, a localização da exibição é baseada no sufixo do arquivo de exibição. Por exemplo, "fr" no Index.fr.cshtml arquivo.

  • AddDataAnnotationsLocalization adiciona suporte a mensagens de validação localizadas DataAnnotations por meio de IStringLocalizer abstrações.

Observação

Talvez não seja possível inserir vírgulas decimais em campos decimais. Para dar suporte à validação do jQuery para localidades diferentes do inglês que usam uma vírgula (",") para um ponto decimal e formatos de data não US-English, você deve tomar medidas para globalizar seu aplicativo. Consulte este comentário 4076 do GitHub para obter instruções sobre como adicionar vírgula decimal.

Próximos passos

A localização de um aplicativo também envolve as seguintes tarefas:

Recursos adicionais