CEP panel for Adobe InDesign that extracts story text from a document, sends it to an LLM for translation, writes the result back into the same stories, and runs a handful of QA checks (overset text, leftover untranslated strings, missing glyph support) — all without leaving InDesign.
Panel-side JS drives the UI and calls the LLM provider directly over
fetch; an ExtendScript host (jsx/host.jsx) does the actual document
read/write inside InDesign's scripting engine.
Works at the story level rather than per text frame, since InDesign frames can be threaded (one story flowing across several frames) — indexing by frame the way the Illustrator sibling extension does would either split one logical piece of text across multiple fragments, or duplicate it once per frame it flows through.
| ChatGPT, German target | Ollama, German target | Provider dropdown |
|---|---|---|
![]() |
![]() |
![]() |
- Extract story text — current selection (a whole story, or just a dragged text range within one), or the whole document if nothing is selected
- Translate via one of four providers: local Ollama, Claude, ChatGPT, Gemini
- Optional formatting-preserving mode — captures per-run font/size/color/
underline/tracking as inline markers (via InDesign's
textStyleRanges) so mixed bold/regular text survives translation unchanged - Apply translated text back to the original stories (or just the selected
sub-range, written in place — InDesign's
characters.itemByRange()can assign.contentsdirectly to a sub-range, so a partial edit never touches the rest of the story) - Per-language style examples (
examples/<lang-code>/*.txt) fed to the LLM as house-style reference - Checks: overset stories (via InDesign's native
.overflowsflag on a story's last text container), untranslated leftovers, font/script glyph support (heuristic registry, not real font introspection)
Read SECURITY.md first — installing this enables
Adobe's PlayerDebugMode, which is not scoped to just this extension.
Run ./install-mac.sh (prints the same warning and asks
for confirmation before changing anything), or follow the manual steps in
install-mac.md.
- Select a target language (e.g.
German (de)) and, if using a hosted provider, paste an API key — stored only in the panel's local storage on this Mac. - 1. Extract text — pulls story text from the current selection, or the whole document if nothing is selected.
- 2. Translate — batches stories to the chosen provider (chunked by character count so long documents don't get cut off mid-reply).
- 3. Apply to document — writes translated text back into the same stories by index.
- 4. Run checks — flags overset stories, untranslated leftovers, and fonts that may not cover the scripts used in the translated text.
Providers:
| Provider | Needs API key | Notes |
|---|---|---|
| Ollama (local) | No | http://localhost:11434, default model gemma4:26b — no cost, nothing leaves the machine |
| Claude (Anthropic) | Yes | default model claude-sonnet-5 |
| ChatGPT (OpenAI) | Yes | default model gpt-4o |
| Gemini (Google) | Yes | default model gemini-2.5-flash |
Drop approved .txt snippets in examples/<lang-code>/ (folders already
present: en, de, fr, cs, pl, nl) to steer tone/terminology per
language. Empty or missing folder = default IEC/IEEE 82079 minimalist style
only. See examples/README.txt.
For how the prompt itself is built (and how to change it), see
CUSTOMIZATION.md.
- Story
ids are index positions intodoc.stories— the document must not gain/lose/reorder stories between Extract and Apply. - A story is skipped only if every one of its text containers is locked, or every one is hidden — a partly editable/visible threaded story is still surfaced.
- "Missing glyph support" is a manual font→script registry
(
js/checks.js), not real font introspection — InDesign's scripting API can't query a font file's actual glyph coverage. ExtendFONT_SCRIPT_SUPPORTfor fonts not already listed. - Formatting-preserving mode assumes source text has no literal
<</>>sequences. - Color fingerprinting is by swatch name (InDesign colors are always a named swatch — solid, spot, gradient, mixed ink, Paper, Registration — never a raw RGB/CMYK value), so a swatch renamed or removed between extract and apply won't be re-applied.
MIT — see LICENSE.


