API Imperativa
Esta página fue traducida por PageTurner AI (beta). No está respaldada oficialmente por el proyecto. ¿Encontraste un error? Reportar problema →
React Intl ofrece y se construye sobre varias capas de API. Al usar React Intl interactuarás con su API (documentada aquí) y sus componentes de React.
¿Por qué una API Imperativa?
Si bien nuestros componentes ofrecen una integración fluida con React, la API imperativa se recomienda (y a veces requiere) en varios casos de uso:
-
Configurar atributos de texto como
title,aria-labely similares donde no se puede usar un componente de React (ej:<img title/>) -
Formatear texto/fechas-horas... en entornos no React como Node, API de servidor, store de Redux, pruebas...
-
Escenarios de alto rendimiento donde la cantidad de componentes React renderizados se convierte en cuello de botella (ej: renderizado de carteras bursátiles, tablas virtuales con muchas celdas...)
El objeto intl
El núcleo de react-intl es el objeto intl (de tipo IntlShape), que almacena en caché todas las APIs Intl.*, configuraciones, mensajes compilados, etc. El ciclo de vida del objeto intl está ligado al locale y la lista de messages que contiene, lo que significa que al cambiar el locale, este objeto debe recrearse.
El objeto intl debe reutilizarse tanto como sea posible por rendimiento.
Existen varias formas de acceder al objeto intl:
-
Hook
useIntl: Tras declarar tuIntlProvider, puedes acceder al objetointlllamando a este hook en tu componente funcional de React -
HOC
injectIntl: En componentes React basados enclass, puedes envolverlos con el HOCinjectIntlyintlestará disponible comoprop. -
createIntl: En entornos no React (Node, Vue, Angular, pruebas... lo que sea), puedes crear directamente un objetointlllamando a esta función con la misma configuración queIntlProvider.
Hook useIntl
Si un componente puede expresarse como componente funcional, usar el hook useIntl resulta práctico. Este hook useIntl no espera ninguna opción como argumento al ser llamado. Típicamente, así es como se usa:
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 mantener la superficie de la API limpia y simple, solo proporcionamos el hook useIntl en el paquete. Si lo prefieres, el usuario puede envolver este hook integrado para crear hooks personalizados como useFormatMessage fácilmente. Visita el sitio oficial de React para una introducción general a los hooks de React.
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 función es exportada por el paquete react-intl y es una fábrica de Componentes de Orden Superior (HOC). Envolverá el componente React pasado con otro componente React que provee la API de formateo imperativo al componente envuelto mediante sus props. (Similar al patrón connect-to-stores de muchas implementaciones Flux).
Por defecto, la API de formateo se proveerá al componente envuelto mediante props.intl, pero esto puede sobrescribirse especificando options.intlPropName. El valor de la prop será de tipo IntlShape, definido en la siguiente sección.
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
Esto permite crear un objeto IntlShape sin usar Provider. Permite formatear elementos fuera del ciclo de vida de React mientras se reutiliza el mismo objeto intl. Por ejemplo:
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
Crea una instancia de caché para uso global entre localizaciones. Esto memoriza constructores Intl.* creados previamente para mejorar el rendimiento y es solo una caché en memoria.
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 interfaz es exportada por el paquete react-intl y puede usarse junto con la función fábrica HOC injectIntl.
La definición anterior muestra cómo se verá el objeto props.intl inyectado a tu componente mediante injectIntl. Consta de dos partes:
-
IntlConfig: Los metadatos intl pasados como props al componente padre<IntlProvider>. -
IntlFormatters: La API imperativa de formateo descrita abajo.
locale, formats y messages
La localización actual del usuario y en qué debe renderizarse la aplicación. Mientras que defaultLocale y defaultFormats son para fallbacks o durante desarrollo, representando los valores predeterminados de la aplicación. Observa que no hay defaultMessages, porque cada Descriptor de Mensaje proporciona un defaultMessage.
defaultLocale y defaultFormats
Localización y formatos predeterminados para cuando un mensaje no está traducido (ausente en messages). defaultLocale debe ser la localización donde se declaran los defaultMessage para que una oración sea coherente en un único idioma. Sin defaultLocale o si está configurado incorrectamente, podrías encontrarte con escenarios donde una oración está en inglés pero las fechas/horas incrustadas están en español.
textComponent
Permite configurar el contenedor predeterminado para componentes <Formatted*>. Si no se especifica, se usa <React.Fragment>. Antes de V3 se usaba span; consulta la guía de migración para más detalles.
onError
Permite al usuario proporcionar un manejador de errores personalizado. Por defecto, los mensajes de error se registran con console.error si NODE_ENV no está configurado como production.
wrapRichTextChunksInFragment
Al formatear mensajes de texto enriquecido, la salida es de tipo Array<string | React.ReactElement>, lo que puede causar errores de keys. Esta opción envuelve el resultado en un único React.Fragment para evitarlo.
defaultRichTextElements
Un mapa de etiqueta a función de formateo de texto enriquecido. Su propósito es centralizar el formateo de etiquetas comunes como <b>, <p>... o imponer cierto Design System en el código (ej: <a> o <button> estandarizados). Consulta https://github.com/formatjs/formatjs/issues/1752 para más contexto.
formatDate
function formatDate(
value: number | Date | string,
options?: Intl.DateTimeFormatOptions & {format?: string}
): string
Esta función devolverá una cadena con la fecha formateada. Espera un value que pueda analizarse como fecha (ej: isFinite(new Date(value))) y acepta options que cumplen con 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 función devolverá una cadena con la fecha formateada, pero difiere de formatDate por tener las siguientes opciones predeterminadas:
{
hour: 'numeric',
minute: 'numeric',
}
Espera un value que pueda analizarse como fecha (ej: isFinite(new Date(value))) y acepta options que cumplen con DateTimeFormatOptions.
intl.formatTime(Date.now()) /* "4:03 PM" */
formatDateTimeRange
Requiere Intl.DateTimeFormat.prototype.formatRange que tiene soporte limitado en navegadores. Usa nuestro polyfill si necesitas dar soporte.
function formatDateTimeRange(
from: number | Date | string,
to: number | Date | string,
options?: Intl.DateTimeFormatOptions & {format?: string}
): string
Esta función devuelve una cadena formateada de rango fecha/hora. Tanto from como to deben ser valores analizables como fechas (ej: isFinite(new Date(value))).
Espera 2 valores (una fecha from y una fecha to) y acepta options que cumplen con DateTimeFormatOptions.
intl.formatDateTimeRange(new Date('2020-1-1'), new Date('2020-1-15'))
formatRelativeTime
Esto requiere Intl.RelativeTimeFormat que tiene soporte limitado en navegadores. Por favor, usa nuestro polyfill si planeas darles soporte.
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
Esta función devuelve una cadena de tiempo relativo formateada (ej: "hace 1 hora"). Espera un value numérico, una unit y options que cumplen con Intl.RelativeTimeFormatOptions.
intl.formatRelativeTime(0)
intl.formatRelativeTime(-24, 'hour', {style: 'narrow'})
formatNumber
Esta función usa opciones de Intl.NumberFormat.
function formatNumber(
value: number,
options?: Intl.NumberFormatOptions & {format?: string}
): string
Esta función devuelve una cadena numérica formateada. Espera un value analizable como número y acepta options que cumplen con NumberFormatOptions.
intl.formatNumber(1000, {style: 'currency', currency: 'USD'})
Formateando números usando unit
Actualmente es parte de ES2020 NumberFormat.
Hemos proporcionado un polyfill aquí y los tipos de react-intl permiten usar
unidades aprobadas:
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'
Esta función devuelve una categoría plural: "zero", "one", "two", "few", "many", o "other". Espera un value analizable como número y acepta options que cumplen con PluralFormatOptions.
Es una utilidad de bajo nivel cuya salida puede usarse en una sentencia switch para seleccionar cadenas específicas.
intl.formatPlural(1)
intl.formatPlural(3, {style: 'ordinal'})
intl.formatPlural(4, {style: 'ordinal'})
Solo debe usarse en aplicaciones que soporten un único idioma. Para múltiples idiomas usa formatMessage.
formatList
Esto requiere Intl.ListFormat que tiene soporte limitado en navegadores. Por favor, usa nuestro polyfill si planeas darles soporte.
type ListFormatOptions = {
type?: 'disjunction' | 'conjunction' | 'unit'
style?: 'long' | 'short' | 'narrow'
}
function formatList(
elements: (string | React.ReactNode)[],
options?: Intl.ListFormatOptions
): string | React.ReactNode[]
Esta función permite unir listas de elementos de manera segura para i18n. Por ejemplo, cuando la localización es en:
intl.formatList(['Me', 'myself', 'I'], {type: 'conjunction'})
intl.formatList(['5 hours', '3 minutes'], {type: 'unit'})
formatDisplayName
Esto requiere Intl.DisplayNames que tiene soporte limitado en navegadores. Por favor, usa nuestro polyfill si planeas darles soporte.
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
Ejemplos 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
Sintaxis de mensajes
El formateo de cadenas/mensajes es una característica primordial de React Intl que se basa en ICU Message Formatting utilizando la Sintaxis de Mensajes ICU. Esta sintaxis permite definir mensajes desde simples hasta complejos, traducirlos y luego formatearlos en tiempo de ejecución.
Mensaje simple:
Hello, {name}
Mensaje complejo:
Hello, {name}, you have {itemCount, plural,
=0 {no items}
one {# item}
other {# items}
}.
Ver: La Guía de sintaxis de mensajes.
Message Descriptor
React Intl utiliza el concepto de Descriptor de Mensaje para definir los mensajes predeterminados de tu aplicación. Estos descriptores se pasan a formatMessage y son esenciales para la traducción, conteniendo las siguientes propiedades:
-
id: Identificador único y estable para el mensaje -
description: Contexto para el traductor sobre su uso en la UI -
defaultMessage: Mensaje predeterminado (probablemente en inglés)
type MessageDescriptor = {
id: string
defaultMessage?: string
description?: string | object
}
Puedes extraer mensajes declarados en línea usando nuestra CLI.
Fallbacks de formateo de mensajes
Las API de formateo de mensajes realizan un esfuerzo adicional para proporcionar alternativas en situaciones comunes donde falla el formateo; como mínimo, siempre debe devolverse una cadena no vacía. Este es el algoritmo de respaldo para el formateo de mensajes:
-
Buscar y formatear el mensaje traducido con
idpasado a<IntlProvider> -
Recurrir al formateo del
defaultMessage. -
Fallback al contenido original del mensaje traducido con
id -
Fallback al contenido original de
defaultMessage -
Recurrir al
idliteral del mensaje.
"Contenido original" se refiere a usar la plantilla tal cual, sin sustituciones.
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 función devuelve una cadena de mensaje formateada. Requiere un MessageDescriptor con al menos la propiedad id, y acepta un objeto values para rellenar marcadores de posición.
Si se ha pasado un mensaje traducido con id al <IntlProvider> mediante messages, se formateará. De lo contrario, usará defaultMessage. Ver: Fallbacks en Formateo.
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'}) }
con 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>}) }
con formateo de texto enriquecido
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>, }) }
El mensaje definido usando defineMessages para soportar extracción mediante babel-plugin-formatjs, aunque no es obligatorio si no usas el plugin Babel.
Los mensajes pueden ser cadenas simples sin marcadores de posición, siendo el tipo más común.
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
Estas funciones exportadas por react-intl son simplemente un hook para nuestra CLI y plugins de Babel/TS al compilar mensajes predeterminados en archivos JavaScript. La función devuelve el objeto de descriptores de mensaje pasado 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',
})