> ## Documentation Index
> Fetch the complete documentation index at: https://breezeblue-pre.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# Localizing a voice

> Create a new voice that speaks another language from a voice you already have.

Voice localization turns a voice you already use into a second voice whose reference audio is in another language. Breeze writes the preview script itself, generates the preview from the source voice, and returns a `generated_voice_id` you can audition and then save as a separate voice. The source voice is never modified.

Localization is asynchronous: creating a preview returns a `generation_job_id`, and the preview audio becomes available once the job reaches `ready`.

## When to localize

Text to speech already accepts a `language_code` for any saved voice, so a single voice can read lines in several languages. Localize when a language deserves its own speaker identity:

* The target language is part of your product's catalog and needs a stable, auditionable voice rather than a per-request language switch.
* You want native-language reference audio behind the voice, so pronunciation and delivery stay consistent across every request in that language.
* You want separate `voice_id` values, names, and metadata per language for routing, analytics, or voice pickers.

Scripts, performance instructions, and custom preview text are not accepted. To control what the voice says, save it and use [Text to Speech](/guides/text-to-speech).

## What you provide

| Field           | Required | Description                                                                                                               |
| --------------- | -------- | ------------------------------------------------------------------------------------------------------------------------- |
| `voice_id`      | Yes      | The source voice to localize. Any voice your account can generate with, including saved voices and public catalog voices. |
| `language_code` | Yes      | The target language as a supported two-letter code, such as `es`. See [supported language codes](/concepts/multilingual). |
| `name`          | No       | Display name for the preview. Defaults to the source voice's name.                                                        |

All 51 languages accepted by the Voice contract can be localization targets. Run one request per target language; each one produces its own preview.

## Step 1: Start a localization job

`POST /v1/voice-previews/localize` returns `202` as soon as the job is admitted. The response carries the `generation_job_id` used for every later poll.

```python theme={null}
import os

from breeze_blue import BreezeBlue

client = BreezeBlue(api_key=os.environ["BREEZE_API_KEY"])

job = client.voices.create_localize_preview(
    voice_id="voc_8rsb3nhb7645",
    language_code="es",
    name="Story narrator (Spanish)",
)

print(job["generation_job_id"])
```

```typescript theme={null}
import { BreezeBlueClient } from "@breeze.blue/sdk";

const client = new BreezeBlueClient({
  apiKey: process.env.BREEZE_API_KEY!,
});

const job = await client.voices.createLocalizePreview({
  voiceId: "voc_8rsb3nhb7645",
  languageCode: "es",
  name: "Story narrator (Spanish)",
});

console.log(job.generationJobId);
```

```bash theme={null}
curl -X POST "https://api.breeze.blue/v1/voice-previews/localize" \
  -H "xi-api-key: $BREEZE_API_KEY" \
  -H "content-type: application/json" \
  -d '{
    "voice_id": "voc_8rsb3nhb7645",
    "language_code": "es",
    "name": "Story narrator (Spanish)"
  }'
```

```json theme={null}
{
  "generation_job_id": "gen_01hlocalize",
  "status": "admitted"
}
```

## Step 2: Poll until the preview is ready

`GET /v1/voice-previews/localize/{generation_job_id}` reports the job's current state. Poll every two seconds or slower; the job runs two synthesis passes, so it typically takes longer than a single text-to-speech request.

| `status`                                | Meaning                                                                                 |
| --------------------------------------- | --------------------------------------------------------------------------------------- |
| `queued`, `admitted`                    | Accepted and waiting for capacity.                                                      |
| `generating`, `streaming`, `finalizing` | Synthesis in progress.                                                                  |
| `ready`                                 | The preview exists. `generated_voice_id`, `text`, and `language_code` are populated.    |
| `failed`                                | Generation stopped. `error` carries the machine-readable `code` and a `detail` message. |
| `cancelled`                             | The job was cancelled before it produced audio.                                         |

`generated_voice_id`, `text`, and `language_code` are `null` until the job is `ready`. `error` is `null` unless the job failed.

```python theme={null}
import time

status = client.voices.get_localize_preview(job["generation_job_id"])
while status["status"] not in ("ready", "failed", "cancelled"):
    time.sleep(2)
    status = client.voices.get_localize_preview(job["generation_job_id"])

if status["status"] != "ready":
    raise RuntimeError(status["error"]["detail"])

print(status["generated_voice_id"], status["text"])
```

```typescript theme={null}
let status = await client.voices.getLocalizePreview(job.generationJobId);
while (!["ready", "failed", "cancelled"].includes(status.status)) {
  await new Promise((resolve) => setTimeout(resolve, 2_000));
  status = await client.voices.getLocalizePreview(job.generationJobId);
}

if (status.status !== "ready") {
  throw new Error(status.error?.detail ?? status.status);
}

console.log(status.generatedVoiceId, status.text);
```

```bash theme={null}
curl "https://api.breeze.blue/v1/voice-previews/localize/gen_01hlocalize" \
  -H "xi-api-key: $BREEZE_API_KEY"
```

```json theme={null}
{
  "generation_job_id": "gen_01hlocalize",
  "status": "ready",
  "language_code": "es",
  "generated_voice_id": "gvi_01hpreview",
  "text": "El faro parpadeó dos veces y se quedó en silencio.",
  "error": null
}
```

`text` is the script Breeze wrote for the target language. Show it next to the preview so listeners know what they are hearing.

## Step 3: Audition the preview

Download the completed preview with `GET /v1/voice-previews/{generated_voice_id}/stream`. Request `mp3` for browser playback or omit `output_format` for the default.

