Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions apps/web/src/components/language-switcher.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import { useEffect, useRef, useState } from "react";
const LOCALES = [
{ value: "en", short: "EN", label: "English" },
{ value: "de", short: "DE", label: "Deutsch" },
{ value: "hu", short: "HU", label: "Magyar" },
] as const;

export function LanguageSwitcher({ locale }: { locale: string }) {
Expand Down
196 changes: 194 additions & 2 deletions apps/web/src/i18n/dictionaries.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
export type Locale = "en" | "de";
export type Locale = "en" | "de" | "hu";

const en = {
header: { login: "Log in", dashboard: "Dashboard", logout: "Log out", toggleTheme: "Toggle theme", language: "Language" },
Expand Down Expand Up @@ -386,4 +386,196 @@ const de: Dictionary = {
authError: "Anmeldung fehlgeschlagen. Bitte versuche es erneut.",
};

export const dictionaries: Record<Locale, Dictionary> = { en, de };
const hu: Dictionary = {
header: { login: "Bejelentkezés", dashboard: "Vezérlőpult", logout: "Kijelentkezés", toggleTheme: "Téma váltása", language: "Nyelv" },
footer: {
tagline: "Jelentkezési űrlapok valódi állapotkövetéssel, a MSK Scripts-től.",
product: "Termék", ecosystem: "Ökoszisztéma", legal: "Jogi információk",
demoForm: "Demo űrlap", documentation: "Dokumentáció", github: "GitHub",
imprint: "Impresszum", privacy: "Adatvédelem", terms: "Felhasználási feltételek",
rights: "Minden jog fenntartva.",
},
hero: {
badge: "Jelentkezési platform",
headPre: "Jelentkezési űrlapok valódi ", headAccent: "állapotkövetéssel", headPost: ".",
sub: "Hozz létre űrlapot, oszd meg a linket, és a jelentkezők élőben követhetik az állapotukat. Discord bottal bármelyik szerver meghívhatja.",
loginDiscord: "Bejelentkezés Discorddal", demo: "Demo űrlap megtekintése", openDashboard: "Vezérlőpult megnyitása",
inviteBot: "Bot meghívása",
},
features: {
title: "Amit a legtöbb űrlapeszköz kihagy.",
sub: "Egy űrlap egyszerű. A nehéz rész elmondani az embereknek, mi történt a beküldés után. Pontosan erről szól a MSK Forms.",
uspTitle: "A jelentkezők mindig tudják, hol tartanak.",
uspBody:
"Minden beküldés privát linket kap. Az állapot frissül, amint egy bíráló intézkedik – ugyanazon az oldalon, ahol jelentkeztek. Nincs több „láttad a jelentkezésem?”",
sSubmitted: "Beküldve", sInReview: "Elbírálás alatt", sAccepted: "Elfogadva",
botTitle: "Meghívható bot",
botBody: "Tedd ki az űrlapokat egy csatornába, és küldd az állapotfrissítéseket közvetlenül a jelentkezőknek privát üzenetben.",
buildTitle: "Építsd kód nélkül",
buildBody: "Állítsd össze az űrlapokat típusos mezőkből: szöveg, választás, dátum, hozzájárulás. Másodpercek alatt kész.",
},
steps: {
title: "Nulláról élesbe három lépésben.",
build: "Építés", buildBody: "Húzd be a szükséges mezőket, és állítsd be, ki küldhet be.",
share: "Megosztás", shareBody: "Tedd közzé a linket, vagy posztold az űrlapot Discordra a bottal.",
review: "Elbírálás", reviewBody: "Fogadd el, utasítsd el, vagy kérj többet. A jelentkezők élőben látják.",
},
cta: {
title: "Kezdj el olyan jelentkezéseket gyűjteni, amelyeket valóban követni lehet.",
openDashboard: "Vezérlőpult megnyitása", loginDiscord: "Bejelentkezés Discorddal",
inviteBot: "Discord bot meghívása",
},
form: {
notAccepting: "Ez az űrlap jelenleg nem fogad válaszokat.",
needLogin: "Az űrlap kitöltéséhez be kell jelentkezned.",
loginDiscord: "Bejelentkezés Discorddal",
accessRestricted: "Ez az űrlap olyan hozzáférési korlátozást használ, amely még nem támogatott.",
submit: "Beküldés", submitting: "Beküldés…", required: "Ez a mező kötelező.",
submitFailed: "A beküldés sikertelen.",
captchaRequired: "Kérjük, töltsd ki a captchát.",
fileUploading: "Feltöltés…", fileRemove: "Eltávolítás", uploadFailed: "A feltöltés sikertelen.",
signatureClear: "Törlés",
next: "Tovább", back: "Vissza", step: "Lépés",
},
status: {
yourSubmission: "A beküldésed", activity: "Tevékenység", yourAnswers: "A válaszaid",
submitted: "Beküldve", notAnswered: "Nincs megválaszolva", statusChangedTo: "Az állapot megváltozott erre:", update: "Frissítés",
yes: "Igen", no: "Nem",
yourData: "Az adataid",
withdraw: "Beküldés visszavonása",
withdrawConfirm: "Visszavonod ezt a beküldést? Lehet, hogy nem tudsz azonnal újra jelentkezni.",
exportData: "Adataim letöltése (JSON)",
deleteData: "Beküldésem törlése",
deleteConfirm: "Véglegesen törlöd ezt a beküldést és a feltöltött fájljait? Ez nem vonható vissza.",
deleted: "A beküldésed törölve lett.",
actionFailed: "A művelet sikertelen. Kérjük, próbáld újra.",
cancel: "Mégse",
},
preview: {
submission: "A beküldésed", title: "Whitelist jelentkezés", inReview: "Elbírálás alatt",
submitted: "Beküldve", pickedUp: "Egy bíráló átvette", decision: "Döntés",
pending: "függőben", reviewerNote: "Bírálói megjegyzés",
note: "Jól néz ki. Megerősítjük a játékbeli neved, és bent vagy.",
},
dashboard: {
guilds: "Szerverek", mySubmissions: "Beküldéseim", formsTab: "Űrlapok", submissionsTab: "Beküldések", boardTab: "Tábla", brandingTab: "Arculat", botTab: "Bot", statusesTab: "Állapotok",
board: {
title: "Tábla",
moveTo: "Áthelyezés ide",
columnEmpty: "Itt nincs semmi.",
saveFailed: "Az állapot nem frissíthető.",
noPerm: "Nincs jogosultságod a beküldések elbírálásához.",
},
bulk: { selected: "kiválasztva", apply: "Alkalmaz", applying: "Alkalmazás…", failed: "A tömeges frissítés sikertelen." },
statuses: {
title: "Egyéni állapotok",
intro: "Adj hozzá saját bírálati állapotokat a beépített folyamat mellé. A bírálók bármelyikre áthelyezhetik a beküldéseket.",
defaultsTitle: "Beépített állapotok",
key: "Kulcs", label: "Címke", color: "Szín", terminal: "Végállapot", visible: "Látható a jelentkezőnek",
add: "Állapot hozzáadása", remove: "Eltávolítás",
save: "Állapotok mentése", saving: "Mentés…", saved: "Mentve!",
empty: "Még nincsenek egyéni állapotok.",
errSave: "Az állapotok mentése sikertelen.",
noPerm: "Nincs jogosultságod az állapotok kezeléséhez.",
},
yourGuilds: "A szervereid",
noGuilds: "Még nem kezelsz egyetlen szervert sem.",
noGuildsHint:
"Egy szerver összekapcsolása a Discord bot meghívásán keresztül történik. Ez a folyamat egy későbbi szakaszban érkezik. Egyelőre egy adminisztrátor hozzáadhat egy szerverhez.",
countForm: "űrlap", countForms: "űrlap", countSubmissions: "beküldés",
newForm: "Új űrlap", noForms: "Még nincsenek űrlapok. Hozd létre az elsőt.", edit: "Szerkesztés", exportCsv: "CSV exportálás",
deleteForm: "Törlés", deleteFormTitle: "Törlöd az űrlapot?", deleteFormConfirm: "Törlöd ezt az űrlapot? Az összes beküldése, fájlja és tevékenysége véglegesen törlődik. Ez nem vonható vissza.", deleteFormFailed: "Az űrlap törlése sikertelen.", cancel: "Mégse",
colApplicant: "Jelentkező", colForm: "Űrlap", colDate: "Dátum", colStatus: "Állapot",
anonymous: "Névtelen", noSubmissions: "Még nincsenek beküldések.", open: "Megnyitás",
mySubmissionsTitle: "Beküldéseim", noMySubmissions: "Még nem küldtél be egyetlen űrlapot sem.",
newFormTitle: "Új űrlap", editFormTitle: "Űrlap szerkesztése",
noPermCreate: "Nincs jogosultságod űrlapok létrehozásához.",
noPermEdit: "Nincs jogosultságod űrlapok szerkesztéséhez.",
},
review: {
back: "Vissza a beküldésekhez",
applicant: "Jelentkező", anonymous: "Névtelen", submitted: "Beküldve",
answers: "Válaszok", timeline: "Tevékenység", noEvents: "Még nincs tevékenység.",
actions: "Bírálati műveletek",
changeStatus: "Állapot módosítása", apply: "Alkalmaz",
noteLabel: "Belső megjegyzés", noteHint: "Csak a csapatod látja.",
notePlaceholder: "Adj hozzá megjegyzést a csapatnak…", saveNote: "Megjegyzés mentése",
messageLabel: "Üzenet a jelentkezőnek", messageHint: "Megjelenik a jelentkező állapotoldalán.",
messagePlaceholder: "Írj üzenetet a jelentkezőnek…", sendMessage: "Üzenet küldése",
internal: "Belső", public: "Nyilvános", system: "Rendszer",
statusChanged: "állapotot módosított", noteAdded: "belső megjegyzést adott hozzá", messageSent: "üzenetet küldött",
to: "erre:", saving: "Mentés…", actionFailed: "A művelet sikertelen.",
noPermReview: "Nincs jogosultságod a beküldések elbírálásához.",
},
branding: {
title: "Arculat",
accentColor: "Kiemelő szín",
accentHint: "A nyilvános űrlap- és állapotoldalakon jelenik meg.",
save: "Mentés", saving: "Mentés…", saved: "Mentve.", reset: "Visszaállítás",
errSave: "Az arculat mentése sikertelen.",
noPerm: "Nincs jogosultságod az arculat szerkesztéséhez.",
logo: "Logó",
logoHint: "PNG, JPEG vagy WebP, legfeljebb 1 MB. A nyilvános űrlap- és állapotoldalakon jelenik meg.",
logoUploading: "Feltöltés…", logoRemove: "Logó eltávolítása", logoFailed: "A logó frissítése sikertelen.",
},
botConfig: {
title: "Bot beállítások",
reviewChannel: "Bírálati csatorna azonosítója",
reviewChannelHint: "Az új beküldések ide kerülnek, hogy a csapatod elbírálhassa.",
acceptedRole: "Elfogadási szerep azonosítója",
acceptedRoleHint: "Alapértelmezett szerep elfogadáskor. Minden űrlap felülírhatja a saját beállításaiban.",
idHint: "Kapcsold be a Fejlesztői módot a Discordban (Beállítások → Speciális), majd jobb klikk egy csatornára/szerepre → Azonosító másolása.",
postName: "Megjelenítendő név posztoláskor",
postNameHint: "Ha be van állítva, a bot ezzel a névvel és a logóddal posztolja az űrlapokat és bírálati beágyazásokat (webhookon keresztül). Szükséges a Webhookok kezelése jogosultság. Hagyd üresen, hogy botként posztoljon.",
save: "Mentés", saving: "Mentés…", saved: "Mentve.",
errSave: "A bot beállítások mentése sikertelen.",
noPerm: "Nincs jogosultságod a bot beállítások szerkesztéséhez.",
},
builder: {
title: "Cím", description: "Leírás", slug: "Slug", slugHint: "Nyilvános URL: /f/<slug>", auto: "Auto",
status: "Állapot", visibility: "Láthatóság",
statusDraft: "Vázlat", statusLive: "Élő", statusClosed: "Lezárt", statusArchived: "Archivált",
visPublic: "Nyilvános", visAuth: "Bejelentkezés szükséges",
acceptedRole: "Elfogadási szerep azonosítója", acceptedRoleHint: "Elfogadáskor ehhez az űrlaphoz adva (felülírja a szerver alapértelmezését a Bot beállításokban). Hagyd üresen az alapértelmezéshez.",
addField: "Mező hozzáadása", add: "Hozzáadás",
page: "Oldal", addPage: "Oldal hozzáadása", removePage: "Oldal eltávolítása", pageTitlePh: "Oldal címe (opcionális)…",
saving: "Mentés…", saveChanges: "Módosítások mentése", createForm: "Űrlap létrehozása", cancel: "Mégse",
errTitle: "A cím kötelező.", errSlug: "A slug kötelező.", errFields: "Adj hozzá legalább egy mezőt.",
errSave: "Az űrlap mentése sikertelen.",
fieldLabel: "Címke", fieldText: "Szöveg", helpText: "Súgószöveg", helpHint: "Opcionális, a címke alatt jelenik meg.",
options: "Opciók", optionPh: "Opció", required: "Kötelező", addOption: "Opció hozzáadása",
moveUp: "Mozgatás felfelé", moveDown: "Mozgatás lefelé", remove: "Eltávolítás", removeOption: "Opció eltávolítása",
labelPh: "Kérdés címkéje…", headingPh: "Szakasz címe…",
stars: "Csillagok", min: "Min", max: "Max", step: "Lépés",
columns: "Oszlopok", rows: "Sorok", rowPh: "Sor", addRow: "Sor hozzáadása", removeRow: "Sor eltávolítása",
cond: {
title: "Logika",
addRule: "Szabály hozzáadása",
removeRule: "Szabály eltávolítása",
noFields: "Előbb adj hozzá más mezőket a logikához.",
valuePh: "Érték",
whenField: "mező",
actShow: "Megjelenítés, ha", actHide: "Elrejtés, ha", actRequire: "Kötelező, ha",
opEquals: "egyenlő", opNotEquals: "nem egyenlő", opContains: "tartalmazza",
opGreater: "nagyobb mint", opLess: "kisebb mint",
opEmpty: "üres", opNotEmpty: "nem üres", opInList: "listában (vesszővel elválasztva)",
},
ft: {
short_text: "Rövid szöveg", long_text: "Hosszú szöveg", email: "E-mail", number: "Szám", phone: "Telefon", url: "URL",
single_choice: "Egy választás", dropdown: "Legördülő", multi_choice: "Több választás", yes_no: "Igen / Nem",
rating_stars: "Csillagos értékelés", nps: "NPS (0–10)", slider: "Csúszka", emoji_scale: "Emoji skála", matrix: "Mátrix",
date: "Dátum", file_upload: "Fájlfeltöltés", image_upload: "Képfeltöltés", signature: "Aláírás",
consent: "Hozzájárulás", heading: "Címsor", paragraph: "Bekezdés", divider: "Elválasztó",
},
},
share: {
share: "Megosztás",
link: "Nyilvános link",
copy: "Másolás", copied: "Másolva!",
qrCode: "QR-kód",
embedCode: "Beágyazási kód",
},
authError: "A bejelentkezés sikertelen. Kérjük, próbáld újra.",
};

export const dictionaries: Record<Locale, Dictionary> = { en, de, hu };
4 changes: 2 additions & 2 deletions apps/web/src/i18n/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,14 @@ import { dictionaries, type Dictionary, type Locale } from "./dictionaries";

export type { Dictionary, Locale } from "./dictionaries";

export const locales: Locale[] = ["en", "de"];
export const locales: Locale[] = ["en", "de", "hu"];
export const defaultLocale: Locale = "en";
export const LOCALE_COOKIE = "NEXT_LOCALE";

/** Current locale from the NEXT_LOCALE cookie (default en). */
export async function getLocale(): Promise<Locale> {
const value = (await cookies()).get(LOCALE_COOKIE)?.value;
return value === "de" || value === "en" ? value : defaultLocale;
return locales.includes(value as Locale) ? (value as Locale) : defaultLocale;
}

/** Dictionary for the current locale. */
Expand Down