Files
kandev/apps/web/lib/plugins/plugin-translations.test.ts

51 lines
1.8 KiB
TypeScript

import { afterEach, describe, expect, it } from "vitest";
import { i18n } from "@/lib/i18n";
import {
pluginTranslationNamespace,
registerPluginTranslations,
unregisterPluginTranslations,
} from "./plugin-translations";
const PLUGIN_ID = "translation-test";
afterEach(() => unregisterPluginTranslations(PLUGIN_ID));
describe("plugin translations", () => {
it("isolates catalogs by plugin and removes them on revocation", () => {
const namespace = pluginTranslationNamespace(PLUGIN_ID);
registerPluginTranslations(PLUGIN_ID, { en: { greeting: "Hello {{name}}" } });
expect(i18n.t(`${namespace}:greeting`, { name: "Ada" })).toBe("Hello Ada");
unregisterPluginTranslations(PLUGIN_ID);
expect(i18n.hasResourceBundle("en", namespace)).toBe(false);
});
it("rejects unsupported locales and unsafe keys", () => {
expect(() =>
registerPluginTranslations(PLUGIN_ID, {
en: { greeting: "Hello" },
fr: { greeting: "Bonjour" },
}),
).toThrow("unsupported translation locale");
expect(() =>
registerPluginTranslations(PLUGIN_ID, { en: { "__proto__.polluted": "unsafe" } }),
).toThrow("invalid translation message");
});
it("requires an English fallback catalog", () => {
expect(() => registerPluginTranslations(PLUGIN_ID, { "pt-pt": { greeting: "Olá" } })).toThrow(
"English fallback",
);
});
it("keeps the active catalog when a replacement is invalid", () => {
const namespace = pluginTranslationNamespace(PLUGIN_ID);
registerPluginTranslations(PLUGIN_ID, { en: { greeting: "Hello" } });
expect(() => registerPluginTranslations(PLUGIN_ID, { en: { "unsafe.key": "broken" } })).toThrow(
"invalid translation message",
);
expect(i18n.t(`${namespace}:greeting`)).toBe("Hello");
});
});