Votre application Lovable peut être entièrement traduite et afficher quand même « 5 элемент » ou un prix sous la forme « 1,234.50 » à un utilisateur allemand. La cause : une logique de pluriel et de formatage écrite pour l'anglais et restée dans vos composants. globalize.now est une infrastructure de localisation propulsée par l'IA qui conserve vos chaînes dans des catalogues versionnés ; le correctif ci-dessous place les règles de pluriel dans ces catalogues plutôt que dans votre code.

Pourquoi les pluriels cassent-ils quand Lovable traduit mon app ?

Parce que la règle de pluriel vit dans le composant, pas dans la traduction. Un schéma généré courant ressemble à ceci :

<p>{count} {count === 1 ? "item" : "items"} in your cart</p>

Cette ligne code en dur la grammaire anglaise. Un traducteur peut changer les mots, mais pas le test === 1, et l'ordre des mots est figé lui aussi, avec le nombre toujours en premier. L'anglais a deux formes. Le russe en a quatre : « 1 элемент », « 2 элемента », « 5 элементов » et « 1,5 элемента » demandent chacun une terminaison différente.

Si vous avez d'abord configuré le routage (voir comment rendre une app Lovable multilingue), les pluriels sont le bug suivant que remarquent les utilisateurs, car rien ne plante. La phrase est simplement fausse.

Étape 1 : comment écrire un pluriel que les traducteurs peuvent modifier ?

Utilisez un message de pluriel ICU pour que la règle passe dans la traduction. Avec Lingui, le composant Plural et la macro plural en produisent un.

import { Plural } from "@lingui/react/macro";

<p>
  <Plural value={count} one="# item in your cart" other="# items in your cart" />
</p>

Pour les chaînes hors JSX, utilisez la macro du paquet core :

import { plural } from "@lingui/core/macro";

const label = plural(count, { one: "# file", other: "# files" });

# est remplacé par le nombre. D'après la documentation de Lingui, vous n'écrivez que les formes dont votre langue source a besoin, et other est obligatoire. Les correspondances exactes comme _0="Your cart is empty" gèrent le cas zéro en anglais sans branche séparée.

Les stacks par défaut de Lovable diffèrent par leur configuration, mais pas par cette API : le même composant fonctionne donc dans les projets Vite SPA et TanStack Start.

À quoi ressemble le catalogue une fois les pluriels extraits ?

Un message par chaîne, en syntaxe ICU standard, stocké dans un fichier PO de votre repo. Le traducteur, humain ou IA, fournit les formes dont sa langue a besoin.

msgid "{count, plural, one {# item in your cart} other {# items in your cart}}"
msgstr "{count, plural, one {# товар в корзине} few {# товара в корзине} many {# товаров в корзине} other {# товара в корзине}}"

La forme russe other couvre les fractions comme 1,5, ce qui explique qu'elle corresponde au génitif singulier. Le catalogue étant un fichier versionné, vous relisez les changements de pluriel dans une pull request comme n'importe quel autre code. Pour la syntaxe elle-même, voir ce qu'est ICU MessageFormat.

Quelles langues ont besoin de plus que one et other ?

Unicode CLDR définit six catégories de pluriel : zero, one, two, few, many et other. Chaque langue en utilise un sous-ensemble, et other est obligatoire partout.

LangueCatégories utilisées
Japonais, chinoisother
Anglaisone, other
Russeone, few, many, other
Arabezero, one, two, few, many, other

La spécification CLDR indique que le gallois utilise lui aussi les six. Inutile de tout mémoriser. Il vous faut un format de catalogue où chaque langue remplit ses propres formes, ce que fait PO avec des messages ICU.

Comment empêcher Lovable de réécrire des pluriels en ternaire ?

Placez la règle là où Lovable lit ses instructions. Lovable régénère des composants quand vous demandez de nouvelles fonctionnalités, et une fonctionnalité écrite sans la règle ramène le ternaire.

Ajoutez ceci à votre Knowledge ou à 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.

La compétence lovable-i18n écrit ce genre de règles pour vous. Son fonctionnement est détaillé dans ce que fait la compétence Lovable i18n. Après votre prochaine fonctionnalité générée, cherchez === 1 et !== 1 dans le diff pour vérifier que la règle a tenu.

Étape 2 : comment formater dates et devises selon la locale ?

Utilisez Intl avec la locale active. L'objet i18n de Lingui propose aussi i18n.date() et i18n.number(), mais appeler Intl directement avec i18n.locale garde les options de formatage visibles dans votre propre code.

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>;
}

Les mêmes 1234,5 euros donnent une chaîne différente dans chaque locale, avec ses propres séparateurs et la position de son symbole. Le formatage ne convertit jamais l'argent. Un prix stocké en euros reste en euros dans toutes les langues : conservez donc le code de devise à côté de chaque prix dans votre base de données.

Étape 3 : comment tester chaque catégorie de pluriel avant de livrer ?

Demandez au navigateur dans quelle catégorie tombe un nombre, puis vérifiez que chacune a une forme.

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"]

Ajoutez un test par langue livrée : rendez le composant avec un nombre de chaque catégorie et vérifiez qu'aucun ne retombe sur une forme manquante. Parcourez ensuite une fois les pages russe et arabe dans le navigateur. Un few manquant dans un catalogue se manifeste par une mauvaise terminaison, pas par une erreur.

Qu'est-ce qui change si j'utilisais un widget runtime auparavant ?

Les widgets d'exécution traduisent le texte rendu après le chargement : ils ne voient donc pas une règle de pluriel présente dans votre code. C'est en partie pour cela qu'il est important de déplacer les traductions dans le dépôt. Lovalingo a cessé son activité le 31/08/2026 ; le guide de migration et la page de comparaison détaillent ce qui change quand les catalogues vivent dans votre dépôt.

Avec globalize.now, vous connectez le dépôt une seule fois et la base de code est convertie dans l'app. Ensuite, des tâches déclenchées à chaque push traduisent les nouvelles unités du catalogue et le résultat arrive sous forme de pull request. Lovable se synchronise depuis GitHub : les formes plurielles atteignent donc votre app comme n'importe quel autre changement. La configuration est décrite sur la page d'intégration Lovable, et le flux de travail sans tableau de bord dans localiser une app Lovable sans tableau de bord.

globalize.now transforme le texte codé en dur de votre application en fichiers de traduction prêts à l'emploi et les maintient à jour au fur et à mesure de vos déploiements.

Essayer globalize.now gratuitement