Skip to content

Commit db7d718

Browse files
josixclaude
andauthored
feat: add review-rendered-diff skill (#1252)
* feat: add review-rendered-diff skill for viewing translation changes on rendered pages Builds a page before and after a PO change in isolation (temp locale_dirs, no changes to the working tree or ../cpython), then highlights each changed paragraph on the real rendered HTML and screenshots it: - small edits as inline red/green diffs - new translations and heavy rewrites as stacked before/after blocks Also lists the skill in README and ignores its default output dir. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_014pJTfUKUkCc4HFprcvhxRe * fix: improve review-rendered-diff paragraph matching and labels - Treat fuzzy msgstr as untranslated, since Sphinx does not render it - Pick the closest, not-yet-highlighted block when the snippet appears in several paragraphs (asdict/astuple, class C/D __init__ examples) - Ignore URLs when measuring CJK share, so short Chinese text around a long URL is not labelled as English - Show whitespace-only changes as ␣ instead of an empty colored box - Resolve --out to an absolute path - Fix ruff warnings (explicit check=False, narrow Playwright exception) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_014pJTfUKUkCc4HFprcvhxRe * refactor: declare render_diff.py dependencies inline (PEP 723) `uv run <script>` now installs polib, beautifulsoup4, playwright and pillow itself, so the --no-project/--with flags are no longer needed. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_014pJTfUKUkCc4HFprcvhxRe --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
1 parent c14b87d commit db7d718

4 files changed

Lines changed: 487 additions & 1 deletion

File tree

Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
---
2+
name: review-rendered-diff
3+
description: Use when a reviewer needs to see how changed PO translations look on the rendered Python docs page — before/after comparison, red/green inline diff on the built HTML, or screenshots of changed paragraphs for a PR description or review comment.
4+
argument-hint: <po-file> [--base <git-ref>] [--new <git-ref>]
5+
---
6+
7+
# review-rendered-diff
8+
9+
Show translation changes **inside the real rendered page**, each changed paragraph outlined,
10+
one screenshot per paragraph plus an overview image. Each entry is shown one of three ways:
11+
12+
| Change | Shown as | Picked when (`--mode auto`) |
13+
|---|---|---|
14+
| Edit of an existing translation | **inline**: deleted text red with strikethrough, inserted green | default |
15+
| English → Chinese (new translation) | **two blocks**: gray「原文 (English)」above green「譯文」 | base msgstr empty, or the old rendered text is <20% CJK |
16+
| Heavy rewrite of a translation | **two blocks**: red「修改前」above green「修改後」 | text ≥30 chars and >50% of characters changed |
17+
18+
Two blocks are used where a character diff would be solid red and green. Short text, such as
19+
headings and table cells, always stays inline. Force a style with `--mode inline|blocks`, or
20+
tune the rewrite cut-off with `--rewrite-threshold` (default 0.5). Each report line names the
21+
mode used, e.g. `[blocks: rewritten, 87% changed]`.
22+
23+
## Run it
24+
25+
From the repo root:
26+
27+
```bash
28+
uv run .claude/skills/review-rendered-diff/scripts/render_diff.py howto/logging.po --base origin/3.15
29+
```
30+
31+
The script declares its dependencies inline (PEP 723), so `uv run` needs no `--with` flags.
32+
33+
| Flag | Default | Use |
34+
|---|---|---|
35+
| `--base` | `origin/3.15` | "before" version (fetch it first; SSH may fail, see below) |
36+
| `--new` | working-tree file | "after" version as a git ref, e.g. a PR branch |
37+
| `--out` | `.render-review/<po without .po>/` | where screenshots and builds go; with several POs, one subfolder per PO |
38+
| `--context` | `140` | px of surrounding page kept above/below each paragraph |
39+
40+
Common targets:
41+
42+
| Review | Command arguments |
43+
|---|---|
44+
| Uncommitted edits | `<po> --base HEAD` |
45+
| A PR branch | `<po> --base origin/3.15 --new <branch>` |
46+
| One past commit, all its POs | `$(git show --name-only --format= <sha> -- '*.po') --base <sha>^ --new <sha>` |
47+
48+
Each PO takes about 40 seconds, because the page is built twice. The script prints one
49+
line per changed entry (`L<entry line>: diff-N.png`), plus the diff page path and
50+
`all-diffs.png`.
51+
52+
Before reporting, open a couple of PNGs with Read. To share them, use SendUserFile on
53+
`all-diffs.png` if you have it. As a subagent, return the absolute paths instead. Or drag
54+
the images into a GitHub comment.
55+
56+
## How it works (why it is safe)
57+
58+
- **Isolated builds:** each version's PO goes into its own temp `locale_dirs`, and
59+
`sphinx-build` runs on that one `.rst` into `--out/build-{old,new}/`. The working-tree PO
60+
and `../cpython/Doc/locales` are never touched.
61+
- **Changed entries** are found by comparing msgstr per `(msgctxt, msgid)` with polib. A fuzzy
62+
msgstr counts as untranslated, because Sphinx does not render it, so a fixed fuzzy entry
63+
shows as a new translation.
64+
- **Locating paragraphs:** roles, inline literals and links are dropped first, because
65+
`` :meth:`~Handler.setFormatter` `` renders as `setFormatter()`. The longest remaining plain
66+
run is matched against the rendered text, and the smallest enclosing block is used. When
67+
that run appears in several blocks (e.g. the `asdict()`/`astuple()` sentences), the block
68+
not yet highlighted and closest to the whole entry wins.
69+
- **Two blocks in tables and lists** go inside the cell or item, so the table and list
70+
structure survives.
71+
- **Diff on text, not HTML:** a character diff of the rendered text, applied to text nodes only,
72+
so links, inline code and `` anchors keep working.
73+
74+
## Gotchas
75+
76+
- **Do not use `make build` for this.** It hard-links the PO into `../cpython`, runs
77+
`git pull` on cpython, and swapping the PO in place risks losing uncommitted edits.
78+
- **Exit code 1 is normal.** Sphinx fails on unrelated CPython redirect warnings
79+
(`library/functions.html redirects to ...`). The script judges success by whether the HTML
80+
exists. On failure, read `build-*/build.log`.
81+
- **`SKIPPED (paragraph not found)`** means the entry has no rendered paragraph, e.g. an index
82+
entry or code block, or its msgid no longer matches the `../cpython` sources (the page
83+
shows English). Check `../cpython` is on the same branch as the PO. `../cpython` can also be
84+
newer than the PO's last CPython sync: those entries are not a script bug, they will turn
85+
fuzzy at the next sync, and are worth telling the PR author about. A trailing ` ::`
86+
literal-block marker is already handled, so it is not the cause. For a skip you cannot
87+
explain, grep the new msgstr's plain text in `build-new/html/<po>.html`.
88+
- **A paragraph containing several changed entries** is highlighted once, and later entries
89+
report "already highlighted".
90+
- **Inline diffs fragment small CJK edits** (e.g. 可能~~不是~~ shows only the changed
91+
characters). That is accurate. If a reviewer finds a paragraph choppy, rerun with
92+
`--mode blocks` or a lower `--rewrite-threshold`.
93+
- **Do not judge a rewrite by `SequenceMatcher.ratio()`.** Common CJK characters keep
94+
matching, so a fully rewritten paragraph still scored 0.45. The script measures the share
95+
of changed characters instead.
96+
- **A large new translation** (a whole file) makes one screenshot per paragraph, e.g. 147 for
97+
`howto/logging.po`. Point reviewers to `<po>-diff.html` rather than `all-diffs.png`.
98+
- **Labels use the entry's first line** (the `#:` comment), not the msgstr line.
99+
- **No `../cpython`:** run `make prepare_deps` once.
100+
- **SSH to GitHub resets:** fetch over HTTPS:
101+
`git -c credential.helper='!gh auth git-credential' fetch https://github.com/python/python-docs-zh-tw.git 3.15:refs/remotes/origin/3.15`
102+
103+
## Not for
104+
105+
- Checking reST validity: use `make lint` / `sphinx-lint`.
106+
- Judging translation quality: use the `validate-translation` skill. This skill only
107+
visualizes changes.

0 commit comments

Comments
 (0)