mirror of
https://github.com/JimLiu/baoyu-skills.git
synced 2026-07-12 22:09:48 +08:00
Compare commits
8 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| f6cef6bcbb | |||
| 4300e6899c | |||
| 4435366898 | |||
| 69cd89184e | |||
| 5771e6d8c5 | |||
| 970f5e741a | |||
| 8cea550627 | |||
| 82029160d1 |
@@ -6,7 +6,7 @@
|
||||
},
|
||||
"metadata": {
|
||||
"description": "Skills shared by Baoyu for improving daily work efficiency",
|
||||
"version": "1.53.0"
|
||||
"version": "1.54.1"
|
||||
},
|
||||
"plugins": [
|
||||
{
|
||||
|
||||
@@ -2,6 +2,24 @@
|
||||
|
||||
English | [中文](./CHANGELOG.zh.md)
|
||||
|
||||
## 1.54.1 - 2026-03-07
|
||||
|
||||
### Fixes
|
||||
- `baoyu-post-to-x`: keep composed posts open in Chrome so users can review and publish manually
|
||||
|
||||
### Documentation
|
||||
- `baoyu-post-to-x`: document default post type selection and manual publishing flow
|
||||
- `README`: add Star History charts to the English and Chinese READMEs
|
||||
|
||||
## 1.54.0 - 2026-03-06
|
||||
|
||||
### Features
|
||||
- `baoyu-format-markdown`: improve title and summary generation with style-differentiated candidates, prohibited patterns, and hook-first principles
|
||||
- `baoyu-markdown-to-html`: add `--cite` option to convert ordinary external links to numbered bottom citations
|
||||
- `baoyu-post-to-wechat`: enable bottom citations by default for markdown input, add `--no-cite` flag to disable
|
||||
- `baoyu-translate`: support external glossary files via `glossary_files` in EXTEND.md (markdown table or YAML)
|
||||
- `baoyu-translate`: add frontmatter transformation rules to rename source metadata fields with `source` prefix
|
||||
|
||||
## 1.53.0 - 2026-03-06
|
||||
|
||||
### Features
|
||||
|
||||
@@ -2,6 +2,24 @@
|
||||
|
||||
[English](./CHANGELOG.md) | 中文
|
||||
|
||||
## 1.54.1 - 2026-03-07
|
||||
|
||||
### 修复
|
||||
- `baoyu-post-to-x`:保持已填充的发帖窗口处于打开状态,方便用户手动检查并发布
|
||||
|
||||
### 文档
|
||||
- `baoyu-post-to-x`:补充默认帖子类型选择规则和手动发布流程说明
|
||||
- `README`:为中英文 README 新增 Star History 图表
|
||||
|
||||
## 1.54.0 - 2026-03-06
|
||||
|
||||
### 新功能
|
||||
- `baoyu-format-markdown`:优化标题和摘要生成,支持多风格候选(颠覆型、方案型、悬念型、数字型),新增禁用模式和钩子优先原则
|
||||
- `baoyu-markdown-to-html`:新增 `--cite` 选项,将普通外链转换为底部编号引用
|
||||
- `baoyu-post-to-wechat`:Markdown 输入默认启用底部引用,新增 `--no-cite` 标志可关闭
|
||||
- `baoyu-translate`:EXTEND.md 支持 `glossary_files` 加载外部术语表文件(Markdown 表格或 YAML 格式)
|
||||
- `baoyu-translate`:新增 frontmatter 转换规则,翻译时将源文章元数据字段添加 `source` 前缀
|
||||
|
||||
## 1.53.0 - 2026-03-06
|
||||
|
||||
### 新功能
|
||||
|
||||
@@ -504,6 +504,8 @@ Smart article illustration skill with Type × Style two-dimension approach. Anal
|
||||
|
||||
Post content and articles to X (Twitter). Supports regular posts with images and X Articles (long-form Markdown). Uses real Chrome with CDP to bypass anti-automation.
|
||||
|
||||
Plain text input is treated as a regular post. Markdown files are treated as X Articles. Scripts fill content into the browser, and the user reviews and publishes manually.
|
||||
|
||||
```bash
|
||||
# Post with text
|
||||
/baoyu-post-to-x "Hello from Claude Code!"
|
||||
@@ -961,3 +963,7 @@ This skill uses a reverse-engineered X (Twitter) API.
|
||||
## License
|
||||
|
||||
MIT
|
||||
|
||||
## Star History
|
||||
|
||||
[](https://www.star-history.com/#JimLiu/baoyu-skills&Date)
|
||||
|
||||
@@ -504,6 +504,8 @@ npx skills add jimliu/baoyu-skills
|
||||
|
||||
发布内容和文章到 X (Twitter)。支持带图片的普通帖子和 X 文章(长篇 Markdown)。使用真实 Chrome + CDP 绕过反自动化检测。
|
||||
|
||||
纯文本输入默认按普通帖子处理,Markdown 文件默认按 X 文章处理。脚本会将内容填入浏览器,用户需手动检查并发布。
|
||||
|
||||
```bash
|
||||
# 发布文字
|
||||
/baoyu-post-to-x "Hello from Claude Code!"
|
||||
@@ -961,3 +963,7 @@ HTTP_PROXY=http://127.0.0.1:7890 HTTPS_PROXY=http://127.0.0.1:7890 /baoyu-danger
|
||||
## 许可证
|
||||
|
||||
MIT
|
||||
|
||||
## Star History
|
||||
|
||||
[](https://www.star-history.com/#JimLiu/baoyu-skills&Date)
|
||||
|
||||
@@ -168,29 +168,55 @@ Check for YAML frontmatter (`---` block). Create if missing.
|
||||
|
||||
**Title Generation:**
|
||||
|
||||
Generate 3 candidate titles with different angles/styles. Present to user for selection:
|
||||
Whether or not a title already exists, always run the title optimization flow (unless `auto_select_title` is set).
|
||||
|
||||
**Preparation** — read the full text and extract:
|
||||
- Core argument (one sentence: "what is this article about?")
|
||||
- Most impactful opinion or conclusion
|
||||
- Reader pain point or curiosity trigger
|
||||
- Most memorable metaphor or golden quote
|
||||
|
||||
**Generate 3-4 style-differentiated candidates:**
|
||||
|
||||
| Style | Characteristics | Example |
|
||||
|-------|----------------|---------|
|
||||
| Subversive | Deny common practice, create conflict | "All de-AI-flavor prompts are wrong" |
|
||||
| Solution | Give the answer directly, promise value | "One recipe to make AI write in your voice" |
|
||||
| Suspense | Reveal half, spark curiosity | "It took me six months to find how to remove AI flavor" |
|
||||
| Concrete number | Use numbers for credibility | "150 lines of docs taught AI my writing style" |
|
||||
|
||||
Present to user:
|
||||
|
||||
```
|
||||
Pick a title:
|
||||
|
||||
1. [Title A] — [angle/style note]
|
||||
2. [Title B] — [angle/style note]
|
||||
3. [Title C] — [angle/style note]
|
||||
1. [Title A] — (recommended)
|
||||
2. [Title B] — [style note]
|
||||
3. [Title C] — [style note]
|
||||
|
||||
Enter number, or type a custom title:
|
||||
```
|
||||
|
||||
Title principles:
|
||||
- Engaging, sparks reading interest
|
||||
- Captures core message or most compelling angle
|
||||
- Accurate, avoids clickbait
|
||||
- Vary angles: e.g. story-driven, conclusion-driven, question-driven
|
||||
Put the strongest hook first and mark it (recommended).
|
||||
|
||||
If frontmatter already has `title`, skip selection and use it. If first line is H1, extract to frontmatter as default title but still offer alternatives.
|
||||
**Title principles:**
|
||||
- **Hook in first 5 chars**: create information gap or cognitive conflict
|
||||
- **Specific > abstract**: "150 lines" beats "a document"
|
||||
- **Negation > affirmation**: "you're doing it wrong" beats "the right way"
|
||||
- **Conversational**: like chatting with a friend, not a paper title
|
||||
- **Max ~25 chars**: longer titles get truncated in feeds
|
||||
- **Accurate, not clickbait**: the article must deliver what the title promises
|
||||
|
||||
**Prohibited patterns:**
|
||||
- "浅谈 XX"、"关于 XX 的思考"、"XX 的探索与实践"
|
||||
- "震惊!"、"万字长文"、"建议收藏"
|
||||
- Pure questions without direction: "AI 写作的未来在哪里?"
|
||||
|
||||
If first line is H1, extract to frontmatter and remove from body. If frontmatter already has `title`, include it as context but still generate fresh candidates.
|
||||
|
||||
**Summary Generation:**
|
||||
|
||||
Generate 3 candidate summaries with different focuses. Present to user for selection:
|
||||
Generate 3 candidate summaries with different angles. Present to user:
|
||||
|
||||
```
|
||||
Pick a summary:
|
||||
@@ -202,11 +228,17 @@ Pick a summary:
|
||||
Enter number, or type a custom summary:
|
||||
```
|
||||
|
||||
Summary principles:
|
||||
**Summary principles:**
|
||||
- 80-150 characters, precise and information-rich
|
||||
- Convey article's core value, not just topic
|
||||
- Vary focuses: e.g. problem-driven, result-driven, insight-driven
|
||||
- Avoid generic descriptions like "本文介绍了..."
|
||||
- Convey **core value** to the reader, not just the topic
|
||||
- Vary angles: problem-driven, result-driven, insight-driven
|
||||
- **Hook the reader**: make them want to read the full article
|
||||
- Use concrete details (numbers, outcomes, specific methods) over vague descriptions
|
||||
|
||||
**Prohibited patterns:**
|
||||
- "本文介绍了..."、"本文探讨了..."
|
||||
- Pure topic description without value proposition
|
||||
- Repeating the title in different words
|
||||
|
||||
If frontmatter already has `summary`, skip selection and use it.
|
||||
|
||||
@@ -240,9 +272,11 @@ Apply formatting guided by the Step 2 analysis. The goal is making the content s
|
||||
|
||||
**Formatting principles — what TO do:**
|
||||
- Preserve the author's voice, tone, and every word
|
||||
- Use bold sparingly for genuinely important points
|
||||
- **Bold key conclusions and core takeaways** — the sentences a reader would highlight
|
||||
- Extract parallel items from prose into lists only when the structure is clearly there
|
||||
- Add headings where the topic genuinely shifts
|
||||
- Add headings where the topic genuinely shifts — prefer vivid, specific headings over generic ones (e.g., "3 天搞定 vs 传统方案" over "方案对比")
|
||||
- Use tables for comparisons or structured data buried in prose
|
||||
- Use blockquotes for golden quotes, memorable statements, or important warnings
|
||||
- Fix obvious typos (based on Step 2 findings)
|
||||
|
||||
### Step 5: Save Formatted File
|
||||
@@ -319,7 +353,7 @@ Display a report summarizing all changes made:
|
||||
- Tables created: X
|
||||
- Code markers added: X
|
||||
- Blockquotes added: X
|
||||
- Typos fixed: X [list each: "原文" → "修正"]
|
||||
- Typos fixed: X [list each: "original" → "corrected"]
|
||||
|
||||
**Typography Script:**
|
||||
- CJK spacing: [applied/skipped]
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
---
|
||||
name: baoyu-markdown-to-html
|
||||
description: Converts Markdown to styled HTML with WeChat-compatible themes. Supports code highlighting, math, PlantUML, footnotes, alerts, and infographics. Use when user asks for "markdown to html", "convert md to html", "md转html", or needs styled HTML output from markdown.
|
||||
description: Converts Markdown to styled HTML with WeChat-compatible themes. Supports code highlighting, math, PlantUML, footnotes, alerts, infographics, and optional bottom citations for external links. Use when user asks for "markdown to html", "convert md to html", "md转html", "微信外链转底部引用", or needs styled HTML output from markdown.
|
||||
---
|
||||
|
||||
# Markdown to HTML Converter
|
||||
@@ -98,15 +98,26 @@ if (Test-Path "$HOME/.baoyu-skills/baoyu-post-to-wechat/EXTEND.md") { Select-Str
|
||||
|
||||
| Theme | Description |
|
||||
|-------|-------------|
|
||||
| `default` (Recommended) | 经典主题 - 传统排版,标题居中带底边,二级标题白字彩底 |
|
||||
| `grace` | 优雅主题 - 文字阴影,圆角卡片,精致引用块 |
|
||||
| `simple` | 简洁主题 - 现代极简风,不对称圆角,清爽留白 |
|
||||
| `modern` | 现代主题 - 大圆角、药丸形标题、宽松行距(搭配 `--color red` 还原传统红金风格) |
|
||||
| `default` (Recommended) | Classic - traditional layout, centered title with bottom border, H2 with white text on colored background |
|
||||
| `grace` | Elegant - text shadow, rounded cards, refined blockquotes |
|
||||
| `simple` | Minimal - modern minimalist, asymmetric rounded corners, clean whitespace |
|
||||
| `modern` | Modern - large radius, pill-shaped titles, relaxed line height (pair with `--color red` for traditional red-gold style) |
|
||||
|
||||
### Step 1.5: Determine Citation Mode
|
||||
|
||||
**Default**: Off. Do not ask by default.
|
||||
|
||||
**Enable only if the user explicitly asks** for "微信外链转底部引用", "底部引用", "文末引用", or passes `--cite`.
|
||||
|
||||
**Behavior when enabled**:
|
||||
- Ordinary external links are rendered with numbered superscripts and collected under a final `引用链接` section.
|
||||
- `https://mp.weixin.qq.com/...` links stay as direct links and are not moved to the bottom.
|
||||
- Bare links where link text equals URL stay inline.
|
||||
|
||||
### Step 2: Convert
|
||||
|
||||
```bash
|
||||
${BUN_X} ${SKILL_DIR}/scripts/main.ts <markdown_file> --theme <theme>
|
||||
${BUN_X} ${SKILL_DIR}/scripts/main.ts <markdown_file> --theme <theme> [--cite]
|
||||
```
|
||||
|
||||
### Step 3: Report Result
|
||||
@@ -128,6 +139,7 @@ ${BUN_X} ${SKILL_DIR}/scripts/main.ts <markdown_file> [options]
|
||||
| `--font-family <name>` | Font: sans, serif, serif-cjk, mono, or CSS value | theme default |
|
||||
| `--font-size <N>` | Font size: 14px, 15px, 16px, 17px, 18px | 16px |
|
||||
| `--title <title>` | Override title from frontmatter | |
|
||||
| `--cite` | Convert external links to bottom citations, append `引用链接` section | false (off) |
|
||||
| `--keep-title` | Keep the first heading in content | false (removed) |
|
||||
| `--help` | Show help | |
|
||||
|
||||
@@ -135,19 +147,19 @@ ${BUN_X} ${SKILL_DIR}/scripts/main.ts <markdown_file> [options]
|
||||
|
||||
| Name | Hex | Label |
|
||||
|------|-----|-------|
|
||||
| blue | #0F4C81 | 经典蓝 |
|
||||
| green | #009874 | 翡翠绿 |
|
||||
| vermilion | #FA5151 | 活力橘 |
|
||||
| yellow | #FECE00 | 柠檬黄 |
|
||||
| purple | #92617E | 薰衣紫 |
|
||||
| sky | #55C9EA | 天空蓝 |
|
||||
| rose | #B76E79 | 玫瑰金 |
|
||||
| olive | #556B2F | 橄榄绿 |
|
||||
| black | #333333 | 石墨黑 |
|
||||
| gray | #A9A9A9 | 雾烟灰 |
|
||||
| pink | #FFB7C5 | 樱花粉 |
|
||||
| red | #A93226 | 中国红 |
|
||||
| orange | #D97757 | 暖橘 (modern default) |
|
||||
| blue | #0F4C81 | Classic Blue |
|
||||
| green | #009874 | Emerald Green |
|
||||
| vermilion | #FA5151 | Vibrant Vermilion |
|
||||
| yellow | #FECE00 | Lemon Yellow |
|
||||
| purple | #92617E | Lavender Purple |
|
||||
| sky | #55C9EA | Sky Blue |
|
||||
| rose | #B76E79 | Rose Gold |
|
||||
| olive | #556B2F | Olive Green |
|
||||
| black | #333333 | Graphite Black |
|
||||
| gray | #A9A9A9 | Smoke Gray |
|
||||
| pink | #FFB7C5 | Sakura Pink |
|
||||
| red | #A93226 | China Red |
|
||||
| orange | #D97757 | Warm Orange (modern default) |
|
||||
|
||||
**Examples:**
|
||||
|
||||
@@ -161,6 +173,9 @@ ${BUN_X} ${SKILL_DIR}/scripts/main.ts article.md --theme grace
|
||||
# Theme with custom color
|
||||
${BUN_X} ${SKILL_DIR}/scripts/main.ts article.md --theme modern --color red
|
||||
|
||||
# Enable bottom citations for ordinary external links
|
||||
${BUN_X} ${SKILL_DIR}/scripts/main.ts article.md --cite
|
||||
|
||||
# Keep the first heading in content
|
||||
${BUN_X} ${SKILL_DIR}/scripts/main.ts article.md --keep-title
|
||||
|
||||
@@ -200,10 +215,10 @@ ${BUN_X} ${SKILL_DIR}/scripts/main.ts article.md --title "My Article"
|
||||
|
||||
| Theme | Description |
|
||||
|-------|-------------|
|
||||
| `default` | 经典主题 - 传统排版,标题居中带底边,二级标题白字彩底 |
|
||||
| `grace` | 优雅主题 - 文字阴影,圆角卡片,精致引用块 (by @brzhang) |
|
||||
| `simple` | 简洁主题 - 现代极简风,不对称圆角,清爽留白 (by @okooo5km) |
|
||||
| `modern` | 现代主题 - 大圆角、药丸形标题、宽松行距(搭配 `--color red` 还原传统红金风格) |
|
||||
| `default` | Classic - traditional layout, centered title with bottom border, H2 with white text on colored background |
|
||||
| `grace` | Elegant - text shadow, rounded cards, refined blockquotes (by @brzhang) |
|
||||
| `simple` | Minimal - modern minimalist, asymmetric rounded corners, clean whitespace (by @okooo5km) |
|
||||
| `modern` | Modern - large radius, pill-shaped titles, relaxed line height (pair with `--color red` for traditional red-gold style) |
|
||||
|
||||
## Supported Markdown Features
|
||||
|
||||
@@ -215,7 +230,7 @@ ${BUN_X} ${SKILL_DIR}/scripts/main.ts article.md --title "My Article"
|
||||
| Inline code | `` `code` `` |
|
||||
| Tables | GitHub-flavored markdown tables |
|
||||
| Images | `` |
|
||||
| Links | `[text](url)` with footnote references |
|
||||
| Links | `[text](url)`; add `--cite` to move ordinary external links into bottom references |
|
||||
| Blockquotes | `> quote` |
|
||||
| Lists | `-` unordered, `1.` ordered |
|
||||
| Alerts | `> [!NOTE]`, `> [!WARNING]`, etc. |
|
||||
|
||||
@@ -122,11 +122,15 @@ function parseFrontmatter(content: string): { frontmatter: Record<string, string
|
||||
return { frontmatter, body: match[2]! };
|
||||
}
|
||||
|
||||
export async function convertMarkdown(markdownPath: string, options?: { title?: string; theme?: string; keepTitle?: boolean }): Promise<ParsedResult> {
|
||||
export async function convertMarkdown(
|
||||
markdownPath: string,
|
||||
options?: { title?: string; theme?: string; keepTitle?: boolean; citeStatus?: boolean }
|
||||
): Promise<ParsedResult> {
|
||||
const baseDir = path.dirname(markdownPath);
|
||||
const content = fs.readFileSync(markdownPath, 'utf-8');
|
||||
const theme = options?.theme ?? 'default';
|
||||
const keepTitle = options?.keepTitle ?? false;
|
||||
const citeStatus = options?.citeStatus ?? false;
|
||||
|
||||
const { frontmatter, body } = parseFrontmatter(content);
|
||||
|
||||
@@ -191,7 +195,7 @@ export async function convertMarkdown(markdownPath: string, options?: { title?:
|
||||
|
||||
const modifiedMarkdown = `---\n${Object.entries(frontmatter).map(([k, v]) => `${k}: ${v}`).join('\n')}\n---\n${modifiedBody}`;
|
||||
|
||||
console.error(`[markdown-to-html] Rendering with theme: ${theme}, keepTitle: ${keepTitle}`);
|
||||
console.error(`[markdown-to-html] Rendering with theme: ${theme}, keepTitle: ${keepTitle}, citeStatus: ${citeStatus}`);
|
||||
|
||||
const themeDefaults = THEME_STYLE_DEFAULTS[theme] ?? {};
|
||||
const style: StyleConfig = { ...DEFAULT_STYLE, ...themeDefaults };
|
||||
@@ -199,7 +203,7 @@ export async function convertMarkdown(markdownPath: string, options?: { title?:
|
||||
const css = normalizeThemeCss(buildCss(baseCss, themeCss, style));
|
||||
const codeThemeCss = loadCodeThemeCss('github');
|
||||
|
||||
const renderer = initRenderer({});
|
||||
const renderer = initRenderer({ citeStatus });
|
||||
const { html: baseHtml, readingTime } = renderMarkdown(modifiedMarkdown, renderer);
|
||||
let htmlContent = postProcessHtml(baseHtml, readingTime, renderer);
|
||||
if (!keepTitle) htmlContent = removeFirstHeading(htmlContent);
|
||||
@@ -263,6 +267,7 @@ Usage:
|
||||
Options:
|
||||
--title <title> Override title
|
||||
--theme <name> Theme name (default, grace, simple). Default: default
|
||||
--cite Convert ordinary external links to bottom citations. Default: off
|
||||
--keep-title Keep the first heading in content. Default: false (removed)
|
||||
--help Show this help
|
||||
|
||||
@@ -284,6 +289,7 @@ Output JSON format:
|
||||
Example:
|
||||
npx -y bun main.ts article.md
|
||||
npx -y bun main.ts article.md --theme grace
|
||||
npx -y bun main.ts article.md --cite
|
||||
`);
|
||||
process.exit(0);
|
||||
}
|
||||
@@ -297,6 +303,7 @@ async function main(): Promise<void> {
|
||||
let markdownPath: string | undefined;
|
||||
let title: string | undefined;
|
||||
let theme: string | undefined;
|
||||
let citeStatus = false;
|
||||
let keepTitle = false;
|
||||
|
||||
for (let i = 0; i < args.length; i++) {
|
||||
@@ -305,6 +312,8 @@ async function main(): Promise<void> {
|
||||
title = args[++i];
|
||||
} else if (arg === '--theme' && args[i + 1]) {
|
||||
theme = args[++i];
|
||||
} else if (arg === '--cite') {
|
||||
citeStatus = true;
|
||||
} else if (arg === '--keep-title') {
|
||||
keepTitle = true;
|
||||
} else if (!arg.startsWith('-')) {
|
||||
@@ -322,7 +331,7 @@ async function main(): Promise<void> {
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
const result = await convertMarkdown(markdownPath, { title, theme, keepTitle });
|
||||
const result = await convertMarkdown(markdownPath, { title, theme, keepTitle, citeStatus });
|
||||
console.log(JSON.stringify(result, null, 2));
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
---
|
||||
name: baoyu-post-to-wechat
|
||||
description: Posts content to WeChat Official Account (微信公众号) via API or Chrome CDP. Supports article posting (文章) with HTML, markdown, or plain text input, and image-text posting (贴图, formerly 图文) with multiple images. Use when user mentions "发布公众号", "post to wechat", "微信公众号", or "贴图/图文/文章".
|
||||
description: Posts content to WeChat Official Account (微信公众号) via API or Chrome CDP. Supports article posting (文章) with HTML, markdown, or plain text input, and image-text posting (贴图, formerly 图文) with multiple images. Markdown article workflows default to converting ordinary external links into bottom citations for WeChat-friendly output. Use when user mentions "发布公众号", "post to wechat", "微信公众号", or "贴图/图文/文章".
|
||||
---
|
||||
|
||||
# Post to WeChat Official Account
|
||||
@@ -252,10 +252,15 @@ WECHAT_APP_SECRET=<user_input>
|
||||
|
||||
**CRITICAL**: Publishing scripts handle markdown conversion internally. Do NOT pre-convert markdown to HTML — pass the original markdown file directly. This ensures the API method renders images as `<img>` tags (for API upload) while the browser method uses placeholders (for paste-and-replace workflow).
|
||||
|
||||
**Markdown citation default**:
|
||||
- For markdown input, ordinary external links are converted to bottom citations by default.
|
||||
- Use `--no-cite` only if the user explicitly wants to keep ordinary external links inline.
|
||||
- Existing HTML input is left as-is; no extra citation conversion is applied.
|
||||
|
||||
**API method** (accepts `.md` or `.html`):
|
||||
|
||||
```bash
|
||||
${BUN_X} ${SKILL_DIR}/scripts/wechat-api.ts <file> --theme <theme> [--color <color>] [--title <title>] [--summary <summary>] [--author <author>] [--cover <cover_path>]
|
||||
${BUN_X} ${SKILL_DIR}/scripts/wechat-api.ts <file> --theme <theme> [--color <color>] [--title <title>] [--summary <summary>] [--author <author>] [--cover <cover_path>] [--no-cite]
|
||||
```
|
||||
|
||||
**CRITICAL**: Always include `--theme` parameter. Never omit it, even if using `default`. Only include `--color` if explicitly set by user or EXTEND.md.
|
||||
@@ -274,7 +279,7 @@ If script parameters do not expose the two comment fields, still ensure final AP
|
||||
**Browser method** (accepts `--markdown` or `--html`):
|
||||
|
||||
```bash
|
||||
${BUN_X} ${SKILL_DIR}/scripts/wechat-article.ts --markdown <markdown_file> --theme <theme> [--color <color>]
|
||||
${BUN_X} ${SKILL_DIR}/scripts/wechat-article.ts --markdown <markdown_file> --theme <theme> [--color <color>] [--no-cite]
|
||||
${BUN_X} ${SKILL_DIR}/scripts/wechat-article.ts --html <html_file>
|
||||
```
|
||||
|
||||
|
||||
@@ -11,6 +11,9 @@ ${BUN_X} ./scripts/wechat-article.ts --markdown article.md
|
||||
# With theme
|
||||
${BUN_X} ./scripts/wechat-article.ts --markdown article.md --theme grace
|
||||
|
||||
# Disable bottom citations for ordinary external links
|
||||
${BUN_X} ./scripts/wechat-article.ts --markdown article.md --no-cite
|
||||
|
||||
# With explicit options
|
||||
${BUN_X} ./scripts/wechat-article.ts --markdown article.md --author "作者名" --summary "摘要"
|
||||
```
|
||||
@@ -21,6 +24,7 @@ ${BUN_X} ./scripts/wechat-article.ts --markdown article.md --author "作者名"
|
||||
|-----------|-------------|
|
||||
| `--markdown <path>` | Markdown file to convert and post |
|
||||
| `--theme <name>` | Theme: default, grace, simple, modern |
|
||||
| `--no-cite` | Keep ordinary external links inline instead of converting them to bottom citations |
|
||||
| `--title <text>` | Override title (auto-extracted from markdown) |
|
||||
| `--author <name>` | Author name |
|
||||
| `--summary <text>` | Article summary |
|
||||
@@ -51,6 +55,8 @@ Regular paragraph with **bold** and *italic*.
|
||||
[Link text](https://example.com)
|
||||
```
|
||||
|
||||
Markdown mode converts ordinary external links into bottom citations by default for WeChat-friendly output. Use `--no-cite` to disable that behavior.
|
||||
|
||||
## Image Handling
|
||||
|
||||
1. **Parse**: Images in markdown are replaced with `WECHATIMGPH_N`
|
||||
|
||||
@@ -112,10 +112,14 @@ function parseFrontmatter(content: string): { frontmatter: Record<string, string
|
||||
return { frontmatter, body: match[2]! };
|
||||
}
|
||||
|
||||
export async function convertMarkdown(markdownPath: string, options?: { title?: string; theme?: string; color?: string }): Promise<ParsedResult> {
|
||||
export async function convertMarkdown(
|
||||
markdownPath: string,
|
||||
options?: { title?: string; theme?: string; color?: string; citeStatus?: boolean }
|
||||
): Promise<ParsedResult> {
|
||||
const baseDir = path.dirname(markdownPath);
|
||||
const content = fs.readFileSync(markdownPath, 'utf-8');
|
||||
const theme = options?.theme ?? 'default';
|
||||
const citeStatus = options?.citeStatus ?? true;
|
||||
|
||||
const { frontmatter, body } = parseFrontmatter(content);
|
||||
|
||||
@@ -185,8 +189,9 @@ export async function convertMarkdown(markdownPath: string, options?: { title?:
|
||||
|
||||
const renderArgs = ['-y', 'bun', renderScript, tempMdPath, '--theme', theme];
|
||||
if (options?.color) renderArgs.push('--color', options.color);
|
||||
if (citeStatus) renderArgs.push('--cite');
|
||||
|
||||
console.error(`[md-to-wechat] Rendering markdown with theme: ${theme}${options?.color ? `, color: ${options.color}` : ''}`);
|
||||
console.error(`[md-to-wechat] Rendering markdown with theme: ${theme}${options?.color ? `, color: ${options.color}` : ''}, citeStatus: ${citeStatus}`);
|
||||
|
||||
const result = spawnSync('npx', renderArgs, {
|
||||
stdio: ['inherit', 'pipe', 'pipe'],
|
||||
@@ -232,6 +237,7 @@ Options:
|
||||
--title <title> Override title
|
||||
--theme <name> Theme name (default, grace, simple, modern)
|
||||
--color <name|hex> Primary color (blue, green, vermilion, etc. or hex)
|
||||
--no-cite Disable bottom citations for ordinary external links
|
||||
--help Show this help
|
||||
|
||||
Output JSON format:
|
||||
@@ -251,6 +257,7 @@ Example:
|
||||
npx -y bun md-to-wechat.ts article.md
|
||||
npx -y bun md-to-wechat.ts article.md --theme grace
|
||||
npx -y bun md-to-wechat.ts article.md --theme modern --color blue
|
||||
npx -y bun md-to-wechat.ts article.md --no-cite
|
||||
`);
|
||||
process.exit(0);
|
||||
}
|
||||
@@ -265,6 +272,7 @@ async function main(): Promise<void> {
|
||||
let title: string | undefined;
|
||||
let theme: string | undefined;
|
||||
let color: string | undefined;
|
||||
let citeStatus = true;
|
||||
|
||||
for (let i = 0; i < args.length; i++) {
|
||||
const arg = args[i]!;
|
||||
@@ -274,6 +282,10 @@ async function main(): Promise<void> {
|
||||
theme = args[++i];
|
||||
} else if (arg === '--color' && args[i + 1]) {
|
||||
color = args[++i];
|
||||
} else if (arg === '--cite') {
|
||||
citeStatus = true;
|
||||
} else if (arg === '--no-cite') {
|
||||
citeStatus = false;
|
||||
} else if (!arg.startsWith('-')) {
|
||||
markdownPath = arg;
|
||||
}
|
||||
@@ -289,7 +301,7 @@ async function main(): Promise<void> {
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
const result = await convertMarkdown(markdownPath, { title, theme, color });
|
||||
const result = await convertMarkdown(markdownPath, { title, theme, color, citeStatus });
|
||||
console.log(JSON.stringify(result, null, 2));
|
||||
}
|
||||
|
||||
|
||||
@@ -307,7 +307,12 @@ function parseFrontmatter(content: string): { frontmatter: Record<string, string
|
||||
return { frontmatter, body: match[2]! };
|
||||
}
|
||||
|
||||
function renderMarkdownToHtml(markdownPath: string, theme: string = "default", color?: string): string {
|
||||
function renderMarkdownToHtml(
|
||||
markdownPath: string,
|
||||
theme: string = "default",
|
||||
color?: string,
|
||||
citeStatus: boolean = true
|
||||
): string {
|
||||
const __filename = fileURLToPath(import.meta.url);
|
||||
const __dirname = path.dirname(__filename);
|
||||
const renderScript = path.join(__dirname, "md", "render.ts");
|
||||
@@ -315,8 +320,9 @@ function renderMarkdownToHtml(markdownPath: string, theme: string = "default", c
|
||||
|
||||
const renderArgs = ["-y", "bun", renderScript, markdownPath, "--theme", theme];
|
||||
if (color) renderArgs.push("--color", color);
|
||||
if (citeStatus) renderArgs.push("--cite");
|
||||
|
||||
console.error(`[wechat-api] Rendering markdown with theme: ${theme}${color ? `, color: ${color}` : ""}`);
|
||||
console.error(`[wechat-api] Rendering markdown with theme: ${theme}${color ? `, color: ${color}` : ""}, citeStatus: ${citeStatus}`);
|
||||
const result = spawnSync("npx", renderArgs, {
|
||||
stdio: ["inherit", "pipe", "pipe"],
|
||||
cwd: baseDir,
|
||||
@@ -362,6 +368,7 @@ Options:
|
||||
--theme <name> Theme name for markdown (default, grace, simple, modern). Default: default
|
||||
--color <name|hex> Primary color (blue, green, vermilion, etc. or hex)
|
||||
--cover <path> Cover image path (local or URL)
|
||||
--no-cite Disable bottom citations for ordinary external links in markdown mode
|
||||
--dry-run Parse and render only, don't publish
|
||||
--help Show this help
|
||||
|
||||
@@ -390,6 +397,7 @@ Example:
|
||||
npx -y bun wechat-api.ts article.html --title "My Article"
|
||||
npx -y bun wechat-api.ts images/ --type newspic --title "Photo Album"
|
||||
npx -y bun wechat-api.ts article.md --dry-run
|
||||
npx -y bun wechat-api.ts article.md --no-cite
|
||||
`);
|
||||
process.exit(0);
|
||||
}
|
||||
@@ -404,6 +412,7 @@ interface CliArgs {
|
||||
theme: string;
|
||||
color?: string;
|
||||
cover?: string;
|
||||
citeStatus: boolean;
|
||||
dryRun: boolean;
|
||||
}
|
||||
|
||||
@@ -417,6 +426,7 @@ function parseArgs(argv: string[]): CliArgs {
|
||||
isHtml: false,
|
||||
articleType: "news",
|
||||
theme: "default",
|
||||
citeStatus: true,
|
||||
dryRun: false,
|
||||
};
|
||||
|
||||
@@ -439,6 +449,10 @@ function parseArgs(argv: string[]): CliArgs {
|
||||
args.color = argv[++i];
|
||||
} else if (arg === "--cover" && argv[i + 1]) {
|
||||
args.cover = argv[++i];
|
||||
} else if (arg === "--cite") {
|
||||
args.citeStatus = true;
|
||||
} else if (arg === "--no-cite") {
|
||||
args.citeStatus = false;
|
||||
} else if (arg === "--dry-run") {
|
||||
args.dryRun = true;
|
||||
} else if (arg.startsWith("--") && argv[i + 1] && !argv[i + 1]!.startsWith("-")) {
|
||||
@@ -513,8 +527,8 @@ async function main(): Promise<void> {
|
||||
if (!author) author = frontmatter.author || "";
|
||||
if (!digest) digest = frontmatter.digest || frontmatter.summary || frontmatter.description || "";
|
||||
|
||||
console.error(`[wechat-api] Theme: ${args.theme}${args.color ? `, color: ${args.color}` : ""}`);
|
||||
htmlPath = renderMarkdownToHtml(filePath, args.theme, args.color);
|
||||
console.error(`[wechat-api] Theme: ${args.theme}${args.color ? `, color: ${args.color}` : ""}, citeStatus: ${args.citeStatus}`);
|
||||
htmlPath = renderMarkdownToHtml(filePath, args.theme, args.color, args.citeStatus);
|
||||
console.error(`[wechat-api] HTML generated: ${htmlPath}`);
|
||||
htmlContent = extractHtmlContent(htmlPath);
|
||||
}
|
||||
|
||||
@@ -20,6 +20,7 @@ interface ArticleOptions {
|
||||
markdownFile?: string;
|
||||
theme?: string;
|
||||
color?: string;
|
||||
citeStatus?: boolean;
|
||||
author?: string;
|
||||
summary?: string;
|
||||
images?: string[];
|
||||
@@ -182,13 +183,19 @@ async function pasteFromClipboardInEditor(session: ChromeSession): Promise<void>
|
||||
await sleep(1000);
|
||||
}
|
||||
|
||||
async function parseMarkdownWithPlaceholders(markdownPath: string, theme?: string, color?: string): Promise<{ title: string; author: string; summary: string; htmlPath: string; contentImages: ImageInfo[] }> {
|
||||
async function parseMarkdownWithPlaceholders(
|
||||
markdownPath: string,
|
||||
theme?: string,
|
||||
color?: string,
|
||||
citeStatus: boolean = true
|
||||
): Promise<{ title: string; author: string; summary: string; htmlPath: string; contentImages: ImageInfo[] }> {
|
||||
const __filename = fileURLToPath(import.meta.url);
|
||||
const __dirname = path.dirname(__filename);
|
||||
const mdToWechatScript = path.join(__dirname, 'md-to-wechat.ts');
|
||||
const args = ['-y', 'bun', mdToWechatScript, markdownPath];
|
||||
if (theme) args.push('--theme', theme);
|
||||
if (color) args.push('--color', color);
|
||||
if (!citeStatus) args.push('--no-cite');
|
||||
|
||||
const result = spawnSync('npx', args, { stdio: ['inherit', 'pipe', 'pipe'] });
|
||||
if (result.status !== 0) {
|
||||
@@ -383,7 +390,7 @@ async function removeExtraEmptyLineAfterImage(session: ChromeSession): Promise<b
|
||||
}
|
||||
|
||||
export async function postArticle(options: ArticleOptions): Promise<void> {
|
||||
const { title, content, htmlFile, markdownFile, theme, color, author, summary, images = [], submit = false, profileDir, cdpPort } = options;
|
||||
const { title, content, htmlFile, markdownFile, theme, color, citeStatus = true, author, summary, images = [], submit = false, profileDir, cdpPort } = options;
|
||||
let { contentImages = [] } = options;
|
||||
let effectiveTitle = title || '';
|
||||
let effectiveAuthor = author || '';
|
||||
@@ -392,7 +399,7 @@ export async function postArticle(options: ArticleOptions): Promise<void> {
|
||||
|
||||
if (markdownFile) {
|
||||
console.log(`[wechat] Parsing markdown: ${markdownFile}`);
|
||||
const parsed = await parseMarkdownWithPlaceholders(markdownFile, theme, color);
|
||||
const parsed = await parseMarkdownWithPlaceholders(markdownFile, theme, color, citeStatus);
|
||||
effectiveTitle = effectiveTitle || parsed.title;
|
||||
effectiveAuthor = effectiveAuthor || parsed.author;
|
||||
effectiveSummary = effectiveSummary || parsed.summary;
|
||||
@@ -677,6 +684,7 @@ Options:
|
||||
--markdown <path> Markdown file to convert and post (recommended)
|
||||
--theme <name> Theme for markdown (default, grace, simple, modern)
|
||||
--color <name|hex> Primary color (blue, green, vermilion, etc. or hex)
|
||||
--no-cite Disable bottom citations for ordinary external links in markdown mode
|
||||
--author <name> Author name
|
||||
--summary <text> Article summary
|
||||
--image <path> Content image, can repeat (only with --content)
|
||||
@@ -687,13 +695,15 @@ Options:
|
||||
Examples:
|
||||
npx -y bun wechat-article.ts --markdown article.md
|
||||
npx -y bun wechat-article.ts --markdown article.md --theme grace --submit
|
||||
npx -y bun wechat-article.ts --markdown article.md --no-cite
|
||||
npx -y bun wechat-article.ts --title "标题" --content "内容" --image img.png
|
||||
npx -y bun wechat-article.ts --title "标题" --html article.html --submit
|
||||
|
||||
Markdown mode:
|
||||
Images in markdown are converted to placeholders. After pasting HTML,
|
||||
each placeholder is selected, scrolled into view, deleted, and replaced
|
||||
with the actual image via paste.
|
||||
with the actual image via paste. Ordinary external links are converted to
|
||||
bottom citations by default.
|
||||
`);
|
||||
process.exit(0);
|
||||
}
|
||||
@@ -709,6 +719,7 @@ async function main(): Promise<void> {
|
||||
let markdownFile: string | undefined;
|
||||
let theme: string | undefined;
|
||||
let color: string | undefined;
|
||||
let citeStatus = true;
|
||||
let author: string | undefined;
|
||||
let summary: string | undefined;
|
||||
let submit = false;
|
||||
@@ -723,6 +734,8 @@ async function main(): Promise<void> {
|
||||
else if (arg === '--markdown' && args[i + 1]) markdownFile = args[++i];
|
||||
else if (arg === '--theme' && args[i + 1]) theme = args[++i];
|
||||
else if (arg === '--color' && args[i + 1]) color = args[++i];
|
||||
else if (arg === '--cite') citeStatus = true;
|
||||
else if (arg === '--no-cite') citeStatus = false;
|
||||
else if (arg === '--author' && args[i + 1]) author = args[++i];
|
||||
else if (arg === '--summary' && args[i + 1]) summary = args[++i];
|
||||
else if (arg === '--image' && args[i + 1]) images.push(args[++i]!);
|
||||
@@ -734,7 +747,7 @@ async function main(): Promise<void> {
|
||||
if (!markdownFile && !htmlFile && !title) { console.error('Error: --title is required (or use --markdown/--html)'); process.exit(1); }
|
||||
if (!markdownFile && !htmlFile && !content) { console.error('Error: --content, --html, or --markdown is required'); process.exit(1); }
|
||||
|
||||
await postArticle({ title: title || '', content, htmlFile, markdownFile, theme, color, author, summary, images, submit, profileDir, cdpPort });
|
||||
await postArticle({ title: title || '', content, htmlFile, markdownFile, theme, color, citeStatus, author, summary, images, submit, profileDir, cdpPort });
|
||||
}
|
||||
|
||||
await main().then(() => {
|
||||
|
||||
@@ -98,9 +98,13 @@ Checks: Chrome, profile isolation, Bun, Accessibility, clipboard, paste keystrok
|
||||
|
||||
---
|
||||
|
||||
## Regular Posts
|
||||
## Post Type Selection
|
||||
|
||||
Text + up to 4 images.
|
||||
Unless the user explicitly specifies the post type:
|
||||
- **Plain text** + within 10,000 characters → **Regular Post** (Premium members support up to 10,000 characters, non-Premium: 280)
|
||||
- **Markdown file** (.md) → **X Article**
|
||||
|
||||
## Regular Posts
|
||||
|
||||
```bash
|
||||
${BUN_X} ${SKILL_DIR}/scripts/x-browser.ts "Hello!" --image ./photo.png
|
||||
|
||||
@@ -187,20 +187,13 @@ export async function postToX(options: XBrowserOptions): Promise<void> {
|
||||
await sleep(2000);
|
||||
console.log('[x-browser] Post submitted!');
|
||||
} else {
|
||||
console.log('[x-browser] Post composed (preview mode). Add --submit to post.');
|
||||
console.log('[x-browser] Browser will stay open for 30 seconds for preview...');
|
||||
await sleep(30_000);
|
||||
console.log('[x-browser] Post composed. Please review and click the publish button in the browser.');
|
||||
}
|
||||
} finally {
|
||||
if (cdp) {
|
||||
try { await cdp.send('Browser.close', {}, { timeoutMs: 5_000 }); } catch {}
|
||||
cdp.close();
|
||||
}
|
||||
|
||||
setTimeout(() => {
|
||||
if (!chrome.killed) try { chrome.kill('SIGKILL'); } catch {}
|
||||
}, 2_000).unref?.();
|
||||
try { chrome.kill('SIGTERM'); } catch {}
|
||||
chrome.unref();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -41,7 +41,7 @@ if (Test-Path "$HOME/.baoyu-skills/baoyu-translate/EXTEND.md") { "user" }
|
||||
| Found | Read, parse, apply settings. On first use in session, briefly remind: "Using preferences from [path]. You can edit EXTEND.md to customize glossary, audience, etc." |
|
||||
| Not found | **MUST** run first-time setup (see below) — do NOT silently use defaults |
|
||||
|
||||
**EXTEND.md Supports**: Default target language | Default mode | Target audience | Custom glossaries | Translation style | Chunk settings
|
||||
**EXTEND.md Supports**: Default target language | Default mode | Target audience | Custom glossaries (inline or file path) | Translation style | Chunk settings
|
||||
|
||||
Schema: [references/config/extend-schema.md](references/config/extend-schema.md)
|
||||
|
||||
@@ -135,7 +135,7 @@ Custom audience descriptions are also accepted, e.g., `--audience "AI感兴趣
|
||||
1.2 Load built-in glossary for the language pair if available:
|
||||
- EN→ZH: [references/glossary-en-zh.md](references/glossary-en-zh.md)
|
||||
|
||||
1.3 Merge glossaries: EXTEND.md glossary + built-in glossary + `--glossary` file (CLI overrides all)
|
||||
1.3 Merge glossaries: EXTEND.md `glossary` (inline) + EXTEND.md `glossary_files` (external files, paths relative to EXTEND.md location) + built-in glossary + `--glossary` file (CLI overrides all)
|
||||
|
||||
### Step 2: Materialize Source & Create Output Directory
|
||||
|
||||
@@ -201,6 +201,7 @@ Before translating chunks:
|
||||
- **Natural flow**: Use idiomatic target language word order and sentence patterns; break or restructure sentences freely when the source structure doesn't work naturally in the target language
|
||||
- **Terminology**: Use standard translations; annotate with original term in parentheses on first occurrence
|
||||
- **Preserve format**: Keep all markdown formatting (headings, bold, italic, images, links, code blocks)
|
||||
- **Frontmatter transformation**: If the source has YAML frontmatter, preserve it in the translation with these changes: (1) Rename metadata fields that describe the *source* article — `url`→`sourceUrl`, `title`→`sourceTitle`, `description`→`sourceDescription`, `author`→`sourceAuthor`, `date`→`sourceDate`, and any similar origin-metadata fields — by adding a `source` prefix (camelCase). (2) Translate the values of text fields (title, description, etc.) and add them as new top-level fields. (3) Keep other fields (tags, categories, custom fields) as-is, translating their values where appropriate
|
||||
- **Respect original**: Maintain original meaning and intent; do not add, remove, or editorialize — but sentence structure and imagery may be adapted freely to serve the meaning
|
||||
- **Translator's notes**: For terms, concepts, or cultural references that target readers may not understand — due to jargon, cultural gaps, or domain-specific knowledge — add a concise explanatory note in parentheses immediately after the term. The note should explain *what it means* in plain language, not just provide the English original. Format: `译文(English original,通俗解释)`. Calibrate annotation depth to the target audience: general readers need more notes than technical readers. Only add notes where genuinely needed; do not over-annotate obvious terms.
|
||||
|
||||
|
||||
@@ -25,6 +25,7 @@ chunk_max_words: 5000
|
||||
|
||||
# Custom glossary (merged with built-in glossary)
|
||||
# CLI --glossary flag overrides these
|
||||
# Supports inline entries and/or file paths
|
||||
glossary:
|
||||
- from: "Reinforcement Learning"
|
||||
to: "强化学习"
|
||||
@@ -32,6 +33,14 @@ glossary:
|
||||
to: "Transformer"
|
||||
note: "Keep English"
|
||||
|
||||
# Load glossary from external file(s)
|
||||
# Supports absolute path or relative to EXTEND.md location
|
||||
# File format: markdown table with | from | to | note | columns,
|
||||
# or YAML list of {from, to, note} entries
|
||||
glossary_files:
|
||||
- ./my-glossary.md
|
||||
- /path/to/shared-glossary.yaml
|
||||
|
||||
# Language-pair specific glossaries
|
||||
glossaries:
|
||||
en-zh:
|
||||
@@ -52,7 +61,8 @@ glossaries:
|
||||
| `style` | string | `storytelling` | Translation style (`storytelling` / `formal` / `technical` / `literal` / `academic` / `business` / `humorous` / `conversational` / `elegant` / custom) |
|
||||
| `chunk_threshold` | number | `4000` | Word count threshold to trigger chunked translation |
|
||||
| `chunk_max_words` | number | `5000` | Max words per chunk |
|
||||
| `glossary` | array | `[]` | Universal glossary entries |
|
||||
| `glossary` | array | `[]` | Universal glossary entries (inline) |
|
||||
| `glossary_files` | array | `[]` | External glossary file paths (absolute or relative to EXTEND.md) |
|
||||
| `glossaries` | object | `{}` | Language-pair specific glossary entries |
|
||||
|
||||
## Glossary Entry
|
||||
@@ -63,11 +73,35 @@ glossaries:
|
||||
| `to` | yes | Target translation |
|
||||
| `note` | no | Usage note (e.g., "Keep English", "Only in tech context") |
|
||||
|
||||
## Glossary File Format
|
||||
|
||||
External glossary files (`glossary_files`) support two formats:
|
||||
|
||||
**Markdown table** (`.md`):
|
||||
```markdown
|
||||
| from | to | note |
|
||||
|------|----|------|
|
||||
| Reinforcement Learning | 强化学习 | |
|
||||
| Transformer | Transformer | Keep English |
|
||||
```
|
||||
|
||||
**YAML list** (`.yaml` / `.yml`):
|
||||
```yaml
|
||||
- from: "Reinforcement Learning"
|
||||
to: "强化学习"
|
||||
- from: "Transformer"
|
||||
to: "Transformer"
|
||||
note: "Keep English"
|
||||
```
|
||||
|
||||
Paths can be absolute or relative to the EXTEND.md file location.
|
||||
|
||||
## Priority
|
||||
|
||||
1. CLI `--glossary` file entries
|
||||
2. EXTEND.md `glossaries[pair]` entries
|
||||
3. EXTEND.md `glossary` entries
|
||||
4. Built-in glossary (e.g., `references/glossary-en-zh.md`)
|
||||
3. EXTEND.md `glossary` entries (inline)
|
||||
4. EXTEND.md `glossary_files` entries (in listed order, later files override earlier)
|
||||
5. Built-in glossary (e.g., `references/glossary-en-zh.md`)
|
||||
|
||||
Later entries override earlier ones for the same source term.
|
||||
|
||||
Reference in New Issue
Block a user