> ## Documentation Index
> Fetch the complete documentation index at: https://docs.camb.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Image Translation

> Localize images and PDFs into any language using the Python or TypeScript SDK

## Overview

Localize images and PDFs into any language while keeping the original design. It works on posters, signage, screenshots, menus, comics, and multi-page documents, and can translate into several languages in a single job. If a line of text needs different wording or a different look, fine-tune just that region with a short prompt.

Image translation is asynchronous: you submit a job, poll until it completes, then retrieve the result.

### Prerequisites

**1. Create an account**

Sign up at [CAMB.AI Studio](https://studio.camb.ai) if you haven't already.

**2. Get your API key**

Go to **Settings → API Keys** in Studio and copy your key. See [Authentication](https://docs.camb.ai/getting-started/authentication.md) for details.

**3. Install the SDK**

```bash Python theme={null}
pip install camb-sdk
```

```bash TypeScript theme={null}
npm install @camb-ai/sdk
```

Skip this step if you're using the [direct API](https://docs.camb.ai/tutorials/direct-api.md).

**4. Set your API key to use in your code**

```bash theme={null}
export CAMB_API_KEY="your_api_key_here"
```

***

## Code

```python Python theme={null}
import os
import time
from camb.client import CambAI
from camb.types.language_enums import Languages

client = CambAI(api_key=os.getenv("CAMB_API_KEY"))

response = client.image_translation.create_image_translation(
    source_language=Languages.EN_US,
    target_languages=[Languages.ES_ES],
    media_url="https://example.com/image.png",
    export_format="ZIP",
)
print(f"Image translation task created: {response.task_id}")

while True:
    status = client.image_translation.get_image_translation_status(
        task_id=response.task_id
    )
    print(f"Status: {status.status}")
    if status.status == "SUCCESS":
        result = client.image_translation.get_image_translation_result(
            run_id=response.run_id
        )
        print(f"Download URL: {result.download_url}")
        break
    elif status.status == "ERROR":
        print(f"Image translation failed: {status.exception_reason}")
        break
    time.sleep(5)
```

```javascript TypeScript theme={null}
import { CambClient, CambApi } from '@camb-ai/sdk';

const client = new CambClient({
    apiKey: process.env.CAMB_API_KEY
});

async function translateImage() {
    const response = await client.imageTranslation.createImageTranslation({
        source_language: CambApi.Languages.EN_US,
        target_languages: [CambApi.Languages.ES_ES],
        media_url: 'https://example.com/image.png',
        export_format: 'ZIP',
    });
    console.log(`Image translation task created: ${response.task_id}`);

    while (true) {
        const status = await client.imageTranslation.getImageTranslationStatus({
            task_id: response.task_id,
        });
        console.log(`Status: ${status.status}`);

        if (status.status === 'SUCCESS') {
            const result = await client.imageTranslation.getImageTranslationResult({
                run_id: response.run_id,
            });
            console.log(`Download URL: ${result.download_url}`);
            break;
        } else if (status.status === 'ERROR') {
            console.error(`Image translation failed: ${status.exception_reason}`);
            break;
        }

        await new Promise((resolve) => setTimeout(resolve, 5000));
    }
}

translateImage();
```

***

## Parameters

### Required

| Parameter | Type | Description |
| - | - | - |
| `source_language` | `Languages` enum | Language of the text in the source image |
| `target_languages` | `Languages[]` | Languages to translate into. Pass a single-element list (`[Languages.ES_ES]`) for one target, or several to translate into all of them in a single job. |
| `media_url` | string | Publicly accessible URL of the image, PDF, or ZIP of page images |

On the raw HTTP API, `target_languages` is a comma-separated string (`es-es` or `es-es,pt-br`). The SDKs take an array and join it.

### Optional

| Parameter | Type | Description |
| - | - | - |
| `export_format` | `"ZIP"` \| `"PDF"` | What the result ZIP contains. Defaults to `ZIP` (page images). `PDF` packs one PDF per target language inside the ZIP. |
| `project_name` | string | Label for the job in your dashboard |
| `project_description` | string | Additional notes for the job |
| `folder_id` | integer | Studio folder that belongs to the API key's team |

### Result shape

`get_image_translation_result` / `getImageTranslationResult` returns `{ "download_url": "..." }` — a presigned URL to a ZIP. That ZIP contains page images (`export_format="ZIP"`, the default) or one PDF per target language (`export_format="PDF"`). Request a fresh URL if the previous one has expired.

### Language Enum

Use the `Languages` enum (Python) or `CambApi.Languages` (TypeScript) to specify languages:

```python Python theme={null}
from camb.types.language_enums import Languages

# Examples
Languages.EN_US   # English (US)
Languages.ES_ES   # Spanish (Spain)
Languages.FR_FR   # French
Languages.DE_DE   # German
Languages.HI_IN   # Hindi
Languages.JA_JP   # Japanese
Languages.ZH_CN   # Chinese (Simplified)
```

```javascript TypeScript theme={null}
import { CambApi } from '@camb-ai/sdk';

// Examples
CambApi.Languages.EN_US   // English (US)
CambApi.Languages.ES_ES   // Spanish (Spain)
CambApi.Languages.FR_FR   // French
CambApi.Languages.DE_DE   // German
CambApi.Languages.HI_IN   // Hindi
CambApi.Languages.JA_JP   // Japanese
CambApi.Languages.ZH_CN   // Chinese (Simplified)
```

***

## Inspect the project

Fetch the project to get region IDs, source text, and per-page previews, for example before a fine-tune. The response looks like this:

```json [expandable] theme={null}
{
  "run_id": 12345,
  "source_language_id": 1,
  "target_languages": [{ "target_language_id": 54 }],
  "pages": [
    {
      "page_id": 1,
      "order_index": 0,
      "width": 1200,
      "height": 1800,
      "renders": [
        {
          "target_language_id": 54,
          "is_stale": false,
          "preview_url": "https://..."
        }
      ],
      "regions": [
        {
          "region_id": 1,
          "order_index": 0,
          "box": { "x": 120, "y": 80, "width": 480, "height": 140 },
          "source_text": "Summer Sale",
          "translations": [
            { "target_language_id": 54, "text": "Rebajas de verano", "is_stale": false }
          ]
        }
      ]
    }
  ]
}
```

```python Python theme={null}
project = client.image_translation.get_image_translation_project(
    run_id=response.run_id
)
region = project.pages[0].regions[0]
print(region.region_id, region.source_text)
```

```javascript TypeScript theme={null}
const project = await client.imageTranslation.getImageTranslationProject({
    run_id: response.run_id,
});
const region = project.pages[0].regions[0];
console.log(region.region_id, region.source_text);
```

This route 404s until the export ZIP exists. Poll the create `task_id` to `SUCCESS` first.

***

## Fine-tune a region

Send a short written instruction for one `region_id` from the project payload, such as `Change the text color to white`, `Use a bolder font`, or `Add a soft drop shadow`. Poll the returned `task_id` the same way as create, then [export](#export) so the change appears in your download.

```python Python theme={null}
ft = client.image_translation.fine_tune_image_translation(
    run_id=response.run_id,
    target_language_id=Languages.ES_ES,
    region_id=region.region_id,
    prompt="Change the text color to white and add a soft drop shadow",
)
print(f"Fine-tune task created: {ft.task_id}")
```

```javascript TypeScript theme={null}
const ft = await client.imageTranslation.fineTuneImageTranslation({
    run_id: response.run_id,
    target_language_id: CambApi.Languages.ES_ES,
    region_id: region.region_id,
    prompt: 'Change the text color to white and add a soft drop shadow',
});
console.log(`Fine-tune task created: ${ft.task_id}`);
```

TypeScript request bodies use **snake\_case** keys (`run_id`, `target_language_id`), matching the HTTP API.

***

## Export

Creating a job exports your translated pages automatically. A fine-tune does not: it updates the project, but your download stays the same until you export again. Run an export after every fine-tune, or whenever you want to switch `export_format`. It's also the fix if the result route returns a 404.

`export_image_translation` / `exportImageTranslation` returns `{ task_id, cached }`. Poll `task_id` only when it is present; if `cached` is true and there is no `task_id`, skip polling and fetch the result.

```python Python theme={null}
exported = client.image_translation.export_image_translation(
    run_id=response.run_id,
    export_format="PDF",
)
if exported.task_id:
    # poll exported.task_id the same way as create
    pass
result = client.image_translation.get_image_translation_result(run_id=response.run_id)
print(result.download_url)
```

```javascript TypeScript theme={null}
const exported = await client.imageTranslation.exportImageTranslation({
    run_id: response.run_id,
    export_format: 'PDF',
});
if (exported.task_id) {
    // poll exported.task_id the same way as create
}
const result = await client.imageTranslation.getImageTranslationResult({
    run_id: response.run_id,
});
console.log(result.download_url);
```

***

## Tips

* **Public URL:** `media_url` must be reachable without authentication.
* **Formats:** PNG, JPG, JPEG, WEBP, and PDF. For multi-page sources, you can also pass a ZIP of page images.
* **`export_format`:** The download is always a ZIP. `ZIP` (default) puts page images inside it; `PDF` puts one PDF per target language inside it. Pass it on create or on a later export.
* **`task_id` vs `run_id`:** `task_id` is the async job (create, export, or fine-tune). `run_id` is the project; use it for result, project, export, and fine-tune.
* **Multiple targets:** `target_languages` accepts several languages in one job, which is more efficient than submitting separate jobs.
* **Expired URLs:** `download_url` and preview URLs are presigned. Call the result or project route again when they expire.

***

## Next Steps

> [card] [End-to-End Image Translation API](https://docs.camb.ai/api-reference/endpoint/end-to-end-image-translation.md)
>
> Full API reference for the create endpoint.

> [card] [Get Image Translation Status](https://docs.camb.ai/api-reference/endpoint/get-end-to-end-image-translation-status.md)
>
> Status polling endpoint reference.

> [card] [Get Image Translation Result](https://docs.camb.ai/api-reference/endpoint/get-image-translation-result.md)
>
> Retrieve the translated ZIP.

> [card] [Fine-Tune Image Translation](https://docs.camb.ai/api-reference/endpoint/fine-tune-image-translation.md)
>
> Re-render one region with a prompt.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.