---
title: "DeepL bulk translation: limits, file support, and alternatives"
description: "What DeepL supports for bulk translation: file format caps, the 50,000-character minimum fee, quality limits on structured files, and alternatives."
date: 2026-10-11
language: en
canonical: https://ai-glot.com/blog/deepl-bulk-translation
source: AI Glot blog
---
**DeepL is the first tool most teams try when they have a folder of files to translate, and for a single Word document or a few paragraphs of European prose, it earns that reputation.** The friction starts when you move from translating a document to running a bulk localization workflow: product catalogues in CSV or Excel, app language files across ten locales, Markdown documentation with frontmatter, or partially translated spreadsheets where only the new rows need work.

I built AI Glot after hitting these exact walls myself. At first, I assumed machine translation only needed a wrapper around its API. Once we looked closely at [DeepL's official developer documentation](https://developers.deepl.com/docs/best-practices/document-translations) and talked to teams migrating their batches over, two separate problems stood out: **hard technical and billing limits on bulk files, and a string-by-string translation mechanism that loses context across structured data.**

## DeepL Translator vs. DeepL API: two separate products

When someone searches for "DeepL bulk translation," they usually have one of two workflows in mind: dragging a batch of files into the DeepL app, or wiring a script up to the DeepL API. **Those two routes sit on separate subscriptions and do not share quotas.**

*Illustration: DeepL splits bulk translation across two separate subscriptions: the web and desktop app caps monthly file uploads, while the API charges per character with a 50,000-character floor on office documents.*

On the web and desktop side, DeepL's paid plans (recently renamed from Starter, Advanced, and Ultimate to **Individual, Team, and Business**) enforce strict monthly file upload quotas per user:

* **Individual**: 3 file translations per month (up to 300,000 characters per month).
* **Team**: 20 file translations per month (up to 1,000,000 characters per month).
* **Business**: 100 file translations per month.

Because each target language counts as a separate file translation, **localizing 5 documents into 6 languages consumes 30 file translations**, which immediately exceeds a Team seat's monthly allowance.

To remove the monthly file counter, you have to buy a separate **DeepL API Pro** subscription (\$5.49 per month base fee plus \$25.00 per million characters, or €4.99 plus €20.00 per million characters in Europe). The API gives you two endpoints:

1. **`POST /v2/translate`**: accepts an array of raw text strings (up to 50 strings per call, with a hard **128 KiB total request body limit**). You have to parse your own files, strip the structure, batch the strings, and rebuild the file afterwards.
2. **`POST /v2/document`**: accepts a whole file for one target language, queues it asynchronously, and returns a translated file you poll and download.

## What files DeepL actually supports in bulk (and what is missing or in beta)

If you use `/v2/document` so you do not have to write a custom parser for every format, your pipeline is bound by [DeepL's per-format size limits](https://developers.deepl.com/docs/resources/usage-limits) and its [alpha and beta feature rules](https://developers.deepl.com/docs/resources/alpha-and-beta-features).

| Category | Formats in `/v2/document` | Paid API size cap | Important caveats from DeepL's docs |
| :--- | :--- | :--- | :--- |
| **Production office & publishing** | `.docx`, `.doc`, `.pptx`, `.pdf`, `.xlsx`, `.idml`, `.mif` | 100 MB (`.docx`, `.pptx`, `.pdf`) or 30 MB (`.xlsx`, `.idml`, `.mif`), up to 1M chars | `.docx`, `.doc`, `.pptx`, `.xlsx`, and `.pdf` each bill a **minimum of 50,000 characters** per upload. |
| **Production web, data & subtitles** | `.xlf` / `.xliff` (1.2, 2.0, 2.1), `.xml`, `.html`, `.dita`, `.txt`, `.json`, `.srt` | 10 MB (`.xliff`, `.xml`), 5 MB (`.html`, `.dita`), **1 MB** (`.json`, `.txt`), **150 KB** (`.srt`) | Existing `<target>` values in XLIFF are overwritten. JSON is capped at 1 MB and SRT at 150 KB even on paid plans. |
| **Beta only (not for production)** | `.md`, `.yaml` / `.yml`, `.properties`, `.strings`, `.resx`, `.vtt`, `.xlsm`, `.odt`, `.rtf`, `.zip` (SCORM only) | 1 MB for code/docs, 150 KB for `.vtt`, 30 MB for `.xlsm` / `.odt` / `.rtf`, 100 MB for SCORM `.zip` | Marked by DeepL as **not intended for production** and subject to breaking changes without notice. |
| **Unsupported in `/v2/document`** | `.csv`, `.tsv`, `.po` / `.pot`, `.arb`, `.xcstrings`, `.stringsdict`, `.ts` (Qt), `.toml`, `.ini`, `.jsonl`, `.ass` / `.ssa`, `.lrc`, standard `.zip` folders | Not accepted | CSV is only accepted for uploading 2-column glossaries. Non-SCORM `.zip` archives fail with `400 Invalid or missing file extension`. |

Four details in that table catch engineering and localization teams off guard:

* **No native CSV or TSV document translation.** If your e-commerce store, PIM, or CMS exports a [CSV file](/file-formats/csv-translation), `/v2/document` rejects it. You either convert every CSV into `.xlsx` by hand (which triggers the 50,000-character minimum charge per file and translates every column indiscriminately) or build your own CSV parser around `/v2/translate`.
* **1 MB and 150 KB ceilings on developer and subtitle files.** Even on a paid API Pro plan, `.json`, `.yaml`, `.md`, `.properties`, `.strings`, and `.resx` files are capped at **1 MB**, and [`.srt` and `.vtt` subtitle files](/file-formats/srt-translation) are capped at **150 KB**. A single feature-length subtitle file or a monolithic locale JSON regularly exceeds those limits.
* **Markdown and localization files are still in beta, with a known frontmatter bug.** DeepL's documentation explicitly warns that beta features should not be used in production pipelines. More concretely, [DeepL's document guide notes a known bug on `.md` files](https://developers.deepl.com/docs/best-practices/document-translations): the `---` delimiters that open and close YAML frontmatter blocks are dropped from the translated file, fusing your page metadata into the opening paragraph. If you run an Astro, Next.js, Hugo, or Docusaurus site, that breaks the build on every translated page.
* **Standard ZIP folders are rejected.** The `.zip` extension in `/v2/document` only accepts e-learning SCORM packages containing an `imsmanifest.xml` at the root. Uploading a normal [ZIP archive of localization files](/file-formats/zip-translation) returns a `400` error. And core app formats like [gettext `.po`](/file-formats/po-translation), [Flutter `.arb`](/file-formats/arb-translation), and [Xcode `.xcstrings` String Catalogs](/file-formats/xcstrings-translation) are not supported at all.

## The 50,000-character billing floor on Excel, Word, PowerPoint, and PDF

At \$25 per million characters, DeepL's headline API rate looks like \$0.025 per thousand characters. That math holds on `/v2/translate`, and it breaks on `/v2/document` whenever you process batches of office files.

DeepL's documentation states two billing rules for `.docx`, `.doc`, `.pptx`, `.xlsx`, and `.pdf` uploads:

1. **Every submitted document is billed a minimum of 50,000 characters**, no matter how few characters the file actually contains.
2. **All content inside the uploaded file counts toward billed characters**, including content that was not actually translated.

Because `/v2/document` translates one file into one target language per request, **every target language multiplies that 50,000-character floor**.

*Illustration: How DeepL's 50,000-character minimum per office document multiplies the bill when you translate small spreadsheets or multiple target languages.*

Consider an illustrative scenario: you have **20 small Excel product sheets** averaging 2,500 characters each (around 400 words per file, or 50,000 characters in total across all 20 files), and you need them in **5 target languages**.

* In reality, you are translating **250,000 characters** across those five languages. At \$25 per million characters, you would expect to pay **\$6.25**.
* Because `/v2/document` requires 100 separate `.xlsx` uploads (20 files × 5 languages) and enforces a 50,000-character floor on each one, DeepL bills **5,000,000 characters**, which comes out to **\$125.00** (a 20x multiplier over the raw character rate).
* Even if your `.xlsx` file is larger than 50,000 characters, DeepL counts every character in the workbook toward the bill, including SKU columns, URLs, internal notes, and rows that were already translated last month.

## Why whole-file translation breaks spreadsheet and localization workflows

Cost is only half of the problem with whole-file uploads. The deeper issue is that **`/v2/document` has no concept of programmable scope**. When you hand it a structured file, you cannot tell it which parts are translatable content and which parts are data structure.

*Illustration: Whole-file document translation treats every text cell as prose: URL handles and headers get translated alongside product titles, instead of filling only the empty target column.*

In real production files, four workflow gaps show up immediately:

1. **No column selection in Excel.** Uploading [an Excel workbook](/blog/translate-excel-file-another-language) to DeepL translates every text cell across every worksheet. Product handles, category slugs, vendor names, and status flags get translated alongside product descriptions. DeepL's own documentation notes that `VLOOKUP`, `MATCH`, and `INDEX` formulas that match on string literals break when the referenced table is translated.
2. **No incremental translation for missing rows.** Most catalogues and localization files are partly translated: 3,800 rows were finished in March, and 200 new products arrived this week. DeepL cannot [translate only the missing rows in a spreadsheet](/blog/translate-only-missing-rows-csv-excel), and in `.xliff` files its documentation warns that **existing `<target>` values are overwritten**, requiring you to strip already-translated `<trans-unit>` nodes out of the XML before uploading and merge them back afterwards.
3. **One language per file upload.** If your spreadsheet holds `en`, `fr`, `de`, and `es` as side-by-side columns in one file, DeepL cannot populate the target columns in place. It returns a separate file per language with the source cells overwritten.
4. **No reviewable plan before spending.** A `POST /v2/document` call starts translating and billing immediately. There is no dry-run step that shows you which fields were matched, how many words are in scope, and what the job will cost before you approve it.

## Where DeepL's quality hits a ceiling on real content

Nobody who has used DeepL would claim that it translates a standalone sentence poorly. On a paragraph of general French, German, or Spanish prose, its neural engine is fast and fluent.

Yet customers regularly come to us after running both DeepL and AI Glot on their actual files because **DeepL fell below the quality bar they needed to publish on their site, while AI Glot cleared it.** That is customer experience rather than a formal benchmark (we have not run a synthetic benchmark against DeepL, and you should distrust any vendor that invents a percentage score), and the reason it happens comes down to the **mechanism** of how a batch is translated.

### 1. Isolated strings vs. document and field awareness

When you build a script around DeepL's `/v2/translate` endpoint to avoid breaking your CSV or JSON structure, you send an array of up to 50 strings per request. DeepL's OpenAPI specification states the limitation directly: **"Each text in the array is translated independently, texts do not share context with each other."**

When a translator sees `"Light"` in an isolated string array, it has no way to know whether the file is a lighting catalogue, a dietary supplement table, or a theme toggle in a SaaS app's settings menu. Even if you pass DeepL's optional `context` parameter on `/v2/translate` (which is not available on `/v2/document`), [DeepL's guide on the `context` parameter](https://developers.deepl.com/docs/learning-how-tos/examples-and-guides/how-to-use-context-parameter) explicitly warns: *"Many users try to use `context` like ChatGPT system prompts. This does not work reliably... Keep context pure text from the same document, not instructions."*

### 2. Term substitution vs. a glossary carried as meaning

DeepL supports glossaries (`v3/glossaries`) across 26 root languages, capped at 1,024 UTF-8 bytes per entry. While it adjusts basic noun and verb inflections, **a machine translation glossary is fundamentally a 1-to-1 lookup table**: wherever source term A appears, swap in target term B.

*Illustration: A machine translator's glossary swaps the word. A glossary read as meaning fixes the term and writes the sentence around it.*

In real localization work, [how a glossary is applied](/blog/how-translation-glossaries-improve-csv-localization) determines whether a sentence sounds natural:

* A 1-to-1 lookup table cannot understand **why** a term is locked, or apply a conditional rule like *"Keep 'Pro' and 'Workspace' in English when referring to our pricing plans or UI navigation, but translate them normally in general sentences."*
* DeepL recently added `custom_instructions` inside its `v3/style_rules` API (available on Pro and Business plans for a subset of target languages), but each style rule is capped at **a maximum of 10 custom instructions of 300 characters each**, applied sentence by sentence. As DeepL's own style rules guide notes, this makes them unreliable for rules that depend on broader document structure.

## DeepL vs. alternatives for bulk translation

No single tool wins every translation job. Here is how DeepL compares with the main alternatives when you have real volume to move:

| Tool | Best for | File formats & scope | Where it stops working |
| :--- | :--- | :--- | :--- |
| **DeepL** (Translator & API) | Individual office files (`.docx`, `.pptx`) and low-latency raw text API calls in European languages | 14 prod formats + 10 beta in `/v2/document`. Whole-file only, 1 language per upload | No CSV, PO, ARB, `.xcstrings`, or general ZIPs. 50k-char minimum fee on office files. Overwrites XLIFF targets. Drops Markdown `---` frontmatter. |
| **AI Glot** | Bulk structured files: catalogues, spreadsheets, subtitles, Markdown docs, and [app language files](/blog/how-to-translate-app-language-files-with-ai) | **35+ formats** natively (CSV, Excel, JSON, XLIFF, PO, ARB, `.xcstrings`, Markdown, SRT, DOCX, PDF, ZIP of up to 200 files) | Not a real-time chat translator or a human agency marketplace. |
| **TMS platforms** (Lokalise, Crowdin, Phrase) | Teams with dedicated localization managers, continuous Git connectors, and in-editor human review | Broad localization format support via project importers | Heavy project setup before translating a single file; seat and hosted-key pricing gets expensive for periodic file batches. |
| **ChatGPT / Claude** (chat window) | Translating 20 lines of copy, an email, or brainstorming localized ad hooks | Copy-paste or small attachments in chat | Output token limits truncate files past a few hundred rows, keys and CSV commas drift, and rules are forgotten mid-file. |
| **Weglot** | Turning a live website multilingual in minutes via proxy/JS without touching source files | Translates live HTML pages on the fly (uses DeepL/Google under the hood) | Proxy lock-in and [steep word-tier pricing](/blog/weglot-pricing); does not translate your offline CSVs, app files, or documentation repos. |

## How a scoped bulk workflow runs in AI Glot

When you move a bulk batch from DeepL to AI Glot, three things change in the workflow: **you do not convert your file first, you scope the job in plain English, and you read the plan before spending a cent.**

**1. Upload the file as it is.** Drop in a [CSV export](/file-formats/csv-translation), an [Excel workbook](/file-formats/excel-translation), a [JSON locale file](/file-formats/json-translation), a [Markdown article](/file-formats/markdown-translation) (with its `---` YAML frontmatter kept intact), an [XLIFF export](/file-formats/xliff-translation), or a [ZIP archive](/file-formats/zip-translation) of up to 200 files.

**2. Write what needs to happen in one sentence.** Instead of writing a Python script to filter rows and strip columns before calling an API, you state the scope in plain English:

```
Translate title_en and body_html into French and German.
Only translate rows where the target cell is empty.
Leave sku, handle, and vendor untouched.
```

*Illustration: You describe the job in plain English. AI Glot turns it into a plan you can read and correct before anything runs.*

AI Glot compiles that sentence into a deterministic program that runs over your file and selects the exact fields and rows in scope. Row 18,000 gets the exact same test as row 1.

**3. Inspect the free plan before approving.** Before any credits are spent, the plan shows you the matched fields, the exact item and word counts, a preview of the output structure, and the credit cost. If your instruction matched a column you meant to skip, you change your sentence and re-plan for free.

**4. Apply your workspace glossary and batch instructions.** Your [brand glossary](/blog/build-translation-glossary-brand) and tone rules travel with every batch into the translation model, so terminology is woven into the grammar of the sentence rather than swapped blindly after the fact.

*Illustration: A glossary settles the terms that must not drift, and applies the same decision to every file.*

**5. Run it from the app, the CLI, or your AI agent.** You can click through in the browser, automate the loop in CI with the `aiglot` CLI, or connect AI Glot as an [MCP server](https://ai-glot.com/docs/mcp/overview) so Claude Code or Cursor can translate your repository's locale files directly.

## When to keep DeepL, and when to switch

**Keep DeepL** when you are translating a handful of standalone Word documents or slide decks where every line of text in the file should be translated, or when you need a sub-second neural machine translation API for live user-generated text in a chat widget.

**Switch to a file-aware translation engine** as soon as any of these are true:

* Your data lives in **CSV, TSV, PO, ARB, `.xcstrings`, TOML, Markdown with frontmatter, or a ZIP folder** of localization files.
* You are translating **many small `.xlsx` or `.docx` files** (or several target languages) and do not want to pay DeepL's 50,000-character minimum charge per file and per language.
* Your file has **columns, keys, or already-translated rows that must not be touched**, and you are tired of writing pre-processing and post-processing scripts around an API.
* You need your **glossary, placeholders, and brand brief** applied with full context so the output clears your publishing bar on the first pass.

You can test any format without an account on our [free file translator tools](/file-formats), or **[create a free AI Glot account](https://app.ai-glot.com/signup)** to get your first **5,000 words free** on your first file and compare the output side by side on your own data. See [pricing](/pricing) for volume credit packs.

---

*All DeepL technical specifications, file size limits, beta status labels, and billing rules cited in this article come from [DeepL's official developer documentation](https://developers.deepl.com/docs/best-practices/document-translations) and [usage limits reference](https://developers.deepl.com/docs/resources/usage-limits) as of October 2026. The 20-file spreadsheet calculation and the product table rows in the diagrams are illustrative examples showing how those published rules apply.*