Files
office_translator/tests/test_excel_chart_text_applied.py
sepehr 992f13d53c
All checks were successful
Deploy to Production / Build and Deploy (push) Successful in 2m35s
fix(translate): apply Excel chart text setters (were silently dropped)
Chart <a:t> elements (title, axis labels, series names) were collected and
sent to the LLM, but the apply loop never invoked their setters. Reason:
the apply loop iterated only text_elements[:sheet_name_offset], which
excluded the chart-text positions (sheet names were inserted in the
middle, pushing chart texts past sheet_name_offset). The LLM correctly
returned French for "Revenue by Product" / "Quantity Trend" / "Order #"
but the result was thrown away.

Fix: include the chart-text slice [sheet_name_offset + N .. total_texts]
in the apply loop. Setters for sheet names are still None, so they are
naturally skipped.

Add test_excel_chart_text_applied.py (2 end-to-end tests) using a fixed
provider that pre-translates every known chart text; the test asserts
all chart <a:t> values in the output .xlsx come from the FR table, not
the original English source.
2026-07-15 22:21:53 +02:00

112 lines
3.8 KiB
Python

"""Regression test for the bug where chart <a:t> text was never written back
to the .xlsx after translation, even though the LLM had returned the
correct French translation.
Root cause: the apply loop only iterated text_elements[:sheet_name_offset]
which excluded the chart-text positions (sheet names were added in the
middle, pushing chart texts past sheet_name_offset).
"""
import sys
import shutil
from pathlib import Path
sys.path.insert(0, str(Path(__file__).resolve().parents[1]))
from lxml import etree
from openpyxl import load_workbook
import zipfile
from translators.excel_translator import ExcelTranslator
NS_A = "http://schemas.openxmlformats.org/drawingml/2006/main"
NS_C = "http://schemas.openxmlformats.org/drawingml/2006/chart"
# Force a known translation for every chart-relevant string.
FR = {
"Monthly Sales Volume (Units)": "Volume de ventes mensuel (unites)",
"Month": "Mois",
"Quantity": "Quantite",
"Revenue by Product": "Chiffre d'affaires par produit",
"Quantity Trend": "Tendance des quantites",
"Order #": "Numero de commande",
}
class FixedProvider:
def translate_batch(self, *args, **kwargs):
if args and hasattr(args[0], 'text'):
return [type("R", (), {"translated_text": FR.get(req.text, req.text)})() for req in args[0]]
texts = args[0] if args else kwargs.get('texts', [])
return [FR.get(t, t) for t in texts]
def _read_chart_a_t(xlsx_path: Path):
out = {}
with zipfile.ZipFile(xlsx_path, 'r') as zf:
for name in zf.namelist():
if name.startswith('xl/charts/') and name.endswith('.xml'):
xml = etree.fromstring(zf.read(name))
out[name] = [t.text for t in xml.iter(f'{{{NS_A}}}t') if t.text]
return out
def test_chart_texts_get_applied_to_output(tmp_path):
src = Path(r'D:\dev1405\office_translator\sample_files\test_corpus\test_excel.xlsx')
dst = tmp_path / "out.xlsx"
shutil.copy(src, dst)
tr = ExcelTranslator()
tr.set_provider(FixedProvider())
tr.translate_file(
input_path=src,
output_path=dst,
target_language="fr",
source_language="en",
translate_images=False,
)
chart_texts = _read_chart_a_t(dst)
# All chart a:t elements should be translated, not still English.
for cf, texts in chart_texts.items():
for t in texts:
assert t in FR.values(), (
f"{cf} still has untranslated text: {t!r}. "
f"Expected one of: {list(FR.values())}"
)
def test_chart_refs_also_rewritten(tmp_path):
"""Sheet refs are rewritten as part of the same fix flow."""
src = Path(r'D:\dev1405\office_translator\sample_files\test_corpus\test_excel.xlsx')
dst = tmp_path / "out2.xlsx"
shutil.copy(src, dst)
tr = ExcelTranslator()
tr.set_provider(FixedProvider())
tr.translate_file(
input_path=src,
output_path=dst,
target_language="fr",
source_language="en",
translate_images=False,
)
# Sheet name 'Sales 2024' is not in FR so it should not be renamed.
# The chart refs should still point at 'Sales 2024' (no rename happened).
with zipfile.ZipFile(dst, 'r') as zf:
for name in zf.namelist():
if name.startswith('xl/charts/') and name.endswith('.xml'):
xml = etree.fromstring(zf.read(name))
refs = [f.text for f in xml.iter(f'{{{NS_C}}}f') if f.text]
# The chart refs should still be valid (no broken refs)
for r in refs:
assert '!' in r, f"Invalid chart ref in {name}: {r!r}"
if __name__ == "__main__":
import tempfile
with tempfile.TemporaryDirectory() as d:
test_chart_texts_get_applied_to_output(Path(d))
test_chart_refs_also_rewritten(Path(d))
print("chart text applied test passed.")