import { afterEach, describe, expect, it, vi } from "vitest"; import { setLocale } from "./locale.svelte"; import { t } from "./t"; import { LOCALE_TAGS } from "./dict"; import { normalizeForSearch, scoreDoc } from "./matching"; import { toolSearchDoc } from "./tool-strings"; import { TOOLS } from "../registry"; afterEach(() => { setLocale("ru"); vi.unstubAllGlobals(); }); describe("Смоук §6 i18n", () => { it("1. html lang следует за локалью", () => { const doc = { documentElement: { lang: "" } }; vi.stubGlobal("document", doc); setLocale("en"); expect(doc.documentElement.lang).toBe("en"); setLocale("ru"); expect(doc.documentElement.lang).toBe("ru"); }); it("3. Ключевые секции переведены без смеси языков", () => { const samples: Array<[string, string, string]> = [ ["header.workspace", "Рабочая область", "Workspace"], ["catalog.heading", "Каталог инструментов", "Tool catalog"], [ "home.heroTitle", "Что делаем с изображением?", "What do you want to do", ], ["chain.inputLegend", "Вход", "Input"], ["resultCard.nextTool", "Следующий инструмент", "Next tool"], ["download.busy", "Готовим файл", "Preparing file"], ]; for (const [key, ruPart, enPart] of samples) { setLocale("ru"); expect(t(key), key + " @ru").toContain(ruPart); setLocale("en"); expect(t(key), key + " @en").toContain(enPart); } }); it("5. Ошибки с vars локализуются на оба языка", () => { setLocale("ru"); expect(t("errors.badHex", { value: "#zz" })).toBe( 'Некорректный HEX-цвет: "#zz"', ); expect(t("errors.toolNotFound", { id: "x" })).toContain("не найден"); setLocale("en"); expect(t("errors.badHex", { value: "#zz" })).toBe( 'Invalid HEX color: "#zz"', ); }); it("6. Поиск кросс-языковой в обе стороны", () => { const ids = (q: string) => TOOLS.filter((tool) => { const s = scoreDoc(toolSearchDoc(tool), normalizeForSearch(q)); return s !== null && s > 0; }).map((tool) => tool.id); setLocale("ru"); let hits = ids("rotate"); expect(hits).toContain("rotate-png"); hits = ids("повер"); expect(hits).toContain("rotate-png"); setLocale("en"); hits = ids("пово"); expect(hits).toContain("rotate-free-png"); hits = ids("rotate"); expect(hits).toContain("rotate-png"); }); it("6b. Ё не мешает совпадению", () => { const blackWhite = TOOLS.find((tool) => tool.id === "black-and-white-png")!; setLocale("ru"); const hit = scoreDoc( toolSearchDoc(blackWhite), normalizeForSearch("ЧЁРНО"), ); expect(hit).not.toBeNull(); const withoutYo = scoreDoc( toolSearchDoc(blackWhite), normalizeForSearch("черно"), ); expect(withoutYo).not.toBeNull(); }); it("7. Теги локалей для форматирования чисел корректны", () => { expect(LOCALE_TAGS.ru).toBe("ru-RU"); expect(LOCALE_TAGS.en).toBe("en-US"); }); });