4e66e6a7f4
In-progress work committed to unblock the config import/export plan: - i18n: new changePassword/modelConfig/imageModels/systemConfig catalogs (zh+en) - AccountDialog/ChangePasswordDialog/ConfigDialog/ImageModelsDialog rewired - RegistryEditor/ImageModelsEditor updated for the new catalogs - system-config tabs restyled; page/layout follow-ons
84 lines
2.4 KiB
TypeScript
84 lines
2.4 KiB
TypeScript
import { describe, expect, it, vi } from "vitest";
|
|
import en from "./en";
|
|
import zh from "./zh";
|
|
import enCommon from "./en/common";
|
|
import enHeader from "./en/header";
|
|
import enThreadList from "./en/threadList";
|
|
import enChat from "./en/chat";
|
|
import enDialogs from "./en/dialogs";
|
|
import enPanels from "./en/panels";
|
|
import enLogin from "./en/login";
|
|
import enErrors from "./en/errors";
|
|
import enUserManagement from "./en/userManagement";
|
|
import enChangePassword from "./en/changePassword";
|
|
import enModelConfig from "./en/modelConfig";
|
|
import enImageModels from "./en/imageModels";
|
|
import enSystemConfig from "./en/systemConfig";
|
|
|
|
vi.mock("server-only", () => ({}));
|
|
|
|
const { API_ERROR_CODES } = await import("@/lib/server/errorCodes");
|
|
|
|
type Tree = Record<string, unknown>;
|
|
|
|
function leafPaths(tree: Tree, prefix = ""): string[] {
|
|
return Object.entries(tree).flatMap(([key, value]) => {
|
|
const path = prefix ? `${prefix}.${key}` : key;
|
|
if (value !== null && typeof value === "object") {
|
|
return leafPaths(value as Tree, path);
|
|
}
|
|
return [path];
|
|
});
|
|
}
|
|
|
|
function leafAt(tree: Tree, path: string): string {
|
|
let node: unknown = tree;
|
|
for (const key of path.split(".")) node = (node as Tree)[key];
|
|
return node as string;
|
|
}
|
|
|
|
function icuVars(message: string): string[] {
|
|
return [...message.matchAll(/\{(\w+)[,}]/g)].map((m) => m[1]).sort();
|
|
}
|
|
|
|
describe("message catalogs", () => {
|
|
it("en and zh have identical key sets", () => {
|
|
expect(leafPaths(zh).sort()).toEqual(leafPaths(en).sort());
|
|
});
|
|
|
|
it("each leaf has the same ICU variables in both locales", () => {
|
|
for (const path of leafPaths(en)) {
|
|
expect(icuVars(leafAt(zh, path)), path).toEqual(
|
|
icuVars(leafAt(en, path))
|
|
);
|
|
}
|
|
});
|
|
|
|
it("domain modules do not shadow each other at the top level", () => {
|
|
const modules = [
|
|
enCommon,
|
|
enHeader,
|
|
enThreadList,
|
|
enChat,
|
|
enDialogs,
|
|
enPanels,
|
|
enLogin,
|
|
enErrors,
|
|
enUserManagement,
|
|
enChangePassword,
|
|
enModelConfig,
|
|
enImageModels,
|
|
enSystemConfig,
|
|
];
|
|
const total = modules.reduce((n, m) => n + Object.keys(m).length, 0);
|
|
expect(Object.keys(en).length).toBe(total);
|
|
});
|
|
|
|
it("errors.* covers every code the WebUI API can emit", () => {
|
|
const errors = (en as unknown as Tree).errors as Tree;
|
|
for (const code of API_ERROR_CODES) {
|
|
expect(typeof errors[code], code).toBe("string");
|
|
}
|
|
});
|
|
});
|