Ir para o conteúdo principal

API Imperativa

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 →

O React Intl fornece e é construído sobre algumas camadas de API. Ao usá-lo, você interagirá com sua API (documentada aqui) e seus componentes React.

Por que uma API Imperativa?

Embora nossos componentes ofereçam integração perfeita com React, a API imperativa é recomendada (às vezes necessária) em vários casos:

  • Definir atributos de texto como title, aria-label etc. onde componentes React não podem ser usados (ex: <img title/>)

  • Formatar texto/datas... em ambientes não-React como Node, APIs de servidor, stores Redux, testes...

  • Cenários de alta performance onde a quantidade de componentes React se torna um gargalo (ex: renderização de portfólios financeiros, tabelas virtuais com muitas células...)

O objeto intl

O núcleo do react-intl é o objeto intl (do tipo IntlShape), que armazena cache das APIs Intl.*, configurações, mensagens compiladas etc. O ciclo de vida do objeto intl está vinculado ao locale & à lista de messages, significando que ao alternar locale, este objeto deve ser recriado.

dica

O objeto intl deve ser reutilizado sempre que possível por questões de desempenho.

Há várias formas de acessar o objeto intl:

  • Hook useIntl: Após declarar seu IntlProvider, acesse o intl chamando este hook em componentes funcionais React

  • HOC injectIntl: Em componentes React baseados em class, envolva-os com injectIntl e intl estará disponível como prop

  • createIntl: Em ambientes não-React (Node, Vue, Angular, testes...), crie diretamente um objeto intl chamando esta função com mesma configuração do IntlProvider

Hook useIntl

Para componentes expressos como funções, o hook useIntl é prático. Este hook useIntl não requer opções como argumento. Exemplo de uso típico:

import React from 'react'
import {useIntl, FormattedDate} from 'react-intl'

const FunctionComponent: React.FC<{date: number | Date}> = ({date}) => {
const intl = useIntl()
return (
<span title={intl.formatDate(date)}>
<FormattedDate value={date} />
</span>
)
}

export default FunctionComponent

Para manter a API limpa, fornecemos apenas useIntl. Se preferir, encapsule este hook para criar soluções como useFormatMessage. Consulte a introdução oficial a hooks.

HOC injectIntl

type WrappedComponentProps<IntlPropName extends string = 'intl'> = {
[k in IntlPropName]: IntlShape
}

type WithIntlProps<P> = Omit<P, keyof WrappedComponentProps> & {
forwardedRef?: React.Ref<any>
}

function injectIntl<
IntlPropName extends string = 'intl',
P extends WrappedComponentProps<IntlPropName> = WrappedComponentProps<any>,
>(
WrappedComponent: React.ComponentType<P>,
options?: Opts<IntlPropName>
): React.ComponentType<WithIntlProps<P>> & {
WrappedComponent: typeof WrappedComponent
}

Esta função exportada pelo react-intl é uma fábrica de Componentes de Alta Ordem (HOC). Ela envolve seu componente React com outro que fornece a API imperativa via props (similar ao padrão connect-to-stores do Flux).

Por padrão, a API é fornecida via props.intl, mas isso pode ser sobrescrito com options.intlPropName. O valor será do tipo IntlShape descrito a seguir.

import React from 'react'
import {injectIntl, FormattedDate} from 'react-intl'

interface Props {
date: Date | number
}

const FunctionalComponent: React.FC<Props> = props => {
const {
date,
intl, // Injected by `injectIntl`
} = props
return (
<span title={intl.formatDate(date)}>
<FormattedDate value={date} />
</span>
)
}

export default injectIntl(FunctionalComponent)

createIntl

Permite criar um objeto IntlShape sem Provider, formatando elementos fora do ciclo React enquanto reutiliza o mesmo intl. Exemplo:

import {createIntl, createIntlCache, RawIntlProvider} from 'react-intl'

// This is optional but highly recommended
// since it prevents memory leak
const cache = createIntlCache()

const intl = createIntl({
locale: 'fr-FR',
messages: {}
}, cache)

// Call imperatively
intl.formatNumber(20)

// Pass it to IntlProvider
<RawIntlProvider value={intl}>{foo}</RawIntlProvider>

createIntlCache

Cria uma instância de cache para uso global entre locales. Memoriza construtores Intl.* previamente criados para desempenho, sendo apenas um cache em memória.

IntlShape

interface IntlConfig {
locale: string
timeZone?: string
formats: CustomFormats
textComponent?: React.ComponentType | keyof React.JSX.IntrinsicElements
messages: Record<string, string> | Record<string, MessageFormatElement[]>
defaultLocale: string
defaultFormats: CustomFormats
onError(err: string): void
onWarn(warning: string): void
}

