Ir para o conteúdo principal

Intl MessageFormat

Tradução Beta Não Oficial

Esta página foi traduzida por PageTurner AI (beta). Não é oficialmente endossada pelo projeto. Encontrou um erro? Reportar problema →

Formata strings de mensagem ICU com espaços reservados para números, datas, plural e select para criar mensagens localizadas.

npm Version intl-messageformat minzipped size

Visão Geral

Objetivos

Este pacote visa fornecer uma forma de gerenciar e formatar mensagens de string do seu aplicativo JavaScript em textos localizados para os usuários. Você pode usar este pacote no navegador e no servidor via Node.js.

Esta implementação é baseada na proposta Strawman, mas existem alguns pontos onde esta implementação diverge.

Mudanças Futuras

A API IntlMessageFormat pode mudar para se manter alinhada com a ECMA-402, mas este pacote seguirá semver.

Funcionamento

As mensagens são fornecidas ao construtor como uma string String ou um objeto AST pré-analisado.

const msg = new IntlMessageFormat(message, locales, [formats], [opts])

A string message é analisada e armazenada internamente em formato compilado, otimizado para o método format() produzir a string formatada para exibição ao usuário.

const output = msg.format(values)

Exemplo Comum de Uso

Um exemplo muito comum é formatar mensagens com números e rótulos de plural. Com este pacote você garante que o texto seja formatado corretamente para o idioma do usuário, por exemplo:

Live Editor
new IntlMessageFormat(
  `{numPhotos, plural,
      =0 {You have no photos.}
      =1 {You have one photo.}
      other {You have # photos.}
    }`,
  'en-US'
).format({numPhotos: 1000})
Result
Live Editor
new IntlMessageFormat(
  `{numPhotos, plural,
      =0 {Usted no tiene fotos.}
      =1 {Usted tiene una foto.}
      other {Usted tiene # fotos.}
    }`,
  'es-ES'
).format({numPhotos: 1000})
Result

Sintaxe da Mensagem

A sintaxe de mensagem utilizada não é proprietária - é um padrão comum que funciona entre linguagens de programação e conhecido por tradutores profissionais. Este pacote utiliza a sintaxe de mensagem ICU e funciona para todos os idiomas CLDR com regras de pluralização definidas.

Recursos

  • Utiliza padrões do setor: Sintaxe de mensagem ICU e dados de localidade CLDR.

  • Suporta argumentos de mensagem plural, select e selectordinal.

  • Formata números e datas/horas em mensagens usando Intl.NumberFormat e Intl.DateTimeFormat, respectivamente.

  • Otimizado para chamadas repetidas ao método format() de instâncias IntlMessageFormat.

  • Permite definir estilos/opções de formatação personalizados.

  • Suporta sequências de escape para caracteres de sintaxe, ex.: "'{foo}'" produz "{foo}" na saída formatada em vez de interpretar como argumento foo.

Uso

Dependência Moderna Intl

Este pacote assume que o objeto global Intl existe no runtime. Intl está presente em todos os navegadores modernos (IE11+) e Node (com ICU completo). Os métodos Intl utilizados são:

  1. Intl.NumberFormat para formatação numérica (pode ser preenchido via polyfill usando @formatjs/intl-numberformat)

  2. Intl.DateTimeFormat para formatação de datas/horas (pode ser polipreenchido usando @formatjs/intl-datetimeformat)

  3. Intl.PluralRules para formatação plural/ordinal (pode ser polipreenchido usando @formatjs/intl-pluralrules)

Carregando Intl MessageFormat no navegador

<script src="intl-messageformat/intl-messageformat.min.js"></script>

Carregando Intl MessageFormat no Node.js

Faça um dos seguintes:

import IntlMessageFormat from 'intl-messageformat'
const IntlMessageFormat = require('intl-messageformat').default

NOTA: Seu Node deve incluir ICU completo

API Pública

Construtor IntlMessageFormat

Para criar uma mensagem para formatação, use o construtor IntlMessageFormat. Ele recebe três parâmetros:

  • message: string | AST - Mensagem em string (ou AST pré-analisada) que serve como padrão de formatação.

  • locales: string | string[] - String com tag de idioma BCP 47 ou array dessas strings. Se não fornecido, será usado o locale padrão. Com array, cada item e seus locais ancestrais são verificados, retornando o primeiro com dados registrados. Veja: Resolução de Locale para detalhes.

  • formats?: object - Objeto opcional com opções de estilo definidas pelo usuário.

  • opts?: { formatters?: Formatters, ignoreTag?: boolean } - Opções opcionais.

    • formatters: Mapa contendo formatadores memorizados para desempenho.
    • ignoreTag: Trata tags HTML/XML como literais em vez de tokens. Quando false, permite apenas tags simples sem atributos.
const msg = new IntlMessageFormat('My name is {name}.', 'en-US')

Resolução de Locale

IntlMessageFormat usa Intl.NumberFormat.supportedLocalesOf() para determinar os dados de locale baseados no valor locales passado ao construtor. O resultado pode ser obtido via método resolvedOptions().

Método resolvedOptions()

Retorna um objeto com as opções resolvidas durante a criação da instância. Atualmente contém apenas a propriedade locale:

Live Editor
new IntlMessageFormat('', 'en-us').resolvedOptions().locale
Result

Note como o locale especificado em minúsculas "en-us" foi resolvido e normalizado para "en-US".

Método format(values)

Após criar a mensagem, formate-a chamando format() na instância com uma coleção de values:

