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

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.

Este artigo explica como renderizar conteúdo globalizado e localizado para usuários em diferentes culturas e idiomas.

Globalização e localização

Para globalização, o Blazor oferece formatação de número e data. Para localização, o Blazor renderiza o conteúdo com o sistema de recursos do .NET.

Um conjunto limitado de recursos de localização do ASP.NET Core tem compatibilidade:

Suporte: IStringLocalizer e IStringLocalizer<T> são suportados em aplicativos Blazor.

Sem suporte: IHtmlLocalizer, IViewLocalizer, e a localização de Anotações de Dados são recursos do ASP.NET Core MVC e não tem suporte em Blazor aplicativos.

Este artigo descreve como usar os recursos de globalização e localização do Blazor com base:

  • no Accept-Languagecabeçalho, que é definido pelas preferências de idioma do usuário no navegador.
  • em uma cultura definida pelo aplicativo que não se baseia no valor do Accept-Languagecabeçalho. A configuração pode ser estática para todos os usuários ou dinâmica com base na lógica do aplicativo. Quando a configuração é baseada na preferência do usuário, geralmente é salva para recarregar em visitas futuras.

Para saber mais informações gerais, confira estes artigos:

Muitas vezes, os termos idioma e cultura são usados de forma intercambiável ao falar sobre os conceitos de globalização e localização.

Neste artigo, idioma se refere às seleções feitas por um usuário nas configurações do navegador. As seleções de idioma do usuário são enviadas em solicitações do navegador no Accept-Language cabeçalho. Geralmente, as configurações do navegador usam a palavra "idioma" na interface do usuário.

Cultura diz respeito aos membros do .NET e da API Blazor. Por exemplo, a solicitação de um usuário pode incluir o Accept-Language cabeçalho com a especificação de um idioma na perspectiva do usuário. Mas, em última análise, o aplicativo define a propriedade CurrentCulture ("cultura") no idioma solicitado pelo usuário. Normalmente, a API usa a palavra "cultura" nos nomes dos membros.

As orientações nesse artigo não abrangem a configuração do atributo de idioma HTML da página (<html lang="...">), usado pelas ferramentas de acessibilidade. Você pode definir o valor estaticamente atribuindo um idioma ao atributo lang da tag <html> ou a document.documentElement.lang em JavaScript. Você pode definir dinamicamente o valor de document.documentElement.lang com JS interop.

Observação

Os exemplos de código neste artigo adotam NRTs (tipos de referência anuláveis) e análise estática de estado nulo do compilador do .NET, que têm suporte no ASP.NET Core no .NET 6 ou posterior. Para o ASP.NET Core 5.0 ou anterior, remova a designação de tipo nulo (?) dos exemplos do artigo.

Globalização

A diretiva do atributo @bind aplica formatos e analisa valores para exibição com base no primeiro idioma preferencial do usuário disponível no aplicativo. @bind é compatível com o parâmetro @bind:culture a fim de fornecer System.Globalization.CultureInfo para análise e formatação de um valor.

É possível acessar a cultura atual na propriedade System.Globalization.CultureInfo.CurrentCulture.

CultureInfo.InvariantCulture é usado para os seguintes tipos de campo (<input type="{TYPE}" />, em que o espaço reservado {TYPE} é o tipo):

  • date
  • number

Os tipos de campo anteriores:

  • São exibidos com as regras de formatação apropriadas do navegador.
  • Não podem conter texto de forma livre.
  • Fornecem características de interação do usuário com base na implementação do navegador.

Blazor fornece suporte interno para renderizar valores na cultura atual. Portanto, especificar uma cultura com @bind:culture não é recomendado ao usar os tipos de campo date e number.

Os seguintes tipos de campos têm requisitos de formatação específicos e não possuem suporte atualmente nos maiores navegadores, então não possuem suporte no Blazor:

  • datetime-local
  • month
  • week

Para saber a compatibilidade do navegador atual com esses tipos, confira Posso usar.

Suporte à globalização do .NET e a ICU (Componentes Internacionais para Unicode) (Blazor WebAssembly)

O Blazor WebAssembly usa uma API de globalização reduzida e um conjunto de localidades internas dos Componentes Internacionais para Unicode (ICU). Para saber mais, confira Globalização e ICU do .NET: ICU no WebAssembly.

Para carregar um arquivo de dados de ICU personalizado para controlar as localidades do aplicativo, consulte ICU de Globalização do WASM. Atualmente, é necessário criar manualmente o arquivo de dados de ICU personalizado. As ferramentas do .NET para facilitar o processo de criação do arquivo estão previstas para o .NET 9 em novembro de 2024.

O Blazor WebAssembly usa uma API de globalização reduzida e um conjunto de localidades internas dos Componentes Internacionais para Unicode (ICU). Para saber mais, confira Globalização e ICU do .NET: ICU no WebAssembly.

Há suporte para o carregamento de um subconjunto personalizado de localidades em um aplicativo Blazor WebAssembly no .NET 8 ou posterior. Para obter mais informações, acesse esta seção para uma versão 8.0 ou posterior deste artigo.

Globalização invariável

Esta seção se aplica somente a cenários Blazor do lado do cliente.

Se o aplicativo não exigir localização, configure-o para aceitar a cultura invariável, que geralmente se baseia em Estados Unidos Inglês (en-US). O uso da globalização invariável reduz o tamanho do download do aplicativo e resulta em uma inicialização mais rápida do aplicativo. Defina a propriedade InvariantGlobalization para true no arquivo de projeto do aplicativo (.csproj):

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

Como alternativa, configure a globalização invariável com as seguintes abordagens:

  • No runtimeconfig.json:

    {
      "runtimeOptions": {
        "configProperties": {
          "System.Globalization.Invariant": true
        }
      }
    }
    
  • Com uma variável de ambiente:

    • Chave: DOTNET_SYSTEM_GLOBALIZATION_INVARIANT
    • Valor: true ou 1

Para saber mais, confira Opções de configuração de execução para globalização (documentação do .NET).

Informações de fuso horário

Esta seção se aplica somente a cenários Blazor do lado do cliente.

A adoção da globalização invariável resulta apenas no uso de nomes de fuso horário não localizados. Para aparar os dados e o código de fuso horário, o que reduz o tamanho do download do aplicativo e resulta em uma inicialização mais rápida do aplicativo, aplique a propriedade MSBuild <InvariantTimezone> com um valor de true no arquivo de projeto do aplicativo:

<PropertyGroup>
  <InvariantTimezone>true</InvariantTimezone>
</PropertyGroup>

Observação

<BlazorEnableTimeZoneSupport> substitui uma configuração <InvariantTimezone> anterior. Recomendamos remover a configuração <BlazorEnableTimeZoneSupport>.

Um arquivo de dados é incluído para corrigir as informações de fuso horário. Se o aplicativo não exigir esse recurso, desabilite-o definindo a propriedade MSBuild <BlazorEnableTimeZoneSupport> no arquivo de projeto do aplicativo como false:

<PropertyGroup>
  <BlazorEnableTimeZoneSupport>false</BlazorEnableTimeZoneSupport>
</PropertyGroup>

Componente de demonstração

É possível usar o componente CultureExample1 para demonstrar os conceitos de globalização e localização no Blazor abordados neste artigo.

CultureExample1.razor:

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

<h1>Culture Example 1</h1>

