Faça sua pergunta e obtenha um resumo do documento referenciando esta página e o provedor AI de sua escolha
O conteúdo desta página foi traduzido com uma IA.
Veja a última versão do conteúdo original em inglêsSe você tiver uma ideia para melhorar esta documentação, sinta-se à vontade para contribuir enviando uma pull request no GitHub.
Link do GitHub para a documentaçãoCopiar o Markdown do documento para a área de transferência
Formatando datas e números por idioma com Intl
Traduzir strings de texto é apenas a metade visível da internacionalização. A outra metade, responsável pela maioria dos relatos de bugs, é a formatação: um usuário na Alemanha vendo 1,234.56 em vez de 1.234,56, um usuário no Japão vendo 08/02/2026 e lendo como agosto, ou uma data que renderiza diferente no servidor e no navegador, derrubando a página na hidratação do React.
Nada disso requer bibliotecas externas. A API nativa Intl já está presente em qualquer ambiente moderno de execução.
Sumário
Comece deletando suas funções helper caseiras de data
Quase todo repositório possui uma função formatDate escrita antes de qualquer planejamento para internacionalização. Ela fixa uma ordem arbitrária, um separador e quase sempre nomes de meses em inglês.
Copiar o código para a área de transferência
Intl.DateTimeFormat a substitui por completo e entrega o resultado correto para cada localidade:
Copiar o código para a área de transferência
O mesmo vale para valores numéricos. toFixed(2) produz 1234.56 em qualquer lugar, o que é incorreto na maior parte da Europa.
O que a API Intl engloba
Abrir a tabela em um modal para ver todo o conteúdo claramente
| API | Quando utilizar |
|---|---|
Intl.DateTimeFormat | Datas e horários, com presets dateStyle / timeStyle |
Intl.NumberFormat | Decimais, moedas, porcentagens, unidades, notação compacta |
Intl.RelativeTimeFormat | "há 3 dias", "em 2 horas" |
Intl.ListFormat | "a, b e c" versus "a, b, and c" |
Intl.PluralRules | Identificar categorias de plural para números |
Intl.Collator | Ordenação alfabética linguística correta de strings |
Intl.Collator é o mais esquecido. Um simples array.sort() sobre strings utiliza a ordenação de code points do Unicode, fazendo caracteres com acentos ficarem depois de z e colocando o ö sueco na posição errada. Sempre que ordenar listas visíveis para os usuários, use um collator.
Copiar o código para a área de transferência
Prefira presets a opções montadas manualmente
dateStyle e timeStyle deixam o locale decidir a ordem e os separadores lógicos. Especificar year, month e day separadamente dá um controle raramente desejável, pois a ordem correta varia de acordo com a região e você acaba sobrescrevendo os dados do CLDR com suas próprias suposições.
Copiar o código para a área de transferência
Defina componentes explícitos apenas quando o layout visual exigir rigorosamente uma largura fixa, como em uma coluna estreita de tabela.
Instanciar formatadores é custoso
Este é o detalhe de desempenho mais crítico. Criar um Intl.NumberFormat carrega dados pesados de localidade na memória, sendo um processo muito mais custoso do que a chamada subsequente a .format(). Fazer isso em um loop de renderização sobre mil linhas cria um gargalo expressivo.
Copiar o código para a área de transferência
toLocaleDateString() e toLocaleString() escondem o mesmo problema: cada execução cria um novo formatador. Funcionam para um valor pontual, mas são péssimos para listas.
Armazene-os em cache com base na combinação de localidade e opções:
Copiar o código para a área de transferência
O bug de fuso horário que só surge em produção
Esse problema já custou tardes inteiras de trabalho. O servidor renderiza a data no SSR, o navegador hidrata o componente no cliente, e o React acusa um erro de hydration mismatch porque os dois ambientes produziram textos conflitantes.
A causa: Intl.DateTimeFormat assume o fuso horário padrão do sistema quando nenhum é especificado. Seu servidor de produção opera em UTC, enquanto sua máquina de desenvolvimento local está em outro fuso. Com isso, o erro fica invisível localmente e só aparece em produção.
Copiar o código para a área de transferência
Três soluções viáveis:
- Fixar o fuso horário no servidor e passá-lo explicitamente. Seguro e determinístico, mas todos veem horário em UTC.
- Renderizar apenas no cliente, com um placeholder estável durante o SSR. Preciso para cada usuário, com um leve salto visual.
- Salvar o fuso do usuário e passá-lo em ambos os lados. A melhor experiência, exigindo um pouco mais de infraestrutura.
Qualquer que seja sua escolha, informe sempre timeZone de forma explícita em qualquer data renderizada tanto no servidor quanto no cliente. Uma data sem fuso explícito é uma data com dois valores contraditórios.
Moeda precisa de moeda, não de locale
Localidade e moeda são conceitos independentes. fr-FR não significa euro: um usuário na França pode perfeitamente estar analisando uma fatura em dólares americanos.
Copiar o código para a área de transferência
O locale governa os separadores, o agrupamento de dígitos e a posição do símbolo. A moeda vem dos seus dados. Presumir uma a partir da outra gera inconsistências financeiras.
Fique atento também a currencyDisplay. Em interfaces com múltiplas moedas que compartilham o símbolo de cifrão, "code" elimina a ambiguidade entre dólares americanos, canadenses e australianos.
Tempo relativo soa mais natural que tempo absoluto
Para ocorrências recentes, "há 2 horas" é muito mais claro do que um timestamp bruto, e Intl.RelativeTimeFormat lida com isso de maneira nativa.
Copiar o código para a área de transferência
numeric: "auto" entrega "ontem" em vez de "há 1 dia". Sem isso, você recebe a expressão puramente numérica, que soa artificial.
O que o Intlayer adiciona
O Intlayer encapsula essas APIs em utilitários com cache embutido para poupar o gerenciamento manual do Map acima, e aplica a localidade ativa como padrão sem obrigar você a passá-la a cada chamada.
Copiar o código para a área de transferência
A função date() também suporta presets ("short", "long", "dateOnly", "timeOnly", "full"), eliminando a necessidade de objetos de opções nos casos comuns. Equivalentes para React e Vue estão disponíveis como hooks e composables, resolvendo a localidade ativa diretamente do contexto.
Trata-se de uma camada ágil de cache e resolução padrão sobre as APIs da plataforma. A formatação em si continua sendo 100% Intl. Consulte as assinaturas completas na documentação de formatadores.
Erros comuns
toLocaleDateString()sem definir locale. Usa o locale do ambiente hospedeiro, que no servidor reflete a imagem do contêiner.- Formatar dentro de laços de repetição. O custo reside na instanciação do formatador. Crie uma vez e reutilize.
- Omitir
timeZoneem datas isomórficas. Gera erros de hidratação impossíveis de reproduzir localmente. - Deduzir a moeda a partir do locale.
fr-FRnão garante valores em euros. - Chamar
sort()simples em textos de interface. Use sempreIntl.Collator. - Escrever nomes de meses ou dias fixos no código. O CLDR já armazena tudo em todas as línguas.
- Manter
numeric: "always"em tempo relativo. Gera "há 1 dia" onde todo idioma possui uma palavra como ontem.
Para se aprofundar
- Formatadores e utilitários de locale:
number,currency,date,relativeTime,list - Referência de configuração
- Relatórios de benchmark entre frameworks
- Adaptador de compatibilidade react-intl
- Formato de mensagens ICU: plurais, select e skeletons numéricos
- Como testar traduções, cobrindo formatadores e plurais
- O que a internacionalização realmente abrange
Comentários
Ainda sem comentários. Seja o primeiro a compartilhar seus pensamentos.
