Add the DeepL and Google Translate backends #192

Closed
opened 2026-08-24 21:28:32 +01:00 by naps62-yolo · 1 comment
Owner

Implement the DeepL and Google Translate backends, each behind its own cargo
feature, against the trait from #190.

They share a shape — a dedicated translation API, per-character billing, no
context carried between requests — which is why they are one issue rather than
two. What differs is auth and response format.

  • DeepL has a real PT-PT target distinct from PT-BR; use it, and do not
    accept a request for pt-PT that would silently return Brazilian text.
  • Google Translate's pt target is Brazilian in practice. The backend must say
    that it cannot express pt-PT rather than pretending, per #190's contract.
  • Both report per-character usage. Surface it so #197 can budget against the
    real number rather than an estimate.

Keys come from config or environment per §10. Fixture responses in tests.

Depends on: #190

Implement the DeepL and Google Translate backends, each behind its own cargo feature, against the trait from #190. They share a shape — a dedicated translation API, per-character billing, no context carried between requests — which is why they are one issue rather than two. What differs is auth and response format. - DeepL has a real `PT-PT` target distinct from `PT-BR`; use it, and do not accept a request for pt-PT that would silently return Brazilian text. - Google Translate's `pt` target is Brazilian in practice. The backend must say that it cannot express pt-PT rather than pretending, per #190's contract. - Both report per-character usage. Surface it so #197 can budget against the real number rather than an estimate. Keys come from config or environment per §10. Fixture responses in tests. Depends on: #190
naps62-yolo added this to the Subtitles milestone 2026-08-24 21:28:32 +01:00
naps62-yolo added the difficulty/easyarea/subsphase/9-subtitlestype/feature labels 2026-08-24 21:28:32 +01:00
naps62-yolo added a new dependency 2026-08-24 21:29:27 +01:00
Author
Owner

Implemented the DeepL and Google Translate translation backends in arr-subs, each behind its existing cargo feature (translate-deepl, translate-google), implementing #190's Backend trait. DeepL keeps PT-PT and PT-BR apart as first-class targets, auto-selects the free-tier host from a :fx key, and maps DeepL's 403/429/456 to Unauthorized/RateLimited; bare pt is accepted as a source but refused as a target. Google Translate refuses pt-PT in supports() (its pt target is Brazilian) rather than pretending, and decodes the HTML entities its v2 API emits even in text mode (", ', numeric forms). Both preserve cue numbering by array position (one output per input text), surface per-character usage via a new provided Backend::characters_billed() method (default zero, so additive for #191/#193), and map connection failures to Transport. All HTTP paths are tested against wiremock fixtures — no live service. Keys stay in bootstrap config/env per §10; arr-daemon already plumbs ARR_TRANSLATE_DEEPL_API_KEY/ARR_TRANSLATE_GOOGLE_API_KEY.

Branch: subtitles/192-deepl-google (3 commits, pushed)

just ci: passed through the gate (exit 0), 556 tests green. Note the gate runs default features, so it does not compile the backends; I ran cargo test/clippy -p arr-subs --features translate-deepl,translate-google locally with all green, both with and without features.

Findings

  • The CI gate never compiles any translation backend (default feature set is empty), so backend code and tests are invisible to CI until something enables the features. Worth an issue: run at least one job with --all-features, or enable the shipped backends in the release build's features.
  • Backend::characters_billed() is cumulative since construction; #197 may prefer a returned-per-call number instead of polling a counter on a dyn Backend. The trait change is small if that turns out better.
  • lib.rs had two identical #[cfg(test)] use wiremock as _; blocks (lines ~24 and ~46); harmless duplicate, left alone.
Implemented the DeepL and Google Translate translation backends in `arr-subs`, each behind its existing cargo feature (`translate-deepl`, `translate-google`), implementing #190's `Backend` trait. DeepL keeps `PT-PT` and `PT-BR` apart as first-class targets, auto-selects the free-tier host from a `:fx` key, and maps DeepL's 403/429/456 to `Unauthorized`/`RateLimited`; bare `pt` is accepted as a source but refused as a target. Google Translate refuses pt-PT in `supports()` (its `pt` target is Brazilian) rather than pretending, and decodes the HTML entities its v2 API emits even in text mode (`"`, `'`, numeric forms). Both preserve cue numbering by array position (one output per input text), surface per-character usage via a new provided `Backend::characters_billed()` method (default zero, so additive for #191/#193), and map connection failures to `Transport`. All HTTP paths are tested against wiremock fixtures — no live service. Keys stay in bootstrap config/env per §10; `arr-daemon` already plumbs `ARR_TRANSLATE_DEEPL_API_KEY`/`ARR_TRANSLATE_GOOGLE_API_KEY`. Branch: `subtitles/192-deepl-google` (3 commits, pushed) `just ci`: **passed** through the gate (exit 0), 556 tests green. Note the gate runs default features, so it does not compile the backends; I ran `cargo test/clippy -p arr-subs --features translate-deepl,translate-google` locally with all green, both with and without features. ## Findings - The CI gate never compiles any translation backend (default feature set is empty), so backend code and tests are invisible to CI until something enables the features. Worth an issue: run at least one job with `--all-features`, or enable the shipped backends in the release build's features. - `Backend::characters_billed()` is cumulative since construction; #197 may prefer a returned-per-call number instead of polling a counter on a `dyn Backend`. The trait change is small if that turns out better. - lib.rs had two identical `#[cfg(test)] use wiremock as _;` blocks (lines ~24 and ~46); harmless duplicate, left alone.
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Reference: yolo/arr#192