interface IntlFormatters {
formatDate(value: number | Date | string, opts?: FormatDateOptions): string
formatTime(value: number | Date | string, opts?: FormatDateOptions): string
formatDateToParts(
value: number | Date | string,
opts?: FormatDateOptions
): Intl.DateTimeFormatPart[]
formatTimeToParts(
value: number | Date | string,
opts?: FormatDateOptions
): Intl.DateTimeFormatPart[]
formatRelativeTime(
value: number,
unit?: FormattableUnit,
opts?: FormatRelativeTimeOptions
): string
formatNumber(value: number, opts?: FormatNumberOptions): string
formatNumberToParts(
value: number,
opts?: FormatNumberOptions
): Intl.NumberFormatPart[]
formatPlural(
value: number | string,
opts?: FormatPluralOptions
): ReturnType<Intl.PluralRules['select']>
formatMessage(
descriptor: MessageDescriptor,
values?: Record<string, PrimitiveType | FormatXMLElementFn<string, string>>
): string
formatMessage(
descriptor: MessageDescriptor,
values?: Record<string, PrimitiveType | T | FormatXMLElementFn<T, R>>
): R
formatList(values: Iterable<string>, opts?: FormatListOptions): string
formatList(
values: Iterable<string | T>,
opts?: FormatListOptions
): T | string | Array<string | T>
formatListToParts(
values: Iterable<string | T>,
opts?: FormatListOptions
): Part[]
formatDisplayName(
value: string,
opts?: FormatDisplayNameOptions
): string | undefined
}

type IntlShape = IntlConfig & IntlFormatters

Esta interface exportada pelo react-intl é usada em conjunto com a função HOC injectIntl.

A definição acima mostra como o objeto props.intl injetado via injectIntl se estrutura, composto por duas partes:

  • IntlConfig: Metadados intl passados como props no componente pai <IntlProvider>.

  • IntlFormatters: A API imperativa de formatação descrita abaixo.

locale, formats e messages

O locale atual do usuário e no qual o aplicativo deve ser renderizado. Enquanto defaultLocale e defaultFormats servem para fallbacks ou durante o desenvolvimento, representando os padrões do aplicativo. Note que não há defaultMessages, pois cada Message Descriptor fornece seu próprio defaultMessage.

defaultLocale e defaultFormats

Locale e formatos padrão para quando uma mensagem não está traduzida (ausente em messages). defaultLocale deve ser o locale onde defaultMessages são declarados, garantindo coerência na sentença. Sem defaultLocale ou configurado incorretamente, pode ocorrer uma sentença em inglês com data/hora em espanhol.

textComponent

Configura o wrapper padrão para componentes <Formatted*> do React Intl. Se não especificado, usa <React.Fragment>. Antes da v3, usava-se span; consulte o guia de migração para detalhes.

onError

Permite fornecer um tratador de erros personalizado. Por padrão, erros são registrados via console.error se NODE_ENV não estiver definido como production.

wrapRichTextChunksInFragment

Ao formatar mensagens rich text, a saída Array<string | React.ReactElement> causa erros de chave. Esta prop envolve a saída em um único React.Fragment para suprimir isso.

defaultRichTextElements

Um mapeamento de tags para funções de formatação de rich text. Fornece uma forma centralizada de formatar tags comuns como <b>, <p>... ou aplicar sistemas de design (ex: <a> ou <button> padronizados). Veja https://github.com/formatjs/formatjs/issues/1752 para contexto.

formatDate

function formatDate(
value: number | Date | string,
options?: Intl.DateTimeFormatOptions & {format?: string}
): string

Retorna uma string formatada de data. Espera um value que possa ser interpretado como data (ex: isFinite(new Date(value))) e aceita options que seguem DateTimeFormatOptions.

Live Editor
intl.formatDate(Date.now(), {
  year: 'numeric',
  month: 'numeric',
  day: 'numeric',
})
Result

formatTime

function formatTime(
value: number | Date | string,
options?: Intl.DateTimeFormatOptions & {format?: string}
): string

Esta função retorna uma string formatada de data, mas difere do formatDate por ter as seguintes opções padrão:

{
hour: 'numeric',
minute: 'numeric',
}

Espera um value que possa ser interpretado como data (ex: isFinite(new Date(value))) e aceita options que seguem DateTimeFormatOptions.

Live Editor
intl.formatTime(Date.now()) /* "4:03 PM" */
Result

formatDateTimeRange

suporte do navegador

Requer Intl.DateTimeFormat.prototype.formatRange com suporte limitado em navegadores. Use nosso polyfill para compatibilidade.

function formatDateTimeRange(
from: number | Date | string,
to: number | Date | string,
options?: Intl.DateTimeFormatOptions & {format?: string}
): string

