mdx-validator
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseMDX Validator
MDX Validator
MDX 语法预检查工具,补充现有工具(eslint-mdx, prettier)。
MDX语法预检查工具,补充现有工具(eslint-mdx、prettier)的能力。
🎯 设计理念
🎯 设计理念
与现有工具的关系
与现有工具的关系
eslint-mdx (基础 MDX 检查)
+
prettier (格式化)
+
mdx-validator (Fumadocs 专项检查) ← 你在这里
↓
完整的 MDX 质量保证为什么需要本 skill:
- eslint-mdx 不检查图片文件名规范
- prettier 不检查翻译完整性
- 现有工具没有 Fumadocs 特定问题的检查
eslint-mdx (基础 MDX 检查)
+
prettier (格式化)
+
mdx-validator (Fumadocs 专项检查) ← 你在这里
↓
完整的 MDX 质量保证为什么需要本Skill:
- eslint-mdx 不检查图片文件名规范
- prettier 不检查翻译完整性
- 现有工具没有针对Fumadocs特定问题的检查
📦 前置条件
📦 前置条件
推荐安装(可选)
推荐安装(可选)
bash
undefinedbash
undefined1. 安装 eslint-mdx(官方 MDX 检查工具)
1. 安装 eslint-mdx(官方 MDX 检查工具)
npm install -D eslint-plugin-mdx
npm install -D eslint-plugin-mdx
2. 安装 prettier(MDX 格式化)
2. 安装 prettier(MDX 格式化)
npm install -D prettier
npm install -D prettier
3. 创建配置
3. 创建配置
echo '{"extends":["plugin:mdx/recommended"]}' > .eslintrc.json
undefinedecho '{"extends":["plugin:mdx/recommended"]}' > .eslintrc.json
undefined🔍 检查项
🔍 检查项
Step 0: 使用现有工具(如果有)
Step 0: 使用现有工具(如果有)
bash
undefinedbash
undefined检查是否有 eslint-mdx
检查是否有 eslint-mdx
if [ -f "node_modules/eslint-plugin-mdx" ]; then
echo "✅ 发现 eslint-mdx,运行检查..."
npx eslint "**/*.mdx" --fix
else
echo "⚠️ 未安装 eslint-mdx,跳过基础检查"
echo " 推荐: npm install -D eslint-plugin-mdx"
fi
if [ -f "node_modules/eslint-plugin-mdx" ]; then
echo "✅ 发现 eslint-mdx,运行检查..."
npx eslint "**/*.mdx" --fix
else
echo "⚠️ 未安装 eslint-mdx,跳过基础检查"
echo " 推荐: npm install -D eslint-plugin-mdx"
fi
检查是否有 prettier
检查是否有 prettier
if [ -f "node_modules/prettier" ]; then
echo "✅ 发现 prettier,格式化..."
npx prettier --write "**/*.mdx"
fi
undefinedif [ -f "node_modules/prettier" ]; then
echo "✅ 发现 prettier,格式化..."
npx prettier --write "**/*.mdx"
fi
undefinedStep 1: 特殊字符检查(MDX 语法)
Step 1: 特殊字符检查(MDX 语法)
问题字符:
- - 被解析为 JSX 标签
< - - 被解析为 JSX 标签
> {- 被解析为 JSX 表达式}
检查命令:
bash
undefined问题字符:
- - 会被解析为JSX标签
< - - 会被解析为JSX标签
> {- 会被解析为JSX表达式}
检查命令:
bash
undefined检查危险的 < 符号(不在代码块和 HTML 标签中)
检查危险的 < 符号(不在代码块和 HTML 标签中)
grep -n '<[^a-zA-Z/!]' .mdx | grep -v '```' | grep -v '^.:.*<(a|img|div|span|p|h[1-6]|ul|ol|li|code|pre|strong|em|br|hr)'
grep -n '<[^a-zA-Z/!]' .mdx | grep -v '```' | grep -v '^.:.*<(a|img|div|span|p|h[1-6]|ul|ol|li|code|pre|strong|em|br|hr)'
检查危险的 > 符号(不在代码块中)
检查危险的 > 符号(不在代码块中)
grep -n '>[^a-zA-Z/]' .mdx | grep -v '```' | grep -v '^.:.*</(a|img|div|span|p|h[1-6|ul|ol|li|code|pre|strong|em)>'
undefinedgrep -n '>[^a-zA-Z/]' .mdx | grep -v '```' | grep -v '^.:.*</(a|img|div|span|p|h[1-6|ul|ol|li|code|pre|strong|em)>'
undefined2. 图片路径检查
2. 图片路径检查
问题模式: ,
img-1.pngscreenshot-10.png检查命令:
bash
undefined问题模式: ,
img-1.pngscreenshot-10.png检查命令:
bash
undefined检查连字符+数字的文件名
检查连字符+数字的文件名
grep -nE '(img|image|screenshot|fig|figure)-[0-9]+.(png|jpg|webp|gif)' *.mdx
undefinedgrep -nE '(img|image|screenshot|fig|figure)-[0-9]+.(png|jpg|webp|gif)' *.mdx
undefined3. Frontmatter 检查
3. Frontmatter 检查
必需字段: ,
titledescription检查命令:
bash
undefined必需字段: ,
titledescription检查命令:
bash
undefined检查缺失 title 的文件
检查缺失 title 的文件
grep -L '^title:' *.mdx
grep -L '^title:' *.mdx
检查缺失 description 的文件
检查缺失 description 的文件
grep -L '^description:' *.mdx
grep -L '^description:' *.mdx
检查 description 长度(建议 50-160 字符)
检查 description 长度(建议 50-160 字符)
for f in *.mdx; do
desc=$(grep '^description:' "$f" | cut -d':' -f2-)
len=${#desc}
if [ $len -lt 50 ] || [ $len -gt 160 ]; then
echo "⚠️ $f: description 长度 $len(建议 50-160)"
fi
done
undefinedfor f in *.mdx; do
desc=$(grep '^description:' "$f" | cut -d':' -f2-)
len=${#desc}
if [ $len -lt 50 ] || [ $len -gt 160 ]; then
echo "⚠️ $f: description 长度 $len(建议 50-160)"
fi
done
undefined4. 代码块完整性检查
4. 代码块完整性检查
检查命令:
bash
undefined检查命令:
bash
undefined检查未闭合的代码块
检查未闭合的代码块
awk '/^```/{flag=1-flag} END{if(flag)print "❌ 未闭合的代码块"}' *.mdx
awk '/^```/{flag=1-flag} END{if(flag)print "❌ 未闭合的代码块"}' *.mdx
检查代码块语言标识
检查代码块语言标识
grep -n '^```[^a-z]$' .mdx | grep -v '^.:.````*$'
undefinedgrep -n '^```[^a-z]$' .mdx | grep -v '^.:.````*$'
undefined5. 翻译完整性检查
5. 翻译完整性检查
改进后的检测逻辑:
bash
undefined改进后的检测逻辑:
bash
undefined1. 定义常见的英文技术术语(不应被检测为未翻译)
1. 定义常见的英文技术术语(不应被检测为未翻译)
TECH_TERMS=(
"React|TypeScript|JavaScript|Node.js|npm|yarn|pnpm"
"API|SDK|CLI|GUI|IDE|JSON|YAML|XML|HTTP|HTTPS"
"CSS|HTML|SQL|NoSQL|REST|GraphQL"
"Git|GitHub|GitLab|Bitbucket"
"Docker|Kubernetes|AWS|GCP|Azure"
"MacOS|Windows|Linux|Ubuntu|Debian"
"CDN|DNS|SSL|TLS|OAuth|JWT"
)
TECH_TERMS=(
"React|TypeScript|JavaScript|Node.js|npm|yarn|pnpm"
"API|SDK|CLI|GUI|IDE|JSON|YAML|XML|HTTP|HTTPS"
"CSS|HTML|SQL|NoSQL|REST|GraphQL"
"Git|GitHub|GitLab|Bitbucket"
"Docker|Kubernetes|AWS|GCP|Azure"
"MacOS|Windows|Linux|Ubuntu|Debian"
"CDN|DNS|SSL|TLS|OAuth|JWT"
)
合并为正则表达式
合并为正则表达式
TECH_REGEX=$(IFS="|"; echo "${TECH_TERMS[*]}")
TECH_REGEX=$(IFS="|"; echo "${TECH_TERMS[*]}")
2. 检查中文文件中的英文单词(排除技术术语)
2. 检查中文文件中的英文单词(排除技术术语)
for f in content/docs/zh-CN/*.mdx; do
统计英文单词数量(排除技术术语)
english=$(grep -oE '\b[A-Za-z]+\b' "$f" |
grep -v -E "^($TECH_REGEX)$" |
wc -l)
grep -v -E "^($TECH_REGEX)$" |
wc -l)
统计总词数
total=$(wc -w < "$f")
计算英文占比
if [ $total -gt 0 ]; then
ratio=$((english * 100 / total))
if [ $ratio -gt 20 ]; then
echo "⚠️ $f: 英文占比 ${ratio}%,可能未翻译"
fi
fi
done
for f in content/docs/zh-CN/*.mdx; do
统计英文单词数量(排除技术术语)
english=$(grep -oE '\b[A-Za-z]+\b' "$f" |
grep -v -E "^($TECH_REGEX)$" |
wc -l)
grep -v -E "^($TECH_REGEX)$" |
wc -l)
统计总词数
total=$(wc -w < "$f")
计算英文占比
if [ $total -gt 0 ]; then
ratio=$((english * 100 / total))
if [ $ratio -gt 20 ]; then
echo "⚠️ $f: 英文占比 ${ratio}%,可能未翻译"
fi
fi
done
3. 检查正文内容是否与英文版相同(排除 frontmatter)
3. 检查正文内容是否与英文版相同(排除 frontmatter)
for f in content/docs/zh-CN/*.mdx; do
en_file="${f/zh-CN/en}"
if [ -f "$en_file" ]; then
# 提取正文(跳过前 10 行 frontmatter)
zh_body=$(tail -n +10 "$f")
en_body=$(tail -n +10 "$en_file")
if [ "$zh_body" = "$en_body" ]; then
echo "❌ $f: 正文内容与英文版相同,未翻译!"
fifi
done
for f in content/docs/zh-CN/*.mdx; do
en_file="${f/zh-CN/en}"
if [ -f "$en_file" ]; then
# 提取正文(跳过前 10 行 frontmatter)
zh_body=$(tail -n +10 "$f")
en_body=$(tail -n +10 "$en_file")
if [ "$zh_body" = "$en_body" ]; then
echo "❌ $f: 正文内容与英文版相同,未翻译!"
fifi
done
4. 智能检测(基于句子级别)
4. 智能检测(基于句子级别)
for f in content/docs/zh-CN/*.mdx; do
提取包含大量英文的句子
grep -nE '^[^#][A-Za-z]{20,}[^#]$' "$f" |
grep -v '```' |
grep -v '<!--' |
head -5 done
grep -v '```' |
grep -v '<!--' |
head -5 done
**更智能的检测**:
```bashfor f in content/docs/zh-CN/*.mdx; do
提取包含大量英文的句子
grep -nE '^[^#][A-Za-z]{20,}[^#]$' "$f" |
grep -v '```' |
grep -v '<!--' |
head -5 done
grep -v '```' |
grep -v '<!--' |
head -5 done
**更智能的检测**:
```bash使用 MDX AST 解析(更准确)
使用 MDX AST 解析(更准确)
需要安装: npm install -D remark remark-mdx
需要安装: npm install -D remark remark-mdx
npx remark content/docs/zh-CN/article.mdx
--use remark-mdx
--tree |
jq '.. | .value? | select(. != null) | select(test("[A-Za-z]{10,}"))'
--use remark-mdx
--tree |
jq '.. | .value? | select(. != null) | select(test("[A-Za-z]{10,}"))'
undefinednpx remark content/docs/zh-CN/article.mdx
--use remark-mdx
--tree |
jq '.. | .value? | select(. != null) | select(test("[A-Za-z]{10,}"))'
--use remark-mdx
--tree |
jq '.. | .value? | select(. != null) | select(test("[A-Za-z]{10,}"))'
undefined自动修复
自动修复
优先使用 prettier
优先使用 prettier
bash
undefinedbash
undefined如果有 prettier,优先使用
如果有 prettier,优先使用
if command -v prettier &> /dev/null; then
echo "✅ 使用 prettier 格式化..."
prettier --write "**/*.mdx"
fi
undefinedif command -v prettier &> /dev/null; then
echo "✅ 使用 prettier 格式化..."
prettier --write "**/*.mdx"
fi
undefined修复特殊字符
修复特殊字符
bash
undefinedbash
undefined修复 < 符号(数字前)
修复 < 符号(数字前)
sed -i 's|<([0-9])|under \1|g' *.mdx
sed -i 's|<([0-9])|<\1|g' *.mdx # 或使用 HTML 实体
sed -i 's|<([0-9])|under \1|g' *.mdx
sed -i 's|<([0-9])|<\1|g' *.mdx # 或使用 HTML 实体
修复 > 符号(数字前)
修复 > 符号(数字前)
sed -i 's|>([0-9])|over \1|g' *.mdx
sed -i 's|>([0-9])|>\1|g' *.mdx # 或使用 HTML 实体
undefinedsed -i 's|>([0-9])|over \1|g' *.mdx
sed -i 's|>([0-9])|>\1|g' *.mdx # 或使用 HTML 实体
undefined修复图片路径
修复图片路径
bash
undefinedbash
undefined修复连字符+数字的文件名
修复连字符+数字的文件名
img-1.png → img01.png
img-1.png → img01.png
screenshot-10.png → screenshot10.png
screenshot-10.png → screenshot10.png
sed -i -E 's|(img|image|screenshot|fig|figure)-([0-9]+).|\1\2.|g' *.mdx
undefinedsed -i -E 's|(img|image|screenshot|fig|figure)-([0-9]+).|\1\2.|g' *.mdx
undefined修复 Frontmatter
修复 Frontmatter
bash
undefinedbash
undefined添加缺失的 title(如果文件名有意义)
添加缺失的 title(如果文件名有意义)
for f in *.mdx; do
if ! grep -q '^title:' "$f"; then
title=$(basename "$f" .mdx | sed 's/-/ /g' | sed 's/\b(.)/\u\1/')
sed -i "1i---\ntitle: $title\n---" "$f"
fi
done
undefinedfor f in *.mdx; do
if ! grep -q '^title:' "$f"; then
title=$(basename "$f" .mdx | sed 's/-/ /g' | sed 's/\b(.)/\u\1/')
sed -i "1i---\ntitle: $title\n---" "$f"
fi
done
undefined使用方式
使用方式
方式 1: 完整检查(推荐)
方式 1: 完整检查(推荐)
bash
undefinedbash
undefined1. 基础检查(如果有 eslint-mdx)
1. 基础检查(如果有 eslint-mdx)
if [ -f "node_modules/eslint-plugin-mdx" ]; then
npx eslint "**/*.mdx" --fix
fi
if [ -f "node_modules/eslint-plugin-mdx" ]; then
npx eslint "**/*.mdx" --fix
fi
2. 格式化(如果有 prettier)
2. 格式化(如果有 prettier)
if [ -f "node_modules/prettier" ]; then
npx prettier --write "**/*.mdx"
fi
if [ -f "node_modules/prettier" ]; then
npx prettier --write "**/*.mdx"
fi
3. Fumadocs 专项检查
3. Fumadocs 专项检查
mdx-validator --check-images --check-translation
mdx-validator --check-images --check-translation
4. 自动修复剩余问题
4. 自动修复剩余问题
mdx-validator --fix
undefinedmdx-validator --fix
undefined方式 2: 仅使用 mdx-validator
方式 2: 仅使用 mdx-validator
bash
undefinedbash
undefined检查单个文件
检查单个文件
mdx-validator article.mdx
mdx-validator article.mdx
检查目录下所有文件
检查目录下所有文件
mdx-validator content/docs/en/**/*.mdx
mdx-validator content/docs/en/**/*.mdx
检查并修复
检查并修复
mdx-validator --fix content/docs/en/**/*.mdx
undefinedmdx-validator --fix content/docs/en/**/*.mdx
undefined方式 2: 集成到工作流
方式 3: 集成到工作流
bash
undefinedbash
undefined在翻译后运行
在翻译后运行
article-translator article.mdx --to zh
mdx-validator --fix content/docs/zh/article.mdx
article-translator article.mdx --to zh
mdx-validator --fix content/docs/zh/article.mdx
在构建前运行
在构建前运行
mdx-validator content/docs/**/*.mdx && pnpm build:docs
undefinedmdx-validator content/docs/**/*.mdx && pnpm build:docs
undefined输出示例
输出示例
=== MDX Validation Report ===
File: content/docs/en/ai-ml/jina-vlm.mdx
✅ Special characters: OK
⚠️ Image paths: 2 issues found
Line 45: img-10.png → img10.png
Line 78: screenshot-1.png → screenshot01.png
✅ Frontmatter: OK
✅ Code blocks: OK
Auto-fix available: mdx-validator --fix jina-vlm.mdx=== MDX Validation Report ===
File: content/docs/en/ai-ml/jina-vlm.mdx
✅ Special characters: OK
⚠️ Image paths: 2 issues found
Line 45: img-10.png → img10.png
Line 78: screenshot-1.png → screenshot01.png
✅ Frontmatter: OK
✅ Code blocks: OK
Auto-fix available: mdx-validator --fix jina-vlm.mdx配置
配置
可在项目根目录创建 :
.mdx-validator.jsonjson
{
"rules": {
"specialChars": true,
"imagePaths": true,
"frontmatter": true,
"codeBlocks": true
},
"autoFix": false,
"ignore": ["node_modules", ".next"]
}可在项目根目录创建 :
.mdx-validator.jsonjson
{
"rules": {
"specialChars": true,
"imagePaths": true,
"frontmatter": true,
"codeBlocks": true
},
"autoFix": false,
"ignore": ["node_modules", ".next"]
}与其他 Skills 配合
与其他 Skills 配合
fumadocs-article-importer (导入文章)
↓
article-translator (翻译内容)
↓
┌────────┴────────┐
│ eslint-mdx │ ← 基础 MDX 检查(推荐)
│ prettier │ ← 格式化(推荐)
└────────┬────────┘
↓
mdx-validator ← 你在这里(Fumadocs 专项检查)
↓
pnpm build:docs (构建)
↓
fumadocs-deploy (部署验证)fumadocs-article-importer (导入文章)
↓
article-translator (翻译内容)
↓
┌────────┴────────┐
│ eslint-mdx │ ← 基础 MDX 检查(推荐)
│ prettier │ ← 格式化(推荐)
└────────┬────────┘
↓
mdx-validator ← 你在这里(Fumadocs 专项检查)
↓
pnpm build:docs (构建)
↓
fumadocs-deploy (部署验证)🆚 与现有工具对比
🆚 与现有工具对比
| 检查项 | eslint-mdx | prettier | mdx-validator |
|---|---|---|---|
| MDX JSX 语法 | ✅ | - | - |
| Markdown 语法 | ✅ | - | - |
| 代码风格 | - | ✅ | - |
| 特殊字符(MDX) | - | - | ✅ |
| 图片文件名 | - | - | ✅ |
| 翻译完整性 | - | - | ✅ |
| Fumadocs 特定 | - | - | ✅ |
结论:
- 使用 eslint-mdx + prettier 进行基础检查
- 使用 mdx-validator 进行专项检查
- 三者互补,不冲突
| 检查项 | eslint-mdx | prettier | mdx-validator |
|---|---|---|---|
| MDX JSX 语法 | ✅ | - | - |
| Markdown 语法 | ✅ | - | - |
| 代码风格 | - | ✅ | - |
| 特殊字符(MDX) | - | - | ✅ |
| 图片文件名 | - | - | ✅ |
| 翻译完整性 | - | - | ✅ |
| Fumadocs 特定 | - | - | ✅ |
结论:
- 使用eslint-mdx + prettier进行基础检查
- 使用mdx-validator进行专项检查
- 三者互补,不存在冲突
常见问题
常见问题
Q: 为什么要预检查?
Q: 为什么要进行预检查?
A: MDX 语法错误在构建时才会发现,预检查可以:
- 提前发现问题,节省构建时间
- 自动修复常见问题
- 避免 CI/CD 失败
A: MDX语法错误通常在构建阶段才会被发现,预检查可以:
- 提前发现问题,节省构建时间
- 自动修复常见问题
- 避免CI/CD流程失败
Q: 哪些字符是安全的?
Q: 哪些字符是安全的?
A:
- 安全: 字母、数字、基本标点()
. , ! ? ; : ' " ( ) - 不安全:
<>{}(需要特殊处理)& - 代码块中: 所有字符都安全
A:
- 安全字符: 字母、数字、基础标点()
. , ! ? ; : ' " ( ) - 不安全字符:
<>{}(需要特殊处理)& - 代码块内: 所有字符均安全
Q: 图片路径为什么不能用连字符?
Q: 图片路径为什么不能使用连字符?
A: MDX 会将 解析为 减去 ,导致路径错误。
使用 或 可避免此问题。
img-1.pngimg1.pngimg01.pngopenclaw01.pngA: MDX会将解析为减去,导致路径解析错误。使用或这类命名方式可避免该问题。
img-1.pngimg1.pngimg01.pngopenclaw01.png