Files
punktfunk/web/messages/en.json
T
enricobuehler 833f3348a0
apple / swift (push) Successful in 1m22s
release / apple (push) Successful in 9m59s
windows-host / package (push) Successful in 9m52s
windows-msix / package (arm64, C:\Users\Public\ffmpeg-arm64, --no-default-features, aarch64-pc-windows-msvc, C:\t-a64) (push) Successful in 3m20s
apple / screenshots (push) Successful in 6m28s
windows-msix / package (x64, C:\Users\Public\ffmpeg, , x86_64-pc-windows-msvc, C:\t) (push) Successful in 3m21s
windows / build (aarch64-pc-windows-msvc) (push) Successful in 4m39s
windows / build (x86_64-pc-windows-msvc) (push) Successful in 5m45s
audit / cargo-audit (push) Successful in 2m58s
audit / bun-audit (push) Successful in 13s
ci / web (push) Successful in 52s
ci / docs-site (push) Successful in 59s
android / android (push) Has been cancelled
arch / build-publish (push) Has been cancelled
ci / bench (push) Has been cancelled
ci / rust (push) Has been cancelled
docker / build-push (--build-arg FEDORA_VERSION=44, ci, ci/fedora-rpm.Dockerfile, punktfunk-fedora44-rpm) (push) Successful in 11s
docker / build-push (ci, ci/fedora-rpm.Dockerfile, punktfunk-fedora-rpm) (push) Successful in 10s
decky / build-publish (push) Successful in 23s
docker / build-push (ci, ci/rust-ci.Dockerfile, punktfunk-rust-ci) (push) Successful in 10s
docker / build-push (ci, ci/rust-ci-noble.Dockerfile, punktfunk-rust-ci-noble) (push) Successful in 10s
docker / build-push (., web/Dockerfile, punktfunk-web) (push) Successful in 35s
docker / build-push (docs-site, docs-site/Dockerfile, punktfunk-docs) (push) Successful in 49s
flatpak / build-publish (push) Successful in 7m53s
docker / deploy-docs (push) Has been cancelled
rpm / build-publish (43, bazzite, punktfunk-fedora-rpm) (push) Has been cancelled
rpm / build-publish (44, fedora-44, punktfunk-fedora44-rpm) (push) Has been cancelled
deb / build-publish (push) Successful in 11m41s
deb / build-publish-host (push) Successful in 13m32s
feat(store): console plugin store, index repo, and the fixes on-glass found
Console: a Plugins section (Browse / Installed / Sources) on a static nav
entry, with install friction proportional to trust — a plain confirm for a
verified entry, a warning naming the curator for an external one, and a
danger dialog that makes you retype the spec for a raw package. Tier badges
are permanent and follow the plugin onto its own UI page.

Index: unom/punktfunk-plugin-index published and served from Gitea's raw
endpoint (real HTTPS, byte-exact, no vhost to stand up) — merge to main is
publish, which resolves the design's open hosting question.

Four things only running it could find:
- runner discovery matched @punktfunk/plugin-* only, so a third-party
  scoped plugin (which D8 requires) would install and never run
- ...and that convention also matches @punktfunk/plugin-kit, a plugin's
  own framework: it listed as installed and would have been imported as a
  unit. Both now key off the plugins dir's top-level dependencies, with an
  emptied dependency list meaning 'nothing installed' rather than falling
  back to the naming convention
- the store must not pass new flags to the runner: the scripting package
  ships separately and an older one reads an unknown flag's value as a
  package name. The host writes the bunfig scope mapping itself
- ureq reports only >= 400 as Err, so a conditional request's 304 arrives
  as Ok with an empty body — handled as an error it made every refresh
  after the first verify a signature over zero bytes and sit stale

Also: the console's first Tabs use exposed an @unom/ui theme gap that
rendered inactive tabs invisible (caught in a browser pass, not by types).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-20 20:48:02 +02:00

