Translation
The problem. A support agent in Paris, a customer speaking Spanish; a conference streamed to an international audience. Translation turns each sentence into the languages you choose while the person is still speaking: live subtitles, a bilingual call log, a meeting record in your team’s language.
Where it works. solaria-3 only. The translation is made from the audio of each utterance, not from its
transcript.
Step by step
Section titled “Step by step”1. Choose the target languages
Section titled “1. Choose the target languages”{ "model": "solaria-3", "realtime_processing": { "translation": true, "translation_config": { "target_languages": ["en", "fr"] } }}2. Start a session with it
Section titled “2. Start a session with it”Each program streams a 16-bit WAV file and prints what comes back. Put your API key in the GLADIA_API_KEY environment variable, then run python translation.py meeting.wav.
# pip install gladiaio-sdkimport osimport sysimport threadingimport wave
from gladiaio_sdk import GladiaClient, LiveV2InitRequest
API_URL = os.environ.get("GLADIA_API_URL", "https://eu1.api.gladia.io")API_KEY = os.environ["GLADIA_API_KEY"]
with wave.open(sys.argv[1]) as wav: # a 16-bit PCM WAV file rate, channels = wav.getframerate(), wav.getnchannels() audio = wav.readframes(wav.getnframes())
config = { "encoding": "wav/pcm", "sample_rate": rate, "bit_depth": 16, "channels": channels, "model": "solaria-3", "language_config": { "languages": [ "es" ] }, "realtime_processing": { "translation": True, "translation_config": { "target_languages": [ "en", "fr" ] } }}
client = GladiaClient(api_key=API_KEY, api_url=API_URL)session = client.live_v2().start_session(LiveV2InitRequest.from_dict(config))ended, errors = threading.Event(), []
@session.on("message")def on_message(message): if message.type == "transcript" and message.data.is_final: print(message.data.utterance.text) elif message.type == "translation" and message.data.translated_utterance: translated = message.data.translated_utterance print(f" {translated.language}: {translated.text}")
session.on("error", errors.append)session.once("ended", lambda _: ended.set())
step = rate * channels * 2 // 10 # 100 ms of audio per chunkfor start in range(0, len(audio), step): session.send_audio(audio[start : start + step]) # live audio: send each chunk as it is capturedsession.stop_recording()
ended.wait(timeout=60)sys.exit(1 if errors or not ended.is_set() else 0)// npm install @gladiaio/sdkimport { readFileSync } from "node:fs";import { GladiaClient } from "@gladiaio/sdk";
const { sampleRate, channels, pcm } = readWav(process.argv[2]); // a 16-bit PCM WAV file
const config = { encoding: "wav/pcm", sample_rate: sampleRate, bit_depth: 16, channels, model: "solaria-3", language_config: { languages: [ "es" ] }, realtime_processing: { translation: true, translation_config: { target_languages: [ "en", "fr" ] } }};
const client = new GladiaClient({ apiKey: process.env.GLADIA_API_KEY, apiUrl: process.env.GLADIA_API_URL ?? "https://eu1.api.gladia.io",});const session = client.liveV2().startSession(config);
session.on("message", (message) => { if (message.type === "transcript" && message.data.is_final) console.log(message.data.utterance.text); if (message.type === "translation" && message.data.translated_utterance) { const { language, text } = message.data.translated_utterance; console.log(` ${language}: ${text}`); }});session.on("error", (error) => { console.error(error); process.exitCode = 1;});session.once("ended", () => process.exit());
const step = (sampleRate * channels * 2) / 10; // 100 ms of audio per chunkfor (let start = 0; start < pcm.length; start += step) { session.sendAudio(pcm.subarray(start, start + step)); // live audio: send each chunk as it is captured}session.stopRecording();
function readWav(path) { const file = readFileSync(path); let fmt, pcm; for (let pos = 12; pos < file.length; ) { const id = file.toString("ascii", pos, pos + 4); const size = file.readUInt32LE(pos + 4); if (id === "fmt ") fmt = { channels: file.readUInt16LE(pos + 10), sampleRate: file.readUInt32LE(pos + 12) }; if (id === "data") pcm = file.subarray(pos + 8, pos + 8 + size); pos += 8 + size + (size % 2); } return { ...fmt, pcm };}Create the session, then stream its audio to the returned url (Live WebSocket):
curl -X POST https://eu1.api.gladia.io/v2/live \ -H "x-gladia-key: $GLADIA_API_KEY" \ -H "content-type: application/json" \ -d '{ "encoding": "wav/pcm", "sample_rate": 16000, "bit_depth": 16, "channels": 1, "model": "solaria-3", "language_config": { "languages": [ "es" ] }, "realtime_processing": { "translation": true, "translation_config": { "target_languages": [ "en", "fr" ] } } }'3. Read the translations
Section titled “3. Read the translations”Each final transcript is followed by one translation message per target language:
{ "type": "translation", "session_id": "0199d7a2-5c3e-7b41-9f0a-3c2d1e4f5a6b", "error": null, "data": { "utterance_id": "00_00000003", "utterance": { "text": "¿Dónde está la estación?", "start": 12.4, "end": 13.9, "language": "es", "channel": 0 }, "original_language": "es", "target_language": "en", "translated_utterance": { "text": "Where is the station?", "start": 12.4, "end": 13.9, "language": "en", "channel": 0, "confidence": 1, "words": [] } }}4. Get them all at the end
Section titled “4. Get them all at the end”The session’s result (GET /v2/live/{id}, post_final_transcript) has a
translation block: one result per target language, with its utterances and full text.
Limits and gotchas
Section titled “Limits and gotchas”solaria-3only. With another model, no model can serve the session:POST /v2/liveanswers500“no inference endpoint available”.- Only the languages below. Another code passes the creation, then the session is refused when it starts: the
WebSocket closes with code
1011and the reasonrejected: translation: target language(s) [...] not served. - Not with PII redaction. The translation is made from the audio and would carry the redacted data back: a
session with both
piiandtranslationis refused when it starts (1011,rejected: ...). - Finals only. Partials are not translated. Translations arrive shortly after their final, never before it, and never delay it.
- Same language, same text. An utterance already in a target language comes back as transcribed.
- Long utterances. Translation reads up to 60 seconds of an utterance: set
maximum_duration_without_endpointing(at most 60) for monologues without pauses. - A translation can fail alone. It then comes with
errorset andtranslated_utterance: null; the transcript is not affected. Show the original text as a fallback. - At the end, the session waits up to 5 seconds for the last translations before
end_session. - Spelling and vocabulary do not apply to translations (they come from the audio).
- Accepted, not applied. Gladia’s cloud fields
model,context,context_adaptation,informal,lipsyncandmatch_original_utterancesintranslation_configare accepted for compatibility and have no effect.
Target languages
Section titled “Target languages”| Target language | Code |
|---|---|
| Afrikaans | af |
| Amharic | am |
| Arabic | ar |
| Assamese | as |
| Belarusian | be |
| Bulgarian | bg |
| Bangla | bn |
| Catalan | ca |
| Danish | da |
| German | de |
| English | en |
| Spanish | es |
| Persian | fa |
| French | fr |
| Galician | gl |
| Indonesian | id |
| Italian | it |
| Japanese | ja |
| Khmer | km |
| Korean | ko |
| Lingala | ln |
| Lao | lo |
| Malay | ms |
| Burmese | my |
| Nepali | ne |
| Dutch | nl |
| Norwegian | no |
| Pashto | ps |
| Portuguese | pt |
| Romanian | ro |
| Russian | ru |
| Somali | so |
| Swedish | sv |
| Thai | th |
| Vietnamese | vi |
| Wolof | wo |
| Yoruba | yo |
| Chinese | zh |
Troubleshooting
Section titled “Troubleshooting”| symptom | cause | fix |
|---|---|---|
500 “no inference endpoint available” at creation |
the model is not solaria-3 |
set "model": "solaria-3" |
WebSocket closed 1011 “rejected: translation: target language(s)…” |
a target not in the list | use the codes above |
WebSocket closed 1011 “rejected: … pii redaction” |
pii and translation together |
drop one of them |
no translation message |
messages_config.receive_realtime_processing_events: false |
turn it back on, or read the session’s result |