<ul>
    <li><b>CurrentCulture</b>: @CultureInfo.CurrentCulture</li>
    <li><b>CurrentUICulture</b>: @CultureInfo.CurrentUICulture</li>
</ul>

<h2>Rendered values</h2>

<ul>
    <li><b>Date</b>: @dt</li>
    <li><b>Number</b>: @number.ToString("N2")</li>
</ul>

<h2><code>&lt;input&gt;</code> elements that don't set a <code>type</code></h2>

<p>
    The following <code>&lt;input&gt;</code> elements use
    <code>CultureInfo.CurrentCulture</code>.
</p>

<ul>
    <li><label><b>Date:</b> <input @bind="dt" /></label></li>
    <li><label><b>Number:</b> <input @bind="number" /></label></li>
</ul>

<h2><code>&lt;input&gt;</code> elements that set a <code>type</code></h2>

<p>
    The following <code>&lt;input&gt;</code> elements use
    <code>CultureInfo.InvariantCulture</code>.
</p>

<ul>
    <li><label><b>Date:</b> <input type="date" @bind="dt" /></label></li>
    <li><label><b>Number:</b> <input type="number" @bind="number" /></label></li>
</ul>

@code {
    private DateTime dt = DateTime.Now;
    private double number = 1999.69;
}

O formato de cadeia de caracteres numérica (N2) no exemplo anterior (.ToString("N2")) é um especificador de formato numérico padrão do .NET. O formato N2 é compatível com todos os tipos numéricos, inclui um separador de grupo e renderiza até duas casas decimais.

Existe a opção de adicionar um item de menu à navegação no componente NavMenu (NavMenu.razor) para o componente CultureExample1.

Definir dinamicamente a cultura do cabeçalho Accept-Language

Adicione o pacote Microsoft.Extensions.Localization ao aplicativo.

O cabeçalho Accept-Language é definido pelo navegador e controlado pelas preferências de idioma do usuário nas configurações do navegador. Nas configurações do navegador, um usuário define um ou mais idiomas favoritos em ordem de preferência. A ordem de preferência é usada pelo navegador para definir valores de qualidade (q, 0-1) para cada idioma no cabeçalho. O seguinte exemplo especifica inglês dos Estados Unidos, inglês e espanhol costarriquenho com preferência por inglês dos Estados Unidos ou inglês:

Accept-Language: en-US,en;q=0.9,es-CR;q=0.8

A cultura do aplicativo é definida pela combinação com o primeiro idioma solicitado que corresponde a uma cultura disponível no aplicativo.

No desenvolvimento do lado do cliente, defina a propriedade BlazorWebAssemblyLoadAllGlobalizationData como true no arquivo de projeto do aplicativo do lado do cliente (.csproj):

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

No desenvolvimento do lado do cliente, não há suporte para definir dinamicamente a cultura do cabeçalho Accept-Language.

Observação

Se a especificação do aplicativo exigir a limitação do número de culturas compatíveis a uma lista explícita, confira a seção Definir dinamicamente a cultura por preferência do usuário deste artigo.

Os aplicativos são localizados usando o Middleware de Localização. Adicione serviços de localização ao aplicativo com AddLocalization.

Adicione a seguinte linha ao arquivo Program em que os serviços são registrados:

builder.Services.AddLocalization();

No desenvolvimento do lado do servidor, especifique as culturas com suporte do aplicativo antes de qualquer middleware que possa verificar a cultura de solicitação. Geralmente, coloque o Request Localization Middleware imediatamente antes de chamar MapRazorComponentso . O seguinte exemplo configura culturas compatíveis com inglês dos Estados Unidos e espanhol costarriquenho:

No desenvolvimento do lado do servidor, especifique as culturas com suporte do aplicativo imediatamente após o Middleware de Roteamento (UseRouting) ser adicionado ao pipeline de processamento. O seguinte exemplo configura culturas compatíveis com inglês dos Estados Unidos e espanhol costarriquenho:

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

Para saber mais sobre como ordenar o middleware de localização no pipeline de middleware do arquivo Program, confira Middleware do ASP.NET Core.

Use o componente CultureExample1 mostrado na seção Componente de demonstração para estudar como a globalização funciona. Faça uma solicitação com inglês dos Estados Unidos (en-US). Altere para espanhol costarriquenho (es-CR) nas configurações de idioma do navegador. Solicite a página da Web novamente.

Observação

Alguns navegadores forçam você a usar a configuração de idioma padrão para solicitações e as próprias configurações de interface do usuário do navegador. Isso pode dificultar a alteração do idioma para um que você entenda, porque todas as telas de configuração da interface do usuário podem acabar em um idioma que você não consegue ler. Um navegador como o Opera é uma boa opção para teste porque permite que você defina um idioma padrão para solicitações de página da Web, mas deixe a interface do usuário de configurações do navegador em seu idioma.

Quando a cultura é inglês dos Estados Unidos (en-US), o componente renderizado usa formatação de data de mês/dia (6/7), hora de 12 horas (AM/PM) e separadores de vírgulas em números com um ponto para o valor decimal (1,999.69):

  • Data: 6/7/2021 6:45:22 AM
  • Número: 1,999.69

Quando a cultura é espanhol costarriquenho (es-CR), o componente renderizado usa formatação de data de dia/mês (7/6), hora de 24 horas e separadores de período em números com uma vírgula para o valor decimal (1.999,69):

  • Data: 7/6/2021 6:49:38
  • Número: 1.999,69

Definir estaticamente a cultura do lado do cliente

Defina a propriedade BlazorWebAssemblyLoadAllGlobalizationData para true no arquivo de projeto do aplicativo (.csproj):

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

A configuração do vinculador de IL (linguagem intermediária) para renderização do lado do cliente remove as informações de internacionalização, exceto nas localidades solicitadas explicitamente. Para obter mais informações, confira Configurar o vinculador para Blazor do ASP.NET Core.

A cultura do aplicativo pode ser definida em JavaScript quando o Blazor começa com a opção applicationCultureBlazor de início. O exemplo a seguir configura o aplicativo para iniciar usando a cultura inglês do Estados Unidos (en-US).

Evite o início automático do Blazor adicionando autostart="false" à marca <script> de Blazor:

<script src="{BLAZOR SCRIPT}" autostart="false"></script>

No exemplo anterior, o espaço reservado {BLAZOR SCRIPT} é o caminho de script Blazor e o nome do arquivo. Para obter a localização do script, confira a estrutura do projeto ASP.NET Core Blazor.

Adicione o bloco <script> a seguir após a marca <script> de Blazor e antes de fechar a marca </body>:

Blazor Web App:

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

Blazor WebAssembly autônomo:

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

O valor de applicationCulture deve estar em conformidade com o formato de tag de idioma BCP-47. Para obter mais informações sobre a inicialização de Blazor, veja Inicialização de Blazor no ASP.NET Core.

Uma alternativa para definir a opção de início da cultura no Blazor é definir a cultura no código C#. Defina CultureInfo.DefaultThreadCurrentCulture e CultureInfo.DefaultThreadCurrentUICulture no arquivo Program para a mesma cultura.

Adicione o namespace System.Globalization ao arquivo Program:

using System.Globalization;

Adicione as configurações de cultura antes da linha que cria e executa o WebAssemblyHostBuilder (await builder.Build().RunAsync();):