Retorna uma string formatada de intervalo de data/hora. Tanto from quanto to devem ser valores interpretáveis como datas (ex: isFinite(new Date(value))).

Espera 2 valores (data from e data to) e aceita options que seguem DateTimeFormatOptions.

Live Editor
intl.formatDateTimeRange(new Date('2020-1-1'), new Date('2020-1-15'))
Result

formatRelativeTime

suporte do navegador

Este recurso requer Intl.RelativeTimeFormat, com suporte limitado nos navegadores. Use nosso polyfill se precisar dar suporte a eles.

type Unit =
| 'second'
| 'minute'
| 'hour'
| 'day'
| 'week'
| 'month'
| 'quarter'
| 'year'

type RelativeTimeFormatOptions = {
numeric?: 'always' | 'auto'
style?: 'long' | 'short' | 'narrow'
}

function formatRelativeTime(
value: number,
unit: Unit,
options?: Intl.RelativeTimeFormatOptions & {
format?: string
}
): string

Retorna uma string de tempo relativo formatado (ex: "há 1 hora"). Espera um value numérico, uma unit e options que seguem Intl.RelativeTimeFormatOptions.

Live Editor
intl.formatRelativeTime(0)
Result
Live Editor
intl.formatRelativeTime(-24, 'hour', {style: 'narrow'})
Result

formatNumber

Esta função utiliza opções de Intl.NumberFormat.

function formatNumber(
value: number,
options?: Intl.NumberFormatOptions & {format?: string}
): string

Retorna uma string numérica formatada. Espera um value interpretável como número e aceita options que seguem NumberFormatOptions.

Live Editor
intl.formatNumber(1000, {style: 'currency', currency: 'USD'})
Result

Formatação numérica usando unit

Atualmente parte do ES2020 NumberFormat. Fornecemos um polyfill aqui e os tipos do react-intl permitem usar unidades homologadas:

Live Editor
intl.formatNumber(1000, {
  style: 'unit',
  unit: 'kilobyte',
  unitDisplay: 'narrow',
})
Result
Live Editor
intl.formatNumber(1000, {
  unit: 'fahrenheit',
  unitDisplay: 'long',
  style: 'unit',
})
Result

formatPlural

type PluralFormatOptions = {
type?: 'cardinal' | 'ordinal' = 'cardinal'
}

function formatPlural(
value: number,
options?: Intl.PluralFormatOptions
): 'zero' | 'one' | 'two' | 'few' | 'many' | 'other'

Retorna uma categoria plural: "zero", "one", "two", "few", "many" ou "other". Espera um value interpretável como número e aceita options que seguem PluralFormatOptions.

Utilitário de baixo nível cuja saída pode alimentar estruturas switch para selecionar strings específicas.

Live Editor
intl.formatPlural(1)
Result
Live Editor
intl.formatPlural(3, {style: 'ordinal'})
Result
Live Editor
intl.formatPlural(4, {style: 'ordinal'})
Result
suporte multilíngue

Use apenas em aplicações com suporte a um único idioma. Para múltiplos idiomas, prefira formatMessage.

formatList

suporte do navegador

Requer Intl.ListFormat com suporte limitado em navegadores. Use nosso polyfill se precisar de compatibilidade.

type ListFormatOptions = {
type?: 'disjunction' | 'conjunction' | 'unit'
style?: 'long' | 'short' | 'narrow'
}

function formatList(
elements: (string | React.ReactNode)[],
options?: Intl.ListFormatOptions
): string | React.ReactNode[]

Esta função permite juntar listas de elementos de forma segura para internacionalização. Por exemplo, quando o locale é en:

Live Editor
intl.formatList(['Me', 'myself', 'I'], {type: 'conjunction'})
Result
Live Editor
intl.formatList(['5 hours', '3 minutes'], {type: 'unit'})
Result

formatDisplayName

suporte do navegador

Requer Intl.DisplayNames com suporte limitado em navegadores. Use nosso polyfill se precisar de compatibilidade.

type FormatDisplayNameOptions = {
style?: 'narrow' | 'short' | 'long'
type?: 'language' | 'region' | 'script' | 'currency'
fallback?: 'code' | 'none'
}

function formatDisplayName(
value: string | number | Record<string, unknown>,
options?: FormatDisplayNameOptions
): string | undefined

Exemplos de uso:

Live Editor
intl.formatDisplayName('zh-Hans-SG', {type: 'language'})
Result
Live Editor
// ISO-15924 four letters script code to localized display name
intl.formatDisplayName('Deva', {type: 'script'})
Result
Live Editor
// ISO-4217 currency code to localized display name
intl.formatDisplayName('CNY', {type: 'currency'})
Result
Live Editor
// ISO-3166 two letters region code to localized display name
intl.formatDisplayName('UN', {type: 'region'})
Result

