API Imperativa
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-labeletc. 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.
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 seuIntlProvider, acesse ointlchamando este hook em componentes funcionais React -
HOC
injectIntl: Em componentes React baseados emclass, envolva-os cominjectIntleintlestará disponível comoprop -
createIntl: Em ambientes não-React (Node, Vue, Angular, testes...), crie diretamente um objetointlchamando esta função com mesma configuração doIntlProvider
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.
intl.formatDate(Date.now(), { year: 'numeric', month: 'numeric', day: 'numeric', })
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.
intl.formatTime(Date.now()) /* "4:03 PM" */
formatDateTimeRange
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.
intl.formatDateTimeRange(new Date('2020-1-1'), new Date('2020-1-15'))
formatRelativeTime
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.
intl.formatRelativeTime(0)
intl.formatRelativeTime(-24, 'hour', {style: 'narrow'})
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.
intl.formatNumber(1000, {style: 'currency', currency: 'USD'})
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:
intl.formatNumber(1000, { style: 'unit', unit: 'kilobyte', unitDisplay: 'narrow', })
intl.formatNumber(1000, { unit: 'fahrenheit', unitDisplay: 'long', style: 'unit', })
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.
intl.formatPlural(1)
intl.formatPlural(3, {style: 'ordinal'})
intl.formatPlural(4, {style: 'ordinal'})
Use apenas em aplicações com suporte a um único idioma. Para múltiplos idiomas, prefira formatMessage.
formatList
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:
intl.formatList(['Me', 'myself', 'I'], {type: 'conjunction'})
intl.formatList(['5 hours', '3 minutes'], {type: 'unit'})
formatDisplayName
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:
intl.formatDisplayName('zh-Hans-SG', {type: 'language'})
// ISO-15924 four letters script code to localized display name intl.formatDisplayName('Deva', {type: 'script'})
// ISO-4217 currency code to localized display name intl.formatDisplayName('CNY', {type: 'currency'})
// ISO-3166 two letters region code to localized display name intl.formatDisplayName('UN', {type: 'region'})
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
}
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 é:
-
Busca e formata mensagem traduzida pelo
idno<IntlProvider> -
Fallback para formatação do
defaultMessage. -
Fallback para fonte da mensagem traduzida pelo
id -
Fallback para fonte do
defaultMessage -
Fallback para o
idliteral 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.
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'}) }
com ReactElement
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>}) }
com formatação rich text
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>, }) }
A mensagem definida usando defineMessages para extração via babel-plugin-formatjs, mas não é obrigatório sem o plugin Babel.
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',
})