feat: First iteration, multi themes, I18N
This commit is contained in:
@@ -0,0 +1,70 @@
|
||||
// Guards the content packs: every theme and language must be complete, so a
|
||||
// missing translation is caught by `npm test` instead of showing a raw key.
|
||||
|
||||
import assert from 'node:assert/strict';
|
||||
import { readdirSync } from 'node:fs';
|
||||
import { test } from 'node:test';
|
||||
import { flatKeys, loadContext, PUBLIC_DIR, readJson } from './helpers.js';
|
||||
|
||||
const ctx = loadContext();
|
||||
const codes = (dir) =>
|
||||
readdirSync(PUBLIC_DIR + dir)
|
||||
.filter((f) => f.endsWith('.json'))
|
||||
.map((f) => f.slice(0, -5));
|
||||
const themes = readdirSync(PUBLIC_DIR + 'themes', { withFileTypes: true })
|
||||
.filter((e) => e.isDirectory())
|
||||
.map((e) => e.name);
|
||||
|
||||
test('core locales define the same keys as English', () => {
|
||||
const reference = flatKeys(readJson('locales/en.json')).sort();
|
||||
for (const code of codes('locales')) {
|
||||
assert.deepEqual(flatKeys(readJson(`locales/${code}.json`)).sort(), reference, `locales/${code}.json`);
|
||||
}
|
||||
});
|
||||
|
||||
test('every effect type has a core text', () => {
|
||||
const keys = new Set(flatKeys(readJson('locales/en.json')));
|
||||
for (const u of ctx.upgrades) assert.ok(keys.has(`effect.${u.effect.type}`), u.effect.type);
|
||||
});
|
||||
|
||||
test('there is at least one theme, each with a manifest, a stylesheet and English texts', () => {
|
||||
assert.ok(themes.length >= 1);
|
||||
for (const id of themes) {
|
||||
assert.ok(readdirSync(`${PUBLIC_DIR}themes/${id}`).includes('theme.css'), `${id}/theme.css`);
|
||||
assert.ok(codes(`themes/${id}/locales`).includes('en'), `${id} needs an en locale`);
|
||||
assert.ok(readJson(`themes/${id}/theme.json`));
|
||||
}
|
||||
});
|
||||
|
||||
test('every theme names every resource, generator and upgrade, in every language', () => {
|
||||
const required = [
|
||||
'theme.name',
|
||||
'theme.title',
|
||||
'theme.res.units',
|
||||
'theme.res.unit',
|
||||
'theme.res.funds',
|
||||
'theme.res.material',
|
||||
'theme.fmt.funds',
|
||||
'theme.action.make',
|
||||
'theme.action.buyMaterial',
|
||||
...ctx.generators.flatMap((g) => [`theme.gen.${g.id}.name`, `theme.gen.${g.id}.desc`]),
|
||||
...ctx.upgrades.map((u) => `theme.upg.${u.id}`),
|
||||
];
|
||||
|
||||
for (const id of themes) {
|
||||
const reference = flatKeys(readJson(`themes/${id}/locales/en.json`)).sort();
|
||||
assert.deepEqual(reference.filter((k) => required.includes(k)).sort(), [...required].sort(), `${id}/en`);
|
||||
for (const code of codes(`themes/${id}/locales`)) {
|
||||
const keys = flatKeys(readJson(`themes/${id}/locales/${code}.json`)).sort();
|
||||
assert.deepEqual(keys, reference, `${id}/${code} differs from ${id}/en`);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
test('every theme is translated in every core language', () => {
|
||||
for (const id of themes) {
|
||||
for (const code of codes('locales')) {
|
||||
assert.ok(codes(`themes/${id}/locales`).includes(code), `${id} has no "${code}" texts`);
|
||||
}
|
||||
}
|
||||
});
|
||||
Reference in New Issue
Block a user