Tu app de Lovable puede estar totalmente traducida y aun así decir «5 элемент» o mostrar un precio como «1,234.50» a un usuario alemán. La causa es la lógica de plurales y formatos escrita para el inglés que se queda en tus componentes. globalize.now es infraestructura de localización impulsada por IA que mantiene tus cadenas en catálogos versionados, y la solución de abajo coloca las reglas de plural dentro de esos catálogos en lugar de en tu código.
¿Por qué se rompen los plurales cuando Lovable traduce mi app?
Porque la regla de plural vive en el componente, no en la traducción. Un patrón generado habitual tiene este aspecto:
<p>{count} {count === 1 ? "item" : "items"} in your cart</p>
Esa línea codifica la gramática del inglés. Quien traduce puede cambiar las palabras, pero no la comprobación === 1, y el orden de las palabras también queda fijo, con el número siempre primero. El inglés tiene dos formas. El ruso tiene cuatro, así que «1 элемент», «2 элемента», «5 элементов» y «1,5 элемента» necesitan terminaciones distintas.
Si configuraste antes el enrutado (consulta cómo hacer multilingüe una app de Lovable), los plurales son el siguiente bug que notan los usuarios, porque nada falla. La frase simplemente es incorrecta.
Paso 1: ¿Cómo escribo un plural que los traductores puedan cambiar?
Usa un mensaje de plural ICU para que la regla pase a la traducción. Con Lingui, tanto el componente Plural como la macro plural generan uno.
import { Plural } from "@lingui/react/macro";
<p>
<Plural value={count} one="# item in your cart" other="# items in your cart" />
</p>
Para cadenas fuera de JSX, usa la macro del paquete core:
import { plural } from "@lingui/core/macro";
const label = plural(count, { one: "# file", other: "# files" });
# se sustituye por el número. Según la documentación de Lingui, solo escribes las formas que necesita tu idioma de origen, y other es obligatoria. Las coincidencias exactas como _0="Your cart is empty" resuelven el caso cero en inglés sin una rama aparte.
Los stacks por defecto de Lovable difieren en la configuración, pero no en esta API, así que el mismo componente funciona en los proyectos Vite SPA y TanStack Start.
¿Qué aspecto tiene el catálogo una vez extraídos los plurales?
Un mensaje por cadena, en sintaxis ICU estándar, guardado como archivo PO en tu repositorio. Quien traduce, ya sea una persona o una IA, aporta las formas que necesita su idioma.
msgid "{count, plural, one {# item in your cart} other {# items in your cart}}"
msgstr "{count, plural, one {# товар в корзине} few {# товара в корзине} many {# товаров в корзине} other {# товара в корзине}}"
La forma other del ruso cubre fracciones como 1,5, por eso coincide con el genitivo singular. Como el catálogo es un archivo versionado, revisas los cambios de plural en una pull request como cualquier otro código. Para la sintaxis en sí, consulta qué es ICU MessageFormat.
¿Qué idiomas necesitan más que one y other?
Unicode CLDR define seis categorías de plural: zero, one, two, few, many y other. Cada idioma usa un subconjunto, y other es obligatoria en todos.
| Idioma | Categorías usadas |
|---|---|
| japonés, chino | other |
| Inglés | one, other |
| Ruso | one, few, many, other |
| Árabe | zero, one, two, few, many, other |
La especificación CLDR indica que el galés también usa las seis. No hace falta memorizarlo. Lo que necesitas es un formato de catálogo que deje a cada idioma rellenar sus propias formas, y PO con mensajes ICU lo hace.
¿Cómo evito que Lovable vuelva a escribir plurales con ternarios?
Pon la regla donde Lovable lee las instrucciones. Lovable regenera componentes cuando le pides nuevas funcionalidades, y una funcionalidad nueva escrita sin la regla trae de vuelta el ternario.
Añade esto a tu Knowledge o a AGENTS.md:
Never hand-build plurals or number formats. Use the Lingui Plural component
or plural() macro for every count. Use Intl with the active locale for every
date, number and price.
El Skill lovable-i18n escribe reglas de este tipo por ti. Cómo lo hace se explica en qué hace el Skill de i18n para Lovable. Tras tu próxima funcionalidad generada, busca === 1 y !== 1 en el diff para confirmar que la regla se cumplió.
Paso 2: ¿Cómo formateo fechas y moneda según el locale?
Usa Intl con el locale activo. El objeto i18n de Lingui también ofrece i18n.date() y i18n.number(), pero llamar directamente a Intl con i18n.locale mantiene las opciones de formato visibles en tu propio código.
import { useLingui } from "@lingui/react";
export function Price({ amount, currency }: { amount: number; currency: string }) {
const { i18n } = useLingui();
return (
<span>
{new Intl.NumberFormat(i18n.locale, { style: "currency", currency }).format(amount)}
</span>
);
}
export function OrderDate({ date }: { date: Date }) {
const { i18n } = useLingui();
return <time>{new Intl.DateTimeFormat(i18n.locale, { dateStyle: "long" }).format(date)}</time>;
}
Los mismos 1234,5 euros se muestran como una cadena distinta en cada locale, con sus propios separadores y posición del símbolo. El formato nunca convierte dinero. Un precio guardado en euros sigue en euros en todos los idiomas, así que guarda el código de moneda junto a cada precio en tu base de datos.
Paso 3: ¿Cómo pruebo todas las categorías de plural antes de publicar?
Pregunta al navegador en qué categoría cae un número y comprueba que cada una tenga su forma.
const ru = new Intl.PluralRules("ru");
[1, 2, 5, 21, 1.5].map((n) => ru.select(n));
// ["one", "few", "many", "one", "other"]
const ar = new Intl.PluralRules("ar");
[0, 1, 2, 3, 11, 100].map((n) => ar.select(n));
// ["zero", "one", "two", "few", "many", "other"]
Añade una prueba por cada idioma que publiques: renderiza el componente con un número de cada categoría y comprueba que ninguno recurra a una forma ausente. Después lee una vez las páginas en ruso y en árabe en el navegador. Un few que falta en un catálogo se nota como una terminación incorrecta, no como un error.
¿Qué cambia si antes usaba un widget de runtime?
Los widgets de runtime traducen el texto ya renderizado tras la carga, así que no pueden ver una regla de plural en tu código. Esa es parte de la razón por la que importa llevar las traducciones al repositorio. Lovalingo cerró el 31/08/2026; la guía de migración y la página de comparación explican qué cambia cuando los catálogos viven en tu repo.
Con globalize.now conectas el repositorio una vez y el codebase se convierte dentro de la app. Después, los jobs de push traducen las nuevas unidades del catálogo y el resultado llega como una pull request. Lovable sincroniza desde GitHub, así que las formas de plural llegan a tu app igual que cualquier otro cambio. La configuración está en la página de integración con Lovable, y el flujo sin dashboard, en localiza una app de Lovable sin dashboard.
globalize.now convierte el texto codificado de tu app en archivos de traducción listos para localizar y los mantiene actualizados en cada despliegue.
Prueba globalize.now gratis