Skip to content

Commit

Permalink
add translation key ci check
Browse files Browse the repository at this point in the history
  • Loading branch information
benalleng committed Feb 22, 2024
1 parent 9db53cc commit 4ef4ab3
Show file tree
Hide file tree
Showing 9 changed files with 1,165 additions and 4 deletions.
10 changes: 8 additions & 2 deletions .eslintrc.cjs
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,13 @@ module.exports = {
rules: {
"@typescript-eslint/no-var-requires": "off" // Disable this specific rule for CJS files
}
}
},
{
files: ['src/i18n/**/translations.ts'],
rules: {
"internal-rules/check-i18n-keys": "off" //Disabled so no warnings are presented everytime pre-commit is run
}
},
],
parser: "@typescript-eslint/parser",
parserOptions: {
Expand All @@ -32,7 +38,7 @@ module.exports = {
jsx: true
}
},
plugins: ["@typescript-eslint", "solid", "import"],
plugins: ["@typescript-eslint", "solid", "import", "internal-rules"],
rules: {
"@typescript-eslint/no-unused-vars": [
"warn",
Expand Down
5 changes: 5 additions & 0 deletions justfile
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,11 @@ dev:
pre:
pnpm run pre-commit

i18n LANG:
#!/bin/bash

pnpm eslint "./src/i18n/{{LANG}}/translations.ts" --rule "{internal-rules/check-i18n-keys: warn}"

local:
pnpm install && pnpm link --global "@mutinywallet/mutiny-wasm"

Expand Down
6 changes: 4 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,9 @@
"dev": "vite",
"build": "tsc && vite build",
"check-types": "tsc --noemit",
"eslint": "eslint src",
"pre-commit": "pnpm run eslint && pnpm run check-types && pnpm run format",
"eslint-src": "eslint src",
"check-i18n-keys": "eslint src/i18n/**/translations.ts --rule \"{internal-rules/check-i18n-keys: warn}\"",
"pre-commit": "pnpm eslint-src && pnpm run check-types && pnpm run format",
"format": "prettier --write \"{.,src/**,e2e/**}/*.{ts,tsx,js,jsx,json,css,scss,md}\"",
"check-format": "prettier --check \"src/**/*.{ts,tsx,js,jsx,json,css,scss,md}\""
},
Expand All @@ -26,6 +27,7 @@
"eslint": "^8.52.0",
"eslint-import-resolver-typescript": "2.7.1",
"eslint-plugin-import": "2.27.5",
"eslint-plugin-internal-rules": "file:tools/internal-rules",
"eslint-plugin-prettier": "4.2.1",
"eslint-plugin-solid": "0.13.0",
"postcss": "^8.4.31",
Expand Down
20 changes: 20 additions & 0 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

19 changes: 19 additions & 0 deletions tools/internal-rules/.eslintrc.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
"use strict";

module.exports = {
root: true,
extends: [
"eslint:recommended",
"plugin:eslint-plugin/recommended",
"plugin:node/recommended"
],
env: {
node: true
},
overrides: [
{
files: ["tests/**/*.js"],
env: { mocha: true }
}
]
};
18 changes: 18 additions & 0 deletions tools/internal-rules/lib/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
/**
* @fileoverview internal eslint rules
* @author
*/
"use strict";

//------------------------------------------------------------------------------
// Requirements
//------------------------------------------------------------------------------

const requireIndex = require("requireindex");

//------------------------------------------------------------------------------
// Plugin Definition
//------------------------------------------------------------------------------

// import all rules in lib/rules
module.exports.rules = requireIndex(__dirname + "/rules");
98 changes: 98 additions & 0 deletions tools/internal-rules/lib/rules/check-i18n-keys.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
"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}'`
});
}
});
}
}
};
}
};
32 changes: 32 additions & 0 deletions tools/internal-rules/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
{
"name": "eslint-plugin-internal-rules",
"version": "0.0.0",
"description": "internal eslint rules",
"keywords": [
"eslint",
"eslintplugin",
"eslint-plugin"
],
"author": "",
"main": "./lib/index.js",
"exports": "./lib/index.js",
"scripts": {
"lint": "npm-run-all \"lint:*\"",
"lint:js": "eslint ."
},
"dependencies": {
"requireindex": "^1.2.0"
},
"devDependencies": {
"eslint": "^8.19.0",
"eslint-plugin-eslint-plugin": "^5.0.0",
"eslint-plugin-node": "^11.1.0"
},
"engines": {
"node": "^14.17.0 || ^16.0.0 || >= 18.0.0"
},
"peerDependencies": {
"eslint": ">=7"
},
"license": "ISC"
}
Loading

0 comments on commit 4ef4ab3

Please sign in to comment.