379 lines
21 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",
"nav_plugins": "Plugins",
"plugin_offline_title": "This plugin isn't running",
"plugin_offline_hint": "Start the scripting runner, then retry.",
"plugin_retry": "Retry",
"plugin_open_new_tab": "Open in new tab",
"status_title": "Live status",
"status_video": "Video",
"status_audio": "Audio",
"status_streaming": "Streaming",
"status_idle": "Idle",
"status_session": "Session",
"status_sessions_active": "{count} active",
"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": "Headless box",
"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_forever": "Forever",
"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_pin_sent": "PIN sent. If it's correct, the client finishes pairing and appears under Paired devices below.",
"pairing_failed": "Couldn't submit the PIN — check it's correct and that the client is still waiting to pair.",
"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_sources_title": "Game sources",
"library_sources_help": "Launchers this host scans for installed games. Turn one off to hide its games from every device — nothing is deleted, and turning it back on brings them right back.",
"library_sources_failed": "Could not update the game source.",
"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_logo": "Logo 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",
"settings_logout_failed": "Sign-out failed — you're still signed in. Please try again.",
"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_bitrate_target": "Target Mb/s",
"stats_health_gamestream_note": "Packet loss, send-drops, and FEC recovery are receiver-side metrics the GameStream path doesn't instrument — only frame drops are shown here.",
"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.",
"store_title": "Plugins",
"store_subtitle": "Browse the plugin catalog, install and remove plugins, and choose which catalogs this host trusts.",
"store_tab_browse": "Browse",
"store_tab_installed": "Installed",
"store_tab_sources": "Sources",
"store_tier_verified": "Verified",
"store_tier_verified_hint": "From the built-in unom catalog — unom reviewed this exact package.",
"store_tier_external": "External source",
"store_tier_external_hint": "Pinned and integrity-checked, but curated by someone other than unom. Nobody at unom reviewed this code.",
"store_tier_unverified": "Unverified",
"store_tier_unverified_hint": "Installed from a raw package spec. No catalog, no review — nobody checked this code.",
"store_tier_cli": "Installed via CLI",
"store_tier_cli_hint": "Installed from the command line, so the host has no record of where it came from.",
"store_from_source": "from",
"store_search_placeholder": "Search plugins…",
"store_filter_all": "All sources",
"store_empty": "No plugins in the catalog yet.",
"store_no_match": "No plugin matches your search.",
"store_by_author": "by {author}",
"store_homepage": "Homepage",
"store_install": "Install",
"store_installed_label": "Installed",
"store_update_to": "Update to {version}",
"store_incompatible": "Not compatible with this host.",
"store_blocked": "Blocked by the host: {reason}",
"store_spec_open": "Install from package spec…",
"store_runner_title": "Plugin runner",
"store_runner_help": "The service every plugin runs inside. Disabling it stops all plugins at once without uninstalling anything.",
"store_runner_not_installed": "The plugin runner isn't installed on this host, so plugins can't start.",
"store_runner_banner": "The plugin runner is switched off — plugins won't start until you enable it.",
"store_runner_enable": "Enable runner",
"store_runner_disable": "Disable runner",
"store_runner_state_running": "Running",
"store_runner_state_stopped": "Stopped",
"store_runner_state_disabled": "Disabled",
"store_runner_state_missing": "Not installed",
"store_runner_unit": "Service",
"store_runner_principal": "Runs as",
"store_runner_failed": "Could not change the plugin runner.",
"store_installed_title": "Installed plugins",
"store_installed_empty": "No plugins installed yet.",
"store_running": "Running",
"store_stopped": "Not running",
"store_uninstall": "Uninstall",
"store_uninstall_confirm": "Uninstall {title}? You can install it again from the catalog.",
"store_uninstall_failed": "Could not start the removal.",
"store_update_no_entry": "That plugin isn't in any catalog right now — refresh the sources and try again.",
"store_sources_title": "Catalog sources",
"store_sources_help": "Where this host looks for plugins. The built-in unom catalog is always present; every other source is one you added and vouch for yourself.",
"store_refresh_all": "Refresh all",
"store_refresh_failed": "Could not refresh the catalogs.",
"store_source_builtin": "Built in",
"store_source_signed": "Signed",
"store_source_unsigned": "Unsigned",
"store_source_stale": "Out of date",
"store_source_entries": "{count} plugins",
"store_source_fetched": "last fetched {when}",
"store_source_never": "never",
"store_source_remove": "Remove source",
"store_source_remove_confirm": "Remove the source “{name}”? Plugins already installed from it stay installed.",
"store_source_remove_failed": "Could not remove the source.",
"store_source_builtin_locked": "The built-in unom catalog can't be removed.",
"store_add_source_title": "Add a catalog source",
"store_field_source_name": "Name",
"store_field_source_url": "Index URL",
"store_field_source_key": "Public key (optional)",
"store_field_source_key_help": "An ed25519:… key. With a key set, the host only accepts a signed index from this source.",
"store_add_source": "Add source",
"store_add_source_failed": "Could not save the source — check the name and the URL.",
"store_source_trust_title": "Trust this source?",
"store_source_trust_body": "Everything you install from “{name}” is code unom has not reviewed. It runs on this host with the plugin runner's privileges. Only add a catalog whose operator you trust.",
"store_source_trust_unsigned": "Without a public key the host can't tell whether this index was tampered with in transit.",
"store_source_trust_confirm": "I understand — add the source",
"store_install_title": "Install {title}?",
"store_install_verified_body": "Version {version} from the built-in unom catalog. unom reviewed this exact package.",
"store_install_confirm": "Install",
"store_install_external_title": "Install {title} from an external source?",
"store_install_external_body": "Version {version} comes from “{source}”, a catalog you added yourself.",
"store_install_external_note": "unom has not reviewed this code. The package is pinned and integrity-checked, but it will run on this host with the plugin runner's privileges.",
"store_install_external_confirm": "Install anyway",
"store_install_failed": "Could not start the install.",
"store_busy": "The host is already installing or removing a plugin. Try again once it's finished.",
"store_spec_title": "Install from a package spec",
"store_spec_lead": "This installs code straight from a package registry. It is in no catalog, nobody has reviewed it, and it will run on this host with the plugin runner's privileges — the same access it has to your files and your session.",
"store_spec_permanent": "A plugin installed this way stays marked Unverified for as long as it is installed.",
"store_spec_field": "Package spec",
"store_spec_field_help": "For example @scope/plugin-name@1.2.3.",
"store_spec_confirm_field": "Type the package spec again to confirm",
"store_spec_checkbox": "I understand that this runs unreviewed code with operator privileges.",
"store_spec_confirm": "Install unverified",
"store_job_install": "Installing {target}",
"store_job_uninstall": "Removing {target}",
"store_job_done_install": "Installed.",
"store_job_done_uninstall": "Removed.",
"store_job_failed": "The job failed.",
"store_job_restarting": "The plugin runner is restarting — the sidebar catches up in a moment.",
"store_job_log": "Show log",
"store_job_dismiss": "Dismiss",
"store_phase_queued": "Queued",
"store_phase_verifying": "Verifying the package",
"store_phase_installing": "Installing",
"store_phase_removing": "Removing",
"store_phase_checking": "Checking the install",
"store_phase_rolling_back": "Rolling back",
"store_phase_recording": "Recording provenance",
"store_phase_restarting": "Restarting the plugin runner",
"store_phase_done": "Done"
}