a011aebef5
ci / web (push) Successful in 1m0s
ci / docs-site (push) Successful in 1m6s
apple / swift (push) Successful in 1m9s
decky / build-publish (push) Successful in 22s
docker / build-push (., web/Dockerfile, punktfunk-web) (push) Successful in 47s
windows-host / package (push) Failing after 3m40s
windows-msix / package (arm64, C:\Users\Public\ffmpeg-arm64, --no-default-features, aarch64-pc-windows-msvc, C:\t-a64) (push) Successful in 2m54s
android / android (push) Has been cancelled
apple / screenshots (push) Has been cancelled
arch / build-publish (push) Has been cancelled
ci / rust (push) Has been cancelled
ci / bench (push) Has been cancelled
deb / build-publish (push) Has been cancelled
docker / deploy-docs (push) Has been cancelled
docker / build-push (--build-arg FEDORA_VERSION=44, ci, ci/fedora-rpm.Dockerfile, punktfunk-fedora44-rpm) (push) Has been cancelled
docker / build-push (docs-site, docs-site/Dockerfile, punktfunk-docs) (push) Has been cancelled
docker / build-push (ci, ci/fedora-rpm.Dockerfile, punktfunk-fedora-rpm) (push) Has been cancelled
docker / build-push (ci, ci/rust-ci.Dockerfile, punktfunk-rust-ci) (push) Has been cancelled
windows-msix / package (x64, C:\Users\Public\ffmpeg, , x86_64-pc-windows-msvc, C:\t) (push) Successful in 2m21s
flatpak / build-publish (push) Failing after 2m26s
windows / build (aarch64-pc-windows-msvc) (push) Failing after 1m2s
windows / build (x86_64-pc-windows-msvc) (push) Has been cancelled
rpm / build-publish (44, fedora-44, punktfunk-fedora44-rpm) (push) Has been cancelled
rpm / build-publish (43, bazzite, punktfunk-fedora-rpm) (push) Has been cancelled
release / apple (push) Failing after 19m24s
Second experiment against the connected-but-dark-head stutter (field-proven on the reporter's box: unplugging his standby HDMI TV removes a metronomic ~4 s double-jolt; DDC/CI is a dead end for TVs — measured on the lab LG, VCP 0xD6 gets no I2C ACK). An Exclusive isolate only removes physical monitors from the CCD topology; their PnP devnodes stay live, so every standby wake (auto input scan, Instant-On HPD cycling) still triggers the full Windows reaction: PnP arrival/removal, CCD re-evaluation, DWM invalidation — the suspected hiccup mechanism (Apollo #368's Device-Manager-refresh signature). - New `pnp_disable_monitors` display-policy axis (default off): orthogonal to presets like game_session/ddc_power_off, surfaced in GET/PUT /display/settings + the enforced list, carried through the layout transform. - windows/monitor_devnode.rs: after the isolate takes, disable exactly the deactivated monitors' devnodes — CCD target → monitor device path (DISPLAYCONFIG_TARGET_DEVICE_NAME) → PnP instance id → CM_Disable_DevNode with CM_DISABLE_PERSIST, so a hot-plug RE-ARRIVAL stays disabled (that persistence is the whole point). Teardown re-enables BEFORE the CCD restore (+300 ms re-arrival settle) so restored paths have their monitors back. Precise selection — co-installed third-party virtual displays are never touched. - Crash safety: instance ids journal to <config>/pnp-disabled-monitors.json before disabling; serve startup re-enables leftovers from a crashed host. Worst case is documented in the console help (Device Manager re-enable). - Web console: second Experimental-badged toggle (the DDC block refactored into a shared ExperimentalToggle), EN/DE strings, preset-switch carry. Verified: Linux 263 tests + clippy + fmt clean; Windows (RTX box) 220/220 + clippy clean; web tsc + production build clean; openapi.json regenerated. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
258 lines
14 KiB
JSON
258 lines
14 KiB
JSON
{
|
|
"$schema": "https://inlang.com/schema/inlang-message-format",
|
|
"app_name": "Punktfunk",
|
|
"app_tagline": "management console",
|
|
"display_settings_saved": "Display configuration saved",
|
|
"nav_dashboard": "Dashboard",
|
|
"nav_host": "Host",
|
|
"nav_displays": "Virtual displays",
|
|
"nav_clients": "Paired clients",
|
|
"nav_pairing": "Pairing",
|
|
"nav_library": "Library",
|
|
"nav_settings": "Settings",
|
|
"nav_more": "More",
|
|
"status_title": "Live status",
|
|
"status_video": "Video",
|
|
"status_audio": "Audio",
|
|
"status_streaming": "Streaming",
|
|
"status_idle": "Idle",
|
|
"status_session": "Session",
|
|
"status_no_session": "No active session",
|
|
"status_paired_count": "Paired clients",
|
|
"status_pin_pending": "Pairing PIN pending",
|
|
"stream_codec": "Codec",
|
|
"stream_resolution": "Resolution",
|
|
"stream_fps": "Frame rate",
|
|
"stream_bitrate": "Bitrate",
|
|
"action_stop_session": "Stop session",
|
|
"action_request_idr": "Request keyframe",
|
|
"action_unpair": "Unpair",
|
|
"host_identity": "Identity",
|
|
"host_hostname": "Hostname",
|
|
"host_local_ip": "Local IP",
|
|
"host_version": "Version",
|
|
"host_abi": "ABI version",
|
|
"host_codecs": "Codecs",
|
|
"host_ports": "Ports",
|
|
"host_uniqueid": "Unique ID",
|
|
"host_compositors": "Compositors",
|
|
"host_compositors_help": "Backends the host can drive a virtual output on. Pass an id to a client's --compositor flag; the host honors it if available, else auto-detects.",
|
|
"compositor_available": "Available",
|
|
"compositor_unavailable": "Unavailable",
|
|
"compositor_default": "Default",
|
|
"host_gpus": "GPUs",
|
|
"host_gpus_help": "The GPU the host captures and encodes on. Automatic picks the best GPU; preferring one pins capture + encode to it. A change applies to the next session.",
|
|
"gpu_automatic": "Automatic",
|
|
"gpu_prefer": "Prefer",
|
|
"gpu_preferred": "Preferred",
|
|
"gpu_in_use": "In use · {backend}",
|
|
"gpu_next_session": "Next session",
|
|
"gpu_none": "No GPUs detected.",
|
|
"gpu_missing_warning": "The preferred GPU “{name}” is not present — automatic selection is used instead.",
|
|
"gpu_env_note": "PUNKTFUNK_RENDER_ADAPTER={value} pins the GPU while in automatic mode.",
|
|
"host_displays": "Virtual displays",
|
|
"host_displays_help": "How virtual displays are created, kept alive, and arranged. Pick a preset, or choose Custom to set options directly. A change applies to the next session.",
|
|
"display_config_title": "Configuration",
|
|
"display_preset": "Preset",
|
|
"display_preset_custom": "Custom",
|
|
"display_preset_default": "Default",
|
|
"display_preset_gaming_rig": "Gaming rig",
|
|
"display_preset_shared_desktop": "Shared desktop",
|
|
"display_preset_hotdesk": "Hot-desk",
|
|
"display_preset_workstation": "Workstation",
|
|
"display_keep_alive": "Keep alive after disconnect",
|
|
"display_keep_alive_off": "Off",
|
|
"display_keep_alive_keep": "Keep for",
|
|
"display_keep_alive_seconds": "seconds",
|
|
"display_topology": "Topology",
|
|
"display_topology_auto": "Automatic",
|
|
"display_topology_extend": "Extend",
|
|
"display_topology_primary": "Primary",
|
|
"display_topology_exclusive": "Exclusive",
|
|
"display_max": "Max displays",
|
|
"display_save": "Save",
|
|
"display_effective": "In effect",
|
|
"display_pending_note": "Changes apply from the next connection — a streaming session keeps the display it opened on.",
|
|
"display_live": "Live displays",
|
|
"display_none_live": "No virtual displays right now.",
|
|
"display_state_active": "Active",
|
|
"display_state_lingering": "Lingering",
|
|
"display_state_pinned": "Pinned",
|
|
"display_release_btn": "Release",
|
|
"display_release_all": "Release all kept",
|
|
"display_expires_in": "tears down in {sec}s",
|
|
"display_sessions": "{count} streaming",
|
|
"display_arrange": "Arrange displays",
|
|
"display_arrange_help": "Set where each streamed display sits on the desktop, in pixels. Saving switches to a manual layout; it applies from the next connect.",
|
|
"display_arrange_save": "Save arrangement",
|
|
"display_custom_desc": "Set every option yourself.",
|
|
"display_preset_current": "Active",
|
|
"display_preset_soon": "coming soon",
|
|
"display_keep_alive_help": "Off tears the display down as soon as the client disconnects. Keep it alive (and, on gamescope, its game) so a quick reconnect resumes instantly instead of rebuilding.",
|
|
"display_topology_help": "How the streamed display fits into the host's desktop. Extend: an extra screen alongside your monitors. Primary: the streamed display becomes the primary output, your monitors kept. Exclusive: the streamed display is the sole output — physical monitors are disabled while streaming and restored after. On a headless host it just sets whether the streamed display is the primary.",
|
|
"display_conflict": "When another client connects",
|
|
"display_conflict_help": "What happens if a second client connects while one is already streaming and asks for a different resolution.",
|
|
"display_conflict_separate": "Own display",
|
|
"display_conflict_steal": "Take over",
|
|
"display_conflict_join": "Share view",
|
|
"display_conflict_reject": "Busy — reject",
|
|
"display_identity": "Per-client identity",
|
|
"display_identity_help": "Whether the streamed display carries a stable per-client identity, so the host's desktop remembers that client's per-monitor settings (scaling, resolution) and reapplies them when it reconnects. Shared: one identity for everyone. Per client: each device keeps its own. Per client + resolution: a device keeps separate settings per resolution it connects at.",
|
|
"display_game_session": "Dedicated game sessions",
|
|
"display_game_session_help": "How a session that launches a game from the library is served. “Dedicated” always gives the launch its own headless gamescope at your exact resolution — the game boots straight in, no Steam Big Picture, no game mode. “Auto” uses whatever session the box is in. gamescope must be installed; otherwise Dedicated falls back to Auto.",
|
|
"display_game_session_auto": "Auto",
|
|
"display_game_session_dedicated": "Dedicated",
|
|
"display_experimental": "Experimental",
|
|
"display_ddc": "Turn monitors off while streaming (DDC/CI)",
|
|
"display_ddc_help": "Windows only, takes effect with Exclusive topology. Before disabling your physical monitors, the host also tells them to power their panel off over the DDC/CI monitor-control channel, and wakes them again when the stream ends. This can eliminate a periodic stutter some setups see when the streamed display is the only active one (the dark monitor keeps probing its inputs; a panel that was told to sleep doesn't). Monitors without DDC/CI support are skipped — if your monitor doesn't wake up afterwards, press its power button once and turn this off.",
|
|
"display_ddc_disabled": "Off",
|
|
"display_ddc_enabled": "On",
|
|
"display_ddc_badge": "Monitors off via DDC/CI",
|
|
"display_pnp": "Disable monitor devices while streaming (PnP)",
|
|
"display_pnp_help": "Windows only, takes effect with Exclusive topology. On top of removing your physical monitors from the desktop, the host disables their Windows device entries for the duration of the stream and re-enables them afterwards. A standby monitor or TV that keeps waking its connection (auto input scan, instant-on) can no longer interrupt the stream — Windows ignores its wake events entirely while the device is disabled. If the host crashes mid-stream, the monitors are re-enabled the next time it starts; until then you can re-enable them manually in Device Manager.",
|
|
"display_pnp_disabled": "Off",
|
|
"display_pnp_enabled": "On",
|
|
"display_pnp_badge": "Monitor devices disabled (PnP)",
|
|
"display_identity_shared": "Shared",
|
|
"display_identity_per_client": "Per client",
|
|
"display_identity_per_client_mode": "Per client + resolution",
|
|
"display_layout_mode": "Multi-monitor layout",
|
|
"display_layout_help": "Auto lays displays out side by side, left to right. Manual: you position each one yourself — a per-display X/Y editor appears in the Live displays section below once two or more are streaming.",
|
|
"display_layout_auto_row": "Auto (side by side)",
|
|
"display_layout_manual": "Manual",
|
|
"display_preset_custom_label": "Custom presets",
|
|
"display_preset_save_as": "Save as preset…",
|
|
"display_preset_name": "Preset name",
|
|
"display_preset_edit": "Rename",
|
|
"display_preset_update": "Update to current settings",
|
|
"display_preset_delete": "Delete",
|
|
"display_preset_delete_confirm": "Delete this custom preset?",
|
|
"clients_title": "Paired clients",
|
|
"clients_empty": "No paired clients yet.",
|
|
"clients_name": "Name",
|
|
"clients_fingerprint": "Fingerprint",
|
|
"clients_unpair_confirm": "Unpair this client? It will need to pair again to connect.",
|
|
"pairing_title": "Pairing",
|
|
"pairing_idle": "No pairing in progress. Start pairing from a Moonlight client, then enter its PIN here.",
|
|
"pairing_waiting": "A client is waiting to pair. Enter the PIN it shows:",
|
|
"pairing_pin_label": "PIN",
|
|
"pairing_submit": "Submit PIN",
|
|
"pairing_success": "Paired successfully.",
|
|
"pairing_failed": "Pairing failed — check the PIN and try again.",
|
|
"pairing_native_title": "Pair a device",
|
|
"pairing_native_desc": "Show a one-time PIN here, then enter it in your Punktfunk app to pair this device.",
|
|
"pairing_native_disabled": "The native host isn't running. Start it with `serve --native` to pair Punktfunk devices.",
|
|
"pairing_native_arm": "Pair a device",
|
|
"pairing_native_enter": "Enter this PIN on your device:",
|
|
"pairing_native_expires": "Expires in",
|
|
"pairing_native_cancel": "Cancel",
|
|
"pairing_native_devices": "Paired devices",
|
|
"pairing_native_empty": "No devices paired yet.",
|
|
"pairing_native_unpair_confirm": "Unpair this device? It will need to pair again to connect.",
|
|
"pairing_protocol": "Protocol",
|
|
"pairing_protocol_native": "punktfunk/1",
|
|
"pairing_protocol_moonlight": "Moonlight",
|
|
"pairing_pending_title": "Waiting for approval",
|
|
"pairing_pending_desc": "These devices tried to connect. Approving pairs a device immediately — no PIN needed.",
|
|
"pairing_pending_approve": "Approve",
|
|
"pairing_pending_deny": "Deny",
|
|
"pairing_pending_name_prompt": "Name this device:",
|
|
"pairing_pending_age_just_now": "just now",
|
|
"pairing_pending_age_secs": "{s}s ago",
|
|
"pairing_pending_age_mins": "{min} min ago",
|
|
"pairing_moonlight_title": "Moonlight (GameStream) pairing",
|
|
"library_title": "Library",
|
|
"library_empty": "No games found yet.",
|
|
"library_store_steam": "Steam",
|
|
"library_store_custom": "Custom",
|
|
"library_add_title": "Add a custom game",
|
|
"library_edit_title": "Edit custom game",
|
|
"library_add_button": "Add custom game",
|
|
"library_field_title": "Title",
|
|
"library_field_portrait": "Portrait art URL",
|
|
"library_field_hero": "Hero art URL",
|
|
"library_field_header": "Header art URL",
|
|
"library_field_command": "Launch command",
|
|
"library_field_command_help": "Optional. The command the host runs to launch this title.",
|
|
"library_save": "Save",
|
|
"library_create": "Add",
|
|
"library_cancel": "Cancel",
|
|
"library_edit": "Edit",
|
|
"library_delete": "Delete",
|
|
"library_delete_confirm": "Delete this custom game? This can't be undone.",
|
|
"settings_title": "Settings",
|
|
"settings_token_label": "API token",
|
|
"settings_token_help": "Bearer token for the management API. Leave empty for a loopback host with no token.",
|
|
"settings_language": "Language",
|
|
"settings_save": "Save",
|
|
"settings_saved": "Saved.",
|
|
"common_loading": "Loading…",
|
|
"common_error": "Something went wrong.",
|
|
"common_retry": "Retry",
|
|
"common_yes": "Yes",
|
|
"common_cancel": "Cancel",
|
|
"common_unauthorized": "Session expired — redirecting to sign in…",
|
|
"login_title": "Sign in",
|
|
"login_subtitle": "Enter the management password to continue. Don't know what to do?",
|
|
"login_docs_link": "Visit the documentation",
|
|
"login_password": "Password",
|
|
"login_submit": "Sign in",
|
|
"login_error": "Wrong password.",
|
|
"login_signing_in": "Signing in…",
|
|
"action_logout": "Sign out",
|
|
"nav_stats": "Performance",
|
|
"nav_logs": "Logs",
|
|
"logs_title": "Logs",
|
|
"logs_subtitle": "The host's recent log stream — follow live, filter by level, search.",
|
|
"logs_follow": "Follow",
|
|
"logs_pause": "Pause",
|
|
"logs_clear": "Clear",
|
|
"logs_search": "Search logs…",
|
|
"logs_empty": "No log entries match — adjust the filter or wait for host activity.",
|
|
"logs_dropped": "Some entries were evicted before they could be fetched",
|
|
"stats_title": "Performance",
|
|
"stats_subtitle": "Record a session's pipeline timings and review them as graphs.",
|
|
"stats_capture_title": "Capture",
|
|
"stats_capture_desc": "Arm capture, run a session, then stop to save a recording. Sampling runs at the host's aggregation boundary — no per-frame overhead.",
|
|
"stats_recording": "Recording",
|
|
"stats_idle": "Idle",
|
|
"stats_start": "Start capture",
|
|
"stats_stop": "Stop & save",
|
|
"stats_elapsed": "Elapsed",
|
|
"stats_samples": "Samples",
|
|
"stats_kind": "Path",
|
|
"stats_kind_native": "Native",
|
|
"stats_kind_gamestream": "GameStream",
|
|
"stats_live_title": "Live",
|
|
"stats_live_waiting": "Armed — waiting for the first samples. Start a session to begin recording.",
|
|
"stats_latency_title": "Latency by stage",
|
|
"stats_latency_axis": "µs",
|
|
"stats_latency_desc": "Per-stage pipeline time, stacked — the \"where does the time go\" view.",
|
|
"stats_throughput_title": "Throughput",
|
|
"stats_health_title": "Health",
|
|
"stats_fps_new": "New fps",
|
|
"stats_fps_repeat": "Repeat fps",
|
|
"stats_mbps": "Mb/s",
|
|
"stats_p99": "p99",
|
|
"stats_p50": "p50",
|
|
"stats_frames_dropped": "Frames dropped",
|
|
"stats_packets_dropped": "Packets dropped",
|
|
"stats_send_dropped": "Send drops",
|
|
"stats_fec_recovered": "FEC recovered",
|
|
"stats_recordings_title": "Recordings",
|
|
"stats_recordings_empty": "No recordings yet. Start a capture to record one.",
|
|
"stats_col_time": "Time",
|
|
"stats_col_kind": "Path",
|
|
"stats_col_resolution": "Resolution",
|
|
"stats_col_codec": "Codec",
|
|
"stats_col_duration": "Duration",
|
|
"stats_col_samples": "Samples",
|
|
"stats_view": "View",
|
|
"stats_download": "Download",
|
|
"stats_delete": "Delete",
|
|
"stats_delete_confirm": "Delete this recording? This can't be undone.",
|
|
"stats_detail_title": "Recording detail",
|
|
"stats_close": "Close",
|
|
"stats_no_samples": "This recording has no samples."
|
|
}
|