Files
CC-Switch/tests/config/localeCoverage.test.ts
T

85 lines
2.3 KiB
TypeScript

import { describe, expect, it } from "vitest";
import en from "@/i18n/locales/en.json";
import ja from "@/i18n/locales/ja.json";
import zhTW from "@/i18n/locales/zh-TW.json";
import zh from "@/i18n/locales/zh.json";
type TranslationTree = Record<string, unknown>;
function flattenStrings(
value: unknown,
path: string[] = [],
result = new Map<string, string>(),
): Map<string, string> {
if (typeof value === "string") {
result.set(path.join("."), value);
} else if (typeof value === "object" && value !== null) {
for (const [key, child] of Object.entries(value)) {
flattenStrings(child, [...path, key], result);
}
}
return result;
}
function interpolationVariables(value: string): string[] {
return Array.from(
value.matchAll(/\{\{\s*([^}]+?)\s*\}\}/g),
([, name]) => name,
).sort();
}
const reference = flattenStrings(en);
const piKeysOutsideNamespace = new Set([
"apps.pi",
"deeplink.api",
"sessionManager.piDiscoveryUnavailable",
"sessionManager.piRelativeSessionDir",
"settings.browsePlaceholderPi",
"settings.piConfigDir",
"settings.piConfigDirDescription",
"settings.piImportExportBoundary",
"usage.appFilter.pi",
]);
const piReference = new Map(
[...reference].filter(
([key]) =>
key.startsWith("pi.") ||
key.startsWith("proxy.piGateway.") ||
key.startsWith("skills.piStatus.") ||
piKeysOutsideNamespace.has(key),
),
);
const locales = [
["zh", zh],
["ja", ja],
["zh-TW", zhTW],
] as const;
describe("locale coverage", () => {
it.each(locales)("covers every Pi translation key in %s", (_name, tree) => {
const translations = flattenStrings(tree as TranslationTree);
const missing = [...piReference.keys()].filter(
(key) => !translations.has(key),
);
expect(missing).toEqual([]);
});
it.each(locales)(
"preserves every Pi interpolation variable in %s",
(_name, tree) => {
const translations = flattenStrings(tree as TranslationTree);
const mismatched = [...piReference].flatMap(([key, expected]) => {
const actual = translations.get(key);
return actual !== undefined &&
interpolationVariables(actual).join("\0") !==
interpolationVariables(expected).join("\0")
? [key]
: [];
});
expect(mismatched).toEqual([]);
},
);
});