# General Translation Knowledge Base: ¿Qué es el formato de mensajes ICU?
URL: https://generaltranslation.com/es/kb/icu-message-format.mdx
Docs index: https://generaltranslation.com/llms.txt
Description: El formato de mensajes ICU es una sintaxis que permite que una sola cadena traducible contenga variables, plurales, opciones de selección y ordinales, como {count, plural, one {# file} other {# files}}. Cada idioma conserva las categorías de plural de CLDR que necesita: el inglés usa one y other, mientras que el polaco añade few y many.
Category: Formato según la configuración regional
Last updated: 2026-10-20
Authors: Kevin Wu, Jackie Chen
Published: 2026-10-20

La sintaxis proviene de la clase MessageFormat de ICU (International Components for Unicode), las bibliotecas de internacionalización del Unicode Consortium para C/C++ y Java. Algunas bibliotecas de JavaScript, como FormatJS, implementan la misma gramática. Actualmente también se la conoce como MessageFormat 1, ya que existe una versión rediseñada, MessageFormat 2.

## ¿Qué problema resuelve el formato de mensajes ICU?

El código que arma oraciones a partir de fragmentos funciona en inglés, pero falla en otros idiomas. `'You have ' + n + ' files'` deja fijados en el código el orden de las palabras del inglés y sus dos formas plurales. El polaco necesita cuatro formas para la misma oración: 1 plik, 2 pliki, 5 plików y 1,5 pliku. En muchos idiomas, una oración con género (&quot;She replied&quot; o &quot;He replied&quot;) modifica otras palabras, y los ordinales (1.º, 2.º, 3.º) siguen sus propias reglas.

El formato de mensajes ICU reúne todos esos casos en una sola cadena. El traductor ve la oración completa con todas sus ramas, la reescribe para su idioma y agrega o elimina ramas según lo exija la gramática. Por eso mismo, la [guía de usuario de ICU](https://unicode-org.github.io/icu/userguide/format_parse/messages/) recomienda escribir una oración completa en cada rama: un traductor no puede corregir la gramática de un fragmento que no ve.

## La sintaxis, con ejemplos ejecutables

Todos los ejemplos siguientes se ejecutaron con [`intl-messageformat`](https://formatjs.github.io/docs/intl-messageformat) 12.1.4 de FormatJS en Node.js 24. Un mensaje se analiza una sola vez y luego se le da formato con valores:

```js
import { IntlMessageFormat } from 'intl-messageformat';

const msg = new IntlMessageFormat(
  '{count, plural, =0 {You have no messages.} one {You have # message.} other {You have # messages.}}',
  'en'
);

msg.format({ count: 0 });    // 'You have no messages.'
msg.format({ count: 1 });    // 'You have 1 message.'
msg.format({ count: 1234 }); // 'You have 1,234 messages.'
```

### Argumentos

`{name}` inserta un valor: `Hello, {name}!` con `{ name: 'Ada' }` da como resultado «Hello, Ada!». Los argumentos con tipo dan formato al valor según la configuración regional; así, `Total: {price, number, ::currency/EUR}` con `1234.5` da como resultado «Total: €1,234.50» en inglés.

### plural, `#` y coincidencias exactas

`{count, plural, ...}` elige una rama según la categoría de plural de la configuración regional: `zero`, `one`, `two`, `few`, `many` u `other`. Dentro de una rama, `#` representa el número, con el formato propio de la configuración regional; el mensaje en alemán `{count, plural, one {Sie haben # Nachricht.} other {Sie haben # Nachrichten.}}` muestra &quot;Sie haben 1.234 Nachrichten.&quot; Una coincidencia exacta como `=0` tiene prioridad sobre la categoría; así es como el ejemplo anterior muestra &quot;no messages&quot; en lugar de &quot;0 messages&quot;.

La misma oración en polaco, con las ramas que usa el polaco:

```text
{count, plural, one {# plik} few {# pliki} many {# plików} other {# pliku}}
```

Con `pl`, esto da formato a 1, 2, 5, 22 y 1.5 como &quot;1 plik&quot;, &quot;2 pliki&quot;, &quot;5 plików&quot;, &quot;22 pliki&quot; y &quot;1,5 pliku&quot;.

### select

`select` elige una rama en función de un valor de cadena, y la rama `other` captura todo lo demás:

```text
{gender, select,
  female {She replied to your comment.}
  male {He replied to your comment.}
  other {They replied to your comment.}}
```

`{ gender: 'female' }` produce &quot;She replied to your comment.&quot; y `{ gender: 'nonbinary' }` produce &quot;They replied to your comment.&quot; Mantén la oración completa dentro de cada rama: en otros idiomas, el género puede afectar tanto al verbo como al pronombre.

### selectordinal

`selectordinal` utiliza reglas ordinales, que en inglés tienen cuatro categorías:

```text
{place, selectordinal,
  one {You finished #st.}
  two {You finished #nd.}
  few {You finished #rd.}
  other {You finished #th.}}
```

Para los puestos 1, 2 y 11, los resultados son `You finished 1st.`, `You finished 2nd.` y `You finished 11th.` Los sufijos para 3, 4, 22 y 103 son `rd`, `th`, `nd` y `rd`, respectivamente.

### offset

`offset:1` resta uno al número antes de elegir una categoría y de imprimir `#`, lo que resulta ideal para mensajes del tipo &quot;tú y N personas más&quot;. Las coincidencias exactas se comparan con el valor original:

```text
{guests, plural, offset:1
  =0 {Nobody is going.}
  =1 {{host} is going.}
  one {{host} and # other person are going.}
  other {{host} and # other people are going.}}
```

Con `host: 'Mia'`, para 0, 1, 2 y 5 invitados se obtiene, respectivamente, &quot;Nobody is going.&quot;, &quot;Mia is going.&quot;, &quot;Mia and 1 other person are going.&quot; y &quot;Mia and 4 other people are going.&quot;

### Argumentos anidados

Los argumentos se pueden anidar. La guía de ICU recomienda colocar `select` en el nivel exterior y `plural` en el interior, con una oración completa en cada rama:

```text
{gender, select,
  female {{count, plural, one {She has # new follower} other {She has # new followers}}}
  other {{count, plural, one {They have # new follower} other {They have # new followers}}}}
```

### Apóstrofos y escape

Un apóstrofo ASCII sirve para escapar caracteres de sintaxis, y dos apóstrofos seguidos generan uno literal. A partir de ICU 4.8, un apóstrofo simple solo inicia texto escapado cuando aparece justo antes de un carácter que necesita escaparse, de modo que las contracciones habituales funcionan sin problemas:

```text
It's {name}'s turn. Type '{name}' to insert a name. I''m here.
```

Con `{ name: 'Ada' }`, esto imprime `It's Ada's turn. Type {name} to insert a name. I'm here.` Dentro de un plural, `'#'` imprime un `#` literal. La [guía de sintaxis ICU](https://formatjs.github.io/docs/core-concepts/icu-syntax) de FormatJS recomienda usar el apóstrofo tipográfico (’) en el texto human-readable, lo que evita el problema por completo.

## ¿Qué son las categorías de plural de CLDR?

Las categorías provienen de las [reglas de plural de Unicode CLDR](https://cldr.unicode.org/index/cldr-spec/plural-rules), los mismos datos en los que se basa `Intl.PluralRules` de JavaScript. Esto es lo que devuelve `Intl.PluralRules` para algunos idiomas:

| Idioma                     | Categorías cardinales                        |
| -------------------------- | -------------------------------------------- |
| Inglés (`en`)              | `one`, `other`                               |
| Polaco (`pl`), ruso (`ru`) | `one`, `few`, `many`, `other`                |
| Árabe (`ar`)               | `zero`, `one`, `two`, `few`, `many`, `other` |
| Japonés (`ja`)             | `other`                                      |

`one` no significa exactamente 1: en ruso, 21 también pertenece a `one`. Usa `=1` solo cuando te refieras literalmente a ese número. Para ver cómo se aplica esto a nivel de componente en React, consulta [¿Cómo manejo los plurales en React?](/kb/how-to-handle-plurals-in-react).

## Problemas comunes

* **Los errores de sintaxis se detectan tarde.** Una llave que falta no es más que una cadena hasta que se analiza, y entonces `intl-messageformat` lanza `EXPECT_ARGUMENT_CLOSING_BRACE`. Analiza o valida los mensajes en CI, o precompílalos.
* **Falta la rama `other`.** `intl-messageformat` lanza `MISSING_OTHER_CLAUSE` ante un plural sin `other`, y FormatJS también la exige para `select`.
* **Ramas que no se ajustan al idioma de destino.** Un mensaje en inglés tiene `one` y `other`; la traducción al polaco necesita además `few` y `many`, y la japonesa solo `other`. Tu proceso de traducción tiene que agregar y eliminar ramas, no solo traducir el texto que contienen.
* **Fragmentos.** `{count} {count, plural, one {file} other {files}} deleted` obliga a los traductores a reordenar piezas sueltas. Incluye la oración completa en cada rama.
* **Dialectos mezclados.** La sintaxis predeterminada de i18next es `{{name}}`, con claves de plural como `key_one`, no ICU. Los equipos que quieren usar ICU en i18next agregan el plugin [`i18next-icu`](https://github.com/i18next/i18next-icu).

## ¿Qué bibliotecas admiten el formato de mensajes ICU?

* **ICU4J e ICU4C** son las implementaciones de referencia, en Java y C/C++.
* **FormatJS**: [`intl-messageformat`](https://formatjs.github.io/docs/intl-messageformat) es el analizador y formateador en el que se basa react-intl, con esqueletos de números y fechas como `::currency/EUR` y etiquetas de texto enriquecido. (Consulta [General Translation vs. react-intl](/kb/general-translation-vs-react-intl)).
* **messageformat**: [`@messageformat/core`](https://messageformat.github.io/messageformat/) compila mensajes ICU en funciones de JavaScript; en cambio, la versión 4 del paquete `messageformat` implementa MessageFormat 2.
* **i18next-icu**: el plugin de i18next que hace que i18next use la sintaxis ICU, basado en `intl-messageformat`.
* **Lingui**: sus [macros](https://lingui.dev/ref/macro) convierten JSX y plantillas etiquetadas en mensajes en formato de mensajes ICU en tiempo de compilación.
* **next-intl**: sus [mensajes usan la sintaxis ICU](https://next-intl.dev/docs/usage/messages).

## ¿Qué cambia en MessageFormat 2?

MessageFormat 2 (MF2) es el rediseño del Unicode Consortium, con una sintaxis nueva: declaraciones como `.input` y `.match`, y patrones entre llaves dobles. Su especificación es la [Parte 9 de Unicode LDML](https://www.unicode.org/reports/tr35/tr35-messageFormat.html), que figura como documento estable (aunque algunas funciones siguen marcadas como Draft), y ya está integrada en ICU4C e ICU4J. En JavaScript, la [propuesta `Intl.MessageFormat`](https://github.com/tc39/proposal-intl-messageformat) de TC39 está en Stage 1, así que todavía no forma parte del lenguaje; el paquete `messageformat` 4.x funciona como polyfill. Así queda el ejemplo de plural en MF2:

```text
.input {$count :number}
.match $count
0   {{You have no messages.}}
one {{You have {$count} message.}}
*   {{You have {$count} messages.}}
```

Si se ejecuta con `messageformat` 4.1.0, imprime &quot;You have no messages.&quot;, &quot;You have 1 message.&quot; y &quot;You have 1,234 messages.&quot; para 0, 1 y 1234. Los mensajes de MF2 no son compatibles con las cadenas de MessageFormat 1, y las demás bibliotecas mencionadas leen MessageFormat 1.

## Cómo gestiona ICU General Translation

En `gt-react` y `gt-next`, [`useGT`](/docs/react/reference/hooks/use-gt) devuelve una función que acepta un mensaje ICU y sus valores:

```tsx title="Inbox.tsx"
import { useGT } from 'gt-react';

export function Inbox({ count }: { count: number }) {
  const gt = useGT();
  return (
    <p>
      {gt('{count, plural, =0 {You have no messages.} one {You have # message.} other {You have # messages.}}', {
        count,
        $context: 'Unread message count in the inbox',
      })}
    </p>
  );
}
```

[`npx gt translate`](/docs/cli/reference/commands/translate) extrae estas cadenas y genera una traducción para cada configuración regional de destino, usando como contexto `$context`, tu glosario y tus prompts personalizados. En la configuración regional de origen, `gt-react` 11.4.12 imprime los mismos tres resultados que el ejemplo anterior de `intl-messageformat`.

* **Diccionarios.** Las entradas que se leen mediante [`useTranslations`](/docs/react/reference/hooks/use-translations) pueden usar formateo de ICU, como `{dollars, number, ::currency/USD}`.
* **Catálogos JSON existentes.** La CLI detecta next-intl e i18next (incluido `i18next-icu`) a partir de `package.json` y traduce sus archivos JSON respetando la sintaxis de cada biblioteca. (Consulta [Archivos JSON](/docs/cli/reference/formats/json-files)).
* **Formato sin traducción.** La función [`formatMessage`](/docs/platform/core/reference/utility-functions/formatting/format-message) de la biblioteca Core da formato a un mensaje ICU para una configuración regional.
* **Linting.** La regla `static-string` de `@generaltranslation/react-core-linter` señala los mensajes ICU mal formados. (Consulta [Reglas de lint](/docs/react/reference/lint-rules#static-string)).

No todas las API analizan ICU: [`tx`](/docs/node/reference/functions/tx) de `gt-node` trata las llaves como texto literal. En JSX, [`<Plural>`](/docs/react/reference/components/plural) y [`<Branch>`](/docs/react/reference/components/branch) dentro de [`<T>`](/docs/react/reference/components/t) cubren los mismos casos de plural y select sin necesidad de escribir la sintaxis a mano.

## Conclusiones clave

* El formato de mensajes ICU reúne variables, `plural`, `select`, `selectordinal` y `offset` en una sola cadena traducible, con `#` para representar el número formateado y coincidencias exactas del tipo `=0`.
* Las categorías de plural provienen de CLDR: el inglés tiene 2 formas cardinales; el polaco y el ruso, 4; el árabe, 6, y el japonés, 1, por lo que las traducciones deben añadir o eliminar ramas.
* Escribe oraciones completas en cada rama, incluye siempre `other` y valida la sintaxis antes de que llegue a producción.
* MessageFormat 2 es una especificación estable de Unicode integrada en ICU4C e ICU4J, pero `Intl.MessageFormat` sigue siendo una propuesta de TC39 en Stage 1.
* El hook [`useGT`](/docs/react/reference/hooks/use-gt) de General Translation acepta cadenas ICU en `gt-react` y `gt-next`, y [`npx gt translate`](/docs/cli/reference/commands/translate) genera las traducciones.

## Related questions

- [¿Cómo gestiono los plurales en React?](https://generaltranslation.com/es/kb/how-to-handle-plurals-in-react.mdx): Para gestionar los plurales en React, asigna a cada idioma una oración por cada forma plural y selecciónala con las reglas de plural de ese idioma, ya que el inglés tiene 2 formas, el ruso tiene 4 y el árabe tiene 6. El componente `<Plural>` de General Translation en gt-react y gt-next recibe tus formas de origen, y General Translation genera las formas que necesita cada idioma de destino.
- [Alternativas a react-intl: General Translation vs. react-intl](https://generaltranslation.com/es/kb/general-translation-vs-react-intl.mdx): General Translation permite a los equipos de React conservar la sintaxis de mensajes ICU y, además, añade generación de traducciones, terminología compartida y revisión en el panel de control. react-intl ofrece formato y herramientas de catálogos de FormatJS; General Translation, además, genera las traducciones.
- [¿Cómo traduzco archivos JSON de i18n?](https://generaltranslation.com/es/kb/translate-json-files.mdx): Traduce solo los valores de cadena de un archivo JSON de configuración regional. No modifiques las claves no plurales, los marcadores de posición como {{name}} ni las etiquetas, pero ten en cuenta que las claves plurales varían según el idioma: el polaco necesita inbox_few e inbox_many. Usa una herramienta o API que reconozca el formato y, después, analiza y valida el resultado antes de revisarlo.
- [Alternativas a i18next: General Translation vs. i18next](https://generaltranslation.com/es/kb/general-translation-vs-i18next.mdx): Elige General Translation para mantener los textos inline en los componentes de React y generar traducciones a partir de su estructura JSX y del contexto del producto. También puedes seguir usando i18next y recurrir a General Translation para traducir los catálogos existentes. i18next se encarga de renderizar los mensajes y seleccionar los plurales, pero las traducciones las genera un servicio aparte.
- [¿Cómo debo nombrar las claves de traducción de i18n?](https://generaltranslation.com/es/kb/i18n-key-naming.mdx): Nombra las claves según dónde aparece el texto y qué significa, como checkout.summary.title, y no según su redacción en inglés. Asigna a cada uso distinto su propia clave, aunque el texto en inglés coincida: en alemán, el botón Open se traduce como Öffnen y el estado Open como Offen.

## Previous and next questions

- Previous question: [¿Es la traducción con IA lo bastante precisa para una aplicación en producción?](https://generaltranslation.com/es/kb/is-ai-translation-accurate.mdx)
- Next question: [¿Qué es hreflang y cómo se configura?](https://generaltranslation.com/es/kb/what-is-hreflang.mdx)

## Sitemap

See the [Knowledge Base sitemap](https://generaltranslation.com/es/kb/sitemap.md) for every article.