Live Editor
new IntlMessageFormat('My name is {name}.', 'en-US').format({name: 'Eric'})
Result
placeholders

Um valor deve ser fornecido para cada argumento no padrão de mensagem usado no construtor.

Suporte a Rich Text

Live Editor
new IntlMessageFormat('hello <b>world</b>', 'en').format({
  b: chunks => <strong>{chunks}</strong>,
})
Result

Suportamos tags XML incorporadas na mensagem, ex: this is a <b>strong</b> tag. Isto não se destina a ser um método completo para incorporar HTML, mas sim para marcar trechos específicos de texto para que a tradução possa ser mais contextual. Portanto, aplicam-se as seguintes restrições:

  1. Atributos em tags HTML são ignorados.

  2. Tags auto-fechadas são tratadas como literais (não suportadas) - use placeholders ICU como {placeholder}.

  3. Todas as tags devem ter valores correspondentes - ausência causa erro:

Live Editor
function () {
  try {
    return new IntlMessageFormat('a <foo>strong</foo>').format()
  } catch (e) {
    return String(e)
  }
}
Result
  1. Tags XML/HTML são escapadas com apóstrofes como outros constructs ICU. Exemplo de escape:
Live Editor
new IntlMessageFormat("I '<'3 cats").format()
Result
Live Editor
new IntlMessageFormat("raw '<b>HTML</b>'").format()
Result
Live Editor
new IntlMessageFormat("raw '<b>HTML</b>' with '<a>'{placeholder}'</a>'").format(
  {placeholder: 'some word'}
)
Result
  1. Tags HTML válidas incorporadas são uma área cinzenta atualmente (suporte limitado à especificação completa).

Método getAst

Retorna a AST subjacente da mensagem compilada.

Esqueleto de Data/Hora/Número

Suportamos o esqueleto de números do ICU e um subconjunto do esqueleto de data/hora para personalização avançada de formatos.

Esqueleto de Número

Exemplo:

Live Editor
new IntlMessageFormat(
  'The price is: {price, number, ::currency/EUR}',
  'en-GB'
).format({price: 100})
Result

O conjunto completo de opções e sintaxe pode ser encontrado aqui

Esqueleto de Data/Hora

O ICU oferece uma ampla variedade de padrões para personalizar formatos de data e hora. Entretanto, nem todos estão disponíveis através da API Intl do ECMA402. Portanto, nosso analisador suporta apenas os seguintes padrões:

SymbolMeaningNotes
GEra designator
yyear
Mmonth in year
Lstand-alone month in year
dday in month
Eday of week
elocal day of weeke..eee is not supported
cstand-alone local day of weekc..ccc is not supported
aAM/PM marker
hHour [1-12]
HHour [0-23]
KHour [0-11]
kHour [1-24]
mMinute
sSecond
zTime Zone

Exemplo:

Live Editor
new IntlMessageFormat('Today is: {now, date, ::yyyyMMdd}', 'en-GB').format({
  now: new Date(),
})
Result

Uso Avançado

Passando AST

Você pode passar ASTs pré-analisadas para o IntlMessageFormat desta forma:

new IntlMessageFormat('hello').format() // prints out hello

// is equivalent to

import IntlMessageFormat from 'intl-messageformat'
import {parse} from '@formatjs/icu-messageformat-parser'
new IntlMessageFormat(parse('hello')).format() // prints out hello

Isso melhora o desempenho em casos como SSR ou plataformas com suporte a pré-carregamento/pré-compilação, pois a AST pode ser armazenada em cache.

Se todas suas mensagens estiverem em ASTs, você pode criar um alias para @formatjs/icu-messageformat-parser como {default: undefined} para economizar bytes no empacotamento.

Formatadores

Para mensagens complexas, inicializar construtores Intl.* pode ser custoso. Por isso, permitimos que o usuário passe formatters para fornecer instâncias memoizadas desses objetos Intl. Esta opção combinada com passar AST e fast-memoize pode acelerar em até 30x conforme o benchmark abaixo.

Por exemplo:

import IntlMessageFormat from 'intl-messageformat'
import {memoize} from '@formatjs/fast-memoize'
const formatters = {
getNumberFormat: memoize(
(locale, opts) => new Intl.NumberFormat(locale, opts)
),
getDateTimeFormat: memoize(
(locale, opts) => new Intl.DateTimeFormat(locale, opts)
),
getPluralRules: memoize((locale, opts) => new Intl.PluralRules(locale, opts)),
}
new IntlMessageFormat('hello {number, number}', 'en', undefined, {
formatters,
}).format({number: 3}) // prints out `hello, 3`

Benchmark

format_cached_complex_msg x 153,868 ops/sec ±1.13% (85 runs sampled)
format_cached_string_msg x 21,661,621 ops/sec ±4.06% (84 runs sampled)
new_complex_msg_preparsed x 719,056 ops/sec ±2.83% (78 runs sampled)
new_complex_msg x 12,844 ops/sec ±1.97% (85 runs sampled)
new_string_msg x 409,770 ops/sec ±2.57% (79 runs sampled)
complex msg format x 12,065 ops/sec ±1.66% (81 runs sampled)
complex msg w/ formatters format x 11,649 ops/sec ±2.05% (78 runs sampled)
complex preparsed msg w/ formatters format x 597,153 ops/sec ±1.46% (90 runs sampled)
complex preparsed msg w/ new formatters format x 684,263 ops/sec ±1.37% (89 runs sampled)