What changed

translate-text now follows the same bounded provider path as the translate route. It tries the fast translation model first, then falls back when needed. It also accepts a JSON reply wrapped in a code fence, which some providers send despite JSON-mode requests.

If both providers are unavailable, the route returns a dependency failure instead of presenting it as an internal server error. That makes a paid failure clearer to callers and keeps retry decisions honest.

What stays the same

The request and response fields are unchanged: send text and target_language, then receive translated_text and the detected source language. Markdown, code blocks, URLs, and proper nouns remain part of the translation contract.