# AI Subtitle & Document Translator — SRT, VTT, DOCX (`sian.agency/ai-subtitle-and-document-translator`) Actor

Translate SRT and VTT subtitles into 110 languages with every timestamp preserved byte-for-byte, plus plain text and DOCX/PPTX documents that keep their original layout. Two engines: a fast affordable one and a professional high-accuracy one. Bulk input, per-character billing.

- **URL**: https://apify.com/sian.agency/ai-subtitle-and-document-translator.md
- **Developed by:** [SIÁN OÜ](https://apify.com/sian.agency) (community)
- **Categories:** AI, Videos, Automation
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 1 bookmarks
- **User rating**: No ratings yet

## Pricing

from $10.80 / 1,000 subtitles translated (fast engine)s

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.
Since this Actor supports Apify Store discounts, the price gets lower the higher subscription plan you have.

Learn more: https://docs.apify.com/platform/actors/running/actors-in-store#pay-per-event

## What's an Apify Actor?

Actors are web data automations that power AI and operations. They run on the Apify platform to scrape websites, process data, connect APIs, and automate workflows.
In Batch mode, an Actor accepts a well-defined JSON input, performs an action which can take anything from a few seconds to a few hours,
and optionally produces a well-defined JSON output, datasets with results, or files in key-value store.
In Standby mode, an Actor provides a web server which can be used as a website, API, or an MCP server.
Actors are written with capital "A".

## How to integrate an Actor?

If asked about integration, you help developers integrate Actors into their projects.
You adapt to their stack and deliver integrations that are safe, well-documented, and production-ready.
The best way to integrate Actors is as follows.

- **AI agents and MCP clients** — the [Apify MCP server](https://docs.apify.com/integrations/mcp.md) at `https://mcp.apify.com` (remote, streamable HTTP, OAuth on first use).
- **Agentic workflows and local Actor development** — [Agent Skills](https://apify.com/.well-known/agent-skills/index.json) with the [Apify CLI](https://docs.apify.com/cli/docs.md): `npm install -g apify-cli`, then `apify login`.
- **JavaScript/TypeScript projects** — the official [JS/TS client](https://docs.apify.com/api/client/js/docs.md): `npm install apify-client`.
- **Python projects** — the official [Python client](https://docs.apify.com/api/client/python/docs.md): `pip install apify-client`.
- **Any other language** — the [REST API](https://docs.apify.com/api/v2.md).

For usage examples, see the [API](#api) section below.

For more details, see Apify documentation as [Markdown index](https://docs.apify.com/llms.txt) and [Markdown full-text](https://docs.apify.com/llms-full.txt).

# README

## AI Subtitle & Document Translator — SRT, VTT, DOCX

Translate subtitle files, plain text and office documents into **110 languages** — without ever touching a timestamp.

Most translation tools treat an `.srt` file as a wall of text. They re-generate the timing track on the way out, and you find out three episodes later that cue 47 drifted by 200 milliseconds. This actor never regenerates a timestamp it was handed. Timings, cue numbers, blank lines, byte-order marks and Windows line endings are copied through as raw bytes, and every file is re-parsed and compared against its source before it is delivered. A file whose timings did not survive is discarded rather than shipped — and you are not charged for it.

***

### What it does

| Mode | Input | Output |
|---|---|---|
| **Subtitles** | `.srt` and `.vtt` files, by URL or upload | Translated subtitle files, timings byte-identical |
| **Text** | One string, or hundreds | Translated strings, repeats charged once |
| **Documents** | `.docx` and `.pptx`, by URL or upload | Translated documents with layout, styles, tables and images intact |

Every source item is translated into every language you pick, and every combination is one row in the dataset with its own download link.

***

### Why the subtitle mode is different

**Timings are never recalculated.** They are opaque strings that pass straight through. 100-hour timestamps, `,` and `.` separators, and cue positioning coordinates all survive untouched.

**A cue is never silently dropped.** Language models skip, merge and reorder list items. This actor matches every returned translation to an explicit cue id — never to its position in an array — retries anything missing, and as a last resort keeps the cue's original text and reports it in `partialCues`. Your file always has the same number of cues it started with.

**WebVTT structure is respected.** The `WEBVTT` header, `NOTE` comments, `STYLE` blocks (which are CSS — translating them corrupts the file) and `REGION` definitions pass through untranslated and unbilled. Cue identifiers and cue settings such as `line:0 position:20% align:start` are re-emitted exactly.

**Formatting survives.** Italics, bold and colour tags stay wrapped around the same words they wrapped in the source. Positioning overrides like `{\an8}`, voice spans like `<v Roger Bingham>` and class spans like `<c.loud>` are lifted out before translation and restored afterwards.

**Neighbouring cues are used as free context.** Two cues either side of each batch are sent to the engine as context — not translated, not billed. That is what fixes the pronoun and gender agreement that breaks when a sentence spans two cues.

**Lines are re-wrapped, not left ragged.** German runs about 30% longer than English. `lineWrap: preserve` keeps the source's line count and only adds a line when one would exceed your character limit (42 by default — the Netflix and BBC readability standard).

**Overlapping cues are reported, never "fixed".** If the source has out-of-order or overlapping timings, you get an `overlappingCues` count and the file exactly as authored.

***

### Two engines

| | **Fast** | **Professional** |
|---|---|---|
| Best for | back-catalogues, drafts, high volume | published output, client work, documents |
| Cost per 1,000 characters | $0.008 text · $0.012 subtitles | $0.12 text · $0.15 subtitles |
| Formality control | applied through instructions, every language | applied natively on the 15 languages that distinguish it |
| Documents | — | `.docx` and `.pptx` |
| Free Apify plans | ✅ | — |

Pick **Fast** when you are working through a hundred hours of archive. Pick **Professional** when the output goes in front of a customer.

***

### Billing you can check yourself

Charging is per **1,000 source characters**, per target language — and the characters are banked across the whole run rather than rounded up per item.

That distinction is the whole point. Translating 500 interface labels of 40 characters each is 20,000 characters of work. Rounding each item up to a whole 1,000 would bill **500 events**. This actor bills **20**, plus at most one rounding event per language for the leftover. Every row carries `billedCharacters` and `billedEvents`, and the HTML run report breaks the total down per event and per language.

**Repeats are charged once.** A recurring station ident, a repeated UI string, a chorus line — translated once, delivered everywhere it appeared, billed once.

**Nothing but cue text is counted.** Timestamps, cue numbers, the `WEBVTT` header, `NOTE`/`STYLE`/`REGION` blocks and the free context window are never billed.

**`maxSpendUsd` is a real pre-flight brake.** The run is priced before the first charge and aborts with an explanation if the estimate exceeds your cap. You are not charged for a run that stops there.

#### Documents cost differently — and the row says so

Office documents are billed by the upstream engine with a **50,000-character minimum per file, per language**, whatever the real length. A two-page contract and a fifty-page contract both cost the same $2.49. Anything above 50,000 characters is charged as overage.

Every document row reports `minimumApplied`, the authoritative `billedCharacters` and the `overageEvents` charged, so the number on your invoice is one you can reconstruct.

***

### Input

| Field | Notes |
|---|---|
| `mode` | `text` · `subtitles` · `document` |
| `engine` | `ai` (fast) · `deepl` (professional, paying plans) |
| `targetLanguages` | 110 codes. Each one is a separate translation and a separate charge |
| `sourceLanguage` | `auto` by default |
| `text` / `texts` | text mode |
| `subtitleUrls` / `subtitleFiles` | `.srt` and `.vtt`, links or uploads |
| `documentUrls` / `documentFiles` | `.docx` and `.pptx`, up to 30 MB |
| `outputFormat` | `same` · `srt` · `vtt` — conversion changes the decimal separator, never a digit |
| `lineWrap` | `preserve` · `single` · `none` |
| `maxCharsPerLine` | default 42 |
| `formality` | `default` · `more` · `less` |
| `preserveTags` | on by default |
| `maxSpendUsd` | pre-flight cost ceiling |

#### Example

```json
{
  "mode": "subtitles",
  "engine": "ai",
  "targetLanguages": ["DE", "ES", "PT-BR", "JA"],
  "sourceLanguage": "EN",
  "subtitleUrls": ["https://example.com/episode-04.srt"],
  "lineWrap": "preserve",
  "maxCharsPerLine": 42,
  "maxSpendUsd": 5.00
}
```

***

### Output

One row per source item per target language:

- `translatedText` for text mode, or `subtitleUrl` / `documentUrl` for a downloadable file
- `subtitleText` inline while the file stays under 100 KB
- `cueCount`, `translatedCueCount`, `partialCues`, `overlappingCues`
- `timingsPreserved` and `tagsPreserved` — the integrity result for that exact file
- `sourceCharacters`, `billedCharacters`, `billedEvents`

Plus `report.html` in the key-value store: the run summary with the full billing breakdown, written even if the run fails.

***

### Free plan limits

Free Apify accounts get the fast engine, one target language, 5 items and 20,000 source characters per run. The professional engine and document mode require a paying plan.

***

### Works well with

Subtitle mode takes exactly what these actors produce:

- [Transcribe Podcast to Text](https://apify.com/sian.agency/transcribe-podcast-to-text?fpr=sian) — generates SRT and VTT from audio
- [TikTok AI Transcript Extractor](https://apify.com/sian.agency/tiktok-ai-transcript-extractor?fpr=sian)
- [Instagram AI Transcript Extractor](https://apify.com/sian.agency/instagram-ai-transcript-extractor?fpr=sian)
- [Best YouTube Video Downloader](https://apify.com/sian.agency/best-youtube-video-downloader?fpr=sian)

Transcribe once, then translate the timed output into every market you sell into.

***

### Support

- [SIÁN Agency](https://www.sian-agency.online)
- [More actors](https://apify.com/sian.agency?fpr=sian)
- [Telegram support](https://t.me/+vyh1sRE08sAxMGRi)

# Actor input Schema

## `mode` (type: `string`):

text — plain strings, product copy, UI labels, transcripts. subtitles — .srt / .vtt files with every timestamp preserved byte-for-byte. document — .docx / .pptx files that come back with their original layout, styles and images intact (professional engine only).

## `engine` (type: `string`):

Fast — a modern language model. Cheap enough for whole back-catalogues, and the only engine free plans can use. Professional — the highest-accuracy engine available, with native formality control and document support. Paying plans only.

## `targetLanguages` (type: `array`):

Every language you pick is a separate translation and is charged separately. Free runs translate into one language.

## `sourceLanguage` (type: `string`):

Leave on automatic detection unless the source is genuinely ambiguous (very short strings, mixed-language files).

## `text` (type: `string`):

A single piece of text to translate. Used when mode is text.

## `texts` (type: `array`):

Several strings to translate in one run. Identical strings are translated once and charged once. Used when mode is text.

## `subtitleUrls` (type: `array`):

Direct links to .srt or .vtt files. Every timestamp, cue index, blank line and byte-order mark comes back exactly as it went in.

## `subtitleFiles` (type: `array`):

Upload .srt or .vtt files instead of linking them.

## `outputFormat` (type: `string`):

same keeps the input format. Choosing srt or vtt converts the file: only the decimal separator changes, never the digits of a timestamp.

## `lineWrap` (type: `string`):

preserve keeps the source line count, adding a line only when one would exceed the character limit below. single collapses each cue to one line. none leaves the engine output untouched.

## `maxCharsPerLine` (type: `integer`):

Readability limit used when line wrapping is set to preserve. 42 is the Netflix and BBC subtitle standard.

## `documentUrls` (type: `array`):

Direct links to .docx or .pptx files. Requires the professional engine and a paying plan. PDF and XLSX are not supported.

## `documentFiles` (type: `array`):

Upload .docx or .pptx files instead of linking them. Maximum 30 MB per file.

## `formality` (type: `string`):

Register of the translation. The professional engine applies this natively on the 15 languages that distinguish formality; the fast engine applies it through its instructions on every language.

## `preserveTags` (type: `boolean`):

Keeps italics, bold, colour tags, positioning overrides and voice spans around the same words they wrapped in the source.

## `maxSpendUsd` (type: `number`):

Safety cap. The run is priced up front and aborts before anything is charged if the estimate exceeds this. Leave empty for no cap.

## Actor input object example

```json
{
  "mode": "text",
  "engine": "ai",
  "targetLanguages": [
    "ES"
  ],
  "sourceLanguage": "auto",
  "texts": [],
  "subtitleUrls": [],
  "subtitleFiles": [],
  "outputFormat": "same",
  "lineWrap": "preserve",
  "maxCharsPerLine": 42,
  "documentUrls": [],
  "documentFiles": [],
  "formality": "default",
  "preserveTags": true
}
```

# Actor output Schema

## `results` (type: `string`):

One row per source item per target language, with the translated text, the download link, the character count that was billed and the timing-integrity result.

## `files` (type: `string`):

Every translated subtitle and document, ready to download.

## `htmlReport` (type: `string`):

HTML summary of the run, including the full billing breakdown per event and language.

# API

You can run this Actor programmatically using our API. Below are code examples in JavaScript, Python, and CLI, as well as the OpenAPI specification and MCP server setup.

## JavaScript example

```javascript
import { ApifyClient } from 'apify-client';

// Initialize the ApifyClient with your Apify API token
// Replace the '<YOUR_API_TOKEN>' with your token
const client = new ApifyClient({
    token: '<YOUR_API_TOKEN>',
});

// Prepare Actor input
const input = {
    "mode": "text",
    "engine": "ai",
    "targetLanguages": [
        "ES"
    ],
    "sourceLanguage": "auto",
    "outputFormat": "same",
    "lineWrap": "preserve",
    "maxCharsPerLine": 42,
    "formality": "default"
};

// Run the Actor and wait for it to finish
const run = await client.actor("sian.agency/ai-subtitle-and-document-translator").call(input);

// Fetch and print Actor results from the run's dataset (if any)
console.log('Results from dataset');
console.log(`💾 Check your data here: https://console.apify.com/storage/datasets/${run.defaultDatasetId}`);
const { items } = await client.dataset(run.defaultDatasetId).listItems();
items.forEach((item) => {
    console.dir(item);
});

// 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/js/docs

```

## Python example

```python
from apify_client import ApifyClient

# Initialize the ApifyClient with your Apify API token
# Replace '<YOUR_API_TOKEN>' with your token.
client = ApifyClient("<YOUR_API_TOKEN>")

# Prepare the Actor input
run_input = {
    "mode": "text",
    "engine": "ai",
    "targetLanguages": ["ES"],
    "sourceLanguage": "auto",
    "outputFormat": "same",
    "lineWrap": "preserve",
    "maxCharsPerLine": 42,
    "formality": "default",
}

# Run the Actor and wait for it to finish
run = client.actor("sian.agency/ai-subtitle-and-document-translator").call(run_input=run_input)

# Fetch and print Actor results from the run's dataset (if there are any)
print(f"💾 Check your data here: https://console.apify.com/storage/datasets/{run.default_dataset_id}")
for item in client.dataset(run.default_dataset_id).iterate_items():
    print(item)

# 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/python/docs/quick-start

```

## CLI example

```bash
echo '{
  "mode": "text",
  "engine": "ai",
  "targetLanguages": [
    "ES"
  ],
  "sourceLanguage": "auto",
  "outputFormat": "same",
  "lineWrap": "preserve",
  "maxCharsPerLine": 42,
  "formality": "default"
}' |
apify call sian.agency/ai-subtitle-and-document-translator --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,sian.agency/ai-subtitle-and-document-translator"
        }
    }
}

```

The hosted server signs you in with OAuth on first connect, so no API token belongs in this config. Clients without OAuth support can send an `Authorization: Bearer <APIFY_API_TOKEN>` header instead, using a token from API & Integrations in Apify Console (https://console.apify.com/settings/integrations).

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/actors/rdiVKQQ1eF8aTr0mh/builds/CdGJAUpAtDfpa5Mp2/openapi.json
