Mirror qet_en.ts instead of qet_fr.ts now that English is the source

#1379 added misc/i18n/mirror_source_language.py and an INSTALL.md rule
to run it on lang/qet_fr.ts after update_translations, while French was
the source language. Since #1390 the code is English and qet_fr.ts is an
ordinary translation, so following the rule would copy English text into
empty French entries. The repository test still checked qet_fr.ts and
kept passing.

The rule, the script's description and the repository test now name
lang/qet_en.ts. The script refuses a file whose <TS> header names a
language different from its sourcelanguage (qet_fr.ts says fr_FR / en),
exits 2 and leaves it untouched; files without a sourcelanguage, like
the fixtures, are accepted as before. The 6 entries master added since
the conversion are mirrored, so qet_en.ts is complete again.

Tests: 19 in misc/i18n/test_mirror_source_language.py. The repository
test fails on master (6 entries to mirror); with the check_languages()
call removed, the two refusal tests fail and a run on qet_fr.ts goes
through.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Beat Hangartner
2026-10-09 10:42:00 +02:00
parent 8e7904d7b0
commit 7cff54dd19
4 changed files with 110 additions and 35 deletions
+40 -6
View File
@@ -10,7 +10,7 @@ byte for byte. Every message class the script distinguishes appears
once in the pair, so a change in behaviour shows up as a diff in a
known place.
The last test looks at the repository's own lang/qet_fr.ts and fails
The last test looks at the repository's own lang/qet_en.ts and fails
when it needs a mirror run: that is the maintenance rule from
INSTALL.md, kept honest.
"""
@@ -33,6 +33,7 @@ import mirror_source_language as m # noqa: E402
SCRIPT = HERE / "mirror_source_language.py"
BEFORE = HERE / "fixtures" / "mirror_before.ts"
AFTER = HERE / "fixtures" / "mirror_after.ts"
REPO_EN = HERE.parent.parent / "lang" / "qet_en.ts"
REPO_FR = HERE.parent.parent / "lang" / "qet_fr.ts"
@@ -153,6 +154,27 @@ class MirrorText(unittest.TestCase):
self.assertNotIn("unfinished", out)
ET.fromstring(out)
def test_translation_into_another_language_is_refused(self):
for header in ('<TS version="2.1" language="fr_FR" sourcelanguage="en">',
'<TS language="de" sourcelanguage="en_US">'):
text = (header + '<context><name>C</name><message>\n'
' <source>Open</source>\n'
' <translation></translation>\n'
' </message></context></TS>')
with self.assertRaises(m.LanguageError, msg=header):
m.mirror_text(text)
def test_source_language_file_is_accepted(self):
for header in ('<TS version="2.1" language="en_US" sourcelanguage="en">',
'<TS version="2.1" language="fr_FR">'): # no sourcelanguage
text = (header + '<context><name>C</name><message>\n'
' <source>Open</source>\n'
' <translation></translation>\n'
' </message></context></TS>')
out, stats = m.mirror_text(text)
self.assertEqual(stats.mirrored_messages, 1, header)
self.assertIn("<translation>Open</translation>", out)
def test_source_with_child_element_is_refused(self):
text = ('<TS><context><name>C</name><message>\n'
' <source>a<byte value="7"/>b</source>\n'
@@ -198,12 +220,24 @@ class CommandLine(unittest.TestCase):
self.assertIn("child element", r.stderr)
self.assertEqual(read(tmp), bad)
@unittest.skipUnless(REPO_FR.is_file(), "lang/qet_fr.ts not found next to the tool")
def test_repository_french_file_is_mirrored(self):
"""The maintenance rule: run the mirror after update_translations."""
r = self.run_script("--check", str(REPO_FR))
@unittest.skipUnless(REPO_EN.is_file(), "lang/qet_en.ts not found next to the tool")
def test_repository_source_language_file_is_mirrored(self):
"""The maintenance rule: run the mirror after update_translations.
Until 2026-10-09 this checked lang/qet_fr.ts, which #1390 had turned
into an ordinary translation; it passed while the rule was wrong."""
r = self.run_script("--check", str(REPO_EN))
self.assertEqual(r.returncode, 0,
f"lang/qet_fr.ts needs a mirror run:\n{r.stdout}")
f"lang/qet_en.ts needs a mirror run:\n{r.stdout}")
@unittest.skipUnless(REPO_FR.is_file(), "lang/qet_fr.ts not found next to the tool")
def test_repository_translation_file_is_refused(self):
"""A run on the French translation would copy English into it."""
before = REPO_FR.read_bytes()
r = self.run_script(str(REPO_FR))
self.assertEqual(r.returncode, 2, r.stdout)
self.assertIn("only the source language", r.stderr)
self.assertEqual(REPO_FR.read_bytes(), before)
if __name__ == "__main__":