mirror of https://github.com/jetkvm/kvm.git
Compare commits
2 Commits
bd772afc83
...
ad188365b2
| Author | SHA1 | Date |
|---|---|---|
|
|
ad188365b2 | |
|
|
e6fdd4a73b |
|
|
@ -15,5 +15,36 @@
|
|||
"containerUser": "vscode",
|
||||
"containerEnv": {
|
||||
"HOME": "/home/vscode"
|
||||
},
|
||||
"mounts": [
|
||||
"source=${localEnv:HOME}/.ssh,target=/home/vscode/.ssh,type=bind,consistency=cached"
|
||||
],
|
||||
"onCreateCommand": ".devcontainer/install-deps.sh",
|
||||
"customizations": {
|
||||
"vscode": {
|
||||
"extensions": [
|
||||
// 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"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -13,3 +13,5 @@ node_modules
|
|||
# generated during the build process
|
||||
#internal/native/include
|
||||
#internal/native/lib
|
||||
|
||||
ui/reports
|
||||
|
|
@ -1,21 +0,0 @@
|
|||
#!/usr/bin/env python3
|
||||
import json
|
||||
from pathlib import Path
|
||||
|
||||
messages_dir = Path(__file__).resolve().parent.parent / 'ui' / 'localization' / 'messages'
|
||||
files = list(messages_dir.glob('*.json'))
|
||||
|
||||
for f in files:
|
||||
data = json.loads(f.read_text(encoding='utf-8'))
|
||||
# Keep $schema first if present
|
||||
schema = None
|
||||
if '$schema' in data:
|
||||
schema = data.pop('$schema')
|
||||
sorted_items = dict(sorted(data.items()))
|
||||
if schema is not None:
|
||||
out = {'$schema': schema}
|
||||
out.update(sorted_items)
|
||||
else:
|
||||
out = sorted_items
|
||||
f.write_text(json.dumps(out, ensure_ascii=False, indent=4) + '\n', encoding='utf-8')
|
||||
print(f'Processed {len(files)} files in {messages_dir}')
|
||||
|
|
@ -31,7 +31,7 @@
|
|||
"access_no_device_id": "Intet enheds-ID tilgængeligt",
|
||||
"access_private_key_description": "Af sikkerhedsmæssige årsager vil den ikke blive vist efter lagring.",
|
||||
"access_private_key_label": "Privat nøgle",
|
||||
"access_provider_custom": "Skik",
|
||||
"access_provider_custom": "Tilpasset",
|
||||
"access_provider_jetkvm": "JetKVM Cloud",
|
||||
"access_remote_description": "Administrer tilstanden for fjernadgang til enheden",
|
||||
"access_security_encryption": "End-to-end-kryptering ved hjælp af WebRTC (DTLS og SRTP)",
|
||||
|
|
@ -42,15 +42,14 @@
|
|||
"access_title": "Adgang",
|
||||
"access_tls_certificate_description": "Indsæt dit TLS-certifikat nedenfor. For certifikatkæder skal du inkludere hele kæden (blad-, mellem- og rodcertifikater).",
|
||||
"access_tls_certificate_title": "TLS-certifikat",
|
||||
"access_tls_custom": "Skik",
|
||||
"access_tls_disabled": "Handicappet",
|
||||
"access_tls_custom": "Tilpasset",
|
||||
"access_tls_disabled": "Deaktiveret",
|
||||
"access_tls_self_signed": "Selvsigneret",
|
||||
"access_tls_updated": "TLS-indstillingerne er blevet opdateret",
|
||||
"access_update_tls_settings": "Opdater TLS-indstillinger",
|
||||
"action_bar_connection_stats": "Forbindelsesstatistik",
|
||||
"action_bar_extension": "Udvidelse",
|
||||
"action_bar_fullscreen": "Fuldskærm",
|
||||
"action_bar_paste_text": "Indsæt tekst",
|
||||
"action_bar_settings": "Indstillinger",
|
||||
"action_bar_virtual_keyboard": "Virtuelt tastatur",
|
||||
"action_bar_virtual_media": "Virtuelle medier",
|
||||
|
|
@ -116,7 +115,7 @@
|
|||
"atx_power_control_get_state_error": "Kunne ikke hente ATX-strømtilstand: {error}",
|
||||
"atx_power_control_hdd_led": "HDD-LED",
|
||||
"atx_power_control_long_power_button": "Langt tryk",
|
||||
"atx_power_control_power_button": "Magt",
|
||||
"atx_power_control_power_button": "Strøm",
|
||||
"atx_power_control_power_led": "Strøm-LED",
|
||||
"atx_power_control_reset_button": "Nulstil",
|
||||
"atx_power_control_send_action_error": "Kunne ikke sende ATX-strømfunktion {action} : {error}",
|
||||
|
|
@ -142,7 +141,6 @@
|
|||
"auth_mode_local_password_confirm_description": "Bekræft din adgangskode",
|
||||
"auth_mode_local_password_confirm_label": "Bekræft adgangskode",
|
||||
"auth_mode_local_password_description": "Sikr din enhed med en adgangskode for ekstra beskyttelse.",
|
||||
"auth_mode_local_password_do_not_match": "Adgangskoderne stemmer ikke overens",
|
||||
"auth_mode_local_password_failed_set": "Kunne ikke angive adgangskode: {error}",
|
||||
"auth_mode_local_password_note": "Denne adgangskode vil blive brugt til at sikre dine enhedsdata og beskytte mod uautoriseret adgang.",
|
||||
"auth_mode_local_password_note_local": "Alle data forbliver på din lokale enhed.",
|
||||
|
|
@ -156,8 +154,8 @@
|
|||
"auth_signup_create_account_description": "Opret din konto, og begynd nemt at administrere dine enheder.",
|
||||
"back": "Tilbage",
|
||||
"back_to_devices": "Tilbage til Enheder",
|
||||
"cancel": "Ophæve",
|
||||
"close": "Tæt",
|
||||
"cancel": "Annuller",
|
||||
"close": "Luk",
|
||||
"cloud_kvms": "Cloud KVM'er",
|
||||
"cloud_kvms_description": "Administrer dine cloud-KVM'er, og opret forbindelse til dem sikkert.",
|
||||
"cloud_kvms_no_devices": "Ingen enheder fundet",
|
||||
|
|
@ -181,6 +179,9 @@
|
|||
"connection_stats_round_trip_time": "Rundturstid",
|
||||
"connection_stats_round_trip_time_description": "Rundrejsetid for det aktive ICE-kandidatpar mellem peers.",
|
||||
"connection_stats_sidebar": "Forbindelsesstatistik",
|
||||
"connection_stats_unit_frames_per_second": " fps",
|
||||
"connection_stats_unit_milliseconds": " ms",
|
||||
"connection_stats_unit_packets": " pakker",
|
||||
"connection_stats_video": "Video",
|
||||
"connection_stats_video_description": "Videostreamen fra JetKVM'en til klienten.",
|
||||
"continue": "Fortsætte",
|
||||
|
|
@ -188,7 +189,7 @@
|
|||
"dc_power_control_current": "Strøm",
|
||||
"dc_power_control_current_unit": "EN",
|
||||
"dc_power_control_get_state_error": "Kunne ikke hente DC-strømtilstand: {error}",
|
||||
"dc_power_control_power": "Magt",
|
||||
"dc_power_control_power": "Strøm",
|
||||
"dc_power_control_power_off_button": "Sluk",
|
||||
"dc_power_control_power_off_state": "Sluk",
|
||||
"dc_power_control_power_on_button": "Tænd",
|
||||
|
|
@ -207,6 +208,8 @@
|
|||
"deregister_error": "Der opstod en fejl {status} under afregistreringen af din enhed. Prøv igen.",
|
||||
"deregister_headline": "Afregistrér {device} fra din cloud-konto",
|
||||
"detach": "Løsrive",
|
||||
"dhcp_empty_lease_description": "Vi har endnu ikke modtaget nogen DHCP-leaseoplysninger fra enheden.",
|
||||
"dhcp_empty_lease_headline": "Ingen DHCP-leaseoplysninger",
|
||||
"dhcp_lease_boot_file": "Boot-fil",
|
||||
"dhcp_lease_boot_next_server": "Start næste server",
|
||||
"dhcp_lease_boot_server_name": "Navn på bootserver",
|
||||
|
|
@ -371,7 +374,7 @@
|
|||
"local_auth_create_new_password_label": "Ny adgangskode",
|
||||
"local_auth_create_new_password_placeholder": "Indtast en stærk adgangskode",
|
||||
"local_auth_create_not_now_button": "Ikke nu",
|
||||
"local_auth_create_secure_button": "Sikker enhed",
|
||||
"local_auth_create_secure_button": "Sikr enheden",
|
||||
"local_auth_create_title": "Beskyttelse af lokal enhed",
|
||||
"local_auth_current_password_label": "Nuværende adgangskode",
|
||||
"local_auth_disable_local_device_protection_description": "Indtast din nuværende adgangskode for at deaktivere lokal enhedsbeskyttelse.",
|
||||
|
|
@ -396,7 +399,7 @@
|
|||
"local_auth_success_password_updated_description": "Du har ændret din adgangskode til beskyttelse af din lokale enhed. Husk din nye adgangskode til senere brug.",
|
||||
"local_auth_success_password_updated_title": "Adgangskode opdateret",
|
||||
"local_auth_update_password_button": "Opdater adgangskode",
|
||||
"locale_auto": "Bil",
|
||||
"locale_auto": "Auto",
|
||||
"locale_change_success": "Sproget er ændret til {locale}",
|
||||
"locale_da": "Dansk",
|
||||
"locale_de": "Tysk",
|
||||
|
|
@ -426,7 +429,8 @@
|
|||
"macro_name_too_long": "Navnet skal være mindre end 50 tegn",
|
||||
"macro_please_fix_validation_errors": "Ret venligst valideringsfejlene",
|
||||
"macro_save": "Gem makro",
|
||||
"macro_save_error": "Der opstod en fejl under lagring.",
|
||||
"macro_save_failed": "Der opstod en fejl under lagring.",
|
||||
"macro_save_failed_error": "Der opstod en fejl under lagring: {error}.",
|
||||
"macro_step_count": "{steps} / {max} trin",
|
||||
"macro_step_duration_description": "Tid til at vente, før man udfører det næste trin.",
|
||||
"macro_step_duration_label": "Trinvarighed",
|
||||
|
|
@ -549,9 +553,9 @@
|
|||
"mouse_hide_cursor_description": "Skjul markøren, når du sender musebevægelser",
|
||||
"mouse_hide_cursor_title": "Skjul markør",
|
||||
"mouse_jiggler_config_updated": "Jiggler-konfigurationen er blevet opdateret",
|
||||
"mouse_jiggler_custom": "Skik",
|
||||
"mouse_jiggler_custom": "Tilpasset",
|
||||
"mouse_jiggler_description": "Simuler bevægelsen af en computermus",
|
||||
"mouse_jiggler_disabled": "Handicappet",
|
||||
"mouse_jiggler_disabled": "Deaktiveret",
|
||||
"mouse_jiggler_error_config": "Der opstod en fejl under indstilling af jiggler-konfigurationen",
|
||||
"mouse_jiggler_failed_state": "Kunne ikke indstille jiggler-tilstand: {error}",
|
||||
"mouse_jiggler_frequent": "Hyppig - 30'erne",
|
||||
|
|
@ -578,7 +582,6 @@
|
|||
"network_dhcp_client_description": "Konfigurer hvilken DHCP-klient der skal bruges",
|
||||
"network_dhcp_client_jetkvm": "JetKVM Intern",
|
||||
"network_dhcp_client_title": "DHCP-klient",
|
||||
"network_dhcp_information": "DHCP-oplysninger",
|
||||
"network_dhcp_lease_renew": "Forny DHCP-lease",
|
||||
"network_dhcp_lease_renew_confirm": "Forny lejekontrakt",
|
||||
"network_dhcp_lease_renew_confirm_description": "Dette vil anmode om en ny IP-adresse fra din DHCP-server. Din enhed kan midlertidigt miste netværksforbindelsen under denne proces.",
|
||||
|
|
@ -586,7 +589,7 @@
|
|||
"network_dhcp_lease_renew_confirm_new_b": "du skal muligvis genoprette forbindelsen ved hjælp af den nye adresse",
|
||||
"network_dhcp_lease_renew_failed": "Kunne ikke forny leasing: {error}",
|
||||
"network_dhcp_lease_renew_success": "DHCP-lease fornyet",
|
||||
"network_domain_custom": "Skik",
|
||||
"network_domain_custom": "Tilpasset",
|
||||
"network_domain_description": "Netværksdomænesuffiks for enheden",
|
||||
"network_domain_dhcp_provided": "DHCP leveret",
|
||||
"network_domain_local": ".lokal",
|
||||
|
|
@ -599,39 +602,46 @@
|
|||
"network_ipv4_address": "IPv4-adresse",
|
||||
"network_ipv4_dns": "IPv4 DNS",
|
||||
"network_ipv4_gateway": "IPv4-gateway",
|
||||
"network_ipv4_invalid": "Ugyldig IPv4-adresse",
|
||||
"network_ipv4_invalid_cidr": "Ugyldig CIDR-notation for IPv4-adresse",
|
||||
"network_ipv4_mode_description": "Konfigurer IPv4-tilstanden",
|
||||
"network_ipv4_mode_dhcp": "DHCP",
|
||||
"network_ipv4_mode_static": "Statisk",
|
||||
"network_ipv4_mode_title": "IPv4-tilstand",
|
||||
"network_ipv4_netmask": "IPv4-netmaske",
|
||||
"network_ipv6_address": "IPv6-adresse",
|
||||
"network_ipv6_addresses_header": "IPv6-adresser",
|
||||
"network_ipv6_cidr_suggestion": "Brug venligst CIDR-notation (f.eks. 2001:db8::1/64)",
|
||||
"network_ipv6_dns": "IPv6 DNS",
|
||||
"network_ipv6_flag_dad_failed": "DAD mislykkedes",
|
||||
"network_ipv6_flag_deprecated": "Udfaset",
|
||||
"network_ipv6_gateway": "IPv6-gateway",
|
||||
"network_ipv6_information": "IPv6-oplysninger",
|
||||
"network_ipv6_invalid": "Ugyldig IPv6-adresse",
|
||||
"network_ipv6_mode_description": "Konfigurer IPv6-tilstanden",
|
||||
"network_ipv6_mode_dhcpv6": "DHCPv6",
|
||||
"network_ipv6_mode_disabled": "Handicappet",
|
||||
"network_ipv6_mode_disabled": "Deaktiveret",
|
||||
"network_ipv6_mode_link_local": "Kun link-lokal",
|
||||
"network_ipv6_mode_slaac": "SLAAC",
|
||||
"network_ipv6_mode_slaac_dhcpv6": "SLAAC + DHCPv6",
|
||||
"network_ipv6_mode_static": "Statisk",
|
||||
"network_ipv6_mode_title": "IPv6-tilstand",
|
||||
"network_ipv6_netmask": "IPv6-netmaske",
|
||||
"network_ipv6_no_addresses": "Ingen IPv6-adresser konfigureret",
|
||||
"network_ipv6_prefix": "IP-præfiks",
|
||||
"network_ipv6_prefix_invalid": "Præfikset skal være mellem 0 og 128",
|
||||
"network_ll_dp_all": "Alle",
|
||||
"network_ll_dp_basic": "Grundlæggende",
|
||||
"network_ll_dp_description": "Styr hvilke TLV'er der sendes via Link Layer Discovery Protocol",
|
||||
"network_ll_dp_disabled": "Handicappet",
|
||||
"network_ll_dp_disabled": "Deaktiveret",
|
||||
"network_ll_dp_title": "LLDP",
|
||||
"network_mac_address_copy_error": "Kunne ikke kopiere MAC-adressen",
|
||||
"network_mac_address_copy_success": "MAC-adresse { mac } kopieret til udklipsholder",
|
||||
"network_mac_address_description": "Hardware-identifikator for netværksgrænsefladen",
|
||||
"network_mac_address_title": "MAC-adresse",
|
||||
"network_mdns_auto": "Bil",
|
||||
"network_mdns_auto": "Auto",
|
||||
"network_mdns_description": "Styr mDNS (multicast DNS) driftstilstand",
|
||||
"network_mdns_disabled": "Handicappet",
|
||||
"network_mdns_disabled": "Deaktiveret",
|
||||
"network_mdns_ipv4_only": "Kun IPv4",
|
||||
"network_mdns_ipv6_only": "Kun IPv6",
|
||||
"network_mdns_title": "mDNS",
|
||||
"network_no_dhcp_lease": "Ingen DHCP-leaseoplysninger tilgængelige",
|
||||
"network_no_information_description": "Ingen netværkskonfiguration tilgængelig",
|
||||
"network_no_information_headline": "Netværksoplysninger",
|
||||
"network_pending_dhcp_mode_change_description": "Gem indstillinger for at aktivere DHCP-tilstand og se leasingoplysninger",
|
||||
|
|
@ -643,8 +653,10 @@
|
|||
"network_save_settings_confirm_heading": "Konfigurationsændringer",
|
||||
"network_save_settings_failed": "Kunne ikke gemme netværksindstillinger: {error}",
|
||||
"network_save_settings_success": "Netværksindstillinger gemt",
|
||||
"network_settings_invalid_ipv4_cidr": "Ugyldig CIDR-notation for IPv4-adresse",
|
||||
"network_settings_add_dns": "Tilføj DNS-server",
|
||||
"network_settings_load_error": "Kunne ikke indlæse netværksindstillinger: {error}",
|
||||
"network_static_ipv4_header": "Statisk IPv4-konfiguration",
|
||||
"network_static_ipv6_header": "Statisk IPv6-konfiguration",
|
||||
"network_time_sync_description": "Konfigurer indstillinger for tidssynkronisering",
|
||||
"network_time_sync_http_only": "Kun HTTP",
|
||||
"network_time_sync_ntp_and_http": "NTP og HTTP",
|
||||
|
|
@ -670,9 +682,9 @@
|
|||
"paste_modal_failed_paste": "Kunne ikke indsætte tekst: {error}",
|
||||
"paste_modal_invalid_chars_intro": "Følgende tegn vil ikke blive indsat:",
|
||||
"paste_modal_paste_from_host": "Indsæt fra vært",
|
||||
"paste_modal_paste_text": "Indsæt tekst",
|
||||
"paste_modal_paste_text_description": "Indsæt tekst fra din klient til den eksterne vært",
|
||||
"paste_modal_sending_using_layout": "Sender tekst ved hjælp af tastaturlayout: {iso} - {name}",
|
||||
"paste_text": "Indsæt tekst",
|
||||
"paste_text_description": "Indsæt tekst fra din klient til den eksterne vært",
|
||||
"peer_connection_closed": "Lukket",
|
||||
"peer_connection_closing": "Lukker",
|
||||
"peer_connection_connected": "Forbundet",
|
||||
|
|
@ -743,7 +755,7 @@
|
|||
"updates_failed_get_device_version": "Kunne ikke hente enhedsversion: {error}",
|
||||
"updating_leave_device_on": "Sluk venligst ikke din enhed…",
|
||||
"usb": "USB",
|
||||
"usb_config_custom": "Skik",
|
||||
"usb_config_custom": "Tilpasset",
|
||||
"usb_config_default": "JetKVM-standard",
|
||||
"usb_config_dell": "Dell Multimedia Pro-tastatur",
|
||||
"usb_config_failed_load": "Kunne ikke indlæse USB-konfiguration: {error}",
|
||||
|
|
@ -767,7 +779,7 @@
|
|||
"usb_config_vendor_id_placeholder": "Indtast leverandør-ID",
|
||||
"usb_device_classes_description": "USB-enhedsklasser i den sammensatte enhed",
|
||||
"usb_device_classes_title": "Klasser",
|
||||
"usb_device_custom": "Skik",
|
||||
"usb_device_custom": "Tilpasset",
|
||||
"usb_device_description": "USB-enheder, der skal emuleres på målcomputeren",
|
||||
"usb_device_enable_absolute_mouse_description": "Aktivér absolut mus (markør)",
|
||||
"usb_device_enable_absolute_mouse_title": "Aktivér absolut mus (markør)",
|
||||
|
|
@ -802,7 +814,7 @@
|
|||
"video_description": "Konfigurer skærmindstillinger og EDID for optimal kompatibilitet",
|
||||
"video_edid_acer_b246wl": "Acer B246WL, 1920x1200",
|
||||
"video_edid_asus_pa248qv": "ASUS PA248QV, 1920x1200",
|
||||
"video_edid_custom": "Skik",
|
||||
"video_edid_custom": "Tilpasset",
|
||||
"video_edid_dell_d2721h": "DELL D2721H, 1920x1080",
|
||||
"video_edid_dell_idrac": "DELL IDRAC EDID, 1280x1024",
|
||||
"video_edid_description": "Juster EDID-indstillingerne for skærmen",
|
||||
|
|
|
|||
|
|
@ -50,7 +50,6 @@
|
|||
"action_bar_connection_stats": "Verbindungsstatistiken",
|
||||
"action_bar_extension": "Verlängerung",
|
||||
"action_bar_fullscreen": "Vollbild",
|
||||
"action_bar_paste_text": "Text einfügen",
|
||||
"action_bar_settings": "Einstellungen",
|
||||
"action_bar_virtual_keyboard": "Virtuelle Tastatur",
|
||||
"action_bar_virtual_media": "Virtuelle Medien",
|
||||
|
|
@ -142,7 +141,6 @@
|
|||
"auth_mode_local_password_confirm_description": "Bestätigen Sie Ihr Passwort",
|
||||
"auth_mode_local_password_confirm_label": "Passwort bestätigen",
|
||||
"auth_mode_local_password_description": "Sichern Sie Ihr Gerät für zusätzlichen Schutz mit einem Passwort.",
|
||||
"auth_mode_local_password_do_not_match": "Passwörter stimmen nicht überein",
|
||||
"auth_mode_local_password_failed_set": "Kennwort konnte nicht festgelegt werden: {error}",
|
||||
"auth_mode_local_password_note": "Dieses Passwort wird verwendet, um Ihre Gerätedaten zu sichern und vor unbefugtem Zugriff zu schützen.",
|
||||
"auth_mode_local_password_note_local": "Alle Daten verbleiben auf Ihrem lokalen Gerät.",
|
||||
|
|
@ -181,6 +179,9 @@
|
|||
"connection_stats_round_trip_time": "Round-Trip-Zeit",
|
||||
"connection_stats_round_trip_time_description": "Roundtrip-Zeit für das aktive ICE-Kandidatenpaar zwischen Peers.",
|
||||
"connection_stats_sidebar": "Verbindungsstatistiken",
|
||||
"connection_stats_unit_frames_per_second": " fps",
|
||||
"connection_stats_unit_milliseconds": " ms",
|
||||
"connection_stats_unit_packets": " Pakete",
|
||||
"connection_stats_video": "Video",
|
||||
"connection_stats_video_description": "Der Videostream vom JetKVM zum Client.",
|
||||
"continue": "Weitermachen",
|
||||
|
|
@ -207,6 +208,8 @@
|
|||
"deregister_error": "Beim Abmelden Ihres Geräts ist ein Fehler aufgetreten {status} . Bitte versuchen Sie es erneut.",
|
||||
"deregister_headline": "Melden Sie {device}",
|
||||
"detach": "Abtrennen",
|
||||
"dhcp_empty_lease_description": "Wir haben noch keine DHCP-Lease-Informationen vom Gerät erhalten.",
|
||||
"dhcp_empty_lease_headline": "Keine DHCP-Lease-Informationen",
|
||||
"dhcp_lease_boot_file": "Boot-Datei",
|
||||
"dhcp_lease_boot_next_server": "Nächsten Server starten",
|
||||
"dhcp_lease_boot_server_name": "Name des Boot-Servers",
|
||||
|
|
@ -426,7 +429,8 @@
|
|||
"macro_name_too_long": "Der Name muss weniger als 50 Zeichen lang sein",
|
||||
"macro_please_fix_validation_errors": "Bitte beheben Sie die Validierungsfehler",
|
||||
"macro_save": "Makro speichern",
|
||||
"macro_save_error": "Beim Speichern ist ein Fehler aufgetreten.",
|
||||
"macro_save_failed": "Beim Speichern ist ein Fehler aufgetreten.",
|
||||
"macro_save_failed_error": "Beim Speichern ist ein Fehler aufgetreten: {error}.",
|
||||
"macro_step_count": "{steps} / {max} Schritte",
|
||||
"macro_step_duration_description": "Wartezeit vor der Ausführung des nächsten Schritts.",
|
||||
"macro_step_duration_label": "Schrittdauer",
|
||||
|
|
@ -578,7 +582,6 @@
|
|||
"network_dhcp_client_description": "Konfigurieren Sie, welcher DHCP-Client verwendet werden soll",
|
||||
"network_dhcp_client_jetkvm": "JetKVM intern",
|
||||
"network_dhcp_client_title": "DHCP-Client",
|
||||
"network_dhcp_information": "DHCP-Informationen",
|
||||
"network_dhcp_lease_renew": "DHCP-Lease erneuern",
|
||||
"network_dhcp_lease_renew_confirm": "Mietvertrag verlängern",
|
||||
"network_dhcp_lease_renew_confirm_description": "Dadurch wird eine neue IP-Adresse von Ihrem DHCP-Server angefordert. Während dieses Vorgangs kann die Netzwerkverbindung Ihres Geräts vorübergehend unterbrochen werden.",
|
||||
|
|
@ -599,13 +602,21 @@
|
|||
"network_ipv4_address": "IPv4-Adresse",
|
||||
"network_ipv4_dns": "IPv4 DNS",
|
||||
"network_ipv4_gateway": "IPv4-Gateway",
|
||||
"network_ipv4_invalid": "Ungültige IPv4-Adresse",
|
||||
"network_ipv4_invalid_cidr": "Ungültige CIDR-Notation für IPv4-Adresse",
|
||||
"network_ipv4_mode_description": "Konfigurieren des IPv4-Modus",
|
||||
"network_ipv4_mode_dhcp": "DHCP",
|
||||
"network_ipv4_mode_static": "Statisch",
|
||||
"network_ipv4_mode_title": "IPv4-Modus",
|
||||
"network_ipv4_netmask": "IPv4-Netzmaske",
|
||||
"network_ipv6_address": "IPv6-Adresse",
|
||||
"network_ipv6_addresses_header": "IPv6-Adressen",
|
||||
"network_ipv6_cidr_suggestion": "Bitte verwenden Sie die CIDR-Notation (z. B. 2001:db8::1/64).",
|
||||
"network_ipv6_dns": "IPv6 DNS",
|
||||
"network_ipv6_flag_dad_failed": "DAD ist fehlgeschlagen",
|
||||
"network_ipv6_flag_deprecated": "Veraltet",
|
||||
"network_ipv6_gateway": "IPv6-Gateway",
|
||||
"network_ipv6_information": "IPv6-Informationen",
|
||||
"network_ipv6_invalid": "Ungültige IPv6-Adresse",
|
||||
"network_ipv6_mode_description": "Konfigurieren des IPv6-Modus",
|
||||
"network_ipv6_mode_dhcpv6": "DHCPv6",
|
||||
"network_ipv6_mode_disabled": "Deaktiviert",
|
||||
|
|
@ -614,8 +625,8 @@
|
|||
"network_ipv6_mode_slaac_dhcpv6": "SLAAC + DHCPv6",
|
||||
"network_ipv6_mode_static": "Statisch",
|
||||
"network_ipv6_mode_title": "IPv6-Modus",
|
||||
"network_ipv6_netmask": "IPv6-Netzmaske",
|
||||
"network_ipv6_no_addresses": "Keine IPv6-Adressen konfiguriert",
|
||||
"network_ipv6_prefix": "IP-Präfix",
|
||||
"network_ipv6_prefix_invalid": "Das Präfix muss zwischen 0 und 128 liegen",
|
||||
"network_ll_dp_all": "Alle",
|
||||
"network_ll_dp_basic": "Basic",
|
||||
"network_ll_dp_description": "Steuern Sie, welche TLVs über das Link Layer Discovery Protocol gesendet werden",
|
||||
|
|
@ -631,7 +642,6 @@
|
|||
"network_mdns_ipv4_only": "Nur IPv4",
|
||||
"network_mdns_ipv6_only": "Nur IPv6",
|
||||
"network_mdns_title": "mDNS",
|
||||
"network_no_dhcp_lease": "Keine DHCP-Lease-Informationen verfügbar",
|
||||
"network_no_information_description": "Keine Netzwerkkonfiguration verfügbar",
|
||||
"network_no_information_headline": "Netzwerkinformationen",
|
||||
"network_pending_dhcp_mode_change_description": "Speichern Sie die Einstellungen, um den DHCP-Modus zu aktivieren und Leasinginformationen anzuzeigen",
|
||||
|
|
@ -643,8 +653,10 @@
|
|||
"network_save_settings_confirm_heading": "Konfigurationsänderungen",
|
||||
"network_save_settings_failed": "Netzwerkeinstellungen konnten nicht gespeichert werden: {error}",
|
||||
"network_save_settings_success": "Netzwerkeinstellungen gespeichert",
|
||||
"network_settings_invalid_ipv4_cidr": "Ungültige CIDR-Notation für IPv4-Adresse",
|
||||
"network_settings_add_dns": "DNS-Server hinzufügen",
|
||||
"network_settings_load_error": "Netzwerkeinstellungen konnten nicht geladen werden: {error}",
|
||||
"network_static_ipv4_header": "Statische IPv4-Konfiguration",
|
||||
"network_static_ipv6_header": "Statische IPv6-Konfiguration",
|
||||
"network_time_sync_description": "Konfigurieren der Zeitsynchronisierungseinstellungen",
|
||||
"network_time_sync_http_only": "Nur HTTP",
|
||||
"network_time_sync_ntp_and_http": "NTP und HTTP",
|
||||
|
|
@ -670,9 +682,9 @@
|
|||
"paste_modal_failed_paste": "Fehler beim Einfügen des Textes: {error}",
|
||||
"paste_modal_invalid_chars_intro": "Die folgenden Zeichen werden nicht eingefügt:",
|
||||
"paste_modal_paste_from_host": "Vom Host einfügen",
|
||||
"paste_modal_paste_text": "Text einfügen",
|
||||
"paste_modal_paste_text_description": "Fügen Sie Text von Ihrem Client in den Remote-Host ein",
|
||||
"paste_modal_sending_using_layout": "Senden von Text mithilfe des Tastaturlayouts: {iso} - {name}",
|
||||
"paste_text": "Text einfügen",
|
||||
"paste_text_description": "Fügen Sie Text von Ihrem Client in den Remote-Host ein",
|
||||
"peer_connection_closed": "Geschlossen",
|
||||
"peer_connection_closing": "Schließen",
|
||||
"peer_connection_connected": "Verbunden",
|
||||
|
|
|
|||
|
|
@ -50,7 +50,6 @@
|
|||
"action_bar_connection_stats": "Connection Stats",
|
||||
"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",
|
||||
|
|
@ -142,7 +141,6 @@
|
|||
"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": "This password will be used to secure your device data and protect against unauthorized access.",
|
||||
"auth_mode_local_password_note_local": "All data remains on your local device.",
|
||||
|
|
@ -181,6 +179,9 @@
|
|||
"connection_stats_round_trip_time": "Round-Trip Time",
|
||||
"connection_stats_round_trip_time_description": "Round-trip time for the active ICE candidate pair between peers.",
|
||||
"connection_stats_sidebar": "Connection Stats",
|
||||
"connection_stats_unit_frames_per_second": " fps",
|
||||
"connection_stats_unit_milliseconds": " ms",
|
||||
"connection_stats_unit_packets": " packets",
|
||||
"connection_stats_video": "Video",
|
||||
"connection_stats_video_description": "The video stream from the JetKVM to the client.",
|
||||
"continue": "Continue",
|
||||
|
|
@ -207,6 +208,8 @@
|
|||
"deregister_error": "There was an error {status} deregistering your device. Please try again.",
|
||||
"deregister_headline": "Deregister {device} from your cloud account",
|
||||
"detach": "Detach",
|
||||
"dhcp_empty_lease_description": "We haven't received any DHCP lease information from the device yet.",
|
||||
"dhcp_empty_lease_headline": "No DHCP Lease information",
|
||||
"dhcp_lease_boot_file": "Boot File",
|
||||
"dhcp_lease_boot_next_server": "Boot Next Server",
|
||||
"dhcp_lease_boot_server_name": "Boot Server Name",
|
||||
|
|
@ -426,7 +429,8 @@
|
|||
"macro_name_too_long": "Name must be less than 50 characters",
|
||||
"macro_please_fix_validation_errors": "Please fix the validation errors",
|
||||
"macro_save": "Save Macro",
|
||||
"macro_save_error": "An error occurred while saving.",
|
||||
"macro_save_failed": "An error occurred while saving.",
|
||||
"macro_save_failed_error": "An error occurred while saving: {error}.",
|
||||
"macro_step_count": "{steps} / {max} steps",
|
||||
"macro_step_duration_description": "Time to wait before executing the next step.",
|
||||
"macro_step_duration_label": "Step Duration",
|
||||
|
|
@ -578,7 +582,6 @@
|
|||
"network_dhcp_client_description": "Configure which DHCP client to use",
|
||||
"network_dhcp_client_jetkvm": "JetKVM Internal",
|
||||
"network_dhcp_client_title": "DHCP Client",
|
||||
"network_dhcp_information": "DHCP Information",
|
||||
"network_dhcp_lease_renew": "Renew DHCP Lease",
|
||||
"network_dhcp_lease_renew_confirm": "Renew Lease",
|
||||
"network_dhcp_lease_renew_confirm_description": "This will request a new IP address from your DHCP server. Your device may temporarily lose network connectivity during this process.",
|
||||
|
|
@ -599,13 +602,21 @@
|
|||
"network_ipv4_address": "IPv4 Address",
|
||||
"network_ipv4_dns": "IPv4 DNS",
|
||||
"network_ipv4_gateway": "IPv4 Gateway",
|
||||
"network_ipv4_invalid": "Invalid IPv4 address",
|
||||
"network_ipv4_invalid_cidr": "Invalid CIDR notation for IPv4 address",
|
||||
"network_ipv4_mode_description": "Configure the IPv4 mode",
|
||||
"network_ipv4_mode_dhcp": "DHCP",
|
||||
"network_ipv4_mode_static": "Static",
|
||||
"network_ipv4_mode_title": "IPv4 Mode",
|
||||
"network_ipv4_netmask": "IPv4 Netmask",
|
||||
"network_ipv6_address": "IPv6 Address",
|
||||
"network_ipv6_addresses_header": "IPv6 Addresses",
|
||||
"network_ipv6_cidr_suggestion": "Please use CIDR notation (e.g., 2001:db8::1/64)",
|
||||
"network_ipv6_dns": "IPv6 DNS",
|
||||
"network_ipv6_flag_dad_failed": "DAD Failed",
|
||||
"network_ipv6_flag_deprecated": "Deprecated",
|
||||
"network_ipv6_gateway": "IPv6 Gateway",
|
||||
"network_ipv6_information": "IPv6 Information",
|
||||
"network_ipv6_invalid": "Invalid IPv6 address",
|
||||
"network_ipv6_mode_description": "Configure the IPv6 mode",
|
||||
"network_ipv6_mode_dhcpv6": "DHCPv6",
|
||||
"network_ipv6_mode_disabled": "Disabled",
|
||||
|
|
@ -614,8 +625,8 @@
|
|||
"network_ipv6_mode_slaac_dhcpv6": "SLAAC + DHCPv6",
|
||||
"network_ipv6_mode_static": "Static",
|
||||
"network_ipv6_mode_title": "IPv6 Mode",
|
||||
"network_ipv6_netmask": "IPv6 Netmask",
|
||||
"network_ipv6_no_addresses": "No IPv6 addresses configured",
|
||||
"network_ipv6_prefix": "IP Prefix",
|
||||
"network_ipv6_prefix_invalid": "Prefix must be between 0 and 128",
|
||||
"network_ll_dp_all": "All",
|
||||
"network_ll_dp_basic": "Basic",
|
||||
"network_ll_dp_description": "Control which TLVs will be sent over Link Layer Discovery Protocol",
|
||||
|
|
@ -631,7 +642,6 @@
|
|||
"network_mdns_ipv4_only": "IPv4 only",
|
||||
"network_mdns_ipv6_only": "IPv6 only",
|
||||
"network_mdns_title": "mDNS",
|
||||
"network_no_dhcp_lease": "No DHCP lease information available",
|
||||
"network_no_information_description": "No network configuration available",
|
||||
"network_no_information_headline": "Network Information",
|
||||
"network_pending_dhcp_mode_change_description": "Save settings to enable DHCP mode and view lease information",
|
||||
|
|
@ -643,8 +653,10 @@
|
|||
"network_save_settings_confirm_heading": "Configuration changes",
|
||||
"network_save_settings_failed": "Failed to save network settings: {error}",
|
||||
"network_save_settings_success": "Network settings saved",
|
||||
"network_settings_invalid_ipv4_cidr": "Invalid CIDR notation for IPv4 address",
|
||||
"network_settings_add_dns": "Add DNS Server",
|
||||
"network_settings_load_error": "Failed to load network settings: {error}",
|
||||
"network_static_ipv4_header": "Static IPv4 Configuration",
|
||||
"network_static_ipv6_header": "Static IPv6 Configuration",
|
||||
"network_time_sync_description": "Configure time synchronization settings",
|
||||
"network_time_sync_http_only": "HTTP only",
|
||||
"network_time_sync_ntp_and_http": "NTP and HTTP",
|
||||
|
|
@ -670,9 +682,9 @@
|
|||
"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": "Paste text",
|
||||
"paste_modal_paste_text_description": "Paste text from your client to the remote host",
|
||||
"paste_modal_sending_using_layout": "Sending text using keyboard layout: {iso}-{name}",
|
||||
"paste_text": "Paste text",
|
||||
"paste_text_description": "Paste text from your client to the remote host",
|
||||
"peer_connection_closed": "Closed",
|
||||
"peer_connection_closing": "Closing",
|
||||
"peer_connection_connected": "Connected",
|
||||
|
|
|
|||
|
|
@ -50,7 +50,6 @@
|
|||
"action_bar_connection_stats": "Estadísticas de conexión",
|
||||
"action_bar_extension": "Extensión",
|
||||
"action_bar_fullscreen": "Pantalla completa",
|
||||
"action_bar_paste_text": "Pegar texto",
|
||||
"action_bar_settings": "Ajustes",
|
||||
"action_bar_virtual_keyboard": "Teclado virtual",
|
||||
"action_bar_virtual_media": "Medios virtuales",
|
||||
|
|
@ -142,7 +141,6 @@
|
|||
"auth_mode_local_password_confirm_description": "Confirma tu contraseña",
|
||||
"auth_mode_local_password_confirm_label": "confirmar Contraseña",
|
||||
"auth_mode_local_password_description": "Proteja su dispositivo con una contraseña para mayor protección.",
|
||||
"auth_mode_local_password_do_not_match": "Las contraseñas no coinciden",
|
||||
"auth_mode_local_password_failed_set": "No se pudo establecer la contraseña: {error}",
|
||||
"auth_mode_local_password_note": "Esta contraseña se utilizará para proteger los datos de su dispositivo y contra accesos no autorizados.",
|
||||
"auth_mode_local_password_note_local": "Todos los datos permanecen en su dispositivo local.",
|
||||
|
|
@ -181,6 +179,9 @@
|
|||
"connection_stats_round_trip_time": "Tiempo de ida y vuelta",
|
||||
"connection_stats_round_trip_time_description": "Tiempo de ida y vuelta para el par de candidatos ICE activos entre pares.",
|
||||
"connection_stats_sidebar": "Estadísticas de conexión",
|
||||
"connection_stats_unit_frames_per_second": " fps",
|
||||
"connection_stats_unit_milliseconds": " ms",
|
||||
"connection_stats_unit_packets": " paquetes",
|
||||
"connection_stats_video": "Video",
|
||||
"connection_stats_video_description": "La transmisión de vídeo desde JetKVM al cliente.",
|
||||
"continue": "Continuar",
|
||||
|
|
@ -207,6 +208,8 @@
|
|||
"deregister_error": "Se produjo un error {status} al cancelar el registro de su dispositivo. Inténtelo de nuevo.",
|
||||
"deregister_headline": "Anular el registro de {device} en su cuenta en la nube",
|
||||
"detach": "Despegar",
|
||||
"dhcp_empty_lease_description": "Aún no hemos recibido ninguna información de concesión de DHCP del dispositivo.",
|
||||
"dhcp_empty_lease_headline": "No hay información de arrendamiento de DHCP",
|
||||
"dhcp_lease_boot_file": "Archivo de arranque",
|
||||
"dhcp_lease_boot_next_server": "Arrancar el siguiente servidor",
|
||||
"dhcp_lease_boot_server_name": "Nombre del servidor de arranque",
|
||||
|
|
@ -426,7 +429,8 @@
|
|||
"macro_name_too_long": "El nombre debe tener menos de 50 caracteres.",
|
||||
"macro_please_fix_validation_errors": "Por favor corrija los errores de validación",
|
||||
"macro_save": "Guardar macro",
|
||||
"macro_save_error": "Se produjo un error al guardar.",
|
||||
"macro_save_failed": "Se produjo un error al guardar.",
|
||||
"macro_save_failed_error": "Se produjo un error al guardar: {error}.",
|
||||
"macro_step_count": "{steps} / {max} pasos",
|
||||
"macro_step_duration_description": "Tiempo de espera antes de ejecutar el siguiente paso.",
|
||||
"macro_step_duration_label": "Duración del paso",
|
||||
|
|
@ -578,7 +582,6 @@
|
|||
"network_dhcp_client_description": "Configurar qué cliente DHCP utilizar",
|
||||
"network_dhcp_client_jetkvm": "JetKVM interno",
|
||||
"network_dhcp_client_title": "Cliente DHCP",
|
||||
"network_dhcp_information": "Información de DHCP",
|
||||
"network_dhcp_lease_renew": "Renovar la concesión de DHCP",
|
||||
"network_dhcp_lease_renew_confirm": "Renovar el contrato de arrendamiento",
|
||||
"network_dhcp_lease_renew_confirm_description": "Esto solicitará una nueva dirección IP a su servidor DHCP. Es posible que su dispositivo pierda temporalmente la conexión a la red durante este proceso.",
|
||||
|
|
@ -599,13 +602,21 @@
|
|||
"network_ipv4_address": "Dirección IPv4",
|
||||
"network_ipv4_dns": "DNS IPv4",
|
||||
"network_ipv4_gateway": "Puerta de enlace IPv4",
|
||||
"network_ipv4_invalid": "Dirección IPv4 no válida",
|
||||
"network_ipv4_invalid_cidr": "Notación CIDR no válida para la dirección IPv4",
|
||||
"network_ipv4_mode_description": "Configurar el modo IPv4",
|
||||
"network_ipv4_mode_dhcp": "DHCP",
|
||||
"network_ipv4_mode_static": "Estático",
|
||||
"network_ipv4_mode_title": "Modo IPv4",
|
||||
"network_ipv4_netmask": "Máscara de red IPv4",
|
||||
"network_ipv6_address": "Dirección IPv6",
|
||||
"network_ipv6_addresses_header": "Direcciones IPv6",
|
||||
"network_ipv6_cidr_suggestion": "Utilice la notación CIDR (por ejemplo, 2001:db8::1/64)",
|
||||
"network_ipv6_dns": "DNS IPv6",
|
||||
"network_ipv6_flag_dad_failed": "Papá falló",
|
||||
"network_ipv6_flag_deprecated": "Obsoleto",
|
||||
"network_ipv6_gateway": "Puerta de enlace IPv6",
|
||||
"network_ipv6_information": "Información de IPv6",
|
||||
"network_ipv6_invalid": "Dirección IPv6 no válida",
|
||||
"network_ipv6_mode_description": "Configurar el modo IPv6",
|
||||
"network_ipv6_mode_dhcpv6": "DHCPv6",
|
||||
"network_ipv6_mode_disabled": "Desactivado",
|
||||
|
|
@ -614,8 +625,8 @@
|
|||
"network_ipv6_mode_slaac_dhcpv6": "SLAAC + DHCPv6",
|
||||
"network_ipv6_mode_static": "Estático",
|
||||
"network_ipv6_mode_title": "Modo IPv6",
|
||||
"network_ipv6_netmask": "Máscara de red IPv6",
|
||||
"network_ipv6_no_addresses": "No hay direcciones IPv6 configuradas",
|
||||
"network_ipv6_prefix": "Prefijo IP",
|
||||
"network_ipv6_prefix_invalid": "El prefijo debe estar entre 0 y 128",
|
||||
"network_ll_dp_all": "Todo",
|
||||
"network_ll_dp_basic": "Básico",
|
||||
"network_ll_dp_description": "Controlar qué TLV se enviarán a través del Protocolo de descubrimiento de capa de enlace",
|
||||
|
|
@ -631,7 +642,6 @@
|
|||
"network_mdns_ipv4_only": "Sólo IPv4",
|
||||
"network_mdns_ipv6_only": "Sólo IPv6",
|
||||
"network_mdns_title": "mDNS",
|
||||
"network_no_dhcp_lease": "No hay información de arrendamiento de DHCP disponible",
|
||||
"network_no_information_description": "No hay configuración de red disponible",
|
||||
"network_no_information_headline": "Información de la red",
|
||||
"network_pending_dhcp_mode_change_description": "Guardar la configuración para habilitar el modo DHCP y ver la información de arrendamiento",
|
||||
|
|
@ -643,8 +653,10 @@
|
|||
"network_save_settings_confirm_heading": "Cambios de configuración",
|
||||
"network_save_settings_failed": "No se pudo guardar la configuración de red: {error}",
|
||||
"network_save_settings_success": "Configuración de red guardada",
|
||||
"network_settings_invalid_ipv4_cidr": "Notación CIDR no válida para la dirección IPv4",
|
||||
"network_settings_add_dns": "Agregar servidor DNS",
|
||||
"network_settings_load_error": "No se pudo cargar la configuración de red: {error}",
|
||||
"network_static_ipv4_header": "Configuración estática de IPv4",
|
||||
"network_static_ipv6_header": "Configuración estática de IPv6",
|
||||
"network_time_sync_description": "Configurar los ajustes de sincronización horaria",
|
||||
"network_time_sync_http_only": "Sólo HTTP",
|
||||
"network_time_sync_ntp_and_http": "NTP y HTTP",
|
||||
|
|
@ -670,9 +682,9 @@
|
|||
"paste_modal_failed_paste": "No se pudo pegar el texto: {error}",
|
||||
"paste_modal_invalid_chars_intro": "Los siguientes caracteres no se pegarán:",
|
||||
"paste_modal_paste_from_host": "Pegar desde el host",
|
||||
"paste_modal_paste_text": "Pegar texto",
|
||||
"paste_modal_paste_text_description": "Pegue el texto de su cliente al host remoto",
|
||||
"paste_modal_sending_using_layout": "Envío de texto mediante la distribución del teclado: {iso} - {name}",
|
||||
"paste_text": "Pegar texto",
|
||||
"paste_text_description": "Pegue el texto de su cliente al host remoto",
|
||||
"peer_connection_closed": "Cerrado",
|
||||
"peer_connection_closing": "Cierre",
|
||||
"peer_connection_connected": "Conectado",
|
||||
|
|
|
|||
|
|
@ -50,7 +50,6 @@
|
|||
"action_bar_connection_stats": "Statistiques de connexion",
|
||||
"action_bar_extension": "Extension",
|
||||
"action_bar_fullscreen": "Plein écran",
|
||||
"action_bar_paste_text": "Coller du texte",
|
||||
"action_bar_settings": "Paramètres",
|
||||
"action_bar_virtual_keyboard": "Clavier virtuel",
|
||||
"action_bar_virtual_media": "Médias virtuels",
|
||||
|
|
@ -142,7 +141,6 @@
|
|||
"auth_mode_local_password_confirm_description": "Confirmez votre mot de passe",
|
||||
"auth_mode_local_password_confirm_label": "Confirmez le mot de passe",
|
||||
"auth_mode_local_password_description": "Sécurisez votre appareil avec un mot de passe pour une protection supplémentaire.",
|
||||
"auth_mode_local_password_do_not_match": "Les mots de passe ne correspondent pas",
|
||||
"auth_mode_local_password_failed_set": "Échec de la définition du mot de passe : {error}",
|
||||
"auth_mode_local_password_note": "Ce mot de passe sera utilisé pour sécuriser les données de votre appareil et les protéger contre tout accès non autorisé.",
|
||||
"auth_mode_local_password_note_local": "Toutes les données restent sur votre appareil local.",
|
||||
|
|
@ -181,6 +179,9 @@
|
|||
"connection_stats_round_trip_time": "Temps de trajet aller-retour",
|
||||
"connection_stats_round_trip_time_description": "Temps de trajet aller-retour pour la paire de candidats ICE actifs entre pairs.",
|
||||
"connection_stats_sidebar": "Statistiques de connexion",
|
||||
"connection_stats_unit_frames_per_second": " fps",
|
||||
"connection_stats_unit_milliseconds": " ms",
|
||||
"connection_stats_unit_packets": " paquets",
|
||||
"connection_stats_video": "Vidéo",
|
||||
"connection_stats_video_description": "Le flux vidéo du JetKVM vers le client.",
|
||||
"continue": "Continuer",
|
||||
|
|
@ -207,6 +208,8 @@
|
|||
"deregister_error": "Une erreur {status} s'est produite lors de l'annulation de l'enregistrement de votre appareil. Veuillez réessayer.",
|
||||
"deregister_headline": "Désinscrivez {device} de votre compte cloud",
|
||||
"detach": "Détacher",
|
||||
"dhcp_empty_lease_description": "Nous n'avons pas encore reçu d'informations sur le bail DHCP de l'appareil.",
|
||||
"dhcp_empty_lease_headline": "Aucune information sur le bail DHCP",
|
||||
"dhcp_lease_boot_file": "Fichier de démarrage",
|
||||
"dhcp_lease_boot_next_server": "Démarrer le serveur suivant",
|
||||
"dhcp_lease_boot_server_name": "Nom du serveur de démarrage",
|
||||
|
|
@ -426,7 +429,8 @@
|
|||
"macro_name_too_long": "Le nom doit comporter moins de 50 caractères",
|
||||
"macro_please_fix_validation_errors": "Veuillez corriger les erreurs de validation",
|
||||
"macro_save": "Enregistrer la macro",
|
||||
"macro_save_error": "Une erreur s'est produite lors de l'enregistrement.",
|
||||
"macro_save_failed": "Une erreur s'est produite lors de l'enregistrement.",
|
||||
"macro_save_failed_error": "Une erreur s'est produite lors de l'enregistrement: {error}.",
|
||||
"macro_step_count": "{steps} / {max} étapes",
|
||||
"macro_step_duration_description": "Il est temps d’attendre avant d’exécuter l’étape suivante.",
|
||||
"macro_step_duration_label": "Durée de l'étape",
|
||||
|
|
@ -578,7 +582,6 @@
|
|||
"network_dhcp_client_description": "Configurer le client DHCP à utiliser",
|
||||
"network_dhcp_client_jetkvm": "JetKVM interne",
|
||||
"network_dhcp_client_title": "Client DHCP",
|
||||
"network_dhcp_information": "Informations DHCP",
|
||||
"network_dhcp_lease_renew": "Renouveler le bail DHCP",
|
||||
"network_dhcp_lease_renew_confirm": "Renouveler le bail",
|
||||
"network_dhcp_lease_renew_confirm_description": "Cette opération demandera une nouvelle adresse IP à votre serveur DHCP. Votre appareil pourrait perdre temporairement sa connectivité réseau pendant cette opération.",
|
||||
|
|
@ -599,13 +602,21 @@
|
|||
"network_ipv4_address": "Adresse IPv4",
|
||||
"network_ipv4_dns": "DNS IPv4",
|
||||
"network_ipv4_gateway": "Passerelle IPv4",
|
||||
"network_ipv4_invalid": "Adresse IPv4 non valide",
|
||||
"network_ipv4_invalid_cidr": "Notation CIDR non valide pour l'adresse IPv4",
|
||||
"network_ipv4_mode_description": "Configurer le mode IPv4",
|
||||
"network_ipv4_mode_dhcp": "DHCP",
|
||||
"network_ipv4_mode_static": "Statique",
|
||||
"network_ipv4_mode_title": "Mode IPv4",
|
||||
"network_ipv4_netmask": "Masque de réseau IPv4",
|
||||
"network_ipv6_address": "Adresse IPv6",
|
||||
"network_ipv6_addresses_header": "Adresses IPv6",
|
||||
"network_ipv6_cidr_suggestion": "Veuillez utiliser la notation CIDR (par exemple, 2001:db8::1/64)",
|
||||
"network_ipv6_dns": "DNS IPv6",
|
||||
"network_ipv6_flag_dad_failed": "Papa a échoué",
|
||||
"network_ipv6_flag_deprecated": "Obsolète",
|
||||
"network_ipv6_gateway": "Passerelle IPv6",
|
||||
"network_ipv6_information": "Informations IPv6",
|
||||
"network_ipv6_invalid": "Adresse IPv6 non valide",
|
||||
"network_ipv6_mode_description": "Configurer le mode IPv6",
|
||||
"network_ipv6_mode_dhcpv6": "DHCPv6",
|
||||
"network_ipv6_mode_disabled": "Désactivé",
|
||||
|
|
@ -614,8 +625,8 @@
|
|||
"network_ipv6_mode_slaac_dhcpv6": "SLAAC + DHCPv6",
|
||||
"network_ipv6_mode_static": "Statique",
|
||||
"network_ipv6_mode_title": "Mode IPv6",
|
||||
"network_ipv6_netmask": "Masque de réseau IPv6",
|
||||
"network_ipv6_no_addresses": "Aucune adresse IPv6 configurée",
|
||||
"network_ipv6_prefix": "Préfixe IP",
|
||||
"network_ipv6_prefix_invalid": "Le préfixe doit être compris entre 0 et 128",
|
||||
"network_ll_dp_all": "Tous",
|
||||
"network_ll_dp_basic": "Basique",
|
||||
"network_ll_dp_description": "Contrôler les TLV qui seront envoyés via le protocole Link Layer Discovery",
|
||||
|
|
@ -631,7 +642,6 @@
|
|||
"network_mdns_ipv4_only": "IPv4 uniquement",
|
||||
"network_mdns_ipv6_only": "IPv6 uniquement",
|
||||
"network_mdns_title": "mDNS",
|
||||
"network_no_dhcp_lease": "Aucune information de bail DHCP disponible",
|
||||
"network_no_information_description": "Aucune configuration réseau disponible",
|
||||
"network_no_information_headline": "Informations sur le réseau",
|
||||
"network_pending_dhcp_mode_change_description": "Enregistrer les paramètres pour activer le mode DHCP et afficher les informations de bail",
|
||||
|
|
@ -643,8 +653,10 @@
|
|||
"network_save_settings_confirm_heading": "Modifications de configuration",
|
||||
"network_save_settings_failed": "Échec de l'enregistrement des paramètres réseau : {error}",
|
||||
"network_save_settings_success": "Paramètres réseau enregistrés",
|
||||
"network_settings_invalid_ipv4_cidr": "Notation CIDR non valide pour l'adresse IPv4",
|
||||
"network_settings_add_dns": "Ajouter un serveur DNS",
|
||||
"network_settings_load_error": "Échec du chargement des paramètres réseau : {error}",
|
||||
"network_static_ipv4_header": "Configuration IPv4 statique",
|
||||
"network_static_ipv6_header": "Configuration IPv6 statique",
|
||||
"network_time_sync_description": "Configurer les paramètres de synchronisation de l'heure",
|
||||
"network_time_sync_http_only": "HTTP uniquement",
|
||||
"network_time_sync_ntp_and_http": "NTP et HTTP",
|
||||
|
|
@ -670,9 +682,9 @@
|
|||
"paste_modal_failed_paste": "Échec du collage du texte : {error}",
|
||||
"paste_modal_invalid_chars_intro": "Les caractères suivants ne seront pas collés :",
|
||||
"paste_modal_paste_from_host": "Coller depuis l'hôte",
|
||||
"paste_modal_paste_text": "Coller du texte",
|
||||
"paste_modal_paste_text_description": "Collez le texte de votre client sur l'hôte distant",
|
||||
"paste_modal_sending_using_layout": "Envoi de texte à l'aide de la disposition du clavier : {iso} - {name}",
|
||||
"paste_text": "Coller du texte",
|
||||
"paste_text_description": "Collez le texte de votre client sur l'hôte distant",
|
||||
"peer_connection_closed": "Fermé",
|
||||
"peer_connection_closing": "Clôture",
|
||||
"peer_connection_connected": "Connecté",
|
||||
|
|
|
|||
|
|
@ -50,7 +50,6 @@
|
|||
"action_bar_connection_stats": "Statistiche di connessione",
|
||||
"action_bar_extension": "Estensione",
|
||||
"action_bar_fullscreen": "A schermo intero",
|
||||
"action_bar_paste_text": "Incolla il testo",
|
||||
"action_bar_settings": "Impostazioni",
|
||||
"action_bar_virtual_keyboard": "Tastiera virtuale",
|
||||
"action_bar_virtual_media": "Media virtuali",
|
||||
|
|
@ -142,7 +141,6 @@
|
|||
"auth_mode_local_password_confirm_description": "Conferma la tua password",
|
||||
"auth_mode_local_password_confirm_label": "Conferma password",
|
||||
"auth_mode_local_password_description": "Per una maggiore protezione, proteggi il tuo dispositivo con una password.",
|
||||
"auth_mode_local_password_do_not_match": "Le password non corrispondono",
|
||||
"auth_mode_local_password_failed_set": "Impossibile impostare la password: {error}",
|
||||
"auth_mode_local_password_note": "Questa password verrà utilizzata per proteggere i dati del tuo dispositivo e proteggerli da accessi non autorizzati.",
|
||||
"auth_mode_local_password_note_local": "Tutti i dati rimangono sul tuo dispositivo locale.",
|
||||
|
|
@ -181,6 +179,9 @@
|
|||
"connection_stats_round_trip_time": "Tempo di andata e ritorno",
|
||||
"connection_stats_round_trip_time_description": "Tempo di andata e ritorno per la coppia di candidati ICE attivi tra pari.",
|
||||
"connection_stats_sidebar": "Statistiche di connessione",
|
||||
"connection_stats_unit_frames_per_second": " fps",
|
||||
"connection_stats_unit_milliseconds": " ms",
|
||||
"connection_stats_unit_packets": " pacchetti",
|
||||
"connection_stats_video": "Video",
|
||||
"connection_stats_video_description": "Il flusso video dal JetKVM al client.",
|
||||
"continue": "Continuare",
|
||||
|
|
@ -207,6 +208,8 @@
|
|||
"deregister_error": "Si è verificato un errore {status} durante l'annullamento della registrazione del dispositivo. Riprova.",
|
||||
"deregister_headline": "Annulla la registrazione di {device} dal tuo account cloud",
|
||||
"detach": "Staccare",
|
||||
"dhcp_empty_lease_description": "Non abbiamo ancora ricevuto alcuna informazione di lease DHCP dal dispositivo.",
|
||||
"dhcp_empty_lease_headline": "Nessuna informazione sul lease DHCP",
|
||||
"dhcp_lease_boot_file": "File di avvio",
|
||||
"dhcp_lease_boot_next_server": "Avvia il server successivo",
|
||||
"dhcp_lease_boot_server_name": "Nome del server di avvio",
|
||||
|
|
@ -426,7 +429,8 @@
|
|||
"macro_name_too_long": "Il nome deve contenere meno di 50 caratteri",
|
||||
"macro_please_fix_validation_errors": "Si prega di correggere gli errori di convalida",
|
||||
"macro_save": "Salva macro",
|
||||
"macro_save_error": "Si è verificato un errore durante il salvataggio.",
|
||||
"macro_save_failed": "Si è verificato un errore durante il salvataggio.",
|
||||
"macro_save_failed_error": "Si è verificato un errore durante il salvataggio: {error}.",
|
||||
"macro_step_count": "{steps} / {max} steps",
|
||||
"macro_step_duration_description": "Tempo di attesa prima di eseguire il passaggio successivo.",
|
||||
"macro_step_duration_label": "Durata del passo",
|
||||
|
|
@ -578,7 +582,6 @@
|
|||
"network_dhcp_client_description": "Configurare quale client DHCP utilizzare",
|
||||
"network_dhcp_client_jetkvm": "JetKVM interno",
|
||||
"network_dhcp_client_title": "Cliente DHCP",
|
||||
"network_dhcp_information": "Informazioni DHCP",
|
||||
"network_dhcp_lease_renew": "Rinnova il contratto di locazione DHCP",
|
||||
"network_dhcp_lease_renew_confirm": "Rinnovare il contratto di locazione",
|
||||
"network_dhcp_lease_renew_confirm_description": "Verrà richiesto un nuovo indirizzo IP al server DHCP. Durante questo processo, il dispositivo potrebbe perdere temporaneamente la connettività di rete.",
|
||||
|
|
@ -599,13 +602,21 @@
|
|||
"network_ipv4_address": "Indirizzo IPv4",
|
||||
"network_ipv4_dns": "DNS IPv4",
|
||||
"network_ipv4_gateway": "Gateway IPv4",
|
||||
"network_ipv4_invalid": "Indirizzo IPv4 non valido",
|
||||
"network_ipv4_invalid_cidr": "Notazione CIDR non valida per l'indirizzo IPv4",
|
||||
"network_ipv4_mode_description": "Configurare la modalità IPv4",
|
||||
"network_ipv4_mode_dhcp": "DHCP",
|
||||
"network_ipv4_mode_static": "Statico",
|
||||
"network_ipv4_mode_title": "Modalità IPv4",
|
||||
"network_ipv4_netmask": "Maschera di rete IPv4",
|
||||
"network_ipv6_address": "Indirizzo IPv6",
|
||||
"network_ipv6_addresses_header": "Indirizzi IPv6",
|
||||
"network_ipv6_cidr_suggestion": "Si prega di utilizzare la notazione CIDR (ad esempio, 2001:db8::1/64)",
|
||||
"network_ipv6_dns": "DNS IPv6",
|
||||
"network_ipv6_flag_dad_failed": "DAD fallito",
|
||||
"network_ipv6_flag_deprecated": "Obsoleto",
|
||||
"network_ipv6_gateway": "Gateway IPv6",
|
||||
"network_ipv6_information": "Informazioni IPv6",
|
||||
"network_ipv6_invalid": "Indirizzo IPv6 non valido",
|
||||
"network_ipv6_mode_description": "Configurare la modalità IPv6",
|
||||
"network_ipv6_mode_dhcpv6": "DHCPv6",
|
||||
"network_ipv6_mode_disabled": "Disabili",
|
||||
|
|
@ -614,8 +625,8 @@
|
|||
"network_ipv6_mode_slaac_dhcpv6": "SLAAC + DHCPv6",
|
||||
"network_ipv6_mode_static": "Statico",
|
||||
"network_ipv6_mode_title": "Modalità IPv6",
|
||||
"network_ipv6_netmask": "Maschera di rete IPv6",
|
||||
"network_ipv6_no_addresses": "Nessun indirizzo IPv6 configurato",
|
||||
"network_ipv6_prefix": "Prefisso IP",
|
||||
"network_ipv6_prefix_invalid": "Il prefisso deve essere compreso tra 0 e 128",
|
||||
"network_ll_dp_all": "Tutto",
|
||||
"network_ll_dp_basic": "Di base",
|
||||
"network_ll_dp_description": "Controlla quali TLV verranno inviati tramite Link Layer Discovery Protocol",
|
||||
|
|
@ -631,7 +642,6 @@
|
|||
"network_mdns_ipv4_only": "Solo IPv4",
|
||||
"network_mdns_ipv6_only": "Solo IPv6",
|
||||
"network_mdns_title": "mDNS",
|
||||
"network_no_dhcp_lease": "Nessuna informazione disponibile sul lease DHCP",
|
||||
"network_no_information_description": "Nessuna configurazione di rete disponibile",
|
||||
"network_no_information_headline": "Informazioni di rete",
|
||||
"network_pending_dhcp_mode_change_description": "Salva le impostazioni per abilitare la modalità DHCP e visualizzare le informazioni di locazione",
|
||||
|
|
@ -643,8 +653,10 @@
|
|||
"network_save_settings_confirm_heading": "Modifiche alla configurazione",
|
||||
"network_save_settings_failed": "Impossibile salvare le impostazioni di rete: {error}",
|
||||
"network_save_settings_success": "Impostazioni di rete salvate",
|
||||
"network_settings_invalid_ipv4_cidr": "Notazione CIDR non valida per l'indirizzo IPv4",
|
||||
"network_settings_add_dns": "Aggiungi server DNS",
|
||||
"network_settings_load_error": "Impossibile caricare le impostazioni di rete: {error}",
|
||||
"network_static_ipv4_header": "Configurazione IPv4 statica",
|
||||
"network_static_ipv6_header": "Configurazione IPv6 statica",
|
||||
"network_time_sync_description": "Configurare le impostazioni di sincronizzazione dell'ora",
|
||||
"network_time_sync_http_only": "Solo HTTP",
|
||||
"network_time_sync_ntp_and_http": "NTP e HTTP",
|
||||
|
|
@ -670,9 +682,9 @@
|
|||
"paste_modal_failed_paste": "Impossibile incollare il testo: {error}",
|
||||
"paste_modal_invalid_chars_intro": "I seguenti caratteri non verranno incollati:",
|
||||
"paste_modal_paste_from_host": "Incolla dall'host",
|
||||
"paste_modal_paste_text": "Incolla il testo",
|
||||
"paste_modal_paste_text_description": "Incolla il testo dal tuo client all'host remoto",
|
||||
"paste_modal_sending_using_layout": "Invio di testo tramite layout di tastiera: {iso} - {name}",
|
||||
"paste_text": "Incolla il testo",
|
||||
"paste_text_description": "Incolla il testo dal tuo client all'host remoto",
|
||||
"peer_connection_closed": "Chiuso",
|
||||
"peer_connection_closing": "Chiusura",
|
||||
"peer_connection_connected": "Collegato",
|
||||
|
|
|
|||
|
|
@ -31,7 +31,7 @@
|
|||
"access_no_device_id": "Ingen enhets-ID tilgjengelig",
|
||||
"access_private_key_description": "Av sikkerhetshensyn vil den ikke vises etter lagring.",
|
||||
"access_private_key_label": "Privat nøkkel",
|
||||
"access_provider_custom": "Skikk",
|
||||
"access_provider_custom": "Tilpasset",
|
||||
"access_provider_jetkvm": "JetKVM Cloud",
|
||||
"access_remote_description": "Administrer modusen for ekstern tilgang til enheten",
|
||||
"access_security_encryption": "Ende-til-ende-kryptering ved bruk av WebRTC (DTLS og SRTP)",
|
||||
|
|
@ -42,15 +42,14 @@
|
|||
"access_title": "Adgang",
|
||||
"access_tls_certificate_description": "Lim inn TLS-sertifikatet ditt nedenfor. For sertifikatkjeder, inkluder hele kjeden (blad-, mellom- og rotsertifikater).",
|
||||
"access_tls_certificate_title": "TLS-sertifikat",
|
||||
"access_tls_custom": "Skikk",
|
||||
"access_tls_disabled": "Funksjonshemmet",
|
||||
"access_tls_custom": "Tilpasset",
|
||||
"access_tls_disabled": "Deaktivert",
|
||||
"access_tls_self_signed": "Selvsignert",
|
||||
"access_tls_updated": "TLS-innstillingene er oppdatert",
|
||||
"access_update_tls_settings": "Oppdater TLS-innstillinger",
|
||||
"action_bar_connection_stats": "Tilkoblingsstatistikk",
|
||||
"action_bar_extension": "Forlengelse",
|
||||
"action_bar_fullscreen": "Fullskjerm",
|
||||
"action_bar_paste_text": "Lim inn tekst",
|
||||
"action_bar_settings": "Innstillinger",
|
||||
"action_bar_virtual_keyboard": "Virtuelt tastatur",
|
||||
"action_bar_virtual_media": "Virtuelle medier",
|
||||
|
|
@ -116,7 +115,7 @@
|
|||
"atx_power_control_get_state_error": "Klarte ikke å hente ATX-strømstatus: {error}",
|
||||
"atx_power_control_hdd_led": "HDD-LED",
|
||||
"atx_power_control_long_power_button": "Langt trykk",
|
||||
"atx_power_control_power_button": "Makt",
|
||||
"atx_power_control_power_button": "Strøm",
|
||||
"atx_power_control_power_led": "Strøm-LED",
|
||||
"atx_power_control_reset_button": "Tilbakestill",
|
||||
"atx_power_control_send_action_error": "Kunne ikke sende ATX-strømhandling {action} : {error}",
|
||||
|
|
@ -142,7 +141,6 @@
|
|||
"auth_mode_local_password_confirm_description": "Bekreft passordet ditt",
|
||||
"auth_mode_local_password_confirm_label": "Bekreft passord",
|
||||
"auth_mode_local_password_description": "Sikre enheten din med et passord for ekstra beskyttelse.",
|
||||
"auth_mode_local_password_do_not_match": "Passordene stemmer ikke overens",
|
||||
"auth_mode_local_password_failed_set": "Klarte ikke å angi passord: {error}",
|
||||
"auth_mode_local_password_note": "Dette passordet vil bli brukt til å sikre enhetsdataene dine og beskytte mot uautorisert tilgang.",
|
||||
"auth_mode_local_password_note_local": "Alle dataene forblir på din lokale enhet.",
|
||||
|
|
@ -156,8 +154,8 @@
|
|||
"auth_signup_create_account_description": "Opprett kontoen din og begynn å administrere enhetene dine med letthet.",
|
||||
"back": "Tilbake",
|
||||
"back_to_devices": "Tilbake til Enheter",
|
||||
"cancel": "Kansellere",
|
||||
"close": "Lukke",
|
||||
"cancel": "Avbryt",
|
||||
"close": "Lukk",
|
||||
"cloud_kvms": "Cloud KVM-er",
|
||||
"cloud_kvms_description": "Administrer skybaserte KVM-er og koble til dem sikkert.",
|
||||
"cloud_kvms_no_devices": "Ingen enheter funnet",
|
||||
|
|
@ -181,6 +179,9 @@
|
|||
"connection_stats_round_trip_time": "Tur-retur-tid",
|
||||
"connection_stats_round_trip_time_description": "Rundturstid for det aktive ICE-kandidatparet mellom jevnaldrende.",
|
||||
"connection_stats_sidebar": "Tilkoblingsstatistikk",
|
||||
"connection_stats_unit_frames_per_second": " fps",
|
||||
"connection_stats_unit_milliseconds": " ms",
|
||||
"connection_stats_unit_packets": " pakker",
|
||||
"connection_stats_video": "Video",
|
||||
"connection_stats_video_description": "Videostrømmen fra JetKVM til klienten.",
|
||||
"continue": "Fortsette",
|
||||
|
|
@ -188,7 +189,7 @@
|
|||
"dc_power_control_current": "Nåværende",
|
||||
"dc_power_control_current_unit": "EN",
|
||||
"dc_power_control_get_state_error": "Klarte ikke å hente likestrømsstatus: {error}",
|
||||
"dc_power_control_power": "Makt",
|
||||
"dc_power_control_power": "Strøm",
|
||||
"dc_power_control_power_off_button": "Slå av",
|
||||
"dc_power_control_power_off_state": "Slå av",
|
||||
"dc_power_control_power_on_button": "Slå på",
|
||||
|
|
@ -207,6 +208,8 @@
|
|||
"deregister_error": "Det oppsto en feil {status} enheten din skulle avregistreres. Prøv på nytt.",
|
||||
"deregister_headline": "Avregistrer {device} fra skykontoen din",
|
||||
"detach": "Løsne",
|
||||
"dhcp_empty_lease_description": "Vi har ikke mottatt noen DHCP-leaseinformasjon fra enheten ennå.",
|
||||
"dhcp_empty_lease_headline": "Ingen DHCP-leaseinformasjon",
|
||||
"dhcp_lease_boot_file": "Oppstartsfil",
|
||||
"dhcp_lease_boot_next_server": "Start opp neste server",
|
||||
"dhcp_lease_boot_server_name": "Navn på oppstartsserver",
|
||||
|
|
@ -371,7 +374,7 @@
|
|||
"local_auth_create_new_password_label": "Nytt passord",
|
||||
"local_auth_create_new_password_placeholder": "Skriv inn et sterkt passord",
|
||||
"local_auth_create_not_now_button": "Ikke nå",
|
||||
"local_auth_create_secure_button": "Sikker enhet",
|
||||
"local_auth_create_secure_button": "Sikre enheten",
|
||||
"local_auth_create_title": "Lokal enhetsbeskyttelse",
|
||||
"local_auth_current_password_label": "Nåværende passord",
|
||||
"local_auth_disable_local_device_protection_description": "Skriv inn ditt nåværende passord for å deaktivere lokal enhetsbeskyttelse.",
|
||||
|
|
@ -396,7 +399,7 @@
|
|||
"local_auth_success_password_updated_description": "Du har endret passordet for beskyttelse av den lokale enheten. Husk det nye passordet for fremtidig tilgang.",
|
||||
"local_auth_success_password_updated_title": "Passord oppdatert",
|
||||
"local_auth_update_password_button": "Oppdater passord",
|
||||
"locale_auto": "Bil",
|
||||
"locale_auto": "Auto",
|
||||
"locale_change_success": "Språket er endret til {locale}",
|
||||
"locale_da": "Dansk",
|
||||
"locale_de": "Tysk",
|
||||
|
|
@ -426,7 +429,8 @@
|
|||
"macro_name_too_long": "Navnet må være mindre enn 50 tegn",
|
||||
"macro_please_fix_validation_errors": "Vennligst rett opp valideringsfeilene",
|
||||
"macro_save": "Lagre makro",
|
||||
"macro_save_error": "Det oppsto en feil under lagring.",
|
||||
"macro_save_failed": "Det oppsto en feil under lagring.",
|
||||
"macro_save_failed_error": "Det oppsto en feil under lagring: {error}.",
|
||||
"macro_step_count": "{steps} / {max} trinn",
|
||||
"macro_step_duration_description": "Tid for å vente før man tar neste steg.",
|
||||
"macro_step_duration_label": "Stegvarighet",
|
||||
|
|
@ -549,9 +553,9 @@
|
|||
"mouse_hide_cursor_description": "Skjul markøren når du sender musebevegelser",
|
||||
"mouse_hide_cursor_title": "Skjul markør",
|
||||
"mouse_jiggler_config_updated": "Jiggler-konfigurasjonen er oppdatert",
|
||||
"mouse_jiggler_custom": "Skikk",
|
||||
"mouse_jiggler_custom": "Tilpasset",
|
||||
"mouse_jiggler_description": "Simuler bevegelsen til en datamus",
|
||||
"mouse_jiggler_disabled": "Funksjonshemmet",
|
||||
"mouse_jiggler_disabled": "Deaktivert",
|
||||
"mouse_jiggler_error_config": "Det oppsto en feil under innstilling av jiggler-konfigurasjonen",
|
||||
"mouse_jiggler_failed_state": "Klarte ikke å angi jiggler-tilstand: {error}",
|
||||
"mouse_jiggler_frequent": "Hyppig - 30-tallet",
|
||||
|
|
@ -578,7 +582,6 @@
|
|||
"network_dhcp_client_description": "Konfigurer hvilken DHCP-klient som skal brukes",
|
||||
"network_dhcp_client_jetkvm": "JetKVM intern",
|
||||
"network_dhcp_client_title": "DHCP-klient",
|
||||
"network_dhcp_information": "DHCP-informasjon",
|
||||
"network_dhcp_lease_renew": "Forny DHCP-leieavtale",
|
||||
"network_dhcp_lease_renew_confirm": "Forny leieavtalen",
|
||||
"network_dhcp_lease_renew_confirm_description": "Dette vil be om en ny IP-adresse fra DHCP-serveren din. Enheten din kan midlertidig miste nettverkstilkoblingen under denne prosessen.",
|
||||
|
|
@ -586,7 +589,7 @@
|
|||
"network_dhcp_lease_renew_confirm_new_b": "du må kanskje koble til på nytt med den nye adressen",
|
||||
"network_dhcp_lease_renew_failed": "Kunne ikke fornye leieavtalen: {error}",
|
||||
"network_dhcp_lease_renew_success": "DHCP-leieavtale fornyet",
|
||||
"network_domain_custom": "Skikk",
|
||||
"network_domain_custom": "Tilpasset",
|
||||
"network_domain_description": "Nettverksdomenesuffiks for enheten",
|
||||
"network_domain_dhcp_provided": "DHCP levert",
|
||||
"network_domain_local": ".lokal",
|
||||
|
|
@ -599,39 +602,46 @@
|
|||
"network_ipv4_address": "IPv4-adresse",
|
||||
"network_ipv4_dns": "IPv4 DNS",
|
||||
"network_ipv4_gateway": "IPv4-gateway",
|
||||
"network_ipv4_invalid": "Ugyldig IPv4-adresse",
|
||||
"network_ipv4_invalid_cidr": "Ugyldig CIDR-notasjon for IPv4-adresse",
|
||||
"network_ipv4_mode_description": "Konfigurer IPv4-modusen",
|
||||
"network_ipv4_mode_dhcp": "DHCP",
|
||||
"network_ipv4_mode_static": "Statisk",
|
||||
"network_ipv4_mode_title": "IPv4-modus",
|
||||
"network_ipv4_netmask": "IPv4-nettmaske",
|
||||
"network_ipv6_address": "IPv6-adresse",
|
||||
"network_ipv6_addresses_header": "IPv6-adresser",
|
||||
"network_ipv6_cidr_suggestion": "Vennligst bruk CIDR-notasjon (f.eks. 2001:db8::1/64)",
|
||||
"network_ipv6_dns": "IPv6 DNS",
|
||||
"network_ipv6_flag_dad_failed": "DAD mislyktes",
|
||||
"network_ipv6_flag_deprecated": "Utdatert",
|
||||
"network_ipv6_gateway": "IPv6-gateway",
|
||||
"network_ipv6_information": "IPv6-informasjon",
|
||||
"network_ipv6_invalid": "Ugyldig IPv6-adresse",
|
||||
"network_ipv6_mode_description": "Konfigurer IPv6-modusen",
|
||||
"network_ipv6_mode_dhcpv6": "DHCPv6",
|
||||
"network_ipv6_mode_disabled": "Funksjonshemmet",
|
||||
"network_ipv6_mode_disabled": "Deaktivert",
|
||||
"network_ipv6_mode_link_local": "Kun lenkelokal",
|
||||
"network_ipv6_mode_slaac": "SLAAC",
|
||||
"network_ipv6_mode_slaac_dhcpv6": "SLAAC + DHCPv6",
|
||||
"network_ipv6_mode_static": "Statisk",
|
||||
"network_ipv6_mode_title": "IPv6-modus",
|
||||
"network_ipv6_netmask": "IPv6-nettmaske",
|
||||
"network_ipv6_no_addresses": "Ingen IPv6-adresser konfigurert",
|
||||
"network_ipv6_prefix": "IP-prefiks",
|
||||
"network_ipv6_prefix_invalid": "Prefikset må være mellom 0 og 128",
|
||||
"network_ll_dp_all": "Alle",
|
||||
"network_ll_dp_basic": "Grunnleggende",
|
||||
"network_ll_dp_description": "Kontroller hvilke TLV-er som skal sendes over Link Layer Discovery Protocol",
|
||||
"network_ll_dp_disabled": "Funksjonshemmet",
|
||||
"network_ll_dp_disabled": "Deaktivert",
|
||||
"network_ll_dp_title": "LLDP",
|
||||
"network_mac_address_copy_error": "Kunne ikke kopiere MAC-adressen",
|
||||
"network_mac_address_copy_success": "MAC-adresse { mac } kopiert til utklippstavlen",
|
||||
"network_mac_address_description": "Maskinvareidentifikator for nettverksgrensesnittet",
|
||||
"network_mac_address_title": "MAC-adresse",
|
||||
"network_mdns_auto": "Bil",
|
||||
"network_mdns_auto": "Auto",
|
||||
"network_mdns_description": "Kontrollmodus for mDNS (multicast DNS)",
|
||||
"network_mdns_disabled": "Funksjonshemmet",
|
||||
"network_mdns_disabled": "Deaktivert",
|
||||
"network_mdns_ipv4_only": "Kun IPv4",
|
||||
"network_mdns_ipv6_only": "Kun IPv6",
|
||||
"network_mdns_title": "mDNS",
|
||||
"network_no_dhcp_lease": "Ingen DHCP-leaseinformasjon tilgjengelig",
|
||||
"network_no_information_description": "Ingen nettverkskonfigurasjon tilgjengelig",
|
||||
"network_no_information_headline": "Nettverksinformasjon",
|
||||
"network_pending_dhcp_mode_change_description": "Lagre innstillinger for å aktivere DHCP-modus og vise leieavtaleinformasjon",
|
||||
|
|
@ -643,8 +653,10 @@
|
|||
"network_save_settings_confirm_heading": "Konfigurasjonsendringer",
|
||||
"network_save_settings_failed": "Kunne ikke lagre nettverksinnstillinger: {error}",
|
||||
"network_save_settings_success": "Nettverksinnstillinger lagret",
|
||||
"network_settings_invalid_ipv4_cidr": "Ugyldig CIDR-notasjon for IPv4-adresse",
|
||||
"network_settings_add_dns": "Legg til DNS-server",
|
||||
"network_settings_load_error": "Kunne ikke laste inn nettverksinnstillinger: {error}",
|
||||
"network_static_ipv4_header": "Statisk IPv4-konfigurasjon",
|
||||
"network_static_ipv6_header": "Statisk IPv6-konfigurasjon",
|
||||
"network_time_sync_description": "Konfigurer innstillinger for tidssynkronisering",
|
||||
"network_time_sync_http_only": "Kun HTTP",
|
||||
"network_time_sync_ntp_and_http": "NTP og HTTP",
|
||||
|
|
@ -670,9 +682,9 @@
|
|||
"paste_modal_failed_paste": "Klarte ikke å lime inn tekst: {error}",
|
||||
"paste_modal_invalid_chars_intro": "Følgende tegn vil ikke bli limt inn:",
|
||||
"paste_modal_paste_from_host": "Lim inn fra verten",
|
||||
"paste_modal_paste_text": "Lim inn tekst",
|
||||
"paste_modal_paste_text_description": "Lim inn tekst fra klienten din til den eksterne verten",
|
||||
"paste_modal_sending_using_layout": "Sende tekst ved hjelp av tastaturoppsett: {iso} - {name}",
|
||||
"paste_text": "Lim inn tekst",
|
||||
"paste_text_description": "Lim inn tekst fra klienten din til den eksterne verten",
|
||||
"peer_connection_closed": "Lukket",
|
||||
"peer_connection_closing": "Lukking",
|
||||
"peer_connection_connected": "Tilkoblet",
|
||||
|
|
@ -743,7 +755,7 @@
|
|||
"updates_failed_get_device_version": "Klarte ikke å hente enhetsversjon: {error}",
|
||||
"updating_leave_device_on": "Vennligst ikke slå av enheten din ...",
|
||||
"usb": "USB",
|
||||
"usb_config_custom": "Skikk",
|
||||
"usb_config_custom": "Tilpasset",
|
||||
"usb_config_default": "JetKVM-standard",
|
||||
"usb_config_dell": "Dell Multimedia Pro-tastatur",
|
||||
"usb_config_failed_load": "Klarte ikke å laste inn USB-konfigurasjon: {error}",
|
||||
|
|
@ -767,7 +779,7 @@
|
|||
"usb_config_vendor_id_placeholder": "Skriv inn leverandør-ID",
|
||||
"usb_device_classes_description": "USB-enhetsklasser i den sammensatte enheten",
|
||||
"usb_device_classes_title": "Klasser",
|
||||
"usb_device_custom": "Skikk",
|
||||
"usb_device_custom": "Tilpasset",
|
||||
"usb_device_description": "USB-enheter som skal emuleres på måldatamaskinen",
|
||||
"usb_device_enable_absolute_mouse_description": "Aktiver absolutt mus (peker)",
|
||||
"usb_device_enable_absolute_mouse_title": "Aktiver absolutt mus (peker)",
|
||||
|
|
@ -802,7 +814,7 @@
|
|||
"video_description": "Konfigurer skjerminnstillinger og EDID for optimal kompatibilitet",
|
||||
"video_edid_acer_b246wl": "Acer B246WL, 1920x1200",
|
||||
"video_edid_asus_pa248qv": "ASUS PA248QV, 1920x1200",
|
||||
"video_edid_custom": "Skikk",
|
||||
"video_edid_custom": "Tilpasset",
|
||||
"video_edid_dell_d2721h": "DELL D2721H, 1920x1080",
|
||||
"video_edid_dell_idrac": "DELL IDRAC EDID, 1280x1024",
|
||||
"video_edid_description": "Juster EDID-innstillingene for skjermen",
|
||||
|
|
|
|||
|
|
@ -31,7 +31,7 @@
|
|||
"access_no_device_id": "Inget enhets-ID tillgängligt",
|
||||
"access_private_key_description": "Av säkerhetsskäl kommer den inte att visas efter att den har sparats.",
|
||||
"access_private_key_label": "Privat nyckel",
|
||||
"access_provider_custom": "Beställnings",
|
||||
"access_provider_custom": "Anpassad",
|
||||
"access_provider_jetkvm": "JetKVM-molnet",
|
||||
"access_remote_description": "Hantera läget för fjärråtkomst till enheten",
|
||||
"access_security_encryption": "End-to-end-kryptering med WebRTC (DTLS och SRTP)",
|
||||
|
|
@ -42,15 +42,14 @@
|
|||
"access_title": "Tillträde",
|
||||
"access_tls_certificate_description": "Klistra in ditt TLS-certifikat nedan. För certifikatkedjor, inkludera hela kedjan (löv-, mellan- och rotcertifikat).",
|
||||
"access_tls_certificate_title": "TLS-certifikat",
|
||||
"access_tls_custom": "Beställnings",
|
||||
"access_tls_disabled": "Funktionshindrad",
|
||||
"access_tls_custom": "Anpassad",
|
||||
"access_tls_disabled": "Inaktiverad",
|
||||
"access_tls_self_signed": "Självsignerad",
|
||||
"access_tls_updated": "TLS-inställningarna har uppdaterats",
|
||||
"access_update_tls_settings": "Uppdatera TLS-inställningar",
|
||||
"action_bar_connection_stats": "Anslutningsstatistik",
|
||||
"action_bar_extension": "Förlängning",
|
||||
"action_bar_fullscreen": "Helskärm",
|
||||
"action_bar_paste_text": "Klistra in text",
|
||||
"action_bar_settings": "Inställningar",
|
||||
"action_bar_virtual_keyboard": "Virtuellt tangentbord",
|
||||
"action_bar_virtual_media": "Virtuella medier",
|
||||
|
|
@ -142,7 +141,6 @@
|
|||
"auth_mode_local_password_confirm_description": "Bekräfta ditt lösenord",
|
||||
"auth_mode_local_password_confirm_label": "Bekräfta lösenord",
|
||||
"auth_mode_local_password_description": "Säkra din enhet med ett lösenord för extra skydd.",
|
||||
"auth_mode_local_password_do_not_match": "Lösenorden matchar inte",
|
||||
"auth_mode_local_password_failed_set": "Misslyckades med att ange lösenord: {error}",
|
||||
"auth_mode_local_password_note": "Detta lösenord kommer att användas för att säkra dina enhetsdata och skydda mot obehörig åtkomst.",
|
||||
"auth_mode_local_password_note_local": "All data finns kvar på din lokala enhet.",
|
||||
|
|
@ -156,8 +154,8 @@
|
|||
"auth_signup_create_account_description": "Skapa ditt konto och börja enkelt hantera dina enheter.",
|
||||
"back": "Tillbaka",
|
||||
"back_to_devices": "Tillbaka till Enheter",
|
||||
"cancel": "Avboka",
|
||||
"close": "Nära",
|
||||
"cancel": "Avbryt",
|
||||
"close": "Stäng",
|
||||
"cloud_kvms": "Moln-KVM:er",
|
||||
"cloud_kvms_description": "Hantera dina moln-KVM:er och anslut till dem säkert.",
|
||||
"cloud_kvms_no_devices": "Inga enheter hittades",
|
||||
|
|
@ -181,6 +179,9 @@
|
|||
"connection_stats_round_trip_time": "Tur- och returtid",
|
||||
"connection_stats_round_trip_time_description": "Tur- och returtid för det aktiva ICE-kandidatparet mellan peers.",
|
||||
"connection_stats_sidebar": "Anslutningsstatistik",
|
||||
"connection_stats_unit_frames_per_second": " fps",
|
||||
"connection_stats_unit_milliseconds": " ms",
|
||||
"connection_stats_unit_packets": " paket",
|
||||
"connection_stats_video": "Video",
|
||||
"connection_stats_video_description": "Videoströmmen från JetKVM till klienten.",
|
||||
"continue": "Fortsätta",
|
||||
|
|
@ -207,6 +208,8 @@
|
|||
"deregister_error": "Det uppstod ett fel {status} enheten avregistrerades. Försök igen.",
|
||||
"deregister_headline": "Avregistrera {device} från ditt molnkonto",
|
||||
"detach": "Lösgöra",
|
||||
"dhcp_empty_lease_description": "Vi har inte mottagit någon DHCP-leaseinformation från enheten ännu.",
|
||||
"dhcp_empty_lease_headline": "Ingen DHCP-leaseinformation",
|
||||
"dhcp_lease_boot_file": "Startfil",
|
||||
"dhcp_lease_boot_next_server": "Starta nästa server",
|
||||
"dhcp_lease_boot_server_name": "Namn på startserver",
|
||||
|
|
@ -371,7 +374,7 @@
|
|||
"local_auth_create_new_password_label": "Nytt lösenord",
|
||||
"local_auth_create_new_password_placeholder": "Ange ett starkt lösenord",
|
||||
"local_auth_create_not_now_button": "Inte nu",
|
||||
"local_auth_create_secure_button": "Säker enhet",
|
||||
"local_auth_create_secure_button": "Säkra enheten",
|
||||
"local_auth_create_title": "Lokalt enhetsskydd",
|
||||
"local_auth_current_password_label": "Nuvarande lösenord",
|
||||
"local_auth_disable_local_device_protection_description": "Ange ditt nuvarande lösenord för att inaktivera lokalt enhetsskydd.",
|
||||
|
|
@ -396,14 +399,14 @@
|
|||
"local_auth_success_password_updated_description": "Du har ändrat ditt lösenord för lokal enhetsskydd. Se till att komma ihåg ditt nya lösenord för framtida åtkomst.",
|
||||
"local_auth_success_password_updated_title": "Lösenordet har uppdaterats",
|
||||
"local_auth_update_password_button": "Uppdatera lösenord",
|
||||
"locale_auto": "Bil",
|
||||
"locale_auto": "Auto",
|
||||
"locale_change_success": "Språket har ändrats till {locale}",
|
||||
"locale_da": "Danska",
|
||||
"locale_de": "Deutsch",
|
||||
"locale_de": "Tyska",
|
||||
"locale_en": "Engelska",
|
||||
"locale_es": "Spanska",
|
||||
"locale_fr": "Franska",
|
||||
"locale_it": "italiensk",
|
||||
"locale_it": "Italienska",
|
||||
"locale_nb": "Norska (bokmål)",
|
||||
"locale_sv": "Svenska",
|
||||
"locale_zh": "中文 (简体)",
|
||||
|
|
@ -426,7 +429,8 @@
|
|||
"macro_name_too_long": "Namnet måste vara kortare än 50 tecken",
|
||||
"macro_please_fix_validation_errors": "Vänligen åtgärda valideringsfelen",
|
||||
"macro_save": "Spara makro",
|
||||
"macro_save_error": "Ett fel uppstod när dokumentet skulle sparas.",
|
||||
"macro_save_failed": "Ett fel uppstod när dokumentet skulle sparas.",
|
||||
"macro_save_failed_error": "Ett fel uppstod när dokumentet skulle sparas: {error}.",
|
||||
"macro_step_count": "{steps} / {max} steg",
|
||||
"macro_step_duration_description": "Dags att vänta innan nästa steg genomförs.",
|
||||
"macro_step_duration_label": "Steglängd",
|
||||
|
|
@ -549,9 +553,9 @@
|
|||
"mouse_hide_cursor_description": "Dölj markören när du skickar musrörelser",
|
||||
"mouse_hide_cursor_title": "Dölj markören",
|
||||
"mouse_jiggler_config_updated": "Jiggler-konfigurationen har uppdaterats",
|
||||
"mouse_jiggler_custom": "Beställnings",
|
||||
"mouse_jiggler_custom": "Anpassad",
|
||||
"mouse_jiggler_description": "Simulera rörelsen hos en datormus",
|
||||
"mouse_jiggler_disabled": "Funktionshindrad",
|
||||
"mouse_jiggler_disabled": "Inaktiverad",
|
||||
"mouse_jiggler_error_config": "Det uppstod ett fel vid konfiguration av jiggler",
|
||||
"mouse_jiggler_failed_state": "Misslyckades med att ställa in jiggler-tillstånd: {error}",
|
||||
"mouse_jiggler_frequent": "Frekvent - 30-talet",
|
||||
|
|
@ -578,7 +582,6 @@
|
|||
"network_dhcp_client_description": "Konfigurera vilken DHCP-klient som ska användas",
|
||||
"network_dhcp_client_jetkvm": "JetKVM Intern",
|
||||
"network_dhcp_client_title": "DHCP-klient",
|
||||
"network_dhcp_information": "DHCP-information",
|
||||
"network_dhcp_lease_renew": "Förnya DHCP-lease",
|
||||
"network_dhcp_lease_renew_confirm": "Förnya hyresavtalet",
|
||||
"network_dhcp_lease_renew_confirm_description": "Detta kommer att begära en ny IP-adress från din DHCP-server. Din enhet kan tillfälligt förlora nätverksanslutningen under denna process.",
|
||||
|
|
@ -586,7 +589,7 @@
|
|||
"network_dhcp_lease_renew_confirm_new_b": "du kan behöva återansluta med den nya adressen",
|
||||
"network_dhcp_lease_renew_failed": "Misslyckades med att förnya leasingavtalet: {error}",
|
||||
"network_dhcp_lease_renew_success": "DHCP-lease förnyad",
|
||||
"network_domain_custom": "Beställnings",
|
||||
"network_domain_custom": "Anpassad",
|
||||
"network_domain_description": "Nätverksdomänsuffix för enheten",
|
||||
"network_domain_dhcp_provided": "DHCP tillhandahålls",
|
||||
"network_domain_local": ".lokal",
|
||||
|
|
@ -599,39 +602,46 @@
|
|||
"network_ipv4_address": "IPv4-adress",
|
||||
"network_ipv4_dns": "IPv4 DNS",
|
||||
"network_ipv4_gateway": "IPv4-gateway",
|
||||
"network_ipv4_invalid": "Ogiltig IPv4-adress",
|
||||
"network_ipv4_invalid_cidr": "Ogiltig CIDR-notation för IPv4-adress",
|
||||
"network_ipv4_mode_description": "Konfigurera IPv4-läget",
|
||||
"network_ipv4_mode_dhcp": "DHCP",
|
||||
"network_ipv4_mode_static": "Statisk",
|
||||
"network_ipv4_mode_title": "IPv4-läge",
|
||||
"network_ipv4_netmask": "IPv4-nätmask",
|
||||
"network_ipv6_address": "IPv6-adress",
|
||||
"network_ipv6_addresses_header": "IPv6-adresser",
|
||||
"network_ipv6_cidr_suggestion": "Använd CIDR-notation (t.ex. 2001:db8::1/64)",
|
||||
"network_ipv6_dns": "IPv6 DNS",
|
||||
"network_ipv6_flag_dad_failed": "DAD misslyckades",
|
||||
"network_ipv6_flag_deprecated": "Föråldrad",
|
||||
"network_ipv6_gateway": "IPv6-gateway",
|
||||
"network_ipv6_information": "IPv6-information",
|
||||
"network_ipv6_invalid": "Ogiltig IPv6-adress",
|
||||
"network_ipv6_mode_description": "Konfigurera IPv6-läget",
|
||||
"network_ipv6_mode_dhcpv6": "DHCPv6",
|
||||
"network_ipv6_mode_disabled": "Funktionshindrad",
|
||||
"network_ipv6_mode_disabled": "Inaktiverad",
|
||||
"network_ipv6_mode_link_local": "Endast länklokal",
|
||||
"network_ipv6_mode_slaac": "SLAAC",
|
||||
"network_ipv6_mode_slaac_dhcpv6": "SLAAC + DHCPv6",
|
||||
"network_ipv6_mode_static": "Statisk",
|
||||
"network_ipv6_mode_title": "IPv6-läge",
|
||||
"network_ipv6_netmask": "IPv6-nätmask",
|
||||
"network_ipv6_no_addresses": "Inga IPv6-adresser konfigurerade",
|
||||
"network_ipv6_prefix": "IP-prefix",
|
||||
"network_ipv6_prefix_invalid": "Prefixet måste vara mellan 0 och 128",
|
||||
"network_ll_dp_all": "Alla",
|
||||
"network_ll_dp_basic": "Grundläggande",
|
||||
"network_ll_dp_description": "Kontrollera vilka TLV:er som ska skickas via Link Layer Discovery Protocol",
|
||||
"network_ll_dp_disabled": "Funktionshindrad",
|
||||
"network_ll_dp_disabled": "Inaktiverad",
|
||||
"network_ll_dp_title": "LLDP",
|
||||
"network_mac_address_copy_error": "Misslyckades med att kopiera MAC-adressen",
|
||||
"network_mac_address_copy_success": "MAC-adress { mac } kopierad till urklipp",
|
||||
"network_mac_address_description": "Maskinvaruidentifierare för nätverksgränssnittet",
|
||||
"network_mac_address_title": "MAC-adress",
|
||||
"network_mdns_auto": "Bil",
|
||||
"network_mdns_auto": "Auto",
|
||||
"network_mdns_description": "Kontroll av mDNS (multicast DNS) driftläge",
|
||||
"network_mdns_disabled": "Funktionshindrad",
|
||||
"network_mdns_disabled": "Inaktiverad",
|
||||
"network_mdns_ipv4_only": "Endast IPv4",
|
||||
"network_mdns_ipv6_only": "Endast IPv6",
|
||||
"network_mdns_title": "mDNS",
|
||||
"network_no_dhcp_lease": "Ingen DHCP-leaseinformation tillgänglig",
|
||||
"network_no_information_description": "Ingen nätverkskonfiguration tillgänglig",
|
||||
"network_no_information_headline": "Nätverksinformation",
|
||||
"network_pending_dhcp_mode_change_description": "Spara inställningar för att aktivera DHCP-läge och visa leasinginformation",
|
||||
|
|
@ -643,8 +653,10 @@
|
|||
"network_save_settings_confirm_heading": "Konfigurationsändringar",
|
||||
"network_save_settings_failed": "Misslyckades med att spara nätverksinställningar: {error}",
|
||||
"network_save_settings_success": "Nätverksinställningar sparade",
|
||||
"network_settings_invalid_ipv4_cidr": "Ogiltig CIDR-notation för IPv4-adress",
|
||||
"network_settings_add_dns": "Lägg till DNS-server",
|
||||
"network_settings_load_error": "Misslyckades med att läsa in nätverksinställningar: {error}",
|
||||
"network_static_ipv4_header": "Statisk IPv4-konfiguration",
|
||||
"network_static_ipv6_header": "Statisk IPv6-konfiguration",
|
||||
"network_time_sync_description": "Konfigurera inställningar för tidssynkronisering",
|
||||
"network_time_sync_http_only": "Endast HTTP",
|
||||
"network_time_sync_ntp_and_http": "NTP och HTTP",
|
||||
|
|
@ -670,9 +682,9 @@
|
|||
"paste_modal_failed_paste": "Misslyckades med att klistra in text: {error}",
|
||||
"paste_modal_invalid_chars_intro": "Följande tecken klistras inte in:",
|
||||
"paste_modal_paste_from_host": "Klistra in från värd",
|
||||
"paste_modal_paste_text": "Klistra in text",
|
||||
"paste_modal_paste_text_description": "Klistra in text från din klient till fjärrdatorn",
|
||||
"paste_modal_sending_using_layout": "Skicka text med tangentbordslayout: {iso} - {name}",
|
||||
"paste_text": "Klistra in text",
|
||||
"paste_text_description": "Klistra in text från din klient till fjärrdatorn",
|
||||
"peer_connection_closed": "Stängd",
|
||||
"peer_connection_closing": "Stängning",
|
||||
"peer_connection_connected": "Ansluten",
|
||||
|
|
@ -743,7 +755,7 @@
|
|||
"updates_failed_get_device_version": "Misslyckades med att hämta enhetsversionen: {error}",
|
||||
"updating_leave_device_on": "Stäng inte av din enhet…",
|
||||
"usb": "USB",
|
||||
"usb_config_custom": "Beställnings",
|
||||
"usb_config_custom": "Anpassad",
|
||||
"usb_config_default": "JetKVM-standard",
|
||||
"usb_config_dell": "Dell Multimedia Pro-tangentbord",
|
||||
"usb_config_failed_load": "Misslyckades med att ladda USB-konfigurationen: {error}",
|
||||
|
|
@ -767,7 +779,7 @@
|
|||
"usb_config_vendor_id_placeholder": "Ange leverantörs-ID",
|
||||
"usb_device_classes_description": "USB-enhetsklasser i den sammansatta enheten",
|
||||
"usb_device_classes_title": "Klasser",
|
||||
"usb_device_custom": "Beställnings",
|
||||
"usb_device_custom": "Anpassad",
|
||||
"usb_device_description": "USB-enheter att emulera på måldatorn",
|
||||
"usb_device_enable_absolute_mouse_description": "Aktivera absolut mus (pekare)",
|
||||
"usb_device_enable_absolute_mouse_title": "Aktivera absolut mus (pekare)",
|
||||
|
|
@ -802,7 +814,7 @@
|
|||
"video_description": "Konfigurera skärminställningar och EDID för optimal kompatibilitet",
|
||||
"video_edid_acer_b246wl": "Acer B246WL, 1920x1200",
|
||||
"video_edid_asus_pa248qv": "ASUS PA248QV, 1920x1200",
|
||||
"video_edid_custom": "Beställnings",
|
||||
"video_edid_custom": "Anpassad",
|
||||
"video_edid_dell_d2721h": "DELL D2721H, 1920x1080",
|
||||
"video_edid_dell_idrac": "DELL IDRAC EDID, 1280x1024",
|
||||
"video_edid_description": "Justera EDID-inställningarna för skärmen",
|
||||
|
|
|
|||
|
|
@ -50,7 +50,6 @@
|
|||
"action_bar_connection_stats": "连接统计",
|
||||
"action_bar_extension": "扩展",
|
||||
"action_bar_fullscreen": "全屏",
|
||||
"action_bar_paste_text": "粘贴文本",
|
||||
"action_bar_settings": "设置",
|
||||
"action_bar_virtual_keyboard": "虚拟键盘",
|
||||
"action_bar_virtual_media": "虚拟媒体",
|
||||
|
|
@ -142,7 +141,6 @@
|
|||
"auth_mode_local_password_confirm_description": "确认您的密码",
|
||||
"auth_mode_local_password_confirm_label": "确认密码",
|
||||
"auth_mode_local_password_description": "使用密码保护您的设备以增强保护。",
|
||||
"auth_mode_local_password_do_not_match": "密码不匹配",
|
||||
"auth_mode_local_password_failed_set": "无法设置密码: {error}",
|
||||
"auth_mode_local_password_note": "此密码将用于保护您的设备数据并防止未经授权的访问。",
|
||||
"auth_mode_local_password_note_local": "所有数据都保留在您的本地设备上。",
|
||||
|
|
@ -181,6 +179,9 @@
|
|||
"connection_stats_round_trip_time": "往返时间",
|
||||
"connection_stats_round_trip_time_description": "对等体之间活跃 ICE 候选对的往返时间。",
|
||||
"connection_stats_sidebar": "连接统计",
|
||||
"connection_stats_unit_frames_per_second": " 帧每秒",
|
||||
"connection_stats_unit_milliseconds": " 毫秒",
|
||||
"connection_stats_unit_packets": " 数据包",
|
||||
"connection_stats_video": "视频",
|
||||
"connection_stats_video_description": "从 JetKVM 到客户端的视频流。",
|
||||
"continue": "继续",
|
||||
|
|
@ -207,6 +208,8 @@
|
|||
"deregister_error": "注销您的设备时出现错误{status} 。请重试。",
|
||||
"deregister_headline": "从您的云帐户中取消注册{device}",
|
||||
"detach": "分离",
|
||||
"dhcp_empty_lease_description": "我们尚未收到来自该设备的任何 DHCP 租约信息。",
|
||||
"dhcp_empty_lease_headline": "无 DHCP 租约信息",
|
||||
"dhcp_lease_boot_file": "引导文件",
|
||||
"dhcp_lease_boot_next_server": "启动下一个服务器",
|
||||
"dhcp_lease_boot_server_name": "启动服务器名称",
|
||||
|
|
@ -426,7 +429,8 @@
|
|||
"macro_name_too_long": "名称必须少于 50 个字符",
|
||||
"macro_please_fix_validation_errors": "请修复验证错误",
|
||||
"macro_save": "保存宏",
|
||||
"macro_save_error": "保存时发生错误。",
|
||||
"macro_save_failed": "保存时发生错误。",
|
||||
"macro_save_failed_error": "保存时发生错误:{error}。",
|
||||
"macro_step_count": "{steps} / {max}步骤",
|
||||
"macro_step_duration_description": "执行下一步之前需要等待的时间。",
|
||||
"macro_step_duration_label": "步骤持续时间",
|
||||
|
|
@ -578,7 +582,6 @@
|
|||
"network_dhcp_client_description": "配置要使用的 DHCP 客户端",
|
||||
"network_dhcp_client_jetkvm": "JetKVM 内部",
|
||||
"network_dhcp_client_title": "DHCP客户端",
|
||||
"network_dhcp_information": "DHCP 信息",
|
||||
"network_dhcp_lease_renew": "续订 DHCP 租约",
|
||||
"network_dhcp_lease_renew_confirm": "续租",
|
||||
"network_dhcp_lease_renew_confirm_description": "这将从您的 DHCP 服务器请求新的 IP 地址。在此过程中,您的设备可能会暂时失去网络连接。",
|
||||
|
|
@ -599,13 +602,21 @@
|
|||
"network_ipv4_address": "IPv4 地址",
|
||||
"network_ipv4_dns": "IPv4 域名服务器",
|
||||
"network_ipv4_gateway": "IPv4 网关",
|
||||
"network_ipv4_invalid": "IPv4 地址无效",
|
||||
"network_ipv4_invalid_cidr": "IPv4 地址的 CIDR 表示法无效",
|
||||
"network_ipv4_mode_description": "配置 IPv4 模式",
|
||||
"network_ipv4_mode_dhcp": "DHCP",
|
||||
"network_ipv4_mode_static": "静止的",
|
||||
"network_ipv4_mode_title": "IPv4 模式",
|
||||
"network_ipv4_netmask": "IPv4 网络掩码",
|
||||
"network_ipv6_address": "IPv6 地址",
|
||||
"network_ipv6_addresses_header": "IPv6 地址",
|
||||
"network_ipv6_cidr_suggestion": "请使用 CIDR 表示法(例如,2001:db8::1/64)",
|
||||
"network_ipv6_dns": "IPv6 域名服务器",
|
||||
"network_ipv6_flag_dad_failed": "DAD 失败",
|
||||
"network_ipv6_flag_deprecated": "已弃用",
|
||||
"network_ipv6_gateway": "IPv6网关",
|
||||
"network_ipv6_information": "IPv6 信息",
|
||||
"network_ipv6_invalid": "IPv6 地址无效",
|
||||
"network_ipv6_mode_description": "配置 IPv6 模式",
|
||||
"network_ipv6_mode_dhcpv6": "DHCPv6",
|
||||
"network_ipv6_mode_disabled": "已禁用",
|
||||
|
|
@ -614,8 +625,8 @@
|
|||
"network_ipv6_mode_slaac_dhcpv6": "SLAAC + DHCPv6",
|
||||
"network_ipv6_mode_static": "静止的",
|
||||
"network_ipv6_mode_title": "IPv6模式",
|
||||
"network_ipv6_netmask": "IPv6 网络掩码",
|
||||
"network_ipv6_no_addresses": "未配置 IPv6 地址",
|
||||
"network_ipv6_prefix": "IP 前缀",
|
||||
"network_ipv6_prefix_invalid": "前缀必须介于 0 到 128 之间",
|
||||
"network_ll_dp_all": "全部",
|
||||
"network_ll_dp_basic": "基本的",
|
||||
"network_ll_dp_description": "控制哪些 TLV 将通过链路层发现协议发送",
|
||||
|
|
@ -631,7 +642,6 @@
|
|||
"network_mdns_ipv4_only": "仅限 IPv4",
|
||||
"network_mdns_ipv6_only": "仅限 IPv6",
|
||||
"network_mdns_title": "移动DNS",
|
||||
"network_no_dhcp_lease": "没有可用的 DHCP 租约信息",
|
||||
"network_no_information_description": "没有可用的网络配置",
|
||||
"network_no_information_headline": "网络信息",
|
||||
"network_pending_dhcp_mode_change_description": "保存设置以启用 DHCP 模式并查看租约信息",
|
||||
|
|
@ -643,8 +653,10 @@
|
|||
"network_save_settings_confirm_heading": "配置更改",
|
||||
"network_save_settings_failed": "无法保存网络设置: {error}",
|
||||
"network_save_settings_success": "网络设置已保存",
|
||||
"network_settings_invalid_ipv4_cidr": "IPv4 地址的 CIDR 表示法无效",
|
||||
"network_settings_add_dns": "添加 DNS 服务器",
|
||||
"network_settings_load_error": "无法加载网络设置: {error}",
|
||||
"network_static_ipv4_header": "静态 IPv4 配置",
|
||||
"network_static_ipv6_header": "静态 IPv6 配置",
|
||||
"network_time_sync_description": "配置时间同步设置",
|
||||
"network_time_sync_http_only": "仅 HTTP",
|
||||
"network_time_sync_ntp_and_http": "NTP 和 HTTP",
|
||||
|
|
@ -670,9 +682,9 @@
|
|||
"paste_modal_failed_paste": "粘贴文本失败: {error}",
|
||||
"paste_modal_invalid_chars_intro": "以下字符将不会被粘贴:",
|
||||
"paste_modal_paste_from_host": "从主机粘贴",
|
||||
"paste_modal_paste_text": "粘贴文本",
|
||||
"paste_modal_paste_text_description": "将文本从客户端粘贴到远程主机",
|
||||
"paste_modal_sending_using_layout": "使用键盘布局发送文本: {iso} - {name}",
|
||||
"paste_text": "粘贴文本",
|
||||
"paste_text_description": "将文本从客户端粘贴到远程主机",
|
||||
"peer_connection_closed": "关闭",
|
||||
"peer_connection_closing": "结束语",
|
||||
"peer_connection_connected": "已连接",
|
||||
|
|
|
|||
|
|
@ -1,16 +1,17 @@
|
|||
{
|
||||
"name": "kvm-ui",
|
||||
"version": "2025.10.14.2130",
|
||||
"version": "2025.10.15.1700",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "kvm-ui",
|
||||
"version": "2025.10.14.2130",
|
||||
"version": "2025.10.15.1700",
|
||||
"dependencies": {
|
||||
"@headlessui/react": "^2.2.9",
|
||||
"@headlessui/tailwindcss": "^0.2.2",
|
||||
"@heroicons/react": "^2.2.0",
|
||||
"@types/uuid": "^10.0.0",
|
||||
"@vitejs/plugin-basic-ssl": "^2.1.0",
|
||||
"@xterm/addon-clipboard": "^0.1.0",
|
||||
"@xterm/addon-fit": "^0.10.0",
|
||||
|
|
@ -68,7 +69,7 @@
|
|||
"eslint-plugin-prettier": "^5.5.4",
|
||||
"eslint-plugin-react": "^7.37.5",
|
||||
"eslint-plugin-react-hooks": "^7.0.0",
|
||||
"eslint-plugin-react-refresh": "^0.4.23",
|
||||
"eslint-plugin-react-refresh": "^0.4.24",
|
||||
"globals": "^16.4.0",
|
||||
"postcss": "^8.5.6",
|
||||
"prettier": "^3.6.2",
|
||||
|
|
@ -126,6 +127,7 @@
|
|||
"integrity": "sha512-2BCOP7TN8M+gVDj7/ht3hsaO/B/n5oDbiAyyvnRlNOs+u1o+JWNYTQrmpuNp1/Wq2gcFrI01JAW+paEKDMx/CA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@babel/code-frame": "^7.27.1",
|
||||
"@babel/generator": "^7.28.3",
|
||||
|
|
@ -2405,6 +2407,7 @@
|
|||
"resolved": "https://registry.npmjs.org/@types/react/-/react-19.2.2.tgz",
|
||||
"integrity": "sha512-6mDvHUFSjyT2B2yeNx2nUgMxh9LtOWvkhIU3uePn2I2oyNymUAX1NIsdgviM4CH+JSrp2D2hsMvJOkxY+0wNRA==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"csstype": "^3.0.2"
|
||||
}
|
||||
|
|
@ -2414,6 +2417,7 @@
|
|||
"resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-19.2.2.tgz",
|
||||
"integrity": "sha512-9KQPoO6mZCi7jcIStSnlOWn2nEF3mNmyr3rIAsGnAbQKYbRLyqmeSc39EVgtxXVia+LMT8j3knZLAZAh+xLmrw==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"peerDependencies": {
|
||||
"@types/react": "^19.2.0"
|
||||
}
|
||||
|
|
@ -2431,6 +2435,12 @@
|
|||
"integrity": "sha512-zFDAD+tlpf2r4asuHEj0XH6pY6i0g5NeAHPn+15wk3BV6JA69eERFXC1gyGThDkVa1zCyKr5jox1+2LbV/AMLg==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@types/uuid": {
|
||||
"version": "10.0.0",
|
||||
"resolved": "https://registry.npmjs.org/@types/uuid/-/uuid-10.0.0.tgz",
|
||||
"integrity": "sha512-7gqG38EyHgyP1S+7+xomFtL+ZNHcKv6DwNaCZmJmo1vgMugyF3TCnXVg4t1uk89mLNwnLtnY3TpOpCOyp1/xHQ==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@types/validator": {
|
||||
"version": "13.15.3",
|
||||
"resolved": "https://registry.npmjs.org/@types/validator/-/validator-13.15.3.tgz",
|
||||
|
|
@ -2484,6 +2494,7 @@
|
|||
"integrity": "sha512-6JSSaBZmsKvEkbRUkf7Zj7dru/8ZCrJxAqArcLaVMee5907JdtEbKGsZ7zNiIm/UAkpGUkaSMZEXShnN2D1HZA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@typescript-eslint/scope-manager": "8.46.1",
|
||||
"@typescript-eslint/types": "8.46.1",
|
||||
|
|
@ -2790,13 +2801,15 @@
|
|||
"version": "5.5.0",
|
||||
"resolved": "https://registry.npmjs.org/@xterm/xterm/-/xterm-5.5.0.tgz",
|
||||
"integrity": "sha512-hqJHYaQb5OptNunnyAnkHyM8aCjZ1MEIDTQu1iIbbTD/xops91NB5yq1ZK/dC2JDbVWtF23zUtl9JE2NqwT87A==",
|
||||
"license": "MIT"
|
||||
"license": "MIT",
|
||||
"peer": true
|
||||
},
|
||||
"node_modules/acorn": {
|
||||
"version": "8.15.0",
|
||||
"resolved": "https://registry.npmjs.org/acorn/-/acorn-8.15.0.tgz",
|
||||
"integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"bin": {
|
||||
"acorn": "bin/acorn"
|
||||
},
|
||||
|
|
@ -3132,6 +3145,7 @@
|
|||
}
|
||||
],
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"baseline-browser-mapping": "^2.8.9",
|
||||
"caniuse-lite": "^1.0.30001746",
|
||||
|
|
@ -3371,7 +3385,8 @@
|
|||
"version": "3.1.3",
|
||||
"resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz",
|
||||
"integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==",
|
||||
"license": "MIT"
|
||||
"license": "MIT",
|
||||
"peer": true
|
||||
},
|
||||
"node_modules/cva": {
|
||||
"version": "1.0.0-beta.4",
|
||||
|
|
@ -3967,6 +3982,7 @@
|
|||
"resolved": "https://registry.npmjs.org/eslint/-/eslint-9.37.0.tgz",
|
||||
"integrity": "sha512-XyLmROnACWqSxiGYArdef1fItQd47weqB7iwtfr9JHwRrqIXZdcFMvvEcL9xHCmL0SNsOvF0c42lWyM1U5dgig==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@eslint-community/eslint-utils": "^4.8.0",
|
||||
"@eslint-community/regexpp": "^4.12.1",
|
||||
|
|
@ -4028,6 +4044,7 @@
|
|||
"integrity": "sha512-82GZUjRS0p/jganf6q1rEO25VSoHH0hKPCTrgillPjdI/3bgBhAE1QzHrHTizjpRvy6pGAvKjDJtk2pF9NDq8w==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"bin": {
|
||||
"eslint-config-prettier": "bin/cli.js"
|
||||
},
|
||||
|
|
@ -4101,6 +4118,7 @@
|
|||
"resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.32.0.tgz",
|
||||
"integrity": "sha512-whOE1HFo/qJDyX4SnXzP4N6zOWn79WhnCUY/iDR0mPfQZO8wcYE4JClzI2oZrhBnnMUCBCHZhO6VQyoBU95mZA==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@rtsao/scc": "^1.1.0",
|
||||
"array-includes": "^3.1.9",
|
||||
|
|
@ -5523,6 +5541,7 @@
|
|||
"integrity": "sha512-FIyV/64EkKhJmjgC0g2hygpBv5RNWVPyNCqSAD7eTCv6eFWNIi4PN1UvdSJGicN/o35bnevgis4Y0UDC0qi8jQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"engines": {
|
||||
"node": ">=14.0.0"
|
||||
}
|
||||
|
|
@ -6247,6 +6266,7 @@
|
|||
}
|
||||
],
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"nanoid": "^3.3.11",
|
||||
"picocolors": "^1.1.1",
|
||||
|
|
@ -6292,6 +6312,7 @@
|
|||
"integrity": "sha512-I7AIg5boAr5R0FFtJ6rCfD+LFsWHp81dolrFD8S79U9tb8Az2nGrJncnMSnys+bpQJfRUzqs9hnA81OAA3hCuQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"bin": {
|
||||
"prettier": "bin/prettier.cjs"
|
||||
},
|
||||
|
|
@ -6448,6 +6469,7 @@
|
|||
"resolved": "https://registry.npmjs.org/react/-/react-19.2.0.tgz",
|
||||
"integrity": "sha512-tmbWg6W31tQLeB5cdIBOicJDJRR2KzXsV7uSK9iNfLWQ5bIZfxuPEHp7M8wiHyHnn0DD1i7w3Zmin0FtkrwoCQ==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"engines": {
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
|
|
@ -6470,6 +6492,7 @@
|
|||
"resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.2.0.tgz",
|
||||
"integrity": "sha512-UlbRu4cAiGaIewkPyiRGJk0imDN2T3JjieT6spoL2UeSf5od4n5LB/mQ4ejmxhCFT1tYe8IvaFulzynWovsEFQ==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"scheduler": "^0.27.0"
|
||||
},
|
||||
|
|
@ -6531,6 +6554,7 @@
|
|||
"resolved": "https://registry.npmjs.org/react-redux/-/react-redux-9.2.0.tgz",
|
||||
"integrity": "sha512-ROY9fvHhwOD9ySfrF0wmvu//bKCQ6AeZZq1nJNtbDC+kk5DuSuNX/n6YWYF/SYy7bSba4D4FSz8DJeKY/S/r+g==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@types/use-sync-external-store": "^0.0.6",
|
||||
"use-sync-external-store": "^1.4.0"
|
||||
|
|
@ -6627,7 +6651,8 @@
|
|||
"version": "5.0.1",
|
||||
"resolved": "https://registry.npmjs.org/redux/-/redux-5.0.1.tgz",
|
||||
"integrity": "sha512-M9/ELqF6fy8FwmkpnF0S3YKOqMyoWJ4+CS5Efg2ct3oY9daQvd/Pc71FpGZsVsbl3Cpb+IIcjBDUnnyBdQbq4w==",
|
||||
"license": "MIT"
|
||||
"license": "MIT",
|
||||
"peer": true
|
||||
},
|
||||
"node_modules/redux-thunk": {
|
||||
"version": "3.1.0",
|
||||
|
|
@ -7217,7 +7242,8 @@
|
|||
"version": "4.1.14",
|
||||
"resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-4.1.14.tgz",
|
||||
"integrity": "sha512-b7pCxjGO98LnxVkKjaZSDeNuljC4ueKUddjENJOADtubtdo8llTaJy7HwBMeLNSSo2N5QIAgklslK1+Ir8r6CA==",
|
||||
"license": "MIT"
|
||||
"license": "MIT",
|
||||
"peer": true
|
||||
},
|
||||
"node_modules/tapable": {
|
||||
"version": "2.3.0",
|
||||
|
|
@ -7304,6 +7330,7 @@
|
|||
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz",
|
||||
"integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
},
|
||||
|
|
@ -7480,6 +7507,7 @@
|
|||
"integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==",
|
||||
"devOptional": true,
|
||||
"license": "Apache-2.0",
|
||||
"peer": true,
|
||||
"bin": {
|
||||
"tsc": "bin/tsc",
|
||||
"tsserver": "bin/tsserver"
|
||||
|
|
@ -7663,6 +7691,7 @@
|
|||
"resolved": "https://registry.npmjs.org/vite/-/vite-7.1.10.tgz",
|
||||
"integrity": "sha512-CmuvUBzVJ/e3HGxhg6cYk88NGgTnBoOo7ogtfJJ0fefUWAxN/WDSUa50o+oVBxuIhO8FoEZW0j2eW7sfjs5EtA==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"esbuild": "^0.25.0",
|
||||
"fdir": "^6.5.0",
|
||||
|
|
@ -7774,6 +7803,7 @@
|
|||
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz",
|
||||
"integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
},
|
||||
|
|
@ -7922,6 +7952,7 @@
|
|||
"integrity": "sha512-JInaHOamG8pt5+Ey8kGmdcAcg3OL9reK8ltczgHTAwNhMys/6ThXHityHxVV2p3fkw/c+MAvBHFVYHFZDmjMCQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/colinhacks"
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
{
|
||||
"name": "kvm-ui",
|
||||
"private": true,
|
||||
"version": "2025.10.14.2130",
|
||||
"version": "2025.10.15.1700",
|
||||
"type": "module",
|
||||
"engines": {
|
||||
"node": "^22.20.0"
|
||||
|
|
@ -16,14 +16,20 @@
|
|||
"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"
|
||||
"i18n": "npm run i18n:resort && npm run i18n:validate && npm run i18n:compile",
|
||||
"i18n:resort": "python3 tools/resort_messages.py",
|
||||
"i18n:validate": "inlang validate --project ./localization/jetKVM.UI.inlang",
|
||||
"i18n:compile": "paraglide-js compile --project ./localization/jetKVM.UI.inlang --outdir ./localization/paraglide",
|
||||
"i18n:machine-translate": "inlang machine translate --project ./localization/jetKVM.UI.inlang",
|
||||
"i18n:find-excess": "python3 ./tools/find_excess_messages.py",
|
||||
"i18n:find-unused": "python3 ./tools/find_unused_messages.py",
|
||||
"i18n:find-dupes": "python3 ./tools/find_duplicate_translations.py"
|
||||
},
|
||||
"dependencies": {
|
||||
"@headlessui/react": "^2.2.9",
|
||||
"@headlessui/tailwindcss": "^0.2.2",
|
||||
"@heroicons/react": "^2.2.0",
|
||||
"@types/uuid": "^10.0.0",
|
||||
"@vitejs/plugin-basic-ssl": "^2.1.0",
|
||||
"@xterm/addon-clipboard": "^0.1.0",
|
||||
"@xterm/addon-fit": "^0.10.0",
|
||||
|
|
@ -41,8 +47,8 @@
|
|||
"react": "^19.2.0",
|
||||
"react-animate-height": "^3.2.3",
|
||||
"react-dom": "^19.2.0",
|
||||
"react-hot-toast": "^2.6.0",
|
||||
"react-hook-form": "^7.65.0",
|
||||
"react-hot-toast": "^2.6.0",
|
||||
"react-icons": "^5.5.0",
|
||||
"react-router": "^7.9.4",
|
||||
"react-simple-keyboard": "^3.8.130",
|
||||
|
|
@ -81,7 +87,7 @@
|
|||
"eslint-plugin-prettier": "^5.5.4",
|
||||
"eslint-plugin-react": "^7.37.5",
|
||||
"eslint-plugin-react-hooks": "^7.0.0",
|
||||
"eslint-plugin-react-refresh": "^0.4.23",
|
||||
"eslint-plugin-react-refresh": "^0.4.24",
|
||||
"globals": "^16.4.0",
|
||||
"postcss": "^8.5.6",
|
||||
"prettier": "^3.6.2",
|
||||
|
|
|
|||
|
|
@ -72,7 +72,7 @@ export default function Actionbar({
|
|||
<Button
|
||||
size="XS"
|
||||
theme="light"
|
||||
text={m.action_bar_paste_text()}
|
||||
text={m.paste_text()}
|
||||
LeadingIcon={MdOutlineContentPasteGo}
|
||||
onClick={() => {
|
||||
setDisableVideoFocusTrap(true);
|
||||
|
|
|
|||
|
|
@ -1,12 +1,12 @@
|
|||
import { LuRefreshCcw } from "react-icons/lu";
|
||||
|
||||
import { Button } from "@components/Button";
|
||||
import EmptyCard from "@components/EmptyCard";
|
||||
import { GridCard } from "@components/Card";
|
||||
import { LifeTimeLabel } from "@routes/devices.$id.settings.network";
|
||||
import { NetworkState } from "@hooks/stores";
|
||||
import { m } from "@localizations/messages.js";
|
||||
|
||||
import EmptyCard from "./EmptyCard";
|
||||
|
||||
export default function DhcpLeaseCard({
|
||||
networkState,
|
||||
|
|
@ -20,8 +20,8 @@ export default function DhcpLeaseCard({
|
|||
if (isDhcpLeaseEmpty) {
|
||||
return (
|
||||
<EmptyCard
|
||||
headline="No DHCP Lease information"
|
||||
description="We haven't received any DHCP lease information from the device yet."
|
||||
headline={m.dhcp_empty_lease_headline()}
|
||||
description={m.dhcp_empty_lease_description()}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
|
@ -41,7 +41,7 @@ export default function DhcpLeaseCard({
|
|||
theme="light"
|
||||
type="button"
|
||||
className="text-red-500"
|
||||
text="Renew DHCP Lease"
|
||||
text={m.dhcp_lease_renew()}
|
||||
LeadingIcon={LuRefreshCcw}
|
||||
onClick={() => setShowRenewLeaseConfirm(true)}
|
||||
/>
|
||||
|
|
@ -54,7 +54,7 @@ export default function DhcpLeaseCard({
|
|||
<div className="flex justify-between border-slate-800/10 pt-2 dark:border-slate-300/20">
|
||||
<span className="text-sm text-slate-600 dark:text-slate-400">
|
||||
{m.ip_address()}
|
||||
</span>
|
||||
</span>
|
||||
<span className="text-sm font-medium">
|
||||
{networkState?.dhcp_lease?.ip}
|
||||
</span>
|
||||
|
|
@ -65,7 +65,7 @@ export default function DhcpLeaseCard({
|
|||
<div className="flex justify-between border-t border-slate-800/10 pt-2 dark:border-slate-300/20">
|
||||
<span className="text-sm text-slate-600 dark:text-slate-400">
|
||||
{m.subnet_mask()}
|
||||
</span>
|
||||
</span>
|
||||
<span className="text-sm font-medium">
|
||||
{networkState?.dhcp_lease?.netmask}
|
||||
</span>
|
||||
|
|
@ -76,7 +76,7 @@ export default function DhcpLeaseCard({
|
|||
<div className="flex justify-between border-t border-slate-800/10 pt-2 dark:border-slate-300/20">
|
||||
<span className="text-sm text-slate-600 dark:text-slate-400">
|
||||
{m.dns_servers()}
|
||||
</span>
|
||||
</span>
|
||||
<span className="text-right text-sm font-medium">
|
||||
{networkState?.dhcp_lease?.dns_servers.map(dns => (
|
||||
<div key={dns}>{dns}</div>
|
||||
|
|
@ -89,7 +89,7 @@ export default function DhcpLeaseCard({
|
|||
<div className="flex justify-between border-t border-slate-800/10 pt-2 dark:border-slate-300/20">
|
||||
<span className="text-sm text-slate-600 dark:text-slate-400">
|
||||
{m.dhcp_lease_broadcast()}
|
||||
</span>
|
||||
</span>
|
||||
<span className="text-sm font-medium">
|
||||
{networkState?.dhcp_lease?.broadcast}
|
||||
</span>
|
||||
|
|
@ -100,7 +100,7 @@ export default function DhcpLeaseCard({
|
|||
<div className="flex justify-between border-t border-slate-800/10 pt-2 dark:border-slate-300/20">
|
||||
<span className="text-sm text-slate-600 dark:text-slate-400">
|
||||
{m.dhcp_lease_domain()}
|
||||
</span>
|
||||
</span>
|
||||
<span className="text-sm font-medium">
|
||||
{networkState?.dhcp_lease?.domain}
|
||||
</span>
|
||||
|
|
@ -112,7 +112,7 @@ export default function DhcpLeaseCard({
|
|||
<div className="flex justify-between gap-x-8 border-t border-slate-800/10 pt-2 dark:border-slate-300/20">
|
||||
<div className="w-full grow text-sm text-slate-600 dark:text-slate-400">
|
||||
{m.ntp_servers()}
|
||||
</div>
|
||||
</div>
|
||||
<div className="shrink text-right text-sm font-medium">
|
||||
{networkState?.dhcp_lease?.ntp_servers.map(server => (
|
||||
<div key={server}>{server}</div>
|
||||
|
|
@ -125,7 +125,7 @@ export default function DhcpLeaseCard({
|
|||
<div className="flex justify-between border-t border-slate-800/10 pt-2 dark:border-slate-300/20">
|
||||
<span className="text-sm text-slate-600 dark:text-slate-400">
|
||||
{m.dhcp_lease_hostname()}
|
||||
</span>
|
||||
</span>
|
||||
<span className="text-sm font-medium">
|
||||
{networkState?.dhcp_lease?.hostname}
|
||||
</span>
|
||||
|
|
@ -139,7 +139,7 @@ export default function DhcpLeaseCard({
|
|||
<div className="flex justify-between pt-2">
|
||||
<span className="text-sm text-slate-600 dark:text-slate-400">
|
||||
{m.dhcp_lease_gateway()}
|
||||
</span>
|
||||
</span>
|
||||
<span className="text-right text-sm font-medium">
|
||||
{networkState?.dhcp_lease?.routers.map(router => (
|
||||
<div key={router}>{router}</div>
|
||||
|
|
@ -152,7 +152,7 @@ export default function DhcpLeaseCard({
|
|||
<div className="flex justify-between border-t border-slate-800/10 pt-2 dark:border-slate-300/20">
|
||||
<span className="text-sm text-slate-600 dark:text-slate-400">
|
||||
{m.dhcp_server()}
|
||||
</span>
|
||||
</span>
|
||||
<span className="text-sm font-medium">
|
||||
{networkState?.dhcp_lease?.server_id}
|
||||
</span>
|
||||
|
|
@ -163,7 +163,7 @@ export default function DhcpLeaseCard({
|
|||
<div className="flex justify-between border-t border-slate-800/10 pt-2 dark:border-slate-300/20">
|
||||
<span className="text-sm text-slate-600 dark:text-slate-400">
|
||||
{m.dhcp_lease_lease_expires()}
|
||||
</span>
|
||||
</span>
|
||||
<span className="text-sm font-medium">
|
||||
<LifeTimeLabel
|
||||
lifetime={`${networkState?.dhcp_lease?.lease_expiry}`}
|
||||
|
|
@ -175,8 +175,8 @@ export default function DhcpLeaseCard({
|
|||
{networkState?.dhcp_lease?.broadcast && (
|
||||
<div className="flex justify-between border-t border-slate-800/10 pt-2 dark:border-slate-300/20">
|
||||
<span className="text-sm text-slate-600 dark:text-slate-400">
|
||||
Broadcast
|
||||
</span>
|
||||
{m.dhcp_lease_broadcast()}
|
||||
</span>
|
||||
<span className="text-sm font-medium">
|
||||
{networkState?.dhcp_lease?.broadcast}
|
||||
</span>
|
||||
|
|
@ -185,18 +185,22 @@ export default function DhcpLeaseCard({
|
|||
|
||||
{networkState?.dhcp_lease?.mtu && (
|
||||
<div className="flex justify-between border-t border-slate-800/10 pt-2 dark:border-slate-300/20">
|
||||
<span className="text-sm text-slate-600 dark:text-slate-400">MTU</span>
|
||||
<span className="text-sm font-medium">
|
||||
<span className="text-sm text-slate-600 dark:text-slate-400">
|
||||
{m.dhcp_lease_maximum_transfer_unit()}
|
||||
</span>
|
||||
<span className="text-sm font-medium">
|
||||
{networkState?.dhcp_lease?.mtu}
|
||||
</span>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{networkState?.dhcp_lease?.ttl && (
|
||||
<div className="flex justify-between border-t border-slate-800/10 pt-2 dark:border-slate-300/20">
|
||||
<span className="text-sm text-slate-600 dark:text-slate-400">TTL</span>
|
||||
<span className="text-sm font-medium">
|
||||
<span className="text-sm text-slate-600 dark:text-slate-400">
|
||||
{m.dhcp_lease_time_to_live()}
|
||||
</span>
|
||||
<span className="text-sm font-medium">
|
||||
{networkState?.dhcp_lease?.ttl}
|
||||
</span>
|
||||
</div>
|
||||
)}
|
||||
|
|
@ -205,7 +209,7 @@ export default function DhcpLeaseCard({
|
|||
<div className="flex justify-between border-t border-slate-800/10 pt-2 dark:border-slate-300/20">
|
||||
<span className="text-sm text-slate-600 dark:text-slate-400">
|
||||
{m.dhcp_lease_boot_next_server()}
|
||||
</span>
|
||||
</span>
|
||||
<span className="text-sm font-medium">
|
||||
{networkState?.dhcp_lease?.bootp_next_server}
|
||||
</span>
|
||||
|
|
@ -216,7 +220,7 @@ export default function DhcpLeaseCard({
|
|||
<div className="flex justify-between border-t border-slate-800/10 pt-2 dark:border-slate-300/20">
|
||||
<span className="text-sm text-slate-600 dark:text-slate-400">
|
||||
{m.dhcp_lease_boot_server_name()}
|
||||
</span>
|
||||
</span>
|
||||
<span className="text-sm font-medium">
|
||||
{networkState?.dhcp_lease?.bootp_server_name}
|
||||
</span>
|
||||
|
|
@ -227,7 +231,7 @@ export default function DhcpLeaseCard({
|
|||
<div className="flex justify-between border-t border-slate-800/10 pt-2 dark:border-slate-300/20">
|
||||
<span className="text-sm text-slate-600 dark:text-slate-400">
|
||||
{m.dhcp_lease_boot_file()}
|
||||
</span>
|
||||
</span>
|
||||
<span className="text-sm font-medium">
|
||||
{networkState?.dhcp_lease?.bootp_file}
|
||||
</span>
|
||||
|
|
@ -236,8 +240,12 @@ export default function DhcpLeaseCard({
|
|||
|
||||
{networkState?.dhcp_lease?.dhcp_client && (
|
||||
<div className="flex justify-between border-t border-slate-800/10 pt-2 dark:border-slate-300/20">
|
||||
<span className="text-sm text-slate-600 dark:text-slate-400">DHCP Client</span>
|
||||
<span className="text-sm font-medium">{networkState?.dhcp_lease?.dhcp_client}</span>
|
||||
<span className="text-sm text-slate-600 dark:text-slate-400">
|
||||
{m.network_dhcp_client_title()}
|
||||
</span>
|
||||
<span className="text-sm font-medium">
|
||||
{networkState?.dhcp_lease?.dhcp_client}
|
||||
</span>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -33,7 +33,7 @@ export default function Ipv6NetworkCard({
|
|||
<div className="flex flex-col justify-between">
|
||||
<span className="text-sm text-slate-600 dark:text-slate-400">
|
||||
{m.ipv6_link_local()}
|
||||
</span>
|
||||
</span>
|
||||
<span className="text-sm font-medium">
|
||||
{networkState?.ipv6_link_local}
|
||||
</span>
|
||||
|
|
@ -42,7 +42,7 @@ export default function Ipv6NetworkCard({
|
|||
<div className="flex flex-col justify-between">
|
||||
<span className="text-sm text-slate-600 dark:text-slate-400">
|
||||
{m.ipv6_gateway()}
|
||||
</span>
|
||||
</span>
|
||||
<span className="text-sm font-medium">
|
||||
{networkState?.ipv6_gateway}
|
||||
</span>
|
||||
|
|
@ -52,7 +52,9 @@ export default function Ipv6NetworkCard({
|
|||
<div className="space-y-3 pt-2">
|
||||
{networkState?.ipv6_addresses && networkState?.ipv6_addresses.length > 0 && (
|
||||
<div className="space-y-3">
|
||||
<h4 className="text-sm font-semibold">IPv6 Addresses</h4>
|
||||
<h4 className="text-sm font-semibold">
|
||||
{m.network_ipv6_addresses_header()}
|
||||
</h4>
|
||||
{networkState.ipv6_addresses.map(addr => (
|
||||
<div
|
||||
key={addr.address}
|
||||
|
|
@ -62,12 +64,12 @@ export default function Ipv6NetworkCard({
|
|||
<div className="col-span-2 flex flex-col justify-between">
|
||||
<span className="text-sm text-slate-600 dark:text-slate-400">
|
||||
{m.ipv6_address_label()}
|
||||
</span>
|
||||
</span>
|
||||
<span className="text-sm font-medium flex">
|
||||
<span className="flex-1">{addr.address}</span>
|
||||
<span className="flex-1">{addr.address}</span>
|
||||
<span className="text-sm font-medium flex gap-x-1">
|
||||
{addr.flag_deprecated ? <FlagLabel flag="Deprecated" /> : null}
|
||||
{addr.flag_dad_failed ? <FlagLabel flag="DAD Failed" /> : null}
|
||||
{addr.flag_deprecated ? <FlagLabel flag={m.network_ipv6_flag_deprecated()} /> : null}
|
||||
{addr.flag_dad_failed ? <FlagLabel flag={m.network_ipv6_flag_dad_failed()} /> : null}
|
||||
</span>
|
||||
</span>
|
||||
</div>
|
||||
|
|
@ -76,7 +78,7 @@ export default function Ipv6NetworkCard({
|
|||
<div className="flex flex-col justify-between">
|
||||
<span className="text-sm text-slate-600 dark:text-slate-400">
|
||||
{m.ipv6_valid_lifetime()}
|
||||
</span>
|
||||
</span>
|
||||
<span className="text-sm font-medium">
|
||||
{addr.valid_lifetime === "" ? (
|
||||
<span className="text-slate-400 dark:text-slate-600">
|
||||
|
|
@ -93,7 +95,7 @@ export default function Ipv6NetworkCard({
|
|||
<div className="flex flex-col justify-between">
|
||||
<span className="text-sm text-slate-600 dark:text-slate-400">
|
||||
{m.ipv6_preferred_lifetime()}
|
||||
</span>
|
||||
</span>
|
||||
<span className="text-sm font-medium">
|
||||
{addr.preferred_lifetime === "" ? (
|
||||
<span className="text-slate-400 dark:text-slate-600">
|
||||
|
|
|
|||
|
|
@ -39,7 +39,7 @@ export function MacroForm({
|
|||
onSubmit,
|
||||
onCancel,
|
||||
isSubmitting = false,
|
||||
}: MacroFormProps) {
|
||||
}: Readonly<MacroFormProps>) {
|
||||
const [macro, setMacro] = useState<Partial<KeySequence>>(initialData);
|
||||
const [keyQueries, setKeyQueries] = useState<Record<number, string>>({});
|
||||
const [errors, setErrors] = useState<ValidationErrors>({});
|
||||
|
|
@ -61,11 +61,11 @@ export function MacroForm({
|
|||
newErrors.name = m.macro_name_too_long();
|
||||
}
|
||||
|
||||
if (!macro.steps?.length) {
|
||||
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,
|
||||
const steps = (macro.steps || []);
|
||||
|
||||
if (steps.length) {
|
||||
const hasKeyOrModifier = steps.some(
|
||||
step => step.keys.length > 0 || step.modifiers.length > 0,
|
||||
);
|
||||
|
||||
if (!hasKeyOrModifier) {
|
||||
|
|
@ -73,6 +73,8 @@ export function MacroForm({
|
|||
0: { keys: m.macro_at_least_one_step_keys_or_modifiers() },
|
||||
};
|
||||
}
|
||||
} else {
|
||||
newErrors.steps = { 0: { keys: m.macro_at_least_one_step_required() } };
|
||||
}
|
||||
|
||||
setErrors(newErrors);
|
||||
|
|
@ -89,9 +91,9 @@ export function MacroForm({
|
|||
await onSubmit(macro);
|
||||
} catch (error) {
|
||||
if (error instanceof Error) {
|
||||
showTemporaryError(error.message);
|
||||
showTemporaryError(m.macro_save_failed_error(error.message || m.unknown_error));
|
||||
} else {
|
||||
showTemporaryError(m.macro_save_error());
|
||||
showTemporaryError(m.macro_save_failed());
|
||||
}
|
||||
}
|
||||
};
|
||||
|
|
@ -104,14 +106,14 @@ export function MacroForm({
|
|||
if (!newSteps[stepIndex]) return;
|
||||
|
||||
if (option.keys) {
|
||||
// they gave us a full set of keys (e.g. from deleting one)
|
||||
newSteps[stepIndex].keys = option.keys;
|
||||
} else if (option.value) {
|
||||
// they gave us a single key to add
|
||||
if (!newSteps[stepIndex].keys) {
|
||||
newSteps[stepIndex].keys = [];
|
||||
}
|
||||
const keysArray = Array.isArray(newSteps[stepIndex].keys)
|
||||
? newSteps[stepIndex].keys
|
||||
: [];
|
||||
const keysArray = newSteps[stepIndex].keys;
|
||||
if (keysArray.length >= MAX_KEYS_PER_STEP) {
|
||||
showTemporaryError(m.macro_max_steps_error({ max: MAX_KEYS_PER_STEP }));
|
||||
return;
|
||||
|
|
@ -172,7 +174,6 @@ export function MacroForm({
|
|||
const isMaxStepsReached = (macro.steps?.length || 0) >= MAX_STEPS_PER_MACRO;
|
||||
|
||||
return (
|
||||
<>
|
||||
<div className="space-y-4">
|
||||
<Fieldset>
|
||||
<InputFieldWithLabel
|
||||
|
|
@ -204,16 +205,16 @@ export function MacroForm({
|
|||
{m.macro_step_count({ steps: macro.steps?.length || 0, max: MAX_STEPS_PER_MACRO })}
|
||||
</span>
|
||||
</div>
|
||||
{errors.steps && errors.steps[0]?.keys && (
|
||||
{errors.steps?.[0]?.keys && (
|
||||
<div className="mt-2">
|
||||
<FieldError error={errors.steps[0].keys} />
|
||||
<FieldError error={errors.steps?.[0]?.keys} />
|
||||
</div>
|
||||
)}
|
||||
<Fieldset>
|
||||
<div className="mt-2 space-y-4">
|
||||
{(macro.steps || []).map((step, stepIndex) => (
|
||||
<MacroStepCard
|
||||
key={stepIndex}
|
||||
key={`step-{stepIndex}`}
|
||||
step={step}
|
||||
stepIndex={stepIndex}
|
||||
onDelete={
|
||||
|
|
@ -285,6 +286,5 @@ export function MacroForm({
|
|||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ 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'];
|
||||
const modifierKeyPrefixes = ["Alt", "Control", "Shift", "Meta"];
|
||||
|
||||
const modifierOptions = Object.keys(modifiers).map(modifier => ({
|
||||
value: modifier,
|
||||
|
|
@ -20,10 +20,10 @@ const modifierOptions = Object.keys(modifiers).map(modifier => ({
|
|||
}));
|
||||
|
||||
const groupedModifiers: Record<string, typeof modifierOptions> = {
|
||||
Control: modifierOptions.filter(mod => mod.value.startsWith('Control')),
|
||||
Shift: modifierOptions.filter(mod => mod.value.startsWith('Shift')),
|
||||
Alt: modifierOptions.filter(mod => mod.value.startsWith('Alt')),
|
||||
Meta: modifierOptions.filter(mod => mod.value.startsWith('Meta')),
|
||||
Control: modifierOptions.filter(mod => mod.value.startsWith("Control")),
|
||||
Shift: modifierOptions.filter(mod => mod.value.startsWith("Shift")),
|
||||
Alt: modifierOptions.filter(mod => mod.value.startsWith("Alt")),
|
||||
Meta: modifierOptions.filter(mod => mod.value.startsWith("Meta")),
|
||||
};
|
||||
|
||||
// not going to localize these since they're short time intervals
|
||||
|
|
@ -64,13 +64,17 @@ interface MacroStepCardProps {
|
|||
onModifierChange: (modifiers: string[]) => void;
|
||||
onDelayChange: (delay: number) => void;
|
||||
isLastStep: boolean;
|
||||
keyboard: KeyboardLayout
|
||||
keyboard: KeyboardLayout;
|
||||
}
|
||||
|
||||
const ensureArray = <T,>(arr: T[] | null | undefined): T[] => {
|
||||
return Array.isArray(arr) ? arr : [];
|
||||
};
|
||||
|
||||
const keyDisplay = (keyDisplayMap: Record<string, string>, key: string): string => {
|
||||
return keyDisplayMap[key] || key
|
||||
};
|
||||
|
||||
export function MacroStepCard({
|
||||
step,
|
||||
stepIndex,
|
||||
|
|
@ -83,28 +87,42 @@ export function MacroStepCard({
|
|||
onModifierChange,
|
||||
onDelayChange,
|
||||
isLastStep,
|
||||
keyboard
|
||||
}: MacroStepCardProps) {
|
||||
keyboard,
|
||||
}: Readonly<MacroStepCardProps>) {
|
||||
const { keyDisplayMap } = keyboard;
|
||||
|
||||
const keyOptions = useMemo(() =>
|
||||
const keyOptions = useMemo(
|
||||
() =>
|
||||
Object.keys(keys)
|
||||
.filter(key => !modifierKeyPrefixes.some(prefix => key.startsWith(prefix)))
|
||||
.map(key => ({
|
||||
value: key,
|
||||
label: keyDisplayMap[key] || key,
|
||||
label: keyDisplay(keyDisplayMap, key),
|
||||
})),
|
||||
[keyDisplayMap]
|
||||
[keyDisplayMap],
|
||||
);
|
||||
|
||||
const handleModifierToggle = (optionValue: string) => {
|
||||
const modifiersArray = ensureArray(step.modifiers);
|
||||
const isSelected = modifiersArray.includes(optionValue);
|
||||
const newModifiers = isSelected
|
||||
? modifiersArray.filter(m => m !== optionValue)
|
||||
: [...modifiersArray, optionValue];
|
||||
onModifierChange(newModifiers);
|
||||
};
|
||||
|
||||
const filteredKeys = useMemo(() => {
|
||||
const selectedKeys = ensureArray(step.keys);
|
||||
const availableKeys = keyOptions.filter(option => !selectedKeys.includes(option.value));
|
||||
const availableKeys = keyOptions.filter(
|
||||
option => !selectedKeys.includes(option.value),
|
||||
);
|
||||
|
||||
if (keyQuery === '') {
|
||||
if (keyQuery === "") {
|
||||
return availableKeys;
|
||||
} else {
|
||||
return availableKeys.filter(option => option.label.toLowerCase().includes(keyQuery.toLowerCase()));
|
||||
return availableKeys.filter(option =>
|
||||
option.label.toLowerCase().includes(keyQuery.toLowerCase()),
|
||||
);
|
||||
}
|
||||
}, [keyOptions, keyQuery, step.keys]);
|
||||
|
||||
|
|
@ -147,13 +165,19 @@ export function MacroStepCard({
|
|||
</div>
|
||||
</div>
|
||||
|
||||
<div className="space-y-4 mt-2">
|
||||
<div className="w-full flex flex-col gap-2">
|
||||
<FieldLabel label={m.macro_step_modifiers_label()} description={m.macro_step_modifiers_description()} />
|
||||
<div className="mt-2 space-y-4">
|
||||
<div className="flex w-full flex-col gap-2">
|
||||
<FieldLabel
|
||||
label={m.macro_step_modifiers_label()}
|
||||
description={m.macro_step_modifiers_description()}
|
||||
/>
|
||||
<div className="inline-flex flex-wrap gap-3">
|
||||
{Object.entries(groupedModifiers).map(([group, mods]) => (
|
||||
<div key={group} className="relative min-w-[120px] rounded-md border border-slate-200 dark:border-slate-700 p-2">
|
||||
<span className="absolute -top-2.5 left-2 px-1 text-xs font-medium bg-white dark:bg-slate-800 text-slate-500 dark:text-slate-400">
|
||||
<div
|
||||
key={group}
|
||||
className="relative min-w-[120px] rounded-md border border-slate-200 p-2 dark:border-slate-700"
|
||||
>
|
||||
<span className="absolute -top-2.5 left-2 bg-white px-1 text-xs font-medium text-slate-500 dark:bg-slate-800 dark:text-slate-400">
|
||||
{group}
|
||||
</span>
|
||||
<div className="flex flex-wrap gap-4 pt-1">
|
||||
|
|
@ -161,16 +185,13 @@ export function MacroStepCard({
|
|||
<Button
|
||||
key={option.value}
|
||||
size="XS"
|
||||
theme={ensureArray(step.modifiers).includes(option.value) ? "primary" : "light"}
|
||||
text={option.label.split(' ')[1] || option.label}
|
||||
onClick={() => {
|
||||
const modifiersArray = ensureArray(step.modifiers);
|
||||
const isSelected = modifiersArray.includes(option.value);
|
||||
const newModifiers = isSelected
|
||||
? modifiersArray.filter(m => m !== option.value)
|
||||
: [...modifiersArray, option.value];
|
||||
onModifierChange(newModifiers);
|
||||
}}
|
||||
theme={
|
||||
ensureArray(step.modifiers).includes(option.value)
|
||||
? "primary"
|
||||
: "light"
|
||||
}
|
||||
text={option.label.split(" ")[1] || option.label}
|
||||
onClick={() => handleModifierToggle(option.value)}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
|
|
@ -179,27 +200,30 @@ export function MacroStepCard({
|
|||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<div className="w-full flex flex-col gap-1">
|
||||
<div className="flex w-full flex-col gap-1">
|
||||
<div className="flex items-center gap-1">
|
||||
<FieldLabel label={m.macro_step_keys_label()} description={m.macro_step_keys_description({ max: MAX_KEYS_PER_STEP })} />
|
||||
<FieldLabel
|
||||
label={m.macro_step_keys_label()}
|
||||
description={m.macro_step_keys_description({ max: MAX_KEYS_PER_STEP })}
|
||||
/>
|
||||
</div>
|
||||
{ensureArray(step.keys) && step.keys.length > 0 && (
|
||||
|
||||
{step.keys?.length > 0 && (
|
||||
<div className="flex flex-wrap gap-1 pb-2">
|
||||
{step.keys.map((key, keyIndex) => (
|
||||
<span
|
||||
key={keyIndex}
|
||||
className="inline-flex items-center py-0.5 rounded-md bg-blue-100 px-1 text-xs font-medium text-blue-800 dark:bg-blue-900/40 dark:text-blue-200"
|
||||
key={`key-{keyIndex}`}
|
||||
className="inline-flex items-center rounded-md bg-blue-100 px-1 py-0.5 text-xs font-medium text-blue-800 dark:bg-blue-900/40 dark:text-blue-200"
|
||||
>
|
||||
<span className="px-1">
|
||||
{keyDisplayMap[key] || key}
|
||||
</span>
|
||||
<span className="px-1">{keyDisplay(keyDisplayMap, key)}</span>
|
||||
<Button
|
||||
size="XS"
|
||||
className=""
|
||||
theme="blank"
|
||||
onClick={() => {
|
||||
const newKeys = ensureArray(step.keys).filter((_, i) => i !== keyIndex);
|
||||
const newKeys = step.keys.filter(
|
||||
(_, i) => i !== keyIndex,
|
||||
);
|
||||
onKeySelect({ value: null, keys: newKeys });
|
||||
}}
|
||||
LeadingIcon={LuX}
|
||||
|
|
@ -210,10 +234,10 @@ export function MacroStepCard({
|
|||
)}
|
||||
<div className="relative w-full">
|
||||
<Combobox
|
||||
onChange={(option) => {
|
||||
onChange={option => {
|
||||
const selectedOption = option as ComboboxOption | null;
|
||||
onKeySelect({ value: selectedOption?.value ?? null });
|
||||
onKeyQueryChange('');
|
||||
onKeyQueryChange("");
|
||||
}}
|
||||
displayValue={() => keyQuery}
|
||||
onInputChange={onKeyQueryChange}
|
||||
|
|
@ -222,22 +246,29 @@ export function MacroStepCard({
|
|||
size="SM"
|
||||
immediate
|
||||
disabled={ensureArray(step.keys).length >= MAX_KEYS_PER_STEP}
|
||||
placeholder={ensureArray(step.keys).length >= MAX_KEYS_PER_STEP ? m.macro_step_max_keys_reached() : m.macro_step_search_for_key()}
|
||||
placeholder={
|
||||
ensureArray(step.keys).length >= MAX_KEYS_PER_STEP
|
||||
? m.macro_step_max_keys_reached()
|
||||
: m.macro_step_search_for_key()
|
||||
}
|
||||
emptyMessage={m.macro_step_no_matching_keys_found()}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="w-full flex flex-col gap-1">
|
||||
<div className="flex w-full flex-col gap-1">
|
||||
<div className="flex items-center gap-1">
|
||||
<FieldLabel label={m.macro_step_duration_label()} description={m.macro_step_duration_description()} />
|
||||
<FieldLabel
|
||||
label={m.macro_step_duration_label()}
|
||||
description={m.macro_step_duration_description()}
|
||||
/>
|
||||
</div>
|
||||
<div className="flex items-center gap-3">
|
||||
<SelectMenuBasic
|
||||
size="SM"
|
||||
fullWidth
|
||||
value={step.delay.toString()}
|
||||
onChange={(e) => onDelayChange(parseInt(e.target.value, 10))}
|
||||
onChange={e => onDelayChange(Number.parseInt(e.target.value, 10))}
|
||||
options={PRESET_DELAYS}
|
||||
/>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -1,14 +1,15 @@
|
|||
import { LuPlus, LuX } from "react-icons/lu";
|
||||
import { useFieldArray, useFormContext } from "react-hook-form";
|
||||
import { useEffect } from "react";
|
||||
import validator from "validator";
|
||||
import { LuPlus, LuX } from "react-icons/lu";
|
||||
import { useFieldArray, useFormContext } from "react-hook-form";
|
||||
import { cx } from "cva";
|
||||
|
||||
import { GridCard } from "@/components/Card";
|
||||
import { Button } from "@/components/Button";
|
||||
import { InputFieldWithLabel } from "@/components/InputField";
|
||||
import { NetworkSettings } from "@/hooks/stores";
|
||||
import { NetworkSettings } from "@hooks/stores";
|
||||
import { Button } from "@components/Button";
|
||||
import { GridCard } from "@components/Card";
|
||||
import { InputFieldWithLabel } from "@components/InputField";
|
||||
import { netMaskFromCidr4 } from "@/utils/ip";
|
||||
import { m } from "@localizations/messages.js";
|
||||
|
||||
export default function StaticIpv4Card() {
|
||||
const formMethods = useFormContext<NetworkSettings>();
|
||||
|
|
@ -24,6 +25,7 @@ export default function StaticIpv4Card() {
|
|||
|
||||
const ipv4StaticAddress = watch("ipv4_static.address");
|
||||
const hideSubnetMask = ipv4StaticAddress?.includes("/");
|
||||
|
||||
useEffect(() => {
|
||||
const parts = ipv4StaticAddress?.split("/", 2);
|
||||
if (parts?.length !== 2) return;
|
||||
|
|
@ -35,13 +37,13 @@ export default function StaticIpv4Card() {
|
|||
setValue("ipv4_static.netmask", mask);
|
||||
}, [ipv4StaticAddress, setValue]);
|
||||
|
||||
const validate = (value: string) => {
|
||||
if (!validator.isIP(value)) return "Invalid IP address";
|
||||
const ipv4Validation = (value: string) => {
|
||||
if (!validator.isIP(value, 4)) return m.network_ipv4_invalid()
|
||||
return true;
|
||||
};
|
||||
|
||||
const validateIsIPOrCIDR4 = (value: string) => {
|
||||
if (!validator.isIP(value, 4) && !validator.isIPRange(value, 4)) return "Invalid IP address or CIDR notation";
|
||||
if (!validator.isIP(value) && !validator.isIPRange(value, 4)) return m.network_ipv4_invalid_cidr();
|
||||
return true;
|
||||
};
|
||||
|
||||
|
|
@ -50,12 +52,12 @@ export default function StaticIpv4Card() {
|
|||
<div className="animate-fadeIn p-4 text-black opacity-0 animation-duration-500 dark:text-white">
|
||||
<div className="space-y-4">
|
||||
<h3 className="text-base font-bold text-slate-900 dark:text-white">
|
||||
Static IPv4 Configuration
|
||||
{m.network_static_ipv4_header()}
|
||||
</h3>
|
||||
|
||||
<div className={cx("grid grid-cols-1 gap-4", hideSubnetMask ? "md:grid-cols-1" : "md:grid-cols-2")}>
|
||||
<InputFieldWithLabel
|
||||
label="IP Address"
|
||||
label={m.network_ipv4_address()}
|
||||
type="text"
|
||||
size="SM"
|
||||
placeholder="192.168.1.100"
|
||||
|
|
@ -67,21 +69,21 @@ export default function StaticIpv4Card() {
|
|||
/>
|
||||
|
||||
{!hideSubnetMask && <InputFieldWithLabel
|
||||
label="Subnet Mask"
|
||||
label={m.network_ipv4_netmask()}
|
||||
type="text"
|
||||
size="SM"
|
||||
placeholder="255.255.255.0"
|
||||
{...register("ipv4_static.netmask", { validate: (value: string | undefined) => validate(value ?? "") })}
|
||||
{...register("ipv4_static.netmask", { validate: (value: string | undefined) => ipv4Validation(value ?? "") })}
|
||||
error={formState.errors.ipv4_static?.netmask?.message}
|
||||
/>}
|
||||
</div>
|
||||
|
||||
<InputFieldWithLabel
|
||||
label="Gateway"
|
||||
label={m.network_ipv4_gateway()}
|
||||
type="text"
|
||||
size="SM"
|
||||
placeholder="192.168.1.1"
|
||||
{...register("ipv4_static.gateway", { validate: (value: string | undefined) => validate(value ?? "") })}
|
||||
{...register("ipv4_static.gateway", { validate: (value: string | undefined) => ipv4Validation(value ?? "") })}
|
||||
error={formState.errors.ipv4_static?.gateway?.message}
|
||||
/>
|
||||
|
||||
|
|
@ -93,13 +95,13 @@ export default function StaticIpv4Card() {
|
|||
<div className="flex items-start gap-x-2">
|
||||
<div className="flex-1">
|
||||
<InputFieldWithLabel
|
||||
label={index === 0 ? "DNS Server" : null}
|
||||
label={index === 0 ? m.network_ipv4_dns() : null}
|
||||
type="text"
|
||||
size="SM"
|
||||
placeholder="1.1.1.1"
|
||||
{...register(
|
||||
`ipv4_static.dns.${index}`,
|
||||
{ validate: (value: string | undefined) => validate(value ?? "") }
|
||||
{ validate: (value: string | undefined) => ipv4Validation(value ?? "") }
|
||||
)}
|
||||
error={formState.errors.ipv4_static?.dns?.[index]?.message}
|
||||
/>
|
||||
|
|
@ -127,7 +129,7 @@ export default function StaticIpv4Card() {
|
|||
onClick={() => append("", { shouldFocus: true })}
|
||||
LeadingIcon={LuPlus}
|
||||
type="button"
|
||||
text="Add DNS Server"
|
||||
text={m.network_settings_add_dns()}
|
||||
disabled={dns?.[0] === ""}
|
||||
/>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -1,12 +1,13 @@
|
|||
import { useEffect } from "react";
|
||||
import validator from "validator";
|
||||
import { LuPlus, LuX } from "react-icons/lu";
|
||||
import { useFieldArray, useFormContext } from "react-hook-form";
|
||||
import validator from "validator";
|
||||
import { useEffect } from "react";
|
||||
|
||||
import { GridCard } from "@/components/Card";
|
||||
import { Button } from "@/components/Button";
|
||||
import { InputFieldWithLabel } from "@/components/InputField";
|
||||
import { NetworkSettings } from "@/hooks/stores";
|
||||
import { NetworkSettings } from "@hooks/stores";
|
||||
import { Button } from "@components/Button";
|
||||
import { GridCard } from "@components/Card";
|
||||
import { InputFieldWithLabel } from "@components/InputField";
|
||||
import { m } from "@localizations/messages.js";
|
||||
|
||||
export default function StaticIpv6Card() {
|
||||
const formMethods = useFormContext<NetworkSettings>();
|
||||
|
|
@ -25,20 +26,20 @@ export default function StaticIpv6Card() {
|
|||
|
||||
// Check if it's a valid IPv6 address with CIDR notation
|
||||
const parts = value.split("/");
|
||||
if (parts.length !== 2) return "Please use CIDR notation (e.g., 2001:db8::1/64)";
|
||||
if (parts.length !== 2) return m.network_ipv6_cidr_suggestion();
|
||||
|
||||
const [address, prefix] = parts;
|
||||
if (!validator.isIP(address, 6)) return "Invalid IPv6 address";
|
||||
if (!validator.isIP(address, 6)) return m.network_ipv6_invalid();
|
||||
const prefixNum = parseInt(prefix);
|
||||
if (isNaN(prefixNum) || prefixNum < 0 || prefixNum > 128) {
|
||||
return "Prefix must be between 0 and 128";
|
||||
return m.network_ipv6_prefix_invalid();
|
||||
}
|
||||
|
||||
return true;
|
||||
};
|
||||
|
||||
const ipv6Validation = (value: string) => {
|
||||
if (!validator.isIP(value, 6)) return "Invalid IPv6 address";
|
||||
if (!validator.isIP(value, 6)) return m.network_ipv6_invalid()
|
||||
return true;
|
||||
};
|
||||
|
||||
|
|
@ -47,11 +48,11 @@ export default function StaticIpv6Card() {
|
|||
<div className="animate-fadeIn p-4 text-black opacity-0 animation-duration-500 dark:text-white">
|
||||
<div className="space-y-4">
|
||||
<h3 className="text-base font-bold text-slate-900 dark:text-white">
|
||||
Static IPv6 Configuration
|
||||
{m.network_static_ipv6_header()}
|
||||
</h3>
|
||||
|
||||
<InputFieldWithLabel
|
||||
label="IP Prefix"
|
||||
label={m.network_ipv6_prefix()}
|
||||
type="text"
|
||||
size="SM"
|
||||
placeholder="2001:db8::1/64"
|
||||
|
|
@ -60,7 +61,7 @@ export default function StaticIpv6Card() {
|
|||
/>
|
||||
|
||||
<InputFieldWithLabel
|
||||
label="Gateway"
|
||||
label={m.network_ipv6_gateway()}
|
||||
type="text"
|
||||
size="SM"
|
||||
placeholder="2001:db8::1"
|
||||
|
|
@ -76,7 +77,7 @@ export default function StaticIpv6Card() {
|
|||
<div className="flex items-start gap-x-2">
|
||||
<div className="flex-1">
|
||||
<InputFieldWithLabel
|
||||
label={index === 0 ? "DNS Server" : null}
|
||||
label={index === 0 ? m.network_ipv6_dns() : null}
|
||||
type="text"
|
||||
size="SM"
|
||||
placeholder="2001:4860:4860::8888"
|
||||
|
|
@ -107,7 +108,7 @@ export default function StaticIpv6Card() {
|
|||
onClick={() => append("", { shouldFocus: true })}
|
||||
LeadingIcon={LuPlus}
|
||||
type="button"
|
||||
text="Add DNS Server"
|
||||
text={m.network_settings_add_dns()}
|
||||
disabled={dns?.[0] === ""}
|
||||
/>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -123,8 +123,8 @@ export default function PasteModal() {
|
|||
<div className="h-full space-y-4">
|
||||
<div className="space-y-4">
|
||||
<SettingsPageHeader
|
||||
title={m.paste_modal_paste_text()}
|
||||
description={m.paste_modal_paste_text_description()}
|
||||
title={m.paste_text()}
|
||||
description={m.paste_text_description()}
|
||||
/>
|
||||
|
||||
<div
|
||||
|
|
|
|||
|
|
@ -116,7 +116,7 @@ export default function ConnectionStatsSidebar() {
|
|||
metric: x.metric != null ? Math.round(x.metric * 1000) : null,
|
||||
})}
|
||||
domain={[0, 600]}
|
||||
unit=" ms"
|
||||
unit={m.connection_stats_units_milliseconds()}
|
||||
/>
|
||||
</div>
|
||||
|
||||
|
|
@ -140,7 +140,7 @@ export default function ConnectionStatsSidebar() {
|
|||
metric: x.metric != null ? Math.round(x.metric * 1000) : null,
|
||||
})}
|
||||
domain={[0, 10]}
|
||||
unit=" ms"
|
||||
unit={m.connection_stats_units_milliseconds()}
|
||||
/>
|
||||
|
||||
{/* Playback Delay */}
|
||||
|
|
@ -162,7 +162,7 @@ export default function ConnectionStatsSidebar() {
|
|||
)
|
||||
}
|
||||
domain={[0, 30]}
|
||||
unit=" ms"
|
||||
unit={m.connection_stats_unit_milliseconds()}
|
||||
/>
|
||||
|
||||
{/* Packets Lost */}
|
||||
|
|
@ -172,7 +172,7 @@ export default function ConnectionStatsSidebar() {
|
|||
stream={inboundVideoRtpStats}
|
||||
metric="packetsLost"
|
||||
domain={[0, 100]}
|
||||
unit=" packets"
|
||||
unit={m.connection_stats_unit_packets()}
|
||||
/>
|
||||
|
||||
{/* Frames Per Second */}
|
||||
|
|
@ -182,7 +182,7 @@ export default function ConnectionStatsSidebar() {
|
|||
stream={inboundVideoRtpStats}
|
||||
metric="framesPerSecond"
|
||||
domain={[0, 80]}
|
||||
unit=" fps"
|
||||
unit={m.connection_stats_unit_frames_per_second()}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -11,11 +11,13 @@ import { useJsonRpc } from "@hooks/useJsonRpc";
|
|||
import AutoHeight from "@components/AutoHeight";
|
||||
import { Button } from "@components/Button";
|
||||
import { ConfirmDialog } from "@components/ConfirmDialog";
|
||||
import DhcpLeaseCard from "@components/DhcpLeaseCard";
|
||||
import EmptyCard from "@components/EmptyCard";
|
||||
import { GridCard } from "@components/Card";
|
||||
import InputField, { InputFieldWithLabel } from "@components/InputField";
|
||||
import Ipv6NetworkCard from "@components/Ipv6NetworkCard";
|
||||
import { SelectMenuBasic } from "@/components/SelectMenuBasic";
|
||||
import { SettingsItem } from "@components/SettingsItem";
|
||||
import { SettingsPageHeader } from "@/components/SettingsPageheader";
|
||||
import StaticIpv4Card from "@components/StaticIpv4Card";
|
||||
import StaticIpv6Card from "@components/StaticIpv6Card";
|
||||
|
|
@ -24,11 +26,11 @@ import { netMaskFromCidr4 } from "@/utils/ip";
|
|||
import { getNetworkSettings, getNetworkState } from "@/utils/jsonrpc";
|
||||
import notifications from "@/notifications";
|
||||
import { m } from "@localizations/messages";
|
||||
import { SettingsItem } from "@components/SettingsItem";
|
||||
import DhcpLeaseCard from "@components/DhcpLeaseCard";
|
||||
|
||||
dayjs.extend(relativeTime);
|
||||
|
||||
const isLLDPAvailable = false; // LLDP is not supported yet
|
||||
|
||||
const resolveOnRtcReady = () => {
|
||||
return new Promise(resolve => {
|
||||
// Check if RTC is already connected
|
||||
|
|
@ -160,7 +162,7 @@ export default function SettingsNetworkRoute() {
|
|||
const parts = settings.ipv4_static.address.split("/");
|
||||
const cidrNotation = parseInt(parts[1]);
|
||||
if (isNaN(cidrNotation) || cidrNotation < 0 || cidrNotation > 32) {
|
||||
return notifications.error(m.network_settings_invalid_ipv4_cidr());
|
||||
return notifications.error(m.network_ipv4_invalid_cidr());
|
||||
}
|
||||
settings.ipv4_static.netmask = netMaskFromCidr4(cidrNotation);
|
||||
settings.ipv4_static.address = parts[0];
|
||||
|
|
@ -251,6 +253,30 @@ export default function SettingsNetworkRoute() {
|
|||
});
|
||||
}
|
||||
|
||||
if (dirty.ipv6_static?.prefix) {
|
||||
changes.push({
|
||||
label: m.network_ipv6_prefix(),
|
||||
from: initialSettingsRef.current?.ipv6_static?.prefix as string,
|
||||
to: data.ipv6_static?.prefix as string,
|
||||
});
|
||||
}
|
||||
|
||||
if (dirty.ipv4_static?.gateway) {
|
||||
changes.push({
|
||||
label: m.network_ipv6_gateway(),
|
||||
from: initialSettingsRef.current?.ipv6_static?.gateway as string,
|
||||
to: data.ipv6_static?.gateway as string,
|
||||
});
|
||||
}
|
||||
|
||||
if (dirty.ipv6_static?.dns) {
|
||||
changes.push({
|
||||
label: m.network_ipv6_dns(),
|
||||
from: initialSettingsRef.current?.ipv6_static?.dns.join(", ").toString() ?? "",
|
||||
to: data.ipv4_static?.dns.join(", ").toString() ?? "",
|
||||
});
|
||||
}
|
||||
|
||||
// If no critical fields are changed, save immediately
|
||||
if (changes.length === 0) return onSubmit(settings);
|
||||
|
||||
|
|
@ -516,9 +542,7 @@ export default function SettingsNetworkRoute() {
|
|||
</AutoHeight>
|
||||
</div>
|
||||
|
||||
|
||||
{ // eslint-disable-next-line no-constant-condition
|
||||
false ? /* LLDP is not supported yet */
|
||||
{ isLLDPAvailable &&
|
||||
(
|
||||
<div className="hidden space-y-4">
|
||||
<SettingsItem
|
||||
|
|
@ -536,7 +560,7 @@ export default function SettingsNetworkRoute() {
|
|||
/>
|
||||
</SettingsItem>
|
||||
</div>
|
||||
) : null
|
||||
)
|
||||
}
|
||||
|
||||
<div className="animate-fadeInStill animation-duration-300">
|
||||
|
|
@ -598,7 +622,7 @@ export default function SettingsNetworkRoute() {
|
|||
<path strokeLinecap="round" strokeLinejoin="round" d="M13 7l5 5m0 0l-5 5m5-5H6" />
|
||||
</svg>
|
||||
<code className="rounded border border-slate-800/20 bg-slate-50 px-1.5 py-1 text-xs text-black font-mono dark:border-slate-300/20 dark:bg-slate-800 dark:text-slate-100">
|
||||
{c.to}
|
||||
{c.to || "—"}
|
||||
</code>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -611,7 +635,7 @@ export default function SettingsNetworkRoute() {
|
|||
|
||||
<ConfirmDialog
|
||||
open={showRenewLeaseConfirm}
|
||||
title={m.network_dhcp_lease_renew()}
|
||||
title={m.dhcp_lease_renew()}
|
||||
variant="warning"
|
||||
confirmText={m.network_dhcp_lease_renew_confirm()}
|
||||
description={
|
||||
|
|
|
|||
|
|
@ -31,7 +31,7 @@ const action: ActionFunction = async ({ request }: ActionFunctionArgs) => {
|
|||
const confirmPassword = formData.get("confirmPassword");
|
||||
|
||||
if (password !== confirmPassword) {
|
||||
return { error: m.auth_mode_local_password_do_not_match() };
|
||||
return { error: m.local_auth_error_passwords_not_match() };
|
||||
}
|
||||
|
||||
try {
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
#!/usr/bin/env python3
|
||||
import argparse
|
||||
import json
|
||||
import os
|
||||
import re
|
||||
from datetime import datetime
|
||||
from pathlib import Path
|
||||
|
|
@ -26,12 +25,30 @@ def normalize(s, ignore_case=False, trim=False, collapse_ws=False):
|
|||
return s
|
||||
|
||||
def main():
|
||||
p = argparse.ArgumentParser(description="Find identical translation targets with different keys in en.json")
|
||||
p.add_argument("--en", default="../ui/localization/messages/en.json", help="path to en.json")
|
||||
p.add_argument("--out", default="../reports/duplicate_translations.json", help="output report path (JSON)")
|
||||
p.add_argument("--ignore-case", action="store_true", help="ignore case when comparing values")
|
||||
p.add_argument("--trim", action="store_true", help="trim surrounding whitespace before comparing")
|
||||
p.add_argument("--collapse-ws", action="store_true", help="collapse internal whitespace before comparing")
|
||||
p = argparse.ArgumentParser(
|
||||
description="Find identical translation targets with different keys in en.json"
|
||||
)
|
||||
p.add_argument(
|
||||
"--en", default="./localization/messages/en.json", help="path to en.json"
|
||||
)
|
||||
p.add_argument(
|
||||
"--out",
|
||||
default="./reports/duplicate_translation_targets.json",
|
||||
help="output report path (JSON)",
|
||||
)
|
||||
p.add_argument(
|
||||
"--ignore-case", default=True, action="store_true", help="ignore case when comparing values"
|
||||
)
|
||||
p.add_argument(
|
||||
"--trim",
|
||||
default=True, action="store_true",
|
||||
help="trim surrounding whitespace before comparing",
|
||||
)
|
||||
p.add_argument(
|
||||
"--collapse-ws",
|
||||
default=True, action="store_true",
|
||||
help="collapse internal whitespace before comparing",
|
||||
)
|
||||
args = p.parse_args()
|
||||
|
||||
en_path = Path(args.en)
|
||||
|
|
@ -48,7 +65,12 @@ def main():
|
|||
groups = {}
|
||||
original_values = {}
|
||||
for key, val in entries:
|
||||
norm = normalize(val, ignore_case=args.ignore_case, trim=args.trim, collapse_ws=args.collapse_ws)
|
||||
norm = normalize(
|
||||
val,
|
||||
ignore_case=args.ignore_case,
|
||||
trim=args.trim,
|
||||
collapse_ws=args.collapse_ws,
|
||||
)
|
||||
groups.setdefault(norm, []).append(key)
|
||||
# keep the first seen original for reporting
|
||||
original_values.setdefault(norm, val)
|
||||
|
|
@ -56,19 +78,23 @@ def main():
|
|||
duplicates = []
|
||||
for norm, keys in groups.items():
|
||||
if len(keys) > 1:
|
||||
duplicates.append({
|
||||
duplicates.append(
|
||||
{
|
||||
"normalized_value": norm,
|
||||
"original_value": original_values.get(norm),
|
||||
"keys": sorted(keys),
|
||||
"count": len(keys)
|
||||
})
|
||||
"count": len(keys),
|
||||
}
|
||||
)
|
||||
|
||||
report = {
|
||||
"generated_at": datetime.utcnow().isoformat() + "Z",
|
||||
"en_json": str(en_path),
|
||||
"total_string_keys": total_keys,
|
||||
"duplicate_groups": sorted(duplicates, key=lambda d: (-d["count"], d["normalized_value"])),
|
||||
"duplicate_count": len(duplicates)
|
||||
"duplicate_groups": sorted(
|
||||
duplicates, key=lambda d: (-d["count"], d["normalized_value"])
|
||||
),
|
||||
"duplicate_count": len(duplicates),
|
||||
}
|
||||
|
||||
out_path = Path(args.out)
|
||||
|
|
@ -76,7 +102,9 @@ def main():
|
|||
with out_path.open("w", encoding="utf-8") as f:
|
||||
json.dump(report, f, indent=2, ensure_ascii=False)
|
||||
|
||||
print(f"Wrote {out_path} — total keys: {total_keys}, duplicate groups: {len(duplicates)}")
|
||||
print(
|
||||
f"Wrote {out_path} — total keys: {total_keys}, duplicate groups: {len(duplicates)}"
|
||||
)
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
sys.exit(main(sys.argv[1:]))
|
||||
|
|
@ -0,0 +1,72 @@
|
|||
#!/usr/bin/env python3
|
||||
"""Find excess translation keys that exist in other language files but are not in en.json
|
||||
|
||||
Usage:
|
||||
python3 tools/find_excess_messages.py
|
||||
|
||||
Optional: set `--json` to print machine-readable JSON output.
|
||||
Optional: set `--path` to point to the directory containing messages JSON files.
|
||||
Optional: set `--out` to specify a file to write the JSON report to.
|
||||
"""
|
||||
import argparse
|
||||
import json
|
||||
import sys
|
||||
from pathlib import Path
|
||||
from json import JSONDecodeError
|
||||
|
||||
def load_json(path: Path):
|
||||
try:
|
||||
return json.loads(path.read_text(encoding='utf-8'))
|
||||
except (JSONDecodeError, OSError) as e:
|
||||
print(f"Failed to read {path}: {e}")
|
||||
return {}
|
||||
|
||||
def main(argv):
|
||||
p = argparse.ArgumentParser(
|
||||
description="Sort translations keys in message *.json files"
|
||||
)
|
||||
p.add_argument("--path", default="./localization/messages/", help="path to messages *.json")
|
||||
p.add_argument("--json", default=False, action="store_true", help="output excess keys as JSON")
|
||||
p.add_argument("--out", default="./reports/excess_messages.json", help="output report file")
|
||||
args = p.parse_args()
|
||||
|
||||
messages_path = Path(args.path)
|
||||
if not messages_path.is_dir():
|
||||
print(f"message path is not a directory: {messages_path}")
|
||||
raise SystemExit(2)
|
||||
|
||||
files = list(messages_path.glob("*.json"))
|
||||
if len(files) == 0:
|
||||
print(f"no message files (*.json) found in: {messages_path}")
|
||||
raise SystemExit(3)
|
||||
|
||||
en_path = messages_path / 'en.json'
|
||||
en = load_json(en_path) if en_path.exists() else {}
|
||||
en_keys = set(en.keys())
|
||||
|
||||
extras = {} # key -> list of files where present
|
||||
|
||||
for f in files:
|
||||
if f.name == 'en.json':
|
||||
continue
|
||||
data = load_json(f)
|
||||
for k in data.keys():
|
||||
if k not in en_keys:
|
||||
extras.setdefault(k, []).append(f.name)
|
||||
|
||||
if '--json' in argv:
|
||||
print(json.dumps(extras, ensure_ascii=False, indent=2))
|
||||
return 0
|
||||
|
||||
if not extras:
|
||||
print('No excess message keys found in other languages.')
|
||||
return 0
|
||||
|
||||
print(f"Message keys present in other languages but not in en.json ({len(extras)}):\n")
|
||||
for key, files in sorted(extras.items()):
|
||||
print(f"{key}: {', '.join(files)}")
|
||||
|
||||
return 0
|
||||
|
||||
if __name__ == '__main__':
|
||||
sys.exit(main(sys.argv[1:]))
|
||||
|
|
@ -14,7 +14,9 @@ def flatten(d, prefix=""):
|
|||
else:
|
||||
yield key
|
||||
|
||||
def gather_files(src_dir, exts=(".ts", ".tsx", ".js", ".jsx", ".html", ".vue", ".json")):
|
||||
def gather_files(
|
||||
src_dir, exts=(".ts", ".tsx", ".js", ".jsx")
|
||||
):
|
||||
for root, _, files in os.walk(src_dir):
|
||||
parts = root.split(os.sep)
|
||||
if "node_modules" in parts or ".git" in parts:
|
||||
|
|
@ -25,29 +27,38 @@ def gather_files(src_dir, exts=(".ts", ".tsx", ".js", ".jsx", ".html", ".vue", "
|
|||
|
||||
def find_usages(keys, files):
|
||||
usages = {k: [] for k in keys}
|
||||
|
||||
print(f"Compiling {len(keys)} patterns for keys ...")
|
||||
# Precompile patterns for speed
|
||||
patterns = {k: re.compile(r"\bm\." + re.escape(k) + r"\s*\(") for k in keys}
|
||||
|
||||
print(f"Scanning files...")
|
||||
for file in files:
|
||||
try:
|
||||
text = file.read_text(encoding="utf-8")
|
||||
except Exception:
|
||||
except (OSError, UnicodeDecodeError):
|
||||
# skip files that can't be read due to I/O or decoding errors
|
||||
continue
|
||||
lines = text.splitlines()
|
||||
for i, line in enumerate(lines, start=1):
|
||||
for k, pat in patterns.items():
|
||||
if pat.search(line):
|
||||
usages[k].append({
|
||||
"file": str(file),
|
||||
"line": i,
|
||||
"text": line.strip()
|
||||
})
|
||||
usages[k].append(
|
||||
{"file": str(file), "line": i, "text": line.strip()}
|
||||
)
|
||||
return usages
|
||||
|
||||
def main():
|
||||
p = argparse.ArgumentParser(description="Generate JSON report of localization key usage (m.key_name_here()).")
|
||||
p.add_argument("--en", default="../ui/localization/messages/en.json", help="path to en.json")
|
||||
p.add_argument("--src", default="../ui", help="root source directory to scan")
|
||||
p.add_argument("--out", default="../reports/localization_report.json", help="output report file")
|
||||
p = argparse.ArgumentParser(
|
||||
description="Generate JSON report of localization key usage (m.key_name_here())."
|
||||
)
|
||||
p.add_argument(
|
||||
"--en", default="./localization/messages/en.json", help="path to en.json"
|
||||
)
|
||||
p.add_argument("--src", default="./", help="root source directory to scan")
|
||||
p.add_argument(
|
||||
"--out", default="./reports/localization_key_usage.json", help="output report file"
|
||||
)
|
||||
args = p.parse_args()
|
||||
|
||||
en_path = Path(args.en)
|
||||
|
|
@ -55,34 +66,40 @@ def main():
|
|||
print(f"en.json not found: {en_path}", flush=True)
|
||||
raise SystemExit(2)
|
||||
|
||||
print(f"Reading english from {en_path}")
|
||||
with en_path.open(encoding="utf-8") as f:
|
||||
payload = json.load(f)
|
||||
|
||||
keys = sorted(list(flatten(payload)))
|
||||
keys.pop(0) if keys and keys[0] == "$schema" else None # remove $schema if present
|
||||
print(f"Found {len(keys)} localization keys")
|
||||
|
||||
print(f"Gathering source files in {args.src} ...")
|
||||
files = list(gather_files(args.src))
|
||||
|
||||
print(f"Scanning {len(files)} source files ...")
|
||||
usages = find_usages(keys, files)
|
||||
|
||||
print(f"Generating report for {len(usages)} usages ...")
|
||||
report = {
|
||||
"generated_at": datetime.utcnow().isoformat() + "Z",
|
||||
"en_json": str(en_path),
|
||||
"src_root": args.src,
|
||||
"total_keys": len(keys),
|
||||
"keys": {}
|
||||
"keys": {},
|
||||
}
|
||||
|
||||
unused_count = 0
|
||||
for k in keys:
|
||||
occ = usages.get(k, [])
|
||||
used = bool(occ)
|
||||
if not used:
|
||||
unused_count += 1
|
||||
report["keys"][k] = {
|
||||
"used": used,
|
||||
"occurrences": occ
|
||||
}
|
||||
report["keys"][k] = {"used": used, "occurrences": occ}
|
||||
|
||||
unused_keys = [k for k, v in report["keys"].items() if not v["used"]]
|
||||
unused_count = len(unused_keys)
|
||||
print(f"Found {unused_count} unused keys")
|
||||
|
||||
report["unused_count"] = unused_count
|
||||
report["unused_keys"] = [k for k, v in report["keys"].items() if not v["used"]]
|
||||
report["unused_keys"] = unused_keys
|
||||
|
||||
out_path = Path(args.out)
|
||||
out_path.parent.mkdir(parents=True, exist_ok=True)
|
||||
|
|
@ -92,5 +109,6 @@ def main():
|
|||
print(f"Report written to {out_path}")
|
||||
print(f"Total keys: {report['total_keys']}, Unused: {report['unused_count']}")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
|
|
@ -0,0 +1,49 @@
|
|||
#!/usr/bin/env python3
|
||||
import argparse
|
||||
import json
|
||||
from pathlib import Path
|
||||
|
||||
def main():
|
||||
p = argparse.ArgumentParser(
|
||||
description="Sort translations keys in message *.json files"
|
||||
)
|
||||
p.add_argument(
|
||||
"--path", default="./localization/messages/", help="path to messages *.json"
|
||||
)
|
||||
args = p.parse_args()
|
||||
|
||||
messages_path = Path(args.path)
|
||||
if not messages_path.is_dir():
|
||||
print(f"message path is not a directory: {messages_path}")
|
||||
raise SystemExit(2)
|
||||
|
||||
files = list(messages_path.glob("*.json"))
|
||||
if len(files) == 0:
|
||||
print(f"no message files (*.json) found in: {messages_path}")
|
||||
raise SystemExit(3)
|
||||
|
||||
for f in files:
|
||||
print(f"Processing {f.name} ...")
|
||||
data = json.loads(f.read_text(encoding="utf-8"))
|
||||
|
||||
# Keep $schema first if present
|
||||
schema = None
|
||||
if "$schema" in data:
|
||||
schema = data.pop("$schema")
|
||||
|
||||
sorted_items = dict(sorted(data.items()))
|
||||
|
||||
if schema is not None:
|
||||
out = {"$schema": schema}
|
||||
out.update(sorted_items)
|
||||
else:
|
||||
out = sorted_items
|
||||
|
||||
f.write_text(
|
||||
json.dumps(out, ensure_ascii=False, indent=4) + "\n", encoding="utf-8"
|
||||
)
|
||||
|
||||
print(f"Processed {len(files)} files in {messages_path}")
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
Loading…
Reference in New Issue