From 962a94cdedc3e775ffb5049da56c5c69fa1d0ab0 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Tue, 8 Sep 2026 08:42:40 +0000 Subject: [PATCH] docs: add generated pages from pipeline run 20260908-082715 Generated 3 pages for: Languages, Voice, unknown - docs/voice/translate-a-pre-recorded-audio-file.mdx: No guide (tutorial or how-to) covers the 'Translate Audio Files' endpoints - docs/languages/check-which-languages-and-features-are-supported-for-a-resource.mdx: No guide (tutorial or how-to) covers the 'Languages' endpoints - docs/learning-how-tos/cookbook/google-sheets: docs/learning-how-tos/cookbook/google-sheets has under 100 words --- docs.json | 6 +- ...-features-are-supported-for-a-resource.mdx | 169 +++++++++++ .../translate-a-pre-recorded-audio-file.mdx | 266 ++++++++++++++++++ 3 files changed, 440 insertions(+), 1 deletion(-) create mode 100644 docs/languages/check-which-languages-and-features-are-supported-for-a-resource.mdx create mode 100644 docs/voice/translate-a-pre-recorded-audio-file.mdx diff --git a/docs.json b/docs.json index 38559381..94d1a1b4 100644 --- a/docs.json +++ b/docs.json @@ -102,6 +102,9 @@ } ] } + ], + "pages": [ + "docs/languages/check-which-languages-and-features-are-supported-for-a-resource" ] }, { @@ -149,7 +152,8 @@ "docs/voice/understanding-voice-sessions", "docs/voice/message-encoding", "docs/voice/supported-voice-languages", - "docs/voice/voice-api-requirements" + "docs/voice/voice-api-requirements", + "docs/voice/translate-a-pre-recorded-audio-file" ] }, { diff --git a/docs/languages/check-which-languages-and-features-are-supported-for-a-resource.mdx b/docs/languages/check-which-languages-and-features-are-supported-for-a-resource.mdx new file mode 100644 index 00000000..7317743c --- /dev/null +++ b/docs/languages/check-which-languages-and-features-are-supported-for-a-resource.mdx @@ -0,0 +1,169 @@ +--- +title: "Check which languages and features are supported for a resource" +description: "Query the Languages API to discover which languages and optional features are available for a specific DeepL API resource before making translation requests." +covers: [Languages] +--- + +The Languages API lets you query language and feature support per DeepL API resource at runtime. Use it to populate language dropdowns, enable or disable feature toggles (like formality or glossaries), and validate language codes — instead of hardcoding assumptions that go stale when DeepL adds new languages. + +This guide shows you how to fetch languages for a resource, read the response, and filter by feature availability. + + + `GET /v3/languages` replaces the deprecated `GET /v2/languages` endpoint. If you're currently using v2, see the [migration guide](/docs/languages/migrating-from-v2-languages). + + +## Before you start + +You'll need a DeepL API key. If you don't have one, [sign up for a free account](https://www.deepl.com/pro/change-plan#developer). + +Set your key as an environment variable so you can reuse it across examples: + +```sh +export DEEPL_API_KEY=your-api-key-here +``` + +If you're on the free plan, replace `https://api.deepl.com` with `https://api-free.deepl.com` in every request below. + +## Step 1: Choose a resource + +The `resource` query parameter is required. It tells the API which DeepL product you're querying language support for: + +| **Value** | **Use when building against...** | +|---|---| +| `translate_text` | Text translation (`/v2/translate`) | +| `translate_document` | Document translation (`/v2/document`) | +| `glossary` | Glossary management (`/v2/` and `/v3/glossaries`) | +| `voice` | Speech transcription and translation (`/v3/voice`) | +| `write` | Text improvement (`/v2/write`) | +| `style_rules` | Style rules (`/v3/style-rules`) | +| `translation_memory` | Translation memory | + +For this guide, we'll use `translate_text` — the most common starting point. + +## Step 2: Fetch supported languages + +Call `GET /v3/languages` with your chosen resource: + +```sh +curl -X GET 'https://api.deepl.com/v3/languages?resource=translate_text' \ + --header "Authorization: DeepL-Auth-Key $DEEPL_API_KEY" +``` + +The response is a JSON array. Each entry represents one language: + +```json +[ + { + "lang": "de", + "name": "German", + "status": "stable", + "usable_as_source": true, + "usable_as_target": true, + "features": { + "formality": { "status": "stable" }, + "glossary": { "status": "stable" }, + "tag_handling": { "status": "stable" } + } + }, + { + "lang": "en", + "name": "English", + "status": "stable", + "usable_as_source": true, + "usable_as_target": false, + "features": { + "glossary": { "status": "stable" }, + "tag_handling": { "status": "stable" } + } + }, + { + "lang": "en-US", + "name": "English (American)", + "status": "stable", + "usable_as_source": false, + "usable_as_target": true, + "features": { + "glossary": { "status": "stable" }, + "tag_handling": { "status": "stable" } + } + } +] +``` + +Notice that `en` and `en-US` are separate entries. `en` is source-only (`usable_as_source: true`, `usable_as_target: false`) while `en-US` is target-only. Always use `usable_as_source` and `usable_as_target` to determine role — don't infer it from the language code. + + + Treat `lang` codes as opaque identifiers. Don't assume they'll always be two letters, or that hyphenated codes follow any particular pattern. Use a BCP 47-compliant library if you need to parse them. See [Language release process](/docs/resources/language-release-process) for details. + + +## Step 3: Read the features object + +Each language entry includes a `features` object. The keys are feature names; each value has at least a `status` field (`stable`, `beta`, or `early_access`). + +Whether a feature requires source-language support, target-language support, or both depends on the resource. To look that up programmatically, call `GET /v3/languages/resources`: + +```sh +curl -X GET 'https://api.deepl.com/v3/languages/resources' \ + --header "Authorization: DeepL-Auth-Key $DEEPL_API_KEY" +``` + +```json +[ + { + "name": "translate_text", + "features": [ + { "name": "formality", "needs_target_support": true }, + { "name": "glossary", "needs_source_support": true, "needs_target_support": true }, + { "name": "tag_handling", "needs_source_support": true, "needs_target_support": true }, + { "name": "auto_detection", "needs_source_support": true } + ] + } +] +``` + +This tells you, for example, that `formality` only requires the target language to support it — the source language doesn't matter. `glossary` requires both. Use this response to determine feature availability for any language pair without hardcoding the rules. + +## Step 4: Filter by feature or role + +Here are common filtering tasks you'll encounter when building a UI or validating inputs. + +**Get all valid target languages:** + +```sh +curl -s 'https://api.deepl.com/v3/languages?resource=translate_text' \ + --header "Authorization: DeepL-Auth-Key $DEEPL_API_KEY" \ + | jq '[.[] | select(.usable_as_target == true) | {lang, name}]' +``` + +**Get target languages that support formality:** + +```sh +curl -s 'https://api.deepl.com/v3/languages?resource=translate_text' \ + --header "Authorization: DeepL-Auth-Key $DEEPL_API_KEY" \ + | jq '[.[] | select(.usable_as_target == true and .features.formality != null) | {lang, name}]' +``` + +**Include beta languages** (excluded by default): + +```sh +curl -X GET 'https://api.deepl.com/v3/languages?resource=translate_text&include=beta' \ + --header "Authorization: DeepL-Auth-Key $DEEPL_API_KEY" +``` + +Use `include=beta` when you want to surface languages that are available but not yet stable. You can also pass `include=external` to include features provided by third-party service partners, or combine them: `?include=beta&include=external`. + +## What to do with this data + +A few practical patterns: + +- **Language pickers**: filter by `usable_as_source` or `usable_as_target` and display `name` to users. Store `lang` as the value to send in API requests. +- **Feature toggles**: before showing a formality selector, check that the target language has `formality` in its `features` object. Hide the control if it's absent. +- **Input validation**: check that a user-supplied language code appears in the response before passing it to a translation request. Return a clear error if it doesn't. +- **Cache the response**: language support changes infrequently. Cache the `/v3/languages` response for a reasonable period (for example, 24 hours) rather than fetching it on every request. + +## Next steps + +- See the full response schema and parameter reference: [Retrieve languages](/api-reference/languages/retrieve-languages-by-resource) +- Understand which features each resource supports: [Retrieve language resources](/api-reference/languages/retrieve-resources) +- Browse the full list of supported languages: [Languages supported](/docs/getting-started/supported-languages) +- Migrating from v2? See the [migration guide](/docs/languages/migrating-from-v2-languages) \ No newline at end of file diff --git a/docs/voice/translate-a-pre-recorded-audio-file.mdx b/docs/voice/translate-a-pre-recorded-audio-file.mdx new file mode 100644 index 00000000..1a75d4f1 --- /dev/null +++ b/docs/voice/translate-a-pre-recorded-audio-file.mdx @@ -0,0 +1,266 @@ +--- +title: "Translate a Pre-Recorded Audio File" +description: "Submit an audio file to the Voice Translate Job API, poll for results, and download translations as text, subtitles, or audio." +covers: [Translate Audio Files] +--- + + + **Closed alpha.** This API may change without notice and is only available to select DeepL customers. See [alpha and beta features](/docs/resources/alpha-and-beta-features) for details. To request access, contact your customer success manager. + + +The Voice Translate Job API translates pre-recorded audio files asynchronously. You submit a file, poll until each target is ready, then download the results. One source file can produce multiple outputs in one job: plain text transcripts, SRT subtitles, and translated speech audio in any combination. + +This guide walks through all four steps with a concrete example: an English MP3 podcast episode translated into German text and Spanish audio. + +## Overview + +- The API separates job creation from file upload and uses pre-signed URLs for direct object storage access +- Job targets are tracked independently, each transitioning through its own status values +- Per-target results must be checked individually; partial failures do not affect other targets in the same job + +## Prerequisites + +- A DeepL API key with Voice Translate Job access +- An audio file to translate (see [supported source formats](/api-reference/jobs-voice-translate/reference#supported-source-audio-formats) and [limits](/api-reference/jobs-voice-translate/reference#limits)) +- `curl` for the HTTP requests; `wget` or any HTTP client for the download + +## Create a job + +Send a POST request to `/v1/jobs/voice/translate` with the source file metadata and a list of targets. The API returns an upload URL for your audio file; it does not accept the file directly. + +```bash +curl https://api.deepl.com/v1/jobs/voice/translate \ + --request POST \ + --header "Authorization: DeepL-Auth-Key YOUR_AUTH_KEY" \ + --header "Content-Type: application/json" \ + --data '{ + "source_file": { + "name": "podcast-episode-42.mp3", + "content_type": "audio/mpeg", + "content_length": 15728640 + }, + "parameters": { + "source_language": "en" + }, + "targets": [ + { "language": "de", "type": "text/plain" }, + { "language": "es", "type": "audio/pcm;encoding=s16le;rate=16000" } + ] + }' +``` + +`content_length` must be the exact byte size of the file. The API uses this to pre-allocate the upload URL and rejects uploads that don't match. + +The response contains the job ID and a pre-signed upload URL: + +```json +{ + "job_id": "a74d88fb-ed2a-4943-a664-a4512398b994", + "upload_url": "https://assets.deepl.com/collections/a74d88fb-ed2a-4943-a664-a4512398b994/assets/b1c2d3e4-f5a6-7890-abcd-ef1234567890", + "signature": "eyJhbGciOiJIUzI1NiIs..." +} +``` + +Save the `job_id` and `upload_url`. You have 5 minutes to complete the upload before the URL expires. + + + API Free users should use `https://api-free.deepl.com` instead of `https://api.deepl.com`. + + +## Upload the source file + +PUT your audio file directly to the `upload_url` from the previous step. This is a direct upload to object storage, not to the DeepL API, so no authorization header is needed. + +```bash +curl "https://assets.deepl.com/collections/a74d88fb-ed2a-4943-a664-a4512398b994/assets/b1c2d3e4-f5a6-7890-abcd-ef1234567890" \ + --request PUT \ + --header "Content-Type: audio/mpeg" \ + --data-binary @podcast-episode-42.mp3 +``` + +The `Content-Type` header must match the `content_type` you declared when creating the job. + +A successful upload returns HTTP 200 with an empty body. Processing starts automatically once the upload is complete. + + + You must upload within 5 minutes of creating the job. If the upload URL expires, create a new job. + + +## Poll for status + +Check the job status by sending a GET request to `/v1/jobs/voice/translate/{job_id}`. Results for each target are returned in the same order as the targets in your create request. + +```bash +curl "https://api.deepl.com/v1/jobs/voice/translate/a74d88fb-ed2a-4943-a664-a4512398b994" \ + --header "Authorization: DeepL-Auth-Key YOUR_AUTH_KEY" +``` + +While processing is still underway, targets will be in `processing` status: + +```json +{ + "job_id": "a74d88fb-ed2a-4943-a664-a4512398b994", + "operation": "translate", + "product": "voice", + "source_file": { + "name": "podcast-episode-42.mp3", + "content_type": "audio/mpeg", + "content_length": 15728640 + }, + "parameters": { "source_language": "en" }, + "targets": [ + { "language": "de", "type": "text/plain" }, + { "language": "es", "type": "audio/pcm;encoding=s16le;rate=16000" } + ], + "results": [ + { "status": "processing" }, + { "status": "processing" } + ], + "created_at": "2026-10-01T01:03:03.444Z", + "updated_at": "2026-10-01T04:03:03.333Z" +} +``` + +Poll every 10-30 seconds until each target reaches `complete` or `failed`. See the [status lifecycle reference](/api-reference/jobs-voice-translate/reference) for the full set of intermediate statuses. When a target reaches `complete`, its result object includes a `download_url`: + +```json +{ + "job_id": "a74d88fb-ed2a-4943-a664-a4512398b994", + "results": [ + { + "status": "complete", + "download_url": "https://assets.deepl.com/collections/a74d88fb/assets/c3d4e5f6", + "signature": "eyJhbGciOiJIUzI1NiIs..." + }, + { + "status": "failed", + "error": { "message": "processing failed" } + } + ] +} +``` + +Targets can fail independently. A failed target does not affect other targets in the same job. Check each result's `status` field before attempting to download. + +## Download results + +Fetch each completed result from its `download_url`. Like the upload, this is a direct request to object storage, so no authorization header is needed (access is controlled by the pre-signed URL itself). + +```bash +curl "https://assets.deepl.com/collections/a74d88fb/assets/c3d4e5f6" \ + --output translation-de.txt +``` + +For audio targets, save the file with an extension matching the format you requested (`.pcm`, `.mp3`, `.wav`, etc.). + + + Download results within 1 hour of the upload completing. After that window, results expire and the job returns 404. Once all results are downloaded, assets are also marked for deletion. + + +## Full example script + +This Python script runs all four steps end to end. Replace the placeholder values with your own. + + + This is a minimal example. It reads the full audio file into memory, which is not suitable for large files. Production code should open the file in streaming mode rather than loading it all at once. + + +```python translate_audio.py +import os +import time +import requests + +AUTH_KEY = "YOUR_AUTH_KEY" +BASE_URL = "https://api.deepl.com" +AUDIO_FILE = "podcast-episode-42.mp3" + +def create_job(file_path: str) -> dict: + file_size = os.path.getsize(file_path) + + response = requests.post( + f"{BASE_URL}/v1/jobs/voice/translate", + headers={"Authorization": f"DeepL-Auth-Key {AUTH_KEY}"}, + json={ + "source_file": { + "name": file_path, + "content_type": "audio/mpeg", + "content_length": file_size, + }, + "parameters": {"source_language": "en"}, + "targets": [ + {"language": "de", "type": "text/plain"}, + {"language": "es", "type": "audio/pcm;encoding=s16le;rate=16000"}, + ], + }, + ) + response.raise_for_status() + return response.json() + + +def upload_file(upload_url: str, file_path: str) -> None: + with open(file_path, "rb") as f: + response = requests.put( + upload_url, + headers={"Content-Type": "audio/mpeg"}, + data=f, + ) + response.raise_for_status() + + +def poll_until_done(job_id: str, poll_interval: int = 15) -> list: + while True: + response = requests.get( + f"{BASE_URL}/v1/jobs/voice/translate/{job_id}", + headers={"Authorization": f"DeepL-Auth-Key {AUTH_KEY}"}, + ) + response.raise_for_status() + data = response.json() + results = data["results"] + + # Check whether all targets have reached a terminal state + if all(r["status"] in ("complete", "failed") for r in results): + return results + + print(f"Status: {[r['status'] for r in results]}, polling again in {poll_interval}s") + time.sleep(poll_interval) + + +def download_results(results: list, targets: list) -> None: + extensions = {"text/plain": "txt", "audio/pcm;encoding=s16le;rate=16000": "pcm"} + + for i, result in enumerate(results): + if result["status"] != "complete": + print(f"Target {i} failed: {result.get('error', {}).get('message')}") + continue + + target = targets[i] + ext = extensions.get(target["type"], "bin") + filename = f"translation-{target['language']}.{ext}" + + url = result.get("download_url") + if not url: + print(f"Target {i} missing download_url") + continue + content = requests.get(url).content + with open(filename, "wb") as f: + f.write(content) + print(f"Saved {filename}") + + +job_response = create_job(AUDIO_FILE) +job_id = job_response["job_id"] +upload_url = job_response["upload_url"] +print(f"Job created: {job_id}") + +upload_file(upload_url, AUDIO_FILE) +print("Upload complete") + +results = poll_until_done(job_id) +download_results(results, job_response["targets"]) +``` + +## Next steps + +- Check the [status lifecycle, limits, and supported formats](/api-reference/jobs-voice-translate/reference) for the full list of input and output audio types +- For live audio, see the [Real-Time Voice Quickstart](/docs/voice/real-time-voice-quickstart) +- Review the [Create Job](/api-reference/jobs-voice-translate/create-voice-translate-job) and [Get Job Status](/api-reference/jobs-voice-translate/get-voice-translate-job-status) endpoint references for complete request and response schemas \ No newline at end of file