The configurable LicenseGraceHours setting is gone. If the master is down or rejects the key, a running server now only warns and keeps running until the next restart; a (re)start still works up to 72 h after the last confirmation. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
437 lines
25 KiB
JavaScript
437 lines
25 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 = {
|
|
// 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 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\) or copy it to data\/save$/,
|
|
"Noch kein Spielstand - lade einen als ZIP/RAR im Panel hoch (Welt & Backups) 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"],
|
|
[/^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();
|
|
})();
|