Initial commit (unpacked platform)

This commit is contained in:
Sven (AAMOS AI)
2026-08-05 19:21:11 +07:00
commit ac5340195a
314 changed files with 57584 additions and 0 deletions
+132
View File
@@ -0,0 +1,132 @@
import { describe, expect, it } from "vitest";
import { getLanguageTag, setLocale, t } from "../src/lib/i18n";
import { formatMinor } from "../src/lib/money";
import sv from "../src/locales/sv/common.json";
import en from "../src/locales/en/common.json";
import es from "../src/locales/es/common.json";
import it_ from "../src/locales/it/common.json";
import de from "../src/locales/de/common.json";
import fr from "../src/locales/fr/common.json";
import da from "../src/locales/da/common.json";
import nb from "../src/locales/nb/common.json";
import fi from "../src/locales/fi/common.json";
import nl from "../src/locales/nl/common.json";
import pl from "../src/locales/pl/common.json";
import pt from "../src/locales/pt/common.json";
describe("i18n (i18n-spec §5, §78 M4, D-031)", () => {
it("ALLA 12 språk har samma basnycklar (pluralvarianter får skilja per språk)", () => {
const baseKeys = (obj: Record<string, string>) =>
[
...new Set(
Object.keys(obj).map((k) => {
const suffix = k.split("_").pop();
return suffix && ["one", "few", "many", "other"].includes(suffix)
? k.slice(0, k.lastIndexOf("_"))
: k;
}),
),
].sort();
const base = baseKeys(sv);
const locales = { en, es, it: it_, de, fr, da, nb, fi, nl, pl, pt };
for (const [name, locale] of Object.entries(locales)) {
expect(baseKeys(locale), `språk: ${name}`).toEqual(base);
}
});
it("interpolerar {brand} från konfig aldrig hårdkodat namn", () => {
setLocale("sv-SE");
const text = t("memory.title");
expect(text).not.toContain("{brand}");
expect(text.length).toBeGreaterThan(0);
});
it("plural via Intl.PluralRules: 1 dag / 3 dagar", () => {
setLocale("sv-SE");
expect(t("home.expiresIn", { days: 1, count: 1 })).toBe("1 dag kvar");
expect(t("home.expiresIn", { days: 3, count: 3 })).toBe("3 dagar kvar");
});
it("språkbyte utan omstart + fallback till sv för okända språk", () => {
setLocale("en-US");
expect(t("tabs.home")).toBe("At home");
expect(getLanguageTag()).toBe("en-US");
setLocale("zz-ZZ"); // stöds inte -> sv
expect(t("tabs.home")).toBe("Hemma");
setLocale("sv-SE");
});
it("pengar formatteras per språk ur minor units (i18n-spec §20)", () => {
setLocale("sv-SE");
const svText = formatMinor(7900, "SEK");
expect(svText).toMatch(/79/);
setLocale("en-US");
const enText = formatMinor(7900, "SEK");
expect(enText).toMatch(/79/);
expect(enText).not.toBe(svText); // olika locale -> olika formatering
setLocale("sv-SE");
});
});
describe("språkpolicy D-031 automatik + manuellt val", () => {
it("spanska väljs och pluralformer fungerar", () => {
setLocale("es-ES");
expect(t("tabs.whatToEat")).toBe("¿Qué comemos?");
expect(t("home.expiresIn", { days: 1, count: 1 })).toBe("Queda 1 día");
expect(t("home.expiresIn", { days: 3, count: 3 })).toBe("Quedan 3 días");
setLocale("sv-SE");
});
it("regional variant faller till primärspråket (es-MX -> es)", () => {
setLocale("es-MX");
expect(t("tabs.home")).toBe("En casa");
expect(getLanguageTag()).toBe("es-MX"); // Intl behåller regionen
setLocale("sv-SE");
});
it("italienska, tyska och franska svarar på sina språk", () => {
setLocale("it-IT");
expect(t("tabs.whatToEat")).toBe("Cosa mangiamo?");
setLocale("de-DE");
expect(t("tabs.whatToEat")).toBe("Was essen wir?");
setLocale("fr-FR");
expect(t("tabs.whatToEat")).toBe("On mange quoi ?");
setLocale("sv-SE");
});
it("polska pluralformer: one/few/many via Intl.PluralRules", () => {
setLocale("pl-PL");
expect(t("recipe.portions", { count: 1 })).toBe("1 porcja");
expect(t("recipe.portions", { count: 3 })).toBe("3 porcje");
expect(t("recipe.portions", { count: 5 })).toBe("5 porcji");
expect(t("recipe.portions", { count: 22 })).toBe("22 porcje");
setLocale("sv-SE");
});
it("nordiska språk + nederländska/portugisiska svarar rätt", () => {
setLocale("da-DK");
expect(t("tabs.whatToEat")).toBe("Hvad skal vi spise?");
setLocale("nb-NO");
expect(t("tabs.whatToEat")).toBe("Hva skal vi spise?");
setLocale("fi-FI");
expect(t("tabs.whatToEat")).toBe("Mitä syödään?");
setLocale("nl-NL");
expect(t("tabs.whatToEat")).toBe("Wat eten we?");
setLocale("pt-PT");
expect(t("tabs.whatToEat")).toBe("O que vamos comer?");
setLocale("sv-SE");
});
it("ostött språk faller till svenska i t(), utan krasch", () => {
setLocale("el-GR"); // grekiska stöds inte ännu
expect(t("tabs.home")).toBe("Hemma");
setLocale("sv-SE");
});
it("pt-BR får portugisiska resurser med brasiliansk Intl-formattering", () => {
setLocale("pt-BR");
expect(t("tabs.home")).toBe("Em casa");
expect(getLanguageTag()).toBe("pt-BR");
setLocale("sv-SE");
});
});