O Intl é uma API do Javascript que fornece funcionalidades para criação de textos internacionalizados. Entretanto, ela pode ser usada em qualquer caso que você precise formatar informações de Javascript em textos, removendo a necessidade de bibliotecas externas.
Uma das funcionalidades mais conhecidas é o Intl.DateTimeFormat, que está disponível desde 2017. Ele é usado para formatar datas e horas:
const portugueseFormatter = new Intl.DateTimeFormat("pt-BR", {
dateStyle: "full",
timeStyle: "short",
});
const englishFormatter = new Intl.DateTimeFormat("en-US", {
dateStyle: "full",
timeStyle: "short",
});
const date = new Date("2025-05-01T12:00:00Z");
console.log(portugueseFormatter.format(date)); // Thursday, May 1, 2025 at 9:00 AM (in PT)
console.log(englishFormatter.format(date)); // Thursday, May 1, 2025 at 9:00 AM
Entretanto, existem outras APIs menos conhecidas (mas muito úteis) que também estão disponíveis através do Intl.
Intl.NumberFormat
O NumberFormat é muito útil para aplicativos em português, já que utilizamos vírgula para representar casas decimais.
const conversionRate = 3.7;
const portugueseNumberFormatter = Intl.NumberFormat("pt-BR");
console.log(portugueseNumberFormatter.format(conversionRate)); // 3,7
Também é possível definir um valor mínimo ou máximo de dígitos depois da vírgula (com a possibilidade de definir a estratégia de arredondamento):
const winningRate = 1.2345653;
const zero = 0;
const portugueseNumberFormatter = Intl.NumberFormat("pt-BR", {
maximumFractionDigits: 3,
minimumFractionDigits: 3,
});
console.log(portugueseNumberFormatter.format(winningRate)); // 1,235
console.log(portugueseNumberFormatter.format(zero)); // 0,000
E se você pensou que essa é a solução para manter preços sempre dentro do estilo necessário, existe algo melhor, uma opção específica para formatar preços e moedas:
const ticketPrice = 5.9;
const realFormatter = new Intl.NumberFormat("pt-BR", {
style: "currency",
currency: "BRL",
});
console.log(realFormatter.format(ticketPrice)); // R$ 5,90
E até unidades podem ser utilizadas:
const distanceKilometers = 90;
const timeInHours = 0.4;
const velocity = distanceKilometers / timeInHours;
const velocityFormatter = new Intl.NumberFormat("pt-BR", {
style: "unit",
unit: "kilometer-per-hour",
});
console.log(velocityFormatter.format(velocity)); // 225 km/h
Outras opções e exemplos estão disponíveis no MDN.
Intl.PluralRules
1 usuário online
É muito fácil de esquecer de incluir regras de plural. E verificar manualmente pode ser repetitivo.
`${userCount} ${ userCount > 1 ? "users" : "user" } online`;
O Intl.PluralRules fornece ajuda retornando a categoria cardinal baseado no número:
const enCardinalRules = new Intl.PluralRules("en-US");
const enNumberFormatter = new Intl.NumberFormat("en-US", {
notation: "compact",
compactDisplay: "long",
});
function userCountText(userCount: number) {
const category = enCardinalRules.select(userCount);
const userCountDisplay = enNumberFormatter.format(userCount);
if (category === "one") {
return `${userCountDisplay} user online`;
}
if (category === "other") {
return `${userCountDisplay} users online`;
}
// Would you remember this case?
if (category === "many") {
return `${userCountDisplay} of users online`;
}
}
console.log(userCountText(1)); // 1 user online
console.log(userCountText(2)); // 2 users online
console.log(userCountText(2000000)); // 2 million users online
Entretanto, algo estranho acontece quando usamos o zero:
console.log(userCountText(0)); // 0 users online
A realidade é que a especificação do CLDR sobre regras de plurais, em que o Intl.PluralRules se baseia, considera que 0 está dentro de one para o locale pt (como pt-BR está ausente na lista, os navegadores utilizam pt de "fallback").
Existe uma discussão na língua portuguesa a respeito do uso do plural com o 0, mas ela está fora do escopo desse artigo. Para fazer o 0 ser parte da categoria other, você pode utilizar o locale pt-PT.
const ptBRplural = new Intl.PluralRules("pt-BR");
const ptPTplural = new Intl.PluralRules("pt-PT");
console.log(ptBRplural.select(0)); // one
console.log(ptPTplural.select(0)); // other
Intl.ListFormat
Formata uma lista, seguindo as regras da língua.
const formatter = new Intl.ListFormat("en", {
type: "conjunction",
});
const users = ["John"];
console.log(formatter.format(users)); // John
users.push("Lennon");
console.log(formatter.format(users)); // John and Lennon
users.push("Ringo");
users.push("George");
console.log(formatter.format(users)); // John, Lennon, Ringo, and George
Para utilizar "ou", utilizamos type: "disjunction":
const formatter = new Intl.ListFormat("en", {
type: "disjunction",
});
const meansOfTransport = ["Car", "Bicycle", "Bus"];
console.log(formatter.format(meansOfTransport)); // Car, Bicycle, or Bus
Intl.RelativeTimeFormat
O RelativeTimeFormat permite converter uma unidade em tempo relativo.
const relativeTime = new Intl.RelativeTimeFormat("en");
console.log(relativeTime.format(2, "day")); // in 2 days
console.log(relativeTime.format(12, "years")); // in 12 years
console.log(relativeTime.format(-1, "week")); // 1 week ago
As unidades possíveis são:
year, quarter, month, week, day, hour, minute ou second.
Por padrão, o resultado é sempre númerico, mas você pode permitir o uso de frases idiomáticas:
const relativeTime = new Intl.RelativeTimeFormat("en", {
numeric: "auto",
});
console.log(relativeTime.format(2, "day")); // day after tomorrow
console.log(relativeTime.format(0, "years")); // this year
console.log(relativeTime.format(1, "week")); // next week
console.log(relativeTime.format(0, "second")); // now
Entretanto, eu acho a API do RelativeTimeFormat pequena em relação à quantidade de possibilidades. Eu acho sempre muito difícil trabalhar com Tempo e Duração no Javascript com bibliotecas externas. Novas APIs estão por vir para facilitar essas tarefas, mas isso é assunto para outro post.