Resumo
A internacionalização (i18n) em JavaScript dependia historicamente de bibliotecas externas pesadas, como Moment.js ou date-fns. A API Intl (disponível nativamente em todos os navegadores modernos) resolve isso oferecendo formatação numérica, manipulação de datas, ordenação de strings e segmentação diretamente no motor do JavaScript.
Este artigo explora os construtores-chave do namespace Intl, ensinando como adaptar suas aplicações para múltiplas culturas com zero dependências.
1. O objeto global Intl
O objeto global Intl atua como um namespace (semelhante ao Math). Não pode ser instanciado com new. Em vez disso, abriga vários construtores especializados.
Quase todos esses construtores aceitam dois parâmetros:
locales: uma string com o código BCP 47 (ex.:"pt-BR","en-GB") ou um array deles. Se omitido, usa o locale do sistema do usuário.options: um objeto de configuração para ajustar o comportamento do construtor.
2. Formatação de Números e Moedas (Intl.NumberFormat)
O construtor Intl.NumberFormat formata números com base em convenções regionais (separadores de milhar, decimais, etc.).
2.1 Moedas e Porcentagens
Configurando a propriedade style, podemos formatar finanças ou unidades sem concatenar strings manualmente:
const amount = 123456.789;
// Formato português (Brasil) - usa vírgula para decimais
const formatPT = new Intl.NumberFormat('pt-BR');
console.log(formatPT.format(amount)); // "123.456,789"
// Formato de moeda (Reais)
const formatReal = new Intl.NumberFormat('pt-BR', {
style: 'currency',
currency: 'BRL'
});
console.log(formatReal.format(amount)); // "R$ 123.456,79"
// Formato contábil dos EUA (números negativos entre parênteses)
const formatAccounting = new Intl.NumberFormat('en-US', {
style: 'currency',
currency: 'USD',
currencySign: 'accounting'
});
console.log(formatAccounting.format(-amount)); // "($123,456.79)"
2.2 Unidades Físicas
Podemos formatar unidades padronizadas (quilômetros, litros, bytes) de forma nativa:
const speed = new Intl.NumberFormat('pt-BR', {
style: 'unit',
unit: 'kilometer-per-hour',
unitDisplay: 'long'
});
console.log(speed.format(120)); // "120 quilômetros por hora"
3. Pluralização (Intl.PluralRules)
Diferentes idiomas possuem regras gramaticais de pluralização altamente complexas. O Intl.PluralRules não retorna uma string formatada, mas classifica um número em categorias ("zero", "one", "two", "few", "many", "other"), que você pode usar como chaves para o seu sistema de traduções.
const arabicRules = new Intl.PluralRules('ar-EG');
console.log(arabicRules.select(0)); // "zero"
console.log(arabicRules.select(1)); // "one"
console.log(arabicRules.select(2)); // "two"
console.log(arabicRules.select(6)); // "few"
// Uso de ordinais em inglês (1st, 2nd, 3rd)
const ordinalRulesEN = new Intl.PluralRules('en-US', { type: 'ordinal' });
console.log(ordinalRulesEN.select(1)); // "one" (para o sufixo "st")
console.log(ordinalRulesEN.select(2)); // "two" (para o sufixo "nd")
console.log(ordinalRulesEN.select(3)); // "few" (para o sufixo "rd")
console.log(ordinalRulesEN.select(4)); // "other" (para o sufixo "th")
4. Manipulação do Tempo
O tempo é gerenciado de forma abrangente através de três pilares na API Intl:
4.1 Formatadores Absolutos: Intl.DateTimeFormat
Converte datas em texto humano de acordo com horários e calendários regionais. Suporta macros como dateStyle e timeStyle para simplificar as opções.
const date = new Date(Date.UTC(2026, 0, 10, 10, 0, 0));
const fullFormat = new Intl.DateTimeFormat('pt-BR', {
dateStyle: 'full',
timeStyle: 'long',
timeZone: 'America/Sao_Paulo'
});
console.log(fullFormat.format(date));
// "sábado, 10 de janeiro de 2026 às 07:00:00 BRT"
// Suporta intervalos sem redundâncias temporais
const endDate = new Date(Date.UTC(2026, 0, 12, 10, 0, 0));
const rangeFormat = new Intl.DateTimeFormat('pt-BR', { dateStyle: 'long' });
console.log(rangeFormat.formatRange(date, endDate));
// "10 a 12 de janeiro de 2026"
4.2 Tempo Relativo: Intl.RelativeTimeFormat
Adequado para exibir tempos relativos na interface (“há 5 minutos”, “ontem”).
const relativeTime = new Intl.RelativeTimeFormat('pt-BR', { numeric: 'auto' });
console.log(relativeTime.format(-1, 'day')); // "ontem"
console.log(relativeTime.format(2, 'day')); // "depois de amanhã"
console.log(relativeTime.format(-3, 'month')); // "há 3 meses"
4.3 Durações: Intl.DurationFormat
Exibe a duração de um intervalo independentemente do contexto da data. Recebe objetos da nova especificação Temporal.
const span = { hours: 2, minutes: 4, seconds: 35 };
const stopwatch = new Intl.DurationFormat('en-US', {
style: 'digital',
hoursDisplay: 'always',
minutes: '2-digit'
});
console.log(stopwatch.format(span)); // "2:04:35"
5. Manipulação de Strings e Dados
5.1 Ordenação Natural: Intl.Collator
Resolve as deficiências do .sort() padrão dos arrays, ordenando números e ignorando acentos corretamente.
const docs = ['arquivo10.txt', 'arquivo2.txt', 'Álbum.txt', 'Zebra.txt'];
// Array.sort() falhará ao colocar "10" antes do "2", e a "Á" no final.
// Intl.Collator corrige isso:
const collator = new Intl.Collator('pt-BR', { numeric: true, sensitivity: 'base' });
docs.sort(collator.compare);
console.log(docs);
// ["Álbum.txt", "arquivo2.txt", "arquivo10.txt", "Zebra.txt"]
5.2 Formatação de Listas: Intl.ListFormat
Gera as conjunções ou disjunções corretas de acordo com o idioma (“e”, “ou”, dependendo do locale).
const ingredients = ['Farinha', 'Ovos', 'Açúcar'];
const formatterPT = new Intl.ListFormat('pt-BR', { type: 'conjunction' });
console.log(formatterPT.format(ingredients)); // "Farinha, Ovos e Açúcar"
const formatterEN = new Intl.ListFormat('en-US', { type: 'conjunction' });
console.log(formatterEN.format(ingredients)); // "Farinha, Ovos, and Açúcar"
5.3 Segmentação Inteligente: Intl.Segmenter
Identificar os limites das palavras usando .split(' ') falha com linguagens logográficas (como japonês ou chinês), ou com emojis compostos por múltiplos glifos.
const japaneseText = "吾輩は猫である。名前はたぬき。";
const segmenter = new Intl.Segmenter('ja-JP', { granularity: 'word' });
const segments = segmenter.segment(japaneseText);
for (const chunk of segments) {
if (chunk.isWordLike) {
console.log(chunk.segment);
// Exibe "吾輩", "は", "猫", "で", "ある", "名前", "は", "たぬき"
}
}
5.4 Nomes de Regiões e Idiomas: Intl.DisplayNames
Evita carregar grandes dicionários JSON ao traduzir de forma nativa os nomes de idiomas, regiões ou moedas.
const regionTranslator = new Intl.DisplayNames(['pt-BR'], { type: 'region' });
console.log(regionTranslator.of('US')); // "Estados Unidos"
console.log(regionTranslator.of('JP')); // "Japão"
const languageTranslator = new Intl.DisplayNames(['en-US'], { type: 'language' });
console.log(languageTranslator.of('es-419')); // "Latin American Spanish"
6. Desempenho e Caching
Inicializar construtores do namespace Intl é uma operação relativamente dispendiosa em termos de desempenho.
Se sua aplicação realiza a mesma formatação intensamente (por exemplo, ao mapear milhares de transações para a interface), nunca instancie a classe dentro do loop iterativo.
Padrão recomendado de Caching:
const prices = [10.5, 20.9, 100, 450.2];
// ✅ CORRETO: Instanciamos o objeto formatador UMA única vez fora do loop.
const formatBRL = new Intl.NumberFormat('pt-BR', { style: 'currency', currency: 'BRL' });
const renderOutput = prices.map(price => formatBRL.format(price));
7. Conclusão
A API Intl do ECMAScript é a abordagem padrão para a internacionalização de aplicações web e Node.js. Ao transferir as dependências algorítmicas para o motor do navegador ou servidor, a Intl elimina a necessidade de bibliotecas adicionais, resultando em aplicações mais eficientes, robustas e resilientes diante das mudanças contínuas nas convenções regionais.
Fontes: MDN Web Docs, Especificação ECMA-402 API de Internacionalização.