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)); // quinta-feira, 1 de maio de 2025 às 09:00
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ários online
É muito fácil de esquecer de incluir regras de plural. E verificar manualmente pode ser repetitivo.
`${userCount} ${ userCount > 1 ? "usuários" : "usuário" } online`;
O Intl.PluralRules
fornece ajuda retornando a categoria cardinal baseado no número:
const ptCardinalRules = new Intl.PluralRules("pt-BR");
const ptNumberFormatter = new Intl.NumberFormat("pt-BR", {
notation: "compact",
compactDisplay: "long",
});
function userCountText(userCount: number) {
const category = ptCardinalRules.select(userCount);
const userCountDisplay = ptNumberFormatter.format(userCount);
if (category === "one") {
return `${userCountDisplay} usuário online`;
}
if (category === "other") {
return `${userCountDisplay} usuários online`;
}
// Você lembraria desse caso?
if (category === "many") {
return `${userCountDisplay} de usuários online`;
}
}
console.log(userCountText(1)); // 1 usuário online
console.log(userCountText(2)); // 2 usuários online
console.log(userCountText(2000000)); // 2 milhões de usuários online
Entretanto, algo estranho acontece quando usamos o zero:
console.log(userCountText(0)); // 0 usuário 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("pt", {
type: "conjunction",
});
const users = ["John"];
console.log(formatter.format(users)); // John
users.push("Lennon");
console.log(formatter.format(users)); // John e Lennon
users.push("Ringo");
users.push("George");
console.log(formatter.format(users)); // John, Lennon, Ringo e George
Para utilizar "ou", utilizamos type: "disjunction"
:
const formatter = new Intl.ListFormat("pt", {
type: "disjunction",
});
const meansOfTransport = ["Carro", "Bicicleta", "Ônibus"];
console.log(formatter.format(meansOfTransport)); // Carro, Bicicleta ou Ônibus
Intl.RelativeTimeFormat
O RelativeTimeFormat
permite converter uma unidade em tempo relativo.
const relativeTime = new Intl.RelativeTimeFormat("pt");
console.log(relativeTime.format(2, "day")); // em 2 dias
console.log(relativeTime.format(12, "years")); // em 12 anos
console.log(relativeTime.format(-1, "week")); // há 1 semana
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("pt", {
numeric: "auto",
});
console.log(relativeTime.format(2, "day")); // depois de amanhã
console.log(relativeTime.format(0, "years")); // este ano
console.log(relativeTime.format(1, "week")); // próxima semana
console.log(relativeTime.format(0, "second")); // agora
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.