Translating books with a neural network: keeping style and names over hundreds of pages

How to translate long texts in chunks without losing names, terms and tone: a glossary, the tail of the previous translation, cache and the price of a whole book.

5 min · · автоматизация · API keys

Paste a chapter of a book into a chat and the model will translate it decently. Paste chapter thirty separately from chapter one and the heroine suddenly has a different name, the formal "you" has turned into the informal one, and a rare term is translated a third way. A neural network gives a coherent book translation only when you give it memory: a glossary, a style, and the end of the previous translation. Here is that approach step by step, with code and a price calculation for a whole book.

Why "all in one window" and "chapter by chapter" do not solve it

Catalog models have a context of up to 1M tokens, so you might think a book can go in one request. There are two practical obstacles:

  • the answer length is bounded by the max_tokens parameter and the model itself, so you will not get a whole book in one answer;
  • if something goes wrong halfway, you lose the whole request and pay for it.

So the text is cut into chunks of 2,000 to 4,000 tokens and translated in order. That raises the problem of consistency between chunks, solved with three techniques.

Preparation: text from PDF or EPUB

For book translation from PDF you need plain text. If the PDF is built from text, a library such as pypdf is enough; if it is a scan, you need recognition (OCR) or a model with image support, see how to recognize a PDF with a neural network. After extraction, clean up headers, page numbers and end-of-line hyphenation, otherwise the model will translate those too. Check that paragraphs have not merged.

It is better to cut text at paragraph boundaries:

bash
def split_chunks(text: str, max_chars: int = 9000) -> list[str]:
    chunks, cur = [], ""
    for para in text.split("\n\n"):
        if cur and len(cur) + len(para) > max_chars:
            chunks.append(cur)
            cur = ""
        cur += para + "\n\n"
    if cur.strip():
        chunks.append(cur)
    return chunks

9,000 characters of English correspond to roughly 2,000 to 3,000 tokens; measure the exact number with token counting.

Technique 1. A glossary: names, terms, forms of address

A glossary is a file of hard correspondences. It answers questions the model would otherwise decide differently every time:

bash
{
  "names": {"Eleanor Vance": "Элеонора Вэнс", "Hill House": "Хилл-Хаус"},
  "terms": {"the Ministry": "Министерство", "ward": "подопечный"},
  "address": "characters use the formal 'you', except Eleanor and Luke with each other",
  "tone": "restrained prose, long periods, no modern slang"
}

How to build it: first run the opening chapters and ask the model to list all names, places and recurring terms. Then you edit the translation variants yourself, because the glossary outranks the model. Grow it as you go: found a new name, added it.

Technique 2. The tail of the previous translation

Each request includes the last one or two paragraphs of already translated text and asks to continue in the same style. This holds the intonation and closes gaps at chunk boundaries. Keep the tail small: you pay for every one of its tokens in every request.

Technique 3. Prompt cache for the constant part

The instruction and glossary are identical across requests. That is an ideal cache candidate: the prefix is written in the first request and read at a reduced price in the rest. For Claude the cache discount comes from the Anthropic format (/v1/messages), so we use the official Anthropic SDK with a base URL without /v1:

bash
import os, json, pathlib
import anthropic

client = anthropic.Anthropic(
    base_url="https://api.zukko.pro",
    api_key=os.environ["ZUKKO_API_KEY"],
)
MODEL = "claude-sonnet-5-5"

glossary = pathlib.Path("glossary.json").read_text(encoding="utf-8")
SYSTEM = (
    "You are a literary translator from English to Russian. "
    "Translate accurately, keeping tone, rhythm and paragraph structure. "
    "Take names and terms strictly from the glossary. Add nothing and skip nothing. "

The script saves each chunk to its own file and skips finished ones on a rerun, so a network drop will not make you pay twice. The cache_read_input_tokens field shows whether the cache hit; if it is always zero, the prefix may be shorter than the minimum cacheable size given in Anthropic's documentation. Python reference: Python SDK.

Calculation: what a book costs

Assumptions for the example (prices on October 18, 2026, per 1M tokens): a book of about 120,000 source tokens, 40 chunks of 3,000 tokens. The cached prefix (instruction plus glossary) is 4,000 tokens. The previous-translation tail plus the chunk is 5,000 fresh tokens per request. Russian text takes more tokens than English, so we take 6,000 output tokens per chunk (twice the input). These are assumptions: your book will have different numbers, so measure them on the first chunk.

Totals: fresh input 40 × 5,000 = 200,000, cache read 39 × 4,000 = 156,000, cache write 4,000, output 40 × 6,000 = 240,000.

ModelFormulaTotal
claude-sonnet-5-5 (0.4 / 2; cache 0.05 / 0.5)0.2 × 0.4 + 0.156 × 0.05 + 0.004 × 0.5 + 0.24 × 2 = 0.08 + 0.0078 + 0.002 + 0.48about $0.57
claude-opus-5-5 (0.8 / 4; cache 0.08 / 1)0.2 × 0.8 + 0.156 × 0.08 + 0.004 × 1 + 0.24 × 4 = 0.16 + 0.01248 + 0.004 + 0.96about $1.14
deepseek-v4.1-flash (0.013 / 0.038; cache read 0.013)(0.2 + 0.156 + 0.004) × 0.013 + 0.24 × 0.038 = 0.00468 + 0.00912about $0.014

Without cache Sonnet would come to $0.62: input 0.36 × 0.4 = $0.144 plus output $0.48. Output clearly dominates translation, so cache gives a modest saving and the main price lever is the choice of model. For DeepSeek a cache write is not billed separately; in the calculation it is included in input at the input price for simplicity. Numbers cannot tell which model translates better: translate the same passage on two or three models and compare by eye, ideally with a native speaker. On choosing a model by price: model strength index.

Checking quality over hundreds of pages

  • A name sweep: export the whole translation and search for variants that are not in the glossary (for example, a different spelling of a heroine's name).
  • Spot checks: read every tenth chunk next to the original, watching for skipped paragraphs.
  • Length comparison: a sharp difference between the translation's length and the original's points to an omission or added text.
  • A second pass: ask the model to proofread a finished chapter for consistency with the glossary without retelling the plot.

Translating a book creates a derivative work, and rights to it are governed by national law and the rightsholder's terms. We are not lawyers and give no legal advice. Terms differ for your own study or private reading and for publishing or distribution. Safe options: works in the public domain, your own texts, and books you have the rightsholder's permission to translate. If a book is protected, clarify the rights before publishing.

FAQ

Which neural network translates books best?

There is no universal answer. Compare two or three models on one passage of two to three pages and choose by result and by price from the calculation above.

How do I keep names consistent over hundreds of pages?

Keep the glossary in the system instruction of every request and extend it as you work. If the instruction is long, turn on prompt caching.

Can I translate a whole PDF?

First extract the text (scans need OCR or an image-capable model), then cut it into chunks at paragraph boundaries and translate in order, as in the code example.

How do I start?

Create a key in the dashboard, set a daily limit and test the script on one chapter before running the whole book.

zukko

Pay 25×
less

for Claude Code & ChatGPT

One fetch_* key and base URL api.zukko.pro — for Cursor, Claude Code, Codex, and any SDK.

Get API keyDocumentation

api.zukko.pro · fetch_*

AI for translating books: style, names, and cost · Zukko