A internacionalização (i18n) é um aspecto crucial no desenvolvimento de aplicações modernas. O JavaScript oferece a API Intl, que fornece funcionalidades de formatação sensíveis ao idioma para números, datas, moedas, pluralização e ordenação de strings. Nesta aula, vamos explorar os principais objetos dessa API, mostrando como adaptar sua aplicação para diferentes regiões e culturas de forma eficiente e correta.

Dominar Intl não apenas melhora a experiência do usuário, mas também evita erros comuns de formatação manual, como separadores decimais, ordem de data e pluralização irregular. Vamos mergulhar em exemplos práticos e entender como cada componente funciona.

Formatação de números, datas e moedas

O objeto Intl.NumberFormat é usado para formatar números de acordo com o locale. Ele lida com separadores de milhares, decimais, notação científica, e também formata moedas e porcentagens. O construtor recebe um locale (ex.: 'pt-BR', 'en-US') e um objeto de opções que define o estilo (decimal, currency, percent) e outras configurações.

Para datas e horas, temos Intl.DateTimeFormat, que formata datas e horas de acordo com o locale, incluindo nomes de meses, dias da semana e formatos de hora (12h ou 24h). Com as opções, podemos controlar a exibição de cada componente (dia, mês, ano, hora, minuto, etc.).

// Exemplo de formatação de número
const numero = 1234567.89;
const formatadorNumero = new Intl.NumberFormat('pt-BR', { style: 'decimal', maximumFractionDigits: 2 });
console.log(formatadorNumero.format(numero)); // "1.234.567,89"

// Exemplo de formatação de moeda
const formatadorMoeda = new Intl.NumberFormat('pt-BR', { style: 'currency', currency: 'BRL' });
console.log(formatadorMoeda.format(numero)); // "R$ 1.234.567,89"

// Exemplo de formatação de data
const data = new Date('2024-07-15T14:30:00Z');
const formatadorData = new Intl.DateTimeFormat('pt-BR', { dateStyle: 'full', timeStyle: 'short' });
console.log(formatadorData.format(data)); // "segunda-feira, 15 de julho de 2024 às 11:30" (fuso local)

Além de pt-BR, você pode usar qualquer BCP 47 tag, como en-US, de-DE, ja-JP. O JavaScript moderno também suporta a detecção automática de locale do ambiente via navigator.language ou Intl.DateTimeFormat().resolvedOptions().locale.

Pluralização

Pluralização é um desafio em muitos idiomas: enquanto o inglês tem apenas singular e plural, o português tem regras específicas, e outras línguas como o russo ou o árabe têm múltiplas formas. A API Intl.PluralRules resolve isso fornecendo a categoria plural correta para um número em um dado locale.

Com Intl.PluralRules, você pode obter categorias como 'zero', 'one', 'two', 'few', 'many', 'other'. Essas categorias são usadas para escolher a forma correta de uma palavra em uma mensagem. Por exemplo, em português, usamos '1 item' e '2 itens', mas '0 itens' também usa a forma plural.

const regrasPlural = new Intl.PluralRules('pt-BR');
console.log(regrasPlural.select(0)); // "other" (em pt-BR, 0 é tratado como plural)
console.log(regrasPlural.select(1)); // "one"
console.log(regrasPlural.select(2)); // "other"

// Função auxiliar para pluralizar
function pluralizar(numero, formas) {
  const categoria = regrasPlural.select(numero);
  return formas[categoria] || formas['other'];
}

const formas = {
  one: 'item',
  other: 'itens'
};
console.log(`1 ${pluralizar(1, formas)}`); // "1 item"
console.log(`5 ${pluralizar(5, formas)}`); // "5 itens"

Em aplicações reais, você pode combinar Intl.PluralRules com bibliotecas de internacionalização (como i18next) ou usá-lo diretamente para mensagens dinâmicas. É importante lembrar que as categorias variam por idioma; por exemplo, o árabe tem 6 categorias, enquanto o japonês tem apenas 'other'.

Collation

Collation refere-se à ordenação de strings de acordo com as regras de um idioma. O objeto Intl.Collator permite comparar e ordenar strings de forma sensível ao locale, considerando acentos, maiúsculas/minúsculas e regras específicas de cada idioma.

Por exemplo, em português, a ordem alfabética considera acentos: 'á' vem depois de 'a' e antes de 'b'. O Intl.Collator também pode ser usado com o método sort de arrays para obter uma ordenação correta.

