1
0
mirror of https://github.com/bitwarden/browser.git synced 2024-11-14 10:26:19 +01:00
bitwarden-browser/scripts/test-locales.ts
Maciej Zieniuk df14e3f030
[PM-13207] Detect incompatible locale changes (#11425)
* detecting unsupported modifications in locales

* typo fix

* limit to english locales, increased verbosity

* increased verbosity
2024-10-08 14:02:58 +02:00

106 lines
3.1 KiB
TypeScript

/* eslint no-console:0 */
import fs from "fs";
import path from "path";
type Messages = {
[id: string]: {
message: string;
};
};
function findLocaleFiles(dir: string): string[] {
return fs
.readdirSync(dir, { encoding: null, recursive: true })
.filter((file) => path.basename(file) === "messages.json")
.filter((file) => path.dirname(file).endsWith("en"))
.map((file) => path.join(dir, file));
}
function findAllLocaleFiles(rootDir: string): string[] {
return [
...findLocaleFiles(path.join(rootDir, "apps", "browser", "src")),
...findLocaleFiles(path.join(rootDir, "apps", "cli", "src")),
...findLocaleFiles(path.join(rootDir, "apps", "desktop", "src")),
...findLocaleFiles(path.join(rootDir, "apps", "web", "src")),
].map((file) => path.relative(rootDir, file));
}
function readMessagesJson(file: string): Messages {
let content = fs.readFileSync(file, { encoding: "utf-8" });
// Strip BOM
content = content.replace(/^\uFEFF/, "");
try {
return JSON.parse(content);
} catch (e: unknown) {
console.error(`ERROR: Invalid JSON file ${file}`, e);
throw e;
}
}
function compareMessagesJson(beforeFile: string, afterFile: string): boolean {
try {
console.log("Comparing locale files:", beforeFile, afterFile);
const messagesBeforeJson = readMessagesJson(beforeFile);
const messagesAfterJson = readMessagesJson(afterFile);
const messagesIdMapBefore = toMessageIdMap(messagesBeforeJson);
const messagesIdMapAfter = toMessageIdMap(messagesAfterJson);
let changed = false;
for (const [id, message] of messagesIdMapAfter.entries()) {
if (!messagesIdMapBefore.has(id)) {
console.log("New message:", id);
continue;
}
if (messagesIdMapBefore.get(id) !== message) {
console.error("ERROR: Message changed:", id);
changed = true;
}
}
return changed;
} catch (e: unknown) {
console.error(`ERROR: Unable to compare files ${beforeFile} and ${afterFile}`, e);
throw e;
}
}
function toMessageIdMap(messagesJson: Messages): Map<string, string> {
return Object.entries(messagesJson).reduce((map, [id, value]) => {
map.set(id, value.message);
return map;
}, new Map<string, string>());
}
const rootDir = path.join(__dirname, "..", "..");
const baseBranchRootDir = path.join(rootDir, "base");
const files = findAllLocaleFiles(rootDir);
console.log("Detected valid English locale files:", files);
let changedFiles = false;
for (const file of files) {
const baseBranchFile = path.join(baseBranchRootDir, file);
if (!fs.existsSync(baseBranchFile)) {
console.error("ERROR: File not found in base branch:", file);
continue;
}
const changed = compareMessagesJson(baseBranchFile, path.join(rootDir, file));
changedFiles ||= changed;
}
if (changedFiles) {
console.error(
"ERROR: Incompatible Crowdin locale files. " +
"All messages in messages.json locale files needs to be immutable and cannot be updated. " +
"If a message needs to be changed, create a new message id and update your code to use it instead.",
);
process.exit(1);
}