Le build arabe semble cassé, mais la traduction est correcte. La barre latérale reste à gauche, la flèche de retour pointe vers la gauche et l’avatar colle au bord gauche de chaque carte: chaque mot est en arabe, mais chaque bloc reste à l’endroit laissé par la version anglaise. La direction du texte est un attribut HTML et un ensemble de décisions CSS qui vivent dans vos composants; aucun fichier de catalogue ne la contient. globalize.now est une infrastructure de localisation propulsée par l’IA qui extrait les chaînes et maintient les catalogues synchronisés à chaque push Git.
Pourquoi mon app Lovable reste-t-elle orientée de gauche à droite en arabe?
Parce que la direction est une propriété du document et de la feuille de style, pas du message.
Vos catalogues associent des chaînes sources et des chaînes traduites. Une fois compilés pour ar et rendus par vos composants, les mots changent, mais rien d’autre. Que ces catalogues soient au format Lingui, dans lequel globalize.now écrit, ou qu’ils soient gérés par react-i18next ne change rien ici. Aucun de ces formats ne permet d’indiquer « la barre latérale passe de l’autre côté ».
Deux éléments doivent changer. L’attribut dir de l’élément html indique au navigateur dans quel sens s’étend l’axe inline. Votre CSS doit cesser de nommer les côtés et commencer à nommer le début et la fin de cet axe. Tout le reste découle de ces deux changements.
Qu’est-ce qui casse réellement lorsque vous ajoutez l’arabe à une app Lovable?
Les problèmes apparaissent à des endroits prévisibles et concernent tous le style, pas le contenu.
- Les tiroirs de navigation et les barres latérales restent physiquement à gauche.
- Les chevrons, les flèches de retour et les indicateurs de progression pointent dans la mauvaise direction.
- Un padding asymétrique plaque le contenu contre le mauvais bord, ce qui tasse les libellés d’un côté.
text-leftsur un titre maintient l’arabe à gauche de son conteneur.- Les badges et boutons de fermeture en position absolue se retrouvent dans le coin opposé à celui attendu par le lecteur.
- Les bordures gauches qui signalent un élément de liste actif apparaissent sur le bord de fin au lieu du bord de début.
- Un code produit anglais au milieu d’une phrase arabe se réordonne de manière imprévisible sans indication de direction.
Aucun de ces problèmes n’est un défaut de traduction. Ils viennent tous d’une direction physique inscrite dans un nom de classe.
Comment déduire la direction du texte à partir de la balise de locale?
Demandez à la locale quelle direction elle utilise, puis inscrivez la réponse dans le document.
Intl.Locale.prototype.getTextInfo() renvoie une direction égale à ltr ou rtl pour une balise de locale. L’API a été ajoutée à Baseline en juillet 2026, ce qui signifie qu’elle est disponible dans la version actuelle de tous les navigateurs principaux, mais pas dans la plupart de ceux utilisés par vos utilisateurs. Considérez le fallback ci-dessous comme le chemin actif et l’API comme ce qui le remplacera à terme.
// getTextInfo() is not yet in TypeScript's bundled Intl.Locale definitions.
declare global {
namespace Intl {
interface Locale {
getTextInfo?(): { direction: "ltr" | "rtl" };
}
}
}
// Stopgap for runtimes without getTextInfo(). This set is the one place where
// adding a new right-to-left language still costs you a code change.
const RTL_FALLBACK = new Set([
"ar", "he", "fa", "ur", "ps", "sd", "yi", "dv", "ckb", "ug", "nqo", "syr",
]);
export function directionFor(locale: string): "ltr" | "rtl" {
let tag: Intl.Locale | undefined;
try {
tag = new Intl.Locale(locale);
} catch {
// Malformed tag. Fall through to the string path below.
}
const direction = tag?.getTextInfo?.().direction;
if (direction === "ltr" || direction === "rtl") return direction;
const language = tag?.language ?? locale.split(/[-_]/)[0].toLowerCase();
return RTL_FALLBACK.has(language) ? "rtl" : "ltr";
}
Les deux emplacements de try comptent. new Intl.Locale() lève une RangeError avec une balise malformée, tandis que getTextInfo() n’existe tout simplement pas dans les runtimes plus anciens. Ne gérer que le second cas est le bug classique: une locale comme ar_EG provenant d’une query string envoie la fonction dans son propre chemin de récupération, puis la fait ressortir immédiatement sous forme d’erreur non interceptée.
Définissez les deux attributs partout où votre app connaît déjà la locale active. Lovable génère actuellement deux architectures: une app monopage Vite et une app TanStack Start rendue côté serveur. Vérifiez donc ce que votre projet a réellement généré. Avec TanStack Start, c’est le composant du document racine. Avec Vite, c’est l’endroit où vous montez le provider i18n.
<html lang={locale} dir={directionFor(locale)}>
Placez dir sur html plutôt que sur un wrapper div. Les portals, modales et toasts sont rendus en dehors de votre arbre de composants et doivent tout de même en hériter.
Quelles classes Tailwind dois-je modifier pour le RTL?
Celles qui nomment un côté physique. Leurs équivalents logiques suivent l’axe inline et s’inversent automatiquement lorsque dir change.
| Utilitaire physique | Remplacement logique | Propriété définie |
|---|---|---|
| ml-4 / mr-4 | ms-4 / me-4 | margin-inline-start / margin-inline-end |
| pl-6 / pr-6 | ps-6 / pe-6 | padding-inline-start / padding-inline-end |
| left-0 / right-0 | start-0 / end-0 | inset-inline-start / inset-inline-end |
| text-left / text-right | text-start / text-end | alignement du texte sur l’axe inline |
| border-l / border-r | border-s / border-e | bordure de début / bordure de fin |
| coins arrondis à gauche / coins arrondis à droite | coins arrondis au début / coins arrondis à la fin | coins de début / coins de fin |
| flottant à gauche / flottant à droite | flottant au début / flottant à la fin | flottement sur l’axe inline |
| annulation du flottement à gauche / à droite | annulation du flottement au début / à la fin | annulation du flottement sur l’axe inline |
| scroll-ml-4 / scroll-mr-4 | scroll-ms-4 / scroll-me-4 | marge d’accrochage au défilement |
La documentation des marges de Tailwind montre directement l’effet: ms-8 et me-8, rendus dans des conteneurs dir="ltr" et dir="rtl", se placent sur des côtés opposés. Les utilitaires de propriétés logiques sont arrivés dans Tailwind v3.3; un projet ancien peut donc ne pas les prendre en charge.
Deux utilitaires méritent un second examen plutôt qu’un simple renommage. space-x-* et divide-x-* ajoutent de l’espacement et des bordures entre les éléments frères; dans une ligne inversée, ils se retrouvent donc du mauvais côté de chaque élément. Tailwind fournit space-x-reverse et divide-x-reverse précisément pour ce cas. Les utilitaires verticaux comme mt-* et pb-* ne nécessitent aucune modification, puisque la direction ne régit que l’axe inline.
Que peuvent faire les propriétés logiques?
Tout ce qui encode une direction en dehors du modèle de boîte: c’est là que les variantes rtl: et ltr: trouvent leur utilité.
<ChevronRight className="rtl:rotate-180" />
<div className="bg-[url(/hero.svg)] bg-left rtl:bg-right" />
<div className="shadow-[4px_0_8px_rgba(0,0,0,.15)] rtl:shadow-[-4px_0_8px_rgba(0,0,0,.15)]" />
Les transformations, les positions d’arrière-plan, les décalages d’ombre, les angles de dégradé, les calculs de défilement des carrousels et toute icône qui signifie «avancer» entrent dans cette catégorie. Gardez cette liste courte. Écrire rtl: sur un élément sur deux signifie que les styles sous-jacents sont toujours physiques et devraient plutôt être convertis.
Le contenu généré par les utilisateurs nécessite un traitement spécifique, et les deux cas sont différents. Pour un bloc entier dont vous ne contrôlez pas la langue, dir="auto" permet au navigateur de définir la direction de base du bloc à partir de son premier caractère fort.
<p dir="auto">{review.body}</p>
Pour une séquence dans une écriture étrangère au sein d’une phrase dont la direction est déjà définie — un SKU anglais dans un texte arabe, par exemple — dir="auto" ne fait rien, car il définit la direction de base du paragraphe au lieu d’isoler une séquence inline. Encadrez plutôt cette séquence.
<bdi>{product.sku}</bdi>
Pourquoi un widget de traduction ne peut-il pas inverser votre mise en page?
Parce qu’un widget agit sur les nœuds de texte de la page rendue, alors que votre problème de direction se trouve dans les styles qui ont produit cette page.
Un service exécuté à l’exécution peut injecter dir="rtl" dans le document et traduire les chaînes visibles après l’affichage de la version anglaise. Il ne peut pas ouvrir vos composants et transformer ml-4 en ms-4, car ml-4 a déjà été compilé en margin-left dans une feuille de style que le service ne contrôle pas. Résultat: du texte arabe dans une mise en page de gauche à droite.
Il y a un deuxième coût. Lovalingo, un service de traduction à l’exécution utilisé par certaines apps Lovable, a annoncé sa fermeture le 31 août 2026 à 2359 CEST. Ses consignes de migration demandent aux clients de passer à une internationalisation gérée par le projet et de revérifier les routes de locale, les URL canoniques et les balises hreflang avant de le supprimer. Le travail de mise en page effectué dans le produit d’un fournisseur disparaît avec ce fournisseur. Les utilitaires logiques et un attribut dir dans votre propre repo, eux, restent. Notre comparatif Lovalingo défend le même principe pour la couche des chaînes.
Comment empêcher le prochain prompt Lovable de tout annuler?
Convertissez une fois, puis rendez les utilitaires physiques visibles lors de la review.
- Installez le workflow. Dans l’espace de travail Lovable, ajoutez la compétence
lovable-i18net demandez à Lovable de configurer l’i18n. En dehors de l’éditeur, l’installation se fait avecnpx skills add globalize-now/globalize-skills, puis--allpour l’installer pour chaque agent. - Définissez la direction à partir de la locale avec
directionForsur l’élémenthtml. - Convertissez les utilitaires physiques en utilitaires logiques dans vos composants, en commençant par ceux qui englobent vos pages.
- Ajoutez les variantes
rtl:uniquement pour les transformations, les arrière-plans, les ombres et les icônes directionnelles, et utilisez<bdi>pour les séquences inline dans une écriture étrangère. - Ajoutez une règle grep à la review afin qu’un nouvel utilitaire physique échoue avant le merge.
rg -n '\b(ml|mr|pl|pr|scroll-m[lr])-|\b(float|clear|text)-(left|right)\b|\bborder-[lr]\b|\brounded-[lr]-|\b(left|right)-[0-9]' src/
C’est la cinquième étape qui tient dans la durée. Lovable régénère les composants à chaque prompt, et un modèle auquel on demande d’ajouter un panneau de paramètres choisira ml-4, car les utilitaires physiques dominent le code React sur lequel ces modèles ont été entraînés. Un contrôle qui fait échouer la pull request coûte moins cher que de découvrir le problème dans une capture d’écran arabe trois semaines plus tard.
La moitié chaînes de la boucle fonctionne toute seule. globalize.now extrait les nouvelles chaînes codées en dur de tout ce que Lovable a généré, les écrit dans vos catalogues et synchronise le tout à chaque push Git. Le build arabe reste ainsi à jour pendant que vous continuez à prompter. C’est le même mécanisme que celui décrit dans le guide Vite et le guide TanStack Start, et c’est pourquoi les traductions cessent de casser à chaque push.
Ajouter l’arabe ne coûte rien de plus avec ce plan. Le plan Starter coûte 20 € par mois et par espace de travail, avec 20 € de crédit de traduction inclus — soit environ 200 000 mots — puis la consommation continue au même tarif par caractère. Aucun frais par siège ni par langue, et les langues RTL sont incluses. Pour la configuration, consultez la page d’intégration Lovable; pour les détails techniques, la page développeurs; pour un parcours plus court destiné aux créateurs non techniques, la page des vibe coders.
Un changement de mise en page, puis c’est réglé
La direction est une décision que votre repo prend une fois. Les chaînes, elles, changent à chaque prompt — et cette partie fonctionne toute seule.
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