// The Import step card's sentences, as the locale files write them (#422). // // A sentence names a control through an interpolation (`StepCardText.labels`, // translated by `StepCard`); the label then reads between quotation marks, // « » in French and “ ” in English (D11), so the reader tells the button's // name from the sentence around it. The folder name of `noSources` is quoted // the same way. These tests hold the real files to that rule. import { describe, it, expect } from "vitest"; import fr from "../i18n/locales/fr.json"; import en from "../i18n/locales/en.json"; type Cards = Record; const IMPORT_CARDS: Record<"fr" | "en", Cards> = { fr: (fr as { onboarding: { card: { import: Cards } } }).onboarding.card.import, en: (en as { onboarding: { card: { import: Cards } } }).onboarding.card.import, }; const QUOTED: Record<"fr" | "en", (name: string) => RegExp> = { fr: (name) => new RegExp(`« \\{\\{${name}\\}\\} »`), en: (name) => new RegExp(`“\\{\\{${name}\\}\\}”`), }; /** The names of the plain interpolations of a sentence (`{{name}}`). */ function interpolations(sentence: string): string[] { return [...sentence.matchAll(/\{\{(\w+)\}\}/g)].map((match) => match[1]); } describe("Import step card sentences quote every control they name (#422)", () => { it.each(["fr", "en"] as const)("%s: each interpolation sits between quotation marks", (lang) => { const cards = IMPORT_CARDS[lang]; let named = 0; for (const [key, sentence] of Object.entries(cards)) { for (const name of interpolations(sentence)) { named += 1; expect(sentence, `onboarding.card.import.${key}: ${name}`).toMatch(QUOTED[lang](name)); } } // noFolder 1, noSources 3, sourceConfig 1, filePreview 2, duplicateCheck 1, confirm 1. expect(named).toBe(9); }); it.each(["fr", "en"] as const)("%s: the preview names the flip and the next button", (lang) => { expect(interpolations(IMPORT_CARDS[lang].filePreview).sort()).toEqual(["button", "flip"]); }); });