From 7cdd2b6321475e9a4439053c7d1e0878919ebe8e Mon Sep 17 00:00:00 2001 From: Musiker15 Date: Thu, 29 Oct 2026 06:51:37 +0100 Subject: [PATCH] Label every field type in the builder builder.ft had labels for 24 of the 39 field types, and the builder falls back to the raw key for the rest. A form imported with discord_user, country, steam_hex, ranking or one of the other eleven showed keys like "steam_hex" in the outline and the type picker. All 15 missing labels are added in the seven languages, and a test checks that every type in FIELD_TYPES has a label in every dictionary, so a new field type can't ship without one. --- apps/web/src/i18n/dictionaries.ts | 105 ++++++++++++++++++++ apps/web/src/i18n/field-type-labels.test.ts | 14 +++ 2 files changed, 119 insertions(+) create mode 100644 apps/web/src/i18n/field-type-labels.test.ts diff --git a/apps/web/src/i18n/dictionaries.ts b/apps/web/src/i18n/dictionaries.ts index a020a61..6061567 100644 --- a/apps/web/src/i18n/dictionaries.ts +++ b/apps/web/src/i18n/dictionaries.ts @@ -1174,6 +1174,21 @@ const en = { heading: "Heading", paragraph: "Paragraph", divider: "Divider", + password: "Password", + multi_select: "Multi-select list", + ranking: "Ranking", + time: "Time", + datetime: "Date and time", + address: "Address", + country: "Country", + discord_user: "Discord user", + steam_hex: "Steam hex", + fivem_id: "FiveM ID", + age_check: "Age check", + captcha: "Captcha", + section_break: "Section break", + image_block: "Image", + spacer: "Spacer", }, autom: { ruleN: "Rule {n}", @@ -2490,6 +2505,21 @@ const de: Dictionary = { heading: "Überschrift", paragraph: "Absatz", divider: "Trenner", + password: "Passwort", + multi_select: "Mehrfachauswahl-Liste", + ranking: "Rangfolge", + time: "Uhrzeit", + datetime: "Datum und Uhrzeit", + address: "Adresse", + country: "Land", + discord_user: "Discord-Nutzer", + steam_hex: "Steam-Hex", + fivem_id: "FiveM-ID", + age_check: "Altersprüfung", + captcha: "Captcha", + section_break: "Abschnittswechsel", + image_block: "Bild", + spacer: "Abstand", }, autom: { ruleN: "Regel {n}", @@ -3800,6 +3830,21 @@ const hu: Dictionary = { heading: "Címsor", paragraph: "Bekezdés", divider: "Elválasztó", + password: "Jelszó", + multi_select: "Többválasztós lista", + ranking: "Rangsor", + time: "Idő", + datetime: "Dátum és idő", + address: "Cím", + country: "Ország", + discord_user: "Discord-felhasználó", + steam_hex: "Steam hex", + fivem_id: "FiveM-azonosító", + age_check: "Életkor-ellenőrzés", + captcha: "Captcha", + section_break: "Szakaszhatár", + image_block: "Kép", + spacer: "Térköz", }, autom: { ruleN: "{n}. szabály", @@ -5106,6 +5151,21 @@ const fr: Dictionary = { heading: "Titre", paragraph: "Paragraphe", divider: "Séparateur", + password: "Mot de passe", + multi_select: "Liste à choix multiples", + ranking: "Classement", + time: "Heure", + datetime: "Date et heure", + address: "Adresse", + country: "Pays", + discord_user: "Utilisateur Discord", + steam_hex: "Steam hex", + fivem_id: "ID FiveM", + age_check: "Vérification de l’âge", + captcha: "Captcha", + section_break: "Saut de section", + image_block: "Image", + spacer: "Espacement", }, autom: { ruleN: "Règle {n}", @@ -6410,6 +6470,21 @@ const es: Dictionary = { heading: "Encabezado", paragraph: "Párrafo", divider: "Separador", + password: "Contraseña", + multi_select: "Lista de selección múltiple", + ranking: "Clasificación", + time: "Hora", + datetime: "Fecha y hora", + address: "Dirección", + country: "País", + discord_user: "Usuario de Discord", + steam_hex: "Steam hex", + fivem_id: "ID de FiveM", + age_check: "Verificación de edad", + captcha: "Captcha", + section_break: "Salto de sección", + image_block: "Imagen", + spacer: "Espaciador", }, autom: { ruleN: "Regla {n}", @@ -7712,6 +7787,21 @@ const pt: Dictionary = { heading: "Título", paragraph: "Parágrafo", divider: "Divisor", + password: "Senha", + multi_select: "Lista de seleção múltipla", + ranking: "Classificação", + time: "Hora", + datetime: "Data e hora", + address: "Endereço", + country: "País", + discord_user: "Usuário do Discord", + steam_hex: "Steam hex", + fivem_id: "ID do FiveM", + age_check: "Verificação de idade", + captcha: "Captcha", + section_break: "Quebra de seção", + image_block: "Imagem", + spacer: "Espaçador", }, autom: { ruleN: "Regra {n}", @@ -9006,6 +9096,21 @@ const pl: Dictionary = { heading: "Nagłówek", paragraph: "Akapit", divider: "Separator", + password: "Hasło", + multi_select: "Lista wielokrotnego wyboru", + ranking: "Ranking", + time: "Godzina", + datetime: "Data i godzina", + address: "Adres", + country: "Kraj", + discord_user: "Użytkownik Discord", + steam_hex: "Steam hex", + fivem_id: "ID FiveM", + age_check: "Weryfikacja wieku", + captcha: "Captcha", + section_break: "Podział sekcji", + image_block: "Obraz", + spacer: "Odstęp", }, autom: { ruleN: "Reguła {n}", diff --git a/apps/web/src/i18n/field-type-labels.test.ts b/apps/web/src/i18n/field-type-labels.test.ts new file mode 100644 index 0000000..90850d2 --- /dev/null +++ b/apps/web/src/i18n/field-type-labels.test.ts @@ -0,0 +1,14 @@ +import { FIELD_TYPES } from "@msk-forms/shared"; +import { describe, expect, it } from "vitest"; + +import { dictionaries } from "./dictionaries"; + +describe("builder field type labels", () => { + // The builder falls back to the raw type key for a missing label, so an + // imported form with, say, `steam_hex` would show that key to the owner. + it.each(Object.entries(dictionaries))("%s has a label for every field type", (_, dict) => { + const labels = dict.builder.ft as Record; + const missing = FIELD_TYPES.filter((type) => !labels[type]); + expect(missing).toEqual([]); + }); +});