- source unique RTL_LANGUAGES/is_rtl dans core/languages.py (fin des 3 copies) - Word: bidi partout (corps, tableaux bidiVisual, notes/fin/commentaires, zones de texte, 6 zones d'en-tetes/pieds), insertion OOXML ordonnee, polices cs elargies aux 11 langues - PowerPoint: alignements explicites preserves, notes du presentateur, indice de police <a:cs> insert a sa place - Excel: feuilles affichees de droite a gauche, feuilles graphiques ignorees - PDF: faconnage bidi (arabic-reshaper + python-bidi), polices par ecriture (arabe/hebreu), TTF enregistree pour le PDF recompose - 46 tests nouveaux (tests/test_translators/test_rtl_layout.py), 253 au total
11 KiB
title, type, created, status, review_loop_iteration, baseline_commit, context
| title | type | created | status | review_loop_iteration | baseline_commit | context |
|---|---|---|---|---|---|---|
| Rendu fidèle des traductions pour les langues RTL (persan, arabe, hébreu…) | feature | 2026-09-01 | done | 0 | fddd7b7428 |
Intent
Problem: Un document traduit vers une langue de droite à gauche sort dégradé : Excel ignore totalement le sens, PowerPoint force l'alignement à droite même sur les titres centrés et oublie les notes du présentateur, les tableaux Word ne sont pas inversés (ni notes de bas de page, ni zones de texte), et le PDF n'applique ni le façonnage des lettres arabes ni de police adaptée (lettres déconnectées, ordre inversé, carrés). Pour un lecteur persanophone ou arabophone, le résultat est parfois illisible.
Approach: Source de vérité unique pour le RTL dans core/languages.py, puis corrections ciblées dans les 4 traducteurs : direction et alignement corrects sans écraser les alignements explicites, inversion des tableaux, couverture des zones oubliées (notes, zones de texte), et pour le PDF façonnage bidi (arabic-reshaper + python-bidi) avec police couvrant l'écriture arabe.
Boundaries & Constraints
Always: Comportement inchangé pour toute cible non-RTL ; alignements explicites (centré, justifié) jamais écrasés ; aucun texte re-traduit ni altéré (seuls direction/alignement/indices de police sont ajoutés) ; RTL_LANGUAGES n'existe plus qu'une fois ; si arabic-reshaper/python-bidi manquent ou échouent, la traduction réussit quand même (texte tel quel + log d'avertissement).
Ask First: Ajouter une dépendance autre que arabic-reshaper et python-bidi ; modifier le Dockerfile (le paquet fonts-noto de Debian devrait déjà fournir Noto Naskh Arabic — vérifier dans l'image avant tout changement).
Never: Pas de refonte de la collecte des runs (fusion des runs PowerPoint / notes Word = chantier différé) ; pas de retentative automatique sur les contrôles qualité (différé) ; pas de modification des providers, de l'interface ni du frontend ; pas d'inversion des images ou graphiques vectoriels.
I/O & Edge-Case Matrix
| Scenario | Input / State | Expected Output / Behavior | Error Handling |
|---|---|---|---|
| Word cible RTL | docx : corps, tableau, note de bas de page, zone de texte | w:bidi sur tous les paragraphes, w:bidiVisual sur les tableaux, w:sectPr/w:bidi |
N/A |
| PPTX titre centré, cible ar | algn="ctr" existant |
rtl="1" posé, algn reste "ctr" ; si algn absent ou "l" → algn="r" |
N/A |
| PPTX avec notes | diapositive avec notes du présentateur | notes traduites ET passées en RTL | N/A |
| Excel cible he | xlsx multi-feuilles | sheet_view.rightToLeft = True sur chaque feuille |
N/A |
| PDF mode mise en page, cible fa/ar | pdf avec blocs de texte | texte façonné avant insertion, police couvrant l'arabe, alignement à droite | Police introuvable → police actuelle + warning ; bibliothèque absente → texte non façonné + warning ; jamais d'échec |
| PDF scanné / mode texte, cible RTL | OCR ou mode text_only | reportlab : police TTF enregistrée, wordWrap="RTL" sur le style |
Pas de TTF → Helvetica + warning (dégradation documentée) |
| Cible non-RTL (fr, zh…) | tous formats | Aucun attribut RTL ajouté, sortie identique à aujourd'hui | N/A |
| Code régional | fa-IR, ar-EG |
is_rtl() normalise le préfixe → RTL appliqué |
N/A |
Code Map
core/languages.py--LANGUAGE_NAMESl.12-123,language_name()l.126-137 : y ajouterRTL_LANGUAGES(frozenset) etis_rtl(code).translators/word_translator.py-- copieRTL_LANGUAGESl.30-32 (supprimer) ;CS_FONTSl.45-50 (ar/he/fa/ur seulement) ;_set_paragraph_rtll.126-153 (modèle :w:jctouché seulement sans alignement explicite) ;_apply_rtl_to_documentl.156-182 (corps + tableaux + en-têtes/pieds ; manquew:bidiVisual, zones de texte, notes) ; déclencheur l.422-424 ; notes/comments réécrits en ZIP post-save l.811-995 (parts sans RTL).translators/pptx_translator.py-- copie l.28-30 (supprimer) ;_set_pptx_paragraph_rtll.57-71 (algn="r"inconditionnel — bug) ;_apply_rtl_to_presentationl.74-78 (pas dehas_notes_slide) ;_apply_ea_font_hintsl.114-158 (modèle exact pour<a:cs>) ; notes collectées l.313-319 ; déclencheur l.399-401.translators/excel_translator.py--translate_filel.141-175 ; aucun support RTL (0 occurrence) ; sauvegarde en fin de méthode.translators/pdf_translator.py-- copie l.63-64 (supprimer) ;_FONT_SEARCH_PATHSl.115-134 (aucune police arabe) ;_get_font_pathl.187-196 (première trouvée, insensible au script) ; alignement RTL l.903 ;insert_textboxl.1017-1049 (pas de façonnage) ;_generate_clean_pdfl.1434-1516 (reportlab, aucune police enregistrée).requirements.txt+pyproject.toml(dependencies l.7+) -- dépendances dupliquées : mettre les deux à jour.docker/backend/Dockerfilel.30-40 --fonts-notoinstallé (vérifier le chemin de Noto Naskh Arabic dans l'image avant tout ajout).tests/test_translators/-- modèles :test_word_translator.py,test_pptx_translator.py,test_excel_translator.py,test_b3_pdf_fixes.py.services/quality/script_detector.py-- lecture seule (distingue déjà arabe/persan — réutilisable plus tard, hors périmètre).
Tasks & Acceptance
Execution:
core/languages.py-- AjouterRTL_LANGUAGES({ar, he, fa, ur, ku, ps, ug, sd, yi, dv, ckb}) etis_rtl(code) -> bool(casse et préfixe régional ignorés) -- source unique, fin des 3 copies.translators/word_translator.py-- Importer depuiscore.languages;_apply_rtl_to_document:w:bidiVisualsur chaquew:tbldu corps et des en-têtes/pieds (XPath.//w:tbl, couvre l'imbriqué), bidi/rtl sur les paragraphes desw:txbxContent; réécriture ZIP (l.811-995) :w:bidisur lesw:pPrdefootnotes.xml/endnotes.xml/comments.xmlquand cible RTL ;CS_FONTSélargi à ps, ku, sd, ug, yi, dv, ckb (Arial).translators/pptx_translator.py-- Importer ;algn="r"seulement sialgnabsent ou"l";_apply_rtl_to_presentationtraite aussinotes_text_framequandhas_notes_slide; ajouter_apply_cs_font_hints(modèle_apply_ea_font_hints) posant<a:cs typeface="Arial">pour les cibles RTL.translators/excel_translator.py-- Importeris_rtl; avant sauvegarde :ws.sheet_view.rightToLeft = Truepar feuille quand cible RTL.translators/pdf_translator.py-- Importer ; chemins Noto Naskh Arabic / Noto Sans Arabic (Linux) +C:/Windows/Fonts/arial.ttf;_get_font_pathprend la langue et choisit une police couvrant l'arabe pour les cibles RTL ;_shape_rtl(text)(import protégé, fallback texte tel quel + warning) appliquée aux blocs du mode mise en page et à_generate_clean_pdf; dans ce dernier :pdfmetrics.registerFontde la TTF si présente +wordWrap="RTL"+fontName.requirements.txt+pyproject.toml-- Ajouterarabic-reshaperetpython-bidi(versions pinnées comme le reste).tests/test_translators/test_rtl_layout.py-- Couvrir la matrice : docx (bidi corps/note, bidiVisual), pptx (algn conservé/posé, notes,<a:cs>), xlsx (rightToLeft), pdf (façonnage, police, fallback sans bibliothèque),is_rtl("fa-IR")/is_rtl("fr").
Acceptance Criteria:
- Given un docx avec tableau et note de bas de page, when traduction vers
fa, thenw:bidisur corps/note/zone de texte etw:bidiVisualsur le tableau. - Given un pptx avec un titre
algn="ctr", when traduction versar, then le titre gardealgn="ctr"et reçoitrtl="1". - Given un xlsx de 3 feuilles, when traduction vers
he, then les 3sheet_view.rightToLeftsont vrais. - Given un pdf textuel traduit vers
fa, when mode mise en page, then texte façonné inséré et police arabe sélectionnée si présente. - Given une traduction vers
fr, then aucun attribut RTL ajouté (sortie inchangée).
Spec Change Log
Verification
Commands:
python -m pytest tests/test_translators/test_rtl_layout.py -v-- expected: tous les tests passent.python -m pytest tests/test_translators/ tests/test_language_validation.py -q-- expected: aucune régression.python -c "import arabic_reshaper, bidi.algorithm; print('ok')"-- expected: ok.
Suggested Review Order
Source de vérité des langues
-
Liste unique partagée par les 4 traducteurs, fin des 3 copies locales
languages.py:142 -
Normalisation casse/préfixe régional (fa-IR, AR → RTL ; fr, None → non)
languages.py:147
Word — direction et ordre OOXML
-
Insertion positionnée selon le schéma (bidi/jc/rtl/bidiVisual jamais en fin)
word_translator.py:187 -
Paragraphe RTL : bidi + miroir d'alignement sans toucher centré/justifié
word_translator.py:202 -
Tableaux inversés visuellement (w:bidiVisual)
word_translator.py:236 -
Notes/commentaires : bidi + rtl sur les runs + tableaux, pendant la réécriture ZIP
word_translator.py:254 -
Les 6 zones d'en-têtes/pieds (défaut, première page, pages paires) couvertes
word_translator.py:288
PowerPoint — alignements et polices
-
rtl=1 posé, algn forcé à droite seulement si absent ou « l »
pptx_translator.py:71 -
Notes du présentateur incluses dans le passage RTL
pptx_translator.py:91 -
Indice de police <a:ea>/<a:cs> inséré à sa place, rPr en tête du run, notes incluses
pptx_translator.py:136
Excel — sens des feuilles
- rightToLeft par feuille, protégé (feuilles graphiques sans sheet_view ignorées)
excel_translator.py:369
PDF — façonnage et polices
-
Façonnage bidi (lettres liées, bon ordre), repli sans échec si bibliothèques absentes
pdf_translator.py:69 -
Police enregistrée une seule fois par chemin, nom unique par processus
pdf_translator.py:106 -
Groupe d'écriture (arabe / hébreu / générique) avant le choix de police
pdf_translator.py:185 -
Sélection de police sensible à l'écriture cible, cache par groupe
pdf_translator.py:309 -
PDF recomposé : TTF enregistrée, wordWrap RTL, texte façonné
pdf_translator.py:1597
Périphérie
-
46 tests couvrant la matrice (docx/pptx/xlsx/pdf + endnotes/comments/chartsheet)
test_rtl_layout.py:1 -
Dépendances façonnage (requirements.txt + pyproject.toml + uv.lock alignés)
requirements.txt:11