JavaScript Intl (API de Internacionalização)
Aprenda a API Intl do JavaScript para formatar números, moedas, datas, tempos relativos, listas e plurais para qualquer locale, e ordenar strings corretamente com comparação sensível ao locale.
Intl é um namespace embutido do JavaScript para formatação e comparação sensíveis ao locale. Não há nenhuma biblioteca para instalar nem nada para importar — ele acompanha todos os navegadores modernos e o Node.js. Com ele você pode formatar números, moedas, datas, tempos relativos e listas exatamente da forma que os usuários de uma determinada região esperam, e pode ordenar texto corretamente para idiomas em que a ordenação baseada apenas em inglês falha.
Quase todos os construtores de Intl seguem a mesma estrutura: você passa um locale (ou um array de locales de fallback) e um objeto de opções. Um locale é uma tag de idioma BCP 47 como 'en-US', 'de-DE', 'fr-FR' ou 'ja-JP'. Se você omitir o locale completamente, o Intl usa o locale padrão do ambiente de execução (a configuração de idioma do navegador, ou o locale do sistema no Node).
// locale + options
new Intl.NumberFormat('de-DE', { style: 'currency', currency: 'EUR' });
// no locale → uses the runtime default
new Intl.NumberFormat();
// an array provides fallbacks: try Welsh, then fall back to English
new Intl.NumberFormat(['cy', 'en']);Intl.NumberFormat
Intl.NumberFormat formata números de acordo com as convenções de um locale. Isso é importante porque os separadores de agrupamento e decimais diferem de lugar para lugar: o número 1234.56 é escrito 1,234.56 nos Estados Unidos, mas 1.234,56 na Alemanha.
const n = 1234.56;
console.log(new Intl.NumberFormat('en-US').format(n)); // "1,234.56"
console.log(new Intl.NumberFormat('de-DE').format(n)); // "1.234,56"
console.log(new Intl.NumberFormat('fr-FR').format(n)); // "1 234,56"A opção style seleciona que tipo de valor você está formatando: 'decimal' (o padrão), 'currency', 'percent' ou 'unit'.
Moeda
Para valores monetários, defina style: 'currency' e nomeie a moeda com a opção currency (um código ISO 4217 como 'USD' ou 'EUR'). O locale decide a posição do símbolo e os separadores.
const price = 1499.9;
console.log(
new Intl.NumberFormat('en-US', { style: 'currency', currency: 'USD' }).format(price)
); // "$1,499.90"
console.log(
new Intl.NumberFormat('de-DE', { style: 'currency', currency: 'EUR' }).format(price)
); // "1.499,90 €"
console.log(
new Intl.NumberFormat('ja-JP', { style: 'currency', currency: 'JPY' }).format(price)
); // "¥1,500" (yen has no minor unit, so it is rounded)Percentual, dígitos fracionários e notação compacta
Use style: 'percent' para formatar uma razão como percentual — o valor é multiplicado por 100. Controle quantas casas decimais aparecem com minimumFractionDigits e maximumFractionDigits. Defina notation: 'compact' para produzir formas abreviadas como 1.2K e 3.4M.
console.log(
new Intl.NumberFormat('en-US', { style: 'percent' }).format(0.1875)
); // "19%"
console.log(
new Intl.NumberFormat('en-US', {
style: 'percent',
minimumFractionDigits: 2,
}).format(0.1875)
); // "18.75%"
console.log(
new Intl.NumberFormat('en-US', { notation: 'compact' }).format(1200000)
); // "1.2M"Unidades
Com style: 'unit' você pode formatar medidas. Nomeie a unidade com a opção unit (por exemplo 'kilometer-per-hour' ou 'megabyte') e escolha um unitDisplay de 'short', 'long' ou 'narrow'.
console.log(
new Intl.NumberFormat('en-US', {
style: 'unit',
unit: 'kilometer-per-hour',
}).format(90)
); // "90 km/h"
console.log(
new Intl.NumberFormat('en-US', {
style: 'unit',
unit: 'megabyte',
unitDisplay: 'long',
}).format(16)
); // "16 megabytes"Para trabalho mais aprofundado com números — arredondamento, precisão e aritmética — consulte Numbers e JavaScript Math.
Intl.DateTimeFormat
Intl.DateTimeFormat formata objetos Date (e timestamps) para um locale. A abordagem mais rápida são as opções dateStyle e timeStyle, cada uma aceitando 'full', 'long', 'medium' ou 'short'.
Para um controle mais refinado, defina componentes individuais como year, month, day, hour, minute e second, e fixe a saída em um fuso horário com timeZone.
const date = new Date('2026-06-19T14:30:00Z');
const fmt = new Intl.DateTimeFormat('en-GB', {
year: 'numeric',
month: 'short',
day: '2-digit',
hour: '2-digit',
minute: '2-digit',
timeZone: 'Europe/Berlin',
});
console.log(fmt.format(date)); // "19 Jun 2026, 16:30"Dois métodos extras valem a pena conhecer. .formatToParts() retorna a saída dividida em partes rotuladas ({ type: 'month', value: 'Jun' }, e assim por diante), o que permite reestilizar partes individuais. .formatRange(start, end) formata um intervalo de datas de forma compacta, recolhendo as partes em comum.
const fmt = new Intl.DateTimeFormat('en-US', { month: 'long', day: 'numeric' });
console.log(fmt.formatRange(new Date(2026, 5, 1), new Date(2026, 5, 5)));
// "June 1 – 5"Para tudo sobre como criar e manipular datas, consulte JavaScript Date.
Intl.RelativeTimeFormat
Intl.RelativeTimeFormat produz frases como "2 dias atrás" ou "em 3 horas". Você chama .format(value, unit), onde um value negativo é no passado e um value positivo é no futuro. A opção numeric: 'auto' permite que o formatador use palavras como "yesterday" e "tomorrow" em vez de "1 day ago".
const rtf = new Intl.RelativeTimeFormat('en', { numeric: 'auto' });
console.log(rtf.format(-1, 'day')); // "yesterday"
console.log(rtf.format(3, 'hour')); // "in 3 hours"
console.log(rtf.format(-2, 'day')); // "2 days ago"
console.log(rtf.format(1, 'week')); // "next week"A mesma chamada em outro locale produz fraseamento nativo — new Intl.RelativeTimeFormat('fr').format(-1, 'day') resulta em "il y a 1 jour".
Intl.Collator
Ordenar texto é o ponto onde código ingênuo mais frequentemente erra. O Array.prototype.sort() padrão do JavaScript compara strings pelos seus code units UTF-16, não pelas regras alfabéticas. Isso significa que letras maiúsculas são ordenadas antes das minúsculas, e letras acentuadas ou não-latinas aparecem em lugares surpreendentes.
const words = ['Zürich', 'apple', 'Banana', 'Älpler'];
console.log([...words].sort());
// ["Banana", "Zürich", "Älpler", "apple"] ← not what a reader expectsIntl.Collator corrige isso comparando strings da forma que um determinado idioma faz. Seu método .compare tem exatamente a assinatura que sort() espera, portanto você pode passá-lo diretamente.
Para uma comparação pontual de duas strings você também pode usar String.prototype.localeCompare, que aceita os mesmos argumentos de locale e opções: 'ä'.localeCompare('z', 'de'). Quando você está ordenando um array inteiro, prefira um Intl.Collator reutilizado — é mais rápido do que chamar localeCompare em cada par. Consulte Strings para mais informações sobre como trabalhar com texto.
Intl.PluralRules
Idiomas diferentes têm categorias de plural diferentes. O inglês tem apenas duas ('one' e 'other'), mas muitos idiomas têm mais. Intl.PluralRules informa em qual categoria um número se enquadra para que você possa selecionar o texto correto em uma mensagem traduzida.
const pr = new Intl.PluralRules('en-US');
console.log(pr.select(0)); // "other"
console.log(pr.select(1)); // "one"
console.log(pr.select(5)); // "other"
function items(count) {
const word = pr.select(count) === 'one' ? 'item' : 'items';
return `${count} ${word}`;
}
console.log(items(1)); // "1 item"
console.log(items(3)); // "3 items"Intl.ListFormat
Intl.ListFormat une um array de strings em uma lista com som natural, inserindo os separadores e a conjunção corretos para o locale — incluindo a vírgula de Oxford onde o idioma a utiliza.
const items = ['apples', 'bananas', 'oranges'];
const en = new Intl.ListFormat('en-US', { style: 'long', type: 'conjunction' });
console.log(en.format(items)); // "apples, bananas, and oranges"
const enOr = new Intl.ListFormat('en-US', { type: 'disjunction' });
console.log(enOr.format(items)); // "apples, bananas, or oranges"
const de = new Intl.ListFormat('de-DE', { type: 'conjunction' });
console.log(de.format(items)); // "apples, bananas und oranges"Reutilize formatadores para melhor desempenho
Construir um formatador Intl é relativamente custoso — ele carrega e resolve dados de locale. Crie cada formatador uma única vez e reutilize-o, especialmente dentro de loops ou renderização de listas. Construir um novo new Intl.NumberFormat(...) para cada linha pode ser muito mais lento do que a própria formatação.
// Slow: a new formatter is built on every iteration
prices.forEach((p) =>
console.log(new Intl.NumberFormat('en-US', { style: 'currency', currency: 'USD' }).format(p))
);
// Fast: build it once, reuse it
const money = new Intl.NumberFormat('en-US', { style: 'currency', currency: 'USD' });
prices.forEach((p) => console.log(money.format(p)));Cada formatador também expõe .resolvedOptions(), que informa o locale e as opções efetivamente escolhidos após a negociação. É útil para depurar casos em que o ambiente de execução recorre a um locale diferente do solicitado.
Resumo
A API Intl cobre as tarefas de formatação e comparação que antes exigiam bibliotecas pesadas de terceiros: números, moedas, datas, tempos relativos, plurais e listas sensíveis ao locale, além de ordenação correta de texto via Intl.Collator. Por estar embutida em todos os navegadores modernos e no Node.js, usá-la em primeiro lugar mantém seu bundle pequeno e sua saída correta para usuários em qualquer lugar. Lembre-se da regra que mais compensa: construa cada formatador uma vez e reutilize-o.