// 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"; import * as path from "path"; const projectRoot = path.resolve(import.meta.dirname, ".."); /** * * @param {string} output * @param {string[]} inputs * @returns */ function translate(output, kind, inputs) { const lines = inputs.flatMap((input) => fs .readFileSync(path.resolve(projectRoot, input), "utf-8") .split("\n") .map((line) => line.trim()) .filter((line) => !line.startsWith("#") && line.length > 0), ); 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); fs.mkdirSync(langDir, { recursive: true }); const langEnPath = `${langDir}/${kind}.json`; const langEnData = translations["en"]; fs.writeFileSync(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); fs.writeFileSync(langPath, langPack); // alias zh-cn if (kind === "bundle.l10n" && lang === "zh") { const langZhCNPath = `${langDir}/${kind}.zh-cn.json`; fs.writeFileSync(langZhCNPath, langPack); } } return translations; } // todo: verify using rust function genVscodeExt() { const translations = translate("editors/vscode", "package.nls", ["locales/tinymist-vscode.toml"]); translate("editors/vscode/l10n", "bundle.l10n", ["locales/tinymist-vscode-rt.toml"]); const pat = /\%(extension\.tinymist\..*?)\%/g; const data = fs.readFileSync(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; } export const vscodeExtTranslations = genVscodeExt();