Files
computer-playbook/tests/unit/python/utils/i18n/test_repairs.py
T
kevinveenbirkenbachandClaude Opus 5 0c541cbb2f fix(i18n): stop resegment from splitting a name an agglutinative language suffixed
2aa7325eca put role names and product titles into the spans mask() produces, and
unmask hands those same spans to resegment. That was safe for every span the
protection had before, because each ends in a delimiter, so a letter right
behind it can only be the text a lost boundary was taken from. A bare name ends
in a word character, and Bengali writes `Baserowo` where the source says
`Baserow`, so the substring search found the name inside the longer word and put
the punctuation in the middle of it:

  resegment('Baserowo-r shathe', ('Baserow',), 'Adapter to Baserow: ...')
  -> 'Baserow: o-r shathe'

Names are skipped. The repair still fires for the spans it was written for, and
the 85 entries the boundary lint reported across et, fi, eu, cs, ja and bn drop
to none.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-24 23:10:47 +02:00

150 lines
4.8 KiB
Python

"""Unit tests for the repairs a restored translation goes through.
Every case is a shape measured in the catalogs: a bracket that moved in front of
a protected span and took the full stop with it, an opening word the translator
lower-cased, and a run of spaces it opened around a span.
"""
from __future__ import annotations
import unittest
from utils.i18n.placeholders import (
collapse,
mask,
recapitalise,
resegment,
terminate,
unmask,
)
from utils.i18n.translate import truncated
def _round_trip(source: str, translated: str) -> str | None:
"""Send ``translated`` back through the unmasking a real answer goes through.
Args:
source: the source message.
translated: what the translator returned for the masked request.
"""
return unmask(translated, mask(source), source)
class TestCollapse(unittest.TestCase):
def test_a_run_the_source_lacks_is_closed(self) -> None:
self.assertEqual(
collapse("Works with the helper", "Works with it"), "Works with the helper"
)
def test_a_run_the_source_carries_is_left_alone(self) -> None:
source = "column aligned"
self.assertEqual(
collapse("Spalte ausgerichtet", source), "Spalte ausgerichtet"
)
def test_a_tab_in_the_source_disables_the_repair(self) -> None:
self.assertEqual(collapse("a b", "a\tb"), "a b")
class TestTerminate(unittest.TestCase):
def test_a_lost_full_stop_comes_back(self) -> None:
source = "Return whether the paths match (as os.path.samefile() does)."
self.assertEqual(
terminate("Ob die Pfade gleich sind (wie) os.path.samefile()", source),
"Ob die Pfade gleich sind (wie) os.path.samefile().",
)
def test_a_question_mark_comes_back(self) -> None:
self.assertEqual(terminate("Ist es bereit", "Is it ready?"), "Ist es bereit?")
def test_a_translation_that_kept_one_is_untouched(self) -> None:
self.assertEqual(terminate("Fertig!", "Done."), "Fertig!")
def test_a_source_without_one_adds_nothing(self) -> None:
self.assertEqual(terminate("Backup", "Backup"), "Backup")
class TestRecapitalise(unittest.TestCase):
def test_a_lower_cased_opening_is_restored(self) -> None:
self.assertEqual(
recapitalise("alle `alpha` Kriterien.", "All `alpha` criteria."),
"Alle `alpha` Kriterien.",
)
def test_a_lowercase_source_keeps_its_case(self) -> None:
self.assertEqual(
recapitalise("alle Kriterien", "all criteria"), "alle Kriterien"
)
def test_an_already_capital_opening_is_untouched(self) -> None:
self.assertEqual(
recapitalise("Alle Kriterien", "All criteria"), "Alle Kriterien"
)
def test_an_opening_protected_span_is_untouched(self) -> None:
self.assertEqual(
recapitalise("`alpha` zuerst", "`alpha` first"), "`alpha` zuerst"
)
class TestUnmaskAppliesTheRepairs(unittest.TestCase):
def test_a_lower_cased_opening_is_repaired_on_the_way_back(self) -> None:
restored = _round_trip(
"All `alpha` criteria.", 'alle <x id="0"></x> Kriterien.'
)
self.assertEqual(restored, "Alle `alpha` Kriterien.")
def test_a_missing_full_stop_is_repaired_on_the_way_back(self) -> None:
restored = _round_trip("All `alpha` criteria.", 'Alle <x id="0"></x> Kriterien')
self.assertEqual(restored, "Alle `alpha` Kriterien.")
def test_a_space_run_is_repaired_on_the_way_back(self) -> None:
restored = _round_trip(
"All `alpha` criteria.", 'Alle <x id="0"></x> Kriterien.'
)
self.assertEqual(restored, "Alle `alpha` Kriterien.")
class TestResegmentLeavesNamesAlone(unittest.TestCase):
def test_a_suffixed_name_keeps_its_word(self) -> None:
source = "Adapter to Baserow: the endpoint key"
self.assertEqual(
resegment("Baserowo-r shathe", mask(source).spans, source),
"Baserowo-r shathe",
)
def test_a_swallowed_boundary_behind_a_delimiter_is_still_put_back(self) -> None:
source = "See `compose.yml`. The next sentence."
self.assertEqual(
resegment(
"Siehe `compose.yml`Der naechste Satz.", mask(source).spans, source
),
"Siehe `compose.yml`. Der naechste Satz.",
)
class TestTruncated(unittest.TestCase):
def test_a_short_entry_may_shrink(self) -> None:
self.assertFalse(truncated("Situation", "Lage"))
def test_a_long_passage_that_halved_is_reported(self) -> None:
source = "A" * 200
self.assertTrue(truncated(source, "B" * 80))
def test_a_long_passage_that_kept_its_body_is_not(self) -> None:
source = "A" * 200
self.assertFalse(truncated(source, "B" * 180))
if __name__ == "__main__":
unittest.main()