skills: move translation skills to ./skills/, symlink from ~/.hermes/skills/

pptx-translate, chinese-text-normalize, dharma-translation: canonical
location now ./skills/ with symlinks in ~/.hermes/skills/.

translation-review: merged CSV/XLSX review + .dj comparison workflows
into single SKILL.md. Added buddhist-terminology.md and
terms-db-alignment.md references from Hermes version.
This commit is contained in:
iacore
2026-06-09 19:46:23 +08:00
parent 10c449f4d9
commit 7e8ba4b291
9 changed files with 693 additions and 51 deletions
+42
View File
@@ -0,0 +1,42 @@
---
name: chinese-text-normalize
description: Normalize Chinese markdown files — remove extraneous mid-sentence line breaks from fixed-width exports while preserving TOC structures, section headers, and intentional paragraph breaks.
---
When Chinese text has hard line breaks at a fixed width (~20-25 chars) — common in PDF exports, OCR output, or poorly-converted documents — use this skill to join them into flowing paragraphs.
## Triggers
- User asks to "fix line breaks" or "remove extraneous breaks" in Chinese text
- Chinese markdown files with lines that break mid-sentence at a consistent short width
- Files with vertical TOC (single-char-per-line 【】 sections) that need preservation
## Approach
Run `scripts/normalize_breaks.py <directory>` — it processes all .md files in the directory.
The script handles three file patterns:
1. **Vertical TOC + fixed-width body** — Preserves the decorative single-char TOC section, joins body paragraphs, strips inline page numbers (standalone digits like "3", "4")
2. **Outline TOC with stray breaks** — Preserves numbered outline items (一、...、1、...、...... separators), joins body paragraphs
3. **Already in paragraph format** — No change (safe to run idempotently)
### What it preserves
- Vertical TOC: single CJK/punctuation lines with 【】 brackets
- Section headers: 【...】、## ...、# ...、一、二、三、...、1、2、3、...
- Outline TOC entries: short numbered lines, lines with ...... separators
- Blank lines as paragraph separators
### What it removes
- Mid-sentence hard line breaks (joins consecutive CJK body lines)
- Inline page numbers (standalone 1-2 digit lines)
- Trailing blank lines
## Pitfalls
- **TOC detection boundaries**: The vertical TOC end is detected by finding the first line with 3+ CJK characters. If a page number like "2" sits between TOC and body, it lands in the TOC section — harmless but visible.
- **Section headers without markers**: Plain-text section titles (e.g., "生命可以被设计的依据") without 【】 or number prefixes won't be detected as headers. They'll form standalone paragraphs separated by blank lines, which is fine as long as blank lines exist around them.
- **Wiki-link TOC files**: Files like a course index with [[wiki links]] are NOT prose and should be excluded. The script has no special handling — skip those files manually or restore from git.
- **Not for mixed CJK/English prose**: The script treats any line with CJK characters as body text. Mixed-language documents may need manual review.
@@ -0,0 +1,168 @@
"""
Fix extraneous line breaks in Chinese markdown files.
Three file patterns:
1. Fixed-width body text (20-25 chars/line) + vertical TOC -> join lines, remove page nums
2. Mostly-paragraph with stray breaks + outline TOC -> join broken lines, preserve list items
3. Already fine -> skip (idempotent)
Usage: python3 normalize_breaks.py <directory>
"""
import re
import sys
from pathlib import Path
CJK = re.compile(r'[\u4e00-\u9fff\u3400-\u4dbf\uf900-\ufaff]')
CN_PUNCT = ',。!?;:、""''()《》【】…—~·'
NUM_MARKER = re.compile(r'^[一二三四五六七八九十]+[、,,]')
DIGIT_MARKER = re.compile(r'^\d+[、.,]')
TOC_SEP = re.compile(r'\.{3,}') # "......" separators in outline TOCs
def has_cjk(s):
return bool(CJK.search(s))
def is_page_num(line):
s = line.strip()
return s and s.isdigit() and len(s) <= 2
def is_toc_line(line):
"""Vertical TOC: single char, or 【, 】, ·, or solo digit"""
s = line.strip()
if not s:
return False
if len(s) == 1 and (has_cjk(s) or s in CN_PUNCT or s in '【】·' or s.isdigit()):
return True
return False
def is_section_header(line):
"""Section headers: 【...】, ## ..., # ..., 一、..., 1、..., or standalone title lines"""
s = line.strip()
if not s:
return False
if s.startswith('') and s.endswith(''):
return True
if s.startswith('#'):
return True
if NUM_MARKER.match(s):
return True
if DIGIT_MARKER.match(s):
return True
return False
def is_outline_toc_line(line):
"""Outline/list TOC: entries separated by ...... or short numbered items"""
s = line.strip()
if TOC_SEP.search(s):
return True
m = re.match(r'^(\d+[.、,]|[一二三四五六七八九十]+[、,])\s*\S', s)
if m and len(s) < 30:
return True
return False
def find_toc_end(lines):
"""Find where the vertical TOC section ends and body text begins."""
for i, line in enumerate(lines):
s = line.strip()
if has_cjk(s) and len([c for c in s if has_cjk(c)]) >= 3:
j = i
while j > 0 and not lines[j - 1].strip():
j -= 1
return j
return 0
def process_body(lines):
"""Join body text lines into paragraphs, preserving section headers and outline items."""
result = []
buf = []
def flush():
nonlocal buf
if buf:
joined = ''.join(buf)
result.append(joined)
buf = []
for line in lines:
s = line.strip()
if not s:
flush()
result.append('')
continue
if is_section_header(s):
flush()
result.append(s)
continue
if is_outline_toc_line(s):
flush()
result.append(s)
continue
if is_page_num(s):
continue
if has_cjk(s) or (buf and s):
buf.append(s)
else:
flush()
result.append(s)
flush()
return result
def process_file(filepath):
content = filepath.read_text(encoding='utf-8')
lines = content.split('\n')
toc_end = find_toc_end(lines)
if toc_end > 10:
toc_part = lines[:toc_end]
body_part = lines[toc_end:]
body_processed = process_body(body_part)
new_lines = toc_part + body_processed
else:
new_lines = process_body(lines)
cleaned = []
prev_blank = False
for line in new_lines:
is_blank = line.strip() == ''
if is_blank and prev_blank:
continue
cleaned.append(line)
prev_blank = is_blank
while cleaned and cleaned[-1] == '':
cleaned.pop()
new_content = '\n'.join(cleaned) + '\n'
if new_content != content:
filepath.write_text(new_content, encoding='utf-8')
return True
return False
def main():
workdir = Path(sys.argv[1])
files = sorted(workdir.glob('*.md'))
for f in files:
changed = process_file(f)
status = 'FIXED' if changed else 'OK'
print(f'{status}: {f.name}')
if __name__ == '__main__':
main()
+75
View File
@@ -0,0 +1,75 @@
---
name: dharma-translation
description: Translate Chinese Buddhist Dharma talks into English djot with annotations. Use when the user asks to translate a Dharma talk, 开示, Buddhist lecture, or similar material from Chinese to English.
---
# Dharma Talk Translation
## Trigger
User asks to translate a Chinese Buddhist Dharma talk (开示, 讲座, 法义) to English, or convert a PDF of such material into a translated djot file.
## Workflow
### 1. Extract source text from PDF
Prefer `pdftotext -layout` — it's the most reliable fallback and almost always available:
```bash
pdftotext -layout input.pdf /tmp/extracted.txt
```
pypdf and pdfplumber may not be installed; pdftotext (poppler-utils) is the safe default.
### 2. Convert to structured djot
Clean the extracted text into a djot file (`original.dj`) with this structure:
- `# Title` — h1, the talk title
- Subtitle line — date and venue, prefixed with `——`
- Opening remarks — body paragraphs before the first section
- `## 一、Section Name` — h2 for each numbered section (一、二、三、etc.)
- Closing line — revision date in parentheses
Strip page numbers (standalone digits separated by form feeds `\f`). Join broken lines within paragraphs — Chinese text joins cleanly with `''.join()` since there are no inter-word spaces.
### 3. Translate
Translate directly — no external translation APIs. The model IS the translator.
Key approach:
- Preserve the djot structure exactly (headings, paragraphs)
- Translate section headings preserving the Chinese numbering (一、→ 1., 二、→ 2., etc.)
- Keep the original Chinese in `%` comment lines alongside the translation (see annotations below)
### 4. Annotate in djot comments
Use `%` comment lines before relevant paragraphs to annotate:
- **Buddhist technical terms**: Sanskrit equivalents (e.g., 五蕴 → five aggregates / skandhas), doctrinal context
- **Cultural references**: Historical figures, place names, sutra names with explanation
- **Structural notes**: Why the speaker frames something a certain way, organizational philosophy
- **Recurring metaphors**: The McDonald's analogy throughout, the lamp/light metaphor
Format:
```
% Chinese term (pinyin) = English gloss, Sanskrit if applicable. Brief context.
Paragraph text here...
```
For sutra quotes, annotate the sutra name with both Chinese and Sanskrit.
For organizational terms (传帮带, 分灯, 三种精神), explain their meaning within the community's framework.
### 5. Output files
- `original.dj` — cleaned Chinese djot
- `translated.dj` — English translation with `%` annotations
## Pitfalls
- Do NOT call external translation APIs. Translate directly.
- Do NOT delete comparison/对照 files — they are intentional work artifacts.
- pdftotext may produce hard line breaks at column boundaries; join within paragraphs using `''.join()` for Chinese.
- Page numbers appear as isolated digits between form feeds (`\f`); strip them with regex.
- Djot `%` comments work line-by-line; place them on their own lines before the relevant paragraph.
- Keep annotations concise — one or two lines, not an essay.
+84
View File
@@ -0,0 +1,84 @@
---
name: pptx-translate
description: Translate PowerPoint files between Chinese and English — extract strings to YAML, translate, quality review, and write back with font-shrink + auto-fit for layout.
category: productivity
---
# PPTX Translation
Translate `.pptx` files between Chinese and English. Covers the full pipeline: extraction → translation → review → write-back.
## Workflow
### 1. Extract strings to YAML
Run `scripts/extract.py original.pptx strings.yaml`. Produces YAML with entries:
```yaml
- slide: 1
shape: 0
run: 0
kind: title
zh: 开启生命的富足
en: ""
```
- `slide` — 1-based slide number
- `shape` — 0-based shape index within slide
- `run` — 0-based paragraph index within text frame (or computed index for tables)
- `kind``title` | `subtitle` | `center_title` | `body` | `table` | `notes`
- `zh` — source text
- `en` — translation target (initially empty)
Table `run` index formula: `num_rows * col + row`. Reverse with `row = run % num_rows`, `col = run // num_rows`.
Speaker notes use `shape: -1`.
### 2. Translate
**Do NOT call external translation APIs.** Translate directly — the agent IS the model. The user corrects this: "Why do you call external models to do it? You can do it yourself!"
Fill in the `en` field for every entry. Batch if needed, but translate in your response, not via API calls.
Terminology guidance for Buddhist/gratitude content:
- 感恩=gratitude, 缘起=dependent origination, 众生=sentient beings
- 因缘=causes and conditions, 三宝=Three Jewels, 福报=merit/blessings
- 座上=formal practice, 座下=daily life practice, 共修=group practice
- 上报四重恩=repaying the four great kindnesses
### 3. Quality review
Scan for:
- Terminology consistency (same zh term → same en term throughout)
- Ellipsis convention — English uses 3 dots `...`, zh may use 6
- Buddhist term accuracy
- Missing translations
- Overly literal renderings
### 4. Write back with layout fixes
Run `scripts/build.py strings.yaml original.pptx translated.pptx`.
The script:
- Replaces text in matching paragraphs (clears all runs, sets first run)
- Replaces table cell text (using row/col from computed index)
- Reduces font size by 18% (`FONT_SCALE = 0.82`) on all translated shapes and tables
- Sets `auto_size = TEXT_TO_FIT_SHAPE` on text frames to handle overflow
- English text is ~1.31.5× longer than Chinese — font shrink + auto-fit handles most cases
## Alternate scripts
The absorbed `pptx-translation` skill had alternate script names: `extract_pptx.py` and `build_pptx.py`. These are functionally equivalent to `extract.py` and `build.py` with minor formatting differences (docstrings, variable naming). If the primary scripts fail, the alternates are available in the archive at `~/.hermes/skills/.archive/pptx-translation/scripts/`.
## Pitfalls
- "run" in the YAML is actually the **paragraph index** within a text frame, not the OOXML text-run index. python-pptx iterates paragraphs, not runs.
- Font shrink only applies to runs that have an explicit `font.size` — inherited sizes from paragraph/layout defaults are skipped.
- After write-back, verify with `python -m markitdown translated.pptx` to check text landed correctly.
- Tables: font shrink is applied per-cell text frame. Each cell is its own text frame.
- markitdown may fail with `ModuleNotFoundError: dotenv` — run `pip install python-dotenv` first.
## Scripts
- `scripts/extract.py` — extract strings from PPTX to YAML
- `scripts/build.py` — write translations back with font shrink + auto-fit
+68
View File
@@ -0,0 +1,68 @@
import sys, yaml
from pptx import Presentation
from pptx.util import Pt
from pptx.enum.text import MSO_AUTO_SIZE
FONT_SCALE = 0.82 # shrink ~18%
yaml_path, src_path, out_path = sys.argv[1], sys.argv[2], sys.argv[3]
with open(yaml_path) as f:
entries = yaml.safe_load(f)
index = {}
for e in entries:
index[(e["slide"], e["shape"], e["run"])] = e["en"]
def shrink_font_tf(tf):
for para in tf.paragraphs:
for run in para.runs:
if run.font.size:
run.font.size = Pt(int(run.font.size.pt * FONT_SCALE))
try:
tf.auto_size = MSO_AUTO_SIZE.TEXT_TO_FIT_SHAPE
except Exception:
pass
prs = Presentation(src_path)
for slide_num, slide in enumerate(prs.slides, 1):
for shape_idx, shape in enumerate(slide.shapes):
if shape.has_text_frame:
has_translation = False
for para_idx, para in enumerate(shape.text_frame.paragraphs):
key = (slide_num, shape_idx, para_idx)
if key in index:
has_translation = True
en = index[key]
for r in para.runs:
r.text = ""
if para.runs:
para.runs[0].text = en
else:
para.add_run().text = en
if has_translation:
shrink_font_tf(shape.text_frame)
elif shape.has_table:
num_rows = len(shape.table.rows)
for r in range(num_rows * len(shape.table.columns)):
key = (slide_num, shape_idx, r)
if key in index:
row = r % num_rows
col = r // num_rows
shape.table.cell(row, col).text = index[key]
for row in shape.table.rows:
for cell in row.cells:
shrink_font_tf(cell.text_frame)
key = (slide_num, -1, 0)
if key in index and slide.has_notes_slide:
ns = slide.notes_slide
ns.notes_text_frame.clear()
ns.notes_text_frame.paragraphs[0].add_run().text = index[key]
prs.save(out_path)
print(f"Saved {out_path}")
+68
View File
@@ -0,0 +1,68 @@
import sys, yaml
from pptx import Presentation
PLACEHOLDER_KINDS = {
1: "title", 2: "body", 3: "center_title",
4: "subtitle", 5: "body", 6: "body", 7: "body",
}
def shape_kind(shape):
if shape.has_table:
return "table"
try:
ph = shape.placeholder_format
if ph is not None and ph.type is not None:
return PLACEHOLDER_KINDS.get(ph.type, "body")
except ValueError:
pass
return "body"
def extract(pptx_path):
prs = Presentation(pptx_path)
entries = []
for slide_num, slide in enumerate(prs.slides, 1):
for shape_idx, shape in enumerate(slide.shapes):
kind = shape_kind(shape)
if shape.has_text_frame:
for para_idx, para in enumerate(shape.text_frame.paragraphs):
full = para.text.strip()
if not full:
continue
entries.append({
"slide": slide_num, "shape": shape_idx,
"run": para_idx, "kind": kind,
"zh": full, "en": "",
})
elif shape.has_table:
for row_idx, row in enumerate(shape.table.rows):
for col_idx, cell in enumerate(row.cells):
text = cell.text.strip()
if not text:
continue
entries.append({
"slide": slide_num, "shape": shape_idx,
"run": len(shape.table.rows) * col_idx + row_idx,
"kind": "table", "zh": text, "en": "",
})
if slide.has_notes_slide:
notes = slide.notes_slide.notes_text_frame.text.strip()
if notes:
entries.append({
"slide": slide_num, "shape": -1, "run": 0,
"kind": "notes", "zh": notes, "en": "",
})
return entries
if __name__ == "__main__":
entries = extract(sys.argv[1])
with open(sys.argv[2], "w") as f:
yaml.dump(entries, f, allow_unicode=True, default_flow_style=False, sort_keys=False)
print(f"Extracted {len(entries)} entries to {sys.argv[2]}")
+80 -51
View File
@@ -1,93 +1,122 @@
---
name: translation-review
description: Review Chinese↔English translation pairs for quality issues — terminology errors, grammar, consistency, formatting. Works with CSV/XLSX files and writes edit suggestions in .dj format.
description: Review Chinese↔English translations for quality issues — terminology, grammar, consistency, formatting. Two workflows: CSV/XLSX batch review (write .dj suggestions) and .dj comparison line-by-line review (surgical patching).
---
# Translation Review
## When to use
Two workflows, used depending on input format.
- User has a CSV or XLSX file with `Chinese`/`English` (or similar) columns
- User asks you to "find problems," "check translations," or "review localization"
- User mentions `.dj` edit-suggestions files
## Workflow A: CSV/XLSX batch review
## Workflow
Use when input is a CSV/XLSX with `Chinese`/`English` columns. Produces an `edit-suggestions.dj` file.
### 1. Get the data into CSV
If the file is XLSX, have the user export to CSV (or use `openpyxl` if installed). CSV is easier and faster to process. The user may also provide XHTML — CSV is preferred.
If XLSX, export to CSV (or use `openpyxl`). CSV is faster.
### 2. Read the full file
Use `read_file` with offsets to get the complete CSV into context. Don't sample — issues repeat across rows and you need full coverage.
Use `read_file` with offsets for complete coverage. Don't sample.
### 3. Write a systematic analysis script
Write a Python script to `/tmp/` and run it with `terminal: python3 /tmp/script.py`. Do NOT use heredocs (`<<'PYEOF'`) or `-c` — the terminal tool may block these. Always write to a temp file.
Write to `/tmp/script.py`, run with `python3 /tmp/script.py`. No heredocs or `-c`.
The script should:
- Parse the CSV with `csv.DictReader`
- Apply detection rules (regex-based) for each known issue category
- Collect issues with: CSV row number, page context, CN text, EN text, problem description, suggested fix
- Group/deduplicate identical issues across rows
- Parse CSV with `csv.DictReader`
- Apply detection rules per category
- Collect issues: row number, CN text, EN text, problem, suggested fix
- Group/deduplicate identical issues
Common detection categories for Chinese→English:
- **Buddhist terminology**: 正念→mindfulness (not "righteous thoughts"), 布施→generosity (not "alms"), 胜解→resolute conviction, etc.
- **Identity terms**: 学士/修士/胜士/智士 are practice stages, not "bachelor/monk/winner/wise man"
- **Literal machine translations**: "Is we"→"if we", "hard drive" for 硬盘 (endurance), "Walk without letting go" for 行舍不放逸
- **四摄法 terms**: 同事→"acting in harmony" (not "colleagues"), 爱语→"kind speech" (not "love words")
- **Grammar**: subject-verb agreement, "have it been"→"has it been", unbalanced quotes
- **Typos/formatting**: "AndroidAndroid", "IOS"→"iOS", unbalanced HTML tags, Chinese punctuation in English
- **UI terminology**: "Suspended"→"Paused" for media, product name consistency
- **Inconsistency**: same CN term translated differently across rows (e.g., "Bodhi Navigator" vs "Bodhi Navigation")
Common detection categories:
- **Buddhist terminology**: 正念→mindfulness (not "righteous thoughts"), 布施→generosity (not "alms")
- **Identity terms**: 学士/修士/胜士/智士 are practice stages, not titles
- **Literal machine translations**: "hard drive" for 硬盘 (endurance)
- **四摄法 terms**: 同事→"acting in harmony", 爱语→"kind speech"
- **Grammar**: subject-verb agreement, unbalanced quotes
- **Typos/formatting**: Chinese punctuation in English, "IOS"→"iOS"
- **Inconsistency**: same CN term translated differently across rows
### 4. Deduplicate into unique issue categories
The same error pattern often repeats across many rows (e.g., "subversion" for 覆 appears in 6+ rows). Group these into single entries in the .dj file — one entry per unique problem, with a list of affected rows.
### 5. Write edit-suggestions.dj
### 4. Write edit-suggestions.dj
Format:
```
# 1
original: <Chinese text or key term>
translated: <current English>
<Explanation of the problem and suggested fix.>
<Explanation and suggested fix.>
# 2
...
```
Each entry gets a `# N` header, `original:` and `translated:` fields, then a free-text explanation. End with suggested replacement text. Mention affected row numbers. For globally-wrong terms, note "Change globally."
One entry per problem category, not per row. Mention affected row numbers.
Do NOT write one entry per CSV row — group by problem type.
## Workflow B: .dj comparison file review
### 6. Sanity check
Use when input is a `.dj` comparison file (Chinese/English alternating line pairs). Produces `translation-findings.dj` and applies patches.
Run a quick second pass to catch: empty English fields, Chinese characters leaking into English column, untranslated rows (CN == EN), trailing whitespace.
### 1. Read the full file
Use `terminal: cat``read_file` deduplicates within a session.
### 2. Scan for problems (ordered by severity)
**Terms database drift** (systematic):
- Cross-reference glossary terms against the MPI terms database
- HTTP API: `http://localhost:8910/search?q=...` (start: `python3 /home/user/documents/mpi/terms-search/server.py &`)
- Prefer DoT定稿 > 内部特色词 > 佛教术语 > 经论名
- Fix both glossary comments AND body text
- See `references/terms-db-alignment.md` for batch-lookup patterns
**Real errors** (affect meaning):
- Mistranslation of key terms
- Garbled/malformed source text
- Wrong proper names or technical terms
**Inconsistency** (confusing but not wrong):
- Terminology drift across file
- Numbering style chaos
- Grammatical voice/person shifts
**Cleanup needed**:
- Processing artifacts (HTML comments, markers)
- Stray spacing in Chinese text
- Awkward line splits
- Odd word choices
**Missing content**: bare headings with no body — flag, don't invent.
### 3. Dump findings to `translation-findings.dj`
```
Finding N — Title (line numbers)
Chinese: ...
English: ...
Issue: description
```
### 4. Apply fixes with `patch`
Surgical string replacement. Verify every patch with `cat` — never rely on `read_file` (session dedup).
## Buddhist terminology reference
See `references/buddhist-terminology.md` for Chinese-English term mappings and common pitfalls.
## Pitfalls
- **Don't use heredocs or `-c` for multi-line Python** — write to `/tmp/script.py` first, then `python3 /tmp/script.py`. The terminal tool may block heredocs as long-lived processes.
- **Deduplicate aggressively** — 80+ raw issues may collapse to 20-25 unique categories. Writing one .dj entry per CSV row is useless noise.
- **Buddhist terminology is technical** — don't guess. 正念 is mindfulness (sati), not "righteous thoughts." 唯识 is Yogācāra/Consciousness-Only, not "knowledge and view alone." When uncertain, flag for human review rather than confidently suggesting wrong fixes.
- **Don't delete the comparison/对照 file** — translation projects keep these as intentional work artifacts.
- **Don't use heredocs or `-c`** — write to `/tmp/script.py` first
- **Deduplicate aggressively** — group by problem type, not per-row
- **Buddhist terminology is technical** — don't guess. When uncertain, flag for review
- **Never delete .dj comparison files** — intentional work artifacts
- **Verify patches with `cat`** — `read_file` dedup makes it unreliable
- **Re-read before fixing** — user may have made interim edits
## .dj file format reference
## References
```
# N
original: <source text>
translated: <current translation>
<Free-text explanation and suggestion. Can be multiple paragraphs.>
# N+1
...
```
Entries may end with `{% TK %}` to mark "to check" items. The file lives alongside the source CSV/XLSX in the same directory.
- `references/buddhist-terminology.md` — Chinese-English Buddhist term mappings and pitfalls
- `references/terms-db-alignment.md` — Batch-aligning glossary terms against the MPI terms database
@@ -0,0 +1,47 @@
# Buddhist Text Translation — Terminology
Terms encountered in Chinese-English translation of Dharma study materials. These may vary by translator/context; document actual usage per-project.
## Section headers (common triad)
| Chinese | English options seen | Notes |
|---------|---------------------|-------|
| 法义 | Understanding, Dharma Teachings | |
| 思考 | Contemplation, Reflection | Consistency within a document matters more than which word |
| 练习 | Practice, Application, Exercises | "Application" seen as section header; "Practice"/"Exercise" in running text |
## Key Buddhist terms
| Chinese | English | Pitfalls |
|---------|---------|----------|
| 慈经 | Metta Sutta (Karaniya Metta Sutta) | NOT "Mettavihari Sutta" |
| 回向 | Dedication (of merit) | |
| 因缘之网 | Web of Causes and Conditions | Also "Network of Causes and Conditions" |
| 感恩 | Gratitude | |
| 众生 | sentient beings | Consistent throughout |
| 使人内心调柔 | makes one's heart gentle | 使人 = makes ONE(self), never "makes others" |
| 利益思维 | benefit-oriented thinking | NOT "mindset of benefiting others" — it's about considering benefits TO oneself |
| 恩田 | field of gratitude / gratitude as a field of merit | |
| 观照 | attend to the mind / mindful observation | Contemplative practice, not intellectual study. NOT "observe" (passive) or "study" (analytical). |
| 闻思修 | hearing, contemplating, cultivating | 修 = broad cultivation/practice, not specifically 禅 (meditation). Distinct from 禅修 (meditative cultivation). |
| 八步三禅 | Eight Steps and Three Meditations | Community-specific structured contemplative method |
| 传帮带 | transmit, help, guide (three-part mentoring) | Core community methodology |
| 分灯 | lamp-dividing (decentralization) | Deliberate decentralization of authority across nodes |
| 自觉 | self-awareness, voluntary commitment | First of the "Three Spirits" |
| 法治 | rule-based governance | Second of the "Three Spirits" |
| 无我利他 | selfless service to others | Third of the "Three Spirits" |
| 凡夫心 | ordinary mind | Mind governed by afflictions, contrasted with awakened mind |
| 贪嗔痴 | greed, anger, ignorance (三毒) | The three root poisons: rāga, dveṣa, moha |
| 愿心 | mind of vows, bodhicitta aspiration | Plural "vows" in English |
| 重要感、优越感、主宰欲 | sense of importance, superiority, desire to control | Three ego-driven motivations |
## Structural patterns
- Section numbering: Chinese uses 一、二、三... English should pick one style (Part One/Two, First/Second, I/II) and stick with it.
- Poetry/prayer blocks: Chinese uses parallel structures (感恩... 感恩...; 愿... 愿...). English must match the parallelism.
- 愿 (yuàn) at sentence start = optative "May..." — not "we hope that", not "we should".
## Formatting artifacts
- Stray spaces between Chinese characters (eg. `感 恩 研 究`) are justified-text paste artifacts from the source document — remove them.
- `<!-- === Progress : Below are unprocessed === -->` is a processing marker — remove from final file.
@@ -0,0 +1,61 @@
# Terms Database Alignment
Batch-align translation glossary entries and body text against the MPI terms database.
## Setup
Start the HTTP API server if not running:
```
python3 /home/user/documents/mpi/terms-search/server.py &
```
Server listens on port 8910.
## Batch lookup pattern
Use Python via execute_code to query the API for multiple terms:
```python
import urllib.request, json, urllib.parse
terms = ["三无漏学", "八步三禅", "闻思修", ...]
for term in terms:
q = urllib.parse.quote(term)
resp = urllib.request.urlopen(f"http://localhost:8910/search?q={q}&limit=5", timeout=10)
data = json.loads(resp.read())
# Filter to authoritative sources
author_sources = ["DoT定稿", "内部特色词", "佛教术语", "经论名"]
relevant = [r for r in data["results"] if r["source"] in author_sources]
# Compare against current translation, report mismatches
```
Or with curl:
```
curl -s "http://localhost:8910/search?q=三级修学&limit=5" | python3 -c "import sys,json; ..."
```
## Priority ranking
When the same term has entries in multiple source tables, prefer:
1. DoT定稿 (highest authority — final translation decisions)
2. 内部特色词 (MPI internal terminology)
3. 佛教术语 (general Buddhist terminology)
4. 经论名 (sutra/shastra titles)
## Alignment workflow
1. Extract all Chinese glossary terms from `{% "TERM" ... %}` blocks in the .dj file
2. Extract body-text domain terms that may not have glossary entries
3. Batch-query each term against the HTTP API
4. Filter results to authoritative source tables
5. Compare DB canonical translation against current file translation
6. Flag mismatches where DB entry differs materially from current
7. Apply fixes with `patch` tool — fix both glossary comments AND body text occurrences
8. Verify with `grep` that no old terms remain
## Pitfalls
- `replace_all` can create doubled words when the surrounding context already contains the replacement string (e.g., "The Eight Steps" → "The The Eight Steps"). Prefer targeted single-replacement patches.
- The `search.py` CLI does not support `src:` or `loc:` filters — use the HTTP API.
- Start patches from the bottom of the file upward to preserve line numbers.
- Some DB entries are contextual phrases (e.g., "珍惜法缘" → a full sentence), not standalone term translations. Use standalone term entries where available.