mirror of
https://github.com/openclaw/openclaw.git
synced 2026-04-08 18:33:39 +02:00
173 lines
4.7 KiB
JavaScript
173 lines
4.7 KiB
JavaScript
#!/usr/bin/env node
|
|
|
|
import { execFileSync } from "node:child_process";
|
|
import fs from "node:fs";
|
|
import path from "node:path";
|
|
import { fileURLToPath } from "node:url";
|
|
|
|
const HERE = path.dirname(fileURLToPath(import.meta.url));
|
|
const ROOT = path.resolve(HERE, "..");
|
|
const SOURCE_DOCS_DIR = path.join(ROOT, "docs");
|
|
const SOURCE_CONFIG_PATH = path.join(SOURCE_DOCS_DIR, "docs.json");
|
|
const GENERATED_LOCALES = [
|
|
{
|
|
language: "zh-Hans",
|
|
dir: "zh-CN",
|
|
navFile: "zh-Hans-navigation.json",
|
|
tmFile: "zh-CN.tm.jsonl",
|
|
},
|
|
{ language: "ja", dir: "ja-JP", navFile: "ja-navigation.json", tmFile: "ja-JP.tm.jsonl" },
|
|
{ language: "es", dir: "es", navFile: "es-navigation.json", tmFile: "es.tm.jsonl" },
|
|
{ language: "pt-BR", dir: "pt-BR", navFile: "pt-BR-navigation.json", tmFile: "pt-BR.tm.jsonl" },
|
|
{ language: "ko", dir: "ko", navFile: "ko-navigation.json", tmFile: "ko.tm.jsonl" },
|
|
{ language: "de", dir: "de", navFile: "de-navigation.json", tmFile: "de.tm.jsonl" },
|
|
{ language: "fr", dir: "fr", navFile: "fr-navigation.json", tmFile: "fr.tm.jsonl" },
|
|
{ language: "ar", dir: "ar", navFile: "ar-navigation.json", tmFile: "ar.tm.jsonl" },
|
|
];
|
|
|
|
function parseArgs(argv) {
|
|
const args = {
|
|
target: "",
|
|
sourceRepo: "",
|
|
sourceSha: "",
|
|
};
|
|
|
|
for (let index = 0; index < argv.length; index += 1) {
|
|
const part = argv[index];
|
|
switch (part) {
|
|
case "--target":
|
|
args.target = argv[index + 1] ?? "";
|
|
index += 1;
|
|
break;
|
|
case "--source-repo":
|
|
args.sourceRepo = argv[index + 1] ?? "";
|
|
index += 1;
|
|
break;
|
|
case "--source-sha":
|
|
args.sourceSha = argv[index + 1] ?? "";
|
|
index += 1;
|
|
break;
|
|
default:
|
|
throw new Error(`unknown arg: ${part}`);
|
|
}
|
|
}
|
|
|
|
if (!args.target) {
|
|
throw new Error("missing --target");
|
|
}
|
|
|
|
return args;
|
|
}
|
|
|
|
function run(command, args, options = {}) {
|
|
execFileSync(command, args, {
|
|
cwd: ROOT,
|
|
stdio: "inherit",
|
|
...options,
|
|
});
|
|
}
|
|
|
|
function ensureDir(dirPath) {
|
|
fs.mkdirSync(dirPath, { recursive: true });
|
|
}
|
|
|
|
function readJson(filePath) {
|
|
return JSON.parse(fs.readFileSync(filePath, "utf8"));
|
|
}
|
|
|
|
function writeJson(filePath, value) {
|
|
ensureDir(path.dirname(filePath));
|
|
fs.writeFileSync(filePath, `${JSON.stringify(value, null, 2)}\n`);
|
|
}
|
|
|
|
function composeDocsConfig() {
|
|
const sourceConfig = readJson(SOURCE_CONFIG_PATH);
|
|
const languages = sourceConfig?.navigation?.languages;
|
|
|
|
if (!Array.isArray(languages)) {
|
|
throw new Error("docs/docs.json is missing navigation.languages");
|
|
}
|
|
|
|
const generatedLanguageSet = new Set(GENERATED_LOCALES.map((entry) => entry.language));
|
|
const withoutGenerated = languages.filter((entry) => !generatedLanguageSet.has(entry?.language));
|
|
const enIndex = withoutGenerated.findIndex((entry) => entry?.language === "en");
|
|
const generated = GENERATED_LOCALES.map((entry) =>
|
|
readJson(path.join(SOURCE_DOCS_DIR, ".i18n", entry.navFile)),
|
|
);
|
|
if (enIndex === -1) {
|
|
withoutGenerated.push(...generated);
|
|
} else {
|
|
withoutGenerated.splice(enIndex + 1, 0, ...generated);
|
|
}
|
|
|
|
return {
|
|
...sourceConfig,
|
|
navigation: {
|
|
...sourceConfig.navigation,
|
|
languages: withoutGenerated,
|
|
},
|
|
};
|
|
}
|
|
|
|
function syncDocsTree(targetRoot) {
|
|
const targetDocsDir = path.join(targetRoot, "docs");
|
|
ensureDir(targetDocsDir);
|
|
|
|
const localeFilters = GENERATED_LOCALES.flatMap((entry) => [
|
|
"--filter",
|
|
`P ${entry.dir}/`,
|
|
"--filter",
|
|
`P .i18n/${entry.tmFile}`,
|
|
"--exclude",
|
|
`${entry.dir}/`,
|
|
"--exclude",
|
|
`.i18n/${entry.tmFile}`,
|
|
]);
|
|
|
|
run("rsync", [
|
|
"-a",
|
|
"--delete",
|
|
"--filter",
|
|
"P .i18n/README.md",
|
|
"--exclude",
|
|
".i18n/README.md",
|
|
...localeFilters,
|
|
`${SOURCE_DOCS_DIR}/`,
|
|
`${targetDocsDir}/`,
|
|
]);
|
|
|
|
for (const locale of GENERATED_LOCALES) {
|
|
const sourceTmPath = path.join(SOURCE_DOCS_DIR, ".i18n", locale.tmFile);
|
|
const targetTmPath = path.join(targetDocsDir, ".i18n", locale.tmFile);
|
|
if (!fs.existsSync(targetTmPath) && fs.existsSync(sourceTmPath)) {
|
|
ensureDir(path.dirname(targetTmPath));
|
|
fs.copyFileSync(sourceTmPath, targetTmPath);
|
|
}
|
|
}
|
|
|
|
writeJson(path.join(targetDocsDir, "docs.json"), composeDocsConfig());
|
|
}
|
|
|
|
function writeSyncMetadata(targetRoot, args) {
|
|
const metadata = {
|
|
repository: args.sourceRepo || "",
|
|
sha: args.sourceSha || "",
|
|
syncedAt: new Date().toISOString(),
|
|
};
|
|
writeJson(path.join(targetRoot, ".openclaw-sync", "source.json"), metadata);
|
|
}
|
|
|
|
function main() {
|
|
const args = parseArgs(process.argv.slice(2));
|
|
const targetRoot = path.resolve(args.target);
|
|
|
|
if (!fs.existsSync(targetRoot)) {
|
|
throw new Error(`target does not exist: ${targetRoot}`);
|
|
}
|
|
|
|
syncDocsTree(targetRoot);
|
|
writeSyncMetadata(targetRoot, args);
|
|
}
|
|
|
|
main();
|