Install
$ agentstack add skill-jesamkim-oh-my-skills-paper-trans ✓ scanned · ✓ verified, works with Claude Code, Cursor, and more.
Security review
✓ PassedNo issues found. Passed automated security review. · v0.1.0 How review works →
- ✓ Prompt-injection patterns
- ✓ Secret / credential exfiltration
- ✓ Dangerous shell & filesystem operations
- ✓ Untrusted network calls
- ✓ Known-malicious package signatures
What it can access
- ✓ Network access No
- ● Filesystem access Used
- ✓ Shell / process execution No
- ✓ Environment & secrets No
- ✓ Dynamic code execution No
From automated source analysis of v0.1.0. “Used” means the capability is present in the source — more access means more to trust, not that it’s unsafe.
Verified badge
Passed review? Show it. Paste this badge into your README, it links to the public security report.
Reliability & compatibility
Declared compatibility
Compatibility is declared by the source manifest. End-to-end runtime verification is coming, see below.
We're building live execution health for every listing: tool-call success rate, median latency, uptime, and last-checked timestamps, measured, not self-reported. It isn't live yet, so we don't show numbers we can't stand behind.
How agent discovery & health will work →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": falseunless you have a
clear reason to override (then flip the flag AND fill translated_text)
- NEVER translate
figure-text/rotatedblocks (labels inside
diagrams) — overwriting them is what garbles figures; leave them original
- NEVER modify
id,page,bbox,font_size, orboldfields - 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_textfield - 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+ forinsert_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/.
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
# 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:
{"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:
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
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: trueblocks withouttranslated_textare 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
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:
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:
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
- Source: jesamkim/oh-my-skills
- License: MIT
Install and usage instructions live in the source repository linked above.
Reviews
No reviews yet, be the first.
Write a review
Versions
- v0.1.0 Imported from the upstream source.