CultureInfo.DefaultThreadCurrentCulture = new CultureInfo("en-US");
CultureInfo.DefaultThreadCurrentUICulture = new CultureInfo("en-US");

Observação

Atualmente, os aplicativos Blazor WebAssembly só carregam recursos baseados em DefaultThreadCurrentCulture. Para obter mais informações, confira Blazor O WASM depende apenas da cultura atual (a cultura atual da interface do usuário não é respeitada) (dotnet/aspnetcore nº 56824).

Use o componente CultureExample1 mostrado na seção Componente de demonstração para estudar como a globalização funciona. Faça uma solicitação com inglês dos Estados Unidos (en-US). Altere para espanhol costarriquenho (es-CR) nas configurações de idioma do navegador. Solicite a página da Web novamente. Quando o idioma solicitado é espanhol costarriquenho, a cultura do aplicativo permanece como inglês dos Estados Unidos (en-US).

Definir estaticamente a cultura do lado do servidor

Os aplicativos do lado do servidor são localizados usando o Middleware de localização. Adicione serviços de localização ao aplicativo com AddLocalization.

No arquivo Program:

builder.Services.AddLocalization();

Especifique a cultura estática no Program arquivo antes de qualquer middleware que possa verificar a cultura de solicitação. Geralmente, coloque o Request Localization Middleware imediatamente antes MapRazorComponentsde . O exemplo a seguir configura inglês dos Estados Unidos:

Especifique a cultura estática no arquivo imediatamente após o Program Middleware de Roteamento (UseRouting) ser adicionado ao pipeline de processamento. O exemplo a seguir configura inglês dos Estados Unidos:

app.UseRequestLocalization("en-US");

O valor da cultura para UseRequestLocalization precisa estar em conformidade com o formato de tag de idioma BCP-47.

Para saber mais sobre como ordenar o middleware de localização no pipeline de middleware do arquivo Program, confira Middleware do ASP.NET Core.

Os aplicativos do lado do servidor são localizados usando o Middleware de localização. Adicione serviços de localização ao aplicativo com AddLocalization.

Em Startup.ConfigureServices (Startup.cs):

services.AddLocalization();

Especifique a cultura estática em Startup.Configure (Startup.cs) imediatamente após o middleware de roteamento ser adicionado ao pipeline de processamento. O exemplo a seguir configura inglês dos Estados Unidos:

app.UseRequestLocalization("en-US");

O valor da cultura para UseRequestLocalization precisa estar em conformidade com o formato de tag de idioma BCP-47.

Para saber mais sobre como ordenar o middleware de localização no pipeline de middleware de Startup.Configure, confira Middleware do ASP.NET Core.

Use o componente CultureExample1 mostrado na seção Componente de demonstração para estudar como a globalização funciona. Faça uma solicitação com inglês dos Estados Unidos (en-US). Altere para espanhol costarriquenho (es-CR) nas configurações de idioma do navegador. Solicite a página da Web novamente. Quando o idioma solicitado é espanhol costarriquenho, a cultura do aplicativo permanece como inglês dos Estados Unidos (en-US).

Definir dinamicamente a cultura do lado do cliente por preferência do usuário

Exemplos de locais em que um aplicativo pode armazenar a preferência de um usuário incluem: em um armazenamento local no navegador (comum em uma renderização do lado do cliente), em uma localização cookie ou banco de dados (comum para cenários do lado do servidor) ou em um serviço externo anexado a um banco de dados externo e acessado por uma API web. O exemplo a seguir demonstra como usar o armazenamento local do navegador.

Adicione o pacote Microsoft.Extensions.Localization ao aplicativo.

Observação

Para obter diretrizes sobre como adicionar pacotes a aplicativos .NET, consulte os artigos em Instalar e gerenciar pacotes no Fluxo de trabalho de consumo de pacotes (documentação do NuGet). Confirme as versões corretas de pacote em NuGet.org.

Defina a propriedade BlazorWebAssemblyLoadAllGlobalizationData para true no arquivo de projeto:

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

A cultura do aplicativo para renderização do lado do cliente é definida usando a API da estrutura Blazor. A seleção de cultura de um usuário pode ser mantida no armazenamento local do navegador.

Forneça funções JS após a marca <script> de Blazor para obter e definir a seleção de cultura do usuário com o armazenamento local do navegador:

<script>
  window.blazorCulture = {
    get: () => window.localStorage['BlazorCulture'],
    set: (value) => window.localStorage['BlazorCulture'] = value
  };
</script>

Observação

O exemplo anterior polui o cliente com funções globais. Para obter uma abordagem melhor em aplicativos de produção, confira Isolamento de JavaScript em módulos JavaScript.

Adicione os namespaces para System.Globalization e Microsoft.JSInterop na parte superior do arquivo Program:

using System.Globalization;
using Microsoft.JSInterop;

Remova a seguinte linha:

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

Substitua a linha anterior pelo código a seguir. O código adiciona o serviço de localização do Blazor à coleção de serviços do aplicativo com AddLocalization e usa a JSinteroperabilidade para chamar o JS e recuperar a seleção de cultura do usuário do armazenamento local. Se o armazenamento local não contiver uma cultura para o usuário, o código definirá um valor padrão de inglês dos Estados Unidos (en-US).

builder.Services.AddLocalization();

var host = builder.Build();

const string defaultCulture = "en-US";

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

if (result == null)
{
    await js.InvokeVoidAsync("blazorCulture.set", defaultCulture);
}

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

await host.RunAsync();

Observação

Atualmente, os aplicativos Blazor WebAssembly só carregam recursos baseados em DefaultThreadCurrentCulture. Para obter mais informações, confira Blazor O WASM depende apenas da cultura atual (a cultura atual da interface do usuário não é respeitada) (dotnet/aspnetcore nº 56824).

O componente CultureSelector a seguir mostra como realizar as seguintes ações:

  • Defina a seleção de cultura do usuário no armazenamento local do navegador pela interoperabilidade do JS.
  • Recarregue o componente solicitado (forceLoad: true), que usa a cultura atualizada.

CultureSelector.razor:

@using System.Globalization
@inject IJSRuntime JS
@inject NavigationManager Navigation

<p>
    <label>
        Select your locale:
        <select @bind="selectedCulture" @bind:after="ApplySelectedCultureAsync">
            @foreach (var culture in supportedCultures)
            {
                <option value="@culture">@culture.DisplayName</option>
            }
        </select>
    </label>
</p>

@code
{
    private CultureInfo[] supportedCultures = new[]
    {
        new CultureInfo("en-US"),
        new CultureInfo("es-CR"),
    };

    private CultureInfo? selectedCulture;

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

    private async Task ApplySelectedCultureAsync()
    {
        if (CultureInfo.CurrentCulture != selectedCulture)
        {
            await JS.InvokeVoidAsync("blazorCulture.set", selectedCulture!.Name);

            Navigation.NavigateTo(Navigation.Uri, forceLoad: true);
        }
    }
}
@using System.Globalization
@inject IJSRuntime JS
@inject NavigationManager Navigation

<p>
    <label>
        Select your locale:
        <select value="@selectedCulture" @onchange="HandleSelectedCultureChanged">
            @foreach (var culture in supportedCultures)
            {
                <option value="@culture">@culture.DisplayName</option>
            }
        </select>
    </label>
</p>

