Skip to content

Commit 5f7b8f8

Browse files
authored
Merge pull request #1336 from 404mike/locale-check
Locale check script
2 parents d62ed56 + 33d06b6 commit 5f7b8f8

File tree

3 files changed

+176
-2
lines changed

3 files changed

+176
-2
lines changed

β€Žpackage.jsonβ€Ž

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,10 @@
2525
"copy-files": "copyfiles -u 1 src/**/*.svg dist/cjs && copyfiles -u 1 src/**/*.gif dist/cjs && copyfiles -u 1 src/**/*.less dist/cjs && copyfiles -u 1 src/extensions/**/*.less dist/cjs && copyfiles -u 1 src/**/*.css dist/cjs",
2626
"docs": "typedoc --plugin typedoc-plugin-missing-exports ; echo docs.universalviewer.io > docs/CNAME",
2727
"test": "jest",
28-
"prepublishOnly": "npm run build && npm run build-tsc && npm run build-es"
28+
"prepublishOnly": "npm run build && npm run build-tsc && npm run build-es",
29+
"checkLocaleUsage": "node scripts/validate_locale.ts checkLocaleUsage",
30+
"findMissingTranslations": "node scripts/validate_locale.ts missingTranslations",
31+
"findHardCodedLocaleStrings": "node scripts/validate_locale.ts hardCodedStrings"
2932
},
3033
"repository": {
3134
"type": "git",

β€Žscripts/validate_locale.tsβ€Ž

Lines changed: 171 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,171 @@
1+
const fs = require('fs');
2+
const path = require('path');
3+
4+
// Read in parameters to choose which type of validation to run
5+
let args = process.argv.slice(2);
6+
let runType = args[0];
7+
8+
// Define primary locale
9+
const primaryLocale = 'en-GB.json';
10+
11+
const checkLocaleUsage = () => {
12+
// get a list of all UV extensions
13+
const uvExtensions = getUVExtensions();
14+
15+
// Read primary locale file.
16+
let localeData = readLocaleFile(primaryLocale);
17+
// replace all values with a 0
18+
// we will increment the value for each key found in the extension config files
19+
let localeKeys = Object.keys(localeData).reduce((acc, key) => {
20+
acc[key] = 0;
21+
return acc;
22+
}, {});
23+
24+
// Loop through all UV extensions.
25+
uvExtensions.forEach(extension => {
26+
let config = readExtensionConfig(extension);
27+
// Recursively extract all locale values from any "content" objects.
28+
let contentLocaleValues = extractContentLocaleValues(config);
29+
// For each locale value found, if it exists in the primary locale keys, increment its count.
30+
contentLocaleValues.forEach(val => {
31+
if (val in localeKeys) {
32+
localeKeys[val]++;
33+
}
34+
});
35+
});
36+
37+
console.log("Final locale keys count:", localeKeys);
38+
console.log("Unused locale keys:", getUnusedLocaleKeys(localeKeys));
39+
};
40+
41+
42+
const checkHardCodedStrings = () => {
43+
let missing = [];
44+
// get a list of all UV extensions
45+
const uvExtensions = getUVExtensions();
46+
47+
// Loop through all UV extensions.
48+
uvExtensions.forEach(extension => {
49+
let config = readExtensionConfig(extension);
50+
// Recursively extract all locale values from any "content" objects.
51+
let contentLocaleValues = extractContentLocaleValues(config);
52+
// For each locale value found, if it exists in the primary locale keys, increment its count.
53+
contentLocaleValues.forEach(val => {
54+
// if val does not start with $
55+
let hasStartingDelimiter = keyStartsWithDollar(val);
56+
if (!hasStartingDelimiter) {
57+
missing.push({ extension: extension, key: val });
58+
}
59+
});
60+
});
61+
62+
console.log("missing locale keys:", missing);
63+
};
64+
65+
const keyStartsWithDollar = (val) => {
66+
if (val.substring(0, 1) !== '$') {
67+
return false
68+
}
69+
70+
return true;
71+
};
72+
73+
const getUVExtensions = () => {
74+
let extensions = [];
75+
// get a list of all UV extensions
76+
const directoryPath = path.join(__dirname, '../src/content-handlers/iiif/extensions/');
77+
78+
try {
79+
const files = fs.readdirSync(directoryPath);
80+
81+
files.forEach(function (file) {
82+
let dir = file.substring(0, 2);
83+
// only get directories that start with 'uv'
84+
if (dir === 'uv') {
85+
extensions.push(file);
86+
}
87+
});
88+
} catch (err) {
89+
console.log('Unable to scan directory: ' + err);
90+
}
91+
92+
return extensions;
93+
}
94+
95+
const getUVLocales = () => {
96+
const localeDir = path.join(__dirname, '../src/locales');
97+
const localeFiles = fs.readdirSync(localeDir);
98+
return localeFiles;
99+
};
100+
101+
const getUnusedLocaleKeys = (localeKeys) => {
102+
return Object.entries(localeKeys).filter(([key, value]) => value === 0);
103+
}
104+
105+
// Recursively extract all values in any "content" object that are strings starting with "$"
106+
const extractContentLocaleValues = (obj) => {
107+
let values = [];
108+
for (const [prop, value] of Object.entries(obj)) {
109+
if (prop === 'content' && typeof value === 'object' && value !== null) {
110+
Object.values(value).forEach(item => {
111+
if (typeof item === 'string') {
112+
values.push(item);
113+
}
114+
});
115+
} else if (typeof value === 'object' && value !== null) {
116+
values = values.concat(extractContentLocaleValues(value));
117+
}
118+
}
119+
return values;
120+
};
121+
122+
const readLocaleFile = (lang) => {
123+
const localeDir = path.join(__dirname, '../src/locales');
124+
const localeFiles = fs.readdirSync(localeDir).filter(file => file.endsWith(`${lang}`));
125+
if (localeFiles.length === 0) {
126+
throw new Error(`No locale file found for language ${lang}`);
127+
}
128+
const filePath = path.join(localeDir, localeFiles[0]);
129+
const fileContent = fs.readFileSync(filePath, 'utf8');
130+
return JSON.parse(fileContent);
131+
};
132+
133+
const readExtensionConfig = (extension) => {
134+
const configPath = path.join(__dirname, `../src/content-handlers/iiif/extensions/${extension}/config/config.json`);
135+
const configContent = fs.readFileSync(configPath, 'utf8');
136+
return JSON.parse(configContent);
137+
};
138+
139+
const missingTranslations = () => {
140+
const primaryLocaleData = readLocaleFile(primaryLocale);
141+
const allLocales = getUVLocales();
142+
143+
for (let locale of allLocales) {
144+
if (locale === primaryLocale) {
145+
continue;
146+
}
147+
const localeData = readLocaleFile(locale);
148+
// Compare primary locale keys with each other locale's keys.
149+
// If a key is missing in the other locale, log an error.
150+
for (let key of Object.keys(primaryLocaleData)) {
151+
if (!(key in localeData)) {
152+
console.error(`Key "${key}" missing in locale "${locale}"`);
153+
}
154+
}
155+
}
156+
};
157+
158+
switch (runType) {
159+
case 'checkLocaleUsage':
160+
checkLocaleUsage();
161+
break;
162+
case 'missingTranslations':
163+
missingTranslations();
164+
break;
165+
case 'hardCodedStrings':
166+
checkHardCodedStrings();
167+
break;
168+
default:
169+
console.error('No parameter or no valid run type. Please use checkLocaleUsage, missingTranslations or hardCodedStrings');
170+
break;
171+
}

β€Žsrc/locales/en-GB.jsonβ€Ž

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -119,7 +119,7 @@
119119
"$navigatorEnabled": "Navigator Enabled",
120120
"$clickToZoomEnabled": "Mouse Click To Zoom",
121121
"$reducedMotion": "Reduce motion (disables animations)",
122-
"truncateThumbnailLabels": "Truncate Thumbnail Labels",
122+
"$truncateThumbnailLabels": "Truncate Thumbnail Labels",
123123
"$preserveViewport": "Preserve Zoom",
124124
"$uvWebsite": "<a href='https://github.com/UniversalViewer/universalviewer/wiki/About'>More info about the Universal Viewer</a>",
125125
"$custom": "custom",

0 commit comments

Comments
Β (0)