fix(rtl): les textes centrs en persan s'affichaient du mauvais cote
- Word: sous w:bidi, w:jc est logique (left=dbut=droite visuelle, right=fin=gauche visuelle) ; forcer jc=right alignait donc les paragraphes a gauche et crasait le centrage hrit du style. Dsormais le RTL pose w:bidi et w:rtl sans jamais toucher w:jc, comme le fait Word lui-mme pour un document RTL. - PowerPoint: algn n'est plus crit quand le paragraphe n'en dfinit pas, afin de respecter l'alignement hrit du masque (titres centrs) ; algn=l explicite reste converti en r (algn est visuel en DrawingML). - tests: centrage par style Word prserv, aucun w:jic crit, algn absent non cras côté PowerPoint
This commit is contained in:
@@ -22,6 +22,7 @@ from pathlib import Path
|
||||
|
||||
import pytest
|
||||
from docx import Document
|
||||
from docx.enum.style import WD_STYLE_TYPE
|
||||
from docx.enum.text import WD_ALIGN_PARAGRAPH
|
||||
from lxml import etree
|
||||
from openpyxl import Workbook, load_workbook
|
||||
@@ -447,6 +448,46 @@ class TestWordRtlLayout:
|
||||
)
|
||||
assert marker in part_text, part_name
|
||||
|
||||
def test_fa_target_never_writes_alignment(self, tmp_path):
|
||||
"""Reported bug: centered Persian text rendered on the wrong side.
|
||||
|
||||
Under w:bidi, Word interprets w:jc logically: "right" means the
|
||||
END of the line — the visual LEFT for RTL. Writing jc="right"
|
||||
pushes unaligned paragraphs to the left and overrides style-level
|
||||
centering. RTL must add w:bidi (+ run w:rtl) and never touch
|
||||
w:jc: unaligned paragraphs start at the right edge, explicit
|
||||
"left" resolves to the right edge, and centering stays centering.
|
||||
"""
|
||||
provider = MockTranslationProvider(
|
||||
{"Plain body": "FA1", "Styled centered title": "FA2"}
|
||||
)
|
||||
translator = WordTranslator(provider=provider)
|
||||
|
||||
doc = Document()
|
||||
doc.add_paragraph("Plain body") # no alignment anywhere
|
||||
style = doc.styles.add_style("CenteredCustom", WD_STYLE_TYPE.PARAGRAPH)
|
||||
style.paragraph_format.alignment = WD_ALIGN_PARAGRAPH.CENTER
|
||||
doc.add_paragraph("Styled centered title", style=style) # centered via style
|
||||
|
||||
input_file = tmp_path / "input.docx"
|
||||
doc.save(input_file)
|
||||
output_file = tmp_path / "output.docx"
|
||||
translator.translate_file(input_file, output_file, "fa")
|
||||
|
||||
doc_out = Document(output_file)
|
||||
for para in doc_out.paragraphs:
|
||||
pPr = para._p.find(f"{{{W_NS}}}pPr")
|
||||
assert pPr is not None
|
||||
assert pPr.find(f"{{{W_NS}}}bidi") is not None
|
||||
assert pPr.find(f"{{{W_NS}}}jc") is None, "RTL must never write w:jc"
|
||||
|
||||
# The style-level centering still resolves to centered
|
||||
assert (
|
||||
doc_out.paragraphs[1].style.paragraph_format.alignment
|
||||
== WD_ALIGN_PARAGRAPH.CENTER
|
||||
)
|
||||
assert "FA2" in doc_out.paragraphs[1].text
|
||||
|
||||
def test_fr_target_no_rtl_attributes(self, tmp_path):
|
||||
"""A non-RTL target produces no bidi/bidiVisual/rtl markup."""
|
||||
provider = MockTranslationProvider({"Body text": "FR_Body"})
|
||||
@@ -552,7 +593,14 @@ class TestPptxRtlLayout:
|
||||
assert pPr.get("rtl") == "1"
|
||||
assert pPr.get("algn") == "just", "justified alignment must be preserved"
|
||||
|
||||
def test_alignment_absent_becomes_right(self, tmp_path):
|
||||
def test_alignment_absent_inherits_from_layout(self, tmp_path):
|
||||
"""Reported bug: centered Persian text rendered on the wrong side.
|
||||
|
||||
When algn is absent the paragraph inherits its alignment from
|
||||
the layout/master (often centered titles); writing algn="r"
|
||||
overrides that inheritance. rtl="1" alone already renders the
|
||||
paragraph from its start edge (right), so algn stays untouched.
|
||||
"""
|
||||
provider = MockTranslationProvider({"Plain text": "AR_Plain"})
|
||||
translator = PowerPointTranslator(provider=provider)
|
||||
input_file = self._build_single_text_pptx(tmp_path, "Plain text")
|
||||
@@ -564,7 +612,7 @@ class TestPptxRtlLayout:
|
||||
pPr = para._p.find(f"{{{A_NS}}}pPr")
|
||||
assert pPr is not None
|
||||
assert pPr.get("rtl") == "1"
|
||||
assert pPr.get("algn") == "r"
|
||||
assert pPr.get("algn") is None, "inherited alignment must not be overridden"
|
||||
|
||||
def test_alignment_left_becomes_right(self, tmp_path):
|
||||
provider = MockTranslationProvider({"Left text": "AR_Left"})
|
||||
|
||||
Reference in New Issue
Block a user