# Paper Trans

> |

- **Type:** Skill
- **Install:** `agentstack add skill-jesamkim-oh-my-skills-paper-trans`
- **Verified:** Yes — security-reviewed for prompt injection and unsafe behavior
- **Seller:** [jesamkim](https://agentstack.voostack.com/s/jesamkim)
- **Installs:** 0
- **Category:** [Agent Skills](https://agentstack.voostack.com/c/agent-skills)
- **Latest version:** 0.1.0
- **License:** MIT
- **Upstream author:** [jesamkim](https://github.com/jesamkim)
- **Source:** https://github.com/jesamkim/oh-my-skills/tree/main/my-skills/paper-trans

## Install

```sh
agentstack add skill-jesamkim-oh-my-skills-paper-trans
```

Requires the [AgentStack CLI](https://agentstack.voostack.com/docs/cli). Works with Claude Code, Cursor, and any MCP-compatible agent.

## About

# Paper Format-Preserving PDF Translation

## Overview

Translate academic paper PDFs (arXiv, ACL, IEEE, ACM, ...) into Korean while
keeping the **original layout, page count, figures, tables, and equations
intact**. The method is an in-place overlay: each translatable text block is
erased from the original page (text only — images and vector line art are
preserved) and the Korean translation is inserted into the same bounding box,
auto-shrinking when the translation runs longer than the original.

**Pipeline**: fetch -> extract/classify -> Claude translates JSON -> overlay -> verify.

**What gets translated**: body paragraphs, abstract, figure/table captions.
**What stays original**: equations, code blocks, the References list,
authors/affiliations/emails, paper and section titles, headers/footers/page
numbers, arXiv margin stamp, text inside figures, tables of symbols.

## Critical Rules

### NEVER DO
- **NEVER** translate blocks marked `"translate": false` unless you have a
  clear reason to override (then flip the flag AND fill `translated_text`)
- **NEVER** translate `figure-text` / `rotated` blocks (labels inside
  diagrams) — overwriting them is what garbles figures; leave them original
- **NEVER** modify `id`, `page`, `bbox`, `font_size`, or `bold` fields
- **NEVER** translate: model/dataset/product names, technical acronyms,
  author names, citation markers `[12]`, inline math symbols, URLs
- **NEVER** produce invalid JSON — escape inner double quotes with `\"`

### ALWAYS DO
- **ALWAYS** fill only the `translated_text` field
- **ALWAYS** use academic written Korean (문어체: "~한다", "~이다")
- **ALWAYS** keep `"그림 N:"` / `"표 N:"` prefixes for captions
- **ALWAYS** run the verify step with `--blocks` (figure-integrity diff) and
  the Vision QA before delivering, and Read every `figdiff_*` crop pair

## Prerequisites

- PyMuPDF: `pip install pymupdf` (1.26+ for `insert_htmlbox`)
- A Korean font (NanumGothic preferred): `sudo apt install fonts-nanum`
  (the apply script auto-detects via known paths and `fc-match`)

## Step 0 — Resolve input

Accept a local PDF path or a URL. arXiv `abs` pages are rewritten to `/pdf/`.

```bash
python ${SKILL_DIR}/scripts/fetch_pdf.py "" --out-dir 
```

The last stdout line is the local PDF path. Exit 1 = download/validation
failure; report the error to the user.

## Step 1 — Extract and classify blocks

```bash
# Small papers ("

# Larger papers: one JSON per 3-page group, translatable blocks only
python ${SKILL_DIR}/scripts/extract_blocks.py "" --split-pages 3 --translatable-only
```

Outputs `{stem}_blocks.json` (or `{stem}_blocks_g{K}.json` per group) plus a
classification histogram on stderr. Review the histogram: `TRANSLATE` should
dominate on body pages; `references`, `front-matter`, `figure-text`, `math`
buckets should be non-zero for a typical paper.

**Exit 2** means the PDF has no usable text layer (scanned document) — stop
and tell the user OCR is out of scope for this skill.

Each block:

```json
{"id": "p3_b7", "page": 3, "bbox": [53.8, 84.8, 295.6, 227.0],
 "text": "English text ...", "font_size": 8.96, "bold": false,
 "translate": true, "reason": "body", "translated_text": null}
```

The classifier is heuristic. You may override individual mistakes during
translation: a mislabeled skip block can be translated by setting
`"translate": true` + `translated_text`; a mislabeled body block (e.g. a
table of numbers) is skipped by leaving `translated_text` null.

## Step 2 — Translate the JSON (Claude)

### Workflow A — Sequential (single JSON, small papers)

Read the blocks JSON, translate every `"translate": true` block, write the
JSON back with `translated_text` filled.

### Workflow B — Parallel (group JSONs, > 10 pages)

Dispatch one subagent per group file (all in parallel). Subagent prompt
template:

```
You are a professional English-to-Korean translator for academic AI/ML papers.
Edit the JSON file: {group_file}
For EVERY block with "translate": true, fill "translated_text" with a Korean
translation. Do not modify any other field.

Rules:
- Academic written register (문어체: "~한다", "~이다"), natural Korean structure.
- KEEP IN ENGLISH: model/product/dataset names, technical acronyms
  (ML, RL, LLM, API, ...), author names, citation markers like [12],
  inline math symbols, URLs.
- Captions: "Figure N:" -> "그림 N:", "Table N:" -> "표 N:".
- If a block is clearly not translatable prose (numeric table, code,
  figure fragment), leave translated_text null.
- CRITICAL: output must remain valid JSON — escape inner double quotes (\").
Write the complete updated JSON back to the same path, then verify with:
python3 -c "import json; json.load(open('{group_file}'))"
```

After all subagents return, audit coverage before applying:

```bash
python3 -c "
import json, glob
for f in sorted(glob.glob('_blocks_g*.json')):
    d = json.load(open(f))
    miss = [b['id'] for b in d['blocks'] if b['translate'] and not b['translated_text']]
    print(f, 'missing:', miss)
"
```

Re-dispatch a fix-up subagent for any file with missing blocks.

## Step 3 — Apply overlay

```bash
python ${SKILL_DIR}/scripts/apply_overlay.py "" "_blocks*.json"
```

Creates `KO_{name}.pdf` (override with `--out`, prefix with `--prefix JA_`
etc.) and `{stem}_apply_report.json` with expected/untranslated/applied/
failed/shrunk stats. Per page it redacts only the translated blocks' text
(images and line art preserved via `PDF_REDACT_IMAGE_NONE` /
`PDF_REDACT_LINE_ART_NONE`), then inserts Korean with `insert_htmlbox`
(auto-shrink down to scale 0.4, NanumGothic with DejaVu fallback for math
glyphs).

Safety behavior:
- Every JSON is validated against the target PDF (source name, page count,
  page ranges, duplicate ids) — mismatches abort before any redaction.
- `translate: true` blocks without `translated_text` are kept original and
  listed in the report (`untranslated`) — the intended path for blocks a
  translator judged non-prose.
- A block that cannot fit even at scale 0.4 counts as failed, and the
  output is saved as `KO_{name}.partial.pdf` instead of the normal name so
  a broken PDF is never presented as the final result. Shorten those
  translations in the JSON and re-run.

## Step 4 — Verify + Vision QA

```bash
python ${SKILL_DIR}/scripts/verify_output.py "" "KO_.pdf" \
    "_apply_report.json" --blocks "_blocks*.json" \
    --render 0,1,5 --render-dir /qa
```

Checks page count, failed insertions, hangul coverage, excessive shrink
( crop-patch fallback below)

Fix prose issues by editing the affected block's JSON (e.g. shorten the
translation, or null out a figure block's `translated_text`) and re-running
Step 3. Render 2-3 representative pages: page 0, the densest body page, and
one caption/figure-heavy page.

### Crop-patch fallback (damaged figure regions)

**Confirm before patching.** A figdiff finding is a *candidate*, not a
verdict — the pixel diff can flag a legitimate change or a boundary artifact.
Always Read the `figdiff_*_src.png` / `figdiff_*_out.png` pair first and
judge whether the figure is actually damaged. Patch only regions you have
visually confirmed as damaged; report ambiguous ones to the user rather than
patching blind.

When a figdiff crop shows real damage — a figure label wiped by redaction,
Korean text sitting inside a diagram, lost strokes — paste the original
pixels back over just that region. `verify_output.py` prints the exact
command for each finding:

```bash
python ${SKILL_DIR}/scripts/patch_regions.py "" "KO_.pdf" \
    --region 4:160.4,86.3,386.0,98.8 --region 4:411.0,109.3,471.0,128.3
```

Each region is rendered from the SOURCE page at 300 dpi and inserted over
the same rect in the output, so the figure area becomes a pixel-perfect
image of the original (non-selectable, but visually intact). Prefer fixing
the root cause first — a figure block that got translated should have its
`translated_text` nulled and Step 3 re-run; patch only what redaction
itself damaged. **Run patching last**: re-running apply_overlay.py
regenerates the PDF and discards patches. After patching, re-run Step 4 —
patched regions are auto-masked, so a clean result confirms the fix.

If a diff is legitimate (e.g. a page you deliberately altered), exclude it
with `--fig-skip-pages 4` instead of patching.

### Rasterize fallback (whole-page)

If damage is spread across a whole page (vector figure losing many strokes,
table rules disappearing everywhere), patching region-by-region is not
worth it — re-run Step 3 with that page in rasterize mode instead. The page
is rendered to a 200-dpi image as background, translated regions are
covered with white patches, and Korean is overlaid on top. Text on such
pages becomes non-selectable but visuals are pixel-perfect:

```bash
python ${SKILL_DIR}/scripts/apply_overlay.py "" "_blocks*.json" --rasterize-pages 4,7
```

## Translation Quality Guidelines

- Terminology consistent across the whole paper (e.g. "reinforcement
  learning" -> "강화학습" everywhere)
- Keep sentence-level fidelity; do not summarize or expand
- Prefer established Korean academic terms; keep the English in parentheses
  on first use only when the Korean term is uncommon:
  "지식 증류(knowledge distillation)"
- Numbers, percentages, units: keep as-is

## Edge Cases

- **Scanned PDF**: extract exits 2 — abort with a clear user message
- **Two-column layouts**: handled naturally (block-level processing)
- **Overflow**: htmlbox auto-shrinks to 0.4 scale; verify warns below 0.6,
  and below 0.4 the block fails (output becomes `.partial.pdf`) — shorten
  those translations and re-apply
- **Hyperlinks**: annotation layer untouched by redaction — preserved
- **Appendix after References**: classifier resumes translation at bold
  appendix headings ("A.1 ...") — spot-check this boundary in the JSON

## Output Naming

- Default: `KO_{original_name}.pdf` (same directory as source)
- Other languages: `--prefix JA_` etc., and adapt the translation prompt

## Source & license

This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.

- **Author:** [jesamkim](https://github.com/jesamkim)
- **Source:** [jesamkim/oh-my-skills](https://github.com/jesamkim/oh-my-skills)
- **License:** MIT

Install and usage instructions live in the source repository linked above.

## Pricing

- **Free** — Free

## Security capabilities

Automated source analysis of v0.1.0 — what this tool can access:

- **Network access:** no
- **Filesystem access:** yes
- **Shell / process execution:** no
- **Environment & secrets:** no
- **Dynamic code execution:** no

*"Yes" means the capability is present in the source — more access means more to trust, not that it is unsafe.*


## Versions

- **0.1.0** — security scan: passed — Imported from the upstream source.

## Links

- Listing page: https://agentstack.voostack.com/l/skill-jesamkim-oh-my-skills-paper-trans
- Seller: https://agentstack.voostack.com/s/jesamkim
- Browse the marketplace: https://agentstack.voostack.com/browse

---
Listed on AgentStack — the marketplace for AI agent skills and MCP servers. Every listing is security-reviewed. Creators keep 70%.
