Merge origin/i18n-spanish: whole-interface translation meets KartaView

This branch moved twice at once: upstream merged KartaView (#1121, a
third keyless street-level provider sharing a new lineCoverage.js), and
the remote i18n-spanish gained the whole-interface translation work
(1993 catalog entries, translateKnown, data-i18n-runtime, the unmarked-
string detector in npm run i18n) built on the Street View merge.

Integration keeps the remote's mechanisms and re-adds KartaView on top:

- presentMeta: remote's translateHint for coverage hints, plus the
  KartaView count line as its own literal tn pair (Russian plurals need
  the noun inside the template; keyed off coverageLabel.noun with the
  sequences pair as the default).
- uiState: upstream's highlightsSequence legend gate (KartaView's lines
  do not highlight) with t('Selected').
- layer-panels.html: remote's data-i18n/data-i18n-runtime hooks plus the
  sl-since-note wiring KartaView's upload-date SINCE note needs.
- kartaview viewer: the photo-navigation aria-label and img alt go
  through t(), as the remote's unmarked-string detector requires.
- catalogs: remote's 1987-entry base (its refined keys supersede this
  branch's earlier Street View wording) plus the KartaView entries:
  coverage hints, the upload-date note, the streets count line (with
  Russian one/few/many/other forms) and the viewer strings.

npm run i18n: complete, no unmarked strings. npm test: 6520/6522 (the
one failure is the pre-existing environmental OPENAI_API_KEY leak in
devFreshDotenv). Build passes.
This commit is contained in:
Meir Michanie committed 2026-10-14 17:45:57 +02:00
commit 32b11e27de
176 files changed
+9713 -2210

No files matched your search

