Files
UmbraAudio/samples/translations
B.D. Murphy 2b294d7fa4 Per-utterance language flag + a working language selector (spec 31)
The review UI's language dropdown did nothing: every selection kept
rendering the English text. Two independent causes, both fixed.

1. The translations were never being read. The pipeline's
   `utterance_translations` table holds one row in Deal Hunter, and that
   row stores the *English* text under a `zh-Hans` code. The real
   translations live in the on-disk sample files under
   `samples/translations/`. `umbraaudio/translations.py` now resolves both
   sources and merges them by (chapter_id, utterance_index): the table wins
   where it holds a real translation, the sample files fill the gaps. A
   candidate whose text is identical to the source is a placeholder, not a
   translation, so it is ignored - otherwise the page would show English
   under a Chinese heading and claim it was translated.

2. The query that read them was broken. `language_routes.py` selected
   `u.index` and `u.speaker`; the columns are `utterance_index` and
   `speaker_name`, so every read raised `sqlite3.OperationalError: near
   "index": syntax error` and `/language-mockup` returned 500. It also
   opened `<project>/project.db` - a 0-byte decoy - instead of
   `<project>/.umbra/project.db`, the file that actually holds the data.

Also in this commit:

* The chapter review page honours `?lang=`, remembers the choice in a
  cookie (set by a middleware, so it survives on every page), and shows the
  selected language's *name* in the "has not been translated yet" message.
* The page now shows the translation, not the source, and the edit box is
  bound to the source text so saving cannot overwrite the English with the
  Chinese.
* The stray language selector that sat after `</html>` in base.html is
  gone; the chapters-list page's dropdown had zero options because the
  route never passed the language list.
* The language tag is wired into generation: `utterance.language_code`
  (NULL = project source language) reaches `engine.generate()` and the
  staleness marker, so a retagged line is re-rendered instead of keeping
  English phonology behind an unchanged text. The marker records the
  language; a marker written before the tag existed means English, so the
  ~4,300 existing clips are not invalidated.
* `project.source_language` (spec 31 section 13.1) records the book's own
  language, with a migration for existing project DBs.
* A scene-break marker deliberately records no language: it is silence,
  identical in every language, and tagging it would claim a phonology the
  audio does not have.

Tests: 883 passed / 8 failed - the same 8 pre-existing failures
(2 test_pronunciation, 6 voice_profile_manager accent). 26 new tests
cover the resolver and the generation wiring. ruff introduces no new
findings.
2026-11-06 16:55:49 -08:00
..

Deal Hunter sample chapter - translated

Sample chapter 1 (the voice-introduction sample) in all 10 languages Qwen3-TTS produces. Files are named <base>_<LANG>.json.

These are LLM-produced samples from a single pass. They are not the multi-pass semantic translation the production pipeline is meant to do (see specs/27-translation-pipeline-multipass.md). They exist to evaluate the audio stage per language and to agree the file format early. Native-speaker review required.

Register

Casual/informal register throughout, matching the English source. Korean uses 해요체 (everyday polite), NOT 합쇼체 (formal written) and NOT 해체 (반말, which would be socially wrong between these characters). T/V languages use the informal form (du/tu/tú). Russian keeps вы, because ты is too intimate for narration. Japanese stays polite-but-warm.

Files

  • deal_hunter_sample_ch1_DE.json
  • deal_hunter_sample_ch1_EN.json
  • deal_hunter_sample_ch1_ES.json
  • deal_hunter_sample_ch1_FR.json
  • deal_hunter_sample_ch1_IT.json
  • deal_hunter_sample_ch1_JA.json
  • deal_hunter_sample_ch1_KO.json
  • deal_hunter_sample_ch1_PT.json
  • deal_hunter_sample_ch1_RU.json
  • deal_hunter_sample_ch1_ZH.json

Source issues found while translating

  • utt 3: 'Kianda's aunt' — 'Kianda' is a typo for 'Kainda'.
  • utt 5: 'the AI the runs the ship' — 'the' should be 'that'.
  • utt 8: 'I trade salvage' — double space.
  • The narrator's cues are telegraphic ('Princess Kainda say hello'), which a translator has to resolve by guessing. The production pipeline should decide whether to normalise these at the source.
  • Every utterance in this chapter is typed 'narration' even where a character speaks in the first person. Same class of finding as the speaker-review audit; it matters because emotion and pace are set per utterance.

Decisions to confirm

  • Deal Hunter and Umbra Audio kept in English in every language. Deal Hunter is both the title and the ship AI's name, so translating it would break the referent inside the story. Localisation decision, yours.
  • Character names transliterated by sound, not translated by meaning.