Non-English voices drifted to English/wrong-language because the request's or
profile's language wasn't reaching the model:
- #533: generate_speech() read instruct/ref_text/seed from a resolved profile row
but never row['language'] (and collapsed Auto→None), so a German archetype
previewed in German yet generated in English on the user's own call (and via
Docker/API). Fall back to the profile's stored language when the request didn't
pin one; an explicit non-Auto request language still wins. (Frontend already
sets the dropdown on profile-select; this is the authoritative backend fix.)
- #505 (B2): the audiobook/longform synth hardcoded language=None, so the engine
re-autodetected per chunk and a non-English clone flipped language mid-render.
Add _resolve_default_language (request → profile → autodetect) and thread the
resolved language through _build_synth/_prepare_synth/_render_longform_sse, the
three longform request models, the preview path, and the resume manifest.
Genuine Auto/unset behavior is unchanged.
- #502 (partial): the duration estimator weights combining marks (U+0300–036F)
at 0.0, so NFD/decomposed text under-allocated frames → rushed audio. NFC-
normalize text at the estimator entry — fixes the whole diacritic-script class
(no-op for precomposed text). (The residual "distorted" core still needs the
reporter's sample; tracked separately.)
Tests (fail-before/pass-after): profile language reaches the engine (German→de;
explicit/Auto override semantics); longform synth gets the resolved language
(→ja), not None; NFD vs NFC duration parity (Korean Hangul diverges ~3x pre-fix).
Full suite: tests/ 1740 passed, backend/tests/ 114 passed.
Co-authored-by: mergetest <test@local>
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>