formatMessage

Sintaxe da Mensagem

A formatação de strings/mensagens é essencial no React Intl, baseando-se em ICU Message Formatting através da Sintaxe ICU. Essa sintaxe permite definir mensagens simples ou complexas, traduzi-las e formatá-las em tempo de execução.

Mensagem Simples:

Hello, {name}

Mensagem Complexa:

Hello, {name}, you have {itemCount, plural,
=0 {no items}
one {# item}
other {# items}
}.

Veja: Guia de Sintaxe de Mensagem.

Descritor de Mensagem

O React Intl usa o conceito de Message Descriptor para definir mensagens padrão do aplicativo, passadas para formatMessage. Esses descritores são fundamentais para traduções e contêm:

  • id: Identificador único e estável para a mensagem

  • description: Contexto para tradutores sobre o uso na interface

  • defaultMessage: Mensagem padrão (geralmente em inglês)

type MessageDescriptor = {
id: string
defaultMessage?: string
description?: string | object
}
Extração de Message Descriptor

Mensagens inline podem ser extraídas de arquivos fonte usando nossa CLI.

Fallbacks de Formatação de Mensagem

As APIs de formatação implementam fallbacks robustos para garantir retorno de strings não vazias. O algoritmo é:

  1. Busca e formata mensagem traduzida pelo id no <IntlProvider>

  2. Fallback para formatação do defaultMessage.

  3. Fallback para fonte da mensagem traduzida pelo id

  4. Fallback para fonte do defaultMessage

  5. Fallback para o id literal da mensagem.

"Fonte" refere-se ao uso do template bruto, sem substituições.

Uso

type MessageFormatPrimitiveValue = string | number | boolean | null | undefined
function formatMessage(
descriptor: MessageDescriptor,
values?: Record<string, MessageFormatPrimitiveValue>
): string
function formatMessage(
descriptor: MessageDescriptor,
values?: Record<
string,
MessageFormatPrimitiveValue | React.ReactElement | FormatXMLElementFn
>
): string | React.ReactNode[]

Esta função retorna uma string de mensagem formatada. Espera um MessageDescriptor com pelo menos a propriedade id e aceita um objeto values para preencher placeholders.

Se uma mensagem traduzida com esse id foi passada ao <IntlProvider> via prop messages, ela será formatada. Caso contrário, usa fallback para defaultMessage. Veja Fallbacks de Formatação.

Live Editor
function () {
  const messages = defineMessages({
    greeting: {
      id: 'app.greeting',
      defaultMessage: 'Hello, {name}!',
      description: 'Greeting to welcome the user to the app',
    },
  })

  return intl.formatMessage(messages.greeting, {name: 'Eric'})
}
Result

com ReactElement

Live Editor
function () {
  const messages = defineMessages({
    greeting: {
      id: 'app.greeting',
      defaultMessage: 'Hello, {name}!',
      description: 'Greeting to welcome the user to the app',
    },
  })

  return intl.formatMessage(messages.greeting, {name: <b>Eric</b>})
}
Result

com formatação rich text

Live Editor
function () {
  const messages = defineMessages({
    greeting: {
      id: 'app.greeting',
      defaultMessage: 'Hello, <bold>{name}</bold>!',
      description: 'Greeting to welcome the user to the app',
    },
  })

  return intl.formatMessage(messages.greeting, {
    name: 'Eric',
    bold: str => <b>{str}</b>,
  })
}
Result

A mensagem definida usando defineMessages para extração via babel-plugin-formatjs, mas não é obrigatório sem o plugin Babel.

mensagem simples

Mensagens podem ser strings simples sem placeholders, sendo o tipo mais comum.

defineMessages/defineMessage

interface MessageDescriptor {
id?: string
description?: string | object
defaultMessage?: string
}

function defineMessages(
messageDescriptors: Record<string, MessageDescriptor>
): Record<string, MessageDescriptor>

function defineMessage(messageDescriptor: MessageDescriptor): MessageDescriptor

Exportadas pelo pacote react-intl, funcionam como hooks para nossa CLI e plugins Babel/TS compilarem mensagens padrão em arquivos JavaScript. Simplesmente retornam o objeto Message Descriptor passado como parâmetro.

import {defineMessages, defineMessage} from 'react-intl'

const messages = defineMessages({
greeting: {
id: 'app.home.greeting',
description: 'Message to greet the user.',
defaultMessage: 'Hello, {name}!',
},
})

const msg = defineMessage({
id: 'single',
defaultMessage: 'single message',
description: 'header',
})