tinymist/scripts/build-l10n.mjs
Myriad-Dreamin 1c9db1ce69
Some checks are pending
tinymist::auto_tag / auto-tag (push) Waiting to run
tinymist::ci / Duplicate Actions Detection (push) Waiting to run
tinymist::ci / Check Clippy, Formatting, Completion, Documentation, and Tests (Linux) (push) Waiting to run
tinymist::ci / Check Minimum Rust version and Tests (Windows) (push) Waiting to run
tinymist::ci / prepare-build (push) Waiting to run
tinymist::ci / announce (push) Blocked by required conditions
tinymist::ci / build (push) Blocked by required conditions
tinymist::gh_pages / build-gh-pages (push) Waiting to run
build: make use of async io of js to speed up vscode builds (#2069)
2025-08-31 18:34:20 +08:00

107 lines
3 KiB
JavaScript

// The toml looks like that:
// # The translation are partially generated by copilot
// [description]
// en = "An integrated language service for Typst"
// zh-CN = "Typst 的集成语言服务"
import * as fs from "fs/promises";
import * as path from "path";
const projectRoot = path.resolve(import.meta.dirname, "..");
/**
*
* @param {string} output
* @param {string[]} inputs
* @returns
*/
async function translate(output, kind, inputs) {
const lines = (
await Promise.all(
inputs.map(async (input) =>
(await fs.readFile(path.resolve(projectRoot, input), "utf-8"))
.split("\n")
.map((line) => line.trim())
.filter((line) => !line.startsWith("#") && line.length > 0),
),
)
).flat();
const translations = {};
let key = "";
for (let line of lines) {
if (line.startsWith("[")) {
key = line.substring(1, line.length - 1);
if (key.startsWith('"')) {
key = JSON.parse(key);
}
} else {
const equalIndex = line.indexOf("=");
const lang = line.substring(0, equalIndex).trim();
const value = line.substring(equalIndex + 1).trim();
translations[lang] ||= {};
translations[lang][key] = JSON.parse(value);
}
}
const langs = Object.keys(translations);
const langEn = langs.find((lang) => lang === "en");
if (!langEn) {
console.error("en is required");
return;
}
const langRest = langs.filter((lang) => lang !== "en");
const langDir = path.resolve(projectRoot, output);
await fs.mkdir(langDir, { recursive: true });
const langEnPath = `${langDir}/${kind}.json`;
const langEnData = translations["en"];
await fs.writeFile(langEnPath, JSON.stringify(langEnData, null, 2));
for (let lang of langRest) {
const langPath = `${langDir}/${kind}.${lang}.json`;
const langData = translations[lang];
const langPack = JSON.stringify(langData, null, 2);
await fs.writeFile(langPath, langPack);
// alias zh-cn
if (kind === "bundle.l10n" && lang === "zh") {
const langZhCNPath = `${langDir}/${kind}.zh-cn.json`;
await fs.writeFile(langZhCNPath, langPack);
}
}
return translations;
}
// todo: verify using rust
export async function genVscodeExt() {
const translations = await translate("editors/vscode", "package.nls", [
"locales/tinymist-vscode.toml",
]);
await translate("editors/vscode/l10n", "bundle.l10n", ["locales/tinymist-vscode-rt.toml"]);
const pat = /\%(extension\.tinymist\..*?)\%/g;
const data = await fs.readFile(path.resolve(projectRoot, "editors/vscode/package.json"), "utf-8");
const matchAll = data.matchAll(pat);
const used = Array.from(matchAll).map((m) => m[1]);
used.push("description");
const en = translations["en"];
const enKeys = Object.keys(en);
const missing = used.filter((key) => !enKeys.includes(key));
if (missing.length > 0) {
console.error("Missing translations", missing);
}
const extra = enKeys.filter((key) => !used.includes(key));
if (extra.length > 0) {
console.error("Extra translations", extra);
}
return translations;
}