Files
mutiny-web/tools/internal-rules/lib/rules/check-i18n-keys.js
2024-02-22 21:34:19 +00:00

99 lines
3.3 KiB
JavaScript

"use strict";
const fs = require("fs");
const path = require("path");
const { parse } = require("@babel/parser");
module.exports = {
meta: {
name: "check-i18n-keys",
type: "suggestion",
docs: {
description:
"Ensure translation keys in other language files match the keys in the English translation file.",
category: "Best Practices",
recommended: true
},
fixable: null,
schema: []
},
create: function (context) {
function extractKeys(node, parentKey = "") {
const keys = [];
let properties = node.properties;
if (typeof node === "string") {
const fileContent = fs.readFileSync(node, "utf8");
const ast = parse(fileContent, {
sourceType: "module",
plugins: ["typescript", "jsx"]
});
properties =
!!ast && ast.program.body[0].declaration.properties;
}
function traverseProperties(properties, parentKey) {
properties.forEach((property) => {
if (
(property.type === "ObjectProperty" ||
property.type === "Property") &&
property.key.type === "Identifier"
) {
const currentKey = parentKey
? `${parentKey}.${property.key.name}`
: property.key.name;
keys.push(currentKey);
if (property.value.type === "ObjectExpression") {
traverseProperties(
property.value.properties,
currentKey
);
}
}
});
}
traverseProperties(properties, parentKey);
return keys;
}
return {
Program(node) {
for (const statement of node.body) {
const fallbackFilePath = path
.relative(process.cwd(), context.getFilename())
.replace(
/\/i18n\/\w+\/translations\.ts$/,
"/i18n/en/translations.ts"
);
const keys = extractKeys(statement.declaration);
const enKeys = extractKeys(fallbackFilePath);
// Report missing keys
enKeys.forEach((enKey) => {
if (!keys.includes(enKey)) {
context.report({
node: node,
message: `missing key '${enKey}'`
});
}
});
// Report extra keys
keys.forEach((key) => {
if (!enKeys.includes(key)) {
context.report({
node: node,
message: `extra key '${key}'`
});
}
});
}
}
};
}
};