feat(i18n): deploy libretranslate into the i18n runner before translating

server() now resolves a translation endpoint in three steps: use the running
service, rebuild when the host has a GPU but no accelerated deploy left its
stamp, otherwise deploy. A plain run therefore costs nothing, and the rebuild
fires once, on the move from a CPU-built container to an accelerated one.

deploy() brings the runner up, waits for State.Running and deploys the role
inside it. The exec steps address `docker compose exec i18n` directly:
cli.administration.deploy.development exec hardcodes the `infinito` service
(compose.py:261), so every deploy through it silently ran in the main
container, where mailu already holds port 25 and postfix cannot start.
check=True stops a failing step instead of carrying on against the wrong
target.

The deploy router writes its pid to build/deploy.pid, which survives the exec
into the subscripts, and deploying() refuses a translation while that process
lives. The running deploy is left untouched.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
kevinveenbirkenbachandClaude Opus 5 committed 2026-09-24 01:53:19 +02:00
1 parent bb1dbaa022
commit a0a24e2c0e
5 files changed
+286 -7

No files matched your search

@@ -44,8 +44,7 @@ class TestTranslate(unittest.TestCase):
)
with (
mock.patch.object(cli, "PROJECT_ROOT", self.root),
mock.patch.object(cli, "pinned_image", return_value="lt:1"),
mock.patch.object(cli, "container", started),
mock.patch.object(cli, "server", started),
mock.patch.object(cli, "LibreTranslate", client),
):
return cli.translate("core", []), started