summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.github/workflows/locale.yml27
-rw-r--r--locales/verify.js53
2 files changed, 80 insertions, 0 deletions
diff --git a/.github/workflows/locale.yml b/.github/workflows/locale.yml
new file mode 100644
index 0000000000..de2247e772
--- /dev/null
+++ b/.github/workflows/locale.yml
@@ -0,0 +1,27 @@
+name: Lint
+
+on:
+ push:
+ paths:
+ - locales/**
+ pull_request:
+ paths:
+ - locales/**
+
+jobs:
+ locale_verify:
+ runs-on: ubuntu-latest
+ continue-on-error: true
+ steps:
+ - uses: actions/checkout@v4.1.1
+ with:
+ fetch-depth: 0
+ submodules: true
+ - uses: pnpm/action-setup@v4
+ - uses: actions/setup-node@v4.0.2
+ with:
+ node-version-file: '.node-version'
+ cache: 'pnpm'
+ - run: corepack enable
+ - run: pnpm i --frozen-lockfile
+ - run: cd locales && node verify.js
diff --git a/locales/verify.js b/locales/verify.js
new file mode 100644
index 0000000000..a8e9875d6e
--- /dev/null
+++ b/locales/verify.js
@@ -0,0 +1,53 @@
+import locales from './index.js';
+
+let valid = true;
+
+function writeError(type, lang, tree, data) {
+ process.stderr.write(JSON.stringify({ type, lang, tree, data }));
+ process.stderr.write('\n');
+ valid = false;
+}
+
+function verify(expected, actual, lang, trace) {
+ for (let key in expected) {
+ if (!Object.prototype.hasOwnProperty.call(actual, key)) {
+ continue;
+ }
+ if (typeof expected[key] === 'object') {
+ if (typeof actual[key] !== 'object') {
+ writeError('mismatched_type', lang, trace ? `${trace}.${key}` : key, { expected: 'object', actual: typeof actual[key] });
+ continue;
+ }
+ verify(expected[key], actual[key], lang, trace ? `${trace}.${key}` : key);
+ } else if (typeof expected[key] === 'string') {
+ switch (typeof actual[key]) {
+ case 'object':
+ writeError('mismatched_type', lang, trace ? `${trace}.${key}` : key, { expected: 'string', actual: 'object' });
+ break;
+ case 'undefined':
+ continue;
+ case 'string':
+ const expectedParameters = new Set(expected[key].match(/\{[^}]+\}/g)?.map((s) => s.slice(1, -1)));
+ const actualParameters = new Set(actual[key].match(/\{[^}]+\}/g)?.map((s) => s.slice(1, -1)));
+ for (let parameter of expectedParameters) {
+ if (!actualParameters.has(parameter)) {
+ writeError('missing_parameter', lang, trace ? `${trace}.${key}` : key, { parameter });
+ }
+ }
+ }
+ }
+ }
+}
+
+const { ['ja-JP']: original, ...verifiees } = locales;
+
+for (let lang in verifiees) {
+ if (!Object.prototype.hasOwnProperty.call(locales, lang)) {
+ continue;
+ }
+ verify(original, verifiees[lang], lang);
+}
+
+if (!valid) {
+ process.exit(1);
+}