Translating PDFs from English to Russian with AI: text, tables, formulas

A working PDF translation pipeline: extract the text, split it, translate with a glossary and assemble the result. What 100 pages cost.

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

Uploading a PDF to a chat and typing "translate" works as long as the document is short. A 40-page paper or a 300-page manual runs into the answer length limit, loses tables and translates the same term differently each time. An AI model translating PDFs from English to Russian gives predictable results if you split the work into stages: extract the text, translate in chunks with a shared glossary and assemble the result. Below is such a pipeline in Python and a cost estimate for 100 pages.

Step 0. Determine the PDF type

The extraction method depends on it:

  • A PDF with a text layer (downloaded from a journal, exported from Word): the text can be extracted programmatically. Test it by selecting a phrase with the mouse in a viewer.
  • A scan or photos of pages: no text layer, so you either need recognition or send pages to the model as images.
  • Mixed: some pages are text, some are scans. Separate them by page.

Translate only documents you have the right to: someone else's books and closed materials must not be translated for distribution.

Step 1. Extracting the text

For text PDFs the pypdf library will do:

bash
pip install pypdf openai
bash
from pypdf import PdfReader

reader = PdfReader("paper.pdf")
pages = [(page.extract_text() or "").strip() for page in reader.pages]
empty = [i + 1 for i, text in enumerate(pages) if len(text) < 50]
print(f"Pages: {len(pages)}, nearly empty: {empty}")

Pages with almost no text are candidates for image mode (step 4). Columns, footnotes and tables may get shuffled during extraction: look at two or three pages by eye before running everything.

Step 2. Splitting into chunks

A model translates medium-sized chunks more reliably than the whole document at once. A simple rule: collect pages until you reach about 6,000 characters and do not cut in the middle of a page.

bash
def make_chunks(pages, limit=6000):
    chunks, current = [], ""
    for text in pages:
        if current and len(current) + len(text) > limit:
            chunks.append(current)
            current = ""
        current += text + "\n\n"
    if current.strip():
        chunks.append(current)
    return chunks

chunks = make_chunks(pages)

If the document has chapters, it is better to cut along them: semantic context is preserved.

Step 3. Translating with a glossary

The main cause of inconsistent terms is that the model does not know how you translated them in earlier chunks. The fix is a glossary at the start of every request. Compile it yourself for 20–50 key terms, or ask the model to list terms from the first chapter and correct the list by hand.

bash
from openai import OpenAI

client = OpenAI(base_url="https://api.zukko.pro/v1", api_key="fetch_your_key")

GLOSSARY = """attention head — голова внимания
fine-tuning — дообучение
loss function — функция потерь"""

SYSTEM = f"""You are a technical translator from English into Russian.
Rules:
1. Translate precisely, without paraphrasing or shortening. Add nothing of your own.
2. Leave formulas, LaTeX, code, variable names, links and numbers unchanged.
3. Return tables as Markdown, keeping the order of rows and columns.
4. Keep headings and lists as Markdown.

Notes on the code:

  • The temperature parameter is not supported by all models. If a request fails on this parameter, remove it.
  • For hundreds of chunks, run the translation in parallel with retries: an example is in async requests in Python.
  • Save intermediate results to disk so you do not translate everything again after a failure.
  • Request parameters and Python usage are described in the SDK guide.

Step 4. Scans and complex layout: pages as images

If there is no text layer or the layout scrambled the line order, send pages to the model as images. A page can be rendered with the PyMuPDF library (pip install pymupdf; in older versions the import is called fitz):

bash
import base64
import pymupdf

doc = pymupdf.open("scan.pdf")

def translate_page_image(page_index: int, model: str = "claude-sonnet-5-5") -> str:
    png = doc[page_index].get_pixmap(dpi=150).tobytes("png")
    b64 = base64.b64encode(png).decode()
    response = client.chat.completions.create(
        model=model,
        messages=[
            {"role": "system", "content": SYSTEM},
            {"role": "user", "content": [
                {"type": "image_url", "image_url": {"url": f"data:image/png;base64,{b64}"}},
                {"type": "text", "text": "Translate the text on the page into Russian following the rules above."},
            ]},
        ],
    )
    return response.choices[0].message.content

Not every model accepts images as input. Per the table as of 18 October 2026 that includes claude-sonnet-5-5 and gpt-6.1-sol, while deepseek-v4.1-flash and glm-5.3-flash do not accept images. A detailed look at recognition: how to recognize a PDF with AI. An image page costs more than a text page: check how many tokens one page takes in the usage field on a single request.

Tables and formulas

  • Tables. Ask for a Markdown table and check the row and column count against the original. For big tables it is safer to translate only the text cells and leave numbers alone.
  • Formulas. If formulas came out as garbage, that is an extraction problem, not a translation one. In image mode the model usually preserves the look of a formula, but check selectively.
  • Figure captions and references. Do not translate numbers and citations: this is in the rules.

Quality checks

AI translation makes mistakes in terminology and numbers, so:

  1. Compare the count of numbers in the original and the translation chunk by chunk: a mismatch is a reason to open that spot.
  2. Read 5–10% of pages selectively, especially tables and definitions.
  3. Scan the result for English words that should have been translated.
  4. For important documents give the translation to a specialist: an AI model does not replace a certified translation.

What 100 pages cost

Assumptions for the example: 100 pages of 500 words, about 650 tokens per page in the original, i.e. 65,000 tokens of text. Add the instruction and glossary in each of about 50 requests (500 tokens each): 25,000 tokens. Total input is 90,000 tokens. A Russian translation takes more tokens than the English original (see why Russian text is counted differently); take output as 130,000 tokens. Exact numbers depend on the document, so this is an estimate.

Zukko prices as of 18 October 2026, $ per 1M tokens:

ModelInputOutputCalculationTotal
claude-sonnet-5-50.4290,000 × 0.4 / 1M + 130,000 × 2 / 1M = $0.036 + $0.26about $0.30
gpt-6.1-sol0.271.3290,000 × 0.27 / 1M + 130,000 × 1.32 / 1M = $0.0243 + $0.1716about $0.20
deepseek-v4.1-flash0.0130.03890,000 × 0.013 / 1M + 130,000 × 0.038 / 1M = $0.00117 + $0.00494about $0.006

The table shows that the translation price is driven mostly by output. When choosing a model, go by price, strength index and your own test: translate one chapter on two models and compare. Prices change; the current ones come from GET https://api.zukko.pro/v1/models.

FAQ

Can I translate a PDF without programming?

For small files you can use the browser chat: paste the text in parts together with the glossary. For large documents a script is handier.

Will the PDF layout be preserved?

No. You get Markdown with headings, lists and tables. The layout of the source PDF has to be rebuilt separately, for example by converting Markdown to the format you need.

Which model should I choose?

Start with an inexpensive one and compare the result with a stronger one on a single chapter. Scanned pages require a model that supports images.

How do I start?

Create a key in the Zukko dashboard, run the script on 3–5 pages and look at the spending on the "Usage" page.

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 to translate a PDF from English to Russian · Zukko