Skip to content

Commit 569fd11

Browse files
committed
translations: Add validation workflow
1 parent e5f0902 commit 569fd11

File tree

2 files changed

+95
-0
lines changed

2 files changed

+95
-0
lines changed
Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
const glob = require('fast-glob');
2+
const fs = require('fs');
3+
const path = require('path');
4+
5+
const KEY_REGEX = /(['`])\$\.(\w+(?:\.\w+)+)(?=;;|\1|$)/g;
6+
const LOCALE_FILE = path.resolve('locales/en_us.json');
7+
const SRC_FILES = glob.sync(['src/**/*.ts'], { dot: false });
8+
9+
const localeData = JSON.parse(fs.readFileSync(LOCALE_FILE, 'utf-8'));
10+
const flatLocaleKeys = flattenKeys(localeData);
11+
const usedKeysMap = new Map();
12+
13+
for (const file of SRC_FILES) {
14+
const content = fs.readFileSync(file, 'utf-8');
15+
let match;
16+
while ((match = KEY_REGEX.exec(content)) !== null) {
17+
const key = match[2];
18+
if (!usedKeysMap.has(key)) usedKeysMap.set(key, new Set());
19+
usedKeysMap.get(key).add(file);
20+
}
21+
}
22+
23+
const usedKeys = [...usedKeysMap.keys()];
24+
const missingKeys = usedKeys.filter((key) => !flatLocaleKeys.has(key));
25+
const unusedKeys = [...flatLocaleKeys].filter((key) => !usedKeysMap.has(key));
26+
27+
console.log('\n🔍 Localization Check Results:\n');
28+
29+
if (missingKeys.length) {
30+
console.log('❌ Missing keys in en_us.json:');
31+
missingKeys.forEach((key) => {
32+
const files = [...usedKeysMap.get(key)];
33+
files.forEach((file) => {
34+
console.log(` - ${key} (${file})`);
35+
});
36+
});
37+
} else {
38+
console.log('✅ No missing keys.');
39+
}
40+
41+
if (unusedKeys.length) {
42+
console.log('\n⚠️ Unused keys in en_us.json:');
43+
unusedKeys.forEach((key) => console.log(` - ${key}`));
44+
console.log(flatLocaleKeys.size, unusedKeys.length)
45+
} else {
46+
console.log('✅ No unused keys.');
47+
}
48+
49+
if (missingKeys.length || unusedKeys.length) {
50+
process.exit(1); // Fail the action
51+
}
52+
53+
function flattenKeys(obj, prefix = '') {
54+
const keys = new Set();
55+
for (const key in obj) {
56+
const fullKey = prefix ? `${prefix}.${key}` : key;
57+
if (typeof obj[key] === 'object' && obj[key] !== null) {
58+
for (const subKey of flattenKeys(obj[key], fullKey)) {
59+
keys.add(subKey);
60+
}
61+
} else {
62+
keys.add(fullKey);
63+
}
64+
}
65+
return keys;
66+
}
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
name: Validate Localization Keys
2+
3+
on:
4+
push:
5+
paths:
6+
- 'src/**/*.ts'
7+
- 'locales/en_us.json'
8+
- '.github/scripts/validate-translations.js'
9+
- '.github/workflows/validate-translations.yml'
10+
pull_request:
11+
12+
jobs:
13+
validate-translations:
14+
runs-on: ubuntu-latest
15+
16+
steps:
17+
- name: Checkout repo
18+
uses: actions/checkout@v4
19+
20+
- name: Set up Node.js
21+
uses: actions/setup-node@v4
22+
with:
23+
node-version: 22
24+
25+
- name: Install dependencies
26+
run: npm install fast-glob
27+
28+
- name: Run localization key check
29+
run: node .github/scripts/validate-translations.js

0 commit comments

Comments
 (0)