diff --git a/Application/API/EventAPI.cs b/Application/API/EventAPI.cs index 34c43fe6c..cc8f0a2d0 100644 --- a/Application/API/EventAPI.cs +++ b/Application/API/EventAPI.cs @@ -46,7 +46,7 @@ namespace IW4MAdmin.Application.API FlaggedMessageCount = 0; - E.Owner.Broadcast("If you suspect someone of ^5CHEATING ^7use the ^5!report ^7command").Wait(); + E.Owner.Broadcast(Utilities.CurrentLocalization.LocalizationSet["GLOBAL_REPORT"]).Wait(); Events.Enqueue(new EventInfo( EventInfo.EventType.ALERT, EventInfo.EventVersion.IW4MAdmin, diff --git a/Application/Application.csproj b/Application/Application.csproj index 5ee1fef5e..7522fd4d0 100644 --- a/Application/Application.csproj +++ b/Application/Application.csproj @@ -58,6 +58,9 @@ PreserveNewest + + PreserveNewest + PreserveNewest diff --git a/Application/BuildScripts/PostPublish.bat b/Application/BuildScripts/PostPublish.bat index 8b8f091fc..8c0803d45 100644 --- a/Application/BuildScripts/PostPublish.bat +++ b/Application/BuildScripts/PostPublish.bat @@ -3,6 +3,8 @@ set ProjectDir=%2 set TargetDir=%3 echo Deleting extra language files + +if exist "%SolutionDir%Publish\Windows\en-US\" powershell Remove-Item -Force -Recurse '%SolutionDir%Publish\Windows\en-US' if exist "%SolutionDir%Publish\Windows\de\" powershell Remove-Item -Force -Recurse '%SolutionDir%Publish\Windows\de' if exist "%SolutionDir%Publish\Windows\es\" powershell Remove-Item -Force -Recurse '%SolutionDir%Publish\Windows\es' if exist "%SolutionDir%Publish\Windows\fr\" powershell Remove-Item -Force -Recurse '%SolutionDir%Publish\Windows\fr' @@ -13,6 +15,17 @@ if exist "%SolutionDir%Publish\Windows\ru\" powershell Remove-Item -Force -Recur if exist "%SolutionDir%Publish\Windows\zh-Hans\" powershell Remove-Item -Force -Recurse '%SolutionDir%Publish\Windows\zh-Hans' if exist "%SolutionDir%Publish\Windows\zh-Hant\" powershell Remove-Item -Force -Recurse '%SolutionDir%Publish\Windows\zh-Hant' +if exist "%SolutionDir%Publish\WindowsPrerelease\en-US\" powershell Remove-Item -Force -Recurse '%SolutionDir%Publish\WindowsPrerelease\en-US' +if exist "%SolutionDir%Publish\WindowsPrerelease\de\" powershell Remove-Item -Force -Recurse '%SolutionDir%Publish\WindowsPrerelease\de' +if exist "%SolutionDir%Publish\WindowsPrerelease\es\" powershell Remove-Item -Force -Recurse '%SolutionDir%Publish\WindowsPrerelease\es' +if exist "%SolutionDir%Publish\WindowsPrerelease\fr\" powershell Remove-Item -Force -Recurse '%SolutionDir%Publish\WindowsPrerelease\fr' +if exist "%SolutionDir%Publish\WindowsPrerelease\it\" powershell Remove-Item -Force -Recurse '%SolutionDir%Publish\WindowsPrerelease\it' +if exist "%SolutionDir%Publish\WindowsPrerelease\ja\" powershell Remove-Item -Force -Recurse '%SolutionDir%Publish\WindowsPrerelease\ja' +if exist "%SolutionDir%Publish\WindowsPrerelease\ko\" powershell Remove-Item -Force -Recurse '%SolutionDir%Publish\WindowsPrerelease\ko' +if exist "%SolutionDir%Publish\WindowsPrerelease\ru\" powershell Remove-Item -Force -Recurse '%SolutionDir%Publish\WindowsPrerelease\ru' +if exist "%SolutionDir%Publish\WindowsPrerelease\zh-Hans\" powershell Remove-Item -Force -Recurse '%SolutionDir%Publish\WindowsPrerelease\zh-Hans' +if exist "%SolutionDir%Publish\WindowsPrerelease\zh-Hant\" powershell Remove-Item -Force -Recurse '%SolutionDir%Publish\WindowsPrerelease\zh-Hant' + echo Deleting extra runtime files if exist "%SolutionDir%Publish\Windows\runtimes\linux-arm" powershell Remove-Item -Force -Recurse '%SolutionDir%Publish\Windows\runtimes\linux-arm' if exist "%SolutionDir%Publish\Windows\runtimes\linux-arm64" powershell Remove-Item -Force -Recurse '%SolutionDir%Publish\Windows\runtimes\linux-arm64' @@ -24,6 +37,19 @@ if exist "%SolutionDir%Publish\Windows\runtimes\osx-x64" powershell Remove-Item if exist "%SolutionDir%Publish\Windows\runtimes\win-arm" powershell Remove-Item -Force -Recurse '%SolutionDir%Publish\Windows\runtimes\win-arm' if exist "%SolutionDir%Publish\Windows\runtimes\win-arm64" powershell Remove-Item -Force -Recurse '%SolutionDir%Publish\Windows\runtimes\win-arm64' +if exist "%SolutionDir%Publish\WindowsPrerelease\runtimes\linux-arm" powershell Remove-Item -Force -Recurse '%SolutionDir%Publish\WindowsPrerelease\runtimes\linux-arm' +if exist "%SolutionDir%Publish\WindowsPrerelease\runtimes\linux-arm64" powershell Remove-Item -Force -Recurse '%SolutionDir%Publish\WindowsPrerelease\runtimes\linux-arm64' +if exist "%SolutionDir%Publish\WindowsPrerelease\runtimes\linux-armel" powershell Remove-Item -Force -Recurse '%SolutionDir%Publish\WindowsPrerelease\runtimes\linux-armel' + +if exist "%SolutionDir%Publish\WindowsPrerelease\runtimes\osx" powershell Remove-Item -Force -Recurse '%SolutionDir%Publish\WindowsPrerelease\runtimes\osx' +if exist "%SolutionDir%Publish\WindowsPrerelease\runtimes\osx-x64" powershell Remove-Item -Force -Recurse '%SolutionDir%Publish\WindowsPrerelease\runtimes\osx-x64' + +if exist "%SolutionDir%Publish\WindowsPrerelease\runtimes\win-arm" powershell Remove-Item -Force -Recurse '%SolutionDir%Publish\WindowsPrerelease\runtimes\win-arm' +if exist "%SolutionDir%Publish\WindowsPrerelease\runtimes\win-arm64" powershell Remove-Item -Force -Recurse '%SolutionDir%Publish\WindowsPrerelease\runtimes\win-arm64' + echo Deleting misc files if exist "%SolutionDir%Publish\Windows\web.config" del "%SolutionDir%Publish\Windows\web.config" del "%SolutionDir%Publish\Windows\*pdb" + +if exist "%SolutionDir%Publish\WindowsPrerelease\web.config" del "%SolutionDir%Publish\WindowsPrerelease\web.config" +del "%SolutionDir%Publish\WindowsPrerelease\*pdb" diff --git a/Application/EventParsers/IW4EventParser.cs b/Application/EventParsers/IW4EventParser.cs index d9cccdfa2..3bf836007 100644 --- a/Application/EventParsers/IW4EventParser.cs +++ b/Application/EventParsers/IW4EventParser.cs @@ -75,11 +75,6 @@ namespace Application.EventParsers if (cleanedEventLine.Contains("InitGame")) { string dump = cleanedEventLine.Replace("InitGame: ", ""); - string[] values = dump.Split('\\', StringSplitOptions.RemoveEmptyEntries); - var dict = new Dictionary(); - - for (int i = 0; i < values.Length; i += 2) - dict.Add(values[i], values[i + 1]); return new GameEvent() { @@ -93,8 +88,8 @@ namespace Application.EventParsers { ClientId = 1 }, - Owner = server, - Extra = dict + Owner = server, + Extra = dump.DictionaryFromKeyValue() }; } diff --git a/Application/EventParsers/T6MEventParser.cs b/Application/EventParsers/T6MEventParser.cs index 07b6a4ceb..b26f5985e 100644 --- a/Application/EventParsers/T6MEventParser.cs +++ b/Application/EventParsers/T6MEventParser.cs @@ -73,11 +73,6 @@ namespace Application.EventParsers if (lineSplit[0].Contains("InitGame")) { string dump = cleanedEventLine.Replace("InitGame: ", ""); - string[] values = dump.Split('\\', StringSplitOptions.RemoveEmptyEntries); - var dict = new Dictionary(); - - for (int i = 0; i < values.Length; i += 2) - dict.Add(values[i], values[i + 1]); return new GameEvent() { @@ -92,7 +87,7 @@ namespace Application.EventParsers ClientId = 1 }, Owner = server, - Extra = dict + Extra = dump.DictionaryFromKeyValue() }; } diff --git a/Application/Localization/Configure.cs b/Application/Localization/Configure.cs index 77c7a40cb..78e7c7c64 100644 --- a/Application/Localization/Configure.cs +++ b/Application/Localization/Configure.cs @@ -11,16 +11,17 @@ namespace IW4MAdmin.Application.Localization { public static void Initialize() { - string currentLocal = CultureInfo.CurrentCulture.Name; + string currentLocale = Program.ServerManager.GetApplicationSettings().Configuration().CustomLocale ?? + CultureInfo.CurrentCulture.Name.Substring(0, 2); #if DEBUG // currentLocal = "ru-RU"; #endif - string localizationFile = $"Localization{Path.DirectorySeparatorChar}IW4MAdmin.{currentLocal}.json"; + string localizationFile = $"Localization{Path.DirectorySeparatorChar}IW4MAdmin.{currentLocale}-{currentLocale.ToUpper()}.json"; string localizationContents; if (File.Exists(localizationFile)) { - localizationContents = File.ReadAllText(localizationFile, Encoding.UTF8); + localizationContents = File.ReadAllText(localizationFile, Encoding.UTF8); } else diff --git a/Application/Localization/IW4MAdmin.en-US.json b/Application/Localization/IW4MAdmin.en-US.json index b9ad8c23a..84dd43c9b 100644 --- a/Application/Localization/IW4MAdmin.en-US.json +++ b/Application/Localization/IW4MAdmin.en-US.json @@ -7,6 +7,9 @@ "MANAGER_VERSION_SUCCESS": "IW4MAdmin is up to date", "MANAGER_INIT_FAIL": "Fatal error during initialization", "MANAGER_EXIT": "Press any key to exit...", + "MANAGER_SHUTDOWN_SUCCESS": "Shutdown complete", + "MANAGER_MONITORING_TEXT": "Now monitoring", + "MANAGER_CONNECTION_REST": "Connection has been reestablished with", "SETUP_ENABLE_WEBFRONT": "Enable webfront", "SETUP_ENABLE_MULTIOWN": "Enable multiple owners", "SETUP_ENABLE_STEPPEDPRIV": "Enable stepped privilege hierarchy", @@ -18,11 +21,25 @@ "SETUP_IPHUB_KEY": "Enter iphub.info api key", "SETUP_DISPLAY_DISCORD": "Display discord link on webfront", "SETUP_DISCORD_INVITE": "Enter discord invite link", - "SETUP_SERVER_USET6M": "Use T6M parser", + "SETUP_SERVER_USET6M": "Use Pluto T6 parser", + "SETUP_SERVER_USEIW5M": "Use Pluto IW5 Parser", + "SETUP_SERVER_MANUALLOG": "Enter manual log file path", "SETUP_SERVER_IP": "Enter server IP Address", "SETUP_SERVER_PORT": "Enter server port", "SETUP_SERVER_RCON": "Enter server RCon password", "SETUP_SERVER_SAVE": "Configuration saved, add another", + "SERVER_ERROR_DNE": "does not exist", + "SERVER_ERROR_LOG": "Invalid game log file", + "SERVER_ERROR_COMMAND_INGAME": "An internal error occured while processing your command", + "SERVER_ERROR_COMMAND_LOG": "command generated an error", + "SERVER_ERROR_UNFIXABLE": "Not monitoring server due to uncorrectable errors", + "SERVER_ERROR_DVAR": "Could not get the dvar value for", + "SERVER_ERROR_DVAR_HELP": "ensure the server has a map loaded", + "SERVER_ERROR_PLUGIN": "An error occured loading plugin", + "SERVER_ERROR_ADDPLAYER": "Unable to add player", + "SERVER_ERROR_POLLING": "reducing polling rate", + "SERVER_ERROR_COMMUNICATION": "Could not communicate with", + "SERVER_ERROR_EXCEPTION": "Unexpected exception on", "SERVER_KICK_VPNS_NOTALLOWED": "VPNs are not allowed on this server", "SERVER_KICK_TEXT": "You were kicked", "SERVER_KICK_MINNAME": "Your name must contain at least 3 characters", @@ -36,7 +53,7 @@ "SERVER_BAN_APPEAL": "appeal at", "SERVER_REPORT_COUNT": "There are ^5{0} ^7recent reports", "SERVER_WARNLIMT_REACHED": "Too many warnings", - "SERVER_WARNING": "Warning", + "SERVER_WARNING": "WARNING", "SERVER_WEBSITE_GENERIC": "this server's website", "BROADCAST_ONLINE": "^5IW4MADMIN ^7is now ^2ONLINE", "BROADCAST_OFFLINE": "IW4MAdmin is going offline", @@ -104,6 +121,77 @@ "COMMANDS_PASSWORD_FAIL": "Your password must be at least 5 characters long", "COMMANDS_PASSWORD_SUCCESS": "Your password has been set successfully", "COMMANDS_PING_TARGET": "ping is", - "COMMANDS_PING_SELF": "Your ping is" + "COMMANDS_PING_SELF": "Your ping is", + "COMMANDS_QUIT_DESC": "quit IW4MAdmin", + "COMMANDS_OWNER_DESC": "claim ownership of the server", + "COMMANDS_WARN_DESC": "warn client for infringing rules", + "COMMANDS_WARNCLEAR_DESC": "remove all warnings for a client", + "COMMANDS_KICK_DESC": "kick a client by name", + "COMMANDS_SAY_DESC": "broadcast message to all clients", + "COMMANDS_TEMPBAN_DESC": "temporarily ban a client for specified time (defaults to 1 hour)", + "COMMANDS_BAN_DESC": "permanently ban a client from the server", + "COMMANDS_UNBAN_DESC": "unban client by client id", + "COMMANDS_WHO_DESC": "give information about yourself", + "COMMANDS_LIST_DESC": "list active clients", + "COMMANDS_HELP_DESC": "list all available commands", + "COMMANDS_FASTRESTART_DESC": "fast restart current map", + "COMMANDS_MAPROTATE_DESC": "cycle to the next map in rotation", + "COMMANDS_SETLEVEL_DESC": "set client to specified privilege level", + "COMMANDS_USAGE_DESC": "get application memory usage", + "COMMANDS_USAGE_TEXT": "is using", + "COMMANDS_UPTIME_DESC": "get current application running time", + "COMMANDS_UPTIME_TEXT": "has been online for", + "COMMANDS_ADMINS_DESC": "list currently connected privileged clients", + "COMMANDS_MAP_DESC": "change to specified map", + "COMMANDS_FIND_DESC": "find client in database", + "COMMANDS_RULES_DESC": "list server rules", + "COMMANDS_PM_DESC": "send message to other client", + "COMMANDS_FLAG_DESC": "flag a suspicious client and announce to admins on join", + "COMMANDS_REPORT_DESC": "report a client for suspicious behavior", + "COMMANDS_REPORTS_DESC": "get or clear recent reports", + "COMMANDS_MASK_DESC": "hide your presence as a privileged client", + "COMMANDS_BANINFO_DESC": "get information about a ban for a client", + "COMMANDS_ALIAS_DESC": "get past aliases and ips of a client", + "COMMANDS_RCON_DESC": "send rcon command to server", + "COMMANDS_PLUGINS_DESC": "view all loaded plugins", + "COMMANDS_IP_DESC": "view your external IP address", + "COMMANDS_PRUNE_DESC": "demote any privileged clients that have not connected recently (defaults to 30 days)", + "COMMANDS_SETPASSWORD_DESC": "set your authentication password", + "COMMANDS_PING_DESC": "get client's ping", + "COMMANDS_ARGS_PLAYER": "player", + "COMMANDS_ARGS_REASON": "reason", + "COMMANDS_ARGS_MESSAGE": "message", + "COMMANDS_ARGS_DURATION": "duration (m|h|d|w|y)", + "COMMANDS_ARGS_CLIENTID": "client id", + "COMMANDS_ARGS_COMMANDS": "commands", + "COMMANDS_ARGS_LEVEL": "level", + "COMMANDS_ARGS_MAP": "map", + "COMMANDS_ARGS_CLEAR": "clear", + "COMMANDS_ARGS_INACTIVE": "inactive days", + "COMMANDS_ARGS_PASSWORD": "password", + "PLUGINS_LOGIN_COMMANDS_LOGIN_DESC": "login using password", + "PLUGINS_LOGIN_COMMANDS_LOGIN_SUCCESS": "You are now logged in", + "PLUGINS_LOGIN_COMMANDS_LOGIN_FAIL": "Your password is incorrect", + "PLUGINS_STATS_COMMANDS_RESET_DESC": "reset your stats to factory-new", + "PLUGINS_STATS_COMMANDS_RESET_SUCCESS": "Your stats for this server have been reset", + "PLUGINS_STATS_COMMANDS_RESET_FAIL": "You must be connected to a server to reset your stats", + "PLUGINS_STATS_COMMANDS_VIEW_DESC": "view your stats", + "PLUGINS_STATS_COMMANDS_VIEW_FAIL_INGAME": "The specified player must be ingame", + "PLUGINS_STATS_COMMANDS_VIEW_FAIL_INGAME_SELF": "You must be ingame to view your stats", + "PLUGINS_STATS_COMMANDS_VIEW_FAIL": "Cannot find the player you specified", + "PLUGINS_STATS_COMMANDS_VIEW_SUCCESS": "Stats for", + "PLUGINS_STATS_COMMANDS_TOP_DESC": "view the top 5 players in this server", + "PLUGINS_STATS_COMMANDS_TOP_TEXT": "Top Players", + "PLUGINS_STATS_TEXT_KILLS": "KILLS", + "PLUGINS_STATS_TEXT_DEATHS": "DEATHS", + "PLUGINS_STATS_TEXT_SKILL": "SKILL", + "GLOBAL_DAYS": "days", + "GLOBAL_HOURS": "hours", + "GLOBAL_MINUTES": "minutes", + "GLOBAL_REPORT": "If you suspect someone of ^5CHEATING ^7use the ^5!report ^7command", + "GLOBAL_ERROR": "Error", + "GLOBAL_WARNING": "Warning", + "GLOBAL_INFO": "Info", + "GLOBAL_VERBOSE": "Verbose" } } \ No newline at end of file diff --git a/Application/Localization/IW4MAdmin.es-ES.json b/Application/Localization/IW4MAdmin.es-ES.json new file mode 100644 index 000000000..490a50582 --- /dev/null +++ b/Application/Localization/IW4MAdmin.es-ES.json @@ -0,0 +1,197 @@ +{ + "LocalizationName": "es-ES", + "LocalizationSet": { + "MANAGER_VERSION_FAIL": "No se ha podido conseguir la última versión de IW4MAdmin", + "MANAGER_VERSION_UPDATE": "tiene una actualización. La última versión es", + "MANAGER_VERSION_CURRENT": "Tu versión es", + "MANAGER_VERSION_SUCCESS": "IW4MAdmin está actualizado", + "MANAGER_INIT_FAIL": "Error fatal durante la inicialización", + "MANAGER_EXIT": "Presione cualquier tecla para salir...", + "MANAGER_SHUTDOWN_SUCCESS": "Apagado completo", + "MANAGER_MONITORING_TEXT": "Ahora monitoreando", + "MANAGER_CONNECTION_REST": "La conexión ha sido restablecida con", + "SETUP_ENABLE_WEBFRONT": "Habilitar frente de la web", + "SETUP_ENABLE_MULTIOWN": "Habilitar múltiples propietarios", + "SETUP_ENABLE_STEPPEDPRIV": "Habilitar jerarquía de privilegios por escalones", + "SETUP_ENABLE_CUSTOMSAY": "Habilitar nombre a decir personalizado", + "SETUP_SAY_NAME": "Ingresar nombre a decir personalizado", + "SETUP_USE_CUSTOMENCODING": "Usar analizador de codificación personalizado", + "SETUP_ENCODING_STRING": "Ingresar cadena de codificación", + "SETUP_ENABLE_VPNS": "Habilitar VPNs clientes", + "SETUP_IPHUB_KEY": "Ingresar clave api de iphub.info", + "SETUP_DISPLAY_DISCORD": "Mostrar link de Discord en frente de la web", + "SETUP_DISCORD_INVITE": "Ingresar link de invitación a discord", + "SETUP_SERVER_USET6M": "Usar analizador Pluto T6", + "SETUP_SERVER_USEIW5M": "Usar analizador Pluto IW5", + "SETUP_SERVER_MANUALLOG": "Ingresar manualmente la ruta del archivo de registro", + "SETUP_SERVER_IP": "Ingresar Dirección IP del servidor", + "SETUP_SERVER_PORT": "Ingresar puerto del servidor", + "SETUP_SERVER_RCON": "Ingresar contraseña RCon del servidor", + "SETUP_SERVER_SAVE": "Configuración guardada, añadir otra", + "SERVER_ERROR_DNE": "No existe", + "SERVER_ERROR_LOG": "Archivo de registro del juego invalido", + "SERVER_ERROR_COMMAND_INGAME": "Un error interno ocurrió mientras se procesaba tu comando", + "SERVER_ERROR_COMMAND_LOG": "Comando generó error", + "SERVER_ERROR_UNFIXABLE": "No se está supervisando el servidor debido a errores incorregibles", + "SERVER_ERROR_DVAR": "No se pudo obtener el valor dvar", + "SERVER_ERROR_DVAR_HELP": "asegúrate de que el servidor tenga un mapa cargado", + "SERVER_ERROR_PLUGIN": "Un error ocurrió mientras se cargaba el complemente", + "SERVER_ERROR_ADDPLAYER": "Incapaz de añadir al jugador", + "SERVER_ERROR_POLLING": "reduciendo la tasa de sondeo", + "SERVER_ERROR_COMMUNICATION": "No se ha podido comunicar con", + "SERVER_ERROR_EXCEPTION": "Excepción inesperada en", + "SERVER_KICK_VPNS_NOTALLOWED": "Las VPNs no están permitidas en este servidor", + "SERVER_KICK_TEXT": "Fuiste expulsado", + "SERVER_KICK_MINNAME": "Tu nombre debe contener al menos 3 caracteres", + "SERVER_KICK_NAME_INUSE": "Tu nombre está siendo usado por alguien más", + "SERVER_KICK_GENERICNAME": "Por favor cambia tu nombre usando /name", + "SERVER_KICK_CONTROLCHARS": "Tu nombre no puede contener caracteres de control", + "SERVER_TB_TEXT": "Estás temporalmente baneado", + "SERVER_TB_REMAIN": "Tú estás temporalmente baneado", + "SERVER_BAN_TEXT": "Estás baneado", + "SERVER_BAN_PREV": "Baneado anteriormente por", + "SERVER_BAN_APPEAL": "apela en", + "SERVER_REPORT_COUNT": "Hay ^5{0} ^7reportes recientes", + "SERVER_WARNLIMT_REACHED": "Muchas advertencias", + "SERVER_WARNING": "ADVERTENCIA", + "SERVER_WEBSITE_GENERIC": "el sitio web de este servidor", + "BROADCAST_ONLINE": "^5IW4MADMIN ^7está ahora ^2en línea", + "BROADCAST_OFFLINE": "IW4MAdmin está desconectado", + "COMMAND_HELP_SYNTAX": "sintaxis:", + "COMMAND_HELP_OPTIONAL": "opcional", + "COMMAND_UNKNOWN": "Has ingresado un comando desconocido", + "COMMAND_NOACCESS": "Tú no tienes acceso a ese comando", + "COMMAND_NOTAUTHORIZED": "Tú no estás autorizado para ejecutar ese comando", + "COMMAND_MISSINGARGS": "No se han proporcionado suficientes argumentos", + "COMMAND_TARGET_MULTI": "Múltiples jugadores coinciden con ese nombre", + "COMMAND_TARGET_NOTFOUND": "No se puede encontrar el jugador especificado", + "PLUGIN_IMPORTER_NOTFOUND": "No se encontraron complementos para cargar", + "PLUGIN_IMPORTER_REGISTERCMD": "Comando registrado", + "COMMANDS_OWNER_SUCCESS": "¡Felicidades, has reclamado la propiedad de este servidor!", + "COMMANDS_OWNER_FAIL": "Este servidor ya tiene un propietario", + "COMMANDS_WARN_FAIL": "No tiene los privilegios necesarios para advertir a", + "COMMANDS_WARNCLEAR_SUCCESS": "Todas las advertencias borradas para", + "COMMANDS_KICK_SUCCESS": "ha sido expulsado", + "COMMANDS_KICK_FAIL": "No tienes los privilegios necesarios para expulsar a", + "COMMANDS_TEMPBAN_SUCCESS": "ha sido baneado temporalmente por", + "COMMANDS_TEMPBAN_FAIL": "Tú no puedes banear temporalmente", + "COMMANDS_BAN_SUCCESS": "ha sido baneado permanentemente", + "COMMANDS_BAN_FAIL": "Tú no puedes banear", + "COMMANDS_UNBAN_SUCCESS": "Exitosamente desbaneado", + "COMMANDS_UNBAN_FAIL": "no está baneado", + "COMMANDS_HELP_NOTFOUND": "No se ha podido encontrar ese comando", + "COMMANDS_HELP_MOREINFO": "Escribe !help para obtener la sintaxis de uso del comando", + "COMMANDS_FASTRESTART_UNMASKED": "ha dado rápido reinicio al mapa", + "COMMANDS_FASTRESTART_MASKED": "Al mapa se le ha dado un reinicio rápido", + "COMMANDS_MAPROTATE": "Rotación de mapa en ^55 ^7segundos", + "COMMANDS_SETLEVEL_SELF": "No puedes cambiar tu propio nivel", + "COMMANDS_SETLEVEL_OWNER": "Solo puede haber un propietario. Modifica tu configuración si múltiples propietarios son requeridos", + "COMMANDS_SETLEVEL_STEPPEDDISABLED": "Este servidor no te permite promover", + "COMMANDS_SETLEVEL_LEVELTOOHIGH": "Tú solo puedes promover ^5{0} ^7a ^5{1} ^7o menor privilegio", + "COMMANDS_SETLEVEL_SUCCESS_TARGET": "¡Felicitaciones! has ha sido promovido a", + "COMMANDS_SETLEVEL_SUCCESS": "fue promovido con éxito", + "COMMANDS_SETLEVEL_FAIL": "Grupo inválido especificado", + "COMMANDS_ADMINS_NONE": "No hay administradores visibles en línea", + "COMMANDS_MAP_SUCCESS": "Cambiando al mapa", + "COMMANDS_MAP_UKN": "Intentando cambiar a un mapa desconocido", + "COMMANDS_FIND_MIN": "Por Favor introduzca al menos 3 caracteres", + "COMMANDS_FIND_EMPTY": "No se encontraron jugadores", + "COMMANDS_RULES_NONE": "El propietario del servidor no ha establecido ninguna regla", + "COMMANDS_FLAG_SUCCESS": "Has marcado a", + "COMMANDS_FLAG_UNFLAG": "Has desmarcado a", + "COMMANDS_FLAG_FAIL": "Tú no puedes marcar", + "COMMANDS_REPORT_FAIL_CAMP": "No puedes reportar a un jugador por campear", + "COMMANDS_REPORT_FAIL_DUPLICATE": "Ya has reportado a este jugador", + "COMMANDS_REPORT_FAIL_SELF": "No puedes reportarte a ti mismo", + "COMMANDS_REPORT_FAIL": "Tú no puedes reportar", + "COMMANDS_REPORT_SUCCESS": "Gracias por su reporte, un administrador ha sido notificado", + "COMMANDS_REPORTS_CLEAR_SUCCESS": "Reportes borrados con éxito", + "COMMANDS_REPORTS_NONE": "No hay jugadores reportados aun", + "COMMANDS_MASK_ON": "Ahora estás enmascarado", + "COMMANDS_MASK_OFF": "Ahora estás desenmascarado", + "COMMANDS_BANINFO_NONE": "No se encontró ban activo para ese jugador", + "COMMANDS_BANINO_SUCCESS": "fue baneado por ^5{0} ^7debido a:", + "COMMANDS_ALIAS_ALIASES": "Aliases", + "COMMANDS_ALIAS_IPS": "IPs", + "COMMANDS_RCON_SUCCESS": "Exitosamente enviado el comando RCon", + "COMMANDS_PLUGINS_LOADED": "Complementos cargados", + "COMMANDS_IP_SUCCESS": "Tu IP externa es", + "COMMANDS_PRUNE_FAIL": "Número inválido de días inactivos", + "COMMANDS_PRUNE_SUCCESS": "los usuarios privilegiados inactivos fueron podados", + "COMMANDS_PASSWORD_FAIL": "Tu contraseña debe tener al menos 5 caracteres de largo", + "COMMANDS_PASSWORD_SUCCESS": "Su contraseña ha sido establecida con éxito", + "COMMANDS_PING_TARGET": "ping es", + "COMMANDS_PING_SELF": "Tu ping es", + "COMMANDS_QUIT_DESC": "salir de IW4MAdmin", + "COMMANDS_OWNER_DESC": "reclamar la propiedad del servidor", + "COMMANDS_WARN_DESC": "advertir al cliente por infringir las reglas", + "COMMANDS_WARNCLEAR_DESC": "eliminar todas las advertencias de un cliente", + "COMMANDS_KICK_DESC": "expulsar a un cliente por su nombre", + "COMMANDS_SAY_DESC": "transmitir el mensaje a todos los clientes", + "COMMANDS_TEMPBAN_DESC": "banear temporalmente a un cliente por el tiempo especificado (predeterminado en 1 hora)", + "COMMANDS_BAN_DESC": "banear permanentemente un cliente del servidor", + "COMMANDS_UNBAN_DESC": "desbanear al cliente por ID", + "COMMANDS_WHO_DESC": "da información sobre ti", + "COMMANDS_LIST_DESC": "enlistar clientes activos", + "COMMANDS_HELP_DESC": "enlistar todos los comandos disponibles", + "COMMANDS_FASTRESTART_DESC": "dar reinicio rápido al mapa actial", + "COMMANDS_MAPROTATE_DESC": "pasar al siguiente mapa en rotación", + "COMMANDS_SETLEVEL_DESC": "establecer el cliente al nivel de privilegio especificado", + "COMMANDS_USAGE_DESC": "obtener uso de la memoria de la aplicación", + "COMMANDS_USAGE_TEXT": "está usando", + "COMMANDS_UPTIME_DESC": "obtener el tiempo de ejecución de la aplicación actual", + "COMMANDS_UPTIME_TEXT": "ha estado en línea por", + "COMMANDS_ADMINS_DESC": "enlistar clientes privilegiados actualmente conectados", + "COMMANDS_MAP_DESC": "cambiar al mapa especificado", + "COMMANDS_FIND_DESC": "encontrar cliente en la base de datos", + "COMMANDS_RULES_DESC": "enlistar reglas del servidor", + "COMMANDS_PM_DESC": "enviar mensaje a otro cliente", + "COMMANDS_FLAG_DESC": "marcar un cliente sospechoso y anunciar a los administradores al unirse", + "COMMANDS_REPORT_DESC": "reportar un cliente por comportamiento sospechoso", + "COMMANDS_REPORTS_DESC": "obtener o borrar informes recientes", + "COMMANDS_MASK_DESC": "esconde tu presencia como un cliente privilegiado", + "COMMANDS_BANINFO_DESC": "obtener información sobre el ban de un cliente", + "COMMANDS_ALIAS_DESC": "obtener alias e ips anteriores de un cliente", + "COMMANDS_RCON_DESC": "enviar el comando rcon al servidor", + "COMMANDS_PLUGINS_DESC": "ver todos los complementos cargados", + "COMMANDS_IP_DESC": "ver tu dirección IP externa", + "COMMANDS_PRUNE_DESC": "degradar a los clientes con privilegios que no se hayan conectado recientemente (el valor predeterminado es 30 días)", + "COMMANDS_SETPASSWORD_DESC": "configura tu contraseña de autenticación", + "COMMANDS_PING_DESC": "obtener ping del cliente", + "COMMANDS_ARGS_PLAYER": "jugador", + "COMMANDS_ARGS_REASON": "razón", + "COMMANDS_ARGS_MESSAGE": "mensaje", + "COMMANDS_ARGS_DURATION": "duración (m|h|d|w|y)", + "COMMANDS_ARGS_CLIENTID": "id del cliente", + "COMMANDS_ARGS_COMMANDS": "comandos", + "COMMANDS_ARGS_LEVEL": "nivel", + "COMMANDS_ARGS_MAP": "mapa", + "COMMANDS_ARGS_CLEAR": "borrar", + "COMMANDS_ARGS_INACTIVE": "días inactivo", + "COMMANDS_ARGS_PASSWORD": "contraseña", + "PLUGINS_LOGIN_COMMANDS_LOGIN_DESC": "iniciar sesión usando la contraseña", + "PLUGINS_LOGIN_COMMANDS_LOGIN_SUCCESS": "Ahora está conectado", + "PLUGINS_LOGIN_COMMANDS_LOGIN_FAIL": "tu contraseña es incorrecta", + "PLUGINS_STATS_COMMANDS_RESET_DESC": "restablece tus estadísticas a las nuevas de fábrica", + "PLUGINS_STATS_COMMANDS_RESET_SUCCESS": "Tus estadísticas para este servidor se han restablecido", + "PLUGINS_STATS_COMMANDS_RESET_FAIL": "Debes estar conectado a un servidor para restablecer tus estadísticas", + "PLUGINS_STATS_COMMANDS_VIEW_DESC": "ver tus estadísticas", + "PLUGINS_STATS_COMMANDS_VIEW_FAIL_INGAME": "El jugador especificado debe estar dentro del juego", + "PLUGINS_STATS_COMMANDS_VIEW_FAIL_INGAME_SELF": "Debes estar dentro del juego para ver tus estadísticas", + "PLUGINS_STATS_COMMANDS_VIEW_FAIL": "No se puede encontrar el jugador que especificó", + "PLUGINS_STATS_COMMANDS_VIEW_SUCCESS": "Estadísticas para", + "PLUGINS_STATS_COMMANDS_TOP_DESC": "ver los 5 mejores jugadores en este servidor", + "PLUGINS_STATS_COMMANDS_TOP_TEXT": "Mejores Jugadores", + "PLUGINS_STATS_TEXT_KILLS": "Asesinatos", + "PLUGINS_STATS_TEXT_DEATHS": "Muertes", + "PLUGINS_STATS_TEXT_SKILL": "Habilidad", + "GLOBAL_DAYS": "días", + "GLOBAL_HOURS": "horas", + "GLOBAL_MINUTES": "minutos", + "GLOBAL_REPORT": "Si sospechas que alguien ^5usa cheats ^7usa el comando ^5!report", + "GLOBAL_ERROR": "Error", + "GLOBAL_WARNING": "Advertencia", + "GLOBAL_INFO": "Información", + "GLOBAL_VERBOSE": "Detallado" + } +} \ No newline at end of file diff --git a/Application/Localization/IW4MAdmin.ru-RU.json b/Application/Localization/IW4MAdmin.ru-RU.json index 01b5f9663..da10739e1 100644 --- a/Application/Localization/IW4MAdmin.ru-RU.json +++ b/Application/Localization/IW4MAdmin.ru-RU.json @@ -2,29 +2,31 @@ "LocalizationName": "ru-RU", "LocalizationSet": { "MANAGER_VERSION_FAIL": "Не удалось получить последнюю версию IW4MAdmin", - "MANAGER_VERSION_UPDATE": "имеет обновление. Последняя версия", - "MANAGER_VERSION_CURRENT": "Ваша версия", + "MANAGER_VERSION_UPDATE": "- есть обновление. Последняя версия:", + "MANAGER_VERSION_CURRENT": "Ваша версия:", "MANAGER_VERSION_SUCCESS": "IW4MAdmin обновлен", - "MANAGER_INIT_FAIL": "Неустранимая ошибка при инициализации", - "MANAGER_EXIT": "Нажмите любую клавишу чтобы выйти ...", + "MANAGER_INIT_FAIL": "Критическая ошибка во время инициализации", + "MANAGER_EXIT": "Нажмите любую клавишу, чтобы выйти...", "SETUP_ENABLE_WEBFRONT": "Включить веб-интерфейс", "SETUP_ENABLE_MULTIOWN": "Включить поддержку нескольких владельцев", "SETUP_ENABLE_STEPPEDPRIV": "Включить последовательную иерархию прав", - "SETUP_ENABLE_CUSTOMSAY": "Включить серверное имя для чата", - "SETUP_SAY_NAME": "Введите серверное имя для чата", - "SETUP_USE_CUSTOMENCODING": "Использовать иную кодировку текста", - "SETUP_ENCODING_STRING": "Введите желаемую кодировку", - "SETUP_ENABLE_VPNS": "Разрешить игрокам подключаться с VPN", + "SETUP_ENABLE_CUSTOMSAY": "Включить кастомное имя для чата", + "SETUP_SAY_NAME": "Введите кастомное имя для чата", + "SETUP_USE_CUSTOMENCODING": "Использовать кастомную кодировку парсера", + "SETUP_ENCODING_STRING": "Введите кодировку", + "SETUP_ENABLE_VPNS": "Включить поддержку VPN у игроков", "SETUP_IPHUB_KEY": "Введите iphub.info api-ключ", "SETUP_DISPLAY_DISCORD": "Отображать ссылку на Discord в веб-интерфейсе", "SETUP_DISCORD_INVITE": "Введите ссылку-приглашение в Discord", - "SETUP_SERVER_USET6M": "Использовать T6M парсер для Black Ops 2", + "SETUP_SERVER_USET6M": "Использовать Pluto T6 парсер", + "SETUP_SERVER_USEIW5M": "Использовать парсер Pluto IW5", + "SETUP_SERVER_MANUALLOG": "Введите путь для лог-файла", "SETUP_SERVER_IP": "Введите IP-адрес сервера", - "SETUP_SERVER_PORT": "введите порт сервера", + "SETUP_SERVER_PORT": "Введите порт сервера", "SETUP_SERVER_RCON": "Введите RCon пароль сервера", - "SETUP_SERVER_SAVE": "Конфигурация сохранена, добавить еще?", + "SETUP_SERVER_SAVE": "Настройки сохранены, добавить", "SERVER_KICK_VPNS_NOTALLOWED": "Использование VPN не разрешено на этом сервере", - "SERVER_KICK_TEXT": "Вы исключены", + "SERVER_KICK_TEXT": "Вы были исключены", "SERVER_KICK_MINNAME": "Ваше имя должно содержать хотя бы 3 символа", "SERVER_KICK_NAME_INUSE": "Ваше имя используется кем-то другим", "SERVER_KICK_GENERICNAME": "Пожалуйста, смените ваше имя, используя /name", @@ -36,42 +38,42 @@ "SERVER_BAN_APPEAL": "оспорить:", "SERVER_REPORT_COUNT": "Имеется ^5{0} ^7жалоб за последнее время", "SERVER_WARNLIMT_REACHED": "Слишком много предупреждений", - "SERVER_WARNING": "предупреждение", + "SERVER_WARNING": "Предупреждение", "SERVER_WEBSITE_GENERIC": "веб-сайт этого сервера", - "BROADCAST_ONLINE": "^5IW4MADMIN ^7сейчас ^2ОНЛАЙН", + "BROADCAST_ONLINE": "^5IW4MADMIN ^7сейчас ^В СЕТИ", "BROADCAST_OFFLINE": "IW4MAdmin отключается", "COMMAND_HELP_SYNTAX": "синтаксис:", "COMMAND_HELP_OPTIONAL": "опционально", "COMMAND_UNKNOWN": "Вы ввели неизвестную команду", "COMMAND_NOACCESS": "У вас нет доступа к этой команде", - "COMMAND_NOTAUTHORIZED": "У вас нет разрешения выполнить эту команду", - "COMMAND_MISSINGARGS": "Приведено недостаточно аргументов", - "COMMAND_TARGET_MULTI": "Это имя использует не один игрок", + "COMMAND_NOTAUTHORIZED": "Вы не авторизованы для исполнения этой команды", + "COMMAND_MISSINGARGS": "Недостаточно аргументов приведено", + "COMMAND_TARGET_MULTI": "Несколько игроков соответствуют этому имени", "COMMAND_TARGET_NOTFOUND": "Невозможно найти указанного игрока", - "PLUGIN_IMPORTER_NOTFOUND": "Нет загружаемых плагинов", + "PLUGIN_IMPORTER_NOTFOUND": "Не найдено плагинов для загрузки", "PLUGIN_IMPORTER_REGISTERCMD": "Зарегистрированная команда", - "COMMANDS_OWNER_SUCCESS": "Поздравляем, Вы стали владельцем этого сервера!", + "COMMANDS_OWNER_SUCCESS": "Поздравления, вы утвердили владение этим сервером!", "COMMANDS_OWNER_FAIL": "Этот сервер уже имеет владельца", - "COMMANDS_WARN_FAIL": "У вас недостаточно прав чтобы предупреждать!", + "COMMANDS_WARN_FAIL": "У вас недостаточно прав, чтобы выносить предупреждения", "COMMANDS_WARNCLEAR_SUCCESS": "Все предупреждения очищены за", "COMMANDS_KICK_SUCCESS": "был исключен", - "COMMANDS_KICK_FAIL": "У вас недостаточно прав чтобы исключать!", + "COMMANDS_KICK_FAIL": "У вас нет достаточных прав, чтобы исключать", "COMMANDS_TEMPBAN_SUCCESS": "был временно забанен за", - "COMMANDS_TEMPBAN_FAIL": "Вы не можете временно банить!", + "COMMANDS_TEMPBAN_FAIL": "Вы не можете выдавать временный бан", "COMMANDS_BAN_SUCCESS": "был забанен навсегда", - "COMMANDS_BAN_FAIL": "Вы не можете банить!", + "COMMANDS_BAN_FAIL": "Вы не можете выдавать бан", "COMMANDS_UNBAN_SUCCESS": "Успешно разбанен", "COMMANDS_UNBAN_FAIL": "не забанен", "COMMANDS_HELP_NOTFOUND": "Не удалось найти эту команду", - "COMMANDS_HELP_MOREINFO": "Введите !help <имя команды>, чтобы узнать синтаксис команды", - "COMMANDS_FASTRESTART_UNMASKED": "перезапуск карты", - "COMMANDS_FASTRESTART_MASKED": "Карта перезапущена", + "COMMANDS_HELP_MOREINFO": "Введите !help <имя команды>, чтобы узнать синтаксис для использования команды", + "COMMANDS_FASTRESTART_UNMASKED": "перезапустил карту", + "COMMANDS_FASTRESTART_MASKED": "Карта была перезапущена", "COMMANDS_MAPROTATE": "Смена карты через ^55 ^7секунд", "COMMANDS_SETLEVEL_SELF": "Вы не можете изменить свой уровень", - "COMMANDS_SETLEVEL_OWNER": "Возможен только 1 владелец. Включите возможность нескольких владельцев!", + "COMMANDS_SETLEVEL_OWNER": "Может быть только 1 владелец. Измените настройки, если требуется несколько владельцов", "COMMANDS_SETLEVEL_STEPPEDDISABLED": "Этот сервер не разрешает вам повыситься", "COMMANDS_SETLEVEL_LEVELTOOHIGH": "Вы только можете повысить ^5{0} ^7до ^5{1} ^7или понизиться в правах", - "COMMANDS_SETLEVEL_SUCCESS_TARGET": "Поздравляем! Вы были повышены до", + "COMMANDS_SETLEVEL_SUCCESS_TARGET": "Поздравления! Вы были повышены до", "COMMANDS_SETLEVEL_SUCCESS": "был успешно повышен", "COMMANDS_SETLEVEL_FAIL": "Указана неверная группа", "COMMANDS_ADMINS_NONE": "Нет администраторов в сети", @@ -88,22 +90,108 @@ "COMMANDS_REPORT_FAIL_SELF": "Вы не можете пожаловаться на самого себя", "COMMANDS_REPORT_FAIL": "Вы не можете пожаловаться", "COMMANDS_REPORT_SUCCESS": "Спасибо за вашу жалобу, администратор оповещен", - "COMMANDS_REPORTS_CLEAR_SUCCESS": "Жалобы полностью очищены", + "COMMANDS_REPORTS_CLEAR_SUCCESS": "Жалобы успешно очищены", "COMMANDS_REPORTS_NONE": "Пока нет жалоб на игроков", - "COMMANDS_MASK_ON": "Вы замаскированы", - "COMMANDS_MASK_OFF": "Маскировка снята", - "COMMANDS_BANINFO_NONE": "Нет активного запрета для этого игрока", - "COMMANDS_BANINO_SUCCESS": "был забанен ^5{0} ^7на:", - "COMMANDS_ALIAS_ALIASES": "Псевдонимы", + "COMMANDS_MASK_ON": "Вы теперь замаскированы", + "COMMANDS_MASK_OFF": "Вы теперь демаскированы", + "COMMANDS_BANINFO_NONE": "Не найдено действующего бана для этого игрока", + "COMMANDS_BANINO_SUCCESS": "был забанен игроком ^5{0} ^7на:", + "COMMANDS_ALIAS_ALIASES": "Имена", "COMMANDS_ALIAS_IPS": "IP", - "COMMANDS_RCON_SUCCESS": "​​ RCon команда успешно отправлена", + "COMMANDS_RCON_SUCCESS": "Успешно отправлена команда RCon", "COMMANDS_PLUGINS_LOADED": "Загруженные плагины", - "COMMANDS_IP_SUCCESS": "Ваш внешний IP-адрес", - "COMMANDS_PRUNE_FAIL": "Недопустимое количество неактивных дней", - "COMMANDS_PRUNE_SUCCESS": "неактивные привилегированные пользователи были разжалованы", - "COMMANDS_PASSWORD_FAIL": "Ваш пароль должен содержать не менее 5 символов", - "COMMANDS_PASSWORD_SUCCESS": "Ваш пароль успешно установлен", - "COMMANDS_PING_TARGET": "пинг", - "COMMANDS_PING_SELF": "Ваш пинг" + "COMMANDS_IP_SUCCESS": "Ваш внешний IP:", + "COMMANDS_PRUNE_FAIL": "Неверное количество дней бездействия", + "COMMANDS_PRUNE_SUCCESS": "бездействующих пользователей с правами было сокращено", + "COMMANDS_PASSWORD_FAIL": "Ваш пароль должен быть хотя бы 5 символов в длину", + "COMMANDS_PASSWORD_SUCCESS": "Ваш пароль был успешно установлен", + "COMMANDS_PING_TARGET": "пинг:", + "COMMANDS_PING_SELF": "Ваш пинг:", + "MANAGER_SHUTDOWN_SUCCESS": "Выключение завершено", + "MANAGER_MONITORING_TEXT": "Идет мониторинг", + "MANAGER_CONNECTION_REST": "Соединение было восстановлено с помощью", + "SERVER_ERROR_DNE": "не существует", + "SERVER_ERROR_LOG": "Неверный файл игрового лога", + "SERVER_ERROR_COMMAND_INGAME": "Произошла внутренняя ошибка при обработке вашей команды", + "SERVER_ERROR_COMMAND_LOG": "команда сгенерировала ошибку", + "SERVER_ERROR_UNFIXABLE": "Мониторинг сервера выключен из-за неисправимых ошибок", + "SERVER_ERROR_DVAR": "Не удалось получить значение dvar:", + "SERVER_ERROR_DVAR_HELP": "убедитесь, что на сервере загружена карта", + "SERVER_ERROR_PLUGIN": "Произошла ошибка загрузки плагина", + "SERVER_ERROR_ADDPLAYER": "Не удалось добавить игрока", + "SERVER_ERROR_POLLING": "снижение частоты обновления данных", + "SERVER_ERROR_COMMUNICATION": "Не удалось связаться с", + "SERVER_ERROR_EXCEPTION": "Неожиданное исключение на", + "COMMANDS_QUIT_DESC": "покинуть IW4MAdmin", + "COMMANDS_OWNER_DESC": "утверить владение сервером", + "COMMANDS_WARN_DESC": "предупредить игрока за нарушение правил", + "COMMANDS_WARNCLEAR_DESC": "удалить все предупреждения у игрока", + "COMMANDS_KICK_DESC": "исключить игрока по имени", + "COMMANDS_SAY_DESC": "транслировать сообщения всем игрокам", + "COMMANDS_TEMPBAN_DESC": "временно забанить игрока на определенное время (по умолчанию: 1 час)", + "COMMANDS_BAN_DESC": "навсегда забанить игрока на сервере", + "COMMANDS_UNBAN_DESC": "разбанить игрока по ID игрока", + "COMMANDS_WHO_DESC": "предоставить информацию о себе", + "COMMANDS_LIST_DESC": "перечислить действующих игроков", + "COMMANDS_HELP_DESC": "перечислить все доступные команды", + "COMMANDS_FASTRESTART_DESC": "перезапустить нынешнюю карту", + "COMMANDS_MAPROTATE_DESC": "переключиться на следующую карту в ротации", + "COMMANDS_SETLEVEL_DESC": "установить особый уровень прав игроку", + "COMMANDS_USAGE_DESC": "узнать о потреблении памяти приложением", + "COMMANDS_USAGE_TEXT": "используется", + "COMMANDS_UPTIME_DESC": "получить время с начала запуска текущего приложения", + "COMMANDS_UPTIME_TEXT": "был в сети", + "COMMANDS_ADMINS_DESC": "перечислить присоединенных на данный момент игроков с правами", + "COMMANDS_MAP_DESC": "сменить на определенную карту", + "COMMANDS_FIND_DESC": "найти игрока в базе данных", + "COMMANDS_RULES_DESC": "перечислить правила сервера", + "COMMANDS_PM_DESC": "отправить сообщение другому игроку", + "COMMANDS_FLAG_DESC": "отметить подозрительного игрока и сообщить администраторам, чтобы присоединились", + "COMMANDS_REPORT_DESC": "пожаловаться на игрока за подозрительное поведение", + "COMMANDS_REPORTS_DESC": "получить или очистить последние жалобы", + "COMMANDS_MASK_DESC": "скрыть свое присутствие как игрока с правами", + "COMMANDS_BANINFO_DESC": "получить информацию о бане игрока", + "COMMANDS_ALIAS_DESC": "получить прошлые имена и IP игрока", + "COMMANDS_RCON_DESC": "отправить RCon команду на сервер", + "COMMANDS_PLUGINS_DESC": "просмотреть все загруженные плагины", + "COMMANDS_IP_DESC": "просмотреть ваш внешний IP-адрес", + "COMMANDS_PRUNE_DESC": "понизить любых игроков с правами, которые не подключались за последнее время (по умолчанию: 30 дней)", + "COMMANDS_SETPASSWORD_DESC": "установить свой пароль аутентификации", + "COMMANDS_PING_DESC": "получить пинг игрока", + "COMMANDS_ARGS_PLAYER": "игрок", + "COMMANDS_ARGS_REASON": "причина", + "COMMANDS_ARGS_MESSAGE": "сообщение", + "COMMANDS_ARGS_DURATION": "длительность (m|h|d|w|y)", + "COMMANDS_ARGS_CLIENTID": "ID игрока", + "COMMANDS_ARGS_COMMANDS": "команды", + "COMMANDS_ARGS_LEVEL": "уровень", + "COMMANDS_ARGS_MAP": "карта", + "COMMANDS_ARGS_CLEAR": "очистить", + "COMMANDS_ARGS_INACTIVE": "дни бездействия", + "COMMANDS_ARGS_PASSWORD": "пароль", + "PLUGINS_LOGIN_COMMANDS_LOGIN_DESC": "войти, используя пароль", + "PLUGINS_LOGIN_COMMANDS_LOGIN_SUCCESS": "Вы теперь вошли", + "PLUGINS_LOGIN_COMMANDS_LOGIN_FAIL": "Ваш пароль неверный", + "PLUGINS_STATS_COMMANDS_RESET_DESC": "сбросить вашу статистику под ноль", + "PLUGINS_STATS_COMMANDS_RESET_SUCCESS": "Ваша статистика на этом сервере была сброшена", + "PLUGINS_STATS_COMMANDS_RESET_FAIL": "Вы должны быть подключены к серверу, чтобы сбросить свою статистику", + "PLUGINS_STATS_COMMANDS_VIEW_DESC": "просмотреть свою статистику", + "PLUGINS_STATS_COMMANDS_VIEW_FAIL_INGAME": "Указанный игрок должен быть в игре", + "PLUGINS_STATS_COMMANDS_VIEW_FAIL_INGAME_SELF": "Вы должны быть в игре, чтобы просмотреть свою статистику", + "PLUGINS_STATS_COMMANDS_VIEW_FAIL": "Не удается найти игрока, которого вы указали.", + "PLUGINS_STATS_COMMANDS_VIEW_SUCCESS": "Статистика", + "PLUGINS_STATS_COMMANDS_TOP_DESC": "показать топ-5 лучших игроков на этом сервере", + "PLUGINS_STATS_COMMANDS_TOP_TEXT": "Лучшие игроки", + "PLUGINS_STATS_TEXT_KILLS": "УБИЙСТВ", + "PLUGINS_STATS_TEXT_DEATHS": "СМЕРТЕЙ", + "PLUGINS_STATS_TEXT_SKILL": "МАСТЕРСТВО", + "GLOBAL_DAYS": "дней", + "GLOBAL_HOURS": "часов", + "GLOBAL_MINUTES": "минут", + "GLOBAL_REPORT": "Если вы подозреваете кого-то в ^5ЧИТЕРСТВЕ^7, используйте команду ^5!report", + "GLOBAL_ERROR": "Ошибка", + "GLOBAL_WARNING": "Предупреждение", + "GLOBAL_INFO": "Информация", + "GLOBAL_VERBOSE": "Подробно" } } \ No newline at end of file diff --git a/Application/Logger.cs b/Application/Logger.cs index 88de9b5cb..9f0f1c694 100644 --- a/Application/Logger.cs +++ b/Application/Logger.cs @@ -1,4 +1,6 @@ -using System; +using SharedLibraryCore; +using System; +using System.Collections.Generic; using System.IO; namespace IW4MAdmin.Application @@ -28,7 +30,19 @@ namespace IW4MAdmin.Application void Write(string msg, LogType type) { - string LogLine = $"[{DateTime.Now.ToString("HH:mm:ss")}] - {type}: {msg}"; + string stringType; + + try + { + stringType = Utilities.CurrentLocalization.LocalizationSet[$"GLOBAL_{type.ToString().ToUpper()}"]; + } + + catch(KeyNotFoundException) + { + stringType = type.ToString(); + } + + string LogLine = $"[{DateTime.Now.ToString("HH:mm:ss")}] - {stringType}: {msg}"; lock (ThreadLock) { #if DEBUG diff --git a/Application/Main.cs b/Application/Main.cs index a4209269b..9be847d1b 100644 --- a/Application/Main.cs +++ b/Application/Main.cs @@ -130,7 +130,7 @@ namespace IW4MAdmin.Application } ServerManager.Start(); - ServerManager.Logger.WriteVerbose("Shutdown complete"); + ServerManager.Logger.WriteVerbose(loc["MANAGER_SHUTDOWN_SUCCESS"]); } diff --git a/Application/Manager.cs b/Application/Manager.cs index c42f6ff31..4be917e9b 100644 --- a/Application/Manager.cs +++ b/Application/Manager.cs @@ -184,7 +184,7 @@ namespace IW4MAdmin.Application catch (Exception e) { - Logger.WriteError($"An error occured loading plugin {Plugin.Name}"); + Logger.WriteError($"{Utilities.CurrentLocalization.LocalizationSet["SERVER_ERROR_PLUGIN"]} {Plugin.Name}"); Logger.WriteDebug($"Exception: {e.Message}"); Logger.WriteDebug($"Stack Trace: {e.StackTrace}"); } @@ -226,7 +226,7 @@ namespace IW4MAdmin.Application Commands.Add(new CIP()); Commands.Add(new CMask()); Commands.Add(new CPruneAdmins()); - Commands.Add(new CKillServer()); + //Commands.Add(new CKillServer()); Commands.Add(new CSetPassword()); Commands.Add(new CPing()); @@ -247,7 +247,7 @@ namespace IW4MAdmin.Application _servers.Add(ServerInstance); } - Logger.WriteVerbose($"Now monitoring {ServerInstance.Hostname}"); + Logger.WriteVerbose($"{Utilities.CurrentLocalization.LocalizationSet["MANAGER_MONITORING_TEXT"]} {ServerInstance.Hostname}"); // this way we can keep track of execution time and see if problems arise. var Status = new AsyncStatus(ServerInstance, UPDATE_FREQUENCY); @@ -259,9 +259,9 @@ namespace IW4MAdmin.Application catch (ServerException e) { - Logger.WriteError($"Not monitoring server {Conf.IPAddress}:{Conf.Port} due to uncorrectable errors"); + Logger.WriteError($"{Utilities.CurrentLocalization.LocalizationSet["SERVER_ERROR_UNFIXABLE"]} [{Conf.IPAddress}:{Conf.Port}]"); if (e.GetType() == typeof(DvarException)) - Logger.WriteDebug($"Could not get the dvar value for {(e as DvarException).Data["dvar_name"]} (ensure the server has a map loaded)"); + Logger.WriteDebug($"{Utilities.CurrentLocalization.LocalizationSet["SERVER_ERROR_DVAR"]} {(e as DvarException).Data["dvar_name"]} ({Utilities.CurrentLocalization.LocalizationSet["SERVER_ERROR_DVAR_HELP"]})"); else if (e.GetType() == typeof(NetworkException)) { Logger.WriteDebug(e.Message); diff --git a/Application/RconParsers/IW4RConParser.cs b/Application/RconParsers/IW4RConParser.cs index df7d275eb..ca9caf0af 100644 --- a/Application/RconParsers/IW4RConParser.cs +++ b/Application/RconParsers/IW4RConParser.cs @@ -103,7 +103,7 @@ namespace Application.RconParsers IPAddress = cIP, Ping = Ping, Score = score, - IsBot = npID == -1 + IsBot = npID == 0 }; StatusPlayers.Add(P); } diff --git a/Application/RconParsers/IW5MRConParser.cs b/Application/RconParsers/IW5MRConParser.cs index 31a88fc61..ef5c42d26 100644 --- a/Application/RconParsers/IW5MRConParser.cs +++ b/Application/RconParsers/IW5MRConParser.cs @@ -155,7 +155,7 @@ namespace Application.RconParsers IPAddress = ipAddress, Ping = Ping, Score = score, - IsBot = networkId < 1 + IsBot = networkId == 0 }); } } diff --git a/Application/RconParsers/T6MRConParser.cs b/Application/RconParsers/T6MRConParser.cs index 54204830f..7ef408549 100644 --- a/Application/RconParsers/T6MRConParser.cs +++ b/Application/RconParsers/T6MRConParser.cs @@ -186,7 +186,7 @@ namespace Application.RconParsers IPAddress = ipAddress, Ping = Ping, Score = score, - IsBot = networkId < 1 + IsBot = networkId == 0 }); } } diff --git a/Application/Server.cs b/Application/Server.cs index 3c0d778f3..9f62a9a79 100644 --- a/Application/Server.cs +++ b/Application/Server.cs @@ -195,7 +195,7 @@ namespace IW4MAdmin catch (Exception E) { - Manager.GetLogger().WriteError($"Unable to add player {polledPlayer.Name}::{polledPlayer.NetworkId}"); + Manager.GetLogger().WriteError($"{loc["SERVER_ERROR_ADDPLAYER"]} {polledPlayer.Name}::{polledPlayer.NetworkId}"); Manager.GetLogger().WriteDebug(E.StackTrace); return false; } @@ -466,7 +466,7 @@ namespace IW4MAdmin if (ConnectionErrors > 0) { - Logger.WriteVerbose($"Connection has been reestablished with {IP}:{Port}"); + Logger.WriteVerbose($"{loc["MANAGER_CONNECTION_REST"]} {IP}:{Port}"); Throttled = false; } ConnectionErrors = 0; @@ -479,7 +479,7 @@ namespace IW4MAdmin ConnectionErrors++; if (ConnectionErrors == 1) { - Logger.WriteError($"{e.Message} {IP}:{Port}, reducing polling rate"); + Logger.WriteError($"{e.Message} {IP}:{Port}, {loc["SERVER_ERROR_POLLING"]}"); Logger.WriteDebug($"Internal Exception: {e.Data["internal_exception"]}"); Throttled = true; } @@ -569,7 +569,7 @@ namespace IW4MAdmin //#if !DEBUG catch (NetworkException) { - Logger.WriteError($"Could not communicate with {IP}:{Port}"); + Logger.WriteError($"{loc["SERVER_ERROR_COMMUNICATION"]} {IP}:{Port}"); return false; } @@ -582,7 +582,7 @@ namespace IW4MAdmin catch (Exception E) { - Logger.WriteError($"Encountered error on {IP}:{Port}"); + Logger.WriteError($"{loc["SERVER_ERROR_EXCEPTION"]} {IP}:{Port}"); Logger.WriteDebug("Error Message: " + E.Message); Logger.WriteDebug("Error Trace: " + E.StackTrace); return false; @@ -680,9 +680,9 @@ namespace IW4MAdmin if (!File.Exists(logPath)) { - Logger.WriteError($"Gamelog {logPath} does not exist!"); + Logger.WriteError($"{logPath} {loc["SERVER_ERROR_DNE"]}"); #if !DEBUG - throw new ServerException($"Invalid gamelog file {logPath}"); + throw new ServerException($"{loc["SERVER_ERROR_LOG"]} {logPath}"); #endif } else @@ -796,10 +796,10 @@ namespace IW4MAdmin catch (Exception Except) { - Logger.WriteError(String.Format("A command request \"{0}\" generated an error.", C.Name)); + Logger.WriteError(String.Format($"\"{0}\" {loc["SERVER_ERROR_COMMAND_LOG"]}", C.Name)); Logger.WriteDebug(String.Format("Error Message: {0}", Except.Message)); Logger.WriteDebug(String.Format("Error Trace: {0}", Except.StackTrace)); - await E.Origin.Tell("^1An internal error occured while processing your command^7"); + await E.Origin.Tell($"^1{loc["SERVER_ERROR_COMMAND_INGAME"]}"); #if DEBUG await E.Origin.Tell(Except.Message); #endif @@ -824,12 +824,29 @@ namespace IW4MAdmin { Logger.WriteInfo($"New map loaded - {ClientNum} active players"); - var dict = (Dictionary)E.Extra; - Gametype = dict["g_gametype"].StripColors(); - Hostname = dict["sv_hostname"].StripColors(); + // iw4 doesn't log the game info + if (E.Extra == null) + { + var dict = await this.GetInfoAsync(); + + Gametype = dict["gametype"].StripColors(); + Hostname = dict["hostname"].StripColors(); + + string mapname = dict["mapname"].StripColors(); + CurrentMap = Maps.Find(m => m.Name == mapname) ?? new Map() { Alias = mapname, Name = mapname }; + } + + else + + { + var dict = (Dictionary)E.Extra; + Gametype = dict["g_gametype"].StripColors(); + Hostname = dict["sv_hostname"].StripColors(); + + string mapname = dict["mapname"].StripColors(); + CurrentMap = Maps.Find(m => m.Name == mapname) ?? new Map() { Alias = mapname, Name = mapname }; + } - string mapname = dict["mapname"].StripColors(); - CurrentMap = Maps.Find(m => m.Name == mapname) ?? new Map() { Alias = mapname, Name = mapname }; } if (E.Type == GameEvent.EventType.MapEnd) diff --git a/Master/master/config/master.json b/Master/master/config/master.json index 53bc048de..c23b10ed7 100644 --- a/Master/master/config/master.json +++ b/Master/master/config/master.json @@ -1,4 +1,4 @@ { "current-version-stable": 2.0, - "current-version-prerelease": 2.0 + "current-version-prerelease": 2.1 } \ No newline at end of file diff --git a/Master/master/resources/history_graph.py b/Master/master/resources/history_graph.py index 8bf4e280b..6fc903848 100644 --- a/Master/master/resources/history_graph.py +++ b/Master/master/resources/history_graph.py @@ -11,18 +11,18 @@ class HistoryGraph(Resource): custom_style = Style( background='transparent', plot_background='transparent', - foreground='rgba(109, 118, 126, 0.3)', - foreground_strong='rgba(109, 118, 126, 0.3)', - foreground_subtle='rgba(109, 118, 126, 0.3)', + foreground='#6c757d', + foreground_strong='#6c757d', + foreground_subtle='#6c757d', opacity='0.1', opacity_hover='0.2', - transition='100ms ease-in', - colors=('#007acc', '#749363') + transition='0ms', + colors=('#749363','#007acc'), ) - graph = pygal.StackedLine( + graph = pygal.Line( stroke_style={'width': 0.4}, - show_dots=False, + #show_dots=False, show_legend=False, fill=True, style=custom_style, @@ -36,9 +36,9 @@ class HistoryGraph(Resource): instance_counts = [history['count'] for history in ctx.history.instance_history][-history_count:] client_counts = [history['count'] for history in ctx.history.client_history][-history_count:] - graph.add('Instance Count', instance_counts) graph.add('Client Count', client_counts) - return { 'message' : graph.render(), + graph.add('Instance Count', instance_counts) + return { 'message' : graph.render().replace("Pygal", ""), 'data_points' : len(instance_count), 'instance_count' : 0 if len(instance_counts) is 0 else instance_counts[-1], 'client_count' : 0 if len(client_counts) is 0 else client_counts[-1] diff --git a/Master/master/templates/index.html b/Master/master/templates/index.html index db8d27356..a427f0d75 100644 --- a/Master/master/templates/index.html +++ b/Master/master/templates/index.html @@ -14,42 +14,50 @@ — {{client_count}} clients - +
- +
{% endblock %} {% block scripts %} - - + + {% endblock %} diff --git a/Master/master/templates/layout.html b/Master/master/templates/layout.html index ddc75d238..2526a533a 100644 --- a/Master/master/templates/layout.html +++ b/Master/master/templates/layout.html @@ -14,6 +14,18 @@ .oi:hover { color: #fff !important; } + .dot { + opacity: 0; + padding: 5px; + } + + .dot:hover { + opacity: 1; + } + + .tooltip-box { + fill: #343a40 !important; + } diff --git a/Plugins/Login/Commands/CLogin.cs b/Plugins/Login/Commands/CLogin.cs index 332bbbfc3..61fdbb2a4 100644 --- a/Plugins/Login/Commands/CLogin.cs +++ b/Plugins/Login/Commands/CLogin.cs @@ -8,7 +8,7 @@ namespace IW4MAdmin.Plugins.Login.Commands { public class CLogin : Command { - public CLogin() : base("login", "login using password", "l", Player.Permission.Trusted, false, new CommandArgument[] + public CLogin() : base("login", Utilities.CurrentLocalization.LocalizationSet["PLUGINS_LOGIN_COMMANDS_LOGIN_DESC"], "l", Player.Permission.Trusted, false, new CommandArgument[] { new CommandArgument() { @@ -25,12 +25,12 @@ namespace IW4MAdmin.Plugins.Login.Commands if (hashedPassword[0] == client.Password) { Plugin.AuthorizedClients[E.Origin.ClientId] = true; - await E.Origin.Tell("You are now logged in"); + await E.Origin.Tell(Utilities.CurrentLocalization.LocalizationSet["PLUGINS_LOGIN_COMMANDS_LOGIN_SUCCESS"]); } else { - await E.Origin.Tell("Your password is incorrect"); + await E.Origin.Tell(Utilities.CurrentLocalization.LocalizationSet["PLUGINS_LOGIN_COMMANDS_LOGIN_FAIL"]); } } } diff --git a/Plugins/Stats/Commands/ResetStats.cs b/Plugins/Stats/Commands/ResetStats.cs index 018bd56f1..8ec347ad8 100644 --- a/Plugins/Stats/Commands/ResetStats.cs +++ b/Plugins/Stats/Commands/ResetStats.cs @@ -11,7 +11,7 @@ namespace IW4MAdmin.Plugins.Stats.Commands { public class ResetStats : Command { - public ResetStats() : base("resetstats", "reset your stats to factory-new", "rs", Player.Permission.User, false) { } + public ResetStats() : base("resetstats", Utilities.CurrentLocalization.LocalizationSet["PLUGINS_STATS_COMMANDS_RESET_DESC"], "rs", Player.Permission.User, false) { } public override async Task ExecuteAsync(GameEvent E) { @@ -31,12 +31,12 @@ namespace IW4MAdmin.Plugins.Stats.Commands // fixme: this doesn't work properly when another context exists await svc.SaveChangesAsync(); - await E.Origin.Tell("Your stats for this server have been reset"); + await E.Origin.Tell(Utilities.CurrentLocalization.LocalizationSet["PLUGINS_STATS_COMMANDS_RESET_SUCCESS"]); } else { - await E.Origin.Tell("You must be connected to a server to reset your stats"); + await E.Origin.Tell(Utilities.CurrentLocalization.LocalizationSet["PLUGINS_STATS_COMMANDS_RESET_FAIL"]); } } } diff --git a/Plugins/Stats/Commands/TopStats.cs b/Plugins/Stats/Commands/TopStats.cs index 225b3a475..ef1daf48d 100644 --- a/Plugins/Stats/Commands/TopStats.cs +++ b/Plugins/Stats/Commands/TopStats.cs @@ -12,7 +12,7 @@ namespace IW4MAdmin.Plugins.Stats.Commands { class TopStats : Command { - public TopStats() : base("topstats", "view the top 5 players on this server", "ts", Player.Permission.User, false) { } + public TopStats() : base("topstats", Utilities.CurrentLocalization.LocalizationSet["PLUGINS_STATS_COMMANDS_TOP_DESC"], "ts", Player.Permission.User, false) { } public override async Task ExecuteAsync(GameEvent E) { @@ -43,17 +43,17 @@ namespace IW4MAdmin.Plugins.Stats.Commands if (!E.Message.IsBroadcastCommand()) { - await E.Origin.Tell("^5--Top Players--"); + await E.Origin.Tell($"^5--{Utilities.CurrentLocalization.LocalizationSet["PLUGINS_STATS_COMMANDS_TOP_TEXT"]}--"); foreach (var stat in topStats) - await E.Origin.Tell($"^3{stat.Name}^7 - ^5{stat.KDR} ^7KDR | ^5{stat.Skill} ^7SKILL"); + await E.Origin.Tell($"^3{stat.Name}^7 - ^5{stat.KDR} ^7KDR | ^5{stat.Skill} ^7{Utilities.CurrentLocalization.LocalizationSet["PLUGINS_STATS_TEXT_SKILL"]}"); } else { - await E.Owner.Broadcast("^5--Top Players--"); + await E.Owner.Broadcast($"^5--{Utilities.CurrentLocalization.LocalizationSet["PLUGINS_STATS_COMMANDS_TOP_TEXT"]}--"); foreach (var stat in topStats) - await E.Owner.Broadcast($"^3{stat.Name}^7 - ^5{stat.KDR} ^7KDR | ^5{stat.Skill} ^7SKILL"); + await E.Owner.Broadcast($"^3{stat.Name}^7 - ^5{stat.KDR} ^7KDR | ^5{stat.Skill} ^7{Utilities.CurrentLocalization.LocalizationSet["PLUGINS_STATS_TEXT_SKILL"]}"); } } } diff --git a/Plugins/Stats/Commands/ViewStats.cs b/Plugins/Stats/Commands/ViewStats.cs index 7da9cb60e..8053674b8 100644 --- a/Plugins/Stats/Commands/ViewStats.cs +++ b/Plugins/Stats/Commands/ViewStats.cs @@ -12,7 +12,7 @@ namespace IW4MAdmin.Plugins.Stats.Commands { public class CViewStats : Command { - public CViewStats() : base("stats", "view your stats", "xlrstats", Player.Permission.User, false, new CommandArgument[] + public CViewStats() : base("stats", Utilities.CurrentLocalization.LocalizationSet["PLUGINS_STATS_COMMANDS_VIEW_DESC"], "xlrstats", Player.Permission.User, false, new CommandArgument[] { new CommandArgument() { @@ -24,15 +24,17 @@ namespace IW4MAdmin.Plugins.Stats.Commands public override async Task ExecuteAsync(GameEvent E) { + var loc = Utilities.CurrentLocalization.LocalizationSet; + if (E.Target?.ClientNumber < 0) { - await E.Origin.Tell("The specified player must be ingame"); + await E.Origin.Tell(loc["PLUGINS_STATS_COMMANDS_VIEW_FAIL_INGAME"]); return; } if (E.Origin.ClientNumber < 0 && E.Target == null) { - await E.Origin.Tell("You must be ingame to view your stats"); + await E.Origin.Tell(loc["PLUGINS_STATS_COMMANDS_VIEW_FAIL_INGAME_SELF"]); return; } @@ -41,7 +43,7 @@ namespace IW4MAdmin.Plugins.Stats.Commands if (E.Data.Length > 0 && E.Target == null) { - await E.Origin.Tell("Cannot find the player you specified"); + await E.Origin.Tell(loc["PLUGINS_STATS_COMMANDS_VIEW_FAIL"]); return; } @@ -51,26 +53,26 @@ namespace IW4MAdmin.Plugins.Stats.Commands if (E.Target != null) { pStats = clientStats.Find(c => c.ServerId == serverId && c.ClientId == E.Target.ClientId).First(); - statLine = String.Format("^5{0} ^7KILLS | ^5{1} ^7DEATHS | ^5{2} ^7KDR | ^5{3} ^7SKILL", pStats.Kills, pStats.Deaths, pStats.KDR, pStats.Skill); + statLine = $"^5{pStats.Kills} ^7{loc["PLUGINS_STATS_TEXT_KILLS"]} | ^5{pStats.Deaths} ^7{loc["PLUGINS_STATS_TEXT_DEATHS"]} | ^5{pStats.KDR} ^7KDR | ^5{pStats.Skill} ^7{loc["PLUGINS_STATS_TEXT_SKILL"]}"; } else { pStats = pStats = clientStats.Find(c => c.ServerId == serverId && c.ClientId == E.Origin.ClientId).First(); - statLine = String.Format("^5{0} ^7KILLS | ^5{1} ^7DEATHS | ^5{2} ^7KDR | ^5{3} ^7SKILL", pStats.Kills, pStats.Deaths, pStats.KDR, pStats.Skill); + statLine = $"^5{pStats.Kills} ^7{loc["PLUGINS_STATS_TEXT_KILLS"]} | ^5{pStats.Deaths} ^7{loc["PLUGINS_STATS_TEXT_DEATHS"]} | ^5{pStats.KDR} ^7KDR | ^5{pStats.Skill} ^7{loc["PLUGINS_STATS_TEXT_SKILL"]}"; } if (E.Message.IsBroadcastCommand()) { string name = E.Target == null ? E.Origin.Name : E.Target.Name; - await E.Owner.Broadcast($"Stats for ^5{name}^7"); + await E.Owner.Broadcast($"{loc["PLUGINS_STATS_COMMANDS_VIEW_SUCCESS"]} ^5{name}^7"); await E.Owner.Broadcast(statLine); } else { if (E.Target != null) - await E.Origin.Tell($"Stats for ^5{E.Target.Name}^7"); + await E.Origin.Tell($"{loc["PLUGINS_STATS_COMMANDS_VIEW_SUCCESS"]} ^5{E.Target.Name}^7"); await E.Origin.Tell(statLine); } } diff --git a/README.md b/README.md index dbba21dd0..689c8ef2b 100644 --- a/README.md +++ b/README.md @@ -5,7 +5,7 @@ ### Version 2.1 _______ ### About -**IW4MAdmin** is an administration tool for [IW4x](https://iw4xcachep26muba.onion.link/), [Pluto T6](https://forum.plutonium.pw/category/33/plutonium-t6) [Pluto IW5](https://forum.plutonium.pw/category/5/plutonium-iw5), and most Call of Duty dedicated servers. It allows complete control of your server; from changing maps, to banning players, **IW4MAdmin** monitors and records activity on your server(s). With plugin support, extending its functionality is a breeze. +**IW4MAdmin** is an administration tool for [IW4x](https://iw4xcachep26muba.onion.link/), [Pluto T6](https://forum.plutonium.pw/category/33/plutonium-t6), [Pluto IW5](https://forum.plutonium.pw/category/5/plutonium-iw5), and most Call of Duty dedicated servers. It allows complete control of your server; from changing maps, to banning players, **IW4MAdmin** monitors and records activity on your server(s). With plugin support, extending its functionality is a breeze. ### Setup **IW4MAdmin** requires minimal configuration to run. There is only one prerequisite. diff --git a/SharedLibraryCore/Commands/NativeCommands.cs b/SharedLibraryCore/Commands/NativeCommands.cs index 868f2ec9d..dd1accd45 100644 --- a/SharedLibraryCore/Commands/NativeCommands.cs +++ b/SharedLibraryCore/Commands/NativeCommands.cs @@ -15,7 +15,7 @@ namespace SharedLibraryCore.Commands public class CQuit : Command { public CQuit() : - base("quit", "quit IW4MAdmin", "q", Player.Permission.Owner, false) + base("quit", Utilities.CurrentLocalization.LocalizationSet["COMMANDS_QUIT_DESC"], "q", Player.Permission.Owner, false) { } public override Task ExecuteAsync(GameEvent E) @@ -27,7 +27,7 @@ namespace SharedLibraryCore.Commands public class COwner : Command { public COwner() : - base("owner", "claim ownership of the server", "o", Player.Permission.User, false) + base("owner", Utilities.CurrentLocalization.LocalizationSet["COMMANDS_OWNER_DESC"], "o", Player.Permission.User, false) { } public override async Task ExecuteAsync(GameEvent E) @@ -46,16 +46,16 @@ namespace SharedLibraryCore.Commands public class CWarn : Command { public CWarn() : - base("warn", "warn player for infringing rules", "w", Player.Permission.Trusted, true, new CommandArgument[] + base("warn", Utilities.CurrentLocalization.LocalizationSet["COMMANDS_WARN_DESC"], "w", Player.Permission.Trusted, true, new CommandArgument[] { new CommandArgument() { - Name = "player", + Name = Utilities.CurrentLocalization.LocalizationSet["COMMANDS_ARGS_PLAYER"], Required = true }, new CommandArgument() { - Name = "reason", + Name = Utilities.CurrentLocalization.LocalizationSet["COMMANDS_ARGS_REASON"], Required = true } }) @@ -73,11 +73,11 @@ namespace SharedLibraryCore.Commands public class CWarnClear : Command { public CWarnClear() : - base("warnclear", "remove all warning for a player", "wc", Player.Permission.Trusted, true, new CommandArgument[] + base("warnclear", Utilities.CurrentLocalization.LocalizationSet["COMMANDS_WARNCLEAR_DESC"], "wc", Player.Permission.Trusted, true, new CommandArgument[] { new CommandArgument() { - Name = "player", + Name = Utilities.CurrentLocalization.LocalizationSet["COMMANDS_ARGS_PLAYER"], Required = true } }) @@ -94,17 +94,17 @@ namespace SharedLibraryCore.Commands public class CKick : Command { public CKick() : - base("kick", "kick a player by name", "k", Player.Permission.Trusted, true, new CommandArgument[] + base("kick", Utilities.CurrentLocalization.LocalizationSet["COMMANDS_KICK_DESC"], "k", Player.Permission.Trusted, true, new CommandArgument[] { new CommandArgument() { - Name = "player", + Name = Utilities.CurrentLocalization.LocalizationSet["COMMANDS_ARGS_PLAYER"], Required = true }, new CommandArgument() { - Name = "reason", - Required = true + Name = Utilities.CurrentLocalization.LocalizationSet["COMMANDS_ARGS_REASON"], + Required = true } }) { } @@ -125,11 +125,11 @@ namespace SharedLibraryCore.Commands public class CSay : Command { public CSay() : - base("say", "broadcast message to all players", "s", Player.Permission.Moderator, false, new CommandArgument[] + base("say", Utilities.CurrentLocalization.LocalizationSet["COMMANDS_SAY_DESC"], "s", Player.Permission.Moderator, false, new CommandArgument[] { new CommandArgument() { - Name = "message", + Name = Utilities.CurrentLocalization.LocalizationSet["COMMANDS_ARGS_MESSAGE"], Required = true } }) @@ -144,21 +144,21 @@ namespace SharedLibraryCore.Commands public class CTempBan : Command { public CTempBan() : - base("tempban", "temporarily ban a player for specified time (defaults to 1 hour)", "tb", Player.Permission.Moderator, true, new CommandArgument[] + base("tempban", Utilities.CurrentLocalization.LocalizationSet["COMMANDS_TEMPBAN_DESC"], "tb", Player.Permission.Moderator, true, new CommandArgument[] { new CommandArgument() { - Name = "player", + Name = Utilities.CurrentLocalization.LocalizationSet["COMMANDS_ARGS_PLAYER"], Required = true }, new CommandArgument() { - Name = "duration (m|h|d|w|y)", + Name = Utilities.CurrentLocalization.LocalizationSet["COMMANDS_ARGS_DURATION"], Required = true, }, new CommandArgument() { - Name = "reason", + Name = Utilities.CurrentLocalization.LocalizationSet["COMMANDS_ARGS_REASON"], Required = true } }) @@ -184,16 +184,16 @@ namespace SharedLibraryCore.Commands public class CBan : Command { public CBan() : - base("ban", "permanently ban a player from the server", "b", Player.Permission.SeniorAdmin, true, new CommandArgument[] + base("ban", Utilities.CurrentLocalization.LocalizationSet["COMMANDS_BAN_DESC"], "b", Player.Permission.SeniorAdmin, true, new CommandArgument[] { new CommandArgument() { - Name = "player", + Name = Utilities.CurrentLocalization.LocalizationSet["COMMANDS_ARGS_PLAYER"], Required = true }, new CommandArgument() { - Name = "reason", + Name = Utilities.CurrentLocalization.LocalizationSet["COMMANDS_ARGS_REASON"], Required = true } }) @@ -214,16 +214,16 @@ namespace SharedLibraryCore.Commands public class CUnban : Command { public CUnban() : - base("unban", "unban player by client id", "ub", Player.Permission.SeniorAdmin, true, new CommandArgument[] + base("unban", Utilities.CurrentLocalization.LocalizationSet["COMMANDS_UNBAN_DESC"], "ub", Player.Permission.SeniorAdmin, true, new CommandArgument[] { new CommandArgument() { - Name = "client id", + Name = Utilities.CurrentLocalization.LocalizationSet["COMMANDS_ARGS_CLIENTID"], Required = true, }, new CommandArgument() { - Name = "reason", + Name = Utilities.CurrentLocalization.LocalizationSet["COMMANDS_ARGS_REASON"], Required = true } }) @@ -247,7 +247,7 @@ namespace SharedLibraryCore.Commands public class CWhoAmI : Command { public CWhoAmI() : - base("whoami", "give information about yourself.", "who", Player.Permission.User, false) + base("whoami", Utilities.CurrentLocalization.LocalizationSet["COMMANDS_WHO_DESC"], "who", Player.Permission.User, false) { } public override async Task ExecuteAsync(GameEvent E) @@ -260,7 +260,7 @@ namespace SharedLibraryCore.Commands public class CList : Command { public CList() : - base("list", "list active clients", "l", Player.Permission.Moderator, false) + base("list", Utilities.CurrentLocalization.LocalizationSet["COMMANDS_LIST_DESC"], "l", Player.Permission.Moderator, false) { } public override async Task ExecuteAsync(GameEvent E) @@ -295,11 +295,11 @@ namespace SharedLibraryCore.Commands public class CHelp : Command { public CHelp() : - base("help", "list all available commands", "h", Player.Permission.User, false, new CommandArgument[] + base("help", Utilities.CurrentLocalization.LocalizationSet["COMMANDS_HELP_DESC"], "h", Player.Permission.User, false, new CommandArgument[] { new CommandArgument() { - Name = "command", + Name = Utilities.CurrentLocalization.LocalizationSet["COMMANDS_ARGS_COMMANDS"], Required = false } }) @@ -359,7 +359,7 @@ namespace SharedLibraryCore.Commands public class CFastRestart : Command { public CFastRestart() : - base("fastrestart", "fast restart current map", "fr", Player.Permission.Moderator, false) + base("fastrestart", Utilities.CurrentLocalization.LocalizationSet["COMMANDS_FASTRESTART_DESC"], "fr", Player.Permission.Moderator, false) { } public override async Task ExecuteAsync(GameEvent E) @@ -376,7 +376,7 @@ namespace SharedLibraryCore.Commands public class CMapRotate : Command { public CMapRotate() : - base("maprotate", "cycle to the next map in rotation", "mr", Player.Permission.Administrator, false) + base("maprotate", Utilities.CurrentLocalization.LocalizationSet["COMMANDS_MAPROTATE_DESC"], "mr", Player.Permission.Administrator, false) { } public override async Task ExecuteAsync(GameEvent E) @@ -393,16 +393,16 @@ namespace SharedLibraryCore.Commands public class CSetLevel : Command { public CSetLevel() : - base("setlevel", "set player to specified administration level", "sl", Player.Permission.Moderator, true, new CommandArgument[] + base("setlevel", Utilities.CurrentLocalization.LocalizationSet["COMMANDS_SETLEVEL_DESC"], "sl", Player.Permission.Moderator, true, new CommandArgument[] { new CommandArgument() { - Name = "player", + Name = Utilities.CurrentLocalization.LocalizationSet["COMMANDS_ARGS_PLAYER"], Required = true }, new CommandArgument() { - Name = "level", + Name = Utilities.CurrentLocalization.LocalizationSet["COMMANDS_ARGS_LEVEL"], Required = true } }) @@ -437,7 +437,6 @@ namespace SharedLibraryCore.Commands if (E.Origin.Level < Player.Permission.Owner) { await E.Origin.Tell(string.Format(Utilities.CurrentLocalization.LocalizationSet["COMMANDS_SETLEVEL_LEVELTOOHIGH"], E.Target.Name, (E.Origin.Level - 1).ToString())); - await E.Origin.Tell($"You can only promote ^5{E.Target.Name} ^7to ^5{(E.Origin.Level - 1)} ^7or lower privilege"); return; } } @@ -480,32 +479,33 @@ namespace SharedLibraryCore.Commands public class CUsage : Command { public CUsage() : - base("usage", "get current application memory usage", "us", Player.Permission.Moderator, false) + base("usage", Utilities.CurrentLocalization.LocalizationSet["COMMANDS_USAGE_DESC"], "us", Player.Permission.Moderator, false) { } public override async Task ExecuteAsync(GameEvent E) { - await E.Origin.Tell("IW4M Admin is using " + Math.Round(((System.Diagnostics.Process.GetCurrentProcess().PrivateMemorySize64 / 2048f) / 1200f), 1) + "MB"); + await E.Origin.Tell($"IW4MAdmin {Utilities.CurrentLocalization.LocalizationSet["COMMANDS_USAGE_TEXT"]}" + Math.Round(((System.Diagnostics.Process.GetCurrentProcess().PrivateMemorySize64 / 2048f) / 1200f), 1) + "MB"); } } public class CUptime : Command { public CUptime() : - base("uptime", "get current application running time", "up", Player.Permission.Moderator, false) + base("uptime", Utilities.CurrentLocalization.LocalizationSet["COMMANDS_UPTIME_DESC"], "up", Player.Permission.Moderator, false) { } public override async Task ExecuteAsync(GameEvent E) { TimeSpan uptime = DateTime.Now - System.Diagnostics.Process.GetCurrentProcess().StartTime; - await E.Origin.Tell(String.Format("IW4M Admin has been up for {0} days, {1} hours, and {2} minutes", uptime.Days, uptime.Hours, uptime.Minutes)); + var loc = Utilities.CurrentLocalization.LocalizationSet; + await E.Origin.Tell($"IW4M Admin {loc["COMMANDS_UPTIME_TEXT"]} {uptime.Days} {loc["GLOBAL_DAYS"]}, {uptime.Hours} {loc["GLOBAL_HOURS"]}, {uptime.Minutes} {loc["GLOBAL_MINUTES"]}"); } } public class CListAdmins : Command { public CListAdmins() : - base("admins", "list currently connected admins", "a", Player.Permission.User, false) + base("admins", Utilities.CurrentLocalization.LocalizationSet["COMMANDS_ADMINS_DESC"], "a", Player.Permission.User, false) { } public override async Task ExecuteAsync(GameEvent E) @@ -532,11 +532,11 @@ namespace SharedLibraryCore.Commands public class CLoadMap : Command { public CLoadMap() : - base("map", "change to specified map", "m", Player.Permission.Administrator, false, new CommandArgument[] + base("map", Utilities.CurrentLocalization.LocalizationSet["COMMANDS_MAP_DESC"], "m", Player.Permission.Administrator, false, new CommandArgument[] { new CommandArgument() { - Name = "map", + Name = Utilities.CurrentLocalization.LocalizationSet["COMMANDS_ARGS_MAP"], Required = true } }) @@ -565,11 +565,11 @@ namespace SharedLibraryCore.Commands public class CFindPlayer : Command { public CFindPlayer() : - base("find", "find player in database", "f", Player.Permission.Administrator, false, new CommandArgument[] + base("find", Utilities.CurrentLocalization.LocalizationSet["COMMANDS_FIND_DESC"], "f", Player.Permission.Administrator, false, new CommandArgument[] { new CommandArgument() { - Name = "player", + Name = Utilities.CurrentLocalization.LocalizationSet["COMMANDS_ARGS_PLAYER"], Required = true } }) @@ -608,7 +608,7 @@ namespace SharedLibraryCore.Commands public class CListRules : Command { public CListRules() : - base("rules", "list server rules", "r", Player.Permission.User, false) + base("rules", Utilities.CurrentLocalization.LocalizationSet["COMMANDS_RULES_DESC"], "r", Player.Permission.User, false) { } public override async Task ExecuteAsync(GameEvent E) @@ -643,16 +643,16 @@ namespace SharedLibraryCore.Commands public class CPrivateMessage : Command { public CPrivateMessage() : - base("privatemessage", "send message to other player", "pm", Player.Permission.User, true, new CommandArgument[] + base("privatemessage", Utilities.CurrentLocalization.LocalizationSet["COMMANDS_PM_DESC"], "pm", Player.Permission.User, true, new CommandArgument[] { new CommandArgument() { - Name = "player", + Name = Utilities.CurrentLocalization.LocalizationSet["COMMANDS_ARGS_PLAYER"], Required = true }, new CommandArgument() { - Name = "message", + Name = Utilities.CurrentLocalization.LocalizationSet["COMMANDS_ARGS_MESSAGE"], Required = true } }) @@ -668,16 +668,16 @@ namespace SharedLibraryCore.Commands public class CFlag : Command { public CFlag() : - base("flag", "flag a suspicious player and announce to admins on join", "fp", Player.Permission.Moderator, true, new CommandArgument[] + base("flag", Utilities.CurrentLocalization.LocalizationSet["COMMANDS_FLAG_DESC"], "fp", Player.Permission.Moderator, true, new CommandArgument[] { new CommandArgument() { - Name = "player", + Name = Utilities.CurrentLocalization.LocalizationSet["COMMANDS_ARGS_PLAYER"], Required = true }, new CommandArgument() { - Name = "reason", + Name = Utilities.CurrentLocalization.LocalizationSet["COMMANDS_ARGS_REASON"], Required = true } }) @@ -726,16 +726,16 @@ namespace SharedLibraryCore.Commands public class CReport : Command { public CReport() : - base("report", "report a player for suspicious behavior", "rep", Player.Permission.User, true, new CommandArgument[] + base("report", Utilities.CurrentLocalization.LocalizationSet["COMMANDS_REPORT_DESC"], "rep", Player.Permission.User, true, new CommandArgument[] { new CommandArgument() { - Name = "player", + Name = Utilities.CurrentLocalization.LocalizationSet["COMMANDS_ARGS_PLAYER"], Required = true }, new CommandArgument() { - Name = "reason", + Name = Utilities.CurrentLocalization.LocalizationSet["COMMANDS_ARGS_REASON"], Required = true } }) @@ -778,11 +778,11 @@ namespace SharedLibraryCore.Commands public class CListReports : Command { public CListReports() : - base("reports", "get or clear recent reports", "reps", Player.Permission.Moderator, false, new CommandArgument[] + base("reports", Utilities.CurrentLocalization.LocalizationSet["COMMANDS_REPORTS_DESC"], "reps", Player.Permission.Moderator, false, new CommandArgument[] { new CommandArgument() { - Name = "clear", + Name = Utilities.CurrentLocalization.LocalizationSet["COMMANDS_ARGS_CLEAR"], Required = false } }) @@ -790,7 +790,7 @@ namespace SharedLibraryCore.Commands public override async Task ExecuteAsync(GameEvent E) { - if (E.Data != null && E.Data.ToLower().Contains("clear")) + if (E.Data != null && E.Data.ToLower().Contains(Utilities.CurrentLocalization.LocalizationSet["COMMANDS_ARGS_CLEAR"])) { E.Owner.Reports = new List(); await E.Origin.Tell(Utilities.CurrentLocalization.LocalizationSet["COMMANDS_REPORTS_CLEAR_SUCCESS"]); @@ -811,7 +811,7 @@ namespace SharedLibraryCore.Commands public class CMask : Command { public CMask() : - base("mask", "hide your presence as an administrator", "hide", Player.Permission.Moderator, false) + base("mask", Utilities.CurrentLocalization.LocalizationSet["COMMANDS_MASK_DESC"], "hide", Player.Permission.Moderator, false) { } public override async Task ExecuteAsync(GameEvent E) @@ -834,11 +834,11 @@ namespace SharedLibraryCore.Commands public class CListBanInfo : Command { public CListBanInfo() : - base("baninfo", "get information about a ban for a player", "bi", Player.Permission.Moderator, true, new CommandArgument[] + base("baninfo", Utilities.CurrentLocalization.LocalizationSet["COMMANDS_BANINFO_DESC"], "bi", Player.Permission.Moderator, true, new CommandArgument[] { new CommandArgument() { - Name = "player", + Name = Utilities.CurrentLocalization.LocalizationSet["COMMANDS_ARGS_PLAYER"], Required = true } }) @@ -861,17 +861,17 @@ namespace SharedLibraryCore.Commands await E.Origin.Tell($"^1{E.Target.Name} ^7{string.Format(success, penalty.Punisher.Name)} {penalty.Punisher.Name} {timeRemaining}"); } - + } public class CListAlias : Command { public CListAlias() : - base("alias", "get past aliases and ips of a player", "known", Player.Permission.Moderator, true, new CommandArgument[] + base("alias", Utilities.CurrentLocalization.LocalizationSet["COMMANDS_ALIAS_DESC"], "known", Player.Permission.Moderator, true, new CommandArgument[] { new CommandArgument() { - Name = "player", + Name = Utilities.CurrentLocalization.LocalizationSet["COMMANDS_ARGS_PLAYER"], Required = true, } }) @@ -899,11 +899,11 @@ namespace SharedLibraryCore.Commands public class CExecuteRCON : Command { public CExecuteRCON() : - base("rcon", "send rcon command to server", "rcon", Player.Permission.Owner, false, new CommandArgument[] + base("rcon", Utilities.CurrentLocalization.LocalizationSet["COMMANDS_RCON_DESC"], "rcon", Player.Permission.Owner, false, new CommandArgument[] { new CommandArgument() { - Name = "command", + Name = Utilities.CurrentLocalization.LocalizationSet["COMMANDS_ARGS_COMMANDS"], Required = true } }) @@ -922,12 +922,12 @@ namespace SharedLibraryCore.Commands public class CPlugins : Command { public CPlugins() : - base("plugins", "view all loaded plugins", "p", Player.Permission.Administrator, false) + base("plugins", Utilities.CurrentLocalization.LocalizationSet["COMMANDS_PLUGINS_DESC"], "p", Player.Permission.Administrator, false) { } public override async Task ExecuteAsync(GameEvent E) { - await E.Origin.Tell(Utilities.CurrentLocalization.LocalizationSet["COMMANDS_PLUGINS_LOADE"]); + await E.Origin.Tell(Utilities.CurrentLocalization.LocalizationSet["COMMANDS_PLUGINS_LOADED"]); foreach (var P in Plugins.PluginImporter.ActivePlugins) { await E.Origin.Tell(String.Format("^3{0} ^7[v^3{1}^7] by ^5{2}^7", P.Name, P.Version, P.Author)); @@ -938,7 +938,7 @@ namespace SharedLibraryCore.Commands public class CIP : Command { public CIP() : - base("getexternalip", "view your external IP address", "ip", Player.Permission.User, false) + base("getexternalip", Utilities.CurrentLocalization.LocalizationSet["COMMANDS_IP_DESC"], "ip", Player.Permission.User, false) { } public override async Task ExecuteAsync(GameEvent E) @@ -949,11 +949,11 @@ namespace SharedLibraryCore.Commands public class CPruneAdmins : Command { - public CPruneAdmins() : base("prune", "demote any admins that have not connected recently (defaults to 30 days)", "pa", Player.Permission.Owner, false, new CommandArgument[] + public CPruneAdmins() : base("prune", Utilities.CurrentLocalization.LocalizationSet["COMMANDS_PRUNE_DESC"], "pa", Player.Permission.Owner, false, new CommandArgument[] { new CommandArgument() { - Name = "inactive days", + Name = Utilities.CurrentLocalization.LocalizationSet["COMMANDS_ARGS_INACTIVE"], Required = false } }) @@ -975,7 +975,7 @@ namespace SharedLibraryCore.Commands catch (FormatException) { - await E.Origin.Tell("Invalid number of inactive days"); + await E.Origin.Tell(Utilities.CurrentLocalization.LocalizationSet["COMMANDS_PRUNE_FAIL"]); return; } @@ -999,11 +999,11 @@ namespace SharedLibraryCore.Commands public class CSetPassword : Command { - public CSetPassword() : base("setpassword", "set your authentication password", "sp", Player.Permission.Moderator, false, new CommandArgument[] + public CSetPassword() : base("setpassword", Utilities.CurrentLocalization.LocalizationSet["COMMANDS_SETPASSWORD_DESC"], "sp", Player.Permission.Moderator, false, new CommandArgument[] { new CommandArgument() { - Name = "password", + Name = Utilities.CurrentLocalization.LocalizationSet["COMMANDS_ARGS_PASSWORD"], Required = true } }) @@ -1030,6 +1030,7 @@ namespace SharedLibraryCore.Commands } } + /* public class CKillServer : Command { public CKillServer() : base("killserver", "kill the game server", "kill", Player.Permission.Administrator, false) @@ -1081,19 +1082,20 @@ namespace SharedLibraryCore.Commands } } } - } + }*/ public class CPing : Command { - public CPing() : base("ping", "get client's ping", "pi", Player.Permission.User, false, new CommandArgument[] + public CPing() : base("ping", Utilities.CurrentLocalization.LocalizationSet["COMMANDS_PING_DESC"], "pi", Player.Permission.User, false, new CommandArgument[] { new CommandArgument() { - Name = "client", + Name = Utilities.CurrentLocalization.LocalizationSet["COMMANDS_ARGS_PLAYER"], Required = false } - }){} + }) + { } public override async Task ExecuteAsync(GameEvent E) { diff --git a/SharedLibraryCore/Configuration/ApplicationConfiguration.cs b/SharedLibraryCore/Configuration/ApplicationConfiguration.cs index b697107aa..6114bce2c 100644 --- a/SharedLibraryCore/Configuration/ApplicationConfiguration.cs +++ b/SharedLibraryCore/Configuration/ApplicationConfiguration.cs @@ -18,6 +18,7 @@ namespace SharedLibraryCore.Configuration public string IPHubAPIKey { get; set; } public string WebfrontBindUrl { get; set; } public string CustomParserEncoding { get; set; } + public string CustomLocale { get; set; } public string Id { get; set; } public List Servers { get; set; } public int AutoMessagePeriod { get; set; } diff --git a/SharedLibraryCore/RCon/Connection.cs b/SharedLibraryCore/RCon/Connection.cs index 1644d387b..7059b2e05 100644 --- a/SharedLibraryCore/RCon/Connection.cs +++ b/SharedLibraryCore/RCon/Connection.cs @@ -171,7 +171,6 @@ namespace SharedLibraryCore.RCon OnSent.Reset(); OnReceived.Reset(); - string queryString = ""; byte[] payload = null; switch (type) @@ -186,10 +185,11 @@ namespace SharedLibraryCore.RCon case StaticHelpers.QueryType.GET_STATUS: payload = "ÿÿÿÿgetstatus".Select(Convert.ToByte).ToArray(); break; + case StaticHelpers.QueryType.GET_INFO: + payload = "ÿÿÿÿgetinfo".Select(Convert.ToByte).ToArray(); + break; } - // byte[] payload = Utilities.EncodingType.GetBytes(queryString); // queryString.Select(Convert.ToByte).ToArray(); - retrySend: try { diff --git a/SharedLibraryCore/Utilities.cs b/SharedLibraryCore/Utilities.cs index f051c02c9..70e892631 100644 --- a/SharedLibraryCore/Utilities.cs +++ b/SharedLibraryCore/Utilities.cs @@ -182,8 +182,9 @@ namespace SharedLibraryCore public static long ConvertLong(this string str) { - Int64.TryParse(str, NumberStyles.HexNumber, CultureInfo.InvariantCulture, out long id); - return id; + if (Int64.TryParse(str, NumberStyles.HexNumber, CultureInfo.InvariantCulture, out long id)) + return id; + return 0; } public static int ConvertToIP(this string str) @@ -357,6 +358,22 @@ namespace SharedLibraryCore return pID; } + public static Dictionary DictionaryFromKeyValue(this string eventLine) + { + string[] values = eventLine.Substring(1).Split('\\'); + + Dictionary dict = null; + + if (values.Length % 2 == 0 && values.Length > 1) + { + dict = new Dictionary(); + for (int i = 0; i < values.Length; i += 2) + dict.Add(values[i], values[i + 1]); + } + + return dict; + } + public static Task> GetDvarAsync(this Server server, string dvarName) => server.RconParser.GetDvarAsync(server.RemoteConnection, dvarName); public static Task SetDvarAsync(this Server server, string dvarName, object dvarValue) => server.RconParser.SetDvarAsync(server.RemoteConnection, dvarName, dvarValue); @@ -365,5 +382,11 @@ namespace SharedLibraryCore public static Task> GetStatusAsync(this Server server) => server.RconParser.GetStatusAsync(server.RemoteConnection); + public static async Task> GetInfoAsync(this Server server) + { + var response = await server.RemoteConnection.SendQueryAsync(RCon.StaticHelpers.QueryType.GET_INFO); + return response.FirstOrDefault(r => r[0] == '\\')?.DictionaryFromKeyValue(); + } + } } diff --git a/WebfrontCore/bower.json b/WebfrontCore/bower.json index a9d85da5f..7993c6ff9 100644 --- a/WebfrontCore/bower.json +++ b/WebfrontCore/bower.json @@ -2,14 +2,14 @@ "name": "asp.net", "private": true, "dependencies": { - "bootstrap": "v4.0.0", + "bootstrap": "v4.1.0", "jquery": "3.3.1", "popper.js": "v1.12.9", "open-iconic": "1.1.1", "moment-timezone": "0.5.14" }, "resolutions": { - "bootstrap": "v4.0.0", + "bootstrap": "v4.1.0", "jquery": "3.3.1" } } diff --git a/WebfrontCore/bundleconfig.json b/WebfrontCore/bundleconfig.json index 38588e925..b234f2d48 100644 --- a/WebfrontCore/bundleconfig.json +++ b/WebfrontCore/bundleconfig.json @@ -14,9 +14,9 @@ "outputFileName": "wwwroot/js/global.min.js", "inputFiles": [ "wwwroot/lib/jQuery/dist/jquery.min.js", + "wwwroot/lib/bootstrap/dist/js/bootstrap.min.js", "wwwroot/lib/moment/min/moment.min.js", "wwwroot/lib/moment-timezone/builds/moment-timezone.min.js", - "wwwroot/lib/bootstrap/dist/js/bootstrap.min.js", "wwwroot/js/action.js", "wwwroot/js/console.js", "wwwroot/js/penalty.js", diff --git a/WebfrontCore/wwwroot/lib/bootstrap/scss/_variables.scss b/WebfrontCore/wwwroot/lib/bootstrap/scss/_variables.scss index 98a19807b..23253eb70 100644 --- a/WebfrontCore/wwwroot/lib/bootstrap/scss/_variables.scss +++ b/WebfrontCore/wwwroot/lib/bootstrap/scss/_variables.scss @@ -9,7 +9,7 @@ // // stylelint-disable -$white: #fff !default; +$white: #fff !default; $gray-100: #f8f9fa !default; $gray-200: #e9ecef !default; $gray-300: #dee2e6 !default; @@ -19,73 +19,40 @@ $gray-600: #6c757d !default; $gray-700: #495057 !default; $gray-800: #343a40 !default; $gray-900: #212529 !default; -$black: #000 !default; +$black: #000 !default; $grays: () !default; -$grays: map-merge(( - "100": $gray-100, - "200": $gray-200, - "300": $gray-300, - "400": $gray-400, - "500": $gray-500, - "600": $gray-600, - "700": $gray-700, - "800": $gray-800, - "900": $gray-900 -), $grays); +$grays: map-merge(( "100": $gray-100, "200": $gray-200, "300": $gray-300, "400": $gray-400, "500": $gray-500, "600": $gray-600, "700": $gray-700, "800": $gray-800, "900": $gray-900 ), $grays); -$blue: #007ACC !default; -$indigo: #6610f2 !default; -$purple: #6f42c1 !default; -$pink: #e83e8c !default; -$red: rgba(255, 69, 69, 0.85) !default; -$orange: #fd7e14 !default; -$yellow: #ffc107 !default; -$green: rgba(116,147,99, 1) !default; -$teal: #20c997 !default; -$cyan: #17a2b8 !default; +$blue: #007ACC !default; +$indigo: #6610f2 !default; +$purple: #6f42c1 !default; +$pink: #e83e8c !default; +$red: rgba(255, 69, 69, 0.85) !default; +$orange: #fd7e14 !default; +$yellow: #ffc107 !default; +$green: rgba(116,147,99, 1) !default; +$teal: #20c997 !default; +$cyan: #17a2b8 !default; $colors: () !default; -$colors: map-merge(( - "blue": rgb(0, 122, 204), - "indigo": $indigo, - "purple": $purple, - "pink": $pink, - "red": $red, - "orange": rgb(255, 102, 51), - "yellow": $yellow, - "green": $green, - "teal": $teal, - "cyan": $cyan, - "white": $white, - "gray": $gray-600, - "gray-dark": $gray-800 -), $colors); +$colors: map-merge(( "blue": rgb(0, 122, 204), "indigo": $indigo, "purple": $purple, "pink": $pink, "red": $red, "orange": rgb(255, 102, 51), "yellow": $yellow, "green": $green, "teal": $teal, "cyan": $cyan, "white": $white, "gray": $gray-600, "gray-dark": $gray-800 ), $colors); -$primary: $blue !default; -$secondary: $orange !default; -$success: $green !default; -$info: $cyan !default; -$warning: $yellow !default; -$danger: $red !default; -$light: rgb(204, 204, 204) !default; -$dark: rgb(24, 24, 24) !default; +$primary: $blue !default; +$secondary: $orange !default; +$success: $green !default; +$info: $cyan !default; +$warning: $yellow !default; +$danger: $red !default; +$light: rgb(204, 204, 204) !default; +$dark: rgb(24, 24, 24) !default; $theme-colors: () !default; -$theme-colors: map-merge(( - "primary": $primary, - "secondary": $secondary, - "success": $success, - "info": $info, - "warning": $warning, - "danger": $danger, - "light": $light, - "dark": $dark -), $theme-colors); +$theme-colors: map-merge(( "primary": $primary, "secondary": $secondary, "success": $success, "info": $info, "warning": $warning, "danger": $danger, "light": $light, "dark": $dark ), $theme-colors); // stylelint-enable // Set a specific jump point for requesting color jumps -$theme-color-interval: 8% !default; +$theme-color-interval: 8% !default; // The yiq lightness value that determines when the lightness of color changes from "dark" to "light". Acceptable values are between 0 and 255. $yiq-contrasted-threshold: 150 !default; @@ -98,14 +65,14 @@ $yiq-text-light: $white !default; // // Quickly modify global styling by enabling or disabling optional features. -$enable-caret: true !default; -$enable-rounded: true !default; -$enable-shadows: false !default; -$enable-gradients: false !default; -$enable-transitions: true !default; -$enable-hover-media-query: false !default; // Deprecated, no longer affects any compiled CSS -$enable-grid-classes: true !default; -$enable-print-styles: true !default; +$enable-caret: true !default; +$enable-rounded: true !default; +$enable-shadows: false !default; +$enable-gradients: false !default; +$enable-transitions: true !default; +$enable-hover-media-query: false !default; // Deprecated, no longer affects any compiled CSS +$enable-grid-classes: true !default; +$enable-print-styles: true !default; // Spacing @@ -117,46 +84,34 @@ $enable-print-styles: true !default; // stylelint-disable $spacer: 1rem !default; $spacers: () !default; -$spacers: map-merge(( - 0: 0, - 1: ($spacer * .25), - 2: ($spacer * .5), - 3: $spacer, - 4: ($spacer * 1.5), - 5: ($spacer * 3) -), $spacers); +$spacers: map-merge(( 0: 0, 1: ($spacer * .25), 2: ($spacer * .5), 3: $spacer, 4: ($spacer * 1.5), 5: ($spacer * 3) ), $spacers); // This variable affects the `.h-*` and `.w-*` classes. $sizes: () !default; -$sizes: map-merge(( - 25: 25%, - 50: 50%, - 75: 75%, - 100: 100% -), $sizes); +$sizes: map-merge(( 25: 25%, 50: 50%, 75: 75%, 100: 100% ), $sizes); // stylelint-enable // Body // // Settings for the `` element. -$body-bg: rgb(34,34,34) !default; -$body-color: $white !default; +$body-bg: rgb(34,34,34) !default; +$body-color: $white !default; // Links // // Style anchor elements. -$link-color: $white !default; -$link-decoration: none !default; -$link-hover-color: $primary !default; -$link-hover-decoration: none !default; +$link-color: $white !default; +$link-decoration: none !default; +$link-hover-color: $primary !default; +$link-hover-decoration: none !default; // Paragraphs // // Style p element. -$paragraph-margin-bottom: 1rem !default; +$paragraph-margin-bottom: 1rem !default; // Grid breakpoints @@ -164,13 +119,7 @@ $paragraph-margin-bottom: 1rem !default; // Define the minimum dimensions at which your layout will change, // adapting to different screen sizes, for use in media queries. -$grid-breakpoints: ( - xs: 0, - sm: 576px, - md: 768px, - lg: 992px, - xl: 1200px -) !default; +$grid-breakpoints: ( xs: 0, sm: 576px, md: 768px, lg: 992px, xl: 1200px ) !default; @include _assert-ascending($grid-breakpoints, "$grid-breakpoints"); @include _assert-starts-at-zero($grid-breakpoints); @@ -180,12 +129,7 @@ $grid-breakpoints: ( // // Define the maximum width of `.container` for different screen sizes. -$container-max-widths: ( - sm: 540px, - md: 720px, - lg: 960px, - xl: 1140px -) !default; +$container-max-widths: ( sm: 540px, md: 720px, lg: 960px, xl: 1140px ) !default; @include _assert-ascending($container-max-widths, "$container-max-widths"); @@ -194,31 +138,31 @@ $container-max-widths: ( // // Set the number of columns and specify the width of the gutters. -$grid-columns: 12 !default; -$grid-gutter-width: 30px !default; +$grid-columns: 12 !default; +$grid-gutter-width: 30px !default; // Components // // Define common padding and border radius sizes and more. -$line-height-lg: 1.5 !default; -$line-height-sm: 1.5 !default; +$line-height-lg: 1.5 !default; +$line-height-sm: 1.5 !default; -$border-width: 1px !default; -$border-color: $gray-300 !default; +$border-width: 1px !default; +$border-color: $gray-300 !default; -$border-radius: .25rem !default; -$border-radius-lg: .3rem !default; -$border-radius-sm: .2rem !default; +$border-radius: .25rem !default; +$border-radius-lg: .3rem !default; +$border-radius-sm: .2rem !default; -$component-active-color: $white !default; -$component-active-bg: theme-color("primary") !default; +$component-active-color: $white !default; +$component-active-bg: theme-color("primary") !default; -$caret-width: .3em !default; +$caret-width: .3em !default; -$transition-base: all .2s ease-in-out !default; -$transition-fade: opacity .15s linear !default; -$transition-collapse: height .35s ease !default; +$transition-base: all .2s ease-in-out !default; +$transition-fade: opacity .15s linear !default; +$transition-collapse: height .35s ease !default; // Fonts @@ -226,332 +170,330 @@ $transition-collapse: height .35s ease !default; // Font, line-height, and color for body text, headings, and more. // stylelint-disable value-keyword-case -$font-family-sans-serif: -apple-system, BlinkMacSystemFont, "Open Sans", "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol" !default; -$font-family-monospace: SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace !default; -$font-family-base: $font-family-sans-serif !default; +$font-family-sans-serif: -apple-system, BlinkMacSystemFont, "Open Sans", "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol" !default; +$font-family-monospace: SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace !default; +$font-family-base: $font-family-sans-serif !default; // stylelint-enable value-keyword-case -$font-size-base: 1rem !default; // Assumes the browser default, typically `16px` -$font-size-lg: ($font-size-base * 1.25) !default; -$font-size-sm: ($font-size-base * .875) !default; +$font-size-base: 1rem !default; // Assumes the browser default, typically `16px` +$font-size-lg: ($font-size-base * 1.25) !default; +$font-size-sm: ($font-size-base * .875) !default; -$font-weight-light: 300 !default; -$font-weight-normal: 400 !default; -$font-weight-bold: 700 !default; +$font-weight-light: 300 !default; +$font-weight-normal: 400 !default; +$font-weight-bold: 700 !default; -$font-weight-base: $font-weight-normal !default; -$line-height-base: 1.5 !default; +$font-weight-base: $font-weight-normal !default; +$line-height-base: 1.5 !default; -$h1-font-size: $font-size-base * 2.5 !default; -$h2-font-size: $font-size-base * 2 !default; -$h3-font-size: $font-size-base * 1.75 !default; -$h4-font-size: $font-size-base * 1.5 !default; -$h5-font-size: $font-size-base * 1.25 !default; -$h6-font-size: $font-size-base !default; +$h1-font-size: $font-size-base * 2.5 !default; +$h2-font-size: $font-size-base * 2 !default; +$h3-font-size: $font-size-base * 1.75 !default; +$h4-font-size: $font-size-base * 1.5 !default; +$h5-font-size: $font-size-base * 1.25 !default; +$h6-font-size: $font-size-base !default; -$headings-margin-bottom: ($spacer / 2) !default; -$headings-font-family: inherit !default; -$headings-font-weight: 500 !default; -$headings-line-height: 1.2 !default; -$headings-color: inherit !default; +$headings-margin-bottom: ($spacer / 2) !default; +$headings-font-family: inherit !default; +$headings-font-weight: 500 !default; +$headings-line-height: 1.2 !default; +$headings-color: inherit !default; -$display1-size: 6rem !default; -$display2-size: 5.5rem !default; -$display3-size: 4.5rem !default; -$display4-size: 3.5rem !default; +$display1-size: 6rem !default; +$display2-size: 5.5rem !default; +$display3-size: 4.5rem !default; +$display4-size: 3.5rem !default; -$display1-weight: 300 !default; -$display2-weight: 300 !default; -$display3-weight: 300 !default; -$display4-weight: 300 !default; -$display-line-height: $headings-line-height !default; +$display1-weight: 300 !default; +$display2-weight: 300 !default; +$display3-weight: 300 !default; +$display4-weight: 300 !default; +$display-line-height: $headings-line-height !default; -$lead-font-size: ($font-size-base * 1.25) !default; -$lead-font-weight: 300 !default; +$lead-font-size: ($font-size-base * 1.25) !default; +$lead-font-weight: 300 !default; -$small-font-size: 80% !default; +$small-font-size: 80% !default; -$text-muted: $gray-600 !default; +$text-muted: $gray-600 !default; -$blockquote-small-color: $gray-600 !default; -$blockquote-font-size: ($font-size-base * 1.25) !default; +$blockquote-small-color: $gray-600 !default; +$blockquote-font-size: ($font-size-base * 1.25) !default; -$hr-border-color: rgba($black, .1) !default; -$hr-border-width: $border-width !default; +$hr-border-color: rgba($black, .1) !default; +$hr-border-width: $border-width !default; -$mark-padding: .2em !default; +$mark-padding: .2em !default; -$dt-font-weight: $font-weight-bold !default; +$dt-font-weight: $font-weight-bold !default; -$kbd-box-shadow: inset 0 -.1rem 0 rgba($black, .25) !default; -$nested-kbd-font-weight: $font-weight-bold !default; +$kbd-box-shadow: inset 0 -.1rem 0 rgba($black, .25) !default; +$nested-kbd-font-weight: $font-weight-bold !default; -$list-inline-padding: .5rem !default; +$list-inline-padding: .5rem !default; -$mark-bg: #fcf8e3 !default; +$mark-bg: #fcf8e3 !default; -$hr-margin-y: $spacer !default; +$hr-margin-y: $spacer !default; // Tables // // Customizes the `.table` component with basic values, each used across all table variations. -$table-cell-padding: .75rem !default; -$table-cell-padding-sm: .3rem !default; +$table-cell-padding: .75rem !default; +$table-cell-padding-sm: .3rem !default; -$table-bg: transparent !default; -$table-accent-bg: rgba($black, .05) !default; -$table-hover-bg: rgba($black, .075) !default; -$table-active-bg: $table-hover-bg !default; +$table-bg: transparent !default; +$table-accent-bg: rgba($black, .05) !default; +$table-hover-bg: rgba($black, .075) !default; +$table-active-bg: $table-hover-bg !default; -$table-border-width: $border-width !default; -$table-border-color: $gray-300 !default; +$table-border-width: $border-width !default; +$table-border-color: $gray-300 !default; -$table-head-bg: $gray-200 !default; -$table-head-color: $gray-700 !default; +$table-head-bg: $gray-200 !default; +$table-head-color: $gray-700 !default; -$table-dark-bg: $gray-900 !default; -$table-dark-accent-bg: rgba($white, .05) !default; -$table-dark-hover-bg: rgba($white, .075) !default; -$table-dark-border-color: lighten($gray-900, 7.5%) !default; -$table-dark-color: $body-bg !default; +$table-dark-bg: $gray-900 !default; +$table-dark-accent-bg: rgba($white, .05) !default; +$table-dark-hover-bg: rgba($white, .075) !default; +$table-dark-border-color: lighten($gray-900, 7.5%) !default; +$table-dark-color: $body-bg !default; // Buttons + Forms // // Shared variables that are reassigned to `$input-` and `$btn-` specific variables. -$input-btn-padding-y: .375rem !default; -$input-btn-padding-x: .75rem !default; -$input-btn-line-height: $line-height-base !default; +$input-btn-padding-y: .375rem !default; +$input-btn-padding-x: .75rem !default; +$input-btn-line-height: $line-height-base !default; -$input-btn-focus-width: .2rem !default; -$input-btn-focus-color: rgba($component-active-bg, .25) !default; -$input-btn-focus-box-shadow: 0 0 0 $input-btn-focus-width $input-btn-focus-color !default; +$input-btn-focus-width: .2rem !default; +$input-btn-focus-color: rgba($component-active-bg, .25) !default; +$input-btn-focus-box-shadow: 0 0 0 $input-btn-focus-width $input-btn-focus-color !default; -$input-btn-padding-y-sm: .25rem !default; -$input-btn-padding-x-sm: .5rem !default; -$input-btn-line-height-sm: $line-height-sm !default; +$input-btn-padding-y-sm: .25rem !default; +$input-btn-padding-x-sm: .5rem !default; +$input-btn-line-height-sm: $line-height-sm !default; -$input-btn-padding-y-lg: .5rem !default; -$input-btn-padding-x-lg: 1rem !default; -$input-btn-line-height-lg: $line-height-lg !default; +$input-btn-padding-y-lg: .5rem !default; +$input-btn-padding-x-lg: 1rem !default; +$input-btn-line-height-lg: $line-height-lg !default; -$input-btn-border-width: $border-width !default; +$input-btn-border-width: $border-width !default; // Buttons // // For each of Bootstrap's buttons, define text, background, and border color. -$btn-padding-y: $input-btn-padding-y !default; -$btn-padding-x: $input-btn-padding-x !default; -$btn-line-height: $input-btn-line-height !default; +$btn-padding-y: $input-btn-padding-y !default; +$btn-padding-x: $input-btn-padding-x !default; +$btn-line-height: $input-btn-line-height !default; -$btn-padding-y-sm: $input-btn-padding-y-sm !default; -$btn-padding-x-sm: $input-btn-padding-x-sm !default; -$btn-line-height-sm: $input-btn-line-height-sm !default; +$btn-padding-y-sm: $input-btn-padding-y-sm !default; +$btn-padding-x-sm: $input-btn-padding-x-sm !default; +$btn-line-height-sm: $input-btn-line-height-sm !default; -$btn-padding-y-lg: $input-btn-padding-y-lg !default; -$btn-padding-x-lg: $input-btn-padding-x-lg !default; -$btn-line-height-lg: $input-btn-line-height-lg !default; +$btn-padding-y-lg: $input-btn-padding-y-lg !default; +$btn-padding-x-lg: $input-btn-padding-x-lg !default; +$btn-line-height-lg: $input-btn-line-height-lg !default; -$btn-border-width: $input-btn-border-width !default; +$btn-border-width: $input-btn-border-width !default; -$btn-font-weight: $font-weight-normal !default; -$btn-box-shadow: inset 0 1px 0 rgba($white, .15), 0 1px 1px rgba($black, .075) !default; -$btn-focus-width: $input-btn-focus-width !default; -$btn-focus-box-shadow: $input-btn-focus-box-shadow !default; -$btn-disabled-opacity: .65 !default; -$btn-active-box-shadow: inset 0 3px 5px rgba($black, .125) !default; +$btn-font-weight: $font-weight-normal !default; +$btn-box-shadow: inset 0 1px 0 rgba($white, .15), 0 1px 1px rgba($black, .075) !default; +$btn-focus-width: $input-btn-focus-width !default; +$btn-focus-box-shadow: $input-btn-focus-box-shadow !default; +$btn-disabled-opacity: .65 !default; +$btn-active-box-shadow: inset 0 3px 5px rgba($black, .125) !default; -$btn-link-disabled-color: $gray-600 !default; +$btn-link-disabled-color: $gray-600 !default; -$btn-block-spacing-y: .5rem !default; +$btn-block-spacing-y: .5rem !default; // Allows for customizing button radius independently from global border radius -$btn-border-radius: $border-radius !default; -$btn-border-radius-lg: $border-radius-lg !default; -$btn-border-radius-sm: $border-radius-sm !default; +$btn-border-radius: $border-radius !default; +$btn-border-radius-lg: $border-radius-lg !default; +$btn-border-radius-sm: $border-radius-sm !default; -$btn-transition: color .15s ease-in-out, background-color .15s ease-in-out, border-color .15s ease-in-out, box-shadow .15s ease-in-out !default; +$btn-transition: color .15s ease-in-out, background-color .15s ease-in-out, border-color .15s ease-in-out, box-shadow .15s ease-in-out !default; // Forms -$input-padding-y: $input-btn-padding-y !default; -$input-padding-x: $input-btn-padding-x !default; -$input-line-height: $input-btn-line-height !default; +$input-padding-y: $input-btn-padding-y !default; +$input-padding-x: $input-btn-padding-x !default; +$input-line-height: $input-btn-line-height !default; -$input-padding-y-sm: $input-btn-padding-y-sm !default; -$input-padding-x-sm: $input-btn-padding-x-sm !default; -$input-line-height-sm: $input-btn-line-height-sm !default; +$input-padding-y-sm: $input-btn-padding-y-sm !default; +$input-padding-x-sm: $input-btn-padding-x-sm !default; +$input-line-height-sm: $input-btn-line-height-sm !default; -$input-padding-y-lg: $input-btn-padding-y-lg !default; -$input-padding-x-lg: $input-btn-padding-x-lg !default; -$input-line-height-lg: $input-btn-line-height-lg !default; +$input-padding-y-lg: $input-btn-padding-y-lg !default; +$input-padding-x-lg: $input-btn-padding-x-lg !default; +$input-line-height-lg: $input-btn-line-height-lg !default; -$input-bg: $white !default; -$input-disabled-bg: $gray-200 !default; +$input-bg: $white !default; +$input-disabled-bg: $gray-200 !default; -$input-color: $gray-700 !default; -$input-border-color: $gray-400 !default; -$input-border-width: $input-btn-border-width !default; -$input-box-shadow: inset 0 1px 1px rgba($black, .075) !default; +$input-color: $gray-700 !default; +$input-border-color: $gray-400 !default; +$input-border-width: $input-btn-border-width !default; +$input-box-shadow: inset 0 1px 1px rgba($black, .075) !default; -$input-border-radius: $border-radius !default; -$input-border-radius-lg: $border-radius-lg !default; -$input-border-radius-sm: $border-radius-sm !default; +$input-border-radius: $border-radius !default; +$input-border-radius-lg: $border-radius-lg !default; +$input-border-radius-sm: $border-radius-sm !default; -$input-focus-bg: $input-bg !default; -$input-focus-border-color: lighten($component-active-bg, 25%) !default; -$input-focus-color: $input-color !default; -$input-focus-width: $input-btn-focus-width !default; -$input-focus-box-shadow: $input-btn-focus-box-shadow !default; +$input-focus-bg: $input-bg !default; +$input-focus-border-color: lighten($component-active-bg, 25%) !default; +$input-focus-color: $input-color !default; +$input-focus-width: $input-btn-focus-width !default; +$input-focus-box-shadow: $input-btn-focus-box-shadow !default; -$input-placeholder-color: $gray-600 !default; +$input-placeholder-color: $gray-600 !default; -$input-height-border: $input-border-width * 2 !default; +$input-height-border: $input-border-width * 2 !default; -$input-height-inner: ($font-size-base * $input-btn-line-height) + ($input-btn-padding-y * 2) !default; -$input-height: calc(#{$input-height-inner} + #{$input-height-border}) !default; +$input-height-inner: ($font-size-base * $input-btn-line-height) + ($input-btn-padding-y * 2) !default; +$input-height: calc(#{$input-height-inner} + #{$input-height-border}) !default; -$input-height-inner-sm: ($font-size-sm * $input-btn-line-height-sm) + ($input-btn-padding-y-sm * 2) !default; -$input-height-sm: calc(#{$input-height-inner-sm} + #{$input-height-border}) !default; +$input-height-inner-sm: ($font-size-sm * $input-btn-line-height-sm) + ($input-btn-padding-y-sm * 2) !default; +$input-height-sm: calc(#{$input-height-inner-sm} + #{$input-height-border}) !default; -$input-height-inner-lg: ($font-size-lg * $input-btn-line-height-lg) + ($input-btn-padding-y-lg * 2) !default; -$input-height-lg: calc(#{$input-height-inner-lg} + #{$input-height-border}) !default; +$input-height-inner-lg: ($font-size-lg * $input-btn-line-height-lg) + ($input-btn-padding-y-lg * 2) !default; +$input-height-lg: calc(#{$input-height-inner-lg} + #{$input-height-border}) !default; -$input-transition: border-color .15s ease-in-out, box-shadow .15s ease-in-out !default; +$input-transition: border-color .15s ease-in-out, box-shadow .15s ease-in-out !default; -$form-text-margin-top: .25rem !default; +$form-text-margin-top: .25rem !default; -$form-check-input-gutter: 1.25rem !default; -$form-check-input-margin-y: .3rem !default; -$form-check-input-margin-x: .25rem !default; +$form-check-input-gutter: 1.25rem !default; +$form-check-input-margin-y: .3rem !default; +$form-check-input-margin-x: .25rem !default; -$form-check-inline-margin-x: .75rem !default; -$form-check-inline-input-margin-x: .3125rem !default; +$form-check-inline-margin-x: .75rem !default; +$form-check-inline-input-margin-x: .3125rem !default; -$form-group-margin-bottom: 1rem !default; +$form-group-margin-bottom: 1rem !default; -$input-group-addon-color: $input-color !default; -$input-group-addon-bg: $gray-200 !default; -$input-group-addon-border-color: $input-border-color !default; +$input-group-addon-color: $input-color !default; +$input-group-addon-bg: $gray-200 !default; +$input-group-addon-border-color: $input-border-color !default; -$custom-control-gutter: 1.5rem !default; -$custom-control-spacer-x: 1rem !default; +$custom-control-gutter: 1.5rem !default; +$custom-control-spacer-x: 1rem !default; -$custom-control-indicator-size: 1rem !default; -$custom-control-indicator-bg: $gray-300 !default; -$custom-control-indicator-bg-size: 50% 50% !default; -$custom-control-indicator-box-shadow: inset 0 .25rem .25rem rgba($black, .1) !default; +$custom-control-indicator-size: 1rem !default; +$custom-control-indicator-bg: $gray-300 !default; +$custom-control-indicator-bg-size: 50% 50% !default; +$custom-control-indicator-box-shadow: inset 0 .25rem .25rem rgba($black, .1) !default; -$custom-control-indicator-disabled-bg: $gray-200 !default; -$custom-control-label-disabled-color: $gray-600 !default; +$custom-control-indicator-disabled-bg: $gray-200 !default; +$custom-control-label-disabled-color: $gray-600 !default; -$custom-control-indicator-checked-color: $component-active-color !default; -$custom-control-indicator-checked-bg: $component-active-bg !default; -$custom-control-indicator-checked-disabled-bg: rgba(theme-color("primary"), .5) !default; -$custom-control-indicator-checked-box-shadow: none !default; +$custom-control-indicator-checked-color: $component-active-color !default; +$custom-control-indicator-checked-bg: $component-active-bg !default; +$custom-control-indicator-checked-disabled-bg: rgba(theme-color("primary"), .5) !default; +$custom-control-indicator-checked-box-shadow: none !default; -$custom-control-indicator-focus-box-shadow: 0 0 0 1px $body-bg, $input-btn-focus-box-shadow !default; +$custom-control-indicator-focus-box-shadow: 0 0 0 1px $body-bg, $input-btn-focus-box-shadow !default; -$custom-control-indicator-active-color: $component-active-color !default; -$custom-control-indicator-active-bg: lighten($component-active-bg, 35%) !default; -$custom-control-indicator-active-box-shadow: none !default; +$custom-control-indicator-active-color: $component-active-color !default; +$custom-control-indicator-active-bg: lighten($component-active-bg, 35%) !default; +$custom-control-indicator-active-box-shadow: none !default; -$custom-checkbox-indicator-border-radius: $border-radius !default; -$custom-checkbox-indicator-icon-checked: str-replace(url("data:image/svg+xml;charset=utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 8 8'%3E%3Cpath fill='#{$custom-control-indicator-checked-color}' d='M6.564.75l-3.59 3.612-1.538-1.55L0 4.26 2.974 7.25 8 2.193z'/%3E%3C/svg%3E"), "#", "%23") !default; +$custom-checkbox-indicator-border-radius: $border-radius !default; +$custom-checkbox-indicator-icon-checked: str-replace(url("data:image/svg+xml;charset=utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 8 8'%3E%3Cpath fill='#{$custom-control-indicator-checked-color}' d='M6.564.75l-3.59 3.612-1.538-1.55L0 4.26 2.974 7.25 8 2.193z'/%3E%3C/svg%3E"), "#", "%23") !default; -$custom-checkbox-indicator-indeterminate-bg: $component-active-bg !default; +$custom-checkbox-indicator-indeterminate-bg: $component-active-bg !default; $custom-checkbox-indicator-indeterminate-color: $custom-control-indicator-checked-color !default; -$custom-checkbox-indicator-icon-indeterminate: str-replace(url("data:image/svg+xml;charset=utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 4 4'%3E%3Cpath stroke='#{$custom-checkbox-indicator-indeterminate-color}' d='M0 2h4'/%3E%3C/svg%3E"), "#", "%23") !default; +$custom-checkbox-indicator-icon-indeterminate: str-replace(url("data:image/svg+xml;charset=utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 4 4'%3E%3Cpath stroke='#{$custom-checkbox-indicator-indeterminate-color}' d='M0 2h4'/%3E%3C/svg%3E"), "#", "%23") !default; $custom-checkbox-indicator-indeterminate-box-shadow: none !default; -$custom-radio-indicator-border-radius: 50% !default; -$custom-radio-indicator-icon-checked: str-replace(url("data:image/svg+xml;charset=utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='-4 -4 8 8'%3E%3Ccircle r='3' fill='#{$custom-control-indicator-checked-color}'/%3E%3C/svg%3E"), "#", "%23") !default; +$custom-radio-indicator-border-radius: 50% !default; +$custom-radio-indicator-icon-checked: str-replace(url("data:image/svg+xml;charset=utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='-4 -4 8 8'%3E%3Ccircle r='3' fill='#{$custom-control-indicator-checked-color}'/%3E%3C/svg%3E"), "#", "%23") !default; -$custom-select-padding-y: .375rem !default; -$custom-select-padding-x: .75rem !default; -$custom-select-height: $input-height !default; -$custom-select-indicator-padding: 1rem !default; // Extra padding to account for the presence of the background-image based indicator -$custom-select-line-height: $input-btn-line-height !default; -$custom-select-color: $input-color !default; -$custom-select-disabled-color: $gray-600 !default; -$custom-select-bg: $white !default; -$custom-select-disabled-bg: $gray-200 !default; -$custom-select-bg-size: 8px 10px !default; // In pixels because image dimensions -$custom-select-indicator-color: $gray-800 !default; -$custom-select-indicator: str-replace(url("data:image/svg+xml;charset=utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 4 5'%3E%3Cpath fill='#{$custom-select-indicator-color}' d='M2 0L0 2h4zm0 5L0 3h4z'/%3E%3C/svg%3E"), "#", "%23") !default; -$custom-select-border-width: $input-btn-border-width !default; -$custom-select-border-color: $input-border-color !default; -$custom-select-border-radius: $border-radius !default; +$custom-select-padding-y: .375rem !default; +$custom-select-padding-x: .75rem !default; +$custom-select-height: $input-height !default; +$custom-select-indicator-padding: 1rem !default; // Extra padding to account for the presence of the background-image based indicator +$custom-select-line-height: $input-btn-line-height !default; +$custom-select-color: $input-color !default; +$custom-select-disabled-color: $gray-600 !default; +$custom-select-bg: $white !default; +$custom-select-disabled-bg: $gray-200 !default; +$custom-select-bg-size: 8px 10px !default; // In pixels because image dimensions +$custom-select-indicator-color: $gray-800 !default; +$custom-select-indicator: str-replace(url("data:image/svg+xml;charset=utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 4 5'%3E%3Cpath fill='#{$custom-select-indicator-color}' d='M2 0L0 2h4zm0 5L0 3h4z'/%3E%3C/svg%3E"), "#", "%23") !default; +$custom-select-border-width: $input-btn-border-width !default; +$custom-select-border-color: $input-border-color !default; +$custom-select-border-radius: $border-radius !default; -$custom-select-focus-border-color: $input-focus-border-color !default; -$custom-select-focus-box-shadow: inset 0 1px 2px rgba($black, .075), 0 0 5px rgba($custom-select-focus-border-color, .5) !default; +$custom-select-focus-border-color: $input-focus-border-color !default; +$custom-select-focus-box-shadow: inset 0 1px 2px rgba($black, .075), 0 0 5px rgba($custom-select-focus-border-color, .5) !default; -$custom-select-font-size-sm: 75% !default; -$custom-select-height-sm: $input-height-sm !default; +$custom-select-font-size-sm: 75% !default; +$custom-select-height-sm: $input-height-sm !default; -$custom-select-font-size-lg: 125% !default; -$custom-select-height-lg: $input-height-lg !default; +$custom-select-font-size-lg: 125% !default; +$custom-select-height-lg: $input-height-lg !default; -$custom-file-height: $input-height !default; -$custom-file-focus-border-color: $input-focus-border-color !default; -$custom-file-focus-box-shadow: $input-btn-focus-box-shadow !default; +$custom-file-height: $input-height !default; +$custom-file-focus-border-color: $input-focus-border-color !default; +$custom-file-focus-box-shadow: $input-btn-focus-box-shadow !default; -$custom-file-padding-y: $input-btn-padding-y !default; -$custom-file-padding-x: $input-btn-padding-x !default; -$custom-file-line-height: $input-btn-line-height !default; -$custom-file-color: $input-color !default; -$custom-file-bg: $input-bg !default; -$custom-file-border-width: $input-btn-border-width !default; -$custom-file-border-color: $input-border-color !default; -$custom-file-border-radius: $input-border-radius !default; -$custom-file-box-shadow: $input-box-shadow !default; -$custom-file-button-color: $custom-file-color !default; -$custom-file-button-bg: $input-group-addon-bg !default; -$custom-file-text: ( - en: "Browse" -) !default; +$custom-file-padding-y: $input-btn-padding-y !default; +$custom-file-padding-x: $input-btn-padding-x !default; +$custom-file-line-height: $input-btn-line-height !default; +$custom-file-color: $input-color !default; +$custom-file-bg: $input-bg !default; +$custom-file-border-width: $input-btn-border-width !default; +$custom-file-border-color: $input-border-color !default; +$custom-file-border-radius: $input-border-radius !default; +$custom-file-box-shadow: $input-box-shadow !default; +$custom-file-button-color: $custom-file-color !default; +$custom-file-button-bg: $input-group-addon-bg !default; +$custom-file-text: ( en: "Browse" ) !default; // Form validation -$form-feedback-margin-top: $form-text-margin-top !default; -$form-feedback-font-size: $small-font-size !default; -$form-feedback-valid-color: theme-color("success") !default; -$form-feedback-invalid-color: theme-color("danger") !default; +$form-feedback-margin-top: $form-text-margin-top !default; +$form-feedback-font-size: $small-font-size !default; +$form-feedback-valid-color: theme-color("success") !default; +$form-feedback-invalid-color: theme-color("danger") !default; // Dropdowns // // Dropdown menu container and contents. -$dropdown-min-width: 10rem !default; -$dropdown-padding-y: .5rem !default; -$dropdown-spacer: .125rem !default; -$dropdown-bg: $white !default; -$dropdown-border-color: rgba($black, .15) !default; -$dropdown-border-radius: $border-radius !default; -$dropdown-border-width: $border-width !default; -$dropdown-divider-bg: $gray-200 !default; -$dropdown-box-shadow: 0 .5rem 1rem rgba($black, .175) !default; +$dropdown-min-width: 10rem !default; +$dropdown-padding-y: .5rem !default; +$dropdown-spacer: .125rem !default; +$dropdown-bg: $white !default; +$dropdown-border-color: rgba($black, .15) !default; +$dropdown-border-radius: $border-radius !default; +$dropdown-border-width: $border-width !default; +$dropdown-divider-bg: $gray-200 !default; +$dropdown-box-shadow: 0 .5rem 1rem rgba($black, .175) !default; -$dropdown-link-color: $gray-900 !default; -$dropdown-link-hover-color: darken($gray-900, 5%) !default; -$dropdown-link-hover-bg: $gray-100 !default; +$dropdown-link-color: $gray-900 !default; +$dropdown-link-hover-color: darken($gray-900, 5%) !default; +$dropdown-link-hover-bg: $gray-100 !default; -$dropdown-link-active-color: $component-active-color !default; -$dropdown-link-active-bg: $component-active-bg !default; +$dropdown-link-active-color: $component-active-color !default; +$dropdown-link-active-bg: $component-active-bg !default; -$dropdown-link-disabled-color: $gray-600 !default; +$dropdown-link-disabled-color: $gray-600 !default; -$dropdown-item-padding-y: .25rem !default; -$dropdown-item-padding-x: 1.5rem !default; +$dropdown-item-padding-y: .25rem !default; +$dropdown-item-padding-x: 1.5rem !default; -$dropdown-header-color: $gray-600 !default; +$dropdown-header-color: $gray-600 !default; // Z-index master list @@ -559,336 +501,336 @@ $dropdown-header-color: $gray-600 !default; // Warning: Avoid customizing these values. They're used for a bird's eye view // of components dependent on the z-axis and are designed to all work together. -$zindex-dropdown: 1000 !default; -$zindex-sticky: 1020 !default; -$zindex-fixed: 1030 !default; -$zindex-modal-backdrop: 1040 !default; -$zindex-modal: 1050 !default; -$zindex-popover: 1060 !default; -$zindex-tooltip: 1070 !default; +$zindex-dropdown: 1000 !default; +$zindex-sticky: 1020 !default; +$zindex-fixed: 1030 !default; +$zindex-modal-backdrop: 1040 !default; +$zindex-modal: 1050 !default; +$zindex-popover: 1060 !default; +$zindex-tooltip: 1070 !default; // Navs -$nav-link-padding-y: .5rem !default; -$nav-link-padding-x: 1rem !default; -$nav-link-disabled-color: $gray-600 !default; +$nav-link-padding-y: .5rem !default; +$nav-link-padding-x: 1rem !default; +$nav-link-disabled-color: $gray-600 !default; -$nav-tabs-border-color: $gray-300 !default; -$nav-tabs-border-width: $border-width !default; -$nav-tabs-border-radius: $border-radius !default; -$nav-tabs-link-hover-border-color: $gray-200 $gray-200 $nav-tabs-border-color !default; -$nav-tabs-link-active-color: $gray-700 !default; -$nav-tabs-link-active-bg: $body-bg !default; +$nav-tabs-border-color: $gray-300 !default; +$nav-tabs-border-width: $border-width !default; +$nav-tabs-border-radius: $border-radius !default; +$nav-tabs-link-hover-border-color: $gray-200 $gray-200 $nav-tabs-border-color !default; +$nav-tabs-link-active-color: $gray-700 !default; +$nav-tabs-link-active-bg: $body-bg !default; $nav-tabs-link-active-border-color: $gray-300 $gray-300 $nav-tabs-link-active-bg !default; -$nav-pills-border-radius: $border-radius !default; -$nav-pills-link-active-color: $component-active-color !default; -$nav-pills-link-active-bg: $component-active-bg !default; +$nav-pills-border-radius: $border-radius !default; +$nav-pills-link-active-color: $component-active-color !default; +$nav-pills-link-active-bg: $component-active-bg !default; // Navbar -$navbar-padding-y: 0 !default; -$navbar-padding-x: $spacer !default; +$navbar-padding-y: 0 !default; +$navbar-padding-x: $spacer !default; -$navbar-nav-link-padding-x: 2rem !default; +$navbar-nav-link-padding-x: 2rem !default; $navbar-brand-font-size: $h1-font-size !default; // Compute the navbar-brand padding-y so the navbar-brand will have the same height as navbar-text and nav-link -$nav-link-height: ($font-size-base * $line-height-base + $nav-link-padding-y * 2) !default; -$navbar-brand-height: $navbar-brand-font-size * $line-height-base !default; -$navbar-brand-padding-y: ($nav-link-height - $navbar-brand-height) / 2 !default; +$nav-link-height: ($font-size-base * $line-height-base + $nav-link-padding-y * 2) !default; +$navbar-brand-height: $navbar-brand-font-size * $line-height-base !default; +$navbar-brand-padding-y: ($nav-link-height - $navbar-brand-height) / 2 !default; -$navbar-toggler-padding-y: .25rem !default; -$navbar-toggler-padding-x: .75rem !default; -$navbar-toggler-font-size: $h5-font-size !default; -$navbar-toggler-border-radius: $btn-border-radius !default; +$navbar-toggler-padding-y: .25rem !default; +$navbar-toggler-padding-x: .75rem !default; +$navbar-toggler-font-size: $h5-font-size !default; +$navbar-toggler-border-radius: $btn-border-radius !default; -$navbar-dark-color: rgba($white, .5) !default; -$navbar-dark-hover-color: $primary !default; -$navbar-dark-active-color: $white !default; -$navbar-dark-disabled-color: rgba($white, .25) !default; -$navbar-dark-toggler-icon-bg: str-replace(url("data:image/svg+xml;charset=utf8,%3Csvg viewBox='0 0 30 30' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath stroke='#{$navbar-dark-color}' stroke-width='2' stroke-linecap='round' stroke-miterlimit='10' d='M4 7h22M4 15h22M4 23h22'/%3E%3C/svg%3E"), "#", "%23") !default; -$navbar-dark-toggler-border-color: rgba($white, .1) !default; +$navbar-dark-color: rgba($white, .5) !default; +$navbar-dark-hover-color: $primary !default; +$navbar-dark-active-color: $white !default; +$navbar-dark-disabled-color: rgba($white, .25) !default; +$navbar-dark-toggler-icon-bg: str-replace(url("data:image/svg+xml;charset=utf8,%3Csvg viewBox='0 0 30 30' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath stroke='#{$navbar-dark-color}' stroke-width='2' stroke-linecap='round' stroke-miterlimit='10' d='M4 7h22M4 15h22M4 23h22'/%3E%3C/svg%3E"), "#", "%23") !default; +$navbar-dark-toggler-border-color: rgba($white, .1) !default; -$navbar-light-color: rgba($black, .5) !default; -$navbar-light-hover-color: rgba($black, .7) !default; -$navbar-light-active-color: rgba($black, .9) !default; -$navbar-light-disabled-color: rgba($black, .3) !default; -$navbar-light-toggler-icon-bg: str-replace(url("data:image/svg+xml;charset=utf8,%3Csvg viewBox='0 0 30 30' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath stroke='#{$navbar-light-color}' stroke-width='2' stroke-linecap='round' stroke-miterlimit='10' d='M4 7h22M4 15h22M4 23h22'/%3E%3C/svg%3E"), "#", "%23") !default; +$navbar-light-color: rgba($black, .5) !default; +$navbar-light-hover-color: rgba($black, .7) !default; +$navbar-light-active-color: rgba($black, .9) !default; +$navbar-light-disabled-color: rgba($black, .3) !default; +$navbar-light-toggler-icon-bg: str-replace(url("data:image/svg+xml;charset=utf8,%3Csvg viewBox='0 0 30 30' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath stroke='#{$navbar-light-color}' stroke-width='2' stroke-linecap='round' stroke-miterlimit='10' d='M4 7h22M4 15h22M4 23h22'/%3E%3C/svg%3E"), "#", "%23") !default; $navbar-light-toggler-border-color: rgba($black, .1) !default; // Pagination -$pagination-padding-y: .5rem !default; -$pagination-padding-x: .75rem !default; -$pagination-padding-y-sm: .25rem !default; -$pagination-padding-x-sm: .5rem !default; -$pagination-padding-y-lg: .75rem !default; -$pagination-padding-x-lg: 1.5rem !default; -$pagination-line-height: 1.25 !default; +$pagination-padding-y: .5rem !default; +$pagination-padding-x: .75rem !default; +$pagination-padding-y-sm: .25rem !default; +$pagination-padding-x-sm: .5rem !default; +$pagination-padding-y-lg: .75rem !default; +$pagination-padding-x-lg: 1.5rem !default; +$pagination-line-height: 1.25 !default; -$pagination-color: $link-color !default; -$pagination-bg: $white !default; -$pagination-border-width: $border-width !default; -$pagination-border-color: $gray-300 !default; +$pagination-color: $link-color !default; +$pagination-bg: $white !default; +$pagination-border-width: $border-width !default; +$pagination-border-color: $gray-300 !default; -$pagination-focus-box-shadow: $input-btn-focus-box-shadow !default; +$pagination-focus-box-shadow: $input-btn-focus-box-shadow !default; -$pagination-hover-color: $link-hover-color !default; -$pagination-hover-bg: $gray-200 !default; -$pagination-hover-border-color: $gray-300 !default; +$pagination-hover-color: $link-hover-color !default; +$pagination-hover-bg: $gray-200 !default; +$pagination-hover-border-color: $gray-300 !default; -$pagination-active-color: $component-active-color !default; -$pagination-active-bg: $component-active-bg !default; -$pagination-active-border-color: $pagination-active-bg !default; +$pagination-active-color: $component-active-color !default; +$pagination-active-bg: $component-active-bg !default; +$pagination-active-border-color: $pagination-active-bg !default; -$pagination-disabled-color: $gray-600 !default; -$pagination-disabled-bg: $white !default; -$pagination-disabled-border-color: $gray-300 !default; +$pagination-disabled-color: $gray-600 !default; +$pagination-disabled-bg: $white !default; +$pagination-disabled-border-color: $gray-300 !default; // Jumbotron -$jumbotron-padding: 2rem !default; -$jumbotron-bg: $gray-200 !default; +$jumbotron-padding: 2rem !default; +$jumbotron-bg: $gray-200 !default; // Cards -$card-spacer-y: .75rem !default; -$card-spacer-x: 1.25rem !default; -$card-border-width: $border-width !default; -$card-border-radius: $border-radius !default; -$card-border-color: rgba($black, .125) !default; -$card-inner-border-radius: calc(#{$card-border-radius} - #{$card-border-width}) !default; -$card-cap-bg: rgba($black, .03) !default; -$card-bg: $white !default; +$card-spacer-y: .75rem !default; +$card-spacer-x: 1.25rem !default; +$card-border-width: $border-width !default; +$card-border-radius: $border-radius !default; +$card-border-color: rgba($black, .125) !default; +$card-inner-border-radius: calc(#{$card-border-radius} - #{$card-border-width}) !default; +$card-cap-bg: rgba($black, .03) !default; +$card-bg: $white !default; -$card-img-overlay-padding: 1.25rem !default; +$card-img-overlay-padding: 1.25rem !default; -$card-group-margin: ($grid-gutter-width / 2) !default; -$card-deck-margin: $card-group-margin !default; +$card-group-margin: ($grid-gutter-width / 2) !default; +$card-deck-margin: $card-group-margin !default; -$card-columns-count: 3 !default; -$card-columns-gap: 1.25rem !default; -$card-columns-margin: $card-spacer-y !default; +$card-columns-count: 3 !default; +$card-columns-gap: 1.25rem !default; +$card-columns-margin: $card-spacer-y !default; // Tooltips -$tooltip-font-size: $font-size-sm !default; -$tooltip-max-width: 200px !default; -$tooltip-color: $white !default; -$tooltip-bg: $black !default; -$tooltip-border-radius: $border-radius !default; -$tooltip-opacity: .9 !default; -$tooltip-padding-y: .25rem !default; -$tooltip-padding-x: .5rem !default; -$tooltip-margin: 0 !default; +$tooltip-font-size: $font-size-sm !default; +$tooltip-max-width: 200px !default; +$tooltip-color: $white !default; +$tooltip-bg: $black !default; +$tooltip-border-radius: $border-radius !default; +$tooltip-opacity: .9 !default; +$tooltip-padding-y: .25rem !default; +$tooltip-padding-x: .5rem !default; +$tooltip-margin: 0 !default; -$tooltip-arrow-width: .8rem !default; -$tooltip-arrow-height: .4rem !default; -$tooltip-arrow-color: $tooltip-bg !default; +$tooltip-arrow-width: .8rem !default; +$tooltip-arrow-height: .4rem !default; +$tooltip-arrow-color: $tooltip-bg !default; // Popovers -$popover-font-size: $font-size-sm !default; -$popover-bg: $white !default; -$popover-max-width: 276px !default; -$popover-border-width: $border-width !default; -$popover-border-color: rgba($black, .2) !default; -$popover-border-radius: $border-radius-lg !default; -$popover-box-shadow: 0 .25rem .5rem rgba($black, .2) !default; +$popover-font-size: $font-size-sm !default; +$popover-bg: $white !default; +$popover-max-width: 276px !default; +$popover-border-width: $border-width !default; +$popover-border-color: rgba($black, .2) !default; +$popover-border-radius: $border-radius-lg !default; +$popover-box-shadow: 0 .25rem .5rem rgba($black, .2) !default; -$popover-header-bg: darken($popover-bg, 3%) !default; -$popover-header-color: $headings-color !default; -$popover-header-padding-y: .5rem !default; -$popover-header-padding-x: .75rem !default; +$popover-header-bg: darken($popover-bg, 3%) !default; +$popover-header-color: $headings-color !default; +$popover-header-padding-y: .5rem !default; +$popover-header-padding-x: .75rem !default; -$popover-body-color: $body-color !default; -$popover-body-padding-y: $popover-header-padding-y !default; -$popover-body-padding-x: $popover-header-padding-x !default; +$popover-body-color: $body-color !default; +$popover-body-padding-y: $popover-header-padding-y !default; +$popover-body-padding-x: $popover-header-padding-x !default; -$popover-arrow-width: 1rem !default; -$popover-arrow-height: .5rem !default; -$popover-arrow-color: $popover-bg !default; +$popover-arrow-width: 1rem !default; +$popover-arrow-height: .5rem !default; +$popover-arrow-color: $popover-bg !default; -$popover-arrow-outer-color: fade-in($popover-border-color, .05) !default; +$popover-arrow-outer-color: fade-in($popover-border-color, .05) !default; // Badges -$badge-font-size: 75% !default; -$badge-font-weight: $font-weight-bold !default; -$badge-padding-y: .25em !default; -$badge-padding-x: .4em !default; -$badge-border-radius: $border-radius !default; +$badge-font-size: 75% !default; +$badge-font-weight: $font-weight-bold !default; +$badge-padding-y: .25em !default; +$badge-padding-x: .4em !default; +$badge-border-radius: $border-radius !default; -$badge-pill-padding-x: .6em !default; +$badge-pill-padding-x: .6em !default; // Use a higher than normal value to ensure completely rounded edges when // customizing padding or font-size on labels. -$badge-pill-border-radius: 10rem !default; +$badge-pill-border-radius: 10rem !default; // Modals // Padding applied to the modal body -$modal-inner-padding: 1rem !default; +$modal-inner-padding: 1rem !default; -$modal-dialog-margin: .5rem !default; +$modal-dialog-margin: .5rem !default; $modal-dialog-margin-y-sm-up: 1.75rem !default; -$modal-title-line-height: $line-height-base !default; +$modal-title-line-height: $line-height-base !default; -$modal-content-bg: $white !default; -$modal-content-border-color: rgba($black, .2) !default; -$modal-content-border-width: $border-width !default; -$modal-content-box-shadow-xs: 0 .25rem .5rem rgba($black, .5) !default; +$modal-content-bg: $white !default; +$modal-content-border-color: rgba($black, .2) !default; +$modal-content-border-width: $border-width !default; +$modal-content-box-shadow-xs: 0 .25rem .5rem rgba($black, .5) !default; $modal-content-box-shadow-sm-up: 0 .5rem 1rem rgba($black, .5) !default; -$modal-backdrop-bg: $black !default; -$modal-backdrop-opacity: .5 !default; -$modal-header-border-color: $gray-200 !default; -$modal-footer-border-color: $modal-header-border-color !default; -$modal-header-border-width: $modal-content-border-width !default; -$modal-footer-border-width: $modal-header-border-width !default; -$modal-header-padding: 1rem !default; +$modal-backdrop-bg: $black !default; +$modal-backdrop-opacity: .5 !default; +$modal-header-border-color: $gray-200 !default; +$modal-footer-border-color: $modal-header-border-color !default; +$modal-header-border-width: $modal-content-border-width !default; +$modal-footer-border-width: $modal-header-border-width !default; +$modal-header-padding: 1rem !default; -$modal-lg: 800px !default; -$modal-md: 500px !default; -$modal-sm: 300px !default; +$modal-lg: 800px !default; +$modal-md: 500px !default; +$modal-sm: 300px !default; -$modal-transition: transform .3s ease-out !default; +$modal-transition: transform .3s ease-out !default; // Alerts // // Define alert colors, border radius, and padding. -$alert-padding-y: .75rem !default; -$alert-padding-x: 1.25rem !default; -$alert-margin-bottom: 1rem !default; -$alert-border-radius: $border-radius !default; -$alert-link-font-weight: $font-weight-bold !default; -$alert-border-width: $border-width !default; +$alert-padding-y: .75rem !default; +$alert-padding-x: 1.25rem !default; +$alert-margin-bottom: 1rem !default; +$alert-border-radius: $border-radius !default; +$alert-link-font-weight: $font-weight-bold !default; +$alert-border-width: $border-width !default; -$alert-bg-level: -10 !default; -$alert-border-level: -9 !default; -$alert-color-level: 6 !default; +$alert-bg-level: -10 !default; +$alert-border-level: -9 !default; +$alert-color-level: 6 !default; // Progress bars -$progress-height: 1rem !default; -$progress-font-size: ($font-size-base * .75) !default; -$progress-bg: $gray-200 !default; -$progress-border-radius: $border-radius !default; -$progress-box-shadow: inset 0 .1rem .1rem rgba($black, .1) !default; -$progress-bar-color: $white !default; -$progress-bar-bg: theme-color("primary") !default; -$progress-bar-animation-timing: 1s linear infinite !default; -$progress-bar-transition: width .6s ease !default; +$progress-height: 1rem !default; +$progress-font-size: ($font-size-base * .75) !default; +$progress-bg: $gray-200 !default; +$progress-border-radius: $border-radius !default; +$progress-box-shadow: inset 0 .1rem .1rem rgba($black, .1) !default; +$progress-bar-color: $white !default; +$progress-bar-bg: theme-color("primary") !default; +$progress-bar-animation-timing: 1s linear infinite !default; +$progress-bar-transition: width .6s ease !default; // List group -$list-group-bg: $white !default; -$list-group-border-color: rgba($black, .125) !default; -$list-group-border-width: $border-width !default; -$list-group-border-radius: $border-radius !default; +$list-group-bg: $white !default; +$list-group-border-color: rgba($black, .125) !default; +$list-group-border-width: $border-width !default; +$list-group-border-radius: $border-radius !default; -$list-group-item-padding-y: .75rem !default; -$list-group-item-padding-x: 1.25rem !default; +$list-group-item-padding-y: .75rem !default; +$list-group-item-padding-x: 1.25rem !default; -$list-group-hover-bg: $gray-100 !default; -$list-group-active-color: $component-active-color !default; -$list-group-active-bg: $component-active-bg !default; -$list-group-active-border-color: $list-group-active-bg !default; +$list-group-hover-bg: $gray-100 !default; +$list-group-active-color: $component-active-color !default; +$list-group-active-bg: $component-active-bg !default; +$list-group-active-border-color: $list-group-active-bg !default; -$list-group-disabled-color: $gray-600 !default; -$list-group-disabled-bg: $list-group-bg !default; +$list-group-disabled-color: $gray-600 !default; +$list-group-disabled-bg: $list-group-bg !default; -$list-group-action-color: $gray-700 !default; -$list-group-action-hover-color: $list-group-action-color !default; +$list-group-action-color: $gray-700 !default; +$list-group-action-hover-color: $list-group-action-color !default; -$list-group-action-active-color: $body-color !default; -$list-group-action-active-bg: $gray-200 !default; +$list-group-action-active-color: $body-color !default; +$list-group-action-active-bg: $gray-200 !default; // Image thumbnails -$thumbnail-padding: .25rem !default; -$thumbnail-bg: $body-bg !default; -$thumbnail-border-width: $border-width !default; -$thumbnail-border-color: $gray-300 !default; -$thumbnail-border-radius: $border-radius !default; -$thumbnail-box-shadow: 0 1px 2px rgba($black, .075) !default; +$thumbnail-padding: .25rem !default; +$thumbnail-bg: $body-bg !default; +$thumbnail-border-width: $border-width !default; +$thumbnail-border-color: $gray-300 !default; +$thumbnail-border-radius: $border-radius !default; +$thumbnail-box-shadow: 0 1px 2px rgba($black, .075) !default; // Figures -$figure-caption-font-size: 90% !default; -$figure-caption-color: $gray-600 !default; +$figure-caption-font-size: 90% !default; +$figure-caption-color: $gray-600 !default; // Breadcrumbs -$breadcrumb-padding-y: .75rem !default; -$breadcrumb-padding-x: 1rem !default; -$breadcrumb-item-padding: .5rem !default; +$breadcrumb-padding-y: .75rem !default; +$breadcrumb-padding-x: 1rem !default; +$breadcrumb-item-padding: .5rem !default; -$breadcrumb-margin-bottom: 1rem !default; +$breadcrumb-margin-bottom: 1rem !default; -$breadcrumb-bg: $gray-200 !default; -$breadcrumb-divider-color: $gray-600 !default; -$breadcrumb-active-color: $gray-600 !default; -$breadcrumb-divider: "/" !default; +$breadcrumb-bg: $gray-200 !default; +$breadcrumb-divider-color: $gray-600 !default; +$breadcrumb-active-color: $gray-600 !default; +$breadcrumb-divider: "/" !default; // Carousel -$carousel-control-color: $white !default; -$carousel-control-width: 15% !default; -$carousel-control-opacity: .5 !default; +$carousel-control-color: $white !default; +$carousel-control-width: 15% !default; +$carousel-control-opacity: .5 !default; -$carousel-indicator-width: 30px !default; -$carousel-indicator-height: 3px !default; -$carousel-indicator-spacer: 3px !default; -$carousel-indicator-active-bg: $white !default; +$carousel-indicator-width: 30px !default; +$carousel-indicator-height: 3px !default; +$carousel-indicator-spacer: 3px !default; +$carousel-indicator-active-bg: $white !default; -$carousel-caption-width: 70% !default; -$carousel-caption-color: $white !default; +$carousel-caption-width: 70% !default; +$carousel-caption-color: $white !default; -$carousel-control-icon-width: 20px !default; +$carousel-control-icon-width: 20px !default; -$carousel-control-prev-icon-bg: str-replace(url("data:image/svg+xml;charset=utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='#{$carousel-control-color}' viewBox='0 0 8 8'%3E%3Cpath d='M5.25 0l-4 4 4 4 1.5-1.5-2.5-2.5 2.5-2.5-1.5-1.5z'/%3E%3C/svg%3E"), "#", "%23") !default; -$carousel-control-next-icon-bg: str-replace(url("data:image/svg+xml;charset=utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='#{$carousel-control-color}' viewBox='0 0 8 8'%3E%3Cpath d='M2.75 0l-1.5 1.5 2.5 2.5-2.5 2.5 1.5 1.5 4-4-4-4z'/%3E%3C/svg%3E"), "#", "%23") !default; +$carousel-control-prev-icon-bg: str-replace(url("data:image/svg+xml;charset=utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='#{$carousel-control-color}' viewBox='0 0 8 8'%3E%3Cpath d='M5.25 0l-4 4 4 4 1.5-1.5-2.5-2.5 2.5-2.5-1.5-1.5z'/%3E%3C/svg%3E"), "#", "%23") !default; +$carousel-control-next-icon-bg: str-replace(url("data:image/svg+xml;charset=utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='#{$carousel-control-color}' viewBox='0 0 8 8'%3E%3Cpath d='M2.75 0l-1.5 1.5 2.5 2.5-2.5 2.5 1.5 1.5 4-4-4-4z'/%3E%3C/svg%3E"), "#", "%23") !default; -$carousel-transition: transform .6s ease !default; +$carousel-transition: transform .6s ease !default; // Close -$close-font-size: $font-size-base * 1.5 !default; -$close-font-weight: $font-weight-bold !default; -$close-color: $black !default; -$close-text-shadow: 0 1px 0 $white !default; +$close-font-size: $font-size-base * 1.5 !default; +$close-font-weight: $font-weight-bold !default; +$close-color: $black !default; +$close-text-shadow: 0 1px 0 $white !default; // Code -$code-font-size: 87.5% !default; -$code-color: $pink !default; +$code-font-size: 87.5% !default; +$code-color: $pink !default; -$kbd-padding-y: .2rem !default; -$kbd-padding-x: .4rem !default; -$kbd-font-size: $code-font-size !default; -$kbd-color: $white !default; -$kbd-bg: $gray-900 !default; +$kbd-padding-y: .2rem !default; +$kbd-padding-x: .4rem !default; +$kbd-font-size: $code-font-size !default; +$kbd-color: $white !default; +$kbd-bg: $gray-900 !default; -$pre-color: $gray-900 !default; -$pre-scrollable-max-height: 340px !default; +$pre-color: $gray-900 !default; +$pre-scrollable-max-height: 340px !default; // Printing -$print-page-size: a3 !default; -$print-body-min-width: map-get($grid-breakpoints, "lg") !default; +$print-page-size: a3 !default; +$print-body-min-width: map-get($grid-breakpoints, "lg") !default;