mirror of
https://github.com/Myriad-Dreamin/tinymist.git
synced 2025-07-07 21:15:03 +00:00

* feat: runtime translation * feat: poc of rust translation * feat: clean up implementation * feat: initialize correctly * dev: remove dirty log * dev: rename l10nMsg * fix: desc * feat: update assets building * feat: update assets building * build: update cargo.lock * fix: warnings * fix: warnings * dev: expose api * fix: compile error * fix: compile errors in scripts
104 lines
3 KiB
JavaScript
104 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";
|
|
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();
|