"use strict"; // The bundled plugins written in Czech translate through ui/i18n.js (Czech texts are the keys). Every key used in // index.html (data-i18n*) and every literal t("…")/k("…") key in index.js needs an English and a German text with the same // {placeholders}, and no Czech text may stay outside the catalog. const test = require("node:test"); const assert = require("node:assert/strict"); const fs = require("node:fs"); const path = require("node:path"); const ROOT = path.join(__dirname, "../src/main/firstPartyPlugins"); const PLUGINS = ["chj.log-viewer", "chj.key-generator", "chj.nginx-manager", "chj.system-monitor", "chj.file-manager", "chj.users"]; const CZECH = /[ěščřžýáíéůúťďňĚŠČŘŽÝÁÍÉŮÚŤĎŇ]/; const placeholders = (text) => [...String(text).matchAll(/\{(\w+)\}/g)].map((match) => match[1]).sort(); const decode = (text) => text.replace(/"/g, "\"").replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">"); function usedKeys(ui) { const html = fs.readFileSync(path.join(ui, "index.html"), "utf8"); const js = fs.readFileSync(path.join(ui, "index.js"), "utf8"); const keys = new Set(); for (const match of html.matchAll(/data-i18n(?:-placeholder|-title|-aria-label)?="([^"]*)"/g)) keys.add(decode(match[1])); for (const match of js.matchAll(/\b[tk]\(\s*("(?:[^"\\]|\\.)*")/g)) keys.add(JSON.parse(match[1])); return { html, js, keys }; } for (const plugin of PLUGINS) { test(`${plugin}: every UI text has English and German translations`, () => { const ui = path.join(ROOT, plugin, "0.0.1/ui"); const { catalogs, createI18n } = require(path.join(ui, "i18n.js")); const { html, js, keys } = usedKeys(ui); assert.ok(keys.size > 0); for (const key of keys) { for (const language of ["en", "de"]) { const value = catalogs[language][key]; assert.equal(typeof value, "string", `${language} missing: ${key}`); assert.equal(CZECH.test(value), false, `${language} still Czech: ${key}`); assert.deepEqual(placeholders(value), placeholders(key), `${language} placeholders: ${key}`); } } assert.match(html, /