const palavras = ['café', 'casa', 'álbum', 'abacaxi'];
const colador = new Intl.Collator('pt-BR', { sensitivity: 'base' });
console.log(palavras.sort(colador.compare)); // ["abacaxi", "álbum", "café", "casa"]

// Comparação direta
console.log(colador.compare('a', 'á')); // -1 (a vem antes de á)

O Intl.Collator suporta opções como usage (sort ou search), sensitivity (base, accent, case, variant) e ignorePunctuation. Isso é essencial para funcionalidades de busca e ordenação em aplicações multilíngues.

Boas práticas

Ao trabalhar com Intl, é recomendado reutilizar instâncias dos objetos, pois criá-los repetidamente pode ter custo de desempenho. Em ambientes Node.js, você pode usar o módulo full-icu para garantir suporte completo a locales, mas desde o Node 13 o ICU completo é incluído por padrão.

Sempre que possível, evite formatar manualmente números ou datas; use a API Intl para garantir consistência e correção. Além disso, teste em diferentes locales para verificar se o comportamento atende às expectativas.

Referências

Exercícios

  1. Formatação de moeda: Escreva uma função que receba um valor numérico e um código de moeda (ex.: 'USD', 'EUR', 'BRL') e retorne a string formatada usando Intl.NumberFormat com o locale 'pt-BR'. Teste com 1234.5 e 'USD'.

    ✓ Resposta:
    function formatarMoeda(valor, moeda) {
      const formatador = new Intl.NumberFormat('pt-BR', { style: 'currency', currency: moeda });
      return formatador.format(valor);
    }
    console.log(formatarMoeda(1234.5, 'USD')); // "US$ 1.234,50"
    
  2. Data longa: Crie uma função que receba uma string de data ISO (ex.: '2024-07-15') e retorne a data no formato longo em português (ex.: '15 de julho de 2024'). Use Intl.DateTimeFormat com opções adequadas.

    ✓ Resposta:
    function formatarDataLonga(dataISO) {
      const data = new Date(dataISO);
      const formatador = new Intl.DateTimeFormat('pt-BR', { day: 'numeric', month: 'long', year: 'numeric' });
      return formatador.format(data);
    }
    console.log(formatarDataLonga('2024-07-15')); // "15 de julho de 2024"
    
  3. Pluralização: Implemente uma função que retorne a forma correta da palavra "item" para um número dado, usando Intl.PluralRules com locale 'pt-BR'. Teste com 0, 1 e 5.

    ✓ Resposta:
    function pluralizarItem(numero) {
      const regras = new Intl.PluralRules('pt-BR');
      const categoria = regras.select(numero);
      return categoria === 'one' ? 'item' : 'itens';
    }
    console.log(pluralizarItem(0)); // "itens"
    console.log(pluralizarItem(1)); // "item"
    console.log(pluralizarItem(5)); // "itens"
    
  4. Ordenação: Dado um array de palavras em português, ordene-o usando Intl.Collator com locale 'pt-BR' e sensitivity 'base'. Imprima o array ordenado.

    ✓ Resposta:
    const palavras = ['café', 'casa', 'álbum', 'abacaxi'];
    const colador = new Intl.Collator('pt-BR', { sensitivity: 'base' });
    const ordenadas = palavras.sort(colador.compare);
    console.log(ordenadas); // ["abacaxi", "álbum", "café", "casa"]
    
  5. Locale automático: Escreva uma função que use o locale do navegador (via navigator.language) para formatar um número como moeda (ex.: 1234.56). Se não houver suporte, use 'pt-BR' como fallback.

    ✓ Resposta:
    function formatarMoedaAutomatica(valor) {
      const locale = (typeof navigator !== 'undefined' && navigator.language) || 'pt-BR';
      const formatador = new Intl.NumberFormat(locale, { style: 'currency', currency: 'BRL' });
      return formatador.format(valor);
    }
    console.log(formatarMoedaAutomatica(1234.56)); // Depende do locale do navegador
    

Observações finais

A API Intl é uma ferramenta poderosa e essencial para desenvolvedores que buscam criar aplicações globais. Ela encapsula complexidades de formatação e ordenação, permitindo que você se concentre na lógica de negócio. Sempre consulte a documentação da MDN para explorar todas as opções disponíveis e mantenha seu código atualizado com as melhores práticas.