@code
{
    private CultureInfo[] supportedCultures = new[]
    {
        new CultureInfo("en-US"),
        new CultureInfo("es-CR"),
    };

    private CultureInfo? selectedCulture;

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

    private async Task HandleSelectedCultureChanged(ChangeEventArgs args)
    {
        selectedCulture = CultureInfo.GetCultureInfo((string)args.Value!);

        if (CultureInfo.CurrentCulture != selectedCulture)
        {
            await JS.InvokeVoidAsync("blazorCulture.set", selectedCulture!.Name);

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

Dentro da marca de fechamento do elemento </main> no componente MainLayout (MainLayout.razor), adicione o componente CultureSelector:

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

Use o componente CultureExample1 mostrado na seção Componente de demonstração para estudar como o exemplo anterior funciona.

Definir dinamicamente a cultura do lado do servidor por preferência do usuário

Exemplos de locais em que um aplicativo pode armazenar a preferência de um usuário incluem: em um armazenamento local no navegador (comum em uma renderização do lado do cliente), em uma localização cookie ou banco de dados (comum para cenários do lado do servidor) ou em um serviço externo anexado a um banco de dados externo e acessado por uma API web. O exemplo a seguir demonstra como usar o cookie de localização.

Observação

O exemplo a seguir pressupõe que o aplicativo adote interatividade global especificando a renderização interativa do lado do servidor (SSR interativa) no componente Routes no componente App (Components/App.razor):

<Routes @rendermode="InteractiveServer" />

Se o aplicativo adotar a interatividade por página/componente, consulte as observações no final desta seção para modificar os modos de renderização dos componentes do exemplo.

Adicione o pacote Microsoft.Extensions.Localization ao aplicativo.

Observação

Para obter diretrizes sobre como adicionar pacotes a aplicativos .NET, consulte os artigos em Instalar e gerenciar pacotes no Fluxo de trabalho de consumo de pacotes (documentação do NuGet). Confirme as versões corretas de pacote em NuGet.org.

Os aplicativos do lado do servidor são localizados usando o Middleware de localização. Adicione serviços de localização ao aplicativo com AddLocalization.

No arquivo Program:

builder.Services.AddLocalization();

Defina as culturas padrão e compatível do aplicativo com RequestLocalizationOptions.

Antes da chamada para MapRazorComponents no pipeline de processamento de solicitação, insira o seguinte código:

Depois que o Middleware de Roteamento (UseRouting) for adicionado ao pipeline de processamento de solicitações, coloque o seguinte código:

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

app.UseRequestLocalization(localizationOptions);

Para saber mais sobre como ordenar o middleware de localização no pipeline de middleware, confira Middleware do ASP.NET Core.

O exemplo a seguir mostra como definir a cultura atual em um cookie que pode ser lido pelo middleware de localização.

Os namespaces a seguir são necessários para o componente App:

Adicione o seguinte na parte superior do arquivo do App componente (Components/App.razor):

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

Adicione o seguinte bloco de @code na parte inferior do arquivo do componente App:

@code {
    [CascadingParameter]
    public HttpContext? HttpContext { get; set; }

    protected override void OnInitialized()
    {
        HttpContext?.Response.Cookies.Append(
            CookieRequestCultureProvider.DefaultCookieName,
            CookieRequestCultureProvider.MakeCookieValue(
                new RequestCulture(
                    CultureInfo.CurrentCulture,
                    CultureInfo.CurrentUICulture)));
    }
}

As modificações no arquivo Pages/_Host.cshtml exigem estes namespaces:

Adicione o seguinte ao arquivo:

@using System.Globalization
@using Microsoft.AspNetCore.Localization
@{
    this.HttpContext.Response.Cookies.Append(
        CookieRequestCultureProvider.DefaultCookieName,
        CookieRequestCultureProvider.MakeCookieValue(
            new RequestCulture(
                CultureInfo.CurrentCulture,
                CultureInfo.CurrentUICulture)));
}

Para saber mais sobre como ordenar o middleware de localização no pipeline de middleware, confira Middleware do ASP.NET Core.

Se o aplicativo não estiver configurado para processar ações do controlador:

  • Adicione serviços MVC chamando AddControllers na coleção de serviços no arquivo Program:

    builder.Services.AddControllers();
    
  • Adicione o roteamento do ponto de extremidade do controlador no arquivo Program chamando MapControllers no IEndpointRouteBuilder (app):

    app.MapControllers();
    

Para que a interface do usuário permita selecionar uma cultura, use uma abordagem baseada em redirecionamento com um cookie de localização. O aplicativo persiste a cultura selecionada pelo usuário por meio de um redirecionamento para um controlador. O controlador define a cultura selecionada pelo usuário em um cookie e redireciona o usuário de volta para o URI original. O processo é semelhante ao que acontece em um aplicativo Web quando um usuário tenta acessar um recurso seguro e é redirecionado para uma página de entrada e, em seguida, enviado de volta ao recurso original.

Controllers/CultureController.cs:

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

[Route("[controller]/[action]")]
public class CultureController : Controller
{
    public IActionResult Set(string culture, string redirectUri)
    {
        if (culture != null)
        {
            HttpContext.Response.Cookies.Append(
                CookieRequestCultureProvider.DefaultCookieName,
                CookieRequestCultureProvider.MakeCookieValue(
                    new RequestCulture(culture, culture)));
        }

        return LocalRedirect(redirectUri);
    }
}

Aviso

Use o resultado da ação LocalRedirect, conforme mostrado no exemplo anterior, para evitar ataques de redirecionamento abertos. Para obter mais informações, confira Impedir ataques de redirecionamento em aberto no ASP.NET Core.

O componente CultureSelector a seguir mostra como chamar o método Set do CultureController com a nova cultura. O componente Shared é colocado na pasta para uso em todo o aplicativo.

CultureSelector.razor:

@using System.Globalization
@inject IJSRuntime JS
@inject NavigationManager Navigation

<p>
    <label>
        Select your locale:
        <select @bind="selectedCulture" @bind:after="ApplySelectedCultureAsync">
            @foreach (var culture in supportedCultures)
            {
                <option value="@culture">@culture.DisplayName</option>
            }
        </select>
    </label>
</p>

@code
{
    private CultureInfo[] supportedCultures = new[]
    {
        new CultureInfo("en-US"),
        new CultureInfo("es-CR"),
    };

    private CultureInfo? selectedCulture;

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

    private async Task ApplySelectedCultureAsync()
    {
        if (CultureInfo.CurrentCulture != selectedCulture)
        {
            var uri = new Uri(Navigation.Uri)
                .GetComponents(UriComponents.PathAndQuery, UriFormat.Unescaped);
            var cultureEscaped = Uri.EscapeDataString(selectedCulture.Name);
            var uriEscaped = Uri.EscapeDataString(uri);

            Navigation.NavigateTo(
                $"Culture/Set?culture={cultureEscaped}&redirectUri={uriEscaped}",
                forceLoad: true);
        }
    }
}
@using System.Globalization
@inject IJSRuntime JS
@inject NavigationManager Navigation

<p>
    <label>
        Select your locale:
        <select value="@selectedCulture" @onchange="HandleSelectedCultureChanged">
            @foreach (var culture in supportedCultures)
            {
                <option value="@culture">@culture.DisplayName</option>
            }
        </select>
    </label>
</p>

@code
{
    private CultureInfo[] supportedCultures = new[]
    {
        new CultureInfo("en-US"),
        new CultureInfo("es-CR"),
    };

    private CultureInfo? selectedCulture;

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

    private async Task HandleSelectedCultureChanged(ChangeEventArgs args)
    {
        selectedCulture = CultureInfo.GetCultureInfo((string)args.Value!);

        if (CultureInfo.CurrentCulture != selectedCulture)
        {
            var uri = new Uri(Navigation.Uri)
                .GetComponents(UriComponents.PathAndQuery, UriFormat.Unescaped);
            var cultureEscaped = Uri.EscapeDataString(selectedCulture.Name);
            var uriEscaped = Uri.EscapeDataString(uri);

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

Adicione o componente CultureSelector ao componente MainLayout. Insira a seguinte marcação na marca do </main> de fechamento no arquivo Components/Layout/MainLayout.razor:

Adicione o componente CultureSelector ao componente MainLayout. Insira a seguinte marcação na marca do </main> de fechamento no arquivo Shared/MainLayout.razor:

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

Use o componente CultureExample1 mostrado na seção Componente de demonstração para estudar como o exemplo anterior funciona.

O exemplo anterior pressupõe que o aplicativo adote interatividade global especificando o modo de renderização do Servidor Interativo no componente Routes no componente App ( Components/App.razor ):

<Routes @rendermode="InteractiveServer" />

Se o aplicativo adotar a interatividade por página/componente, faça as seguintes alterações:

  • Adicione o modo de renderização do Servidor Interativo à parte superior do arquivo de componente CultureExample1 (Components/Pages/CultureExample1.razor):

    @rendermode InteractiveServer
    
  • No layout principal do aplicativo (Components/Layout/MainLayout.razor), aplique o modo de renderização do Servidor Interativo ao componente CultureSelector :

    <CultureSelector @rendermode="InteractiveServer" />
    

Definir de forma dinâmica a cultura em um Blazor Web App por preferência do usuário

Esta seção se aplica a Blazor Web Apps que adotam interatividade automática (Servidor e WebAssembly).

Exemplos de locais em que um aplicativo pode armazenar a preferência de um usuário incluem: em um armazenamento local no navegador (comum em cenários do lado do cliente), em um cookie ou banco de dados de localização (comum para cenários do lado do servidor), armazenamento local e um cookie de localização (Blazor Web Apps com servidor e componentes de WebAssembly), ou em um serviço externo anexado a um banco de dados externo e acessado por uma API Web. O exemplo a seguir demonstra como usar o armazenamento local do navegador para componentes CSR (renderizados do lado do cliente) e uma localização cookie para componentes SSR (renderizados no lado do servidor).

Atualizações ao projeto .Client

Adicione o pacote Microsoft.Extensions.Localization ao projeto .Client.

Observação

Para obter diretrizes sobre como adicionar pacotes a aplicativos .NET, consulte os artigos em Instalar e gerenciar pacotes no Fluxo de trabalho de consumo de pacotes (documentação do NuGet). Confirme as versões corretas de pacote em NuGet.org.

Defina a propriedade BlazorWebAssemblyLoadAllGlobalizationData para true no arquivo de projeto .Client:

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

Adicione os namespaces para System.Globalization e Microsoft.JSInterop na parte superior do arquivo Program do projeto .Client:

using System.Globalization;
using Microsoft.JSInterop;

Remova a seguinte linha:

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

Substitua a linha anterior pelo código a seguir. O código adiciona o serviço de localização do Blazor à coleção de serviços do aplicativo com AddLocalization e usa a JSinteroperabilidade para chamar o JS e recuperar a seleção de cultura do usuário do armazenamento local. Se o armazenamento local não contiver uma cultura para o usuário, o código definirá um valor padrão de inglês dos Estados Unidos (en-US).

builder.Services.AddLocalization();

var host = builder.Build();

const string defaultCulture = "en-US";

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

if (result == null)
{
    await js.InvokeVoidAsync("blazorCulture.set", defaultCulture);
}

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

await host.RunAsync();

Observação

Atualmente, os aplicativos Blazor WebAssembly só carregam recursos baseados em DefaultThreadCurrentCulture. Para obter mais informações, confira Blazor O WASM depende apenas da cultura atual (a cultura atual da interface do usuário não é respeitada) (dotnet/aspnetcore nº 56824).

Adicione o componente CultureSelector a seguir ao projeto .Client.

O componente adota as seguintes abordagens para funcionar para componentes SSR ou CSR:

  • O nome de exibição de cada cultura disponível na lista suspensa é fornecido por um dicionário porque os dados de globalização do lado do cliente incluem texto localizado de nomes de exibição de cultura fornecidos pelos dados de globalização do lado do servidor. Por exemplo, a localização do lado do servidor exibe English (United States) quando a cultura é en-US e Ingles () quando uma cultura diferente é usada. Como a localização dos nomes de exibição de cultura não está disponível com a globalização do Blazor WebAssembly, o nome de exibição do inglês dos Estados Unidos no cliente para qualquer cultura carregada é apenas en-US. O uso de um dicionário personalizado permite que o componente pelo menos exiba nomes de cultura em inglês completos.
  • Quando o usuário altera a cultura, a interoperabilidade JS define a cultura no armazenamento do navegador local e uma ação do controlador atualiza o cookie de localização com a cultura. O controlador é adicionado ao aplicativo posteriormente na seção de Atualizações de projeto do servidor.

Pages/CultureSelector.razor:

@using System.Globalization
@inject IJSRuntime JS
@inject NavigationManager Navigation

<p>
    <label>
        Select your locale:
        <select @bind="@selectedCulture" @bind:after="ApplySelectedCultureAsync">
            @foreach (var culture in supportedCultures)
            {
                <option value="@culture">@cultureDict[culture.Name]</option>
            }
        </select>
    </label>
</p>

@code
{
    private Dictionary<string, string> cultureDict = 
        new()
        {
            { "en-US", "English (United States)" },
            { "es-CR", "Spanish (Costa Rica)" }
        };

    private CultureInfo[] supportedCultures = new[]
    {
        new CultureInfo("en-US"),
        new CultureInfo("es-CR"),
    };

    private CultureInfo? selectedCulture;

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

    private async Task ApplySelectedCultureAsync()
    {
        if (CultureInfo.CurrentCulture != selectedCulture)
        {
            await JS.InvokeVoidAsync("blazorCulture.set", selectedCulture!.Name);

            var uri = new Uri(Navigation.Uri)
                .GetComponents(UriComponents.PathAndQuery, UriFormat.Unescaped);
            var cultureEscaped = Uri.EscapeDataString(selectedCulture.Name);
            var uriEscaped = Uri.EscapeDataString(uri);

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

No projeto .Client, coloque o componente CultureClient a seguir para estudar como a globalização funciona para componentes de CSR.

Pages/CultureClient.razor:

@page "/culture-client"
@rendermode InteractiveWebAssembly
@using System.Globalization

<PageTitle>Culture Client</PageTitle>

<h1>Culture Client</h1>

<ul>
    <li><b>CurrentCulture</b>: @CultureInfo.CurrentCulture</li>
    <li><b>CurrentUICulture</b>: @CultureInfo.CurrentUICulture</li>
</ul>

<h2>Rendered values</h2>

<ul>
    <li><b>Date</b>: @dt</li>
    <li><b>Number</b>: @number.ToString("N2")</li>
</ul>

<h2><code>&lt;input&gt;</code> elements that don't set a <code>type</code></h2>

<p>
    The following <code>&lt;input&gt;</code> elements use
    <code>CultureInfo.CurrentCulture</code>.
</p>

<ul>
    <li><label><b>Date:</b> <input @bind="dt" /></label></li>
    <li><label><b>Number:</b> <input @bind="number" /></label></li>
</ul>

<h2><code>&lt;input&gt;</code> elements that set a <code>type</code></h2>

<p>
    The following <code>&lt;input&gt;</code> elements use
    <code>CultureInfo.InvariantCulture</code>.
</p>

<ul>
    <li><label><b>Date:</b> <input type="date" @bind="dt" /></label></li>
    <li><label><b>Number:</b> <input type="number" @bind="number" /></label></li>
</ul>

@code {
    private DateTime dt = DateTime.Now;
    private double number = 1999.69;
}

Atualizações de projeto do servidor

Adicione o pacote Microsoft.Extensions.Localization ao projeto de servidor.

Observação

Para obter diretrizes sobre como adicionar pacotes a aplicativos .NET, consulte os artigos em Instalar e gerenciar pacotes no Fluxo de trabalho de consumo de pacotes (documentação do NuGet). Confirme as versões corretas de pacote em NuGet.org.

Os aplicativos do lado do servidor são localizados usando o Middleware de localização. Adicione serviços de localização ao aplicativo com AddLocalization.

No arquivo Program do projeto de servidor em que os serviços estão registrados:

builder.Services.AddLocalization();

Defina as culturas padrão e compatível do aplicativo com RequestLocalizationOptions.

Antes da chamada para MapRazorComponents no pipeline de processamento de solicitação, insira o seguinte código:

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

app.UseRequestLocalization(localizationOptions);

O exemplo a seguir mostra como definir a cultura atual em um cookie que pode ser lido pelo middleware de localização.

Os namespaces a seguir são necessários para o componente App:

Adicione o seguinte na parte superior do arquivo do App componente (Components/App.razor):

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

A cultura do aplicativo para renderização do lado do cliente é definida usando a API da estrutura Blazor. A seleção de cultura de um usuário pode ser mantida no armazenamento local do navegador para componentes CSR.

Após a marca <script> de Blazor, forneça funções JS para obter e definir a seleção de cultura do usuário com o armazenamento local do navegador:

<script>
  window.blazorCulture = {
    get: () => window.localStorage['BlazorCulture'],
    set: (value) => window.localStorage['BlazorCulture'] = value
  };
</script>

Observação

O exemplo anterior polui o cliente com funções globais. Para obter uma abordagem melhor em aplicativos de produção, confira Isolamento de JavaScript em módulos JavaScript.

Adicione o seguinte bloco de @code na parte inferior do arquivo do componente App:

@code {
    [CascadingParameter]
    public HttpContext? HttpContext { get; set; }

    protected override void OnInitialized()
    {
        HttpContext?.Response.Cookies.Append(
            CookieRequestCultureProvider.DefaultCookieName,
            CookieRequestCultureProvider.MakeCookieValue(
                new RequestCulture(
                    CultureInfo.CurrentCulture,
                    CultureInfo.CurrentUICulture)));
    }
}

Se o projeto de servidor não estiver configurado para processar ações do controlador:

  • Adicione serviços MVC chamando AddControllers na coleção de serviços no arquivo Program:

    builder.Services.AddControllers();
    
  • Adicione o roteamento do ponto de extremidade do controlador no arquivo Program chamando MapControllers no IEndpointRouteBuilder (app):

    app.MapControllers();
    

Para permitir que um usuário selecione uma cultura para componentes SSR, use uma abordagem baseada em redirecionamento com um cookie de localização. O aplicativo persiste a cultura selecionada pelo usuário por meio de um redirecionamento para um controlador. O controlador define a cultura selecionada pelo usuário em um cookie e redireciona o usuário de volta para o URI original. O processo é semelhante ao que acontece em um aplicativo Web quando um usuário tenta acessar um recurso seguro e é redirecionado para uma página de entrada e, em seguida, enviado de volta ao recurso original.

Controllers/CultureController.cs:

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

[Route("[controller]/[action]")]
public class CultureController : Controller
{
    public IActionResult Set(string culture, string redirectUri)
    {
        if (culture != null)
        {
            HttpContext.Response.Cookies.Append(
                CookieRequestCultureProvider.DefaultCookieName,
                CookieRequestCultureProvider.MakeCookieValue(
                    new RequestCulture(culture, culture)));
        }

        return LocalRedirect(redirectUri);
    }
}

Aviso

Use o resultado da ação LocalRedirect, conforme mostrado no exemplo anterior, para evitar ataques de redirecionamento abertos. Para obter mais informações, confira Impedir ataques de redirecionamento em aberto no ASP.NET Core.

Adicione o componente CultureSelector ao componente MainLayout. Insira a seguinte marcação na marca do </main> de fechamento no arquivo Components/Layout/MainLayout.razor:

<article class="bottom-row px-4">
    <CultureSelector @rendermode="InteractiveAuto" />
</article>

Use o componente CultureExample1 mostrado na seção Componente de demonstração para estudar como o exemplo anterior funciona.

No projeto de servidor, coloque o componente CultureServer a seguir para estudar como a globalização funciona para componentes de SSR.

Components/Pages/CultureServer.razor:

@page "/culture-server"
@rendermode InteractiveServer
@using System.Globalization

<PageTitle>Culture Server</PageTitle>

<h1>Culture Server</h1>

<ul>
    <li><b>CurrentCulture</b>: @CultureInfo.CurrentCulture</li>
    <li><b>CurrentUICulture</b>: @CultureInfo.CurrentUICulture</li>
</ul>

<h2>Rendered values</h2>

<ul>
    <li><b>Date</b>: @dt</li>
    <li><b>Number</b>: @number.ToString("N2")</li>
</ul>

<h2><code>&lt;input&gt;</code> elements that don't set a <code>type</code></h2>

<p>
    The following <code>&lt;input&gt;</code> elements use
    <code>CultureInfo.CurrentCulture</code>.
</p>

<ul>
    <li><label><b>Date:</b> <input @bind="dt" /></label></li>
    <li><label><b>Number:</b> <input @bind="number" /></label></li>
</ul>

<h2><code>&lt;input&gt;</code> elements that set a <code>type</code></h2>

<p>
    The following <code>&lt;input&gt;</code> elements use
    <code>CultureInfo.InvariantCulture</code>.
</p>

<ul>
    <li><label><b>Date:</b> <input type="date" @bind="dt" /></label></li>
    <li><label><b>Number:</b> <input type="number" @bind="number" /></label></li>
</ul>

@code {
    private DateTime dt = DateTime.Now;
    private double number = 1999.69;
}

Adicione os componentes CultureClient e CultureServer à navegação da barra lateral em Components/Layout/NavMenu.razor:

<div class="nav-item px-3">
    <NavLink class="nav-link" href="culture-server">
        <span class="bi bi-list-nested-nav-menu" aria-hidden="true"></span> Culture (Server)
    </NavLink>
</div>
<div class="nav-item px-3">
    <NavLink class="nav-link" href="culture-client">
        <span class="bi bi-list-nested-nav-menu" aria-hidden="true"></span> Culture (Client)
    </NavLink>
</div>

Componentes automáticos interativos

As diretrizes nesta seção também funcionam para componentes que adotam o modo de renderização automática interativa:

@rendermode InteractiveAuto

Localização

Se o aplicativo ainda não dá suporte à seleção de cultura dinâmica, adicione o pacote Microsoft.Extensions.Localization ao aplicativo.

Observação

Para obter diretrizes sobre como adicionar pacotes a aplicativos .NET, consulte os artigos em Instalar e gerenciar pacotes no Fluxo de trabalho de consumo de pacotes (documentação do NuGet). Confirme as versões corretas de pacote em NuGet.org.

Localização do lado do cliente

Defina a propriedade BlazorWebAssemblyLoadAllGlobalizationData para true no arquivo de projeto do aplicativo (.csproj):

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

No arquivo Program, adicione o namespace para System.Globalization na parte superior do arquivo:

using System.Globalization;

Adicione o serviço de localização do Blazor à coleção de serviços do aplicativo com AddLocalization:

builder.Services.AddLocalization();

Localização do lado do servidor

Use o middleware de localização para definir a cultura do aplicativo.

Se o aplicativo ainda não dá suporte à seleção de cultura dinâmica:

  • Adicione serviços de localização ao aplicativo com AddLocalization.
  • Especifique as culturas padrão e com suporte do aplicativo no arquivo Program. O exemplo a seguir configura culturas compatíveis com inglês dos Estados Unidos e espanhol costarriquenho.
builder.Services.AddLocalization();

Coloque o Middleware de Localização de Solicitação antes de qualquer middleware que possa verificar a cultura de solicitação. Geralmente, coloque o middleware imediatamente antes de chamar MapRazorComponents:

Imediatamente após o Middleware de Roteamento (UseRouting) ser adicionado ao pipeline de processamento:

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

app.UseRequestLocalization(localizationOptions);

Para saber mais sobre como ordenar o middleware de localização no pipeline de middleware, confira Middleware do ASP.NET Core.

  • Adicione serviços de localização ao aplicativo com AddLocalization.
  • Especifique as culturas padrão e compatível do aplicativo em Startup.Configure (Startup.cs). O exemplo a seguir configura culturas compatíveis com inglês dos Estados Unidos e espanhol costarriquenho.

Em Startup.ConfigureServices (Startup.cs):

services.AddLocalization();

Imediatamente Startup.Configure após o Middleware de Roteamento (UseRouting) ser adicionado ao pipeline de processamento:

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

app.UseRequestLocalization(localizationOptions);

Para saber mais sobre como ordenar o middleware de localização no pipeline de middleware de Startup.Configure, confira Middleware do ASP.NET Core.

Se o aplicativo deve localizar recursos com base no armazenamento da configuração de cultura do usuário, use um cookie de localização de cultura. O uso de um cookie garante que a conexão WebSocket possa propagar corretamente a cultura. Se os esquemas de localização forem baseados no caminho da URL ou na cadeia de caracteres de consulta, talvez o esquema não consiga trabalhar com WebSockets e, portanto, não persista a cultura. Portanto, a abordagem recomendada é usar um cookie de localização de cultura. Confira a seção Definir dinamicamente a cultura por preferência do usuário deste artigo para ver um exemplo de expressão do Razor que mantém a seleção de cultura do usuário.

Exemplo de recursos localizados

O exemplo de recursos localizados nesta seção funciona com os exemplos anteriores neste artigo em que as culturas disponíveis no aplicativo são inglês (en) como localidade padrão e espanhol (es) como uma localidade alternativa selecionada pelo usuário ou especificada pelo navegador.

Crie um arquivo de recurso para cada localidade. No exemplo a seguir, os recursos são criados para uma cadeia de caracteres Greeting em inglês e espanhol:

  • Inglês (en): Hello, World!
  • Espanhol (es): ¡Hola, Mundo!

Observação

O arquivo de recurso a seguir pode ser adicionado no Visual Studio clicando com o botão direito do mouse na pasta Pages e selecionando Adicionar>Novo Item>Arquivo de Recursos. Dê o nome CultureExample2.resx para o arquivo. Quando o editor for exibido, forneça dados para uma nova entrada. Defina o Nome como Greeting e Valor como Hello, World!. Salve o arquivo.

Se estiver usando o Visual Studio Code, recomendamos instalar o Visualizador e Editor ResX de Tim Heuer. Adicione um arquivo CultureExample2.resx vazio à pasta Pages. A extensão assume automaticamente o gerenciamento do arquivo na interface do usuário. Selecione o botão Adicionar Novo Recurso. Siga as instruções para adicionar uma entrada para Greeting (chave), Hello, World! (valor) e None (comentário). Salve o arquivo. Se você fechar e reabrir o arquivo, poderá ver o recurso Greeting.

O Visualizador e Editor ResX de Tim Heuer não é de propriedade ou é mantido pela Microsoft e não é coberto por nenhuma licença ou Contrato de Suporte da Microsoft.

O seguinte demonstra um arquivo de recurso típico. Você pode colocar manualmente arquivos de recurso na pasta Pages do aplicativo se preferir não usar ferramentas internas com um IDE (ambiente de desenvolvimento integrado), como o editor de arquivos de recursos interno do Visual Studio ou o Visual Studio Code com uma extensão para criar e editar arquivos de recursos.

Pages/CultureExample2.resx:

<?xml version="1.0" encoding="utf-8"?>
<root>
  <xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
    <xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
    <xsd:element name="root" msdata:IsDataSet="true">
      <xsd:complexType>
        <xsd:choice maxOccurs="unbounded">
          <xsd:element name="metadata">
            <xsd:complexType>
              <xsd:sequence>
                <xsd:element name="value" type="xsd:string" minOccurs="0" />
              </xsd:sequence>
              <xsd:attribute name="name" use="required" type="xsd:string" />
              <xsd:attribute name="type" type="xsd:string" />
              <xsd:attribute name="mimetype" type="xsd:string" />
              <xsd:attribute ref="xml:space" />
            </xsd:complexType>
          </xsd:element>
          <xsd:element name="assembly">
            <xsd:complexType>
              <xsd:attribute name="alias" type="xsd:string" />
              <xsd:attribute name="name" type="xsd:string" />
            </xsd:complexType>
          </xsd:element>
          <xsd:element name="data">
            <xsd:complexType>
              <xsd:sequence>
                <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
                <xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
              </xsd:sequence>
              <xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
              <xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
              <xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
              <xsd:attribute ref="xml:space" />
            </xsd:complexType>
          </xsd:element>
          <xsd:element name="resheader">
            <xsd:complexType>
              <xsd:sequence>
                <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
              </xsd:sequence>
              <xsd:attribute name="name" type="xsd:string" use="required" />
            </xsd:complexType>
          </xsd:element>
        </xsd:choice>
      </xsd:complexType>
    </xsd:element>
  </xsd:schema>
  <resheader name="resmimetype">
    <value>text/microsoft-resx</value>
  </resheader>
  <resheader name="version">
    <value>2.0</value>
  </resheader>
  <resheader name="reader">
    <value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
  </resheader>
  <resheader name="writer">
    <value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
  </resheader>
  <data name="Greeting" xml:space="preserve">
    <value>Hello, World!</value>
  </data>
</root>

Observação

O arquivo de recurso a seguir pode ser adicionado no Visual Studio clicando com o botão direito do mouse na pasta Pages e selecionando Adicionar>Novo Item>Arquivo de Recursos. Dê o nome CultureExample2.es.resx para o arquivo. Quando o editor for exibido, forneça dados para uma nova entrada. Defina o Nome como Greeting e Valor como ¡Hola, Mundo!. Salve o arquivo.

Se estiver usando o Visual Studio Code, recomendamos instalar o Visualizador e Editor ResX de Tim Heuer. Adicione um arquivo CultureExample2.resx vazio à pasta Pages. A extensão assume automaticamente o gerenciamento do arquivo na interface do usuário. Selecione o botão Adicionar Novo Recurso. Siga as instruções para adicionar uma entrada para Greeting (chave), ¡Hola, Mundo! (valor) e None (comentário). Salve o arquivo. Se você fechar e reabrir o arquivo, poderá ver o recurso Greeting.

O seguinte demonstra um arquivo de recurso típico. Você pode colocar manualmente arquivos de recurso na pasta Pages do aplicativo se preferir não usar ferramentas internas com um IDE (ambiente de desenvolvimento integrado), como o editor de arquivos de recursos interno do Visual Studio ou o Visual Studio Code com uma extensão para criar e editar arquivos de recursos.

Pages/CultureExample2.es.resx:

<?xml version="1.0" encoding="utf-8"?>
<root>
  <xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
    <xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
    <xsd:element name="root" msdata:IsDataSet="true">
      <xsd:complexType>
        <xsd:choice maxOccurs="unbounded">
          <xsd:element name="metadata">
            <xsd:complexType>
              <xsd:sequence>
                <xsd:element name="value" type="xsd:string" minOccurs="0" />
              </xsd:sequence>
              <xsd:attribute name="name" use="required" type="xsd:string" />
              <xsd:attribute name="type" type="xsd:string" />
              <xsd:attribute name="mimetype" type="xsd:string" />
              <xsd:attribute ref="xml:space" />
            </xsd:complexType>
          </xsd:element>
          <xsd:element name="assembly">
            <xsd:complexType>
              <xsd:attribute name="alias" type="xsd:string" />
              <xsd:attribute name="name" type="xsd:string" />
            </xsd:complexType>
          </xsd:element>
          <xsd:element name="data">
            <xsd:complexType>
              <xsd:sequence>
                <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
                <xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
              </xsd:sequence>
              <xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
              <xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
              <xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
              <xsd:attribute ref="xml:space" />
            </xsd:complexType>
          </xsd:element>
          <xsd:element name="resheader">
            <xsd:complexType>
              <xsd:sequence>
                <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
              </xsd:sequence>
              <xsd:attribute name="name" type="xsd:string" use="required" />
            </xsd:complexType>
          </xsd:element>
        </xsd:choice>
      </xsd:complexType>
    </xsd:element>
  </xsd:schema>
  <resheader name="resmimetype">
    <value>text/microsoft-resx</value>
  </resheader>
  <resheader name="version">
    <value>2.0</value>
  </resheader>
  <resheader name="reader">
    <value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
  </resheader>
  <resheader name="writer">
    <value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
  </resheader>
  <data name="Greeting" xml:space="preserve">
    <value>¡Hola, Mundo!</value>
  </data>
</root>

O componente a seguir demonstra o uso da cadeia de caracteres Greeting localizada com IStringLocalizer<T>. A marcação do Razor @Loc["Greeting"] no exemplo a seguir localiza a cadeia de caracteres com chave para o valor Greeting, que é definido nos arquivos de recurso anteriores.

Adicione o namespace de Microsoft.Extensions.Localization ao arquivo _Imports.razor do aplicativo:

@using Microsoft.Extensions.Localization

CultureExample2.razor:

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

<h1>Culture Example 2</h1>

<ul>
    <li><b>CurrentCulture</b>: @CultureInfo.CurrentCulture</li>
    <li><b>CurrentUICulture</b>: @CultureInfo.CurrentUICulture</li>
</ul>

<h2>Greeting</h2>

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

<p>
    @greeting
</p>

@code {
    private string? greeting;

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

Opcionalmente, adicione um item de menu para o componente CultureExample2 à navegação no componente NavMenu (NavMenu.razor).

Fonte de referência do provedor de cultura do WebAssembly

Para entender melhor como a estrutura do Blazor processa a localização, confira a WebAssemblyCultureProviderclasse na fonte de referência do ASP.NET Core.

Observação

Os links de documentação para a fonte de referência do .NET geralmente carregam o branch padrão do repositório, que representa o desenvolvimento atual da próxima versão do .NET. Para selecionar uma marca para uma versão específica, use a lista suspensa para Alternar branches ou marcas. Para saber mais, confira Como selecionar uma marca de versão do código-fonte do ASP.NET Core (dotnet/AspNetCore.Docs #26205).

Recursos compartilhados

Para criar recursos compartilhados de localização, adote a abordagem a seguir.

  • Crie uma classe fictícia com um nome de classe arbitrário. No exemplo a seguir:

    • O aplicativo usa o namespace BlazorSample e os ativos de localização usam o namespace BlazorSample.Localization.
    • A classe fictícia é chamada SharedResource.
    • O arquivo de classe é colocado em uma pasta Localization na raiz do aplicativo.

    Localization/SharedResource.cs:

    namespace BlazorSample.Localization;
    
    public class SharedResource
    {
    }
    
  • Crie os arquivos de recursos compartilhados com uma Ação de Build de Embedded resource. No exemplo a seguir:

    • Os arquivos são colocados na pasta Localization com a classe fictícia SharedResource (Localization/SharedResource.cs).

    • Nomeie os arquivos de recurso com o mesmo nome da classe fictícia. Os arquivos de exemplo a seguir incluem um arquivo de localização padrão e um arquivo para localização em espanhol (es).

    • Localization/SharedResource.resx

    • Localization/SharedResource.es.resx

    Aviso

    Ao seguir a abordagem descrita nesta seção, você não pode definir LocalizationOptions.ResourcesPath e usar IStringLocalizerFactory.Create simultaneamente para carregar recursos.

  • Para fazer referência à classe fictícia de um IStringLocalizer<T> injetado em um componente Razor, coloque uma diretiva @using para o namespace de localização ou inclua o namespace de localização na referência de classe fictícia. Nos exemplos a seguir:

    • O primeiro exemplo indica o namespace Localization da classe fictícia SharedResource com uma diretiva @using.
    • O segundo exemplo indica explicitamente o namespace SharedResource da classe fictícia.

    No componente Razor, use qualquer uma das seguintes abordagens:

    @using Localization
    @inject IStringLocalizer<SharedResource> Loc
    
    @inject IStringLocalizer<Localization.SharedResource> Loc
    

Para mais diretrizes, confira Globalização e localização em ASP.NET Core.

Substituição de local usando o painel "Sensores" nas ferramentas de desenvolvedor

Ao usar a substituição de local usando o painel Sensores nas ferramentas de desenvolvedor do Google Chrome ou do Microsoft Edge, a linguagem de fallback é redefinida após a pré-renderização. Evite definir o idioma usando o painel Sensores ao testar. Defina o idioma usando as configurações de idioma do navegador.

Para obter mais informações, consulte Blazor A localização não funciona com InteractiveServer (dotnet/aspnetcore nº 53707).

Recursos adicionais