Files
MSCO-Dedicated-Server/Panel/i18n.js
T
MrMahoandClaude Opus 5.5 835d3ce998 Panel: unticking 'web panel enabled' + restart panel really turns it off (2.9.5)
The restart used to refuse when the panel was disabled, so it stayed
reachable. Now it stops the panel (also the relay on the game port);
'panel on|off' in the console turns it on/off and saves server.json.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-02 21:07:18 +02:00

522 lines
32 KiB
JavaScript

"use strict";
// Sprache des Panels (Englisch / Deutsch). Die Oberfläche wird auf Englisch gebaut; diese Schicht übersetzt Texte,
// Platzhalter und Tooltips, sobald sie auf der Seite erscheinen. Spielernamen, SteamIDs, der Servername und das
// Konsolen-Log werden nie übersetzt.
(function () {
const KEY = "msco-panel-lang";
let lang = "en";
try {
lang = localStorage.getItem(KEY) || ((navigator.language || "").toLowerCase().startsWith("de") ? "de" : "en");
} catch { /* egal */ }
if (lang !== "de") lang = "en";
document.documentElement.lang = lang;
window.MSCO_LANG = lang;
const DE = {
"The web panel is turned off - turn it on again with 'panel on' in the server console or PanelEnabled in server.json":
"Das Web-Panel ist ausgeschaltet - wieder an mit 'panel on' in der Server-Konsole oder PanelEnabled in server.json",
// Neues Spiel
"New game": "Neues Spiel",
"Start a completely fresh My Summer Car game instead of an uploaded save. The current save game is backed up first. The first player to join creates the new world.":
"Ein komplett neues My-Summer-Car-Spiel statt eines hochgeladenen Spielstands. Der aktuelle Spielstand wird vorher gesichert. Der erste Spieler, der beitritt, legt die neue Welt an.",
"Start new game": "Neues Spiel starten",
"Start a new game?": "Neues Spiel starten?",
"The current save game and all changes in the world are replaced by a fresh new game (the current state is kept as a backup). “Reset world” then also goes back to a new game. Everyone reconnects.":
"Der aktuelle Spielstand und alle Änderungen in der Welt werden durch ein frisches neues Spiel ersetzt (der jetzige Stand bleibt als Backup). „Welt zurücksetzen“ geht danach ebenfalls auf ein neues Spiel zurück. Alle verbinden sich neu.",
"New game started - the first player to join creates the new world": "Neues Spiel gestartet - der erste Spieler, der beitritt, legt die neue Welt an",
"New game set up - start the server; the first player to join creates the new world": "Neues Spiel eingerichtet - starte den Server; der erste Spieler, der beitritt, legt die neue Welt an",
"World reset to a new game": "Welt auf ein neues Spiel zurückgesetzt",
// Tags
"Tags": "Tags",
"e.g. german, roleplay, vanilla": "z.B. deutsch, roleplay, vanilla",
"Shown in the server list, comma separated (max. 6). The tag official is only given by the MSCO admins.":
"Werden in der Serverliste angezeigt, mit Komma getrennt (max. 6). Den Tag official vergeben nur die MSCO-Admins.",
// Updates
"Update": "Update",
"Update available": "Update verfügbar",
"new": "neu",
"Server update": "Server-Update",
"⟳ Check for updates": "⟳ Nach Updates suchen",
"What's new": "Neuerungen",
"Installed": "Installiert",
"Newest": "Neueste",
"Last check": "Letzte Prüfung",
"not checked yet": "noch nicht geprüft",
"automatically every 6 hours": "automatisch alle 6 Stunden",
"Check failed": "Prüfung fehlgeschlagen",
"The last update failed": "Das letzte Update ist fehlgeschlagen",
"Show log": "Log anzeigen",
"⇪ Install update": "⇪ Update installieren",
"Update from the panel not possible": "Update über das Panel nicht möglich",
"The server is up to date": "Der Server ist aktuell",
"Source: ": "Quelle: ",
"The server downloads and builds the new version (takes a minute or two), then restarts. Players are warned and reconnect automatically. The panel shows the progress and reloads itself.":
"Der Server lädt die neue Version herunter, baut sie (dauert ein, zwei Minuten) und startet dann neu. Spieler werden vorgewarnt und verbinden sich automatisch neu. Das Panel zeigt den Fortschritt und lädt sich danach selbst neu.",
"Update now": "Jetzt updaten",
"Update started": "Update gestartet",
"Updating the server": "Server wird aktualisiert",
"Download": "Download",
"Build": "Bauen",
"Install": "Installieren",
"Show build log": "Build-Log anzeigen",
"Hide build log": "Build-Log ausblenden",
"Update failed": "Update fehlgeschlagen",
"The update failed - the server keeps running the old version": "Das Update ist fehlgeschlagen - der Server läuft mit der alten Version weiter",
"Close": "Schließen",
"Waiting for the server to come back …": "Warte, bis der Server wieder da ist …",
"The server has not come back yet. Docker/systemd restart it automatically - otherwise start it again.":
"Der Server ist noch nicht wieder da. Docker/systemd starten ihn automatisch neu - sonst bitte von Hand starten.",
"Checking the newest version": "Prüfe die neueste Version",
"Download complete": "Download fertig",
"Building (dotnet publish) - this takes a minute": "Wird gebaut (dotnet publish) - das dauert etwa eine Minute",
"Building - packages restored": "Wird gebaut - Pakete geladen",
"Building - compiled": "Wird gebaut - kompiliert",
"Building - published": "Wird gebaut - veröffentlicht",
"Build complete": "Build fertig",
"Installing": "Wird installiert",
"An update is already running": "Es läuft schon ein Update",
"No update available - check again first": "Kein Update verfügbar - bitte zuerst erneut prüfen",
"No update available anymore": "Kein Update mehr verfügbar",
// Anmeldung
"Sign in": "Anmelden",
"Set up the panel": "Panel einrichten",
"Create account": "Konto anlegen",
"Setup code": "Einrichtungs-Code",
"Username": "Benutzername",
"Password": "Passwort",
"Repeat password": "Passwort wiederholen",
"Server Panel": "Server-Panel",
"Create the owner account. The setup code is shown in the server console (docker logs msco-server).":
"Lege das Owner-Konto an. Den Einrichtungs-Code findest du in der Server-Konsole (docker logs msco-server).",
"The passwords do not match": "Die Passwörter stimmen nicht überein",
"Log out": "Abmelden",
"Menu": "Menü",
"My Account": "Mein Konto",
"My account": "Mein Konto",
"Server status": "Serverstatus",
// Navigation
"Server": "Server",
"Moderation": "Moderation",
"Management": "Verwaltung",
"Dashboard": "Übersicht",
"Players": "Spieler",
"Console": "Konsole",
"Admins": "Admins",
"Bans": "Banns",
"World & Backups": "Welt & Backups",
"Settings": "Einstellungen",
"Panel Users": "Panel-Benutzer",
"Panel users": "Panel-Benutzer",
// Dashboard
"Running - players can join": "Läuft - Spieler können beitreten",
"Starting …": "Startet …",
"Stopped - players cannot join. The panel keeps running.": "Gestoppt - niemand kann beitreten. Das Panel läuft weiter.",
"Not running": "Läuft nicht",
"▶ Start": "▶ Starten",
"■ Stop": "■ Stoppen",
"⟳ Restart": "⟳ Neu starten",
"Stop the server?": "Server stoppen?",
"All players are disconnected and nobody can join until you start it again. The panel keeps running.":
"Alle Spieler werden getrennt und niemand kann beitreten, bis du ihn wieder startest. Das Panel läuft weiter.",
"Stop": "Stoppen",
"Restart the server?": "Server neu starten?",
"Settings (server.json), license and save game are loaded again. Players reconnect automatically.":
"Einstellungen (server.json), Lizenz und Spielstand werden neu geladen. Spieler verbinden sich automatisch neu.",
"Restart": "Neu starten",
"The server could not start": "Der Server konnte nicht starten",
"Note": "Hinweis",
"Enter license key": "Lizenzschlüssel eintragen",
"Upload save game": "Spielstand hochladen",
"Open console": "Konsole öffnen",
"Recent activity": "Letzte Aktivität",
"Uptime": "Laufzeit",
"World": "Welt",
"Save game": "Spielstand",
"Backups": "Backups",
"Admins / Bans": "Admins / Banns",
"listed in the server browser": "in der Serverliste sichtbar",
"not listed (private)": "nicht gelistet (privat)",
"on join": "beim Beitreten",
"no reset point yet": "noch kein Reset-Punkt",
"save game backups": "Spielstand-Backups",
"Steam verification on": "Steam-Prüfung an",
"Steam verification OFF (no Web API key)": "Steam-Prüfung AUS (kein Web-API-Key)",
// Spieler
"ID": "ID",
"Name": "Name",
"SteamID": "SteamID",
"Address": "Adresse",
"Online": "Online",
"Nobody is online right now.": "Gerade ist niemand online.",
"Server message": "Nachricht an alle",
"Message to all players…": "Nachricht an alle Spieler …",
"Send": "Senden",
"Kick": "Kicken",
"Ban": "Bannen",
"Make admin": "Zum Admin machen",
"Remove admin": "Admin entfernen",
"ADMIN": "ADMIN",
"unverified": "nicht bestätigt",
"SteamID not verified by Steam": "SteamID nicht von Steam bestätigt",
"The player is kicked and cannot join again until you unban them.": "Der Spieler fliegt raus und kann erst wieder beitreten, wenn du ihn entbannst.",
"The player sees the reason and can join again.": "Der Spieler sieht den Grund und kann wieder beitreten.",
"Reason (shown to the player)": "Grund (sieht der Spieler)",
"optional": "optional",
"In-game admins can kick, ban, spawn items and reset the world.": "Ingame-Admins können kicken, bannen, Items spawnen und die Welt zurücksetzen.",
"Remove": "Entfernen",
"Cancel": "Abbrechen",
"OK": "OK",
// Konsole
"Live console": "Live-Konsole",
"chat, joins, admin actions and command output": "Chat, Beitritte, Admin-Aktionen und Befehlsausgaben",
"Command… (help for a list)": "Befehl … (help für eine Liste)",
"Only admins can enter commands": "Nur Admins können Befehle eingeben",
"Run": "Ausführen",
// Admins
"Add an admin": "Admin hinzufügen",
"also works when the player is offline": "geht auch, wenn der Spieler offline ist",
"SteamID64 (17 digits)": "SteamID64 (17 Ziffern)",
"Add admin": "Admin hinzufügen",
"Find a SteamID64 on the player's Steam profile or with ": "Die SteamID64 findest du im Steam-Profil des Spielers oder mit ",
". Online players can also be made admin on the Players page.": ". Spieler, die online sind, kannst du auch auf der Spieler-Seite zum Admin machen.",
"In-game admins": "Ingame-Admins",
"can use /admin in the game: kick, ban, teleport, items, world": "dürfen im Spiel /admin benutzen: kicken, bannen, teleportieren, Items, Welt",
"Player": "Spieler",
"offline": "offline",
"online": "online",
"No admins yet.": "Noch keine Admins.",
"Admin rights are disabled": "Admin-Rechte sind ausgeschaltet",
"Without a Steam Web API key the server cannot verify Steam accounts - anyone could pretend to be an admin.":
"Ohne Steam-Web-API-Key kann der Server Steam-Konten nicht prüfen - jeder könnte sich als Admin ausgeben.",
"Get a Steam key ↗": "Steam-Key holen ↗",
"Enter it in Settings": "In den Einstellungen eintragen",
"Enter a SteamID64 (17 digits)": "Gib eine SteamID64 ein (17 Ziffern)",
// Banns
"Ban a SteamID": "SteamID bannen",
"SteamID64 (17 digits) or name:playername": "SteamID64 (17 Ziffern) oder name:spielername",
"Banned players": "Gebannte Spieler",
"Identity": "Identität",
"Nobody is banned.": "Niemand ist gebannt.",
"Unban": "Entbannen",
// Welt & Backups
"Reset world": "Welt zurücksetzen",
"Everything goes back to the reset point (the save game as it was uploaded to the server). The current state is backed up first. Everyone reconnects.":
"Alles geht zurück auf den Reset-Punkt (den Spielstand, wie er auf den Server hochgeladen wurde). Der aktuelle Stand wird vorher gesichert. Alle verbinden sich neu.",
"Reset the whole world?": "Die ganze Welt zurücksetzen?",
"Moved objects, bought items, doors, vehicle values and player positions are reset to the reset point. The current state is kept as a backup.":
"Bewegte Objekte, gekaufte Items, Türen, Fahrzeugwerte und Spielerpositionen gehen zurück auf den Reset-Punkt. Der aktuelle Stand bleibt als Backup erhalten.",
"Backup": "Backup",
"Save a copy of the current server save game. The last 5 backups are kept.": "Sichert eine Kopie des aktuellen Server-Spielstands. Die letzten 5 Backups bleiben erhalten.",
"Backup now": "Jetzt sichern",
"Reset point": "Reset-Punkt",
"Use the current save game as the new reset point for “Reset world”.": "Den aktuellen Spielstand als neuen Reset-Punkt für „Welt zurücksetzen“ nehmen.",
"Set reset point": "Reset-Punkt setzen",
"Set a new reset point?": "Neuen Reset-Punkt setzen?",
"“Reset world” will go back to the save game as it is right now.": "„Welt zurücksetzen“ geht dann auf den Spielstand von jetzt zurück.",
"Pack the files from AppData\\LocalLow\\Amistech\\My Summer Car as ZIP, RAR or 7z. They replace the server save and become the reset point. Everyone reconnects.":
"Pack die Dateien aus AppData\\LocalLow\\Amistech\\My Summer Car als ZIP, RAR oder 7z. Sie ersetzen den Server-Spielstand und werden der Reset-Punkt. Alle verbinden sich neu.",
"Upload": "Hochladen",
"Download current": "Aktuellen herunterladen",
"Choose a ZIP, RAR or 7z file first": "Wähle zuerst eine ZIP-, RAR- oder 7z-Datei",
"The current save game is backed up, then replaced. All changes in the world are reset and everyone reconnects.":
"Der aktuelle Spielstand wird gesichert und dann ersetzt. Alle Änderungen in der Welt werden zurückgesetzt, alle verbinden sich neu.",
"Save game files": "Spielstand-Dateien",
"Copied new save files into data/save? Load them (they also become the reset point).": "Neue Spielstand-Dateien nach data/save kopiert? Hier laden (sie werden auch der Reset-Punkt).",
"Reload save": "Spielstand laden",
"Save world state": "Weltzustand speichern",
"Load the save game from data/save?": "Spielstand aus data/save laden?",
"Everyone reconnects and gets this save game.": "Alle verbinden sich neu und bekommen diesen Spielstand.",
"Load": "Laden",
"Save game backups": "Spielstand-Backups",
"newest first": "neueste zuerst",
"Created": "Erstellt",
"Folder": "Ordner",
"No backups yet.": "Noch keine Backups.",
"Restore": "Wiederherstellen",
"The server goes back to this save game (the current one is backed up first). Everyone reconnects.":
"Der Server geht auf diesen Spielstand zurück (der aktuelle wird vorher gesichert). Alle verbinden sich neu.",
// Einstellungen
"General": "Allgemein",
"applies immediately": "gilt sofort",
"Server name": "Servername",
"Description": "Beschreibung",
"Max players": "Max. Spieler",
"Public address": "Öffentliche Adresse",
"automatic": "automatisch",
"IP or domain players connect to (empty = automatic)": "IP oder Domain, zu der Spieler verbinden (leer = automatisch)",
"Listed in the server browser": "In der Serverliste anzeigen",
"Steam required": "Steam erforderlich",
"Off = players without Steam can join too": "Aus = auch Spieler ohne Steam können beitreten",
"Saving": "Speichern",
"Take the save game from a player every … minutes": "Spielstand alle … Minuten von einem Spieler holen",
"0 = only when someone joins": "0 = nur wenn jemand beitritt",
"Write the world state every … seconds": "Weltzustand alle … Sekunden speichern",
"Network & panel": "Netzwerk & Panel",
"needs a restart": "braucht einen Neustart",
"restart": "Neustart",
"Game port": "Spiel-Port",
"Panel port": "Panel-Port",
"0 = same port as the game (recommended)": "0 = derselbe Port wie das Spiel (empfohlen)",
"0 = same port as the game (recommended). Docker: another port must also be published in docker-compose.yml":
"0 = derselbe Port wie das Spiel (empfohlen). Docker: ein anderer Port muss zusätzlich in docker-compose.yml freigegeben werden",
"Panel bind address": "Panel-Bind-Adresse",
"only with an own panel port - 127.0.0.1 = only via a local reverse proxy": "nur mit eigenem Panel-Port - 127.0.0.1 = nur über einen lokalen Reverse-Proxy",
"Panel sub path": "Panel-Unterpfad",
"e.g. /panel when the proxy serves it there": "z.B. /panel, wenn der Proxy es dort ausliefert",
"Behind a reverse proxy": "Hinter einem Reverse-Proxy",
"Trust X-Forwarded-For / -Proto / -Prefix": "X-Forwarded-For / -Proto / -Prefix vertrauen",
"Web panel enabled": "Web-Panel eingeschaltet",
"Turning it off locks you out of this panel after the next program start": "Ausschalten sperrt dich nach dem nächsten Programmstart aus diesem Panel aus",
"Keys": "Schlüssel",
"only owners can change keys": "nur Owner können Schlüssel ändern",
"owner only": "nur Owner",
"License key": "Lizenzschlüssel",
"Steam Web API key": "Steam-Web-API-Key",
"Needed for admins (verifies Steam accounts). ": "Nötig für Admins (prüft Steam-Konten). ",
"Get your free key on Steam ↗": "Kostenlosen Key bei Steam holen ↗",
"not set": "nicht gesetzt",
"•••••••• (set - leave empty to keep)": "•••••••• (gesetzt - leer lassen zum Behalten)",
"Also set by an environment variable (.env) - that value wins on restart": "Auch per Umgebungsvariable (.env) gesetzt - dieser Wert gilt nach einem Neustart",
"Save settings": "Einstellungen speichern",
"Restart to apply": "Neu starten zum Übernehmen",
"Restart / start the server now?": "Server jetzt neu starten / starten?",
"Loads the saved settings. Players reconnect automatically.": "Lädt die gespeicherten Einstellungen. Spieler verbinden sich automatisch neu.",
// Benutzer
"+ Add user": "+ Benutzer hinzufügen",
"Role": "Rolle",
"Last login": "Letzte Anmeldung",
"never": "nie",
"you": "du",
"Password (min. 8 characters)": "Passwort (mind. 8 Zeichen)",
"Add panel user": "Panel-Benutzer hinzufügen",
"Create": "Anlegen",
"Save": "Speichern",
"Set password": "Passwort setzen",
"New password": "Neues Passwort",
"They are logged out everywhere.": "Er wird überall abgemeldet.",
"They can no longer log in to the panel.": "Er kann sich dann nicht mehr im Panel anmelden.",
"Delete": "Löschen",
": players, kick, server messages, read console & bans. ": ": Spieler, kicken, Nachrichten, Konsole & Banns lesen. ",
": everything on the server (ban, console commands, world reset, backups). ": ": alles am Server (bannen, Konsolenbefehle, Welt-Reset, Backups). ",
": additionally manages panel users.": ": verwaltet zusätzlich die Panel-Benutzer.",
// Konto
"Current password": "Aktuelles Passwort",
"New password (min. 8 characters)": "Neues Passwort (mind. 8 Zeichen)",
"Repeat new password": "Neues Passwort wiederholen",
"Change password": "Passwort ändern",
"The new passwords do not match": "Die neuen Passwörter stimmen nicht überein",
// Meldungen vom Server
"Please log in": "Bitte anmelden",
"Wrong username or password": "Falscher Benutzername oder falsches Passwort",
"Too many failed logins - wait a few minutes": "Zu viele Fehlversuche - warte ein paar Minuten",
"Too many attempts - wait a few minutes": "Zu viele Versuche - warte ein paar Minuten",
"Wrong setup code (see the server console / docker logs)": "Falscher Einrichtungs-Code (siehe Server-Konsole / docker logs)",
"The game server is not running - start it on the dashboard": "Der Gameserver läuft nicht - starte ihn in der Übersicht",
"The server is busy or stopping": "Der Server ist beschäftigt oder stoppt gerade",
"Starting the server": "Server wird gestartet",
"Stopping the server - the panel keeps running": "Server wird gestoppt - das Panel läuft weiter",
"Restarting - the server is back in a few seconds": "Neustart - der Server ist in ein paar Sekunden wieder da",
"The server is not running": "Der Server läuft nicht",
"Nothing changed": "Nichts geändert",
"Sent": "Gesendet",
"Password changed": "Passwort geändert",
"Done": "Erledigt",
"Backup created": "Backup erstellt",
"World state saved": "Weltzustand gespeichert",
"World reset": "Welt zurückgesetzt",
"World reset to the original save game": "Welt auf den ursprünglichen Spielstand zurückgesetzt",
"World reset to the reset point": "Welt auf den Reset-Punkt zurückgesetzt",
"The current save game is now the reset point": "Der aktuelle Spielstand ist jetzt der Reset-Punkt",
"No save game to use as reset point": "Kein Spielstand für den Reset-Punkt vorhanden",
"Player not found": "Spieler nicht gefunden",
"Your role (Moderator) is not allowed to do this": "Deine Rolle (Moderator) darf das nicht",
"Your role (Admin) is not allowed to do this": "Deine Rolle (Admin) darf das nicht",
"Only the owner can change keys": "Nur der Owner kann Schlüssel ändern",
"You cannot delete yourself": "Du kannst dich nicht selbst löschen",
"The last owner cannot be deleted": "Der letzte Owner kann nicht gelöscht werden",
"There must be at least one owner": "Es muss mindestens einen Owner geben",
"A user with this name already exists": "Diesen Benutzernamen gibt es schon",
"Password: at least 8 characters": "Passwort: mindestens 8 Zeichen",
"Username: 3-32 characters (letters, numbers, _ . -)": "Benutzername: 3-32 Zeichen (Buchstaben, Zahlen, _ . -)",
"Current password is wrong": "Das aktuelle Passwort ist falsch",
"The server name cannot be empty": "Der Servername darf nicht leer sein",
"There is no save game on the server yet": "Auf dem Server gibt es noch keinen Spielstand",
"The archive is password protected": "Das Archiv ist passwortgeschützt",
"The save game is too large": "Der Spielstand ist zu groß",
"Enter a command": "Gib einen Befehl ein",
"Choose a ZIP, RAR or 7z file": "Wähle eine ZIP-, RAR- oder 7z-Datei",
"License not confirmed": "Lizenz nicht bestätigt",
"Keep running without license confirmation for … hours": "Ohne Lizenzbestätigung weiterlaufen für … Stunden",
"⟳ Restart panel": "⟳ Panel neu starten",
"Restart the panel?": "Panel neu starten?",
"Applies the saved port and panel settings. If the game port changed, the game server restarts too. You stay logged in.":
"Übernimmt die gespeicherten Port- und Panel-Einstellungen. Hat sich der Spiel-Port geändert, startet auch der Gameserver neu. Du bleibst angemeldet.",
"Restart panel": "Panel neu starten",
"The panel restarts - reloading in a few seconds": "Das Panel startet neu - die Seite lädt in ein paar Sekunden neu",
"The panel is turned off in the settings - turn it on again or edit server.json by hand": "Das Panel ist in den Einstellungen ausgeschaltet - schalte es wieder ein oder bearbeite server.json von Hand",
};
// Zusammengesetzte Texte (Name, Zahl ... darin)
const PATTERNS = [
[/^Kick (.+)$/, "$1 kicken"],
[/^Ban (.+)$/, "$1 bannen"],
[/^Make (.+) an admin\?$/, "$1 zum Admin machen?"],
[/^Remove admin: (.+)$/, "Admin entfernen: $1"],
[/^Remove admin (.+)\?$/, "Admin $1 entfernen?"],
[/^Upload (.+)\?$/, "$1 hochladen?"],
[/^Restore (.+)\?$/, "$1 wiederherstellen?"],
[/^Role of (.+)$/, "Rolle von $1"],
[/^New password for (.+)$/, "Neues Passwort für $1"],
[/^Delete (.+)\?$/, "$1 löschen?"],
[/^(.+) ago$/, "vor $1"],
[/^just now$/, "gerade eben"],
[/^version (.+)$/, "Version $1"],
[/^every (\d+) min$/, "alle $1 Min."],
[/^reset point from (.+)$/, "Reset-Punkt vom $1"],
[/^moved objects · (\d+) part actions · (\d+) bought items$/, "bewegte Objekte · $1 Teile-Aktionen · $2 gekaufte Items"],
[/^(\d+) \/ (\d+) players online$/, "$1 / $2 Spieler online"],
[/^(\d+)\/(\d+) players · v(.+) · up (.+)$/, "$1/$2 Spieler · v$3 · seit $4"],
[/^server (\w+) · v(.+)$/, (m, s, v) => "Server " + STATE[s] + " · v" + v],
[/^Server (running|stopped|starting|error)(: .*)?$/, (m, s, rest) => "Server " + STATE[s] + (rest ? ": " + tr1(rest.slice(2)) : "")],
[/^(.+) was kicked$/, "$1 wurde gekickt"],
[/^(.+) was banned$/, "$1 wurde gebannt"],
[/^(.+) is banned$/, "$1 ist gebannt"],
[/^(.+) is no longer banned$/, "$1 ist nicht mehr gebannt"],
[/^(.+) is already banned$/, "$1 ist schon gebannt"],
[/^SteamID (\d+) is now an admin$/, "SteamID $1 ist jetzt Admin"],
[/^SteamID (\d+) is no longer an admin$/, "SteamID $1 ist kein Admin mehr"],
[/^(.+) is now an admin$/, "$1 ist jetzt Admin"],
[/^(.+) is no longer an admin$/, "$1 ist kein Admin mehr"],
[/^User (.+) created$/, "Benutzer $1 angelegt"],
[/^Backup created: (.+)$/, "Backup erstellt: $1"],
[/^Restored (.+?)( - start the server to use it)?$/, (m, n, s) => n + " wiederhergestellt" + (s ? " - starte den Server, um ihn zu benutzen" : "")],
[/^Save game uploaded \((\d+) files\) - everyone reconnects$/, "Spielstand hochgeladen ($1 Dateien) - alle verbinden sich neu"],
[/^Save game uploaded \((\d+) files\) - start the server to use it$/, "Spielstand hochgeladen ($1 Dateien) - starte den Server, um ihn zu benutzen"],
[/^Settings saved(.*)$/, (m, rest) => "Einstellungen gespeichert" + rest
.replace(" - some changes need a restart", " - manche Änderungen brauchen einen Neustart")
.replace(/ - the tag (.+) is only given by the MSCO admins$/, " - den Tag $1 vergeben nur die MSCO-Admins")
.replace(" - the new port only applies after the whole program restarts (docker compose restart); in Docker publish it in docker-compose.yml first",
" - der neue Port gilt erst nach einem Neustart des ganzen Programms (docker compose restart); in Docker vorher in docker-compose.yml freigeben")],
[/^The server is already (\w+)$/, (m, s) => "Der Server " + (s === "running" ? "läuft schon" : "startet schon")],
[/^No save game yet - upload one as ZIP in the panel \(World & Backups\), start a new game there or copy it to data\/save$/,
"Noch kein Spielstand - lade einen als ZIP/RAR im Panel hoch (Welt & Backups), starte dort ein neues Spiel oder kopiere ihn nach data/save"],
[/^No license key set - (.+)$/, "Kein Lizenzschlüssel gesetzt - hol dir einen unter msco.mbm.wtf/keys und trag ihn in den Einstellungen ein"],
[/^License key invalid: (.+)$/, "Lizenzschlüssel ungültig: $1"],
[/^Update available: (.+)$/, "Update verfügbar: $1"],
[/^(.*) - the tag (.+) is only given by the MSCO admins$/, (m, before, tag) => (DE[before] || before) + " - den Tag " + tag + " vergeben nur die MSCO-Admins"],
[/^Version (.+) is available$/, "Version $1 ist verfügbar"],
[/^Version ([0-9.]+)$/, "Version $1"],
[/^Install update (.+)\?$/, "Update $1 installieren?"],
[/^Players then need MSCO mod (.+) \(currently (.+)\)$/, "Spieler brauchen danach die MSCO-Mod $1 (aktuell $2)"],
[/^for MSCO mod (.+)$/, "für MSCO-Mod $1"],
[/^Downloading MSCO server (.+)$/, "Lade MSCO-Server $1 herunter"],
[/^Downloading … (.+)$/, "Lade herunter … $1"],
[/^Restarting with version (.+)$/, "Neustart mit Version $1"],
[/^Server updated to (.+) - reloading the panel …$/, "Server auf $1 aktualisiert - Panel wird neu geladen …"],
[/^The server restarted but still runs version (.+)\. The update could not be started - see the console\.$/,
"Der Server wurde neu gestartet, läuft aber noch mit Version $1. Das Update konnte nicht gestartet werden - siehe Konsole."],
[/^Could not check for updates: (.+)$/, "Konnte nicht nach Updates suchen: $1"],
[/^No \.NET (\d+) SDK found - (.+)$/, "Kein .NET-$1-SDK gefunden - es wird zum Bauen des Updates gebraucht. Mit Docker: einmal die neue Version holen (git pull && docker compose up -d --build), deren Image enthält das SDK."],
[/^The dotnet command was not found (.+)$/, "Der Befehl dotnet wurde nicht gefunden $1 - installiere das .NET SDK, um über das Panel zu updaten."],
[/^Master server not reachable (.+)$/, "Master-Server nicht erreichbar $1"],
[/^Crashed: (.+)$/, "Abgestürzt: $1"],
[/^The master server (rejects the license key|is not reachable) \(last confirmed (.+) ago\) - the server keeps running until the next restart$/,
(m, why, ago) => (why.startsWith("rejects") ? "Der Master-Server lehnt den Lizenzschlüssel ab" : "Der Master-Server ist nicht erreichbar") +
" (zuletzt bestätigt vor " + ago + ") - der Server läuft bis zum nächsten Neustart weiter"],
[/^This file could not be read - upload a ZIP, RAR or 7z archive (.+)$/, "Die Datei konnte nicht gelesen werden - lade ein ZIP-, RAR- oder 7z-Archiv hoch $1"],
[/^No defaultES2File\.txt in the archive(.*)$/, "Keine defaultES2File.txt im Archiv - pack die Dateien aus %USERPROFILE%\\AppData\\LocalLow\\Amistech\\My Summer Car"],
];
const STATE = { running: "läuft", stopped: "gestoppt", starting: "startet", error: "Fehler" };
function tr1(text) {
if (Object.prototype.hasOwnProperty.call(DE, text)) return DE[text];
for (const [re, rep] of PATTERNS) if (re.test(text)) return text.replace(re, rep);
return null;
}
function translateText(value) {
if (lang === "en" || !value || !value.trim()) return null;
const lead = value.match(/^\s*/)[0], trail = value.match(/\s*$/)[0];
const core = value.slice(lead.length, value.length - trail.length);
let out = tr1(core);
if (out === null && Object.prototype.hasOwnProperty.call(DE, value)) out = DE[value]; // Texte mit Leerzeichen am Rand
if (out === null) return null;
return (DE[value] !== undefined ? "" : lead) + out + (DE[value] !== undefined ? "" : trail);
}
// Nutzerdaten nie übersetzen
const RAW = ".player-name, .mono, code, .console, #serverName, #scName, #meName, #authServer, .brand-title";
function isRaw(el) {
if (!el) return true;
if (el.closest(".console")) return true;
if (el.matches(RAW)) return true;
return false;
}
function translateNode(node) {
if (node.nodeType === 3) {
if (isRaw(node.parentElement)) return;
const out = translateText(node.nodeValue);
if (out !== null && out !== node.nodeValue) node.nodeValue = out;
return;
}
if (node.nodeType !== 1) return;
for (const attr of ["placeholder", "title", "aria-label"]) {
const v = node.getAttribute && node.getAttribute(attr);
if (!v) continue;
const out = translateText(v);
if (out !== null && out !== v) node.setAttribute(attr, out);
}
if (node.closest && node.closest(".console")) return;
const walker = document.createTreeWalker(node, NodeFilter.SHOW_TEXT | NodeFilter.SHOW_ELEMENT);
for (let n = walker.nextNode(); n; n = walker.nextNode()) {
if (n.nodeType === 3) translateNode(n);
else for (const attr of ["placeholder", "title", "aria-label"]) {
const v = n.getAttribute(attr);
if (!v) continue;
const out = translateText(v);
if (out !== null && out !== v) n.setAttribute(attr, out);
}
}
}
function renderSwitches() {
document.querySelectorAll("[data-lang-switch]").forEach((box) => {
box.replaceChildren();
for (const code of ["en", "de"]) {
const b = document.createElement("button");
b.type = "button";
b.textContent = code.toUpperCase();
b.className = code === lang ? "on" : "";
b.title = code === "de" ? "Deutsch" : "English";
b.addEventListener("click", () => {
if (code === lang) return;
try { localStorage.setItem(KEY, code); } catch { /* egal */ }
location.reload();
});
box.append(b);
}
});
}
function start() {
renderSwitches();
if (lang === "en") return;
translateNode(document.body);
new MutationObserver((mutations) => {
for (const m of mutations) {
if (m.type === "characterData") translateNode(m.target);
else if (m.type === "attributes") translateNode(m.target);
else m.addedNodes.forEach(translateNode);
}
}).observe(document.body, { subtree: true, childList: true, characterData: true, attributes: true, attributeFilter: ["placeholder", "title"] });
}
if (document.readyState === "loading") document.addEventListener("DOMContentLoaded", start);
else start();
})();