blob: 311cd2c4bd423dec6262b41e40ee01bb06bd6dcd [file]
#!/usr/bin/env node
/**
* post-process.js
*
* 职责:
* - 读取 translate-claude.js 输出的中间 JSON
* - 将 translated segment 还原为合法 Markdown
* - 写入 Docusaurus i18n 目录结构
*
* 设计原则:
* - 结构 100% 可还原
* - 翻译失败可回退到英文
* - 不在此阶段调用任何 LLM
*/
const fs = require('fs');
const path = require('path');
const matter = require('gray-matter');
const INPUT_DIR = process.argv[2];
const TARGET_ROOT = process.argv[3];
if (!INPUT_DIR || !TARGET_ROOT) {
console.error('Usage: node post-process.js <translatedDir> <i18nRoot>');
process.exit(1);
}
function normalizeSourcePath(sourcePath) {
const raw = path.isAbsolute(sourcePath)
? path.relative(process.cwd(), sourcePath)
: sourcePath;
return raw.replace(/\\/g, '/').replace(/^\.\/+/, '');
}
function resolveTargetPath(sourcePath, i18nRoot) {
const normalizedSource = normalizeSourcePath(sourcePath);
if (normalizedSource.startsWith('docs/')) {
const relative = normalizedSource.slice('docs/'.length);
return path.join(i18nRoot, 'docusaurus-plugin-content-docs', 'current', relative);
}
if (normalizedSource.startsWith('versioned_docs/')) {
const relative = normalizedSource.slice('versioned_docs/'.length);
const firstSlash = relative.indexOf('/');
if (firstSlash === -1) {
throw new Error(`Invalid versioned docs path: ${sourcePath}`);
}
const versionDir = relative.slice(0, firstSlash);
const versionRelativePath = relative.slice(firstSlash + 1);
return path.join(i18nRoot, 'docusaurus-plugin-content-docs', versionDir, versionRelativePath);
}
if (normalizedSource.startsWith('community/')) {
const relative = normalizedSource.slice('community/'.length);
return path.join(i18nRoot, 'docusaurus-plugin-content-docs-community', 'current', relative);
}
throw new Error(`Unsupported source path for translation output: ${sourcePath}`);
}
/**
* 确保目录存在
*/
function ensureDir(filePath) {
fs.mkdirSync(path.dirname(filePath), { recursive: true });
}
/**
* 将 segments 还原为 markdown 文本
*/
function restoreMarkdown(segments) {
let output = '';
for (const seg of segments) {
if (seg.type === 'text') {
output += (seg.translated || seg.value) + '\n\n';
} else if (seg.type === 'code') {
output += seg.value + '\n';
}
}
return output.trim() + '\n';
}
function main() {
const files = fs.readdirSync(INPUT_DIR).filter(f => f.endsWith('.json'));
for (const file of files) {
const inputPath = path.join(INPUT_DIR, file);
const data = JSON.parse(fs.readFileSync(inputPath, 'utf8'));
const { source, frontMatter = {}, segments } = data;
// 1. 还原 Markdown body
const body = restoreMarkdown(segments);
// 2. 重新注入 front matter
const finalMarkdown = matter.stringify(body, { ...frontMatter, language: 'ja' }, { language: 'json' });
// 3. 优先使用 prepare 阶段记录的 target(保持 workflow 输入一致)
const targetPath = data.target
? path.isAbsolute(data.target)
? data.target
: path.join(process.cwd(), data.target)
: resolveTargetPath(source, TARGET_ROOT);
ensureDir(targetPath);
fs.writeFileSync(targetPath, finalMarkdown, 'utf8');
console.log(`Written: ${targetPath}`);
}
}
main();