Files
XTLS_Xray-docs-next/scripts/gen-i18n-stale.mjs
T
2025-12-21 22:14:50 -05:00

106 lines
3.1 KiB
JavaScript

import fs from "node:fs";
import path from "node:path";
import { execSync } from "node:child_process";
const ROOT = process.cwd();
const DOCS_DIR = path.resolve(ROOT, "docs");
const OUT_DIR = path.resolve(ROOT, ".vitepress/.generated");
const OUT_FILE = path.join(OUT_DIR, "i18n-status.json");
const LOCALES = ["en", "ru"];
function walk(dir) {
const out = [];
for (const name of fs.readdirSync(dir)) {
const p = path.join(dir, name);
const st = fs.statSync(p);
if (st.isDirectory()) out.push(...walk(p));
else if (p.endsWith(".md")) out.push(p);
}
return out;
}
function gitLastCommitISO(fileAbsPath) {
const rel = path.relative(ROOT, fileAbsPath).replaceAll("\\", "/");
try {
const iso = execSync(`git log -1 --format=%cI -- "${rel}"`, {
encoding: "utf8",
}).trim();
return iso || null;
} catch {
return null;
}
}
function toRouteFromDocsRel(relToDocs) {
let route = "/" + relToDocs.replace(/\.md$/, "");
route = route.replace(/\/index$/, "/");
return route;
}
const zhFiles = walk(DOCS_DIR).filter((p) => {
const rel = path.relative(DOCS_DIR, p).replaceAll("\\", "/");
return !LOCALES.some((l) => rel.startsWith(l + "/"));
});
const zhByRel = new Map(); // relToDocs -> abs
for (const abs of zhFiles) {
const relToDocs = path.relative(DOCS_DIR, abs).replaceAll("\\", "/");
zhByRel.set(relToDocs, abs);
}
const data = {};
for (const locale of LOCALES) {
const localeDir = path.join(DOCS_DIR, locale);
if (!fs.existsSync(localeDir)) continue;
const tFiles = walk(localeDir);
for (const tAbs of tFiles) {
const relToDocs = path.relative(DOCS_DIR, tAbs).replaceAll("\\", "/"); // en/config/log.md
const relNoLocale = relToDocs.replace(new RegExp(`^${locale}/`), ""); // config/log.md
const zhAbs = zhByRel.get(relNoLocale);
const tRoute = toRouteFromDocsRel(relToDocs); // /en/config/log
const zhRoute = toRouteFromDocsRel(relNoLocale); // /config/log
const tISO = gitLastCommitISO(tAbs);
const zhISO = zhAbs ? gitLastCommitISO(zhAbs) : null;
const stale =
Boolean(zhISO && tISO) &&
new Date(tISO).getTime() < new Date(zhISO).getTime();
data[tRoute] = {
locale,
zhRoute,
translated: true,
stale,
tLastUpdated: tISO,
zhLastUpdated: zhISO,
};
}
}
for (const [zhRel, zhAbs] of zhByRel.entries()) {
const zhRoute = toRouteFromDocsRel(zhRel);
const zhISO = gitLastCommitISO(zhAbs);
for (const locale of LOCALES) {
const tRoute = "/" + locale + (zhRoute === "/" ? "/" : zhRoute);
if (!data[tRoute]) {
data[tRoute] = {
locale,
zhRoute,
translated: false,
stale: true,
tLastUpdated: null,
zhLastUpdated: zhISO,
};
}
}
}
fs.mkdirSync(OUT_DIR, { recursive: true });
fs.writeFileSync(OUT_FILE, JSON.stringify(data, null, 2), "utf8");
console.log(`Generated i18n status -> ${OUT_FILE}`);