```python theme={null}
from pathlib import Path

from breeze_blue import save

preview_audio = client.voices.stream_preview(
    status["generated_voice_id"],
    output_format="mp3",
)
save(preview_audio, Path("localize-preview.mp3"))
```

```typescript theme={null}
import { save } from "@breeze.blue/sdk/node";

const previewAudio = await client.voices.streamPreview(status.generatedVoiceId, {
  outputFormat: "mp3",
});
await save(previewAudio, "localize-preview.mp3");
```

```bash theme={null}
curl "https://api.breeze.blue/v1/voice-previews/gvi_01hpreview/stream?output_format=mp3" \
  -H "xi-api-key: $BREEZE_API_KEY" \
  --output localize-preview.mp3
```

A preview is temporary. If you do not save it, nothing is added to your account.

## Step 4: Save the preview as a voice

Save with `POST /v1/voice-previews/{generated_voice_id}/save`, exactly as you would for a designed or cloned preview. Pass the target language as `language_code` so later cross-language synthesis can tell the voice's reference language from the requested speech language.

```python theme={null}
voice = client.voices.save_preview(
    generated_voice_id=status["generated_voice_id"],
    voice_name="Story narrator (Spanish)",
    language_code="es",
)

print(voice["voice_id"])
```

```typescript theme={null}
const voice = await client.voices.savePreview({
  generatedVoiceId: status.generatedVoiceId,
  voiceName: "Story narrator (Spanish)",
  languageCode: "es",
});

console.log(voice.voiceId);
```

```bash theme={null}
curl -X POST "https://api.breeze.blue/v1/voice-previews/gvi_01hpreview/save" \
  -H "xi-api-key: $BREEZE_API_KEY" \
  -H "content-type: application/json" \
  -d '{
    "voice_name": "Story narrator (Spanish)",
    "language_code": "es"
  }'
```

Saving creates an independent voice with its own `voice_id` and consumes a voice slot. The source voice keeps its own reference audio, settings, and metadata. Set `gender`, `age`, `tone`, `accent`, and `tags` in the same call, or update them later with `PATCH /v1/voices/{voice_id}`; see [Voice Metadata](/concepts/voices#voice-metadata). Accent codes are language specific, so an accent saved for the source language is not carried over.

## Credits

Localization costs 100 credits per generation, the same fixed price as a voice clone generation, regardless of the preview script's length or language. Failed jobs release their reservation, and saving a completed preview does not incur another generation charge.

Each localization job counts toward your plan's concurrent generation limit while it runs. See [Pricing](/concepts/pricing) for metering and [Rate limits](/reference/rate-limits) for concurrency and retry guidance.

## Error handling

Creating the job can fail before anything is generated:

* `VALIDATION_ERROR` (422) — the language code is not a supported target, or the name exceeds the voice-name limit.
* `RESOURCE_NOT_FOUND` (404) — the `voice_id` does not exist or is not available to your account.
* `BILLING_INSUFFICIENT_CREDITS` (402) — the account balance or the API key's credit budget cannot cover the generation.
* `GENERATION_CONCURRENCY_EXCEEDED` (429) — your plan's concurrent generation limit was reached. Retry after the `Retry-After` interval.
* `GENERATION_CAPACITY_EXCEEDED` (503) — capacity is temporarily exhausted. Retry shortly.

After admission, failures surface in the poll response rather than as an HTTP error. `status` becomes `failed` and `error.code` identifies the cause; `VOICE_LOCALIZE_FAILED` means synthesis did not complete and the request can be retried. Treat any terminal status other than `ready` as the end of the job: start a new localization request instead of polling a finished job. The full code list is in [Errors](/reference/errors).

## Localize from the terminal

`breeze voice localize` runs the same flow in one command, waits for the job, and plays the preview in interactive terminals:

```bash theme={null}
breeze voice localize --voice voc_8rsb3nhb7645 --language es \
  --name "Story narrator (Spanish)"
```

Save the keeper with `breeze voice preview save`. See [CLI voices](/cli/reference/voices).

## Continue building

<Columns cols={2}>
  <Card title="Create localize preview" icon="braces" href="/api-reference/voice-previews/create-localize-preview">
    Queue a localization job and read the returned `generation_job_id`.
  </Card>

  <Card title="Get localize preview" icon="list-checks" href="/api-reference/voice-previews/get-localize-preview">
    Poll the job until it turns `ready` and hands back a `generated_voice_id`.
  </Card>

  <Card title="Save voice preview" icon="save" href="/api-reference/voice-previews/save-voice-preview">
    Persist the localized preview as a reusable voice; saving consumes a voice slot.
  </Card>

  <Card title="Multilingual audio" icon="globe" href="/concepts/multilingual">
    Look up the 51 supported language codes and the accent rules per language.
  </Card>

  <Card title="Voices" icon="sliders-horizontal" href="/concepts/voices">
    See how localized, cloned, designed, and public voices fit together.
  </Card>

  <Card title="Text to speech" icon="mic" href="/guides/text-to-speech">
    Generate lines with the saved localized `voice_id`.
  </Card>

  <Card title="Voice Clone" icon="copy" href="/guides/voice-clone">
    Create the source voice from a consented audio sample.
  </Card>

  <Card title="CLI voices" icon="terminal" href="/cli/reference/voices">
    Localize, audition, and save voices from the terminal.
  </Card>

  <Card title="Pricing" icon="credit-card" href="/concepts/pricing">
    Estimate localization cost and shared generation concurrency.
  </Card>
</Columns>
