nginx-proxy-manager/frontend/check-locales.js

128 lines
3.3 KiB
JavaScript
Executable File

#!/usr/bin/env node
// This file does a few things to ensure that the Locales are present and valid:
// - Ensures that the name of the locale exists in the language list
// - Ensures that each locale contains the translations used in the application
// - Ensures that there are no unused translations in the locale files
// - Also checks the error messages returned by the backend
const allLocales = [
["en", "en-US"],
["de", "de-DE"],
["fa", "fa-IR"],
];
const ignoreUnused = [/^capability\..*$/, /^host-type\..*$/, /^acmesh\..*$/];
const { spawnSync } = require("child_process");
const fs = require("fs");
const tmp = require("tmp");
// Parse backend errors
const BACKEND_ERRORS_FILE = "../backend/internal/errors/errors.go";
const BACKEND_ERRORS = [];
try {
const backendErrorsContent = fs.readFileSync(BACKEND_ERRORS_FILE, "utf8");
const backendErrorsContentRes = [
...backendErrorsContent.matchAll(/errors\.New\("([^"]+)"\)/g),
];
backendErrorsContentRes.map((item) => {
BACKEND_ERRORS.push("error." + item[1]);
return null;
});
} catch (err) {
console.log("\x1b[31m%s\x1b[0m", err);
process.exit(1);
}
// get all translations used in frontend code
const tmpobj = tmp.fileSync({ postfix: ".json" });
spawnSync("yarn", ["locale-extract", "--out-file", tmpobj.name]);
const allLocalesInProject = require(tmpobj.name);
// get list og language names and locales
const langList = require("./src/locale/src/lang-list.json");
// store a list of all validation errors
const allErrors = [];
const checkLangList = (fullCode) => {
const key = "locale-" + fullCode;
if (typeof langList[key] === "undefined") {
allErrors.push(
"ERROR: `" + key + "` language does not exist in lang-list.json",
);
}
};
const compareLocale = (locale) => {
const projectLocaleKeys = Object.keys(allLocalesInProject);
// Check that locale contains the items used in the codebase
projectLocaleKeys.map((key) => {
if (typeof locale.data[key] === "undefined") {
allErrors.push(
"ERROR: `" + locale[0] + "` does not contain item: `" + key + "`",
);
}
return null;
});
// Check that locale contains all error.* items
BACKEND_ERRORS.forEach((key) => {
if (typeof locale.data[key] === "undefined") {
allErrors.push(
"ERROR: `" + locale[0] + "` does not contain item: `" + key + "`",
);
}
return null;
});
// Check that locale does not contain items not used in the codebase
const localeKeys = Object.keys(locale.data);
localeKeys.map((key) => {
let ignored = false;
ignoreUnused.map((regex) => {
if (key.match(regex)) {
ignored = true;
}
return null;
});
if (!ignored && typeof allLocalesInProject[key] === "undefined") {
// ensure this key doesn't exist in the backend errors either
if (!BACKEND_ERRORS.includes(key)) {
allErrors.push(
"ERROR: `" + locale[0] + "` contains unused item: `" + key + "`",
);
}
}
return null;
});
};
// Local all locale data
allLocales.map((locale, idx) => {
checkLangList(locale[1]);
allLocales[idx].data = require("./src/locale/src/" + locale[0] + ".json");
return null;
});
// Verify all locale data
allLocales.map((locale) => {
compareLocale(locale);
return null;
});
if (allErrors.length) {
allErrors.map((err) => {
console.log("\x1b[31m%s\x1b[0m", err);
return null;
});
process.exit(1);
}
console.log("\x1b[32m%s\x1b[0m", "Locale check passed");
process.exit(0);