Panel: German/English, redesigned sidebar, in-game admins page, Steam Web API key link, RAR/7z save upload (SharpCompress), responsive cards; upload errors return 400; tests
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
+419
@@ -0,0 +1,419 @@
|
||||
"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)",
|
||||
"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",
|
||||
};
|
||||
|
||||
// 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")],
|
||||
[/^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"],
|
||||
[/^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();
|
||||
})();
|
||||
Reference in New Issue
Block a user