Saltar al contenido principal

Núcleo FormatJS Intl

Traducción Beta No Oficial

Esta página fue traducida por PageTurner AI (beta). No está respaldada oficialmente por el proyecto. ¿Encontraste un error? Reportar problema →

Esta biblioteca contiene la API intl central utilizada por react-intl.

Instalación

npm i -S @formatjs/intl

El objeto intl

El núcleo de @formatjs/intl es el objeto intl (de tipo IntlShape), que es la instancia que almacena en caché todas las APIs Intl.*, configuraciones, mensajes compilados y demás. El ciclo de vida del objeto intl está típicamente vinculado al locale y la lista de messages que contiene, lo que significa que al cambiar el locale, este objeto debe recrearse.

consejo

El objeto intl debe reutilizarse tanto como sea posible por rendimiento.

createIntl

Permite crear un objeto IntlShape que contiene todos los métodos format*. Por ejemplo:

import {createIntl, createIntlCache} from '@formatjs/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)

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
fallbackOnEmptyString?: boolean
formats: CustomFormats
messages: Record<string, string> | Record<string, MessageFormatElement[]>
defaultLocale: string
defaultRichTextElements?: Record<string, FormatXMLElementFn<React.ReactNode>>
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

La definición anterior muestra cómo se verá el objeto intl. 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.

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.

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.

fallbackOnEmptyString

Por defecto es true.

Esta opción booleana puede ser útil si deseas proporcionar intencionalmente valores vacíos para ciertas localizaciones mediante cadenas vacías. Cuando fallbackOnEmptyString es false, se devolverán cadenas vacías en lugar de activar el procedimiento de fallback. Este comportamiento puede aprovecharse para "omitir" contenido en localizaciones específicas.

Consulta este issue para más contexto.

formatDate

function formatDate(
value: number | Date,
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.

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

formatTime

function formatTime(
value: number | Date,
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.

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

formatRelativeTime

soporte del navegador

Requiere Intl.RelativeTimeFormat que tiene soporte limitado en navegadores. Usa nuestro polyfill si necesitas compatibilidad.

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.

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

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.

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

Formateando números usando unit

Actualmente es parte de ES2020 NumberFormat. Proporcionamos un polyfill aquí y los tipos de @formatjs/intl permiten usar unidades admitidas:

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'

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.

Live Editor
intl.formatPlural(1)
Result
Live Editor
intl.formatPlural(3, {style: 'ordinal'})
Result
Live Editor
intl.formatPlural(4, {style: 'ordinal'})
Result
soporte multiidioma

Solo debe usarse en aplicaciones que soporten un único idioma. Para múltiples idiomas usa formatMessage.

formatList

soporte del navegador

Requiere Intl.ListFormat con soporte limitado. Usa nuestro polyfill para compatibilidad.

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

function formatList(
elements: Iterable<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:

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

formatDisplayName

soporte del navegador

Requiere Intl.DisplayNames con soporte limitado. Usa nuestro polyfill para compatibilidad.

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:

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

Sintaxis de mensajes

El formateo de cadenas/mensajes usa ICU Message Formatting mediante Sintaxis ICU, permitiendo mensajes simples/complejos traducidos y formateados 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: 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
}
Extracción de Descriptor de Mensaje

Puedes extraer mensajes declarados en línea de archivos fuente 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:

  1. Buscar y formatear el mensaje traducido con id pasado a <IntlProvider>

  2. Recurrir al formateo del defaultMessage.

  3. Fallback al contenido original del mensaje traducido con id

  4. Fallback al contenido original de defaultMessage

  5. Recurrir al id literal 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.

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

con 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

con formateo de texto enriquecido

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

El mensaje definido usando defineMessages para soportar extracción mediante babel-plugin-formatjs, aunque no es obligatorio si no usas el plugin Babel.

mensaje simple

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 @formatjs/intl sirven como punto de integración para nuestra CLI y plugins de Babel/TS al compilar mensajes predeterminados en archivos JavaScript. Simplemente devuelven el objeto de mapa de Descriptor de Mensaje que reciben.

import {defineMessages, defineMessage} from '@formatjs/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',
})