mirror of
https://github.com/kevinveenbirkenbach/computer-playbook.git
synced 2026-11-08 11:46:35 +00:00
meta/languages.yml carried `libretranslate: true|false` per entry, which
answered two different questions with one field: which languages the
repository translates, and which engine renders them. The first is the
table's business; the second is not. The gateway offers every backend
that serves a pair, falls through when one refuses or mangles the
answer, drops an engine whose failures pile up, and settles a request
class on the engine that wins its comparisons - and `signature()` is
"{source}:{target}:{length bucket}:{markup|plain}", so that learning is
already per target language. A static column beside it is a second
opinion that goes stale the moment the router learns something.
So the field is gone, 184 lines, and the table now holds name, endonym
and direction. Every language it names carries a catalog in every
domain.
What one engine can do is declared with that engine instead:
services.libretranslate-engine.serves, 47 codes. Not a detour - both
readers run before any engine answers. The lane prefetches one model per
code, and the readiness probe is itself the thing that would have asked.
`translatable()` split along that seam. Catalog-scoped callers take
`domain_languages()`, engine-scoped ones take the new
`served_languages()`: the CI matrix, extraction and translation the
first, the model prefetch and the tuning sweep the second. Collapsing
the two is what this change is guarding against - `baked_languages()`
renders identically before and after, verified by diffing both outputs.
`translate()` also stops dying on a language whose catalog has not been
extracted yet. It reads a missing catalog as nothing pending rather than
raising, because 136 docs catalogs do not exist until the next
extraction and refusing those languages would quietly shrink the set the
repository promises to translate.
The oracle suite follows: tests/oracle/test_translation_score.py asks
utils/i18n/judge.py about every language instead of routing a laya
checkpoint per language. It cannot run yet - the tools lane carries no
LiteLLM - and its skip message says exactly that.
test_catalogs_complete_on_gpu now measures against the table rather than
one engine's coverage. It is live on a GPU host and will report the 136
missing catalogs as the gap they are, which is the point: narrowing it
to the engine would hide exactly the languages worth watching.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
88 lines
2.9 KiB
Python
88 lines
2.9 KiB
Python
import unittest
|
|
|
|
from utils import PROJECT_ROOT
|
|
from utils.i18n.languages import (
|
|
DOMAINS,
|
|
SOURCE_LANGUAGE,
|
|
domain_languages,
|
|
load_languages,
|
|
)
|
|
from utils.i18n.libretranslate import PIVOT_LANGUAGE, baked_languages, served_languages
|
|
|
|
FIELDS = {"name", "native", "direction"}
|
|
DIRECTIONS = {"ltr", "rtl"}
|
|
|
|
|
|
class TestDomainLanguages(unittest.TestCase):
|
|
def test_a_domain_the_file_does_not_name_is_refused(self) -> None:
|
|
with self.assertRaises(ValueError):
|
|
domain_languages({"de": {}}, "handbook")
|
|
|
|
def test_the_source_language_carries_no_catalog_of_its_own(self) -> None:
|
|
self.assertNotIn(
|
|
SOURCE_LANGUAGE, domain_languages({"de": {}, SOURCE_LANGUAGE: {}}, "core")
|
|
)
|
|
|
|
|
|
class TestTheLanguageTable(unittest.TestCase):
|
|
@classmethod
|
|
def setUpClass(cls) -> None:
|
|
cls.languages = load_languages(PROJECT_ROOT)
|
|
|
|
def test_every_entry_carries_the_three_identity_fields(self) -> None:
|
|
self.assertEqual(
|
|
sorted(
|
|
code for code, entry in self.languages.items() if set(entry) != FIELDS
|
|
),
|
|
[],
|
|
)
|
|
|
|
def test_no_entry_names_an_engine_or_a_scorer(self) -> None:
|
|
"""The gateway learns the engine per language and the oracle asks one
|
|
judge for all of them, so a route written here would be a second
|
|
opinion that goes stale as soon as either learns something."""
|
|
self.assertEqual(
|
|
sorted(
|
|
code
|
|
for code, entry in self.languages.items()
|
|
if {"engine", "oracle", "libretranslate"} & set(entry)
|
|
),
|
|
[],
|
|
)
|
|
|
|
def test_every_direction_is_one_of_the_two_writing_directions(self) -> None:
|
|
self.assertEqual(
|
|
sorted(
|
|
code
|
|
for code, entry in self.languages.items()
|
|
if entry["direction"] not in DIRECTIONS
|
|
),
|
|
[],
|
|
)
|
|
|
|
def test_every_language_but_the_source_carries_a_catalog(self) -> None:
|
|
expected = sorted(code for code in self.languages if code != SOURCE_LANGUAGE)
|
|
for domain in DOMAINS:
|
|
with self.subTest(domain=domain):
|
|
self.assertEqual(domain_languages(self.languages, domain), expected)
|
|
|
|
|
|
class TestTheEnginesOwnCoverage(unittest.TestCase):
|
|
@classmethod
|
|
def setUpClass(cls) -> None:
|
|
cls.languages = load_languages(PROJECT_ROOT)
|
|
cls.served = served_languages(PROJECT_ROOT)
|
|
|
|
def test_every_served_code_is_a_language_the_repository_names(self) -> None:
|
|
self.assertEqual(sorted(set(self.served) - set(self.languages)), [])
|
|
|
|
def test_the_lane_bakes_the_pivot_beside_every_served_model(self) -> None:
|
|
self.assertEqual(
|
|
baked_languages(PROJECT_ROOT),
|
|
sorted({PIVOT_LANGUAGE, *self.served}),
|
|
)
|
|
|
|
|
|
if __name__ == "__main__":
|
|
unittest.main()
|