Sortie arabe correcte du premier coup
Objectif : un arabe qui s'affiche, se lit et se ressent comme natif du premier coup, dans tout format de sortie.
1. Décider de trois choses avant d'écrire quoi que ce soit
| Décision | Par défaut | Changer quand |
|---|---|---|
| Locale du public | ar + région si connue (ar-SA, ar-EG, ar-AE, ar-MA...) | L'utilisateur nomme un pays/une ville/un marché |
| Chiffres | Chiffres occidentaux 0-9 pour UI, prix, téléphones, code, graphiques. Chiffres arabo-indiens ٠-٩ pour texte formel/éditorial destiné à l'Égypte, l'Arabie Saoudite, l'Irak, le Levant, le Soudan, le Yémen | L'utilisateur le demande, ou la marque/région utilise clairement ٠-٩. Le Maghreb (MA/DZ/TN) utilise toujours 0-9 |
| Registre | Arabe standard moderne (فصحى), clair et moderne, pas classique | L'utilisateur demande un dialecte (égyptien, du Golfe, levantin...) ou le canal est informel (promos WhatsApp, publications sociales) : voir references/writing.md |
Ne jamais mélanger les systèmes de chiffres dans une même sortie.
2. Règles fondamentales (s'appliquent à tout type de sortie)
- Déclarer la direction à la racine, une fois. Puis tout hérite.
❌
<html>+style="direction:rtl"appliqué à des éléments ✅<html lang="ar" dir="rtl">· docx<w:bidi/>+<w:rtl/>· pptxrtl="1"· FlutterDirectionality(textDirection: TextDirection.rtl)/locale: Locale('ar') - Utiliser les directions logiques, jamais gauche/droite. "Début" est le côté droit en arabe.
❌
margin-left,ml-4,text-left,left: 0,EdgeInsets.only(left:)✅margin-inline-start,ms-4,text-start,inset-inline-start: 0,EdgeInsetsDirectional.only(start:) - Isoler les îlots LTR (numéros de téléphone, e-mails, URLs, code, noms anglais à côté de nombres, nombres négatifs).
❌
اتصل على +966 50 123 4567.→ s'affiche comme4567 123 50 966+✅اتصل على <bdi dir="ltr">+966 50 123 4567</bdi>.· texte brut : entourer de LRI…PDI (…) ou mettre LRMavant-5 - Les champs de saisie pour téléphone, e-mail, URL, code, IBAN, mots de passe restent
dir="ltr"même dans un formulaire RTL (les aligner avectext-end). - Inverser uniquement les icônes directionnelles. Les flèches avant/arrière, chevrons, envoyer, répondre, annuler/rétablir, la direction de progression s'inversent. Les contrôles lecture/pause, médias, coches, horloges, recherche, logos, marques et nombres ne sont pas inversés.
- Typographie : utiliser une police conçue pour l'arabe (liste dans
references/typography.md), un interlignage ≥ 1.6 pour le corps du texte, et laisser de l'espace au-dessus et en dessous pour les tashkeel. Ne jamais appliquer d'espacement des lettres/tracking-*,uppercase,italicou de hauteursoverflow:hiddenserrées à du texte arabe. - Ligature (shaping) : texte brut vers les moteurs qui ligaturent, texte ligaturé vers le reste. Jamais les deux.
Les navigateurs, Word, LibreOffice, PowerPoint, WeasyPrint, Chromium PDF, matplotlib ≥ 3.11, Pillow avec libraqm, fpdf2 avec
set_text_shaping()ligaturent eux-mêmes : passer la chaîne brute. reportlab, PyMuPDFinsert_text, OpenCV, matplotlib ≤ 3.10, Pillow sans raqm dessinent glyphe par glyphe : passerprepare(text)descripts/shape_text.py. Religaturer un texte pour un moteur qui le fait déjà l'inverse à nouveau (vérifié dans matplotlib 3.11 et Pillow+raqm). - Ponctuation arabe :
،virgule,؛point-virgule,؟point d'interrogation,«»guillemets. Garder.et!. Ne pas mettre d'espace avant la ponctuation et un espace après. - Écrire en arabe natif, ne pas traduire mot à mot. Verbes impératifs pour les boutons (
أرسل,احفظ,ابدأ الآن), et pas d'ordre des mots anglais. Voirreferences/writing.md. - Formater les nombres/dates/monnaie avec la locale, pas par concaténation de chaînes. Utiliser
Intl.NumberFormat('ar-SA', ...)/Intl.DateTimeFormat('ar-EG-u-nu-latn', ...), et toujours définirnu(chiffres) etca(calendrier) explicitement.
3. Charger la référence pour votre type de sortie
Lire uniquement ce dont la tâche a besoin :
| Sortie | Lire |
|---|---|
| HTML, CSS, Tailwind, React, Next.js, Vue, React Native, Flutter, e-mail HTML | references/web.md + references/bidi.md |
| Arabe + anglais/chiffres mélangés partout (y compris markdown, texte brut, SMS, chaînes JSON) | references/bidi.md |
| Polices, interlignage, tashkeel, graisses, justification | references/typography.md |
| Word (.docx), PowerPoint (.pptx), PDF | references/documents.md |
| matplotlib, Pillow, SVG, canvas, OpenCV, Plotly, toute image avec texte | references/charts-images.md |
| Rédaction, traduction, dialectes, chiffres, dates, monnaie, noms, Hijri | references/writing.md |
4. Ce qui s'inverse en RTL et ce qui ne s'inverse pas
| S'inverse (miroir de la mise en page) | Reste identique |
|---|---|
| Ordre de lecture, alignement du texte, ordre de navigation, position de la barre latérale | Numéros de téléphone, cartes de crédit, IBAN (toujours LTR) |
Fil d'Ariane, pagination, steppers : "suivant" pointe à gauche. Les textes › > ( s'inversent automatiquement, mais pas → ni les icônes SVG | Blocs de code, sortie terminal, URLs, e-mails |
| Flèches précédent/suivant, chevrons, sens de balayage des carrousels/curseurs | Axe x des graphiques temporels (le temps va de gauche à droite). Les axes de catégories peuvent s'inverser |
| Ordre des colonnes d'un tableau (première colonne à droite) | Contrôles média (lecture ▶, avance rapide), horloges, coches |
| Barres de progression et curseurs se remplissent depuis la droite | Logos, marques, photos, cartes |
Étiquettes de formulaire à droite, bouton de fermeture × à gauche d'une boîte de dialogue | Expressions mathématiques et nombres eux-mêmes (1 234,5 reste 1 234,5) |
| Côté de glissement des toasts/tiroirs, badges sur les avatars, puces de liste | Raccourcis clavier (Ctrl+S) |
5. Avant de terminer
- Exécuter le linter sur tout code produit (il nécessite uniquement la bibliothèque standard Python) :
python <skill-dir>/scripts/rtl_check.py <fichier-ou-dossier>Corriger chaqueerror. Corriger leswarnings sauf s'ils sont intentionnels, et marquer les intentionnels avec un commentairertl-ok. - Rendre et regarder quand c'est possible, puis vérifier que les lettres sont connectées, le premier mot est à droite, la ponctuation se trouve à l'extrémité gauche et les nombres se lisent dans le bon ordre :
- HTML :
python -m playwright screenshot --full-page file://$PWD/index.html shot.png(ounpx playwright screenshot …). Si aucun navigateur n'est disponible,weasyprint index.html out.pdfdonne un rendu statique. - docx/pptx :
soffice --headless --convert-to pdf file.docx, puis pixelliser le PDF. - PDF → PNG :
python -c "import pymupdf; pymupdf.open('f.pdf')[0].get_pixmap(dpi=110).save('f.png')" - Images/graphiques : ouvrir le PNG que vous avez écrit.
- HTML :
- Si les scripts ne peuvent pas s'exécuter (pas de Python, pas de shell), parcourir cette liste de vérification manuellement :
- racine
dir="rtl"+lang="ar…"(ou l'équivalent du format) - pas de
left/rightdans l'espacement, le positionnement ou l'alignement - téléphones/e-mails/URLs/code isolés et LTR
- icônes directionnelles inversées, autres non touchées
- police arabe chargée, interlignage ≥ 1.6, pas d'espacement des lettres, ni italique ni majuscules
- texte image/PDF : le chemin de ligature correspond au moteur de rendu (règle 7)
-
،؛؟utilisés, un seul système de chiffres, MSA naturel (ou le dialecte demandé)
- racine
Scripts
scripts/rtl_check.py <chemin>: vérifie HTML/CSS/Tailwind/JSX/TSX/Vue/Svelte/React Native/Flutter pour les bugs RTL. Affichefichier:ligne, le problème et la correction exacte. Code de sortie 1 en cas d'erreurs. Stdlib uniquement.scripts/shape_text.py:prepare(text, cible)pour les moteurs qui ne ligaturent pas l'arabe. Il détecte le support natif de matplotlib/Pillow et renvoie le texte inchangé quand la ligature n'est pas nécessaire. Il utilisearabic-reshaper+python-bidi(installé via pip à la demande) ou se rabat sur un ligateur intégré basé sur la bibliothèque standard.python shape_text.py --checkindique ce dont cette machine a besoin.