## Language Translation (LT)

Language Translation (LT) runs on the remote-inference pipeline. Unlike audio processing, it is **selected by the presence of an `lt_config`**, not by a model key — so `AudioAttributes.model_name` is left empty. Translated audio comes back from `process_frame`; transcripts arrive on the `lt_config` callback. This tutorial follows the `language_translation_example.py` example. If you haven’t yet, read [Processing a Single Stream](https://developer.sanas.ai/Docs/Tutorials/Single-Stream) first — LT reuses the same activation, pipeline-readiness, and real-time feed mechanics.

LT has a large round-trip latency (~3–4 s). You must keep pushing silence for a window that **exceeds** that latency after the input ends, or the translated tail will be lost.

## Prerequisites

| Variable                        | Required | Default               | Purpose                                          |
|---------------------------------|----------|----------------------|--------------------------------------------------|
| `SANAS_API_KEY`                | Yes      | —                    | Licence key                                     |
| `SANAS_STORAGE_DIR`            | No       | `./storage`         | SDK data + logs                                 |
| `SANAS_LANG_IN`                | No       | `en-US`             | Source language code                            |
| `SANAS_LANG_OUT`               | No       | `es-ES`             | Target language code                            |
| `SANAS_CONVERSATION_ID`        | No       | `conversation-id-1` | Links two-party sessions                        |
| `SANAS_LT_DRAIN_SECONDS`       | No       | `5.0`               | Silence drain window; must exceed LT latency    |

```
export SANAS_API_KEY="your-key"
python language_translation_example.py --input test_input.wav --output translated.wav
```

## Step 1: Handle transcript callbacks

Transcripts arrive as `TextFrame`s. Each frame is either a `TRANSLATION` or a `TRANSCRIPTION`, carries an utterance index and language code, and contains `complete` and `partial` segments. Segments may include redacted text.

```
import sanas

def print_transcript(tf):
    label = "Translation" if tf.type_ == sanas.TranscriptType.TRANSLATION else "Transcription"
    td = tf.transcript_data_
    lang = f" lang={{td.language_code_}}" if td.language_code_ else ""
    print(f"\n[{{label}}] utterance {{td.utterance_idx}}{{lang}}")
    for kind, segs in (("complete", td.complete), ("partial", td.partial)):
        for s in segs:
            redacted = f' (redacted: "{{s.redacted_text}}")' if s.redacted_text else ""
            print(f'  [{{kind}}] "{{s.text}}"{{redacted}} [{{s.start}}-{{s.end}} p={{s.probability:.2f}}]')
```

## Step 2: Activate and load audio

Identical to single-stream processing:

```
from helpers import PipelineWaiter, feed_and_drain, load_samples
from wav_utils import save_wav

sdk = sanas.create_sdk(sanas.InitParams(storage_dir=storage_dir))
res = sdk.activate_api_key(api_key)
if not res.success:
    sys.exit(f"Activation failed: {{res.message}}")
print(f"[activation] OK (SDK {{sdk.version}})")

samples, sample_rate, channels = load_samples(args.input)
```

## Step 3: Configure translation via `lt_config`

Leave `model_name` empty and attach a `LanguageTranslationConfig`. Its presence is what puts the pipeline into translation mode.

```
waiter = PipelineWaiter(on_state=lambda s: print(f"[pipeline] {{s}}"))

attrs = sanas.ProcessorAttributes(
    audio_attributes=sanas.AudioAttributes(
        sampling_rate=sample_rate,
        channels=channels,
        model_name="",   # LT is selected by lt_config, not a model key
        audio_pipeline_state_notify=waiter.callback,
    ),
    lt_config=sanas.LanguageTranslationConfig(
        language_in=lang_in,
        language_out=lang_out,
        conversation_id=conversation_id,   # optional; links two-party sessions
        callback=print_transcript,
    ),
)
```

## Step 4: Feed with an extended drain window

Because translation lags several seconds behind the input, pass `drain_seconds` to `feed_and_drain`. This makes the helper pump silence for a fixed, real-time-paced window (instead of stopping early on empty frames), giving the remote wall-clock time to return the tail.

```
drain_seconds = float(os.environ.get("SANAS_LT_DRAIN_SECONDS", "5.0"))

with sdk.create_audio_processor(attrs) as proc:
    print("[pipeline] waiting for RUNNING ...")
    waiter.wait_until_running(timeout=30.0)
    result = feed_and_drain(proc, samples, sample_rate, channels, drain_seconds=drain_seconds)
```

Set `SANAS_LT_DRAIN_SECONDS` comfortably above the observed round-trip latency. The default of 5 s covers the typical ~3–4 s; increase it if your target language or network is slower.

## Step 5: Save the translated audio

```
combined = result["output"]
if combined:
    save_wav(args.output, combined, sample_rate, channels)
    print(f"\n[output] {{len(combined) // 4}} samples -> {{args.output}}")
else:
    print("\n[output] no translated audio received.")
```

## How it differs from audio processing

|  | Audio processing               | Language Translation                  |
|---|-------------------------------|--------------------------------------|
| Selected by   | `model_name` (e.g. `VI_G_SE`) | presence of `lt_config`              |
| `model_name`   | a model key                    | empty string                          |
| Latency         | ~50–100 ms                    | ~3–4 s                               |
| Tail drain      | stop on empty frames (default) | fixed `drain_seconds` window         |
| Extra output    | processed audio only           | audio **and** transcript callbacks    |

## Next Steps

[**Processing a Single Stream** \
\
The core flow this benchmark scales up.](https://developer.sanas.ai/Docs/Tutorials/Single-Stream)

[**API Reference** \
\
Full SDK documentation for classes, enums, and callbacks.](https://developer.sanas.ai/API-Reference/Overview)

[**Language Translation** \
\
Translate speech between languages and receive audio plus transcripts.](https://developer.sanas.ai/Docs/Tutorials/Language-Translation)

[**Processing Multiple Streams** \
\
Run many concurrent processors on one SDK instance.](https://developer.sanas.ai/Docs/Tutorials/Processing-Multiple-Streams)

## References

[**SDK** \
\
SDK lifecycle methods including create_sdk, activate_api_key, and create_audio_processor.](https://developer.sanas.ai/API-Reference/Reference/Core-Classes/RemoteSDK)

[**AudioProcessor** \
\
process_frame method for audio processing.](https://developer.sanas.ai/API-Reference/Reference/Core-Classes/AudioProcessor)