+22 -22
View File
@@ -113,7 +113,7 @@
<div class="cockpit-topline">
<div>
<span class="cockpit-kicker" data-i18n>FIRST PERSON</span>
<strong id="cockpit-callsign">AIRCRAFT</strong>
<strong id="cockpit-callsign" data-i18n>AIRCRAFT</strong>
<span id="cockpit-aircraft-meta" class="cockpit-aircraft-meta" data-i18n>LIVE TRACK · COURSE ALIGNED</span>
</div>
<div class="cockpit-vision-controls" role="group" aria-label="Cockpit vision style" data-i18n-aria-label>
@@ -123,7 +123,7 @@
</button>
<button id="cockpit-vision-current" class="cockpit-vision-current" type="button" data-cockpit-vision="optical" aria-label="Current cockpit vision style: NORMAL. Activate for next style." title="Current style: NORMAL — click for next" data-i18n-aria-label data-i18n-title>
<small data-i18n>CURRENT</small>
<strong id="cockpit-vision-current-label" aria-live="polite">NORMAL</strong>
<strong id="cockpit-vision-current-label" aria-live="polite" data-i18n>NORMAL</strong>
</button>
<button id="cockpit-vision-next" class="cockpit-vision-nav" type="button" aria-label="Next cockpit vision style" title="Next vision style" data-i18n-aria-label data-i18n-title>
<small data-i18n>NEXT</small>
@@ -137,13 +137,13 @@
<div class="cockpit-readout cockpit-speed">
<span class="cockpit-readout-label" data-i18n>GROUND SPEED</span>
<strong id="cockpit-speed-value">---</strong>
<span class="cockpit-readout-unit">KTS</span>
<span class="cockpit-readout-unit" data-i18n>KTS</span>
</div>
<div class="cockpit-heading-value"><span id="cockpit-heading-value">---</span><small>°</small></div>
<div class="cockpit-readout cockpit-altitude">
<span class="cockpit-readout-label" data-i18n>ALTITUDE</span>
<strong id="cockpit-altitude-value">-----</strong>
<span class="cockpit-readout-unit">FT</span>
<span class="cockpit-readout-unit" data-i18n>FT</span>
</div>
</div>
<span class="cockpit-heading-caret material-symbols-outlined" aria-hidden="true">arrow_drop_down</span>
@@ -156,7 +156,7 @@
<aside id="cockpit-context" class="cockpit-context-window" aria-label="Contact cockpit summary" hidden data-i18n-aria-label>
<header class="cockpit-context-header">
<div>
<span class="cockpit-context-kicker">CONTACT</span>
<span data-i18n class="cockpit-context-kicker">CONTACT</span>
<strong id="cockpit-context-subject" data-i18n>CONTACTS · 250 KM</strong>
</div>
<nav class="cockpit-context-actions" aria-label="Contact navigation" data-i18n-aria-label>
@@ -173,10 +173,10 @@
<span class="cockpit-context-qualifier" data-i18n>CONTEXT ONLY</span>
</header>
<div class="cockpit-context-cohorts" role="list" aria-label="Nearby cohort counts" data-i18n-aria-label>
<div role="listitem" data-context-cohort="flights"><span>FLT</span><strong>—</strong><small>OpenSky</small></div>
<div role="listitem" data-context-cohort="military"><span>MIL</span><strong>—</strong><small>adsb.lol</small></div>
<div role="listitem" data-context-cohort="ais-live-vessels"><span>AIS</span><strong>—</strong><small>AISStream</small></div>
<div role="listitem" data-context-cohort="military-installations"><span>SITE</span><strong>—</strong><small>OpenStreetMap</small></div>
<div role="listitem" data-context-cohort="flights"><span data-i18n>FLT</span><strong>—</strong><small translate="no">OpenSky</small></div>
<div role="listitem" data-context-cohort="military"><span data-i18n>MIL</span><strong>—</strong><small translate="no">adsb.lol</small></div>
<div role="listitem" data-context-cohort="ais-live-vessels"><span translate="no">AIS</span><strong>—</strong><small translate="no">AISStream</small></div>
<div role="listitem" data-context-cohort="military-installations"><span data-i18n>SITE</span><strong>—</strong><small translate="no">OpenStreetMap</small></div>
</div>
<div class="cockpit-context-nearest">
<span id="cockpit-context-direction" class="material-symbols-outlined" aria-hidden="true">navigation</span>
@@ -197,8 +197,8 @@
aria-pressed="false"
title="Enable cockpit weather effects" data-i18n-aria-label data-i18n-title
>
<span>WX</span>
<strong id="cockpit-weather-state">OFF</strong>
<span data-i18n>WX</span>
<strong data-i18n id="cockpit-weather-state">OFF</strong>
</button>
<time id="cockpit-context-updated">--:--:--Z</time>
</footer>
@@ -223,7 +223,7 @@
</section>
<header class="cockpit-signal-header">
<div class="cockpit-brief-heading">
<span id="cockpit-brief-kicker" class="cockpit-signal-kicker"><i aria-hidden="true"></i> LIVE SIGNALS</span>
<span id="cockpit-brief-kicker" class="cockpit-signal-kicker" data-i18n-runtime><i aria-hidden="true"></i> LIVE SIGNALS</span>
<strong id="cockpit-brief-subtitle" data-i18n>OBSERVED / MAPPED PINGS</strong>
</div>
<nav class="cockpit-brief-actions" aria-label="Cockpit briefing controls" data-i18n-aria-label>
@@ -239,7 +239,7 @@
type="button"
aria-label="CYCLE OFF"
aria-pressed="false"
title="Cycle briefing pages automatically every 9 seconds (Signals → News → Local). Pauses while you hover or focus the panel. Live signal data refreshes continuously either way." data-i18n-title
title="Cycle briefing pages automatically every 9 seconds (Signals → News → Local). Pauses while you hover or focus the panel. Live signal data refreshes continuously either way." data-i18n-title data-i18n-aria-label data-i18n
>CYCLE OFF</button>
<button id="cockpit-signal-toggle" type="button" aria-label="Collapse cockpit briefing panel" aria-expanded="true" title="Collapse briefing panel" data-i18n-aria-label data-i18n-title>
<span class="material-symbols-outlined" aria-hidden="true">right_panel_close</span>
@@ -260,20 +260,20 @@
<small id="cockpit-local-coordinates">--</small>
</div>
<div class="cockpit-local-grid">
<div><span data-i18n>TEMP</span><strong id="cockpit-local-temperature">—</strong><small>OPEN-METEO</small></div>
<div><span data-i18n>TEMP</span><strong id="cockpit-local-temperature">—</strong><small translate="no">OPEN-METEO</small></div>
<div><span data-i18n>WIND</span><strong id="cockpit-local-wind">—</strong><small id="cockpit-local-wind-direction">—</small></div>
<div><span data-i18n>SKY</span><strong id="cockpit-local-condition">UNKNOWN</strong><small id="cockpit-local-cloud">—</small></div>
<div><span data-i18n>PRECIP</span><strong id="cockpit-local-precipitation">—</strong><small>MM</small></div>
<div><span data-i18n>SKY</span><strong id="cockpit-local-condition" data-i18n>UNKNOWN</strong><small id="cockpit-local-cloud">—</small></div>
<div><span data-i18n>PRECIP</span><strong id="cockpit-local-precipitation">—</strong><small data-i18n>MM</small></div>
</div>
<a class="cockpit-weather-credit" href="https://open-meteo.com/" target="_blank" rel="noopener">Weather data by Open-Meteo.com</a>
<a class="cockpit-weather-credit" href="https://open-meteo.com/" target="_blank" rel="noopener" data-i18n>Weather data by Open-Meteo.com</a>
</section>
</div>
<footer class="cockpit-signal-footer">
<span id="cockpit-brief-source" data-i18n>SOURCE-BACKED EVENTS · NO SYNTHETIC NEWS</span>
<nav class="cockpit-brief-tabs" aria-label="Cockpit briefing pages">
<button type="button" data-cockpit-brief-index="0" aria-label="Show Live Signals" aria-current="true" data-i18n-aria-label>SIG</button>
<button type="button" data-cockpit-brief-index="1" aria-label="Show Regional News" data-i18n-aria-label>NEWS</button>
<button type="button" data-cockpit-brief-index="2" aria-label="Show Local Info" data-i18n-aria-label>LOCAL</button>
<nav class="cockpit-brief-tabs" aria-label="Cockpit briefing pages" data-i18n-aria-label>
<button type="button" data-cockpit-brief-index="0" aria-label="Show Live Signals" aria-current="true" data-i18n-aria-label data-i18n>SIG</button>
<button type="button" data-cockpit-brief-index="1" aria-label="Show Regional News" data-i18n-aria-label data-i18n>NEWS</button>
<button type="button" data-cockpit-brief-index="2" aria-label="Show Local Info" data-i18n-aria-label data-i18n>LOCAL</button>
</nav>
</footer>
</aside>
@@ -313,7 +313,7 @@
</div>
</div>
</aside>
<div class="cockpit-help">ESC EXIT <span>·</span> C TOGGLE</div>
<div class="cockpit-help"><bdi data-i18n>ESC EXIT</bdi> <span>·</span> <bdi data-i18n>C TOGGLE</bdi></div>
</section>
<nav id="view-switcher" aria-label="View switcher" data-i18n-aria-label>
+5 -5
View File
@@ -7,7 +7,7 @@
<button id="control-panel-toggle" class="panel-header dock-tray-toggle" type="button"
data-dock-toggle-target="control-panel" aria-expanded="false"
aria-controls="control-panel-popover" aria-label="Expand Visual Presets" data-i18n-aria-label>
<span class="panel-title"><span class="dock-label-icon dock-label-icon-presets" aria-hidden="true"></span>VISUAL PRESETS</span>
<span class="panel-title" data-i18n-runtime><span class="dock-label-icon dock-label-icon-presets" aria-hidden="true"></span>VISUAL PRESETS</span>
<span class="panel-divider"></span>
</button>
<!-- Language selector: buttons are rendered by applicationShell _initLocaleSelector(), one per shipped locale. -->
@@ -53,15 +53,15 @@
</div>
<section class="map-source-section" aria-labelledby="map-source-label">
<div class="map-source-heading">
<span id="map-source-label">MAP SOURCE</span>
<span data-i18n id="map-source-label">MAP SOURCE</span>
<span id="map-stack-status" class="pp-stack-status" aria-live="polite">3D</span>
</div>
<div id="map-stack-chips" class="map-stack-chip-row" role="group" aria-label="Map source"></div>
<div id="map-stack-chips" class="map-stack-chip-row" role="group" aria-label="Map source" data-i18n-aria-label></div>
</section>
</div>
<div id="style-mini-status" class="panel-mini-status" aria-live="polite">
<span class="panel-mini-label" data-i18n>Style</span>
<span id="style-mini-value" class="panel-mini-value">NORMAL</span>
<span id="style-mini-value" class="panel-mini-value" data-i18n>NORMAL</span>
</div>
</div>
</div>
@@ -72,7 +72,7 @@
<div class="location-inner">
<div class="location-toolbar">
<button id="location-bar-toggle" class="dock-tray-toggle" type="button" data-dock-toggle-target="location-bar" aria-controls="location-bar-popover" aria-expanded="false" aria-label="Expand LOCATION" title="Expand LOCATION" data-i18n-aria-label data-i18n-title>
<span class="location-toolbar-label"><span class="dock-label-icon dock-label-icon-location" aria-hidden="true"></span>LOCATION</span>
<span class="location-toolbar-label" data-i18n-runtime><span class="dock-label-icon dock-label-icon-location" aria-hidden="true"></span>LOCATION</span>
</button>
<button class="panel-collapse-btn" data-collapse-target="location-bar" title="Collapse panel" data-i18n-title>+</button>
</div>
+65 -66
View File
@@ -4,10 +4,10 @@
<div class="panel-glow"></div>
<div class="weather-panel-inner" data-rail-scroller>
<div class="panel-header">
<span class="panel-title">WEATHER</span>
<span id="weather-panel-count" aria-label="Active weather products">0</span>
<span class="panel-title" data-i18n>WEATHER</span>
<span id="weather-panel-count" aria-label="Active weather products" data-i18n-aria-label>0</span>
<span class="panel-divider"></span>
<button class="panel-collapse-btn" data-collapse-target="weather-panel" type="button" title="Collapse panel">▼</button>
<button class="panel-collapse-btn" data-collapse-target="weather-panel" type="button" title="Collapse panel" data-i18n-title>▼</button>
</div>
<div id="weather-panel-body" data-rail-scroller></div>
</div>
@@ -16,10 +16,10 @@
<div class="panel-glow"></div>
<div class="recent-imagery-panel-inner" data-rail-scroller>
<div class="panel-header">
<span class="panel-title">RECENT IMAGERY</span>
<span id="recent-imagery-panel-count" aria-label="Imagery days in the box"></span>
<span class="panel-title" data-i18n>RECENT IMAGERY</span>
<span id="recent-imagery-panel-count" aria-label="Imagery days in the box" data-i18n-aria-label></span>
<span class="panel-divider"></span>
<button class="panel-collapse-btn" data-collapse-target="recent-imagery-panel" type="button" title="Collapse panel">▼</button>
<button class="panel-collapse-btn" data-collapse-target="recent-imagery-panel" type="button" title="Collapse panel" data-i18n-title>▼</button>
</div>
<div id="recent-imagery-panel-body" data-rail-scroller></div>
</div>
@@ -75,7 +75,7 @@
</div>
<div id="context-mode-standby" class="context-mode-standby">
<strong data-i18n>SELECT CONTEXT</strong>
<span>CONTACTS — nearest planes · vessels · sites<br>SPACE MISSIONS — launches &amp; orbital assets</span>
<span data-i18n-runtime>CONTACTS — nearest planes · vessels · sites<br>SPACE MISSIONS — launches &amp; orbital assets</span>
</div>
<section id="context-flights-view" class="context-mode-view" role="tabpanel" aria-labelledby="global-context-flights-btn" hidden>
<div class="global-context-actions" aria-label="Contact Context actions" data-i18n-aria-label>
@@ -114,7 +114,7 @@
<div class="radio-panel-inner">
<div class="panel-header">
<span class="panel-title" data-i18n>RADIO</span>
<span id="radio-layer-state" class="radio-layer-state">OFF</span>
<span id="radio-layer-state" class="radio-layer-state" data-i18n>OFF</span>
<span class="panel-divider"></span>
<button class="panel-collapse-btn" data-collapse-target="radio-panel" title="Expand Radio" aria-label="Expand Radio section" data-i18n-title data-i18n-aria-label>+</button>
</div>
@@ -132,14 +132,14 @@
</div>
<div id="radio-tuner" class="radio-tuner" hidden>
<div class="radio-tuner-header">
<span id="radio-tuner-band-label">DIRECTORY BAND</span>
<span data-i18n id="radio-tuner-band-label">DIRECTORY BAND</span>
<output id="radio-tuner-value" for="radio-tuner-slider" data-i18n>DRAG TO TUNE</output>
</div>
<div class="radio-tuner-dial">
<div class="radio-tuner-scale" aria-hidden="true"></div>
<div id="radio-tuner-needle" class="radio-tuner-needle" aria-hidden="true"></div>
<input id="radio-tuner-slider" type="range" min="0" max="0" step="1" value="0"
aria-label="Tune available internet radio stations" aria-valuetext="No station available" disabled />
aria-label="Tune available internet radio stations" aria-valuetext="No station available" disabled data-i18n-aria-label />
</div>
<div class="radio-tuner-readout">
<span id="radio-tuner-station" data-i18n>ALL · DRAG THE NEEDLE</span>
@@ -160,81 +160,80 @@
<div id="radio-playback-state" class="radio-playback-state" role="status" aria-live="polite" data-i18n>Radio off</div>
<div class="radio-links">
<a id="radio-station-homepage" href="#" target="_blank" rel="noopener noreferrer" hidden data-i18n>STATION SITE</a>
<a href="https://www.radio-browser.info/" target="_blank" rel="noopener noreferrer">DIRECTORY: RADIO BROWSER</a>
<a href="https://www.radio-browser.info/" target="_blank" rel="noopener noreferrer" data-i18n>DIRECTORY: RADIO BROWSER</a>
</div>
<p class="radio-privacy" data-i18n>Audio connects directly to the broadcaster after you press play. Your IP is visible to that broadcaster.</p>
<p class="radio-privacy">Audio connects directly to the broadcaster after you press play. Your IP is visible to that broadcaster.</p>
<div id="sdr-radio-card" class="sdr-radio-card" role="group" aria-label="Local RTL-SDR receiver">
<div id="sdr-radio-card" class="sdr-radio-card" role="group" aria-label="Local RTL-SDR receiver" data-i18n-aria-label>
<div class="sdr-radio-heading">
<strong>LOCAL RTL-SDR</strong>
<span id="sdr-connection-state">NO USB</span>
<strong data-i18n>LOCAL RTL-SDR</strong>
<span id="sdr-connection-state" data-i18n-runtime>NO USB</span>
</div>
<p>Chrome/Edge · WebUSB · one local tuner shared by FM and the Local ADS-B layer.</p>
<p data-i18n>Chrome/Edge · WebUSB · one local tuner shared by FM and the Local ADS-B layer.</p>
<div class="sdr-radio-actions">
<button id="sdr-connect-btn" class="panel-layer-toggle" type="button" aria-pressed="false">CONNECT</button>
<button id="sdr-locate-btn" type="button" title="Use your location for faster ADS-B position decoding">LOCATE</button>
<button id="sdr-change-device-btn" type="button" title="Choose a different RTL-SDR or receiver channel">CHANGE DEVICE</button>
<button id="sdr-connect-btn" class="panel-layer-toggle" type="button" aria-pressed="false" data-i18n>CONNECT</button>
<button id="sdr-locate-btn" type="button" title="Use your location for faster ADS-B position decoding" data-i18n-title data-i18n>LOCATE</button>
<button id="sdr-change-device-btn" type="button" title="Choose a different RTL-SDR or receiver channel" data-i18n-title data-i18n>CHANGE DEVICE</button>
</div>
<div class="sdr-mode-row" role="group" aria-label="RTL-SDR receiver mode">
<button id="sdr-mode-fm-btn" class="active" type="button" aria-pressed="true">FM</button>
<button id="sdr-mode-adsb-btn" type="button" aria-pressed="false">ADS-B · 1090</button>
<div class="sdr-mode-row" role="group" aria-label="RTL-SDR receiver mode" data-i18n-aria-label>
<button id="sdr-mode-fm-btn" class="active" type="button" aria-pressed="true" translate="no">FM</button>
<button id="sdr-mode-adsb-btn" type="button" aria-pressed="false" translate="no">ADS-B · 1090</button>
</div>
<div class="sdr-gain-row">
<label for="sdr-gain-select">GAIN</label>
<select id="sdr-gain-select" aria-label="RTL-SDR tuner gain for the current mode">
<option value="auto">AUTO</option>
<option value="0.0">0.0 dB</option>
<option value="0.9">0.9 dB</option>
<option value="1.4">1.4 dB</option>
<option value="2.7">2.7 dB</option>
<option value="3.7">3.7 dB</option>
<option value="7.7">7.7 dB</option>
<option value="8.7">8.7 dB</option>
<option value="12.5">12.5 dB</option>
<option value="14.4">14.4 dB</option>
<option value="15.7">15.7 dB</option>
<option value="16.6">16.6 dB</option>
<option value="19.7">19.7 dB</option>
<option value="20.7">20.7 dB</option>
<option value="22.9">22.9 dB</option>
<option value="25.4">25.4 dB</option>
<option value="28.0">28.0 dB</option>
<option value="29.7">29.7 dB</option>
<option value="32.8">32.8 dB</option>
<option value="33.8">33.8 dB</option>
<option value="36.4">36.4 dB</option>
<option value="37.2">37.2 dB</option>
<option value="38.6">38.6 dB</option>
<option value="40.2">40.2 dB</option>
<option value="42.1">42.1 dB</option>
<option value="43.4">43.4 dB</option>
<option value="43.9">43.9 dB</option>
<option value="44.5">44.5 dB</option>
<option value="48.0">48.0 dB</option>
<option value="49.6">49.6 dB</option>
<label for="sdr-gain-select" data-i18n>GAIN</label>
<select id="sdr-gain-select" aria-label="RTL-SDR tuner gain for the current mode" data-i18n-aria-label>
<option value="auto" data-i18n>AUTO</option>
<option value="0.0" translate="no">0.0 dB</option>
<option value="0.9" translate="no">0.9 dB</option>
<option value="1.4" translate="no">1.4 dB</option>
<option value="2.7" translate="no">2.7 dB</option>
<option value="3.7" translate="no">3.7 dB</option>
<option value="7.7" translate="no">7.7 dB</option>
<option value="8.7" translate="no">8.7 dB</option>
<option value="12.5" translate="no">12.5 dB</option>
<option value="14.4" translate="no">14.4 dB</option>
<option value="15.7" translate="no">15.7 dB</option>
<option value="16.6" translate="no">16.6 dB</option>
<option value="19.7" translate="no">19.7 dB</option>
<option value="20.7" translate="no">20.7 dB</option>
<option value="22.9" translate="no">22.9 dB</option>
<option value="25.4" translate="no">25.4 dB</option>
<option value="28.0" translate="no">28.0 dB</option>
<option value="29.7" translate="no">29.7 dB</option>
<option value="32.8" translate="no">32.8 dB</option>
<option value="33.8" translate="no">33.8 dB</option>
<option value="36.4" translate="no">36.4 dB</option>
<option value="37.2" translate="no">37.2 dB</option>
<option value="38.6" translate="no">38.6 dB</option>
<option value="40.2" translate="no">40.2 dB</option>
<option value="42.1" translate="no">42.1 dB</option>
<option value="43.4" translate="no">43.4 dB</option>
<option value="43.9" translate="no">43.9 dB</option>
<option value="44.5" translate="no">44.5 dB</option>
<option value="48.0" translate="no">48.0 dB</option>
<option value="49.6" translate="no">49.6 dB</option>
</select>
</div>
<div id="sdr-adsb-stats" class="sdr-adsb-stats" role="status" aria-live="off" hidden>
<span><output id="sdr-stat-rate">--</output> MSG/S</span>
<span><output id="sdr-stat-heard">0</output> HEARD</span>
<span><output id="sdr-stat-positioned">0</output> POSITIONED</span>
<span>IQ <output id="sdr-stat-iq">--</output></span>
<span><output id="sdr-stat-rate">--</output> <span data-i18n>MSG/S</span></span>
<span><output id="sdr-stat-heard">0</output> <span data-i18n>HEARD</span></span>
<span><output id="sdr-stat-positioned">0</output> <span data-i18n>POSITIONED</span></span>
<span translate="no">IQ <output id="sdr-stat-iq">--</output></span>
</div>
<div class="sdr-frequency-row">
<label for="sdr-frequency-input">FM MHZ</label>
<label for="sdr-frequency-input" data-i18n>FM MHZ</label>
<input id="sdr-frequency-input" type="number" min="87.5" max="108" step="0.1" value="98.5" inputmode="decimal" />
<button id="sdr-tune-btn" type="button">TUNE</button>
<button id="sdr-tune-btn" type="button" data-i18n>TUNE</button>
</div>
<div class="sdr-seek-row" role="group" aria-label="Seek broadcast FM stations">
<button id="sdr-seek-back-btn" type="button" disabled>◀ SEEK</button>
<button id="sdr-seek-forward-btn" type="button" disabled>SEEK ▶</button>
<div class="sdr-seek-row" role="group" aria-label="Seek broadcast FM stations" data-i18n-aria-label>
<button id="sdr-seek-back-btn" type="button" disabled data-i18n>◀ SEEK</button>
<button id="sdr-seek-forward-btn" type="button" disabled data-i18n>SEEK ▶</button>
</div>
<label class="radio-volume-row" for="sdr-volume">
<span>SDR VOL</span>
<input id="sdr-volume" class="gev-quantitative-slider" type="range" min="0" max="100" value="80" aria-label="Local SDR volume" />
<span data-i18n>SDR VOL</span>
<input id="sdr-volume" class="gev-quantitative-slider" type="range" min="0" max="100" value="80" aria-label="Local SDR volume" data-i18n-aria-label />
<output id="sdr-volume-value" class="gev-slider-value" for="sdr-volume">80%</output>
</label>
<div id="sdr-status" class="radio-playback-state" role="status" aria-live="polite">Connect an RTL-SDR to begin.</div>
<div id="sdr-status" class="radio-playback-state" role="status" aria-live="polite" data-i18n>Connect an RTL-SDR to begin.</div>
<div id="sdr-feed-status" class="sdr-feed-status" role="status" aria-live="off" hidden></div>
</div>
</div>
+15 -15
View File
@@ -1,7 +1,7 @@
<!-- Post-processing toggles (top-right) -->
<div id="pp-toggles" class="panel-collapsible collapsed" data-panel-id="pp-toggles">
<div class="compact pp-header-row">
<span class="pp-header-label">DISPLAY</span>
<span data-i18n class="pp-header-label">DISPLAY</span>
<span class="panel-divider" aria-hidden="true"></span>
<button class="panel-collapse-btn pp-collapse-btn" data-collapse-target="pp-toggles" title="Collapse panel" data-i18n-title>&#x25C0;</button>
</div>
@@ -9,7 +9,7 @@
<div class="pp-toggle-group">
<button class="pp-toggle-btn" id="hud-toggle" title="Intelligence HUD (H)" data-i18n-title>
<span class="pp-icon">&#x25CE;</span>
<span class="pp-label">HUD</span>
<span class="pp-label" translate="no">HUD</span>
</button>
<div class="pp-slider-row" id="hud-layout-row">
<span class="pp-slider-mini-label" data-i18n>Layout</span>
@@ -17,37 +17,37 @@
<option value="tactical" data-i18n>Tactical</option>
<option value="operator" data-i18n>Operator</option>
<option value="minimal" data-i18n>Minimal</option>
<option value="cyber">Cyber</option>
<option value="cyber" data-i18n>Cyber</option>
</select>
</div>
<div class="pp-slider-row cyber-sonar-control cyber-sonar-toggle-row" id="cyber-sonar-row">
<span class="pp-slider-mini-label">Sonar</span>
<button class="pp-mode-btn active" id="cyber-sonar-toggle" title="Cyber sonar contact scanner" aria-label="Cyber sonar contact scanner" aria-pressed="true">ON</button>
<span class="pp-slider-mini-label" data-i18n>Sonar</span>
<button class="pp-mode-btn active" id="cyber-sonar-toggle" title="Cyber sonar contact scanner" aria-label="Cyber sonar contact scanner" aria-pressed="true" data-i18n-title data-i18n-aria-label data-i18n>ON</button>
</div>
<output id="cyber-sonar-status" class="cyber-sonar-control" role="status"></output>
<div class="pp-slider-row cyber-sonar-control cyber-sonar-setting" id="cyber-sonar-rings-row">
<label class="pp-slider-mini-label" for="cyber-sonar-rings">Rings</label>
<input type="range" class="pp-slider" id="cyber-sonar-rings" min="3" max="12" step="1" value="8" aria-label="Sonar ring count" />
<label class="pp-slider-mini-label" for="cyber-sonar-rings" data-i18n>Rings</label>
<input type="range" class="pp-slider" id="cyber-sonar-rings" min="3" max="12" step="1" value="8" aria-label="Sonar ring count" data-i18n-aria-label />
<span class="pp-slider-value" id="cyber-sonar-rings-value">8</span>
</div>
<div class="pp-slider-row cyber-sonar-control cyber-sonar-setting" id="cyber-sonar-range-row">
<label class="pp-slider-mini-label" for="cyber-sonar-range">Range</label>
<input type="range" class="pp-slider" id="cyber-sonar-range" min="60" max="120" step="1" value="100" aria-label="Sonar ring range" />
<label class="pp-slider-mini-label" for="cyber-sonar-range" data-i18n>Range</label>
<input type="range" class="pp-slider" id="cyber-sonar-range" min="60" max="120" step="1" value="100" aria-label="Sonar ring range" data-i18n-aria-label />
<span class="pp-slider-value" id="cyber-sonar-range-value">100%</span>
</div>
<div class="pp-slider-row cyber-sonar-control cyber-sonar-setting" id="cyber-sonar-intensity-row">
<label class="pp-slider-mini-label" for="cyber-sonar-intensity">Power</label>
<input type="range" class="pp-slider" id="cyber-sonar-intensity" min="0" max="100" step="1" value="70" aria-label="Sonar intensity" />
<label class="pp-slider-mini-label" for="cyber-sonar-intensity" data-i18n>Power</label>
<input type="range" class="pp-slider" id="cyber-sonar-intensity" min="0" max="100" step="1" value="70" aria-label="Sonar intensity" data-i18n-aria-label />
<span class="pp-slider-value" id="cyber-sonar-intensity-value">70%</span>
</div>
<div class="pp-slider-row cyber-sonar-control cyber-sonar-setting" id="cyber-sonar-opacity-row">
<label class="pp-slider-mini-label" for="cyber-sonar-opacity">Opacity</label>
<input type="range" class="pp-slider" id="cyber-sonar-opacity" min="35" max="100" step="1" value="84" aria-label="Cyber contact and label opacity" title="Minimum opacity for map dots, icons, models, brackets, and labels between sonar passes" />
<label class="pp-slider-mini-label" for="cyber-sonar-opacity" data-i18n>Opacity</label>
<input type="range" class="pp-slider" id="cyber-sonar-opacity" min="35" max="100" step="1" value="84" aria-label="Cyber contact and label opacity" title="Minimum opacity for map dots, icons, models, brackets, and labels between sonar passes" data-i18n-aria-label data-i18n-title />
<span class="pp-slider-value" id="cyber-sonar-opacity-value">84%</span>
</div>
<div class="pp-slider-row cyber-sonar-control cyber-sonar-setting" id="cyber-sonar-sector-row">
<label class="pp-slider-mini-label" for="cyber-sonar-sector">Sector</label>
<input type="range" class="pp-slider" id="cyber-sonar-sector" min="8" max="60" step="1" value="24" aria-label="Sonar sector width" />
<label class="pp-slider-mini-label" for="cyber-sonar-sector" data-i18n>Sector</label>
<input type="range" class="pp-slider" id="cyber-sonar-sector" min="8" max="60" step="1" value="24" aria-label="Sonar sector width" data-i18n-aria-label />
<span class="pp-slider-value" id="cyber-sonar-sector-value">24°</span>
</div>
</div>
+1 -1
View File
@@ -5,7 +5,7 @@
<div id="loading-screen">
<div class="loader-content">
<span class="loader-logo brand-logo" data-logo-gaze data-logo-src="/logo.svg" aria-hidden="true"><img src="/logo.svg" alt="" /></span>
<h2>GOD'S EYE <span class="title-accent">VIEW</span></h2>
<h2 translate="no">GOD'S EYE <span class="title-accent">VIEW</span></h2>
<p class="loader-status" data-i18n>Initializing photorealistic world...</p>
</div>
</div>
+10 -10
View File
@@ -44,7 +44,7 @@
</div>
<div class="cctv-controls">
<button id="cctv-projection-btn" class="scene-btn" data-i18n>PROJECTION ON</button>
<span id="cctv-quality-chip">CAL · --</span>
<span id="cctv-quality-chip" data-i18n-runtime>CAL · --</span>
</div>
<div class="cctv-calibration-block">
<div class="cctv-calibration-header">
@@ -52,11 +52,11 @@
<button id="cctv-adjust-btn" class="scene-btn" title="Drag the camera in the world: rings rotate, arrows move, handles set range/FOV" data-i18n-title data-i18n>ADJUST</button>
</div>
<div id="cctv-cal-readout" class="cctv-cal-readout" aria-label="Camera pose — click a value to type" data-i18n-aria-label>
<button class="cctv-cal-value" data-cal-field="heading" title="Heading (compass °) — click to type" data-i18n-title>HDG --</button>
<button class="cctv-cal-value" data-cal-field="pitch" title="Pitch (° up/down) — click to type" data-i18n-title>PITCH --</button>
<button class="cctv-cal-value" data-cal-field="fov" title="Horizontal FOV (°) — click to type" data-i18n-title>FOV --</button>
<button class="cctv-cal-value" data-cal-field="range" title="Range / monitor-plane distance (m) — click to type" data-i18n-title>RANGE --</button>
<button class="cctv-cal-value" data-cal-field="height" title="Mount height above ground (m) — click to type" data-i18n-title>HGT --</button>
<button class="cctv-cal-value" data-cal-field="heading" title="Heading (compass °) — click to type" data-i18n-title data-i18n-runtime>HDG --</button>
<button class="cctv-cal-value" data-cal-field="pitch" title="Pitch (° up/down) — click to type" data-i18n-title data-i18n-runtime>PITCH --</button>
<button class="cctv-cal-value" data-cal-field="fov" title="Horizontal FOV (°) — click to type" data-i18n-title data-i18n-runtime>FOV --</button>
<button class="cctv-cal-value" data-cal-field="range" title="Range / monitor-plane distance (m) — click to type" data-i18n-title data-i18n-runtime>RANGE --</button>
<button class="cctv-cal-value" data-cal-field="height" title="Mount height above ground (m) — click to type" data-i18n-title data-i18n-runtime>HGT --</button>
<button class="cctv-cal-value" data-cal-field="north" title="North offset from catalog position (m) — click to type" data-i18n-title>ΔN --</button>
<button class="cctv-cal-value" data-cal-field="east" title="East offset from catalog position (m) — click to type" data-i18n-title>ΔE --</button>
</div>
@@ -78,8 +78,8 @@
<div class="panel-header">
<span class="panel-title" data-i18n>STREET LEVEL</span>
<span class="panel-divider"></span>
<button id="sl-status" class="sl-status" type="button" aria-pressed="false" title="Turn Street Level on or off">OFF</button>
<button class="panel-collapse-btn" data-collapse-target="street-level-panel" title="Expand panel">◀</button>
<button id="sl-status" class="sl-status" type="button" aria-pressed="false" title="Turn Street Level on or off" data-i18n-title data-i18n>OFF</button>
<button class="panel-collapse-btn" data-collapse-target="street-level-panel" title="Expand panel" data-i18n-title>◀</button>
</div>
<div id="sl-body" class="sl-body">
<div class="sl-main">
@@ -129,7 +129,7 @@
<div id="sl-since-row" class="sl-since">
<label class="cctv-summary-label" for="sl-since" data-i18n>SINCE</label>
<input id="sl-since" class="sl-range" type="range" min="0" max="8" step="1" value="0" aria-valuetext="ANY DATE" aria-describedby="sl-since-label sl-since-note" />
<output id="sl-since-label" class="sl-since-label" for="sl-since">ANY DATE</output>
<output id="sl-since-label" class="sl-since-label" for="sl-since" data-i18n>ANY DATE</output>
<small id="sl-since-note" class="sl-since-note" hidden></small>
</div>
</fieldset>
@@ -137,7 +137,7 @@
<!-- The hint says how to open imagery; the button does it without a pointer. -->
<div class="sl-meta-row">
<div id="sl-coverage-meta" class="sl-meta"></div>
<button id="sl-nearest-btn" class="scene-btn sl-nearest-btn" type="button" hidden data-i18n>OPEN STREET VIEW</button>
<button id="sl-nearest-btn" class="scene-btn sl-nearest-btn" type="button" hidden data-i18n-runtime>OPEN STREET VIEW</button>
</div>
</div>
</div>
+4 -4
View File
@@ -10,14 +10,14 @@
<!-- Title -->
<div id="title-bar">
<div class="title-glow"></div>
<h1><span class="title-logo brand-logo" data-logo-gaze data-logo-src="/logo.svg" aria-hidden="true"><img src="/logo.svg" alt="" /></span> <span>GOD'S EYE <span class="title-accent">VIEW</span></span></h1>
<h1><span class="title-logo brand-logo" data-logo-gaze data-logo-src="/logo.svg" aria-hidden="true"><img src="/logo.svg" alt="" /></span> <span translate="no">GOD'S EYE <span class="title-accent">VIEW</span></span></h1>
<p class="subtitle" data-i18n>NO PLACE LEFT BEHIND</p>
</div>
<!-- Style indicator -->
<div id="style-indicator">
<span class="indicator-label" data-i18n>ACTIVE STYLE</span>
<span class="indicator-value" id="active-style-name">NORMAL</span>
<span class="indicator-value" id="active-style-name" data-i18n>NORMAL</span>
</div>
<!-- Top-center camera and share actions -->
@@ -28,10 +28,10 @@
<button id="share-btn" type="button" aria-label="Copy share link" title="Copy share link" data-i18n-aria-label data-i18n-title>
<span class="share-icon" aria-hidden="true">&#x1F517;</span>
</button>
<button id="tilt-map-view" type="button" aria-label="Tilt map to oblique view" aria-pressed="false" title="Toggle straight-down and tilted map views">
<button id="tilt-map-view" type="button" aria-label="Tilt map to oblique view" aria-pressed="false" title="Toggle straight-down and tilted map views" data-i18n-aria-label data-i18n-title>
<span class="material-symbols-outlined" aria-hidden="true">view_in_ar</span>
</button>
<button id="north-up-view" type="button" aria-label="Reset map to north up" title="Reset map bearing to north">
<button id="north-up-view" type="button" aria-label="Reset map to north up" title="Reset map bearing to north" data-i18n-aria-label data-i18n-title>
<span class="camera-compass-n" aria-hidden="true">N</span>
<span class="camera-compass-needle material-symbols-outlined" aria-hidden="true">navigation</span>
</button>
+2 -2
View File
@@ -12,7 +12,7 @@
— including the unspaced em dash. The arc it has to carry: this looks
like something you should not have access to → the sources are all
public → the data is real. Tile subcopy stays purely functional. -->
<p id="first-run-description">It feels like a forbidden cockpit—then you realize the sources are public and the data is real.</p>
<p id="first-run-description" data-i18n-runtime>It feels like a forbidden cockpit—then you realize the sources are public and the data is real.</p>
<div class="first-run-choices">
<button type="button" data-first-run-choice="contacts">
<span class="material-symbols-outlined" aria-hidden="true">radar</span>
@@ -30,7 +30,7 @@
<!-- Subcopy names BOTH feeds this tile turns on, because the launcher
optimizes for the fully configured experience (owner ruling,
2026-08-23) — see the mission table in src/firstRunExperience.js. -->
<span><strong data-first-run-environmental-title>ENVIRONMENTAL</strong><small>Live earthquakes and active fires, from USGS and NASA</small></span>
<span data-i18n-runtime><strong data-first-run-environmental-title>ENVIRONMENTAL</strong><small>Live earthquakes and active fires, from USGS and NASA</small></span>
<span class="material-symbols-outlined first-run-arrow" aria-hidden="true">arrow_forward</span>
</button>
<button type="button" class="first-run-explore" data-first-run-choice="explore">