diff --git a/update-Nitrov3.sh b/update-Nitrov3.sh index 09862c79..1db59b9d 100755 --- a/update-Nitrov3.sh +++ b/update-Nitrov3.sh @@ -61,6 +61,7 @@ WARNINGS=0 UPDATED_REPOS=() LAST_BACKUP="" ROLLBACK_NEEDED=false +BINARY_BACKUP_DIR="" NOTIFY_FAILED=false CONFIG_BACKUP_DIR="" MAVEN_OPTS="${MAVEN_OPTS:--Xmx2G}" @@ -117,6 +118,7 @@ HEALTH_INTERVAL="${NITRO_HEALTH_INTERVAL:-5}" NITRO_SSL_VERIFY="${NITRO_SSL_VERIFY:-OFF}" CONFIG_BACKUP_DIR="${SCRIPT_DIR}/storage/config-backups" mkdir -p "$CONFIG_BACKUP_DIR" 2>/dev/null || true +NITRO_LANG="${NITRO_LANG:-en}" MYSQL_CRED="-h $DB_HOST -P $DB_PORT -u $DB_USER --ssl-verify-server-cert=${NITRO_SSL_VERIFY}" [ -n "$DB_PASS" ] && MYSQL_CRED="$MYSQL_CRED --password=$DB_PASS" @@ -129,13 +131,540 @@ else MYSQL_CLIENT="mariadb"; MYSQL_DUMP="mariadb-dump" fi +# ============================================================================= +# LANGUAGE / INTERNATIONALIZATION +# ============================================================================= +declare -A _T + +_t() { + local key="$1"; shift + local text="${_T[$key]:-$key}" + for arg in "$@"; do + text="${text/\%s/$arg}" + done + echo "$text" +} + +load_language() { + local lang="${NITRO_LANG:-en}" + case "${lang,,}" in + nl) _T=( +# ── MENU ────────────────────────────────────────────── +["UPDATE"]="UPDATE" +["TOOLS"]="TOOLS" +["ADVANCED"]="ADVANCED" +["Quick Update — current branch"]="Snelle Update — huidige branch" +["Full Update (choose branch)"]="Volledige Update (kies branch)" +["Emulator Only"]="Alleen Emulator" +["Nitro-V3 Client Only"]="Alleen Nitro-V3 Client" +["Renderer Only"]="Alleen Renderer" +["Configs Only"]="Alleen Configuraties" +["Dev Mode (skip builds, only configs)"]="Dev Modus (skip builds, alleen configs)" +["Switch Branch"]="Wissel Branch" +["Database"]="Database" +["Backup / Restore"]="Backup / Herstel" +["Services"]="Services" +["Status"]="Status" +["Health Check"]="Gezondheidscheck" +["Clean"]="Opschonen" +["Logs"]="Logboeken" +["Config"]="Configuratie" +["Git Log"]="Git Logboek" +["Compare Branches"]="Vergelijk Branches" +["Cron Scheduler"]="Cron Planner" +["View Git Stashes"]="Bekijk Git Stashes" +["Exit"]="Afsluiten" +["Select [0-20]"]="Selecteer [0-20]" +["Press Enter to continue..."]="Druk op Enter om door te gaan..." +["Goodbye!"]="Tot ziens!" +# ── HELP ────────────────────────────────────────────── +["SMaRT — Emulator / Nitro-V3 / Nitro-V3-Render Updater & Manager"]="SMaRT — Emulator / Nitro-V3 / Nitro-V3-Render Updater & Beheerder" +["USAGE:"]="GEBRUIK:" +["COMMANDS:"]="COMMANDO'S:" +["Open menu (default)"]="Open menu (standaard)" +["Run update"]="Voer update uit" +["Create database backup"]="Maak databasebackup" +["Restore from backup"]="Herstel vanuit backup" +["List backups"]="Toon backups" +["System dashboard"]="Systeemdashboard" +["Health check"]="Gezondheidscheck" +["Service manager"]="Servicebeheerder" +["Database tools"]="Database tools" +["Show config"]="Toon configuratie" +["View logs"]="Bekijk logboeken" +["Cache cleanup"]="Cache opschonen" +["Git history"]="Git geschiedenis" +["Branch diff"]="Branch vergelijking" +["Cron setup"]="Cron instellen" +["View git stashes"]="Bekijk git stashes" +["Branch (auto-detects)"]="Branch (auto-detectie)" +["Site URL"]="Site URL" +["emulator|client|renderer|configs|dev"]="emulator|client|renderer|configs|dev" +["Preview only (no changes)"]="Alleen voorbeeld (geen wijzigingen)" +["Show this help"]="Toon deze hulp" +["Show version"]="Toon versie" +["OPTIONS:"]="OPTIES:" +["Unknown:"]="Onbekend:" +# ── STEP HEADERS ────────────────────────────────────── +["Update & Build Emulator"]="Update & Bouw Emulator" +["Update Nitro_Render_V3"]="Update Nitro_Render_V3" +["Update & Build Nitro-V3"]="Update & Bouw Nitro-V3" +["Sync Configurations"]="Synchroniseer Configuraties" +["Cleanup"]="Opschonen" +["Set Permissions"]="Stel Permissies in" +["Restart Services"]="Herstart Services" +["System Diagnostics"]="Systeemdiagnose" +["Database Backup"]="Databasebackup" +["Database Restore"]="Database Herstel" +["Backup Inventory"]="Backup Inventaris" +["System Status"]="Systeemstatus" +["Health Check"]="Gezondheidscheck" +["Service Manager"]="Servicebeheer" +["Database Tools"]="Database Tools" +["Configuration"]="Configuratie" +["Log Viewer"]="Logboekweergave" +["Cache Cleanup"]="Cache Opschonen" +["Git Commit History"]="Git Commit Geschiedenis" +["Branch Comparison"]="Branch Vergelijking" +["Cron Scheduler"]="Cron Planner" +["Git Stashes"]="Git Stashes" +# ── PROMPTS / CONFIRM ───────────────────────────────── +["Start update?"]="Update starten?" +["Continue?"]="Doorgaan?" +["Restore %s? OVERWRITES database!"]="Herstel %s? OVERSCHRIJFT database!" +["Select [1-%s]"]="Selecteer [1-%s]" +["Branch [1-%s]"]="Branch [1-%s]" +["Name:"]="Naam:" +["Custom"]="Aangepast" +["Select:"]="Selecteer:" +["SQL:"]="SQL:" +["Minute [0-59]:"]="Minuut [0-59]:" +["Hour [0-23]:"]="Uur [0-23]:" +["Branch A:"]="Branch A:" +["Branch B:"]="Branch B:" +["(current)"]="(huidig)" +# ── INFO / OK / WARN / FAIL ────────────────────────── +["All commands available"]="Alle commando's beschikbaar" +["All directories exist"]="Alle mappen bestaan" +["Database connected"]="Database verbonden" +["Emulator: already up to date"]="Emulator: al up-to-date" +["Renderer: already up to date"]="Renderer: al up-to-date" +["Nitro-V3: already up to date"]="Nitro-V3: al up-to-date" +["Emulator JAR backed up"]="Emulator JAR geback-upt" +["Nitro-V3 dist backed up"]="Nitro-V3 dist geback-upt" +["Emulator JAR restored"]="Emulator JAR hersteld" +["Nitro-V3 dist restored"]="Nitro-V3 dist hersteld" +["Renderer dependencies installed"]="Renderer afhankelijkheden geïnstalleerd" +["No repo updates; skipping parallel builds"]="Geen repo-updates; parallel bouwen overgeslagen" +["Dev mode: skipping builds, syncing configs only"]="Dev modus: builds overgeslagen, alleen configs synchroniseren" +["Config back-up: %s"]="Config-backup: %s" +["%s config file(s) synced"]="%s configuratiebestand(en) gesynchroniseerd" +["All config files valid"]="Alle configuratiebestanden geldig" +["%s config(s) invalid"]="%s configuratie(s) ongeldig" +["All config URLs synced"]="Alle config-URL's gesynchroniseerd" +["Redis cache flushed"]="Redis cache geleegd" +["Permissions set"]="Permissies ingesteld" +["Jar: %s"]="Jar: %s" +["Launch script updated"]="Startscript bijgewerkt" +["%s restarted"]="%s herstart" +["Emulator health check passed (service up + port listening)"]="Emulator gezondheidscheck geslaagd (service actief + poort luistert)" +["Emulator not healthy after %s retries"]="Emulator niet gezond na %s pogingen" +["Nginx reloaded"]="Nginx herladen" +["Redis flushed"]="Redis geleegd" +["Cleanup done (%s logs removed)"]="Opschonen voltooid (%s logs verwijderd)" +["Old config backups pruned"]="Oude config-backups opgeruimd" +["Dry-run: would update repos, run DB backups, build, sync configs, cleanup, restart services"]="Proefrun: zou repos updaten, DB-backups maken, bouwen, configs synchroniseren, opschonen, services herstarten" +["Backup: %s — %s"]="Backup: %s — %s" +["Restored"]="Hersteld" +["Cancelled"]="Geannuleerd" +["Started"]="Gestart" +["Stopped"]="Gestopt" +["Restarted"]="Herstart" +["Yarn cleaned"]="Yarn opgeschoond" +["Next.js cache cleared"]="Next.js cache gewist" +["Logs cleaned"]="Logs opgeschoond" +["Full cleanup"]="Volledig opgeschoond" +["Docker pruned"]="Docker opgeruimd" +["Optimized"]="Geoptimaliseerd" +["Old Maven artifacts cleaned"]="Oude Maven artefacten opgeruimd" +["Scheduled daily 03:00"]="Ingesteld dagelijks 03:00" +["Scheduled daily 04:00"]="Ingesteld dagelijks 04:00" +["Scheduled weekly"]="Ingesteld wekelijks" +["Scheduled %s"]="Ingesteld %s" +["Removed"]="Verwijderd" +["Branch: %s"]="Branch: %s" +["No backup dir"]="Geen backup-map" +["No backups"]="Geen backups" +["No logs"]="Geen logboeken" +["No log dir"]="Geen logboek-map" +["No stashes found"]="Geen stashes gevonden" +["Not a git repo"]="Geen git-repository" +["Invalid"]="Ongeldig" +["Invalid selection"]="Ongeldige selectie" +["%s updates, %s warnings"]="%s updates, %s waarschuwingen" +["Update had errors"]="Update had fouten" +["Dev mode had errors"]="Dev modus had fouten" +["Invalid, using: %s"]="Ongeldig, gebruik: %s" +["Backup: %s — %s"]="Backup: %s — %s" +["Script:"]="Script:" +["Bash syntax"]="Bash syntax" +["Configs:"]="Configuraties:" +["Config dir"]="Config map" +["All JSON valid"]="Alle JSON geldig" +["JSON errors:"]="JSON fouten:" +["Gamedata config"]="Gamedata config" +["Backup dir"]="Backup map" +["Network:"]="Netwerk:" +["Nginx config"]="Nginx configuratie" +["Redis PING"]="Redis PING" +["Site reachable"]="Site bereikbaar" +["Emulator port open"]="Emulator poort open" +["Emulator port closed"]="Emulator poort gesloten" +["Databases:"]="Databases:" +["MySQL connect"]="MySQL verbinding" +["Disk:"]="Schijf:" +["Memory:"]="Geheugen:" +["Load:"]="Belasting:" +["Commands:"]="Commando's:" +["Bashisms"]="Bashisms" +["Tables:"]="Tabellen:" +# ── DIE MESSAGES ────────────────────────────────────── +["Another instance is already running (lock: %s)"]="Er draait al een andere instantie (lock: %s)" +["Required commands missing"]="Vereiste commando's ontbreken" +["Missing: %s"]="Ontbreekt: %s" +["Missing dir: %s"]="Map ontbreekt: %s" +["Only %sGB free (min %sGB)"]="Slechts %sGB vrij (min %sGB)" +["Low disk: %sGB free"]="Weinig schijfruimte: %sGB vrij" +["%sGB disk available"]="%sGB schijf beschikbaar" +["DB connection failed"]="Databaseverbinding mislukt" +["Maven build failed (see: %s)"]="Maven build mislukt (zie: %s)" +["No jar found"]="Geen jar gevonden" +["yarn install failed"]="yarn install mislukt" +["yarn build failed (see: %s)"]="yarn build mislukt (zie: %s)" +["Build failure in: %s"]="Buildfout in: %s" +["Backup failed"]="Backup mislukt" +["Restore failed"]="Herstel mislukt" +# ── SECTIONS ────────────────────────────────────────── +[" UPDATE "]=" UPDATE " +[" TOOLS "]=" TOOLS " +[" ADVANCED "]=" GEAVANCEERD " +# ── SUBMENUS ────────────────────────────────────────── +["Start Emulator"]="Start Emulator" +["Stop Emulator"]="Stop Emulator" +["Restart Emulator"]="Herstart Emulator" +["Start Nginx"]="Start Nginx" +["Restart Nginx"]="Herstart Nginx" +["Status All"]="Status Alles" +["Emulator Logs"]="Emulator Logs" +["Emulator Journal"]="Emulator Journal" +["Return"]="Terug" +["DB Info"]="DB Info" +["List Tables"]="Toon Tabellen" +["Table Sizes"]="Tabelgroottes" +["Optimize"]="Optimaliseer" +["Custom Query"]="Eigen Query" +["Active Users"]="Actieve Gebruikers" +["Processlist"]="Proceslijst" +["Yarn"]="Yarn" +["Next.js"]="Next.js" +["Redis"]="Redis" +["Everything"]="Alles" +["Docker"]="Docker" +["Maven"]="Maven" +["Daily 03:00"]="Dagelijks 03:00" +["Daily 04:00"]="Dagelijks 04:00" +["Weekly Sun 03:00"]="Wekelijks Zo 03:00" +["Custom time"]="Eigen tijd" +["Remove"]="Verwijderen" +["Last 20 commits on %s (ahead: %s):"]="Laatste 20 commits op %s (vooruit: %s):" +["%s is %s ahead, %s behind %s"]="%s is %s voor, %s achter op %s" +["Current:"]="Huidig:" +["none"]="geen" +# ── BOX LABELS ──────────────────────────────────────── +["SERVER"]="SERVER" +["RESOURCES"]="BRONNEN" +["SERVICES"]="SERVICES" +["GIT REPOS"]="GIT REPOS" +["SCORE"]="SCORE" +["DB INFO"]="DB INFO" +["CONFIGURATION"]="CONFIGURATIE" +["Host:"]="Host:" +["OS:"]="Besturingssysteem:" +["Uptime:"]="Uptime:" +["CPU:"]="CPU:" +["Memory:"]="Geheugen:" +["Disk:"]="Schijf:" +["Database:"]="Database:" +["Passed:"]="Geslaagd:" +["Failed:"]="Mislukt:" +["Warnings:"]="Waarschuwingen:" +["Name:"]="Naam:" +["Size:"]="Grootte:" +["Tables:"]="Tabellen:" +["Site:"]="Site:" +["Branch:"]="Branch:" +["Emulator:"]="Emulator:" +["Nitro-V3:"]="Nitro-V3:" +["Renderer:"]="Renderer:" +["Service:"]="Service:" +["Socket:"]="Socket:" +["API:"]="API:" +["Gamedata:"]="Gamedata:" +["Min Disk:"]="Min Schijf:" +# ── SPINNER ─────────────────────────────────────────── +["Building emulator (parallel)..."]="Emulator aan het bouwen (parallel)..." +["Installing deps..."]="Afhankelijkheden installeren..." +["Building frontend..."]="Frontend aan het bouwen..." +["Backing up..."]="Backup aan het maken..." +["Restoring..."]="Aan het herstellen..." +["Optimizing..."]="Aan het optimaliseren..." +# ── NOTIFY ────────────────────────────────────────── +["SUCCESS"]="GELUKT" +["FAILED"]="MISLUKT" +["Completed in %s (%s warnings)"]="Voltooid in %s (%s waarschuwingen)" +# ── OTHER ─────────────────────────────────────────── +["Total: %s backups — %s"]="Totaal: %s backups — %s" +["FILENAME"]="BESTANDSNAAM" +["SIZE"]="GROOTTE" +["All config files valid"]="Alle configuratiebestanden geldig" +# ── SUMMARY ────────────────────────────────────────── +["UPDATE COMPLETED SUCCESSFULLY"]="UPDATE SUCCESVOL VOLTOOID" +["COMPLETED WITH %s ERROR(S)"]="VOLTOOID MET %s FOUT(EN)" +["Duration:"]="Duur:" +["Updates:"]="Updates:" +["Nitro build:"]="Nitro build:" +["Warnings:"]="Waarschuwingen:" +["Repos:"]="Repos:" +["Yes"]="Ja" +["No"]="Nee" + ) ;; + fr) _T=( +# ── MENU ────────────────────────────────────────────── +["UPDATE"]="MISE À JOUR" +["TOOLS"]="OUTILS" +["ADVANCED"]="AVANCÉ" +["Quick Update — current branch"]="Mise à jour rapide — branche actuelle" +["Full Update (choose branch)"]="Mise à jour complète (choisir branche)" +["Emulator Only"]="Émulateur uniquement" +["Nitro-V3 Client Only"]="Client Nitro-V3 uniquement" +["Renderer Only"]="Rendu uniquement" +["Configs Only"]="Configs uniquement" +["Dev Mode (skip builds, only configs)"]="Mode Dev (sans builds, configs seulement)" +["Switch Branch"]="Changer de branche" +["Database"]="Base de données" +["Backup / Restore"]="Sauvegarde / Restauration" +["Services"]="Services" +["Status"]="Statut" +["Health Check"]="Vérification de santé" +["Clean"]="Nettoyer" +["Logs"]="Journaux" +["Config"]="Configuration" +["Git Log"]="Journal Git" +["Compare Branches"]="Comparer les branches" +["Cron Scheduler"]="Planificateur Cron" +["View Git Stashes"]="Voir les stashs Git" +["Exit"]="Quitter" +["Select [0-20]"]="Sélectionner [0-20]" +["Press Enter to continue..."]="Appuyez sur Entrée pour continuer..." +["Goodbye!"]="Au revoir !" +["Start update?"]="Lancer la mise à jour ?" +["Continue?"]="Continuer ?" +# ── HELP ────────────────────────────────────────────── +["USAGE:"]="UTILISATION :" +["COMMANDS:"]="COMMANDES :" +["OPTIONS:"]="OPTIONS :" +# ── STEP HEADERS ────────────────────────────────────── +["Update & Build Emulator"]="Mise à jour & Construction Émulateur" +["Update Nitro_Render_V3"]="Mise à jour Nitro_Render_V3" +["Update & Build Nitro-V3"]="Mise à jour & Construction Nitro-V3" +["Sync Configurations"]="Synchroniser les configurations" +["Cleanup"]="Nettoyage" +["Set Permissions"]="Définir les permissions" +["Restart Services"]="Redémarrer les services" +["System Diagnostics"]="Diagnostics système" +["Database Backup"]="Sauvegarde base de données" +["Database Restore"]="Restauration base de données" +["Backup Inventory"]="Inventaire des sauvegardes" +["System Status"]="Statut du système" +["Health Check"]="Vérification de santé" +["Service Manager"]="Gestionnaire de services" +["Database Tools"]="Outils base de données" +["Configuration"]="Configuration" +["Log Viewer"]="Visualisateur de journaux" +["Cache Cleanup"]="Nettoyage du cache" +["Git Commit History"]="Historique des commits Git" +["Branch Comparison"]="Comparaison de branches" +["Cron Scheduler"]="Planificateur Cron" +["Git Stashes"]="Stashs Git" +["Missing: %s"]="Manquant : %s" +["Missing dir: %s"]="Répertoire manquant : %s" +["All commands available"]="Toutes les commandes disponibles" +["All directories exist"]="Tous les répertoires existent" +["Database connected"]="Base de données connectée" +["Maven build failed (see: %s)"]="Build Maven échoué (voir : %s)" +["yarn install failed"]="yarn install échoué" +["yarn build failed (see: %s)"]="yarn build échoué (voir : %s)" +["Jar: %s"]="Jar : %s" +["Backup: %s — %s"]="Sauvegarde : %s — %s" +["Restored"]="Restauré" +["Cancelled"]="Annulé" +["Invalid"]="Invalide" +["Invalid selection"]="Sélection invalide" +["Scheduled daily 03:00"]="Planifié quotidien 03:00" +["Scheduled daily 04:00"]="Planifié quotidien 04:00" +["Scheduled weekly"]="Planifié hebdomadaire" +["Removed"]="Supprimé" +["Return"]="Retour" +["none"]="aucun" +["Yes"]="Oui" +["No"]="Non" +["Goodbye!"]="Au revoir !" + ) ;; + es) _T=( +# ── MENU ────────────────────────────────────────────── +["UPDATE"]="ACTUALIZAR" +["TOOLS"]="HERRAMIENTAS" +["ADVANCED"]="AVANZADO" +["Quick Update — current branch"]="Actualización rápida — rama actual" +["Full Update (choose branch)"]="Actualización completa (elegir rama)" +["Emulator Only"]="Solo Emulador" +["Nitro-V3 Client Only"]="Solo Cliente Nitro-V3" +["Renderer Only"]="Solo Renderizador" +["Configs Only"]="Solo Configuraciones" +["Dev Mode (skip builds, only configs)"]="Modo Dev (sin builds, solo configs)" +["Switch Branch"]="Cambiar Rama" +["Database"]="Base de Datos" +["Backup / Restore"]="Respaldo / Restaurar" +["Services"]="Servicios" +["Status"]="Estado" +["Health Check"]="Verificación de Salud" +["Clean"]="Limpiar" +["Logs"]="Registros" +["Config"]="Configuración" +["Git Log"]="Registro Git" +["Compare Branches"]="Comparar Ramas" +["Cron Scheduler"]="Programador Cron" +["View Git Stashes"]="Ver Stashes Git" +["Exit"]="Salir" +["Select [0-20]"]="Seleccionar [0-20]" +["Press Enter to continue..."]="Presione Enter para continuar..." +["Goodbye!"]="¡Hasta luego!" +["Start update?"]="¿Iniciar actualización?" +["Continue?"]="¿Continuar?" +["Missing: %s"]="Falta: %s" +["Missing dir: %s"]="Directorio faltante: %s" +["All commands available"]="Todos los comandos disponibles" +["All directories exist"]="Todos los directorios existen" +["Database connected"]="Base de datos conectada" +["Maven build failed (see: %s)"]="Build Maven falló (ver: %s)" +["yarn install failed"]="yarn install falló" +["yarn build failed (see: %s)"]="yarn build falló (ver: %s)" +["Goodbye!"]="¡Hasta luego!" +["Return"]="Volver" +["none"]="ninguno" +["Yes"]="Sí" +["No"]="No" + ) ;; + de) _T=( +# ── MENU ────────────────────────────────────────────── +["UPDATE"]="AKTUALISIEREN" +["TOOLS"]="WERKZEUGE" +["ADVANCED"]="ERWEITERT" +["Quick Update — current branch"]="Schnellupdate — aktueller Branch" +["Full Update (choose branch)"]="Vollständiges Update (Branch wählen)" +["Emulator Only"]="Nur Emulator" +["Nitro-V3 Client Only"]="Nur Nitro-V3 Client" +["Renderer Only"]="Nur Renderer" +["Configs Only"]="Nur Konfigurationen" +["Dev Mode (skip builds, only configs)"]="Dev-Modus (ohne Builds, nur Konfigs)" +["Switch Branch"]="Branch wechseln" +["Database"]="Datenbank" +["Backup / Restore"]="Sicherung / Wiederherstellung" +["Services"]="Dienste" +["Status"]="Status" +["Health Check"]="Gesundheitsprüfung" +["Clean"]="Bereinigen" +["Logs"]="Protokolle" +["Config"]="Konfiguration" +["Git Log"]="Git-Verlauf" +["Compare Branches"]="Branches vergleichen" +["Cron Scheduler"]="Cron-Planer" +["View Git Stashes"]="Git-Stashes anzeigen" +["Exit"]="Beenden" +["Select [0-20]"]="Auswählen [0-20]" +["Press Enter to continue..."]="Drücken Sie Enter zum Fortfahren..." +["Goodbye!"]="Auf Wiedersehen!" +["Start update?"]="Update starten?" +["Continue?"]="Fortfahren?" +["Missing: %s"]="Fehlt: %s" +["Missing dir: %s"]="Verzeichnis fehlt: %s" +["All commands available"]="Alle Befehle verfügbar" +["All directories exist"]="Alle Verzeichnisse vorhanden" +["Database connected"]="Datenbank verbunden" +["Maven build failed (see: %s)"]="Maven-Build fehlgeschlagen (siehe: %s)" +["yarn install failed"]="yarn install fehlgeschlagen" +["yarn build failed (see: %s)"]="yarn build fehlgeschlagen (siehe: %s)" +["Goodbye!"]="Auf Wiedersehen!" +["Return"]="Zurück" +["none"]="keine" +["Yes"]="Ja" +["No"]="Nein" + ) ;; + it) _T=( +# ── MENU ────────────────────────────────────────────── +["UPDATE"]="AGGIORNA" +["TOOLS"]="STRUMENTI" +["ADVANCED"]="AVANZATE" +["Quick Update — current branch"]="Aggiornamento rapido — ramo attuale" +["Full Update (choose branch)"]="Aggiornamento completo (scegli ramo)" +["Emulator Only"]="Solo Emulatore" +["Nitro-V3 Client Only"]="Solo Client Nitro-V3" +["Renderer Only"]="Solo Renderer" +["Configs Only"]="Solo Configurazioni" +["Dev Mode (skip builds, only configs)"]="Modalità Dev (senza build, solo configs)" +["Switch Branch"]="Cambia Ramo" +["Database"]="Database" +["Backup / Restore"]="Backup / Ripristino" +["Services"]="Servizi" +["Status"]="Stato" +["Health Check"]="Controllo Salute" +["Clean"]="Pulisci" +["Logs"]="Registri" +["Config"]="Configurazione" +["Git Log"]="Registro Git" +["Compare Branches"]="Confronta Rami" +["Cron Scheduler"]="Pianificatore Cron" +["View Git Stashes"]="Vedi Stash Git" +["Exit"]="Esci" +["Select [0-20]"]="Seleziona [0-20]" +["Press Enter to continue..."]="Premi Invio per continuare..." +["Goodbye!"]="Arrivederci!" +["Start update?"]="Avviare aggiornamento?" +["Continue?"]="Continuare?" +["Missing: %s"]="Mancante: %s" +["Missing dir: %s"]="Directory mancante: %s" +["All commands available"]="Tutti i comandi disponibili" +["All directories exist"]="Tutte le directory esistono" +["Database connected"]="Database connesso" +["Maven build failed (see: %s)"]="Build Maven fallita (vedi: %s)" +["yarn install failed"]="yarn install fallito" +["yarn build failed (see: %s)"]="yarn build fallito (vedi: %s)" +["Goodbye!"]="Arrivederci!" +["Return"]="Indietro" +["none"]="nessuno" +["Yes"]="Sì" +["No"]="No" + ) ;; + esac +} + # ============================================================================= # LOCKFILE # ============================================================================= acquire_lock() { exec 9>"$LOCK_FILE" if ! flock -n 9; then - die "Another instance is already running (lock: $LOCK_FILE)" + die "Another instance is already running (lock: %s)" "$LOCK_FILE" fi } @@ -148,16 +677,17 @@ release_lock() { # UI HELPERS # ============================================================================= log_write() { printf "[%s] [%s] %s\n" "$(date '+%Y-%m-%d %H:%M:%S')" "$1" "$2" >> "$LOG_FILE" 2>/dev/null || true; } -info() { echo -e " ${C_BLUE}${E_ARROW}${C_RESET} $1"; log_write "INFO" "$1"; } -ok() { echo -e " ${C_GREEN}${E_OK}${C_RESET} $1"; log_write "OK" "$1"; } -warn() { echo -e " ${C_YELLOW}${E_WARN}${C_RESET} $1"; WARNINGS=$((WARNINGS + 1)); log_write "WARN" "$1"; } -fail() { echo -e " ${C_RED}${E_FAIL}${C_RESET} $1"; log_write "FAIL" "$1"; } +info() { local m; m=$(_t "$1" "${@:2}"); echo -e " ${C_BLUE}${E_ARROW}${C_RESET} $m"; log_write "INFO" "$m"; } +ok() { local m; m=$(_t "$1" "${@:2}"); echo -e " ${C_GREEN}${E_OK}${C_RESET} $m"; log_write "OK" "$m"; } +warn() { local m; m=$(_t "$1" "${@:2}"); echo -e " ${C_YELLOW}${E_WARN}${C_RESET} $m"; WARNINGS=$((WARNINGS + 1)); log_write "WARN" "$m"; } +fail() { local m; m=$(_t "$1" "${@:2}"); echo -e " ${C_RED}${E_FAIL}${C_RESET} $m"; log_write "FAIL" "$m"; } die() { + local m; m=$(_t "$1" "${@:2}") echo "" - echo -e " ${C_BG_RED}${C_WHITE}${C_BOLD} ERROR ${C_RESET} ${C_RED}$1${C_RESET}" - log_write "FATAL" "$1" - cleanup_notify_failure "$1" + echo -e " ${C_BG_RED}${C_WHITE}${C_BOLD} $(_t "ERROR") ${C_RESET} ${C_RED}$m${C_RESET}" + log_write "FATAL" "$m" + cleanup_notify_failure "$m" release_lock cursor_show exit 1 @@ -197,7 +727,7 @@ spinner_start() { ( local i=0 while true; do - printf "\r ${C_CYAN}${frames[$i]}${C_RESET} %s " "$msg" + printf "\r ${C_CYAN}${frames[$i]}${C_RESET} %s " "$(_t "$msg")" i=$(( (i + 1) % ${#frames[@]} )) sleep 0.1 done @@ -218,14 +748,14 @@ spinner_stop() { step() { local num="${1}" total="${2}" title="${3}" echo "" - echo -e " ${C_BG_CYAN}${C_WHITE}${C_BOLD} Step ${num}/${total} — ${title} ${C_RESET}" + echo -e " ${C_BG_CYAN}${C_WHITE}${C_BOLD} Step ${num}/${total} — $(_t "$title") ${C_RESET}" echo "" } confirm() { local msg="${1:-Continue?}" default="${2:-y}" local hint="[Y/n]"; [ "$default" = "n" ] && hint="[y/N]" - echo -en " ${C_YELLOW}${E_ARROW}${C_RESET} ${C_BOLD}$msg${C_RESET} $hint " + echo -en " ${C_YELLOW}${E_ARROW}${C_RESET} ${C_BOLD}$(_t "$msg")${C_RESET} $hint " local reply; read -rt 30 reply; reply="${reply:-$default}" [[ "$reply" =~ ^[Yy] ]] } @@ -241,8 +771,9 @@ dry_run() { box_top() { local title="${1:-}" width="${2:-60}" if [ -n "$title" ]; then - local pad=$((width - ${#title} - 6)); [ $pad -lt 0 ] && pad=0 - printf "${C_CYAN}╔═══ ${C_BOLD}%s${C_RESET}${C_CYAN}" "$title" + local tt; tt=$(_t "$title") + local pad=$((width - ${#tt} - 6)); [ $pad -lt 0 ] && pad=0 + printf "${C_CYAN}╔═══ ${C_BOLD}%s${C_RESET}${C_CYAN}" "$tt" repeat '═' "$pad" echo -e "╗${C_RESET}" else @@ -251,10 +782,11 @@ box_top() { } box_kv() { local key="${1}" val="${2}" width="${3:-60}" - local ck=$(echo -e "$key" | sed 's/\x1b\[[0-9;]*m//g') + local kk; kk=$(_t "$key") + local ck=$(echo -e "$kk" | sed 's/\x1b\[[0-9;]*m//g') local cv=$(echo -e "$val" | sed 's/\x1b\[[0-9;]*m//g') local pad=$((width - ${#ck} - ${#cv} - 6)); [ $pad -lt 0 ] && pad=0 - printf "${C_CYAN}║${C_RESET} %s%*s%s ${C_CYAN}║${C_RESET}\n" "$key" $pad "" "$val" + printf "${C_CYAN}║${C_RESET} %s%*s%s ${C_CYAN}║${C_RESET}\n" "$kk" $pad "" "$val" } box_line() { local text="${1:-}" width="${2:-60}" @@ -293,12 +825,13 @@ cleanup_notify_failure() { $NOTIFY_FAILED && return; NOTIFY_FAILED=true; notify cleanup_on_exit() { local ec=$?; cursor_show; release_lock if [ $ec -ne 0 ] && [ "$ROLLBACK_NEEDED" = true ]; then - echo -e "\n ${C_BG_RED}${C_WHITE}${C_BOLD} ROLLBACK ${C_RESET}" - echo -e " Restoring config back-ups from $CONFIG_BACKUP_DIR/rollback..." + echo -e "\n ${C_BG_RED}${C_WHITE}${C_BOLD} $(_t "ROLLBACK") ${C_RESET}" + echo -e " $(_t "Restoring config back-ups from") $CONFIG_BACKUP_DIR/rollback..." if [ -d "$CONFIG_BACKUP_DIR/rollback" ]; then cp -r "$CONFIG_BACKUP_DIR/rollback/"* "$NITRO_SRC_DIR/" 2>/dev/null || true ok "Config files restored from rollback" fi + restore_binaries fi [ $ec -ne 0 ] && cleanup_notify_failure "Exit code $ec" } @@ -355,7 +888,7 @@ git_update() { elif git pull --ff-only 2>/dev/null; then pulled=0; break fi - warn "Pull attempt $attempt failed in $(basename "$repo"), retrying..." >&2 + warn "Pull attempt %s failed in %s, retrying..." "$attempt" "$(basename "$repo")" >&2 sleep 2 done [ "$pulled" -ne 0 ] && { warn "Pull failed in $(basename "$repo")"; exit 1; } @@ -440,13 +973,55 @@ validate_configs() { for f in "$dir"/*.json; do [ -f "$f" ] || continue if ! validate_json "$f"; then - warn "Invalid JSON: $(basename "$f")" + warn "Invalid JSON: %s" "$(basename "$f")" errors=$((errors + 1)) fi done [ "$errors" -eq 0 ] && ok "All config files valid" || warn "$errors config(s) invalid" } +# ============================================================================= +# BINARY BACKUP & ROLLBACK +# ============================================================================= +backup_binaries() { + [ -n "$BINARY_BACKUP_DIR" ] && return + BINARY_BACKUP_DIR="$CONFIG_BACKUP_DIR/binaries-$(date +%Y%m%d-%H%M%S)" + mkdir -p "$BINARY_BACKUP_DIR" + + local jar_dir="$EMULATOR_DIR/Emulator/target" + if [ -d "$jar_dir" ] && ls "$jar_dir"/Polaris-*-jar-with-dependencies.jar &>/dev/null 2>&1; then + cp "$jar_dir"/Polaris-*-jar-with-dependencies.jar "$BINARY_BACKUP_DIR/" 2>/dev/null || true + ok "Emulator JAR backed up" + fi + + local client_dist="$NITRO_CLIENT/dist" + if [ -d "$client_dist" ]; then + cp -r "$client_dist" "$BINARY_BACKUP_DIR/client-dist" 2>/dev/null || true + ok "Nitro-V3 dist backed up" + fi +} + +restore_binaries() { + [ -z "$BINARY_BACKUP_DIR" ] && return + [ ! -d "$BINARY_BACKUP_DIR" ] && return + echo "" + echo -e " ${C_BG_RED}${C_WHITE}${C_BOLD} $(_t "RESTORE BINARIES") ${C_RESET}" + + if ls "$BINARY_BACKUP_DIR"/Polaris-*-jar-with-dependencies.jar &>/dev/null 2>&1; then + local jar_dir="$EMULATOR_DIR/Emulator/target" + mkdir -p "$jar_dir" + cp "$BINARY_BACKUP_DIR"/Polaris-*-jar-with-dependencies.jar "$jar_dir/" 2>/dev/null || true + ok "Emulator JAR restored" + fi + + if [ -d "$BINARY_BACKUP_DIR/client-dist" ]; then + local client_dist="$NITRO_CLIENT/dist" + rm -rf "$client_dist" 2>/dev/null || true + cp -r "$BINARY_BACKUP_DIR/client-dist" "$client_dist" 2>/dev/null || true + ok "Nitro-V3 dist restored" + fi +} + # ============================================================================= # PRE-FLIGHT CHECKS # ============================================================================= @@ -471,9 +1046,9 @@ preflight_check() { local total_gb=$((total_kb / 1024 / 1024)) [ "$total_gb" -lt "$MIN_DISK_GB" ] && die "Only ${total_gb}GB free (min ${MIN_DISK_GB}GB)" if [ "$total_gb" -lt $((MIN_DISK_GB * 2)) ]; then - warn "Low disk: ${total_gb}GB free" + warn "Low disk: %sGB free" "$total_gb" else - ok "${total_gb}GB disk available" + ok "%sGB disk available" "$total_gb" fi $MYSQL_CLIENT $MYSQL_CRED -e "SELECT 1" "$DB_NAME" &>/dev/null || die "DB connection failed" @@ -488,6 +1063,8 @@ update_emulator() { if git_update "$EMULATOR_DIR/Emulator" "$NITRO_BRANCH"; then HAD_UPDATES=true; UPDATED_REPOS+=("Emulator") cd "$EMULATOR_DIR/Emulator" + backup_binaries + ROLLBACK_NEEDED=true spinner_start "Building emulator (parallel)..." # Prefer offline mode when the local Maven repo is warm; fall back to # online if offline resolution fails. ccache speeds up repeated JNI/C++ @@ -499,11 +1076,11 @@ update_emulator() { else spinner_stop fail tail -30 "$LOG_FILE" | grep -E '(ERROR|FAILURE|BUILD)' || true - die "Maven build failed (see: $LOG_FILE)" + die "Maven build failed (see: %s)" "$LOG_FILE" fi local jar=$(find target -maxdepth 1 -name 'Polaris-*-jar-with-dependencies.jar' -printf '%T@ %p\n' 2>/dev/null | sort -rn | sed -n '1s/^[0-9.]* //p' | xargs -r basename 2>/dev/null || echo "") [ -z "$jar" ] && die "No jar found" - ok "Jar: $jar" + ok "Jar: %s" "$jar" cd target/ cat > emulator << EOJ #!/bin/sh @@ -538,6 +1115,8 @@ update_client() { if git_update "$NITRO_CLIENT" "$NITRO_BRANCH"; then HAD_UPDATES=true; NITRO_BUILT=true; UPDATED_REPOS+=("Nitro-V3") cd "$NITRO_CLIENT" + backup_binaries + ROLLBACK_NEEDED=true spinner_start "Installing deps..." yarn install --frozen-lockfile --prefer-offline 2>&1 || { clean_node_modules && yarn install 2>&1; } || { spinner_stop fail; die "yarn install failed"; } spinner_stop ok @@ -547,7 +1126,7 @@ update_client() { else spinner_stop fail tail -10 "$LOG_FILE" || true - die "yarn build failed (see: $LOG_FILE)" + die "yarn build failed (see: %s)" "$LOG_FILE" fi else info "Nitro-V3: already up to date" @@ -562,7 +1141,7 @@ sync_configs() { # Backup current configs before overwriting local cb=$(backup_configs) - info "Config back-up: $(basename "$cb")" + info "Config back-up: %s" "$(basename "$cb")" local ms="$SCRIPT_DIR/scripts/merge-config.cjs" local dcd="$NITRO_CLIENT/dist/configuration" @@ -579,7 +1158,7 @@ sync_configs() { [ -d "$dcd" ] && cp "$NITRO_SRC_DIR/$tn" "$dcd/$tn" 2>/dev/null || true ec=$((ec+1)) done - ok "$ec config file(s) synced" + ok "%s config file(s) synced" "$ec" # Validate the generated configs validate_configs "$NITRO_SRC_DIR" @@ -637,7 +1216,7 @@ do_cleanup() { rm -rf /tmp/nitro-* /tmp/epicnext-* 2>/dev/null || true # Clean old Maven build artifacts (older than 7 days) find "$EMULATOR_DIR/Emulator" -maxdepth 3 -name '*.jar' -mtime +7 2>/dev/null -exec rm -f {} \; || true - ok "Cleanup done ($lc logs removed)" + ok "Cleanup done (%s logs removed)" "$lc" } do_permissions() { @@ -654,15 +1233,17 @@ do_restart() { sudo systemctl restart "$EMULATOR_SERVICE" 2>/dev/null && ok "$EMULATOR_SERVICE restarted" || warn "Restart failed" local hc=0 while [ "$hc" -lt "$HEALTH_RETRIES" ]; do - sleep "$HEALTH_INTERVAL" if service_active "$EMULATOR_SERVICE" && emulator_port_open; then ok "Emulator health check passed (service up + port listening)" break fi hc=$((hc+1)) + [ "$hc" -lt "$HEALTH_RETRIES" ] && sleep "$HEALTH_INTERVAL" done if [ "$hc" -eq "$HEALTH_RETRIES" ]; then - warn "Emulator not healthy after $HEALTH_RETRIES retries" + warn "Emulator not healthy after %s retries" "$HEALTH_RETRIES" + sudo journalctl -u "$EMULATOR_SERVICE" --no-pager -n 20 2>/dev/null || true + ERRORS=$((ERRORS + 1)) ROLLBACK_NEEDED=true fi elif command -v pm2 &>/dev/null; then @@ -679,15 +1260,16 @@ do_restart() { emulator_port_open() { local port="${NITRO_EMULATOR_PORT:-30000}" if command -v redis-cli >/dev/null 2>&1; then - # Emulator advertises its port via the gamedata/extradata; fall back to env. local p; p=$(redis-cli GET nitro:emulator:port 2>/dev/null) [ -n "$p" ] && port="$p" fi if command -v nc >/dev/null 2>&1; then - timeout 3 bash -c "exec 3<>/dev/tcp/127.0.0.1/$port" 2>/dev/null && return 0 - elif command -v ss >/dev/null 2>&1; then + nc -z 127.0.0.1 "$port" -w 3 2>/dev/null && return 0 + fi + if command -v ss >/dev/null 2>&1; then ss -ltn 2>/dev/null | grep -q ":$port " && return 0 fi + timeout 3 bash -c "exec 3<>/dev/tcp/127.0.0.1/$port" 2>/dev/null && return 0 return 1 } @@ -696,16 +1278,16 @@ show_summary() { echo "" echo -e " ${C_CYAN}╔══════════════════════════════════════════════════════════════════╗${C_RESET}" if [ "$ERRORS" -eq 0 ]; then - echo -e " ${C_CYAN}║${C_RESET} ${C_GREEN}${C_BOLD}✔ UPDATE COMPLETED SUCCESSFULLY${C_RESET} ${C_CYAN}║${C_RESET}" + echo -e " ${C_CYAN}║${C_RESET} ${C_GREEN}${C_BOLD}✔ $(_t "UPDATE COMPLETED SUCCESSFULLY")${C_RESET} ${C_CYAN}║${C_RESET}" else - echo -e " ${C_CYAN}║${C_RESET} ${C_YELLOW}${C_BOLD}⚠ COMPLETED WITH $ERRORS ERROR(S)${C_RESET} ${C_CYAN}║${C_RESET}" + echo -e " ${C_CYAN}║${C_RESET} ${C_YELLOW}${C_BOLD}⚠ $(_t "COMPLETED WITH") $ERRORS $(_t "ERROR(S)")${C_RESET} ${C_CYAN}║${C_RESET}" fi echo -e " ${C_CYAN}╠══════════════════════════════════════════════════════════════════╣${C_RESET}" - printf " ${C_CYAN}║${C_RESET} Duration: %-46s${C_CYAN}║${C_RESET}\n" "$ef" - printf " ${C_CYAN}║${C_RESET} Updates: %-46s${C_CYAN}║${C_RESET}\n" "$([ "$HAD_UPDATES" = true ] && echo "Yes" || echo "No")" - printf " ${C_CYAN}║${C_RESET} Nitro build: %-46s${C_CYAN}║${C_RESET}\n" "$([ "$NITRO_BUILT" = true ] && echo "Yes" || echo "No")" - printf " ${C_CYAN}║${C_RESET} Warnings: %-46s${C_CYAN}║${C_RESET}\n" "$WARNINGS" - [ ${#UPDATED_REPOS[@]} -gt 0 ] && printf " ${C_CYAN}║${C_RESET} Repos: %-46s${C_CYAN}║${C_RESET}\n" "${UPDATED_REPOS[*]}" + printf " ${C_CYAN}║${C_RESET} $(_t "Duration:") %-46s${C_CYAN}║${C_RESET}\n" "$ef" + printf " ${C_CYAN}║${C_RESET} $(_t "Updates:") %-46s${C_CYAN}║${C_RESET}\n" "$([ "$HAD_UPDATES" = true ] && echo "$(_t "Yes")" || echo "$(_t "No")")" + printf " ${C_CYAN}║${C_RESET} $(_t "Nitro build:") %-46s${C_CYAN}║${C_RESET}\n" "$([ "$NITRO_BUILT" = true ] && echo "$(_t "Yes")" || echo "$(_t "No")")" + printf " ${C_CYAN}║${C_RESET} $(_t "Warnings:") %-46s${C_CYAN}║${C_RESET}\n" "$WARNINGS" + [ ${#UPDATED_REPOS[@]} -gt 0 ] && printf " ${C_CYAN}║${C_RESET} $(_t "Repos:") %-46s${C_CYAN}║${C_RESET}\n" "${UPDATED_REPOS[*]}" echo -e " ${C_CYAN}╚══════════════════════════════════════════════════════════════════╝${C_RESET}" echo "" notify "SUCCESS" "Completed in $ef (${WARNINGS} warnings)" @@ -718,8 +1300,8 @@ cmd_update() { echo "" acquire_lock DRY_RUN=${DRY_RUN:-false} - info "Site: ${NITRO_SITE_URL:-?} | Branch: $NITRO_BRANCH | Mode: ${SELECTIVE_UPDATE:-full}${DRY_RUN:+ [DRY-RUN]}" - info "Log: $LOG_FILE" + info "Site: %s | Branch: %s | Mode: %s" "${NITRO_SITE_URL:-?}" "$NITRO_BRANCH" "${SELECTIVE_UPDATE:-full}${DRY_RUN:+ [DRY-RUN]}" + info "Log: %s" "$LOG_FILE" if [ "$DRY_RUN" = true ]; then info "Dry-run: would update repos, run DB backups, build, sync configs, cleanup, restart services" show_summary @@ -749,9 +1331,9 @@ cmd_update() { parallel_run "client" update_client parallel_wait if ! parallel_failed; then - warn "Parallel build(s) failed: ${PARALLEL_FAILED[*]} — aborting before restart" + warn "Parallel build(s) failed: %s — aborting before restart" "${PARALLEL_FAILED[*]}" ROLLBACK_NEEDED=true - die "Build failure in: ${PARALLEL_FAILED[*]}" + die "Build failure in: %s" "${PARALLEL_FAILED[*]}" fi else info "No repo updates; skipping parallel builds" @@ -761,6 +1343,7 @@ cmd_update() { do_permissions do_restart RUN_ROLLBACK=false + [ -n "$BINARY_BACKUP_DIR" ] && rm -rf "$BINARY_BACKUP_DIR" 2>/dev/null || true ;; esac @@ -778,7 +1361,7 @@ cmd_backup() { spinner_start "Backing up..." if $MYSQL_DUMP $MYSQL_CRED --force --skip-lock-tables --routines --events --triggers "$DB_NAME" > "$bf" 2>/dev/null; then local sz=$(stat -c%s "$bf" 2>/dev/null || echo 0); spinner_stop ok - ok "Backup: $(format_size "$sz") — $(basename "$bf")" + ok "Backup: %s — %s" "$(format_size "$sz")" "$(basename "$bf")" else spinner_stop fail; die "Backup failed" fi @@ -791,16 +1374,16 @@ cmd_restore() { while IFS= read -r line; do backups+=("$line"); done < <(list_sorted "$BACKUP_DIR" '*.sql') [ ${#backups[@]} -eq 0 ] && die "No backups" echo "" - echo -e " ${C_BOLD}${C_CYAN}Backups:${C_RESET}" + echo -e " ${C_BOLD}${C_CYAN}$(_t "Backups:")${C_RESET}" local i=1 for bk in "${backups[@]}"; do local sz=$(format_size "$(stat -c%s "$bk" 2>/dev/null || echo 0)") printf " ${C_GREEN}${C_BOLD}%2d)${C_RESET} %-40s ${C_DIM}%s${C_RESET}\n" "$i" "$(basename "$bk")" "$sz" i=$((i+1)) done - echo -en "\n Select [1-$((i-1))]: " + echo -en "\n $(_t "Select") [1-$((i-1))]: " local c; read -rt 30 c - [[ "$c" =~ ^[0-9]+$ ]] && [ "$c" -ge 1 ] && [ "$c" -le ${#backups[@]} ] || die "Invalid" + [[ "$c" =~ ^[0-9]+$ ]] && [ "$c" -ge 1 ] && [ "$c" -le ${#backups[@]} ] || die "$(_t "Invalid")" local sel="${backups[$((c-1))]}" if ! confirm "Restore $(basename "$sel")? OVERWRITES database!"; then info "Cancelled"; return; fi spinner_start "Restoring..." @@ -819,7 +1402,7 @@ cmd_backups() { printf " ${C_GREEN}%2d${C_RESET} %-38s ${C_CYAN}%s${C_RESET}\n" "$t" "$n" "$(format_size "$s")" done < <(list_sorted "$BACKUP_DIR" '*.sql') printf " ${C_DIM}%s${C_RESET}\n" "$(repeat '─' 56)" - echo -e " ${C_BOLD}Total: $t backups — $(format_size "$ts")${C_RESET}\n" + echo -e " ${C_BOLD}$(_t "Total:") $t $(_t "backups") — $(format_size "$ts")${C_RESET}\n" } # ============================================================================= @@ -869,30 +1452,61 @@ cmd_status() { cmd_health() { step 1 1 "Health Check" local t=0 p=0 f=0 w=0 - check() { t=$((t+1)); "$@" &>/dev/null && { p=$((p+1)); ok "$1"; } || { f=$((f+1)); fail "$1"; }; } - checkw() { t=$((t+1)); "$@" &>/dev/null && { p=$((p+1)); ok "$1"; } || { w=$((w+1)); warn "$1"; }; } + check() { t=$((t+1)); "$@" &>/dev/null && { p=$((p+1)); ok "$(_t "$1")"; } || { f=$((f+1)); fail "$(_t "$1")"; }; } + checkw() { t=$((t+1)); "$@" &>/dev/null && { p=$((p+1)); ok "$(_t "$1")"; } || { w=$((w+1)); warn "$(_t "$1")"; }; } echo "" - echo -e " ${C_BOLD}System:${C_RESET}" + echo -e " ${C_BOLD}$(_t "Commands:")${C_RESET}" checkw "Git" command -v git; checkw "Node.js" command -v node; checkw "Yarn" command -v yarn checkw "Python3" command -v python3; checkw "Java" command -v java; checkw "Maven" command -v mvn - echo -e "\n ${C_BOLD}Directories:${C_RESET}" + checkw "MariaDB" command -v "$MYSQL_CLIENT" + echo -e "\n ${C_BOLD}$(_t "Script:")${C_RESET}" + checkw "$(_t "Bash syntax")" bash -n "$SCRIPT_DIR/$SCRIPT_NAME" + if command -v shellcheck &>/dev/null; then checkw "ShellCheck" shellcheck --quiet "$SCRIPT_DIR/$SCRIPT_NAME"; fi + if command -v checkbashisms &>/dev/null; then checkw "$(_t "Bashisms")" checkbashisms "$SCRIPT_DIR/$SCRIPT_NAME"; fi + echo -e "\n ${C_BOLD}$(_t "Configs:")${C_RESET}" + checkw "$(_t "Config dir")" test -d "$NITRO_SRC_DIR" + local cerr=0 + for cf in "$NITRO_SRC_DIR"/*.json; do + [ -f "$cf" ] || continue + python3 -m json.tool "$cf" >/dev/null 2>&1 || cerr=$((cerr+1)) + done + [ "$cerr" -eq 0 ] && ok "$(_t "All JSON valid")" || warn "$(_t "JSON errors:") $cerr" + echo -e "\n ${C_BOLD}$(_t "Config URLs:")${C_RESET}" + for key in NITRO_SITE_URL NITRO_API_URL NITRO_SOCKET_URL NITRO_GAMEDATA_URL NITRO_IMAGE_LIBRARY_URL; do + local val="${!key}" + [ -n "$val" ] && ok "$key" || warn "$key" + done + echo -e "\n ${C_BOLD}$(_t "Directories:")${C_RESET}" checkw "Emulator" test -d "$EMULATOR_DIR/Emulator"; checkw "Nitro-V3" test -d "$NITRO_CLIENT"; checkw "Renderer" test -d "$NITRO_RENDERER" - echo -e "\n ${C_BOLD}Services:${C_RESET}" + checkw "$(_t "Gamedata config")" test -d "$GAMEDATA_CONF_DIR"; checkw "$(_t "Backup dir")" test -d "$BACKUP_DIR" + echo -e "\n ${C_BOLD}$(_t "Services:")${C_RESET}" checkw "MariaDB" service_active mariadb; checkw "Nginx" service_active nginx; checkw "Redis" service_active redis-server - echo -e "\n ${C_BOLD}Application:${C_RESET}" - checkw "Next.js" test -f "$SCRIPT_DIR/next.config.js" -o -f "$SCRIPT_DIR/next.config.mjs" -o -f "$SCRIPT_DIR/next.config.ts"; checkw ".env" test -f "$SCRIPT_DIR/.env" - checkw "Site" timeout 5 curl -sf "${NITRO_SITE_URL:-}" 2>/dev/null - echo -e "\n ${C_BOLD}Resources:${C_RESET}" + checkw "$EMULATOR_SERVICE" service_active "$EMULATOR_SERVICE" + echo -e "\n ${C_BOLD}$(_t "Network:")${C_RESET}" + checkw "$(_t "Nginx config")" nginx -t 2>/dev/null + if command -v redis-cli &>/dev/null; then checkw "Redis PING" redis-cli PING 2>/dev/null; fi + checkw "$(_t "Site reachable")" timeout 5 curl -sf "${NITRO_SITE_URL:-}" 2>/dev/null + if emulator_port_open; then ok "$(_t "Emulator port open")"; else warn "$(_t "Emulator port closed")"; fi + echo -e "\n ${C_BOLD}$(_t "Databases:")${C_RESET}" + checkw "$(_t "MySQL connect")" $MYSQL_CLIENT $MYSQL_CRED -e "SELECT 1" "$DB_NAME" 2>/dev/null + local dbt=$($MYSQL_CLIENT $MYSQL_CRED -N -e "SELECT COUNT(*) FROM information_schema.tables WHERE table_schema='$DB_NAME'" "$DB_NAME" 2>/dev/null || echo "?") + t=$((t+1)); [ "$dbt" != "?" ] && { p=$((p+1)); ok "$(_t "Tables:") $dbt"; } || { f=$((f+1)); fail "$(_t "Tables:") ?"; } + echo -e "\n ${C_BOLD}$(_t "Resources:")${C_RESET}" local ak=$(df --output=avail "$EMULATOR_DIR" 2>/dev/null | tail -1); local ag=$((ak/1024/1024)) - t=$((t+1)); [ "$ag" -ge "$MIN_DISK_GB" ] && { p=$((p+1)); ok "Disk: ${ag}GB"; } || { f=$((f+1)); fail "Disk: ${ag}GB"; } + t=$((t+1)); [ "$ag" -ge "$MIN_DISK_GB" ] && { p=$((p+1)); ok "$(_t "Disk:") ${ag}GB"; } || { f=$((f+1)); fail "$(_t "Disk:") ${ag}GB"; } + local mem=$(free -m 2>/dev/null | awk '/^Mem:/{printf "%dMB / %dMB", $3, $2}') + t=$((t+1)); ok "$(_t "Memory:") $mem" + local load=$(awk '{printf "%.1f", $1}' /proc/loadavg 2>/dev/null || echo "?") + local cores=$(nproc 2>/dev/null || echo "?") + t=$((t+1)); ok "$(_t "Load:") $load / $cores cores" echo "" local sc=$((p*100/t)) box_top "SCORE" 50 box_kv "Passed:" "$p / $t" 50 box_kv "Failed:" "$f" 50; box_kv "Warnings:" "$w" 50 - if [ "$sc" -ge 90 ]; then box_line "${C_GREEN}${C_BOLD}${sc}% — EXCELLENT${C_RESET}" 50 - elif [ "$sc" -ge 70 ]; then box_line "${C_YELLOW}${C_BOLD}${sc}% — GOOD${C_RESET}" 50 - else box_line "${C_RED}${C_BOLD}${sc}% — NEEDS ATTENTION${C_RESET}" 50; fi + if [ "$sc" -ge 90 ]; then box_line "${C_GREEN}${C_BOLD}${sc}% — $(_t "EXCELLENT")${C_RESET}" 50 + elif [ "$sc" -ge 70 ]; then box_line "${C_YELLOW}${C_BOLD}${sc}% — $(_t "GOOD")${C_RESET}" 50 + else box_line "${C_RED}${C_BOLD}${sc}% — $(_t "NEEDS ATTENTION")${C_RESET}" 50; fi box_bottom 50; echo "" } @@ -902,10 +1516,10 @@ cmd_health() { cmd_services() { step 1 1 "Service Manager" echo "" - echo -e " ${C_BOLD}1)${C_RESET} Start Emulator ${C_BOLD}2)${C_RESET} Stop Emulator ${C_BOLD}3)${C_RESET} Restart Emulator" - echo -e " ${C_BOLD}4)${C_RESET} Start Nginx ${C_BOLD}5)${C_RESET} Restart Nginx ${C_BOLD}6)${C_RESET} Status All" - echo -e " ${C_BOLD}7)${C_RESET} Emulator Logs ${C_BOLD}8)${C_RESET} Emulator Journal ${C_BOLD}0)${C_RESET} Return" - echo -en "\n Select: "; local c; read -rt 30 c + echo -e " ${C_BOLD}1)${C_RESET} $(_t "Start Emulator") ${C_BOLD}2)${C_RESET} $(_t "Stop Emulator") ${C_BOLD}3)${C_RESET} $(_t "Restart Emulator")" + echo -e " ${C_BOLD}4)${C_RESET} $(_t "Start Nginx") ${C_BOLD}5)${C_RESET} $(_t "Restart Nginx") ${C_BOLD}6)${C_RESET} $(_t "Status All")" + echo -e " ${C_BOLD}7)${C_RESET} $(_t "Emulator Logs") ${C_BOLD}8)${C_RESET} $(_t "Emulator Journal") ${C_BOLD}0)${C_RESET} $(_t "Return")" + echo -en "\n $(_t "Select:") "; local c; read -rt 30 c case "$c" in 1) sudo systemctl start "$EMULATOR_SERVICE" && ok "Started" || fail "Failed" ;; 2) sudo systemctl stop "$EMULATOR_SERVICE" && ok "Stopped" || fail "Failed" ;; @@ -913,7 +1527,7 @@ cmd_services() { 4) sudo systemctl start nginx && ok "Started" || fail "Failed" ;; 5) sudo systemctl restart nginx && ok "Restarted" || fail "Failed" ;; 6) for s in nginx mariadb redis-server "$EMULATOR_SERVICE" php-fpm cron; do - local st="${C_RED}DOWN${C_RESET}"; service_active "$s" && st="${C_GREEN}UP${C_RESET}" + local st="${C_RED}$(_t "DOWN")${C_RESET}"; service_active "$s" && st="${C_GREEN}$(_t "UP")${C_RESET}" printf " %-25s %b\n" "$s" "$st" done ;; 7) sudo journalctl -u "$EMULATOR_SERVICE" --no-pager -n 30 ;; @@ -927,10 +1541,10 @@ cmd_services() { cmd_database() { step 1 1 "Database Tools" echo "" - echo -e " ${C_BOLD}1)${C_RESET} DB Info ${C_BOLD}2)${C_RESET} List Tables ${C_BOLD}3)${C_RESET} Table Sizes" - echo -e " ${C_BOLD}4)${C_RESET} Optimize ${C_BOLD}5)${C_RESET} Custom Query ${C_BOLD}6)${C_RESET} Active Users" - echo -e " ${C_BOLD}7)${C_RESET} Processlist ${C_BOLD}0)${C_RESET} Return" - echo -en "\n Select: "; local c; read -rt 30 c + echo -e " ${C_BOLD}1)${C_RESET} $(_t "DB Info") ${C_BOLD}2)${C_RESET} $(_t "List Tables") ${C_BOLD}3)${C_RESET} $(_t "Table Sizes")" + echo -e " ${C_BOLD}4)${C_RESET} $(_t "Optimize") ${C_BOLD}5)${C_RESET} $(_t "Custom Query") ${C_BOLD}6)${C_RESET} $(_t "Active Users")" + echo -e " ${C_BOLD}7)${C_RESET} $(_t "Processlist") ${C_BOLD}0)${C_RESET} $(_t "Return")" + echo -en "\n $(_t "Select:") "; local c; read -rt 30 c case "$c" in 1) box_top "DB INFO" 50 local dbs=$($MYSQL_CLIENT $MYSQL_CRED -N -e "SELECT ROUND(SUM(data_length+index_length)/1024/1024,1) FROM information_schema.tables WHERE table_schema='$DB_NAME'" "$DB_NAME" 2>/dev/null || echo "?") @@ -986,7 +1600,7 @@ cmd_logs() { printf " ${C_GREEN}${C_BOLD}%2d)${C_RESET} %-35s ${C_DIM}%s${C_RESET}\n" "$i" "$(basename "$l")" "$sz" i=$((i+1)) done - echo -en "\n Select [1-$((i-1))]: "; local c; read -rt 30 c + echo -en "\n $(_t "Select") [1-$((i-1))]: "; local c; read -rt 30 c if [[ "$c" =~ ^[0-9]+$ ]] && [ "$c" -ge 1 ] && [ "$c" -le ${#logs[@]} ]; then less -R "${logs[$((c-1))]}" 2>/dev/null || cat "${logs[$((c-1))]}" fi @@ -998,10 +1612,10 @@ cmd_logs() { cmd_clean() { step 1 1 "Cache Cleanup" echo "" - echo -e " ${C_BOLD}1)${C_RESET} Yarn ${C_BOLD}2)${C_RESET} Next.js ${C_BOLD}3)${C_RESET} Redis" - echo -e " ${C_BOLD}4)${C_RESET} Logs ${C_BOLD}5)${C_RESET} Everything ${C_BOLD}6)${C_RESET} Docker" - echo -e " ${C_BOLD}7)${C_RESET} Maven ${C_BOLD}0)${C_RESET} Return" - echo -en "\n Select: "; local c; read -rt 30 c + echo -e " ${C_BOLD}1)${C_RESET} $(_t "Yarn") ${C_BOLD}2)${C_RESET} $(_t "Next.js") ${C_BOLD}3)${C_RESET} $(_t "Redis")" + echo -e " ${C_BOLD}4)${C_RESET} $(_t "Logs") ${C_BOLD}5)${C_RESET} $(_t "Everything") ${C_BOLD}6)${C_RESET} $(_t "Docker")" + echo -e " ${C_BOLD}7)${C_RESET} $(_t "Maven") ${C_BOLD}0)${C_RESET} $(_t "Return")" + echo -en "\n $(_t "Select:") "; local c; read -rt 30 c case "$c" in 1) yarn cache clean 2>/dev/null && ok "Yarn cleaned" ;; 2) cd "$SCRIPT_DIR" && rm -rf .next 2>/dev/null && ok "Next.js cache cleared" ;; @@ -1019,8 +1633,8 @@ cmd_clean() { cmd_gitlog() { step 1 1 "Git Commit History" echo "" - echo -e " ${C_BOLD}1)${C_RESET} Emulator ${C_BOLD}2)${C_RESET} Nitro-V3 ${C_BOLD}3)${C_RESET} Renderer" - echo -en "\n Select: "; local c; read -rt 30 c + echo -e " ${C_BOLD}1)${C_RESET} $(_t "Emulator") ${C_BOLD}2)${C_RESET} $(_t "Nitro-V3") ${C_BOLD}3)${C_RESET} $(_t "Renderer")" + echo -en "\n $(_t "Select:") "; local c; read -rt 30 c local repo="" case "$c" in 1) repo="$EMULATOR_DIR/Emulator" ;; 2) repo="$NITRO_CLIENT" ;; 3) repo="$NITRO_RENDERER" ;; *) return ;; esac [ ! -d "$repo/.git" ] && { warn "Not a git repo"; return; } @@ -1029,7 +1643,7 @@ cmd_gitlog() { branch=$(cd "$repo" && git branch --show-current 2>/dev/null || echo "?") local ahead ahead=$(cd "$repo" && git rev-list --count "origin/${branch}"..HEAD 2>/dev/null || echo "0") - echo -e " ${C_BOLD}Last 20 commits on ${C_CYAN}${branch}${C_RESET} (ahead: ${C_RED}${ahead}${C_RESET}):" + echo -e " ${C_BOLD}$(_t "Last 20 commits on") ${C_CYAN}${branch}${C_RESET} ($(_t "ahead:") ${C_RED}${ahead}${C_RESET}):" echo "" cd "$repo" && git log --pretty=format:" ${C_CYAN}%h${C_RESET} %C(yellow)%cr${C_RESET} %s" -20 2>/dev/null echo -e "\n" @@ -1044,11 +1658,11 @@ cmd_compare() { local branches=() load_branches branches [ ${#branches[@]} -lt 2 ] && { warn "Need 2+ branches (found ${#branches[@]})"; return; } - echo -e " ${C_BOLD}Branches:${C_RESET}" + echo -e " ${C_BOLD}$(_t "Branches:")${C_RESET}" local i=1 for b in "${branches[@]}"; do echo -e " ${C_GREEN}${C_BOLD}$i)${C_RESET} $b"; i=$((i+1)); done - echo -en "\n Branch A: "; local ba; read -rt 30 ba - echo -en " Branch B: "; local bb; read -rt 30 bb + echo -en "\n $(_t "Branch A:") "; local ba; read -rt 30 ba + echo -en " $(_t "Branch B:") "; local bb; read -rt 30 bb [[ "$ba" =~ ^[0-9]+$ ]] && [[ "$bb" =~ ^[0-9]+$ ]] && [ "$ba" -ge 1 ] && [ "$bb" -ge 1 ] && [ "$ba" -le ${#branches[@]} ] && [ "$bb" -le ${#branches[@]} ] || { warn "Invalid"; return; } local bA="${branches[$((ba-1))]}" bB="${branches[$((bb-1))]}" echo "" @@ -1059,7 +1673,7 @@ cmd_compare() { if git rev-parse --verify "$bA" &>/dev/null && git rev-parse --verify "$bB" &>/dev/null; then local ahead=$(git rev-list --count "$bB".."$bA" 2>/dev/null || echo "0") local behind=$(git rev-list --count "$bA".."$bB" 2>/dev/null || echo "0") - echo -e " $bA is ${C_GREEN}$ahead${C_RESET} ahead, ${C_YELLOW}$behind${C_RESET} behind $bB" + echo -e " $bA $(_t "is") ${C_GREEN}$ahead${C_RESET} $(_t "ahead,") ${C_YELLOW}$behind${C_RESET} $(_t "behind") $bB" fi done; echo "" } @@ -1071,17 +1685,17 @@ cmd_schedule() { step 1 1 "Cron Scheduler" echo "" local cc=$(crontab -l 2>/dev/null | grep -F "$SCRIPT_NAME" || echo "") - echo -e " ${C_BOLD}Current:${C_RESET} ${cc:-${C_DIM}none${C_RESET}}" + echo -e " ${C_BOLD}$(_t "Current:")${C_RESET} ${cc:-${C_DIM}$(_t "none")${C_RESET}}" echo "" - echo -e " ${C_BOLD}1)${C_RESET} Daily 03:00 ${C_BOLD}2)${C_RESET} Daily 04:00 ${C_BOLD}3)${C_RESET} Weekly Sun 03:00" - echo -e " ${C_BOLD}4)${C_RESET} Custom time ${C_BOLD}5)${C_RESET} Remove ${C_BOLD}0)${C_RESET} Return" - echo -en "\n Select: "; local c; read -rt 30 c + echo -e " ${C_BOLD}1)${C_RESET} $(_t "Daily 03:00") ${C_BOLD}2)${C_RESET} $(_t "Daily 04:00") ${C_BOLD}3)${C_RESET} $(_t "Weekly Sun 03:00")" + echo -e " ${C_BOLD}4)${C_RESET} $(_t "Custom time") ${C_BOLD}5)${C_RESET} $(_t "Remove") ${C_BOLD}0)${C_RESET} $(_t "Return")" + echo -en "\n $(_t "Select:") "; local c; read -rt 30 c case "$c" in 1) (crontab -l 2>/dev/null | grep -vF "$SCRIPT_NAME"; echo "0 3 * * * cd $SCRIPT_DIR && ./$SCRIPT_NAME update --branch $NITRO_BRANCH >> /var/log/nitro-cron.log 2>&1") | crontab - && ok "Scheduled daily 03:00" ;; 2) (crontab -l 2>/dev/null | grep -vF "$SCRIPT_NAME"; echo "0 4 * * * cd $SCRIPT_DIR && ./$SCRIPT_NAME update --branch $NITRO_BRANCH >> /var/log/nitro-cron.log 2>&1") | crontab - && ok "Scheduled daily 04:00" ;; 3) (crontab -l 2>/dev/null | grep -vF "$SCRIPT_NAME"; echo "0 3 * * 0 cd $SCRIPT_DIR && ./$SCRIPT_NAME update --branch $NITRO_BRANCH >> /var/log/nitro-cron.log 2>&1") | crontab - && ok "Scheduled weekly" ;; - 4) echo -en " Minute [0-59]: "; local m; read -rt 30 m - echo -en " Hour [0-23]: "; local h; read -rt 30 h + 4) echo -en " $(_t "Minute") [0-59]: "; local m; read -rt 30 m + echo -en " $(_t "Hour") [0-23]: "; local h; read -rt 30 h (crontab -l 2>/dev/null | grep -vF "$SCRIPT_NAME"; echo "$m $h * * * cd $SCRIPT_DIR && ./$SCRIPT_NAME update --branch $NITRO_BRANCH >> /var/log/nitro-cron.log 2>&1") | crontab - && ok "Scheduled $m $h * * *" ;; 5) crontab -l 2>/dev/null | grep -vF "$SCRIPT_NAME" | crontab - && ok "Removed" ;; esac @@ -1121,7 +1735,7 @@ pick_branch_and_update() { local branches=() load_branches branches echo "" - echo -e " ${C_BOLD}${C_CYAN}Update: ${C_GREEN}$mode_label${C_RESET}" + echo -e " ${C_BOLD}${C_CYAN}$(_t "Update:") ${C_GREEN}$mode_label${C_RESET}" echo "" local i=1 for b in "${branches[@]}"; do @@ -1129,17 +1743,17 @@ pick_branch_and_update() { echo -e " ${C_GREEN}${C_BOLD}$i)${C_RESET} ${C_CYAN}$b${C_RESET}$m" i=$((i+1)) done - echo -e " ${C_GREEN}${C_BOLD}$i)${C_RESET} Custom" - echo -en "\n Branch [1-$i]: " + echo -e " ${C_GREEN}${C_BOLD}$i)${C_RESET} $(_t "Custom")" + echo -en "\n $(_t "Branch") [1-$i]: " local bc; read -rt 30 bc if [[ "$bc" =~ ^[0-9]+$ ]] && [ "$bc" -ge 1 ] && [ "$bc" -lt "$i" ]; then NITRO_BRANCH="${branches[$((bc-1))]}" elif [ "$bc" = "$i" ]; then - echo -en " Name: "; read -rt 30 NITRO_BRANCH; [ -z "$NITRO_BRANCH" ] && NITRO_BRANCH="main" + echo -en " $(_t "Name:") "; read -rt 30 NITRO_BRANCH; [ -z "$NITRO_BRANCH" ] && NITRO_BRANCH="main" else - warn "Invalid, using: $NITRO_BRANCH" + warn "Invalid, using: %s" "$NITRO_BRANCH" fi - echo -e "\n Branch: ${C_CYAN}${C_BOLD}$NITRO_BRANCH${C_RESET} Mode: ${C_GREEN}$mode_label${C_RESET}" + echo -e "\n $(_t "Branch:") ${C_CYAN}${C_BOLD}$NITRO_BRANCH${C_RESET} $(_t "Mode:") ${C_GREEN}$mode_label${C_RESET}" if ! confirm "Start update?"; then info "Cancelled"; return; fi cmd_update } @@ -1164,39 +1778,39 @@ cmd_interactive() { echo -e " ║ ${C_GOLD}${C_BOLD} SMaRT v${SCRIPT_VERSION} — Emulator / Nitro-V3 / Nitro-V3-Render${C_CYAN} ║" echo -e " ║ ${C_WHITE}${C_BOLD} Updater & Manager by Remco — epicnabbo.nl${C_CYAN} ║" echo " ╠═══════════════════════════════════════════════════════════════════════════╣" - echo -e " ║ ${C_DIM}Branch: ${C_CYAN}${NITRO_BRANCH}${C_DIM} (${#branches[@]} branches) │ $(date '+%H:%M')${C_CYAN} ║" + echo -e " ║ ${C_DIM}$(_t "Branch:") ${C_CYAN}${NITRO_BRANCH}${C_DIM} (${#branches[@]} $(_t "branches")) │ $(date '+%H:%M')${C_CYAN} ║" echo " ╚═══════════════════════════════════════════════════════════════════════════╝" echo -e "${C_RESET}" - echo -e " ${C_BG_GREEN}${C_WHITE}${C_BOLD} UPDATE ${C_RESET}" - echo -e " ${C_GREEN}${C_BOLD}1)${C_RESET} ${E_ROCKET} Quick Update — current branch" - echo -e " ${C_GREEN}${C_BOLD}2)${C_RESET} ${E_BOLT} Full Update (choose branch)" - echo -e " ${C_GREEN}${C_BOLD}3)${C_RESET} ${E_GEAR} Emulator Only" - echo -e " ${C_GREEN}${C_BOLD}4)${C_RESET} ${E_GEAR} Nitro-V3 Client Only" - echo -e " ${C_GREEN}${C_BOLD}5)${C_RESET} ${E_GEAR} Renderer Only" - echo -e " ${C_GREEN}${C_BOLD}6)${C_RESET} ${E_GEAR} Configs Only" - echo -e " ${C_GREEN}${C_BOLD}19)${C_RESET} ${E_BOLT} Dev Mode (skip builds, only configs)" + echo -e " ${C_BG_GREEN}${C_WHITE}${C_BOLD} $(_t "UPDATE") ${C_RESET}" + echo -e " ${C_GREEN}${C_BOLD}1)${C_RESET} ${E_ROCKET} $(_t "Quick Update — current branch")" + echo -e " ${C_GREEN}${C_BOLD}2)${C_RESET} ${E_BOLT} $(_t "Full Update (choose branch)")" + echo -e " ${C_GREEN}${C_BOLD}3)${C_RESET} ${E_GEAR} $(_t "Emulator Only")" + echo -e " ${C_GREEN}${C_BOLD}4)${C_RESET} ${E_GEAR} $(_t "Nitro-V3 Client Only")" + echo -e " ${C_GREEN}${C_BOLD}5)${C_RESET} ${E_GEAR} $(_t "Renderer Only")" + echo -e " ${C_GREEN}${C_BOLD}6)${C_RESET} ${E_GEAR} $(_t "Configs Only")" + echo -e " ${C_GREEN}${C_BOLD}19)${C_RESET} ${E_BOLT} $(_t "Dev Mode (skip builds, only configs)")" echo "" - echo -e " ${C_BG_MAGENTA}${C_WHITE}${C_BOLD} TOOLS ${C_RESET}" - echo -e " ${C_MAGENTA}${C_BOLD}7)${C_RESET} ${E_GIT} Switch Branch" - echo -e " ${C_YELLOW}${C_BOLD}8)${C_RESET} ${E_DB} Database" - echo -e " ${C_YELLOW}${C_BOLD}9)${C_RESET} ${E_SHIELD} Backup / Restore" - echo -e " ${C_YELLOW}${C_BOLD}10)${C_RESET} ${E_WRENCH} Services" - echo -e " ${C_YELLOW}${C_BOLD}11)${C_RESET} ${E_CHART} Status" - echo -e " ${C_YELLOW}${C_BOLD}12)${C_RESET} ${E_HEART} Health Check" - echo -e " ${C_YELLOW}${C_BOLD}13)${C_RESET} ${E_BROOM} Clean" - echo -e " ${C_YELLOW}${C_BOLD}14)${C_RESET} ${E_EYE} Logs" - echo -e " ${C_YELLOW}${C_BOLD}15)${C_RESET} ${E_GEAR} Config" + echo -e " ${C_BG_MAGENTA}${C_WHITE}${C_BOLD} $(_t "TOOLS") ${C_RESET}" + echo -e " ${C_MAGENTA}${C_BOLD}7)${C_RESET} ${E_GIT} $(_t "Switch Branch")" + echo -e " ${C_YELLOW}${C_BOLD}8)${C_RESET} ${E_DB} $(_t "Database")" + echo -e " ${C_YELLOW}${C_BOLD}9)${C_RESET} ${E_SHIELD} $(_t "Backup / Restore")" + echo -e " ${C_YELLOW}${C_BOLD}10)${C_RESET} ${E_WRENCH} $(_t "Services")" + echo -e " ${C_YELLOW}${C_BOLD}11)${C_RESET} ${E_CHART} $(_t "Status")" + echo -e " ${C_YELLOW}${C_BOLD}12)${C_RESET} ${E_HEART} $(_t "Health Check")" + echo -e " ${C_YELLOW}${C_BOLD}13)${C_RESET} ${E_BROOM} $(_t "Clean")" + echo -e " ${C_YELLOW}${C_BOLD}14)${C_RESET} ${E_EYE} $(_t "Logs")" + echo -e " ${C_YELLOW}${C_BOLD}15)${C_RESET} ${E_GEAR} $(_t "Config")" echo "" - echo -e " ${C_BG_BLUE}${C_WHITE}${C_BOLD} ADVANCED ${C_RESET}" - echo -e " ${C_BLUE}${C_BOLD}16)${C_RESET} ${E_CONSOLE} Git Log" - echo -e " ${C_BLUE}${C_BOLD}17)${C_RESET} ${E_GLOBE} Compare Branches" - echo -e " ${C_BLUE}${C_BOLD}18)${C_RESET} ${E_CLOCK} Cron Scheduler" - echo -e " ${C_BLUE}${C_BOLD}20)${C_RESET} ${E_GIT} View Git Stashes" + echo -e " ${C_BG_BLUE}${C_WHITE}${C_BOLD} $(_t "ADVANCED") ${C_RESET}" + echo -e " ${C_BLUE}${C_BOLD}16)${C_RESET} ${E_CONSOLE} $(_t "Git Log")" + echo -e " ${C_BLUE}${C_BOLD}17)${C_RESET} ${E_GLOBE} $(_t "Compare Branches")" + echo -e " ${C_BLUE}${C_BOLD}18)${C_RESET} ${E_CLOCK} $(_t "Cron Scheduler")" + echo -e " ${C_BLUE}${C_BOLD}20)${C_RESET} ${E_GIT} $(_t "View Git Stashes")" echo "" - echo -e " ${C_RED}${C_BOLD}0)${C_RESET} Exit" + echo -e " ${C_RED}${C_BOLD}0)${C_RESET} $(_t "Exit")" echo "" - echo -en " ${C_CYAN}${C_BOLD}Select [0-20]${C_RESET}: " + echo -en " ${C_CYAN}${C_BOLD}$(_t "Select [0-20]")${C_RESET}: " local choice; read -rt 30 choice case "$choice" in @@ -1213,14 +1827,14 @@ cmd_interactive() { local m=""; [ "$b" = "$NITRO_BRANCH" ] && m=" ${C_GREEN}*${C_RESET}" echo -e " ${C_GREEN}${C_BOLD}$i)${C_RESET} $b$m"; i=$((i+1)) done - echo -e " ${C_GREEN}${C_BOLD}$i)${C_RESET} Custom" - echo -en "\n Branch [1-$i]: "; local bc; read -rt 30 bc + echo -e " ${C_GREEN}${C_BOLD}$i)${C_RESET} $(_t "Custom")" + echo -en "\n $(_t "Branch") [1-$i]: "; local bc; read -rt 30 bc if [[ "$bc" =~ ^[0-9]+$ ]] && [ "$bc" -ge 1 ] && [ "$bc" -lt "$i" ]; then NITRO_BRANCH="${branches[$((bc-1))]}" - elif [ "$bc" = "$i" ]; then echo -en " Name: "; read -rt 30 NITRO_BRANCH + elif [ "$bc" = "$i" ]; then echo -en " $(_t "Name:") "; read -rt 30 NITRO_BRANCH fi load_branches branches - ok "Branch: $NITRO_BRANCH" ;; + ok "Branch: %s" "$NITRO_BRANCH" ;; 8) (cmd_database) ;; 9) (cmd_backup); echo ""; (cmd_backups) ;; 10) (cmd_services) ;; @@ -1234,12 +1848,12 @@ cmd_interactive() { 18) (cmd_schedule) ;; 19) SELECTIVE_UPDATE="dev"; (pick_branch_and_update) || warn "Dev mode had errors" ;; 20) (cmd_stash) ;; - 0|q|Q) echo -e "\n ${C_GREEN}Goodbye!${C_RESET}"; cursor_show; exit 0 ;; + 0|q|Q) echo -e "\n ${C_GREEN}$(_t "Goodbye!")${C_RESET}"; cursor_show; exit 0 ;; *) warn "Invalid selection" ;; esac echo "" - echo -en " ${C_DIM}Press Enter to continue...${C_RESET}" + echo -en " ${C_DIM}$(_t "Press Enter to continue...")${C_RESET}" read -rt 30 done } @@ -1249,36 +1863,36 @@ cmd_interactive() { # ============================================================================= show_help() { echo "" - echo -e " ${C_GOLD}${C_BOLD}SMaRT — Emulator / Nitro-V3 / Nitro-V3-Render Updater & Manager${C_RESET}" + echo -e " ${C_GOLD}${C_BOLD}$(_t "SMaRT — Emulator / Nitro-V3 / Nitro-V3-Render Updater & Manager")${C_RESET}" echo -e " ${C_DIM}by Remco — epicnabbo.nl v${SCRIPT_VERSION} (build ${SCRIPT_BUILD})${C_RESET}" echo "" - echo -e " ${C_BOLD}USAGE:${C_RESET} $SCRIPT_NAME [options]" + echo -e " ${C_BOLD}$(_t "USAGE:")${C_RESET} $SCRIPT_NAME [options]" echo "" - echo -e " ${C_BOLD}COMMANDS:${C_RESET}" - echo -e " ${C_GREEN}interactive${C_RESET} Open menu (default)" - echo -e " ${C_GREEN}update${C_RESET} Run update" - echo -e " ${C_GREEN}backup${C_RESET} Create database backup" - echo -e " ${C_GREEN}restore${C_RESET} Restore from backup" - echo -e " ${C_GREEN}backups${C_RESET} List backups" - echo -e " ${C_GREEN}status${C_RESET} System dashboard" - echo -e " ${C_GREEN}health${C_RESET} Health check" - echo -e " ${C_GREEN}services${C_RESET} Service manager" - echo -e " ${C_GREEN}database${C_RESET} Database tools" - echo -e " ${C_GREEN}config${C_RESET} Show config" - echo -e " ${C_GREEN}logs${C_RESET} View logs" - echo -e " ${C_GREEN}clean${C_RESET} Cache cleanup" - echo -e " ${C_GREEN}gitlog${C_RESET} Git history" - echo -e " ${C_GREEN}compare${C_RESET} Branch diff" - echo -e " ${C_GREEN}schedule${C_RESET} Cron setup" - echo -e " ${C_GREEN}stash${C_RESET} View git stashes" + echo -e " ${C_BOLD}$(_t "COMMANDS:")${C_RESET}" + echo -e " ${C_GREEN}interactive${C_RESET} $(_t "Open menu (default)")" + echo -e " ${C_GREEN}update${C_RESET} $(_t "Run update")" + echo -e " ${C_GREEN}backup${C_RESET} $(_t "Create database backup")" + echo -e " ${C_GREEN}restore${C_RESET} $(_t "Restore from backup")" + echo -e " ${C_GREEN}backups${C_RESET} $(_t "List backups")" + echo -e " ${C_GREEN}status${C_RESET} $(_t "System dashboard")" + echo -e " ${C_GREEN}health${C_RESET} $(_t "Health check")" + echo -e " ${C_GREEN}services${C_RESET} $(_t "Service manager")" + echo -e " ${C_GREEN}database${C_RESET} $(_t "Database tools")" + echo -e " ${C_GREEN}config${C_RESET} $(_t "Show config")" + echo -e " ${C_GREEN}logs${C_RESET} $(_t "View logs")" + echo -e " ${C_GREEN}clean${C_RESET} $(_t "Cache cleanup")" + echo -e " ${C_GREEN}gitlog${C_RESET} $(_t "Git history")" + echo -e " ${C_GREEN}compare${C_RESET} $(_t "Branch diff")" + echo -e " ${C_GREEN}schedule${C_RESET} $(_t "Cron setup")" + echo -e " ${C_GREEN}stash${C_RESET} $(_t "View git stashes")" echo "" - echo -e " ${C_BOLD}OPTIONS:${C_RESET}" - echo -e " ${C_CYAN}--branch, -b${C_RESET} Branch (auto-detects)" - echo -e " ${C_CYAN}--url, -u${C_RESET} Site URL" - echo -e " ${C_CYAN}--only=${C_RESET} emulator|client|renderer|configs|dev" - echo -e " ${C_CYAN}--dry-run, -n${C_RESET} Preview only (no changes)" - echo -e " ${C_CYAN}--help, -h${C_RESET} Show this help" - echo -e " ${C_CYAN}--version, -V${C_RESET} Show version" + echo -e " ${C_BOLD}$(_t "OPTIONS:")${C_RESET}" + echo -e " ${C_CYAN}--branch, -b${C_RESET} $(_t "Branch (auto-detects)")" + echo -e " ${C_CYAN}--url, -u${C_RESET} $(_t "Site URL")" + echo -e " ${C_CYAN}--only=${C_RESET} $(_t "emulator|client|renderer|configs|dev")" + echo -e " ${C_CYAN}--dry-run, -n${C_RESET} $(_t "Preview only (no changes)")" + echo -e " ${C_CYAN}--help, -h${C_RESET} $(_t "Show this help")" + echo -e " ${C_CYAN}--version, -V${C_RESET} $(_t "Show version")" echo "" } @@ -1286,6 +1900,7 @@ show_help() { # MAIN # ============================================================================= main() { + load_language local cmd="" while [ $# -gt 0 ]; do case "$1" in @@ -1311,7 +1926,7 @@ main() { --url|-u) shift; NITRO_SITE_URL="$1" ;; --only=*) SELECTIVE_UPDATE="${1#*=}" ;; --dry-run|-n) DRY_RUN=true ;; - -*) echo "Unknown: $1"; exit 1 ;; + -*) echo "$(_t "Unknown:") $1"; exit 1 ;; *) [ -z "$cmd" ] && cmd="interactive" ;; esac shift