Implemented `translateEntryLabel` helper function with mapping dictionary for translating German game entry labels (spells, potions, locations) to English equivalents. Added language parameter extraction in SheetSection component and applied translation to entry labels based on current language setting. Maintains German as source labels with English translations provided via lookup table.
247 lines
8.1 KiB
React
247 lines
8.1 KiB
React
import React, { createContext, useContext, useEffect, useMemo, useState } from "react";
|
||
|
||
const STORAGE_KEY = "hpLanguage";
|
||
const LanguageContext = createContext(null);
|
||
|
||
const entryLabels = {
|
||
"Schlaftrunk": "Sleeping Potion",
|
||
"Verschwindekabinett": "Vanishing Cabinet",
|
||
"Portschlüssel": "Portkey",
|
||
"Impedimenta": "Impedimenta",
|
||
"Petrificus Totalus": "Petrificus Totalus",
|
||
"Alraune": "Mandrake",
|
||
"Große Halle": "Great Hall",
|
||
"Krankenflügel": "Hospital Wing",
|
||
"Raum der Wünsche": "Room of Requirement",
|
||
"Klassenzimmer für Zaubertränke": "Potions Classroom",
|
||
"Pokalszimmer": "Trophy Room",
|
||
"Klassenzimmer für Wahrsagen": "Divination Classroom",
|
||
"Eulerei": "Owlery",
|
||
"Bibliothek": "Library",
|
||
"Verteidigung gegen die dunklen Künste": "Defence Against the Dark Arts",
|
||
};
|
||
|
||
export function translateEntryLabel(label, language) {
|
||
return language === "en" ? (entryLabels[label] || label) : label;
|
||
}
|
||
|
||
export const translations = {
|
||
de: {
|
||
language: "Deutsch",
|
||
changeLanguage: "Sprache ändern",
|
||
switchTo: "English",
|
||
statistics: "Statistik",
|
||
adminDashboard: "Admin Dashboard",
|
||
adminSettings: "Admin Settings",
|
||
setPassword: "Passwort setzen",
|
||
changeDesign: "Design ändern",
|
||
logout: "Logout",
|
||
newGame: "New Game",
|
||
user: "User",
|
||
admin: "Admin",
|
||
help: "Hilfe",
|
||
game: "Spiel",
|
||
players: "Spieler",
|
||
suspects: "Verdächtige Personen",
|
||
items: "Gegenstände",
|
||
locations: "Orte",
|
||
winner: "Sieger",
|
||
started: "Spiel läuft",
|
||
finished: "Spiel beendet",
|
||
lobby: "Lobby",
|
||
startGame: "Spiel starten",
|
||
waitingForHost: "Warte, bis der Host das Spiel startet.",
|
||
chipsCreated: "Spieler-Chips erstellt",
|
||
atLeastTwoPlayers: "Mindestens 2 Spieler werden benötigt.",
|
||
chipsOnStart: "Beim Start werden die Spieler-Chips erstellt.",
|
||
noPlayersYet: "Noch keine Spieler beigetreten.",
|
||
close: "Schließen",
|
||
cancel: "Abbrechen",
|
||
save: "Speichern",
|
||
create: "Erstellen",
|
||
edit: "Bearbeiten",
|
||
delete: "Löschen",
|
||
disable: "Deaktivieren",
|
||
active: "aktiv",
|
||
disabled: "deaktiviert",
|
||
loading: "Laden …",
|
||
email: "E-Mail",
|
||
password: "Passwort",
|
||
confirmPassword: "Passwort bestätigen",
|
||
role: "Rolle",
|
||
displayName: "Anzeigename",
|
||
name: "Name",
|
||
createUser: "User anlegen",
|
||
editUser: "User bearbeiten",
|
||
newUser: "Neuen User anlegen",
|
||
existingUsers: "Vorhandene User",
|
||
accountActive: "Konto ist aktiv",
|
||
optional: "optional",
|
||
inviteHint: "Leer lassen = Einladung senden",
|
||
inviteNotice: "Ohne Passwort wird automatisch eine einmalige Einladung per SMTP verschickt.",
|
||
adminDashboardSubtitle: "Benutzer, Rollen und Zugangsdaten verwalten",
|
||
adminSettingsSubtitle: "SMTP und Einladungen konfigurieren",
|
||
smtpServer: "SMTP-Server",
|
||
port: "Port",
|
||
smtpUsername: "SMTP-Benutzername",
|
||
senderEmail: "Absender-E-Mail",
|
||
senderName: "Absendername",
|
||
appUrl: "App-URL für Einladungslinks",
|
||
useTls: "STARTTLS verwenden (empfohlen)",
|
||
testEmail: "Test-E-Mail",
|
||
sendTest: "Test senden",
|
||
saveSettings: "Einstellungen speichern",
|
||
setupAdmin: "Admin einrichten",
|
||
login: "Anmelden",
|
||
logout: "Logout",
|
||
enterEmail: "E-Mail eingeben",
|
||
passwordMin: "Mindestens 8 Zeichen",
|
||
passwordAgain: "Passwort wiederholen",
|
||
acceptInvite: "Einladung annehmen",
|
||
invite: "Deine Einladung",
|
||
setPasswordTitle: "Passwort setzen",
|
||
design: "Design ändern",
|
||
joinGame: "Spiel beitreten",
|
||
newGameTitle: "Neues Spiel",
|
||
gameCode: "Spiel-Code",
|
||
copy: "Kopieren",
|
||
copied: "Kopiert",
|
||
createGame: "Spiel erstellen",
|
||
join: "Beitreten",
|
||
chooseAction: "Was möchtest du tun?",
|
||
helpTitle: "Hilfe & Spielablauf",
|
||
notes: "Notizen",
|
||
playerChips: "Spieler-Chips",
|
||
whoHasCard: "Wer hat die Karte?",
|
||
selectChip: "Chip auswählen",
|
||
readOnly: "Spiel beendet – Notizzettel ist schreibgeschützt",
|
||
cycleStatus: "Klick: Grün → Rot → Grau → Leer",
|
||
cycleNote: "— → i → m → s.(Chip) → —",
|
||
gameStarted: "Spiel gestartet",
|
||
investigationsBegin: "Die Ermittlungen beginnen",
|
||
bestDetective: "Möge der beste Detektiv gewinnen.",
|
||
},
|
||
en: {
|
||
language: "English",
|
||
changeLanguage: "Change language",
|
||
switchTo: "Deutsch",
|
||
statistics: "Statistics",
|
||
adminDashboard: "Admin Dashboard",
|
||
adminSettings: "Admin Settings",
|
||
setPassword: "Set password",
|
||
changeDesign: "Change design",
|
||
logout: "Logout",
|
||
newGame: "New Game",
|
||
user: "User",
|
||
admin: "Admin",
|
||
help: "Help",
|
||
game: "Game",
|
||
players: "Players",
|
||
suspects: "Suspects",
|
||
items: "Items",
|
||
locations: "Locations",
|
||
winner: "Winner",
|
||
started: "Game in progress",
|
||
finished: "Game finished",
|
||
lobby: "Lobby",
|
||
startGame: "Start game",
|
||
waitingForHost: "Wait for the host to start the game.",
|
||
chipsCreated: "player chips created",
|
||
atLeastTwoPlayers: "At least 2 players are required.",
|
||
chipsOnStart: "Player chips will be created when the game starts.",
|
||
noPlayersYet: "No players have joined yet.",
|
||
close: "Close",
|
||
cancel: "Cancel",
|
||
save: "Save",
|
||
create: "Create",
|
||
edit: "Edit",
|
||
delete: "Delete",
|
||
disable: "Disable",
|
||
active: "active",
|
||
disabled: "disabled",
|
||
loading: "Loading …",
|
||
email: "Email",
|
||
password: "Password",
|
||
confirmPassword: "Confirm password",
|
||
role: "Role",
|
||
displayName: "Display name",
|
||
name: "Name",
|
||
createUser: "Create user",
|
||
editUser: "Edit user",
|
||
newUser: "Create new user",
|
||
existingUsers: "Existing users",
|
||
accountActive: "Account is active",
|
||
optional: "optional",
|
||
inviteHint: "Leave blank = send invitation",
|
||
inviteNotice: "Without a password, a one-time invitation is sent via SMTP.",
|
||
adminDashboardSubtitle: "Manage users, roles and credentials",
|
||
adminSettingsSubtitle: "Configure SMTP and invitations",
|
||
smtpServer: "SMTP server",
|
||
port: "Port",
|
||
smtpUsername: "SMTP username",
|
||
senderEmail: "Sender email",
|
||
senderName: "Sender name",
|
||
appUrl: "App URL for invitation links",
|
||
useTls: "Use STARTTLS (recommended)",
|
||
testEmail: "Test email",
|
||
sendTest: "Send test",
|
||
saveSettings: "Save settings",
|
||
setupAdmin: "Set up admin",
|
||
login: "Log in",
|
||
enterEmail: "Enter email",
|
||
passwordMin: "At least 8 characters",
|
||
passwordAgain: "Repeat password",
|
||
acceptInvite: "Accept invitation",
|
||
invite: "Your invitation",
|
||
setPasswordTitle: "Set password",
|
||
design: "Change design",
|
||
joinGame: "Join game",
|
||
newGameTitle: "New game",
|
||
gameCode: "Game code",
|
||
copy: "Copy",
|
||
copied: "Copied",
|
||
createGame: "Create game",
|
||
join: "Join",
|
||
chooseAction: "What would you like to do?",
|
||
helpTitle: "Help & game guide",
|
||
notes: "Notes",
|
||
playerChips: "Player chips",
|
||
whoHasCard: "Who has the card?",
|
||
selectChip: "Select chip",
|
||
readOnly: "Game finished – note sheet is read-only",
|
||
cycleStatus: "Click: Green → Red → Grey → Empty",
|
||
cycleNote: "— → i → m → s.(chip) → —",
|
||
gameStarted: "Game started",
|
||
investigationsBegin: "The investigation begins",
|
||
bestDetective: "May the best detective win.",
|
||
},
|
||
};
|
||
|
||
export function LanguageProvider({ children }) {
|
||
const [language, setLanguage] = useState(() => {
|
||
try { return localStorage.getItem(STORAGE_KEY) === "en" ? "en" : "de"; } catch { return "de"; }
|
||
});
|
||
|
||
useEffect(() => {
|
||
try { localStorage.setItem(STORAGE_KEY, language); } catch {}
|
||
document.documentElement.lang = language;
|
||
}, [language]);
|
||
|
||
const value = useMemo(() => ({
|
||
language,
|
||
setLanguage,
|
||
toggleLanguage: () => setLanguage((current) => current === "de" ? "en" : "de"),
|
||
t: (key, values = {}) => {
|
||
let value = translations[language][key] || key;
|
||
Object.entries(values).forEach(([name, replacement]) => { value = value.replaceAll(`{${name}}`, replacement); });
|
||
return value;
|
||
},
|
||
}), [language]);
|
||
|
||
return <LanguageContext.Provider value={value}>{children}</LanguageContext.Provider>;
|
||
}
|
||
|
||
export function useLanguage() {
|
||
return useContext(LanguageContext) || { language: "de", toggleLanguage: () => {}, t: (key) => key };
|
||
}
|