diff --git a/.devcontainer/docker/devcontainer.json b/.devcontainer/docker/devcontainer.json index 6a4e6ae0..51c5240e 100644 --- a/.devcontainer/docker/devcontainer.json +++ b/.devcontainer/docker/devcontainer.json @@ -8,7 +8,8 @@ } }, "mounts": [ - "source=${localEnv:HOME}/.ssh,target=/home/vscode/.ssh,type=bind,consistency=cached" + "source=${localEnv:HOME}/.ssh,target=/home/vscode/.ssh,type=bind,consistency=cached", + "source=/var/run/docker.sock,target=/var/run/docker.sock,type=bind" ], "onCreateCommand": ".devcontainer/install-deps.sh", "customizations": { @@ -31,8 +32,11 @@ // Frontend "esbenp.prettier-vscode", "dbaeumer.vscode-eslint", - "bradlc.vscode-tailwindcss" + "bradlc.vscode-tailwindcss", + "codeandstuff.package-json-upgrade", + // Localization + "inlang.vs-code-extension" ] } } -} +} \ No newline at end of file diff --git a/.vscode/extensions.json b/.vscode/extensions.json new file mode 100644 index 00000000..d89bc64c --- /dev/null +++ b/.vscode/extensions.json @@ -0,0 +1,25 @@ +{ + "recommendations": [ + // coding styles + "chrislajoie.vscode-modelines", + "editorconfig.editorconfig", + // GitHub + "GitHub.vscode-pull-request-github", + "github.vscode-github-actions", + // Golang + "golang.go", + // C / C++ + "ms-vscode.cpptools", + "ms-vscode.cpptools-extension-pack", + // CMake / Makefile + "ms-vscode.makefile-tools", + "ms-vscode.cmake-tools", + // Frontend + "esbenp.prettier-vscode", + "dbaeumer.vscode-eslint", + "bradlc.vscode-tailwindcss", + "codeandstuff.package-json-upgrade", + // Localization + "inlang.vs-code-extension" + ] +} \ No newline at end of file diff --git a/DEVELOPMENT.md b/DEVELOPMENT.md index 964526d6..5c906860 100644 --- a/DEVELOPMENT.md +++ b/DEVELOPMENT.md @@ -97,38 +97,42 @@ tail -f /var/log/jetkvm.log ``` /kvm/ -├── main.go # App entry point -├── config.go # Settings & configuration -├── display.go # Device UI control -├── web.go # API endpoints -├── cmd/ # Command line main -├── internal/ # Internal Go packages -│ ├── confparser/ # Configuration file implementation -│ ├── hidrpc/ # HIDRPC implementation for HID devices (keyboard, mouse, etc.) -│ ├── logging/ # Logging implementation -│ ├── mdns/ # mDNS implementation -│ ├── native/ # CGO / Native code glue layer (on-device hardware) -│ │ ├── cgo/ # C files for the native library (HDMI, Touchscreen, etc.) -│ │ └── eez/ # EEZ Studio Project files (for Touchscreen) -│ ├── network/ # Network implementation -│ ├── timesync/ # Time sync/NTP implementation -│ ├── tzdata/ # Timezone data and generation -│ ├── udhcpc/ # DHCP implementation -│ ├── usbgadget/ # USB gadget -│ ├── utils/ # SSH handling -│ └── websecure/ # TLS certificate management -├── resource/ # netboot iso and other resources -├── scripts/ # Bash shell scripts for building and deploying -└── static/ # (react client build output) -└── ui/ # React frontend - ├── public/ # UI website static images and fonts - └── src/ # Client React UI - ├── assets/ # UI in-page images - ├── components/ # UI components - ├── hooks/ # Hooks (stores, RPC handling, virtual devices) - ├── keyboardLayouts/ # Keyboard layout definitions - ├── providers/ # Feature flags - └── routes/ # Pages (login, settings, etc.) +├── main.go # App entry point +├── config.go # Settings & configuration +├── display.go # Device UI control +├── web.go # API endpoints +├── cmd/ # Command line main +├── internal/ # Internal Go packages +│ ├── confparser/ # Configuration file implementation +│ ├── hidrpc/ # HIDRPC implementation for HID devices (keyboard, mouse, etc.) +│ ├── logging/ # Logging implementation +│ ├── mdns/ # mDNS implementation +│ ├── native/ # CGO / Native code glue layer (on-device hardware) +│ │ ├── cgo/ # C files for the native library (HDMI, Touchscreen, etc.) +│ │ └── eez/ # EEZ Studio Project files (for Touchscreen) +│ ├── network/ # Network implementation +│ ├── timesync/ # Time sync/NTP implementation +│ ├── tzdata/ # Timezone data and generation +│ ├── udhcpc/ # DHCP implementation +│ ├── usbgadget/ # USB gadget +│ ├── utils/ # SSH handling +│ └── websecure/ # TLS certificate management +├── resource/ # netboot iso and other resources +├── scripts/ # Bash shell scripts for building and deploying +└── static/ # (react client build output) +└── ui/ # React frontend + ├── localization/ # Client UI localization (i18n) + │ ├── jetKVM.UI.inlang/ # Settings for inlang + │ └── messages/ # Messages localized + ├── public/ # UI website static images and fonts + └── src/ # Client React UI + ├── assets/ # UI in-page images + ├── components/ # UI components + ├── hooks/ # Hooks (stores, RPC handling, virtual devices) + ├── keyboardLayouts/ # Keyboard layout definitions + │ ├── paraglide/ # (localization compiled messages output) + ├── providers/ # Feature flags + └── routes/ # Pages (login, settings, etc.) ``` **Key files for beginners:** diff --git a/ui/eslint.config.cjs b/ui/eslint.config.cjs index 6e972586..ad4338a3 100644 --- a/ui/eslint.config.cjs +++ b/ui/eslint.config.cjs @@ -9,8 +9,6 @@ const { fixupConfigRules, } = require("@eslint/compat"); -const tsParser = require("@typescript-eslint/parser"); -const reactRefresh = require("eslint-plugin-react-refresh"); const js = require("@eslint/js"); const { @@ -23,6 +21,9 @@ const compat = new FlatCompat({ allConfig: js.configs.all }); +const tsParser = require("@typescript-eslint/parser"); +const reactRefresh = require("eslint-plugin-react-refresh"); + module.exports = defineConfig([{ languageOptions: { globals: { @@ -66,7 +67,7 @@ module.exports = defineConfig([{ groups: ["builtin", "external", "internal", "parent", "sibling"], "newlines-between": "always", }], - + "@typescript-eslint/no-unused-vars": ["warn", { "argsIgnorePattern": "^_", "varsIgnorePattern": "^_" }], @@ -81,7 +82,10 @@ module.exports = defineConfig([{ map: [ ["@components", "./src/components"], ["@routes", "./src/routes"], + ["@hooks", "./src/hooks"], + ["@providers", "./src/providers"], ["@assets", "./src/assets"], + ["@localizations", "./localization/paraglide"], ["@", "./src"], ], diff --git a/ui/index.html b/ui/index.html index 3c6c5606..77936233 100644 --- a/ui/index.html +++ b/ui/index.html @@ -45,31 +45,39 @@ - + - + -
+
diff --git a/ui/localization/jetKVM.UI.inlang/.gitignore b/ui/localization/jetKVM.UI.inlang/.gitignore new file mode 100644 index 00000000..5e465967 --- /dev/null +++ b/ui/localization/jetKVM.UI.inlang/.gitignore @@ -0,0 +1 @@ +cache \ No newline at end of file diff --git a/ui/localization/jetKVM.UI.inlang/project_id b/ui/localization/jetKVM.UI.inlang/project_id new file mode 100644 index 00000000..07e358cc --- /dev/null +++ b/ui/localization/jetKVM.UI.inlang/project_id @@ -0,0 +1 @@ +TI1a2RjjH4qkImNj0w \ No newline at end of file diff --git a/ui/localization/jetKVM.UI.inlang/settings.json b/ui/localization/jetKVM.UI.inlang/settings.json new file mode 100644 index 00000000..efe14c88 --- /dev/null +++ b/ui/localization/jetKVM.UI.inlang/settings.json @@ -0,0 +1,40 @@ +{ + "$schema": "https://inlang.com/schema/project-settings", + "baseLocale": "en", + "sourceLanguageTag": "en", + "locales": [ + "en", + "da", + "de", + "es", + "fr", + "it", + "nb", + "sv", + "zh" + ], + "languageTags": [ + "en", + "da", + "de", + "es", + "fr", + "it", + "nb", + "sv", + "zh" + ], + "modules": [ + "https://cdn.jsdelivr.net/npm/@inlang/plugin-message-format@latest/dist/index.js", + "https://cdn.jsdelivr.net/npm/@inlang/plugin-m-function-matcher@latest/dist/index.js" + ], + "plugin.inlang.messageFormat": { + "pathPattern": "./messages/{locale}.json" + }, + "strategy": [ + "cookie", + "localStorage", + "preferredLanguage", + "baseLocale" + ] +} \ No newline at end of file diff --git a/ui/localization/messages/da.json b/ui/localization/messages/da.json new file mode 100644 index 00000000..50f6c500 --- /dev/null +++ b/ui/localization/messages/da.json @@ -0,0 +1,66 @@ +{ + "$schema": "https://inlang.com/schema/inlang-message-format", + "jetkvm": "JetKVM", + "oh_no": "Åh nej!", + "something_went_wrong": "Noget gik galt. Prøv igen senere, eller kontakt support.", + "jetkvm_logo": "JetKVM-logo", + "load": "Indlæs", + "unknown_error": "Ukendt fejl", + "action_bar_virtual_media": "Virtuelle medier", + "action_bar_paste_text": "Indsæt tekst", + "action_bar_web_terminal": "Webterminal", + "action_bar_wake_on_lan": "Vågn på LAN", + "action_bar_virtual_keyboard": "Virtuelt tastatur", + "action_bar_extension": "Udvidelse", + "action_bar_connection_stats": "Forbindelsesstatistik", + "action_bar_settings": "Indstillinger", + "action_bar_fullscreen": "Fuldskærm", + "action_bar_exit_fullscreen": "Afslut fuldskærm", + "extensions_popover_extensions": "Udvidelser", + "extension_popover_set_error_notification": "Kunne ikke angive aktiv udvidelse: {error}", + "extension_popover_unload_extension": "Fjern udvidelse", + "extension_popover_load_and_manage_extensions": "Indlæs og administrer dine udvidelser", + "extensions_atx_power_control": "ATX-strømstyring", + "extensions_atx_power_control_description": "Styr din maskines strømtilstand via ATX-strømstyring.", + "extensions_dc_power_control": "DC-strømstyring", + "extensions_dc_power_control_description": "Styr din DC-strømforlænger", + "extension_serial_console": "Seriel konsol", + "extension_serial_console_description": "Få adgang til din serielle konsoludvidelse", + "atx_power_control_get_state_error": "Kunne ikke hente ATX-strømtilstand: {error}", + "atx_power_control_send_action_error": "Kunne ikke sende ATX-strømfunktion {action} : {error}", + "atx_power_control_power_button": "Magt", + "atx_power_control_short_power_button": "Kort tryk", + "atx_power_control_long_power_button": "Langt tryk", + "atx_power_control_reset_button": "Nulstil", + "atx_power_control_power_led": "Strøm-LED", + "atx_power_control_hdd_led": "HDD-LED", + "dc_power_control_get_state_error": "Kunne ikke hente DC-strømtilstand: {error}", + "dc_power_control_set_power_state_error": "Kunne ikke sende DC-strømstatus til {enabled} : {error}", + "dc_power_control_set_restore_state_error": "Kunne ikke sende DC-strømgendannelsesstatus til {state} : {error}", + "dc_power_control_power_on_button": "Tænd", + "dc_power_control_power_off_button": "Sluk", + "dc_power_control_restore_power_state": "Gendan strømtab", + "dc_power_control_power_on_state": "Tænd", + "dc_power_control_power_off_state": "Sluk", + "dc_power_control_voltage": "Spænding", + "dc_power_control_voltage_unit": "V", + "dc_power_control_current": "Strøm", + "dc_power_control_current_unit": "A", + "dc_power_control_power": "Magt", + "dc_power_control_power_unit": "W", + "serial_console_get_state_error": "Kunne ikke hente indstillinger for seriel konsol: {error}", + "serial_console_set_power_state_error": "Kunne ikke indstille seriel konsolindstillinger til {settings} : {error}", + "serial_console_configure_description": "Konfigurer dine serielle konsolindstillinger", + "serial_console_open_console": "Åbn konsol", + "serial_console_baud_rate": "Baudhastighed", + "serial_console_data_bits": "Databits", + "serial_console_stop_bits": "Stopbits", + "serial_console_parity": "Paritet", + "serial_console_parity_even": "Lige paritet", + "serial_console_parity_odd": "Ulige paritet", + "serial_console_parity_none": "Ingen paritet", + "serial_console_parity_mark": "Mark Paritet", + "serial_console_parity_space": "Rumparitet", + "serial_console_get_settings_error": "Kunne ikke hente indstillinger for seriel konsol: {error}", + "serial_console_set_settings_error": "Kunne ikke indstille seriel konsolindstillinger til {settings} : {error}" +} \ No newline at end of file diff --git a/ui/localization/messages/de.json b/ui/localization/messages/de.json new file mode 100644 index 00000000..1d427372 --- /dev/null +++ b/ui/localization/messages/de.json @@ -0,0 +1,66 @@ +{ + "$schema": "https://inlang.com/schema/inlang-message-format", + "jetkvm": "JetKVM", + "oh_no": "Oh nein!", + "something_went_wrong": "Ein Fehler ist aufgetreten. Bitte versuchen Sie es später noch einmal oder wenden Sie sich an den Support.", + "jetkvm_logo": "JetKVM Logo", + "load": "Laden", + "unknown_error": "Unbekannter Fehler", + "action_bar_virtual_media": "Virtuelle Medien", + "action_bar_paste_text": "Text einfügen", + "action_bar_web_terminal": "Web-Terminal", + "action_bar_wake_on_lan": "Wake-on-LAN", + "action_bar_virtual_keyboard": "Virtuelle Tastatur", + "action_bar_extension": "Verlängerung", + "action_bar_connection_stats": "Verbindungsstatistiken", + "action_bar_settings": "Einstellungen", + "action_bar_fullscreen": "Vollbild", + "action_bar_exit_fullscreen": "Vollbildmodus beenden", + "extensions_popover_extensions": "Erweiterungen", + "extension_popover_set_error_notification": "Fehler beim Festlegen der aktiven Erweiterung: {error}", + "extension_popover_unload_extension": "Erweiterung entladen", + "extension_popover_load_and_manage_extensions": "Laden und verwalten Sie Ihre Erweiterungen", + "extensions_atx_power_control": "ATX-Stromsteuerung", + "extensions_atx_power_control_description": "Steuern Sie den Energiezustand Ihrer Maschine über die ATX-Energiesteuerung.", + "extensions_dc_power_control": "Gleichstromsteuerung", + "extensions_dc_power_control_description": "Steuern Sie Ihre DC-Stromerweiterung", + "extension_serial_console": "Serielle Konsole", + "extension_serial_console_description": "Greifen Sie auf Ihre serielle Konsolenerweiterung zu", + "atx_power_control_get_state_error": "ATX-Stromversorgungsstatus konnte nicht abgerufen werden: {error}", + "atx_power_control_send_action_error": "ATX-Stromversorgungsaktion {action} konnte nicht gesendet werden: {error}", + "atx_power_control_power_button": "Leistung", + "atx_power_control_short_power_button": "Kurzes Drücken", + "atx_power_control_long_power_button": "Langes Drücken", + "atx_power_control_reset_button": "Zurücksetzen", + "atx_power_control_power_led": "Betriebs-LED", + "atx_power_control_hdd_led": "Festplatten-LED", + "dc_power_control_get_state_error": "Der Gleichstromstatus konnte nicht abgerufen werden: {error}", + "dc_power_control_set_power_state_error": "Der DC-Stromversorgungsstatus konnte nicht an {enabled} werden: {error}", + "dc_power_control_set_restore_state_error": "Der Status zur Wiederherstellung der Gleichstromversorgung konnte nicht an {state} gesendet werden: {error}", + "dc_power_control_power_on_button": "Einschalten", + "dc_power_control_power_off_button": "Ausschalten", + "dc_power_control_restore_power_state": "Wiederherstellung nach Stromausfall", + "dc_power_control_power_on_state": "Einschalten", + "dc_power_control_power_off_state": "Ausschalten", + "dc_power_control_voltage": "Stromspannung", + "dc_power_control_voltage_unit": "V", + "dc_power_control_current": "Aktuell", + "dc_power_control_current_unit": "A", + "dc_power_control_power": "Leistung", + "dc_power_control_power_unit": "W", + "serial_console_get_state_error": "Die seriellen Konsoleneinstellungen konnten nicht abgerufen werden: {error}", + "serial_console_set_power_state_error": "Die Einstellungen der seriellen Konsole konnten nicht auf {settings} festgelegt werden: {error}", + "serial_console_configure_description": "Konfigurieren Sie die Einstellungen Ihrer seriellen Konsole", + "serial_console_open_console": "Konsole öffnen", + "serial_console_baud_rate": "Baudrate", + "serial_console_data_bits": "Datenbits", + "serial_console_stop_bits": "Stoppbits", + "serial_console_parity": "Parität", + "serial_console_parity_even": "Gerade Parität", + "serial_console_parity_odd": "Ungerade Parität", + "serial_console_parity_none": "Keine Parität", + "serial_console_parity_mark": "Parität markieren", + "serial_console_parity_space": "Raumparität", + "serial_console_get_settings_error": "Die seriellen Konsoleneinstellungen konnten nicht abgerufen werden: {error}", + "serial_console_set_settings_error": "Die Einstellungen der seriellen Konsole konnten nicht auf {settings} festgelegt werden: {error}" +} \ No newline at end of file diff --git a/ui/localization/messages/en.json b/ui/localization/messages/en.json new file mode 100644 index 00000000..b38d1c64 --- /dev/null +++ b/ui/localization/messages/en.json @@ -0,0 +1,726 @@ +{ + "$schema": "https://inlang.com/schema/inlang-message-format", + "access_adopt_kvm": "Adopt KVM to Cloud", + "access_adopted_message": "Your device is adopted to the Cloud", + "access_auth_mode_no_password": "Current mode: No password", + "access_auth_mode_password": "Current mode: Password protected", + "access_authentication_mode_title": "Authentication Mode", + "access_certificate_label": "Certificate", + "access_change_password_button": "Change Password", + "access_change_password_description": "Update your device access password", + "access_change_password_title": "Change Password", + "access_cloud_api_url_label": "Cloud API URL", + "access_cloud_app_url_label": "Cloud Application URL", + "access_cloud_provider_description": "Select the cloud provider for your device", + "access_cloud_provider_title": "Cloud Provider", + "access_cloud_security_title": "Cloud Security", + "access_confirm_deregister": "Are you sure you want to de-register this device?", + "access_deregister": "De-register from Cloud", + "access_description": "Manage the Access Control of the device", + "access_disable_protection": "Disable Protection", + "access_enable_password": "Enable Password", + "access_failed_deregister": "Failed to de-register device: {error}", + "access_failed_update_cloud_url": "Failed to update cloud URL: {error}", + "access_failed_update_tls": "Failed to update TLS settings: {error}", + "access_github_link": "GitHub", + "access_https_description": "Configure secure HTTPS access to your device", + "access_https_mode_title": "HTTPS Mode", + "access_learn_security": "Learn about our cloud security", + "access_local_description": "Manage the mode of local access to the device", + "access_local_title": "Local", + "access_no_device_id": "No device ID available", + "access_private_key_description": "For security reasons, it will not be displayed after saving.", + "access_private_key_label": "Private Key", + "access_provider_custom": "Custom", + "access_provider_jetkvm": "JetKVM Cloud", + "access_remote_description": "Manage the mode of Remote access to the device", + "access_security_encryption": "End-to-end encryption using WebRTC (DTLS and SRTP)", + "access_security_oidc": "OIDC (OpenID Connect) authentication", + "access_security_open_source": "All cloud components are open-source and available on GitHub.", + "access_security_streams": "All streams encrypted in transit", + "access_security_zero_trust": "Zero Trust security model", + "access_title": "Access", + "access_tls_certificate_description": "Paste your TLS certificate below. For certificate chains, include the entire chain (leaf, intermediate, and root certificates).", + "access_tls_certificate_title": "TLS Certificate", + "access_tls_custom": "Custom", + "access_tls_disabled": "Disabled", + "access_tls_self_signed": "Self-signed", + "access_tls_updated": "TLS settings updated successfully", + "access_update_tls_settings": "Update TLS Settings", + "action_bar_connection_stats": "Connection Stats", + "action_bar_exit_fullscreen": "Exit Fullscreen", + "action_bar_extension": "Extension", + "action_bar_fullscreen": "Fullscreen", + "action_bar_paste_text": "Paste text", + "action_bar_settings": "Settings", + "action_bar_virtual_keyboard": "Virtual Keyboard", + "action_bar_virtual_media": "Virtual Media", + "action_bar_wake_on_lan": "Wake on LAN", + "action_bar_web_terminal": "Web Terminal", + "advanced_description": "Access additional settings for troubleshooting and customization", + "advanced_dev_channel_description": "Receive early updates from the development channel", + "advanced_dev_channel_title": "Dev Channel Updates", + "advanced_developer_mode_description": "Enable advanced features for developers", + "advanced_developer_mode_enabled_title": "Developer Mode Enabled", + "advanced_developer_mode_title": "Developer Mode", + "advanced_developer_mode_warning_advanced": "For advanced users only. Not for production use.", + "advanced_developer_mode_warning_risks": "Only use if you understand the risks", + "advanced_developer_mode_warning_security": "Security is weakened while active", + "advanced_disable_usb_emulation": "Disable USB Emulation", + "advanced_enable_usb_emulation": "Enable USB Emulation", + "advanced_error_loopback_disable": "Failed to disable loopback-only mode: {error}", + "advanced_error_loopback_enable": "Failed to enable loopback-only mode: {error}", + "advanced_error_reset_config": "Failed to reset configuration: {error}", + "advanced_error_set_dev_channel": "Failed to set dev channel state: {error}", + "advanced_error_set_dev_mode": "Failed to set dev mode: {error}", + "advanced_error_update_ssh_key": "Failed to update SSH key: {error}", + "advanced_error_usb_emulation_disable": "Failed to disable USB emulation: {error}", + "advanced_error_usb_emulation_enable": "Failed to enable USB emulation: {error}", + "advanced_loopback_only_description": "Restrict web interface access to localhost only (127.0.0.1)", + "advanced_loopback_only_title": "Loopback-Only Mode", + "advanced_loopback_warning_before": "Before enabling this feature, make sure you have either:", + "advanced_loopback_warning_cloud": "Cloud access enabled and working", + "advanced_loopback_warning_confirm": "I Understand, Enable Anyway", + "advanced_loopback_warning_description": "WARNING: This will restrict web interface access to localhost (127.0.0.1) only.", + "advanced_loopback_warning_ssh": "SSH access configured and tested", + "advanced_loopback_warning_title": "Enable Loopback-Only Mode?", + "advanced_reset_config_button": "Reset Config", + "advanced_reset_config_description": "Reset configuration to default. This will log you out.", + "advanced_reset_config_title": "Reset Configuration", + "advanced_ssh_access_description": "Add your SSH public key to enable secure remote access to the device", + "advanced_ssh_access_title": "SSH Access", + "advanced_ssh_default_user": "The default SSH user is", + "advanced_ssh_public_key_label": "SSH Public Key", + "advanced_ssh_public_key_placeholder": "Enter your SSH public key", + "advanced_success_loopback_disabled": "Loopback-only mode disabled. Restart your device to apply.", + "advanced_success_loopback_enabled": "Loopback-only mode enabled. Restart your device to apply.", + "advanced_success_reset_config": "Configuration reset to default successfully", + "advanced_success_update_ssh_key": "SSH key updated successfully", + "advanced_title": "Advanced", + "advanced_troubleshooting_mode_description": "Diagnostic tools and additional controls for troubleshooting and development purposes", + "advanced_troubleshooting_mode_title": "Troubleshooting Mode", + "advanced_update_ssh_key_button": "Update SSH Key", + "advanced_usb_emulation_description": "Control the USB emulation state", + "advanced_usb_emulation_title": "USB Emulation", + "already_adopted_new_owner": "If you're the new owner, please ask the previous owner to de-register the device from their account in the cloud dashboard. If you believe this is an error, contact our support team for assistance.", + "already_adopted_other_user": "This device is currently registered to another user in our cloud dashboard.", + "already_adopted_return_to_dashboard": "Return to Dashboard", + "already_adopted_title": "Device Already Registered", + "appearance_description": "Choose your preferred color theme", + "appearance_page_description": "Customize the look and feel of your JetKVM interface", + "appearance_theme_dark": "Dark", + "appearance_theme_light": "Light", + "appearance_theme_system": "System", + "appearance_theme": "Theme", + "appearance_title": "Appearance", + "attach": "Attach", + "atx_power_control_get_state_error": "Failed to get ATX power state: {error}", + "atx_power_control_hdd_led": "HDD LED", + "atx_power_control_long_power_button": "Long Press", + "atx_power_control_power_button": "Power", + "atx_power_control_power_led": "Power LED", + "atx_power_control_reset_button": "Reset", + "atx_power_control_send_action_error": "Failed to send ATX power action {action}: {error}", + "atx_power_control_short_power_button": "Short Press", + "auth_authentication_mode_error": "An error occurred while setting the authentication mode", + "auth_authentication_mode_invalid": "Invalid authentication mode", + "auth_authentication_mode": "Please select an authentication mode", + "auth_connect_to_cloud_action": "Log in & Connect device", + "auth_connect_to_cloud_description": "Unlock remote access and advanced features for your device", + "auth_connect_to_cloud": "Connect your JetKVM to the cloud", + "auth_header_cta_already_have_account": "Already have an account?", + "auth_header_cta_dont_have_account": "Don't have an account?", + "auth_header_cta_new_to_jetkvm": "New to JetKVM?", + "auth_login_action": "Log in", + "auth_login_description": "Log in to access and manage your devices securely", + "auth_login": "Log in to your JetKVM account", + "auth_mode_local_change_later": "You can always change your authentication method later in the settings.", + "auth_mode_local_description": "Select how you would like to secure your JetKVM device locally.", + "auth_mode_local_no_password_description": "Quick access without password authentication.", + "auth_mode_local_no_password": "No Password", + "auth_mode_local_password_confirm_description": "Confirm your password", + "auth_mode_local_password_confirm_label": "Confirm Password", + "auth_mode_local_password_description": "Secure your device with a password for added protection.", + "auth_mode_local_password_do_not_match": "Passwords do not match", + "auth_mode_local_password_failed_set": "Failed to set password: {error}", + "auth_mode_local_password_note_local": "All data remains on your local device.", + "auth_mode_local_password_note": "This password will be used to secure your device data and protect against unauthorized access.", + "auth_mode_local_password_set_button": "Set Password", + "auth_mode_local_password_set_description": "Create a strong password to secure your JetKVM device locally.", + "auth_mode_local_password_set_label": "Enter a password", + "auth_mode_local_password_set": "Set a Password", + "auth_mode_local_password": "Password", + "auth_mode_local": "Local Authentication Method", + "auth_signup_connect_to_cloud_action": "Signup & Connect device", + "auth_signup_create_account_action": "Create Account", + "auth_signup_create_account_description": "Create your account and start managing your devices with ease.", + "auth_signup_create_account": "Create your JetKVM account", + "back_to_devices": "Back to Devices", + "back": "Back", + "cancel": "Cancel", + "close": "Close", + "cloud_kvms_description": "Manage your cloud KVMs and connect to them securely.", + "cloud_kvms_no_devices_description": "You don't have any devices with enabled JetKVM Cloud yet.", + "cloud_kvms_no_devices": "No devices found", + "cloud_kvms": "Cloud KVMs", + "confirm": "Confirm", + "connect_to_kvm": "Connect to KVM", + "connecting_to_device": "Connecting to device…", + "connection_established": "Connection established", + "connection_stats_badge_jitter_buffer_avg_delay": "Jitter Buffer Avg. Delay", + "connection_stats_badge_jitter": "Jitter", + "connection_stats_connection_description": "The connection between the client and the JetKVM.", + "connection_stats_connection": "Connection", + "connection_stats_frames_per_second_description": "Number of inbound video frames displayed per second.", + "connection_stats_frames_per_second": "Frames per second", + "connection_stats_network_stability_description": "How steady the flow of inbound video packets is across the network.", + "connection_stats_network_stability": "Network Stability", + "connection_stats_packets_lost_description": "Count of lost inbound video RTP packets.", + "connection_stats_packets_lost": "Packets Lost", + "connection_stats_playback_delay_description": "Delay added by the jitter buffer to smooth playback when frames arrive unevenly.", + "connection_stats_playback_delay": "Playback Delay", + "connection_stats_round_trip_time_description": "Round-trip time for the active ICE candidate pair between peers.", + "connection_stats_round_trip_time": "Round-Trip Time", + "connection_stats_sidebar": "Connection Stats", + "connection_stats_video_description": "The video stream from the JetKVM to the client.", + "connection_stats_video": "Video", + "continue": "Continue", + "creating_peer_connection": "Creating peer connection…", + "dc_power_control_current_unit": "A", + "dc_power_control_current": "Current", + "dc_power_control_get_state_error": "Failed to get DC power state: {error}", + "dc_power_control_power_off_button": "Power Off", + "dc_power_control_power_off_state": "Power OFF", + "dc_power_control_power_on_button": "Power On", + "dc_power_control_power_on_state": "Power ON", + "dc_power_control_power_unit": "W", + "dc_power_control_power": "Power", + "dc_power_control_restore_last_state": "Last State", + "dc_power_control_restore_power_state": "Restore Power Loss", + "dc_power_control_set_power_state_error": "Failed to send DC power state to {enabled}: {error}", + "dc_power_control_set_restore_state_error": "Failed to send DC power restore state to {state}: {error}", + "dc_power_control_voltage_unit": "V", + "dc_power_control_voltage": "Voltage", + "default": "Default", + "delete": "Delete", + "deregister_button": "Deregister from Cloud", + "deregister_cloud_devices": "Cloud Devices", + "deregister_description": "This will remove the device from your cloud account and revoke remote access to it. Please note that local access will still be possible", + "deregister_error": "There was an error {status} deregistering your device. Please try again.", + "deregister_from_cloud": "Deregister from cloud", + "deregister_headline": "Deregister {device} from your cloud account", + "detach": "Detach", + "dhcp_lease_boot_file": "Boot File", + "dhcp_lease_boot_next_server": "Boot Next Server", + "dhcp_lease_boot_server_name": "Boot Server Name", + "dhcp_lease_broadcast": "Broadcast", + "dhcp_lease_domain": "Domain", + "dhcp_lease_gateway": "Gateway", + "dhcp_lease_header": "DHCP Lease Information", + "dhcp_lease_hostname": "Hostname", + "dhcp_lease_lease_expires": "Lease Expires", + "dhcp_lease_maximum_transfer_unit": "MTU", + "dhcp_lease_renew": "Renew DHCP Lease", + "dhcp_lease_time_to_live": "TTL", + "dhcp_server": "DHCP Server", + "dns_servers": "DNS Servers", + "establishing_secure_connection": "Establishing secure connection…", + "experimental": "Experimental", + "extension_popover_load_and_manage_extensions": "Load and manage your extensions", + "extension_popover_set_error_notification": "Failed to set active extension: {error}", + "extension_popover_unload_extension": "Unload Extension", + "extension_serial_console_description": "Access your serial console extension", + "extension_serial_console": "Serial Console", + "extensions_atx_power_control_description": "Control the power state of your machine via ATX power control.", + "extensions_atx_power_control": "ATX Power Control", + "extensions_dc_power_control_description": "Control your DC Power extension", + "extensions_dc_power_control": "DC Power Control", + "extensions_popover_extensions": "Extensions", + "gathering_ice_candidates": "Gathering ICE candidates…", + "general_app_version": "App: {version}", + "general_auto_update_description": "Automatically update the device to the latest version", + "general_auto_update_error": "Failed to set auto-update: {error}", + "general_auto_update_title": "Auto Update", + "general_check_for_updates": "Check for Updates", + "general_page_description": "Configure device settings and update preferences", + "general_reboot_description": "Do you want to proceed with rebooting the system?", + "general_reboot_device_description": "Power cycle the JetKVM", + "general_reboot_device": "Reboot Device", + "general_reboot_no_button": "No", + "general_reboot_title": "Reboot JetKVM", + "general_reboot_yes_button": "Yes", + "general_system_version": "System: {version}", + "general_title": "General", + "general_update_app_update_title": "App Update", + "general_update_application_type": "App", + "general_update_available_description": "A new update is available to enhance system performance and improve compatibility. We recommend updating to ensure everything runs smoothly.", + "general_update_available_title": "Update available", + "general_update_background_button": "Update in Background", + "general_update_check_again_button": "Check Again", + "general_update_checking_description": "We're ensuring your device has the latest features and improvements.", + "general_update_checking_title": "Checking for updates…", + "general_update_completed_description": "Your device has been successfully updated to the latest version. Enjoy the new features and improvements!", + "general_update_completed_title": "Update Completed Successfully", + "general_update_error_description": "An error occurred while updating your device. Please try again later.", + "general_update_error_details": "Error details: {errorMessage}", + "general_update_error_title": "Update Error", + "general_update_later_button": "Do it later", + "general_update_now_button": "Update Now", + "general_update_rebooting": "Rebooting to complete the update…", + "general_update_status_awaiting_reboot": "Awaiting reboot", + "general_update_status_downloading": "Downloading {update_type} update…", + "general_update_status_fetching": "Fetching update information…", + "general_update_status_installing": "Installing {update_type} update…", + "general_update_status_verifying": "Verifying {update_type} update…", + "general_update_system_type": "System", + "general_update_system_update_title": "Linux System Update", + "general_update_up_to_date_description": "Your system is running the latest version. No updates are currently available.", + "general_update_up_to_date_title": "System is up to date", + "general_update_updating_description": "Please don't turn off your device. This process may take a few minutes.", + "general_update_updating_title": "Updating your device", + "getting_remote_session_description": "Getting remote session description attempt {attempt}", + "hardware_backlight_settings_error": "Failed to set backlight settings: {error}", + "hardware_backlight_settings_get_error": "Failed to get backlight settings: {error}", + "hardware_backlight_settings_success": "Backlight settings updated successfully", + "hardware_dim_display_after_description": "Set how long to wait before dimming the display", + "hardware_dim_display_after_title": "Dim Display After", + "hardware_display_brightness_description": "Set the brightness of the display", + "hardware_display_brightness_high": "High", + "hardware_display_brightness_low": "Low", + "hardware_display_brightness_medium": "Medium", + "hardware_display_brightness_off": "Off", + "hardware_display_brightness_title": "Display Brightness", + "hardware_display_orientation_description": "Set the orientation of the display", + "hardware_display_orientation_error": "Failed to set display orientation: {error}", + "hardware_display_orientation_inverted": "Inverted", + "hardware_display_orientation_normal": "Normal", + "hardware_display_orientation_success": "Display orientation updated successfully", + "hardware_display_orientation_title": "Display Orientation", + "hardware_display_wake_up_note": "The display will wake up when the connection state changes, or when touched.", + "hardware_page_description": "Configure display settings and hardware options for your JetKVM device", + "hardware_time_1_hour": "1 Hour", + "hardware_time_1_minute": "1 Minute", + "hardware_time_10_minutes": "10 Minutes", + "hardware_time_30_minutes": "30 Minutes", + "hardware_time_5_minutes": "5 Minutes", + "hardware_time_never": "Never", + "hardware_title": "Hardware", + "hardware_turn_off_display_after_description": "Period of inactivity before display automatically turns off", + "hardware_turn_off_display_after_title": "Turn off Display After", + "hide": "Hide", + "ice_gathering_completed": "ICE Gathering completed", + "info_caps_lock": "Caps Lock", + "info_compose": "Compose", + "info_hdmi_state": "HDMI State:", + "info_hidrpc_state": "HidRPC State:", + "info_kana": "Kana", + "info_keys": "Keys:", + "info_last_move": "Last Move:", + "info_num_lock": "Num Lock", + "info_paste_enabled": "Enabled", + "info_paste_mode": "Paste Mode:", + "info_pointer": "Pointer:", + "info_relayed_by_cloudflare": "Relayed by Cloudflare", + "info_resolution": "Resolution:", + "info_scroll_lock": "Scroll Lock", + "info_shift": "Shift", + "info_usb_state": "USB State:", + "info_video_size": "Video Size:", + "input_disabled": "Input disabled", + "invalid_password": "Invalid password", + "ip_address": "IP Address", + "ipv6_address_label": "Address", + "ipv6_addresses": "IPv6 Addresses", + "ipv6_information": "IPv6 Information", + "ipv6_link_local": "Link-local", + "ipv6_preferred_lifetime": "Preferred Lifetime", + "ipv6_valid_lifetime": "Valid Lifetime", + "jetkvm_description": "JetKVM combines powerful hardware with intuitive software to provide a seamless remote control experience.", + "jetkvm_device": "JetKVM Device", + "jetkvm_logo": "JetKVM Logo", + "jetkvm_setup": "Set up your JetKVM", + "jetkvm": "JetKVM", + "jiggler_cron_schedule_description": "Cron expression for scheduling", + "jiggler_cron_schedule_label": "Cron Schedule", + "jiggler_example_business_hours_early": "Business Hours 8-17", + "jiggler_example_business_hours_late": "Business Hours 9-17", + "jiggler_examples_label": "Examples", + "jiggler_inactivity_limit_description": "Inactivity time before jiggle", + "jiggler_inactivity_limit_label": "Inactivity Limit Seconds", + "jiggler_more_examples": "More examples", + "jiggler_random_delay_description": "To avoid recognizable patterns", + "jiggler_random_delay_label": "Random delay", + "jiggler_save_jiggler_config": "Save Jiggler Config", + "jiggler_timezone_description": "Timezone for cron schedule", + "jiggler_timezone_label": "Timezone", + "keyboard_description": "Configure keyboard settings for your device", + "keyboard_layout_description": "Keyboard layout of target operating system", + "keyboard_layout_error": "Failed to set keyboard layout: {error}", + "keyboard_layout_long_description": "The virtual keyboard, paste text, and keyboard macros send individual key strokes to the target device. The keyboard layout determines which key codes are being sent. Ensure that the keyboard layout in JetKVM matches the settings in the operating system.", + "keyboard_layout_success": "Keyboard layout set successfully to {layout}", + "keyboard_layout_title": "Keyboard Layout", + "keyboard_show_pressed_keys_description": "Display currently pressed keys in the status bar", + "keyboard_show_pressed_keys_title": "Show Pressed Keys", + "keyboard_title": "Keyboard", + "kvm_terminal": "KVM Terminal", + "last_online": "Last online {time}", + "learn_more": "Learn more", + "load": "Load", + "loading": "Loading…", + "local_auth_change_local_device_password_description": "Enter your current password and a new password to update your local device protection.", + "local_auth_change_local_device_password_title": "Change Local Device Password", + "local_auth_confirm_new_password_label": "Confirm New Password", + "local_auth_create_confirm_password_label": "Confirm New Password", + "local_auth_create_confirm_password_placeholder": "Re-enter your password", + "local_auth_create_description": "Create a password to protect your device from unauthorized local access.", + "local_auth_create_new_password_label": "New Password", + "local_auth_create_new_password_placeholder": "Enter a strong password", + "local_auth_create_not_now_button": "Not Now", + "local_auth_create_secure_button": "Secure Device", + "local_auth_create_title": "Local Device Protection", + "local_auth_current_password_label": "Current Password", + "local_auth_disable_local_device_protection_description": "Enter your current password to disable local device protection.", + "local_auth_disable_local_device_protection_title": "Disable Local Device Protection", + "local_auth_disable_protection_button": "Disable Protection", + "local_auth_enter_current_password_placeholder": "Enter your current password", + "local_auth_enter_new_password_placeholder": "Enter a new strong password", + "local_auth_error_changing_password": "An error occurred while changing the password", + "local_auth_error_disabling_password": "An error occurred while disabling the password", + "local_auth_error_enter_current_password": "Please enter your current password", + "local_auth_error_enter_new_password": "Please enter a new password", + "local_auth_error_enter_old_password": "Please enter your old password", + "local_auth_error_enter_password": "Please enter a password", + "local_auth_error_passwords_not_match": "Passwords do not match", + "local_auth_error_setting_password": "An error occurred while setting the password", + "local_auth_new_password_label": "New Password", + "local_auth_reenter_new_password_placeholder": "Re-enter your new password", + "local_auth_success_password_disabled_description": "You've successfully disabled the password protection for local access. Remember, your device is now less secure.", + "local_auth_success_password_disabled_title": "Password Protection Disabled", + "local_auth_success_password_set_description": "You've successfully set up local device protection. Your device is now secure against unauthorized local access.", + "local_auth_success_password_set_title": "Password Set Successfully", + "local_auth_success_password_updated_description": "You've successfully changed your local device protection password. Make sure to remember your new password for future access.", + "local_auth_success_password_updated_title": "Password Updated Successfully", + "local_auth_update_confirm_password_label": "Confirm New Password", + "local_auth_update_current_password_label": "Current Password", + "local_auth_update_description": "Enter your current password and a new password to update your local device protection.", + "local_auth_update_new_password_label": "New Password", + "local_auth_update_password_button": "Update Password", + "local_auth_update_title": "Change Local Device Password", + "log_in": "Log In", + "log_out": "Log out", + "logged_in_as": "Logged in as", + "login_enter_password_description": "Enter your password to access your JetKVM.", + "login_enter_password": "Enter your password", + "login_error": "An error occurred while logging in", + "login_forgot_password": "Forgot password?", + "login_password_label": "Password", + "login_welcome_back": "Welcome back to JetKVM", + "macro_add_step": "Add Step{maxed_out}", + "macro_at_least_one_step_keys_or_modifiers": "At least one step must have keys or modifiers", + "macro_at_least_one_step_required": "At least one step is required", + "macro_max_steps_error": "You can only add a maximum of {max} steps per macro.", + "macro_max_steps_reached": "({max} max)", + "macro_name_label": "Macro Name", + "macro_name_required": "Name is required", + "macro_name_too_long": "Name must be less than 50 characters", + "macro_please_fix_validation_errors": "Please fix the validation errors", + "macro_save_error": "An error occurred while saving.", + "macro_save": "Save Macro", + "macro_step_count": "{steps} / {max} steps", + "macro_step_duration_description": "Time to wait before executing the next step.", + "macro_step_duration_label": "Step Duration", + "macro_step_keys_description": "Maximum {max} keys per step.", + "macro_step_keys_label": "Keys", + "macro_step_max_keys_reached": "Maximum keys reached", + "macro_step_modifiers_description": "What modifiers (Shift/Ctrl/Alt/Meta) are pressed during this step.", + "macro_step_modifiers_label": "Modifiers", + "macro_step_no_matching_keys_found": "No matching keys found", + "macro_step_search_for_key": "Search for key…", + "macro_steps_description": "Keys/modifiers executed in sequence with a delay between each step.", + "macro_steps_label": "Steps", + "macros_add_description": "Create a new keyboard macro", + "macros_add_new": "Add New Macro", + "macros_create_first": "Create your first macro to get started", + "macros_created_success": "Macro \"{name}\" created successfully", + "macros_delete_confirm": "Are you sure you want to delete this macro? This action cannot be undone.", + "macros_delete_macro": "Delete Macro", + "macros_deleted_success": "Macro \"{name}\" deleted successfully", + "macros_deleting": "Deleting", + "macros_duplicate": "Duplicate", + "macros_duplicated_success": "Macro \"{name}\" duplicated successfully", + "macros_edit_description": "Modify your keyboard macro", + "macros_edit_title": "Edit Macro", + "macros_edit": "Edit", + "macros_failed_create": "Failed to create macro", + "macros_failed_create_error": "Failed to create macro: {error}", + "macros_failed_delete": "Failed to delete macro", + "macros_failed_delete_error": "Failed to delete macro: {error}", + "macros_failed_duplicate": "Failed to duplicate macro", + "macros_failed_duplicate_error": "Failed to duplicate macro: {error}", + "macros_failed_reorder": "Failed to reorder macros", + "macros_failed_reorder_error": "Failed to reorder macros: {error}", + "macros_failed_update": "Failed to update macro", + "macros_failed_update_error": "Failed to update macro: {error}", + "macros_invalid_data": "Invalid macro data", + "macros_maximum_macros_reached": "You have reached the maximum number of {maximum} macros allowed.", + "macros_move_down": "Move Down", + "macros_move_up": "Move Up", + "macros_no_macros_available": "No macros available", + "macros_no_macros_found": "No macros found", + "macros_order_updated": "Macro order updated successfully", + "macros_title": "Keyboard Macros", + "macros_updated_success": "Macro \"{name}\" updated successfully", + "macros_aria_delete": "Delete macro {name}", + "macros_aria_duplicate": "Duplicate macro {name}", + "macros_aria_edit": "Edit macro {name}", + "macros_aria_move_down": "Move {name} down", + "macros_aria_move_up": "Move {name} up", + "macros_confirm_delete_description": "Are you sure you want to delete \"{name}\"? This action cannot be undone.", + "macros_confirm_delete_title": "Delete Macro", + "macros_confirm_deleting": "Deleting…", + "macros_add_new_macro": "Add New Macro", + "macros_aria_add_new": "Add new macro", + "macros_create_first_headline": "Create Your First Macro", + "macros_create_first_description": "Combine keystrokes into a single action", + "macros_delay_only": "Delay only", + "macros_edit_button": "Edit", + "macros_loading": "Loading macros…", + "macros_max_reached": "Max Reached", + "metric_not_supported": "Metric not supported", + "metric_waiting_for_data": "Waiting for data…", + "mount_add_file_to_get_started": "Add a file to get started", + "mount_add_new_media": "Add New Media", + "mount_available_storage": "Available Storage", + "mount_button_back_to_overview": "Back to Overview", + "mount_button_cancel_upload": "Cancel Upload", + "mount_button_continue_upload": "Continue uploading", + "mount_button_mount_file": "Mount File", + "mount_button_mount_url": "Mount URL", + "mount_button_next": "Next", + "mount_button_previous": "Previous", + "mount_button_select": "Select", + "mount_button_showing_results": "Showing {from} to {to} of {total} results", + "mount_button_upload_new_image": "Upload a new image", + "mount_bytes_free": "{bytesFree} free", + "mount_bytes_used": "{bytesUsed} used", + "mount_calculating": "Calculating…", + "mount_click_to_select_file": "Click to select a file", + "mount_click_to_select_incomplete": "Click to select \"{name}\"", + "mount_confirm_delete": "Are you sure you want to delete {name}?", + "mount_continue_uploading_with_name": "Continue uploading \"{name}\"", + "mount_description_mode": "Choose how you want to mount your virtual media", + "mount_error_delete_file": "Error deleting file: {error}", + "mount_error_description": "An error occurred while attempting to mount the media. Please try again.", + "mount_error_get_storage_space": "Error getting storage space: {error}", + "mount_error_list_storage": "Error listing storage files: {error}", + "mount_error_title": "Mount Error", + "mount_get_state_error": "Failed to get virtual media state: {error}", + "mount_jetkvm_storage_description": "Mount previously uploaded files from the JetKVM storage", + "mount_jetkvm_storage": "JetKVM Storage Mount", + "mount_label_mount_as": "Mount as", + "mount_label_url_description": "Mount files from any public web address", + "mount_label_url": "URL Mount", + "mount_mode_cdrom": "CD/DVD", + "mount_mode_disk": "Disk", + "mount_mounted_as": "Mounted as", + "mount_mounted_from_storage": "Mounted from JetKVM Storage", + "mount_no_images_description": "Upload an image to start virtual media mounting.", + "mount_no_images_title": "No images available", + "mount_no_mounted_media": "No mounted media", + "mount_percentage_used": "{percentageUsed}% used", + "mount_please_select_file_to_upload": "Please select the file to upload.", + "mount_please_select_file": "Please select the file \"{name}\" to continue the upload.", + "mount_popular_images": "Popular images", + "mount_streaming_from_url": "Streaming from URL", + "mount_supported_formats": "Supported formats: ISO, IMG", + "mount_tag_experimental": "Experimental", + "mount_title_mode": "Virtual Media Source", + "mount_unmount_error": "Failed to unmount image: {error}", + "mount_unmount": "Unmount", + "mount_upload_description": "Select an image file to upload to JetKVM storage", + "mount_upload_error": "Upload error: {error}", + "mount_upload_failed_datachannel": "Failed to create data channel for file upload", + "mount_upload_failed_rtc": "Upload failed: {error}", + "mount_upload_successful": "Upload successful", + "mount_upload_title": "Upload New Image", + "mount_uploaded_has_been_uploaded": "{name} has been uploaded", + "mount_uploading_with_name": "Uploading {name}", + "mount_uploading": "Uploading…", + "mount_url_description": "Mount files from any public web address", + "mount_url_input_label": "Image URL", + "mount_url_mount": "URL Mount", + "mount_view_device_description": "Select an image to mount from the JetKVM storage", + "mount_view_device_title": "Mount from JetKVM Storage", + "mount_view_url_description": "Enter an URL to the image file to mount", + "mount_view_url_title": "Mount from URL", + "mount_virtual_media_description": "Mount an image to boot from or install an operating system.", + "mount_virtual_media_source_description": "Choose how you want to mount your virtual media", + "mount_virtual_media_source": "Virtual Media Source", + "mount_virtual_media": "Virtual Media", + "never_seen_online": "Never seen online", + "next": "Next", + "no_results_found": "No results found", + "not_available": "N/A", + "not_found": "Not found", + "ntp_servers": "NTP Servers", + "oh_no": "Oh no!", + "online": "Online", + "other_session_detected": "Another Active Session Detected", + "other_session_take_over": " Only one active session is supported at a time. Would you like to take over this session?", + "other_session_use_here_button": "Use Here", + "page_not_found_description": "The page you were looking for does not exist.", + "paste_modal_confirm_paste": "Confirm Paste", + "paste_modal_delay_between_keys": "Delay between keys", + "paste_modal_delay_out_of_range": "Delay must be between {min} and {max}", + "paste_modal_failed_paste": "Failed to paste text: {error}", + "paste_modal_invalid_chars_intro": "The following characters won't be pasted:", + "paste_modal_paste_from_host": "Paste from host", + "paste_modal_paste_text_description": "Paste text from your client to the remote host", + "paste_modal_paste_text": "Paste text", + "paste_modal_sending_using_layout": "Sending text using keyboard layout: {iso}-{name}", + "peer_connection_closed": "Closed", + "peer_connection_closing": "Closing", + "peer_connection_connected": "Connected", + "peer_connection_connecting": "Connecting", + "peer_connection_disconnected": "Disconnected", + "peer_connection_error": "Connection error", + "peer_connection_failed": "Connection failed", + "peer_connection_new": "Connecting", + "previous": "Previous", + "register_device_error": "There was an error {error} registering your device.", + "register_device_finish_button": "Finish Setup", + "register_device_name_description": "Name your device so you can easily identify it later. You can change this name at any time.", + "register_device_name_label": "Device Name", + "register_device_name_placeholder": "Plex Media Server", + "register_device_no_name": "Please specify a name", + "rename_device_button": "Rename Device", + "rename_device_description": "Properly name your device to easily identify it.", + "rename_device_error": "There was an error {error} renaming your device.", + "rename_device_headline": "Rename {name}", + "rename_device_new_name_label": "New device name", + "rename_device_new_name_placeholder": "Plex Media Server", + "rename_device_no_name": "Please specify a name", + "rename": "Rename", + "retry": "Retry", + "saving": "Saving…", + "search_placeholder": "Search…", + "serial_console_baud_rate": "Baud Rate", + "serial_console_configure_description": "Configure your serial console settings", + "serial_console_data_bits": "Data Bits", + "serial_console_get_settings_error": "Failed to get serial console settings: {error}", + "serial_console_open_console": "Open Console", + "serial_console_parity_even": "Even Parity", + "serial_console_parity_mark": "Mark Parity", + "serial_console_parity_none": "No Parity", + "serial_console_parity_odd": "Odd Parity", + "serial_console_parity_space": "Space Parity", + "serial_console_parity": "Parity", + "serial_console_set_settings_error": "Failed to set serial console settings to {settings}: {error}", + "serial_console_stop_bits": "Stop Bits", + "serial_console": "Serial Console", + "setting_remote_description": "Setting remote description", + "setting_remote_session_description": "Setting remote session description...", + "setting_up_connection_to_device": "Setting up connection to device...", + "something_went_wrong": "Something went wrong. Please try again later or contact support", + "step_counter_step": "Step {step}", + "subnet_mask": "Subnet Mask", + "troubleshoot_connection": "Troubleshoot Connection", + "unknown_error": "Unknown error", + "update_in_progress": "Update in Progress", + "updates_failed_check": "Failed to check for updates: {error}", + "updates_failed_get_device_version": "Failed to get device version: {error}", + "updating_leave_device_on": "Please don't turn off your device…", + "usb_config_custom": "Custom", + "usb_config_default": "JetKVM Default", + "usb_config_dell": "Dell Multimedia Pro Keyboard", + "usb_config_failed_load": "Failed to load USB Config: {error}", + "usb_config_failed_set": "Failed to set USB config: {error}", + "usb_config_identifiers_description": "USB device identifiers exposed to the target computer", + "usb_config_identifiers_title": "Identifiers", + "usb_config_logitech": "Logitech Universal Adapter", + "usb_config_manufacturer_label": "Manufacturer", + "usb_config_manufacturer_placeholder": "Enter Manufacturer", + "usb_config_microsoft": "Microsoft Wireless MultiMedia Keyboard", + "usb_config_product_id_label": "Product ID", + "usb_config_product_id_placeholder": "Enter Product ID", + "usb_config_product_name_label": "Product Name", + "usb_config_product_name_placeholder": "Enter Product Name", + "usb_config_restore_default": "Restore to Default", + "usb_config_serial_number_label": "Serial Number", + "usb_config_serial_number_placeholder": "Enter Serial Number", + "usb_config_set_success": "USB Config set to {manufacturer} {product}", + "usb_config_update_identifiers": "Update USB Identifiers", + "usb_config_vendor_id_label": "Vendor ID", + "usb_config_vendor_id_placeholder": "Enter Vendor ID", + "usb_device_classes_description": "USB device classes in the composite device", + "usb_device_classes_title": "Classes", + "usb_device_custom": "Custom", + "usb_device_description": "USB devices to emulate on the target computer", + "usb_device_enable_absolute_mouse_description": "Enable Absolute Mouse (Pointer)", + "usb_device_enable_absolute_mouse_title": "Enable Absolute Mouse (Pointer)", + "usb_device_enable_keyboard_description": "Enable Keyboard", + "usb_device_enable_keyboard_title": "Enable Keyboard", + "usb_device_enable_mass_storage_description": "Sometimes it might need to be disabled to prevent issues with certain devices", + "usb_device_enable_mass_storage_title": "Enable USB Mass Storage", + "usb_device_enable_relative_mouse_description": "Enable Relative Mouse", + "usb_device_enable_relative_mouse_title": "Enable Relative Mouse", + "usb_device_failed_load": "Failed to load USB devices: {error}", + "usb_device_failed_set": "Failed to set USB devices: {error}", + "usb_device_keyboard_mouse_and_mass_storage": "Keyboard, Mouse and Mass Storage", + "usb_device_keyboard_only": "Keyboard Only", + "usb_device_restore_default": "Restore to Default", + "usb_device_title": "USB Device", + "usb_device_update_classes": "Update USB Classes", + "usb_device_updated": "USB Devices updated", + "usb_state_connected": "Connected", + "usb_state_connecting": "Connecting", + "usb_state_disconnected": "Disconnected", + "usb_state_low_power_mode": "Low power mode", + "usb": "USB", + "video_overlay_autoplay_permissions_required": "Autoplay permissions required", + "video_overlay_conn_check_cables": "Check all cable connections for any loose or damaged wires", + "video_overlay_conn_ensure_network": "Ensure your network connection is stable and active", + "video_overlay_conn_restart": "Try restarting both the device and your computer", + "video_overlay_conn_verify_power": "Verify that the device is powered on and properly connected", + "video_overlay_connection_issue_title": "Connection Issue Detected", + "video_overlay_enable_autoplay_settings": "Please adjust browser settings to enable autoplay", + "video_overlay_hdmi_error_title": "HDMI signal error detected.", + "video_overlay_hdmi_incompatible_resolution": "Incompatible resolution or refresh rate settings", + "video_overlay_hdmi_loose_faulty": "A loose or faulty HDMI connection", + "video_overlay_hdmi_source_issue": "Issues with the source device's HDMI output", + "video_overlay_learn_more": "Learn more", + "video_overlay_loading_stream": "Loading video stream…", + "video_overlay_manually_start_stream": "Manually start stream", + "video_overlay_no_hdmi_adapter_compat": "If using an adapter, ensure it's compatible and functioning correctly", + "video_overlay_no_hdmi_ensure_cable": "Ensure the HDMI cable securely connected at both ends", + "video_overlay_no_hdmi_ensure_power": "Ensure source device is powered on and outputting a signal", + "video_overlay_no_hdmi_signal": "No HDMI signal detected.", + "video_overlay_pointerlock_click_to_enable": "Click on the video to enable mouse control", + "video_overlay_retrying_connection": "Retrying connection…", + "video_overlay_troubleshooting_guide": "Troubleshooting Guide", + "video_overlay_try_again": "Try again", + "video_pointer_lock_disabled": "Pointer lock disabled", + "video_pointer_lock_enabled": "Pointer lock enabled — press Escape to unlock", + "view_details": "View Details", + "virtual_keyboard_description": "Use the virtual keyboard to send special keys or key combinations to the remote computer.", + "virtual_keyboard_header": "Virtual Keyboard", + "wake_on_lan_add_device_back": "Back", + "wake_on_lan_add_device_device_name": "Device Name", + "wake_on_lan_add_device_example_device_name": "Plex Media Server", + "wake_on_lan_add_device_mac_address": "MAC Address", + "wake_on_lan_add_device_save_device": "Save Device", + "wake_on_lan_description": "Send a Magic Packet to wake up a remote device.", + "wake_on_lan_device_list_add_new_device": "Add New Device", + "wake_on_lan_device_list_delete_device": "Delete device", + "wake_on_lan_device_list_wake": "Wake", + "wake_on_lan_empty_add_device_to_start": "Add a device to start using Wake-on-LAN", + "wake_on_lan_empty_add_new_device": "Add New Device", + "wake_on_lan_empty_no_devices_added": "No devices added", + "wake_on_lan_failed_add_device": "Failed to add device", + "wake_on_lan_failed_send_magic": "Failed to send Magic Packet", + "wake_on_lan_invalid_mac": "Invalid MAC address", + "wake_on_lan_magic_sent_success": "Magic Packet sent successfully", + "wake_on_lan": "Wake On LAN", + "welcome_to_jetkvm_description": "Control any computer remotely", + "welcome_to_jetkvm": "Welcome to JetKVM" +} \ No newline at end of file diff --git a/ui/localization/messages/es.json b/ui/localization/messages/es.json new file mode 100644 index 00000000..c182658a --- /dev/null +++ b/ui/localization/messages/es.json @@ -0,0 +1,66 @@ +{ + "$schema": "https://inlang.com/schema/inlang-message-format", + "jetkvm": "JetKVM", + "oh_no": "¡Oh, no!", + "something_went_wrong": "Algo salió mal. Inténtalo de nuevo más tarde o contacta con el servicio de asistencia.", + "jetkvm_logo": "Logotipo de JetKVM", + "load": "Carga", + "unknown_error": "Error desconocido", + "action_bar_virtual_media": "Medios virtuales", + "action_bar_paste_text": "Pegar texto", + "action_bar_web_terminal": "Terminal web", + "action_bar_wake_on_lan": "Activación en LAN", + "action_bar_virtual_keyboard": "Teclado virtual", + "action_bar_extension": "Extensión", + "action_bar_connection_stats": "Estadísticas de conexión", + "action_bar_settings": "Ajustes", + "action_bar_fullscreen": "Pantalla completa", + "action_bar_exit_fullscreen": "Salir de pantalla completa", + "extensions_popover_extensions": "Extensiones", + "extension_popover_set_error_notification": "No se pudo establecer la extensión activa: {error}", + "extension_popover_unload_extension": "Extensión de descarga", + "extension_popover_load_and_manage_extensions": "Cargar y administrar sus extensiones", + "extensions_atx_power_control": "Control de alimentación ATX", + "extensions_atx_power_control_description": "Controle el estado de energía de su máquina a través del control de energía ATX.", + "extensions_dc_power_control": "Control de potencia de CC", + "extensions_dc_power_control_description": "Controle su extensión de alimentación de CC", + "extension_serial_console": "Consola serial", + "extension_serial_console_description": "Acceda a la extensión de su consola serie", + "atx_power_control_get_state_error": "No se pudo obtener el estado de energía ATX: {error}", + "atx_power_control_send_action_error": "No se pudo enviar la acción de alimentación ATX {action} : {error}", + "atx_power_control_power_button": "Fuerza", + "atx_power_control_short_power_button": "Prensa corta", + "atx_power_control_long_power_button": "Pulsación larga", + "atx_power_control_reset_button": "Reiniciar", + "atx_power_control_power_led": "LED de encendido", + "atx_power_control_hdd_led": "LED del disco duro", + "dc_power_control_get_state_error": "No se pudo obtener el estado de la alimentación de CC: {error}", + "dc_power_control_set_power_state_error": "No se pudo enviar el estado de alimentación de CC a {enabled} : {error}", + "dc_power_control_set_restore_state_error": "No se pudo enviar el estado de restauración de energía de CC a {state} : {error}", + "dc_power_control_power_on_button": "Encendido", + "dc_power_control_power_off_button": "Apagado", + "dc_power_control_restore_power_state": "Restaurar pérdida de energía", + "dc_power_control_power_on_state": "Encendido", + "dc_power_control_power_off_state": "Apagado", + "dc_power_control_voltage": "Voltaje", + "dc_power_control_voltage_unit": "V", + "dc_power_control_current": "Amperio", + "dc_power_control_current_unit": "A", + "dc_power_control_power": "Vatio", + "dc_power_control_power_unit": "O", + "serial_console_get_state_error": "No se pudo obtener la configuración de la consola serial: {error}", + "serial_console_set_power_state_error": "No se pudieron establecer los ajustes de la consola serial en {settings} : {error}", + "serial_console_configure_description": "Configure los ajustes de su consola serie", + "serial_console_open_console": "Consola abierta", + "serial_console_baud_rate": "Tasa de Baud", + "serial_console_data_bits": "Bits de datos", + "serial_console_stop_bits": "Bits de parada", + "serial_console_parity": "Paridad", + "serial_console_parity_even": "Paridad uniforme", + "serial_console_parity_odd": "Paridad impar", + "serial_console_parity_none": "Sin paridad", + "serial_console_parity_mark": "Paridad de marca", + "serial_console_parity_space": "Paridad espacial", + "serial_console_get_settings_error": "No se pudo obtener la configuración de la consola serial: {error}", + "serial_console_set_settings_error": "No se pudieron establecer los ajustes de la consola serial en {settings} : {error}" +} \ No newline at end of file diff --git a/ui/localization/messages/fr.json b/ui/localization/messages/fr.json new file mode 100644 index 00000000..400d9bb0 --- /dev/null +++ b/ui/localization/messages/fr.json @@ -0,0 +1,66 @@ +{ + "$schema": "https://inlang.com/schema/inlang-message-format", + "jetkvm": "JetKVM", + "oh_no": "Oh non!", + "something_went_wrong": "Une erreur s'est produite. Veuillez réessayer ultérieurement ou contacter le support.", + "jetkvm_logo": "Logo JetKVM", + "load": "Charger", + "unknown_error": "Erreur inconnue", + "action_bar_virtual_media": "Médias virtuels", + "action_bar_paste_text": "Coller du texte", + "action_bar_web_terminal": "Terminal Web", + "action_bar_wake_on_lan": "Réveil sur LAN", + "action_bar_virtual_keyboard": "Clavier virtuel", + "action_bar_extension": "Extension", + "action_bar_connection_stats": "Statistiques de connexion", + "action_bar_settings": "Paramètres", + "action_bar_fullscreen": "Plein écran", + "action_bar_exit_fullscreen": "Quitter le plein écran", + "extensions_popover_extensions": "Extensions", + "extension_popover_set_error_notification": "Échec de la définition de l'extension active: {error}", + "extension_popover_unload_extension": "Extension de déchargement", + "extension_popover_load_and_manage_extensions": "Chargez et gérez vos extensions", + "extensions_atx_power_control": "Contrôle d'alimentation ATX", + "extensions_atx_power_control_description": "Contrôlez l'état d'alimentation de votre machine via le contrôle d'alimentation ATX.", + "extensions_dc_power_control": "Contrôle de l'alimentation CC", + "extensions_dc_power_control_description": "Contrôlez votre extension d'alimentation CC", + "extension_serial_console": "Console série", + "extension_serial_console_description": "Accédez à votre extension de console série", + "atx_power_control_get_state_error": "Échec de l'obtention de l'état d'alimentation ATX : {error}", + "atx_power_control_send_action_error": "Échec de l'envoi de l'action d'alimentation ATX {action} : {error}", + "atx_power_control_power_button": "Pouvoir", + "atx_power_control_short_power_button": "Appui court", + "atx_power_control_long_power_button": "Appui long", + "atx_power_control_reset_button": "Réinitialiser", + "atx_power_control_power_led": "LED d'alimentation", + "atx_power_control_hdd_led": "Voyant du disque dur", + "dc_power_control_get_state_error": "Échec de l'obtention de l'état d'alimentation CC : {error}", + "dc_power_control_set_power_state_error": "Échec de l'envoi de l'état d'alimentation CC à {enabled} : {error}", + "dc_power_control_set_restore_state_error": "Échec de l'envoi de l'état de restauration de l'alimentation CC à {state} : {error}", + "dc_power_control_power_on_button": "Mise sous tension", + "dc_power_control_power_off_button": "Éteindre", + "dc_power_control_restore_power_state": "Restaurer la perte de puissance", + "dc_power_control_power_on_state": "Mise sous tension", + "dc_power_control_power_off_state": "Éteindre", + "dc_power_control_voltage": "Tension", + "dc_power_control_voltage_unit": "V", + "dc_power_control_current": "Ampère", + "dc_power_control_current_unit": "UN", + "dc_power_control_power": "Pouvoir", + "dc_power_control_power_unit": "W", + "serial_console_get_state_error": "Échec de l'obtention des paramètres de la console série : {error}", + "serial_console_set_power_state_error": "Échec de la définition des paramètres de la console série sur {settings} : {error}", + "serial_console_configure_description": "Configurez les paramètres de votre console série", + "serial_console_open_console": "Ouvrir la console", + "serial_console_baud_rate": "Débit en bauds", + "serial_console_data_bits": "Bits de données", + "serial_console_stop_bits": "Bits d'arrêt", + "serial_console_parity": "Parité", + "serial_console_parity_even": "Parité égale", + "serial_console_parity_odd": "Parité impaire", + "serial_console_parity_none": "Pas de parité", + "serial_console_parity_mark": "Marquer la parité", + "serial_console_parity_space": "Parité spatiale", + "serial_console_get_settings_error": "Échec de l'obtention des paramètres de la console série : {error}", + "serial_console_set_settings_error": "Échec de la définition des paramètres de la console série sur {settings} : {error}" +} \ No newline at end of file diff --git a/ui/localization/messages/it.json b/ui/localization/messages/it.json new file mode 100644 index 00000000..12a0b1e3 --- /dev/null +++ b/ui/localization/messages/it.json @@ -0,0 +1,66 @@ +{ + "$schema": "https://inlang.com/schema/inlang-message-format", + "jetkvm": "JetKVM", + "oh_no": "Oh no!", + "something_went_wrong": "Qualcosa è andato storto. Riprova più tardi o contatta l'assistenza.", + "jetkvm_logo": "Logo JetKVM", + "load": "Carico", + "unknown_error": "Errore sconosciuto", + "action_bar_virtual_media": "Media virtuali", + "action_bar_paste_text": "Incolla il testo", + "action_bar_web_terminal": "Terminale Web", + "action_bar_wake_on_lan": "Wake on LAN", + "action_bar_virtual_keyboard": "Tastiera virtuale", + "action_bar_extension": "Estensione", + "action_bar_connection_stats": "Statistiche di connessione", + "action_bar_settings": "Impostazioni", + "action_bar_fullscreen": "A schermo intero", + "action_bar_exit_fullscreen": "Esci dalla modalità a schermo intero", + "extensions_popover_extensions": "Estensioni", + "extension_popover_set_error_notification": "Impossibile impostare l'estensione attiva: {error}", + "extension_popover_unload_extension": "Estensione di scaricamento", + "extension_popover_load_and_manage_extensions": "Carica e gestisci le tue estensioni", + "extensions_atx_power_control": "Controllo di potenza ATX", + "extensions_atx_power_control_description": "Controlla lo stato di alimentazione del tuo computer tramite il controllo di alimentazione ATX.", + "extensions_dc_power_control": "Controllo di potenza CC", + "extensions_dc_power_control_description": "Controlla la tua estensione di alimentazione CC", + "extension_serial_console": "Console seriale", + "extension_serial_console_description": "Accedi all'estensione della tua console seriale", + "atx_power_control_get_state_error": "Impossibile ottenere lo stato di alimentazione ATX: {error}", + "atx_power_control_send_action_error": "Impossibile inviare l'azione di alimentazione ATX {action} : {error}", + "atx_power_control_power_button": "Energia", + "atx_power_control_short_power_button": "Pressione breve", + "atx_power_control_long_power_button": "Pressione lunga", + "atx_power_control_reset_button": "Reset", + "atx_power_control_power_led": "LED di potenza", + "atx_power_control_hdd_led": "LED dell'HDD", + "dc_power_control_get_state_error": "Impossibile ottenere lo stato di alimentazione CC: {error}", + "dc_power_control_set_power_state_error": "Impossibile inviare lo stato di alimentazione CC a {enabled} : {error}", + "dc_power_control_set_restore_state_error": "Impossibile inviare lo stato di ripristino dell'alimentazione CC a {state} : {error}", + "dc_power_control_power_on_button": "Accensione", + "dc_power_control_power_off_button": "Spegnimento", + "dc_power_control_restore_power_state": "Ripristinare la perdita di potenza", + "dc_power_control_power_on_state": "Accensione", + "dc_power_control_power_off_state": "Spegnimento", + "dc_power_control_voltage": "Voltaggio", + "dc_power_control_voltage_unit": "V", + "dc_power_control_current": "Attuale", + "dc_power_control_current_unit": "UN", + "dc_power_control_power": "Energia", + "dc_power_control_power_unit": "O", + "serial_console_get_state_error": "Impossibile ottenere le impostazioni della console seriale: {error}", + "serial_console_set_power_state_error": "Impossibile impostare le impostazioni della console seriale su {settings} : {error}", + "serial_console_configure_description": "Configura le impostazioni della tua console seriale", + "serial_console_open_console": "Apri console", + "serial_console_baud_rate": "Velocità in baud", + "serial_console_data_bits": "Bit di dati", + "serial_console_stop_bits": "Bit di stop", + "serial_console_parity": "Parità", + "serial_console_parity_even": "Parità pari", + "serial_console_parity_odd": "Parità dispari", + "serial_console_parity_none": "Nessuna parità", + "serial_console_parity_mark": "Segna la parità", + "serial_console_parity_space": "Parità spaziale", + "serial_console_get_settings_error": "Impossibile ottenere le impostazioni della console seriale: {error}", + "serial_console_set_settings_error": "Impossibile impostare le impostazioni della console seriale su {settings} : {error}" +} \ No newline at end of file diff --git a/ui/localization/messages/nb.json b/ui/localization/messages/nb.json new file mode 100644 index 00000000..bf68e4f9 --- /dev/null +++ b/ui/localization/messages/nb.json @@ -0,0 +1,66 @@ +{ + "$schema": "https://inlang.com/schema/inlang-message-format", + "jetkvm": "JetKVM", + "oh_no": "Å nei!", + "something_went_wrong": "Noe gikk galt. Prøv igjen senere, eller kontakt kundestøtte.", + "jetkvm_logo": "JetKVM-logo", + "load": "Laste", + "unknown_error": "Ukjent feil", + "action_bar_virtual_media": "Virtuelle medier", + "action_bar_paste_text": "Lim inn tekst", + "action_bar_web_terminal": "Nettterminal", + "action_bar_wake_on_lan": "Vekk på LAN", + "action_bar_virtual_keyboard": "Virtuelt tastatur", + "action_bar_extension": "Forlengelse", + "action_bar_connection_stats": "Tilkoblingsstatistikk", + "action_bar_settings": "Innstillinger", + "action_bar_fullscreen": "Fullskjerm", + "action_bar_exit_fullscreen": "Avslutt fullskjerm", + "extensions_popover_extensions": "Utvidelser", + "extension_popover_set_error_notification": "Klarte ikke å angi aktiv utvidelse: {error}", + "extension_popover_unload_extension": "Fjern utvidelse", + "extension_popover_load_and_manage_extensions": "Last inn og administrer utvidelsene dine", + "extensions_atx_power_control": "ATX-strømstyring", + "extensions_atx_power_control_description": "Kontroller maskinens strømstatus via ATX-strømkontroll.", + "extensions_dc_power_control": "DC-strømkontroll", + "extensions_dc_power_control_description": "Kontroller DC-strømutvidelsen din", + "extension_serial_console": "Seriell konsoll", + "extension_serial_console_description": "Få tilgang til seriekonsollutvidelsen din", + "atx_power_control_get_state_error": "Klarte ikke å hente ATX-strømstatus: {error}", + "atx_power_control_send_action_error": "Kunne ikke sende ATX-strømhandling {action} : {error}", + "atx_power_control_power_button": "Makt", + "atx_power_control_short_power_button": "Kort trykk", + "atx_power_control_long_power_button": "Langt trykk", + "atx_power_control_reset_button": "Tilbakestill", + "atx_power_control_power_led": "Strøm-LED", + "atx_power_control_hdd_led": "HDD-LED", + "dc_power_control_get_state_error": "Klarte ikke å hente likestrømsstatus: {error}", + "dc_power_control_set_power_state_error": "Kunne ikke sende likestrømsstatus til {enabled} : {error}", + "dc_power_control_set_restore_state_error": "Kunne ikke sende gjenopprettingsstatus for likestrøm til {state} : {error}", + "dc_power_control_power_on_button": "Slå på", + "dc_power_control_power_off_button": "Slå av", + "dc_power_control_restore_power_state": "Gjenopprett strømtap", + "dc_power_control_power_on_state": "Slå PÅ", + "dc_power_control_power_off_state": "Slå av", + "dc_power_control_voltage": "Spenning", + "dc_power_control_voltage_unit": "V", + "dc_power_control_current": "Nåværende", + "dc_power_control_current_unit": "EN", + "dc_power_control_power": "Makt", + "dc_power_control_power_unit": "V", + "serial_console_get_state_error": "Klarte ikke å hente innstillinger for seriell konsoll: {error}", + "serial_console_set_power_state_error": "Klarte ikke å sette innstillingene for seriell konsoll til {settings} : {error}", + "serial_console_configure_description": "Konfigurer innstillingene for seriekonsollen", + "serial_console_open_console": "Åpne konsollen", + "serial_console_baud_rate": "Baudhastighet", + "serial_console_data_bits": "Databiter", + "serial_console_stop_bits": "Stoppbiter", + "serial_console_parity": "Paritet", + "serial_console_parity_even": "Paritet", + "serial_console_parity_odd": "Oddeparitet", + "serial_console_parity_none": "Ingen paritet", + "serial_console_parity_mark": "Mark Paritet", + "serial_console_parity_space": "Romparitet", + "serial_console_get_settings_error": "Klarte ikke å hente innstillinger for seriell konsoll: {error}", + "serial_console_set_settings_error": "Klarte ikke å sette innstillingene for seriell konsoll til {settings} : {error}" +} \ No newline at end of file diff --git a/ui/localization/messages/sv.json b/ui/localization/messages/sv.json new file mode 100644 index 00000000..2ecace3f --- /dev/null +++ b/ui/localization/messages/sv.json @@ -0,0 +1,66 @@ +{ + "$schema": "https://inlang.com/schema/inlang-message-format", + "jetkvm": "JetKVM", + "oh_no": "nej då!", + "something_went_wrong": "Något gick fel. Försök igen senare eller kontakta supporten.", + "jetkvm_logo": "JetKVM-logotyp", + "load": "Ladda", + "unknown_error": "Okänt fel", + "action_bar_virtual_media": "Virtuella medier", + "action_bar_paste_text": "Klistra in text", + "action_bar_web_terminal": "Webbterminal", + "action_bar_wake_on_lan": "Vakna på LAN", + "action_bar_virtual_keyboard": "Virtuellt tangentbord", + "action_bar_extension": "Förlängning", + "action_bar_connection_stats": "Anslutningsstatistik", + "action_bar_settings": "Inställningar", + "action_bar_fullscreen": "Helskärm", + "action_bar_exit_fullscreen": "Avsluta helskärm", + "extensions_popover_extensions": "Tillägg", + "extension_popover_set_error_notification": "Misslyckades med att ange aktivt tillägg: {error}", + "extension_popover_unload_extension": "Avlasta tillägg", + "extension_popover_load_and_manage_extensions": "Ladda och hantera dina tillägg", + "extensions_atx_power_control": "ATX-strömkontroll", + "extensions_atx_power_control_description": "Styr din maskins strömförsörjning via ATX-strömkontroll.", + "extensions_dc_power_control": "DC-strömstyrning", + "extensions_dc_power_control_description": "Styr din DC-strömförlängning", + "extension_serial_console": "Seriell konsol", + "extension_serial_console_description": "Åtkomst till din seriella konsoltillägg", + "atx_power_control_get_state_error": "Misslyckades med att hämta ATX-strömstatus: {error}", + "atx_power_control_send_action_error": "Misslyckades med att skicka ATX-strömåtgärd {action} : {error}", + "atx_power_control_power_button": "Driva", + "atx_power_control_short_power_button": "Kort tryck", + "atx_power_control_long_power_button": "Långt tryck", + "atx_power_control_reset_button": "Återställa", + "atx_power_control_power_led": "Ström-LED", + "atx_power_control_hdd_led": "Hårddisk-LED", + "dc_power_control_get_state_error": "Misslyckades med att hämta likströmsstatus: {error}", + "dc_power_control_set_power_state_error": "Misslyckades med att skicka likströmsstatus till {enabled} : {error}", + "dc_power_control_set_restore_state_error": "Misslyckades med att skicka återställningsstatus för likström till {state} : {error}", + "dc_power_control_power_on_button": "Slå på", + "dc_power_control_power_off_button": "Stäng av", + "dc_power_control_restore_power_state": "Återställ strömförlust", + "dc_power_control_power_on_state": "Slå på", + "dc_power_control_power_off_state": "Stäng av", + "dc_power_control_voltage": "Spänning", + "dc_power_control_voltage_unit": "V", + "dc_power_control_current": "Nuvarande", + "dc_power_control_current_unit": "En", + "dc_power_control_power": "Driva", + "dc_power_control_power_unit": "V", + "serial_console_get_state_error": "Misslyckades med att hämta inställningar för seriekonsolen: {error}", + "serial_console_set_power_state_error": "Misslyckades med att ställa in seriekonsolinställningarna till {settings} : {error}", + "serial_console_configure_description": "Konfigurera dina seriella konsolinställningar", + "serial_console_open_console": "Öppna konsolen", + "serial_console_baud_rate": "Baudhastighet", + "serial_console_data_bits": "Databitar", + "serial_console_stop_bits": "Stoppbitar", + "serial_console_parity": "Paritet", + "serial_console_parity_even": "Jämn paritet", + "serial_console_parity_odd": "Udda paritet", + "serial_console_parity_none": "Ingen paritet", + "serial_console_parity_mark": "Markera paritet", + "serial_console_parity_space": "Rymdparitet", + "serial_console_get_settings_error": "Misslyckades med att hämta inställningar för seriekonsolen: {error}", + "serial_console_set_settings_error": "Misslyckades med att ställa in seriekonsolinställningarna till {settings} : {error}" +} \ No newline at end of file diff --git a/ui/localization/messages/zh.json b/ui/localization/messages/zh.json new file mode 100644 index 00000000..70ef92f7 --- /dev/null +++ b/ui/localization/messages/zh.json @@ -0,0 +1,66 @@ +{ + "$schema": "https://inlang.com/schema/inlang-message-format", + "jetkvm": "JetKVM", + "oh_no": "噢不!", + "something_went_wrong": "出了点问题。请稍后重试或联系客服", + "jetkvm_logo": "JetKVM 徽标", + "load": "加载", + "unknown_error": "未知错误", + "action_bar_virtual_media": "虚拟媒体", + "action_bar_paste_text": "粘贴文本", + "action_bar_web_terminal": "网页终端", + "action_bar_wake_on_lan": "局域网唤醒", + "action_bar_virtual_keyboard": "虚拟键盘", + "action_bar_extension": "扩展", + "action_bar_connection_stats": "连接统计", + "action_bar_settings": "设置", + "action_bar_fullscreen": "全屏", + "action_bar_exit_fullscreen": "退出全屏", + "extensions_popover_extensions": "扩展", + "extension_popover_set_error_notification": "无法设置活动扩展:{error}", + "extension_popover_unload_extension": "卸载扩展", + "extension_popover_load_and_manage_extensions": "加载和管理您的扩展", + "extensions_atx_power_control": "ATX 电源控制", + "extensions_atx_power_control_description": "通过 ATX 电源控制来控制机器的电源状态。", + "extensions_dc_power_control": "直流电源控制", + "extensions_dc_power_control_description": "控制您的直流电源扩展", + "extension_serial_console": "串行控制台", + "extension_serial_console_description": "访问串行控制台扩展", + "atx_power_control_get_state_error": "无法获取 ATX 电源状态:{error}", + "atx_power_control_send_action_error": "无法发送 ATX 电源操作 {action} : {error}", + "atx_power_control_power_button": "电源", + "atx_power_control_short_power_button": "短按", + "atx_power_control_long_power_button": "长按", + "atx_power_control_reset_button": "重置", + "atx_power_control_power_led": "电源 LED", + "atx_power_control_hdd_led": "硬盘指示灯", + "dc_power_control_get_state_error": "无法获取直流电源状态:{error}", + "dc_power_control_set_power_state_error": "无法将直流电源状态发送到 {enabled} : {error}", + "dc_power_control_set_restore_state_error": "无法将直流电源恢复状态发送到 {state} : {error}", + "dc_power_control_power_on_button": "开机", + "dc_power_control_power_off_button": "关闭电源", + "dc_power_control_restore_power_state": "恢复断电", + "dc_power_control_power_on_state": "开启电源", + "dc_power_control_power_off_state": "关闭电源", + "dc_power_control_voltage": "电压", + "dc_power_control_voltage_unit": "V", + "dc_power_control_current": "电流", + "dc_power_control_current_unit": "A", + "dc_power_control_power": "瓦特", + "dc_power_control_power_unit": "W", + "serial_console_get_state_error": "无法获取串行控制台设置: {error}", + "serial_console_set_power_state_error": "无法将串行控制台设置设置为 {settings} : {error}", + "serial_console_configure_description": "配置串行控制台设置", + "serial_console_open_console": "打开控制台", + "serial_console_baud_rate": "波特率", + "serial_console_data_bits": "数据位", + "serial_console_stop_bits": "停止位", + "serial_console_parity": "奇偶校验位", + "serial_console_parity_even": "偶校验", + "serial_console_parity_odd": "奇校验", + "serial_console_parity_none": "无", + "serial_console_parity_mark": "Mark", + "serial_console_parity_space": "Space", + "serial_console_get_settings_error": "无法获取串行控制台设置: {error}", + "serial_console_set_settings_error": "无法将串行控制台设置设置为 {settings} : {error}" +} \ No newline at end of file diff --git a/ui/package-lock.json b/ui/package-lock.json index 7d4faf36..c208aa9a 100644 --- a/ui/package-lock.json +++ b/ui/package-lock.json @@ -1,12 +1,12 @@ { "name": "kvm-ui", - "version": "2025.10.01.1900", + "version": "2025.10.13.2055", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "kvm-ui", - "version": "2025.10.01.1900", + "version": "2025.10.13.2055", "dependencies": { "@headlessui/react": "^2.2.9", "@headlessui/tailwindcss": "^0.2.2", @@ -22,16 +22,16 @@ "dayjs": "^1.11.18", "eslint-import-resolver-alias": "^1.1.2", "focus-trap-react": "^11.0.4", - "framer-motion": "^12.23.22", + "framer-motion": "^12.23.24", "lodash.throttle": "^4.1.1", "mini-svg-data-uri": "^1.4.4", - "react": "^19.1.1", + "react": "^19.2.0", "react-animate-height": "^3.2.3", - "react-dom": "^19.1.1", + "react-dom": "^19.2.0", "react-hot-toast": "^2.6.0", "react-icons": "^5.5.0", - "react-router": "^7.9.3", - "react-simple-keyboard": "^3.8.125", + "react-router": "^7.9.4", + "react-simple-keyboard": "^3.8.130", "react-use-websocket": "^4.13.0", "react-xtermjs": "^1.0.10", "recharts": "^3.2.1", @@ -43,32 +43,37 @@ "devDependencies": { "@eslint/compat": "^1.4.0", "@eslint/eslintrc": "^3.3.1", - "@eslint/js": "^9.36.0", + "@eslint/js": "^9.37.0", + "@inlang/cli": "^3.0.12", + "@inlang/paraglide-js": "^2.4.0", + "@inlang/plugin-m-function-matcher": "^2.1.0", + "@inlang/plugin-message-format": "^4.0.0", + "@inlang/sdk": "^2.4.9", "@tailwindcss/forms": "^0.5.10", "@tailwindcss/postcss": "^4.1.14", "@tailwindcss/typography": "^0.5.19", "@tailwindcss/vite": "^4.1.14", - "@types/react": "^19.1.17", - "@types/react-dom": "^19.1.10", + "@types/react": "^19.2.2", + "@types/react-dom": "^19.2.2", "@types/semver": "^7.7.1", "@types/validator": "^13.15.3", - "@typescript-eslint/eslint-plugin": "^8.45.0", - "@typescript-eslint/parser": "^8.45.0", + "@typescript-eslint/eslint-plugin": "^8.46.1", + "@typescript-eslint/parser": "^8.46.1", "@vitejs/plugin-react-swc": "^4.1.0", "autoprefixer": "^10.4.21", - "eslint": "^9.36.0", - "eslint-config-prettier": "^10.1.8", + "eslint": "^9.37.0", "eslint-plugin-import": "^2.32.0", + "eslint-plugin-prettier": "^5.5.4", "eslint-plugin-react": "^7.37.5", - "eslint-plugin-react-hooks": "^5.2.0", - "eslint-plugin-react-refresh": "^0.4.22", + "eslint-plugin-react-hooks": "^7.0.0", + "eslint-plugin-react-refresh": "^0.4.23", "globals": "^16.4.0", "postcss": "^8.5.6", "prettier": "^3.6.2", "prettier-plugin-tailwindcss": "^0.6.14", "tailwindcss": "^4.1.14", "typescript": "^5.9.3", - "vite": "^7.1.7", + "vite": "^7.1.9", "vite-tsconfig-paths": "^5.1.4" }, "engines": { @@ -88,6 +93,266 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/@babel/code-frame": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.27.1.tgz", + "integrity": "sha512-cjQ7ZlQ0Mv3b47hABuTevyTuYN4i+loJKGeV9flcCgIK37cCXRh+L1bd3iBHlynerhQ7BhCkn2BPbQUL+rGqFg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-validator-identifier": "^7.27.1", + "js-tokens": "^4.0.0", + "picocolors": "^1.1.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/compat-data": { + "version": "7.28.4", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.28.4.tgz", + "integrity": "sha512-YsmSKC29MJwf0gF8Rjjrg5LQCmyh+j/nD8/eP7f+BeoQTKYqs9RoWbjGOdy0+1Ekr68RJZMUOPVQaQisnIo4Rw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/core": { + "version": "7.28.4", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.28.4.tgz", + "integrity": "sha512-2BCOP7TN8M+gVDj7/ht3hsaO/B/n5oDbiAyyvnRlNOs+u1o+JWNYTQrmpuNp1/Wq2gcFrI01JAW+paEKDMx/CA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.27.1", + "@babel/generator": "^7.28.3", + "@babel/helper-compilation-targets": "^7.27.2", + "@babel/helper-module-transforms": "^7.28.3", + "@babel/helpers": "^7.28.4", + "@babel/parser": "^7.28.4", + "@babel/template": "^7.27.2", + "@babel/traverse": "^7.28.4", + "@babel/types": "^7.28.4", + "@jridgewell/remapping": "^2.3.5", + "convert-source-map": "^2.0.0", + "debug": "^4.1.0", + "gensync": "^1.0.0-beta.2", + "json5": "^2.2.3", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/babel" + } + }, + "node_modules/@babel/core/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/@babel/generator": { + "version": "7.28.3", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.28.3.tgz", + "integrity": "sha512-3lSpxGgvnmZznmBkCRnVREPUFJv2wrv9iAoFDvADJc0ypmdOxdUtcLeBgBJ6zE0PMeTKnxeQzyk0xTBq4Ep7zw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.28.3", + "@babel/types": "^7.28.2", + "@jridgewell/gen-mapping": "^0.3.12", + "@jridgewell/trace-mapping": "^0.3.28", + "jsesc": "^3.0.2" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-compilation-targets": { + "version": "7.27.2", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.27.2.tgz", + "integrity": "sha512-2+1thGUUWWjLTYTHZWK1n8Yga0ijBz1XAhUXcKy81rd5g6yh7hGqMp45v7cadSbEHc9G3OTv45SyneRN3ps4DQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/compat-data": "^7.27.2", + "@babel/helper-validator-option": "^7.27.1", + "browserslist": "^4.24.0", + "lru-cache": "^5.1.1", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-compilation-targets/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/@babel/helper-globals": { + "version": "7.28.0", + "resolved": "https://registry.npmjs.org/@babel/helper-globals/-/helper-globals-7.28.0.tgz", + "integrity": "sha512-+W6cISkXFa1jXsDEdYA8HeevQT/FULhxzR99pxphltZcVaugps53THCeiWA8SguxxpSp3gKPiuYfSWopkLQ4hw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-imports": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.27.1.tgz", + "integrity": "sha512-0gSFWUPNXNopqtIPQvlD5WgXYI5GY2kP2cCvoT8kczjbfcfuIljTbcWrulD1CIPIX2gt1wghbDy08yE1p+/r3w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/traverse": "^7.27.1", + "@babel/types": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-transforms": { + "version": "7.28.3", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.28.3.tgz", + "integrity": "sha512-gytXUbs8k2sXS9PnQptz5o0QnpLL51SwASIORY6XaBKF88nsOT0Zw9szLqlSGQDP/4TljBAD5y98p2U1fqkdsw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-module-imports": "^7.27.1", + "@babel/helper-validator-identifier": "^7.27.1", + "@babel/traverse": "^7.28.3" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-string-parser": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.27.1.tgz", + "integrity": "sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-identifier": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.27.1.tgz", + "integrity": "sha512-D2hP9eA+Sqx1kBZgzxZh0y1trbuU+JoDkiEwqhQ36nodYqJwyEIhPSdMNd7lOm/4io72luTPWH20Yda0xOuUow==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-option": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.27.1.tgz", + "integrity": "sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helpers": { + "version": "7.28.4", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.28.4.tgz", + "integrity": "sha512-HFN59MmQXGHVyYadKLVumYsA9dBFun/ldYxipEjzA4196jpLZd8UjEEBLkbEkvfYreDqJhZxYAWFPtrfhNpj4w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/template": "^7.27.2", + "@babel/types": "^7.28.4" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/parser": { + "version": "7.28.4", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.28.4.tgz", + "integrity": "sha512-yZbBqeM6TkpP9du/I2pUZnJsRMGGvOuIrhjzC1AwHwW+6he4mni6Bp/m8ijn0iOuZuPI2BfkCoSRunpyjnrQKg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.28.4" + }, + "bin": { + "parser": "bin/babel-parser.js" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/template": { + "version": "7.27.2", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.27.2.tgz", + "integrity": "sha512-LPDZ85aEJyYSd18/DkjNh4/y1ntkE5KwUHWTiqgRxruuZL2F1yuHligVHLvcHY2vMHXttKFpJn6LwfI7cw7ODw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.27.1", + "@babel/parser": "^7.27.2", + "@babel/types": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/traverse": { + "version": "7.28.4", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.28.4.tgz", + "integrity": "sha512-YEzuboP2qvQavAcjgQNVgsvHIDv6ZpwXvcvjmyySP2DIMuByS/6ioU5G9pYrWHM6T2YDfc7xga9iNzYOs12CFQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.27.1", + "@babel/generator": "^7.28.3", + "@babel/helper-globals": "^7.28.0", + "@babel/parser": "^7.28.4", + "@babel/template": "^7.27.2", + "@babel/types": "^7.28.4", + "debug": "^4.3.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/types": { + "version": "7.28.4", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.28.4.tgz", + "integrity": "sha512-bkFqkLhh3pMBUQQkpVgWDWq/lqzc2678eUyDlTBhRqhCHFguYYGM0Efga7tYk4TogG/3x0EEl66/OQ+WGbWB/Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-string-parser": "^7.27.1", + "@babel/helper-validator-identifier": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, "node_modules/@esbuild/aix-ppc64": { "version": "0.25.10", "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.10.tgz", @@ -567,10 +832,13 @@ } }, "node_modules/@eslint/config-helpers": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/@eslint/config-helpers/-/config-helpers-0.3.1.tgz", - "integrity": "sha512-xR93k9WhrDYpXHORXpxVL5oHj3Era7wo6k/Wd8/IsQNnZUTzkGS29lyn3nAT05v6ltUuTFVCCYDEGfy2Or/sPA==", + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/@eslint/config-helpers/-/config-helpers-0.4.0.tgz", + "integrity": "sha512-WUFvV4WoIwW8Bv0KeKCIIEgdSiFOsulyN0xrMu+7z43q/hkOLXjvb5u7UC9jDxvRzcrbEmuZBX5yJZz1741jog==", "license": "Apache-2.0", + "dependencies": { + "@eslint/core": "^0.16.0" + }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" } @@ -579,7 +847,6 @@ "version": "0.16.0", "resolved": "https://registry.npmjs.org/@eslint/core/-/core-0.16.0.tgz", "integrity": "sha512-nmC8/totwobIiFcGkDza3GIKfAw1+hLiYVrh3I1nIomQ8PEr5cxg34jnkmGawul/ep52wGRAcyeDCNtWKSOj4Q==", - "dev": true, "license": "Apache-2.0", "dependencies": { "@types/json-schema": "^7.0.15" @@ -624,9 +891,9 @@ } }, "node_modules/@eslint/js": { - "version": "9.36.0", - "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.36.0.tgz", - "integrity": "sha512-uhCbYtYynH30iZErszX78U+nR3pJU3RHGQ57NXy5QupD4SBVwDeU8TNBy+MjMngc1UyIW9noKqsRqfjQTBU2dw==", + "version": "9.37.0", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.37.0.tgz", + "integrity": "sha512-jaS+NJ+hximswBG6pjNX0uEJZkrT0zwpVi3BA3vX22aFGjJjmgSTSmPpZCRKmoBL5VY/M6p0xsSJx7rk7sy5gg==", "license": "MIT", "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -645,30 +912,18 @@ } }, "node_modules/@eslint/plugin-kit": { - "version": "0.3.5", - "resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.3.5.tgz", - "integrity": "sha512-Z5kJ+wU3oA7MMIqVR9tyZRtjYPr4OC004Q4Rw7pgOKUOKkJfZ3O24nz3WYfGRpMDNmcOi3TwQOmgm7B7Tpii0w==", + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.4.0.tgz", + "integrity": "sha512-sB5uyeq+dwCWyPi31B2gQlVlo+j5brPlWx4yZBrEaRo/nhdDE8Xke1gsGgtiBdaBTxuTkceLVuVt/pclrasb0A==", "license": "Apache-2.0", "dependencies": { - "@eslint/core": "^0.15.2", + "@eslint/core": "^0.16.0", "levn": "^0.4.1" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" } }, - "node_modules/@eslint/plugin-kit/node_modules/@eslint/core": { - "version": "0.15.2", - "resolved": "https://registry.npmjs.org/@eslint/core/-/core-0.15.2.tgz", - "integrity": "sha512-78Md3/Rrxh83gCxoUc0EiciuOHsIITzLy53m3d9UyiW8y9Dj2D29FeETqyKA+BRK76tnTp6RXWb3pCay8Oyomg==", - "license": "Apache-2.0", - "dependencies": { - "@types/json-schema": "^7.0.15" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - } - }, "node_modules/@floating-ui/core": { "version": "1.7.3", "resolved": "https://registry.npmjs.org/@floating-ui/core/-/core-1.7.3.tgz", @@ -811,6 +1066,87 @@ "url": "https://github.com/sponsors/nzakas" } }, + "node_modules/@inlang/cli": { + "version": "3.0.12", + "resolved": "https://registry.npmjs.org/@inlang/cli/-/cli-3.0.12.tgz", + "integrity": "sha512-0FZJtgrt1Ol4iwKtA0VICrsHcA3stWTSP2jq8mpTgjTlFU63gr5JcyFljUT8Dp5nDIJYmdh3kJ0a8PhW0X8clQ==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@inlang/sdk": "2.4.9", + "esbuild-wasm": "^0.19.2" + }, + "bin": { + "inlang": "bin/run.js" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@inlang/paraglide-js": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/@inlang/paraglide-js/-/paraglide-js-2.4.0.tgz", + "integrity": "sha512-T/m9uoev574/1JrhCnPcgK1xnAwkVMgaDev4LFthnmID8ubX2xjboSGO3IztwXWwO0aJoT1UJr89JCwjbwgnJQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@inlang/recommend-sherlock": "0.2.1", + "@inlang/sdk": "2.4.9", + "commander": "11.1.0", + "consola": "3.4.0", + "json5": "2.2.3", + "unplugin": "^2.1.2", + "urlpattern-polyfill": "^10.0.0" + }, + "bin": { + "paraglide-js": "bin/run.js" + } + }, + "node_modules/@inlang/plugin-m-function-matcher": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@inlang/plugin-m-function-matcher/-/plugin-m-function-matcher-2.1.0.tgz", + "integrity": "sha512-IAbG7rOl+rlTiZY7qj92we6lmII693lVthPtY9bFDkZ/Ig7FPSpae/TfLzqjf2KcR1nDdx1zRpSo6roDPeM85g==", + "dev": true, + "dependencies": { + "@inlang/sdk": "2.4.9" + } + }, + "node_modules/@inlang/plugin-message-format": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@inlang/plugin-message-format/-/plugin-message-format-4.0.0.tgz", + "integrity": "sha512-zNpLxLTt+bDd3JLXj1ONzo+Q6AOzz2MfcgGo8XB6/bweGhFIndK3GU/q0iU4o7VI4KS1+OHNLpKwFcrAifwERQ==", + "dev": true, + "dependencies": { + "flat": "^6.0.1" + } + }, + "node_modules/@inlang/recommend-sherlock": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/@inlang/recommend-sherlock/-/recommend-sherlock-0.2.1.tgz", + "integrity": "sha512-ckv8HvHy/iTqaVAEKrr+gnl+p3XFNwe5D2+6w6wJk2ORV2XkcRkKOJ/XsTUJbPSiyi4PI+p+T3bqbmNx/rDUlg==", + "dev": true, + "license": "MIT", + "dependencies": { + "comment-json": "^4.2.3" + } + }, + "node_modules/@inlang/sdk": { + "version": "2.4.9", + "resolved": "https://registry.npmjs.org/@inlang/sdk/-/sdk-2.4.9.tgz", + "integrity": "sha512-cvz/C1rF5WBxzHbEoiBoI6Sz6q6M+TdxfWkEGBYTD77opY8i8WN01prUWXEM87GPF4SZcyIySez9U0Ccm12oFQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@lix-js/sdk": "0.4.7", + "@sinclair/typebox": "^0.31.17", + "kysely": "^0.27.4", + "sqlite-wasm-kysely": "0.3.0", + "uuid": "^10.0.0" + }, + "engines": { + "node": ">=18.0.0" + } + }, "node_modules/@isaacs/fs-minipass": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/@isaacs/fs-minipass/-/fs-minipass-4.0.1.tgz", @@ -874,6 +1210,32 @@ "@jridgewell/sourcemap-codec": "^1.4.14" } }, + "node_modules/@lix-js/sdk": { + "version": "0.4.7", + "resolved": "https://registry.npmjs.org/@lix-js/sdk/-/sdk-0.4.7.tgz", + "integrity": "sha512-pRbW+joG12L0ULfMiWYosIW0plmW4AsUdiPCp+Z8rAsElJ+wJ6in58zhD3UwUcd4BNcpldEGjg6PdA7e0RgsDQ==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@lix-js/server-protocol-schema": "0.1.1", + "dedent": "1.5.1", + "human-id": "^4.1.1", + "js-sha256": "^0.11.0", + "kysely": "^0.27.4", + "sqlite-wasm-kysely": "0.3.0", + "uuid": "^10.0.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/@lix-js/server-protocol-schema": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/@lix-js/server-protocol-schema/-/server-protocol-schema-0.1.1.tgz", + "integrity": "sha512-jBeALB6prAbtr5q4vTuxnRZZv1M2rKe8iNqRQhFJ4Tv7150unEa0vKyz0hs8Gl3fUGsWaNJBh3J8++fpbrpRBQ==", + "dev": true, + "license": "Apache-2.0" + }, "node_modules/@nodelib/fs.scandir": { "version": "2.1.5", "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", @@ -912,15 +1274,28 @@ "node": ">= 8" } }, + "node_modules/@pkgr/core": { + "version": "0.2.9", + "resolved": "https://registry.npmjs.org/@pkgr/core/-/core-0.2.9.tgz", + "integrity": "sha512-QNqXyfVS2wm9hweSYD2O7F0G06uurj9kZ96TRQE5Y9hU7+tgdZwIkbAKc5Ocy1HxEY2kuDQa6cQ1WRs/O5LFKA==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^12.20.0 || ^14.18.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/pkgr" + } + }, "node_modules/@react-aria/focus": { - "version": "3.21.1", - "resolved": "https://registry.npmjs.org/@react-aria/focus/-/focus-3.21.1.tgz", - "integrity": "sha512-hmH1IhHlcQ2lSIxmki1biWzMbGgnhdxJUM0MFfzc71Rv6YAzhlx4kX3GYn4VNcjCeb6cdPv4RZ5vunV4kgMZYQ==", + "version": "3.21.2", + "resolved": "https://registry.npmjs.org/@react-aria/focus/-/focus-3.21.2.tgz", + "integrity": "sha512-JWaCR7wJVggj+ldmM/cb/DXFg47CXR55lznJhZBh4XVqJjMKwaOOqpT5vNN7kpC1wUpXicGNuDnJDN1S/+6dhQ==", "license": "Apache-2.0", "dependencies": { - "@react-aria/interactions": "^3.25.5", - "@react-aria/utils": "^3.30.1", - "@react-types/shared": "^3.32.0", + "@react-aria/interactions": "^3.25.6", + "@react-aria/utils": "^3.31.0", + "@react-types/shared": "^3.32.1", "@swc/helpers": "^0.5.0", "clsx": "^2.0.0" }, @@ -930,15 +1305,15 @@ } }, "node_modules/@react-aria/interactions": { - "version": "3.25.5", - "resolved": "https://registry.npmjs.org/@react-aria/interactions/-/interactions-3.25.5.tgz", - "integrity": "sha512-EweYHOEvMwef/wsiEqV73KurX/OqnmbzKQa2fLxdULbec5+yDj6wVGaRHIzM4NiijIDe+bldEl5DG05CAKOAHA==", + "version": "3.25.6", + "resolved": "https://registry.npmjs.org/@react-aria/interactions/-/interactions-3.25.6.tgz", + "integrity": "sha512-5UgwZmohpixwNMVkMvn9K1ceJe6TzlRlAfuYoQDUuOkk62/JVJNDLAPKIf5YMRc7d2B0rmfgaZLMtbREb0Zvkw==", "license": "Apache-2.0", "dependencies": { "@react-aria/ssr": "^3.9.10", - "@react-aria/utils": "^3.30.1", + "@react-aria/utils": "^3.31.0", "@react-stately/flags": "^3.1.2", - "@react-types/shared": "^3.32.0", + "@react-types/shared": "^3.32.1", "@swc/helpers": "^0.5.0" }, "peerDependencies": { @@ -962,15 +1337,15 @@ } }, "node_modules/@react-aria/utils": { - "version": "3.30.1", - "resolved": "https://registry.npmjs.org/@react-aria/utils/-/utils-3.30.1.tgz", - "integrity": "sha512-zETcbDd6Vf9GbLndO6RiWJadIZsBU2MMm23rBACXLmpRztkrIqPEb2RVdlLaq1+GklDx0Ii6PfveVjx+8S5U6A==", + "version": "3.31.0", + "resolved": "https://registry.npmjs.org/@react-aria/utils/-/utils-3.31.0.tgz", + "integrity": "sha512-ABOzCsZrWzf78ysswmguJbx3McQUja7yeGj6/vZo4JVsZNlxAN+E9rs381ExBRI0KzVo6iBTeX5De8eMZPJXig==", "license": "Apache-2.0", "dependencies": { "@react-aria/ssr": "^3.9.10", "@react-stately/flags": "^3.1.2", "@react-stately/utils": "^3.10.8", - "@react-types/shared": "^3.32.0", + "@react-types/shared": "^3.32.1", "@swc/helpers": "^0.5.0", "clsx": "^2.0.0" }, @@ -1001,9 +1376,9 @@ } }, "node_modules/@react-types/shared": { - "version": "3.32.0", - "resolved": "https://registry.npmjs.org/@react-types/shared/-/shared-3.32.0.tgz", - "integrity": "sha512-t+cligIJsZYFMSPFMvsJMjzlzde06tZMOIOFa1OV5Z0BcMowrb2g4mB57j/9nP28iJIRYn10xCniQts+qadrqQ==", + "version": "3.32.1", + "resolved": "https://registry.npmjs.org/@react-types/shared/-/shared-3.32.1.tgz", + "integrity": "sha512-famxyD5emrGGpFuUlgOP6fVW2h/ZaF405G5KDi3zPHzyjAWys/8W6NAVJtNbkCkhedmvL0xOhvt8feGXyXaw5w==", "license": "Apache-2.0", "peerDependencies": { "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1" @@ -1043,9 +1418,9 @@ "license": "MIT" }, "node_modules/@rollup/rollup-android-arm-eabi": { - "version": "4.52.3", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.52.3.tgz", - "integrity": "sha512-h6cqHGZ6VdnwliFG1NXvMPTy/9PS3h8oLh7ImwR+kl+oYnQizgjxsONmmPSb2C66RksfkfIxEVtDSEcJiO0tqw==", + "version": "4.52.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.52.4.tgz", + "integrity": "sha512-BTm2qKNnWIQ5auf4deoetINJm2JzvihvGb9R6K/ETwKLql/Bb3Eg2H1FBp1gUb4YGbydMA3jcmQTR73q7J+GAA==", "cpu": [ "arm" ], @@ -1056,9 +1431,9 @@ ] }, "node_modules/@rollup/rollup-android-arm64": { - "version": "4.52.3", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.52.3.tgz", - "integrity": "sha512-wd+u7SLT/u6knklV/ifG7gr5Qy4GUbH2hMWcDauPFJzmCZUAJ8L2bTkVXC2niOIxp8lk3iH/QX8kSrUxVZrOVw==", + "version": "4.52.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.52.4.tgz", + "integrity": "sha512-P9LDQiC5vpgGFgz7GSM6dKPCiqR3XYN1WwJKA4/BUVDjHpYsf3iBEmVz62uyq20NGYbiGPR5cNHI7T1HqxNs2w==", "cpu": [ "arm64" ], @@ -1069,9 +1444,9 @@ ] }, "node_modules/@rollup/rollup-darwin-arm64": { - "version": "4.52.3", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.52.3.tgz", - "integrity": "sha512-lj9ViATR1SsqycwFkJCtYfQTheBdvlWJqzqxwc9f2qrcVrQaF/gCuBRTiTolkRWS6KvNxSk4KHZWG7tDktLgjg==", + "version": "4.52.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.52.4.tgz", + "integrity": "sha512-QRWSW+bVccAvZF6cbNZBJwAehmvG9NwfWHwMy4GbWi/BQIA/laTIktebT2ipVjNncqE6GLPxOok5hsECgAxGZg==", "cpu": [ "arm64" ], @@ -1082,9 +1457,9 @@ ] }, "node_modules/@rollup/rollup-darwin-x64": { - "version": "4.52.3", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.52.3.tgz", - "integrity": "sha512-+Dyo7O1KUmIsbzx1l+4V4tvEVnVQqMOIYtrxK7ncLSknl1xnMHLgn7gddJVrYPNZfEB8CIi3hK8gq8bDhb3h5A==", + "version": "4.52.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.52.4.tgz", + "integrity": "sha512-hZgP05pResAkRJxL1b+7yxCnXPGsXU0fG9Yfd6dUaoGk+FhdPKCJ5L1Sumyxn8kvw8Qi5PvQ8ulenUbRjzeCTw==", "cpu": [ "x64" ], @@ -1095,9 +1470,9 @@ ] }, "node_modules/@rollup/rollup-freebsd-arm64": { - "version": "4.52.3", - "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.52.3.tgz", - "integrity": "sha512-u9Xg2FavYbD30g3DSfNhxgNrxhi6xVG4Y6i9Ur1C7xUuGDW3banRbXj+qgnIrwRN4KeJ396jchwy9bCIzbyBEQ==", + "version": "4.52.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.52.4.tgz", + "integrity": "sha512-xmc30VshuBNUd58Xk4TKAEcRZHaXlV+tCxIXELiE9sQuK3kG8ZFgSPi57UBJt8/ogfhAF5Oz4ZSUBN77weM+mQ==", "cpu": [ "arm64" ], @@ -1108,9 +1483,9 @@ ] }, "node_modules/@rollup/rollup-freebsd-x64": { - "version": "4.52.3", - "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.52.3.tgz", - "integrity": "sha512-5M8kyi/OX96wtD5qJR89a/3x5x8x5inXBZO04JWhkQb2JWavOWfjgkdvUqibGJeNNaz1/Z1PPza5/tAPXICI6A==", + "version": "4.52.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.52.4.tgz", + "integrity": "sha512-WdSLpZFjOEqNZGmHflxyifolwAiZmDQzuOzIq9L27ButpCVpD7KzTRtEG1I0wMPFyiyUdOO+4t8GvrnBLQSwpw==", "cpu": [ "x64" ], @@ -1121,9 +1496,9 @@ ] }, "node_modules/@rollup/rollup-linux-arm-gnueabihf": { - "version": "4.52.3", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.52.3.tgz", - "integrity": "sha512-IoerZJ4l1wRMopEHRKOO16e04iXRDyZFZnNZKrWeNquh5d6bucjezgd+OxG03mOMTnS1x7hilzb3uURPkJ0OfA==", + "version": "4.52.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.52.4.tgz", + "integrity": "sha512-xRiOu9Of1FZ4SxVbB0iEDXc4ddIcjCv2aj03dmW8UrZIW7aIQ9jVJdLBIhxBI+MaTnGAKyvMwPwQnoOEvP7FgQ==", "cpu": [ "arm" ], @@ -1134,9 +1509,9 @@ ] }, "node_modules/@rollup/rollup-linux-arm-musleabihf": { - "version": "4.52.3", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.52.3.tgz", - "integrity": "sha512-ZYdtqgHTDfvrJHSh3W22TvjWxwOgc3ThK/XjgcNGP2DIwFIPeAPNsQxrJO5XqleSlgDux2VAoWQ5iJrtaC1TbA==", + "version": "4.52.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.52.4.tgz", + "integrity": "sha512-FbhM2p9TJAmEIEhIgzR4soUcsW49e9veAQCziwbR+XWB2zqJ12b4i/+hel9yLiD8pLncDH4fKIPIbt5238341Q==", "cpu": [ "arm" ], @@ -1147,9 +1522,9 @@ ] }, "node_modules/@rollup/rollup-linux-arm64-gnu": { - "version": "4.52.3", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.52.3.tgz", - "integrity": "sha512-NcViG7A0YtuFDA6xWSgmFb6iPFzHlf5vcqb2p0lGEbT+gjrEEz8nC/EeDHvx6mnGXnGCC1SeVV+8u+smj0CeGQ==", + "version": "4.52.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.52.4.tgz", + "integrity": "sha512-4n4gVwhPHR9q/g8lKCyz0yuaD0MvDf7dV4f9tHt0C73Mp8h38UCtSCSE6R9iBlTbXlmA8CjpsZoujhszefqueg==", "cpu": [ "arm64" ], @@ -1160,9 +1535,9 @@ ] }, "node_modules/@rollup/rollup-linux-arm64-musl": { - "version": "4.52.3", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.52.3.tgz", - "integrity": "sha512-d3pY7LWno6SYNXRm6Ebsq0DJGoiLXTb83AIPCXl9fmtIQs/rXoS8SJxxUNtFbJ5MiOvs+7y34np77+9l4nfFMw==", + "version": "4.52.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.52.4.tgz", + "integrity": "sha512-u0n17nGA0nvi/11gcZKsjkLj1QIpAuPFQbR48Subo7SmZJnGxDpspyw2kbpuoQnyK+9pwf3pAoEXerJs/8Mi9g==", "cpu": [ "arm64" ], @@ -1173,9 +1548,9 @@ ] }, "node_modules/@rollup/rollup-linux-loong64-gnu": { - "version": "4.52.3", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-gnu/-/rollup-linux-loong64-gnu-4.52.3.tgz", - "integrity": "sha512-3y5GA0JkBuirLqmjwAKwB0keDlI6JfGYduMlJD/Rl7fvb4Ni8iKdQs1eiunMZJhwDWdCvrcqXRY++VEBbvk6Eg==", + "version": "4.52.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-gnu/-/rollup-linux-loong64-gnu-4.52.4.tgz", + "integrity": "sha512-0G2c2lpYtbTuXo8KEJkDkClE/+/2AFPdPAbmaHoE870foRFs4pBrDehilMcrSScrN/fB/1HTaWO4bqw+ewBzMQ==", "cpu": [ "loong64" ], @@ -1186,9 +1561,9 @@ ] }, "node_modules/@rollup/rollup-linux-ppc64-gnu": { - "version": "4.52.3", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.52.3.tgz", - "integrity": "sha512-AUUH65a0p3Q0Yfm5oD2KVgzTKgwPyp9DSXc3UA7DtxhEb/WSPfbG4wqXeSN62OG5gSo18em4xv6dbfcUGXcagw==", + "version": "4.52.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.52.4.tgz", + "integrity": "sha512-teSACug1GyZHmPDv14VNbvZFX779UqWTsd7KtTM9JIZRDI5NUwYSIS30kzI8m06gOPB//jtpqlhmraQ68b5X2g==", "cpu": [ "ppc64" ], @@ -1199,9 +1574,9 @@ ] }, "node_modules/@rollup/rollup-linux-riscv64-gnu": { - "version": "4.52.3", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.52.3.tgz", - "integrity": "sha512-1makPhFFVBqZE+XFg3Dkq+IkQ7JvmUrwwqaYBL2CE+ZpxPaqkGaiWFEWVGyvTwZace6WLJHwjVh/+CXbKDGPmg==", + "version": "4.52.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.52.4.tgz", + "integrity": "sha512-/MOEW3aHjjs1p4Pw1Xk4+3egRevx8Ji9N6HUIA1Ifh8Q+cg9dremvFCUbOX2Zebz80BwJIgCBUemjqhU5XI5Eg==", "cpu": [ "riscv64" ], @@ -1212,9 +1587,9 @@ ] }, "node_modules/@rollup/rollup-linux-riscv64-musl": { - "version": "4.52.3", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.52.3.tgz", - "integrity": "sha512-OOFJa28dxfl8kLOPMUOQBCO6z3X2SAfzIE276fwT52uXDWUS178KWq0pL7d6p1kz7pkzA0yQwtqL0dEPoVcRWg==", + "version": "4.52.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.52.4.tgz", + "integrity": "sha512-1HHmsRyh845QDpEWzOFtMCph5Ts+9+yllCrREuBR/vg2RogAQGGBRC8lDPrPOMnrdOJ+mt1WLMOC2Kao/UwcvA==", "cpu": [ "riscv64" ], @@ -1225,9 +1600,9 @@ ] }, "node_modules/@rollup/rollup-linux-s390x-gnu": { - "version": "4.52.3", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.52.3.tgz", - "integrity": "sha512-jMdsML2VI5l+V7cKfZx3ak+SLlJ8fKvLJ0Eoa4b9/vCUrzXKgoKxvHqvJ/mkWhFiyp88nCkM5S2v6nIwRtPcgg==", + "version": "4.52.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.52.4.tgz", + "integrity": "sha512-seoeZp4L/6D1MUyjWkOMRU6/iLmCU2EjbMTyAG4oIOs1/I82Y5lTeaxW0KBfkUdHAWN7j25bpkt0rjnOgAcQcA==", "cpu": [ "s390x" ], @@ -1238,9 +1613,9 @@ ] }, "node_modules/@rollup/rollup-linux-x64-gnu": { - "version": "4.52.3", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.52.3.tgz", - "integrity": "sha512-tPgGd6bY2M2LJTA1uGq8fkSPK8ZLYjDjY+ZLK9WHncCnfIz29LIXIqUgzCR0hIefzy6Hpbe8Th5WOSwTM8E7LA==", + "version": "4.52.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.52.4.tgz", + "integrity": "sha512-Wi6AXf0k0L7E2gteNsNHUs7UMwCIhsCTs6+tqQ5GPwVRWMaflqGec4Sd8n6+FNFDw9vGcReqk2KzBDhCa1DLYg==", "cpu": [ "x64" ], @@ -1251,9 +1626,9 @@ ] }, "node_modules/@rollup/rollup-linux-x64-musl": { - "version": "4.52.3", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.52.3.tgz", - "integrity": "sha512-BCFkJjgk+WFzP+tcSMXq77ymAPIxsX9lFJWs+2JzuZTLtksJ2o5hvgTdIcZ5+oKzUDMwI0PfWzRBYAydAHF2Mw==", + "version": "4.52.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.52.4.tgz", + "integrity": "sha512-dtBZYjDmCQ9hW+WgEkaffvRRCKm767wWhxsFW3Lw86VXz/uJRuD438/XvbZT//B96Vs8oTA8Q4A0AfHbrxP9zw==", "cpu": [ "x64" ], @@ -1264,9 +1639,9 @@ ] }, "node_modules/@rollup/rollup-openharmony-arm64": { - "version": "4.52.3", - "resolved": "https://registry.npmjs.org/@rollup/rollup-openharmony-arm64/-/rollup-openharmony-arm64-4.52.3.tgz", - "integrity": "sha512-KTD/EqjZF3yvRaWUJdD1cW+IQBk4fbQaHYJUmP8N4XoKFZilVL8cobFSTDnjTtxWJQ3JYaMgF4nObY/+nYkumA==", + "version": "4.52.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-openharmony-arm64/-/rollup-openharmony-arm64-4.52.4.tgz", + "integrity": "sha512-1ox+GqgRWqaB1RnyZXL8PD6E5f7YyRUJYnCqKpNzxzP0TkaUh112NDrR9Tt+C8rJ4x5G9Mk8PQR3o7Ku2RKqKA==", "cpu": [ "arm64" ], @@ -1277,9 +1652,9 @@ ] }, "node_modules/@rollup/rollup-win32-arm64-msvc": { - "version": "4.52.3", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.52.3.tgz", - "integrity": "sha512-+zteHZdoUYLkyYKObGHieibUFLbttX2r+58l27XZauq0tcWYYuKUwY2wjeCN9oK1Um2YgH2ibd6cnX/wFD7DuA==", + "version": "4.52.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.52.4.tgz", + "integrity": "sha512-8GKr640PdFNXwzIE0IrkMWUNUomILLkfeHjXBi/nUvFlpZP+FA8BKGKpacjW6OUUHaNI6sUURxR2U2g78FOHWQ==", "cpu": [ "arm64" ], @@ -1290,9 +1665,9 @@ ] }, "node_modules/@rollup/rollup-win32-ia32-msvc": { - "version": "4.52.3", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.52.3.tgz", - "integrity": "sha512-of1iHkTQSo3kr6dTIRX6t81uj/c/b15HXVsPcEElN5sS859qHrOepM5p9G41Hah+CTqSh2r8Bm56dL2z9UQQ7g==", + "version": "4.52.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.52.4.tgz", + "integrity": "sha512-AIy/jdJ7WtJ/F6EcfOb2GjR9UweO0n43jNObQMb6oGxkYTfLcnN7vYYpG+CN3lLxrQkzWnMOoNSHTW54pgbVxw==", "cpu": [ "ia32" ], @@ -1303,9 +1678,9 @@ ] }, "node_modules/@rollup/rollup-win32-x64-gnu": { - "version": "4.52.3", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-gnu/-/rollup-win32-x64-gnu-4.52.3.tgz", - "integrity": "sha512-s0hybmlHb56mWVZQj8ra9048/WZTPLILKxcvcq+8awSZmyiSUZjjem1AhU3Tf4ZKpYhK4mg36HtHDOe8QJS5PQ==", + "version": "4.52.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-gnu/-/rollup-win32-x64-gnu-4.52.4.tgz", + "integrity": "sha512-UF9KfsH9yEam0UjTwAgdK0anlQ7c8/pWPU2yVjyWcF1I1thABt6WXE47cI71pGiZ8wGvxohBoLnxM04L/wj8mQ==", "cpu": [ "x64" ], @@ -1316,9 +1691,9 @@ ] }, "node_modules/@rollup/rollup-win32-x64-msvc": { - "version": "4.52.3", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.52.3.tgz", - "integrity": "sha512-zGIbEVVXVtauFgl3MRwGWEN36P5ZGenHRMgNw88X5wEhEBpq0XrMEZwOn07+ICrwM17XO5xfMZqh0OldCH5VTA==", + "version": "4.52.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.52.4.tgz", + "integrity": "sha512-bf9PtUa0u8IXDVxzRToFQKsNCRz9qLYfR/MpECxl4mRoWYjAeFjgxj1XdZr2M/GNVpT05p+LgQOHopYDlUu6/w==", "cpu": [ "x64" ], @@ -1334,6 +1709,23 @@ "integrity": "sha512-zt6OdqaDoOnJ1ZYsCYGt9YmWzDXl4vQdKTyJev62gFhRGKdx7mcT54V9KIjg+d2wi9EXsPvAPKe7i7WjfVWB8g==", "license": "MIT" }, + "node_modules/@sinclair/typebox": { + "version": "0.31.28", + "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.31.28.tgz", + "integrity": "sha512-/s55Jujywdw/Jpan+vsy6JZs1z2ZTGxTmbZTPiuSL2wz9mfzA2gN1zzaqmvfi4pq+uOt7Du85fkiwv5ymW84aQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/@sqlite.org/sqlite-wasm": { + "version": "3.48.0-build4", + "resolved": "https://registry.npmjs.org/@sqlite.org/sqlite-wasm/-/sqlite-wasm-3.48.0-build4.tgz", + "integrity": "sha512-hI6twvUkzOmyGZhQMza1gpfqErZxXRw6JEsiVjUbo7tFanVD+8Oil0Ih3l2nGzHdxPI41zFmfUQG7GHqhciKZQ==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "sqlite-wasm": "bin/index.js" + } + }, "node_modules/@standard-schema/spec": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/@standard-schema/spec/-/spec-1.0.0.tgz", @@ -2007,21 +2399,21 @@ "license": "MIT" }, "node_modules/@types/react": { - "version": "19.1.17", - "resolved": "https://registry.npmjs.org/@types/react/-/react-19.1.17.tgz", - "integrity": "sha512-Qec1E3mhALmaspIrhWt9jkQMNdw6bReVu64mjvhbhq2NFPftLPVr+l1SZgmw/66WwBNpDh7ao5AT6gF5v41PFA==", + "version": "19.2.2", + "resolved": "https://registry.npmjs.org/@types/react/-/react-19.2.2.tgz", + "integrity": "sha512-6mDvHUFSjyT2B2yeNx2nUgMxh9LtOWvkhIU3uePn2I2oyNymUAX1NIsdgviM4CH+JSrp2D2hsMvJOkxY+0wNRA==", "license": "MIT", "dependencies": { "csstype": "^3.0.2" } }, "node_modules/@types/react-dom": { - "version": "19.1.11", - "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-19.1.11.tgz", - "integrity": "sha512-3BKc/yGdNTYQVVw4idqHtSOcFsgGuBbMveKCOgF8wQ5QtrYOc3jDIlzg3jef04zcXFIHLelyGlj0T+BJ8+KN+w==", + "version": "19.2.2", + "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-19.2.2.tgz", + "integrity": "sha512-9KQPoO6mZCi7jcIStSnlOWn2nEF3mNmyr3rIAsGnAbQKYbRLyqmeSc39EVgtxXVia+LMT8j3knZLAZAh+xLmrw==", "license": "MIT", "peerDependencies": { - "@types/react": "^19.0.0" + "@types/react": "^19.2.0" } }, "node_modules/@types/semver": { @@ -2045,17 +2437,17 @@ "license": "MIT" }, "node_modules/@typescript-eslint/eslint-plugin": { - "version": "8.45.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.45.0.tgz", - "integrity": "sha512-HC3y9CVuevvWCl/oyZuI47dOeDF9ztdMEfMH8/DW/Mhwa9cCLnK1oD7JoTVGW/u7kFzNZUKUoyJEqkaJh5y3Wg==", + "version": "8.46.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.46.1.tgz", + "integrity": "sha512-rUsLh8PXmBjdiPY+Emjz9NX2yHvhS11v0SR6xNJkm5GM1MO9ea/1GoDKlHHZGrOJclL/cZ2i/vRUYVtjRhrHVQ==", "dev": true, "license": "MIT", "dependencies": { "@eslint-community/regexpp": "^4.10.0", - "@typescript-eslint/scope-manager": "8.45.0", - "@typescript-eslint/type-utils": "8.45.0", - "@typescript-eslint/utils": "8.45.0", - "@typescript-eslint/visitor-keys": "8.45.0", + "@typescript-eslint/scope-manager": "8.46.1", + "@typescript-eslint/type-utils": "8.46.1", + "@typescript-eslint/utils": "8.46.1", + "@typescript-eslint/visitor-keys": "8.46.1", "graphemer": "^1.4.0", "ignore": "^7.0.0", "natural-compare": "^1.4.0", @@ -2069,7 +2461,7 @@ "url": "https://opencollective.com/typescript-eslint" }, "peerDependencies": { - "@typescript-eslint/parser": "^8.45.0", + "@typescript-eslint/parser": "^8.46.1", "eslint": "^8.57.0 || ^9.0.0", "typescript": ">=4.8.4 <6.0.0" } @@ -2085,16 +2477,16 @@ } }, "node_modules/@typescript-eslint/parser": { - "version": "8.45.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.45.0.tgz", - "integrity": "sha512-TGf22kon8KW+DeKaUmOibKWktRY8b2NSAZNdtWh798COm1NWx8+xJ6iFBtk3IvLdv6+LGLJLRlyhrhEDZWargQ==", + "version": "8.46.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.46.1.tgz", + "integrity": "sha512-6JSSaBZmsKvEkbRUkf7Zj7dru/8ZCrJxAqArcLaVMee5907JdtEbKGsZ7zNiIm/UAkpGUkaSMZEXShnN2D1HZA==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/scope-manager": "8.45.0", - "@typescript-eslint/types": "8.45.0", - "@typescript-eslint/typescript-estree": "8.45.0", - "@typescript-eslint/visitor-keys": "8.45.0", + "@typescript-eslint/scope-manager": "8.46.1", + "@typescript-eslint/types": "8.46.1", + "@typescript-eslint/typescript-estree": "8.46.1", + "@typescript-eslint/visitor-keys": "8.46.1", "debug": "^4.3.4" }, "engines": { @@ -2110,14 +2502,14 @@ } }, "node_modules/@typescript-eslint/project-service": { - "version": "8.45.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.45.0.tgz", - "integrity": "sha512-3pcVHwMG/iA8afdGLMuTibGR7pDsn9RjDev6CCB+naRsSYs2pns5QbinF4Xqw6YC/Sj3lMrm/Im0eMfaa61WUg==", + "version": "8.46.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.46.1.tgz", + "integrity": "sha512-FOIaFVMHzRskXr5J4Jp8lFVV0gz5ngv3RHmn+E4HYxSJ3DgDzU7fVI1/M7Ijh1zf6S7HIoaIOtln1H5y8V+9Zg==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/tsconfig-utils": "^8.45.0", - "@typescript-eslint/types": "^8.45.0", + "@typescript-eslint/tsconfig-utils": "^8.46.1", + "@typescript-eslint/types": "^8.46.1", "debug": "^4.3.4" }, "engines": { @@ -2132,14 +2524,14 @@ } }, "node_modules/@typescript-eslint/scope-manager": { - "version": "8.45.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.45.0.tgz", - "integrity": "sha512-clmm8XSNj/1dGvJeO6VGH7EUSeA0FMs+5au/u3lrA3KfG8iJ4u8ym9/j2tTEoacAffdW1TVUzXO30W1JTJS7dA==", + "version": "8.46.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.46.1.tgz", + "integrity": "sha512-weL9Gg3/5F0pVQKiF8eOXFZp8emqWzZsOJuWRUNtHT+UNV2xSJegmpCNQHy37aEQIbToTq7RHKhWvOsmbM680A==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/types": "8.45.0", - "@typescript-eslint/visitor-keys": "8.45.0" + "@typescript-eslint/types": "8.46.1", + "@typescript-eslint/visitor-keys": "8.46.1" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -2150,9 +2542,9 @@ } }, "node_modules/@typescript-eslint/tsconfig-utils": { - "version": "8.45.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.45.0.tgz", - "integrity": "sha512-aFdr+c37sc+jqNMGhH+ajxPXwjv9UtFZk79k8pLoJ6p4y0snmYpPA52GuWHgt2ZF4gRRW6odsEj41uZLojDt5w==", + "version": "8.46.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.46.1.tgz", + "integrity": "sha512-X88+J/CwFvlJB+mK09VFqx5FE4H5cXD+H/Bdza2aEWkSb8hnWIQorNcscRl4IEo1Cz9VI/+/r/jnGWkbWPx54g==", "dev": true, "license": "MIT", "engines": { @@ -2167,15 +2559,15 @@ } }, "node_modules/@typescript-eslint/type-utils": { - "version": "8.45.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.45.0.tgz", - "integrity": "sha512-bpjepLlHceKgyMEPglAeULX1vixJDgaKocp0RVJ5u4wLJIMNuKtUXIczpJCPcn2waII0yuvks/5m5/h3ZQKs0A==", + "version": "8.46.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.46.1.tgz", + "integrity": "sha512-+BlmiHIiqufBxkVnOtFwjah/vrkF4MtKKvpXrKSPLCkCtAp8H01/VV43sfqA98Od7nJpDcFnkwgyfQbOG0AMvw==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/types": "8.45.0", - "@typescript-eslint/typescript-estree": "8.45.0", - "@typescript-eslint/utils": "8.45.0", + "@typescript-eslint/types": "8.46.1", + "@typescript-eslint/typescript-estree": "8.46.1", + "@typescript-eslint/utils": "8.46.1", "debug": "^4.3.4", "ts-api-utils": "^2.1.0" }, @@ -2192,9 +2584,9 @@ } }, "node_modules/@typescript-eslint/types": { - "version": "8.45.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.45.0.tgz", - "integrity": "sha512-WugXLuOIq67BMgQInIxxnsSyRLFxdkJEJu8r4ngLR56q/4Q5LrbfkFRH27vMTjxEK8Pyz7QfzuZe/G15qQnVRA==", + "version": "8.46.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.46.1.tgz", + "integrity": "sha512-C+soprGBHwWBdkDpbaRC4paGBrkIXxVlNohadL5o0kfhsXqOC6GYH2S/Obmig+I0HTDl8wMaRySwrfrXVP8/pQ==", "dev": true, "license": "MIT", "engines": { @@ -2206,16 +2598,16 @@ } }, "node_modules/@typescript-eslint/typescript-estree": { - "version": "8.45.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.45.0.tgz", - "integrity": "sha512-GfE1NfVbLam6XQ0LcERKwdTTPlLvHvXXhOeUGC1OXi4eQBoyy1iVsW+uzJ/J9jtCz6/7GCQ9MtrQ0fml/jWCnA==", + "version": "8.46.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.46.1.tgz", + "integrity": "sha512-uIifjT4s8cQKFQ8ZBXXyoUODtRoAd7F7+G8MKmtzj17+1UbdzFl52AzRyZRyKqPHhgzvXunnSckVu36flGy8cg==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/project-service": "8.45.0", - "@typescript-eslint/tsconfig-utils": "8.45.0", - "@typescript-eslint/types": "8.45.0", - "@typescript-eslint/visitor-keys": "8.45.0", + "@typescript-eslint/project-service": "8.46.1", + "@typescript-eslint/tsconfig-utils": "8.46.1", + "@typescript-eslint/types": "8.46.1", + "@typescript-eslint/visitor-keys": "8.46.1", "debug": "^4.3.4", "fast-glob": "^3.3.2", "is-glob": "^4.0.3", @@ -2261,16 +2653,16 @@ } }, "node_modules/@typescript-eslint/utils": { - "version": "8.45.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.45.0.tgz", - "integrity": "sha512-bxi1ht+tLYg4+XV2knz/F7RVhU0k6VrSMc9sb8DQ6fyCTrGQLHfo7lDtN0QJjZjKkLA2ThrKuCdHEvLReqtIGg==", + "version": "8.46.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.46.1.tgz", + "integrity": "sha512-vkYUy6LdZS7q1v/Gxb2Zs7zziuXN0wxqsetJdeZdRe/f5dwJFglmuvZBfTUivCtjH725C1jWCDfpadadD95EDQ==", "dev": true, "license": "MIT", "dependencies": { "@eslint-community/eslint-utils": "^4.7.0", - "@typescript-eslint/scope-manager": "8.45.0", - "@typescript-eslint/types": "8.45.0", - "@typescript-eslint/typescript-estree": "8.45.0" + "@typescript-eslint/scope-manager": "8.46.1", + "@typescript-eslint/types": "8.46.1", + "@typescript-eslint/typescript-estree": "8.46.1" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -2285,13 +2677,13 @@ } }, "node_modules/@typescript-eslint/visitor-keys": { - "version": "8.45.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.45.0.tgz", - "integrity": "sha512-qsaFBA3e09MIDAGFUrTk+dzqtfv1XPVz8t8d1f0ybTzrCY7BKiMC5cjrl1O/P7UmHsNyW90EYSkU/ZWpmXelag==", + "version": "8.46.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.46.1.tgz", + "integrity": "sha512-ptkmIf2iDkNUjdeu2bQqhFPV1m6qTnFFjg7PPDjxKWaMaP0Z6I9l30Jr3g5QqbZGdw8YdYvLp+XnqnWWZOg/NA==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/types": "8.45.0", + "@typescript-eslint/types": "8.46.1", "eslint-visitor-keys": "^4.2.1" }, "engines": { @@ -2494,6 +2886,13 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/array-timsort": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/array-timsort/-/array-timsort-1.0.3.tgz", + "integrity": "sha512-/+3GRL7dDAGEfM6TseQk/U+mi18TU2Ms9I3UlLdUMhz2hbvGNTKdj9xniwXfUqgYhHxRx0+8UnKkvlNwVU+cWQ==", + "dev": true, + "license": "MIT" + }, "node_modules/array.prototype.findlast": { "version": "1.2.5", "resolved": "https://registry.npmjs.org/array.prototype.findlast/-/array.prototype.findlast-1.2.5.tgz", @@ -2679,9 +3078,9 @@ "license": "MIT" }, "node_modules/baseline-browser-mapping": { - "version": "2.8.10", - "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.8.10.tgz", - "integrity": "sha512-uLfgBi+7IBNay8ECBO2mVMGZAc1VgZWEChxm4lv+TobGdG82LnXMjuNGo/BSSZZL4UmkWhxEHP2f5ziLNwGWMA==", + "version": "2.8.14", + "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.8.14.tgz", + "integrity": "sha512-GM9c0cWWR8Ga7//Ves/9KRgTS8nLausCkP3CGiFLrnwA2CDUluXgaQqvrULoR2Ujrd/mz/lkX87F5BHFsNr5sQ==", "dev": true, "license": "Apache-2.0", "bin": { @@ -2802,9 +3201,9 @@ } }, "node_modules/caniuse-lite": { - "version": "1.0.30001746", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001746.tgz", - "integrity": "sha512-eA7Ys/DGw+pnkWWSE/id29f2IcPHVoE8wxtvE5JdvD2V28VTDPy1yEeo11Guz0sJ4ZeGRcm3uaTcAqK1LXaphA==", + "version": "1.0.30001749", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001749.tgz", + "integrity": "sha512-0rw2fJOmLfnzCRbkm8EyHL8SvI2Apu5UbnQuTsJ0ClgrH8hcwFooJ1s5R0EP8o8aVrFu8++ae29Kt9/gZAZp/Q==", "dev": true, "funding": [ { @@ -2875,12 +3274,54 @@ "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", "license": "MIT" }, + "node_modules/commander": { + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-11.1.0.tgz", + "integrity": "sha512-yPVavfyCcRhmorC7rWlkHn15b4wDVgVmBA7kV4QVBsF7kv/9TKJAbAXVTxvTnwP8HHKjRCJDClKbciiYS7p0DQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=16" + } + }, + "node_modules/comment-json": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/comment-json/-/comment-json-4.4.1.tgz", + "integrity": "sha512-r1To31BQD5060QdkC+Iheai7gHwoSZobzunqkf2/kQ6xIAfJyrKNAFUwdKvkK7Qgu7pVTKQEa7ok7Ed3ycAJgg==", + "dev": true, + "license": "MIT", + "dependencies": { + "array-timsort": "^1.0.3", + "core-util-is": "^1.0.3", + "esprima": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, "node_modules/concat-map": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", "license": "MIT" }, + "node_modules/consola": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/consola/-/consola-3.4.0.tgz", + "integrity": "sha512-EiPU8G6dQG0GFHNR8ljnZFki/8a+cQwEQ+7wpxdChl02Q8HXlwEZWD5lqAF8vC2sEC3Tehr8hy7vErz88LHyUA==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^14.18.0 || >=16.10.0" + } + }, + "node_modules/convert-source-map": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", + "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", + "dev": true, + "license": "MIT" + }, "node_modules/cookie": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/cookie/-/cookie-1.0.2.tgz", @@ -2890,6 +3331,13 @@ "node": ">=18" } }, + "node_modules/core-util-is": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz", + "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==", + "dev": true, + "license": "MIT" + }, "node_modules/cross-spawn": { "version": "7.0.6", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", @@ -3144,6 +3592,21 @@ "integrity": "sha512-qIMFpTMZmny+MMIitAB6D7iVPEorVw6YQRWkvarTkT4tBeSLLiHzcwj6q0MmYSFCiVpiqPJTJEYIrpcPzVEIvg==", "license": "MIT" }, + "node_modules/dedent": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/dedent/-/dedent-1.5.1.tgz", + "integrity": "sha512-+LxW+KLWxu3HW3M2w2ympwtqPrqYRzU8fqi6Fhd18fBALe15blJPI/I4+UHveMVG6lJqB4JNd4UG0S5cnVHwIg==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "babel-plugin-macros": "^3.1.0" + }, + "peerDependenciesMeta": { + "babel-plugin-macros": { + "optional": true + } + } + }, "node_modules/deep-is": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", @@ -3185,9 +3648,9 @@ } }, "node_modules/detect-libc": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.1.1.tgz", - "integrity": "sha512-ecqj/sy1jcK1uWrwpR67UhYrIFQ+5WlGxth34WquCbamhFA6hkkwiu37o6J5xCHdo1oixJRfVRw+ywV+Hq/0Aw==", + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.1.2.tgz", + "integrity": "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==", "devOptional": true, "license": "Apache-2.0", "engines": { @@ -3221,9 +3684,9 @@ } }, "node_modules/electron-to-chromium": { - "version": "1.5.228", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.228.tgz", - "integrity": "sha512-nxkiyuqAn4MJ1QbobwqJILiDtu/jk14hEAWaMiJmNPh1Z+jqoFlBFZjdXwLWGeVSeu9hGLg6+2G9yJaW8rBIFA==", + "version": "1.5.233", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.233.tgz", + "integrity": "sha512-iUdTQSf7EFXsDdQsp8MwJz5SVk4APEFqXU/S47OtQ0YLqacSwPXdZ5vRlMX3neb07Cy2vgioNuRnWUXFwuslkg==", "dev": true, "license": "ISC" }, @@ -3412,9 +3875,9 @@ } }, "node_modules/es-toolkit": { - "version": "1.39.10", - "resolved": "https://registry.npmjs.org/es-toolkit/-/es-toolkit-1.39.10.tgz", - "integrity": "sha512-E0iGnTtbDhkeczB0T+mxmoVlT4YNweEKBLq7oaU4p11mecdsZpNWOglI4895Vh4usbQ+LsJiuLuI2L0Vdmfm2w==", + "version": "1.40.0", + "resolved": "https://registry.npmjs.org/es-toolkit/-/es-toolkit-1.40.0.tgz", + "integrity": "sha512-8o6w0KFmU0CiIl0/Q/BCEOabF2IJaELM1T2PWj6e8KqzHv1gdx+7JtFnDwOx1kJH/isJ5NwlDG1nCr1HrRF94Q==", "license": "MIT", "workspaces": [ "docs", @@ -3462,6 +3925,19 @@ "@esbuild/win32-x64": "0.25.10" } }, + "node_modules/esbuild-wasm": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/esbuild-wasm/-/esbuild-wasm-0.19.12.tgz", + "integrity": "sha512-Zmc4hk6FibJZBcTx5/8K/4jT3/oG1vkGTEeKJUQFCUQKimD6Q7+adp/bdVQyYJFolMKaXkQnVZdV4O5ZaTYmyQ==", + "dev": true, + "license": "MIT", + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=12" + } + }, "node_modules/escalade": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", @@ -3485,19 +3961,19 @@ } }, "node_modules/eslint": { - "version": "9.36.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.36.0.tgz", - "integrity": "sha512-hB4FIzXovouYzwzECDcUkJ4OcfOEkXTv2zRY6B9bkwjx/cprAq0uvm1nl7zvQ0/TsUk0zQiN4uPfJpB9m+rPMQ==", + "version": "9.37.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.37.0.tgz", + "integrity": "sha512-XyLmROnACWqSxiGYArdef1fItQd47weqB7iwtfr9JHwRrqIXZdcFMvvEcL9xHCmL0SNsOvF0c42lWyM1U5dgig==", "license": "MIT", "dependencies": { "@eslint-community/eslint-utils": "^4.8.0", "@eslint-community/regexpp": "^4.12.1", "@eslint/config-array": "^0.21.0", - "@eslint/config-helpers": "^0.3.1", - "@eslint/core": "^0.15.2", + "@eslint/config-helpers": "^0.4.0", + "@eslint/core": "^0.16.0", "@eslint/eslintrc": "^3.3.1", - "@eslint/js": "9.36.0", - "@eslint/plugin-kit": "^0.3.5", + "@eslint/js": "9.37.0", + "@eslint/plugin-kit": "^0.4.0", "@humanfs/node": "^0.16.6", "@humanwhocodes/module-importer": "^1.0.1", "@humanwhocodes/retry": "^0.4.2", @@ -3550,6 +4026,8 @@ "integrity": "sha512-82GZUjRS0p/jganf6q1rEO25VSoHH0hKPCTrgillPjdI/3bgBhAE1QzHrHTizjpRvy6pGAvKjDJtk2pF9NDq8w==", "dev": true, "license": "MIT", + "optional": true, + "peer": true, "bin": { "eslint-config-prettier": "bin/cli.js" }, @@ -3669,6 +4147,37 @@ "semver": "bin/semver.js" } }, + "node_modules/eslint-plugin-prettier": { + "version": "5.5.4", + "resolved": "https://registry.npmjs.org/eslint-plugin-prettier/-/eslint-plugin-prettier-5.5.4.tgz", + "integrity": "sha512-swNtI95SToIz05YINMA6Ox5R057IMAmWZ26GqPxusAp1TZzj+IdY9tXNWWD3vkF/wEqydCONcwjTFpxybBqZsg==", + "dev": true, + "license": "MIT", + "dependencies": { + "prettier-linter-helpers": "^1.0.0", + "synckit": "^0.11.7" + }, + "engines": { + "node": "^14.18.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint-plugin-prettier" + }, + "peerDependencies": { + "@types/eslint": ">=8.0.0", + "eslint": ">=8.0.0", + "eslint-config-prettier": ">= 7.0.0 <10.0.0 || >=10.1.0", + "prettier": ">=3.0.0" + }, + "peerDependenciesMeta": { + "@types/eslint": { + "optional": true + }, + "eslint-config-prettier": { + "optional": true + } + } + }, "node_modules/eslint-plugin-react": { "version": "7.37.5", "resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.37.5.tgz", @@ -3703,22 +4212,29 @@ } }, "node_modules/eslint-plugin-react-hooks": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-5.2.0.tgz", - "integrity": "sha512-+f15FfK64YQwZdJNELETdn5ibXEUQmW1DZL6KXhNnc2heoy/sg9VJJeT7n8TlMWouzWqSWavFkIhHyIbIAEapg==", + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-7.0.0.tgz", + "integrity": "sha512-fNXaOwvKwq2+pXiRpXc825Vd63+KM4DLL40Rtlycb8m7fYpp6efrTp1sa6ZbP/Ap58K2bEKFXRmhURE+CJAQWw==", "dev": true, "license": "MIT", + "dependencies": { + "@babel/core": "^7.24.4", + "@babel/parser": "^7.24.4", + "hermes-parser": "^0.25.1", + "zod": "^3.22.4 || ^4.0.0", + "zod-validation-error": "^3.0.3 || ^4.0.0" + }, "engines": { - "node": ">=10" + "node": ">=18" }, "peerDependencies": { "eslint": "^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0 || ^9.0.0" } }, "node_modules/eslint-plugin-react-refresh": { - "version": "0.4.22", - "resolved": "https://registry.npmjs.org/eslint-plugin-react-refresh/-/eslint-plugin-react-refresh-0.4.22.tgz", - "integrity": "sha512-atkAG6QaJMGoTLc4MDAP+rqZcfwQuTIh2IqHWFLy2TEjxr0MOK+5BSG4RzL2564AAPpZkDRsZXAUz68kjnU6Ug==", + "version": "0.4.23", + "resolved": "https://registry.npmjs.org/eslint-plugin-react-refresh/-/eslint-plugin-react-refresh-0.4.23.tgz", + "integrity": "sha512-G4j+rv0NmbIR45kni5xJOrYvCtyD3/7LjpVH8MPPcudXDcNu8gv+4ATTDXTtbRR8rTCM5HxECvCSsRmxKnWDsA==", "dev": true, "license": "MIT", "peerDependencies": { @@ -3781,18 +4297,6 @@ "url": "https://opencollective.com/eslint" } }, - "node_modules/eslint/node_modules/@eslint/core": { - "version": "0.15.2", - "resolved": "https://registry.npmjs.org/@eslint/core/-/core-0.15.2.tgz", - "integrity": "sha512-78Md3/Rrxh83gCxoUc0EiciuOHsIITzLy53m3d9UyiW8y9Dj2D29FeETqyKA+BRK76tnTp6RXWb3pCay8Oyomg==", - "license": "Apache-2.0", - "dependencies": { - "@types/json-schema": "^7.0.15" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - } - }, "node_modules/eslint/node_modules/eslint-visitor-keys": { "version": "4.2.1", "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.1.tgz", @@ -3834,6 +4338,20 @@ "url": "https://opencollective.com/eslint" } }, + "node_modules/esprima": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", + "dev": true, + "license": "BSD-2-Clause", + "bin": { + "esparse": "bin/esparse.js", + "esvalidate": "bin/esvalidate.js" + }, + "engines": { + "node": ">=4" + } + }, "node_modules/esquery": { "version": "1.6.0", "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.6.0.tgz", @@ -3888,6 +4406,13 @@ "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", "license": "MIT" }, + "node_modules/fast-diff": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/fast-diff/-/fast-diff-1.3.0.tgz", + "integrity": "sha512-VxPP4NqbUjj6MaAOafWeUn2cXWLcCtljklUtZf0Ind4XQ+QPtmA0b18zZy0jIQx+ExRVCR/ZQpBmik5lXshNsw==", + "dev": true, + "license": "Apache-2.0" + }, "node_modules/fast-glob": { "version": "3.3.3", "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.3.tgz", @@ -3981,6 +4506,19 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/flat": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/flat/-/flat-6.0.1.tgz", + "integrity": "sha512-/3FfIa8mbrg3xE7+wAhWeV+bd7L2Mof+xtZb5dRDKZ+wDvYJK4WDYeIOuOhre5Yv5aQObZrlbRmk3RTSiuQBtw==", + "dev": true, + "license": "BSD-3-Clause", + "bin": { + "flat": "cli.js" + }, + "engines": { + "node": ">=18" + } + }, "node_modules/flat-cache": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-4.0.1.tgz", @@ -4055,12 +4593,12 @@ } }, "node_modules/framer-motion": { - "version": "12.23.22", - "resolved": "https://registry.npmjs.org/framer-motion/-/framer-motion-12.23.22.tgz", - "integrity": "sha512-ZgGvdxXCw55ZYvhoZChTlG6pUuehecgvEAJz0BHoC5pQKW1EC5xf1Mul1ej5+ai+pVY0pylyFfdl45qnM1/GsA==", + "version": "12.23.24", + "resolved": "https://registry.npmjs.org/framer-motion/-/framer-motion-12.23.24.tgz", + "integrity": "sha512-HMi5HRoRCTou+3fb3h9oTLyJGBxHfW+HnNE25tAXOvVx/IvwMHK0cx7IR4a2ZU6sh3IX1Z+4ts32PcYBOqka8w==", "license": "MIT", "dependencies": { - "motion-dom": "^12.23.21", + "motion-dom": "^12.23.23", "motion-utils": "^12.23.6", "tslib": "^2.4.0" }, @@ -4142,6 +4680,16 @@ "node": ">= 0.4" } }, + "node_modules/gensync": { + "version": "1.0.0-beta.2", + "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", + "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, "node_modules/get-intrinsic": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz", @@ -4245,9 +4793,9 @@ "license": "MIT" }, "node_modules/goober": { - "version": "2.1.16", - "resolved": "https://registry.npmjs.org/goober/-/goober-2.1.16.tgz", - "integrity": "sha512-erjk19y1U33+XAMe1VTvIONHYoSqE4iS7BYUZfHaqeohLmnC0FdxEh7rQU+6MZ4OajItzjZFSRtVANrQwNq6/g==", + "version": "2.1.18", + "resolved": "https://registry.npmjs.org/goober/-/goober-2.1.18.tgz", + "integrity": "sha512-2vFqsaDVIT9Gz7N6kAL++pLpp41l3PfDuusHcjnGLfR6+huZkl6ziX+zgVC3ZxpqWhzH6pyDdGrCeDhMIvwaxw==", "license": "MIT", "peerDependencies": { "csstype": "^3.0.10" @@ -4366,6 +4914,33 @@ "node": ">= 0.4" } }, + "node_modules/hermes-estree": { + "version": "0.25.1", + "resolved": "https://registry.npmjs.org/hermes-estree/-/hermes-estree-0.25.1.tgz", + "integrity": "sha512-0wUoCcLp+5Ev5pDW2OriHC2MJCbwLwuRx+gAqMTOkGKJJiBCLjtrvy4PWUGn6MIVefecRpzoOZ/UV6iGdOr+Cw==", + "dev": true, + "license": "MIT" + }, + "node_modules/hermes-parser": { + "version": "0.25.1", + "resolved": "https://registry.npmjs.org/hermes-parser/-/hermes-parser-0.25.1.tgz", + "integrity": "sha512-6pEjquH3rqaI6cYAXYPcz9MS4rY6R4ngRgrgfDshRptUZIc3lw0MCIJIGDj9++mfySOuPTHB4nrSW99BCvOPIA==", + "dev": true, + "license": "MIT", + "dependencies": { + "hermes-estree": "0.25.1" + } + }, + "node_modules/human-id": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/human-id/-/human-id-4.1.2.tgz", + "integrity": "sha512-v/J+4Z/1eIJovEBdlV5TYj1IR+ZiohcYGRY+qN/oC9dAfKzVT023N/Bgw37hrKCoVRBvk3bqyzpr2PP5YeTMSg==", + "dev": true, + "license": "MIT", + "bin": { + "human-id": "dist/cli.js" + } + }, "node_modules/ignore": { "version": "5.3.2", "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", @@ -4847,6 +5422,13 @@ "integrity": "sha512-hNngCeKxIUQiEUN3GPJOkz4wF/YvdUdbNL9hsBcMQTkKzboD7T/q3OYOuuPZLUE6dBxSGpwhk5mwuDud7JVAow==", "license": "BSD-3-Clause" }, + "node_modules/js-sha256": { + "version": "0.11.1", + "resolved": "https://registry.npmjs.org/js-sha256/-/js-sha256-0.11.1.tgz", + "integrity": "sha512-o6WSo/LUvY2uC4j7mO50a2ms7E/EAdbP0swigLV+nzHKTTaYnaLIWJ02VdXrsJX0vGedDESQnLsOekr94ryfjg==", + "dev": true, + "license": "MIT" + }, "node_modules/js-tokens": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", @@ -4866,6 +5448,19 @@ "js-yaml": "bin/js-yaml.js" } }, + "node_modules/jsesc": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.1.0.tgz", + "integrity": "sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==", + "dev": true, + "license": "MIT", + "bin": { + "jsesc": "bin/jsesc" + }, + "engines": { + "node": ">=6" + } + }, "node_modules/json-buffer": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", @@ -4885,15 +5480,16 @@ "license": "MIT" }, "node_modules/json5": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.2.tgz", - "integrity": "sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==", + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", + "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", + "dev": true, "license": "MIT", - "dependencies": { - "minimist": "^1.2.0" - }, "bin": { "json5": "lib/cli.js" + }, + "engines": { + "node": ">=6" } }, "node_modules/jsx-ast-utils": { @@ -4921,6 +5517,16 @@ "json-buffer": "3.0.1" } }, + "node_modules/kysely": { + "version": "0.27.6", + "resolved": "https://registry.npmjs.org/kysely/-/kysely-0.27.6.tgz", + "integrity": "sha512-FIyV/64EkKhJmjgC0g2hygpBv5RNWVPyNCqSAD7eTCv6eFWNIi4PN1UvdSJGicN/o35bnevgis4Y0UDC0qi8jQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=14.0.0" + } + }, "node_modules/levn": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", @@ -5209,6 +5815,16 @@ "loose-envify": "cli.js" } }, + "node_modules/lru-cache": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", + "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", + "dev": true, + "license": "ISC", + "dependencies": { + "yallist": "^3.0.2" + } + }, "node_modules/magic-string": { "version": "0.30.19", "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.19.tgz", @@ -5306,9 +5922,9 @@ } }, "node_modules/motion-dom": { - "version": "12.23.21", - "resolved": "https://registry.npmjs.org/motion-dom/-/motion-dom-12.23.21.tgz", - "integrity": "sha512-5xDXx/AbhrfgsQmSE7YESMn4Dpo6x5/DTZ4Iyy4xqDvVHWvFVoV+V2Ri2S/ksx+D40wrZ7gPYiMWshkdoqNgNQ==", + "version": "12.23.23", + "resolved": "https://registry.npmjs.org/motion-dom/-/motion-dom-12.23.23.tgz", + "integrity": "sha512-n5yolOs0TQQBRUFImrRfs/+6X4p3Q4n1dUEqt/H58Vx7OW6RF+foWEgmTVDhIWJIMXOuNNL0apKH2S16en9eiA==", "license": "MIT", "dependencies": { "motion-utils": "^12.23.6" @@ -5351,9 +5967,9 @@ "license": "MIT" }, "node_modules/node-releases": { - "version": "2.0.21", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.21.tgz", - "integrity": "sha512-5b0pgg78U3hwXkCM8Z9b2FJdPZlr9Psr9V2gQPESdGHqbntyFJKFW4r5TeWGFzafGY3hzs1JC62VEQMbl1JFkw==", + "version": "2.0.23", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.23.tgz", + "integrity": "sha512-cCmFDMSm26S6tQSDpBCg/NR8NENrVPhAJSf+XbxBG4rPFaaonlEoE9wHQmun+cls499TQGSb7ZyPBRlzgKfpeg==", "dev": true, "license": "MIT" }, @@ -5686,6 +6302,19 @@ "url": "https://github.com/prettier/prettier?sponsor=1" } }, + "node_modules/prettier-linter-helpers": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/prettier-linter-helpers/-/prettier-linter-helpers-1.0.0.tgz", + "integrity": "sha512-GbK2cP9nraSSUF9N2XwUwqfzlAFlMNYYl+ShE/V+H8a9uNl/oUqB1w2EL54Jh0OlyRSd8RfWYJ3coVS4TROP2w==", + "dev": true, + "license": "MIT", + "dependencies": { + "fast-diff": "^1.1.2" + }, + "engines": { + "node": ">=6.0.0" + } + }, "node_modules/prettier-plugin-tailwindcss": { "version": "0.6.14", "resolved": "https://registry.npmjs.org/prettier-plugin-tailwindcss/-/prettier-plugin-tailwindcss-0.6.14.tgz", @@ -5823,9 +6452,9 @@ "license": "MIT" }, "node_modules/react": { - "version": "19.1.1", - "resolved": "https://registry.npmjs.org/react/-/react-19.1.1.tgz", - "integrity": "sha512-w8nqGImo45dmMIfljjMwOGtbmC/mk4CMYhWIicdSflH91J9TyCyczcPFXJzrZ/ZXcgGRFeP6BU0BEJTw6tZdfQ==", + "version": "19.2.0", + "resolved": "https://registry.npmjs.org/react/-/react-19.2.0.tgz", + "integrity": "sha512-tmbWg6W31tQLeB5cdIBOicJDJRR2KzXsV7uSK9iNfLWQ5bIZfxuPEHp7M8wiHyHnn0DD1i7w3Zmin0FtkrwoCQ==", "license": "MIT", "engines": { "node": ">=0.10.0" @@ -5845,15 +6474,15 @@ } }, "node_modules/react-dom": { - "version": "19.1.1", - "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.1.1.tgz", - "integrity": "sha512-Dlq/5LAZgF0Gaz6yiqZCf6VCcZs1ghAJyrsu84Q/GT0gV+mCxbfmKNoGRKBYMJ8IEdGPqu49YWXD02GCknEDkw==", + "version": "19.2.0", + "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.2.0.tgz", + "integrity": "sha512-UlbRu4cAiGaIewkPyiRGJk0imDN2T3JjieT6spoL2UeSf5od4n5LB/mQ4ejmxhCFT1tYe8IvaFulzynWovsEFQ==", "license": "MIT", "dependencies": { - "scheduler": "^0.26.0" + "scheduler": "^0.27.0" }, "peerDependencies": { - "react": "^19.1.1" + "react": "^19.2.0" } }, "node_modules/react-hot-toast": { @@ -5883,9 +6512,9 @@ } }, "node_modules/react-is": { - "version": "19.1.1", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-19.1.1.tgz", - "integrity": "sha512-tr41fA15Vn8p4X9ntI+yCyeGSf1TlYaY5vlTZfQmeLBrFo3psOPX6HhTDnFNL9uj3EhP0KAQ80cugCl4b4BERA==", + "version": "19.2.0", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-19.2.0.tgz", + "integrity": "sha512-x3Ax3kNSMIIkyVYhWPyO09bu0uttcAIoecO/um/rKGQ4EltYWVYtyiGkS/3xMynrbVQdS69Jhlv8FXUEZehlzA==", "license": "MIT", "peer": true }, @@ -5913,9 +6542,9 @@ } }, "node_modules/react-router": { - "version": "7.9.3", - "resolved": "https://registry.npmjs.org/react-router/-/react-router-7.9.3.tgz", - "integrity": "sha512-4o2iWCFIwhI/eYAIL43+cjORXYn/aRQPgtFRRZb3VzoyQ5Uej0Bmqj7437L97N9NJW4wnicSwLOLS+yCXfAPgg==", + "version": "7.9.4", + "resolved": "https://registry.npmjs.org/react-router/-/react-router-7.9.4.tgz", + "integrity": "sha512-SD3G8HKviFHg9xj7dNODUKDFgpG4xqD5nhyd0mYoB5iISepuZAvzSr8ywxgxKJ52yRzf/HWtVHc9AWwoTbljvA==", "license": "MIT", "dependencies": { "cookie": "^1.0.1", @@ -5935,9 +6564,9 @@ } }, "node_modules/react-simple-keyboard": { - "version": "3.8.125", - "resolved": "https://registry.npmjs.org/react-simple-keyboard/-/react-simple-keyboard-3.8.125.tgz", - "integrity": "sha512-8+PbmGA2auM7V57hapHsKV7IJcJVl0QNNW09RJQ7xCiohHuZNKvqrxGvisxhhr7X8C8TKulxbqdxjZbFelwO7w==", + "version": "3.8.130", + "resolved": "https://registry.npmjs.org/react-simple-keyboard/-/react-simple-keyboard-3.8.130.tgz", + "integrity": "sha512-sq51zg3fe4NPCRyDLYyAtot8+pIn9DmC+YqAEqx5FOIpHUC86Qvv2/0F2KvhLNDvgZ+5s4w649YKf1gWK8LiIQ==", "license": "MIT", "peerDependencies": { "react": "^16.0.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", @@ -6090,9 +6719,9 @@ } }, "node_modules/rollup": { - "version": "4.52.3", - "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.52.3.tgz", - "integrity": "sha512-RIDh866U8agLgiIcdpB+COKnlCreHJLfIhWC3LVflku5YHfpnsIKigRZeFfMfCc4dVcqNVfQQ5gO/afOck064A==", + "version": "4.52.4", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.52.4.tgz", + "integrity": "sha512-CLEVl+MnPAiKh5pl4dEWSyMTpuflgNQiLGhMv8ezD5W/qP8AKvmYpCOKRRNOh7oRKnauBZ4SyeYkMS+1VSyKwQ==", "license": "MIT", "dependencies": { "@types/estree": "1.0.8" @@ -6105,28 +6734,28 @@ "npm": ">=8.0.0" }, "optionalDependencies": { - "@rollup/rollup-android-arm-eabi": "4.52.3", - "@rollup/rollup-android-arm64": "4.52.3", - "@rollup/rollup-darwin-arm64": "4.52.3", - "@rollup/rollup-darwin-x64": "4.52.3", - "@rollup/rollup-freebsd-arm64": "4.52.3", - "@rollup/rollup-freebsd-x64": "4.52.3", - "@rollup/rollup-linux-arm-gnueabihf": "4.52.3", - "@rollup/rollup-linux-arm-musleabihf": "4.52.3", - "@rollup/rollup-linux-arm64-gnu": "4.52.3", - "@rollup/rollup-linux-arm64-musl": "4.52.3", - "@rollup/rollup-linux-loong64-gnu": "4.52.3", - "@rollup/rollup-linux-ppc64-gnu": "4.52.3", - "@rollup/rollup-linux-riscv64-gnu": "4.52.3", - "@rollup/rollup-linux-riscv64-musl": "4.52.3", - "@rollup/rollup-linux-s390x-gnu": "4.52.3", - "@rollup/rollup-linux-x64-gnu": "4.52.3", - "@rollup/rollup-linux-x64-musl": "4.52.3", - "@rollup/rollup-openharmony-arm64": "4.52.3", - "@rollup/rollup-win32-arm64-msvc": "4.52.3", - "@rollup/rollup-win32-ia32-msvc": "4.52.3", - "@rollup/rollup-win32-x64-gnu": "4.52.3", - "@rollup/rollup-win32-x64-msvc": "4.52.3", + "@rollup/rollup-android-arm-eabi": "4.52.4", + "@rollup/rollup-android-arm64": "4.52.4", + "@rollup/rollup-darwin-arm64": "4.52.4", + "@rollup/rollup-darwin-x64": "4.52.4", + "@rollup/rollup-freebsd-arm64": "4.52.4", + "@rollup/rollup-freebsd-x64": "4.52.4", + "@rollup/rollup-linux-arm-gnueabihf": "4.52.4", + "@rollup/rollup-linux-arm-musleabihf": "4.52.4", + "@rollup/rollup-linux-arm64-gnu": "4.52.4", + "@rollup/rollup-linux-arm64-musl": "4.52.4", + "@rollup/rollup-linux-loong64-gnu": "4.52.4", + "@rollup/rollup-linux-ppc64-gnu": "4.52.4", + "@rollup/rollup-linux-riscv64-gnu": "4.52.4", + "@rollup/rollup-linux-riscv64-musl": "4.52.4", + "@rollup/rollup-linux-s390x-gnu": "4.52.4", + "@rollup/rollup-linux-x64-gnu": "4.52.4", + "@rollup/rollup-linux-x64-musl": "4.52.4", + "@rollup/rollup-openharmony-arm64": "4.52.4", + "@rollup/rollup-win32-arm64-msvc": "4.52.4", + "@rollup/rollup-win32-ia32-msvc": "4.52.4", + "@rollup/rollup-win32-x64-gnu": "4.52.4", + "@rollup/rollup-win32-x64-msvc": "4.52.4", "fsevents": "~2.3.2" } }, @@ -6207,15 +6836,15 @@ } }, "node_modules/scheduler": { - "version": "0.26.0", - "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.26.0.tgz", - "integrity": "sha512-NlHwttCI/l5gCPR3D1nNXtWABUmBwvZpEQiD4IXSbIDq8BzLIK/7Ir5gTFSGZDUu37K5cMNp0hFtzO38sC7gWA==", + "version": "0.27.0", + "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.27.0.tgz", + "integrity": "sha512-eNv+WrVbKu1f3vbYJT/xtiF5syA5HPIMtf9IgY/nKg0sWqzAUEvqY/xm7OcZc/qafLx/iO9FgOmeSAp4v5ti/Q==", "license": "MIT" }, "node_modules/semver": { - "version": "7.7.2", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.2.tgz", - "integrity": "sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA==", + "version": "7.7.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.3.tgz", + "integrity": "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==", "dev": true, "license": "ISC", "bin": { @@ -6379,6 +7008,18 @@ "node": ">=0.10.0" } }, + "node_modules/sqlite-wasm-kysely": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/sqlite-wasm-kysely/-/sqlite-wasm-kysely-0.3.0.tgz", + "integrity": "sha512-TzjBNv7KwRw6E3pdKdlRyZiTmUIE0UttT/Sl56MVwVARl/u5gp978KepazCJZewFUnlWHz9i3NQd4kOtP/Afdg==", + "dev": true, + "dependencies": { + "@sqlite.org/sqlite-wasm": "^3.48.0-build2" + }, + "peerDependencies": { + "kysely": "*" + } + }, "node_modules/stop-iteration-iterator": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/stop-iteration-iterator/-/stop-iteration-iterator-1.1.0.tgz", @@ -6532,6 +7173,22 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/synckit": { + "version": "0.11.11", + "resolved": "https://registry.npmjs.org/synckit/-/synckit-0.11.11.tgz", + "integrity": "sha512-MeQTA1r0litLUf0Rp/iisCaL8761lKAZHaimlbGK4j0HysC4PLfqygQj9srcs0m2RdtDYnF8UuYyKpbjHYp7Jw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@pkgr/core": "^0.2.9" + }, + "engines": { + "node": "^14.18.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/synckit" + } + }, "node_modules/tabbable": { "version": "6.2.0", "resolved": "https://registry.npmjs.org/tabbable/-/tabbable-6.2.0.tgz", @@ -6555,9 +7212,9 @@ "license": "MIT" }, "node_modules/tapable": { - "version": "2.2.3", - "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.2.3.tgz", - "integrity": "sha512-ZL6DDuAlRlLGghwcfmSn9sK3Hr6ArtyudlSAiCqQ6IfE+b+HHbydbYDIG15IfS5do+7XQQBdBiubF/cV2dnDzg==", + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.3.0.tgz", + "integrity": "sha512-g9ljZiwki/LfxmQADO3dEY1CbpmXT5Hm2fJ+QaGKwSXUylMybePR7/67YW7jOrrvjEgL1Fmz5kzyAjWVWLlucg==", "dev": true, "license": "MIT", "engines": { @@ -6585,6 +7242,16 @@ "node": ">=18" } }, + "node_modules/tar/node_modules/yallist": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-5.0.0.tgz", + "integrity": "sha512-YgvUTfwqyc7UXVMrB+SImsVYSmTS8X/tSrtdNZMImM+n7+QTriRXyXim0mBrTXNeqzVF0KWGgHPeiyViFFrNDw==", + "dev": true, + "license": "BlueOak-1.0.0", + "engines": { + "node": ">=18" + } + }, "node_modules/tiny-invariant": { "version": "1.3.3", "resolved": "https://registry.npmjs.org/tiny-invariant/-/tiny-invariant-1.3.3.tgz", @@ -6695,6 +7362,18 @@ "strip-bom": "^3.0.0" } }, + "node_modules/tsconfig-paths/node_modules/json5": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.2.tgz", + "integrity": "sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==", + "license": "MIT", + "dependencies": { + "minimist": "^1.2.0" + }, + "bin": { + "json5": "lib/cli.js" + } + }, "node_modules/tslib": { "version": "2.8.1", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", @@ -6819,6 +7498,35 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/unplugin": { + "version": "2.3.10", + "resolved": "https://registry.npmjs.org/unplugin/-/unplugin-2.3.10.tgz", + "integrity": "sha512-6NCPkv1ClwH+/BGE9QeoTIl09nuiAt0gS28nn1PvYXsGKRwM2TCbFA2QiilmehPDTXIe684k4rZI1yl3A1PCUw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/remapping": "^2.3.5", + "acorn": "^8.15.0", + "picomatch": "^4.0.3", + "webpack-virtual-modules": "^0.6.2" + }, + "engines": { + "node": ">=18.12.0" + } + }, + "node_modules/unplugin/node_modules/picomatch": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz", + "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, "node_modules/update-browserslist-db": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.1.3.tgz", @@ -6859,10 +7567,17 @@ "punycode": "^2.1.0" } }, + "node_modules/urlpattern-polyfill": { + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/urlpattern-polyfill/-/urlpattern-polyfill-10.1.0.tgz", + "integrity": "sha512-IGjKp/o0NL3Bso1PymYURCJxMPNAf/ILOpendP9f5B6e1rTJgdgiOvgfoT8VxCAdY+Wisb9uhGaJJf3yZ2V9nw==", + "dev": true, + "license": "MIT" + }, "node_modules/use-sync-external-store": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.5.0.tgz", - "integrity": "sha512-Rb46I4cGGVBmjamjphe8L/UnvJD+uPPtTkNvX5mZgqdbavhI4EbgIWJiIHXJ8bc/i9EQGPRh4DwEURJ552Do0A==", + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.6.0.tgz", + "integrity": "sha512-Pp6GSwGP/NrPIrxVFAIkOQeyw8lFenOHijQWkUTrDvrF4ALqylP2C/KCkeS9dpUM3KvYRQhna5vt7IL95+ZQ9w==", "license": "MIT", "peerDependencies": { "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" @@ -6890,6 +7605,20 @@ "dev": true, "license": "MIT" }, + "node_modules/uuid": { + "version": "10.0.0", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-10.0.0.tgz", + "integrity": "sha512-8XkAphELsDnEGrDxUOHB3RGvXz6TeuYSGEZBOjtTtPm2lwhGBjLgOzLHB63IUWfBpNucQjND6d3AOudO+H3RWQ==", + "dev": true, + "funding": [ + "https://github.com/sponsors/broofa", + "https://github.com/sponsors/ctavan" + ], + "license": "MIT", + "bin": { + "uuid": "dist/bin/uuid" + } + }, "node_modules/validator": { "version": "13.15.15", "resolved": "https://registry.npmjs.org/validator/-/validator-13.15.15.tgz", @@ -6922,9 +7651,9 @@ } }, "node_modules/vite": { - "version": "7.1.7", - "resolved": "https://registry.npmjs.org/vite/-/vite-7.1.7.tgz", - "integrity": "sha512-VbA8ScMvAISJNJVbRDTJdCwqQoAareR/wutevKanhR2/1EkoXVZVkkORaYm/tNVCjP/UDTKtcw3bAkwOUdedmA==", + "version": "7.1.9", + "resolved": "https://registry.npmjs.org/vite/-/vite-7.1.9.tgz", + "integrity": "sha512-4nVGliEpxmhCL8DslSAUdxlB6+SMrhB0a1v5ijlh1xB1nEPuy1mxaHxysVucLHuWryAxLWg6a5ei+U4TLn/rFg==", "license": "MIT", "dependencies": { "esbuild": "^0.25.0", @@ -7044,6 +7773,13 @@ "url": "https://github.com/sponsors/jonschlinkert" } }, + "node_modules/webpack-virtual-modules": { + "version": "0.6.2", + "resolved": "https://registry.npmjs.org/webpack-virtual-modules/-/webpack-virtual-modules-0.6.2.tgz", + "integrity": "sha512-66/V2i5hQanC51vBQKPH4aI8NMAcBW59FVBs+rC7eGHupMyfn34q7rZIE+ETlJ+XTevqfUhVVBgSUNSW2flEUQ==", + "dev": true, + "license": "MIT" + }, "node_modules/which": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", @@ -7154,14 +7890,11 @@ } }, "node_modules/yallist": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-5.0.0.tgz", - "integrity": "sha512-YgvUTfwqyc7UXVMrB+SImsVYSmTS8X/tSrtdNZMImM+n7+QTriRXyXim0mBrTXNeqzVF0KWGgHPeiyViFFrNDw==", + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", + "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", "dev": true, - "license": "BlueOak-1.0.0", - "engines": { - "node": ">=18" - } + "license": "ISC" }, "node_modules/yocto-queue": { "version": "0.1.0", @@ -7175,6 +7908,29 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/zod": { + "version": "4.1.12", + "resolved": "https://registry.npmjs.org/zod/-/zod-4.1.12.tgz", + "integrity": "sha512-JInaHOamG8pt5+Ey8kGmdcAcg3OL9reK8ltczgHTAwNhMys/6ThXHityHxVV2p3fkw/c+MAvBHFVYHFZDmjMCQ==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/colinhacks" + } + }, + "node_modules/zod-validation-error": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/zod-validation-error/-/zod-validation-error-4.0.2.tgz", + "integrity": "sha512-Q6/nZLe6jxuU80qb/4uJ4t5v2VEZ44lzQjPDhYJNztRQ4wyWc6VF3D3Kb/fAuPetZQnhS3hnajCf9CsWesghLQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18.0.0" + }, + "peerDependencies": { + "zod": "^3.25.0 || ^4.0.0" + } + }, "node_modules/zustand": { "version": "4.5.7", "resolved": "https://registry.npmjs.org/zustand/-/zustand-4.5.7.tgz", diff --git a/ui/package.json b/ui/package.json index 412b407c..8eaa78bd 100644 --- a/ui/package.json +++ b/ui/package.json @@ -1,7 +1,7 @@ { "name": "kvm-ui", "private": true, - "version": "2025.10.01.1900", + "version": "2025.10.13.2055", "type": "module", "engines": { "node": "^22.15.0" @@ -11,12 +11,14 @@ "dev:ssl": "USE_SSL=true ./dev_device.sh", "dev:cloud": "vite dev --mode=cloud-development", "build": "npm run build:prod", - "build:device": "tsc && vite build --mode=device --emptyOutDir", - "build:staging": "tsc && vite build --mode=cloud-staging", - "build:prod": "tsc && vite build --mode=cloud-production", - "lint": "eslint './src/**/*.{ts,tsx}'", - "lint:fix": "eslint './src/**/*.{ts,tsx}' --fix", - "preview": "vite preview" + "build:device": "npm run paraglide && tsc && vite build --mode=device --emptyOutDir", + "build:staging": "npm run paraglide && tsc && vite build --mode=cloud-staging", + "build:prod": "npm run paraglide && tsc && vite build --mode=cloud-production", + "lint": "npm run paraglide && eslint './src/**/*.{ts,tsx}'", + "lint:fix": "npm run paraglide && eslint './src/**/*.{ts,tsx}' --fix", + "paraglide": "paraglide-js compile --project ./localization/jetKVM.UI.inlang --outdir ./localization/paraglide", + "validate": "inlang validate --project ./localization/jetKVM.UI.inlang", + "machine-translate": "inlang machine translate --project ./localization/jetKVM.UI.inlang" }, "dependencies": { "@headlessui/react": "^2.2.9", @@ -33,16 +35,16 @@ "dayjs": "^1.11.18", "eslint-import-resolver-alias": "^1.1.2", "focus-trap-react": "^11.0.4", - "framer-motion": "^12.23.22", + "framer-motion": "^12.23.24", "lodash.throttle": "^4.1.1", "mini-svg-data-uri": "^1.4.4", - "react": "^19.1.1", + "react": "^19.2.0", "react-animate-height": "^3.2.3", - "react-dom": "^19.1.1", + "react-dom": "^19.2.0", "react-hot-toast": "^2.6.0", "react-icons": "^5.5.0", - "react-router": "^7.9.3", - "react-simple-keyboard": "^3.8.125", + "react-router": "^7.9.4", + "react-simple-keyboard": "^3.8.130", "react-use-websocket": "^4.13.0", "react-xtermjs": "^1.0.10", "recharts": "^3.2.1", @@ -54,32 +56,37 @@ "devDependencies": { "@eslint/compat": "^1.4.0", "@eslint/eslintrc": "^3.3.1", - "@eslint/js": "^9.36.0", + "@eslint/js": "^9.37.0", + "@inlang/cli": "^3.0.12", + "@inlang/paraglide-js": "^2.4.0", + "@inlang/plugin-m-function-matcher": "^2.1.0", + "@inlang/plugin-message-format": "^4.0.0", + "@inlang/sdk": "^2.4.9", "@tailwindcss/forms": "^0.5.10", "@tailwindcss/postcss": "^4.1.14", "@tailwindcss/typography": "^0.5.19", "@tailwindcss/vite": "^4.1.14", - "@types/react": "^19.1.17", - "@types/react-dom": "^19.1.10", + "@types/react": "^19.2.2", + "@types/react-dom": "^19.2.2", "@types/semver": "^7.7.1", "@types/validator": "^13.15.3", - "@typescript-eslint/eslint-plugin": "^8.45.0", - "@typescript-eslint/parser": "^8.45.0", + "@typescript-eslint/eslint-plugin": "^8.46.1", + "@typescript-eslint/parser": "^8.46.1", "@vitejs/plugin-react-swc": "^4.1.0", "autoprefixer": "^10.4.21", - "eslint": "^9.36.0", - "eslint-config-prettier": "^10.1.8", + "eslint": "^9.37.0", + "eslint-plugin-prettier": "^5.5.4", "eslint-plugin-import": "^2.32.0", "eslint-plugin-react": "^7.37.5", - "eslint-plugin-react-hooks": "^5.2.0", - "eslint-plugin-react-refresh": "^0.4.22", + "eslint-plugin-react-hooks": "^7.0.0", + "eslint-plugin-react-refresh": "^0.4.23", "globals": "^16.4.0", "postcss": "^8.5.6", "prettier": "^3.6.2", "prettier-plugin-tailwindcss": "^0.6.14", "tailwindcss": "^4.1.14", "typescript": "^5.9.3", - "vite": "^7.1.7", + "vite": "^7.1.9", "vite-tsconfig-paths": "^5.1.4" } } diff --git a/ui/src/components/ActionBar.tsx b/ui/src/components/ActionBar.tsx index 4f79d7ed..456a8385 100644 --- a/ui/src/components/ActionBar.tsx +++ b/ui/src/components/ActionBar.tsx @@ -1,24 +1,25 @@ +import { Fragment, useCallback, useRef } from "react"; import { MdOutlineContentPasteGo } from "react-icons/md"; import { LuCable, LuHardDrive, LuMaximize, LuSettings, LuSignal } from "react-icons/lu"; import { FaKeyboard } from "react-icons/fa6"; import { Popover, PopoverButton, PopoverPanel } from "@headlessui/react"; -import { Fragment, useCallback, useRef } from "react"; import { CommandLineIcon } from "@heroicons/react/20/solid"; -import { Button } from "@components/Button"; +import { cx } from "@/cva.config"; import { useHidStore, useMountMediaStore, useSettingsStore, useUiStore, -} from "@/hooks/stores"; +} from "@hooks/stores"; +import { useDeviceUiNavigation } from "@hooks/useAppNavigation"; +import { Button } from "@components/Button"; import Container from "@components/Container"; -import { cx } from "@/cva.config"; -import PasteModal from "@/components/popovers/PasteModal"; -import WakeOnLanModal from "@/components/popovers/WakeOnLan/Index"; -import MountPopopover from "@/components/popovers/MountPopover"; -import ExtensionPopover from "@/components/popovers/ExtensionPopover"; -import { useDeviceUiNavigation } from "@/hooks/useAppNavigation"; +import PasteModal from "@components/popovers/PasteModal"; +import WakeOnLanModal from "@components/popovers/WakeOnLan/Index"; +import MountPopopover from "@components/popovers/MountPopover"; +import ExtensionPopover from "@components/popovers/ExtensionPopover"; +import { m } from "@localizations/messages.js"; export default function Actionbar({ requestFullscreen, @@ -28,10 +29,7 @@ export default function Actionbar({ const { navigateTo } = useDeviceUiNavigation(); const { isVirtualKeyboardEnabled, setVirtualKeyboardEnabled } = useHidStore(); const { setDisableVideoFocusTrap, terminalType, setTerminalType, toggleSidebarView } = useUiStore(); - - const remoteVirtualMediaState = useMountMediaStore( - state => state.remoteVirtualMediaState, - ); + const { remoteVirtualMediaState } = useMountMediaStore(); const { developerMode } = useSettingsStore(); // This is the only way to get a reliable state change for the popover @@ -64,7 +62,7 @@ export default function Actionbar({ diff --git a/ui/src/components/InfoBar.tsx b/ui/src/components/InfoBar.tsx index ce444d85..2c4eb9e0 100644 --- a/ui/src/components/InfoBar.tsx +++ b/ui/src/components/InfoBar.tsx @@ -1,6 +1,5 @@ -import { useEffect, useMemo } from "react"; +import { useMemo } from "react"; -import { cx } from "@/cva.config"; import { useHidStore, useMouseStore, @@ -8,9 +7,11 @@ import { useSettingsStore, useVideoStore, VideoState -} from "@/hooks/stores"; +} from "@hooks/stores"; +import { useHidRpc } from "@hooks/useHidRpc"; import { keys, modifiers } from "@/keyboardMappings"; -import { useHidRpc } from "@/hooks/useHidRpc"; +import { cx } from "@/cva.config"; +import { m } from "@localizations/messages.js"; export default function InfoBar() { const { keysDownState } = useHidStore(); @@ -25,29 +26,23 @@ export default function InfoBar() { (state: VideoState) => `${Math.round(state.width)}x${Math.round(state.height)}`, ); - const { rpcDataChannel } = useRTCStore(); const { debugMode, mouseMode, showPressedKeys } = useSettingsStore(); const { isPasteInProgress } = useHidStore(); - - useEffect(() => { - if (!rpcDataChannel) return; - rpcDataChannel.onclose = () => console.log("rpcDataChannel has closed"); - rpcDataChannel.onerror = (e: Event) => - console.error(`Error on DataChannel '${rpcDataChannel.label}': ${e}`); - }, [rpcDataChannel]); - const { keyboardLedState, usbState } = useHidStore(); const { isTurnServerInUse } = useRTCStore(); const { hdmiState } = useVideoStore(); const displayKeys = useMemo(() => { - if (!showPressedKeys) - return ""; + if (!showPressedKeys) return ""; const activeModifierMask = keysDownState.modifier || 0; const keysDown = keysDownState.keys || []; - const modifierNames = Object.entries(modifiers).filter(([_, mask]) => (activeModifierMask & mask) !== 0).map(([name, _]) => name); - const keyNames = Object.entries(keys).filter(([_, value]) => keysDown.includes(value)).map(([name, _]) => name); + const modifierNames = Object.entries(modifiers) + .filter(([_, mask]) => (activeModifierMask & mask) !== 0) + .map(([name]) => name); + const keyNames = Object.entries(keys) + .filter(([_, value]) => keysDown.includes(value)) + .map(([name]) => name); return [...modifierNames, ...keyNames].join(", "); }, [keysDownState, showPressedKeys]); @@ -59,76 +54,75 @@ export default function InfoBar() {
{debugMode ? (
- Resolution:{" "} + {m.info_resolution()}{" "} {videoSize}
) : null} {debugMode ? (
- Video Size: + {m.info_video_size()} {videoClientSize}
) : null} {(debugMode && mouseMode == "absolute") ? (
- Pointer: - - {mouseX},{mouseY} - + {m.info_pointer()} + {mouseX},{mouseY}
) : null} {(debugMode && mouseMode == "relative") ? (
- Last Move: + {m.info_last_move()} - {mouseMove ? - `${mouseMove.x},${mouseMove.y} ${mouseMove.buttons ? `(${mouseMove.buttons})` : ""}` : - "N/A"} + {mouseMove ? `${mouseMove.x},${mouseMove.y} ${mouseMove.buttons ? `(${mouseMove.buttons})` : ""}` : "N/A"}
) : null} {debugMode && (
- USB State: + {m.info_usb_state()} {usbState}
)} + {debugMode && (
- HDMI State: + {m.info_hdmi_state()} {hdmiState}
)} + {debugMode && (
- HidRPC State: + {m.info_hidrpc_state()} {rpcHidStatus}
)} + {isPasteInProgress && (
- Paste Mode: - Enabled + {m.info_paste_mode()} + {m.info_paste_enabled()}
)} + {showPressedKeys && (
- Keys: -

- {displayKeys} -

+ {m.info_keys()} +

{displayKeys}

)}
+
{isTurnServerInUse && (
- Relayed by Cloudflare + {m.info_relayed_by_cloudflare()}
)} @@ -140,8 +134,9 @@ export default function InfoBar() { : "text-slate-800/20 dark:text-slate-300/20", )} > - Caps Lock + {m.info_caps_lock()}
+
- Num Lock + {m.info_num_lock()}
+
- Scroll Lock + {m.info_scroll_lock()}
+ {keyboardLedState.compose ? ( -
- Compose -
+
{m.info_compose()}
) : null} + {keyboardLedState.kana ? ( -
- Kana -
+
{m.info_kana()}
) : null} + {keyboardLedState.shift ? ( -
- Shift -
+
{m.info_shift()}
) : null} diff --git a/ui/src/components/Ipv6NetworkCard.tsx b/ui/src/components/Ipv6NetworkCard.tsx index 0cfacc6d..6d561510 100644 --- a/ui/src/components/Ipv6NetworkCard.tsx +++ b/ui/src/components/Ipv6NetworkCard.tsx @@ -1,7 +1,7 @@ -import { NetworkState } from "../hooks/stores"; -import { LifeTimeLabel } from "../routes/devices.$id.settings.network"; - -import { GridCard } from "./Card"; +import { NetworkState } from "@hooks/stores"; +import { GridCard } from "@components/Card"; +import { LifeTimeLabel } from "@routes/devices.$id.settings.network"; +import { m } from "@localizations/messages.js"; export default function Ipv6NetworkCard({ networkState, @@ -13,14 +13,14 @@ export default function Ipv6NetworkCard({

- IPv6 Information + {m.ipv6_information()}

{networkState?.ipv6_link_local && (
- Link-local + {m.ipv6_link_local()} {networkState?.ipv6_link_local} @@ -42,7 +42,7 @@ export default function Ipv6NetworkCard({
- Address + {m.ipv6_address_label()} {addr.address}
@@ -50,12 +50,12 @@ export default function Ipv6NetworkCard({ {addr.valid_lifetime && (
- Valid Lifetime + {m.ipv6_valid_lifetime()} {addr.valid_lifetime === "" ? ( - N/A + {m.not_available()} ) : ( @@ -66,12 +66,12 @@ export default function Ipv6NetworkCard({ {addr.preferred_lifetime && (
- Preferred Lifetime + {m.ipv6_preferred_lifetime()} {addr.preferred_lifetime === "" ? ( - N/A + {m.not_available()} ) : ( diff --git a/ui/src/components/JigglerSetting.tsx b/ui/src/components/JigglerSetting.tsx index fc0f50dd..6578906e 100644 --- a/ui/src/components/JigglerSetting.tsx +++ b/ui/src/components/JigglerSetting.tsx @@ -1,11 +1,11 @@ import { useEffect, useMemo, useState } from "react"; import { LuExternalLink } from "react-icons/lu"; +import { JsonRpcResponse, useJsonRpc } from "@hooks/useJsonRpc"; import { Button, LinkButton } from "@components/Button"; -import { JsonRpcResponse, useJsonRpc } from "@/hooks/useJsonRpc"; - -import { InputFieldWithLabel } from "./InputField"; -import { SelectMenuBasic } from "./SelectMenuBasic"; +import { InputFieldWithLabel } from "@components/InputField"; +import { SelectMenuBasic } from "@components/SelectMenuBasic"; +import { m } from "@localizations/messages.js"; export interface JigglerConfig { inactivity_limit_seconds: number; @@ -51,7 +51,7 @@ export function JigglerSetting({ const exampleConfigs = [ { - name: "Business Hours 9-17", + name: m.jiggler_example_business_hours_late(), config: { inactivity_limit_seconds: 60, jitter_percentage: 25, @@ -60,7 +60,7 @@ export function JigglerSetting({ }, }, { - name: "Business Hours 8-17", + name: m.jiggler_example_business_hours_early(), config: { inactivity_limit_seconds: 60, jitter_percentage: 25, @@ -69,13 +69,10 @@ export function JigglerSetting({ }, }, ]; - return (
-

- Examples -

+

{m.jiggler_examples_label()}

{exampleConfigs.map((example, index) => (
@@ -100,8 +97,8 @@ export function JigglerSetting({ @@ -114,8 +111,8 @@ export function JigglerSetting({ %} value={jigglerConfigState.jitter_percentage} @@ -149,8 +146,8 @@ export function JigglerSetting({ @@ -167,7 +164,7 @@ export function JigglerSetting({
diff --git a/ui/src/components/KvmCard.tsx b/ui/src/components/KvmCard.tsx index ab34976b..f4e3bf4d 100644 --- a/ui/src/components/KvmCard.tsx +++ b/ui/src/components/KvmCard.tsx @@ -1,10 +1,11 @@ +import { Link } from "react-router"; import { MdConnectWithoutContact } from "react-icons/md"; import { Menu, MenuButton, MenuItem, MenuItems } from "@headlessui/react"; -import { Link } from "react-router"; import { LuEllipsisVertical } from "react-icons/lu"; import Card from "@components/Card"; import { Button, LinkButton } from "@components/Button"; +import { m } from "@localizations/messages.js"; function getRelativeTimeString(date: Date | number, lang = navigator.language): string { // Allow dates or times to be passed @@ -62,16 +63,16 @@ export default function KvmCard({ {online ? (
-
Online
+
{m.online()}
) : (
{lastSeen ? ( - <>Last online {getRelativeTimeString(lastSeen)} + <>{m.last_online({ time: getRelativeTimeString(lastSeen) })} ) : ( - <>Never seen online + <>{m.never_seen_online()} )}
@@ -85,7 +86,7 @@ export default function KvmCard({ )} diff --git a/ui/src/components/MacroBar.tsx b/ui/src/components/MacroBar.tsx index 0ba8cf4f..7536ad2a 100644 --- a/ui/src/components/MacroBar.tsx +++ b/ui/src/components/MacroBar.tsx @@ -1,11 +1,11 @@ import { useEffect } from "react"; import { LuCommand } from "react-icons/lu"; +import { useMacrosStore } from "@hooks/stores"; +import useKeyboard from "@hooks/useKeyboard"; +import { useJsonRpc } from "@hooks/useJsonRpc"; import { Button } from "@components/Button"; import Container from "@components/Container"; -import { useMacrosStore } from "@/hooks/stores"; -import useKeyboard from "@/hooks/useKeyboard"; -import { useJsonRpc } from "@/hooks/useJsonRpc"; export default function MacroBar() { const { macros, initialized, loadMacros, setSendFn } = useMacrosStore(); diff --git a/ui/src/components/MacroForm.tsx b/ui/src/components/MacroForm.tsx index 1aafe9c9..f9517164 100644 --- a/ui/src/components/MacroForm.tsx +++ b/ui/src/components/MacroForm.tsx @@ -1,18 +1,19 @@ import { useState } from "react"; import { LuPlus } from "react-icons/lu"; -import { Button } from "@/components/Button"; -import FieldLabel from "@/components/FieldLabel"; -import Fieldset from "@/components/Fieldset"; -import { InputFieldWithLabel, FieldError } from "@/components/InputField"; -import { MacroStepCard } from "@/components/MacroStepCard"; +import { KeySequence } from "@hooks/stores"; +import useKeyboardLayout from "@hooks/useKeyboardLayout"; +import { Button } from "@components/Button"; +import FieldLabel from "@components/FieldLabel"; +import Fieldset from "@components/Fieldset"; +import { InputFieldWithLabel, FieldError } from "@components/InputField"; +import { MacroStepCard } from "@components/MacroStepCard"; import { DEFAULT_DELAY, MAX_STEPS_PER_MACRO, MAX_KEYS_PER_STEP, } from "@/constants/macros"; -import { KeySequence } from "@/hooks/stores"; -import useKeyboardLayout from "@/hooks/useKeyboardLayout"; +import { m } from "@localizations/messages.js"; interface ValidationErrors { name?: string; @@ -31,7 +32,6 @@ interface MacroFormProps { onSubmit: (macro: Partial) => Promise; onCancel: () => void; isSubmitting?: boolean; - submitText?: string; } export function MacroForm({ @@ -39,7 +39,6 @@ export function MacroForm({ onSubmit, onCancel, isSubmitting = false, - submitText = "Save Macro", }: MacroFormProps) { const [macro, setMacro] = useState>(initialData); const [keyQueries, setKeyQueries] = useState>({}); @@ -57,13 +56,13 @@ export function MacroForm({ // Name validation if (!macro.name?.trim()) { - newErrors.name = "Name is required"; + newErrors.name = m.macro_name_required(); } else if (macro.name.trim().length > 50) { - newErrors.name = "Name must be less than 50 characters"; + newErrors.name = m.macro_name_too_long(); } if (!macro.steps?.length) { - newErrors.steps = { 0: { keys: "At least one step is required" } }; + newErrors.steps = { 0: { keys: m.macro_at_least_one_step_required() } }; } else { const hasKeyOrModifier = macro.steps.some( step => (step.keys?.length || 0) > 0 || (step.modifiers?.length || 0) > 0, @@ -71,7 +70,7 @@ export function MacroForm({ if (!hasKeyOrModifier) { newErrors.steps = { - 0: { keys: "At least one step must have keys or modifiers" }, + 0: { keys: m.macro_at_least_one_step_keys_or_modifiers() }, }; } } @@ -82,7 +81,7 @@ export function MacroForm({ const handleSubmit = async () => { if (!validateForm()) { - showTemporaryError("Please fix the validation errors"); + showTemporaryError(m.macro_please_fix_validation_errors()); return; } @@ -92,7 +91,7 @@ export function MacroForm({ if (error instanceof Error) { showTemporaryError(error.message); } else { - showTemporaryError("An error occurred while saving"); + showTemporaryError(m.macro_save_error()); } } }; @@ -114,7 +113,7 @@ export function MacroForm({ ? newSteps[stepIndex].keys : []; if (keysArray.length >= MAX_KEYS_PER_STEP) { - showTemporaryError(`Maximum of ${MAX_KEYS_PER_STEP} keys per step allowed`); + showTemporaryError(m.macro_max_steps_error({max: MAX_KEYS_PER_STEP})); return; } newSteps[stepIndex].keys = [...keysArray, option.value]; @@ -178,8 +177,8 @@ export function MacroForm({
{ @@ -197,12 +196,12 @@ export function MacroForm({
- {macro.steps?.length || 0}/{MAX_STEPS_PER_MACRO} steps + {m.macro_step_count({steps: macro.steps?.length || 0, max: MAX_STEPS_PER_MACRO})}
{errors.steps && errors.steps[0]?.keys && ( @@ -220,10 +219,10 @@ export function MacroForm({ onDelete={ macro.steps && macro.steps.length > 1 ? () => { - const newSteps = [...(macro.steps || [])]; - newSteps.splice(stepIndex, 1); - setMacro(prev => ({ ...prev, steps: newSteps })); - } + const newSteps = [...(macro.steps || [])]; + newSteps.splice(stepIndex, 1); + setMacro(prev => ({ ...prev, steps: newSteps })); + } : undefined } onMoveUp={() => handleStepMove(stepIndex, "up")} @@ -248,12 +247,10 @@ export function MacroForm({ theme="light" fullWidth LeadingIcon={LuPlus} - text={`Add Step ${isMaxStepsReached ? `(${MAX_STEPS_PER_MACRO} max)` : ""}`} + text={m.macro_add_step({ maxed_out: isMaxStepsReached ? m.macro_max_steps_reached({ max: MAX_STEPS_PER_MACRO} ) : ""})} onClick={() => { if (isMaxStepsReached) { - showTemporaryError( - `You can only add a maximum of ${MAX_STEPS_PER_MACRO} steps per macro.`, - ); + showTemporaryError(m.macro_max_steps_error({max: MAX_STEPS_PER_MACRO})); return; } @@ -280,11 +277,11 @@ export function MacroForm({
diff --git a/ui/src/components/MacroStepCard.tsx b/ui/src/components/MacroStepCard.tsx index c795520d..337e74a3 100644 --- a/ui/src/components/MacroStepCard.tsx +++ b/ui/src/components/MacroStepCard.tsx @@ -1,14 +1,15 @@ import { useMemo } from "react"; import { LuArrowUp, LuArrowDown, LuX, LuTrash2 } from "react-icons/lu"; -import { Button } from "@/components/Button"; -import { Combobox } from "@/components/Combobox"; -import { SelectMenuBasic } from "@/components/SelectMenuBasic"; -import Card from "@/components/Card"; -import FieldLabel from "@/components/FieldLabel"; +import { Button } from "@components/Button"; +import { Combobox } from "@components/Combobox"; +import Card from "@components/Card"; +import FieldLabel from "@components/FieldLabel"; +import { SelectMenuBasic } from "@components/SelectMenuBasic"; import { MAX_KEYS_PER_STEP, DEFAULT_DELAY } from "@/constants/macros"; import { KeyboardLayout } from "@/keyboardLayouts"; import { keys, modifiers } from "@/keyboardMappings"; +import { m } from "@localizations/messages.js"; // Filter out modifier keys since they're handled in the modifiers section const modifierKeyPrefixes = ['Alt', 'Control', 'Shift', 'Meta']; @@ -25,6 +26,7 @@ const groupedModifiers: Record = { Meta: modifierOptions.filter(mod => mod.value.startsWith('Meta')), }; +// not going to localize these since they're short time intervals const basePresetDelays = [ { value: "50", label: "50ms" }, { value: "100", label: "100ms" }, @@ -132,12 +134,12 @@ export function MacroStepCard({ LeadingIcon={LuArrowDown} />
- {onDelete && ( + {onDelete && (
); } diff --git a/ui/src/components/Terminal.tsx b/ui/src/components/Terminal.tsx index ba3e667c..7e0d3673 100644 --- a/ui/src/components/Terminal.tsx +++ b/ui/src/components/Terminal.tsx @@ -1,6 +1,6 @@ +import { useEffect, useMemo } from "react"; import "react-simple-keyboard/build/css/index.css"; import { ChevronDownIcon } from "@heroicons/react/16/solid"; -import { useEffect, useMemo } from "react"; import { useXTerm } from "react-xtermjs"; import { FitAddon } from "@xterm/addon-fit"; import { WebLinksAddon } from "@xterm/addon-web-links"; @@ -9,9 +9,9 @@ import { Unicode11Addon } from "@xterm/addon-unicode11"; import { ClipboardAddon } from "@xterm/addon-clipboard"; import { cx } from "@/cva.config"; -import { AvailableTerminalTypes, useUiStore } from "@/hooks/stores"; - -import { Button } from "./Button"; +import { AvailableTerminalTypes, useUiStore } from "@hooks/stores"; +import { Button } from "@components/Button"; +import { m } from "@localizations/messages.js"; const isWebGl2Supported = !!document.createElement("canvas").getContext("webgl2"); @@ -54,6 +54,7 @@ const TERMINAL_CONFIG = { // Add these configurations: cursorStyle: "block", rendererType: "canvas", // Ensure we're using the canvas renderer + unicode: { activeVersion: "11" } } as const; function Terminal({ @@ -144,7 +145,6 @@ function Terminal({ instance.loadAddon(new ClipboardAddon()); instance.loadAddon(new Unicode11Addon()); instance.loadAddon(new WebLinksAddon()); - instance.unicode.activeVersion = "11"; if (isWebGl2Supported) { const webGl2Addon = new WebglAddon(); @@ -191,7 +191,7 @@ function Terminal({
diff --git a/ui/src/components/UsbInfoSetting.tsx b/ui/src/components/UsbInfoSetting.tsx index 1b4f3114..1a564e03 100644 --- a/ui/src/components/UsbInfoSetting.tsx +++ b/ui/src/components/UsbInfoSetting.tsx @@ -1,15 +1,14 @@ import { useMemo , useCallback , useEffect, useState } from "react"; +import { UsbConfigState } from "@hooks/stores"; +import { JsonRpcResponse, useJsonRpc } from "@hooks/useJsonRpc"; import { Button } from "@components/Button"; +import Fieldset from "@components/Fieldset"; +import { InputFieldWithLabel } from "@components/InputField"; +import { SelectMenuBasic } from "@components/SelectMenuBasic"; import { SettingsItem } from "@components/SettingsItem"; - -import { UsbConfigState } from "../hooks/stores"; -import { JsonRpcResponse, useJsonRpc } from "../hooks/useJsonRpc"; -import notifications from "../notifications"; - -import { InputFieldWithLabel } from "./InputField"; -import { SelectMenuBasic } from "./SelectMenuBasic"; -import Fieldset from "./Fieldset"; +import notifications from "@/notifications"; +import { m } from "@localizations/messages.js"; const generatedSerialNumber = [generateNumber(1, 9), generateHex(7, 7), 0, 1].join("&"); @@ -31,21 +30,22 @@ export interface USBConfig { product: string; } + const usbConfigs = [ { - label: "JetKVM Default", + label: m.usb_config_default(), value: "USB Emulation Device", }, { - label: "Logitech Universal Adapter", + label: m.usb_config_logitech(), value: "Logitech USB Input Device", }, { - label: "Microsoft Wireless MultiMedia Keyboard", + label: m.usb_config_microsoft(), value: "Wireless MultiMedia Keyboard", }, { - label: "Dell Multimedia Pro Keyboard", + label: m.usb_config_dell(), value: "Multimedia Pro Keyboard", }, ]; @@ -94,10 +94,10 @@ export function UsbInfoSetting() { const syncUsbConfigProduct = useCallback(() => { send("getUsbConfig", {}, (resp: JsonRpcResponse) => { - if ("error" in resp) { + if ("error" in resp) { console.error("Failed to load USB Config:", resp.error); notifications.error( - `Failed to load USB Config: ${resp.error.data || "Unknown error"}`, + m.usb_config_failed_load({ error: String(resp.error.data || "Unknown error") }), ); } else { const usbConfigState = resp.result as UsbConfigState; @@ -116,7 +116,7 @@ export function UsbInfoSetting() { send("setUsbConfig", { usbConfig }, async (resp: JsonRpcResponse) => { if ("error" in resp) { notifications.error( - `Failed to set usb config: ${resp.error.data || "Unknown error"}`, + m.usb_config_failed_set({ error: String(resp.error.data || "Unknown error") }), ); setLoading(false); return; @@ -126,7 +126,7 @@ export function UsbInfoSetting() { await new Promise(resolve => setTimeout(resolve, 2000)); setLoading(false); notifications.success( - `USB Config set to ${usbConfig.manufacturer} ${usbConfig.product}`, + m.usb_config_set_success({ manufacturer: usbConfig.manufacturer, product: usbConfig.product }), ); syncUsbConfigProduct(); @@ -152,8 +152,8 @@ export function UsbInfoSetting() {
{usbConfigProduct === "custom" && ( @@ -246,38 +246,38 @@ function USBConfigDialog({
handleUsbVendorIdChange(e.target.value)} /> handleUsbProductIdChange(e.target.value)} /> handleUsbSerialChange(e.target.value)} /> handleUsbManufacturer(e.target.value)} /> handleUsbProduct(e.target.value)} /> @@ -287,13 +287,13 @@ function USBConfigDialog({ loading={loading} size="SM" theme="primary" - text="Update USB Identifiers" + text={m.usb_config_update_identifiers()} onClick={() => onSetUsbConfig(usbConfigState)} />
diff --git a/ui/src/components/VideoOverlay.tsx b/ui/src/components/VideoOverlay.tsx index 1c59e788..1194e1e9 100644 --- a/ui/src/components/VideoOverlay.tsx +++ b/ui/src/components/VideoOverlay.tsx @@ -5,6 +5,7 @@ import { motion, AnimatePresence } from "framer-motion"; import { LuPlay } from "react-icons/lu"; import { BsMouseFill } from "react-icons/bs"; +import { m } from "@localizations/messages.js"; import { Button, LinkButton } from "@components/Button"; import LoadingSpinner from "@components/LoadingSpinner"; import Card, { GridCard } from "@components/Card"; @@ -46,7 +47,7 @@ export function LoadingVideoOverlay({ show }: LoadingOverlayProps) {

- Loading video stream... + {m.video_overlay_loading_stream()}

@@ -118,26 +119,26 @@ export function ConnectionFailedOverlay({
-

Connection Issue Detected

+

{m.video_overlay_connection_issue_title()}

    -
  • Verify that the device is powered on and properly connected
  • -
  • Check all cable connections for any loose or damaged wires
  • -
  • Ensure your network connection is stable and active
  • -
  • Try restarting both the device and your computer
  • +
  • {m.video_overlay_conn_verify_power()}
  • +
  • {m.video_overlay_conn_check_cables()}
  • +
  • {m.video_overlay_conn_ensure_network()}
  • +
  • {m.video_overlay_conn_restart()}

- Virtual Keyboard + {m.virtual_keyboard_header()}

@@ -274,7 +272,7 @@ function KeyboardWrapper() {
@@ -110,8 +111,8 @@ export default function ExtensionPopover() { // Extensions List View
@@ -131,7 +132,7 @@ export default function ExtensionPopover() {
diff --git a/ui/src/components/popovers/MountPopover.tsx b/ui/src/components/popovers/MountPopover.tsx index 8b6a8a55..dfa88665 100644 --- a/ui/src/components/popovers/MountPopover.tsx +++ b/ui/src/components/popovers/MountPopover.tsx @@ -1,20 +1,17 @@ import { PlusCircleIcon } from "@heroicons/react/20/solid"; import { forwardRef, useEffect, useCallback } from "react"; -import { - LuLink, - LuPlus, - LuRadioReceiver, -} from "react-icons/lu"; +import { LuLink, LuPlus, LuRadioReceiver } from "react-icons/lu"; import { useClose } from "@headlessui/react"; import { useLocation } from "react-router"; +import { m } from "@localizations/messages.js"; import { Button } from "@components/Button"; import Card, { GridCard } from "@components/Card"; import { formatters } from "@/utils"; -import { RemoteVirtualMediaState, useMountMediaStore } from "@/hooks/stores"; +import { RemoteVirtualMediaState, useMountMediaStore } from "@hooks/stores"; import { SettingsPageHeader } from "@components/SettingsPageheader"; -import { JsonRpcResponse, useJsonRpc } from "@/hooks/useJsonRpc"; -import { useDeviceUiNavigation } from "@/hooks/useAppNavigation"; +import { JsonRpcResponse, useJsonRpc } from "@hooks/useJsonRpc"; +import { useDeviceUiNavigation } from "@hooks/useAppNavigation"; import notifications from "@/notifications"; const MountPopopover = forwardRef((_props, ref) => { @@ -25,9 +22,7 @@ const MountPopopover = forwardRef((_props, ref) => { const syncRemoteVirtualMediaState = useCallback(() => { send("getVirtualMediaState", {}, (response: JsonRpcResponse) => { if ("error" in response) { - notifications.error( - `Failed to get virtual media state: ${response.error.message}`, - ); + notifications.error(m.mount_get_state_error({ error: response.error.message })); } else { setRemoteVirtualMediaState(response.result as unknown as RemoteVirtualMediaState); } @@ -37,7 +32,7 @@ const MountPopopover = forwardRef((_props, ref) => { const handleUnmount = () => { send("unmountImage", {}, (response: JsonRpcResponse) => { if ("error" in response) { - notifications.error(`Failed to unmount image: ${response.error.message}`); + notifications.error(m.mount_unmount_error({ error: response.error.message })); } else { syncRemoteVirtualMediaState(); } @@ -57,10 +52,10 @@ const MountPopopover = forwardRef((_props, ref) => {

- No mounted media + {m.mount_no_mounted_media()}

- Add a file to get started + {m.mount_add_file_to_get_started()}

@@ -81,7 +76,7 @@ const MountPopopover = forwardRef((_props, ref) => {

- Streaming from URL + {m.mount_streaming_from_url()}

{formatters.truncateMiddle(url, 55)} @@ -105,7 +100,7 @@ const MountPopopover = forwardRef((_props, ref) => {

- Mounted from JetKVM Storage + {m.mount_mounted_from_storage()}

{formatters.truncateMiddle(path, 50)} @@ -138,8 +133,8 @@ const MountPopopover = forwardRef((_props, ref) => {

((_props, ref) => {
{remoteVirtualMediaState ? (
-
- Mounted as{" "} +
+ {m.mount_mounted_as()}{" "} - {remoteVirtualMediaState.mode === "Disk" ? "Disk" : "CD-ROM"} + {remoteVirtualMediaState.mode === "Disk" ? m.mount_mode_disk() : m.mount_mode_cdrom()}
@@ -173,7 +168,7 @@ const MountPopopover = forwardRef((_props, ref) => {
@@ -69,11 +70,11 @@ export default function DeviceList({ animationDelay: "0.2s", }} > -

- No devices added + {m.wake_on_lan_empty_no_devices_added()}

- Add a device to start using Wake-on-LAN + {m.wake_on_lan_empty_add_device_to_start()}

@@ -41,11 +42,11 @@ export default function EmptyStateCard({ animationDelay: "0.2s", }} > -
{error?.message && (

- {error?.message} + {m.deregister_error({ status: error.message })}

)} diff --git a/ui/src/routes/devices.$id.mount.tsx b/ui/src/routes/devices.$id.mount.tsx index 4672ef99..d5d43326 100644 --- a/ui/src/routes/devices.$id.mount.tsx +++ b/ui/src/routes/devices.$id.mount.tsx @@ -1,4 +1,5 @@ import { useCallback, useEffect, useMemo, useRef, useState } from "react"; +import { useNavigate } from "react-router"; import { LuLink, LuRadioReceiver, @@ -7,28 +8,28 @@ import { } from "react-icons/lu"; import { PlusCircleIcon, ExclamationTriangleIcon } from "@heroicons/react/20/solid"; import { TrashIcon } from "@heroicons/react/16/solid"; -import { useNavigate } from "react-router"; -import Card, { GridCard } from "@/components/Card"; -import { Button } from "@components/Button"; -import LogoBlueIcon from "@/assets/logo-blue.svg"; -import LogoWhiteIcon from "@/assets/logo-white.svg"; -import { formatters } from "@/utils"; +import DebianIcon from "@assets/debian-icon.png"; +import UbuntuIcon from "@assets/ubuntu-icon.png"; +import FedoraIcon from "@assets/fedora-icon.png"; +import OpenSUSEIcon from "@assets/opensuse-icon.png"; +import ArchIcon from "@assets/arch-icon.png"; +import NetBootIcon from "@assets/netboot-icon.svg"; +import LogoBlueIcon from "@assets/logo-blue.svg"; +import LogoWhiteIcon from "@assets/logo-white.svg"; +import { cx } from "@/cva.config"; +import { JsonRpcResponse, useJsonRpc } from "@hooks/useJsonRpc"; import AutoHeight from "@components/AutoHeight"; +import { Button } from "@components/Button"; +import Card, { GridCard } from "@components/Card"; +import Fieldset from "@components/Fieldset"; import { InputFieldWithLabel } from "@/components/InputField"; -import DebianIcon from "@/assets/debian-icon.png"; -import UbuntuIcon from "@/assets/ubuntu-icon.png"; -import FedoraIcon from "@/assets/fedora-icon.png"; -import OpenSUSEIcon from "@/assets/opensuse-icon.png"; -import ArchIcon from "@/assets/arch-icon.png"; -import NetBootIcon from "@/assets/netboot-icon.svg"; -import Fieldset from "@/components/Fieldset"; +import { formatters } from "@/utils"; import { DEVICE_API } from "@/ui.config"; +import { isOnDevice } from "@/main"; +import notifications from "@/notifications"; +import { m } from "@localizations/messages.js"; -import { JsonRpcResponse, useJsonRpc } from "../hooks/useJsonRpc"; -import notifications from "../notifications"; -import { isOnDevice } from "../main"; -import { cx } from "../cva.config"; import { MountMediaState, RemoteVirtualMediaState, @@ -145,12 +146,12 @@ export function Dialog({ onClose }: { onClose: () => void }) {
JetKVM Logo JetKVM Logo {modalView === "mode" && ( @@ -238,26 +239,26 @@ function ModeSelectionView({

- Virtual Media Source + {m.mount_virtual_media_source()}

- Choose how you want to mount your virtual media + {m.mount_virtual_media_source_description()}
{[ { - label: "URL Mount", + label: m.mount_url_mount(), value: "url", - description: "Mount files from any public web address", + description: m.mount_url_description(), icon: LuLink, - tag: "Experimental", + tag: m.experimental(), disabled: false, }, { - label: "JetKVM Storage Mount", + label: m.mount_jetkvm_storage(), value: "device", - description: "Mount previously uploaded files from the JetKVM storage", + description: m.mount_jetkvm_storage_description(), icon: LuRadioReceiver, tag: null, disabled: false, @@ -332,7 +333,7 @@ function ModeSelectionView({ onClick={() => { setModalView(selectedMode); }} - text="Continue" + text={m.continue()} />
@@ -351,6 +352,7 @@ function UrlView({ }) { const [usbMode, setUsbMode] = useState("CDROM"); const [url, setUrl] = useState(""); + const [isUrlValid, setIsUrlValid] = useState(false); const popularImages = [ { @@ -398,6 +400,12 @@ function UrlView({ const urlRef = useRef(null); + useEffect(() => { + if (urlRef.current) { + setIsUrlValid(urlRef.current.validity.valid); + } + }, [url]); + function handleUrlChange(url: string) { setUrl(url); if (url.endsWith(".iso")) { @@ -410,8 +418,8 @@ function UrlView({ return (
handleUrlChange(e.target.value)} @@ -436,19 +444,19 @@ function UrlView({ animationDelay: "0.1s", }} > -
+
-
@@ -463,7 +471,7 @@ function UrlView({ }} >

- Popular images + {m.mount_popular_images()}

{popularImages.map((image, index) => ( @@ -487,7 +495,7 @@ function UrlView({
@@ -553,7 +561,7 @@ function DeviceFileView({ const syncStorage = useCallback(() => { send("listStorageFiles", {}, (resp: JsonRpcResponse) => { if ("error" in resp) { - notifications.error(`Error listing storage files: ${resp.error}`); + notifications.error(m.mount_error_list_storage({ error: resp.error })); return; } const { files } = resp.result as StorageFiles; @@ -568,7 +576,7 @@ function DeviceFileView({ send("getStorageSpace", {}, (resp: JsonRpcResponse) => { if ("error" in resp) { - notifications.error(`Error getting storage space: ${resp.error}`); + notifications.error(m.mount_error_get_storage_space({ error: resp.error })); return; } @@ -597,7 +605,7 @@ function DeviceFileView({ console.log("Deleting file:", file); send("deleteStorageFile", { filename: file.name }, (resp: JsonRpcResponse) => { if ("error" in resp) { - notifications.error(`Error deleting file: ${resp.error}`); + notifications.error(m.mount_error_delete_file({ error: resp.error })); return; } @@ -630,8 +638,8 @@ function DeviceFileView({ return (

- No images available + {m.mount_no_images_title()}

- Upload an image to start virtual media mounting. + {m.mount_no_images_description()}

@@ -677,9 +685,7 @@ function DeviceFileView({ const selectedFile = onStorageFiles.find(f => f.name === file.name); if (!selectedFile) return; if ( - window.confirm( - "Are you sure you want to delete " + selectedFile.name + "?", - ) + window.confirm(m.mount_confirm_delete({ name: selectedFile.name })) ) { handleDeleteFile(selectedFile); } @@ -692,24 +698,24 @@ function DeviceFileView({ {onStorageFiles.length > filesPerPage && (

- Showing {indexOfFirstFile + 1} to{" "} - - {Math.min(indexOfLastFile, onStorageFiles.length)} - {" "} - of {onStorageFiles.length} results + {m.mount_button_showing_results({ + from: indexOfFirstFile + 1, + to: Math.min(indexOfLastFile, onStorageFiles.length), + total: onStorageFiles.length + })}

@@ -806,7 +812,7 @@ function DeviceFileView({ size="MD" theme="light" fullWidth - text="Upload a new image" + text={m.mount_button_upload_new_image()} onClick={() => onNewImageClick()} />
@@ -862,7 +868,7 @@ function UploadFileView({ if (!rtcDataChannel) { console.error("Failed to create data channel for file upload"); - notifications.error("Failed to create data channel for file upload"); + notifications.error(m.mount_upload_failed_datachannel()); setUploadState("idle"); console.log("Upload state set to 'idle'"); @@ -952,7 +958,7 @@ function UploadFileView({ rtcDataChannel.onerror = error => { console.error("RTC Data channel error:", error); - notifications.error(`Upload failed: ${error}`); + notifications.error(m.mount_upload_failed_rtc({ error: error })); setUploadState("idle"); console.log("Upload state set to 'idle'"); }; @@ -1037,7 +1043,7 @@ function UploadFileView({ file.name !== incompleteFileName.replace(".incomplete", "") ) { setFileError( - `Please select the file "${incompleteFileName.replace(".incomplete", "")}" to continue the upload.`, + m.mount_please_select_file({ name: incompleteFileName.replace(".incomplete", "") }), ); return; } @@ -1080,11 +1086,11 @@ function UploadFileView({ return (

{incompleteFileName - ? `Click to select "${incompleteFileName.replace(".incomplete", "")}"` - : "Click to select a file"} + ? m.mount_click_to_select_incomplete({ name: incompleteFileName.replace(".incomplete", "") }) + : m.mount_click_to_select_file()}

- Supported formats: ISO, IMG + {m.mount_supported_formats()}

)} @@ -1140,7 +1146,7 @@ function UploadFileView({

- Uploading {formatters.truncateMiddle(uploadedFileName, 30)} + {m.mount_uploading_with_name({ name: formatters.truncateMiddle(uploadedFileName, 30) })}

{formatters.bytes(uploadedFileSize || 0)} @@ -1153,11 +1159,11 @@ function UploadFileView({ >

- Uploading... + {m.mount_uploading()} {uploadSpeed !== null ? `${formatters.bytes(uploadSpeed)}/s` - : "Calculating..."} + : m.mount_calculating()}
@@ -1174,11 +1180,10 @@ function UploadFileView({

- Upload successful + {m.mount_upload_successful()}

- {formatters.truncateMiddle(uploadedFileName, 40)} has been - uploaded + {m.mount_uploaded_has_been_uploaded({ name: formatters.truncateMiddle(uploadedFileName, 40) })}

)} @@ -1205,7 +1210,7 @@ function UploadFileView({ className="mt-2 animate-fadeIn truncate text-sm text-red-600 dark:text-red-400 opacity-0" style={{ animationDuration: "0.7s" }} > - Error: {uploadError} + {m.mount_upload_error({ error: String(uploadError) })} )} @@ -1221,7 +1226,7 @@ function UploadFileView({