feat: add Condo owner desk frontend and backend
This commit is contained in:
81
tests/i18n.test.mjs
Normal file
81
tests/i18n.test.mjs
Normal file
@@ -0,0 +1,81 @@
|
||||
import assert from "node:assert/strict";
|
||||
import { readFile } from "node:fs/promises";
|
||||
import test from "node:test";
|
||||
import vm from "node:vm";
|
||||
|
||||
const appSource = await readFile(new URL("../app.js", import.meta.url), "utf8");
|
||||
const htmlSource = await readFile(new URL("../index.html", import.meta.url), "utf8");
|
||||
const cssSource = await readFile(new URL("../styles.css", import.meta.url), "utf8");
|
||||
|
||||
function loadDictionaries() {
|
||||
const start = appSource.indexOf("const I18N = ");
|
||||
const end = appSource.indexOf("\n\nconst $ =", start);
|
||||
assert.notEqual(start, -1, "I18N block should exist");
|
||||
assert.notEqual(end, -1, "I18N block should have a stable end marker");
|
||||
const expression = appSource.slice(start + "const I18N = ".length, end).trim().replace(/;$/, "");
|
||||
return vm.runInNewContext(`(${expression})`, {
|
||||
formatNumber: value => String(value)
|
||||
});
|
||||
}
|
||||
|
||||
const dictionaries = loadDictionaries();
|
||||
const locales = Object.keys(dictionaries);
|
||||
|
||||
function placeholderNames(value) {
|
||||
if (typeof value === "function") {
|
||||
const match = value.toString().match(/\(\s*\{([^}]*)\}\s*\)/);
|
||||
return match
|
||||
? match[1].split(",").map(name => name.trim().split(/\s*=/)[0]).filter(Boolean).sort()
|
||||
: [];
|
||||
}
|
||||
return [...String(value).matchAll(/\{(\w+)\}/g)].map(match => match[1]).sort();
|
||||
}
|
||||
|
||||
test("all three locale dictionaries have identical keys", () => {
|
||||
assert.deepEqual(locales, ["en", "zh", "th"]);
|
||||
const expected = Object.keys(dictionaries.en).sort();
|
||||
assert.equal(expected.length, 195);
|
||||
for (const locale of locales) {
|
||||
assert.deepEqual(Object.keys(dictionaries[locale]).sort(), expected, `${locale} key parity`);
|
||||
}
|
||||
});
|
||||
|
||||
test("parameter placeholders stay aligned across locales", () => {
|
||||
for (const key of Object.keys(dictionaries.en)) {
|
||||
const expected = placeholderNames(dictionaries.en[key]);
|
||||
for (const locale of locales.slice(1)) {
|
||||
assert.deepEqual(placeholderNames(dictionaries[locale][key]), expected, `${locale}.${key} placeholders`);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
test("all literal translation references resolve in every locale", () => {
|
||||
const referenced = new Set();
|
||||
for (const match of appSource.matchAll(/\bt\(\s*["']([^"']+)["']/g)) referenced.add(match[1]);
|
||||
for (const match of htmlSource.matchAll(/data-i18n(?:-placeholder|-aria-label)?="([^"]+)"/g)) referenced.add(match[1]);
|
||||
for (const key of referenced) {
|
||||
for (const locale of locales) assert.ok(key in dictionaries[locale], `${locale}.${key} is defined`);
|
||||
}
|
||||
assert.ok(referenced.size >= 100, `expected broad translation coverage, got ${referenced.size}`);
|
||||
});
|
||||
|
||||
test("Thai locale metadata and three-way controls are present", () => {
|
||||
assert.match(appSource, /th:\s*Object\.freeze\(\{ html: "th", intl: "th-TH-u-ca-gregory-nu-latn"/);
|
||||
assert.equal((htmlSource.match(/data-login-language=/g) || []).length, 3);
|
||||
assert.equal((htmlSource.match(/data-language=/g) || []).length, 3);
|
||||
assert.match(cssSource, /grid-template-rows: repeat\(3, 1fr\)/);
|
||||
assert.match(cssSource, /grid-template-columns: repeat\(3, 1fr\)/);
|
||||
assert.match(cssSource, /\[data-locale="th"\][^{]*\{ transform: translateY\(200%\); \}/);
|
||||
assert.match(cssSource, /\[data-locale="th"\][^{]*\{ transform: translateX\(200%\); \}/);
|
||||
});
|
||||
|
||||
test("Thai messages do not fall back for representative runtime states", () => {
|
||||
const keys = [
|
||||
"signIn", "invalidCredentials", "sessionExpired", "runtimeApiLoadingMessage", "accountsShown",
|
||||
"recordsShown", "checkoutLater", "insufficientPrivileges", "usageSaveNetwork", "usageSavedMessage"
|
||||
];
|
||||
for (const key of keys) {
|
||||
assert.notEqual(dictionaries.th[key], undefined, `Thai key ${key}`);
|
||||
if (typeof dictionaries.th[key] === "string") assert.notEqual(dictionaries.th[key], dictionaries.en[key], `Thai copy for ${key}`);
|
||||
}
|
||||
});
|
||||
Reference in New Issue
Block a user