Saltar al contenido principal

Formato de Mensajes 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 →

Formatea cadenas de mensajes ICU con marcadores de posición para números, fechas, plurales y selecciones para crear mensajes localizados.

npm Version intl-messageformat minzipped size

Visión general

Objetivos

Este paquete proporciona una forma de gestionar y formatear los mensajes de texto de tu aplicación JavaScript en cadenas localizadas para los usuarios. Puedes usarlo tanto en el navegador como en el servidor mediante Node.js.

Esta implementación se basa en la propuesta Strawman, aunque difiere en algunos aspectos.

Cambios futuros

La API de IntlMessageFormat podría cambiar para mantenerse alineada con ECMA-402, pero este paquete seguirá semver.

Funcionamiento

Los mensajes se proporcionan al constructor como una cadena String o como un objeto AST pre-analizado.

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

La cadena message se analiza y luego se almacena internamente en forma compilada, optimizada para que el método format() genere la cadena formateada para mostrar al usuario.

const output = msg.format(values)

Ejemplo común de uso

Un ejemplo muy frecuente es formatear mensajes con números y etiquetas de plural. Con este paquete puedes asegurarte de que la cadena se formatea correctamente según el locale del usuario, por ejemplo:

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

Sintaxis de mensajes

La sintaxis de mensajes que utiliza este paquete no es propietaria; de hecho, es un estándar común que funciona en múltiples lenguajes de programación y que los traductores profesionales conocen. Este paquete utiliza la sintaxis de mensajes ICU y funciona para todos los idiomas CLDR que tienen reglas de pluralización definidas.

Características

  • Utiliza estándares de la industria: Sintaxis de mensajes ICU y datos de locale CLDR.

  • Soporta argumentos de mensaje plural, select y selectordinal.

  • Formatea números y fechas/horas en mensajes usando Intl.NumberFormat e Intl.DateTimeFormat, respectivamente.

  • Optimizado para llamadas repetidas al método format() de una instancia de IntlMessageFormat.

  • Permite definir estilos/opciones de formato personalizados.

  • Soporta secuencias de escape para caracteres de sintaxis de mensajes, ej.: "'{foo}'" producirá "{foo}" en lugar de interpretarlo como un argumento foo.

Uso

Dependencia moderna de Intl

Este paquete asume que existe el objeto global Intl en el entorno de ejecución. Intl está presente en todos los navegadores modernos (IE11+) y Node (con ICU completo). Los métodos de Intl que utilizamos son:

  1. Intl.NumberFormat para formateo numérico (se puede aplicar polyfill usando @formatjs/intl-numberformat)

  2. Intl.DateTimeFormat para formateo de fechas y horas (se puede aplicar polyfill mediante @formatjs/intl-datetimeformat)

  3. Intl.PluralRules para formateo plural/ordinal (se puede aplicar polyfill mediante @formatjs/intl-pluralrules)

Carga de Intl MessageFormat en el navegador

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

Carga de Intl MessageFormat en Node.js

Se puede hacer de dos maneras:

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

NOTA: Tu Node debe incluir ICU completo

API Pública

Constructor IntlMessageFormat

Para crear un mensaje para formatear, usa el constructor IntlMessageFormat. Este toma tres parámetros:

  • message: string | AST - Mensaje en formato string (o AST preanalizado) que sirve como patrón de formateo.

  • locales: string | string[] - Cadena con etiqueta de idioma BCP 47, o array de dichas cadenas. Si no se proporciona locale, se usará el predeterminado. Cuando se pasa un array de locales, se verifica cada elemento y sus locales ancestros, devolviendo el primero con datos de locale registrados. Ver: Resolución de Locale para más detalles.

  • formats?: object - Objeto opcional con opciones de formato definidas por el usuario.

  • opts?: { formatters?: Formatters, ignoreTag?: boolean } - Opciones opcionales.

    • formatters: Mapa que contiene formateadores memorizados para rendimiento.
    • ignoreTag: Si se deben tratar etiquetas HTML/XML como literales de texto en lugar de tokens. Cuando es false solo permitimos etiquetas simples sin atributos.
const msg = new IntlMessageFormat('My name is {name}.', 'en-US')

Resolución de Locale

IntlMessageFormat usa Intl.NumberFormat.supportedLocalesOf() para determinar qué datos de locale usar según el valor locales pasado al constructor. El resultado se puede obtener llamando al método prototipo resolvedOptions().

Método resolvedOptions()

Este método devuelve un objeto con los valores de opciones resueltos durante la creación de la instancia. Actualmente solo contiene la propiedad locale; ejemplo:

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

Observa cómo el locale especificado en minúsculas: "en-us", se resolvió y normalizó a: "en-US".

Método format(values)

Una vez creado el mensaje, el formateo se realiza llamando al método format() de la instancia pasando una colección de values:

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

Debe proporcionarse un valor para cada argumento en el patrón de mensaje usado en la construcción de la instancia.

Soporte de texto enriquecido

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

Admitimos etiquetas XML incrustadas en el mensaje, ej: this is a <b>strong</b> tag. Esto no es un método completo para incrustar HTML, sino etiquetar fragmentos de texto para contextualizar traducciones. Se aplican restricciones:

  1. Se ignoran los atributos en las etiquetas HTML.

  2. Las etiquetas de autocierre se tratan como literales y no son compatibles; usa placeholders ICU normales como {placeholder}.

  3. Todas las etiquetas especificadas deben tener valores correspondientes, de lo contrario se lanzará error, ej:

Live Editor
function () {
  try {
    return new IntlMessageFormat('a <foo>strong</foo>').format()
  } catch (e) {
    return String(e)
  }
}
Result
  1. Las etiquetas XML/HTML se escapan con apóstrofes como otras construcciones ICU. Para escapar puedes hacer:
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. La incrustación de etiquetas HTML válidas es un área gris actualmente, pues no admitimos especificaciones completas HTML/XHTML/XML.

Método getAst

Devuelve el AST subyacente del mensaje compilado.

Esqueleto de Fecha/Hora/Número

Admitimos el esqueleto de números ICU y un subconjunto del esqueleto de fecha/hora para personalización avanzada de formatos.

Esqueleto de Números

Ejemplo:

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

Puede encontrar el conjunto completo de opciones y sintaxis aquí

Esqueleto de Fecha/Hora

ICU ofrece una amplia gama de patrones para personalizar formatos de fecha/hora. Sin embargo, no todos están disponibles en la API Intl de ECMA402. Por lo tanto, nuestro analizador solo admite los siguientes patrones:

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

Ejemplo:

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

Uso Avanzado

Pasar AST

Puedes pasar AST preanalizados a IntlMessageFormat así:

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

Esto mejora el rendimiento en casos como SSR o plataformas con precarga/precompilación, ya que el AST se puede almacenar en caché.

Si todos tus mensajes están en AST, puedes crear un alias de @formatjs/icu-messageformat-parser a {default: undefined} para ahorrar bytes en el bundling.

Formateadores

Para mensajes complejos, inicializar constructores Intl.* puede ser costoso. Por ello, permitimos pasar formatters para proporcionar instancias memoizadas de estos objetos Intl. Esta opción combinada con pasar AST y fast-memoize puede acelerar el proceso hasta 30x según el benchmark más abajo.

Por ejemplo:

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)