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..a7bf672d --- /dev/null +++ b/ui/localization/messages/en.json @@ -0,0 +1,461 @@ +{ + "$schema": "https://inlang.com/schema/inlang-message-format", + "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", + "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", + "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...", + "getting_remote_session_description": "Getting remote session description attempt {attempt}", + "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", + "kvm_terminal": "KVM Terminal", + "last_online": "Last online {time}", + "learn_more": "Learn more", + "load": "Load", + "loading": "Loading…", + "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", + "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", + "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..677f894b 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.09.0200", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "kvm-ui", - "version": "2025.10.01.1900", + "version": "2025.10.09.0200", "dependencies": { "@headlessui/react": "^2.2.9", "@headlessui/tailwindcss": "^0.2.2", @@ -25,13 +25,13 @@ "framer-motion": "^12.23.22", "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.127", "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.1", "@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.0", + "@typescript-eslint/parser": "^8.46.0", "@vitejs/plugin-react-swc": "^4.1.0", "autoprefixer": "^10.4.21", - "eslint": "^9.36.0", + "eslint": "^9.37.0", "eslint-config-prettier": "^10.1.8", "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" }, "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", @@ -913,14 +1275,14 @@ } }, "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 +1292,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 +1324,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 +1363,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 +1405,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 +1418,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 +1431,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 +1444,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 +1457,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 +1470,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 +1483,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 +1496,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 +1509,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 +1522,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 +1535,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 +1548,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 +1561,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 +1574,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 +1587,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 +1600,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 +1613,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 +1626,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 +1639,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 +1652,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 +1665,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 +1678,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 +1696,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 +2386,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.1", + "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-19.2.1.tgz", + "integrity": "sha512-/EEvYBdT3BflCWvTMO7YkYBHVE9Ci6XdqZciZANQgKpaiDRGOLIlRo91jbTNRQjgPFWVaRxcYc0luVNFitz57A==", "license": "MIT", "peerDependencies": { - "@types/react": "^19.0.0" + "@types/react": "^19.2.0" } }, "node_modules/@types/semver": { @@ -2045,17 +2424,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.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.46.0.tgz", + "integrity": "sha512-hA8gxBq4ukonVXPy0OKhiaUh/68D0E88GSmtC1iAEnGaieuDi38LhS7jdCHRLi6ErJBNDGCzvh5EnzdPwUc0DA==", "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.0", + "@typescript-eslint/type-utils": "8.46.0", + "@typescript-eslint/utils": "8.46.0", + "@typescript-eslint/visitor-keys": "8.46.0", "graphemer": "^1.4.0", "ignore": "^7.0.0", "natural-compare": "^1.4.0", @@ -2069,7 +2448,7 @@ "url": "https://opencollective.com/typescript-eslint" }, "peerDependencies": { - "@typescript-eslint/parser": "^8.45.0", + "@typescript-eslint/parser": "^8.46.0", "eslint": "^8.57.0 || ^9.0.0", "typescript": ">=4.8.4 <6.0.0" } @@ -2085,16 +2464,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.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.46.0.tgz", + "integrity": "sha512-n1H6IcDhmmUEG7TNVSspGmiHHutt7iVKtZwRppD7e04wha5MrkV1h3pti9xQLcCMt6YWsncpoT0HMjkH1FNwWQ==", "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.0", + "@typescript-eslint/types": "8.46.0", + "@typescript-eslint/typescript-estree": "8.46.0", + "@typescript-eslint/visitor-keys": "8.46.0", "debug": "^4.3.4" }, "engines": { @@ -2110,14 +2489,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.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.46.0.tgz", + "integrity": "sha512-OEhec0mH+U5Je2NZOeK1AbVCdm0ChyapAyTeXVIYTPXDJ3F07+cu87PPXcGoYqZ7M9YJVvFnfpGg1UmCIqM+QQ==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/tsconfig-utils": "^8.45.0", - "@typescript-eslint/types": "^8.45.0", + "@typescript-eslint/tsconfig-utils": "^8.46.0", + "@typescript-eslint/types": "^8.46.0", "debug": "^4.3.4" }, "engines": { @@ -2132,14 +2511,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.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.46.0.tgz", + "integrity": "sha512-lWETPa9XGcBes4jqAMYD9fW0j4n6hrPtTJwWDmtqgFO/4HF4jmdH/Q6wggTw5qIT5TXjKzbt7GsZUBnWoO3dqw==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/types": "8.45.0", - "@typescript-eslint/visitor-keys": "8.45.0" + "@typescript-eslint/types": "8.46.0", + "@typescript-eslint/visitor-keys": "8.46.0" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -2150,9 +2529,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.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.46.0.tgz", + "integrity": "sha512-WrYXKGAHY836/N7zoK/kzi6p8tXFhasHh8ocFL9VZSAkvH956gfeRfcnhs3xzRy8qQ/dq3q44v1jvQieMFg2cw==", "dev": true, "license": "MIT", "engines": { @@ -2167,15 +2546,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.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.46.0.tgz", + "integrity": "sha512-hy+lvYV1lZpVs2jRaEYvgCblZxUoJiPyCemwbQZ+NGulWkQRy0HRPYAoef/CNSzaLt+MLvMptZsHXHlkEilaeg==", "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.0", + "@typescript-eslint/typescript-estree": "8.46.0", + "@typescript-eslint/utils": "8.46.0", "debug": "^4.3.4", "ts-api-utils": "^2.1.0" }, @@ -2192,9 +2571,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.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.46.0.tgz", + "integrity": "sha512-bHGGJyVjSE4dJJIO5yyEWt/cHyNwga/zXGJbJJ8TiO01aVREK6gCTu3L+5wrkb1FbDkQ+TKjMNe9R/QQQP9+rA==", "dev": true, "license": "MIT", "engines": { @@ -2206,16 +2585,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.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.46.0.tgz", + "integrity": "sha512-ekDCUfVpAKWJbRfm8T1YRrCot1KFxZn21oV76v5Fj4tr7ELyk84OS+ouvYdcDAwZL89WpEkEj2DKQ+qg//+ucg==", "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.0", + "@typescript-eslint/tsconfig-utils": "8.46.0", + "@typescript-eslint/types": "8.46.0", + "@typescript-eslint/visitor-keys": "8.46.0", "debug": "^4.3.4", "fast-glob": "^3.3.2", "is-glob": "^4.0.3", @@ -2261,16 +2640,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.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.46.0.tgz", + "integrity": "sha512-nD6yGWPj1xiOm4Gk0k6hLSZz2XkNXhuYmyIrOWcHoPuAhjT9i5bAG+xbWPgFeNR8HPHHtpNKdYUXJl/D3x7f5g==", "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.0", + "@typescript-eslint/types": "8.46.0", + "@typescript-eslint/typescript-estree": "8.46.0" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -2285,13 +2664,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.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.46.0.tgz", + "integrity": "sha512-FrvMpAK+hTbFy7vH5j1+tMYHMSKLE6RzluFJlkFNKD0p9YsUT75JlBSmr5so3QRzvMwU5/bIEdeNrxm8du8l3Q==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/types": "8.45.0", + "@typescript-eslint/types": "8.46.0", "eslint-visitor-keys": "^4.2.1" }, "engines": { @@ -2494,6 +2873,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 +3065,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 +3188,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 +3261,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 +3318,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 +3579,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 +3635,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 +3671,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 +3862,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 +3912,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 +3948,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", @@ -3703,22 +4166,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 +4251,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 +4292,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", @@ -3981,6 +4453,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", @@ -4142,6 +4627,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 +4740,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 +4861,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 +5369,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 +5395,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 +5427,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 +5464,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 +5762,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", @@ -5351,9 +5914,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" }, @@ -5823,9 +6386,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 +6408,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 +6446,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 +6476,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 +6498,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.127", + "resolved": "https://registry.npmjs.org/react-simple-keyboard/-/react-simple-keyboard-3.8.127.tgz", + "integrity": "sha512-CncdXLnJ3tBlB6iEHtkgj5W21ns/DdKKO1bCy9pLWey5xONf+KAComVVnDsnAaC0b4LLI7frWBDjOT01vj8dew==", "license": "MIT", "peerDependencies": { "react": "^16.0.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", @@ -6090,9 +6653,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 +6668,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 +6770,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 +6942,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", @@ -6555,9 +7130,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 +7160,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 +7280,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 +7416,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 +7485,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 +7523,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 +7569,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 +7691,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 +7808,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 +7826,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..1ec23a71 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.09.0200", "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", @@ -36,13 +38,13 @@ "framer-motion": "^12.23.22", "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.127", "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.1", "@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.0", + "@typescript-eslint/parser": "^8.46.0", "@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..5c6afa46 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 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 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 { 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()} />
@@ -410,8 +411,8 @@ function UrlView({ return (
handleUrlChange(e.target.value)} @@ -440,12 +441,12 @@ function UrlView({
-
@@ -553,7 +554,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 +569,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 +598,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 +631,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 +678,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 +691,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 +805,7 @@ function DeviceFileView({ size="MD" theme="light" fullWidth - text="Upload a new image" + text={m.mount_button_upload_new_image()} onClick={() => onNewImageClick()} />
@@ -862,7 +861,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 +951,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 +1036,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 +1079,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 +1139,7 @@ function UploadFileView({

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

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

- Uploading... + {m.mount_uploading()} {uploadSpeed !== null ? `${formatters.bytes(uploadSpeed)}/s` - : "Calculating..."} + : m.mount_calculating()}
@@ -1174,11 +1173,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 +1203,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 +1219,7 @@ function UploadFileView({