From 978cd72ac246cf6cb3ad1c4f7c83c09e174b32f9 Mon Sep 17 00:00:00 2001 From: Enzo Abyie Date: Wed, 28 Oct 2026 12:36:27 +0400 Subject: [PATCH 01/83] i18n(it): Italian strings from #912 The Italian locale by abiyeenzo (#912), converted from its namespaced JS catalogs to the English-keyed it.json: 859 entries whose English still matches the current UI. --- src/i18n/locales/it.json | 882 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 882 insertions(+) create mode 100644 src/i18n/locales/it.json diff --git a/src/i18n/locales/it.json b/src/i18n/locales/it.json new file mode 100644 index 000000000..d5c65f04c --- /dev/null +++ b/src/i18n/locales/it.json @@ -0,0 +1,882 @@ +{ + "Flying to Austin, TX...": "Volo verso Austin, TX...", + "Restoring shared view...": "Ripristino della vista condivisa...", + "Configuring viewer...": "Configurazione del visualizzatore...", + "Loading Google 3D Tiles...": "Caricamento di Google 3D Tiles...", + "Loading the keyless globe...": "Caricamento del globo senza chiave...", + "Google 3D Tiles unavailable ({detail}). Loading the keyless globe...": "Google 3D Tiles non disponibile ({detail}). Caricamento del globo senza chiave...", + "Initializing systems...": "Inizializzazione dei sistemi...", + "Close data attribution": "Chiudi le attribuzioni dei dati", + "UNAVAILABLE": "NON DISPONIBILE", + "SOURCE": "FONTE", + "Overpass rate-limited": "Overpass ha limitato le richieste", + "Overpass timed out": "Overpass è andato in timeout", + "Overpass could not complete the query": "Overpass non ha potuto completare la query", + "Overpass temporarily unavailable": "Overpass temporaneamente non disponibile", + "Retrying mapped sites…": "Nuovo tentativo sui siti mappati…", + "Fetching mapped sites…": "Ricerca dei siti mappati…", + "{reason} — retrying in {seconds}s": "{reason} — nuovo tentativo tra {seconds}s", + "{reason} — retry pending": "{reason} — nuovo tentativo in sospeso", + "Zoom in to search mapped installations": "Ingrandisci per cercare le installazioni mappate", + "Showing cached mapped sites": "Siti mappati in cache", + "Mapped sites not loaded": "Siti mappati non caricati", + "Mapped sites loaded": "Siti mappati caricati", + "feed unavailable": "feed non disponibile", + "feed stale": "feed obsoleto", + "observed or mapped nearby context": "contesto osservato o mappato nelle vicinanze", + "no observed or mapped objects in current feeds": "nessun oggetto osservato o mappato nei feed attuali", + "STATION": "STAZIONE", + "Crewed stations and their visiting vehicles": "Stazioni con equipaggio e veicoli in visita", + "NAV": "NAV", + "GNSS navigation — GPS, GLONASS, Galileo": "Navigazione GNSS — GPS, GLONASS, Galileo", + "GEO": "GEO", + "Geostationary belt — comms and weather, fixed over the equator": "Fascia geostazionaria — comunicazioni e meteo, fissi sopra l'equatore", + "VISUAL": "VISIVO", + "Brightest naked-eye objects — CelesTrak visual group": "Oggetti più luminosi a occhio nudo — gruppo visual di CelesTrak", + "COMMS": "COMUN", + "Broadband constellation shell — shown only in DENSE mode": "Shell della costellazione broadband — mostrato solo in modalità DENSO", + "FISHING": "PESCA", + "TOWING": "RIMORCHIO", + "DREDGER": "DRAGA", + "DIVE OPS": "OP. SUBACQUEE", + "MILITARY": "MILITARE", + "SAILING": "VELA", + "PLEASURE": "DIPORTO", + "PILOT": "PILOTINA", + "SAR": "SAR", + "TUG": "REBOCCATORE", + "PORT TENDER": "TENDER PORTO", + "ANTI-POLLUTION": "ANTINQUINAMENTO", + "LAW ENFORCE": "FORZE ORDINE", + "MEDICAL": "MEDICA", + "HIGH-SPEED": "ALTA VELOCITÀ", + "PASSENGER": "PASSEGGERI", + "CARGO": "CARGO", + "TANKER": "CISTERNA", + "OTHER": "ALTRO", + "ENVIRONMENTAL": "AMBIENTE", + "EARTH WATCH": "OSSERVATORIO TERRA", + "ACTIVE EVENTS": "EVENTI ATTIVI", + "Starting live contacts…": "Avvio dei contatti live…", + "Opening space missions…": "Apertura delle missioni spaziali…", + "Scanning active events…": "Scansione degli eventi attivi…", + "Live earthquakes and active fires, from USGS and NASA": "Terremoti e incendi attivi in tempo reale, da USGS e NASA", + "It feels like a forbidden cockpit—then you realize the sources are public and the data is real.": "Sembra un cockpit proibito, poi capisci che le fonti sono pubbliche e i dati sono reali.", + "Working…": "Operazione in corso…", + "Could not open that mission{detail}. Retry or explore manually.": "Impossibile aprire quella missione{detail}. Riprova o esplora a mano.", + "This browser is blocking storage, so that could not be saved.": "Questo browser blocca l'archiviazione, quindi non è stato possibile salvare.", + "CRT": "CRT", + "NVG": "NVG", + "FLIR": "FLIR", + "SNOW": "NEVE", + "LOADING": "CARICAMENTO", + "DEGRADED": "DEGRADATO", + "STALE": "OBSOLETO", + "PARTIAL": "PARZIALE", + "FALLBACK": "FALLBACK", + "SUMMARY": "RIEPILOGO", + "Awaiting telemetry...": "In attesa di telemetria...", + "REC": "REC", + "AIS: --": "AIS: --", + "POWER UP · {count} KEYS WAITING": { + "one": "POWER UP · {count} CHIAVE IN ATTESA", + "other": "POWER UP · {count} CHIAVI IN ATTESA" + }, + "POWERED UP": "ACCESO", + "Save failed ({status}).": "Salvataggio non riuscito ({status}).", + "REMOVE": "RIMUOVI", + "Remove {title} from this app's saved keys": "Rimuovi {title} dalle chiavi salvate di questa app", + "your app configuration": "la configurazione della tua app", + "your local .env": "il tuo .env locale", + "Saving…": "Salvataggio…", + "Save failed: {detail}": "Salvataggio non riuscito: {detail}", + "Paste at least one key first.": "Incolla prima almeno una chiave.", + "Saved to {store}. Restarting — this page reloads itself.": "Salvato ({store}). Riavvio in corso: questa pagina si ricarica da sola.", + "Remove this key from your saved configuration?": "Rimuovere questa chiave dalla configurazione salvata?", + "Removed from {store}. Restarting — this page reloads itself.": "Rimosso ({store}). Riavvio in corso: questa pagina si ricarica da sola.", + "Places context + Street View fallback; optional separate key": "Contesto luoghi + fallback Street View; chiave separata opzionale", + "Live ships, worldwide": "Navi live, in tutto il mondo", + "Live active-fire detections": "Rilevamenti live di incendi attivi", + "Real live traffic (keyless runs a simulation)": "Traffico reale live (senza chiave usa una simulazione)", + "Bing imagery map stacks + world terrain": "Stack mappa con immagini Bing + terreno globale", + "More flight-polling credits (anonymous works without)": "Più crediti di polling voli (funziona anche in modo anonimo)", + "CONTEXT READY": "CONTESTO PRONTO", + "GLOBAL CONTEXT OFF": "CONTESTO GLOBALE OFF", + "SELECT A FLIGHT, VESSEL, OR MAPPED INSTALLATION": "SELEZIONA UN VOLO, UNA NAVE O UN'INSTALLAZIONE MAPPATA", + "ENABLE TO LOAD OBSERVED / MAPPED PROXIMITY": "ATTIVA PER CARICARE LA PROSSIMITÀ OSSERVATA / MAPPATA", + "Unavailable": "Non disponibile", + "Focus {label}": "Focus su {label}", + "Global Context navigation": "Navigazione Contesto globale", + "Previous — prior visited contact in the 250 km window": "Precedente — contatto visitato in precedenza nella finestra di 250 km", + "PREVIOUS": "PRECEDENTE", + "FOCUS": "FOCUS", + "Next — nearest unvisited contact in the 250 km window": "Successivo — contatto non visitato più vicino nella finestra di 250 km", + "NEXT": "SUCC", + "Open-source mapped/observed context. Missing broadcasts, unloaded map areas, or unmapped sites are not evidence of absence.": "Contesto mappato/osservato da fonti aperte. Trasmissioni mancanti, aree di mappa non caricate o siti non mappati non sono prova di assenza.", + "HDG {value}°": "HDG {value}°", + "BRG {value}°": "BRG {value}°", + "BRG —": "BRG —", + "CRS {value}°": "CRS {value}°", + "CURRENT VIEWPORT ONLY": "SOLO VISTA ATTUALE", + "WITHIN {km} KM": "ENTRO {km} KM", + "Flights": "Voli", + "Military flights": "Voli militari", + "AIS vessels": "Navi AIS", + "Mapped installations": "Installazioni mappate", + "syncing {count} city feeds...": "sincronizzazione di {count} feed città...", + "scanning nearby systems...": "scansione dei sistemi vicini...", + "Station {id}": "Stazione {id}", + "Station": "Stazione", + "🚲 {bikes} avail · {docks} docks · {capacity} cap": "🚲 {bikes} disp · {docks} stalli · {capacity} cap", + "⚠️ Not installed": "⚠️ Non installata", + "⚠️ Not renting": "⚠️ Noleggio non attivo", + "⚠️ Not returning": "⚠️ Restituzione non attiva", + "HDG {value}° (ESTIMATED)": "HDG {value}° (STIMATO)", + "{count} CAMERAS STANDING BY · NO CAMERA SELECTED · CLICK A CAMERA TO ACTIVATE": "{count} TELECAMERE IN ATTESA · NESSUNA TELECAMERA SELEZIONATA · CLIC SU UNA TELECAMERA PER ATTIVARLA", + "No cameras available in catalog.": "Nessuna telecamera disponibile nel catalogo.", + "{city} CCTV": "CCTV {city}", + "FOV {value}°": "FOV {value}°", + "COVERAGE {value}km²": "COPERTURA {value}km²", + "OVERLAP {count} cams": "SOVRAPP. {count} cam", + "ISOLATED VIEW": "VISTA ISOLATA", + "PROJ MONITOR": "PROIEZ MONITOR", + "PROJ OFF": "PROIEZ OFF", + "VIEWSHED": "VIEWSHED", + "CAL {value}": "CAL {value}", + "SRC {value}": "FONTE {value}", + "{value} CONTEXT": "CONTESTO {value}", + "Focus fire detection {title}, {details}": "Focus sul rilevamento incendio {title}, {details}", + "{value} conf": "{value} conf", + "{value} ago": "{value} fa", + "sensor n/a": "sensore n/d", + "FIRE · {frp} MW": "INCENDIO · {frp} MW", + "NIGHT": "NOTTE", + "▲ {frp} MW": "▲ {frp} MW", + "FIRE": "INCENDIO", + "FIRES": "INCENDI", + "max {value} MW": "max {value} MW", + "new {value}": "nuovo {value}", + "just now": "adesso", + "<1m ago": "<1m fa", + "{count}m ago": "{count}m fa", + "{count}h ago": "{count}h fa", + "STALE · cached {age}": "OBSOLETO · in cache {age}", + "refreshing...": "aggiornamento...", + "loading...": "caricamento...", + "KEY REQUIRED": "CHIAVE RICHIESTA", + "LIVE · updated {age}": "LIVE · aggiornato {age}", + "loading mapped installation context": "caricamento del contesto dell'installazione mappata", + "MAPPED INSTALLATION": "INSTALLAZIONE MAPPATA", + "LAUNCH SITE · {site}": "SITO DI LANCIO · {site}", + "LAUNCH SITE": "SITO DI LANCIO", + "T−{time} · {mission}": "T−{time} · {mission}", + "LAUNCH STANDBY": "LANCIO IN ATTESA", + "LIFTOFF · {mission}": "DECOLLO · {mission}", + "ASCENT REPLAY · {mission}": "REPLAY SALITA · {mission}", + "ASCENT ESTIMATE · {mission}": "STIMA SALITA · {mission}", + "STAGE RE-ENTRY / RECOVERY · {mission}": "RIENTRO / RECUPERO STADI · {mission}", + "ORBIT REPLAY · {mission}": "REPLAY ORBITA · {mission}", + "PAUSED · {title}": "IN PAUSA · {title}", + "UNSPECIFIED": "NON SPECIFICATO", + "+{count} additional payload records": "+{count} record payload aggiuntivi", + "PAYLOAD DATA UNAVAILABLE": "DATI PAYLOAD NON DISPONIBILI", + "{value} KM DOWNRANGE": "{value} KM DOWNRANGE", + "POSITION UNAVAILABLE": "POSIZIONE NON DISPONIBILE", + "FLIGHT {count}": "VOLO {count}", + "REUSED": "RIUTILIZZATO", + "NO STAGE RE-ENTRY / RECOVERY DATA": "NESSUN DATO DI RIENTRO / RECUPERO DEGLI STADI", + "{count} / 30D": "{count} / 30G", + "NO MISSIONS AVAILABLE IN THE CURRENT 30-DAY WINDOW": "NESSUNA MISSIONE DISPONIBILE NELLA FINESTRA ATTUALE DI 30 GIORNI", + "DATE UNAVAILABLE": "DATA NON DISPONIBILE", + "UNSPECIFIED OPERATOR": "OPERATORE NON SPECIFICATO", + "Select {mission}": "Seleziona {mission}", + "{value} KM": "{value} KM", + "{value} KM/S": "{value} KM/S", + "SELECTED SPACE MISSION": "MISSIONE SPAZIALE SELEZIONATA", + "Show all missions": "Mostra tutte le missioni", + "Deselect mission": "Deseleziona la missione", + "MISSION": "MISSIONE", + "STATUS · ": "STATO · ", + "LAUNCH SITE · ": "SITO DI LANCIO · ", + "LAUNCH TIME · ": "ORA DI LANCIO · ", + "ORBIT · ": "ORBITA · ", + "ASCENT PATH · ": "TRAIETTORIA DI SALITA · ", + "CURRENT DISTANCE FROM EARTH · ": "DISTANZA ATTUALE DALLA TERRA · ", + "SATELLITE SPEED · ": "VELOCITÀ SATELLITE · ", + "PAYLOAD": "PAYLOAD", + "NAME": "NOME", + "TYPE": "TIPO", + "DESTINATION": "DESTINAZIONE", + "STAGE / RE-ENTRY / RECOVERY": "STADIO / RIENTRO / RECUPERO", + "STAGE": "STADIO", + "STATUS": "STATO", + "FINAL POSITION": "POSIZIONE FINALE", + "REPLAY SPEED": "VELOCITÀ REPLAY", + "Replay speed multiplier": "Moltiplicatore di velocità del replay", + "REPLAY ASCENT": "RIVEDI SALITA", + "Previous mission": "Missione precedente", + "PREV": "PREC", + "Next mission": "Missione successiva", + "SHOW ALL / DESELECT": "MOSTRA TUTTE / DESELEZIONA", + "Pause replay": "Metti in pausa il replay", + "Cancel replay": "Annulla il replay", + "EST. DOWNRANGE": "DOWNRANGE STIM.", + "PLANNED · ": "PIANIFICATO · ", + "SUPPLIED TRAJECTORY POINTS": "PUNTI DI TRAIETTORIA FORNITI", + "RECONSTRUCTED ESTIMATE": "STIMA RICOSTRUITA", + "Replay the estimated ascent with a following camera": "Rivedi la salita stimata con una camera che segue il razzo", + "Resume replay": "Riprendi il replay", + "T minus {seconds}": "T meno {seconds}", + "Preparing launch site": "Preparazione del sito di lancio", + "Liftoff": "Decollo", + "Ascent replay": "Replay della salita", + "Orbit replay": "Replay dell'orbita", + ", paused": ", in pausa", + "Alt unknown": "Quota sconosciuta", + "Type unknown": "Tipo sconosciuto", + "Reg unknown": "Matricola sconosciuta", + "Operator unknown": "Operatore sconosciuto", + "News": "Notizie", + "Talk": "Talk", + "Weather / Emergency": "Meteo / Emergenza", + "Public Safety": "Sicurezza pubblica", + "Aviation / Marine": "Aviazione / Marina", + "Traffic / Transit": "Traffico / Trasporti", + "Music": "Musica", + "Other": "Altro", + "radio|TALK": "TALK", + "radio|SAFETY": "SICUREZZA", + "radio|AIR / SEA": "AERO / MARE", + "radio|TRANSIT": "TRASPORTI", + "radio|MUSIC": "MUSICA", + "Alternative": "Alternative", + "Ambient": "Ambient", + "Blues": "Blues", + "Classical": "Classica", + "Country": "Country", + "Dance": "Dance", + "Electronic": "Elettronica", + "Folk": "Folk", + "Funk": "Funk", + "Hip-Hop": "Hip-Hop", + "House": "House", + "Indie": "Indie", + "Jazz": "Jazz", + "Latin": "Latina", + "Metal": "Metal", + "Oldies": "Oldies", + "Pop": "Pop", + "Punk": "Punk", + "R&B": "R&B", + "Reggae": "Reggae", + "Rock": "Rock", + "Soul": "Soul", + "Techno": "Techno", + "Trance": "Trance", + "World": "World", + "Add the full Starlink broadband shell (thousands of extra points)": "Aggiungi l'intero shell broadband Starlink (migliaia di punti in più)", + "Loading the Starlink shell…": "Caricamento dello shell Starlink…", + "Starlink {detail} — click to retry": "Starlink {detail} — clic per riprovare", + "load failed": "caricamento non riuscito", + "Showing the full Starlink shell — click for the core catalog only": "Mostra l'intero shell Starlink — clic per il solo catalogo principale", + "DENSE ···": "DENSO ···", + "DENSE ✕": "DENSO ✕", + "DENSE": "DENSA", + "Syncing flow · Roads: {source}": "Sincronizzazione flusso · Strade: {source}", + "LIVE · Roads: {source} · Roads without flow hidden": "LIVE · Strade: {source} · Strade senza flusso nascoste", + "LIVE · Roads: {source} · No flow roads in view": "LIVE · Strade: {source} · Nessuna strada con flusso in vista", + "LIVE · Roads: {source} · Flow {percent}%": "LIVE · Strade: {source} · Flusso {percent}%", + "SIMULATED · Roads: {source} · Flow {percent}%": "SIMULATO · Strade: {source} · Flusso {percent}%", + "Syncing flow · Roads: OpenStreetMap · Flow: TomTom · Unmatched: simulated": "Sincronizzazione flusso · Strade: OpenStreetMap · Flusso: TomTom · Non abbinate: simulate", + "LIVE · Roads: OpenStreetMap · Flow: TomTom · {percent}% cov · Unmatched: simulated": "LIVE · Strade: OpenStreetMap · Flusso: TomTom · {percent}% cop · Non abbinate: simulate", + "LIVE · Roads: OpenStreetMap · Flow: TomTom · {percent}% cov": "LIVE · Strade: OpenStreetMap · Flusso: TomTom · {percent}% cop", + "SIMULATED · Roads: OpenStreetMap · Flow: TomTom (no matches)": "SIMULATO · Strade: OpenStreetMap · Flusso: TomTom (nessuna corrispondenza)", + "SIMULATED — traffic service unreachable": "SIMULATO — servizio traffico irraggiungibile", + "SIMULATED — add TomTom key for live": "SIMULATO — aggiungi la chiave TomTom per il live", + "AIS: {name}": "AIS: {name}", + "{type} SPD: {speed} HDG: {heading}": "{type} VEL: {speed} HDG: {heading}", + "VESSEL": "NAVE", + "POS: LIVE": "POS: LIVE", + "POS: {time}Z": "POS: {time}Z", + "awaiting first AIS position…": "in attesa della prima posizione AIS…", + "awaiting usable AIS positions…": "in attesa di posizioni AIS utilizzabili…", + "awaiting first AIS message…": "in attesa del primo messaggio AIS…", + "Resume": "Riprendi", + "Pause": "Pausa", + "Error: {message}": "Errore: {message}", + "Needs {envVars} — add it in Provider Settings": "Richiede {envVars}: vai su Impostazioni Provider", + "{label} is unavailable": "{label} non è disponibile", + "This map stack": "Questo stack mappa", + "{label} unavailable: {hint}": "{label} non disponibile: {hint}", + "Visible map targets": "Obiettivi mappa visibili", + "Ready": "Pronto", + "Loaded: {scene} / {shot}": "Caricato: {scene} / {shot}", + "Cannot capture shot: camera not ready": "Impossibile catturare lo scatto: camera non pronta", + "Captured: {scene} / {shot}": "Catturato: {scene} / {shot}", + "Select a shot first": "Seleziona prima uno scatto", + "Updated: {scene} / {shot}": "Aggiornato: {scene} / {shot}", + "Camera unavailable — exit cockpit first": "Camera non disponibile: esci prima dal cockpit", + "No shots to run": "Nessuno scatto da eseguire", + "Project exported": "Progetto esportato", + "Could not exit {mode} — scene layers may be refused": "Impossibile uscire da {mode}: i livelli della scena potrebbero essere rifiutati", + "Running {index}/{total}: {scene} / {shot}": "Esecuzione {index}/{total}: {scene} / {shot}", + "Scene run complete": "Esecuzione della scena completata", + "Global Flights Radar": "Radar Voli Globale", + "Orbital Watch": "Sorveglianza Orbitale", + "Thermal Threat Board": "Quadro Minacce Termiche", + "City Overload": "Sovraccarico Urbano", + "Omniscience Pullback": "Zoom Out Onniscienza", + "Shot {n}": "Scatto {n}", + "Density": "Densità", + "Bloom": "Bloom", + "VISUAL PRESETS": "PRESET VISIVI", + "LOCATION": "POSIZIONE", + "CONTACTS — nearest planes · vessels · sites": "CONTATTI — aerei · navi · siti più vicini", + "SPACE MISSIONS — launches & orbital assets": "MISSIONI SPAZIALI — lanci e asset orbitali", + "LIVE SIGNALS": "SEGNALI LIVE", + "Contacts could not complete the requested transition; try again": "Impossibile completare la transizione richiesta per Contatti; riprova", + "CCTV layer unavailable": "Livello CCTV non disponibile", + "Link copied!": "Link copiato!", + "Copy failed": "Copia non riuscita", + "CCTV calibration saved": "Calibrazione CCTV salvata", + "CCTV calibration reset": "Calibrazione CCTV ripristinata", + "ADJUST ON": "REGOLAZ. ON", + "ADJUST": "REGOLAZ.", + "UNKNOWN": "SCONOSCIUTO", + "ERROR": "ERRORE", + "SOURCE · UNKNOWN": "FONTE · SCONOSCIUTA", + "FRAME · LOADING": "FOTOGRAMMA · CARICAMENTO", + "FRAME · UNAVAILABLE": "FOTOGRAMMA · NON DISPONIBILE", + "CALIBRATED": "CALIBRATA", + "CURATED": "CURATA", + "RAW PRIOR": "STIMA GREZZA", + "CCTV ON": "CCTV ON", + "CCTV OFF": "CCTV OFF", + "VIEWSHED ON": "VIEWSHED ON", + "COVERAGE ON": "COPERTURA ON", + "COVERAGE OFF": "COPERTURA OFF", + "AUTO HOP ON": "AUTO HOP ON", + "AUTO HOP OFF": "AUTO HOP OFF", + "PROJECTION ON": "PROIEZIONE ON", + "PROJECTION OFF": "PROIEZIONE OFF", + "CAL · EDITED (UNSAVED)": "CAL · MODIFICATA (NON SALVATA)", + "CAL · {badge}": "CAL · {badge}", + "MONITOR": "MONITOR", + "OFF": "OFF", + "{city} · HDG {heading} · FOV {fov} · RANGE {range}m · {projection}{calBadge} · {provider}{status}": "{city} · HDG {heading} · FOV {fov} · PORTATA {range}m · {projection}{calBadge} · {provider}{status}", + "{count} cameras loaded · click a camera to activate": { + "one": "{count} telecamera caricata · clic su una telecamera per attivarla", + "other": "{count} telecamere caricate · clic su una telecamera per attivarla" + }, + "{count} cameras loaded · enable CCTV to activate": { + "one": "{count} telecamera caricata · attiva CCTV per attivarla", + "other": "{count} telecamere caricate · attiva CCTV per attivarle" + }, + "Enable CCTV to load camera intersections": "Attiva CCTV per caricare gli incroci delle telecamere", + "Enable CCTV to start camera-linked intelligence summaries.": "Attiva CCTV per avviare i riepiloghi intelligence collegati alle telecamere.", + "No summary available.": "Nessun riepilogo disponibile.", + "loading frames": "caricamento fotogrammi", + "camera grid ready": "griglia telecamere pronta", + "Clearing selected data layers": "Disattivazione dei livelli dati selezionati", + "Clear selected data layers": "Disattiva i livelli dati selezionati", + "CONDITIONS UNKNOWN": "CONDIZIONI SCONOSCIUTE", + "CLEAR": "SERENO", + "PARTLY CLOUDY": "POCO NUVOLOSO", + "OVERCAST": "COPERTO", + "FOG": "NEBBIA", + "DRIZZLE": "PIOGGERELLA", + "RAIN": "PIOGGIA", + "RAIN SHOWERS": "ROVESCI DI PIOGGIA", + "SNOW SHOWERS": "ROVESCI DI NEVE", + "THUNDERSTORM": "TEMPORALE", + "MIXED CONDITIONS": "CONDIZIONI MISTE", + "CYCLE ON": "CICLO ON", + "CYCLE OFF": "CICLO OFF", + "Stop automatic page cycling. Previous, Next, and the SIG/NEWS/LOCAL tabs stay available.": "Ferma lo scorrimento automatico delle pagine. Precedente, Successiva e le schede SIG/NEWS/LOCAL restano disponibili.", + "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.": "Scorre automaticamente le pagine del briefing ogni 9 secondi (Segnali → Notizie → Locale). Si mette in pausa quando passi sul pannello o lo selezioni. I dati dei segnali live si aggiornano comunque di continuo.", + "ACQUIRING REGIONAL NEWS": "ACQUISIZIONE NOTIZIE REGIONALI", + "REGIONAL NEWS UNAVAILABLE": "NOTIZIE REGIONALI NON DISPONIBILI", + "RESOLVING REGION": "RISOLUZIONE REGIONE", + "REGION UNAVAILABLE": "REGIONE NON DISPONIBILE", + "NO RECENT LOCATION MATCHES": "NESSUNA CORRISPONDENZA RECENTE PER POSIZIONE", + "{domain} · {age}": "{domain} · {age}", + "CLOUD {pct}%": "NUVOLE {pct}%", + "CLOUD UNKNOWN": "NUVOLE SCONOSCIUTE", + "{source} · LOCATION QUERY": "{source} · QUERY PER POSIZIONE", + "REGIONAL NEWS": "NOTIZIE REGIONALI", + "CONTEXT STANDBY": "CONTESTO IN ATTESA", + "ENABLE GLOBAL CONTEXT FOR PROXIMITY PINGS": "ATTIVA IL CONTESTO GLOBALE PER I PING DI PROSSIMITÀ", + "CONTACT LOST · LAST KNOWN READOUT · NOT AN ALL-CLEAR": "CONTATTO PERSO · ULTIMA LETTURA NOTA · NON È UN VIA LIBERA", + "CONTACT LOST · {subject}": "CONTATTO PERSO · {subject}", + "SUBJECT LEFT ITS FEED · READOUT HOLDING LAST KNOWN": "IL SOGGETTO HA LASCIATO IL FEED · LETTURA ALL'ULTIMO VALORE NOTO", + "{cohort} · {contact}": "{cohort} · {contact}", + "NO AVAILABLE EXAMPLE": "NESSUN ESEMPIO DISPONIBILE", + "{cohort}, Unavailable": "{cohort}, non disponibile", + "AHEAD": "DAVANTI", + "{side} {angle}": "{side} {angle}", + "L": "S", + "R": "D", + "{count} INPUTS UNKNOWN · NOT AN ALL-CLEAR": { + "one": "{count} INPUT SCONOSCIUTO · NON È UN VIA LIBERA", + "other": "{count} INPUT SCONOSCIUTI · NON È UN VIA LIBERA" + }, + "AVAILABLE INPUTS CURRENT · NOT AN ALL-CLEAR": "INPUT DISPONIBILI AGGIORNATI · NON È UN VIA LIBERA", + "AIRCRAFT": "AEREO", + "ACQUIRING SURFACE": "ACQUISIZIONE SUPERFICIE", + "SURFACE FALLBACK": "FALLBACK SUPERFICIE", + "STALE FEED": "FEED OBSOLETO", + "LIVE TRACK": "TRACCIA LIVE", + "COMMERCIAL": "COMMERCIALE", + "{aircraftClass} · {feedState} · COURSE ALIGNED": "{aircraftClass} · {feedState} · ROTTA ALLINEATA", + "ARROW · ESTIMATED DIRECTION": "FRECCIA · DIREZIONE STIMATA", + "ROUTE DATA UNAVAILABLE": "DATI ROTTA NON DISPONIBILI", + "DEST {bearing}": "DEST {bearing}", + "Disable cockpit weather effects": "Disattiva gli effetti meteo del cockpit", + "Enable cockpit weather effects": "Attiva gli effetti meteo del cockpit", + "ON": "ON", + "Normal": "Normale", + "Night vision": "Visione notturna", + "Thermal": "Termico", + "Anime": "Anime", + "Noir": "Noir", + "Snow": "Neve", + "Current cockpit vision style: {style}. Activate for next style.": "Stile di visione del cockpit attuale: {style}. Attiva per lo stile successivo.", + "Current style: {style} — click for next": "Stile attuale: {style} — clic per il successivo", + "Collapse Contact panel": "Comprimi il pannello Contatto", + "Expand Contact panel": "Espandi il pannello Contatto", + "Collapse contact panel": "Comprimi pannello contatto", + "Expand contact panel": "Espandi pannello contatto", + "Collapse cockpit briefing panel": "Comprimi il pannello briefing del cockpit", + "Expand cockpit briefing panel": "Espandi il pannello briefing del cockpit", + "Collapse briefing panel": "Comprimi pannello briefing", + "Expand briefing panel": "Espandi pannello briefing", + "OBSERVED / MAPPED PINGS": "PING OSSERVATI / MAPPATI", + "SOURCE-BACKED EVENTS · NO SYNTHETIC NEWS": "EVENTI DA FONTI · NESSUNA NOTIZIA SINTETICA", + "LATEST LOCATION-MATCHED REPORTING": "ULTIME NOTIZIE PER POSIZIONE", + "LOCAL INFO": "INFO LOCALI", + "PLACE / CONDITIONS / POSITION": "LUOGO / CONDIZIONI / POSIZIONE", + "TIME UNKNOWN": "ORA SCONOSCIUTA", + "{count}M AGO": "{count} MIN FA", + "{count}H AGO": "{count} H FA", + "{count}D AGO": "{count} G FA", + "DIR UNKNOWN": "DIR SCONOSCIUTA", + "Select flight {title}": "Seleziona il volo {title}", + "{aircraftClass} · CURRENT": "{aircraftClass} · ATTUALE", + "MILITARY FLIGHT": "VOLO MILITARE", + "COMMERCIAL FLIGHT": "VOLO COMMERCIALE", + "{aircraftClass} · {distance}": "{aircraftClass} · {distance}", + "DISTANCE UNKNOWN": "DISTANZA SCONOSCIUTA", + "{count} INPUTS UNKNOWN": { + "one": "{count} INPUT SCONOSCIUTO", + "other": "{count} INPUT SCONOSCIUTI" + }, + "SOURCE STATUS UNAVAILABLE": "STATO FONTE NON DISPONIBILE", + "Restore real aircraft": "Ripristina l'aereo reale", + "Reclassify as TR-3B": "Riclassifica come TR-3B", + "TRACK ACQUIRED": "TRACCIA ACQUISITA", + "{label} · COURSE {heading}°": "{label} · ROTTA {heading}°", + "Context could not restore every layer; try again": "Il Contesto non ha potuto ripristinare tutti i livelli; riprova", + "No selected data layers": "Nessun livello dati selezionato", + "{count} data layers could not be cleared": { + "one": "{count} livello dati non è stato disattivato", + "other": "{count} livelli dati non sono stati disattivati" + }, + "Cleared {count} data layers": { + "one": "Disattivato {count} livello dati", + "other": "Disattivati {count} livelli dati" + }, + "Selected data layers could not be cleared": "Impossibile disattivare i livelli dati selezionati", + "Space Missions could not complete the requested transition; try again": "Impossibile completare la transizione richiesta per Missioni spaziali; riprova", + "Nearby installations refreshed": "Installazioni vicine aggiornate", + "Nearby installations could not be refreshed; try again": "Impossibile aggiornare le installazioni vicine; riprova", + "Space Missions cancellation could not restore the previous layer state": "L'annullamento di Missioni spaziali non ha potuto ripristinare lo stato precedente dei livelli", + "That layer is unavailable in the current Context mode": "Quel livello non è disponibile nella modalità Contesto attuale", + "{layerId} could not {action} cleanly": "{layerId} non ha potuto {action} correttamente", + "start": "avviarsi", + "stop": "fermarsi", + "{mode} could not start because another layer did not stop cleanly": "Impossibile avviare {mode}: un altro livello non si è fermato correttamente", + "Space Missions": "Missioni spaziali", + "Context": "Contesto", + "Live Flights": "Voli Live", + "Military Flights": "Voli Militari", + "Earthquakes (24h)": "Terremoti (24h)", + "Satellites": "Satelliti", + "Space Missions (30d)": "Missioni Spaziali (30g)", + "Street Traffic": "Traffico Stradale", + "CCTV": "CCTV", + "Radio": "Radio", + "Bikeshare": "Bike Sharing", + "Live AIS Vessels": "Navi AIS Live", + "Mapped Installations": "Installazioni Mappate", + "Global Context": "Contesto Globale", + "Datacenters": "Data Center", + "Dams": "Dighe", + "Submarine Cables": "Cavi Sottomarini", + "FIRMS Active Fires": "Incendi Attivi FIRMS", + "ENABLING": "ATTIVAZIONE", + "DISABLING": "DISATTIVAZIONE", + "{state} · {source}": "{state} · {source}", + "UNCERTAIN · {source} · lifecycle state requires reconciliation": "INCERTO · {source} · lo stato del ciclo di vita richiede riconciliazione", + "{state} · {source} · {detail} · retry {seconds}s": "{state} · {source} · {detail} · nuovo tentativo tra {seconds}s", + "{state} · {source} · {detail}": "{state} · {source} · {detail}", + "never": "mai", + "{source} · {loadingLabel}": "{source} · {loadingLabel}", + "{accepted} of {raw} records accepted": "{accepted} record accettati su {raw}", + "incomplete snapshot": "snapshot incompleto", + "{state} · {source} · {detail} · {ago}": "{state} · {source} · {detail} · {ago}", + "{state} · {source} · {ago} · retrying in {seconds}s": "{state} · {source} · {ago} · nuovo tentativo tra {seconds}s", + "{state} · {source} · {ago}": "{state} · {source} · {ago}", + "{source} · {ago}": "{source} · {ago}", + "UNCERTAIN": "INCERTO", + "{name}: {state}": "{name}: {state}", + "{count}s ago": "{count}s fa", + "CONNECTING": "CONNESSIONE", + "📍 Location: --": "📍 Posizione: --", + "Landmark: --": "Punto di interesse: --", + "Searched location": "Luogo cercato", + "ORBIT": "ORBITA", + "Location not found": "Luogo non trovato", + "Search failed": "Ricerca non riuscita", + "Fly to a POI first": "Vola prima a un punto di interesse", + "Reset to full globe view": "Ripristina la vista del globo intero", + "Reset cockpit to full globe view": "Ripristina il cockpit alla vista del globo intero", + "Resetting to full globe view": "Ripristino della vista del globo intero", + "Resetting cockpit to full globe view": "Ripristino del cockpit alla vista del globo intero", + "MAP": "MAPPA", + "panel": "pannello", + "Expand {name}": "Espandi {name}", + "Collapse {name}": "Comprimi {name}", + "Expand Radio": "Espandi Radio", + "Collapse Radio": "Comprimi Radio", + "Expand Radio section": "Espandi la sezione Radio", + "Collapse Radio section": "Comprimi la sezione Radio", + "Panel layout updated — positions reset to new defaults": "Layout dei pannelli aggiornato — posizioni ripristinate ai nuovi valori predefiniti", + "Collapse Cockpit display options": "Comprimi le opzioni display del cockpit", + "Expand Cockpit display options": "Espandi le opzioni display del cockpit", + "Collapse Cockpit Radio controls": "Comprimi i controlli Radio del cockpit", + "Expand Cockpit Radio controls": "Espandi i controlli Radio del cockpit", + "NO STATIONS": "NESSUNA STAZIONE", + "NO STATION AVAILABLE": "NESSUNA STAZIONE DISPONIBILE", + "{name}, station {index} of {total}": "{name}, stazione {index} di {total}", + "No station available": "Nessuna stazione disponibile", + "OFF AIR": "FUORI ONDA", + "STATION UNAVAILABLE": "STAZIONE NON DISPONIBILE", + "Radio could not {action} cleanly": "La Radio non ha potuto {action} correttamente", + "Close compact Radio controls": "Chiudi i controlli Radio compatti", + "Open compact Radio controls": "Apri i controlli Radio compatti", + "SYNC": "SYNC", + "RECONCILE": "RICONCILIA", + "DISABLE": "DISATTIVA", + "ENABLE": "ATTIVA", + "Reconcile Radio — lifecycle uncertain": "Riconcilia la Radio — ciclo di vita incerto", + "Disable Radio": "Disattiva la Radio", + "Enable Radio": "Attiva la Radio", + "DIRECTORY BAND": "BANDA ELENCO", + "{category} BAND": "BANDA {category}", + "NO STATION SELECTED": "NESSUNA STAZIONE SELEZIONATA", + "Directory metadata only": "Solo metadati dell'elenco", + "Loading station directory…": "Caricamento dell'elenco stazioni…", + "Choose a globe marker or use next.": "Scegli un marcatore sul globo o usa SUCC.", + "TAGS · {tags}": "TAG · {tags}", + "Play": "Riproduci", + "PLAY": "PLAY", + "selected": "selezionata", + "nearest": "più vicina", + "{action} {target} radio station": "{action} stazione radio {target}", + "RADIO STATE UNCERTAIN": "STATO RADIO INCERTO", + "SYNCING DIRECTORY": "SINCRONIZZAZIONE ELENCO", + "RADIO READY": "RADIO PRONTA", + "SYNCING": "SYNC IN CORSO", + "READY": "PRONTA", + "station": "stazione", + " · stale/degraded directory": " · elenco obsoleto/degradato", + " · degraded directory": " · elenco degradato", + " · stale directory": " · elenco obsoleto", + " · outside current filter": " · fuori dal filtro attuale", + "Ready — playback starts only from your action": "Pronta — la riproduzione parte solo su tua azione", + "Radio off": "Radio spenta", + "Connecting directly to broadcaster…": "Connessione diretta all'emittente…", + "Buffering broadcaster stream…": "Buffering del flusso dell'emittente…", + "Playing {station}": "In riproduzione: {station}", + "Paused {station}": "In pausa: {station}", + "Broadcaster stream unavailable": "Flusso dell'emittente non disponibile", + " · muted during voice interaction": " · silenziata durante l'interazione vocale", + " · restoring volume after voice": " · ripristino del volume dopo la voce", + " · static indicates no broadcaster audio": " · il rumore indica assenza di audio dall'emittente", + " · tuning static until broadcaster starts": " · rumore di sintonia fino all'avvio dell'emittente", + "Station unavailable after directory refresh — choose another channel": "Stazione non disponibile dopo l'aggiornamento dell'elenco — scegli un altro canale", + "Radio is enabling…": "Attivazione della Radio…", + "Radio is disabling…": "Disattivazione della Radio…", + "Radio lifecycle is uncertain — use Enable or Disable to reconcile": "Il ciclo di vita della Radio è incerto — usa Attiva o Disattiva per riconciliare", + "Scene action failed": "Azione sulla scena non riuscita", + "Delete shot \"{shot}\"?": "Eliminare lo scatto \"{shot}\"?", + "SPARSE": "RADA", + "BALANCED": "BILANCIATA", + "DEL": "ELIM", + "entity": "elemento", + "Shared {subject} follow expired": "Il tracciamento condiviso di {subject} è scaduto", + "Shared {subject} could not be restored — feed unavailable": "Impossibile ripristinare la condivisione di {subject} — feed non disponibile", + "Shared {subject} is unavailable": "La condivisione di {subject} non è disponibile", + "ACQUIRING": "ACQUISIZIONE", + "SHARED {subject}": "CONDIVISO: {subject}", + "LOADING LIVE DATA": "CARICAMENTO DATI LIVE", + "LOAD COMPLETE": "CARICAMENTO COMPLETATO", + "LOAD CANCELLED": "CARICAMENTO ANNULLATO", + "LOAD FAILED": "CARICAMENTO FALLITO", + "LIVE DATA OFF": "DATI LIVE DISATTIVATI", + "MAPPED SITES LOADED": "SITI MAPPATI CARICATI", + "RETRYING MAPPED SITES": "NUOVO TENTATIVO SITI MAPPATI", + "FETCHING MAPPED SITES": "RICERCA SITI MAPPATI", + "TURNING OFF LIVE DATA": "DISATTIVAZIONE DATI LIVE", + "REFRESHING LIVE DATA": "AGGIORNAMENTO DATI LIVE", + "syncing road network": "sincronizzazione rete stradale", + "retry pending": "nuovo tentativo in sospeso", + "retrying in {seconds}s": "nuovo tentativo tra {seconds}s", + "Celestial ring — reveal the full globe": "Anello celeste — mostra il globo intero", + "Celestial ring — available in Normal style": "Anello celeste — disponibile nello stile Normale", + "Detection overlay: {mode}": "Overlay di rilevamento: {mode}", + "Detection overlay: off": "Overlay di rilevamento: disattivato", + "DETECT": "RILEV.", + "voice|LISTENING": "IN ASCOLTO", + "voice|EXECUTING": "ESECUZIONE", + "AI AGENT": "AGENTE IA", + "Voice model tier — applies next session": "Livello del modello vocale: si applica alla prossima sessione", + "Estimated session cost": "Costo stimato della sessione", + "Voice control — activate to toggle voice; hold Space to speak": "Controllo vocale: attiva per abilitare la voce; tieni premuto Spazio per parlare", + "VOICE STANDBY": "VOCE IN ATTESA", + "VOICE CONTROL": "CONTROLLO VOCALE", + "Hold Space to speak · tap Space to activate focused controls": "Tieni premuto Spazio per parlare · tocca Spazio per attivare i controlli in focus", + "VOICE SYSTEM ERROR": "ERRORE SISTEMA VOCALE", + "DISMISS": "CHIUDI", + "Check microphone permission and network access, then try again.": "Controlla il permesso del microfono e l'accesso alla rete, poi riprova.", + "Release Space to send": "Rilascia Spazio per inviare", + "Hold Space to talk": "Tieni premuto Spazio per parlare", + "Requesting microphone": "Richiesta microfono", + "Ask or command": "Chiedi o comanda", + "Running command": "Comando in esecuzione", + "Voice off": "Voce disattivata", + "WebRTC microphone support unavailable": "Supporto microfono WebRTC non disponibile", + "VOICE UNAVAILABLE": "VOCE NON DISPONIBILE", + "VOICE ACTIVE": "VOCE ATTIVA", + "Voice session could not be started.": "Impossibile avviare la sessione vocale.", + "Next session: {pendingId} — this session stays on {modelId}": "Prossima sessione: {pendingId}. Questa sessione resta su {modelId}", + "Voice model: {pendingId} — click to switch to {target}; applies next session": "Modello vocale: {pendingId}. Clic per passare a {target}; si applica alla prossima sessione", + "Estimated session cost on {modelId} — {responses} response(s). Warns at {warn}, ends the session at {cap}.": "Costo stimato della sessione su {modelId}: {responses} risposta/e. Avviso a {warn}, la sessione termina a {cap}.", + "{tier} applies next session": "{tier} si applica alla prossima sessione", + "Session ended — cost cap {cost}": "Sessione terminata: limite di costo {cost}", + "Radio did not start": "La radio non si è avviata", + "Aircraft cockpit view": "Vista cockpit dell'aereo", + "LEVEL": "LIVELLO", + "Estimated destination direction": "Direzione stimata della destinazione", + "DEST ---°": "DEST ---°", + "OPTICAL PLANE · 01": "PIANO OTTICO · 01", + "VISOR LOCK · ACTIVE": "BLOCCO VISIERA · ATTIVO", + "GROUND SPEED · KTS": "VEL. AL SUOLO · KTS", + "ALTITUDE · FT": "ALTITUDINE · FT", + "FIRST PERSON": "PRIMA PERSONA", + "LIVE TRACK · COURSE ALIGNED": "TRACCIA LIVE · ROTTA ALLINEATA", + "Cockpit vision style": "Stile di visione del cockpit", + "Previous cockpit vision style": "Stile di visione del cockpit precedente", + "Previous vision style": "Stile di visione precedente", + "Current cockpit vision style: NORMAL. Activate for next style.": "Stile di visione del cockpit attuale: NORMALE. Attiva per lo stile successivo.", + "Current style: NORMAL — click for next": "Stile attuale: NORMALE — clic per il successivo", + "CURRENT": "ATTUALE", + "Next cockpit vision style": "Stile di visione del cockpit successivo", + "Next vision style": "Stile di visione successivo", + "Current aircraft heading": "Prua attuale dell'aereo", + "GROUND SPEED": "VEL. AL SUOLO", + "ALTITUDE": "ALTITUDINE", + "Contact cockpit summary": "Riepilogo contatto del cockpit", + "CONTACT": "CONTATTO", + "CONTACTS · 250 KM": "CONTATTI · 250 KM", + "Contact navigation": "Navigazione contatti", + "CONTEXT ONLY": "SOLO CONTESTO", + "Nearby cohort counts": "Conteggi dei gruppi vicini", + "NEAREST OBSERVED / MAPPED": "PIÙ VICINO OSSERVATO / MAPPATO", + "AVAILABLE INPUTS ONLY · NOT AN ALL-CLEAR": "SOLO INPUT DISPONIBILI · NON È UN VIA LIBERA", + "Cockpit briefing carousel": "Carosello briefing del cockpit", + "Estimated flight plan": "Piano di volo stimato", + "ESTIMATED FLIGHT PLAN": "PIANO DI VOLO STIMATO", + "FROM": "DA", + "TO": "A", + "Cockpit briefing controls": "Controlli briefing del cockpit", + "Previous briefing page": "Pagina briefing precedente", + "Next briefing page": "Pagina briefing successiva", + "Live signals": "Segnali live", + "Latest regional news": "Ultime notizie regionali", + "Location-based information": "Informazioni basate sulla posizione", + "TEMP": "TEMP", + "WIND": "VENTO", + "SKY": "CIELO", + "PRECIP": "PRECIP", + "Show Live Signals": "Mostra Segnali live", + "NEWS": "NOTIZIE", + "Show Regional News": "Mostra Notizie regionali", + "Show Local Info": "Mostra Info locali", + "Cockpit display and Radio controls": "Controlli display e Radio del cockpit", + "DISPLAY": "DISPLAY", + "Cockpit display options": "Opzioni display del cockpit", + "RADIO": "RADIO", + "Cockpit compact Radio controls": "Controlli Radio compatti del cockpit", + "Previous filtered radio station": "Stazione radio filtrata precedente", + "Play selected radio station": "Riproduci la stazione radio selezionata", + "Next filtered radio station": "Stazione radio filtrata successiva", + "VOLUME": "VOLUME", + "Cockpit Radio volume": "Volume Radio del cockpit", + "View switcher": "Selettore vista", + "Exit cockpit and return to full globe view": "Esci dal cockpit e torna alla vista del globo intero", + "RESET": "RESET", + "Exit cockpit view": "Esci dalla vista cockpit", + "EXIT COCKPIT": "ESCI DAL COCKPIT", + "Navigation, voice, and visual preset controls": "Controlli di navigazione, voce e preset visivi", + "Expand Visual Presets": "Espandi Preset visivi", + "Pin visual presets": "Fissa i preset visivi", + "Keep visual presets open": "Mantieni aperti i preset visivi", + "Show the globe without a visual filter.": "Mostra il globo senza filtro visivo.", + "Emulate a green phosphor CRT with scanlines and screen curvature.": "Emula un CRT a fosfori verdi con scanline e curvatura dello schermo.", + "Simulate night-vision goggles with green intensification and a tube vignette.": "Simula la visione notturna con intensificazione verde e vignettatura del tubo.", + "Simulate FLIR-style thermal contrast. Turn up Ironbow for color.": "Simula il contrasto termico in stile FLIR. Alza Ironbow per il colore.", + "Apply bright cel-shaded color and illustrated outlines.": "Applica colori vivaci cel-shaded e contorni illustrati.", + "Apply high-contrast monochrome film-noir grading.": "Applica un color grading noir monocromatico ad alto contrasto.", + "Add a cold, snowy whiteout treatment to the scene.": "Aggiunge alla scena un effetto freddo di nevicata e whiteout.", + "MAP SOURCE": "FONTE MAPPA", + "Map source": "Fonte mappa", + "Style": "Stile", + "Expand LOCATION": "Espandi POSIZIONE", + "Collapse panel": "Comprimi pannello", + "Pin location tray": "Fissa il pannello posizione", + "Keep location tray open": "Mantieni aperto il pannello posizione", + "Search any location": "Cerca un luogo qualsiasi", + "Search location by name or coordinates": "Cerca un luogo per nome o coordinate", + "Search any location...": "Cerca un luogo qualsiasi...", + "WEATHER": "METEO", + "CONTEXT": "CONTESTO", + "Compact Radio controls": "Controlli Radio compatti", + "Open detailed Radio controls": "Apri i controlli Radio dettagliati", + "Previous station": "Stazione precedente", + "Next station": "Stazione successiva", + "Compact Radio volume": "Volume Radio compatto", + "Expand panel": "Espandi pannello", + "Context mode": "Modalità contesto", + "CONTACTS": "CONTATTI", + "Cycles the nearest contacts of whatever type you select — planes, vessels, installations. Satellites track independently.": "Scorre i contatti più vicini del tipo selezionato: aerei, navi, installazioni. I satelliti vengono tracciati in modo indipendente.", + "SPACE MISSIONS": "MISSIONI SPAZIALI", + "SELECT CONTEXT": "SELEZIONA CONTESTO", + "Contact Context actions": "Azioni Contesto contatto", + "COCKPIT": "COCKPIT", + "SEARCH NEARBY SITES": "CERCA SITI VICINI", + "Reclassify tracked contact as TR-3B": "Riclassifica il contatto tracciato come TR-3B", + "CONTACTS CONTEXT OFF": "CONTESTO CONTATTI DISATTIVATO", + "SELECT CONTACTS TO LOAD OBSERVED / MAPPED PROXIMITY": "SELEZIONA CONTATTI PER CARICARE LA PROSSIMITÀ OSSERVATA / MAPPATA", + "Available Space Missions": "Missioni spaziali disponibili", + "AVAILABLE MISSIONS": "MISSIONI DISPONIBILI", + "SELECT A MISSION TO INSPECT": "SELEZIONA UNA MISSIONE DA ESAMINARE", + "LOADING 30-DAY MISSION INDEX": "CARICAMENTO INDICE MISSIONI A 30 GIORNI", + "TAB PREVIEWS · ENTER / SPACE SELECTS": "TAB ANTEPRIMA · INVIO / SPAZIO SELEZIONA", + "Internet radio and local SDR": "Radio internet e SDR locale", + "STATION TAG": "TAG STAZIONE", + "Filter stations by station tag": "Filtra le stazioni per tag", + "All": "Tutti", + "Enable Radio, then choose a globe marker or use next.": "Attiva la Radio, poi scegli un marcatore sul globo o usa SUCC.", + "DRAG TO TUNE": "TRASCINA PER SINTONIZZARE", + "ALL · DRAG THE NEEDLE": "TUTTE · TRASCINA L'AGO", + "SNAPS TO AVAILABLE STATIONS": "SI AGGANCIA ALLE STAZIONI DISPONIBILI", + "Radio playback": "Riproduzione radio", + "Previous filtered station": "Stazione filtrata precedente", + "Play selected station": "Riproduci la stazione selezionata", + "Next filtered station": "Stazione filtrata successiva", + "STOP": "STOP", + "Stop radio playback": "Ferma la riproduzione radio", + "Radio volume": "Volume radio", + "STATION SITE": "SITO STAZIONE", + "Audio connects directly to the broadcaster after you press play. Your IP is visible to that broadcaster.": "L'audio si collega direttamente all'emittente dopo aver premuto play. Il tuo IP è visibile a quell'emittente.", + "Intelligence HUD (H)": "HUD Intelligence (H)", + "Layout": "Layout", + "HUD layout": "Layout HUD", + "Tactical": "Tattico", + "Operator": "Operatore", + "Minimal": "Minimale", + "Detection Overlay (D)": "Overlay di rilevamento (D)", + "Detection overlay": "Overlay di rilevamento", + "Detection label density": "Densità delle etichette di rilevamento", + "Allocation": "Allocazione", + "Detection label allocation": "Allocazione delle etichette di rilevamento", + "Elastic": "Elastica", + "Weighted": "Ponderata", + "Fade": "Dissolv.", + "Detection fade distance": "Distanza di dissolvenza del rilevamento", + "World-overlay fade distance outside the keyhole as a percentage of its radius": "Distanza di dissolvenza dell'overlay fuori dal foro, come percentuale del suo raggio", + "Outside": "Esterno", + "Detection opacity outside the keyhole": "Opacità del rilevamento fuori dal foro", + "World-overlay label and card opacity beyond the fade distance": "Opacità di etichette e schede dell'overlay oltre la distanza di dissolvenza", + "PARAMETERS": "PARAMETRI", + "3D aircraft — flat icons zoomed out, 3D models up close": "Aerei 3D — icone piatte da lontano, modelli 3D da vicino", + "Models": "Modelli", + "3D model coverage": "Copertura dei modelli 3D", + "Proximity": "Prossimità", + "Scope — the circular viewport mask": "Scope — la maschera circolare della vista", + "Scope": "Scope", + "Feather": "Sfumatura", + "Scope edge feather": "Sfumatura del bordo dello scope", + "Scope edge feather as a percentage of the keyhole radius": "Sfumatura del bordo dello scope, come percentuale del raggio del foro", + "Celestial": "Celeste", + "Hide UI chrome": "Nascondi l'interfaccia", + "Clean UI": "UI pulita", + "Bloom / Glow": "Bloom / Bagliore", + "Bloom intensity": "Intensità del bloom", + "Sharpening": "Nitidezza", + "Sharpen": "Nitidezza", + "Sharpen intensity": "Intensità della nitidezza", + "EXIT CLEAN VIEW": "ESCI DA VISTA PULITA", + "Return UI controls": "Ripristina i controlli UI", + "Initializing photorealistic world...": "Inizializzazione del mondo fotorealistico...", + "DATA LAYERS": "LIVELLI DATI", + "NEAREST": "PIÙ VICINA", + "CCTV camera": "Telecamera CCTV", + "CALIBRATION": "CALIBRAZIONE", + "Drag the camera in the world: rings rotate, arrows move, handles set range/FOV": "Trascina la telecamera nel mondo: gli anelli ruotano, le frecce spostano, i punti di controllo impostano portata/FOV", + "Camera pose — click a value to type": "Posa della telecamera — clic su un valore per digitare", + "Heading (compass °) — click to type": "Direzione (bussola °) — clic per digitare", + "Pitch (° up/down) — click to type": "Inclinazione (° su/giù) — clic per digitare", + "Horizontal FOV (°) — click to type": "FOV orizzontale (°) — clic per digitare", + "Range / monitor-plane distance (m) — click to type": "Portata / distanza del piano monitor (m) — clic per digitare", + "Mount height above ground (m) — click to type": "Altezza di montaggio dal suolo (m) — clic per digitare", + "North offset from catalog position (m) — click to type": "Scostamento a nord dalla posizione a catalogo (m) — clic per digitare", + "East offset from catalog position (m) — click to type": "Scostamento a est dalla posizione a catalogo (m) — clic per digitare", + "SAVE CAL": "SALVA CAL", + "RESET CAL": "RESET CAL", + "SCENE SUMMARY": "RIEPILOGO SCENA", + "SCENES": "SCENE", + "Scene recipe": "Ricetta della scena", + "NEW": "NUOVA", + "CAPTURE SHOT": "CATTURA SCATTO", + "UPDATE SHOT": "AGGIORNA SCATTO", + "START": "AVVIA", + "EXPORT PRESETS": "ESPORTA PRESET", + "IMPORT": "IMPORTA", + "RUN LOG": "LOG ESECUZIONE", + "POWER UP": "POWER UP", + "GROUND STATION · PROVIDER SETTINGS": "STAZIONE A TERRA · IMPOSTAZIONI PROVIDER", + "Close key setup": "Chiudi la configurazione delle chiavi", + "Power up the globe": "Accendi il globo", + "The globe already flies keyless. Every key below switches on another real feed — paste one and it's saved into this app's local configuration, then the server restarts itself. Server-side keys stay on this machine; Google Maps and Cesium ion run in the browser and must be provider-restricted. Keys you configured elsewhere are shown but never touched.": "Il globo funziona già senza chiavi. Ogni chiave qui sotto attiva un altro feed reale: incollane una e verrà salvata nella configurazione locale di questa app, poi il server si riavvia da solo. Le chiavi lato server restano su questa macchina; Google Maps e Cesium ion funzionano nel browser e vanno limitate al provider. Le chiavi configurate altrove vengono mostrate ma mai modificate.", + "SAVE KEYS": "SALVA CHIAVI", + "ESC to close": "ESC per chiudere", + "The Google Maps key buys the photorealistic planet — everything else stacks on top.": "La chiave Google Maps sblocca il pianeta fotorealistico: tutto il resto si aggiunge sopra.", + "NO PLACE LEFT BEHIND": "NESSUN LUOGO ESCLUSO", + "ACTIVE STYLE": "STILE ATTIVO", + "Globe actions": "Azioni del globo", + "Turn off all selected data layers": "Disattiva tutti i livelli dati selezionati", + "Copy share link": "Copia il link di condivisione", + "Reset camera and return to full globe view": "Ripristina la camera e torna alla vista del globo intero", + "MISSION CONTROL · FIRST LAUNCH": "CONTROLLO MISSIONE · PRIMO AVVIO", + "Choose your first view": "Scegli la tua prima vista", + "LIVE CONTACTS": "CONTATTI LIVE", + "Aircraft, vessels and nearby intelligence": "Aerei, navi e intelligence nelle vicinanze", + "Launches, spacecraft and orbital context": "Lanci, veicoli spaziali e contesto orbitale", + "EXPLORE MANUALLY": "ESPLORA A MANO", + "Begin with a clean globe": "Inizia con un globo pulito", + "Don't show this again": "Non mostrare più", + "ESC to dismiss": "ESC per chiudere", + "Tip: the GEV MIC button in the dock lets you talk to the map.": "Suggerimento: il pulsante GEV MIC nel dock ti permette di parlare con la mappa." +} From bdd24798db6ac7120401f2e1368cb0b853311ad9 Mon Sep 17 00:00:00 2001 From: Enzo Abyie Date: Wed, 28 Oct 2026 12:37:08 +0400 Subject: [PATCH 02/83] i18n(ja): Japanese strings from #913 The Japanese locale by abiyeenzo (#913), converted from its namespaced JS catalogs to the English-keyed ja.json: 852 entries whose English still matches the current UI. --- src/i18n/locales/ja.json | 868 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 868 insertions(+) create mode 100644 src/i18n/locales/ja.json diff --git a/src/i18n/locales/ja.json b/src/i18n/locales/ja.json new file mode 100644 index 000000000..28c57d3d1 --- /dev/null +++ b/src/i18n/locales/ja.json @@ -0,0 +1,868 @@ +{ + "Flying to Austin, TX...": "テキサス州オースティンへ移動中...", + "Restoring shared view...": "共有ビューを復元中...", + "Configuring viewer...": "ビューアを設定中...", + "Loading Google 3D Tiles...": "Google 3D Tiles を読み込み中...", + "Loading the keyless globe...": "キー不要の地球儀を読み込み中...", + "Google 3D Tiles unavailable ({detail}). Loading the keyless globe...": "Google 3D Tiles を利用できません ({detail})。キー不要の地球儀を読み込み中...", + "Initializing systems...": "システムを初期化中...", + "Close data attribution": "データ出典を閉じる", + "UNAVAILABLE": "利用不可", + "SOURCE": "ソース", + "Overpass rate-limited": "Overpass がレート制限中", + "Overpass timed out": "Overpass がタイムアウトしました", + "Overpass could not complete the query": "Overpass がクエリを完了できませんでした", + "Overpass temporarily unavailable": "Overpass が一時的に利用できません", + "Retrying mapped sites…": "マップ済み施設を再試行中…", + "Fetching mapped sites…": "マップ済み施設を取得中…", + "{reason} — retrying in {seconds}s": "{reason} — {seconds}秒後に再試行", + "{reason} — retry pending": "{reason} — 再試行待ち", + "Zoom in to search mapped installations": "ズームインして、マップ済み施設を検索してください", + "Showing cached mapped sites": "キャッシュ済みのマップ済み施設を表示中", + "Mapped sites not loaded": "マップ済み施設は未読込です", + "Mapped sites loaded": "マップ済み施設を読み込みました", + "feed unavailable": "フィードを利用できません", + "feed stale": "フィードが古い", + "observed or mapped nearby context": "観測またはマップ済みの周辺コンテキスト", + "no observed or mapped objects in current feeds": "現在のフィードに観測またはマップ済みの対象なし", + "STATION": "宇宙ステーション", + "Crewed stations and their visiting vehicles": "有人宇宙ステーションと来訪機", + "NAV": "測位", + "GNSS navigation — GPS, GLONASS, Galileo": "GNSS測位: GPS、GLONASS、Galileo", + "GEO": "GEO", + "Geostationary belt — comms and weather, fixed over the equator": "静止軌道帯: 通信と気象、赤道上空に固定", + "VISUAL": "可視", + "Brightest naked-eye objects — CelesTrak visual group": "肉眼で見える最も明るい天体: CelesTrak visual グループ", + "COMMS": "通信", + "Broadband constellation shell — shown only in DENSE mode": "ブロードバンドコンステレーションのシェル: 高密度モードでのみ表示", + "FISHING": "漁船", + "TOWING": "曳航", + "DREDGER": "浚渫船", + "DIVE OPS": "潜水作業", + "MILITARY": "軍用", + "SAILING": "帆船", + "PLEASURE": "プレジャーボート", + "PILOT": "水先船", + "SAR": "SAR", + "TUG": "タグボート", + "PORT TENDER": "港湾作業船", + "ANTI-POLLUTION": "汚染防除船", + "LAW ENFORCE": "法執行", + "MEDICAL": "医療", + "HIGH-SPEED": "高速船", + "PASSENGER": "旅客船", + "CARGO": "貨物船", + "TANKER": "タンカー", + "OTHER": "その他", + "ENVIRONMENTAL": "環境", + "EARTH WATCH": "地球ウォッチ", + "ACTIVE EVENTS": "発生中のイベント", + "Starting live contacts…": "ライブコンタクトを開始中…", + "Opening space missions…": "宇宙ミッションを開いています…", + "Scanning active events…": "発生中のイベントをスキャン中…", + "Live earthquakes and active fires, from USGS and NASA": "USGS と NASA による、地震と火災のライブ情報", + "It feels like a forbidden cockpit—then you realize the sources are public and the data is real.": "禁断のコックピットのようですが、情報源はすべて公開されており、データは本物です。", + "Working…": "処理中…", + "Could not open that mission{detail}. Retry or explore manually.": "ミッションを開けませんでした{detail}。再試行するか、手動で探索してください。", + "This browser is blocking storage, so that could not be saved.": "このブラウザはストレージをブロックしているため、保存できませんでした。", + "CRT": "CRT", + "NVG": "NVG", + "FLIR": "FLIR", + "SNOW": "雪", + "LOADING": "読込中", + "DEGRADED": "性能低下", + "STALE": "古い", + "PARTIAL": "一部", + "FALLBACK": "フォールバック", + "SUMMARY": "概要", + "Awaiting telemetry...": "テレメトリー待機中...", + "REC": "REC", + "AIS: --": "AIS: --", + "POWER UP · {count} KEYS WAITING": { + "other": "POWER UP · キー待機 {count}件" + }, + "POWERED UP": "電源オン", + "Save failed ({status}).": "保存に失敗しました ({status})。", + "REMOVE": "削除", + "Remove {title} from this app's saved keys": "{title}をこのアプリの保存済みキーから削除", + "your app configuration": "アプリの設定", + "your local .env": "ローカルの .env", + "Saving…": "保存中…", + "Save failed: {detail}": "保存に失敗しました: {detail}", + "Paste at least one key first.": "まず、キーを1つ以上貼り付けてください。", + "Saved to {store}. Restarting — this page reloads itself.": "{store}に保存しました。再起動中です。このページは自動で再読み込みされます。", + "Remove this key from your saved configuration?": "このキーを保存済みの設定から削除しますか?", + "Removed from {store}. Restarting — this page reloads itself.": "{store}から削除しました。再起動中です。このページは自動で再読み込みされます。", + "Places context + Street View fallback; optional separate key": "Places コンテキスト + Street View フォールバック。別キーも指定可", + "Live ships, worldwide": "世界中の船舶をライブ表示", + "Live active-fire detections": "火災のライブ検知", + "Real live traffic (keyless runs a simulation)": "実際のライブ交通情報 (キーなしはシミュレーション)", + "Bing imagery map stacks + world terrain": "Bing 画像のマップスタック + 世界地形", + "More flight-polling credits (anonymous works without)": "航空機ポーリングのクレジット増加 (匿名でも利用可)", + "CONTEXT READY": "コンテキスト準備完了", + "GLOBAL CONTEXT OFF": "グローバルコンテキスト オフ", + "SELECT A FLIGHT, VESSEL, OR MAPPED INSTALLATION": "フライト、船舶、またはマップ済み施設を選択", + "ENABLE TO LOAD OBSERVED / MAPPED PROXIMITY": "有効にして、観測 / マップ済みの近接情報を読み込み", + "Unavailable": "利用不可", + "Focus {label}": "{label}にフォーカス", + "Global Context navigation": "グローバルコンテキストナビゲーション", + "Previous — prior visited contact in the 250 km window": "前へ: 250 km圏内で直前に訪れたコンタクト", + "PREVIOUS": "前へ", + "FOCUS": "フォーカス", + "Next — nearest unvisited contact in the 250 km window": "次へ: 250 km圏内で最も近い未訪問のコンタクト", + "NEXT": "次へ", + "Open-source mapped/observed context. Missing broadcasts, unloaded map areas, or unmapped sites are not evidence of absence.": "オープンソースのマップ済み/観測済みコンテキストです。放送の欠落、未読込のマップ領域、未マップの施設は、不在の証拠ではありません。", + "HDG {value}°": "HDG {value}°", + "BRG {value}°": "BRG {value}°", + "BRG —": "BRG —", + "CRS {value}°": "CRS {value}°", + "CURRENT VIEWPORT ONLY": "現在の表示範囲のみ", + "WITHIN {km} KM": "{km} KM以内", + "Flights": "フライト", + "Military flights": "軍用機", + "AIS vessels": "AIS船舶", + "Mapped installations": "マップ済み施設", + "syncing {count} city feeds...": "{count}都市のフィードを同期中...", + "scanning nearby systems...": "周辺のシステムをスキャン中...", + "Station {id}": "ステーション {id}", + "Station": "ステーション", + "🚲 {bikes} avail · {docks} docks · {capacity} cap": "🚲 空き {bikes} · ドック {docks} · 容量 {capacity}", + "⚠️ Not installed": "⚠️ 未設置", + "⚠️ Not renting": "⚠️ 貸出停止中", + "⚠️ Not returning": "⚠️ 返却不可", + "HDG {value}° (ESTIMATED)": "HDG {value}° (推定)", + "{count} CAMERAS STANDING BY · NO CAMERA SELECTED · CLICK A CAMERA TO ACTIVATE": "{count}台のカメラが待機中 · カメラ未選択 · カメラをクリックして有効化", + "No cameras available in catalog.": "カタログに利用できるカメラがありません。", + "{city} CCTV": "{city} CCTV", + "FOV {value}°": "FOV {value}°", + "COVERAGE {value}km²": "カバレッジ {value}km²", + "OVERLAP {count} cams": "重複 {count}台", + "ISOLATED VIEW": "単独ビュー", + "PROJ MONITOR": "投影 モニター", + "PROJ OFF": "投影 オフ", + "VIEWSHED": "可視域", + "CAL {value}": "CAL {value}", + "SRC {value}": "SRC {value}", + "{value} CONTEXT": "{value} コンテキスト", + "Focus fire detection {title}, {details}": "火災検知 {title} にフォーカス、{details}", + "{value} conf": "信頼度 {value}", + "{value} ago": "{value}前", + "sensor n/a": "センサー不明", + "FIRE · {frp} MW": "火災 · {frp} MW", + "NIGHT": "夜間", + "▲ {frp} MW": "▲ {frp} MW", + "FIRE": "火災", + "FIRES": "火災", + "max {value} MW": "最大 {value} MW", + "new {value}": "新規 {value}", + "just now": "たった今", + "<1m ago": "1分以内", + "{count}m ago": "{count}分前", + "{count}h ago": "{count}時間前", + "STALE · cached {age}": "古い · キャッシュ {age}", + "refreshing...": "更新中...", + "loading...": "読込中...", + "KEY REQUIRED": "キーが必要", + "LIVE · updated {age}": "ライブ · 更新 {age}", + "loading mapped installation context": "マップ済み施設のコンテキストを読み込み中", + "MAPPED INSTALLATION": "マップ済み施設", + "LAUNCH SITE · {site}": "射場 · {site}", + "LAUNCH SITE": "射場", + "T−{time} · {mission}": "T−{time} · {mission}", + "LAUNCH STANDBY": "打ち上げ待機", + "LIFTOFF · {mission}": "リフトオフ · {mission}", + "ASCENT REPLAY · {mission}": "上昇リプレイ · {mission}", + "ASCENT ESTIMATE · {mission}": "上昇推定 · {mission}", + "STAGE RE-ENTRY / RECOVERY · {mission}": "ステージ再突入 / 回収 · {mission}", + "ORBIT REPLAY · {mission}": "軌道リプレイ · {mission}", + "PAUSED · {title}": "一時停止 · {title}", + "UNSPECIFIED": "未指定", + "+{count} additional payload records": "追加のペイロード記録 +{count}件", + "PAYLOAD DATA UNAVAILABLE": "ペイロードデータなし", + "{value} KM DOWNRANGE": "ダウンレンジ {value} KM", + "POSITION UNAVAILABLE": "位置を取得できません", + "FLIGHT {count}": "フライト {count}", + "REUSED": "再使用", + "NO STAGE RE-ENTRY / RECOVERY DATA": "ステージの再突入 / 回収データなし", + "{count} / 30D": "{count} / 30日", + "NO MISSIONS AVAILABLE IN THE CURRENT 30-DAY WINDOW": "現在の30日間に該当するミッションはありません", + "DATE UNAVAILABLE": "日付不明", + "UNSPECIFIED OPERATOR": "運用者未指定", + "Select {mission}": "{mission}を選択", + "{value} KM": "{value} KM", + "{value} KM/S": "{value} KM/S", + "SELECTED SPACE MISSION": "選択中の宇宙ミッション", + "Show all missions": "すべてのミッションを表示", + "Deselect mission": "ミッションの選択を解除", + "MISSION": "ミッション", + "STATUS · ": "ステータス · ", + "LAUNCH SITE · ": "射場 · ", + "LAUNCH TIME · ": "打ち上げ時刻 · ", + "ORBIT · ": "軌道 · ", + "ASCENT PATH · ": "上昇経路 · ", + "CURRENT DISTANCE FROM EARTH · ": "現在の地球からの距離 · ", + "SATELLITE SPEED · ": "衛星速度 · ", + "PAYLOAD": "ペイロード", + "NAME": "名称", + "TYPE": "種別", + "DESTINATION": "目的地", + "STAGE / RE-ENTRY / RECOVERY": "ステージ / 再突入 / 回収", + "STAGE": "ステージ", + "STATUS": "ステータス", + "FINAL POSITION": "最終位置", + "REPLAY SPEED": "リプレイ速度", + "Replay speed multiplier": "リプレイ速度の倍率", + "REPLAY ASCENT": "上昇をリプレイ", + "Previous mission": "前のミッション", + "PREV": "前へ", + "Next mission": "次のミッション", + "SHOW ALL / DESELECT": "すべて表示 / 選択解除", + "Pause replay": "リプレイを一時停止", + "Cancel replay": "リプレイをキャンセル", + "EST. DOWNRANGE": "推定ダウンレンジ", + "PLANNED · ": "計画 · ", + "SUPPLIED TRAJECTORY POINTS": "提供された軌道点", + "RECONSTRUCTED ESTIMATE": "再構成による推定", + "Replay the estimated ascent with a following camera": "追従カメラで、推定された上昇をリプレイします", + "Resume replay": "リプレイを再開", + "T minus {seconds}": "T マイナス {seconds}", + "Preparing launch site": "射場を準備中", + "Liftoff": "リフトオフ", + "Ascent replay": "上昇リプレイ", + "Orbit replay": "軌道リプレイ", + ", paused": "、一時停止中", + "Alt unknown": "高度不明", + "Type unknown": "機種不明", + "Reg unknown": "登録記号不明", + "Operator unknown": "運航者不明", + "News": "ニュース", + "Talk": "トーク", + "Weather / Emergency": "気象 / 緊急", + "Public Safety": "公共安全", + "Aviation / Marine": "航空 / 海事", + "Traffic / Transit": "交通 / 公共交通", + "Music": "音楽", + "Other": "その他", + "Alternative": "オルタナティブ", + "Ambient": "アンビエント", + "Blues": "ブルース", + "Classical": "クラシック", + "Country": "カントリー", + "Dance": "ダンス", + "Electronic": "エレクトロニック", + "Folk": "フォーク", + "Funk": "ファンク", + "Hip-Hop": "ヒップホップ", + "House": "ハウス", + "Indie": "インディー", + "Jazz": "ジャズ", + "Latin": "ラテン", + "Metal": "メタル", + "Oldies": "オールディーズ", + "Pop": "ポップ", + "Punk": "パンク", + "R&B": "R&B", + "Reggae": "レゲエ", + "Rock": "ロック", + "Soul": "ソウル", + "Techno": "テクノ", + "Trance": "トランス", + "World": "ワールド", + "Add the full Starlink broadband shell (thousands of extra points)": "Starlink ブロードバンドシェル全体を追加 (数千の追加ポイント)", + "Loading the Starlink shell…": "Starlink シェルを読み込み中…", + "Starlink {detail} — click to retry": "Starlink {detail}: クリックで再試行", + "load failed": "読込失敗", + "Showing the full Starlink shell — click for the core catalog only": "Starlink シェル全体を表示中: クリックでコアカタログのみに戻す", + "DENSE ···": "高密度 ···", + "DENSE ✕": "高密度 ✕", + "DENSE": "高密度", + "Syncing flow · Roads: {source}": "フロー同期中 · 道路: {source}", + "LIVE · Roads: {source} · Roads without flow hidden": "ライブ · 道路: {source} · フローのない道路は非表示", + "LIVE · Roads: {source} · No flow roads in view": "ライブ · 道路: {source} · 表示範囲にフローのある道路なし", + "LIVE · Roads: {source} · Flow {percent}%": "ライブ · 道路: {source} · フロー {percent}%", + "SIMULATED · Roads: {source} · Flow {percent}%": "シミュレーション · 道路: {source} · フロー {percent}%", + "Syncing flow · Roads: OpenStreetMap · Flow: TomTom · Unmatched: simulated": "フロー同期中 · 道路: OpenStreetMap · フロー: TomTom · 未一致: シミュレーション", + "LIVE · Roads: OpenStreetMap · Flow: TomTom · {percent}% cov · Unmatched: simulated": "ライブ · 道路: OpenStreetMap · フロー: TomTom · カバー率 {percent}% · 未一致: シミュレーション", + "LIVE · Roads: OpenStreetMap · Flow: TomTom · {percent}% cov": "ライブ · 道路: OpenStreetMap · フロー: TomTom · カバー率 {percent}%", + "SIMULATED · Roads: OpenStreetMap · Flow: TomTom (no matches)": "シミュレーション · 道路: OpenStreetMap · フロー: TomTom (一致なし)", + "SIMULATED — traffic service unreachable": "シミュレーション: 交通サービスに接続できません", + "SIMULATED — add TomTom key for live": "シミュレーション: ライブ表示には TomTom キーを追加", + "AIS: {name}": "AIS: {name}", + "{type} SPD: {speed} HDG: {heading}": "{type} SPD: {speed} HDG: {heading}", + "VESSEL": "船舶", + "POS: LIVE": "位置: ライブ", + "POS: {time}Z": "位置: {time}Z", + "awaiting first AIS position…": "最初のAIS位置を待機中…", + "awaiting usable AIS positions…": "利用可能なAIS位置を待機中…", + "awaiting first AIS message…": "最初のAISメッセージを待機中…", + "Resume": "再開", + "Pause": "一時停止", + "Error: {message}": "エラー: {message}", + "Needs {envVars} — add it in Provider Settings": "{envVars}が必要です。プロバイダー設定で追加してください", + "{label} is unavailable": "{label}は利用できません", + "This map stack": "このマップスタック", + "{label} unavailable: {hint}": "{label}は利用できません: {hint}", + "Visible map targets": "表示中のマップターゲット", + "Ready": "準備完了", + "Loaded: {scene} / {shot}": "読み込みました: {scene} / {shot}", + "Cannot capture shot: camera not ready": "ショットを取得できません: カメラの準備ができていません", + "Captured: {scene} / {shot}": "取得しました: {scene} / {shot}", + "Select a shot first": "まずショットを選択してください", + "Updated: {scene} / {shot}": "更新しました: {scene} / {shot}", + "Camera unavailable — exit cockpit first": "カメラを使用できません: 先にコックピットを終了してください", + "No shots to run": "実行するショットがありません", + "Project exported": "プロジェクトを書き出しました", + "Could not exit {mode} — scene layers may be refused": "{mode}を終了できませんでした。シーンのレイヤーが拒否される可能性があります", + "Running {index}/{total}: {scene} / {shot}": "実行中 {index}/{total}: {scene} / {shot}", + "Scene run complete": "シーンの実行が完了しました", + "Global Flights Radar": "グローバル航空レーダー", + "Orbital Watch": "軌道ウォッチ", + "Thermal Threat Board": "熱源脅威ボード", + "City Overload": "シティオーバーロード", + "Omniscience Pullback": "オムニサイエンス・プルバック", + "Shot {n}": "ショット {n}", + "Density": "密度", + "Bloom": "ブルーム", + "VISUAL PRESETS": "ビジュアルプリセット", + "LOCATION": "位置", + "CONTACTS — nearest planes · vessels · sites": "コンタクト: 最寄りの航空機 · 船舶 · 施設", + "SPACE MISSIONS — launches & orbital assets": "宇宙ミッション: 打ち上げと軌道上の資産", + "LIVE SIGNALS": "ライブシグナル", + "Contacts could not complete the requested transition; try again": "コンタクトが要求された切り替えを完了できませんでした。もう一度お試しください", + "CCTV layer unavailable": "CCTVレイヤーを利用できません", + "Link copied!": "リンクをコピーしました", + "Copy failed": "コピーに失敗しました", + "CCTV calibration saved": "CCTVキャリブレーションを保存しました", + "CCTV calibration reset": "CCTVキャリブレーションをリセットしました", + "ADJUST ON": "調整 オン", + "ADJUST": "調整", + "UNKNOWN": "不明", + "ERROR": "エラー", + "SOURCE · UNKNOWN": "ソース · 不明", + "FRAME · LOADING": "フレーム · 読込中", + "FRAME · UNAVAILABLE": "フレーム · 利用不可", + "CALIBRATED": "校正済み", + "CURATED": "調整済み", + "RAW PRIOR": "未処理の初期値", + "CCTV ON": "CCTV オン", + "CCTV OFF": "CCTV オフ", + "VIEWSHED ON": "可視域 オン", + "COVERAGE ON": "カバレッジ オン", + "COVERAGE OFF": "カバレッジ オフ", + "AUTO HOP ON": "自動切替 オン", + "AUTO HOP OFF": "自動切替 オフ", + "PROJECTION ON": "投影 オン", + "PROJECTION OFF": "投影 オフ", + "CAL · EDITED (UNSAVED)": "CAL · 編集済み (未保存)", + "CAL · {badge}": "CAL · {badge}", + "MONITOR": "モニター", + "OFF": "オフ", + "{city} · HDG {heading} · FOV {fov} · RANGE {range}m · {projection}{calBadge} · {provider}{status}": "{city} · HDG {heading} · FOV {fov} · 距離 {range}m · {projection}{calBadge} · {provider}{status}", + "{count} cameras loaded · click a camera to activate": { + "other": "カメラ {count}台を読込済み · カメラをクリックして有効化" + }, + "{count} cameras loaded · enable CCTV to activate": { + "other": "カメラ {count}台を読込済み · CCTVを有効にして使用" + }, + "Enable CCTV to load camera intersections": "CCTVを有効にすると、カメラの交差点を読み込みます", + "Enable CCTV to start camera-linked intelligence summaries.": "CCTVを有効にすると、カメラ連動のインテリジェンス概要を開始します。", + "No summary available.": "利用できる概要はありません。", + "loading frames": "フレーム読込中", + "camera grid ready": "カメラグリッド準備完了", + "Clearing selected data layers": "選択中のデータレイヤーを解除中", + "Clear selected data layers": "選択中のデータレイヤーを解除", + "CONDITIONS UNKNOWN": "気象状況不明", + "CLEAR": "快晴", + "PARTLY CLOUDY": "晴れ時々曇り", + "OVERCAST": "曇天", + "FOG": "霧", + "DRIZZLE": "霧雨", + "RAIN": "雨", + "RAIN SHOWERS": "にわか雨", + "SNOW SHOWERS": "にわか雪", + "THUNDERSTORM": "雷雨", + "MIXED CONDITIONS": "混在した状況", + "CYCLE ON": "自動切替 オン", + "CYCLE OFF": "自動切替 オフ", + "Stop automatic page cycling. Previous, Next, and the SIG/NEWS/LOCAL tabs stay available.": "ページの自動切り替えを停止します。前へ、次へ、SIG/NEWS/LOCALタブは引き続き使えます。", + "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.": "9秒ごとにブリーフィングページを自動で切り替えます (シグナル → ニュース → ローカル)。パネルにカーソルを合わせるかフォーカスしている間は一時停止します。ライブシグナルのデータは、どちらの場合も継続的に更新されます。", + "ACQUIRING REGIONAL NEWS": "地域ニュースを取得中", + "REGIONAL NEWS UNAVAILABLE": "地域ニュースを取得できません", + "RESOLVING REGION": "地域を特定中", + "REGION UNAVAILABLE": "地域を取得できません", + "NO RECENT LOCATION MATCHES": "最近の位置一致なし", + "{domain} · {age}": "{domain} · {age}", + "CLOUD {pct}%": "雲量 {pct}%", + "CLOUD UNKNOWN": "雲量不明", + "{source} · LOCATION QUERY": "{source} · 位置クエリ", + "REGIONAL NEWS": "地域ニュース", + "CONTEXT STANDBY": "コンテキスト待機", + "ENABLE GLOBAL CONTEXT FOR PROXIMITY PINGS": "グローバルコンテキストを有効にすると近接ピングを表示", + "CONTACT LOST · LAST KNOWN READOUT · NOT AN ALL-CLEAR": "コンタクト喪失 · 最終既知の値 · 安全を保証するものではありません", + "CONTACT LOST · {subject}": "コンタクト喪失 · {subject}", + "SUBJECT LEFT ITS FEED · READOUT HOLDING LAST KNOWN": "対象がフィードから外れました · 最終既知の値を保持", + "{cohort} · {contact}": "{cohort} · {contact}", + "NO AVAILABLE EXAMPLE": "該当する例なし", + "{cohort}, Unavailable": "{cohort}、利用不可", + "AHEAD": "正面", + "{side} {angle}": "{side} {angle}", + "L": "左", + "R": "右", + "{count} INPUTS UNKNOWN · NOT AN ALL-CLEAR": { + "other": "入力不明 {count}件 · 安全を保証するものではありません" + }, + "AVAILABLE INPUTS CURRENT · NOT AN ALL-CLEAR": "利用可能な入力は最新 · 安全を保証するものではありません", + "AIRCRAFT": "航空機", + "ACQUIRING SURFACE": "地表を取得中", + "SURFACE FALLBACK": "地表フォールバック", + "STALE FEED": "古いフィード", + "LIVE TRACK": "ライブ追跡", + "COMMERCIAL": "民間", + "{aircraftClass} · {feedState} · COURSE ALIGNED": "{aircraftClass} · {feedState} · 針路一致", + "ARROW · ESTIMATED DIRECTION": "矢印 · 推定方向", + "ROUTE DATA UNAVAILABLE": "経路データなし", + "DEST {bearing}": "目的地 {bearing}", + "Disable cockpit weather effects": "コックピットの天候エフェクトを無効にする", + "Enable cockpit weather effects": "コックピットの天候エフェクトを有効にする", + "ON": "オン", + "Normal": "標準", + "Night vision": "暗視", + "Thermal": "サーマル", + "Anime": "アニメ", + "Noir": "ノワール", + "Snow": "雪", + "Current cockpit vision style: {style}. Activate for next style.": "現在のコックピットビジョンスタイル: {style}。有効にすると次のスタイルへ。", + "Current style: {style} — click for next": "現在のスタイル: {style} — クリックで次へ", + "Collapse Contact panel": "コンタクトパネルを折りたたむ", + "Expand Contact panel": "コンタクトパネルを展開", + "Collapse contact panel": "コンタクトパネルを折りたたむ", + "Expand contact panel": "コンタクトパネルを展開", + "Collapse cockpit briefing panel": "コックピットブリーフィングパネルを折りたたむ", + "Expand cockpit briefing panel": "コックピットブリーフィングパネルを展開", + "Collapse briefing panel": "ブリーフィングパネルを折りたたむ", + "Expand briefing panel": "ブリーフィングパネルを展開", + "OBSERVED / MAPPED PINGS": "観測 / マップ済みピング", + "SOURCE-BACKED EVENTS · NO SYNTHETIC NEWS": "出典付きイベントのみ · 合成ニュースなし", + "LATEST LOCATION-MATCHED REPORTING": "位置に一致する最新の報道", + "LOCAL INFO": "ローカル情報", + "PLACE / CONDITIONS / POSITION": "場所 / 状況 / 位置", + "TIME UNKNOWN": "時刻不明", + "{count}M AGO": "{count}分前", + "{count}H AGO": "{count}時間前", + "{count}D AGO": "{count}日前", + "DIR UNKNOWN": "風向不明", + "Select flight {title}": "フライト {title} を選択", + "{aircraftClass} · CURRENT": "{aircraftClass} · 現在", + "MILITARY FLIGHT": "軍用機", + "COMMERCIAL FLIGHT": "民間機", + "{aircraftClass} · {distance}": "{aircraftClass} · {distance}", + "DISTANCE UNKNOWN": "距離不明", + "{count} INPUTS UNKNOWN": { + "other": "入力不明 {count}件" + }, + "SOURCE STATUS UNAVAILABLE": "ソース状態を取得できません", + "Restore real aircraft": "実際の航空機に戻す", + "Reclassify as TR-3B": "TR-3Bに再分類", + "TRACK ACQUIRED": "追跡開始", + "{label} · COURSE {heading}°": "{label} · 針路 {heading}°", + "Context could not restore every layer; try again": "コンテキストがすべてのレイヤーを復元できませんでした。もう一度お試しください", + "No selected data layers": "選択中のデータレイヤーはありません", + "{count} data layers could not be cleared": { + "other": "データレイヤー{count}件を解除できませんでした" + }, + "Cleared {count} data layers": { + "other": "データレイヤーを{count}件解除しました" + }, + "Selected data layers could not be cleared": "選択中のデータレイヤーを解除できませんでした", + "Space Missions could not complete the requested transition; try again": "宇宙ミッションが要求された切り替えを完了できませんでした。もう一度お試しください", + "Nearby installations refreshed": "周辺施設を更新しました", + "Nearby installations could not be refreshed; try again": "周辺施設を更新できませんでした。もう一度お試しください", + "Space Missions cancellation could not restore the previous layer state": "宇宙ミッションのキャンセル時に、以前のレイヤー状態を復元できませんでした", + "That layer is unavailable in the current Context mode": "そのレイヤーは現在のコンテキストモードでは利用できません", + "{layerId} could not {action} cleanly": "{layerId}を正常に{action}できませんでした", + "start": "開始", + "stop": "停止", + "{mode} could not start because another layer did not stop cleanly": "別のレイヤーが正常に停止しなかったため、{mode}を開始できませんでした", + "Space Missions": "宇宙ミッション", + "Context": "コンテキスト", + "Live Flights": "ライブフライト", + "Military Flights": "軍用機", + "Earthquakes (24h)": "地震 (24時間)", + "Satellites": "衛星", + "Space Missions (30d)": "宇宙ミッション (30日)", + "Street Traffic": "道路交通", + "CCTV": "CCTV", + "Radio": "ラジオ", + "Bikeshare": "バイクシェア", + "Live AIS Vessels": "ライブAIS船舶", + "Mapped Installations": "マップ済み施設", + "Global Context": "グローバルコンテキスト", + "Datacenters": "データセンター", + "Dams": "ダム", + "Submarine Cables": "海底ケーブル", + "FIRMS Active Fires": "FIRMS 火災検知", + "ENABLING": "有効化中", + "DISABLING": "無効化中", + "{state} · {source}": "{state} · {source}", + "UNCERTAIN · {source} · lifecycle state requires reconciliation": "不明確 · {source} · ライフサイクル状態の調整が必要です", + "{state} · {source} · {detail} · retry {seconds}s": "{state} · {source} · {detail} · {seconds}秒後に再試行", + "{state} · {source} · {detail}": "{state} · {source} · {detail}", + "never": "未取得", + "{source} · {loadingLabel}": "{source} · {loadingLabel}", + "{accepted} of {raw} records accepted": "{raw}件中{accepted}件のレコードを採用", + "incomplete snapshot": "不完全なスナップショット", + "{state} · {source} · {detail} · {ago}": "{state} · {source} · {detail} · {ago}", + "{state} · {source} · {ago} · retrying in {seconds}s": "{state} · {source} · {ago} · {seconds}秒後に再試行", + "{state} · {source} · {ago}": "{state} · {source} · {ago}", + "{source} · {ago}": "{source} · {ago}", + "UNCERTAIN": "不明確", + "{name}: {state}": "{name}: {state}", + "{count}s ago": "{count}秒前", + "CONNECTING": "接続中", + "📍 Location: --": "📍 位置: --", + "Landmark: --": "ランドマーク: --", + "Searched location": "検索した場所", + "ORBIT": "周回", + "Location not found": "場所が見つかりません", + "Search failed": "検索に失敗しました", + "Fly to a POI first": "先にPOIへ移動してください", + "Reset to full globe view": "地球全体ビューに戻す", + "Reset cockpit to full globe view": "コックピットを地球全体ビューに戻す", + "Resetting to full globe view": "地球全体ビューに戻しています", + "Resetting cockpit to full globe view": "コックピットを地球全体ビューに戻しています", + "MAP": "マップ", + "panel": "パネル", + "Expand {name}": "{name}を展開", + "Collapse {name}": "{name}を折りたたむ", + "Expand Radio": "ラジオを展開", + "Collapse Radio": "ラジオを折りたたむ", + "Expand Radio section": "ラジオセクションを展開", + "Collapse Radio section": "ラジオセクションを折りたたむ", + "Panel layout updated — positions reset to new defaults": "パネルレイアウトを更新しました。位置を新しい初期値にリセットしました", + "Collapse Cockpit display options": "コックピットのディスプレイ設定を折りたたむ", + "Expand Cockpit display options": "コックピットのディスプレイ設定を展開", + "Collapse Cockpit Radio controls": "コックピットのラジオ操作を折りたたむ", + "Expand Cockpit Radio controls": "コックピットのラジオ操作を展開", + "NO STATIONS": "局なし", + "NO STATION AVAILABLE": "利用できる局がありません", + "{name}, station {index} of {total}": "{name}、{total}局中{index}局目", + "No station available": "利用できる局がありません", + "OFF AIR": "放送休止", + "STATION UNAVAILABLE": "局を利用できません", + "Radio could not {action} cleanly": "ラジオを正常に{action}できませんでした", + "Close compact Radio controls": "コンパクトラジオ操作を閉じる", + "Open compact Radio controls": "コンパクトラジオ操作を開く", + "SYNC": "同期", + "RECONCILE": "再調整", + "DISABLE": "無効化", + "ENABLE": "有効化", + "Reconcile Radio — lifecycle uncertain": "ラジオを再調整: ライフサイクルが不明確", + "Disable Radio": "ラジオを無効にする", + "Enable Radio": "ラジオを有効にする", + "DIRECTORY BAND": "ディレクトリバンド", + "{category} BAND": "{category}バンド", + "NO STATION SELECTED": "局が未選択", + "Directory metadata only": "ディレクトリのメタデータのみ", + "Loading station directory…": "局ディレクトリを読み込み中…", + "Choose a globe marker or use next.": "地球儀のマーカーを選ぶか、次へを使用してください。", + "TAGS · {tags}": "タグ · {tags}", + "Play": "再生", + "PLAY": "再生", + "selected": "選択中の", + "nearest": "最寄りの", + "{action} {target} radio station": "{target}ラジオ局を{action}", + "RADIO STATE UNCERTAIN": "ラジオ状態不明", + "SYNCING DIRECTORY": "ディレクトリ同期中", + "RADIO READY": "ラジオ準備完了", + "SYNCING": "同期中", + "READY": "準備完了", + "station": "局", + " · stale/degraded directory": " · ディレクトリが古い/性能低下", + " · degraded directory": " · ディレクトリ性能低下", + " · stale directory": " · ディレクトリが古い", + " · outside current filter": " · 現在の絞り込み対象外", + "Ready — playback starts only from your action": "準備完了: 再生は操作したときのみ開始されます", + "Radio off": "ラジオ オフ", + "Connecting directly to broadcaster…": "放送局に直接接続中…", + "Buffering broadcaster stream…": "放送局のストリームをバッファリング中…", + "Playing {station}": "{station}を再生中", + "Paused {station}": "{station}を一時停止中", + "Broadcaster stream unavailable": "放送局のストリームを利用できません", + " · muted during voice interaction": " · 音声操作中はミュート", + " · restoring volume after voice": " · 音声操作後に音量を復元中", + " · static indicates no broadcaster audio": " · ノイズは放送局の音声がないことを示します", + " · tuning static until broadcaster starts": " · 放送局の開始までノイズで選局中", + "Station unavailable after directory refresh — choose another channel": "ディレクトリ更新後に局を利用できません。別のチャンネルを選んでください", + "Radio is enabling…": "ラジオを有効化しています…", + "Radio is disabling…": "ラジオを無効化しています…", + "Radio lifecycle is uncertain — use Enable or Disable to reconcile": "ラジオのライフサイクルが不明確です。有効化または無効化で再調整してください", + "Scene action failed": "シーン操作に失敗しました", + "Delete shot \"{shot}\"?": "ショット「{shot}」を削除しますか?", + "SPARSE": "低密度", + "BALANCED": "標準", + "DEL": "削除", + "entity": "エンティティ", + "Shared {subject} follow expired": "共有された{subject}の追従が期限切れになりました", + "Shared {subject} could not be restored — feed unavailable": "共有された{subject}を復元できませんでした: フィードを利用できません", + "Shared {subject} is unavailable": "共有された{subject}は利用できません", + "ACQUIRING": "取得中", + "SHARED {subject}": "共有 {subject}", + "LOADING LIVE DATA": "ライブデータ読込中", + "LOAD COMPLETE": "読込完了", + "LOAD CANCELLED": "読込中止", + "LOAD FAILED": "読込失敗", + "LIVE DATA OFF": "ライブデータ オフ", + "MAPPED SITES LOADED": "マップ済み施設を読込済み", + "RETRYING MAPPED SITES": "マップ済み施設を再試行中", + "FETCHING MAPPED SITES": "マップ済み施設を取得中", + "TURNING OFF LIVE DATA": "ライブデータをオフにしています", + "REFRESHING LIVE DATA": "ライブデータを更新中", + "syncing road network": "道路網を同期中", + "retry pending": "再試行待ち", + "retrying in {seconds}s": "{seconds}秒後に再試行", + "Celestial ring — reveal the full globe": "天球リング: 地球全体を表示", + "Celestial ring — available in Normal style": "天球リング: 標準スタイルで利用可能", + "Detection overlay: {mode}": "検出オーバーレイ: {mode}", + "Detection overlay: off": "検出オーバーレイ: オフ", + "DETECT": "検出", + "AI AGENT": "AIエージェント", + "Voice model tier — applies next session": "音声モデルのティア: 次回セッションで適用", + "Estimated session cost": "セッションの推定コスト", + "Voice control — activate to toggle voice; hold Space to speak": "音声コントロール: 有効にすると音声をオン/オフ、Space を押し続けて話す", + "VOICE STANDBY": "音声待機中", + "VOICE CONTROL": "音声コントロール", + "Hold Space to speak · tap Space to activate focused controls": "Space を押し続けて話す · Space をタップでフォーカス中のコントロールを実行", + "VOICE SYSTEM ERROR": "音声システムエラー", + "DISMISS": "閉じる", + "Check microphone permission and network access, then try again.": "マイクの許可とネットワーク接続を確認して、もう一度お試しください。", + "Release Space to send": "Space を離して送信", + "Hold Space to talk": "Space を押し続けて話す", + "Requesting microphone": "マイクを要求中", + "Ask or command": "質問またはコマンドをどうぞ", + "Running command": "コマンド実行中", + "Voice off": "音声オフ", + "WebRTC microphone support unavailable": "WebRTC マイクに対応していません", + "VOICE UNAVAILABLE": "音声利用不可", + "VOICE ACTIVE": "音声オン", + "Voice session could not be started.": "音声セッションを開始できませんでした。", + "Next session: {pendingId} — this session stays on {modelId}": "次回セッション: {pendingId}。このセッションは{modelId}のままです", + "Voice model: {pendingId} — click to switch to {target}; applies next session": "音声モデル: {pendingId}。クリックで{target}に切り替え、次回セッションで適用", + "Estimated session cost on {modelId} — {responses} response(s). Warns at {warn}, ends the session at {cap}.": "{modelId}でのセッション推定コスト。応答 {responses}件。{warn}で警告し、{cap}でセッションを終了します。", + "{tier} applies next session": "{tier}は次回セッションで適用", + "Session ended — cost cap {cost}": "セッション終了: コスト上限 {cost}", + "Radio did not start": "ラジオを開始できませんでした", + "Aircraft cockpit view": "航空機コックピットビュー", + "LEVEL": "レベル", + "Estimated destination direction": "推定目的地の方向", + "DEST ---°": "目的地 ---°", + "OPTICAL PLANE · 01": "光学面 · 01", + "VISOR LOCK · ACTIVE": "バイザーロック · 有効", + "GROUND SPEED · KTS": "対地速度 · KTS", + "ALTITUDE · FT": "高度 · FT", + "FIRST PERSON": "一人称視点", + "LIVE TRACK · COURSE ALIGNED": "ライブ追跡 · 針路一致", + "Cockpit vision style": "コックピットのビジョンスタイル", + "Previous cockpit vision style": "前のコックピットビジョンスタイル", + "Previous vision style": "前のビジョンスタイル", + "Current cockpit vision style: NORMAL. Activate for next style.": "現在のコックピットビジョンスタイル: 標準。有効にすると次のスタイルへ。", + "Current style: NORMAL — click for next": "現在のスタイル: 標準 — クリックで次へ", + "CURRENT": "現在", + "Next cockpit vision style": "次のコックピットビジョンスタイル", + "Next vision style": "次のビジョンスタイル", + "Current aircraft heading": "現在の機首方位", + "GROUND SPEED": "対地速度", + "ALTITUDE": "高度", + "Contact cockpit summary": "コンタクトのコックピット概要", + "CONTACT": "コンタクト", + "CONTACTS · 250 KM": "コンタクト · 250 KM", + "Contact navigation": "コンタクトナビゲーション", + "CONTEXT ONLY": "参考情報のみ", + "Nearby cohort counts": "周辺の種別ごとの件数", + "NEAREST OBSERVED / MAPPED": "最寄りの観測 / マップ済み", + "AVAILABLE INPUTS ONLY · NOT AN ALL-CLEAR": "利用可能な入力のみ · 安全を保証するものではありません", + "Cockpit briefing carousel": "コックピットブリーフィングカルーセル", + "Estimated flight plan": "推定フライトプラン", + "ESTIMATED FLIGHT PLAN": "推定フライトプラン", + "FROM": "出発", + "TO": "到着", + "Cockpit briefing controls": "コックピットブリーフィングの操作", + "Previous briefing page": "前のブリーフィングページ", + "Next briefing page": "次のブリーフィングページ", + "Live signals": "ライブシグナル", + "Latest regional news": "最新の地域ニュース", + "Location-based information": "位置に基づく情報", + "TEMP": "気温", + "WIND": "風", + "SKY": "空", + "PRECIP": "降水", + "Show Live Signals": "ライブシグナルを表示", + "NEWS": "ニュース", + "Show Regional News": "地域ニュースを表示", + "Show Local Info": "ローカル情報を表示", + "Cockpit display and Radio controls": "コックピットのディスプレイとラジオの操作", + "DISPLAY": "ディスプレイ", + "Cockpit display options": "コックピットのディスプレイ設定", + "RADIO": "ラジオ", + "Cockpit compact Radio controls": "コックピットのコンパクトラジオ操作", + "Previous filtered radio station": "絞り込み中の前のラジオ局", + "Play selected radio station": "選択したラジオ局を再生", + "Next filtered radio station": "絞り込み中の次のラジオ局", + "VOLUME": "音量", + "Cockpit Radio volume": "コックピットラジオの音量", + "View switcher": "ビュー切替", + "Exit cockpit and return to full globe view": "コックピットを終了して地球全体ビューに戻る", + "RESET": "リセット", + "Exit cockpit view": "コックピットビューを終了", + "EXIT COCKPIT": "コックピット終了", + "Navigation, voice, and visual preset controls": "ナビゲーション、音声、ビジュアルプリセットの操作", + "Expand Visual Presets": "ビジュアルプリセットを展開", + "Pin visual presets": "ビジュアルプリセットを固定", + "Keep visual presets open": "ビジュアルプリセットを開いたままにする", + "Show the globe without a visual filter.": "ビジュアルフィルターなしで地球儀を表示します。", + "Emulate a green phosphor CRT with scanlines and screen curvature.": "走査線と画面の湾曲を備えた、緑色蛍光体のCRTを再現します。", + "Simulate night-vision goggles with green intensification and a tube vignette.": "緑色の光増幅とチューブ周辺の減光で、暗視ゴーグルを再現します。", + "Simulate FLIR-style thermal contrast. Turn up Ironbow for color.": "FLIR風の熱コントラストを再現します。色を付けるには Ironbow を上げてください。", + "Apply bright cel-shaded color and illustrated outlines.": "明るいセルシェーディングの色と輪郭線を適用します。", + "Apply high-contrast monochrome film-noir grading.": "コントラストの強いモノクロのフィルムノワール調に仕上げます。", + "Add a cold, snowy whiteout treatment to the scene.": "冷たい雪のホワイトアウト効果をシーンに加えます。", + "MAP SOURCE": "マップソース", + "Map source": "マップソース", + "Style": "スタイル", + "Expand LOCATION": "位置を展開", + "Collapse panel": "パネルを折りたたむ", + "Pin location tray": "位置トレイを固定", + "Keep location tray open": "位置トレイを開いたままにする", + "Search any location": "場所を検索", + "Search location by name or coordinates": "名前または座標で場所を検索", + "Search any location...": "場所を検索...", + "WEATHER": "気象", + "CONTEXT": "コンテキスト", + "Compact Radio controls": "コンパクトラジオ操作", + "Open detailed Radio controls": "詳細ラジオ操作を開く", + "Previous station": "前の局", + "Next station": "次の局", + "Compact Radio volume": "コンパクトラジオの音量", + "Expand panel": "パネルを展開", + "Context mode": "コンテキストモード", + "CONTACTS": "コンタクト", + "Cycles the nearest contacts of whatever type you select — planes, vessels, installations. Satellites track independently.": "選択した種類 (航空機、船舶、施設) の最寄りのコンタクトを順に切り替えます。衛星は独立して追跡されます。", + "SPACE MISSIONS": "宇宙ミッション", + "SELECT CONTEXT": "コンテキストを選択", + "Contact Context actions": "コンタクトコンテキストの操作", + "COCKPIT": "コックピット", + "SEARCH NEARBY SITES": "周辺施設を検索", + "Reclassify tracked contact as TR-3B": "追跡中のコンタクトをTR-3Bに再分類", + "CONTACTS CONTEXT OFF": "コンタクトコンテキスト オフ", + "SELECT CONTACTS TO LOAD OBSERVED / MAPPED PROXIMITY": "コンタクトを選択して、観測 / マップ済みの近接情報を読み込み", + "Available Space Missions": "利用可能な宇宙ミッション", + "AVAILABLE MISSIONS": "利用可能なミッション", + "SELECT A MISSION TO INSPECT": "ミッションを選択して詳細を表示", + "LOADING 30-DAY MISSION INDEX": "30日間のミッション一覧を読込中", + "TAB PREVIEWS · ENTER / SPACE SELECTS": "TABでプレビュー · ENTER / SPACEで選択", + "Internet radio and local SDR": "インターネットラジオとローカルSDR", + "STATION TAG": "局タグ", + "Filter stations by station tag": "局タグで局を絞り込み", + "All": "すべて", + "Enable Radio, then choose a globe marker or use next.": "ラジオを有効にして、地球儀のマーカーを選ぶか、次へを使用してください。", + "DRAG TO TUNE": "ドラッグで選局", + "ALL · DRAG THE NEEDLE": "すべて · 針をドラッグ", + "SNAPS TO AVAILABLE STATIONS": "利用可能な局にスナップ", + "Radio playback": "ラジオ再生", + "Previous filtered station": "絞り込み中の前の局", + "Play selected station": "選択した局を再生", + "Next filtered station": "絞り込み中の次の局", + "STOP": "停止", + "Stop radio playback": "ラジオ再生を停止", + "Radio volume": "ラジオの音量", + "STATION SITE": "放送局サイト", + "Audio connects directly to the broadcaster after you press play. Your IP is visible to that broadcaster.": "再生ボタンを押すと、音声は放送局に直接接続されます。IPアドレスは放送局に表示されます。", + "Intelligence HUD (H)": "インテリジェンスHUD (H)", + "Layout": "レイアウト", + "HUD layout": "HUDレイアウト", + "Tactical": "タクティカル", + "Operator": "オペレーター", + "Minimal": "ミニマル", + "Detection Overlay (D)": "検出オーバーレイ (D)", + "Detection overlay": "検出オーバーレイ", + "Detection label density": "検出ラベルの密度", + "Allocation": "配分", + "Detection label allocation": "検出ラベルの配分", + "Elastic": "エラスティック", + "Weighted": "加重", + "Fade": "フェード", + "Detection fade distance": "検出のフェード距離", + "World-overlay fade distance outside the keyhole as a percentage of its radius": "キーホール外のワールドオーバーレイのフェード距離 (キーホール半径に対する割合)", + "Outside": "外側", + "Detection opacity outside the keyhole": "キーホール外の検出の不透明度", + "World-overlay label and card opacity beyond the fade distance": "フェード距離を超えた範囲のワールドオーバーレイのラベルとカードの不透明度", + "PARAMETERS": "パラメーター", + "3D aircraft — flat icons zoomed out, 3D models up close": "3D航空機: 遠景はフラットアイコン、近景は3Dモデル", + "Models": "モデル", + "3D model coverage": "3Dモデルの適用範囲", + "Proximity": "近接", + "Scope — the circular viewport mask": "スコープ: 円形のビューポートマスク", + "Scope": "スコープ", + "Feather": "ぼかし", + "Scope edge feather": "スコープ縁のぼかし", + "Scope edge feather as a percentage of the keyhole radius": "スコープ縁のぼかし (キーホール半径に対する割合)", + "Celestial": "天球", + "Hide UI chrome": "UIを非表示", + "Clean UI": "クリーンUI", + "Bloom / Glow": "ブルーム / グロー", + "Bloom intensity": "ブルームの強度", + "Sharpening": "シャープ化", + "Sharpen": "シャープ", + "Sharpen intensity": "シャープの強度", + "EXIT CLEAN VIEW": "クリーンビュー終了", + "Return UI controls": "UIコントロールを戻す", + "Initializing photorealistic world...": "フォトリアルな世界を初期化中...", + "DATA LAYERS": "データレイヤー", + "NEAREST": "最寄り", + "CCTV camera": "CCTVカメラ", + "CALIBRATION": "キャリブレーション", + "Drag the camera in the world: rings rotate, arrows move, handles set range/FOV": "ワールド上でカメラをドラッグ: リングで回転、矢印で移動、ハンドルで距離/FOVを設定", + "Camera pose — click a value to type": "カメラの姿勢: 値をクリックして入力", + "Heading (compass °) — click to type": "方位 (コンパス °): クリックして入力", + "Pitch (° up/down) — click to type": "ピッチ (上下 °): クリックして入力", + "Horizontal FOV (°) — click to type": "水平FOV (°): クリックして入力", + "Range / monitor-plane distance (m) — click to type": "距離 / モニター面までの距離 (m): クリックして入力", + "Mount height above ground (m) — click to type": "地上からの設置高 (m): クリックして入力", + "North offset from catalog position (m) — click to type": "カタログ位置からの北方向オフセット (m): クリックして入力", + "East offset from catalog position (m) — click to type": "カタログ位置からの東方向オフセット (m): クリックして入力", + "SAVE CAL": "CAL保存", + "RESET CAL": "CALリセット", + "SCENE SUMMARY": "シーン概要", + "SCENES": "シーン", + "Scene recipe": "シーンレシピ", + "NEW": "新規", + "CAPTURE SHOT": "ショット取得", + "UPDATE SHOT": "ショット更新", + "START": "開始", + "EXPORT PRESETS": "プリセット書出", + "IMPORT": "読込", + "RUN LOG": "実行ログ", + "POWER UP": "POWER UP", + "GROUND STATION · PROVIDER SETTINGS": "地上局 · プロバイダー設定", + "Close key setup": "キー設定を閉じる", + "Power up the globe": "地球儀に電源を入れる", + "The globe already flies keyless. Every key below switches on another real feed — paste one and it's saved into this app's local configuration, then the server restarts itself. Server-side keys stay on this machine; Google Maps and Cesium ion run in the browser and must be provider-restricted. Keys you configured elsewhere are shown but never touched.": "地球儀はキーなしでも飛行できます。下記の各キーは、それぞれ別の実データフィードを有効にします。キーを貼り付けるとこのアプリのローカル設定に保存され、サーバーが自動で再起動します。サーバー側のキーはこのマシンから出ません。Google Maps と Cesium ion はブラウザで動作するため、プロバイダー側で利用制限を設定してください。他の場所で設定済みのキーは表示のみで、変更されません。", + "SAVE KEYS": "キーを保存", + "ESC to close": "ESCで閉じる", + "The Google Maps key buys the photorealistic planet — everything else stacks on top.": "Google Maps のキーでフォトリアルな地球が使えるようになり、他のすべてはその上に重なります。", + "NO PLACE LEFT BEHIND": "誰も取り残さない", + "ACTIVE STYLE": "現在のスタイル", + "Globe actions": "地球儀の操作", + "Turn off all selected data layers": "選択中のデータレイヤーをすべてオフにする", + "Copy share link": "共有リンクをコピー", + "Reset camera and return to full globe view": "カメラをリセットして地球全体ビューに戻す", + "MISSION CONTROL · FIRST LAUNCH": "ミッションコントロール · 初回起動", + "Choose your first view": "最初のビューを選択", + "LIVE CONTACTS": "ライブコンタクト", + "Aircraft, vessels and nearby intelligence": "航空機、船舶、周辺のインテリジェンス", + "Launches, spacecraft and orbital context": "打ち上げ、宇宙機、軌道の状況", + "EXPLORE MANUALLY": "手動で探索", + "Begin with a clean globe": "まっさらな地球儀から始める", + "Don't show this again": "今後表示しない", + "ESC to dismiss": "ESCで閉じる", + "Tip: the GEV MIC button in the dock lets you talk to the map.": "ヒント: ドックの GEV MIC ボタンで、マップに話しかけられます。" +} From e2acee4b0a29d4d273b16343117b055a6dbe3754 Mon Sep 17 00:00:00 2001 From: Meir Michanie Date: Wed, 28 Oct 2026 12:37:13 +0400 Subject: [PATCH 03/83] i18n(uk): Ukrainian strings from #312 The Ukrainian locale by meirm (#312), converted from its namespaced JS catalogs to the English-keyed uk.json: 832 entries whose English still matches the current UI. --- src/i18n/locales/uk.json | 869 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 869 insertions(+) create mode 100644 src/i18n/locales/uk.json diff --git a/src/i18n/locales/uk.json b/src/i18n/locales/uk.json new file mode 100644 index 000000000..09fdc59e3 --- /dev/null +++ b/src/i18n/locales/uk.json @@ -0,0 +1,869 @@ +{ + "Flying to Austin, TX...": "Переліт до Austin, TX...", + "Restoring shared view...": "Відновлення спільного вигляду...", + "Configuring viewer...": "Налаштування переглядача...", + "Loading Google 3D Tiles...": "Завантаження Google 3D Tiles...", + "Loading the keyless globe...": "Завантаження глобуса без ключа...", + "Google 3D Tiles unavailable ({detail}). Loading the keyless globe...": "Google 3D Tiles недоступні ({detail}). Завантаження глобуса без ключа...", + "Initializing systems...": "Ініціалізація систем...", + "Close data attribution": "Закрити відомості про джерела даних", + "UNAVAILABLE": "НЕДОСТУПНО", + "SOURCE": "ДЖЕРЕЛО", + "Overpass rate-limited": "Overpass обмежує частоту запитів", + "Overpass timed out": "Перевищено час очікування Overpass", + "Overpass could not complete the query": "Overpass не зміг завершити запит", + "Overpass temporarily unavailable": "Overpass тимчасово недоступний", + "Retrying mapped sites…": "Повторне завантаження нанесених об’єктів…", + "Fetching mapped sites…": "Завантаження нанесених об’єктів…", + "{reason} — retrying in {seconds}s": "{reason} — повтор через {seconds} с", + "{reason} — retry pending": "{reason} — очікується повтор", + "Zoom in to search mapped installations": "Наблизьте карту, щоб шукати нанесені об’єкти", + "Showing cached mapped sites": "Показано кешовані нанесені об’єкти", + "Mapped sites not loaded": "Нанесені об’єкти не завантажено", + "Mapped sites loaded": "Нанесені об’єкти завантажено", + "feed unavailable": "канал даних недоступний", + "feed stale": "канал даних застарів", + "observed or mapped nearby context": "спостережений або нанесений контекст поблизу", + "no observed or mapped objects in current feeds": "немає спостережених або нанесених об’єктів у поточних каналах даних", + "STATION": "СТАНЦІЇ", + "Crewed stations and their visiting vehicles": "Пілотовані станції та кораблі відвідування", + "NAV": "НАВ", + "GNSS navigation — GPS, GLONASS, Galileo": "Навігація GNSS — GPS, GLONASS, Galileo", + "GEO": "ГЕО", + "Geostationary belt — comms and weather, fixed over the equator": "Геостаціонарний пояс — зв’язок і погода, нерухомо над екватором", + "VISUAL": "ВИДИМІ", + "Brightest naked-eye objects — CelesTrak visual group": "Найяскравіші об’єкти для неозброєного ока — група visual CelesTrak", + "COMMS": "ЗВ’ЯЗОК", + "Broadband constellation shell — shown only in DENSE mode": "Оболонка широкосмугового угруповання — лише в режимі ЩІЛЬНО", + "FISHING": "РИБАЛЬСЬКЕ", + "TOWING": "БУКСИРУВАННЯ", + "DREDGER": "ДНОПОГЛИБ.", + "DIVE OPS": "ВОДОЛАЗНІ РОБОТИ", + "MILITARY": "ВІЙСЬКОВЕ", + "SAILING": "ВІТРИЛЬНЕ", + "PLEASURE": "ПРОГУЛКОВЕ", + "PILOT": "ЛОЦМАН", + "SAR": "SAR", + "TUG": "БУКСИР", + "PORT TENDER": "ПОРТОВИЙ КАТЕР", + "ANTI-POLLUTION": "АНТИЗАБРУДНЕННЯ", + "LAW ENFORCE": "ПРАВООХОРОНА", + "MEDICAL": "МЕДИЧНЕ", + "HIGH-SPEED": "ШВИДКІСНЕ", + "PASSENGER": "ПАСАЖИРСЬКЕ", + "CARGO": "ВАНТАЖНЕ", + "TANKER": "ТАНКЕР", + "OTHER": "ІНШЕ", + "ENVIRONMENTAL": "ДОВКІЛЛЯ", + "EARTH WATCH": "НАГЛЯД ЗА ЗЕМЛЕЮ", + "ACTIVE EVENTS": "АКТИВНІ ПОДІЇ", + "Starting live contacts…": "Запуск контактів у реальному часі…", + "Opening space missions…": "Відкриття космічних місій…", + "Scanning active events…": "Сканування активних подій…", + "Live earthquakes and active fires, from USGS and NASA": "Землетруси в реальному часі й активні пожежі від USGS та NASA", + "It feels like a forbidden cockpit—then you realize the sources are public and the data is real.": "Немов заборонена кабіна — а потім ви усвідомлюєте: джерела публічні, а дані — справжні.", + "Working…": "Працюємо…", + "Could not open that mission{detail}. Retry or explore manually.": "Не вдалося відкрити цю місію{detail}. Повторіть спробу або дослідіть вручну.", + "This browser is blocking storage, so that could not be saved.": "Цей браузер блокує сховище, тож зберегти не вдалося.", + "CRT": "CRT", + "NVG": "NVG", + "FLIR": "FLIR", + "SNOW": "СНІГ", + "LOADING": "ЗАВАНТАЖЕННЯ", + "DEGRADED": "ДЕГРАД.", + "STALE": "ЗАСТАРІЛО", + "FALLBACK": "РЕЗЕРВ", + "SUMMARY": "ЗВЕДЕННЯ", + "Awaiting telemetry...": "Очікування телеметрії...", + "REC": "REC", + "AIS: --": "AIS: --", + "POWER UP · {count} KEYS WAITING": { + "one": "ЗАПУСК · {count} ключ у черзі", + "few": "ЗАПУСК · {count} ключі в черзі", + "many": "ЗАПУСК · {count} ключів у черзі", + "other": "ЗАПУСК · {count} ключа в черзі" + }, + "POWERED UP": "ЗАПУЩЕНО", + "Save failed ({status}).": "Не вдалося зберегти ({status}).", + "REMOVE": "ВИДАЛИТИ", + "Remove {title} from this app's saved keys": "Видалити {title} із збережених ключів застосунку", + "your app configuration": "вашої конфігурації застосунку", + "your local .env": "вашого локального .env", + "Saving…": "Збереження…", + "Save failed: {detail}": "Не вдалося зберегти: {detail}", + "Paste at least one key first.": "Спочатку вставте принаймні один ключ.", + "Saved to {store}. Restarting — this page reloads itself.": "Збережено до {store}. Перезапуск — сторінка перезавантажиться сама.", + "Remove this key from your saved configuration?": "Видалити цей ключ із вашої збереженої конфігурації?", + "Removed from {store}. Restarting — this page reloads itself.": "Видалено з {store}. Перезапуск — сторінка перезавантажиться сама.", + "Places context + Street View fallback; optional separate key": "Контекст Places + резервний Street View; окремий ключ за бажанням", + "Live ships, worldwide": "Судна в реальному часі по всьому світу", + "Live active-fire detections": "Виявлення активних пожеж у реальному часі", + "Real live traffic (keyless runs a simulation)": "Справжній трафік у реальному часі (без ключа — симуляція)", + "Bing imagery map stacks + world terrain": "Стеки карт Bing imagery + світовий рельєф", + "More flight-polling credits (anonymous works without)": "Більше кредитів опитування польотів (працює й анонімно)", + "CONTEXT READY": "КОНТЕКСТ ГОТОВИЙ", + "GLOBAL CONTEXT OFF": "ГЛОБАЛЬНИЙ КОНТЕКСТ ВИМК.", + "SELECT A FLIGHT, VESSEL, OR MAPPED INSTALLATION": "ВИБЕРІТЬ ЛІТАК, СУДНО ЧИ НАНЕСЕНИЙ ОБ’ЄКТ", + "ENABLE TO LOAD OBSERVED / MAPPED PROXIMITY": "УВІМКНІТЬ ДЛЯ ЗАВАНТАЖЕННЯ СПОСТЕРЕЖЕНОЇ / НАНЕСЕНОЇ ОКРУГИ", + "Unavailable": "Недоступно", + "Focus {label}": "Фокус: {label}", + "Global Context navigation": "Навігація глобального контексту", + "Previous — prior visited contact in the 250 km window": "Попередня — вже відвідана ціль у вікні 250 км", + "PREVIOUS": "ПОПЕРЕДНЯ", + "FOCUS": "ФОКУС", + "Next — nearest unvisited contact in the 250 km window": "Наступна — найближча невідвідана ціль у вікні 250 км", + "NEXT": "ДАЛІ", + "Open-source mapped/observed context. Missing broadcasts, unloaded map areas, or unmapped sites are not evidence of absence.": "Контекст із відкритих джерел (нанесений/спостережений). Відсутність трансляцій, незавантажені ділянки карти або ненанесені об’єкти не є доказом відсутності.", + "HDG {value}°": "HDG {value}°", + "BRG {value}°": "BRG {value}°", + "BRG —": "BRG —", + "CRS {value}°": "CRS {value}°", + "CURRENT VIEWPORT ONLY": "ЛИШЕ ПОТОЧНА ОБЛАСТЬ ОГЛЯДУ", + "Flights": "Літаки", + "Military flights": "Військова авіація", + "AIS vessels": "Судна AIS", + "Mapped installations": "Нанесені об’єкти", + "syncing {count} city feeds...": "синхронізація каналів даних {count} міст...", + "scanning nearby systems...": "пошук ближніх систем...", + "Station {id}": "Станція {id}", + "Station": "Станція", + "🚲 {bikes} avail · {docks} docks · {capacity} cap": "🚲 {bikes} вільно · {docks} доків · {capacity} містк.", + "⚠️ Not installed": "⚠️ Не встановлено", + "⚠️ Not renting": "⚠️ Не видає", + "⚠️ Not returning": "⚠️ Не приймає", + "{count} CAMERAS STANDING BY · NO CAMERA SELECTED · CLICK A CAMERA TO ACTIVATE": "{count} КАМЕР ОЧІКУЄ · КАМЕРУ НЕ ВИБРАНО · КЛАЦНІТЬ КАМЕРУ ДЛЯ АКТИВАЦІЇ", + "No cameras available in catalog.": "У каталозі немає доступних камер.", + "{city} CCTV": "CCTV: {city}", + "FOV {value}°": "FOV {value}°", + "COVERAGE {value}km²": "ЗОНА ОГЛЯДУ {value}km²", + "OVERLAP {count} cams": "ПЕРЕКРИТТЯ {count} КАМ.", + "ISOLATED VIEW": "ОКРЕМИЙ ВИГЛЯД", + "PROJ MONITOR": "ПРОЄКЦ. МОНІТОР", + "PROJ OFF": "ПРОЄКЦ. ВИМК.", + "VIEWSHED": "ЗОНА ВИДИМОСТІ", + "CAL {value}": "КАЛ. {value}", + "SRC {value}": "ДЖЕР. {value}", + "{value} CONTEXT": "{value} КОНТЕКСТ", + "Focus fire detection {title}, {details}": "Фокус на виявленні пожежі {title}, {details}", + "{value} conf": "{value} впевн.", + "{value} ago": "{value} тому", + "sensor n/a": "датчик н/д", + "FIRE · {frp} MW": "ПОЖЕЖА · {frp} MW", + "NIGHT": "НІЧ", + "▲ {frp} MW": "▲ {frp} MW", + "FIRE": "ПОЖЕЖА", + "FIRES": "ПОЖЕЖІ", + "max {value} MW": "макс {value} MW", + "new {value}": "нова {value}", + "just now": "щойно", + "<1m ago": "<1 хв тому", + "{count}m ago": "{count} хв тому", + "{count}h ago": "{count} год тому", + "STALE · cached {age}": "ЗАСТАРІЛО · кешовано {age}", + "refreshing...": "оновлення...", + "loading...": "завантаження...", + "KEY REQUIRED": "ПОТРІБЕН КЛЮЧ", + "LIVE · updated {age}": "У РЕАЛЬНОМУ ЧАСІ · оновлено {age}", + "loading mapped installation context": "завантаження контексту нанесених об’єктів", + "MAPPED INSTALLATION": "НАНЕСЕНИЙ ОБ’ЄКТ", + "LAUNCH SITE · {site}": "МІСЦЕ ЗАПУСКУ · {site}", + "LAUNCH SITE": "МІСЦЕ ЗАПУСКУ", + "T−{time} · {mission}": "T−{time} · {mission}", + "LAUNCH STANDBY": "ГОТОВНІСТЬ ДО ЗАПУСКУ", + "LIFTOFF · {mission}": "СТАРТ · {mission}", + "ASCENT REPLAY · {mission}": "ПОВТОР ЗЛЬОТУ · {mission}", + "ASCENT ESTIMATE · {mission}": "РОЗРАХУНКОВИЙ ЗЛІТ · {mission}", + "STAGE RE-ENTRY / RECOVERY · {mission}": "ВХІД В АТМОСФЕРУ / ПОВЕРНЕННЯ · {mission}", + "ORBIT REPLAY · {mission}": "ПОВТОР ОРБІТИ · {mission}", + "PAUSED · {title}": "ПАУЗА · {title}", + "UNSPECIFIED": "НЕ ВКАЗАНО", + "+{count} additional payload records": "+{count} додаткових записів корисного навантаження", + "PAYLOAD DATA UNAVAILABLE": "ДАНІ КОРИСНОГО НАВАНТАЖЕННЯ НЕДОСТУПНІ", + "{value} KM DOWNRANGE": "{value} KM ПО ТРАЄКТОРІЇ", + "POSITION UNAVAILABLE": "ПОЗИЦІЯ НЕДОСТУПНА", + "FLIGHT {count}": "РЕЙС {count}", + "REUSED": "ПОВТОРНО ВИКОРИСТАНИЙ", + "NO STAGE RE-ENTRY / RECOVERY DATA": "НЕМАЄ ДАНИХ ПРО ВХІД В АТМОСФЕРУ / ПОВЕРНЕННЯ", + "{count} / 30D": "{count} / 30D", + "NO MISSIONS AVAILABLE IN THE CURRENT 30-DAY WINDOW": "НЕМАЄ МІСІЙ У ПОТОЧНОМУ 30-ДЕННОМУ ВІКНІ", + "DATE UNAVAILABLE": "ДАТА НЕДОСТУПНА", + "UNSPECIFIED OPERATOR": "ОПЕРАТОРА НЕ ВКАЗАНО", + "Select {mission}": "Вибрати {mission}", + "{value} KM": "{value} KM", + "{value} KM/S": "{value} KM/S", + "SELECTED SPACE MISSION": "ВИБРАНА КОСМІЧНА МІСІЯ", + "Show all missions": "Показати всі місії", + "Deselect mission": "Зняти вибір місії", + "MISSION": "МІСІЯ", + "PAYLOAD": "КОРИСНЕ НАВАНТАЖЕННЯ", + "NAME": "НАЗВА", + "TYPE": "ТИП", + "DESTINATION": "ПРИЗНАЧЕННЯ", + "STAGE / RE-ENTRY / RECOVERY": "СТУПІНЬ / ВХІД В АТМОСФЕРУ / ПОВЕРНЕННЯ", + "STAGE": "СТУПІНЬ", + "STATUS": "СТАТУС", + "FINAL POSITION": "КІНЦЕВА ПОЗИЦІЯ", + "REPLAY SPEED": "ШВИДКІСТЬ ПОВТОРУ", + "Replay speed multiplier": "Множник швидкості повтору", + "REPLAY ASCENT": "ПОВТОР ЗЛЬОТУ", + "Previous mission": "Попередня місія", + "PREV": "ПОПЕР.", + "Next mission": "Наступна місія", + "SHOW ALL / DESELECT": "ПОКАЗАТИ ВСІ / ЗНЯТИ ВИБІР", + "Pause replay": "Призупинити повтор", + "Cancel replay": "Скасувати повтор", + "EST. DOWNRANGE": "РОЗРАХ. ДАЛЬНІСТЬ", + "SUPPLIED TRAJECTORY POINTS": "НАДАНІ ТОЧКИ ТРАЄКТОРІЇ", + "RECONSTRUCTED ESTIMATE": "ВІДТВОРЕНА ОЦІНКА", + "Replay the estimated ascent with a following camera": "Відтворити розрахунковий зліт із камерою-супроводом", + "Resume replay": "Продовжити повтор", + "T minus {seconds}": "T мінус {seconds}", + "Preparing launch site": "Підготовка місця запуску", + "Liftoff": "Старт", + "Ascent replay": "Повтор зльоту", + "Orbit replay": "Повтор орбіти", + ", paused": ", пауза", + "Alt unknown": "Висота невідома", + "Type unknown": "Тип невідомий", + "Reg unknown": "Рег. невідомий", + "Operator unknown": "Оператор невідомий", + "radio tag|All": "Усі", + "News": "Новини", + "Talk": "Розмовні", + "Weather / Emergency": "Погода / Надзвичайні події", + "Public Safety": "Громадська безпека", + "Aviation / Marine": "Авіація / Флот", + "Traffic / Transit": "Рух / Транспорт", + "Music": "Музика", + "Other": "Інше", + "radio|NEWS": "НОВИНИ", + "radio|TALK": "РОЗМОВНІ", + "radio|WEATHER": "ПОГОДА", + "radio|SAFETY": "БЕЗПЕКА", + "radio|AIR / SEA": "АВІА / ФЛОТ", + "radio|TRANSIT": "ТРАНСПОРТ", + "radio|MUSIC": "МУЗИКА", + "radio|OTHER": "ІНШЕ", + "Alternative": "Альтернатива", + "Ambient": "Ембієнт", + "Blues": "Блюз", + "Classical": "Класика", + "Country": "Кантрі", + "Dance": "Танцювальна", + "Electronic": "Електронна", + "Folk": "Фолк", + "Funk": "Фанк", + "Hip-Hop": "Хіп-хоп", + "House": "Хаус", + "Indie": "Інді", + "Jazz": "Джаз", + "Latin": "Латина", + "Metal": "Метал", + "Oldies": "Ретро", + "Pop": "Поп", + "Punk": "Панк", + "R&B": "R&B", + "Reggae": "Реґі", + "Rock": "Рок", + "Soul": "Соул", + "Techno": "Техно", + "Trance": "Транс", + "World": "Етнічна", + "Add the full Starlink broadband shell (thousands of extra points)": "Додати повну широкосмугову оболонку Starlink (тисячі додаткових точок)", + "Loading the Starlink shell…": "Завантаження оболонки Starlink…", + "Starlink {detail} — click to retry": "Starlink: {detail} — клацніть, щоб повторити", + "load failed": "помилка завантаження", + "Showing the full Starlink shell — click for the core catalog only": "Показано повну оболонку Starlink — клацніть, щоб лишити лише основний каталог", + "DENSE ···": "ЩІЛЬНО ···", + "DENSE ✕": "ЩІЛЬНО ✕", + "DENSE": "ЩІЛЬНО", + "SIMULATED — traffic service unreachable": "ІМІТАЦІЯ — сервіс руху недоступний", + "SIMULATED — add TomTom key for live": "ІМІТАЦІЯ — додайте ключ TomTom для реального часу", + "AIS: {name}": "AIS: {name}", + "VESSEL": "СУДНО", + "POS: LIVE": "POS: У РЕАЛЬНОМУ ЧАСІ", + "POS: {time}Z": "POS: {time}Z", + "awaiting first AIS position…": "очікується перша позиція AIS…", + "awaiting usable AIS positions…": "очікуються придатні позиції AIS…", + "awaiting first AIS message…": "очікується перше повідомлення AIS…", + "Resume": "Продовжити", + "Pause": "Пауза", + "Error: {message}": "Помилка: {message}", + "Needs {envVars} — add it in Provider Settings": "Потрібно {envVars} — додайте у налаштуваннях постачальників", + "{label} is unavailable": "{label} — недоступно", + "This map stack": "Цей стек карт", + "{label} unavailable: {hint}": "{label} — недоступно: {hint}", + "Visible map targets": "Видимі цілі на карті", + "Ready": "Готово", + "Loaded: {scene} / {shot}": "Завантажено: {scene} / {shot}", + "Cannot capture shot: camera not ready": "Не вдалося зняти кадр: камера не готова", + "Captured: {scene} / {shot}": "Знято: {scene} / {shot}", + "Select a shot first": "Спочатку оберіть кадр", + "Updated: {scene} / {shot}": "Оновлено: {scene} / {shot}", + "Camera unavailable — exit cockpit first": "Камера недоступна — спершу вийдіть із кабіни", + "No shots to run": "Немає кадрів для запуску", + "Project exported": "Проєкт експортовано", + "Could not exit {mode} — scene layers may be refused": "Не вдалося вийти з {mode} — шари сцени може бути відхилено", + "Running {index}/{total}: {scene} / {shot}": "Виконання {index}/{total}: {scene} / {shot}", + "Scene run complete": "Запуск сцени завершено", + "Global Flights Radar": "Глобальний радар польотів", + "Orbital Watch": "Орбітальний нагляд", + "Thermal Threat Board": "Панель теплових загроз", + "City Overload": "Міське перевантаження", + "Omniscience Pullback": "Всевидячий від'їзд", + "Shot {n}": "Кадр {n}", + "Density": "Щільність", + "Bloom": "Світіння", + "VISUAL PRESETS": "ВІЗУАЛЬНІ ПРЕСЕТИ", + "LOCATION": "РОЗТАШУВАННЯ", + "CONTACTS — nearest planes · vessels · sites": "КОНТАКТИ — найближчі літаки · судна · об’єкти", + "SPACE MISSIONS — launches & orbital assets": "КОСМІЧНІ МІСІЇ — запуски та орбітальні апарати", + "LIVE SIGNALS": "СИГНАЛИ У РЕАЛЬНОМУ ЧАСІ", + "Contacts could not complete the requested transition; try again": "Контакти не змогли завершити запитаний перехід; спробуйте ще раз", + "CCTV layer unavailable": "Шар CCTV недоступний", + "Link copied!": "Посилання скопійовано!", + "Copy failed": "Не вдалося скопіювати", + "CCTV calibration saved": "Калібрування CCTV збережено", + "CCTV calibration reset": "Калібрування CCTV скинуто", + "ADJUST ON": "КОРИГУВАННЯ УВІМК.", + "ADJUST": "КОРИГУВАННЯ", + "UNKNOWN": "НЕВІДОМО", + "ERROR": "ПОМИЛКА", + "SOURCE · UNKNOWN": "ДЖЕРЕЛО · НЕВІДОМЕ", + "FRAME · LOADING": "КАДР · ЗАВАНТАЖЕННЯ", + "FRAME · UNAVAILABLE": "КАДР · НЕДОСТУПНИЙ", + "CALIBRATED": "КАЛІБРОВАНО", + "CURATED": "ПІДІБРАНО", + "RAW PRIOR": "СИРЕ АПРІОРНЕ", + "CCTV ON": "CCTV УВІМК.", + "CCTV OFF": "CCTV ВИМК.", + "VIEWSHED ON": "ЗОНА ВИДИМОСТІ УВІМКНЕНА", + "COVERAGE ON": "ЗОНА ОГЛЯДУ УВІМК.", + "COVERAGE OFF": "ЗОНА ОГЛЯДУ ВИМК.", + "AUTO HOP ON": "АВТОПЕРЕХІД УВІМК.", + "AUTO HOP OFF": "АВТОПЕРЕХІД ВИМК.", + "PROJECTION ON": "ПРОЄКЦІЯ УВІМК.", + "PROJECTION OFF": "ПРОЄКЦІЯ ВИМК.", + "CAL · EDITED (UNSAVED)": "CAL · ЗМІНЕНО (НЕ ЗБЕРЕЖЕНО)", + "CAL · {badge}": "CAL · {badge}", + "MONITOR": "МОНІТОР", + "OFF": "ВИМКНЕНО", + "{city} · HDG {heading} · FOV {fov} · RANGE {range}m · {projection}{calBadge} · {provider}{status}": "{city} · HDG {heading} · FOV {fov} · RANGE {range}m · {projection}{calBadge} · {provider}{status}", + "{count} cameras loaded · click a camera to activate": { + "one": "{count} камеру завантажено · клацніть камеру, щоб активувати", + "few": "{count} камери завантажено · клацніть камеру, щоб активувати", + "many": "{count} камер завантажено · клацніть камеру, щоб активувати", + "other": "{count} камери завантажено · клацніть камеру, щоб активувати" + }, + "{count} cameras loaded · enable CCTV to activate": { + "one": "{count} камеру завантажено · увімкніть CCTV, щоб активувати", + "few": "{count} камери завантажено · увімкніть CCTV, щоб активувати", + "many": "{count} камер завантажено · увімкніть CCTV, щоб активувати", + "other": "{count} камери завантажено · увімкніть CCTV, щоб активувати" + }, + "Enable CCTV to load camera intersections": "Увімкніть CCTV, щоб завантажити перехрестя камер", + "Enable CCTV to start camera-linked intelligence summaries.": "Увімкніть CCTV, щоб почати зведення розвідки за камерами.", + "No summary available.": "Зведення недоступне.", + "loading frames": "завантаження кадрів", + "camera grid ready": "сітка камер готова", + "Clearing selected data layers": "Очищення обраних шарів даних", + "Clear selected data layers": "Очистити вибрані шари даних", + "CONDITIONS UNKNOWN": "УМОВИ НЕВІДОМІ", + "CLEAR": "ЯСНО", + "PARTLY CLOUDY": "МІНЛИВА ХМАРНІСТЬ", + "OVERCAST": "ПОХМУРО", + "FOG": "ТУМАН", + "DRIZZLE": "МЖИЧКА", + "RAIN": "ДОЩ", + "RAIN SHOWERS": "ЗЛИВИ", + "SNOW SHOWERS": "СНІЖНІ ЗЛИВИ", + "THUNDERSTORM": "ГРОЗА", + "MIXED CONDITIONS": "ЗМІШАНІ УМОВИ", + "CYCLE ON": "ЦИКЛ УВІМКНЕНО", + "CYCLE OFF": "ЦИКЛ ВИМКНЕНО", + "Stop automatic page cycling. Previous, Next, and the SIG/NEWS/LOCAL tabs stay available.": "Зупинити автоматичне гортання сторінок. Попередня, Наступна та вкладки СИГ/НОВ/ЛОК залишаються доступними.", + "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.": "Гортає сторінки брифінгу автоматично кожні 9 секунд (Сигнали → Новини → Локально). Пауза, доки ви наводите вказівник або фокусуєте панель. Дані сигналів у реальному часі оновлюються безперервно незалежно від цього.", + "ACQUIRING REGIONAL NEWS": "ОТРИМАННЯ РЕГІОНАЛЬНИХ НОВИН", + "REGIONAL NEWS UNAVAILABLE": "РЕГІОНАЛЬНІ НОВИНИ НЕДОСТУПНІ", + "RESOLVING REGION": "ВИЗНАЧЕННЯ РЕГІОНУ", + "REGION UNAVAILABLE": "РЕГІОН НЕДОСТУПНИЙ", + "NO RECENT LOCATION MATCHES": "НЕМАЄ СВІЖИХ ЗБІГІВ ЗА РОЗТАШУВАННЯМ", + "{domain} · {age}": "{domain} · {age}", + "CLOUD {pct}%": "ХМАРНІСТЬ {pct}%", + "CLOUD UNKNOWN": "ХМАРНІСТЬ НЕВІДОМА", + "{source} · LOCATION QUERY": "{source} · ЗАПИТ ЗА РОЗТАШУВАННЯМ", + "REGIONAL NEWS": "РЕГІОНАЛЬНІ НОВИНИ", + "CONTEXT STANDBY": "КОНТЕКСТ: ОЧІКУВАННЯ", + "ENABLE GLOBAL CONTEXT FOR PROXIMITY PINGS": "УВІМКНІТЬ ГЛОБАЛЬНИЙ КОНТЕКСТ ДЛЯ ПІНГІВ БЛИЗЬКОСТІ", + "CONTACT LOST · LAST KNOWN READOUT · NOT AN ALL-CLEAR": "КОНТАКТ ВТРАЧЕНО · ОСТАННІ ВІДОМІ ПОКАЗНИКИ · НЕ ОЗНАЧАЄ «УСЕ ЧИСТО»", + "CONTACT LOST · {subject}": "КОНТАКТ ВТРАЧЕНО · {subject}", + "SUBJECT LEFT ITS FEED · READOUT HOLDING LAST KNOWN": "ОБ’ЄКТ ПОКИНУВ КАНАЛ ДАНИХ · ІНДИКАТОРИ ТРИМАЮТЬ ОСТАННЄ ВІДОМЕ", + "{cohort} · {contact}": "{cohort} · {contact}", + "NO AVAILABLE EXAMPLE": "НЕМАЄ ДОСТУПНОГО ПРИКЛАДУ", + "{cohort}, Unavailable": "{cohort}, недоступно", + "AHEAD": "ПОПЕРЕДУ", + "{side} {angle}": "{side} {angle}", + "L": "L", + "R": "R", + "{count} INPUTS UNKNOWN · NOT AN ALL-CLEAR": { + "one": "{count} НЕВІДОМИЙ ПАРАМЕТР · НЕ ОЗНАЧАЄ «УСЕ ЧИСТО»", + "few": "{count} НЕВІДОМІ ПАРАМЕТРИ · НЕ ОЗНАЧАЄ «УСЕ ЧИСТО»", + "many": "{count} НЕВІДОМИХ ПАРАМЕТРІВ · НЕ ОЗНАЧАЄ «УСЕ ЧИСТО»", + "other": "{count} НЕВІДОМОГО ПАРАМЕТРА · НЕ ОЗНАЧАЄ «УСЕ ЧИСТО»" + }, + "AVAILABLE INPUTS CURRENT · NOT AN ALL-CLEAR": "ДОСТУПНІ ВХІДНІ ДАНІ АКТУАЛЬНІ · НЕ ОЗНАЧАЄ «УСЕ ЧИСТО»", + "AIRCRAFT": "БОРТ", + "ACQUIRING SURFACE": "ОТРИМАННЯ НАЗЕМНИХ ДАНИХ", + "SURFACE FALLBACK": "РЕЗЕРВ НАЗЕМНИХ ДАНИХ", + "STALE FEED": "ЗАСТАРІЛИЙ КАНАЛ ДАНИХ", + "LIVE TRACK": "ТРЕК У РЕАЛЬНОМУ ЧАСІ", + "COMMERCIAL": "КОМЕРЦІЙНИЙ", + "{aircraftClass} · {feedState} · COURSE ALIGNED": "{aircraftClass} · {feedState} · КУРС ВИРІВНЯНО", + "ARROW · ESTIMATED DIRECTION": "СТРІЛКА · ОРІЄНТОВНИЙ НАПРЯМОК", + "ROUTE DATA UNAVAILABLE": "ДАНІ МАРШРУТУ НЕДОСТУПНІ", + "DEST {bearing}": "DEST {bearing}", + "Disable cockpit weather effects": "Вимкнути погодні ефекти кабіни", + "Enable cockpit weather effects": "Увімкнути погодні ефекти кабіни", + "ON": "УВІМК.", + "Normal": "Звичайний", + "Night vision": "Нічне бачення", + "Thermal": "Тепловізор", + "Anime": "Аніме", + "Noir": "Нуар", + "Snow": "Сніг", + "Current cockpit vision style: {style}. Activate for next style.": "Поточний стиль бачення кабіни: {style}. Активуйте для наступного стилю.", + "Current style: {style} — click for next": "Поточний стиль: {style} — клацніть для наступного", + "Collapse Contact panel": "Згорнути панель контактів", + "Expand Contact panel": "Розгорнути панель контактів", + "Collapse contact panel": "Згорнути панель контактів", + "Expand contact panel": "Розгорнути панель контактів", + "Collapse cockpit briefing panel": "Згорнути панель брифінгу кабіни", + "Expand cockpit briefing panel": "Розгорнути панель брифінгу кабіни", + "Collapse briefing panel": "Згорнути панель брифінгу", + "Expand briefing panel": "Розгорнути панель брифінгу", + "OBSERVED / MAPPED PINGS": "СПОСТЕРЕЖЕНІ / КАРТОГРАФОВАНІ ПІНГИ", + "SOURCE-BACKED EVENTS · NO SYNTHETIC NEWS": "ПОДІЇ ПІДТВЕРДЖЕНІ ДЖЕРЕЛАМИ · БЕЗ ШТУЧНИХ НОВИН", + "LATEST LOCATION-MATCHED REPORTING": "ОСТАННІ ПУБЛІКАЦІЇ ЗА РОЗТАШУВАННЯМ", + "LOCAL INFO": "ЛОКАЛЬНА ІНФОРМАЦІЯ", + "PLACE / CONDITIONS / POSITION": "МІСЦЕ / УМОВИ / ПОЗИЦІЯ", + "TIME UNKNOWN": "ЧАС НЕВІДОМИЙ", + "{count}M AGO": "{count} ХВ ТОМУ", + "{count}H AGO": "{count} ГОД ТОМУ", + "{count}D AGO": "{count} ДН ТОМУ", + "DIR UNKNOWN": "НАПР. НЕВІДОМИЙ", + "Select flight {title}": "Обрати рейс {title}", + "{aircraftClass} · CURRENT": "{aircraftClass} · ПОТОЧНИЙ", + "MILITARY FLIGHT": "ВІЙСЬКОВИЙ РЕЙС", + "COMMERCIAL FLIGHT": "КОМЕРЦІЙНИЙ РЕЙС", + "{aircraftClass} · {distance}": "{aircraftClass} · {distance}", + "DISTANCE UNKNOWN": "ВІДСТАНЬ НЕВІДОМА", + "{count} INPUTS UNKNOWN": { + "one": "{count} НЕВІДОМИЙ ПАРАМЕТР", + "few": "{count} НЕВІДОМІ ПАРАМЕТРИ", + "many": "{count} НЕВІДОМИХ ПАРАМЕТРІВ", + "other": "{count} НЕВІДОМОГО ПАРАМЕТРА" + }, + "SOURCE STATUS UNAVAILABLE": "СТАТУС ДЖЕРЕЛА НЕДОСТУПНИЙ", + "Restore real aircraft": "Повернути справжній літак", + "Reclassify as TR-3B": "Перекласифікувати як TR-3B", + "TRACK ACQUIRED": "ТРЕК ЗАХОПЛЕНО", + "{label} · COURSE {heading}°": "{label} · КУРС {heading}°", + "Context could not restore every layer; try again": "Не вдалося відновити всі шари контексту; спробуйте ще раз", + "No selected data layers": "Шари даних не вибрано", + "{count} data layers could not be cleared": { + "one": "Не вдалося очистити {count} шар даних", + "few": "Не вдалося очистити {count} шари даних", + "many": "Не вдалося очистити {count} шарів даних", + "other": "Не вдалося очистити {count} шара даних" + }, + "Cleared {count} data layers": { + "one": "Очищено {count} шар даних", + "few": "Очищено {count} шари даних", + "many": "Очищено {count} шарів даних", + "other": "Очищено {count} шара даних" + }, + "Selected data layers could not be cleared": "Не вдалося очистити обрані шари даних", + "Space Missions could not complete the requested transition; try again": "Космічні місії не змогли завершити запитаний перехід; спробуйте ще раз", + "Nearby installations refreshed": "Найближчі об’єкти оновлено", + "Nearby installations could not be refreshed; try again": "Не вдалося оновити найближчі об’єкти; спробуйте ще раз", + "Space Missions cancellation could not restore the previous layer state": "Скасування Космічних місій не змогло відновити попередній стан шарів", + "That layer is unavailable in the current Context mode": "Цей шар недоступний у поточному режимі контексту", + "{layerId} could not {action} cleanly": "{layerId}: не вдалося коректно {action}", + "start": "запустити", + "stop": "зупинити", + "{mode} could not start because another layer did not stop cleanly": "{mode} не вдалося запустити, бо інший шар не зупинився коректно", + "Space Missions": "Космічні місії", + "Context": "Контекст", + "Live Flights": "Літаки в реальному часі", + "Military Flights": "Військова авіація", + "Earthquakes (24h)": "Землетруси (24 год)", + "Satellites": "Супутники", + "Space Missions (30d)": "Космічні місії (30 дн)", + "Street Traffic": "Вуличний рух", + "CCTV": "CCTV", + "Radio": "Радіо", + "Bikeshare": "Велопрокат", + "Live AIS Vessels": "Судна AIS у реальному часі", + "Mapped Installations": "Нанесені об’єкти", + "Global Context": "Глобальний контекст", + "Datacenters": "Дата-центри", + "Dams": "Греблі", + "Submarine Cables": "Підводні кабелі", + "FIRMS Active Fires": "Активні пожежі FIRMS", + "ENABLING": "УВІМКНЕННЯ", + "DISABLING": "ВИМКНЕННЯ", + "{state} · {source}": "{state} · {source}", + "UNCERTAIN · {source} · lifecycle state requires reconciliation": "НЕВИЗНАЧЕНО · {source} · стан життєвого циклу потребує звірки", + "{state} · {source} · {detail} · retry {seconds}s": "{state} · {source} · {detail} · повтор через {seconds} с", + "{state} · {source} · {detail}": "{state} · {source} · {detail}", + "never": "ніколи", + "{source} · {loadingLabel}": "{source} · {loadingLabel}", + "{state} · {source} · {ago} · retrying in {seconds}s": "{state} · {source} · {ago} · повтор через {seconds} с", + "{state} · {source} · {ago}": "{state} · {source} · {ago}", + "{source} · {ago}": "{source} · {ago}", + "UNCERTAIN": "НЕВИЗНАЧЕНО", + "status chip|UNAVAILABLE": "НЕДОСТУПНО", + "{name}: {state}": "{name}: {state}", + "{count}s ago": "{count} с тому", + "CONNECTING": "З'ЄДНАННЯ", + "📍 Location: --": "📍 Розташування: --", + "Landmark: --": "Орієнтир: --", + "Searched location": "Знайдене розташування", + "ORBIT": "ОРБІТА", + "Location not found": "Розташування не знайдено", + "Search failed": "Пошук не вдався", + "Fly to a POI first": "Спершу полетіть до орієнтира", + "Reset to full globe view": "Скинути до загального вигляду глобуса", + "Reset cockpit to full globe view": "Скинути кабіну до вигляду всього глобуса", + "Resetting to full globe view": "Скидання до вигляду всього глобуса", + "Resetting cockpit to full globe view": "Скидання кабіни до вигляду всього глобуса", + "MAP": "КАРТА", + "panel": "панель", + "Expand {name}": "Розгорнути {name}", + "Collapse {name}": "Згорнути {name}", + "Expand Radio": "Розгорнути радіо", + "Collapse Radio": "Згорнути радіо", + "Expand Radio section": "Розгорнути розділ радіо", + "Collapse Radio section": "Згорнути розділ радіо", + "Panel layout updated — positions reset to new defaults": "Компонування панелей оновлено — позиції скинуто до нових типових", + "Collapse Cockpit display options": "Згорнути параметри дисплея кабіни", + "Expand Cockpit display options": "Розгорнути параметри дисплея кабіни", + "Collapse Cockpit Radio controls": "Згорнути керування радіо кабіни", + "Expand Cockpit Radio controls": "Розгорнути керування радіо кабіни", + "NO STATIONS": "НЕМАЄ СТАНЦІЙ", + "NO STATION AVAILABLE": "НЕМАЄ ДОСТУПНИХ СТАНЦІЙ", + "{name}, station {index} of {total}": "{name}, станція {index} з {total}", + "No station available": "Немає доступної станції", + "OFF AIR": "НЕ В ЕФІРІ", + "STATION UNAVAILABLE": "СТАНЦІЯ НЕДОСТУПНА", + "Radio could not {action} cleanly": "Радіо: не вдалося коректно {action}", + "Close compact Radio controls": "Закрити компактне керування радіо", + "Open compact Radio controls": "Відкрити компактне керування радіо", + "SYNC": "СИНХР.", + "RECONCILE": "ЗВІРИТИ", + "DISABLE": "ВИМКНУТИ", + "ENABLE": "УВІМКНУТИ", + "Reconcile Radio — lifecycle uncertain": "Звірити радіо — стан життєвого циклу невизначений", + "Disable Radio": "Вимкнути радіо", + "Enable Radio": "Увімкнути радіо", + "DIRECTORY BAND": "ДІАПАЗОН КАТАЛОГУ", + "{category} BAND": "{category} ДІАПАЗОН", + "NO STATION SELECTED": "СТАНЦІЮ НЕ ВИБРАНО", + "Directory metadata only": "Лише метадані каталогу", + "Loading station directory…": "Завантаження каталогу станцій…", + "Choose a globe marker or use next.": "Виберіть маркер на глобусі або натисніть «наступна».", + "TAGS · {tags}": "ТЕГИ · {tags}", + "Play": "Відтворити", + "PLAY": "ВІДТВОРИТИ", + "selected": "обрану", + "nearest": "найближчу", + "{action} {target} radio station": "{action} {target} радіостанцію", + "RADIO STATE UNCERTAIN": "СТАН РАДІО НЕВИЗНАЧЕНИЙ", + "SYNCING DIRECTORY": "СИНХРОНІЗАЦІЯ КАТАЛОГУ", + "RADIO READY": "РАДІО ГОТОВЕ", + "SYNCING": "СИНХРОНІЗАЦІЯ", + "READY": "ГОТОВА", + "station": "станція", + "Ready — playback starts only from your action": "Готово — відтворення починається лише за вашою дією", + "Radio off": "Радіо вимкнено", + "Connecting directly to broadcaster…": "Пряме з’єднання з мовником…", + "Buffering broadcaster stream…": "Буферизація потоку мовника…", + "Playing {station}": "Відтворюється: {station}", + "Paused {station}": "Пауза: {station}", + "Broadcaster stream unavailable": "Потік мовника недоступний", + "Station unavailable after directory refresh — choose another channel": "Станція недоступна після оновлення каталогу — виберіть інший канал", + "Radio is enabling…": "Радіо вмикається…", + "Radio is disabling…": "Радіо вимикається…", + "Radio lifecycle is uncertain — use Enable or Disable to reconcile": "Стан радіо невизначений — звірте через «Увімкнути» або «Вимкнути»", + "Scene action failed": "Не вдалося виконати дію сцени", + "Delete shot \"{shot}\"?": "Видалити кадр «{shot}»?", + "SPARSE": "РЕДКИЙ", + "BALANCED": "ЗБАЛАНСОВАНИЙ", + "DEL": "ВИДАЛ.", + "entity": "об’єкт", + "Shared {subject} follow expired": "{subject}: ТЕРМІН СТЕЖЕННЯ МИНУВ", + "Shared {subject} could not be restored — feed unavailable": "{subject} НЕ ВДАЛОСЯ ВІДНОВИТИ — КАНАЛ ДАНИХ НЕДОСТУПНИЙ", + "Shared {subject} is unavailable": "{subject}: НЕМАЄ ДОСТУПУ", + "ACQUIRING": "ОТРИМАННЯ", + "SHARED {subject}": "ПОДІЛЕНО: {subject}", + "LOADING LIVE DATA": "ЗАВАНТАЖЕННЯ ДАНИХ У РЕАЛЬНОМУ ЧАСІ", + "LOAD COMPLETE": "ЗАВАНТАЖЕННЯ ЗАВЕРШЕНО", + "LOAD CANCELLED": "ЗАВАНТАЖЕННЯ СКАСОВАНО", + "LOAD FAILED": "ПОМИЛКА ЗАВАНТАЖЕННЯ", + "LIVE DATA OFF": "ДАНІ У РЕАЛЬНОМУ ЧАСІ ВИМКНЕНО", + "MAPPED SITES LOADED": "МІСЦЯ НА КАРТІ ЗАВАНТАЖЕНО", + "RETRYING MAPPED SITES": "ПОВТОРНЕ ЗАВАНТАЖЕННЯ МІСЦЬ НА КАРТІ", + "FETCHING MAPPED SITES": "ЗАВАНТАЖЕННЯ МІСЦЬ НА КАРТІ", + "TURNING OFF LIVE DATA": "ВИМКНЕННЯ ДАНИХ У РЕАЛЬНОМУ ЧАСІ", + "REFRESHING LIVE DATA": "ОНОВЛЕННЯ ДАНИХ У РЕАЛЬНОМУ ЧАСІ", + "syncing road network": "синхронізація дорожньої мережі", + "Celestial ring — reveal the full globe": "Небесне кільце — показати весь глобус", + "Celestial ring — available in Normal style": "Небесне кільце — доступне у стилі «Звичайний»", + "Detection overlay: {mode}": "Накладка виявлення: {mode}", + "Detection overlay: off": "Накладка виявлення: вимк.", + "DETECT": "ВИЯВЛЕННЯ", + "voice|OFF": "ВИМКНЕНО", + "voice|CONNECTING": "З'ЄДНАННЯ", + "voice|LISTENING": "СЛУХАЮ", + "voice|EXECUTING": "ВИКОНАННЯ", + "voice|ERROR": "ПОМИЛКА", + "AI AGENT": "АГЕНТ ШІ", + "Voice model tier — applies next session": "Рівень голосової моделі — набуде чинності з наступної сесії", + "Estimated session cost": "Орієнтовна вартість сесії", + "Voice control — activate to toggle voice; hold Space to speak": "Голосове керування — активуйте, щоб увімкнути або вимкнути голос; утримуйте Space, щоб говорити", + "VOICE STANDBY": "ГОЛОСОВЕ ОЧІКУВАННЯ", + "VOICE CONTROL": "ГОЛОСОВЕ КЕРУВАННЯ", + "Hold Space to speak · tap Space to activate focused controls": "Утримуйте Space, щоб говорити · тапніть Space, щоб активувати елемент у фокусі", + "VOICE SYSTEM ERROR": "ПОМИЛКА ГОЛОСОВОЇ СИСТЕМИ", + "DISMISS": "ЗАКРИТИ", + "Check microphone permission and network access, then try again.": "Перевірте дозвіл на мікрофон і доступ до мережі, потім спробуйте ще раз.", + "Release Space to send": "Відпустіть Space, щоб надіслати", + "Hold Space to talk": "Утримуйте Space, щоб говорити", + "Requesting microphone": "Запит доступу до мікрофона", + "Ask or command": "Питання або команда", + "Running command": "Виконання команди", + "Voice off": "Голос вимкнено", + "WebRTC microphone support unavailable": "Підтримка мікрофона WebRTC недоступна", + "VOICE UNAVAILABLE": "ГОЛОС НЕДОСТУПНИЙ", + "VOICE ACTIVE": "ГОЛОС АКТИВНИЙ", + "Voice session could not be started.": "Не вдалося запустити голосову сесію.", + "Next session: {pendingId} — this session stays on {modelId}": "Наступна сесія: {pendingId} — поточна залишається на {modelId}", + "Voice model: {pendingId} — click to switch to {target}; applies next session": "Голосова модель: {pendingId} — натисніть, щоб перейти на {target}; набуде чинності з наступної сесії", + "Estimated session cost on {modelId} — {responses} response(s). Warns at {warn}, ends the session at {cap}.": "Орієнтовна вартість сесії на {modelId} — відповідей: {responses}. Попереджає при {warn}, завершує сесію при {cap}.", + "{tier} applies next session": "{tier} набуде чинності з наступної сесії", + "Session ended — cost cap {cost}": "Сесію завершено — ліміт витрат {cost}", + "Radio did not start": "Радіо не запустилося", + "Aircraft cockpit view": "Вигляд кабіни повітряного судна", + "LEVEL": "РІВЕНЬ", + "Estimated destination direction": "Орієнтовний напрямок до пункту призначення", + "DEST ---°": "DEST ---°", + "OPTICAL PLANE · 01": "ОПТИЧНА ПЛОЩИНА · 01", + "VISOR LOCK · ACTIVE": "ФІКСАЦІЯ ВІЗОРА · АКТИВНА", + "GROUND SPEED · KTS": "ШВИДКІСТЬ · KTS", + "ALTITUDE · FT": "ВИСОТА · FT", + "FIRST PERSON": "ВІД ПЕРШОЇ ОСОБИ", + "LIVE TRACK · COURSE ALIGNED": "ТРЕК У РЕАЛЬНОМУ ЧАСІ · КУРС ВИРІВНЯНО", + "Cockpit vision style": "Стиль бачення кабіни", + "Previous cockpit vision style": "Попередній стиль бачення кабіни", + "Previous vision style": "Попередній стиль бачення", + "Current cockpit vision style: NORMAL. Activate for next style.": "Поточний стиль бачення кабіни: NORMAL. Активуйте для наступного стилю.", + "Current style: NORMAL — click for next": "Поточний стиль: NORMAL — клацніть для наступного", + "CURRENT": "ПОТОЧНИЙ", + "Next cockpit vision style": "Наступний стиль бачення кабіни", + "Next vision style": "Наступний стиль бачення", + "Current aircraft heading": "Поточний курс повітряного судна", + "GROUND SPEED": "ШВИДКІСТЬ", + "ALTITUDE": "ВИСОТА", + "Contact cockpit summary": "Зведення контакта в кабіні", + "CONTACT": "КОНТАКТ", + "CONTACTS · 250 KM": "КОНТАКТИ · 250 KM", + "Contact navigation": "Навігація контактами", + "CONTEXT ONLY": "ЛИШЕ КОНТЕКСТ", + "Nearby cohort counts": "Кількість найближчих груп", + "NEAREST OBSERVED / MAPPED": "НАЙБЛИЖЧІ СПОСТЕРЕЖЕНІ / КАРТОГРАФОВАНІ", + "AVAILABLE INPUTS ONLY · NOT AN ALL-CLEAR": "ЛИШЕ ДОСТУПНІ ВХІДНІ ДАНІ · НЕ ОЗНАЧАЄ «УСЕ ЧИСТО»", + "Cockpit briefing carousel": "Карусель брифінгу кабіни", + "Estimated flight plan": "Орієнтовний план польоту", + "ESTIMATED FLIGHT PLAN": "ОРІЄНТОВНИЙ ПЛАН ПОЛЬОТУ", + "FROM": "ВІД", + "TO": "ДО", + "Cockpit briefing controls": "Керування брифінгом кабіни", + "Previous briefing page": "Попередня сторінка брифінгу", + "Next briefing page": "Наступна сторінка брифінгу", + "Live signals": "Сигнали в реальному часі", + "Latest regional news": "Останні регіональні новини", + "Location-based information": "Інформація за розташуванням", + "TEMP": "ТЕМП", + "WIND": "ВІТЕР", + "SKY": "НЕБО", + "PRECIP": "ОПАДИ", + "Show Live Signals": "Показати сигнали в реальному часі", + "NEWS": "НОВИНИ", + "Show Regional News": "Показати регіональні новини", + "Show Local Info": "Показати локальну інформацію", + "Cockpit display and Radio controls": "Керування дисплеєм і радіо кабіни", + "DISPLAY": "ДИСПЛЕЙ", + "Cockpit display options": "Параметри дисплея кабіни", + "RADIO": "РАДІО", + "Cockpit compact Radio controls": "Компактне керування радіо кабіни", + "Previous filtered radio station": "Попередня відфільтрована радіостанція", + "Play selected radio station": "Відтворити обрану радіостанцію", + "Next filtered radio station": "Наступна відфільтрована радіостанція", + "VOLUME": "ГУЧНІСТЬ", + "Cockpit Radio volume": "Гучність радіо кабіни", + "View switcher": "Перемикач вигляду", + "Exit cockpit and return to full globe view": "Вийти з кабіни та повернутися до вигляду всього глобуса", + "RESET": "СКИНУТИ", + "Exit cockpit view": "Вийти з вигляду кабіни", + "EXIT COCKPIT": "ВИЙТИ З КАБІНИ", + "Navigation, voice, and visual preset controls": "Керування навігацією, голосом і візуальними пресетами", + "Expand Visual Presets": "Розгорнути візуальні пресети", + "Pin visual presets": "Закріпити візуальні пресети", + "Keep visual presets open": "Тримати візуальні пресети відкритими", + "Show the globe without a visual filter.": "Показує глобус без візуального фільтра.", + "Emulate a green phosphor CRT with scanlines and screen curvature.": "Імітує CRT-монітор із зеленим фосфором, рядками розгортки та вигнутим екраном.", + "Simulate night-vision goggles with green intensification and a tube vignette.": "Імітує прилад нічного бачення з зеленим підсиленням та віньєткою туби.", + "Simulate FLIR-style thermal contrast. Turn up Ironbow for color.": "Імітує термальний контраст у стилі FLIR. Для кольору збільште Ironbow.", + "Apply bright cel-shaded color and illustrated outlines.": "Застосовує яскраву мультяшну заливку та ілюстровані контури.", + "Apply high-contrast monochrome film-noir grading.": "Застосовує висококонтрастну чорно-білу обробку в стилі нуар.", + "Add a cold, snowy whiteout treatment to the scene.": "Додає до сцени холодний засніжений білий ефект.", + "MAP SOURCE": "ДЖЕРЕЛО КАРТИ", + "Map source": "Джерело карти", + "Style": "Стиль", + "Expand LOCATION": "Розгорнути РОЗТАШУВАННЯ", + "Collapse panel": "Згорнути панель", + "Pin location tray": "Закріпити панель розташування", + "Keep location tray open": "Тримати панель розташування відкритою", + "Search any location": "Шукати будь-яке розташування", + "Search location by name or coordinates": "Шукати розташування за назвою або координатами", + "Search any location...": "Шукати будь-яке розташування...", + "WEATHER": "ПОГОДА", + "CONTEXT": "КОНТЕКСТ", + "Compact Radio controls": "Компактне керування радіо", + "Open detailed Radio controls": "Відкрити докладне керування радіо", + "Previous station": "Попередня станція", + "Next station": "Наступна станція", + "Compact Radio volume": "Гучність компактного радіо", + "Expand panel": "Розгорнути панель", + "Context mode": "Режим контексту", + "CONTACTS": "КОНТАКТИ", + "Cycles the nearest contacts of whatever type you select — planes, vessels, installations. Satellites track independently.": "Гортає найближчі контакти обраного вами типу — літаки, судна, об’єкти. Супутники відстежуються окремо.", + "SPACE MISSIONS": "КОСМІЧНІ МІСІЇ", + "SELECT CONTEXT": "ОБЕРІТЬ КОНТЕКСТ", + "Contact Context actions": "Дії контексту контактів", + "COCKPIT": "КАБІНА", + "SEARCH NEARBY SITES": "ПОШУК НАЙБЛИЖЧИХ ОБ’ЄКТІВ", + "Reclassify tracked contact as TR-3B": "Перекласифікувати відстежуваний контакт як TR-3B", + "CONTACTS CONTEXT OFF": "КОНТЕКСТ КОНТАКТІВ ВИМКНЕНО", + "SELECT CONTACTS TO LOAD OBSERVED / MAPPED PROXIMITY": "ОБЕРІТЬ КОНТАКТИ, ЩОБ ЗАВАНТАЖИТИ СПОСТЕРЕЖЕНУ / КАРТОГРАФОВАНУ БЛИЗЬКІСТЬ", + "Available Space Missions": "Доступні космічні місії", + "AVAILABLE MISSIONS": "ДОСТУПНІ МІСІЇ", + "SELECT A MISSION TO INSPECT": "ОБЕРІТЬ МІСІЮ ДЛЯ ПЕРЕГЛЯДУ", + "LOADING 30-DAY MISSION INDEX": "ЗАВАНТАЖЕННЯ ІНДЕКСУ МІСІЙ ЗА 30 ДНІВ", + "TAB PREVIEWS · ENTER / SPACE SELECTS": "TAB — ОГЛЯД · ENTER / SPACE — ВИБІР", + "STATION TAG": "ТЕГ СТАНЦІЇ", + "Filter stations by station tag": "Фільтрувати станції за тегом", + "All": "Усі", + "Enable Radio, then choose a globe marker or use next.": "Увімкніть радіо, потім виберіть маркер на глобусі або натисніть «наступна».", + "DRAG TO TUNE": "ТЯГНІТЬ ДЛЯ НАЛАШТУВАННЯ", + "ALL · DRAG THE NEEDLE": "УСІ · ПОТЯГНІТЬ СТРІЛКУ", + "SNAPS TO AVAILABLE STATIONS": "ПРИЛИПАЄ ДО ДОСТУПНИХ СТАНЦІЙ", + "Radio playback": "Відтворення радіо", + "Previous filtered station": "Попередня станція у фільтрі", + "Play selected station": "Відтворити вибрану станцію", + "Next filtered station": "Наступна станція у фільтрі", + "STOP": "СТОП", + "Stop radio playback": "Зупинити відтворення радіо", + "Radio volume": "Гучність радіо", + "STATION SITE": "САЙТ СТАНЦІЇ", + "Audio connects directly to the broadcaster after you press play. Your IP is visible to that broadcaster.": "Після натискання відтворення аудіо з’єднується напряму з мовником. Мовник бачить вашу IP-адресу.", + "Intelligence HUD (H)": "Розвідувальний HUD (H)", + "Layout": "Компонування", + "HUD layout": "Компонування HUD", + "Tactical": "Тактичне", + "Operator": "Операторське", + "Minimal": "Мінімальне", + "Detection Overlay (D)": "Накладка виявлення (D)", + "Detection overlay": "Накладка виявлення", + "Detection label density": "Щільність підписів виявлення", + "Allocation": "Розподіл", + "Detection label allocation": "Розподіл підписів виявлення", + "Elastic": "Пружний", + "Weighted": "Зважений", + "Fade": "Згасання", + "Detection fade distance": "Відстань згасання виявлення", + "World-overlay fade distance outside the keyhole as a percentage of its radius": "Відстань згасання накладки світу за межами ілюмінатора у відсотках його радіуса", + "Outside": "Ззовні", + "Detection opacity outside the keyhole": "Непрозорість виявлення за межами ілюмінатора", + "World-overlay label and card opacity beyond the fade distance": "Непрозорість підписів і карток накладки світу за межею згасання", + "PARAMETERS": "ПАРАМЕТРИ", + "3D aircraft — flat icons zoomed out, 3D models up close": "3D літаки — плоскі іконки здалеку, 3D-моделі зблизька", + "Models": "Моделі", + "3D model coverage": "Зона огляду 3D-моделей", + "Proximity": "Поблизу", + "Scope — the circular viewport mask": "Приціл — кругла маска вікна перегляду", + "Scope": "Приціл", + "Feather": "Розмиття", + "Scope edge feather": "Розмиття краю приціла", + "Scope edge feather as a percentage of the keyhole radius": "Розмиття краю приціла у відсотках радіуса ілюмінатора", + "Celestial": "Небесне", + "Hide UI chrome": "Сховати оформлення інтерфейсу", + "Clean UI": "Чистий інтерфейс", + "Bloom / Glow": "Світіння / Ореол", + "Bloom intensity": "Інтенсивність світіння", + "Sharpening": "Підвищення різкості", + "Sharpen": "Різкість", + "Sharpen intensity": "Інтенсивність різкості", + "EXIT CLEAN VIEW": "ВИЙТИ З ЧИСТОГО ВИГЛЯДУ", + "Return UI controls": "Повернути елементи керування", + "Initializing photorealistic world...": "Ініціалізація фотореалістичного світу...", + "DATA LAYERS": "ШАРИ ДАНИХ", + "NEAREST": "НАЙБЛИЖЧА", + "CCTV camera": "Камера CCTV", + "CALIBRATION": "КАЛІБРУВАННЯ", + "Drag the camera in the world: rings rotate, arrows move, handles set range/FOV": "Перетягніть камеру у сцені: кільця обертаються, стрілки переміщуються, маркери задають дальність/FOV", + "Camera pose — click a value to type": "Позиція камери — клацніть значення, щоб увести", + "Heading (compass °) — click to type": "Курс (° за компасом) — клацніть, щоб увести", + "Pitch (° up/down) — click to type": "Тангаж (° вгору/вниз) — клацніть, щоб увести", + "Horizontal FOV (°) — click to type": "Горизонтальний FOV (°) — клацніть, щоб увести", + "Range / monitor-plane distance (m) — click to type": "Дальність / відстань до площини монітора (м) — клацніть, щоб увести", + "Mount height above ground (m) — click to type": "Висота кріплення над землею (м) — клацніть, щоб увести", + "North offset from catalog position (m) — click to type": "Зміщення на північ від позиції каталогу (м) — клацніть, щоб увести", + "East offset from catalog position (m) — click to type": "Зміщення на схід від позиції каталогу (м) — клацніть, щоб увести", + "SAVE CAL": "ЗБЕРЕГТИ КАЛ.", + "RESET CAL": "СКИНУТИ КАЛ.", + "SCENE SUMMARY": "ЗВЕДЕННЯ СЦЕНИ", + "SCENES": "СЦЕНИ", + "Scene recipe": "Рецепт сцени", + "NEW": "НОВА", + "CAPTURE SHOT": "ЗНЯТИ КАДР", + "UPDATE SHOT": "ОНОВИТИ КАДР", + "START": "СТАРТ", + "EXPORT PRESETS": "ЕКСПОРТУВАТИ ПРЕСЕТИ", + "IMPORT": "ІМПОРТУВАТИ", + "RUN LOG": "ЖУРНАЛ ЗАПУСКІВ", + "POWER UP": "ЗАПУСК", + "GROUND STATION · PROVIDER SETTINGS": "НАЗЕМНА СТАНЦІЯ · НАЛАШТУВАННЯ ПОСТАЧАЛЬНИКІВ", + "Close key setup": "Закрити налаштування ключів", + "Power up the globe": "Запустіть глобус", + "The globe already flies keyless. Every key below switches on another real feed — paste one and it's saved into this app's local configuration, then the server restarts itself. Server-side keys stay on this machine; Google Maps and Cesium ion run in the browser and must be provider-restricted. Keys you configured elsewhere are shown but never touched.": "Глобус уже літає без ключів. Кожен ключ нижче вмикає ще один справжній канал даних — вставте його, і він збережеться в локальну конфігурацію застосунку, після чого сервер перезапуститься самостійно. Серверні ключі залишаються на цій машині; Google Maps і Cesium ion працюють у браузері, тож їхні ключі треба обмежити на боці постачальника. Ключі, налаштовані деінде, показуються, але ніколи не змінюються.", + "SAVE KEYS": "ЗБЕРЕГТИ КЛЮЧІ", + "ESC to close": "ESC — закрити", + "The Google Maps key buys the photorealistic planet — everything else stacks on top.": "Ключ Google Maps відкриває фотореалістичну планету — усе інше нашаровується зверху.", + "NO PLACE LEFT BEHIND": "НІКОГО НЕ ЗАЛИШАЄМО ПОЗАДУ", + "ACTIVE STYLE": "АКТИВНИЙ СТИЛЬ", + "Globe actions": "Дії з глобусом", + "Turn off all selected data layers": "Вимкнути всі вибрані шари даних", + "Copy share link": "Копіювати посилання для поширення", + "Reset camera and return to full globe view": "Скинути камеру та повернутися до загального вигляду глобуса", + "MISSION CONTROL · FIRST LAUNCH": "ЦЕНТР КЕРУВАННЯ · ПЕРШИЙ ЗАПУСК", + "Choose your first view": "Оберіть свій перший вигляд", + "LIVE CONTACTS": "КОНТАКТИ В РЕАЛЬНОМУ ЧАСІ", + "Aircraft, vessels and nearby intelligence": "Літаки, судна та розвідка поблизу", + "Launches, spacecraft and orbital context": "Запуски, космічні апарати та орбітальний контекст", + "EXPLORE MANUALLY": "ДОСЛІДИТИ ВРУЧНУ", + "Begin with a clean globe": "Почніть із чистого глобуса", + "Don't show this again": "Більше не показувати", + "ESC to dismiss": "ESC — приховати", + "Tip: the GEV MIC button in the dock lets you talk to the map.": "Порада: кнопка GEV MIC у доку дає змогу говорити з картою." +} From ce17d0cade1b6f35bb8a4c68c09d5522c9078a7b Mon Sep 17 00:00:00 2001 From: Enzo Abyie Date: Wed, 28 Oct 2026 12:37:19 +0400 Subject: [PATCH 04/83] i18n(pt): Portuguese strings from #909 The Brazilian Portuguese locale by abiyeenzo (#909), converted from its namespaced JS catalogs to the English-keyed pt.json: 859 entries whose English still matches the current UI. --- src/i18n/locales/pt.json | 889 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 889 insertions(+) create mode 100644 src/i18n/locales/pt.json diff --git a/src/i18n/locales/pt.json b/src/i18n/locales/pt.json new file mode 100644 index 000000000..0afe119ed --- /dev/null +++ b/src/i18n/locales/pt.json @@ -0,0 +1,889 @@ +{ + "Flying to Austin, TX...": "Voando para Austin, TX...", + "Restoring shared view...": "Restaurando a vista compartilhada...", + "Configuring viewer...": "Configurando o visualizador...", + "Loading Google 3D Tiles...": "Carregando Google 3D Tiles...", + "Loading the keyless globe...": "Carregando o globo sem chave...", + "Google 3D Tiles unavailable ({detail}). Loading the keyless globe...": "Google 3D Tiles indisponível ({detail}). Carregando o globo sem chave...", + "Initializing systems...": "Inicializando sistemas...", + "Close data attribution": "Fechar atribuição de dados", + "UNAVAILABLE": "INDISPONÍVEL", + "SOURCE": "FONTE", + "Overpass rate-limited": "Overpass com limite de requisições", + "Overpass timed out": "Tempo esgotado no Overpass", + "Overpass could not complete the query": "Overpass não conseguiu concluir a consulta", + "Overpass temporarily unavailable": "Overpass temporariamente indisponível", + "Retrying mapped sites…": "Repetindo busca de locais mapeados…", + "Fetching mapped sites…": "Buscando locais mapeados…", + "{reason} — retrying in {seconds}s": "{reason} — nova tentativa em {seconds}s", + "{reason} — retry pending": "{reason} — nova tentativa pendente", + "Zoom in to search mapped installations": "Aproxime o zoom para buscar instalações mapeadas", + "Showing cached mapped sites": "Mostrando locais mapeados em cache", + "Mapped sites not loaded": "Locais mapeados não carregados", + "Mapped sites loaded": "Locais mapeados carregados", + "feed unavailable": "feed indisponível", + "feed stale": "feed desatualizado", + "observed or mapped nearby context": "contexto observado ou mapeado nas proximidades", + "no observed or mapped objects in current feeds": "nenhum objeto observado ou mapeado nos feeds atuais", + "STATION": "ESTAÇÃO", + "Crewed stations and their visiting vehicles": "Estações tripuladas e seus veículos visitantes", + "NAV": "NAV", + "GNSS navigation — GPS, GLONASS, Galileo": "Navegação GNSS — GPS, GLONASS, Galileo", + "GEO": "GEO", + "Geostationary belt — comms and weather, fixed over the equator": "Cinturão geoestacionário — comunicações e clima, fixo sobre o equador", + "VISUAL": "VISUAL", + "Brightest naked-eye objects — CelesTrak visual group": "Objetos mais brilhantes a olho nu — grupo visual do CelesTrak", + "COMMS": "COMS", + "Broadband constellation shell — shown only in DENSE mode": "Malha de constelação de banda larga — exibida só no modo DENSO", + "FISHING": "PESCA", + "TOWING": "REBOQUE", + "DREDGER": "DRAGA", + "DIVE OPS": "OPS DE MERGULHO", + "MILITARY": "MILITAR", + "SAILING": "VELEIRO", + "PLEASURE": "RECREIO", + "PILOT": "PRÁTICO", + "SAR": "SAR", + "TUG": "REBOCADOR", + "PORT TENDER": "APOIO PORTUÁRIO", + "ANTI-POLLUTION": "ANTIPOLUIÇÃO", + "LAW ENFORCE": "FISCALIZAÇÃO", + "MEDICAL": "MÉDICO", + "HIGH-SPEED": "ALTA VELOCIDADE", + "PASSENGER": "PASSAGEIROS", + "CARGO": "CARGUEIRO", + "TANKER": "PETROLEIRO", + "OTHER": "OUTROS", + "ENVIRONMENTAL": "AMBIENTAL", + "EARTH WATCH": "VIGIA DA TERRA", + "ACTIVE EVENTS": "EVENTOS ATIVOS", + "Starting live contacts…": "Iniciando contatos ao vivo…", + "Opening space missions…": "Abrindo missões espaciais…", + "Scanning active events…": "Varrendo eventos ativos…", + "Live earthquakes and active fires, from USGS and NASA": "Terremotos e incêndios ativos ao vivo, de USGS e NASA", + "It feels like a forbidden cockpit—then you realize the sources are public and the data is real.": "Parece uma cabine proibida—até você perceber que as fontes são públicas e os dados são reais.", + "Working…": "Processando…", + "Could not open that mission{detail}. Retry or explore manually.": "Não foi possível abrir essa missão{detail}. Tente novamente ou explore manualmente.", + "This browser is blocking storage, so that could not be saved.": "Este navegador está bloqueando o armazenamento, então não foi possível salvar.", + "CRT": "CRT", + "NVG": "NVG", + "FLIR": "FLIR", + "SNOW": "NEVE", + "LOADING": "CARREGANDO", + "DEGRADED": "DEGRADADO", + "STALE": "DESATUALIZADO", + "PARTIAL": "PARCIAL", + "FALLBACK": "ALTERNATIVO", + "SUMMARY": "RESUMO", + "Awaiting telemetry...": "Aguardando telemetria...", + "REC": "GRAV", + "AIS: --": "AIS: --", + "POWER UP · {count} KEYS WAITING": { + "one": "ATIVAR · {count} CHAVE PENDENTE", + "many": "ATIVAR · {count} CHAVES PENDENTES", + "other": "ATIVAR · {count} CHAVES PENDENTES" + }, + "POWERED UP": "ATIVADO", + "Save failed ({status}).": "Falha ao salvar ({status}).", + "REMOVE": "REMOVER", + "Remove {title} from this app's saved keys": "Remover {title} das chaves salvas deste app", + "your app configuration": "sua configuração do app", + "your local .env": "seu .env local", + "Saving…": "Salvando…", + "Save failed: {detail}": "Falha ao salvar: {detail}", + "Paste at least one key first.": "Cole pelo menos uma chave primeiro.", + "Saved to {store}. Restarting — this page reloads itself.": "Salvo em {store}. Reiniciando — esta página recarrega sozinha.", + "Remove this key from your saved configuration?": "Remover esta chave da sua configuração salva?", + "Removed from {store}. Restarting — this page reloads itself.": "Removido de {store}. Reiniciando — esta página recarrega sozinha.", + "Places context + Street View fallback; optional separate key": "Contexto de lugares + alternativa do Street View; chave separada opcional", + "Live ships, worldwide": "Navios ao vivo, no mundo todo", + "Live active-fire detections": "Detecções de incêndios ativos ao vivo", + "Real live traffic (keyless runs a simulation)": "Trânsito real ao vivo (sem chave roda uma simulação)", + "Bing imagery map stacks + world terrain": "Pilhas de mapa com imagens Bing + relevo mundial", + "More flight-polling credits (anonymous works without)": "Mais créditos de consulta de voos (funciona sem, de forma anônima)", + "CONTEXT READY": "CONTEXTO PRONTO", + "GLOBAL CONTEXT OFF": "CONTEXTO GLOBAL DESLIGADO", + "SELECT A FLIGHT, VESSEL, OR MAPPED INSTALLATION": "SELECIONE UM VOO, EMBARCAÇÃO OU INSTALAÇÃO MAPEADA", + "ENABLE TO LOAD OBSERVED / MAPPED PROXIMITY": "ATIVE PARA CARREGAR PROXIMIDADE OBSERVADA / MAPEADA", + "Unavailable": "Indisponível", + "Focus {label}": "Focar {label}", + "Global Context navigation": "Navegação do contexto global", + "Previous — prior visited contact in the 250 km window": "Anterior — contato visitado anteriormente na janela de 250 km", + "PREVIOUS": "ANTERIOR", + "FOCUS": "FOCAR", + "Next — nearest unvisited contact in the 250 km window": "Próximo — contato não visitado mais próximo na janela de 250 km", + "NEXT": "PRÓX", + "Open-source mapped/observed context. Missing broadcasts, unloaded map areas, or unmapped sites are not evidence of absence.": "Contexto mapeado/observado de fontes abertas. Transmissões ausentes, áreas de mapa não carregadas ou locais não mapeados não são prova de ausência.", + "HDG {value}°": "HDG {value}°", + "BRG {value}°": "RMO {value}°", + "BRG —": "RMO —", + "CRS {value}°": "CRS {value}°", + "CURRENT VIEWPORT ONLY": "SÓ A VISTA ATUAL", + "WITHIN {km} KM": "EM ATÉ {km} KM", + "Flights": "Voos", + "Military flights": "Voos militares", + "AIS vessels": "Embarcações AIS", + "Mapped installations": "Instalações mapeadas", + "syncing {count} city feeds...": "sincronizando {count} feeds de cidades...", + "scanning nearby systems...": "buscando sistemas próximos...", + "Station {id}": "Estação {id}", + "Station": "Estação", + "🚲 {bikes} avail · {docks} docks · {capacity} cap": "🚲 {bikes} disp · {docks} docas · {capacity} cap", + "⚠️ Not installed": "⚠️ Não instalada", + "⚠️ Not renting": "⚠️ Sem aluguel", + "⚠️ Not returning": "⚠️ Sem devolução", + "HDG {value}° (ESTIMATED)": "HDG {value}° (ESTIMADO)", + "{count} CAMERAS STANDING BY · NO CAMERA SELECTED · CLICK A CAMERA TO ACTIVATE": "{count} CÂMERAS EM ESPERA · NENHUMA CÂMERA SELECIONADA · CLIQUE EM UMA CÂMERA PARA ATIVAR", + "No cameras available in catalog.": "Nenhuma câmera disponível no catálogo.", + "{city} CCTV": "CCTV {city}", + "FOV {value}°": "FOV {value}°", + "COVERAGE {value}km²": "COBERTURA {value}km²", + "OVERLAP {count} cams": "SOBREPOSIÇÃO {count} câm", + "ISOLATED VIEW": "VISTA ISOLADA", + "PROJ MONITOR": "PROJ MONITOR", + "PROJ OFF": "PROJ DESLIG.", + "VIEWSHED": "VIEWSHED", + "CAL {value}": "CAL {value}", + "SRC {value}": "FONTE {value}", + "{value} CONTEXT": "CONTEXTO {value}", + "Focus fire detection {title}, {details}": "Focar detecção de incêndio {title}, {details}", + "{value} conf": "{value} conf", + "{value} ago": "há {value}", + "sensor n/a": "sensor n/d", + "FIRE · {frp} MW": "INCÊNDIO · {frp} MW", + "NIGHT": "NOITE", + "▲ {frp} MW": "▲ {frp} MW", + "FIRE": "INCÊNDIO", + "FIRES": "INCÊNDIOS", + "max {value} MW": "máx {value} MW", + "new {value}": "novo {value}", + "just now": "agora mesmo", + "<1m ago": "há <1min", + "{count}m ago": "há {count}min", + "{count}h ago": "há {count}h", + "STALE · cached {age}": "DESATUALIZADO · em cache {age}", + "refreshing...": "atualizando...", + "loading...": "carregando...", + "KEY REQUIRED": "CHAVE NECESSÁRIA", + "LIVE · updated {age}": "AO VIVO · atualizado {age}", + "loading mapped installation context": "carregando contexto da instalação mapeada", + "MAPPED INSTALLATION": "INSTALAÇÃO MAPEADA", + "LAUNCH SITE · {site}": "LOCAL DE LANÇAMENTO · {site}", + "LAUNCH SITE": "LOCAL DE LANÇAMENTO", + "T−{time} · {mission}": "T−{time} · {mission}", + "LAUNCH STANDBY": "LANÇAMENTO EM ESPERA", + "LIFTOFF · {mission}": "DECOLAGEM · {mission}", + "ASCENT REPLAY · {mission}": "REPRISE DA SUBIDA · {mission}", + "ASCENT ESTIMATE · {mission}": "SUBIDA ESTIMADA · {mission}", + "STAGE RE-ENTRY / RECOVERY · {mission}": "REENTRADA / RECUPERAÇÃO DE ESTÁGIO · {mission}", + "ORBIT REPLAY · {mission}": "REPRISE DA ÓRBITA · {mission}", + "PAUSED · {title}": "PAUSADO · {title}", + "UNSPECIFIED": "NÃO ESPECIFICADO", + "+{count} additional payload records": "+{count} registros de carga útil adicionais", + "PAYLOAD DATA UNAVAILABLE": "DADOS DA CARGA ÚTIL INDISPONÍVEIS", + "{value} KM DOWNRANGE": "{value} KM DOWNRANGE", + "POSITION UNAVAILABLE": "POSIÇÃO INDISPONÍVEL", + "FLIGHT {count}": "VOO {count}", + "REUSED": "REUTILIZADO", + "NO STAGE RE-ENTRY / RECOVERY DATA": "SEM DADOS DE REENTRADA / RECUPERAÇÃO DE ESTÁGIO", + "{count} / 30D": "{count} / 30D", + "NO MISSIONS AVAILABLE IN THE CURRENT 30-DAY WINDOW": "NENHUMA MISSÃO DISPONÍVEL NA JANELA ATUAL DE 30 DIAS", + "DATE UNAVAILABLE": "DATA INDISPONÍVEL", + "UNSPECIFIED OPERATOR": "OPERADOR NÃO ESPECIFICADO", + "Select {mission}": "Selecionar {mission}", + "{value} KM": "{value} KM", + "{value} KM/S": "{value} KM/S", + "SELECTED SPACE MISSION": "MISSÃO ESPACIAL SELECIONADA", + "Show all missions": "Mostrar todas as missões", + "Deselect mission": "Desmarcar missão", + "MISSION": "MISSÃO", + "STATUS · ": "STATUS · ", + "LAUNCH SITE · ": "LOCAL DE LANÇAMENTO · ", + "LAUNCH TIME · ": "HORÁRIO DE LANÇAMENTO · ", + "ORBIT · ": "ÓRBITA · ", + "ASCENT PATH · ": "TRAJETÓRIA DE SUBIDA · ", + "CURRENT DISTANCE FROM EARTH · ": "DISTÂNCIA ATUAL DA TERRA · ", + "SATELLITE SPEED · ": "VELOCIDADE DO SATÉLITE · ", + "PAYLOAD": "CARGA ÚTIL", + "NAME": "NOME", + "TYPE": "TIPO", + "DESTINATION": "DESTINO", + "STAGE / RE-ENTRY / RECOVERY": "ESTÁGIO / REENTRADA / RECUPERAÇÃO", + "STAGE": "ESTÁGIO", + "STATUS": "STATUS", + "FINAL POSITION": "POSIÇÃO FINAL", + "REPLAY SPEED": "VELOCIDADE DA REPRISE", + "Replay speed multiplier": "Multiplicador de velocidade da reprise", + "REPLAY ASCENT": "REPRISE DA SUBIDA", + "Previous mission": "Missão anterior", + "PREV": "ANT", + "Next mission": "Próxima missão", + "SHOW ALL / DESELECT": "MOSTRAR TODAS / DESMARCAR", + "Pause replay": "Pausar reprise", + "Cancel replay": "Cancelar reprise", + "EST. DOWNRANGE": "DOWNRANGE EST.", + "PLANNED · ": "PLANEJADO · ", + "SUPPLIED TRAJECTORY POINTS": "PONTOS DE TRAJETÓRIA FORNECIDOS", + "RECONSTRUCTED ESTIMATE": "ESTIMATIVA RECONSTRUÍDA", + "Replay the estimated ascent with a following camera": "Reproduzir a subida estimada com uma câmera de acompanhamento", + "Resume replay": "Retomar reprise", + "T minus {seconds}": "T menos {seconds}", + "Preparing launch site": "Preparando o local de lançamento", + "Liftoff": "Decolagem", + "Ascent replay": "Reprise da subida", + "Orbit replay": "Reprise da órbita", + ", paused": ", pausado", + "Alt unknown": "Alt. desconhecida", + "Type unknown": "Tipo desconhecido", + "Reg unknown": "Matrícula desconhecida", + "Operator unknown": "Operador desconhecido", + "News": "Notícias", + "Talk": "Conversa", + "Weather / Emergency": "Clima / Emergência", + "Public Safety": "Segurança Pública", + "Aviation / Marine": "Aviação / Marítimo", + "Traffic / Transit": "Trânsito / Transporte", + "Music": "Música", + "Other": "Outras", + "radio|TALK": "CONVERSA", + "radio|SAFETY": "SEGURANÇA", + "radio|AIR / SEA": "AR / MAR", + "radio|TRANSIT": "TRANSPORTE", + "radio|MUSIC": "MÚSICA", + "Alternative": "Alternativo", + "Ambient": "Ambiente", + "Blues": "Blues", + "Classical": "Clássica", + "Country": "Country", + "Dance": "Dance", + "Electronic": "Eletrônica", + "Folk": "Folk", + "Funk": "Funk", + "Hip-Hop": "Hip-Hop", + "House": "House", + "Indie": "Indie", + "Jazz": "Jazz", + "Latin": "Latina", + "Metal": "Metal", + "Oldies": "Clássicos", + "Pop": "Pop", + "Punk": "Punk", + "R&B": "R&B", + "Reggae": "Reggae", + "Rock": "Rock", + "Soul": "Soul", + "Techno": "Techno", + "Trance": "Trance", + "World": "Mundial", + "Add the full Starlink broadband shell (thousands of extra points)": "Adicionar toda a malha de banda larga Starlink (milhares de pontos extras)", + "Loading the Starlink shell…": "Carregando a malha Starlink…", + "Starlink {detail} — click to retry": "Starlink {detail} — clique para tentar novamente", + "load failed": "falha ao carregar", + "Showing the full Starlink shell — click for the core catalog only": "Mostrando toda a malha Starlink — clique para ver só o catálogo principal", + "DENSE ···": "DENSO ···", + "DENSE ✕": "DENSO ✕", + "DENSE": "DENSO", + "Syncing flow · Roads: {source}": "Sincronizando fluxo · Vias: {source}", + "LIVE · Roads: {source} · Roads without flow hidden": "AO VIVO · Vias: {source} · Vias sem fluxo ocultas", + "LIVE · Roads: {source} · No flow roads in view": "AO VIVO · Vias: {source} · Nenhuma via com fluxo na vista", + "LIVE · Roads: {source} · Flow {percent}%": "AO VIVO · Vias: {source} · Fluxo {percent}%", + "SIMULATED · Roads: {source} · Flow {percent}%": "SIMULADO · Vias: {source} · Fluxo {percent}%", + "Syncing flow · Roads: OpenStreetMap · Flow: TomTom · Unmatched: simulated": "Sincronizando fluxo · Vias: OpenStreetMap · Fluxo: TomTom · Sem correspondência: simulado", + "LIVE · Roads: OpenStreetMap · Flow: TomTom · {percent}% cov · Unmatched: simulated": "AO VIVO · Vias: OpenStreetMap · Fluxo: TomTom · {percent}% cob · Sem correspondência: simulado", + "LIVE · Roads: OpenStreetMap · Flow: TomTom · {percent}% cov": "AO VIVO · Vias: OpenStreetMap · Fluxo: TomTom · {percent}% cob", + "SIMULATED · Roads: OpenStreetMap · Flow: TomTom (no matches)": "SIMULADO · Vias: OpenStreetMap · Fluxo: TomTom (sem correspondências)", + "SIMULATED — traffic service unreachable": "SIMULADO — serviço de trânsito inacessível", + "SIMULATED — add TomTom key for live": "SIMULADO — adicione a chave TomTom para dados ao vivo", + "AIS: {name}": "AIS: {name}", + "{type} SPD: {speed} HDG: {heading}": "{type} VEL: {speed} HDG: {heading}", + "VESSEL": "EMBARCAÇÃO", + "POS: LIVE": "POS: AO VIVO", + "POS: {time}Z": "POS: {time}Z", + "awaiting first AIS position…": "aguardando primeira posição AIS…", + "awaiting usable AIS positions…": "aguardando posições AIS utilizáveis…", + "awaiting first AIS message…": "aguardando primeira mensagem AIS…", + "Resume": "Retomar", + "Pause": "Pausar", + "Error: {message}": "Erro: {message}", + "Needs {envVars} — add it in Provider Settings": "Requer {envVars} — adicione em Configurações de Provedores", + "{label} is unavailable": "{label} indisponível", + "This map stack": "Esta pilha de mapa", + "{label} unavailable: {hint}": "{label} indisponível: {hint}", + "Visible map targets": "Alvos visíveis no mapa", + "Ready": "Pronto", + "Loaded: {scene} / {shot}": "Carregado: {scene} / {shot}", + "Cannot capture shot: camera not ready": "Não foi possível capturar o plano: câmera não está pronta", + "Captured: {scene} / {shot}": "Capturado: {scene} / {shot}", + "Select a shot first": "Selecione um plano primeiro", + "Updated: {scene} / {shot}": "Atualizado: {scene} / {shot}", + "Camera unavailable — exit cockpit first": "Câmera indisponível — saia da cabine primeiro", + "No shots to run": "Nenhum plano para executar", + "Project exported": "Projeto exportado", + "Could not exit {mode} — scene layers may be refused": "Não foi possível sair de {mode} — as camadas da cena podem ser recusadas", + "Running {index}/{total}: {scene} / {shot}": "Executando {index}/{total}: {scene} / {shot}", + "Scene run complete": "Execução da cena concluída", + "Global Flights Radar": "Radar Global de Voos", + "Orbital Watch": "Vigilância Orbital", + "Thermal Threat Board": "Painel de Ameaças Térmicas", + "City Overload": "Sobrecarga Urbana", + "Omniscience Pullback": "Recuo da Onisciência", + "Shot {n}": "Plano {n}", + "Density": "Densidade", + "Bloom": "Bloom", + "VISUAL PRESETS": "PREDEFINIÇÕES VISUAIS", + "LOCATION": "LOCAL", + "CONTACTS — nearest planes · vessels · sites": "CONTATOS — aviões · embarcações · locais mais próximos", + "SPACE MISSIONS — launches & orbital assets": "MISSÕES ESPACIAIS — lançamentos e ativos orbitais", + "LIVE SIGNALS": "SINAIS AO VIVO", + "Contacts could not complete the requested transition; try again": "Contatos não conseguiram concluir a transição solicitada; tente novamente", + "CCTV layer unavailable": "Camada de CCTV indisponível", + "Link copied!": "Link copiado!", + "Copy failed": "Falha ao copiar", + "CCTV calibration saved": "Calibração do CCTV salva", + "CCTV calibration reset": "Calibração do CCTV redefinida", + "ADJUST ON": "AJUSTE LIGADO", + "ADJUST": "AJUSTAR", + "UNKNOWN": "DESCONHECIDO", + "ERROR": "ERRO", + "SOURCE · UNKNOWN": "FONTE · DESCONHECIDA", + "FRAME · LOADING": "QUADRO · CARREGANDO", + "FRAME · UNAVAILABLE": "QUADRO · INDISPONÍVEL", + "CALIBRATED": "CALIBRADA", + "CURATED": "CURADA", + "RAW PRIOR": "ESTIMATIVA BRUTA", + "CCTV ON": "CCTV LIGADO", + "CCTV OFF": "CCTV DESLIG.", + "VIEWSHED ON": "VIEWSHED LIGADO", + "COVERAGE ON": "COBERTURA LIGADA", + "COVERAGE OFF": "COBERTURA DESLIG.", + "AUTO HOP ON": "AUTO SALTO LIGADO", + "AUTO HOP OFF": "AUTO SALTO DESLIG.", + "PROJECTION ON": "PROJEÇÃO LIGADA", + "PROJECTION OFF": "PROJEÇÃO DESLIG.", + "CAL · EDITED (UNSAVED)": "CAL · EDITADA (NÃO SALVA)", + "CAL · {badge}": "CAL · {badge}", + "MONITOR": "MONITOR", + "OFF": "DESLIGADO", + "{city} · HDG {heading} · FOV {fov} · RANGE {range}m · {projection}{calBadge} · {provider}{status}": "{city} · HDG {heading} · FOV {fov} · ALCANCE {range}m · {projection}{calBadge} · {provider}{status}", + "{count} cameras loaded · click a camera to activate": { + "one": "{count} câmera carregada · clique em uma câmera para ativar", + "many": "{count} câmeras carregadas · clique em uma câmera para ativar", + "other": "{count} câmeras carregadas · clique em uma câmera para ativar" + }, + "{count} cameras loaded · enable CCTV to activate": { + "one": "{count} câmera carregada · ative o CCTV para usar", + "many": "{count} câmeras carregadas · ative o CCTV para usar", + "other": "{count} câmeras carregadas · ative o CCTV para usar" + }, + "Enable CCTV to load camera intersections": "Ative o CCTV para carregar interseções de câmeras", + "Enable CCTV to start camera-linked intelligence summaries.": "Ative o CCTV para iniciar resumos de inteligência vinculados às câmeras.", + "No summary available.": "Nenhum resumo disponível.", + "loading frames": "carregando quadros", + "camera grid ready": "grade de câmeras pronta", + "Clearing selected data layers": "Limpando camadas de dados selecionadas", + "Clear selected data layers": "Limpar camadas de dados selecionadas", + "CONDITIONS UNKNOWN": "CONDIÇÕES DESCONHECIDAS", + "CLEAR": "CÉU LIMPO", + "PARTLY CLOUDY": "PARCIALMENTE NUBLADO", + "OVERCAST": "ENCOBERTO", + "FOG": "NEBLINA", + "DRIZZLE": "GAROA", + "RAIN": "CHUVA", + "RAIN SHOWERS": "PANCADAS DE CHUVA", + "SNOW SHOWERS": "PANCADAS DE NEVE", + "THUNDERSTORM": "TROVOADA", + "MIXED CONDITIONS": "CONDIÇÕES MISTAS", + "CYCLE ON": "CICLO LIGADO", + "CYCLE OFF": "CICLO DESLIGADO", + "Stop automatic page cycling. Previous, Next, and the SIG/NEWS/LOCAL tabs stay available.": "Parar a rotação automática de páginas. Anterior, Próxima e as abas SIG/NOTÍCIAS/LOCAL continuam disponíveis.", + "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.": "Alterna as páginas do briefing automaticamente a cada 9 segundos (Sinais → Notícias → Local). Pausa enquanto você passa o mouse ou foca o painel. Os dados de sinais ao vivo continuam atualizando de qualquer forma.", + "ACQUIRING REGIONAL NEWS": "OBTENDO NOTÍCIAS REGIONAIS", + "REGIONAL NEWS UNAVAILABLE": "NOTÍCIAS REGIONAIS INDISPONÍVEIS", + "RESOLVING REGION": "IDENTIFICANDO REGIÃO", + "REGION UNAVAILABLE": "REGIÃO INDISPONÍVEL", + "NO RECENT LOCATION MATCHES": "NENHUMA CORRESPONDÊNCIA RECENTE COM O LOCAL", + "{domain} · {age}": "{domain} · {age}", + "CLOUD {pct}%": "NUVENS {pct}%", + "CLOUD UNKNOWN": "NUVENS DESCONHECIDAS", + "{source} · LOCATION QUERY": "{source} · CONSULTA POR LOCAL", + "REGIONAL NEWS": "NOTÍCIAS REGIONAIS", + "CONTEXT STANDBY": "CONTEXTO EM ESPERA", + "ENABLE GLOBAL CONTEXT FOR PROXIMITY PINGS": "ATIVE O CONTEXTO GLOBAL PARA PINGS DE PROXIMIDADE", + "CONTACT LOST · LAST KNOWN READOUT · NOT AN ALL-CLEAR": "CONTATO PERDIDO · ÚLTIMA LEITURA CONHECIDA · NÃO GARANTE SEGURANÇA", + "CONTACT LOST · {subject}": "CONTATO PERDIDO · {subject}", + "SUBJECT LEFT ITS FEED · READOUT HOLDING LAST KNOWN": "ALVO SAIU DO SEU FEED · LEITURA MANTIDA NA ÚLTIMA POSIÇÃO CONHECIDA", + "{cohort} · {contact}": "{cohort} · {contact}", + "NO AVAILABLE EXAMPLE": "NENHUM EXEMPLO DISPONÍVEL", + "{cohort}, Unavailable": "{cohort}, indisponível", + "AHEAD": "À FRENTE", + "{side} {angle}": "{side} {angle}", + "L": "E", + "R": "D", + "{count} INPUTS UNKNOWN · NOT AN ALL-CLEAR": { + "one": "{count} ENTRADA DESCONHECIDA · NÃO GARANTE SEGURANÇA", + "many": "{count} ENTRADAS DESCONHECIDAS · NÃO GARANTE SEGURANÇA", + "other": "{count} ENTRADAS DESCONHECIDAS · NÃO GARANTE SEGURANÇA" + }, + "AVAILABLE INPUTS CURRENT · NOT AN ALL-CLEAR": "ENTRADAS DISPONÍVEIS ATUAIS · NÃO GARANTE SEGURANÇA", + "AIRCRAFT": "AERONAVE", + "ACQUIRING SURFACE": "ADQUIRINDO SUPERFÍCIE", + "SURFACE FALLBACK": "SUPERFÍCIE ALTERNATIVA", + "STALE FEED": "FEED DESATUALIZADO", + "LIVE TRACK": "RASTRO AO VIVO", + "COMMERCIAL": "COMERCIAL", + "{aircraftClass} · {feedState} · COURSE ALIGNED": "{aircraftClass} · {feedState} · CURSO ALINHADO", + "ARROW · ESTIMATED DIRECTION": "SETA · DIREÇÃO ESTIMADA", + "ROUTE DATA UNAVAILABLE": "DADOS DE ROTA INDISPONÍVEIS", + "DEST {bearing}": "DEST {bearing}", + "Disable cockpit weather effects": "Desativar efeitos de clima na cabine", + "Enable cockpit weather effects": "Ativar efeitos de clima na cabine", + "ON": "LIGADO", + "Normal": "Normal", + "Night vision": "Visão noturna", + "Thermal": "Térmico", + "Anime": "Anime", + "Noir": "Noir", + "Snow": "Neve", + "Current cockpit vision style: {style}. Activate for next style.": "Estilo de visão da cabine atual: {style}. Ative para o próximo estilo.", + "Current style: {style} — click for next": "Estilo atual: {style} — clique para o próximo", + "Collapse Contact panel": "Recolher painel de contato", + "Expand Contact panel": "Expandir painel de contato", + "Collapse contact panel": "Recolher painel de contato", + "Expand contact panel": "Expandir painel de contato", + "Collapse cockpit briefing panel": "Recolher painel de briefing da cabine", + "Expand cockpit briefing panel": "Expandir painel de briefing da cabine", + "Collapse briefing panel": "Recolher painel de briefing", + "Expand briefing panel": "Expandir painel de briefing", + "OBSERVED / MAPPED PINGS": "PINGS OBSERVADOS / MAPEADOS", + "SOURCE-BACKED EVENTS · NO SYNTHETIC NEWS": "EVENTOS COM FONTE · SEM NOTÍCIAS SINTÉTICAS", + "LATEST LOCATION-MATCHED REPORTING": "ÚLTIMAS REPORTAGENS DA LOCALIZAÇÃO", + "LOCAL INFO": "INFO LOCAL", + "PLACE / CONDITIONS / POSITION": "LUGAR / CONDIÇÕES / POSIÇÃO", + "TIME UNKNOWN": "HORA DESCONHECIDA", + "{count}M AGO": "HÁ {count}MIN", + "{count}H AGO": "HÁ {count}H", + "{count}D AGO": "HÁ {count}D", + "DIR UNKNOWN": "DIR DESCONHECIDA", + "Select flight {title}": "Selecionar voo {title}", + "{aircraftClass} · CURRENT": "{aircraftClass} · ATUAL", + "MILITARY FLIGHT": "VOO MILITAR", + "COMMERCIAL FLIGHT": "VOO COMERCIAL", + "{aircraftClass} · {distance}": "{aircraftClass} · {distance}", + "DISTANCE UNKNOWN": "DISTÂNCIA DESCONHECIDA", + "{count} INPUTS UNKNOWN": { + "one": "{count} ENTRADA DESCONHECIDA", + "many": "{count} ENTRADAS DESCONHECIDAS", + "other": "{count} ENTRADAS DESCONHECIDAS" + }, + "SOURCE STATUS UNAVAILABLE": "STATUS DA FONTE INDISPONÍVEL", + "Restore real aircraft": "Restaurar a aeronave real", + "Reclassify as TR-3B": "Reclassificar como TR-3B", + "TRACK ACQUIRED": "RASTRO ADQUIRIDO", + "{label} · COURSE {heading}°": "{label} · CURSO {heading}°", + "Context could not restore every layer; try again": "O contexto não conseguiu restaurar todas as camadas; tente novamente", + "No selected data layers": "Nenhuma camada de dados selecionada", + "{count} data layers could not be cleared": { + "one": "{count} camada de dados não pôde ser limpa", + "many": "{count} camadas de dados não puderam ser limpas", + "other": "{count} camadas de dados não puderam ser limpas" + }, + "Cleared {count} data layers": { + "one": "{count} camada de dados limpa", + "many": "{count} camadas de dados limpas", + "other": "{count} camadas de dados limpas" + }, + "Selected data layers could not be cleared": "Não foi possível limpar as camadas de dados selecionadas", + "Space Missions could not complete the requested transition; try again": "Missões espaciais não conseguiram concluir a transição solicitada; tente novamente", + "Nearby installations refreshed": "Instalações próximas atualizadas", + "Nearby installations could not be refreshed; try again": "Não foi possível atualizar as instalações próximas; tente novamente", + "Space Missions cancellation could not restore the previous layer state": "O cancelamento de Missões espaciais não conseguiram restaurar o estado anterior das camadas", + "That layer is unavailable in the current Context mode": "Essa camada não está disponível no modo de contexto atual", + "{layerId} could not {action} cleanly": "Não foi possível {action} {layerId} corretamente", + "start": "iniciar", + "stop": "parar", + "{mode} could not start because another layer did not stop cleanly": "Não foi possível iniciar {mode} porque outra camada não parou corretamente", + "Space Missions": "Missões espaciais", + "Context": "Contexto", + "Live Flights": "Voos ao Vivo", + "Military Flights": "Voos Militares", + "Earthquakes (24h)": "Terremotos (24h)", + "Satellites": "Satélites", + "Space Missions (30d)": "Missões Espaciais (30d)", + "Street Traffic": "Trânsito Urbano", + "CCTV": "CCTV", + "Radio": "Rádio", + "Bikeshare": "Bicicletas Compartilhadas", + "Live AIS Vessels": "Embarcações AIS ao Vivo", + "Mapped Installations": "Instalações Mapeadas", + "Global Context": "Contexto Global", + "Datacenters": "Data Centers", + "Dams": "Barragens", + "Submarine Cables": "Cabos Submarinos", + "FIRMS Active Fires": "Incêndios Ativos FIRMS", + "ENABLING": "ATIVANDO", + "DISABLING": "DESATIVANDO", + "{state} · {source}": "{state} · {source}", + "UNCERTAIN · {source} · lifecycle state requires reconciliation": "INCERTO · {source} · estado do ciclo de vida requer reconciliação", + "{state} · {source} · {detail} · retry {seconds}s": "{state} · {source} · {detail} · nova tentativa em {seconds}s", + "{state} · {source} · {detail}": "{state} · {source} · {detail}", + "never": "nunca", + "{source} · {loadingLabel}": "{source} · {loadingLabel}", + "{accepted} of {raw} records accepted": "{accepted} de {raw} registros aceitos", + "incomplete snapshot": "snapshot incompleto", + "{state} · {source} · {detail} · {ago}": "{state} · {source} · {detail} · {ago}", + "{state} · {source} · {ago} · retrying in {seconds}s": "{state} · {source} · {ago} · nova tentativa em {seconds}s", + "{state} · {source} · {ago}": "{state} · {source} · {ago}", + "{source} · {ago}": "{source} · {ago}", + "UNCERTAIN": "INCERTO", + "{name}: {state}": "{name}: {state}", + "{count}s ago": "há {count}s", + "CONNECTING": "CONECTANDO", + "📍 Location: --": "📍 Local: --", + "Landmark: --": "Ponto de referência: --", + "Searched location": "Local pesquisado", + "ORBIT": "ÓRBITA", + "Location not found": "Local não encontrado", + "Search failed": "Falha na busca", + "Fly to a POI first": "Voe até um ponto de interesse primeiro", + "Reset to full globe view": "Voltar à vista do globo completo", + "Reset cockpit to full globe view": "Redefinir a cabine para a vista do globo completo", + "Resetting to full globe view": "Voltando à vista do globo completo", + "Resetting cockpit to full globe view": "Redefinindo a cabine para a vista do globo completo", + "MAP": "MAPA", + "panel": "painel", + "Expand {name}": "Expandir {name}", + "Collapse {name}": "Recolher {name}", + "Expand Radio": "Expandir rádio", + "Collapse Radio": "Recolher rádio", + "Expand Radio section": "Expandir seção de rádio", + "Collapse Radio section": "Recolher seção de rádio", + "Panel layout updated — positions reset to new defaults": "Layout dos painéis atualizado — posições redefinidas para os novos padrões", + "Collapse Cockpit display options": "Recolher opções de exibição da cabine", + "Expand Cockpit display options": "Expandir opções de exibição da cabine", + "Collapse Cockpit Radio controls": "Recolher controles de rádio da cabine", + "Expand Cockpit Radio controls": "Expandir controles de rádio da cabine", + "NO STATIONS": "SEM ESTAÇÕES", + "NO STATION AVAILABLE": "NENHUMA ESTAÇÃO DISPONÍVEL", + "{name}, station {index} of {total}": "{name}, estação {index} de {total}", + "No station available": "Nenhuma estação disponível", + "OFF AIR": "FORA DO AR", + "STATION UNAVAILABLE": "ESTAÇÃO INDISPONÍVEL", + "Radio could not {action} cleanly": "Não foi possível {action} o rádio corretamente", + "Close compact Radio controls": "Fechar controles compactos do rádio", + "Open compact Radio controls": "Abrir controles compactos do rádio", + "SYNC": "SINC", + "RECONCILE": "RECONCILIAR", + "DISABLE": "DESATIVAR", + "ENABLE": "ATIVAR", + "Reconcile Radio — lifecycle uncertain": "Reconciliar rádio — ciclo de vida incerto", + "Disable Radio": "Desativar rádio", + "Enable Radio": "Ativar rádio", + "DIRECTORY BAND": "BANDA DO DIRETÓRIO", + "{category} BAND": "BANDA {category}", + "NO STATION SELECTED": "NENHUMA ESTAÇÃO SELECIONADA", + "Directory metadata only": "Somente metadados do diretório", + "Loading station directory…": "Carregando diretório de estações…", + "Choose a globe marker or use next.": "Escolha um marcador no globo ou use próxima.", + "TAGS · {tags}": "TAGS · {tags}", + "Play": "Reproduzir", + "PLAY": "PLAY", + "selected": "selecionada", + "nearest": "mais próxima", + "{action} {target} radio station": "{action} estação de rádio {target}", + "RADIO STATE UNCERTAIN": "ESTADO DO RÁDIO INCERTO", + "SYNCING DIRECTORY": "SINCRONIZANDO DIRETÓRIO", + "RADIO READY": "RÁDIO PRONTO", + "SYNCING": "SINCRONIZANDO", + "READY": "PRONTO", + "station": "estação", + " · stale/degraded directory": " · diretório desatualizado/degradado", + " · degraded directory": " · diretório degradado", + " · stale directory": " · diretório desatualizado", + " · outside current filter": " · fora do filtro atual", + "Ready — playback starts only from your action": "Pronto — a reprodução só começa por ação sua", + "Radio off": "Rádio desligado", + "Connecting directly to broadcaster…": "Conectando direto à emissora…", + "Buffering broadcaster stream…": "Armazenando em buffer o stream da emissora…", + "Playing {station}": "Reproduzindo {station}", + "Paused {station}": "Pausado: {station}", + "Broadcaster stream unavailable": "Stream da emissora indisponível", + " · muted during voice interaction": " · silenciado durante a interação por voz", + " · restoring volume after voice": " · restaurando o volume após a voz", + " · static indicates no broadcaster audio": " · chiado indica ausência de áudio da emissora", + " · tuning static until broadcaster starts": " · chiado de sintonia até a emissora iniciar", + "Station unavailable after directory refresh — choose another channel": "Estação indisponível após atualizar o diretório — escolha outro canal", + "Radio is enabling…": "O rádio está sendo ativado…", + "Radio is disabling…": "O rádio está sendo desativado…", + "Radio lifecycle is uncertain — use Enable or Disable to reconcile": "O ciclo de vida do rádio é incerto — use Ativar ou Desativar para reconciliar", + "Scene action failed": "A ação da cena falhou", + "Delete shot \"{shot}\"?": "Excluir o plano \"{shot}\"?", + "SPARSE": "ESPARSA", + "BALANCED": "EQUILIBRADA", + "DEL": "EXCL", + "entity": "entidade", + "Shared {subject} follow expired": "O acompanhamento compartilhado de {subject} expirou", + "Shared {subject} could not be restored — feed unavailable": "Não foi possível restaurar o compartilhamento de {subject} — feed indisponível", + "Shared {subject} is unavailable": "O compartilhamento de {subject} está indisponível", + "ACQUIRING": "ADQUIRINDO", + "SHARED {subject}": "COMPARTILHADO: {subject}", + "LOADING LIVE DATA": "CARREGANDO DADOS AO VIVO", + "LOAD COMPLETE": "CARGA CONCLUÍDA", + "LOAD CANCELLED": "CARGA CANCELADA", + "LOAD FAILED": "FALHA NA CARGA", + "LIVE DATA OFF": "DADOS AO VIVO DESLIGADOS", + "MAPPED SITES LOADED": "LOCAIS MAPEADOS CARREGADOS", + "RETRYING MAPPED SITES": "REPETINDO BUSCA DE LOCAIS MAPEADOS", + "FETCHING MAPPED SITES": "BUSCANDO LOCAIS MAPEADOS", + "TURNING OFF LIVE DATA": "DESLIGANDO DADOS AO VIVO", + "REFRESHING LIVE DATA": "ATUALIZANDO DADOS AO VIVO", + "syncing road network": "sincronizando malha viária", + "retry pending": "nova tentativa pendente", + "retrying in {seconds}s": "nova tentativa em {seconds}s", + "Celestial ring — reveal the full globe": "Anel celeste — revelar o globo inteiro", + "Celestial ring — available in Normal style": "Anel celeste — disponível no estilo Normal", + "Detection overlay: {mode}": "Sobreposição de detecção: {mode}", + "Detection overlay: off": "Sobreposição de detecção: desligada", + "DETECT": "DETECÇÃO", + "voice|LISTENING": "OUVINDO", + "voice|EXECUTING": "EXECUTANDO", + "AI AGENT": "AGENTE DE IA", + "Voice model tier — applies next session": "Nível do modelo de voz — vale na próxima sessão", + "Estimated session cost": "Custo estimado da sessão", + "Voice control — activate to toggle voice; hold Space to speak": "Controle por voz — ative para alternar a voz; segure Espaço para falar", + "VOICE STANDBY": "VOZ EM ESPERA", + "VOICE CONTROL": "CONTROLE POR VOZ", + "Hold Space to speak · tap Space to activate focused controls": "Segure Espaço para falar · toque em Espaço para ativar controles em foco", + "VOICE SYSTEM ERROR": "ERRO NO SISTEMA DE VOZ", + "DISMISS": "DISPENSAR", + "Check microphone permission and network access, then try again.": "Verifique a permissão do microfone e o acesso à rede, e tente novamente.", + "Release Space to send": "Solte Espaço para enviar", + "Hold Space to talk": "Segure Espaço para falar", + "Requesting microphone": "Solicitando microfone", + "Ask or command": "Pergunte ou comande", + "Running command": "Executando comando", + "Voice off": "Voz desligada", + "WebRTC microphone support unavailable": "Suporte a microfone WebRTC indisponível", + "VOICE UNAVAILABLE": "VOZ INDISPONÍVEL", + "VOICE ACTIVE": "VOZ ATIVA", + "Voice session could not be started.": "Não foi possível iniciar a sessão de voz.", + "Next session: {pendingId} — this session stays on {modelId}": "Próxima sessão: {pendingId} — esta sessão continua em {modelId}", + "Voice model: {pendingId} — click to switch to {target}; applies next session": "Modelo de voz: {pendingId} — clique para mudar para {target}; vale na próxima sessão", + "Estimated session cost on {modelId} — {responses} response(s). Warns at {warn}, ends the session at {cap}.": "Custo estimado da sessão em {modelId} — {responses} resposta(s). Alerta em {warn}, encerra a sessão em {cap}.", + "{tier} applies next session": "{tier} vale na próxima sessão", + "Session ended — cost cap {cost}": "Sessão encerrada — limite de custo {cost}", + "Radio did not start": "O rádio não iniciou", + "Aircraft cockpit view": "Vista da cabine da aeronave", + "LEVEL": "NÍVEL", + "Estimated destination direction": "Direção estimada do destino", + "DEST ---°": "DEST ---°", + "OPTICAL PLANE · 01": "PLANO ÓPTICO · 01", + "VISOR LOCK · ACTIVE": "TRAVA DO VISOR · ATIVA", + "GROUND SPEED · KTS": "VELOC. SOLO · KTS", + "ALTITUDE · FT": "ALTITUDE · FT", + "FIRST PERSON": "PRIMEIRA PESSOA", + "LIVE TRACK · COURSE ALIGNED": "RASTRO AO VIVO · CURSO ALINHADO", + "Cockpit vision style": "Estilo de visão da cabine", + "Previous cockpit vision style": "Estilo de visão da cabine anterior", + "Previous vision style": "Estilo de visão anterior", + "Current cockpit vision style: NORMAL. Activate for next style.": "Estilo de visão da cabine atual: NORMAL. Ative para o próximo estilo.", + "Current style: NORMAL — click for next": "Estilo atual: NORMAL — clique para o próximo", + "CURRENT": "ATUAL", + "Next cockpit vision style": "Próximo estilo de visão da cabine", + "Next vision style": "Próximo estilo de visão", + "Current aircraft heading": "Rumo atual da aeronave", + "GROUND SPEED": "VELOC. SOLO", + "ALTITUDE": "ALTITUDE", + "Contact cockpit summary": "Resumo do contato na cabine", + "CONTACT": "CONTATO", + "CONTACTS · 250 KM": "CONTATOS · 250 KM", + "Contact navigation": "Navegação de contatos", + "CONTEXT ONLY": "SÓ CONTEXTO", + "Nearby cohort counts": "Contagem de grupos próximos", + "NEAREST OBSERVED / MAPPED": "MAIS PRÓXIMO OBSERVADO / MAPEADO", + "AVAILABLE INPUTS ONLY · NOT AN ALL-CLEAR": "SÓ ENTRADAS DISPONÍVEIS · NÃO GARANTE SEGURANÇA", + "Cockpit briefing carousel": "Carrossel de briefing da cabine", + "Estimated flight plan": "Plano de voo estimado", + "ESTIMATED FLIGHT PLAN": "PLANO DE VOO ESTIMADO", + "FROM": "DE", + "TO": "PARA", + "Cockpit briefing controls": "Controles do briefing da cabine", + "Previous briefing page": "Página anterior do briefing", + "Next briefing page": "Próxima página do briefing", + "Live signals": "Sinais ao vivo", + "Latest regional news": "Últimas notícias regionais", + "Location-based information": "Informações baseadas na localização", + "TEMP": "TEMP", + "WIND": "VENTO", + "SKY": "CÉU", + "PRECIP": "PRECIP", + "Show Live Signals": "Mostrar sinais ao vivo", + "NEWS": "NOTÍCIAS", + "Show Regional News": "Mostrar notícias regionais", + "Show Local Info": "Mostrar informações locais", + "Cockpit display and Radio controls": "Controles de exibição e rádio da cabine", + "DISPLAY": "EXIBIÇÃO", + "Cockpit display options": "Opções de exibição da cabine", + "RADIO": "RÁDIO", + "Cockpit compact Radio controls": "Controles compactos de rádio da cabine", + "Previous filtered radio station": "Estação de rádio filtrada anterior", + "Play selected radio station": "Reproduzir a estação de rádio selecionada", + "Next filtered radio station": "Próxima estação de rádio filtrada", + "VOLUME": "VOLUME", + "Cockpit Radio volume": "Volume do rádio da cabine", + "View switcher": "Alternador de vista", + "Exit cockpit and return to full globe view": "Sair da cabine e voltar à vista do globo completo", + "RESET": "REDEFINIR", + "Exit cockpit view": "Sair da vista da cabine", + "EXIT COCKPIT": "SAIR DA CABINE", + "Navigation, voice, and visual preset controls": "Controles de navegação, voz e predefinições visuais", + "Expand Visual Presets": "Expandir predefinições visuais", + "Pin visual presets": "Fixar predefinições visuais", + "Keep visual presets open": "Manter predefinições visuais abertas", + "Show the globe without a visual filter.": "Mostrar o globo sem filtro visual.", + "Emulate a green phosphor CRT with scanlines and screen curvature.": "Emular um CRT de fósforo verde com linhas de varredura e curvatura de tela.", + "Simulate night-vision goggles with green intensification and a tube vignette.": "Simular óculos de visão noturna com intensificação verde e vinheta de tubo.", + "Simulate FLIR-style thermal contrast. Turn up Ironbow for color.": "Simular contraste térmico estilo FLIR. Aumente o Ironbow para ter cor.", + "Apply bright cel-shaded color and illustrated outlines.": "Aplicar cores vivas em cel shading e contornos ilustrados.", + "Apply high-contrast monochrome film-noir grading.": "Aplicar gradação monocromática de filme noir com alto contraste.", + "Add a cold, snowy whiteout treatment to the scene.": "Adicionar à cena um efeito frio de nevasca branca.", + "MAP SOURCE": "FONTE DO MAPA", + "Map source": "Fonte do mapa", + "Style": "Estilo", + "Expand LOCATION": "Expandir LOCAL", + "Collapse panel": "Recolher painel", + "Pin location tray": "Fixar bandeja de locais", + "Keep location tray open": "Manter bandeja de locais aberta", + "Search any location": "Buscar qualquer local", + "Search location by name or coordinates": "Buscar local por nome ou coordenadas", + "Search any location...": "Buscar qualquer local...", + "WEATHER": "CLIMA", + "CONTEXT": "CONTEXTO", + "Compact Radio controls": "Controles compactos do rádio", + "Open detailed Radio controls": "Abrir controles detalhados do rádio", + "Previous station": "Estação anterior", + "Next station": "Próxima estação", + "Compact Radio volume": "Volume do rádio compacto", + "Expand panel": "Expandir painel", + "Context mode": "Modo de contexto", + "CONTACTS": "CONTATOS", + "Cycles the nearest contacts of whatever type you select — planes, vessels, installations. Satellites track independently.": "Percorre os contatos mais próximos do tipo que você selecionar — aviões, embarcações, instalações. Os satélites são rastreados de forma independente.", + "SPACE MISSIONS": "MISSÕES ESPACIAIS", + "SELECT CONTEXT": "SELECIONE O CONTEXTO", + "Contact Context actions": "Ações de contexto do contato", + "COCKPIT": "CABINE", + "SEARCH NEARBY SITES": "BUSCAR LOCAIS PRÓXIMOS", + "Reclassify tracked contact as TR-3B": "Reclassificar o contato rastreado como TR-3B", + "CONTACTS CONTEXT OFF": "CONTEXTO DE CONTATOS DESLIGADO", + "SELECT CONTACTS TO LOAD OBSERVED / MAPPED PROXIMITY": "SELECIONE CONTATOS PARA CARREGAR PROXIMIDADE OBSERVADA / MAPEADA", + "Available Space Missions": "Missões espaciais disponíveis", + "AVAILABLE MISSIONS": "MISSÕES DISPONÍVEIS", + "SELECT A MISSION TO INSPECT": "SELECIONE UMA MISSÃO PARA INSPECIONAR", + "LOADING 30-DAY MISSION INDEX": "CARREGANDO ÍNDICE DE MISSÕES DE 30 DIAS", + "TAB PREVIEWS · ENTER / SPACE SELECTS": "TAB PRÉVIA · ENTER / ESPAÇO SELECIONA", + "Internet radio and local SDR": "Rádio pela internet e SDR local", + "STATION TAG": "TAG DA ESTAÇÃO", + "Filter stations by station tag": "Filtrar estações por tag", + "All": "Todas", + "Enable Radio, then choose a globe marker or use next.": "Ative o rádio e escolha um marcador no globo ou use próxima.", + "DRAG TO TUNE": "ARRASTE PARA SINTONIZAR", + "ALL · DRAG THE NEEDLE": "TODAS · ARRASTE A AGULHA", + "SNAPS TO AVAILABLE STATIONS": "AJUSTA ÀS ESTAÇÕES DISPONÍVEIS", + "Radio playback": "Reprodução do rádio", + "Previous filtered station": "Estação filtrada anterior", + "Play selected station": "Reproduzir a estação selecionada", + "Next filtered station": "Próxima estação filtrada", + "STOP": "PARAR", + "Stop radio playback": "Parar a reprodução do rádio", + "Radio volume": "Volume do rádio", + "STATION SITE": "SITE DA ESTAÇÃO", + "Audio connects directly to the broadcaster after you press play. Your IP is visible to that broadcaster.": "O áudio conecta direto à emissora depois que você aperta play. Seu IP fica visível para essa emissora.", + "Intelligence HUD (H)": "HUD de inteligência (H)", + "Layout": "Layout", + "HUD layout": "Layout do HUD", + "Tactical": "Tático", + "Operator": "Operador", + "Minimal": "Mínimo", + "Detection Overlay (D)": "Sobreposição de detecção (D)", + "Detection overlay": "Sobreposição de detecção", + "Detection label density": "Densidade dos rótulos de detecção", + "Allocation": "Alocação", + "Detection label allocation": "Alocação dos rótulos de detecção", + "Elastic": "Elástica", + "Weighted": "Ponderada", + "Fade": "Esmaecer", + "Detection fade distance": "Distância de esmaecimento da detecção", + "World-overlay fade distance outside the keyhole as a percentage of its radius": "Distância de esmaecimento da sobreposição no mundo fora do visor, como porcentagem do seu raio", + "Outside": "Fora", + "Detection opacity outside the keyhole": "Opacidade da detecção fora do visor", + "World-overlay label and card opacity beyond the fade distance": "Opacidade de rótulos e cartões da sobreposição além da distância de esmaecimento", + "PARAMETERS": "PARÂMETROS", + "3D aircraft — flat icons zoomed out, 3D models up close": "Aeronaves 3D — ícones planos de longe, modelos 3D de perto", + "Models": "Modelos", + "3D model coverage": "Cobertura de modelos 3D", + "Proximity": "Proximidade", + "Scope — the circular viewport mask": "Mira — a máscara circular da janela de visualização", + "Scope": "Mira", + "Feather": "Suavizar", + "Scope edge feather": "Suavização da borda da mira", + "Scope edge feather as a percentage of the keyhole radius": "Suavização da borda da mira, como porcentagem do raio do visor", + "Celestial": "Celeste", + "Hide UI chrome": "Ocultar a interface", + "Clean UI": "Interface limpa", + "Bloom / Glow": "Bloom / Brilho", + "Bloom intensity": "Intensidade do bloom", + "Sharpening": "Nitidez", + "Sharpen": "Nitidez", + "Sharpen intensity": "Intensidade da nitidez", + "EXIT CLEAN VIEW": "SAIR DA VISTA LIMPA", + "Return UI controls": "Restaurar controles da interface", + "Initializing photorealistic world...": "Inicializando o mundo fotorrealista...", + "DATA LAYERS": "CAMADAS DE DADOS", + "NEAREST": "MAIS PRÓX.", + "CCTV camera": "Câmera de CCTV", + "CALIBRATION": "CALIBRAÇÃO", + "Drag the camera in the world: rings rotate, arrows move, handles set range/FOV": "Arraste a câmera no mundo: anéis giram, setas movem, alças definem alcance/FOV", + "Camera pose — click a value to type": "Pose da câmera — clique em um valor para digitar", + "Heading (compass °) — click to type": "Rumo (bússola °) — clique para digitar", + "Pitch (° up/down) — click to type": "Inclinação (° para cima/baixo) — clique para digitar", + "Horizontal FOV (°) — click to type": "FOV horizontal (°) — clique para digitar", + "Range / monitor-plane distance (m) — click to type": "Alcance / distância do plano do monitor (m) — clique para digitar", + "Mount height above ground (m) — click to type": "Altura de instalação acima do solo (m) — clique para digitar", + "North offset from catalog position (m) — click to type": "Deslocamento norte da posição do catálogo (m) — clique para digitar", + "East offset from catalog position (m) — click to type": "Deslocamento leste da posição do catálogo (m) — clique para digitar", + "SAVE CAL": "SALVAR CAL", + "RESET CAL": "REDEFINIR CAL", + "SCENE SUMMARY": "RESUMO DA CENA", + "SCENES": "CENAS", + "Scene recipe": "Receita de cena", + "NEW": "NOVA", + "CAPTURE SHOT": "CAPTURAR PLANO", + "UPDATE SHOT": "ATUALIZAR PLANO", + "START": "INICIAR", + "EXPORT PRESETS": "EXPORTAR PREDEFINIÇÕES", + "IMPORT": "IMPORTAR", + "RUN LOG": "REGISTRO", + "POWER UP": "ATIVAR", + "GROUND STATION · PROVIDER SETTINGS": "ESTAÇÃO TERRESTRE · CONFIGURAÇÕES DE PROVEDORES", + "Close key setup": "Fechar configuração de chaves", + "Power up the globe": "Ative o globo", + "The globe already flies keyless. Every key below switches on another real feed — paste one and it's saved into this app's local configuration, then the server restarts itself. Server-side keys stay on this machine; Google Maps and Cesium ion run in the browser and must be provider-restricted. Keys you configured elsewhere are shown but never touched.": "O globo já voa sem chaves. Cada chave abaixo ativa mais uma fonte real — cole uma e ela será salva na configuração local deste app, e então o servidor reinicia sozinho. As chaves do servidor ficam nesta máquina; Google Maps e Cesium ion rodam no navegador e devem ser restritas ao provedor. Chaves configuradas em outro lugar são exibidas, mas nunca alteradas.", + "SAVE KEYS": "SALVAR CHAVES", + "ESC to close": "ESC para fechar", + "The Google Maps key buys the photorealistic planet — everything else stacks on top.": "A chave do Google Maps libera o planeta fotorrealista — todo o resto se soma a ela.", + "NO PLACE LEFT BEHIND": "NENHUM LUGAR ESQUECIDO", + "ACTIVE STYLE": "ESTILO ATIVO", + "Globe actions": "Ações do globo", + "Turn off all selected data layers": "Desativar todas as camadas de dados selecionadas", + "Copy share link": "Copiar link de compartilhamento", + "Reset camera and return to full globe view": "Redefinir a câmera e voltar à vista do globo completo", + "MISSION CONTROL · FIRST LAUNCH": "CENTRO DE CONTROLE · PRIMEIRO ACESSO", + "Choose your first view": "Escolha sua primeira vista", + "LIVE CONTACTS": "CONTATOS AO VIVO", + "Aircraft, vessels and nearby intelligence": "Aeronaves, embarcações e inteligência próxima", + "Launches, spacecraft and orbital context": "Lançamentos, espaçonaves e contexto orbital", + "EXPLORE MANUALLY": "EXPLORAR MANUALMENTE", + "Begin with a clean globe": "Comece com um globo limpo", + "Don't show this again": "Não mostrar novamente", + "ESC to dismiss": "ESC para dispensar", + "Tip: the GEV MIC button in the dock lets you talk to the map.": "Dica: o botão GEV MIC no dock permite falar com o mapa." +} From 6167aae6e4b7e4eda39609eed7ae94b0a53295fc Mon Sep 17 00:00:00 2001 From: Enzo Abyie Date: Wed, 28 Oct 2026 12:37:35 +0400 Subject: [PATCH 05/83] i18n(fr): French strings from #907 The French locale by abiyeenzo (#907), converted from its namespaced JS catalogs to the English-keyed fr.json: 862 entries whose English still matches the current UI. --- src/i18n/locales/fr.json | 885 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 885 insertions(+) create mode 100644 src/i18n/locales/fr.json diff --git a/src/i18n/locales/fr.json b/src/i18n/locales/fr.json new file mode 100644 index 000000000..0c6deba4e --- /dev/null +++ b/src/i18n/locales/fr.json @@ -0,0 +1,885 @@ +{ + "Flying to Austin, TX...": "Vol vers Austin, TX...", + "Restoring shared view...": "Restauration de la vue partagée...", + "Configuring viewer...": "Configuration de la vue...", + "Loading Google 3D Tiles...": "Chargement de Google 3D Tiles...", + "Loading the keyless globe...": "Chargement du globe sans clé...", + "Google 3D Tiles unavailable ({detail}). Loading the keyless globe...": "Google 3D Tiles indisponible ({detail}). Chargement du globe sans clé...", + "Initializing systems...": "Initialisation des systèmes...", + "Close data attribution": "Fermer l'attribution des données", + "UNAVAILABLE": "INDISPONIBLE", + "SOURCE": "SOURCE", + "Overpass rate-limited": "Overpass limite le débit", + "Overpass timed out": "Délai Overpass dépassé", + "Overpass could not complete the query": "Overpass n'a pas pu terminer la requête", + "Overpass temporarily unavailable": "Overpass temporairement indisponible", + "Retrying mapped sites…": "Nouvel essai des sites cartographiés…", + "Fetching mapped sites…": "Récupération des sites cartographiés…", + "{reason} — retrying in {seconds}s": "{reason} — nouvel essai dans {seconds}s", + "{reason} — retry pending": "{reason} — nouvel essai en attente", + "Zoom in to search mapped installations": "Zoomez pour chercher les installations cartographiées", + "Showing cached mapped sites": "Sites cartographiés en cache affichés", + "Mapped sites not loaded": "Sites cartographiés non chargés", + "Mapped sites loaded": "Sites cartographiés chargés", + "feed unavailable": "flux indisponible", + "feed stale": "flux périmé", + "observed or mapped nearby context": "contexte observé ou cartographié à proximité", + "no observed or mapped objects in current feeds": "aucun objet observé ou cartographié dans les flux actuels", + "STATION": "STATION", + "Crewed stations and their visiting vehicles": "Stations habitées et leurs véhicules visiteurs", + "NAV": "NAV", + "GNSS navigation — GPS, GLONASS, Galileo": "Navigation GNSS — GPS, GLONASS, Galileo", + "GEO": "GEO", + "Geostationary belt — comms and weather, fixed over the equator": "Ceinture géostationnaire — télécoms et météo, fixes au-dessus de l'équateur", + "VISUAL": "VISUEL", + "Brightest naked-eye objects — CelesTrak visual group": "Objets les plus brillants à l'œil nu — groupe visuel CelesTrak", + "COMMS": "COMMS", + "Broadband constellation shell — shown only in DENSE mode": "Constellation haut débit — affichée uniquement en mode DENSE", + "FISHING": "PÊCHE", + "TOWING": "REMORQUAGE", + "DREDGER": "DRAGUE", + "DIVE OPS": "PLONGÉE", + "MILITARY": "MILITAIRE", + "SAILING": "VOILIER", + "PLEASURE": "PLAISANCE", + "PILOT": "PILOTE", + "SAR": "SAR", + "TUG": "REMORQUEUR", + "PORT TENDER": "TENDER PORTUAIRE", + "ANTI-POLLUTION": "ANTIPOLLUTION", + "LAW ENFORCE": "FORCES DE L'ORDRE", + "MEDICAL": "MÉDICAL", + "HIGH-SPEED": "GRANDE VITESSE", + "PASSENGER": "PASSAGERS", + "CARGO": "CARGO", + "TANKER": "PÉTROLIER", + "OTHER": "AUTRE", + "ENVIRONMENTAL": "ENVIRONNEMENT", + "EARTH WATCH": "VEILLE TERRE", + "ACTIVE EVENTS": "ÉVÉNEMENTS ACTIFS", + "Starting live contacts…": "Démarrage des contacts live…", + "Opening space missions…": "Ouverture des missions spatiales…", + "Scanning active events…": "Analyse des événements actifs…", + "Live earthquakes and active fires, from USGS and NASA": "Séismes et incendies actifs en direct, via USGS et NASA", + "It feels like a forbidden cockpit—then you realize the sources are public and the data is real.": "On dirait un cockpit interdit—puis on comprend que les sources sont publiques et que les données sont réelles.", + "Working…": "En cours…", + "Could not open that mission{detail}. Retry or explore manually.": "Impossible d'ouvrir cette mission{detail}. Réessayez ou explorez manuellement.", + "This browser is blocking storage, so that could not be saved.": "Ce navigateur bloque le stockage, l'enregistrement a donc échoué.", + "CRT": "CRT", + "NVG": "NVG", + "FLIR": "FLIR", + "SNOW": "NEIGE", + "LOADING": "CHARGEMENT", + "DEGRADED": "DÉGRADÉ", + "STALE": "PÉRIMÉ", + "PARTIAL": "PARTIEL", + "FALLBACK": "SECOURS", + "SUMMARY": "RÉSUMÉ", + "Awaiting telemetry...": "En attente de télémétrie...", + "REC": "REC", + "AIS: --": "AIS : --", + "POWER UP · {count} KEYS WAITING": { + "one": "POWER UP · {count} CLÉ EN ATTENTE", + "other": "POWER UP · {count} CLÉS EN ATTENTE" + }, + "POWERED UP": "SOUS TENSION", + "Save failed ({status}).": "Échec de l'enregistrement ({status}).", + "REMOVE": "SUPPRIMER", + "Remove {title} from this app's saved keys": "Supprimer {title} des clés enregistrées de l'application", + "your app configuration": "la configuration de votre application", + "your local .env": "votre .env local", + "Saving…": "Enregistrement…", + "Save failed: {detail}": "Échec de l'enregistrement : {detail}", + "Paste at least one key first.": "Collez d'abord au moins une clé.", + "Saved to {store}. Restarting — this page reloads itself.": "Enregistré dans {store}. Redémarrage — cette page se recharge seule.", + "Remove this key from your saved configuration?": "Supprimer cette clé de votre configuration enregistrée ?", + "Removed from {store}. Restarting — this page reloads itself.": "Supprimé de {store}. Redémarrage — cette page se recharge seule.", + "Places context + Street View fallback; optional separate key": "Contexte Places + secours Street View ; clé séparée facultative", + "Live ships, worldwide": "Navires en direct, dans le monde entier", + "Live active-fire detections": "Détections d'incendies actifs en direct", + "Real live traffic (keyless runs a simulation)": "Trafic réel en direct (sans clé : simulation)", + "Bing imagery map stacks + world terrain": "Fonds de carte Bing + relief mondial", + "More flight-polling credits (anonymous works without)": "Plus de crédits d'interrogation des vols (fonctionne sans, en anonyme)", + "CONTEXT READY": "CONTEXTE PRÊT", + "GLOBAL CONTEXT OFF": "CONTEXTE GLOBAL OFF", + "SELECT A FLIGHT, VESSEL, OR MAPPED INSTALLATION": "CHOISIR UN VOL, UN NAVIRE OU UNE INSTALLATION CARTOGRAPHIÉE", + "ENABLE TO LOAD OBSERVED / MAPPED PROXIMITY": "ACTIVER POUR CHARGER LA PROXIMITÉ OBSERVÉE / CARTOGRAPHIÉE", + "Unavailable": "Indisponible", + "Focus {label}": "Centrer sur {label}", + "Global Context navigation": "Navigation du Contexte global", + "Previous — prior visited contact in the 250 km window": "Précédent — contact visité précédemment dans la fenêtre de 250 km", + "PREVIOUS": "PRÉCÉDENT", + "FOCUS": "CENTRER", + "Next — nearest unvisited contact in the 250 km window": "Suivant — contact non visité le plus proche dans la fenêtre de 250 km", + "NEXT": "SUIVANT", + "Open-source mapped/observed context. Missing broadcasts, unloaded map areas, or unmapped sites are not evidence of absence.": "Contexte cartographié/observé en source ouverte. Des diffusions manquantes, des zones de carte non chargées ou des sites non cartographiés ne prouvent pas une absence.", + "HDG {value}°": "HDG {value}°", + "BRG {value}°": "BRG {value}°", + "BRG —": "BRG —", + "CRS {value}°": "CRS {value}°", + "CURRENT VIEWPORT ONLY": "VUE ACTUELLE SEULEMENT", + "WITHIN {km} KM": "DANS {km} KM", + "Flights": "Vols", + "Military flights": "Vols militaires", + "AIS vessels": "Navires AIS", + "Mapped installations": "Installations cartographiées", + "syncing {count} city feeds...": "synchro de {count} flux de villes...", + "scanning nearby systems...": "analyse des systèmes proches...", + "Station {id}": "Station {id}", + "Station": "Station", + "🚲 {bikes} avail · {docks} docks · {capacity} cap": "🚲 {bikes} dispo · {docks} bornes · {capacity} cap.", + "⚠️ Not installed": "⚠️ Non installée", + "⚠️ Not renting": "⚠️ Location impossible", + "⚠️ Not returning": "⚠️ Retour impossible", + "HDG {value}° (ESTIMATED)": "HDG {value}° (ESTIMÉ)", + "{count} CAMERAS STANDING BY · NO CAMERA SELECTED · CLICK A CAMERA TO ACTIVATE": "{count} CAMÉRAS EN ATTENTE · AUCUNE CAMÉRA SÉLECTIONNÉE · CLIQUER SUR UNE CAMÉRA POUR L'ACTIVER", + "No cameras available in catalog.": "Aucune caméra disponible dans le catalogue.", + "{city} CCTV": "CCTV {city}", + "FOV {value}°": "FOV {value}°", + "COVERAGE {value}km²": "COUVERTURE {value}km²", + "OVERLAP {count} cams": "CHEVAUCHEMENT {count} cam.", + "ISOLATED VIEW": "VUE ISOLÉE", + "PROJ MONITOR": "PROJ MONITEUR", + "PROJ OFF": "PROJ OFF", + "VIEWSHED": "ZONE VISIBLE", + "CAL {value}": "CAL {value}", + "SRC {value}": "SRC {value}", + "{value} CONTEXT": "CONTEXTE {value}", + "Focus fire detection {title}, {details}": "Centrer sur la détection d'incendie {title}, {details}", + "{value} conf": "conf. {value}", + "{value} ago": "il y a {value}", + "sensor n/a": "capteur n/d", + "FIRE · {frp} MW": "INCENDIE · {frp} MW", + "NIGHT": "NUIT", + "▲ {frp} MW": "▲ {frp} MW", + "FIRE": "INCENDIE", + "FIRES": "INCENDIES", + "max {value} MW": "max {value} MW", + "new {value}": "nouveau {value}", + "just now": "à l'instant", + "<1m ago": "il y a <1 min", + "{count}m ago": "il y a {count} min", + "{count}h ago": "il y a {count} h", + "STALE · cached {age}": "PÉRIMÉ · en cache {age}", + "refreshing...": "actualisation...", + "loading...": "chargement...", + "KEY REQUIRED": "CLÉ REQUISE", + "LIVE · updated {age}": "LIVE · mis à jour {age}", + "loading mapped installation context": "chargement du contexte de l'installation cartographiée", + "MAPPED INSTALLATION": "INSTALLATION CARTOGRAPHIÉE", + "LAUNCH SITE · {site}": "SITE DE LANCEMENT · {site}", + "LAUNCH SITE": "SITE DE LANCEMENT", + "T−{time} · {mission}": "T−{time} · {mission}", + "LAUNCH STANDBY": "LANCEMENT EN ATTENTE", + "LIFTOFF · {mission}": "DÉCOLLAGE · {mission}", + "ASCENT REPLAY · {mission}": "RELECTURE ASCENSION · {mission}", + "ASCENT ESTIMATE · {mission}": "ASCENSION ESTIMÉE · {mission}", + "STAGE RE-ENTRY / RECOVERY · {mission}": "RENTRÉE / RÉCUPÉRATION D'ÉTAGE · {mission}", + "ORBIT REPLAY · {mission}": "RELECTURE ORBITE · {mission}", + "PAUSED · {title}": "PAUSE · {title}", + "UNSPECIFIED": "NON PRÉCISÉ", + "+{count} additional payload records": "+{count} enregistrements de charge utile supplémentaires", + "PAYLOAD DATA UNAVAILABLE": "DONNÉES DE CHARGE UTILE INDISPONIBLES", + "{value} KM DOWNRANGE": "{value} KM EN AVAL", + "POSITION UNAVAILABLE": "POSITION INDISPONIBLE", + "FLIGHT {count}": "VOL {count}", + "REUSED": "RÉUTILISÉ", + "NO STAGE RE-ENTRY / RECOVERY DATA": "AUCUNE DONNÉE DE RENTRÉE / RÉCUPÉRATION D'ÉTAGE", + "{count} / 30D": "{count} / 30J", + "NO MISSIONS AVAILABLE IN THE CURRENT 30-DAY WINDOW": "AUCUNE MISSION DISPONIBLE DANS LA FENÊTRE ACTUELLE DE 30 JOURS", + "DATE UNAVAILABLE": "DATE INDISPONIBLE", + "UNSPECIFIED OPERATOR": "OPÉRATEUR NON PRÉCISÉ", + "Select {mission}": "Sélectionner {mission}", + "{value} KM": "{value} KM", + "{value} KM/S": "{value} KM/S", + "SELECTED SPACE MISSION": "MISSION SPATIALE SÉLECTIONNÉE", + "Show all missions": "Afficher toutes les missions", + "Deselect mission": "Désélectionner la mission", + "MISSION": "MISSION", + "STATUS · ": "STATUT · ", + "LAUNCH SITE · ": "SITE DE LANCEMENT · ", + "LAUNCH TIME · ": "HEURE DE LANCEMENT · ", + "ORBIT · ": "ORBITE · ", + "ASCENT PATH · ": "TRAJECTOIRE D'ASCENSION · ", + "CURRENT DISTANCE FROM EARTH · ": "DISTANCE ACTUELLE DE LA TERRE · ", + "SATELLITE SPEED · ": "VITESSE DU SATELLITE · ", + "PAYLOAD": "CHARGE UTILE", + "NAME": "NOM", + "TYPE": "TYPE", + "DESTINATION": "DESTINATION", + "STAGE / RE-ENTRY / RECOVERY": "ÉTAGE / RENTRÉE / RÉCUPÉRATION", + "STAGE": "ÉTAGE", + "STATUS": "STATUT", + "FINAL POSITION": "POSITION FINALE", + "REPLAY SPEED": "VITESSE DE RELECTURE", + "Replay speed multiplier": "Multiplicateur de vitesse de relecture", + "REPLAY ASCENT": "REJOUER L'ASCENSION", + "Previous mission": "Mission précédente", + "PREV": "PRÉC.", + "Next mission": "Mission suivante", + "SHOW ALL / DESELECT": "TOUT AFFICHER / DÉSÉLECTIONNER", + "Pause replay": "Mettre la relecture en pause", + "Cancel replay": "Annuler la relecture", + "EST. DOWNRANGE": "EN AVAL EST.", + "PLANNED · ": "PRÉVU · ", + "SUPPLIED TRAJECTORY POINTS": "POINTS DE TRAJECTOIRE FOURNIS", + "RECONSTRUCTED ESTIMATE": "ESTIMATION RECONSTITUÉE", + "Replay the estimated ascent with a following camera": "Rejouer l'ascension estimée avec une caméra de suivi", + "Resume replay": "Reprendre la relecture", + "T minus {seconds}": "T moins {seconds}", + "Preparing launch site": "Préparation du site de lancement", + "Liftoff": "Décollage", + "Ascent replay": "Relecture de l'ascension", + "Orbit replay": "Relecture de l'orbite", + ", paused": ", en pause", + "Alt unknown": "Alt. inconnue", + "Type unknown": "Type inconnu", + "Reg unknown": "Immat. inconnue", + "Operator unknown": "Opérateur inconnu", + "radio tag|All": "Toutes", + "News": "Actualités", + "Talk": "Débats", + "Weather / Emergency": "Météo / Urgences", + "Public Safety": "Sécurité publique", + "Aviation / Marine": "Aviation / Marine", + "Traffic / Transit": "Trafic / Transports", + "Music": "Musique", + "Other": "Autres", + "radio|NEWS": "ACTUS", + "radio|TALK": "DÉBATS", + "radio|WEATHER": "MÉTÉO", + "radio|SAFETY": "SÉCURITÉ", + "radio|AIR / SEA": "AIR / MER", + "radio|TRANSIT": "TRANSPORTS", + "radio|MUSIC": "MUSIQUE", + "radio|OTHER": "AUTRES", + "Alternative": "Alternatif", + "Ambient": "Ambient", + "Blues": "Blues", + "Classical": "Classique", + "Country": "Country", + "Dance": "Dance", + "Electronic": "Électronique", + "Folk": "Folk", + "Funk": "Funk", + "Hip-Hop": "Hip-Hop", + "House": "House", + "Indie": "Indie", + "Jazz": "Jazz", + "Latin": "Latino", + "Metal": "Metal", + "Oldies": "Oldies", + "Pop": "Pop", + "Punk": "Punk", + "R&B": "R&B", + "Reggae": "Reggae", + "Rock": "Rock", + "Soul": "Soul", + "Techno": "Techno", + "Trance": "Trance", + "World": "Musiques du monde", + "Add the full Starlink broadband shell (thousands of extra points)": "Ajouter toute la constellation Starlink (des milliers de points en plus)", + "Loading the Starlink shell…": "Chargement de la constellation Starlink…", + "Starlink {detail} — click to retry": "Starlink {detail} — cliquer pour réessayer", + "load failed": "échec du chargement", + "Showing the full Starlink shell — click for the core catalog only": "Constellation Starlink complète affichée — cliquer pour le catalogue de base seulement", + "DENSE ···": "DENSE ···", + "DENSE ✕": "DENSE ✕", + "DENSE": "DENSE", + "Syncing flow · Roads: {source}": "Synchro du flux · Routes : {source}", + "LIVE · Roads: {source} · Roads without flow hidden": "LIVE · Routes : {source} · Routes sans flux masquées", + "LIVE · Roads: {source} · No flow roads in view": "LIVE · Routes : {source} · Aucune route avec flux en vue", + "LIVE · Roads: {source} · Flow {percent}%": "LIVE · Routes : {source} · Flux {percent}%", + "SIMULATED · Roads: {source} · Flow {percent}%": "SIMULÉ · Routes : {source} · Flux {percent}%", + "Syncing flow · Roads: OpenStreetMap · Flow: TomTom · Unmatched: simulated": "Synchro du flux · Routes : OpenStreetMap · Flux : TomTom · Non appariées : simulées", + "LIVE · Roads: OpenStreetMap · Flow: TomTom · {percent}% cov · Unmatched: simulated": "LIVE · Routes : OpenStreetMap · Flux : TomTom · {percent}% couv. · Non appariées : simulées", + "LIVE · Roads: OpenStreetMap · Flow: TomTom · {percent}% cov": "LIVE · Routes : OpenStreetMap · Flux : TomTom · {percent}% couv.", + "SIMULATED · Roads: OpenStreetMap · Flow: TomTom (no matches)": "SIMULÉ · Routes : OpenStreetMap · Flux : TomTom (aucune correspondance)", + "SIMULATED — traffic service unreachable": "SIMULÉ — service de trafic injoignable", + "SIMULATED — add TomTom key for live": "SIMULÉ — ajoutez une clé TomTom pour le live", + "AIS: {name}": "AIS : {name}", + "{type} SPD: {speed} HDG: {heading}": "{type} VIT : {speed} CAP : {heading}", + "VESSEL": "NAVIRE", + "POS: LIVE": "POS : LIVE", + "POS: {time}Z": "POS : {time}Z", + "awaiting first AIS position…": "en attente de la première position AIS…", + "awaiting usable AIS positions…": "en attente de positions AIS exploitables…", + "awaiting first AIS message…": "en attente du premier message AIS…", + "Resume": "Reprendre", + "Pause": "Mettre en pause", + "Error: {message}": "Erreur : {message}", + "Needs {envVars} — add it in Provider Settings": "Nécessite {envVars} — à ajouter dans les paramètres des fournisseurs", + "{label} is unavailable": "{label} est indisponible", + "This map stack": "Ce fond de carte", + "{label} unavailable: {hint}": "{label} indisponible : {hint}", + "Visible map targets": "Cibles visibles sur la carte", + "Ready": "Prêt", + "Loaded: {scene} / {shot}": "Chargé : {scene} / {shot}", + "Cannot capture shot: camera not ready": "Capture impossible : caméra non prête", + "Captured: {scene} / {shot}": "Capturé : {scene} / {shot}", + "Select a shot first": "Sélectionnez d'abord un plan", + "Updated: {scene} / {shot}": "Mis à jour : {scene} / {shot}", + "Camera unavailable — exit cockpit first": "Caméra indisponible — quittez d'abord le cockpit", + "No shots to run": "Aucun plan à lancer", + "Project exported": "Projet exporté", + "Could not exit {mode} — scene layers may be refused": "Impossible de quitter {mode} — les couches de la scène peuvent être refusées", + "Running {index}/{total}: {scene} / {shot}": "Exécution {index}/{total} : {scene} / {shot}", + "Scene run complete": "Scène terminée", + "Global Flights Radar": "Radar mondial des vols", + "Orbital Watch": "Veille orbitale", + "Thermal Threat Board": "Tableau des menaces thermiques", + "City Overload": "Surcharge urbaine", + "Omniscience Pullback": "Recul omniscient", + "Shot {n}": "Plan {n}", + "Density": "Densité", + "Bloom": "Bloom", + "VISUAL PRESETS": "PRÉRÉGLAGES VISUELS", + "LOCATION": "LIEU", + "CONTACTS — nearest planes · vessels · sites": "CONTACTS — avions · navires · sites les plus proches", + "SPACE MISSIONS — launches & orbital assets": "MISSIONS SPATIALES — lancements et objets orbitaux", + "LIVE SIGNALS": "SIGNAUX LIVE", + "Contacts could not complete the requested transition; try again": "Les contacts n'ont pas pu effectuer la transition demandée ; réessayez", + "CCTV layer unavailable": "Couche CCTV indisponible", + "Link copied!": "Lien copié !", + "Copy failed": "Échec de la copie", + "CCTV calibration saved": "Calibration CCTV enregistrée", + "CCTV calibration reset": "Calibration CCTV réinitialisée", + "ADJUST ON": "AJUSTER ON", + "ADJUST": "AJUSTER", + "UNKNOWN": "INCONNU", + "SOURCE · UNKNOWN": "SOURCE · INCONNUE", + "FRAME · LOADING": "IMAGE · CHARGEMENT", + "FRAME · UNAVAILABLE": "IMAGE · INDISPONIBLE", + "CALIBRATED": "CALIBRÉE", + "CURATED": "SÉLECTIONNÉE", + "RAW PRIOR": "VALEUR BRUTE", + "CCTV ON": "CCTV ON", + "CCTV OFF": "CCTV OFF", + "VIEWSHED ON": "ZONE VISIBLE ON", + "COVERAGE ON": "COUVERTURE ON", + "COVERAGE OFF": "COUVERTURE OFF", + "AUTO HOP ON": "AUTO-SAUT ON", + "AUTO HOP OFF": "AUTO-SAUT OFF", + "PROJECTION ON": "PROJECTION ON", + "PROJECTION OFF": "PROJECTION OFF", + "CAL · EDITED (UNSAVED)": "CAL · MODIFIÉE (NON ENREGISTRÉE)", + "CAL · {badge}": "CAL · {badge}", + "MONITOR": "MONITEUR", + "OFF": "OFF", + "{city} · HDG {heading} · FOV {fov} · RANGE {range}m · {projection}{calBadge} · {provider}{status}": "{city} · HDG {heading} · FOV {fov} · PORTÉE {range}m · {projection}{calBadge} · {provider}{status}", + "{count} cameras loaded · click a camera to activate": { + "one": "{count} caméra chargée · cliquer sur une caméra pour l'activer", + "other": "{count} caméras chargées · cliquer sur une caméra pour l'activer" + }, + "{count} cameras loaded · enable CCTV to activate": { + "one": "{count} caméra chargée · activer CCTV pour l'utiliser", + "other": "{count} caméras chargées · activer CCTV pour les utiliser" + }, + "Enable CCTV to load camera intersections": "Activez CCTV pour charger les intersections de caméras", + "Enable CCTV to start camera-linked intelligence summaries.": "Activez CCTV pour lancer les résumés de renseignement liés aux caméras.", + "No summary available.": "Aucun résumé disponible.", + "loading frames": "chargement des images", + "camera grid ready": "grille de caméras prête", + "Clearing selected data layers": "Effacement des couches de données sélectionnées", + "Clear selected data layers": "Effacer les couches de données sélectionnées", + "CONDITIONS UNKNOWN": "CONDITIONS INCONNUES", + "CLEAR": "DÉGAGÉ", + "PARTLY CLOUDY": "PARTIELLEMENT NUAGEUX", + "OVERCAST": "COUVERT", + "FOG": "BROUILLARD", + "DRIZZLE": "BRUINE", + "RAIN": "PLUIE", + "RAIN SHOWERS": "AVERSES DE PLUIE", + "SNOW SHOWERS": "AVERSES DE NEIGE", + "THUNDERSTORM": "ORAGE", + "MIXED CONDITIONS": "CONDITIONS VARIABLES", + "CYCLE ON": "DÉFIL. ON", + "CYCLE OFF": "DÉFIL. OFF", + "Stop automatic page cycling. Previous, Next, and the SIG/NEWS/LOCAL tabs stay available.": "Arrêter le défilement automatique des pages. Précédent, Suivant et les onglets SIG/ACTUS/LOCAL restent disponibles.", + "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.": "Faire défiler automatiquement les pages du briefing toutes les 9 secondes (Signaux → Actus → Local). En pause pendant le survol ou le focus du panneau. Les signaux live s'actualisent en continu dans les deux cas.", + "ACQUIRING REGIONAL NEWS": "ACQUISITION DES ACTUS RÉGIONALES", + "REGIONAL NEWS UNAVAILABLE": "ACTUS RÉGIONALES INDISPONIBLES", + "RESOLVING REGION": "RÉSOLUTION DE LA RÉGION", + "REGION UNAVAILABLE": "RÉGION INDISPONIBLE", + "NO RECENT LOCATION MATCHES": "AUCUNE CORRESPONDANCE RÉCENTE AU LIEU", + "{domain} · {age}": "{domain} · {age}", + "CLOUD {pct}%": "NUAGES {pct}%", + "CLOUD UNKNOWN": "NUAGES INCONNUS", + "{source} · LOCATION QUERY": "{source} · REQUÊTE DE LIEU", + "REGIONAL NEWS": "ACTUS RÉGIONALES", + "CONTEXT STANDBY": "CONTEXTE EN VEILLE", + "ENABLE GLOBAL CONTEXT FOR PROXIMITY PINGS": "ACTIVER LE CONTEXTE GLOBAL POUR LES PINGS DE PROXIMITÉ", + "CONTACT LOST · LAST KNOWN READOUT · NOT AN ALL-CLEAR": "CONTACT PERDU · DERNIÈRE POSITION CONNUE · PAS UN FEU VERT", + "CONTACT LOST · {subject}": "CONTACT PERDU · {subject}", + "SUBJECT LEFT ITS FEED · READOUT HOLDING LAST KNOWN": "SUJET SORTI DE SON FLUX · AFFICHAGE SUR LA DERNIÈRE POSITION CONNUE", + "{cohort} · {contact}": "{cohort} · {contact}", + "NO AVAILABLE EXAMPLE": "AUCUN EXEMPLE DISPONIBLE", + "{cohort}, Unavailable": "{cohort}, indisponible", + "AHEAD": "DEVANT", + "{side} {angle}": "{side} {angle}", + "L": "G", + "R": "D", + "{count} INPUTS UNKNOWN · NOT AN ALL-CLEAR": { + "one": "{count} ENTRÉE INCONNUE · PAS UN FEU VERT", + "other": "{count} ENTRÉES INCONNUES · PAS UN FEU VERT" + }, + "AVAILABLE INPUTS CURRENT · NOT AN ALL-CLEAR": "ENTRÉES DISPONIBLES À JOUR · PAS UN FEU VERT", + "AIRCRAFT": "AÉRONEF", + "ACQUIRING SURFACE": "ACQUISITION SURFACE", + "SURFACE FALLBACK": "SECOURS SURFACE", + "STALE FEED": "FLUX PÉRIMÉ", + "LIVE TRACK": "PISTE LIVE", + "COMMERCIAL": "COMMERCIAL", + "{aircraftClass} · {feedState} · COURSE ALIGNED": "{aircraftClass} · {feedState} · CAP ALIGNÉ", + "ARROW · ESTIMATED DIRECTION": "FLÈCHE · DIRECTION ESTIMÉE", + "ROUTE DATA UNAVAILABLE": "DONNÉES DE ROUTE INDISPONIBLES", + "DEST {bearing}": "DEST {bearing}", + "Disable cockpit weather effects": "Désactiver les effets météo du cockpit", + "Enable cockpit weather effects": "Activer les effets météo du cockpit", + "ON": "ON", + "Normal": "Normal", + "Night vision": "Vision nocturne", + "Thermal": "Thermique", + "Anime": "Anime", + "Noir": "Noir", + "Snow": "Neige", + "Current cockpit vision style: {style}. Activate for next style.": "Style de vision actuel du cockpit : {style}. Activer pour le style suivant.", + "Current style: {style} — click for next": "Style actuel : {style} — cliquer pour le suivant", + "Collapse Contact panel": "Réduire le panneau Contact", + "Expand Contact panel": "Développer le panneau Contact", + "Collapse contact panel": "Réduire le panneau contact", + "Expand contact panel": "Développer le panneau contact", + "Collapse cockpit briefing panel": "Réduire le panneau de briefing du cockpit", + "Expand cockpit briefing panel": "Développer le panneau de briefing du cockpit", + "Collapse briefing panel": "Réduire le panneau de briefing", + "Expand briefing panel": "Développer le panneau de briefing", + "OBSERVED / MAPPED PINGS": "PINGS OBSERVÉS / CARTOGRAPHIÉS", + "SOURCE-BACKED EVENTS · NO SYNTHETIC NEWS": "ÉVÉNEMENTS SOURCÉS · AUCUNE ACTU SYNTHÉTIQUE", + "LATEST LOCATION-MATCHED REPORTING": "DERNIERS REPORTAGES SELON LE LIEU", + "LOCAL INFO": "INFOS LOCALES", + "PLACE / CONDITIONS / POSITION": "LIEU / CONDITIONS / POSITION", + "TIME UNKNOWN": "HEURE INCONNUE", + "{count}M AGO": "IL Y A {count} MIN", + "{count}H AGO": "IL Y A {count} H", + "{count}D AGO": "IL Y A {count} J", + "DIR UNKNOWN": "DIR INCONNUE", + "Select flight {title}": "Sélectionner le vol {title}", + "{aircraftClass} · CURRENT": "{aircraftClass} · ACTUEL", + "MILITARY FLIGHT": "VOL MILITAIRE", + "COMMERCIAL FLIGHT": "VOL COMMERCIAL", + "{aircraftClass} · {distance}": "{aircraftClass} · {distance}", + "DISTANCE UNKNOWN": "DISTANCE INCONNUE", + "{count} INPUTS UNKNOWN": { + "one": "{count} ENTRÉE INCONNUE", + "other": "{count} ENTRÉES INCONNUES" + }, + "SOURCE STATUS UNAVAILABLE": "ÉTAT DE LA SOURCE INDISPONIBLE", + "Restore real aircraft": "Restaurer l'aéronef réel", + "Reclassify as TR-3B": "Reclasser en TR-3B", + "TRACK ACQUIRED": "PISTE ACQUISE", + "{label} · COURSE {heading}°": "{label} · CAP {heading}°", + "Context could not restore every layer; try again": "Le contexte n'a pas pu restaurer toutes les couches ; réessayez", + "No selected data layers": "Aucune couche de données sélectionnée", + "{count} data layers could not be cleared": { + "one": "{count} couche de données n'a pas pu être effacée", + "other": "{count} couches de données n'ont pas pu être effacées" + }, + "Cleared {count} data layers": { + "one": "{count} couche de données effacée", + "other": "{count} couches de données effacées" + }, + "Selected data layers could not be cleared": "Impossible d'effacer les couches de données sélectionnées", + "Space Missions could not complete the requested transition; try again": "Les missions spatiales n'ont pas pu effectuer la transition demandée ; réessayez", + "Nearby installations refreshed": "Installations proches actualisées", + "Nearby installations could not be refreshed; try again": "Impossible d'actualiser les installations proches ; réessayez", + "Space Missions cancellation could not restore the previous layer state": "L'annulation des missions spatiales n'a pas pu restaurer l'état précédent des couches", + "That layer is unavailable in the current Context mode": "Cette couche est indisponible dans le mode Contexte actuel", + "{layerId} could not {action} cleanly": "{layerId} n'a pas pu {action} proprement", + "start": "démarrer", + "stop": "s'arrêter", + "{mode} could not start because another layer did not stop cleanly": "Impossible de démarrer {mode} : une autre couche ne s'est pas arrêtée proprement", + "Space Missions": "Missions spatiales", + "Context": "Contexte", + "Live Flights": "Vols en direct", + "Military Flights": "Vols militaires", + "Earthquakes (24h)": "Séismes (24 h)", + "Satellites": "Satellites", + "Space Missions (30d)": "Missions spatiales (30 j)", + "Street Traffic": "Trafic routier", + "CCTV": "CCTV", + "Radio": "Radio", + "Bikeshare": "Vélos en libre-service", + "Live AIS Vessels": "Navires AIS en direct", + "Mapped Installations": "Installations cartographiées", + "Global Context": "Contexte global", + "Datacenters": "Centres de données", + "Dams": "Barrages", + "Submarine Cables": "Câbles sous-marins", + "FIRMS Active Fires": "Incendies actifs FIRMS", + "ENABLING": "ACTIVATION", + "DISABLING": "DÉSACTIVATION", + "{state} · {source}": "{state} · {source}", + "UNCERTAIN · {source} · lifecycle state requires reconciliation": "INCERTAIN · {source} · état du cycle de vie à réconcilier", + "{state} · {source} · {detail} · retry {seconds}s": "{state} · {source} · {detail} · nouvel essai {seconds} s", + "{state} · {source} · {detail}": "{state} · {source} · {detail}", + "never": "jamais", + "{source} · {loadingLabel}": "{source} · {loadingLabel}", + "{accepted} of {raw} records accepted": "{accepted} enregistrements acceptés sur {raw}", + "incomplete snapshot": "instantané incomplet", + "{state} · {source} · {detail} · {ago}": "{state} · {source} · {detail} · {ago}", + "{state} · {source} · {ago} · retrying in {seconds}s": "{state} · {source} · {ago} · nouvel essai dans {seconds} s", + "{state} · {source} · {ago}": "{state} · {source} · {ago}", + "{source} · {ago}": "{source} · {ago}", + "UNCERTAIN": "INCERTAIN", + "{name}: {state}": "{name} : {state}", + "{count}s ago": "il y a {count} s", + "📍 Location: --": "📍 Lieu : --", + "Landmark: --": "Repère : --", + "Searched location": "Lieu recherché", + "ORBIT": "ORBITE", + "Location not found": "Lieu introuvable", + "Search failed": "Échec de la recherche", + "Fly to a POI first": "Rejoignez d'abord un repère", + "Reset to full globe view": "Revenir à la vue du globe entier", + "Reset cockpit to full globe view": "Réinitialiser le cockpit sur la vue du globe entier", + "Resetting to full globe view": "Retour à la vue du globe entier", + "Resetting cockpit to full globe view": "Réinitialisation du cockpit sur la vue du globe entier", + "MAP": "CARTE", + "panel": "le panneau", + "Expand {name}": "Développer {name}", + "Collapse {name}": "Réduire {name}", + "Expand Radio": "Développer la Radio", + "Collapse Radio": "Réduire la Radio", + "Expand Radio section": "Développer la section Radio", + "Collapse Radio section": "Réduire la section Radio", + "Panel layout updated — positions reset to new defaults": "Disposition des panneaux mise à jour — positions réinitialisées", + "Collapse Cockpit display options": "Réduire les options d'affichage du cockpit", + "Expand Cockpit display options": "Développer les options d'affichage du cockpit", + "Collapse Cockpit Radio controls": "Réduire les commandes Radio du cockpit", + "Expand Cockpit Radio controls": "Développer les commandes Radio du cockpit", + "NO STATIONS": "AUCUNE STATION", + "NO STATION AVAILABLE": "AUCUNE STATION DISPONIBLE", + "{name}, station {index} of {total}": "{name}, station {index} sur {total}", + "No station available": "Aucune station disponible", + "OFF AIR": "HORS ANTENNE", + "STATION UNAVAILABLE": "STATION INDISPONIBLE", + "Radio could not {action} cleanly": "La Radio n'a pas pu {action} proprement", + "Close compact Radio controls": "Fermer les commandes Radio compactes", + "Open compact Radio controls": "Ouvrir les commandes Radio compactes", + "SYNC": "SYNCHRO", + "RECONCILE": "RÉCONCILIER", + "DISABLE": "DÉSACTIVER", + "ENABLE": "ACTIVER", + "Reconcile Radio — lifecycle uncertain": "Réconcilier la Radio — cycle de vie incertain", + "Disable Radio": "Désactiver la Radio", + "Enable Radio": "Activer la Radio", + "DIRECTORY BAND": "BANDE DE L'ANNUAIRE", + "{category} BAND": "BANDE {category}", + "NO STATION SELECTED": "AUCUNE STATION SÉLECTIONNÉE", + "Directory metadata only": "Métadonnées de l'annuaire seulement", + "Loading station directory…": "Chargement de l'annuaire des stations…", + "Choose a globe marker or use next.": "Choisissez un marqueur du globe ou utilisez suivant.", + "TAGS · {tags}": "TAGS · {tags}", + "Play": "Lire", + "PLAY": "LIRE", + "selected": "sélectionnée", + "nearest": "la plus proche", + "{action} {target} radio station": "{action} la station radio {target}", + "RADIO STATE UNCERTAIN": "ÉTAT RADIO INCERTAIN", + "SYNCING DIRECTORY": "SYNCHRO DE L'ANNUAIRE", + "RADIO READY": "RADIO PRÊTE", + "SYNCING": "SYNCHRO", + "READY": "PRÊT", + "station": "station", + " · stale/degraded directory": " · annuaire périmé/dégradé", + " · degraded directory": " · annuaire dégradé", + " · stale directory": " · annuaire périmé", + " · outside current filter": " · hors du filtre actuel", + "Ready — playback starts only from your action": "Prêt — la lecture ne démarre que sur votre action", + "Radio off": "Radio désactivée", + "Connecting directly to broadcaster…": "Connexion directe au diffuseur…", + "Buffering broadcaster stream…": "Mise en mémoire tampon du flux du diffuseur…", + "Playing {station}": "Lecture de {station}", + "Paused {station}": "{station} en pause", + "Broadcaster stream unavailable": "Flux du diffuseur indisponible", + " · muted during voice interaction": " · coupé pendant l'interaction vocale", + " · restoring volume after voice": " · rétablissement du volume après la voix", + " · static indicates no broadcaster audio": " · le grésillement indique l'absence de flux du diffuseur", + " · tuning static until broadcaster starts": " · grésillement de syntonisation jusqu'au démarrage du diffuseur", + "Station unavailable after directory refresh — choose another channel": "Station indisponible après l'actualisation de l'annuaire — choisissez un autre canal", + "Radio is enabling…": "Activation de la Radio…", + "Radio is disabling…": "Désactivation de la Radio…", + "Radio lifecycle is uncertain — use Enable or Disable to reconcile": "Cycle de vie de la Radio incertain — utilisez Activer ou Désactiver pour réconcilier", + "Scene action failed": "Échec de l'action sur la scène", + "Delete shot \"{shot}\"?": "Supprimer le plan « {shot} » ?", + "SPARSE": "ÉPARS", + "BALANCED": "ÉQUILIBRÉ", + "DEL": "SUPPR.", + "entity": "entité", + "Shared {subject} follow expired": "Le suivi partagé de {subject} a expiré", + "Shared {subject} could not be restored — feed unavailable": "Impossible de restaurer le suivi partagé de {subject} — flux indisponible", + "Shared {subject} is unavailable": "Partage indisponible : {subject}", + "ACQUIRING": "ACQUISITION", + "SHARED {subject}": "PARTAGÉ : {subject}", + "LOADING LIVE DATA": "CHARGEMENT DES DONNÉES LIVE", + "LOAD COMPLETE": "CHARGEMENT TERMINÉ", + "LOAD CANCELLED": "CHARGEMENT ANNULÉ", + "LOAD FAILED": "ÉCHEC DU CHARGEMENT", + "LIVE DATA OFF": "DONNÉES LIVE DÉSACTIVÉES", + "MAPPED SITES LOADED": "SITES CARTOGRAPHIÉS CHARGÉS", + "RETRYING MAPPED SITES": "NOUVEL ESSAI SITES CARTOGRAPHIÉS", + "FETCHING MAPPED SITES": "RÉCUPÉRATION DES SITES CARTOGRAPHIÉS", + "TURNING OFF LIVE DATA": "DÉSACTIVATION DES DONNÉES LIVE", + "REFRESHING LIVE DATA": "ACTUALISATION DES DONNÉES LIVE", + "syncing road network": "synchro du réseau routier", + "retry pending": "nouvel essai en attente", + "retrying in {seconds}s": "nouvel essai dans {seconds}s", + "Celestial ring — reveal the full globe": "Anneau céleste — révéler le globe entier", + "Celestial ring — available in Normal style": "Anneau céleste — disponible en style Normal", + "Detection overlay: {mode}": "Surcouche de détection : {mode}", + "Detection overlay: off": "Surcouche de détection : désactivée", + "DETECT": "DÉTECT.", + "voice|OFF": "OFF", + "voice|CONNECTING": "CONNEXION", + "voice|LISTENING": "ÉCOUTE", + "voice|EXECUTING": "EXÉCUTION", + "voice|ERROR": "ERREUR", + "AI AGENT": "AGENT IA", + "Voice model tier — applies next session": "Niveau du modèle vocal — à la prochaine session", + "Estimated session cost": "Coût estimé de la session", + "Voice control — activate to toggle voice; hold Space to speak": "Commande vocale — activer pour basculer la voix ; maintenir Espace pour parler", + "VOICE STANDBY": "VOIX EN VEILLE", + "VOICE CONTROL": "COMMANDE VOCALE", + "Hold Space to speak · tap Space to activate focused controls": "Maintenez Espace pour parler · appuyez sur Espace pour activer les commandes ciblées", + "VOICE SYSTEM ERROR": "ERREUR DU SYSTÈME VOCAL", + "DISMISS": "FERMER", + "Check microphone permission and network access, then try again.": "Vérifiez l'autorisation du microphone et l'accès réseau, puis réessayez.", + "Release Space to send": "Relâchez Espace pour envoyer", + "Hold Space to talk": "Maintenez Espace pour parler", + "Requesting microphone": "Demande du microphone", + "Ask or command": "Posez une question ou donnez un ordre", + "Running command": "Commande en cours", + "Voice off": "Voix désactivée", + "WebRTC microphone support unavailable": "Microphone WebRTC non pris en charge", + "VOICE UNAVAILABLE": "VOIX INDISPONIBLE", + "VOICE ACTIVE": "VOIX ACTIVE", + "Voice session could not be started.": "Impossible de démarrer la session vocale.", + "Next session: {pendingId} — this session stays on {modelId}": "Prochaine session : {pendingId} — cette session reste sur {modelId}", + "Voice model: {pendingId} — click to switch to {target}; applies next session": "Modèle vocal : {pendingId} — cliquer pour passer à {target} ; à la prochaine session", + "Estimated session cost on {modelId} — {responses} response(s). Warns at {warn}, ends the session at {cap}.": "Coût estimé de la session sur {modelId} — {responses} réponse(s). Alerte à {warn}, fin de session à {cap}.", + "{tier} applies next session": "{tier} à la prochaine session", + "Session ended — cost cap {cost}": "Session terminée — plafond de coût {cost}", + "Radio did not start": "La radio n'a pas démarré", + "Aircraft cockpit view": "Vue cockpit de l'aéronef", + "LEVEL": "NIVEAU", + "Estimated destination direction": "Direction estimée de la destination", + "DEST ---°": "DEST ---°", + "OPTICAL PLANE · 01": "PLAN OPTIQUE · 01", + "VISOR LOCK · ACTIVE": "VERROU VISIÈRE · ACTIF", + "GROUND SPEED · KTS": "VITESSE SOL · KTS", + "ALTITUDE · FT": "ALTITUDE · FT", + "FIRST PERSON": "PREMIÈRE PERSONNE", + "LIVE TRACK · COURSE ALIGNED": "PISTE LIVE · CAP ALIGNÉ", + "Cockpit vision style": "Style de vision du cockpit", + "Previous cockpit vision style": "Style de vision précédent du cockpit", + "Previous vision style": "Style de vision précédent", + "Current cockpit vision style: NORMAL. Activate for next style.": "Style de vision actuel du cockpit : NORMAL. Activer pour le style suivant.", + "Current style: NORMAL — click for next": "Style actuel : NORMAL — cliquer pour le suivant", + "CURRENT": "ACTUEL", + "Next cockpit vision style": "Style de vision suivant du cockpit", + "Next vision style": "Style de vision suivant", + "Current aircraft heading": "Cap actuel de l'aéronef", + "GROUND SPEED": "VITESSE SOL", + "ALTITUDE": "ALTITUDE", + "Contact cockpit summary": "Résumé cockpit du contact", + "CONTACT": "CONTACT", + "CONTACTS · 250 KM": "CONTACTS · 250 KM", + "Contact navigation": "Navigation des contacts", + "CONTEXT ONLY": "CONTEXTE SEULEMENT", + "Nearby cohort counts": "Nombre de contacts par groupe à proximité", + "NEAREST OBSERVED / MAPPED": "PLUS PROCHE OBSERVÉ / CARTOGRAPHIÉ", + "AVAILABLE INPUTS ONLY · NOT AN ALL-CLEAR": "ENTRÉES DISPONIBLES SEULEMENT · PAS UN FEU VERT", + "Cockpit briefing carousel": "Carrousel de briefing du cockpit", + "Estimated flight plan": "Plan de vol estimé", + "ESTIMATED FLIGHT PLAN": "PLAN DE VOL ESTIMÉ", + "FROM": "DE", + "TO": "VERS", + "Cockpit briefing controls": "Commandes du briefing du cockpit", + "Previous briefing page": "Page de briefing précédente", + "Next briefing page": "Page de briefing suivante", + "Live signals": "Signaux live", + "Latest regional news": "Dernières actualités régionales", + "Location-based information": "Informations selon le lieu", + "TEMP": "TEMP", + "WIND": "VENT", + "SKY": "CIEL", + "PRECIP": "PRÉCIP", + "Show Live Signals": "Afficher les signaux live", + "Show Regional News": "Afficher les actus régionales", + "Show Local Info": "Afficher les infos locales", + "Cockpit display and Radio controls": "Commandes d'affichage et de Radio du cockpit", + "DISPLAY": "AFFICHAGE", + "Cockpit display options": "Options d'affichage du cockpit", + "RADIO": "RADIO", + "Cockpit compact Radio controls": "Commandes Radio compactes du cockpit", + "Previous filtered radio station": "Station radio filtrée précédente", + "Play selected radio station": "Lire la station radio sélectionnée", + "Next filtered radio station": "Station radio filtrée suivante", + "VOLUME": "VOLUME", + "Cockpit Radio volume": "Volume de la Radio du cockpit", + "View switcher": "Sélecteur de vue", + "Exit cockpit and return to full globe view": "Quitter le cockpit et revenir à la vue du globe entier", + "RESET": "RÉINIT.", + "Exit cockpit view": "Quitter la vue cockpit", + "EXIT COCKPIT": "QUITTER LE COCKPIT", + "Navigation, voice, and visual preset controls": "Commandes de navigation, de voix et de préréglages visuels", + "Expand Visual Presets": "Développer les préréglages visuels", + "Pin visual presets": "Épingler les préréglages visuels", + "Keep visual presets open": "Garder les préréglages visuels ouverts", + "Show the globe without a visual filter.": "Afficher le globe sans filtre visuel.", + "Emulate a green phosphor CRT with scanlines and screen curvature.": "Émuler un écran CRT à phosphore vert avec lignes de balayage et courbure d'écran.", + "Simulate night-vision goggles with green intensification and a tube vignette.": "Simuler des jumelles de vision nocturne avec intensification verte et vignettage du tube.", + "Simulate FLIR-style thermal contrast. Turn up Ironbow for color.": "Simuler un contraste thermique de type FLIR. Montez Ironbow pour la couleur.", + "Apply bright cel-shaded color and illustrated outlines.": "Appliquer des couleurs vives en cel-shading et des contours illustrés.", + "Apply high-contrast monochrome film-noir grading.": "Appliquer un étalonnage film noir monochrome à fort contraste.", + "Add a cold, snowy whiteout treatment to the scene.": "Ajouter un effet de voile blanc, froid et enneigé à la scène.", + "MAP SOURCE": "SOURCE CARTE", + "Map source": "Source de la carte", + "Style": "Style", + "Expand LOCATION": "Développer LIEU", + "Collapse panel": "Réduire le panneau", + "Pin location tray": "Épingler le tiroir des lieux", + "Keep location tray open": "Garder le tiroir des lieux ouvert", + "Search any location": "Rechercher n'importe quel lieu", + "Search location by name or coordinates": "Rechercher un lieu par nom ou coordonnées", + "Search any location...": "Rechercher n'importe quel lieu...", + "CONTEXT": "CONTEXTE", + "Compact Radio controls": "Commandes Radio compactes", + "Open detailed Radio controls": "Ouvrir les commandes Radio détaillées", + "Previous station": "Station précédente", + "Next station": "Station suivante", + "Compact Radio volume": "Volume de la Radio compacte", + "Expand panel": "Développer le panneau", + "Context mode": "Mode de contexte", + "CONTACTS": "CONTACTS", + "Cycles the nearest contacts of whatever type you select — planes, vessels, installations. Satellites track independently.": "Parcourt les contacts les plus proches du type sélectionné — avions, navires, installations. Les satellites sont suivis séparément.", + "SPACE MISSIONS": "MISSIONS SPATIALES", + "SELECT CONTEXT": "CHOISIR UN CONTEXTE", + "Contact Context actions": "Actions du contexte Contact", + "COCKPIT": "COCKPIT", + "SEARCH NEARBY SITES": "CHERCHER SITES PROCHES", + "Reclassify tracked contact as TR-3B": "Reclasser le contact suivi en TR-3B", + "CONTACTS CONTEXT OFF": "CONTEXTE CONTACTS DÉSACTIVÉ", + "SELECT CONTACTS TO LOAD OBSERVED / MAPPED PROXIMITY": "CHOISIR CONTACTS POUR CHARGER LA PROXIMITÉ OBSERVÉE / CARTOGRAPHIÉE", + "Available Space Missions": "Missions spatiales disponibles", + "AVAILABLE MISSIONS": "MISSIONS DISPONIBLES", + "SELECT A MISSION TO INSPECT": "CHOISIR UNE MISSION À EXAMINER", + "LOADING 30-DAY MISSION INDEX": "CHARGEMENT DE L'INDEX DES MISSIONS À 30 JOURS", + "TAB PREVIEWS · ENTER / SPACE SELECTS": "TAB APERÇU · ENTRÉE / ESPACE SÉLECTIONNE", + "Internet radio and local SDR": "Radio Internet et SDR local", + "STATION TAG": "TAG DE STATION", + "Filter stations by station tag": "Filtrer les stations par tag de station", + "All": "Tous", + "Enable Radio, then choose a globe marker or use next.": "Activez la Radio, puis choisissez un marqueur du globe ou utilisez suivant.", + "DRAG TO TUNE": "GLISSER POUR SYNTONISER", + "ALL · DRAG THE NEEDLE": "TOUTES · GLISSEZ L'AIGUILLE", + "SNAPS TO AVAILABLE STATIONS": "SE CALE SUR LES STATIONS DISPONIBLES", + "Radio playback": "Lecture radio", + "Previous filtered station": "Station filtrée précédente", + "Play selected station": "Lire la station sélectionnée", + "Next filtered station": "Station filtrée suivante", + "STOP": "ARRÊT", + "Stop radio playback": "Arrêter la lecture radio", + "Radio volume": "Volume de la radio", + "STATION SITE": "SITE DE STATION", + "Audio connects directly to the broadcaster after you press play. Your IP is visible to that broadcaster.": "Le flux audio se connecte directement au diffuseur après avoir appuyé sur lecture. Votre IP est visible par ce diffuseur.", + "Intelligence HUD (H)": "HUD de renseignement (H)", + "Layout": "Disposition", + "HUD layout": "Disposition du HUD", + "Tactical": "Tactique", + "Operator": "Opérateur", + "Minimal": "Minimal", + "Detection Overlay (D)": "Surcouche de détection (D)", + "Detection overlay": "Surcouche de détection", + "Detection label density": "Densité des étiquettes de détection", + "Allocation": "Allocation", + "Detection label allocation": "Allocation des étiquettes de détection", + "Elastic": "Élastique", + "Weighted": "Pondérée", + "Fade": "Fondu", + "Detection fade distance": "Distance de fondu de la détection", + "World-overlay fade distance outside the keyhole as a percentage of its radius": "Distance de fondu de la surcouche hors de l'ouverture, en pourcentage de son rayon", + "Outside": "Extérieur", + "Detection opacity outside the keyhole": "Opacité de la détection hors de l'ouverture", + "World-overlay label and card opacity beyond the fade distance": "Opacité des étiquettes et cartes de la surcouche au-delà de la distance de fondu", + "PARAMETERS": "PARAMÈTRES", + "3D aircraft — flat icons zoomed out, 3D models up close": "Aéronefs 3D — icônes plates de loin, modèles 3D de près", + "Models": "Modèles", + "3D model coverage": "Couverture des modèles 3D", + "Proximity": "Proximité", + "Scope — the circular viewport mask": "Scope — le masque circulaire de la vue", + "Scope": "Scope", + "Feather": "Adouci", + "Scope edge feather": "Adoucissement du bord du scope", + "Scope edge feather as a percentage of the keyhole radius": "Adoucissement du bord du scope, en pourcentage du rayon de l'ouverture", + "Celestial": "Céleste", + "Hide UI chrome": "Masquer l'interface", + "Clean UI": "Vue épurée", + "Bloom / Glow": "Bloom / Lueur", + "Bloom intensity": "Intensité du bloom", + "Sharpening": "Netteté", + "Sharpen": "Netteté", + "Sharpen intensity": "Intensité de la netteté", + "EXIT CLEAN VIEW": "QUITTER LA VUE ÉPURÉE", + "Return UI controls": "Rétablir les commandes de l'interface", + "Initializing photorealistic world...": "Initialisation du monde photoréaliste...", + "DATA LAYERS": "COUCHES DE DONNÉES", + "NEAREST": "PROCHE", + "CCTV camera": "Caméra CCTV", + "CALIBRATION": "CALIBRATION", + "Drag the camera in the world: rings rotate, arrows move, handles set range/FOV": "Faites glisser la caméra dans le monde : les anneaux pivotent, les flèches déplacent, les poignées règlent portée/FOV", + "Camera pose — click a value to type": "Pose de la caméra — cliquer sur une valeur pour la saisir", + "Heading (compass °) — click to type": "Cap (boussole °) — cliquer pour saisir", + "Pitch (° up/down) — click to type": "Inclinaison (° haut/bas) — cliquer pour saisir", + "Horizontal FOV (°) — click to type": "FOV horizontal (°) — cliquer pour saisir", + "Range / monitor-plane distance (m) — click to type": "Portée / distance du plan moniteur (m) — cliquer pour saisir", + "Mount height above ground (m) — click to type": "Hauteur de montage au-dessus du sol (m) — cliquer pour saisir", + "North offset from catalog position (m) — click to type": "Décalage nord par rapport à la position du catalogue (m) — cliquer pour saisir", + "East offset from catalog position (m) — click to type": "Décalage est par rapport à la position du catalogue (m) — cliquer pour saisir", + "SAVE CAL": "ENREG. CAL", + "RESET CAL": "RÉINIT. CAL", + "SCENE SUMMARY": "RÉSUMÉ DE SCÈNE", + "SCENES": "SCÈNES", + "Scene recipe": "Recette de scène", + "NEW": "NOUV.", + "CAPTURE SHOT": "CAPTURER UN PLAN", + "UPDATE SHOT": "MAJ DU PLAN", + "START": "LANCER", + "EXPORT PRESETS": "EXPORTER LES PRÉRÉGLAGES", + "IMPORT": "IMPORTER", + "RUN LOG": "JOURNAL", + "POWER UP": "POWER UP", + "GROUND STATION · PROVIDER SETTINGS": "STATION AU SOL · PARAMÈTRES DES FOURNISSEURS", + "Close key setup": "Fermer la configuration des clés", + "Power up the globe": "Allumer le globe", + "The globe already flies keyless. Every key below switches on another real feed — paste one and it's saved into this app's local configuration, then the server restarts itself. Server-side keys stay on this machine; Google Maps and Cesium ion run in the browser and must be provider-restricted. Keys you configured elsewhere are shown but never touched.": "Le globe fonctionne déjà sans clé. Chaque clé ci-dessous active un flux réel de plus : collez-en une et elle est enregistrée dans la configuration locale de l'application, puis le serveur redémarre. Les clés côté serveur restent sur cette machine ; Google Maps et Cesium ion s'exécutent dans le navigateur et doivent être restreintes au fournisseur. Les clés configurées ailleurs sont affichées mais jamais modifiées.", + "SAVE KEYS": "ENREGISTRER LES CLÉS", + "ESC to close": "ÉCHAP pour fermer", + "The Google Maps key buys the photorealistic planet — everything else stacks on top.": "La clé Google Maps offre la planète photoréaliste, tout le reste s'y superpose.", + "NO PLACE LEFT BEHIND": "NO PLACE LEFT BEHIND", + "ACTIVE STYLE": "STYLE ACTIF", + "Globe actions": "Actions du globe", + "Turn off all selected data layers": "Désactiver toutes les couches de données sélectionnées", + "Copy share link": "Copier le lien de partage", + "Reset camera and return to full globe view": "Réinitialiser la caméra et revenir à la vue du globe entier", + "MISSION CONTROL · FIRST LAUNCH": "CENTRE DE CONTRÔLE · PREMIER LANCEMENT", + "Choose your first view": "Choisissez votre première vue", + "LIVE CONTACTS": "CONTACTS LIVE", + "Aircraft, vessels and nearby intelligence": "Avions, navires et renseignements à proximité", + "Launches, spacecraft and orbital context": "Lancements, vaisseaux et contexte orbital", + "EXPLORE MANUALLY": "EXPLORER MANUELLEMENT", + "Begin with a clean globe": "Commencer avec un globe vierge", + "Don't show this again": "Ne plus afficher", + "ESC to dismiss": "ÉCHAP pour fermer", + "Tip: the GEV MIC button in the dock lets you talk to the map.": "Astuce : le bouton GEV MIC du dock permet de parler à la carte." +} From 7d7c535dc7e22ed8a38ad5134b6d996142fd3f8d Mon Sep 17 00:00:00 2001 From: Enzo Abyie Date: Wed, 28 Oct 2026 12:37:52 +0400 Subject: [PATCH 06/83] i18n(de): German strings from #908 The German locale by abiyeenzo (#908), converted from its namespaced JS catalogs to the English-keyed de.json: 859 entries whose English still matches the current UI. --- src/i18n/locales/de.json | 882 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 882 insertions(+) create mode 100644 src/i18n/locales/de.json diff --git a/src/i18n/locales/de.json b/src/i18n/locales/de.json new file mode 100644 index 000000000..f80420d3b --- /dev/null +++ b/src/i18n/locales/de.json @@ -0,0 +1,882 @@ +{ + "Flying to Austin, TX...": "Flug nach Austin, TX...", + "Restoring shared view...": "Geteilte Ansicht wird wiederhergestellt...", + "Configuring viewer...": "Viewer wird konfiguriert...", + "Loading Google 3D Tiles...": "Google 3D Tiles werden geladen...", + "Loading the keyless globe...": "Globus ohne Schlüssel wird geladen...", + "Google 3D Tiles unavailable ({detail}). Loading the keyless globe...": "Google 3D Tiles nicht verfügbar ({detail}). Globus ohne Schlüssel wird geladen...", + "Initializing systems...": "Systeme werden initialisiert...", + "Close data attribution": "Datenquellenhinweis schließen", + "UNAVAILABLE": "NICHT VERFÜGBAR", + "SOURCE": "QUELLE", + "Overpass rate-limited": "Overpass-Ratenlimit erreicht", + "Overpass timed out": "Zeitüberschreitung bei Overpass", + "Overpass could not complete the query": "Overpass konnte die Abfrage nicht abschließen", + "Overpass temporarily unavailable": "Overpass vorübergehend nicht verfügbar", + "Retrying mapped sites…": "Neuer Versuch für kartierte Standorte…", + "Fetching mapped sites…": "Kartierte Standorte werden abgerufen…", + "{reason} — retrying in {seconds}s": "{reason}: neuer Versuch in {seconds}s", + "{reason} — retry pending": "{reason}: neuer Versuch steht aus", + "Zoom in to search mapped installations": "Hineinzoomen, um kartierte Anlagen zu suchen", + "Showing cached mapped sites": "Kartierte Standorte aus dem Cache", + "Mapped sites not loaded": "Kartierte Standorte nicht geladen", + "Mapped sites loaded": "Kartierte Standorte geladen", + "feed unavailable": "Feed nicht verfügbar", + "feed stale": "Feed veraltet", + "observed or mapped nearby context": "beobachteter oder kartierter Kontext in der Nähe", + "no observed or mapped objects in current feeds": "keine beobachteten oder kartierten Objekte in den aktuellen Feeds", + "STATION": "STATION", + "Crewed stations and their visiting vehicles": "Bemannte Stationen und ihre Besucherfahrzeuge", + "NAV": "NAV", + "GNSS navigation — GPS, GLONASS, Galileo": "GNSS-Navigation: GPS, GLONASS, Galileo", + "GEO": "GEO", + "Geostationary belt — comms and weather, fixed over the equator": "Geostationärer Gürtel: Kommunikation und Wetter, fest über dem Äquator", + "VISUAL": "VISUELL", + "Brightest naked-eye objects — CelesTrak visual group": "Hellste Objekte mit bloßem Auge: CelesTrak-Gruppe visual", + "COMMS": "KOMM", + "Broadband constellation shell — shown only in DENSE mode": "Breitband-Konstellationsschale: nur im Modus DICHT sichtbar", + "FISHING": "FISCHEREI", + "TOWING": "SCHLEPPEN", + "DREDGER": "BAGGER", + "DIVE OPS": "TAUCHEINSATZ", + "MILITARY": "MILITÄR", + "SAILING": "SEGELN", + "PLEASURE": "SPORTBOOT", + "PILOT": "LOTSE", + "SAR": "SAR", + "TUG": "SCHLEPPER", + "PORT TENDER": "HAFENTENDER", + "ANTI-POLLUTION": "UMWELTSCHUTZ", + "LAW ENFORCE": "POLIZEI", + "MEDICAL": "MEDIZIN", + "HIGH-SPEED": "SCHNELLFAHRT", + "PASSENGER": "PASSAGIER", + "CARGO": "FRACHT", + "TANKER": "TANKER", + "OTHER": "SONSTIGE", + "ENVIRONMENTAL": "UMWELT", + "EARTH WATCH": "ERDBEOBACHTUNG", + "ACTIVE EVENTS": "AKTIVE EREIGNISSE", + "Starting live contacts…": "Live-Kontakte werden gestartet…", + "Opening space missions…": "Raummissionen werden geöffnet…", + "Scanning active events…": "Aktive Ereignisse werden gescannt…", + "Live earthquakes and active fires, from USGS and NASA": "Live-Erdbeben und aktive Brände, von USGS und NASA", + "It feels like a forbidden cockpit—then you realize the sources are public and the data is real.": "Es fühlt sich an wie ein verbotenes Cockpit—dann merkt man, dass die Quellen öffentlich und die Daten echt sind.", + "Working…": "In Arbeit…", + "Could not open that mission{detail}. Retry or explore manually.": "Mission{detail} konnte nicht geöffnet werden. Erneut versuchen oder manuell erkunden.", + "This browser is blocking storage, so that could not be saved.": "Dieser Browser blockiert den Speicher, daher konnte das nicht gespeichert werden.", + "CRT": "CRT", + "NVG": "NVG", + "FLIR": "FLIR", + "SNOW": "SCHNEE", + "LOADING": "LÄDT", + "DEGRADED": "EINGESCHRÄNKT", + "STALE": "VERALTET", + "PARTIAL": "TEILWEISE", + "FALLBACK": "FALLBACK", + "SUMMARY": "ÜBERSICHT", + "Awaiting telemetry...": "Warte auf Telemetrie...", + "REC": "REC", + "AIS: --": "AIS: --", + "POWER UP · {count} KEYS WAITING": { + "one": "STARTKLAR · {count} SCHLÜSSEL OFFEN", + "other": "STARTKLAR · {count} SCHLÜSSEL OFFEN" + }, + "POWERED UP": "HOCHGEFAHREN", + "Save failed ({status}).": "Speichern fehlgeschlagen ({status}).", + "REMOVE": "ENTFERNEN", + "Remove {title} from this app's saved keys": "{title} aus den gespeicherten Schlüsseln dieser App entfernen", + "your app configuration": "der App-Konfiguration", + "your local .env": "der lokalen .env", + "Saving…": "Speichern…", + "Save failed: {detail}": "Speichern fehlgeschlagen: {detail}", + "Paste at least one key first.": "Zuerst mindestens einen Schlüssel einfügen.", + "Saved to {store}. Restarting — this page reloads itself.": "In {store} gespeichert. Neustart läuft, diese Seite lädt sich selbst neu.", + "Remove this key from your saved configuration?": "Diesen Schlüssel aus der gespeicherten Konfiguration entfernen?", + "Removed from {store}. Restarting — this page reloads itself.": "Aus {store} entfernt. Neustart läuft, diese Seite lädt sich selbst neu.", + "Places context + Street View fallback; optional separate key": "Orts-Kontext + Street-View-Fallback; optional eigener Schlüssel", + "Live ships, worldwide": "Live-Schiffe, weltweit", + "Live active-fire detections": "Live-Erkennung aktiver Brände", + "Real live traffic (keyless runs a simulation)": "Echter Live-Verkehr (ohne Schlüssel: Simulation)", + "Bing imagery map stacks + world terrain": "Bing-Bildmaterial als Kartenstapel + Weltgelände", + "More flight-polling credits (anonymous works without)": "Mehr Abfrage-Credits für Flüge (anonym geht es auch ohne)", + "CONTEXT READY": "KONTEXT BEREIT", + "GLOBAL CONTEXT OFF": "GLOBALER KONTEXT AUS", + "SELECT A FLIGHT, VESSEL, OR MAPPED INSTALLATION": "FLUG, SCHIFF ODER KARTIERTE ANLAGE WÄHLEN", + "ENABLE TO LOAD OBSERVED / MAPPED PROXIMITY": "AKTIVIEREN, UM BEOBACHTETE / KARTIERTE NÄHE ZU LADEN", + "Unavailable": "Nicht verfügbar", + "Focus {label}": "{label} fokussieren", + "Global Context navigation": "Navigation des globalen Kontexts", + "Previous — prior visited contact in the 250 km window": "Zurück: zuvor besuchter Kontakt im 250-km-Fenster", + "PREVIOUS": "ZURÜCK", + "FOCUS": "FOKUS", + "Next — nearest unvisited contact in the 250 km window": "Weiter: nächster unbesuchter Kontakt im 250-km-Fenster", + "NEXT": "WEITER", + "Open-source mapped/observed context. Missing broadcasts, unloaded map areas, or unmapped sites are not evidence of absence.": "Kontext aus offenen Quellen, kartiert/beobachtet. Fehlende Funksignale, nicht geladene Kartenbereiche oder nicht kartierte Standorte sind kein Beleg für Abwesenheit.", + "HDG {value}°": "HDG {value}°", + "BRG {value}°": "PEIL {value}°", + "BRG —": "PEIL —", + "CRS {value}°": "KRS {value}°", + "CURRENT VIEWPORT ONLY": "NUR AKTUELLER BILDAUSSCHNITT", + "WITHIN {km} KM": "INNERHALB {km} KM", + "Flights": "Flüge", + "Military flights": "Militärflüge", + "AIS vessels": "AIS-Schiffe", + "Mapped installations": "Kartierte Anlagen", + "syncing {count} city feeds...": "{count} Stadt-Feeds werden synchronisiert...", + "scanning nearby systems...": "Systeme in der Nähe werden gesucht...", + "Station {id}": "Station {id}", + "Station": "Station", + "🚲 {bikes} avail · {docks} docks · {capacity} cap": "🚲 {bikes} frei · {docks} Docks · {capacity} Kap.", + "⚠️ Not installed": "⚠️ Nicht installiert", + "⚠️ Not renting": "⚠️ Keine Ausleihe", + "⚠️ Not returning": "⚠️ Keine Rückgabe", + "HDG {value}° (ESTIMATED)": "HDG {value}° (GESCHÄTZT)", + "{count} CAMERAS STANDING BY · NO CAMERA SELECTED · CLICK A CAMERA TO ACTIVATE": "{count} KAMERAS BEREIT · KEINE KAMERA GEWÄHLT · KAMERA ANKLICKEN ZUM AKTIVIEREN", + "No cameras available in catalog.": "Keine Kameras im Katalog verfügbar.", + "{city} CCTV": "{city} CCTV", + "FOV {value}°": "FOV {value}°", + "COVERAGE {value}km²": "ABDECKUNG {value}km²", + "OVERLAP {count} cams": "ÜBERLAPPUNG {count} Kam.", + "ISOLATED VIEW": "EINZELANSICHT", + "PROJ MONITOR": "PROJ MONITOR", + "PROJ OFF": "PROJ AUS", + "VIEWSHED": "SICHTBEREICH", + "CAL {value}": "KAL {value}", + "SRC {value}": "QUELLE {value}", + "{value} CONTEXT": "{value} KONTEXT", + "Focus fire detection {title}, {details}": "Branderkennung {title} fokussieren, {details}", + "{value} conf": "{value} Konf.", + "{value} ago": "vor {value}", + "sensor n/a": "Sensor k. A.", + "FIRE · {frp} MW": "BRAND · {frp} MW", + "NIGHT": "NACHT", + "▲ {frp} MW": "▲ {frp} MW", + "FIRE": "BRAND", + "FIRES": "BRÄNDE", + "max {value} MW": "max. {value} MW", + "new {value}": "neu {value}", + "just now": "gerade eben", + "<1m ago": "vor <1 min", + "{count}m ago": "vor {count} min", + "{count}h ago": "vor {count} h", + "STALE · cached {age}": "VERALTET · im Cache {age}", + "refreshing...": "wird aktualisiert...", + "loading...": "lädt...", + "KEY REQUIRED": "SCHLÜSSEL ERFORDERLICH", + "LIVE · updated {age}": "LIVE · aktualisiert {age}", + "loading mapped installation context": "Kontext der kartierten Anlage wird geladen", + "MAPPED INSTALLATION": "KARTIERTE ANLAGE", + "LAUNCH SITE · {site}": "STARTPLATZ · {site}", + "LAUNCH SITE": "STARTPLATZ", + "T−{time} · {mission}": "T−{time} · {mission}", + "LAUNCH STANDBY": "STARTBEREITSCHAFT", + "LIFTOFF · {mission}": "ABHEBEN · {mission}", + "ASCENT REPLAY · {mission}": "AUFSTIEGS-REPLAY · {mission}", + "ASCENT ESTIMATE · {mission}": "AUFSTIEGSSCHÄTZUNG · {mission}", + "STAGE RE-ENTRY / RECOVERY · {mission}": "STUFEN-WIEDEREINTRITT / BERGUNG · {mission}", + "ORBIT REPLAY · {mission}": "ORBIT-REPLAY · {mission}", + "PAUSED · {title}": "PAUSIERT · {title}", + "UNSPECIFIED": "NICHT ANGEGEBEN", + "+{count} additional payload records": "+{count} weitere Nutzlast-Einträge", + "PAYLOAD DATA UNAVAILABLE": "NUTZLASTDATEN NICHT VERFÜGBAR", + "{value} KM DOWNRANGE": "{value} KM DOWNRANGE", + "POSITION UNAVAILABLE": "POSITION NICHT VERFÜGBAR", + "FLIGHT {count}": "FLUG {count}", + "REUSED": "WIEDERVERWENDET", + "NO STAGE RE-ENTRY / RECOVERY DATA": "KEINE DATEN ZU STUFEN-WIEDEREINTRITT / BERGUNG", + "{count} / 30D": "{count} / 30T", + "NO MISSIONS AVAILABLE IN THE CURRENT 30-DAY WINDOW": "KEINE MISSIONEN IM AKTUELLEN 30-TAGE-FENSTER", + "DATE UNAVAILABLE": "DATUM NICHT VERFÜGBAR", + "UNSPECIFIED OPERATOR": "BETREIBER NICHT ANGEGEBEN", + "Select {mission}": "{mission} auswählen", + "{value} KM": "{value} KM", + "{value} KM/S": "{value} KM/S", + "SELECTED SPACE MISSION": "GEWÄHLTE RAUMMISSION", + "Show all missions": "Alle Missionen anzeigen", + "Deselect mission": "Mission abwählen", + "MISSION": "MISSION", + "STATUS · ": "STATUS · ", + "LAUNCH SITE · ": "STARTPLATZ · ", + "LAUNCH TIME · ": "STARTZEIT · ", + "ORBIT · ": "ORBIT · ", + "ASCENT PATH · ": "AUFSTIEGSPFAD · ", + "CURRENT DISTANCE FROM EARTH · ": "AKTUELLE ENTFERNUNG VON DER ERDE · ", + "SATELLITE SPEED · ": "SATELLITENGESCHW. · ", + "PAYLOAD": "NUTZLAST", + "NAME": "NAME", + "TYPE": "TYP", + "DESTINATION": "ZIEL", + "STAGE / RE-ENTRY / RECOVERY": "STUFE / WIEDEREINTRITT / BERGUNG", + "STAGE": "STUFE", + "STATUS": "STATUS", + "FINAL POSITION": "ENDPOSITION", + "REPLAY SPEED": "WIEDERGABETEMPO", + "Replay speed multiplier": "Faktor der Wiedergabegeschwindigkeit", + "REPLAY ASCENT": "AUFSTIEG ABSPIELEN", + "Previous mission": "Vorherige Mission", + "PREV": "ZURÜCK", + "Next mission": "Nächste Mission", + "SHOW ALL / DESELECT": "ALLE ZEIGEN / ABWÄHLEN", + "Pause replay": "Wiedergabe pausieren", + "Cancel replay": "Wiedergabe abbrechen", + "EST. DOWNRANGE": "GESCH. DOWNRANGE", + "PLANNED · ": "GEPLANT · ", + "SUPPLIED TRAJECTORY POINTS": "GELIEFERTE BAHNPUNKTE", + "RECONSTRUCTED ESTIMATE": "REKONSTRUIERTE SCHÄTZUNG", + "Replay the estimated ascent with a following camera": "Geschätzten Aufstieg mit folgender Kamera abspielen", + "Resume replay": "Wiedergabe fortsetzen", + "T minus {seconds}": "T minus {seconds}", + "Preparing launch site": "Startplatz wird vorbereitet", + "Liftoff": "Abheben", + "Ascent replay": "Aufstiegs-Replay", + "Orbit replay": "Orbit-Replay", + ", paused": ", pausiert", + "Alt unknown": "Höhe unbekannt", + "Type unknown": "Typ unbekannt", + "Reg unknown": "Kennz. unbekannt", + "Operator unknown": "Betreiber unbekannt", + "News": "Nachrichten", + "Talk": "Talk", + "Weather / Emergency": "Wetter / Notfall", + "Public Safety": "Öffentliche Sicherheit", + "Aviation / Marine": "Luftfahrt / Seefahrt", + "Traffic / Transit": "Verkehr / ÖPNV", + "Music": "Musik", + "Other": "Sonstige", + "radio|TALK": "TALK", + "radio|SAFETY": "SICHERH.", + "radio|AIR / SEA": "LUFT / SEE", + "radio|TRANSIT": "ÖPNV", + "radio|MUSIC": "MUSIK", + "Alternative": "Alternative", + "Ambient": "Ambient", + "Blues": "Blues", + "Classical": "Klassik", + "Country": "Country", + "Dance": "Dance", + "Electronic": "Elektronik", + "Folk": "Folk", + "Funk": "Funk", + "Hip-Hop": "Hip-Hop", + "House": "House", + "Indie": "Indie", + "Jazz": "Jazz", + "Latin": "Latin", + "Metal": "Metal", + "Oldies": "Oldies", + "Pop": "Pop", + "Punk": "Punk", + "R&B": "R&B", + "Reggae": "Reggae", + "Rock": "Rock", + "Soul": "Soul", + "Techno": "Techno", + "Trance": "Trance", + "World": "Weltmusik", + "Add the full Starlink broadband shell (thousands of extra points)": "Komplette Starlink-Breitbandschale hinzufügen (Tausende zusätzliche Punkte)", + "Loading the Starlink shell…": "Starlink-Schale wird geladen…", + "Starlink {detail} — click to retry": "Starlink {detail}: zum erneuten Versuch klicken", + "load failed": "Laden fehlgeschlagen", + "Showing the full Starlink shell — click for the core catalog only": "Komplette Starlink-Schale sichtbar: klicken für nur den Kernkatalog", + "DENSE ···": "DICHT ···", + "DENSE ✕": "DICHT ✕", + "DENSE": "DICHT", + "Syncing flow · Roads: {source}": "Verkehrsfluss wird synchronisiert · Straßen: {source}", + "LIVE · Roads: {source} · Roads without flow hidden": "LIVE · Straßen: {source} · Straßen ohne Verkehrsdaten ausgeblendet", + "LIVE · Roads: {source} · No flow roads in view": "LIVE · Straßen: {source} · Keine Straßen mit Verkehrsdaten im Bild", + "LIVE · Roads: {source} · Flow {percent}%": "LIVE · Straßen: {source} · Verkehr {percent}%", + "SIMULATED · Roads: {source} · Flow {percent}%": "SIMULIERT · Straßen: {source} · Verkehr {percent}%", + "Syncing flow · Roads: OpenStreetMap · Flow: TomTom · Unmatched: simulated": "Verkehrsfluss wird synchronisiert · Straßen: OpenStreetMap · Verkehr: TomTom · Ohne Zuordnung: simuliert", + "LIVE · Roads: OpenStreetMap · Flow: TomTom · {percent}% cov · Unmatched: simulated": "LIVE · Straßen: OpenStreetMap · Verkehr: TomTom · {percent}% Abd. · Ohne Zuordnung: simuliert", + "LIVE · Roads: OpenStreetMap · Flow: TomTom · {percent}% cov": "LIVE · Straßen: OpenStreetMap · Verkehr: TomTom · {percent}% Abd.", + "SIMULATED · Roads: OpenStreetMap · Flow: TomTom (no matches)": "SIMULIERT · Straßen: OpenStreetMap · Verkehr: TomTom (keine Treffer)", + "SIMULATED — traffic service unreachable": "SIMULIERT: Verkehrsdienst nicht erreichbar", + "SIMULATED — add TomTom key for live": "SIMULIERT: TomTom-Schlüssel für Live-Daten hinzufügen", + "AIS: {name}": "AIS: {name}", + "{type} SPD: {speed} HDG: {heading}": "{type} SPD: {speed} HDG: {heading}", + "VESSEL": "SCHIFF", + "POS: LIVE": "POS: LIVE", + "POS: {time}Z": "POS: {time}Z", + "awaiting first AIS position…": "warte auf erste AIS-Position…", + "awaiting usable AIS positions…": "warte auf nutzbare AIS-Positionen…", + "awaiting first AIS message…": "warte auf erste AIS-Nachricht…", + "Resume": "Fortsetzen", + "Pause": "Pause", + "Error: {message}": "Fehler: {message}", + "Needs {envVars} — add it in Provider Settings": "Benötigt {envVars}: in den Anbieter-Einstellungen hinzufügen", + "{label} is unavailable": "{label} ist nicht verfügbar", + "This map stack": "Dieser Kartenstapel", + "{label} unavailable: {hint}": "{label} nicht verfügbar: {hint}", + "Visible map targets": "Sichtbare Kartenziele", + "Ready": "Bereit", + "Loaded: {scene} / {shot}": "Geladen: {scene} / {shot}", + "Cannot capture shot: camera not ready": "Aufnahme nicht möglich: Kamera nicht bereit", + "Captured: {scene} / {shot}": "Aufgenommen: {scene} / {shot}", + "Select a shot first": "Zuerst eine Aufnahme wählen", + "Updated: {scene} / {shot}": "Aktualisiert: {scene} / {shot}", + "Camera unavailable — exit cockpit first": "Kamera nicht verfügbar: zuerst Cockpit verlassen", + "No shots to run": "Keine Aufnahmen zum Abspielen", + "Project exported": "Projekt exportiert", + "Could not exit {mode} — scene layers may be refused": "{mode} konnte nicht beendet werden: Szenenebenen werden eventuell abgelehnt", + "Running {index}/{total}: {scene} / {shot}": "Läuft {index}/{total}: {scene} / {shot}", + "Scene run complete": "Szenenlauf abgeschlossen", + "Global Flights Radar": "Globales Flugradar", + "Orbital Watch": "Orbitalwache", + "Thermal Threat Board": "Thermische Bedrohungslage", + "City Overload": "Stadt-Überlast", + "Omniscience Pullback": "Allwissenheits-Rückzug", + "Shot {n}": "Aufnahme {n}", + "Density": "Dichte", + "Bloom": "Bloom", + "VISUAL PRESETS": "VISUELLE PRESETS", + "LOCATION": "STANDORT", + "CONTACTS — nearest planes · vessels · sites": "KONTAKTE: nächste Flugzeuge · Schiffe · Standorte", + "SPACE MISSIONS — launches & orbital assets": "RAUMMISSIONEN: Starts & Orbit-Objekte", + "LIVE SIGNALS": "LIVE-SIGNALE", + "Contacts could not complete the requested transition; try again": "Kontakte konnten den gewünschten Wechsel nicht abschließen; erneut versuchen", + "CCTV layer unavailable": "CCTV-Ebene nicht verfügbar", + "Link copied!": "Link kopiert!", + "Copy failed": "Kopieren fehlgeschlagen", + "CCTV calibration saved": "CCTV-Kalibrierung gespeichert", + "CCTV calibration reset": "CCTV-Kalibrierung zurückgesetzt", + "ADJUST ON": "ANPASSEN EIN", + "ADJUST": "ANPASSEN", + "UNKNOWN": "UNBEKANNT", + "ERROR": "FEHLER", + "SOURCE · UNKNOWN": "QUELLE · UNBEKANNT", + "FRAME · LOADING": "FRAME · LÄDT", + "FRAME · UNAVAILABLE": "FRAME · NICHT VERFÜGBAR", + "CALIBRATED": "KALIBRIERT", + "CURATED": "KURATIERT", + "RAW PRIOR": "ROH-SCHÄTZUNG", + "CCTV ON": "CCTV EIN", + "CCTV OFF": "CCTV AUS", + "VIEWSHED ON": "SICHTBEREICH EIN", + "COVERAGE ON": "ABDECKUNG EIN", + "COVERAGE OFF": "ABDECKUNG AUS", + "AUTO HOP ON": "AUTO-WECHSEL EIN", + "AUTO HOP OFF": "AUTO-WECHSEL AUS", + "PROJECTION ON": "PROJEKTION EIN", + "PROJECTION OFF": "PROJEKTION AUS", + "CAL · EDITED (UNSAVED)": "KAL · GEÄNDERT (UNGESPEICHERT)", + "CAL · {badge}": "KAL · {badge}", + "MONITOR": "MONITOR", + "OFF": "AUS", + "{city} · HDG {heading} · FOV {fov} · RANGE {range}m · {projection}{calBadge} · {provider}{status}": "{city} · HDG {heading} · FOV {fov} · REICHW. {range}m · {projection}{calBadge} · {provider}{status}", + "{count} cameras loaded · click a camera to activate": { + "one": "{count} Kamera geladen · Kamera anklicken zum Aktivieren", + "other": "{count} Kameras geladen · Kamera anklicken zum Aktivieren" + }, + "{count} cameras loaded · enable CCTV to activate": { + "one": "{count} Kamera geladen · CCTV aktivieren", + "other": "{count} Kameras geladen · CCTV aktivieren" + }, + "Enable CCTV to load camera intersections": "CCTV aktivieren, um Kamerakreuzungen zu laden", + "Enable CCTV to start camera-linked intelligence summaries.": "CCTV aktivieren, um kameragestützte Lagezusammenfassungen zu starten.", + "No summary available.": "Keine Zusammenfassung verfügbar.", + "loading frames": "Frames werden geladen", + "camera grid ready": "Kameraraster bereit", + "Clearing selected data layers": "Ausgewählte Datenebenen werden gelöscht", + "Clear selected data layers": "Ausgewählte Datenebenen löschen", + "CONDITIONS UNKNOWN": "BEDINGUNGEN UNBEKANNT", + "CLEAR": "KLAR", + "PARTLY CLOUDY": "TEILS BEWÖLKT", + "OVERCAST": "BEDECKT", + "FOG": "NEBEL", + "DRIZZLE": "NIESELREGEN", + "RAIN": "REGEN", + "RAIN SHOWERS": "REGENSCHAUER", + "SNOW SHOWERS": "SCHNEESCHAUER", + "THUNDERSTORM": "GEWITTER", + "MIXED CONDITIONS": "WECHSELHAFT", + "CYCLE ON": "WECHSEL EIN", + "CYCLE OFF": "WECHSEL AUS", + "Stop automatic page cycling. Previous, Next, and the SIG/NEWS/LOCAL tabs stay available.": "Automatischen Seitenwechsel stoppen. Zurück, Weiter und die Tabs SIG/NEWS/LOKAL bleiben verfügbar.", + "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.": "Briefing-Seiten automatisch alle 9 Sekunden wechseln (Signale → News → Lokal). Pausiert, solange der Bereich überfahren oder fokussiert ist. Live-Signaldaten werden in beiden Fällen laufend aktualisiert.", + "ACQUIRING REGIONAL NEWS": "REGIONALE NEWS WERDEN ERFASST", + "REGIONAL NEWS UNAVAILABLE": "REGIONALE NEWS NICHT VERFÜGBAR", + "RESOLVING REGION": "REGION WIRD ERMITTELT", + "REGION UNAVAILABLE": "REGION NICHT VERFÜGBAR", + "NO RECENT LOCATION MATCHES": "KEINE AKTUELLEN ORTSTREFFER", + "{domain} · {age}": "{domain} · {age}", + "CLOUD {pct}%": "WOLKEN {pct}%", + "CLOUD UNKNOWN": "WOLKEN UNBEKANNT", + "{source} · LOCATION QUERY": "{source} · ORTSABFRAGE", + "REGIONAL NEWS": "REGIONALE NEWS", + "CONTEXT STANDBY": "KONTEXT STANDBY", + "ENABLE GLOBAL CONTEXT FOR PROXIMITY PINGS": "GLOBALEN KONTEXT FÜR NÄHE-PINGS AKTIVIEREN", + "CONTACT LOST · LAST KNOWN READOUT · NOT AN ALL-CLEAR": "KONTAKT VERLOREN · LETZTER STAND · KEINE ENTWARNUNG", + "CONTACT LOST · {subject}": "KONTAKT VERLOREN · {subject}", + "SUBJECT LEFT ITS FEED · READOUT HOLDING LAST KNOWN": "OBJEKT HAT SEINEN FEED VERLASSEN · ANZEIGE HÄLT LETZTEN STAND", + "{cohort} · {contact}": "{cohort} · {contact}", + "NO AVAILABLE EXAMPLE": "KEIN BEISPIEL VERFÜGBAR", + "{cohort}, Unavailable": "{cohort}, nicht verfügbar", + "AHEAD": "VORAUS", + "{side} {angle}": "{side} {angle}", + "L": "L", + "R": "R", + "{count} INPUTS UNKNOWN · NOT AN ALL-CLEAR": { + "one": "{count} EINGABE UNBEKANNT · KEINE ENTWARNUNG", + "other": "{count} EINGABEN UNBEKANNT · KEINE ENTWARNUNG" + }, + "AVAILABLE INPUTS CURRENT · NOT AN ALL-CLEAR": "VERFÜGBARE EINGABEN AKTUELL · KEINE ENTWARNUNG", + "AIRCRAFT": "FLUGZEUG", + "ACQUIRING SURFACE": "OBERFLÄCHE WIRD ERFASST", + "SURFACE FALLBACK": "OBERFLÄCHEN-FALLBACK", + "STALE FEED": "VERALTETER FEED", + "LIVE TRACK": "LIVE-TRACK", + "COMMERCIAL": "ZIVIL", + "{aircraftClass} · {feedState} · COURSE ALIGNED": "{aircraftClass} · {feedState} · KURS ANGEGLICHEN", + "ARROW · ESTIMATED DIRECTION": "PFEIL · GESCHÄTZTE RICHTUNG", + "ROUTE DATA UNAVAILABLE": "ROUTENDATEN NICHT VERFÜGBAR", + "DEST {bearing}": "ZIEL {bearing}", + "Disable cockpit weather effects": "Cockpit-Wettereffekte deaktivieren", + "Enable cockpit weather effects": "Cockpit-Wettereffekte aktivieren", + "ON": "EIN", + "Normal": "Normal", + "Night vision": "Nachtsicht", + "Thermal": "Thermal", + "Anime": "Anime", + "Noir": "Noir", + "Snow": "Schnee", + "Current cockpit vision style: {style}. Activate for next style.": "Aktueller Cockpit-Sichtstil: {style}. Aktivieren für den nächsten Stil.", + "Current style: {style} — click for next": "Aktueller Stil: {style}. Klicken für den nächsten", + "Collapse Contact panel": "Kontaktbereich einklappen", + "Expand Contact panel": "Kontaktbereich ausklappen", + "Collapse contact panel": "Kontaktbereich einklappen", + "Expand contact panel": "Kontaktbereich ausklappen", + "Collapse cockpit briefing panel": "Cockpit-Briefing-Bereich einklappen", + "Expand cockpit briefing panel": "Cockpit-Briefing-Bereich ausklappen", + "Collapse briefing panel": "Briefing-Bereich einklappen", + "Expand briefing panel": "Briefing-Bereich ausklappen", + "OBSERVED / MAPPED PINGS": "BEOBACHTETE / KARTIERTE PINGS", + "SOURCE-BACKED EVENTS · NO SYNTHETIC NEWS": "QUELLENBASIERTE EREIGNISSE · KEINE SYNTHETISCHEN NEWS", + "LATEST LOCATION-MATCHED REPORTING": "AKTUELLE ORTSBEZOGENE BERICHTERSTATTUNG", + "LOCAL INFO": "LOKALE INFOS", + "PLACE / CONDITIONS / POSITION": "ORT / BEDINGUNGEN / POSITION", + "TIME UNKNOWN": "ZEIT UNBEKANNT", + "{count}M AGO": "VOR {count} MIN", + "{count}H AGO": "VOR {count} STD", + "{count}D AGO": "VOR {count} T", + "DIR UNKNOWN": "RICHTUNG UNBEKANNT", + "Select flight {title}": "Flug {title} auswählen", + "{aircraftClass} · CURRENT": "{aircraftClass} · AKTUELL", + "MILITARY FLIGHT": "MILITÄRFLUG", + "COMMERCIAL FLIGHT": "ZIVILFLUG", + "{aircraftClass} · {distance}": "{aircraftClass} · {distance}", + "DISTANCE UNKNOWN": "DISTANZ UNBEKANNT", + "{count} INPUTS UNKNOWN": { + "one": "{count} EINGABE UNBEKANNT", + "other": "{count} EINGABEN UNBEKANNT" + }, + "SOURCE STATUS UNAVAILABLE": "QUELLENSTATUS NICHT VERFÜGBAR", + "Restore real aircraft": "Echtes Flugzeug wiederherstellen", + "Reclassify as TR-3B": "Als TR-3B umklassifizieren", + "TRACK ACQUIRED": "TRACK ERFASST", + "{label} · COURSE {heading}°": "{label} · KURS {heading}°", + "Context could not restore every layer; try again": "Kontext konnte nicht alle Ebenen wiederherstellen; erneut versuchen", + "No selected data layers": "Keine Datenebenen ausgewählt", + "{count} data layers could not be cleared": { + "one": "{count} Datenebene konnte nicht gelöscht werden", + "other": "{count} Datenebenen konnten nicht gelöscht werden" + }, + "Cleared {count} data layers": { + "one": "{count} Datenebene gelöscht", + "other": "{count} Datenebenen gelöscht" + }, + "Selected data layers could not be cleared": "Ausgewählte Datenebenen konnten nicht gelöscht werden", + "Space Missions could not complete the requested transition; try again": "Raummissionen konnten den gewünschten Wechsel nicht abschließen; erneut versuchen", + "Nearby installations refreshed": "Anlagen in der Nähe aktualisiert", + "Nearby installations could not be refreshed; try again": "Anlagen in der Nähe konnten nicht aktualisiert werden; erneut versuchen", + "Space Missions cancellation could not restore the previous layer state": "Abbruch der Raummissionen konnte den vorherigen Ebenenstatus nicht wiederherstellen", + "That layer is unavailable in the current Context mode": "Diese Ebene ist im aktuellen Kontextmodus nicht verfügbar", + "{layerId} could not {action} cleanly": "{layerId} konnte nicht sauber {action}", + "start": "starten", + "stop": "beenden", + "{mode} could not start because another layer did not stop cleanly": "{mode}: Start nicht möglich, da eine andere Ebene nicht sauber beendet wurde", + "Space Missions": "Raummissionen", + "Context": "Kontext", + "Live Flights": "Live-Flüge", + "Military Flights": "Militärflüge", + "Earthquakes (24h)": "Erdbeben (24 Std)", + "Satellites": "Satelliten", + "Space Missions (30d)": "Raummissionen (30 T)", + "Street Traffic": "Straßenverkehr", + "CCTV": "CCTV", + "Radio": "Radio", + "Bikeshare": "Bikesharing", + "Live AIS Vessels": "Live-AIS-Schiffe", + "Mapped Installations": "Kartierte Anlagen", + "Global Context": "Globaler Kontext", + "Datacenters": "Rechenzentren", + "Dams": "Staudämme", + "Submarine Cables": "Seekabel", + "FIRMS Active Fires": "FIRMS aktive Brände", + "ENABLING": "WIRD AKTIVIERT", + "DISABLING": "WIRD DEAKTIVIERT", + "{state} · {source}": "{state} · {source}", + "UNCERTAIN · {source} · lifecycle state requires reconciliation": "UNKLAR · {source} · Lebenszyklus-Status muss abgeglichen werden", + "{state} · {source} · {detail} · retry {seconds}s": "{state} · {source} · {detail} · neuer Versuch {seconds}s", + "{state} · {source} · {detail}": "{state} · {source} · {detail}", + "never": "nie", + "{source} · {loadingLabel}": "{source} · {loadingLabel}", + "{accepted} of {raw} records accepted": "{accepted} von {raw} Datensätzen übernommen", + "incomplete snapshot": "unvollständiger Snapshot", + "{state} · {source} · {detail} · {ago}": "{state} · {source} · {detail} · {ago}", + "{state} · {source} · {ago} · retrying in {seconds}s": "{state} · {source} · {ago} · neuer Versuch in {seconds}s", + "{state} · {source} · {ago}": "{state} · {source} · {ago}", + "{source} · {ago}": "{source} · {ago}", + "UNCERTAIN": "UNKLAR", + "{name}: {state}": "{name}: {state}", + "{count}s ago": "vor {count} s", + "CONNECTING": "VERBINDET", + "📍 Location: --": "📍 Standort: --", + "Landmark: --": "Wahrzeichen: --", + "Searched location": "Gesuchter Ort", + "ORBIT": "ORBIT", + "Location not found": "Ort nicht gefunden", + "Search failed": "Suche fehlgeschlagen", + "Fly to a POI first": "Zuerst zu einem POI fliegen", + "Reset to full globe view": "Auf Vollglobus-Ansicht zurücksetzen", + "Reset cockpit to full globe view": "Cockpit auf Vollglobus-Ansicht zurücksetzen", + "Resetting to full globe view": "Zurücksetzen auf Vollglobus-Ansicht", + "Resetting cockpit to full globe view": "Cockpit wird auf Vollglobus-Ansicht zurückgesetzt", + "MAP": "KARTE", + "panel": "Bereich", + "Expand {name}": "{name} ausklappen", + "Collapse {name}": "{name} einklappen", + "Expand Radio": "Radio ausklappen", + "Collapse Radio": "Radio einklappen", + "Expand Radio section": "Radio-Bereich ausklappen", + "Collapse Radio section": "Radio-Bereich einklappen", + "Panel layout updated — positions reset to new defaults": "Bereichslayout aktualisiert. Positionen auf neue Standards zurückgesetzt", + "Collapse Cockpit display options": "Cockpit-Anzeigeoptionen einklappen", + "Expand Cockpit display options": "Cockpit-Anzeigeoptionen aufklappen", + "Collapse Cockpit Radio controls": "Cockpit-Radio-Steuerung einklappen", + "Expand Cockpit Radio controls": "Cockpit-Radio-Steuerung aufklappen", + "NO STATIONS": "KEINE SENDER", + "NO STATION AVAILABLE": "KEIN SENDER VERFÜGBAR", + "{name}, station {index} of {total}": "{name}, Sender {index} von {total}", + "No station available": "Kein Sender verfügbar", + "OFF AIR": "NICHT AUF SENDUNG", + "STATION UNAVAILABLE": "SENDER NICHT VERFÜGBAR", + "Radio could not {action} cleanly": "Radio konnte nicht sauber {action}", + "Close compact Radio controls": "Kompakte Radio-Steuerung schließen", + "Open compact Radio controls": "Kompakte Radio-Steuerung öffnen", + "SYNC": "SYNC", + "RECONCILE": "ABGLEICHEN", + "DISABLE": "DEAKTIV.", + "ENABLE": "AKTIV.", + "Reconcile Radio — lifecycle uncertain": "Radio abgleichen: Lebenszyklus unklar", + "Disable Radio": "Radio deaktivieren", + "Enable Radio": "Radio aktivieren", + "DIRECTORY BAND": "VERZEICHNISBAND", + "{category} BAND": "{category}-BAND", + "NO STATION SELECTED": "KEIN SENDER GEWÄHLT", + "Directory metadata only": "Nur Verzeichnis-Metadaten", + "Loading station directory…": "Senderverzeichnis wird geladen…", + "Choose a globe marker or use next.": "Globus-Marker wählen oder Weiter nutzen.", + "TAGS · {tags}": "TAGS · {tags}", + "Play": "Abspielen", + "PLAY": "PLAY", + "selected": "gewählter", + "nearest": "nächster", + "{action} {target} radio station": "{action}: {target} Radiosender", + "RADIO STATE UNCERTAIN": "RADIOSTATUS UNKLAR", + "SYNCING DIRECTORY": "VERZEICHNIS WIRD SYNCHRONISIERT", + "RADIO READY": "RADIO BEREIT", + "SYNCING": "SYNC", + "READY": "BEREIT", + "station": "Sender", + " · stale/degraded directory": " · veraltetes/eingeschränktes Verzeichnis", + " · degraded directory": " · eingeschränktes Verzeichnis", + " · stale directory": " · veraltetes Verzeichnis", + " · outside current filter": " · außerhalb des aktuellen Filters", + "Ready — playback starts only from your action": "Bereit: Wiedergabe startet nur auf eigene Aktion", + "Radio off": "Radio aus", + "Connecting directly to broadcaster…": "Direktverbindung zum Sender wird aufgebaut…", + "Buffering broadcaster stream…": "Sender-Stream wird gepuffert…", + "Playing {station}": "{station} läuft", + "Paused {station}": "{station} pausiert", + "Broadcaster stream unavailable": "Sender-Stream nicht verfügbar", + " · muted during voice interaction": " · stumm bei Sprachinteraktion", + " · restoring volume after voice": " · Lautstärke wird nach Sprache wiederhergestellt", + " · static indicates no broadcaster audio": " · Rauschen bedeutet: kein Sender-Audio", + " · tuning static until broadcaster starts": " · Rauschen bis der Sender startet", + "Station unavailable after directory refresh — choose another channel": "Sender nach Verzeichnisaktualisierung nicht verfügbar: anderen Kanal wählen", + "Radio is enabling…": "Radio wird aktiviert…", + "Radio is disabling…": "Radio wird deaktiviert…", + "Radio lifecycle is uncertain — use Enable or Disable to reconcile": "Radio-Lebenszyklus unklar: zum Abgleichen Aktivieren oder Deaktivieren nutzen", + "Scene action failed": "Szenenaktion fehlgeschlagen", + "Delete shot \"{shot}\"?": "Aufnahme \"{shot}\" löschen?", + "SPARSE": "WENIG", + "BALANCED": "AUSGEWOGEN", + "DEL": "ENTF.", + "entity": "Objekt", + "Shared {subject} follow expired": "Geteilte Verfolgung abgelaufen: {subject}", + "Shared {subject} could not be restored — feed unavailable": "Geteilt: {subject} konnte nicht wiederhergestellt werden, Feed nicht verfügbar", + "Shared {subject} is unavailable": "Geteilt: {subject} ist nicht verfügbar", + "ACQUIRING": "ERFASSUNG", + "SHARED {subject}": "GETEILT: {subject}", + "LOADING LIVE DATA": "LIVE-DATEN WERDEN GELADEN", + "LOAD COMPLETE": "LADEN ABGESCHLOSSEN", + "LOAD CANCELLED": "LADEN ABGEBROCHEN", + "LOAD FAILED": "LADEN FEHLGESCHLAGEN", + "LIVE DATA OFF": "LIVE-DATEN AUS", + "MAPPED SITES LOADED": "KARTIERTE STANDORTE GELADEN", + "RETRYING MAPPED SITES": "KARTIERTE STANDORTE: NEUER VERSUCH", + "FETCHING MAPPED SITES": "KARTIERTE STANDORTE WERDEN ABGERUFEN", + "TURNING OFF LIVE DATA": "LIVE-DATEN WERDEN AUSGESCHALTET", + "REFRESHING LIVE DATA": "LIVE-DATEN WERDEN AKTUALISIERT", + "syncing road network": "Straßennetz wird synchronisiert", + "retry pending": "neuer Versuch steht aus", + "retrying in {seconds}s": "neuer Versuch in {seconds}s", + "Celestial ring — reveal the full globe": "Himmelsring: ganzen Globus zeigen", + "Celestial ring — available in Normal style": "Himmelsring: im Stil Normal verfügbar", + "Detection overlay: {mode}": "Erkennungs-Overlay: {mode}", + "Detection overlay: off": "Erkennungs-Overlay: aus", + "DETECT": "ERKENN.", + "voice|LISTENING": "HÖRT ZU", + "voice|EXECUTING": "FÜHRT AUS", + "AI AGENT": "KI-AGENT", + "Voice model tier — applies next session": "Sprachmodell-Stufe: gilt ab nächster Sitzung", + "Estimated session cost": "Geschätzte Sitzungskosten", + "Voice control — activate to toggle voice; hold Space to speak": "Sprachsteuerung: aktivieren zum Umschalten; Leertaste halten zum Sprechen", + "VOICE STANDBY": "SPRACHE STANDBY", + "VOICE CONTROL": "SPRACHSTEUERUNG", + "Hold Space to speak · tap Space to activate focused controls": "Leertaste halten zum Sprechen · Leertaste tippen für fokussierte Elemente", + "VOICE SYSTEM ERROR": "SPRACHSYSTEM-FEHLER", + "DISMISS": "SCHLIESSEN", + "Check microphone permission and network access, then try again.": "Mikrofonberechtigung und Netzwerkzugriff prüfen, dann erneut versuchen.", + "Release Space to send": "Leertaste loslassen zum Senden", + "Hold Space to talk": "Leertaste halten zum Sprechen", + "Requesting microphone": "Mikrofon wird angefragt", + "Ask or command": "Fragen oder Befehl geben", + "Running command": "Befehl läuft", + "Voice off": "Sprache aus", + "WebRTC microphone support unavailable": "WebRTC-Mikrofonunterstützung nicht verfügbar", + "VOICE UNAVAILABLE": "SPRACHE NICHT VERFÜGBAR", + "VOICE ACTIVE": "SPRACHE AKTIV", + "Voice session could not be started.": "Sprachsitzung konnte nicht gestartet werden.", + "Next session: {pendingId} — this session stays on {modelId}": "Nächste Sitzung: {pendingId}. Diese Sitzung bleibt bei {modelId}", + "Voice model: {pendingId} — click to switch to {target}; applies next session": "Sprachmodell: {pendingId}. Klicken zum Wechsel auf {target}; gilt ab nächster Sitzung", + "Estimated session cost on {modelId} — {responses} response(s). Warns at {warn}, ends the session at {cap}.": "Geschätzte Sitzungskosten mit {modelId}. {responses} Antwort(en). Warnung bei {warn}, Sitzungsende bei {cap}.", + "{tier} applies next session": "{tier} gilt ab nächster Sitzung", + "Session ended — cost cap {cost}": "Sitzung beendet: Kostenlimit {cost}", + "Radio did not start": "Radio wurde nicht gestartet", + "Aircraft cockpit view": "Flugzeug-Cockpitansicht", + "LEVEL": "HORIZONT", + "Estimated destination direction": "Geschätzte Richtung zum Ziel", + "DEST ---°": "ZIEL ---°", + "OPTICAL PLANE · 01": "OPTISCHE EBENE · 01", + "VISOR LOCK · ACTIVE": "VISIER-LOCK · AKTIV", + "GROUND SPEED · KTS": "GESCHW. ÜBER GRUND · KTS", + "ALTITUDE · FT": "HÖHE · FT", + "FIRST PERSON": "EGO-PERSPEKTIVE", + "LIVE TRACK · COURSE ALIGNED": "LIVE-TRACK · KURS ANGEGLICHEN", + "Cockpit vision style": "Sichtstil im Cockpit", + "Previous cockpit vision style": "Vorheriger Cockpit-Sichtstil", + "Previous vision style": "Vorheriger Sichtstil", + "Current cockpit vision style: NORMAL. Activate for next style.": "Aktueller Cockpit-Sichtstil: NORMAL. Aktivieren für den nächsten Stil.", + "Current style: NORMAL — click for next": "Aktueller Stil: NORMAL. Klicken für den nächsten", + "CURRENT": "AKTUELL", + "Next cockpit vision style": "Nächster Cockpit-Sichtstil", + "Next vision style": "Nächster Sichtstil", + "Current aircraft heading": "Aktueller Flugzeugkurs", + "GROUND SPEED": "GESCHW. ÜBER GRUND", + "ALTITUDE": "HÖHE", + "Contact cockpit summary": "Cockpit-Zusammenfassung des Kontakts", + "CONTACT": "KONTAKT", + "CONTACTS · 250 KM": "KONTAKTE · 250 KM", + "Contact navigation": "Kontaktnavigation", + "CONTEXT ONLY": "NUR KONTEXT", + "Nearby cohort counts": "Anzahl Kontakte in der Nähe", + "NEAREST OBSERVED / MAPPED": "NÄCHSTER BEOBACHTET / KARTIERT", + "AVAILABLE INPUTS ONLY · NOT AN ALL-CLEAR": "NUR VERFÜGBARE EINGABEN · KEINE ENTWARNUNG", + "Cockpit briefing carousel": "Cockpit-Briefing-Karussell", + "Estimated flight plan": "Geschätzter Flugplan", + "ESTIMATED FLIGHT PLAN": "GESCHÄTZTER FLUGPLAN", + "FROM": "VON", + "TO": "NACH", + "Cockpit briefing controls": "Cockpit-Briefing-Steuerung", + "Previous briefing page": "Vorherige Briefing-Seite", + "Next briefing page": "Nächste Briefing-Seite", + "Live signals": "Live-Signale", + "Latest regional news": "Aktuelle regionale Nachrichten", + "Location-based information": "Ortsbezogene Informationen", + "TEMP": "TEMP", + "WIND": "WIND", + "SKY": "HIMMEL", + "PRECIP": "NIEDERSCHL.", + "Show Live Signals": "Live-Signale anzeigen", + "NEWS": "NEWS", + "Show Regional News": "Regionale News anzeigen", + "Show Local Info": "Lokale Infos anzeigen", + "Cockpit display and Radio controls": "Cockpit-Anzeige und Radio-Steuerung", + "DISPLAY": "ANZEIGE", + "Cockpit display options": "Cockpit-Anzeigeoptionen", + "RADIO": "RADIO", + "Cockpit compact Radio controls": "Kompakte Cockpit-Radio-Steuerung", + "Previous filtered radio station": "Vorheriger gefilterter Radiosender", + "Play selected radio station": "Gewählten Radiosender abspielen", + "Next filtered radio station": "Nächster gefilterter Radiosender", + "VOLUME": "LAUTSTÄRKE", + "Cockpit Radio volume": "Cockpit-Radio-Lautstärke", + "View switcher": "Ansichtsumschalter", + "Exit cockpit and return to full globe view": "Cockpit verlassen und zur Vollglobus-Ansicht zurückkehren", + "RESET": "RESET", + "Exit cockpit view": "Cockpitansicht verlassen", + "EXIT COCKPIT": "COCKPIT VERLASSEN", + "Navigation, voice, and visual preset controls": "Steuerung für Navigation, Sprache und visuelle Presets", + "Expand Visual Presets": "Visuelle Presets aufklappen", + "Pin visual presets": "Visuelle Presets anheften", + "Keep visual presets open": "Visuelle Presets geöffnet lassen", + "Show the globe without a visual filter.": "Globus ohne visuellen Filter anzeigen.", + "Emulate a green phosphor CRT with scanlines and screen curvature.": "Grüne Phosphor-Röhre mit Zeilen und Bildschirmkrümmung nachahmen.", + "Simulate night-vision goggles with green intensification and a tube vignette.": "Nachtsichtgerät mit grüner Aufhellung und Röhrenvignette simulieren.", + "Simulate FLIR-style thermal contrast. Turn up Ironbow for color.": "FLIR-artigen Wärmekontrast simulieren. Ironbow aufdrehen für Farbe.", + "Apply bright cel-shaded color and illustrated outlines.": "Leuchtende Cel-Shading-Farben und gezeichnete Konturen anwenden.", + "Apply high-contrast monochrome film-noir grading.": "Kontrastreiche monochrome Film-noir-Farbgebung anwenden.", + "Add a cold, snowy whiteout treatment to the scene.": "Kalten, verschneiten Whiteout-Effekt auf die Szene legen.", + "MAP SOURCE": "KARTENQUELLE", + "Map source": "Kartenquelle", + "Style": "Stil", + "Expand LOCATION": "STANDORT aufklappen", + "Collapse panel": "Bereich einklappen", + "Pin location tray": "Standortleiste anheften", + "Keep location tray open": "Standortleiste geöffnet lassen", + "Search any location": "Beliebigen Ort suchen", + "Search location by name or coordinates": "Ort nach Name oder Koordinaten suchen", + "Search any location...": "Beliebigen Ort suchen...", + "WEATHER": "WETTER", + "CONTEXT": "KONTEXT", + "Compact Radio controls": "Kompakte Radio-Steuerung", + "Open detailed Radio controls": "Detaillierte Radio-Steuerung öffnen", + "Previous station": "Vorheriger Sender", + "Next station": "Nächster Sender", + "Compact Radio volume": "Lautstärke des kompakten Radios", + "Expand panel": "Bereich ausklappen", + "Context mode": "Kontextmodus", + "CONTACTS": "KONTAKTE", + "Cycles the nearest contacts of whatever type you select — planes, vessels, installations. Satellites track independently.": "Wechselt durch die nächsten Kontakte des gewählten Typs: Flugzeuge, Schiffe, Anlagen. Satelliten werden unabhängig verfolgt.", + "SPACE MISSIONS": "RAUMMISSIONEN", + "SELECT CONTEXT": "KONTEXT WÄHLEN", + "Contact Context actions": "Aktionen für Kontaktkontext", + "COCKPIT": "COCKPIT", + "SEARCH NEARBY SITES": "STANDORTE IN DER NÄHE SUCHEN", + "Reclassify tracked contact as TR-3B": "Verfolgten Kontakt als TR-3B umklassifizieren", + "CONTACTS CONTEXT OFF": "KONTAKTKONTEXT AUS", + "SELECT CONTACTS TO LOAD OBSERVED / MAPPED PROXIMITY": "KONTAKTE WÄHLEN, UM BEOBACHTETE / KARTIERTE NÄHE ZU LADEN", + "Available Space Missions": "Verfügbare Raummissionen", + "AVAILABLE MISSIONS": "VERFÜGBARE MISSIONEN", + "SELECT A MISSION TO INSPECT": "MISSION ZUM ANSEHEN WÄHLEN", + "LOADING 30-DAY MISSION INDEX": "30-TAGE-MISSIONSINDEX WIRD GELADEN", + "TAB PREVIEWS · ENTER / SPACE SELECTS": "TAB VORSCHAU · ENTER / LEERTASTE WÄHLT", + "Internet radio and local SDR": "Internetradio und lokales SDR", + "STATION TAG": "SENDER-TAG", + "Filter stations by station tag": "Sender nach Sender-Tag filtern", + "All": "Alle", + "Enable Radio, then choose a globe marker or use next.": "Radio aktivieren, dann einen Globus-Marker wählen oder Weiter nutzen.", + "DRAG TO TUNE": "ZUM ABSTIMMEN ZIEHEN", + "ALL · DRAG THE NEEDLE": "ALLE · NADEL ZIEHEN", + "SNAPS TO AVAILABLE STATIONS": "RASTET AUF VERFÜGBARE SENDER EIN", + "Radio playback": "Radiowiedergabe", + "Previous filtered station": "Vorheriger gefilterter Sender", + "Play selected station": "Gewählten Sender abspielen", + "Next filtered station": "Nächster gefilterter Sender", + "STOP": "STOPP", + "Stop radio playback": "Radiowiedergabe stoppen", + "Radio volume": "Radio-Lautstärke", + "STATION SITE": "SENDERSTANDORT", + "Audio connects directly to the broadcaster after you press play. Your IP is visible to that broadcaster.": "Audio verbindet sich nach dem Abspielen direkt mit dem Sender. Die IP-Adresse ist für diesen Sender sichtbar.", + "Intelligence HUD (H)": "Intelligence-HUD (H)", + "Layout": "Layout", + "HUD layout": "HUD-Layout", + "Tactical": "Taktisch", + "Operator": "Operator", + "Minimal": "Minimal", + "Detection Overlay (D)": "Erkennungs-Overlay (D)", + "Detection overlay": "Erkennungs-Overlay", + "Detection label density": "Dichte der Erkennungslabels", + "Allocation": "Zuteilung", + "Detection label allocation": "Zuteilung der Erkennungslabels", + "Elastic": "Elastisch", + "Weighted": "Gewichtet", + "Fade": "Ausblenden", + "Detection fade distance": "Ausblendeabstand der Erkennung", + "World-overlay fade distance outside the keyhole as a percentage of its radius": "Ausblendeabstand des Welt-Overlays außerhalb des Schlüssellochs, in Prozent seines Radius", + "Outside": "Außen", + "Detection opacity outside the keyhole": "Erkennungsdeckkraft außerhalb des Schlüssellochs", + "World-overlay label and card opacity beyond the fade distance": "Deckkraft von Welt-Overlay-Labels und -Karten jenseits des Ausblendeabstands", + "PARAMETERS": "PARAMETER", + "3D aircraft — flat icons zoomed out, 3D models up close": "3D-Flugzeuge: flache Symbole bei Fernsicht, 3D-Modelle aus der Nähe", + "Models": "Modelle", + "3D model coverage": "3D-Modellabdeckung", + "Proximity": "Nähe", + "Scope — the circular viewport mask": "Scope: die kreisrunde Ansichtsmaske", + "Scope": "Scope", + "Feather": "Weichzeichnung", + "Scope edge feather": "Weichzeichnung des Scope-Rands", + "Scope edge feather as a percentage of the keyhole radius": "Weichzeichnung des Scope-Rands in Prozent des Schlüsselloch-Radius", + "Celestial": "Himmel", + "Hide UI chrome": "Oberfläche ausblenden", + "Clean UI": "Reine Ansicht", + "Bloom / Glow": "Bloom / Glühen", + "Bloom intensity": "Bloom-Stärke", + "Sharpening": "Schärfen", + "Sharpen": "Schärfen", + "Sharpen intensity": "Schärfestärke", + "EXIT CLEAN VIEW": "REINE ANSICHT BEENDEN", + "Return UI controls": "Bedienelemente wieder einblenden", + "Initializing photorealistic world...": "Fotorealistische Welt wird initialisiert...", + "DATA LAYERS": "DATENEBENEN", + "NEAREST": "NÄCHSTE", + "CCTV camera": "CCTV-Kamera", + "CALIBRATION": "KALIBRIERUNG", + "Drag the camera in the world: rings rotate, arrows move, handles set range/FOV": "Kamera in der Welt ziehen: Ringe drehen, Pfeile verschieben, Griffe setzen Reichweite/FOV", + "Camera pose — click a value to type": "Kamerapose: Wert anklicken zum Eingeben", + "Heading (compass °) — click to type": "Ausrichtung (Kompass °): anklicken zum Eingeben", + "Pitch (° up/down) — click to type": "Neigung (° auf/ab): anklicken zum Eingeben", + "Horizontal FOV (°) — click to type": "Horizontales FOV (°): anklicken zum Eingeben", + "Range / monitor-plane distance (m) — click to type": "Reichweite / Abstand der Monitorebene (m): anklicken zum Eingeben", + "Mount height above ground (m) — click to type": "Montagehöhe über Grund (m): anklicken zum Eingeben", + "North offset from catalog position (m) — click to type": "Nordversatz zur Katalogposition (m): anklicken zum Eingeben", + "East offset from catalog position (m) — click to type": "Ostversatz zur Katalogposition (m): anklicken zum Eingeben", + "SAVE CAL": "KAL SPEICHERN", + "RESET CAL": "KAL ZURÜCKSETZEN", + "SCENE SUMMARY": "SZENEN-ÜBERSICHT", + "SCENES": "SZENEN", + "Scene recipe": "Szenenrezept", + "NEW": "NEU", + "CAPTURE SHOT": "AUFNAHME SPEICHERN", + "UPDATE SHOT": "AUFNAHME AKTUALISIEREN", + "START": "START", + "EXPORT PRESETS": "PRESETS EXPORTIEREN", + "IMPORT": "IMPORT", + "RUN LOG": "LAUFPROTOKOLL", + "POWER UP": "STARTKLAR", + "GROUND STATION · PROVIDER SETTINGS": "BODENSTATION · ANBIETER-EINSTELLUNGEN", + "Close key setup": "Schlüssel-Einrichtung schließen", + "Power up the globe": "Globus hochfahren", + "The globe already flies keyless. Every key below switches on another real feed — paste one and it's saved into this app's local configuration, then the server restarts itself. Server-side keys stay on this machine; Google Maps and Cesium ion run in the browser and must be provider-restricted. Keys you configured elsewhere are shown but never touched.": "Der Globus fliegt bereits ohne Schlüssel. Jeder Schlüssel unten schaltet einen weiteren echten Feed frei: Einfügen genügt, er wird in der lokalen Konfiguration dieser App gespeichert, danach startet der Server selbst neu. Serverseitige Schlüssel bleiben auf diesem Rechner; Google Maps und Cesium ion laufen im Browser und müssen auf den Anbieter beschränkt sein. Anderswo konfigurierte Schlüssel werden angezeigt, aber nie verändert.", + "SAVE KEYS": "SCHLÜSSEL SPEICHERN", + "ESC to close": "ESC zum Schließen", + "The Google Maps key buys the photorealistic planet — everything else stacks on top.": "Der Google-Maps-Schlüssel liefert den fotorealistischen Planeten, alles andere kommt obendrauf.", + "NO PLACE LEFT BEHIND": "KEIN ORT BLEIBT ZURÜCK", + "ACTIVE STYLE": "AKTIVER STIL", + "Globe actions": "Globus-Aktionen", + "Turn off all selected data layers": "Alle ausgewählten Datenebenen ausschalten", + "Copy share link": "Link zum Teilen kopieren", + "Reset camera and return to full globe view": "Kamera zurücksetzen und zur Vollglobus-Ansicht", + "MISSION CONTROL · FIRST LAUNCH": "MISSION CONTROL · ERSTER START", + "Choose your first view": "Erste Ansicht wählen", + "LIVE CONTACTS": "LIVE-KONTAKTE", + "Aircraft, vessels and nearby intelligence": "Flugzeuge, Schiffe und Aufklärung in der Nähe", + "Launches, spacecraft and orbital context": "Starts, Raumfahrzeuge und Orbit-Kontext", + "EXPLORE MANUALLY": "MANUELL ERKUNDEN", + "Begin with a clean globe": "Mit einem leeren Globus beginnen", + "Don't show this again": "Nicht mehr anzeigen", + "ESC to dismiss": "ESC zum Schließen", + "Tip: the GEV MIC button in the dock lets you talk to the map.": "Tipp: Mit der Taste GEV MIC im Dock lässt sich die Karte per Sprache steuern." +} From 2172183dc7581c3d1010c57dfea3064903eb6dc4 Mon Sep 17 00:00:00 2001 From: German Khokhlov Date: Wed, 28 Oct 2026 12:51:02 +0400 Subject: [PATCH 07/83] i18n(it): translate the remaining strings and review #912 - Translate the 1,868 strings #912 does not cover: directions, weather and wind, cyclones, Recent Imagery, Street Level, GNSS, the Bhote Koshi reconstruction, scenes and sharing, local SDR, voice and key setup. - Add the Italian `many` plural form (exact millions) to every plural entry. - Review the #912 entries: fix RIMORCHIATORE, POWER UP (ACCENDI), DENSO, minutes as "min", sentence case for layer and scene names, keyboard keys kept in English (Space, Enter), and the SIG/NOTIZIE/LOCALE tab names. - List codes, product names and words Italian spells as English in same-as-english.json. Co-Authored-By: Claude Opus 5.5 --- src/i18n/locales/it.json | 2199 ++++++++++++++++++++++++++++++++- src/i18n/same-as-english.json | 167 +++ 2 files changed, 2328 insertions(+), 38 deletions(-) diff --git a/src/i18n/locales/it.json b/src/i18n/locales/it.json index d5c65f04c..bf4df8736 100644 --- a/src/i18n/locales/it.json +++ b/src/i18n/locales/it.json @@ -1,4 +1,24 @@ { + "Pick a shape, then click the map.": "Scegli una forma, poi fai clic sulla mappa.", + "Enter to place the pin, Esc to cancel.": "Premi Enter per posizionare il segnaposto, Esc per annullare.", + "Click where the pin goes.": "Fai clic dove va il segnaposto.", + "Click {count} more points.": { + "one": "Fai clic su {count} altro punto.", + "many": "Fai clic su altri {count} di punti.", + "other": "Fai clic su altri {count} punti." + }, + "Those points are in a line — move one off it to enclose an area.": "Quei punti sono allineati: spostane uno fuori dalla linea per racchiudere un'area.", + "That line has no length — click somewhere further away.": "Quella linea non ha lunghezza: fai clic più lontano.", + " · {max}-point limit reached": " · raggiunto il limite di {max} punti", + "{measure} · double-click or Enter to finish, Backspace undoes, Esc cancels.{full}": "{measure} · doppio clic o Enter per finire, Backspace torna indietro, Esc annulla.{full}", + "drawings on the map": "disegni sulla mappa", + "That shape already has {count} points — finish it or press Backspace.": "Quella forma ha già {count} punti: finiscila o premi Backspace.", + "That point is off the globe — click on the world.": "Quel punto è fuori dal globo: fai clic sul mondo.", + "That shape could not be placed.": "Impossibile posizionare quella forma.", + "Could not place the shape: {error}": "Impossibile posizionare la forma: {error}", + "Board cleared.": "Lavagna cancellata.", + "{owner} is using the pointer — close it first.": "{owner} sta usando il puntatore: chiudilo prima.", + "{label} · Detailed outline unavailable": "{label} · Contorno dettagliato non disponibile", "Flying to Austin, TX...": "Volo verso Austin, TX...", "Restoring shared view...": "Ripristino della vista condivisa...", "Configuring viewer...": "Configurazione del visualizzatore...", @@ -6,12 +26,221 @@ "Loading the keyless globe...": "Caricamento del globo senza chiave...", "Google 3D Tiles unavailable ({detail}). Loading the keyless globe...": "Google 3D Tiles non disponibile ({detail}). Caricamento del globo senza chiave...", "Initializing systems...": "Inizializzazione dei sistemi...", + "Space Missions isolates replay data. Exit the mode to enable {layer}.": "Missioni spaziali isola i dati del replay. Esci dalla modalità per attivare {layer}.", + "Data attribution": "Attribuzione dei dati", + "Data provided by:": "Dati forniti da:", "Close data attribution": "Chiudi le attribuzioni dei dati", + "Light aircraft": "Aereo leggero", + "Glider": "Aliante", + "Turboprop": "Turboelica", + "Airliner": "Aereo di linea", + "Widebody": "Fusoliera larga", + "Four-engine jet": "Quadrigetto", + "Helicopter": "Elicottero", + "Fast jet": "Jet veloce", + "Business jet": "Business jet", + "Drone": "Drone", + "General emergency": "Emergenza generale", + "Unlawful interference": "Interferenza illecita", + "Radio failure": "Avaria radio", + "Downed aircraft": "Aeromobile abbattuto", + "Minimum fuel": "Carburante minimo", + "Lifeguard (medical priority)": "Lifeguard (priorità medica)", + "Rasuwagadhi witness video": "Video del testimone a Rasuwagadhi", + "Bhote Koshi valley footage": "Riprese della valle del Bhote Koshi", + "Flood footage": "Riprese dell'alluvione", + "Compilation and casualty claims": "Compilazione e dichiarazioni sulle vittime", + "SOURCE GEOCONFIRMED · WORLD-PINNED": "FONTE GEOCONFERMATA · ANCORATA AL MONDO", + "SOURCE CREDITED · LOCATION UNRESOLVED": "FONTE CITATA · POSIZIONE NON RISOLTA", + "REFERENCE ONLY · CLAIMS UNVERIFIED": "SOLO RIFERIMENTO · DICHIARAZIONI NON VERIFICATE", + "SOURCE GEOCONFIRMED": "FONTE GEOCONFERMATA", + "2021 historical reference versus 2026 post-event imagery; changes are cumulative and include the July 2025 Rasuwagadhi flood. Schematic downstream progression, not modeled arrival time; not an official hazard model.": "Riferimento storico 2021 contro immagini 2026 successive all'evento; i cambiamenti sono cumulativi e includono l'alluvione di Rasuwagadhi del luglio 2025. Progressione schematica a valle, non un tempo di arrivo modellato; non è un modello ufficiale di pericolosità.", + "Immediate collapse viewpoint": "Punto di vista sul crollo immediato", + "Collapse viewpoint": "Punto di vista sul crollo", + "Debris-dammed lake": "Lago di sbarramento da detriti", + "Dammed lake": "Lago di sbarramento", + "Second landslide": "Seconda frana", + "Gyirong border gate": "Valico di frontiera di Gyirong", + "Border gate": "Valico di frontiera", + "Timure evidence cluster": "Gruppo di prove di Timure", + "Mailung / Upper Trishuli bridge": "Ponte di Mailung / Alto Trishuli", + "Dandagaun viewpoint restaurant": "Ristorante panoramico di Dandagaun", + "Dandagaun viewpoint": "Punto panoramico di Dandagaun", + "Bidur - Trishuli bridge": "Ponte di Bidur - Trishuli", + "Bidur bridge": "Ponte di Bidur", + "Devighat / Taadi Khola Bridge": "Ponte di Devighat / Taadi Khola", + "Devighat bridge": "Ponte di Devighat", + "Facebook player API did not initialize.": "L'API del player di Facebook non si è inizializzata.", + "Facebook player API could not load.": "Impossibile caricare l'API del player di Facebook.", + "Facebook player API timed out.": "L'API del player di Facebook è andata in timeout.", + "X embed API did not initialize.": "L'API di incorporamento di X non si è inizializzata.", + "X embed could not load.": "Impossibile caricare l'incorporamento di X.", + "X embed timed out.": "L'incorporamento di X è andato in timeout.", "UNAVAILABLE": "NON DISPONIBILE", + "TIMEOUT": "TIMEOUT", + "BLOCKED": "BLOCCATO", "SOURCE": "FONTE", + "Facebook embed unavailable. The post may be private, removed, region-restricted, or blocked.": "Incorporamento di Facebook non disponibile. Il post potrebbe essere privato, rimosso, limitato per regione o bloccato.", + "Preloading {provider} media": "Precaricamento dei contenuti {provider}", + "LOADING X POST…": "CARICAMENTO POST DI X…", + "The X post is unavailable or cannot be embedded.": "Il post di X non è disponibile o non può essere incorporato.", + "X POST · PROVIDER CONTROLS": "POST DI X · CONTROLLI DEL PROVIDER", + "{reason} OPEN ORIGINAL.": "{reason} APRI L'ORIGINALE.", + "X embed unavailable": "Incorporamento di X non disponibile", + "FACEBOOK · PROVIDER CONTROLS": "FACEBOOK · CONTROLLI DEL PROVIDER", + "Facebook embed unavailable": "Incorporamento di Facebook non disponibile", + "AUTOPLAY BLOCKED · USE PROVIDER CONTROLS": "AUTOPLAY BLOCCATO · USA I CONTROLLI DEL PROVIDER", + "Embedded {provider} media for {source}": "Contenuto {provider} incorporato per {source}", + "witness source": "fonte testimone", + "Witness source": "Fonte testimone", + "{provider} · EMBEDDED SOURCE": "{provider} · FONTE INCORPORATA", + "OPEN ORIGINAL ↗": "APRI L'ORIGINALE ↗", + "{provider} media: {source}": "Contenuto {provider}: {source}", + "{provider} · PROVIDER CONTROLS": "{provider} · CONTROLLI DEL PROVIDER", + "YOUTUBE {state} · OPEN ORIGINAL": "YOUTUBE {state} · APRI L'ORIGINALE", + "INITIATION": "INNESCO", + "DAMMING": "SBARRAMENTO", + "SECONDARY FAILURE": "CEDIMENTO SECONDARIO", + "BORDER ARRIVAL": "ARRIVO AL CONFINE", + "PROPAGATION": "PROPAGAZIONE", + "DOWNSTREAM PASSAGE": "PASSAGGIO A VALLE", + "CONSEQUENCE": "CONSEGUENZA", + "DOWNSTREAM CONSEQUENCE": "CONSEGUENZA A VALLE", + "EVIDENCE": "PROVE", + "{year} HISTORICAL REFERENCE": "RIFERIMENTO STORICO {year}", + "{year} POST-EVENT": "{year} DOPO L'EVENTO", + "{count} GEOLOCATED SOURCE-MAP PLACEMENTS": { + "one": "{count} POSIZIONAMENTO GEOLOCALIZZATO SULLA MAPPA DELLE FONTI", + "many": "{count} DI POSIZIONAMENTI GEOLOCALIZZATI SULLA MAPPA DELLE FONTI", + "other": "{count} POSIZIONAMENTI GEOLOCALIZZATI SULLA MAPPA DELLE FONTI" + }, + "NO PREVIEW": "NESSUNA ANTEPRIMA", + "YouTube source": "Fonte YouTube", + "Facebook source": "Fonte Facebook", + "SOURCE LINK": "LINK ALLA FONTE", + "{publisher} / OPEN": "{publisher} / APRI", + "Bhote Koshi flood reconstruction controls": "Controlli della ricostruzione dell'alluvione del Bhote Koshi", + "EVENT RECONSTRUCTION · 26 AUG 2026": "RICOSTRUZIONE DELL'EVENTO · 26 AGO 2026", + "BHOTE KOSHI OUTBURST FLOOD": "ALLUVIONE DA SVUOTAMENTO DEL BHOTE KOSHI", + "Close event layer": "Chiudi il livello evento", + "OBSERVED IMAGERY": "IMMAGINI OSSERVATE", + "SCHEMATIC CORRIDOR": "CORRIDOIO SCHEMATICO", + "2021 HISTORICAL REFERENCE / 2026 POST-EVENT": "RIFERIMENTO STORICO 2021 / DOPO L'EVENTO 2026", + "Historical reference and post-event image split": "Confronto tra immagine storica di riferimento e immagine successiva all'evento", + "RECONSTRUCTION CLOCK": "OROLOGIO DELLA RICOSTRUZIONE", + "Schematic downstream progression": "Progressione schematica a valle", + "Story beat navigation": "Navigazione tra le tappe del racconto", + "Previous story beat": "Tappa precedente del racconto", + "CAUSE": "CAUSA", + "CAPTURE TIME UNVERIFIED": "ORA DI ACQUISIZIONE NON VERIFICATA", + "Next story beat": "Tappa successiva del racconto", + "▶ PLAY": "▶ RIPRODUCI", + "Play the next shot and continue through this scene": "Riproduci lo scatto successivo e prosegui con questa scena", + "▶ PLAY SCENE": "▶ RIPRODUCI SCENA", + "◉ CINEMATIC": "◉ CINEMATICA", + "↺ FULL STORY": "↺ STORIA COMPLETA", + "↗ OPEN ORIGINAL": "↗ APRI L'ORIGINALE", + "⌖ LOWER GORGE": "⌖ GOLA INFERIORE", + "FIELD REPORTS · {count}": "RAPPORTI DAL CAMPO · {count}", + "GEOLOCATIONS · {credit}": "GEOLOCALIZZAZIONI · {credit}", + "↗ OPEN PUBLIC MAP": "↗ APRI LA MAPPA PUBBLICA", + " Clouds are preserved from the source imagery.": " Le nuvole sono conservate dalle immagini di origine.", + "Rasuwagadhi witness": "Testimone a Rasuwagadhi", + "Open original source for {source}; capture time unverified": "Apri la fonte originale per {source}; ora di acquisizione non verificata", + "Historical reference and post-event image divider": "Divisore tra immagine storica di riferimento e immagine successiva all'evento", + "A historical reference {before} percent, B post-event {after} percent": "A riferimento storico {before} percento, B dopo l'evento {after} percento", + "■ RELEASE CAMERA": "■ RILASCIA LA CAMERA", + "Seek Nepal scene clock": "Scorri l'orologio della scena in Nepal", + "NEPAL SCENE CLOCK": "OROLOGIO SCENA NEPAL", + "… PLAYING SHOT": "… SCATTO IN RIPRODUZIONE", + "▶ PLAY SHOT": "▶ RIPRODUCI SCATTO", + "Ⅱ PAUSE": "Ⅱ PAUSA", + "↺ REPLAY CINEMATIC": "↺ RIVEDI CINEMATICA", + "↺ REPLAY": "↺ RIVEDI", + "… PLAYING SCENE": "… SCENA IN RIPRODUZIONE", + "Continue {scene} from next shot": "Continua {scene} dallo scatto successivo", + "current scene": "scena attuale", + "Replay the full reconstruction": "Rivedi l'intera ricostruzione", + "SCENE SHOT": "SCATTO DELLA SCENA", + "TIME UNVERIFIED": "ORA NON VERIFICATA", + "{count} SOURCES": { + "one": "{count} FONTE", + "many": "{count} DI FONTI", + "other": "{count} FONTI" + }, + "OUTSIDE IMAGERY SWIPE": "FUORI DAL CONFRONTO IMMAGINI", + "{scene} / AUTHORED SHOT": "{scene} / SCATTO D'AUTORE", + "NEPAL FLOOD INCIDENT": "ALLUVIONE IN NEPAL", + "Play {shot}": "Riproduci {shot}", + "current scene shot": "scatto della scena attuale", + "Play reconstruction": "Riproduci la ricostruzione", + "Load previous scene shot": "Carica lo scatto precedente della scena", + "Load next scene shot": "Carica lo scatto successivo della scena", + "SCHEMATIC CORRIDOR, NOT MODELED ARRIVAL TIME.": "CORRIDOIO SCHEMATICO, NON UN TEMPO DI ARRIVO MODELLATO.", + "Rasuwa · 26 Aug 2026": "Rasuwa · 26 ago 2026", + "Event reconstruction": "Ricostruzione dell'evento", + "BHOTE KOSHI FLOOD INCIDENT": "ALLUVIONE DEL BHOTE KOSHI", + "NEPAL · 26 AUG 2026": "NEPAL · 26 AGO 2026", + "USGS INITIAL REPORT": "RAPPORTO INIZIALE USGS", + "26 AUG 2026 · 08:37 NPT": "26 AGO 2026 · 08:37 NPT", + "28.2710° N · 85.5150° E": "28,2710° N · 85,5150° E", + "INITIAL M4.4 · RECLASSIFIED M5.2 LANDSLIDE": "INIZIALE M4.4 · RICLASSIFICATO FRANA M5.2", + "USGS EVENT us7000tbwb · OPEN SOURCE": "EVENTO USGS us7000tbwb · FONTE APERTA", + "Open the USGS initial report for the 26 August 2026 Nepal landslide": "Apri il rapporto iniziale USGS sulla frana del 26 agosto 2026 in Nepal", + "Show the Nepal context callout without a border or country fill": "Mostra il riquadro di contesto sul Nepal senza confine né riempimento del paese", + "Introduce Nepal, draw its border, then reveal the Bhote Koshi incident": "Presenta il Nepal, traccia il suo confine, poi mostra l'evento del Bhote Koshi", + "CITIES": "CITTÀ", + "Keep the regional incident context and introduce nearby city labels": "Mantieni il contesto regionale dell'evento e mostra le etichette delle città vicine", + "PLACES": "LUOGHI", + "Introduce the reconstruction scene key places from trigger to downstream": "Presenta i luoghi chiave della scena ricostruita, dall'innesco fino a valle", + "PATH": "PERCORSO", + "Animate the sourced cyan river-centerline route to Trishuli Bazaar": "Anima il percorso ciano lungo l'asse del fiume, da fonti, fino a Trishuli Bazaar", + "OVERVIEW": "PANORAMICA", + "Keep the completed flood path and location labels visible": "Mantieni visibili il percorso completo dell'alluvione e le etichette dei luoghi", + "RECORD": "REGISTRO", + "Reveal the trigger record while making a slow camera approach": "Mostra il registro dell'innesco con un lento avvicinamento della camera", + "{speed} kn": "{speed} kn", + "That file is not valid JSON.": "Quel file non è un JSON valido.", + "That JSON file is not GeoJSON.": "Quel file JSON non è GeoJSON.", + "That FeatureCollection has no features list.": "Quella FeatureCollection non ha un elenco di feature.", + "Every GeoJSON feature must have type Feature.": "Ogni feature GeoJSON deve avere type Feature.", + "That GeoJSON has invalid geometries.": "Quel GeoJSON ha geometrie non valide.", + "That GeoJSON contains an unsupported geometry.": "Quel GeoJSON contiene una geometria non supportata.", + "That GeoJSON has invalid coordinates.": "Quel GeoJSON ha coordinate non valide.", + "That file creates more than {limit} map objects (the limit).": "Quel file crea più di {limit} oggetti sulla mappa (il limite).", + "That file has more than {limit} style definitions and image links after cleanup (the limit).": "Quel file ha più di {limit} definizioni di stile e link a immagini dopo la pulizia (il limite).", + "That file has more than {limit} features (the limit).": "Quel file ha più di {limit} feature (il limite).", + "That file has more than {limit} points (the limit) across {features} features.": "Quel file ha più di {limit} punti (il limite) in {features} feature.", + "That file has more than {limit} points (the limit).": "Quel file ha più di {limit} punti (il limite).", + "That KMZ unpacks to more than the import limit.": "Quel KMZ, una volta estratto, supera il limite di importazione.", + "That KMZ is damaged and could not be unpacked.": "Quel KMZ è danneggiato e non è stato possibile estrarlo.", + "That KMZ is not a readable zip archive.": "Quel KMZ non è un archivio zip leggibile.", + "That KMZ uses a zip format this import does not read.": "Quel KMZ usa un formato zip che questa importazione non legge.", + "That KMZ is encrypted.": "Quel KMZ è crittografato.", + "That KMZ uses a compression method this import does not read.": "Quel KMZ usa un metodo di compressione che questa importazione non legge.", + "That KML has invalid geometry bounds.": "Quel KML ha limiti di geometria non validi.", + "That KML has invalid coordinates.": "Quel KML ha coordinate non valide.", + "That GPX file has no document.": "Quel file GPX non ha un documento .", + "That {format} file is not valid XML.": "Quel file {format} non è un XML valido.", + "That file has an unreadable image or exceeds the 16-megapixel image limit.": "Quel file ha un'immagine illeggibile o supera il limite di 16 megapixel per immagine.", + "That KML could not be read.": "Impossibile leggere quel KML.", + "That file has invalid point coordinates.": "Quel file ha coordinate dei punti non valide.", + "Ground heights are not available for that file. Try again when the map has loaded.": "Le quote del terreno non sono disponibili per quel file. Riprova quando la mappa è caricata.", + "That file took too long to read.": "La lettura di quel file ha richiesto troppo tempo.", + "Nothing to import.": "Niente da importare.", + "That file is larger than {size} MiB.": "Quel file supera i {size} MiB.", + "Only GeoJSON, KML, KMZ and GPX files can be imported.": "Si possono importare solo file GeoJSON, KML, KMZ e GPX.", + "That file has nothing to draw.": "Quel file non contiene nulla da disegnare.", + "That KMZ holds no KML document.": "Quel KMZ non contiene alcun documento KML.", + "That {format} file could not be read.": "Impossibile leggere quel file {format}.", + "That file has {count} map objects; the limit is {limit}.": "Quel file ha {count} oggetti sulla mappa; il limite è {limit}.", + "Ground heights could not be read. Try that file again.": "Impossibile leggere le quote del terreno. Riprova con quel file.", + "That file has invalid point graphics.": "Quel file ha grafiche dei punti non valide.", "Overpass rate-limited": "Overpass ha limitato le richieste", "Overpass timed out": "Overpass è andato in timeout", "Overpass could not complete the query": "Overpass non ha potuto completare la query", + "Map tiles temporarily unavailable": "Tile della mappa temporaneamente non disponibili", + "Mapped names temporarily unavailable": "Nomi mappati temporaneamente non disponibili", "Overpass temporarily unavailable": "Overpass temporaneamente non disponibile", "Retrying mapped sites…": "Nuovo tentativo sui siti mappati…", "Fetching mapped sites…": "Ricerca dei siti mappati…", @@ -21,10 +250,22 @@ "Showing cached mapped sites": "Siti mappati in cache", "Mapped sites not loaded": "Siti mappati non caricati", "Mapped sites loaded": "Siti mappati caricati", + "Military airfield": "Aeroporto militare", + "Naval base": "Base navale", + "Firing range": "Poligono di tiro", + "Military land": "Terreno militare", + "Mapped installation": "Installazione mappata", + "Military area": "Area militare", + "flight": "volo", + "military flight": "volo militare", + "satellite": "satellite", "feed unavailable": "feed non disponibile", "feed stale": "feed obsoleto", "observed or mapped nearby context": "contesto osservato o mappato nelle vicinanze", "no observed or mapped objects in current feeds": "nessun oggetto osservato o mappato nei feed attuali", + "Draw": "Disegno", + "Directions": "Indicazioni", + "Recent imagery": "Immagini recenti", "STATION": "STAZIONE", "Crewed stations and their visiting vehicles": "Stazioni con equipaggio e veicoli in visita", "NAV": "NAV", @@ -33,7 +274,7 @@ "Geostationary belt — comms and weather, fixed over the equator": "Fascia geostazionaria — comunicazioni e meteo, fissi sopra l'equatore", "VISUAL": "VISIVO", "Brightest naked-eye objects — CelesTrak visual group": "Oggetti più luminosi a occhio nudo — gruppo visual di CelesTrak", - "COMMS": "COMUN", + "COMMS": "TLC", "Broadband constellation shell — shown only in DENSE mode": "Shell della costellazione broadband — mostrato solo in modalità DENSO", "FISHING": "PESCA", "TOWING": "RIMORCHIO", @@ -44,7 +285,7 @@ "PLEASURE": "DIPORTO", "PILOT": "PILOTINA", "SAR": "SAR", - "TUG": "REBOCCATORE", + "TUG": "RIMORCHIATORE", "PORT TENDER": "TENDER PORTO", "ANTI-POLLUTION": "ANTINQUINAMENTO", "LAW ENFORCE": "FORZE ORDINE", @@ -54,6 +295,10 @@ "CARGO": "CARGO", "TANKER": "CISTERNA", "OTHER": "ALTRO", + "Included in bundle": "Incluso nel pacchetto", + "Missing bundle file — reimport its bundle": "File del pacchetto mancante: reimporta il suo pacchetto", + "Source configured; file checked when loaded": "Fonte configurata; file verificato al caricamento", + "Source unavailable": "Fonte non disponibile", "ENVIRONMENTAL": "AMBIENTE", "EARTH WATCH": "OSSERVATORIO TERRA", "ACTIVE EVENTS": "EVENTI ATTIVI", @@ -65,41 +310,182 @@ "Working…": "Operazione in corso…", "Could not open that mission{detail}. Retry or explore manually.": "Impossibile aprire quella missione{detail}. Riprova o esplora a mano.", "This browser is blocking storage, so that could not be saved.": "Questo browser blocca l'archiviazione, quindi non è stato possibile salvare.", + "NORMAL": "NORMALE", "CRT": "CRT", "NVG": "NVG", "FLIR": "FLIR", + "ANIME": "ANIME", + "NOIR": "NOIR", "SNOW": "NEVE", + "ARCTIC": "ARTICO", + "ANTARCTIC": "ANTARTIDE", + "NORTH AMERICA": "NORD AMERICA", + "SOUTH AMERICA": "SUD AMERICA", + "EUROPE": "EUROPA", + "AFRICA": "AFRICA", + "ASIA": "ASIA", + "OCEANIA": "OCEANIA", + "NORTHERN OCEANIC GRID": "GRIGLIA OCEANICA NORD", + "SOUTHERN OCEANIC GRID": "GRIGLIA OCEANICA SUD", "LOADING": "CARICAMENTO", "DEGRADED": "DEGRADATO", "STALE": "OBSOLETO", "PARTIAL": "PARZIALE", - "FALLBACK": "FALLBACK", + "FALLBACK": "RISERVA", + "{state} {layers}": "{state} {layers}", + "view band|STREET": "STRADA", + "view band|CITY": "CITTÀ", + "view band|METRO": "METRO", + "view band|REGIONAL": "REGIONALE", + "view band|GLOBAL": "GLOBALE", "SUMMARY": "RIEPILOGO", "Awaiting telemetry...": "In attesa di telemetria...", "REC": "REC", "AIS: --": "AIS: --", + "N/A": "N/D", + "{mode} {band} {locality} | {region} | ALT {alt} | WINDOW {window} | SUN {sun}° | ONA {ona}° | {zone}": " {mode} {band} {locality} | {region} | ALT {alt} | FINESTRA {window} | SOLE {sun}° | ONA {ona}° | {zone}", + "NEAR {poi} ({city}) {distance}": "VICINO A {poi} ({city}) {distance}", + "SECTOR {lat} {lon}": "SETTORE {lat} {lon}", + "hemisphere|N": "N", + "hemisphere|S": "S", + "hemisphere|E": "E", + "hemisphere|W": "O", "POWER UP · {count} KEYS WAITING": { - "one": "POWER UP · {count} CHIAVE IN ATTESA", - "other": "POWER UP · {count} CHIAVI IN ATTESA" + "one": "ACCENDI · {count} CHIAVE IN ATTESA", + "many": "ACCENDI · {count} DI CHIAVI IN ATTESA", + "other": "ACCENDI · {count} CHIAVI IN ATTESA" }, "POWERED UP": "ACCESO", + "Provider Settings does not answer proxied requests": "Impostazioni provider non risponde alle richieste tramite proxy", + "Provider Settings is disabled while sharing is enabled": "Impostazioni provider è disattivato mentre la condivisione è attiva", + "Provider Settings answers only the machine running the server": "Impostazioni provider risponde solo alla macchina su cui gira il server", + "Provider Settings answers only local hostnames": "Impostazioni provider risponde solo a nomi host locali", + "Provider Settings requires an exact local Origin": "Impostazioni provider richiede un'Origin locale esatta", + "Unrecognized Origin refused": "Origin non riconosciuta rifiutata", + "Cross-origin requests are refused": "Le richieste cross-origin sono rifiutate", + "Content-Type must be application/json": "Content-Type deve essere application/json", + "Method not allowed": "Metodo non consentito", + "Request too large": "Richiesta troppo grande", + "Invalid JSON": "JSON non valido", + "Body must be a JSON object of {ENV_VAR: value}": "Il corpo deve essere un oggetto JSON {ENV_VAR: value}", + "No keys provided": "Nessuna chiave fornita", + "At most {limit} keys per save": "Al massimo {limit} chiavi per salvataggio", + "Unknown key: {name}": "Chiave sconosciuta: {name}", + "{name} must be a string": "{name} deve essere una stringa", + "{name} is empty": "{name} è vuota", + "{name} is longer than any real key ({limit} max)": "{name} è più lunga di qualsiasi chiave reale (max {limit})", + "{name} may only contain printable characters with no spaces": "{name} può contenere solo caratteri stampabili senza spazi", + "{name} contains a character that is not valid in a key (#, quotes, $, \\, or backtick)": "{name} contiene un carattere non valido in una chiave (#, virgolette, $, \\ o backtick)", + "{name} is configured outside Provider Settings and can only be changed where it was set": "{name} è configurata fuori da Impostazioni provider e si può cambiare solo dove è stata impostata", + "The key was not saved: could not restrict the credential file to your account; nothing was saved": "La chiave non è stata salvata: impossibile limitare il file delle credenziali al tuo account; non è stato salvato nulla", + "The key was not saved: the existing configuration could not be read, so nothing was changed": "La chiave non è stata salvata: impossibile leggere la configurazione esistente, quindi non è cambiato nulla", + "Could not write the {store} store": "Impossibile scrivere nell'archivio {store}", "Save failed ({status}).": "Salvataggio non riuscito ({status}).", + "OAuth check failed: {detail}": "Verifica OAuth non riuscita: {detail}", + "Could not check ChatGPT sign-in. Try again.": "Impossibile verificare l'accesso a ChatGPT. Riprova.", + "VOICE AUTH · CHATGPT OAUTH": "AUTENTICAZIONE VOCE · CHATGPT OAUTH", + "VOICE AUTH · API KEY": "AUTENTICAZIONE VOCE · CHIAVE API", + "USE API KEY": "USA CHIAVE API", + "USE CHATGPT OAUTH": "USA CHATGPT OAUTH", + "Use OPENAI_API_KEY for the next cloud voice session": "Usa OPENAI_API_KEY per la prossima sessione vocale cloud", + "Use the signed-in local ChatGPT/Codex OAuth session for the next cloud voice session": "Usa la sessione OAuth locale di ChatGPT/Codex con accesso effettuato per la prossima sessione vocale cloud", + "Metered — a billing-enabled account": "A consumo: un account con fatturazione attiva", + "Optional paid token — public access works without one": "Token a pagamento opzionale: l'accesso pubblico funziona anche senza", + "Free key — register, paste, done": "Chiave gratuita: registrati, incolla, fatto", + "browser-side": "lato browser", + "This key runs in the browser by design — restrict it at the provider (see SECURITY.md)": "Questa chiave gira nel browser per progettazione: limitala presso il provider (vedi SECURITY.md)", + "configured externally": "configurata esternamente", + "Supplied by your environment, Keychain, or launcher — change it where it was set": "Fornita dal tuo ambiente, dal Portachiavi o dal launcher: cambiala dove è stata impostata", + "MANAGE ↗": "GESTISCI ↗", + "GET KEY ↗": "OTTIENI CHIAVE ↗", + "{envVar} saved — paste to replace": "{envVar} salvata: incolla per sostituirla", + "paste {envVar}": "incolla {envVar}", "REMOVE": "RIMUOVI", "Remove {title} from this app's saved keys": "Rimuovi {title} dalle chiavi salvate di questa app", + "unsaved provider keys": "chiavi provider non salvate", + "Project keys: {status}": "Chiavi del progetto: {status}", "your app configuration": "la configurazione della tua app", "your local .env": "il tuo .env locale", "Saving…": "Salvataggio…", "Save failed: {detail}": "Salvataggio non riuscito: {detail}", "Paste at least one key first.": "Incolla prima almeno una chiave.", "Saved to {store}. Restarting — this page reloads itself.": "Salvato ({store}). Riavvio in corso: questa pagina si ricarica da sola.", + "Cloud voice will use OPENAI_API_KEY on the next session.": "La voce cloud userà OPENAI_API_KEY dalla prossima sessione.", + "Checking local ChatGPT OAuth sign-in…": "Verifica dell'accesso OAuth locale a ChatGPT…", + "Could not check ChatGPT sign-in.": "Impossibile verificare l'accesso a ChatGPT.", + "ChatGPT OAuth selected for cloud voice. Your API key stays saved and available.": "ChatGPT OAuth selezionato per la voce cloud. La tua chiave API resta salvata e disponibile.", + "ChatGPT sign-in expired. Opening sign-in again…": "Accesso a ChatGPT scaduto. Riapertura dell'accesso…", + "Opening ChatGPT sign-in in your browser…": "Apertura dell'accesso a ChatGPT nel browser…", + "Could not start ChatGPT sign-in on this machine.": "Impossibile avviare l'accesso a ChatGPT su questa macchina.", + "Finish ChatGPT sign-in in the browser. Waiting for it to complete…": "Completa l'accesso a ChatGPT nel browser. In attesa del completamento…", + "ChatGPT sign-in timed out. Click {button} to try again.": "Accesso a ChatGPT scaduto. Fai clic su {button} per riprovare.", + "ChatGPT sign-in complete. OAuth will be used for the next cloud voice session.": "Accesso a ChatGPT completato. OAuth verrà usato per la prossima sessione vocale cloud.", "Remove this key from your saved configuration?": "Rimuovere questa chiave dalla configurazione salvata?", "Removed from {store}. Restarting — this page reloads itself.": "Rimosso ({store}). Riavvio in corso: questa pagina si ricarica da sola.", + "The photorealistic 3D planet, place search + Street View": "Il pianeta 3D fotorealistico, ricerca luoghi + Street View", "Places context + Street View fallback; optional separate key": "Contesto luoghi + fallback Street View; chiave separata opzionale", + "Voice control — API key or ChatGPT OAuth": "Controllo vocale: chiave API o ChatGPT OAuth", + "Gemini Live voice control": "Controllo vocale Gemini Live", "Live ships, worldwide": "Navi live, in tutto il mondo", "Live active-fire detections": "Rilevamenti live di incendi attivi", "Real live traffic (keyless runs a simulation)": "Traffico reale live (senza chiave usa una simulazione)", "Bing imagery map stacks + world terrain": "Stack mappa con immagini Bing + terreno globale", "More flight-polling credits (anonymous works without)": "Più crediti di polling voli (funziona anche in modo anonimo)", + "Street-level imagery and coverage in the Street Level layer. Free: register an app in the Mapillary developer dashboard and paste its Client Token": "Immagini a livello stradale e copertura nel livello Vista stradale. Gratis: registra un'app nella dashboard sviluppatori di Mapillary e incolla il suo Client Token", + "Public space-missions access needs no key. Leave blank for standard use; paid tokens only raise request limits.": "L'accesso pubblico alle missioni spaziali non richiede chiavi. Lascia vuoto per l'uso normale; i token a pagamento alzano solo i limiti di richieste.", + "Air quality request failed": "Richiesta della qualità dell'aria non riuscita", + "No readings available": "Nessuna lettura disponibile", + "No current readings": "Nessuna lettura attuale", + "{count} stations reporting": { + "one": "{count} stazione attiva", + "many": "{count} di stazioni attive", + "other": "{count} stazioni attive" + }, + "Highest air-quality readings in view": "Valori di qualità dell'aria più alti nella vista", + "Low": "Basso", + "Low health risk": "Rischio per la salute basso", + "Moderate": "Moderato", + "Moderate health risk": "Rischio per la salute moderato", + "High": "Alto", + "High health risk": "Rischio per la salute alto", + "Very High": "Molto alto", + "Very High health risk": "Rischio per la salute molto alto", + "Air quality": "Qualità dell'aria", + "Canada only · ECCC AQHI network": "Solo Canada · rete AQHI di ECCC", + "ECCC request timed out": "La richiesta a ECCC è andata in timeout", + "Malformed AQHI station response": "Risposta delle stazioni AQHI non valida", + "No AQHI stations available": "Nessuna stazione AQHI disponibile", + "Malformed AQHI observation response": "Risposta delle osservazioni AQHI non valida", + "Camera source temporarily unavailable": "Fonte delle telecamere temporaneamente non disponibile", + "Mapped camera locations": "Posizioni mappate delle telecamere", + "SHOW NEAREST": "MOSTRA LA PIÙ VICINA", + "Stop following the current object before navigating to a camera": "Smetti di seguire l'oggetto attuale prima di spostarti su una telecamera", + "Move to the nearest loaded camera and show its details": "Spostati sulla telecamera caricata più vicina e mostrane i dettagli", + "Camera badges": "Badge delle telecamere", + "Cyan cameras turn coral when selected. Wedges illustrate mapped direction, not measured coverage. Nearby cameras may be outside the screen.": "Le telecamere ciano diventano corallo quando selezionate. I settori indicano la direzione mappata, non la copertura misurata. Le telecamere vicine possono essere fuori dallo schermo.", + "{count} nearby · {onScreen} on screen": { + "one": "{count} vicina · {onScreen} sullo schermo", + "many": "{count} vicine · {onScreen} sullo schermo", + "other": "{count} vicine · {onScreen} sullo schermo" + }, + "{count} nearby": { + "one": "{count} vicina", + "many": "{count} vicine", + "other": "{count} vicine" + }, + "retrying mapped ALPR cameras": "nuovo tentativo telecamere ALPR mappate", + "loading mapped ALPR cameras": "caricamento telecamere ALPR mappate", + "No ALPR data for this area — US and Canada only": "Nessun dato ALPR per quest'area: solo USA e Canada", + "Zoom in to load mapped cameras": "Ingrandisci per caricare le telecamere mappate", + "Showing cached locations": "Posizioni in cache", + "Coverage limited — zoom in": "Copertura limitata: ingrandisci", + "No ALPR data for this area": "Nessun dato ALPR per quest'area", + "None on screen — nearby cameras are outside the view": "Nessuna sullo schermo: le telecamere vicine sono fuori dalla vista", + "ALPR camera": "Telecamera ALPR", + "Camera coverage unavailable": "Copertura telecamere non disponibile", + "OpenStreetMap · community mapped": "OpenStreetMap · mappatura della comunità", + "Overpass returned an incomplete camera response": "Overpass ha restituito una risposta incompleta sulle telecamere", + "At least {count}": "Almeno {count}", "CONTEXT READY": "CONTESTO PRONTO", "GLOBAL CONTEXT OFF": "CONTESTO GLOBALE OFF", "SELECT A FLIGHT, VESSEL, OR MAPPED INSTALLATION": "SELEZIONA UN VOLO, UNA NAVE O UN'INSTALLAZIONE MAPPATA", @@ -112,7 +498,13 @@ "FOCUS": "FOCUS", "Next — nearest unvisited contact in the 250 km window": "Successivo — contatto non visitato più vicino nella finestra di 250 km", "NEXT": "SUCC", + "Named areas ({n})": "Aree con nome ({n})", + "{distance} FLIGHT / VESSEL WINDOW": "FINESTRA VOLI / NAVI {distance}", "Open-source mapped/observed context. Missing broadcasts, unloaded map areas, or unmapped sites are not evidence of absence.": "Contesto mappato/osservato da fonti aperte. Trasmissioni mancanti, aree di mappa non caricate o siti non mappati non sono prova di assenza.", + "mapped matches within {km} km of the subject": "corrispondenze mappate entro {km} km dal soggetto", + "none mapped within {km} km; not a complete 250 km survey": "nessuna mappata entro {km} km; non è un rilevamento completo di 250 km", + "mapped matches from the loaded viewport": "corrispondenze mappate dalla vista caricata", + "viewport feed is not a complete 250 km survey": "il feed della vista non è un rilevamento completo di 250 km", "HDG {value}°": "HDG {value}°", "BRG {value}°": "BRG {value}°", "BRG —": "BRG —", @@ -125,9 +517,10 @@ "Mapped installations": "Installazioni mappate", "syncing {count} city feeds...": "sincronizzazione di {count} feed città...", "scanning nearby systems...": "scansione dei sistemi vicini...", + "GBFS fetch error": "Errore di recupero GBFS", "Station {id}": "Stazione {id}", "Station": "Stazione", - "🚲 {bikes} avail · {docks} docks · {capacity} cap": "🚲 {bikes} disp · {docks} stalli · {capacity} cap", + "🚲 {bikes} avail · {docks} docks · {capacity} cap": "🚲 {bikes} disp · {docks} stalli · {capacity} tot", "⚠️ Not installed": "⚠️ Non installata", "⚠️ Not renting": "⚠️ Noleggio non attivo", "⚠️ Not returning": "⚠️ Restituzione non attiva", @@ -135,7 +528,9 @@ "{count} CAMERAS STANDING BY · NO CAMERA SELECTED · CLICK A CAMERA TO ACTIVATE": "{count} TELECAMERE IN ATTESA · NESSUNA TELECAMERA SELEZIONATA · CLIC SU UNA TELECAMERA PER ATTIVARLA", "No cameras available in catalog.": "Nessuna telecamera disponibile nel catalogo.", "{city} CCTV": "CCTV {city}", + "FOV {value}° (DATASHEET)": "FOV {value}° (SCHEDA TECNICA)", "FOV {value}°": "FOV {value}°", + "SPEC FOV {span}° (CAPABILITY)": "FOV SPEC {span}° (CAPACITÀ)", "COVERAGE {value}km²": "COPERTURA {value}km²", "OVERLAP {count} cams": "SOVRAPP. {count} cam", "ISOLATED VIEW": "VISTA ISOLATA", @@ -145,7 +540,173 @@ "CAL {value}": "CAL {value}", "SRC {value}": "FONTE {value}", "{value} CONTEXT": "CONTESTO {value}", + "{spec} · SPECS: CCTV-DATABASE.COM": "{spec} · SPECIFICHE: CCTV-DATABASE.COM", + "Atlantic and eastern/central North Pacific; not worldwide cyclone coverage.": "Atlantico e Pacifico settentrionale orientale/centrale; non è una copertura mondiale dei cicloni.", + "Cyclone advisories unavailable": "Bollettini sui cicloni non disponibili", + "Cyclone data unavailable": "Dati sui cicloni non disponibili", + "Potential tropical cyclone": "Potenziale ciclone tropicale", + "Post-tropical cyclone": "Ciclone post-tropicale", + "Hurricane": "Uragano", + "Tropical storm": "Tempesta tropicale", + "Tropical depression": "Depressione tropicale", + "Subtropical storm": "Tempesta subtropicale", + "Subtropical depression": "Depressione subtropicale", + "Track and cone match this advisory": "Traccia e cono corrispondono a questo bollettino", + "Track/cone awaiting advisory {number}": "Traccia/cono in attesa del bollettino {number}", + "Track/cone unavailable": "Traccia/cono non disponibili", + "Cached advisory · stale source": "Bollettino in cache · fonte obsoleta", + "Loading advisories…": "Caricamento dei bollettini…", + "{count} active storms": { + "one": "{count} tempesta attiva", + "many": "{count} di tempeste attive", + "other": "{count} tempeste attive" + }, + "Position as of {time}": "Posizione alle {time}", + "Maximum sustained wind: {wind} · Pressure: {pressure}": "Vento massimo sostenuto: {wind} · Pressione: {pressure}", + "{name} · {classification} · Advisory {number} · issued {time}": "{name} · {classification} · Bollettino {number} · emesso {time}", + "No active NHC/CPHC systems": "Nessun sistema NHC/CPHC attivo", + "Advisories unavailable": "Bollettini non disponibili", + "Cyclones · NHC / CPHC": "Cicloni · NHC / CPHC", + "Atlantic · E/C Pacific": "Atlantico · Pacifico E/C", + "{storms} · {name} selected": "{storms} · {name} selezionata", + "Official advisory ↗": "Bollettino ufficiale ↗", + "Active NHC and CPHC cyclone advisories": "Bollettini attivi sui cicloni di NHC e CPHC", + "Wind unavailable": "Vento non disponibile", + "Advisory center / forecast track": "Centro del bollettino / traccia prevista", + "Center-track uncertainty cone": "Cono di incertezza della traccia del centro", + "Select a storm on the map, or choose a storm in the list to select it and move the camera. Click empty map space to clear the selection. NOAA NHC/CPHC advisory context. The cone describes forecast center-track uncertainty, not storm size or the full hazard area. Forecast point labels are source lead hours, not times computed from advisory issuance. Geometry follows the surface; height is not weather altitude. Consult the official advisory.": "Seleziona una tempesta sulla mappa, o scegline una nell'elenco per selezionarla e spostare la camera. Fai clic su un punto vuoto della mappa per annullare la selezione. Contesto dai bollettini NOAA NHC/CPHC. Il cono descrive l'incertezza prevista sulla traccia del centro, non le dimensioni della tempesta né l'intera area di pericolo. Le etichette dei punti di previsione sono le ore di anticipo della fonte, non orari calcolati dall'emissione del bollettino. La geometria segue la superficie; l'altezza non è la quota meteorologica. Consulta il bollettino ufficiale.", + "DRIVE": "AUTO", + "Drive": "In auto", + "WALK": "A PIEDI", + "Walk": "A piedi", + "BIKE": "BICI", + "Bike": "In bici", + "rate limited": "limite di richieste raggiunto", + "routing service is rate limited": "il servizio di percorsi ha raggiunto il limite di richieste", + "route leg too long": "tratta del percorso troppo lunga", + "route too long": "percorso troppo lungo", + "{error} — try again in a moment": "{error}: riprova tra un momento", + "Routing is rate limited — try again in a moment": "Il calcolo del percorso ha raggiunto il limite di richieste: riprova tra un momento", + "Routing unavailable (HTTP {status})": "Calcolo del percorso non disponibile (HTTP {status})", + "Routing unavailable": "Calcolo del percorso non disponibile", + "direction|left": "a sinistra", + "direction|right": "a destra", + "direction|slightly left": "leggermente a sinistra", + "direction|slightly right": "leggermente a destra", + "direction|sharply left": "nettamente a sinistra", + "direction|sharply right": "nettamente a destra", + "direction|straight": "dritto", + "direction|around": "in senso opposto", + "fork direction|left": "la sinistra", + "fork direction|right": "la destra", + "fork direction|slightly left": "leggermente a sinistra", + "fork direction|slightly right": "leggermente a destra", + "fork direction|sharply left": "nettamente a sinistra", + "fork direction|sharply right": "nettamente a destra", + "fork direction|straight": "dritto", + "lane direction|left": "di sinistra", + "lane direction|right": "di destra", + "lane direction|slightly left": "di sinistra", + "lane direction|slightly right": "di destra", + "lane direction|sharply left": "all'estrema sinistra", + "lane direction|sharply right": "all'estrema destra", + "lane direction|straight": "centrale", + "ordinal|{number}st": "{number}ª", + "ordinal|{number}nd": "{number}ª", + "ordinal|{number}rd": "{number}ª", + "ordinal|{number}th": "{number}ª", + "Head out on {road}": "Parti su {road}", + "Head out": "Parti", + "Arrive at your destination, on the left": "Arrivo a destinazione, sulla sinistra", + "Arrive at your destination, on the right": "Arrivo a destinazione, sulla destra", + "Arrive at your destination": "Arrivo a destinazione", + "Make a U-turn onto {road}": "Fai inversione a U su {road}", + "Make a U-turn": "Fai inversione a U", + "Continue straight onto {road}": "Prosegui dritto su {road}", + "Continue straight": "Prosegui dritto", + "Turn {direction} onto {road}": "Svolta {direction} su {road}", + "Turn {direction}": "Svolta {direction}", + "Turn onto {road}": "Svolta su {road}", + "maneuver|Turn": "Svolta", + "Continue {direction} onto {road}": "Prosegui {direction} su {road}", + "Continue {direction}": "Prosegui {direction}", + "At the end of the road, turn {direction} onto {road}": "Alla fine della strada, svolta {direction} su {road}", + "At the end of the road, turn {direction}": "Alla fine della strada, svolta {direction}", + "At the end of the road, continue onto {road}": "Alla fine della strada, prosegui su {road}", + "At the end of the road, continue": "Alla fine della strada, prosegui", + "Keep {direction} at the fork onto {road}": "Al bivio, tieni {direction} verso {road}", + "Keep {direction} at the fork": "Al bivio, tieni {direction}", + "Continue at the fork onto {road}": "Al bivio, prosegui verso {road}", + "Continue at the fork": "Al bivio, prosegui", + "Merge {direction} onto {road}": "Immettiti {direction} su {road}", + "Merge {direction}": "Immettiti {direction}", + "Merge onto {road}": "Immettiti su {road}", + "maneuver|Merge": "Immettiti", + "Take the ramp on the {direction} onto {road}": "Prendi la rampa {direction} verso {road}", + "Take the ramp on the {direction}": "Prendi la rampa {direction}", + "Take the ramp {direction} onto {road}": "Prendi la rampa {direction} verso {road}", + "Take the ramp {direction}": "Prendi la rampa {direction}", + "Take the ramp onto {road}": "Prendi la rampa verso {road}", + "Take the ramp": "Prendi la rampa", + "Take the exit on the {direction} onto {road}": "Prendi l'uscita {direction} verso {road}", + "Take the exit on the {direction}": "Prendi l'uscita {direction}", + "Take the exit {direction} onto {road}": "Prendi l'uscita {direction} verso {road}", + "Take the exit {direction}": "Prendi l'uscita {direction}", + "Take the exit onto {road}": "Prendi l'uscita verso {road}", + "Take the exit": "Prendi l'uscita", + "At the roundabout, take the {exit} exit onto {road}": "Alla rotonda, prendi la {exit} uscita verso {road}", + "At the roundabout, take the {exit} exit": "Alla rotonda, prendi la {exit} uscita", + "Enter the roundabout onto {road}": "Entra nella rotonda verso {road}", + "Enter the roundabout": "Entra nella rotonda", + "At the roundabout, turn {direction} onto {road}": "Alla rotonda, svolta {direction} su {road}", + "At the roundabout, turn {direction}": "Alla rotonda, svolta {direction}", + "At the roundabout, continue onto {road}": "Alla rotonda, prosegui su {road}", + "At the roundabout, continue": "Alla rotonda, prosegui", + "Exit the roundabout onto {road}": "Esci dalla rotonda su {road}", + "Exit the roundabout": "Esci dalla rotonda", + "Use the {direction} lane onto {road}": "Usa la corsia {direction} verso {road}", + "Use the {direction} lane": "Usa la corsia {direction}", + "Continue onto {road}": "Prosegui su {road}", + "maneuver|Continue": "Prosegui", + "{mode} — reroute for {modeLower}": "{mode} — ricalcola il percorso {modeLower}", + "CLICK MAP": "CLIC SULLA MAPPA", + "SET A": "IMPOSTA A", + "Click a spot on the globe to place A (click again to cancel)": "Fai clic su un punto del globo per posizionare A (clic di nuovo per annullare)", + "Then click the globe to place the start": "Poi fai clic sul globo per posizionare la partenza", + "SET B": "IMPOSTA B", + "Click a spot on the globe to place B (click again to cancel)": "Fai clic su un punto del globo per posizionare B (clic di nuovo per annullare)", + "Then click the globe to place the destination": "Poi fai clic sul globo per posizionare la destinazione", + "Swap A and B": "Scambia A e B", + "FLY ···": "VOLA ···", + "FLYING": "IN VOLO", + "FLY": "VOLA", + "Fly the camera along the route": "Fai volare la camera lungo il percorso", + "Place A and B first": "Posiziona prima A e B", + "action|CLEAR": "CANCELLA", + "Remove the route and both markers": "Rimuovi il percorso ed entrambi i marcatori", + "press Escape twice to leave Draw": "premi Esc due volte per uscire da Disegno", + "{name} is active — turn {name} off, then set {endpoint}": "{name} è attivo: disattiva {name}, poi imposta {endpoint}", + "{name} is active — {leave}, then set {endpoint}": "{name} è attivo: {leave}, poi imposta {endpoint}", + "Only the first {count} turns of this route are shown": "Sono mostrate solo le prime {count} svolte di questo percorso", + "Turn-by-turn directions": "Indicazioni passo passo", + "Another map tool is using clicks — close it, then SET A again": "Un altro strumento della mappa sta usando i clic: chiudilo, poi IMPOSTA A di nuovo", + "Routing…": "Calcolo del percorso…", + "No route found": "Nessun percorso trovato", + "{distance} · {duration} · {mode} · first {count} turns": "{distance} · {duration} · {mode} · prime {count} svolte", + "{distance} · {duration} · {mode}": "{distance} · {duration} · {mode}", + "Click the globe to place {endpoint}": "Fai clic sul globo per posizionare {endpoint}", + "SET B, then click the globe": "IMPOSTA B, poi fai clic sul globo", + "SET A, then click the globe": "IMPOSTA A, poi fai clic sul globo", + "Step {step} of {total} · then {leg}": "Passo {step} di {total} · poi {leg}", + "Step {step} of {total}": "Passo {step} di {total}", + "Then: {instruction}": "Poi: {instruction}", + "No route found between A and B": "Nessun percorso trovato tra A e B", + "Routing failed: {error}": "Calcolo del percorso non riuscito: {error}", + "Routing timed out": "Il calcolo del percorso è andato in timeout", + "Routing unavailable — no response from the routing service": "Calcolo del percorso non disponibile: nessuna risposta dal servizio", + "Earthquake source unavailable": "Fonte dei terremoti non disponibile", "Focus fire detection {title}, {details}": "Focus sul rilevamento incendio {title}, {details}", + "live feed unavailable": "feed live non disponibile", "{value} conf": "{value} conf", "{value} ago": "{value} fa", "sensor n/a": "sensore n/d", @@ -156,17 +717,93 @@ "FIRES": "INCENDI", "max {value} MW": "max {value} MW", "new {value}": "nuovo {value}", + "{value}°N": "{value}°N", + "{value}°S": "{value}°S", + "{value}°E": "{value}°E", + "{value}°W": "{value}°O", "just now": "adesso", - "<1m ago": "<1m fa", - "{count}m ago": "{count}m fa", - "{count}h ago": "{count}h fa", + "<1m ago": "<1 min fa", + "{count}m ago": "{count} min fa", + "{count}h ago": "{count} h fa", + "fire confidence|high": "alta", + "fire confidence|nominal": "nominale", + "fire confidence|low": "bassa", + "age|<1h": "<1 h", + "age|{count}h": "{count} h", + "age|{count}d": "{count} g", "STALE · cached {age}": "OBSOLETO · in cache {age}", "refreshing...": "aggiornamento...", "loading...": "caricamento...", "KEY REQUIRED": "CHIAVE RICHIESTA", "LIVE · updated {age}": "LIVE · aggiornato {age}", + "Source snapshot time unavailable": "Ora dello snapshot della fonte non disponibile", + "Live data unavailable": "Dati live non disponibili", + "Intel Picture": "Quadro intelligence", + "Kinetic 30d": "Cinetico 30 g", + "Border Crisis": "Crisi di confine", + "Iran Picture": "Quadro Iran", + "Iran Kinetic": "Iran cinetico", + "Yemen FLOT": "FLOT Yemen", + "Latest Drop": "Ultima pubblicazione", + "GhostMaps file could not be read": "Impossibile leggere il file GhostMaps", + "{count} source links ↗ · click card to open the first": { + "one": "{count} link alla fonte ↗ · clic sulla scheda per aprirlo", + "many": "{count} di link alle fonti ↗ · clic sulla scheda per aprire il primo", + "other": "{count} link alle fonti ↗ · clic sulla scheda per aprire il primo" + }, + "S2 · {name}": "S2 · {name}", + "Report": "Rapporto", + "Open the source for {title}": "Apri la fonte di {title}", + "GhostMaps catalog unavailable": "Catalogo GhostMaps non disponibile", + "LIVE · GitHub {commit} · {message} · checked every {seconds}s": "LIVE · GitHub {commit} · {message} · controllato ogni {seconds}s", + "GitHub {commit} · {message} · reconnecting for live updates": "GitHub {commit} · {message} · riconnessione per gli aggiornamenti live", + "Connecting to the S2 GhostMaps repository…": "Connessione al repository S2 GhostMaps…", + "{count} placemarks": { + "one": "{count} segnaposto", + "many": "{count} di segnaposto", + "other": "{count} segnaposto" + }, + "S2 Underground publishes these KMZ products to GitHub. New uploads are detected within seconds and replace the previous edition automatically. Click a marker for its report.": "S2 Underground pubblica questi prodotti KMZ su GitHub. I nuovi caricamenti vengono rilevati in pochi secondi e sostituiscono automaticamente l'edizione precedente. Fai clic su un marcatore per il suo rapporto.", + "Malformed GhostMaps catalog": "Catalogo GhostMaps non valido", + "Low-accuracy score < 2%": "Indice di bassa precisione < 2%", + "Low-accuracy score 2–10%": "Indice di bassa precisione 2–10%", + "Low-accuracy score > 10%": "Indice di bassa precisione > 10%", + "GNSS integrity source unavailable": "Fonte di integrità GNSS non disponibile", + "Regional sample · 250 nm radius · cells from visited views over 30 min": "Campione regionale · raggio di 250 NM · celle dalle viste visitate negli ultimi 30 min", + "Retrying automatically at {time} UTC": "Nuovo tentativo automatico alle {time} UTC", + "Retrying automatically after provider cooldown": "Nuovo tentativo automatico dopo la pausa del provider", + "Updates automatically after pan or zoom and once a minute. The public feed covers a 250-nautical-mile circle around the view centre; zooming out does not make it a worldwide snapshot. Blank cells are outside sampled coverage or have insufficient observations.": "Si aggiorna automaticamente dopo uno spostamento o uno zoom e una volta al minuto. Il feed pubblico copre un cerchio di 250 miglia nautiche attorno al centro della vista; allontanare lo zoom non lo rende un'istantanea mondiale. Le celle vuote sono fuori dalla copertura campionata o hanno osservazioni insufficienti.", + "Low-accuracy score = 100 × max(0, bad − 1) / total: one aircraft is discounted, so this is not the raw share. Cells need {aircraft} aircraft over {minutes} minutes. Navigation-integrity anomalies are not a detection of jamming or spoofing.": "Indice di bassa precisione = 100 × max(0, anomali − 1) / totale: un aereo viene scontato, quindi non è la quota grezza. Le celle richiedono {aircraft} aerei in {minutes} minuti. Le anomalie di integrità della navigazione non indicano un rilevamento di jamming o spoofing.", + "GNSS snapshot needs a view anchor": "Lo snapshot GNSS richiede un punto di riferimento della vista", + "GNSS feed rate limited (HTTP 429)": "Limite di richieste del feed GNSS raggiunto (HTTP 429)", + "Malformed GNSS integrity snapshot": "Snapshot di integrità GNSS non valido", + "GNSS integrity snapshot has no observation time": "Lo snapshot di integrità GNSS non ha un'ora di osservazione", + "installation class|AIRFIELD": "AEROPORTO", + "installation class|NAVAL BASE": "BASE NAVALE", + "installation class|RANGE": "POLIGONO", + "installation class|MILITARY LAND": "TERRENO MILITARE", + "installation class|BASE": "BASE", + "installation class|BARRACKS": "CASERMA", + "installation class|TRAINING AREA": "AREA ADDESTRAMENTO", + "installation class|PLACES CANDIDATE": "CANDIDATO PLACES", + "installation class|INSTALLATION": "INSTALLAZIONE", + "No mapped sites within {km} km of the contact": "Nessun sito mappato entro {km} km dal contatto", + "{count} mapped sites within {km} km of the contact": { + "one": "{count} sito mappato entro {km} km dal contatto", + "many": "{count} di siti mappati entro {km} km dal contatto", + "other": "{count} siti mappati entro {km} km dal contatto" + }, + "No mapped sites in view": "Nessun sito mappato nella vista", + "{count} mapped sites in view": { + "one": "{count} sito mappato nella vista", + "many": "{count} di siti mappati nella vista", + "other": "{count} siti mappati nella vista" + }, "loading mapped installation context": "caricamento del contesto dell'installazione mappata", + "Too many mapped sites in view to list them all": "Troppi siti mappati nella vista per elencarli tutti", + "Installation context unavailable": "Contesto delle installazioni non disponibile", "MAPPED INSTALLATION": "INSTALLAZIONE MAPPATA", + "Unknown": "Sconosciuto", "LAUNCH SITE · {site}": "SITO DI LANCIO · {site}", "LAUNCH SITE": "SITO DI LANCIO", "T−{time} · {mission}": "T−{time} · {mission}", @@ -192,6 +829,7 @@ "Select {mission}": "Seleziona {mission}", "{value} KM": "{value} KM", "{value} KM/S": "{value} KM/S", + "Selected Space Mission": "Missione spaziale selezionata", "SELECTED SPACE MISSION": "MISSIONE SPAZIALE SELEZIONATA", "Show all missions": "Mostra tutte le missioni", "Deselect mission": "Deseleziona la missione", @@ -232,10 +870,82 @@ "Ascent replay": "Replay della salita", "Orbit replay": "Replay dell'orbita", ", paused": ", in pausa", + "Malformed launch snapshot": "Snapshot dei lanci non valido", + "Heard by your receiver": "Ricevuto dal tuo ricevitore", + "1090 MHz": "1090 MHz", + "978 MHz UAT": "978 MHz UAT", + "browser SDR": "SDR nel browser", + "decoder feed": "feed del decoder", + "Your RTL-SDR receiver and decoder feed": "Il tuo ricevitore RTL-SDR e il feed del decoder", + "Your decoder feed": "Il tuo feed del decoder", + "Your RTL-SDR receiver": "Il tuo ricevitore RTL-SDR", + "NO CALLSIGN": "NESSUN NOMINATIVO", + "ALT {altitude} FT · GS {speed} KT · TRK {track}": "ALT {altitude} FT · GS {speed} KT · TRK {track}", + "V/S {rate}": "V/S {rate}", + "V/S {rate} FPM": "V/S {rate} FPM", + "POSITION {age}": "POSIZIONE {age}", + "POSITION {seconds} S AGO": "POSIZIONE {seconds} S FA", + "{count} MSGS": { + "one": "{count} MSG", + "many": "{count} DI MSG", + "other": "{count} MSG" + }, + "Decoder feeds": "Feed dei decoder", + "WebUSB + decoder feeds": "WebUSB + feed dei decoder", + "opening receiver": "apertura del ricevitore", + "checking decoder feeds": "verifica dei feed dei decoder", + "WebUSB needs desktop Chrome or Edge": "WebUSB richiede Chrome o Edge desktop", + "connect a receiver in Radio": "collega un ricevitore in Radio", + "receiver is in FM mode": "il ricevitore è in modalità FM", + "listening": "in ascolto", + "USB error": "errore USB", "Alt unknown": "Quota sconosciuta", "Type unknown": "Tipo sconosciuto", "Reg unknown": "Matricola sconosciuta", "Operator unknown": "Operatore sconosciuto", + "${amount}K": "{amount}K $", + "${amount}M": "{amount} mln $", + "${amount}B": "{amount} mld $", + "fire cause|Human": "Umana", + "fire cause|Natural": "Naturale", + "fire cause|Undetermined": "Indeterminata", + "fire cause|Unknown": "Sconosciuta", + "fire behavior|Minimal": "Minimo", + "fire behavior|Moderate": "Moderato", + "fire behavior|Active": "Attivo", + "fire behavior|Extreme": "Estremo", + "Type {level} Incident": "Incidente di tipo {level}", + "age|{count}m": "{count} min", + "{acres} ac": { + "one": "{acres} acro", + "many": "{acres} di acri", + "other": "{acres} acri" + }, + "{percent}% contained": "contenuto al {percent}%", + "containment unknown": "contenimento sconosciuto", + "{cause} cause": "causa {cause}", + "{personnel} personnel": { + "one": "{personnel} addetto", + "many": "{personnel} di addetti", + "other": "{personnel} addetti" + }, + "{county} County": "Contea di {county}", + "{cost} to date": "{cost} finora", + "discovered {age} ago": "scoperto {age} fa", + "updated {age} ago": "aggiornato {age} fa", + "part of {complex}": "parte di {complex}", + "InciWeb ↗ · click card to open": "InciWeb ↗ · clic sulla scheda per aprirlo", + "FIRE · {name}": "INCENDIO · {name}", + "Unnamed incident": "Incidente senza nome", + "Open {title} on InciWeb": "Apri {title} su InciWeb", + "Perimeter source unavailable": "Fonte dei perimetri non disponibile", + "Not contained or unknown": "Non contenuto o sconosciuto", + "Under 50% contained": "Contenuto meno del 50%", + "50–99% contained": "Contenuto al 50–99%", + "Fully contained": "Completamente contenuto", + "Colour shows reported containment. Perimeters are simplified to about 100 m.": "Il colore indica il contenimento riportato. I perimetri sono semplificati a circa 100 m.", + "Malformed perimeter snapshot": "Snapshot dei perimetri non valido", + "radio tag|All": "Tutti", "News": "Notizie", "Talk": "Talk", "Weather / Emergency": "Meteo / Emergenza", @@ -244,11 +954,21 @@ "Traffic / Transit": "Traffico / Trasporti", "Music": "Musica", "Other": "Altro", + "Directory refresh degraded; showing the previous station catalog.": "Aggiornamento dell'elenco degradato; viene mostrato il catalogo stazioni precedente.", + "Radio directory coverage is degraded.": "La copertura dell'elenco radio è degradata.", + "Directory refresh failed; showing the previous station catalog.": "Aggiornamento dell'elenco non riuscito; viene mostrato il catalogo stazioni precedente.", + "Radio directory is temporarily unavailable.": "L'elenco radio è temporaneamente non disponibile.", + "radio|NEWS": "NOTIZIE", "radio|TALK": "TALK", + "radio|WEATHER": "METEO", "radio|SAFETY": "SICUREZZA", "radio|AIR / SEA": "AERO / MARE", "radio|TRANSIT": "TRASPORTI", "radio|MUSIC": "MUSICA", + "radio|OTHER": "ALTRO", + "Broadcaster stream is unavailable or blocked by the browser.": "Il flusso dell'emittente non è disponibile o è bloccato dal browser.", + "Playback requires a direct click or tap.": "La riproduzione richiede un clic o un tocco diretto.", + "Broadcaster stream could not be started.": "Impossibile avviare il flusso dell'emittente.", "Alternative": "Alternative", "Ambient": "Ambient", "Blues": "Blues", @@ -274,6 +994,32 @@ "Techno": "Techno", "Trance": "Trance", "World": "World", + "overview": "panoramica", + "cloud unknown": "nuvolosità sconosciuta", + "{percent}% scene cloud": "{percent}% di nubi nella scena", + "{min}–{max}% scene cloud": "{min}–{max}% di nubi nella scena", + "Comparison in use by another scene": "Confronto in uso da un'altra scena", + "Esri map unavailable · no swipe": "Mappa Esri non disponibile · niente confronto", + "Swipe needs a globe map": "Il confronto richiede una mappa del globo", + "Imagery stays on Esri · CLEAR to use Google 3D": "Le immagini restano su Esri · CANCELLA per usare Google 3D", + "Imagery catalog unavailable": "Catalogo immagini non disponibile", + "Catalog truncated · a newer clear day may exist": "Catalogo troncato · potrebbe esistere un giorno sereno più recente", + "{label} catalog unavailable · {detail}": "Catalogo {label} non disponibile · {detail}", + "Daily overview for today may still be empty until the pass": "La panoramica giornaliera di oggi potrebbe restare vuota fino al passaggio", + "Box and images cleared": "Riquadro e immagini cancellati", + "MORE DETAIL · 30 m": "PIÙ DETTAGLIO · 30 m", + "Sentinel-2 and Landsat via HLS, 30 m, every 2–6 days": "Sentinel-2 e Landsat tramite HLS, 30 m, ogni 2–6 giorni", + "DAILY OVERVIEW · 250 m": "PANORAMICA GIORNALIERA · 250 m", + "VIIRS daily mosaic, 250 m, follows broad changes; little detail under 25 km": "Mosaico giornaliero VIIRS, 250 m, segue i cambiamenti ampi; pochi dettagli sotto i 25 km", + "Sentinel-2": "Sentinel-2", + "Sentinel-2 via HLS": "Sentinel-2 tramite HLS", + "Landsat 8/9": "Landsat 8/9", + "Landsat 8/9 via HLS": "Landsat 8/9 tramite HLS", + "Daily overview": "Panoramica giornaliera", + "Box edges must be finite": "I bordi del riquadro devono essere finiti", + "Longitudes must be within ±180°": "Le longitudini devono essere entro ±180°", + "Select one side of the dateline": "Seleziona un solo lato della linea del cambio di data", + "Box must enclose an area": "Il riquadro deve racchiudere un'area", "Add the full Starlink broadband shell (thousands of extra points)": "Aggiungi l'intero shell broadband Starlink (migliaia di punti in più)", "Loading the Starlink shell…": "Caricamento dello shell Starlink…", "Starlink {detail} — click to retry": "Starlink {detail} — clic per riprovare", @@ -281,7 +1027,89 @@ "Showing the full Starlink shell — click for the core catalog only": "Mostra l'intero shell Starlink — clic per il solo catalogo principale", "DENSE ···": "DENSO ···", "DENSE ✕": "DENSO ✕", - "DENSE": "DENSA", + "DENSE": "DENSO", + "CelesTrak unreachable": "CelesTrak irraggiungibile", + "DOCKED · {name} · +{extra}": "AGGANCIATO · {name} · +{extra}", + "DOCKED · {name}": "AGGANCIATO · {name}", + "{name} needs the Google 3D map: choose it under MAP SOURCE": "{name} richiede la mappa Google 3D: sceglila in FONTE MAPPA", + "zoom in to a street to open {name}": "ingrandisci su una strada per aprire {name}", + "loading coverage...": "caricamento della copertura...", + "No street-level imagery within {radius} m of that point": "Nessuna immagine a livello stradale entro {radius} m da quel punto", + "No street-level imagery within {radius} m of the view centre": "Nessuna immagine a livello stradale entro {radius} m dal centro della vista", + "Zoom in to see street-level coverage": "Ingrandisci per vedere la copertura a livello stradale", + "Point the camera at the ground for street-level coverage": "Punta la camera verso il suolo per la copertura a livello stradale", + "Coverage tile failed": "Tile di copertura non riuscito", + "The photo could not be loaded": "Impossibile caricare la foto", + "{name} photo. ← and → step along the sequence. On a 360° photo, drag or use Shift+← →, ↑ ↓ to look around, and + − to zoom": "Foto {name}. ← e → scorrono la sequenza. Su una foto a 360°, trascina o usa Shift+← →, ↑ ↓ per guardarti intorno, e + − per lo zoom", + "{name} street-level photo": "Foto a livello stradale {name}", + "Previous photo in this sequence (←)": "Foto precedente in questa sequenza (←)", + "Next photo in this sequence (→)": "Foto successiva in questa sequenza (→)", + "Aim the middle of the view at a street to look for imagery there": "Punta il centro della vista su una strada per cercare immagini lì", + "KEY REJECTED": "CHIAVE RIFIUTATA", + "GOOGLE_MAPS_API_KEY is not set": "GOOGLE_MAPS_API_KEY non è impostata", + "The Google Maps JavaScript API could not load": "Impossibile caricare la Google Maps JavaScript API", + "Google Street View": "Google Street View", + "GOOGLE STREET VIEW": "GOOGLE STREET VIEW", + "Google refused GOOGLE_MAPS_API_KEY for Street View — check that the Maps JavaScript API is enabled for it and this site is an allowed referrer": "Google ha rifiutato GOOGLE_MAPS_API_KEY per Street View: verifica che la Maps JavaScript API sia abilitata per la chiave e che questo sito sia un referrer consentito", + "Street View did not answer — check the network, and that the Maps JavaScript API is enabled for GOOGLE_MAPS_API_KEY": "Street View non ha risposto: controlla la rete e che la Maps JavaScript API sia abilitata per GOOGLE_MAPS_API_KEY", + "click a street to open Street View": "fai clic su una strada per aprire Street View", + "Street View has no imagery for this place": "Street View non ha immagini per questo luogo", + "KartaView has no position for this photo": "KartaView non ha una posizione per questa foto", + "The KartaView photo could not be loaded": "Impossibile caricare la foto KartaView", + "zoom in to see KartaView coverage": "ingrandisci per vedere la copertura KartaView", + "no KartaView photos in view": "nessuna foto KartaView nella vista", + "KartaView is rate-limiting requests — they resume on their own": "KartaView sta limitando le richieste: riprenderanno da sole", + "KartaView’s photos here are archived and cannot be shown": "Le foto KartaView qui sono archiviate e non possono essere mostrate", + "KartaView did not filter this area in time — move the map to ask again": "KartaView non ha filtrato quest'area in tempo: sposta la mappa per riprovare", + "None of KartaView’s photos here pass the imagery filter": "Nessuna delle foto KartaView qui supera il filtro delle immagini", + "KartaView did not answer in time — try again": "KartaView non ha risposto in tempo: riprova", + "KartaView could not be reached — check the network": "KartaView non è raggiungibile: controlla la rete", + "KartaView sent an answer that could not be read": "KartaView ha inviato una risposta illeggibile", + "KartaView is rate-limiting requests": "KartaView sta limitando le richieste", + "KartaView sent too much data": "KartaView ha inviato troppi dati", + "KartaView is rate-limiting requests — try again in a moment": "KartaView sta limitando le richieste: riprova tra un momento", + "KartaView has no such photo": "KartaView non ha questa foto", + "Mapillary rejected MAPILLARY_CLIENT_TOKEN — replace it in Provider Settings": "Mapillary ha rifiutato MAPILLARY_CLIENT_TOKEN: sostituiscilo in Impostazioni provider", + "Coverage requests are being rate-limited — they resume on their own": "Le richieste di copertura sono limitate: riprenderanno da sole", + "The Panoramax photo could not be loaded": "Impossibile caricare la foto Panoramax", + "Panoramax is busy — coverage resumes on its own": "Panoramax è occupato: la copertura riprenderà da sola", + "no Panoramax photos in view": "nessuna foto Panoramax nella vista", + "no Panoramax photos here match the filters": "nessuna foto Panoramax qui corrisponde ai filtri", + "Panoramax sent a map tile that could not be read": "Panoramax ha inviato un tile della mappa illeggibile", + "This Panoramax photo is no longer available": "Questa foto Panoramax non è più disponibile", + "zoom in to see Panoramax coverage": "ingrandisci per vedere la copertura Panoramax", + "Panoramax did not answer in time — try again": "Panoramax non ha risposto in tempo: riprova", + "Panoramax could not be reached — check the connection": "Panoramax non è raggiungibile: controlla la connessione", + "Panoramax sent too much data": "Panoramax ha inviato troppi dati", + "Panoramax is busy": "Panoramax è occupato", + "Panoramax sent an unreadable answer": "Panoramax ha inviato una risposta illeggibile", + "Sequence images unavailable": "Immagini della sequenza non disponibili", + "No street-level imagery providers configured": "Nessun provider di immagini a livello stradale configurato", + "(by upload date)": "(per data di caricamento)", + "Open the Street Level panel to view imagery": "Apri il pannello Vista stradale per vedere le immagini", + "Image could not be opened": "Impossibile aprire l'immagine", + "TeleGeography load failed": "Caricamento TeleGeography non riuscito", + "UNAVAILABLE · {source} · Roads unavailable": "NON DISPONIBILE · {source} · Strade non disponibili", + "Roads: {source}": "Strade: {source}", + "TomTom roads unavailable while the traffic service is unreachable": "Strade TomTom non disponibili mentre il servizio traffico è irraggiungibile", + "Hybrid unavailable while the traffic service is unreachable": "Ibrido non disponibile mentre il servizio traffico è irraggiungibile", + "TomTom roads need a TomTom key": "Le strade TomTom richiedono una chiave TomTom", + "Hybrid needs a TomTom key": "Ibrido richiede una chiave TomTom", + "Local surface still loading": "Superficie locale ancora in caricamento", + "Partial coverage": "Copertura parziale", + "Detailed roads unavailable": "Strade dettagliate non disponibili", + "Reduced detail coverage": "Copertura con dettaglio ridotto", + "TomTom roads only, each with its live flow": "Solo strade TomTom, ognuna con il suo flusso live", + "TomTom roads only, each with its live flow (needs a TomTom key)": "Solo strade TomTom, ognuna con il suo flusso live (richiede una chiave TomTom)", + "OpenStreetMap roads, with TomTom flow matched when available": "Strade OpenStreetMap, con il flusso TomTom abbinato quando disponibile", + "TomTom roads first; OpenStreetMap fills the rest, simulated": "Prima le strade TomTom; OpenStreetMap completa il resto, simulato", + "TomTom roads first; OpenStreetMap fills the rest, simulated (needs a TomTom key)": "Prima le strade TomTom; OpenStreetMap completa il resto, simulato (richiede una chiave TomTom)", + "Hybrid": "Ibrido", + "TomTom key unavailable": "Chiave TomTom non disponibile", + "TomTom daily budget reached": "Budget giornaliero TomTom esaurito", + "TomTom upstream unreachable": "Servizio TomTom irraggiungibile", + "TomTom flow unavailable": "Flusso TomTom non disponibile", + "SIMULATED — {reason}": "SIMULATO — {reason}", "Syncing flow · Roads: {source}": "Sincronizzazione flusso · Strade: {source}", "LIVE · Roads: {source} · Roads without flow hidden": "LIVE · Strade: {source} · Strade senza flusso nascoste", "LIVE · Roads: {source} · No flow roads in view": "LIVE · Strade: {source} · Nessuna strada con flusso in vista", @@ -293,42 +1121,425 @@ "SIMULATED · Roads: OpenStreetMap · Flow: TomTom (no matches)": "SIMULATO · Strade: OpenStreetMap · Flusso: TomTom (nessuna corrispondenza)", "SIMULATED — traffic service unreachable": "SIMULATO — servizio traffico irraggiungibile", "SIMULATED — add TomTom key for live": "SIMULATO — aggiungi la chiave TomTom per il live", + "OpenFreeMap tiles rate-limited": "Tile OpenFreeMap con limite di richieste", + "OpenFreeMap tiles timed out": "Tile OpenFreeMap in timeout", + "OpenFreeMap tiles unavailable": "Tile OpenFreeMap non disponibili", + "occupancy|empty": "vuoto", + "occupancy|many seats available": "molti posti disponibili", + "occupancy|few seats available": "pochi posti disponibili", + "occupancy|standing room only": "solo posti in piedi", + "occupancy|crushed standing room only": "solo posti in piedi, affollato", + "occupancy|full": "pieno", + "occupancy|not accepting passengers": "non accetta passeggeri", + "occupancy|not boardable": "non accessibile", + "Route {route}": "Linea {route}", + "Vehicle {vehicle}": "Veicolo {vehicle}", + "vehicle motion|Stopped": "Fermo", + "No recent fix": "Nessuna posizione recente", + "Waiting for update": "In attesa di aggiornamento", + "Moving": "In movimento", + "reported {speed} km/h": "{speed} km/h riportati", + "reported hdg {heading}°": "prua {heading}° riportata", + "Last report: stopped at stop {stop}": "Ultimo rapporto: fermo alla fermata {stop}", + "Last report: arriving at stop {stop}": "Ultimo rapporto: in arrivo alla fermata {stop}", + "Last report: next stop {stop}": "Ultimo rapporto: prossima fermata {stop}", + "Shown at street level · depth not in the feed": "Mostrato a livello stradale · profondità non presente nel feed", + "Reported {seconds} s ago": "Riportato {seconds} s fa", + "Reported {minutes} min ago": "Riportato {minutes} min fa", + "shown {seconds} s behind": "mostrato con {seconds} s di ritardo", + "{reported} (feed time)": "{reported} (ora del feed)", + "Available trail: {minutes} min (limited)": "Scia disponibile: {minutes} min (limitata)", + "Available trail: {minutes} min": "Scia disponibile: {minutes} min", + "Bus": "Autobus", + "Tram": "Tram", + "Subway": "Metropolitana", + "Train": "Treno", + "Ferry": "Traghetto", + "Transit vehicle": "Veicolo del trasporto pubblico", "AIS: {name}": "AIS: {name}", "{type} SPD: {speed} HDG: {heading}": "{type} VEL: {speed} HDG: {heading}", "VESSEL": "NAVE", + "{speed}KT": "{speed}KT", + "{heading}DEG": "{heading}°", "POS: LIVE": "POS: LIVE", "POS: {time}Z": "POS: {time}Z", + "AIS live load failed": "Caricamento AIS live non riuscito", "awaiting first AIS position…": "in attesa della prima posizione AIS…", "awaiting usable AIS positions…": "in attesa di posizioni AIS utilizzabili…", "awaiting first AIS message…": "in attesa del primo messaggio AIS…", + "AISSTREAM_API_KEY not set": "AISSTREAM_API_KEY non impostata", + "live feed unsupported": "feed live non supportato", + "connecting to feed…": "connessione al feed…", + "feed disconnected": "feed disconnesso", + "feed down": "feed inattivo", + "feed idle": "feed fermo", + "API key rejected — check AISSTREAM_API_KEY": "Chiave API rifiutata: controlla AISSTREAM_API_KEY", + "feed silent {seconds}s — no AIS data": "feed silenzioso da {seconds}s: nessun dato AIS", + "feed silent — no AIS data": "feed silenzioso: nessun dato AIS", + "feed down — retrying slowly (attempt {attempt})": "feed fermo: nuovi tentativi lenti (tentativo {attempt})", + "reconnecting to feed… (attempt {attempt})": "riconnessione al feed… (tentativo {attempt})", + "feed down — retrying slowly": "feed fermo: nuovi tentativi lenti", + "reconnecting to feed…": "riconnessione al feed…", + "Focus vessel {name}, MMSI {mmsi}": "Focus sulla nave {name}, MMSI {mmsi}", + "Hidden by this map source · choose a globe map": "Nascosto da questa fonte mappa · scegli una mappa del globo", + "Weather image HTTP {status}": "Immagine meteo HTTP {status}", + "Weather HTTP {status}": "Meteo HTTP {status}", + "Frame unavailable; previous observation retained": "Fotogramma non disponibile; mantenuta l'osservazione precedente", + "Weather imagery unavailable": "Immagini meteo non disponibili", + "Weather source unavailable; previous observation retained": "Fonte meteo non disponibile; mantenuta l'osservazione precedente", + "Weather unavailable": "Meteo non disponibile", + "No frame within {gap} min of {time}": "Nessun fotogramma entro {gap} min dalle {time}", + "No frame within {gap} h of {time}": "Nessun fotogramma entro {gap} h dalle {time}", + "{hours}h {minutes}m ago": "{hours} h {minutes} min fa", + "{minutes}m ago": "{minutes} min fa", + "{state} · {time} · {lag}": "{state} · {time} · {lag}", + "Observed": "Osservato", + "History": "Storico", + "Observation unavailable": "Osservazione non disponibile", + "Waiting for observation": "In attesa dell'osservazione", + "{detail} · synced": "{detail} · sincronizzato", + "{detail} · nearest": "{detail} · più vicino", + "RADAR REFLECTIVITY · dBZ": "RIFLETTIVITÀ RADAR · dBZ", + "LIGHTNING DENSITY · 15 min accumulation": "DENSITÀ DI FULMINI · accumulo di 15 min", + "GLOBAL INFRARED · hourly": "INFRAROSSO GLOBALE · orario", + "GOES INFRARED · ~5 min": "INFRAROSSO GOES · ~5 min", + "{state}: {time}": "{state}: {time}", + "Latest observation": "Ultima osservazione", + "frame {index}/{total}": "fotogramma {index}/{total}", + "loading": "caricamento", + "Observation: unavailable": "Osservazione: non disponibile", + "Contiguous US · gaps ≠ no rain": "USA contigui · lacune ≠ assenza di pioggia", + "Americas + Pacific · not individual strikes": "Americhe + Pacifico · non singole fulminazioni", + "Color: strikes/km²/min ×10³": "Colore: fulmini/km²/min ×10³", + "60°S–60°N · typically 2–3 h delayed": "60°S–60°N · di solito 2–3 h di ritardo", + "North America · infrared imagery": "Nord America · immagini all'infrarosso", + "Reduced motion · history playback unavailable": "Movimento ridotto · riproduzione dello storico non disponibile", + "Reduced motion · manual history available": "Movimento ridotto · storico manuale disponibile", + "Rain radar · US": "Radar pioggia · USA", + "Lightning density · 15 min": "Densità di fulmini · 15 min", + "Satellite clouds": "Nuvole da satellite", + "Americas + Pacific": "Americhe + Pacifico", + "Global · 60°S–60°N": "Globale · 60°S–60°N", + "North America": "Nord America", + "Source observations delayed": "Osservazioni della fonte in ritardo", + "Stale source": "Fonte obsoleta", + "Loading next frame…": "Caricamento del fotogramma successivo…", + "Map center outside coverage": "Centro della mappa fuori copertura", + "strikes/km²/min ×10³": "fulmini/km²/min ×10³", + "N. America": "Nord America", + "Global": "Globale", + "Hourly global mosaic; usually 2–3 hours delayed": "Mosaico globale orario; di solito 2–3 ore di ritardo", + "GOES regional clouds; approximately 5-minute updates": "Nuvole regionali GOES; aggiornamenti circa ogni 5 minuti", + "Clouds only": "Solo nuvole", + "Apply the full cloud brightness key; 100% filter strength": "Applica l'intera scala di luminosità delle nuvole; intensità del filtro 100%", + "Full": "Completo", + "Show the complete infrared image; 0% filter strength": "Mostra l'intera immagine all'infrarosso; intensità del filtro 0%", + "Soft": "Tenue", + "Vivid": "Vivido", + "Image opacity; does not alter the observed values": "Opacità dell'immagine; non altera i valori osservati", + "View US radar": "Vedi il radar USA", + "View Americas & Pacific": "Vedi Americhe e Pacifico", + "View coverage": "Vedi la copertura", + "{value} strikes/km²/min ×10³ (15-minute density)": "{value} fulmini/km²/min ×10³ (densità su 15 minuti)", + "{value} dBZ radar reflectivity": "{value} dBZ di riflettività radar", + "STALE · cached source metadata": "OBSOLETO · metadati della fonte in cache", + "Map center is outside source coverage": "Il centro della mappa è fuori dalla copertura della fonte", + "NOAA/NWS 15-minute lightning density derived from Vaisala NLDN/GLD360. Coverage 110°E across the Pacific/Americas to 0°, 25°S–80°N. Not a live strike count, global coverage or a safety warning.": "Densità di fulmini a 15 minuti NOAA/NWS derivata da Vaisala NLDN/GLD360. Copertura da 110°E attraverso il Pacifico e le Americhe fino a 0°, 25°S–80°N. Non è un conteggio live delle fulminazioni, né una copertura globale né un avviso di sicurezza.", + "NOAA MRMS radar echoes indicate precipitation patterns, not rain rate, a storm warning or a future forecast. Native source approximately 1 km; display is limited to level 6. Frames use exact advertised observation times.": "Gli echi radar NOAA MRMS indicano la distribuzione delle precipitazioni, non l'intensità della pioggia, un avviso di tempesta o una previsione. Risoluzione nativa della fonte circa 1 km; la visualizzazione è limitata al livello 6. I fotogrammi usano gli orari esatti di osservazione dichiarati.", + "GOES-19/18 longwave infrared Band 14 regional; NESDIS global longwave mosaic. Clouds only dims everything but bright, cold cloud tops; a brightness filter, not a cloud mask. Coverage and freshness differ by region.": "Infrarosso a onda lunga GOES-19/18 Banda 14 regionale; mosaico globale a onda lunga NESDIS. Solo nuvole attenua tutto tranne le sommità nuvolose fredde e luminose; è un filtro di luminosità, non una maschera delle nuvole. Copertura e aggiornamento variano per regione.", + "REGION": "REGIONE", + "IMAGE": "IMMAGINE", + "FILTER": "FILTRO", + "Cloud filter strength": "Intensità del filtro nuvole", + "OPACITY": "OPACITÀ", + "Infrared decode failed": "Decodifica dell'infrarosso non riuscita", + "Weather prefetch unavailable": "Precaricamento meteo non disponibile", + "Weather tiles unavailable · previous frame retained": "Tile meteo non disponibili · mantenuto il fotogramma precedente", + "Some weather tiles unavailable": "Alcuni tile meteo non sono disponibili", + "Malformed weather manifest": "Manifest meteo non valido", + "Weather request timed out": "La richiesta meteo è andata in timeout", + "Temperature field unavailable": "Campo di temperatura non disponibile", + "Mean sea level pressure field unavailable": "Campo di pressione al livello del mare non disponibile", + "Wind upstream unavailable": "Servizio del vento non disponibile", + "{source} HTTP {status}": "{source} HTTP {status}", + "Wind": "Vento", + "Wind source unavailable": "Fonte del vento non disponibile", + "Forecast · does not follow history": "Previsione · non segue lo storico", + "Wind motion": "Movimento del vento", + "Wind speed": "Velocità del vento", + "Sea-level pressure": "Pressione al livello del mare", + "Air temperature · 2 m": "Temperatura dell'aria · 2 m", + "Global · 1° grid": "Globale · griglia di 1°", + "{model} forecast · {time}": "Previsione {model} · {time}", + "Loading forecast": "Caricamento della previsione", + "Preparing flow": "Preparazione del flusso", + "Selected field unavailable": "Campo selezionato non disponibile", + "Cached forecast · stale": "Previsione in cache · obsoleta", + "ECMWF IFS surface forecast": "Previsione di superficie ECMWF IFS", + "NOAA GFS surface forecast": "Previsione di superficie NOAA GFS", + "Reduced motion": "Movimento ridotto", "Resume": "Riprendi", "Pause": "Pausa", + "Pause visual flow; forecast time does not advance with animation": "Mette in pausa il flusso visivo; l'ora della previsione non avanza con l'animazione", + "None": "Nessuno", + "Speed": "Velocità", + "Pressure": "Pressione", + "Temperature": "Temperatura", + "Wind trails with no field shading": "Scie del vento senza ombreggiatura del campo", + "How hard the surface wind is blowing": "Quanto forte soffia il vento in superficie", + "Sea-level air pressure: broad highs and lows": "Pressione atmosferica al livello del mare: aree di alta e bassa pressione", + "Air temperature two meters above the surface": "Temperatura dell'aria a due metri dalla superficie", + "Wind speed units": "Unità della velocità del vento", + "Read wind at map center": "Leggi il vento al centro della mappa", + "Read the forecast at the center of the map without changing selection": "Leggi la previsione al centro della mappa senza cambiare la selezione", + "{model} forecast · {field} ({unit})": "Previsione {model} · {field} ({unit})", + "Valid: {time}": "Valida: {time}", + "preparing": "preparazione", + "Issued: {time}": "Emessa: {time}", + "Selected field unavailable · wind remains visible": "Campo selezionato non disponibile · il vento resta visibile", + "{error} · wind remains visible": "{error} · il vento resta visibile", + "Surface wind at 10 m. Approximately 1° global grid. Curves follow the 10 m wind field, lifted 12 km for visibility; display height is not weather altitude. View lighting is for readability. Animation shows flow through one fixed forecast; it does not advance time. Color fields drape the globe basemap or the active photorealistic 3D Tiles.": "Vento in superficie a 10 m. Griglia globale di circa 1°. Le curve seguono il campo del vento a 10 m, sollevate di 12 km per visibilità; l'altezza visualizzata non è la quota meteorologica. L'illuminazione della vista serve alla leggibilità. L'animazione mostra il flusso di una singola previsione fissa; non fa avanzare il tempo. I campi colorati ricoprono la mappa di base del globo o i 3D Tiles fotorealistici attivi.", + "MODEL": "MODELLO", + "FIELD": "CAMPO", + "UNITS": "UNITÀ", + "MOTION": "MOVIMENTO", + "Forecast": "Previsione", + "N": "N", + "NNE": "NNE", + "NE": "NE", + "ENE": "ENE", + "E": "E", + "ESE": "ESE", + "SE": "SE", + "SSE": "SSE", + "S": "S", + "SSW": "SSO", + "SW": "SO", + "WSW": "OSO", + "W": "O", + "WNW": "ONO", + "NW": "NO", + "NNW": "NNO", + "No surface reading": "Nessuna lettura in superficie", + "Aim the map center at Earth": "Punta il centro della mappa sulla Terra", + "A location reading needs a loaded forecast and the Earth at the center of the view.": "Una lettura sul luogo richiede una previsione caricata e la Terra al centro della vista.", + "Interpolated model forecast on an approximately 1° grid. Broad weather patterns, not a street-level measurement.": "Previsione del modello interpolata su una griglia di circa 1°. Andamenti meteo generali, non una misura a livello stradale.", + " · calm": " · calma", + " from {direction}": " da {direction}", + "WIND AT {coordinates}": "VENTO A {coordinates}", + "{model} · valid {time}": "{model} · valida {time}", + "Wind speed field unavailable": "Campo della velocità del vento non disponibile", + "Globe imagery unavailable": "Immagini del globo non disponibili", + "Globe field image unavailable": "Immagine del campo sul globo non disponibile", + "Unknown wind model": "Modello del vento sconosciuto", + "Unknown weather overlay": "Overlay meteo sconosciuto", + "Wind request timed out": "La richiesta del vento è andata in timeout", + "Malformed wind manifest": "Manifest del vento non valido", + "Malformed wind grid": "Griglia del vento non valida", "Error: {message}": "Errore: {message}", - "Needs {envVars} — add it in Provider Settings": "Richiede {envVars}: vai su Impostazioni Provider", + "Needs {envVars} — add it in Provider Settings": "Richiede {envVars}: aggiungila in Impostazioni provider", "{label} is unavailable": "{label} non è disponibile", "This map stack": "Questo stack mappa", "{label} unavailable: {hint}": "{label} non disponibile: {hint}", + "Google 3D tiles unavailable — check the key's API restrictions, quota, or network": "Google 3D Tiles non disponibili: controlla le restrizioni API della chiave, la quota o la rete", + "Needs {envVars} — add it in Provider Settings — or a Cesium ion token for the ion-hosted route": "Richiede {envVars}: aggiungila in Impostazioni provider, oppure un token Cesium ion per il percorso ospitato da ion", + "Exit cockpit to fly to a camera": "Esci dal cockpit per volare a una telecamera", + "Exit cockpit to fly to a location": "Esci dal cockpit per volare a un luogo", + "Exit cockpit to fly to a photo": "Esci dal cockpit per volare a una foto", + "Exit cockpit to fly to a shared view": "Esci dal cockpit per volare a una vista condivisa", + "Exit cockpit to fly to a target": "Esci dal cockpit per volare a un obiettivo", + "Exit cockpit to fly to a vessel": "Esci dal cockpit per volare a una nave", + "Exit cockpit to fly to a fire": "Esci dal cockpit per volare a un incendio", + "Exit cockpit to fly to a route": "Esci dal cockpit per volare a un percorso", + "Exit cockpit to fly to a file": "Esci dal cockpit per volare a un file", + "Exit cockpit to fly to a scene": "Esci dal cockpit per volare a una scena", + "Exit cockpit to view weather coverage": "Esci dal cockpit per vedere la copertura meteo", + "Exit cockpit to fly to a cyclone": "Esci dal cockpit per volare a un ciclone", + "Exit cockpit to fly to an aircraft": "Esci dal cockpit per volare a un aereo", + "Exit cockpit to fly to a satellite": "Esci dal cockpit per volare a un satellite", + "Exit cockpit to frame contacts": "Esci dal cockpit per inquadrare i contatti", "Visible map targets": "Obiettivi mappa visibili", + "Focusing {label}": "Focus su {label}", + "Source": "Fonte", + "Camera ownership changed": "Il controllo della camera è cambiato", + "Saved project could not be read; storage preserved. Import a valid file to resume saving.": "Impossibile leggere il progetto salvato; archivio conservato. Importa un file valido per riprendere i salvataggi.", "Ready": "Pronto", + "Scene layer turned off": "Livello della scena disattivato", + "Stopped": "Fermato", + "Scene not saved — existing saved project could not be read. Export edits or import a valid file.": "Scena non salvata: impossibile leggere il progetto salvato esistente. Esporta le modifiche o importa un file valido.", + "Scene not saved — {reason}": "Scena non salvata: {reason}", + "Scene not saved — browser storage unavailable": "Scena non salvata: archiviazione del browser non disponibile", "Loaded: {scene} / {shot}": "Caricato: {scene} / {shot}", + "Cannot update {scene}: shot inventory changed": "Impossibile aggiornare {scene}: l'elenco degli scatti è cambiato", + "Cannot update {scene}: evidence beats changed": "Impossibile aggiornare {scene}: le tappe delle prove sono cambiate", + "Cannot update {scene}: shot bindings are incomplete": "Impossibile aggiornare {scene}: i collegamenti degli scatti sono incompleti", + "Updated {count} shots: {scene}": { + "one": "Aggiornato {count} scatto: {scene}", + "many": "Aggiornati {count} di scatti: {scene}", + "other": "Aggiornati {count} scatti: {scene}" + }, + "Appended {count} shots: {scene}": { + "one": "Aggiunto {count} scatto: {scene}", + "many": "Aggiunti {count} di scatti: {scene}", + "other": "Aggiunti {count} scatti: {scene}" + }, "Cannot capture shot: camera not ready": "Impossibile catturare lo scatto: camera non pronta", "Captured: {scene} / {shot}": "Catturato: {scene} / {shot}", "Select a shot first": "Seleziona prima uno scatto", "Updated: {scene} / {shot}": "Aggiornato: {scene} / {shot}", + "Could not leave scene: {scene}": "Impossibile uscire dalla scena: {scene}", + "Seeked: {scene} / {shot}": "Posizionato: {scene} / {shot}", + "Seeking scene clock": "Spostamento sull'orologio della scena", "Camera unavailable — exit cockpit first": "Camera non disponibile: esci prima dal cockpit", "No shots to run": "Nessuno scatto da eseguire", + "Scene transition limit reached — load a shot to reset": "Limite di transizioni della scena raggiunto: carica uno scatto per azzerarlo", + "Export failed: {error}": "Esportazione non riuscita: {error}", "Project exported": "Progetto esportato", + "Importing project": "Importazione del progetto", + "Imported {file}": "Importato {file}", + "Import failed: {error}": "Importazione non riuscita: {error}", + "Import failed (could not read JSON file)": "Importazione non riuscita (impossibile leggere il file JSON)", + "Layers refused: {layers}": "Livelli rifiutati: {layers}", "Could not exit {mode} — scene layers may be refused": "Impossibile uscire da {mode}: i livelli della scena potrebbero essere rifiutati", + "Camera move interrupted": "Movimento della camera interrotto", + "Scene media timed out": "I contenuti della scena sono andati in timeout", + "Action complete": "Azione completata", + "Action unavailable or cancelled": "Azione non disponibile o annullata", + "Scene actions": "Azioni della scena", + "Select a feature or use Tab and Enter to choose an action.": "Seleziona un elemento o usa Tab e Enter per scegliere un'azione.", + "Selected feature: {feature}. Choose an action.": "Elemento selezionato: {feature}. Scegli un'azione.", "Running {index}/{total}: {scene} / {shot}": "Esecuzione {index}/{total}: {scene} / {shot}", "Scene run complete": "Esecuzione della scena completata", - "Global Flights Radar": "Radar Voli Globale", - "Orbital Watch": "Sorveglianza Orbitale", - "Thermal Threat Board": "Quadro Minacce Termiche", - "City Overload": "Sovraccarico Urbano", - "Omniscience Pullback": "Zoom Out Onniscienza", + "Bhote Koshi Evidence Sequence": "Sequenza delle prove del Bhote Koshi", + "Nepal Flood Incident": "Alluvione in Nepal", + "Global Flights Radar": "Radar voli globale", + "Orbital Watch": "Sorveglianza orbitale", + "Thermal Threat Board": "Quadro minacce termiche", + "City Overload": "Sovraccarico urbano", + "Omniscience Pullback": "Allontanamento onnisciente", + "Global Incident Context": "Contesto globale dell'evento", + "Nepal-Focused Globe Rotation": "Rotazione del globo sul Nepal", + "Bhote Koshi Regional Approach": "Avvicinamento regionale al Bhote Koshi", + "Bhote Koshi Nearby Cities": "Città vicine al Bhote Koshi", + "Bhote Koshi Incident Corridor": "Corridoio dell'evento del Bhote Koshi", + "Bhote Koshi Flood Path": "Percorso dell'alluvione del Bhote Koshi", + "Bhote Koshi Corridor Overview": "Panoramica del corridoio del Bhote Koshi", + "Bhote Koshi Upper Valley": "Alta valle del Bhote Koshi", + "Upper Valley Collapse": "Crollo nell'alta valle", + "Debris-Dammed Lake": "Lago di sbarramento da detriti", + "Nepal-China Border Gate": "Valico di frontiera Nepal-Cina", + "Timure Evidence Cluster": "Gruppo di prove di Timure", + "Syabru Besi Passage": "Passaggio a Syabru Besi", + "Bidur / Trishuli Consequence": "Conseguenze a Bidur / Trishuli", + "Final view": "Vista finale", + "Scene {n}": "Scena {n}", "Shot {n}": "Scatto {n}", + "the title of scene {scene} is empty or longer than {max} characters": "il titolo della scena {scene} è vuoto o supera i {max} caratteri", + "the title of shot {shot} in scene {scene} is empty or longer than {max} characters": "il titolo dello scatto {shot} nella scena {scene} è vuoto o supera i {max} caratteri", + "the project is larger than 5 MiB": "il progetto supera i 5 MiB", + "the project has too many shots": "il progetto ha troppi scatti", + "the scene data failed validation": "i dati della scena non hanno superato la validazione", + "Could not complete this action. Check the file, references and selected assets.": "Impossibile completare questa azione. Controlla il file, i riferimenti e le risorse selezionate.", + "{count} scenes": { + "one": "{count} scena", + "many": "{count} di scene", + "other": "{count} scene" + }, + "{count} shots": { + "one": "{count} scatto", + "many": "{count} di scatti", + "other": "{count} scatti" + }, + "{count} data packs": { + "one": "{count} pacchetto dati", + "many": "{count} di pacchetti dati", + "other": "{count} pacchetti dati" + }, + "{scene} / {pack}: {status}. File: {path}. {attribution} · {license}": "{scene} / {pack}: {status}. File: {path}. {attribution} · {license}", + "Unavailable layers: {layers}": "Livelli non disponibili: {layers}", + "Uses registered content or linked media. Those external files are not included in a scene bundle. Their original notices still apply.": "Usa contenuti registrati o media collegati. Quei file esterni non sono inclusi nel pacchetto della scena. Valgono ancora le loro note originali.", + "{bytes} bundled bytes verified. Files stay in memory for this session. Reimport the bundle after reloading the app.": "{bytes} byte nel pacchetto verificati. I file restano in memoria per questa sessione. Reimporta il pacchetto dopo aver ricaricato l'app.", + "Review scene import": "Rivedi l'importazione della scena", + "Nothing is loaded or changed until you apply this file.": "Nulla viene caricato o modificato finché non applichi questo file.", + "Ready to import": "Pronto per l'importazione", + "Apply replaces the current project. Export your current project first if you want to keep both.": "Applica sostituisce il progetto attuale. Esporta prima il progetto attuale se vuoi conservarli entrambi.", + "Apply import": "Applica importazione", + "Import was not applied. The current project may have changed.": "L'importazione non è stata applicata. Il progetto attuale potrebbe essere cambiato.", + "Select a scene and shot first": "Seleziona prima una scena e uno scatto", + "Edit scene details": "Modifica i dettagli della scena", + "Camera positions use degrees and meters above the ellipsoid. Drafts are validated before they replace your saved scene.": "Le posizioni della camera usano gradi e metri sopra l'ellissoide. Le bozze vengono validate prima di sostituire la scena salvata.", + "Anchors and data packs": "Ancore e pacchetti dati", + "Shot camera, timing, packs and actions": "Camera, tempi, pacchetti e azioni dello scatto", + "New anchor ID": "ID nuova ancora", + "Capture camera as anchor": "Cattura la camera come ancora", + "Anchor added to draft": "Ancora aggiunta alla bozza", + "Set move start to current camera": "Imposta l'inizio del movimento sulla camera attuale", + "Move added to draft; destination remains the shot camera": "Movimento aggiunto alla bozza; la destinazione resta la camera dello scatto", + "Use ordinary flight": "Usa il volo normale", + "Invalid shot JSON": "JSON dello scatto non valido", + "Apply details": "Applica i dettagli", + "Select a scene first": "Seleziona prima una scena", + "Share selected scene": "Condividi la scena selezionata", + "Scene JSON preserves authored settings and attribution. It does not include asset files. Bundles include only pack files you choose here or previously imported bundle files.": "Il JSON della scena conserva le impostazioni d'autore e l'attribuzione. Non include i file delle risorse. I pacchetti includono solo i file dei pacchetti dati scelti qui o i file di pacchetti importati in precedenza.", + "Download scene JSON": "Scarica il JSON della scena", + "Choose data-pack files": "Scegli i file del pacchetto dati", + "Or choose a data-pack folder": "Oppure scegli una cartella del pacchetto dati", + "Download asset bundle": "Scarica il pacchetto di risorse", + "Asset bundle downloaded": "Pacchetto di risorse scaricato", + "No RTL-SDR device selected": "Nessun dispositivo RTL-SDR selezionato", + "WebUSB requires desktop Chrome or Edge on localhost/HTTPS": "WebUSB richiede Chrome o Edge desktop su localhost/HTTPS", + "RTL-SDR access failed; close other SDR apps and check USB permissions": "Accesso a RTL-SDR non riuscito; chiudi le altre app SDR e controlla i permessi USB", + "RTL-SDR connection failed": "Connessione a RTL-SDR non riuscita", + "Receiving 1090 MHz ADS-B": "Ricezione ADS-B a 1090 MHz", + "Receiving broadcast FM": "Ricezione FM broadcast", + "Connect an RTL-SDR to begin.": "Collega un RTL-SDR per iniziare.", + "WebUSB is unavailable in this browser": "WebUSB non è disponibile in questo browser", + "USB work abandoned after a stalled transfer": "Operazione USB abbandonata dopo un trasferimento bloccato", + "SDR decoder worker failed": "Errore del worker del decoder SDR", + "SDR decoder did not start; receiver stopped": "Il decoder SDR non si è avviato; ricevitore fermato", + "SDR decoder stopped responding; receiver stopped": "Il decoder SDR ha smesso di rispondere; ricevitore fermato", + "SDR decoder fell behind; receiver stopped": "Il decoder SDR è rimasto indietro; ricevitore fermato", + "WebUSB requires desktop Chrome or Edge": "WebUSB richiede Chrome o Edge desktop", + "Waiting for an RTL-SDR device…": "In attesa di un dispositivo RTL-SDR…", + "Browser audio is suspended; press Connect again to resume it": "L'audio del browser è sospeso; premi di nuovo Connetti per riprenderlo", + "RTL-SDR sample stream stopped": "Flusso di campioni RTL-SDR interrotto", + "Switching to {mode}…": "Passaggio a {mode}…", + "Browser audio is suspended; select FM again to resume it": "L'audio del browser è sospeso; seleziona di nuovo FM per riprenderlo", + "RTL-SDR gain change failed": "Modifica del guadagno RTL-SDR non riuscita", + "Tuned to {mhz} MHz FM": "Sintonizzato su {mhz} MHz FM", + "Seeking up…": "Ricerca verso l'alto…", + "Seeking down…": "Ricerca verso il basso…", + "Seek stopped": "Ricerca interrotta", + "Scanning {mhz} MHz…": "Scansione di {mhz} MHz…", + "Found {mhz} MHz · {snr} dB": "Trovato {mhz} MHz · {snr} dB", + "FM signal found at {mhz} MHz": "Segnale FM trovato a {mhz} MHz", + "No FM signal found": "Nessun segnale FM trovato", + "Browser location is unavailable": "La posizione del browser non è disponibile", + "Receiver location was not granted": "Posizione del ricevitore non concessa", + "RTL-SDR disconnected": "RTL-SDR disconnesso", + "Upstream response too large": "Risposta del servizio upstream troppo grande", + "Vector tile request timed out": "La richiesta dei tile vettoriali è andata in timeout", + "Vector tiles unavailable": "Tile vettoriali non disponibili", + "Vector tile metadata unavailable": "Metadati dei tile vettoriali non disponibili", + "Zoom in for vector tile coverage": "Ingrandisci per la copertura dei tile vettoriali", + "Saturation": "Saturazione", + "Edge Thickness": "Spessore dei bordi", + "Contrast": "Contrasto", + "Grain": "Grana", + "Vignette": "Vignettatura", + "Pixelation": "Pixelizzazione", + "Distortion": "Distorsione", + "Instability": "Instabilità", "Density": "Densità", + "Gain": "Guadagno", "Bloom": "Bloom", + "Scanlines": "Scanline", + "Sensitivity": "Sensibilità", + "WHOT/BHOT": "WHOT/BHOT", + "Ironbow": "Ironbow", + "unsaved CCTV calibration": "calibrazione CCTV non salvata", + "the open cockpit": "il cockpit aperto", + "Switching language reloads the page. This will be lost: {items}. Switch anyway?": "Cambiare lingua ricarica la pagina. Andrà perso: {items}. Cambiare comunque?", "VISUAL PRESETS": "PRESET VISIVI", "LOCATION": "POSIZIONE", "CONTACTS — nearest planes · vessels · sites": "CONTATTI — aerei · navi · siti più vicini", @@ -336,14 +1547,51 @@ "LIVE SIGNALS": "SEGNALI LIVE", "Contacts could not complete the requested transition; try again": "Impossibile completare la transizione richiesta per Contatti; riprova", "CCTV layer unavailable": "Livello CCTV non disponibile", + "Link shared": "Link condiviso", "Link copied!": "Link copiato!", "Copy failed": "Copia non riuscita", + "Return map to straight-down view": "Riporta la mappa alla vista dall'alto", + "Tilt map to oblique view": "Inclina la mappa in vista obliqua", + "Reset map to north up. Current heading {heading} degrees": "Orienta la mappa a nord. Direzione attuale {heading} gradi", + "Tilted view": "Vista inclinata", + "Straight-down view": "Vista dall'alto", + "North up": "Nord in alto", "CCTV calibration saved": "Calibrazione CCTV salvata", + "HDG": "HDG", + "PITCH": "INCL.", + "FOV": "FOV", + "RANGE": "PORTATA", + "HGT": "ALT.", + "ΔN": "ΔN", + "ΔE": "ΔE", + "{value}m": "{value} m", "CCTV calibration reset": "Calibrazione CCTV ripristinata", "ADJUST ON": "REGOLAZ. ON", "ADJUST": "REGOLAZ.", + "SNAPSHOT": "SNAPSHOT", + "LIVE": "LIVE", + "UPSTREAM": "UPSTREAM", + "SYNTHETIC": "SINTETICO", + "CONFIGURED": "CONFIGURATO", + "SEED": "CATALOGO", "UNKNOWN": "SCONOSCIUTO", + "OK": "OK", "ERROR": "ERRORE", + "Live HLS connected": "HLS live connesso", + "Live HLS unavailable": "HLS live non disponibile", + "No stream URL configured": "Nessun URL di stream configurato", + "Live stream connected": "Stream live connesso", + "Snapshot feed connected": "Feed di snapshot connesso", + "Media fetch failed": "Recupero dei media non riuscito", + "Upstream snapshot active": "Snapshot upstream attivo", + "Fallback Street View frame": "Fotogramma Street View di riserva", + "Upstream unavailable": "Upstream non disponibile", + "No source configured": "Nessuna fonte configurata", + "Configured source": "Fonte configurata", + "Configured Source": "Fonte configurata", + "Synthetic fallback": "Riserva sintetica", + "Upstream HTTP {status}": "Upstream HTTP {status}", + "Unexpected media type {type}": "Tipo di media inatteso {type}", "SOURCE · UNKNOWN": "FONTE · SCONOSCIUTA", "FRAME · LOADING": "FOTOGRAMMA · CARICAMENTO", "FRAME · UNAVAILABLE": "FOTOGRAMMA · NON DISPONIBILE", @@ -366,10 +1614,12 @@ "{city} · HDG {heading} · FOV {fov} · RANGE {range}m · {projection}{calBadge} · {provider}{status}": "{city} · HDG {heading} · FOV {fov} · PORTATA {range}m · {projection}{calBadge} · {provider}{status}", "{count} cameras loaded · click a camera to activate": { "one": "{count} telecamera caricata · clic su una telecamera per attivarla", + "many": "{count} di telecamere caricate · clic su una telecamera per attivarla", "other": "{count} telecamere caricate · clic su una telecamera per attivarla" }, "{count} cameras loaded · enable CCTV to activate": { "one": "{count} telecamera caricata · attiva CCTV per attivarla", + "many": "{count} di telecamere caricate · attiva CCTV per attivarle", "other": "{count} telecamere caricate · attiva CCTV per attivarle" }, "Enable CCTV to load camera intersections": "Attiva CCTV per caricare gli incroci delle telecamere", @@ -392,7 +1642,7 @@ "MIXED CONDITIONS": "CONDIZIONI MISTE", "CYCLE ON": "CICLO ON", "CYCLE OFF": "CICLO OFF", - "Stop automatic page cycling. Previous, Next, and the SIG/NEWS/LOCAL tabs stay available.": "Ferma lo scorrimento automatico delle pagine. Precedente, Successiva e le schede SIG/NEWS/LOCAL restano disponibili.", + "Stop automatic page cycling. Previous, Next, and the SIG/NEWS/LOCAL tabs stay available.": "Ferma lo scorrimento automatico delle pagine. Precedente, Successiva e le schede SIG/NOTIZIE/LOCALE restano disponibili.", "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.": "Scorre automaticamente le pagine del briefing ogni 9 secondi (Segnali → Notizie → Locale). Si mette in pausa quando passi sul pannello o lo selezioni. I dati dei segnali live si aggiornano comunque di continuo.", "ACQUIRING REGIONAL NEWS": "ACQUISIZIONE NOTIZIE REGIONALI", "REGIONAL NEWS UNAVAILABLE": "NOTIZIE REGIONALI NON DISPONIBILI", @@ -400,10 +1650,13 @@ "REGION UNAVAILABLE": "REGIONE NON DISPONIBILE", "NO RECENT LOCATION MATCHES": "NESSUNA CORRISPONDENZA RECENTE PER POSIZIONE", "{domain} · {age}": "{domain} · {age}", + "{value} KM/H": "{value} KM/H", "CLOUD {pct}%": "NUVOLE {pct}%", "CLOUD UNKNOWN": "NUVOLE SCONOSCIUTE", "{source} · LOCATION QUERY": "{source} · QUERY PER POSIZIONE", "REGIONAL NEWS": "NOTIZIE REGIONALI", + "{label} · {radius} AIR/SEA WINDOW": "{label} · FINESTRA ARIA/MARE {radius}", + "{scope} · INSTALLATIONS {coverage}": "{scope} · INSTALLAZIONI {coverage}", "CONTEXT STANDBY": "CONTESTO IN ATTESA", "ENABLE GLOBAL CONTEXT FOR PROXIMITY PINGS": "ATTIVA IL CONTESTO GLOBALE PER I PING DI PROSSIMITÀ", "CONTACT LOST · LAST KNOWN READOUT · NOT AN ALL-CLEAR": "CONTATTO PERSO · ULTIMA LETTURA NOTA · NON È UN VIA LIBERA", @@ -418,15 +1671,20 @@ "R": "D", "{count} INPUTS UNKNOWN · NOT AN ALL-CLEAR": { "one": "{count} INPUT SCONOSCIUTO · NON È UN VIA LIBERA", + "many": "{count} DI INPUT SCONOSCIUTI · NON È UN VIA LIBERA", "other": "{count} INPUT SCONOSCIUTI · NON È UN VIA LIBERA" }, "AVAILABLE INPUTS CURRENT · NOT AN ALL-CLEAR": "INPUT DISPONIBILI AGGIORNATI · NON È UN VIA LIBERA", + "SQUAWK {code} · {status}": "SQUAWK {code} · {status}", + "ADS-B PRIORITY · {status}": "PRIORITÀ ADS-B · {status}", + "ADS-B EMERGENCY · {status}": "EMERGENZA ADS-B · {status}", "AIRCRAFT": "AEREO", "ACQUIRING SURFACE": "ACQUISIZIONE SUPERFICIE", "SURFACE FALLBACK": "FALLBACK SUPERFICIE", "STALE FEED": "FEED OBSOLETO", "LIVE TRACK": "TRACCIA LIVE", "COMMERCIAL": "COMMERCIALE", + "{aircraftClass} · {emergency} · {feedState}": "{aircraftClass} · {emergency} · {feedState}", "{aircraftClass} · {feedState} · COURSE ALIGNED": "{aircraftClass} · {feedState} · ROTTA ALLINEATA", "ARROW · ESTIMATED DIRECTION": "FRECCIA · DIREZIONE STIMATA", "ROUTE DATA UNAVAILABLE": "DATI ROTTA NON DISPONIBILI", @@ -453,6 +1711,7 @@ "OBSERVED / MAPPED PINGS": "PING OSSERVATI / MAPPATI", "SOURCE-BACKED EVENTS · NO SYNTHETIC NEWS": "EVENTI DA FONTI · NESSUNA NOTIZIA SINTETICA", "LATEST LOCATION-MATCHED REPORTING": "ULTIME NOTIZIE PER POSIZIONE", + "{source} · LOCATION QUERY · RECENT": "{source} · QUERY PER POSIZIONE · RECENTI", "LOCAL INFO": "INFO LOCALI", "PLACE / CONDITIONS / POSITION": "LUOGO / CONDIZIONI / POSIZIONE", "TIME UNKNOWN": "ORA SCONOSCIUTA", @@ -468,6 +1727,7 @@ "DISTANCE UNKNOWN": "DISTANZA SCONOSCIUTA", "{count} INPUTS UNKNOWN": { "one": "{count} INPUT SCONOSCIUTO", + "many": "{count} DI INPUT SCONOSCIUTI", "other": "{count} INPUT SCONOSCIUTI" }, "SOURCE STATUS UNAVAILABLE": "STATO FONTE NON DISPONIBILE", @@ -479,10 +1739,12 @@ "No selected data layers": "Nessun livello dati selezionato", "{count} data layers could not be cleared": { "one": "{count} livello dati non è stato disattivato", + "many": "{count} di livelli dati non sono stati disattivati", "other": "{count} livelli dati non sono stati disattivati" }, "Cleared {count} data layers": { "one": "Disattivato {count} livello dati", + "many": "Disattivati {count} di livelli dati", "other": "Disattivati {count} livelli dati" }, "Selected data layers could not be cleared": "Impossibile disattivare i livelli dati selezionati", @@ -497,24 +1759,89 @@ "{mode} could not start because another layer did not stop cleanly": "Impossibile avviare {mode}: un altro livello non si è fermato correttamente", "Space Missions": "Missioni spaziali", "Context": "Contesto", - "Live Flights": "Voli Live", - "Military Flights": "Voli Militari", + "Rendered globe frames per second · toggle with `": "Fotogrammi al secondo del globo · attiva/disattiva con `", + "imported map files": "file di mappa importati", + "Ground heights could not be refreshed. Try the file again when the map has loaded.": "Impossibile aggiornare le quote del terreno. Riprova con il file quando la mappa è caricata.", + "{count} map objects": { + "one": "{count} oggetto sulla mappa", + "many": "{count} di oggetti sulla mappa", + "other": "{count} oggetti sulla mappa" + }, + ", drawn with its own styles": ", disegnato con i propri stili", + "Hide {name}": "Nascondi {name}", + "Show {name}": "Mostra {name}", + "Fly to {name}": "Vola su {name}", + "Remove {name}": "Rimuovi {name}", + "At most {count} files at once — remove one first.": "Al massimo {count} file alla volta: rimuovine uno prima.", + "Reading {name}…": "Lettura di {name}…", + "That file could not be read.": "Impossibile leggere quel file.", + "Added {count} files.": { + "one": "Aggiunto {count} file.", + "many": "Aggiunti {count} di file.", + "other": "Aggiunti {count} file." + }, + "{count} files could not be added ({name}: {error})": { + "one": "Impossibile aggiungere {count} file ({name}: {error})", + "many": "Impossibile aggiungere {count} di file ({name}: {error})", + "other": "Impossibile aggiungere {count} file ({name}: {error})" + }, + "Some KML content was left out.": "Una parte del contenuto KML è stata esclusa.", + "Press on the ground, not the sky": "Premi sul terreno, non sul cielo", + "Drag to size the box": "Trascina per dimensionare il riquadro", + "light {source} to use your {name} key": "attiva {source} per usare la tua chiave {name}", + "light {source}": "attiva {source}", + ", or ": ", oppure ", + "{requirement}, or {offer}": "{requirement}, oppure {offer}", + "Live Flights": "Voli live", + "Military Flights": "Voli militari", "Earthquakes (24h)": "Terremoti (24h)", "Satellites": "Satelliti", - "Space Missions (30d)": "Missioni Spaziali (30g)", - "Street Traffic": "Traffico Stradale", + "Space Missions (30d)": "Missioni spaziali (30 g)", + "Street Traffic": "Traffico stradale", "CCTV": "CCTV", "Radio": "Radio", - "Bikeshare": "Bike Sharing", - "Live AIS Vessels": "Navi AIS Live", - "Mapped Installations": "Installazioni Mappate", - "Global Context": "Contesto Globale", + "Bikeshare": "Bike sharing", + "Live AIS Vessels": "Navi AIS live", + "Mapped Installations": "Installazioni mappate", + "Global Context": "Contesto globale", "Datacenters": "Data Center", "Dams": "Dighe", - "Submarine Cables": "Cavi Sottomarini", - "FIRMS Active Fires": "Incendi Attivi FIRMS", + "Submarine Cables": "Cavi sottomarini", + "FIRMS Active Fires": "Incendi attivi FIRMS", + "Local ADS-B": "ADS-B locale", + "Transit": "Trasporto pubblico", + "Recent Imagery": "Immagini recenti", + "Fire Perimeters": "Perimetri degli incendi", + "GNSS Integrity": "Integrità GNSS", + "S2 GhostMaps": "S2 GhostMaps", + "Rain radar": "Radar pioggia", + "Lightning density": "Densità di fulmini", + "Cyclone advisories": "Bollettini sui cicloni", + "ALPR Cameras": "Telecamere ALPR", + "Live Vessels": "Navi live", + "Bike Share": "Bike sharing", + "Cameras": "Telecamere", + "Street Level": "Vista stradale", + "Mapped ALPR Cameras": "Telecamere ALPR mappate", + "Data Centers": "Data center", + "Active Fires": "Incendi attivi", + "Military aircraft": "Aerei militari", + "Vessels": "Navi", + "CCTV + Street View fallback": "CCTV + Street View di riserva", + "OpenStreetMap + optional Google Maps Places": "OpenStreetMap + Google Maps Places opzionale", + "GFS / ECMWF IFS · FORECAST": "GFS / ECMWF IFS · PREVISIONE", + "NOAA nowCOAST · OBSERVED": "NOAA nowCOAST · OSSERVATO", + "NASA FIRMS · LIVE": "NASA FIRMS · LIVE", + "OSM routing": "Percorsi OSM", + "data source|Local": "Dati locali", "ENABLING": "ATTIVAZIONE", "DISABLING": "DISATTIVAZIONE", + "Movement": "Movimento", + "Infrastructure": "Infrastrutture", + "Events": "Eventi", + "Weather": "Meteo", + "Utilities": "Strumenti", + "Other layers": "Altri livelli", "{state} · {source}": "{state} · {source}", "UNCERTAIN · {source} · lifecycle state requires reconciliation": "INCERTO · {source} · lo stato del ciclo di vita richiede riconciliazione", "{state} · {source} · {detail} · retry {seconds}s": "{state} · {source} · {detail} · nuovo tentativo tra {seconds}s", @@ -528,21 +1855,75 @@ "{state} · {source} · {ago}": "{state} · {source} · {ago}", "{source} · {ago}": "{source} · {ago}", "UNCERTAIN": "INCERTO", + "status chip|UNAVAILABLE": "NON DISPONIBILE", + "Data source unavailable": "Fonte dati non disponibile", "{name}: {state}": "{name}: {state}", - "{count}s ago": "{count}s fa", + "{count}s ago": "{count} s fa", + "Local FM stopped: internet radio started": "FM locale fermata: radio internet avviata", + "IDLE": "INATTIVO", "CONNECTING": "CONNESSIONE", + "TUNING": "SINTONIA", + "STREAMING": "IN STREAMING", + "UNSUPPORTED": "NON SUPPORTATO", + "idle": "inattivo", + "running": "in esecuzione", + "suspended": "sospeso", + "closed": "chiuso", + "feed status|live": "in diretta", + "feed status|stale": "obsoleto", + "feed status|unreachable": "irraggiungibile", + "feed status|invalid": "non valido", + "waiting for IQ": "in attesa di IQ", + "{count} messages": { + "one": "{count} messaggio", + "many": "{count} di messaggi", + "other": "{count} messaggi" + }, + "DSP {count} blocks": { + "one": "DSP {count} blocco", + "many": "DSP {count} di blocchi", + "other": "DSP {count} blocchi" + }, + "DSP waiting": "DSP in attesa", + "{level} dBFS audio": "audio {level} dBFS", + "audio signal --": "segnale audio --", + "audio {state}": "audio {state}", + "{count} HEARD": { + "one": "{count} RICEVUTO", + "many": "{count} RICEVUTI", + "other": "{count} RICEVUTI" + }, + "DISCONNECT": "DISCONNETTI", + "CONNECT": "CONNETTI", + "LOCATING…": "LOCALIZZAZIONE…", + "LOCATED": "LOCALIZZATO", + "LOCATE": "LOCALIZZA", + " · read while Local ADS-B is on": " · letto mentre ADS-B locale è attivo", + "Decoder feeds: {feeds}": "Feed dei decoder: {feeds}", + "Language: {language}": "Lingua: {language}", + "Change the interface language": "Cambia la lingua dell'interfaccia", + "Interface language": "Lingua dell'interfaccia", + "Search languages": "Cerca lingue", + "No matching languages": "Nessuna lingua corrispondente", "📍 Location: --": "📍 Posizione: --", "Landmark: --": "Punto di interesse: --", "Searched location": "Luogo cercato", "ORBIT": "ORBITA", "Location not found": "Luogo non trovato", + "Check the spelling and press Enter to search again.": "Controlla l'ortografia e premi Enter per cercare di nuovo.", "Search failed": "Ricerca non riuscita", + "Press Enter to try again.": "Premi Enter per riprovare.", + "Detailed outline unavailable": "Contorno dettagliato non disponibile", "Fly to a POI first": "Vola prima a un punto di interesse", "Reset to full globe view": "Ripristina la vista del globo intero", "Reset cockpit to full globe view": "Ripristina il cockpit alla vista del globo intero", "Resetting to full globe view": "Ripristino della vista del globo intero", "Resetting cockpit to full globe view": "Ripristino del cockpit alla vista del globo intero", "MAP": "MAPPA", + "Layers": "Livelli", + "Search": "Cerca", + "More": "Altro", + "Panels": "Pannelli", "panel": "pannello", "Expand {name}": "Espandi {name}", "Collapse {name}": "Comprimi {name}", @@ -551,17 +1932,31 @@ "Expand Radio section": "Espandi la sezione Radio", "Collapse Radio section": "Comprimi la sezione Radio", "Panel layout updated — positions reset to new defaults": "Layout dei pannelli aggiornato — posizioni ripristinate ai nuovi valori predefiniti", + "Austin": "Austin", + "San Francisco": "San Francisco", + "New York": "New York", + "Tokyo": "Tokyo", + "London": "Londra", + "Paris": "Parigi", + "Dubai": "Dubai", + "Washington DC": "Washington DC", + "Tallinn": "Tallinn", + "Los Angeles": "Los Angeles", "Collapse Cockpit display options": "Comprimi le opzioni display del cockpit", "Expand Cockpit display options": "Espandi le opzioni display del cockpit", "Collapse Cockpit Radio controls": "Comprimi i controlli Radio del cockpit", "Expand Cockpit Radio controls": "Espandi i controlli Radio del cockpit", + "CH {index} / {total}": "CAN {index} / {total}", "NO STATIONS": "NESSUNA STAZIONE", "NO STATION AVAILABLE": "NESSUNA STAZIONE DISPONIBILE", "{name}, station {index} of {total}": "{name}, stazione {index} di {total}", "No station available": "Nessuna stazione disponibile", "OFF AIR": "FUORI ONDA", "STATION UNAVAILABLE": "STAZIONE NON DISPONIBILE", + "Station unavailable after directory refresh": "Stazione non disponibile dopo l'aggiornamento dell'elenco", "Radio could not {action} cleanly": "La Radio non ha potuto {action} correttamente", + "Go to expanded Radio section": "Vai alla sezione Radio espansa", + "Expand Radio section in Context": "Espandi la sezione Radio in Contesto", "Close compact Radio controls": "Chiudi i controlli Radio compatti", "Open compact Radio controls": "Apri i controlli Radio compatti", "SYNC": "SYNC", @@ -571,14 +1966,17 @@ "Reconcile Radio — lifecycle uncertain": "Riconcilia la Radio — ciclo di vita incerto", "Disable Radio": "Disattiva la Radio", "Enable Radio": "Attiva la Radio", + "{category} ({count})": "{category} ({count})", "DIRECTORY BAND": "BANDA ELENCO", "{category} BAND": "BANDA {category}", "NO STATION SELECTED": "NESSUNA STAZIONE SELEZIONATA", "Directory metadata only": "Solo metadati dell'elenco", "Loading station directory…": "Caricamento dell'elenco stazioni…", - "Choose a globe marker or use next.": "Scegli un marcatore sul globo o usa SUCC.", + "Choose a globe marker or use next.": "Scegli un marcatore sul globo o passa alla successiva.", "TAGS · {tags}": "TAG · {tags}", "Play": "Riproduci", + "PAUSE": "PAUSA", + "RESUME": "RIPRENDI", "PLAY": "PLAY", "selected": "selezionata", "nearest": "più vicina", @@ -608,63 +2006,692 @@ "Radio is enabling…": "Attivazione della Radio…", "Radio is disabling…": "Disattivazione della Radio…", "Radio lifecycle is uncertain — use Enable or Disable to reconcile": "Il ciclo di vita della Radio è incerto — usa Attiva o Disattiva per riconciliare", + "Clear reading": "Cancella la lettura", + "Earlier observation": "Osservazione precedente", + "Observed history": "Storico osservato", + "Later observation": "Osservazione successiva", + "Latest": "Più recente", + "Newest frame per product": "Fotogramma più recente per prodotto", + "Replay observed history": "Rivedi lo storico osservato", + "Imagery on Esri · Google 3D returns when cleared": "Immagini su Esri · Google 3D torna dopo la cancellazione", + "Point the camera at the ground to use the view": "Punta la camera verso il suolo per usare la vista", + "That point cannot anchor a box": "Quel punto non può ancorare un riquadro", + "Imagery stops at ±{limit}° latitude": "Le immagini si fermano a ±{limit}° di latitudine", + "{owner} is using the pointer — close it first": "{owner} sta usando il puntatore: chiudilo prima", + "Box is {size} wide · limit {limit}": "Il riquadro è largo {size} · limite {limit}", + "View is {size} wide · limit {limit}": "La vista è larga {size} · limite {limit}", + "VS BASEMAP": "VS MAPPA DI BASE", + "A / B": "A / B", + "Newest low-cloud day for this box · scene cloud, not box cloud": "Giorno più recente con poche nuvole per questo riquadro · nuvole della scena, non del riquadro", + "Newest day covering this box · cloudier than 20%": "Giorno più recente che copre questo riquadro · nuvole oltre il 20%", + "Newest day with imagery for this box · partial coverage": "Giorno più recente con immagini per questo riquadro · copertura parziale", + "Newest daily overview for this box": "Panoramica giornaliera più recente per questo riquadro", + "newest clear day": "giorno sereno più recente", + "newest day (cloudy)": "giorno più recente (nuvoloso)", + "newest day (partial coverage)": "giorno più recente (copertura parziale)", + "newest overview": "panoramica più recente", + "No imagery": "Nessuna immagine", + "Loading": "Caricamento", + "coverage|full": "completa", + "coverage|partial": "parziale", + "unknown": "sconosciuta", + "no imagery": "nessuna immagine", + "{percent}% cloud": "{percent}% di nubi", + "{min}–{max}% cloud": "{min}–{max}% di nubi", + "NO BOX": "NESSUN RIQUADRO", + "SEARCHING": "RICERCA", + "{count} DAYS": { + "one": "{count} GIORNO", + "many": "{count} DI GIORNI", + "other": "{count} GIORNI" + }, + "Zoom in or draw a smaller box": "Ingrandisci o disegna un riquadro più piccolo", + "Select a box or use the view": "Seleziona un riquadro o usa la vista", + "Searching the last 30 days": "Ricerca negli ultimi 30 giorni", + "No days to show for this box": "Nessun giorno da mostrare per questo riquadro", + "Drag the divider · SWAP trades sides": "Trascina il divisore · SCAMBIA inverte i lati", + "← → preview · A or B pins the focused day": "← → anteprima · A o B fissa il giorno selezionato", + "← → preview the other side · A or B pins it": "← → anteprima dell'altro lato · A o B lo fissa", + "S on another day replaces it · × unpins": "S su un altro giorno lo sostituisce · × lo sblocca", + "← → preview · S shows the focused day": "← → anteprima · S mostra il giorno selezionato", + "ZOOM IN": "INGRANDISCI", + "Fly in until the view fits the 1,000 km limit": "Avvicinati finché la vista rientra nel limite di 1.000 km", + "Imagery days, newest first · arrows move, S or A and B pin": "Giorni con immagini, dal più recente · le frecce spostano, S o A e B fissano", + "On the map": "Sulla mappa", + "Mode": "Modalità", + "Imagery opacity": "Opacità delle immagini", + "SWAP": "SCAMBIA", + "Trade the two sides of the divider": "Inverti i due lati del divisore", + "SELECT BOX": "SELEZIONA RIQUADRO", + "Drag a box on the map (Esc cancels)": "Trascina un riquadro sulla mappa (Esc annulla)", + "USE VIEW": "USA LA VISTA", + "Use the current view as the box": "Usa la vista attuale come riquadro", + "Forget the box and its images": "Dimentica il riquadro e le sue immagini", + "START HERE": "INIZIA DA QUI", + "Checking": "Verifica", + "PREVIEW": "ANTEPRIMA", + "Newest day with imagery for this box": "Giorno più recente con immagini per questo riquadro", + "SHOW": "MOSTRA", + "Pin {day} as {slot}": "Fissa {day} come {slot}", + "Show {day}": "Mostra {day}", + "pinned {slot}": "fissato {slot}", + "shown": "mostrato", + "preview": "anteprima", + "start here": "inizia da qui", + "No box": "Nessun riquadro", + "Searching": "Ricerca", + "Every day is empty here": "Ogni giorno è vuoto qui", + "Sources off": "Fonti disattivate", + "VS": "VS", + "Not set": "Non impostato", + "Basemap": "Mappa di base", + "Source off": "Fonte disattivata", + "Unpin {slot}": "Sblocca {slot}", + "Unpin the image": "Sblocca l'immagine", + "EXPORT {slot}": "ESPORTA {slot}", + "EXPORT": "ESPORTA", + "Download {slot} as a PNG": "Scarica {slot} come PNG", + "Download the image as a PNG": "Scarica l'immagine come PNG", + "Box {width} × {height} km": "Riquadro {width} × {height} km", + "Acquired {time}": "Acquisita {time}", + "Coverage {coverage}": "Copertura {coverage}", + "START HERE · {reason}": "INIZIA DA QUI · {reason}", + "Daily overview shows little detail in a box this small": "La panoramica giornaliera mostra pochi dettagli in un riquadro così piccolo", + "Imagery: NASA GIBS and Worldview · HLS (Sentinel-2, Landsat 8/9) and VIIRS": "Immagini: NASA GIBS e Worldview · HLS (Sentinel-2, Landsat 8/9) e VIIRS", + "Details": "Dettagli", + "Times, coverage, sources": "Orari, copertura, fonti", + "HIDE EMPTY DAYS": "NASCONDI GIORNI VUOTI", + "SHOW EMPTY DAYS · {count}": "MOSTRA GIORNI VUOTI · {count}", + "Days the probe found empty in this box": "Giorni che la verifica ha trovato vuoti in questo riquadro", + "image": "immagine", + "BASEMAP": "MAPPA DI BASE", + "The basemap": "La mappa di base", + "basemap": "mappa di base", + "Recent imagery against the basemap divider": "Divisore tra immagini recenti e mappa di base", + "Recent imagery A and B divider": "Divisore tra immagini recenti A e B", + "{before} {left} percent, {after} {right} percent": "{before} {left} percento, {after} {right} percento", + "Export failed · {error}": "Esportazione non riuscita · {error}", "Scene action failed": "Azione sulla scena non riuscita", + "New scene name": "Nome della nuova scena", + "Delete scene \"{scene}\" and all shots?": "Eliminare la scena \"{scene}\" e tutti i suoi scatti?", "Delete shot \"{shot}\"?": "Eliminare lo scatto \"{shot}\"?", + "Stopped (Esc)": "Fermato (Esc)", "SPARSE": "RADA", "BALANCED": "BILANCIATA", + "No shots yet. Use CAPTURE SHOT to save current look.": "Ancora nessuno scatto. Usa CATTURA SCATTO per salvare l'aspetto attuale.", + "Double-click to rename": "Doppio clic per rinominare", + "Shot name": "Nome dello scatto", + "LOAD": "CARICA", "DEL": "ELIM", + "{duration}s + {hold}s": "{duration}s + {hold}s", + "Choose files": "Scegli i file", + "{count} files selected": { + "one": "{count} file selezionato", + "many": "{count} di file selezionati", + "other": "{count} file selezionati" + }, + "No file chosen": "Nessun file scelto", + "Cancel": "Annulla", + "EDIT DETAILS": "MODIFICA DETTAGLI", + "SHARE SCENE": "CONDIVIDI SCENA", + "Shared flight follow expired": "Il tracciamento condiviso del volo è scaduto", + "Shared military flight follow expired": "Il tracciamento condiviso del volo militare è scaduto", + "Shared satellite follow expired": "Il tracciamento condiviso del satellite è scaduto", + "Shared flight could not be restored — feed unavailable": "Impossibile ripristinare il volo condiviso: feed non disponibile", + "Shared military flight could not be restored — feed unavailable": "Impossibile ripristinare il volo militare condiviso: feed non disponibile", + "Shared satellite could not be restored — feed unavailable": "Impossibile ripristinare il satellite condiviso: feed non disponibile", + "Shared flight is unavailable": "Il volo condiviso non è disponibile", + "Shared military flight is unavailable": "Il volo militare condiviso non è disponibile", + "Shared satellite is unavailable": "Il satellite condiviso non è disponibile", "entity": "elemento", "Shared {subject} follow expired": "Il tracciamento condiviso di {subject} è scaduto", "Shared {subject} could not be restored — feed unavailable": "Impossibile ripristinare la condivisione di {subject} — feed non disponibile", "Shared {subject} is unavailable": "La condivisione di {subject} non è disponibile", + "{id} isn't reporting now — showing where it was last seen": "{id} non sta trasmettendo ora: viene mostrata l'ultima posizione nota", + "{id} isn't reporting now — showing where it was at {time}": "{id} non sta trasmettendo ora: viene mostrata la posizione alle {time}", + "This share link can't be opened": "Impossibile aprire questo link di condivisione", + "Shared vessel is unavailable": "La nave condivisa non è disponibile", "ACQUIRING": "ACQUISIZIONE", "SHARED {subject}": "CONDIVISO: {subject}", + "subject": "soggetto", "LOADING LIVE DATA": "CARICAMENTO DATI LIVE", "LOAD COMPLETE": "CARICAMENTO COMPLETATO", "LOAD CANCELLED": "CARICAMENTO ANNULLATO", - "LOAD FAILED": "CARICAMENTO FALLITO", + "LOAD FAILED": "CARICAMENTO NON RIUSCITO", "LIVE DATA OFF": "DATI LIVE DISATTIVATI", "MAPPED SITES LOADED": "SITI MAPPATI CARICATI", "RETRYING MAPPED SITES": "NUOVO TENTATIVO SITI MAPPATI", "FETCHING MAPPED SITES": "RICERCA SITI MAPPATI", + "RETRYING ALPR CAMERAS": "NUOVO TENTATIVO TELECAMERE ALPR", + "FETCHING ALPR CAMERAS": "RICERCA TELECAMERE ALPR", + "OVERPASS TEMPORARILY UNAVAILABLE": "OVERPASS TEMPORANEAMENTE NON DISPONIBILE", + "OVERPASS RATE-LIMITED": "OVERPASS HA LIMITATO LE RICHIESTE", + "OVERPASS TIMED OUT": "OVERPASS IN TIMEOUT", + "OVERPASS COULD NOT COMPLETE THE QUERY": "OVERPASS NON HA POTUTO COMPLETARE LA QUERY", + "MAP TILES TEMPORARILY UNAVAILABLE": "TILE DELLA MAPPA TEMPORANEAMENTE NON DISPONIBILI", + "MAPPED NAMES TEMPORARILY UNAVAILABLE": "NOMI MAPPATI TEMPORANEAMENTE NON DISPONIBILI", "TURNING OFF LIVE DATA": "DISATTIVAZIONE DATI LIVE", "REFRESHING LIVE DATA": "AGGIORNAMENTO DATI LIVE", "syncing road network": "sincronizzazione rete stradale", "retry pending": "nuovo tentativo in sospeso", "retrying in {seconds}s": "nuovo tentativo tra {seconds}s", + "ALPR cameras": "telecamere ALPR", + "OpenSky OAuth client missing/invalid": "Client OAuth di OpenSky mancante/non valido", + "OpenSky OAuth rejected credentials": "OAuth di OpenSky ha rifiutato le credenziali", + "OpenSky username/password rejected": "Nome utente/password di OpenSky rifiutati", + "OpenSky auth missing": "Autenticazione OpenSky mancante", + "OpenSky auth required": "Autenticazione OpenSky richiesta", + "OpenSky auth invalid": "Autenticazione OpenSky non valida", + "OpenSky auth failed": "Autenticazione OpenSky non riuscita", + "KartaView answered HTTP {status}": "KartaView ha risposto HTTP {status}", + "Panoramax answered HTTP {status}": "Panoramax ha risposto HTTP {status}", + "KartaView refused the request (code {code})": "KartaView ha rifiutato la richiesta (codice {code})", + "Vector tiles unavailable (HTTP {status})": "Tile vettoriali non disponibili (HTTP {status})", + "GNSS feed unavailable (HTTP {status})": "Feed GNSS non disponibile (HTTP {status})", + "{count} CelesTrak groups unavailable": { + "one": "{count} gruppo CelesTrak non disponibile", + "many": "{count} di gruppi CelesTrak non disponibili", + "other": "{count} gruppi CelesTrak non disponibili" + }, + "{feed} feed unavailable": "feed {feed} non disponibile", + "Source snapshot {minutes} min old": "Snapshot della fonte vecchio di {minutes} min", + "{source} rate limited (anonymous)": "{source}: limite di richieste (anonimo)", + "{source} rate limited": "{source}: limite di richieste", + "{source} network error": "{source}: errore di rete", + "Malformed {source} aircraft rows": "Righe aereo di {source} non valide", + "Malformed {source} response": "Risposta di {source} non valida", + "entry {n}": "voce {n}", + "feeds {names} stale": { + "one": "feed {names} obsoleto", + "many": "feed {names} obsoleti", + "other": "feed {names} obsoleti" + }, + "feeds {names} unreachable": { + "one": "feed {names} irraggiungibile", + "many": "feed {names} irraggiungibili", + "other": "feed {names} irraggiungibili" + }, + "feeds {names} invalid": { + "one": "feed {names} non valido", + "many": "feed {names} non validi", + "other": "feed {names} non validi" + }, + "Loading {feeds}": "Caricamento di {feeds}", + "{count} heard": { + "one": "{count} ricevuto", + "many": "{count} ricevuti", + "other": "{count} ricevuti" + }, + "USB {rate} msg/s": "USB {rate} msg/s", + "{rate} msg/s": "{rate} msg/s", + "{count} feeds live": { + "one": "{count} feed live", + "many": "{count} di feed live", + "other": "{count} feed live" + }, + "{feed} {count} ({seconds}s old)": "{feed} {count} ({seconds}s fa)", + "Street Level toggle failed": "Attivazione di Vista stradale non riuscita", + "Street Level could not start": "Impossibile avviare Vista stradale", + "SHRINK": "RIDUCI", + "EXPAND": "ESPANDI", + "Shrink": "Riduci", + "Expand": "Espandi", + "ANY DATE": "QUALSIASI DATA", + "LAST 10 YEARS": "ULTIMI 10 ANNI", + "LAST 5 YEARS": "ULTIMI 5 ANNI", + "LAST 3 YEARS": "ULTIMI 3 ANNI", + "LAST 2 YEARS": "ULTIMI 2 ANNI", + "LAST YEAR": "ULTIMO ANNO", + "LAST 6 MONTHS": "ULTIMI 6 MESI", + "LAST 3 MONTHS": "ULTIMI 3 MESI", + "LAST MONTH": "ULTIMO MESE", + "LAST {count} DAYS": { + "one": "ULTIMO {count} GIORNO", + "many": "ULTIMI {count} DI GIORNI", + "other": "ULTIMI {count} GIORNI" + }, + "{window} · SINCE {date}": "{window} · DAL {date}", + "Turn Street Level off": "Disattiva Vista stradale", + "Turn Street Level on": "Attiva Vista stradale", + "{name} imagery on": "Immagini {name} attive", + "{name} imagery off": "Immagini {name} disattivate", + "Image by {creator}": "Immagine di {creator}", + " or ": " o ", + "OPEN {labels}": "APRI {labels}", + "Open {names} at the centre of the view": "Apri {names} al centro della vista", + "Zoom in to a street to open {names} here": "Ingrandisci su una strada per aprire {names} qui", + "Switch Street Level on to draw its coverage.": "Attiva Vista stradale per disegnarne la copertura.", + "Every provider is switched off: light a chip to draw its coverage.": "Tutti i provider sono disattivati: accendi un chip per disegnarne la copertura.", + "Loading this sequence…": "Caricamento di questa sequenza…", + "{n} images in this sequence · Esc clears": { + "one": "{n} immagine in questa sequenza · Esc cancella", + "many": "{n} di immagini in questa sequenza · Esc cancella", + "other": "{n} immagini in questa sequenza · Esc cancella" + }, + "No sequences in view match the filter": "Nessuna sequenza nella vista corrisponde al filtro", + "No coverage in view": "Nessuna copertura nella vista", + "{n} streets in view · click a line for its nearest photo": { + "one": "{n} strada nella vista · clic su una linea per la foto più vicina", + "many": "{n} di strade nella vista · clic su una linea per la foto più vicina", + "other": "{n} strade nella vista · clic su una linea per la foto più vicina" + }, + "{n} sequences in view · click a line for its nearest photo": { + "one": "{n} sequenza nella vista · clic su una linea per la foto più vicina", + "many": "{n} di sequenze nella vista · clic su una linea per la foto più vicina", + "other": "{n} sequenze nella vista · clic su una linea per la foto più vicina" + }, + "{n} sequences in view · click a line for its photos": { + "one": "{n} sequenza nella vista · clic su una linea per le sue foto", + "many": "{n} di sequenze nella vista · clic su una linea per le sue foto", + "other": "{n} sequenze nella vista · clic su una linea per le sue foto" + }, + "km/h": "km/h", + "m/s": "m/s", + "mph": "mph", + "hPa": "hPa", + "kt": "kn", + "kts": "kn", + "ft": "ft", + "km": "km", + "m": "m", + "h": "h", + "min": "min", + "s": "s", + "dB": "dB", "Celestial ring — reveal the full globe": "Anello celeste — mostra il globo intero", "Celestial ring — available in Normal style": "Anello celeste — disponibile nello stile Normale", "Detection overlay: {mode}": "Overlay di rilevamento: {mode}", "Detection overlay: off": "Overlay di rilevamento: disattivato", "DETECT": "RILEV.", + "{time} · {minutes} min ago": "{time} · {minutes} min fa", + "Active weather": "Meteo attivo", + "LATEST · newest per product": "ULTIMO · il più recente per prodotto", + "Forecast · valid {valid} · issued {issued}": "Previsione · valida {valid} · emessa {issued}", + "{detail} · Does not follow history": "{detail} · Non segue lo storico", + "Forecast · valid {valid}": "Previsione · valida {valid}", + "voice|OFF": "OFF", + "voice|CONNECTING": "CONNESSIONE", "voice|LISTENING": "IN ASCOLTO", "voice|EXECUTING": "ESECUZIONE", + "voice|ERROR": "ERRORE", + "Voice provider": "Provider vocale", + "Changing provider reconnects voice if it is on.": "Cambiare provider riconnette la voce se è attiva.", + "Voice Settings": "Impostazioni voce", "AI AGENT": "AGENTE IA", "Voice model tier — applies next session": "Livello del modello vocale: si applica alla prossima sessione", + "STD": "STD", "Estimated session cost": "Costo stimato della sessione", - "Voice control — activate to toggle voice; hold Space to speak": "Controllo vocale: attiva per abilitare la voce; tieni premuto Spazio per parlare", + "Voice control — activate to toggle voice; hold Space to speak": "Controllo vocale: attiva per abilitare o disabilitare la voce; tieni premuto Space per parlare", + "ON/OFF": "ON/OFF", "VOICE STANDBY": "VOCE IN ATTESA", "VOICE CONTROL": "CONTROLLO VOCALE", - "Hold Space to speak · tap Space to activate focused controls": "Tieni premuto Spazio per parlare · tocca Spazio per attivare i controlli in focus", + "Hold Space to speak · tap Space to activate focused controls": "Tieni premuto Space per parlare · premi Space per attivare il controllo selezionato", + "VOICE": "VOCE", + "Preview": "Anteprima", + "Settings": "Impostazioni", + "Close voice panel": "Chiudi il pannello voce", + "Voice replies appear here.": "Le risposte vocali appaiono qui.", + "Voice assistant": "Assistente vocale", + "Dismiss voice card": "Chiudi la scheda voce", + "YOU": "TU", + "THIS": "QUESTO", + "Plan": "Piano", + "Referenced items": "Elementi citati", + "NOTES & SOURCES": "NOTE E FONTI", + "Show Voice Preview": "Mostra l'anteprima voce", + "Voice inactivity timeout": "Timeout di inattività della voce", + "Minutes": "Minuti", + "Custom": "Personalizzato", + "These preferences stay in this browser.": "Queste preferenze restano in questo browser.", "VOICE SYSTEM ERROR": "ERRORE SISTEMA VOCALE", "DISMISS": "CHIUDI", "Check microphone permission and network access, then try again.": "Controlla il permesso del microfono e l'accesso alla rete, poi riprova.", - "Release Space to send": "Rilascia Spazio per inviare", - "Hold Space to talk": "Tieni premuto Spazio per parlare", + "Gemini returned an oversized audio chunk": "Gemini ha restituito un blocco audio troppo grande", + "Gemini returned an unsupported audio format": "Gemini ha restituito un formato audio non supportato", + "Gemini returned an invalid audio sample rate": "Gemini ha restituito una frequenza di campionamento audio non valida", + "Gemini returned incomplete PCM audio": "Gemini ha restituito audio PCM incompleto", + "This browser does not support Gemini microphone audio": "Questo browser non supporta l'audio del microfono per Gemini", + "Microphone audio processing failed": "Elaborazione dell'audio del microfono non riuscita", + "Gemini audio playback fell behind. Reconnect to continue.": "La riproduzione audio di Gemini è rimasta indietro. Riconnetti per continuare.", + "Gemini token response did not include an ephemeral credential": "La risposta del token Gemini non includeva una credenziale temporanea", + "Invalid Gemini connection endpoint": "Endpoint di connessione Gemini non valido", + "Gemini voice could not connect. Try again.": "Impossibile connettere la voce Gemini. Riprova.", + "Gemini voice requires a same-origin app request": "La voce Gemini richiede una richiesta dall'app con la stessa origine", + "Add a Gemini API key in Provider Settings": "Aggiungi una chiave API Gemini in Impostazioni provider", + "The Gemini Live model configuration is invalid": "La configurazione del modello Gemini Live non è valida", + "Gemini voice is starting too often. Try again shortly.": "La voce Gemini si sta avviando troppo spesso. Riprova tra poco.", + "Gemini quota is unavailable. Try again later.": "La quota Gemini non è disponibile. Riprova più tardi.", + "Gemini access was refused. Check the API key and model access.": "L'accesso a Gemini è stato rifiutato. Controlla la chiave API e l'accesso al modello.", + "Gemini Live is unavailable for the configured model.": "Gemini Live non è disponibile per il modello configurato.", + "Token request is too large": "La richiesta del token è troppo grande", + "Use an empty JSON token request": "Usa una richiesta di token JSON vuota", + "Release Space to send": "Rilascia Space per inviare", + "Hold Space to talk": "Tieni premuto Space per parlare", + "Voice command context is too large": "Il contesto del comando vocale è troppo grande", + "Gemini reliable transport exceeded its queue limit. Start voice again.": "Il trasporto affidabile di Gemini ha superato il limite della coda. Riavvia la voce.", + "Gemini reliable transport did not drain. Start voice again.": "Il trasporto affidabile di Gemini non si è svuotato. Riavvia la voce.", + "Gemini token request failed (HTTP {status})": "Richiesta del token Gemini non riuscita (HTTP {status})", + "Gemini token response did not include a valid model": "La risposta del token Gemini non includeva un modello valido", + "Gemini token response did not include session settings": "La risposta del token Gemini non includeva le impostazioni della sessione", + "Gemini session settings do not match the input mode": "Le impostazioni della sessione Gemini non corrispondono alla modalità di input", "Requesting microphone": "Richiesta microfono", + "Gemini could not submit this input. Start voice again.": "Gemini non ha potuto inviare questo input. Riavvia la voce.", + "Connecting to Gemini": "Connessione a Gemini", "Ask or command": "Chiedi o comanda", + "Gemini returned an oversized message": "Gemini ha restituito un messaggio troppo grande", + "Gemini Live connection failed. Check network access, then start voice again.": "Connessione a Gemini Live non riuscita. Controlla l'accesso alla rete, poi riavvia la voce.", + "Gemini Live connection ended. Start voice again for a new conversation.": "Connessione a Gemini Live terminata. Riavvia la voce per una nuova conversazione.", + "Gemini Live could not start. Start voice again to request a fresh session.": "Gemini Live non si è avviato. Riavvia la voce per richiedere una nuova sessione.", + "Start voice again for a fresh token and a new conversation.": "Riavvia la voce per un nuovo token e una nuova conversazione.", + "Start voice again to request a fresh session credential.": "Riavvia la voce per richiedere una nuova credenziale di sessione.", + "Microphone permission was denied. Allow microphone access and try again.": "Il permesso del microfono è stato negato. Consenti l'accesso al microfono e riprova.", + "Gemini connection timed out. Try again.": "La connessione a Gemini è andata in timeout. Riprova.", + "Gemini voice could not start": "Impossibile avviare la voce Gemini", + "Gemini did not finish the interrupted reply. Start voice again.": "Gemini non ha completato la risposta interrotta. Riavvia la voce.", + "Gemini session expiring; finishing the current reply": "Sessione Gemini in scadenza; completamento della risposta in corso", + "Gemini rejected the voice session. Start voice again to request a fresh session.": "Gemini ha rifiutato la sessione vocale. Riavvia la voce per richiedere una nuova sessione.", + "Start voice again for a fresh session credential. If it repeats, check Gemini model and API access.": "Riavvia la voce per una nuova credenziale di sessione. Se si ripete, controlla il modello Gemini e l'accesso API.", + "Gemini action history is full. Start voice again for a fresh session.": "La cronologia delle azioni di Gemini è piena. Riavvia la voce per una nuova sessione.", + "Gemini requested too many simultaneous actions": "Gemini ha richiesto troppe azioni simultanee", "Running command": "Comando in esecuzione", + "Voice text command is too long": "Il comando vocale testuale è troppo lungo", + "Gemini voice is not connected": "La voce Gemini non è connessa", + "Gemini interrupted input exceeded its buffer or wait limit. Start voice again.": "L'input interrotto di Gemini ha superato il limite di buffer o di attesa. Riavvia la voce.", + "Gemini Live connection is expiring. Start voice again for a new conversation.": "La connessione a Gemini Live sta scadendo. Riavvia la voce per una nuova conversazione.", "Voice off": "Voce disattivata", + "Gemini voice sessions have a time limit. When a session expires, start voice again for a new conversation.": "Le sessioni vocali Gemini hanno un limite di tempo. Quando una sessione scade, riavvia la voce per una nuova conversazione.", + "Stopped by voice": "Fermato dalla voce", + "Automatic stop is unavailable for this voice connection.": "L'arresto automatico non è disponibile per questa connessione vocale.", + "Preview is off.": "L'anteprima è disattivata.", + "Your choice applies now, but could not be saved.": "La tua scelta vale da subito, ma non è stato possibile salvarla.", "WebRTC microphone support unavailable": "Supporto microfono WebRTC non disponibile", "VOICE UNAVAILABLE": "VOCE NON DISPONIBILE", "VOICE ACTIVE": "VOCE ATTIVA", "Voice session could not be started.": "Impossibile avviare la sessione vocale.", + "MINI": "MINI", "Next session: {pendingId} — this session stays on {modelId}": "Prossima sessione: {pendingId}. Questa sessione resta su {modelId}", "Voice model: {pendingId} — click to switch to {target}; applies next session": "Modello vocale: {pendingId}. Clic per passare a {target}; si applica alla prossima sessione", + "standard": "standard", + "mini": "mini", + "COST UNKNOWN": "COSTO SCONOSCIUTO", + "ChatGPT OAuth session: {responses} response(s), {input} input and {output} output tokens, {captions} caption transcription(s) reported.": "Sessione ChatGPT OAuth: {responses} risposta/e, {input} token di input e {output} di output, {captions} trascrizione/i di sottotitoli riportate.", + "USD cost and the API spend cap are unavailable for this auth mode.": "Il costo in USD e il limite di spesa API non sono disponibili per questa modalità di autenticazione.", + "Usage is incomplete because a response was still in flight when the session ended.": "L'utilizzo è incompleto perché una risposta era ancora in corso quando la sessione è terminata.", "Estimated session cost on {modelId} — {responses} response(s). Warns at {warn}, ends the session at {cap}.": "Costo stimato della sessione su {modelId}: {responses} risposta/e. Avviso a {warn}, la sessione termina a {cap}.", + "Estimate is incomplete — a response was still in flight when the session ended, so its usage was never reported.": "Stima incompleta: una risposta era ancora in corso quando la sessione è terminata, quindi il suo utilizzo non è mai stato riportato.", + "STANDARD": "STANDARD", "{tier} applies next session": "{tier} si applica alla prossima sessione", "Session ended — cost cap {cost}": "Sessione terminata: limite di costo {cost}", + "MIC": "MIC", "Radio did not start": "La radio non si è avviata", + "{n} aircraft": { + "one": "{n} aereo", + "many": "{n} di aerei", + "other": "{n} aerei" + }, + "{n} military aircraft": { + "one": "{n} aereo militare", + "many": "{n} di aerei militari", + "other": "{n} aerei militari" + }, + "{n} ships": { + "one": "{n} nave", + "many": "{n} di navi", + "other": "{n} navi" + }, + "{n} satellites": { + "one": "{n} satellite", + "many": "{n} di satelliti", + "other": "{n} satelliti" + }, + "{n} launches": { + "one": "{n} lancio", + "many": "{n} di lanci", + "other": "{n} lanci" + }, + "{n} earthquakes": { + "one": "{n} terremoto", + "many": "{n} di terremoti", + "other": "{n} terremoti" + }, + "{n} fires": { + "one": "{n} incendio", + "many": "{n} di incendi", + "other": "{n} incendi" + }, + "{n} fire perimeters": { + "one": "{n} perimetro di incendio", + "many": "{n} di perimetri di incendi", + "other": "{n} perimetri di incendi" + }, + "{n} cyclones": { + "one": "{n} ciclone", + "many": "{n} di cicloni", + "other": "{n} cicloni" + }, + "{n} buses": { + "one": "{n} autobus", + "many": "{n} di autobus", + "other": "{n} autobus" + }, + "{n} bike share": { + "one": "{n} stazione bike sharing", + "many": "{n} di stazioni bike sharing", + "other": "{n} stazioni bike sharing" + }, + "{n} flock cameras": { + "one": "{n} telecamera Flock", + "many": "{n} di telecamere Flock", + "other": "{n} telecamere Flock" + }, + "{n} military bases": { + "one": "{n} base militare", + "many": "{n} di basi militari", + "other": "{n} basi militari" + }, + "{n} datacenters": { + "one": "{n} data center", + "many": "{n} di data center", + "other": "{n} data center" + }, + "{n} dams": { + "one": "{n} diga", + "many": "{n} di dighe", + "other": "{n} dighe" + }, + "{n} air quality": { + "one": "{n} stazione qualità dell'aria", + "many": "{n} di stazioni qualità dell'aria", + "other": "{n} stazioni qualità dell'aria" + }, + "{n} results": { + "one": "{n} risultato", + "many": "{n} di risultati", + "other": "{n} risultati" + }, + "anywhere in the loaded data": "ovunque nei dati caricati", + "in view": "nella vista", + "within {radius} of the view centre": "entro {radius} dal centro della vista", + "within {radius} of {place} (Contacts window)": "entro {radius} da {place} (finestra Contatti)", + "within {radius} of {place}": "entro {radius} da {place}", + "within {radius}": "entro {radius}", + "over {region}": "sopra {region}", + "At least {items}": "Almeno {items}", + "{items} {scope}": "{items} {scope}", + "last 24 h": "ultime 24 h", + "past 30 d and upcoming": "ultimi 30 g e prossimi", + "the flights layer loads by viewport": "il livello voli si carica per vista", + "distance is ground distance, not overhead": "la distanza è al suolo, non in linea d'aria", + "the count is a lower bound because at least one layer reached its retained limit.": "il conteggio è un limite inferiore perché almeno un livello ha raggiunto il suo limite di conservazione.", + "{label} off": "{label} disattivato", + "{label} loading": "{label} in caricamento", + "{label} error": "{label} in errore", + "counted the first {returned} loaded records": "contati i primi {returned} record caricati", + "counted {returned} of {total} loaded records": "contati {returned} di {total} record caricati", + "{layers} just turned on — still loading, counts will rise": "{layers} appena attivati: ancora in caricamento, i conteggi aumenteranno", + "Contacts panel snapshot at {time} — the same retained cohort supplies the card, speech, and follow-up memory": "Snapshot del pannello Contatti alle {time}: lo stesso gruppo conservato fornisce la scheda, il parlato e la memoria per le domande successive", + "Contacts panel snapshot — the same retained cohort supplies the card, speech, and follow-up memory": "Snapshot del pannello Contatti: lo stesso gruppo conservato fornisce la scheda, il parlato e la memoria per le domande successive", + "Fly below {km} km to a covered region": "Scendi sotto {km} km su una regione coperta", + "No feed here yet · {n} regions available": { + "one": "Ancora nessun feed qui · {n} regione disponibile", + "many": "Ancora nessun feed qui · {n} di regioni disponibili", + "other": "Ancora nessun feed qui · {n} regioni disponibili" + }, + "degraded": "degradato", + "stale": "obsoleto", + "partial": "parziale", + "fallback": "di riserva", + "unavailable": "non disponibile", + "Not answered: {layers}": "Senza risposta: {layers}", + "Toggle voice control": "Attiva/disattiva il controllo vocale", + "Activate to toggle voice": "Attiva per abilitare o disabilitare la voce", + "Voice active": "Voce attiva", + "Voice could not be started.": "Impossibile avviare la voce.", + "the active voice session": "la sessione vocale attiva", + "{value} feet": "{value} piedi", + "Fire · FRP {frp} MW": "Incendio · FRP {frp} MW", + "The flights layer is not enabled": "Il livello voli non è attivo", + "The military layer is not enabled": "Il livello militare non è attivo", + "The satellites layer is not enabled": "Il livello satelliti non è attivo", + "The ais-live-vessels layer is not enabled": "Il livello ais-live-vessels non è attivo", + "Could not enable the requested layer": "Impossibile attivare il livello richiesto", + "Could not disable the requested layer": "Impossibile disattivare il livello richiesto", + "Radio layer unavailable": "Livello Radio non disponibile", + "Camera navigation is unavailable in the current view": "La navigazione della camera non è disponibile nella vista attuale", + "Camera navigation policy unavailable": "Regole di navigazione della camera non disponibili", + "Nearest-aircraft selection supports Flights or Military Flights only": "La selezione dell'aereo più vicino supporta solo Voli o Voli militari", + "Nearest-aircraft selection needs a preset, place name, or latitude and longitude": "La selezione dell'aereo più vicino richiede un preset, un nome di luogo o latitudine e longitudine", + "Could not arrive at the requested place": "Impossibile arrivare al luogo richiesto", + "The nearest airborne aircraft could not be selected": "Impossibile selezionare l'aereo in volo più vicino", + "No flights within {radius} of the current view": "Nessun volo entro {radius} dalla vista attuale", + "No military within {radius} of the current view": "Nessun mezzo militare entro {radius} dalla vista attuale", + "No satellites within {radius} of the current view": "Nessun satellite entro {radius} dalla vista attuale", + "No vessels within {radius} of the current view": "Nessuna nave entro {radius} dalla vista attuale", + "{layer} is enabled on the {source} feed, but no airborne aircraft is loaded in the {place} view yet": "{layer} è attivo sul feed {source}, ma nessun aereo in volo è ancora caricato nella vista di {place}", + "{layer} is enabled, but no airborne aircraft is loaded in the {place} view yet": "{layer} è attivo, ma nessun aereo in volo è ancora caricato nella vista di {place}", + "{layer} is enabled, but its aircraft feed is unavailable": "{layer} è attivo, ma il suo feed di aerei non è disponibile", + "{layer} is enabled, but its destination refresh did not complete": "{layer} è attivo, ma l'aggiornamento delle destinazioni non è stato completato", + "{layer} is enabled, but {source} is unavailable": "{layer} è attivo, ma {source} non è disponibile", + "Could not arrive at {place}": "Impossibile arrivare a {place}", + "{name} is no longer loaded": "{name} non è più caricato", + "Unknown target layer: {target}": "Livello obiettivo sconosciuto: {target}", + "nominal": "nominale", + "{label} on": "{label} attivato", + "Frame aircraft": "Inquadra gli aerei", + "Frame military aircraft": "Inquadra gli aerei militari", + "Frame ships": "Inquadra le navi", + "Frame satellites": "Inquadra i satelliti", + "Frame contacts": "Inquadra i contatti", + "{count} aircraft in frame": { + "one": "{count} aereo inquadrato", + "many": "{count} di aerei inquadrati", + "other": "{count} aerei inquadrati" + }, + "{count} military aircraft in frame": { + "one": "{count} aereo militare inquadrato", + "many": "{count} di aerei militari inquadrati", + "other": "{count} aerei militari inquadrati" + }, + "{count} ships in frame": { + "one": "{count} nave inquadrata", + "many": "{count} di navi inquadrate", + "other": "{count} navi inquadrate" + }, + "{count} satellites in frame": { + "one": "{count} satellite inquadrato", + "many": "{count} di satelliti inquadrati", + "other": "{count} satelliti inquadrati" + }, + "{count} contacts in frame": { + "one": "{count} contatto inquadrato", + "many": "{count} di contatti inquadrati", + "other": "{count} contatti inquadrati" + }, + "Nearest military aircraft": "Aerei militari più vicini", + "Nearest ships": "Navi più vicine", + "Nearest satellites": "Satelliti più vicini", + "Nearest aircraft": "Aerei più vicini", + "{first} and {second}": "{first} e {second}", + "Layer": "Livello", + "there": "lì", + "Camera range {range}": "Distanza della camera {range}", + "Within {radius} of the view": "Entro {radius} dalla vista", + "Labels on": "Etichette attivate", + "Framing uses the nearest 80 loaded contacts": "L'inquadratura usa gli 80 contatti caricati più vicini", + "{distance} from {location}": "{distance} da {location}", + "Altitude {altitude}": "Altitudine {altitude}", + "{origin} to {destination}": "Da {origin} a {destination}", + "from {origin}": "da {origin}", + "to {destination}": "a {destination}", + "Registration {registration}": "Immatricolazione {registration}", + "View state": "Stato della vista", + "Marked {count} places": { + "one": "Segnato {count} luogo", + "many": "Segnati {count} di luoghi", + "other": "Segnati {count} luoghi" + }, + "Nothing marked": "Nulla di segnato", + "Not found: {places}": "Non trovati: {places}", + "Tracing outlines": "Tracciamento dei contorni", + "Frame flights": "Inquadra i voli", + "Frame military": "Inquadra i militari", + "Frame vessels": "Inquadra le navi", + "Frame {target}": "Inquadra {target}", + "Zoom out to globe": "Allontana fino al globo", + "Open data layers": "Apri i livelli dati", + "Open or close a panel": "Apri o chiudi un pannello", + "Change context mode": "Cambia la modalità contesto", + "Control cockpit": "Controlla il cockpit", + "Change visual style": "Cambia lo stile visivo", + "Adjust HUD": "Regola l'HUD", + "Adjust cyber sonar": "Regola il sonar Cyber", + "Adjust detection overlay": "Regola l'overlay di rilevamento", + "Change map stack": "Cambia lo stack mappa", + "Adjust post-processing": "Regola la post-elaborazione", + "Control scene": "Controlla la scena", + "Control CCTV": "Controlla le CCTV", + "Control radio": "Controlla la radio", + "Track contact": "Traccia il contatto", + "Stop tracking": "Interrompi il tracciamento", + "Clear marks": "Cancella i segni", + "Move camera": "Sposta la camera", + "Fly route": "Vola lungo il percorso", + "Analyst query": "Richiesta di analisi", + "Next ISS pass": "Prossimo passaggio della ISS", + "Next satellite pass": "Prossimo passaggio del satellite", + "Mark the map": "Segna sulla mappa", + "Mark {targets} +{more}": "Segna {targets} +{more}", + "Mark {targets}": "Segna {targets}", + "Fly to {place}": "Vola su {place}", + "Fly to Location": "Vola sul luogo", + "Nearest aircraft to {place}": "Aereo più vicino a {place}", + "Nearest aircraft to Here": "Aereo più vicino a qui", + "Layer on": "Livello attivato", + "Layer off": "Livello disattivato", + "Zoom out": "Allontana", + "Zoom in": "Avvicina", + "Read the view": "Leggi la vista", + "Check view state": "Controlla lo stato della vista", + "Action": "Azione", + "Finding places": "Ricerca dei luoghi", + "Tracing outline": "Tracciamento del contorno", + "Looking up place": "Ricerca del luogo", + "Flying": "In volo", + "Turning on layer": "Attivazione del livello", + "Loading aircraft": "Caricamento degli aerei", + "Picking nearest": "Scelta del più vicino", + "Working": "Operazione in corso", + "in progress": "in corso", + "done": "fatto", + "failed": "non riuscito", + "cancelled": "annullato", + "Outline traced": "Contorno tracciato", + "Outline unavailable": "Contorno non disponibile", + "Source: {label}": "Fonte: {label}", + "WORKING": "IN CORSO", + "DONE": "FATTO", + "Recent speech": "Parlato recente", + "HERE": "QUI", "Aircraft cockpit view": "Vista cockpit dell'aereo", "LEVEL": "LIVELLO", "Estimated destination direction": "Direzione stimata della destinazione", @@ -685,15 +2712,21 @@ "Next vision style": "Stile di visione successivo", "Current aircraft heading": "Prua attuale dell'aereo", "GROUND SPEED": "VEL. AL SUOLO", + "KTS": "KTS", "ALTITUDE": "ALTITUDINE", + "FT": "FT", "Contact cockpit summary": "Riepilogo contatto del cockpit", "CONTACT": "CONTATTO", "CONTACTS · 250 KM": "CONTATTI · 250 KM", "Contact navigation": "Navigazione contatti", "CONTEXT ONLY": "SOLO CONTESTO", "Nearby cohort counts": "Conteggi dei gruppi vicini", + "FLT": "VOLI", + "MIL": "MIL", + "SITE": "SITI", "NEAREST OBSERVED / MAPPED": "PIÙ VICINO OSSERVATO / MAPPATO", "AVAILABLE INPUTS ONLY · NOT AN ALL-CLEAR": "SOLO INPUT DISPONIBILI · NON È UN VIA LIBERA", + "WX": "METEO", "Cockpit briefing carousel": "Carosello briefing del cockpit", "Estimated flight plan": "Piano di volo stimato", "ESTIMATED FLIGHT PLAN": "PIANO DI VOLO STIMATO", @@ -709,9 +2742,14 @@ "WIND": "VENTO", "SKY": "CIELO", "PRECIP": "PRECIP", + "MM": "MM", + "Weather data by Open-Meteo.com": "Dati meteo di Open-Meteo.com", + "Cockpit briefing pages": "Pagine del briefing del cockpit", + "SIG": "SIG", "Show Live Signals": "Mostra Segnali live", "NEWS": "NOTIZIE", "Show Regional News": "Mostra Notizie regionali", + "LOCAL": "LOCALE", "Show Local Info": "Mostra Info locali", "Cockpit display and Radio controls": "Controlli display e Radio del cockpit", "DISPLAY": "DISPLAY", @@ -723,6 +2761,8 @@ "Next filtered radio station": "Stazione radio filtrata successiva", "VOLUME": "VOLUME", "Cockpit Radio volume": "Volume Radio del cockpit", + "ESC EXIT": "ESC ESCI", + "C TOGGLE": "C ALTERNA", "View switcher": "Selettore vista", "Exit cockpit and return to full globe view": "Esci dal cockpit e torna alla vista del globo intero", "RESET": "RESET", @@ -750,6 +2790,9 @@ "Search location by name or coordinates": "Cerca un luogo per nome o coordinate", "Search any location...": "Cerca un luogo qualsiasi...", "WEATHER": "METEO", + "Active weather products": "Prodotti meteo attivi", + "RECENT IMAGERY": "IMMAGINI RECENTI", + "Imagery days in the box": "Giorni con immagini nel riquadro", "CONTEXT": "CONTESTO", "Compact Radio controls": "Controlli Radio compatti", "Open detailed Radio controls": "Apri i controlli Radio dettagliati", @@ -772,13 +2815,14 @@ "AVAILABLE MISSIONS": "MISSIONI DISPONIBILI", "SELECT A MISSION TO INSPECT": "SELEZIONA UNA MISSIONE DA ESAMINARE", "LOADING 30-DAY MISSION INDEX": "CARICAMENTO INDICE MISSIONI A 30 GIORNI", - "TAB PREVIEWS · ENTER / SPACE SELECTS": "TAB ANTEPRIMA · INVIO / SPAZIO SELEZIONA", + "TAB PREVIEWS · ENTER / SPACE SELECTS": "TAB: ANTEPRIMA · ENTER / SPACE: SELEZIONA", "Internet radio and local SDR": "Radio internet e SDR locale", "STATION TAG": "TAG STAZIONE", "Filter stations by station tag": "Filtra le stazioni per tag", "All": "Tutti", - "Enable Radio, then choose a globe marker or use next.": "Attiva la Radio, poi scegli un marcatore sul globo o usa SUCC.", + "Enable Radio, then choose a globe marker or use next.": "Attiva la Radio, poi scegli un marcatore sul globo o passa alla successiva.", "DRAG TO TUNE": "TRASCINA PER SINTONIZZARE", + "Tune available internet radio stations": "Sintonizza le stazioni radio internet disponibili", "ALL · DRAG THE NEEDLE": "TUTTE · TRASCINA L'AGO", "SNAPS TO AVAILABLE STATIONS": "SI AGGANCIA ALLE STAZIONI DISPONIBILI", "Radio playback": "Riproduzione radio", @@ -789,13 +2833,48 @@ "Stop radio playback": "Ferma la riproduzione radio", "Radio volume": "Volume radio", "STATION SITE": "SITO STAZIONE", + "DIRECTORY: RADIO BROWSER": "ELENCO: RADIO BROWSER", "Audio connects directly to the broadcaster after you press play. Your IP is visible to that broadcaster.": "L'audio si collega direttamente all'emittente dopo aver premuto play. Il tuo IP è visibile a quell'emittente.", - "Intelligence HUD (H)": "HUD Intelligence (H)", + "Local RTL-SDR receiver": "Ricevitore RTL-SDR locale", + "LOCAL RTL-SDR": "RTL-SDR LOCALE", + "Chrome/Edge · WebUSB · one local tuner shared by FM and the Local ADS-B layer.": "Chrome/Edge · WebUSB · un sintonizzatore locale condiviso tra FM e il livello ADS-B locale.", + "Use your location for faster ADS-B position decoding": "Usa la tua posizione per decodificare più in fretta le posizioni ADS-B", + "CHANGE DEVICE": "CAMBIA DISPOSITIVO", + "Choose a different RTL-SDR or receiver channel": "Scegli un altro RTL-SDR o canale del ricevitore", + "RTL-SDR receiver mode": "Modalità del ricevitore RTL-SDR", + "GAIN": "GUADAGNO", + "RTL-SDR tuner gain for the current mode": "Guadagno del sintonizzatore RTL-SDR per la modalità attuale", + "AUTO": "AUTO", + "MSG/S": "MSG/S", + "HEARD": "RICEVUTI", + "POSITIONED": "POSIZIONATI", + "FM MHZ": "FM MHZ", + "TUNE": "SINTONIZZA", + "Seek broadcast FM stations": "Cerca stazioni FM broadcast", + "◀ SEEK": "◀ CERCA", + "SEEK ▶": "CERCA ▶", + "SDR VOL": "VOL SDR", + "Local SDR volume": "Volume dell'SDR locale", + "Intelligence HUD (H)": "HUD intelligence (H)", "Layout": "Layout", "HUD layout": "Layout HUD", "Tactical": "Tattico", "Operator": "Operatore", "Minimal": "Minimale", + "Cyber": "Cyber", + "Sonar": "Sonar", + "Cyber sonar contact scanner": "Scanner di contatti sonar Cyber", + "Rings": "Anelli", + "Sonar ring count": "Numero di anelli del sonar", + "Range": "Portata", + "Sonar ring range": "Portata degli anelli del sonar", + "Power": "Potenza", + "Sonar intensity": "Intensità del sonar", + "Opacity": "Opacità", + "Cyber contact and label opacity": "Opacità di contatti ed etichette Cyber", + "Minimum opacity for map dots, icons, models, brackets, and labels between sonar passes": "Opacità minima di punti sulla mappa, icone, modelli, riquadri ed etichette tra un passaggio del sonar e l'altro", + "Sector": "Settore", + "Sonar sector width": "Ampiezza del settore del sonar", "Detection Overlay (D)": "Overlay di rilevamento (D)", "Detection overlay": "Overlay di rilevamento", "Detection label density": "Densità delle etichette di rilevamento", @@ -819,6 +2898,26 @@ "Feather": "Sfumatura", "Scope edge feather": "Sfumatura del bordo dello scope", "Scope edge feather as a percentage of the keyhole radius": "Sfumatura del bordo dello scope, come percentuale del raggio del foro", + "Draw on the world — click vertices, double-click or Enter to finish, Esc to cancel": "Disegna sul mondo: fai clic sui vertici, doppio clic o Enter per finire, Esc per annullare", + "Shape": "Forma", + "Shape to draw": "Forma da disegnare", + "Area": "Area", + "Line": "Linea", + "Pin": "Segnaposto", + "Label (optional)": "Etichetta (opzionale)", + "Label for the drawn shape": "Etichetta della forma disegnata", + "Colour of the drawn shape": "Colore della forma disegnata", + "Primary": "Principale", + "Amber": "Ambra", + "Cyan": "Ciano", + "Green": "Verde", + "Red": "Rosso", + "Clear": "Cancella", + "Remove every mark from the board": "Rimuovi tutti i segni dalla lavagna", + "Show your own GeoJSON, KML, KMZ or GPX files on the globe (or drop them onto it). File bytes stay on this device; overlays can appear in map screenshots shared with voice.": "Mostra sul globo i tuoi file GeoJSON, KML, KMZ o GPX (o trascinali sopra). I dati dei file restano su questo dispositivo; gli overlay possono comparire negli screenshot della mappa condivisi con la voce.", + "Import": "Importa", + "Choose GeoJSON, KML, KMZ or GPX files": "Scegli file GeoJSON, KML, KMZ o GPX", + "Imported files": "File importati", "Celestial": "Celeste", "Hide UI chrome": "Nascondi l'interfaccia", "Clean UI": "UI pulita", @@ -831,6 +2930,7 @@ "Return UI controls": "Ripristina i controlli UI", "Initializing photorealistic world...": "Inizializzazione del mondo fotorealistico...", "DATA LAYERS": "LIVELLI DATI", + "ACQUIRING FRAME": "ACQUISIZIONE FOTOGRAMMA", "NEAREST": "PIÙ VICINA", "CCTV camera": "Telecamera CCTV", "CALIBRATION": "CALIBRAZIONE", @@ -846,6 +2946,26 @@ "SAVE CAL": "SALVA CAL", "RESET CAL": "RESET CAL", "SCENE SUMMARY": "RIEPILOGO SCENA", + "STREET LEVEL": "VISTA STRADALE", + "Turn Street Level on or off": "Attiva o disattiva Vista stradale", + "Show the street-level view full screen (Esc shrinks it)": "Mostra la vista stradale a schermo intero (Esc la riduce)", + "Image fit": "Adattamento immagine", + "FIT": "ADATTA", + "Fit: show the whole photo, with dark bars where its shape differs from the frame": "Adatta: mostra l'intera foto, con bande scure dove la sua forma differisce dal riquadro", + "FILL": "RIEMPI", + "Fill: fill the frame edge to edge, cropping the photo": "Riempi: riempie il riquadro da bordo a bordo, ritagliando la foto", + "Close the image and deselect it on the map": "Chiudi l'immagine e deselezionala sulla mappa", + "Close the street-level image": "Chiudi l'immagine a livello stradale", + "Street-level viewer": "Visualizzatore a livello stradale", + "Open this image on the provider's site": "Apri questa immagine sul sito del provider", + "Imagery providers": "Provider di immagini", + "PROVIDERS": "PROVIDER", + "Imagery filters": "Filtri delle immagini", + "IMAGERY": "IMMAGINI", + "Panorama filter": "Filtro panorami", + "ALL": "TUTTE", + "FLAT": "PIATTE", + "SINCE": "DAL", "SCENES": "SCENE", "Scene recipe": "Ricetta della scena", "NEW": "NUOVA", @@ -855,7 +2975,7 @@ "EXPORT PRESETS": "ESPORTA PRESET", "IMPORT": "IMPORTA", "RUN LOG": "LOG ESECUZIONE", - "POWER UP": "POWER UP", + "POWER UP": "ACCENDI", "GROUND STATION · PROVIDER SETTINGS": "STAZIONE A TERRA · IMPOSTAZIONI PROVIDER", "Close key setup": "Chiudi la configurazione delle chiavi", "Power up the globe": "Accendi il globo", @@ -868,6 +2988,9 @@ "Globe actions": "Azioni del globo", "Turn off all selected data layers": "Disattiva tutti i livelli dati selezionati", "Copy share link": "Copia il link di condivisione", + "Toggle straight-down and tilted map views": "Alterna tra vista dall'alto e vista inclinata della mappa", + "Reset map to north up": "Orienta la mappa a nord", + "Reset map bearing to north": "Riporta l'orientamento della mappa a nord", "Reset camera and return to full globe view": "Ripristina la camera e torna alla vista del globo intero", "MISSION CONTROL · FIRST LAUNCH": "CONTROLLO MISSIONE · PRIMO AVVIO", "Choose your first view": "Scegli la tua prima vista", diff --git a/src/i18n/same-as-english.json b/src/i18n/same-as-english.json index 83c8897d8..be8a06f0c 100644 --- a/src/i18n/same-as-english.json +++ b/src/i18n/same-as-english.json @@ -124,6 +124,173 @@ "ΔN", "▲ {frp} MW" ], + "it": [ + "1090 MHz", + "978 MHz UAT", + "AFRICA", + "AIS: --", + "AIS: {name}", + "ALT {altitude} FT · GS {speed} KT · TRK {track}", + "ANIME", + "ASIA", + "AUTO", + "AUTO HOP OFF", + "AUTO HOP ON", + "Alternative", + "Ambient", + "Anime", + "Area", + "Austin", + "BRG {value}°", + "BRG —", + "Bloom", + "Blues", + "Business jet", + "CAL {value}", + "CAL · {badge}", + "CARGO", + "CCTV", + "CCTV OFF", + "CCTV ON", + "COCKPIT", + "CRS {value}°", + "CRT", + "Country", + "Cyber", + "DEST ---°", + "DEST {bearing}", + "DISPLAY", + "Dance", + "Drone", + "Dubai", + "ENE", + "ESE", + "FLIR", + "FM MHZ", + "FOCUS", + "FOV", + "FOV {value}°", + "FT", + "Folk", + "Funk", + "GEO", + "GOOGLE STREET VIEW", + "Google Street View", + "HDG", + "HDG {value}°", + "Hip-Hop", + "House", + "Indie", + "Ironbow", + "Jazz", + "KTS", + "LIVE", + "Landsat 8/9", + "Layout", + "Los Angeles", + "MIC", + "MIL", + "MINI", + "MM", + "MONITOR", + "MSG/S", + "Metal", + "NASA FIRMS · LIVE", + "NAV", + "NE", + "NNE", + "NOIR", + "NVG", + "New York", + "Noir", + "OCEANIA", + "OFF", + "OK", + "ON", + "ON/OFF", + "Oldies", + "PAYLOAD", + "PLAY", + "POS: LIVE", + "POS: {time}Z", + "PRECIP", + "Pop", + "Punk", + "RADIO", + "REC", + "RESET", + "RESET CAL", + "Radio", + "Reggae", + "Rock", + "S2 GhostMaps", + "SAR", + "SE", + "SIG", + "SNAPSHOT", + "SQUAWK {code} · {status}", + "SSE", + "STANDARD", + "STD", + "STOP", + "SYNC", + "San Francisco", + "Scope", + "Sentinel-2", + "Sonar", + "Soul", + "TEMP", + "TIMEOUT", + "Talk", + "Tallinn", + "Techno", + "Tokyo", + "Tram", + "Trance", + "UPSTREAM", + "USB {rate} msg/s", + "Upstream HTTP {status}", + "V/S {rate} FPM", + "VIEWSHED", + "VIEWSHED ON", + "VOLUME", + "VS", + "WHOT/BHOT", + "Washington DC", + "World", + "audio {state}", + "dB", + "ft", + "hPa", + "installation class|BASE", + "km", + "km/h", + "max {value} MW", + "min", + "mini", + "mph", + "radio|TALK", + "satellite", + "standard", + "view band|METRO", + "voice|OFF", + "{count} MSGS", + "{count} feeds live", + "{count} scenes", + "{rate} msg/s", + "{scene} / {pack}: {status}. File: {path}. {attribution} · {license}", + "{source} HTTP {status}", + "{speed} kn", + "{speed}KT", + "{value} KM", + "{value} KM DOWNRANGE", + "{value} KM/H", + "{value} KM/S", + "{value} conf", + "ΔE", + "ΔN", + "▲ {frp} MW" + ], "ru": [ "AIS: --", "AIS: {name}", From c4dfee6e5c1504f15f7e26d667399c310c8fd066 Mon Sep 17 00:00:00 2001 From: German Khokhlov Date: Wed, 28 Oct 2026 12:51:02 +0400 Subject: [PATCH 08/83] i18n(it): ship Italian - Register it: catalog in index.js, LOCALES and LOCALE_NAMES (Italiano); it-IT, it-CH and other it tags select it. - List it.json with the other catalogs in package-boundaries.json. - docs/translations/it.md: style, plurals and glossary; Italian in the shipped lists of TRANSLATORS.md and CURRENT-STATE.md. Co-Authored-By: Claude Opus 5.5 --- docs/CURRENT-STATE.md | 2 +- docs/TRANSLATORS.md | 4 +- docs/translations/it.md | 90 +++++++++++++++++++++++++++++++++ scripts/package-boundaries.json | 43 ++++++++++++++++ src/i18n/i18n.test.mjs | 2 + src/i18n/index.js | 9 +++- src/i18n/locale.js | 10 +++- src/ui/localePicker.test.mjs | 6 +-- 8 files changed, 158 insertions(+), 8 deletions(-) create mode 100644 docs/translations/it.md diff --git a/docs/CURRENT-STATE.md b/docs/CURRENT-STATE.md index c55031a6a..b65f48193 100644 --- a/docs/CURRENT-STATE.md +++ b/docs/CURRENT-STATE.md @@ -3733,7 +3733,7 @@ test:track` 43 tracking invariants · headless QA harnesses under ### Interface localization (October 2026) -Shipped locales: **en** (source and fallback), **es**, **ru**, **zh-CN** and **zh-Hant**. The code lives in +Shipped locales: **en** (source and fallback), **es**, **it**, **ru**, **zh-CN** and **zh-Hant**. The code lives in `src/i18n/`. How to mark UI text: [`docs/I18N.md`](./I18N.md); translator workflow: [`docs/TRANSLATORS.md`](./TRANSLATORS.md). diff --git a/docs/TRANSLATORS.md b/docs/TRANSLATORS.md index 830ca155e..01ed1a92e 100644 --- a/docs/TRANSLATORS.md +++ b/docs/TRANSLATORS.md @@ -1,6 +1,6 @@ # Translating God's Eye View -Shipped languages: **English** (source and fallback), **Spanish** (`es`), **Russian** (`ru`), **Simplified Chinese** (`zh-CN`) and **Traditional Chinese** (`zh-Hant`). +Shipped languages: **English** (source and fallback), **Spanish** (`es`), **Italian** (`it`), **Russian** (`ru`), **Simplified Chinese** (`zh-CN`) and **Traditional Chinese** (`zh-Hant`). ## How it works @@ -63,4 +63,4 @@ These are contracts, not copy: layer ids and registry keys, status enums and oth ## Language notes -Each language keeps its glossary, plural forms, units and style in its own file, `docs/translations/.md`: [Spanish](./translations/es.md), [Russian](./translations/ru.md), [Simplified Chinese](./translations/zh-CN.md), [Traditional Chinese](./translations/zh-Hant.md). Read it before translating, and add a term there when you settle on one. +Each language keeps its glossary, plural forms, units and style in its own file, `docs/translations/.md`: [Spanish](./translations/es.md), [Italian](./translations/it.md), [Russian](./translations/ru.md), [Simplified Chinese](./translations/zh-CN.md), [Traditional Chinese](./translations/zh-Hant.md). Read it before translating, and add a term there when you settle on one. diff --git a/docs/translations/it.md b/docs/translations/it.md new file mode 100644 index 000000000..155c0e563 --- /dev/null +++ b/docs/translations/it.md @@ -0,0 +1,90 @@ +# Italian (`it`) + +Catalog: `src/i18n/locales/it.json`. General rules: [TRANSLATORS.md](../TRANSLATORS.md). + +Translation source: abiyeenzo (#912). + +## Style + +- Standard Italian as in Italian software UIs. Address the user with informal "tu" imperatives: «Aggiungi», «Attiva», «Scegli», «Incolla», «Riprova». Tooltips that name an action use the same imperative: «Espandi il pannello», «Ripristina la camera». +- Sentence case, not Title Case: "Live Flights" → «Voli live», "Space Missions" → «Missioni spaziali». UPPERCASE English stays UPPERCASE: «LIVE», «NON DISPONIBILE». +- Quotes inside Italian text are straight double quotes: «Eliminare lo scatto "{shot}"?». Use the accented capitals (È, À) in UPPERCASE text: «VELOCITÀ», «CITTÀ». +- Errors read as a statement, not a past participle on its own: "Search failed" → «Ricerca non riuscita»; "Could not …" → «Impossibile …». A dash that joins a cause and a hint becomes a colon: «Chiave API rifiutata: controlla AISSTREAM_API_KEY». +- Short labels, chips and HUD readouts stay short. A standard abbreviation with a period beats a wrapped line: REGOLAZ., RILEV., INCL., ALT., VEL., STIM.; PREC / SUCC for PREV / NEXT. +- The HUD codes HDG, BRG, CRS, FOV and DEST stay in English, as in cockpit avionics. RANGE is «PORTATA». Words used in a sentence are translated: heading → «prua» (aircraft) or «direzione» (camera), course → «rotta». +- Keyboard keys stay in English: Space, Enter, Esc, Tab, Shift, Backspace, H, 1–9 («Tieni premuto Space per parlare», «Premi Enter per riprovare»). +- Decimal comma in numbers written in the text: «28,2710° N». Numbers formatted by the code follow `Intl` and need nothing. +- Units: km, m, km/h, m/s, kn (knots), ft (feet), h, min, s; in UPPERCASE text KM, KM/S, KT, FT, MIN, H. "m" is always metres, so minutes are «min» («5 min fa»). MW stays MW. `°` and `%` stay. +- "ago" goes after the time: «{count} min fa». When a placeholder already holds a localized "ago" text (`{age}`, `{ago}`), do not add «fa» again. +- English loanwords that Italian UIs use as they are stay in English: feed, live, cockpit, briefing, preset, overlay, layout, snapshot, tile, provider, timeout, payload, bloom, scope. + +## Plurals + +A `tn()` entry needs three forms. `Intl.PluralRules('it')` picks: + +| Form | Counts | Example | +| ------- | -------------------------------------- | ----------------------- | +| `one` | 1 | 1 telecamera | +| `many` | 1 000 000, 2 000 000… (exact millions) | 1 000 000 di telecamere | +| `other` | everything else: 0, 2–999 999, 1,5… | 3 telecamere | + +The `many` form is the `other` text with «di» after the number when a noun follows: «{count} di telecamere caricate», «{count} DI CHIAVI IN ATTESA». When no noun follows the number («{count} vicine», «{count} RICEVUTI»), `many` repeats `other`. Nouns that do not change in the plural keep one form for all three (`{count} file`, `{count} data center`), with «di» in `many`. + +## Glossary + +| English | Italiano | +| --------------------------------------------- | ------------------------------------------------------------ | +| layer / data layer | livello / livello dati | +| feed / source / data source | feed / fonte / fonte dati | +| LIVE (status) / live data | LIVE / dati live | +| SIMULATED | SIMULATO | +| stale / degraded / unavailable | obsoleto / degradato / non disponibile | +| retry / retrying | riprova / nuovo tentativo | +| rate limited | limite di richieste (raggiunto) | +| key (API key) / POWER UP / POWERED UP | chiave / ACCENDI / ACCESO | +| Provider Settings | Impostazioni provider | +| ON / OFF (state chips) | ON / OFF | +| enable / disable | attivare / disattivare | +| globe / map / map source / map stack | globo / mappa / fonte mappa / stack mappa | +| basemap / box (Recent Imagery area) | mappa di base / riquadro | +| aircraft, plane / flight / military flights | aereo / volo / voli militari | +| vessel, ship | nave | +| satellite / shell (Starlink) / DENSE | satellite / shell / DENSO | +| launch (rocket) / launch site / space mission | lancio / sito di lancio / missione spaziale | +| ascent / replay / payload / stage | salita / replay / payload / stadio | +| contact / tracking | contatto / tracciamento | +| installation / site | installazione / sito | +| mapped / observed | mappato / osservato | +| camera (view) / camera, CCTV camera | camera / telecamera, telecamera CCTV | +| earthquake / active fire / fire perimeter | terremoto / incendio attivo / perimetro dell'incendio | +| advisory (NHC/CPHC cyclone) / cone | bollettino / cono di incertezza | +| radio station / broadcaster | stazione radio / emittente | +| road / flow (traffic) | strada / flusso | +| transit / bike share | trasporto pubblico / bike sharing | +| scene / shot / scene recipe | scena / scatto / ricetta della scena | +| anchor / data pack / bundle (scene) | ancora / pacchetto dati / pacchetto | +| story beat | tappa del racconto | +| briefing / panel / dock | briefing / pannello / dock | +| cockpit | cockpit | +| preset / visual preset | preset / preset visivo | +| Tactical / Operator / Minimal / Cyber | Tattico / Operatore / Minimale / Cyber | +| Scope (circular viewport mask) / keyhole | scope / foro | +| feather / fade | sfumatura / dissolvenza | +| detection overlay | overlay di rilevamento | +| pin (Draw tool) / mark | segnaposto / segno | +| pin (Recent Imagery) | fissare | +| Draw / Directions (tools) | Disegno / Indicazioni | +| Street Level (layer) / Street View (Google) | Vista stradale / Street View | +| Recent Imagery | Immagini recenti | +| Global Context / Context (panel) | Contesto globale / Contesto | +| heading, course / altitude / ground speed | prua, rotta / altitudine / velocità al suolo (VEL. AL SUOLO) | +| HDG / BRG / CRS / FOV / DEST | HDG / BRG / CRS / FOV / DEST (unchanged) | +| RANGE / PITCH / HGT (CCTV calibration) | PORTATA / INCL. / ALT. | +| PREV / NEXT | PREC / SUCC | +| Previous / Next (button text) | Precedente / Successivo | +| L / R (relative bearing) | S / D | +| SIG / NEWS / LOCAL (briefing tabs) | SIG / NOTIZIE / LOCALE | +| compass points (N, NNE, …, W, NW) | N, NNE, …, O, NO (west is «O», ovest) | +| NOT AN ALL-CLEAR | NON È UN VIA LIBERA | +| weather field / model / valid / issued | campo / modello / valida / emessa | +| click / click to … | fai clic / clic per … | diff --git a/scripts/package-boundaries.json b/scripts/package-boundaries.json index 9f06f73f6..991ab9498 100644 --- a/scripts/package-boundaries.json +++ b/scripts/package-boundaries.json @@ -440,6 +440,7 @@ "src/i18n/index.js", "src/i18n/locale.js", "src/i18n/locales/es.json", + "src/i18n/locales/it.json", "src/i18n/locales/ru.json", "src/i18n/locales/zh-CN.json", "src/i18n/locales/zh-Hant.json" @@ -480,6 +481,7 @@ "src/i18n/index.js", "src/i18n/locale.js", "src/i18n/locales/es.json", + "src/i18n/locales/it.json", "src/i18n/locales/ru.json", "src/i18n/locales/zh-CN.json", "src/i18n/locales/zh-Hant.json" @@ -510,6 +512,7 @@ "src/i18n/index.js", "src/i18n/locale.js", "src/i18n/locales/es.json", + "src/i18n/locales/it.json", "src/i18n/locales/ru.json", "src/i18n/locales/zh-CN.json", "src/i18n/locales/zh-Hant.json", @@ -532,6 +535,7 @@ "src/i18n/index.js", "src/i18n/locale.js", "src/i18n/locales/es.json", + "src/i18n/locales/it.json", "src/i18n/locales/ru.json", "src/i18n/locales/zh-CN.json", "src/i18n/locales/zh-Hant.json" @@ -549,6 +553,7 @@ "src/i18n/index.js", "src/i18n/locale.js", "src/i18n/locales/es.json", + "src/i18n/locales/it.json", "src/i18n/locales/ru.json", "src/i18n/locales/zh-CN.json", "src/i18n/locales/zh-Hant.json" @@ -569,6 +574,7 @@ "src/i18n/index.js", "src/i18n/locale.js", "src/i18n/locales/es.json", + "src/i18n/locales/it.json", "src/i18n/locales/ru.json", "src/i18n/locales/zh-CN.json", "src/i18n/locales/zh-Hant.json", @@ -596,6 +602,7 @@ "src/i18n/index.js", "src/i18n/locale.js", "src/i18n/locales/es.json", + "src/i18n/locales/it.json", "src/i18n/locales/ru.json", "src/i18n/locales/zh-CN.json", "src/i18n/locales/zh-Hant.json", @@ -631,6 +638,7 @@ "src/i18n/index.js", "src/i18n/locale.js", "src/i18n/locales/es.json", + "src/i18n/locales/it.json", "src/i18n/locales/ru.json", "src/i18n/locales/zh-CN.json", "src/i18n/locales/zh-Hant.json", @@ -648,6 +656,7 @@ "src/i18n/index.js", "src/i18n/locale.js", "src/i18n/locales/es.json", + "src/i18n/locales/it.json", "src/i18n/locales/ru.json", "src/i18n/locales/zh-CN.json", "src/i18n/locales/zh-Hant.json", @@ -807,6 +816,7 @@ "src/i18n/index.js", "src/i18n/locale.js", "src/i18n/locales/es.json", + "src/i18n/locales/it.json", "src/i18n/locales/ru.json", "src/i18n/locales/zh-CN.json", "src/i18n/locales/zh-Hant.json", @@ -929,6 +939,7 @@ "src/i18n/index.js", "src/i18n/locale.js", "src/i18n/locales/es.json", + "src/i18n/locales/it.json", "src/i18n/locales/ru.json", "src/i18n/locales/zh-CN.json", "src/i18n/locales/zh-Hant.json", @@ -997,6 +1008,7 @@ "src/i18n/index.js", "src/i18n/locale.js", "src/i18n/locales/es.json", + "src/i18n/locales/it.json", "src/i18n/locales/ru.json", "src/i18n/locales/zh-CN.json", "src/i18n/locales/zh-Hant.json", @@ -1046,6 +1058,7 @@ "src/i18n/index.js", "src/i18n/locale.js", "src/i18n/locales/es.json", + "src/i18n/locales/it.json", "src/i18n/locales/ru.json", "src/i18n/locales/zh-CN.json", "src/i18n/locales/zh-Hant.json" @@ -1109,6 +1122,7 @@ "src/i18n/index.js", "src/i18n/locale.js", "src/i18n/locales/es.json", + "src/i18n/locales/it.json", "src/i18n/locales/ru.json", "src/i18n/locales/zh-CN.json", "src/i18n/locales/zh-Hant.json" @@ -1139,6 +1153,7 @@ "src/i18n/index.js", "src/i18n/locale.js", "src/i18n/locales/es.json", + "src/i18n/locales/it.json", "src/i18n/locales/ru.json", "src/i18n/locales/zh-CN.json", "src/i18n/locales/zh-Hant.json", @@ -1170,6 +1185,7 @@ "src/i18n/index.js", "src/i18n/locale.js", "src/i18n/locales/es.json", + "src/i18n/locales/it.json", "src/i18n/locales/ru.json", "src/i18n/locales/zh-CN.json", "src/i18n/locales/zh-Hant.json" @@ -1201,6 +1217,7 @@ "src/i18n/index.js", "src/i18n/locale.js", "src/i18n/locales/es.json", + "src/i18n/locales/it.json", "src/i18n/locales/ru.json", "src/i18n/locales/zh-CN.json", "src/i18n/locales/zh-Hant.json", @@ -1235,6 +1252,7 @@ "src/i18n/index.js", "src/i18n/locale.js", "src/i18n/locales/es.json", + "src/i18n/locales/it.json", "src/i18n/locales/ru.json", "src/i18n/locales/zh-CN.json", "src/i18n/locales/zh-Hant.json" @@ -1278,6 +1296,7 @@ "src/i18n/index.js", "src/i18n/locale.js", "src/i18n/locales/es.json", + "src/i18n/locales/it.json", "src/i18n/locales/ru.json", "src/i18n/locales/zh-CN.json", "src/i18n/locales/zh-Hant.json", @@ -1315,6 +1334,7 @@ "src/i18n/index.js", "src/i18n/locale.js", "src/i18n/locales/es.json", + "src/i18n/locales/it.json", "src/i18n/locales/ru.json", "src/i18n/locales/zh-CN.json", "src/i18n/locales/zh-Hant.json", @@ -1366,6 +1386,7 @@ "src/i18n/index.js", "src/i18n/locale.js", "src/i18n/locales/es.json", + "src/i18n/locales/it.json", "src/i18n/locales/ru.json", "src/i18n/locales/zh-CN.json", "src/i18n/locales/zh-Hant.json" @@ -1396,6 +1417,7 @@ "src/i18n/index.js", "src/i18n/locale.js", "src/i18n/locales/es.json", + "src/i18n/locales/it.json", "src/i18n/locales/ru.json", "src/i18n/locales/zh-CN.json", "src/i18n/locales/zh-Hant.json" @@ -1445,6 +1467,7 @@ "src/i18n/index.js", "src/i18n/locale.js", "src/i18n/locales/es.json", + "src/i18n/locales/it.json", "src/i18n/locales/ru.json", "src/i18n/locales/zh-CN.json", "src/i18n/locales/zh-Hant.json" @@ -1509,6 +1532,7 @@ "src/i18n/index.js", "src/i18n/locale.js", "src/i18n/locales/es.json", + "src/i18n/locales/it.json", "src/i18n/locales/ru.json", "src/i18n/locales/zh-CN.json", "src/i18n/locales/zh-Hant.json", @@ -1539,6 +1563,7 @@ "src/i18n/index.js", "src/i18n/locale.js", "src/i18n/locales/es.json", + "src/i18n/locales/it.json", "src/i18n/locales/ru.json", "src/i18n/locales/zh-CN.json", "src/i18n/locales/zh-Hant.json" @@ -1580,6 +1605,7 @@ "src/i18n/index.js", "src/i18n/locale.js", "src/i18n/locales/es.json", + "src/i18n/locales/it.json", "src/i18n/locales/ru.json", "src/i18n/locales/zh-CN.json", "src/i18n/locales/zh-Hant.json" @@ -1603,6 +1629,7 @@ "src/i18n/index.js", "src/i18n/locale.js", "src/i18n/locales/es.json", + "src/i18n/locales/it.json", "src/i18n/locales/ru.json", "src/i18n/locales/zh-CN.json", "src/i18n/locales/zh-Hant.json" @@ -1660,6 +1687,7 @@ "src/i18n/index.js", "src/i18n/locale.js", "src/i18n/locales/es.json", + "src/i18n/locales/it.json", "src/i18n/locales/ru.json", "src/i18n/locales/zh-CN.json", "src/i18n/locales/zh-Hant.json" @@ -1723,6 +1751,7 @@ "src/i18n/index.js", "src/i18n/locale.js", "src/i18n/locales/es.json", + "src/i18n/locales/it.json", "src/i18n/locales/ru.json", "src/i18n/locales/zh-CN.json", "src/i18n/locales/zh-Hant.json", @@ -2606,6 +2635,7 @@ "src/i18n/index.js", "src/i18n/locale.js", "src/i18n/locales/es.json", + "src/i18n/locales/it.json", "src/i18n/locales/ru.json", "src/i18n/locales/zh-CN.json", "src/i18n/locales/zh-Hant.json", @@ -3191,6 +3221,7 @@ "src/i18n/index.js", "src/i18n/locale.js", "src/i18n/locales/es.json", + "src/i18n/locales/it.json", "src/i18n/locales/ru.json", "src/i18n/locales/zh-CN.json", "src/i18n/locales/zh-Hant.json", @@ -3302,6 +3333,7 @@ "src/data/cameraArrival.js", "src/i18n/locale.js", "src/i18n/locales/es.json", + "src/i18n/locales/it.json", "src/i18n/locales/ru.json", "src/i18n/locales/zh-CN.json", "src/i18n/locales/zh-Hant.json", @@ -3326,6 +3358,7 @@ "src/i18n/index.js", "src/i18n/locale.js", "src/i18n/locales/es.json", + "src/i18n/locales/it.json", "src/i18n/locales/ru.json", "src/i18n/locales/zh-CN.json", "src/i18n/locales/zh-Hant.json" @@ -3363,6 +3396,7 @@ "src/i18n/index.js", "src/i18n/locale.js", "src/i18n/locales/es.json", + "src/i18n/locales/it.json", "src/i18n/locales/ru.json", "src/i18n/locales/zh-CN.json", "src/i18n/locales/zh-Hant.json", @@ -3390,6 +3424,7 @@ "src/i18n/index.js", "src/i18n/locale.js", "src/i18n/locales/es.json", + "src/i18n/locales/it.json", "src/i18n/locales/ru.json", "src/i18n/locales/zh-CN.json", "src/i18n/locales/zh-Hant.json" @@ -3482,6 +3517,7 @@ "src/i18n/index.js", "src/i18n/locale.js", "src/i18n/locales/es.json", + "src/i18n/locales/it.json", "src/i18n/locales/ru.json", "src/i18n/locales/zh-CN.json", "src/i18n/locales/zh-Hant.json", @@ -3538,6 +3574,7 @@ "src/i18n/index.js", "src/i18n/locale.js", "src/i18n/locales/es.json", + "src/i18n/locales/it.json", "src/i18n/locales/ru.json", "src/i18n/locales/zh-CN.json", "src/i18n/locales/zh-Hant.json", @@ -3793,6 +3830,7 @@ "src/i18n/index.js", "src/i18n/locale.js", "src/i18n/locales/es.json", + "src/i18n/locales/it.json", "src/i18n/locales/ru.json", "src/i18n/locales/zh-CN.json", "src/i18n/locales/zh-Hant.json" @@ -3837,6 +3875,7 @@ "src/i18n/index.js", "src/i18n/locale.js", "src/i18n/locales/es.json", + "src/i18n/locales/it.json", "src/i18n/locales/ru.json", "src/i18n/locales/zh-CN.json", "src/i18n/locales/zh-Hant.json" @@ -3891,6 +3930,7 @@ "src/i18n/index.js", "src/i18n/locale.js", "src/i18n/locales/es.json", + "src/i18n/locales/it.json", "src/i18n/locales/ru.json", "src/i18n/locales/zh-CN.json", "src/i18n/locales/zh-Hant.json" @@ -3908,6 +3948,7 @@ "src/i18n/index.js", "src/i18n/locale.js", "src/i18n/locales/es.json", + "src/i18n/locales/it.json", "src/i18n/locales/ru.json", "src/i18n/locales/zh-CN.json", "src/i18n/locales/zh-Hant.json", @@ -3968,6 +4009,7 @@ "src/i18n/index.js", "src/i18n/locale.js", "src/i18n/locales/es.json", + "src/i18n/locales/it.json", "src/i18n/locales/ru.json", "src/i18n/locales/zh-CN.json", "src/i18n/locales/zh-Hant.json", @@ -4165,6 +4207,7 @@ "src/i18n/index.js", "src/i18n/locale.js", "src/i18n/locales/es.json", + "src/i18n/locales/it.json", "src/i18n/locales/ru.json", "src/i18n/locales/zh-CN.json", "src/i18n/locales/zh-Hant.json", diff --git a/src/i18n/i18n.test.mjs b/src/i18n/i18n.test.mjs index 1b421f2ff..ae491dc93 100644 --- a/src/i18n/i18n.test.mjs +++ b/src/i18n/i18n.test.mjs @@ -35,6 +35,8 @@ test('normalizeLocale folds regional variants and rejects unshipped tags', () => assert.equal(normalizeLocale(' RU '), 'ru'); assert.equal(normalizeLocale('en_GB'), 'en'); assert.equal(normalizeLocale('xx'), null); + assert.equal(normalizeLocale('it-IT'), 'it'); + assert.equal(normalizeLocale('it_CH'), 'it'); // Explicit script tags take precedence over regional defaults. assert.equal(normalizeLocale('zh'), 'zh-CN'); assert.equal(normalizeLocale('zh-CN'), 'zh-CN'); diff --git a/src/i18n/index.js b/src/i18n/index.js index 6fc4becc9..e7954ed2a 100644 --- a/src/i18n/index.js +++ b/src/i18n/index.js @@ -17,11 +17,18 @@ import { writeStoredLocale, } from './locale.js'; import es from './locales/es.json' with { type: 'json' }; +import it from './locales/it.json' with { type: 'json' }; import ru from './locales/ru.json' with { type: 'json' }; import zhCN from './locales/zh-CN.json' with { type: 'json' }; import zhHant from './locales/zh-Hant.json' with { type: 'json' }; -const CATALOGS = Object.freeze({ es, ru, 'zh-CN': zhCN, 'zh-Hant': zhHant }); +const CATALOGS = Object.freeze({ + es, + it, + ru, + 'zh-CN': zhCN, + 'zh-Hant': zhHant, +}); let currentLocale = DEFAULT_LOCALE; diff --git a/src/i18n/locale.js b/src/i18n/locale.js index 55ed71163..fda8dacd3 100644 --- a/src/i18n/locale.js +++ b/src/i18n/locale.js @@ -8,12 +8,20 @@ export const LOCALE_STORAGE_KEY = 'gev:locale:v1'; export const DEFAULT_LOCALE = 'en'; /** Shipped locales; order does not matter. Adding one: docs/TRANSLATORS.md. */ -export const LOCALES = Object.freeze(['en', 'es', 'ru', 'zh-CN', 'zh-Hant']); +export const LOCALES = Object.freeze([ + 'en', + 'es', + 'it', + 'ru', + 'zh-CN', + 'zh-Hant', +]); /** Each locale named in its own language, for the selector. */ export const LOCALE_NAMES = Object.freeze({ en: 'English', es: 'Español', + it: 'Italiano', ru: 'Русский', 'zh-CN': '中文(简体)', 'zh-Hant': '中文(繁體)', diff --git a/src/ui/localePicker.test.mjs b/src/ui/localePicker.test.mjs index 057642827..47062f08c 100644 --- a/src/ui/localePicker.test.mjs +++ b/src/ui/localePicker.test.mjs @@ -40,7 +40,7 @@ test('the current language comes first, the rest by their own names', () => { nativeNames: LOCALE_NAMES, }), ), - ['ru', 'en', 'es', 'zh-CN', 'zh-Hant'], + ['ru', 'en', 'es', 'it', 'zh-CN', 'zh-Hant'], ); assert.deepEqual( codes( @@ -50,7 +50,7 @@ test('the current language comes first, the rest by their own names', () => { nativeNames: LOCALE_NAMES, }), ), - ['es', 'en', 'ru', 'zh-CN', 'zh-Hant'], + ['es', 'en', 'it', 'ru', 'zh-CN', 'zh-Hant'], ); assert.deepEqual( codes( @@ -60,7 +60,7 @@ test('the current language comes first, the rest by their own names', () => { nativeNames: LOCALE_NAMES, }), ), - ['en', 'es', 'ru', 'zh-CN', 'zh-Hant'], + ['en', 'es', 'it', 'ru', 'zh-CN', 'zh-Hant'], ); const rows = buildLocaleOptions({ locales: MANY, From 8269f0e4e6f6f86f32bf34b54f7ae3cf778d443d Mon Sep 17 00:00:00 2001 From: German Khokhlov Date: Wed, 28 Oct 2026 12:52:01 +0400 Subject: [PATCH 09/83] i18n(pt): complete and ship Brazilian Portuguese MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Translate the remaining 1,868 strings (pt-BR, as in #909) and review the contributor entries: HUD codes BRG/SPD/RANGE stay as in the other languages, sentence-case layer and scene names, Space key named as on the keyboard, short PREV/NEXT/ON/OFF chips, and the CLDR many form (exact millions take «de») on every plural. - Register pt: any pt tag (pt-BR, pt-PT) maps to it; the picker shows «Português (Brasil)». - Codes, units and product names identical to English go to same-as-english.json. - docs/translations/pt.md: style, plurals, units and glossary. Co-Authored-By: Claude Opus 5.5 --- docs/CURRENT-STATE.md | 4 +- docs/TRANSLATORS.md | 4 +- docs/translations/pt.md | 81 ++ scripts/package-boundaries.json | 43 + src/i18n/i18n.test.mjs | 16 + src/i18n/index.js | 9 +- src/i18n/locale.js | 11 +- src/i18n/locales/pt.json | 2270 +++++++++++++++++++++++++++++-- src/i18n/same-as-english.json | 125 ++ src/ui/localePicker.test.mjs | 6 +- 10 files changed, 2483 insertions(+), 86 deletions(-) create mode 100644 docs/translations/pt.md diff --git a/docs/CURRENT-STATE.md b/docs/CURRENT-STATE.md index c55031a6a..b4f62379a 100644 --- a/docs/CURRENT-STATE.md +++ b/docs/CURRENT-STATE.md @@ -3733,7 +3733,7 @@ test:track` 43 tracking invariants · headless QA harnesses under ### Interface localization (October 2026) -Shipped locales: **en** (source and fallback), **es**, **ru**, **zh-CN** and **zh-Hant**. The code lives in +Shipped locales: **en** (source and fallback), **es**, **pt** (Brazilian Portuguese), **ru**, **zh-CN** and **zh-Hant**. The code lives in `src/i18n/`. How to mark UI text: [`docs/I18N.md`](./I18N.md); translator workflow: [`docs/TRANSLATORS.md`](./TRANSLATORS.md). @@ -3744,7 +3744,7 @@ Shipped locales: **en** (source and fallback), **es**, **ru**, **zh-CN** and **z value). English has no catalog; every other locale is `src/i18n/locales/.json`, and a missing entry falls back to English. - **Locale choice.** `?lang=` → stored choice (`gev:locale:v1`) → - `navigator.languages` → English. Chinese tags default to `zh-CN`; Traditional Chinese tags + `navigator.languages` → English. Any `pt` tag (`pt-BR`, `pt-PT`) selects `pt`. Chinese tags default to `zh-CN`; Traditional Chinese tags select `zh-Hant`. Explicit `Hans` selects `zh-CN` regardless of region. `?lang=` is not stored, and share links drop it, so a recipient keeps their own language. The globe picker in the bottom-right corner (`src/ui/localePicker.js`) stores the choice, drops diff --git a/docs/TRANSLATORS.md b/docs/TRANSLATORS.md index 830ca155e..afdbe350d 100644 --- a/docs/TRANSLATORS.md +++ b/docs/TRANSLATORS.md @@ -1,6 +1,6 @@ # Translating God's Eye View -Shipped languages: **English** (source and fallback), **Spanish** (`es`), **Russian** (`ru`), **Simplified Chinese** (`zh-CN`) and **Traditional Chinese** (`zh-Hant`). +Shipped languages: **English** (source and fallback), **Spanish** (`es`), **Brazilian Portuguese** (`pt`), **Russian** (`ru`), **Simplified Chinese** (`zh-CN`) and **Traditional Chinese** (`zh-Hant`). ## How it works @@ -63,4 +63,4 @@ These are contracts, not copy: layer ids and registry keys, status enums and oth ## Language notes -Each language keeps its glossary, plural forms, units and style in its own file, `docs/translations/.md`: [Spanish](./translations/es.md), [Russian](./translations/ru.md), [Simplified Chinese](./translations/zh-CN.md), [Traditional Chinese](./translations/zh-Hant.md). Read it before translating, and add a term there when you settle on one. +Each language keeps its glossary, plural forms, units and style in its own file, `docs/translations/.md`: [Spanish](./translations/es.md), [Brazilian Portuguese](./translations/pt.md), [Russian](./translations/ru.md), [Simplified Chinese](./translations/zh-CN.md), [Traditional Chinese](./translations/zh-Hant.md). Read it before translating, and add a term there when you settle on one. diff --git a/docs/translations/pt.md b/docs/translations/pt.md new file mode 100644 index 000000000..7417fd64f --- /dev/null +++ b/docs/translations/pt.md @@ -0,0 +1,81 @@ +# Brazilian Portuguese (`pt`) + +Catalog: `src/i18n/locales/pt.json`. General rules: [TRANSLATORS.md](../TRANSLATORS.md). + +Translation source: abiyeenzo (#909). + +## Style + +- Brazilian Portuguese (pt-BR): câmera, tela, compartilhar, arquivo, baixar, ônibus, metrô. Every `pt` tag, `pt-PT` included, gets this catalog, so avoid slang and regionalisms. +- Address the user with «você» imperatives: «Clique no mapa», «Ative o CCTV», «Tente novamente». Tooltips that name an action use the infinitive: «Expandir painel», «Redefinir a câmera». +- Sentence case, not Title Case: "Live Flights" → «Voos ao vivo». UPPERCASE English stays UPPERCASE: «AO VIVO», «SEM DADOS». +- Quotes inside Portuguese text are straight double quotes: «Excluir o plano "{shot}"?». +- Short labels, chips and HUD readouts stay short. A standard abbreviation with a period beats a wrapped line: ANT., PRÓX., DESLIG., EXCL., INCL., ALT., VEL., câm. +- The HUD codes HDG, BRG, CRS, FOV, DEST, SPD, RANGE, ALT, GS and TRK stay in English, as in cockpit avionics. Words used in a sentence are translated: heading → «rumo», range → «alcance». +- Keyboard keys stay in English: Space, Esc, Enter, Tab, Shift, Backspace, H, 1–9 («Segure Space para falar»). +- Common English tech words used in Brazil stay: feed, stream, snapshot, briefing, dock, layout, bloom, status, app, link, token. +- Units: km, m, km/h, m/s, kt (knots), ft (feet), h, min, s; in UPPERCASE text KM, KM/S, KT, FT, MIN, H. "m" is always metres, so minutes are «min» («há 5 min»). MW stays MW. `°` and `%` stay. Decimal comma in written numbers («M4,4»). +- "ago" goes before the time: «há {count} min». When a placeholder already holds a localized "ago" text (`{age}`, `{ago}`), do not add «há» again. +- Money: «US$ {amount} mil / mi / bi» for thousands, millions and billions. +- Compass points use Leste/Oeste: N, NNE, NE, ENE, L, ESE, SE, SSE, S, SSO, SO, OSO, O, ONO, NO, NNO; hemisphere letters N, S, L, O. + +## Plurals + +A `tn()` entry needs three forms. `Intl.PluralRules('pt')` follows Brazilian usage: + +| Form | Counts | Example | +| ------- | -------------------------------------- | ------------------ | +| `one` | 0, 1 and anything below 2: 0, 1, 1.5 | 0 câmera, 1 câmera | +| `many` | 1 000 000, 2 000 000… (exact millions) | 1000000 de câmeras | +| `other` | everything else: 2–999 999, 2.5… | 3 câmeras | + +The `many` form is the `other` text with «de» after the number: «{count} de câmeras carregadas», «{count} DE CHAVES PENDENTES». A `one` form is also read for 0, so keep it natural with zero («0 arquivo selecionado» is standard Brazilian usage). + +## Glossary + +| English | Português | +| --------------------------------------------- | ------------------------------------------------------------ | +| layer / data layer | camada / camada de dados | +| feed / source / data source | feed / fonte / fonte de dados | +| LIVE (status) / live data | AO VIVO / dados ao vivo | +| SIMULATED | SIMULADO | +| stale / degraded / unavailable | desatualizado / degradado / indisponível | +| retry / retrying | nova tentativa / tentando de novo | +| key (API key) / POWER UP / POWERED UP | chave / ATIVAR / ATIVADO | +| Provider Settings | Configurações de provedores | +| ON / OFF (state chips) | ATIVO / INATIVO | +| enable / disable | ativar / desativar | +| globe / map / map source / map stack | globo / mapa / fonte do mapa / pilha de mapas | +| basemap / tile | mapa base / bloco | +| aircraft, plane / flight / military flights | aeronave, avião / voo / voos militares | +| vessel, ship | embarcação | +| satellite / shell (Starlink) / DENSE | satélite / camada orbital / DENSO | +| launch (rocket) / launch site / space mission | lançamento / local de lançamento / missão espacial | +| ascent / replay / payload / stage | subida / reprise / carga útil / estágio | +| contact / tracking / track | contato / rastreamento / rastro | +| installation / site | instalação / local | +| mapped / observed | mapeado / observado | +| camera / CCTV camera | câmera / câmera de CCTV | +| earthquake / active fire | terremoto / incêndio ativo | +| advisory (NHC/CPHC cyclone) | boletim | +| radio station / broadcaster | estação de rádio / emissora | +| road / flow (traffic) | via / fluxo | +| Street Level (layer) | Nível da rua | +| scene / shot / scene recipe | cena / plano / receita de cena | +| briefing / panel / dock | briefing / painel / dock | +| cockpit | cabine | +| preset / visual preset | predefinição / predefinição visual | +| Scope (circular viewport mask) / keyhole | mira / visor | +| feather / fade | suavização / esmaecimento | +| detection overlay | sobreposição de detecção | +| pin (Draw tool) / box (Recent Imagery) | marcador / área | +| Cyber (HUD layout, effect) | Ciber | +| heading / course / altitude / ground speed | rumo / curso / altitude / velocidade solo (VELOC. SOLO) | +| HDG / BRG / CRS / FOV / DEST / SPD / RANGE | HDG / BRG / CRS / FOV / DEST / SPD / RANGE (unchanged) | +| PREV / NEXT | ANT. / PRÓX. | +| Previous / Next (button text) | Anterior / Próximo (Próxima) | +| L / R (relative bearing) | E / D | +| SIG / NEWS / LOCAL (briefing tabs) | SIG / NOTÍCIAS / LOCAL | +| PITCH / HGT (CCTV calibration chips) | INCL. / ALT. | +| NOT AN ALL-CLEAR | NÃO GARANTE SEGURANÇA | +| turn-by-turn: turn left / keep left / lane | vire à esquerda / mantenha-se à esquerda / faixa da esquerda | diff --git a/scripts/package-boundaries.json b/scripts/package-boundaries.json index 9f06f73f6..602895c76 100644 --- a/scripts/package-boundaries.json +++ b/scripts/package-boundaries.json @@ -440,6 +440,7 @@ "src/i18n/index.js", "src/i18n/locale.js", "src/i18n/locales/es.json", + "src/i18n/locales/pt.json", "src/i18n/locales/ru.json", "src/i18n/locales/zh-CN.json", "src/i18n/locales/zh-Hant.json" @@ -480,6 +481,7 @@ "src/i18n/index.js", "src/i18n/locale.js", "src/i18n/locales/es.json", + "src/i18n/locales/pt.json", "src/i18n/locales/ru.json", "src/i18n/locales/zh-CN.json", "src/i18n/locales/zh-Hant.json" @@ -510,6 +512,7 @@ "src/i18n/index.js", "src/i18n/locale.js", "src/i18n/locales/es.json", + "src/i18n/locales/pt.json", "src/i18n/locales/ru.json", "src/i18n/locales/zh-CN.json", "src/i18n/locales/zh-Hant.json", @@ -532,6 +535,7 @@ "src/i18n/index.js", "src/i18n/locale.js", "src/i18n/locales/es.json", + "src/i18n/locales/pt.json", "src/i18n/locales/ru.json", "src/i18n/locales/zh-CN.json", "src/i18n/locales/zh-Hant.json" @@ -549,6 +553,7 @@ "src/i18n/index.js", "src/i18n/locale.js", "src/i18n/locales/es.json", + "src/i18n/locales/pt.json", "src/i18n/locales/ru.json", "src/i18n/locales/zh-CN.json", "src/i18n/locales/zh-Hant.json" @@ -569,6 +574,7 @@ "src/i18n/index.js", "src/i18n/locale.js", "src/i18n/locales/es.json", + "src/i18n/locales/pt.json", "src/i18n/locales/ru.json", "src/i18n/locales/zh-CN.json", "src/i18n/locales/zh-Hant.json", @@ -596,6 +602,7 @@ "src/i18n/index.js", "src/i18n/locale.js", "src/i18n/locales/es.json", + "src/i18n/locales/pt.json", "src/i18n/locales/ru.json", "src/i18n/locales/zh-CN.json", "src/i18n/locales/zh-Hant.json", @@ -631,6 +638,7 @@ "src/i18n/index.js", "src/i18n/locale.js", "src/i18n/locales/es.json", + "src/i18n/locales/pt.json", "src/i18n/locales/ru.json", "src/i18n/locales/zh-CN.json", "src/i18n/locales/zh-Hant.json", @@ -648,6 +656,7 @@ "src/i18n/index.js", "src/i18n/locale.js", "src/i18n/locales/es.json", + "src/i18n/locales/pt.json", "src/i18n/locales/ru.json", "src/i18n/locales/zh-CN.json", "src/i18n/locales/zh-Hant.json", @@ -807,6 +816,7 @@ "src/i18n/index.js", "src/i18n/locale.js", "src/i18n/locales/es.json", + "src/i18n/locales/pt.json", "src/i18n/locales/ru.json", "src/i18n/locales/zh-CN.json", "src/i18n/locales/zh-Hant.json", @@ -929,6 +939,7 @@ "src/i18n/index.js", "src/i18n/locale.js", "src/i18n/locales/es.json", + "src/i18n/locales/pt.json", "src/i18n/locales/ru.json", "src/i18n/locales/zh-CN.json", "src/i18n/locales/zh-Hant.json", @@ -997,6 +1008,7 @@ "src/i18n/index.js", "src/i18n/locale.js", "src/i18n/locales/es.json", + "src/i18n/locales/pt.json", "src/i18n/locales/ru.json", "src/i18n/locales/zh-CN.json", "src/i18n/locales/zh-Hant.json", @@ -1046,6 +1058,7 @@ "src/i18n/index.js", "src/i18n/locale.js", "src/i18n/locales/es.json", + "src/i18n/locales/pt.json", "src/i18n/locales/ru.json", "src/i18n/locales/zh-CN.json", "src/i18n/locales/zh-Hant.json" @@ -1109,6 +1122,7 @@ "src/i18n/index.js", "src/i18n/locale.js", "src/i18n/locales/es.json", + "src/i18n/locales/pt.json", "src/i18n/locales/ru.json", "src/i18n/locales/zh-CN.json", "src/i18n/locales/zh-Hant.json" @@ -1139,6 +1153,7 @@ "src/i18n/index.js", "src/i18n/locale.js", "src/i18n/locales/es.json", + "src/i18n/locales/pt.json", "src/i18n/locales/ru.json", "src/i18n/locales/zh-CN.json", "src/i18n/locales/zh-Hant.json", @@ -1170,6 +1185,7 @@ "src/i18n/index.js", "src/i18n/locale.js", "src/i18n/locales/es.json", + "src/i18n/locales/pt.json", "src/i18n/locales/ru.json", "src/i18n/locales/zh-CN.json", "src/i18n/locales/zh-Hant.json" @@ -1201,6 +1217,7 @@ "src/i18n/index.js", "src/i18n/locale.js", "src/i18n/locales/es.json", + "src/i18n/locales/pt.json", "src/i18n/locales/ru.json", "src/i18n/locales/zh-CN.json", "src/i18n/locales/zh-Hant.json", @@ -1235,6 +1252,7 @@ "src/i18n/index.js", "src/i18n/locale.js", "src/i18n/locales/es.json", + "src/i18n/locales/pt.json", "src/i18n/locales/ru.json", "src/i18n/locales/zh-CN.json", "src/i18n/locales/zh-Hant.json" @@ -1278,6 +1296,7 @@ "src/i18n/index.js", "src/i18n/locale.js", "src/i18n/locales/es.json", + "src/i18n/locales/pt.json", "src/i18n/locales/ru.json", "src/i18n/locales/zh-CN.json", "src/i18n/locales/zh-Hant.json", @@ -1315,6 +1334,7 @@ "src/i18n/index.js", "src/i18n/locale.js", "src/i18n/locales/es.json", + "src/i18n/locales/pt.json", "src/i18n/locales/ru.json", "src/i18n/locales/zh-CN.json", "src/i18n/locales/zh-Hant.json", @@ -1366,6 +1386,7 @@ "src/i18n/index.js", "src/i18n/locale.js", "src/i18n/locales/es.json", + "src/i18n/locales/pt.json", "src/i18n/locales/ru.json", "src/i18n/locales/zh-CN.json", "src/i18n/locales/zh-Hant.json" @@ -1396,6 +1417,7 @@ "src/i18n/index.js", "src/i18n/locale.js", "src/i18n/locales/es.json", + "src/i18n/locales/pt.json", "src/i18n/locales/ru.json", "src/i18n/locales/zh-CN.json", "src/i18n/locales/zh-Hant.json" @@ -1445,6 +1467,7 @@ "src/i18n/index.js", "src/i18n/locale.js", "src/i18n/locales/es.json", + "src/i18n/locales/pt.json", "src/i18n/locales/ru.json", "src/i18n/locales/zh-CN.json", "src/i18n/locales/zh-Hant.json" @@ -1509,6 +1532,7 @@ "src/i18n/index.js", "src/i18n/locale.js", "src/i18n/locales/es.json", + "src/i18n/locales/pt.json", "src/i18n/locales/ru.json", "src/i18n/locales/zh-CN.json", "src/i18n/locales/zh-Hant.json", @@ -1539,6 +1563,7 @@ "src/i18n/index.js", "src/i18n/locale.js", "src/i18n/locales/es.json", + "src/i18n/locales/pt.json", "src/i18n/locales/ru.json", "src/i18n/locales/zh-CN.json", "src/i18n/locales/zh-Hant.json" @@ -1580,6 +1605,7 @@ "src/i18n/index.js", "src/i18n/locale.js", "src/i18n/locales/es.json", + "src/i18n/locales/pt.json", "src/i18n/locales/ru.json", "src/i18n/locales/zh-CN.json", "src/i18n/locales/zh-Hant.json" @@ -1603,6 +1629,7 @@ "src/i18n/index.js", "src/i18n/locale.js", "src/i18n/locales/es.json", + "src/i18n/locales/pt.json", "src/i18n/locales/ru.json", "src/i18n/locales/zh-CN.json", "src/i18n/locales/zh-Hant.json" @@ -1660,6 +1687,7 @@ "src/i18n/index.js", "src/i18n/locale.js", "src/i18n/locales/es.json", + "src/i18n/locales/pt.json", "src/i18n/locales/ru.json", "src/i18n/locales/zh-CN.json", "src/i18n/locales/zh-Hant.json" @@ -1723,6 +1751,7 @@ "src/i18n/index.js", "src/i18n/locale.js", "src/i18n/locales/es.json", + "src/i18n/locales/pt.json", "src/i18n/locales/ru.json", "src/i18n/locales/zh-CN.json", "src/i18n/locales/zh-Hant.json", @@ -2606,6 +2635,7 @@ "src/i18n/index.js", "src/i18n/locale.js", "src/i18n/locales/es.json", + "src/i18n/locales/pt.json", "src/i18n/locales/ru.json", "src/i18n/locales/zh-CN.json", "src/i18n/locales/zh-Hant.json", @@ -3191,6 +3221,7 @@ "src/i18n/index.js", "src/i18n/locale.js", "src/i18n/locales/es.json", + "src/i18n/locales/pt.json", "src/i18n/locales/ru.json", "src/i18n/locales/zh-CN.json", "src/i18n/locales/zh-Hant.json", @@ -3302,6 +3333,7 @@ "src/data/cameraArrival.js", "src/i18n/locale.js", "src/i18n/locales/es.json", + "src/i18n/locales/pt.json", "src/i18n/locales/ru.json", "src/i18n/locales/zh-CN.json", "src/i18n/locales/zh-Hant.json", @@ -3326,6 +3358,7 @@ "src/i18n/index.js", "src/i18n/locale.js", "src/i18n/locales/es.json", + "src/i18n/locales/pt.json", "src/i18n/locales/ru.json", "src/i18n/locales/zh-CN.json", "src/i18n/locales/zh-Hant.json" @@ -3363,6 +3396,7 @@ "src/i18n/index.js", "src/i18n/locale.js", "src/i18n/locales/es.json", + "src/i18n/locales/pt.json", "src/i18n/locales/ru.json", "src/i18n/locales/zh-CN.json", "src/i18n/locales/zh-Hant.json", @@ -3390,6 +3424,7 @@ "src/i18n/index.js", "src/i18n/locale.js", "src/i18n/locales/es.json", + "src/i18n/locales/pt.json", "src/i18n/locales/ru.json", "src/i18n/locales/zh-CN.json", "src/i18n/locales/zh-Hant.json" @@ -3482,6 +3517,7 @@ "src/i18n/index.js", "src/i18n/locale.js", "src/i18n/locales/es.json", + "src/i18n/locales/pt.json", "src/i18n/locales/ru.json", "src/i18n/locales/zh-CN.json", "src/i18n/locales/zh-Hant.json", @@ -3538,6 +3574,7 @@ "src/i18n/index.js", "src/i18n/locale.js", "src/i18n/locales/es.json", + "src/i18n/locales/pt.json", "src/i18n/locales/ru.json", "src/i18n/locales/zh-CN.json", "src/i18n/locales/zh-Hant.json", @@ -3793,6 +3830,7 @@ "src/i18n/index.js", "src/i18n/locale.js", "src/i18n/locales/es.json", + "src/i18n/locales/pt.json", "src/i18n/locales/ru.json", "src/i18n/locales/zh-CN.json", "src/i18n/locales/zh-Hant.json" @@ -3837,6 +3875,7 @@ "src/i18n/index.js", "src/i18n/locale.js", "src/i18n/locales/es.json", + "src/i18n/locales/pt.json", "src/i18n/locales/ru.json", "src/i18n/locales/zh-CN.json", "src/i18n/locales/zh-Hant.json" @@ -3891,6 +3930,7 @@ "src/i18n/index.js", "src/i18n/locale.js", "src/i18n/locales/es.json", + "src/i18n/locales/pt.json", "src/i18n/locales/ru.json", "src/i18n/locales/zh-CN.json", "src/i18n/locales/zh-Hant.json" @@ -3908,6 +3948,7 @@ "src/i18n/index.js", "src/i18n/locale.js", "src/i18n/locales/es.json", + "src/i18n/locales/pt.json", "src/i18n/locales/ru.json", "src/i18n/locales/zh-CN.json", "src/i18n/locales/zh-Hant.json", @@ -3968,6 +4009,7 @@ "src/i18n/index.js", "src/i18n/locale.js", "src/i18n/locales/es.json", + "src/i18n/locales/pt.json", "src/i18n/locales/ru.json", "src/i18n/locales/zh-CN.json", "src/i18n/locales/zh-Hant.json", @@ -4165,6 +4207,7 @@ "src/i18n/index.js", "src/i18n/locale.js", "src/i18n/locales/es.json", + "src/i18n/locales/pt.json", "src/i18n/locales/ru.json", "src/i18n/locales/zh-CN.json", "src/i18n/locales/zh-Hant.json", diff --git a/src/i18n/i18n.test.mjs b/src/i18n/i18n.test.mjs index 1b421f2ff..df6b4d000 100644 --- a/src/i18n/i18n.test.mjs +++ b/src/i18n/i18n.test.mjs @@ -34,6 +34,8 @@ test('normalizeLocale folds regional variants and rejects unshipped tags', () => assert.equal(normalizeLocale('ru-RU'), 'ru'); assert.equal(normalizeLocale(' RU '), 'ru'); assert.equal(normalizeLocale('en_GB'), 'en'); + assert.equal(normalizeLocale('pt-BR'), 'pt'); + assert.equal(normalizeLocale('pt_PT'), 'pt'); assert.equal(normalizeLocale('xx'), null); // Explicit script tags take precedence over regional defaults. assert.equal(normalizeLocale('zh'), 'zh-CN'); @@ -142,6 +144,20 @@ test('tn() picks English and Russian plural forms', () => { assert.match(label(21), / 21 КЛЮЧ(?![А-ЯЁ])/); }); +test('tn() picks the Portuguese one, many and other forms', () => { + const label = (count) => + tn( + count, + 'POWER UP · {count} KEY WAITING', + 'POWER UP · {count} KEYS WAITING', + ); + setLocale('pt'); + assert.equal(label(0), 'ATIVAR · 0 CHAVE PENDENTE'); + assert.equal(label(1), 'ATIVAR · 1 CHAVE PENDENTE'); + assert.equal(label(3), 'ATIVAR · 3 CHAVES PENDENTES'); + assert.equal(label(1_000_000), 'ATIVAR · 1000000 DE CHAVES PENDENTES'); +}); + test('t() context separates identical English with different meanings', () => { assert.equal(t('CLEAR', { context: 'action' }), 'CLEAR'); setLocale('ru'); diff --git a/src/i18n/index.js b/src/i18n/index.js index 6fc4becc9..a6076bbd5 100644 --- a/src/i18n/index.js +++ b/src/i18n/index.js @@ -17,11 +17,18 @@ import { writeStoredLocale, } from './locale.js'; import es from './locales/es.json' with { type: 'json' }; +import pt from './locales/pt.json' with { type: 'json' }; import ru from './locales/ru.json' with { type: 'json' }; import zhCN from './locales/zh-CN.json' with { type: 'json' }; import zhHant from './locales/zh-Hant.json' with { type: 'json' }; -const CATALOGS = Object.freeze({ es, ru, 'zh-CN': zhCN, 'zh-Hant': zhHant }); +const CATALOGS = Object.freeze({ + es, + pt, + ru, + 'zh-CN': zhCN, + 'zh-Hant': zhHant, +}); let currentLocale = DEFAULT_LOCALE; diff --git a/src/i18n/locale.js b/src/i18n/locale.js index 55ed71163..db072d179 100644 --- a/src/i18n/locale.js +++ b/src/i18n/locale.js @@ -8,12 +8,20 @@ export const LOCALE_STORAGE_KEY = 'gev:locale:v1'; export const DEFAULT_LOCALE = 'en'; /** Shipped locales; order does not matter. Adding one: docs/TRANSLATORS.md. */ -export const LOCALES = Object.freeze(['en', 'es', 'ru', 'zh-CN', 'zh-Hant']); +export const LOCALES = Object.freeze([ + 'en', + 'es', + 'pt', + 'ru', + 'zh-CN', + 'zh-Hant', +]); /** Each locale named in its own language, for the selector. */ export const LOCALE_NAMES = Object.freeze({ en: 'English', es: 'Español', + pt: 'Português (Brasil)', ru: 'Русский', 'zh-CN': '中文(简体)', 'zh-Hant': '中文(繁體)', @@ -24,6 +32,7 @@ const RTL_LOCALES = Object.freeze([]); /** * Map any language tag to a shipped locale: 'ru-RU' and 'RU' → 'ru', + * 'pt-BR' and 'pt-PT' → 'pt' (Brazilian Portuguese), * 'zh', 'zh-CN' and 'zh-Hans-SG' → 'zh-CN'; * 'zh-Hant', 'zh-TW', 'zh-HK' and 'zh-MO' → 'zh-Hant'. * @returns {string|null} diff --git a/src/i18n/locales/pt.json b/src/i18n/locales/pt.json index 0afe119ed..c64e4b4bd 100644 --- a/src/i18n/locales/pt.json +++ b/src/i18n/locales/pt.json @@ -1,4 +1,24 @@ { + "Pick a shape, then click the map.": "Escolha uma forma e clique no mapa.", + "Enter to place the pin, Esc to cancel.": "Enter para colocar o marcador, Esc para cancelar.", + "Click where the pin goes.": "Clique onde o marcador deve ficar.", + "Click {count} more points.": { + "one": "Clique em mais {count} ponto.", + "many": "Clique em mais {count} de pontos.", + "other": "Clique em mais {count} pontos." + }, + "Those points are in a line — move one off it to enclose an area.": "Esses pontos estão em linha — tire um deles da linha para fechar uma área.", + "That line has no length — click somewhere further away.": "Essa linha não tem comprimento — clique em um ponto mais distante.", + " · {max}-point limit reached": " · limite de {max} pontos atingido", + "{measure} · double-click or Enter to finish, Backspace undoes, Esc cancels.{full}": "{measure} · clique duplo ou Enter para concluir, Backspace desfaz, Esc cancela.{full}", + "drawings on the map": "os desenhos no mapa", + "That shape already has {count} points — finish it or press Backspace.": "Essa forma já tem {count} pontos — conclua-a ou pressione Backspace.", + "That point is off the globe — click on the world.": "Esse ponto está fora do globo — clique sobre o mundo.", + "That shape could not be placed.": "Não foi possível colocar essa forma.", + "Could not place the shape: {error}": "Não foi possível colocar a forma: {error}", + "Board cleared.": "Quadro limpo.", + "{owner} is using the pointer — close it first.": "Ponteiro em uso: {owner}. Feche-o primeiro.", + "{label} · Detailed outline unavailable": "{label} · Contorno detalhado indisponível", "Flying to Austin, TX...": "Voando para Austin, TX...", "Restoring shared view...": "Restaurando a vista compartilhada...", "Configuring viewer...": "Configurando o visualizador...", @@ -6,14 +26,223 @@ "Loading the keyless globe...": "Carregando o globo sem chave...", "Google 3D Tiles unavailable ({detail}). Loading the keyless globe...": "Google 3D Tiles indisponível ({detail}). Carregando o globo sem chave...", "Initializing systems...": "Inicializando sistemas...", + "Space Missions isolates replay data. Exit the mode to enable {layer}.": "O modo Missões espaciais isola os dados da reprise. Saia do modo para ativar {layer}.", + "Data attribution": "Atribuição de dados", + "Data provided by:": "Dados fornecidos por:", "Close data attribution": "Fechar atribuição de dados", + "Light aircraft": "Aeronave leve", + "Glider": "Planador", + "Turboprop": "Turboélice", + "Airliner": "Avião comercial", + "Widebody": "Avião de fuselagem larga", + "Four-engine jet": "Jato quadrimotor", + "Helicopter": "Helicóptero", + "Fast jet": "Jato de alto desempenho", + "Business jet": "Jato executivo", + "Drone": "Drone", + "General emergency": "Emergência geral", + "Unlawful interference": "Interferência ilícita", + "Radio failure": "Falha de rádio", + "Downed aircraft": "Aeronave acidentada", + "Minimum fuel": "Combustível mínimo", + "Lifeguard (medical priority)": "Lifeguard (prioridade médica)", + "Rasuwagadhi witness video": "Vídeo de testemunha em Rasuwagadhi", + "Bhote Koshi valley footage": "Imagens do vale do Bhote Koshi", + "Flood footage": "Imagens da inundação", + "Compilation and casualty claims": "Compilação e relatos de vítimas", + "SOURCE GEOCONFIRMED · WORLD-PINNED": "FONTE GEOCONFIRMADA · FIXADA NO MAPA", + "SOURCE CREDITED · LOCATION UNRESOLVED": "FONTE CREDITADA · LOCAL NÃO DETERMINADO", + "REFERENCE ONLY · CLAIMS UNVERIFIED": "SÓ REFERÊNCIA · RELATOS NÃO VERIFICADOS", + "SOURCE GEOCONFIRMED": "FONTE GEOCONFIRMADA", + "2021 historical reference versus 2026 post-event imagery; changes are cumulative and include the July 2025 Rasuwagadhi flood. Schematic downstream progression, not modeled arrival time; not an official hazard model.": "Referência histórica de 2021 comparada a imagens posteriores ao evento de 2026; as mudanças são cumulativas e incluem a inundação de Rasuwagadhi de julho de 2025. Avanço esquemático rio abaixo, não um tempo de chegada modelado; não é um modelo oficial de risco.", + "Immediate collapse viewpoint": "Ponto de vista junto ao colapso", + "Collapse viewpoint": "Vista do colapso", + "Debris-dammed lake": "Lago represado por detritos", + "Dammed lake": "Lago represado", + "Second landslide": "Segundo deslizamento", + "Gyirong border gate": "Posto de fronteira de Gyirong", + "Border gate": "Posto de fronteira", + "Timure evidence cluster": "Grupo de evidências de Timure", + "Mailung / Upper Trishuli bridge": "Mailung / ponte de Upper Trishuli", + "Dandagaun viewpoint restaurant": "Restaurante mirante de Dandagaun", + "Dandagaun viewpoint": "Mirante de Dandagaun", + "Bidur - Trishuli bridge": "Ponte Bidur - Trishuli", + "Bidur bridge": "Ponte de Bidur", + "Devighat / Taadi Khola Bridge": "Devighat / ponte de Taadi Khola", + "Devighat bridge": "Ponte de Devighat", + "Facebook player API did not initialize.": "A API do player do Facebook não foi inicializada.", + "Facebook player API could not load.": "Não foi possível carregar a API do player do Facebook.", + "Facebook player API timed out.": "A API do player do Facebook excedeu o tempo limite.", + "X embed API did not initialize.": "A API de incorporação do X não foi inicializada.", + "X embed could not load.": "Não foi possível carregar a incorporação do X.", + "X embed timed out.": "A incorporação do X excedeu o tempo limite.", "UNAVAILABLE": "INDISPONÍVEL", + "TIMEOUT": "TEMPO ESGOTADO", + "BLOCKED": "BLOQUEADO", "SOURCE": "FONTE", + "Facebook embed unavailable. The post may be private, removed, region-restricted, or blocked.": "Incorporação do Facebook indisponível. A publicação pode ser privada, ter sido removida, ter restrição regional ou estar bloqueada.", + "Preloading {provider} media": "Pré-carregando mídia do {provider}", + "LOADING X POST…": "CARREGANDO PUBLICAÇÃO DO X…", + "The X post is unavailable or cannot be embedded.": "A publicação do X está indisponível ou não pode ser incorporada.", + "X POST · PROVIDER CONTROLS": "PUBLICAÇÃO DO X · CONTROLES DO PROVEDOR", + "{reason} OPEN ORIGINAL.": "{reason} ABRA O ORIGINAL.", + "X embed unavailable": "Incorporação do X indisponível", + "FACEBOOK · PROVIDER CONTROLS": "FACEBOOK · CONTROLES DO PROVEDOR", + "Facebook embed unavailable": "Incorporação do Facebook indisponível", + "AUTOPLAY BLOCKED · USE PROVIDER CONTROLS": "REPRODUÇÃO AUTOMÁTICA BLOQUEADA · USE OS CONTROLES DO PROVEDOR", + "Embedded {provider} media for {source}": "Mídia do {provider} incorporada para {source}", + "witness source": "fonte de testemunha", + "Witness source": "Fonte de testemunha", + "{provider} · EMBEDDED SOURCE": "{provider} · FONTE INCORPORADA", + "OPEN ORIGINAL ↗": "ABRIR ORIGINAL ↗", + "{provider} media: {source}": "Mídia do {provider}: {source}", + "{provider} · PROVIDER CONTROLS": "{provider} · CONTROLES DO PROVEDOR", + "YOUTUBE {state} · OPEN ORIGINAL": "YOUTUBE {state} · ABRIR ORIGINAL", + "INITIATION": "INÍCIO", + "DAMMING": "REPRESAMENTO", + "SECONDARY FAILURE": "RUPTURA SECUNDÁRIA", + "BORDER ARRIVAL": "CHEGADA À FRONTEIRA", + "PROPAGATION": "PROPAGAÇÃO", + "DOWNSTREAM PASSAGE": "PASSAGEM RIO ABAIXO", + "CONSEQUENCE": "CONSEQUÊNCIAS", + "DOWNSTREAM CONSEQUENCE": "CONSEQUÊNCIAS RIO ABAIXO", + "EVIDENCE": "EVIDÊNCIA", + "{year} HISTORICAL REFERENCE": "REFERÊNCIA HISTÓRICA {year}", + "{year} POST-EVENT": "PÓS-EVENTO {year}", + "{count} GEOLOCATED SOURCE-MAP PLACEMENTS": { + "one": "{count} POSIÇÃO GEOLOCALIZADA NO MAPA DE FONTES", + "many": "{count} DE POSIÇÕES GEOLOCALIZADAS NO MAPA DE FONTES", + "other": "{count} POSIÇÕES GEOLOCALIZADAS NO MAPA DE FONTES" + }, + "NO PREVIEW": "SEM PRÉVIA", + "YouTube source": "Fonte do YouTube", + "Facebook source": "Fonte do Facebook", + "SOURCE LINK": "LINK DA FONTE", + "{publisher} / OPEN": "{publisher} / ABRIR", + "Bhote Koshi flood reconstruction controls": "Controles da reconstrução da inundação do Bhote Koshi", + "EVENT RECONSTRUCTION · 26 AUG 2026": "RECONSTRUÇÃO DO EVENTO · 26 AGO 2026", + "BHOTE KOSHI OUTBURST FLOOD": "INUNDAÇÃO POR ROMPIMENTO NO BHOTE KOSHI", + "Close event layer": "Fechar a camada do evento", + "OBSERVED IMAGERY": "IMAGENS OBSERVADAS", + "SCHEMATIC CORRIDOR": "CORREDOR ESQUEMÁTICO", + "2021 HISTORICAL REFERENCE / 2026 POST-EVENT": "REF. HISTÓRICA 2021 / PÓS-EVENTO 2026", + "Historical reference and post-event image split": "Divisão entre a imagem de referência histórica e a pós-evento", + "RECONSTRUCTION CLOCK": "RELÓGIO DA RECONSTRUÇÃO", + "Schematic downstream progression": "Avanço esquemático rio abaixo", + "Story beat navigation": "Navegação pelos momentos da história", + "Previous story beat": "Momento anterior da história", + "CAUSE": "CAUSA", + "CAPTURE TIME UNVERIFIED": "HORA DE CAPTURA NÃO VERIFICADA", + "Next story beat": "Próximo momento da história", + "▶ PLAY": "▶ REPRODUZIR", + "Play the next shot and continue through this scene": "Reproduzir o próximo plano e seguir por esta cena", + "▶ PLAY SCENE": "▶ REPRODUZIR CENA", + "◉ CINEMATIC": "◉ CINEMATOGRÁFICO", + "↺ FULL STORY": "↺ HISTÓRIA COMPLETA", + "↗ OPEN ORIGINAL": "↗ ABRIR ORIGINAL", + "⌖ LOWER GORGE": "⌖ GARGANTA INFERIOR", + "FIELD REPORTS · {count}": "RELATOS DE CAMPO · {count}", + "GEOLOCATIONS · {credit}": "GEOLOCALIZAÇÕES · {credit}", + "↗ OPEN PUBLIC MAP": "↗ ABRIR MAPA PÚBLICO", + " Clouds are preserved from the source imagery.": " As nuvens vêm das imagens de origem.", + "Rasuwagadhi witness": "Testemunha em Rasuwagadhi", + "Open original source for {source}; capture time unverified": "Abrir a fonte original de {source}; hora de captura não verificada", + "Historical reference and post-event image divider": "Divisor entre a imagem de referência histórica e a pós-evento", + "A historical reference {before} percent, B post-event {after} percent": "A, referência histórica, {before} por cento; B, pós-evento, {after} por cento", + "■ RELEASE CAMERA": "■ LIBERAR CÂMERA", + "Seek Nepal scene clock": "Navegar pelo relógio da cena do Nepal", + "NEPAL SCENE CLOCK": "RELÓGIO DA CENA DO NEPAL", + "… PLAYING SHOT": "… REPRODUZINDO PLANO", + "▶ PLAY SHOT": "▶ REPRODUZIR PLANO", + "Ⅱ PAUSE": "Ⅱ PAUSAR", + "↺ REPLAY CINEMATIC": "↺ REPETIR CINEMATOGRÁFICO", + "↺ REPLAY": "↺ REPETIR", + "… PLAYING SCENE": "… REPRODUZINDO CENA", + "Continue {scene} from next shot": "Continuar {scene} a partir do próximo plano", + "current scene": "a cena atual", + "Replay the full reconstruction": "Repetir a reconstrução completa", + "SCENE SHOT": "PLANO DA CENA", + "TIME UNVERIFIED": "HORA NÃO VERIFICADA", + "{count} SOURCES": { + "one": "{count} FONTE", + "many": "{count} DE FONTES", + "other": "{count} FONTES" + }, + "OUTSIDE IMAGERY SWIPE": "FORA DA COMPARAÇÃO DE IMAGENS", + "{scene} / AUTHORED SHOT": "{scene} / PLANO AUTORAL", + "NEPAL FLOOD INCIDENT": "INCIDENTE DE INUNDAÇÃO NO NEPAL", + "Play {shot}": "Reproduzir {shot}", + "current scene shot": "o plano atual da cena", + "Play reconstruction": "Reproduzir a reconstrução", + "Load previous scene shot": "Carregar o plano anterior da cena", + "Load next scene shot": "Carregar o próximo plano da cena", + "SCHEMATIC CORRIDOR, NOT MODELED ARRIVAL TIME.": "CORREDOR ESQUEMÁTICO, NÃO UM TEMPO DE CHEGADA MODELADO.", + "Rasuwa · 26 Aug 2026": "Rasuwa · 26 ago 2026", + "Event reconstruction": "Reconstrução do evento", + "BHOTE KOSHI FLOOD INCIDENT": "INCIDENTE DE INUNDAÇÃO NO BHOTE KOSHI", + "NEPAL · 26 AUG 2026": "NEPAL · 26 AGO 2026", + "USGS INITIAL REPORT": "RELATÓRIO INICIAL DO USGS", + "26 AUG 2026 · 08:37 NPT": "26 AGO 2026 · 08:37 NPT", + "28.2710° N · 85.5150° E": "28,2710° N · 85,5150° L", + "INITIAL M4.4 · RECLASSIFIED M5.2 LANDSLIDE": "INICIAL M4,4 · RECLASSIFICADO COMO DESLIZAMENTO M5,2", + "USGS EVENT us7000tbwb · OPEN SOURCE": "EVENTO USGS us7000tbwb · ABRIR FONTE", + "Open the USGS initial report for the 26 August 2026 Nepal landslide": "Abrir o relatório inicial do USGS sobre o deslizamento de 26 de agosto de 2026 no Nepal", + "Show the Nepal context callout without a border or country fill": "Mostra o destaque de contexto do Nepal sem fronteira nem preenchimento do país", + "Introduce Nepal, draw its border, then reveal the Bhote Koshi incident": "Apresenta o Nepal, desenha sua fronteira e depois revela o incidente do Bhote Koshi", + "CITIES": "CIDADES", + "Keep the regional incident context and introduce nearby city labels": "Mantém o contexto regional do incidente e apresenta os rótulos das cidades próximas", + "PLACES": "LUGARES", + "Introduce the reconstruction scene key places from trigger to downstream": "Apresenta os lugares-chave da cena de reconstrução, do gatilho até rio abaixo", + "PATH": "PERCURSO", + "Animate the sourced cyan river-centerline route to Trishuli Bazaar": "Anima a rota ciano documentada pelo eixo do rio até Trishuli Bazaar", + "OVERVIEW": "VISÃO GERAL", + "Keep the completed flood path and location labels visible": "Mantém visíveis o percurso completo da inundação e os rótulos dos locais", + "RECORD": "REGISTRO", + "Reveal the trigger record while making a slow camera approach": "Revela o registro do gatilho com uma aproximação lenta da câmera", + "{speed} kn": "{speed} kt", + "That file is not valid JSON.": "Esse arquivo não é um JSON válido.", + "That JSON file is not GeoJSON.": "Esse arquivo JSON não é GeoJSON.", + "That FeatureCollection has no features list.": "Essa FeatureCollection não tem lista de features.", + "Every GeoJSON feature must have type Feature.": "Todo elemento GeoJSON deve ter o tipo Feature.", + "That GeoJSON has invalid geometries.": "Esse GeoJSON tem geometrias inválidas.", + "That GeoJSON contains an unsupported geometry.": "Esse GeoJSON contém uma geometria não suportada.", + "That GeoJSON has invalid coordinates.": "Esse GeoJSON tem coordenadas inválidas.", + "That file creates more than {limit} map objects (the limit).": "Esse arquivo cria mais de {limit} objetos no mapa (o limite).", + "That file has more than {limit} style definitions and image links after cleanup (the limit).": "Após a limpeza, esse arquivo tem mais de {limit} definições de estilo e links de imagem (o limite).", + "That file has more than {limit} features (the limit).": "Esse arquivo tem mais de {limit} elementos (o limite).", + "That file has more than {limit} points (the limit) across {features} features.": "Esse arquivo tem mais de {limit} pontos (o limite) em {features} elementos.", + "That file has more than {limit} points (the limit).": "Esse arquivo tem mais de {limit} pontos (o limite).", + "That KMZ unpacks to more than the import limit.": "Descompactado, esse KMZ ultrapassa o limite de importação.", + "That KMZ is damaged and could not be unpacked.": "Esse KMZ está danificado e não pôde ser descompactado.", + "That KMZ is not a readable zip archive.": "Esse KMZ não é um arquivo zip legível.", + "That KMZ uses a zip format this import does not read.": "Esse KMZ usa um formato zip que esta importação não lê.", + "That KMZ is encrypted.": "Esse KMZ está criptografado.", + "That KMZ uses a compression method this import does not read.": "Esse KMZ usa um método de compressão que esta importação não lê.", + "That KML has invalid geometry bounds.": "Esse KML tem limites de geometria inválidos.", + "That KML has invalid coordinates.": "Esse KML tem coordenadas inválidas.", + "That GPX file has no document.": "Esse arquivo GPX não tem documento .", + "That {format} file is not valid XML.": "Esse arquivo {format} não é um XML válido.", + "That file has an unreadable image or exceeds the 16-megapixel image limit.": "Esse arquivo tem uma imagem ilegível ou ultrapassa o limite de imagem de 16 megapixels.", + "That KML could not be read.": "Não foi possível ler esse KML.", + "That file has invalid point coordinates.": "Esse arquivo tem coordenadas de pontos inválidas.", + "Ground heights are not available for that file. Try again when the map has loaded.": "As altitudes do terreno não estão disponíveis para esse arquivo. Tente de novo quando o mapa tiver carregado.", + "That file took too long to read.": "A leitura desse arquivo demorou demais.", + "Nothing to import.": "Nada para importar.", + "That file is larger than {size} MiB.": "Esse arquivo tem mais de {size} MiB.", + "Only GeoJSON, KML, KMZ and GPX files can be imported.": "Só é possível importar arquivos GeoJSON, KML, KMZ e GPX.", + "That file has nothing to draw.": "Esse arquivo não tem nada para desenhar.", + "That KMZ holds no KML document.": "Esse KMZ não contém nenhum documento KML.", + "That {format} file could not be read.": "Não foi possível ler esse arquivo {format}.", + "That file has {count} map objects; the limit is {limit}.": "Esse arquivo tem {count} objetos no mapa; o limite é {limit}.", + "Ground heights could not be read. Try that file again.": "Não foi possível ler as altitudes do terreno. Tente esse arquivo de novo.", + "That file has invalid point graphics.": "Esse arquivo tem gráficos de pontos inválidos.", "Overpass rate-limited": "Overpass com limite de requisições", "Overpass timed out": "Tempo esgotado no Overpass", "Overpass could not complete the query": "Overpass não conseguiu concluir a consulta", + "Map tiles temporarily unavailable": "Blocos do mapa temporariamente indisponíveis", + "Mapped names temporarily unavailable": "Nomes mapeados temporariamente indisponíveis", "Overpass temporarily unavailable": "Overpass temporariamente indisponível", - "Retrying mapped sites…": "Repetindo busca de locais mapeados…", + "Retrying mapped sites…": "Tentando de novo os locais mapeados…", "Fetching mapped sites…": "Buscando locais mapeados…", "{reason} — retrying in {seconds}s": "{reason} — nova tentativa em {seconds}s", "{reason} — retry pending": "{reason} — nova tentativa pendente", @@ -21,10 +250,22 @@ "Showing cached mapped sites": "Mostrando locais mapeados em cache", "Mapped sites not loaded": "Locais mapeados não carregados", "Mapped sites loaded": "Locais mapeados carregados", + "Military airfield": "Aeródromo militar", + "Naval base": "Base naval", + "Firing range": "Campo de tiro", + "Military land": "Terreno militar", + "Mapped installation": "Instalação mapeada", + "Military area": "Área militar", + "flight": "voo", + "military flight": "voo militar", + "satellite": "satélite", "feed unavailable": "feed indisponível", "feed stale": "feed desatualizado", "observed or mapped nearby context": "contexto observado ou mapeado nas proximidades", "no observed or mapped objects in current feeds": "nenhum objeto observado ou mapeado nos feeds atuais", + "Draw": "Desenho", + "Directions": "Rotas", + "Recent imagery": "Imagens recentes", "STATION": "ESTAÇÃO", "Crewed stations and their visiting vehicles": "Estações tripuladas e seus veículos visitantes", "NAV": "NAV", @@ -33,8 +274,8 @@ "Geostationary belt — comms and weather, fixed over the equator": "Cinturão geoestacionário — comunicações e clima, fixo sobre o equador", "VISUAL": "VISUAL", "Brightest naked-eye objects — CelesTrak visual group": "Objetos mais brilhantes a olho nu — grupo visual do CelesTrak", - "COMMS": "COMS", - "Broadband constellation shell — shown only in DENSE mode": "Malha de constelação de banda larga — exibida só no modo DENSO", + "COMMS": "TELECOM", + "Broadband constellation shell — shown only in DENSE mode": "Camada orbital da constelação de banda larga — exibida só no modo DENSO", "FISHING": "PESCA", "TOWING": "REBOQUE", "DREDGER": "DRAGA", @@ -54,6 +295,10 @@ "CARGO": "CARGUEIRO", "TANKER": "PETROLEIRO", "OTHER": "OUTROS", + "Included in bundle": "Incluído no pacote", + "Missing bundle file — reimport its bundle": "Arquivo ausente no pacote — importe o pacote de novo", + "Source configured; file checked when loaded": "Fonte configurada; o arquivo será verificado ao carregar", + "Source unavailable": "Fonte indisponível", "ENVIRONMENTAL": "AMBIENTAL", "EARTH WATCH": "VIGIA DA TERRA", "ACTIVE EVENTS": "EVENTOS ATIVOS", @@ -65,42 +310,182 @@ "Working…": "Processando…", "Could not open that mission{detail}. Retry or explore manually.": "Não foi possível abrir essa missão{detail}. Tente novamente ou explore manualmente.", "This browser is blocking storage, so that could not be saved.": "Este navegador está bloqueando o armazenamento, então não foi possível salvar.", + "NORMAL": "NORMAL", "CRT": "CRT", "NVG": "NVG", "FLIR": "FLIR", + "ANIME": "ANIME", + "NOIR": "NOIR", "SNOW": "NEVE", + "ARCTIC": "ÁRTICO", + "ANTARCTIC": "ANTÁRTICO", + "NORTH AMERICA": "AMÉRICA DO NORTE", + "SOUTH AMERICA": "AMÉRICA DO SUL", + "EUROPE": "EUROPA", + "AFRICA": "ÁFRICA", + "ASIA": "ÁSIA", + "OCEANIA": "OCEANIA", + "NORTHERN OCEANIC GRID": "GRADE OCEÂNICA NORTE", + "SOUTHERN OCEANIC GRID": "GRADE OCEÂNICA SUL", "LOADING": "CARREGANDO", "DEGRADED": "DEGRADADO", "STALE": "DESATUALIZADO", "PARTIAL": "PARCIAL", "FALLBACK": "ALTERNATIVO", + "{state} {layers}": "{state}: {layers}", + "view band|STREET": "RUA", + "view band|CITY": "CIDADE", + "view band|METRO": "METRÓPOLE", + "view band|REGIONAL": "REGIÃO", + "view band|GLOBAL": "GLOBAL", "SUMMARY": "RESUMO", "Awaiting telemetry...": "Aguardando telemetria...", "REC": "GRAV", "AIS: --": "AIS: --", + "N/A": "N/D", + "{mode} {band} {locality} | {region} | ALT {alt} | WINDOW {window} | SUN {sun}° | ONA {ona}° | {zone}": "{mode} · {band} · {locality} | {region} | ALT {alt} | JANELA {window} | SOL {sun}° | ONA {ona}° | {zone}", + "NEAR {poi} ({city}) {distance}": "PERTO DE {poi} ({city}) {distance}", + "SECTOR {lat} {lon}": "SETOR {lat} {lon}", + "hemisphere|N": "N", + "hemisphere|S": "S", + "hemisphere|E": "L", + "hemisphere|W": "O", "POWER UP · {count} KEYS WAITING": { "one": "ATIVAR · {count} CHAVE PENDENTE", - "many": "ATIVAR · {count} CHAVES PENDENTES", + "many": "ATIVAR · {count} DE CHAVES PENDENTES", "other": "ATIVAR · {count} CHAVES PENDENTES" }, "POWERED UP": "ATIVADO", + "Provider Settings does not answer proxied requests": "Configurações de provedores não responde a requisições via proxy", + "Provider Settings is disabled while sharing is enabled": "O painel \"Configurações de provedores\" fica desativado enquanto o compartilhamento estiver ativo", + "Provider Settings answers only the machine running the server": "Configurações de provedores só responde à máquina que executa o servidor", + "Provider Settings answers only local hostnames": "Configurações de provedores só responde a nomes de host locais", + "Provider Settings requires an exact local Origin": "Configurações de provedores exige um Origin local exato", + "Unrecognized Origin refused": "Origin não reconhecido: requisição recusada", + "Cross-origin requests are refused": "Requisições de outra origem são recusadas", + "Content-Type must be application/json": "Content-Type deve ser application/json", + "Method not allowed": "Método não permitido", + "Request too large": "Requisição grande demais", + "Invalid JSON": "JSON inválido", + "Body must be a JSON object of {ENV_VAR: value}": "O corpo deve ser um objeto JSON de {ENV_VAR: value}", + "No keys provided": "Nenhuma chave enviada", + "At most {limit} keys per save": "No máximo {limit} chaves por salvamento", + "Unknown key: {name}": "Chave desconhecida: {name}", + "{name} must be a string": "{name}: o valor deve ser uma string", + "{name} is empty": "{name}: o valor está vazio", + "{name} is longer than any real key ({limit} max)": "{name}: o valor é mais longo que qualquer chave real (máximo {limit})", + "{name} may only contain printable characters with no spaces": "{name}: só são aceitos caracteres imprimíveis, sem espaços", + "{name} contains a character that is not valid in a key (#, quotes, $, \\, or backtick)": "{name}: há um caractere inválido para uma chave (#, aspas, $, \\ ou crase)", + "{name} is configured outside Provider Settings and can only be changed where it was set": "{name} foi configurada fora de Configurações de provedores e só pode ser alterada onde foi definida", + "The key was not saved: could not restrict the credential file to your account; nothing was saved": "A chave não foi salva: não foi possível restringir o arquivo de credenciais à sua conta; nada foi salvo", + "The key was not saved: the existing configuration could not be read, so nothing was changed": "A chave não foi salva: não foi possível ler a configuração existente, então nada foi alterado", + "Could not write the {store} store": "Não foi possível gravar no armazenamento {store}", "Save failed ({status}).": "Falha ao salvar ({status}).", + "OAuth check failed: {detail}": "Falha ao verificar o OAuth: {detail}", + "Could not check ChatGPT sign-in. Try again.": "Não foi possível verificar o login do ChatGPT. Tente novamente.", + "VOICE AUTH · CHATGPT OAUTH": "AUTENTICAÇÃO DE VOZ · OAUTH DO CHATGPT", + "VOICE AUTH · API KEY": "AUTENTICAÇÃO DE VOZ · CHAVE DE API", + "USE API KEY": "USAR CHAVE DE API", + "USE CHATGPT OAUTH": "USAR OAUTH DO CHATGPT", + "Use OPENAI_API_KEY for the next cloud voice session": "Usar OPENAI_API_KEY na próxima sessão de voz na nuvem", + "Use the signed-in local ChatGPT/Codex OAuth session for the next cloud voice session": "Usar a sessão OAuth local do ChatGPT/Codex já conectada na próxima sessão de voz na nuvem", + "Metered — a billing-enabled account": "Cobrança por uso — uma conta com faturamento ativado", + "Optional paid token — public access works without one": "Token pago opcional — o acesso público funciona sem ele", + "Free key — register, paste, done": "Chave gratuita — cadastre-se, cole e pronto", + "browser-side": "no navegador", + "This key runs in the browser by design — restrict it at the provider (see SECURITY.md)": "Esta chave roda no navegador por design — restrinja-a no provedor (veja SECURITY.md)", + "configured externally": "configurada externamente", + "Supplied by your environment, Keychain, or launcher — change it where it was set": "Fornecida pelo seu ambiente, Keychain ou inicializador — altere-a onde foi definida", + "MANAGE ↗": "GERENCIAR ↗", + "GET KEY ↗": "OBTER CHAVE ↗", + "{envVar} saved — paste to replace": "{envVar} salva — cole outra para substituir", + "paste {envVar}": "cole {envVar}", "REMOVE": "REMOVER", "Remove {title} from this app's saved keys": "Remover {title} das chaves salvas deste app", + "unsaved provider keys": "chaves de provedores não salvas", + "Project keys: {status}": "Chaves do projeto: {status}", "your app configuration": "sua configuração do app", "your local .env": "seu .env local", "Saving…": "Salvando…", "Save failed: {detail}": "Falha ao salvar: {detail}", "Paste at least one key first.": "Cole pelo menos uma chave primeiro.", "Saved to {store}. Restarting — this page reloads itself.": "Salvo em {store}. Reiniciando — esta página recarrega sozinha.", + "Cloud voice will use OPENAI_API_KEY on the next session.": "A voz na nuvem usará OPENAI_API_KEY na próxima sessão.", + "Checking local ChatGPT OAuth sign-in…": "Verificando o login OAuth local do ChatGPT…", + "Could not check ChatGPT sign-in.": "Não foi possível verificar o login do ChatGPT.", + "ChatGPT OAuth selected for cloud voice. Your API key stays saved and available.": "OAuth do ChatGPT selecionado para a voz na nuvem. Sua chave de API continua salva e disponível.", + "ChatGPT sign-in expired. Opening sign-in again…": "O login do ChatGPT expirou. Abrindo o login de novo…", + "Opening ChatGPT sign-in in your browser…": "Abrindo o login do ChatGPT no seu navegador…", + "Could not start ChatGPT sign-in on this machine.": "Não foi possível iniciar o login do ChatGPT nesta máquina.", + "Finish ChatGPT sign-in in the browser. Waiting for it to complete…": "Conclua o login do ChatGPT no navegador. Aguardando a conclusão…", + "ChatGPT sign-in timed out. Click {button} to try again.": "O tempo do login do ChatGPT esgotou. Clique em \"{button}\" para tentar novamente.", + "ChatGPT sign-in complete. OAuth will be used for the next cloud voice session.": "Login do ChatGPT concluído. O OAuth será usado na próxima sessão de voz na nuvem.", "Remove this key from your saved configuration?": "Remover esta chave da sua configuração salva?", "Removed from {store}. Restarting — this page reloads itself.": "Removido de {store}. Reiniciando — esta página recarrega sozinha.", - "Places context + Street View fallback; optional separate key": "Contexto de lugares + alternativa do Street View; chave separada opcional", + "The photorealistic 3D planet, place search + Street View": "O planeta 3D fotorrealista, busca de lugares + Street View", + "Places context + Street View fallback; optional separate key": "Contexto de lugares + Street View como alternativa; chave separada opcional", + "Voice control — API key or ChatGPT OAuth": "Controle por voz — chave de API ou OAuth do ChatGPT", + "Gemini Live voice control": "Controle por voz com Gemini Live", "Live ships, worldwide": "Navios ao vivo, no mundo todo", "Live active-fire detections": "Detecções de incêndios ativos ao vivo", - "Real live traffic (keyless runs a simulation)": "Trânsito real ao vivo (sem chave roda uma simulação)", - "Bing imagery map stacks + world terrain": "Pilhas de mapa com imagens Bing + relevo mundial", - "More flight-polling credits (anonymous works without)": "Mais créditos de consulta de voos (funciona sem, de forma anônima)", + "Real live traffic (keyless runs a simulation)": "Trânsito real ao vivo (sem chave, roda uma simulação)", + "Bing imagery map stacks + world terrain": "Pilhas de mapas com imagens do Bing + relevo mundial", + "More flight-polling credits (anonymous works without)": "Mais créditos de consulta de voos (o acesso anônimo funciona sem)", + "Street-level imagery and coverage in the Street Level layer. Free: register an app in the Mapillary developer dashboard and paste its Client Token": "Imagens e cobertura no nível da rua na camada \"Nível da rua\". Grátis: registre um app no painel de desenvolvedores do Mapillary e cole o token de cliente (Client Token)", + "Public space-missions access needs no key. Leave blank for standard use; paid tokens only raise request limits.": "O acesso público às missões espaciais não precisa de chave. Deixe em branco para o uso padrão; tokens pagos só aumentam os limites de requisições.", + "Air quality request failed": "Falha na requisição de qualidade do ar", + "No readings available": "Nenhuma leitura disponível", + "No current readings": "Sem leituras atuais", + "{count} stations reporting": { + "one": "{count} estação com dados", + "many": "{count} de estações com dados", + "other": "{count} estações com dados" + }, + "Highest air-quality readings in view": "Leituras de qualidade do ar mais altas na vista", + "Low": "Baixa", + "Low health risk": "Risco baixo para a saúde", + "Moderate": "Moderada", + "Moderate health risk": "Risco moderado para a saúde", + "High": "Alta", + "High health risk": "Risco alto para a saúde", + "Very High": "Muito alta", + "Very High health risk": "Risco muito alto para a saúde", + "Air quality": "Qualidade do ar", + "Canada only · ECCC AQHI network": "Só Canadá · rede AQHI do ECCC", + "ECCC request timed out": "A requisição ao ECCC excedeu o tempo limite", + "Malformed AQHI station response": "Resposta de estações AQHI malformada", + "No AQHI stations available": "Nenhuma estação AQHI disponível", + "Malformed AQHI observation response": "Resposta de observações AQHI malformada", + "Camera source temporarily unavailable": "Fonte de câmeras temporariamente indisponível", + "Mapped camera locations": "Locais de câmeras mapeadas", + "SHOW NEAREST": "MOSTRAR A MAIS PRÓXIMA", + "Stop following the current object before navigating to a camera": "Pare de seguir o objeto atual antes de ir até uma câmera", + "Move to the nearest loaded camera and show its details": "Ir até a câmera carregada mais próxima e mostrar seus detalhes", + "Camera badges": "Ícones de câmeras", + "Cyan cameras turn coral when selected. Wedges illustrate mapped direction, not measured coverage. Nearby cameras may be outside the screen.": "As câmeras ciano ficam coral quando selecionadas. As cunhas ilustram a direção mapeada, não a cobertura medida. Câmeras próximas podem estar fora da tela.", + "{count} nearby · {onScreen} on screen": { + "one": "{count} próxima · {onScreen} na tela", + "many": "{count} de câmeras próximas · {onScreen} na tela", + "other": "{count} próximas · {onScreen} na tela" + }, + "{count} nearby": { + "one": "{count} próxima", + "many": "{count} de câmeras próximas", + "other": "{count} próximas" + }, + "retrying mapped ALPR cameras": "tentando de novo as câmeras ALPR mapeadas", + "loading mapped ALPR cameras": "carregando câmeras ALPR mapeadas", + "No ALPR data for this area — US and Canada only": "Sem dados ALPR para esta área — só EUA e Canadá", + "Zoom in to load mapped cameras": "Aproxime o zoom para carregar as câmeras mapeadas", + "Showing cached locations": "Mostrando locais em cache", + "Coverage limited — zoom in": "Cobertura limitada — aproxime o zoom", + "No ALPR data for this area": "Sem dados ALPR para esta área", + "None on screen — nearby cameras are outside the view": "Nenhuma na tela — as câmeras próximas estão fora da vista", + "ALPR camera": "Câmera ALPR", + "Camera coverage unavailable": "Cobertura de câmeras indisponível", + "OpenStreetMap · community mapped": "OpenStreetMap · mapeado pela comunidade", + "Overpass returned an incomplete camera response": "O Overpass retornou uma resposta de câmeras incompleta", + "At least {count}": "Pelo menos {count}", "CONTEXT READY": "CONTEXTO PRONTO", "GLOBAL CONTEXT OFF": "CONTEXTO GLOBAL DESLIGADO", "SELECT A FLIGHT, VESSEL, OR MAPPED INSTALLATION": "SELECIONE UM VOO, EMBARCAÇÃO OU INSTALAÇÃO MAPEADA", @@ -112,11 +497,17 @@ "PREVIOUS": "ANTERIOR", "FOCUS": "FOCAR", "Next — nearest unvisited contact in the 250 km window": "Próximo — contato não visitado mais próximo na janela de 250 km", - "NEXT": "PRÓX", + "NEXT": "PRÓX.", + "Named areas ({n})": "Áreas com nome ({n})", + "{distance} FLIGHT / VESSEL WINDOW": "JANELA DE VOOS / EMBARCAÇÕES DE {distance}", "Open-source mapped/observed context. Missing broadcasts, unloaded map areas, or unmapped sites are not evidence of absence.": "Contexto mapeado/observado de fontes abertas. Transmissões ausentes, áreas de mapa não carregadas ou locais não mapeados não são prova de ausência.", + "mapped matches within {km} km of the subject": "correspondências mapeadas a até {km} km do alvo", + "none mapped within {km} km; not a complete 250 km survey": "nenhuma mapeada a até {km} km; não é uma varredura completa de 250 km", + "mapped matches from the loaded viewport": "correspondências mapeadas na vista carregada", + "viewport feed is not a complete 250 km survey": "os dados da vista não são uma varredura completa de 250 km", "HDG {value}°": "HDG {value}°", - "BRG {value}°": "RMO {value}°", - "BRG —": "RMO —", + "BRG {value}°": "BRG {value}°", + "BRG —": "BRG —", "CRS {value}°": "CRS {value}°", "CURRENT VIEWPORT ONLY": "SÓ A VISTA ATUAL", "WITHIN {km} KM": "EM ATÉ {km} KM", @@ -126,6 +517,7 @@ "Mapped installations": "Instalações mapeadas", "syncing {count} city feeds...": "sincronizando {count} feeds de cidades...", "scanning nearby systems...": "buscando sistemas próximos...", + "GBFS fetch error": "erro ao obter dados GBFS", "Station {id}": "Estação {id}", "Station": "Estação", "🚲 {bikes} avail · {docks} docks · {capacity} cap": "🚲 {bikes} disp · {docks} docas · {capacity} cap", @@ -136,18 +528,186 @@ "{count} CAMERAS STANDING BY · NO CAMERA SELECTED · CLICK A CAMERA TO ACTIVATE": "{count} CÂMERAS EM ESPERA · NENHUMA CÂMERA SELECIONADA · CLIQUE EM UMA CÂMERA PARA ATIVAR", "No cameras available in catalog.": "Nenhuma câmera disponível no catálogo.", "{city} CCTV": "CCTV {city}", + "FOV {value}° (DATASHEET)": "FOV {value}° (FICHA TÉCNICA)", "FOV {value}°": "FOV {value}°", - "COVERAGE {value}km²": "COBERTURA {value}km²", - "OVERLAP {count} cams": "SOBREPOSIÇÃO {count} câm", + "SPEC FOV {span}° (CAPABILITY)": "FOV DA FICHA {span}° (CAPACIDADE)", + "COVERAGE {value}km²": "COBERTURA {value} km²", + "OVERLAP {count} cams": "SOBREPOSIÇÃO {count} câm.", "ISOLATED VIEW": "VISTA ISOLADA", - "PROJ MONITOR": "PROJ MONITOR", - "PROJ OFF": "PROJ DESLIG.", - "VIEWSHED": "VIEWSHED", + "PROJ MONITOR": "PROJ. MONITOR", + "PROJ OFF": "PROJ. DESLIG.", + "VIEWSHED": "ÁREA VISÍVEL", "CAL {value}": "CAL {value}", "SRC {value}": "FONTE {value}", "{value} CONTEXT": "CONTEXTO {value}", + "{spec} · SPECS: CCTV-DATABASE.COM": "{spec} · ESPECIFICAÇÕES: CCTV-DATABASE.COM", + "Atlantic and eastern/central North Pacific; not worldwide cyclone coverage.": "Atlântico e Pacífico Norte oriental/central; não é uma cobertura mundial de ciclones.", + "Cyclone advisories unavailable": "Boletins de ciclones indisponíveis", + "Cyclone data unavailable": "Dados de ciclones indisponíveis", + "Potential tropical cyclone": "Potencial ciclone tropical", + "Post-tropical cyclone": "Ciclone pós-tropical", + "Hurricane": "Furacão", + "Tropical storm": "Tempestade tropical", + "Tropical depression": "Depressão tropical", + "Subtropical storm": "Tempestade subtropical", + "Subtropical depression": "Depressão subtropical", + "Track and cone match this advisory": "A trajetória e o cone correspondem a este boletim", + "Track/cone awaiting advisory {number}": "Trajetória/cone aguardando o boletim {number}", + "Track/cone unavailable": "Trajetória/cone indisponível", + "Cached advisory · stale source": "Boletim em cache · fonte desatualizada", + "Loading advisories…": "Carregando boletins…", + "{count} active storms": { + "one": "{count} ciclone ativo", + "many": "{count} de ciclones ativos", + "other": "{count} ciclones ativos" + }, + "Position as of {time}": "Posição às {time}", + "Maximum sustained wind: {wind} · Pressure: {pressure}": "Vento máximo sustentado: {wind} · Pressão: {pressure}", + "{name} · {classification} · Advisory {number} · issued {time}": "{name} · {classification} · Boletim {number} · emitido {time}", + "No active NHC/CPHC systems": "Nenhum sistema ativo do NHC/CPHC", + "Advisories unavailable": "Boletins indisponíveis", + "Cyclones · NHC / CPHC": "Ciclones · NHC / CPHC", + "Atlantic · E/C Pacific": "Atlântico · Pacífico L/C", + "{storms} · {name} selected": "{storms} · {name} selecionado", + "Official advisory ↗": "Boletim oficial ↗", + "Active NHC and CPHC cyclone advisories": "Boletins de ciclones ativos do NHC e do CPHC", + "Wind unavailable": "Vento indisponível", + "Advisory center / forecast track": "Centro do ciclone no boletim / trajetória prevista", + "Center-track uncertainty cone": "Cone de incerteza da trajetória do centro", + "Select a storm on the map, or choose a storm in the list to select it and move the camera. Click empty map space to clear the selection. NOAA NHC/CPHC advisory context. The cone describes forecast center-track uncertainty, not storm size or the full hazard area. Forecast point labels are source lead hours, not times computed from advisory issuance. Geometry follows the surface; height is not weather altitude. Consult the official advisory.": "Selecione um ciclone no mapa ou escolha um na lista para selecioná-lo e mover a câmera. Clique em um espaço vazio do mapa para limpar a seleção. Contexto dos boletins NOAA NHC/CPHC. O cone descreve a incerteza da trajetória prevista do centro, não o tamanho do ciclone nem toda a área de risco. Os rótulos dos pontos de previsão são horas de antecedência da fonte, não horários calculados a partir da emissão do boletim. A geometria acompanha a superfície; a altura não é altitude meteorológica. Consulte o boletim oficial.", + "DRIVE": "CARRO", + "Drive": "De carro", + "WALK": "A PÉ", + "Walk": "A pé", + "BIKE": "BIKE", + "Bike": "De bicicleta", + "rate limited": "limite de requisições atingido", + "routing service is rate limited": "o serviço de rotas atingiu o limite de requisições", + "route leg too long": "trecho da rota longo demais", + "route too long": "rota longa demais", + "{error} — try again in a moment": "{error} — tente novamente em instantes", + "Routing is rate limited — try again in a moment": "O limite de requisições de rotas foi atingido — tente novamente em instantes", + "Routing unavailable (HTTP {status})": "Rotas indisponíveis (HTTP {status})", + "Routing unavailable": "Rotas indisponíveis", + "direction|left": "à esquerda", + "direction|right": "à direita", + "direction|slightly left": "levemente à esquerda", + "direction|slightly right": "levemente à direita", + "direction|sharply left": "acentuadamente à esquerda", + "direction|sharply right": "acentuadamente à direita", + "direction|straight": "em frente", + "direction|around": "no sentido contrário", + "fork direction|left": "à esquerda", + "fork direction|right": "à direita", + "fork direction|slightly left": "levemente à esquerda", + "fork direction|slightly right": "levemente à direita", + "fork direction|sharply left": "bem à esquerda", + "fork direction|sharply right": "bem à direita", + "fork direction|straight": "em frente", + "lane direction|left": "da esquerda", + "lane direction|right": "da direita", + "lane direction|slightly left": "da esquerda", + "lane direction|slightly right": "da direita", + "lane direction|sharply left": "da extrema esquerda", + "lane direction|sharply right": "da extrema direita", + "lane direction|straight": "central", + "ordinal|{number}st": "{number}ª", + "ordinal|{number}nd": "{number}ª", + "ordinal|{number}rd": "{number}ª", + "ordinal|{number}th": "{number}ª", + "Head out on {road}": "Siga por {road}", + "Head out": "Inicie o trajeto", + "Arrive at your destination, on the left": "Seu destino está à esquerda", + "Arrive at your destination, on the right": "Seu destino está à direita", + "Arrive at your destination": "Você chegou ao seu destino", + "Make a U-turn onto {road}": "Faça o retorno para {road}", + "Make a U-turn": "Faça o retorno", + "Continue straight onto {road}": "Siga em frente por {road}", + "Continue straight": "Siga em frente", + "Turn {direction} onto {road}": "Vire {direction} em {road}", + "Turn {direction}": "Vire {direction}", + "Turn onto {road}": "Vire em {road}", + "maneuver|Turn": "Vire", + "Continue {direction} onto {road}": "Siga {direction} por {road}", + "Continue {direction}": "Siga {direction}", + "At the end of the road, turn {direction} onto {road}": "No fim da via, vire {direction} em {road}", + "At the end of the road, turn {direction}": "No fim da via, vire {direction}", + "At the end of the road, continue onto {road}": "No fim da via, siga por {road}", + "At the end of the road, continue": "No fim da via, siga", + "Keep {direction} at the fork onto {road}": "Na bifurcação, mantenha-se {direction} em direção a {road}", + "Keep {direction} at the fork": "Na bifurcação, mantenha-se {direction}", + "Continue at the fork onto {road}": "Na bifurcação, siga por {road}", + "Continue at the fork": "Na bifurcação, siga", + "Merge {direction} onto {road}": "Entre {direction} em {road}", + "Merge {direction}": "Entre na via {direction}", + "Merge onto {road}": "Entre em {road}", + "maneuver|Merge": "Entre na via", + "Take the ramp on the {direction} onto {road}": "Pegue a rampa {direction} para {road}", + "Take the ramp on the {direction}": "Pegue a rampa {direction}", + "Take the ramp {direction} onto {road}": "Pegue a rampa {direction} para {road}", + "Take the ramp {direction}": "Pegue a rampa {direction}", + "Take the ramp onto {road}": "Pegue a rampa para {road}", + "Take the ramp": "Pegue a rampa", + "Take the exit on the {direction} onto {road}": "Pegue a saída {direction} para {road}", + "Take the exit on the {direction}": "Pegue a saída {direction}", + "Take the exit {direction} onto {road}": "Pegue a saída {direction} para {road}", + "Take the exit {direction}": "Pegue a saída {direction}", + "Take the exit onto {road}": "Pegue a saída para {road}", + "Take the exit": "Pegue a saída", + "At the roundabout, take the {exit} exit onto {road}": "Na rotatória, pegue a {exit} saída para {road}", + "At the roundabout, take the {exit} exit": "Na rotatória, pegue a {exit} saída", + "Enter the roundabout onto {road}": "Entre na rotatória para {road}", + "Enter the roundabout": "Entre na rotatória", + "At the roundabout, turn {direction} onto {road}": "Na rotatória, vire {direction} em {road}", + "At the roundabout, turn {direction}": "Na rotatória, vire {direction}", + "At the roundabout, continue onto {road}": "Na rotatória, siga por {road}", + "At the roundabout, continue": "Na rotatória, siga", + "Exit the roundabout onto {road}": "Saia da rotatória para {road}", + "Exit the roundabout": "Saia da rotatória", + "Use the {direction} lane onto {road}": "Use a faixa {direction} para {road}", + "Use the {direction} lane": "Use a faixa {direction}", + "Continue onto {road}": "Siga por {road}", + "maneuver|Continue": "Siga", + "{mode} — reroute for {modeLower}": "{mode} — recalcular a rota {modeLower}", + "CLICK MAP": "CLIQUE NO MAPA", + "SET A": "DEFINIR A", + "Click a spot on the globe to place A (click again to cancel)": "Clique em um ponto do globo para colocar A (clique de novo para cancelar)", + "Then click the globe to place the start": "Depois clique no globo para colocar a partida", + "SET B": "DEFINIR B", + "Click a spot on the globe to place B (click again to cancel)": "Clique em um ponto do globo para colocar B (clique de novo para cancelar)", + "Then click the globe to place the destination": "Depois clique no globo para colocar o destino", + "Swap A and B": "Trocar A e B", + "FLY ···": "VOAR ···", + "FLYING": "VOANDO", + "FLY": "VOAR", + "Fly the camera along the route": "Voar com a câmera ao longo da rota", + "Place A and B first": "Coloque A e B primeiro", + "action|CLEAR": "LIMPAR", + "Remove the route and both markers": "Remover a rota e os dois marcadores", + "press Escape twice to leave Draw": "pressione Esc duas vezes para sair de Desenho", + "{name} is active — turn {name} off, then set {endpoint}": "{name} está ativo — desative {name} e depois defina {endpoint}", + "{name} is active — {leave}, then set {endpoint}": "{name} está ativo — {leave} e depois defina {endpoint}", + "Only the first {count} turns of this route are shown": "Só as primeiras {count} conversões desta rota são mostradas", + "Turn-by-turn directions": "Instruções passo a passo", + "Another map tool is using clicks — close it, then SET A again": "Outra ferramenta do mapa está usando os cliques — feche-a e pressione DEFINIR A de novo", + "Routing…": "Calculando a rota…", + "No route found": "Nenhuma rota encontrada", + "{distance} · {duration} · {mode} · first {count} turns": "{distance} · {duration} · {mode} · primeiras {count} conversões", + "{distance} · {duration} · {mode}": "{distance} · {duration} · {mode}", + "Click the globe to place {endpoint}": "Clique no globo para colocar {endpoint}", + "SET B, then click the globe": "Pressione DEFINIR B e depois clique no globo", + "SET A, then click the globe": "Pressione DEFINIR A e depois clique no globo", + "Step {step} of {total} · then {leg}": "Passo {step} de {total} · depois {leg}", + "Step {step} of {total}": "Passo {step} de {total}", + "Then: {instruction}": "Depois: {instruction}", + "No route found between A and B": "Nenhuma rota encontrada entre A e B", + "Routing failed: {error}": "Falha ao calcular a rota: {error}", + "Routing timed out": "O cálculo da rota excedeu o tempo limite", + "Routing unavailable — no response from the routing service": "Rotas indisponíveis — sem resposta do serviço de rotas", + "Earthquake source unavailable": "Fonte de terremotos indisponível", "Focus fire detection {title}, {details}": "Focar detecção de incêndio {title}, {details}", - "{value} conf": "{value} conf", + "live feed unavailable": "feed ao vivo indisponível", + "{value} conf": "confiança {value}", "{value} ago": "há {value}", "sensor n/a": "sensor n/d", "FIRE · {frp} MW": "INCÊNDIO · {frp} MW", @@ -157,17 +717,93 @@ "FIRES": "INCÊNDIOS", "max {value} MW": "máx {value} MW", "new {value}": "novo {value}", + "{value}°N": "{value}°N", + "{value}°S": "{value}°S", + "{value}°E": "{value}°L", + "{value}°W": "{value}°O", "just now": "agora mesmo", - "<1m ago": "há <1min", - "{count}m ago": "há {count}min", + "<1m ago": "há <1 min", + "{count}m ago": "há {count} min", "{count}h ago": "há {count}h", + "fire confidence|high": "alta", + "fire confidence|nominal": "nominal", + "fire confidence|low": "baixa", + "age|<1h": "<1 h", + "age|{count}h": "{count} h", + "age|{count}d": "{count} d", "STALE · cached {age}": "DESATUALIZADO · em cache {age}", "refreshing...": "atualizando...", "loading...": "carregando...", "KEY REQUIRED": "CHAVE NECESSÁRIA", "LIVE · updated {age}": "AO VIVO · atualizado {age}", + "Source snapshot time unavailable": "Horário do snapshot da fonte indisponível", + "Live data unavailable": "Dados ao vivo indisponíveis", + "Intel Picture": "Panorama de inteligência", + "Kinetic 30d": "Cinético 30 d", + "Border Crisis": "Crise na fronteira", + "Iran Picture": "Panorama do Irã", + "Iran Kinetic": "Irã cinético", + "Yemen FLOT": "FLOT do Iêmen", + "Latest Drop": "Última publicação", + "GhostMaps file could not be read": "Não foi possível ler o arquivo do GhostMaps", + "{count} source links ↗ · click card to open the first": { + "one": "{count} link da fonte ↗ · clique no cartão para abrir", + "many": "{count} de links das fontes ↗ · clique no cartão para abrir o primeiro", + "other": "{count} links das fontes ↗ · clique no cartão para abrir o primeiro" + }, + "S2 · {name}": "S2 · {name}", + "Report": "Relatório", + "Open the source for {title}": "Abrir a fonte de {title}", + "GhostMaps catalog unavailable": "Catálogo do GhostMaps indisponível", + "LIVE · GitHub {commit} · {message} · checked every {seconds}s": "AO VIVO · GitHub {commit} · {message} · verificado a cada {seconds} s", + "GitHub {commit} · {message} · reconnecting for live updates": "GitHub {commit} · {message} · reconectando para receber atualizações ao vivo", + "Connecting to the S2 GhostMaps repository…": "Conectando ao repositório S2 GhostMaps…", + "{count} placemarks": { + "one": "{count} marcador", + "many": "{count} de marcadores", + "other": "{count} marcadores" + }, + "S2 Underground publishes these KMZ products to GitHub. New uploads are detected within seconds and replace the previous edition automatically. Click a marker for its report.": "O S2 Underground publica estes produtos KMZ no GitHub. Novos envios são detectados em segundos e substituem a edição anterior automaticamente. Clique em um marcador para ver o relatório.", + "Malformed GhostMaps catalog": "Catálogo do GhostMaps malformado", + "Low-accuracy score < 2%": "Índice de baixa precisão < 2%", + "Low-accuracy score 2–10%": "Índice de baixa precisão 2–10%", + "Low-accuracy score > 10%": "Índice de baixa precisão > 10%", + "GNSS integrity source unavailable": "Fonte de integridade GNSS indisponível", + "Regional sample · 250 nm radius · cells from visited views over 30 min": "Amostra regional · raio de 250 NM · células das vistas visitadas em 30 min", + "Retrying automatically at {time} UTC": "Nova tentativa automática às {time} UTC", + "Retrying automatically after provider cooldown": "Nova tentativa automática após a pausa do provedor", + "Updates automatically after pan or zoom and once a minute. The public feed covers a 250-nautical-mile circle around the view centre; zooming out does not make it a worldwide snapshot. Blank cells are outside sampled coverage or have insufficient observations.": "Atualiza automaticamente após mover ou dar zoom e uma vez por minuto. O feed público cobre um círculo de 250 milhas náuticas ao redor do centro da vista; afastar o zoom não o transforma em um snapshot mundial. Células vazias estão fora da cobertura amostrada ou não têm observações suficientes.", + "Low-accuracy score = 100 × max(0, bad − 1) / total: one aircraft is discounted, so this is not the raw share. Cells need {aircraft} aircraft over {minutes} minutes. Navigation-integrity anomalies are not a detection of jamming or spoofing.": "Índice de baixa precisão = 100 × max(0, ruins − 1) / total: uma aeronave é descontada, então não é a proporção bruta. Cada célula precisa de {aircraft} aeronaves em {minutes} minutos. Anomalias de integridade de navegação não são detecção de interferência (jamming) nem de falsificação (spoofing).", + "GNSS snapshot needs a view anchor": "O snapshot GNSS precisa de um ponto de referência da vista", + "GNSS feed rate limited (HTTP 429)": "Feed GNSS: limite de requisições atingido (HTTP 429)", + "Malformed GNSS integrity snapshot": "Snapshot de integridade GNSS malformado", + "GNSS integrity snapshot has no observation time": "O snapshot de integridade GNSS não tem horário de observação", + "installation class|AIRFIELD": "AERÓDROMO", + "installation class|NAVAL BASE": "BASE NAVAL", + "installation class|RANGE": "CAMPO DE TIRO", + "installation class|MILITARY LAND": "TERRENO MILITAR", + "installation class|BASE": "BASE", + "installation class|BARRACKS": "QUARTEL", + "installation class|TRAINING AREA": "ÁREA DE TREINAMENTO", + "installation class|PLACES CANDIDATE": "DO GOOGLE PLACES", + "installation class|INSTALLATION": "INSTALAÇÃO", + "No mapped sites within {km} km of the contact": "Nenhum local mapeado a até {km} km do contato", + "{count} mapped sites within {km} km of the contact": { + "one": "{count} local mapeado a até {km} km do contato", + "many": "{count} de locais mapeados a até {km} km do contato", + "other": "{count} locais mapeados a até {km} km do contato" + }, + "No mapped sites in view": "Nenhum local mapeado na vista", + "{count} mapped sites in view": { + "one": "{count} local mapeado na vista", + "many": "{count} de locais mapeados na vista", + "other": "{count} locais mapeados na vista" + }, "loading mapped installation context": "carregando contexto da instalação mapeada", + "Too many mapped sites in view to list them all": "Há locais mapeados demais na vista para listar todos", + "Installation context unavailable": "Contexto de instalações indisponível", "MAPPED INSTALLATION": "INSTALAÇÃO MAPEADA", + "Unknown": "Desconhecido", "LAUNCH SITE · {site}": "LOCAL DE LANÇAMENTO · {site}", "LAUNCH SITE": "LOCAL DE LANÇAMENTO", "T−{time} · {mission}": "T−{time} · {mission}", @@ -181,7 +817,7 @@ "UNSPECIFIED": "NÃO ESPECIFICADO", "+{count} additional payload records": "+{count} registros de carga útil adicionais", "PAYLOAD DATA UNAVAILABLE": "DADOS DA CARGA ÚTIL INDISPONÍVEIS", - "{value} KM DOWNRANGE": "{value} KM DOWNRANGE", + "{value} KM DOWNRANGE": "{value} KM DE PERCURSO", "POSITION UNAVAILABLE": "POSIÇÃO INDISPONÍVEL", "FLIGHT {count}": "VOO {count}", "REUSED": "REUTILIZADO", @@ -193,6 +829,7 @@ "Select {mission}": "Selecionar {mission}", "{value} KM": "{value} KM", "{value} KM/S": "{value} KM/S", + "Selected Space Mission": "Missão espacial selecionada", "SELECTED SPACE MISSION": "MISSÃO ESPACIAL SELECIONADA", "Show all missions": "Mostrar todas as missões", "Deselect mission": "Desmarcar missão", @@ -216,12 +853,12 @@ "Replay speed multiplier": "Multiplicador de velocidade da reprise", "REPLAY ASCENT": "REPRISE DA SUBIDA", "Previous mission": "Missão anterior", - "PREV": "ANT", + "PREV": "ANT.", "Next mission": "Próxima missão", "SHOW ALL / DESELECT": "MOSTRAR TODAS / DESMARCAR", "Pause replay": "Pausar reprise", "Cancel replay": "Cancelar reprise", - "EST. DOWNRANGE": "DOWNRANGE EST.", + "EST. DOWNRANGE": "DIST. ESTIMADA", "PLANNED · ": "PLANEJADO · ", "SUPPLIED TRAJECTORY POINTS": "PONTOS DE TRAJETÓRIA FORNECIDOS", "RECONSTRUCTED ESTIMATE": "ESTIMATIVA RECONSTRUÍDA", @@ -233,23 +870,105 @@ "Ascent replay": "Reprise da subida", "Orbit replay": "Reprise da órbita", ", paused": ", pausado", + "Malformed launch snapshot": "Snapshot de lançamentos malformado", + "Heard by your receiver": "Captado pelo seu receptor", + "1090 MHz": "1090 MHz", + "978 MHz UAT": "978 MHz UAT", + "browser SDR": "SDR do navegador", + "decoder feed": "feed do decodificador", + "Your RTL-SDR receiver and decoder feed": "Seu receptor RTL-SDR e o feed do decodificador", + "Your decoder feed": "Seu feed do decodificador", + "Your RTL-SDR receiver": "Seu receptor RTL-SDR", + "NO CALLSIGN": "SEM INDICATIVO", + "ALT {altitude} FT · GS {speed} KT · TRK {track}": "ALT {altitude} FT · VEL. SOLO {speed} KT · TRK {track}", + "V/S {rate}": "VEL. VERT. {rate}", + "V/S {rate} FPM": "VEL. VERT. {rate} FT/MIN", + "POSITION {age}": "POSIÇÃO {age}", + "POSITION {seconds} S AGO": "POSIÇÃO HÁ {seconds} S", + "{count} MSGS": { + "one": "{count} MENSAGEM", + "many": "{count} DE MENSAGENS", + "other": "{count} MENSAGENS" + }, + "Decoder feeds": "Feeds do decodificador", + "WebUSB + decoder feeds": "WebUSB + feeds do decodificador", + "opening receiver": "abrindo o receptor", + "checking decoder feeds": "verificando os feeds do decodificador", + "WebUSB needs desktop Chrome or Edge": "O WebUSB requer Chrome ou Edge para desktop", + "connect a receiver in Radio": "conecte um receptor em Rádio", + "receiver is in FM mode": "o receptor está no modo FM", + "listening": "escutando", + "USB error": "erro de USB", "Alt unknown": "Alt. desconhecida", "Type unknown": "Tipo desconhecido", "Reg unknown": "Matrícula desconhecida", "Operator unknown": "Operador desconhecido", + "${amount}K": "US$ {amount} mil", + "${amount}M": "US$ {amount} mi", + "${amount}B": "US$ {amount} bi", + "fire cause|Human": "humana", + "fire cause|Natural": "natural", + "fire cause|Undetermined": "indeterminada", + "fire cause|Unknown": "desconhecida", + "fire behavior|Minimal": "atividade mínima", + "fire behavior|Moderate": "atividade moderada", + "fire behavior|Active": "atividade alta", + "fire behavior|Extreme": "atividade extrema", + "Type {level} Incident": "incidente tipo {level}", + "age|{count}m": "{count} min", + "{acres} ac": { + "one": "{acres} acre", + "many": "{acres} de acres", + "other": "{acres} acres" + }, + "{percent}% contained": "{percent}% contido", + "containment unknown": "contenção desconhecida", + "{cause} cause": "causa: {cause}", + "{personnel} personnel": { + "one": "{personnel} pessoa na equipe", + "many": "{personnel} de pessoas na equipe", + "other": "{personnel} pessoas na equipe" + }, + "{county} County": "condado de {county}", + "{cost} to date": "{cost} até agora", + "discovered {age} ago": "detectado há {age}", + "updated {age} ago": "atualizado há {age}", + "part of {complex}": "parte de {complex}", + "InciWeb ↗ · click card to open": "InciWeb ↗ · clique no cartão para abrir", + "FIRE · {name}": "INCÊNDIO · {name}", + "Unnamed incident": "Sem nome", + "Open {title} on InciWeb": "Abrir {title} no InciWeb", + "Perimeter source unavailable": "Fonte de perímetros indisponível", + "Not contained or unknown": "Não contido ou desconhecido", + "Under 50% contained": "Menos de 50% contido", + "50–99% contained": "50–99% contido", + "Fully contained": "Totalmente contido", + "Colour shows reported containment. Perimeters are simplified to about 100 m.": "A cor indica a contenção informada. Os perímetros são simplificados para cerca de 100 m.", + "Malformed perimeter snapshot": "Snapshot de perímetros malformado", + "radio tag|All": "Todas", "News": "Notícias", "Talk": "Conversa", "Weather / Emergency": "Clima / Emergência", - "Public Safety": "Segurança Pública", + "Public Safety": "Segurança pública", "Aviation / Marine": "Aviação / Marítimo", "Traffic / Transit": "Trânsito / Transporte", "Music": "Música", "Other": "Outras", + "Directory refresh degraded; showing the previous station catalog.": "A atualização do diretório foi parcial; mostrando o catálogo de estações anterior.", + "Radio directory coverage is degraded.": "O diretório de rádio está funcionando com falhas.", + "Directory refresh failed; showing the previous station catalog.": "A atualização do diretório falhou; mostrando o catálogo de estações anterior.", + "Radio directory is temporarily unavailable.": "O diretório de rádio está temporariamente indisponível.", + "radio|NEWS": "NOTÍCIAS", "radio|TALK": "CONVERSA", + "radio|WEATHER": "CLIMA", "radio|SAFETY": "SEGURANÇA", "radio|AIR / SEA": "AR / MAR", "radio|TRANSIT": "TRANSPORTE", "radio|MUSIC": "MÚSICA", + "radio|OTHER": "OUTRAS", + "Broadcaster stream is unavailable or blocked by the browser.": "O stream da emissora está indisponível ou foi bloqueado pelo navegador.", + "Playback requires a direct click or tap.": "A reprodução exige um clique ou toque direto.", + "Broadcaster stream could not be started.": "Não foi possível iniciar o stream da emissora.", "Alternative": "Alternativo", "Ambient": "Ambiente", "Blues": "Blues", @@ -275,14 +994,122 @@ "Techno": "Techno", "Trance": "Trance", "World": "Mundial", - "Add the full Starlink broadband shell (thousands of extra points)": "Adicionar toda a malha de banda larga Starlink (milhares de pontos extras)", - "Loading the Starlink shell…": "Carregando a malha Starlink…", + "overview": "visão geral", + "cloud unknown": "nebulosidade desconhecida", + "{percent}% scene cloud": "{percent}% de nuvens na cena", + "{min}–{max}% scene cloud": "{min}–{max}% de nuvens na cena", + "Comparison in use by another scene": "A comparação está em uso por outra cena", + "Esri map unavailable · no swipe": "Mapa Esri indisponível · sem comparação", + "Swipe needs a globe map": "A comparação precisa de um mapa de globo", + "Imagery stays on Esri · CLEAR to use Google 3D": "As imagens continuam no Esri · LIMPAR para usar o Google 3D", + "Imagery catalog unavailable": "Catálogo de imagens indisponível", + "Catalog truncated · a newer clear day may exist": "Catálogo truncado · pode haver um dia limpo mais recente", + "{label} catalog unavailable · {detail}": "Catálogo de {label} indisponível · {detail}", + "Daily overview for today may still be empty until the pass": "A visão geral diária de hoje pode continuar vazia até a passagem do satélite", + "Box and images cleared": "Área e imagens limpas", + "MORE DETAIL · 30 m": "MAIS DETALHE · 30 m", + "Sentinel-2 and Landsat via HLS, 30 m, every 2–6 days": "Sentinel-2 e Landsat via HLS, 30 m, a cada 2–6 dias", + "DAILY OVERVIEW · 250 m": "VISÃO GERAL DIÁRIA · 250 m", + "VIIRS daily mosaic, 250 m, follows broad changes; little detail under 25 km": "Mosaico diário do VIIRS, 250 m, acompanha mudanças amplas; pouco detalhe abaixo de 25 km", + "Sentinel-2": "Sentinel-2", + "Sentinel-2 via HLS": "Sentinel-2 via HLS", + "Landsat 8/9": "Landsat 8/9", + "Landsat 8/9 via HLS": "Landsat 8/9 via HLS", + "Daily overview": "Visão geral diária", + "Box edges must be finite": "Coordenadas da área inválidas", + "Longitudes must be within ±180°": "As longitudes devem estar dentro de ±180°", + "Select one side of the dateline": "Não cruze a linha internacional de data", + "Box must enclose an area": "A área deve delimitar uma superfície", + "Add the full Starlink broadband shell (thousands of extra points)": "Adicionar toda a camada orbital de banda larga da Starlink (milhares de pontos extras)", + "Loading the Starlink shell…": "Carregando a camada orbital da Starlink…", "Starlink {detail} — click to retry": "Starlink {detail} — clique para tentar novamente", "load failed": "falha ao carregar", - "Showing the full Starlink shell — click for the core catalog only": "Mostrando toda a malha Starlink — clique para ver só o catálogo principal", + "Showing the full Starlink shell — click for the core catalog only": "Mostrando toda a camada orbital da Starlink — clique para ver só o catálogo principal", "DENSE ···": "DENSO ···", "DENSE ✕": "DENSO ✕", "DENSE": "DENSO", + "CelesTrak unreachable": "CelesTrak inacessível", + "DOCKED · {name} · +{extra}": "ACOPLADO · {name} · +{extra}", + "DOCKED · {name}": "ACOPLADO · {name}", + "{name} needs the Google 3D map: choose it under MAP SOURCE": "{name} requer o mapa Google 3D: escolha-o em FONTE DO MAPA", + "zoom in to a street to open {name}": "aproxime o zoom de uma rua para abrir {name}", + "loading coverage...": "carregando cobertura...", + "No street-level imagery within {radius} m of that point": "Nenhuma imagem no nível da rua a até {radius} m desse ponto", + "No street-level imagery within {radius} m of the view centre": "Nenhuma imagem no nível da rua a até {radius} m do centro da vista", + "Zoom in to see street-level coverage": "Aproxime o zoom para ver a cobertura no nível da rua", + "Point the camera at the ground for street-level coverage": "Aponte a câmera para o chão para ver a cobertura no nível da rua", + "Coverage tile failed": "Falha ao carregar o bloco de cobertura", + "The photo could not be loaded": "Não foi possível carregar a foto", + "{name} photo. ← and → step along the sequence. On a 360° photo, drag or use Shift+← →, ↑ ↓ to look around, and + − to zoom": "Foto do {name}. ← e → avançam pela sequência. Em uma foto 360°, arraste ou use Shift+← →, ↑ ↓ para olhar ao redor, e + − para dar zoom", + "{name} street-level photo": "Foto no nível da rua do {name}", + "Previous photo in this sequence (←)": "Foto anterior da sequência (←)", + "Next photo in this sequence (→)": "Próxima foto da sequência (→)", + "Aim the middle of the view at a street to look for imagery there": "Aponte o centro da vista para uma rua para buscar imagens ali", + "KEY REJECTED": "CHAVE RECUSADA", + "GOOGLE_MAPS_API_KEY is not set": "GOOGLE_MAPS_API_KEY não está configurada", + "The Google Maps JavaScript API could not load": "Não foi possível carregar a API Maps JavaScript do Google", + "Google Street View": "Google Street View", + "GOOGLE STREET VIEW": "GOOGLE STREET VIEW", + "Google refused GOOGLE_MAPS_API_KEY for Street View — check that the Maps JavaScript API is enabled for it and this site is an allowed referrer": "O Google recusou a GOOGLE_MAPS_API_KEY para o Street View — verifique se a API Maps JavaScript está ativada para a chave e se este site é um referenciador permitido", + "Street View did not answer — check the network, and that the Maps JavaScript API is enabled for GOOGLE_MAPS_API_KEY": "O Street View não respondeu — verifique a rede e se a API Maps JavaScript está ativada para a GOOGLE_MAPS_API_KEY", + "click a street to open Street View": "clique em uma rua para abrir o Street View", + "Street View has no imagery for this place": "O Street View não tem imagens deste lugar", + "KartaView has no position for this photo": "O KartaView não tem a posição desta foto", + "The KartaView photo could not be loaded": "Não foi possível carregar a foto do KartaView", + "zoom in to see KartaView coverage": "aproxime o zoom para ver a cobertura do KartaView", + "no KartaView photos in view": "nenhuma foto do KartaView na vista", + "KartaView is rate-limiting requests — they resume on their own": "O KartaView está limitando as requisições — elas são retomadas sozinhas", + "KartaView’s photos here are archived and cannot be shown": "As fotos do KartaView aqui estão arquivadas e não podem ser exibidas", + "KartaView did not filter this area in time — move the map to ask again": "O KartaView não filtrou esta área a tempo — mova o mapa para pedir de novo", + "None of KartaView’s photos here pass the imagery filter": "Nenhuma foto do KartaView aqui passa no filtro de imagens", + "KartaView did not answer in time — try again": "O KartaView não respondeu a tempo — tente novamente", + "KartaView could not be reached — check the network": "Não foi possível acessar o KartaView — verifique a rede", + "KartaView sent an answer that could not be read": "O KartaView enviou uma resposta que não pôde ser lida", + "KartaView is rate-limiting requests": "O KartaView está limitando as requisições", + "KartaView sent too much data": "O KartaView enviou dados demais", + "KartaView is rate-limiting requests — try again in a moment": "O KartaView está limitando as requisições — tente novamente em instantes", + "KartaView has no such photo": "O KartaView não tem essa foto", + "Mapillary rejected MAPILLARY_CLIENT_TOKEN — replace it in Provider Settings": "O Mapillary recusou o MAPILLARY_CLIENT_TOKEN — substitua-o em Configurações de provedores", + "Coverage requests are being rate-limited — they resume on their own": "As requisições de cobertura estão sendo limitadas — elas são retomadas sozinhas", + "The Panoramax photo could not be loaded": "Não foi possível carregar a foto do Panoramax", + "Panoramax is busy — coverage resumes on its own": "O Panoramax está sobrecarregado — a cobertura volta sozinha", + "no Panoramax photos in view": "nenhuma foto do Panoramax na vista", + "no Panoramax photos here match the filters": "nenhuma foto do Panoramax aqui atende aos filtros", + "Panoramax sent a map tile that could not be read": "O Panoramax enviou um bloco do mapa que não pôde ser lido", + "This Panoramax photo is no longer available": "Esta foto do Panoramax não está mais disponível", + "zoom in to see Panoramax coverage": "aproxime o zoom para ver a cobertura do Panoramax", + "Panoramax did not answer in time — try again": "O Panoramax não respondeu a tempo — tente novamente", + "Panoramax could not be reached — check the connection": "Não foi possível acessar o Panoramax — verifique a conexão", + "Panoramax sent too much data": "O Panoramax enviou dados demais", + "Panoramax is busy": "O Panoramax está sobrecarregado", + "Panoramax sent an unreadable answer": "O Panoramax enviou uma resposta ilegível", + "Sequence images unavailable": "Imagens da sequência indisponíveis", + "No street-level imagery providers configured": "Nenhum provedor de imagens no nível da rua configurado", + "(by upload date)": "(por data de envio)", + "Open the Street Level panel to view imagery": "Abra o painel \"Nível da rua\" para ver as imagens", + "Image could not be opened": "Não foi possível abrir a imagem", + "TeleGeography load failed": "Falha ao carregar o TeleGeography", + "UNAVAILABLE · {source} · Roads unavailable": "INDISPONÍVEL · {source} · Vias indisponíveis", + "Roads: {source}": "Vias: {source}", + "TomTom roads unavailable while the traffic service is unreachable": "Vias do TomTom indisponíveis enquanto o serviço de trânsito estiver inacessível", + "Hybrid unavailable while the traffic service is unreachable": "Modo híbrido indisponível enquanto o serviço de trânsito estiver inacessível", + "TomTom roads need a TomTom key": "As vias do TomTom precisam de uma chave do TomTom", + "Hybrid needs a TomTom key": "O modo híbrido precisa de uma chave do TomTom", + "Local surface still loading": "A superfície sob as vias ainda está carregando", + "Partial coverage": "Cobertura parcial", + "Detailed roads unavailable": "Vias detalhadas indisponíveis", + "Reduced detail coverage": "Cobertura com menos detalhe", + "TomTom roads only, each with its live flow": "Só vias do TomTom, cada uma com seu fluxo ao vivo", + "TomTom roads only, each with its live flow (needs a TomTom key)": "Só vias do TomTom, cada uma com seu fluxo ao vivo (precisa de uma chave do TomTom)", + "OpenStreetMap roads, with TomTom flow matched when available": "Vias do OpenStreetMap, com o fluxo do TomTom associado quando disponível", + "TomTom roads first; OpenStreetMap fills the rest, simulated": "Primeiro as vias do TomTom; o OpenStreetMap completa o resto com fluxo simulado", + "TomTom roads first; OpenStreetMap fills the rest, simulated (needs a TomTom key)": "Primeiro as vias do TomTom; o OpenStreetMap completa o resto com fluxo simulado (precisa de uma chave do TomTom)", + "Hybrid": "Híbrido", + "TomTom key unavailable": "Chave do TomTom indisponível", + "TomTom daily budget reached": "Limite diário do TomTom atingido", + "TomTom upstream unreachable": "Servidor do TomTom inacessível", + "TomTom flow unavailable": "Fluxo do TomTom indisponível", + "SIMULATED — {reason}": "SIMULADO — {reason}", "Syncing flow · Roads: {source}": "Sincronizando fluxo · Vias: {source}", "LIVE · Roads: {source} · Roads without flow hidden": "AO VIVO · Vias: {source} · Vias sem fluxo ocultas", "LIVE · Roads: {source} · No flow roads in view": "AO VIVO · Vias: {source} · Nenhuma via com fluxo na vista", @@ -294,57 +1121,477 @@ "SIMULATED · Roads: OpenStreetMap · Flow: TomTom (no matches)": "SIMULADO · Vias: OpenStreetMap · Fluxo: TomTom (sem correspondências)", "SIMULATED — traffic service unreachable": "SIMULADO — serviço de trânsito inacessível", "SIMULATED — add TomTom key for live": "SIMULADO — adicione a chave TomTom para dados ao vivo", + "OpenFreeMap tiles rate-limited": "Blocos do OpenFreeMap com limite de requisições", + "OpenFreeMap tiles timed out": "Os blocos do OpenFreeMap excederam o tempo limite", + "OpenFreeMap tiles unavailable": "Blocos do OpenFreeMap indisponíveis", + "occupancy|empty": "vazio", + "occupancy|many seats available": "muitos assentos livres", + "occupancy|few seats available": "poucos assentos livres", + "occupancy|standing room only": "só em pé", + "occupancy|crushed standing room only": "lotado, só em pé", + "occupancy|full": "cheio", + "occupancy|not accepting passengers": "não aceita passageiros", + "occupancy|not boardable": "embarque indisponível", + "Route {route}": "Linha {route}", + "Vehicle {vehicle}": "Veículo {vehicle}", + "vehicle motion|Stopped": "Parado", + "No recent fix": "Sem posição recente", + "Waiting for update": "Aguardando atualização", + "Moving": "Em movimento", + "reported {speed} km/h": "velocidade informada: {speed} km/h", + "reported hdg {heading}°": "rumo informado: {heading}°", + "Last report: stopped at stop {stop}": "Último relato: parado no ponto {stop}", + "Last report: arriving at stop {stop}": "Último relato: chegando ao ponto {stop}", + "Last report: next stop {stop}": "Último relato: próximo ponto {stop}", + "Shown at street level · depth not in the feed": "Exibido no nível da rua · o feed não informa a profundidade", + "Reported {seconds} s ago": "Informado há {seconds} s", + "Reported {minutes} min ago": "Informado há {minutes} min", + "shown {seconds} s behind": "exibido com {seconds} s de atraso", + "{reported} (feed time)": "{reported} (horário do feed)", + "Available trail: {minutes} min (limited)": "Rastro disponível: {minutes} min (limitado)", + "Available trail: {minutes} min": "Rastro disponível: {minutes} min", + "Bus": "Ônibus", + "Tram": "Bonde", + "Subway": "Metrô", + "Train": "Trem", + "Ferry": "Balsa", + "Transit vehicle": "Veículo de transporte público", "AIS: {name}": "AIS: {name}", - "{type} SPD: {speed} HDG: {heading}": "{type} VEL: {speed} HDG: {heading}", + "{type} SPD: {speed} HDG: {heading}": "{type} SPD: {speed} HDG: {heading}", "VESSEL": "EMBARCAÇÃO", + "{speed}KT": "{speed} KT", + "{heading}DEG": "{heading}°", "POS: LIVE": "POS: AO VIVO", "POS: {time}Z": "POS: {time}Z", + "AIS live load failed": "Falha ao carregar o AIS ao vivo", "awaiting first AIS position…": "aguardando primeira posição AIS…", "awaiting usable AIS positions…": "aguardando posições AIS utilizáveis…", "awaiting first AIS message…": "aguardando primeira mensagem AIS…", + "AISSTREAM_API_KEY not set": "AISSTREAM_API_KEY não configurada", + "live feed unsupported": "feed ao vivo não suportado", + "connecting to feed…": "conectando ao feed…", + "feed disconnected": "feed desconectado", + "feed down": "feed fora do ar", + "feed idle": "feed inativo", + "API key rejected — check AISSTREAM_API_KEY": "Chave de API recusada — verifique a AISSTREAM_API_KEY", + "feed silent {seconds}s — no AIS data": "feed em silêncio há {seconds} s — sem dados AIS", + "feed silent — no AIS data": "feed em silêncio — sem dados AIS", + "feed down — retrying slowly (attempt {attempt})": "feed fora do ar — tentando de novo devagar (tentativa {attempt})", + "reconnecting to feed… (attempt {attempt})": "reconectando ao feed… (tentativa {attempt})", + "feed down — retrying slowly": "feed fora do ar — tentando de novo devagar", + "reconnecting to feed…": "reconectando ao feed…", + "Focus vessel {name}, MMSI {mmsi}": "Focar a embarcação {name}, MMSI {mmsi}", + "Hidden by this map source · choose a globe map": "Oculto com esta fonte do mapa · escolha um mapa de globo", + "Weather image HTTP {status}": "Imagem do clima: HTTP {status}", + "Weather HTTP {status}": "Clima: HTTP {status}", + "Frame unavailable; previous observation retained": "Quadro indisponível; a observação anterior foi mantida", + "Weather imagery unavailable": "Imagens meteorológicas indisponíveis", + "Weather source unavailable; previous observation retained": "Fonte meteorológica indisponível; a observação anterior foi mantida", + "Weather unavailable": "Clima indisponível", + "No frame within {gap} min of {time}": "Nenhum quadro a ±{gap} min de {time}", + "No frame within {gap} h of {time}": "Nenhum quadro a ±{gap} h de {time}", + "{hours}h {minutes}m ago": "há {hours} h {minutes} min", + "{minutes}m ago": "há {minutes} min", + "{state} · {time} · {lag}": "{state} · {time} · {lag}", + "Observed": "Observado", + "History": "Histórico", + "Observation unavailable": "Observação indisponível", + "Waiting for observation": "Aguardando observação", + "{detail} · synced": "{detail} · sinc.", + "{detail} · nearest": "{detail} · mais próximo", + "RADAR REFLECTIVITY · dBZ": "REFLETIVIDADE DE RADAR · dBZ", + "LIGHTNING DENSITY · 15 min accumulation": "DENSIDADE DE RAIOS · acumulado de 15 min", + "GLOBAL INFRARED · hourly": "INFRAVERMELHO GLOBAL · a cada hora", + "GOES INFRARED · ~5 min": "INFRAVERMELHO GOES · ~5 min", + "{state}: {time}": "{state}: {time}", + "Latest observation": "Última observação", + "frame {index}/{total}": "quadro {index}/{total}", + "loading": "carregando", + "Observation: unavailable": "Observação: indisponível", + "Contiguous US · gaps ≠ no rain": "EUA contíguos · lacunas ≠ sem chuva", + "Americas + Pacific · not individual strikes": "Américas + Pacífico · não são raios individuais", + "Color: strikes/km²/min ×10³": "Cor: raios/km²/min ×10³", + "60°S–60°N · typically 2–3 h delayed": "60°S–60°N · normalmente com 2–3 h de atraso", + "North America · infrared imagery": "América do Norte · imagens infravermelhas", + "Reduced motion · history playback unavailable": "Movimento reduzido · reprodução do histórico indisponível", + "Reduced motion · manual history available": "Movimento reduzido · é possível percorrer o histórico manualmente", + "Rain radar · US": "Radar de chuva · EUA", + "Lightning density · 15 min": "Densidade de raios · 15 min", + "Satellite clouds": "Nuvens por satélite", + "Americas + Pacific": "Américas + Pacífico", + "Global · 60°S–60°N": "Global · 60°S–60°N", + "North America": "América do Norte", + "Source observations delayed": "Observações da fonte com atraso", + "Stale source": "Fonte desatualizada", + "Loading next frame…": "Carregando o próximo quadro…", + "Map center outside coverage": "Centro do mapa fora da cobertura", + "strikes/km²/min ×10³": "raios/km²/min ×10³", + "N. America": "Am. do Norte", + "Global": "Global", + "Hourly global mosaic; usually 2–3 hours delayed": "Mosaico global por hora; normalmente com 2–3 horas de atraso", + "GOES regional clouds; approximately 5-minute updates": "Nuvens regionais do GOES; atualizações a cada 5 minutos aproximadamente", + "Clouds only": "Só nuvens", + "Apply the full cloud brightness key; 100% filter strength": "Aplica o filtro completo de brilho das nuvens; intensidade do filtro 100%", + "Full": "Completa", + "Show the complete infrared image; 0% filter strength": "Mostra a imagem infravermelha completa; intensidade do filtro 0%", + "Soft": "Suave", + "Vivid": "Intensa", + "Image opacity; does not alter the observed values": "Opacidade da imagem; não altera os valores observados", + "View US radar": "Ver radar dos EUA", + "View Americas & Pacific": "Ver Américas e Pacífico", + "View coverage": "Ver cobertura", + "{value} strikes/km²/min ×10³ (15-minute density)": "{value} raios/km²/min ×10³ (densidade de 15 minutos)", + "{value} dBZ radar reflectivity": "{value} dBZ de refletividade de radar", + "STALE · cached source metadata": "DESATUALIZADO · metadados da fonte em cache", + "Map center is outside source coverage": "O centro do mapa está fora da cobertura da fonte", + "NOAA/NWS 15-minute lightning density derived from Vaisala NLDN/GLD360. Coverage 110°E across the Pacific/Americas to 0°, 25°S–80°N. Not a live strike count, global coverage or a safety warning.": "Densidade de raios de 15 minutos da NOAA/NWS derivada do Vaisala NLDN/GLD360. Cobertura de 110°L, passando pelo Pacífico/Américas, até 0°, 25°S–80°N. Não é uma contagem de raios ao vivo, nem cobertura global, nem um alerta de segurança.", + "NOAA MRMS radar echoes indicate precipitation patterns, not rain rate, a storm warning or a future forecast. Native source approximately 1 km; display is limited to level 6. Frames use exact advertised observation times.": "Os ecos de radar NOAA MRMS indicam padrões de precipitação, não a intensidade da chuva, nem um alerta de tempestade, nem uma previsão futura. Fonte nativa de aproximadamente 1 km; a exibição é limitada ao nível 6. Os quadros usam os horários de observação exatos informados.", + "GOES-19/18 longwave infrared Band 14 regional; NESDIS global longwave mosaic. Clouds only dims everything but bright, cold cloud tops; a brightness filter, not a cloud mask. Coverage and freshness differ by region.": "Infravermelho de onda longa GOES-19/18, banda 14, regional; mosaico global de onda longa da NESDIS. Só nuvens escurece tudo, exceto os topos de nuvens brilhantes e frios; é um filtro de brilho, não uma máscara de nuvens. A cobertura e a atualização variam por região.", + "REGION": "REGIÃO", + "IMAGE": "IMAGEM", + "FILTER": "FILTRO", + "Cloud filter strength": "Intensidade do filtro de nuvens", + "OPACITY": "OPACIDADE", + "Infrared decode failed": "Falha ao decodificar o infravermelho", + "Weather prefetch unavailable": "Pré-carregamento do clima indisponível", + "Weather tiles unavailable · previous frame retained": "Blocos meteorológicos indisponíveis · o quadro anterior foi mantido", + "Some weather tiles unavailable": "Alguns blocos meteorológicos indisponíveis", + "Malformed weather manifest": "Manifesto do clima malformado", + "Weather request timed out": "A requisição do clima excedeu o tempo limite", + "Temperature field unavailable": "Campo de temperatura indisponível", + "Mean sea level pressure field unavailable": "Campo de pressão ao nível do mar indisponível", + "Wind upstream unavailable": "Origem dos dados de vento indisponível", + "{source} HTTP {status}": "{source}: HTTP {status}", + "Wind": "Vento", + "Wind source unavailable": "Fonte de vento indisponível", + "Forecast · does not follow history": "Previsão · não acompanha o histórico", + "Wind motion": "Movimento do vento", + "Wind speed": "Velocidade do vento", + "Sea-level pressure": "Pressão ao nível do mar", + "Air temperature · 2 m": "Temperatura do ar · 2 m", + "Global · 1° grid": "Global · grade de 1°", + "{model} forecast · {time}": "Previsão {model} · {time}", + "Loading forecast": "Carregando previsão", + "Preparing flow": "Preparando fluxo", + "Selected field unavailable": "Campo selecionado indisponível", + "Cached forecast · stale": "Previsão em cache · desatualizada", + "ECMWF IFS surface forecast": "Previsão de superfície ECMWF IFS", + "NOAA GFS surface forecast": "Previsão de superfície NOAA GFS", + "Reduced motion": "Movimento reduzido", "Resume": "Retomar", "Pause": "Pausar", + "Pause visual flow; forecast time does not advance with animation": "Pausa o fluxo visual; o horário da previsão não avança com a animação", + "None": "Nenhum", + "Speed": "Velocidade", + "Pressure": "Pressão", + "Temperature": "Temperatura", + "Wind trails with no field shading": "Rastros de vento sem sombreamento do campo", + "How hard the surface wind is blowing": "Com que força o vento sopra na superfície", + "Sea-level air pressure: broad highs and lows": "Pressão do ar ao nível do mar: altas e baixas amplas", + "Air temperature two meters above the surface": "Temperatura do ar a dois metros acima da superfície", + "Wind speed units": "Unidades de velocidade do vento", + "Read wind at map center": "Ler o vento no centro do mapa", + "Read the forecast at the center of the map without changing selection": "Ler a previsão no centro do mapa sem mudar a seleção", + "{model} forecast · {field} ({unit})": "Previsão {model} · {field} ({unit})", + "Valid: {time}": "Válida: {time}", + "preparing": "preparando", + "Issued: {time}": "Emitida: {time}", + "Selected field unavailable · wind remains visible": "Campo selecionado indisponível · o vento continua visível", + "{error} · wind remains visible": "{error} · o vento continua visível", + "Surface wind at 10 m. Approximately 1° global grid. Curves follow the 10 m wind field, lifted 12 km for visibility; display height is not weather altitude. View lighting is for readability. Animation shows flow through one fixed forecast; it does not advance time. Color fields drape the globe basemap or the active photorealistic 3D Tiles.": "Vento de superfície a 10 m. Grade global de aproximadamente 1°. As curvas seguem o campo de vento a 10 m, elevadas 12 km para ficarem visíveis; a altura exibida não é altitude meteorológica. A iluminação da vista serve para facilitar a leitura. A animação mostra o fluxo de uma única previsão fixa; ela não avança o tempo. Os campos de cor cobrem o mapa base do globo ou os 3D Tiles fotorrealistas ativos.", + "MODEL": "MODELO", + "FIELD": "CAMPO", + "UNITS": "UNIDADES", + "MOTION": "MOVIMENTO", + "Forecast": "Previsão", + "N": "N", + "NNE": "NNE", + "NE": "NE", + "ENE": "ENE", + "E": "L", + "ESE": "ESE", + "SE": "SE", + "SSE": "SSE", + "S": "S", + "SSW": "SSO", + "SW": "SO", + "WSW": "OSO", + "W": "O", + "WNW": "ONO", + "NW": "NO", + "NNW": "NNO", + "No surface reading": "Sem leitura na superfície", + "Aim the map center at Earth": "Aponte o centro do mapa para a Terra", + "A location reading needs a loaded forecast and the Earth at the center of the view.": "A leitura de um ponto precisa de uma previsão carregada e da Terra no centro da vista.", + "Interpolated model forecast on an approximately 1° grid. Broad weather patterns, not a street-level measurement.": "Previsão de modelo interpolada em uma grade de aproximadamente 1°. Padrões meteorológicos gerais, não uma medição no nível da rua.", + " · calm": " · calmo", + " from {direction}": " de {direction}", + "WIND AT {coordinates}": "VENTO EM {coordinates}", + "{model} · valid {time}": "{model} · válida {time}", + "Wind speed field unavailable": "Campo de velocidade do vento indisponível", + "Globe imagery unavailable": "Imagens do globo indisponíveis", + "Globe field image unavailable": "Imagem do campo no globo indisponível", + "Unknown wind model": "Modelo de vento desconhecido", + "Unknown weather overlay": "Camada de clima desconhecida", + "Wind request timed out": "A requisição de vento excedeu o tempo limite", + "Malformed wind manifest": "Manifesto de vento malformado", + "Malformed wind grid": "Grade de vento malformada", "Error: {message}": "Erro: {message}", - "Needs {envVars} — add it in Provider Settings": "Requer {envVars} — adicione em Configurações de Provedores", + "Needs {envVars} — add it in Provider Settings": "Requer {envVars} — adicione em Configurações de provedores", "{label} is unavailable": "{label} indisponível", "This map stack": "Esta pilha de mapa", "{label} unavailable: {hint}": "{label} indisponível: {hint}", + "Google 3D tiles unavailable — check the key's API restrictions, quota, or network": "Google 3D Tiles indisponível — verifique as restrições de API da chave, a cota ou a rede", + "Needs {envVars} — add it in Provider Settings — or a Cesium ion token for the ion-hosted route": "Requer {envVars} — adicione em Configurações de provedores — ou um token do Cesium ion para a rota hospedada no ion", + "Exit cockpit to fly to a camera": "Saia da cabine para voar até uma câmera", + "Exit cockpit to fly to a location": "Saia da cabine para voar até um local", + "Exit cockpit to fly to a photo": "Saia da cabine para voar até uma foto", + "Exit cockpit to fly to a shared view": "Saia da cabine para voar até uma vista compartilhada", + "Exit cockpit to fly to a target": "Saia da cabine para voar até um alvo", + "Exit cockpit to fly to a vessel": "Saia da cabine para voar até uma embarcação", + "Exit cockpit to fly to a fire": "Saia da cabine para voar até um incêndio", + "Exit cockpit to fly to a route": "Saia da cabine para voar até uma rota", + "Exit cockpit to fly to a file": "Saia da cabine para voar até um arquivo", + "Exit cockpit to fly to a scene": "Saia da cabine para voar até uma cena", + "Exit cockpit to view weather coverage": "Saia da cabine para ver a cobertura da camada de clima", + "Exit cockpit to fly to a cyclone": "Saia da cabine para voar até um ciclone", + "Exit cockpit to fly to an aircraft": "Saia da cabine para voar até uma aeronave", + "Exit cockpit to fly to a satellite": "Saia da cabine para voar até um satélite", + "Exit cockpit to frame contacts": "Saia da cabine para enquadrar contatos", "Visible map targets": "Alvos visíveis no mapa", + "Focusing {label}": "Focando {label}", + "Source": "Fonte", + "Camera ownership changed": "O controle da câmera mudou", + "Saved project could not be read; storage preserved. Import a valid file to resume saving.": "Não foi possível ler o projeto salvo; o armazenamento foi preservado. Importe um arquivo válido para voltar a salvar.", "Ready": "Pronto", + "Scene layer turned off": "Camada da cena desativada", + "Stopped": "Parado", + "Scene not saved — existing saved project could not be read. Export edits or import a valid file.": "Cena não salva — não foi possível ler o projeto salvo. Exporte as alterações ou importe um arquivo válido.", + "Scene not saved — {reason}": "Cena não salva — {reason}", + "Scene not saved — browser storage unavailable": "Cena não salva — armazenamento do navegador indisponível", "Loaded: {scene} / {shot}": "Carregado: {scene} / {shot}", + "Cannot update {scene}: shot inventory changed": "Não é possível atualizar {scene}: o inventário de planos mudou", + "Cannot update {scene}: evidence beats changed": "Não é possível atualizar {scene}: os momentos de evidência mudaram", + "Cannot update {scene}: shot bindings are incomplete": "Não é possível atualizar {scene}: os vínculos dos planos estão incompletos", + "Updated {count} shots: {scene}": { + "one": "{count} plano atualizado: {scene}", + "many": "{count} de planos atualizados: {scene}", + "other": "{count} planos atualizados: {scene}" + }, + "Appended {count} shots: {scene}": { + "one": "{count} plano adicionado: {scene}", + "many": "{count} de planos adicionados: {scene}", + "other": "{count} planos adicionados: {scene}" + }, "Cannot capture shot: camera not ready": "Não foi possível capturar o plano: câmera não está pronta", "Captured: {scene} / {shot}": "Capturado: {scene} / {shot}", "Select a shot first": "Selecione um plano primeiro", "Updated: {scene} / {shot}": "Atualizado: {scene} / {shot}", + "Could not leave scene: {scene}": "Não foi possível sair da cena: {scene}", + "Seeked: {scene} / {shot}": "Posicionado em: {scene} / {shot}", + "Seeking scene clock": "Movendo o relógio da cena", "Camera unavailable — exit cockpit first": "Câmera indisponível — saia da cabine primeiro", "No shots to run": "Nenhum plano para executar", + "Scene transition limit reached — load a shot to reset": "Limite de transições de cena atingido — carregue um plano para redefinir", + "Export failed: {error}": "Falha na exportação: {error}", "Project exported": "Projeto exportado", + "Importing project": "Importando projeto", + "Imported {file}": "Importado: {file}", + "Import failed: {error}": "Falha na importação: {error}", + "Import failed (could not read JSON file)": "Falha na importação (não foi possível ler o arquivo JSON)", + "Layers refused: {layers}": "Camadas recusadas: {layers}", "Could not exit {mode} — scene layers may be refused": "Não foi possível sair de {mode} — as camadas da cena podem ser recusadas", + "Camera move interrupted": "Movimento de câmera interrompido", + "Scene media timed out": "A mídia da cena excedeu o tempo limite", + "Action complete": "Ação concluída", + "Action unavailable or cancelled": "Ação indisponível ou cancelada", + "Scene actions": "Ações da cena", + "Select a feature or use Tab and Enter to choose an action.": "Selecione um elemento ou use Tab e Enter para escolher uma ação.", + "Selected feature: {feature}. Choose an action.": "Elemento selecionado: {feature}. Escolha uma ação.", "Running {index}/{total}: {scene} / {shot}": "Executando {index}/{total}: {scene} / {shot}", "Scene run complete": "Execução da cena concluída", - "Global Flights Radar": "Radar Global de Voos", - "Orbital Watch": "Vigilância Orbital", - "Thermal Threat Board": "Painel de Ameaças Térmicas", - "City Overload": "Sobrecarga Urbana", - "Omniscience Pullback": "Recuo da Onisciência", + "Bhote Koshi Evidence Sequence": "Sequência de evidências do Bhote Koshi", + "Nepal Flood Incident": "Incidente de inundação no Nepal", + "Global Flights Radar": "Radar global de voos", + "Orbital Watch": "Vigilância orbital", + "Thermal Threat Board": "Painel de ameaças térmicas", + "City Overload": "Sobrecarga urbana", + "Omniscience Pullback": "Recuo da onisciência", + "Global Incident Context": "Contexto global do incidente", + "Nepal-Focused Globe Rotation": "Rotação do globo até o Nepal", + "Bhote Koshi Regional Approach": "Aproximação regional ao Bhote Koshi", + "Bhote Koshi Nearby Cities": "Cidades próximas ao Bhote Koshi", + "Bhote Koshi Incident Corridor": "Corredor do incidente do Bhote Koshi", + "Bhote Koshi Flood Path": "Percurso da inundação do Bhote Koshi", + "Bhote Koshi Corridor Overview": "Visão geral do corredor do Bhote Koshi", + "Bhote Koshi Upper Valley": "Vale superior do Bhote Koshi", + "Upper Valley Collapse": "Colapso no vale superior", + "Debris-Dammed Lake": "Lago represado por detritos", + "Nepal-China Border Gate": "Posto de fronteira Nepal-China", + "Timure Evidence Cluster": "Grupo de evidências de Timure", + "Syabru Besi Passage": "Passagem por Syabru Besi", + "Bidur / Trishuli Consequence": "Consequências em Bidur / Trishuli", + "Final view": "Vista final", + "Scene {n}": "Cena {n}", "Shot {n}": "Plano {n}", + "the title of scene {scene} is empty or longer than {max} characters": "o título da cena {scene} está vazio ou passa de {max} caracteres", + "the title of shot {shot} in scene {scene} is empty or longer than {max} characters": "o título do plano {shot} da cena {scene} está vazio ou passa de {max} caracteres", + "the project is larger than 5 MiB": "o projeto tem mais de 5 MiB", + "the project has too many shots": "o projeto tem planos demais", + "the scene data failed validation": "os dados da cena não passaram na validação", + "Could not complete this action. Check the file, references and selected assets.": "Não foi possível concluir esta ação. Verifique o arquivo, as referências e os recursos selecionados.", + "{count} scenes": { + "one": "{count} cena", + "many": "{count} de cenas", + "other": "{count} cenas" + }, + "{count} shots": { + "one": "{count} plano", + "many": "{count} de planos", + "other": "{count} planos" + }, + "{count} data packs": { + "one": "{count} pacote de dados", + "many": "{count} de pacotes de dados", + "other": "{count} pacotes de dados" + }, + "{scene} / {pack}: {status}. File: {path}. {attribution} · {license}": "{scene} / {pack}: {status}. Arquivo: {path}. {attribution} · {license}", + "Unavailable layers: {layers}": "Camadas indisponíveis: {layers}", + "Uses registered content or linked media. Those external files are not included in a scene bundle. Their original notices still apply.": "Usa conteúdo registrado ou mídia vinculada. Esses arquivos externos não são incluídos no pacote da cena. Os avisos originais deles continuam valendo.", + "{bytes} bundled bytes verified. Files stay in memory for this session. Reimport the bundle after reloading the app.": "{bytes} bytes do pacote verificados. Os arquivos ficam na memória durante esta sessão. Importe o pacote de novo depois de recarregar o app.", + "Review scene import": "Revisar a importação da cena", + "Nothing is loaded or changed until you apply this file.": "Nada é carregado nem alterado até você aplicar este arquivo.", + "Ready to import": "Pronto para importar", + "Apply replaces the current project. Export your current project first if you want to keep both.": "Aplicar substitui o projeto atual. Exporte o projeto atual primeiro se quiser manter os dois.", + "Apply import": "Aplicar importação", + "Import was not applied. The current project may have changed.": "A importação não foi aplicada. O projeto atual pode ter mudado.", + "Select a scene and shot first": "Selecione uma cena e um plano primeiro", + "Edit scene details": "Editar os detalhes da cena", + "Camera positions use degrees and meters above the ellipsoid. Drafts are validated before they replace your saved scene.": "As posições da câmera usam graus e metros acima do elipsoide. Os rascunhos são validados antes de substituir a cena salva.", + "Anchors and data packs": "Âncoras e pacotes de dados", + "Shot camera, timing, packs and actions": "Câmera, tempos, pacotes e ações do plano", + "New anchor ID": "ID da nova âncora", + "Capture camera as anchor": "Capturar a câmera como âncora", + "Anchor added to draft": "Âncora adicionada ao rascunho", + "Set move start to current camera": "Definir o início do movimento na câmera atual", + "Move added to draft; destination remains the shot camera": "Movimento adicionado ao rascunho; o destino continua sendo a câmera do plano", + "Use ordinary flight": "Usar voo comum", + "Invalid shot JSON": "JSON de plano inválido", + "Apply details": "Aplicar detalhes", + "Select a scene first": "Selecione uma cena primeiro", + "Share selected scene": "Compartilhar a cena selecionada", + "Scene JSON preserves authored settings and attribution. It does not include asset files. Bundles include only pack files you choose here or previously imported bundle files.": "O JSON da cena preserva as configurações do autor e a atribuição. Ele não inclui arquivos de recursos. Os pacotes incluem só os arquivos de pacotes de dados que você escolher aqui ou os arquivos de pacotes importados antes.", + "Download scene JSON": "Baixar JSON da cena", + "Choose data-pack files": "Escolher arquivos do pacote de dados", + "Or choose a data-pack folder": "Ou escolha uma pasta de pacote de dados", + "Download asset bundle": "Baixar pacote de recursos", + "Asset bundle downloaded": "Pacote de recursos baixado", + "No RTL-SDR device selected": "Nenhum dispositivo RTL-SDR selecionado", + "WebUSB requires desktop Chrome or Edge on localhost/HTTPS": "O WebUSB requer Chrome ou Edge para desktop em localhost/HTTPS", + "RTL-SDR access failed; close other SDR apps and check USB permissions": "Falha ao acessar o RTL-SDR; feche outros apps de SDR e verifique as permissões USB", + "RTL-SDR connection failed": "Falha na conexão com o RTL-SDR", + "Receiving 1090 MHz ADS-B": "Recebendo ADS-B em 1090 MHz", + "Receiving broadcast FM": "Recebendo rádio FM", + "Connect an RTL-SDR to begin.": "Conecte um RTL-SDR para começar.", + "WebUSB is unavailable in this browser": "O WebUSB não está disponível neste navegador", + "USB work abandoned after a stalled transfer": "Operação USB abandonada após uma transferência travada", + "SDR decoder worker failed": "Falha no processo do decodificador SDR", + "SDR decoder did not start; receiver stopped": "O decodificador SDR não iniciou; receptor parado", + "SDR decoder stopped responding; receiver stopped": "O decodificador SDR parou de responder; receptor parado", + "SDR decoder fell behind; receiver stopped": "O decodificador SDR ficou para trás; receptor parado", + "WebUSB requires desktop Chrome or Edge": "O WebUSB requer Chrome ou Edge para desktop", + "Waiting for an RTL-SDR device…": "Aguardando um dispositivo RTL-SDR…", + "Browser audio is suspended; press Connect again to resume it": "O áudio do navegador está suspenso; pressione Conectar de novo para retomá-lo", + "RTL-SDR sample stream stopped": "Fluxo de amostras do RTL-SDR parado", + "Switching to {mode}…": "Mudando para {mode}…", + "Browser audio is suspended; select FM again to resume it": "O áudio do navegador está suspenso; selecione FM de novo para retomá-lo", + "RTL-SDR gain change failed": "Não foi possível mudar o ganho do RTL-SDR", + "Tuned to {mhz} MHz FM": "Sintonizado em {mhz} MHz FM", + "Seeking up…": "Buscando para cima…", + "Seeking down…": "Buscando para baixo…", + "Seek stopped": "Busca parada", + "Scanning {mhz} MHz…": "Varrendo {mhz} MHz…", + "Found {mhz} MHz · {snr} dB": "Encontrado {mhz} MHz · {snr} dB", + "FM signal found at {mhz} MHz": "Sinal FM encontrado em {mhz} MHz", + "No FM signal found": "Nenhum sinal FM encontrado", + "Browser location is unavailable": "A localização do navegador não está disponível", + "Receiver location was not granted": "A permissão de localização do receptor não foi concedida", + "RTL-SDR disconnected": "RTL-SDR desconectado", + "Upstream response too large": "Resposta da origem grande demais", + "Vector tile request timed out": "A requisição de blocos vetoriais excedeu o tempo limite", + "Vector tiles unavailable": "Blocos vetoriais indisponíveis", + "Vector tile metadata unavailable": "Metadados dos blocos vetoriais indisponíveis", + "Zoom in for vector tile coverage": "Aproxime o zoom para carregar os blocos vetoriais", + "Saturation": "Saturação", + "Edge Thickness": "Espessura das bordas", + "Contrast": "Contraste", + "Grain": "Granulação", + "Vignette": "Vinheta", + "Pixelation": "Pixelização", + "Distortion": "Distorção", + "Instability": "Instabilidade", "Density": "Densidade", + "Gain": "Ganho", "Bloom": "Bloom", + "Scanlines": "Linhas de varredura", + "Sensitivity": "Sensibilidade", + "WHOT/BHOT": "WHOT/BHOT", + "Ironbow": "Ironbow", + "unsaved CCTV calibration": "a calibração de CCTV não salva", + "the open cockpit": "a cabine aberta", + "Switching language reloads the page. This will be lost: {items}. Switch anyway?": "Mudar de idioma recarrega a página. Isto será perdido: {items}. Mudar mesmo assim?", "VISUAL PRESETS": "PREDEFINIÇÕES VISUAIS", "LOCATION": "LOCAL", "CONTACTS — nearest planes · vessels · sites": "CONTATOS — aviões · embarcações · locais mais próximos", "SPACE MISSIONS — launches & orbital assets": "MISSÕES ESPACIAIS — lançamentos e ativos orbitais", "LIVE SIGNALS": "SINAIS AO VIVO", - "Contacts could not complete the requested transition; try again": "Contatos não conseguiram concluir a transição solicitada; tente novamente", + "Contacts could not complete the requested transition; try again": "Contatos: não foi possível concluir a transição solicitada; tente novamente", "CCTV layer unavailable": "Camada de CCTV indisponível", + "Link shared": "Link compartilhado", "Link copied!": "Link copiado!", "Copy failed": "Falha ao copiar", + "Return map to straight-down view": "Voltar o mapa à vista de cima", + "Tilt map to oblique view": "Inclinar o mapa para uma vista oblíqua", + "Reset map to north up. Current heading {heading} degrees": "Orientar o mapa com o norte para cima. Rumo atual: {heading} graus", + "Tilted view": "Vista inclinada", + "Straight-down view": "Vista de cima", + "North up": "Norte para cima", "CCTV calibration saved": "Calibração do CCTV salva", + "HDG": "HDG", + "PITCH": "INCL.", + "FOV": "FOV", + "RANGE": "RANGE", + "HGT": "ALT.", + "ΔN": "ΔN", + "ΔE": "ΔL", + "{value}m": "{value} m", "CCTV calibration reset": "Calibração do CCTV redefinida", "ADJUST ON": "AJUSTE LIGADO", "ADJUST": "AJUSTAR", + "SNAPSHOT": "SNAPSHOT", + "LIVE": "AO VIVO", + "UPSTREAM": "ORIGEM", + "SYNTHETIC": "SINTÉTICO", + "CONFIGURED": "CONFIGURADO", + "SEED": "CATÁLOGO", "UNKNOWN": "DESCONHECIDO", + "OK": "OK", "ERROR": "ERRO", + "Live HLS connected": "HLS ao vivo conectado", + "Live HLS unavailable": "HLS ao vivo indisponível", + "No stream URL configured": "Nenhuma URL de stream configurada", + "Live stream connected": "Stream ao vivo conectado", + "Snapshot feed connected": "Feed de snapshots conectado", + "Media fetch failed": "Falha ao obter a mídia", + "Upstream snapshot active": "Snapshot da origem ativo", + "Fallback Street View frame": "Quadro alternativo do Street View", + "Upstream unavailable": "Origem indisponível", + "No source configured": "Nenhuma fonte configurada", + "Configured source": "Fonte configurada", + "Configured Source": "Fonte configurada", + "Synthetic fallback": "Alternativa sintética", + "Upstream HTTP {status}": "Origem: HTTP {status}", + "Unexpected media type {type}": "Tipo de mídia inesperado: {type}", "SOURCE · UNKNOWN": "FONTE · DESCONHECIDA", "FRAME · LOADING": "QUADRO · CARREGANDO", "FRAME · UNAVAILABLE": "QUADRO · INDISPONÍVEL", @@ -353,7 +1600,7 @@ "RAW PRIOR": "ESTIMATIVA BRUTA", "CCTV ON": "CCTV LIGADO", "CCTV OFF": "CCTV DESLIG.", - "VIEWSHED ON": "VIEWSHED LIGADO", + "VIEWSHED ON": "ÁREA VISÍVEL LIGADA", "COVERAGE ON": "COBERTURA LIGADA", "COVERAGE OFF": "COBERTURA DESLIG.", "AUTO HOP ON": "AUTO SALTO LIGADO", @@ -363,16 +1610,16 @@ "CAL · EDITED (UNSAVED)": "CAL · EDITADA (NÃO SALVA)", "CAL · {badge}": "CAL · {badge}", "MONITOR": "MONITOR", - "OFF": "DESLIGADO", - "{city} · HDG {heading} · FOV {fov} · RANGE {range}m · {projection}{calBadge} · {provider}{status}": "{city} · HDG {heading} · FOV {fov} · ALCANCE {range}m · {projection}{calBadge} · {provider}{status}", + "OFF": "INATIVO", + "{city} · HDG {heading} · FOV {fov} · RANGE {range}m · {projection}{calBadge} · {provider}{status}": "{city} · HDG {heading} · FOV {fov} · RANGE {range} m · {projection}{calBadge} · {provider}{status}", "{count} cameras loaded · click a camera to activate": { "one": "{count} câmera carregada · clique em uma câmera para ativar", - "many": "{count} câmeras carregadas · clique em uma câmera para ativar", + "many": "{count} de câmeras carregadas · clique em uma câmera para ativar", "other": "{count} câmeras carregadas · clique em uma câmera para ativar" }, "{count} cameras loaded · enable CCTV to activate": { "one": "{count} câmera carregada · ative o CCTV para usar", - "many": "{count} câmeras carregadas · ative o CCTV para usar", + "many": "{count} de câmeras carregadas · ative o CCTV para usar", "other": "{count} câmeras carregadas · ative o CCTV para usar" }, "Enable CCTV to load camera intersections": "Ative o CCTV para carregar interseções de câmeras", @@ -403,15 +1650,18 @@ "REGION UNAVAILABLE": "REGIÃO INDISPONÍVEL", "NO RECENT LOCATION MATCHES": "NENHUMA CORRESPONDÊNCIA RECENTE COM O LOCAL", "{domain} · {age}": "{domain} · {age}", + "{value} KM/H": "{value} KM/H", "CLOUD {pct}%": "NUVENS {pct}%", "CLOUD UNKNOWN": "NUVENS DESCONHECIDAS", "{source} · LOCATION QUERY": "{source} · CONSULTA POR LOCAL", "REGIONAL NEWS": "NOTÍCIAS REGIONAIS", + "{label} · {radius} AIR/SEA WINDOW": "{label} · JANELA AR/MAR {radius}", + "{scope} · INSTALLATIONS {coverage}": "{scope} · INSTALAÇÕES: {coverage}", "CONTEXT STANDBY": "CONTEXTO EM ESPERA", "ENABLE GLOBAL CONTEXT FOR PROXIMITY PINGS": "ATIVE O CONTEXTO GLOBAL PARA PINGS DE PROXIMIDADE", "CONTACT LOST · LAST KNOWN READOUT · NOT AN ALL-CLEAR": "CONTATO PERDIDO · ÚLTIMA LEITURA CONHECIDA · NÃO GARANTE SEGURANÇA", "CONTACT LOST · {subject}": "CONTATO PERDIDO · {subject}", - "SUBJECT LEFT ITS FEED · READOUT HOLDING LAST KNOWN": "ALVO SAIU DO SEU FEED · LEITURA MANTIDA NA ÚLTIMA POSIÇÃO CONHECIDA", + "SUBJECT LEFT ITS FEED · READOUT HOLDING LAST KNOWN": "ALVO SAIU DO FEED · LEITURA MANTIDA NO ÚLTIMO VALOR CONHECIDO", "{cohort} · {contact}": "{cohort} · {contact}", "NO AVAILABLE EXAMPLE": "NENHUM EXEMPLO DISPONÍVEL", "{cohort}, Unavailable": "{cohort}, indisponível", @@ -421,23 +1671,27 @@ "R": "D", "{count} INPUTS UNKNOWN · NOT AN ALL-CLEAR": { "one": "{count} ENTRADA DESCONHECIDA · NÃO GARANTE SEGURANÇA", - "many": "{count} ENTRADAS DESCONHECIDAS · NÃO GARANTE SEGURANÇA", + "many": "{count} DE ENTRADAS DESCONHECIDAS · NÃO GARANTE SEGURANÇA", "other": "{count} ENTRADAS DESCONHECIDAS · NÃO GARANTE SEGURANÇA" }, "AVAILABLE INPUTS CURRENT · NOT AN ALL-CLEAR": "ENTRADAS DISPONÍVEIS ATUAIS · NÃO GARANTE SEGURANÇA", + "SQUAWK {code} · {status}": "SQUAWK {code} · {status}", + "ADS-B PRIORITY · {status}": "ADS-B PRIORIDADE · {status}", + "ADS-B EMERGENCY · {status}": "ADS-B EMERGÊNCIA · {status}", "AIRCRAFT": "AERONAVE", "ACQUIRING SURFACE": "ADQUIRINDO SUPERFÍCIE", "SURFACE FALLBACK": "SUPERFÍCIE ALTERNATIVA", "STALE FEED": "FEED DESATUALIZADO", "LIVE TRACK": "RASTRO AO VIVO", "COMMERCIAL": "COMERCIAL", + "{aircraftClass} · {emergency} · {feedState}": "{aircraftClass} · {emergency} · {feedState}", "{aircraftClass} · {feedState} · COURSE ALIGNED": "{aircraftClass} · {feedState} · CURSO ALINHADO", "ARROW · ESTIMATED DIRECTION": "SETA · DIREÇÃO ESTIMADA", "ROUTE DATA UNAVAILABLE": "DADOS DE ROTA INDISPONÍVEIS", "DEST {bearing}": "DEST {bearing}", "Disable cockpit weather effects": "Desativar efeitos de clima na cabine", "Enable cockpit weather effects": "Ativar efeitos de clima na cabine", - "ON": "LIGADO", + "ON": "ATIVO", "Normal": "Normal", "Night vision": "Visão noturna", "Thermal": "Térmico", @@ -457,10 +1711,11 @@ "OBSERVED / MAPPED PINGS": "PINGS OBSERVADOS / MAPEADOS", "SOURCE-BACKED EVENTS · NO SYNTHETIC NEWS": "EVENTOS COM FONTE · SEM NOTÍCIAS SINTÉTICAS", "LATEST LOCATION-MATCHED REPORTING": "ÚLTIMAS REPORTAGENS DA LOCALIZAÇÃO", + "{source} · LOCATION QUERY · RECENT": "{source} · CONSULTA POR LOCAL · RECENTE", "LOCAL INFO": "INFO LOCAL", "PLACE / CONDITIONS / POSITION": "LUGAR / CONDIÇÕES / POSIÇÃO", "TIME UNKNOWN": "HORA DESCONHECIDA", - "{count}M AGO": "HÁ {count}MIN", + "{count}M AGO": "HÁ {count} MIN", "{count}H AGO": "HÁ {count}H", "{count}D AGO": "HÁ {count}D", "DIR UNKNOWN": "DIR DESCONHECIDA", @@ -472,7 +1727,7 @@ "DISTANCE UNKNOWN": "DISTÂNCIA DESCONHECIDA", "{count} INPUTS UNKNOWN": { "one": "{count} ENTRADA DESCONHECIDA", - "many": "{count} ENTRADAS DESCONHECIDAS", + "many": "{count} DE ENTRADAS DESCONHECIDAS", "other": "{count} ENTRADAS DESCONHECIDAS" }, "SOURCE STATUS UNAVAILABLE": "STATUS DA FONTE INDISPONÍVEL", @@ -483,20 +1738,20 @@ "Context could not restore every layer; try again": "O contexto não conseguiu restaurar todas as camadas; tente novamente", "No selected data layers": "Nenhuma camada de dados selecionada", "{count} data layers could not be cleared": { - "one": "{count} camada de dados não pôde ser limpa", - "many": "{count} camadas de dados não puderam ser limpas", - "other": "{count} camadas de dados não puderam ser limpas" + "one": "Não foi possível limpar {count} camada de dados", + "many": "Não foi possível limpar {count} de camadas de dados", + "other": "Não foi possível limpar {count} camadas de dados" }, "Cleared {count} data layers": { "one": "{count} camada de dados limpa", - "many": "{count} camadas de dados limpas", + "many": "{count} de camadas de dados limpas", "other": "{count} camadas de dados limpas" }, "Selected data layers could not be cleared": "Não foi possível limpar as camadas de dados selecionadas", - "Space Missions could not complete the requested transition; try again": "Missões espaciais não conseguiram concluir a transição solicitada; tente novamente", + "Space Missions could not complete the requested transition; try again": "Missões espaciais: não foi possível concluir a transição solicitada; tente novamente", "Nearby installations refreshed": "Instalações próximas atualizadas", "Nearby installations could not be refreshed; try again": "Não foi possível atualizar as instalações próximas; tente novamente", - "Space Missions cancellation could not restore the previous layer state": "O cancelamento de Missões espaciais não conseguiram restaurar o estado anterior das camadas", + "Space Missions cancellation could not restore the previous layer state": "O cancelamento de Missões espaciais não conseguiu restaurar o estado anterior das camadas", "That layer is unavailable in the current Context mode": "Essa camada não está disponível no modo de contexto atual", "{layerId} could not {action} cleanly": "Não foi possível {action} {layerId} corretamente", "start": "iniciar", @@ -504,24 +1759,89 @@ "{mode} could not start because another layer did not stop cleanly": "Não foi possível iniciar {mode} porque outra camada não parou corretamente", "Space Missions": "Missões espaciais", "Context": "Contexto", - "Live Flights": "Voos ao Vivo", - "Military Flights": "Voos Militares", + "Rendered globe frames per second · toggle with `": "Quadros por segundo renderizados do globo · alterne com `", + "imported map files": "os arquivos importados no mapa", + "Ground heights could not be refreshed. Try the file again when the map has loaded.": "Não foi possível atualizar as altitudes do terreno. Tente o arquivo de novo quando o mapa tiver carregado.", + "{count} map objects": { + "one": "{count} objeto no mapa", + "many": "{count} de objetos no mapa", + "other": "{count} objetos no mapa" + }, + ", drawn with its own styles": ", desenhado com os próprios estilos", + "Hide {name}": "Ocultar {name}", + "Show {name}": "Mostrar {name}", + "Fly to {name}": "Voar até {name}", + "Remove {name}": "Remover {name}", + "At most {count} files at once — remove one first.": "No máximo {count} arquivos de cada vez — remova um primeiro.", + "Reading {name}…": "Lendo {name}…", + "That file could not be read.": "Não foi possível ler esse arquivo.", + "Added {count} files.": { + "one": "{count} arquivo adicionado.", + "many": "{count} de arquivos adicionados.", + "other": "{count} arquivos adicionados." + }, + "{count} files could not be added ({name}: {error})": { + "one": "Não foi possível adicionar {count} arquivo ({name}: {error})", + "many": "Não foi possível adicionar {count} de arquivos ({name}: {error})", + "other": "Não foi possível adicionar {count} arquivos ({name}: {error})" + }, + "Some KML content was left out.": "Parte do conteúdo KML foi deixada de fora.", + "Press on the ground, not the sky": "Pressione no chão, não no céu", + "Drag to size the box": "Arraste para definir o tamanho da área", + "light {source} to use your {name} key": "ative {source} para usar sua chave do {name}", + "light {source}": "ative {source}", + ", or ": ", ou ", + "{requirement}, or {offer}": "{requirement}, ou {offer}", + "Live Flights": "Voos ao vivo", + "Military Flights": "Voos militares", "Earthquakes (24h)": "Terremotos (24h)", "Satellites": "Satélites", - "Space Missions (30d)": "Missões Espaciais (30d)", - "Street Traffic": "Trânsito Urbano", + "Space Missions (30d)": "Missões espaciais (30 d)", + "Street Traffic": "Trânsito urbano", "CCTV": "CCTV", "Radio": "Rádio", - "Bikeshare": "Bicicletas Compartilhadas", - "Live AIS Vessels": "Embarcações AIS ao Vivo", - "Mapped Installations": "Instalações Mapeadas", - "Global Context": "Contexto Global", - "Datacenters": "Data Centers", + "Bikeshare": "Bicicletas compartilhadas", + "Live AIS Vessels": "Embarcações AIS ao vivo", + "Mapped Installations": "Instalações mapeadas", + "Global Context": "Contexto global", + "Datacenters": "Data centers", "Dams": "Barragens", - "Submarine Cables": "Cabos Submarinos", - "FIRMS Active Fires": "Incêndios Ativos FIRMS", + "Submarine Cables": "Cabos submarinos", + "FIRMS Active Fires": "Incêndios ativos FIRMS", + "Local ADS-B": "ADS-B local", + "Transit": "Transporte público", + "Recent Imagery": "Imagens recentes", + "Fire Perimeters": "Perímetros de incêndios", + "GNSS Integrity": "Integridade GNSS", + "S2 GhostMaps": "S2 GhostMaps", + "Rain radar": "Radar de chuva", + "Lightning density": "Densidade de raios", + "Cyclone advisories": "Boletins de ciclones", + "ALPR Cameras": "Câmeras ALPR", + "Live Vessels": "Embarcações ao vivo", + "Bike Share": "Bicicletas compartilhadas", + "Cameras": "Câmeras", + "Street Level": "Nível da rua", + "Mapped ALPR Cameras": "Câmeras ALPR mapeadas", + "Data Centers": "Data centers", + "Active Fires": "Incêndios ativos", + "Military aircraft": "Aeronaves militares", + "Vessels": "Embarcações", + "CCTV + Street View fallback": "CCTV + Street View como alternativa", + "OpenStreetMap + optional Google Maps Places": "OpenStreetMap + Google Maps Places opcional", + "GFS / ECMWF IFS · FORECAST": "GFS / ECMWF IFS · PREVISÃO", + "NOAA nowCOAST · OBSERVED": "NOAA nowCOAST · OBSERVADO", + "NASA FIRMS · LIVE": "NASA FIRMS · AO VIVO", + "OSM routing": "Rotas do OSM", + "data source|Local": "Dados locais", "ENABLING": "ATIVANDO", "DISABLING": "DESATIVANDO", + "Movement": "Movimento", + "Infrastructure": "Infraestrutura", + "Events": "Eventos", + "Weather": "Clima", + "Utilities": "Utilitários", + "Other layers": "Outras camadas", "{state} · {source}": "{state} · {source}", "UNCERTAIN · {source} · lifecycle state requires reconciliation": "INCERTO · {source} · estado do ciclo de vida requer reconciliação", "{state} · {source} · {detail} · retry {seconds}s": "{state} · {source} · {detail} · nova tentativa em {seconds}s", @@ -535,21 +1855,75 @@ "{state} · {source} · {ago}": "{state} · {source} · {ago}", "{source} · {ago}": "{source} · {ago}", "UNCERTAIN": "INCERTO", + "status chip|UNAVAILABLE": "INDISP.", + "Data source unavailable": "Fonte de dados indisponível", "{name}: {state}": "{name}: {state}", "{count}s ago": "há {count}s", + "Local FM stopped: internet radio started": "FM local parada: a rádio pela internet começou", + "IDLE": "EM ESPERA", "CONNECTING": "CONECTANDO", + "TUNING": "SINTONIZANDO", + "STREAMING": "RECEBENDO", + "UNSUPPORTED": "NÃO SUPORTADO", + "idle": "em espera", + "running": "ativo", + "suspended": "suspenso", + "closed": "fechado", + "feed status|live": "ao vivo", + "feed status|stale": "desatualizado", + "feed status|unreachable": "inacessível", + "feed status|invalid": "inválido", + "waiting for IQ": "aguardando IQ", + "{count} messages": { + "one": "{count} mensagem", + "many": "{count} de mensagens", + "other": "{count} mensagens" + }, + "DSP {count} blocks": { + "one": "DSP {count} bloco", + "many": "DSP {count} de blocos", + "other": "DSP {count} blocos" + }, + "DSP waiting": "DSP em espera", + "{level} dBFS audio": "áudio {level} dBFS", + "audio signal --": "sinal de áudio --", + "audio {state}": "áudio {state}", + "{count} HEARD": { + "one": "CAPTADAS: {count}", + "many": "CAPTADAS: {count}", + "other": "CAPTADAS: {count}" + }, + "DISCONNECT": "DESCONECTAR", + "CONNECT": "CONECTAR", + "LOCATING…": "LOCALIZANDO…", + "LOCATED": "LOCALIZADO", + "LOCATE": "LOCALIZAR", + " · read while Local ADS-B is on": " · lidos enquanto o ADS-B local está ativo", + "Decoder feeds: {feeds}": "Feeds do decodificador: {feeds}", + "Language: {language}": "Idioma: {language}", + "Change the interface language": "Mudar o idioma da interface", + "Interface language": "Idioma da interface", + "Search languages": "Buscar idioma", + "No matching languages": "Nenhum idioma corresponde", "📍 Location: --": "📍 Local: --", "Landmark: --": "Ponto de referência: --", "Searched location": "Local pesquisado", "ORBIT": "ÓRBITA", "Location not found": "Local não encontrado", + "Check the spelling and press Enter to search again.": "Verifique a grafia e pressione Enter para buscar de novo.", "Search failed": "Falha na busca", + "Press Enter to try again.": "Pressione Enter para tentar novamente.", + "Detailed outline unavailable": "Contorno detalhado indisponível", "Fly to a POI first": "Voe até um ponto de interesse primeiro", "Reset to full globe view": "Voltar à vista do globo completo", "Reset cockpit to full globe view": "Redefinir a cabine para a vista do globo completo", "Resetting to full globe view": "Voltando à vista do globo completo", "Resetting cockpit to full globe view": "Redefinindo a cabine para a vista do globo completo", "MAP": "MAPA", + "Layers": "Camadas", + "Search": "Buscar", + "More": "Mais", + "Panels": "Painéis", "panel": "painel", "Expand {name}": "Expandir {name}", "Collapse {name}": "Recolher {name}", @@ -558,17 +1932,31 @@ "Expand Radio section": "Expandir seção de rádio", "Collapse Radio section": "Recolher seção de rádio", "Panel layout updated — positions reset to new defaults": "Layout dos painéis atualizado — posições redefinidas para os novos padrões", + "Austin": "Austin", + "San Francisco": "São Francisco", + "New York": "Nova York", + "Tokyo": "Tóquio", + "London": "Londres", + "Paris": "Paris", + "Dubai": "Dubai", + "Washington DC": "Washington, D.C.", + "Tallinn": "Tallinn", + "Los Angeles": "Los Angeles", "Collapse Cockpit display options": "Recolher opções de exibição da cabine", "Expand Cockpit display options": "Expandir opções de exibição da cabine", "Collapse Cockpit Radio controls": "Recolher controles de rádio da cabine", "Expand Cockpit Radio controls": "Expandir controles de rádio da cabine", + "CH {index} / {total}": "CANAL {index} / {total}", "NO STATIONS": "SEM ESTAÇÕES", "NO STATION AVAILABLE": "NENHUMA ESTAÇÃO DISPONÍVEL", "{name}, station {index} of {total}": "{name}, estação {index} de {total}", "No station available": "Nenhuma estação disponível", "OFF AIR": "FORA DO AR", "STATION UNAVAILABLE": "ESTAÇÃO INDISPONÍVEL", + "Station unavailable after directory refresh": "Estação indisponível após atualizar o diretório", "Radio could not {action} cleanly": "Não foi possível {action} o rádio corretamente", + "Go to expanded Radio section": "Ir para a seção de rádio expandida", + "Expand Radio section in Context": "Expandir a seção de rádio em Contexto", "Close compact Radio controls": "Fechar controles compactos do rádio", "Open compact Radio controls": "Abrir controles compactos do rádio", "SYNC": "SINC", @@ -578,15 +1966,18 @@ "Reconcile Radio — lifecycle uncertain": "Reconciliar rádio — ciclo de vida incerto", "Disable Radio": "Desativar rádio", "Enable Radio": "Ativar rádio", + "{category} ({count})": "{category} ({count})", "DIRECTORY BAND": "BANDA DO DIRETÓRIO", "{category} BAND": "BANDA {category}", "NO STATION SELECTED": "NENHUMA ESTAÇÃO SELECIONADA", "Directory metadata only": "Somente metadados do diretório", "Loading station directory…": "Carregando diretório de estações…", - "Choose a globe marker or use next.": "Escolha um marcador no globo ou use próxima.", + "Choose a globe marker or use next.": "Escolha um marcador no globo ou use Próxima.", "TAGS · {tags}": "TAGS · {tags}", "Play": "Reproduzir", - "PLAY": "PLAY", + "PAUSE": "PAUSAR", + "RESUME": "RETOMAR", + "PLAY": "OUVIR", "selected": "selecionada", "nearest": "mais próxima", "{action} {target} radio station": "{action} estação de rádio {target}", @@ -603,7 +1994,7 @@ "Ready — playback starts only from your action": "Pronto — a reprodução só começa por ação sua", "Radio off": "Rádio desligado", "Connecting directly to broadcaster…": "Conectando direto à emissora…", - "Buffering broadcaster stream…": "Armazenando em buffer o stream da emissora…", + "Buffering broadcaster stream…": "Carregando o stream da emissora…", "Playing {station}": "Reproduzindo {station}", "Paused {station}": "Pausado: {station}", "Broadcaster stream unavailable": "Stream da emissora indisponível", @@ -615,63 +2006,692 @@ "Radio is enabling…": "O rádio está sendo ativado…", "Radio is disabling…": "O rádio está sendo desativado…", "Radio lifecycle is uncertain — use Enable or Disable to reconcile": "O ciclo de vida do rádio é incerto — use Ativar ou Desativar para reconciliar", + "Clear reading": "Limpar leitura", + "Earlier observation": "Observação anterior", + "Observed history": "Histórico observado", + "Later observation": "Observação posterior", + "Latest": "Mais recente", + "Newest frame per product": "Quadro mais recente por produto", + "Replay observed history": "Reproduzir o histórico observado", + "Imagery on Esri · Google 3D returns when cleared": "Imagens sobre o Esri · LIMPAR restaura o Google 3D", + "Point the camera at the ground to use the view": "Aponte a câmera para o chão para usar a vista", + "That point cannot anchor a box": "Esse ponto não pode ancorar uma área", + "Imagery stops at ±{limit}° latitude": "As imagens vão até ±{limit}° de latitude", + "{owner} is using the pointer — close it first": "Ponteiro em uso: {owner}. Feche-o primeiro", + "Box is {size} wide · limit {limit}": "A área tem {size} de largura · limite {limit}", + "View is {size} wide · limit {limit}": "A vista tem {size} de largura · limite {limit}", + "VS BASEMAP": "VS MAPA BASE", + "A / B": "A / B", + "Newest low-cloud day for this box · scene cloud, not box cloud": "Dia mais recente com poucas nuvens para esta área · nuvens da cena, não da área", + "Newest day covering this box · cloudier than 20%": "Dia mais recente que cobre esta área · mais de 20% de nuvens", + "Newest day with imagery for this box · partial coverage": "Dia mais recente com imagens para esta área · cobertura parcial", + "Newest daily overview for this box": "Visão geral diária mais recente para esta área", + "newest clear day": "dia limpo mais recente", + "newest day (cloudy)": "dia mais recente (nublado)", + "newest day (partial coverage)": "dia mais recente (cobertura parcial)", + "newest overview": "visão geral mais recente", + "No imagery": "Sem imagens", + "Loading": "Carregando", + "coverage|full": "completa", + "coverage|partial": "parcial", + "unknown": "desconhecida", + "no imagery": "sem imagens", + "{percent}% cloud": "{percent}% de nuvens", + "{min}–{max}% cloud": "{min}–{max}% de nuvens", + "NO BOX": "SEM ÁREA", + "SEARCHING": "BUSCANDO", + "{count} DAYS": { + "one": "{count} DIA", + "many": "{count} DE DIAS", + "other": "{count} DIAS" + }, + "Zoom in or draw a smaller box": "Aproxime o zoom ou desenhe uma área menor", + "Select a box or use the view": "Selecione uma área ou use a vista", + "Searching the last 30 days": "Buscando nos últimos 30 dias", + "No days to show for this box": "Nenhum dia para mostrar nesta área", + "Drag the divider · SWAP trades sides": "Arraste o divisor · INVERTER troca os lados", + "← → preview · A or B pins the focused day": "← → prévia · A ou B fixa o dia em foco", + "← → preview the other side · A or B pins it": "← → prévia do outro lado · A ou B o fixa", + "S on another day replaces it · × unpins": "S em outro dia o substitui · × desafixa", + "← → preview · S shows the focused day": "← → prévia · S mostra o dia em foco", + "ZOOM IN": "APROXIMAR", + "Fly in until the view fits the 1,000 km limit": "Aproxime até a vista caber no limite de 1.000 km", + "Imagery days, newest first · arrows move, S or A and B pin": "Dias com imagens, do mais recente · as setas movem, S ou A e B fixam", + "On the map": "No mapa", + "Mode": "Modo", + "Imagery opacity": "Opacidade das imagens", + "SWAP": "INVERTER", + "Trade the two sides of the divider": "Trocar os dois lados do divisor", + "SELECT BOX": "SELECIONAR", + "Drag a box on the map (Esc cancels)": "Arraste uma área no mapa (Esc cancela)", + "USE VIEW": "USAR VISTA", + "Use the current view as the box": "Usar a vista atual como área", + "Forget the box and its images": "Esquecer a área e suas imagens", + "START HERE": "COMECE AQUI", + "Checking": "Verificando", + "PREVIEW": "PRÉVIA", + "Newest day with imagery for this box": "Dia mais recente com imagens para esta área", + "SHOW": "MOSTRAR", + "Pin {day} as {slot}": "Fixar {day} como {slot}", + "Show {day}": "Mostrar {day}", + "pinned {slot}": "fixado em {slot}", + "shown": "exibido", + "preview": "prévia", + "start here": "comece aqui", + "No box": "Sem área", + "Searching": "Buscando", + "Every day is empty here": "Todos os dias estão vazios aqui", + "Sources off": "Fontes desativadas", + "VS": "VS", + "Not set": "Não definido", + "Basemap": "Mapa base", + "Source off": "Fonte desativada", + "Unpin {slot}": "Desafixar {slot}", + "Unpin the image": "Desafixar a imagem", + "EXPORT {slot}": "EXP. {slot}", + "EXPORT": "EXPORTAR", + "Download {slot} as a PNG": "Baixar {slot} como PNG", + "Download the image as a PNG": "Baixar a imagem como PNG", + "Box {width} × {height} km": "Área de {width} × {height} km", + "Acquired {time}": "Adquirida {time}", + "Coverage {coverage}": "Cobertura {coverage}", + "START HERE · {reason}": "COMECE AQUI · {reason}", + "Daily overview shows little detail in a box this small": "A visão geral diária mostra pouco detalhe em uma área tão pequena", + "Imagery: NASA GIBS and Worldview · HLS (Sentinel-2, Landsat 8/9) and VIIRS": "Imagens: NASA GIBS e Worldview · HLS (Sentinel-2, Landsat 8/9) e VIIRS", + "Details": "Detalhes", + "Times, coverage, sources": "Horários, cobertura, fontes", + "HIDE EMPTY DAYS": "OCULTAR DIAS VAZIOS", + "SHOW EMPTY DAYS · {count}": "MOSTRAR DIAS VAZIOS · {count}", + "Days the probe found empty in this box": "Dias que a sondagem encontrou vazios nesta área", + "image": "imagem", + "BASEMAP": "MAPA BASE", + "The basemap": "O mapa base", + "basemap": "mapa base", + "Recent imagery against the basemap divider": "Divisor entre imagens recentes e o mapa base", + "Recent imagery A and B divider": "Divisor A e B de imagens recentes", + "{before} {left} percent, {after} {right} percent": "{before} {left} por cento, {after} {right} por cento", + "Export failed · {error}": "Falha na exportação · {error}", "Scene action failed": "A ação da cena falhou", + "New scene name": "Nome da nova cena", + "Delete scene \"{scene}\" and all shots?": "Excluir a cena \"{scene}\" e todos os planos?", "Delete shot \"{shot}\"?": "Excluir o plano \"{shot}\"?", + "Stopped (Esc)": "Parado (Esc)", "SPARSE": "ESPARSA", "BALANCED": "EQUILIBRADA", - "DEL": "EXCL", + "No shots yet. Use CAPTURE SHOT to save current look.": "Ainda não há planos. Use CAPTURAR PLANO para salvar o visual atual.", + "Double-click to rename": "Clique duplo para renomear", + "Shot name": "Nome do plano", + "LOAD": "CARREGAR", + "DEL": "EXCL.", + "{duration}s + {hold}s": "{duration} s + {hold} s", + "Choose files": "Escolher arquivos", + "{count} files selected": { + "one": "{count} arquivo selecionado", + "many": "{count} de arquivos selecionados", + "other": "{count} arquivos selecionados" + }, + "No file chosen": "Nenhum arquivo escolhido", + "Cancel": "Cancelar", + "EDIT DETAILS": "EDITAR DETALHES", + "SHARE SCENE": "COMPARTILHAR CENA", + "Shared flight follow expired": "O acompanhamento do voo compartilhado expirou", + "Shared military flight follow expired": "O acompanhamento do voo militar compartilhado expirou", + "Shared satellite follow expired": "O acompanhamento do satélite compartilhado expirou", + "Shared flight could not be restored — feed unavailable": "Não foi possível restaurar o voo compartilhado — feed indisponível", + "Shared military flight could not be restored — feed unavailable": "Não foi possível restaurar o voo militar compartilhado — feed indisponível", + "Shared satellite could not be restored — feed unavailable": "Não foi possível restaurar o satélite compartilhado — feed indisponível", + "Shared flight is unavailable": "O voo compartilhado está indisponível", + "Shared military flight is unavailable": "O voo militar compartilhado está indisponível", + "Shared satellite is unavailable": "O satélite compartilhado está indisponível", "entity": "entidade", "Shared {subject} follow expired": "O acompanhamento compartilhado de {subject} expirou", "Shared {subject} could not be restored — feed unavailable": "Não foi possível restaurar o compartilhamento de {subject} — feed indisponível", "Shared {subject} is unavailable": "O compartilhamento de {subject} está indisponível", + "{id} isn't reporting now — showing where it was last seen": "{id} não está transmitindo agora — mostrando onde foi visto pela última vez", + "{id} isn't reporting now — showing where it was at {time}": "{id} não está transmitindo agora — mostrando onde estava às {time}", + "This share link can't be opened": "Não é possível abrir este link de compartilhamento", + "Shared vessel is unavailable": "A embarcação compartilhada está indisponível", "ACQUIRING": "ADQUIRINDO", "SHARED {subject}": "COMPARTILHADO: {subject}", + "subject": "alvo", "LOADING LIVE DATA": "CARREGANDO DADOS AO VIVO", "LOAD COMPLETE": "CARGA CONCLUÍDA", "LOAD CANCELLED": "CARGA CANCELADA", "LOAD FAILED": "FALHA NA CARGA", "LIVE DATA OFF": "DADOS AO VIVO DESLIGADOS", "MAPPED SITES LOADED": "LOCAIS MAPEADOS CARREGADOS", - "RETRYING MAPPED SITES": "REPETINDO BUSCA DE LOCAIS MAPEADOS", + "RETRYING MAPPED SITES": "TENTANDO DE NOVO OS LOCAIS MAPEADOS", "FETCHING MAPPED SITES": "BUSCANDO LOCAIS MAPEADOS", + "RETRYING ALPR CAMERAS": "TENTANDO DE NOVO AS CÂMERAS ALPR", + "FETCHING ALPR CAMERAS": "BUSCANDO CÂMERAS ALPR", + "OVERPASS TEMPORARILY UNAVAILABLE": "OVERPASS TEMPORARIAMENTE INDISPONÍVEL", + "OVERPASS RATE-LIMITED": "OVERPASS COM LIMITE DE REQUISIÇÕES", + "OVERPASS TIMED OUT": "TEMPO ESGOTADO NO OVERPASS", + "OVERPASS COULD NOT COMPLETE THE QUERY": "OVERPASS NÃO CONSEGUIU CONCLUIR A CONSULTA", + "MAP TILES TEMPORARILY UNAVAILABLE": "BLOCOS DO MAPA TEMPORARIAMENTE INDISPONÍVEIS", + "MAPPED NAMES TEMPORARILY UNAVAILABLE": "NOMES MAPEADOS TEMPORARIAMENTE INDISPONÍVEIS", "TURNING OFF LIVE DATA": "DESLIGANDO DADOS AO VIVO", "REFRESHING LIVE DATA": "ATUALIZANDO DADOS AO VIVO", "syncing road network": "sincronizando malha viária", "retry pending": "nova tentativa pendente", "retrying in {seconds}s": "nova tentativa em {seconds}s", + "ALPR cameras": "câmeras ALPR", + "OpenSky OAuth client missing/invalid": "Cliente OAuth do OpenSky ausente ou inválido", + "OpenSky OAuth rejected credentials": "O OAuth do OpenSky recusou as credenciais", + "OpenSky username/password rejected": "O OpenSky recusou o usuário ou a senha", + "OpenSky auth missing": "Falta a autenticação do OpenSky", + "OpenSky auth required": "O OpenSky exige autenticação", + "OpenSky auth invalid": "Autenticação do OpenSky inválida", + "OpenSky auth failed": "Falha na autenticação do OpenSky", + "KartaView answered HTTP {status}": "O KartaView respondeu HTTP {status}", + "Panoramax answered HTTP {status}": "O Panoramax respondeu HTTP {status}", + "KartaView refused the request (code {code})": "O KartaView recusou a requisição (código {code})", + "Vector tiles unavailable (HTTP {status})": "Blocos vetoriais indisponíveis (HTTP {status})", + "GNSS feed unavailable (HTTP {status})": "Feed GNSS indisponível (HTTP {status})", + "{count} CelesTrak groups unavailable": { + "one": "{count} grupo do CelesTrak indisponível", + "many": "{count} de grupos do CelesTrak indisponíveis", + "other": "{count} grupos do CelesTrak indisponíveis" + }, + "{feed} feed unavailable": "Feed {feed} indisponível", + "Source snapshot {minutes} min old": "O snapshot da fonte tem {minutes} min", + "{source} rate limited (anonymous)": "{source}: limite de requisições (anônimo)", + "{source} rate limited": "{source}: limite de requisições", + "{source} network error": "{source}: erro de rede", + "Malformed {source} aircraft rows": "{source}: linhas de aeronaves malformadas", + "Malformed {source} response": "{source}: resposta malformada", + "entry {n}": "nº {n}", + "feeds {names} stale": { + "one": "feed {names} desatualizado", + "many": "feeds {names} desatualizados", + "other": "feeds {names} desatualizados" + }, + "feeds {names} unreachable": { + "one": "feed {names} inacessível", + "many": "feeds {names} inacessíveis", + "other": "feeds {names} inacessíveis" + }, + "feeds {names} invalid": { + "one": "feed {names} inválido", + "many": "feeds {names} inválidos", + "other": "feeds {names} inválidos" + }, + "Loading {feeds}": "Carregando {feeds}", + "{count} heard": { + "one": "{count} aeronave captada", + "many": "{count} de aeronaves captadas", + "other": "{count} aeronaves captadas" + }, + "USB {rate} msg/s": "USB {rate} msg/s", + "{rate} msg/s": "{rate} msg/s", + "{count} feeds live": { + "one": "{count} feed ao vivo", + "many": "{count} de feeds ao vivo", + "other": "{count} feeds ao vivo" + }, + "{feed} {count} ({seconds}s old)": "{feed} {count} (há {seconds} s)", + "Street Level toggle failed": "Não foi possível ativar ou desativar a camada Nível da rua", + "Street Level could not start": "Não foi possível iniciar Nível da rua", + "SHRINK": "REDUZIR", + "EXPAND": "AMPLIAR", + "Shrink": "Reduzir", + "Expand": "Ampliar", + "ANY DATE": "QUALQUER DATA", + "LAST 10 YEARS": "ÚLTIMOS 10 ANOS", + "LAST 5 YEARS": "ÚLTIMOS 5 ANOS", + "LAST 3 YEARS": "ÚLTIMOS 3 ANOS", + "LAST 2 YEARS": "ÚLTIMOS 2 ANOS", + "LAST YEAR": "ÚLTIMO ANO", + "LAST 6 MONTHS": "ÚLTIMOS 6 MESES", + "LAST 3 MONTHS": "ÚLTIMOS 3 MESES", + "LAST MONTH": "ÚLTIMO MÊS", + "LAST {count} DAYS": { + "one": "ÚLTIMO {count} DIA", + "many": "ÚLTIMOS {count} DE DIAS", + "other": "ÚLTIMOS {count} DIAS" + }, + "{window} · SINCE {date}": "{window} · DESDE {date}", + "Turn Street Level off": "Desativar Nível da rua", + "Turn Street Level on": "Ativar Nível da rua", + "{name} imagery on": "Imagens do {name} ativadas", + "{name} imagery off": "Imagens do {name} desativadas", + "Image by {creator}": "Imagem de {creator}", + " or ": " ou ", + "OPEN {labels}": "ABRIR {labels}", + "Open {names} at the centre of the view": "Abrir {names} no centro da vista", + "Zoom in to a street to open {names} here": "Aproxime o zoom de uma rua para abrir {names} aqui", + "Switch Street Level on to draw its coverage.": "Ative Nível da rua para desenhar a cobertura.", + "Every provider is switched off: light a chip to draw its coverage.": "Todos os provedores estão desligados: ative um para desenhar a cobertura dele.", + "Loading this sequence…": "Carregando esta sequência…", + "{n} images in this sequence · Esc clears": { + "one": "{n} imagem nesta sequência · Esc limpa a seleção", + "many": "{n} de imagens nesta sequência · Esc limpa a seleção", + "other": "{n} imagens nesta sequência · Esc limpa a seleção" + }, + "No sequences in view match the filter": "Nenhuma sequência na vista corresponde ao filtro", + "No coverage in view": "Sem cobertura na vista", + "{n} streets in view · click a line for its nearest photo": { + "one": "{n} rua na vista · clique em uma linha para ver a foto mais próxima", + "many": "{n} de ruas na vista · clique em uma linha para ver a foto mais próxima", + "other": "{n} ruas na vista · clique em uma linha para ver a foto mais próxima" + }, + "{n} sequences in view · click a line for its nearest photo": { + "one": "{n} sequência na vista · clique em uma linha para ver a foto mais próxima", + "many": "{n} de sequências na vista · clique em uma linha para ver a foto mais próxima", + "other": "{n} sequências na vista · clique em uma linha para ver a foto mais próxima" + }, + "{n} sequences in view · click a line for its photos": { + "one": "{n} sequência na vista · clique em uma linha para ver as fotos", + "many": "{n} de sequências na vista · clique em uma linha para ver as fotos", + "other": "{n} sequências na vista · clique em uma linha para ver as fotos" + }, + "km/h": "km/h", + "m/s": "m/s", + "mph": "mph", + "hPa": "hPa", + "kt": "kt", + "kts": "kt", + "ft": "ft", + "km": "km", + "m": "m", + "h": "h", + "min": "min", + "s": "s", + "dB": "dB", "Celestial ring — reveal the full globe": "Anel celeste — revelar o globo inteiro", "Celestial ring — available in Normal style": "Anel celeste — disponível no estilo Normal", "Detection overlay: {mode}": "Sobreposição de detecção: {mode}", "Detection overlay: off": "Sobreposição de detecção: desligada", "DETECT": "DETECÇÃO", + "{time} · {minutes} min ago": "{time} · há {minutes} min", + "Active weather": "Camadas de clima ativas", + "LATEST · newest per product": "MAIS RECENTE · último por produto", + "Forecast · valid {valid} · issued {issued}": "Previsão · válida {valid} · emitida {issued}", + "{detail} · Does not follow history": "{detail} · Não acompanha o histórico", + "Forecast · valid {valid}": "Previsão · válida {valid}", + "voice|OFF": "DESLIG.", + "voice|CONNECTING": "CONECT…", "voice|LISTENING": "OUVINDO", "voice|EXECUTING": "EXECUTANDO", + "voice|ERROR": "ERRO", + "Voice provider": "Provedor de voz", + "Changing provider reconnects voice if it is on.": "Mudar de provedor reconecta a voz se ela estiver ativa.", + "Voice Settings": "Configurações de voz", "AI AGENT": "AGENTE DE IA", "Voice model tier — applies next session": "Nível do modelo de voz — vale na próxima sessão", + "STD": "PADR.", "Estimated session cost": "Custo estimado da sessão", - "Voice control — activate to toggle voice; hold Space to speak": "Controle por voz — ative para alternar a voz; segure Espaço para falar", + "Voice control — activate to toggle voice; hold Space to speak": "Controle por voz — ative para ligar ou desligar a voz; segure Space para falar", + "ON/OFF": "LIGA/DESL.", "VOICE STANDBY": "VOZ EM ESPERA", "VOICE CONTROL": "CONTROLE POR VOZ", - "Hold Space to speak · tap Space to activate focused controls": "Segure Espaço para falar · toque em Espaço para ativar controles em foco", + "Hold Space to speak · tap Space to activate focused controls": "Segure Space para falar · toque em Space para acionar o controle em foco", + "VOICE": "VOZ", + "Preview": "Prévia", + "Settings": "Configurações", + "Close voice panel": "Fechar o painel de voz", + "Voice replies appear here.": "As respostas de voz aparecem aqui.", + "Voice assistant": "Assistente de voz", + "Dismiss voice card": "Fechar o cartão de voz", + "YOU": "VOCÊ", + "THIS": "ISTO", + "Plan": "Plano", + "Referenced items": "Itens citados", + "NOTES & SOURCES": "NOTAS E FONTES", + "Show Voice Preview": "Mostrar prévia de voz", + "Voice inactivity timeout": "Tempo limite de inatividade da voz", + "Minutes": "Minutos", + "Custom": "Personalizado", + "These preferences stay in this browser.": "Estas preferências ficam neste navegador.", "VOICE SYSTEM ERROR": "ERRO NO SISTEMA DE VOZ", "DISMISS": "DISPENSAR", "Check microphone permission and network access, then try again.": "Verifique a permissão do microfone e o acesso à rede, e tente novamente.", - "Release Space to send": "Solte Espaço para enviar", - "Hold Space to talk": "Segure Espaço para falar", + "Gemini returned an oversized audio chunk": "O Gemini retornou um trecho de áudio grande demais", + "Gemini returned an unsupported audio format": "O Gemini retornou um formato de áudio não suportado", + "Gemini returned an invalid audio sample rate": "O Gemini retornou uma taxa de amostragem de áudio inválida", + "Gemini returned incomplete PCM audio": "O Gemini retornou áudio PCM incompleto", + "This browser does not support Gemini microphone audio": "Este navegador não suporta áudio do microfone para o Gemini", + "Microphone audio processing failed": "Falha no processamento do áudio do microfone", + "Gemini audio playback fell behind. Reconnect to continue.": "A reprodução de áudio do Gemini atrasou. Reconecte para continuar.", + "Gemini token response did not include an ephemeral credential": "A resposta de token do Gemini não incluiu uma credencial temporária", + "Invalid Gemini connection endpoint": "Endpoint de conexão do Gemini inválido", + "Gemini voice could not connect. Try again.": "Não foi possível conectar a voz do Gemini. Tente novamente.", + "Gemini voice requires a same-origin app request": "A voz do Gemini exige uma requisição da mesma origem do app", + "Add a Gemini API key in Provider Settings": "Adicione uma chave de API do Gemini em Configurações de provedores", + "The Gemini Live model configuration is invalid": "A configuração do modelo do Gemini Live é inválida", + "Gemini voice is starting too often. Try again shortly.": "A voz do Gemini está sendo iniciada com frequência demais. Tente novamente em breve.", + "Gemini quota is unavailable. Try again later.": "A cota do Gemini está indisponível. Tente novamente mais tarde.", + "Gemini access was refused. Check the API key and model access.": "O acesso ao Gemini foi recusado. Verifique a chave de API e o acesso ao modelo.", + "Gemini Live is unavailable for the configured model.": "O Gemini Live não está disponível para o modelo configurado.", + "Token request is too large": "A requisição de token é grande demais", + "Use an empty JSON token request": "Use uma requisição de token com um objeto JSON vazio", + "Release Space to send": "Solte Space para enviar", + "Hold Space to talk": "Segure Space para falar", + "Voice command context is too large": "O contexto do comando de voz é grande demais", + "Gemini reliable transport exceeded its queue limit. Start voice again.": "A fila de envio confiável do Gemini excedeu o limite. Inicie a voz de novo.", + "Gemini reliable transport did not drain. Start voice again.": "A fila de envio confiável do Gemini não esvaziou. Inicie a voz de novo.", + "Gemini token request failed (HTTP {status})": "Falha na requisição de token do Gemini (HTTP {status})", + "Gemini token response did not include a valid model": "A resposta de token do Gemini não incluiu um modelo válido", + "Gemini token response did not include session settings": "A resposta de token do Gemini não incluiu as configurações da sessão", + "Gemini session settings do not match the input mode": "As configurações da sessão do Gemini não correspondem ao modo de entrada", "Requesting microphone": "Solicitando microfone", + "Gemini could not submit this input. Start voice again.": "O Gemini não conseguiu enviar esta entrada. Inicie a voz de novo.", + "Connecting to Gemini": "Conectando ao Gemini", "Ask or command": "Pergunte ou comande", + "Gemini returned an oversized message": "O Gemini retornou uma mensagem grande demais", + "Gemini Live connection failed. Check network access, then start voice again.": "Falha na conexão com o Gemini Live. Verifique o acesso à rede e inicie a voz de novo.", + "Gemini Live connection ended. Start voice again for a new conversation.": "A conexão com o Gemini Live terminou. Inicie a voz de novo para uma nova conversa.", + "Gemini Live could not start. Start voice again to request a fresh session.": "O Gemini Live não conseguiu iniciar. Inicie a voz de novo para pedir uma nova sessão.", + "Start voice again for a fresh token and a new conversation.": "Inicie a voz de novo para obter um novo token e começar outra conversa.", + "Start voice again to request a fresh session credential.": "Inicie a voz de novo para pedir uma nova credencial de sessão.", + "Microphone permission was denied. Allow microphone access and try again.": "A permissão do microfone foi negada. Permita o acesso ao microfone e tente novamente.", + "Gemini connection timed out. Try again.": "A conexão com o Gemini excedeu o tempo limite. Tente novamente.", + "Gemini voice could not start": "Não foi possível iniciar a voz do Gemini", + "Gemini did not finish the interrupted reply. Start voice again.": "O Gemini não concluiu a resposta interrompida. Inicie a voz de novo.", + "Gemini session expiring; finishing the current reply": "A sessão do Gemini vai expirar; concluindo a resposta atual", + "Gemini rejected the voice session. Start voice again to request a fresh session.": "O Gemini recusou a sessão de voz. Inicie a voz de novo para pedir uma nova sessão.", + "Start voice again for a fresh session credential. If it repeats, check Gemini model and API access.": "Inicie a voz de novo para obter uma nova credencial de sessão. Se isso se repetir, verifique o modelo do Gemini e o acesso à API.", + "Gemini action history is full. Start voice again for a fresh session.": "O histórico de ações do Gemini está cheio. Inicie a voz de novo para uma nova sessão.", + "Gemini requested too many simultaneous actions": "O Gemini pediu ações simultâneas demais", "Running command": "Executando comando", + "Voice text command is too long": "O comando de voz digitado é longo demais", + "Gemini voice is not connected": "A voz do Gemini não está conectada", + "Gemini interrupted input exceeded its buffer or wait limit. Start voice again.": "A entrada interrompida do Gemini excedeu o limite de buffer ou de espera. Inicie a voz de novo.", + "Gemini Live connection is expiring. Start voice again for a new conversation.": "A conexão com o Gemini Live vai expirar. Inicie a voz de novo para uma nova conversa.", "Voice off": "Voz desligada", + "Gemini voice sessions have a time limit. When a session expires, start voice again for a new conversation.": "As sessões de voz do Gemini têm limite de tempo. Quando uma sessão expirar, inicie a voz de novo para uma nova conversa.", + "Stopped by voice": "Parado por voz", + "Automatic stop is unavailable for this voice connection.": "A parada automática não está disponível para esta conexão de voz.", + "Preview is off.": "A prévia está desativada.", + "Your choice applies now, but could not be saved.": "Sua escolha vale agora, mas não pôde ser salva.", "WebRTC microphone support unavailable": "Suporte a microfone WebRTC indisponível", "VOICE UNAVAILABLE": "VOZ INDISPONÍVEL", "VOICE ACTIVE": "VOZ ATIVA", "Voice session could not be started.": "Não foi possível iniciar a sessão de voz.", + "MINI": "MINI", "Next session: {pendingId} — this session stays on {modelId}": "Próxima sessão: {pendingId} — esta sessão continua em {modelId}", "Voice model: {pendingId} — click to switch to {target}; applies next session": "Modelo de voz: {pendingId} — clique para mudar para {target}; vale na próxima sessão", + "standard": "padrão", + "mini": "mini", + "COST UNKNOWN": "CUSTO DESCONHECIDO", + "ChatGPT OAuth session: {responses} response(s), {input} input and {output} output tokens, {captions} caption transcription(s) reported.": "Sessão OAuth do ChatGPT (dados informados): {responses} resposta(s), {input} tokens de entrada e {output} de saída, {captions} transcrição(ões) de legendas.", + "USD cost and the API spend cap are unavailable for this auth mode.": "O custo em USD e o limite de gastos da API não estão disponíveis neste modo de autenticação.", + "Usage is incomplete because a response was still in flight when the session ended.": "O uso está incompleto porque uma resposta ainda estava em andamento quando a sessão terminou.", "Estimated session cost on {modelId} — {responses} response(s). Warns at {warn}, ends the session at {cap}.": "Custo estimado da sessão em {modelId} — {responses} resposta(s). Alerta em {warn}, encerra a sessão em {cap}.", + "Estimate is incomplete — a response was still in flight when the session ended, so its usage was never reported.": "A estimativa está incompleta — uma resposta ainda estava em andamento quando a sessão terminou, então o uso dela nunca foi informado.", + "STANDARD": "PADRÃO", "{tier} applies next session": "{tier} vale na próxima sessão", "Session ended — cost cap {cost}": "Sessão encerrada — limite de custo {cost}", + "MIC": "MIC", "Radio did not start": "O rádio não iniciou", + "{n} aircraft": { + "one": "{n} aeronave", + "many": "{n} de aeronaves", + "other": "{n} aeronaves" + }, + "{n} military aircraft": { + "one": "{n} aeronave militar", + "many": "{n} de aeronaves militares", + "other": "{n} aeronaves militares" + }, + "{n} ships": { + "one": "{n} embarcação", + "many": "{n} de embarcações", + "other": "{n} embarcações" + }, + "{n} satellites": { + "one": "{n} satélite", + "many": "{n} de satélites", + "other": "{n} satélites" + }, + "{n} launches": { + "one": "{n} lançamento", + "many": "{n} de lançamentos", + "other": "{n} lançamentos" + }, + "{n} earthquakes": { + "one": "{n} terremoto", + "many": "{n} de terremotos", + "other": "{n} terremotos" + }, + "{n} fires": { + "one": "{n} incêndio", + "many": "{n} de incêndios", + "other": "{n} incêndios" + }, + "{n} fire perimeters": { + "one": "{n} perímetro de incêndio", + "many": "{n} de perímetros de incêndio", + "other": "{n} perímetros de incêndio" + }, + "{n} cyclones": { + "one": "{n} ciclone", + "many": "{n} de ciclones", + "other": "{n} ciclones" + }, + "{n} buses": { + "one": "{n} ônibus", + "many": "{n} de ônibus", + "other": "{n} ônibus" + }, + "{n} bike share": { + "one": "{n} estação de bicicletas compartilhadas", + "many": "{n} de estações de bicicletas compartilhadas", + "other": "{n} estações de bicicletas compartilhadas" + }, + "{n} flock cameras": { + "one": "{n} câmera ALPR", + "many": "{n} de câmeras ALPR", + "other": "{n} câmeras ALPR" + }, + "{n} military bases": { + "one": "{n} base militar", + "many": "{n} de bases militares", + "other": "{n} bases militares" + }, + "{n} datacenters": { + "one": "{n} data center", + "many": "{n} de data centers", + "other": "{n} data centers" + }, + "{n} dams": { + "one": "{n} barragem", + "many": "{n} de barragens", + "other": "{n} barragens" + }, + "{n} air quality": { + "one": "{n} estação de qualidade do ar", + "many": "{n} de estações de qualidade do ar", + "other": "{n} estações de qualidade do ar" + }, + "{n} results": { + "one": "{n} resultado", + "many": "{n} de resultados", + "other": "{n} resultados" + }, + "anywhere in the loaded data": "em todos os dados carregados", + "in view": "na vista", + "within {radius} of the view centre": "em um raio de {radius} do centro da vista", + "within {radius} of {place} (Contacts window)": "em um raio de {radius} de {place} (janela de Contatos)", + "within {radius} of {place}": "em um raio de {radius} de {place}", + "within {radius}": "em um raio de {radius}", + "over {region}": "sobre {region}", + "At least {items}": "Pelo menos {items}", + "{items} {scope}": "{items} {scope}", + "last 24 h": "últimas 24 h", + "past 30 d and upcoming": "últimos 30 d e próximos", + "the flights layer loads by viewport": "a camada de voos carrega conforme a vista", + "distance is ground distance, not overhead": "a distância é medida no solo até o ponto subsatélite, não até o satélite", + "the count is a lower bound because at least one layer reached its retained limit.": "a contagem é um mínimo porque pelo menos uma camada atingiu o limite de retenção.", + "{label} off": "{label}: desativado", + "{label} loading": "{label}: carregando", + "{label} error": "{label}: erro", + "counted the first {returned} loaded records": "foram contados os primeiros {returned} registros carregados", + "counted {returned} of {total} loaded records": "foram contados {returned} de {total} registros carregados", + "{layers} just turned on — still loading, counts will rise": "{layers}: acabou de ser ativado — ainda carregando, as contagens vão subir", + "Contacts panel snapshot at {time} — the same retained cohort supplies the card, speech, and follow-up memory": "Snapshot do painel Contatos ({time}) — o mesmo grupo retido alimenta o cartão, a fala e a memória de acompanhamento", + "Contacts panel snapshot — the same retained cohort supplies the card, speech, and follow-up memory": "Snapshot do painel Contatos — o mesmo grupo retido alimenta o cartão, a fala e a memória de acompanhamento", + "Fly below {km} km to a covered region": "Desça abaixo de {km} km sobre uma região com cobertura", + "No feed here yet · {n} regions available": { + "one": "Ainda não há feed aqui · {n} região disponível", + "many": "Ainda não há feed aqui · {n} de regiões disponíveis", + "other": "Ainda não há feed aqui · {n} regiões disponíveis" + }, + "degraded": "degradado", + "stale": "desatualizado", + "partial": "parcial", + "fallback": "alternativo", + "unavailable": "indisponível", + "Not answered: {layers}": "Sem resposta: {layers}", + "Toggle voice control": "Alternar o controle por voz", + "Activate to toggle voice": "Ative para ligar ou desligar a voz", + "Voice active": "Voz ativa", + "Voice could not be started.": "Não foi possível iniciar a voz.", + "the active voice session": "a sessão de voz ativa", + "{value} feet": "{value} pés", + "Fire · FRP {frp} MW": "Incêndio · FRP {frp} MW", + "The flights layer is not enabled": "A camada de voos não está ativada", + "The military layer is not enabled": "A camada de voos militares não está ativada", + "The satellites layer is not enabled": "A camada de satélites não está ativada", + "The ais-live-vessels layer is not enabled": "A camada de embarcações AIS não está ativada", + "Could not enable the requested layer": "Não foi possível ativar a camada solicitada", + "Could not disable the requested layer": "Não foi possível desativar a camada solicitada", + "Radio layer unavailable": "A camada de rádio está indisponível", + "Camera navigation is unavailable in the current view": "A navegação da câmera não está disponível na vista atual", + "Camera navigation policy unavailable": "A política de navegação da câmera está indisponível", + "Nearest-aircraft selection supports Flights or Military Flights only": "A seleção da aeronave mais próxima só funciona com voos ou voos militares", + "Nearest-aircraft selection needs a preset, place name, or latitude and longitude": "Para selecionar a aeronave mais próxima é preciso uma predefinição, um nome de lugar ou a latitude e a longitude", + "Could not arrive at the requested place": "Não foi possível chegar ao lugar solicitado", + "The nearest airborne aircraft could not be selected": "Não foi possível selecionar a aeronave em voo mais próxima", + "No flights within {radius} of the current view": "Nenhum voo em um raio de {radius} da vista atual", + "No military within {radius} of the current view": "Nenhum voo militar em um raio de {radius} da vista atual", + "No satellites within {radius} of the current view": "Nenhum satélite em um raio de {radius} da vista atual", + "No vessels within {radius} of the current view": "Nenhuma embarcação em um raio de {radius} da vista atual", + "{layer} is enabled on the {source} feed, but no airborne aircraft is loaded in the {place} view yet": "A camada {layer} está ativada com o feed {source}, mas ainda não há aeronaves em voo carregadas na vista de {place}", + "{layer} is enabled, but no airborne aircraft is loaded in the {place} view yet": "A camada {layer} está ativada, mas ainda não há aeronaves em voo carregadas na vista de {place}", + "{layer} is enabled, but its aircraft feed is unavailable": "A camada {layer} está ativada, mas o feed de aeronaves dela está indisponível", + "{layer} is enabled, but its destination refresh did not complete": "A camada {layer} está ativada, mas a atualização no destino não foi concluída", + "{layer} is enabled, but {source} is unavailable": "A camada {layer} está ativada, mas {source} está indisponível", + "Could not arrive at {place}": "Não foi possível chegar a {place}", + "{name} is no longer loaded": "{name} não está mais carregado", + "Unknown target layer: {target}": "Camada de destino desconhecida: {target}", + "nominal": "nominal", + "{label} on": "{label}: ativado", + "Frame aircraft": "Enquadrar aeronaves", + "Frame military aircraft": "Enquadrar aeronaves militares", + "Frame ships": "Enquadrar embarcações", + "Frame satellites": "Enquadrar satélites", + "Frame contacts": "Enquadrar contatos", + "{count} aircraft in frame": { + "one": "{count} aeronave no enquadramento", + "many": "{count} de aeronaves no enquadramento", + "other": "{count} aeronaves no enquadramento" + }, + "{count} military aircraft in frame": { + "one": "{count} aeronave militar no enquadramento", + "many": "{count} de aeronaves militares no enquadramento", + "other": "{count} aeronaves militares no enquadramento" + }, + "{count} ships in frame": { + "one": "{count} embarcação no enquadramento", + "many": "{count} de embarcações no enquadramento", + "other": "{count} embarcações no enquadramento" + }, + "{count} satellites in frame": { + "one": "{count} satélite no enquadramento", + "many": "{count} de satélites no enquadramento", + "other": "{count} satélites no enquadramento" + }, + "{count} contacts in frame": { + "one": "{count} contato no enquadramento", + "many": "{count} de contatos no enquadramento", + "other": "{count} contatos no enquadramento" + }, + "Nearest military aircraft": "Aeronaves militares mais próximas", + "Nearest ships": "Embarcações mais próximas", + "Nearest satellites": "Satélites mais próximos", + "Nearest aircraft": "Aeronaves mais próximas", + "{first} and {second}": "{first} e {second}", + "Layer": "Camada", + "there": "lá", + "Camera range {range}": "Distância da câmera {range}", + "Within {radius} of the view": "Em um raio de {radius} da vista", + "Labels on": "Rótulos ativados", + "Framing uses the nearest 80 loaded contacts": "O enquadramento usa os 80 contatos carregados mais próximos", + "{distance} from {location}": "A {distance} de {location}", + "Altitude {altitude}": "Altitude {altitude}", + "{origin} to {destination}": "De {origin} para {destination}", + "from {origin}": "de {origin}", + "to {destination}": "para {destination}", + "Registration {registration}": "Matrícula {registration}", + "View state": "Estado da vista", + "Marked {count} places": { + "one": "{count} lugar marcado", + "many": "{count} de lugares marcados", + "other": "{count} lugares marcados" + }, + "Nothing marked": "Nada marcado", + "Not found: {places}": "Não encontrado: {places}", + "Tracing outlines": "Traçando contornos", + "Frame flights": "Enquadrar voos", + "Frame military": "Enquadrar voos militares", + "Frame vessels": "Enquadrar embarcações", + "Frame {target}": "Enquadrar {target}", + "Zoom out to globe": "Afastar até o globo", + "Open data layers": "Abrir as camadas de dados", + "Open or close a panel": "Abrir ou fechar um painel", + "Change context mode": "Mudar o modo de contexto", + "Control cockpit": "Controlar a cabine", + "Change visual style": "Mudar o estilo visual", + "Adjust HUD": "Ajustar o HUD", + "Adjust cyber sonar": "Ajustar o sonar Ciber", + "Adjust detection overlay": "Ajustar a sobreposição de detecção", + "Change map stack": "Mudar a pilha de mapas", + "Adjust post-processing": "Ajustar o pós-processamento", + "Control scene": "Controlar a cena", + "Control CCTV": "Controlar as câmeras CCTV", + "Control radio": "Controlar o rádio", + "Track contact": "Rastrear o contato", + "Stop tracking": "Parar o rastreamento", + "Clear marks": "Limpar as marcações", + "Move camera": "Mover a câmera", + "Fly route": "Percorrer a rota", + "Analyst query": "Consulta analítica", + "Next ISS pass": "Próxima passagem da ISS", + "Next satellite pass": "Próxima passagem do satélite", + "Mark the map": "Marcar o mapa", + "Mark {targets} +{more}": "Marcar {targets} +{more}", + "Mark {targets}": "Marcar: {targets}", + "Fly to {place}": "Voar até {place}", + "Fly to Location": "Voar até o local", + "Nearest aircraft to {place}": "Aeronave mais próxima de {place}", + "Nearest aircraft to Here": "Aeronave mais próxima daqui", + "Layer on": "Camada: ativada", + "Layer off": "Camada: desativada", + "Zoom out": "Afastar", + "Zoom in": "Aproximar", + "Read the view": "Consultar a vista", + "Check view state": "Verificar o estado da vista", + "Action": "Ação", + "Finding places": "Buscando lugares", + "Tracing outline": "Traçando contorno", + "Looking up place": "Buscando lugar", + "Flying": "Voando", + "Turning on layer": "Ativando camada", + "Loading aircraft": "Carregando aeronaves", + "Picking nearest": "Escolhendo a mais próxima", + "Working": "Processando", + "in progress": "em andamento", + "done": "concluído", + "failed": "falhou", + "cancelled": "cancelado", + "Outline traced": "Contorno traçado", + "Outline unavailable": "Contorno indisponível", + "Source: {label}": "Fonte: {label}", + "WORKING": "EM ANDAMENTO", + "DONE": "CONCLUÍDO", + "Recent speech": "Fala recente", + "HERE": "AQUI", "Aircraft cockpit view": "Vista da cabine da aeronave", "LEVEL": "NÍVEL", "Estimated destination direction": "Direção estimada do destino", @@ -692,15 +2712,21 @@ "Next vision style": "Próximo estilo de visão", "Current aircraft heading": "Rumo atual da aeronave", "GROUND SPEED": "VELOC. SOLO", + "KTS": "KT", "ALTITUDE": "ALTITUDE", + "FT": "FT", "Contact cockpit summary": "Resumo do contato na cabine", "CONTACT": "CONTATO", "CONTACTS · 250 KM": "CONTATOS · 250 KM", "Contact navigation": "Navegação de contatos", "CONTEXT ONLY": "SÓ CONTEXTO", "Nearby cohort counts": "Contagem de grupos próximos", + "FLT": "FLT", + "MIL": "MIL", + "SITE": "LOCAIS", "NEAREST OBSERVED / MAPPED": "MAIS PRÓXIMO OBSERVADO / MAPEADO", "AVAILABLE INPUTS ONLY · NOT AN ALL-CLEAR": "SÓ ENTRADAS DISPONÍVEIS · NÃO GARANTE SEGURANÇA", + "WX": "WX", "Cockpit briefing carousel": "Carrossel de briefing da cabine", "Estimated flight plan": "Plano de voo estimado", "ESTIMATED FLIGHT PLAN": "PLANO DE VOO ESTIMADO", @@ -716,9 +2742,14 @@ "WIND": "VENTO", "SKY": "CÉU", "PRECIP": "PRECIP", + "MM": "MM", + "Weather data by Open-Meteo.com": "Dados meteorológicos do Open-Meteo.com", + "Cockpit briefing pages": "Páginas do briefing da cabine", + "SIG": "SIG", "Show Live Signals": "Mostrar sinais ao vivo", "NEWS": "NOTÍCIAS", "Show Regional News": "Mostrar notícias regionais", + "LOCAL": "LOCAL", "Show Local Info": "Mostrar informações locais", "Cockpit display and Radio controls": "Controles de exibição e rádio da cabine", "DISPLAY": "EXIBIÇÃO", @@ -730,6 +2761,8 @@ "Next filtered radio station": "Próxima estação de rádio filtrada", "VOLUME": "VOLUME", "Cockpit Radio volume": "Volume do rádio da cabine", + "ESC EXIT": "ESC SAIR", + "C TOGGLE": "C ALTERNAR", "View switcher": "Alternador de vista", "Exit cockpit and return to full globe view": "Sair da cabine e voltar à vista do globo completo", "RESET": "REDEFINIR", @@ -757,6 +2790,9 @@ "Search location by name or coordinates": "Buscar local por nome ou coordenadas", "Search any location...": "Buscar qualquer local...", "WEATHER": "CLIMA", + "Active weather products": "Produtos meteorológicos ativos", + "RECENT IMAGERY": "IMAGENS RECENTES", + "Imagery days in the box": "Dias com imagens na área", "CONTEXT": "CONTEXTO", "Compact Radio controls": "Controles compactos do rádio", "Open detailed Radio controls": "Abrir controles detalhados do rádio", @@ -779,13 +2815,14 @@ "AVAILABLE MISSIONS": "MISSÕES DISPONÍVEIS", "SELECT A MISSION TO INSPECT": "SELECIONE UMA MISSÃO PARA INSPECIONAR", "LOADING 30-DAY MISSION INDEX": "CARREGANDO ÍNDICE DE MISSÕES DE 30 DIAS", - "TAB PREVIEWS · ENTER / SPACE SELECTS": "TAB PRÉVIA · ENTER / ESPAÇO SELECIONA", + "TAB PREVIEWS · ENTER / SPACE SELECTS": "TAB MOSTRA PRÉVIA · ENTER / SPACE SELECIONA", "Internet radio and local SDR": "Rádio pela internet e SDR local", "STATION TAG": "TAG DA ESTAÇÃO", "Filter stations by station tag": "Filtrar estações por tag", "All": "Todas", - "Enable Radio, then choose a globe marker or use next.": "Ative o rádio e escolha um marcador no globo ou use próxima.", + "Enable Radio, then choose a globe marker or use next.": "Ative o rádio e escolha um marcador no globo ou use Próxima.", "DRAG TO TUNE": "ARRASTE PARA SINTONIZAR", + "Tune available internet radio stations": "Sintonizar as estações de rádio pela internet disponíveis", "ALL · DRAG THE NEEDLE": "TODAS · ARRASTE A AGULHA", "SNAPS TO AVAILABLE STATIONS": "AJUSTA ÀS ESTAÇÕES DISPONÍVEIS", "Radio playback": "Reprodução do rádio", @@ -796,13 +2833,48 @@ "Stop radio playback": "Parar a reprodução do rádio", "Radio volume": "Volume do rádio", "STATION SITE": "SITE DA ESTAÇÃO", + "DIRECTORY: RADIO BROWSER": "DIRETÓRIO: RADIO BROWSER", "Audio connects directly to the broadcaster after you press play. Your IP is visible to that broadcaster.": "O áudio conecta direto à emissora depois que você aperta play. Seu IP fica visível para essa emissora.", + "Local RTL-SDR receiver": "Receptor RTL-SDR local", + "LOCAL RTL-SDR": "RTL-SDR LOCAL", + "Chrome/Edge · WebUSB · one local tuner shared by FM and the Local ADS-B layer.": "Chrome/Edge · WebUSB · um sintonizador local compartilhado entre o FM e a camada ADS-B local.", + "Use your location for faster ADS-B position decoding": "Use sua localização para decodificar as posições ADS-B mais rápido", + "CHANGE DEVICE": "TROCAR", + "Choose a different RTL-SDR or receiver channel": "Escolha outro RTL-SDR ou outro canal do receptor", + "RTL-SDR receiver mode": "Modo do receptor RTL-SDR", + "GAIN": "GANHO", + "RTL-SDR tuner gain for the current mode": "Ganho do sintonizador RTL-SDR para o modo atual", + "AUTO": "AUTO", + "MSG/S": "MSG/S", + "HEARD": "CAPTADAS", + "POSITIONED": "POSICIONADAS", + "FM MHZ": "FM MHZ", + "TUNE": "SINTONIZAR", + "Seek broadcast FM stations": "Buscar estações de rádio FM", + "◀ SEEK": "◀ BUSCAR", + "SEEK ▶": "BUSCAR ▶", + "SDR VOL": "VOL. SDR", + "Local SDR volume": "Volume do SDR local", "Intelligence HUD (H)": "HUD de inteligência (H)", "Layout": "Layout", "HUD layout": "Layout do HUD", "Tactical": "Tático", "Operator": "Operador", "Minimal": "Mínimo", + "Cyber": "Ciber", + "Sonar": "Sonar", + "Cyber sonar contact scanner": "Scanner de contatos do sonar Ciber", + "Rings": "Anéis", + "Sonar ring count": "Número de anéis do sonar", + "Range": "Alcance", + "Sonar ring range": "Alcance dos anéis do sonar", + "Power": "Potência", + "Sonar intensity": "Intensidade do sonar", + "Opacity": "Opacidade", + "Cyber contact and label opacity": "Opacidade de contatos e rótulos Ciber", + "Minimum opacity for map dots, icons, models, brackets, and labels between sonar passes": "Opacidade mínima de pontos, ícones, modelos, colchetes e rótulos do mapa entre as passagens do sonar", + "Sector": "Setor", + "Sonar sector width": "Largura do setor do sonar", "Detection Overlay (D)": "Sobreposição de detecção (D)", "Detection overlay": "Sobreposição de detecção", "Detection label density": "Densidade dos rótulos de detecção", @@ -810,9 +2882,9 @@ "Detection label allocation": "Alocação dos rótulos de detecção", "Elastic": "Elástica", "Weighted": "Ponderada", - "Fade": "Esmaecer", + "Fade": "Esmaecimento", "Detection fade distance": "Distância de esmaecimento da detecção", - "World-overlay fade distance outside the keyhole as a percentage of its radius": "Distância de esmaecimento da sobreposição no mundo fora do visor, como porcentagem do seu raio", + "World-overlay fade distance outside the keyhole as a percentage of its radius": "Distância de esmaecimento da sobreposição fora do visor, em porcentagem do raio dele", "Outside": "Fora", "Detection opacity outside the keyhole": "Opacidade da detecção fora do visor", "World-overlay label and card opacity beyond the fade distance": "Opacidade de rótulos e cartões da sobreposição além da distância de esmaecimento", @@ -821,11 +2893,31 @@ "Models": "Modelos", "3D model coverage": "Cobertura de modelos 3D", "Proximity": "Proximidade", - "Scope — the circular viewport mask": "Mira — a máscara circular da janela de visualização", + "Scope — the circular viewport mask": "Mira — a máscara circular da vista", "Scope": "Mira", - "Feather": "Suavizar", + "Feather": "Suavização", "Scope edge feather": "Suavização da borda da mira", - "Scope edge feather as a percentage of the keyhole radius": "Suavização da borda da mira, como porcentagem do raio do visor", + "Scope edge feather as a percentage of the keyhole radius": "Suavização da borda da mira, em porcentagem do raio do visor", + "Draw on the world — click vertices, double-click or Enter to finish, Esc to cancel": "Desenhe sobre o mundo — clique nos vértices, clique duplo ou Enter para concluir, Esc para cancelar", + "Shape": "Forma", + "Shape to draw": "Forma a desenhar", + "Area": "Área", + "Line": "Linha", + "Pin": "Marcador", + "Label (optional)": "Rótulo (opcional)", + "Label for the drawn shape": "Rótulo da forma desenhada", + "Colour of the drawn shape": "Cor da forma desenhada", + "Primary": "Principal", + "Amber": "Âmbar", + "Cyan": "Ciano", + "Green": "Verde", + "Red": "Vermelho", + "Clear": "Limpar", + "Remove every mark from the board": "Remover todas as marcações do quadro", + "Show your own GeoJSON, KML, KMZ or GPX files on the globe (or drop them onto it). File bytes stay on this device; overlays can appear in map screenshots shared with voice.": "Mostre no globo seus próprios arquivos GeoJSON, KML, KMZ ou GPX (ou solte-os sobre ele). Os arquivos não saem deste dispositivo; as sobreposições podem aparecer em capturas do mapa compartilhadas com a voz.", + "Import": "Importar", + "Choose GeoJSON, KML, KMZ or GPX files": "Escolha arquivos GeoJSON, KML, KMZ ou GPX", + "Imported files": "Arquivos importados", "Celestial": "Celeste", "Hide UI chrome": "Ocultar a interface", "Clean UI": "Interface limpa", @@ -838,6 +2930,7 @@ "Return UI controls": "Restaurar controles da interface", "Initializing photorealistic world...": "Inicializando o mundo fotorrealista...", "DATA LAYERS": "CAMADAS DE DADOS", + "ACQUIRING FRAME": "OBTENDO QUADRO", "NEAREST": "MAIS PRÓX.", "CCTV camera": "Câmera de CCTV", "CALIBRATION": "CALIBRAÇÃO", @@ -853,6 +2946,26 @@ "SAVE CAL": "SALVAR CAL", "RESET CAL": "REDEFINIR CAL", "SCENE SUMMARY": "RESUMO DA CENA", + "STREET LEVEL": "NÍVEL DA RUA", + "Turn Street Level on or off": "Ativar ou desativar Nível da rua", + "Show the street-level view full screen (Esc shrinks it)": "Mostrar a vista no nível da rua em tela cheia (Esc reduz)", + "Image fit": "Ajuste da imagem", + "FIT": "AJUSTAR", + "Fit: show the whole photo, with dark bars where its shape differs from the frame": "Ajustar: mostra a foto inteira, com barras escuras onde o formato dela difere do quadro", + "FILL": "PREENCHER", + "Fill: fill the frame edge to edge, cropping the photo": "Preencher: preenche o quadro de ponta a ponta, cortando a foto", + "Close the image and deselect it on the map": "Fechar a imagem e desmarcá-la no mapa", + "Close the street-level image": "Fechar a imagem no nível da rua", + "Street-level viewer": "Visualizador no nível da rua", + "Open this image on the provider's site": "Abrir esta imagem no site do provedor", + "Imagery providers": "Provedores de imagens", + "PROVIDERS": "PROVEDORES", + "Imagery filters": "Filtros de imagens", + "IMAGERY": "IMAGENS", + "Panorama filter": "Filtro de panoramas", + "ALL": "TODAS", + "FLAT": "PLANAS", + "SINCE": "DESDE", "SCENES": "CENAS", "Scene recipe": "Receita de cena", "NEW": "NOVA", @@ -875,6 +2988,9 @@ "Globe actions": "Ações do globo", "Turn off all selected data layers": "Desativar todas as camadas de dados selecionadas", "Copy share link": "Copiar link de compartilhamento", + "Toggle straight-down and tilted map views": "Alternar entre a vista de cima e a vista inclinada do mapa", + "Reset map to north up": "Orientar o mapa com o norte para cima", + "Reset map bearing to north": "Redefinir a orientação do mapa para o norte", "Reset camera and return to full globe view": "Redefinir a câmera e voltar à vista do globo completo", "MISSION CONTROL · FIRST LAUNCH": "CENTRO DE CONTROLE · PRIMEIRO ACESSO", "Choose your first view": "Escolha sua primeira vista", diff --git a/src/i18n/same-as-english.json b/src/i18n/same-as-english.json index 83c8897d8..920016262 100644 --- a/src/i18n/same-as-english.json +++ b/src/i18n/same-as-english.json @@ -124,6 +124,131 @@ "ΔN", "▲ {frp} MW" ], + "pt": [ + "1090 MHz", + "978 MHz UAT", + "AIS: --", + "AIS: {name}", + "ALTITUDE", + "ALTITUDE · FT", + "ANIME", + "AUTO", + "Altitude {altitude}", + "Anime", + "Austin", + "BIKE", + "BRG {value}°", + "BRG —", + "Bloom", + "Blues", + "CAL {value}", + "CAL · {badge}", + "CCTV", + "CRS {value}°", + "CRT", + "Country", + "DEST ---°", + "DEST {bearing}", + "Dance", + "Drone", + "Dubai", + "ENE", + "ESE", + "FLIR", + "FLT", + "FM MHZ", + "FOV", + "FOV {value}°", + "FT", + "Folk", + "Funk", + "GEO", + "GOOGLE STREET VIEW", + "Global", + "Global · 60°S–60°N", + "Google Street View", + "HDG", + "HDG {value}°", + "Hip-Hop", + "House", + "Indie", + "Ironbow", + "Jazz", + "LOCAL", + "Landsat 8/9", + "Landsat 8/9 via HLS", + "Layout", + "Los Angeles", + "MIC", + "MIL", + "MINI", + "MM", + "MONITOR", + "MSG/S", + "Metal", + "NAV", + "NE", + "NNE", + "NOIR", + "NORMAL", + "NVG", + "Noir", + "Normal", + "OCEANIA", + "OK", + "POS: {time}Z", + "PRECIP", + "Paris", + "Pop", + "Punk", + "RANGE", + "Reggae", + "Rock", + "S2 GhostMaps", + "SAR", + "SE", + "SIG", + "SNAPSHOT", + "SQUAWK {code} · {status}", + "SSE", + "STATUS", + "STATUS · ", + "Sentinel-2", + "Sentinel-2 via HLS", + "Sonar", + "Soul", + "TAGS · {tags}", + "TEMP", + "Tallinn", + "Techno", + "Trance", + "USB {rate} msg/s", + "VISUAL", + "VOLUME", + "VS", + "WHOT/BHOT", + "WX", + "dB", + "fire confidence|nominal", + "ft", + "hPa", + "installation class|BASE", + "km", + "km/h", + "kt", + "min", + "mini", + "mph", + "nominal", + "view band|GLOBAL", + "{rate} msg/s", + "{type} SPD: {speed} HDG: {heading}", + "{value} KM", + "{value} KM/H", + "{value} KM/S", + "ΔN", + "▲ {frp} MW" + ], "ru": [ "AIS: --", "AIS: {name}", diff --git a/src/ui/localePicker.test.mjs b/src/ui/localePicker.test.mjs index 057642827..660eacaf1 100644 --- a/src/ui/localePicker.test.mjs +++ b/src/ui/localePicker.test.mjs @@ -40,7 +40,7 @@ test('the current language comes first, the rest by their own names', () => { nativeNames: LOCALE_NAMES, }), ), - ['ru', 'en', 'es', 'zh-CN', 'zh-Hant'], + ['ru', 'en', 'es', 'pt', 'zh-CN', 'zh-Hant'], ); assert.deepEqual( codes( @@ -50,7 +50,7 @@ test('the current language comes first, the rest by their own names', () => { nativeNames: LOCALE_NAMES, }), ), - ['es', 'en', 'ru', 'zh-CN', 'zh-Hant'], + ['es', 'en', 'pt', 'ru', 'zh-CN', 'zh-Hant'], ); assert.deepEqual( codes( @@ -60,7 +60,7 @@ test('the current language comes first, the rest by their own names', () => { nativeNames: LOCALE_NAMES, }), ), - ['en', 'es', 'ru', 'zh-CN', 'zh-Hant'], + ['en', 'es', 'pt', 'ru', 'zh-CN', 'zh-Hant'], ); const rows = buildLocaleOptions({ locales: MANY, From dfa7ac98a7741804d63cb06751c3d81a09cc6701 Mon Sep 17 00:00:00 2001 From: German Khokhlov Date: Wed, 28 Oct 2026 12:53:49 +0400 Subject: [PATCH 10/83] i18n(de): complete and ship German MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Translate the remaining 1,868 strings in a neutral infinitive style (no Sie/du), with German compounds, decimal commas and CLDR one/other plurals. - Review the #908 entries: knots are kn everywhere, the avionics codes BRG, CRS and DEST stay English like HDG and SPD, expand/collapse is ausklappen/einklappen, the radio toggle reads EIN/AUS, density SPARSE is DÜNN, the Thermal style is Wärmebild, German quotes in the shot prompt. - Register de: catalog, LOCALES, LOCALE_NAMES (Deutsch), package boundaries, same-as-english (codes, product names, music genres, units). - Tests: picker order and keyboard model with Deutsch, de/de-AT/de_CH normalization, browser de-DE resolves to German. - docs/translations/de.md: style, plurals, units and glossary; TRANSLATORS.md and CURRENT-STATE.md list German. Co-Authored-By: Claude Opus 5.5 --- docs/CURRENT-STATE.md | 2 +- docs/TRANSLATORS.md | 4 +- docs/translations/de.md | 90 ++ scripts/package-boundaries.json | 43 + src/i18n/i18n.test.mjs | 15 +- src/i18n/index.js | 9 +- src/i18n/locale.js | 11 +- src/i18n/locales/de.json | 2090 ++++++++++++++++++++++++++++++- src/i18n/same-as-english.json | 164 +++ src/ui/localePicker.test.mjs | 11 +- 10 files changed, 2409 insertions(+), 30 deletions(-) create mode 100644 docs/translations/de.md diff --git a/docs/CURRENT-STATE.md b/docs/CURRENT-STATE.md index c55031a6a..ec85b9c39 100644 --- a/docs/CURRENT-STATE.md +++ b/docs/CURRENT-STATE.md @@ -3733,7 +3733,7 @@ test:track` 43 tracking invariants · headless QA harnesses under ### Interface localization (October 2026) -Shipped locales: **en** (source and fallback), **es**, **ru**, **zh-CN** and **zh-Hant**. The code lives in +Shipped locales: **en** (source and fallback), **de**, **es**, **ru**, **zh-CN** and **zh-Hant**. The code lives in `src/i18n/`. How to mark UI text: [`docs/I18N.md`](./I18N.md); translator workflow: [`docs/TRANSLATORS.md`](./TRANSLATORS.md). diff --git a/docs/TRANSLATORS.md b/docs/TRANSLATORS.md index 830ca155e..2768eaa49 100644 --- a/docs/TRANSLATORS.md +++ b/docs/TRANSLATORS.md @@ -1,6 +1,6 @@ # Translating God's Eye View -Shipped languages: **English** (source and fallback), **Spanish** (`es`), **Russian** (`ru`), **Simplified Chinese** (`zh-CN`) and **Traditional Chinese** (`zh-Hant`). +Shipped languages: **English** (source and fallback), **German** (`de`), **Spanish** (`es`), **Russian** (`ru`), **Simplified Chinese** (`zh-CN`) and **Traditional Chinese** (`zh-Hant`). ## How it works @@ -63,4 +63,4 @@ These are contracts, not copy: layer ids and registry keys, status enums and oth ## Language notes -Each language keeps its glossary, plural forms, units and style in its own file, `docs/translations/.md`: [Spanish](./translations/es.md), [Russian](./translations/ru.md), [Simplified Chinese](./translations/zh-CN.md), [Traditional Chinese](./translations/zh-Hant.md). Read it before translating, and add a term there when you settle on one. +Each language keeps its glossary, plural forms, units and style in its own file, `docs/translations/.md`: [German](./translations/de.md), [Spanish](./translations/es.md), [Russian](./translations/ru.md), [Simplified Chinese](./translations/zh-CN.md), [Traditional Chinese](./translations/zh-Hant.md). Read it before translating, and add a term there when you settle on one. diff --git a/docs/translations/de.md b/docs/translations/de.md new file mode 100644 index 000000000..a66141a58 --- /dev/null +++ b/docs/translations/de.md @@ -0,0 +1,90 @@ +# German (`de`) + +Catalog: `src/i18n/locales/de.json`. General rules: [TRANSLATORS.md](../TRANSLATORS.md). + +Translation source: abiyeenzo (#908). + +## Style + +- Standard German that reads naturally in Germany, Austria and Switzerland; ß where it belongs (Straße, schließen), no Swiss ss. +- No direct address: neither «Sie» nor «du». Actions and hints use the neutral infinitive: «Erneut versuchen», «Kamera anklicken zum Aktivieren», «Zuerst eine Aufnahme wählen», «Mikrofonzugriff erlauben und erneut versuchen». "Your" becomes the article or «eigene»: «Eigener RTL-SDR-Empfänger», «Die IP-Adresse ist für diesen Sender sichtbar». +- Nouns are capitalized, as German requires; otherwise sentence case, not Title Case: "Live Flights" → «Live-Flüge», "Provider Settings" → «Anbieter-Einstellungen». UPPERCASE English stays UPPERCASE: «LIVE-DATEN AUS», «KEINE ENTWARNUNG». In UPPERCASE, ß is written SS: «SCHLIESSEN», «STRASSENEBENE». +- Compounds are written as one word or with a hyphen next to a name, code or English term: «Datenebene», «Wetterkacheln», «TomTom-Schlüssel», «AIS-Schiffe», «Street-View-Fallback». Do not split them with spaces. +- Short labels, chips and HUD readouts stay short. German runs about a third longer than English, so prefer a short word or a standard abbreviation with a period over a wrapped line: REICHW., GESCHW., NIEDERSCHL., SONST., NACHR., VERST., VGL., KAL. +- The avionics codes HDG, BRG, CRS, DEST, SPD, ALT, GS, TRK, V/S, FOV and SQUAWK stay in English, as in the cockpit. Words used in a sentence are translated: heading → «Kurs», bearing → «Peilung», range → «Reichweite». +- A dash between clauses is a spaced en dash « – »; a colon is fine where it explains: «Feed ausgefallen – langsame Wiederholung», «SIMULIERT: Verkehrsdienst nicht erreichbar». Quotes are „…“. +- Keyboard keys are named as on German keyboards where they differ: Leertaste, Rücktaste, Umschalt; Esc, Enter, Tab and letter keys stay. +- Decimal comma in fixed text: «M4,4», «28,2710° N». Thousands separator is a period: «1.000 km». Formatted numbers come from `Intl` and are already German. +- Units: km, m, km/h, m/s, kn (knots, also in the cockpit), ft (feet), hPa, MW, h, min, s, T (days, in short readouts); in UPPERCASE text KM, KM/H, KN, FT, MIN. A space between number and unit: «{value} m», «{count} min», «50 %». `°` sticks to the number. +- "ago" goes before the time: «vor {count} min», «vor {value}». When a placeholder already holds a localized "ago" text (`{age}` in `STALE · cached {age}`, `{ago}`), do not add «vor» again. +- Compass points use O for Ost: N, NNO, NO, ONO, O, OSO, SO, SSO, S, SSW, SW, WSW, W, WNW, NW, NNW; hemisphere letters N, S, O, W. +- Routing: direction words are lowercase adverbs (links, leicht rechts, scharf links, geradeaus), so a sentence never starts with one: «Auf {road} {direction} abbiegen», «Dann {direction} abbiegen», «Weiter {direction}». Roundabout exits are ordinals with a period: «die {exit} Ausfahrt» → «die 2. Ausfahrt». + +## Plurals + +A `tn()` entry needs two forms. `Intl.PluralRules('de')` picks: + +| Form | Counts | Example | +| ------- | --------------------------- | --------- | +| `one` | 1 | 1 Kamera | +| `other` | everything else: 0, 2, 1,5… | 3 Kameras | + +Keep the verb in agreement: «{count} Station meldet» / «{count} Stationen melden». Abbreviated units and codes do not change: «{count} NACHR.», «{count} EMPFANGEN». + +## Glossary + +| English | Deutsch | +| ---------------------------------------------- | -------------------------------------------------------------------- | +| layer / data layer | Ebene / Datenebene | +| feed / source / data source | Feed / Quelle / Datenquelle | +| LIVE (status) / live data | LIVE / Live-Daten | +| SIMULATED | SIMULIERT | +| stale / degraded / unavailable | veraltet / eingeschränkt / nicht verfügbar | +| retry / retrying | neuer Versuch / erneut versuchen | +| fallback | Fallback | +| key (API key) / POWER UP / POWERED UP | Schlüssel / STARTKLAR / HOCHGEFAHREN | +| Provider Settings | Anbieter-Einstellungen | +| ON / OFF (state chips) | EIN / AUS | +| enable / disable | aktivieren / deaktivieren | +| globe / map / map source / map stack / basemap | Globus / Karte / Kartenquelle / Kartenstapel / Basiskarte | +| aircraft / flight / military flights | Luftfahrzeug (HUD and short labels: Flugzeug) / Flug / Militärflüge | +| vessel, ship | Schiff | +| satellite / shell (Starlink) / DENSE | Satellit / Schale / DICHT | +| launch (rocket) / launch site / space mission | Start / Startplatz / Raummission | +| ascent / replay / payload / stage / downrange | Aufstieg / Replay, Wiedergabe / Nutzlast / Stufe / Downrange | +| contact / tracking | Kontakt / Verfolgung | +| installation / site | Anlage / Standort | +| mapped / observed | kartiert / beobachtet | +| camera / CCTV camera / camera badge | Kamera / CCTV-Kamera / Kamera-Markierung | +| earthquake / active fire / fire perimeter | Erdbeben / aktiver Brand / Brandgrenze | +| cyclone / advisory (NHC/CPHC) / cone | Wirbelsturm / Warnung / Kegel | +| radio station | Sender | +| broadcast FM | UKW | +| road / flow (traffic) | Straße / Verkehrsfluss | +| transit / bike share | ÖPNV / Bikesharing | +| scene / shot / scene recipe | Szene / Aufnahme / Szenenrezept | +| capture shot / camera move | Aufnahme speichern / Kameraflug | +| anchor / data pack / bundle | Anker / Datenpaket / Bundle | +| story beat / evidence beat | Story-Schritt / Beweisschritt | +| briefing / panel / dock | Briefing / Bereich / Dock | +| cockpit | Cockpit | +| preset / visual preset | Preset / visuelles Preset | +| Scope (circular viewport mask) / keyhole | Scope / Schlüsselloch | +| feather / fade | Weichzeichnung / Ausblenden | +| overlay / detection overlay | Overlay / Erkennungs-Overlay | +| Clean UI | Reine Ansicht | +| Night vision / Thermal / Snow (cockpit styles) | Nachtsicht / Wärmebild / Schnee | +| heading / altitude / ground speed | Kurs / Höhe / Geschwindigkeit über Grund (short: GESCHW. ÜBER GRUND) | +| HDG / BRG / CRS / DEST / SPD / FOV | unchanged | +| RANGE / PITCH / HGT (CCTV calibration chips) | REICHW. / NEIGUNG / HÖHE | +| PREV / NEXT | ZURÜCK / WEITER | +| L / R (relative bearing) | L / R | +| SIG / NEWS / LOCAL (briefing tabs) | SIG / NEWS / LOKAL | +| NOT AN ALL-CLEAR | KEINE ENTWARNUNG | +| Street Level / Street View (Google) | Straßenebene / Street View | +| Recent Imagery / box / pin (a day) | Aktuelle Bilddaten / Bereich / fixieren | +| frame (bring into view) | ins Bild nehmen | +| mark (map annotation) / outline | Markierung / Umriss | +| voice (control) / voice session | Sprachsteuerung / Sprachsitzung | +| YOU / THIS / HERE (voice card labels) | EINGABE / DIES / HIER | +| click / click to … | anklicken / … klicken | diff --git a/scripts/package-boundaries.json b/scripts/package-boundaries.json index 9f06f73f6..b1b3ecc0b 100644 --- a/scripts/package-boundaries.json +++ b/scripts/package-boundaries.json @@ -439,6 +439,7 @@ "src/ui/slider.js", "src/i18n/index.js", "src/i18n/locale.js", + "src/i18n/locales/de.json", "src/i18n/locales/es.json", "src/i18n/locales/ru.json", "src/i18n/locales/zh-CN.json", @@ -479,6 +480,7 @@ "src/localRequestGate.mjs", "src/i18n/index.js", "src/i18n/locale.js", + "src/i18n/locales/de.json", "src/i18n/locales/es.json", "src/i18n/locales/ru.json", "src/i18n/locales/zh-CN.json", @@ -509,6 +511,7 @@ "src/data/layerSnapshot.js", "src/i18n/index.js", "src/i18n/locale.js", + "src/i18n/locales/de.json", "src/i18n/locales/es.json", "src/i18n/locales/ru.json", "src/i18n/locales/zh-CN.json", @@ -531,6 +534,7 @@ "src/app/stateChannel.js", "src/i18n/index.js", "src/i18n/locale.js", + "src/i18n/locales/de.json", "src/i18n/locales/es.json", "src/i18n/locales/ru.json", "src/i18n/locales/zh-CN.json", @@ -548,6 +552,7 @@ "src/ui/radioTunerModel.js", "src/i18n/index.js", "src/i18n/locale.js", + "src/i18n/locales/de.json", "src/i18n/locales/es.json", "src/i18n/locales/ru.json", "src/i18n/locales/zh-CN.json", @@ -568,6 +573,7 @@ "src/ui/cctvPresentation.js", "src/i18n/index.js", "src/i18n/locale.js", + "src/i18n/locales/de.json", "src/i18n/locales/es.json", "src/i18n/locales/ru.json", "src/i18n/locales/zh-CN.json", @@ -595,6 +601,7 @@ "src/ui/panelRailGeometry.js", "src/i18n/index.js", "src/i18n/locale.js", + "src/i18n/locales/de.json", "src/i18n/locales/es.json", "src/i18n/locales/ru.json", "src/i18n/locales/zh-CN.json", @@ -630,6 +637,7 @@ "src/ui/panelRailGeometry.js", "src/i18n/index.js", "src/i18n/locale.js", + "src/i18n/locales/de.json", "src/i18n/locales/es.json", "src/i18n/locales/ru.json", "src/i18n/locales/zh-CN.json", @@ -647,6 +655,7 @@ "src/ui/actionButton.js", "src/i18n/index.js", "src/i18n/locale.js", + "src/i18n/locales/de.json", "src/i18n/locales/es.json", "src/i18n/locales/ru.json", "src/i18n/locales/zh-CN.json", @@ -806,6 +815,7 @@ "src/data/cameraArrival.js", "src/i18n/index.js", "src/i18n/locale.js", + "src/i18n/locales/de.json", "src/i18n/locales/es.json", "src/i18n/locales/ru.json", "src/i18n/locales/zh-CN.json", @@ -928,6 +938,7 @@ "src/data/cameraArrival.js", "src/i18n/index.js", "src/i18n/locale.js", + "src/i18n/locales/de.json", "src/i18n/locales/es.json", "src/i18n/locales/ru.json", "src/i18n/locales/zh-CN.json", @@ -996,6 +1007,7 @@ "src/data/modelEligibility.js", "src/i18n/index.js", "src/i18n/locale.js", + "src/i18n/locales/de.json", "src/i18n/locales/es.json", "src/i18n/locales/ru.json", "src/i18n/locales/zh-CN.json", @@ -1045,6 +1057,7 @@ "src/data/modelEligibility.js", "src/i18n/index.js", "src/i18n/locale.js", + "src/i18n/locales/de.json", "src/i18n/locales/es.json", "src/i18n/locales/ru.json", "src/i18n/locales/zh-CN.json", @@ -1108,6 +1121,7 @@ "src/data/inputOwnership.js", "src/i18n/index.js", "src/i18n/locale.js", + "src/i18n/locales/de.json", "src/i18n/locales/es.json", "src/i18n/locales/ru.json", "src/i18n/locales/zh-CN.json", @@ -1138,6 +1152,7 @@ "src/maps/imageryHost.js", "src/i18n/index.js", "src/i18n/locale.js", + "src/i18n/locales/de.json", "src/i18n/locales/es.json", "src/i18n/locales/ru.json", "src/i18n/locales/zh-CN.json", @@ -1169,6 +1184,7 @@ "src/data/inputOwnership.js", "src/i18n/index.js", "src/i18n/locale.js", + "src/i18n/locales/de.json", "src/i18n/locales/es.json", "src/i18n/locales/ru.json", "src/i18n/locales/zh-CN.json", @@ -1200,6 +1216,7 @@ "src/data/inputOwnership.js", "src/i18n/index.js", "src/i18n/locale.js", + "src/i18n/locales/de.json", "src/i18n/locales/es.json", "src/i18n/locales/ru.json", "src/i18n/locales/zh-CN.json", @@ -1234,6 +1251,7 @@ "src/data/inputOwnership.js", "src/i18n/index.js", "src/i18n/locale.js", + "src/i18n/locales/de.json", "src/i18n/locales/es.json", "src/i18n/locales/ru.json", "src/i18n/locales/zh-CN.json", @@ -1277,6 +1295,7 @@ "src/data/infrastructureOverlayEntry.js", "src/i18n/index.js", "src/i18n/locale.js", + "src/i18n/locales/de.json", "src/i18n/locales/es.json", "src/i18n/locales/ru.json", "src/i18n/locales/zh-CN.json", @@ -1314,6 +1333,7 @@ "src/ui/panelRailGeometry.js", "src/i18n/index.js", "src/i18n/locale.js", + "src/i18n/locales/de.json", "src/i18n/locales/es.json", "src/i18n/locales/ru.json", "src/i18n/locales/zh-CN.json", @@ -1365,6 +1385,7 @@ "src/layers/traffic/roadModes.js", "src/i18n/index.js", "src/i18n/locale.js", + "src/i18n/locales/de.json", "src/i18n/locales/es.json", "src/i18n/locales/ru.json", "src/i18n/locales/zh-CN.json", @@ -1395,6 +1416,7 @@ "src/data/cameraSensitivity.js", "src/i18n/index.js", "src/i18n/locale.js", + "src/i18n/locales/de.json", "src/i18n/locales/es.json", "src/i18n/locales/ru.json", "src/i18n/locales/zh-CN.json", @@ -1444,6 +1466,7 @@ "src/layers/cctv/sourcePolicy.js", "src/i18n/index.js", "src/i18n/locale.js", + "src/i18n/locales/de.json", "src/i18n/locales/es.json", "src/i18n/locales/ru.json", "src/i18n/locales/zh-CN.json", @@ -1508,6 +1531,7 @@ "scripts/qa-street-level.mjs", "src/i18n/index.js", "src/i18n/locale.js", + "src/i18n/locales/de.json", "src/i18n/locales/es.json", "src/i18n/locales/ru.json", "src/i18n/locales/zh-CN.json", @@ -1538,6 +1562,7 @@ "src/layers/alpr/floors.js", "src/i18n/index.js", "src/i18n/locale.js", + "src/i18n/locales/de.json", "src/i18n/locales/es.json", "src/i18n/locales/ru.json", "src/i18n/locales/zh-CN.json", @@ -1579,6 +1604,7 @@ "src/data/inputOwnership.js", "src/i18n/index.js", "src/i18n/locale.js", + "src/i18n/locales/de.json", "src/i18n/locales/es.json", "src/i18n/locales/ru.json", "src/i18n/locales/zh-CN.json", @@ -1602,6 +1628,7 @@ "src/data/inputOwnership.js", "src/i18n/index.js", "src/i18n/locale.js", + "src/i18n/locales/de.json", "src/i18n/locales/es.json", "src/i18n/locales/ru.json", "src/i18n/locales/zh-CN.json", @@ -1659,6 +1686,7 @@ "src/maps/imageryHost.js", "src/i18n/index.js", "src/i18n/locale.js", + "src/i18n/locales/de.json", "src/i18n/locales/es.json", "src/i18n/locales/ru.json", "src/i18n/locales/zh-CN.json", @@ -1722,6 +1750,7 @@ "src/voice/pointerReticle.js", "src/i18n/index.js", "src/i18n/locale.js", + "src/i18n/locales/de.json", "src/i18n/locales/es.json", "src/i18n/locales/ru.json", "src/i18n/locales/zh-CN.json", @@ -2605,6 +2634,7 @@ "src/app/embed.js", "src/i18n/index.js", "src/i18n/locale.js", + "src/i18n/locales/de.json", "src/i18n/locales/es.json", "src/i18n/locales/ru.json", "src/i18n/locales/zh-CN.json", @@ -3190,6 +3220,7 @@ "src/sources/infrastructureData.js", "src/i18n/index.js", "src/i18n/locale.js", + "src/i18n/locales/de.json", "src/i18n/locales/es.json", "src/i18n/locales/ru.json", "src/i18n/locales/zh-CN.json", @@ -3301,6 +3332,7 @@ "src/app/stateChannel.js", "src/data/cameraArrival.js", "src/i18n/locale.js", + "src/i18n/locales/de.json", "src/i18n/locales/es.json", "src/i18n/locales/ru.json", "src/i18n/locales/zh-CN.json", @@ -3325,6 +3357,7 @@ "src/ui/uiLifetime.js", "src/i18n/index.js", "src/i18n/locale.js", + "src/i18n/locales/de.json", "src/i18n/locales/es.json", "src/i18n/locales/ru.json", "src/i18n/locales/zh-CN.json", @@ -3362,6 +3395,7 @@ "src/i18n/marker.js", "src/i18n/index.js", "src/i18n/locale.js", + "src/i18n/locales/de.json", "src/i18n/locales/es.json", "src/i18n/locales/ru.json", "src/i18n/locales/zh-CN.json", @@ -3389,6 +3423,7 @@ "src/ui/uiLifetime.js", "src/i18n/index.js", "src/i18n/locale.js", + "src/i18n/locales/de.json", "src/i18n/locales/es.json", "src/i18n/locales/ru.json", "src/i18n/locales/zh-CN.json", @@ -3481,6 +3516,7 @@ "src/data/routeSteps.js", "src/i18n/index.js", "src/i18n/locale.js", + "src/i18n/locales/de.json", "src/i18n/locales/es.json", "src/i18n/locales/ru.json", "src/i18n/locales/zh-CN.json", @@ -3537,6 +3573,7 @@ "src/voice/pointerReticle.js", "src/i18n/index.js", "src/i18n/locale.js", + "src/i18n/locales/de.json", "src/i18n/locales/es.json", "src/i18n/locales/ru.json", "src/i18n/locales/zh-CN.json", @@ -3792,6 +3829,7 @@ "src/sources/capability.js", "src/i18n/index.js", "src/i18n/locale.js", + "src/i18n/locales/de.json", "src/i18n/locales/es.json", "src/i18n/locales/ru.json", "src/i18n/locales/zh-CN.json", @@ -3836,6 +3874,7 @@ "src/sources/transitHistory.js", "src/i18n/index.js", "src/i18n/locale.js", + "src/i18n/locales/de.json", "src/i18n/locales/es.json", "src/i18n/locales/ru.json", "src/i18n/locales/zh-CN.json", @@ -3890,6 +3929,7 @@ "src/layers/perimeters/inciweb.js", "src/i18n/index.js", "src/i18n/locale.js", + "src/i18n/locales/de.json", "src/i18n/locales/es.json", "src/i18n/locales/ru.json", "src/i18n/locales/zh-CN.json", @@ -3907,6 +3947,7 @@ "src/layers/gnss/records.js", "src/i18n/index.js", "src/i18n/locale.js", + "src/i18n/locales/de.json", "src/i18n/locales/es.json", "src/i18n/locales/ru.json", "src/i18n/locales/zh-CN.json", @@ -3967,6 +4008,7 @@ "src/i18n/marker.js", "src/i18n/index.js", "src/i18n/locale.js", + "src/i18n/locales/de.json", "src/i18n/locales/es.json", "src/i18n/locales/ru.json", "src/i18n/locales/zh-CN.json", @@ -4164,6 +4206,7 @@ "src/i18n/marker.js", "src/i18n/index.js", "src/i18n/locale.js", + "src/i18n/locales/de.json", "src/i18n/locales/es.json", "src/i18n/locales/ru.json", "src/i18n/locales/zh-CN.json", diff --git a/src/i18n/i18n.test.mjs b/src/i18n/i18n.test.mjs index 1b421f2ff..c06c9fbf2 100644 --- a/src/i18n/i18n.test.mjs +++ b/src/i18n/i18n.test.mjs @@ -34,6 +34,9 @@ test('normalizeLocale folds regional variants and rejects unshipped tags', () => assert.equal(normalizeLocale('ru-RU'), 'ru'); assert.equal(normalizeLocale(' RU '), 'ru'); assert.equal(normalizeLocale('en_GB'), 'en'); + assert.equal(normalizeLocale('de'), 'de'); + assert.equal(normalizeLocale('de-AT'), 'de'); + assert.equal(normalizeLocale('de_CH'), 'de'); assert.equal(normalizeLocale('xx'), null); // Explicit script tags take precedence over regional defaults. assert.equal(normalizeLocale('zh'), 'zh-CN'); @@ -68,7 +71,7 @@ test('resolveLocale: ?lang= wins, then the stored choice, then browser languages resolveLocale({ location: { search: '?lang=xx' }, storage: memoryStorage(), - languages: ['de-DE', 'ru-RU'], + languages: ['ko-KR', 'ru-RU'], }), 'ru', ); @@ -76,7 +79,15 @@ test('resolveLocale: ?lang= wins, then the stored choice, then browser languages resolveLocale({ location: { search: '' }, storage: memoryStorage(), - languages: ['de'], + languages: ['de-DE', 'ru-RU'], + }), + 'de', + ); + assert.equal( + resolveLocale({ + location: { search: '' }, + storage: memoryStorage(), + languages: ['ko'], }), 'en', ); diff --git a/src/i18n/index.js b/src/i18n/index.js index 6fc4becc9..70c131c40 100644 --- a/src/i18n/index.js +++ b/src/i18n/index.js @@ -16,12 +16,19 @@ import { normalizeLocale, writeStoredLocale, } from './locale.js'; +import de from './locales/de.json' with { type: 'json' }; import es from './locales/es.json' with { type: 'json' }; import ru from './locales/ru.json' with { type: 'json' }; import zhCN from './locales/zh-CN.json' with { type: 'json' }; import zhHant from './locales/zh-Hant.json' with { type: 'json' }; -const CATALOGS = Object.freeze({ es, ru, 'zh-CN': zhCN, 'zh-Hant': zhHant }); +const CATALOGS = Object.freeze({ + de, + es, + ru, + 'zh-CN': zhCN, + 'zh-Hant': zhHant, +}); let currentLocale = DEFAULT_LOCALE; diff --git a/src/i18n/locale.js b/src/i18n/locale.js index 55ed71163..e34a66a3c 100644 --- a/src/i18n/locale.js +++ b/src/i18n/locale.js @@ -8,11 +8,19 @@ export const LOCALE_STORAGE_KEY = 'gev:locale:v1'; export const DEFAULT_LOCALE = 'en'; /** Shipped locales; order does not matter. Adding one: docs/TRANSLATORS.md. */ -export const LOCALES = Object.freeze(['en', 'es', 'ru', 'zh-CN', 'zh-Hant']); +export const LOCALES = Object.freeze([ + 'en', + 'de', + 'es', + 'ru', + 'zh-CN', + 'zh-Hant', +]); /** Each locale named in its own language, for the selector. */ export const LOCALE_NAMES = Object.freeze({ en: 'English', + de: 'Deutsch', es: 'Español', ru: 'Русский', 'zh-CN': '中文(简体)', @@ -24,6 +32,7 @@ const RTL_LOCALES = Object.freeze([]); /** * Map any language tag to a shipped locale: 'ru-RU' and 'RU' → 'ru', + * 'de-AT' and 'de_CH' → 'de', * 'zh', 'zh-CN' and 'zh-Hans-SG' → 'zh-CN'; * 'zh-Hant', 'zh-TW', 'zh-HK' and 'zh-MO' → 'zh-Hant'. * @returns {string|null} diff --git a/src/i18n/locales/de.json b/src/i18n/locales/de.json index f80420d3b..0a86aea98 100644 --- a/src/i18n/locales/de.json +++ b/src/i18n/locales/de.json @@ -61,7 +61,7 @@ "Opening space missions…": "Raummissionen werden geöffnet…", "Scanning active events…": "Aktive Ereignisse werden gescannt…", "Live earthquakes and active fires, from USGS and NASA": "Live-Erdbeben und aktive Brände, von USGS und NASA", - "It feels like a forbidden cockpit—then you realize the sources are public and the data is real.": "Es fühlt sich an wie ein verbotenes Cockpit—dann merkt man, dass die Quellen öffentlich und die Daten echt sind.", + "It feels like a forbidden cockpit—then you realize the sources are public and the data is real.": "Es fühlt sich an wie ein verbotenes Cockpit – dann merkt man, dass die Quellen öffentlich und die Daten echt sind.", "Working…": "In Arbeit…", "Could not open that mission{detail}. Retry or explore manually.": "Mission{detail} konnte nicht geöffnet werden. Erneut versuchen oder manuell erkunden.", "This browser is blocking storage, so that could not be saved.": "Dieser Browser blockiert den Speicher, daher konnte das nicht gespeichert werden.", @@ -114,9 +114,9 @@ "NEXT": "WEITER", "Open-source mapped/observed context. Missing broadcasts, unloaded map areas, or unmapped sites are not evidence of absence.": "Kontext aus offenen Quellen, kartiert/beobachtet. Fehlende Funksignale, nicht geladene Kartenbereiche oder nicht kartierte Standorte sind kein Beleg für Abwesenheit.", "HDG {value}°": "HDG {value}°", - "BRG {value}°": "PEIL {value}°", - "BRG —": "PEIL —", - "CRS {value}°": "KRS {value}°", + "BRG {value}°": "BRG {value}°", + "BRG —": "BRG —", + "CRS {value}°": "CRS {value}°", "CURRENT VIEWPORT ONLY": "NUR AKTUELLER BILDAUSSCHNITT", "WITHIN {km} KM": "INNERHALB {km} KM", "Flights": "Flüge", @@ -430,13 +430,13 @@ "{aircraftClass} · {feedState} · COURSE ALIGNED": "{aircraftClass} · {feedState} · KURS ANGEGLICHEN", "ARROW · ESTIMATED DIRECTION": "PFEIL · GESCHÄTZTE RICHTUNG", "ROUTE DATA UNAVAILABLE": "ROUTENDATEN NICHT VERFÜGBAR", - "DEST {bearing}": "ZIEL {bearing}", + "DEST {bearing}": "DEST {bearing}", "Disable cockpit weather effects": "Cockpit-Wettereffekte deaktivieren", "Enable cockpit weather effects": "Cockpit-Wettereffekte aktivieren", "ON": "EIN", "Normal": "Normal", "Night vision": "Nachtsicht", - "Thermal": "Thermal", + "Thermal": "Wärmebild", "Anime": "Anime", "Noir": "Noir", "Snow": "Schnee", @@ -552,9 +552,9 @@ "Collapse Radio section": "Radio-Bereich einklappen", "Panel layout updated — positions reset to new defaults": "Bereichslayout aktualisiert. Positionen auf neue Standards zurückgesetzt", "Collapse Cockpit display options": "Cockpit-Anzeigeoptionen einklappen", - "Expand Cockpit display options": "Cockpit-Anzeigeoptionen aufklappen", + "Expand Cockpit display options": "Cockpit-Anzeigeoptionen ausklappen", "Collapse Cockpit Radio controls": "Cockpit-Radio-Steuerung einklappen", - "Expand Cockpit Radio controls": "Cockpit-Radio-Steuerung aufklappen", + "Expand Cockpit Radio controls": "Cockpit-Radio-Steuerung ausklappen", "NO STATIONS": "KEINE SENDER", "NO STATION AVAILABLE": "KEIN SENDER VERFÜGBAR", "{name}, station {index} of {total}": "{name}, Sender {index} von {total}", @@ -566,8 +566,8 @@ "Open compact Radio controls": "Kompakte Radio-Steuerung öffnen", "SYNC": "SYNC", "RECONCILE": "ABGLEICHEN", - "DISABLE": "DEAKTIV.", - "ENABLE": "AKTIV.", + "DISABLE": "AUS", + "ENABLE": "EIN", "Reconcile Radio — lifecycle uncertain": "Radio abgleichen: Lebenszyklus unklar", "Disable Radio": "Radio deaktivieren", "Enable Radio": "Radio aktivieren", @@ -609,8 +609,8 @@ "Radio is disabling…": "Radio wird deaktiviert…", "Radio lifecycle is uncertain — use Enable or Disable to reconcile": "Radio-Lebenszyklus unklar: zum Abgleichen Aktivieren oder Deaktivieren nutzen", "Scene action failed": "Szenenaktion fehlgeschlagen", - "Delete shot \"{shot}\"?": "Aufnahme \"{shot}\" löschen?", - "SPARSE": "WENIG", + "Delete shot \"{shot}\"?": "Aufnahme „{shot}“ löschen?", + "SPARSE": "DÜNN", "BALANCED": "AUSGEWOGEN", "DEL": "ENTF.", "entity": "Objekt", @@ -668,10 +668,10 @@ "Aircraft cockpit view": "Flugzeug-Cockpitansicht", "LEVEL": "HORIZONT", "Estimated destination direction": "Geschätzte Richtung zum Ziel", - "DEST ---°": "ZIEL ---°", + "DEST ---°": "DEST ---°", "OPTICAL PLANE · 01": "OPTISCHE EBENE · 01", "VISOR LOCK · ACTIVE": "VISIER-LOCK · AKTIV", - "GROUND SPEED · KTS": "GESCHW. ÜBER GRUND · KTS", + "GROUND SPEED · KTS": "GESCHW. ÜBER GRUND · KN", "ALTITUDE · FT": "HÖHE · FT", "FIRST PERSON": "EGO-PERSPEKTIVE", "LIVE TRACK · COURSE ALIGNED": "LIVE-TRACK · KURS ANGEGLICHEN", @@ -729,7 +729,7 @@ "Exit cockpit view": "Cockpitansicht verlassen", "EXIT COCKPIT": "COCKPIT VERLASSEN", "Navigation, voice, and visual preset controls": "Steuerung für Navigation, Sprache und visuelle Presets", - "Expand Visual Presets": "Visuelle Presets aufklappen", + "Expand Visual Presets": "Visuelle Presets ausklappen", "Pin visual presets": "Visuelle Presets anheften", "Keep visual presets open": "Visuelle Presets geöffnet lassen", "Show the globe without a visual filter.": "Globus ohne visuellen Filter anzeigen.", @@ -742,7 +742,7 @@ "MAP SOURCE": "KARTENQUELLE", "Map source": "Kartenquelle", "Style": "Stil", - "Expand LOCATION": "STANDORT aufklappen", + "Expand LOCATION": "STANDORT ausklappen", "Collapse panel": "Bereich einklappen", "Pin location tray": "Standortleiste anheften", "Keep location tray open": "Standortleiste geöffnet lassen", @@ -853,7 +853,7 @@ "UPDATE SHOT": "AUFNAHME AKTUALISIEREN", "START": "START", "EXPORT PRESETS": "PRESETS EXPORTIEREN", - "IMPORT": "IMPORT", + "IMPORT": "IMPORTIEREN", "RUN LOG": "LAUFPROTOKOLL", "POWER UP": "STARTKLAR", "GROUND STATION · PROVIDER SETTINGS": "BODENSTATION · ANBIETER-EINSTELLUNGEN", @@ -878,5 +878,2059 @@ "Begin with a clean globe": "Mit einem leeren Globus beginnen", "Don't show this again": "Nicht mehr anzeigen", "ESC to dismiss": "ESC zum Schließen", - "Tip: the GEV MIC button in the dock lets you talk to the map.": "Tipp: Mit der Taste GEV MIC im Dock lässt sich die Karte per Sprache steuern." + "Tip: the GEV MIC button in the dock lets you talk to the map.": "Tipp: Mit der Taste GEV MIC im Dock lässt sich die Karte per Sprache steuern.", + "Pick a shape, then click the map.": "Form wählen, dann auf die Karte klicken.", + "Enter to place the pin, Esc to cancel.": "Enter setzt den Pin, Esc bricht ab.", + "Click where the pin goes.": "Auf die Stelle für den Pin klicken.", + "Click {count} more points.": { + "one": "Noch {count} Punkt anklicken.", + "other": "Noch {count} Punkte anklicken." + }, + "Those points are in a line — move one off it to enclose an area.": "Diese Punkte liegen auf einer Linie – einen davon verschieben, um eine Fläche einzuschließen.", + "That line has no length — click somewhere further away.": "Diese Linie hat keine Länge – weiter entfernt klicken.", + " · {max}-point limit reached": " · Limit von {max} Punkten erreicht", + "{measure} · double-click or Enter to finish, Backspace undoes, Esc cancels.{full}": "{measure} · Doppelklick oder Enter beendet, Rücktaste macht rückgängig, Esc bricht ab.{full}", + "drawings on the map": "Zeichnungen auf der Karte", + "That shape already has {count} points — finish it or press Backspace.": "Diese Form hat bereits {count} Punkte – abschließen oder Rücktaste drücken.", + "That point is off the globe — click on the world.": "Dieser Punkt liegt außerhalb des Globus – auf die Erde klicken.", + "That shape could not be placed.": "Diese Form konnte nicht platziert werden.", + "Could not place the shape: {error}": "Form konnte nicht platziert werden: {error}", + "Board cleared.": "Zeichenfläche geleert.", + "{owner} is using the pointer — close it first.": "{owner} verwendet gerade den Zeiger – zuerst schließen.", + "{label} · Detailed outline unavailable": "{label} · Detaillierter Umriss nicht verfügbar", + "Space Missions isolates replay data. Exit the mode to enable {layer}.": "Der Modus Raummissionen isoliert Replay-Daten. Modus verlassen, um {layer} zu aktivieren.", + "Data attribution": "Datenquellen", + "Data provided by:": "Daten bereitgestellt von:", + "Light aircraft": "Leichtflugzeug", + "Glider": "Segelflugzeug", + "Turboprop": "Turboprop", + "Airliner": "Verkehrsflugzeug", + "Widebody": "Großraumflugzeug", + "Four-engine jet": "Vierstrahliger Jet", + "Helicopter": "Hubschrauber", + "Fast jet": "Kampfjet", + "Business jet": "Businessjet", + "Drone": "Drohne", + "General emergency": "Allgemeiner Notfall", + "Unlawful interference": "Widerrechtlicher Eingriff", + "Radio failure": "Funkausfall", + "Downed aircraft": "Abgestürztes Luftfahrzeug", + "Minimum fuel": "Mindesttreibstoff", + "Lifeguard (medical priority)": "Lifeguard (medizinische Priorität)", + "Rasuwagadhi witness video": "Augenzeugenvideo Rasuwagadhi", + "Bhote Koshi valley footage": "Aufnahmen aus dem Bhote-Koshi-Tal", + "Flood footage": "Hochwasseraufnahmen", + "Compilation and casualty claims": "Zusammenschnitt und Opferangaben", + "SOURCE GEOCONFIRMED · WORLD-PINNED": "QUELLE GEOVERIFIZIERT · AUF GLOBUS FIXIERT", + "SOURCE CREDITED · LOCATION UNRESOLVED": "QUELLE GENANNT · ORT UNGEKLÄRT", + "REFERENCE ONLY · CLAIMS UNVERIFIED": "NUR REFERENZ · ANGABEN UNBESTÄTIGT", + "SOURCE GEOCONFIRMED": "QUELLE GEOVERIFIZIERT", + "2021 historical reference versus 2026 post-event imagery; changes are cumulative and include the July 2025 Rasuwagadhi flood. Schematic downstream progression, not modeled arrival time; not an official hazard model.": "Historische Referenz von 2021 gegenüber Bildern nach dem Ereignis von 2026; die Veränderungen sind kumulativ und umfassen die Rasuwagadhi-Flut vom Juli 2025. Schematischer Verlauf flussabwärts, keine modellierte Ankunftszeit; kein offizielles Gefahrenmodell.", + "Immediate collapse viewpoint": "Blickpunkt direkt am Abbruch", + "Collapse viewpoint": "Blickpunkt Abbruch", + "Debris-dammed lake": "Durch Geröll aufgestauter See", + "Dammed lake": "Aufgestauter See", + "Second landslide": "Zweiter Erdrutsch", + "Gyirong border gate": "Grenzübergang Gyirong", + "Border gate": "Grenzübergang", + "Timure evidence cluster": "Beweiscluster Timure", + "Mailung / Upper Trishuli bridge": "Mailung / Brücke am oberen Trishuli", + "Dandagaun viewpoint restaurant": "Aussichtsrestaurant Dandagaun", + "Dandagaun viewpoint": "Aussichtspunkt Dandagaun", + "Bidur - Trishuli bridge": "Bidur – Trishuli-Brücke", + "Bidur bridge": "Brücke Bidur", + "Devighat / Taadi Khola Bridge": "Devighat / Taadi-Khola-Brücke", + "Devighat bridge": "Brücke Devighat", + "Facebook player API did not initialize.": "Facebook-Player-API wurde nicht initialisiert.", + "Facebook player API could not load.": "Facebook-Player-API konnte nicht geladen werden.", + "Facebook player API timed out.": "Zeitüberschreitung bei der Facebook-Player-API.", + "X embed API did not initialize.": "X-Embed-API wurde nicht initialisiert.", + "X embed could not load.": "X-Einbettung konnte nicht geladen werden.", + "X embed timed out.": "Zeitüberschreitung bei der X-Einbettung.", + "TIMEOUT": "ZEITÜBERSCHREITUNG", + "BLOCKED": "BLOCKIERT", + "Facebook embed unavailable. The post may be private, removed, region-restricted, or blocked.": "Facebook-Einbettung nicht verfügbar. Der Beitrag ist möglicherweise privat, entfernt, regional gesperrt oder blockiert.", + "Preloading {provider} media": "{provider}-Medien werden vorgeladen", + "LOADING X POST…": "X-BEITRAG WIRD GELADEN…", + "The X post is unavailable or cannot be embedded.": "Der X-Beitrag ist nicht verfügbar oder kann nicht eingebettet werden.", + "X POST · PROVIDER CONTROLS": "X-BEITRAG · STEUERUNG DES ANBIETERS", + "{reason} OPEN ORIGINAL.": "{reason} ORIGINAL ÖFFNEN.", + "X embed unavailable": "X-Einbettung nicht verfügbar", + "FACEBOOK · PROVIDER CONTROLS": "FACEBOOK · STEUERUNG DES ANBIETERS", + "Facebook embed unavailable": "Facebook-Einbettung nicht verfügbar", + "AUTOPLAY BLOCKED · USE PROVIDER CONTROLS": "AUTOPLAY BLOCKIERT · STEUERUNG DES ANBIETERS NUTZEN", + "Embedded {provider} media for {source}": "Eingebettete {provider}-Medien für {source}", + "witness source": "Augenzeugenquelle", + "Witness source": "Augenzeugenquelle", + "{provider} · EMBEDDED SOURCE": "{provider} · EINGEBETTETE QUELLE", + "OPEN ORIGINAL ↗": "ORIGINAL ÖFFNEN ↗", + "{provider} media: {source}": "{provider}-Medien: {source}", + "{provider} · PROVIDER CONTROLS": "{provider} · STEUERUNG DES ANBIETERS", + "YOUTUBE {state} · OPEN ORIGINAL": "YOUTUBE {state} · ORIGINAL ÖFFNEN", + "INITIATION": "AUSLÖSUNG", + "DAMMING": "AUFSTAUUNG", + "SECONDARY FAILURE": "FOLGEVERSAGEN", + "BORDER ARRIVAL": "ANKUNFT AN DER GRENZE", + "PROPAGATION": "AUSBREITUNG", + "DOWNSTREAM PASSAGE": "DURCHGANG FLUSSABWÄRTS", + "CONSEQUENCE": "FOLGEN", + "DOWNSTREAM CONSEQUENCE": "FOLGEN FLUSSABWÄRTS", + "EVIDENCE": "BELEGE", + "{year} HISTORICAL REFERENCE": "HISTORISCHE REFERENZ {year}", + "{year} POST-EVENT": "NACH DEM EREIGNIS {year}", + "{count} GEOLOCATED SOURCE-MAP PLACEMENTS": { + "one": "{count} GEOLOKALISIERTE PLATZIERUNG AUF DER QUELLENKARTE", + "other": "{count} GEOLOKALISIERTE PLATZIERUNGEN AUF DER QUELLENKARTE" + }, + "NO PREVIEW": "KEINE VORSCHAU", + "YouTube source": "YouTube-Quelle", + "Facebook source": "Facebook-Quelle", + "SOURCE LINK": "QUELLENLINK", + "{publisher} / OPEN": "{publisher} / ÖFFNEN", + "Bhote Koshi flood reconstruction controls": "Steuerung der Bhote-Koshi-Flutrekonstruktion", + "EVENT RECONSTRUCTION · 26 AUG 2026": "REKONSTRUKTION DES EREIGNISSES · 26. AUG. 2026", + "BHOTE KOSHI OUTBURST FLOOD": "AUSBRUCHSFLUT BHOTE KOSHI", + "Close event layer": "Ereignisebene schließen", + "OBSERVED IMAGERY": "BEOBACHTETE BILDER", + "SCHEMATIC CORRIDOR": "SCHEMATISCHER KORRIDOR", + "2021 HISTORICAL REFERENCE / 2026 POST-EVENT": "HISTORISCHE REFERENZ 2021 / NACH DEM EREIGNIS 2026", + "Historical reference and post-event image split": "Bildvergleich: historische Referenz und nach dem Ereignis", + "RECONSTRUCTION CLOCK": "REKONSTRUKTIONSUHR", + "Schematic downstream progression": "Schematischer Verlauf flussabwärts", + "Story beat navigation": "Navigation durch die Story", + "Previous story beat": "Vorheriger Story-Schritt", + "CAUSE": "URSACHE", + "CAPTURE TIME UNVERIFIED": "AUFNAHMEZEIT UNBESTÄTIGT", + "Next story beat": "Nächster Story-Schritt", + "▶ PLAY": "▶ ABSPIELEN", + "Play the next shot and continue through this scene": "Nächste Aufnahme abspielen und die Szene fortsetzen", + "▶ PLAY SCENE": "▶ SZENE ABSPIELEN", + "◉ CINEMATIC": "◉ KINOMODUS", + "↺ FULL STORY": "↺ GANZE STORY", + "↗ OPEN ORIGINAL": "↗ ORIGINAL ÖFFNEN", + "⌖ LOWER GORGE": "⌖ UNTERE SCHLUCHT", + "FIELD REPORTS · {count}": "FELDBERICHTE · {count}", + "GEOLOCATIONS · {credit}": "GEOLOKALISIERUNGEN · {credit}", + "↗ OPEN PUBLIC MAP": "↗ ÖFFENTLICHE KARTE ÖFFNEN", + " Clouds are preserved from the source imagery.": " Die Wolken stammen aus den Quellbildern.", + "Rasuwagadhi witness": "Augenzeuge Rasuwagadhi", + "Open original source for {source}; capture time unverified": "Originalquelle für {source} öffnen; Aufnahmezeit unbestätigt", + "Historical reference and post-event image divider": "Trennlinie zwischen historischer Referenz und Bild nach dem Ereignis", + "A historical reference {before} percent, B post-event {after} percent": "A historische Referenz {before} Prozent, B nach dem Ereignis {after} Prozent", + "■ RELEASE CAMERA": "■ KAMERA FREIGEBEN", + "Seek Nepal scene clock": "Szenenuhr Nepal spulen", + "NEPAL SCENE CLOCK": "SZENENUHR NEPAL", + "… PLAYING SHOT": "… AUFNAHME LÄUFT", + "▶ PLAY SHOT": "▶ AUFNAHME ABSPIELEN", + "Ⅱ PAUSE": "Ⅱ PAUSE", + "↺ REPLAY CINEMATIC": "↺ KINOMODUS WIEDERHOLEN", + "↺ REPLAY": "↺ WIEDERHOLEN", + "… PLAYING SCENE": "… SZENE LÄUFT", + "Continue {scene} from next shot": "{scene} ab der nächsten Aufnahme fortsetzen", + "current scene": "aktuelle Szene", + "Replay the full reconstruction": "Gesamte Rekonstruktion wiederholen", + "SCENE SHOT": "SZENENAUFNAHME", + "TIME UNVERIFIED": "ZEIT UNBESTÄTIGT", + "{count} SOURCES": { + "one": "{count} QUELLE", + "other": "{count} QUELLEN" + }, + "OUTSIDE IMAGERY SWIPE": "AUSSERHALB DES BILDVERGLEICHS", + "{scene} / AUTHORED SHOT": "{scene} / GESTALTETE AUFNAHME", + "NEPAL FLOOD INCIDENT": "FLUTEREIGNIS NEPAL", + "Play {shot}": "{shot} abspielen", + "current scene shot": "aktuelle Szenenaufnahme", + "Play reconstruction": "Rekonstruktion abspielen", + "Load previous scene shot": "Vorherige Szenenaufnahme laden", + "Load next scene shot": "Nächste Szenenaufnahme laden", + "SCHEMATIC CORRIDOR, NOT MODELED ARRIVAL TIME.": "SCHEMATISCHER KORRIDOR, KEINE MODELLIERTE ANKUNFTSZEIT.", + "Rasuwa · 26 Aug 2026": "Rasuwa · 26. Aug. 2026", + "Event reconstruction": "Rekonstruktion des Ereignisses", + "BHOTE KOSHI FLOOD INCIDENT": "FLUTEREIGNIS BHOTE KOSHI", + "NEPAL · 26 AUG 2026": "NEPAL · 26. AUG. 2026", + "USGS INITIAL REPORT": "USGS-ERSTMELDUNG", + "26 AUG 2026 · 08:37 NPT": "26. AUG. 2026 · 08:37 NPT", + "28.2710° N · 85.5150° E": "28,2710° N · 85,5150° O", + "INITIAL M4.4 · RECLASSIFIED M5.2 LANDSLIDE": "ZUERST M4,4 · NEU EINGESTUFT ALS M5,2-ERDRUTSCH", + "USGS EVENT us7000tbwb · OPEN SOURCE": "USGS-EREIGNIS us7000tbwb · QUELLE ÖFFNEN", + "Open the USGS initial report for the 26 August 2026 Nepal landslide": "USGS-Erstmeldung zum Erdrutsch in Nepal vom 26. August 2026 öffnen", + "Show the Nepal context callout without a border or country fill": "Kontexthinweis zu Nepal ohne Grenze und Landesfläche zeigen", + "Introduce Nepal, draw its border, then reveal the Bhote Koshi incident": "Nepal vorstellen, die Grenze zeichnen und dann das Bhote-Koshi-Ereignis zeigen", + "CITIES": "STÄDTE", + "Keep the regional incident context and introduce nearby city labels": "Regionalen Ereigniskontext beibehalten und Städtenamen in der Nähe einblenden", + "PLACES": "ORTE", + "Introduce the reconstruction scene key places from trigger to downstream": "Die wichtigsten Orte der Rekonstruktion vom Auslöser bis flussabwärts vorstellen", + "PATH": "PFAD", + "Animate the sourced cyan river-centerline route to Trishuli Bazaar": "Die belegte cyanfarbene Flussmittellinie bis Trishuli Bazaar animieren", + "OVERVIEW": "ÜBERSICHT", + "Keep the completed flood path and location labels visible": "Fertigen Flutpfad und Ortsnamen sichtbar lassen", + "RECORD": "AUFZEICHNUNG", + "Reveal the trigger record while making a slow camera approach": "Auslöser-Aufzeichnung zeigen, während die Kamera sich langsam nähert", + "{speed} kn": "{speed} kn", + "That file is not valid JSON.": "Diese Datei ist kein gültiges JSON.", + "That JSON file is not GeoJSON.": "Diese JSON-Datei ist kein GeoJSON.", + "That FeatureCollection has no features list.": "Diese FeatureCollection hat keine Feature-Liste.", + "Every GeoJSON feature must have type Feature.": "Jedes GeoJSON-Feature muss den Typ Feature haben.", + "That GeoJSON has invalid geometries.": "Dieses GeoJSON enthält ungültige Geometrien.", + "That GeoJSON contains an unsupported geometry.": "Dieses GeoJSON enthält eine nicht unterstützte Geometrie.", + "That GeoJSON has invalid coordinates.": "Dieses GeoJSON enthält ungültige Koordinaten.", + "That file creates more than {limit} map objects (the limit).": "Diese Datei erzeugt mehr als {limit} Kartenobjekte (das Limit).", + "That file has more than {limit} style definitions and image links after cleanup (the limit).": "Diese Datei enthält nach der Bereinigung mehr als {limit} Stildefinitionen und Bildlinks (das Limit).", + "That file has more than {limit} features (the limit).": "Diese Datei enthält mehr als {limit} Features (das Limit).", + "That file has more than {limit} points (the limit) across {features} features.": "Diese Datei enthält mehr als {limit} Punkte (das Limit) in {features} Features.", + "That file has more than {limit} points (the limit).": "Diese Datei enthält mehr als {limit} Punkte (das Limit).", + "That KMZ unpacks to more than the import limit.": "Diese KMZ ist entpackt größer als das Importlimit.", + "That KMZ is damaged and could not be unpacked.": "Diese KMZ ist beschädigt und konnte nicht entpackt werden.", + "That KMZ is not a readable zip archive.": "Diese KMZ ist kein lesbares ZIP-Archiv.", + "That KMZ uses a zip format this import does not read.": "Diese KMZ verwendet ein ZIP-Format, das dieser Import nicht liest.", + "That KMZ is encrypted.": "Diese KMZ ist verschlüsselt.", + "That KMZ uses a compression method this import does not read.": "Diese KMZ verwendet eine Komprimierungsmethode, die dieser Import nicht liest.", + "That KML has invalid geometry bounds.": "Diese KML enthält ungültige Geometriegrenzen.", + "That KML has invalid coordinates.": "Diese KML enthält ungültige Koordinaten.", + "That GPX file has no document.": "Diese GPX-Datei hat kein -Dokument.", + "That {format} file is not valid XML.": "Diese {format}-Datei ist kein gültiges XML.", + "That file has an unreadable image or exceeds the 16-megapixel image limit.": "Diese Datei enthält ein unlesbares Bild oder überschreitet das Bildlimit von 16 Megapixeln.", + "That KML could not be read.": "Diese KML konnte nicht gelesen werden.", + "That file has invalid point coordinates.": "Diese Datei enthält ungültige Punktkoordinaten.", + "Ground heights are not available for that file. Try again when the map has loaded.": "Für diese Datei sind keine Geländehöhen verfügbar. Erneut versuchen, wenn die Karte geladen ist.", + "That file took too long to read.": "Das Lesen dieser Datei hat zu lange gedauert.", + "Nothing to import.": "Nichts zu importieren.", + "That file is larger than {size} MiB.": "Diese Datei ist größer als {size} MiB.", + "Only GeoJSON, KML, KMZ and GPX files can be imported.": "Nur GeoJSON-, KML-, KMZ- und GPX-Dateien können importiert werden.", + "That file has nothing to draw.": "Diese Datei enthält nichts zum Zeichnen.", + "That KMZ holds no KML document.": "Diese KMZ enthält kein KML-Dokument.", + "That {format} file could not be read.": "Diese {format}-Datei konnte nicht gelesen werden.", + "That file has {count} map objects; the limit is {limit}.": "Diese Datei hat {count} Kartenobjekte; das Limit ist {limit}.", + "Ground heights could not be read. Try that file again.": "Geländehöhen konnten nicht gelesen werden. Die Datei erneut versuchen.", + "That file has invalid point graphics.": "Diese Datei enthält ungültige Punktgrafiken.", + "Map tiles temporarily unavailable": "Kartenkacheln vorübergehend nicht verfügbar", + "Mapped names temporarily unavailable": "Kartierte Namen vorübergehend nicht verfügbar", + "Military airfield": "Militärflugplatz", + "Naval base": "Marinestützpunkt", + "Firing range": "Schießplatz", + "Military land": "Militärgelände", + "Mapped installation": "Kartierte Anlage", + "Military area": "Militärisches Gebiet", + "flight": "Flug", + "military flight": "Militärflug", + "satellite": "Satellit", + "Draw": "Zeichnen", + "Directions": "Route", + "Recent imagery": "Aktuelle Bilddaten", + "Included in bundle": "Im Bundle enthalten", + "Missing bundle file — reimport its bundle": "Bundle-Datei fehlt – Bundle erneut importieren", + "Source configured; file checked when loaded": "Quelle konfiguriert; Datei wird beim Laden geprüft", + "Source unavailable": "Quelle nicht verfügbar", + "NORMAL": "NORMAL", + "ANIME": "ANIME", + "NOIR": "NOIR", + "ARCTIC": "ARKTIS", + "ANTARCTIC": "ANTARKTIS", + "NORTH AMERICA": "NORDAMERIKA", + "SOUTH AMERICA": "SÜDAMERIKA", + "EUROPE": "EUROPA", + "AFRICA": "AFRIKA", + "ASIA": "ASIEN", + "OCEANIA": "OZEANIEN", + "NORTHERN OCEANIC GRID": "NÖRDLICHES OZEANRASTER", + "SOUTHERN OCEANIC GRID": "SÜDLICHES OZEANRASTER", + "{state} {layers}": "{state} {layers}", + "view band|STREET": "STRASSE", + "view band|CITY": "STADT", + "view band|METRO": "GROSSRAUM", + "view band|REGIONAL": "REGION", + "view band|GLOBAL": "GLOBAL", + "N/A": "k. A.", + "{mode} {band} {locality} | {region} | ALT {alt} | WINDOW {window} | SUN {sun}° | ONA {ona}° | {zone}": "{mode} {band} {locality} | {region} | ALT {alt} | FENSTER {window} | SONNE {sun}° | ONA {ona}° | {zone}", + "NEAR {poi} ({city}) {distance}": "NAHE {poi} ({city}) {distance}", + "SECTOR {lat} {lon}": "SEKTOR {lat} {lon}", + "hemisphere|N": "N", + "hemisphere|S": "S", + "hemisphere|E": "O", + "hemisphere|W": "W", + "Provider Settings does not answer proxied requests": "Anbieter-Einstellungen beantworten keine weitergeleiteten Anfragen", + "Provider Settings is disabled while sharing is enabled": "Anbieter-Einstellungen sind deaktiviert, solange das Teilen aktiv ist", + "Provider Settings answers only the machine running the server": "Anbieter-Einstellungen antworten nur dem Rechner, auf dem der Server läuft", + "Provider Settings answers only local hostnames": "Anbieter-Einstellungen antworten nur lokalen Hostnamen", + "Provider Settings requires an exact local Origin": "Anbieter-Einstellungen erfordern einen exakt lokalen Origin", + "Unrecognized Origin refused": "Unbekannter Origin abgelehnt", + "Cross-origin requests are refused": "Cross-Origin-Anfragen werden abgelehnt", + "Content-Type must be application/json": "Content-Type muss application/json sein", + "Method not allowed": "Methode nicht erlaubt", + "Request too large": "Anfrage zu groß", + "Invalid JSON": "Ungültiges JSON", + "Body must be a JSON object of {ENV_VAR: value}": "Body muss ein JSON-Objekt der Form {ENV_VAR: value} sein", + "No keys provided": "Keine Schlüssel angegeben", + "At most {limit} keys per save": "Höchstens {limit} Schlüssel pro Speichervorgang", + "Unknown key: {name}": "Unbekannter Schlüssel: {name}", + "{name} must be a string": "{name} muss ein String sein", + "{name} is empty": "{name} ist leer", + "{name} is longer than any real key ({limit} max)": "{name} ist länger als jeder echte Schlüssel (max. {limit})", + "{name} may only contain printable characters with no spaces": "{name} darf nur druckbare Zeichen ohne Leerzeichen enthalten", + "{name} contains a character that is not valid in a key (#, quotes, $, \\, or backtick)": "{name} enthält ein Zeichen, das in einem Schlüssel ungültig ist (#, Anführungszeichen, $, \\ oder Backtick)", + "{name} is configured outside Provider Settings and can only be changed where it was set": "{name} ist außerhalb der Anbieter-Einstellungen konfiguriert und kann nur dort geändert werden, wo er gesetzt wurde", + "The key was not saved: could not restrict the credential file to your account; nothing was saved": "Der Schlüssel wurde nicht gespeichert: Die Zugangsdatei ließ sich nicht auf das eigene Benutzerkonto beschränken; nichts wurde gespeichert", + "The key was not saved: the existing configuration could not be read, so nothing was changed": "Der Schlüssel wurde nicht gespeichert: Die vorhandene Konfiguration konnte nicht gelesen werden, daher wurde nichts geändert", + "Could not write the {store} store": "Speicher {store} konnte nicht geschrieben werden", + "OAuth check failed: {detail}": "OAuth-Prüfung fehlgeschlagen: {detail}", + "Could not check ChatGPT sign-in. Try again.": "ChatGPT-Anmeldung konnte nicht geprüft werden. Erneut versuchen.", + "VOICE AUTH · CHATGPT OAUTH": "SPRACH-AUTH · CHATGPT OAUTH", + "VOICE AUTH · API KEY": "SPRACH-AUTH · API-SCHLÜSSEL", + "USE API KEY": "API-SCHLÜSSEL VERWENDEN", + "USE CHATGPT OAUTH": "CHATGPT OAUTH VERWENDEN", + "Use OPENAI_API_KEY for the next cloud voice session": "OPENAI_API_KEY für die nächste Cloud-Sprachsitzung verwenden", + "Use the signed-in local ChatGPT/Codex OAuth session for the next cloud voice session": "Die angemeldete lokale ChatGPT/Codex-OAuth-Sitzung für die nächste Cloud-Sprachsitzung verwenden", + "Metered — a billing-enabled account": "Kostenpflichtig – Konto mit aktivierter Abrechnung", + "Optional paid token — public access works without one": "Optionales kostenpflichtiges Token – öffentlicher Zugang funktioniert auch ohne", + "Free key — register, paste, done": "Kostenloser Schlüssel – registrieren, einfügen, fertig", + "browser-side": "browserseitig", + "This key runs in the browser by design — restrict it at the provider (see SECURITY.md)": "Dieser Schlüssel läuft absichtlich im Browser – beim Anbieter einschränken (siehe SECURITY.md)", + "configured externally": "extern konfiguriert", + "Supplied by your environment, Keychain, or launcher — change it where it was set": "Aus Umgebung, Schlüsselbund oder Launcher – dort ändern, wo er gesetzt wurde", + "MANAGE ↗": "VERWALTEN ↗", + "GET KEY ↗": "SCHLÜSSEL HOLEN ↗", + "{envVar} saved — paste to replace": "{envVar} gespeichert – zum Ersetzen einfügen", + "paste {envVar}": "{envVar} einfügen", + "unsaved provider keys": "ungespeicherte Anbieter-Schlüssel", + "Project keys: {status}": "Projektschlüssel: {status}", + "Cloud voice will use OPENAI_API_KEY on the next session.": "Die Cloud-Sprachsteuerung verwendet ab der nächsten Sitzung OPENAI_API_KEY.", + "Checking local ChatGPT OAuth sign-in…": "Lokale ChatGPT-OAuth-Anmeldung wird geprüft…", + "Could not check ChatGPT sign-in.": "ChatGPT-Anmeldung konnte nicht geprüft werden.", + "ChatGPT OAuth selected for cloud voice. Your API key stays saved and available.": "ChatGPT OAuth für die Cloud-Sprachsteuerung gewählt. Der API-Schlüssel bleibt gespeichert und verfügbar.", + "ChatGPT sign-in expired. Opening sign-in again…": "ChatGPT-Anmeldung abgelaufen. Anmeldung wird erneut geöffnet…", + "Opening ChatGPT sign-in in your browser…": "ChatGPT-Anmeldung wird im Browser geöffnet…", + "Could not start ChatGPT sign-in on this machine.": "ChatGPT-Anmeldung konnte auf diesem Rechner nicht gestartet werden.", + "Finish ChatGPT sign-in in the browser. Waiting for it to complete…": "ChatGPT-Anmeldung im Browser abschließen. Warte auf Abschluss…", + "ChatGPT sign-in timed out. Click {button} to try again.": "Zeitüberschreitung bei der ChatGPT-Anmeldung. Zum erneuten Versuch auf {button} klicken.", + "ChatGPT sign-in complete. OAuth will be used for the next cloud voice session.": "ChatGPT-Anmeldung abgeschlossen. OAuth wird für die nächste Cloud-Sprachsitzung verwendet.", + "The photorealistic 3D planet, place search + Street View": "Der fotorealistische 3D-Planet, Ortssuche + Street View", + "Voice control — API key or ChatGPT OAuth": "Sprachsteuerung – API-Schlüssel oder ChatGPT OAuth", + "Gemini Live voice control": "Sprachsteuerung mit Gemini Live", + "Street-level imagery and coverage in the Street Level layer. Free: register an app in the Mapillary developer dashboard and paste its Client Token": "Bilder auf Straßenebene und Abdeckung in der Ebene Straßenansicht. Kostenlos: im Mapillary-Entwickler-Dashboard eine App registrieren und deren Client Token einfügen", + "Public space-missions access needs no key. Leave blank for standard use; paid tokens only raise request limits.": "Öffentlicher Zugang zu Raummissionen braucht keinen Schlüssel. Für normale Nutzung leer lassen; kostenpflichtige Tokens erhöhen nur die Anfragelimits.", + "Air quality request failed": "Luftqualitätsabfrage fehlgeschlagen", + "No readings available": "Keine Messwerte verfügbar", + "No current readings": "Keine aktuellen Messwerte", + "{count} stations reporting": { + "one": "{count} Station meldet", + "other": "{count} Stationen melden" + }, + "Highest air-quality readings in view": "Höchste Luftqualitätswerte im Bild", + "Low": "Niedrig", + "Low health risk": "Geringes Gesundheitsrisiko", + "Moderate": "Mäßig", + "Moderate health risk": "Mäßiges Gesundheitsrisiko", + "High": "Hoch", + "High health risk": "Hohes Gesundheitsrisiko", + "Very High": "Sehr hoch", + "Very High health risk": "Sehr hohes Gesundheitsrisiko", + "Air quality": "Luftqualität", + "Canada only · ECCC AQHI network": "Nur Kanada · ECCC-AQHI-Messnetz", + "ECCC request timed out": "Zeitüberschreitung bei der ECCC-Abfrage", + "Malformed AQHI station response": "Fehlerhafte Antwort der AQHI-Stationen", + "No AQHI stations available": "Keine AQHI-Stationen verfügbar", + "Malformed AQHI observation response": "Fehlerhafte Antwort der AQHI-Beobachtungen", + "Camera source temporarily unavailable": "Kameraquelle vorübergehend nicht verfügbar", + "Mapped camera locations": "Kartierte Kamerastandorte", + "SHOW NEAREST": "NÄCHSTE ZEIGEN", + "Stop following the current object before navigating to a camera": "Vor dem Wechsel zu einer Kamera das Verfolgen des aktuellen Objekts beenden", + "Move to the nearest loaded camera and show its details": "Zur nächsten geladenen Kamera wechseln und Details zeigen", + "Camera badges": "Kamera-Markierungen", + "Cyan cameras turn coral when selected. Wedges illustrate mapped direction, not measured coverage. Nearby cameras may be outside the screen.": "Cyanfarbene Kameras werden bei Auswahl korallenrot. Keile zeigen die kartierte Blickrichtung, keine gemessene Abdeckung. Kameras in der Nähe können außerhalb des Bildschirms liegen.", + "{count} nearby · {onScreen} on screen": { + "one": "{count} in der Nähe · {onScreen} im Bild", + "other": "{count} in der Nähe · {onScreen} im Bild" + }, + "{count} nearby": { + "one": "{count} in der Nähe", + "other": "{count} in der Nähe" + }, + "retrying mapped ALPR cameras": "kartierte ALPR-Kameras: neuer Versuch", + "loading mapped ALPR cameras": "kartierte ALPR-Kameras werden geladen", + "No ALPR data for this area — US and Canada only": "Keine ALPR-Daten für dieses Gebiet – nur USA und Kanada", + "Zoom in to load mapped cameras": "Hineinzoomen, um kartierte Kameras zu laden", + "Showing cached locations": "Standorte aus dem Cache", + "Coverage limited — zoom in": "Abdeckung begrenzt – hineinzoomen", + "No ALPR data for this area": "Keine ALPR-Daten für dieses Gebiet", + "None on screen — nearby cameras are outside the view": "Keine im Bild – Kameras in der Nähe liegen außerhalb der Ansicht", + "ALPR camera": "ALPR-Kamera", + "Camera coverage unavailable": "Kameraabdeckung nicht verfügbar", + "OpenStreetMap · community mapped": "OpenStreetMap · von der Community kartiert", + "Overpass returned an incomplete camera response": "Overpass hat eine unvollständige Kamera-Antwort geliefert", + "At least {count}": "Mindestens {count}", + "Named areas ({n})": "Benannte Gebiete ({n})", + "{distance} FLIGHT / VESSEL WINDOW": "{distance} FLUG-/SCHIFFSFENSTER", + "mapped matches within {km} km of the subject": "kartierte Treffer im Umkreis von {km} km um das Objekt", + "none mapped within {km} km; not a complete 250 km survey": "keine kartierten Treffer im Umkreis von {km} km; keine vollständige 250-km-Erfassung", + "mapped matches from the loaded viewport": "kartierte Treffer aus dem geladenen Bildausschnitt", + "viewport feed is not a complete 250 km survey": "Feed des Bildausschnitts ist keine vollständige 250-km-Erfassung", + "GBFS fetch error": "GBFS-Abruffehler", + "FOV {value}° (DATASHEET)": "FOV {value}° (DATENBLATT)", + "SPEC FOV {span}° (CAPABILITY)": "SPEZ. FOV {span}° (LEISTUNG)", + "{spec} · SPECS: CCTV-DATABASE.COM": "{spec} · SPEZ.: CCTV-DATABASE.COM", + "Atlantic and eastern/central North Pacific; not worldwide cyclone coverage.": "Atlantik und östlicher/zentraler Nordpazifik; keine weltweite Abdeckung von Wirbelstürmen.", + "Cyclone advisories unavailable": "Sturmwarnungen nicht verfügbar", + "Cyclone data unavailable": "Sturmdaten nicht verfügbar", + "Potential tropical cyclone": "Potenzieller tropischer Wirbelsturm", + "Post-tropical cyclone": "Posttropischer Wirbelsturm", + "Hurricane": "Hurrikan", + "Tropical storm": "Tropischer Sturm", + "Tropical depression": "Tropisches Tiefdruckgebiet", + "Subtropical storm": "Subtropischer Sturm", + "Subtropical depression": "Subtropisches Tiefdruckgebiet", + "Track and cone match this advisory": "Zugbahn und Kegel passen zu dieser Warnung", + "Track/cone awaiting advisory {number}": "Zugbahn/Kegel warten auf Warnung {number}", + "Track/cone unavailable": "Zugbahn/Kegel nicht verfügbar", + "Cached advisory · stale source": "Warnung aus dem Cache · Quelle veraltet", + "Loading advisories…": "Warnungen werden geladen…", + "{count} active storms": { + "one": "{count} aktiver Sturm", + "other": "{count} aktive Stürme" + }, + "Position as of {time}": "Position mit Stand {time}", + "Maximum sustained wind: {wind} · Pressure: {pressure}": "Maximaler Dauerwind: {wind} · Luftdruck: {pressure}", + "{name} · {classification} · Advisory {number} · issued {time}": "{name} · {classification} · Warnung {number} · herausgegeben {time}", + "No active NHC/CPHC systems": "Keine aktiven NHC/CPHC-Systeme", + "Advisories unavailable": "Warnungen nicht verfügbar", + "Cyclones · NHC / CPHC": "Wirbelstürme · NHC / CPHC", + "Atlantic · E/C Pacific": "Atlantik · östl./zentr. Pazifik", + "{storms} · {name} selected": "{storms} · {name} ausgewählt", + "Official advisory ↗": "Offizielle Warnung ↗", + "Active NHC and CPHC cyclone advisories": "Aktive Wirbelsturmwarnungen von NHC und CPHC", + "Wind unavailable": "Wind nicht verfügbar", + "Advisory center / forecast track": "Zentrum laut Warnung / Vorhersagebahn", + "Center-track uncertainty cone": "Unsicherheitskegel der Zentrumsbahn", + "Select a storm on the map, or choose a storm in the list to select it and move the camera. Click empty map space to clear the selection. NOAA NHC/CPHC advisory context. The cone describes forecast center-track uncertainty, not storm size or the full hazard area. Forecast point labels are source lead hours, not times computed from advisory issuance. Geometry follows the surface; height is not weather altitude. Consult the official advisory.": "Einen Sturm auf der Karte auswählen oder in der Liste wählen, um ihn auszuwählen und die Kamera dorthin zu bewegen. Auf eine leere Kartenstelle klicken, um die Auswahl aufzuheben. Kontext aus Warnungen von NOAA NHC/CPHC. Der Kegel beschreibt die Unsicherheit der vorhergesagten Zentrumsbahn, nicht die Sturmgröße oder das gesamte Gefahrengebiet. Die Beschriftungen der Vorhersagepunkte sind Vorlaufstunden der Quelle, keine aus dem Ausgabezeitpunkt berechneten Zeiten. Die Geometrie folgt der Oberfläche; die Höhe ist keine Wetterhöhe. Die offizielle Warnung beachten.", + "DRIVE": "AUTO", + "Drive": "Auto", + "WALK": "ZU FUSS", + "Walk": "Zu Fuß", + "BIKE": "RAD", + "Bike": "Fahrrad", + "rate limited": "Anfragelimit erreicht", + "routing service is rate limited": "Routing-Dienst hat das Anfragelimit erreicht", + "route leg too long": "Routenabschnitt zu lang", + "route too long": "Route zu lang", + "{error} — try again in a moment": "{error} – gleich erneut versuchen", + "Routing is rate limited — try again in a moment": "Routing-Anfragelimit erreicht – gleich erneut versuchen", + "Routing unavailable (HTTP {status})": "Routing nicht verfügbar (HTTP {status})", + "Routing unavailable": "Routing nicht verfügbar", + "direction|left": "links", + "direction|right": "rechts", + "direction|slightly left": "leicht links", + "direction|slightly right": "leicht rechts", + "direction|sharply left": "scharf links", + "direction|sharply right": "scharf rechts", + "direction|straight": "geradeaus", + "direction|around": "in Gegenrichtung", + "fork direction|left": "links", + "fork direction|right": "rechts", + "fork direction|slightly left": "leicht links", + "fork direction|slightly right": "leicht rechts", + "fork direction|sharply left": "scharf links", + "fork direction|sharply right": "scharf rechts", + "fork direction|straight": "geradeaus", + "lane direction|left": "linke", + "lane direction|right": "rechte", + "lane direction|slightly left": "halblinke", + "lane direction|slightly right": "halbrechte", + "lane direction|sharply left": "äußerst linke", + "lane direction|sharply right": "äußerst rechte", + "lane direction|straight": "mittlere", + "ordinal|{number}st": "{number}.", + "ordinal|{number}nd": "{number}.", + "ordinal|{number}rd": "{number}.", + "ordinal|{number}th": "{number}.", + "Head out on {road}": "Start auf {road}", + "Head out": "Start", + "Arrive at your destination, on the left": "Ziel erreicht, es liegt links", + "Arrive at your destination, on the right": "Ziel erreicht, es liegt rechts", + "Arrive at your destination": "Ziel erreicht", + "Make a U-turn onto {road}": "Wenden und weiter auf {road}", + "Make a U-turn": "Wenden", + "Continue straight onto {road}": "Geradeaus weiter auf {road}", + "Continue straight": "Geradeaus weiter", + "Turn {direction} onto {road}": "Auf {road} {direction} abbiegen", + "Turn {direction}": "Dann {direction} abbiegen", + "Turn onto {road}": "Auf {road} abbiegen", + "maneuver|Turn": "Abbiegen", + "Continue {direction} onto {road}": "Weiter {direction} auf {road}", + "Continue {direction}": "Weiter {direction}", + "At the end of the road, turn {direction} onto {road}": "Am Ende der Straße {direction} auf {road} abbiegen", + "At the end of the road, turn {direction}": "Am Ende der Straße {direction} abbiegen", + "At the end of the road, continue onto {road}": "Am Ende der Straße weiter auf {road}", + "At the end of the road, continue": "Am Ende der Straße weiter", + "Keep {direction} at the fork onto {road}": "An der Gabelung {direction} halten, weiter auf {road}", + "Keep {direction} at the fork": "An der Gabelung {direction} halten", + "Continue at the fork onto {road}": "An der Gabelung weiter auf {road}", + "Continue at the fork": "An der Gabelung weiter", + "Merge {direction} onto {road}": "Auf {road} {direction} einfädeln", + "Merge {direction}": "Dann {direction} einfädeln", + "Merge onto {road}": "Auf {road} einfädeln", + "maneuver|Merge": "Einfädeln", + "Take the ramp on the {direction} onto {road}": "Die Auffahrt {direction} auf {road} nehmen", + "Take the ramp on the {direction}": "Die Auffahrt {direction} nehmen", + "Take the ramp {direction} onto {road}": "Die Auffahrt {direction} auf {road} nehmen", + "Take the ramp {direction}": "Die Auffahrt {direction} nehmen", + "Take the ramp onto {road}": "Die Auffahrt auf {road} nehmen", + "Take the ramp": "Die Auffahrt nehmen", + "Take the exit on the {direction} onto {road}": "Die Ausfahrt {direction} auf {road} nehmen", + "Take the exit on the {direction}": "Die Ausfahrt {direction} nehmen", + "Take the exit {direction} onto {road}": "Die Ausfahrt {direction} auf {road} nehmen", + "Take the exit {direction}": "Die Ausfahrt {direction} nehmen", + "Take the exit onto {road}": "Die Ausfahrt auf {road} nehmen", + "Take the exit": "Die Ausfahrt nehmen", + "At the roundabout, take the {exit} exit onto {road}": "Im Kreisverkehr die {exit} Ausfahrt auf {road} nehmen", + "At the roundabout, take the {exit} exit": "Im Kreisverkehr die {exit} Ausfahrt nehmen", + "Enter the roundabout onto {road}": "In den Kreisverkehr auf {road} einfahren", + "Enter the roundabout": "In den Kreisverkehr einfahren", + "At the roundabout, turn {direction} onto {road}": "Im Kreisverkehr {direction} auf {road} abbiegen", + "At the roundabout, turn {direction}": "Im Kreisverkehr {direction} abbiegen", + "At the roundabout, continue onto {road}": "Im Kreisverkehr weiter auf {road}", + "At the roundabout, continue": "Im Kreisverkehr weiter", + "Exit the roundabout onto {road}": "Den Kreisverkehr auf {road} verlassen", + "Exit the roundabout": "Den Kreisverkehr verlassen", + "Use the {direction} lane onto {road}": "Die {direction} Spur auf {road} benutzen", + "Use the {direction} lane": "Die {direction} Spur benutzen", + "Continue onto {road}": "Weiter auf {road}", + "maneuver|Continue": "Weiter", + "{mode} — reroute for {modeLower}": "{mode} – Route für {modeLower} neu berechnen", + "CLICK MAP": "KARTE ANKLICKEN", + "SET A": "A SETZEN", + "Click a spot on the globe to place A (click again to cancel)": "Auf eine Stelle des Globus klicken, um A zu setzen (erneut klicken zum Abbrechen)", + "Then click the globe to place the start": "Dann auf den Globus klicken, um den Start zu setzen", + "SET B": "B SETZEN", + "Click a spot on the globe to place B (click again to cancel)": "Auf eine Stelle des Globus klicken, um B zu setzen (erneut klicken zum Abbrechen)", + "Then click the globe to place the destination": "Dann auf den Globus klicken, um das Ziel zu setzen", + "Swap A and B": "A und B tauschen", + "FLY ···": "FLIEGEN ···", + "FLYING": "IM FLUG", + "FLY": "FLIEGEN", + "Fly the camera along the route": "Kamera entlang der Route fliegen lassen", + "Place A and B first": "Zuerst A und B setzen", + "action|CLEAR": "LÖSCHEN", + "Remove the route and both markers": "Route und beide Markierungen entfernen", + "press Escape twice to leave Draw": "zweimal Esc drücken, um Zeichnen zu verlassen", + "{name} is active — turn {name} off, then set {endpoint}": "{name} ist aktiv – {name} ausschalten, dann {endpoint} setzen", + "{name} is active — {leave}, then set {endpoint}": "{name} ist aktiv – {leave}, dann {endpoint} setzen", + "Only the first {count} turns of this route are shown": "Nur die ersten {count} Abbiegungen dieser Route werden gezeigt", + "Turn-by-turn directions": "Abbiegehinweise", + "Another map tool is using clicks — close it, then SET A again": "Ein anderes Kartenwerkzeug nutzt die Klicks – es schließen, dann erneut A SETZEN", + "Routing…": "Route wird berechnet…", + "No route found": "Keine Route gefunden", + "{distance} · {duration} · {mode} · first {count} turns": "{distance} · {duration} · {mode} · erste {count} Abbiegungen", + "{distance} · {duration} · {mode}": "{distance} · {duration} · {mode}", + "Click the globe to place {endpoint}": "Auf den Globus klicken, um {endpoint} zu setzen", + "SET B, then click the globe": "B SETZEN, dann auf den Globus klicken", + "SET A, then click the globe": "A SETZEN, dann auf den Globus klicken", + "Step {step} of {total} · then {leg}": "Schritt {step} von {total} · dann {leg}", + "Step {step} of {total}": "Schritt {step} von {total}", + "Then: {instruction}": "Dann: {instruction}", + "No route found between A and B": "Keine Route zwischen A und B gefunden", + "Routing failed: {error}": "Routing fehlgeschlagen: {error}", + "Routing timed out": "Zeitüberschreitung beim Routing", + "Routing unavailable — no response from the routing service": "Routing nicht verfügbar – keine Antwort vom Routing-Dienst", + "Earthquake source unavailable": "Erdbebenquelle nicht verfügbar", + "live feed unavailable": "Live-Feed nicht verfügbar", + "{value}°N": "{value}°N", + "{value}°S": "{value}°S", + "{value}°E": "{value}°O", + "{value}°W": "{value}°W", + "fire confidence|high": "hoch", + "fire confidence|nominal": "mittel", + "fire confidence|low": "niedrig", + "age|<1h": "<1 h", + "age|{count}h": "{count} h", + "age|{count}d": "{count} T", + "Source snapshot time unavailable": "Zeitpunkt des Quell-Snapshots nicht verfügbar", + "Live data unavailable": "Live-Daten nicht verfügbar", + "Intel Picture": "Lagebild", + "Kinetic 30d": "Kinetisch 30 T", + "Border Crisis": "Grenzkrise", + "Iran Picture": "Lagebild Iran", + "Iran Kinetic": "Iran kinetisch", + "Yemen FLOT": "Jemen Frontlinie", + "Latest Drop": "Neueste Ausgabe", + "GhostMaps file could not be read": "GhostMaps-Datei konnte nicht gelesen werden", + "{count} source links ↗ · click card to open the first": { + "one": "{count} Quelllink ↗ · Karte anklicken zum Öffnen", + "other": "{count} Quelllinks ↗ · Karte anklicken, um den ersten zu öffnen" + }, + "S2 · {name}": "S2 · {name}", + "Report": "Bericht", + "Open the source for {title}": "Quelle für {title} öffnen", + "GhostMaps catalog unavailable": "GhostMaps-Katalog nicht verfügbar", + "LIVE · GitHub {commit} · {message} · checked every {seconds}s": "LIVE · GitHub {commit} · {message} · Prüfung alle {seconds} s", + "GitHub {commit} · {message} · reconnecting for live updates": "GitHub {commit} · {message} · Verbindung für Live-Updates wird wiederhergestellt", + "Connecting to the S2 GhostMaps repository…": "Verbindung zum S2-GhostMaps-Repository…", + "{count} placemarks": { + "one": "{count} Ortsmarke", + "other": "{count} Ortsmarken" + }, + "S2 Underground publishes these KMZ products to GitHub. New uploads are detected within seconds and replace the previous edition automatically. Click a marker for its report.": "S2 Underground veröffentlicht diese KMZ-Produkte auf GitHub. Neue Uploads werden innerhalb von Sekunden erkannt und ersetzen automatisch die vorherige Ausgabe. Für den Bericht eine Markierung anklicken.", + "Malformed GhostMaps catalog": "Fehlerhafter GhostMaps-Katalog", + "Low-accuracy score < 2%": "Ungenauigkeitswert < 2 %", + "Low-accuracy score 2–10%": "Ungenauigkeitswert 2–10 %", + "Low-accuracy score > 10%": "Ungenauigkeitswert > 10 %", + "GNSS integrity source unavailable": "GNSS-Integritätsquelle nicht verfügbar", + "Regional sample · 250 nm radius · cells from visited views over 30 min": "Regionale Stichprobe · Radius 250 NM · Zellen aus besuchten Ansichten über 30 min", + "Retrying automatically at {time} UTC": "Automatischer neuer Versuch um {time} UTC", + "Retrying automatically after provider cooldown": "Automatischer neuer Versuch nach der Sperrzeit des Anbieters", + "Updates automatically after pan or zoom and once a minute. The public feed covers a 250-nautical-mile circle around the view centre; zooming out does not make it a worldwide snapshot. Blank cells are outside sampled coverage or have insufficient observations.": "Aktualisiert sich nach Schwenken oder Zoomen und einmal pro Minute automatisch. Der öffentliche Feed deckt einen Kreis von 250 Seemeilen um die Bildmitte ab; Herauszoomen macht daraus keinen weltweiten Snapshot. Leere Zellen liegen außerhalb der Stichprobe oder haben zu wenige Beobachtungen.", + "Low-accuracy score = 100 × max(0, bad − 1) / total: one aircraft is discounted, so this is not the raw share. Cells need {aircraft} aircraft over {minutes} minutes. Navigation-integrity anomalies are not a detection of jamming or spoofing.": "Ungenauigkeitswert = 100 × max(0, schlecht − 1) / gesamt: Ein Luftfahrzeug wird abgezogen, das ist also nicht der reine Anteil. Zellen brauchen {aircraft} Luftfahrzeuge über {minutes} Minuten. Anomalien der Navigationsintegrität sind kein Nachweis von Jamming oder Spoofing.", + "GNSS snapshot needs a view anchor": "GNSS-Snapshot braucht einen Ansichtsanker", + "GNSS feed rate limited (HTTP 429)": "GNSS-Feed hat das Anfragelimit erreicht (HTTP 429)", + "Malformed GNSS integrity snapshot": "Fehlerhafter GNSS-Integritäts-Snapshot", + "GNSS integrity snapshot has no observation time": "GNSS-Integritäts-Snapshot ohne Beobachtungszeit", + "installation class|AIRFIELD": "FLUGPLATZ", + "installation class|NAVAL BASE": "MARINESTÜTZPUNKT", + "installation class|RANGE": "SCHIESSPLATZ", + "installation class|MILITARY LAND": "MILITÄRGELÄNDE", + "installation class|BASE": "STÜTZPUNKT", + "installation class|BARRACKS": "KASERNE", + "installation class|TRAINING AREA": "ÜBUNGSPLATZ", + "installation class|PLACES CANDIDATE": "AUS GOOGLE PLACES", + "installation class|INSTALLATION": "ANLAGE", + "No mapped sites within {km} km of the contact": "Keine kartierten Standorte im Umkreis von {km} km um den Kontakt", + "{count} mapped sites within {km} km of the contact": { + "one": "{count} kartierter Standort im Umkreis von {km} km um den Kontakt", + "other": "{count} kartierte Standorte im Umkreis von {km} km um den Kontakt" + }, + "No mapped sites in view": "Keine kartierten Standorte im Bild", + "{count} mapped sites in view": { + "one": "{count} kartierter Standort im Bild", + "other": "{count} kartierte Standorte im Bild" + }, + "Too many mapped sites in view to list them all": "Zu viele kartierte Standorte im Bild, um alle aufzulisten", + "Installation context unavailable": "Kontext der Anlage nicht verfügbar", + "Unknown": "Unbekannt", + "Selected Space Mission": "Gewählte Raummission", + "Malformed launch snapshot": "Fehlerhafter Start-Snapshot", + "Heard by your receiver": "Vom eigenen Empfänger empfangen", + "1090 MHz": "1090 MHz", + "978 MHz UAT": "978 MHz UAT", + "browser SDR": "Browser-SDR", + "decoder feed": "Decoder-Feed", + "Your RTL-SDR receiver and decoder feed": "Eigener RTL-SDR-Empfänger und Decoder-Feed", + "Your decoder feed": "Eigener Decoder-Feed", + "Your RTL-SDR receiver": "Eigener RTL-SDR-Empfänger", + "NO CALLSIGN": "KEIN RUFZEICHEN", + "ALT {altitude} FT · GS {speed} KT · TRK {track}": "ALT {altitude} FT · GS {speed} KN · TRK {track}", + "V/S {rate}": "V/S {rate}", + "V/S {rate} FPM": "V/S {rate} FT/MIN", + "POSITION {age}": "POSITION {age}", + "POSITION {seconds} S AGO": "POSITION VOR {seconds} S", + "{count} MSGS": { + "one": "{count} NACHR.", + "other": "{count} NACHR." + }, + "Decoder feeds": "Decoder-Feeds", + "WebUSB + decoder feeds": "WebUSB + Decoder-Feeds", + "opening receiver": "Empfänger wird geöffnet", + "checking decoder feeds": "Decoder-Feeds werden geprüft", + "WebUSB needs desktop Chrome or Edge": "WebUSB braucht Chrome oder Edge auf dem Desktop", + "connect a receiver in Radio": "Empfänger unter Radio verbinden", + "receiver is in FM mode": "Empfänger ist im FM-Modus", + "listening": "empfängt", + "USB error": "USB-Fehler", + "${amount}K": "{amount} Tsd. $", + "${amount}M": "{amount} Mio. $", + "${amount}B": "{amount} Mrd. $", + "fire cause|Human": "Mensch", + "fire cause|Natural": "Natürlich", + "fire cause|Undetermined": "Ungeklärt", + "fire cause|Unknown": "Unbekannt", + "fire behavior|Minimal": "Minimal", + "fire behavior|Moderate": "Mäßig", + "fire behavior|Active": "Aktiv", + "fire behavior|Extreme": "Extrem", + "Type {level} Incident": "Einsatz Typ {level}", + "age|{count}m": "{count} min", + "{acres} ac": { + "one": "{acres} Acre", + "other": "{acres} Acres" + }, + "{percent}% contained": "{percent} % eingedämmt", + "containment unknown": "Eindämmung unbekannt", + "{cause} cause": "Ursache: {cause}", + "{personnel} personnel": { + "one": "{personnel} Einsatzkraft", + "other": "{personnel} Einsatzkräfte" + }, + "{county} County": "{county} County", + "{cost} to date": "{cost} bisher", + "discovered {age} ago": "entdeckt vor {age}", + "updated {age} ago": "aktualisiert vor {age}", + "part of {complex}": "Teil von {complex}", + "InciWeb ↗ · click card to open": "InciWeb ↗ · Karte anklicken zum Öffnen", + "FIRE · {name}": "BRAND · {name}", + "Unnamed incident": "Unbenannter Einsatz", + "Open {title} on InciWeb": "{title} auf InciWeb öffnen", + "Perimeter source unavailable": "Quelle der Brandgrenzen nicht verfügbar", + "Not contained or unknown": "Nicht eingedämmt oder unbekannt", + "Under 50% contained": "Unter 50 % eingedämmt", + "50–99% contained": "50–99 % eingedämmt", + "Fully contained": "Vollständig eingedämmt", + "Colour shows reported containment. Perimeters are simplified to about 100 m.": "Die Farbe zeigt die gemeldete Eindämmung. Brandgrenzen sind auf etwa 100 m vereinfacht.", + "Malformed perimeter snapshot": "Fehlerhafter Brandgrenzen-Snapshot", + "radio tag|All": "Alle", + "Directory refresh degraded; showing the previous station catalog.": "Verzeichnisaktualisierung eingeschränkt; der vorherige Senderkatalog wird gezeigt.", + "Radio directory coverage is degraded.": "Abdeckung des Radioverzeichnisses ist eingeschränkt.", + "Directory refresh failed; showing the previous station catalog.": "Verzeichnisaktualisierung fehlgeschlagen; der vorherige Senderkatalog wird gezeigt.", + "Radio directory is temporarily unavailable.": "Radioverzeichnis vorübergehend nicht verfügbar.", + "radio|NEWS": "NEWS", + "radio|WEATHER": "WETTER", + "radio|OTHER": "SONST.", + "Broadcaster stream is unavailable or blocked by the browser.": "Der Stream des Senders ist nicht verfügbar oder wird vom Browser blockiert.", + "Playback requires a direct click or tap.": "Die Wiedergabe erfordert einen direkten Klick oder Tipp.", + "Broadcaster stream could not be started.": "Der Stream des Senders konnte nicht gestartet werden.", + "overview": "Übersicht", + "cloud unknown": "Bewölkung unbekannt", + "{percent}% scene cloud": "{percent} % Bewölkung in der Szene", + "{min}–{max}% scene cloud": "{min}–{max} % Bewölkung in der Szene", + "Comparison in use by another scene": "Vergleich wird von einer anderen Szene verwendet", + "Esri map unavailable · no swipe": "Esri-Karte nicht verfügbar · kein Bildvergleich", + "Swipe needs a globe map": "Bildvergleich braucht eine Globuskarte", + "Imagery stays on Esri · CLEAR to use Google 3D": "Bilder bleiben auf Esri · LÖSCHEN, um Google 3D zu verwenden", + "Imagery catalog unavailable": "Bildkatalog nicht verfügbar", + "Catalog truncated · a newer clear day may exist": "Katalog gekürzt · ein neuerer klarer Tag ist möglich", + "{label} catalog unavailable · {detail}": "{label}-Katalog nicht verfügbar · {detail}", + "Daily overview for today may still be empty until the pass": "Die tägliche Übersicht für heute kann bis zum Überflug noch leer sein", + "Box and images cleared": "Bereich und Bilder gelöscht", + "MORE DETAIL · 30 m": "MEHR DETAILS · 30 m", + "Sentinel-2 and Landsat via HLS, 30 m, every 2–6 days": "Sentinel-2 und Landsat über HLS, 30 m, alle 2–6 Tage", + "DAILY OVERVIEW · 250 m": "TÄGLICHE ÜBERSICHT · 250 m", + "VIIRS daily mosaic, 250 m, follows broad changes; little detail under 25 km": "VIIRS-Tagesmosaik, 250 m, zeigt großräumige Veränderungen; kaum Details unter 25 km", + "Sentinel-2": "Sentinel-2", + "Sentinel-2 via HLS": "Sentinel-2 über HLS", + "Landsat 8/9": "Landsat 8/9", + "Landsat 8/9 via HLS": "Landsat 8/9 über HLS", + "Daily overview": "Tägliche Übersicht", + "Box edges must be finite": "Die Ränder des Bereichs müssen endlich sein", + "Longitudes must be within ±180°": "Längengrade müssen innerhalb von ±180° liegen", + "Select one side of the dateline": "Eine Seite der Datumsgrenze wählen", + "Box must enclose an area": "Der Bereich muss eine Fläche umschließen", + "CelesTrak unreachable": "CelesTrak nicht erreichbar", + "DOCKED · {name} · +{extra}": "ANGEDOCKT · {name} · +{extra}", + "DOCKED · {name}": "ANGEDOCKT · {name}", + "{name} needs the Google 3D map: choose it under MAP SOURCE": "{name} braucht die Google-3D-Karte: unter KARTENQUELLE auswählen", + "zoom in to a street to open {name}": "auf eine Straße hineinzoomen, um {name} zu öffnen", + "loading coverage...": "Abdeckung wird geladen...", + "No street-level imagery within {radius} m of that point": "Keine Bilder auf Straßenebene im Umkreis von {radius} m um diesen Punkt", + "No street-level imagery within {radius} m of the view centre": "Keine Bilder auf Straßenebene im Umkreis von {radius} m um die Bildmitte", + "Zoom in to see street-level coverage": "Hineinzoomen, um die Abdeckung auf Straßenebene zu sehen", + "Point the camera at the ground for street-level coverage": "Kamera auf den Boden richten, um die Abdeckung auf Straßenebene zu sehen", + "Coverage tile failed": "Abdeckungskachel fehlgeschlagen", + "The photo could not be loaded": "Das Foto konnte nicht geladen werden", + "{name} photo. ← and → step along the sequence. On a 360° photo, drag or use Shift+← →, ↑ ↓ to look around, and + − to zoom": "{name}-Foto. ← und → blättern durch die Sequenz. Bei einem 360°-Foto ziehen oder Umschalt+← →, ↑ ↓ zum Umsehen und + − zum Zoomen verwenden", + "{name} street-level photo": "{name}-Foto auf Straßenebene", + "Previous photo in this sequence (←)": "Vorheriges Foto dieser Sequenz (←)", + "Next photo in this sequence (→)": "Nächstes Foto dieser Sequenz (→)", + "Aim the middle of the view at a street to look for imagery there": "Die Bildmitte auf eine Straße richten, um dort nach Bildern zu suchen", + "KEY REJECTED": "SCHLÜSSEL ABGELEHNT", + "GOOGLE_MAPS_API_KEY is not set": "GOOGLE_MAPS_API_KEY ist nicht gesetzt", + "The Google Maps JavaScript API could not load": "Die Google Maps JavaScript API konnte nicht geladen werden", + "Google Street View": "Google Street View", + "GOOGLE STREET VIEW": "GOOGLE STREET VIEW", + "Google refused GOOGLE_MAPS_API_KEY for Street View — check that the Maps JavaScript API is enabled for it and this site is an allowed referrer": "Google hat GOOGLE_MAPS_API_KEY für Street View abgelehnt – prüfen, ob die Maps JavaScript API dafür aktiviert und diese Website als Referrer zugelassen ist", + "Street View did not answer — check the network, and that the Maps JavaScript API is enabled for GOOGLE_MAPS_API_KEY": "Street View antwortet nicht – Netzwerk prüfen und ob die Maps JavaScript API für GOOGLE_MAPS_API_KEY aktiviert ist", + "click a street to open Street View": "auf eine Straße klicken, um Street View zu öffnen", + "Street View has no imagery for this place": "Street View hat keine Bilder für diesen Ort", + "KartaView has no position for this photo": "KartaView hat keine Position für dieses Foto", + "The KartaView photo could not be loaded": "Das KartaView-Foto konnte nicht geladen werden", + "zoom in to see KartaView coverage": "hineinzoomen, um die KartaView-Abdeckung zu sehen", + "no KartaView photos in view": "keine KartaView-Fotos im Bild", + "KartaView is rate-limiting requests — they resume on their own": "KartaView begrenzt die Anfragen – sie laufen von selbst weiter", + "KartaView’s photos here are archived and cannot be shown": "Die KartaView-Fotos hier sind archiviert und können nicht angezeigt werden", + "KartaView did not filter this area in time — move the map to ask again": "KartaView hat dieses Gebiet nicht rechtzeitig gefiltert – Karte verschieben, um erneut anzufragen", + "None of KartaView’s photos here pass the imagery filter": "Keines der KartaView-Fotos hier besteht den Bildfilter", + "KartaView did not answer in time — try again": "KartaView hat nicht rechtzeitig geantwortet – erneut versuchen", + "KartaView could not be reached — check the network": "KartaView ist nicht erreichbar – Netzwerk prüfen", + "KartaView sent an answer that could not be read": "KartaView hat eine unlesbare Antwort gesendet", + "KartaView is rate-limiting requests": "KartaView begrenzt die Anfragen", + "KartaView sent too much data": "KartaView hat zu viele Daten gesendet", + "KartaView is rate-limiting requests — try again in a moment": "KartaView begrenzt die Anfragen – gleich erneut versuchen", + "KartaView has no such photo": "KartaView hat dieses Foto nicht", + "Mapillary rejected MAPILLARY_CLIENT_TOKEN — replace it in Provider Settings": "Mapillary hat MAPILLARY_CLIENT_TOKEN abgelehnt – in den Anbieter-Einstellungen ersetzen", + "Coverage requests are being rate-limited — they resume on their own": "Abdeckungsanfragen werden begrenzt – sie laufen von selbst weiter", + "The Panoramax photo could not be loaded": "Das Panoramax-Foto konnte nicht geladen werden", + "Panoramax is busy — coverage resumes on its own": "Panoramax ist ausgelastet – die Abdeckung lädt von selbst weiter", + "no Panoramax photos in view": "keine Panoramax-Fotos im Bild", + "no Panoramax photos here match the filters": "keine Panoramax-Fotos hier passen zu den Filtern", + "Panoramax sent a map tile that could not be read": "Panoramax hat eine unlesbare Kartenkachel gesendet", + "This Panoramax photo is no longer available": "Dieses Panoramax-Foto ist nicht mehr verfügbar", + "zoom in to see Panoramax coverage": "hineinzoomen, um die Panoramax-Abdeckung zu sehen", + "Panoramax did not answer in time — try again": "Panoramax hat nicht rechtzeitig geantwortet – erneut versuchen", + "Panoramax could not be reached — check the connection": "Panoramax ist nicht erreichbar – Verbindung prüfen", + "Panoramax sent too much data": "Panoramax hat zu viele Daten gesendet", + "Panoramax is busy": "Panoramax ist ausgelastet", + "Panoramax sent an unreadable answer": "Panoramax hat eine unlesbare Antwort gesendet", + "Sequence images unavailable": "Sequenzbilder nicht verfügbar", + "No street-level imagery providers configured": "Keine Anbieter für Bilder auf Straßenebene konfiguriert", + "(by upload date)": "(nach Upload-Datum)", + "Open the Street Level panel to view imagery": "Bereich Straßenebene öffnen, um Bilder anzuzeigen", + "Image could not be opened": "Bild konnte nicht geöffnet werden", + "TeleGeography load failed": "TeleGeography konnte nicht geladen werden", + "UNAVAILABLE · {source} · Roads unavailable": "NICHT VERFÜGBAR · {source} · Straßen nicht verfügbar", + "Roads: {source}": "Straßen: {source}", + "TomTom roads unavailable while the traffic service is unreachable": "TomTom-Straßen nicht verfügbar, solange der Verkehrsdienst nicht erreichbar ist", + "Hybrid unavailable while the traffic service is unreachable": "Hybrid nicht verfügbar, solange der Verkehrsdienst nicht erreichbar ist", + "TomTom roads need a TomTom key": "TomTom-Straßen brauchen einen TomTom-Schlüssel", + "Hybrid needs a TomTom key": "Hybrid braucht einen TomTom-Schlüssel", + "Local surface still loading": "Lokale Oberfläche lädt noch", + "Partial coverage": "Teilweise Abdeckung", + "Detailed roads unavailable": "Detaillierte Straßen nicht verfügbar", + "Reduced detail coverage": "Reduzierte Detailabdeckung", + "TomTom roads only, each with its live flow": "Nur TomTom-Straßen, jeweils mit Live-Verkehrsfluss", + "TomTom roads only, each with its live flow (needs a TomTom key)": "Nur TomTom-Straßen, jeweils mit Live-Verkehrsfluss (braucht einen TomTom-Schlüssel)", + "OpenStreetMap roads, with TomTom flow matched when available": "OpenStreetMap-Straßen, mit TomTom-Verkehrsfluss, wo verfügbar", + "TomTom roads first; OpenStreetMap fills the rest, simulated": "Zuerst TomTom-Straßen; OpenStreetMap füllt den Rest, simuliert", + "TomTom roads first; OpenStreetMap fills the rest, simulated (needs a TomTom key)": "Zuerst TomTom-Straßen; OpenStreetMap füllt den Rest, simuliert (braucht einen TomTom-Schlüssel)", + "Hybrid": "Hybrid", + "TomTom key unavailable": "TomTom-Schlüssel nicht verfügbar", + "TomTom daily budget reached": "TomTom-Tagesbudget erreicht", + "TomTom upstream unreachable": "TomTom-Upstream nicht erreichbar", + "TomTom flow unavailable": "TomTom-Verkehrsfluss nicht verfügbar", + "SIMULATED — {reason}": "SIMULIERT – {reason}", + "OpenFreeMap tiles rate-limited": "OpenFreeMap-Kacheln: Anfragelimit erreicht", + "OpenFreeMap tiles timed out": "Zeitüberschreitung bei OpenFreeMap-Kacheln", + "OpenFreeMap tiles unavailable": "OpenFreeMap-Kacheln nicht verfügbar", + "occupancy|empty": "leer", + "occupancy|many seats available": "viele Sitzplätze frei", + "occupancy|few seats available": "wenige Sitzplätze frei", + "occupancy|standing room only": "nur Stehplätze", + "occupancy|crushed standing room only": "nur noch enge Stehplätze", + "occupancy|full": "voll", + "occupancy|not accepting passengers": "keine Fahrgastaufnahme", + "occupancy|not boardable": "kein Einstieg möglich", + "Route {route}": "Linie {route}", + "Vehicle {vehicle}": "Fahrzeug {vehicle}", + "vehicle motion|Stopped": "Steht", + "No recent fix": "Keine aktuelle Position", + "Waiting for update": "Warte auf Aktualisierung", + "Moving": "In Bewegung", + "reported {speed} km/h": "gemeldet {speed} km/h", + "reported hdg {heading}°": "gemeldeter Kurs {heading}°", + "Last report: stopped at stop {stop}": "Letzte Meldung: hält an Haltestelle {stop}", + "Last report: arriving at stop {stop}": "Letzte Meldung: erreicht Haltestelle {stop}", + "Last report: next stop {stop}": "Letzte Meldung: nächster Halt {stop}", + "Shown at street level · depth not in the feed": "Auf Straßenebene gezeigt · Tiefe nicht im Feed", + "Reported {seconds} s ago": "Gemeldet vor {seconds} s", + "Reported {minutes} min ago": "Gemeldet vor {minutes} min", + "shown {seconds} s behind": "{seconds} s verzögert gezeigt", + "{reported} (feed time)": "{reported} (Feed-Zeit)", + "Available trail: {minutes} min (limited)": "Verfügbare Spur: {minutes} min (begrenzt)", + "Available trail: {minutes} min": "Verfügbare Spur: {minutes} min", + "Bus": "Bus", + "Tram": "Straßenbahn", + "Subway": "U-Bahn", + "Train": "Zug", + "Ferry": "Fähre", + "Transit vehicle": "ÖPNV-Fahrzeug", + "{speed}KT": "{speed}KN", + "{heading}DEG": "{heading}°", + "AIS live load failed": "AIS-Live-Daten konnten nicht geladen werden", + "AISSTREAM_API_KEY not set": "AISSTREAM_API_KEY nicht gesetzt", + "live feed unsupported": "Live-Feed nicht unterstützt", + "connecting to feed…": "Verbindung zum Feed…", + "feed disconnected": "Feed getrennt", + "feed down": "Feed ausgefallen", + "feed idle": "Feed inaktiv", + "API key rejected — check AISSTREAM_API_KEY": "API-Schlüssel abgelehnt – AISSTREAM_API_KEY prüfen", + "feed silent {seconds}s — no AIS data": "Feed stumm seit {seconds} s – keine AIS-Daten", + "feed silent — no AIS data": "Feed stumm – keine AIS-Daten", + "feed down — retrying slowly (attempt {attempt})": "Feed ausgefallen – langsame Wiederholung (Versuch {attempt})", + "reconnecting to feed… (attempt {attempt})": "Verbindung zum Feed wird wiederhergestellt… (Versuch {attempt})", + "feed down — retrying slowly": "Feed ausgefallen – langsame Wiederholung", + "reconnecting to feed…": "Verbindung zum Feed wird wiederhergestellt…", + "Focus vessel {name}, MMSI {mmsi}": "Schiff {name} fokussieren, MMSI {mmsi}", + "Hidden by this map source · choose a globe map": "Von dieser Kartenquelle ausgeblendet · eine Globuskarte wählen", + "Weather image HTTP {status}": "Wetterbild HTTP {status}", + "Weather HTTP {status}": "Wetter HTTP {status}", + "Frame unavailable; previous observation retained": "Frame nicht verfügbar; vorherige Beobachtung bleibt erhalten", + "Weather imagery unavailable": "Wetterbilder nicht verfügbar", + "Weather source unavailable; previous observation retained": "Wetterquelle nicht verfügbar; vorherige Beobachtung bleibt erhalten", + "Weather unavailable": "Wetter nicht verfügbar", + "No frame within {gap} min of {time}": "Kein Frame innerhalb von {gap} min um {time}", + "No frame within {gap} h of {time}": "Kein Frame innerhalb von {gap} h um {time}", + "{hours}h {minutes}m ago": "vor {hours} h {minutes} min", + "{minutes}m ago": "vor {minutes} min", + "{state} · {time} · {lag}": "{state} · {time} · {lag}", + "Observed": "Beobachtet", + "History": "Verlauf", + "Observation unavailable": "Beobachtung nicht verfügbar", + "Waiting for observation": "Warte auf Beobachtung", + "{detail} · synced": "{detail} · synchronisiert", + "{detail} · nearest": "{detail} · nächstgelegen", + "RADAR REFLECTIVITY · dBZ": "RADARREFLEKTIVITÄT · dBZ", + "LIGHTNING DENSITY · 15 min accumulation": "BLITZDICHTE · 15-min-Summe", + "GLOBAL INFRARED · hourly": "GLOBALES INFRAROT · stündlich", + "GOES INFRARED · ~5 min": "GOES-INFRAROT · ~5 min", + "{state}: {time}": "{state}: {time}", + "Latest observation": "Letzte Beobachtung", + "frame {index}/{total}": "Frame {index}/{total}", + "loading": "lädt", + "Observation: unavailable": "Beobachtung: nicht verfügbar", + "Contiguous US · gaps ≠ no rain": "USA (Festland) · Lücken ≠ kein Regen", + "Americas + Pacific · not individual strikes": "Amerika + Pazifik · keine Einzelblitze", + "Color: strikes/km²/min ×10³": "Farbe: Blitze/km²/min ×10³", + "60°S–60°N · typically 2–3 h delayed": "60°S–60°N · meist 2–3 h verzögert", + "North America · infrared imagery": "Nordamerika · Infrarotbilder", + "Reduced motion · history playback unavailable": "Reduzierte Bewegung · Verlaufswiedergabe nicht verfügbar", + "Reduced motion · manual history available": "Reduzierte Bewegung · manueller Verlauf verfügbar", + "Rain radar · US": "Regenradar · USA", + "Lightning density · 15 min": "Blitzdichte · 15 min", + "Satellite clouds": "Satellitenwolken", + "Americas + Pacific": "Amerika + Pazifik", + "Global · 60°S–60°N": "Global · 60°S–60°N", + "North America": "Nordamerika", + "Source observations delayed": "Beobachtungen der Quelle verzögert", + "Stale source": "Quelle veraltet", + "Loading next frame…": "Nächster Frame wird geladen…", + "Map center outside coverage": "Kartenmitte außerhalb der Abdeckung", + "strikes/km²/min ×10³": "Blitze/km²/min ×10³", + "N. America": "Nordamerika", + "Global": "Global", + "Hourly global mosaic; usually 2–3 hours delayed": "Stündliches globales Mosaik; meist 2–3 Stunden verzögert", + "GOES regional clouds; approximately 5-minute updates": "Regionale GOES-Wolken; Aktualisierung etwa alle 5 Minuten", + "Clouds only": "Nur Wolken", + "Apply the full cloud brightness key; 100% filter strength": "Volle Wolkenhelligkeitsskala anwenden; Filterstärke 100 %", + "Full": "Voll", + "Show the complete infrared image; 0% filter strength": "Vollständiges Infrarotbild zeigen; Filterstärke 0 %", + "Soft": "Weich", + "Vivid": "Kräftig", + "Image opacity; does not alter the observed values": "Bilddeckkraft; ändert die beobachteten Werte nicht", + "View US radar": "US-Radar anzeigen", + "View Americas & Pacific": "Amerika & Pazifik anzeigen", + "View coverage": "Abdeckung anzeigen", + "{value} strikes/km²/min ×10³ (15-minute density)": "{value} Blitze/km²/min ×10³ (15-Minuten-Dichte)", + "{value} dBZ radar reflectivity": "{value} dBZ Radarreflektivität", + "STALE · cached source metadata": "VERALTET · Quellmetadaten aus dem Cache", + "Map center is outside source coverage": "Kartenmitte liegt außerhalb der Quellabdeckung", + "NOAA/NWS 15-minute lightning density derived from Vaisala NLDN/GLD360. Coverage 110°E across the Pacific/Americas to 0°, 25°S–80°N. Not a live strike count, global coverage or a safety warning.": "NOAA/NWS-Blitzdichte über 15 Minuten, abgeleitet aus Vaisala NLDN/GLD360. Abdeckung von 110°O über Pazifik/Amerika bis 0°, 25°S–80°N. Keine Live-Blitzzählung, keine globale Abdeckung und keine Sicherheitswarnung.", + "NOAA MRMS radar echoes indicate precipitation patterns, not rain rate, a storm warning or a future forecast. Native source approximately 1 km; display is limited to level 6. Frames use exact advertised observation times.": "NOAA-MRMS-Radarechos zeigen Niederschlagsmuster, nicht die Regenrate, keine Unwetterwarnung und keine Vorhersage. Native Quellauflösung etwa 1 km; die Anzeige ist auf Stufe 6 begrenzt. Frames verwenden die exakt angegebenen Beobachtungszeiten.", + "GOES-19/18 longwave infrared Band 14 regional; NESDIS global longwave mosaic. Clouds only dims everything but bright, cold cloud tops; a brightness filter, not a cloud mask. Coverage and freshness differ by region.": "GOES-19/18 langwelliges Infrarot Band 14 regional; globales langwelliges NESDIS-Mosaik. „Nur Wolken“ dunkelt alles außer hellen, kalten Wolkenobergrenzen ab; ein Helligkeitsfilter, keine Wolkenmaske. Abdeckung und Aktualität unterscheiden sich je nach Region.", + "REGION": "REGION", + "IMAGE": "BILD", + "FILTER": "FILTER", + "Cloud filter strength": "Stärke des Wolkenfilters", + "OPACITY": "DECKKRAFT", + "Infrared decode failed": "Infrarot-Dekodierung fehlgeschlagen", + "Weather prefetch unavailable": "Wetter-Vorabruf nicht verfügbar", + "Weather tiles unavailable · previous frame retained": "Wetterkacheln nicht verfügbar · vorheriger Frame bleibt erhalten", + "Some weather tiles unavailable": "Einige Wetterkacheln nicht verfügbar", + "Malformed weather manifest": "Fehlerhaftes Wetter-Manifest", + "Weather request timed out": "Zeitüberschreitung bei der Wetterabfrage", + "Temperature field unavailable": "Temperaturfeld nicht verfügbar", + "Mean sea level pressure field unavailable": "Feld des Luftdrucks auf Meereshöhe nicht verfügbar", + "Wind upstream unavailable": "Wind-Upstream nicht verfügbar", + "{source} HTTP {status}": "{source} HTTP {status}", + "Wind": "Wind", + "Wind source unavailable": "Windquelle nicht verfügbar", + "Forecast · does not follow history": "Vorhersage · folgt nicht dem Verlauf", + "Wind motion": "Windbewegung", + "Wind speed": "Windgeschwindigkeit", + "Sea-level pressure": "Luftdruck auf Meereshöhe", + "Air temperature · 2 m": "Lufttemperatur · 2 m", + "Global · 1° grid": "Global · 1°-Raster", + "{model} forecast · {time}": "{model}-Vorhersage · {time}", + "Loading forecast": "Vorhersage wird geladen", + "Preparing flow": "Strömung wird vorbereitet", + "Selected field unavailable": "Gewähltes Feld nicht verfügbar", + "Cached forecast · stale": "Vorhersage aus dem Cache · veraltet", + "ECMWF IFS surface forecast": "ECMWF-IFS-Bodenvorhersage", + "NOAA GFS surface forecast": "NOAA-GFS-Bodenvorhersage", + "Reduced motion": "Reduzierte Bewegung", + "Pause visual flow; forecast time does not advance with animation": "Visuelle Strömung pausieren; die Vorhersagezeit läuft mit der Animation nicht weiter", + "None": "Keine", + "Speed": "Geschwindigkeit", + "Pressure": "Luftdruck", + "Temperature": "Temperatur", + "Wind trails with no field shading": "Windspuren ohne Feldschattierung", + "How hard the surface wind is blowing": "Wie stark der Bodenwind weht", + "Sea-level air pressure: broad highs and lows": "Luftdruck auf Meereshöhe: großräumige Hochs und Tiefs", + "Air temperature two meters above the surface": "Lufttemperatur zwei Meter über dem Boden", + "Wind speed units": "Einheiten der Windgeschwindigkeit", + "Read wind at map center": "Wind in der Kartenmitte ablesen", + "Read the forecast at the center of the map without changing selection": "Vorhersage in der Kartenmitte ablesen, ohne die Auswahl zu ändern", + "{model} forecast · {field} ({unit})": "{model}-Vorhersage · {field} ({unit})", + "Valid: {time}": "Gültig: {time}", + "preparing": "wird vorbereitet", + "Issued: {time}": "Ausgegeben: {time}", + "Selected field unavailable · wind remains visible": "Gewähltes Feld nicht verfügbar · Wind bleibt sichtbar", + "{error} · wind remains visible": "{error} · Wind bleibt sichtbar", + "Surface wind at 10 m. Approximately 1° global grid. Curves follow the 10 m wind field, lifted 12 km for visibility; display height is not weather altitude. View lighting is for readability. Animation shows flow through one fixed forecast; it does not advance time. Color fields drape the globe basemap or the active photorealistic 3D Tiles.": "Bodenwind in 10 m Höhe. Globales Raster von etwa 1°. Die Kurven folgen dem 10-m-Windfeld, zur Sichtbarkeit 12 km angehoben; die Anzeigehöhe ist keine Wetterhöhe. Die Beleuchtung dient der Lesbarkeit. Die Animation zeigt die Strömung einer festen Vorhersage; die Zeit läuft nicht weiter. Farbfelder liegen auf der Globus-Basiskarte oder den aktiven fotorealistischen 3D Tiles.", + "MODEL": "MODELL", + "FIELD": "FELD", + "UNITS": "EINHEITEN", + "MOTION": "BEWEGUNG", + "Forecast": "Vorhersage", + "N": "N", + "NNE": "NNO", + "NE": "NO", + "ENE": "ONO", + "E": "O", + "ESE": "OSO", + "SE": "SO", + "SSE": "SSO", + "S": "S", + "SSW": "SSW", + "SW": "SW", + "WSW": "WSW", + "W": "W", + "WNW": "WNW", + "NW": "NW", + "NNW": "NNW", + "No surface reading": "Kein Bodenmesswert", + "Aim the map center at Earth": "Kartenmitte auf die Erde richten", + "A location reading needs a loaded forecast and the Earth at the center of the view.": "Ein Ortswert braucht eine geladene Vorhersage und die Erde in der Bildmitte.", + "Interpolated model forecast on an approximately 1° grid. Broad weather patterns, not a street-level measurement.": "Interpolierte Modellvorhersage auf einem Raster von etwa 1°. Großräumige Wetterlagen, keine Messung auf Straßenebene.", + " · calm": " · windstill", + " from {direction}": " aus {direction}", + "WIND AT {coordinates}": "WIND BEI {coordinates}", + "{model} · valid {time}": "{model} · gültig {time}", + "Wind speed field unavailable": "Feld der Windgeschwindigkeit nicht verfügbar", + "Globe imagery unavailable": "Globusbilder nicht verfügbar", + "Globe field image unavailable": "Feldbild für den Globus nicht verfügbar", + "Unknown wind model": "Unbekanntes Windmodell", + "Unknown weather overlay": "Unbekanntes Wetter-Overlay", + "Wind request timed out": "Zeitüberschreitung bei der Windabfrage", + "Malformed wind manifest": "Fehlerhaftes Wind-Manifest", + "Malformed wind grid": "Fehlerhaftes Windraster", + "Google 3D tiles unavailable — check the key's API restrictions, quota, or network": "Google 3D Tiles nicht verfügbar – API-Einschränkungen des Schlüssels, Kontingent oder Netzwerk prüfen", + "Needs {envVars} — add it in Provider Settings — or a Cesium ion token for the ion-hosted route": "Benötigt {envVars} – in den Anbieter-Einstellungen hinzufügen – oder ein Cesium-ion-Token für die von ion gehostete Variante", + "Exit cockpit to fly to a camera": "Cockpit verlassen, um zu einer Kamera zu fliegen", + "Exit cockpit to fly to a location": "Cockpit verlassen, um zu einem Ort zu fliegen", + "Exit cockpit to fly to a photo": "Cockpit verlassen, um zu einem Foto zu fliegen", + "Exit cockpit to fly to a shared view": "Cockpit verlassen, um zu einer geteilten Ansicht zu fliegen", + "Exit cockpit to fly to a target": "Cockpit verlassen, um zu einem Ziel zu fliegen", + "Exit cockpit to fly to a vessel": "Cockpit verlassen, um zu einem Schiff zu fliegen", + "Exit cockpit to fly to a fire": "Cockpit verlassen, um zu einem Brand zu fliegen", + "Exit cockpit to fly to a route": "Cockpit verlassen, um zu einer Route zu fliegen", + "Exit cockpit to fly to a file": "Cockpit verlassen, um zu einer Datei zu fliegen", + "Exit cockpit to fly to a scene": "Cockpit verlassen, um zu einer Szene zu fliegen", + "Exit cockpit to view weather coverage": "Cockpit verlassen, um die Wetterabdeckung anzuzeigen", + "Exit cockpit to fly to a cyclone": "Cockpit verlassen, um zu einem Wirbelsturm zu fliegen", + "Exit cockpit to fly to an aircraft": "Cockpit verlassen, um zu einem Luftfahrzeug zu fliegen", + "Exit cockpit to fly to a satellite": "Cockpit verlassen, um zu einem Satelliten zu fliegen", + "Exit cockpit to frame contacts": "Cockpit verlassen, um Kontakte ins Bild zu nehmen", + "Focusing {label}": "{label} wird fokussiert", + "Source": "Quelle", + "Camera ownership changed": "Kamerasteuerung hat gewechselt", + "Saved project could not be read; storage preserved. Import a valid file to resume saving.": "Gespeichertes Projekt konnte nicht gelesen werden; der Speicher bleibt erhalten. Eine gültige Datei importieren, um wieder speichern zu können.", + "Scene layer turned off": "Szenenebene ausgeschaltet", + "Stopped": "Gestoppt", + "Scene not saved — existing saved project could not be read. Export edits or import a valid file.": "Szene nicht gespeichert – das vorhandene gespeicherte Projekt konnte nicht gelesen werden. Änderungen exportieren oder eine gültige Datei importieren.", + "Scene not saved — {reason}": "Szene nicht gespeichert – {reason}", + "Scene not saved — browser storage unavailable": "Szene nicht gespeichert – Browserspeicher nicht verfügbar", + "Cannot update {scene}: shot inventory changed": "{scene} kann nicht aktualisiert werden: Aufnahmenbestand hat sich geändert", + "Cannot update {scene}: evidence beats changed": "{scene} kann nicht aktualisiert werden: Beweisschritte haben sich geändert", + "Cannot update {scene}: shot bindings are incomplete": "{scene} kann nicht aktualisiert werden: Aufnahmeverknüpfungen sind unvollständig", + "Updated {count} shots: {scene}": { + "one": "{count} Aufnahme aktualisiert: {scene}", + "other": "{count} Aufnahmen aktualisiert: {scene}" + }, + "Appended {count} shots: {scene}": { + "one": "{count} Aufnahme angehängt: {scene}", + "other": "{count} Aufnahmen angehängt: {scene}" + }, + "Could not leave scene: {scene}": "Szene konnte nicht verlassen werden: {scene}", + "Seeked: {scene} / {shot}": "Gesprungen: {scene} / {shot}", + "Seeking scene clock": "Szenenuhr wird gespult", + "Scene transition limit reached — load a shot to reset": "Limit für Szenenwechsel erreicht – eine Aufnahme laden, um es zurückzusetzen", + "Export failed: {error}": "Export fehlgeschlagen: {error}", + "Importing project": "Projekt wird importiert", + "Imported {file}": "{file} importiert", + "Import failed: {error}": "Import fehlgeschlagen: {error}", + "Import failed (could not read JSON file)": "Import fehlgeschlagen (JSON-Datei konnte nicht gelesen werden)", + "Layers refused: {layers}": "Ebenen abgelehnt: {layers}", + "Camera move interrupted": "Kameraflug unterbrochen", + "Scene media timed out": "Zeitüberschreitung bei Szenenmedien", + "Action complete": "Aktion abgeschlossen", + "Action unavailable or cancelled": "Aktion nicht verfügbar oder abgebrochen", + "Scene actions": "Szenenaktionen", + "Select a feature or use Tab and Enter to choose an action.": "Ein Objekt auswählen oder mit Tab und Enter eine Aktion wählen.", + "Selected feature: {feature}. Choose an action.": "Ausgewähltes Objekt: {feature}. Aktion wählen.", + "Bhote Koshi Evidence Sequence": "Bhote Koshi: Beweisfolge", + "Nepal Flood Incident": "Flutereignis Nepal", + "Global Incident Context": "Globaler Ereigniskontext", + "Nepal-Focused Globe Rotation": "Globusdrehung mit Fokus auf Nepal", + "Bhote Koshi Regional Approach": "Bhote Koshi: Anflug auf die Region", + "Bhote Koshi Nearby Cities": "Bhote Koshi: Städte in der Nähe", + "Bhote Koshi Incident Corridor": "Bhote Koshi: Ereigniskorridor", + "Bhote Koshi Flood Path": "Bhote Koshi: Flutpfad", + "Bhote Koshi Corridor Overview": "Bhote Koshi: Korridor im Überblick", + "Bhote Koshi Upper Valley": "Bhote Koshi: oberes Tal", + "Upper Valley Collapse": "Abbruch im oberen Tal", + "Debris-Dammed Lake": "Durch Geröll aufgestauter See", + "Nepal-China Border Gate": "Grenzübergang Nepal–China", + "Timure Evidence Cluster": "Beweiscluster Timure", + "Syabru Besi Passage": "Durchgang Syabru Besi", + "Bidur / Trishuli Consequence": "Folgen in Bidur / Trishuli", + "Final view": "Schlussansicht", + "Scene {n}": "Szene {n}", + "the title of scene {scene} is empty or longer than {max} characters": "Der Titel von Szene {scene} ist leer oder länger als {max} Zeichen", + "the title of shot {shot} in scene {scene} is empty or longer than {max} characters": "Der Titel von Aufnahme {shot} in Szene {scene} ist leer oder länger als {max} Zeichen", + "the project is larger than 5 MiB": "Das Projekt ist größer als 5 MiB", + "the project has too many shots": "Das Projekt hat zu viele Aufnahmen", + "the scene data failed validation": "Die Szenendaten haben die Validierung nicht bestanden", + "Could not complete this action. Check the file, references and selected assets.": "Diese Aktion konnte nicht abgeschlossen werden. Datei, Verweise und ausgewählte Assets prüfen.", + "{count} scenes": { + "one": "{count} Szene", + "other": "{count} Szenen" + }, + "{count} shots": { + "one": "{count} Aufnahme", + "other": "{count} Aufnahmen" + }, + "{count} data packs": { + "one": "{count} Datenpaket", + "other": "{count} Datenpakete" + }, + "{scene} / {pack}: {status}. File: {path}. {attribution} · {license}": "{scene} / {pack}: {status}. Datei: {path}. {attribution} · {license}", + "Unavailable layers: {layers}": "Nicht verfügbare Ebenen: {layers}", + "Uses registered content or linked media. Those external files are not included in a scene bundle. Their original notices still apply.": "Verwendet registrierte Inhalte oder verknüpfte Medien. Diese externen Dateien sind nicht im Szenen-Bundle enthalten. Ihre ursprünglichen Hinweise gelten weiterhin.", + "{bytes} bundled bytes verified. Files stay in memory for this session. Reimport the bundle after reloading the app.": "{bytes} gebündelte Bytes verifiziert. Die Dateien bleiben für diese Sitzung im Speicher. Nach dem Neuladen der App das Bundle erneut importieren.", + "Review scene import": "Szenenimport prüfen", + "Nothing is loaded or changed until you apply this file.": "Nichts wird geladen oder geändert, bis diese Datei angewendet wird.", + "Ready to import": "Bereit zum Import", + "Apply replaces the current project. Export your current project first if you want to keep both.": "Anwenden ersetzt das aktuelle Projekt. Zuerst das aktuelle Projekt exportieren, um beide zu behalten.", + "Apply import": "Import anwenden", + "Import was not applied. The current project may have changed.": "Der Import wurde nicht angewendet. Das aktuelle Projekt hat sich möglicherweise geändert.", + "Select a scene and shot first": "Zuerst eine Szene und eine Aufnahme wählen", + "Edit scene details": "Szenendetails bearbeiten", + "Camera positions use degrees and meters above the ellipsoid. Drafts are validated before they replace your saved scene.": "Kamerapositionen verwenden Grad und Meter über dem Ellipsoid. Entwürfe werden geprüft, bevor sie die gespeicherte Szene ersetzen.", + "Anchors and data packs": "Anker und Datenpakete", + "Shot camera, timing, packs and actions": "Aufnahmekamera, Timing, Pakete und Aktionen", + "New anchor ID": "Neue Anker-ID", + "Capture camera as anchor": "Kamera als Anker erfassen", + "Anchor added to draft": "Anker zum Entwurf hinzugefügt", + "Set move start to current camera": "Startpunkt des Flugs auf aktuelle Kamera setzen", + "Move added to draft; destination remains the shot camera": "Flug zum Entwurf hinzugefügt; das Ziel bleibt die Aufnahmekamera", + "Use ordinary flight": "Normalen Flug verwenden", + "Invalid shot JSON": "Ungültiges Aufnahme-JSON", + "Apply details": "Details anwenden", + "Select a scene first": "Zuerst eine Szene wählen", + "Share selected scene": "Gewählte Szene teilen", + "Scene JSON preserves authored settings and attribution. It does not include asset files. Bundles include only pack files you choose here or previously imported bundle files.": "Szenen-JSON bewahrt die gestalteten Einstellungen und Quellenangaben. Asset-Dateien sind nicht enthalten. Bundles enthalten nur die hier gewählten Paketdateien oder zuvor importierte Bundle-Dateien.", + "Download scene JSON": "Szenen-JSON herunterladen", + "Choose data-pack files": "Datenpaket-Dateien wählen", + "Or choose a data-pack folder": "Oder einen Datenpaket-Ordner wählen", + "Download asset bundle": "Asset-Bundle herunterladen", + "Asset bundle downloaded": "Asset-Bundle heruntergeladen", + "No RTL-SDR device selected": "Kein RTL-SDR-Gerät ausgewählt", + "WebUSB requires desktop Chrome or Edge on localhost/HTTPS": "WebUSB braucht Chrome oder Edge auf dem Desktop über localhost/HTTPS", + "RTL-SDR access failed; close other SDR apps and check USB permissions": "RTL-SDR-Zugriff fehlgeschlagen; andere SDR-Apps schließen und USB-Berechtigungen prüfen", + "RTL-SDR connection failed": "RTL-SDR-Verbindung fehlgeschlagen", + "Receiving 1090 MHz ADS-B": "Empfang von ADS-B auf 1090 MHz", + "Receiving broadcast FM": "Empfang von UKW-Rundfunk", + "Connect an RTL-SDR to begin.": "Ein RTL-SDR anschließen, um zu beginnen.", + "WebUSB is unavailable in this browser": "WebUSB ist in diesem Browser nicht verfügbar", + "USB work abandoned after a stalled transfer": "USB-Vorgang nach einer hängenden Übertragung abgebrochen", + "SDR decoder worker failed": "SDR-Decoder-Worker fehlgeschlagen", + "SDR decoder did not start; receiver stopped": "SDR-Decoder ist nicht gestartet; Empfänger gestoppt", + "SDR decoder stopped responding; receiver stopped": "SDR-Decoder reagiert nicht mehr; Empfänger gestoppt", + "SDR decoder fell behind; receiver stopped": "SDR-Decoder kommt nicht hinterher; Empfänger gestoppt", + "WebUSB requires desktop Chrome or Edge": "WebUSB braucht Chrome oder Edge auf dem Desktop", + "Waiting for an RTL-SDR device…": "Warte auf ein RTL-SDR-Gerät…", + "Browser audio is suspended; press Connect again to resume it": "Browser-Audio ist angehalten; erneut auf Verbinden drücken, um es fortzusetzen", + "RTL-SDR sample stream stopped": "RTL-SDR-Sample-Stream gestoppt", + "Switching to {mode}…": "Wechsel zu {mode}…", + "Browser audio is suspended; select FM again to resume it": "Browser-Audio ist angehalten; erneut UKW wählen, um es fortzusetzen", + "RTL-SDR gain change failed": "Verstärkung des RTL-SDR konnte nicht geändert werden", + "Tuned to {mhz} MHz FM": "Abgestimmt auf {mhz} MHz UKW", + "Seeking up…": "Suchlauf aufwärts…", + "Seeking down…": "Suchlauf abwärts…", + "Seek stopped": "Suchlauf gestoppt", + "Scanning {mhz} MHz…": "{mhz} MHz wird gescannt…", + "Found {mhz} MHz · {snr} dB": "{mhz} MHz gefunden · {snr} dB", + "FM signal found at {mhz} MHz": "UKW-Signal auf {mhz} MHz gefunden", + "No FM signal found": "Kein UKW-Signal gefunden", + "Browser location is unavailable": "Browser-Standort ist nicht verfügbar", + "Receiver location was not granted": "Standort des Empfängers wurde nicht freigegeben", + "RTL-SDR disconnected": "RTL-SDR getrennt", + "Upstream response too large": "Upstream-Antwort zu groß", + "Vector tile request timed out": "Zeitüberschreitung bei der Vektorkachel-Anfrage", + "Vector tiles unavailable": "Vektorkacheln nicht verfügbar", + "Vector tile metadata unavailable": "Metadaten der Vektorkacheln nicht verfügbar", + "Zoom in for vector tile coverage": "Hineinzoomen für die Abdeckung mit Vektorkacheln", + "Saturation": "Sättigung", + "Edge Thickness": "Kantenstärke", + "Contrast": "Kontrast", + "Grain": "Körnung", + "Vignette": "Vignette", + "Pixelation": "Verpixelung", + "Distortion": "Verzerrung", + "Instability": "Instabilität", + "Gain": "Verstärkung", + "Scanlines": "Scanlines", + "Sensitivity": "Empfindlichkeit", + "WHOT/BHOT": "WHOT/BHOT", + "Ironbow": "Ironbow", + "unsaved CCTV calibration": "ungespeicherte CCTV-Kalibrierung", + "the open cockpit": "das geöffnete Cockpit", + "Switching language reloads the page. This will be lost: {items}. Switch anyway?": "Ein Sprachwechsel lädt die Seite neu. Dabei geht verloren: {items}. Trotzdem wechseln?", + "Link shared": "Link geteilt", + "Return map to straight-down view": "Karte wieder senkrecht von oben zeigen", + "Tilt map to oblique view": "Karte in Schrägansicht kippen", + "Reset map to north up. Current heading {heading} degrees": "Karte nach Norden ausrichten. Aktueller Kurs {heading} Grad", + "Tilted view": "Schrägansicht", + "Straight-down view": "Senkrechte Ansicht", + "North up": "Norden oben", + "HDG": "HDG", + "PITCH": "NEIGUNG", + "FOV": "FOV", + "RANGE": "REICHW.", + "HGT": "HÖHE", + "ΔN": "ΔN", + "ΔE": "ΔO", + "{value}m": "{value} m", + "SNAPSHOT": "SNAPSHOT", + "LIVE": "LIVE", + "UPSTREAM": "UPSTREAM", + "SYNTHETIC": "SYNTHETISCH", + "CONFIGURED": "KONFIGURIERT", + "SEED": "KATALOG", + "OK": "OK", + "Live HLS connected": "Live-HLS verbunden", + "Live HLS unavailable": "Live-HLS nicht verfügbar", + "No stream URL configured": "Keine Stream-URL konfiguriert", + "Live stream connected": "Live-Stream verbunden", + "Snapshot feed connected": "Snapshot-Feed verbunden", + "Media fetch failed": "Medienabruf fehlgeschlagen", + "Upstream snapshot active": "Upstream-Snapshot aktiv", + "Fallback Street View frame": "Fallback-Bild aus Street View", + "Upstream unavailable": "Upstream nicht verfügbar", + "No source configured": "Keine Quelle konfiguriert", + "Configured source": "Konfigurierte Quelle", + "Configured Source": "Konfigurierte Quelle", + "Synthetic fallback": "Synthetischer Fallback", + "Upstream HTTP {status}": "Upstream HTTP {status}", + "Unexpected media type {type}": "Unerwarteter Medientyp {type}", + "{value} KM/H": "{value} KM/H", + "{label} · {radius} AIR/SEA WINDOW": "{label} · {radius} LUFT-/SEEFENSTER", + "{scope} · INSTALLATIONS {coverage}": "{scope} · ANLAGEN {coverage}", + "SQUAWK {code} · {status}": "SQUAWK {code} · {status}", + "ADS-B PRIORITY · {status}": "ADS-B-PRIORITÄT · {status}", + "ADS-B EMERGENCY · {status}": "ADS-B-NOTFALL · {status}", + "{aircraftClass} · {emergency} · {feedState}": "{aircraftClass} · {emergency} · {feedState}", + "{source} · LOCATION QUERY · RECENT": "{source} · ORTSABFRAGE · AKTUELL", + "Rendered globe frames per second · toggle with `": "Gerenderte Globus-Frames pro Sekunde · umschalten mit `", + "imported map files": "importierte Kartendateien", + "Ground heights could not be refreshed. Try the file again when the map has loaded.": "Geländehöhen konnten nicht aktualisiert werden. Die Datei erneut versuchen, wenn die Karte geladen ist.", + "{count} map objects": { + "one": "{count} Kartenobjekt", + "other": "{count} Kartenobjekte" + }, + ", drawn with its own styles": ", mit eigenen Stilen gezeichnet", + "Hide {name}": "{name} ausblenden", + "Show {name}": "{name} einblenden", + "Fly to {name}": "Zu {name} fliegen", + "Remove {name}": "{name} entfernen", + "At most {count} files at once — remove one first.": "Höchstens {count} Dateien gleichzeitig – zuerst eine entfernen.", + "Reading {name}…": "{name} wird gelesen…", + "That file could not be read.": "Diese Datei konnte nicht gelesen werden.", + "Added {count} files.": { + "one": "{count} Datei hinzugefügt.", + "other": "{count} Dateien hinzugefügt." + }, + "{count} files could not be added ({name}: {error})": { + "one": "{count} Datei konnte nicht hinzugefügt werden ({name}: {error})", + "other": "{count} Dateien konnten nicht hinzugefügt werden ({name}: {error})" + }, + "Some KML content was left out.": "Einige KML-Inhalte wurden ausgelassen.", + "Press on the ground, not the sky": "Auf den Boden drücken, nicht auf den Himmel", + "Drag to size the box": "Ziehen, um die Größe des Bereichs festzulegen", + "light {source} to use your {name} key": "{source} einschalten, um den eigenen {name}-Schlüssel zu nutzen", + "light {source}": "{source} einschalten", + ", or ": " oder ", + "{requirement}, or {offer}": "{requirement} oder {offer}", + "Local ADS-B": "Lokales ADS-B", + "Transit": "ÖPNV", + "Recent Imagery": "Aktuelle Bilddaten", + "Fire Perimeters": "Brandgrenzen", + "GNSS Integrity": "GNSS-Integrität", + "S2 GhostMaps": "S2 GhostMaps", + "Rain radar": "Regenradar", + "Lightning density": "Blitzdichte", + "Cyclone advisories": "Wirbelsturmwarnungen", + "ALPR Cameras": "ALPR-Kameras", + "Live Vessels": "Live-Schiffe", + "Bike Share": "Bikesharing", + "Cameras": "Kameras", + "Street Level": "Straßenebene", + "Mapped ALPR Cameras": "Kartierte ALPR-Kameras", + "Data Centers": "Rechenzentren", + "Active Fires": "Aktive Brände", + "Military aircraft": "Militärflugzeuge", + "Vessels": "Schiffe", + "CCTV + Street View fallback": "CCTV + Street-View-Fallback", + "OpenStreetMap + optional Google Maps Places": "OpenStreetMap + optional Google Maps Places", + "GFS / ECMWF IFS · FORECAST": "GFS / ECMWF IFS · VORHERSAGE", + "NOAA nowCOAST · OBSERVED": "NOAA nowCOAST · BEOBACHTET", + "NASA FIRMS · LIVE": "NASA FIRMS · LIVE", + "OSM routing": "OSM-Routing", + "data source|Local": "Lokal", + "Movement": "Bewegung", + "Infrastructure": "Infrastruktur", + "Events": "Ereignisse", + "Weather": "Wetter", + "Utilities": "Werkzeuge", + "Other layers": "Weitere Ebenen", + "status chip|UNAVAILABLE": "NICHT VERFÜGBAR", + "Data source unavailable": "Datenquelle nicht verfügbar", + "Local FM stopped: internet radio started": "Lokales UKW gestoppt: Internetradio gestartet", + "IDLE": "BEREIT", + "TUNING": "ABSTIMMUNG", + "STREAMING": "STREAMT", + "UNSUPPORTED": "NICHT UNTERSTÜTZT", + "idle": "inaktiv", + "running": "läuft", + "suspended": "angehalten", + "closed": "geschlossen", + "feed status|live": "live", + "feed status|stale": "veraltet", + "feed status|unreachable": "nicht erreichbar", + "feed status|invalid": "ungültig", + "waiting for IQ": "warte auf IQ", + "{count} messages": { + "one": "{count} Nachricht", + "other": "{count} Nachrichten" + }, + "DSP {count} blocks": { + "one": "DSP {count} Block", + "other": "DSP {count} Blöcke" + }, + "DSP waiting": "DSP wartet", + "{level} dBFS audio": "Audio {level} dBFS", + "audio signal --": "Audiosignal --", + "audio {state}": "Audio {state}", + "{count} HEARD": { + "one": "{count} EMPFANGEN", + "other": "{count} EMPFANGEN" + }, + "DISCONNECT": "TRENNEN", + "CONNECT": "VERBINDEN", + "LOCATING…": "ORTUNG…", + "LOCATED": "GEORTET", + "LOCATE": "ORTEN", + " · read while Local ADS-B is on": " · gelesen, solange Lokales ADS-B an ist", + "Decoder feeds: {feeds}": "Decoder-Feeds: {feeds}", + "Language: {language}": "Sprache: {language}", + "Change the interface language": "Sprache der Oberfläche ändern", + "Interface language": "Sprache der Oberfläche", + "Search languages": "Sprachen durchsuchen", + "No matching languages": "Keine passenden Sprachen", + "Check the spelling and press Enter to search again.": "Schreibweise prüfen und Enter drücken, um erneut zu suchen.", + "Press Enter to try again.": "Enter drücken, um es erneut zu versuchen.", + "Detailed outline unavailable": "Detaillierter Umriss nicht verfügbar", + "Layers": "Ebenen", + "Search": "Suche", + "More": "Mehr", + "Panels": "Bereiche", + "Austin": "Austin", + "San Francisco": "San Francisco", + "New York": "New York", + "Tokyo": "Tokio", + "London": "London", + "Paris": "Paris", + "Dubai": "Dubai", + "Washington DC": "Washington DC", + "Tallinn": "Tallinn", + "Los Angeles": "Los Angeles", + "CH {index} / {total}": "KAN {index} / {total}", + "Station unavailable after directory refresh": "Sender nach Verzeichnisaktualisierung nicht verfügbar", + "Go to expanded Radio section": "Zum erweiterten Radiobereich", + "Expand Radio section in Context": "Radiobereich im Kontext erweitern", + "{category} ({count})": "{category} ({count})", + "PAUSE": "PAUSE", + "RESUME": "WEITER", + "Clear reading": "Messwert löschen", + "Earlier observation": "Frühere Beobachtung", + "Observed history": "Beobachteter Verlauf", + "Later observation": "Spätere Beobachtung", + "Latest": "Neueste", + "Newest frame per product": "Neuester Frame je Produkt", + "Replay observed history": "Beobachteten Verlauf abspielen", + "Imagery on Esri · Google 3D returns when cleared": "Bilder auf Esri · Google 3D kehrt nach dem Löschen zurück", + "Point the camera at the ground to use the view": "Kamera auf den Boden richten, um die Ansicht zu verwenden", + "That point cannot anchor a box": "Dieser Punkt kann keinen Bereich verankern", + "Imagery stops at ±{limit}° latitude": "Bilder enden bei ±{limit}° Breite", + "{owner} is using the pointer — close it first": "{owner} verwendet gerade den Zeiger – zuerst schließen", + "Box is {size} wide · limit {limit}": "Bereich ist {size} breit · Limit {limit}", + "View is {size} wide · limit {limit}": "Ansicht ist {size} breit · Limit {limit}", + "VS BASEMAP": "MIT BASISKARTE", + "A / B": "A / B", + "Newest low-cloud day for this box · scene cloud, not box cloud": "Neuester Tag mit wenig Wolken für diesen Bereich · Bewölkung der Szene, nicht des Bereichs", + "Newest day covering this box · cloudier than 20%": "Neuester Tag mit Abdeckung dieses Bereichs · über 20 % Bewölkung", + "Newest day with imagery for this box · partial coverage": "Neuester Tag mit Bildern für diesen Bereich · teilweise Abdeckung", + "Newest daily overview for this box": "Neueste tägliche Übersicht für diesen Bereich", + "newest clear day": "neuester klarer Tag", + "newest day (cloudy)": "neuester Tag (bewölkt)", + "newest day (partial coverage)": "neuester Tag (teilweise Abdeckung)", + "newest overview": "neueste Übersicht", + "No imagery": "Keine Bilder", + "Loading": "Lädt", + "coverage|full": "vollständig", + "coverage|partial": "teilweise", + "unknown": "unbekannt", + "no imagery": "keine Bilder", + "{percent}% cloud": "{percent} % Bewölkung", + "{min}–{max}% cloud": "{min}–{max} % Bewölkung", + "NO BOX": "KEIN BEREICH", + "SEARCHING": "SUCHE LÄUFT", + "{count} DAYS": { + "one": "{count} TAG", + "other": "{count} TAGE" + }, + "Zoom in or draw a smaller box": "Hineinzoomen oder einen kleineren Bereich zeichnen", + "Select a box or use the view": "Bereich wählen oder die Ansicht verwenden", + "Searching the last 30 days": "Die letzten 30 Tage werden durchsucht", + "No days to show for this box": "Keine Tage für diesen Bereich", + "Drag the divider · SWAP trades sides": "Trennlinie ziehen · TAUSCHEN wechselt die Seiten", + "← → preview · A or B pins the focused day": "← → Vorschau · A oder B fixiert den gewählten Tag", + "← → preview the other side · A or B pins it": "← → Vorschau der anderen Seite · A oder B fixiert sie", + "S on another day replaces it · × unpins": "S auf einem anderen Tag ersetzt ihn · × löst die Fixierung", + "← → preview · S shows the focused day": "← → Vorschau · S zeigt den gewählten Tag", + "ZOOM IN": "HINEINZOOMEN", + "Fly in until the view fits the 1,000 km limit": "Hineinfliegen, bis die Ansicht das Limit von 1.000 km einhält", + "Imagery days, newest first · arrows move, S or A and B pin": "Bildtage, neueste zuerst · Pfeile bewegen, S oder A und B fixieren", + "On the map": "Auf der Karte", + "Mode": "Modus", + "Imagery opacity": "Bilddeckkraft", + "SWAP": "TAUSCHEN", + "Trade the two sides of the divider": "Die beiden Seiten der Trennlinie tauschen", + "SELECT BOX": "BEREICH WÄHLEN", + "Drag a box on the map (Esc cancels)": "Einen Bereich auf die Karte ziehen (Esc bricht ab)", + "USE VIEW": "ANSICHT NUTZEN", + "Use the current view as the box": "Die aktuelle Ansicht als Bereich verwenden", + "Forget the box and its images": "Bereich und Bilder verwerfen", + "START HERE": "HIER STARTEN", + "Checking": "Wird geprüft", + "PREVIEW": "VORSCHAU", + "Newest day with imagery for this box": "Neuester Tag mit Bildern für diesen Bereich", + "SHOW": "ZEIGEN", + "Pin {day} as {slot}": "{day} als {slot} fixieren", + "Show {day}": "{day} zeigen", + "pinned {slot}": "fixiert {slot}", + "shown": "gezeigt", + "preview": "Vorschau", + "start here": "hier starten", + "No box": "Kein Bereich", + "Searching": "Suche läuft", + "Every day is empty here": "Hier ist jeder Tag leer", + "Sources off": "Quellen aus", + "VS": "VGL.", + "Not set": "Nicht gesetzt", + "Basemap": "Basiskarte", + "Source off": "Quelle aus", + "Unpin {slot}": "{slot} lösen", + "Unpin the image": "Bild lösen", + "EXPORT {slot}": "{slot} EXPORTIEREN", + "EXPORT": "EXPORTIEREN", + "Download {slot} as a PNG": "{slot} als PNG herunterladen", + "Download the image as a PNG": "Bild als PNG herunterladen", + "Box {width} × {height} km": "Bereich {width} × {height} km", + "Acquired {time}": "Aufgenommen {time}", + "Coverage {coverage}": "Abdeckung {coverage}", + "START HERE · {reason}": "HIER STARTEN · {reason}", + "Daily overview shows little detail in a box this small": "Die tägliche Übersicht zeigt in einem so kleinen Bereich kaum Details", + "Imagery: NASA GIBS and Worldview · HLS (Sentinel-2, Landsat 8/9) and VIIRS": "Bilder: NASA GIBS und Worldview · HLS (Sentinel-2, Landsat 8/9) und VIIRS", + "Details": "Details", + "Times, coverage, sources": "Zeiten, Abdeckung, Quellen", + "HIDE EMPTY DAYS": "LEERE TAGE AUSBLENDEN", + "SHOW EMPTY DAYS · {count}": "LEERE TAGE ZEIGEN · {count}", + "Days the probe found empty in this box": "Tage, die die Abfrage in diesem Bereich leer fand", + "image": "Bild", + "BASEMAP": "BASISKARTE", + "The basemap": "Die Basiskarte", + "basemap": "Basiskarte", + "Recent imagery against the basemap divider": "Trennlinie: aktuelle Bilddaten gegen Basiskarte", + "Recent imagery A and B divider": "Trennlinie: aktuelle Bilddaten A und B", + "{before} {left} percent, {after} {right} percent": "{before} {left} Prozent, {after} {right} Prozent", + "Export failed · {error}": "Export fehlgeschlagen · {error}", + "New scene name": "Name der neuen Szene", + "Delete scene \"{scene}\" and all shots?": "Szene „{scene}“ und alle Aufnahmen löschen?", + "Stopped (Esc)": "Gestoppt (Esc)", + "No shots yet. Use CAPTURE SHOT to save current look.": "Noch keine Aufnahmen. Mit AUFNAHME SPEICHERN die aktuelle Ansicht sichern.", + "Double-click to rename": "Doppelklick zum Umbenennen", + "Shot name": "Name der Aufnahme", + "LOAD": "LADEN", + "{duration}s + {hold}s": "{duration} s + {hold} s", + "Choose files": "Dateien wählen", + "{count} files selected": { + "one": "{count} Datei ausgewählt", + "other": "{count} Dateien ausgewählt" + }, + "No file chosen": "Keine Datei gewählt", + "Cancel": "Abbrechen", + "EDIT DETAILS": "DETAILS BEARBEITEN", + "SHARE SCENE": "SZENE TEILEN", + "Shared flight follow expired": "Verfolgung des geteilten Flugs abgelaufen", + "Shared military flight follow expired": "Verfolgung des geteilten Militärflugs abgelaufen", + "Shared satellite follow expired": "Verfolgung des geteilten Satelliten abgelaufen", + "Shared flight could not be restored — feed unavailable": "Geteilter Flug konnte nicht wiederhergestellt werden – Feed nicht verfügbar", + "Shared military flight could not be restored — feed unavailable": "Geteilter Militärflug konnte nicht wiederhergestellt werden – Feed nicht verfügbar", + "Shared satellite could not be restored — feed unavailable": "Geteilter Satellit konnte nicht wiederhergestellt werden – Feed nicht verfügbar", + "Shared flight is unavailable": "Geteilter Flug ist nicht verfügbar", + "Shared military flight is unavailable": "Geteilter Militärflug ist nicht verfügbar", + "Shared satellite is unavailable": "Geteilter Satellit ist nicht verfügbar", + "{id} isn't reporting now — showing where it was last seen": "{id} sendet gerade nicht – letzte bekannte Position wird gezeigt", + "{id} isn't reporting now — showing where it was at {time}": "{id} sendet gerade nicht – Position um {time} wird gezeigt", + "This share link can't be opened": "Dieser Link zum Teilen kann nicht geöffnet werden", + "Shared vessel is unavailable": "Geteiltes Schiff ist nicht verfügbar", + "subject": "Objekt", + "RETRYING ALPR CAMERAS": "ALPR-KAMERAS: NEUER VERSUCH", + "FETCHING ALPR CAMERAS": "ALPR-KAMERAS WERDEN ABGERUFEN", + "OVERPASS TEMPORARILY UNAVAILABLE": "OVERPASS VORÜBERGEHEND NICHT VERFÜGBAR", + "OVERPASS RATE-LIMITED": "OVERPASS-RATENLIMIT ERREICHT", + "OVERPASS TIMED OUT": "ZEITÜBERSCHREITUNG BEI OVERPASS", + "OVERPASS COULD NOT COMPLETE THE QUERY": "OVERPASS KONNTE DIE ABFRAGE NICHT ABSCHLIESSEN", + "MAP TILES TEMPORARILY UNAVAILABLE": "KARTENKACHELN VORÜBERGEHEND NICHT VERFÜGBAR", + "MAPPED NAMES TEMPORARILY UNAVAILABLE": "KARTIERTE NAMEN VORÜBERGEHEND NICHT VERFÜGBAR", + "ALPR cameras": "ALPR-Kameras", + "OpenSky OAuth client missing/invalid": "OpenSky-OAuth-Client fehlt oder ist ungültig", + "OpenSky OAuth rejected credentials": "OpenSky-OAuth hat die Zugangsdaten abgelehnt", + "OpenSky username/password rejected": "OpenSky hat Benutzername/Passwort abgelehnt", + "OpenSky auth missing": "OpenSky-Authentifizierung fehlt", + "OpenSky auth required": "OpenSky-Authentifizierung erforderlich", + "OpenSky auth invalid": "OpenSky-Authentifizierung ungültig", + "OpenSky auth failed": "OpenSky-Authentifizierung fehlgeschlagen", + "KartaView answered HTTP {status}": "KartaView hat mit HTTP {status} geantwortet", + "Panoramax answered HTTP {status}": "Panoramax hat mit HTTP {status} geantwortet", + "KartaView refused the request (code {code})": "KartaView hat die Anfrage abgelehnt (Code {code})", + "Vector tiles unavailable (HTTP {status})": "Vektorkacheln nicht verfügbar (HTTP {status})", + "GNSS feed unavailable (HTTP {status})": "GNSS-Feed nicht verfügbar (HTTP {status})", + "{count} CelesTrak groups unavailable": { + "one": "{count} CelesTrak-Gruppe nicht verfügbar", + "other": "{count} CelesTrak-Gruppen nicht verfügbar" + }, + "{feed} feed unavailable": "Feed {feed} nicht verfügbar", + "Source snapshot {minutes} min old": "Quell-Snapshot ist {minutes} min alt", + "{source} rate limited (anonymous)": "{source}: Anfragelimit erreicht (anonym)", + "{source} rate limited": "{source}: Anfragelimit erreicht", + "{source} network error": "{source}: Netzwerkfehler", + "Malformed {source} aircraft rows": "Fehlerhafte Flugzeugzeilen von {source}", + "Malformed {source} response": "Fehlerhafte Antwort von {source}", + "entry {n}": "Eintrag {n}", + "feeds {names} stale": { + "one": "Feed {names} veraltet", + "other": "Feeds {names} veraltet" + }, + "feeds {names} unreachable": { + "one": "Feed {names} nicht erreichbar", + "other": "Feeds {names} nicht erreichbar" + }, + "feeds {names} invalid": { + "one": "Feed {names} ungültig", + "other": "Feeds {names} ungültig" + }, + "Loading {feeds}": "{feeds} wird geladen", + "{count} heard": { + "one": "{count} empfangen", + "other": "{count} empfangen" + }, + "USB {rate} msg/s": "USB {rate} Nachr./s", + "{rate} msg/s": "{rate} Nachr./s", + "{count} feeds live": { + "one": "{count} Feed live", + "other": "{count} Feeds live" + }, + "{feed} {count} ({seconds}s old)": "{feed} {count} (vor {seconds} s)", + "Street Level toggle failed": "Umschalten der Straßenebene fehlgeschlagen", + "Street Level could not start": "Straßenebene konnte nicht gestartet werden", + "SHRINK": "VERKLEINERN", + "EXPAND": "VERGRÖSSERN", + "Shrink": "Verkleinern", + "Expand": "Vergrößern", + "ANY DATE": "BELIEBIGES DATUM", + "LAST 10 YEARS": "LETZTE 10 JAHRE", + "LAST 5 YEARS": "LETZTE 5 JAHRE", + "LAST 3 YEARS": "LETZTE 3 JAHRE", + "LAST 2 YEARS": "LETZTE 2 JAHRE", + "LAST YEAR": "LETZTES JAHR", + "LAST 6 MONTHS": "LETZTE 6 MONATE", + "LAST 3 MONTHS": "LETZTE 3 MONATE", + "LAST MONTH": "LETZTER MONAT", + "LAST {count} DAYS": { + "one": "LETZTER {count} TAG", + "other": "LETZTE {count} TAGE" + }, + "{window} · SINCE {date}": "{window} · SEIT {date}", + "Turn Street Level off": "Straßenebene ausschalten", + "Turn Street Level on": "Straßenebene einschalten", + "{name} imagery on": "{name}-Bilder an", + "{name} imagery off": "{name}-Bilder aus", + "Image by {creator}": "Bild von {creator}", + " or ": " oder", + "OPEN {labels}": "{labels} ÖFFNEN", + "Open {names} at the centre of the view": "{names} in der Bildmitte öffnen", + "Zoom in to a street to open {names} here": "Auf eine Straße hineinzoomen, um hier {names} zu öffnen", + "Switch Street Level on to draw its coverage.": "Straßenebene einschalten, um ihre Abdeckung zu zeichnen.", + "Every provider is switched off: light a chip to draw its coverage.": "Alle Anbieter sind ausgeschaltet: einen Chip einschalten, um seine Abdeckung zu zeichnen.", + "Loading this sequence…": "Diese Sequenz wird geladen…", + "{n} images in this sequence · Esc clears": { + "one": "{n} Bild in dieser Sequenz · Esc leert", + "other": "{n} Bilder in dieser Sequenz · Esc leert" + }, + "No sequences in view match the filter": "Keine Sequenzen im Bild passen zum Filter", + "No coverage in view": "Keine Abdeckung im Bild", + "{n} streets in view · click a line for its nearest photo": { + "one": "{n} Straße im Bild · Linie anklicken für das nächste Foto", + "other": "{n} Straßen im Bild · Linie anklicken für das nächste Foto" + }, + "{n} sequences in view · click a line for its nearest photo": { + "one": "{n} Sequenz im Bild · Linie anklicken für das nächste Foto", + "other": "{n} Sequenzen im Bild · Linie anklicken für das nächste Foto" + }, + "{n} sequences in view · click a line for its photos": { + "one": "{n} Sequenz im Bild · Linie anklicken für ihre Fotos", + "other": "{n} Sequenzen im Bild · Linie anklicken für ihre Fotos" + }, + "km/h": "km/h", + "m/s": "m/s", + "mph": "mph", + "hPa": "hPa", + "kt": "kn", + "kts": "kn", + "ft": "ft", + "km": "km", + "m": "m", + "h": "h", + "min": "min", + "s": "s", + "dB": "dB", + "{time} · {minutes} min ago": "{time} · vor {minutes} min", + "Active weather": "Aktives Wetter", + "LATEST · newest per product": "NEUESTE · je Produkt", + "Forecast · valid {valid} · issued {issued}": "Vorhersage · gültig {valid} · ausgegeben {issued}", + "{detail} · Does not follow history": "{detail} · Folgt nicht dem Verlauf", + "Forecast · valid {valid}": "Vorhersage · gültig {valid}", + "voice|OFF": "AUS", + "voice|CONNECTING": "VERBINDET", + "voice|ERROR": "FEHLER", + "Voice provider": "Sprachanbieter", + "Changing provider reconnects voice if it is on.": "Ein Anbieterwechsel verbindet die Sprachsteuerung neu, wenn sie an ist.", + "Voice Settings": "Spracheinstellungen", + "STD": "STD", + "ON/OFF": "EIN/AUS", + "VOICE": "SPRACHE", + "Preview": "Vorschau", + "Settings": "Einstellungen", + "Close voice panel": "Sprachbereich schließen", + "Voice replies appear here.": "Sprachantworten erscheinen hier.", + "Voice assistant": "Sprachassistent", + "Dismiss voice card": "Sprachkarte schließen", + "YOU": "EINGABE", + "THIS": "DIES", + "Plan": "Plan", + "Referenced items": "Erwähnte Objekte", + "NOTES & SOURCES": "NOTIZEN & QUELLEN", + "Show Voice Preview": "Sprachvorschau anzeigen", + "Voice inactivity timeout": "Zeitlimit bei Sprachinaktivität", + "Minutes": "Minuten", + "Custom": "Benutzerdefiniert", + "These preferences stay in this browser.": "Diese Einstellungen bleiben in diesem Browser.", + "Gemini returned an oversized audio chunk": "Gemini hat einen zu großen Audioblock geliefert", + "Gemini returned an unsupported audio format": "Gemini hat ein nicht unterstütztes Audioformat geliefert", + "Gemini returned an invalid audio sample rate": "Gemini hat eine ungültige Audio-Abtastrate geliefert", + "Gemini returned incomplete PCM audio": "Gemini hat unvollständiges PCM-Audio geliefert", + "This browser does not support Gemini microphone audio": "Dieser Browser unterstützt kein Mikrofon-Audio für Gemini", + "Microphone audio processing failed": "Verarbeitung des Mikrofon-Audios fehlgeschlagen", + "Gemini audio playback fell behind. Reconnect to continue.": "Die Gemini-Audiowiedergabe kommt nicht hinterher. Neu verbinden, um fortzufahren.", + "Gemini token response did not include an ephemeral credential": "Die Gemini-Token-Antwort enthielt keine temporären Zugangsdaten", + "Invalid Gemini connection endpoint": "Ungültiger Gemini-Verbindungsendpunkt", + "Gemini voice could not connect. Try again.": "Gemini-Sprachsteuerung konnte keine Verbindung herstellen. Erneut versuchen.", + "Gemini voice requires a same-origin app request": "Gemini-Sprachsteuerung erfordert eine Anfrage vom selben Origin", + "Add a Gemini API key in Provider Settings": "Einen Gemini-API-Schlüssel in den Anbieter-Einstellungen hinzufügen", + "The Gemini Live model configuration is invalid": "Die Modellkonfiguration für Gemini Live ist ungültig", + "Gemini voice is starting too often. Try again shortly.": "Gemini-Sprachsteuerung wird zu oft gestartet. Gleich erneut versuchen.", + "Gemini quota is unavailable. Try again later.": "Gemini-Kontingent ist nicht verfügbar. Später erneut versuchen.", + "Gemini access was refused. Check the API key and model access.": "Gemini hat den Zugriff verweigert. API-Schlüssel und Modellzugriff prüfen.", + "Gemini Live is unavailable for the configured model.": "Gemini Live ist für das konfigurierte Modell nicht verfügbar.", + "Token request is too large": "Token-Anfrage ist zu groß", + "Use an empty JSON token request": "Eine leere JSON-Token-Anfrage verwenden", + "Voice command context is too large": "Kontext des Sprachbefehls ist zu groß", + "Gemini reliable transport exceeded its queue limit. Start voice again.": "Der zuverlässige Gemini-Transport hat sein Warteschlangenlimit überschritten. Sprachsteuerung neu starten.", + "Gemini reliable transport did not drain. Start voice again.": "Der zuverlässige Gemini-Transport wurde nicht geleert. Sprachsteuerung neu starten.", + "Gemini token request failed (HTTP {status})": "Gemini-Token-Anfrage fehlgeschlagen (HTTP {status})", + "Gemini token response did not include a valid model": "Die Gemini-Token-Antwort enthielt kein gültiges Modell", + "Gemini token response did not include session settings": "Die Gemini-Token-Antwort enthielt keine Sitzungseinstellungen", + "Gemini session settings do not match the input mode": "Die Gemini-Sitzungseinstellungen passen nicht zum Eingabemodus", + "Gemini could not submit this input. Start voice again.": "Gemini konnte diese Eingabe nicht senden. Sprachsteuerung neu starten.", + "Connecting to Gemini": "Verbindung zu Gemini", + "Gemini returned an oversized message": "Gemini hat eine zu große Nachricht geliefert", + "Gemini Live connection failed. Check network access, then start voice again.": "Verbindung zu Gemini Live fehlgeschlagen. Netzwerkzugang prüfen, dann die Sprachsteuerung neu starten.", + "Gemini Live connection ended. Start voice again for a new conversation.": "Verbindung zu Gemini Live beendet. Für ein neues Gespräch die Sprachsteuerung neu starten.", + "Gemini Live could not start. Start voice again to request a fresh session.": "Gemini Live konnte nicht starten. Sprachsteuerung neu starten, um eine neue Sitzung anzufordern.", + "Start voice again for a fresh token and a new conversation.": "Sprachsteuerung neu starten für ein neues Token und ein neues Gespräch.", + "Start voice again to request a fresh session credential.": "Sprachsteuerung neu starten, um neue Sitzungszugangsdaten anzufordern.", + "Microphone permission was denied. Allow microphone access and try again.": "Mikrofonberechtigung wurde verweigert. Mikrofonzugriff erlauben und erneut versuchen.", + "Gemini connection timed out. Try again.": "Zeitüberschreitung bei der Gemini-Verbindung. Erneut versuchen.", + "Gemini voice could not start": "Gemini-Sprachsteuerung konnte nicht starten", + "Gemini did not finish the interrupted reply. Start voice again.": "Gemini hat die unterbrochene Antwort nicht beendet. Sprachsteuerung neu starten.", + "Gemini session expiring; finishing the current reply": "Gemini-Sitzung läuft ab; die aktuelle Antwort wird beendet", + "Gemini rejected the voice session. Start voice again to request a fresh session.": "Gemini hat die Sprachsitzung abgelehnt. Sprachsteuerung neu starten, um eine neue Sitzung anzufordern.", + "Start voice again for a fresh session credential. If it repeats, check Gemini model and API access.": "Sprachsteuerung neu starten für neue Sitzungszugangsdaten. Falls es sich wiederholt, Gemini-Modell und API-Zugriff prüfen.", + "Gemini action history is full. Start voice again for a fresh session.": "Der Gemini-Aktionsverlauf ist voll. Sprachsteuerung für eine neue Sitzung neu starten.", + "Gemini requested too many simultaneous actions": "Gemini hat zu viele gleichzeitige Aktionen angefordert", + "Voice text command is too long": "Textbefehl für die Sprachsteuerung ist zu lang", + "Gemini voice is not connected": "Gemini-Sprachsteuerung ist nicht verbunden", + "Gemini interrupted input exceeded its buffer or wait limit. Start voice again.": "Unterbrochene Gemini-Eingabe hat ihr Puffer- oder Wartelimit überschritten. Sprachsteuerung neu starten.", + "Gemini Live connection is expiring. Start voice again for a new conversation.": "Die Verbindung zu Gemini Live läuft ab. Für ein neues Gespräch die Sprachsteuerung neu starten.", + "Gemini voice sessions have a time limit. When a session expires, start voice again for a new conversation.": "Gemini-Sprachsitzungen sind zeitlich begrenzt. Wenn eine Sitzung abläuft, die Sprachsteuerung für ein neues Gespräch neu starten.", + "Stopped by voice": "Per Sprache gestoppt", + "Automatic stop is unavailable for this voice connection.": "Automatisches Beenden ist für diese Sprachverbindung nicht verfügbar.", + "Preview is off.": "Vorschau ist aus.", + "Your choice applies now, but could not be saved.": "Die Auswahl gilt jetzt, konnte aber nicht gespeichert werden.", + "MINI": "MINI", + "standard": "Standard", + "mini": "Mini", + "COST UNKNOWN": "KOSTEN UNBEKANNT", + "ChatGPT OAuth session: {responses} response(s), {input} input and {output} output tokens, {captions} caption transcription(s) reported.": "ChatGPT-OAuth-Sitzung: {responses} Antwort(en), {input} Eingabe- und {output} Ausgabe-Tokens, {captions} Untertitel-Transkription(en) gemeldet.", + "USD cost and the API spend cap are unavailable for this auth mode.": "USD-Kosten und das API-Ausgabenlimit sind in diesem Authentifizierungsmodus nicht verfügbar.", + "Usage is incomplete because a response was still in flight when the session ended.": "Die Nutzung ist unvollständig, weil beim Sitzungsende noch eine Antwort unterwegs war.", + "Estimate is incomplete — a response was still in flight when the session ended, so its usage was never reported.": "Schätzung unvollständig – beim Sitzungsende war noch eine Antwort unterwegs, ihre Nutzung wurde daher nie gemeldet.", + "STANDARD": "STANDARD", + "MIC": "MIK", + "{n} aircraft": { + "one": "{n} Luftfahrzeug", + "other": "{n} Luftfahrzeuge" + }, + "{n} military aircraft": { + "one": "{n} Militärluftfahrzeug", + "other": "{n} Militärluftfahrzeuge" + }, + "{n} ships": { + "one": "{n} Schiff", + "other": "{n} Schiffe" + }, + "{n} satellites": { + "one": "{n} Satellit", + "other": "{n} Satelliten" + }, + "{n} launches": { + "one": "{n} Start", + "other": "{n} Starts" + }, + "{n} earthquakes": { + "one": "{n} Erdbeben", + "other": "{n} Erdbeben" + }, + "{n} fires": { + "one": "{n} Brand", + "other": "{n} Brände" + }, + "{n} fire perimeters": { + "one": "{n} Brandgrenze", + "other": "{n} Brandgrenzen" + }, + "{n} cyclones": { + "one": "{n} Wirbelsturm", + "other": "{n} Wirbelstürme" + }, + "{n} buses": { + "one": "{n} Bus", + "other": "{n} Busse" + }, + "{n} bike share": { + "one": "{n} Bikesharing-Station", + "other": "{n} Bikesharing-Stationen" + }, + "{n} flock cameras": { + "one": "{n} ALPR-Kamera", + "other": "{n} ALPR-Kameras" + }, + "{n} military bases": { + "one": "{n} Militärstützpunkt", + "other": "{n} Militärstützpunkte" + }, + "{n} datacenters": { + "one": "{n} Rechenzentrum", + "other": "{n} Rechenzentren" + }, + "{n} dams": { + "one": "{n} Staudamm", + "other": "{n} Staudämme" + }, + "{n} air quality": { + "one": "{n} Luftqualitätsstation", + "other": "{n} Luftqualitätsstationen" + }, + "{n} results": { + "one": "{n} Ergebnis", + "other": "{n} Ergebnisse" + }, + "anywhere in the loaded data": "irgendwo in den geladenen Daten", + "in view": "im Bild", + "within {radius} of the view centre": "im Umkreis von {radius} um die Bildmitte", + "within {radius} of {place} (Contacts window)": "im Umkreis von {radius} um {place} (Kontaktfenster)", + "within {radius} of {place}": "im Umkreis von {radius} um {place}", + "within {radius}": "im Umkreis von {radius}", + "over {region}": "über {region}", + "At least {items}": "Mindestens {items}", + "{items} {scope}": "{items} {scope}", + "last 24 h": "letzte 24 h", + "past 30 d and upcoming": "letzte 30 Tage und anstehende", + "the flights layer loads by viewport": "die Flugebene lädt nach Bildausschnitt", + "distance is ground distance, not overhead": "Entfernung ist Bodenentfernung, nicht über Kopf", + "the count is a lower bound because at least one layer reached its retained limit.": "die Anzahl ist eine Untergrenze, weil mindestens eine Ebene ihr Speicherlimit erreicht hat.", + "{label} off": "{label} aus", + "{label} loading": "{label} lädt", + "{label} error": "{label} Fehler", + "counted the first {returned} loaded records": "die ersten {returned} geladenen Einträge gezählt", + "counted {returned} of {total} loaded records": "{returned} von {total} geladenen Einträgen gezählt", + "{layers} just turned on — still loading, counts will rise": "{layers} gerade eingeschaltet – lädt noch, die Zahlen steigen", + "Contacts panel snapshot at {time} — the same retained cohort supplies the card, speech, and follow-up memory": "Snapshot des Kontaktbereichs um {time} – dieselbe gespeicherte Auswahl liefert Karte, Sprachausgabe und Gedächtnis für Folgefragen", + "Contacts panel snapshot — the same retained cohort supplies the card, speech, and follow-up memory": "Snapshot des Kontaktbereichs – dieselbe gespeicherte Auswahl liefert Karte, Sprachausgabe und Gedächtnis für Folgefragen", + "Fly below {km} km to a covered region": "Unter {km} km zu einer abgedeckten Region fliegen", + "No feed here yet · {n} regions available": { + "one": "Hier noch kein Feed · {n} Region verfügbar", + "other": "Hier noch kein Feed · {n} Regionen verfügbar" + }, + "degraded": "eingeschränkt", + "stale": "veraltet", + "partial": "teilweise", + "fallback": "Fallback", + "unavailable": "nicht verfügbar", + "Not answered: {layers}": "Keine Antwort: {layers}", + "Toggle voice control": "Sprachsteuerung umschalten", + "Activate to toggle voice": "Aktivieren, um die Sprachsteuerung umzuschalten", + "Voice active": "Sprachsteuerung aktiv", + "Voice could not be started.": "Sprachsteuerung konnte nicht gestartet werden.", + "the active voice session": "die aktive Sprachsitzung", + "{value} feet": "{value} Fuß", + "Fire · FRP {frp} MW": "Brand · FRP {frp} MW", + "The flights layer is not enabled": "Die Ebene Flüge ist nicht aktiviert", + "The military layer is not enabled": "Die Militär-Ebene ist nicht aktiviert", + "The satellites layer is not enabled": "Die Ebene Satelliten ist nicht aktiviert", + "The ais-live-vessels layer is not enabled": "Die Ebene ais-live-vessels ist nicht aktiviert", + "Could not enable the requested layer": "Die angeforderte Ebene konnte nicht aktiviert werden", + "Could not disable the requested layer": "Die angeforderte Ebene konnte nicht deaktiviert werden", + "Radio layer unavailable": "Radio-Ebene nicht verfügbar", + "Camera navigation is unavailable in the current view": "Kameranavigation ist in der aktuellen Ansicht nicht verfügbar", + "Camera navigation policy unavailable": "Richtlinie für die Kameranavigation nicht verfügbar", + "Nearest-aircraft selection supports Flights or Military Flights only": "Die Auswahl des nächsten Luftfahrzeugs unterstützt nur Flüge oder Militärflüge", + "Nearest-aircraft selection needs a preset, place name, or latitude and longitude": "Die Auswahl des nächsten Luftfahrzeugs braucht ein Preset, einen Ortsnamen oder Breite und Länge", + "Could not arrive at the requested place": "Der angeforderte Ort konnte nicht erreicht werden", + "The nearest airborne aircraft could not be selected": "Das nächste Luftfahrzeug in der Luft konnte nicht ausgewählt werden", + "No flights within {radius} of the current view": "Keine Flüge im Umkreis von {radius} um die aktuelle Ansicht", + "No military within {radius} of the current view": "Keine Militärflüge im Umkreis von {radius} um die aktuelle Ansicht", + "No satellites within {radius} of the current view": "Keine Satelliten im Umkreis von {radius} um die aktuelle Ansicht", + "No vessels within {radius} of the current view": "Keine Schiffe im Umkreis von {radius} um die aktuelle Ansicht", + "{layer} is enabled on the {source} feed, but no airborne aircraft is loaded in the {place} view yet": "{layer} ist mit dem Feed {source} aktiviert, aber in der Ansicht {place} ist noch kein Luftfahrzeug in der Luft geladen", + "{layer} is enabled, but no airborne aircraft is loaded in the {place} view yet": "{layer} ist aktiviert, aber in der Ansicht {place} ist noch kein Luftfahrzeug in der Luft geladen", + "{layer} is enabled, but its aircraft feed is unavailable": "{layer} ist aktiviert, aber der Flugzeug-Feed ist nicht verfügbar", + "{layer} is enabled, but its destination refresh did not complete": "{layer} ist aktiviert, aber die Aktualisierung am Ziel wurde nicht abgeschlossen", + "{layer} is enabled, but {source} is unavailable": "{layer} ist aktiviert, aber {source} ist nicht verfügbar", + "Could not arrive at {place}": "{place} konnte nicht erreicht werden", + "{name} is no longer loaded": "{name} ist nicht mehr geladen", + "Unknown target layer: {target}": "Unbekannte Zielebene: {target}", + "nominal": "normal", + "{label} on": "{label} an", + "Frame aircraft": "Luftfahrzeuge ins Bild nehmen", + "Frame military aircraft": "Militärluftfahrzeuge ins Bild nehmen", + "Frame ships": "Schiffe ins Bild nehmen", + "Frame satellites": "Satelliten ins Bild nehmen", + "Frame contacts": "Kontakte ins Bild nehmen", + "{count} aircraft in frame": { + "one": "{count} Luftfahrzeug im Bild", + "other": "{count} Luftfahrzeuge im Bild" + }, + "{count} military aircraft in frame": { + "one": "{count} Militärluftfahrzeug im Bild", + "other": "{count} Militärluftfahrzeuge im Bild" + }, + "{count} ships in frame": { + "one": "{count} Schiff im Bild", + "other": "{count} Schiffe im Bild" + }, + "{count} satellites in frame": { + "one": "{count} Satellit im Bild", + "other": "{count} Satelliten im Bild" + }, + "{count} contacts in frame": { + "one": "{count} Kontakt im Bild", + "other": "{count} Kontakte im Bild" + }, + "Nearest military aircraft": "Nächste Militärluftfahrzeuge", + "Nearest ships": "Nächste Schiffe", + "Nearest satellites": "Nächste Satelliten", + "Nearest aircraft": "Nächste Luftfahrzeuge", + "{first} and {second}": "{first} und {second}", + "Layer": "Ebene", + "there": "dort", + "Camera range {range}": "Kameraentfernung {range}", + "Within {radius} of the view": "Im Umkreis von {radius} um die Ansicht", + "Labels on": "Beschriftungen an", + "Framing uses the nearest 80 loaded contacts": "Die Bildauswahl nutzt die 80 nächsten geladenen Kontakte", + "{distance} from {location}": "{distance} von {location}", + "Altitude {altitude}": "Höhe {altitude}", + "{origin} to {destination}": "{origin} nach {destination}", + "from {origin}": "von {origin}", + "to {destination}": "nach {destination}", + "Registration {registration}": "Kennzeichen {registration}", + "View state": "Ansichtsstatus", + "Marked {count} places": { + "one": "{count} Ort markiert", + "other": "{count} Orte markiert" + }, + "Nothing marked": "Nichts markiert", + "Not found: {places}": "Nicht gefunden: {places}", + "Tracing outlines": "Umrisse werden nachgezeichnet", + "Frame flights": "Flüge ins Bild nehmen", + "Frame military": "Militär ins Bild nehmen", + "Frame vessels": "Schiffe ins Bild nehmen", + "Frame {target}": "{target} ins Bild nehmen", + "Zoom out to globe": "Auf den Globus herauszoomen", + "Open data layers": "Datenebenen öffnen", + "Open or close a panel": "Bereich öffnen oder schließen", + "Change context mode": "Kontextmodus ändern", + "Control cockpit": "Cockpit steuern", + "Change visual style": "Visuellen Stil ändern", + "Adjust HUD": "HUD anpassen", + "Adjust cyber sonar": "Cyber-Sonar anpassen", + "Adjust detection overlay": "Erkennungs-Overlay anpassen", + "Change map stack": "Kartenstapel ändern", + "Adjust post-processing": "Nachbearbeitung anpassen", + "Control scene": "Szene steuern", + "Control CCTV": "CCTV steuern", + "Control radio": "Radio steuern", + "Track contact": "Kontakt verfolgen", + "Stop tracking": "Verfolgung beenden", + "Clear marks": "Markierungen löschen", + "Move camera": "Kamera bewegen", + "Fly route": "Route abfliegen", + "Analyst query": "Analyseabfrage", + "Next ISS pass": "Nächster ISS-Überflug", + "Next satellite pass": "Nächster Satellitenüberflug", + "Mark the map": "Karte markieren", + "Mark {targets} +{more}": "{targets} +{more} markieren", + "Mark {targets}": "{targets} markieren", + "Fly to {place}": "Zu {place} fliegen", + "Fly to Location": "Zu einem Ort fliegen", + "Nearest aircraft to {place}": "Nächstes Luftfahrzeug bei {place}", + "Nearest aircraft to Here": "Nächstes Luftfahrzeug hier", + "Layer on": "Ebene an", + "Layer off": "Ebene aus", + "Zoom out": "Herauszoomen", + "Zoom in": "Hineinzoomen", + "Read the view": "Ansicht auslesen", + "Check view state": "Ansichtsstatus prüfen", + "Action": "Aktion", + "Finding places": "Orte werden gesucht", + "Tracing outline": "Umriss wird nachgezeichnet", + "Looking up place": "Ort wird nachgeschlagen", + "Flying": "Im Flug", + "Turning on layer": "Ebene wird eingeschaltet", + "Loading aircraft": "Luftfahrzeuge werden geladen", + "Picking nearest": "Nächstes wird ausgewählt", + "Working": "In Arbeit", + "in progress": "läuft", + "done": "erledigt", + "failed": "fehlgeschlagen", + "cancelled": "abgebrochen", + "Outline traced": "Umriss nachgezeichnet", + "Outline unavailable": "Umriss nicht verfügbar", + "Source: {label}": "Quelle: {label}", + "WORKING": "IN ARBEIT", + "DONE": "ERLEDIGT", + "Recent speech": "Zuletzt gesagt", + "HERE": "HIER", + "KTS": "KN", + "FT": "FT", + "FLT": "FLÜGE", + "MIL": "MIL", + "SITE": "ORTE", + "WX": "WETTER", + "MM": "MM", + "Weather data by Open-Meteo.com": "Wetterdaten von Open-Meteo.com", + "Cockpit briefing pages": "Briefing-Seiten im Cockpit", + "SIG": "SIG", + "LOCAL": "LOKAL", + "ESC EXIT": "ESC BEENDEN", + "C TOGGLE": "C UMSCHALTEN", + "Active weather products": "Aktive Wetterprodukte", + "RECENT IMAGERY": "AKTUELLE BILDDATEN", + "Imagery days in the box": "Bildtage im Bereich", + "Tune available internet radio stations": "Verfügbare Internetradiosender einstellen", + "DIRECTORY: RADIO BROWSER": "VERZEICHNIS: RADIO BROWSER", + "Local RTL-SDR receiver": "Lokaler RTL-SDR-Empfänger", + "LOCAL RTL-SDR": "LOKALES RTL-SDR", + "Chrome/Edge · WebUSB · one local tuner shared by FM and the Local ADS-B layer.": "Chrome/Edge · WebUSB · ein lokaler Tuner, den UKW und die Ebene Lokales ADS-B gemeinsam nutzen.", + "Use your location for faster ADS-B position decoding": "Eigenen Standort für schnellere Dekodierung von ADS-B-Positionen verwenden", + "CHANGE DEVICE": "GERÄT WECHSELN", + "Choose a different RTL-SDR or receiver channel": "Ein anderes RTL-SDR oder einen anderen Empfängerkanal wählen", + "RTL-SDR receiver mode": "RTL-SDR-Empfangsmodus", + "GAIN": "VERST.", + "RTL-SDR tuner gain for the current mode": "Tuner-Verstärkung des RTL-SDR für den aktuellen Modus", + "AUTO": "AUTO", + "MSG/S": "NACHR./S", + "HEARD": "EMPFANGEN", + "POSITIONED": "MIT POSITION", + "FM MHZ": "UKW MHZ", + "TUNE": "ABSTIMMEN", + "Seek broadcast FM stations": "UKW-Rundfunksender suchen", + "◀ SEEK": "◀ SUCHEN", + "SEEK ▶": "SUCHEN ▶", + "SDR VOL": "SDR-LAUTST.", + "Local SDR volume": "Lautstärke des lokalen SDR", + "Cyber": "Cyber", + "Sonar": "Sonar", + "Cyber sonar contact scanner": "Cyber-Sonar-Kontaktscanner", + "Rings": "Ringe", + "Sonar ring count": "Anzahl der Sonarringe", + "Range": "Reichweite", + "Sonar ring range": "Reichweite der Sonarringe", + "Power": "Leistung", + "Sonar intensity": "Sonarintensität", + "Opacity": "Deckkraft", + "Cyber contact and label opacity": "Deckkraft von Cyber-Kontakten und Beschriftungen", + "Minimum opacity for map dots, icons, models, brackets, and labels between sonar passes": "Minimale Deckkraft für Kartenpunkte, Symbole, Modelle, Klammern und Beschriftungen zwischen Sonardurchläufen", + "Sector": "Sektor", + "Sonar sector width": "Breite des Sonarsektors", + "Draw on the world — click vertices, double-click or Enter to finish, Esc to cancel": "Auf die Welt zeichnen – Eckpunkte anklicken, Doppelklick oder Enter zum Beenden, Esc zum Abbrechen", + "Shape": "Form", + "Shape to draw": "Zu zeichnende Form", + "Area": "Fläche", + "Line": "Linie", + "Pin": "Pin", + "Label (optional)": "Beschriftung (optional)", + "Label for the drawn shape": "Beschriftung der gezeichneten Form", + "Colour of the drawn shape": "Farbe der gezeichneten Form", + "Primary": "Primär", + "Amber": "Bernstein", + "Cyan": "Cyan", + "Green": "Grün", + "Red": "Rot", + "Clear": "Leeren", + "Remove every mark from the board": "Alle Markierungen von der Zeichenfläche entfernen", + "Show your own GeoJSON, KML, KMZ or GPX files on the globe (or drop them onto it). File bytes stay on this device; overlays can appear in map screenshots shared with voice.": "Eigene GeoJSON-, KML-, KMZ- oder GPX-Dateien auf dem Globus zeigen (oder auf ihn ziehen). Die Dateien bleiben auf diesem Gerät; Overlays können in Kartenscreenshots erscheinen, die mit der Sprachsteuerung geteilt werden.", + "Import": "Importieren", + "Choose GeoJSON, KML, KMZ or GPX files": "GeoJSON-, KML-, KMZ- oder GPX-Dateien wählen", + "Imported files": "Importierte Dateien", + "ACQUIRING FRAME": "FRAME WIRD ERFASST", + "STREET LEVEL": "STRASSENEBENE", + "Turn Street Level on or off": "Straßenebene ein- oder ausschalten", + "Show the street-level view full screen (Esc shrinks it)": "Ansicht auf Straßenebene im Vollbild zeigen (Esc verkleinert sie)", + "Image fit": "Bildanpassung", + "FIT": "EINPASSEN", + "Fit: show the whole photo, with dark bars where its shape differs from the frame": "Einpassen: ganzes Foto zeigen, mit dunklen Balken, wo seine Form vom Rahmen abweicht", + "FILL": "FÜLLEN", + "Fill: fill the frame edge to edge, cropping the photo": "Füllen: den Rahmen randlos füllen, das Foto wird beschnitten", + "Close the image and deselect it on the map": "Bild schließen und auf der Karte abwählen", + "Close the street-level image": "Bild auf Straßenebene schließen", + "Street-level viewer": "Viewer für Straßenebene", + "Open this image on the provider's site": "Dieses Bild auf der Website des Anbieters öffnen", + "Imagery providers": "Bildanbieter", + "PROVIDERS": "ANBIETER", + "Imagery filters": "Bildfilter", + "IMAGERY": "BILDER", + "Panorama filter": "Panoramafilter", + "ALL": "ALLE", + "FLAT": "FLACH", + "SINCE": "SEIT", + "Toggle straight-down and tilted map views": "Zwischen senkrechter und geneigter Kartenansicht wechseln", + "Reset map to north up": "Karte nach Norden ausrichten", + "Reset map bearing to north": "Kartenausrichtung auf Norden zurücksetzen" } diff --git a/src/i18n/same-as-english.json b/src/i18n/same-as-english.json index 83c8897d8..4946512a3 100644 --- a/src/i18n/same-as-english.json +++ b/src/i18n/same-as-english.json @@ -1,4 +1,168 @@ { + "de": [ + "1090 MHz", + "978 MHz UAT", + "AIS: --", + "AIS: {name}", + "ANIME", + "AUTO", + "Alternative", + "Ambient", + "Anime", + "Austin", + "BRG {value}°", + "BRG —", + "Bloom", + "Blues", + "Bus", + "CCTV", + "COCKPIT", + "CRS {value}°", + "CRT", + "Country", + "Cyan", + "Cyber", + "DEST ---°", + "DEST {bearing}", + "Dance", + "Details", + "Dubai", + "FALLBACK", + "FILTER", + "FLIR", + "FOV", + "FOV {value}°", + "FT", + "Folk", + "Funk", + "GEO", + "GOOGLE STREET VIEW", + "Global", + "Global · 60°S–60°N", + "Google Street View", + "HDG", + "HDG {value}°", + "Hip-Hop", + "House", + "Hybrid", + "Indie", + "Ironbow", + "Jazz", + "LIVE", + "Landsat 8/9", + "Latin", + "Layout", + "London", + "Los Angeles", + "MIL", + "MINI", + "MISSION", + "MM", + "MONITOR", + "Metal", + "Minimal", + "NAME", + "NASA FIRMS · LIVE", + "NAV", + "NEWS", + "NNW", + "NOIR", + "NORMAL", + "NVG", + "NW", + "New York", + "Noir", + "Normal", + "OK", + "ORBIT", + "ORBIT · ", + "Oldies", + "OpenStreetMap + optional Google Maps Places", + "Operator", + "PAUSE", + "PLAY", + "POS: LIVE", + "POS: {time}Z", + "POSITION {age}", + "PROJ MONITOR", + "Paris", + "Pause", + "Pin", + "Plan", + "Pop", + "Punk", + "RADIO", + "REC", + "REGION", + "RESET", + "Radio", + "Reggae", + "Rock", + "S2 GhostMaps", + "SAR", + "SIG", + "SNAPSHOT", + "SQUAWK {code} · {status}", + "SSW", + "STANDARD", + "START", + "STATION", + "STATUS", + "STATUS · ", + "STD", + "SW", + "SYNC", + "San Francisco", + "Scanlines", + "Scope", + "Sentinel-2", + "Sonar", + "Soul", + "Station", + "Station {id}", + "T minus {seconds}", + "TAGS · {tags}", + "TANKER", + "TEMP", + "Talk", + "Tallinn", + "Techno", + "Trance", + "Turboprop", + "UPSTREAM", + "Upstream HTTP {status}", + "Vignette", + "WHOT/BHOT", + "WIND", + "WNW", + "WSW", + "Washington DC", + "Wind", + "dB", + "feed status|live", + "fire behavior|Minimal", + "ft", + "hPa", + "km", + "km/h", + "min", + "mph", + "radio|NEWS", + "radio|TALK", + "view band|GLOBAL", + "{city} CCTV", + "{county} County", + "{source} HTTP {status}", + "{speed} kn", + "{type} SPD: {speed} HDG: {heading}", + "{value} KM", + "{value} KM DOWNRANGE", + "{value} KM/H", + "{value} KM/S", + "ΔN", + "Ⅱ PAUSE", + "▲ {frp} MW" + ], "es": [ "1090 MHz", "978 MHz UAT", diff --git a/src/ui/localePicker.test.mjs b/src/ui/localePicker.test.mjs index 057642827..8fb7eecc3 100644 --- a/src/ui/localePicker.test.mjs +++ b/src/ui/localePicker.test.mjs @@ -40,7 +40,7 @@ test('the current language comes first, the rest by their own names', () => { nativeNames: LOCALE_NAMES, }), ), - ['ru', 'en', 'es', 'zh-CN', 'zh-Hant'], + ['ru', 'de', 'en', 'es', 'zh-CN', 'zh-Hant'], ); assert.deepEqual( codes( @@ -50,7 +50,7 @@ test('the current language comes first, the rest by their own names', () => { nativeNames: LOCALE_NAMES, }), ), - ['es', 'en', 'ru', 'zh-CN', 'zh-Hant'], + ['es', 'de', 'en', 'ru', 'zh-CN', 'zh-Hant'], ); assert.deepEqual( codes( @@ -60,7 +60,7 @@ test('the current language comes first, the rest by their own names', () => { nativeNames: LOCALE_NAMES, }), ), - ['en', 'es', 'ru', 'zh-CN', 'zh-Hant'], + ['en', 'de', 'es', 'ru', 'zh-CN', 'zh-Hant'], ); const rows = buildLocaleOptions({ locales: MANY, @@ -95,6 +95,7 @@ test('each row gets the interface-language name for search, unless it only repea const byCode = Object.fromEntries(rows.map((row) => [row.code, row])); assert.equal(byCode.en.localName, 'английский'); assert.equal(byCode.es.localName, 'испанский'); + assert.equal(byCode.de.localName, 'немецкий'); assert.equal(byCode.ru.localName, '', 'русский only repeats Русский'); const english = buildLocaleOptions({ locales: LOCALES, @@ -261,7 +262,7 @@ test('keyboard model: open on the current language, move, choose, close', () => model.openList(); assert.equal(model.activeOption.code, 'ru'); assert.deepEqual(model.keydown({ key: 'ArrowDown' }), { handled: true }); - assert.equal(model.activeOption.code, 'en'); + assert.equal(model.activeOption.code, 'de'); model.keydown({ key: 'End' }); assert.equal(model.activeOption.code, 'zh-Hant'); model.keydown({ key: 'Home' }); @@ -275,7 +276,7 @@ test('keyboard model: open on the current language, move, choose, close', () => model.keydown({ key: 'ArrowDown' }); assert.deepEqual(model.keydown({ key: ' ' }), { handled: true, - choose: 'en', + choose: 'de', }); assert.deepEqual(model.keydown({ key: 'Escape' }), { handled: true, From 114694620726fb29112181beabb209d09685cbbf Mon Sep 17 00:00:00 2001 From: German Khokhlov Date: Wed, 28 Oct 2026 12:57:54 +0400 Subject: [PATCH 11/83] i18n(uk): complete and ship Ukrainian MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Translate the remaining 1,895 strings for the current UI (Bhote Koshi event, weather, imagery, street level, directions, SDR, voice, scenes, import) and review meirm's 832 entries from #312: 134 edited for Ukrainian HUD terms (КУРС/ПЕЛ./ШЛЯХ/ПРИЗН., Л/П, ОНЛАЙН for LIVE, Cyrillic units КМ, ВУЗ, ФТ, МВт), vessel types, number agreement and the ʼ apostrophe throughout. - Register uk: catalog, LOCALES, LOCALE_NAMES (Українська), package boundaries, same-as-English codes; picker and plural tests cover the four Ukrainian forms. - docs/translations/uk.md: style, plurals, units and glossary. Co-Authored-By: Claude Opus 5.5 --- docs/CURRENT-STATE.md | 2 +- docs/TRANSLATORS.md | 4 +- docs/translations/uk.md | 76 + scripts/package-boundaries.json | 43 + src/i18n/i18n.test.mjs | 18 + src/i18n/index.js | 9 +- src/i18n/locale.js | 10 +- src/i18n/locales/uk.json | 2479 +++++++++++++++++++++++++++++-- src/i18n/same-as-english.json | 13 + src/ui/localePicker.test.mjs | 11 +- 10 files changed, 2518 insertions(+), 147 deletions(-) create mode 100644 docs/translations/uk.md diff --git a/docs/CURRENT-STATE.md b/docs/CURRENT-STATE.md index c55031a6a..96d12b5cb 100644 --- a/docs/CURRENT-STATE.md +++ b/docs/CURRENT-STATE.md @@ -3733,7 +3733,7 @@ test:track` 43 tracking invariants · headless QA harnesses under ### Interface localization (October 2026) -Shipped locales: **en** (source and fallback), **es**, **ru**, **zh-CN** and **zh-Hant**. The code lives in +Shipped locales: **en** (source and fallback), **es**, **ru**, **uk**, **zh-CN** and **zh-Hant**. The code lives in `src/i18n/`. How to mark UI text: [`docs/I18N.md`](./I18N.md); translator workflow: [`docs/TRANSLATORS.md`](./TRANSLATORS.md). diff --git a/docs/TRANSLATORS.md b/docs/TRANSLATORS.md index 830ca155e..1992e6fdf 100644 --- a/docs/TRANSLATORS.md +++ b/docs/TRANSLATORS.md @@ -1,6 +1,6 @@ # Translating God's Eye View -Shipped languages: **English** (source and fallback), **Spanish** (`es`), **Russian** (`ru`), **Simplified Chinese** (`zh-CN`) and **Traditional Chinese** (`zh-Hant`). +Shipped languages: **English** (source and fallback), **Spanish** (`es`), **Russian** (`ru`), **Ukrainian** (`uk`), **Simplified Chinese** (`zh-CN`) and **Traditional Chinese** (`zh-Hant`). ## How it works @@ -63,4 +63,4 @@ These are contracts, not copy: layer ids and registry keys, status enums and oth ## Language notes -Each language keeps its glossary, plural forms, units and style in its own file, `docs/translations/.md`: [Spanish](./translations/es.md), [Russian](./translations/ru.md), [Simplified Chinese](./translations/zh-CN.md), [Traditional Chinese](./translations/zh-Hant.md). Read it before translating, and add a term there when you settle on one. +Each language keeps its glossary, plural forms, units and style in its own file, `docs/translations/.md`: [Spanish](./translations/es.md), [Russian](./translations/ru.md), [Ukrainian](./translations/uk.md), [Simplified Chinese](./translations/zh-CN.md), [Traditional Chinese](./translations/zh-Hant.md). Read it before translating, and add a term there when you settle on one. diff --git a/docs/translations/uk.md b/docs/translations/uk.md new file mode 100644 index 000000000..cd90b7b01 --- /dev/null +++ b/docs/translations/uk.md @@ -0,0 +1,76 @@ +# Ukrainian (`uk`) + +Catalog: `src/i18n/locales/uk.json`. General rules: [TRANSLATORS.md](../TRANSLATORS.md). + +Translation source: meirm (#312). + +## Style + +- Address the user with polite imperatives: «Натисніть», «Увімкніть», «Спробуйте ще раз». +- Sentence case, not Title Case: "Live Flights" → «Рейси онлайн». +- Ukrainian norms, not Russian calques: «у радіусі», «за посиланням», «надто довгий», «потім», «вигляд» (view), «стеження» (tracking); prepositions alternate у/в and і/й by euphony. +- The apostrophe is always ʼ (U+02BC): обʼєкт, звʼязок, памʼять. Not ' or ’. +- Quotes inside Ukrainian text are «ялинки»; a button or layer name inside a sentence goes in them: Увімкніть «Вуличні знімки». +- In short labels, a standard abbreviation with a period beats a wrapped line: ПОПЕР., ДАЛЬН., КАЛІБР. +- Units: км, м, км/год, м/с, вуз (knots), фт (feet), год, хв, с, МГц, дБ, гПа; in UPPERCASE text КМ, М, КМ/С, ВУЗ, ФТ. MW is МВт in any case. `°` and `%` stay. Decimal comma in coordinates written as text: 28,2710° пн. ш. +- Coordinates: пн. ш. / пд. ш. / сх. д. / зх. д.; the HUD hemisphere letters are Пн, Пд, Сх, Зх. + +## Plurals + +A `tn()` entry needs four forms. `Intl.PluralRules('uk')` picks: + +| Form | Counts | Example | +| ------- | ------------------------ | ---------- | +| `one` | 1, 21, 31, 101… | 1 камера | +| `few` | 2–4, 22–24, 32–34… | 3 камери | +| `many` | 0, 5–20, 25–30, 111–114… | 5 камер | +| `other` | fractions: 1.5, 2.25… | 1,5 камери | + +`other` takes the genitive singular: 1,5 кадру, 1,5 літака, 1,5 ключа. When a word next to a number cannot agree in every form, move the number after a colon instead: «поруч: {count}», «відповідей: {responses}». The same trick keeps place names and tool names out of a preposition's case: «звідки: {origin}», «Активно: {name}». + +## Glossary + +| English | Українська | +| ------------------------------------------ | ---------------------------------------------------- | +| layer / data layer | шар / шар даних | +| feed | потік даних (short: потік) | +| source / data source | джерело / джерело даних | +| LIVE (status) / live data | ОНЛАЙН / у реальному часі | +| SIMULATED / SYNTHETIC | ІМІТАЦІЯ | +| stale / degraded / unavailable | застарів / з перебоями (chip: ПЕРЕБОЇ) / недоступний | +| retry | повтор | +| key (API key) / POWER UP | ключ / ЗАПУСК | +| Provider Settings / provider | Налаштування постачальників / постачальник | +| globe / map / map source / basemap | глобус / карта / джерело карти / підкладка | +| aircraft / flight / military flights | літак (short HUD: борт) / рейс / військові рейси | +| vessel, ship / vessels | судно / судна (gen. pl. суден) | +| satellite | супутник | +| launch (rocket) / space mission | запуск / космічна місія | +| contact / tracking | контакт / стеження | +| installation, site / mapped | обʼєкт / нанесений на карту | +| camera / CCTV camera | камера / камера CCTV | +| earthquake / active fire / fire perimeter | землетрус / активна пожежа / контур пожежі | +| advisory (NHC/CPHC cyclone) | зведення | +| scene / shot / scene recipe | сцена / кадр / рецепт сцени | +| briefing / panel / dock | брифінг / панель / док | +| preset / visual preset | пресет / візуальний пресет | +| Scope (circular viewport mask) | приціл | +| overlay (detection overlay) | накладка | +| heading / altitude / ground speed | курс / висота / шляхова швидкість | +| HDG / BRG / CRS / FOV / DEST / SPD / RANGE | КУРС / ПЕЛ. / ШЛЯХ / ОГЛЯД / ПРИЗН. / ШВИД / ДАЛЬН. | +| Street View (Google) | Перегляд вулиць (as in Ukrainian Google Maps) | +| Street Level (layer) | Вуличні знімки | +| imagery / recent imagery | знімки / свіжі знімки | +| radar reflectivity / lightning density | радіолокаційна відбивність / щільність блискавок | +| infrared | інфрачервоний (short: ІЧ) | +| receiver / gain / decoder | приймач / підсилення / декодер | +| broadcaster | мовник | +| CONUS, WHOT/BHOT, Ironbow, CRT, NVG, FLIR | без перекладу | +| PREV / NEXT (HUD) / Previous / Next | ПОПЕР. / ДАЛІ / Попередній / Наступний | +| anchor / data pack / bundle (scene) | якір / пакет даних / архів | +| box (Recent Imagery area) | область | +| camera move | переліт | +| SIG / NEWS / LOCAL (briefing tabs) | СИГН. / НОВИНИ / МІСЦ. | +| compass points (N, NNE, NE, …) | Пн, ПнПнСх, ПнСх, … | +| L / R (relative bearing) | Л / П | +| click / tap | клацнути / натиснути | diff --git a/scripts/package-boundaries.json b/scripts/package-boundaries.json index 9f06f73f6..5e5e2dad1 100644 --- a/scripts/package-boundaries.json +++ b/scripts/package-boundaries.json @@ -441,6 +441,7 @@ "src/i18n/locale.js", "src/i18n/locales/es.json", "src/i18n/locales/ru.json", + "src/i18n/locales/uk.json", "src/i18n/locales/zh-CN.json", "src/i18n/locales/zh-Hant.json" ], @@ -481,6 +482,7 @@ "src/i18n/locale.js", "src/i18n/locales/es.json", "src/i18n/locales/ru.json", + "src/i18n/locales/uk.json", "src/i18n/locales/zh-CN.json", "src/i18n/locales/zh-Hant.json" ], @@ -511,6 +513,7 @@ "src/i18n/locale.js", "src/i18n/locales/es.json", "src/i18n/locales/ru.json", + "src/i18n/locales/uk.json", "src/i18n/locales/zh-CN.json", "src/i18n/locales/zh-Hant.json", "src/ui/unitLabels.js", @@ -533,6 +536,7 @@ "src/i18n/locale.js", "src/i18n/locales/es.json", "src/i18n/locales/ru.json", + "src/i18n/locales/uk.json", "src/i18n/locales/zh-CN.json", "src/i18n/locales/zh-Hant.json" ], @@ -550,6 +554,7 @@ "src/i18n/locale.js", "src/i18n/locales/es.json", "src/i18n/locales/ru.json", + "src/i18n/locales/uk.json", "src/i18n/locales/zh-CN.json", "src/i18n/locales/zh-Hant.json" ], @@ -570,6 +575,7 @@ "src/i18n/locale.js", "src/i18n/locales/es.json", "src/i18n/locales/ru.json", + "src/i18n/locales/uk.json", "src/i18n/locales/zh-CN.json", "src/i18n/locales/zh-Hant.json", "src/ui/unitLabels.js", @@ -597,6 +603,7 @@ "src/i18n/locale.js", "src/i18n/locales/es.json", "src/i18n/locales/ru.json", + "src/i18n/locales/uk.json", "src/i18n/locales/zh-CN.json", "src/i18n/locales/zh-Hant.json", "src/ui/layerNames.js" @@ -632,6 +639,7 @@ "src/i18n/locale.js", "src/i18n/locales/es.json", "src/i18n/locales/ru.json", + "src/i18n/locales/uk.json", "src/i18n/locales/zh-CN.json", "src/i18n/locales/zh-Hant.json", "src/ui/unitLabels.js" @@ -649,6 +657,7 @@ "src/i18n/locale.js", "src/i18n/locales/es.json", "src/i18n/locales/ru.json", + "src/i18n/locales/uk.json", "src/i18n/locales/zh-CN.json", "src/i18n/locales/zh-Hant.json", "src/ui/unitLabels.js" @@ -808,6 +817,7 @@ "src/i18n/locale.js", "src/i18n/locales/es.json", "src/i18n/locales/ru.json", + "src/i18n/locales/uk.json", "src/i18n/locales/zh-CN.json", "src/i18n/locales/zh-Hant.json", "src/ui/unitLabels.js", @@ -930,6 +940,7 @@ "src/i18n/locale.js", "src/i18n/locales/es.json", "src/i18n/locales/ru.json", + "src/i18n/locales/uk.json", "src/i18n/locales/zh-CN.json", "src/i18n/locales/zh-Hant.json", "src/ui/unitLabels.js" @@ -998,6 +1009,7 @@ "src/i18n/locale.js", "src/i18n/locales/es.json", "src/i18n/locales/ru.json", + "src/i18n/locales/uk.json", "src/i18n/locales/zh-CN.json", "src/i18n/locales/zh-Hant.json", "src/ui/unitLabels.js" @@ -1047,6 +1059,7 @@ "src/i18n/locale.js", "src/i18n/locales/es.json", "src/i18n/locales/ru.json", + "src/i18n/locales/uk.json", "src/i18n/locales/zh-CN.json", "src/i18n/locales/zh-Hant.json" ], @@ -1110,6 +1123,7 @@ "src/i18n/locale.js", "src/i18n/locales/es.json", "src/i18n/locales/ru.json", + "src/i18n/locales/uk.json", "src/i18n/locales/zh-CN.json", "src/i18n/locales/zh-Hant.json" ], @@ -1140,6 +1154,7 @@ "src/i18n/locale.js", "src/i18n/locales/es.json", "src/i18n/locales/ru.json", + "src/i18n/locales/uk.json", "src/i18n/locales/zh-CN.json", "src/i18n/locales/zh-Hant.json", "src/ui/unitLabels.js", @@ -1171,6 +1186,7 @@ "src/i18n/locale.js", "src/i18n/locales/es.json", "src/i18n/locales/ru.json", + "src/i18n/locales/uk.json", "src/i18n/locales/zh-CN.json", "src/i18n/locales/zh-Hant.json" ], @@ -1202,6 +1218,7 @@ "src/i18n/locale.js", "src/i18n/locales/es.json", "src/i18n/locales/ru.json", + "src/i18n/locales/uk.json", "src/i18n/locales/zh-CN.json", "src/i18n/locales/zh-Hant.json", "src/ui/unitLabels.js" @@ -1236,6 +1253,7 @@ "src/i18n/locale.js", "src/i18n/locales/es.json", "src/i18n/locales/ru.json", + "src/i18n/locales/uk.json", "src/i18n/locales/zh-CN.json", "src/i18n/locales/zh-Hant.json" ], @@ -1279,6 +1297,7 @@ "src/i18n/locale.js", "src/i18n/locales/es.json", "src/i18n/locales/ru.json", + "src/i18n/locales/uk.json", "src/i18n/locales/zh-CN.json", "src/i18n/locales/zh-Hant.json", "src/layers/installations/classLabel.js" @@ -1316,6 +1335,7 @@ "src/i18n/locale.js", "src/i18n/locales/es.json", "src/i18n/locales/ru.json", + "src/i18n/locales/uk.json", "src/i18n/locales/zh-CN.json", "src/i18n/locales/zh-Hant.json", "src/ui/unitLabels.js" @@ -1367,6 +1387,7 @@ "src/i18n/locale.js", "src/i18n/locales/es.json", "src/i18n/locales/ru.json", + "src/i18n/locales/uk.json", "src/i18n/locales/zh-CN.json", "src/i18n/locales/zh-Hant.json" ], @@ -1397,6 +1418,7 @@ "src/i18n/locale.js", "src/i18n/locales/es.json", "src/i18n/locales/ru.json", + "src/i18n/locales/uk.json", "src/i18n/locales/zh-CN.json", "src/i18n/locales/zh-Hant.json" ], @@ -1446,6 +1468,7 @@ "src/i18n/locale.js", "src/i18n/locales/es.json", "src/i18n/locales/ru.json", + "src/i18n/locales/uk.json", "src/i18n/locales/zh-CN.json", "src/i18n/locales/zh-Hant.json" ], @@ -1510,6 +1533,7 @@ "src/i18n/locale.js", "src/i18n/locales/es.json", "src/i18n/locales/ru.json", + "src/i18n/locales/uk.json", "src/i18n/locales/zh-CN.json", "src/i18n/locales/zh-Hant.json", "src/layers/streetLevel/providers/mapillary/policy.js" @@ -1540,6 +1564,7 @@ "src/i18n/locale.js", "src/i18n/locales/es.json", "src/i18n/locales/ru.json", + "src/i18n/locales/uk.json", "src/i18n/locales/zh-CN.json", "src/i18n/locales/zh-Hant.json" ], @@ -1581,6 +1606,7 @@ "src/i18n/locale.js", "src/i18n/locales/es.json", "src/i18n/locales/ru.json", + "src/i18n/locales/uk.json", "src/i18n/locales/zh-CN.json", "src/i18n/locales/zh-Hant.json" ], @@ -1604,6 +1630,7 @@ "src/i18n/locale.js", "src/i18n/locales/es.json", "src/i18n/locales/ru.json", + "src/i18n/locales/uk.json", "src/i18n/locales/zh-CN.json", "src/i18n/locales/zh-Hant.json" ], @@ -1661,6 +1688,7 @@ "src/i18n/locale.js", "src/i18n/locales/es.json", "src/i18n/locales/ru.json", + "src/i18n/locales/uk.json", "src/i18n/locales/zh-CN.json", "src/i18n/locales/zh-Hant.json" ], @@ -1724,6 +1752,7 @@ "src/i18n/locale.js", "src/i18n/locales/es.json", "src/i18n/locales/ru.json", + "src/i18n/locales/uk.json", "src/i18n/locales/zh-CN.json", "src/i18n/locales/zh-Hant.json", "src/ui/statusText.js", @@ -2607,6 +2636,7 @@ "src/i18n/locale.js", "src/i18n/locales/es.json", "src/i18n/locales/ru.json", + "src/i18n/locales/uk.json", "src/i18n/locales/zh-CN.json", "src/i18n/locales/zh-Hant.json", "src/ui/unitLabels.js", @@ -3192,6 +3222,7 @@ "src/i18n/locale.js", "src/i18n/locales/es.json", "src/i18n/locales/ru.json", + "src/i18n/locales/uk.json", "src/i18n/locales/zh-CN.json", "src/i18n/locales/zh-Hant.json", "src/ui/unitLabels.js", @@ -3303,6 +3334,7 @@ "src/i18n/locale.js", "src/i18n/locales/es.json", "src/i18n/locales/ru.json", + "src/i18n/locales/uk.json", "src/i18n/locales/zh-CN.json", "src/i18n/locales/zh-Hant.json", "src/i18n/index.js" @@ -3327,6 +3359,7 @@ "src/i18n/locale.js", "src/i18n/locales/es.json", "src/i18n/locales/ru.json", + "src/i18n/locales/uk.json", "src/i18n/locales/zh-CN.json", "src/i18n/locales/zh-Hant.json" ], @@ -3364,6 +3397,7 @@ "src/i18n/locale.js", "src/i18n/locales/es.json", "src/i18n/locales/ru.json", + "src/i18n/locales/uk.json", "src/i18n/locales/zh-CN.json", "src/i18n/locales/zh-Hant.json", "src/scopeMaskPolicy.js", @@ -3391,6 +3425,7 @@ "src/i18n/locale.js", "src/i18n/locales/es.json", "src/i18n/locales/ru.json", + "src/i18n/locales/uk.json", "src/i18n/locales/zh-CN.json", "src/i18n/locales/zh-Hant.json" ], @@ -3483,6 +3518,7 @@ "src/i18n/locale.js", "src/i18n/locales/es.json", "src/i18n/locales/ru.json", + "src/i18n/locales/uk.json", "src/i18n/locales/zh-CN.json", "src/i18n/locales/zh-Hant.json", "src/ui/unitLabels.js" @@ -3539,6 +3575,7 @@ "src/i18n/locale.js", "src/i18n/locales/es.json", "src/i18n/locales/ru.json", + "src/i18n/locales/uk.json", "src/i18n/locales/zh-CN.json", "src/i18n/locales/zh-Hant.json", "src/ui/statusText.js", @@ -3794,6 +3831,7 @@ "src/i18n/locale.js", "src/i18n/locales/es.json", "src/i18n/locales/ru.json", + "src/i18n/locales/uk.json", "src/i18n/locales/zh-CN.json", "src/i18n/locales/zh-Hant.json" ], @@ -3838,6 +3876,7 @@ "src/i18n/locale.js", "src/i18n/locales/es.json", "src/i18n/locales/ru.json", + "src/i18n/locales/uk.json", "src/i18n/locales/zh-CN.json", "src/i18n/locales/zh-Hant.json" ], @@ -3892,6 +3931,7 @@ "src/i18n/locale.js", "src/i18n/locales/es.json", "src/i18n/locales/ru.json", + "src/i18n/locales/uk.json", "src/i18n/locales/zh-CN.json", "src/i18n/locales/zh-Hant.json" ], @@ -3909,6 +3949,7 @@ "src/i18n/locale.js", "src/i18n/locales/es.json", "src/i18n/locales/ru.json", + "src/i18n/locales/uk.json", "src/i18n/locales/zh-CN.json", "src/i18n/locales/zh-Hant.json", "src/ui/statusText.js", @@ -3969,6 +4010,7 @@ "src/i18n/locale.js", "src/i18n/locales/es.json", "src/i18n/locales/ru.json", + "src/i18n/locales/uk.json", "src/i18n/locales/zh-CN.json", "src/i18n/locales/zh-Hant.json", "src/data/geoImportImages.js", @@ -4166,6 +4208,7 @@ "src/i18n/locale.js", "src/i18n/locales/es.json", "src/i18n/locales/ru.json", + "src/i18n/locales/uk.json", "src/i18n/locales/zh-CN.json", "src/i18n/locales/zh-Hant.json", "src/ui/statusText.js", diff --git a/src/i18n/i18n.test.mjs b/src/i18n/i18n.test.mjs index 1b421f2ff..d38e03ae1 100644 --- a/src/i18n/i18n.test.mjs +++ b/src/i18n/i18n.test.mjs @@ -33,6 +33,8 @@ function memoryStorage(initial = {}) { test('normalizeLocale folds regional variants and rejects unshipped tags', () => { assert.equal(normalizeLocale('ru-RU'), 'ru'); assert.equal(normalizeLocale(' RU '), 'ru'); + assert.equal(normalizeLocale('uk'), 'uk'); + assert.equal(normalizeLocale('uk-UA'), 'uk'); assert.equal(normalizeLocale('en_GB'), 'en'); assert.equal(normalizeLocale('xx'), null); // Explicit script tags take precedence over regional defaults. @@ -142,6 +144,22 @@ test('tn() picks English and Russian plural forms', () => { assert.match(label(21), / 21 КЛЮЧ(?![А-ЯЁ])/); }); +test('tn() picks the four Ukrainian plural forms', () => { + const label = (count) => + tn( + count, + 'POWER UP · {count} KEY WAITING', + 'POWER UP · {count} KEYS WAITING', + ); + setLocale('uk'); + assert.match(label(1), / 1 КЛЮЧ(?![А-ЯҐЄІЇ])/); + assert.match(label(3), / 3 КЛЮЧІ(?![А-ЯҐЄІЇ])/); + assert.match(label(5), / 5 КЛЮЧІВ(?![А-ЯҐЄІЇ])/); + assert.match(label(11), / 11 КЛЮЧІВ(?![А-ЯҐЄІЇ])/); + assert.match(label(21), / 21 КЛЮЧ(?![А-ЯҐЄІЇ])/); + assert.match(label(1.5), / 1\.5 КЛЮЧА(?![А-ЯҐЄІЇ])/); +}); + test('t() context separates identical English with different meanings', () => { assert.equal(t('CLEAR', { context: 'action' }), 'CLEAR'); setLocale('ru'); diff --git a/src/i18n/index.js b/src/i18n/index.js index 6fc4becc9..df15690b2 100644 --- a/src/i18n/index.js +++ b/src/i18n/index.js @@ -18,10 +18,17 @@ import { } from './locale.js'; import es from './locales/es.json' with { type: 'json' }; import ru from './locales/ru.json' with { type: 'json' }; +import uk from './locales/uk.json' with { type: 'json' }; import zhCN from './locales/zh-CN.json' with { type: 'json' }; import zhHant from './locales/zh-Hant.json' with { type: 'json' }; -const CATALOGS = Object.freeze({ es, ru, 'zh-CN': zhCN, 'zh-Hant': zhHant }); +const CATALOGS = Object.freeze({ + es, + ru, + uk, + 'zh-CN': zhCN, + 'zh-Hant': zhHant, +}); let currentLocale = DEFAULT_LOCALE; diff --git a/src/i18n/locale.js b/src/i18n/locale.js index 55ed71163..77c1e68e7 100644 --- a/src/i18n/locale.js +++ b/src/i18n/locale.js @@ -8,13 +8,21 @@ export const LOCALE_STORAGE_KEY = 'gev:locale:v1'; export const DEFAULT_LOCALE = 'en'; /** Shipped locales; order does not matter. Adding one: docs/TRANSLATORS.md. */ -export const LOCALES = Object.freeze(['en', 'es', 'ru', 'zh-CN', 'zh-Hant']); +export const LOCALES = Object.freeze([ + 'en', + 'es', + 'ru', + 'uk', + 'zh-CN', + 'zh-Hant', +]); /** Each locale named in its own language, for the selector. */ export const LOCALE_NAMES = Object.freeze({ en: 'English', es: 'Español', ru: 'Русский', + uk: 'Українська', 'zh-CN': '中文(简体)', 'zh-Hant': '中文(繁體)', }); diff --git a/src/i18n/locales/uk.json b/src/i18n/locales/uk.json index 09fdc59e3..8a543e929 100644 --- a/src/i18n/locales/uk.json +++ b/src/i18n/locales/uk.json @@ -1,59 +1,307 @@ { - "Flying to Austin, TX...": "Переліт до Austin, TX...", + "Pick a shape, then click the map.": "Виберіть фігуру й клацніть на карті.", + "Enter to place the pin, Esc to cancel.": "Enter — поставити мітку, Esc — скасувати.", + "Click where the pin goes.": "Клацніть там, де має бути мітка.", + "Click {count} more points.": { + "one": "Позначте ще {count} точку.", + "few": "Позначте ще {count} точки.", + "many": "Позначте ще {count} точок.", + "other": "Позначте ще {count} точки." + }, + "Those points are in a line — move one off it to enclose an area.": "Точки лежать на одній прямій — змістіть одну з них, щоб утворилася замкнена область.", + "That line has no length — click somewhere further away.": "Лінія не має довжини — клацніть далі.", + " · {max}-point limit reached": " · досягнуто ліміту точок: {max}", + "{measure} · double-click or Enter to finish, Backspace undoes, Esc cancels.{full}": "{measure} · подвійне клацання або Enter — завершити, Backspace — скасувати точку, Esc — скасувати.{full}", + "drawings on the map": "малюнки на карті", + "That shape already has {count} points — finish it or press Backspace.": "У цій фігурі вже точок: {count} — завершіть її або натисніть Backspace.", + "That point is off the globe — click on the world.": "Ця точка поза глобусом — клацніть на Землі.", + "That shape could not be placed.": "Не вдалося розмістити фігуру.", + "Could not place the shape: {error}": "Не вдалося розмістити фігуру: {error}", + "Board cleared.": "Дошку очищено.", + "{owner} is using the pointer — close it first.": "Вказівник зайнятий: «{owner}». Спершу закрийте його.", + "{label} · Detailed outline unavailable": "{label} · Докладний контур недоступний", + "Flying to Austin, TX...": "Переліт до Остіна, Техас...", "Restoring shared view...": "Відновлення спільного вигляду...", "Configuring viewer...": "Налаштування переглядача...", "Loading Google 3D Tiles...": "Завантаження Google 3D Tiles...", "Loading the keyless globe...": "Завантаження глобуса без ключа...", "Google 3D Tiles unavailable ({detail}). Loading the keyless globe...": "Google 3D Tiles недоступні ({detail}). Завантаження глобуса без ключа...", "Initializing systems...": "Ініціалізація систем...", + "Space Missions isolates replay data. Exit the mode to enable {layer}.": "Режим «Космічні місії» ізолює дані відтворення. Вийдіть із режиму, щоб увімкнути шар «{layer}».", + "Data attribution": "Джерела даних", + "Data provided by:": "Дані надали:", "Close data attribution": "Закрити відомості про джерела даних", + "Light aircraft": "Легкий літак", + "Glider": "Планер", + "Turboprop": "Турбогвинтовий літак", + "Airliner": "Авіалайнер", + "Widebody": "Широкофюзеляжний літак", + "Four-engine jet": "Чотиримоторний реактивний літак", + "Helicopter": "Гелікоптер", + "Fast jet": "Високоманеврений літак", + "Business jet": "Бізнес-джет", + "Drone": "Безпілотник", + "General emergency": "Загальна аварійна ситуація", + "Unlawful interference": "Незаконне втручання", + "Radio failure": "Відмова радіозвʼязку", + "Downed aircraft": "Вимушена посадка", + "Minimum fuel": "Мінімальний залишок пального", + "Lifeguard (medical priority)": "Санітарний рейс (медичний пріоритет)", + "Rasuwagadhi witness video": "Відео очевидця в Rasuwagadhi", + "Bhote Koshi valley footage": "Зйомка долини Bhote Koshi", + "Flood footage": "Зйомка паводка", + "Compilation and casualty claims": "Добірка відео та повідомлення про жертви", + "SOURCE GEOCONFIRMED · WORLD-PINNED": "МІСЦЕ ЗЙОМКИ ПІДТВЕРДЖЕНО · ПОЗНАЧЕНО НА КАРТІ", + "SOURCE CREDITED · LOCATION UNRESOLVED": "АВТОРА ЗАЗНАЧЕНО · МІСЦЕ НЕ ВСТАНОВЛЕНО", + "REFERENCE ONLY · CLAIMS UNVERIFIED": "ЛИШЕ ДЛЯ ДОВІДКИ · ТВЕРДЖЕННЯ НЕ ПЕРЕВІРЕНО", + "SOURCE GEOCONFIRMED": "МІСЦЕ ЗЙОМКИ ПІДТВЕРДЖЕНО", + "2021 historical reference versus 2026 post-event imagery; changes are cumulative and include the July 2025 Rasuwagadhi flood. Schematic downstream progression, not modeled arrival time; not an official hazard model.": "Історичний знімок 2021 року порівняно зі знімками 2026 року після події; зміни показано сумарно за весь період, вони охоплюють і паводок у Rasuwagadhi в липні 2025 року. Схематичне просування вниз за течією, а не змодельований час добігання паводка; не офіційна модель небезпеки.", + "Immediate collapse viewpoint": "Точка огляду біля місця обвалу", + "Collapse viewpoint": "Вигляд на обвал", + "Debris-dammed lake": "Озеро, загачене уламками", + "Dammed lake": "Загачене озеро", + "Second landslide": "Другий зсув", + "Gyirong border gate": "Прикордонний перехід Gyirong", + "Border gate": "Прикордонний перехід", + "Timure evidence cluster": "Група свідчень біля Timure", + "Mailung / Upper Trishuli bridge": "Mailung / міст Upper Trishuli", + "Dandagaun viewpoint restaurant": "Ресторан з оглядовим майданчиком, Dandagaun", + "Dandagaun viewpoint": "Оглядовий майданчик Dandagaun", + "Bidur - Trishuli bridge": "Міст Bidur — Trishuli", + "Bidur bridge": "Міст Bidur", + "Devighat / Taadi Khola Bridge": "Devighat / міст Taadi Khola", + "Devighat bridge": "Міст Devighat", + "Facebook player API did not initialize.": "API плеєра Facebook не ініціалізувався.", + "Facebook player API could not load.": "Не вдалося завантажити API плеєра Facebook.", + "Facebook player API timed out.": "Минув час очікування API плеєра Facebook.", + "X embed API did not initialize.": "API вбудовування X не ініціалізувався.", + "X embed could not load.": "Не вдалося завантажити вбудовування X.", + "X embed timed out.": "Минув час очікування вбудовування X.", "UNAVAILABLE": "НЕДОСТУПНО", + "TIMEOUT": "ТАЙМАУТ", + "BLOCKED": "ЗАБЛОКОВАНО", "SOURCE": "ДЖЕРЕЛО", + "Facebook embed unavailable. The post may be private, removed, region-restricted, or blocked.": "Вбудовування Facebook недоступне. Допис може бути приватним, видаленим, обмеженим за регіоном або заблокованим.", + "Preloading {provider} media": "Попереднє завантаження медіа {provider}", + "LOADING X POST…": "ЗАВАНТАЖЕННЯ ДОПИСУ X…", + "The X post is unavailable or cannot be embedded.": "Допис X недоступний або його не можна вбудувати.", + "X POST · PROVIDER CONTROLS": "ДОПИС X · ВБУДОВАНИЙ ВІДЖЕТ", + "{reason} OPEN ORIGINAL.": "{reason} ВІДКРИЙТЕ ОРИГІНАЛ.", + "X embed unavailable": "Вбудовування X недоступне", + "FACEBOOK · PROVIDER CONTROLS": "FACEBOOK · ВБУДОВАНИЙ ПЛЕЄР", + "Facebook embed unavailable": "Вбудовування Facebook недоступне", + "AUTOPLAY BLOCKED · USE PROVIDER CONTROLS": "АВТОВІДТВОРЕННЯ ЗАБЛОКОВАНО · ЗАПУСТІТЬ У ПЛЕЄРІ", + "Embedded {provider} media for {source}": "Вбудоване медіа {provider}: {source}", + "witness source": "свідчення очевидця", + "Witness source": "Свідчення очевидця", + "{provider} · EMBEDDED SOURCE": "{provider} · ВБУДОВАНЕ ДЖЕРЕЛО", + "OPEN ORIGINAL ↗": "ВІДКРИТИ ОРИГІНАЛ ↗", + "{provider} media: {source}": "Медіа {provider}: {source}", + "{provider} · PROVIDER CONTROLS": "{provider} · ВБУДОВАНИЙ ПЛЕЄР", + "YOUTUBE {state} · OPEN ORIGINAL": "YOUTUBE {state} · ВІДКРИТИ ОРИГІНАЛ", + "INITIATION": "ЗАРОДЖЕННЯ", + "DAMMING": "ЗАГАТА", + "SECONDARY FAILURE": "ВТОРИННИЙ ПРОРИВ", + "BORDER ARRIVAL": "ДОСЯГНЕННЯ КОРДОНУ", + "PROPAGATION": "ПОШИРЕННЯ", + "DOWNSTREAM PASSAGE": "ПРОХОДЖЕННЯ ВНИЗ ЗА ТЕЧІЄЮ", + "CONSEQUENCE": "НАСЛІДКИ", + "DOWNSTREAM CONSEQUENCE": "НАСЛІДКИ НИЖЧЕ ЗА ТЕЧІЄЮ", + "EVIDENCE": "СВІДЧЕННЯ", + "{year} HISTORICAL REFERENCE": "{year} ІСТОРИЧНИЙ ЗНІМОК", + "{year} POST-EVENT": "{year} ПІСЛЯ ПОДІЇ", + "{count} GEOLOCATED SOURCE-MAP PLACEMENTS": { + "one": "{count} ГЕОПРИВʼЯЗАНА МІТКА НА КАРТІ ДЖЕРЕЛ", + "few": "{count} ГЕОПРИВʼЯЗАНІ МІТКИ НА КАРТІ ДЖЕРЕЛ", + "many": "{count} ГЕОПРИВʼЯЗАНИХ МІТОК НА КАРТІ ДЖЕРЕЛ", + "other": "{count} ГЕОПРИВʼЯЗАНОЇ МІТКИ НА КАРТІ ДЖЕРЕЛ" + }, + "NO PREVIEW": "НЕМАЄ ПОПЕРЕДНЬОГО ПЕРЕГЛЯДУ", + "YouTube source": "Джерело YouTube", + "Facebook source": "Джерело Facebook", + "SOURCE LINK": "ПОСИЛАННЯ НА ДЖЕРЕЛО", + "{publisher} / OPEN": "{publisher} / ВІДКРИТИ", + "Bhote Koshi flood reconstruction controls": "Керування реконструкцією паводка на Bhote Koshi", + "EVENT RECONSTRUCTION · 26 AUG 2026": "РЕКОНСТРУКЦІЯ ПОДІЇ · 26 СЕРП. 2026", + "BHOTE KOSHI OUTBURST FLOOD": "ПРОРИВНИЙ ПАВОДОК НА BHOTE KOSHI", + "Close event layer": "Закрити шар події", + "OBSERVED IMAGERY": "ФАКТИЧНІ ЗНІМКИ", + "SCHEMATIC CORRIDOR": "СХЕМАТИЧНИЙ КОРИДОР", + "2021 HISTORICAL REFERENCE / 2026 POST-EVENT": "2021 ІСТОРИЧНИЙ ЗНІМОК / 2026 ПІСЛЯ ПОДІЇ", + "Historical reference and post-event image split": "Порівняння історичного знімка та знімка після події", + "RECONSTRUCTION CLOCK": "ЧАС РЕКОНСТРУКЦІЇ", + "Schematic downstream progression": "Схематичне просування вниз за течією", + "Story beat navigation": "Навігація етапами сюжету", + "Previous story beat": "Попередній етап сюжету", + "CAUSE": "ПРИЧИНА", + "CAPTURE TIME UNVERIFIED": "ЧАС ЗЙОМКИ НЕ ПІДТВЕРДЖЕНО", + "Next story beat": "Наступний етап сюжету", + "▶ PLAY": "▶ ПУСК", + "Play the next shot and continue through this scene": "Відтворити наступний кадр і продовжити цю сцену", + "▶ PLAY SCENE": "▶ ПУСК СЦЕНИ", + "◉ CINEMATIC": "◉ КІНОРЕЖИМ", + "↺ FULL STORY": "↺ УСЯ ІСТОРІЯ", + "↗ OPEN ORIGINAL": "↗ ОРИГІНАЛ", + "⌖ LOWER GORGE": "⌖ НИЖНЯ УЩЕЛИНА", + "FIELD REPORTS · {count}": "ПОВІДОМЛЕННЯ З МІСЦЯ · {count}", + "GEOLOCATIONS · {credit}": "ГЕОЛОКАЦІЇ · {credit}", + "↗ OPEN PUBLIC MAP": "↗ ВІДКРИТИ ПУБЛІЧНУ КАРТУ", + " Clouds are preserved from the source imagery.": " Хмари залишено такими, як на вихідних знімках.", + "Rasuwagadhi witness": "Очевидець у Rasuwagadhi", + "Open original source for {source}; capture time unverified": "Відкрити оригінал: {source}; час зйомки не підтверджено", + "Historical reference and post-event image divider": "Роздільник історичного знімка та знімка після події", + "A historical reference {before} percent, B post-event {after} percent": "A — історичний знімок: {before}%, B — після події: {after}%", + "■ RELEASE CAMERA": "■ ЗВІЛЬНИТИ КАМЕРУ", + "Seek Nepal scene clock": "Перемотування часу сцени в Непалі", + "NEPAL SCENE CLOCK": "ЧАС СЦЕНИ В НЕПАЛІ", + "… PLAYING SHOT": "… ЙДЕ КАДР", + "▶ PLAY SHOT": "▶ ПУСК КАДРУ", + "Ⅱ PAUSE": "Ⅱ ПАУЗА", + "↺ REPLAY CINEMATIC": "↺ ПОВТОРИТИ КІНОРЕЖИМ", + "↺ REPLAY": "↺ ПОВТОРИТИ", + "… PLAYING SCENE": "… ЙДЕ СЦЕНА", + "Continue {scene} from next shot": "Продовжити з наступного кадру: {scene}", + "current scene": "поточна сцена", + "Replay the full reconstruction": "Повторити всю реконструкцію", + "SCENE SHOT": "КАДР СЦЕНИ", + "TIME UNVERIFIED": "ЧАС НЕ ПІДТВЕРДЖЕНО", + "{count} SOURCES": { + "one": "{count} ДЖЕРЕЛО", + "few": "{count} ДЖЕРЕЛА", + "many": "{count} ДЖЕРЕЛ", + "other": "{count} ДЖЕРЕЛА" + }, + "OUTSIDE IMAGERY SWIPE": "ПОЗА ПОРІВНЯННЯМ ЗНІМКІВ", + "{scene} / AUTHORED SHOT": "{scene} / АВТОРСЬКИЙ КАДР", + "NEPAL FLOOD INCIDENT": "ПАВОДОК У НЕПАЛІ", + "Play {shot}": "Відтворити: {shot}", + "current scene shot": "поточний кадр сцени", + "Play reconstruction": "Відтворити реконструкцію", + "Load previous scene shot": "Завантажити попередній кадр сцени", + "Load next scene shot": "Завантажити наступний кадр сцени", + "SCHEMATIC CORRIDOR, NOT MODELED ARRIVAL TIME.": "СХЕМАТИЧНИЙ КОРИДОР, А НЕ МОДЕЛЬ ЧАСУ ДОБІГАННЯ ПАВОДКА.", + "Rasuwa · 26 Aug 2026": "Rasuwa · 26 серп. 2026", + "Event reconstruction": "Реконструкція події", + "BHOTE KOSHI FLOOD INCIDENT": "ПАВОДОК НА BHOTE KOSHI", + "NEPAL · 26 AUG 2026": "НЕПАЛ · 26 СЕРП. 2026", + "USGS INITIAL REPORT": "ПЕРВИННЕ ПОВІДОМЛЕННЯ USGS", + "26 AUG 2026 · 08:37 NPT": "26 СЕРП. 2026 · 08:37 NPT", + "28.2710° N · 85.5150° E": "28,2710° ПН. Ш. · 85,5150° СХ. Д.", + "INITIAL M4.4 · RECLASSIFIED M5.2 LANDSLIDE": "СПОЧАТКУ M4,4 · ПЕРЕКЛАСИФІКОВАНО: ЗСУВ M5,2", + "USGS EVENT us7000tbwb · OPEN SOURCE": "ПОДІЯ USGS us7000tbwb · ВІДКРИТИ ДЖЕРЕЛО", + "Open the USGS initial report for the 26 August 2026 Nepal landslide": "Відкрити первинне повідомлення USGS про зсув у Непалі 26 серпня 2026 року", + "Show the Nepal context callout without a border or country fill": "Показати виноску з контекстом Непалу без кордону та заливки країни", + "Introduce Nepal, draw its border, then reveal the Bhote Koshi incident": "Представити Непал, намалювати його кордон, потім показати подію на Bhote Koshi", + "CITIES": "МІСТА", + "Keep the regional incident context and introduce nearby city labels": "Зберегти регіональний контекст події та додати підписи найближчих міст", + "PLACES": "МІСЦЯ", + "Introduce the reconstruction scene key places from trigger to downstream": "Показати ключові місця сцени реконструкції — від першопричини до пониззя", + "PATH": "ШЛЯХ", + "Animate the sourced cyan river-centerline route to Trishuli Bazaar": "Анімувати блакитний маршрут віссю річки до Trishuli Bazaar за даними джерел", + "OVERVIEW": "ОГЛЯД", + "Keep the completed flood path and location labels visible": "Залишити на екрані весь шлях паводка й підписи місць", + "RECORD": "ЗАПИС", + "Reveal the trigger record while making a slow camera approach": "Показати запис про першопричину під час повільного наближення камери", + "{speed} kn": "{speed} вуз", + "That file is not valid JSON.": "Цей файл — некоректний JSON.", + "That JSON file is not GeoJSON.": "Цей файл JSON не є GeoJSON.", + "That FeatureCollection has no features list.": "У цій FeatureCollection немає списку features.", + "Every GeoJSON feature must have type Feature.": "Кожен обʼєкт GeoJSON повинен мати тип Feature.", + "That GeoJSON has invalid geometries.": "У цьому GeoJSON некоректні геометрії.", + "That GeoJSON contains an unsupported geometry.": "У цьому GeoJSON є непідтримувана геометрія.", + "That GeoJSON has invalid coordinates.": "У цьому GeoJSON некоректні координати.", + "That file creates more than {limit} map objects (the limit).": "Файл створює більше обʼєктів на карті, ніж дозволяє ліміт: {limit}.", + "That file has more than {limit} style definitions and image links after cleanup (the limit).": "Після очищення у файлі більше стилів і посилань на зображення, ніж дозволяє ліміт: {limit}.", + "That file has more than {limit} features (the limit).": "У файлі більше обʼєктів, ніж дозволяє ліміт: {limit}.", + "That file has more than {limit} points (the limit) across {features} features.": "У файлі більше точок, ніж дозволяє ліміт: {limit} (обʼєктів: {features}).", + "That file has more than {limit} points (the limit).": "У файлі більше точок, ніж дозволяє ліміт: {limit}.", + "That KMZ unpacks to more than the import limit.": "Після розпакування цей KMZ перевищує ліміт імпорту.", + "That KMZ is damaged and could not be unpacked.": "Цей KMZ пошкоджений, розпакувати його не вдалося.", + "That KMZ is not a readable zip archive.": "Цей KMZ — не придатний для читання zip-архів.", + "That KMZ uses a zip format this import does not read.": "Цей KMZ використовує формат zip, який імпорт не читає.", + "That KMZ is encrypted.": "Цей KMZ зашифровано.", + "That KMZ uses a compression method this import does not read.": "Цей KMZ використовує метод стиснення, який імпорт не читає.", + "That KML has invalid geometry bounds.": "У цьому KML некоректні межі геометрії.", + "That KML has invalid coordinates.": "У цьому KML некоректні координати.", + "That GPX file has no document.": "У цьому файлі GPX немає документа .", + "That {format} file is not valid XML.": "Цей файл {format} — некоректний XML.", + "That file has an unreadable image or exceeds the 16-megapixel image limit.": "У файлі є непридатне для читання зображення або зображення, більше за ліміт 16 мегапікселів.", + "That KML could not be read.": "Не вдалося прочитати цей KML.", + "That file has invalid point coordinates.": "У файлі некоректні координати точок.", + "Ground heights are not available for that file. Try again when the map has loaded.": "Висоти рельєфу для цього файлу недоступні. Спробуйте ще раз, коли карта завантажиться.", + "That file took too long to read.": "Файл читався надто довго.", + "Nothing to import.": "Немає чого імпортувати.", + "That file is larger than {size} MiB.": "Файл більший за {size} МіБ.", + "Only GeoJSON, KML, KMZ and GPX files can be imported.": "Імпортувати можна лише файли GeoJSON, KML, KMZ і GPX.", + "That file has nothing to draw.": "У файлі немає нічого для показу на карті.", + "That KMZ holds no KML document.": "У цьому KMZ немає документа KML.", + "That {format} file could not be read.": "Не вдалося прочитати цей файл {format}.", + "That file has {count} map objects; the limit is {limit}.": "Обʼєктів на карті у файлі: {count}; ліміт: {limit}.", + "Ground heights could not be read. Try that file again.": "Не вдалося отримати висоти рельєфу. Спробуйте імпортувати файл ще раз.", + "That file has invalid point graphics.": "У файлі некоректне оформлення точок.", "Overpass rate-limited": "Overpass обмежує частоту запитів", - "Overpass timed out": "Перевищено час очікування Overpass", + "Overpass timed out": "Минув час очікування Overpass", "Overpass could not complete the query": "Overpass не зміг завершити запит", + "Map tiles temporarily unavailable": "Тайли карти тимчасово недоступні", + "Mapped names temporarily unavailable": "Назви обʼєктів тимчасово недоступні", "Overpass temporarily unavailable": "Overpass тимчасово недоступний", - "Retrying mapped sites…": "Повторне завантаження нанесених об’єктів…", - "Fetching mapped sites…": "Завантаження нанесених об’єктів…", + "Retrying mapped sites…": "Повторне завантаження нанесених обʼєктів…", + "Fetching mapped sites…": "Завантаження нанесених обʼєктів…", "{reason} — retrying in {seconds}s": "{reason} — повтор через {seconds} с", "{reason} — retry pending": "{reason} — очікується повтор", - "Zoom in to search mapped installations": "Наблизьте карту, щоб шукати нанесені об’єкти", - "Showing cached mapped sites": "Показано кешовані нанесені об’єкти", - "Mapped sites not loaded": "Нанесені об’єкти не завантажено", - "Mapped sites loaded": "Нанесені об’єкти завантажено", - "feed unavailable": "канал даних недоступний", - "feed stale": "канал даних застарів", + "Zoom in to search mapped installations": "Наблизьте карту, щоб шукати нанесені обʼєкти", + "Showing cached mapped sites": "Показано кешовані нанесені обʼєкти", + "Mapped sites not loaded": "Нанесені обʼєкти не завантажено", + "Mapped sites loaded": "Нанесені обʼєкти завантажено", + "Military airfield": "Військовий аеродром", + "Naval base": "Військово-морська база", + "Firing range": "Стрільбище", + "Military land": "Військова територія", + "Mapped installation": "Обʼєкт на карті", + "Military area": "Військова зона", + "flight": "рейс", + "military flight": "військовий рейс", + "satellite": "супутник", + "feed unavailable": "потік даних недоступний", + "feed stale": "потік даних застарів", "observed or mapped nearby context": "спостережений або нанесений контекст поблизу", - "no observed or mapped objects in current feeds": "немає спостережених або нанесених об’єктів у поточних каналах даних", + "no observed or mapped objects in current feeds": "немає спостережених або нанесених обʼєктів у поточних потоках даних", + "Draw": "Малювання", + "Directions": "Маршрути", + "Recent imagery": "Свіжі знімки", "STATION": "СТАНЦІЇ", "Crewed stations and their visiting vehicles": "Пілотовані станції та кораблі відвідування", "NAV": "НАВ", "GNSS navigation — GPS, GLONASS, Galileo": "Навігація GNSS — GPS, GLONASS, Galileo", "GEO": "ГЕО", - "Geostationary belt — comms and weather, fixed over the equator": "Геостаціонарний пояс — зв’язок і погода, нерухомо над екватором", + "Geostationary belt — comms and weather, fixed over the equator": "Геостаціонарний пояс — звʼязок і погода, нерухомо над екватором", "VISUAL": "ВИДИМІ", - "Brightest naked-eye objects — CelesTrak visual group": "Найяскравіші об’єкти для неозброєного ока — група visual CelesTrak", - "COMMS": "ЗВ’ЯЗОК", + "Brightest naked-eye objects — CelesTrak visual group": "Найяскравіші обʼєкти для неозброєного ока — група visual CelesTrak", + "COMMS": "ЗВʼЯЗОК", "Broadband constellation shell — shown only in DENSE mode": "Оболонка широкосмугового угруповання — лише в режимі ЩІЛЬНО", "FISHING": "РИБАЛЬСЬКЕ", "TOWING": "БУКСИРУВАННЯ", - "DREDGER": "ДНОПОГЛИБ.", - "DIVE OPS": "ВОДОЛАЗНІ РОБОТИ", + "DREDGER": "ЗЕМСНАРЯД", + "DIVE OPS": "ВОДОЛАЗНЕ", "MILITARY": "ВІЙСЬКОВЕ", "SAILING": "ВІТРИЛЬНЕ", "PLEASURE": "ПРОГУЛКОВЕ", "PILOT": "ЛОЦМАН", - "SAR": "SAR", + "SAR": "РЯТУВАЛЬНЕ", "TUG": "БУКСИР", "PORT TENDER": "ПОРТОВИЙ КАТЕР", - "ANTI-POLLUTION": "АНТИЗАБРУДНЕННЯ", - "LAW ENFORCE": "ПРАВООХОРОНА", + "ANTI-POLLUTION": "НАФТОЗБИРАЛЬНЕ", + "LAW ENFORCE": "ПАТРУЛЬНЕ", "MEDICAL": "МЕДИЧНЕ", "HIGH-SPEED": "ШВИДКІСНЕ", "PASSENGER": "ПАСАЖИРСЬКЕ", "CARGO": "ВАНТАЖНЕ", "TANKER": "ТАНКЕР", "OTHER": "ІНШЕ", + "Included in bundle": "Входить до архіву", + "Missing bundle file — reimport its bundle": "Файлу немає в архіві — імпортуйте цей архів знову", + "Source configured; file checked when loaded": "Джерело налаштовано; файл буде перевірено під час завантаження", + "Source unavailable": "Джерело недоступне", "ENVIRONMENTAL": "ДОВКІЛЛЯ", "EARTH WATCH": "НАГЛЯД ЗА ЗЕМЛЕЮ", "ACTIVE EVENTS": "АКТИВНІ ПОДІЇ", @@ -65,107 +313,509 @@ "Working…": "Працюємо…", "Could not open that mission{detail}. Retry or explore manually.": "Не вдалося відкрити цю місію{detail}. Повторіть спробу або дослідіть вручну.", "This browser is blocking storage, so that could not be saved.": "Цей браузер блокує сховище, тож зберегти не вдалося.", + "NORMAL": "ЗВИЧАЙНИЙ", "CRT": "CRT", "NVG": "NVG", "FLIR": "FLIR", + "ANIME": "АНІМЕ", + "NOIR": "НУАР", "SNOW": "СНІГ", + "ARCTIC": "АРКТИКА", + "ANTARCTIC": "АНТАРКТИКА", + "NORTH AMERICA": "ПІВНІЧНА АМЕРИКА", + "SOUTH AMERICA": "ПІВДЕННА АМЕРИКА", + "EUROPE": "ЄВРОПА", + "AFRICA": "АФРИКА", + "ASIA": "АЗІЯ", + "OCEANIA": "ОКЕАНІЯ", + "NORTHERN OCEANIC GRID": "ПІВНІЧНА ОКЕАНСЬКА СІТКА", + "SOUTHERN OCEANIC GRID": "ПІВДЕННА ОКЕАНСЬКА СІТКА", "LOADING": "ЗАВАНТАЖЕННЯ", - "DEGRADED": "ДЕГРАД.", + "DEGRADED": "ПЕРЕБОЇ", "STALE": "ЗАСТАРІЛО", + "PARTIAL": "ЧАСТКОВО", "FALLBACK": "РЕЗЕРВ", + "{state} {layers}": "{state}: {layers}", + "view band|STREET": "ВУЛИЦЯ", + "view band|CITY": "МІСТО", + "view band|METRO": "АГЛОМЕРАЦІЯ", + "view band|REGIONAL": "РЕГІОН", + "view band|GLOBAL": "ПЛАНЕТА", "SUMMARY": "ЗВЕДЕННЯ", "Awaiting telemetry...": "Очікування телеметрії...", "REC": "REC", "AIS: --": "AIS: --", + "N/A": "Н/Д", + "{mode} {band} {locality} | {region} | ALT {alt} | WINDOW {window} | SUN {sun}° | ONA {ona}° | {zone}": "{mode} · {band} · {locality} | {region} | ALT {alt} | ВІКНО {window} | SUN {sun}° | ONA {ona}° | {zone}", + "NEAR {poi} ({city}) {distance}": "ПОРУЧ: {poi} ({city}) {distance}", + "SECTOR {lat} {lon}": "СЕКТОР {lat} {lon}", + "hemisphere|N": "Пн", + "hemisphere|S": "Пд", + "hemisphere|E": "Сх", + "hemisphere|W": "Зх", "POWER UP · {count} KEYS WAITING": { - "one": "ЗАПУСК · {count} ключ у черзі", - "few": "ЗАПУСК · {count} ключі в черзі", - "many": "ЗАПУСК · {count} ключів у черзі", - "other": "ЗАПУСК · {count} ключа в черзі" + "one": "ЗАПУСК · {count} КЛЮЧ У ЧЕРЗІ", + "few": "ЗАПУСК · {count} КЛЮЧІ В ЧЕРЗІ", + "many": "ЗАПУСК · {count} КЛЮЧІВ У ЧЕРЗІ", + "other": "ЗАПУСК · {count} КЛЮЧА В ЧЕРЗІ" }, "POWERED UP": "ЗАПУЩЕНО", + "Provider Settings does not answer proxied requests": "«Налаштування постачальників» не відповідають на запити через проксі", + "Provider Settings is disabled while sharing is enabled": "«Налаштування постачальників» вимкнено, доки ввімкнено спільний доступ", + "Provider Settings answers only the machine running the server": "«Налаштування постачальників» відповідають лише компʼютеру, на якому запущено сервер", + "Provider Settings answers only local hostnames": "«Налаштування постачальників» відповідають лише на локальні імена хостів", + "Provider Settings requires an exact local Origin": "«Налаштуванням постачальників» потрібен точний локальний Origin", + "Unrecognized Origin refused": "Нерозпізнаний Origin відхилено", + "Cross-origin requests are refused": "Запити з іншого джерела відхиляються", + "Content-Type must be application/json": "Content-Type має бути application/json", + "Method not allowed": "Метод не дозволено", + "Request too large": "Надто великий запит", + "Invalid JSON": "Некоректний JSON", + "Body must be a JSON object of {ENV_VAR: value}": "Тіло запиту має бути JSON-обʼєктом вигляду {ENV_VAR: value}", + "No keys provided": "Ключі не передано", + "At most {limit} keys per save": "Ключів за одне збереження — не більше {limit}", + "Unknown key: {name}": "Невідомий ключ: {name}", + "{name} must be a string": "{name}: значення має бути рядком", + "{name} is empty": "{name}: порожнє значення", + "{name} is longer than any real key ({limit} max)": "{name}: значення довше за будь-який справжній ключ (максимум {limit})", + "{name} may only contain printable characters with no spaces": "{name}: допустимі лише друковані символи без пробілів", + "{name} contains a character that is not valid in a key (#, quotes, $, \\, or backtick)": "{name}: недопустимий для ключа символ (#, лапки, $, \\ або зворотний апостроф)", + "{name} is configured outside Provider Settings and can only be changed where it was set": "{name}: задано поза «Налаштуваннями постачальників», змінити його можна лише там, де його задали", + "The key was not saved: could not restrict the credential file to your account; nothing was saved": "Ключ не збережено: не вдалося закрити файл облікових даних від усіх, крім вашого облікового запису; нічого не збережено", + "The key was not saved: the existing configuration could not be read, so nothing was changed": "Ключ не збережено: не вдалося прочитати поточну конфігурацію, тому нічого не змінено", + "Could not write the {store} store": "Не вдалося записати сховище {store}", "Save failed ({status}).": "Не вдалося зберегти ({status}).", + "OAuth check failed: {detail}": "Не вдалося перевірити OAuth: {detail}", + "Could not check ChatGPT sign-in. Try again.": "Не вдалося перевірити вхід у ChatGPT. Спробуйте ще раз.", + "VOICE AUTH · CHATGPT OAUTH": "ГОЛОС: АВТОРИЗАЦІЯ · CHATGPT OAUTH", + "VOICE AUTH · API KEY": "ГОЛОС: КЛЮЧ API", + "USE API KEY": "ВИКОРИСТАТИ КЛЮЧ API", + "USE CHATGPT OAUTH": "ВИКОРИСТАТИ CHATGPT OAUTH", + "Use OPENAI_API_KEY for the next cloud voice session": "Використати OPENAI_API_KEY для наступної хмарної голосової сесії", + "Use the signed-in local ChatGPT/Codex OAuth session for the next cloud voice session": "Використати локальну OAuth-сесію ChatGPT/Codex, у яку виконано вхід, для наступної хмарної голосової сесії", + "Metered — a billing-enabled account": "Платний — потрібен обліковий запис з увімкненою оплатою", + "Optional paid token — public access works without one": "Необовʼязковий платний токен — публічний доступ працює без нього", + "Free key — register, paste, done": "Безкоштовний ключ — зареєструйтеся, вставте, готово", + "browser-side": "у браузері", + "This key runs in the browser by design — restrict it at the provider (see SECURITY.md)": "Цей ключ за задумом працює в браузері — обмежте його в постачальника (див. SECURITY.md)", + "configured externally": "задано ззовні", + "Supplied by your environment, Keychain, or launcher — change it where it was set": "Задано середовищем, Keychain або лаунчером — змінюйте його там, де його задано", + "MANAGE ↗": "КЕРУВАТИ ↗", + "GET KEY ↗": "ОТРИМАТИ КЛЮЧ ↗", + "{envVar} saved — paste to replace": "{envVar} збережено — вставте, щоб замінити", + "paste {envVar}": "вставте {envVar}", "REMOVE": "ВИДАЛИТИ", - "Remove {title} from this app's saved keys": "Видалити {title} із збережених ключів застосунку", + "Remove {title} from this app's saved keys": "Видалити {title} зі збережених ключів застосунку", + "unsaved provider keys": "незбережені ключі постачальників", + "Project keys: {status}": "Ключі проєкту: {status}", "your app configuration": "вашої конфігурації застосунку", "your local .env": "вашого локального .env", "Saving…": "Збереження…", "Save failed: {detail}": "Не вдалося зберегти: {detail}", "Paste at least one key first.": "Спочатку вставте принаймні один ключ.", - "Saved to {store}. Restarting — this page reloads itself.": "Збережено до {store}. Перезапуск — сторінка перезавантажиться сама.", + "Saved to {store}. Restarting — this page reloads itself.": "Збережено в {store}. Перезапуск — сторінка перезавантажиться сама.", + "Cloud voice will use OPENAI_API_KEY on the next session.": "Наступна хмарна голосова сесія використовуватиме OPENAI_API_KEY.", + "Checking local ChatGPT OAuth sign-in…": "Перевірка локального входу в ChatGPT через OAuth…", + "Could not check ChatGPT sign-in.": "Не вдалося перевірити вхід у ChatGPT.", + "ChatGPT OAuth selected for cloud voice. Your API key stays saved and available.": "Для хмарного голосу вибрано ChatGPT OAuth. Ваш ключ API залишається збереженим і доступним.", + "ChatGPT sign-in expired. Opening sign-in again…": "Сеанс ChatGPT завершився. Знову відкриваємо вхід…", + "Opening ChatGPT sign-in in your browser…": "Відкриваємо вхід у ChatGPT у браузері…", + "Could not start ChatGPT sign-in on this machine.": "Не вдалося почати вхід у ChatGPT на цьому компʼютері.", + "Finish ChatGPT sign-in in the browser. Waiting for it to complete…": "Завершіть вхід у ChatGPT у браузері. Очікування завершення…", + "ChatGPT sign-in timed out. Click {button} to try again.": "Час на вхід у ChatGPT минув. Натисніть «{button}», щоб спробувати ще раз.", + "ChatGPT sign-in complete. OAuth will be used for the next cloud voice session.": "Вхід у ChatGPT виконано. У наступній хмарній голосовій сесії використовуватиметься OAuth.", "Remove this key from your saved configuration?": "Видалити цей ключ із вашої збереженої конфігурації?", "Removed from {store}. Restarting — this page reloads itself.": "Видалено з {store}. Перезапуск — сторінка перезавантажиться сама.", - "Places context + Street View fallback; optional separate key": "Контекст Places + резервний Street View; окремий ключ за бажанням", + "The photorealistic 3D planet, place search + Street View": "Фотореалістична 3D-планета, пошук місць + Перегляд вулиць", + "Places context + Street View fallback; optional separate key": "Контекст Places + резерв: Перегляд вулиць; окремий ключ — за бажанням", + "Voice control — API key or ChatGPT OAuth": "Голосове керування — ключ API або ChatGPT OAuth", + "Gemini Live voice control": "Голосове керування через Gemini Live", "Live ships, worldwide": "Судна в реальному часі по всьому світу", "Live active-fire detections": "Виявлення активних пожеж у реальному часі", - "Real live traffic (keyless runs a simulation)": "Справжній трафік у реальному часі (без ключа — симуляція)", - "Bing imagery map stacks + world terrain": "Стеки карт Bing imagery + світовий рельєф", - "More flight-polling credits (anonymous works without)": "Більше кредитів опитування польотів (працює й анонімно)", + "Real live traffic (keyless runs a simulation)": "Справжні затори в реальному часі (без ключа — імітація)", + "Bing imagery map stacks + world terrain": "Знімки Bing + рельєф світу", + "More flight-polling credits (anonymous works without)": "Вищий ліміт запитів рейсів (анонімно працює й без ключа)", + "Street-level imagery and coverage in the Street Level layer. Free: register an app in the Mapillary developer dashboard and paste its Client Token": "Вуличні знімки й покриття в шарі «Вуличні знімки». Безкоштовно: зареєструйте застосунок у панелі розробника Mapillary і вставте його клієнтський токен (Client Token)", + "Public space-missions access needs no key. Leave blank for standard use; paid tokens only raise request limits.": "Загальнодоступні дані космічних місій не потребують ключа. Для звичайного використання залиште поле порожнім; платні токени лише підвищують ліміти запитів.", + "Air quality request failed": "Не вдалося запитати дані про якість повітря", + "No readings available": "Немає доступних показів", + "No current readings": "Немає актуальних показів", + "{count} stations reporting": { + "one": "{count} станція передає дані", + "few": "{count} станції передають дані", + "many": "{count} станцій передають дані", + "other": "{count} станції передають дані" + }, + "Highest air-quality readings in view": "Найвищі показники якості повітря в полі зору", + "Low": "Низький", + "Low health risk": "Низький ризик для здоровʼя", + "Moderate": "Помірний", + "Moderate health risk": "Помірний ризик для здоровʼя", + "High": "Високий", + "High health risk": "Високий ризик для здоровʼя", + "Very High": "Дуже високий", + "Very High health risk": "Дуже високий ризик для здоровʼя", + "Air quality": "Якість повітря", + "Canada only · ECCC AQHI network": "Лише Канада · мережа AQHI ECCC", + "ECCC request timed out": "Минув час очікування запиту до ECCC", + "Malformed AQHI station response": "Некоректна відповідь зі станціями AQHI", + "No AQHI stations available": "Немає доступних станцій AQHI", + "Malformed AQHI observation response": "Некоректна відповідь зі спостереженнями AQHI", + "Camera source temporarily unavailable": "Джерело камер тимчасово недоступне", + "Mapped camera locations": "Розташування камер на карті", + "SHOW NEAREST": "ПОКАЗАТИ НАЙБЛИЖЧУ", + "Stop following the current object before navigating to a camera": "Припиніть стежити за поточним обʼєктом, перш ніж переходити до камери", + "Move to the nearest loaded camera and show its details": "Перейти до найближчої завантаженої камери й показати її дані", + "Camera badges": "Значки камер", + "Cyan cameras turn coral when selected. Wedges illustrate mapped direction, not measured coverage. Nearby cameras may be outside the screen.": "Блакитні камери після вибору стають кораловими. Сектори показують напрямок за картою, а не виміряне покриття. Найближчі камери можуть бути за межами екрана.", + "{count} nearby · {onScreen} on screen": { + "one": "поруч: {count} · на екрані: {onScreen}", + "few": "поруч: {count} · на екрані: {onScreen}", + "many": "поруч: {count} · на екрані: {onScreen}", + "other": "поруч: {count} · на екрані: {onScreen}" + }, + "{count} nearby": { + "one": "поруч: {count}", + "few": "поруч: {count}", + "many": "поруч: {count}", + "other": "поруч: {count}" + }, + "retrying mapped ALPR cameras": "повторне завантаження камер ALPR", + "loading mapped ALPR cameras": "завантаження камер ALPR", + "No ALPR data for this area — US and Canada only": "Немає даних ALPR для цієї області — лише США й Канада", + "Zoom in to load mapped cameras": "Наблизьте карту, щоб завантажити камери", + "Showing cached locations": "Показано місця з кешу", + "Coverage limited — zoom in": "Покриття обмежене — наблизьте карту", + "No ALPR data for this area": "Немає даних ALPR для цієї області", + "None on screen — nearby cameras are outside the view": "На екрані немає — найближчі камери поза полем зору", + "ALPR camera": "Камера ALPR", + "Camera coverage unavailable": "Покриття камер недоступне", + "OpenStreetMap · community mapped": "OpenStreetMap · дані спільноти", + "Overpass returned an incomplete camera response": "Overpass повернув неповну відповідь про камери", + "At least {count}": "Щонайменше {count}", "CONTEXT READY": "КОНТЕКСТ ГОТОВИЙ", "GLOBAL CONTEXT OFF": "ГЛОБАЛЬНИЙ КОНТЕКСТ ВИМК.", - "SELECT A FLIGHT, VESSEL, OR MAPPED INSTALLATION": "ВИБЕРІТЬ ЛІТАК, СУДНО ЧИ НАНЕСЕНИЙ ОБ’ЄКТ", - "ENABLE TO LOAD OBSERVED / MAPPED PROXIMITY": "УВІМКНІТЬ ДЛЯ ЗАВАНТАЖЕННЯ СПОСТЕРЕЖЕНОЇ / НАНЕСЕНОЇ ОКРУГИ", + "SELECT A FLIGHT, VESSEL, OR MAPPED INSTALLATION": "ВИБЕРІТЬ ЛІТАК, СУДНО ЧИ НАНЕСЕНИЙ ОБʼЄКТ", + "ENABLE TO LOAD OBSERVED / MAPPED PROXIMITY": "УВІМКНІТЬ, ЩОБ ЗАВАНТАЖИТИ СПОСТЕРЕЖЕНЕ / НАНЕСЕНЕ ПОБЛИЗУ", "Unavailable": "Недоступно", "Focus {label}": "Фокус: {label}", "Global Context navigation": "Навігація глобального контексту", - "Previous — prior visited contact in the 250 km window": "Попередня — вже відвідана ціль у вікні 250 км", - "PREVIOUS": "ПОПЕРЕДНЯ", + "Previous — prior visited contact in the 250 km window": "Назад — попередній відвіданий контакт у вікні 250 км", + "PREVIOUS": "НАЗАД", "FOCUS": "ФОКУС", - "Next — nearest unvisited contact in the 250 km window": "Наступна — найближча невідвідана ціль у вікні 250 км", + "Next — nearest unvisited contact in the 250 km window": "Далі — найближчий невідвіданий контакт у вікні 250 км", "NEXT": "ДАЛІ", - "Open-source mapped/observed context. Missing broadcasts, unloaded map areas, or unmapped sites are not evidence of absence.": "Контекст із відкритих джерел (нанесений/спостережений). Відсутність трансляцій, незавантажені ділянки карти або ненанесені об’єкти не є доказом відсутності.", - "HDG {value}°": "HDG {value}°", - "BRG {value}°": "BRG {value}°", - "BRG —": "BRG —", - "CRS {value}°": "CRS {value}°", + "Named areas ({n})": "Іменовані зони ({n})", + "{distance} FLIGHT / VESSEL WINDOW": "РАДІУС РЕЙСІВ / СУДЕН {distance}", + "Open-source mapped/observed context. Missing broadcasts, unloaded map areas, or unmapped sites are not evidence of absence.": "Контекст із відкритих джерел (нанесений/спостережений). Відсутність трансляцій, незавантажені ділянки карти або ненанесені обʼєкти не є доказом відсутності.", + "mapped matches within {km} km of the subject": "збіги на карті в радіусі {km} км від обʼєкта", + "none mapped within {km} km; not a complete 250 km survey": "на карті немає в радіусі {km} км; це не повний огляд на 250 км", + "mapped matches from the loaded viewport": "збіги на карті в завантаженій області", + "viewport feed is not a complete 250 km survey": "дані видимої області — не повний огляд на 250 км", + "HDG {value}°": "КУРС {value}°", + "BRG {value}°": "ПЕЛ. {value}°", + "BRG —": "ПЕЛ. —", + "CRS {value}°": "ШЛЯХ {value}°", "CURRENT VIEWPORT ONLY": "ЛИШЕ ПОТОЧНА ОБЛАСТЬ ОГЛЯДУ", - "Flights": "Літаки", - "Military flights": "Військова авіація", + "WITHIN {km} KM": "У РАДІУСІ {km} КМ", + "Flights": "Рейси", + "Military flights": "Військові рейси", "AIS vessels": "Судна AIS", - "Mapped installations": "Нанесені об’єкти", - "syncing {count} city feeds...": "синхронізація каналів даних {count} міст...", + "Mapped installations": "Нанесені обʼєкти", + "syncing {count} city feeds...": "синхронізація міських потоків: {count}...", "scanning nearby systems...": "пошук ближніх систем...", + "GBFS fetch error": "помилка завантаження GBFS", "Station {id}": "Станція {id}", "Station": "Станція", - "🚲 {bikes} avail · {docks} docks · {capacity} cap": "🚲 {bikes} вільно · {docks} доків · {capacity} містк.", + "🚲 {bikes} avail · {docks} docks · {capacity} cap": "🚲 вільно {bikes} · місць {docks} · містк. {capacity}", "⚠️ Not installed": "⚠️ Не встановлено", "⚠️ Not renting": "⚠️ Не видає", "⚠️ Not returning": "⚠️ Не приймає", - "{count} CAMERAS STANDING BY · NO CAMERA SELECTED · CLICK A CAMERA TO ACTIVATE": "{count} КАМЕР ОЧІКУЄ · КАМЕРУ НЕ ВИБРАНО · КЛАЦНІТЬ КАМЕРУ ДЛЯ АКТИВАЦІЇ", + "HDG {value}° (ESTIMATED)": "КУРС {value}° (ОЦІНКА)", + "{count} CAMERAS STANDING BY · NO CAMERA SELECTED · CLICK A CAMERA TO ACTIVATE": "КАМЕР У ГОТОВНОСТІ: {count} · КАМЕРУ НЕ ВИБРАНО · КЛАЦНІТЬ КАМЕРУ ДЛЯ АКТИВАЦІЇ", "No cameras available in catalog.": "У каталозі немає доступних камер.", "{city} CCTV": "CCTV: {city}", - "FOV {value}°": "FOV {value}°", - "COVERAGE {value}km²": "ЗОНА ОГЛЯДУ {value}km²", + "FOV {value}° (DATASHEET)": "ОГЛЯД {value}° (ЗА ПАСПОРТОМ)", + "FOV {value}°": "ОГЛЯД {value}°", + "SPEC FOV {span}° (CAPABILITY)": "ОГЛЯД ЗА ПАСПОРТОМ {span}° (МОЖЛИВОСТІ)", + "COVERAGE {value}km²": "ОХОПЛЕННЯ {value} КМ²", "OVERLAP {count} cams": "ПЕРЕКРИТТЯ {count} КАМ.", "ISOLATED VIEW": "ОКРЕМИЙ ВИГЛЯД", "PROJ MONITOR": "ПРОЄКЦ. МОНІТОР", "PROJ OFF": "ПРОЄКЦ. ВИМК.", "VIEWSHED": "ЗОНА ВИДИМОСТІ", - "CAL {value}": "КАЛ. {value}", + "CAL {value}": "КАЛІБР. {value}", "SRC {value}": "ДЖЕР. {value}", "{value} CONTEXT": "{value} КОНТЕКСТ", + "{spec} · SPECS: CCTV-DATABASE.COM": "{spec} · ХАРАКТЕРИСТИКИ: CCTV-DATABASE.COM", + "Atlantic and eastern/central North Pacific; not worldwide cyclone coverage.": "Атлантика та східна/центральна частина північного Тихого океану; покриття циклонів не глобальне.", + "Cyclone advisories unavailable": "Зведення про циклони недоступні", + "Cyclone data unavailable": "Дані про циклони недоступні", + "Potential tropical cyclone": "Потенційний тропічний циклон", + "Post-tropical cyclone": "Посттропічний циклон", + "Hurricane": "Ураган", + "Tropical storm": "Тропічний шторм", + "Tropical depression": "Тропічна депресія", + "Subtropical storm": "Субтропічний шторм", + "Subtropical depression": "Субтропічна депресія", + "Track and cone match this advisory": "Трек і конус відповідають цьому зведенню", + "Track/cone awaiting advisory {number}": "Трек і конус зʼявляться зі зведенням № {number}", + "Track/cone unavailable": "Трек/конус недоступні", + "Cached advisory · stale source": "Зведення з кешу · джерело застаріло", + "Loading advisories…": "Завантаження зведень…", + "{count} active storms": { + "one": "{count} активний шторм", + "few": "{count} активні шторми", + "many": "{count} активних штормів", + "other": "{count} активного шторму" + }, + "Position as of {time}": "Положення на {time}", + "Maximum sustained wind: {wind} · Pressure: {pressure}": "Макс. стійкий вітер: {wind} · Тиск: {pressure}", + "{name} · {classification} · Advisory {number} · issued {time}": "{name} · {classification} · Зведення № {number} · випущено {time}", + "No active NHC/CPHC systems": "Немає активних систем NHC/CPHC", + "Advisories unavailable": "Зведення недоступні", + "Cyclones · NHC / CPHC": "Циклони · NHC / CPHC", + "Atlantic · E/C Pacific": "Атлантика · сх./центр. Тихий океан", + "{storms} · {name} selected": "{storms} · вибрано {name}", + "Official advisory ↗": "Офіційне зведення ↗", + "Active NHC and CPHC cyclone advisories": "Чинні зведення NHC і CPHC про циклони", + "Wind unavailable": "Вітер: немає даних", + "Advisory center / forecast track": "Центр циклону за зведенням / прогнозний трек", + "Center-track uncertainty cone": "Конус невизначеності треку центру", + "Select a storm on the map, or choose a storm in the list to select it and move the camera. Click empty map space to clear the selection. NOAA NHC/CPHC advisory context. The cone describes forecast center-track uncertainty, not storm size or the full hazard area. Forecast point labels are source lead hours, not times computed from advisory issuance. Geometry follows the surface; height is not weather altitude. Consult the official advisory.": "Виберіть шторм на карті або в списку, щоб виділити його й перемістити до нього камеру. Клацніть на порожньому місці карти, щоб зняти виділення. Контекст зведень NOAA NHC/CPHC. Конус описує невизначеність прогнозного треку центру, а не розмір шторму чи всю зону небезпеки. Підписи прогнозних точок — завчасність джерела в годинах, а не час, розрахований від випуску зведення. Геометрія повторює поверхню; висота не відображає висоту погодних явищ. Звіряйтеся з офіційним зведенням.", + "DRIVE": "АВТО", + "Drive": "Автомобілем", + "WALK": "ПІШКИ", + "Walk": "Пішки", + "BIKE": "ВЕЛО", + "Bike": "Велосипедом", + "rate limited": "перевищено ліміт запитів", + "routing service is rate limited": "сервіс маршрутизації перевищив ліміт запитів", + "route leg too long": "ділянка маршруту надто довга", + "route too long": "маршрут надто довгий", + "{error} — try again in a moment": "{error} — спробуйте ще раз трохи згодом", + "Routing is rate limited — try again in a moment": "Побудова маршруту: перевищено ліміт запитів — спробуйте ще раз трохи згодом", + "Routing unavailable (HTTP {status})": "Побудова маршруту недоступна (HTTP {status})", + "Routing unavailable": "Побудова маршруту недоступна", + "direction|left": "ліворуч", + "direction|right": "праворуч", + "direction|slightly left": "плавно ліворуч", + "direction|slightly right": "плавно праворуч", + "direction|sharply left": "різко ліворуч", + "direction|sharply right": "різко праворуч", + "direction|straight": "прямо", + "direction|around": "у зворотному напрямку", + "fork direction|left": "лівіше", + "fork direction|right": "правіше", + "fork direction|slightly left": "трохи лівіше", + "fork direction|slightly right": "трохи правіше", + "fork direction|sharply left": "лівіше", + "fork direction|sharply right": "правіше", + "fork direction|straight": "прямо", + "lane direction|left": "ліву", + "lane direction|right": "праву", + "lane direction|slightly left": "ліву", + "lane direction|slightly right": "праву", + "lane direction|sharply left": "крайню ліву", + "lane direction|sharply right": "крайню праву", + "lane direction|straight": "середню", + "ordinal|{number}st": "{number}-й", + "ordinal|{number}nd": "{number}-й", + "ordinal|{number}rd": "{number}-й", + "ordinal|{number}th": "{number}-й", + "Head out on {road}": "Почніть рух дорогою {road}", + "Head out": "Почніть рух", + "Arrive at your destination, on the left": "Пункт призначення ліворуч", + "Arrive at your destination, on the right": "Пункт призначення праворуч", + "Arrive at your destination": "Ви прибули до пункту призначення", + "Make a U-turn onto {road}": "Розверніться на {road}", + "Make a U-turn": "Розверніться", + "Continue straight onto {road}": "Продовжуйте рух прямо на {road}", + "Continue straight": "Продовжуйте рух прямо", + "Turn {direction} onto {road}": "Поверніть {direction} на {road}", + "Turn {direction}": "Поверніть {direction}", + "Turn onto {road}": "Поверніть на {road}", + "maneuver|Turn": "Поверніть", + "Continue {direction} onto {road}": "Продовжуйте рух {direction} на {road}", + "Continue {direction}": "Продовжуйте рух {direction}", + "At the end of the road, turn {direction} onto {road}": "Наприкінці дороги поверніть {direction} на {road}", + "At the end of the road, turn {direction}": "Наприкінці дороги поверніть {direction}", + "At the end of the road, continue onto {road}": "Наприкінці дороги продовжуйте рух на {road}", + "At the end of the road, continue": "Наприкінці дороги продовжуйте рух", + "Keep {direction} at the fork onto {road}": "На розвилці тримайтеся {direction}, щоб виїхати на {road}", + "Keep {direction} at the fork": "На розвилці тримайтеся {direction}", + "Continue at the fork onto {road}": "На розвилці продовжуйте рух на {road}", + "Continue at the fork": "На розвилці продовжуйте рух", + "Merge {direction} onto {road}": "Перешикуйтеся {direction} на {road}", + "Merge {direction}": "Перешикуйтеся {direction}", + "Merge onto {road}": "Виїжджайте на {road}", + "maneuver|Merge": "Перешикуйтеся", + "Take the ramp on the {direction} onto {road}": "Зʼїжджайте {direction} на {road}", + "Take the ramp on the {direction}": "Зʼїжджайте {direction}", + "Take the ramp {direction} onto {road}": "Зʼїжджайте {direction} на {road}", + "Take the ramp {direction}": "Зʼїжджайте {direction}", + "Take the ramp onto {road}": "Скористайтеся зʼїздом на {road}", + "Take the ramp": "Скористайтеся зʼїздом", + "Take the exit on the {direction} onto {road}": "Поверніть на зʼїзд {direction} на {road}", + "Take the exit on the {direction}": "Поверніть на зʼїзд {direction}", + "Take the exit {direction} onto {road}": "Поверніть на зʼїзд {direction} на {road}", + "Take the exit {direction}": "Поверніть на зʼїзд {direction}", + "Take the exit onto {road}": "Поверніть на зʼїзд на {road}", + "Take the exit": "Поверніть на зʼїзд", + "At the roundabout, take the {exit} exit onto {road}": "На колі поверніть на {exit} зʼїзд на {road}", + "At the roundabout, take the {exit} exit": "На колі поверніть на {exit} зʼїзд", + "Enter the roundabout onto {road}": "Вʼїжджайте на коло, виїзд на {road}", + "Enter the roundabout": "Вʼїжджайте на коло", + "At the roundabout, turn {direction} onto {road}": "На колі поверніть {direction} на {road}", + "At the roundabout, turn {direction}": "На колі поверніть {direction}", + "At the roundabout, continue onto {road}": "На колі продовжуйте рух на {road}", + "At the roundabout, continue": "На колі продовжуйте рух", + "Exit the roundabout onto {road}": "Зʼїжджайте з кола на {road}", + "Exit the roundabout": "Зʼїжджайте з кола", + "Use the {direction} lane onto {road}": "Займіть {direction} смугу, щоб виїхати на {road}", + "Use the {direction} lane": "Займіть {direction} смугу", + "Continue onto {road}": "Продовжуйте рух на {road}", + "maneuver|Continue": "Продовжуйте рух", + "{mode} — reroute for {modeLower}": "{mode} — перебудувати маршрут: {modeLower}", + "CLICK MAP": "КЛАЦНІТЬ НА КАРТІ", + "SET A": "ЗАДАТИ A", + "Click a spot on the globe to place A (click again to cancel)": "Клацніть точку на глобусі, щоб поставити A (повторне клацання — скасування)", + "Then click the globe to place the start": "Потім клацніть на глобусі, щоб поставити початок", + "SET B": "ЗАДАТИ B", + "Click a spot on the globe to place B (click again to cancel)": "Клацніть точку на глобусі, щоб поставити B (повторне клацання — скасування)", + "Then click the globe to place the destination": "Потім клацніть на глобусі, щоб поставити пункт призначення", + "Swap A and B": "Поміняти A і B місцями", + "FLY ···": "ПОЛІТ ···", + "FLYING": "У ПОЛЬОТІ", + "FLY": "ПОЛІТ", + "Fly the camera along the route": "Пролетіти камерою маршрутом", + "Place A and B first": "Спершу поставте A і B", + "action|CLEAR": "СКИНУТИ", + "Remove the route and both markers": "Видалити маршрут і обидві мітки", + "press Escape twice to leave Draw": "двічі натисніть Esc, щоб вийти з режиму «Малювання»", + "{name} is active — turn {name} off, then set {endpoint}": "Активно: {name} — вимкніть {name}, потім задайте {endpoint}", + "{name} is active — {leave}, then set {endpoint}": "Активно: {name} — {leave}, потім задайте {endpoint}", + "Only the first {count} turns of this route are shown": "Показано лише перші повороти маршруту: {count}", + "Turn-by-turn directions": "Покрокові вказівки", + "Another map tool is using clicks — close it, then SET A again": "Клацання перехоплює інший інструмент карти — закрийте його й знову натисніть «ЗАДАТИ A»", + "Routing…": "Побудова маршруту…", + "No route found": "Маршрут не знайдено", + "{distance} · {duration} · {mode} · first {count} turns": "{distance} · {duration} · {mode} · перші повороти: {count}", + "{distance} · {duration} · {mode}": "{distance} · {duration} · {mode}", + "Click the globe to place {endpoint}": "Клацніть на глобусі, щоб поставити {endpoint}", + "SET B, then click the globe": "Натисніть «ЗАДАТИ B», потім клацніть на глобусі", + "SET A, then click the globe": "Натисніть «ЗАДАТИ A», потім клацніть на глобусі", + "Step {step} of {total} · then {leg}": "Крок {step} з {total} · потім {leg}", + "Step {step} of {total}": "Крок {step} з {total}", + "Then: {instruction}": "Потім: {instruction}", + "No route found between A and B": "Маршрут між A і B не знайдено", + "Routing failed: {error}": "Не вдалося побудувати маршрут: {error}", + "Routing timed out": "Минув час побудови маршруту", + "Routing unavailable — no response from the routing service": "Побудова маршруту недоступна — сервіс маршрутизації не відповідає", + "Earthquake source unavailable": "Джерело даних про землетруси недоступне", "Focus fire detection {title}, {details}": "Фокус на виявленні пожежі {title}, {details}", - "{value} conf": "{value} впевн.", + "live feed unavailable": "потік даних у реальному часі недоступний", + "{value} conf": "впевн.: {value}", "{value} ago": "{value} тому", "sensor n/a": "датчик н/д", - "FIRE · {frp} MW": "ПОЖЕЖА · {frp} MW", + "FIRE · {frp} MW": "ПОЖЕЖА · {frp} МВт", "NIGHT": "НІЧ", - "▲ {frp} MW": "▲ {frp} MW", + "▲ {frp} MW": "▲ {frp} МВт", "FIRE": "ПОЖЕЖА", "FIRES": "ПОЖЕЖІ", - "max {value} MW": "макс {value} MW", + "max {value} MW": "макс. {value} МВт", "new {value}": "нова {value}", + "{value}°N": "{value}° пн. ш.", + "{value}°S": "{value}° пд. ш.", + "{value}°E": "{value}° сх. д.", + "{value}°W": "{value}° зх. д.", "just now": "щойно", "<1m ago": "<1 хв тому", "{count}m ago": "{count} хв тому", "{count}h ago": "{count} год тому", + "fire confidence|high": "висока", + "fire confidence|nominal": "середня", + "fire confidence|low": "низька", + "age|<1h": "<1 год", + "age|{count}h": "{count} год", + "age|{count}d": "{count} дн", "STALE · cached {age}": "ЗАСТАРІЛО · кешовано {age}", "refreshing...": "оновлення...", "loading...": "завантаження...", "KEY REQUIRED": "ПОТРІБЕН КЛЮЧ", - "LIVE · updated {age}": "У РЕАЛЬНОМУ ЧАСІ · оновлено {age}", - "loading mapped installation context": "завантаження контексту нанесених об’єктів", - "MAPPED INSTALLATION": "НАНЕСЕНИЙ ОБ’ЄКТ", + "LIVE · updated {age}": "ОНЛАЙН · оновлено {age}", + "Source snapshot time unavailable": "Час знімка джерела невідомий", + "Live data unavailable": "Дані в реальному часі недоступні", + "Intel Picture": "Розвідкартина", + "Kinetic 30d": "Бойові 30 дн", + "Border Crisis": "Криза на кордоні", + "Iran Picture": "Іран: картина", + "Iran Kinetic": "Іран: бойові", + "Yemen FLOT": "Ємен: лінія фронту", + "Latest Drop": "Новий випуск", + "GhostMaps file could not be read": "Не вдалося прочитати файл GhostMaps", + "{count} source links ↗ · click card to open the first": { + "one": "{count} посилання на джерело ↗ · клацніть картку, щоб відкрити", + "few": "{count} посилання на джерела ↗ · клацніть картку, щоб відкрити перше", + "many": "{count} посилань на джерела ↗ · клацніть картку, щоб відкрити перше", + "other": "{count} посилання на джерела ↗ · клацніть картку, щоб відкрити перше" + }, + "S2 · {name}": "S2 · {name}", + "Report": "Зведення", + "Open the source for {title}": "Відкрити джерело: {title}", + "GhostMaps catalog unavailable": "Каталог GhostMaps недоступний", + "LIVE · GitHub {commit} · {message} · checked every {seconds}s": "ОНЛАЙН · GitHub {commit} · {message} · перевірка кожні {seconds} с", + "GitHub {commit} · {message} · reconnecting for live updates": "GitHub {commit} · {message} · повторне підключення для оновлень у реальному часі", + "Connecting to the S2 GhostMaps repository…": "Підключення до репозиторію S2 GhostMaps…", + "{count} placemarks": { + "one": "{count} мітка", + "few": "{count} мітки", + "many": "{count} міток", + "other": "{count} мітки" + }, + "S2 Underground publishes these KMZ products to GitHub. New uploads are detected within seconds and replace the previous edition automatically. Click a marker for its report.": "S2 Underground публікує ці продукти KMZ на GitHub. Нові файли виявляються за лічені секунди й автоматично замінюють попередній випуск. Клацніть мітку, щоб відкрити її зведення.", + "Malformed GhostMaps catalog": "Пошкоджений каталог GhostMaps", + "Low-accuracy score < 2%": "Частка неточних < 2%", + "Low-accuracy score 2–10%": "Частка неточних 2–10%", + "Low-accuracy score > 10%": "Частка неточних > 10%", + "GNSS integrity source unavailable": "Джерело цілісності GNSS недоступне", + "Regional sample · 250 nm radius · cells from visited views over 30 min": "Регіональна вибірка · радіус 250 мор. миль · комірки з переглянутих видів за 30 хв", + "Retrying automatically at {time} UTC": "Автоматичний повтор о {time} UTC", + "Retrying automatically after provider cooldown": "Автоматичний повтор після паузи постачальника", + "Updates automatically after pan or zoom and once a minute. The public feed covers a 250-nautical-mile circle around the view centre; zooming out does not make it a worldwide snapshot. Blank cells are outside sampled coverage or have insufficient observations.": "Оновлюється автоматично після зсуву чи масштабування карти та раз на хвилину. Публічний потік даних охоплює коло радіусом 250 морських миль навколо центру вигляду; у разі віддалення карта не стає знімком усього світу. Порожні комірки — поза охопленням вибірки або з недостатньою кількістю спостережень.", + "Low-accuracy score = 100 × max(0, bad − 1) / total: one aircraft is discounted, so this is not the raw share. Cells need {aircraft} aircraft over {minutes} minutes. Navigation-integrity anomalies are not a detection of jamming or spoofing.": "Частка неточних = 100 × max(0, неточні − 1) / усього: один літак не враховується, тож це не пряма частка. Для комірки потрібно літаків: {aircraft} за {minutes} хв. Аномалії цілісності навігації — не виявлення глушіння чи підміни сигналу.", + "GNSS snapshot needs a view anchor": "Для знімка GNSS потрібна опорна точка вигляду", + "GNSS feed rate limited (HTTP 429)": "Потік GNSS: перевищено ліміт запитів (HTTP 429)", + "Malformed GNSS integrity snapshot": "Некоректний знімок цілісності GNSS", + "GNSS integrity snapshot has no observation time": "У знімку цілісності GNSS немає часу спостереження", + "installation class|AIRFIELD": "АЕРОДРОМ", + "installation class|NAVAL BASE": "ВІЙСЬКОВО-МОРСЬКА БАЗА", + "installation class|RANGE": "ПОЛІГОН", + "installation class|MILITARY LAND": "ВІЙСЬКОВА ТЕРИТОРІЯ", + "installation class|BASE": "БАЗА", + "installation class|BARRACKS": "КАЗАРМИ", + "installation class|TRAINING AREA": "НАВЧАЛЬНИЙ ПОЛІГОН", + "installation class|PLACES CANDIDATE": "З GOOGLE PLACES", + "installation class|INSTALLATION": "ОБʼЄКТ", + "No mapped sites within {km} km of the contact": "Немає обʼєктів у радіусі {km} км від контакту", + "{count} mapped sites within {km} km of the contact": { + "one": "{count} обʼєкт у радіусі {km} км від контакту", + "few": "{count} обʼєкти в радіусі {km} км від контакту", + "many": "{count} обʼєктів у радіусі {km} км від контакту", + "other": "{count} обʼєкта в радіусі {km} км від контакту" + }, + "No mapped sites in view": "У кадрі немає обʼєктів", + "{count} mapped sites in view": { + "one": "{count} обʼєкт у кадрі", + "few": "{count} обʼєкти в кадрі", + "many": "{count} обʼєктів у кадрі", + "other": "{count} обʼєкта в кадрі" + }, + "loading mapped installation context": "завантаження контексту нанесених обʼєктів", + "Too many mapped sites in view to list them all": "У кадрі забагато обʼєктів, щоб перелічити всі", + "Installation context unavailable": "Контекст обʼєктів недоступний", + "MAPPED INSTALLATION": "НАНЕСЕНИЙ ОБʼЄКТ", + "Unknown": "Невідомо", "LAUNCH SITE · {site}": "МІСЦЕ ЗАПУСКУ · {site}", "LAUNCH SITE": "МІСЦЕ ЗАПУСКУ", "T−{time} · {mission}": "T−{time} · {mission}", @@ -179,22 +829,30 @@ "UNSPECIFIED": "НЕ ВКАЗАНО", "+{count} additional payload records": "+{count} додаткових записів корисного навантаження", "PAYLOAD DATA UNAVAILABLE": "ДАНІ КОРИСНОГО НАВАНТАЖЕННЯ НЕДОСТУПНІ", - "{value} KM DOWNRANGE": "{value} KM ПО ТРАЄКТОРІЇ", + "{value} KM DOWNRANGE": "{value} КМ УЗДОВЖ ТРАСИ", "POSITION UNAVAILABLE": "ПОЗИЦІЯ НЕДОСТУПНА", "FLIGHT {count}": "РЕЙС {count}", "REUSED": "ПОВТОРНО ВИКОРИСТАНИЙ", "NO STAGE RE-ENTRY / RECOVERY DATA": "НЕМАЄ ДАНИХ ПРО ВХІД В АТМОСФЕРУ / ПОВЕРНЕННЯ", - "{count} / 30D": "{count} / 30D", + "{count} / 30D": "{count} / 30 ДН", "NO MISSIONS AVAILABLE IN THE CURRENT 30-DAY WINDOW": "НЕМАЄ МІСІЙ У ПОТОЧНОМУ 30-ДЕННОМУ ВІКНІ", "DATE UNAVAILABLE": "ДАТА НЕДОСТУПНА", "UNSPECIFIED OPERATOR": "ОПЕРАТОРА НЕ ВКАЗАНО", "Select {mission}": "Вибрати {mission}", - "{value} KM": "{value} KM", - "{value} KM/S": "{value} KM/S", + "{value} KM": "{value} КМ", + "{value} KM/S": "{value} КМ/С", + "Selected Space Mission": "Вибрана космічна місія", "SELECTED SPACE MISSION": "ВИБРАНА КОСМІЧНА МІСІЯ", "Show all missions": "Показати всі місії", "Deselect mission": "Зняти вибір місії", "MISSION": "МІСІЯ", + "STATUS · ": "СТАТУС · ", + "LAUNCH SITE · ": "МІСЦЕ ЗАПУСКУ · ", + "LAUNCH TIME · ": "ЧАС ЗАПУСКУ · ", + "ORBIT · ": "ОРБІТА · ", + "ASCENT PATH · ": "ТРАЄКТОРІЯ ВИВЕДЕННЯ · ", + "CURRENT DISTANCE FROM EARTH · ": "ПОТОЧНА ВІДСТАНЬ ВІД ЗЕМЛІ · ", + "SATELLITE SPEED · ": "ШВИДКІСТЬ СУПУТНИКА · ", "PAYLOAD": "КОРИСНЕ НАВАНТАЖЕННЯ", "NAME": "НАЗВА", "TYPE": "ТИП", @@ -213,6 +871,7 @@ "Pause replay": "Призупинити повтор", "Cancel replay": "Скасувати повтор", "EST. DOWNRANGE": "РОЗРАХ. ДАЛЬНІСТЬ", + "PLANNED · ": "ПЛАН · ", "SUPPLIED TRAJECTORY POINTS": "НАДАНІ ТОЧКИ ТРАЄКТОРІЇ", "RECONSTRUCTED ESTIMATE": "ВІДТВОРЕНА ОЦІНКА", "Replay the estimated ascent with a following camera": "Відтворити розрахунковий зліт із камерою-супроводом", @@ -223,10 +882,84 @@ "Ascent replay": "Повтор зльоту", "Orbit replay": "Повтор орбіти", ", paused": ", пауза", + "Malformed launch snapshot": "Некоректний знімок запусків", + "Heard by your receiver": "Прийнято вашим приймачем", + "1090 MHz": "1090 МГц", + "978 MHz UAT": "978 МГц UAT", + "browser SDR": "SDR у браузері", + "decoder feed": "потік декодера", + "Your RTL-SDR receiver and decoder feed": "Ваш приймач RTL-SDR і потік декодера", + "Your decoder feed": "Ваш потік декодера", + "Your RTL-SDR receiver": "Ваш приймач RTL-SDR", + "NO CALLSIGN": "БЕЗ ПОЗИВНОГО", + "ALT {altitude} FT · GS {speed} KT · TRK {track}": "ВИС. {altitude} ФТ · ШЛЯХ. ШВ. {speed} ВУЗ · ШЛЯХ {track}", + "V/S {rate}": "ВЕРТ. ШВ. {rate}", + "V/S {rate} FPM": "ВЕРТ. ШВ. {rate} ФТ/ХВ", + "POSITION {age}": "ПОЗИЦІЯ {age}", + "POSITION {seconds} S AGO": "ПОЗИЦІЯ {seconds} С ТОМУ", + "{count} MSGS": { + "one": "{count} ПОВІДОМЛЕННЯ", + "few": "{count} ПОВІДОМЛЕННЯ", + "many": "{count} ПОВІДОМЛЕНЬ", + "other": "{count} ПОВІДОМЛЕННЯ" + }, + "Decoder feeds": "Потоки декодера", + "WebUSB + decoder feeds": "WebUSB + потоки декодера", + "opening receiver": "відкриття приймача", + "checking decoder feeds": "перевірка потоків декодера", + "WebUSB needs desktop Chrome or Edge": "Для WebUSB потрібен настільний Chrome або Edge", + "connect a receiver in Radio": "підключіть приймач у розділі «Радіо»", + "receiver is in FM mode": "приймач у режимі FM", + "listening": "приймання", + "USB error": "помилка USB", "Alt unknown": "Висота невідома", "Type unknown": "Тип невідомий", "Reg unknown": "Рег. невідомий", "Operator unknown": "Оператор невідомий", + "${amount}K": "{amount} тис. $", + "${amount}M": "{amount} млн $", + "${amount}B": "{amount} млрд $", + "fire cause|Human": "діяльність людини", + "fire cause|Natural": "природна", + "fire cause|Undetermined": "не встановлена", + "fire cause|Unknown": "невідома", + "fire behavior|Minimal": "мінімальна активність", + "fire behavior|Moderate": "помірна активність", + "fire behavior|Active": "висока активність", + "fire behavior|Extreme": "екстремальна активність", + "Type {level} Incident": "інцидент {level}-го типу", + "age|{count}m": "{count} хв", + "{acres} ac": { + "one": "{acres} акр", + "few": "{acres} акри", + "many": "{acres} акрів", + "other": "{acres} акра" + }, + "{percent}% contained": "локалізовано на {percent}%", + "containment unknown": "локалізація невідома", + "{cause} cause": "причина: {cause}", + "{personnel} personnel": { + "one": "{personnel} особа", + "few": "{personnel} особи", + "many": "{personnel} осіб", + "other": "{personnel} особи" + }, + "{county} County": "округ {county}", + "{cost} to date": "{cost} на сьогодні", + "discovered {age} ago": "виявлено {age} тому", + "updated {age} ago": "оновлено {age} тому", + "part of {complex}": "входить до {complex}", + "InciWeb ↗ · click card to open": "InciWeb ↗ · клацніть картку, щоб відкрити", + "FIRE · {name}": "ПОЖЕЖА · {name}", + "Unnamed incident": "Без назви", + "Open {title} on InciWeb": "Відкрити {title} в InciWeb", + "Perimeter source unavailable": "Джерело контурів пожеж недоступне", + "Not contained or unknown": "Не локалізовано або невідомо", + "Under 50% contained": "Локалізовано менш ніж на 50%", + "50–99% contained": "Локалізовано на 50–99%", + "Fully contained": "Повністю локалізовано", + "Colour shows reported containment. Perimeters are simplified to about 100 m.": "Колір показує заявлений ступінь локалізації. Контури спрощено приблизно до 100 м.", + "Malformed perimeter snapshot": "Некоректний знімок периметрів", "radio tag|All": "Усі", "News": "Новини", "Talk": "Розмовні", @@ -236,6 +969,10 @@ "Traffic / Transit": "Рух / Транспорт", "Music": "Музика", "Other": "Інше", + "Directory refresh degraded; showing the previous station catalog.": "Каталог оновився з перебоями; показано попередній каталог станцій.", + "Radio directory coverage is degraded.": "Каталог радіостанцій працює з перебоями.", + "Directory refresh failed; showing the previous station catalog.": "Не вдалося оновити каталог; показано попередній каталог станцій.", + "Radio directory is temporarily unavailable.": "Каталог радіостанцій тимчасово недоступний.", "radio|NEWS": "НОВИНИ", "radio|TALK": "РОЗМОВНІ", "radio|WEATHER": "ПОГОДА", @@ -244,6 +981,9 @@ "radio|TRANSIT": "ТРАНСПОРТ", "radio|MUSIC": "МУЗИКА", "radio|OTHER": "ІНШЕ", + "Broadcaster stream is unavailable or blocked by the browser.": "Потік мовника недоступний або заблокований браузером.", + "Playback requires a direct click or tap.": "Щоб почати відтворення, натисніть кнопку відтворення.", + "Broadcaster stream could not be started.": "Не вдалося запустити потік мовника.", "Alternative": "Альтернатива", "Ambient": "Ембієнт", "Blues": "Блюз", @@ -257,7 +997,7 @@ "House": "Хаус", "Indie": "Інді", "Jazz": "Джаз", - "Latin": "Латина", + "Latin": "Латиноамериканська", "Metal": "Метал", "Oldies": "Ретро", "Pop": "Поп", @@ -269,6 +1009,32 @@ "Techno": "Техно", "Trance": "Транс", "World": "Етнічна", + "overview": "огляд", + "cloud unknown": "хмарність невідома", + "{percent}% scene cloud": "хмарність сцени {percent}%", + "{min}–{max}% scene cloud": "хмарність сцени {min}–{max}%", + "Comparison in use by another scene": "Порівняння зайняте іншою сценою", + "Esri map unavailable · no swipe": "Карта Esri недоступна · без порівняння", + "Swipe needs a globe map": "Для порівняння потрібна карта-глобус", + "Imagery stays on Esri · CLEAR to use Google 3D": "Знімки залишаються на Esri · «СКИНУТИ», щоб повернути Google 3D", + "Imagery catalog unavailable": "Каталог знімків недоступний", + "Catalog truncated · a newer clear day may exist": "Каталог скорочено · можливо, є пізніший ясний день", + "{label} catalog unavailable · {detail}": "Каталог {label} недоступний · {detail}", + "Daily overview for today may still be empty until the pass": "Щоденний огляд за сьогодні може залишатися порожнім до прольоту супутника", + "Box and images cleared": "Область і знімки скинуто", + "MORE DETAIL · 30 m": "БІЛЬШЕ ДЕТАЛЕЙ · 30 м", + "Sentinel-2 and Landsat via HLS, 30 m, every 2–6 days": "Sentinel‑2 і Landsat через HLS, 30 м, кожні 2–6 днів", + "DAILY OVERVIEW · 250 m": "ЩОДЕННИЙ ОГЛЯД · 250 м", + "VIIRS daily mosaic, 250 m, follows broad changes; little detail under 25 km": "Щоденна мозаїка VIIRS, 250 м, показує великі зміни; мало деталей у масштабі менш ніж 25 км", + "Sentinel-2": "Sentinel‑2", + "Sentinel-2 via HLS": "Sentinel‑2 через HLS", + "Landsat 8/9": "Landsat 8/9", + "Landsat 8/9 via HLS": "Landsat 8/9 через HLS", + "Daily overview": "Щоденний огляд", + "Box edges must be finite": "Некоректні координати області", + "Longitudes must be within ±180°": "Довгота має бути в межах ±180°", + "Select one side of the dateline": "Не перетинайте лінію зміни дат", + "Box must enclose an area": "Область повинна мати площу", "Add the full Starlink broadband shell (thousands of extra points)": "Додати повну широкосмугову оболонку Starlink (тисячі додаткових точок)", "Loading the Starlink shell…": "Завантаження оболонки Starlink…", "Starlink {detail} — click to retry": "Starlink: {detail} — клацніть, щоб повторити", @@ -277,78 +1043,595 @@ "DENSE ···": "ЩІЛЬНО ···", "DENSE ✕": "ЩІЛЬНО ✕", "DENSE": "ЩІЛЬНО", + "CelesTrak unreachable": "CelesTrak недоступний", + "DOCKED · {name} · +{extra}": "ПРИСТИКОВАНО · {name} · +{extra}", + "DOCKED · {name}": "ПРИСТИКОВАНО · {name}", + "{name} needs the Google 3D map: choose it under MAP SOURCE": "{name}: потрібна карта Google 3D — виберіть її в розділі «ДЖЕРЕЛО КАРТИ»", + "zoom in to a street to open {name}": "наблизьтеся до вулиці, щоб відкрити {name}", + "loading coverage...": "завантаження покриття...", + "No street-level imagery within {radius} m of that point": "У радіусі {radius} м від цієї точки вуличних знімків немає", + "No street-level imagery within {radius} m of the view centre": "У радіусі {radius} м від центру вигляду вуличних знімків немає", + "Zoom in to see street-level coverage": "Наблизьтеся, щоб побачити покриття вуличних знімків", + "Point the camera at the ground for street-level coverage": "Спрямуйте камеру на землю, щоб побачити покриття вуличних знімків", + "Coverage tile failed": "Не вдалося завантажити тайл покриття", + "The photo could not be loaded": "Не вдалося завантажити фото", + "{name} photo. ← and → step along the sequence. On a 360° photo, drag or use Shift+← →, ↑ ↓ to look around, and + − to zoom": "Фото {name}. ← і → гортають зйомку. На 360°-фото перетягуйте або використовуйте Shift+← →, ↑ ↓ для огляду, + − для масштабу", + "{name} street-level photo": "Вуличне фото {name}", + "Previous photo in this sequence (←)": "Попереднє фото зйомки (←)", + "Next photo in this sequence (→)": "Наступне фото зйомки (→)", + "Aim the middle of the view at a street to look for imagery there": "Наведіть центр вигляду на вулицю, щоб пошукати там знімки", + "KEY REJECTED": "КЛЮЧ ВІДХИЛЕНО", + "GOOGLE_MAPS_API_KEY is not set": "GOOGLE_MAPS_API_KEY не задано", + "The Google Maps JavaScript API could not load": "Не вдалося завантажити Google Maps JavaScript API", + "Google Street View": "Google Перегляд вулиць", + "GOOGLE STREET VIEW": "GOOGLE ПЕРЕГЛЯД ВУЛИЦЬ", + "Google refused GOOGLE_MAPS_API_KEY for Street View — check that the Maps JavaScript API is enabled for it and this site is an allowed referrer": "Google відхилив GOOGLE_MAPS_API_KEY для Перегляду вулиць — перевірте, що для ключа ввімкнено Maps JavaScript API, а адреса цього сайту є в списку дозволених (HTTP referrer)", + "Street View did not answer — check the network, and that the Maps JavaScript API is enabled for GOOGLE_MAPS_API_KEY": "Перегляд вулиць не відповів — перевірте мережу й те, що для GOOGLE_MAPS_API_KEY увімкнено Maps JavaScript API", + "click a street to open Street View": "клацніть на вулиці, щоб відкрити Перегляд вулиць", + "Street View has no imagery for this place": "У Перегляді вулиць немає знімків цього місця", + "KartaView has no position for this photo": "KartaView не має координат цього фото", + "The KartaView photo could not be loaded": "Не вдалося завантажити фото KartaView", + "zoom in to see KartaView coverage": "наблизьтеся, щоб побачити покриття KartaView", + "no KartaView photos in view": "фото KartaView у полі зору немає", + "KartaView is rate-limiting requests — they resume on their own": "KartaView обмежує частоту запитів — вони відновляться самі", + "KartaView’s photos here are archived and cannot be shown": "Фото KartaView тут в архіві, показати їх не можна", + "KartaView did not filter this area in time — move the map to ask again": "KartaView не встиг відфільтрувати цю область — зсуньте карту, щоб запитати знову", + "None of KartaView’s photos here pass the imagery filter": "Жодне фото KartaView тут не проходить фільтр знімків", + "KartaView did not answer in time — try again": "KartaView не відповів вчасно — спробуйте знову", + "KartaView could not be reached — check the network": "Не вдалося звʼязатися з KartaView — перевірте мережу", + "KartaView sent an answer that could not be read": "KartaView надіслав відповідь, яку не вдалося прочитати", + "KartaView is rate-limiting requests": "KartaView обмежує частоту запитів", + "KartaView sent too much data": "KartaView надіслав забагато даних", + "KartaView is rate-limiting requests — try again in a moment": "KartaView обмежує частоту запитів — спробуйте ще раз трохи згодом", + "KartaView has no such photo": "KartaView не має такого фото", + "Mapillary rejected MAPILLARY_CLIENT_TOKEN — replace it in Provider Settings": "Mapillary відхилив MAPILLARY_CLIENT_TOKEN — замініть його в «Налаштуваннях постачальників»", + "Coverage requests are being rate-limited — they resume on their own": "Запити покриття обмежено за частотою — вони відновляться самі", + "The Panoramax photo could not be loaded": "Не вдалося завантажити фото Panoramax", + "Panoramax is busy — coverage resumes on its own": "Panoramax перевантажений — покриття завантажиться само", + "no Panoramax photos in view": "фото Panoramax у полі зору немає", + "no Panoramax photos here match the filters": "тут немає фото Panoramax, що відповідають фільтрам", + "Panoramax sent a map tile that could not be read": "Panoramax надіслав тайл карти, який не вдалося прочитати", + "This Panoramax photo is no longer available": "Це фото Panoramax більше недоступне", + "zoom in to see Panoramax coverage": "наблизьтеся, щоб побачити покриття Panoramax", + "Panoramax did not answer in time — try again": "Panoramax не відповів вчасно — спробуйте знову", + "Panoramax could not be reached — check the connection": "Не вдалося звʼязатися з Panoramax — перевірте підключення", + "Panoramax sent too much data": "Panoramax надіслав забагато даних", + "Panoramax is busy": "Panoramax перевантажений", + "Panoramax sent an unreadable answer": "Panoramax надіслав відповідь, яку не вдалося прочитати", + "Sequence images unavailable": "Знімки послідовності недоступні", + "No street-level imagery providers configured": "Джерела вуличних знімків не налаштовано", + "(by upload date)": "(за датою завантаження)", + "Open the Street Level panel to view imagery": "Відкрийте панель «Вуличні знімки», щоб їх переглянути", + "Image could not be opened": "Не вдалося відкрити знімок", + "TeleGeography load failed": "Не вдалося завантажити дані TeleGeography", + "UNAVAILABLE · {source} · Roads unavailable": "НЕДОСТУПНО · {source} · Дороги недоступні", + "Roads: {source}": "Дороги: {source}", + "TomTom roads unavailable while the traffic service is unreachable": "Дороги TomTom недоступні, доки сервіс руху не відповідає", + "Hybrid unavailable while the traffic service is unreachable": "Гібридний режим недоступний, доки сервіс руху не відповідає", + "TomTom roads need a TomTom key": "Для доріг TomTom потрібен ключ TomTom", + "Hybrid needs a TomTom key": "Для гібридного режиму потрібен ключ TomTom", + "Local surface still loading": "Поверхня під дорогами ще завантажується", + "Partial coverage": "Часткове покриття", + "Detailed roads unavailable": "Немає детальних даних про дороги", + "Reduced detail coverage": "Покриття зі зниженою деталізацією", + "TomTom roads only, each with its live flow": "Лише дороги TomTom, кожна зі своїм потоком онлайн", + "TomTom roads only, each with its live flow (needs a TomTom key)": "Лише дороги TomTom, кожна зі своїм потоком онлайн (потрібен ключ TomTom)", + "OpenStreetMap roads, with TomTom flow matched when available": "Дороги OpenStreetMap; потік TomTom зіставляється, де він є", + "TomTom roads first; OpenStreetMap fills the rest, simulated": "Спершу дороги TomTom; решту доповнює OpenStreetMap з імітацією потоку", + "TomTom roads first; OpenStreetMap fills the rest, simulated (needs a TomTom key)": "Спершу дороги TomTom; решту доповнює OpenStreetMap з імітацією потоку (потрібен ключ TomTom)", + "Hybrid": "Гібрид", + "TomTom key unavailable": "Ключ TomTom недоступний", + "TomTom daily budget reached": "Вичерпано денний ліміт TomTom", + "TomTom upstream unreachable": "Сервер TomTom не відповідає", + "TomTom flow unavailable": "Потік TomTom недоступний", + "SIMULATED — {reason}": "ІМІТАЦІЯ — {reason}", + "Syncing flow · Roads: {source}": "Синхронізація потоку · Дороги: {source}", + "LIVE · Roads: {source} · Roads without flow hidden": "ОНЛАЙН · Дороги: {source} · Дороги без потоку приховано", + "LIVE · Roads: {source} · No flow roads in view": "ОНЛАЙН · Дороги: {source} · У кадрі немає доріг із потоком", + "LIVE · Roads: {source} · Flow {percent}%": "ОНЛАЙН · Дороги: {source} · Потік {percent}%", + "SIMULATED · Roads: {source} · Flow {percent}%": "ІМІТАЦІЯ · Дороги: {source} · Потік {percent}%", + "Syncing flow · Roads: OpenStreetMap · Flow: TomTom · Unmatched: simulated": "Синхронізація потоку · Дороги: OpenStreetMap · Потік: TomTom · Без збігів: імітація", + "LIVE · Roads: OpenStreetMap · Flow: TomTom · {percent}% cov · Unmatched: simulated": "ОНЛАЙН · Дороги: OpenStreetMap · Потік: TomTom · охоплення {percent}% · Без збігів: імітація", + "LIVE · Roads: OpenStreetMap · Flow: TomTom · {percent}% cov": "ОНЛАЙН · Дороги: OpenStreetMap · Потік: TomTom · охоплення {percent}%", + "SIMULATED · Roads: OpenStreetMap · Flow: TomTom (no matches)": "ІМІТАЦІЯ · Дороги: OpenStreetMap · Потік: TomTom (немає збігів)", "SIMULATED — traffic service unreachable": "ІМІТАЦІЯ — сервіс руху недоступний", "SIMULATED — add TomTom key for live": "ІМІТАЦІЯ — додайте ключ TomTom для реального часу", + "OpenFreeMap tiles rate-limited": "Тайли OpenFreeMap: перевищено ліміт запитів", + "OpenFreeMap tiles timed out": "Тайли OpenFreeMap: минув час очікування", + "OpenFreeMap tiles unavailable": "Тайли OpenFreeMap недоступні", + "occupancy|empty": "порожньо", + "occupancy|many seats available": "багато вільних місць", + "occupancy|few seats available": "мало вільних місць", + "occupancy|standing room only": "лише стоячі місця", + "occupancy|crushed standing room only": "переповнено, лише стоячи", + "occupancy|full": "місць немає", + "occupancy|not accepting passengers": "посадки немає", + "occupancy|not boardable": "посадка неможлива", + "Route {route}": "Маршрут {route}", + "Vehicle {vehicle}": "Борт {vehicle}", + "vehicle motion|Stopped": "Стоїть", + "No recent fix": "Немає свіжих координат", + "Waiting for update": "Очікування оновлення", + "Moving": "У русі", + "reported {speed} km/h": "за звітом {speed} км/год", + "reported hdg {heading}°": "за звітом курс {heading}°", + "Last report: stopped at stop {stop}": "Останній звіт: стоїть на зупинці {stop}", + "Last report: arriving at stop {stop}": "Останній звіт: прибуває на зупинку {stop}", + "Last report: next stop {stop}": "Останній звіт: наступна зупинка {stop}", + "Shown at street level · depth not in the feed": "Показано на рівні вулиці · глибини в потоці немає", + "Reported {seconds} s ago": "Звіт {seconds} с тому", + "Reported {minutes} min ago": "Звіт {minutes} хв тому", + "shown {seconds} s behind": "показ відстає на {seconds} с", + "{reported} (feed time)": "{reported} (час потоку)", + "Available trail: {minutes} min (limited)": "Доступний слід: {minutes} хв (обмежений)", + "Available trail: {minutes} min": "Доступний слід: {minutes} хв", + "Bus": "Автобус", + "Tram": "Трамвай", + "Subway": "Метро", + "Train": "Поїзд", + "Ferry": "Пором", + "Transit vehicle": "Громадський транспорт", "AIS: {name}": "AIS: {name}", + "{type} SPD: {speed} HDG: {heading}": "{type} ШВИД: {speed} КУРС: {heading}", "VESSEL": "СУДНО", - "POS: LIVE": "POS: У РЕАЛЬНОМУ ЧАСІ", - "POS: {time}Z": "POS: {time}Z", + "{speed}KT": "{speed} ВУЗ", + "{heading}DEG": "{heading}°", + "POS: LIVE": "ПОЗ.: ОНЛАЙН", + "POS: {time}Z": "ПОЗ.: {time}Z", + "AIS live load failed": "Не вдалося завантажити AIS у реальному часі", "awaiting first AIS position…": "очікується перша позиція AIS…", "awaiting usable AIS positions…": "очікуються придатні позиції AIS…", "awaiting first AIS message…": "очікується перше повідомлення AIS…", + "AISSTREAM_API_KEY not set": "AISSTREAM_API_KEY не задано", + "live feed unsupported": "потік у реальному часі не підтримується", + "connecting to feed…": "підключення до потоку…", + "feed disconnected": "потік відключено", + "feed down": "потік недоступний", + "feed idle": "потік простоює", + "API key rejected — check AISSTREAM_API_KEY": "Ключ API відхилено — перевірте AISSTREAM_API_KEY", + "feed silent {seconds}s — no AIS data": "немає даних AIS від потоку {seconds} с", + "feed silent — no AIS data": "немає даних AIS від потоку", + "feed down — retrying slowly (attempt {attempt})": "потік недоступний — повторюємо рідше (спроба {attempt})", + "reconnecting to feed… (attempt {attempt})": "повторне підключення до потоку… (спроба {attempt})", + "feed down — retrying slowly": "потік недоступний — повторюємо рідше", + "reconnecting to feed…": "повторне підключення до потоку…", + "Focus vessel {name}, MMSI {mmsi}": "Фокус на судні {name}, MMSI {mmsi}", + "Hidden by this map source · choose a globe map": "Приховано цим джерелом карти · виберіть глобус", + "Weather image HTTP {status}": "Знімок погоди: HTTP {status}", + "Weather HTTP {status}": "Погода: HTTP {status}", + "Frame unavailable; previous observation retained": "Кадр недоступний; показано попереднє спостереження", + "Weather imagery unavailable": "Погодні знімки недоступні", + "Weather source unavailable; previous observation retained": "Джерело погоди недоступне; показано попереднє спостереження", + "Weather unavailable": "Погода недоступна", + "No frame within {gap} min of {time}": "Немає кадру в межах {gap} хв від {time}", + "No frame within {gap} h of {time}": "Немає кадру в межах {gap} год від {time}", + "{hours}h {minutes}m ago": "{hours} год {minutes} хв тому", + "{minutes}m ago": "{minutes} хв тому", + "{state} · {time} · {lag}": "{state} · {time} · {lag}", + "Observed": "Спостереження", + "History": "Історія", + "Observation unavailable": "Спостереження недоступне", + "Waiting for observation": "Очікування спостереження", + "{detail} · synced": "{detail} · синхр.", + "{detail} · nearest": "{detail} · найближчий", + "RADAR REFLECTIVITY · dBZ": "РАДІОЛОК. ВІДБИВНІСТЬ · dBZ", + "LIGHTNING DENSITY · 15 min accumulation": "ЩІЛЬНІСТЬ БЛИСКАВОК · накопичення за 15 хв", + "GLOBAL INFRARED · hourly": "ГЛОБАЛЬНИЙ ІЧ · щогодини", + "GOES INFRARED · ~5 min": "GOES ІЧ · ~5 хв", + "{state}: {time}": "{state}: {time}", + "Latest observation": "Останнє спостереження", + "frame {index}/{total}": "кадр {index}/{total}", + "loading": "завантаження", + "Observation: unavailable": "Спостереження: недоступне", + "Contiguous US · gaps ≠ no rain": "Континентальні США · прогалини ≠ немає дощу", + "Americas + Pacific · not individual strikes": "Америка + Тихий океан · не окремі розряди", + "Color: strikes/km²/min ×10³": "Колір: розрядів/км²/хв ×10³", + "60°S–60°N · typically 2–3 h delayed": "60° пд. ш.–60° пн. ш. · зазвичай затримка 2–3 год", + "North America · infrared imagery": "Північна Америка · ІЧ-знімки", + "Reduced motion · history playback unavailable": "Зменшення руху · відтворення історії недоступне", + "Reduced motion · manual history available": "Зменшення руху · історію можна гортати вручну", + "Rain radar · US": "Радар опадів · США", + "Lightning density · 15 min": "Щільність блискавок · 15 хв", + "Satellite clouds": "Супутникова хмарність", + "Americas + Pacific": "Америка + Тихий океан", + "Global · 60°S–60°N": "Глобально · 60° пд. ш.–60° пн. ш.", + "North America": "Північна Америка", + "Source observations delayed": "Спостереження джерела затримуються", + "Stale source": "Джерело застаріло", + "Loading next frame…": "Завантаження наступного кадру…", + "Map center outside coverage": "Центр карти поза зоною покриття", + "strikes/km²/min ×10³": "розрядів/км²/хв ×10³", + "N. America": "Пн. Америка", + "Global": "Глобально", + "Hourly global mosaic; usually 2–3 hours delayed": "Щогодинна глобальна мозаїка; зазвичай із затримкою 2–3 год", + "GOES regional clouds; approximately 5-minute updates": "Регіональна хмарність GOES; оновлення приблизно кожні 5 хв", + "Clouds only": "Лише хмари", + "Apply the full cloud brightness key; 100% filter strength": "Застосувати повний фільтр яскравості хмар; сила фільтра 100%", + "Full": "Повний", + "Show the complete infrared image; 0% filter strength": "Показати повне ІЧ-зображення; сила фільтра 0%", + "Soft": "Мʼяко", + "Vivid": "Яскраво", + "Image opacity; does not alter the observed values": "Непрозорість зображення; не змінює спостережених значень", + "View US radar": "Показати радар США", + "View Americas & Pacific": "Показати Америку й Тихий океан", + "View coverage": "Показати зону покриття", + "{value} strikes/km²/min ×10³ (15-minute density)": "{value} розрядів/км²/хв ×10³ (щільність за 15 хв)", + "{value} dBZ radar reflectivity": "Радіолокаційна відбивність: {value} dBZ", + "STALE · cached source metadata": "ЗАСТАРІЛО · метадані джерела з кешу", + "Map center is outside source coverage": "Центр карти поза зоною покриття джерела", + "NOAA/NWS 15-minute lightning density derived from Vaisala NLDN/GLD360. Coverage 110°E across the Pacific/Americas to 0°, 25°S–80°N. Not a live strike count, global coverage or a safety warning.": "15-хвилинна щільність блискавок NOAA/NWS на основі Vaisala NLDN/GLD360. Покриття — від 110° сх. д. через Тихий океан і Америку до 0°, 25° пд. ш.–80° пн. ш. Це не підрахунок розрядів у реальному часі, не глобальне покриття й не попередження про небезпеку.", + "NOAA MRMS radar echoes indicate precipitation patterns, not rain rate, a storm warning or a future forecast. Native source approximately 1 km; display is limited to level 6. Frames use exact advertised observation times.": "Радіолокаційні відлуння NOAA MRMS показують картину опадів, а не їхню інтенсивність, штормове попередження чи прогноз. Вихідна роздільність близько 1 км; показ обмежено рівнем 6. Для кадрів використано точний заявлений час спостережень.", + "GOES-19/18 longwave infrared Band 14 regional; NESDIS global longwave mosaic. Clouds only dims everything but bright, cold cloud tops; a brightness filter, not a cloud mask. Coverage and freshness differ by region.": "Регіональний довгохвильовий ІЧ-канал 14 GOES-19/18; глобальна довгохвильова мозаїка NESDIS. Режим «Лише хмари» затемнює все, крім яскравих холодних вершин хмар; це фільтр яскравості, а не маска хмарності. Покриття й актуальність різняться за регіонами.", + "REGION": "РЕГІОН", + "IMAGE": "ЗНІМОК", + "FILTER": "ФІЛЬТР", + "Cloud filter strength": "Сила фільтра хмар", + "OPACITY": "НЕПРОЗОР.", + "Infrared decode failed": "Не вдалося декодувати інфрачервоний знімок", + "Weather prefetch unavailable": "Попереднє завантаження погоди недоступне", + "Weather tiles unavailable · previous frame retained": "Погодні тайли недоступні · показано попередній кадр", + "Some weather tiles unavailable": "Частина погодних тайлів недоступна", + "Malformed weather manifest": "Некоректний маніфест погоди", + "Weather request timed out": "Минув час очікування запиту погоди", + "Temperature field unavailable": "Поле температури недоступне", + "Mean sea level pressure field unavailable": "Поле тиску на рівні моря недоступне", + "Wind upstream unavailable": "Джерело даних про вітер недоступне", + "{source} HTTP {status}": "{source}: HTTP {status}", + "Wind": "Вітер", + "Wind source unavailable": "Джерело вітру недоступне", + "Forecast · does not follow history": "Прогноз · не йде за історією", + "Wind motion": "Рух вітру", + "Wind speed": "Швидкість вітру", + "Sea-level pressure": "Тиск на рівні моря", + "Air temperature · 2 m": "Температура повітря · 2 м", + "Global · 1° grid": "Глобально · сітка 1°", + "{model} forecast · {time}": "Прогноз {model} · {time}", + "Loading forecast": "Завантаження прогнозу", + "Preparing flow": "Підготовка анімації вітру", + "Selected field unavailable": "Вибране поле недоступне", + "Cached forecast · stale": "Прогноз із кешу · застарів", + "ECMWF IFS surface forecast": "Приземний прогноз ECMWF IFS", + "NOAA GFS surface forecast": "Приземний прогноз NOAA GFS", + "Reduced motion": "Зменшення руху", "Resume": "Продовжити", "Pause": "Пауза", + "Pause visual flow; forecast time does not advance with animation": "Призупинити візуальний потік; час прогнозу не зсувається з анімацією", + "None": "Немає", + "Speed": "Швидкість", + "Pressure": "Тиск", + "Temperature": "Температура", + "Wind trails with no field shading": "Сліди вітру без заливки поля", + "How hard the surface wind is blowing": "Наскільки сильно дме приземний вітер", + "Sea-level air pressure: broad highs and lows": "Тиск на рівні моря: великі області високого й низького тиску", + "Air temperature two meters above the surface": "Температура повітря за два метри над поверхнею", + "Wind speed units": "Одиниці швидкості вітру", + "Read wind at map center": "Дізнатися вітер у центрі карти", + "Read the forecast at the center of the map without changing selection": "Отримати прогноз у центрі карти, не змінюючи вибору", + "{model} forecast · {field} ({unit})": "Прогноз {model} · {field} ({unit})", + "Valid: {time}": "Чинний на: {time}", + "preparing": "підготовка", + "Issued: {time}": "Випущено: {time}", + "Selected field unavailable · wind remains visible": "Вибране поле недоступне · вітер залишається видимим", + "{error} · wind remains visible": "{error} · вітер залишається видимим", + "Surface wind at 10 m. Approximately 1° global grid. Curves follow the 10 m wind field, lifted 12 km for visibility; display height is not weather altitude. View lighting is for readability. Animation shows flow through one fixed forecast; it does not advance time. Color fields drape the globe basemap or the active photorealistic 3D Tiles.": "Приземний вітер на висоті 10 м. Глобальна сітка близько 1°. Лінії повторюють поле вітру на 10 м і підняті на 12 км для наочності; висота показу не є висотою погодних явищ. Освітлення вигляду — для зручності читання. Анімація показує потік в одному фіксованому прогнозі й не зсуває час. Кольорові поля накладаються на підкладку глобуса або на активні фотореалістичні 3D Tiles.", + "MODEL": "МОДЕЛЬ", + "FIELD": "ПОЛЕ", + "UNITS": "ОДИНИЦІ", + "MOTION": "РУХ", + "Forecast": "Прогноз", + "N": "Пн", + "NNE": "ПнПнСх", + "NE": "ПнСх", + "ENE": "СхПнСх", + "E": "Сх", + "ESE": "СхПдСх", + "SE": "ПдСх", + "SSE": "ПдПдСх", + "S": "Пд", + "SSW": "ПдПдЗх", + "SW": "ПдЗх", + "WSW": "ЗхПдЗх", + "W": "Зх", + "WNW": "ЗхПнЗх", + "NW": "ПнЗх", + "NNW": "ПнПнЗх", + "No surface reading": "Немає приземних даних", + "Aim the map center at Earth": "Наведіть центр карти на Землю", + "A location reading needs a loaded forecast and the Earth at the center of the view.": "Щоб отримати дані в точці, завантажте прогноз і розмістіть Землю в центрі екрана.", + "Interpolated model forecast on an approximately 1° grid. Broad weather patterns, not a street-level measurement.": "Інтерпольований модельний прогноз на сітці близько 1°. Загальна погодна картина, а не вимірювання на рівні вулиці.", + " · calm": " · штиль", + " from {direction}": " з {direction}", + "WIND AT {coordinates}": "ВІТЕР У ТОЧЦІ {coordinates}", + "{model} · valid {time}": "{model} · на {time}", + "Wind speed field unavailable": "Поле швидкості вітру недоступне", + "Globe imagery unavailable": "Знімки глобуса недоступні", + "Globe field image unavailable": "Зображення поля на глобусі недоступне", + "Unknown wind model": "Невідома модель вітру", + "Unknown weather overlay": "Невідомий погодний шар", + "Wind request timed out": "Минув час очікування запиту вітру", + "Malformed wind manifest": "Некоректний маніфест вітру", + "Malformed wind grid": "Некоректна сітка вітру", "Error: {message}": "Помилка: {message}", - "Needs {envVars} — add it in Provider Settings": "Потрібно {envVars} — додайте у налаштуваннях постачальників", + "Needs {envVars} — add it in Provider Settings": "Потрібен {envVars} — додайте його в «Налаштуваннях постачальників»", "{label} is unavailable": "{label} — недоступно", "This map stack": "Цей стек карт", "{label} unavailable: {hint}": "{label} — недоступно: {hint}", + "Google 3D tiles unavailable — check the key's API restrictions, quota, or network": "Тайли Google 3D недоступні — перевірте обмеження API ключа, квоту або мережу", + "Needs {envVars} — add it in Provider Settings — or a Cesium ion token for the ion-hosted route": "Потрібен {envVars} — додайте його в «Налаштуваннях постачальників» — або токен Cesium ion для варіанта через ion", + "Exit cockpit to fly to a camera": "Вийдіть із кабіни, щоб перелетіти до камери", + "Exit cockpit to fly to a location": "Вийдіть із кабіни, щоб перелетіти до місця", + "Exit cockpit to fly to a photo": "Вийдіть із кабіни, щоб перелетіти до фото", + "Exit cockpit to fly to a shared view": "Вийдіть із кабіни, щоб перелетіти до вигляду за посиланням", + "Exit cockpit to fly to a target": "Вийдіть із кабіни, щоб перелетіти до цілі", + "Exit cockpit to fly to a vessel": "Вийдіть із кабіни, щоб перелетіти до судна", + "Exit cockpit to fly to a fire": "Вийдіть із кабіни, щоб перелетіти до пожежі", + "Exit cockpit to fly to a route": "Вийдіть із кабіни, щоб перелетіти до маршруту", + "Exit cockpit to fly to a file": "Вийдіть із кабіни, щоб перелетіти до файлу", + "Exit cockpit to fly to a scene": "Вийдіть із кабіни, щоб перелетіти до сцени", + "Exit cockpit to view weather coverage": "Вийдіть із кабіни, щоб показати зону покриття погодного шару", + "Exit cockpit to fly to a cyclone": "Вийдіть із кабіни, щоб перелетіти до циклону", + "Exit cockpit to fly to an aircraft": "Вийдіть із кабіни, щоб перелетіти до літака", + "Exit cockpit to fly to a satellite": "Вийдіть із кабіни, щоб перелетіти до супутника", + "Exit cockpit to frame contacts": "Вийдіть із кабіни, щоб показати контакти в кадрі", "Visible map targets": "Видимі цілі на карті", + "Focusing {label}": "Фокусування: {label}", + "Source": "Джерело", + "Camera ownership changed": "Керування камерою перехоплено", + "Saved project could not be read; storage preserved. Import a valid file to resume saving.": "Не вдалося прочитати збережений проєкт; сховище не змінено. Імпортуйте коректний файл, щоб знову зберігати.", "Ready": "Готово", + "Scene layer turned off": "Шар сцени вимкнено", + "Stopped": "Зупинено", + "Scene not saved — existing saved project could not be read. Export edits or import a valid file.": "Сцену не збережено — не вдалося прочитати збережений проєкт. Експортуйте зміни або імпортуйте коректний файл.", + "Scene not saved — {reason}": "Сцену не збережено — {reason}", + "Scene not saved — browser storage unavailable": "Сцену не збережено — сховище браузера недоступне", "Loaded: {scene} / {shot}": "Завантажено: {scene} / {shot}", + "Cannot update {scene}: shot inventory changed": "Не вдалося оновити {scene}: змінився склад кадрів", + "Cannot update {scene}: evidence beats changed": "Не вдалося оновити {scene}: змінилися етапи свідчень", + "Cannot update {scene}: shot bindings are incomplete": "Не вдалося оновити {scene}: привʼязки кадрів неповні", + "Updated {count} shots: {scene}": { + "one": "Оновлено {count} кадр: {scene}", + "few": "Оновлено {count} кадри: {scene}", + "many": "Оновлено {count} кадрів: {scene}", + "other": "Оновлено {count} кадру: {scene}" + }, + "Appended {count} shots: {scene}": { + "one": "Додано {count} кадр: {scene}", + "few": "Додано {count} кадри: {scene}", + "many": "Додано {count} кадрів: {scene}", + "other": "Додано {count} кадру: {scene}" + }, "Cannot capture shot: camera not ready": "Не вдалося зняти кадр: камера не готова", "Captured: {scene} / {shot}": "Знято: {scene} / {shot}", "Select a shot first": "Спочатку оберіть кадр", "Updated: {scene} / {shot}": "Оновлено: {scene} / {shot}", + "Could not leave scene: {scene}": "Не вдалося вийти зі сцени: {scene}", + "Seeked: {scene} / {shot}": "Перемотано: {scene} / {shot}", + "Seeking scene clock": "Перемотування сцени", "Camera unavailable — exit cockpit first": "Камера недоступна — спершу вийдіть із кабіни", "No shots to run": "Немає кадрів для запуску", + "Scene transition limit reached — load a shot to reset": "Досягнуто ліміту переходів сцени — завантажте кадр, щоб скинути лічильник", + "Export failed: {error}": "Помилка експорту: {error}", "Project exported": "Проєкт експортовано", + "Importing project": "Імпорт проєкту", + "Imported {file}": "Імпортовано: {file}", + "Import failed: {error}": "Помилка імпорту: {error}", + "Import failed (could not read JSON file)": "Помилка імпорту (не вдалося прочитати файл JSON)", + "Layers refused: {layers}": "Шари відхилено: {layers}", "Could not exit {mode} — scene layers may be refused": "Не вдалося вийти з {mode} — шари сцени може бути відхилено", + "Camera move interrupted": "Переліт камери перервано", + "Scene media timed out": "Минув час очікування медіа сцени", + "Action complete": "Дію виконано", + "Action unavailable or cancelled": "Дія недоступна або скасована", + "Scene actions": "Дії сцени", + "Select a feature or use Tab and Enter to choose an action.": "Виберіть обʼєкт на карті або скористайтеся Tab і Enter, щоб вибрати дію.", + "Selected feature: {feature}. Choose an action.": "Вибрано обʼєкт: {feature}. Виберіть дію.", "Running {index}/{total}: {scene} / {shot}": "Виконання {index}/{total}: {scene} / {shot}", "Scene run complete": "Запуск сцени завершено", + "Bhote Koshi Evidence Sequence": "Послідовність свідчень: Bhote Koshi", + "Nepal Flood Incident": "Паводок у Непалі", "Global Flights Radar": "Глобальний радар польотів", "Orbital Watch": "Орбітальний нагляд", "Thermal Threat Board": "Панель теплових загроз", "City Overload": "Міське перевантаження", - "Omniscience Pullback": "Всевидячий від'їзд", + "Omniscience Pullback": "Всевидючий відʼїзд", + "Global Incident Context": "Глобальний контекст події", + "Nepal-Focused Globe Rotation": "Поворот глобуса до Непалу", + "Bhote Koshi Regional Approach": "Підліт до регіону Bhote Koshi", + "Bhote Koshi Nearby Cities": "Міста поблизу Bhote Koshi", + "Bhote Koshi Incident Corridor": "Коридор події на Bhote Koshi", + "Bhote Koshi Flood Path": "Шлях паводка на Bhote Koshi", + "Bhote Koshi Corridor Overview": "Огляд коридору Bhote Koshi", + "Bhote Koshi Upper Valley": "Верхня долина Bhote Koshi", + "Upper Valley Collapse": "Обвал у верхній долині", + "Debris-Dammed Lake": "Озеро, загачене уламками", + "Nepal-China Border Gate": "Прикордонний перехід Непал — Китай", + "Timure Evidence Cluster": "Група свідчень біля Timure", + "Syabru Besi Passage": "Проходження через Syabru Besi", + "Bidur / Trishuli Consequence": "Наслідки в Bidur / Trishuli", + "Final view": "Фінальний вигляд", + "Scene {n}": "Сцена {n}", "Shot {n}": "Кадр {n}", + "the title of scene {scene} is empty or longer than {max} characters": "назва сцени {scene} порожня або довша за {max} символів", + "the title of shot {shot} in scene {scene} is empty or longer than {max} characters": "назва кадру {shot} у сцені {scene} порожня або довша за {max} символів", + "the project is larger than 5 MiB": "проєкт більший за 5 МіБ", + "the project has too many shots": "у проєкті забагато кадрів", + "the scene data failed validation": "дані сцени не пройшли перевірку", + "Could not complete this action. Check the file, references and selected assets.": "Не вдалося виконати дію. Перевірте файл, посилання й вибрані ресурси.", + "{count} scenes": { + "one": "{count} сцена", + "few": "{count} сцени", + "many": "{count} сцен", + "other": "{count} сцени" + }, + "{count} shots": { + "one": "{count} кадр", + "few": "{count} кадри", + "many": "{count} кадрів", + "other": "{count} кадру" + }, + "{count} data packs": { + "one": "{count} пакет даних", + "few": "{count} пакети даних", + "many": "{count} пакетів даних", + "other": "{count} пакета даних" + }, + "{scene} / {pack}: {status}. File: {path}. {attribution} · {license}": "{scene} / {pack}: {status}. Файл: {path}. {attribution} · {license}", + "Unavailable layers: {layers}": "Недоступні шари: {layers}", + "Uses registered content or linked media. Those external files are not included in a scene bundle. Their original notices still apply.": "Використовує зареєстрований вміст або повʼязані медіафайли. Ці зовнішні файли не входять до архіву сцени. Їхні початкові умови використання й надалі чинні.", + "{bytes} bundled bytes verified. Files stay in memory for this session. Reimport the bundle after reloading the app.": "Перевірено байтів в архіві: {bytes}. Файли зберігаються в памʼяті лише протягом цього сеансу. Після перезавантаження застосунку імпортуйте архів знову.", + "Review scene import": "Перевірка імпорту сцени", + "Nothing is loaded or changed until you apply this file.": "Нічого не завантажується й не змінюється, доки ви не застосуєте цей файл.", + "Ready to import": "Готово до імпорту", + "Apply replaces the current project. Export your current project first if you want to keep both.": "Застосування замінить поточний проєкт. Щоб не втратити його, спершу експортуйте поточний проєкт.", + "Apply import": "Застосувати імпорт", + "Import was not applied. The current project may have changed.": "Імпорт не застосовано. Можливо, поточний проєкт змінився.", + "Select a scene and shot first": "Спершу виберіть сцену й кадр", + "Edit scene details": "Змінити параметри сцени", + "Camera positions use degrees and meters above the ellipsoid. Drafts are validated before they replace your saved scene.": "Положення камери задаються в градусах і метрах над еліпсоїдом. Перш ніж замінити збережену сцену, чернетку перевіряють.", + "Anchors and data packs": "Якорі й пакети даних", + "Shot camera, timing, packs and actions": "Камера кадру, таймінг, пакети й дії", + "New anchor ID": "ID нового якоря", + "Capture camera as anchor": "Зберегти камеру як якір", + "Anchor added to draft": "Якір додано до чернетки", + "Set move start to current camera": "Початок перельоту — поточна камера", + "Move added to draft; destination remains the shot camera": "Переліт додано до чернетки; кінцевою точкою залишається камера кадру", + "Use ordinary flight": "Використати звичайний переліт", + "Invalid shot JSON": "Некоректний JSON кадру", + "Apply details": "Застосувати параметри", + "Select a scene first": "Спершу виберіть сцену", + "Share selected scene": "Поділитися вибраною сценою", + "Scene JSON preserves authored settings and attribution. It does not include asset files. Bundles include only pack files you choose here or previously imported bundle files.": "JSON сцени зберігає авторські налаштування й атрибуцію, але не містить файлів ресурсів. Архів містить лише файли пакетів, вибрані тут, або файли раніше імпортованих архівів.", + "Download scene JSON": "Завантажити JSON сцени", + "Choose data-pack files": "Виберіть файли пакетів даних", + "Or choose a data-pack folder": "Або виберіть теку пакета даних", + "Download asset bundle": "Завантажити архів ресурсів", + "Asset bundle downloaded": "Архів ресурсів завантажено", + "No RTL-SDR device selected": "Пристрій RTL-SDR не вибрано", + "WebUSB requires desktop Chrome or Edge on localhost/HTTPS": "Для WebUSB потрібен настільний Chrome або Edge на localhost/HTTPS", + "RTL-SDR access failed; close other SDR apps and check USB permissions": "Немає доступу до RTL-SDR; закрийте інші SDR-застосунки й перевірте дозволи USB", + "RTL-SDR connection failed": "Не вдалося підключити RTL-SDR", + "Receiving 1090 MHz ADS-B": "Приймання ADS-B на 1090 МГц", + "Receiving broadcast FM": "Приймання FM-мовлення", + "Connect an RTL-SDR to begin.": "Підключіть RTL-SDR, щоб почати.", + "WebUSB is unavailable in this browser": "WebUSB недоступний у цьому браузері", + "USB work abandoned after a stalled transfer": "Роботу з USB перервано: передавання даних зависло", + "SDR decoder worker failed": "Збій обробника декодера SDR", + "SDR decoder did not start; receiver stopped": "Декодер SDR не запустився; приймач зупинено", + "SDR decoder stopped responding; receiver stopped": "Декодер SDR перестав відповідати; приймач зупинено", + "SDR decoder fell behind; receiver stopped": "Декодер SDR не встигає; приймач зупинено", + "WebUSB requires desktop Chrome or Edge": "Для WebUSB потрібен настільний Chrome або Edge", + "Waiting for an RTL-SDR device…": "Очікування пристрою RTL-SDR…", + "Browser audio is suspended; press Connect again to resume it": "Звук у браузері призупинено; натисніть «Підключити» ще раз, щоб відновити його", + "RTL-SDR sample stream stopped": "Потік вибірок RTL-SDR зупинено", + "Switching to {mode}…": "Перемикання на {mode}…", + "Browser audio is suspended; select FM again to resume it": "Звук у браузері призупинено; виберіть FM ще раз, щоб відновити його", + "RTL-SDR gain change failed": "Не вдалося змінити підсилення RTL-SDR", + "Tuned to {mhz} MHz FM": "Налаштовано на FM {mhz} МГц", + "Seeking up…": "Пошук угору…", + "Seeking down…": "Пошук униз…", + "Seek stopped": "Пошук зупинено", + "Scanning {mhz} MHz…": "Сканування {mhz} МГц…", + "Found {mhz} MHz · {snr} dB": "Знайдено {mhz} МГц · {snr} дБ", + "FM signal found at {mhz} MHz": "Знайдено FM-сигнал на {mhz} МГц", + "No FM signal found": "FM-сигнал не знайдено", + "Browser location is unavailable": "Місцезнаходження браузера недоступне", + "Receiver location was not granted": "Доступ до місцезнаходження приймача не надано", + "RTL-SDR disconnected": "RTL-SDR відключено", + "Upstream response too large": "Надто велика відповідь джерела", + "Vector tile request timed out": "Векторні тайли: минув час очікування", + "Vector tiles unavailable": "Векторні тайли недоступні", + "Vector tile metadata unavailable": "Метадані векторних тайлів недоступні", + "Zoom in for vector tile coverage": "Наблизьте карту, щоб завантажити векторні тайли", + "Saturation": "Насиченість", + "Edge Thickness": "Товщина контурів", + "Contrast": "Контраст", + "Grain": "Зерно", + "Vignette": "Віньєтка", + "Pixelation": "Пікселізація", + "Distortion": "Спотворення", + "Instability": "Нестабільність", "Density": "Щільність", + "Gain": "Підсилення", "Bloom": "Світіння", + "Scanlines": "Рядки розгортки", + "Sensitivity": "Чутливість", + "WHOT/BHOT": "WHOT/BHOT", + "Ironbow": "Ironbow", + "unsaved CCTV calibration": "незбережене калібрування CCTV", + "the open cockpit": "відкрита кабіна", + "Switching language reloads the page. This will be lost: {items}. Switch anyway?": "Зміна мови перезавантажить сторінку. Буде втрачено: {items}. Однаково змінити мову?", "VISUAL PRESETS": "ВІЗУАЛЬНІ ПРЕСЕТИ", "LOCATION": "РОЗТАШУВАННЯ", - "CONTACTS — nearest planes · vessels · sites": "КОНТАКТИ — найближчі літаки · судна · об’єкти", + "CONTACTS — nearest planes · vessels · sites": "КОНТАКТИ — найближчі літаки · судна · обʼєкти", "SPACE MISSIONS — launches & orbital assets": "КОСМІЧНІ МІСІЇ — запуски та орбітальні апарати", - "LIVE SIGNALS": "СИГНАЛИ У РЕАЛЬНОМУ ЧАСІ", + "LIVE SIGNALS": "СИГНАЛИ ОНЛАЙН", "Contacts could not complete the requested transition; try again": "Контакти не змогли завершити запитаний перехід; спробуйте ще раз", "CCTV layer unavailable": "Шар CCTV недоступний", + "Link shared": "Посилання надіслано", "Link copied!": "Посилання скопійовано!", "Copy failed": "Не вдалося скопіювати", + "Return map to straight-down view": "Повернути карту до вигляду згори", + "Tilt map to oblique view": "Нахилити карту в перспективний вигляд", + "Reset map to north up. Current heading {heading} degrees": "Повернути карту північчю вгору. Поточний курс: {heading}°", + "Tilted view": "Вигляд із нахилом", + "Straight-down view": "Вигляд згори", + "North up": "Північ угорі", "CCTV calibration saved": "Калібрування CCTV збережено", + "HDG": "КУРС", + "PITCH": "ТАНГАЖ", + "FOV": "ОГЛЯД", + "RANGE": "ДАЛЬН.", + "HGT": "ВИС.", + "ΔN": "ΔПн", + "ΔE": "ΔСх", + "{value}m": "{value} м", "CCTV calibration reset": "Калібрування CCTV скинуто", "ADJUST ON": "КОРИГУВАННЯ УВІМК.", "ADJUST": "КОРИГУВАННЯ", + "SNAPSHOT": "ЗНІМОК", + "LIVE": "ОНЛАЙН", + "UPSTREAM": "ДЖЕРЕЛО", + "SYNTHETIC": "ІМІТАЦІЯ", + "CONFIGURED": "НАЛАШТОВАНО", + "SEED": "КАТАЛОГ", "UNKNOWN": "НЕВІДОМО", + "OK": "НОРМА", "ERROR": "ПОМИЛКА", + "Live HLS connected": "Потік HLS підключено", + "Live HLS unavailable": "Потік HLS недоступний", + "No stream URL configured": "URL потоку не налаштовано", + "Live stream connected": "Прямий потік підключено", + "Snapshot feed connected": "Потік знімків підключено", + "Media fetch failed": "Не вдалося отримати медіа", + "Upstream snapshot active": "Знімок із джерела активний", + "Fallback Street View frame": "Резервний кадр із Перегляду вулиць", + "Upstream unavailable": "Джерело недоступне", + "No source configured": "Джерело не налаштовано", + "Configured source": "Налаштоване джерело", + "Configured Source": "Налаштоване джерело", + "Synthetic fallback": "Синтетичний резерв", + "Upstream HTTP {status}": "Джерело: HTTP {status}", + "Unexpected media type {type}": "Неочікуваний тип медіа: {type}", "SOURCE · UNKNOWN": "ДЖЕРЕЛО · НЕВІДОМЕ", "FRAME · LOADING": "КАДР · ЗАВАНТАЖЕННЯ", "FRAME · UNAVAILABLE": "КАДР · НЕДОСТУПНИЙ", "CALIBRATED": "КАЛІБРОВАНО", - "CURATED": "ПІДІБРАНО", - "RAW PRIOR": "СИРЕ АПРІОРНЕ", + "CURATED": "ВИВІРЕНО", + "RAW PRIOR": "ПОЧАТКОВА ОЦІНКА", "CCTV ON": "CCTV УВІМК.", "CCTV OFF": "CCTV ВИМК.", - "VIEWSHED ON": "ЗОНА ВИДИМОСТІ УВІМКНЕНА", - "COVERAGE ON": "ЗОНА ОГЛЯДУ УВІМК.", - "COVERAGE OFF": "ЗОНА ОГЛЯДУ ВИМК.", + "VIEWSHED ON": "ЗОНА ВИДИМОСТІ УВІМК.", + "COVERAGE ON": "ОХОПЛЕННЯ УВІМК.", + "COVERAGE OFF": "ОХОПЛЕННЯ ВИМК.", "AUTO HOP ON": "АВТОПЕРЕХІД УВІМК.", "AUTO HOP OFF": "АВТОПЕРЕХІД ВИМК.", "PROJECTION ON": "ПРОЄКЦІЯ УВІМК.", "PROJECTION OFF": "ПРОЄКЦІЯ ВИМК.", - "CAL · EDITED (UNSAVED)": "CAL · ЗМІНЕНО (НЕ ЗБЕРЕЖЕНО)", - "CAL · {badge}": "CAL · {badge}", + "CAL · EDITED (UNSAVED)": "КАЛІБР. · ЗМІНЕНО (НЕ ЗБЕРЕЖЕНО)", + "CAL · {badge}": "КАЛІБР. · {badge}", "MONITOR": "МОНІТОР", - "OFF": "ВИМКНЕНО", - "{city} · HDG {heading} · FOV {fov} · RANGE {range}m · {projection}{calBadge} · {provider}{status}": "{city} · HDG {heading} · FOV {fov} · RANGE {range}m · {projection}{calBadge} · {provider}{status}", + "OFF": "ВИМК.", + "{city} · HDG {heading} · FOV {fov} · RANGE {range}m · {projection}{calBadge} · {provider}{status}": "{city} · КУРС {heading} · ОГЛЯД {fov} · ДАЛЬН. {range} м · {projection}{calBadge} · {provider}{status}", "{count} cameras loaded · click a camera to activate": { "one": "{count} камеру завантажено · клацніть камеру, щоб активувати", "few": "{count} камери завантажено · клацніть камеру, щоб активувати", @@ -381,30 +1664,33 @@ "MIXED CONDITIONS": "ЗМІШАНІ УМОВИ", "CYCLE ON": "ЦИКЛ УВІМКНЕНО", "CYCLE OFF": "ЦИКЛ ВИМКНЕНО", - "Stop automatic page cycling. Previous, Next, and the SIG/NEWS/LOCAL tabs stay available.": "Зупинити автоматичне гортання сторінок. Попередня, Наступна та вкладки СИГ/НОВ/ЛОК залишаються доступними.", - "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.": "Гортає сторінки брифінгу автоматично кожні 9 секунд (Сигнали → Новини → Локально). Пауза, доки ви наводите вказівник або фокусуєте панель. Дані сигналів у реальному часі оновлюються безперервно незалежно від цього.", + "Stop automatic page cycling. Previous, Next, and the SIG/NEWS/LOCAL tabs stay available.": "Зупинити автоматичне гортання сторінок. Кнопки ПОПЕР./ДАЛІ та вкладки СИГН./НОВИНИ/МІСЦ. залишаються доступними.", + "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.": "Автоматично гортає сторінки брифінгу кожні 9 секунд (Сигнали → Новини → Місцеве). Пауза, доки ви наводите вказівник на панель або вона у фокусі. Дані сигналів у реальному часі однаково оновлюються безперервно.", "ACQUIRING REGIONAL NEWS": "ОТРИМАННЯ РЕГІОНАЛЬНИХ НОВИН", "REGIONAL NEWS UNAVAILABLE": "РЕГІОНАЛЬНІ НОВИНИ НЕДОСТУПНІ", "RESOLVING REGION": "ВИЗНАЧЕННЯ РЕГІОНУ", "REGION UNAVAILABLE": "РЕГІОН НЕДОСТУПНИЙ", "NO RECENT LOCATION MATCHES": "НЕМАЄ СВІЖИХ ЗБІГІВ ЗА РОЗТАШУВАННЯМ", "{domain} · {age}": "{domain} · {age}", + "{value} KM/H": "{value} КМ/ГОД", "CLOUD {pct}%": "ХМАРНІСТЬ {pct}%", "CLOUD UNKNOWN": "ХМАРНІСТЬ НЕВІДОМА", "{source} · LOCATION QUERY": "{source} · ЗАПИТ ЗА РОЗТАШУВАННЯМ", "REGIONAL NEWS": "РЕГІОНАЛЬНІ НОВИНИ", + "{label} · {radius} AIR/SEA WINDOW": "{label} · ВІКНО ПОВІТРЯ/МОРЕ {radius}", + "{scope} · INSTALLATIONS {coverage}": "{scope} · ОБʼЄКТИ: {coverage}", "CONTEXT STANDBY": "КОНТЕКСТ: ОЧІКУВАННЯ", "ENABLE GLOBAL CONTEXT FOR PROXIMITY PINGS": "УВІМКНІТЬ ГЛОБАЛЬНИЙ КОНТЕКСТ ДЛЯ ПІНГІВ БЛИЗЬКОСТІ", "CONTACT LOST · LAST KNOWN READOUT · NOT AN ALL-CLEAR": "КОНТАКТ ВТРАЧЕНО · ОСТАННІ ВІДОМІ ПОКАЗНИКИ · НЕ ОЗНАЧАЄ «УСЕ ЧИСТО»", "CONTACT LOST · {subject}": "КОНТАКТ ВТРАЧЕНО · {subject}", - "SUBJECT LEFT ITS FEED · READOUT HOLDING LAST KNOWN": "ОБ’ЄКТ ПОКИНУВ КАНАЛ ДАНИХ · ІНДИКАТОРИ ТРИМАЮТЬ ОСТАННЄ ВІДОМЕ", + "SUBJECT LEFT ITS FEED · READOUT HOLDING LAST KNOWN": "ОБʼЄКТ ЗНИК ІЗ ПОТОКУ · ПОКАЗНИКИ ОСТАННІ ВІДОМІ", "{cohort} · {contact}": "{cohort} · {contact}", "NO AVAILABLE EXAMPLE": "НЕМАЄ ДОСТУПНОГО ПРИКЛАДУ", "{cohort}, Unavailable": "{cohort}, недоступно", "AHEAD": "ПОПЕРЕДУ", "{side} {angle}": "{side} {angle}", - "L": "L", - "R": "R", + "L": "Л", + "R": "П", "{count} INPUTS UNKNOWN · NOT AN ALL-CLEAR": { "one": "{count} НЕВІДОМИЙ ПАРАМЕТР · НЕ ОЗНАЧАЄ «УСЕ ЧИСТО»", "few": "{count} НЕВІДОМІ ПАРАМЕТРИ · НЕ ОЗНАЧАЄ «УСЕ ЧИСТО»", @@ -412,16 +1698,20 @@ "other": "{count} НЕВІДОМОГО ПАРАМЕТРА · НЕ ОЗНАЧАЄ «УСЕ ЧИСТО»" }, "AVAILABLE INPUTS CURRENT · NOT AN ALL-CLEAR": "ДОСТУПНІ ВХІДНІ ДАНІ АКТУАЛЬНІ · НЕ ОЗНАЧАЄ «УСЕ ЧИСТО»", + "SQUAWK {code} · {status}": "СКВОК {code} · {status}", + "ADS-B PRIORITY · {status}": "ADS-B ПРІОРИТЕТ · {status}", + "ADS-B EMERGENCY · {status}": "ADS-B АВАРІЯ · {status}", "AIRCRAFT": "БОРТ", "ACQUIRING SURFACE": "ОТРИМАННЯ НАЗЕМНИХ ДАНИХ", "SURFACE FALLBACK": "РЕЗЕРВ НАЗЕМНИХ ДАНИХ", - "STALE FEED": "ЗАСТАРІЛИЙ КАНАЛ ДАНИХ", - "LIVE TRACK": "ТРЕК У РЕАЛЬНОМУ ЧАСІ", + "STALE FEED": "ЗАСТАРІЛИЙ ПОТІК", + "LIVE TRACK": "ТРЕК ОНЛАЙН", "COMMERCIAL": "КОМЕРЦІЙНИЙ", + "{aircraftClass} · {emergency} · {feedState}": "{aircraftClass} · {emergency} · {feedState}", "{aircraftClass} · {feedState} · COURSE ALIGNED": "{aircraftClass} · {feedState} · КУРС ВИРІВНЯНО", "ARROW · ESTIMATED DIRECTION": "СТРІЛКА · ОРІЄНТОВНИЙ НАПРЯМОК", "ROUTE DATA UNAVAILABLE": "ДАНІ МАРШРУТУ НЕДОСТУПНІ", - "DEST {bearing}": "DEST {bearing}", + "DEST {bearing}": "ПРИЗН. {bearing}", "Disable cockpit weather effects": "Вимкнути погодні ефекти кабіни", "Enable cockpit weather effects": "Увімкнути погодні ефекти кабіни", "ON": "УВІМК.", @@ -441,17 +1731,18 @@ "Expand cockpit briefing panel": "Розгорнути панель брифінгу кабіни", "Collapse briefing panel": "Згорнути панель брифінгу", "Expand briefing panel": "Розгорнути панель брифінгу", - "OBSERVED / MAPPED PINGS": "СПОСТЕРЕЖЕНІ / КАРТОГРАФОВАНІ ПІНГИ", + "OBSERVED / MAPPED PINGS": "СПОСТЕРЕЖЕНІ / НАНЕСЕНІ ПІНГИ", "SOURCE-BACKED EVENTS · NO SYNTHETIC NEWS": "ПОДІЇ ПІДТВЕРДЖЕНІ ДЖЕРЕЛАМИ · БЕЗ ШТУЧНИХ НОВИН", "LATEST LOCATION-MATCHED REPORTING": "ОСТАННІ ПУБЛІКАЦІЇ ЗА РОЗТАШУВАННЯМ", - "LOCAL INFO": "ЛОКАЛЬНА ІНФОРМАЦІЯ", + "{source} · LOCATION QUERY · RECENT": "{source} · ЗАПИТ ЗА МІСЦЕМ · НЕЩОДАВНІ", + "LOCAL INFO": "МІСЦЕВА ІНФОРМАЦІЯ", "PLACE / CONDITIONS / POSITION": "МІСЦЕ / УМОВИ / ПОЗИЦІЯ", "TIME UNKNOWN": "ЧАС НЕВІДОМИЙ", "{count}M AGO": "{count} ХВ ТОМУ", "{count}H AGO": "{count} ГОД ТОМУ", "{count}D AGO": "{count} ДН ТОМУ", "DIR UNKNOWN": "НАПР. НЕВІДОМИЙ", - "Select flight {title}": "Обрати рейс {title}", + "Select flight {title}": "Вибрати рейс {title}", "{aircraftClass} · CURRENT": "{aircraftClass} · ПОТОЧНИЙ", "MILITARY FLIGHT": "ВІЙСЬКОВИЙ РЕЙС", "COMMERCIAL FLIGHT": "КОМЕРЦІЙНИЙ РЕЙС", @@ -484,8 +1775,8 @@ }, "Selected data layers could not be cleared": "Не вдалося очистити обрані шари даних", "Space Missions could not complete the requested transition; try again": "Космічні місії не змогли завершити запитаний перехід; спробуйте ще раз", - "Nearby installations refreshed": "Найближчі об’єкти оновлено", - "Nearby installations could not be refreshed; try again": "Не вдалося оновити найближчі об’єкти; спробуйте ще раз", + "Nearby installations refreshed": "Найближчі обʼєкти оновлено", + "Nearby installations could not be refreshed; try again": "Не вдалося оновити найближчі обʼєкти; спробуйте ще раз", "Space Missions cancellation could not restore the previous layer state": "Скасування Космічних місій не змогло відновити попередній стан шарів", "That layer is unavailable in the current Context mode": "Цей шар недоступний у поточному режимі контексту", "{layerId} could not {action} cleanly": "{layerId}: не вдалося коректно {action}", @@ -494,8 +1785,44 @@ "{mode} could not start because another layer did not stop cleanly": "{mode} не вдалося запустити, бо інший шар не зупинився коректно", "Space Missions": "Космічні місії", "Context": "Контекст", - "Live Flights": "Літаки в реальному часі", - "Military Flights": "Військова авіація", + "Rendered globe frames per second · toggle with `": "Кадрів глобуса за секунду · перемикання клавішею `", + "imported map files": "імпортовані файли на карті", + "Ground heights could not be refreshed. Try the file again when the map has loaded.": "Не вдалося оновити висоти рельєфу. Спробуйте імпортувати файл ще раз, коли карта завантажиться.", + "{count} map objects": { + "one": "{count} обʼєкт на карті", + "few": "{count} обʼєкти на карті", + "many": "{count} обʼєктів на карті", + "other": "{count} обʼєкта на карті" + }, + ", drawn with its own styles": ", зі своїми стилями", + "Hide {name}": "Сховати: {name}", + "Show {name}": "Показати: {name}", + "Fly to {name}": "Переліт: {name}", + "Remove {name}": "Видалити: {name}", + "At most {count} files at once — remove one first.": "Не більше {count} файлів одночасно — спершу видаліть один.", + "Reading {name}…": "Читання: {name}…", + "That file could not be read.": "Не вдалося прочитати цей файл.", + "Added {count} files.": { + "one": "Додано {count} файл.", + "few": "Додано {count} файли.", + "many": "Додано {count} файлів.", + "other": "Додано {count} файлу." + }, + "{count} files could not be added ({name}: {error})": { + "one": "Не вдалося додати {count} файл ({name}: {error})", + "few": "Не вдалося додати {count} файли ({name}: {error})", + "many": "Не вдалося додати {count} файлів ({name}: {error})", + "other": "Не вдалося додати {count} файлу ({name}: {error})" + }, + "Some KML content was left out.": "Частину вмісту KML пропущено.", + "Press on the ground, not the sky": "Натисніть на землю, а не на небо", + "Drag to size the box": "Потягніть, щоб задати розмір області", + "light {source} to use your {name} key": "увімкніть {source}, щоб використати свій ключ {name}", + "light {source}": "увімкніть {source}", + ", or ": " або ", + "{requirement}, or {offer}": "{requirement} або {offer}", + "Live Flights": "Рейси онлайн", + "Military Flights": "Військові рейси", "Earthquakes (24h)": "Землетруси (24 год)", "Satellites": "Супутники", "Space Missions (30d)": "Космічні місії (30 дн)", @@ -503,41 +1830,132 @@ "CCTV": "CCTV", "Radio": "Радіо", "Bikeshare": "Велопрокат", - "Live AIS Vessels": "Судна AIS у реальному часі", - "Mapped Installations": "Нанесені об’єкти", + "Live AIS Vessels": "Судна AIS онлайн", + "Mapped Installations": "Нанесені обʼєкти", "Global Context": "Глобальний контекст", "Datacenters": "Дата-центри", "Dams": "Греблі", "Submarine Cables": "Підводні кабелі", "FIRMS Active Fires": "Активні пожежі FIRMS", + "Local ADS-B": "Локальний ADS-B", + "Transit": "Громадський транспорт", + "Recent Imagery": "Свіжі знімки", + "Fire Perimeters": "Контури пожеж", + "GNSS Integrity": "Цілісність GNSS", + "S2 GhostMaps": "S2 GhostMaps", + "Rain radar": "Радар опадів", + "Lightning density": "Щільність блискавок", + "Cyclone advisories": "Зведення про циклони", + "ALPR Cameras": "Камери ALPR", + "Live Vessels": "Судна онлайн", + "Bike Share": "Прокат велосипедів", + "Cameras": "Камери", + "Street Level": "Вуличні знімки", + "Mapped ALPR Cameras": "Камери ALPR на карті", + "Data Centers": "Дата-центри", + "Active Fires": "Активні пожежі", + "Military aircraft": "Військові літаки", + "Vessels": "Судна", + "CCTV + Street View fallback": "CCTV + резерв: Перегляд вулиць", + "OpenStreetMap + optional Google Maps Places": "OpenStreetMap + Google Maps Places (опц.)", + "GFS / ECMWF IFS · FORECAST": "GFS / ECMWF IFS · ПРОГНОЗ", + "NOAA nowCOAST · OBSERVED": "NOAA nowCOAST · СПОСТЕРЕЖЕННЯ", + "NASA FIRMS · LIVE": "NASA FIRMS · ОНЛАЙН", + "OSM routing": "Маршрутизація OSM", + "data source|Local": "Локальні дані", "ENABLING": "УВІМКНЕННЯ", "DISABLING": "ВИМКНЕННЯ", + "Movement": "Рух", + "Infrastructure": "Інфраструктура", + "Events": "Події", + "Weather": "Погода", + "Utilities": "Інструменти", + "Other layers": "Інші шари", "{state} · {source}": "{state} · {source}", "UNCERTAIN · {source} · lifecycle state requires reconciliation": "НЕВИЗНАЧЕНО · {source} · стан життєвого циклу потребує звірки", "{state} · {source} · {detail} · retry {seconds}s": "{state} · {source} · {detail} · повтор через {seconds} с", "{state} · {source} · {detail}": "{state} · {source} · {detail}", "never": "ніколи", "{source} · {loadingLabel}": "{source} · {loadingLabel}", + "{accepted} of {raw} records accepted": "прийнято записів: {accepted} з {raw}", + "incomplete snapshot": "неповний знімок", + "{state} · {source} · {detail} · {ago}": "{state} · {source} · {detail} · {ago}", "{state} · {source} · {ago} · retrying in {seconds}s": "{state} · {source} · {ago} · повтор через {seconds} с", "{state} · {source} · {ago}": "{state} · {source} · {ago}", "{source} · {ago}": "{source} · {ago}", "UNCERTAIN": "НЕВИЗНАЧЕНО", "status chip|UNAVAILABLE": "НЕДОСТУПНО", + "Data source unavailable": "Джерело даних недоступне", "{name}: {state}": "{name}: {state}", "{count}s ago": "{count} с тому", - "CONNECTING": "З'ЄДНАННЯ", + "Local FM stopped: internet radio started": "Локальний FM зупинено: запущено інтернет-радіо", + "IDLE": "ОЧІКУВАННЯ", + "CONNECTING": "ЗʼЄДНАННЯ", + "TUNING": "НАЛАШТУВАННЯ", + "STREAMING": "ПРИЙМАННЯ", + "UNSUPPORTED": "НЕ ПІДТРИМ.", + "idle": "очікування", + "running": "працює", + "suspended": "призупинено", + "closed": "закрито", + "feed status|live": "онлайн", + "feed status|stale": "застарів", + "feed status|unreachable": "недоступний", + "feed status|invalid": "некоректний", + "waiting for IQ": "очікування IQ", + "{count} messages": { + "one": "{count} повідомлення", + "few": "{count} повідомлення", + "many": "{count} повідомлень", + "other": "{count} повідомлення" + }, + "DSP {count} blocks": { + "one": "DSP {count} блок", + "few": "DSP {count} блоки", + "many": "DSP {count} блоків", + "other": "DSP {count} блоку" + }, + "DSP waiting": "DSP очікує", + "{level} dBFS audio": "аудіо {level} dBFS", + "audio signal --": "аудіосигнал --", + "audio {state}": "аудіо: {state}", + "{count} HEARD": { + "one": "ЧУТНО: {count}", + "few": "ЧУТНО: {count}", + "many": "ЧУТНО: {count}", + "other": "ЧУТНО: {count}" + }, + "DISCONNECT": "ВІДКЛЮЧИТИ", + "CONNECT": "ПІДКЛЮЧИТИ", + "LOCATING…": "ВИЗНАЧЕННЯ…", + "LOCATED": "ВИЗНАЧЕНО", + "LOCATE": "ГЕОПОЗИЦІЯ", + " · read while Local ADS-B is on": " · зчитуються, коли ввімкнено шар «Локальний ADS-B»", + "Decoder feeds: {feeds}": "Потоки декодера: {feeds}", + "Language: {language}": "Мова: {language}", + "Change the interface language": "Змінити мову інтерфейсу", + "Interface language": "Мова інтерфейсу", + "Search languages": "Пошук мови", + "No matching languages": "Відповідних мов немає", "📍 Location: --": "📍 Розташування: --", "Landmark: --": "Орієнтир: --", "Searched location": "Знайдене розташування", "ORBIT": "ОРБІТА", "Location not found": "Розташування не знайдено", + "Check the spelling and press Enter to search again.": "Перевірте написання й натисніть Enter, щоб повторити пошук.", "Search failed": "Пошук не вдався", + "Press Enter to try again.": "Натисніть Enter, щоб спробувати знову.", + "Detailed outline unavailable": "Докладний контур недоступний", "Fly to a POI first": "Спершу полетіть до орієнтира", "Reset to full globe view": "Скинути до загального вигляду глобуса", "Reset cockpit to full globe view": "Скинути кабіну до вигляду всього глобуса", "Resetting to full globe view": "Скидання до вигляду всього глобуса", "Resetting cockpit to full globe view": "Скидання кабіни до вигляду всього глобуса", "MAP": "КАРТА", + "Layers": "Шари", + "Search": "Пошук", + "More": "Ще", + "Panels": "Панелі", "panel": "панель", "Expand {name}": "Розгорнути {name}", "Collapse {name}": "Згорнути {name}", @@ -546,17 +1964,31 @@ "Expand Radio section": "Розгорнути розділ радіо", "Collapse Radio section": "Згорнути розділ радіо", "Panel layout updated — positions reset to new defaults": "Компонування панелей оновлено — позиції скинуто до нових типових", + "Austin": "Остін", + "San Francisco": "Сан-Франциско", + "New York": "Нью-Йорк", + "Tokyo": "Токіо", + "London": "Лондон", + "Paris": "Париж", + "Dubai": "Дубай", + "Washington DC": "Вашингтон", + "Tallinn": "Таллінн", + "Los Angeles": "Лос-Анджелес", "Collapse Cockpit display options": "Згорнути параметри дисплея кабіни", "Expand Cockpit display options": "Розгорнути параметри дисплея кабіни", "Collapse Cockpit Radio controls": "Згорнути керування радіо кабіни", "Expand Cockpit Radio controls": "Розгорнути керування радіо кабіни", + "CH {index} / {total}": "КАН. {index} / {total}", "NO STATIONS": "НЕМАЄ СТАНЦІЙ", "NO STATION AVAILABLE": "НЕМАЄ ДОСТУПНИХ СТАНЦІЙ", "{name}, station {index} of {total}": "{name}, станція {index} з {total}", "No station available": "Немає доступної станції", "OFF AIR": "НЕ В ЕФІРІ", "STATION UNAVAILABLE": "СТАНЦІЯ НЕДОСТУПНА", + "Station unavailable after directory refresh": "Станція недоступна після оновлення каталогу", "Radio could not {action} cleanly": "Радіо: не вдалося коректно {action}", + "Go to expanded Radio section": "Перейти до розгорнутого розділу радіо", + "Expand Radio section in Context": "Розгорнути розділ «Радіо» на панелі «Контекст»", "Close compact Radio controls": "Закрити компактне керування радіо", "Open compact Radio controls": "Відкрити компактне керування радіо", "SYNC": "СИНХР.", @@ -566,46 +1998,196 @@ "Reconcile Radio — lifecycle uncertain": "Звірити радіо — стан життєвого циклу невизначений", "Disable Radio": "Вимкнути радіо", "Enable Radio": "Увімкнути радіо", + "{category} ({count})": "{category} ({count})", "DIRECTORY BAND": "ДІАПАЗОН КАТАЛОГУ", "{category} BAND": "{category} ДІАПАЗОН", "NO STATION SELECTED": "СТАНЦІЮ НЕ ВИБРАНО", "Directory metadata only": "Лише метадані каталогу", "Loading station directory…": "Завантаження каталогу станцій…", - "Choose a globe marker or use next.": "Виберіть маркер на глобусі або натисніть «наступна».", + "Choose a globe marker or use next.": "Виберіть маркер на глобусі або перейдіть до наступної станції.", "TAGS · {tags}": "ТЕГИ · {tags}", "Play": "Відтворити", + "PAUSE": "ПАУЗА", + "RESUME": "ПРОДОВЖ.", "PLAY": "ВІДТВОРИТИ", - "selected": "обрану", + "selected": "вибрану", "nearest": "найближчу", "{action} {target} radio station": "{action} {target} радіостанцію", "RADIO STATE UNCERTAIN": "СТАН РАДІО НЕВИЗНАЧЕНИЙ", "SYNCING DIRECTORY": "СИНХРОНІЗАЦІЯ КАТАЛОГУ", "RADIO READY": "РАДІО ГОТОВЕ", "SYNCING": "СИНХРОНІЗАЦІЯ", - "READY": "ГОТОВА", + "READY": "ГОТОВО", "station": "станція", + " · stale/degraded directory": " · каталог застарів/з перебоями", + " · degraded directory": " · каталог з перебоями", + " · stale directory": " · каталог застарів", + " · outside current filter": " · поза поточним фільтром", "Ready — playback starts only from your action": "Готово — відтворення починається лише за вашою дією", "Radio off": "Радіо вимкнено", - "Connecting directly to broadcaster…": "Пряме з’єднання з мовником…", + "Connecting directly to broadcaster…": "Пряме зʼєднання з мовником…", "Buffering broadcaster stream…": "Буферизація потоку мовника…", "Playing {station}": "Відтворюється: {station}", "Paused {station}": "Пауза: {station}", "Broadcaster stream unavailable": "Потік мовника недоступний", + " · muted during voice interaction": " · приглушено під час голосової сесії", + " · restoring volume after voice": " · відновлення гучності після голосової сесії", + " · static indicates no broadcaster audio": " · шум означає відсутність аудіо мовника", + " · tuning static until broadcaster starts": " · шум налаштування, доки не почнеться мовлення", "Station unavailable after directory refresh — choose another channel": "Станція недоступна після оновлення каталогу — виберіть інший канал", "Radio is enabling…": "Радіо вмикається…", "Radio is disabling…": "Радіо вимикається…", "Radio lifecycle is uncertain — use Enable or Disable to reconcile": "Стан радіо невизначений — звірте через «Увімкнути» або «Вимкнути»", + "Clear reading": "Очистити покази", + "Earlier observation": "Раніше спостереження", + "Observed history": "Історія спостережень", + "Later observation": "Пізніше спостереження", + "Latest": "Останні", + "Newest frame per product": "Найсвіжіший кадр кожного продукту", + "Replay observed history": "Відтворити історію спостережень", + "Imagery on Esri · Google 3D returns when cleared": "Підкладка: Esri · скидання поверне Google 3D", + "Point the camera at the ground to use the view": "Наведіть камеру на землю, щоб використати вигляд", + "That point cannot anchor a box": "Від цієї точки не можна побудувати область", + "Imagery stops at ±{limit}° latitude": "Знімки є лише до ±{limit}° широти", + "{owner} is using the pointer — close it first": "Вказівник зайнятий: «{owner}». Спершу закрийте його", + "Box is {size} wide · limit {limit}": "Область завширшки {size} · межа {limit}", + "View is {size} wide · limit {limit}": "Вигляд завширшки {size} · межа {limit}", + "VS BASEMAP": "З ПІДКЛАДКОЮ", + "A / B": "A / B", + "Newest low-cloud day for this box · scene cloud, not box cloud": "Найсвіжіший малохмарний день для цієї області · хмарність усієї сцени, а не області", + "Newest day covering this box · cloudier than 20%": "Найсвіжіший день із покриттям цієї області · хмарність понад 20%", + "Newest day with imagery for this box · partial coverage": "Найсвіжіший день зі знімками цієї області · часткове покриття", + "Newest daily overview for this box": "Найсвіжіший щоденний огляд для цієї області", + "newest clear day": "найсвіжіший ясний день", + "newest day (cloudy)": "найсвіжіший день (хмарно)", + "newest day (partial coverage)": "найсвіжіший день (часткове покриття)", + "newest overview": "найсвіжіший огляд", + "No imagery": "Немає знімків", + "Loading": "Завантаження", + "coverage|full": "повне", + "coverage|partial": "часткове", + "unknown": "невідомо", + "no imagery": "немає знімків", + "{percent}% cloud": "хмарність {percent}%", + "{min}–{max}% cloud": "хмарність {min}–{max}%", + "NO BOX": "НЕМАЄ ОБЛАСТІ", + "SEARCHING": "ПОШУК", + "{count} DAYS": { + "one": "{count} ДЕНЬ", + "few": "{count} ДНІ", + "many": "{count} ДНІВ", + "other": "{count} ДНЯ" + }, + "Zoom in or draw a smaller box": "Наблизьте карту або виділіть меншу область", + "Select a box or use the view": "Виділіть область або використайте поточний вигляд", + "Searching the last 30 days": "Пошук за останні 30 днів", + "No days to show for this box": "Для цієї області немає чого показати", + "Drag the divider · SWAP trades sides": "Тягніть роздільник · «ПОМІНЯТИ» — зміна сторін", + "← → preview · A or B pins the focused day": "← → перегляд · A або B закріплює вибраний день", + "← → preview the other side · A or B pins it": "← → перегляд іншої сторони · A або B закріплює її", + "S on another day replaces it · × unpins": "S на іншому дні замінює його · × відкріплює", + "← → preview · S shows the focused day": "← → перегляд · S показує вибраний день", + "ZOOM IN": "НАБЛИЗИТИ", + "Fly in until the view fits the 1,000 km limit": "Наближайтеся, доки вигляд не вміститься в межу 1000 км", + "Imagery days, newest first · arrows move, S or A and B pin": "Дні зі знімками, спершу нові · стрілки — переміщення, S або A і B — закріпити", + "On the map": "На карті", + "Mode": "Режим", + "Imagery opacity": "Непрозорість знімків", + "SWAP": "ПОМІНЯТИ", + "Trade the two sides of the divider": "Поміняти місцями сторони роздільника", + "SELECT BOX": "ВИДІЛИТИ", + "Drag a box on the map (Esc cancels)": "Виділіть область на карті (Esc — скасування)", + "USE VIEW": "ЗА ВИГЛЯДОМ", + "Use the current view as the box": "Використати поточний вигляд як область", + "Forget the box and its images": "Скинути область і її знімки", + "START HERE": "ПОЧНІТЬ ТУТ", + "Checking": "Перевірка", + "PREVIEW": "ПЕРЕГЛЯД", + "Newest day with imagery for this box": "Найсвіжіший день зі знімками цієї області", + "SHOW": "ПОКАЗАТИ", + "Pin {day} as {slot}": "Закріпити {day} як {slot}", + "Show {day}": "Показати {day}", + "pinned {slot}": "закріплено як {slot}", + "shown": "показано", + "preview": "перегляд", + "start here": "почніть тут", + "No box": "Немає області", + "Searching": "Пошук", + "Every day is empty here": "Тут усі дні порожні", + "Sources off": "Джерела вимкнено", + "VS": "ПОРІВН.", + "Not set": "Не задано", + "Basemap": "Підкладка", + "Source off": "Джерело вимкнено", + "Unpin {slot}": "Відкріпити {slot}", + "Unpin the image": "Відкріпити знімок", + "EXPORT {slot}": "ЕКСП. {slot}", + "EXPORT": "ЕКСПОРТ", + "Download {slot} as a PNG": "Завантажити {slot} у PNG", + "Download the image as a PNG": "Завантажити знімок у PNG", + "Box {width} × {height} km": "Область {width} × {height} км", + "Acquired {time}": "Знято {time}", + "Coverage {coverage}": "Покриття {coverage}", + "START HERE · {reason}": "ПОЧНІТЬ ТУТ · {reason}", + "Daily overview shows little detail in a box this small": "У такій малій області щоденний огляд майже не показує деталей", + "Imagery: NASA GIBS and Worldview · HLS (Sentinel-2, Landsat 8/9) and VIIRS": "Знімки: NASA GIBS і Worldview · HLS (Sentinel‑2, Landsat 8/9) і VIIRS", + "Details": "Докладно", + "Times, coverage, sources": "Час, покриття, джерела", + "HIDE EMPTY DAYS": "СХОВАТИ ПОРОЖНІ ДНІ", + "SHOW EMPTY DAYS · {count}": "ПОКАЗАТИ ПОРОЖНІ ДНІ · {count}", + "Days the probe found empty in this box": "Дні, у які перевірка не знайшла знімків у цій області", + "image": "знімок", + "BASEMAP": "ПІДКЛАДКА", + "The basemap": "Підкладка", + "basemap": "підкладка", + "Recent imagery against the basemap divider": "Роздільник: свіжі знімки й підкладка", + "Recent imagery A and B divider": "Роздільник свіжих знімків A і B", + "{before} {left} percent, {after} {right} percent": "{before}: {left}%, {after}: {right}%", + "Export failed · {error}": "Помилка експорту · {error}", "Scene action failed": "Не вдалося виконати дію сцени", + "New scene name": "Назва нової сцени", + "Delete scene \"{scene}\" and all shots?": "Видалити сцену «{scene}» і всі кадри?", "Delete shot \"{shot}\"?": "Видалити кадр «{shot}»?", - "SPARSE": "РЕДКИЙ", - "BALANCED": "ЗБАЛАНСОВАНИЙ", + "Stopped (Esc)": "Зупинено (Esc)", + "SPARSE": "РІДКО", + "BALANCED": "ПОМІРНО", + "No shots yet. Use CAPTURE SHOT to save current look.": "Кадрів поки немає. Натисніть «ЗНЯТИ КАДР», щоб зберегти поточний вигляд.", + "Double-click to rename": "Двічі клацніть, щоб перейменувати", + "Shot name": "Назва кадру", + "LOAD": "ЗАВАНТАЖИТИ", "DEL": "ВИДАЛ.", - "entity": "об’єкт", - "Shared {subject} follow expired": "{subject}: ТЕРМІН СТЕЖЕННЯ МИНУВ", - "Shared {subject} could not be restored — feed unavailable": "{subject} НЕ ВДАЛОСЯ ВІДНОВИТИ — КАНАЛ ДАНИХ НЕДОСТУПНИЙ", - "Shared {subject} is unavailable": "{subject}: НЕМАЄ ДОСТУПУ", + "{duration}s + {hold}s": "{duration} с + {hold} с", + "Choose files": "Вибрати файли", + "{count} files selected": { + "one": "Вибрано файлів: {count}", + "few": "Вибрано файлів: {count}", + "many": "Вибрано файлів: {count}", + "other": "Вибрано файлів: {count}" + }, + "No file chosen": "Файли не вибрано", + "Cancel": "Скасувати", + "EDIT DETAILS": "ЗМІНИТИ ПАРАМЕТРИ", + "SHARE SCENE": "ПОДІЛИТИСЯ СЦЕНОЮ", + "Shared flight follow expired": "Термін стеження за рейсом за посиланням минув", + "Shared military flight follow expired": "Термін стеження за військовим рейсом за посиланням минув", + "Shared satellite follow expired": "Термін стеження за супутником за посиланням минув", + "Shared flight could not be restored — feed unavailable": "Не вдалося відновити рейс за посиланням — потік даних недоступний", + "Shared military flight could not be restored — feed unavailable": "Не вдалося відновити військовий рейс за посиланням — потік даних недоступний", + "Shared satellite could not be restored — feed unavailable": "Не вдалося відновити супутник за посиланням — потік даних недоступний", + "Shared flight is unavailable": "Рейс за посиланням недоступний", + "Shared military flight is unavailable": "Військовий рейс за посиланням недоступний", + "Shared satellite is unavailable": "Супутник за посиланням недоступний", + "entity": "обʼєкт", + "Shared {subject} follow expired": "Стеження за посиланням завершено: {subject}", + "Shared {subject} could not be restored — feed unavailable": "Не вдалося відновити за посиланням: {subject} — потік даних недоступний", + "Shared {subject} is unavailable": "Недоступно за посиланням: {subject}", + "{id} isn't reporting now — showing where it was last seen": "{id} зараз не передає даних — показано останнє відоме місце", + "{id} isn't reporting now — showing where it was at {time}": "{id} зараз не передає даних — показано останнє відоме місце ({time})", + "This share link can't be opened": "Не вдається відкрити це посилання", + "Shared vessel is unavailable": "Судно за посиланням недоступне", "ACQUIRING": "ОТРИМАННЯ", - "SHARED {subject}": "ПОДІЛЕНО: {subject}", + "SHARED {subject}": "ЗА ПОСИЛАННЯМ: {subject}", + "subject": "обʼєкт", "LOADING LIVE DATA": "ЗАВАНТАЖЕННЯ ДАНИХ У РЕАЛЬНОМУ ЧАСІ", "LOAD COMPLETE": "ЗАВАНТАЖЕННЯ ЗАВЕРШЕНО", "LOAD CANCELLED": "ЗАВАНТАЖЕННЯ СКАСОВАНО", @@ -614,93 +2196,630 @@ "MAPPED SITES LOADED": "МІСЦЯ НА КАРТІ ЗАВАНТАЖЕНО", "RETRYING MAPPED SITES": "ПОВТОРНЕ ЗАВАНТАЖЕННЯ МІСЦЬ НА КАРТІ", "FETCHING MAPPED SITES": "ЗАВАНТАЖЕННЯ МІСЦЬ НА КАРТІ", + "RETRYING ALPR CAMERAS": "ПОВТОРНЕ ЗАВАНТАЖЕННЯ КАМЕР ALPR", + "FETCHING ALPR CAMERAS": "ЗАВАНТАЖЕННЯ КАМЕР ALPR", + "OVERPASS TEMPORARILY UNAVAILABLE": "OVERPASS ТИМЧАСОВО НЕДОСТУПНИЙ", + "OVERPASS RATE-LIMITED": "OVERPASS: ПЕРЕВИЩЕНО ЛІМІТ ЗАПИТІВ", + "OVERPASS TIMED OUT": "OVERPASS: МИНУВ ЧАС ОЧІКУВАННЯ", + "OVERPASS COULD NOT COMPLETE THE QUERY": "OVERPASS: НЕ ВДАЛОСЯ ЗАВЕРШИТИ ЗАПИТ", + "MAP TILES TEMPORARILY UNAVAILABLE": "ТАЙЛИ КАРТИ ТИМЧАСОВО НЕДОСТУПНІ", + "MAPPED NAMES TEMPORARILY UNAVAILABLE": "НАЗВИ ОБʼЄКТІВ ТИМЧАСОВО НЕДОСТУПНІ", "TURNING OFF LIVE DATA": "ВИМКНЕННЯ ДАНИХ У РЕАЛЬНОМУ ЧАСІ", "REFRESHING LIVE DATA": "ОНОВЛЕННЯ ДАНИХ У РЕАЛЬНОМУ ЧАСІ", "syncing road network": "синхронізація дорожньої мережі", + "retry pending": "очікується повтор", + "retrying in {seconds}s": "повтор через {seconds} с", + "ALPR cameras": "камери ALPR", + "OpenSky OAuth client missing/invalid": "Клієнт OAuth OpenSky відсутній або недійсний", + "OpenSky OAuth rejected credentials": "OpenSky OAuth відхилив облікові дані", + "OpenSky username/password rejected": "OpenSky відхилив імʼя користувача або пароль", + "OpenSky auth missing": "Немає даних для входу в OpenSky", + "OpenSky auth required": "OpenSky вимагає входу", + "OpenSky auth invalid": "Неправильні дані для входу в OpenSky", + "OpenSky auth failed": "Не вдалося увійти в OpenSky", + "KartaView answered HTTP {status}": "KartaView відповів: HTTP {status}", + "Panoramax answered HTTP {status}": "Panoramax відповів: HTTP {status}", + "KartaView refused the request (code {code})": "KartaView відхилив запит (код {code})", + "Vector tiles unavailable (HTTP {status})": "Векторні тайли недоступні (HTTP {status})", + "GNSS feed unavailable (HTTP {status})": "Потік GNSS недоступний (HTTP {status})", + "{count} CelesTrak groups unavailable": { + "one": "{count} група CelesTrak недоступна", + "few": "{count} групи CelesTrak недоступні", + "many": "{count} груп CelesTrak недоступні", + "other": "{count} групи CelesTrak недоступні" + }, + "{feed} feed unavailable": "Потік {feed} недоступний", + "Source snapshot {minutes} min old": "Вік знімка джерела: {minutes} хв", + "{source} rate limited (anonymous)": "{source}: ліміт запитів (анонімно)", + "{source} rate limited": "{source}: ліміт запитів", + "{source} network error": "{source}: помилка мережі", + "Malformed {source} aircraft rows": "{source}: некоректні записи про літаки", + "Malformed {source} response": "{source}: некоректна відповідь", + "entry {n}": "№ {n}", + "feeds {names} stale": { + "one": "потік {names} застарів", + "few": "потоки {names} застаріли", + "many": "потоки {names} застаріли", + "other": "потоки {names} застаріли" + }, + "feeds {names} unreachable": { + "one": "потік {names} недоступний", + "few": "потоки {names} недоступні", + "many": "потоки {names} недоступні", + "other": "потоки {names} недоступні" + }, + "feeds {names} invalid": { + "one": "потік {names} некоректний", + "few": "потоки {names} некоректні", + "many": "потоки {names} некоректні", + "other": "потоки {names} некоректні" + }, + "Loading {feeds}": "Завантаження: {feeds}", + "{count} heard": { + "one": "чутно бортів: {count}", + "few": "чутно бортів: {count}", + "many": "чутно бортів: {count}", + "other": "чутно бортів: {count}" + }, + "USB {rate} msg/s": "USB {rate} повід./с", + "{rate} msg/s": "{rate} повід./с", + "{count} feeds live": { + "one": "{count} потік онлайн", + "few": "{count} потоки онлайн", + "many": "{count} потоків онлайн", + "other": "{count} потоку онлайн" + }, + "{feed} {count} ({seconds}s old)": "{feed} {count} ({seconds} с тому)", + "Street Level toggle failed": "Не вдалося перемкнути «Вуличні знімки»", + "Street Level could not start": "Не вдалося запустити «Вуличні знімки»", + "SHRINK": "ЗГОРНУТИ", + "EXPAND": "РОЗГОРНУТИ", + "Shrink": "Згорнути", + "Expand": "Розгорнути", + "ANY DATE": "БУДЬ-ЯКА ДАТА", + "LAST 10 YEARS": "ЗА 10 РОКІВ", + "LAST 5 YEARS": "ЗА 5 РОКІВ", + "LAST 3 YEARS": "ЗА 3 РОКИ", + "LAST 2 YEARS": "ЗА 2 РОКИ", + "LAST YEAR": "ЗА РІК", + "LAST 6 MONTHS": "ЗА 6 МІСЯЦІВ", + "LAST 3 MONTHS": "ЗА 3 МІСЯЦІ", + "LAST MONTH": "ЗА МІСЯЦЬ", + "LAST {count} DAYS": { + "one": "ЗА {count} ДЕНЬ", + "few": "ЗА {count} ДНІ", + "many": "ЗА {count} ДНІВ", + "other": "ЗА {count} ДНЯ" + }, + "{window} · SINCE {date}": "{window} · З {date}", + "Turn Street Level off": "Вимкнути «Вуличні знімки»", + "Turn Street Level on": "Увімкнути «Вуличні знімки»", + "{name} imagery on": "Знімки {name} увімкнено", + "{name} imagery off": "Знімки {name} вимкнено", + "Image by {creator}": "Автор знімка: {creator}", + " or ": " або ", + "OPEN {labels}": "ВІДКРИТИ {labels}", + "Open {names} at the centre of the view": "Відкрити {names} у центрі вигляду", + "Zoom in to a street to open {names} here": "Наблизьтеся до вулиці, щоб відкрити тут {names}", + "Switch Street Level on to draw its coverage.": "Увімкніть «Вуличні знімки», щоб показати покриття.", + "Every provider is switched off: light a chip to draw its coverage.": "Усі джерела вимкнено: увімкніть одне, щоб показати його покриття.", + "Loading this sequence…": "Завантаження послідовності…", + "{n} images in this sequence · Esc clears": { + "one": "{n} знімок у послідовності · Esc — скинути", + "few": "{n} знімки в послідовності · Esc — скинути", + "many": "{n} знімків у послідовності · Esc — скинути", + "other": "{n} знімка в послідовності · Esc — скинути" + }, + "No sequences in view match the filter": "Жодна послідовність у кадрі не відповідає фільтру", + "No coverage in view": "У кадрі немає покриття", + "{n} streets in view · click a line for its nearest photo": { + "one": "{n} вулиця в кадрі · клацніть лінію, щоб відкрити найближче фото", + "few": "{n} вулиці в кадрі · клацніть лінію, щоб відкрити найближче фото", + "many": "{n} вулиць у кадрі · клацніть лінію, щоб відкрити найближче фото", + "other": "{n} вулиці в кадрі · клацніть лінію, щоб відкрити найближче фото" + }, + "{n} sequences in view · click a line for its nearest photo": { + "one": "{n} зйомка в кадрі · клацніть лінію, щоб відкрити найближче фото", + "few": "{n} зйомки в кадрі · клацніть лінію, щоб відкрити найближче фото", + "many": "{n} зйомок у кадрі · клацніть лінію, щоб відкрити найближче фото", + "other": "{n} зйомки в кадрі · клацніть лінію, щоб відкрити найближче фото" + }, + "{n} sequences in view · click a line for its photos": { + "one": "{n} послідовність у кадрі · клацніть лінію, щоб відкрити знімки", + "few": "{n} послідовності в кадрі · клацніть лінію, щоб відкрити знімки", + "many": "{n} послідовностей у кадрі · клацніть лінію, щоб відкрити знімки", + "other": "{n} послідовності в кадрі · клацніть лінію, щоб відкрити знімки" + }, + "km/h": "км/год", + "m/s": "м/с", + "mph": "миль/год", + "hPa": "гПа", + "kt": "вуз", + "kts": "вуз", + "ft": "фт", + "km": "км", + "m": "м", + "h": "год", + "min": "хв", + "s": "с", + "dB": "дБ", "Celestial ring — reveal the full globe": "Небесне кільце — показати весь глобус", "Celestial ring — available in Normal style": "Небесне кільце — доступне у стилі «Звичайний»", "Detection overlay: {mode}": "Накладка виявлення: {mode}", "Detection overlay: off": "Накладка виявлення: вимк.", "DETECT": "ВИЯВЛЕННЯ", - "voice|OFF": "ВИМКНЕНО", - "voice|CONNECTING": "З'ЄДНАННЯ", + "{time} · {minutes} min ago": "{time} · {minutes} хв тому", + "Active weather": "Активні погодні шари", + "LATEST · newest per product": "ОСТАННІ · найсвіжіші для кожного продукту", + "Forecast · valid {valid} · issued {issued}": "Прогноз · чинний на {valid} · випущено {issued}", + "{detail} · Does not follow history": "{detail} · не йде за історією", + "Forecast · valid {valid}": "Прогноз · чинний на {valid}", + "voice|OFF": "ВИМК.", + "voice|CONNECTING": "ЗʼЄДНАННЯ", "voice|LISTENING": "СЛУХАЮ", "voice|EXECUTING": "ВИКОНАННЯ", "voice|ERROR": "ПОМИЛКА", - "AI AGENT": "АГЕНТ ШІ", - "Voice model tier — applies next session": "Рівень голосової моделі — набуде чинності з наступної сесії", + "Voice provider": "Постачальник голосового сервісу", + "Changing provider reconnects voice if it is on.": "Зміна постачальника перепідключає голосовий режим, якщо його ввімкнено.", + "Voice Settings": "Налаштування голосу", + "AI AGENT": "ШІ-АГЕНТ", + "Voice model tier — applies next session": "Рівень голосової моделі — застосовується з наступної сесії", + "STD": "СТД", "Estimated session cost": "Орієнтовна вартість сесії", "Voice control — activate to toggle voice; hold Space to speak": "Голосове керування — активуйте, щоб увімкнути або вимкнути голос; утримуйте Space, щоб говорити", - "VOICE STANDBY": "ГОЛОСОВЕ ОЧІКУВАННЯ", + "ON/OFF": "УВІМК/ВИМК", + "VOICE STANDBY": "ГОЛОС ОЧІКУЄ", "VOICE CONTROL": "ГОЛОСОВЕ КЕРУВАННЯ", - "Hold Space to speak · tap Space to activate focused controls": "Утримуйте Space, щоб говорити · тапніть Space, щоб активувати елемент у фокусі", + "Hold Space to speak · tap Space to activate focused controls": "Утримуйте Space, щоб говорити · натисніть Space, щоб активувати елемент у фокусі", + "VOICE": "ГОЛОС", + "Preview": "Попередній перегляд", + "Settings": "Налаштування", + "Close voice panel": "Закрити голосову панель", + "Voice replies appear here.": "Тут зʼявляються голосові відповіді.", + "Voice assistant": "Голосовий асистент", + "Dismiss voice card": "Закрити картку голосу", + "YOU": "ВИ", + "THIS": "ЦЕ", + "Plan": "План", + "Referenced items": "Згадані обʼєкти", + "NOTES & SOURCES": "НОТАТКИ Й ДЖЕРЕЛА", + "Show Voice Preview": "Показувати попередній перегляд голосу", + "Voice inactivity timeout": "Тайм-аут бездіяльності голосу", + "Minutes": "Хвилини", + "Custom": "Інше", + "These preferences stay in this browser.": "Ці налаштування зберігаються в цьому браузері.", "VOICE SYSTEM ERROR": "ПОМИЛКА ГОЛОСОВОЇ СИСТЕМИ", "DISMISS": "ЗАКРИТИ", "Check microphone permission and network access, then try again.": "Перевірте дозвіл на мікрофон і доступ до мережі, потім спробуйте ще раз.", + "Gemini returned an oversized audio chunk": "Gemini повернув надто великий фрагмент аудіо", + "Gemini returned an unsupported audio format": "Gemini повернув непідтримуваний формат аудіо", + "Gemini returned an invalid audio sample rate": "Gemini повернув неприпустиму частоту дискретизації аудіо", + "Gemini returned incomplete PCM audio": "Gemini повернув неповні аудіодані PCM", + "This browser does not support Gemini microphone audio": "Цей браузер не підтримує звук із мікрофона для Gemini", + "Microphone audio processing failed": "Не вдалося обробити звук із мікрофона", + "Gemini audio playback fell behind. Reconnect to continue.": "Відтворення звуку Gemini відстає. Підключіться знову, щоб продовжити.", + "Gemini token response did not include an ephemeral credential": "У відповіді Gemini немає тимчасових облікових даних", + "Invalid Gemini connection endpoint": "Неприпустима адреса підключення до Gemini", + "Gemini voice could not connect. Try again.": "Не вдалося підключити голосовий режим Gemini. Спробуйте ще раз.", + "Gemini voice requires a same-origin app request": "Голосовий режим Gemini потребує запиту з того самого джерела, що й застосунок", + "Add a Gemini API key in Provider Settings": "Додайте ключ API Gemini в «Налаштуваннях постачальників»", + "The Gemini Live model configuration is invalid": "Неприпустима конфігурація моделі Gemini Live", + "Gemini voice is starting too often. Try again shortly.": "Голосовий режим Gemini запускається надто часто. Спробуйте трохи згодом.", + "Gemini quota is unavailable. Try again later.": "Квота Gemini недоступна. Спробуйте пізніше.", + "Gemini access was refused. Check the API key and model access.": "Доступ до Gemini заборонено. Перевірте ключ API й доступ до моделі.", + "Gemini Live is unavailable for the configured model.": "Gemini Live недоступний для вибраної моделі.", + "Token request is too large": "Запит токена надто великий", + "Use an empty JSON token request": "Використовуйте запит токена з порожнім обʼєктом JSON", "Release Space to send": "Відпустіть Space, щоб надіслати", "Hold Space to talk": "Утримуйте Space, щоб говорити", + "Voice command context is too large": "Контекст голосової команди надто великий", + "Gemini reliable transport exceeded its queue limit. Start voice again.": "Черга надійного передавання Gemini перевищила ліміт. Запустіть голосовий режим знову.", + "Gemini reliable transport did not drain. Start voice again.": "Черга надійного передавання Gemini не звільнилася. Запустіть голосовий режим знову.", + "Gemini token request failed (HTTP {status})": "Не вдалося запитати токен Gemini (HTTP {status})", + "Gemini token response did not include a valid model": "У відповіді Gemini немає допустимої моделі", + "Gemini token response did not include session settings": "У відповіді Gemini немає налаштувань сеансу", + "Gemini session settings do not match the input mode": "Налаштування сеансу Gemini не відповідають режиму введення", "Requesting microphone": "Запит доступу до мікрофона", + "Gemini could not submit this input. Start voice again.": "Gemini не вдалося надіслати ці дані. Запустіть голосовий режим знову.", + "Connecting to Gemini": "Підключення до Gemini", "Ask or command": "Питання або команда", + "Gemini returned an oversized message": "Gemini повернув надто велике повідомлення", + "Gemini Live connection failed. Check network access, then start voice again.": "Не вдалося підключитися до Gemini Live. Перевірте доступ до мережі й запустіть голосовий режим знову.", + "Gemini Live connection ended. Start voice again for a new conversation.": "Зʼєднання з Gemini Live завершено. Запустіть голосовий режим знову для нової розмови.", + "Gemini Live could not start. Start voice again to request a fresh session.": "Не вдалося запустити Gemini Live. Запустіть голосовий режим знову, щоб запитати новий сеанс.", + "Start voice again for a fresh token and a new conversation.": "Запустіть голосовий режим знову, щоб отримати новий токен і почати нову розмову.", + "Start voice again to request a fresh session credential.": "Запустіть голосовий режим знову, щоб запитати нові облікові дані сеансу.", + "Microphone permission was denied. Allow microphone access and try again.": "Доступ до мікрофона заборонено. Дозвольте доступ і спробуйте ще раз.", + "Gemini connection timed out. Try again.": "Минув час очікування підключення до Gemini. Спробуйте ще раз.", + "Gemini voice could not start": "Не вдалося запустити голосовий режим Gemini", + "Gemini did not finish the interrupted reply. Start voice again.": "Gemini не завершив перервану відповідь. Запустіть голосовий режим знову.", + "Gemini session expiring; finishing the current reply": "Сеанс Gemini спливає; завершується поточна відповідь", + "Gemini rejected the voice session. Start voice again to request a fresh session.": "Gemini відхилив голосовий сеанс. Запустіть голосовий режим знову, щоб запитати новий сеанс.", + "Start voice again for a fresh session credential. If it repeats, check Gemini model and API access.": "Запустіть голосовий режим знову, щоб отримати нові облікові дані. Якщо помилка повториться, перевірте модель Gemini і доступ до API.", + "Gemini action history is full. Start voice again for a fresh session.": "Історія дій Gemini заповнена. Запустіть голосовий режим знову для нового сеансу.", + "Gemini requested too many simultaneous actions": "Gemini запросив забагато одночасних дій", "Running command": "Виконання команди", + "Voice text command is too long": "Текст голосової команди задовгий", + "Gemini voice is not connected": "Голосовий режим Gemini не підключено", + "Gemini interrupted input exceeded its buffer or wait limit. Start voice again.": "Перерване введення Gemini перевищило ліміт буфера або очікування. Запустіть голосовий режим знову.", + "Gemini Live connection is expiring. Start voice again for a new conversation.": "Зʼєднання з Gemini Live спливає. Запустіть голосовий режим знову для нової розмови.", "Voice off": "Голос вимкнено", + "Gemini voice sessions have a time limit. When a session expires, start voice again for a new conversation.": "Час голосових сеансів Gemini обмежений. Коли сеанс спливе, запустіть голосовий режим знову для нової розмови.", + "Stopped by voice": "Зупинено голосовою командою", + "Automatic stop is unavailable for this voice connection.": "Автоматична зупинка недоступна для цього голосового підключення.", + "Preview is off.": "Попередній перегляд вимкнено.", + "Your choice applies now, but could not be saved.": "Ваш вибір застосовано, але зберегти його не вдалося.", "WebRTC microphone support unavailable": "Підтримка мікрофона WebRTC недоступна", "VOICE UNAVAILABLE": "ГОЛОС НЕДОСТУПНИЙ", "VOICE ACTIVE": "ГОЛОС АКТИВНИЙ", "Voice session could not be started.": "Не вдалося запустити голосову сесію.", + "MINI": "МІНІ", "Next session: {pendingId} — this session stays on {modelId}": "Наступна сесія: {pendingId} — поточна залишається на {modelId}", - "Voice model: {pendingId} — click to switch to {target}; applies next session": "Голосова модель: {pendingId} — натисніть, щоб перейти на {target}; набуде чинності з наступної сесії", + "Voice model: {pendingId} — click to switch to {target}; applies next session": "Голосова модель: {pendingId} — натисніть, щоб перейти на {target}; застосовується з наступної сесії", + "standard": "стандартну", + "mini": "міні", + "COST UNKNOWN": "ВАРТІСТЬ НЕВІДОМА", + "ChatGPT OAuth session: {responses} response(s), {input} input and {output} output tokens, {captions} caption transcription(s) reported.": "Сесія ChatGPT OAuth: відповідей — {responses}, вхідних токенів — {input}, вихідних токенів — {output}, транскрипцій субтитрів — {captions}.", + "USD cost and the API spend cap are unavailable for this auth mode.": "Вартість у USD і ліміт витрат API недоступні в цьому режимі авторизації.", + "Usage is incomplete because a response was still in flight when the session ended.": "Дані про використання неповні: на момент завершення сесії одну з відповідей ще не було отримано.", "Estimated session cost on {modelId} — {responses} response(s). Warns at {warn}, ends the session at {cap}.": "Орієнтовна вартість сесії на {modelId} — відповідей: {responses}. Попереджає при {warn}, завершує сесію при {cap}.", - "{tier} applies next session": "{tier} набуде чинності з наступної сесії", + "Estimate is incomplete — a response was still in flight when the session ended, so its usage was never reported.": "Оцінка неповна: на момент завершення сесії одну з відповідей ще не було отримано, тому її використання не враховано.", + "STANDARD": "СТАНДАРТ", + "{tier} applies next session": "{tier} застосовується з наступної сесії", "Session ended — cost cap {cost}": "Сесію завершено — ліміт витрат {cost}", + "MIC": "МІК", "Radio did not start": "Радіо не запустилося", + "{n} aircraft": { + "one": "{n} літак", + "few": "{n} літаки", + "many": "{n} літаків", + "other": "{n} літака" + }, + "{n} military aircraft": { + "one": "{n} військовий літак", + "few": "{n} військові літаки", + "many": "{n} військових літаків", + "other": "{n} військового літака" + }, + "{n} ships": { + "one": "{n} судно", + "few": "{n} судна", + "many": "{n} суден", + "other": "{n} судна" + }, + "{n} satellites": { + "one": "{n} супутник", + "few": "{n} супутники", + "many": "{n} супутників", + "other": "{n} супутника" + }, + "{n} launches": { + "one": "{n} запуск", + "few": "{n} запуски", + "many": "{n} запусків", + "other": "{n} запуску" + }, + "{n} earthquakes": { + "one": "{n} землетрус", + "few": "{n} землетруси", + "many": "{n} землетрусів", + "other": "{n} землетрусу" + }, + "{n} fires": { + "one": "{n} пожежа", + "few": "{n} пожежі", + "many": "{n} пожеж", + "other": "{n} пожежі" + }, + "{n} fire perimeters": { + "one": "{n} контур пожежі", + "few": "{n} контури пожеж", + "many": "{n} контурів пожеж", + "other": "{n} контуру пожеж" + }, + "{n} cyclones": { + "one": "{n} циклон", + "few": "{n} циклони", + "many": "{n} циклонів", + "other": "{n} циклону" + }, + "{n} buses": { + "one": "{n} автобус", + "few": "{n} автобуси", + "many": "{n} автобусів", + "other": "{n} автобуса" + }, + "{n} bike share": { + "one": "{n} станція прокату велосипедів", + "few": "{n} станції прокату велосипедів", + "many": "{n} станцій прокату велосипедів", + "other": "{n} станції прокату велосипедів" + }, + "{n} flock cameras": { + "one": "{n} камера ALPR", + "few": "{n} камери ALPR", + "many": "{n} камер ALPR", + "other": "{n} камери ALPR" + }, + "{n} military bases": { + "one": "{n} військова база", + "few": "{n} військові бази", + "many": "{n} військових баз", + "other": "{n} військової бази" + }, + "{n} datacenters": { + "one": "{n} дата-центр", + "few": "{n} дата-центри", + "many": "{n} дата-центрів", + "other": "{n} дата-центру" + }, + "{n} dams": { + "one": "{n} гребля", + "few": "{n} греблі", + "many": "{n} гребель", + "other": "{n} греблі" + }, + "{n} air quality": { + "one": "{n} станція якості повітря", + "few": "{n} станції якості повітря", + "many": "{n} станцій якості повітря", + "other": "{n} станції якості повітря" + }, + "{n} results": { + "one": "{n} результат", + "few": "{n} результати", + "many": "{n} результатів", + "other": "{n} результату" + }, + "anywhere in the loaded data": "в усіх завантажених даних", + "in view": "у кадрі", + "within {radius} of the view centre": "у радіусі {radius} від центру вигляду", + "within {radius} of {place} (Contacts window)": "у радіусі {radius} — {place} (вікно «Контактів»)", + "within {radius} of {place}": "у радіусі {radius} — {place}", + "within {radius}": "у радіусі {radius}", + "over {region}": "у регіоні {region}", + "At least {items}": "{items} або більше", + "{items} {scope}": "{items} {scope}", + "last 24 h": "за останні 24 год", + "past 30 d and upcoming": "за останні 30 дн і майбутні", + "the flights layer loads by viewport": "шар рейсів завантажується за областю вигляду", + "distance is ground distance, not overhead": "відстань — поверхнею землі до підсупутникової точки, а не до самого апарата", + "the count is a lower bound because at least one layer reached its retained limit.": "це нижня межа: принаймні один шар досяг ліміту збережених записів.", + "{label} off": "{label}: вимк.", + "{label} loading": "{label}: завантаження", + "{label} error": "{label}: помилка", + "counted the first {returned} loaded records": "враховано лише перші завантажені записи: {returned}", + "counted {returned} of {total} loaded records": "враховано завантажених записів: {returned} з {total}", + "{layers} just turned on — still loading, counts will rise": "{layers}: щойно ввімкнено — дані ще завантажуються, значення зростуть", + "Contacts panel snapshot at {time} — the same retained cohort supplies the card, speech, and follow-up memory": "Знімок панелі «Контакти» ({time}) — та сама збережена вибірка використовується для картки, мовлення й памʼяті уточнювальних запитань", + "Contacts panel snapshot — the same retained cohort supplies the card, speech, and follow-up memory": "Знімок панелі «Контакти» — та сама збережена вибірка використовується для картки, мовлення й памʼяті уточнювальних запитань", + "Fly below {km} km to a covered region": "Опустіться нижче {km} км над регіоном із покриттям", + "No feed here yet · {n} regions available": { + "one": "Тут поки немає потоку даних · доступний {n} регіон", + "few": "Тут поки немає потоку даних · доступні {n} регіони", + "many": "Тут поки немає потоку даних · доступно {n} регіонів", + "other": "Тут поки немає потоку даних · доступно {n} регіону" + }, + "degraded": "з перебоями", + "stale": "застарів", + "partial": "частково", + "fallback": "резерв", + "unavailable": "недоступний", + "Not answered: {layers}": "Немає відповіді: {layers}", + "Toggle voice control": "Увімкнути або вимкнути голосове керування", + "Activate to toggle voice": "Активуйте, щоб увімкнути або вимкнути голос", + "Voice active": "Голос активний", + "Voice could not be started.": "Не вдалося запустити голос.", + "the active voice session": "активна голосова сесія", + "{value} feet": "{value} фт", + "Fire · FRP {frp} MW": "Пожежа · FRP {frp} МВт", + "The flights layer is not enabled": "Шар рейсів не ввімкнено", + "The military layer is not enabled": "Шар військових рейсів не ввімкнено", + "The satellites layer is not enabled": "Шар супутників не ввімкнено", + "The ais-live-vessels layer is not enabled": "Шар суден AIS не ввімкнено", + "Could not enable the requested layer": "Не вдалося ввімкнути запитаний шар", + "Could not disable the requested layer": "Не вдалося вимкнути запитаний шар", + "Radio layer unavailable": "Шар радіо недоступний", + "Camera navigation is unavailable in the current view": "Керування камерою недоступне в поточному вигляді", + "Camera navigation policy unavailable": "Правила навігації камери недоступні", + "Nearest-aircraft selection supports Flights or Military Flights only": "Вибір найближчого літака працює лише для рейсів і військових рейсів", + "Nearest-aircraft selection needs a preset, place name, or latitude and longitude": "Для вибору найближчого літака потрібен пресет, назва місця або широта й довгота", + "Could not arrive at the requested place": "Не вдалося долетіти до запитаного місця", + "The nearest airborne aircraft could not be selected": "Не вдалося вибрати найближчий літак у повітрі", + "No flights within {radius} of the current view": "У радіусі {radius} від поточного вигляду немає рейсів", + "No military within {radius} of the current view": "У радіусі {radius} від поточного вигляду немає військових рейсів", + "No satellites within {radius} of the current view": "У радіусі {radius} від поточного вигляду немає супутників", + "No vessels within {radius} of the current view": "У радіусі {radius} від поточного вигляду немає суден", + "{layer} is enabled on the {source} feed, but no airborne aircraft is loaded in the {place} view yet": "{layer}: увімкнено (потік {source}), але у вигляді «{place}» ще не завантажено жодного літака в повітрі", + "{layer} is enabled, but no airborne aircraft is loaded in the {place} view yet": "{layer}: увімкнено, але у вигляді «{place}» ще не завантажено жодного літака в повітрі", + "{layer} is enabled, but its aircraft feed is unavailable": "{layer}: увімкнено, але потік даних про літаки недоступний", + "{layer} is enabled, but its destination refresh did not complete": "{layer}: увімкнено, але оновлення в точці призначення не завершилося", + "{layer} is enabled, but {source} is unavailable": "{layer}: увімкнено, але джерело {source} недоступне", + "Could not arrive at {place}": "Не вдалося долетіти: {place}", + "{name} is no longer loaded": "{name}: обʼєкт більше не завантажено", + "Unknown target layer: {target}": "Невідомий шар цілі: {target}", + "nominal": "у нормі", + "{label} on": "{label}: увімк.", + "Frame aircraft": "Показати літаки в кадрі", + "Frame military aircraft": "Показати військові літаки в кадрі", + "Frame ships": "Показати судна в кадрі", + "Frame satellites": "Показати супутники в кадрі", + "Frame contacts": "Показати контакти в кадрі", + "{count} aircraft in frame": { + "one": "{count} літак у кадрі", + "few": "{count} літаки в кадрі", + "many": "{count} літаків у кадрі", + "other": "{count} літака в кадрі" + }, + "{count} military aircraft in frame": { + "one": "{count} військовий літак у кадрі", + "few": "{count} військові літаки в кадрі", + "many": "{count} військових літаків у кадрі", + "other": "{count} військового літака в кадрі" + }, + "{count} ships in frame": { + "one": "{count} судно в кадрі", + "few": "{count} судна в кадрі", + "many": "{count} суден у кадрі", + "other": "{count} судна в кадрі" + }, + "{count} satellites in frame": { + "one": "{count} супутник у кадрі", + "few": "{count} супутники в кадрі", + "many": "{count} супутників у кадрі", + "other": "{count} супутника в кадрі" + }, + "{count} contacts in frame": { + "one": "{count} контакт у кадрі", + "few": "{count} контакти в кадрі", + "many": "{count} контактів у кадрі", + "other": "{count} контакту в кадрі" + }, + "Nearest military aircraft": "Найближчі військові літаки", + "Nearest ships": "Найближчі судна", + "Nearest satellites": "Найближчі супутники", + "Nearest aircraft": "Найближчі літаки", + "{first} and {second}": "{first} і {second}", + "Layer": "Шар", + "there": "там", + "Camera range {range}": "Дальність камери: {range}", + "Within {radius} of the view": "У радіусі {radius} від вигляду", + "Labels on": "Підписи ввімкнено", + "Framing uses the nearest 80 loaded contacts": "У кадр потрапляють 80 найближчих завантажених контактів", + "{distance} from {location}": "{location}: {distance}", + "Altitude {altitude}": "Висота {altitude}", + "{origin} to {destination}": "{origin} → {destination}", + "from {origin}": "звідки: {origin}", + "to {destination}": "куди: {destination}", + "Registration {registration}": "Реєстраційний номер: {registration}", + "View state": "Стан вигляду", + "Marked {count} places": { + "one": "Позначено {count} місце", + "few": "Позначено {count} місця", + "many": "Позначено {count} місць", + "other": "Позначено {count} місця" + }, + "Nothing marked": "Нічого не позначено", + "Not found: {places}": "Не знайдено: {places}", + "Tracing outlines": "Побудова контурів", + "Frame flights": "Показати літаки в кадрі", + "Frame military": "Показати військові літаки в кадрі", + "Frame vessels": "Показати судна в кадрі", + "Frame {target}": "Показати в кадрі: {target}", + "Zoom out to globe": "Віддалити до глобуса", + "Open data layers": "Відкрити шари даних", + "Open or close a panel": "Відкрити або закрити панель", + "Change context mode": "Змінити режим контексту", + "Control cockpit": "Керувати кабіною", + "Change visual style": "Змінити візуальний стиль", + "Adjust HUD": "Налаштувати HUD", + "Adjust cyber sonar": "Налаштувати кібер-сонар", + "Adjust detection overlay": "Налаштувати накладку виявлення", + "Change map stack": "Змінити набір карт", + "Adjust post-processing": "Налаштувати постобробку", + "Control scene": "Керувати сценою", + "Control CCTV": "Керувати камерами CCTV", + "Control radio": "Керувати радіо", + "Track contact": "Стежити за контактом", + "Stop tracking": "Припинити стеження", + "Clear marks": "Прибрати позначки", + "Move camera": "Перемістити камеру", + "Fly route": "Пролетіти маршрутом", + "Analyst query": "Аналітичний запит", + "Next ISS pass": "Наступний проліт МКС", + "Next satellite pass": "Наступний проліт супутника", + "Mark the map": "Позначити на карті", + "Mark {targets} +{more}": "Позначити {targets} +{more}", + "Mark {targets}": "Позначити {targets}", + "Fly to {place}": "Переліт: {place}", + "Fly to Location": "Переліт до місця", + "Nearest aircraft to {place}": "Найближчий літак: {place}", + "Nearest aircraft to Here": "Найближчий літак тут", + "Layer on": "Шар: увімк.", + "Layer off": "Шар: вимк.", + "Zoom out": "Віддалити", + "Zoom in": "Наблизити", + "Read the view": "Оглянути видиму область", + "Check view state": "Перевірити стан вигляду", + "Action": "Дія", + "Finding places": "Пошук місць", + "Tracing outline": "Побудова контуру", + "Looking up place": "Пошук місця", + "Flying": "Переліт", + "Turning on layer": "Увімкнення шару", + "Loading aircraft": "Завантаження літаків", + "Picking nearest": "Вибір найближчих", + "Working": "Виконується", + "in progress": "виконується", + "done": "готово", + "failed": "помилка", + "cancelled": "скасовано", + "Outline traced": "Контур побудовано", + "Outline unavailable": "Контур недоступний", + "Source: {label}": "Джерело: {label}", + "WORKING": "У РОБОТІ", + "DONE": "ГОТОВО", + "Recent speech": "Нещодавнє мовлення", + "HERE": "ТУТ", "Aircraft cockpit view": "Вигляд кабіни повітряного судна", "LEVEL": "РІВЕНЬ", "Estimated destination direction": "Орієнтовний напрямок до пункту призначення", - "DEST ---°": "DEST ---°", + "DEST ---°": "ПРИЗН. ---°", "OPTICAL PLANE · 01": "ОПТИЧНА ПЛОЩИНА · 01", "VISOR LOCK · ACTIVE": "ФІКСАЦІЯ ВІЗОРА · АКТИВНА", - "GROUND SPEED · KTS": "ШВИДКІСТЬ · KTS", - "ALTITUDE · FT": "ВИСОТА · FT", + "GROUND SPEED · KTS": "ШЛЯХОВА ШВИДКІСТЬ · ВУЗ", + "ALTITUDE · FT": "ВИСОТА · ФТ", "FIRST PERSON": "ВІД ПЕРШОЇ ОСОБИ", - "LIVE TRACK · COURSE ALIGNED": "ТРЕК У РЕАЛЬНОМУ ЧАСІ · КУРС ВИРІВНЯНО", + "LIVE TRACK · COURSE ALIGNED": "ТРЕК ОНЛАЙН · КУРС ВИРІВНЯНО", "Cockpit vision style": "Стиль бачення кабіни", "Previous cockpit vision style": "Попередній стиль бачення кабіни", "Previous vision style": "Попередній стиль бачення", - "Current cockpit vision style: NORMAL. Activate for next style.": "Поточний стиль бачення кабіни: NORMAL. Активуйте для наступного стилю.", - "Current style: NORMAL — click for next": "Поточний стиль: NORMAL — клацніть для наступного", + "Current cockpit vision style: NORMAL. Activate for next style.": "Поточний стиль бачення кабіни: ЗВИЧАЙНИЙ. Активуйте для наступного стилю.", + "Current style: NORMAL — click for next": "Поточний стиль: ЗВИЧАЙНИЙ — клацніть для наступного", "CURRENT": "ПОТОЧНИЙ", "Next cockpit vision style": "Наступний стиль бачення кабіни", "Next vision style": "Наступний стиль бачення", "Current aircraft heading": "Поточний курс повітряного судна", - "GROUND SPEED": "ШВИДКІСТЬ", + "GROUND SPEED": "ШЛЯХОВА ШВИДКІСТЬ", + "KTS": "ВУЗ", "ALTITUDE": "ВИСОТА", - "Contact cockpit summary": "Зведення контакта в кабіні", + "FT": "ФТ", + "Contact cockpit summary": "Зведення контакту в кабіні", "CONTACT": "КОНТАКТ", - "CONTACTS · 250 KM": "КОНТАКТИ · 250 KM", + "CONTACTS · 250 KM": "КОНТАКТИ · 250 КМ", "Contact navigation": "Навігація контактами", "CONTEXT ONLY": "ЛИШЕ КОНТЕКСТ", "Nearby cohort counts": "Кількість найближчих груп", - "NEAREST OBSERVED / MAPPED": "НАЙБЛИЖЧІ СПОСТЕРЕЖЕНІ / КАРТОГРАФОВАНІ", + "FLT": "РЕЙСИ", + "MIL": "ВІЙСЬК.", + "SITE": "ОБʼЄКТИ", + "NEAREST OBSERVED / MAPPED": "НАЙБЛИЖЧІ СПОСТЕРЕЖЕНІ / НАНЕСЕНІ", "AVAILABLE INPUTS ONLY · NOT AN ALL-CLEAR": "ЛИШЕ ДОСТУПНІ ВХІДНІ ДАНІ · НЕ ОЗНАЧАЄ «УСЕ ЧИСТО»", + "WX": "ПОГОДА", "Cockpit briefing carousel": "Карусель брифінгу кабіни", "Estimated flight plan": "Орієнтовний план польоту", "ESTIMATED FLIGHT PLAN": "ОРІЄНТОВНИЙ ПЛАН ПОЛЬОТУ", - "FROM": "ВІД", - "TO": "ДО", + "FROM": "ЗВІДКИ", + "TO": "КУДИ", "Cockpit briefing controls": "Керування брифінгом кабіни", "Previous briefing page": "Попередня сторінка брифінгу", "Next briefing page": "Наступна сторінка брифінгу", "Live signals": "Сигнали в реальному часі", "Latest regional news": "Останні регіональні новини", "Location-based information": "Інформація за розташуванням", - "TEMP": "ТЕМП", + "TEMP": "ТЕМП.", "WIND": "ВІТЕР", "SKY": "НЕБО", "PRECIP": "ОПАДИ", + "MM": "ММ", + "Weather data by Open-Meteo.com": "Дані про погоду: Open-Meteo.com", + "Cockpit briefing pages": "Сторінки брифінгу кабіни", + "SIG": "СИГН.", "Show Live Signals": "Показати сигнали в реальному часі", "NEWS": "НОВИНИ", "Show Regional News": "Показати регіональні новини", - "Show Local Info": "Показати локальну інформацію", + "LOCAL": "МІСЦ.", + "Show Local Info": "Показати місцеву інформацію", "Cockpit display and Radio controls": "Керування дисплеєм і радіо кабіни", "DISPLAY": "ДИСПЛЕЙ", "Cockpit display options": "Параметри дисплея кабіни", @@ -711,6 +2830,8 @@ "Next filtered radio station": "Наступна відфільтрована радіостанція", "VOLUME": "ГУЧНІСТЬ", "Cockpit Radio volume": "Гучність радіо кабіни", + "ESC EXIT": "ESC ВИХІД", + "C TOGGLE": "C ПЕРЕМК.", "View switcher": "Перемикач вигляду", "Exit cockpit and return to full globe view": "Вийти з кабіни та повернутися до вигляду всього глобуса", "RESET": "СКИНУТИ", @@ -738,6 +2859,9 @@ "Search location by name or coordinates": "Шукати розташування за назвою або координатами", "Search any location...": "Шукати будь-яке розташування...", "WEATHER": "ПОГОДА", + "Active weather products": "Активні погодні продукти", + "RECENT IMAGERY": "СВІЖІ ЗНІМКИ", + "Imagery days in the box": "Дні зі знімками в області", "CONTEXT": "КОНТЕКСТ", "Compact Radio controls": "Компактне керування радіо", "Open detailed Radio controls": "Відкрити докладне керування радіо", @@ -747,25 +2871,27 @@ "Expand panel": "Розгорнути панель", "Context mode": "Режим контексту", "CONTACTS": "КОНТАКТИ", - "Cycles the nearest contacts of whatever type you select — planes, vessels, installations. Satellites track independently.": "Гортає найближчі контакти обраного вами типу — літаки, судна, об’єкти. Супутники відстежуються окремо.", + "Cycles the nearest contacts of whatever type you select — planes, vessels, installations. Satellites track independently.": "Гортає найближчі контакти обраного вами типу — літаки, судна, обʼєкти. Супутники відстежуються окремо.", "SPACE MISSIONS": "КОСМІЧНІ МІСІЇ", "SELECT CONTEXT": "ОБЕРІТЬ КОНТЕКСТ", "Contact Context actions": "Дії контексту контактів", "COCKPIT": "КАБІНА", - "SEARCH NEARBY SITES": "ПОШУК НАЙБЛИЖЧИХ ОБ’ЄКТІВ", + "SEARCH NEARBY SITES": "ПОШУК НАЙБЛИЖЧИХ ОБʼЄКТІВ", "Reclassify tracked contact as TR-3B": "Перекласифікувати відстежуваний контакт як TR-3B", "CONTACTS CONTEXT OFF": "КОНТЕКСТ КОНТАКТІВ ВИМКНЕНО", - "SELECT CONTACTS TO LOAD OBSERVED / MAPPED PROXIMITY": "ОБЕРІТЬ КОНТАКТИ, ЩОБ ЗАВАНТАЖИТИ СПОСТЕРЕЖЕНУ / КАРТОГРАФОВАНУ БЛИЗЬКІСТЬ", + "SELECT CONTACTS TO LOAD OBSERVED / MAPPED PROXIMITY": "ВИБЕРІТЬ КОНТАКТИ, ЩОБ ЗАВАНТАЖИТИ СПОСТЕРЕЖЕНЕ / НАНЕСЕНЕ ПОБЛИЗУ", "Available Space Missions": "Доступні космічні місії", "AVAILABLE MISSIONS": "ДОСТУПНІ МІСІЇ", "SELECT A MISSION TO INSPECT": "ОБЕРІТЬ МІСІЮ ДЛЯ ПЕРЕГЛЯДУ", "LOADING 30-DAY MISSION INDEX": "ЗАВАНТАЖЕННЯ ІНДЕКСУ МІСІЙ ЗА 30 ДНІВ", "TAB PREVIEWS · ENTER / SPACE SELECTS": "TAB — ОГЛЯД · ENTER / SPACE — ВИБІР", + "Internet radio and local SDR": "Інтернет-радіо та локальний SDR", "STATION TAG": "ТЕГ СТАНЦІЇ", "Filter stations by station tag": "Фільтрувати станції за тегом", "All": "Усі", - "Enable Radio, then choose a globe marker or use next.": "Увімкніть радіо, потім виберіть маркер на глобусі або натисніть «наступна».", + "Enable Radio, then choose a globe marker or use next.": "Увімкніть радіо, потім виберіть маркер на глобусі або перейдіть до наступної станції.", "DRAG TO TUNE": "ТЯГНІТЬ ДЛЯ НАЛАШТУВАННЯ", + "Tune available internet radio stations": "Налаштування на доступні інтернет-радіостанції", "ALL · DRAG THE NEEDLE": "УСІ · ПОТЯГНІТЬ СТРІЛКУ", "SNAPS TO AVAILABLE STATIONS": "ПРИЛИПАЄ ДО ДОСТУПНИХ СТАНЦІЙ", "Radio playback": "Відтворення радіо", @@ -776,13 +2902,48 @@ "Stop radio playback": "Зупинити відтворення радіо", "Radio volume": "Гучність радіо", "STATION SITE": "САЙТ СТАНЦІЇ", - "Audio connects directly to the broadcaster after you press play. Your IP is visible to that broadcaster.": "Після натискання відтворення аудіо з’єднується напряму з мовником. Мовник бачить вашу IP-адресу.", + "DIRECTORY: RADIO BROWSER": "КАТАЛОГ: RADIO BROWSER", + "Audio connects directly to the broadcaster after you press play. Your IP is visible to that broadcaster.": "Після натискання відтворення аудіо зʼєднується напряму з мовником. Мовник бачить вашу IP-адресу.", + "Local RTL-SDR receiver": "Локальний приймач RTL-SDR", + "LOCAL RTL-SDR": "ЛОКАЛЬНИЙ RTL-SDR", + "Chrome/Edge · WebUSB · one local tuner shared by FM and the Local ADS-B layer.": "Chrome/Edge · WebUSB · один локальний тюнер для FM і шару «Локальний ADS-B».", + "Use your location for faster ADS-B position decoding": "Використовувати ваше місцезнаходження для швидшого декодування позицій ADS-B", + "CHANGE DEVICE": "ЗМІНИТИ", + "Choose a different RTL-SDR or receiver channel": "Вибрати інший RTL-SDR або канал приймача", + "RTL-SDR receiver mode": "Режим приймача RTL-SDR", + "GAIN": "ПІДСИЛЕННЯ", + "RTL-SDR tuner gain for the current mode": "Підсилення тюнера RTL-SDR для поточного режиму", + "AUTO": "АВТО", + "MSG/S": "ПОВІД./С", + "HEARD": "ЧУТНО", + "POSITIONED": "З КООРД.", + "FM MHZ": "FM МГЦ", + "TUNE": "НАЛАШТУВАТИ", + "Seek broadcast FM stations": "Пошук FM-радіостанцій", + "◀ SEEK": "◀ ПОШУК", + "SEEK ▶": "ПОШУК ▶", + "SDR VOL": "ГУЧН. SDR", + "Local SDR volume": "Гучність локального SDR", "Intelligence HUD (H)": "Розвідувальний HUD (H)", "Layout": "Компонування", "HUD layout": "Компонування HUD", "Tactical": "Тактичне", "Operator": "Операторське", "Minimal": "Мінімальне", + "Cyber": "Кібер", + "Sonar": "Сонар", + "Cyber sonar contact scanner": "Кібер-сонар: сканер контактів", + "Rings": "Кільця", + "Sonar ring count": "Кількість кілець сонара", + "Range": "Дальність", + "Sonar ring range": "Дальність кілець сонара", + "Power": "Потужність", + "Sonar intensity": "Інтенсивність сонара", + "Opacity": "Непрозорість", + "Cyber contact and label opacity": "Непрозорість контактів і підписів у режимі «Кібер»", + "Minimum opacity for map dots, icons, models, brackets, and labels between sonar passes": "Мінімальна непрозорість точок, значків, моделей, рамок і підписів на карті між проходами сонара", + "Sector": "Сектор", + "Sonar sector width": "Ширина сектора сонара", "Detection Overlay (D)": "Накладка виявлення (D)", "Detection overlay": "Накладка виявлення", "Detection label density": "Щільність підписів виявлення", @@ -799,13 +2960,33 @@ "PARAMETERS": "ПАРАМЕТРИ", "3D aircraft — flat icons zoomed out, 3D models up close": "3D літаки — плоскі іконки здалеку, 3D-моделі зблизька", "Models": "Моделі", - "3D model coverage": "Зона огляду 3D-моделей", + "3D model coverage": "Охоплення 3D-моделей", "Proximity": "Поблизу", "Scope — the circular viewport mask": "Приціл — кругла маска вікна перегляду", "Scope": "Приціл", "Feather": "Розмиття", "Scope edge feather": "Розмиття краю приціла", "Scope edge feather as a percentage of the keyhole radius": "Розмиття краю приціла у відсотках радіуса ілюмінатора", + "Draw on the world — click vertices, double-click or Enter to finish, Esc to cancel": "Малювати на карті світу — клацайте вершини, подвійне клацання або Enter — завершити, Esc — скасувати", + "Shape": "Фігура", + "Shape to draw": "Фігура для малювання", + "Area": "Зона", + "Line": "Лінія", + "Pin": "Мітка", + "Label (optional)": "Підпис (необовʼязково)", + "Label for the drawn shape": "Підпис намальованої фігури", + "Colour of the drawn shape": "Колір намальованої фігури", + "Primary": "Основний", + "Amber": "Бурштиновий", + "Cyan": "Блакитний", + "Green": "Зелений", + "Red": "Червоний", + "Clear": "Очистити", + "Remove every mark from the board": "Прибрати всі позначки з дошки", + "Show your own GeoJSON, KML, KMZ or GPX files on the globe (or drop them onto it). File bytes stay on this device; overlays can appear in map screenshots shared with voice.": "Показати на глобусі власні файли GeoJSON, KML, KMZ або GPX (чи перетягнути їх на глобус). Вміст файлів залишається на цьому пристрої; накладки можуть потрапити в знімки карти, які передаються голосовому асистентові.", + "Import": "Імпорт", + "Choose GeoJSON, KML, KMZ or GPX files": "Виберіть файли GeoJSON, KML, KMZ або GPX", + "Imported files": "Імпортовані файли", "Celestial": "Небесне", "Hide UI chrome": "Сховати оформлення інтерфейсу", "Clean UI": "Чистий інтерфейс", @@ -818,6 +2999,7 @@ "Return UI controls": "Повернути елементи керування", "Initializing photorealistic world...": "Ініціалізація фотореалістичного світу...", "DATA LAYERS": "ШАРИ ДАНИХ", + "ACQUIRING FRAME": "ОТРИМАННЯ КАДРУ", "NEAREST": "НАЙБЛИЖЧА", "CCTV camera": "Камера CCTV", "CALIBRATION": "КАЛІБРУВАННЯ", @@ -833,6 +3015,26 @@ "SAVE CAL": "ЗБЕРЕГТИ КАЛ.", "RESET CAL": "СКИНУТИ КАЛ.", "SCENE SUMMARY": "ЗВЕДЕННЯ СЦЕНИ", + "STREET LEVEL": "ВУЛИЧНІ ЗНІМКИ", + "Turn Street Level on or off": "Увімкнути або вимкнути «Вуличні знімки»", + "Show the street-level view full screen (Esc shrinks it)": "Показати вуличний знімок на весь екран (Esc згортає)", + "Image fit": "Масштаб знімка", + "FIT": "ВПИСАТИ", + "Fit: show the whole photo, with dark bars where its shape differs from the frame": "Вписати: показати знімок повністю, з темними смугами там, де його форма не збігається з рамкою", + "FILL": "ЗАПОВНИТИ", + "Fill: fill the frame edge to edge, cropping the photo": "Заповнити: заповнити рамку повністю, обрізавши краї знімка", + "Close the image and deselect it on the map": "Закрити знімок і зняти виділення на карті", + "Close the street-level image": "Закрити вуличний знімок", + "Street-level viewer": "Перегляд вуличних знімків", + "Open this image on the provider's site": "Відкрити знімок на сайті джерела", + "Imagery providers": "Джерела знімків", + "PROVIDERS": "ДЖЕРЕЛА", + "Imagery filters": "Фільтри знімків", + "IMAGERY": "ЗНІМКИ", + "Panorama filter": "Фільтр панорам", + "ALL": "УСІ", + "FLAT": "ПЛОСКІ", + "SINCE": "З ДАТИ", "SCENES": "СЦЕНИ", "Scene recipe": "Рецепт сцени", "NEW": "НОВА", @@ -846,24 +3048,27 @@ "GROUND STATION · PROVIDER SETTINGS": "НАЗЕМНА СТАНЦІЯ · НАЛАШТУВАННЯ ПОСТАЧАЛЬНИКІВ", "Close key setup": "Закрити налаштування ключів", "Power up the globe": "Запустіть глобус", - "The globe already flies keyless. Every key below switches on another real feed — paste one and it's saved into this app's local configuration, then the server restarts itself. Server-side keys stay on this machine; Google Maps and Cesium ion run in the browser and must be provider-restricted. Keys you configured elsewhere are shown but never touched.": "Глобус уже літає без ключів. Кожен ключ нижче вмикає ще один справжній канал даних — вставте його, і він збережеться в локальну конфігурацію застосунку, після чого сервер перезапуститься самостійно. Серверні ключі залишаються на цій машині; Google Maps і Cesium ion працюють у браузері, тож їхні ключі треба обмежити на боці постачальника. Ключі, налаштовані деінде, показуються, але ніколи не змінюються.", + "The globe already flies keyless. Every key below switches on another real feed — paste one and it's saved into this app's local configuration, then the server restarts itself. Server-side keys stay on this machine; Google Maps and Cesium ion run in the browser and must be provider-restricted. Keys you configured elsewhere are shown but never touched.": "Глобус уже літає без ключів. Кожен ключ нижче вмикає ще один справжній потік даних — вставте його, і він збережеться в локальну конфігурацію застосунку, після чого сервер сам перезапуститься. Серверні ключі залишаються на цьому компʼютері; Google Maps і Cesium ion працюють у браузері, тож їхні ключі треба обмежити на боці постачальника. Ключі, налаштовані деінде, показано, але їх ніколи не змінюють.", "SAVE KEYS": "ЗБЕРЕГТИ КЛЮЧІ", "ESC to close": "ESC — закрити", "The Google Maps key buys the photorealistic planet — everything else stacks on top.": "Ключ Google Maps відкриває фотореалістичну планету — усе інше нашаровується зверху.", - "NO PLACE LEFT BEHIND": "НІКОГО НЕ ЗАЛИШАЄМО ПОЗАДУ", + "NO PLACE LEFT BEHIND": "ЖОДНЕ МІСЦЕ НЕ ЗАЛИШИТЬСЯ ПОЗА УВАГОЮ", "ACTIVE STYLE": "АКТИВНИЙ СТИЛЬ", "Globe actions": "Дії з глобусом", "Turn off all selected data layers": "Вимкнути всі вибрані шари даних", "Copy share link": "Копіювати посилання для поширення", + "Toggle straight-down and tilted map views": "Перемкнути вигляд карти: згори або з нахилом", + "Reset map to north up": "Повернути карту північчю вгору", + "Reset map bearing to north": "Скинути азимут карти на північ", "Reset camera and return to full globe view": "Скинути камеру та повернутися до загального вигляду глобуса", "MISSION CONTROL · FIRST LAUNCH": "ЦЕНТР КЕРУВАННЯ · ПЕРШИЙ ЗАПУСК", "Choose your first view": "Оберіть свій перший вигляд", - "LIVE CONTACTS": "КОНТАКТИ В РЕАЛЬНОМУ ЧАСІ", + "LIVE CONTACTS": "КОНТАКТИ ОНЛАЙН", "Aircraft, vessels and nearby intelligence": "Літаки, судна та розвідка поблизу", "Launches, spacecraft and orbital context": "Запуски, космічні апарати та орбітальний контекст", "EXPLORE MANUALLY": "ДОСЛІДИТИ ВРУЧНУ", "Begin with a clean globe": "Почніть із чистого глобуса", "Don't show this again": "Більше не показувати", "ESC to dismiss": "ESC — приховати", - "Tip: the GEV MIC button in the dock lets you talk to the map.": "Порада: кнопка GEV MIC у доку дає змогу говорити з картою." + "Tip: the GEV MIC button in the dock lets you talk to the map.": "Порада: кнопка МІК у доку дає змогу говорити з картою." } diff --git a/src/i18n/same-as-english.json b/src/i18n/same-as-english.json index 83c8897d8..21f2ce2fa 100644 --- a/src/i18n/same-as-english.json +++ b/src/i18n/same-as-english.json @@ -142,6 +142,19 @@ "VS", "WHOT/BHOT" ], + "uk": [ + "AIS: --", + "AIS: {name}", + "CCTV", + "CRT", + "FLIR", + "Ironbow", + "Landsat 8/9", + "NVG", + "REC", + "S2 GhostMaps", + "WHOT/BHOT" + ], "zh-CN": [ "1090 MHz", "978 MHz UAT", diff --git a/src/ui/localePicker.test.mjs b/src/ui/localePicker.test.mjs index 057642827..7bdbc7ce4 100644 --- a/src/ui/localePicker.test.mjs +++ b/src/ui/localePicker.test.mjs @@ -40,7 +40,7 @@ test('the current language comes first, the rest by their own names', () => { nativeNames: LOCALE_NAMES, }), ), - ['ru', 'en', 'es', 'zh-CN', 'zh-Hant'], + ['ru', 'uk', 'en', 'es', 'zh-CN', 'zh-Hant'], ); assert.deepEqual( codes( @@ -50,7 +50,7 @@ test('the current language comes first, the rest by their own names', () => { nativeNames: LOCALE_NAMES, }), ), - ['es', 'en', 'ru', 'zh-CN', 'zh-Hant'], + ['es', 'en', 'ru', 'uk', 'zh-CN', 'zh-Hant'], ); assert.deepEqual( codes( @@ -60,7 +60,7 @@ test('the current language comes first, the rest by their own names', () => { nativeNames: LOCALE_NAMES, }), ), - ['en', 'es', 'ru', 'zh-CN', 'zh-Hant'], + ['en', 'es', 'ru', 'uk', 'zh-CN', 'zh-Hant'], ); const rows = buildLocaleOptions({ locales: MANY, @@ -261,7 +261,8 @@ test('keyboard model: open on the current language, move, choose, close', () => model.openList(); assert.equal(model.activeOption.code, 'ru'); assert.deepEqual(model.keydown({ key: 'ArrowDown' }), { handled: true }); - assert.equal(model.activeOption.code, 'en'); + // Russian collation puts the other Cyrillic name next. + assert.equal(model.activeOption.code, 'uk'); model.keydown({ key: 'End' }); assert.equal(model.activeOption.code, 'zh-Hant'); model.keydown({ key: 'Home' }); @@ -275,7 +276,7 @@ test('keyboard model: open on the current language, move, choose, close', () => model.keydown({ key: 'ArrowDown' }); assert.deepEqual(model.keydown({ key: ' ' }), { handled: true, - choose: 'en', + choose: 'uk', }); assert.deepEqual(model.keydown({ key: 'Escape' }), { handled: true, From 7ad073aa9c7a94a4314d1f4b72867e0a6d3e4101 Mon Sep 17 00:00:00 2001 From: German Khokhlov Date: Wed, 28 Oct 2026 12:59:23 +0400 Subject: [PATCH 12/83] i18n(ja): translate the remaining strings and review #913 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Translate the 1,875 strings #913 did not cover (2,727 in all), for a tactical HUD: aviation, maritime, weather and imagery terms, counters next to numbers (機, 隻, 基, 件), year-first dates. - Review the contributor entries: full-width punctuation ():? and …, no space between Japanese and Latin, one katakana form per term (ブラウザー, ビューアー), and fixes where the meaning was off: NO PLACE LEFT BEHIND, LEVEL (horizon), CURATED / RAW PRIOR (CCTV calibration), STALE (更新遅延, not 古い), rocket stage (段), SAR vessels, T minus, POWER UP. - List the codes, units and product names that stay as in English. Co-Authored-By: Claude Opus 5.5 --- src/i18n/locales/ja.json | 2289 ++++++++++++++++++++++++++++++--- src/i18n/same-as-english.json | 51 + 2 files changed, 2195 insertions(+), 145 deletions(-) diff --git a/src/i18n/locales/ja.json b/src/i18n/locales/ja.json index 28c57d3d1..0aca1e20d 100644 --- a/src/i18n/locales/ja.json +++ b/src/i18n/locales/ja.json @@ -1,18 +1,241 @@ { - "Flying to Austin, TX...": "テキサス州オースティンへ移動中...", - "Restoring shared view...": "共有ビューを復元中...", - "Configuring viewer...": "ビューアを設定中...", - "Loading Google 3D Tiles...": "Google 3D Tiles を読み込み中...", - "Loading the keyless globe...": "キー不要の地球儀を読み込み中...", - "Google 3D Tiles unavailable ({detail}). Loading the keyless globe...": "Google 3D Tiles を利用できません ({detail})。キー不要の地球儀を読み込み中...", - "Initializing systems...": "システムを初期化中...", + "Pick a shape, then click the map.": "図形を選んでから、地図をクリックしてください。", + "Enter to place the pin, Esc to cancel.": "Enterでピンを配置、Escでキャンセル。", + "Click where the pin goes.": "ピンを置く場所をクリックしてください。", + "Click {count} more points.": { + "other": "あと{count}点クリックしてください。" + }, + "Those points are in a line — move one off it to enclose an area.": "点が一直線上に並んでいます。範囲を囲むには、いずれかの点を線から外してください。", + "That line has no length — click somewhere further away.": "線の長さがゼロです。もっと離れた場所をクリックしてください。", + " · {max}-point limit reached": " · 上限の{max}点に達しました", + "{measure} · double-click or Enter to finish, Backspace undoes, Esc cancels.{full}": "{measure} · ダブルクリックまたはEnterで完了、Backspaceで元に戻す、Escでキャンセル。{full}", + "drawings on the map": "地図上の描画", + "That shape already has {count} points — finish it or press Backspace.": "この図形はすでに{count}点あります。完了するか、Backspaceを押してください。", + "That point is off the globe — click on the world.": "その点は地球の外です。地表をクリックしてください。", + "That shape could not be placed.": "図形を配置できませんでした。", + "Could not place the shape: {error}": "図形を配置できませんでした:{error}", + "Board cleared.": "ボードを消去しました。", + "{owner} is using the pointer — close it first.": "{owner}がポインターを使用中です。先に閉じてください。", + "{label} · Detailed outline unavailable": "{label} · 詳細な輪郭を取得できません", + "Flying to Austin, TX...": "テキサス州オースティンへ移動中…", + "Restoring shared view...": "共有ビューを復元中…", + "Configuring viewer...": "ビューアーを設定中…", + "Loading Google 3D Tiles...": "Google 3D Tilesを読み込み中…", + "Loading the keyless globe...": "キー不要の地球儀を読み込み中…", + "Google 3D Tiles unavailable ({detail}). Loading the keyless globe...": "Google 3D Tilesを利用できません({detail})。キー不要の地球儀を読み込み中…", + "Initializing systems...": "システムを初期化中…", + "Space Missions isolates replay data. Exit the mode to enable {layer}.": "宇宙ミッションはリプレイデータを分離しています。{layer}を有効にするには、このモードを終了してください。", + "Data attribution": "データの出典", + "Data provided by:": "データ提供:", "Close data attribution": "データ出典を閉じる", + "Light aircraft": "軽飛行機", + "Glider": "グライダー", + "Turboprop": "ターボプロップ機", + "Airliner": "旅客機", + "Widebody": "ワイドボディ機", + "Four-engine jet": "4発ジェット機", + "Helicopter": "ヘリコプター", + "Fast jet": "高速ジェット機", + "Business jet": "ビジネスジェット", + "Drone": "ドローン", + "General emergency": "一般緊急事態", + "Unlawful interference": "不法妨害", + "Radio failure": "無線故障", + "Downed aircraft": "墜落機", + "Minimum fuel": "最低燃料", + "Lifeguard (medical priority)": "救急飛行(医療優先)", + "Rasuwagadhi witness video": "Rasuwagadhiの目撃映像", + "Bhote Koshi valley footage": "Bhote Koshi渓谷の映像", + "Flood footage": "洪水の映像", + "Compilation and casualty claims": "映像まとめと死傷者に関する主張", + "SOURCE GEOCONFIRMED · WORLD-PINNED": "ソース位置確認済み · 地図に固定", + "SOURCE CREDITED · LOCATION UNRESOLVED": "ソース明記 · 位置未特定", + "REFERENCE ONLY · CLAIMS UNVERIFIED": "参考情報のみ · 主張は未検証", + "SOURCE GEOCONFIRMED": "ソース位置確認済み", + "2021 historical reference versus 2026 post-event imagery; changes are cumulative and include the July 2025 Rasuwagadhi flood. Schematic downstream progression, not modeled arrival time; not an official hazard model.": "2021年の過去参照画像と2026年の発生後画像の比較です。変化は累積的で、2025年7月のRasuwagadhi洪水を含みます。下流への進行は模式図であり、到達時刻のモデル計算ではありません。公式のハザードモデルでもありません。", + "Immediate collapse viewpoint": "崩壊地点直近の視点", + "Collapse viewpoint": "崩壊地点の視点", + "Debris-dammed lake": "土砂ダム湖", + "Dammed lake": "せき止め湖", + "Second landslide": "第2の地すべり", + "Gyirong border gate": "Gyirong国境ゲート", + "Border gate": "国境ゲート", + "Timure evidence cluster": "Timureの証拠群", + "Mailung / Upper Trishuli bridge": "Mailung / Upper Trishuli橋", + "Dandagaun viewpoint restaurant": "Dandagaun展望レストラン", + "Dandagaun viewpoint": "Dandagaun展望地点", + "Bidur - Trishuli bridge": "Bidur - Trishuli橋", + "Bidur bridge": "Bidur橋", + "Devighat / Taadi Khola Bridge": "Devighat / Taadi Khola橋", + "Devighat bridge": "Devighat橋", + "Facebook player API did not initialize.": "FacebookプレーヤーAPIが初期化されませんでした。", + "Facebook player API could not load.": "FacebookプレーヤーAPIを読み込めませんでした。", + "Facebook player API timed out.": "FacebookプレーヤーAPIがタイムアウトしました。", + "X embed API did not initialize.": "X埋め込みAPIが初期化されませんでした。", + "X embed could not load.": "X埋め込みを読み込めませんでした。", + "X embed timed out.": "X埋め込みがタイムアウトしました。", "UNAVAILABLE": "利用不可", + "TIMEOUT": "タイムアウト", + "BLOCKED": "ブロック", "SOURCE": "ソース", - "Overpass rate-limited": "Overpass がレート制限中", - "Overpass timed out": "Overpass がタイムアウトしました", - "Overpass could not complete the query": "Overpass がクエリを完了できませんでした", - "Overpass temporarily unavailable": "Overpass が一時的に利用できません", + "Facebook embed unavailable. The post may be private, removed, region-restricted, or blocked.": "Facebookの埋め込みを利用できません。投稿が非公開、削除済み、地域制限中、またはブロックされている可能性があります。", + "Preloading {provider} media": "{provider}のメディアを事前読み込み中", + "LOADING X POST…": "Xの投稿を読み込み中…", + "The X post is unavailable or cannot be embedded.": "このXの投稿は利用できないか、埋め込みできません。", + "X POST · PROVIDER CONTROLS": "Xの投稿 · 提供元の操作", + "{reason} OPEN ORIGINAL.": "{reason}元の投稿を開いてください。", + "X embed unavailable": "X埋め込みを利用できません。", + "FACEBOOK · PROVIDER CONTROLS": "FACEBOOK · 提供元の操作", + "Facebook embed unavailable": "Facebookの埋め込みを利用できません。", + "AUTOPLAY BLOCKED · USE PROVIDER CONTROLS": "自動再生ブロック · 提供元の操作を使用", + "Embedded {provider} media for {source}": "{source}の埋め込み{provider}メディア", + "witness source": "目撃ソース", + "Witness source": "目撃ソース", + "{provider} · EMBEDDED SOURCE": "{provider} · 埋め込みソース", + "OPEN ORIGINAL ↗": "元の投稿を開く ↗", + "{provider} media: {source}": "{provider}メディア:{source}", + "{provider} · PROVIDER CONTROLS": "{provider} · 提供元の操作", + "YOUTUBE {state} · OPEN ORIGINAL": "YOUTUBE {state} · 元の投稿を開く", + "INITIATION": "発生", + "DAMMING": "せき止め", + "SECONDARY FAILURE": "二次崩壊", + "BORDER ARRIVAL": "国境到達", + "PROPAGATION": "伝播", + "DOWNSTREAM PASSAGE": "下流通過", + "CONSEQUENCE": "影響", + "DOWNSTREAM CONSEQUENCE": "下流への影響", + "EVIDENCE": "証拠", + "{year} HISTORICAL REFERENCE": "{year}年 過去参照", + "{year} POST-EVENT": "{year}年 発生後", + "{count} GEOLOCATED SOURCE-MAP PLACEMENTS": { + "other": "ソースマップ上の位置特定 {count}件" + }, + "NO PREVIEW": "プレビューなし", + "YouTube source": "YouTubeソース", + "Facebook source": "Facebookソース", + "SOURCE LINK": "ソースリンク", + "{publisher} / OPEN": "{publisher} / 開く", + "Bhote Koshi flood reconstruction controls": "Bhote Koshi洪水再現の操作", + "EVENT RECONSTRUCTION · 26 AUG 2026": "イベント再現 · 2026年8月26日", + "BHOTE KOSHI OUTBURST FLOOD": "BHOTE KOSHI決壊洪水", + "Close event layer": "イベントレイヤーを閉じる", + "OBSERVED IMAGERY": "観測画像", + "SCHEMATIC CORRIDOR": "模式的な流路", + "2021 HISTORICAL REFERENCE / 2026 POST-EVENT": "2021年 過去参照 / 2026年 発生後", + "Historical reference and post-event image split": "過去参照画像と発生後画像の分割表示", + "RECONSTRUCTION CLOCK": "再現クロック", + "Schematic downstream progression": "下流への進行(模式)", + "Story beat navigation": "ストーリー区切りのナビゲーション", + "Previous story beat": "前のストーリー区切り", + "CAUSE": "原因", + "CAPTURE TIME UNVERIFIED": "撮影時刻未検証", + "Next story beat": "次のストーリー区切り", + "▶ PLAY": "▶ 再生", + "Play the next shot and continue through this scene": "次のショットを再生し、このシーンを最後まで続けます", + "▶ PLAY SCENE": "▶ シーン再生", + "◉ CINEMATIC": "◉ シネマティック", + "↺ FULL STORY": "↺ 全ストーリー", + "↗ OPEN ORIGINAL": "↗ 元の投稿を開く", + "⌖ LOWER GORGE": "⌖ 下流峡谷", + "FIELD REPORTS · {count}": "現地報告 · {count}", + "GEOLOCATIONS · {credit}": "位置特定 · {credit}", + "↗ OPEN PUBLIC MAP": "↗ 公開マップを開く", + " Clouds are preserved from the source imagery.": "雲は元画像のまま残しています。", + "Rasuwagadhi witness": "Rasuwagadhiの目撃者", + "Open original source for {source}; capture time unverified": "{source}の元ソースを開く(撮影時刻未検証)", + "Historical reference and post-event image divider": "過去参照画像と発生後画像の境界線", + "A historical reference {before} percent, B post-event {after} percent": "A(過去参照){before}%、B(発生後){after}%", + "■ RELEASE CAMERA": "■ カメラを解放", + "Seek Nepal scene clock": "ネパールのシーンクロックをシーク", + "NEPAL SCENE CLOCK": "ネパール シーンクロック", + "… PLAYING SHOT": "… ショット再生中", + "▶ PLAY SHOT": "▶ ショット再生", + "Ⅱ PAUSE": "Ⅱ 一時停止", + "↺ REPLAY CINEMATIC": "↺ シネマティックを再生", + "↺ REPLAY": "↺ リプレイ", + "… PLAYING SCENE": "… シーン再生中", + "Continue {scene} from next shot": "次のショットから{scene}を続行", + "current scene": "現在のシーン", + "Replay the full reconstruction": "再現全体をリプレイ", + "SCENE SHOT": "シーンショット", + "TIME UNVERIFIED": "撮影時刻未検証", + "{count} SOURCES": { + "other": "ソース {count}件" + }, + "OUTSIDE IMAGERY SWIPE": "画像比較の範囲外", + "{scene} / AUTHORED SHOT": "{scene} / 作成済みショット", + "NEPAL FLOOD INCIDENT": "ネパール洪水インシデント", + "Play {shot}": "{shot}を再生", + "current scene shot": "現在のシーンショット", + "Play reconstruction": "再現を再生", + "Load previous scene shot": "前のシーンショットを読み込む", + "Load next scene shot": "次のシーンショットを読み込む", + "SCHEMATIC CORRIDOR, NOT MODELED ARRIVAL TIME.": "模式的な流路であり、到達時刻のモデル計算ではありません。", + "Rasuwa · 26 Aug 2026": "Rasuwa · 2026年8月26日", + "Event reconstruction": "イベント再現", + "BHOTE KOSHI FLOOD INCIDENT": "BHOTE KOSHI洪水インシデント", + "NEPAL · 26 AUG 2026": "ネパール · 2026年8月26日", + "USGS INITIAL REPORT": "USGS初期報告", + "26 AUG 2026 · 08:37 NPT": "2026年8月26日 · 08:37 NPT", + "28.2710° N · 85.5150° E": "北緯28.2710° · 東経85.5150°", + "INITIAL M4.4 · RECLASSIFIED M5.2 LANDSLIDE": "初期 M4.4 · M5.2の地すべりに再分類", + "USGS EVENT us7000tbwb · OPEN SOURCE": "USGSイベント us7000tbwb · ソースを開く", + "Open the USGS initial report for the 26 August 2026 Nepal landslide": "2026年8月26日のネパール地すべりに関するUSGS初期報告を開く", + "Show the Nepal context callout without a border or country fill": "国境線や国の塗りつぶしなしで、ネパールの説明ラベルを表示", + "Introduce Nepal, draw its border, then reveal the Bhote Koshi incident": "ネパールを紹介して国境を描き、Bhote Koshiのインシデントを表示", + "CITIES": "都市", + "Keep the regional incident context and introduce nearby city labels": "地域のインシデント情報を残したまま、周辺都市のラベルを表示", + "PLACES": "地点", + "Introduce the reconstruction scene key places from trigger to downstream": "再現シーンの主要地点を、発生地点から下流まで順に紹介", + "PATH": "経路", + "Animate the sourced cyan river-centerline route to Trishuli Bazaar": "出典に基づくシアンの河道中心線をTrishuli Bazaarまでアニメーション表示", + "OVERVIEW": "概観", + "Keep the completed flood path and location labels visible": "完成した洪水経路と地点ラベルを表示したままにする", + "RECORD": "記録", + "Reveal the trigger record while making a slow camera approach": "カメラをゆっくり近づけながら、発生記録を表示", + "{speed} kn": "{speed} kn", + "That file is not valid JSON.": "このファイルは有効なJSONではありません。", + "That JSON file is not GeoJSON.": "このJSONファイルはGeoJSONではありません。", + "That FeatureCollection has no features list.": "このFeatureCollectionにはfeaturesリストがありません。", + "Every GeoJSON feature must have type Feature.": "GeoJSONのすべてのフィーチャーはtypeがFeatureである必要があります。", + "That GeoJSON has invalid geometries.": "このGeoJSONには無効なジオメトリがあります。", + "That GeoJSON contains an unsupported geometry.": "このGeoJSONには対応していないジオメトリが含まれています。", + "That GeoJSON has invalid coordinates.": "このGeoJSONには無効な座標があります。", + "That file creates more than {limit} map objects (the limit).": "このファイルから作成される地図オブジェクトが上限の{limit}個を超えています。", + "That file has more than {limit} style definitions and image links after cleanup (the limit).": "このファイルは、クリーンアップ後もスタイル定義と画像リンクが上限の{limit}個を超えています。", + "That file has more than {limit} features (the limit).": "このファイルのフィーチャーが上限の{limit}個を超えています。", + "That file has more than {limit} points (the limit) across {features} features.": "このファイルの点が上限の{limit}個を超えています(フィーチャー数:{features})。", + "That file has more than {limit} points (the limit).": "このファイルの点が上限の{limit}個を超えています。", + "That KMZ unpacks to more than the import limit.": "このKMZは展開するとインポート上限を超えます。", + "That KMZ is damaged and could not be unpacked.": "このKMZは破損しているため、展開できませんでした。", + "That KMZ is not a readable zip archive.": "このKMZは読み取り可能なzipアーカイブではありません。", + "That KMZ uses a zip format this import does not read.": "このKMZは、このインポートで読み取れないzip形式を使用しています。", + "That KMZ is encrypted.": "このKMZは暗号化されています。", + "That KMZ uses a compression method this import does not read.": "このKMZは、このインポートで読み取れない圧縮方式を使用しています。", + "That KML has invalid geometry bounds.": "このKMLのジオメトリ範囲が無効です。", + "That KML has invalid coordinates.": "このKMLには無効な座標があります。", + "That GPX file has no document.": "このGPXファイルにはドキュメントがありません。", + "That {format} file is not valid XML.": "この{format}ファイルは有効なXMLではありません。", + "That file has an unreadable image or exceeds the 16-megapixel image limit.": "このファイルには読み取れない画像があるか、画像が1,600万画素の上限を超えています。", + "That KML could not be read.": "このKMLを読み取れませんでした。", + "That file has invalid point coordinates.": "このファイルには無効な点座標があります。", + "Ground heights are not available for that file. Try again when the map has loaded.": "このファイルの地表高を取得できません。地図の読み込み後にもう一度お試しください。", + "That file took too long to read.": "ファイルの読み取りに時間がかかりすぎました。", + "Nothing to import.": "インポートするものがありません。", + "That file is larger than {size} MiB.": "このファイルは{size} MiBを超えています。", + "Only GeoJSON, KML, KMZ and GPX files can be imported.": "インポートできるのはGeoJSON、KML、KMZ、GPXファイルのみです。", + "That file has nothing to draw.": "このファイルには描画できる内容がありません。", + "That KMZ holds no KML document.": "このKMZにはKMLドキュメントが含まれていません。", + "That {format} file could not be read.": "この{format}ファイルを読み取れませんでした。", + "That file has {count} map objects; the limit is {limit}.": "このファイルの地図オブジェクトは{count}個です。上限は{limit}個です。", + "Ground heights could not be read. Try that file again.": "地表高を読み取れませんでした。もう一度このファイルをお試しください。", + "That file has invalid point graphics.": "このファイルには無効なポイントグラフィックがあります。", + "Overpass rate-limited": "Overpassがレート制限中", + "Overpass timed out": "Overpassがタイムアウトしました", + "Overpass could not complete the query": "Overpassがクエリを完了できませんでした", + "Map tiles temporarily unavailable": "地図タイルが一時的に利用できません", + "Mapped names temporarily unavailable": "地名が一時的に利用できません", + "Overpass temporarily unavailable": "Overpassが一時的に利用できません", "Retrying mapped sites…": "マップ済み施設を再試行中…", "Fetching mapped sites…": "マップ済み施設を取得中…", "{reason} — retrying in {seconds}s": "{reason} — {seconds}秒後に再試行", @@ -21,20 +244,32 @@ "Showing cached mapped sites": "キャッシュ済みのマップ済み施設を表示中", "Mapped sites not loaded": "マップ済み施設は未読込です", "Mapped sites loaded": "マップ済み施設を読み込みました", + "Military airfield": "軍用飛行場", + "Naval base": "海軍基地", + "Firing range": "射撃場", + "Military land": "軍用地", + "Mapped installation": "マップ済み施設", + "Military area": "軍事区域", + "flight": "フライト", + "military flight": "軍用機", + "satellite": "衛星", "feed unavailable": "フィードを利用できません", - "feed stale": "フィードが古い", + "feed stale": "フィード更新遅延", "observed or mapped nearby context": "観測またはマップ済みの周辺コンテキスト", "no observed or mapped objects in current feeds": "現在のフィードに観測またはマップ済みの対象なし", + "Draw": "描画", + "Directions": "ルート案内", + "Recent imagery": "最近の衛星画像", "STATION": "宇宙ステーション", "Crewed stations and their visiting vehicles": "有人宇宙ステーションと来訪機", "NAV": "測位", - "GNSS navigation — GPS, GLONASS, Galileo": "GNSS測位: GPS、GLONASS、Galileo", + "GNSS navigation — GPS, GLONASS, Galileo": "GNSS測位(GPS、GLONASS、Galileo)", "GEO": "GEO", - "Geostationary belt — comms and weather, fixed over the equator": "静止軌道帯: 通信と気象、赤道上空に固定", + "Geostationary belt — comms and weather, fixed over the equator": "静止軌道帯:通信と気象、赤道上空に固定", "VISUAL": "可視", - "Brightest naked-eye objects — CelesTrak visual group": "肉眼で見える最も明るい天体: CelesTrak visual グループ", + "Brightest naked-eye objects — CelesTrak visual group": "肉眼で見える最も明るい天体(CelesTrak visualグループ)", "COMMS": "通信", - "Broadband constellation shell — shown only in DENSE mode": "ブロードバンドコンステレーションのシェル: 高密度モードでのみ表示", + "Broadband constellation shell — shown only in DENSE mode": "ブロードバンドコンステレーションのシェル:高密度モードでのみ表示", "FISHING": "漁船", "TOWING": "曳航", "DREDGER": "浚渫船", @@ -43,62 +278,200 @@ "SAILING": "帆船", "PLEASURE": "プレジャーボート", "PILOT": "水先船", - "SAR": "SAR", + "SAR": "捜索救助", "TUG": "タグボート", "PORT TENDER": "港湾作業船", "ANTI-POLLUTION": "汚染防除船", - "LAW ENFORCE": "法執行", + "LAW ENFORCE": "法執行船", "MEDICAL": "医療", "HIGH-SPEED": "高速船", "PASSENGER": "旅客船", "CARGO": "貨物船", "TANKER": "タンカー", "OTHER": "その他", + "Included in bundle": "バンドルに含まれています", + "Missing bundle file — reimport its bundle": "バンドルファイルがありません。バンドルを再インポートしてください", + "Source configured; file checked when loaded": "ソース設定済み。ファイルは読み込み時に確認します", + "Source unavailable": "ソースを利用できません", "ENVIRONMENTAL": "環境", "EARTH WATCH": "地球ウォッチ", "ACTIVE EVENTS": "発生中のイベント", "Starting live contacts…": "ライブコンタクトを開始中…", "Opening space missions…": "宇宙ミッションを開いています…", "Scanning active events…": "発生中のイベントをスキャン中…", - "Live earthquakes and active fires, from USGS and NASA": "USGS と NASA による、地震と火災のライブ情報", + "Live earthquakes and active fires, from USGS and NASA": "USGSとNASAによる地震と火災のライブ情報", "It feels like a forbidden cockpit—then you realize the sources are public and the data is real.": "禁断のコックピットのようですが、情報源はすべて公開されており、データは本物です。", "Working…": "処理中…", "Could not open that mission{detail}. Retry or explore manually.": "ミッションを開けませんでした{detail}。再試行するか、手動で探索してください。", - "This browser is blocking storage, so that could not be saved.": "このブラウザはストレージをブロックしているため、保存できませんでした。", + "This browser is blocking storage, so that could not be saved.": "このブラウザーはストレージをブロックしているため、保存できませんでした。", + "NORMAL": "標準", "CRT": "CRT", "NVG": "NVG", "FLIR": "FLIR", + "ANIME": "アニメ", + "NOIR": "ノワール", "SNOW": "雪", + "ARCTIC": "北極圏", + "ANTARCTIC": "南極圏", + "NORTH AMERICA": "北米", + "SOUTH AMERICA": "南米", + "EUROPE": "ヨーロッパ", + "AFRICA": "アフリカ", + "ASIA": "アジア", + "OCEANIA": "オセアニア", + "NORTHERN OCEANIC GRID": "北部海洋グリッド", + "SOUTHERN OCEANIC GRID": "南部海洋グリッド", "LOADING": "読込中", "DEGRADED": "性能低下", - "STALE": "古い", + "STALE": "更新遅延", "PARTIAL": "一部", "FALLBACK": "フォールバック", + "{state} {layers}": "{state} {layers}", + "view band|STREET": "街路", + "view band|CITY": "市街", + "view band|METRO": "都市圏", + "view band|REGIONAL": "地域", + "view band|GLOBAL": "全球", "SUMMARY": "概要", - "Awaiting telemetry...": "テレメトリー待機中...", + "Awaiting telemetry...": "テレメトリー待機中…", "REC": "REC", "AIS: --": "AIS: --", + "N/A": "なし", + "{mode} {band} {locality} | {region} | ALT {alt} | WINDOW {window} | SUN {sun}° | ONA {ona}° | {zone}": "{mode} {band} {locality} | {region} | ALT {alt} | 範囲 {window} | SUN {sun}° | ONA {ona}° | {zone}", + "NEAR {poi} ({city}) {distance}": "{poi}({city})付近 {distance}", + "SECTOR {lat} {lon}": "セクター {lat} {lon}", + "hemisphere|N": "N", + "hemisphere|S": "S", + "hemisphere|E": "E", + "hemisphere|W": "W", "POWER UP · {count} KEYS WAITING": { - "other": "POWER UP · キー待機 {count}件" + "other": "パワーアップ · キー待機 {count}件" }, - "POWERED UP": "電源オン", - "Save failed ({status}).": "保存に失敗しました ({status})。", + "POWERED UP": "パワーアップ済み", + "Provider Settings does not answer proxied requests": "プロバイダー設定はプロキシ経由のリクエストに応答しません", + "Provider Settings is disabled while sharing is enabled": "共有が有効な間、プロバイダー設定は無効です", + "Provider Settings answers only the machine running the server": "プロバイダー設定は、サーバーを実行しているマシンにのみ応答します", + "Provider Settings answers only local hostnames": "プロバイダー設定はローカルのホスト名にのみ応答します", + "Provider Settings requires an exact local Origin": "プロバイダー設定には完全に一致するローカルのOriginが必要です", + "Unrecognized Origin refused": "認識できないOriginを拒否しました", + "Cross-origin requests are refused": "クロスオリジンのリクエストは拒否されます", + "Content-Type must be application/json": "Content-Typeはapplication/jsonである必要があります", + "Method not allowed": "許可されていないメソッドです", + "Request too large": "リクエストが大きすぎます", + "Invalid JSON": "無効なJSONです", + "Body must be a JSON object of {ENV_VAR: value}": "本文は{ENV_VAR: value}形式のJSONオブジェクトである必要があります", + "No keys provided": "キーが指定されていません", + "At most {limit} keys per save": "1回に保存できるキーは最大{limit}個です", + "Unknown key: {name}": "不明なキー:{name}", + "{name} must be a string": "{name}は文字列である必要があります", + "{name} is empty": "{name}が空です", + "{name} is longer than any real key ({limit} max)": "{name}は実在するどのキーよりも長すぎます(最大{limit}文字)", + "{name} may only contain printable characters with no spaces": "{name}には空白を含まない印字可能文字のみ使用できます", + "{name} contains a character that is not valid in a key (#, quotes, $, \\, or backtick)": "{name}にキーで使用できない文字(#、引用符、$、\\、バッククォート)が含まれています", + "{name} is configured outside Provider Settings and can only be changed where it was set": "{name}はプロバイダー設定の外で設定されているため、設定した場所でのみ変更できます", + "The key was not saved: could not restrict the credential file to your account; nothing was saved": "キーは保存されませんでした:認証情報ファイルへのアクセスをお使いのアカウントに制限できなかったため、何も保存されていません", + "The key was not saved: the existing configuration could not be read, so nothing was changed": "キーは保存されませんでした:既存の設定を読み取れなかったため、何も変更されていません", + "Could not write the {store} store": "{store}ストアに書き込めませんでした", + "Save failed ({status}).": "保存に失敗しました({status})。", + "OAuth check failed: {detail}": "OAuthの確認に失敗しました:{detail}", + "Could not check ChatGPT sign-in. Try again.": "ChatGPTのサインイン状態を確認できませんでした。もう一度お試しください。", + "VOICE AUTH · CHATGPT OAUTH": "音声認証 · CHATGPT OAUTH", + "VOICE AUTH · API KEY": "音声認証 · APIキー", + "USE API KEY": "APIキーを使用", + "USE CHATGPT OAUTH": "CHATGPT OAUTHを使用", + "Use OPENAI_API_KEY for the next cloud voice session": "次回のクラウド音声セッションでOPENAI_API_KEYを使用", + "Use the signed-in local ChatGPT/Codex OAuth session for the next cloud voice session": "次回のクラウド音声セッションで、このマシンでサインイン済みのChatGPT/Codex OAuthセッションを使用", + "Metered — a billing-enabled account": "従量課金:請求が有効なアカウントが必要", + "Optional paid token — public access works without one": "任意の有料トークン:なくても公開アクセスで利用可能", + "Free key — register, paste, done": "無料キー:登録して貼り付けるだけ", + "browser-side": "ブラウザー側", + "This key runs in the browser by design — restrict it at the provider (see SECURITY.md)": "このキーは仕様上ブラウザーで動作します。プロバイダー側で利用制限を設定してください(SECURITY.mdを参照)", + "configured externally": "外部で設定済み", + "Supplied by your environment, Keychain, or launcher — change it where it was set": "環境変数、キーチェーン、またはランチャーから提供されています。設定した場所で変更してください", + "MANAGE ↗": "管理 ↗", + "GET KEY ↗": "キーを取得 ↗", + "{envVar} saved — paste to replace": "{envVar}は保存済み:貼り付けると置き換えます", + "paste {envVar}": "{envVar}を貼り付け", "REMOVE": "削除", "Remove {title} from this app's saved keys": "{title}をこのアプリの保存済みキーから削除", + "unsaved provider keys": "未保存のプロバイダーキー", + "Project keys: {status}": "プロジェクトのキー:{status}", "your app configuration": "アプリの設定", "your local .env": "ローカルの .env", "Saving…": "保存中…", - "Save failed: {detail}": "保存に失敗しました: {detail}", + "Save failed: {detail}": "保存に失敗しました:{detail}", "Paste at least one key first.": "まず、キーを1つ以上貼り付けてください。", "Saved to {store}. Restarting — this page reloads itself.": "{store}に保存しました。再起動中です。このページは自動で再読み込みされます。", - "Remove this key from your saved configuration?": "このキーを保存済みの設定から削除しますか?", + "Cloud voice will use OPENAI_API_KEY on the next session.": "次回のセッションから、クラウド音声はOPENAI_API_KEYを使用します。", + "Checking local ChatGPT OAuth sign-in…": "このマシンのChatGPT OAuthサインインを確認中…", + "Could not check ChatGPT sign-in.": "ChatGPTのサインイン状態を確認できませんでした。", + "ChatGPT OAuth selected for cloud voice. Your API key stays saved and available.": "クラウド音声にChatGPT OAuthを選択しました。APIキーは保存されたまま使用できます。", + "ChatGPT sign-in expired. Opening sign-in again…": "ChatGPTのサインインが期限切れです。サインインを再度開いています…", + "Opening ChatGPT sign-in in your browser…": "ブラウザーでChatGPTのサインインを開いています…", + "Could not start ChatGPT sign-in on this machine.": "このマシンでChatGPTのサインインを開始できませんでした。", + "Finish ChatGPT sign-in in the browser. Waiting for it to complete…": "ブラウザーでChatGPTのサインインを完了してください。完了を待っています…", + "ChatGPT sign-in timed out. Click {button} to try again.": "ChatGPTのサインインがタイムアウトしました。「{button}」をクリックしてもう一度お試しください。", + "ChatGPT sign-in complete. OAuth will be used for the next cloud voice session.": "ChatGPTのサインインが完了しました。次回のクラウド音声セッションではOAuthを使用します。", + "Remove this key from your saved configuration?": "このキーを保存済みの設定から削除しますか?", "Removed from {store}. Restarting — this page reloads itself.": "{store}から削除しました。再起動中です。このページは自動で再読み込みされます。", - "Places context + Street View fallback; optional separate key": "Places コンテキスト + Street View フォールバック。別キーも指定可", + "The photorealistic 3D planet, place search + Street View": "フォトリアルな3D地球、場所検索 + ストリートビュー", + "Places context + Street View fallback; optional separate key": "Placesのコンテキスト + ストリートビューの代替。別のキーも指定可", + "Voice control — API key or ChatGPT OAuth": "音声コントロール:APIキーまたはChatGPT OAuth", + "Gemini Live voice control": "Gemini Live音声コントロール", "Live ships, worldwide": "世界中の船舶をライブ表示", "Live active-fire detections": "火災のライブ検知", - "Real live traffic (keyless runs a simulation)": "実際のライブ交通情報 (キーなしはシミュレーション)", - "Bing imagery map stacks + world terrain": "Bing 画像のマップスタック + 世界地形", - "More flight-polling credits (anonymous works without)": "航空機ポーリングのクレジット増加 (匿名でも利用可)", + "Real live traffic (keyless runs a simulation)": "実際のライブ交通情報(キーなしはシミュレーション)", + "Bing imagery map stacks + world terrain": "Bing画像のマップスタック + 全球地形", + "More flight-polling credits (anonymous works without)": "航空機ポーリングのクレジット増加(匿名でも利用可)", + "Street-level imagery and coverage in the Street Level layer. Free: register an app in the Mapillary developer dashboard and paste its Client Token": "ストリートレベルレイヤーのストリートレベル画像とカバレッジ。無料:Mapillary開発者ダッシュボードでアプリを登録し、そのClient Tokenを貼り付けてください", + "Public space-missions access needs no key. Leave blank for standard use; paid tokens only raise request limits.": "公開の宇宙ミッションデータにキーは不要です。通常の利用では空欄のままにしてください。有料トークンはリクエスト上限を引き上げるだけです。", + "Air quality request failed": "大気質のリクエストに失敗しました", + "No readings available": "測定値がありません", + "No current readings": "現在の測定値がありません", + "{count} stations reporting": { + "other": "{count}局が報告中" + }, + "Highest air-quality readings in view": "表示範囲内で大気質の値が最も高い局", + "Low": "低", + "Low health risk": "健康リスク低", + "Moderate": "中", + "Moderate health risk": "健康リスク中", + "High": "高", + "High health risk": "健康リスク高", + "Very High": "非常に高い", + "Very High health risk": "健康リスク非常に高い", + "Air quality": "大気質", + "Canada only · ECCC AQHI network": "カナダのみ · ECCC AQHI観測網", + "ECCC request timed out": "ECCCのリクエストがタイムアウトしました", + "Malformed AQHI station response": "AQHI局の応答形式が不正です", + "No AQHI stations available": "利用できるAQHI局がありません", + "Malformed AQHI observation response": "AQHI観測の応答形式が不正です", + "Camera source temporarily unavailable": "カメラのソースが一時的に利用できません", + "Mapped camera locations": "マップ済みのカメラ位置", + "SHOW NEAREST": "最寄りを表示", + "Stop following the current object before navigating to a camera": "カメラへ移動する前に、現在の対象の追従を停止してください", + "Move to the nearest loaded camera and show its details": "読み込み済みの最寄りのカメラへ移動して詳細を表示", + "Camera badges": "カメラバッジ", + "Cyan cameras turn coral when selected. Wedges illustrate mapped direction, not measured coverage. Nearby cameras may be outside the screen.": "シアンのカメラは選択するとコーラルに変わります。扇形はマップされた向きを示すもので、実測のカバー範囲ではありません。周辺のカメラが画面外にある場合があります。", + "{count} nearby · {onScreen} on screen": { + "other": "周辺{count}台 · 画面内{onScreen}台" + }, + "{count} nearby": { + "other": "周辺{count}台" + }, + "retrying mapped ALPR cameras": "マップ済みのALPRカメラを再試行中", + "loading mapped ALPR cameras": "マップ済みのALPRカメラを読み込み中", + "No ALPR data for this area — US and Canada only": "この地域のALPRデータはありません(米国とカナダのみ)", + "Zoom in to load mapped cameras": "ズームインしてマップ済みのカメラを読み込み", + "Showing cached locations": "キャッシュ済みの位置を表示中", + "Coverage limited — zoom in": "カバー範囲が限られています。ズームインしてください", + "No ALPR data for this area": "この地域のALPRデータはありません", + "None on screen — nearby cameras are outside the view": "画面内になし:周辺のカメラは表示範囲外です", + "ALPR camera": "ALPRカメラ", + "Camera coverage unavailable": "カメラのカバー範囲を取得できません", + "OpenStreetMap · community mapped": "OpenStreetMap · コミュニティによるマッピング", + "Overpass returned an incomplete camera response": "Overpassから不完全なカメラデータが返されました", + "At least {count}": "{count}以上", "CONTEXT READY": "コンテキスト準備完了", "GLOBAL CONTEXT OFF": "グローバルコンテキスト オフ", "SELECT A FLIGHT, VESSEL, OR MAPPED INSTALLATION": "フライト、船舶、またはマップ済み施設を選択", @@ -106,12 +479,18 @@ "Unavailable": "利用不可", "Focus {label}": "{label}にフォーカス", "Global Context navigation": "グローバルコンテキストナビゲーション", - "Previous — prior visited contact in the 250 km window": "前へ: 250 km圏内で直前に訪れたコンタクト", + "Previous — prior visited contact in the 250 km window": "前へ:250 km圏内で直前に訪れたコンタクト", "PREVIOUS": "前へ", "FOCUS": "フォーカス", - "Next — nearest unvisited contact in the 250 km window": "次へ: 250 km圏内で最も近い未訪問のコンタクト", + "Next — nearest unvisited contact in the 250 km window": "次へ:250 km圏内で最も近い未訪問のコンタクト", "NEXT": "次へ", + "Named areas ({n})": "名前付きエリア({n})", + "{distance} FLIGHT / VESSEL WINDOW": "{distance}フライト / 船舶ウィンドウ", "Open-source mapped/observed context. Missing broadcasts, unloaded map areas, or unmapped sites are not evidence of absence.": "オープンソースのマップ済み/観測済みコンテキストです。放送の欠落、未読込のマップ領域、未マップの施設は、不在の証拠ではありません。", + "mapped matches within {km} km of the subject": "対象から{km} km以内のマップ済み一致", + "none mapped within {km} km; not a complete 250 km survey": "{km} km以内にマップ済みのものなし(250 kmの完全な調査ではありません)", + "mapped matches from the loaded viewport": "読み込み済みの表示範囲からのマップ済み一致", + "viewport feed is not a complete 250 km survey": "表示範囲のフィードは250 kmの完全な調査ではありません", "HDG {value}°": "HDG {value}°", "BRG {value}°": "BRG {value}°", "BRG —": "BRG —", @@ -122,19 +501,22 @@ "Military flights": "軍用機", "AIS vessels": "AIS船舶", "Mapped installations": "マップ済み施設", - "syncing {count} city feeds...": "{count}都市のフィードを同期中...", - "scanning nearby systems...": "周辺のシステムをスキャン中...", + "syncing {count} city feeds...": "{count}都市のフィードを同期中…", + "scanning nearby systems...": "周辺のシステムをスキャン中…", + "GBFS fetch error": "GBFS取得エラー", "Station {id}": "ステーション {id}", "Station": "ステーション", "🚲 {bikes} avail · {docks} docks · {capacity} cap": "🚲 空き {bikes} · ドック {docks} · 容量 {capacity}", "⚠️ Not installed": "⚠️ 未設置", "⚠️ Not renting": "⚠️ 貸出停止中", "⚠️ Not returning": "⚠️ 返却不可", - "HDG {value}° (ESTIMATED)": "HDG {value}° (推定)", + "HDG {value}° (ESTIMATED)": "HDG {value}°(推定)", "{count} CAMERAS STANDING BY · NO CAMERA SELECTED · CLICK A CAMERA TO ACTIVATE": "{count}台のカメラが待機中 · カメラ未選択 · カメラをクリックして有効化", "No cameras available in catalog.": "カタログに利用できるカメラがありません。", "{city} CCTV": "{city} CCTV", + "FOV {value}° (DATASHEET)": "FOV {value}°(データシート)", "FOV {value}°": "FOV {value}°", + "SPEC FOV {span}° (CAPABILITY)": "仕様FOV {span}°(可動範囲)", "COVERAGE {value}km²": "カバレッジ {value}km²", "OVERLAP {count} cams": "重複 {count}台", "ISOLATED VIEW": "単独ビュー", @@ -143,8 +525,172 @@ "VIEWSHED": "可視域", "CAL {value}": "CAL {value}", "SRC {value}": "SRC {value}", - "{value} CONTEXT": "{value} コンテキスト", - "Focus fire detection {title}, {details}": "火災検知 {title} にフォーカス、{details}", + "{value} CONTEXT": "{value}コンテキスト", + "{spec} · SPECS: CCTV-DATABASE.COM": "{spec} · 仕様:CCTV-DATABASE.COM", + "Atlantic and eastern/central North Pacific; not worldwide cyclone coverage.": "大西洋と北太平洋東部・中部のみです。全世界のサイクロンを網羅するものではありません。", + "Cyclone advisories unavailable": "サイクロン情報を取得できません", + "Cyclone data unavailable": "サイクロンデータを取得できません", + "Potential tropical cyclone": "潜在的熱帯サイクロン", + "Post-tropical cyclone": "温帯低気圧化したサイクロン", + "Hurricane": "ハリケーン", + "Tropical storm": "熱帯暴風雨", + "Tropical depression": "熱帯低気圧", + "Subtropical storm": "亜熱帯暴風雨", + "Subtropical depression": "亜熱帯低気圧", + "Track and cone match this advisory": "進路と予報円はこの情報と一致しています", + "Track/cone awaiting advisory {number}": "進路/予報円は第{number}報を待機中", + "Track/cone unavailable": "進路/予報円を取得できません", + "Cached advisory · stale source": "キャッシュの情報 · ソース更新遅延", + "Loading advisories…": "情報を読み込み中…", + "{count} active storms": { + "other": "発生中の嵐 {count}個" + }, + "Position as of {time}": "{time}時点の位置", + "Maximum sustained wind: {wind} · Pressure: {pressure}": "最大持続風速:{wind} · 気圧:{pressure}", + "{name} · {classification} · Advisory {number} · issued {time}": "{name} · {classification} · 第{number}報 · {time}発表", + "No active NHC/CPHC systems": "発生中のNHC/CPHCシステムはありません", + "Advisories unavailable": "情報を取得できません", + "Cyclones · NHC / CPHC": "サイクロン · NHC / CPHC", + "Atlantic · E/C Pacific": "大西洋 · 東部/中部太平洋", + "{storms} · {name} selected": "{storms} · {name}を選択中", + "Official advisory ↗": "公式情報 ↗", + "Active NHC and CPHC cyclone advisories": "発生中のNHCおよびCPHCサイクロン情報", + "Wind unavailable": "風のデータを取得できません", + "Advisory center / forecast track": "発表時の中心 / 予報進路", + "Center-track uncertainty cone": "中心進路の予報円", + "Select a storm on the map, or choose a storm in the list to select it and move the camera. Click empty map space to clear the selection. NOAA NHC/CPHC advisory context. The cone describes forecast center-track uncertainty, not storm size or the full hazard area. Forecast point labels are source lead hours, not times computed from advisory issuance. Geometry follows the surface; height is not weather altitude. Consult the official advisory.": "地図上で嵐を選択するか、リストから嵐を選ぶと選択してカメラが移動します。地図の何もない場所をクリックすると選択を解除します。NOAA NHC/CPHCの情報に基づく表示です。予報円は予報される中心進路の不確かさを示すもので、嵐の大きさや危険範囲全体ではありません。予報点のラベルはソースの予報時間で、発表時刻から計算した時刻ではありません。図形は地表に沿って表示され、高さは気象上の高度ではありません。公式情報を確認してください。", + "DRIVE": "車", + "Drive": "車", + "WALK": "徒歩", + "Walk": "徒歩", + "BIKE": "自転車", + "Bike": "自転車", + "rate limited": "レート制限中", + "routing service is rate limited": "ルート検索サービスがレート制限中です", + "route leg too long": "区間が長すぎます", + "route too long": "ルートが長すぎます", + "{error} — try again in a moment": "{error}。しばらくしてからもう一度お試しください", + "Routing is rate limited — try again in a moment": "ルート検索がレート制限中です。しばらくしてからもう一度お試しください", + "Routing unavailable (HTTP {status})": "ルート検索を利用できません(HTTP {status})", + "Routing unavailable": "ルート検索を利用できません", + "direction|left": "左", + "direction|right": "右", + "direction|slightly left": "斜め左", + "direction|slightly right": "斜め右", + "direction|sharply left": "急角度で左", + "direction|sharply right": "急角度で右", + "direction|straight": "まっすぐ", + "direction|around": "反対方向", + "fork direction|left": "左", + "fork direction|right": "右", + "fork direction|slightly left": "やや左", + "fork direction|slightly right": "やや右", + "fork direction|sharply left": "急角度で左", + "fork direction|sharply right": "急角度で右", + "fork direction|straight": "直進", + "lane direction|left": "左", + "lane direction|right": "右", + "lane direction|slightly left": "やや左", + "lane direction|slightly right": "やや右", + "lane direction|sharply left": "急角度で左", + "lane direction|sharply right": "急角度で右", + "lane direction|straight": "直進", + "ordinal|{number}st": "{number}番目", + "ordinal|{number}nd": "{number}番目", + "ordinal|{number}rd": "{number}番目", + "ordinal|{number}th": "{number}番目", + "Head out on {road}": "{road}から出発", + "Head out": "出発", + "Arrive at your destination, on the left": "目的地に到着(左側)", + "Arrive at your destination, on the right": "目的地に到着(右側)", + "Arrive at your destination": "目的地に到着", + "Make a U-turn onto {road}": "Uターンして{road}に入る", + "Make a U-turn": "Uターン", + "Continue straight onto {road}": "直進して{road}に入る", + "Continue straight": "直進", + "Turn {direction} onto {road}": "{direction}に曲がって{road}に入る", + "Turn {direction}": "{direction}に曲がる", + "Turn onto {road}": "曲がって{road}に入る", + "maneuver|Turn": "曲がる", + "Continue {direction} onto {road}": "{direction}に進んで{road}に入る", + "Continue {direction}": "{direction}に進む", + "At the end of the road, turn {direction} onto {road}": "突き当たりを{direction}に曲がって{road}に入る", + "At the end of the road, turn {direction}": "突き当たりを{direction}に曲がる", + "At the end of the road, continue onto {road}": "突き当たりから{road}に入る", + "At the end of the road, continue": "突き当たりをそのまま進む", + "Keep {direction} at the fork onto {road}": "分岐を{direction}方向へ進んで{road}に入る", + "Keep {direction} at the fork": "分岐を{direction}方向へ進む", + "Continue at the fork onto {road}": "分岐を進んで{road}に入る", + "Continue at the fork": "分岐をそのまま進む", + "Merge {direction} onto {road}": "{direction}に合流して{road}に入る", + "Merge {direction}": "{direction}に合流", + "Merge onto {road}": "{road}に合流", + "maneuver|Merge": "合流", + "Take the ramp on the {direction} onto {road}": "{direction}側のランプから{road}に入る", + "Take the ramp on the {direction}": "{direction}側のランプに入る", + "Take the ramp {direction} onto {road}": "ランプを{direction}に進んで{road}に入る", + "Take the ramp {direction}": "ランプを{direction}に進む", + "Take the ramp onto {road}": "ランプから{road}に入る", + "Take the ramp": "ランプに入る", + "Take the exit on the {direction} onto {road}": "{direction}側の出口から{road}に出る", + "Take the exit on the {direction}": "{direction}側の出口を出る", + "Take the exit {direction} onto {road}": "出口を{direction}に進んで{road}に出る", + "Take the exit {direction}": "出口を{direction}に出る", + "Take the exit onto {road}": "出口から{road}に出る", + "Take the exit": "出口を出る", + "At the roundabout, take the {exit} exit onto {road}": "ロータリーで{exit}の出口から{road}に出る", + "At the roundabout, take the {exit} exit": "ロータリーで{exit}の出口を出る", + "Enter the roundabout onto {road}": "ロータリーに入って{road}へ進む", + "Enter the roundabout": "ロータリーに入る", + "At the roundabout, turn {direction} onto {road}": "ロータリーで{direction}に曲がって{road}に入る", + "At the roundabout, turn {direction}": "ロータリーで{direction}に曲がる", + "At the roundabout, continue onto {road}": "ロータリーから{road}に入る", + "At the roundabout, continue": "ロータリーをそのまま進む", + "Exit the roundabout onto {road}": "ロータリーを出て{road}に入る", + "Exit the roundabout": "ロータリーを出る", + "Use the {direction} lane onto {road}": "{direction}車線を通って{road}に入る", + "Use the {direction} lane": "{direction}車線を通行", + "Continue onto {road}": "そのまま{road}に入る", + "maneuver|Continue": "そのまま進む", + "{mode} — reroute for {modeLower}": "{mode}:{modeLower}でルートを再検索", + "CLICK MAP": "地図をクリック", + "SET A": "Aを設定", + "Click a spot on the globe to place A (click again to cancel)": "地球上の地点をクリックしてAを配置(もう一度クリックでキャンセル)", + "Then click the globe to place the start": "次に地球をクリックして出発地を配置", + "SET B": "Bを設定", + "Click a spot on the globe to place B (click again to cancel)": "地球上の地点をクリックしてBを配置(もう一度クリックでキャンセル)", + "Then click the globe to place the destination": "次に地球をクリックして目的地を配置", + "Swap A and B": "AとBを入れ替え", + "FLY ···": "飛行 ···", + "FLYING": "飛行中", + "FLY": "飛行", + "Fly the camera along the route": "ルートに沿ってカメラを飛行", + "Place A and B first": "先にAとBを配置してください", + "action|CLEAR": "消去", + "Remove the route and both markers": "ルートと両方のマーカーを削除", + "press Escape twice to leave Draw": "Escapeを2回押して描画を終了してください", + "{name} is active — turn {name} off, then set {endpoint}": "{name}を使用中です。{name}をオフにしてから{endpoint}を設定してください", + "{name} is active — {leave}, then set {endpoint}": "{name}を使用中です。先に{leave}。その後、{endpoint}を設定してください", + "Only the first {count} turns of this route are shown": "このルートは最初の{count}回の曲がり角のみ表示しています", + "Turn-by-turn directions": "ターンバイターンのルート案内", + "Another map tool is using clicks — close it, then SET A again": "別の地図ツールがクリックを使用中です。そのツールを閉じてから、もう一度Aを設定してください", + "Routing…": "ルート検索中…", + "No route found": "ルートが見つかりません", + "{distance} · {duration} · {mode} · first {count} turns": "{distance} · {duration} · {mode} · 最初の{count}回の曲がり角", + "{distance} · {duration} · {mode}": "{distance} · {duration} · {mode}", + "Click the globe to place {endpoint}": "地球をクリックして{endpoint}を配置", + "SET B, then click the globe": "Bを設定してから地球をクリック", + "SET A, then click the globe": "Aを設定してから地球をクリック", + "Step {step} of {total} · then {leg}": "ステップ {step}/{total} · 次に{leg}", + "Step {step} of {total}": "ステップ {step}/{total}", + "Then: {instruction}": "次:{instruction}", + "No route found between A and B": "AとBの間にルートが見つかりません", + "Routing failed: {error}": "ルート検索に失敗しました:{error}", + "Routing timed out": "ルート検索がタイムアウトしました", + "Routing unavailable — no response from the routing service": "ルート検索を利用できません:ルート検索サービスから応答がありません", + "Earthquake source unavailable": "地震のソースを利用できません", + "Focus fire detection {title}, {details}": "火災検知{title}にフォーカス({details})", + "live feed unavailable": "ライブフィードを利用できません", "{value} conf": "信頼度 {value}", "{value} ago": "{value}前", "sensor n/a": "センサー不明", @@ -155,17 +701,85 @@ "FIRES": "火災", "max {value} MW": "最大 {value} MW", "new {value}": "新規 {value}", + "{value}°N": "{value}°N", + "{value}°S": "{value}°S", + "{value}°E": "{value}°E", + "{value}°W": "{value}°W", "just now": "たった今", "<1m ago": "1分以内", "{count}m ago": "{count}分前", "{count}h ago": "{count}時間前", - "STALE · cached {age}": "古い · キャッシュ {age}", - "refreshing...": "更新中...", - "loading...": "読込中...", + "fire confidence|high": "高", + "fire confidence|nominal": "中", + "fire confidence|low": "低", + "age|<1h": "<1時間", + "age|{count}h": "{count}時間", + "age|{count}d": "{count}日", + "STALE · cached {age}": "更新遅延 · キャッシュ {age}", + "refreshing...": "更新中…", + "loading...": "読込中…", "KEY REQUIRED": "キーが必要", "LIVE · updated {age}": "ライブ · 更新 {age}", + "Source snapshot time unavailable": "ソースのスナップショット時刻を取得できません", + "Live data unavailable": "ライブデータを利用できません", + "Intel Picture": "インテルピクチャー", + "Kinetic 30d": "30日間の軍事行動", + "Border Crisis": "国境危機", + "Iran Picture": "イラン情勢図", + "Iran Kinetic": "イランの軍事行動", + "Yemen FLOT": "イエメン前線(FLOT)", + "Latest Drop": "最新の公開", + "GhostMaps file could not be read": "GhostMapsファイルを読み取れませんでした", + "{count} source links ↗ · click card to open the first": { + "other": "ソースリンク{count}件 ↗ · カードをクリックで最初のリンクを開く" + }, + "S2 · {name}": "S2 · {name}", + "Report": "レポート", + "Open the source for {title}": "{title}のソースを開く", + "GhostMaps catalog unavailable": "GhostMapsカタログを利用できません", + "LIVE · GitHub {commit} · {message} · checked every {seconds}s": "ライブ · GitHub {commit} · {message} · {seconds}秒ごとに確認", + "GitHub {commit} · {message} · reconnecting for live updates": "GitHub {commit} · {message} · ライブ更新のため再接続中", + "Connecting to the S2 GhostMaps repository…": "S2 GhostMapsリポジトリに接続中…", + "{count} placemarks": { + "other": "プレースマーク {count}件" + }, + "S2 Underground publishes these KMZ products to GitHub. New uploads are detected within seconds and replace the previous edition automatically. Click a marker for its report.": "S2 UndergroundはこれらのKMZプロダクトをGitHubで公開しています。新しいアップロードは数秒以内に検出され、以前の版と自動的に置き換わります。マーカーをクリックするとレポートを表示します。", + "Malformed GhostMaps catalog": "GhostMapsカタログの形式が不正です", + "Low-accuracy score < 2%": "低精度スコア < 2%", + "Low-accuracy score 2–10%": "低精度スコア 2–10%", + "Low-accuracy score > 10%": "低精度スコア > 10%", + "GNSS integrity source unavailable": "GNSSインテグリティのソースを利用できません", + "Regional sample · 250 nm radius · cells from visited views over 30 min": "地域サンプル · 半径250 nm · 30分以内に表示したビューのセル", + "Retrying automatically at {time} UTC": "{time} UTCに自動で再試行します", + "Retrying automatically after provider cooldown": "プロバイダーのクールダウン後に自動で再試行します", + "Updates automatically after pan or zoom and once a minute. The public feed covers a 250-nautical-mile circle around the view centre; zooming out does not make it a worldwide snapshot. Blank cells are outside sampled coverage or have insufficient observations.": "パンやズームの後、および1分ごとに自動で更新されます。公開フィードは表示中心から半径250海里の円をカバーします。ズームアウトしても全世界のスナップショットにはなりません。空白のセルは、サンプリング範囲外か観測が不十分です。", + "Low-accuracy score = 100 × max(0, bad − 1) / total: one aircraft is discounted, so this is not the raw share. Cells need {aircraft} aircraft over {minutes} minutes. Navigation-integrity anomalies are not a detection of jamming or spoofing.": "低精度スコア = 100 × max(0, bad − 1) / total:航空機1機分を差し引くため、単純な割合ではありません。セルには{minutes}分間で{aircraft}機の航空機が必要です。航法インテグリティの異常は、妨害(ジャミング)やなりすまし(スプーフィング)を検出したことを意味しません。", + "GNSS snapshot needs a view anchor": "GNSSスナップショットにはビューのアンカーが必要です", + "GNSS feed rate limited (HTTP 429)": "GNSSフィードがレート制限中です(HTTP 429)", + "Malformed GNSS integrity snapshot": "GNSSインテグリティのスナップショットの形式が不正です", + "GNSS integrity snapshot has no observation time": "GNSSインテグリティのスナップショットに観測時刻がありません", + "installation class|AIRFIELD": "飛行場", + "installation class|NAVAL BASE": "海軍基地", + "installation class|RANGE": "演習場", + "installation class|MILITARY LAND": "軍用地", + "installation class|BASE": "基地", + "installation class|BARRACKS": "兵舎", + "installation class|TRAINING AREA": "訓練区域", + "installation class|PLACES CANDIDATE": "Places候補", + "installation class|INSTALLATION": "施設", + "No mapped sites within {km} km of the contact": "コンタクトから{km} km以内にマップ済み施設はありません", + "{count} mapped sites within {km} km of the contact": { + "other": "コンタクトから{km} km以内のマップ済み施設 {count}件" + }, + "No mapped sites in view": "表示範囲内にマップ済み施設はありません", + "{count} mapped sites in view": { + "other": "表示範囲内のマップ済み施設 {count}件" + }, "loading mapped installation context": "マップ済み施設のコンテキストを読み込み中", + "Too many mapped sites in view to list them all": "表示範囲内のマップ済み施設が多すぎて、すべてを一覧表示できません", + "Installation context unavailable": "施設の情報を取得できません", "MAPPED INSTALLATION": "マップ済み施設", + "Unknown": "不明", "LAUNCH SITE · {site}": "射場 · {site}", "LAUNCH SITE": "射場", "T−{time} · {mission}": "T−{time} · {mission}", @@ -173,7 +787,7 @@ "LIFTOFF · {mission}": "リフトオフ · {mission}", "ASCENT REPLAY · {mission}": "上昇リプレイ · {mission}", "ASCENT ESTIMATE · {mission}": "上昇推定 · {mission}", - "STAGE RE-ENTRY / RECOVERY · {mission}": "ステージ再突入 / 回収 · {mission}", + "STAGE RE-ENTRY / RECOVERY · {mission}": "段の再突入 / 回収 · {mission}", "ORBIT REPLAY · {mission}": "軌道リプレイ · {mission}", "PAUSED · {title}": "一時停止 · {title}", "UNSPECIFIED": "未指定", @@ -183,7 +797,7 @@ "POSITION UNAVAILABLE": "位置を取得できません", "FLIGHT {count}": "フライト {count}", "REUSED": "再使用", - "NO STAGE RE-ENTRY / RECOVERY DATA": "ステージの再突入 / 回収データなし", + "NO STAGE RE-ENTRY / RECOVERY DATA": "段の再突入 / 回収データなし", "{count} / 30D": "{count} / 30日", "NO MISSIONS AVAILABLE IN THE CURRENT 30-DAY WINDOW": "現在の30日間に該当するミッションはありません", "DATE UNAVAILABLE": "日付不明", @@ -191,6 +805,7 @@ "Select {mission}": "{mission}を選択", "{value} KM": "{value} KM", "{value} KM/S": "{value} KM/S", + "Selected Space Mission": "選択中の宇宙ミッション", "SELECTED SPACE MISSION": "選択中の宇宙ミッション", "Show all missions": "すべてのミッションを表示", "Deselect mission": "ミッションの選択を解除", @@ -206,8 +821,8 @@ "NAME": "名称", "TYPE": "種別", "DESTINATION": "目的地", - "STAGE / RE-ENTRY / RECOVERY": "ステージ / 再突入 / 回収", - "STAGE": "ステージ", + "STAGE / RE-ENTRY / RECOVERY": "段 / 再突入 / 回収", + "STAGE": "段", "STATUS": "ステータス", "FINAL POSITION": "最終位置", "REPLAY SPEED": "リプレイ速度", @@ -218,23 +833,89 @@ "Next mission": "次のミッション", "SHOW ALL / DESELECT": "すべて表示 / 選択解除", "Pause replay": "リプレイを一時停止", - "Cancel replay": "リプレイをキャンセル", + "Cancel replay": "リプレイを中止", "EST. DOWNRANGE": "推定ダウンレンジ", "PLANNED · ": "計画 · ", "SUPPLIED TRAJECTORY POINTS": "提供された軌道点", "RECONSTRUCTED ESTIMATE": "再構成による推定", "Replay the estimated ascent with a following camera": "追従カメラで、推定された上昇をリプレイします", "Resume replay": "リプレイを再開", - "T minus {seconds}": "T マイナス {seconds}", + "T minus {seconds}": "打ち上げ{seconds}秒前", "Preparing launch site": "射場を準備中", "Liftoff": "リフトオフ", "Ascent replay": "上昇リプレイ", "Orbit replay": "軌道リプレイ", ", paused": "、一時停止中", + "Malformed launch snapshot": "打ち上げスナップショットの形式が不正です", + "Heard by your receiver": "受信機で受信", + "1090 MHz": "1090 MHz", + "978 MHz UAT": "978 MHz UAT", + "browser SDR": "ブラウザーSDR", + "decoder feed": "デコーダーフィード", + "Your RTL-SDR receiver and decoder feed": "お使いのRTL-SDR受信機とデコーダーフィード", + "Your decoder feed": "お使いのデコーダーフィード", + "Your RTL-SDR receiver": "お使いのRTL-SDR受信機", + "NO CALLSIGN": "コールサインなし", + "ALT {altitude} FT · GS {speed} KT · TRK {track}": "高度 {altitude} ft · 対地速度 {speed} kt · 航跡 {track}", + "V/S {rate}": "昇降率 {rate}", + "V/S {rate} FPM": "昇降率 {rate} ft/min", + "POSITION {age}": "位置 {age}", + "POSITION {seconds} S AGO": "位置 {seconds}秒前", + "{count} MSGS": { + "other": "メッセージ {count}件" + }, + "Decoder feeds": "デコーダーフィード", + "WebUSB + decoder feeds": "WebUSB + デコーダーフィード", + "opening receiver": "受信機を開いています", + "checking decoder feeds": "デコーダーフィードを確認中", + "WebUSB needs desktop Chrome or Edge": "WebUSBにはデスクトップ版ChromeまたはEdgeが必要です", + "connect a receiver in Radio": "ラジオで受信機を接続してください", + "receiver is in FM mode": "受信機はFMモードです", + "listening": "受信中", + "USB error": "USBエラー", "Alt unknown": "高度不明", "Type unknown": "機種不明", "Reg unknown": "登録記号不明", "Operator unknown": "運航者不明", + "${amount}K": "${amount}K", + "${amount}M": "${amount}M", + "${amount}B": "${amount}B", + "fire cause|Human": "人為", + "fire cause|Natural": "自然", + "fire cause|Undetermined": "未確定", + "fire cause|Unknown": "不明", + "fire behavior|Minimal": "微弱", + "fire behavior|Moderate": "中程度", + "fire behavior|Active": "活発", + "fire behavior|Extreme": "極端", + "Type {level} Incident": "タイプ{level}インシデント", + "age|{count}m": "{count}分", + "{acres} ac": { + "other": "{acres}エーカー" + }, + "{percent}% contained": "{percent}%鎮圧", + "containment unknown": "鎮圧率不明", + "{cause} cause": "原因:{cause}", + "{personnel} personnel": { + "other": "人員{personnel}人" + }, + "{county} County": "{county}郡", + "{cost} to date": "これまでの費用 {cost}", + "discovered {age} ago": "{age}前に発見", + "updated {age} ago": "{age}前に更新", + "part of {complex}": "{complex}の一部", + "InciWeb ↗ · click card to open": "InciWeb ↗ · カードをクリックで開く", + "FIRE · {name}": "火災 · {name}", + "Unnamed incident": "名称未設定の火災", + "Open {title} on InciWeb": "InciWebで{title}を開く", + "Perimeter source unavailable": "延焼範囲のソースを利用できません", + "Not contained or unknown": "未鎮圧または不明", + "Under 50% contained": "鎮圧50%未満", + "50–99% contained": "鎮圧50–99%", + "Fully contained": "完全鎮圧", + "Colour shows reported containment. Perimeters are simplified to about 100 m.": "色は報告された鎮圧率を示します。延焼範囲は約100 mに簡略化されています。", + "Malformed perimeter snapshot": "延焼範囲スナップショットの形式が不正です", + "radio tag|All": "すべて", "News": "ニュース", "Talk": "トーク", "Weather / Emergency": "気象 / 緊急", @@ -243,6 +924,21 @@ "Traffic / Transit": "交通 / 公共交通", "Music": "音楽", "Other": "その他", + "Directory refresh degraded; showing the previous station catalog.": "ディレクトリの更新が不完全です。前回の局カタログを表示しています。", + "Radio directory coverage is degraded.": "ラジオディレクトリのカバー範囲が不完全です。", + "Directory refresh failed; showing the previous station catalog.": "ディレクトリの更新に失敗しました。前回の局カタログを表示しています。", + "Radio directory is temporarily unavailable.": "ラジオディレクトリは一時的に利用できません。", + "radio|NEWS": "ニュース", + "radio|TALK": "トーク", + "radio|WEATHER": "気象", + "radio|SAFETY": "安全", + "radio|AIR / SEA": "航空 / 海事", + "radio|TRANSIT": "交通", + "radio|MUSIC": "音楽", + "radio|OTHER": "その他", + "Broadcaster stream is unavailable or blocked by the browser.": "放送局のストリームを利用できないか、ブラウザーにブロックされています。", + "Playback requires a direct click or tap.": "再生するには直接クリックまたはタップしてください。", + "Broadcaster stream could not be started.": "放送局のストリームを開始できませんでした。", "Alternative": "オルタナティブ", "Ambient": "アンビエント", "Blues": "ブルース", @@ -268,82 +964,600 @@ "Techno": "テクノ", "Trance": "トランス", "World": "ワールド", - "Add the full Starlink broadband shell (thousands of extra points)": "Starlink ブロードバンドシェル全体を追加 (数千の追加ポイント)", - "Loading the Starlink shell…": "Starlink シェルを読み込み中…", + "overview": "概観", + "cloud unknown": "雲量不明", + "{percent}% scene cloud": "シーン雲量 {percent}%", + "{min}–{max}% scene cloud": "シーン雲量 {min}–{max}%", + "Comparison in use by another scene": "比較機能は別のシーンで使用中です", + "Esri map unavailable · no swipe": "Esriマップ利用不可 · スワイプ比較不可", + "Swipe needs a globe map": "スワイプ比較には地球儀マップが必要です", + "Imagery stays on Esri · CLEAR to use Google 3D": "画像はEsriのまま · 消去するとGoogle 3Dを使用", + "Imagery catalog unavailable": "画像カタログを利用できません", + "Catalog truncated · a newer clear day may exist": "カタログ省略あり · より新しい晴天日がある可能性", + "{label} catalog unavailable · {detail}": "{label}のカタログを利用できません · {detail}", + "Daily overview for today may still be empty until the pass": "今日の日次概観は、衛星の通過まで空の場合があります", + "Box and images cleared": "範囲と画像を消去しました", + "MORE DETAIL · 30 m": "高詳細 · 30 m", + "Sentinel-2 and Landsat via HLS, 30 m, every 2–6 days": "HLS経由のSentinel-2とLandsat、30 m、2~6日ごと", + "DAILY OVERVIEW · 250 m": "日次概観 · 250 m", + "VIIRS daily mosaic, 250 m, follows broad changes; little detail under 25 km": "VIIRSの日次モザイク、250 m。広域の変化を追跡。25 km未満の詳細はほぼなし", + "Sentinel-2": "Sentinel-2", + "Sentinel-2 via HLS": "Sentinel-2(HLS経由)", + "Landsat 8/9": "Landsat 8/9", + "Landsat 8/9 via HLS": "Landsat 8/9(HLS経由)", + "Daily overview": "日次概観", + "Box edges must be finite": "範囲の端は有限の値である必要があります", + "Longitudes must be within ±180°": "経度は±180°以内である必要があります", + "Select one side of the dateline": "日付変更線の片側を選択してください", + "Box must enclose an area": "範囲は面積を囲む必要があります", + "Add the full Starlink broadband shell (thousands of extra points)": "Starlinkブロードバンドシェル全体を追加(数千の追加ポイント)", + "Loading the Starlink shell…": "Starlinkシェルを読み込み中…", "Starlink {detail} — click to retry": "Starlink {detail}: クリックで再試行", "load failed": "読込失敗", - "Showing the full Starlink shell — click for the core catalog only": "Starlink シェル全体を表示中: クリックでコアカタログのみに戻す", + "Showing the full Starlink shell — click for the core catalog only": "Starlinkシェル全体を表示中:クリックでコアカタログのみに戻す", "DENSE ···": "高密度 ···", "DENSE ✕": "高密度 ✕", "DENSE": "高密度", - "Syncing flow · Roads: {source}": "フロー同期中 · 道路: {source}", - "LIVE · Roads: {source} · Roads without flow hidden": "ライブ · 道路: {source} · フローのない道路は非表示", - "LIVE · Roads: {source} · No flow roads in view": "ライブ · 道路: {source} · 表示範囲にフローのある道路なし", - "LIVE · Roads: {source} · Flow {percent}%": "ライブ · 道路: {source} · フロー {percent}%", - "SIMULATED · Roads: {source} · Flow {percent}%": "シミュレーション · 道路: {source} · フロー {percent}%", - "Syncing flow · Roads: OpenStreetMap · Flow: TomTom · Unmatched: simulated": "フロー同期中 · 道路: OpenStreetMap · フロー: TomTom · 未一致: シミュレーション", - "LIVE · Roads: OpenStreetMap · Flow: TomTom · {percent}% cov · Unmatched: simulated": "ライブ · 道路: OpenStreetMap · フロー: TomTom · カバー率 {percent}% · 未一致: シミュレーション", - "LIVE · Roads: OpenStreetMap · Flow: TomTom · {percent}% cov": "ライブ · 道路: OpenStreetMap · フロー: TomTom · カバー率 {percent}%", - "SIMULATED · Roads: OpenStreetMap · Flow: TomTom (no matches)": "シミュレーション · 道路: OpenStreetMap · フロー: TomTom (一致なし)", - "SIMULATED — traffic service unreachable": "シミュレーション: 交通サービスに接続できません", - "SIMULATED — add TomTom key for live": "シミュレーション: ライブ表示には TomTom キーを追加", + "CelesTrak unreachable": "CelesTrakに接続できません", + "DOCKED · {name} · +{extra}": "ドッキング中 · {name} · +{extra}", + "DOCKED · {name}": "ドッキング中 · {name}", + "{name} needs the Google 3D map: choose it under MAP SOURCE": "{name}にはGoogle 3Dマップが必要です。マップソースで選択してください", + "zoom in to a street to open {name}": "{name}を開くには通りまでズームイン", + "loading coverage...": "カバー範囲を読み込み中…", + "No street-level imagery within {radius} m of that point": "その地点から{radius} m以内にストリートレベル画像はありません", + "No street-level imagery within {radius} m of the view centre": "表示中心から{radius} m以内にストリートレベル画像はありません", + "Zoom in to see street-level coverage": "ズームインしてストリートレベルのカバー範囲を表示", + "Point the camera at the ground for street-level coverage": "ストリートレベルのカバー範囲を見るには、カメラを地面に向けてください", + "Coverage tile failed": "カバー範囲タイルの読み込みに失敗しました", + "The photo could not be loaded": "写真を読み込めませんでした", + "{name} photo. ← and → step along the sequence. On a 360° photo, drag or use Shift+← →, ↑ ↓ to look around, and + − to zoom": "{name}の写真。←と→でシーケンス内を移動。360°写真では、ドラッグまたはShift+← →、↑ ↓で見回し、+ −でズーム", + "{name} street-level photo": "{name}のストリートレベル写真", + "Previous photo in this sequence (←)": "このシーケンスの前の写真(←)", + "Next photo in this sequence (→)": "このシーケンスの次の写真(→)", + "Aim the middle of the view at a street to look for imagery there": "画像を探すには、表示の中央を通りに合わせてください", + "KEY REJECTED": "キーが拒否されました", + "GOOGLE_MAPS_API_KEY is not set": "GOOGLE_MAPS_API_KEYが設定されていません", + "The Google Maps JavaScript API could not load": "Google Maps JavaScript APIを読み込めませんでした", + "Google Street View": "Googleストリートビュー", + "GOOGLE STREET VIEW": "GOOGLEストリートビュー", + "Google refused GOOGLE_MAPS_API_KEY for Street View — check that the Maps JavaScript API is enabled for it and this site is an allowed referrer": "GoogleがストリートビューへのGOOGLE_MAPS_API_KEYを拒否しました。このキーでMaps JavaScript APIが有効になっていること、このサイトが許可されたリファラーであることを確認してください", + "Street View did not answer — check the network, and that the Maps JavaScript API is enabled for GOOGLE_MAPS_API_KEY": "ストリートビューから応答がありません。ネットワーク、およびGOOGLE_MAPS_API_KEYでMaps JavaScript APIが有効になっていることを確認してください", + "click a street to open Street View": "通りをクリックしてストリートビューを開く", + "Street View has no imagery for this place": "この場所のストリートビュー画像はありません", + "KartaView has no position for this photo": "KartaViewにこの写真の位置情報がありません", + "The KartaView photo could not be loaded": "KartaViewの写真を読み込めませんでした", + "zoom in to see KartaView coverage": "ズームインしてKartaViewのカバー範囲を表示", + "no KartaView photos in view": "表示範囲内にKartaViewの写真はありません", + "KartaView is rate-limiting requests — they resume on their own": "KartaViewがリクエストをレート制限中です。自動的に再開されます", + "KartaView’s photos here are archived and cannot be shown": "この場所のKartaViewの写真はアーカイブ済みのため表示できません", + "KartaView did not filter this area in time — move the map to ask again": "KartaViewがこの範囲を時間内に絞り込めませんでした。地図を動かして再度リクエストしてください", + "None of KartaView’s photos here pass the imagery filter": "この場所のKartaViewの写真はいずれも画像フィルターを通過しません", + "KartaView did not answer in time — try again": "KartaViewから時間内に応答がありませんでした。もう一度お試しください", + "KartaView could not be reached — check the network": "KartaViewに接続できません。ネットワークを確認してください", + "KartaView sent an answer that could not be read": "KartaViewから読み取れない応答が返されました", + "KartaView is rate-limiting requests": "KartaViewがリクエストをレート制限中です", + "KartaView sent too much data": "KartaViewから送られたデータが多すぎます", + "KartaView is rate-limiting requests — try again in a moment": "KartaViewがリクエストをレート制限中です。しばらくしてからもう一度お試しください", + "KartaView has no such photo": "KartaViewにその写真はありません", + "Mapillary rejected MAPILLARY_CLIENT_TOKEN — replace it in Provider Settings": "MapillaryがMAPILLARY_CLIENT_TOKENを拒否しました。プロバイダー設定で置き換えてください", + "Coverage requests are being rate-limited — they resume on their own": "カバー範囲のリクエストがレート制限中です。自動的に再開されます", + "The Panoramax photo could not be loaded": "Panoramaxの写真を読み込めませんでした", + "Panoramax is busy — coverage resumes on its own": "Panoramaxが混雑しています。カバー範囲は自動的に再開されます", + "no Panoramax photos in view": "表示範囲内にPanoramaxの写真はありません", + "no Panoramax photos here match the filters": "この場所にフィルターに一致するPanoramaxの写真はありません", + "Panoramax sent a map tile that could not be read": "Panoramaxから読み取れない地図タイルが返されました", + "This Panoramax photo is no longer available": "このPanoramaxの写真は利用できなくなりました", + "zoom in to see Panoramax coverage": "ズームインしてPanoramaxのカバー範囲を表示", + "Panoramax did not answer in time — try again": "Panoramaxから時間内に応答がありませんでした。もう一度お試しください", + "Panoramax could not be reached — check the connection": "Panoramaxに接続できません。接続を確認してください", + "Panoramax sent too much data": "Panoramaxから送られたデータが多すぎます", + "Panoramax is busy": "Panoramaxが混雑しています", + "Panoramax sent an unreadable answer": "Panoramaxから読み取れない応答が返されました", + "Sequence images unavailable": "シーケンス画像を利用できません", + "No street-level imagery providers configured": "ストリートレベル画像のプロバイダーが設定されていません", + "(by upload date)": "(アップロード日順)", + "Open the Street Level panel to view imagery": "画像を表示するには、ストリートレベルパネルを開いてください", + "Image could not be opened": "画像を開けませんでした", + "TeleGeography load failed": "TeleGeographyの読み込みに失敗しました", + "UNAVAILABLE · {source} · Roads unavailable": "利用不可 · {source} · 道路を利用できません", + "Roads: {source}": "道路:{source}", + "TomTom roads unavailable while the traffic service is unreachable": "交通サービスに接続できない間はTomTomの道路を利用できません", + "Hybrid unavailable while the traffic service is unreachable": "交通サービスに接続できない間はハイブリッドを利用できません", + "TomTom roads need a TomTom key": "TomTomの道路にはTomTomキーが必要です", + "Hybrid needs a TomTom key": "ハイブリッドにはTomTomキーが必要です", + "Local surface still loading": "周辺の路面を読み込み中", + "Partial coverage": "一部のみカバー", + "Detailed roads unavailable": "詳細な道路を利用できません", + "Reduced detail coverage": "詳細なカバー範囲が限定的", + "TomTom roads only, each with its live flow": "TomTomの道路のみ(各道路にライブの交通流)", + "TomTom roads only, each with its live flow (needs a TomTom key)": "TomTomの道路のみ(各道路にライブの交通流、TomTomキーが必要)", + "OpenStreetMap roads, with TomTom flow matched when available": "OpenStreetMapの道路(利用可能な場合はTomTomの交通流を照合)", + "TomTom roads first; OpenStreetMap fills the rest, simulated": "TomTomの道路を優先し、残りはOpenStreetMapで補完(シミュレーション)", + "TomTom roads first; OpenStreetMap fills the rest, simulated (needs a TomTom key)": "TomTomの道路を優先し、残りはOpenStreetMapで補完(シミュレーション、TomTomキーが必要)", + "Hybrid": "ハイブリッド", + "TomTom key unavailable": "TomTomキーを利用できません", + "TomTom daily budget reached": "TomTomの1日の上限に達しました", + "TomTom upstream unreachable": "TomTomの上流サービスに接続できません", + "TomTom flow unavailable": "TomTomの交通流を利用できません", + "SIMULATED — {reason}": "シミュレーション:{reason}", + "Syncing flow · Roads: {source}": "フロー同期中 · 道路:{source}", + "LIVE · Roads: {source} · Roads without flow hidden": "ライブ · 道路:{source} · フローのない道路は非表示", + "LIVE · Roads: {source} · No flow roads in view": "ライブ · 道路:{source} · 表示範囲にフローのある道路なし", + "LIVE · Roads: {source} · Flow {percent}%": "ライブ · 道路:{source} · フロー {percent}%", + "SIMULATED · Roads: {source} · Flow {percent}%": "シミュレーション · 道路:{source} · フロー {percent}%", + "Syncing flow · Roads: OpenStreetMap · Flow: TomTom · Unmatched: simulated": "フロー同期中 · 道路:OpenStreetMap · フロー:TomTom · 未一致:シミュレーション", + "LIVE · Roads: OpenStreetMap · Flow: TomTom · {percent}% cov · Unmatched: simulated": "ライブ · 道路:OpenStreetMap · フロー:TomTom · カバー率 {percent}% · 未一致:シミュレーション", + "LIVE · Roads: OpenStreetMap · Flow: TomTom · {percent}% cov": "ライブ · 道路:OpenStreetMap · フロー:TomTom · カバー率 {percent}%", + "SIMULATED · Roads: OpenStreetMap · Flow: TomTom (no matches)": "シミュレーション · 道路:OpenStreetMap · フロー:TomTom(一致なし)", + "SIMULATED — traffic service unreachable": "シミュレーション:交通サービスに接続できません", + "SIMULATED — add TomTom key for live": "シミュレーション:ライブ表示にはTomTomキーを追加", + "OpenFreeMap tiles rate-limited": "OpenFreeMapタイルがレート制限中", + "OpenFreeMap tiles timed out": "OpenFreeMapタイルがタイムアウトしました", + "OpenFreeMap tiles unavailable": "OpenFreeMapタイルを利用できません", + "occupancy|empty": "空車", + "occupancy|many seats available": "空席多数", + "occupancy|few seats available": "空席わずか", + "occupancy|standing room only": "立ち席のみ", + "occupancy|crushed standing room only": "満員に近い立ち席のみ", + "occupancy|full": "満員", + "occupancy|not accepting passengers": "乗車不可", + "occupancy|not boardable": "乗車できません", + "Route {route}": "路線 {route}", + "Vehicle {vehicle}": "車両 {vehicle}", + "vehicle motion|Stopped": "停車中", + "No recent fix": "最近の測位なし", + "Waiting for update": "更新待ち", + "Moving": "走行中", + "reported {speed} km/h": "報告速度 {speed} km/h", + "reported hdg {heading}°": "報告方位 {heading}°", + "Last report: stopped at stop {stop}": "最終報告:停留所{stop}に停車中", + "Last report: arriving at stop {stop}": "最終報告:停留所{stop}に到着中", + "Last report: next stop {stop}": "最終報告:次の停留所{stop}", + "Shown at street level · depth not in the feed": "地表の高さで表示 · フィードに深さ情報なし", + "Reported {seconds} s ago": "{seconds}秒前に報告", + "Reported {minutes} min ago": "{minutes}分前に報告", + "shown {seconds} s behind": "{seconds}秒遅れで表示", + "{reported} (feed time)": "{reported}(フィード時刻)", + "Available trail: {minutes} min (limited)": "利用可能な軌跡:{minutes}分(制限あり)", + "Available trail: {minutes} min": "利用可能な軌跡:{minutes}分", + "Bus": "バス", + "Tram": "路面電車", + "Subway": "地下鉄", + "Train": "鉄道", + "Ferry": "フェリー", + "Transit vehicle": "公共交通車両", "AIS: {name}": "AIS: {name}", "{type} SPD: {speed} HDG: {heading}": "{type} SPD: {speed} HDG: {heading}", "VESSEL": "船舶", - "POS: LIVE": "位置: ライブ", - "POS: {time}Z": "位置: {time}Z", + "{speed}KT": "{speed} kt", + "{heading}DEG": "{heading}°", + "POS: LIVE": "位置:ライブ", + "POS: {time}Z": "位置:{time}Z", + "AIS live load failed": "AISライブデータの読み込みに失敗しました", "awaiting first AIS position…": "最初のAIS位置を待機中…", "awaiting usable AIS positions…": "利用可能なAIS位置を待機中…", "awaiting first AIS message…": "最初のAISメッセージを待機中…", + "AISSTREAM_API_KEY not set": "AISSTREAM_API_KEYが設定されていません", + "live feed unsupported": "ライブフィード非対応", + "connecting to feed…": "フィードに接続中…", + "feed disconnected": "フィード切断", + "feed down": "フィード停止", + "feed idle": "フィード待機中", + "API key rejected — check AISSTREAM_API_KEY": "APIキーが拒否されました。AISSTREAM_API_KEYを確認してください", + "feed silent {seconds}s — no AIS data": "フィード無応答 {seconds}秒:AISデータなし", + "feed silent — no AIS data": "フィード無応答:AISデータなし", + "feed down — retrying slowly (attempt {attempt})": "フィード停止:低頻度で再試行中({attempt}回目)", + "reconnecting to feed… (attempt {attempt})": "フィードに再接続中…({attempt}回目)", + "feed down — retrying slowly": "フィード停止:低頻度で再試行中", + "reconnecting to feed…": "フィードに再接続中…", + "Focus vessel {name}, MMSI {mmsi}": "船舶{name}(MMSI {mmsi})にフォーカス", + "Hidden by this map source · choose a globe map": "このマップソースでは非表示 · 地球儀マップを選択してください", + "Weather image HTTP {status}": "気象画像 HTTP {status}", + "Weather HTTP {status}": "気象 HTTP {status}", + "Frame unavailable; previous observation retained": "フレームを利用できません。前回の観測を保持しています", + "Weather imagery unavailable": "気象画像を利用できません", + "Weather source unavailable; previous observation retained": "気象ソースを利用できません。前回の観測を保持しています", + "Weather unavailable": "気象データを利用できません", + "No frame within {gap} min of {time}": "{time}の前後{gap}分以内にフレームがありません", + "No frame within {gap} h of {time}": "{time}の前後{gap}時間以内にフレームがありません", + "{hours}h {minutes}m ago": "{hours}時間{minutes}分前", + "{minutes}m ago": "{minutes}分前", + "{state} · {time} · {lag}": "{state} · {time} · {lag}", + "Observed": "観測", + "History": "履歴", + "Observation unavailable": "観測を利用できません", + "Waiting for observation": "観測を待機中", + "{detail} · synced": "{detail} · 同期済み", + "{detail} · nearest": "{detail} · 最も近いフレーム", + "RADAR REFLECTIVITY · dBZ": "レーダー反射強度 · dBZ", + "LIGHTNING DENSITY · 15 min accumulation": "雷密度 · 15分間積算", + "GLOBAL INFRARED · hourly": "全球赤外 · 1時間ごと", + "GOES INFRARED · ~5 min": "GOES赤外 · 約5分ごと", + "{state}: {time}": "{state}:{time}", + "Latest observation": "最新の観測", + "frame {index}/{total}": "フレーム {index}/{total}", + "loading": "読み込み中", + "Observation: unavailable": "観測:利用不可", + "Contiguous US · gaps ≠ no rain": "米国本土 · 欠測 ≠ 降水なし", + "Americas + Pacific · not individual strikes": "南北アメリカ + 太平洋 · 個々の落雷ではありません", + "Color: strikes/km²/min ×10³": "色:落雷数/km²/分 ×10³", + "60°S–60°N · typically 2–3 h delayed": "60°S–60°N · 通常2~3時間遅れ", + "North America · infrared imagery": "北米 · 赤外画像", + "Reduced motion · history playback unavailable": "動きを減らす · 履歴再生は利用不可", + "Reduced motion · manual history available": "動きを減らす · 手動で履歴を表示可能", + "Rain radar · US": "降水レーダー · 米国", + "Lightning density · 15 min": "雷密度 · 15分", + "Satellite clouds": "衛星雲画像", + "Americas + Pacific": "南北アメリカ + 太平洋", + "Global · 60°S–60°N": "全球 · 60°S–60°N", + "North America": "北米", + "Source observations delayed": "ソースの観測が遅れています", + "Stale source": "ソース更新遅延", + "Loading next frame…": "次のフレームを読み込み中…", + "Map center outside coverage": "地図の中心がカバー範囲外です", + "strikes/km²/min ×10³": "落雷数/km²/分 ×10³", + "N. America": "北米", + "Global": "全球", + "Hourly global mosaic; usually 2–3 hours delayed": "1時間ごとの全球モザイク。通常2~3時間遅れ", + "GOES regional clouds; approximately 5-minute updates": "GOESの地域雲画像。約5分ごとに更新", + "Clouds only": "雲のみ", + "Apply the full cloud brightness key; 100% filter strength": "雲の輝度キーを完全に適用。フィルター強度100%", + "Full": "全体", + "Show the complete infrared image; 0% filter strength": "赤外画像全体を表示。フィルター強度0%", + "Soft": "弱", + "Vivid": "強", + "Image opacity; does not alter the observed values": "画像の不透明度。観測値は変わりません", + "View US radar": "米国のレーダーを表示", + "View Americas & Pacific": "南北アメリカと太平洋を表示", + "View coverage": "カバー範囲を表示", + "{value} strikes/km²/min ×10³ (15-minute density)": "{value}落雷数/km²/分 ×10³(15分間の密度)", + "{value} dBZ radar reflectivity": "{value} dBZレーダー反射強度", + "STALE · cached source metadata": "更新遅延 · キャッシュ済みのソースメタデータ", + "Map center is outside source coverage": "地図の中心がソースのカバー範囲外です", + "NOAA/NWS 15-minute lightning density derived from Vaisala NLDN/GLD360. Coverage 110°E across the Pacific/Americas to 0°, 25°S–80°N. Not a live strike count, global coverage or a safety warning.": "Vaisala NLDN/GLD360から算出したNOAA/NWSの15分間雷密度。カバー範囲は東経110°から太平洋・南北アメリカを経て0°まで、南緯25°~北緯80°。リアルタイムの落雷数、全球カバー、安全上の警報ではありません。", + "NOAA MRMS radar echoes indicate precipitation patterns, not rain rate, a storm warning or a future forecast. Native source approximately 1 km; display is limited to level 6. Frames use exact advertised observation times.": "NOAA MRMSのレーダーエコーは降水のパターンを示すもので、降水強度、嵐の警報、将来の予報ではありません。元データの解像度は約1 km、表示はズームレベル6までです。各フレームは公表された正確な観測時刻を使用します。", + "GOES-19/18 longwave infrared Band 14 regional; NESDIS global longwave mosaic. Clouds only dims everything but bright, cold cloud tops; a brightness filter, not a cloud mask. Coverage and freshness differ by region.": "GOES-19/18長波赤外バンド14の地域画像と、NESDISの全球長波モザイク。「雲のみ」は明るく冷たい雲頂以外をすべて暗くします。これは輝度フィルターであり、雲マスクではありません。カバー範囲と鮮度は地域によって異なります。", + "REGION": "地域", + "IMAGE": "画像", + "FILTER": "フィルター", + "Cloud filter strength": "雲フィルターの強度", + "OPACITY": "不透明度", + "Infrared decode failed": "赤外画像のデコードに失敗しました", + "Weather prefetch unavailable": "気象のプリフェッチを利用できません", + "Weather tiles unavailable · previous frame retained": "気象タイルを利用できません · 前のフレームを保持", + "Some weather tiles unavailable": "一部の気象タイルを利用できません", + "Malformed weather manifest": "気象マニフェストの形式が不正です", + "Weather request timed out": "気象リクエストがタイムアウトしました", + "Temperature field unavailable": "気温場を利用できません", + "Mean sea level pressure field unavailable": "平均海面気圧場を利用できません", + "Wind upstream unavailable": "風の上流ソースを利用できません", + "{source} HTTP {status}": "{source} HTTP {status}", + "Wind": "風", + "Wind source unavailable": "風のソースを利用できません", + "Forecast · does not follow history": "予報 · 履歴とは連動しません", + "Wind motion": "風の流れ", + "Wind speed": "風速", + "Sea-level pressure": "海面気圧", + "Air temperature · 2 m": "気温 · 2 m", + "Global · 1° grid": "全球 · 1°格子", + "{model} forecast · {time}": "{model}予報 · {time}", + "Loading forecast": "予報を読み込み中", + "Preparing flow": "流れを準備中", + "Selected field unavailable": "選択した要素を利用できません", + "Cached forecast · stale": "キャッシュの予報 · 更新遅延", + "ECMWF IFS surface forecast": "ECMWF IFS地上予報", + "NOAA GFS surface forecast": "NOAA GFS地上予報", + "Reduced motion": "動きを減らす", "Resume": "再開", "Pause": "一時停止", - "Error: {message}": "エラー: {message}", + "Pause visual flow; forecast time does not advance with animation": "流れのアニメーションを一時停止。予報時刻はアニメーションでは進みません", + "None": "なし", + "Speed": "風速", + "Pressure": "気圧", + "Temperature": "気温", + "Wind trails with no field shading": "要素の塗り分けなしで風の軌跡を表示", + "How hard the surface wind is blowing": "地上風の強さ", + "Sea-level air pressure: broad highs and lows": "海面気圧:広域の高気圧と低気圧", + "Air temperature two meters above the surface": "地上2 mの気温", + "Wind speed units": "風速の単位", + "Read wind at map center": "地図中心の風を読み取る", + "Read the forecast at the center of the map without changing selection": "選択を変えずに地図中心の予報値を読み取る", + "{model} forecast · {field} ({unit})": "{model}予報 · {field}({unit})", + "Valid: {time}": "対象時刻:{time}", + "preparing": "準備中", + "Issued: {time}": "発表:{time}", + "Selected field unavailable · wind remains visible": "選択した要素を利用できません · 風は表示されたまま", + "{error} · wind remains visible": "{error} · 風は表示されたまま", + "Surface wind at 10 m. Approximately 1° global grid. Curves follow the 10 m wind field, lifted 12 km for visibility; display height is not weather altitude. View lighting is for readability. Animation shows flow through one fixed forecast; it does not advance time. Color fields drape the globe basemap or the active photorealistic 3D Tiles.": "高度10 mの地上風。約1°の全球格子。曲線は10 mの風の場に沿っており、見やすさのため12 km持ち上げています。表示の高さは気象上の高度ではありません。ビューの照明は読みやすさのためです。アニメーションは1つの固定された予報内の流れを示し、時間は進みません。色の塗り分けは地球儀のベースマップまたは有効なフォトリアル3D Tilesの上に重なります。", + "MODEL": "モデル", + "FIELD": "要素", + "UNITS": "単位", + "MOTION": "モーション", + "Forecast": "予報", + "N": "北", + "NNE": "北北東", + "NE": "北東", + "ENE": "東北東", + "E": "東", + "ESE": "東南東", + "SE": "南東", + "SSE": "南南東", + "S": "南", + "SSW": "南南西", + "SW": "南西", + "WSW": "西南西", + "W": "西", + "WNW": "西北西", + "NW": "北西", + "NNW": "北北西", + "No surface reading": "地上の値がありません", + "Aim the map center at Earth": "地図の中心を地球に合わせてください", + "A location reading needs a loaded forecast and the Earth at the center of the view.": "地点の値を読み取るには、予報が読み込まれ、表示の中心に地球がある必要があります。", + "Interpolated model forecast on an approximately 1° grid. Broad weather patterns, not a street-level measurement.": "約1°格子で補間したモデル予報です。大まかな気象パターンを示すもので、街区単位の実測値ではありません。", + " · calm": " · 静穏", + " from {direction}": " · {direction}の風", + "WIND AT {coordinates}": "{coordinates}の風", + "{model} · valid {time}": "{model} · 対象時刻 {time}", + "Wind speed field unavailable": "風速場を利用できません", + "Globe imagery unavailable": "地球儀の画像を利用できません", + "Globe field image unavailable": "地球儀の要素画像を利用できません", + "Unknown wind model": "不明な風モデル", + "Unknown weather overlay": "不明な気象オーバーレイ", + "Wind request timed out": "風のリクエストがタイムアウトしました", + "Malformed wind manifest": "風マニフェストの形式が不正です", + "Malformed wind grid": "風グリッドの形式が不正です", + "Error: {message}": "エラー:{message}", "Needs {envVars} — add it in Provider Settings": "{envVars}が必要です。プロバイダー設定で追加してください", "{label} is unavailable": "{label}は利用できません", "This map stack": "このマップスタック", - "{label} unavailable: {hint}": "{label}は利用できません: {hint}", - "Visible map targets": "表示中のマップターゲット", + "{label} unavailable: {hint}": "{label}は利用できません:{hint}", + "Google 3D tiles unavailable — check the key's API restrictions, quota, or network": "Google 3D Tilesを利用できません。キーのAPI制限、割り当て、ネットワークを確認してください", + "Needs {envVars} — add it in Provider Settings — or a Cesium ion token for the ion-hosted route": "{envVars}が必要です(プロバイダー設定で追加)。またはion経由で利用するためのCesium ionトークンが必要です", + "Exit cockpit to fly to a camera": "カメラへ移動するにはコックピットを終了してください", + "Exit cockpit to fly to a location": "場所へ移動するにはコックピットを終了してください", + "Exit cockpit to fly to a photo": "写真へ移動するにはコックピットを終了してください", + "Exit cockpit to fly to a shared view": "共有ビューへ移動するにはコックピットを終了してください", + "Exit cockpit to fly to a target": "ターゲットへ移動するにはコックピットを終了してください", + "Exit cockpit to fly to a vessel": "船舶へ移動するにはコックピットを終了してください", + "Exit cockpit to fly to a fire": "火災へ移動するにはコックピットを終了してください", + "Exit cockpit to fly to a route": "ルートへ移動するにはコックピットを終了してください", + "Exit cockpit to fly to a file": "ファイルの位置へ移動するにはコックピットを終了してください", + "Exit cockpit to fly to a scene": "シーンへ移動するにはコックピットを終了してください", + "Exit cockpit to view weather coverage": "気象のカバー範囲を表示するにはコックピットを終了してください", + "Exit cockpit to fly to a cyclone": "サイクロンへ移動するにはコックピットを終了してください", + "Exit cockpit to fly to an aircraft": "航空機へ移動するにはコックピットを終了してください", + "Exit cockpit to fly to a satellite": "衛星へ移動するにはコックピットを終了してください", + "Exit cockpit to frame contacts": "コンタクトを視野に収めるにはコックピットを終了してください", + "Visible map targets": "表示中の地図上のターゲット", + "Focusing {label}": "{label}にフォーカス中", + "Source": "ソース", + "Camera ownership changed": "カメラの制御元が変わりました", + "Saved project could not be read; storage preserved. Import a valid file to resume saving.": "保存済みのプロジェクトを読み取れませんでした。ストレージは保持されています。保存を再開するには有効なファイルをインポートしてください。", "Ready": "準備完了", - "Loaded: {scene} / {shot}": "読み込みました: {scene} / {shot}", - "Cannot capture shot: camera not ready": "ショットを取得できません: カメラの準備ができていません", - "Captured: {scene} / {shot}": "取得しました: {scene} / {shot}", + "Scene layer turned off": "シーンのレイヤーをオフにしました", + "Stopped": "停止しました", + "Scene not saved — existing saved project could not be read. Export edits or import a valid file.": "シーンは保存されていません:既存の保存済みプロジェクトを読み取れませんでした。編集内容をエクスポートするか、有効なファイルをインポートしてください。", + "Scene not saved — {reason}": "シーンは保存されていません:{reason}", + "Scene not saved — browser storage unavailable": "シーンは保存されていません:ブラウザーのストレージを利用できません", + "Loaded: {scene} / {shot}": "読み込みました:{scene} / {shot}", + "Cannot update {scene}: shot inventory changed": "{scene}を更新できません:ショット構成が変わりました", + "Cannot update {scene}: evidence beats changed": "{scene}を更新できません:証拠の区切りが変わりました", + "Cannot update {scene}: shot bindings are incomplete": "{scene}を更新できません:ショットのバインドが不完全です", + "Updated {count} shots: {scene}": { + "other": "{count}ショットを更新しました:{scene}" + }, + "Appended {count} shots: {scene}": { + "other": "{count}ショットを追加しました:{scene}" + }, + "Cannot capture shot: camera not ready": "ショットを取得できません:カメラの準備ができていません", + "Captured: {scene} / {shot}": "取得しました:{scene} / {shot}", "Select a shot first": "まずショットを選択してください", - "Updated: {scene} / {shot}": "更新しました: {scene} / {shot}", - "Camera unavailable — exit cockpit first": "カメラを使用できません: 先にコックピットを終了してください", + "Updated: {scene} / {shot}": "更新しました:{scene} / {shot}", + "Could not leave scene: {scene}": "シーンを終了できませんでした:{scene}", + "Seeked: {scene} / {shot}": "シークしました:{scene} / {shot}", + "Seeking scene clock": "シーンクロックをシーク中", + "Camera unavailable — exit cockpit first": "カメラを使用できません:先にコックピットを終了してください", "No shots to run": "実行するショットがありません", + "Scene transition limit reached — load a shot to reset": "シーン切り替えの上限に達しました。リセットするにはショットを読み込んでください", + "Export failed: {error}": "エクスポートに失敗しました:{error}", "Project exported": "プロジェクトを書き出しました", + "Importing project": "プロジェクトをインポート中", + "Imported {file}": "{file}をインポートしました", + "Import failed: {error}": "インポートに失敗しました:{error}", + "Import failed (could not read JSON file)": "インポートに失敗しました(JSONファイルを読み取れませんでした)", + "Layers refused: {layers}": "拒否されたレイヤー:{layers}", "Could not exit {mode} — scene layers may be refused": "{mode}を終了できませんでした。シーンのレイヤーが拒否される可能性があります", - "Running {index}/{total}: {scene} / {shot}": "実行中 {index}/{total}: {scene} / {shot}", + "Camera move interrupted": "カメラの移動が中断されました", + "Scene media timed out": "シーンのメディアがタイムアウトしました", + "Action complete": "操作が完了しました", + "Action unavailable or cancelled": "操作を利用できないか、キャンセルされました", + "Scene actions": "シーンの操作", + "Select a feature or use Tab and Enter to choose an action.": "フィーチャーを選択するか、TabとEnterで操作を選んでください。", + "Selected feature: {feature}. Choose an action.": "選択したフィーチャー:{feature}。操作を選んでください。", + "Running {index}/{total}: {scene} / {shot}": "実行中 {index}/{total}:{scene} / {shot}", "Scene run complete": "シーンの実行が完了しました", + "Bhote Koshi Evidence Sequence": "Bhote Koshi証拠シーケンス", + "Nepal Flood Incident": "ネパール洪水インシデント", "Global Flights Radar": "グローバル航空レーダー", "Orbital Watch": "軌道ウォッチ", "Thermal Threat Board": "熱源脅威ボード", "City Overload": "シティオーバーロード", "Omniscience Pullback": "オムニサイエンス・プルバック", + "Global Incident Context": "グローバルなインシデント状況", + "Nepal-Focused Globe Rotation": "ネパールを中心とした地球の回転", + "Bhote Koshi Regional Approach": "Bhote Koshi地域への接近", + "Bhote Koshi Nearby Cities": "Bhote Koshi周辺の都市", + "Bhote Koshi Incident Corridor": "Bhote Koshiインシデント流路", + "Bhote Koshi Flood Path": "Bhote Koshi洪水の経路", + "Bhote Koshi Corridor Overview": "Bhote Koshi流路の概観", + "Bhote Koshi Upper Valley": "Bhote Koshi上流渓谷", + "Upper Valley Collapse": "上流渓谷の崩壊", + "Debris-Dammed Lake": "土砂ダム湖", + "Nepal-China Border Gate": "ネパール・中国国境ゲート", + "Timure Evidence Cluster": "Timureの証拠群", + "Syabru Besi Passage": "Syabru Besiの通過", + "Bidur / Trishuli Consequence": "Bidur / Trishuliへの影響", + "Final view": "最終ビュー", + "Scene {n}": "シーン {n}", "Shot {n}": "ショット {n}", + "the title of scene {scene} is empty or longer than {max} characters": "シーン{scene}のタイトルが空か、{max}文字を超えています", + "the title of shot {shot} in scene {scene} is empty or longer than {max} characters": "シーン{scene}のショット{shot}のタイトルが空か、{max}文字を超えています", + "the project is larger than 5 MiB": "プロジェクトが5 MiBを超えています", + "the project has too many shots": "プロジェクトのショットが多すぎます", + "the scene data failed validation": "シーンデータの検証に失敗しました", + "Could not complete this action. Check the file, references and selected assets.": "この操作を完了できませんでした。ファイル、参照、選択したアセットを確認してください。", + "{count} scenes": { + "other": "{count}シーン" + }, + "{count} shots": { + "other": "{count}ショット" + }, + "{count} data packs": { + "other": "データパック{count}個" + }, + "{scene} / {pack}: {status}. File: {path}. {attribution} · {license}": "{scene} / {pack}:{status}。ファイル:{path}。{attribution} · {license}", + "Unavailable layers: {layers}": "利用できないレイヤー:{layers}", + "Uses registered content or linked media. Those external files are not included in a scene bundle. Their original notices still apply.": "登録済みのコンテンツまたはリンクされたメディアを使用しています。これらの外部ファイルはシーンバンドルに含まれません。元の表示事項は引き続き適用されます。", + "{bytes} bundled bytes verified. Files stay in memory for this session. Reimport the bundle after reloading the app.": "バンドルされた{bytes}バイトを検証しました。ファイルはこのセッションの間だけメモリーに保持されます。アプリを再読み込みした後は、バンドルを再インポートしてください。", + "Review scene import": "シーンのインポートを確認", + "Nothing is loaded or changed until you apply this file.": "このファイルを適用するまで、何も読み込まれず、変更もされません。", + "Ready to import": "インポートの準備ができました", + "Apply replaces the current project. Export your current project first if you want to keep both.": "適用すると現在のプロジェクトが置き換わります。両方を残したい場合は、先に現在のプロジェクトをエクスポートしてください。", + "Apply import": "インポートを適用", + "Import was not applied. The current project may have changed.": "インポートは適用されませんでした。現在のプロジェクトが変更された可能性があります。", + "Select a scene and shot first": "先にシーンとショットを選択してください", + "Edit scene details": "シーンの詳細を編集", + "Camera positions use degrees and meters above the ellipsoid. Drafts are validated before they replace your saved scene.": "カメラ位置は度と楕円体からの高さ(メートル)で指定します。下書きは検証されてから保存済みのシーンを置き換えます。", + "Anchors and data packs": "アンカーとデータパック", + "Shot camera, timing, packs and actions": "ショットのカメラ、タイミング、パック、操作", + "New anchor ID": "新しいアンカーID", + "Capture camera as anchor": "カメラ位置をアンカーとして取得", + "Anchor added to draft": "アンカーを下書きに追加しました", + "Set move start to current camera": "移動の開始点を現在のカメラに設定", + "Move added to draft; destination remains the shot camera": "移動を下書きに追加しました。移動先はショットのカメラのままです", + "Use ordinary flight": "通常の飛行を使用", + "Invalid shot JSON": "ショットのJSONが無効です", + "Apply details": "詳細を適用", + "Select a scene first": "先にシーンを選択してください", + "Share selected scene": "選択したシーンを共有", + "Scene JSON preserves authored settings and attribution. It does not include asset files. Bundles include only pack files you choose here or previously imported bundle files.": "シーンJSONには作成時の設定と出典情報が保持されます。アセットファイルは含まれません。バンドルには、ここで選択したパックファイルか、以前にインポートしたバンドルファイルのみが含まれます。", + "Download scene JSON": "シーンJSONをダウンロード", + "Choose data-pack files": "データパックのファイルを選択", + "Or choose a data-pack folder": "またはデータパックのフォルダーを選択", + "Download asset bundle": "アセットバンドルをダウンロード", + "Asset bundle downloaded": "アセットバンドルをダウンロードしました", + "No RTL-SDR device selected": "RTL-SDRデバイスが選択されていません", + "WebUSB requires desktop Chrome or Edge on localhost/HTTPS": "WebUSBには、localhostまたはHTTPS上のデスクトップ版ChromeかEdgeが必要です", + "RTL-SDR access failed; close other SDR apps and check USB permissions": "RTL-SDRにアクセスできませんでした。ほかのSDRアプリを閉じて、USBの許可を確認してください", + "RTL-SDR connection failed": "RTL-SDRの接続に失敗しました", + "Receiving 1090 MHz ADS-B": "1090 MHz ADS-Bを受信中", + "Receiving broadcast FM": "FM放送を受信中", + "Connect an RTL-SDR to begin.": "開始するにはRTL-SDRを接続してください。", + "WebUSB is unavailable in this browser": "このブラウザーではWebUSBを利用できません", + "USB work abandoned after a stalled transfer": "転送が停止したためUSB処理を中止しました", + "SDR decoder worker failed": "SDRデコーダーのワーカーが失敗しました", + "SDR decoder did not start; receiver stopped": "SDRデコーダーが起動しませんでした。受信機を停止しました", + "SDR decoder stopped responding; receiver stopped": "SDRデコーダーが応答しなくなりました。受信機を停止しました", + "SDR decoder fell behind; receiver stopped": "SDRデコーダーの処理が追いつきません。受信機を停止しました", + "WebUSB requires desktop Chrome or Edge": "WebUSBにはデスクトップ版ChromeまたはEdgeが必要です", + "Waiting for an RTL-SDR device…": "RTL-SDRデバイスを待機中…", + "Browser audio is suspended; press Connect again to resume it": "ブラウザーの音声が一時停止しています。再開するにはもう一度[接続]を押してください", + "RTL-SDR sample stream stopped": "RTL-SDRのサンプルストリームが停止しました", + "Switching to {mode}…": "{mode}に切り替え中…", + "Browser audio is suspended; select FM again to resume it": "ブラウザーの音声が一時停止しています。再開するにはもう一度FMを選択してください", + "RTL-SDR gain change failed": "RTL-SDRのゲイン変更に失敗しました", + "Tuned to {mhz} MHz FM": "FM {mhz} MHzに同調しました", + "Seeking up…": "上方向にシーク中…", + "Seeking down…": "下方向にシーク中…", + "Seek stopped": "シークを停止しました", + "Scanning {mhz} MHz…": "{mhz} MHzをスキャン中…", + "Found {mhz} MHz · {snr} dB": "{mhz} MHzを検出 · {snr} dB", + "FM signal found at {mhz} MHz": "{mhz} MHzでFM信号を検出しました", + "No FM signal found": "FM信号が見つかりません", + "Browser location is unavailable": "ブラウザーの位置情報を利用できません", + "Receiver location was not granted": "受信機の位置情報が許可されませんでした", + "RTL-SDR disconnected": "RTL-SDRが切断されました", + "Upstream response too large": "上流の応答が大きすぎます", + "Vector tile request timed out": "ベクタータイルのリクエストがタイムアウトしました", + "Vector tiles unavailable": "ベクタータイルを利用できません", + "Vector tile metadata unavailable": "ベクタータイルのメタデータを利用できません", + "Zoom in for vector tile coverage": "ズームインしてベクタータイルのカバー範囲を表示", + "Saturation": "彩度", + "Edge Thickness": "輪郭線の太さ", + "Contrast": "コントラスト", + "Grain": "粒子", + "Vignette": "周辺減光", + "Pixelation": "ピクセル化", + "Distortion": "歪み", + "Instability": "揺らぎ", "Density": "密度", + "Gain": "ゲイン", "Bloom": "ブルーム", + "Scanlines": "走査線", + "Sensitivity": "感度", + "WHOT/BHOT": "WHOT/BHOT", + "Ironbow": "Ironbow", + "unsaved CCTV calibration": "未保存のCCTVキャリブレーション", + "the open cockpit": "開いているコックピット", + "Switching language reloads the page. This will be lost: {items}. Switch anyway?": "言語を切り替えるとページが再読み込みされます。次の内容は失われます:{items}。切り替えますか?", "VISUAL PRESETS": "ビジュアルプリセット", "LOCATION": "位置", - "CONTACTS — nearest planes · vessels · sites": "コンタクト: 最寄りの航空機 · 船舶 · 施設", - "SPACE MISSIONS — launches & orbital assets": "宇宙ミッション: 打ち上げと軌道上の資産", + "CONTACTS — nearest planes · vessels · sites": "コンタクト:最寄りの航空機 · 船舶 · 施設", + "SPACE MISSIONS — launches & orbital assets": "宇宙ミッション:打ち上げと軌道上の資産", "LIVE SIGNALS": "ライブシグナル", "Contacts could not complete the requested transition; try again": "コンタクトが要求された切り替えを完了できませんでした。もう一度お試しください", "CCTV layer unavailable": "CCTVレイヤーを利用できません", + "Link shared": "リンクを共有しました", "Link copied!": "リンクをコピーしました", "Copy failed": "コピーに失敗しました", + "Return map to straight-down view": "地図を真上からの表示に戻す", + "Tilt map to oblique view": "地図を斜めの視点に傾ける", + "Reset map to north up. Current heading {heading} degrees": "地図を北が上になるようにリセット。現在の方位 {heading}度", + "Tilted view": "斜め表示", + "Straight-down view": "真上表示", + "North up": "北を上に", "CCTV calibration saved": "CCTVキャリブレーションを保存しました", + "HDG": "HDG", + "PITCH": "ピッチ", + "FOV": "FOV", + "RANGE": "距離", + "HGT": "高さ", + "ΔN": "ΔN", + "ΔE": "ΔE", + "{value}m": "{value}m", "CCTV calibration reset": "CCTVキャリブレーションをリセットしました", "ADJUST ON": "調整 オン", "ADJUST": "調整", + "SNAPSHOT": "スナップショット", + "LIVE": "ライブ", + "UPSTREAM": "上流", + "SYNTHETIC": "合成", + "CONFIGURED": "設定済み", + "SEED": "初期データ", "UNKNOWN": "不明", + "OK": "正常", "ERROR": "エラー", + "Live HLS connected": "ライブHLS接続済み", + "Live HLS unavailable": "ライブHLSを利用できません", + "No stream URL configured": "ストリームURLが設定されていません", + "Live stream connected": "ライブストリーム接続済み", + "Snapshot feed connected": "スナップショットフィード接続済み", + "Media fetch failed": "メディアの取得に失敗しました", + "Upstream snapshot active": "上流のスナップショットを使用中", + "Fallback Street View frame": "代替のストリートビュー画像", + "Upstream unavailable": "上流を利用できません", + "No source configured": "ソースが設定されていません", + "Configured source": "設定済みのソース", + "Configured Source": "設定済みのソース", + "Synthetic fallback": "合成による代替", + "Upstream HTTP {status}": "上流 HTTP {status}", + "Unexpected media type {type}": "予期しないメディアタイプ {type}", "SOURCE · UNKNOWN": "ソース · 不明", "FRAME · LOADING": "フレーム · 読込中", "FRAME · UNAVAILABLE": "フレーム · 利用不可", "CALIBRATED": "校正済み", - "CURATED": "調整済み", - "RAW PRIOR": "未処理の初期値", + "CURATED": "精査済み", + "RAW PRIOR": "初期推定値", "CCTV ON": "CCTV オン", "CCTV OFF": "CCTV オフ", "VIEWSHED ON": "可視域 オン", @@ -353,7 +1567,7 @@ "AUTO HOP OFF": "自動切替 オフ", "PROJECTION ON": "投影 オン", "PROJECTION OFF": "投影 オフ", - "CAL · EDITED (UNSAVED)": "CAL · 編集済み (未保存)", + "CAL · EDITED (UNSAVED)": "CAL · 編集済み(未保存)", "CAL · {badge}": "CAL · {badge}", "MONITOR": "モニター", "OFF": "オフ", @@ -385,20 +1599,23 @@ "CYCLE ON": "自動切替 オン", "CYCLE OFF": "自動切替 オフ", "Stop automatic page cycling. Previous, Next, and the SIG/NEWS/LOCAL tabs stay available.": "ページの自動切り替えを停止します。前へ、次へ、SIG/NEWS/LOCALタブは引き続き使えます。", - "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.": "9秒ごとにブリーフィングページを自動で切り替えます (シグナル → ニュース → ローカル)。パネルにカーソルを合わせるかフォーカスしている間は一時停止します。ライブシグナルのデータは、どちらの場合も継続的に更新されます。", + "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.": "9秒ごとにブリーフィングページを自動で切り替えます(シグナル → ニュース → ローカル)。パネルにカーソルを合わせるかフォーカスしている間は一時停止します。ライブシグナルのデータは、どちらの場合も継続的に更新されます。", "ACQUIRING REGIONAL NEWS": "地域ニュースを取得中", "REGIONAL NEWS UNAVAILABLE": "地域ニュースを取得できません", "RESOLVING REGION": "地域を特定中", "REGION UNAVAILABLE": "地域を取得できません", "NO RECENT LOCATION MATCHES": "最近の位置一致なし", "{domain} · {age}": "{domain} · {age}", + "{value} KM/H": "{value} KM/H", "CLOUD {pct}%": "雲量 {pct}%", "CLOUD UNKNOWN": "雲量不明", "{source} · LOCATION QUERY": "{source} · 位置クエリ", "REGIONAL NEWS": "地域ニュース", + "{label} · {radius} AIR/SEA WINDOW": "{label} · {radius}空/海ウィンドウ", + "{scope} · INSTALLATIONS {coverage}": "{scope} · 施設 {coverage}", "CONTEXT STANDBY": "コンテキスト待機", "ENABLE GLOBAL CONTEXT FOR PROXIMITY PINGS": "グローバルコンテキストを有効にすると近接ピングを表示", - "CONTACT LOST · LAST KNOWN READOUT · NOT AN ALL-CLEAR": "コンタクト喪失 · 最終既知の値 · 安全を保証するものではありません", + "CONTACT LOST · LAST KNOWN READOUT · NOT AN ALL-CLEAR": "コンタクト喪失 · 最終既知の値 · 安全の保証ではありません", "CONTACT LOST · {subject}": "コンタクト喪失 · {subject}", "SUBJECT LEFT ITS FEED · READOUT HOLDING LAST KNOWN": "対象がフィードから外れました · 最終既知の値を保持", "{cohort} · {contact}": "{cohort} · {contact}", @@ -409,15 +1626,19 @@ "L": "左", "R": "右", "{count} INPUTS UNKNOWN · NOT AN ALL-CLEAR": { - "other": "入力不明 {count}件 · 安全を保証するものではありません" + "other": "不明な入力 {count}件 · 安全の保証ではありません" }, - "AVAILABLE INPUTS CURRENT · NOT AN ALL-CLEAR": "利用可能な入力は最新 · 安全を保証するものではありません", + "AVAILABLE INPUTS CURRENT · NOT AN ALL-CLEAR": "利用可能な入力は最新 · 安全の保証ではありません", + "SQUAWK {code} · {status}": "スコーク {code} · {status}", + "ADS-B PRIORITY · {status}": "ADS-B優先 · {status}", + "ADS-B EMERGENCY · {status}": "ADS-B緊急 · {status}", "AIRCRAFT": "航空機", "ACQUIRING SURFACE": "地表を取得中", "SURFACE FALLBACK": "地表フォールバック", - "STALE FEED": "古いフィード", + "STALE FEED": "フィード更新遅延", "LIVE TRACK": "ライブ追跡", "COMMERCIAL": "民間", + "{aircraftClass} · {emergency} · {feedState}": "{aircraftClass} · {emergency} · {feedState}", "{aircraftClass} · {feedState} · COURSE ALIGNED": "{aircraftClass} · {feedState} · 針路一致", "ARROW · ESTIMATED DIRECTION": "矢印 · 推定方向", "ROUTE DATA UNAVAILABLE": "経路データなし", @@ -431,8 +1652,8 @@ "Anime": "アニメ", "Noir": "ノワール", "Snow": "雪", - "Current cockpit vision style: {style}. Activate for next style.": "現在のコックピットビジョンスタイル: {style}。有効にすると次のスタイルへ。", - "Current style: {style} — click for next": "現在のスタイル: {style} — クリックで次へ", + "Current cockpit vision style: {style}. Activate for next style.": "現在のコックピットビジョンスタイル:{style}。有効にすると次のスタイルへ。", + "Current style: {style} — click for next": "現在のスタイル:{style} — クリックで次へ", "Collapse Contact panel": "コンタクトパネルを折りたたむ", "Expand Contact panel": "コンタクトパネルを展開", "Collapse contact panel": "コンタクトパネルを折りたたむ", @@ -444,6 +1665,7 @@ "OBSERVED / MAPPED PINGS": "観測 / マップ済みピング", "SOURCE-BACKED EVENTS · NO SYNTHETIC NEWS": "出典付きイベントのみ · 合成ニュースなし", "LATEST LOCATION-MATCHED REPORTING": "位置に一致する最新の報道", + "{source} · LOCATION QUERY · RECENT": "{source} · 位置クエリ · 最近", "LOCAL INFO": "ローカル情報", "PLACE / CONDITIONS / POSITION": "場所 / 状況 / 位置", "TIME UNKNOWN": "時刻不明", @@ -451,14 +1673,14 @@ "{count}H AGO": "{count}時間前", "{count}D AGO": "{count}日前", "DIR UNKNOWN": "風向不明", - "Select flight {title}": "フライト {title} を選択", + "Select flight {title}": "フライト{title}を選択", "{aircraftClass} · CURRENT": "{aircraftClass} · 現在", "MILITARY FLIGHT": "軍用機", "COMMERCIAL FLIGHT": "民間機", "{aircraftClass} · {distance}": "{aircraftClass} · {distance}", "DISTANCE UNKNOWN": "距離不明", "{count} INPUTS UNKNOWN": { - "other": "入力不明 {count}件" + "other": "不明な入力 {count}件" }, "SOURCE STATUS UNAVAILABLE": "ソース状態を取得できません", "Restore real aircraft": "実際の航空機に戻す", @@ -485,24 +1707,83 @@ "{mode} could not start because another layer did not stop cleanly": "別のレイヤーが正常に停止しなかったため、{mode}を開始できませんでした", "Space Missions": "宇宙ミッション", "Context": "コンテキスト", + "Rendered globe frames per second · toggle with `": "地球儀の描画フレームレート(毎秒)· `キーで切り替え", + "imported map files": "インポートした地図ファイル", + "Ground heights could not be refreshed. Try the file again when the map has loaded.": "地表高を更新できませんでした。地図の読み込み後に、もう一度このファイルをお試しください。", + "{count} map objects": { + "other": "地図オブジェクト{count}個" + }, + ", drawn with its own styles": "、独自のスタイルで描画", + "Hide {name}": "{name}を非表示", + "Show {name}": "{name}を表示", + "Fly to {name}": "{name}へ移動", + "Remove {name}": "{name}を削除", + "At most {count} files at once — remove one first.": "一度に読み込めるのは最大{count}ファイルです。先に1つ削除してください。", + "Reading {name}…": "{name}を読み取り中…", + "That file could not be read.": "ファイルを読み取れませんでした。", + "Added {count} files.": { + "other": "{count}個のファイルを追加しました。" + }, + "{count} files could not be added ({name}: {error})": { + "other": "{count}個のファイルを追加できませんでした({name}:{error})" + }, + "Some KML content was left out.": "KMLの一部の内容は読み込まれませんでした。", + "Press on the ground, not the sky": "空ではなく地表を押してください", + "Drag to size the box": "ドラッグして範囲の大きさを決めてください", + "light {source} to use your {name} key": "{source}をオンにして{name}キーを使用", + "light {source}": "{source}をオンにする", + ", or ": "、または", + "{requirement}, or {offer}": "{requirement}。または、{offer}", "Live Flights": "ライブフライト", "Military Flights": "軍用機", - "Earthquakes (24h)": "地震 (24時間)", + "Earthquakes (24h)": "地震(24時間)", "Satellites": "衛星", - "Space Missions (30d)": "宇宙ミッション (30日)", + "Space Missions (30d)": "宇宙ミッション(30日)", "Street Traffic": "道路交通", "CCTV": "CCTV", "Radio": "ラジオ", - "Bikeshare": "バイクシェア", + "Bikeshare": "シェアサイクル", "Live AIS Vessels": "ライブAIS船舶", "Mapped Installations": "マップ済み施設", "Global Context": "グローバルコンテキスト", "Datacenters": "データセンター", "Dams": "ダム", "Submarine Cables": "海底ケーブル", - "FIRMS Active Fires": "FIRMS 火災検知", + "FIRMS Active Fires": "FIRMS火災検知", + "Local ADS-B": "ローカルADS-B", + "Transit": "公共交通", + "Recent Imagery": "最近の衛星画像", + "Fire Perimeters": "火災の延焼範囲", + "GNSS Integrity": "GNSSインテグリティ", + "S2 GhostMaps": "S2 GhostMaps", + "Rain radar": "降水レーダー", + "Lightning density": "雷密度", + "Cyclone advisories": "サイクロン情報", + "ALPR Cameras": "ALPRカメラ", + "Live Vessels": "ライブ船舶", + "Bike Share": "シェアサイクル", + "Cameras": "カメラ", + "Street Level": "ストリートレベル", + "Mapped ALPR Cameras": "マップ済みALPRカメラ", + "Data Centers": "データセンター", + "Active Fires": "火災検知", + "Military aircraft": "軍用機", + "Vessels": "船舶", + "CCTV + Street View fallback": "CCTV + ストリートビューで代替", + "OpenStreetMap + optional Google Maps Places": "OpenStreetMap + Google Maps Places(任意)", + "GFS / ECMWF IFS · FORECAST": "GFS / ECMWF IFS · 予報", + "NOAA nowCOAST · OBSERVED": "NOAA nowCOAST · 観測", + "NASA FIRMS · LIVE": "NASA FIRMS · ライブ", + "OSM routing": "OSMルート検索", + "data source|Local": "ローカル", "ENABLING": "有効化中", "DISABLING": "無効化中", + "Movement": "移動体", + "Infrastructure": "インフラ", + "Events": "イベント", + "Weather": "気象", + "Utilities": "ユーティリティ", + "Other layers": "その他のレイヤー", "{state} · {source}": "{state} · {source}", "UNCERTAIN · {source} · lifecycle state requires reconciliation": "不明確 · {source} · ライフサイクル状態の調整が必要です", "{state} · {source} · {detail} · retry {seconds}s": "{state} · {source} · {detail} · {seconds}秒後に再試行", @@ -516,21 +1797,69 @@ "{state} · {source} · {ago}": "{state} · {source} · {ago}", "{source} · {ago}": "{source} · {ago}", "UNCERTAIN": "不明確", + "status chip|UNAVAILABLE": "利用不可", + "Data source unavailable": "データソースを利用できません", "{name}: {state}": "{name}: {state}", "{count}s ago": "{count}秒前", + "Local FM stopped: internet radio started": "ローカルFMを停止しました:インターネットラジオを開始しました", + "IDLE": "待機", "CONNECTING": "接続中", - "📍 Location: --": "📍 位置: --", - "Landmark: --": "ランドマーク: --", + "TUNING": "同調中", + "STREAMING": "受信中", + "UNSUPPORTED": "非対応", + "idle": "待機中", + "running": "実行中", + "suspended": "一時停止中", + "closed": "終了", + "feed status|live": "ライブ", + "feed status|stale": "更新遅延", + "feed status|unreachable": "接続不可", + "feed status|invalid": "無効", + "waiting for IQ": "IQデータ待機中", + "{count} messages": { + "other": "メッセージ {count}件" + }, + "DSP {count} blocks": { + "other": "DSP {count}ブロック" + }, + "DSP waiting": "DSP待機中", + "{level} dBFS audio": "音声 {level} dBFS", + "audio signal --": "音声信号 --", + "audio {state}": "音声 {state}", + "{count} HEARD": { + "other": "受信 {count}機" + }, + "DISCONNECT": "切断", + "CONNECT": "接続", + "LOCATING…": "測位中…", + "LOCATED": "測位済み", + "LOCATE": "測位", + " · read while Local ADS-B is on": " · ローカルADS-Bがオンの間に読み取り", + "Decoder feeds: {feeds}": "デコーダーフィード:{feeds}", + "Language: {language}": "言語:{language}", + "Change the interface language": "インターフェースの言語を変更", + "Interface language": "インターフェースの言語", + "Search languages": "言語を検索", + "No matching languages": "一致する言語がありません", + "📍 Location: --": "📍 位置:--", + "Landmark: --": "ランドマーク:--", "Searched location": "検索した場所", "ORBIT": "周回", "Location not found": "場所が見つかりません", + "Check the spelling and press Enter to search again.": "つづりを確認し、Enterを押してもう一度検索してください。", "Search failed": "検索に失敗しました", + "Press Enter to try again.": "Enterを押してもう一度お試しください。", + "Detailed outline unavailable": "詳細な輪郭を取得できません", "Fly to a POI first": "先にPOIへ移動してください", "Reset to full globe view": "地球全体ビューに戻す", "Reset cockpit to full globe view": "コックピットを地球全体ビューに戻す", "Resetting to full globe view": "地球全体ビューに戻しています", "Resetting cockpit to full globe view": "コックピットを地球全体ビューに戻しています", "MAP": "マップ", + "Layers": "レイヤー", + "Search": "検索", + "More": "その他", + "Panels": "パネル", "panel": "パネル", "Expand {name}": "{name}を展開", "Collapse {name}": "{name}を折りたたむ", @@ -539,34 +1868,51 @@ "Expand Radio section": "ラジオセクションを展開", "Collapse Radio section": "ラジオセクションを折りたたむ", "Panel layout updated — positions reset to new defaults": "パネルレイアウトを更新しました。位置を新しい初期値にリセットしました", + "Austin": "オースティン", + "San Francisco": "サンフランシスコ", + "New York": "ニューヨーク", + "Tokyo": "東京", + "London": "ロンドン", + "Paris": "パリ", + "Dubai": "ドバイ", + "Washington DC": "ワシントンD.C.", + "Tallinn": "タリン", + "Los Angeles": "ロサンゼルス", "Collapse Cockpit display options": "コックピットのディスプレイ設定を折りたたむ", "Expand Cockpit display options": "コックピットのディスプレイ設定を展開", "Collapse Cockpit Radio controls": "コックピットのラジオ操作を折りたたむ", "Expand Cockpit Radio controls": "コックピットのラジオ操作を展開", + "CH {index} / {total}": "CH {index} / {total}", "NO STATIONS": "局なし", "NO STATION AVAILABLE": "利用できる局がありません", "{name}, station {index} of {total}": "{name}、{total}局中{index}局目", "No station available": "利用できる局がありません", "OFF AIR": "放送休止", "STATION UNAVAILABLE": "局を利用できません", + "Station unavailable after directory refresh": "ディレクトリ更新後に局を利用できません", "Radio could not {action} cleanly": "ラジオを正常に{action}できませんでした", + "Go to expanded Radio section": "展開したラジオセクションへ移動", + "Expand Radio section in Context": "コンテキストでラジオセクションを展開", "Close compact Radio controls": "コンパクトラジオ操作を閉じる", "Open compact Radio controls": "コンパクトラジオ操作を開く", "SYNC": "同期", "RECONCILE": "再調整", "DISABLE": "無効化", "ENABLE": "有効化", - "Reconcile Radio — lifecycle uncertain": "ラジオを再調整: ライフサイクルが不明確", + "Reconcile Radio — lifecycle uncertain": "ラジオを再調整:ライフサイクルが不明確", "Disable Radio": "ラジオを無効にする", "Enable Radio": "ラジオを有効にする", + "{category} ({count})": "{category}({count})", "DIRECTORY BAND": "ディレクトリバンド", "{category} BAND": "{category}バンド", "NO STATION SELECTED": "局が未選択", "Directory metadata only": "ディレクトリのメタデータのみ", "Loading station directory…": "局ディレクトリを読み込み中…", - "Choose a globe marker or use next.": "地球儀のマーカーを選ぶか、次へを使用してください。", + "Choose a globe marker or use next.": "地球儀のマーカーを選ぶか、[次へ]を使ってください。", "TAGS · {tags}": "タグ · {tags}", "Play": "再生", + "PAUSE": "一時停止", + "RESUME": "再開", "PLAY": "再生", "selected": "選択中の", "nearest": "最寄りの", @@ -577,11 +1923,11 @@ "SYNCING": "同期中", "READY": "準備完了", "station": "局", - " · stale/degraded directory": " · ディレクトリが古い/性能低下", + " · stale/degraded directory": " · ディレクトリ更新遅延/性能低下", " · degraded directory": " · ディレクトリ性能低下", - " · stale directory": " · ディレクトリが古い", + " · stale directory": " · ディレクトリ更新遅延", " · outside current filter": " · 現在の絞り込み対象外", - "Ready — playback starts only from your action": "準備完了: 再生は操作したときのみ開始されます", + "Ready — playback starts only from your action": "準備完了:再生は操作したときのみ開始されます", "Radio off": "ラジオ オフ", "Connecting directly to broadcaster…": "放送局に直接接続中…", "Buffering broadcaster stream…": "放送局のストリームをバッファリング中…", @@ -596,17 +1942,150 @@ "Radio is enabling…": "ラジオを有効化しています…", "Radio is disabling…": "ラジオを無効化しています…", "Radio lifecycle is uncertain — use Enable or Disable to reconcile": "ラジオのライフサイクルが不明確です。有効化または無効化で再調整してください", + "Clear reading": "読み取り値を消去", + "Earlier observation": "前の観測", + "Observed history": "観測履歴", + "Later observation": "次の観測", + "Latest": "最新", + "Newest frame per product": "プロダクトごとの最新フレーム", + "Replay observed history": "観測履歴を再生", + "Imagery on Esri · Google 3D returns when cleared": "画像はEsri上に表示 · 消去するとGoogle 3Dに戻ります", + "Point the camera at the ground to use the view": "このビューを使うにはカメラを地面に向けてください", + "That point cannot anchor a box": "その地点は範囲の基点にできません", + "Imagery stops at ±{limit}° latitude": "画像は緯度±{limit}°までです", + "{owner} is using the pointer — close it first": "{owner}がポインターを使用中です。先に閉じてください", + "Box is {size} wide · limit {limit}": "範囲の幅 {size} · 上限 {limit}", + "View is {size} wide · limit {limit}": "表示の幅 {size} · 上限 {limit}", + "VS BASEMAP": "ベースマップと比較", + "A / B": "A / B", + "Newest low-cloud day for this box · scene cloud, not box cloud": "この範囲で雲の少ない最新の日 · シーン全体の雲量で、範囲内の雲量ではありません", + "Newest day covering this box · cloudier than 20%": "この範囲をカバーする最新の日 · 雲量20%超", + "Newest day with imagery for this box · partial coverage": "この範囲の画像がある最新の日 · 一部のみカバー", + "Newest daily overview for this box": "この範囲の最新の日次概観", + "newest clear day": "雲の少ない最新の日", + "newest day (cloudy)": "最新の日(曇り)", + "newest day (partial coverage)": "最新の日(一部カバー)", + "newest overview": "最新の概観", + "No imagery": "画像なし", + "Loading": "読み込み中", + "coverage|full": "全体", + "coverage|partial": "一部", + "unknown": "不明", + "no imagery": "画像なし", + "{percent}% cloud": "雲量 {percent}%", + "{min}–{max}% cloud": "雲量 {min}–{max}%", + "NO BOX": "範囲なし", + "SEARCHING": "検索中", + "{count} DAYS": { + "other": "{count}日分" + }, + "Zoom in or draw a smaller box": "ズームインするか、より小さい範囲を描いてください", + "Select a box or use the view": "範囲を選択するか、現在のビューを使用してください", + "Searching the last 30 days": "過去30日間を検索中", + "No days to show for this box": "この範囲で表示できる日がありません", + "Drag the divider · SWAP trades sides": "境界線をドラッグ · 入れ替えで左右を交換", + "← → preview · A or B pins the focused day": "← → でプレビュー · AまたはBで選択中の日を固定", + "← → preview the other side · A or B pins it": "← → で反対側をプレビュー · AまたはBで固定", + "S on another day replaces it · × unpins": "別の日でSを押すと置き換え · ×で固定を解除", + "← → preview · S shows the focused day": "← → でプレビュー · Sで選択中の日を表示", + "ZOOM IN": "ズームイン", + "Fly in until the view fits the 1,000 km limit": "表示が上限の1,000 kmに収まるまで近づいてください", + "Imagery days, newest first · arrows move, S or A and B pin": "画像のある日(新しい順)· 矢印キーで移動、SまたはA・Bで固定", + "On the map": "地図上", + "Mode": "モード", + "Imagery opacity": "画像の不透明度", + "SWAP": "入れ替え", + "Trade the two sides of the divider": "境界線の左右を入れ替える", + "SELECT BOX": "範囲を選択", + "Drag a box on the map (Esc cancels)": "地図上で範囲をドラッグ(Escでキャンセル)", + "USE VIEW": "ビューを使用", + "Use the current view as the box": "現在のビューを範囲として使用", + "Forget the box and its images": "範囲とその画像を破棄", + "START HERE": "ここから開始", + "Checking": "確認中", + "PREVIEW": "プレビュー", + "Newest day with imagery for this box": "この範囲の画像がある最新の日", + "SHOW": "表示", + "Pin {day} as {slot}": "{day}を{slot}に固定", + "Show {day}": "{day}を表示", + "pinned {slot}": "{slot}に固定済み", + "shown": "表示中", + "preview": "プレビュー", + "start here": "ここから開始", + "No box": "範囲なし", + "Searching": "検索中", + "Every day is empty here": "ここではどの日も画像がありません", + "Sources off": "ソースがオフ", + "VS": "比較", + "Not set": "未設定", + "Basemap": "ベースマップ", + "Source off": "ソースがオフ", + "Unpin {slot}": "{slot}の固定を解除", + "Unpin the image": "画像の固定を解除", + "EXPORT {slot}": "{slot}を書き出し", + "EXPORT": "書き出し", + "Download {slot} as a PNG": "{slot}をPNGでダウンロード", + "Download the image as a PNG": "画像をPNGでダウンロード", + "Box {width} × {height} km": "範囲 {width} × {height} km", + "Acquired {time}": "取得日時 {time}", + "Coverage {coverage}": "カバー率 {coverage}", + "START HERE · {reason}": "ここから開始 · {reason}", + "Daily overview shows little detail in a box this small": "この小さな範囲では、日次概観にほとんど詳細が写りません", + "Imagery: NASA GIBS and Worldview · HLS (Sentinel-2, Landsat 8/9) and VIIRS": "画像:NASA GIBSおよびWorldview · HLS(Sentinel-2、Landsat 8/9)とVIIRS", + "Details": "詳細", + "Times, coverage, sources": "時刻、カバー範囲、ソース", + "HIDE EMPTY DAYS": "画像のない日を隠す", + "SHOW EMPTY DAYS · {count}": "画像のない日を表示 · {count}", + "Days the probe found empty in this box": "この範囲で調査の結果、画像がなかった日", + "image": "画像", + "BASEMAP": "ベースマップ", + "The basemap": "ベースマップ", + "basemap": "ベースマップ", + "Recent imagery against the basemap divider": "最近の衛星画像とベースマップの境界線", + "Recent imagery A and B divider": "最近の衛星画像AとBの境界線", + "{before} {left} percent, {after} {right} percent": "{before} {left}%、{after} {right}%", + "Export failed · {error}": "書き出しに失敗しました · {error}", "Scene action failed": "シーン操作に失敗しました", - "Delete shot \"{shot}\"?": "ショット「{shot}」を削除しますか?", + "New scene name": "新しいシーン名", + "Delete scene \"{scene}\" and all shots?": "シーン「{scene}」とすべてのショットを削除しますか?", + "Delete shot \"{shot}\"?": "ショット「{shot}」を削除しますか?", + "Stopped (Esc)": "停止しました(Esc)", "SPARSE": "低密度", "BALANCED": "標準", + "No shots yet. Use CAPTURE SHOT to save current look.": "ショットはまだありません。[ショット取得]で現在の表示を保存してください。", + "Double-click to rename": "ダブルクリックで名前を変更", + "Shot name": "ショット名", + "LOAD": "読込", "DEL": "削除", + "{duration}s + {hold}s": "{duration}秒 + {hold}秒", + "Choose files": "ファイルを選択", + "{count} files selected": { + "other": "{count}個のファイルを選択済み" + }, + "No file chosen": "ファイルが選択されていません", + "Cancel": "キャンセル", + "EDIT DETAILS": "詳細を編集", + "SHARE SCENE": "シーンを共有", + "Shared flight follow expired": "共有されたフライトの追従が期限切れになりました", + "Shared military flight follow expired": "共有された軍用機の追従が期限切れになりました", + "Shared satellite follow expired": "共有された衛星の追従が期限切れになりました", + "Shared flight could not be restored — feed unavailable": "共有されたフライトを復元できませんでした:フィードを利用できません", + "Shared military flight could not be restored — feed unavailable": "共有された軍用機を復元できませんでした:フィードを利用できません", + "Shared satellite could not be restored — feed unavailable": "共有された衛星を復元できませんでした:フィードを利用できません", + "Shared flight is unavailable": "共有されたフライトは利用できません", + "Shared military flight is unavailable": "共有された軍用機は利用できません", + "Shared satellite is unavailable": "共有された衛星は利用できません", "entity": "エンティティ", "Shared {subject} follow expired": "共有された{subject}の追従が期限切れになりました", - "Shared {subject} could not be restored — feed unavailable": "共有された{subject}を復元できませんでした: フィードを利用できません", + "Shared {subject} could not be restored — feed unavailable": "共有された{subject}を復元できませんでした:フィードを利用できません", "Shared {subject} is unavailable": "共有された{subject}は利用できません", + "{id} isn't reporting now — showing where it was last seen": "{id}は現在報告していません。最後に確認された位置を表示しています", + "{id} isn't reporting now — showing where it was at {time}": "{id}は現在報告していません。{time}時点の位置を表示しています", + "This share link can't be opened": "この共有リンクは開けません", + "Shared vessel is unavailable": "共有された船舶は利用できません", "ACQUIRING": "取得中", "SHARED {subject}": "共有 {subject}", + "subject": "対象", "LOADING LIVE DATA": "ライブデータ読込中", "LOAD COMPLETE": "読込完了", "LOAD CANCELLED": "読込中止", @@ -615,44 +2094,468 @@ "MAPPED SITES LOADED": "マップ済み施設を読込済み", "RETRYING MAPPED SITES": "マップ済み施設を再試行中", "FETCHING MAPPED SITES": "マップ済み施設を取得中", + "RETRYING ALPR CAMERAS": "ALPRカメラを再試行中", + "FETCHING ALPR CAMERAS": "ALPRカメラを取得中", + "OVERPASS TEMPORARILY UNAVAILABLE": "OVERPASSが一時的に利用不可", + "OVERPASS RATE-LIMITED": "OVERPASSがレート制限中", + "OVERPASS TIMED OUT": "OVERPASSがタイムアウト", + "OVERPASS COULD NOT COMPLETE THE QUERY": "OVERPASSがクエリを完了できません", + "MAP TILES TEMPORARILY UNAVAILABLE": "地図タイルが一時的に利用不可", + "MAPPED NAMES TEMPORARILY UNAVAILABLE": "地名が一時的に利用不可", "TURNING OFF LIVE DATA": "ライブデータをオフにしています", "REFRESHING LIVE DATA": "ライブデータを更新中", "syncing road network": "道路網を同期中", "retry pending": "再試行待ち", "retrying in {seconds}s": "{seconds}秒後に再試行", - "Celestial ring — reveal the full globe": "天球リング: 地球全体を表示", - "Celestial ring — available in Normal style": "天球リング: 標準スタイルで利用可能", - "Detection overlay: {mode}": "検出オーバーレイ: {mode}", - "Detection overlay: off": "検出オーバーレイ: オフ", + "ALPR cameras": "ALPRカメラ", + "OpenSky OAuth client missing/invalid": "OpenSky OAuthクライアントがないか無効です", + "OpenSky OAuth rejected credentials": "OpenSky OAuthが認証情報を拒否しました", + "OpenSky username/password rejected": "OpenSkyのユーザー名/パスワードが拒否されました", + "OpenSky auth missing": "OpenSkyの認証情報がありません", + "OpenSky auth required": "OpenSkyの認証が必要です", + "OpenSky auth invalid": "OpenSkyの認証が無効です", + "OpenSky auth failed": "OpenSkyの認証に失敗しました", + "KartaView answered HTTP {status}": "KartaViewがHTTP {status}を返しました", + "Panoramax answered HTTP {status}": "PanoramaxがHTTP {status}を返しました", + "KartaView refused the request (code {code})": "KartaViewがリクエストを拒否しました(コード {code})", + "Vector tiles unavailable (HTTP {status})": "ベクタータイルを利用できません(HTTP {status})", + "GNSS feed unavailable (HTTP {status})": "GNSSフィードを利用できません(HTTP {status})", + "{count} CelesTrak groups unavailable": { + "other": "CelesTrakの{count}グループを利用できません" + }, + "{feed} feed unavailable": "{feed}フィードを利用できません", + "Source snapshot {minutes} min old": "ソースのスナップショットは{minutes}分前のものです", + "{source} rate limited (anonymous)": "{source}がレート制限中(匿名)", + "{source} rate limited": "{source}がレート制限中", + "{source} network error": "{source}のネットワークエラー", + "Malformed {source} aircraft rows": "{source}の航空機データ行の形式が不正です", + "Malformed {source} response": "{source}の応答形式が不正です", + "entry {n}": "項目 {n}", + "feeds {names} stale": { + "other": "フィード{names}が更新遅延" + }, + "feeds {names} unreachable": { + "other": "フィード{names}に接続できません" + }, + "feeds {names} invalid": { + "other": "フィード{names}が無効です" + }, + "Loading {feeds}": "{feeds}を読み込み中", + "{count} heard": { + "other": "受信 {count}機" + }, + "USB {rate} msg/s": "USB {rate} msg/s", + "{rate} msg/s": "{rate} msg/s", + "{count} feeds live": { + "other": "ライブフィード {count}件" + }, + "{feed} {count} ({seconds}s old)": "{feed} {count}({seconds}秒前)", + "Street Level toggle failed": "ストリートレベルの切り替えに失敗しました", + "Street Level could not start": "ストリートレベルを開始できませんでした", + "SHRINK": "縮小", + "EXPAND": "拡大", + "Shrink": "縮小", + "Expand": "拡大", + "ANY DATE": "全期間", + "LAST 10 YEARS": "過去10年", + "LAST 5 YEARS": "過去5年", + "LAST 3 YEARS": "過去3年", + "LAST 2 YEARS": "過去2年", + "LAST YEAR": "過去1年", + "LAST 6 MONTHS": "過去6か月", + "LAST 3 MONTHS": "過去3か月", + "LAST MONTH": "過去1か月", + "LAST {count} DAYS": { + "other": "過去{count}日" + }, + "{window} · SINCE {date}": "{window} · {date}以降", + "Turn Street Level off": "ストリートレベルをオフにする", + "Turn Street Level on": "ストリートレベルをオンにする", + "{name} imagery on": "{name}の画像 オン", + "{name} imagery off": "{name}の画像 オフ", + "Image by {creator}": "撮影者:{creator}", + " or ": "、", + "OPEN {labels}": "{labels}を開く", + "Open {names} at the centre of the view": "表示の中心で{names}を開く", + "Zoom in to a street to open {names} here": "ここで{names}を開くには通りまでズームイン", + "Switch Street Level on to draw its coverage.": "カバー範囲を描画するには、ストリートレベルをオンにしてください。", + "Every provider is switched off: light a chip to draw its coverage.": "すべてのプロバイダーがオフです。カバー範囲を描画するには、いずれかのチップをオンにしてください。", + "Loading this sequence…": "このシーケンスを読み込み中…", + "{n} images in this sequence · Esc clears": { + "other": "このシーケンスの画像 {n}枚 · Escで消去" + }, + "No sequences in view match the filter": "表示範囲内にフィルターに一致するシーケンスはありません", + "No coverage in view": "表示範囲内にカバー範囲がありません", + "{n} streets in view · click a line for its nearest photo": { + "other": "表示範囲内の通り {n}本 · 線をクリックすると最寄りの写真を表示" + }, + "{n} sequences in view · click a line for its nearest photo": { + "other": "表示範囲内のシーケンス {n}件 · 線をクリックすると最寄りの写真を表示" + }, + "{n} sequences in view · click a line for its photos": { + "other": "表示範囲内のシーケンス {n}件 · 線をクリックすると写真を表示" + }, + "km/h": "km/h", + "m/s": "m/s", + "mph": "mph", + "hPa": "hPa", + "kt": "kt", + "kts": "kt", + "ft": "ft", + "km": "km", + "m": "m", + "h": "時間", + "min": "分", + "s": "秒", + "dB": "dB", + "Celestial ring — reveal the full globe": "天球リング:地球全体を表示", + "Celestial ring — available in Normal style": "天球リング:標準スタイルで利用可能", + "Detection overlay: {mode}": "検出オーバーレイ:{mode}", + "Detection overlay: off": "検出オーバーレイ:オフ", "DETECT": "検出", + "{time} · {minutes} min ago": "{time} · {minutes}分前", + "Active weather": "有効な気象レイヤー", + "LATEST · newest per product": "最新 · プロダクトごとの最新", + "Forecast · valid {valid} · issued {issued}": "予報 · 対象時刻 {valid} · 発表 {issued}", + "{detail} · Does not follow history": "{detail} · 履歴とは連動しません", + "Forecast · valid {valid}": "予報 · 対象時刻 {valid}", + "voice|OFF": "オフ", + "voice|CONNECTING": "接続中", + "voice|LISTENING": "聞き取り中", + "voice|EXECUTING": "実行中", + "voice|ERROR": "エラー", + "Voice provider": "音声プロバイダー", + "Changing provider reconnects voice if it is on.": "音声がオンの場合、プロバイダーを変更すると音声が再接続されます。", + "Voice Settings": "音声設定", "AI AGENT": "AIエージェント", - "Voice model tier — applies next session": "音声モデルのティア: 次回セッションで適用", + "Voice model tier — applies next session": "音声モデルのティア:次回セッションで適用", + "STD": "標準", "Estimated session cost": "セッションの推定コスト", - "Voice control — activate to toggle voice; hold Space to speak": "音声コントロール: 有効にすると音声をオン/オフ、Space を押し続けて話す", + "Voice control — activate to toggle voice; hold Space to speak": "音声コントロール:有効にすると音声のオン/オフを切り替え、Spaceを長押しで話す", + "ON/OFF": "オン/オフ", "VOICE STANDBY": "音声待機中", "VOICE CONTROL": "音声コントロール", - "Hold Space to speak · tap Space to activate focused controls": "Space を押し続けて話す · Space をタップでフォーカス中のコントロールを実行", + "Hold Space to speak · tap Space to activate focused controls": "Spaceを長押しで話す · Spaceをタップでフォーカス中の操作を実行", + "VOICE": "音声", + "Preview": "プレビュー", + "Settings": "設定", + "Close voice panel": "音声パネルを閉じる", + "Voice replies appear here.": "音声の応答はここに表示されます。", + "Voice assistant": "音声アシスタント", + "Dismiss voice card": "音声カードを閉じる", + "YOU": "あなた", + "THIS": "指示対象", + "Plan": "計画", + "Referenced items": "参照された項目", + "NOTES & SOURCES": "注記と出典", + "Show Voice Preview": "音声プレビューを表示", + "Voice inactivity timeout": "音声の無操作タイムアウト", + "Minutes": "分", + "Custom": "カスタム", + "These preferences stay in this browser.": "これらの設定はこのブラウザーにのみ保存されます。", "VOICE SYSTEM ERROR": "音声システムエラー", "DISMISS": "閉じる", "Check microphone permission and network access, then try again.": "マイクの許可とネットワーク接続を確認して、もう一度お試しください。", - "Release Space to send": "Space を離して送信", - "Hold Space to talk": "Space を押し続けて話す", + "Gemini returned an oversized audio chunk": "Geminiから大きすぎる音声チャンクが返されました", + "Gemini returned an unsupported audio format": "Geminiから対応していない音声形式が返されました", + "Gemini returned an invalid audio sample rate": "Geminiから無効な音声サンプルレートが返されました", + "Gemini returned incomplete PCM audio": "Geminiから不完全なPCM音声が返されました", + "This browser does not support Gemini microphone audio": "このブラウザーはGeminiのマイク音声に対応していません", + "Microphone audio processing failed": "マイク音声の処理に失敗しました", + "Gemini audio playback fell behind. Reconnect to continue.": "Geminiの音声再生が遅れています。続けるには再接続してください。", + "Gemini token response did not include an ephemeral credential": "Geminiのトークン応答に一時的な認証情報が含まれていません", + "Invalid Gemini connection endpoint": "Geminiの接続エンドポイントが無効です", + "Gemini voice could not connect. Try again.": "Gemini音声に接続できませんでした。もう一度お試しください。", + "Gemini voice requires a same-origin app request": "Gemini音声には同一オリジンのアプリからのリクエストが必要です", + "Add a Gemini API key in Provider Settings": "プロバイダー設定でGemini APIキーを追加してください", + "The Gemini Live model configuration is invalid": "Gemini Liveのモデル設定が無効です", + "Gemini voice is starting too often. Try again shortly.": "Gemini音声の起動が頻繁すぎます。しばらくしてからもう一度お試しください。", + "Gemini quota is unavailable. Try again later.": "Geminiの割り当てを利用できません。後でもう一度お試しください。", + "Gemini access was refused. Check the API key and model access.": "Geminiへのアクセスが拒否されました。APIキーとモデルへのアクセス権を確認してください。", + "Gemini Live is unavailable for the configured model.": "設定されたモデルではGemini Liveを利用できません。", + "Token request is too large": "トークンリクエストが大きすぎます", + "Use an empty JSON token request": "空のJSONトークンリクエストを使用してください", + "Release Space to send": "Spaceを離して送信", + "Hold Space to talk": "Spaceを長押しで話す", + "Voice command context is too large": "音声コマンドのコンテキストが大きすぎます", + "Gemini reliable transport exceeded its queue limit. Start voice again.": "Geminiの高信頼トランスポートがキューの上限を超えました。音声をもう一度開始してください。", + "Gemini reliable transport did not drain. Start voice again.": "Geminiの高信頼トランスポートのキューが空になりませんでした。音声をもう一度開始してください。", + "Gemini token request failed (HTTP {status})": "Geminiのトークンリクエストに失敗しました(HTTP {status})", + "Gemini token response did not include a valid model": "Geminiのトークン応答に有効なモデルが含まれていません", + "Gemini token response did not include session settings": "Geminiのトークン応答にセッション設定が含まれていません", + "Gemini session settings do not match the input mode": "Geminiのセッション設定が入力モードと一致しません", "Requesting microphone": "マイクを要求中", + "Gemini could not submit this input. Start voice again.": "Geminiがこの入力を送信できませんでした。音声をもう一度開始してください。", + "Connecting to Gemini": "Geminiに接続中", "Ask or command": "質問またはコマンドをどうぞ", + "Gemini returned an oversized message": "Geminiから大きすぎるメッセージが返されました", + "Gemini Live connection failed. Check network access, then start voice again.": "Gemini Liveの接続に失敗しました。ネットワーク接続を確認してから、音声をもう一度開始してください。", + "Gemini Live connection ended. Start voice again for a new conversation.": "Gemini Liveの接続が終了しました。新しい会話を始めるには、音声をもう一度開始してください。", + "Gemini Live could not start. Start voice again to request a fresh session.": "Gemini Liveを開始できませんでした。新しいセッションを要求するには、音声をもう一度開始してください。", + "Start voice again for a fresh token and a new conversation.": "新しいトークンで新しい会話を始めるには、音声をもう一度開始してください。", + "Start voice again to request a fresh session credential.": "新しいセッションの認証情報を要求するには、音声をもう一度開始してください。", + "Microphone permission was denied. Allow microphone access and try again.": "マイクの使用が拒否されました。マイクへのアクセスを許可して、もう一度お試しください。", + "Gemini connection timed out. Try again.": "Geminiへの接続がタイムアウトしました。もう一度お試しください。", + "Gemini voice could not start": "Gemini音声を開始できませんでした", + "Gemini did not finish the interrupted reply. Start voice again.": "Geminiが中断された応答を完了しませんでした。音声をもう一度開始してください。", + "Gemini session expiring; finishing the current reply": "Geminiのセッションがまもなく期限切れです。現在の応答を完了しています", + "Gemini rejected the voice session. Start voice again to request a fresh session.": "Geminiが音声セッションを拒否しました。新しいセッションを要求するには、音声をもう一度開始してください。", + "Start voice again for a fresh session credential. If it repeats, check Gemini model and API access.": "新しいセッションの認証情報を取得するには、音声をもう一度開始してください。繰り返し発生する場合は、GeminiのモデルとAPIへのアクセスを確認してください。", + "Gemini action history is full. Start voice again for a fresh session.": "Geminiの操作履歴がいっぱいです。新しいセッションを始めるには、音声をもう一度開始してください。", + "Gemini requested too many simultaneous actions": "Geminiが同時に要求した操作が多すぎます", "Running command": "コマンド実行中", - "Voice off": "音声オフ", - "WebRTC microphone support unavailable": "WebRTC マイクに対応していません", + "Voice text command is too long": "音声のテキストコマンドが長すぎます", + "Gemini voice is not connected": "Gemini音声が接続されていません", + "Gemini interrupted input exceeded its buffer or wait limit. Start voice again.": "Geminiの中断された入力がバッファーまたは待機の上限を超えました。音声をもう一度開始してください。", + "Gemini Live connection is expiring. Start voice again for a new conversation.": "Gemini Liveの接続がまもなく期限切れです。新しい会話を始めるには、音声をもう一度開始してください。", + "Voice off": "音声 オフ", + "Gemini voice sessions have a time limit. When a session expires, start voice again for a new conversation.": "Gemini音声のセッションには時間制限があります。セッションが期限切れになったら、音声をもう一度開始して新しい会話を始めてください。", + "Stopped by voice": "音声で停止しました", + "Automatic stop is unavailable for this voice connection.": "この音声接続では自動停止を利用できません。", + "Preview is off.": "プレビューはオフです。", + "Your choice applies now, but could not be saved.": "選択は適用されましたが、保存できませんでした。", + "WebRTC microphone support unavailable": "WebRTCマイクに対応していません", "VOICE UNAVAILABLE": "音声利用不可", - "VOICE ACTIVE": "音声オン", + "VOICE ACTIVE": "音声 オン", "Voice session could not be started.": "音声セッションを開始できませんでした。", - "Next session: {pendingId} — this session stays on {modelId}": "次回セッション: {pendingId}。このセッションは{modelId}のままです", - "Voice model: {pendingId} — click to switch to {target}; applies next session": "音声モデル: {pendingId}。クリックで{target}に切り替え、次回セッションで適用", - "Estimated session cost on {modelId} — {responses} response(s). Warns at {warn}, ends the session at {cap}.": "{modelId}でのセッション推定コスト。応答 {responses}件。{warn}で警告し、{cap}でセッションを終了します。", + "MINI": "ミニ", + "Next session: {pendingId} — this session stays on {modelId}": "次回セッション:{pendingId}。このセッションは{modelId}のままです", + "Voice model: {pendingId} — click to switch to {target}; applies next session": "音声モデル:{pendingId}。クリックで{target}に切り替え、次回セッションで適用", + "standard": "標準", + "mini": "ミニ", + "COST UNKNOWN": "コスト不明", + "ChatGPT OAuth session: {responses} response(s), {input} input and {output} output tokens, {captions} caption transcription(s) reported.": "ChatGPT OAuthセッション:応答{responses}件、入力トークン{input}、出力トークン{output}、字幕の文字起こし{captions}件が報告されました。", + "USD cost and the API spend cap are unavailable for this auth mode.": "この認証モードでは、米ドルでのコストとAPIの支出上限を利用できません。", + "Usage is incomplete because a response was still in flight when the session ended.": "セッション終了時に処理中の応答があったため、使用量は不完全です。", + "Estimated session cost on {modelId} — {responses} response(s). Warns at {warn}, ends the session at {cap}.": "{modelId}でのセッション推定コスト:応答{responses}件。{warn}で警告し、{cap}でセッションを終了します。", + "Estimate is incomplete — a response was still in flight when the session ended, so its usage was never reported.": "推定は不完全です。セッション終了時に処理中の応答があったため、その使用量は報告されませんでした。", + "STANDARD": "標準", "{tier} applies next session": "{tier}は次回セッションで適用", - "Session ended — cost cap {cost}": "セッション終了: コスト上限 {cost}", + "Session ended — cost cap {cost}": "セッション終了:コスト上限 {cost}", + "MIC": "マイク", "Radio did not start": "ラジオを開始できませんでした", + "{n} aircraft": { + "other": "航空機{n}機" + }, + "{n} military aircraft": { + "other": "軍用機{n}機" + }, + "{n} ships": { + "other": "船舶{n}隻" + }, + "{n} satellites": { + "other": "衛星{n}基" + }, + "{n} launches": { + "other": "打ち上げ{n}件" + }, + "{n} earthquakes": { + "other": "地震{n}件" + }, + "{n} fires": { + "other": "火災{n}件" + }, + "{n} fire perimeters": { + "other": "火災の延焼範囲{n}件" + }, + "{n} cyclones": { + "other": "サイクロン{n}個" + }, + "{n} buses": { + "other": "バス{n}台" + }, + "{n} bike share": { + "other": "シェアサイクル{n}か所" + }, + "{n} flock cameras": { + "other": "Flockカメラ{n}台" + }, + "{n} military bases": { + "other": "軍事基地{n}か所" + }, + "{n} datacenters": { + "other": "データセンター{n}か所" + }, + "{n} dams": { + "other": "ダム{n}か所" + }, + "{n} air quality": { + "other": "大気質の観測局{n}局" + }, + "{n} results": { + "other": "結果{n}件" + }, + "anywhere in the loaded data": "読み込み済みデータ全体", + "in view": "表示範囲内", + "within {radius} of the view centre": "表示中心から{radius}以内", + "within {radius} of {place} (Contacts window)": "{place}から{radius}以内(コンタクトのウィンドウ)", + "within {radius} of {place}": "{place}から{radius}以内", + "within {radius}": "{radius}以内", + "over {region}": "{region}全域", + "At least {items}": "少なくとも{items}", + "{items} {scope}": "{scope}の{items}", + "last 24 h": "過去24時間", + "past 30 d and upcoming": "過去30日間と今後", + "the flights layer loads by viewport": "フライトレイヤーは表示範囲ごとに読み込まれます", + "distance is ground distance, not overhead": "距離は地上距離で、真上からの距離ではありません", + "the count is a lower bound because at least one layer reached its retained limit.": "少なくとも1つのレイヤーが保持上限に達したため、この件数は下限値です。", + "{label} off": "{label} オフ", + "{label} loading": "{label}読み込み中", + "{label} error": "{label}エラー", + "counted the first {returned} loaded records": "最初に読み込まれた{returned}件を集計しました", + "counted {returned} of {total} loaded records": "読み込み済みの{total}件のうち{returned}件を集計しました", + "{layers} just turned on — still loading, counts will rise": "{layers}をオンにしたばかりです。読み込み中のため、件数は増えます", + "Contacts panel snapshot at {time} — the same retained cohort supplies the card, speech, and follow-up memory": "{time}時点のコンタクトパネルのスナップショット。カード、音声、追加の質問への記憶には同じ保持対象を使用しています", + "Contacts panel snapshot — the same retained cohort supplies the card, speech, and follow-up memory": "コンタクトパネルのスナップショット。カード、音声、追加の質問への記憶には同じ保持対象を使用しています", + "Fly below {km} km to a covered region": "{km} km未満まで高度を下げ、カバー範囲内の地域へ移動してください", + "No feed here yet · {n} regions available": { + "other": "ここにはまだフィードがありません · 利用可能な地域 {n}か所" + }, + "degraded": "性能低下", + "stale": "更新遅延", + "partial": "一部", + "fallback": "フォールバック", + "unavailable": "利用不可", + "Not answered: {layers}": "応答なし:{layers}", + "Toggle voice control": "音声コントロールを切り替え", + "Activate to toggle voice": "有効にすると音声を切り替え", + "Voice active": "音声 オン", + "Voice could not be started.": "音声を開始できませんでした。", + "the active voice session": "有効な音声セッション", + "{value} feet": "{value}フィート", + "Fire · FRP {frp} MW": "火災 · FRP {frp} MW", + "The flights layer is not enabled": "フライトレイヤーが有効になっていません", + "The military layer is not enabled": "軍用機レイヤーが有効になっていません", + "The satellites layer is not enabled": "衛星レイヤーが有効になっていません", + "The ais-live-vessels layer is not enabled": "ライブAIS船舶レイヤーが有効になっていません", + "Could not enable the requested layer": "要求されたレイヤーを有効にできませんでした", + "Could not disable the requested layer": "要求されたレイヤーを無効にできませんでした", + "Radio layer unavailable": "ラジオレイヤーを利用できません", + "Camera navigation is unavailable in the current view": "現在のビューではカメラのナビゲーションを利用できません", + "Camera navigation policy unavailable": "カメラのナビゲーションポリシーを利用できません", + "Nearest-aircraft selection supports Flights or Military Flights only": "最寄りの航空機の選択は、フライトまたは軍用機のみに対応しています", + "Nearest-aircraft selection needs a preset, place name, or latitude and longitude": "最寄りの航空機を選択するには、プリセット、地名、または緯度・経度が必要です", + "Could not arrive at the requested place": "要求された場所に到達できませんでした", + "The nearest airborne aircraft could not be selected": "飛行中の最寄りの航空機を選択できませんでした", + "No flights within {radius} of the current view": "現在のビューから{radius}以内にフライトはありません", + "No military within {radius} of the current view": "現在のビューから{radius}以内に軍用機はありません", + "No satellites within {radius} of the current view": "現在のビューから{radius}以内に衛星はありません", + "No vessels within {radius} of the current view": "現在のビューから{radius}以内に船舶はありません", + "{layer} is enabled on the {source} feed, but no airborne aircraft is loaded in the {place} view yet": "{layer}は{source}フィードで有効ですが、{place}のビューに飛行中の航空機はまだ読み込まれていません", + "{layer} is enabled, but no airborne aircraft is loaded in the {place} view yet": "{layer}は有効ですが、{place}のビューに飛行中の航空機はまだ読み込まれていません", + "{layer} is enabled, but its aircraft feed is unavailable": "{layer}は有効ですが、航空機フィードを利用できません", + "{layer} is enabled, but its destination refresh did not complete": "{layer}は有効ですが、目的地の更新が完了しませんでした", + "{layer} is enabled, but {source} is unavailable": "{layer}は有効ですが、{source}を利用できません", + "Could not arrive at {place}": "{place}に到達できませんでした", + "{name} is no longer loaded": "{name}は読み込まれていません", + "Unknown target layer: {target}": "不明なターゲットレイヤー:{target}", + "nominal": "標準", + "{label} on": "{label} オン", + "Frame aircraft": "航空機を視野に収める", + "Frame military aircraft": "軍用機を視野に収める", + "Frame ships": "船舶を視野に収める", + "Frame satellites": "衛星を視野に収める", + "Frame contacts": "コンタクトを視野に収める", + "{count} aircraft in frame": { + "other": "視野内の航空機 {count}機" + }, + "{count} military aircraft in frame": { + "other": "視野内の軍用機 {count}機" + }, + "{count} ships in frame": { + "other": "視野内の船舶 {count}隻" + }, + "{count} satellites in frame": { + "other": "視野内の衛星 {count}基" + }, + "{count} contacts in frame": { + "other": "視野内のコンタクト {count}件" + }, + "Nearest military aircraft": "最寄りの軍用機", + "Nearest ships": "最寄りの船舶", + "Nearest satellites": "最寄りの衛星", + "Nearest aircraft": "最寄りの航空機", + "{first} and {second}": "{first}と{second}", + "Layer": "レイヤー", + "there": "そこ", + "Camera range {range}": "カメラ距離 {range}", + "Within {radius} of the view": "ビューから{radius}以内", + "Labels on": "ラベル オン", + "Framing uses the nearest 80 loaded contacts": "視野に収める対象は、読み込み済みの最寄りの80件のコンタクトです", + "{distance} from {location}": "{location}から{distance}", + "Altitude {altitude}": "高度 {altitude}", + "{origin} to {destination}": "{origin}発{destination}行き", + "from {origin}": "{origin}発", + "to {destination}": "{destination}行き", + "Registration {registration}": "登録記号 {registration}", + "View state": "ビューの状態", + "Marked {count} places": { + "other": "{count}か所をマークしました" + }, + "Nothing marked": "マークしたものはありません", + "Not found: {places}": "見つかりません:{places}", + "Tracing outlines": "輪郭を描画中", + "Frame flights": "フライトを視野に収める", + "Frame military": "軍用機を視野に収める", + "Frame vessels": "船舶を視野に収める", + "Frame {target}": "{target}を視野に収める", + "Zoom out to globe": "地球全体までズームアウト", + "Open data layers": "データレイヤーを開く", + "Open or close a panel": "パネルを開閉", + "Change context mode": "コンテキストモードを変更", + "Control cockpit": "コックピットを操作", + "Change visual style": "ビジュアルスタイルを変更", + "Adjust HUD": "HUDを調整", + "Adjust cyber sonar": "サイバーソナーを調整", + "Adjust detection overlay": "検出オーバーレイを調整", + "Change map stack": "マップスタックを変更", + "Adjust post-processing": "ポストプロセスを調整", + "Control scene": "シーンを操作", + "Control CCTV": "CCTVを操作", + "Control radio": "ラジオを操作", + "Track contact": "コンタクトを追跡", + "Stop tracking": "追跡を停止", + "Clear marks": "マークを消去", + "Move camera": "カメラを移動", + "Fly route": "ルートを飛行", + "Analyst query": "分析クエリ", + "Next ISS pass": "次のISS通過", + "Next satellite pass": "次の衛星通過", + "Mark the map": "地図にマーク", + "Mark {targets} +{more}": "{targets}をマーク +{more}", + "Mark {targets}": "{targets}をマーク", + "Fly to {place}": "{place}へ移動", + "Fly to Location": "場所へ移動", + "Nearest aircraft to {place}": "{place}の最寄りの航空機", + "Nearest aircraft to Here": "ここの最寄りの航空機", + "Layer on": "レイヤー オン", + "Layer off": "レイヤー オフ", + "Zoom out": "ズームアウト", + "Zoom in": "ズームイン", + "Read the view": "ビューを読み上げ", + "Check view state": "ビューの状態を確認", + "Action": "操作", + "Finding places": "場所を検索中", + "Tracing outline": "輪郭を描画中", + "Looking up place": "場所を照会中", + "Flying": "移動中", + "Turning on layer": "レイヤーをオン中", + "Loading aircraft": "航空機を読み込み中", + "Picking nearest": "最寄りを選択中", + "Working": "処理中", + "in progress": "処理中", + "done": "完了", + "failed": "失敗", + "cancelled": "キャンセル済み", + "Outline traced": "輪郭を描画しました", + "Outline unavailable": "輪郭を取得できません", + "Source: {label}": "出典:{label}", + "WORKING": "処理中", + "DONE": "完了", + "Recent speech": "最近の発話", + "HERE": "ここ", "Aircraft cockpit view": "航空機コックピットビュー", - "LEVEL": "レベル", + "LEVEL": "水平", "Estimated destination direction": "推定目的地の方向", "DEST ---°": "目的地 ---°", "OPTICAL PLANE · 01": "光学面 · 01", @@ -664,22 +2567,28 @@ "Cockpit vision style": "コックピットのビジョンスタイル", "Previous cockpit vision style": "前のコックピットビジョンスタイル", "Previous vision style": "前のビジョンスタイル", - "Current cockpit vision style: NORMAL. Activate for next style.": "現在のコックピットビジョンスタイル: 標準。有効にすると次のスタイルへ。", - "Current style: NORMAL — click for next": "現在のスタイル: 標準 — クリックで次へ", + "Current cockpit vision style: NORMAL. Activate for next style.": "現在のコックピットビジョンスタイル:標準。有効にすると次のスタイルへ。", + "Current style: NORMAL — click for next": "現在のスタイル:標準 — クリックで次へ", "CURRENT": "現在", "Next cockpit vision style": "次のコックピットビジョンスタイル", "Next vision style": "次のビジョンスタイル", "Current aircraft heading": "現在の機首方位", "GROUND SPEED": "対地速度", + "KTS": "KT", "ALTITUDE": "高度", + "FT": "FT", "Contact cockpit summary": "コンタクトのコックピット概要", "CONTACT": "コンタクト", "CONTACTS · 250 KM": "コンタクト · 250 KM", "Contact navigation": "コンタクトナビゲーション", "CONTEXT ONLY": "参考情報のみ", "Nearby cohort counts": "周辺の種別ごとの件数", + "FLT": "FLT", + "MIL": "軍用", + "SITE": "施設", "NEAREST OBSERVED / MAPPED": "最寄りの観測 / マップ済み", - "AVAILABLE INPUTS ONLY · NOT AN ALL-CLEAR": "利用可能な入力のみ · 安全を保証するものではありません", + "AVAILABLE INPUTS ONLY · NOT AN ALL-CLEAR": "利用可能な入力のみ · 安全の保証ではありません", + "WX": "気象", "Cockpit briefing carousel": "コックピットブリーフィングカルーセル", "Estimated flight plan": "推定フライトプラン", "ESTIMATED FLIGHT PLAN": "推定フライトプラン", @@ -695,9 +2604,14 @@ "WIND": "風", "SKY": "空", "PRECIP": "降水", + "MM": "mm", + "Weather data by Open-Meteo.com": "気象データ提供:Open-Meteo.com", + "Cockpit briefing pages": "コックピットのブリーフィングページ", + "SIG": "信号", "Show Live Signals": "ライブシグナルを表示", "NEWS": "ニュース", "Show Regional News": "地域ニュースを表示", + "LOCAL": "ローカル", "Show Local Info": "ローカル情報を表示", "Cockpit display and Radio controls": "コックピットのディスプレイとラジオの操作", "DISPLAY": "ディスプレイ", @@ -709,6 +2623,8 @@ "Next filtered radio station": "絞り込み中の次のラジオ局", "VOLUME": "音量", "Cockpit Radio volume": "コックピットラジオの音量", + "ESC EXIT": "Escで終了", + "C TOGGLE": "Cで切替", "View switcher": "ビュー切替", "Exit cockpit and return to full globe view": "コックピットを終了して地球全体ビューに戻る", "RESET": "リセット", @@ -721,7 +2637,7 @@ "Show the globe without a visual filter.": "ビジュアルフィルターなしで地球儀を表示します。", "Emulate a green phosphor CRT with scanlines and screen curvature.": "走査線と画面の湾曲を備えた、緑色蛍光体のCRTを再現します。", "Simulate night-vision goggles with green intensification and a tube vignette.": "緑色の光増幅とチューブ周辺の減光で、暗視ゴーグルを再現します。", - "Simulate FLIR-style thermal contrast. Turn up Ironbow for color.": "FLIR風の熱コントラストを再現します。色を付けるには Ironbow を上げてください。", + "Simulate FLIR-style thermal contrast. Turn up Ironbow for color.": "FLIR風の熱コントラストを再現します。色を付けるにはIronbowを上げてください。", "Apply bright cel-shaded color and illustrated outlines.": "明るいセルシェーディングの色と輪郭線を適用します。", "Apply high-contrast monochrome film-noir grading.": "コントラストの強いモノクロのフィルムノワール調に仕上げます。", "Add a cold, snowy whiteout treatment to the scene.": "冷たい雪のホワイトアウト効果をシーンに加えます。", @@ -734,8 +2650,11 @@ "Keep location tray open": "位置トレイを開いたままにする", "Search any location": "場所を検索", "Search location by name or coordinates": "名前または座標で場所を検索", - "Search any location...": "場所を検索...", + "Search any location...": "場所を検索…", "WEATHER": "気象", + "Active weather products": "有効な気象プロダクト", + "RECENT IMAGERY": "最近の衛星画像", + "Imagery days in the box": "範囲内の画像のある日", "CONTEXT": "コンテキスト", "Compact Radio controls": "コンパクトラジオ操作", "Open detailed Radio controls": "詳細ラジオ操作を開く", @@ -745,7 +2664,7 @@ "Expand panel": "パネルを展開", "Context mode": "コンテキストモード", "CONTACTS": "コンタクト", - "Cycles the nearest contacts of whatever type you select — planes, vessels, installations. Satellites track independently.": "選択した種類 (航空機、船舶、施設) の最寄りのコンタクトを順に切り替えます。衛星は独立して追跡されます。", + "Cycles the nearest contacts of whatever type you select — planes, vessels, installations. Satellites track independently.": "選択した種類(航空機、船舶、施設)の最寄りのコンタクトを順に切り替えます。衛星は独立して追跡されます。", "SPACE MISSIONS": "宇宙ミッション", "SELECT CONTEXT": "コンテキストを選択", "Contact Context actions": "コンタクトコンテキストの操作", @@ -763,8 +2682,9 @@ "STATION TAG": "局タグ", "Filter stations by station tag": "局タグで局を絞り込み", "All": "すべて", - "Enable Radio, then choose a globe marker or use next.": "ラジオを有効にして、地球儀のマーカーを選ぶか、次へを使用してください。", + "Enable Radio, then choose a globe marker or use next.": "ラジオを有効にしてから、地球儀のマーカーを選ぶか、[次へ]を使ってください。", "DRAG TO TUNE": "ドラッグで選局", + "Tune available internet radio stations": "利用可能なインターネットラジオ局を選局", "ALL · DRAG THE NEEDLE": "すべて · 針をドラッグ", "SNAPS TO AVAILABLE STATIONS": "利用可能な局にスナップ", "Radio playback": "ラジオ再生", @@ -775,14 +2695,49 @@ "Stop radio playback": "ラジオ再生を停止", "Radio volume": "ラジオの音量", "STATION SITE": "放送局サイト", + "DIRECTORY: RADIO BROWSER": "ディレクトリ:RADIO BROWSER", "Audio connects directly to the broadcaster after you press play. Your IP is visible to that broadcaster.": "再生ボタンを押すと、音声は放送局に直接接続されます。IPアドレスは放送局に表示されます。", - "Intelligence HUD (H)": "インテリジェンスHUD (H)", + "Local RTL-SDR receiver": "ローカルRTL-SDR受信機", + "LOCAL RTL-SDR": "ローカルRTL-SDR", + "Chrome/Edge · WebUSB · one local tuner shared by FM and the Local ADS-B layer.": "Chrome/Edge · WebUSB · 1台のローカルチューナーをFMとローカルADS-Bレイヤーで共有します。", + "Use your location for faster ADS-B position decoding": "位置情報を使ってADS-Bの位置デコードを高速化", + "CHANGE DEVICE": "デバイスを変更", + "Choose a different RTL-SDR or receiver channel": "別のRTL-SDRまたは受信チャンネルを選択", + "RTL-SDR receiver mode": "RTL-SDRの受信モード", + "GAIN": "ゲイン", + "RTL-SDR tuner gain for the current mode": "現在のモードのRTL-SDRチューナーゲイン", + "AUTO": "自動", + "MSG/S": "MSG/S", + "HEARD": "受信", + "POSITIONED": "位置特定済み", + "FM MHZ": "FM MHZ", + "TUNE": "同調", + "Seek broadcast FM stations": "FM放送局をシーク", + "◀ SEEK": "◀ シーク", + "SEEK ▶": "シーク ▶", + "SDR VOL": "SDR音量", + "Local SDR volume": "ローカルSDRの音量", + "Intelligence HUD (H)": "インテリジェンスHUD(H)", "Layout": "レイアウト", "HUD layout": "HUDレイアウト", "Tactical": "タクティカル", "Operator": "オペレーター", "Minimal": "ミニマル", - "Detection Overlay (D)": "検出オーバーレイ (D)", + "Cyber": "サイバー", + "Sonar": "ソナー", + "Cyber sonar contact scanner": "サイバーソナーのコンタクトスキャナー", + "Rings": "リング数", + "Sonar ring count": "ソナーのリング数", + "Range": "範囲", + "Sonar ring range": "ソナーのリング範囲", + "Power": "強さ", + "Sonar intensity": "ソナーの強度", + "Opacity": "不透明度", + "Cyber contact and label opacity": "サイバーのコンタクトとラベルの不透明度", + "Minimum opacity for map dots, icons, models, brackets, and labels between sonar passes": "ソナーの走査の合間における地図上の点、アイコン、モデル、ブラケット、ラベルの最小不透明度", + "Sector": "扇形", + "Sonar sector width": "ソナーの扇形の幅", + "Detection Overlay (D)": "検出オーバーレイ(D)", "Detection overlay": "検出オーバーレイ", "Detection label density": "検出ラベルの密度", "Allocation": "配分", @@ -791,20 +2746,40 @@ "Weighted": "加重", "Fade": "フェード", "Detection fade distance": "検出のフェード距離", - "World-overlay fade distance outside the keyhole as a percentage of its radius": "キーホール外のワールドオーバーレイのフェード距離 (キーホール半径に対する割合)", + "World-overlay fade distance outside the keyhole as a percentage of its radius": "キーホール外のワールドオーバーレイのフェード距離(キーホール半径に対する割合)", "Outside": "外側", "Detection opacity outside the keyhole": "キーホール外の検出の不透明度", "World-overlay label and card opacity beyond the fade distance": "フェード距離を超えた範囲のワールドオーバーレイのラベルとカードの不透明度", "PARAMETERS": "パラメーター", - "3D aircraft — flat icons zoomed out, 3D models up close": "3D航空機: 遠景はフラットアイコン、近景は3Dモデル", + "3D aircraft — flat icons zoomed out, 3D models up close": "3D航空機:遠景はフラットアイコン、近景は3Dモデル", "Models": "モデル", "3D model coverage": "3Dモデルの適用範囲", "Proximity": "近接", - "Scope — the circular viewport mask": "スコープ: 円形のビューポートマスク", + "Scope — the circular viewport mask": "スコープ:円形のビューポートマスク", "Scope": "スコープ", "Feather": "ぼかし", "Scope edge feather": "スコープ縁のぼかし", - "Scope edge feather as a percentage of the keyhole radius": "スコープ縁のぼかし (キーホール半径に対する割合)", + "Scope edge feather as a percentage of the keyhole radius": "スコープ縁のぼかし(キーホール半径に対する割合)", + "Draw on the world — click vertices, double-click or Enter to finish, Esc to cancel": "地球上に描画:クリックで頂点を追加、ダブルクリックまたはEnterで完了、Escでキャンセル", + "Shape": "図形", + "Shape to draw": "描画する図形", + "Area": "範囲", + "Line": "線", + "Pin": "ピン", + "Label (optional)": "ラベル(任意)", + "Label for the drawn shape": "描画した図形のラベル", + "Colour of the drawn shape": "描画した図形の色", + "Primary": "プライマリー", + "Amber": "アンバー", + "Cyan": "シアン", + "Green": "緑", + "Red": "赤", + "Clear": "消去", + "Remove every mark from the board": "ボードからすべてのマークを削除", + "Show your own GeoJSON, KML, KMZ or GPX files on the globe (or drop them onto it). File bytes stay on this device; overlays can appear in map screenshots shared with voice.": "手元のGeoJSON、KML、KMZ、GPXファイルを地球上に表示します(地球にドロップすることもできます)。ファイルのデータはこのデバイスから出ません。オーバーレイは、音声と共有される地図のスクリーンショットに写る場合があります。", + "Import": "インポート", + "Choose GeoJSON, KML, KMZ or GPX files": "GeoJSON、KML、KMZ、GPXファイルを選択", + "Imported files": "インポートしたファイル", "Celestial": "天球", "Hide UI chrome": "UIを非表示", "Clean UI": "クリーンUI", @@ -815,23 +2790,44 @@ "Sharpen intensity": "シャープの強度", "EXIT CLEAN VIEW": "クリーンビュー終了", "Return UI controls": "UIコントロールを戻す", - "Initializing photorealistic world...": "フォトリアルな世界を初期化中...", + "Initializing photorealistic world...": "フォトリアルな世界を初期化中…", "DATA LAYERS": "データレイヤー", + "ACQUIRING FRAME": "フレームを取得中", "NEAREST": "最寄り", "CCTV camera": "CCTVカメラ", "CALIBRATION": "キャリブレーション", - "Drag the camera in the world: rings rotate, arrows move, handles set range/FOV": "ワールド上でカメラをドラッグ: リングで回転、矢印で移動、ハンドルで距離/FOVを設定", - "Camera pose — click a value to type": "カメラの姿勢: 値をクリックして入力", - "Heading (compass °) — click to type": "方位 (コンパス °): クリックして入力", - "Pitch (° up/down) — click to type": "ピッチ (上下 °): クリックして入力", - "Horizontal FOV (°) — click to type": "水平FOV (°): クリックして入力", - "Range / monitor-plane distance (m) — click to type": "距離 / モニター面までの距離 (m): クリックして入力", - "Mount height above ground (m) — click to type": "地上からの設置高 (m): クリックして入力", - "North offset from catalog position (m) — click to type": "カタログ位置からの北方向オフセット (m): クリックして入力", - "East offset from catalog position (m) — click to type": "カタログ位置からの東方向オフセット (m): クリックして入力", + "Drag the camera in the world: rings rotate, arrows move, handles set range/FOV": "ワールド上でカメラをドラッグ:リングで回転、矢印で移動、ハンドルで距離/FOVを設定", + "Camera pose — click a value to type": "カメラの姿勢:値をクリックして入力", + "Heading (compass °) — click to type": "方位(コンパス °):クリックして入力", + "Pitch (° up/down) — click to type": "ピッチ(上下 °):クリックして入力", + "Horizontal FOV (°) — click to type": "水平FOV(°):クリックして入力", + "Range / monitor-plane distance (m) — click to type": "距離 / モニター面までの距離(m):クリックして入力", + "Mount height above ground (m) — click to type": "地上からの設置高(m):クリックして入力", + "North offset from catalog position (m) — click to type": "カタログ位置からの北方向オフセット(m):クリックして入力", + "East offset from catalog position (m) — click to type": "カタログ位置からの東方向オフセット(m):クリックして入力", "SAVE CAL": "CAL保存", "RESET CAL": "CALリセット", "SCENE SUMMARY": "シーン概要", + "STREET LEVEL": "ストリートレベル", + "Turn Street Level on or off": "ストリートレベルのオン/オフ", + "Show the street-level view full screen (Esc shrinks it)": "ストリートレベルのビューを全画面表示(Escで縮小)", + "Image fit": "画像の表示方法", + "FIT": "全体", + "Fit: show the whole photo, with dark bars where its shape differs from the frame": "全体:写真全体を表示し、枠と縦横比が異なる部分は黒帯で埋めます", + "FILL": "フィル", + "Fill: fill the frame edge to edge, cropping the photo": "フィル:枠いっぱいに表示し、写真をトリミングします", + "Close the image and deselect it on the map": "画像を閉じて地図上の選択を解除", + "Close the street-level image": "ストリートレベル画像を閉じる", + "Street-level viewer": "ストリートレベルビューアー", + "Open this image on the provider's site": "この画像をプロバイダーのサイトで開く", + "Imagery providers": "画像プロバイダー", + "PROVIDERS": "プロバイダー", + "Imagery filters": "画像フィルター", + "IMAGERY": "画像", + "Panorama filter": "パノラマフィルター", + "ALL": "すべて", + "FLAT": "平面", + "SINCE": "期間", "SCENES": "シーン", "Scene recipe": "シーンレシピ", "NEW": "新規", @@ -841,19 +2837,22 @@ "EXPORT PRESETS": "プリセット書出", "IMPORT": "読込", "RUN LOG": "実行ログ", - "POWER UP": "POWER UP", + "POWER UP": "パワーアップ", "GROUND STATION · PROVIDER SETTINGS": "地上局 · プロバイダー設定", "Close key setup": "キー設定を閉じる", - "Power up the globe": "地球儀に電源を入れる", - "The globe already flies keyless. Every key below switches on another real feed — paste one and it's saved into this app's local configuration, then the server restarts itself. Server-side keys stay on this machine; Google Maps and Cesium ion run in the browser and must be provider-restricted. Keys you configured elsewhere are shown but never touched.": "地球儀はキーなしでも飛行できます。下記の各キーは、それぞれ別の実データフィードを有効にします。キーを貼り付けるとこのアプリのローカル設定に保存され、サーバーが自動で再起動します。サーバー側のキーはこのマシンから出ません。Google Maps と Cesium ion はブラウザで動作するため、プロバイダー側で利用制限を設定してください。他の場所で設定済みのキーは表示のみで、変更されません。", + "Power up the globe": "地球儀をパワーアップ", + "The globe already flies keyless. Every key below switches on another real feed — paste one and it's saved into this app's local configuration, then the server restarts itself. Server-side keys stay on this machine; Google Maps and Cesium ion run in the browser and must be provider-restricted. Keys you configured elsewhere are shown but never touched.": "地球儀はキーなしでもそのまま使えます。下の各キーは、それぞれ別の実データフィードを有効にします。キーを貼り付けるとこのアプリのローカル設定に保存され、サーバーが自動で再起動します。サーバー側のキーはこのマシンから出ません。Google MapsとCesium ionはブラウザーで動作するため、プロバイダー側で利用制限を設定してください。他の場所で設定済みのキーは表示のみで、変更されません。", "SAVE KEYS": "キーを保存", "ESC to close": "ESCで閉じる", - "The Google Maps key buys the photorealistic planet — everything else stacks on top.": "Google Maps のキーでフォトリアルな地球が使えるようになり、他のすべてはその上に重なります。", - "NO PLACE LEFT BEHIND": "誰も取り残さない", + "The Google Maps key buys the photorealistic planet — everything else stacks on top.": "Google Mapsのキーでフォトリアルな地球が使えるようになり、他のすべてはその上に重なります。", + "NO PLACE LEFT BEHIND": "取り残される場所はない", "ACTIVE STYLE": "現在のスタイル", "Globe actions": "地球儀の操作", "Turn off all selected data layers": "選択中のデータレイヤーをすべてオフにする", "Copy share link": "共有リンクをコピー", + "Toggle straight-down and tilted map views": "真上表示と斜め表示を切り替え", + "Reset map to north up": "地図を北が上になるようにリセット", + "Reset map bearing to north": "地図の方位を北にリセット", "Reset camera and return to full globe view": "カメラをリセットして地球全体ビューに戻す", "MISSION CONTROL · FIRST LAUNCH": "ミッションコントロール · 初回起動", "Choose your first view": "最初のビューを選択", @@ -864,5 +2863,5 @@ "Begin with a clean globe": "まっさらな地球儀から始める", "Don't show this again": "今後表示しない", "ESC to dismiss": "ESCで閉じる", - "Tip: the GEV MIC button in the dock lets you talk to the map.": "ヒント: ドックの GEV MIC ボタンで、マップに話しかけられます。" + "Tip: the GEV MIC button in the dock lets you talk to the map.": "ヒント:ドックのGEV MICボタンで地図に話しかけられます。" } diff --git a/src/i18n/same-as-english.json b/src/i18n/same-as-english.json index 83c8897d8..7938d74a3 100644 --- a/src/i18n/same-as-english.json +++ b/src/i18n/same-as-english.json @@ -124,6 +124,57 @@ "ΔN", "▲ {frp} MW" ], + "ja": [ + "1090 MHz", + "978 MHz UAT", + "AIS: --", + "AIS: {name}", + "BRG {value}°", + "BRG —", + "CAL {value}", + "CAL · {badge}", + "CCTV", + "CH {index} / {total}", + "CRS {value}°", + "CRT", + "FLIR", + "FLT", + "FM MHZ", + "FOV", + "FOV {value}°", + "FT", + "GEO", + "HDG", + "HDG {value}°", + "Ironbow", + "Landsat 8/9", + "MSG/S", + "NVG", + "REC", + "S2 GhostMaps", + "SRC {value}", + "Sentinel-2", + "USB {rate} msg/s", + "WHOT/BHOT", + "dB", + "ft", + "hPa", + "km", + "km/h", + "kt", + "mph", + "{city} CCTV", + "{rate} msg/s", + "{source} HTTP {status}", + "{speed} kn", + "{type} SPD: {speed} HDG: {heading}", + "{value} KM", + "{value} KM/H", + "{value} KM/S", + "ΔE", + "ΔN", + "▲ {frp} MW" + ], "ru": [ "AIS: --", "AIS: {name}", From ed402014814339289eae453f2c705748e7d33778 Mon Sep 17 00:00:00 2001 From: German Khokhlov Date: Wed, 28 Oct 2026 12:59:32 +0400 Subject: [PATCH 13/83] i18n(ja): ship Japanese MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Register ja: CATALOGS, LOCALES, LOCALE_NAMES (日本語) and the package boundaries; ja and ja-JP tags select it. - Japanese unit words follow the number directly, as in the catalog: formatQuantity writes 5分 and 1時間5分 (km and kt keep the space), and formatRelativeTime drops the space CLDR puts in 5 分前. - Tests: locale tags, picker order, Intl output, durations and the ramp/exit/lane wording in Japanese. - docs/translations/ja.md: style, units, plurals and glossary; ja added to TRANSLATORS.md and CURRENT-STATE.md. Co-Authored-By: Claude Opus 5.5 --- docs/CURRENT-STATE.md | 2 +- docs/TRANSLATORS.md | 4 +- docs/translations/ja.md | 90 +++++++++++++++++++++++++++++++++ scripts/package-boundaries.json | 43 ++++++++++++++++ src/data/directions.test.mjs | 13 +++++ src/i18n/i18n.test.mjs | 10 ++++ src/i18n/index.js | 19 +++++-- src/i18n/locale.js | 12 ++++- src/layers/directions/index.js | 10 +++- src/ui/localePicker.test.mjs | 8 +-- src/ui/unitLabels.js | 15 +++++- src/ui/unitLabels.test.mjs | 11 ++++ 12 files changed, 221 insertions(+), 16 deletions(-) create mode 100644 docs/translations/ja.md diff --git a/docs/CURRENT-STATE.md b/docs/CURRENT-STATE.md index c55031a6a..0a71ce3e2 100644 --- a/docs/CURRENT-STATE.md +++ b/docs/CURRENT-STATE.md @@ -3733,7 +3733,7 @@ test:track` 43 tracking invariants · headless QA harnesses under ### Interface localization (October 2026) -Shipped locales: **en** (source and fallback), **es**, **ru**, **zh-CN** and **zh-Hant**. The code lives in +Shipped locales: **en** (source and fallback), **es**, **ja**, **ru**, **zh-CN** and **zh-Hant**. The code lives in `src/i18n/`. How to mark UI text: [`docs/I18N.md`](./I18N.md); translator workflow: [`docs/TRANSLATORS.md`](./TRANSLATORS.md). diff --git a/docs/TRANSLATORS.md b/docs/TRANSLATORS.md index 830ca155e..95d7a6088 100644 --- a/docs/TRANSLATORS.md +++ b/docs/TRANSLATORS.md @@ -1,6 +1,6 @@ # Translating God's Eye View -Shipped languages: **English** (source and fallback), **Spanish** (`es`), **Russian** (`ru`), **Simplified Chinese** (`zh-CN`) and **Traditional Chinese** (`zh-Hant`). +Shipped languages: **English** (source and fallback), **Spanish** (`es`), **Japanese** (`ja`), **Russian** (`ru`), **Simplified Chinese** (`zh-CN`) and **Traditional Chinese** (`zh-Hant`). ## How it works @@ -63,4 +63,4 @@ These are contracts, not copy: layer ids and registry keys, status enums and oth ## Language notes -Each language keeps its glossary, plural forms, units and style in its own file, `docs/translations/.md`: [Spanish](./translations/es.md), [Russian](./translations/ru.md), [Simplified Chinese](./translations/zh-CN.md), [Traditional Chinese](./translations/zh-Hant.md). Read it before translating, and add a term there when you settle on one. +Each language keeps its glossary, plural forms, units and style in its own file, `docs/translations/.md`: [Spanish](./translations/es.md), [Japanese](./translations/ja.md), [Russian](./translations/ru.md), [Simplified Chinese](./translations/zh-CN.md), [Traditional Chinese](./translations/zh-Hant.md). Read it before translating, and add a term there when you settle on one. diff --git a/docs/translations/ja.md b/docs/translations/ja.md new file mode 100644 index 000000000..74abc49b5 --- /dev/null +++ b/docs/translations/ja.md @@ -0,0 +1,90 @@ +# Japanese (`ja`) + +Catalog: `src/i18n/locales/ja.json`. General rules: [TRANSLATORS.md](../TRANSLATORS.md). + +Translation source: abiyeenzo (#913). + +## Style + +- Sentences use です/ます: 「キーを保存しました」, 「もう一度お試しください」. Labels, buttons and HUD chips are short nouns or verb stems without a final 。: 「再試行」, 「保存」, 「ライブ」, 「オフ」. +- Japanese has no case: an UPPERCASE English label becomes the same short Japanese label. Codes, units and names stay in their own case (HDG, ADS-B, km). +- Full-width punctuation in Japanese text: 、。:?!()「」. Quote names and titles with 「」: 「{shot}」を削除しますか? Keep `·` as the HUD separator, `…` for an ellipsis and `—`, `→`, `↗` as in English. A dash inside a sentence becomes 。 or :. +- Button names cited in running text go in []: [次へ]を使ってください. +- No space between Japanese and Latin letters, digits or a `{placeholder}`: 「AIS船舶」, 「Spaceを長押しで話す」, 「{count}件」, 「{name}を表示」. +- Two exceptions keep the space: a Japanese label before its value in a readout (「雲量 {pct}%」, 「ステーション {id}」, 「高度 {altitude}」), and the state words in toggles (「CCTV オン」, 「ラジオ オフ」). +- Loanwords are katakana with the long-vowel mark, as in Microsoft and Apple style: ユーザー, ブラウザー, ビューアー, プロバイダー, レイヤー, フィルター, モニター, パラメーター. Pick one katakana form per term and keep it (see the glossary). +- Product, provider and dataset names stay in Latin script: Google Maps, Cesium ion, OpenSky, CelesTrak, NASA FIRMS, Sentinel-2, KartaView. Google's own product names use Google's Japanese: Google ストリートビュー. Nepal place names in the Bhote Koshi scenes stay in Latin script, as in zh-CN; country and well-known city names are translated (ネパール, 東京, オースティン). + +## Numbers, units and dates + +- Units: km, m, km/h, m/s, kt, ft, mph, hPa, MW, dB, °, % stay as written, with the English spacing (「250 km」, 「{frp} MW」, 「95 kt」). +- Time units are words written straight after the number: 秒, 分, 時間, 日 (「5分前」, 「{count}時間」, 「1時間5分」). `formatQuantity` and `formatRelativeTime` drop the space for Japanese unit words, so code-built values match the catalog. +- Counters follow the thing counted: 機 (aircraft), 隻 (ships), 基 (satellites), 台 (cameras, vehicles), 局 (stations), 件 (records, results, events), か所 (sites), 個 (generic). Prefer a counter to a bare number. +- Dates come from `Intl` and read year first: 2026年8月26日. Coordinates in prose are 北緯 / 東経; HUD hemisphere letters stay N, S, E, W. + +## Plurals + +`Intl.PluralRules('ja')` has one category, `other`: a `tn()` entry has only that form. Put the counter next to the number: 「航空機{n}機」, 「船舶{n}隻」, 「メッセージ {count}件」. + +## Glossary + +| English | 日本語 | +| ----------------------------------------- | --------------------------------------- | +| layer / data layer | レイヤー / データレイヤー | +| feed | フィード | +| source / data source / attribution | ソース / データソース / 出典 | +| LIVE (status) / live data | ライブ / ライブデータ | +| SIMULATED | シミュレーション | +| stale / degraded / unavailable | 更新遅延 / 性能低下 / 利用不可 | +| retry | 再試行 | +| key (API key) / POWER UP | キー(APIキー)/ パワーアップ | +| Provider Settings | プロバイダー設定 | +| globe / map / map source / basemap | 地球儀 / 地図 / マップソース / ベースマップ | +| mapped (OSM-mapped sites) | マップ済み | +| aircraft / flight / military flights | 航空機 / フライト / 軍用機 | +| vessel, ship | 船舶 | +| satellite | 衛星 | +| launch (rocket) / space mission | 打ち上げ / 宇宙ミッション | +| stage (rocket) / downrange | 段 / ダウンレンジ | +| contact (tracked object) | コンタクト | +| installation, site | 施設 | +| camera / CCTV camera | カメラ / CCTVカメラ | +| earthquake / active fire / fire perimeter | 地震 / 火災検知 / 延焼範囲 | +| contained (fire) | 鎮圧 | +| scene / shot | シーン / ショット | +| briefing / panel / dock | ブリーフィング / パネル / ドック | +| preset / visual preset | プリセット / ビジュアルプリセット | +| Tactical / Operator / Minimal / Cyber | タクティカル / オペレーター / ミニマル / サイバー | +| Scope (circular viewport mask) / keyhole | スコープ / キーホール | +| Clean UI | クリーンUI | +| cockpit | コックピット | +| heading / altitude / ground speed | 機首方位 / 高度 / 対地速度 | +| HDG / BRG / CRS / FOV | そのまま(HUDコード) | +| squawk | スコーク | +| map heading / North up | 方位 / 北を上に | +| Street Level / Street View (Google) | ストリートレベル / ストリートビュー | +| Recent Imagery | 最近の衛星画像 | +| Global Context / Context (panel) | グローバルコンテキスト / コンテキスト | +| radio (station) / tune / seek | ラジオ(局)/ 選局・同調 / シーク | +| transit / bikeshare | 公共交通 / シェアサイクル | +| Previous / Next | 前へ / 次へ | +| compass points (N, NNE, NE, ENE, …) | 北, 北北東, 北東, 東北東, … | +| weather field / FIELD (selector) | 要素 | +| weather model / forecast lead hours | モデル / 予報時間 | +| valid (forecast time) / issued | 対象時刻 / 発表 | +| radar reflectivity / lightning density | レーダー反射強度 / 雷密度 | +| cyclone / advisory (NHC/CPHC) | サイクロン / 情報(第N報) | +| forecast uncertainty cone | 予報円 | +| tropical storm / tropical depression | 熱帯暴風雨 / 熱帯低気圧 | +| scene cloud / mosaic / daily overview | シーン雲量 / モザイク / 日次概観 | +| box (Recent Imagery area) | 範囲 | +| pin (Recent Imagery) | 固定 | +| outline / mark (map annotation) | 輪郭 / マーク | +| share (a view or link) | 共有 | +| AI agent | AIエージェント | +| frame (bring into view) | 視野に収める | +| story beat / evidence beat | ストーリー区切り / 証拠の区切り | +| camera pose / camera move | カメラの姿勢 / 移動 | +| roundabout / ramp / exit | ロータリー / ランプ / 出口 | +| reduced motion | 動きを減らす | +| NOT AN ALL-CLEAR | 安全の保証ではありません | diff --git a/scripts/package-boundaries.json b/scripts/package-boundaries.json index 9f06f73f6..89c2596b5 100644 --- a/scripts/package-boundaries.json +++ b/scripts/package-boundaries.json @@ -440,6 +440,7 @@ "src/i18n/index.js", "src/i18n/locale.js", "src/i18n/locales/es.json", + "src/i18n/locales/ja.json", "src/i18n/locales/ru.json", "src/i18n/locales/zh-CN.json", "src/i18n/locales/zh-Hant.json" @@ -480,6 +481,7 @@ "src/i18n/index.js", "src/i18n/locale.js", "src/i18n/locales/es.json", + "src/i18n/locales/ja.json", "src/i18n/locales/ru.json", "src/i18n/locales/zh-CN.json", "src/i18n/locales/zh-Hant.json" @@ -510,6 +512,7 @@ "src/i18n/index.js", "src/i18n/locale.js", "src/i18n/locales/es.json", + "src/i18n/locales/ja.json", "src/i18n/locales/ru.json", "src/i18n/locales/zh-CN.json", "src/i18n/locales/zh-Hant.json", @@ -532,6 +535,7 @@ "src/i18n/index.js", "src/i18n/locale.js", "src/i18n/locales/es.json", + "src/i18n/locales/ja.json", "src/i18n/locales/ru.json", "src/i18n/locales/zh-CN.json", "src/i18n/locales/zh-Hant.json" @@ -549,6 +553,7 @@ "src/i18n/index.js", "src/i18n/locale.js", "src/i18n/locales/es.json", + "src/i18n/locales/ja.json", "src/i18n/locales/ru.json", "src/i18n/locales/zh-CN.json", "src/i18n/locales/zh-Hant.json" @@ -569,6 +574,7 @@ "src/i18n/index.js", "src/i18n/locale.js", "src/i18n/locales/es.json", + "src/i18n/locales/ja.json", "src/i18n/locales/ru.json", "src/i18n/locales/zh-CN.json", "src/i18n/locales/zh-Hant.json", @@ -596,6 +602,7 @@ "src/i18n/index.js", "src/i18n/locale.js", "src/i18n/locales/es.json", + "src/i18n/locales/ja.json", "src/i18n/locales/ru.json", "src/i18n/locales/zh-CN.json", "src/i18n/locales/zh-Hant.json", @@ -631,6 +638,7 @@ "src/i18n/index.js", "src/i18n/locale.js", "src/i18n/locales/es.json", + "src/i18n/locales/ja.json", "src/i18n/locales/ru.json", "src/i18n/locales/zh-CN.json", "src/i18n/locales/zh-Hant.json", @@ -648,6 +656,7 @@ "src/i18n/index.js", "src/i18n/locale.js", "src/i18n/locales/es.json", + "src/i18n/locales/ja.json", "src/i18n/locales/ru.json", "src/i18n/locales/zh-CN.json", "src/i18n/locales/zh-Hant.json", @@ -807,6 +816,7 @@ "src/i18n/index.js", "src/i18n/locale.js", "src/i18n/locales/es.json", + "src/i18n/locales/ja.json", "src/i18n/locales/ru.json", "src/i18n/locales/zh-CN.json", "src/i18n/locales/zh-Hant.json", @@ -929,6 +939,7 @@ "src/i18n/index.js", "src/i18n/locale.js", "src/i18n/locales/es.json", + "src/i18n/locales/ja.json", "src/i18n/locales/ru.json", "src/i18n/locales/zh-CN.json", "src/i18n/locales/zh-Hant.json", @@ -997,6 +1008,7 @@ "src/i18n/index.js", "src/i18n/locale.js", "src/i18n/locales/es.json", + "src/i18n/locales/ja.json", "src/i18n/locales/ru.json", "src/i18n/locales/zh-CN.json", "src/i18n/locales/zh-Hant.json", @@ -1046,6 +1058,7 @@ "src/i18n/index.js", "src/i18n/locale.js", "src/i18n/locales/es.json", + "src/i18n/locales/ja.json", "src/i18n/locales/ru.json", "src/i18n/locales/zh-CN.json", "src/i18n/locales/zh-Hant.json" @@ -1109,6 +1122,7 @@ "src/i18n/index.js", "src/i18n/locale.js", "src/i18n/locales/es.json", + "src/i18n/locales/ja.json", "src/i18n/locales/ru.json", "src/i18n/locales/zh-CN.json", "src/i18n/locales/zh-Hant.json" @@ -1139,6 +1153,7 @@ "src/i18n/index.js", "src/i18n/locale.js", "src/i18n/locales/es.json", + "src/i18n/locales/ja.json", "src/i18n/locales/ru.json", "src/i18n/locales/zh-CN.json", "src/i18n/locales/zh-Hant.json", @@ -1170,6 +1185,7 @@ "src/i18n/index.js", "src/i18n/locale.js", "src/i18n/locales/es.json", + "src/i18n/locales/ja.json", "src/i18n/locales/ru.json", "src/i18n/locales/zh-CN.json", "src/i18n/locales/zh-Hant.json" @@ -1201,6 +1217,7 @@ "src/i18n/index.js", "src/i18n/locale.js", "src/i18n/locales/es.json", + "src/i18n/locales/ja.json", "src/i18n/locales/ru.json", "src/i18n/locales/zh-CN.json", "src/i18n/locales/zh-Hant.json", @@ -1235,6 +1252,7 @@ "src/i18n/index.js", "src/i18n/locale.js", "src/i18n/locales/es.json", + "src/i18n/locales/ja.json", "src/i18n/locales/ru.json", "src/i18n/locales/zh-CN.json", "src/i18n/locales/zh-Hant.json" @@ -1278,6 +1296,7 @@ "src/i18n/index.js", "src/i18n/locale.js", "src/i18n/locales/es.json", + "src/i18n/locales/ja.json", "src/i18n/locales/ru.json", "src/i18n/locales/zh-CN.json", "src/i18n/locales/zh-Hant.json", @@ -1315,6 +1334,7 @@ "src/i18n/index.js", "src/i18n/locale.js", "src/i18n/locales/es.json", + "src/i18n/locales/ja.json", "src/i18n/locales/ru.json", "src/i18n/locales/zh-CN.json", "src/i18n/locales/zh-Hant.json", @@ -1366,6 +1386,7 @@ "src/i18n/index.js", "src/i18n/locale.js", "src/i18n/locales/es.json", + "src/i18n/locales/ja.json", "src/i18n/locales/ru.json", "src/i18n/locales/zh-CN.json", "src/i18n/locales/zh-Hant.json" @@ -1396,6 +1417,7 @@ "src/i18n/index.js", "src/i18n/locale.js", "src/i18n/locales/es.json", + "src/i18n/locales/ja.json", "src/i18n/locales/ru.json", "src/i18n/locales/zh-CN.json", "src/i18n/locales/zh-Hant.json" @@ -1445,6 +1467,7 @@ "src/i18n/index.js", "src/i18n/locale.js", "src/i18n/locales/es.json", + "src/i18n/locales/ja.json", "src/i18n/locales/ru.json", "src/i18n/locales/zh-CN.json", "src/i18n/locales/zh-Hant.json" @@ -1509,6 +1532,7 @@ "src/i18n/index.js", "src/i18n/locale.js", "src/i18n/locales/es.json", + "src/i18n/locales/ja.json", "src/i18n/locales/ru.json", "src/i18n/locales/zh-CN.json", "src/i18n/locales/zh-Hant.json", @@ -1539,6 +1563,7 @@ "src/i18n/index.js", "src/i18n/locale.js", "src/i18n/locales/es.json", + "src/i18n/locales/ja.json", "src/i18n/locales/ru.json", "src/i18n/locales/zh-CN.json", "src/i18n/locales/zh-Hant.json" @@ -1580,6 +1605,7 @@ "src/i18n/index.js", "src/i18n/locale.js", "src/i18n/locales/es.json", + "src/i18n/locales/ja.json", "src/i18n/locales/ru.json", "src/i18n/locales/zh-CN.json", "src/i18n/locales/zh-Hant.json" @@ -1603,6 +1629,7 @@ "src/i18n/index.js", "src/i18n/locale.js", "src/i18n/locales/es.json", + "src/i18n/locales/ja.json", "src/i18n/locales/ru.json", "src/i18n/locales/zh-CN.json", "src/i18n/locales/zh-Hant.json" @@ -1660,6 +1687,7 @@ "src/i18n/index.js", "src/i18n/locale.js", "src/i18n/locales/es.json", + "src/i18n/locales/ja.json", "src/i18n/locales/ru.json", "src/i18n/locales/zh-CN.json", "src/i18n/locales/zh-Hant.json" @@ -1723,6 +1751,7 @@ "src/i18n/index.js", "src/i18n/locale.js", "src/i18n/locales/es.json", + "src/i18n/locales/ja.json", "src/i18n/locales/ru.json", "src/i18n/locales/zh-CN.json", "src/i18n/locales/zh-Hant.json", @@ -2606,6 +2635,7 @@ "src/i18n/index.js", "src/i18n/locale.js", "src/i18n/locales/es.json", + "src/i18n/locales/ja.json", "src/i18n/locales/ru.json", "src/i18n/locales/zh-CN.json", "src/i18n/locales/zh-Hant.json", @@ -3191,6 +3221,7 @@ "src/i18n/index.js", "src/i18n/locale.js", "src/i18n/locales/es.json", + "src/i18n/locales/ja.json", "src/i18n/locales/ru.json", "src/i18n/locales/zh-CN.json", "src/i18n/locales/zh-Hant.json", @@ -3302,6 +3333,7 @@ "src/data/cameraArrival.js", "src/i18n/locale.js", "src/i18n/locales/es.json", + "src/i18n/locales/ja.json", "src/i18n/locales/ru.json", "src/i18n/locales/zh-CN.json", "src/i18n/locales/zh-Hant.json", @@ -3326,6 +3358,7 @@ "src/i18n/index.js", "src/i18n/locale.js", "src/i18n/locales/es.json", + "src/i18n/locales/ja.json", "src/i18n/locales/ru.json", "src/i18n/locales/zh-CN.json", "src/i18n/locales/zh-Hant.json" @@ -3363,6 +3396,7 @@ "src/i18n/index.js", "src/i18n/locale.js", "src/i18n/locales/es.json", + "src/i18n/locales/ja.json", "src/i18n/locales/ru.json", "src/i18n/locales/zh-CN.json", "src/i18n/locales/zh-Hant.json", @@ -3390,6 +3424,7 @@ "src/i18n/index.js", "src/i18n/locale.js", "src/i18n/locales/es.json", + "src/i18n/locales/ja.json", "src/i18n/locales/ru.json", "src/i18n/locales/zh-CN.json", "src/i18n/locales/zh-Hant.json" @@ -3482,6 +3517,7 @@ "src/i18n/index.js", "src/i18n/locale.js", "src/i18n/locales/es.json", + "src/i18n/locales/ja.json", "src/i18n/locales/ru.json", "src/i18n/locales/zh-CN.json", "src/i18n/locales/zh-Hant.json", @@ -3538,6 +3574,7 @@ "src/i18n/index.js", "src/i18n/locale.js", "src/i18n/locales/es.json", + "src/i18n/locales/ja.json", "src/i18n/locales/ru.json", "src/i18n/locales/zh-CN.json", "src/i18n/locales/zh-Hant.json", @@ -3793,6 +3830,7 @@ "src/i18n/index.js", "src/i18n/locale.js", "src/i18n/locales/es.json", + "src/i18n/locales/ja.json", "src/i18n/locales/ru.json", "src/i18n/locales/zh-CN.json", "src/i18n/locales/zh-Hant.json" @@ -3837,6 +3875,7 @@ "src/i18n/index.js", "src/i18n/locale.js", "src/i18n/locales/es.json", + "src/i18n/locales/ja.json", "src/i18n/locales/ru.json", "src/i18n/locales/zh-CN.json", "src/i18n/locales/zh-Hant.json" @@ -3891,6 +3930,7 @@ "src/i18n/index.js", "src/i18n/locale.js", "src/i18n/locales/es.json", + "src/i18n/locales/ja.json", "src/i18n/locales/ru.json", "src/i18n/locales/zh-CN.json", "src/i18n/locales/zh-Hant.json" @@ -3908,6 +3948,7 @@ "src/i18n/index.js", "src/i18n/locale.js", "src/i18n/locales/es.json", + "src/i18n/locales/ja.json", "src/i18n/locales/ru.json", "src/i18n/locales/zh-CN.json", "src/i18n/locales/zh-Hant.json", @@ -3968,6 +4009,7 @@ "src/i18n/index.js", "src/i18n/locale.js", "src/i18n/locales/es.json", + "src/i18n/locales/ja.json", "src/i18n/locales/ru.json", "src/i18n/locales/zh-CN.json", "src/i18n/locales/zh-Hant.json", @@ -4165,6 +4207,7 @@ "src/i18n/index.js", "src/i18n/locale.js", "src/i18n/locales/es.json", + "src/i18n/locales/ja.json", "src/i18n/locales/ru.json", "src/i18n/locales/zh-CN.json", "src/i18n/locales/zh-Hant.json", diff --git a/src/data/directions.test.mjs b/src/data/directions.test.mjs index bf6e2878e..38bada296 100644 --- a/src/data/directions.test.mjs +++ b/src/data/directions.test.mjs @@ -875,6 +875,13 @@ test('route numbers follow the page language and never break from their unit', ( ); const list = directionsStepList({ route }); assert.equal(list.items[1].lead, '240\u00a0м'); + + // Japanese unit words follow the number: 1時間5分, but 1.5 km. + setLocale('ja'); + assert.equal(routeDistanceText(1500), '1.5\u00a0km'); + assert.equal(routeDurationText(39), '39秒'); + assert.equal(routeDurationText(3900), '1時間5分'); + assert.equal(routeDurationText(7200), '2時間'); }); test('ramp and lane wording stays localized after choosing the maneuver form', (t) => { @@ -892,6 +899,12 @@ test('ramp and lane wording stays localized after choosing the maneuver form', ( 'Toma la salida bruscamente a la derecha', 'Toma el carril izquierdo', ], + [ + 'ja', + 'ランプを斜め左に進んでI-95に入る', + '出口を急角度で右に出る', + '左車線を通行', + ], [ 'zh-CN', '向左前方驶入匝道,进入 I-95', diff --git a/src/i18n/i18n.test.mjs b/src/i18n/i18n.test.mjs index 1b421f2ff..2a3dcd39b 100644 --- a/src/i18n/i18n.test.mjs +++ b/src/i18n/i18n.test.mjs @@ -5,6 +5,7 @@ import { applyDocumentTranslations, formatDate, formatNumber, + formatRelativeTime, msg, persistLocaleAndReload, setLocale, @@ -35,6 +36,9 @@ test('normalizeLocale folds regional variants and rejects unshipped tags', () => assert.equal(normalizeLocale(' RU '), 'ru'); assert.equal(normalizeLocale('en_GB'), 'en'); assert.equal(normalizeLocale('xx'), null); + assert.equal(normalizeLocale('ja'), 'ja'); + assert.equal(normalizeLocale('ja-JP'), 'ja'); + assert.equal(normalizeLocale('JA_jp'), 'ja'); // Explicit script tags take precedence over regional defaults. assert.equal(normalizeLocale('zh'), 'zh-CN'); assert.equal(normalizeLocale('zh-CN'), 'zh-CN'); @@ -164,7 +168,13 @@ test('Intl formatters follow the active locale', () => { assert.equal(formatNumber(1234.5), '1,234.5'); setLocale('ru'); assert.equal(formatDate(date, options), '15 января 2026 г.'); + assert.equal(formatRelativeTime(-5, 'minute'), '5 минут назад'); assert.equal(formatNumber(1234.5), '1 234,5'); + // Japanese keeps a number and its unit together, as the catalog does. + setLocale('ja'); + assert.equal(formatDate(date, options), '2026年1月15日'); + assert.equal(formatRelativeTime(-5, 'minute'), '5分前'); + assert.equal(formatRelativeTime(-3, 'day'), '3日前'); }); function fakeElement({ text = '', attributes = {} } = {}) { diff --git a/src/i18n/index.js b/src/i18n/index.js index 6fc4becc9..40814f3a3 100644 --- a/src/i18n/index.js +++ b/src/i18n/index.js @@ -17,11 +17,18 @@ import { writeStoredLocale, } from './locale.js'; import es from './locales/es.json' with { type: 'json' }; +import ja from './locales/ja.json' with { type: 'json' }; import ru from './locales/ru.json' with { type: 'json' }; import zhCN from './locales/zh-CN.json' with { type: 'json' }; import zhHant from './locales/zh-Hant.json' with { type: 'json' }; -const CATALOGS = Object.freeze({ es, ru, 'zh-CN': zhCN, 'zh-Hant': zhHant }); +const CATALOGS = Object.freeze({ + es, + ja, + ru, + 'zh-CN': zhCN, + 'zh-Hant': zhHant, +}); let currentLocale = DEFAULT_LOCALE; @@ -201,13 +208,19 @@ export function formatUtcDayMonth(value) { /** * Locale-aware relative time (Intl.RelativeTimeFormat), e.g. - * formatRelativeTime(-5, 'minute') → '5 minutes ago' / '5 минут назад'. + * formatRelativeTime(-5, 'minute') → '5 minutes ago' / '5 минут назад' / + * '5分前'. */ export function formatRelativeTime(value, unit = 'second', options) { - return cachedFormatter('relative', Intl.RelativeTimeFormat, { + const text = cachedFormatter('relative', Intl.RelativeTimeFormat, { numeric: 'auto', ...options, }).format(value, unit); + // CLDR spaces Japanese (5 分前); the ja catalog writes the number and its + // unit together (5分前), so the two must not differ on one screen. + return currentLocale === 'ja' + ? text.replace(/(?<=\d) (?=\p{Script=Han})/gu, '') + : text; } /** Collapse markup whitespace so a message reads the same in HTML and JS. */ diff --git a/src/i18n/locale.js b/src/i18n/locale.js index 55ed71163..26bd4abc8 100644 --- a/src/i18n/locale.js +++ b/src/i18n/locale.js @@ -8,12 +8,20 @@ export const LOCALE_STORAGE_KEY = 'gev:locale:v1'; export const DEFAULT_LOCALE = 'en'; /** Shipped locales; order does not matter. Adding one: docs/TRANSLATORS.md. */ -export const LOCALES = Object.freeze(['en', 'es', 'ru', 'zh-CN', 'zh-Hant']); +export const LOCALES = Object.freeze([ + 'en', + 'es', + 'ja', + 'ru', + 'zh-CN', + 'zh-Hant', +]); /** Each locale named in its own language, for the selector. */ export const LOCALE_NAMES = Object.freeze({ en: 'English', es: 'Español', + ja: '日本語', ru: 'Русский', 'zh-CN': '中文(简体)', 'zh-Hant': '中文(繁體)', @@ -23,7 +31,7 @@ export const LOCALE_NAMES = Object.freeze({ const RTL_LOCALES = Object.freeze([]); /** - * Map any language tag to a shipped locale: 'ru-RU' and 'RU' → 'ru', + * Map any language tag to a shipped locale: 'ru-RU' and 'RU' → 'ru', 'ja-JP' → 'ja', * 'zh', 'zh-CN' and 'zh-Hans-SG' → 'zh-CN'; * 'zh-Hant', 'zh-TW', 'zh-HK' and 'zh-MO' → 'zh-Hant'. * @returns {string|null} diff --git a/src/layers/directions/index.js b/src/layers/directions/index.js index b8cceff02..1d5c100ae 100644 --- a/src/layers/directions/index.js +++ b/src/layers/directions/index.js @@ -20,7 +20,11 @@ import * as Cesium from 'cesium'; import { roadLabel } from '../../data/routeSteps.js'; import { t, msg, formatNumber, translateKnown } from '../../i18n/index.js'; import { pointerOwnerName } from '../../data/pointerOwnerNames.js'; -import { formatQuantity } from '../../ui/unitLabels.js'; +import { + formatQuantity, + quantitySeparator, + unitLabel, +} from '../../ui/unitLabels.js'; export const DIRECTIONS_STEP_OVERLAY_SOURCE_ID = 'directions-step'; export const DIRECTIONS_STEP_OVERLAY_SOURCE_OPTIONS = Object.freeze({ @@ -137,7 +141,9 @@ export function routeDurationText(seconds) { if (minutes < 60) return formatQuantity(minutes, 'min'); const hours = formatQuantity(Math.floor(minutes / 60), 'h'); const rest = minutes % 60; - return rest ? `${hours}\u00a0${formatQuantity(rest, 'min')}` : hours; + if (!rest) return hours; + // "1 h 5 min"; Japanese runs the parts together: 1時間5分. + return `${hours}${quantitySeparator(unitLabel('h'))}${formatQuantity(rest, 'min')}`; } /** "left", "slightly right", … as it reads inside a maneuver sentence. */ diff --git a/src/ui/localePicker.test.mjs b/src/ui/localePicker.test.mjs index 057642827..8f9f127e2 100644 --- a/src/ui/localePicker.test.mjs +++ b/src/ui/localePicker.test.mjs @@ -40,7 +40,7 @@ test('the current language comes first, the rest by their own names', () => { nativeNames: LOCALE_NAMES, }), ), - ['ru', 'en', 'es', 'zh-CN', 'zh-Hant'], + ['ru', 'en', 'es', 'zh-CN', 'zh-Hant', 'ja'], ); assert.deepEqual( codes( @@ -50,7 +50,7 @@ test('the current language comes first, the rest by their own names', () => { nativeNames: LOCALE_NAMES, }), ), - ['es', 'en', 'ru', 'zh-CN', 'zh-Hant'], + ['es', 'en', 'ru', 'zh-CN', 'zh-Hant', 'ja'], ); assert.deepEqual( codes( @@ -60,7 +60,7 @@ test('the current language comes first, the rest by their own names', () => { nativeNames: LOCALE_NAMES, }), ), - ['en', 'es', 'ru', 'zh-CN', 'zh-Hant'], + ['en', 'es', 'ru', 'zh-CN', 'zh-Hant', 'ja'], ); const rows = buildLocaleOptions({ locales: MANY, @@ -263,7 +263,7 @@ test('keyboard model: open on the current language, move, choose, close', () => assert.deepEqual(model.keydown({ key: 'ArrowDown' }), { handled: true }); assert.equal(model.activeOption.code, 'en'); model.keydown({ key: 'End' }); - assert.equal(model.activeOption.code, 'zh-Hant'); + assert.equal(model.activeOption.code, 'ja'); model.keydown({ key: 'Home' }); assert.equal(model.activeOption.code, 'ru'); model.keydown({ key: 'ArrowUp' }); diff --git a/src/ui/unitLabels.js b/src/ui/unitLabels.js index 1d9bd6a61..3b12da006 100644 --- a/src/ui/unitLabels.js +++ b/src/ui/unitLabels.js @@ -1,4 +1,4 @@ -import { formatNumber, msg, t } from '../i18n/index.js'; +import { formatNumber, getLocale, msg, t } from '../i18n/index.js'; // Unit ids stay English in data, params and AI-tool readings; only the label // shown on the page is translated. dBZ and °C read the same in every language. @@ -23,6 +23,17 @@ export function unitLabel(unit) { return Object.hasOwn(UNIT_LABELS, unit) ? t(UNIT_LABELS[unit]) : unit || ''; } +/** + * What goes between a number and its unit label: a no-break space, except + * before a Japanese unit word, which follows the number directly (5分, 1時間). + */ +export function quantitySeparator(label) { + return getLocale() === 'ja' && + /^[\p{Script=Han}\p{Script=Hiragana}\p{Script=Katakana}]/u.test(label) + ? '' + : '\u00a0'; +} + /** * A number and its unit that never break apart: "22,0 км/ч". Readings carry * no digit grouping ("1008 hPa"), as on weather charts. @@ -30,7 +41,7 @@ export function unitLabel(unit) { export function formatQuantity(value, unit, options) { const label = unitLabel(unit); const number = formatNumber(value, { useGrouping: false, ...options }); - return label ? `${number}\u00a0${label}` : number; + return label ? `${number}${quantitySeparator(label)}${label}` : number; } /** diff --git a/src/ui/unitLabels.test.mjs b/src/ui/unitLabels.test.mjs index c0b1932b1..14b6030e3 100644 --- a/src/ui/unitLabels.test.mjs +++ b/src/ui/unitLabels.test.mjs @@ -44,3 +44,14 @@ test('other languages get their decimal separator and no digit grouping', () => setLocale('en'); } }); + +test('Japanese unit words follow the number directly; symbols keep the space', () => { + try { + setLocale('ja'); + assert.equal(formatQuantity(5, 'min'), '5分'); + assert.equal(formatQuantity(1, 'h'), '1時間'); + assert.equal(formatQuantity(95, 'kt'), '95\u00a0kt'); + } finally { + setLocale('en'); + } +}); From 402f56958f158f26be2dd76a48055fdbb56a2ee2 Mon Sep 17 00:00:00 2001 From: German Khokhlov Date: Wed, 28 Oct 2026 13:00:07 +0400 Subject: [PATCH 14/83] i18n(fr): translate the rest of the French catalog MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Translate the remaining 1,865 strings: aviation, maritime (AIS), weather and remote-sensing terms, radio, routing, scenes, voice and setup. - Review the 862 entries from #907: LIVE becomes DIRECT / en direct, stale becomes obsolète, FIRMS detections are feux actifs, replay is rejeu, the AIS ship types use the French terms (PILOTINE, SERVITUDE, POLICE), keys stay Space / Esc / Enter as docs/TRANSLATORS.md asks, and NEXT/PREVIOUS chips match PREV (SUIV. / PRÉC.). - French typography: narrow no-break space before : ; ? ! and %, inside « », and … for ellipsis; plural entries get the many form (exact millions, "de"). - same-as-english.json: codes, units, genre and product names that French spells the same as English. Co-Authored-By: Claude Opus 5.5 --- src/i18n/locales/fr.json | 2392 +++++++++++++++++++++++++++++++-- src/i18n/same-as-english.json | 179 +++ 2 files changed, 2435 insertions(+), 136 deletions(-) diff --git a/src/i18n/locales/fr.json b/src/i18n/locales/fr.json index 0c6deba4e..98c618a22 100644 --- a/src/i18n/locales/fr.json +++ b/src/i18n/locales/fr.json @@ -1,30 +1,271 @@ { - "Flying to Austin, TX...": "Vol vers Austin, TX...", - "Restoring shared view...": "Restauration de la vue partagée...", - "Configuring viewer...": "Configuration de la vue...", - "Loading Google 3D Tiles...": "Chargement de Google 3D Tiles...", - "Loading the keyless globe...": "Chargement du globe sans clé...", - "Google 3D Tiles unavailable ({detail}). Loading the keyless globe...": "Google 3D Tiles indisponible ({detail}). Chargement du globe sans clé...", - "Initializing systems...": "Initialisation des systèmes...", + "Pick a shape, then click the map.": "Choisissez une forme, puis cliquez sur la carte.", + "Enter to place the pin, Esc to cancel.": "Enter pour poser l'épingle, Esc pour annuler.", + "Click where the pin goes.": "Cliquez à l'endroit où poser l'épingle.", + "Click {count} more points.": { + "one": "Cliquez encore {count} point.", + "many": "Cliquez encore {count} de points.", + "other": "Cliquez encore {count} points." + }, + "Those points are in a line — move one off it to enclose an area.": "Ces points sont alignés — déplacez-en un hors de la ligne pour délimiter une zone.", + "That line has no length — click somewhere further away.": "Cette ligne n'a pas de longueur — cliquez plus loin.", + " · {max}-point limit reached": " · limite de {max} points atteinte", + "{measure} · double-click or Enter to finish, Backspace undoes, Esc cancels.{full}": "{measure} · double-clic ou Enter pour terminer, Backspace annule le dernier point, Esc annule.{full}", + "drawings on the map": "les dessins sur la carte", + "That shape already has {count} points — finish it or press Backspace.": "Cette forme a déjà {count} points — terminez-la ou appuyez sur Backspace.", + "That point is off the globe — click on the world.": "Ce point est hors du globe — cliquez sur la Terre.", + "That shape could not be placed.": "Impossible de placer cette forme.", + "Could not place the shape: {error}": "Impossible de placer la forme : {error}", + "Board cleared.": "Tableau effacé.", + "{owner} is using the pointer — close it first.": "Pointeur utilisé par : {owner}. Fermez-le d'abord.", + "{label} · Detailed outline unavailable": "{label} · Contour détaillé indisponible", + "Flying to Austin, TX...": "En route vers Austin, Texas…", + "Restoring shared view...": "Restauration de la vue partagée…", + "Configuring viewer...": "Configuration de la vue…", + "Loading Google 3D Tiles...": "Chargement de Google 3D Tiles…", + "Loading the keyless globe...": "Chargement du globe sans clé…", + "Google 3D Tiles unavailable ({detail}). Loading the keyless globe...": "Google 3D Tiles indisponible ({detail}). Chargement du globe sans clé…", + "Initializing systems...": "Initialisation des systèmes…", + "Space Missions isolates replay data. Exit the mode to enable {layer}.": "Le mode Missions spatiales isole les données de rejeu. Quittez-le pour activer {layer}.", + "Data attribution": "Attribution des données", + "Data provided by:": "Données fournies par :", "Close data attribution": "Fermer l'attribution des données", + "Light aircraft": "Avion léger", + "Glider": "Planeur", + "Turboprop": "Turbopropulseur", + "Airliner": "Avion de ligne", + "Widebody": "Gros-porteur", + "Four-engine jet": "Quadriréacteur", + "Helicopter": "Hélicoptère", + "Fast jet": "Avion de chasse", + "Business jet": "Jet d'affaires", + "Drone": "Drone", + "General emergency": "Urgence générale", + "Unlawful interference": "Intervention illicite", + "Radio failure": "Panne radio", + "Downed aircraft": "Aéronef abattu", + "Minimum fuel": "Carburant minimum", + "Lifeguard (medical priority)": "Lifeguard (priorité médicale)", + "Rasuwagadhi witness video": "Vidéo d'un témoin à Rasuwagadhi", + "Bhote Koshi valley footage": "Images de la vallée de la Bhote Koshi", + "Flood footage": "Images de la crue", + "Compilation and casualty claims": "Compilation et bilans de victimes non vérifiés", + "SOURCE GEOCONFIRMED · WORLD-PINNED": "SOURCE GÉOCONFIRMÉE · ÉPINGLÉE SUR LA CARTE", + "SOURCE CREDITED · LOCATION UNRESOLVED": "SOURCE CRÉDITÉE · LIEU NON DÉTERMINÉ", + "REFERENCE ONLY · CLAIMS UNVERIFIED": "RÉFÉRENCE SEULEMENT · AFFIRMATIONS NON VÉRIFIÉES", + "SOURCE GEOCONFIRMED": "SOURCE GÉOCONFIRMÉE", + "2021 historical reference versus 2026 post-event imagery; changes are cumulative and include the July 2025 Rasuwagadhi flood. Schematic downstream progression, not modeled arrival time; not an official hazard model.": "Référence historique de 2021 comparée aux images postérieures à l'événement de 2026 ; les changements sont cumulés et incluent la crue de Rasuwagadhi de juillet 2025. Progression schématique vers l'aval, pas une heure d'arrivée modélisée ; ce n'est pas un modèle officiel d'aléa.", + "Immediate collapse viewpoint": "Point de vue au pied de l'effondrement", + "Collapse viewpoint": "Vue de l'effondrement", + "Debris-dammed lake": "Lac de barrage formé par les débris", + "Dammed lake": "Lac de barrage", + "Second landslide": "Second glissement de terrain", + "Gyirong border gate": "Poste frontière de Gyirong", + "Border gate": "Poste frontière", + "Timure evidence cluster": "Groupe d'éléments de preuve de Timure", + "Mailung / Upper Trishuli bridge": "Mailung / pont d'Upper Trishuli", + "Dandagaun viewpoint restaurant": "Restaurant-belvédère de Dandagaun", + "Dandagaun viewpoint": "Belvédère de Dandagaun", + "Bidur - Trishuli bridge": "Pont Bidur - Trishuli", + "Bidur bridge": "Pont de Bidur", + "Devighat / Taadi Khola Bridge": "Devighat / pont de la Taadi Khola", + "Devighat bridge": "Pont de Devighat", + "Facebook player API did not initialize.": "L'API du lecteur Facebook ne s'est pas initialisée.", + "Facebook player API could not load.": "Impossible de charger l'API du lecteur Facebook.", + "Facebook player API timed out.": "Délai dépassé pour l'API du lecteur Facebook.", + "X embed API did not initialize.": "L'API d'intégration X ne s'est pas initialisée.", + "X embed could not load.": "Impossible de charger l'intégration X.", + "X embed timed out.": "Délai dépassé pour l'intégration X.", "UNAVAILABLE": "INDISPONIBLE", + "TIMEOUT": "DÉLAI DÉPASSÉ", + "BLOCKED": "BLOQUÉ", "SOURCE": "SOURCE", - "Overpass rate-limited": "Overpass limite le débit", + "Facebook embed unavailable. The post may be private, removed, region-restricted, or blocked.": "Intégration Facebook indisponible. La publication est peut-être privée, supprimée, restreinte dans votre région ou bloquée.", + "Preloading {provider} media": "Préchargement du média {provider}", + "LOADING X POST…": "CHARGEMENT DU POST X…", + "The X post is unavailable or cannot be embedded.": "Le post X est indisponible ou ne peut pas être intégré.", + "X POST · PROVIDER CONTROLS": "POST X · COMMANDES DU FOURNISSEUR", + "{reason} OPEN ORIGINAL.": "{reason} OUVREZ L'ORIGINAL.", + "X embed unavailable": "Intégration X indisponible", + "FACEBOOK · PROVIDER CONTROLS": "FACEBOOK · COMMANDES DU FOURNISSEUR", + "Facebook embed unavailable": "Intégration Facebook indisponible", + "AUTOPLAY BLOCKED · USE PROVIDER CONTROLS": "LECTURE AUTO BLOQUÉE · UTILISEZ LES COMMANDES DU FOURNISSEUR", + "Embedded {provider} media for {source}": "Média {provider} intégré pour {source}", + "witness source": "source témoin", + "Witness source": "Source témoin", + "{provider} · EMBEDDED SOURCE": "{provider} · SOURCE INTÉGRÉE", + "OPEN ORIGINAL ↗": "OUVRIR L'ORIGINAL ↗", + "{provider} media: {source}": "Média {provider} : {source}", + "{provider} · PROVIDER CONTROLS": "{provider} · COMMANDES DU FOURNISSEUR", + "YOUTUBE {state} · OPEN ORIGINAL": "YOUTUBE {state} · OUVRIR L'ORIGINAL", + "INITIATION": "DÉCLENCHEMENT", + "DAMMING": "OBSTRUCTION", + "SECONDARY FAILURE": "RUPTURE SECONDAIRE", + "BORDER ARRIVAL": "ARRIVÉE À LA FRONTIÈRE", + "PROPAGATION": "PROPAGATION", + "DOWNSTREAM PASSAGE": "PASSAGE EN AVAL", + "CONSEQUENCE": "CONSÉQUENCES", + "DOWNSTREAM CONSEQUENCE": "CONSÉQUENCES EN AVAL", + "EVIDENCE": "PREUVES", + "{year} HISTORICAL REFERENCE": "RÉFÉRENCE HISTORIQUE {year}", + "{year} POST-EVENT": "APRÈS L'ÉVÉNEMENT {year}", + "{count} GEOLOCATED SOURCE-MAP PLACEMENTS": { + "one": "{count} EMPLACEMENT GÉOLOCALISÉ SUR LA CARTE DES SOURCES", + "many": "{count} D'EMPLACEMENTS GÉOLOCALISÉS SUR LA CARTE DES SOURCES", + "other": "{count} EMPLACEMENTS GÉOLOCALISÉS SUR LA CARTE DES SOURCES" + }, + "NO PREVIEW": "PAS D'APERÇU", + "YouTube source": "Source YouTube", + "Facebook source": "Source Facebook", + "SOURCE LINK": "LIEN DE LA SOURCE", + "{publisher} / OPEN": "{publisher} / OUVRIR", + "Bhote Koshi flood reconstruction controls": "Commandes de la reconstitution de la crue de la Bhote Koshi", + "EVENT RECONSTRUCTION · 26 AUG 2026": "RECONSTITUTION DE L'ÉVÉNEMENT · 26 AOÛT 2026", + "BHOTE KOSHI OUTBURST FLOOD": "CRUE PAR VIDANGE BRUTALE DE LA BHOTE KOSHI", + "Close event layer": "Fermer la couche de l'événement", + "OBSERVED IMAGERY": "IMAGERIE OBSERVÉE", + "SCHEMATIC CORRIDOR": "CORRIDOR SCHÉMATIQUE", + "2021 HISTORICAL REFERENCE / 2026 POST-EVENT": "RÉF. HISTORIQUE 2021 / APRÈS L'ÉVÉNEMENT 2026", + "Historical reference and post-event image split": "Comparaison entre l'image de référence historique et l'image postérieure à l'événement", + "RECONSTRUCTION CLOCK": "HORLOGE DE LA RECONSTITUTION", + "Schematic downstream progression": "Progression schématique vers l'aval", + "Story beat navigation": "Navigation entre les étapes du récit", + "Previous story beat": "Étape précédente du récit", + "CAUSE": "CAUSE", + "CAPTURE TIME UNVERIFIED": "HEURE DE PRISE DE VUE NON VÉRIFIÉE", + "Next story beat": "Étape suivante du récit", + "▶ PLAY": "▶ LIRE", + "Play the next shot and continue through this scene": "Lire le plan suivant et poursuivre la scène", + "▶ PLAY SCENE": "▶ LIRE LA SCÈNE", + "◉ CINEMATIC": "◉ CINÉMATIQUE", + "↺ FULL STORY": "↺ RÉCIT COMPLET", + "↗ OPEN ORIGINAL": "↗ OUVRIR L'ORIGINAL", + "⌖ LOWER GORGE": "⌖ GORGE INFÉRIEURE", + "FIELD REPORTS · {count}": "RAPPORTS DE TERRAIN · {count}", + "GEOLOCATIONS · {credit}": "GÉOLOCALISATIONS · {credit}", + "↗ OPEN PUBLIC MAP": "↗ OUVRIR LA CARTE PUBLIQUE", + " Clouds are preserved from the source imagery.": " Les nuages proviennent de l'imagerie source.", + "Rasuwagadhi witness": "Témoin de Rasuwagadhi", + "Open original source for {source}; capture time unverified": "Ouvrir la source originale de {source} ; heure de prise de vue non vérifiée", + "Historical reference and post-event image divider": "Séparateur entre l'image de référence historique et l'image postérieure à l'événement", + "A historical reference {before} percent, B post-event {after} percent": "A, référence historique, {before} pour cent ; B, après l'événement, {after} pour cent", + "■ RELEASE CAMERA": "■ LIBÉRER LA CAMÉRA", + "Seek Nepal scene clock": "Parcourir l'horloge de la scène du Népal", + "NEPAL SCENE CLOCK": "HORLOGE DE LA SCÈNE DU NÉPAL", + "… PLAYING SHOT": "… LECTURE DU PLAN", + "▶ PLAY SHOT": "▶ LIRE LE PLAN", + "Ⅱ PAUSE": "Ⅱ PAUSE", + "↺ REPLAY CINEMATIC": "↺ REVOIR LA CINÉMATIQUE", + "↺ REPLAY": "↺ REVOIR", + "… PLAYING SCENE": "… LECTURE DE LA SCÈNE", + "Continue {scene} from next shot": "Reprendre {scene} au plan suivant", + "current scene": "la scène actuelle", + "Replay the full reconstruction": "Revoir toute la reconstitution", + "SCENE SHOT": "PLAN DE SCÈNE", + "TIME UNVERIFIED": "HEURE NON VÉRIFIÉE", + "{count} SOURCES": { + "one": "{count} SOURCE", + "many": "{count} DE SOURCES", + "other": "{count} SOURCES" + }, + "OUTSIDE IMAGERY SWIPE": "HORS DE LA COMPARAISON D'IMAGES", + "{scene} / AUTHORED SHOT": "{scene} / PLAN CONÇU", + "NEPAL FLOOD INCIDENT": "CRUE AU NÉPAL", + "Play {shot}": "Lire {shot}", + "current scene shot": "le plan actuel de la scène", + "Play reconstruction": "Lire la reconstitution", + "Load previous scene shot": "Charger le plan précédent de la scène", + "Load next scene shot": "Charger le plan suivant de la scène", + "SCHEMATIC CORRIDOR, NOT MODELED ARRIVAL TIME.": "CORRIDOR SCHÉMATIQUE, PAS UNE HEURE D'ARRIVÉE MODÉLISÉE.", + "Rasuwa · 26 Aug 2026": "Rasuwa · 26 août 2026", + "Event reconstruction": "Reconstitution de l'événement", + "BHOTE KOSHI FLOOD INCIDENT": "CRUE DE LA BHOTE KOSHI", + "NEPAL · 26 AUG 2026": "NÉPAL · 26 AOÛT 2026", + "USGS INITIAL REPORT": "RAPPORT INITIAL DE L'USGS", + "26 AUG 2026 · 08:37 NPT": "26 AOÛT 2026 · 08:37 NPT", + "28.2710° N · 85.5150° E": "28,2710° N · 85,5150° E", + "INITIAL M4.4 · RECLASSIFIED M5.2 LANDSLIDE": "M4,4 INITIALE · RECLASSÉ EN GLISSEMENT DE TERRAIN M5,2", + "USGS EVENT us7000tbwb · OPEN SOURCE": "ÉVÉNEMENT USGS us7000tbwb · OUVRIR LA SOURCE", + "Open the USGS initial report for the 26 August 2026 Nepal landslide": "Ouvrir le rapport initial de l'USGS sur le glissement de terrain du 26 août 2026 au Népal", + "Show the Nepal context callout without a border or country fill": "Afficher l'encart de contexte du Népal sans frontière ni remplissage du pays", + "Introduce Nepal, draw its border, then reveal the Bhote Koshi incident": "Présenter le Népal, tracer sa frontière, puis révéler l'incident de la Bhote Koshi", + "CITIES": "VILLES", + "Keep the regional incident context and introduce nearby city labels": "Garder le contexte régional de l'incident et faire apparaître les noms des villes proches", + "PLACES": "LIEUX", + "Introduce the reconstruction scene key places from trigger to downstream": "Présenter les lieux clés de la reconstitution, du déclenchement jusqu'à l'aval", + "PATH": "TRACÉ", + "Animate the sourced cyan river-centerline route to Trishuli Bazaar": "Animer le tracé cyan sourcé de l'axe de la rivière jusqu'à Trishuli Bazaar", + "OVERVIEW": "VUE D'ENSEMBLE", + "Keep the completed flood path and location labels visible": "Garder visibles le tracé complet de la crue et les noms de lieux", + "RECORD": "RELEVÉ", + "Reveal the trigger record while making a slow camera approach": "Révéler le relevé du déclenchement pendant une lente approche de la caméra", + "{speed} kn": "{speed} nd", + "That file is not valid JSON.": "Ce fichier n'est pas un JSON valide.", + "That JSON file is not GeoJSON.": "Ce fichier JSON n'est pas du GeoJSON.", + "That FeatureCollection has no features list.": "Cette FeatureCollection n'a pas de liste features.", + "Every GeoJSON feature must have type Feature.": "Chaque entité GeoJSON doit être de type Feature.", + "That GeoJSON has invalid geometries.": "Ce GeoJSON contient des géométries non valides.", + "That GeoJSON contains an unsupported geometry.": "Ce GeoJSON contient une géométrie non prise en charge.", + "That GeoJSON has invalid coordinates.": "Ce GeoJSON contient des coordonnées non valides.", + "That file creates more than {limit} map objects (the limit).": "Ce fichier crée plus de {limit} objets sur la carte (la limite).", + "That file has more than {limit} style definitions and image links after cleanup (the limit).": "Après nettoyage, ce fichier contient plus de {limit} définitions de style et liens d'images (la limite).", + "That file has more than {limit} features (the limit).": "Ce fichier contient plus de {limit} entités (la limite).", + "That file has more than {limit} points (the limit) across {features} features.": "Ce fichier contient plus de {limit} points (la limite) répartis sur {features} entités.", + "That file has more than {limit} points (the limit).": "Ce fichier contient plus de {limit} points (la limite).", + "That KMZ unpacks to more than the import limit.": "Une fois décompressé, ce KMZ dépasse la limite d'importation.", + "That KMZ is damaged and could not be unpacked.": "Ce KMZ est endommagé et n'a pas pu être décompressé.", + "That KMZ is not a readable zip archive.": "Ce KMZ n'est pas une archive zip lisible.", + "That KMZ uses a zip format this import does not read.": "Ce KMZ utilise un format zip que cette importation ne lit pas.", + "That KMZ is encrypted.": "Ce KMZ est chiffré.", + "That KMZ uses a compression method this import does not read.": "Ce KMZ utilise une méthode de compression que cette importation ne lit pas.", + "That KML has invalid geometry bounds.": "Ce KML a des limites de géométrie non valides.", + "That KML has invalid coordinates.": "Ce KML contient des coordonnées non valides.", + "That GPX file has no document.": "Ce fichier GPX n'a pas de document .", + "That {format} file is not valid XML.": "Ce fichier {format} n'est pas un XML valide.", + "That file has an unreadable image or exceeds the 16-megapixel image limit.": "Ce fichier contient une image illisible ou dépasse la limite de 16 mégapixels par image.", + "That KML could not be read.": "Impossible de lire ce KML.", + "That file has invalid point coordinates.": "Ce fichier contient des coordonnées de points non valides.", + "Ground heights are not available for that file. Try again when the map has loaded.": "Les altitudes du sol ne sont pas disponibles pour ce fichier. Réessayez une fois la carte chargée.", + "That file took too long to read.": "La lecture de ce fichier a pris trop de temps.", + "Nothing to import.": "Rien à importer.", + "That file is larger than {size} MiB.": "Ce fichier dépasse {size} Mio.", + "Only GeoJSON, KML, KMZ and GPX files can be imported.": "Seuls les fichiers GeoJSON, KML, KMZ et GPX peuvent être importés.", + "That file has nothing to draw.": "Ce fichier ne contient rien à dessiner.", + "That KMZ holds no KML document.": "Ce KMZ ne contient aucun document KML.", + "That {format} file could not be read.": "Impossible de lire ce fichier {format}.", + "That file has {count} map objects; the limit is {limit}.": "Ce fichier contient {count} objets cartographiques ; la limite est de {limit}.", + "Ground heights could not be read. Try that file again.": "Impossible de lire les altitudes du sol. Réessayez avec ce fichier.", + "That file has invalid point graphics.": "Ce fichier contient des symboles de points non valides.", + "Overpass rate-limited": "Overpass : limite de requêtes atteinte", "Overpass timed out": "Délai Overpass dépassé", "Overpass could not complete the query": "Overpass n'a pas pu terminer la requête", + "Map tiles temporarily unavailable": "Tuiles de la carte temporairement indisponibles", + "Mapped names temporarily unavailable": "Noms cartographiés temporairement indisponibles", "Overpass temporarily unavailable": "Overpass temporairement indisponible", "Retrying mapped sites…": "Nouvel essai des sites cartographiés…", "Fetching mapped sites…": "Récupération des sites cartographiés…", - "{reason} — retrying in {seconds}s": "{reason} — nouvel essai dans {seconds}s", + "{reason} — retrying in {seconds}s": "{reason} — nouvel essai dans {seconds} s", "{reason} — retry pending": "{reason} — nouvel essai en attente", - "Zoom in to search mapped installations": "Zoomez pour chercher les installations cartographiées", + "Zoom in to search mapped installations": "Zoomez pour rechercher les installations cartographiées", "Showing cached mapped sites": "Sites cartographiés en cache affichés", "Mapped sites not loaded": "Sites cartographiés non chargés", "Mapped sites loaded": "Sites cartographiés chargés", + "Military airfield": "Aérodrome militaire", + "Naval base": "Base navale", + "Firing range": "Champ de tir", + "Military land": "Terrain militaire", + "Mapped installation": "Installation cartographiée", + "Military area": "Zone militaire", + "flight": "vol", + "military flight": "vol militaire", + "satellite": "satellite", "feed unavailable": "flux indisponible", - "feed stale": "flux périmé", + "feed stale": "flux obsolète", "observed or mapped nearby context": "contexte observé ou cartographié à proximité", "no observed or mapped objects in current feeds": "aucun objet observé ou cartographié dans les flux actuels", + "Draw": "Dessin", + "Directions": "Itinéraire", + "Recent imagery": "Imagerie récente", "STATION": "STATION", "Crewed stations and their visiting vehicles": "Stations habitées et leurs véhicules visiteurs", "NAV": "NAV", @@ -33,8 +274,8 @@ "Geostationary belt — comms and weather, fixed over the equator": "Ceinture géostationnaire — télécoms et météo, fixes au-dessus de l'équateur", "VISUAL": "VISUEL", "Brightest naked-eye objects — CelesTrak visual group": "Objets les plus brillants à l'œil nu — groupe visuel CelesTrak", - "COMMS": "COMMS", - "Broadband constellation shell — shown only in DENSE mode": "Constellation haut débit — affichée uniquement en mode DENSE", + "COMMS": "TÉLÉCOM", + "Broadband constellation shell — shown only in DENSE mode": "Couche de la constellation haut débit — affichée uniquement en mode DENSE", "FISHING": "PÊCHE", "TOWING": "REMORQUAGE", "DREDGER": "DRAGUE", @@ -42,64 +283,209 @@ "MILITARY": "MILITAIRE", "SAILING": "VOILIER", "PLEASURE": "PLAISANCE", - "PILOT": "PILOTE", + "PILOT": "PILOTINE", "SAR": "SAR", "TUG": "REMORQUEUR", - "PORT TENDER": "TENDER PORTUAIRE", + "PORT TENDER": "SERVITUDE", "ANTI-POLLUTION": "ANTIPOLLUTION", - "LAW ENFORCE": "FORCES DE L'ORDRE", + "LAW ENFORCE": "POLICE", "MEDICAL": "MÉDICAL", "HIGH-SPEED": "GRANDE VITESSE", "PASSENGER": "PASSAGERS", "CARGO": "CARGO", "TANKER": "PÉTROLIER", "OTHER": "AUTRE", + "Included in bundle": "Inclus dans l'archive", + "Missing bundle file — reimport its bundle": "Fichier absent de l'archive — réimportez son archive", + "Source configured; file checked when loaded": "Source configurée ; fichier vérifié au chargement", + "Source unavailable": "Source indisponible", "ENVIRONMENTAL": "ENVIRONNEMENT", "EARTH WATCH": "VEILLE TERRE", "ACTIVE EVENTS": "ÉVÉNEMENTS ACTIFS", - "Starting live contacts…": "Démarrage des contacts live…", + "Starting live contacts…": "Démarrage des contacts en direct…", "Opening space missions…": "Ouverture des missions spatiales…", "Scanning active events…": "Analyse des événements actifs…", - "Live earthquakes and active fires, from USGS and NASA": "Séismes et incendies actifs en direct, via USGS et NASA", - "It feels like a forbidden cockpit—then you realize the sources are public and the data is real.": "On dirait un cockpit interdit—puis on comprend que les sources sont publiques et que les données sont réelles.", + "Live earthquakes and active fires, from USGS and NASA": "Séismes et feux actifs en direct, via USGS et NASA", + "It feels like a forbidden cockpit—then you realize the sources are public and the data is real.": "On se croirait dans un cockpit interdit — puis on comprend que les sources sont publiques et les données réelles.", "Working…": "En cours…", "Could not open that mission{detail}. Retry or explore manually.": "Impossible d'ouvrir cette mission{detail}. Réessayez ou explorez manuellement.", "This browser is blocking storage, so that could not be saved.": "Ce navigateur bloque le stockage, l'enregistrement a donc échoué.", + "NORMAL": "NORMAL", "CRT": "CRT", "NVG": "NVG", "FLIR": "FLIR", + "ANIME": "ANIME", + "NOIR": "NOIR", "SNOW": "NEIGE", + "ARCTIC": "ARCTIQUE", + "ANTARCTIC": "ANTARCTIQUE", + "NORTH AMERICA": "AMÉRIQUE DU NORD", + "SOUTH AMERICA": "AMÉRIQUE DU SUD", + "EUROPE": "EUROPE", + "AFRICA": "AFRIQUE", + "ASIA": "ASIE", + "OCEANIA": "OCÉANIE", + "NORTHERN OCEANIC GRID": "GRILLE OCÉANIQUE NORD", + "SOUTHERN OCEANIC GRID": "GRILLE OCÉANIQUE SUD", "LOADING": "CHARGEMENT", "DEGRADED": "DÉGRADÉ", - "STALE": "PÉRIMÉ", + "STALE": "OBSOLÈTE", "PARTIAL": "PARTIEL", "FALLBACK": "SECOURS", + "{state} {layers}": "{state} : {layers}", + "view band|STREET": "RUE", + "view band|CITY": "VILLE", + "view band|METRO": "MÉTROPOLE", + "view band|REGIONAL": "RÉGION", + "view band|GLOBAL": "MONDE", "SUMMARY": "RÉSUMÉ", - "Awaiting telemetry...": "En attente de télémétrie...", + "Awaiting telemetry...": "En attente de télémétrie…", "REC": "REC", - "AIS: --": "AIS : --", + "AIS: --": "AIS : --", + "N/A": "N/D", + "{mode} {band} {locality} | {region} | ALT {alt} | WINDOW {window} | SUN {sun}° | ONA {ona}° | {zone}": "{mode} · {band} · {locality} | {region} | ALT {alt} | FENÊTRE {window} | SOLEIL {sun}° | ONA {ona}° | {zone}", + "NEAR {poi} ({city}) {distance}": "PRÈS DE {poi} ({city}) {distance}", + "SECTOR {lat} {lon}": "SECTEUR {lat} {lon}", + "hemisphere|N": "N", + "hemisphere|S": "S", + "hemisphere|E": "E", + "hemisphere|W": "O", "POWER UP · {count} KEYS WAITING": { - "one": "POWER UP · {count} CLÉ EN ATTENTE", - "other": "POWER UP · {count} CLÉS EN ATTENTE" + "one": "ALLUMER · {count} CLÉ EN ATTENTE", + "many": "ALLUMER · {count} DE CLÉS EN ATTENTE", + "other": "ALLUMER · {count} CLÉS EN ATTENTE" }, - "POWERED UP": "SOUS TENSION", + "POWERED UP": "ALLUMÉ", + "Provider Settings does not answer proxied requests": "Les paramètres des fournisseurs ne répondent pas aux requêtes passant par un proxy", + "Provider Settings is disabled while sharing is enabled": "Les paramètres des fournisseurs sont désactivés tant que le partage est activé", + "Provider Settings answers only the machine running the server": "Les paramètres des fournisseurs ne répondent qu'à la machine qui exécute le serveur", + "Provider Settings answers only local hostnames": "Les paramètres des fournisseurs ne répondent qu'aux noms d'hôte locaux", + "Provider Settings requires an exact local Origin": "Les paramètres des fournisseurs exigent un Origin local exact", + "Unrecognized Origin refused": "Origin non reconnu : requête refusée", + "Cross-origin requests are refused": "Les requêtes d'une autre origine sont refusées", + "Content-Type must be application/json": "Le Content-Type doit être application/json", + "Method not allowed": "Méthode non autorisée", + "Request too large": "Requête trop volumineuse", + "Invalid JSON": "JSON non valide", + "Body must be a JSON object of {ENV_VAR: value}": "Le corps doit être un objet JSON de la forme {ENV_VAR: value}", + "No keys provided": "Aucune clé fournie", + "At most {limit} keys per save": "{limit} clés au maximum par enregistrement", + "Unknown key: {name}": "Clé inconnue : {name}", + "{name} must be a string": "{name} : la valeur doit être une chaîne de caractères", + "{name} is empty": "{name} : la valeur est vide", + "{name} is longer than any real key ({limit} max)": "{name} : la valeur est plus longue que toute clé réelle ({limit} max.)", + "{name} may only contain printable characters with no spaces": "{name} : seuls les caractères imprimables sans espace sont acceptés", + "{name} contains a character that is not valid in a key (#, quotes, $, \\, or backtick)": "{name} : un caractère n'est pas valide dans une clé (#, guillemets, $, \\ ou accent grave)", + "{name} is configured outside Provider Settings and can only be changed where it was set": "{name} est configurée hors des paramètres des fournisseurs et ne peut être modifiée qu'à l'endroit où elle a été définie", + "The key was not saved: could not restrict the credential file to your account; nothing was saved": "La clé n'a pas été enregistrée : impossible de restreindre le fichier d'identifiants à votre compte ; rien n'a été enregistré", + "The key was not saved: the existing configuration could not be read, so nothing was changed": "La clé n'a pas été enregistrée : la configuration existante est illisible, rien n'a donc été modifié", + "Could not write the {store} store": "Impossible d'écrire dans le stockage {store}", "Save failed ({status}).": "Échec de l'enregistrement ({status}).", + "OAuth check failed: {detail}": "Échec de la vérification OAuth : {detail}", + "Could not check ChatGPT sign-in. Try again.": "Impossible de vérifier la connexion ChatGPT. Réessayez.", + "VOICE AUTH · CHATGPT OAUTH": "AUTH. VOCALE · OAUTH CHATGPT", + "VOICE AUTH · API KEY": "AUTH. VOCALE · CLÉ API", + "USE API KEY": "UTILISER LA CLÉ API", + "USE CHATGPT OAUTH": "UTILISER L'OAUTH CHATGPT", + "Use OPENAI_API_KEY for the next cloud voice session": "Utiliser OPENAI_API_KEY pour la prochaine session vocale cloud", + "Use the signed-in local ChatGPT/Codex OAuth session for the next cloud voice session": "Utiliser la session OAuth ChatGPT/Codex locale déjà connectée pour la prochaine session vocale cloud", + "Metered — a billing-enabled account": "Payant à l'usage — compte avec facturation activée", + "Optional paid token — public access works without one": "Jeton payant facultatif — l'accès public fonctionne sans", + "Free key — register, paste, done": "Clé gratuite — inscrivez-vous, collez-la, c'est tout", + "browser-side": "côté navigateur", + "This key runs in the browser by design — restrict it at the provider (see SECURITY.md)": "Cette clé s'exécute dans le navigateur par conception — restreignez-la chez le fournisseur (voir SECURITY.md)", + "configured externally": "configurée ailleurs", + "Supplied by your environment, Keychain, or launcher — change it where it was set": "Fournie par votre environnement, le Trousseau ou le lanceur — modifiez-la là où elle a été définie", + "MANAGE ↗": "GÉRER ↗", + "GET KEY ↗": "OBTENIR UNE CLÉ ↗", + "{envVar} saved — paste to replace": "{envVar} enregistrée — collez-en une autre pour la remplacer", + "paste {envVar}": "collez {envVar}", "REMOVE": "SUPPRIMER", "Remove {title} from this app's saved keys": "Supprimer {title} des clés enregistrées de l'application", + "unsaved provider keys": "les clés de fournisseurs non enregistrées", + "Project keys: {status}": "Clés du projet : {status}", "your app configuration": "la configuration de votre application", "your local .env": "votre .env local", "Saving…": "Enregistrement…", - "Save failed: {detail}": "Échec de l'enregistrement : {detail}", + "Save failed: {detail}": "Échec de l'enregistrement : {detail}", "Paste at least one key first.": "Collez d'abord au moins une clé.", "Saved to {store}. Restarting — this page reloads itself.": "Enregistré dans {store}. Redémarrage — cette page se recharge seule.", - "Remove this key from your saved configuration?": "Supprimer cette clé de votre configuration enregistrée ?", + "Cloud voice will use OPENAI_API_KEY on the next session.": "La voix cloud utilisera OPENAI_API_KEY à la prochaine session.", + "Checking local ChatGPT OAuth sign-in…": "Vérification de la connexion OAuth ChatGPT locale…", + "Could not check ChatGPT sign-in.": "Impossible de vérifier la connexion ChatGPT.", + "ChatGPT OAuth selected for cloud voice. Your API key stays saved and available.": "OAuth ChatGPT sélectionné pour la voix cloud. Votre clé API reste enregistrée et disponible.", + "ChatGPT sign-in expired. Opening sign-in again…": "La connexion ChatGPT a expiré. Nouvelle ouverture de la connexion…", + "Opening ChatGPT sign-in in your browser…": "Ouverture de la connexion ChatGPT dans votre navigateur…", + "Could not start ChatGPT sign-in on this machine.": "Impossible de lancer la connexion ChatGPT sur cette machine.", + "Finish ChatGPT sign-in in the browser. Waiting for it to complete…": "Terminez la connexion ChatGPT dans le navigateur. En attente de la fin…", + "ChatGPT sign-in timed out. Click {button} to try again.": "Délai de connexion ChatGPT dépassé. Cliquez sur « {button} » pour réessayer.", + "ChatGPT sign-in complete. OAuth will be used for the next cloud voice session.": "Connexion ChatGPT terminée. OAuth sera utilisé pour la prochaine session vocale cloud.", + "Remove this key from your saved configuration?": "Supprimer cette clé de votre configuration enregistrée ?", "Removed from {store}. Restarting — this page reloads itself.": "Supprimé de {store}. Redémarrage — cette page se recharge seule.", - "Places context + Street View fallback; optional separate key": "Contexte Places + secours Street View ; clé séparée facultative", + "The photorealistic 3D planet, place search + Street View": "La planète 3D photoréaliste, la recherche de lieux + Street View", + "Places context + Street View fallback; optional separate key": "Contexte Places + secours Street View ; clé séparée facultative", + "Voice control — API key or ChatGPT OAuth": "Commande vocale — clé API ou OAuth ChatGPT", + "Gemini Live voice control": "Commande vocale Gemini Live", "Live ships, worldwide": "Navires en direct, dans le monde entier", - "Live active-fire detections": "Détections d'incendies actifs en direct", - "Real live traffic (keyless runs a simulation)": "Trafic réel en direct (sans clé : simulation)", + "Live active-fire detections": "Détections de feux actifs en direct", + "Real live traffic (keyless runs a simulation)": "Trafic réel en direct (sans clé : simulation)", "Bing imagery map stacks + world terrain": "Fonds de carte Bing + relief mondial", "More flight-polling credits (anonymous works without)": "Plus de crédits d'interrogation des vols (fonctionne sans, en anonyme)", + "Street-level imagery and coverage in the Street Level layer. Free: register an app in the Mapillary developer dashboard and paste its Client Token": "Images et couverture au niveau de la rue dans la couche Niveau rue. Gratuit : enregistrez une application dans le tableau de bord développeur de Mapillary et collez son Client Token", + "Public space-missions access needs no key. Leave blank for standard use; paid tokens only raise request limits.": "L'accès public aux missions spatiales ne nécessite pas de clé. Laissez vide pour un usage standard ; les jetons payants ne font qu'augmenter les limites de requêtes.", + "Air quality request failed": "Échec de la requête sur la qualité de l'air", + "No readings available": "Aucune mesure disponible", + "No current readings": "Aucune mesure actuelle", + "{count} stations reporting": { + "one": "{count} station transmet", + "many": "{count} de stations transmettent", + "other": "{count} stations transmettent" + }, + "Highest air-quality readings in view": "Mesures de qualité de l'air les plus élevées dans la vue", + "Low": "Faible", + "Low health risk": "Risque faible pour la santé", + "Moderate": "Modéré", + "Moderate health risk": "Risque modéré pour la santé", + "High": "Élevé", + "High health risk": "Risque élevé pour la santé", + "Very High": "Très élevé", + "Very High health risk": "Risque très élevé pour la santé", + "Air quality": "Qualité de l'air", + "Canada only · ECCC AQHI network": "Canada seulement · réseau CQAS d'ECCC", + "ECCC request timed out": "Délai dépassé pour la requête ECCC", + "Malformed AQHI station response": "Réponse des stations CQAS mal formée", + "No AQHI stations available": "Aucune station CQAS disponible", + "Malformed AQHI observation response": "Réponse des observations CQAS mal formée", + "Camera source temporarily unavailable": "Source de caméras temporairement indisponible", + "Mapped camera locations": "Emplacements de caméras cartographiés", + "SHOW NEAREST": "LA PLUS PROCHE", + "Stop following the current object before navigating to a camera": "Arrêtez de suivre l'objet actuel avant d'aller vers une caméra", + "Move to the nearest loaded camera and show its details": "Aller à la caméra chargée la plus proche et afficher ses détails", + "Camera badges": "Badges de caméras", + "Cyan cameras turn coral when selected. Wedges illustrate mapped direction, not measured coverage. Nearby cameras may be outside the screen.": "Les caméras cyan deviennent corail une fois sélectionnées. Les secteurs illustrent l'orientation cartographiée, pas une couverture mesurée. Des caméras proches peuvent être hors de l'écran.", + "{count} nearby · {onScreen} on screen": { + "one": "{count} proche · {onScreen} à l'écran", + "many": "{count} de caméras proches · {onScreen} à l'écran", + "other": "{count} proches · {onScreen} à l'écran" + }, + "{count} nearby": { + "one": "{count} proche", + "many": "{count} de caméras proches", + "other": "{count} proches" + }, + "retrying mapped ALPR cameras": "nouvel essai des caméras LAPI cartographiées", + "loading mapped ALPR cameras": "chargement des caméras LAPI cartographiées", + "No ALPR data for this area — US and Canada only": "Aucune donnée LAPI pour cette zone — États-Unis et Canada seulement", + "Zoom in to load mapped cameras": "Zoomez pour charger les caméras cartographiées", + "Showing cached locations": "Emplacements en cache affichés", + "Coverage limited — zoom in": "Couverture limitée — zoomez", + "No ALPR data for this area": "Aucune donnée LAPI pour cette zone", + "None on screen — nearby cameras are outside the view": "Aucune à l'écran — les caméras proches sont hors de la vue", + "ALPR camera": "Caméra LAPI", + "Camera coverage unavailable": "Couverture des caméras indisponible", + "OpenStreetMap · community mapped": "OpenStreetMap · cartographie communautaire", + "Overpass returned an incomplete camera response": "Overpass a renvoyé une réponse incomplète pour les caméras", + "At least {count}": "Au moins {count}", "CONTEXT READY": "CONTEXTE PRÊT", "GLOBAL CONTEXT OFF": "CONTEXTE GLOBAL OFF", "SELECT A FLIGHT, VESSEL, OR MAPPED INSTALLATION": "CHOISIR UN VOL, UN NAVIRE OU UNE INSTALLATION CARTOGRAPHIÉE", @@ -108,26 +494,33 @@ "Focus {label}": "Centrer sur {label}", "Global Context navigation": "Navigation du Contexte global", "Previous — prior visited contact in the 250 km window": "Précédent — contact visité précédemment dans la fenêtre de 250 km", - "PREVIOUS": "PRÉCÉDENT", + "PREVIOUS": "PRÉC.", "FOCUS": "CENTRER", "Next — nearest unvisited contact in the 250 km window": "Suivant — contact non visité le plus proche dans la fenêtre de 250 km", - "NEXT": "SUIVANT", + "NEXT": "SUIV.", + "Named areas ({n})": "Zones nommées ({n})", + "{distance} FLIGHT / VESSEL WINDOW": "FENÊTRE VOLS / NAVIRES DE {distance}", "Open-source mapped/observed context. Missing broadcasts, unloaded map areas, or unmapped sites are not evidence of absence.": "Contexte cartographié/observé en source ouverte. Des diffusions manquantes, des zones de carte non chargées ou des sites non cartographiés ne prouvent pas une absence.", + "mapped matches within {km} km of the subject": "correspondances cartographiées à moins de {km} km de la cible", + "none mapped within {km} km; not a complete 250 km survey": "aucune cartographiée à moins de {km} km ; pas un relevé complet sur 250 km", + "mapped matches from the loaded viewport": "correspondances cartographiées dans la vue chargée", + "viewport feed is not a complete 250 km survey": "les données de la vue ne sont pas un relevé complet sur 250 km", "HDG {value}°": "HDG {value}°", "BRG {value}°": "BRG {value}°", "BRG —": "BRG —", "CRS {value}°": "CRS {value}°", "CURRENT VIEWPORT ONLY": "VUE ACTUELLE SEULEMENT", - "WITHIN {km} KM": "DANS {km} KM", + "WITHIN {km} KM": "À MOINS DE {km} KM", "Flights": "Vols", "Military flights": "Vols militaires", "AIS vessels": "Navires AIS", "Mapped installations": "Installations cartographiées", - "syncing {count} city feeds...": "synchro de {count} flux de villes...", - "scanning nearby systems...": "analyse des systèmes proches...", + "syncing {count} city feeds...": "synchro de {count} flux de villes…", + "scanning nearby systems...": "analyse des systèmes proches…", + "GBFS fetch error": "erreur de récupération GBFS", "Station {id}": "Station {id}", "Station": "Station", - "🚲 {bikes} avail · {docks} docks · {capacity} cap": "🚲 {bikes} dispo · {docks} bornes · {capacity} cap.", + "🚲 {bikes} avail · {docks} docks · {capacity} cap": "🚲 {bikes} dispo · {docks} bornes libres · {capacity} places", "⚠️ Not installed": "⚠️ Non installée", "⚠️ Not renting": "⚠️ Location impossible", "⚠️ Not returning": "⚠️ Retour impossible", @@ -135,8 +528,10 @@ "{count} CAMERAS STANDING BY · NO CAMERA SELECTED · CLICK A CAMERA TO ACTIVATE": "{count} CAMÉRAS EN ATTENTE · AUCUNE CAMÉRA SÉLECTIONNÉE · CLIQUER SUR UNE CAMÉRA POUR L'ACTIVER", "No cameras available in catalog.": "Aucune caméra disponible dans le catalogue.", "{city} CCTV": "CCTV {city}", + "FOV {value}° (DATASHEET)": "FOV {value}° (FICHE TECHNIQUE)", "FOV {value}°": "FOV {value}°", - "COVERAGE {value}km²": "COUVERTURE {value}km²", + "SPEC FOV {span}° (CAPABILITY)": "FOV FICHE {span}° (CAPACITÉ)", + "COVERAGE {value}km²": "COUVERTURE {value} km²", "OVERLAP {count} cams": "CHEVAUCHEMENT {count} cam.", "ISOLATED VIEW": "VUE ISOLÉE", "PROJ MONITOR": "PROJ MONITEUR", @@ -145,42 +540,284 @@ "CAL {value}": "CAL {value}", "SRC {value}": "SRC {value}", "{value} CONTEXT": "CONTEXTE {value}", - "Focus fire detection {title}, {details}": "Centrer sur la détection d'incendie {title}, {details}", + "{spec} · SPECS: CCTV-DATABASE.COM": "{spec} · CARACT. : CCTV-DATABASE.COM", + "Atlantic and eastern/central North Pacific; not worldwide cyclone coverage.": "Atlantique et Pacifique Nord oriental/central ; pas une couverture mondiale des cyclones.", + "Cyclone advisories unavailable": "Bulletins cycloniques indisponibles", + "Cyclone data unavailable": "Données cycloniques indisponibles", + "Potential tropical cyclone": "Cyclone tropical potentiel", + "Post-tropical cyclone": "Cyclone post-tropical", + "Hurricane": "Ouragan", + "Tropical storm": "Tempête tropicale", + "Tropical depression": "Dépression tropicale", + "Subtropical storm": "Tempête subtropicale", + "Subtropical depression": "Dépression subtropicale", + "Track and cone match this advisory": "La trajectoire et le cône correspondent à ce bulletin", + "Track/cone awaiting advisory {number}": "Trajectoire/cône en attente du bulletin {number}", + "Track/cone unavailable": "Trajectoire/cône indisponible", + "Cached advisory · stale source": "Bulletin en cache · source obsolète", + "Loading advisories…": "Chargement des bulletins…", + "{count} active storms": { + "one": "{count} cyclone actif", + "many": "{count} de cyclones actifs", + "other": "{count} cyclones actifs" + }, + "Position as of {time}": "Position à {time}", + "Maximum sustained wind: {wind} · Pressure: {pressure}": "Vent maximal soutenu : {wind} · Pression : {pressure}", + "{name} · {classification} · Advisory {number} · issued {time}": "{name} · {classification} · Bulletin {number} · émis à {time}", + "No active NHC/CPHC systems": "Aucun système actif NHC/CPHC", + "Advisories unavailable": "Bulletins indisponibles", + "Cyclones · NHC / CPHC": "Cyclones · NHC / CPHC", + "Atlantic · E/C Pacific": "Atlantique · Pacifique E/C", + "{storms} · {name} selected": "{storms} · {name} sélectionné", + "Official advisory ↗": "Bulletin officiel ↗", + "Active NHC and CPHC cyclone advisories": "Bulletins cycloniques actifs du NHC et du CPHC", + "Wind unavailable": "Vent indisponible", + "Advisory center / forecast track": "Centre selon le bulletin / trajectoire prévue", + "Center-track uncertainty cone": "Cône d'incertitude de la trajectoire du centre", + "Select a storm on the map, or choose a storm in the list to select it and move the camera. Click empty map space to clear the selection. NOAA NHC/CPHC advisory context. The cone describes forecast center-track uncertainty, not storm size or the full hazard area. Forecast point labels are source lead hours, not times computed from advisory issuance. Geometry follows the surface; height is not weather altitude. Consult the official advisory.": "Sélectionnez un cyclone sur la carte, ou choisissez-en un dans la liste pour le sélectionner et déplacer la caméra. Cliquez sur une zone vide de la carte pour effacer la sélection. Contexte des bulletins NOAA NHC/CPHC. Le cône décrit l'incertitude de la trajectoire prévue du centre, pas la taille du cyclone ni toute la zone de danger. Les étiquettes des points de prévision sont les échéances de la source, pas des heures calculées depuis l'émission du bulletin. La géométrie suit la surface ; la hauteur n'est pas une altitude météorologique. Consultez le bulletin officiel.", + "DRIVE": "VOITURE", + "Drive": "En voiture", + "WALK": "À PIED", + "Walk": "À pied", + "BIKE": "VÉLO", + "Bike": "À vélo", + "rate limited": "limite de requêtes atteinte", + "routing service is rate limited": "le service d'itinéraire a atteint sa limite de requêtes", + "route leg too long": "tronçon d'itinéraire trop long", + "route too long": "itinéraire trop long", + "{error} — try again in a moment": "{error} — réessayez dans un instant", + "Routing is rate limited — try again in a moment": "Limite de requêtes d'itinéraire atteinte — réessayez dans un instant", + "Routing unavailable (HTTP {status})": "Itinéraire indisponible (HTTP {status})", + "Routing unavailable": "Itinéraire indisponible", + "direction|left": "à gauche", + "direction|right": "à droite", + "direction|slightly left": "légèrement à gauche", + "direction|slightly right": "légèrement à droite", + "direction|sharply left": "franchement à gauche", + "direction|sharply right": "franchement à droite", + "direction|straight": "tout droit", + "direction|around": "en sens inverse", + "fork direction|left": "à gauche", + "fork direction|right": "à droite", + "fork direction|slightly left": "légèrement à gauche", + "fork direction|slightly right": "légèrement à droite", + "fork direction|sharply left": "franchement à gauche", + "fork direction|sharply right": "franchement à droite", + "fork direction|straight": "tout droit", + "lane direction|left": "de gauche", + "lane direction|right": "de droite", + "lane direction|slightly left": "de gauche", + "lane direction|slightly right": "de droite", + "lane direction|sharply left": "la plus à gauche", + "lane direction|sharply right": "la plus à droite", + "lane direction|straight": "centrale", + "ordinal|{number}st": "{number}re", + "ordinal|{number}nd": "{number}e", + "ordinal|{number}rd": "{number}e", + "ordinal|{number}th": "{number}e", + "Head out on {road}": "Partez par {road}", + "Head out": "Partez", + "Arrive at your destination, on the left": "Vous êtes arrivé, la destination est à gauche", + "Arrive at your destination, on the right": "Vous êtes arrivé, la destination est à droite", + "Arrive at your destination": "Vous êtes arrivé à destination", + "Make a U-turn onto {road}": "Faites demi-tour sur {road}", + "Make a U-turn": "Faites demi-tour", + "Continue straight onto {road}": "Continuez tout droit sur {road}", + "Continue straight": "Continuez tout droit", + "Turn {direction} onto {road}": "Tournez {direction} sur {road}", + "Turn {direction}": "Tournez {direction}", + "Turn onto {road}": "Tournez sur {road}", + "maneuver|Turn": "Tournez", + "Continue {direction} onto {road}": "Continuez {direction} sur {road}", + "Continue {direction}": "Continuez {direction}", + "At the end of the road, turn {direction} onto {road}": "Au bout de la route, tournez {direction} sur {road}", + "At the end of the road, turn {direction}": "Au bout de la route, tournez {direction}", + "At the end of the road, continue onto {road}": "Au bout de la route, continuez sur {road}", + "At the end of the road, continue": "Au bout de la route, continuez", + "Keep {direction} at the fork onto {road}": "À l'embranchement, restez {direction} sur {road}", + "Keep {direction} at the fork": "À l'embranchement, restez {direction}", + "Continue at the fork onto {road}": "À l'embranchement, continuez sur {road}", + "Continue at the fork": "À l'embranchement, continuez", + "Merge {direction} onto {road}": "Insérez-vous {direction} sur {road}", + "Merge {direction}": "Insérez-vous {direction}", + "Merge onto {road}": "Insérez-vous sur {road}", + "maneuver|Merge": "Insérez-vous", + "Take the ramp on the {direction} onto {road}": "Prenez la bretelle {direction} vers {road}", + "Take the ramp on the {direction}": "Prenez la bretelle {direction}", + "Take the ramp {direction} onto {road}": "Prenez la bretelle {direction} vers {road}", + "Take the ramp {direction}": "Prenez la bretelle {direction}", + "Take the ramp onto {road}": "Prenez la bretelle vers {road}", + "Take the ramp": "Prenez la bretelle", + "Take the exit on the {direction} onto {road}": "Prenez la sortie {direction} vers {road}", + "Take the exit on the {direction}": "Prenez la sortie {direction}", + "Take the exit {direction} onto {road}": "Prenez la sortie {direction} vers {road}", + "Take the exit {direction}": "Prenez la sortie {direction}", + "Take the exit onto {road}": "Prenez la sortie vers {road}", + "Take the exit": "Prenez la sortie", + "At the roundabout, take the {exit} exit onto {road}": "Au rond-point, prenez la {exit} sortie vers {road}", + "At the roundabout, take the {exit} exit": "Au rond-point, prenez la {exit} sortie", + "Enter the roundabout onto {road}": "Engagez-vous dans le rond-point vers {road}", + "Enter the roundabout": "Engagez-vous dans le rond-point", + "At the roundabout, turn {direction} onto {road}": "Au rond-point, tournez {direction} sur {road}", + "At the roundabout, turn {direction}": "Au rond-point, tournez {direction}", + "At the roundabout, continue onto {road}": "Au rond-point, continuez sur {road}", + "At the roundabout, continue": "Au rond-point, continuez", + "Exit the roundabout onto {road}": "Sortez du rond-point vers {road}", + "Exit the roundabout": "Sortez du rond-point", + "Use the {direction} lane onto {road}": "Prenez la voie {direction} vers {road}", + "Use the {direction} lane": "Prenez la voie {direction}", + "Continue onto {road}": "Continuez sur {road}", + "maneuver|Continue": "Continuez", + "{mode} — reroute for {modeLower}": "{mode} — recalculer l'itinéraire : {modeLower}", + "CLICK MAP": "CLIQUEZ LA CARTE", + "SET A": "PLACER A", + "Click a spot on the globe to place A (click again to cancel)": "Cliquez sur un point du globe pour placer A (cliquez à nouveau pour annuler)", + "Then click the globe to place the start": "Puis cliquez sur le globe pour placer le départ", + "SET B": "PLACER B", + "Click a spot on the globe to place B (click again to cancel)": "Cliquez sur un point du globe pour placer B (cliquez à nouveau pour annuler)", + "Then click the globe to place the destination": "Puis cliquez sur le globe pour placer la destination", + "Swap A and B": "Inverser A et B", + "FLY ···": "SURVOL ···", + "FLYING": "SURVOL EN COURS", + "FLY": "SURVOLER", + "Fly the camera along the route": "Faire voler la caméra le long de l'itinéraire", + "Place A and B first": "Placez d'abord A et B", + "action|CLEAR": "EFFACER", + "Remove the route and both markers": "Supprimer l'itinéraire et les deux marqueurs", + "press Escape twice to leave Draw": "appuyez deux fois sur Esc pour quitter Dessin", + "{name} is active — turn {name} off, then set {endpoint}": "{name} est actif — désactivez {name}, puis placez {endpoint}", + "{name} is active — {leave}, then set {endpoint}": "{name} est actif — {leave}, puis placez {endpoint}", + "Only the first {count} turns of this route are shown": "Seules les {count} premières manœuvres de cet itinéraire sont affichées", + "Turn-by-turn directions": "Instructions pas à pas", + "Another map tool is using clicks — close it, then SET A again": "Un autre outil de carte utilise les clics — fermez-le, puis refaites PLACER A", + "Routing…": "Calcul de l'itinéraire…", + "No route found": "Aucun itinéraire trouvé", + "{distance} · {duration} · {mode} · first {count} turns": "{distance} · {duration} · {mode} · {count} premières manœuvres", + "{distance} · {duration} · {mode}": "{distance} · {duration} · {mode}", + "Click the globe to place {endpoint}": "Cliquez sur le globe pour placer {endpoint}", + "SET B, then click the globe": "PLACER B, puis cliquez sur le globe", + "SET A, then click the globe": "PLACER A, puis cliquez sur le globe", + "Step {step} of {total} · then {leg}": "Étape {step} sur {total} · puis {leg}", + "Step {step} of {total}": "Étape {step} sur {total}", + "Then: {instruction}": "Puis : {instruction}", + "No route found between A and B": "Aucun itinéraire trouvé entre A et B", + "Routing failed: {error}": "Échec du calcul d'itinéraire : {error}", + "Routing timed out": "Délai dépassé pour le calcul d'itinéraire", + "Routing unavailable — no response from the routing service": "Itinéraire indisponible — aucune réponse du service d'itinéraire", + "Earthquake source unavailable": "Source des séismes indisponible", + "Focus fire detection {title}, {details}": "Centrer sur la détection de feu {title}, {details}", + "live feed unavailable": "flux en direct indisponible", "{value} conf": "conf. {value}", "{value} ago": "il y a {value}", "sensor n/a": "capteur n/d", - "FIRE · {frp} MW": "INCENDIE · {frp} MW", + "FIRE · {frp} MW": "FEU · {frp} MW", "NIGHT": "NUIT", "▲ {frp} MW": "▲ {frp} MW", - "FIRE": "INCENDIE", - "FIRES": "INCENDIES", + "FIRE": "FEU", + "FIRES": "FEUX", "max {value} MW": "max {value} MW", "new {value}": "nouveau {value}", + "{value}°N": "{value}°N", + "{value}°S": "{value}°S", + "{value}°E": "{value}°E", + "{value}°W": "{value}°O", "just now": "à l'instant", "<1m ago": "il y a <1 min", "{count}m ago": "il y a {count} min", "{count}h ago": "il y a {count} h", - "STALE · cached {age}": "PÉRIMÉ · en cache {age}", - "refreshing...": "actualisation...", - "loading...": "chargement...", + "fire confidence|high": "élevée", + "fire confidence|nominal": "nominale", + "fire confidence|low": "faible", + "age|<1h": "<1 h", + "age|{count}h": "{count} h", + "age|{count}d": "{count} j", + "STALE · cached {age}": "OBSOLÈTE · en cache {age}", + "refreshing...": "actualisation…", + "loading...": "chargement…", "KEY REQUIRED": "CLÉ REQUISE", - "LIVE · updated {age}": "LIVE · mis à jour {age}", + "LIVE · updated {age}": "DIRECT · mis à jour {age}", + "Source snapshot time unavailable": "Heure de l'instantané source indisponible", + "Live data unavailable": "Données en direct indisponibles", + "Intel Picture": "Situation renseignement", + "Kinetic 30d": "Cinétique 30 j", + "Border Crisis": "Crise frontalière", + "Iran Picture": "Situation Iran", + "Iran Kinetic": "Iran cinétique", + "Yemen FLOT": "FLOT Yémen", + "Latest Drop": "Dernière publication", + "GhostMaps file could not be read": "Impossible de lire le fichier GhostMaps", + "{count} source links ↗ · click card to open the first": { + "one": "{count} lien source ↗ · cliquez sur la fiche pour l'ouvrir", + "many": "{count} de liens sources ↗ · cliquez sur la fiche pour ouvrir le premier", + "other": "{count} liens sources ↗ · cliquez sur la fiche pour ouvrir le premier" + }, + "S2 · {name}": "S2 · {name}", + "Report": "Rapport", + "Open the source for {title}": "Ouvrir la source de {title}", + "GhostMaps catalog unavailable": "Catalogue GhostMaps indisponible", + "LIVE · GitHub {commit} · {message} · checked every {seconds}s": "DIRECT · GitHub {commit} · {message} · vérifié toutes les {seconds} s", + "GitHub {commit} · {message} · reconnecting for live updates": "GitHub {commit} · {message} · reconnexion pour les mises à jour en direct", + "Connecting to the S2 GhostMaps repository…": "Connexion au dépôt S2 GhostMaps…", + "{count} placemarks": { + "one": "{count} repère", + "many": "{count} de repères", + "other": "{count} repères" + }, + "S2 Underground publishes these KMZ products to GitHub. New uploads are detected within seconds and replace the previous edition automatically. Click a marker for its report.": "S2 Underground publie ces produits KMZ sur GitHub. Les nouvelles publications sont détectées en quelques secondes et remplacent automatiquement l'édition précédente. Cliquez sur un marqueur pour voir son rapport.", + "Malformed GhostMaps catalog": "Catalogue GhostMaps mal formé", + "Low-accuracy score < 2%": "Indice de faible précision < 2 %", + "Low-accuracy score 2–10%": "Indice de faible précision 2–10 %", + "Low-accuracy score > 10%": "Indice de faible précision > 10 %", + "GNSS integrity source unavailable": "Source d'intégrité GNSS indisponible", + "Regional sample · 250 nm radius · cells from visited views over 30 min": "Échantillon régional · rayon de 250 NM · cellules des vues visitées sur 30 min", + "Retrying automatically at {time} UTC": "Nouvel essai automatique à {time} UTC", + "Retrying automatically after provider cooldown": "Nouvel essai automatique après la pause du fournisseur", + "Updates automatically after pan or zoom and once a minute. The public feed covers a 250-nautical-mile circle around the view centre; zooming out does not make it a worldwide snapshot. Blank cells are outside sampled coverage or have insufficient observations.": "Mise à jour automatique après un déplacement ou un zoom, et une fois par minute. Le flux public couvre un cercle de 250 milles nautiques autour du centre de la vue ; dézoomer n'en fait pas un instantané mondial. Les cellules vides sont hors de la couverture échantillonnée ou manquent d'observations.", + "Low-accuracy score = 100 × max(0, bad − 1) / total: one aircraft is discounted, so this is not the raw share. Cells need {aircraft} aircraft over {minutes} minutes. Navigation-integrity anomalies are not a detection of jamming or spoofing.": "Indice de faible précision = 100 × max(0, mauvais − 1) / total : un aéronef est déduit, ce n'est donc pas la proportion brute. Chaque cellule exige {aircraft} aéronefs sur {minutes} minutes. Les anomalies d'intégrité de navigation ne constituent pas une détection de brouillage ou de leurrage.", + "GNSS snapshot needs a view anchor": "L'instantané GNSS nécessite un point d'ancrage de la vue", + "GNSS feed rate limited (HTTP 429)": "Flux GNSS : limite de requêtes atteinte (HTTP 429)", + "Malformed GNSS integrity snapshot": "Instantané d'intégrité GNSS mal formé", + "GNSS integrity snapshot has no observation time": "L'instantané d'intégrité GNSS n'a pas d'heure d'observation", + "installation class|AIRFIELD": "AÉRODROME", + "installation class|NAVAL BASE": "BASE NAVALE", + "installation class|RANGE": "CHAMP DE TIR", + "installation class|MILITARY LAND": "TERRAIN MILITAIRE", + "installation class|BASE": "BASE", + "installation class|BARRACKS": "CASERNE", + "installation class|TRAINING AREA": "ZONE D'ENTRAÎNEMENT", + "installation class|PLACES CANDIDATE": "CANDIDAT PLACES", + "installation class|INSTALLATION": "INSTALLATION", + "No mapped sites within {km} km of the contact": "Aucun site cartographié à moins de {km} km du contact", + "{count} mapped sites within {km} km of the contact": { + "one": "{count} site cartographié à moins de {km} km du contact", + "many": "{count} de sites cartographiés à moins de {km} km du contact", + "other": "{count} sites cartographiés à moins de {km} km du contact" + }, + "No mapped sites in view": "Aucun site cartographié dans la vue", + "{count} mapped sites in view": { + "one": "{count} site cartographié dans la vue", + "many": "{count} de sites cartographiés dans la vue", + "other": "{count} sites cartographiés dans la vue" + }, "loading mapped installation context": "chargement du contexte de l'installation cartographiée", + "Too many mapped sites in view to list them all": "Trop de sites cartographiés dans la vue pour tous les lister", + "Installation context unavailable": "Contexte des installations indisponible", "MAPPED INSTALLATION": "INSTALLATION CARTOGRAPHIÉE", + "Unknown": "Inconnu", "LAUNCH SITE · {site}": "SITE DE LANCEMENT · {site}", "LAUNCH SITE": "SITE DE LANCEMENT", "T−{time} · {mission}": "T−{time} · {mission}", "LAUNCH STANDBY": "LANCEMENT EN ATTENTE", "LIFTOFF · {mission}": "DÉCOLLAGE · {mission}", - "ASCENT REPLAY · {mission}": "RELECTURE ASCENSION · {mission}", + "ASCENT REPLAY · {mission}": "REJEU DE L'ASCENSION · {mission}", "ASCENT ESTIMATE · {mission}": "ASCENSION ESTIMÉE · {mission}", "STAGE RE-ENTRY / RECOVERY · {mission}": "RENTRÉE / RÉCUPÉRATION D'ÉTAGE · {mission}", - "ORBIT REPLAY · {mission}": "RELECTURE ORBITE · {mission}", + "ORBIT REPLAY · {mission}": "REJEU DE L'ORBITE · {mission}", "PAUSED · {title}": "PAUSE · {title}", "UNSPECIFIED": "NON PRÉCISÉ", "+{count} additional payload records": "+{count} enregistrements de charge utile supplémentaires", "PAYLOAD DATA UNAVAILABLE": "DONNÉES DE CHARGE UTILE INDISPONIBLES", - "{value} KM DOWNRANGE": "{value} KM EN AVAL", + "{value} KM DOWNRANGE": "{value} KM PARCOURUS", "POSITION UNAVAILABLE": "POSITION INDISPONIBLE", "FLIGHT {count}": "VOL {count}", "REUSED": "RÉUTILISÉ", @@ -192,6 +829,7 @@ "Select {mission}": "Sélectionner {mission}", "{value} KM": "{value} KM", "{value} KM/S": "{value} KM/S", + "Selected Space Mission": "Mission spatiale sélectionnée", "SELECTED SPACE MISSION": "MISSION SPATIALE SÉLECTIONNÉE", "Show all missions": "Afficher toutes les missions", "Deselect mission": "Désélectionner la mission", @@ -211,31 +849,102 @@ "STAGE": "ÉTAGE", "STATUS": "STATUT", "FINAL POSITION": "POSITION FINALE", - "REPLAY SPEED": "VITESSE DE RELECTURE", - "Replay speed multiplier": "Multiplicateur de vitesse de relecture", + "REPLAY SPEED": "VITESSE DU REJEU", + "Replay speed multiplier": "Multiplicateur de vitesse du rejeu", "REPLAY ASCENT": "REJOUER L'ASCENSION", "Previous mission": "Mission précédente", "PREV": "PRÉC.", "Next mission": "Mission suivante", "SHOW ALL / DESELECT": "TOUT AFFICHER / DÉSÉLECTIONNER", - "Pause replay": "Mettre la relecture en pause", - "Cancel replay": "Annuler la relecture", - "EST. DOWNRANGE": "EN AVAL EST.", + "Pause replay": "Mettre le rejeu en pause", + "Cancel replay": "Annuler le rejeu", + "EST. DOWNRANGE": "DIST. ESTIMÉE", "PLANNED · ": "PRÉVU · ", "SUPPLIED TRAJECTORY POINTS": "POINTS DE TRAJECTOIRE FOURNIS", "RECONSTRUCTED ESTIMATE": "ESTIMATION RECONSTITUÉE", "Replay the estimated ascent with a following camera": "Rejouer l'ascension estimée avec une caméra de suivi", - "Resume replay": "Reprendre la relecture", + "Resume replay": "Reprendre le rejeu", "T minus {seconds}": "T moins {seconds}", "Preparing launch site": "Préparation du site de lancement", "Liftoff": "Décollage", - "Ascent replay": "Relecture de l'ascension", - "Orbit replay": "Relecture de l'orbite", + "Ascent replay": "Rejeu de l'ascension", + "Orbit replay": "Rejeu de l'orbite", ", paused": ", en pause", + "Malformed launch snapshot": "Instantané des lancements mal formé", + "Heard by your receiver": "Capté par votre récepteur", + "1090 MHz": "1090 MHz", + "978 MHz UAT": "978 MHz UAT", + "browser SDR": "SDR du navigateur", + "decoder feed": "flux du décodeur", + "Your RTL-SDR receiver and decoder feed": "Votre récepteur RTL-SDR et le flux du décodeur", + "Your decoder feed": "Votre flux de décodeur", + "Your RTL-SDR receiver": "Votre récepteur RTL-SDR", + "NO CALLSIGN": "SANS INDICATIF", + "ALT {altitude} FT · GS {speed} KT · TRK {track}": "ALT {altitude} FT · GS {speed} ND · TRK {track}", + "V/S {rate}": "V/S {rate}", + "V/S {rate} FPM": "V/S {rate} FT/MIN", + "POSITION {age}": "POSITION {age}", + "POSITION {seconds} S AGO": "POSITION IL Y A {seconds} S", + "{count} MSGS": { + "one": "{count} MSG", + "many": "{count} DE MSG", + "other": "{count} MSG" + }, + "Decoder feeds": "Flux du décodeur", + "WebUSB + decoder feeds": "WebUSB + flux du décodeur", + "opening receiver": "ouverture du récepteur", + "checking decoder feeds": "vérification des flux du décodeur", + "WebUSB needs desktop Chrome or Edge": "WebUSB nécessite Chrome ou Edge sur ordinateur", + "connect a receiver in Radio": "connectez un récepteur dans Radio", + "receiver is in FM mode": "le récepteur est en mode FM", + "listening": "à l'écoute", + "USB error": "erreur USB", "Alt unknown": "Alt. inconnue", "Type unknown": "Type inconnu", "Reg unknown": "Immat. inconnue", "Operator unknown": "Opérateur inconnu", + "${amount}K": "{amount} k$", + "${amount}M": "{amount} M$", + "${amount}B": "{amount} Md$", + "fire cause|Human": "humaine", + "fire cause|Natural": "naturelle", + "fire cause|Undetermined": "indéterminée", + "fire cause|Unknown": "inconnue", + "fire behavior|Minimal": "activité minimale", + "fire behavior|Moderate": "activité modérée", + "fire behavior|Active": "activité forte", + "fire behavior|Extreme": "activité extrême", + "Type {level} Incident": "incident de type {level}", + "age|{count}m": "{count} min", + "{acres} ac": { + "one": "{acres} acre", + "many": "{acres} d'acres", + "other": "{acres} acres" + }, + "{percent}% contained": "maîtrisé à {percent} %", + "containment unknown": "maîtrise inconnue", + "{cause} cause": "cause : {cause}", + "{personnel} personnel": { + "one": "{personnel} intervenant", + "many": "{personnel} d'intervenants", + "other": "{personnel} intervenants" + }, + "{county} County": "comté de {county}", + "{cost} to date": "{cost} à ce jour", + "discovered {age} ago": "détecté il y a {age}", + "updated {age} ago": "mis à jour il y a {age}", + "part of {complex}": "fait partie de {complex}", + "InciWeb ↗ · click card to open": "InciWeb ↗ · cliquez sur la fiche pour l'ouvrir", + "FIRE · {name}": "INCENDIE · {name}", + "Unnamed incident": "Incident sans nom", + "Open {title} on InciWeb": "Ouvrir {title} sur InciWeb", + "Perimeter source unavailable": "Source des périmètres indisponible", + "Not contained or unknown": "Non maîtrisé ou inconnu", + "Under 50% contained": "Maîtrisé à moins de 50 %", + "50–99% contained": "Maîtrisé à 50–99 %", + "Fully contained": "Entièrement maîtrisé", + "Colour shows reported containment. Perimeters are simplified to about 100 m.": "La couleur indique le niveau de maîtrise signalé. Les périmètres sont simplifiés à environ 100 m.", + "Malformed perimeter snapshot": "Instantané des périmètres mal formé", "radio tag|All": "Toutes", "News": "Actualités", "Talk": "Débats", @@ -245,6 +954,10 @@ "Traffic / Transit": "Trafic / Transports", "Music": "Musique", "Other": "Autres", + "Directory refresh degraded; showing the previous station catalog.": "Actualisation partielle de l'annuaire ; affichage du catalogue de stations précédent.", + "Radio directory coverage is degraded.": "La couverture de l'annuaire radio est dégradée.", + "Directory refresh failed; showing the previous station catalog.": "Échec de l'actualisation de l'annuaire ; affichage du catalogue de stations précédent.", + "Radio directory is temporarily unavailable.": "L'annuaire radio est temporairement indisponible.", "radio|NEWS": "ACTUS", "radio|TALK": "DÉBATS", "radio|WEATHER": "MÉTÉO", @@ -253,6 +966,9 @@ "radio|TRANSIT": "TRANSPORTS", "radio|MUSIC": "MUSIQUE", "radio|OTHER": "AUTRES", + "Broadcaster stream is unavailable or blocked by the browser.": "Le flux du diffuseur est indisponible ou bloqué par le navigateur.", + "Playback requires a direct click or tap.": "La lecture nécessite un clic ou un appui direct.", + "Broadcaster stream could not be started.": "Impossible de démarrer le flux du diffuseur.", "Alternative": "Alternatif", "Ambient": "Ambient", "Blues": "Blues", @@ -278,6 +994,32 @@ "Techno": "Techno", "Trance": "Trance", "World": "Musiques du monde", + "overview": "vue d'ensemble", + "cloud unknown": "nébulosité inconnue", + "{percent}% scene cloud": "{percent} % de nuages sur la scène", + "{min}–{max}% scene cloud": "{min}–{max} % de nuages sur la scène", + "Comparison in use by another scene": "Comparaison utilisée par une autre scène", + "Esri map unavailable · no swipe": "Carte Esri indisponible · pas de comparaison", + "Swipe needs a globe map": "La comparaison nécessite une carte du globe", + "Imagery stays on Esri · CLEAR to use Google 3D": "L'imagerie reste sur Esri · EFFACER pour utiliser Google 3D", + "Imagery catalog unavailable": "Catalogue d'images indisponible", + "Catalog truncated · a newer clear day may exist": "Catalogue tronqué · un jour dégagé plus récent peut exister", + "{label} catalog unavailable · {detail}": "Catalogue {label} indisponible · {detail}", + "Daily overview for today may still be empty until the pass": "La vue d'ensemble quotidienne peut rester vide jusqu'au passage du satellite", + "Box and images cleared": "Zone et images effacées", + "MORE DETAIL · 30 m": "PLUS DE DÉTAIL · 30 m", + "Sentinel-2 and Landsat via HLS, 30 m, every 2–6 days": "Sentinel‑2 et Landsat via HLS, 30 m, tous les 2 à 6 jours", + "DAILY OVERVIEW · 250 m": "VUE QUOTIDIENNE · 250 m", + "VIIRS daily mosaic, 250 m, follows broad changes; little detail under 25 km": "Mosaïque quotidienne VIIRS, 250 m, suit les changements à grande échelle ; peu de détail sous 25 km", + "Sentinel-2": "Sentinel‑2", + "Sentinel-2 via HLS": "Sentinel‑2 via HLS", + "Landsat 8/9": "Landsat 8/9", + "Landsat 8/9 via HLS": "Landsat 8/9 via HLS", + "Daily overview": "Vue quotidienne", + "Box edges must be finite": "Coordonnées de la zone non valides", + "Longitudes must be within ±180°": "Les longitudes doivent être comprises entre −180° et +180°", + "Select one side of the dateline": "Ne traversez pas la ligne de changement de date", + "Box must enclose an area": "La zone doit délimiter une surface", "Add the full Starlink broadband shell (thousands of extra points)": "Ajouter toute la constellation Starlink (des milliers de points en plus)", "Loading the Starlink shell…": "Chargement de la constellation Starlink…", "Starlink {detail} — click to retry": "Starlink {detail} — cliquer pour réessayer", @@ -286,67 +1028,570 @@ "DENSE ···": "DENSE ···", "DENSE ✕": "DENSE ✕", "DENSE": "DENSE", - "Syncing flow · Roads: {source}": "Synchro du flux · Routes : {source}", - "LIVE · Roads: {source} · Roads without flow hidden": "LIVE · Routes : {source} · Routes sans flux masquées", - "LIVE · Roads: {source} · No flow roads in view": "LIVE · Routes : {source} · Aucune route avec flux en vue", - "LIVE · Roads: {source} · Flow {percent}%": "LIVE · Routes : {source} · Flux {percent}%", - "SIMULATED · Roads: {source} · Flow {percent}%": "SIMULÉ · Routes : {source} · Flux {percent}%", - "Syncing flow · Roads: OpenStreetMap · Flow: TomTom · Unmatched: simulated": "Synchro du flux · Routes : OpenStreetMap · Flux : TomTom · Non appariées : simulées", - "LIVE · Roads: OpenStreetMap · Flow: TomTom · {percent}% cov · Unmatched: simulated": "LIVE · Routes : OpenStreetMap · Flux : TomTom · {percent}% couv. · Non appariées : simulées", - "LIVE · Roads: OpenStreetMap · Flow: TomTom · {percent}% cov": "LIVE · Routes : OpenStreetMap · Flux : TomTom · {percent}% couv.", - "SIMULATED · Roads: OpenStreetMap · Flow: TomTom (no matches)": "SIMULÉ · Routes : OpenStreetMap · Flux : TomTom (aucune correspondance)", + "CelesTrak unreachable": "CelesTrak injoignable", + "DOCKED · {name} · +{extra}": "AMARRÉ · {name} · +{extra}", + "DOCKED · {name}": "AMARRÉ · {name}", + "{name} needs the Google 3D map: choose it under MAP SOURCE": "{name} nécessite la carte Google 3D : choisissez-la dans SOURCE CARTE", + "zoom in to a street to open {name}": "zoomez sur une rue pour ouvrir {name}", + "loading coverage...": "chargement de la couverture…", + "No street-level imagery within {radius} m of that point": "Aucune image au niveau de la rue à moins de {radius} m de ce point", + "No street-level imagery within {radius} m of the view centre": "Aucune image au niveau de la rue à moins de {radius} m du centre de la vue", + "Zoom in to see street-level coverage": "Zoomez pour voir la couverture au niveau de la rue", + "Point the camera at the ground for street-level coverage": "Orientez la caméra vers le sol pour voir la couverture au niveau de la rue", + "Coverage tile failed": "Échec de la tuile de couverture", + "The photo could not be loaded": "Impossible de charger la photo", + "{name} photo. ← and → step along the sequence. On a 360° photo, drag or use Shift+← →, ↑ ↓ to look around, and + − to zoom": "Photo {name}. ← et → parcourent la séquence. Sur une photo à 360°, faites glisser ou utilisez Shift+← →, ↑ ↓ pour regarder autour, et + − pour zoomer", + "{name} street-level photo": "Photo {name} au niveau de la rue", + "Previous photo in this sequence (←)": "Photo précédente de la séquence (←)", + "Next photo in this sequence (→)": "Photo suivante de la séquence (→)", + "Aim the middle of the view at a street to look for imagery there": "Visez une rue avec le centre de la vue pour y chercher des images", + "KEY REJECTED": "CLÉ REFUSÉE", + "GOOGLE_MAPS_API_KEY is not set": "GOOGLE_MAPS_API_KEY n'est pas définie", + "The Google Maps JavaScript API could not load": "Impossible de charger l'API Google Maps JavaScript", + "Google Street View": "Google Street View", + "GOOGLE STREET VIEW": "GOOGLE STREET VIEW", + "Google refused GOOGLE_MAPS_API_KEY for Street View — check that the Maps JavaScript API is enabled for it and this site is an allowed referrer": "Google a refusé GOOGLE_MAPS_API_KEY pour Street View — vérifiez que l'API Maps JavaScript est activée pour cette clé et que ce site figure parmi les référents autorisés", + "Street View did not answer — check the network, and that the Maps JavaScript API is enabled for GOOGLE_MAPS_API_KEY": "Street View n'a pas répondu — vérifiez le réseau et que l'API Maps JavaScript est activée pour GOOGLE_MAPS_API_KEY", + "click a street to open Street View": "cliquez sur une rue pour ouvrir Street View", + "Street View has no imagery for this place": "Street View n'a pas d'images pour ce lieu", + "KartaView has no position for this photo": "KartaView n'a pas de position pour cette photo", + "The KartaView photo could not be loaded": "Impossible de charger la photo KartaView", + "zoom in to see KartaView coverage": "zoomez pour voir la couverture KartaView", + "no KartaView photos in view": "aucune photo KartaView dans la vue", + "KartaView is rate-limiting requests — they resume on their own": "KartaView limite les requêtes — elles reprendront d'elles-mêmes", + "KartaView’s photos here are archived and cannot be shown": "Les photos KartaView de cet endroit sont archivées et ne peuvent pas être affichées", + "KartaView did not filter this area in time — move the map to ask again": "KartaView n'a pas filtré cette zone à temps — déplacez la carte pour relancer la demande", + "None of KartaView’s photos here pass the imagery filter": "Aucune photo KartaView de cet endroit ne passe le filtre d'images", + "KartaView did not answer in time — try again": "KartaView n'a pas répondu à temps — réessayez", + "KartaView could not be reached — check the network": "KartaView est injoignable — vérifiez le réseau", + "KartaView sent an answer that could not be read": "KartaView a envoyé une réponse illisible", + "KartaView is rate-limiting requests": "KartaView limite les requêtes", + "KartaView sent too much data": "KartaView a envoyé trop de données", + "KartaView is rate-limiting requests — try again in a moment": "KartaView limite les requêtes — réessayez dans un instant", + "KartaView has no such photo": "Cette photo n'existe pas sur KartaView", + "Mapillary rejected MAPILLARY_CLIENT_TOKEN — replace it in Provider Settings": "Mapillary a refusé MAPILLARY_CLIENT_TOKEN — remplacez-le dans les paramètres des fournisseurs", + "Coverage requests are being rate-limited — they resume on their own": "Les requêtes de couverture sont limitées — elles reprendront d'elles-mêmes", + "The Panoramax photo could not be loaded": "Impossible de charger la photo Panoramax", + "Panoramax is busy — coverage resumes on its own": "Panoramax est saturé — la couverture reprendra d'elle-même", + "no Panoramax photos in view": "aucune photo Panoramax dans la vue", + "no Panoramax photos here match the filters": "aucune photo Panoramax de cet endroit ne correspond aux filtres", + "Panoramax sent a map tile that could not be read": "Panoramax a envoyé une tuile de carte illisible", + "This Panoramax photo is no longer available": "Cette photo Panoramax n'est plus disponible", + "zoom in to see Panoramax coverage": "zoomez pour voir la couverture Panoramax", + "Panoramax did not answer in time — try again": "Panoramax n'a pas répondu à temps — réessayez", + "Panoramax could not be reached — check the connection": "Panoramax est injoignable — vérifiez la connexion", + "Panoramax sent too much data": "Panoramax a envoyé trop de données", + "Panoramax is busy": "Panoramax est saturé", + "Panoramax sent an unreadable answer": "Panoramax a envoyé une réponse illisible", + "Sequence images unavailable": "Images de la séquence indisponibles", + "No street-level imagery providers configured": "Aucun fournisseur d'images au niveau de la rue configuré", + "(by upload date)": "(par date de mise en ligne)", + "Open the Street Level panel to view imagery": "Ouvrez le panneau Niveau rue pour voir les images", + "Image could not be opened": "Impossible d'ouvrir l'image", + "TeleGeography load failed": "Échec du chargement de TeleGeography", + "UNAVAILABLE · {source} · Roads unavailable": "INDISPONIBLE · {source} · Routes indisponibles", + "Roads: {source}": "Routes : {source}", + "TomTom roads unavailable while the traffic service is unreachable": "Routes TomTom indisponibles tant que le service de trafic est injoignable", + "Hybrid unavailable while the traffic service is unreachable": "Mode hybride indisponible tant que le service de trafic est injoignable", + "TomTom roads need a TomTom key": "Les routes TomTom nécessitent une clé TomTom", + "Hybrid needs a TomTom key": "Le mode hybride nécessite une clé TomTom", + "Local surface still loading": "Surface locale encore en chargement", + "Partial coverage": "Couverture partielle", + "Detailed roads unavailable": "Routes détaillées indisponibles", + "Reduced detail coverage": "Couverture moins détaillée", + "TomTom roads only, each with its live flow": "Routes TomTom seulement, chacune avec son flux en direct", + "TomTom roads only, each with its live flow (needs a TomTom key)": "Routes TomTom seulement, chacune avec son flux en direct (nécessite une clé TomTom)", + "OpenStreetMap roads, with TomTom flow matched when available": "Routes OpenStreetMap, avec le flux TomTom associé quand il est disponible", + "TomTom roads first; OpenStreetMap fills the rest, simulated": "Routes TomTom d'abord ; OpenStreetMap complète le reste, en simulation", + "TomTom roads first; OpenStreetMap fills the rest, simulated (needs a TomTom key)": "Routes TomTom d'abord ; OpenStreetMap complète le reste, en simulation (nécessite une clé TomTom)", + "Hybrid": "Hybride", + "TomTom key unavailable": "Clé TomTom indisponible", + "TomTom daily budget reached": "Quota quotidien TomTom atteint", + "TomTom upstream unreachable": "Serveur TomTom injoignable", + "TomTom flow unavailable": "Flux TomTom indisponible", + "SIMULATED — {reason}": "SIMULÉ — {reason}", + "Syncing flow · Roads: {source}": "Synchro du flux · Routes : {source}", + "LIVE · Roads: {source} · Roads without flow hidden": "DIRECT · Routes : {source} · Routes sans flux masquées", + "LIVE · Roads: {source} · No flow roads in view": "DIRECT · Routes : {source} · Aucune route avec flux dans la vue", + "LIVE · Roads: {source} · Flow {percent}%": "DIRECT · Routes : {source} · Flux {percent} %", + "SIMULATED · Roads: {source} · Flow {percent}%": "SIMULÉ · Routes : {source} · Flux {percent} %", + "Syncing flow · Roads: OpenStreetMap · Flow: TomTom · Unmatched: simulated": "Synchro du flux · Routes : OpenStreetMap · Flux : TomTom · Non appariées : simulées", + "LIVE · Roads: OpenStreetMap · Flow: TomTom · {percent}% cov · Unmatched: simulated": "DIRECT · Routes : OpenStreetMap · Flux : TomTom · couv. {percent} % · Non appariées : simulées", + "LIVE · Roads: OpenStreetMap · Flow: TomTom · {percent}% cov": "DIRECT · Routes : OpenStreetMap · Flux : TomTom · couv. {percent} %", + "SIMULATED · Roads: OpenStreetMap · Flow: TomTom (no matches)": "SIMULÉ · Routes : OpenStreetMap · Flux : TomTom (aucune correspondance)", "SIMULATED — traffic service unreachable": "SIMULÉ — service de trafic injoignable", - "SIMULATED — add TomTom key for live": "SIMULÉ — ajoutez une clé TomTom pour le live", - "AIS: {name}": "AIS : {name}", - "{type} SPD: {speed} HDG: {heading}": "{type} VIT : {speed} CAP : {heading}", + "SIMULATED — add TomTom key for live": "SIMULÉ — ajoutez une clé TomTom pour le direct", + "OpenFreeMap tiles rate-limited": "Tuiles OpenFreeMap : limite de requêtes atteinte", + "OpenFreeMap tiles timed out": "Délai dépassé pour les tuiles OpenFreeMap", + "OpenFreeMap tiles unavailable": "Tuiles OpenFreeMap indisponibles", + "occupancy|empty": "vide", + "occupancy|many seats available": "nombreuses places assises", + "occupancy|few seats available": "peu de places assises", + "occupancy|standing room only": "places debout seulement", + "occupancy|crushed standing room only": "bondé, places debout seulement", + "occupancy|full": "complet", + "occupancy|not accepting passengers": "n'accepte pas de passagers", + "occupancy|not boardable": "embarquement impossible", + "Route {route}": "Ligne {route}", + "Vehicle {vehicle}": "Véhicule {vehicle}", + "vehicle motion|Stopped": "À l'arrêt", + "No recent fix": "Aucune position récente", + "Waiting for update": "En attente de mise à jour", + "Moving": "En mouvement", + "reported {speed} km/h": "vitesse signalée : {speed} km/h", + "reported hdg {heading}°": "cap signalé : {heading}°", + "Last report: stopped at stop {stop}": "Dernier signalement : à l'arrêt {stop}", + "Last report: arriving at stop {stop}": "Dernier signalement : arrivée à l'arrêt {stop}", + "Last report: next stop {stop}": "Dernier signalement : prochain arrêt {stop}", + "Shown at street level · depth not in the feed": "Affiché au niveau de la rue · profondeur absente du flux", + "Reported {seconds} s ago": "Signalé il y a {seconds} s", + "Reported {minutes} min ago": "Signalé il y a {minutes} min", + "shown {seconds} s behind": "affiché avec {seconds} s de retard", + "{reported} (feed time)": "{reported} (heure du flux)", + "Available trail: {minutes} min (limited)": "Trace disponible : {minutes} min (limitée)", + "Available trail: {minutes} min": "Trace disponible : {minutes} min", + "Bus": "Bus", + "Tram": "Tramway", + "Subway": "Métro", + "Train": "Train", + "Ferry": "Ferry", + "Transit vehicle": "Véhicule de transport en commun", + "AIS: {name}": "AIS : {name}", + "{type} SPD: {speed} HDG: {heading}": "{type} SPD : {speed} HDG : {heading}", "VESSEL": "NAVIRE", - "POS: LIVE": "POS : LIVE", - "POS: {time}Z": "POS : {time}Z", + "{speed}KT": "{speed} ND", + "{heading}DEG": "{heading}°", + "POS: LIVE": "POS : DIRECT", + "POS: {time}Z": "POS : {time}Z", + "AIS live load failed": "Échec du chargement AIS en direct", "awaiting first AIS position…": "en attente de la première position AIS…", "awaiting usable AIS positions…": "en attente de positions AIS exploitables…", "awaiting first AIS message…": "en attente du premier message AIS…", + "AISSTREAM_API_KEY not set": "AISSTREAM_API_KEY non définie", + "live feed unsupported": "flux en direct non pris en charge", + "connecting to feed…": "connexion au flux…", + "feed disconnected": "flux déconnecté", + "feed down": "flux hors service", + "feed idle": "flux inactif", + "API key rejected — check AISSTREAM_API_KEY": "Clé API refusée — vérifiez AISSTREAM_API_KEY", + "feed silent {seconds}s — no AIS data": "flux muet depuis {seconds} s — aucune donnée AIS", + "feed silent — no AIS data": "flux muet — aucune donnée AIS", + "feed down — retrying slowly (attempt {attempt})": "flux hors service — nouvel essai espacé (tentative {attempt})", + "reconnecting to feed… (attempt {attempt})": "reconnexion au flux… (tentative {attempt})", + "feed down — retrying slowly": "flux hors service — nouvel essai espacé", + "reconnecting to feed…": "reconnexion au flux…", + "Focus vessel {name}, MMSI {mmsi}": "Centrer sur le navire {name}, MMSI {mmsi}", + "Hidden by this map source · choose a globe map": "Masqué avec cette source de carte · choisissez une carte du globe", + "Weather image HTTP {status}": "Image météo : HTTP {status}", + "Weather HTTP {status}": "Météo : HTTP {status}", + "Frame unavailable; previous observation retained": "Image indisponible ; observation précédente conservée", + "Weather imagery unavailable": "Imagerie météo indisponible", + "Weather source unavailable; previous observation retained": "Source météo indisponible ; observation précédente conservée", + "Weather unavailable": "Météo indisponible", + "No frame within {gap} min of {time}": "Aucune image à ±{gap} min de {time}", + "No frame within {gap} h of {time}": "Aucune image à ±{gap} h de {time}", + "{hours}h {minutes}m ago": "il y a {hours} h {minutes} min", + "{minutes}m ago": "il y a {minutes} min", + "{state} · {time} · {lag}": "{state} · {time} · {lag}", + "Observed": "Observé", + "History": "Historique", + "Observation unavailable": "Observation indisponible", + "Waiting for observation": "En attente d'observation", + "{detail} · synced": "{detail} · synchro", + "{detail} · nearest": "{detail} · la plus proche", + "RADAR REFLECTIVITY · dBZ": "RÉFLECTIVITÉ RADAR · dBZ", + "LIGHTNING DENSITY · 15 min accumulation": "DENSITÉ DE FOUDRE · cumul sur 15 min", + "GLOBAL INFRARED · hourly": "INFRAROUGE MONDIAL · horaire", + "GOES INFRARED · ~5 min": "INFRAROUGE GOES · ~5 min", + "{state}: {time}": "{state} : {time}", + "Latest observation": "Dernière observation", + "frame {index}/{total}": "image {index}/{total}", + "loading": "chargement", + "Observation: unavailable": "Observation : indisponible", + "Contiguous US · gaps ≠ no rain": "États-Unis contigus · lacunes ≠ absence de pluie", + "Americas + Pacific · not individual strikes": "Amériques + Pacifique · pas des impacts individuels", + "Color: strikes/km²/min ×10³": "Couleur : impacts/km²/min ×10³", + "60°S–60°N · typically 2–3 h delayed": "60°S–60°N · retard habituel de 2 à 3 h", + "North America · infrared imagery": "Amérique du Nord · imagerie infrarouge", + "Reduced motion · history playback unavailable": "Animations réduites · lecture de l'historique indisponible", + "Reduced motion · manual history available": "Animations réduites · historique parcourable manuellement", + "Rain radar · US": "Radar de pluie · États-Unis", + "Lightning density · 15 min": "Densité de foudre · 15 min", + "Satellite clouds": "Nuages satellite", + "Americas + Pacific": "Amériques + Pacifique", + "Global · 60°S–60°N": "Monde · 60°S–60°N", + "North America": "Amérique du Nord", + "Source observations delayed": "Observations de la source en retard", + "Stale source": "Source obsolète", + "Loading next frame…": "Chargement de l'image suivante…", + "Map center outside coverage": "Centre de la carte hors couverture", + "strikes/km²/min ×10³": "impacts/km²/min ×10³", + "N. America": "Am. du Nord", + "Global": "Monde", + "Hourly global mosaic; usually 2–3 hours delayed": "Mosaïque mondiale horaire ; retard habituel de 2 à 3 heures", + "GOES regional clouds; approximately 5-minute updates": "Nuages régionaux GOES ; mise à jour toutes les 5 minutes environ", + "Clouds only": "Nuages seuls", + "Apply the full cloud brightness key; 100% filter strength": "Appliquer toute la clé de luminosité des nuages ; intensité du filtre 100 %", + "Full": "Complète", + "Show the complete infrared image; 0% filter strength": "Afficher l'image infrarouge complète ; intensité du filtre 0 %", + "Soft": "Douce", + "Vivid": "Vive", + "Image opacity; does not alter the observed values": "Opacité de l'image ; ne modifie pas les valeurs observées", + "View US radar": "Voir le radar des États-Unis", + "View Americas & Pacific": "Voir Amériques et Pacifique", + "View coverage": "Voir la couverture", + "{value} strikes/km²/min ×10³ (15-minute density)": "{value} impacts/km²/min ×10³ (densité sur 15 minutes)", + "{value} dBZ radar reflectivity": "{value} dBZ de réflectivité radar", + "STALE · cached source metadata": "OBSOLÈTE · métadonnées de la source en cache", + "Map center is outside source coverage": "Le centre de la carte est hors de la couverture de la source", + "NOAA/NWS 15-minute lightning density derived from Vaisala NLDN/GLD360. Coverage 110°E across the Pacific/Americas to 0°, 25°S–80°N. Not a live strike count, global coverage or a safety warning.": "Densité de foudre sur 15 minutes de NOAA/NWS, dérivée de Vaisala NLDN/GLD360. Couverture de 110°E à 0° à travers le Pacifique et les Amériques, 25°S–80°N. Ce n'est ni un décompte d'impacts en direct, ni une couverture mondiale, ni une alerte de sécurité.", + "NOAA MRMS radar echoes indicate precipitation patterns, not rain rate, a storm warning or a future forecast. Native source approximately 1 km; display is limited to level 6. Frames use exact advertised observation times.": "Les échos radar NOAA MRMS indiquent la structure des précipitations, pas l'intensité de la pluie, une alerte d'orage ou une prévision. Résolution native d'environ 1 km ; l'affichage est limité au niveau 6. Les images utilisent les heures d'observation exactes publiées.", + "GOES-19/18 longwave infrared Band 14 regional; NESDIS global longwave mosaic. Clouds only dims everything but bright, cold cloud tops; a brightness filter, not a cloud mask. Coverage and freshness differ by region.": "Infrarouge grandes longueurs d'onde GOES-19/18, bande 14, régional ; mosaïque mondiale grandes longueurs d'onde NESDIS. Nuages seuls assombrit tout sauf les sommets nuageux brillants et froids ; c'est un filtre de luminosité, pas un masque de nuages. La couverture et la fraîcheur varient selon la région.", + "REGION": "RÉGION", + "IMAGE": "IMAGE", + "FILTER": "FILTRE", + "Cloud filter strength": "Intensité du filtre de nuages", + "OPACITY": "OPACITÉ", + "Infrared decode failed": "Échec du décodage infrarouge", + "Weather prefetch unavailable": "Préchargement météo indisponible", + "Weather tiles unavailable · previous frame retained": "Tuiles météo indisponibles · image précédente conservée", + "Some weather tiles unavailable": "Certaines tuiles météo indisponibles", + "Malformed weather manifest": "Manifeste météo mal formé", + "Weather request timed out": "Délai dépassé pour la requête météo", + "Temperature field unavailable": "Champ de température indisponible", + "Mean sea level pressure field unavailable": "Champ de pression au niveau de la mer indisponible", + "Wind upstream unavailable": "Source amont du vent indisponible", + "{source} HTTP {status}": "{source} : HTTP {status}", + "Wind": "Vent", + "Wind source unavailable": "Source du vent indisponible", + "Forecast · does not follow history": "Prévision · ne suit pas l'historique", + "Wind motion": "Mouvement du vent", + "Wind speed": "Vitesse du vent", + "Sea-level pressure": "Pression au niveau de la mer", + "Air temperature · 2 m": "Température de l'air · 2 m", + "Global · 1° grid": "Monde · grille de 1°", + "{model} forecast · {time}": "Prévision {model} · {time}", + "Loading forecast": "Chargement de la prévision", + "Preparing flow": "Préparation du flux", + "Selected field unavailable": "Champ sélectionné indisponible", + "Cached forecast · stale": "Prévision en cache · obsolète", + "ECMWF IFS surface forecast": "Prévision de surface ECMWF IFS", + "NOAA GFS surface forecast": "Prévision de surface NOAA GFS", + "Reduced motion": "Animations réduites", "Resume": "Reprendre", - "Pause": "Mettre en pause", - "Error: {message}": "Erreur : {message}", + "Pause": "Pause", + "Pause visual flow; forecast time does not advance with animation": "Mettre en pause le flux visuel ; l'heure de prévision n'avance pas avec l'animation", + "None": "Aucun", + "Speed": "Vitesse", + "Pressure": "Pression", + "Temperature": "Température", + "Wind trails with no field shading": "Traînées de vent sans coloration du champ", + "How hard the surface wind is blowing": "Force du vent en surface", + "Sea-level air pressure: broad highs and lows": "Pression de l'air au niveau de la mer : grands anticyclones et dépressions", + "Air temperature two meters above the surface": "Température de l'air à deux mètres au-dessus de la surface", + "Wind speed units": "Unités de vitesse du vent", + "Read wind at map center": "Lire le vent au centre de la carte", + "Read the forecast at the center of the map without changing selection": "Lire la prévision au centre de la carte sans changer la sélection", + "{model} forecast · {field} ({unit})": "Prévision {model} · {field} ({unit})", + "Valid: {time}": "Valide : {time}", + "preparing": "préparation", + "Issued: {time}": "Émise : {time}", + "Selected field unavailable · wind remains visible": "Champ sélectionné indisponible · le vent reste visible", + "{error} · wind remains visible": "{error} · le vent reste visible", + "Surface wind at 10 m. Approximately 1° global grid. Curves follow the 10 m wind field, lifted 12 km for visibility; display height is not weather altitude. View lighting is for readability. Animation shows flow through one fixed forecast; it does not advance time. Color fields drape the globe basemap or the active photorealistic 3D Tiles.": "Vent de surface à 10 m. Grille mondiale d'environ 1°. Les courbes suivent le champ de vent à 10 m, surélevées de 12 km pour rester visibles ; la hauteur affichée n'est pas une altitude météorologique. L'éclairage de la vue sert à la lisibilité. L'animation montre l'écoulement d'une seule prévision fixe ; elle ne fait pas avancer le temps. Les champs colorés recouvrent le fond de carte du globe ou les 3D Tiles photoréalistes actives.", + "MODEL": "MODÈLE", + "FIELD": "CHAMP", + "UNITS": "UNITÉS", + "MOTION": "ANIMATION", + "Forecast": "Prévision", + "N": "N", + "NNE": "NNE", + "NE": "NE", + "ENE": "ENE", + "E": "E", + "ESE": "ESE", + "SE": "SE", + "SSE": "SSE", + "S": "S", + "SSW": "SSO", + "SW": "SO", + "WSW": "OSO", + "W": "O", + "WNW": "ONO", + "NW": "NO", + "NNW": "NNO", + "No surface reading": "Aucune valeur en surface", + "Aim the map center at Earth": "Visez la Terre avec le centre de la carte", + "A location reading needs a loaded forecast and the Earth at the center of the view.": "Une lecture ponctuelle nécessite une prévision chargée et la Terre au centre de la vue.", + "Interpolated model forecast on an approximately 1° grid. Broad weather patterns, not a street-level measurement.": "Prévision de modèle interpolée sur une grille d'environ 1°. Tendances météo générales, pas une mesure à l'échelle de la rue.", + " · calm": " · calme", + " from {direction}": " de {direction}", + "WIND AT {coordinates}": "VENT À {coordinates}", + "{model} · valid {time}": "{model} · valide {time}", + "Wind speed field unavailable": "Champ de vitesse du vent indisponible", + "Globe imagery unavailable": "Imagerie du globe indisponible", + "Globe field image unavailable": "Image du champ sur le globe indisponible", + "Unknown wind model": "Modèle de vent inconnu", + "Unknown weather overlay": "Surcouche météo inconnue", + "Wind request timed out": "Délai dépassé pour la requête de vent", + "Malformed wind manifest": "Manifeste du vent mal formé", + "Malformed wind grid": "Grille du vent mal formée", + "Error: {message}": "Erreur : {message}", "Needs {envVars} — add it in Provider Settings": "Nécessite {envVars} — à ajouter dans les paramètres des fournisseurs", "{label} is unavailable": "{label} est indisponible", "This map stack": "Ce fond de carte", - "{label} unavailable: {hint}": "{label} indisponible : {hint}", + "{label} unavailable: {hint}": "{label} indisponible : {hint}", + "Google 3D tiles unavailable — check the key's API restrictions, quota, or network": "Tuiles Google 3D indisponibles — vérifiez les restrictions d'API de la clé, le quota ou le réseau", + "Needs {envVars} — add it in Provider Settings — or a Cesium ion token for the ion-hosted route": "Nécessite {envVars} — à ajouter dans les paramètres des fournisseurs — ou un jeton Cesium ion pour la variante hébergée par ion", + "Exit cockpit to fly to a camera": "Quittez le cockpit pour rejoindre une caméra", + "Exit cockpit to fly to a location": "Quittez le cockpit pour rejoindre un lieu", + "Exit cockpit to fly to a photo": "Quittez le cockpit pour rejoindre une photo", + "Exit cockpit to fly to a shared view": "Quittez le cockpit pour rejoindre une vue partagée", + "Exit cockpit to fly to a target": "Quittez le cockpit pour rejoindre une cible", + "Exit cockpit to fly to a vessel": "Quittez le cockpit pour rejoindre un navire", + "Exit cockpit to fly to a fire": "Quittez le cockpit pour rejoindre un incendie", + "Exit cockpit to fly to a route": "Quittez le cockpit pour rejoindre un itinéraire", + "Exit cockpit to fly to a file": "Quittez le cockpit pour rejoindre un fichier", + "Exit cockpit to fly to a scene": "Quittez le cockpit pour rejoindre une scène", + "Exit cockpit to view weather coverage": "Quittez le cockpit pour voir la couverture météo", + "Exit cockpit to fly to a cyclone": "Quittez le cockpit pour rejoindre un cyclone", + "Exit cockpit to fly to an aircraft": "Quittez le cockpit pour rejoindre un aéronef", + "Exit cockpit to fly to a satellite": "Quittez le cockpit pour rejoindre un satellite", + "Exit cockpit to frame contacts": "Quittez le cockpit pour cadrer les contacts", "Visible map targets": "Cibles visibles sur la carte", + "Focusing {label}": "Centrage sur {label}", + "Source": "Source", + "Camera ownership changed": "Le contrôle de la caméra a changé", + "Saved project could not be read; storage preserved. Import a valid file to resume saving.": "Le projet enregistré est illisible ; le stockage est conservé. Importez un fichier valide pour reprendre l'enregistrement.", "Ready": "Prêt", - "Loaded: {scene} / {shot}": "Chargé : {scene} / {shot}", - "Cannot capture shot: camera not ready": "Capture impossible : caméra non prête", - "Captured: {scene} / {shot}": "Capturé : {scene} / {shot}", + "Scene layer turned off": "Couche de la scène désactivée", + "Stopped": "Arrêté", + "Scene not saved — existing saved project could not be read. Export edits or import a valid file.": "Scène non enregistrée — le projet enregistré est illisible. Exportez vos modifications ou importez un fichier valide.", + "Scene not saved — {reason}": "Scène non enregistrée — {reason}", + "Scene not saved — browser storage unavailable": "Scène non enregistrée — stockage du navigateur indisponible", + "Loaded: {scene} / {shot}": "Chargé : {scene} / {shot}", + "Cannot update {scene}: shot inventory changed": "Impossible de mettre à jour {scene} : la liste des plans a changé", + "Cannot update {scene}: evidence beats changed": "Impossible de mettre à jour {scene} : les étapes de preuve ont changé", + "Cannot update {scene}: shot bindings are incomplete": "Impossible de mettre à jour {scene} : les liaisons des plans sont incomplètes", + "Updated {count} shots: {scene}": { + "one": "{count} plan mis à jour : {scene}", + "many": "{count} de plans mis à jour : {scene}", + "other": "{count} plans mis à jour : {scene}" + }, + "Appended {count} shots: {scene}": { + "one": "{count} plan ajouté : {scene}", + "many": "{count} de plans ajoutés : {scene}", + "other": "{count} plans ajoutés : {scene}" + }, + "Cannot capture shot: camera not ready": "Capture impossible : caméra non prête", + "Captured: {scene} / {shot}": "Capturé : {scene} / {shot}", "Select a shot first": "Sélectionnez d'abord un plan", - "Updated: {scene} / {shot}": "Mis à jour : {scene} / {shot}", + "Updated: {scene} / {shot}": "Mis à jour : {scene} / {shot}", + "Could not leave scene: {scene}": "Impossible de quitter la scène : {scene}", + "Seeked: {scene} / {shot}": "Position atteinte : {scene} / {shot}", + "Seeking scene clock": "Déplacement dans l'horloge de la scène", "Camera unavailable — exit cockpit first": "Caméra indisponible — quittez d'abord le cockpit", "No shots to run": "Aucun plan à lancer", + "Scene transition limit reached — load a shot to reset": "Limite de transitions de scène atteinte — chargez un plan pour réinitialiser", + "Export failed: {error}": "Échec de l'export : {error}", "Project exported": "Projet exporté", + "Importing project": "Import du projet", + "Imported {file}": "Importé : {file}", + "Import failed: {error}": "Échec de l'import : {error}", + "Import failed (could not read JSON file)": "Échec de l'import (fichier JSON illisible)", + "Layers refused: {layers}": "Couches refusées : {layers}", "Could not exit {mode} — scene layers may be refused": "Impossible de quitter {mode} — les couches de la scène peuvent être refusées", - "Running {index}/{total}: {scene} / {shot}": "Exécution {index}/{total} : {scene} / {shot}", + "Camera move interrupted": "Mouvement de caméra interrompu", + "Scene media timed out": "Délai dépassé pour les médias de la scène", + "Action complete": "Action terminée", + "Action unavailable or cancelled": "Action indisponible ou annulée", + "Scene actions": "Actions de la scène", + "Select a feature or use Tab and Enter to choose an action.": "Sélectionnez un élément ou utilisez Tab et Enter pour choisir une action.", + "Selected feature: {feature}. Choose an action.": "Élément sélectionné : {feature}. Choisissez une action.", + "Running {index}/{total}: {scene} / {shot}": "Exécution {index}/{total} : {scene} / {shot}", "Scene run complete": "Scène terminée", + "Bhote Koshi Evidence Sequence": "Séquence de preuves de la Bhote Koshi", + "Nepal Flood Incident": "Crue au Népal", "Global Flights Radar": "Radar mondial des vols", "Orbital Watch": "Veille orbitale", "Thermal Threat Board": "Tableau des menaces thermiques", "City Overload": "Surcharge urbaine", "Omniscience Pullback": "Recul omniscient", + "Global Incident Context": "Contexte global de l'incident", + "Nepal-Focused Globe Rotation": "Rotation du globe vers le Népal", + "Bhote Koshi Regional Approach": "Approche régionale de la Bhote Koshi", + "Bhote Koshi Nearby Cities": "Villes proches de la Bhote Koshi", + "Bhote Koshi Incident Corridor": "Corridor de l'incident de la Bhote Koshi", + "Bhote Koshi Flood Path": "Tracé de la crue de la Bhote Koshi", + "Bhote Koshi Corridor Overview": "Vue d'ensemble du corridor de la Bhote Koshi", + "Bhote Koshi Upper Valley": "Haute vallée de la Bhote Koshi", + "Upper Valley Collapse": "Effondrement dans la haute vallée", + "Debris-Dammed Lake": "Lac de barrage formé par les débris", + "Nepal-China Border Gate": "Poste frontière Népal-Chine", + "Timure Evidence Cluster": "Groupe d'éléments de preuve de Timure", + "Syabru Besi Passage": "Passage à Syabru Besi", + "Bidur / Trishuli Consequence": "Conséquences à Bidur / Trishuli", + "Final view": "Vue finale", + "Scene {n}": "Scène {n}", "Shot {n}": "Plan {n}", + "the title of scene {scene} is empty or longer than {max} characters": "le titre de la scène {scene} est vide ou dépasse {max} caractères", + "the title of shot {shot} in scene {scene} is empty or longer than {max} characters": "le titre du plan {shot} de la scène {scene} est vide ou dépasse {max} caractères", + "the project is larger than 5 MiB": "le projet dépasse 5 Mio", + "the project has too many shots": "le projet contient trop de plans", + "the scene data failed validation": "les données de la scène n'ont pas passé la validation", + "Could not complete this action. Check the file, references and selected assets.": "Impossible de terminer cette action. Vérifiez le fichier, les références et les ressources sélectionnées.", + "{count} scenes": { + "one": "{count} scène", + "many": "{count} de scènes", + "other": "{count} scènes" + }, + "{count} shots": { + "one": "{count} plan", + "many": "{count} de plans", + "other": "{count} plans" + }, + "{count} data packs": { + "one": "{count} paquet de données", + "many": "{count} de paquets de données", + "other": "{count} paquets de données" + }, + "{scene} / {pack}: {status}. File: {path}. {attribution} · {license}": "{scene} / {pack} : {status}. Fichier : {path}. {attribution} · {license}", + "Unavailable layers: {layers}": "Couches indisponibles : {layers}", + "Uses registered content or linked media. Those external files are not included in a scene bundle. Their original notices still apply.": "Utilise du contenu enregistré ou des médias liés. Ces fichiers externes ne sont pas inclus dans une archive de scène. Leurs mentions d'origine restent applicables.", + "{bytes} bundled bytes verified. Files stay in memory for this session. Reimport the bundle after reloading the app.": "{bytes} octets de l'archive vérifiés. Les fichiers restent en mémoire pour cette session. Réimportez l'archive après avoir rechargé l'application.", + "Review scene import": "Vérifier l'import de scène", + "Nothing is loaded or changed until you apply this file.": "Rien n'est chargé ni modifié tant que vous n'appliquez pas ce fichier.", + "Ready to import": "Prêt à importer", + "Apply replaces the current project. Export your current project first if you want to keep both.": "Appliquer remplace le projet actuel. Exportez d'abord votre projet actuel si vous voulez garder les deux.", + "Apply import": "Appliquer l'import", + "Import was not applied. The current project may have changed.": "L'import n'a pas été appliqué. Le projet actuel a peut-être changé.", + "Select a scene and shot first": "Sélectionnez d'abord une scène et un plan", + "Edit scene details": "Modifier les détails de la scène", + "Camera positions use degrees and meters above the ellipsoid. Drafts are validated before they replace your saved scene.": "Les positions de caméra sont en degrés et en mètres au-dessus de l'ellipsoïde. Les brouillons sont validés avant de remplacer votre scène enregistrée.", + "Anchors and data packs": "Ancres et paquets de données", + "Shot camera, timing, packs and actions": "Caméra, minutage, paquets et actions du plan", + "New anchor ID": "ID de la nouvelle ancre", + "Capture camera as anchor": "Capturer la caméra comme ancre", + "Anchor added to draft": "Ancre ajoutée au brouillon", + "Set move start to current camera": "Définir le début du mouvement sur la caméra actuelle", + "Move added to draft; destination remains the shot camera": "Mouvement ajouté au brouillon ; la destination reste la caméra du plan", + "Use ordinary flight": "Utiliser un vol normal", + "Invalid shot JSON": "JSON de plan non valide", + "Apply details": "Appliquer les détails", + "Select a scene first": "Sélectionnez d'abord une scène", + "Share selected scene": "Partager la scène sélectionnée", + "Scene JSON preserves authored settings and attribution. It does not include asset files. Bundles include only pack files you choose here or previously imported bundle files.": "Le JSON de scène conserve les réglages de l'auteur et l'attribution. Il n'inclut pas les fichiers de ressources. Les archives n'incluent que les fichiers de paquets choisis ici ou ceux d'archives déjà importées.", + "Download scene JSON": "Télécharger le JSON de scène", + "Choose data-pack files": "Choisir des fichiers de paquet de données", + "Or choose a data-pack folder": "Ou choisir un dossier de paquet de données", + "Download asset bundle": "Télécharger l'archive de ressources", + "Asset bundle downloaded": "Archive de ressources téléchargée", + "No RTL-SDR device selected": "Aucun appareil RTL-SDR sélectionné", + "WebUSB requires desktop Chrome or Edge on localhost/HTTPS": "WebUSB nécessite Chrome ou Edge sur ordinateur, en localhost/HTTPS", + "RTL-SDR access failed; close other SDR apps and check USB permissions": "Accès au RTL-SDR impossible ; fermez les autres applications SDR et vérifiez les autorisations USB", + "RTL-SDR connection failed": "Échec de la connexion au RTL-SDR", + "Receiving 1090 MHz ADS-B": "Réception ADS-B sur 1090 MHz", + "Receiving broadcast FM": "Réception de la radio FM", + "Connect an RTL-SDR to begin.": "Connectez un RTL-SDR pour commencer.", + "WebUSB is unavailable in this browser": "WebUSB n'est pas disponible dans ce navigateur", + "USB work abandoned after a stalled transfer": "Opération USB abandonnée après un transfert bloqué", + "SDR decoder worker failed": "Échec du processus du décodeur SDR", + "SDR decoder did not start; receiver stopped": "Le décodeur SDR n'a pas démarré ; récepteur arrêté", + "SDR decoder stopped responding; receiver stopped": "Le décodeur SDR ne répond plus ; récepteur arrêté", + "SDR decoder fell behind; receiver stopped": "Le décodeur SDR a pris du retard ; récepteur arrêté", + "WebUSB requires desktop Chrome or Edge": "WebUSB nécessite Chrome ou Edge sur ordinateur", + "Waiting for an RTL-SDR device…": "En attente d'un appareil RTL-SDR…", + "Browser audio is suspended; press Connect again to resume it": "L'audio du navigateur est suspendu ; appuyez à nouveau sur Connecter pour le reprendre", + "RTL-SDR sample stream stopped": "Flux d'échantillons RTL-SDR arrêté", + "Switching to {mode}…": "Passage en {mode}…", + "Browser audio is suspended; select FM again to resume it": "L'audio du navigateur est suspendu ; sélectionnez à nouveau FM pour le reprendre", + "RTL-SDR gain change failed": "Échec du changement de gain du RTL-SDR", + "Tuned to {mhz} MHz FM": "Réglé sur {mhz} MHz FM", + "Seeking up…": "Recherche vers le haut…", + "Seeking down…": "Recherche vers le bas…", + "Seek stopped": "Recherche arrêtée", + "Scanning {mhz} MHz…": "Balayage de {mhz} MHz…", + "Found {mhz} MHz · {snr} dB": "Trouvé {mhz} MHz · {snr} dB", + "FM signal found at {mhz} MHz": "Signal FM trouvé sur {mhz} MHz", + "No FM signal found": "Aucun signal FM trouvé", + "Browser location is unavailable": "La position du navigateur est indisponible", + "Receiver location was not granted": "L'accès à la position du récepteur n'a pas été accordé", + "RTL-SDR disconnected": "RTL-SDR déconnecté", + "Upstream response too large": "Réponse du serveur amont trop volumineuse", + "Vector tile request timed out": "Délai dépassé pour les tuiles vectorielles", + "Vector tiles unavailable": "Tuiles vectorielles indisponibles", + "Vector tile metadata unavailable": "Métadonnées des tuiles vectorielles indisponibles", + "Zoom in for vector tile coverage": "Zoomez pour charger les tuiles vectorielles", + "Saturation": "Saturation", + "Edge Thickness": "Épaisseur des contours", + "Contrast": "Contraste", + "Grain": "Grain", + "Vignette": "Vignettage", + "Pixelation": "Pixellisation", + "Distortion": "Distorsion", + "Instability": "Instabilité", "Density": "Densité", + "Gain": "Gain", "Bloom": "Bloom", + "Scanlines": "Lignes de balayage", + "Sensitivity": "Sensibilité", + "WHOT/BHOT": "WHOT/BHOT", + "Ironbow": "Ironbow", + "unsaved CCTV calibration": "la calibration CCTV non enregistrée", + "the open cockpit": "le cockpit ouvert", + "Switching language reloads the page. This will be lost: {items}. Switch anyway?": "Changer de langue recharge la page. Ceci sera perdu : {items}. Changer quand même ?", "VISUAL PRESETS": "PRÉRÉGLAGES VISUELS", "LOCATION": "LIEU", "CONTACTS — nearest planes · vessels · sites": "CONTACTS — avions · navires · sites les plus proches", "SPACE MISSIONS — launches & orbital assets": "MISSIONS SPATIALES — lancements et objets orbitaux", - "LIVE SIGNALS": "SIGNAUX LIVE", - "Contacts could not complete the requested transition; try again": "Les contacts n'ont pas pu effectuer la transition demandée ; réessayez", + "LIVE SIGNALS": "SIGNAUX EN DIRECT", + "Contacts could not complete the requested transition; try again": "Les contacts n'ont pas pu effectuer la transition demandée ; réessayez", "CCTV layer unavailable": "Couche CCTV indisponible", - "Link copied!": "Lien copié !", + "Link shared": "Lien partagé", + "Link copied!": "Lien copié !", "Copy failed": "Échec de la copie", + "Return map to straight-down view": "Remettre la carte en vue verticale", + "Tilt map to oblique view": "Incliner la carte en vue oblique", + "Reset map to north up. Current heading {heading} degrees": "Réorienter la carte nord en haut. Cap actuel {heading} degrés", + "Tilted view": "Vue inclinée", + "Straight-down view": "Vue verticale", + "North up": "Nord en haut", "CCTV calibration saved": "Calibration CCTV enregistrée", + "HDG": "HDG", + "PITCH": "INCL.", + "FOV": "FOV", + "RANGE": "PORTÉE", + "HGT": "HAUT.", + "ΔN": "ΔN", + "ΔE": "ΔE", + "{value}m": "{value} m", "CCTV calibration reset": "Calibration CCTV réinitialisée", "ADJUST ON": "AJUSTER ON", "ADJUST": "AJUSTER", + "SNAPSHOT": "INSTANTANÉ", + "LIVE": "DIRECT", + "UPSTREAM": "AMONT", + "SYNTHETIC": "SYNTHÉTIQUE", + "CONFIGURED": "CONFIGURÉ", + "SEED": "CATALOGUE", "UNKNOWN": "INCONNU", + "OK": "OK", + "ERROR": "ERREUR", + "Live HLS connected": "HLS en direct connecté", + "Live HLS unavailable": "HLS en direct indisponible", + "No stream URL configured": "Aucune URL de flux configurée", + "Live stream connected": "Flux en direct connecté", + "Snapshot feed connected": "Flux d'instantanés connecté", + "Media fetch failed": "Échec de la récupération du média", + "Upstream snapshot active": "Instantané amont actif", + "Fallback Street View frame": "Image Street View de secours", + "Upstream unavailable": "Source amont indisponible", + "No source configured": "Aucune source configurée", + "Configured source": "Source configurée", + "Configured Source": "Source configurée", + "Synthetic fallback": "Secours synthétique", + "Upstream HTTP {status}": "Source amont : HTTP {status}", + "Unexpected media type {type}": "Type de média inattendu : {type}", "SOURCE · UNKNOWN": "SOURCE · INCONNUE", "FRAME · LOADING": "IMAGE · CHARGEMENT", "FRAME · UNAVAILABLE": "IMAGE · INDISPONIBLE", @@ -369,10 +1614,12 @@ "{city} · HDG {heading} · FOV {fov} · RANGE {range}m · {projection}{calBadge} · {provider}{status}": "{city} · HDG {heading} · FOV {fov} · PORTÉE {range}m · {projection}{calBadge} · {provider}{status}", "{count} cameras loaded · click a camera to activate": { "one": "{count} caméra chargée · cliquer sur une caméra pour l'activer", + "many": "{count} de caméras chargées · cliquer sur une caméra pour l'activer", "other": "{count} caméras chargées · cliquer sur une caméra pour l'activer" }, "{count} cameras loaded · enable CCTV to activate": { "one": "{count} caméra chargée · activer CCTV pour l'utiliser", + "many": "{count} de caméras chargées · activer CCTV pour les utiliser", "other": "{count} caméras chargées · activer CCTV pour les utiliser" }, "Enable CCTV to load camera intersections": "Activez CCTV pour charger les intersections de caméras", @@ -396,17 +1643,20 @@ "CYCLE ON": "DÉFIL. ON", "CYCLE OFF": "DÉFIL. OFF", "Stop automatic page cycling. Previous, Next, and the SIG/NEWS/LOCAL tabs stay available.": "Arrêter le défilement automatique des pages. Précédent, Suivant et les onglets SIG/ACTUS/LOCAL restent disponibles.", - "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.": "Faire défiler automatiquement les pages du briefing toutes les 9 secondes (Signaux → Actus → Local). En pause pendant le survol ou le focus du panneau. Les signaux live s'actualisent en continu dans les deux cas.", + "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.": "Faire défiler automatiquement les pages du briefing toutes les 9 secondes (Signaux → Actus → Local). Pause pendant le survol ou quand le panneau a le focus. Les signaux en direct s'actualisent en continu dans les deux cas.", "ACQUIRING REGIONAL NEWS": "ACQUISITION DES ACTUS RÉGIONALES", "REGIONAL NEWS UNAVAILABLE": "ACTUS RÉGIONALES INDISPONIBLES", "RESOLVING REGION": "RÉSOLUTION DE LA RÉGION", "REGION UNAVAILABLE": "RÉGION INDISPONIBLE", "NO RECENT LOCATION MATCHES": "AUCUNE CORRESPONDANCE RÉCENTE AU LIEU", "{domain} · {age}": "{domain} · {age}", - "CLOUD {pct}%": "NUAGES {pct}%", + "{value} KM/H": "{value} KM/H", + "CLOUD {pct}%": "NUAGES {pct} %", "CLOUD UNKNOWN": "NUAGES INCONNUS", "{source} · LOCATION QUERY": "{source} · REQUÊTE DE LIEU", "REGIONAL NEWS": "ACTUS RÉGIONALES", + "{label} · {radius} AIR/SEA WINDOW": "{label} · FENÊTRE AIR/MER {radius}", + "{scope} · INSTALLATIONS {coverage}": "{scope} · INSTALLATIONS : {coverage}", "CONTEXT STANDBY": "CONTEXTE EN VEILLE", "ENABLE GLOBAL CONTEXT FOR PROXIMITY PINGS": "ACTIVER LE CONTEXTE GLOBAL POUR LES PINGS DE PROXIMITÉ", "CONTACT LOST · LAST KNOWN READOUT · NOT AN ALL-CLEAR": "CONTACT PERDU · DERNIÈRE POSITION CONNUE · PAS UN FEU VERT", @@ -421,15 +1671,20 @@ "R": "D", "{count} INPUTS UNKNOWN · NOT AN ALL-CLEAR": { "one": "{count} ENTRÉE INCONNUE · PAS UN FEU VERT", + "many": "{count} D'ENTRÉES INCONNUES · PAS UN FEU VERT", "other": "{count} ENTRÉES INCONNUES · PAS UN FEU VERT" }, "AVAILABLE INPUTS CURRENT · NOT AN ALL-CLEAR": "ENTRÉES DISPONIBLES À JOUR · PAS UN FEU VERT", + "SQUAWK {code} · {status}": "SQUAWK {code} · {status}", + "ADS-B PRIORITY · {status}": "PRIORITÉ ADS-B · {status}", + "ADS-B EMERGENCY · {status}": "URGENCE ADS-B · {status}", "AIRCRAFT": "AÉRONEF", "ACQUIRING SURFACE": "ACQUISITION SURFACE", "SURFACE FALLBACK": "SECOURS SURFACE", - "STALE FEED": "FLUX PÉRIMÉ", - "LIVE TRACK": "PISTE LIVE", + "STALE FEED": "FLUX OBSOLÈTE", + "LIVE TRACK": "PISTE EN DIRECT", "COMMERCIAL": "COMMERCIAL", + "{aircraftClass} · {emergency} · {feedState}": "{aircraftClass} · {emergency} · {feedState}", "{aircraftClass} · {feedState} · COURSE ALIGNED": "{aircraftClass} · {feedState} · CAP ALIGNÉ", "ARROW · ESTIMATED DIRECTION": "FLÈCHE · DIRECTION ESTIMÉE", "ROUTE DATA UNAVAILABLE": "DONNÉES DE ROUTE INDISPONIBLES", @@ -443,8 +1698,8 @@ "Anime": "Anime", "Noir": "Noir", "Snow": "Neige", - "Current cockpit vision style: {style}. Activate for next style.": "Style de vision actuel du cockpit : {style}. Activer pour le style suivant.", - "Current style: {style} — click for next": "Style actuel : {style} — cliquer pour le suivant", + "Current cockpit vision style: {style}. Activate for next style.": "Style de vision actuel du cockpit : {style}. Activer pour le style suivant.", + "Current style: {style} — click for next": "Style actuel : {style} — cliquer pour le suivant", "Collapse Contact panel": "Réduire le panneau Contact", "Expand Contact panel": "Développer le panneau Contact", "Collapse contact panel": "Réduire le panneau contact", @@ -456,6 +1711,7 @@ "OBSERVED / MAPPED PINGS": "PINGS OBSERVÉS / CARTOGRAPHIÉS", "SOURCE-BACKED EVENTS · NO SYNTHETIC NEWS": "ÉVÉNEMENTS SOURCÉS · AUCUNE ACTU SYNTHÉTIQUE", "LATEST LOCATION-MATCHED REPORTING": "DERNIERS REPORTAGES SELON LE LIEU", + "{source} · LOCATION QUERY · RECENT": "{source} · REQUÊTE DE LIEU · RÉCENT", "LOCAL INFO": "INFOS LOCALES", "PLACE / CONDITIONS / POSITION": "LIEU / CONDITIONS / POSITION", "TIME UNKNOWN": "HEURE INCONNUE", @@ -471,6 +1727,7 @@ "DISTANCE UNKNOWN": "DISTANCE INCONNUE", "{count} INPUTS UNKNOWN": { "one": "{count} ENTRÉE INCONNUE", + "many": "{count} D'ENTRÉES INCONNUES", "other": "{count} ENTRÉES INCONNUES" }, "SOURCE STATUS UNAVAILABLE": "ÉTAT DE LA SOURCE INDISPONIBLE", @@ -478,28 +1735,63 @@ "Reclassify as TR-3B": "Reclasser en TR-3B", "TRACK ACQUIRED": "PISTE ACQUISE", "{label} · COURSE {heading}°": "{label} · CAP {heading}°", - "Context could not restore every layer; try again": "Le contexte n'a pas pu restaurer toutes les couches ; réessayez", + "Context could not restore every layer; try again": "Le contexte n'a pas pu restaurer toutes les couches ; réessayez", "No selected data layers": "Aucune couche de données sélectionnée", "{count} data layers could not be cleared": { "one": "{count} couche de données n'a pas pu être effacée", + "many": "{count} de couches de données n'ont pas pu être effacées", "other": "{count} couches de données n'ont pas pu être effacées" }, "Cleared {count} data layers": { "one": "{count} couche de données effacée", + "many": "{count} de couches de données effacées", "other": "{count} couches de données effacées" }, "Selected data layers could not be cleared": "Impossible d'effacer les couches de données sélectionnées", - "Space Missions could not complete the requested transition; try again": "Les missions spatiales n'ont pas pu effectuer la transition demandée ; réessayez", + "Space Missions could not complete the requested transition; try again": "Les missions spatiales n'ont pas pu effectuer la transition demandée ; réessayez", "Nearby installations refreshed": "Installations proches actualisées", - "Nearby installations could not be refreshed; try again": "Impossible d'actualiser les installations proches ; réessayez", + "Nearby installations could not be refreshed; try again": "Impossible d'actualiser les installations proches ; réessayez", "Space Missions cancellation could not restore the previous layer state": "L'annulation des missions spatiales n'a pas pu restaurer l'état précédent des couches", "That layer is unavailable in the current Context mode": "Cette couche est indisponible dans le mode Contexte actuel", "{layerId} could not {action} cleanly": "{layerId} n'a pas pu {action} proprement", "start": "démarrer", "stop": "s'arrêter", - "{mode} could not start because another layer did not stop cleanly": "Impossible de démarrer {mode} : une autre couche ne s'est pas arrêtée proprement", + "{mode} could not start because another layer did not stop cleanly": "Impossible de démarrer {mode} : une autre couche ne s'est pas arrêtée proprement", "Space Missions": "Missions spatiales", "Context": "Contexte", + "Rendered globe frames per second · toggle with `": "Images du globe rendues par seconde · basculer avec `", + "imported map files": "les fichiers importés sur la carte", + "Ground heights could not be refreshed. Try the file again when the map has loaded.": "Impossible d'actualiser les altitudes du sol. Réessayez avec le fichier une fois la carte chargée.", + "{count} map objects": { + "one": "{count} objet cartographique", + "many": "{count} d'objets cartographiques", + "other": "{count} objets cartographiques" + }, + ", drawn with its own styles": ", dessiné avec ses propres styles", + "Hide {name}": "Masquer {name}", + "Show {name}": "Afficher {name}", + "Fly to {name}": "Rejoindre {name}", + "Remove {name}": "Retirer {name}", + "At most {count} files at once — remove one first.": "{count} fichiers au maximum à la fois — retirez-en un d'abord.", + "Reading {name}…": "Lecture de {name}…", + "That file could not be read.": "Impossible de lire ce fichier.", + "Added {count} files.": { + "one": "{count} fichier ajouté.", + "many": "{count} de fichiers ajoutés.", + "other": "{count} fichiers ajoutés." + }, + "{count} files could not be added ({name}: {error})": { + "one": "{count} fichier n'a pas pu être ajouté ({name} : {error})", + "many": "{count} de fichiers n'ont pas pu être ajoutés ({name} : {error})", + "other": "{count} fichiers n'ont pas pu être ajoutés ({name} : {error})" + }, + "Some KML content was left out.": "Une partie du contenu KML a été ignorée.", + "Press on the ground, not the sky": "Appuyez sur le sol, pas sur le ciel", + "Drag to size the box": "Faites glisser pour dimensionner la zone", + "light {source} to use your {name} key": "activez {source} pour utiliser votre clé {name}", + "light {source}": "activez {source}", + ", or ": ", ou ", + "{requirement}, or {offer}": "{requirement}, ou {offer}", "Live Flights": "Vols en direct", "Military Flights": "Vols militaires", "Earthquakes (24h)": "Séismes (24 h)", @@ -515,9 +1807,41 @@ "Datacenters": "Centres de données", "Dams": "Barrages", "Submarine Cables": "Câbles sous-marins", - "FIRMS Active Fires": "Incendies actifs FIRMS", + "FIRMS Active Fires": "Feux actifs FIRMS", + "Local ADS-B": "ADS-B local", + "Transit": "Transports en commun", + "Recent Imagery": "Imagerie récente", + "Fire Perimeters": "Périmètres d'incendies", + "GNSS Integrity": "Intégrité GNSS", + "S2 GhostMaps": "S2 GhostMaps", + "Rain radar": "Radar de pluie", + "Lightning density": "Densité de foudre", + "Cyclone advisories": "Bulletins cycloniques", + "ALPR Cameras": "Caméras LAPI", + "Live Vessels": "Navires en direct", + "Bike Share": "Vélos en libre-service", + "Cameras": "Caméras", + "Street Level": "Niveau rue", + "Mapped ALPR Cameras": "Caméras LAPI cartographiées", + "Data Centers": "Centres de données", + "Active Fires": "Feux actifs", + "Military aircraft": "Aéronefs militaires", + "Vessels": "Navires", + "CCTV + Street View fallback": "CCTV + secours Street View", + "OpenStreetMap + optional Google Maps Places": "OpenStreetMap + Google Maps Places en option", + "GFS / ECMWF IFS · FORECAST": "GFS / ECMWF IFS · PRÉVISION", + "NOAA nowCOAST · OBSERVED": "NOAA nowCOAST · OBSERVÉ", + "NASA FIRMS · LIVE": "NASA FIRMS · DIRECT", + "OSM routing": "Itinéraires OSM", + "data source|Local": "Données locales", "ENABLING": "ACTIVATION", "DISABLING": "DÉSACTIVATION", + "Movement": "Mouvement", + "Infrastructure": "Infrastructures", + "Events": "Événements", + "Weather": "Météo", + "Utilities": "Outils", + "Other layers": "Autres couches", "{state} · {source}": "{state} · {source}", "UNCERTAIN · {source} · lifecycle state requires reconciliation": "INCERTAIN · {source} · état du cycle de vie à réconcilier", "{state} · {source} · {detail} · retry {seconds}s": "{state} · {source} · {detail} · nouvel essai {seconds} s", @@ -531,20 +1855,75 @@ "{state} · {source} · {ago}": "{state} · {source} · {ago}", "{source} · {ago}": "{source} · {ago}", "UNCERTAIN": "INCERTAIN", - "{name}: {state}": "{name} : {state}", + "status chip|UNAVAILABLE": "INDISP.", + "Data source unavailable": "Source de données indisponible", + "{name}: {state}": "{name} : {state}", "{count}s ago": "il y a {count} s", - "📍 Location: --": "📍 Lieu : --", - "Landmark: --": "Repère : --", + "Local FM stopped: internet radio started": "FM locale arrêtée : la radio Internet a démarré", + "IDLE": "INACTIF", + "CONNECTING": "CONNEXION", + "TUNING": "RÉGLAGE", + "STREAMING": "RÉCEPTION", + "UNSUPPORTED": "NON PRIS EN CHARGE", + "idle": "inactif", + "running": "actif", + "suspended": "suspendu", + "closed": "fermé", + "feed status|live": "en direct", + "feed status|stale": "obsolète", + "feed status|unreachable": "injoignable", + "feed status|invalid": "non valide", + "waiting for IQ": "en attente des données IQ", + "{count} messages": { + "one": "{count} message", + "many": "{count} de messages", + "other": "{count} messages" + }, + "DSP {count} blocks": { + "one": "DSP {count} bloc", + "many": "DSP {count} de blocs", + "other": "DSP {count} blocs" + }, + "DSP waiting": "DSP en attente", + "{level} dBFS audio": "audio {level} dBFS", + "audio signal --": "signal audio --", + "audio {state}": "audio {state}", + "{count} HEARD": { + "one": "CAPTÉS : {count}", + "many": "CAPTÉS : {count}", + "other": "CAPTÉS : {count}" + }, + "DISCONNECT": "DÉCONNECTER", + "CONNECT": "CONNECTER", + "LOCATING…": "LOCALISATION…", + "LOCATED": "LOCALISÉ", + "LOCATE": "LOCALISER", + " · read while Local ADS-B is on": " · lus tant que ADS-B local est activé", + "Decoder feeds: {feeds}": "Flux du décodeur : {feeds}", + "Language: {language}": "Langue : {language}", + "Change the interface language": "Changer la langue de l'interface", + "Interface language": "Langue de l'interface", + "Search languages": "Rechercher une langue", + "No matching languages": "Aucune langue correspondante", + "📍 Location: --": "📍 Lieu : --", + "Landmark: --": "Repère : --", "Searched location": "Lieu recherché", "ORBIT": "ORBITE", "Location not found": "Lieu introuvable", + "Check the spelling and press Enter to search again.": "Vérifiez l'orthographe et appuyez sur Enter pour relancer la recherche.", "Search failed": "Échec de la recherche", - "Fly to a POI first": "Rejoignez d'abord un repère", + "Press Enter to try again.": "Appuyez sur Enter pour réessayer.", + "Detailed outline unavailable": "Contour détaillé indisponible", + "Fly to a POI first": "Rejoignez d'abord un point d'intérêt", "Reset to full globe view": "Revenir à la vue du globe entier", "Reset cockpit to full globe view": "Réinitialiser le cockpit sur la vue du globe entier", "Resetting to full globe view": "Retour à la vue du globe entier", "Resetting cockpit to full globe view": "Réinitialisation du cockpit sur la vue du globe entier", "MAP": "CARTE", + "Layers": "Couches", + "Search": "Recherche", + "More": "Plus", + "Panels": "Panneaux", "panel": "le panneau", "Expand {name}": "Développer {name}", "Collapse {name}": "Réduire {name}", @@ -553,17 +1932,31 @@ "Expand Radio section": "Développer la section Radio", "Collapse Radio section": "Réduire la section Radio", "Panel layout updated — positions reset to new defaults": "Disposition des panneaux mise à jour — positions réinitialisées", + "Austin": "Austin", + "San Francisco": "San Francisco", + "New York": "New York", + "Tokyo": "Tokyo", + "London": "Londres", + "Paris": "Paris", + "Dubai": "Dubaï", + "Washington DC": "Washington", + "Tallinn": "Tallinn", + "Los Angeles": "Los Angeles", "Collapse Cockpit display options": "Réduire les options d'affichage du cockpit", "Expand Cockpit display options": "Développer les options d'affichage du cockpit", "Collapse Cockpit Radio controls": "Réduire les commandes Radio du cockpit", "Expand Cockpit Radio controls": "Développer les commandes Radio du cockpit", + "CH {index} / {total}": "CANAL {index} / {total}", "NO STATIONS": "AUCUNE STATION", "NO STATION AVAILABLE": "AUCUNE STATION DISPONIBLE", "{name}, station {index} of {total}": "{name}, station {index} sur {total}", "No station available": "Aucune station disponible", "OFF AIR": "HORS ANTENNE", "STATION UNAVAILABLE": "STATION INDISPONIBLE", + "Station unavailable after directory refresh": "Station indisponible après l'actualisation de l'annuaire", "Radio could not {action} cleanly": "La Radio n'a pas pu {action} proprement", + "Go to expanded Radio section": "Aller à la section Radio développée", + "Expand Radio section in Context": "Développer la section Radio dans Contexte", "Close compact Radio controls": "Fermer les commandes Radio compactes", "Open compact Radio controls": "Ouvrir les commandes Radio compactes", "SYNC": "SYNCHRO", @@ -573,6 +1966,7 @@ "Reconcile Radio — lifecycle uncertain": "Réconcilier la Radio — cycle de vie incertain", "Disable Radio": "Désactiver la Radio", "Enable Radio": "Activer la Radio", + "{category} ({count})": "{category} ({count})", "DIRECTORY BAND": "BANDE DE L'ANNUAIRE", "{category} BAND": "BANDE {category}", "NO STATION SELECTED": "AUCUNE STATION SÉLECTIONNÉE", @@ -581,6 +1975,8 @@ "Choose a globe marker or use next.": "Choisissez un marqueur du globe ou utilisez suivant.", "TAGS · {tags}": "TAGS · {tags}", "Play": "Lire", + "PAUSE": "PAUSE", + "RESUME": "REPRENDRE", "PLAY": "LIRE", "selected": "sélectionnée", "nearest": "la plus proche", @@ -591,9 +1987,9 @@ "SYNCING": "SYNCHRO", "READY": "PRÊT", "station": "station", - " · stale/degraded directory": " · annuaire périmé/dégradé", + " · stale/degraded directory": " · annuaire obsolète/dégradé", " · degraded directory": " · annuaire dégradé", - " · stale directory": " · annuaire périmé", + " · stale directory": " · annuaire obsolète", " · outside current filter": " · hors du filtre actuel", "Ready — playback starts only from your action": "Prêt — la lecture ne démarre que sur votre action", "Radio off": "Radio désactivée", @@ -610,95 +2006,727 @@ "Radio is enabling…": "Activation de la Radio…", "Radio is disabling…": "Désactivation de la Radio…", "Radio lifecycle is uncertain — use Enable or Disable to reconcile": "Cycle de vie de la Radio incertain — utilisez Activer ou Désactiver pour réconcilier", + "Clear reading": "Effacer la lecture", + "Earlier observation": "Observation précédente", + "Observed history": "Historique observé", + "Later observation": "Observation suivante", + "Latest": "Dernière", + "Newest frame per product": "Image la plus récente par produit", + "Replay observed history": "Rejouer l'historique observé", + "Imagery on Esri · Google 3D returns when cleared": "Imagerie sur Esri · Google 3D revient après EFFACER", + "Point the camera at the ground to use the view": "Orientez la caméra vers le sol pour utiliser la vue", + "That point cannot anchor a box": "Ce point ne peut pas ancrer une zone", + "Imagery stops at ±{limit}° latitude": "L'imagerie s'arrête à ±{limit}° de latitude", + "{owner} is using the pointer — close it first": "Pointeur utilisé par : {owner}. Fermez-le d'abord", + "Box is {size} wide · limit {limit}": "La zone fait {size} de large · limite {limit}", + "View is {size} wide · limit {limit}": "La vue fait {size} de large · limite {limit}", + "VS BASEMAP": "VS FOND DE CARTE", + "A / B": "A / B", + "Newest low-cloud day for this box · scene cloud, not box cloud": "Jour le plus récent peu nuageux pour cette zone · nuages de la scène, pas de la zone", + "Newest day covering this box · cloudier than 20%": "Jour le plus récent couvrant cette zone · plus de 20 % de nuages", + "Newest day with imagery for this box · partial coverage": "Jour le plus récent avec des images pour cette zone · couverture partielle", + "Newest daily overview for this box": "Vue quotidienne la plus récente pour cette zone", + "newest clear day": "jour dégagé le plus récent", + "newest day (cloudy)": "jour le plus récent (nuageux)", + "newest day (partial coverage)": "jour le plus récent (couverture partielle)", + "newest overview": "vue quotidienne la plus récente", + "No imagery": "Aucune image", + "Loading": "Chargement", + "coverage|full": "complète", + "coverage|partial": "partielle", + "unknown": "inconnue", + "no imagery": "aucune image", + "{percent}% cloud": "{percent} % de nuages", + "{min}–{max}% cloud": "{min}–{max} % de nuages", + "NO BOX": "AUCUNE ZONE", + "SEARCHING": "RECHERCHE", + "{count} DAYS": { + "one": "{count} JOUR", + "many": "{count} DE JOURS", + "other": "{count} JOURS" + }, + "Zoom in or draw a smaller box": "Zoomez ou tracez une zone plus petite", + "Select a box or use the view": "Sélectionnez une zone ou utilisez la vue", + "Searching the last 30 days": "Recherche sur les 30 derniers jours", + "No days to show for this box": "Aucun jour à afficher pour cette zone", + "Drag the divider · SWAP trades sides": "Faites glisser le séparateur · INVERSER échange les côtés", + "← → preview · A or B pins the focused day": "← → aperçu · A ou B épingle le jour ciblé", + "← → preview the other side · A or B pins it": "← → aperçu de l'autre côté · A ou B l'épingle", + "S on another day replaces it · × unpins": "S sur un autre jour le remplace · × le désépingle", + "← → preview · S shows the focused day": "← → aperçu · S affiche le jour ciblé", + "ZOOM IN": "ZOOMER", + "Fly in until the view fits the 1,000 km limit": "Rapprochez-vous jusqu'à ce que la vue tienne dans la limite de 1 000 km", + "Imagery days, newest first · arrows move, S or A and B pin": "Jours d'imagerie, du plus récent au plus ancien · les flèches déplacent, S ou A et B épinglent", + "On the map": "Sur la carte", + "Mode": "Mode", + "Imagery opacity": "Opacité de l'imagerie", + "SWAP": "INVERSER", + "Trade the two sides of the divider": "Échanger les deux côtés du séparateur", + "SELECT BOX": "TRACER ZONE", + "Drag a box on the map (Esc cancels)": "Tracez une zone sur la carte (Esc pour annuler)", + "USE VIEW": "UTILISER LA VUE", + "Use the current view as the box": "Utiliser la vue actuelle comme zone", + "Forget the box and its images": "Oublier la zone et ses images", + "START HERE": "COMMENCER ICI", + "Checking": "Vérification", + "PREVIEW": "APERÇU", + "Newest day with imagery for this box": "Jour le plus récent avec des images pour cette zone", + "SHOW": "AFFICHER", + "Pin {day} as {slot}": "Épingler {day} en {slot}", + "Show {day}": "Afficher {day}", + "pinned {slot}": "épinglé en {slot}", + "shown": "affiché", + "preview": "aperçu", + "start here": "commencer ici", + "No box": "Aucune zone", + "Searching": "Recherche", + "Every day is empty here": "Tous les jours sont vides ici", + "Sources off": "Sources désactivées", + "VS": "VS", + "Not set": "Non défini", + "Basemap": "Fond de carte", + "Source off": "Source désactivée", + "Unpin {slot}": "Désépingler {slot}", + "Unpin the image": "Désépingler l'image", + "EXPORT {slot}": "EXPORT. {slot}", + "EXPORT": "EXPORTER", + "Download {slot} as a PNG": "Télécharger {slot} en PNG", + "Download the image as a PNG": "Télécharger l'image en PNG", + "Box {width} × {height} km": "Zone de {width} × {height} km", + "Acquired {time}": "Acquise le {time}", + "Coverage {coverage}": "Couverture {coverage}", + "START HERE · {reason}": "COMMENCER ICI · {reason}", + "Daily overview shows little detail in a box this small": "La vue quotidienne montre peu de détails dans une zone aussi petite", + "Imagery: NASA GIBS and Worldview · HLS (Sentinel-2, Landsat 8/9) and VIIRS": "Imagerie : NASA GIBS et Worldview · HLS (Sentinel‑2, Landsat 8/9) et VIIRS", + "Details": "Détails", + "Times, coverage, sources": "Heures, couverture, sources", + "HIDE EMPTY DAYS": "MASQUER LES JOURS VIDES", + "SHOW EMPTY DAYS · {count}": "AFFICHER LES JOURS VIDES · {count}", + "Days the probe found empty in this box": "Jours que la sonde a trouvés vides dans cette zone", + "image": "image", + "BASEMAP": "FOND DE CARTE", + "The basemap": "Le fond de carte", + "basemap": "fond de carte", + "Recent imagery against the basemap divider": "Séparateur imagerie récente / fond de carte", + "Recent imagery A and B divider": "Séparateur A / B de l'imagerie récente", + "{before} {left} percent, {after} {right} percent": "{before} {left} pour cent, {after} {right} pour cent", + "Export failed · {error}": "Échec de l'export · {error}", "Scene action failed": "Échec de l'action sur la scène", - "Delete shot \"{shot}\"?": "Supprimer le plan « {shot} » ?", + "New scene name": "Nom de la nouvelle scène", + "Delete scene \"{scene}\" and all shots?": "Supprimer la scène « {scene} » et tous ses plans ?", + "Delete shot \"{shot}\"?": "Supprimer le plan « {shot} » ?", + "Stopped (Esc)": "Arrêté (Esc)", "SPARSE": "ÉPARS", "BALANCED": "ÉQUILIBRÉ", + "No shots yet. Use CAPTURE SHOT to save current look.": "Aucun plan pour l'instant. Utilisez CAPTURER UN PLAN pour enregistrer le rendu actuel.", + "Double-click to rename": "Double-cliquez pour renommer", + "Shot name": "Nom du plan", + "LOAD": "CHARGER", "DEL": "SUPPR.", + "{duration}s + {hold}s": "{duration} s + {hold} s", + "Choose files": "Choisir des fichiers", + "{count} files selected": { + "one": "{count} fichier sélectionné", + "many": "{count} de fichiers sélectionnés", + "other": "{count} fichiers sélectionnés" + }, + "No file chosen": "Aucun fichier choisi", + "Cancel": "Annuler", + "EDIT DETAILS": "MODIFIER LES DÉTAILS", + "SHARE SCENE": "PARTAGER LA SCÈNE", + "Shared flight follow expired": "Le suivi du vol partagé a expiré", + "Shared military flight follow expired": "Le suivi du vol militaire partagé a expiré", + "Shared satellite follow expired": "Le suivi du satellite partagé a expiré", + "Shared flight could not be restored — feed unavailable": "Impossible de restaurer le vol partagé — flux indisponible", + "Shared military flight could not be restored — feed unavailable": "Impossible de restaurer le vol militaire partagé — flux indisponible", + "Shared satellite could not be restored — feed unavailable": "Impossible de restaurer le satellite partagé — flux indisponible", + "Shared flight is unavailable": "Le vol partagé est indisponible", + "Shared military flight is unavailable": "Le vol militaire partagé est indisponible", + "Shared satellite is unavailable": "Le satellite partagé est indisponible", "entity": "entité", "Shared {subject} follow expired": "Le suivi partagé de {subject} a expiré", "Shared {subject} could not be restored — feed unavailable": "Impossible de restaurer le suivi partagé de {subject} — flux indisponible", - "Shared {subject} is unavailable": "Partage indisponible : {subject}", + "Shared {subject} is unavailable": "Partage indisponible : {subject}", + "{id} isn't reporting now — showing where it was last seen": "{id} n'émet pas actuellement — affichage de sa dernière position connue", + "{id} isn't reporting now — showing where it was at {time}": "{id} n'émet pas actuellement — affichage de sa position à {time}", + "This share link can't be opened": "Ce lien de partage ne peut pas être ouvert", + "Shared vessel is unavailable": "Le navire partagé est indisponible", "ACQUIRING": "ACQUISITION", - "SHARED {subject}": "PARTAGÉ : {subject}", - "LOADING LIVE DATA": "CHARGEMENT DES DONNÉES LIVE", + "SHARED {subject}": "PARTAGÉ : {subject}", + "subject": "cible", + "LOADING LIVE DATA": "CHARGEMENT DES DONNÉES EN DIRECT", "LOAD COMPLETE": "CHARGEMENT TERMINÉ", "LOAD CANCELLED": "CHARGEMENT ANNULÉ", "LOAD FAILED": "ÉCHEC DU CHARGEMENT", - "LIVE DATA OFF": "DONNÉES LIVE DÉSACTIVÉES", + "LIVE DATA OFF": "DONNÉES EN DIRECT DÉSACTIVÉES", "MAPPED SITES LOADED": "SITES CARTOGRAPHIÉS CHARGÉS", "RETRYING MAPPED SITES": "NOUVEL ESSAI SITES CARTOGRAPHIÉS", "FETCHING MAPPED SITES": "RÉCUPÉRATION DES SITES CARTOGRAPHIÉS", - "TURNING OFF LIVE DATA": "DÉSACTIVATION DES DONNÉES LIVE", - "REFRESHING LIVE DATA": "ACTUALISATION DES DONNÉES LIVE", + "RETRYING ALPR CAMERAS": "NOUVEL ESSAI CAMÉRAS LAPI", + "FETCHING ALPR CAMERAS": "RÉCUPÉRATION DES CAMÉRAS LAPI", + "OVERPASS TEMPORARILY UNAVAILABLE": "OVERPASS TEMPORAIREMENT INDISPONIBLE", + "OVERPASS RATE-LIMITED": "OVERPASS : LIMITE DE REQUÊTES ATTEINTE", + "OVERPASS TIMED OUT": "OVERPASS : DÉLAI DÉPASSÉ", + "OVERPASS COULD NOT COMPLETE THE QUERY": "OVERPASS N'A PAS PU TERMINER LA REQUÊTE", + "MAP TILES TEMPORARILY UNAVAILABLE": "TUILES DE LA CARTE TEMPORAIREMENT INDISPONIBLES", + "MAPPED NAMES TEMPORARILY UNAVAILABLE": "NOMS CARTOGRAPHIÉS TEMPORAIREMENT INDISPONIBLES", + "TURNING OFF LIVE DATA": "DÉSACTIVATION DES DONNÉES EN DIRECT", + "REFRESHING LIVE DATA": "ACTUALISATION DES DONNÉES EN DIRECT", "syncing road network": "synchro du réseau routier", "retry pending": "nouvel essai en attente", - "retrying in {seconds}s": "nouvel essai dans {seconds}s", + "retrying in {seconds}s": "nouvel essai dans {seconds} s", + "ALPR cameras": "caméras LAPI", + "OpenSky OAuth client missing/invalid": "Client OAuth OpenSky absent ou non valide", + "OpenSky OAuth rejected credentials": "OpenSky OAuth a refusé les identifiants", + "OpenSky username/password rejected": "Identifiant ou mot de passe OpenSky refusé", + "OpenSky auth missing": "Authentification OpenSky absente", + "OpenSky auth required": "Authentification OpenSky requise", + "OpenSky auth invalid": "Authentification OpenSky non valide", + "OpenSky auth failed": "Échec de l'authentification OpenSky", + "KartaView answered HTTP {status}": "KartaView a répondu HTTP {status}", + "Panoramax answered HTTP {status}": "Panoramax a répondu HTTP {status}", + "KartaView refused the request (code {code})": "KartaView a refusé la requête (code {code})", + "Vector tiles unavailable (HTTP {status})": "Tuiles vectorielles indisponibles (HTTP {status})", + "GNSS feed unavailable (HTTP {status})": "Flux GNSS indisponible (HTTP {status})", + "{count} CelesTrak groups unavailable": { + "one": "{count} groupe CelesTrak indisponible", + "many": "{count} de groupes CelesTrak indisponibles", + "other": "{count} groupes CelesTrak indisponibles" + }, + "{feed} feed unavailable": "Flux {feed} indisponible", + "Source snapshot {minutes} min old": "Instantané de la source datant de {minutes} min", + "{source} rate limited (anonymous)": "{source} : limite de requêtes atteinte (anonyme)", + "{source} rate limited": "{source} : limite de requêtes atteinte", + "{source} network error": "{source} : erreur réseau", + "Malformed {source} aircraft rows": "{source} : lignes d'aéronefs mal formées", + "Malformed {source} response": "{source} : réponse mal formée", + "entry {n}": "entrée {n}", + "feeds {names} stale": { + "one": "flux {names} obsolète", + "many": "flux {names} obsolètes", + "other": "flux {names} obsolètes" + }, + "feeds {names} unreachable": { + "one": "flux {names} injoignable", + "many": "flux {names} injoignables", + "other": "flux {names} injoignables" + }, + "feeds {names} invalid": { + "one": "flux {names} non valide", + "many": "flux {names} non valides", + "other": "flux {names} non valides" + }, + "Loading {feeds}": "Chargement de {feeds}", + "{count} heard": { + "one": "{count} aéronef capté", + "many": "{count} d'aéronefs captés", + "other": "{count} aéronefs captés" + }, + "USB {rate} msg/s": "USB {rate} msg/s", + "{rate} msg/s": "{rate} msg/s", + "{count} feeds live": { + "one": "{count} flux en direct", + "many": "{count} de flux en direct", + "other": "{count} flux en direct" + }, + "{feed} {count} ({seconds}s old)": "{feed} {count} (il y a {seconds} s)", + "Street Level toggle failed": "Impossible d'activer ou de désactiver Niveau rue", + "Street Level could not start": "Impossible de démarrer Niveau rue", + "SHRINK": "RÉDUIRE", + "EXPAND": "AGRANDIR", + "Shrink": "Réduire", + "Expand": "Agrandir", + "ANY DATE": "TOUTES DATES", + "LAST 10 YEARS": "10 DERNIÈRES ANNÉES", + "LAST 5 YEARS": "5 DERNIÈRES ANNÉES", + "LAST 3 YEARS": "3 DERNIÈRES ANNÉES", + "LAST 2 YEARS": "2 DERNIÈRES ANNÉES", + "LAST YEAR": "DERNIÈRE ANNÉE", + "LAST 6 MONTHS": "6 DERNIERS MOIS", + "LAST 3 MONTHS": "3 DERNIERS MOIS", + "LAST MONTH": "DERNIER MOIS", + "LAST {count} DAYS": { + "one": "{count} DERNIER JOUR", + "many": "{count} DERNIERS JOURS", + "other": "{count} DERNIERS JOURS" + }, + "{window} · SINCE {date}": "{window} · DEPUIS LE {date}", + "Turn Street Level off": "Désactiver Niveau rue", + "Turn Street Level on": "Activer Niveau rue", + "{name} imagery on": "Images {name} activées", + "{name} imagery off": "Images {name} désactivées", + "Image by {creator}": "Image de {creator}", + " or ": " ou ", + "OPEN {labels}": "OUVRIR {labels}", + "Open {names} at the centre of the view": "Ouvrir {names} au centre de la vue", + "Zoom in to a street to open {names} here": "Zoomez sur une rue pour ouvrir {names} ici", + "Switch Street Level on to draw its coverage.": "Activez Niveau rue pour afficher sa couverture.", + "Every provider is switched off: light a chip to draw its coverage.": "Tous les fournisseurs sont désactivés : activez-en un pour afficher sa couverture.", + "Loading this sequence…": "Chargement de cette séquence…", + "{n} images in this sequence · Esc clears": { + "one": "{n} image dans cette séquence · Esc pour effacer", + "many": "{n} d'images dans cette séquence · Esc pour effacer", + "other": "{n} images dans cette séquence · Esc pour effacer" + }, + "No sequences in view match the filter": "Aucune séquence dans la vue ne correspond au filtre", + "No coverage in view": "Aucune couverture dans la vue", + "{n} streets in view · click a line for its nearest photo": { + "one": "{n} rue dans la vue · cliquez sur une ligne pour sa photo la plus proche", + "many": "{n} de rues dans la vue · cliquez sur une ligne pour sa photo la plus proche", + "other": "{n} rues dans la vue · cliquez sur une ligne pour sa photo la plus proche" + }, + "{n} sequences in view · click a line for its nearest photo": { + "one": "{n} séquence dans la vue · cliquez sur une ligne pour sa photo la plus proche", + "many": "{n} de séquences dans la vue · cliquez sur une ligne pour sa photo la plus proche", + "other": "{n} séquences dans la vue · cliquez sur une ligne pour sa photo la plus proche" + }, + "{n} sequences in view · click a line for its photos": { + "one": "{n} séquence dans la vue · cliquez sur une ligne pour voir ses photos", + "many": "{n} de séquences dans la vue · cliquez sur une ligne pour voir ses photos", + "other": "{n} séquences dans la vue · cliquez sur une ligne pour voir ses photos" + }, + "km/h": "km/h", + "m/s": "m/s", + "mph": "mph", + "hPa": "hPa", + "kt": "nd", + "kts": "nd", + "ft": "ft", + "km": "km", + "m": "m", + "h": "h", + "min": "min", + "s": "s", + "dB": "dB", "Celestial ring — reveal the full globe": "Anneau céleste — révéler le globe entier", "Celestial ring — available in Normal style": "Anneau céleste — disponible en style Normal", - "Detection overlay: {mode}": "Surcouche de détection : {mode}", - "Detection overlay: off": "Surcouche de détection : désactivée", + "Detection overlay: {mode}": "Surcouche de détection : {mode}", + "Detection overlay: off": "Surcouche de détection : désactivée", "DETECT": "DÉTECT.", + "{time} · {minutes} min ago": "{time} · il y a {minutes} min", + "Active weather": "Couches météo actives", + "LATEST · newest per product": "DERNIÈRE · la plus récente par produit", + "Forecast · valid {valid} · issued {issued}": "Prévision · valide {valid} · émise {issued}", + "{detail} · Does not follow history": "{detail} · Ne suit pas l'historique", + "Forecast · valid {valid}": "Prévision · valide {valid}", "voice|OFF": "OFF", "voice|CONNECTING": "CONNEXION", "voice|LISTENING": "ÉCOUTE", "voice|EXECUTING": "EXÉCUTION", "voice|ERROR": "ERREUR", + "Voice provider": "Fournisseur vocal", + "Changing provider reconnects voice if it is on.": "Changer de fournisseur reconnecte la voix si elle est activée.", + "Voice Settings": "Paramètres vocaux", "AI AGENT": "AGENT IA", "Voice model tier — applies next session": "Niveau du modèle vocal — à la prochaine session", + "STD": "STD", "Estimated session cost": "Coût estimé de la session", - "Voice control — activate to toggle voice; hold Space to speak": "Commande vocale — activer pour basculer la voix ; maintenir Espace pour parler", + "Voice control — activate to toggle voice; hold Space to speak": "Commande vocale — activez pour basculer la voix ; maintenez Space pour parler", + "ON/OFF": "ON/OFF", "VOICE STANDBY": "VOIX EN VEILLE", "VOICE CONTROL": "COMMANDE VOCALE", - "Hold Space to speak · tap Space to activate focused controls": "Maintenez Espace pour parler · appuyez sur Espace pour activer les commandes ciblées", + "Hold Space to speak · tap Space to activate focused controls": "Maintenez Space pour parler · appuyez sur Space pour activer la commande ciblée", + "VOICE": "VOIX", + "Preview": "Aperçu", + "Settings": "Paramètres", + "Close voice panel": "Fermer le panneau vocal", + "Voice replies appear here.": "Les réponses vocales s'affichent ici.", + "Voice assistant": "Assistant vocal", + "Dismiss voice card": "Fermer la fiche vocale", + "YOU": "VOUS", + "THIS": "CECI", + "Plan": "Plan", + "Referenced items": "Éléments cités", + "NOTES & SOURCES": "NOTES ET SOURCES", + "Show Voice Preview": "Afficher l'aperçu vocal", + "Voice inactivity timeout": "Délai d'inactivité vocale", + "Minutes": "Minutes", + "Custom": "Personnalisé", + "These preferences stay in this browser.": "Ces préférences restent dans ce navigateur.", "VOICE SYSTEM ERROR": "ERREUR DU SYSTÈME VOCAL", "DISMISS": "FERMER", "Check microphone permission and network access, then try again.": "Vérifiez l'autorisation du microphone et l'accès réseau, puis réessayez.", - "Release Space to send": "Relâchez Espace pour envoyer", - "Hold Space to talk": "Maintenez Espace pour parler", + "Gemini returned an oversized audio chunk": "Gemini a renvoyé un fragment audio trop volumineux", + "Gemini returned an unsupported audio format": "Gemini a renvoyé un format audio non pris en charge", + "Gemini returned an invalid audio sample rate": "Gemini a renvoyé une fréquence d'échantillonnage audio non valide", + "Gemini returned incomplete PCM audio": "Gemini a renvoyé un audio PCM incomplet", + "This browser does not support Gemini microphone audio": "Ce navigateur ne prend pas en charge l'audio du microphone pour Gemini", + "Microphone audio processing failed": "Échec du traitement de l'audio du microphone", + "Gemini audio playback fell behind. Reconnect to continue.": "La lecture audio de Gemini a pris du retard. Reconnectez-vous pour continuer.", + "Gemini token response did not include an ephemeral credential": "La réponse de Gemini ne contenait pas d'identifiant temporaire", + "Invalid Gemini connection endpoint": "Point de connexion Gemini non valide", + "Gemini voice could not connect. Try again.": "Impossible de connecter la voix Gemini. Réessayez.", + "Gemini voice requires a same-origin app request": "La voix Gemini exige une requête de l'application de même origine", + "Add a Gemini API key in Provider Settings": "Ajoutez une clé API Gemini dans les paramètres des fournisseurs", + "The Gemini Live model configuration is invalid": "La configuration du modèle Gemini Live n'est pas valide", + "Gemini voice is starting too often. Try again shortly.": "La voix Gemini démarre trop souvent. Réessayez dans un instant.", + "Gemini quota is unavailable. Try again later.": "Le quota Gemini est indisponible. Réessayez plus tard.", + "Gemini access was refused. Check the API key and model access.": "L'accès à Gemini a été refusé. Vérifiez la clé API et l'accès au modèle.", + "Gemini Live is unavailable for the configured model.": "Gemini Live n'est pas disponible pour le modèle configuré.", + "Token request is too large": "La demande de jeton est trop volumineuse", + "Use an empty JSON token request": "Utilisez une demande de jeton avec un objet JSON vide", + "Release Space to send": "Relâchez Space pour envoyer", + "Hold Space to talk": "Maintenez Space pour parler", + "Voice command context is too large": "Le contexte de la commande vocale est trop volumineux", + "Gemini reliable transport exceeded its queue limit. Start voice again.": "La file d'envoi fiable de Gemini a dépassé sa limite. Relancez la voix.", + "Gemini reliable transport did not drain. Start voice again.": "La file d'envoi fiable de Gemini ne s'est pas vidée. Relancez la voix.", + "Gemini token request failed (HTTP {status})": "Échec de la demande de jeton Gemini (HTTP {status})", + "Gemini token response did not include a valid model": "La réponse de Gemini ne contenait pas de modèle valide", + "Gemini token response did not include session settings": "La réponse de Gemini ne contenait pas les paramètres de session", + "Gemini session settings do not match the input mode": "Les paramètres de session Gemini ne correspondent pas au mode de saisie", "Requesting microphone": "Demande du microphone", + "Gemini could not submit this input. Start voice again.": "Gemini n'a pas pu envoyer cette saisie. Relancez la voix.", + "Connecting to Gemini": "Connexion à Gemini", "Ask or command": "Posez une question ou donnez un ordre", + "Gemini returned an oversized message": "Gemini a renvoyé un message trop volumineux", + "Gemini Live connection failed. Check network access, then start voice again.": "Échec de la connexion à Gemini Live. Vérifiez l'accès au réseau, puis relancez la voix.", + "Gemini Live connection ended. Start voice again for a new conversation.": "La connexion à Gemini Live est terminée. Relancez la voix pour une nouvelle conversation.", + "Gemini Live could not start. Start voice again to request a fresh session.": "Gemini Live n'a pas pu démarrer. Relancez la voix pour demander une nouvelle session.", + "Start voice again for a fresh token and a new conversation.": "Relancez la voix pour obtenir un nouveau jeton et démarrer une nouvelle conversation.", + "Start voice again to request a fresh session credential.": "Relancez la voix pour demander un nouvel identifiant de session.", + "Microphone permission was denied. Allow microphone access and try again.": "L'autorisation du microphone a été refusée. Autorisez l'accès au microphone et réessayez.", + "Gemini connection timed out. Try again.": "Délai de connexion à Gemini dépassé. Réessayez.", + "Gemini voice could not start": "Impossible de démarrer la voix Gemini", + "Gemini did not finish the interrupted reply. Start voice again.": "Gemini n'a pas terminé la réponse interrompue. Relancez la voix.", + "Gemini session expiring; finishing the current reply": "La session Gemini expire ; fin de la réponse en cours", + "Gemini rejected the voice session. Start voice again to request a fresh session.": "Gemini a refusé la session vocale. Relancez la voix pour demander une nouvelle session.", + "Start voice again for a fresh session credential. If it repeats, check Gemini model and API access.": "Relancez la voix pour obtenir un nouvel identifiant de session. Si cela se reproduit, vérifiez le modèle Gemini et l'accès à l'API.", + "Gemini action history is full. Start voice again for a fresh session.": "L'historique des actions de Gemini est plein. Relancez la voix pour une nouvelle session.", + "Gemini requested too many simultaneous actions": "Gemini a demandé trop d'actions simultanées", "Running command": "Commande en cours", + "Voice text command is too long": "La commande vocale écrite est trop longue", + "Gemini voice is not connected": "La voix Gemini n'est pas connectée", + "Gemini interrupted input exceeded its buffer or wait limit. Start voice again.": "La saisie interrompue de Gemini a dépassé sa limite de tampon ou d'attente. Relancez la voix.", + "Gemini Live connection is expiring. Start voice again for a new conversation.": "La connexion à Gemini Live expire. Relancez la voix pour une nouvelle conversation.", "Voice off": "Voix désactivée", + "Gemini voice sessions have a time limit. When a session expires, start voice again for a new conversation.": "Les sessions vocales Gemini sont limitées dans le temps. Quand une session expire, relancez la voix pour une nouvelle conversation.", + "Stopped by voice": "Arrêté par la voix", + "Automatic stop is unavailable for this voice connection.": "L'arrêt automatique n'est pas disponible pour cette connexion vocale.", + "Preview is off.": "L'aperçu est désactivé.", + "Your choice applies now, but could not be saved.": "Votre choix s'applique maintenant, mais n'a pas pu être enregistré.", "WebRTC microphone support unavailable": "Microphone WebRTC non pris en charge", "VOICE UNAVAILABLE": "VOIX INDISPONIBLE", "VOICE ACTIVE": "VOIX ACTIVE", "Voice session could not be started.": "Impossible de démarrer la session vocale.", - "Next session: {pendingId} — this session stays on {modelId}": "Prochaine session : {pendingId} — cette session reste sur {modelId}", - "Voice model: {pendingId} — click to switch to {target}; applies next session": "Modèle vocal : {pendingId} — cliquer pour passer à {target} ; à la prochaine session", + "MINI": "MINI", + "Next session: {pendingId} — this session stays on {modelId}": "Prochaine session : {pendingId} — cette session reste sur {modelId}", + "Voice model: {pendingId} — click to switch to {target}; applies next session": "Modèle vocal : {pendingId} — cliquer pour passer à {target} ; à la prochaine session", + "standard": "standard", + "mini": "mini", + "COST UNKNOWN": "COÛT INCONNU", + "ChatGPT OAuth session: {responses} response(s), {input} input and {output} output tokens, {captions} caption transcription(s) reported.": "Session OAuth ChatGPT (données signalées) : {responses} réponse(s), {input} jetons d'entrée et {output} jetons de sortie, {captions} transcription(s) de sous-titres.", + "USD cost and the API spend cap are unavailable for this auth mode.": "Le coût en USD et le plafond de dépenses API ne sont pas disponibles avec ce mode d'authentification.", + "Usage is incomplete because a response was still in flight when the session ended.": "L'utilisation est incomplète, car une réponse était encore en cours à la fin de la session.", "Estimated session cost on {modelId} — {responses} response(s). Warns at {warn}, ends the session at {cap}.": "Coût estimé de la session sur {modelId} — {responses} réponse(s). Alerte à {warn}, fin de session à {cap}.", + "Estimate is incomplete — a response was still in flight when the session ended, so its usage was never reported.": "L'estimation est incomplète — une réponse était encore en cours à la fin de la session, son utilisation n'a donc jamais été signalée.", + "STANDARD": "STANDARD", "{tier} applies next session": "{tier} à la prochaine session", "Session ended — cost cap {cost}": "Session terminée — plafond de coût {cost}", + "MIC": "MIC", "Radio did not start": "La radio n'a pas démarré", + "{n} aircraft": { + "one": "{n} aéronef", + "many": "{n} d'aéronefs", + "other": "{n} aéronefs" + }, + "{n} military aircraft": { + "one": "{n} aéronef militaire", + "many": "{n} d'aéronefs militaires", + "other": "{n} aéronefs militaires" + }, + "{n} ships": { + "one": "{n} navire", + "many": "{n} de navires", + "other": "{n} navires" + }, + "{n} satellites": { + "one": "{n} satellite", + "many": "{n} de satellites", + "other": "{n} satellites" + }, + "{n} launches": { + "one": "{n} lancement", + "many": "{n} de lancements", + "other": "{n} lancements" + }, + "{n} earthquakes": { + "one": "{n} séisme", + "many": "{n} de séismes", + "other": "{n} séismes" + }, + "{n} fires": { + "one": "{n} feu", + "many": "{n} de feux", + "other": "{n} feux" + }, + "{n} fire perimeters": { + "one": "{n} périmètre d'incendie", + "many": "{n} de périmètres d'incendie", + "other": "{n} périmètres d'incendie" + }, + "{n} cyclones": { + "one": "{n} cyclone", + "many": "{n} de cyclones", + "other": "{n} cyclones" + }, + "{n} buses": { + "one": "{n} bus", + "many": "{n} de bus", + "other": "{n} bus" + }, + "{n} bike share": { + "one": "{n} station de vélos en libre-service", + "many": "{n} de stations de vélos en libre-service", + "other": "{n} stations de vélos en libre-service" + }, + "{n} flock cameras": { + "one": "{n} caméra LAPI", + "many": "{n} de caméras LAPI", + "other": "{n} caméras LAPI" + }, + "{n} military bases": { + "one": "{n} base militaire", + "many": "{n} de bases militaires", + "other": "{n} bases militaires" + }, + "{n} datacenters": { + "one": "{n} centre de données", + "many": "{n} de centres de données", + "other": "{n} centres de données" + }, + "{n} dams": { + "one": "{n} barrage", + "many": "{n} de barrages", + "other": "{n} barrages" + }, + "{n} air quality": { + "one": "{n} station de qualité de l'air", + "many": "{n} de stations de qualité de l'air", + "other": "{n} stations de qualité de l'air" + }, + "{n} results": { + "one": "{n} résultat", + "many": "{n} de résultats", + "other": "{n} résultats" + }, + "anywhere in the loaded data": "dans toutes les données chargées", + "in view": "dans la vue", + "within {radius} of the view centre": "dans un rayon de {radius} autour du centre de la vue", + "within {radius} of {place} (Contacts window)": "dans un rayon de {radius} autour de {place} (fenêtre Contacts)", + "within {radius} of {place}": "dans un rayon de {radius} autour de {place}", + "within {radius}": "dans un rayon de {radius}", + "over {region}": "au-dessus de {region}", + "At least {items}": "Au moins {items}", + "{items} {scope}": "{items} {scope}", + "last 24 h": "dernières 24 h", + "past 30 d and upcoming": "30 derniers jours et à venir", + "the flights layer loads by viewport": "la couche des vols se charge selon la vue", + "distance is ground distance, not overhead": "la distance est mesurée au sol jusqu'au point subsatellite, pas jusqu'au satellite", + "the count is a lower bound because at least one layer reached its retained limit.": "le décompte est un minimum, car au moins une couche a atteint sa limite de rétention.", + "{label} off": "{label} : désactivé", + "{label} loading": "{label} : chargement", + "{label} error": "{label} : erreur", + "counted the first {returned} loaded records": "{returned} premiers enregistrements chargés comptés", + "counted {returned} of {total} loaded records": "{returned} enregistrements chargés comptés sur {total}", + "{layers} just turned on — still loading, counts will rise": "{layers} : vient d'être activé — chargement en cours, les décomptes vont augmenter", + "Contacts panel snapshot at {time} — the same retained cohort supplies the card, speech, and follow-up memory": "Instantané du panneau Contacts ({time}) — le même groupe retenu alimente la fiche, la voix et la mémoire de suivi", + "Contacts panel snapshot — the same retained cohort supplies the card, speech, and follow-up memory": "Instantané du panneau Contacts — le même groupe retenu alimente la fiche, la voix et la mémoire de suivi", + "Fly below {km} km to a covered region": "Descendez sous {km} km au-dessus d'une région couverte", + "No feed here yet · {n} regions available": { + "one": "Pas encore de flux ici · {n} région disponible", + "many": "Pas encore de flux ici · {n} de régions disponibles", + "other": "Pas encore de flux ici · {n} régions disponibles" + }, + "degraded": "dégradé", + "stale": "obsolète", + "partial": "partiel", + "fallback": "secours", + "unavailable": "indisponible", + "Not answered: {layers}": "Sans réponse : {layers}", + "Toggle voice control": "Activer/désactiver la commande vocale", + "Activate to toggle voice": "Activez pour basculer la voix", + "Voice active": "Voix active", + "Voice could not be started.": "Impossible de démarrer la voix.", + "the active voice session": "la session vocale active", + "{value} feet": "{value} pieds", + "Fire · FRP {frp} MW": "Feu · FRP {frp} MW", + "The flights layer is not enabled": "La couche des vols n'est pas activée", + "The military layer is not enabled": "La couche des vols militaires n'est pas activée", + "The satellites layer is not enabled": "La couche des satellites n'est pas activée", + "The ais-live-vessels layer is not enabled": "La couche des navires AIS n'est pas activée", + "Could not enable the requested layer": "Impossible d'activer la couche demandée", + "Could not disable the requested layer": "Impossible de désactiver la couche demandée", + "Radio layer unavailable": "Couche radio indisponible", + "Camera navigation is unavailable in the current view": "La navigation de la caméra n'est pas disponible dans la vue actuelle", + "Camera navigation policy unavailable": "Règle de navigation de la caméra indisponible", + "Nearest-aircraft selection supports Flights or Military Flights only": "La sélection de l'aéronef le plus proche ne fonctionne qu'avec Vols ou Vols militaires", + "Nearest-aircraft selection needs a preset, place name, or latitude and longitude": "La sélection de l'aéronef le plus proche nécessite un préréglage, un nom de lieu ou une latitude et une longitude", + "Could not arrive at the requested place": "Impossible d'atteindre le lieu demandé", + "The nearest airborne aircraft could not be selected": "Impossible de sélectionner l'aéronef en vol le plus proche", + "No flights within {radius} of the current view": "Aucun vol dans un rayon de {radius} autour de la vue actuelle", + "No military within {radius} of the current view": "Aucun vol militaire dans un rayon de {radius} autour de la vue actuelle", + "No satellites within {radius} of the current view": "Aucun satellite dans un rayon de {radius} autour de la vue actuelle", + "No vessels within {radius} of the current view": "Aucun navire dans un rayon de {radius} autour de la vue actuelle", + "{layer} is enabled on the {source} feed, but no airborne aircraft is loaded in the {place} view yet": "La couche {layer} est activée sur le flux {source}, mais aucun aéronef en vol n'est encore chargé dans la vue {place}", + "{layer} is enabled, but no airborne aircraft is loaded in the {place} view yet": "La couche {layer} est activée, mais aucun aéronef en vol n'est encore chargé dans la vue {place}", + "{layer} is enabled, but its aircraft feed is unavailable": "La couche {layer} est activée, mais son flux d'aéronefs est indisponible", + "{layer} is enabled, but its destination refresh did not complete": "La couche {layer} est activée, mais son actualisation à destination ne s'est pas terminée", + "{layer} is enabled, but {source} is unavailable": "La couche {layer} est activée, mais {source} est indisponible", + "Could not arrive at {place}": "Impossible d'atteindre {place}", + "{name} is no longer loaded": "{name} n'est plus chargé", + "Unknown target layer: {target}": "Couche cible inconnue : {target}", + "nominal": "nominal", + "{label} on": "{label} : activé", + "Frame aircraft": "Cadrer les aéronefs", + "Frame military aircraft": "Cadrer les aéronefs militaires", + "Frame ships": "Cadrer les navires", + "Frame satellites": "Cadrer les satellites", + "Frame contacts": "Cadrer les contacts", + "{count} aircraft in frame": { + "one": "{count} aéronef dans le cadre", + "many": "{count} d'aéronefs dans le cadre", + "other": "{count} aéronefs dans le cadre" + }, + "{count} military aircraft in frame": { + "one": "{count} aéronef militaire dans le cadre", + "many": "{count} d'aéronefs militaires dans le cadre", + "other": "{count} aéronefs militaires dans le cadre" + }, + "{count} ships in frame": { + "one": "{count} navire dans le cadre", + "many": "{count} de navires dans le cadre", + "other": "{count} navires dans le cadre" + }, + "{count} satellites in frame": { + "one": "{count} satellite dans le cadre", + "many": "{count} de satellites dans le cadre", + "other": "{count} satellites dans le cadre" + }, + "{count} contacts in frame": { + "one": "{count} contact dans le cadre", + "many": "{count} de contacts dans le cadre", + "other": "{count} contacts dans le cadre" + }, + "Nearest military aircraft": "Aéronefs militaires les plus proches", + "Nearest ships": "Navires les plus proches", + "Nearest satellites": "Satellites les plus proches", + "Nearest aircraft": "Aéronefs les plus proches", + "{first} and {second}": "{first} et {second}", + "Layer": "Couche", + "there": "là", + "Camera range {range}": "Distance de la caméra {range}", + "Within {radius} of the view": "Dans un rayon de {radius} autour de la vue", + "Labels on": "Étiquettes activées", + "Framing uses the nearest 80 loaded contacts": "Le cadrage utilise les 80 contacts chargés les plus proches", + "{distance} from {location}": "À {distance} de {location}", + "Altitude {altitude}": "Altitude {altitude}", + "{origin} to {destination}": "De {origin} à {destination}", + "from {origin}": "depuis {origin}", + "to {destination}": "vers {destination}", + "Registration {registration}": "Immatriculation {registration}", + "View state": "État de la vue", + "Marked {count} places": { + "one": "{count} lieu marqué", + "many": "{count} de lieux marqués", + "other": "{count} lieux marqués" + }, + "Nothing marked": "Rien de marqué", + "Not found: {places}": "Introuvable : {places}", + "Tracing outlines": "Tracé des contours", + "Frame flights": "Cadrer les vols", + "Frame military": "Cadrer les vols militaires", + "Frame vessels": "Cadrer les navires", + "Frame {target}": "Cadrer {target}", + "Zoom out to globe": "Dézoomer jusqu'au globe", + "Open data layers": "Ouvrir les couches de données", + "Open or close a panel": "Ouvrir ou fermer un panneau", + "Change context mode": "Changer le mode de contexte", + "Control cockpit": "Piloter le cockpit", + "Change visual style": "Changer le style visuel", + "Adjust HUD": "Régler le HUD", + "Adjust cyber sonar": "Régler le sonar Cyber", + "Adjust detection overlay": "Régler la surcouche de détection", + "Change map stack": "Changer de fond de carte", + "Adjust post-processing": "Régler le post-traitement", + "Control scene": "Piloter la scène", + "Control CCTV": "Piloter les caméras CCTV", + "Control radio": "Piloter la radio", + "Track contact": "Suivre le contact", + "Stop tracking": "Arrêter le suivi", + "Clear marks": "Effacer les marques", + "Move camera": "Déplacer la caméra", + "Fly route": "Survoler l'itinéraire", + "Analyst query": "Requête d'analyse", + "Next ISS pass": "Prochain passage de l'ISS", + "Next satellite pass": "Prochain passage du satellite", + "Mark the map": "Marquer la carte", + "Mark {targets} +{more}": "Marquer {targets} +{more}", + "Mark {targets}": "Marquer : {targets}", + "Fly to {place}": "Rejoindre {place}", + "Fly to Location": "Rejoindre le lieu", + "Nearest aircraft to {place}": "Aéronef le plus proche de {place}", + "Nearest aircraft to Here": "Aéronef le plus proche d'ici", + "Layer on": "Couche : activée", + "Layer off": "Couche : désactivée", + "Zoom out": "Dézoomer", + "Zoom in": "Zoomer", + "Read the view": "Lire la vue", + "Check view state": "Vérifier l'état de la vue", + "Action": "Action", + "Finding places": "Recherche de lieux", + "Tracing outline": "Tracé du contour", + "Looking up place": "Recherche du lieu", + "Flying": "En vol", + "Turning on layer": "Activation de la couche", + "Loading aircraft": "Chargement des aéronefs", + "Picking nearest": "Choix du plus proche", + "Working": "En cours", + "in progress": "en cours", + "done": "terminé", + "failed": "échec", + "cancelled": "annulé", + "Outline traced": "Contour tracé", + "Outline unavailable": "Contour indisponible", + "Source: {label}": "Source : {label}", + "WORKING": "EN COURS", + "DONE": "TERMINÉ", + "Recent speech": "Propos récents", + "HERE": "ICI", "Aircraft cockpit view": "Vue cockpit de l'aéronef", "LEVEL": "NIVEAU", "Estimated destination direction": "Direction estimée de la destination", "DEST ---°": "DEST ---°", "OPTICAL PLANE · 01": "PLAN OPTIQUE · 01", "VISOR LOCK · ACTIVE": "VERROU VISIÈRE · ACTIF", - "GROUND SPEED · KTS": "VITESSE SOL · KTS", + "GROUND SPEED · KTS": "VITESSE SOL · ND", "ALTITUDE · FT": "ALTITUDE · FT", "FIRST PERSON": "PREMIÈRE PERSONNE", - "LIVE TRACK · COURSE ALIGNED": "PISTE LIVE · CAP ALIGNÉ", + "LIVE TRACK · COURSE ALIGNED": "PISTE EN DIRECT · CAP ALIGNÉ", "Cockpit vision style": "Style de vision du cockpit", "Previous cockpit vision style": "Style de vision précédent du cockpit", "Previous vision style": "Style de vision précédent", - "Current cockpit vision style: NORMAL. Activate for next style.": "Style de vision actuel du cockpit : NORMAL. Activer pour le style suivant.", - "Current style: NORMAL — click for next": "Style actuel : NORMAL — cliquer pour le suivant", + "Current cockpit vision style: NORMAL. Activate for next style.": "Style de vision actuel du cockpit : NORMAL. Activer pour le style suivant.", + "Current style: NORMAL — click for next": "Style actuel : NORMAL — cliquer pour le suivant", "CURRENT": "ACTUEL", "Next cockpit vision style": "Style de vision suivant du cockpit", "Next vision style": "Style de vision suivant", "Current aircraft heading": "Cap actuel de l'aéronef", "GROUND SPEED": "VITESSE SOL", + "KTS": "ND", "ALTITUDE": "ALTITUDE", + "FT": "FT", "Contact cockpit summary": "Résumé cockpit du contact", "CONTACT": "CONTACT", "CONTACTS · 250 KM": "CONTACTS · 250 KM", "Contact navigation": "Navigation des contacts", "CONTEXT ONLY": "CONTEXTE SEULEMENT", "Nearby cohort counts": "Nombre de contacts par groupe à proximité", + "FLT": "VOLS", + "MIL": "MIL", + "SITE": "SITES", "NEAREST OBSERVED / MAPPED": "PLUS PROCHE OBSERVÉ / CARTOGRAPHIÉ", "AVAILABLE INPUTS ONLY · NOT AN ALL-CLEAR": "ENTRÉES DISPONIBLES SEULEMENT · PAS UN FEU VERT", + "WX": "MÉTÉO", "Cockpit briefing carousel": "Carrousel de briefing du cockpit", "Estimated flight plan": "Plan de vol estimé", "ESTIMATED FLIGHT PLAN": "PLAN DE VOL ESTIMÉ", @@ -707,15 +2735,21 @@ "Cockpit briefing controls": "Commandes du briefing du cockpit", "Previous briefing page": "Page de briefing précédente", "Next briefing page": "Page de briefing suivante", - "Live signals": "Signaux live", + "Live signals": "Signaux en direct", "Latest regional news": "Dernières actualités régionales", "Location-based information": "Informations selon le lieu", "TEMP": "TEMP", "WIND": "VENT", "SKY": "CIEL", "PRECIP": "PRÉCIP", - "Show Live Signals": "Afficher les signaux live", + "MM": "MM", + "Weather data by Open-Meteo.com": "Données météo d'Open-Meteo.com", + "Cockpit briefing pages": "Pages du briefing du cockpit", + "SIG": "SIG", + "Show Live Signals": "Afficher les signaux en direct", + "NEWS": "ACTUS", "Show Regional News": "Afficher les actus régionales", + "LOCAL": "LOCAL", "Show Local Info": "Afficher les infos locales", "Cockpit display and Radio controls": "Commandes d'affichage et de Radio du cockpit", "DISPLAY": "AFFICHAGE", @@ -727,6 +2761,8 @@ "Next filtered radio station": "Station radio filtrée suivante", "VOLUME": "VOLUME", "Cockpit Radio volume": "Volume de la Radio du cockpit", + "ESC EXIT": "ESC QUITTER", + "C TOGGLE": "C BASCULER", "View switcher": "Sélecteur de vue", "Exit cockpit and return to full globe view": "Quitter le cockpit et revenir à la vue du globe entier", "RESET": "RÉINIT.", @@ -752,7 +2788,11 @@ "Keep location tray open": "Garder le tiroir des lieux ouvert", "Search any location": "Rechercher n'importe quel lieu", "Search location by name or coordinates": "Rechercher un lieu par nom ou coordonnées", - "Search any location...": "Rechercher n'importe quel lieu...", + "Search any location...": "Rechercher n'importe quel lieu…", + "WEATHER": "MÉTÉO", + "Active weather products": "Produits météo actifs", + "RECENT IMAGERY": "IMAGERIE RÉCENTE", + "Imagery days in the box": "Jours d'imagerie dans la zone", "CONTEXT": "CONTEXTE", "Compact Radio controls": "Commandes Radio compactes", "Open detailed Radio controls": "Ouvrir les commandes Radio détaillées", @@ -775,13 +2815,14 @@ "AVAILABLE MISSIONS": "MISSIONS DISPONIBLES", "SELECT A MISSION TO INSPECT": "CHOISIR UNE MISSION À EXAMINER", "LOADING 30-DAY MISSION INDEX": "CHARGEMENT DE L'INDEX DES MISSIONS À 30 JOURS", - "TAB PREVIEWS · ENTER / SPACE SELECTS": "TAB APERÇU · ENTRÉE / ESPACE SÉLECTIONNE", + "TAB PREVIEWS · ENTER / SPACE SELECTS": "TAB APERÇU · ENTER / SPACE SÉLECTIONNE", "Internet radio and local SDR": "Radio Internet et SDR local", "STATION TAG": "TAG DE STATION", "Filter stations by station tag": "Filtrer les stations par tag de station", "All": "Tous", "Enable Radio, then choose a globe marker or use next.": "Activez la Radio, puis choisissez un marqueur du globe ou utilisez suivant.", "DRAG TO TUNE": "GLISSER POUR SYNTONISER", + "Tune available internet radio stations": "Écouter les stations de radio Internet disponibles", "ALL · DRAG THE NEEDLE": "TOUTES · GLISSEZ L'AIGUILLE", "SNAPS TO AVAILABLE STATIONS": "SE CALE SUR LES STATIONS DISPONIBLES", "Radio playback": "Lecture radio", @@ -791,14 +2832,49 @@ "STOP": "ARRÊT", "Stop radio playback": "Arrêter la lecture radio", "Radio volume": "Volume de la radio", - "STATION SITE": "SITE DE STATION", + "STATION SITE": "SITE DE LA STATION", + "DIRECTORY: RADIO BROWSER": "ANNUAIRE : RADIO BROWSER", "Audio connects directly to the broadcaster after you press play. Your IP is visible to that broadcaster.": "Le flux audio se connecte directement au diffuseur après avoir appuyé sur lecture. Votre IP est visible par ce diffuseur.", + "Local RTL-SDR receiver": "Récepteur RTL-SDR local", + "LOCAL RTL-SDR": "RTL-SDR LOCAL", + "Chrome/Edge · WebUSB · one local tuner shared by FM and the Local ADS-B layer.": "Chrome/Edge · WebUSB · un seul tuner local partagé entre la FM et la couche ADS-B local.", + "Use your location for faster ADS-B position decoding": "Utiliser votre position pour décoder plus vite les positions ADS-B", + "CHANGE DEVICE": "CHANGER", + "Choose a different RTL-SDR or receiver channel": "Choisir un autre RTL-SDR ou un autre canal du récepteur", + "RTL-SDR receiver mode": "Mode du récepteur RTL-SDR", + "GAIN": "GAIN", + "RTL-SDR tuner gain for the current mode": "Gain du tuner RTL-SDR pour le mode actuel", + "AUTO": "AUTO", + "MSG/S": "MSG/S", + "HEARD": "CAPTÉS", + "POSITIONED": "POSITIONNÉS", + "FM MHZ": "FM MHZ", + "TUNE": "RÉGLER", + "Seek broadcast FM stations": "Rechercher des stations FM", + "◀ SEEK": "◀ RECH.", + "SEEK ▶": "RECH. ▶", + "SDR VOL": "VOL. SDR", + "Local SDR volume": "Volume du SDR local", "Intelligence HUD (H)": "HUD de renseignement (H)", "Layout": "Disposition", "HUD layout": "Disposition du HUD", "Tactical": "Tactique", "Operator": "Opérateur", "Minimal": "Minimal", + "Cyber": "Cyber", + "Sonar": "Sonar", + "Cyber sonar contact scanner": "Scanner de contacts du sonar Cyber", + "Rings": "Anneaux", + "Sonar ring count": "Nombre d'anneaux du sonar", + "Range": "Portée", + "Sonar ring range": "Portée des anneaux du sonar", + "Power": "Puissance", + "Sonar intensity": "Intensité du sonar", + "Opacity": "Opacité", + "Cyber contact and label opacity": "Opacité des contacts et étiquettes Cyber", + "Minimum opacity for map dots, icons, models, brackets, and labels between sonar passes": "Opacité minimale des points, icônes, modèles, crochets et étiquettes de la carte entre deux balayages du sonar", + "Sector": "Secteur", + "Sonar sector width": "Largeur du secteur du sonar", "Detection Overlay (D)": "Surcouche de détection (D)", "Detection overlay": "Surcouche de détection", "Detection label density": "Densité des étiquettes de détection", @@ -817,11 +2893,31 @@ "Models": "Modèles", "3D model coverage": "Couverture des modèles 3D", "Proximity": "Proximité", - "Scope — the circular viewport mask": "Scope — le masque circulaire de la vue", - "Scope": "Scope", + "Scope — the circular viewport mask": "Lunette — le masque circulaire de la vue", + "Scope": "Lunette", "Feather": "Adouci", - "Scope edge feather": "Adoucissement du bord du scope", - "Scope edge feather as a percentage of the keyhole radius": "Adoucissement du bord du scope, en pourcentage du rayon de l'ouverture", + "Scope edge feather": "Adoucissement du bord de la lunette", + "Scope edge feather as a percentage of the keyhole radius": "Adoucissement du bord de la lunette, en pourcentage du rayon de l'ouverture", + "Draw on the world — click vertices, double-click or Enter to finish, Esc to cancel": "Dessinez sur le monde — cliquez sur les sommets, double-clic ou Enter pour terminer, Esc pour annuler", + "Shape": "Forme", + "Shape to draw": "Forme à dessiner", + "Area": "Zone", + "Line": "Ligne", + "Pin": "Épingle", + "Label (optional)": "Étiquette (facultatif)", + "Label for the drawn shape": "Étiquette de la forme dessinée", + "Colour of the drawn shape": "Couleur de la forme dessinée", + "Primary": "Principale", + "Amber": "Ambre", + "Cyan": "Cyan", + "Green": "Vert", + "Red": "Rouge", + "Clear": "Effacer", + "Remove every mark from the board": "Retirer toutes les marques du tableau", + "Show your own GeoJSON, KML, KMZ or GPX files on the globe (or drop them onto it). File bytes stay on this device; overlays can appear in map screenshots shared with voice.": "Affichez vos propres fichiers GeoJSON, KML, KMZ ou GPX sur le globe (ou déposez-les dessus). Les fichiers restent sur cet appareil ; les surcouches peuvent apparaître dans les captures de carte partagées avec la voix.", + "Import": "Importer", + "Choose GeoJSON, KML, KMZ or GPX files": "Choisir des fichiers GeoJSON, KML, KMZ ou GPX", + "Imported files": "Fichiers importés", "Celestial": "Céleste", "Hide UI chrome": "Masquer l'interface", "Clean UI": "Vue épurée", @@ -832,12 +2928,13 @@ "Sharpen intensity": "Intensité de la netteté", "EXIT CLEAN VIEW": "QUITTER LA VUE ÉPURÉE", "Return UI controls": "Rétablir les commandes de l'interface", - "Initializing photorealistic world...": "Initialisation du monde photoréaliste...", + "Initializing photorealistic world...": "Initialisation du monde photoréaliste…", "DATA LAYERS": "COUCHES DE DONNÉES", + "ACQUIRING FRAME": "ACQUISITION DE L'IMAGE", "NEAREST": "PROCHE", "CCTV camera": "Caméra CCTV", "CALIBRATION": "CALIBRATION", - "Drag the camera in the world: rings rotate, arrows move, handles set range/FOV": "Faites glisser la caméra dans le monde : les anneaux pivotent, les flèches déplacent, les poignées règlent portée/FOV", + "Drag the camera in the world: rings rotate, arrows move, handles set range/FOV": "Faites glisser la caméra dans le monde : les anneaux pivotent, les flèches déplacent, les poignées règlent portée/FOV", "Camera pose — click a value to type": "Pose de la caméra — cliquer sur une valeur pour la saisir", "Heading (compass °) — click to type": "Cap (boussole °) — cliquer pour saisir", "Pitch (° up/down) — click to type": "Inclinaison (° haut/bas) — cliquer pour saisir", @@ -849,6 +2946,26 @@ "SAVE CAL": "ENREG. CAL", "RESET CAL": "RÉINIT. CAL", "SCENE SUMMARY": "RÉSUMÉ DE SCÈNE", + "STREET LEVEL": "NIVEAU RUE", + "Turn Street Level on or off": "Activer ou désactiver Niveau rue", + "Show the street-level view full screen (Esc shrinks it)": "Afficher la vue au niveau de la rue en plein écran (Esc la réduit)", + "Image fit": "Ajustement de l'image", + "FIT": "AJUSTER", + "Fit: show the whole photo, with dark bars where its shape differs from the frame": "Ajuster : affiche toute la photo, avec des bandes sombres là où son format diffère du cadre", + "FILL": "REMPLIR", + "Fill: fill the frame edge to edge, cropping the photo": "Remplir : remplit le cadre bord à bord en recadrant la photo", + "Close the image and deselect it on the map": "Fermer l'image et la désélectionner sur la carte", + "Close the street-level image": "Fermer l'image au niveau de la rue", + "Street-level viewer": "Visionneuse au niveau de la rue", + "Open this image on the provider's site": "Ouvrir cette image sur le site du fournisseur", + "Imagery providers": "Fournisseurs d'images", + "PROVIDERS": "FOURNISSEURS", + "Imagery filters": "Filtres d'images", + "IMAGERY": "IMAGES", + "Panorama filter": "Filtre de panoramas", + "ALL": "TOUTES", + "FLAT": "PLATES", + "SINCE": "DEPUIS", "SCENES": "SCÈNES", "Scene recipe": "Recette de scène", "NEW": "NOUV.", @@ -858,28 +2975,31 @@ "EXPORT PRESETS": "EXPORTER LES PRÉRÉGLAGES", "IMPORT": "IMPORTER", "RUN LOG": "JOURNAL", - "POWER UP": "POWER UP", + "POWER UP": "ALLUMER", "GROUND STATION · PROVIDER SETTINGS": "STATION AU SOL · PARAMÈTRES DES FOURNISSEURS", "Close key setup": "Fermer la configuration des clés", "Power up the globe": "Allumer le globe", - "The globe already flies keyless. Every key below switches on another real feed — paste one and it's saved into this app's local configuration, then the server restarts itself. Server-side keys stay on this machine; Google Maps and Cesium ion run in the browser and must be provider-restricted. Keys you configured elsewhere are shown but never touched.": "Le globe fonctionne déjà sans clé. Chaque clé ci-dessous active un flux réel de plus : collez-en une et elle est enregistrée dans la configuration locale de l'application, puis le serveur redémarre. Les clés côté serveur restent sur cette machine ; Google Maps et Cesium ion s'exécutent dans le navigateur et doivent être restreintes au fournisseur. Les clés configurées ailleurs sont affichées mais jamais modifiées.", + "The globe already flies keyless. Every key below switches on another real feed — paste one and it's saved into this app's local configuration, then the server restarts itself. Server-side keys stay on this machine; Google Maps and Cesium ion run in the browser and must be provider-restricted. Keys you configured elsewhere are shown but never touched.": "Le globe fonctionne déjà sans clé. Chaque clé ci-dessous active un flux réel de plus : collez-en une et elle est enregistrée dans la configuration locale de l'application, puis le serveur redémarre. Les clés côté serveur restent sur cette machine ; Google Maps et Cesium ion s'exécutent dans le navigateur et doivent être restreintes au fournisseur. Les clés configurées ailleurs sont affichées mais jamais modifiées.", "SAVE KEYS": "ENREGISTRER LES CLÉS", - "ESC to close": "ÉCHAP pour fermer", + "ESC to close": "ESC pour fermer", "The Google Maps key buys the photorealistic planet — everything else stacks on top.": "La clé Google Maps offre la planète photoréaliste, tout le reste s'y superpose.", - "NO PLACE LEFT BEHIND": "NO PLACE LEFT BEHIND", + "NO PLACE LEFT BEHIND": "AUCUN LIEU OUBLIÉ", "ACTIVE STYLE": "STYLE ACTIF", "Globe actions": "Actions du globe", "Turn off all selected data layers": "Désactiver toutes les couches de données sélectionnées", "Copy share link": "Copier le lien de partage", + "Toggle straight-down and tilted map views": "Basculer entre vue verticale et vue inclinée de la carte", + "Reset map to north up": "Réorienter la carte nord en haut", + "Reset map bearing to north": "Réinitialiser l'orientation de la carte vers le nord", "Reset camera and return to full globe view": "Réinitialiser la caméra et revenir à la vue du globe entier", "MISSION CONTROL · FIRST LAUNCH": "CENTRE DE CONTRÔLE · PREMIER LANCEMENT", "Choose your first view": "Choisissez votre première vue", - "LIVE CONTACTS": "CONTACTS LIVE", + "LIVE CONTACTS": "CONTACTS EN DIRECT", "Aircraft, vessels and nearby intelligence": "Avions, navires et renseignements à proximité", "Launches, spacecraft and orbital context": "Lancements, vaisseaux et contexte orbital", "EXPLORE MANUALLY": "EXPLORER MANUELLEMENT", "Begin with a clean globe": "Commencer avec un globe vierge", "Don't show this again": "Ne plus afficher", - "ESC to dismiss": "ÉCHAP pour fermer", - "Tip: the GEV MIC button in the dock lets you talk to the map.": "Astuce : le bouton GEV MIC du dock permet de parler à la carte." + "ESC to dismiss": "ESC pour fermer", + "Tip: the GEV MIC button in the dock lets you talk to the map.": "Astuce : le bouton GEV MIC du dock permet de parler à la carte." } diff --git a/src/i18n/same-as-english.json b/src/i18n/same-as-english.json index 83c8897d8..3889dd09f 100644 --- a/src/i18n/same-as-english.json +++ b/src/i18n/same-as-english.json @@ -124,6 +124,185 @@ "ΔN", "▲ {frp} MW" ], + "fr": [ + "1090 MHz", + "978 MHz UAT", + "ALTITUDE", + "ALTITUDE · FT", + "ANIME", + "AUTO", + "Action", + "Allocation", + "Altitude {altitude}", + "Ambient", + "Anime", + "Austin", + "Aviation / Marine", + "BRG {value}°", + "BRG —", + "Bloom", + "Blues", + "Bus", + "CAL {value}", + "CAL · {badge}", + "CALIBRATION", + "CARGO", + "CAUSE", + "CCTV", + "CCTV OFF", + "CCTV ON", + "COCKPIT", + "COMMERCIAL", + "CONTACT", + "CONTACTS", + "CONTACTS · 250 KM", + "CRS {value}°", + "CRT", + "Country", + "Cyan", + "Cyber", + "Cyclones · NHC / CPHC", + "DENSE", + "DENSE ···", + "DENSE ✕", + "DEST ---°", + "DEST {bearing}", + "DESTINATION", + "Dance", + "Drone", + "ENE", + "ESE", + "EUROPE", + "FLIR", + "FM MHZ", + "FOV", + "FOV {value}°", + "FT", + "Ferry", + "Folk", + "Funk", + "GAIN", + "GEO", + "GOOGLE STREET VIEW", + "Gain", + "Google Street View", + "Grain", + "HDG", + "HDG {value}°", + "Hip-Hop", + "House", + "IMAGE", + "Indie", + "Ironbow", + "Jazz", + "LOCAL", + "Landsat 8/9", + "Landsat 8/9 via HLS", + "Los Angeles", + "MIC", + "MIL", + "MINI", + "MISSION", + "MM", + "MSG/S", + "Metal", + "Minimal", + "Minutes", + "Mode", + "NAV", + "NE", + "NNE", + "NOIR", + "NORMAL", + "NVG", + "New York", + "Noir", + "Normal", + "OFF", + "OK", + "ON", + "ON/OFF", + "Oldies", + "PAUSE", + "POSITION {age}", + "PROJ OFF", + "PROJECTION OFF", + "PROJECTION ON", + "PROPAGATION", + "Paris", + "Pause", + "Plan", + "Pop", + "Punk", + "RADIO", + "REC", + "Radio", + "Reggae", + "Rock", + "S2 GhostMaps", + "SAR", + "SE", + "SIG", + "SOURCE", + "SQUAWK {code} · {status}", + "SRC {value}", + "SSE", + "STANDARD", + "STATION", + "STD", + "San Francisco", + "Satellites", + "Saturation", + "Sonar", + "Soul", + "Source", + "Station", + "Station {id}", + "Style", + "TAGS · {tags}", + "TEMP", + "TYPE", + "Tallinn", + "Techno", + "Tokyo", + "Train", + "Trance", + "USB {rate} msg/s", + "VOLUME", + "VS", + "WHOT/BHOT", + "audio {state}", + "dB", + "ft", + "hPa", + "image", + "installation class|BASE", + "installation class|INSTALLATION", + "km", + "km/h", + "max {value} MW", + "min", + "mini", + "mph", + "nominal", + "satellite", + "standard", + "station", + "voice|OFF", + "{count} MSGS", + "{count} SOURCES", + "{count} messages", + "{n} cyclones", + "{n} satellites", + "{rate} msg/s", + "{value} KM", + "{value} KM/H", + "{value} KM/S", + "ΔE", + "ΔN", + "Ⅱ PAUSE", + "▲ {frp} MW" + ], "ru": [ "AIS: --", "AIS: {name}", From 9f71a62d12694f50e2206ec3e142bd19aa34e266 Mon Sep 17 00:00:00 2001 From: German Khokhlov Date: Wed, 28 Oct 2026 13:00:14 +0400 Subject: [PATCH 15/83] i18n(fr): ship French in the language picker MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Register fr: catalog in CATALOGS, LOCALES and LOCALE_NAMES (Français); any fr-* browser tag (fr-CA, fr-BE, fr-CH) maps to it. - package-boundaries.json lists fr.json next to the other catalogs. - Picker and locale tests cover the new row and its local names. - docs/translations/fr.md: style, typography, plurals and glossary; TRANSLATORS.md and CURRENT-STATE.md list French as shipped. Co-Authored-By: Claude Opus 5.5 --- docs/CURRENT-STATE.md | 2 +- docs/TRANSLATORS.md | 4 +- docs/translations/fr.md | 91 +++++++++++++++++++++++++++++++++ scripts/package-boundaries.json | 43 ++++++++++++++++ src/i18n/i18n.test.mjs | 3 ++ src/i18n/index.js | 9 +++- src/i18n/locale.js | 10 +++- src/ui/localePicker.test.mjs | 8 +-- 8 files changed, 162 insertions(+), 8 deletions(-) create mode 100644 docs/translations/fr.md diff --git a/docs/CURRENT-STATE.md b/docs/CURRENT-STATE.md index c55031a6a..16b9a19ac 100644 --- a/docs/CURRENT-STATE.md +++ b/docs/CURRENT-STATE.md @@ -3733,7 +3733,7 @@ test:track` 43 tracking invariants · headless QA harnesses under ### Interface localization (October 2026) -Shipped locales: **en** (source and fallback), **es**, **ru**, **zh-CN** and **zh-Hant**. The code lives in +Shipped locales: **en** (source and fallback), **es**, **fr**, **ru**, **zh-CN** and **zh-Hant**. The code lives in `src/i18n/`. How to mark UI text: [`docs/I18N.md`](./I18N.md); translator workflow: [`docs/TRANSLATORS.md`](./TRANSLATORS.md). diff --git a/docs/TRANSLATORS.md b/docs/TRANSLATORS.md index 830ca155e..dd7ecaa52 100644 --- a/docs/TRANSLATORS.md +++ b/docs/TRANSLATORS.md @@ -1,6 +1,6 @@ # Translating God's Eye View -Shipped languages: **English** (source and fallback), **Spanish** (`es`), **Russian** (`ru`), **Simplified Chinese** (`zh-CN`) and **Traditional Chinese** (`zh-Hant`). +Shipped languages: **English** (source and fallback), **Spanish** (`es`), **French** (`fr`), **Russian** (`ru`), **Simplified Chinese** (`zh-CN`) and **Traditional Chinese** (`zh-Hant`). ## How it works @@ -63,4 +63,4 @@ These are contracts, not copy: layer ids and registry keys, status enums and oth ## Language notes -Each language keeps its glossary, plural forms, units and style in its own file, `docs/translations/.md`: [Spanish](./translations/es.md), [Russian](./translations/ru.md), [Simplified Chinese](./translations/zh-CN.md), [Traditional Chinese](./translations/zh-Hant.md). Read it before translating, and add a term there when you settle on one. +Each language keeps its glossary, plural forms, units and style in its own file, `docs/translations/.md`: [Spanish](./translations/es.md), [French](./translations/fr.md), [Russian](./translations/ru.md), [Simplified Chinese](./translations/zh-CN.md), [Traditional Chinese](./translations/zh-Hant.md). Read it before translating, and add a term there when you settle on one. diff --git a/docs/translations/fr.md b/docs/translations/fr.md new file mode 100644 index 000000000..80960e48d --- /dev/null +++ b/docs/translations/fr.md @@ -0,0 +1,91 @@ +# French (`fr`) + +Catalog: `src/i18n/locales/fr.json`. General rules: [TRANSLATORS.md](../TRANSLATORS.md). + +Translation source: abiyeenzo (#907); the French part of meirm's #312 was used for comparison. + +## Style + +- Standard French that reads naturally in France, Belgium, Switzerland and Canada; avoid regionalisms. +- Address the user with "vous" imperatives: « Cliquez », « Activez », « Réessayez ». Tooltips that name an action use the infinitive: « Réduire le panneau », « Réinitialiser la caméra ». UPPERCASE HUD instructions also use the infinitive: « CLIQUER SUR UNE CAMÉRA POUR L'ACTIVER ». +- Sentence case, not Title Case: "Live Flights" → « Vols en direct ». UPPERCASE English stays UPPERCASE, accents included: « ÉTAT », « PRÉC. ». +- Typography: a narrow no-break space (U+202F) goes before `:` `;` `?` `!` and `%`, and inside « » quotes: `Supprimer le plan « {shot} » ?`. It keeps the sign on the same line as the word before it. Do not type a plain space there. Ellipsis is `…`, not `...`. Dashes keep their spaces: « flux indisponible — réessayez ». +- Short labels, chips and HUD readouts stay short. A standard abbreviation with a period beats a wrapped line: PRÉC., SUIV., RÉINIT., ENREG., INDISP., DIST. +- The HUD codes HDG, BRG, CRS, FOV, DEST, SPD and ALT stay in English everywhere, as in cockpit avionics. Words are translated: RANGE → « PORTÉE », heading in a sentence → « cap ». +- ON and OFF stay as they are on HUD toggles and chips (« CCTV ON », « PROJECTION OFF »); in a sentence use « activé » / « désactivé ». +- Keyboard keys stay in English: Space, Esc, Enter, Tab, Shift, Backspace, H, 1–9 (« Maintenez Space pour parler », « ESC pour fermer »). +- Units: km, m, km/h, m/s, nd (knots), ft (feet), h, min, s, with a space before the unit: « 250 km », « il y a 5 min »; in UPPERCASE text KM, KM/S, ND, FT, MIN. MW, dBZ, hPa and `°` stay. Decimal comma in fixed numbers: « 28,2710° N », « M4,4 ». Money: « 12 k$ », « 3 M$ », « 2 Md$ ». +- "ago" goes before the time: « il y a {count} min ». When a placeholder already holds a localized "ago" text (`{age}`, `{ago}`), do not add « il y a » again. +- Round-about exit ordinals: 1re, 2e, 3e… (« prenez la 1re sortie »). + +## Plurals + +A `tn()` entry needs three forms. `Intl.PluralRules('fr')` picks: + +| Form | Counts | Example | +| ------- | -------------------------------------- | -------------------- | +| `one` | 0 and 1, fractions below 2 (1,5) | 1 caméra, 0 caméra | +| `many` | 1 000 000, 2 000 000… (exact millions) | 1 000 000 de caméras | +| `other` | everything else: 2–999 999, 2,5… | 3 caméras | + +The `many` form is the `other` text with « de » (« d' » before a vowel) after the number: « {count} de couches effacées », « {count} D'ENTRÉES INCONNUES ». When the words after the number cannot agree (an UPPERCASE readout, a list), put the number after a colon in every form: « CAPTÉS : {count} ». + +## Glossary + +| English | Français | +| ---------------------------------------------- | --------------------------------------------------------------- | +| layer / data layer | couche / couche de données | +| feed / source / data source | flux / source / source de données | +| LIVE (status) / live data | DIRECT / données en direct | +| SIMULATED | SIMULÉ | +| stale / degraded / unavailable | obsolète / dégradé / indisponible | +| retry / retrying | nouvel essai / réessayez | +| rate-limited | limite de requêtes atteinte | +| key (API key) / POWER UP / POWERED UP | clé (clé API) / ALLUMER / ALLUMÉ | +| Provider Settings | paramètres des fournisseurs | +| enable / disable | activer / désactiver | +| globe / map / map source / basemap / map stack | globe / carte / source de carte / fond de carte / fond de carte | +| tile (map) | tuile | +| aircraft / flight / military flights | aéronef (avion in short copy) / vol / vols militaires | +| vessel, ship | navire | +| satellite / shell (Starlink) / DENSE | satellite / couche de la constellation / DENSE | +| launch / launch site / space mission | lancement / site de lancement / mission spatiale | +| ascent / replay / payload / stage / downrange | ascension / rejeu / charge utile / étage / distance parcourue | +| contact / tracking / track (HUD) | contact / suivi / piste | +| installation / site | installation / site | +| mapped / observed | cartographié / observé | +| camera / CCTV camera / ALPR camera | caméra / caméra CCTV / caméra LAPI | +| earthquake | séisme | +| active fire (FIRMS detection) / wildfire | feu actif / incendie | +| contained (wildfire) | maîtrisé | +| advisory (NHC/CPHC cyclone) | bulletin | +| forecast / lead hours / valid / issued | prévision / échéances / valide / émise | +| AQHI (Canada) | CQAS (cote air santé) | +| radio station / tune | station / régler | +| bikeshare / transit | vélos en libre-service / transports en commun | +| route (directions) / turn (maneuver) | itinéraire / manœuvre | +| scene / shot / scene recipe | scène / plan / recette de scène | +| bundle / data pack / anchor | archive / paquet de données / ancre | +| story beat | étape du récit | +| briefing / panel / dock | briefing / panneau / dock | +| cockpit | cockpit | +| preset / visual preset | préréglage / préréglage visuel | +| Scope (circular viewport mask) / keyhole | lunette / ouverture | +| detection overlay | surcouche de détection | +| Clean UI | vue épurée | +| Street Level (layer) / Street View (Google) | Niveau rue / Street View | +| Recent Imagery / box | imagerie récente / zone | +| pin (Draw tool) / pin (Recent Imagery) | épingle / épingler | +| Cyber (HUD layout, effect) | Cyber | +| heading, course / altitude / ground speed | cap / altitude / vitesse sol | +| HDG / BRG / CRS / FOV / DEST / SPD / ALT | unchanged | +| RANGE / PITCH / HGT (CCTV calibration chips) | PORTÉE / INCL. / HAUT. | +| PREV / PREVIOUS / NEXT (chips) | PRÉC. / PRÉC. / SUIV. | +| Previous / Next (button text) | Précédent / Suivant | +| L / R (relative bearing) | G / D | +| SIG / NEWS / LOCAL (briefing tabs) | SIG / ACTUS / LOCAL | +| compass points (N, NNE, …, W, NW) | N, NNE, …, O, NO | +| NOT AN ALL-CLEAR | PAS UN FEU VERT | +| AI agent | agent IA | +| share (a view or link) | partager | +| click / click to … | cliquez / cliquer pour … | diff --git a/scripts/package-boundaries.json b/scripts/package-boundaries.json index 9f06f73f6..2b62411a3 100644 --- a/scripts/package-boundaries.json +++ b/scripts/package-boundaries.json @@ -440,6 +440,7 @@ "src/i18n/index.js", "src/i18n/locale.js", "src/i18n/locales/es.json", + "src/i18n/locales/fr.json", "src/i18n/locales/ru.json", "src/i18n/locales/zh-CN.json", "src/i18n/locales/zh-Hant.json" @@ -480,6 +481,7 @@ "src/i18n/index.js", "src/i18n/locale.js", "src/i18n/locales/es.json", + "src/i18n/locales/fr.json", "src/i18n/locales/ru.json", "src/i18n/locales/zh-CN.json", "src/i18n/locales/zh-Hant.json" @@ -510,6 +512,7 @@ "src/i18n/index.js", "src/i18n/locale.js", "src/i18n/locales/es.json", + "src/i18n/locales/fr.json", "src/i18n/locales/ru.json", "src/i18n/locales/zh-CN.json", "src/i18n/locales/zh-Hant.json", @@ -532,6 +535,7 @@ "src/i18n/index.js", "src/i18n/locale.js", "src/i18n/locales/es.json", + "src/i18n/locales/fr.json", "src/i18n/locales/ru.json", "src/i18n/locales/zh-CN.json", "src/i18n/locales/zh-Hant.json" @@ -549,6 +553,7 @@ "src/i18n/index.js", "src/i18n/locale.js", "src/i18n/locales/es.json", + "src/i18n/locales/fr.json", "src/i18n/locales/ru.json", "src/i18n/locales/zh-CN.json", "src/i18n/locales/zh-Hant.json" @@ -569,6 +574,7 @@ "src/i18n/index.js", "src/i18n/locale.js", "src/i18n/locales/es.json", + "src/i18n/locales/fr.json", "src/i18n/locales/ru.json", "src/i18n/locales/zh-CN.json", "src/i18n/locales/zh-Hant.json", @@ -596,6 +602,7 @@ "src/i18n/index.js", "src/i18n/locale.js", "src/i18n/locales/es.json", + "src/i18n/locales/fr.json", "src/i18n/locales/ru.json", "src/i18n/locales/zh-CN.json", "src/i18n/locales/zh-Hant.json", @@ -631,6 +638,7 @@ "src/i18n/index.js", "src/i18n/locale.js", "src/i18n/locales/es.json", + "src/i18n/locales/fr.json", "src/i18n/locales/ru.json", "src/i18n/locales/zh-CN.json", "src/i18n/locales/zh-Hant.json", @@ -648,6 +656,7 @@ "src/i18n/index.js", "src/i18n/locale.js", "src/i18n/locales/es.json", + "src/i18n/locales/fr.json", "src/i18n/locales/ru.json", "src/i18n/locales/zh-CN.json", "src/i18n/locales/zh-Hant.json", @@ -807,6 +816,7 @@ "src/i18n/index.js", "src/i18n/locale.js", "src/i18n/locales/es.json", + "src/i18n/locales/fr.json", "src/i18n/locales/ru.json", "src/i18n/locales/zh-CN.json", "src/i18n/locales/zh-Hant.json", @@ -929,6 +939,7 @@ "src/i18n/index.js", "src/i18n/locale.js", "src/i18n/locales/es.json", + "src/i18n/locales/fr.json", "src/i18n/locales/ru.json", "src/i18n/locales/zh-CN.json", "src/i18n/locales/zh-Hant.json", @@ -997,6 +1008,7 @@ "src/i18n/index.js", "src/i18n/locale.js", "src/i18n/locales/es.json", + "src/i18n/locales/fr.json", "src/i18n/locales/ru.json", "src/i18n/locales/zh-CN.json", "src/i18n/locales/zh-Hant.json", @@ -1046,6 +1058,7 @@ "src/i18n/index.js", "src/i18n/locale.js", "src/i18n/locales/es.json", + "src/i18n/locales/fr.json", "src/i18n/locales/ru.json", "src/i18n/locales/zh-CN.json", "src/i18n/locales/zh-Hant.json" @@ -1109,6 +1122,7 @@ "src/i18n/index.js", "src/i18n/locale.js", "src/i18n/locales/es.json", + "src/i18n/locales/fr.json", "src/i18n/locales/ru.json", "src/i18n/locales/zh-CN.json", "src/i18n/locales/zh-Hant.json" @@ -1139,6 +1153,7 @@ "src/i18n/index.js", "src/i18n/locale.js", "src/i18n/locales/es.json", + "src/i18n/locales/fr.json", "src/i18n/locales/ru.json", "src/i18n/locales/zh-CN.json", "src/i18n/locales/zh-Hant.json", @@ -1170,6 +1185,7 @@ "src/i18n/index.js", "src/i18n/locale.js", "src/i18n/locales/es.json", + "src/i18n/locales/fr.json", "src/i18n/locales/ru.json", "src/i18n/locales/zh-CN.json", "src/i18n/locales/zh-Hant.json" @@ -1201,6 +1217,7 @@ "src/i18n/index.js", "src/i18n/locale.js", "src/i18n/locales/es.json", + "src/i18n/locales/fr.json", "src/i18n/locales/ru.json", "src/i18n/locales/zh-CN.json", "src/i18n/locales/zh-Hant.json", @@ -1235,6 +1252,7 @@ "src/i18n/index.js", "src/i18n/locale.js", "src/i18n/locales/es.json", + "src/i18n/locales/fr.json", "src/i18n/locales/ru.json", "src/i18n/locales/zh-CN.json", "src/i18n/locales/zh-Hant.json" @@ -1278,6 +1296,7 @@ "src/i18n/index.js", "src/i18n/locale.js", "src/i18n/locales/es.json", + "src/i18n/locales/fr.json", "src/i18n/locales/ru.json", "src/i18n/locales/zh-CN.json", "src/i18n/locales/zh-Hant.json", @@ -1315,6 +1334,7 @@ "src/i18n/index.js", "src/i18n/locale.js", "src/i18n/locales/es.json", + "src/i18n/locales/fr.json", "src/i18n/locales/ru.json", "src/i18n/locales/zh-CN.json", "src/i18n/locales/zh-Hant.json", @@ -1366,6 +1386,7 @@ "src/i18n/index.js", "src/i18n/locale.js", "src/i18n/locales/es.json", + "src/i18n/locales/fr.json", "src/i18n/locales/ru.json", "src/i18n/locales/zh-CN.json", "src/i18n/locales/zh-Hant.json" @@ -1396,6 +1417,7 @@ "src/i18n/index.js", "src/i18n/locale.js", "src/i18n/locales/es.json", + "src/i18n/locales/fr.json", "src/i18n/locales/ru.json", "src/i18n/locales/zh-CN.json", "src/i18n/locales/zh-Hant.json" @@ -1445,6 +1467,7 @@ "src/i18n/index.js", "src/i18n/locale.js", "src/i18n/locales/es.json", + "src/i18n/locales/fr.json", "src/i18n/locales/ru.json", "src/i18n/locales/zh-CN.json", "src/i18n/locales/zh-Hant.json" @@ -1509,6 +1532,7 @@ "src/i18n/index.js", "src/i18n/locale.js", "src/i18n/locales/es.json", + "src/i18n/locales/fr.json", "src/i18n/locales/ru.json", "src/i18n/locales/zh-CN.json", "src/i18n/locales/zh-Hant.json", @@ -1539,6 +1563,7 @@ "src/i18n/index.js", "src/i18n/locale.js", "src/i18n/locales/es.json", + "src/i18n/locales/fr.json", "src/i18n/locales/ru.json", "src/i18n/locales/zh-CN.json", "src/i18n/locales/zh-Hant.json" @@ -1580,6 +1605,7 @@ "src/i18n/index.js", "src/i18n/locale.js", "src/i18n/locales/es.json", + "src/i18n/locales/fr.json", "src/i18n/locales/ru.json", "src/i18n/locales/zh-CN.json", "src/i18n/locales/zh-Hant.json" @@ -1603,6 +1629,7 @@ "src/i18n/index.js", "src/i18n/locale.js", "src/i18n/locales/es.json", + "src/i18n/locales/fr.json", "src/i18n/locales/ru.json", "src/i18n/locales/zh-CN.json", "src/i18n/locales/zh-Hant.json" @@ -1660,6 +1687,7 @@ "src/i18n/index.js", "src/i18n/locale.js", "src/i18n/locales/es.json", + "src/i18n/locales/fr.json", "src/i18n/locales/ru.json", "src/i18n/locales/zh-CN.json", "src/i18n/locales/zh-Hant.json" @@ -1723,6 +1751,7 @@ "src/i18n/index.js", "src/i18n/locale.js", "src/i18n/locales/es.json", + "src/i18n/locales/fr.json", "src/i18n/locales/ru.json", "src/i18n/locales/zh-CN.json", "src/i18n/locales/zh-Hant.json", @@ -2606,6 +2635,7 @@ "src/i18n/index.js", "src/i18n/locale.js", "src/i18n/locales/es.json", + "src/i18n/locales/fr.json", "src/i18n/locales/ru.json", "src/i18n/locales/zh-CN.json", "src/i18n/locales/zh-Hant.json", @@ -3191,6 +3221,7 @@ "src/i18n/index.js", "src/i18n/locale.js", "src/i18n/locales/es.json", + "src/i18n/locales/fr.json", "src/i18n/locales/ru.json", "src/i18n/locales/zh-CN.json", "src/i18n/locales/zh-Hant.json", @@ -3302,6 +3333,7 @@ "src/data/cameraArrival.js", "src/i18n/locale.js", "src/i18n/locales/es.json", + "src/i18n/locales/fr.json", "src/i18n/locales/ru.json", "src/i18n/locales/zh-CN.json", "src/i18n/locales/zh-Hant.json", @@ -3326,6 +3358,7 @@ "src/i18n/index.js", "src/i18n/locale.js", "src/i18n/locales/es.json", + "src/i18n/locales/fr.json", "src/i18n/locales/ru.json", "src/i18n/locales/zh-CN.json", "src/i18n/locales/zh-Hant.json" @@ -3363,6 +3396,7 @@ "src/i18n/index.js", "src/i18n/locale.js", "src/i18n/locales/es.json", + "src/i18n/locales/fr.json", "src/i18n/locales/ru.json", "src/i18n/locales/zh-CN.json", "src/i18n/locales/zh-Hant.json", @@ -3390,6 +3424,7 @@ "src/i18n/index.js", "src/i18n/locale.js", "src/i18n/locales/es.json", + "src/i18n/locales/fr.json", "src/i18n/locales/ru.json", "src/i18n/locales/zh-CN.json", "src/i18n/locales/zh-Hant.json" @@ -3482,6 +3517,7 @@ "src/i18n/index.js", "src/i18n/locale.js", "src/i18n/locales/es.json", + "src/i18n/locales/fr.json", "src/i18n/locales/ru.json", "src/i18n/locales/zh-CN.json", "src/i18n/locales/zh-Hant.json", @@ -3538,6 +3574,7 @@ "src/i18n/index.js", "src/i18n/locale.js", "src/i18n/locales/es.json", + "src/i18n/locales/fr.json", "src/i18n/locales/ru.json", "src/i18n/locales/zh-CN.json", "src/i18n/locales/zh-Hant.json", @@ -3793,6 +3830,7 @@ "src/i18n/index.js", "src/i18n/locale.js", "src/i18n/locales/es.json", + "src/i18n/locales/fr.json", "src/i18n/locales/ru.json", "src/i18n/locales/zh-CN.json", "src/i18n/locales/zh-Hant.json" @@ -3837,6 +3875,7 @@ "src/i18n/index.js", "src/i18n/locale.js", "src/i18n/locales/es.json", + "src/i18n/locales/fr.json", "src/i18n/locales/ru.json", "src/i18n/locales/zh-CN.json", "src/i18n/locales/zh-Hant.json" @@ -3891,6 +3930,7 @@ "src/i18n/index.js", "src/i18n/locale.js", "src/i18n/locales/es.json", + "src/i18n/locales/fr.json", "src/i18n/locales/ru.json", "src/i18n/locales/zh-CN.json", "src/i18n/locales/zh-Hant.json" @@ -3908,6 +3948,7 @@ "src/i18n/index.js", "src/i18n/locale.js", "src/i18n/locales/es.json", + "src/i18n/locales/fr.json", "src/i18n/locales/ru.json", "src/i18n/locales/zh-CN.json", "src/i18n/locales/zh-Hant.json", @@ -3968,6 +4009,7 @@ "src/i18n/index.js", "src/i18n/locale.js", "src/i18n/locales/es.json", + "src/i18n/locales/fr.json", "src/i18n/locales/ru.json", "src/i18n/locales/zh-CN.json", "src/i18n/locales/zh-Hant.json", @@ -4165,6 +4207,7 @@ "src/i18n/index.js", "src/i18n/locale.js", "src/i18n/locales/es.json", + "src/i18n/locales/fr.json", "src/i18n/locales/ru.json", "src/i18n/locales/zh-CN.json", "src/i18n/locales/zh-Hant.json", diff --git a/src/i18n/i18n.test.mjs b/src/i18n/i18n.test.mjs index 1b421f2ff..cf3c8e684 100644 --- a/src/i18n/i18n.test.mjs +++ b/src/i18n/i18n.test.mjs @@ -34,6 +34,9 @@ test('normalizeLocale folds regional variants and rejects unshipped tags', () => assert.equal(normalizeLocale('ru-RU'), 'ru'); assert.equal(normalizeLocale(' RU '), 'ru'); assert.equal(normalizeLocale('en_GB'), 'en'); + assert.equal(normalizeLocale('fr'), 'fr'); + assert.equal(normalizeLocale('fr-CA'), 'fr'); + assert.equal(normalizeLocale('FR_be'), 'fr'); assert.equal(normalizeLocale('xx'), null); // Explicit script tags take precedence over regional defaults. assert.equal(normalizeLocale('zh'), 'zh-CN'); diff --git a/src/i18n/index.js b/src/i18n/index.js index 6fc4becc9..4998798bb 100644 --- a/src/i18n/index.js +++ b/src/i18n/index.js @@ -17,11 +17,18 @@ import { writeStoredLocale, } from './locale.js'; import es from './locales/es.json' with { type: 'json' }; +import fr from './locales/fr.json' with { type: 'json' }; import ru from './locales/ru.json' with { type: 'json' }; import zhCN from './locales/zh-CN.json' with { type: 'json' }; import zhHant from './locales/zh-Hant.json' with { type: 'json' }; -const CATALOGS = Object.freeze({ es, ru, 'zh-CN': zhCN, 'zh-Hant': zhHant }); +const CATALOGS = Object.freeze({ + es, + fr, + ru, + 'zh-CN': zhCN, + 'zh-Hant': zhHant, +}); let currentLocale = DEFAULT_LOCALE; diff --git a/src/i18n/locale.js b/src/i18n/locale.js index 55ed71163..40c703b71 100644 --- a/src/i18n/locale.js +++ b/src/i18n/locale.js @@ -8,12 +8,20 @@ export const LOCALE_STORAGE_KEY = 'gev:locale:v1'; export const DEFAULT_LOCALE = 'en'; /** Shipped locales; order does not matter. Adding one: docs/TRANSLATORS.md. */ -export const LOCALES = Object.freeze(['en', 'es', 'ru', 'zh-CN', 'zh-Hant']); +export const LOCALES = Object.freeze([ + 'en', + 'es', + 'fr', + 'ru', + 'zh-CN', + 'zh-Hant', +]); /** Each locale named in its own language, for the selector. */ export const LOCALE_NAMES = Object.freeze({ en: 'English', es: 'Español', + fr: 'Français', ru: 'Русский', 'zh-CN': '中文(简体)', 'zh-Hant': '中文(繁體)', diff --git a/src/ui/localePicker.test.mjs b/src/ui/localePicker.test.mjs index 057642827..3e9df7180 100644 --- a/src/ui/localePicker.test.mjs +++ b/src/ui/localePicker.test.mjs @@ -40,7 +40,7 @@ test('the current language comes first, the rest by their own names', () => { nativeNames: LOCALE_NAMES, }), ), - ['ru', 'en', 'es', 'zh-CN', 'zh-Hant'], + ['ru', 'en', 'es', 'fr', 'zh-CN', 'zh-Hant'], ); assert.deepEqual( codes( @@ -50,7 +50,7 @@ test('the current language comes first, the rest by their own names', () => { nativeNames: LOCALE_NAMES, }), ), - ['es', 'en', 'ru', 'zh-CN', 'zh-Hant'], + ['es', 'en', 'fr', 'ru', 'zh-CN', 'zh-Hant'], ); assert.deepEqual( codes( @@ -60,7 +60,7 @@ test('the current language comes first, the rest by their own names', () => { nativeNames: LOCALE_NAMES, }), ), - ['en', 'es', 'ru', 'zh-CN', 'zh-Hant'], + ['en', 'es', 'fr', 'ru', 'zh-CN', 'zh-Hant'], ); const rows = buildLocaleOptions({ locales: MANY, @@ -95,6 +95,7 @@ test('each row gets the interface-language name for search, unless it only repea const byCode = Object.fromEntries(rows.map((row) => [row.code, row])); assert.equal(byCode.en.localName, 'английский'); assert.equal(byCode.es.localName, 'испанский'); + assert.equal(byCode.fr.localName, 'французский'); assert.equal(byCode.ru.localName, '', 'русский only repeats Русский'); const english = buildLocaleOptions({ locales: LOCALES, @@ -103,6 +104,7 @@ test('each row gets the interface-language name for search, unless it only repea localName: createLocalNameReader('en'), }); assert.equal(english.find((row) => row.code === 'es').localName, 'Spanish'); + assert.equal(english.find((row) => row.code === 'fr').localName, 'French'); }); test('without Intl.DisplayNames the interface-language name is simply left out', () => { From 9de9106883d87f038d41286d2acec24d966e62c0 Mon Sep 17 00:00:00 2001 From: German Khokhlov Date: Wed, 28 Oct 2026 15:03:34 +0400 Subject: [PATCH 16/83] i18n(it): shorten labels that wrapped or clipped on screen From the screenshot review: the Recent Imagery buttons (SELEZIONA, USA VISTA, VS MAPPA BASE) no longer clip or wrap, the layer state chip reads AVVIO / ARRESTO so a layer name keeps two lines, the cockpit contact header fits two lines (ARIA/MARE, SITI), and the Bhote Koshi play buttons fit on one line (AVVIA). The post-event year follows the label, as the reference one does. Co-Authored-By: Claude Opus 5.5 --- src/i18n/locales/it.json | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/src/i18n/locales/it.json b/src/i18n/locales/it.json index bf4df8736..8618f52a2 100644 --- a/src/i18n/locales/it.json +++ b/src/i18n/locales/it.json @@ -108,7 +108,7 @@ "DOWNSTREAM CONSEQUENCE": "CONSEGUENZA A VALLE", "EVIDENCE": "PROVE", "{year} HISTORICAL REFERENCE": "RIFERIMENTO STORICO {year}", - "{year} POST-EVENT": "{year} DOPO L'EVENTO", + "{year} POST-EVENT": "DOPO L'EVENTO {year}", "{count} GEOLOCATED SOURCE-MAP PLACEMENTS": { "one": "{count} POSIZIONAMENTO GEOLOCALIZZATO SULLA MAPPA DELLE FONTI", "many": "{count} DI POSIZIONAMENTI GEOLOCALIZZATI SULLA MAPPA DELLE FONTI", @@ -121,7 +121,7 @@ "{publisher} / OPEN": "{publisher} / APRI", "Bhote Koshi flood reconstruction controls": "Controlli della ricostruzione dell'alluvione del Bhote Koshi", "EVENT RECONSTRUCTION · 26 AUG 2026": "RICOSTRUZIONE DELL'EVENTO · 26 AGO 2026", - "BHOTE KOSHI OUTBURST FLOOD": "ALLUVIONE DA SVUOTAMENTO DEL BHOTE KOSHI", + "BHOTE KOSHI OUTBURST FLOOD": "PIENA IMPROVVISA DEL BHOTE KOSHI", "Close event layer": "Chiudi il livello evento", "OBSERVED IMAGERY": "IMMAGINI OSSERVATE", "SCHEMATIC CORRIDOR": "CORRIDOIO SCHEMATICO", @@ -134,9 +134,9 @@ "CAUSE": "CAUSA", "CAPTURE TIME UNVERIFIED": "ORA DI ACQUISIZIONE NON VERIFICATA", "Next story beat": "Tappa successiva del racconto", - "▶ PLAY": "▶ RIPRODUCI", + "▶ PLAY": "▶ AVVIA", "Play the next shot and continue through this scene": "Riproduci lo scatto successivo e prosegui con questa scena", - "▶ PLAY SCENE": "▶ RIPRODUCI SCENA", + "▶ PLAY SCENE": "▶ AVVIA SCENA", "◉ CINEMATIC": "◉ CINEMATICA", "↺ FULL STORY": "↺ STORIA COMPLETA", "↗ OPEN ORIGINAL": "↗ APRI L'ORIGINALE", @@ -152,12 +152,12 @@ "■ RELEASE CAMERA": "■ RILASCIA LA CAMERA", "Seek Nepal scene clock": "Scorri l'orologio della scena in Nepal", "NEPAL SCENE CLOCK": "OROLOGIO SCENA NEPAL", - "… PLAYING SHOT": "… SCATTO IN RIPRODUZIONE", - "▶ PLAY SHOT": "▶ RIPRODUCI SCATTO", + "… PLAYING SHOT": "… SCATTO IN CORSO", + "▶ PLAY SHOT": "▶ AVVIA SCATTO", "Ⅱ PAUSE": "Ⅱ PAUSA", "↺ REPLAY CINEMATIC": "↺ RIVEDI CINEMATICA", "↺ REPLAY": "↺ RIVEDI", - "… PLAYING SCENE": "… SCENA IN RIPRODUZIONE", + "… PLAYING SCENE": "… SCENA IN CORSO", "Continue {scene} from next shot": "Continua {scene} dallo scatto successivo", "current scene": "scena attuale", "Replay the full reconstruction": "Rivedi l'intera ricostruzione", @@ -1655,8 +1655,8 @@ "CLOUD UNKNOWN": "NUVOLE SCONOSCIUTE", "{source} · LOCATION QUERY": "{source} · QUERY PER POSIZIONE", "REGIONAL NEWS": "NOTIZIE REGIONALI", - "{label} · {radius} AIR/SEA WINDOW": "{label} · FINESTRA ARIA/MARE {radius}", - "{scope} · INSTALLATIONS {coverage}": "{scope} · INSTALLAZIONI {coverage}", + "{label} · {radius} AIR/SEA WINDOW": "{label} · ARIA/MARE {radius}", + "{scope} · INSTALLATIONS {coverage}": "{scope} · SITI {coverage}", "CONTEXT STANDBY": "CONTESTO IN ATTESA", "ENABLE GLOBAL CONTEXT FOR PROXIMITY PINGS": "ATTIVA IL CONTESTO GLOBALE PER I PING DI PROSSIMITÀ", "CONTACT LOST · LAST KNOWN READOUT · NOT AN ALL-CLEAR": "CONTATTO PERSO · ULTIMA LETTURA NOTA · NON È UN VIA LIBERA", @@ -1794,7 +1794,7 @@ "{requirement}, or {offer}": "{requirement}, oppure {offer}", "Live Flights": "Voli live", "Military Flights": "Voli militari", - "Earthquakes (24h)": "Terremoti (24h)", + "Earthquakes (24h)": "Terremoti (24 h)", "Satellites": "Satelliti", "Space Missions (30d)": "Missioni spaziali (30 g)", "Street Traffic": "Traffico stradale", @@ -1834,8 +1834,8 @@ "NASA FIRMS · LIVE": "NASA FIRMS · LIVE", "OSM routing": "Percorsi OSM", "data source|Local": "Dati locali", - "ENABLING": "ATTIVAZIONE", - "DISABLING": "DISATTIVAZIONE", + "ENABLING": "AVVIO", + "DISABLING": "ARRESTO", "Movement": "Movimento", "Infrastructure": "Infrastrutture", "Events": "Eventi", @@ -2020,7 +2020,7 @@ "{owner} is using the pointer — close it first": "{owner} sta usando il puntatore: chiudilo prima", "Box is {size} wide · limit {limit}": "Il riquadro è largo {size} · limite {limit}", "View is {size} wide · limit {limit}": "La vista è larga {size} · limite {limit}", - "VS BASEMAP": "VS MAPPA DI BASE", + "VS BASEMAP": "VS MAPPA BASE", "A / B": "A / B", "Newest low-cloud day for this box · scene cloud, not box cloud": "Giorno più recente con poche nuvole per questo riquadro · nuvole della scena, non del riquadro", "Newest day covering this box · cloudier than 20%": "Giorno più recente che copre questo riquadro · nuvole oltre il 20%", @@ -2062,9 +2062,9 @@ "Imagery opacity": "Opacità delle immagini", "SWAP": "SCAMBIA", "Trade the two sides of the divider": "Inverti i due lati del divisore", - "SELECT BOX": "SELEZIONA RIQUADRO", + "SELECT BOX": "SELEZIONA", "Drag a box on the map (Esc cancels)": "Trascina un riquadro sulla mappa (Esc annulla)", - "USE VIEW": "USA LA VISTA", + "USE VIEW": "USA VISTA", "Use the current view as the box": "Usa la vista attuale come riquadro", "Forget the box and its images": "Dimentica il riquadro e le sue immagini", "START HERE": "INIZIA DA QUI", From d95bffb5fd16082207ee5a055292893b4e42f14e Mon Sep 17 00:00:00 2001 From: German Khokhlov Date: Wed, 28 Oct 2026 15:09:45 +0400 Subject: [PATCH 17/83] i18n(fr): fit French labels found in the screenshot review MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Shorter wording where the French text ran out of its button, chip or collapsed card at 1600×1100: the DATA LAYERS launcher (COUCHES), Recent Imagery buttons and hints (CETTE VUE, VS CARTE, EXP. A), the ENABLING / DISABLING layer chip, the voice detail line and the location search placeholder. Also the CCTV range readout gets a space before m, the radio privacy note reads naturally, and the cockpit air/sea window is shorter. Co-Authored-By: Claude Opus 5.5 --- docs/translations/fr.md | 4 ++-- src/i18n/locales/fr.json | 34 +++++++++++++++++----------------- 2 files changed, 19 insertions(+), 19 deletions(-) diff --git a/docs/translations/fr.md b/docs/translations/fr.md index 80960e48d..948479e6a 100644 --- a/docs/translations/fr.md +++ b/docs/translations/fr.md @@ -34,7 +34,7 @@ The `many` form is the `other` text with « de » (« d' » before a vowel) afte | English | Français | | ---------------------------------------------- | --------------------------------------------------------------- | -| layer / data layer | couche / couche de données | +| layer / data layer / DATA LAYERS (panel title) | couche / couche de données / COUCHES | | feed / source / data source | flux / source / source de données | | LIVE (status) / live data | DIRECT / données en direct | | SIMULATED | SIMULÉ | @@ -62,7 +62,7 @@ The `many` form is the `other` text with « de » (« d' » before a vowel) afte | forecast / lead hours / valid / issued | prévision / échéances / valide / émise | | AQHI (Canada) | CQAS (cote air santé) | | radio station / tune | station / régler | -| bikeshare / transit | vélos en libre-service / transports en commun | +| bikeshare / transit | vélos partagés / transports en commun | | route (directions) / turn (maneuver) | itinéraire / manœuvre | | scene / shot / scene recipe | scène / plan / recette de scène | | bundle / data pack / anchor | archive / paquet de données / ancre | diff --git a/src/i18n/locales/fr.json b/src/i18n/locales/fr.json index 98c618a22..1ae43fb08 100644 --- a/src/i18n/locales/fr.json +++ b/src/i18n/locales/fr.json @@ -1611,7 +1611,7 @@ "CAL · {badge}": "CAL · {badge}", "MONITOR": "MONITEUR", "OFF": "OFF", - "{city} · HDG {heading} · FOV {fov} · RANGE {range}m · {projection}{calBadge} · {provider}{status}": "{city} · HDG {heading} · FOV {fov} · PORTÉE {range}m · {projection}{calBadge} · {provider}{status}", + "{city} · HDG {heading} · FOV {fov} · RANGE {range}m · {projection}{calBadge} · {provider}{status}": "{city} · HDG {heading} · FOV {fov} · PORTÉE {range} m · {projection}{calBadge} · {provider}{status}", "{count} cameras loaded · click a camera to activate": { "one": "{count} caméra chargée · cliquer sur une caméra pour l'activer", "many": "{count} de caméras chargées · cliquer sur une caméra pour l'activer", @@ -1655,7 +1655,7 @@ "CLOUD UNKNOWN": "NUAGES INCONNUS", "{source} · LOCATION QUERY": "{source} · REQUÊTE DE LIEU", "REGIONAL NEWS": "ACTUS RÉGIONALES", - "{label} · {radius} AIR/SEA WINDOW": "{label} · FENÊTRE AIR/MER {radius}", + "{label} · {radius} AIR/SEA WINDOW": "{label} · AIR/MER {radius}", "{scope} · INSTALLATIONS {coverage}": "{scope} · INSTALLATIONS : {coverage}", "CONTEXT STANDBY": "CONTEXTE EN VEILLE", "ENABLE GLOBAL CONTEXT FOR PROXIMITY PINGS": "ACTIVER LE CONTEXTE GLOBAL POUR LES PINGS DE PROXIMITÉ", @@ -1800,7 +1800,7 @@ "Street Traffic": "Trafic routier", "CCTV": "CCTV", "Radio": "Radio", - "Bikeshare": "Vélos en libre-service", + "Bikeshare": "Vélos partagés", "Live AIS Vessels": "Navires AIS en direct", "Mapped Installations": "Installations cartographiées", "Global Context": "Contexte global", @@ -1819,7 +1819,7 @@ "Cyclone advisories": "Bulletins cycloniques", "ALPR Cameras": "Caméras LAPI", "Live Vessels": "Navires en direct", - "Bike Share": "Vélos en libre-service", + "Bike Share": "Vélos partagés", "Cameras": "Caméras", "Street Level": "Niveau rue", "Mapped ALPR Cameras": "Caméras LAPI cartographiées", @@ -1834,8 +1834,8 @@ "NASA FIRMS · LIVE": "NASA FIRMS · DIRECT", "OSM routing": "Itinéraires OSM", "data source|Local": "Données locales", - "ENABLING": "ACTIVATION", - "DISABLING": "DÉSACTIVATION", + "ENABLING": "ACTIV.", + "DISABLING": "DÉSACT.", "Movement": "Mouvement", "Infrastructure": "Infrastructures", "Events": "Événements", @@ -1972,7 +1972,7 @@ "NO STATION SELECTED": "AUCUNE STATION SÉLECTIONNÉE", "Directory metadata only": "Métadonnées de l'annuaire seulement", "Loading station directory…": "Chargement de l'annuaire des stations…", - "Choose a globe marker or use next.": "Choisissez un marqueur du globe ou utilisez suivant.", + "Choose a globe marker or use next.": "Choisissez un marqueur sur le globe ou utilisez SUIV.", "TAGS · {tags}": "TAGS · {tags}", "Play": "Lire", "PAUSE": "PAUSE", @@ -2013,14 +2013,14 @@ "Latest": "Dernière", "Newest frame per product": "Image la plus récente par produit", "Replay observed history": "Rejouer l'historique observé", - "Imagery on Esri · Google 3D returns when cleared": "Imagerie sur Esri · Google 3D revient après EFFACER", + "Imagery on Esri · Google 3D returns when cleared": "Sur Esri · EFFACER rétablit Google 3D", "Point the camera at the ground to use the view": "Orientez la caméra vers le sol pour utiliser la vue", "That point cannot anchor a box": "Ce point ne peut pas ancrer une zone", "Imagery stops at ±{limit}° latitude": "L'imagerie s'arrête à ±{limit}° de latitude", "{owner} is using the pointer — close it first": "Pointeur utilisé par : {owner}. Fermez-le d'abord", "Box is {size} wide · limit {limit}": "La zone fait {size} de large · limite {limit}", "View is {size} wide · limit {limit}": "La vue fait {size} de large · limite {limit}", - "VS BASEMAP": "VS FOND DE CARTE", + "VS BASEMAP": "VS CARTE", "A / B": "A / B", "Newest low-cloud day for this box · scene cloud, not box cloud": "Jour le plus récent peu nuageux pour cette zone · nuages de la scène, pas de la zone", "Newest day covering this box · cloudier than 20%": "Jour le plus récent couvrant cette zone · plus de 20 % de nuages", @@ -2049,7 +2049,7 @@ "Select a box or use the view": "Sélectionnez une zone ou utilisez la vue", "Searching the last 30 days": "Recherche sur les 30 derniers jours", "No days to show for this box": "Aucun jour à afficher pour cette zone", - "Drag the divider · SWAP trades sides": "Faites glisser le séparateur · INVERSER échange les côtés", + "Drag the divider · SWAP trades sides": "Glissez le séparateur · INVERSER permute", "← → preview · A or B pins the focused day": "← → aperçu · A ou B épingle le jour ciblé", "← → preview the other side · A or B pins it": "← → aperçu de l'autre côté · A ou B l'épingle", "S on another day replaces it · × unpins": "S sur un autre jour le remplace · × le désépingle", @@ -2064,7 +2064,7 @@ "Trade the two sides of the divider": "Échanger les deux côtés du séparateur", "SELECT BOX": "TRACER ZONE", "Drag a box on the map (Esc cancels)": "Tracez une zone sur la carte (Esc pour annuler)", - "USE VIEW": "UTILISER LA VUE", + "USE VIEW": "CETTE VUE", "Use the current view as the box": "Utiliser la vue actuelle comme zone", "Forget the box and its images": "Oublier la zone et ses images", "START HERE": "COMMENCER ICI", @@ -2088,7 +2088,7 @@ "Source off": "Source désactivée", "Unpin {slot}": "Désépingler {slot}", "Unpin the image": "Désépingler l'image", - "EXPORT {slot}": "EXPORT. {slot}", + "EXPORT {slot}": "EXP. {slot}", "EXPORT": "EXPORTER", "Download {slot} as a PNG": "Télécharger {slot} en PNG", "Download the image as a PNG": "Télécharger l'image en PNG", @@ -2377,7 +2377,7 @@ "Requesting microphone": "Demande du microphone", "Gemini could not submit this input. Start voice again.": "Gemini n'a pas pu envoyer cette saisie. Relancez la voix.", "Connecting to Gemini": "Connexion à Gemini", - "Ask or command": "Posez une question ou donnez un ordre", + "Ask or command": "Question ou ordre", "Gemini returned an oversized message": "Gemini a renvoyé un message trop volumineux", "Gemini Live connection failed. Check network access, then start voice again.": "Échec de la connexion à Gemini Live. Vérifiez l'accès au réseau, puis relancez la voix.", "Gemini Live connection ended. Start voice again for a new conversation.": "La connexion à Gemini Live est terminée. Relancez la voix pour une nouvelle conversation.", @@ -2788,7 +2788,7 @@ "Keep location tray open": "Garder le tiroir des lieux ouvert", "Search any location": "Rechercher n'importe quel lieu", "Search location by name or coordinates": "Rechercher un lieu par nom ou coordonnées", - "Search any location...": "Rechercher n'importe quel lieu…", + "Search any location...": "Rechercher un lieu…", "WEATHER": "MÉTÉO", "Active weather products": "Produits météo actifs", "RECENT IMAGERY": "IMAGERIE RÉCENTE", @@ -2820,7 +2820,7 @@ "STATION TAG": "TAG DE STATION", "Filter stations by station tag": "Filtrer les stations par tag de station", "All": "Tous", - "Enable Radio, then choose a globe marker or use next.": "Activez la Radio, puis choisissez un marqueur du globe ou utilisez suivant.", + "Enable Radio, then choose a globe marker or use next.": "Activez la Radio, puis choisissez un marqueur sur le globe ou utilisez SUIV.", "DRAG TO TUNE": "GLISSER POUR SYNTONISER", "Tune available internet radio stations": "Écouter les stations de radio Internet disponibles", "ALL · DRAG THE NEEDLE": "TOUTES · GLISSEZ L'AIGUILLE", @@ -2834,7 +2834,7 @@ "Radio volume": "Volume de la radio", "STATION SITE": "SITE DE LA STATION", "DIRECTORY: RADIO BROWSER": "ANNUAIRE : RADIO BROWSER", - "Audio connects directly to the broadcaster after you press play. Your IP is visible to that broadcaster.": "Le flux audio se connecte directement au diffuseur après avoir appuyé sur lecture. Votre IP est visible par ce diffuseur.", + "Audio connects directly to the broadcaster after you press play. Your IP is visible to that broadcaster.": "Le flux audio se connecte directement au diffuseur dès que vous lancez la lecture. Votre IP est visible par ce diffuseur.", "Local RTL-SDR receiver": "Récepteur RTL-SDR local", "LOCAL RTL-SDR": "RTL-SDR LOCAL", "Chrome/Edge · WebUSB · one local tuner shared by FM and the Local ADS-B layer.": "Chrome/Edge · WebUSB · un seul tuner local partagé entre la FM et la couche ADS-B local.", @@ -2929,7 +2929,7 @@ "EXIT CLEAN VIEW": "QUITTER LA VUE ÉPURÉE", "Return UI controls": "Rétablir les commandes de l'interface", "Initializing photorealistic world...": "Initialisation du monde photoréaliste…", - "DATA LAYERS": "COUCHES DE DONNÉES", + "DATA LAYERS": "COUCHES", "ACQUIRING FRAME": "ACQUISITION DE L'IMAGE", "NEAREST": "PROCHE", "CCTV camera": "Caméra CCTV", From 56a36df006780a4b0ee551f25bfd463b3129b506 Mon Sep 17 00:00:00 2001 From: German Khokhlov Date: Wed, 28 Oct 2026 15:10:32 +0400 Subject: [PATCH 18/83] i18n(pt): fit cockpit labels found in the screenshot review MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - The cockpit news kicker no longer cuts off: regional news reads «notícias locais», the cycle button «CICLO DESLIG.», the subtitle «ÚLTIMAS NOTÍCIAS DO LOCAL». - Contact header fits in two lines («AR/MAR 250 KM · INSTALAÇÕES: ATÉ 100 KM»); ground speed reads KT like the rest of the HUD. - A space between a number and s/h/d («nova tentativa em 30 s», «há 5 h»), and «aproxime-se de uma rua» for zoom-to-street hints. Co-Authored-By: Claude Opus 5.5 --- src/i18n/locales/pt.json | 40 ++++++++++++++++++++-------------------- 1 file changed, 20 insertions(+), 20 deletions(-) diff --git a/src/i18n/locales/pt.json b/src/i18n/locales/pt.json index c64e4b4bd..5f260e65b 100644 --- a/src/i18n/locales/pt.json +++ b/src/i18n/locales/pt.json @@ -244,7 +244,7 @@ "Overpass temporarily unavailable": "Overpass temporariamente indisponível", "Retrying mapped sites…": "Tentando de novo os locais mapeados…", "Fetching mapped sites…": "Buscando locais mapeados…", - "{reason} — retrying in {seconds}s": "{reason} — nova tentativa em {seconds}s", + "{reason} — retrying in {seconds}s": "{reason} — nova tentativa em {seconds} s", "{reason} — retry pending": "{reason} — nova tentativa pendente", "Zoom in to search mapped installations": "Aproxime o zoom para buscar instalações mapeadas", "Showing cached mapped sites": "Mostrando locais mapeados em cache", @@ -510,7 +510,7 @@ "BRG —": "BRG —", "CRS {value}°": "CRS {value}°", "CURRENT VIEWPORT ONLY": "SÓ A VISTA ATUAL", - "WITHIN {km} KM": "EM ATÉ {km} KM", + "WITHIN {km} KM": "ATÉ {km} KM", "Flights": "Voos", "Military flights": "Voos militares", "AIS vessels": "Embarcações AIS", @@ -724,7 +724,7 @@ "just now": "agora mesmo", "<1m ago": "há <1 min", "{count}m ago": "há {count} min", - "{count}h ago": "há {count}h", + "{count}h ago": "há {count} h", "fire confidence|high": "alta", "fire confidence|nominal": "nominal", "fire confidence|low": "baixa", @@ -1032,7 +1032,7 @@ "DOCKED · {name} · +{extra}": "ACOPLADO · {name} · +{extra}", "DOCKED · {name}": "ACOPLADO · {name}", "{name} needs the Google 3D map: choose it under MAP SOURCE": "{name} requer o mapa Google 3D: escolha-o em FONTE DO MAPA", - "zoom in to a street to open {name}": "aproxime o zoom de uma rua para abrir {name}", + "zoom in to a street to open {name}": "aproxime-se de uma rua para abrir {name}", "loading coverage...": "carregando cobertura...", "No street-level imagery within {radius} m of that point": "Nenhuma imagem no nível da rua a até {radius} m desse ponto", "No street-level imagery within {radius} m of the view centre": "Nenhuma imagem no nível da rua a até {radius} m do centro da vista", @@ -1641,11 +1641,11 @@ "THUNDERSTORM": "TROVOADA", "MIXED CONDITIONS": "CONDIÇÕES MISTAS", "CYCLE ON": "CICLO LIGADO", - "CYCLE OFF": "CICLO DESLIGADO", + "CYCLE OFF": "CICLO DESLIG.", "Stop automatic page cycling. Previous, Next, and the SIG/NEWS/LOCAL tabs stay available.": "Parar a rotação automática de páginas. Anterior, Próxima e as abas SIG/NOTÍCIAS/LOCAL continuam disponíveis.", "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.": "Alterna as páginas do briefing automaticamente a cada 9 segundos (Sinais → Notícias → Local). Pausa enquanto você passa o mouse ou foca o painel. Os dados de sinais ao vivo continuam atualizando de qualquer forma.", - "ACQUIRING REGIONAL NEWS": "OBTENDO NOTÍCIAS REGIONAIS", - "REGIONAL NEWS UNAVAILABLE": "NOTÍCIAS REGIONAIS INDISPONÍVEIS", + "ACQUIRING REGIONAL NEWS": "OBTENDO NOTÍCIAS LOCAIS", + "REGIONAL NEWS UNAVAILABLE": "NOTÍCIAS LOCAIS INDISPONÍVEIS", "RESOLVING REGION": "IDENTIFICANDO REGIÃO", "REGION UNAVAILABLE": "REGIÃO INDISPONÍVEL", "NO RECENT LOCATION MATCHES": "NENHUMA CORRESPONDÊNCIA RECENTE COM O LOCAL", @@ -1654,8 +1654,8 @@ "CLOUD {pct}%": "NUVENS {pct}%", "CLOUD UNKNOWN": "NUVENS DESCONHECIDAS", "{source} · LOCATION QUERY": "{source} · CONSULTA POR LOCAL", - "REGIONAL NEWS": "NOTÍCIAS REGIONAIS", - "{label} · {radius} AIR/SEA WINDOW": "{label} · JANELA AR/MAR {radius}", + "REGIONAL NEWS": "NOTÍCIAS LOCAIS", + "{label} · {radius} AIR/SEA WINDOW": "{label} · AR/MAR {radius}", "{scope} · INSTALLATIONS {coverage}": "{scope} · INSTALAÇÕES: {coverage}", "CONTEXT STANDBY": "CONTEXTO EM ESPERA", "ENABLE GLOBAL CONTEXT FOR PROXIMITY PINGS": "ATIVE O CONTEXTO GLOBAL PARA PINGS DE PROXIMIDADE", @@ -1710,14 +1710,14 @@ "Expand briefing panel": "Expandir painel de briefing", "OBSERVED / MAPPED PINGS": "PINGS OBSERVADOS / MAPEADOS", "SOURCE-BACKED EVENTS · NO SYNTHETIC NEWS": "EVENTOS COM FONTE · SEM NOTÍCIAS SINTÉTICAS", - "LATEST LOCATION-MATCHED REPORTING": "ÚLTIMAS REPORTAGENS DA LOCALIZAÇÃO", + "LATEST LOCATION-MATCHED REPORTING": "ÚLTIMAS NOTÍCIAS DO LOCAL", "{source} · LOCATION QUERY · RECENT": "{source} · CONSULTA POR LOCAL · RECENTE", "LOCAL INFO": "INFO LOCAL", "PLACE / CONDITIONS / POSITION": "LUGAR / CONDIÇÕES / POSIÇÃO", "TIME UNKNOWN": "HORA DESCONHECIDA", "{count}M AGO": "HÁ {count} MIN", - "{count}H AGO": "HÁ {count}H", - "{count}D AGO": "HÁ {count}D", + "{count}H AGO": "HÁ {count} H", + "{count}D AGO": "HÁ {count} D", "DIR UNKNOWN": "DIR DESCONHECIDA", "Select flight {title}": "Selecionar voo {title}", "{aircraftClass} · CURRENT": "{aircraftClass} · ATUAL", @@ -1844,21 +1844,21 @@ "Other layers": "Outras camadas", "{state} · {source}": "{state} · {source}", "UNCERTAIN · {source} · lifecycle state requires reconciliation": "INCERTO · {source} · estado do ciclo de vida requer reconciliação", - "{state} · {source} · {detail} · retry {seconds}s": "{state} · {source} · {detail} · nova tentativa em {seconds}s", + "{state} · {source} · {detail} · retry {seconds}s": "{state} · {source} · {detail} · nova tentativa em {seconds} s", "{state} · {source} · {detail}": "{state} · {source} · {detail}", "never": "nunca", "{source} · {loadingLabel}": "{source} · {loadingLabel}", "{accepted} of {raw} records accepted": "{accepted} de {raw} registros aceitos", "incomplete snapshot": "snapshot incompleto", "{state} · {source} · {detail} · {ago}": "{state} · {source} · {detail} · {ago}", - "{state} · {source} · {ago} · retrying in {seconds}s": "{state} · {source} · {ago} · nova tentativa em {seconds}s", + "{state} · {source} · {ago} · retrying in {seconds}s": "{state} · {source} · {ago} · nova tentativa em {seconds} s", "{state} · {source} · {ago}": "{state} · {source} · {ago}", "{source} · {ago}": "{source} · {ago}", "UNCERTAIN": "INCERTO", "status chip|UNAVAILABLE": "INDISP.", "Data source unavailable": "Fonte de dados indisponível", "{name}: {state}": "{name}: {state}", - "{count}s ago": "há {count}s", + "{count}s ago": "há {count} s", "Local FM stopped: internet radio started": "FM local parada: a rádio pela internet começou", "IDLE": "EM ESPERA", "CONNECTING": "CONECTANDO", @@ -2174,7 +2174,7 @@ "REFRESHING LIVE DATA": "ATUALIZANDO DADOS AO VIVO", "syncing road network": "sincronizando malha viária", "retry pending": "nova tentativa pendente", - "retrying in {seconds}s": "nova tentativa em {seconds}s", + "retrying in {seconds}s": "nova tentativa em {seconds} s", "ALPR cameras": "câmeras ALPR", "OpenSky OAuth client missing/invalid": "Cliente OAuth do OpenSky ausente ou inválido", "OpenSky OAuth rejected credentials": "O OAuth do OpenSky recusou as credenciais", @@ -2259,7 +2259,7 @@ " or ": " ou ", "OPEN {labels}": "ABRIR {labels}", "Open {names} at the centre of the view": "Abrir {names} no centro da vista", - "Zoom in to a street to open {names} here": "Aproxime o zoom de uma rua para abrir {names} aqui", + "Zoom in to a street to open {names} here": "Aproxime-se de uma rua para abrir {names} aqui", "Switch Street Level on to draw its coverage.": "Ative Nível da rua para desenhar a cobertura.", "Every provider is switched off: light a chip to draw its coverage.": "Todos os provedores estão desligados: ative um para desenhar a cobertura dele.", "Loading this sequence…": "Carregando esta sequência…", @@ -2698,7 +2698,7 @@ "DEST ---°": "DEST ---°", "OPTICAL PLANE · 01": "PLANO ÓPTICO · 01", "VISOR LOCK · ACTIVE": "TRAVA DO VISOR · ATIVA", - "GROUND SPEED · KTS": "VELOC. SOLO · KTS", + "GROUND SPEED · KTS": "VELOC. SOLO · KT", "ALTITUDE · FT": "ALTITUDE · FT", "FIRST PERSON": "PRIMEIRA PESSOA", "LIVE TRACK · COURSE ALIGNED": "RASTRO AO VIVO · CURSO ALINHADO", @@ -2736,7 +2736,7 @@ "Previous briefing page": "Página anterior do briefing", "Next briefing page": "Próxima página do briefing", "Live signals": "Sinais ao vivo", - "Latest regional news": "Últimas notícias regionais", + "Latest regional news": "Últimas notícias locais", "Location-based information": "Informações baseadas na localização", "TEMP": "TEMP", "WIND": "VENTO", @@ -2748,7 +2748,7 @@ "SIG": "SIG", "Show Live Signals": "Mostrar sinais ao vivo", "NEWS": "NOTÍCIAS", - "Show Regional News": "Mostrar notícias regionais", + "Show Regional News": "Mostrar notícias locais", "LOCAL": "LOCAL", "Show Local Info": "Mostrar informações locais", "Cockpit display and Radio controls": "Controles de exibição e rádio da cabine", From e3054477134cee3d4cc133f68ea9f114e8980346 Mon Sep 17 00:00:00 2001 From: German Khokhlov Date: Wed, 28 Oct 2026 15:13:52 +0400 Subject: [PATCH 19/83] style(ja): CJK label rules for Japanese MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit cjk.css now covers Japanese as well as Chinese: tight tracking, the 9px floor on dock voice labels and layer buttons, whole travel-mode and preset labels, catalog-case units in the HUD and the taller Recent Imagery cards. Japanese also gets strict line breaking (no line starts with ー or a small kana) and unbroken segment labels (すべて, 平面). Chinese rendering is unchanged: :is(:lang(zh), :lang(ja)) keeps the :lang(zh) specificity. Co-Authored-By: Claude Opus 5.5 --- src/ui/styles/cjk.css | 45 ++++++++++++++++++++++++++++--------------- 1 file changed, 29 insertions(+), 16 deletions(-) diff --git a/src/ui/styles/cjk.css b/src/ui/styles/cjk.css index 3c01d3987..d9cb9246d 100644 --- a/src/ui/styles/cjk.css +++ b/src/ui/styles/cjk.css @@ -1,6 +1,7 @@ -/* Tight tracking keeps Chinese labels readable; preserve Latin tracking for - intel HUD readouts and content marked translate="no", including its containers. */ -html:lang(zh) +/* Chinese and Japanese text. Tight tracking keeps CJK labels readable; + preserve Latin tracking for intel HUD readouts and content marked + translate="no", including its containers. */ +html:is(:lang(zh), :lang(ja)) body :not( #intel-hud, @@ -12,40 +13,52 @@ html:lang(zh) letter-spacing: 0.02em !important; } -/* Keep small Chinese labels legible at a minimum of 9px. */ -html:lang(zh) #command-dock .gev-mic-label, -html:lang(zh) #command-dock #gev-voice-detail, -html:lang(zh) .gev-voice-tier-btn, -html:lang(zh) .panel-layer-toggle { +/* Japanese line breaking: never start a line with ー, a small kana or closing + punctuation (プレビュ / ー). */ +html:lang(ja) body { + line-break: strict; +} + +/* Keep small CJK labels legible at a minimum of 9px. */ +html:is(:lang(zh), :lang(ja)) #command-dock .gev-mic-label, +html:is(:lang(zh), :lang(ja)) #command-dock #gev-voice-detail, +html:is(:lang(zh), :lang(ja)) .gev-voice-tier-btn, +html:is(:lang(zh), :lang(ja)) .panel-layer-toggle { font-size: 9px; } /* A two-glyph button label must not break between its glyphs. */ -html:lang(zh) .pp-mode-btn { +html:is(:lang(zh), :lang(ja)) .pp-mode-btn { + white-space: nowrap; +} + +/* Japanese segment labels are short words (すべて, 平面): keep each whole. */ +html:lang(ja) .gev-segment { white-space: nowrap; } /* Keep unit symbols in their catalog case, including the cockpit readouts. */ -html:lang(zh) #intel-hud *, -html:lang(zh) #cockpit-hud * { +html:is(:lang(zh), :lang(ja)) #intel-hud *, +html:is(:lang(zh), :lang(ja)) #cockpit-hud * { text-transform: none; } -/* Move short travel modes (步行 / 骑行) to the next line as whole words. */ -html:lang(zh) [data-layer-id='directions'] .data-toggle-meta { +/* Move short travel modes (步行 / 骑行, 徒歩 / 自転車) to the next line as + whole words. */ +html:is(:lang(zh), :lang(ja)) [data-layer-id='directions'] .data-toggle-meta { word-break: keep-all; overflow-wrap: break-word; } /* Leave room for the complete sensor name and resolution on two lines. */ -html:lang(zh) .recent-imagery-readout .ri-strip { +html:is(:lang(zh), :lang(ja)) .recent-imagery-readout .ri-strip { height: 131px; } -html:lang(zh) .recent-imagery-readout .ri-card { +html:is(:lang(zh), :lang(ja)) .recent-imagery-readout .ri-card { height: 123px; grid-template-rows: 42px 13px 22px 11px 18px; } -html:lang(zh) .recent-imagery-readout .ri-card-sensor { +html:is(:lang(zh), :lang(ja)) .recent-imagery-readout .ri-card-sensor { white-space: normal; text-overflow: clip; } From d6ecaca9571a64af7ebb06b389f70f2dcd305a1d Mon Sep 17 00:00:00 2001 From: German Khokhlov Date: Wed, 28 Oct 2026 15:13:52 +0400 Subject: [PATCH 20/83] i18n(ja): fit labels found in the screenshot review MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Shorter layer and segment labels that wrapped or broke mid-word in the narrow panels: ALPRカメラ, 宇宙ミッション 30日, 地図と比較, 対象. - Window readouts put the value after the label (空/海ウィンドウ 250 km), so a unit never runs into Japanese text. - 情勢図 for the GhostMaps intel picture; Googleストリートビュー joined like any Latin product name in the guide. Co-Authored-By: Claude Opus 5.5 --- docs/translations/ja.md | 2 +- src/i18n/locales/ja.json | 16 ++++++++-------- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/docs/translations/ja.md b/docs/translations/ja.md index 74abc49b5..11ff3b541 100644 --- a/docs/translations/ja.md +++ b/docs/translations/ja.md @@ -13,7 +13,7 @@ Translation source: abiyeenzo (#913). - No space between Japanese and Latin letters, digits or a `{placeholder}`: 「AIS船舶」, 「Spaceを長押しで話す」, 「{count}件」, 「{name}を表示」. - Two exceptions keep the space: a Japanese label before its value in a readout (「雲量 {pct}%」, 「ステーション {id}」, 「高度 {altitude}」), and the state words in toggles (「CCTV オン」, 「ラジオ オフ」). - Loanwords are katakana with the long-vowel mark, as in Microsoft and Apple style: ユーザー, ブラウザー, ビューアー, プロバイダー, レイヤー, フィルター, モニター, パラメーター. Pick one katakana form per term and keep it (see the glossary). -- Product, provider and dataset names stay in Latin script: Google Maps, Cesium ion, OpenSky, CelesTrak, NASA FIRMS, Sentinel-2, KartaView. Google's own product names use Google's Japanese: Google ストリートビュー. Nepal place names in the Bhote Koshi scenes stay in Latin script, as in zh-CN; country and well-known city names are translated (ネパール, 東京, オースティン). +- Product, provider and dataset names stay in Latin script: Google Maps, Cesium ion, OpenSky, CelesTrak, NASA FIRMS, Sentinel-2, KartaView. Google's own product names use Google's Japanese, joined like any Latin word: Googleストリートビュー. Nepal place names in the Bhote Koshi scenes stay in Latin script, as in zh-CN; country and well-known city names are translated (ネパール, 東京, オースティン). ## Numbers, units and dates diff --git a/src/i18n/locales/ja.json b/src/i18n/locales/ja.json index 0aca1e20d..19069f601 100644 --- a/src/i18n/locales/ja.json +++ b/src/i18n/locales/ja.json @@ -469,7 +469,7 @@ "None on screen — nearby cameras are outside the view": "画面内になし:周辺のカメラは表示範囲外です", "ALPR camera": "ALPRカメラ", "Camera coverage unavailable": "カメラのカバー範囲を取得できません", - "OpenStreetMap · community mapped": "OpenStreetMap · コミュニティによるマッピング", + "OpenStreetMap · community mapped": "OpenStreetMap · コミュニティ作成", "Overpass returned an incomplete camera response": "Overpassから不完全なカメラデータが返されました", "At least {count}": "{count}以上", "CONTEXT READY": "コンテキスト準備完了", @@ -485,7 +485,7 @@ "Next — nearest unvisited contact in the 250 km window": "次へ:250 km圏内で最も近い未訪問のコンタクト", "NEXT": "次へ", "Named areas ({n})": "名前付きエリア({n})", - "{distance} FLIGHT / VESSEL WINDOW": "{distance}フライト / 船舶ウィンドウ", + "{distance} FLIGHT / VESSEL WINDOW": "フライト / 船舶ウィンドウ {distance}", "Open-source mapped/observed context. Missing broadcasts, unloaded map areas, or unmapped sites are not evidence of absence.": "オープンソースのマップ済み/観測済みコンテキストです。放送の欠落、未読込のマップ領域、未マップの施設は、不在の証拠ではありません。", "mapped matches within {km} km of the subject": "対象から{km} km以内のマップ済み一致", "none mapped within {km} km; not a complete 250 km survey": "{km} km以内にマップ済みのものなし(250 kmの完全な調査ではありません)", @@ -722,7 +722,7 @@ "LIVE · updated {age}": "ライブ · 更新 {age}", "Source snapshot time unavailable": "ソースのスナップショット時刻を取得できません", "Live data unavailable": "ライブデータを利用できません", - "Intel Picture": "インテルピクチャー", + "Intel Picture": "情勢図", "Kinetic 30d": "30日間の軍事行動", "Border Crisis": "国境危機", "Iran Picture": "イラン情勢図", @@ -1611,7 +1611,7 @@ "CLOUD UNKNOWN": "雲量不明", "{source} · LOCATION QUERY": "{source} · 位置クエリ", "REGIONAL NEWS": "地域ニュース", - "{label} · {radius} AIR/SEA WINDOW": "{label} · {radius}空/海ウィンドウ", + "{label} · {radius} AIR/SEA WINDOW": "{label} · 空/海ウィンドウ {radius}", "{scope} · INSTALLATIONS {coverage}": "{scope} · 施設 {coverage}", "CONTEXT STANDBY": "コンテキスト待機", "ENABLE GLOBAL CONTEXT FOR PROXIMITY PINGS": "グローバルコンテキストを有効にすると近接ピングを表示", @@ -1738,7 +1738,7 @@ "Military Flights": "軍用機", "Earthquakes (24h)": "地震(24時間)", "Satellites": "衛星", - "Space Missions (30d)": "宇宙ミッション(30日)", + "Space Missions (30d)": "宇宙ミッション 30日", "Street Traffic": "道路交通", "CCTV": "CCTV", "Radio": "ラジオ", @@ -1764,7 +1764,7 @@ "Bike Share": "シェアサイクル", "Cameras": "カメラ", "Street Level": "ストリートレベル", - "Mapped ALPR Cameras": "マップ済みALPRカメラ", + "Mapped ALPR Cameras": "ALPRカメラ", "Data Centers": "データセンター", "Active Fires": "火災検知", "Military aircraft": "軍用機", @@ -1956,7 +1956,7 @@ "{owner} is using the pointer — close it first": "{owner}がポインターを使用中です。先に閉じてください", "Box is {size} wide · limit {limit}": "範囲の幅 {size} · 上限 {limit}", "View is {size} wide · limit {limit}": "表示の幅 {size} · 上限 {limit}", - "VS BASEMAP": "ベースマップと比較", + "VS BASEMAP": "地図と比較", "A / B": "A / B", "Newest low-cloud day for this box · scene cloud, not box cloud": "この範囲で雲の少ない最新の日 · シーン全体の雲量で、範囲内の雲量ではありません", "Newest day covering this box · cloudier than 20%": "この範囲をカバーする最新の日 · 雲量20%超", @@ -2244,7 +2244,7 @@ "Voice assistant": "音声アシスタント", "Dismiss voice card": "音声カードを閉じる", "YOU": "あなた", - "THIS": "指示対象", + "THIS": "対象", "Plan": "計画", "Referenced items": "参照された項目", "NOTES & SOURCES": "注記と出典", From 0d28150e2221960d2e61882226234dc1bb3c9a2a Mon Sep 17 00:00:00 2001 From: German Khokhlov Date: Wed, 28 Oct 2026 15:18:49 +0400 Subject: [PATCH 21/83] i18n(de): fixes from the screenshot review MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Labels that ran out of their buttons: EXPORT / EXPORT A stay English (EXPORTIEREN was cut to EXPORTI…), the imagery mode reads VGL. KARTE, the scene run log PROTOKOLL (it broke as LAUFPROTOKOL/L), the dock voice status SPRACHE N. V., and the Esri imagery note fits its line. - The cyclone layer is Sturmwarnungen (no hyphenated break in the layer list); Erdbeben (24 h) matches the other hour readouts; retry countdowns get a space before s; the Mapillary hint names the Straßenebene layer. - The cyclone source's timeout and malformed-snapshot errors were plain English in every language: mark them like the wind source does and translate them in de, es, ru, zh-CN and zh-Hant. Co-Authored-By: Claude Opus 5.5 --- src/i18n/locales/de.json | 32 +++++++++++++++++--------------- src/i18n/locales/es.json | 4 +++- src/i18n/locales/ru.json | 4 +++- src/i18n/locales/zh-CN.json | 4 +++- src/i18n/locales/zh-Hant.json | 4 +++- src/i18n/same-as-english.json | 2 ++ src/layers/cyclones/source.js | 8 ++++++-- 7 files changed, 37 insertions(+), 21 deletions(-) diff --git a/src/i18n/locales/de.json b/src/i18n/locales/de.json index 0a86aea98..8acbc0f6f 100644 --- a/src/i18n/locales/de.json +++ b/src/i18n/locales/de.json @@ -15,7 +15,7 @@ "Overpass temporarily unavailable": "Overpass vorübergehend nicht verfügbar", "Retrying mapped sites…": "Neuer Versuch für kartierte Standorte…", "Fetching mapped sites…": "Kartierte Standorte werden abgerufen…", - "{reason} — retrying in {seconds}s": "{reason}: neuer Versuch in {seconds}s", + "{reason} — retrying in {seconds}s": "{reason}: neuer Versuch in {seconds} s", "{reason} — retry pending": "{reason}: neuer Versuch steht aus", "Zoom in to search mapped installations": "Hineinzoomen, um kartierte Anlagen zu suchen", "Showing cached mapped sites": "Kartierte Standorte aus dem Cache", @@ -372,7 +372,7 @@ "one": "{count} Kamera geladen · CCTV aktivieren", "other": "{count} Kameras geladen · CCTV aktivieren" }, - "Enable CCTV to load camera intersections": "CCTV aktivieren, um Kamerakreuzungen zu laden", + "Enable CCTV to load camera intersections": "CCTV aktivieren, um Kreuzungen mit Kameras zu laden", "Enable CCTV to start camera-linked intelligence summaries.": "CCTV aktivieren, um kameragestützte Lagezusammenfassungen zu starten.", "No summary available.": "Keine Zusammenfassung verfügbar.", "loading frames": "Frames werden geladen", @@ -499,7 +499,7 @@ "Context": "Kontext", "Live Flights": "Live-Flüge", "Military Flights": "Militärflüge", - "Earthquakes (24h)": "Erdbeben (24 Std)", + "Earthquakes (24h)": "Erdbeben (24 h)", "Satellites": "Satelliten", "Space Missions (30d)": "Raummissionen (30 T)", "Street Traffic": "Straßenverkehr", @@ -517,14 +517,14 @@ "DISABLING": "WIRD DEAKTIVIERT", "{state} · {source}": "{state} · {source}", "UNCERTAIN · {source} · lifecycle state requires reconciliation": "UNKLAR · {source} · Lebenszyklus-Status muss abgeglichen werden", - "{state} · {source} · {detail} · retry {seconds}s": "{state} · {source} · {detail} · neuer Versuch {seconds}s", + "{state} · {source} · {detail} · retry {seconds}s": "{state} · {source} · {detail} · neuer Versuch in {seconds} s", "{state} · {source} · {detail}": "{state} · {source} · {detail}", "never": "nie", "{source} · {loadingLabel}": "{source} · {loadingLabel}", "{accepted} of {raw} records accepted": "{accepted} von {raw} Datensätzen übernommen", "incomplete snapshot": "unvollständiger Snapshot", "{state} · {source} · {detail} · {ago}": "{state} · {source} · {detail} · {ago}", - "{state} · {source} · {ago} · retrying in {seconds}s": "{state} · {source} · {ago} · neuer Versuch in {seconds}s", + "{state} · {source} · {ago} · retrying in {seconds}s": "{state} · {source} · {ago} · neuer Versuch in {seconds} s", "{state} · {source} · {ago}": "{state} · {source} · {ago}", "{source} · {ago}": "{source} · {ago}", "UNCERTAIN": "UNKLAR", @@ -631,7 +631,7 @@ "REFRESHING LIVE DATA": "LIVE-DATEN WERDEN AKTUALISIERT", "syncing road network": "Straßennetz wird synchronisiert", "retry pending": "neuer Versuch steht aus", - "retrying in {seconds}s": "neuer Versuch in {seconds}s", + "retrying in {seconds}s": "neuer Versuch in {seconds} s", "Celestial ring — reveal the full globe": "Himmelsring: ganzen Globus zeigen", "Celestial ring — available in Normal style": "Himmelsring: im Stil Normal verfügbar", "Detection overlay: {mode}": "Erkennungs-Overlay: {mode}", @@ -656,7 +656,7 @@ "Running command": "Befehl läuft", "Voice off": "Sprache aus", "WebRTC microphone support unavailable": "WebRTC-Mikrofonunterstützung nicht verfügbar", - "VOICE UNAVAILABLE": "SPRACHE NICHT VERFÜGBAR", + "VOICE UNAVAILABLE": "SPRACHE N. V.", "VOICE ACTIVE": "SPRACHE AKTIV", "Voice session could not be started.": "Sprachsitzung konnte nicht gestartet werden.", "Next session: {pendingId} — this session stays on {modelId}": "Nächste Sitzung: {pendingId}. Diese Sitzung bleibt bei {modelId}", @@ -854,7 +854,7 @@ "START": "START", "EXPORT PRESETS": "PRESETS EXPORTIEREN", "IMPORT": "IMPORTIEREN", - "RUN LOG": "LAUFPROTOKOLL", + "RUN LOG": "PROTOKOLL", "POWER UP": "STARTKLAR", "GROUND STATION · PROVIDER SETTINGS": "BODENSTATION · ANBIETER-EINSTELLUNGEN", "Close key setup": "Schlüssel-Einrichtung schließen", @@ -1206,7 +1206,7 @@ "The photorealistic 3D planet, place search + Street View": "Der fotorealistische 3D-Planet, Ortssuche + Street View", "Voice control — API key or ChatGPT OAuth": "Sprachsteuerung – API-Schlüssel oder ChatGPT OAuth", "Gemini Live voice control": "Sprachsteuerung mit Gemini Live", - "Street-level imagery and coverage in the Street Level layer. Free: register an app in the Mapillary developer dashboard and paste its Client Token": "Bilder auf Straßenebene und Abdeckung in der Ebene Straßenansicht. Kostenlos: im Mapillary-Entwickler-Dashboard eine App registrieren und deren Client Token einfügen", + "Street-level imagery and coverage in the Street Level layer. Free: register an app in the Mapillary developer dashboard and paste its Client Token": "Bilder und Abdeckung auf Straßenebene in der Ebene „Straßenebene“. Kostenlos: im Mapillary-Entwickler-Dashboard eine App registrieren und deren Client Token einfügen", "Public space-missions access needs no key. Leave blank for standard use; paid tokens only raise request limits.": "Öffentlicher Zugang zu Raummissionen braucht keinen Schlüssel. Für normale Nutzung leer lassen; kostenpflichtige Tokens erhöhen nur die Anfragelimits.", "Air quality request failed": "Luftqualitätsabfrage fehlgeschlagen", "No readings available": "Keine Messwerte verfügbar", @@ -2153,7 +2153,7 @@ "S2 GhostMaps": "S2 GhostMaps", "Rain radar": "Regenradar", "Lightning density": "Blitzdichte", - "Cyclone advisories": "Wirbelsturmwarnungen", + "Cyclone advisories": "Sturmwarnungen", "ALPR Cameras": "ALPR-Kameras", "Live Vessels": "Live-Schiffe", "Bike Share": "Bikesharing", @@ -2252,14 +2252,14 @@ "Latest": "Neueste", "Newest frame per product": "Neuester Frame je Produkt", "Replay observed history": "Beobachteten Verlauf abspielen", - "Imagery on Esri · Google 3D returns when cleared": "Bilder auf Esri · Google 3D kehrt nach dem Löschen zurück", + "Imagery on Esri · Google 3D returns when cleared": "Bilder auf Esri · Google 3D nach dem Löschen", "Point the camera at the ground to use the view": "Kamera auf den Boden richten, um die Ansicht zu verwenden", "That point cannot anchor a box": "Dieser Punkt kann keinen Bereich verankern", "Imagery stops at ±{limit}° latitude": "Bilder enden bei ±{limit}° Breite", "{owner} is using the pointer — close it first": "{owner} verwendet gerade den Zeiger – zuerst schließen", "Box is {size} wide · limit {limit}": "Bereich ist {size} breit · Limit {limit}", "View is {size} wide · limit {limit}": "Ansicht ist {size} breit · Limit {limit}", - "VS BASEMAP": "MIT BASISKARTE", + "VS BASEMAP": "VGL. KARTE", "A / B": "A / B", "Newest low-cloud day for this box · scene cloud, not box cloud": "Neuester Tag mit wenig Wolken für diesen Bereich · Bewölkung der Szene, nicht des Bereichs", "Newest day covering this box · cloudier than 20%": "Neuester Tag mit Abdeckung dieses Bereichs · über 20 % Bewölkung", @@ -2326,8 +2326,8 @@ "Source off": "Quelle aus", "Unpin {slot}": "{slot} lösen", "Unpin the image": "Bild lösen", - "EXPORT {slot}": "{slot} EXPORTIEREN", - "EXPORT": "EXPORTIEREN", + "EXPORT {slot}": "EXPORT {slot}", + "EXPORT": "EXPORT", "Download {slot} as a PNG": "{slot} als PNG herunterladen", "Download the image as a PNG": "Bild als PNG herunterladen", "Box {width} × {height} km": "Bereich {width} × {height} km", @@ -2932,5 +2932,7 @@ "SINCE": "SEIT", "Toggle straight-down and tilted map views": "Zwischen senkrechter und geneigter Kartenansicht wechseln", "Reset map to north up": "Karte nach Norden ausrichten", - "Reset map bearing to north": "Kartenausrichtung auf Norden zurücksetzen" + "Reset map bearing to north": "Kartenausrichtung auf Norden zurücksetzen", + "Cyclone request timed out": "Zeitüberschreitung bei der Sturmabfrage", + "Malformed cyclone snapshot": "Fehlerhafter Sturm-Snapshot" } diff --git a/src/i18n/locales/es.json b/src/i18n/locales/es.json index 0285917b0..79780cb40 100644 --- a/src/i18n/locales/es.json +++ b/src/i18n/locales/es.json @@ -3001,5 +3001,7 @@ "Your choice applies now, but could not be saved.": "Tu elección se aplica ahora, pero no se pudo guardar.", "Voice replies appear here.": "Las respuestas de voz aparecen aquí.", "Preview is off.": "La vista previa está desactivada.", - "Automatic stop is unavailable for this voice connection.": "La parada automática no está disponible para esta conexión de voz." + "Automatic stop is unavailable for this voice connection.": "La parada automática no está disponible para esta conexión de voz.", + "Cyclone request timed out": "La petición de ciclones agotó el tiempo de espera", + "Malformed cyclone snapshot": "Instantánea de ciclones mal formada" } diff --git a/src/i18n/locales/ru.json b/src/i18n/locales/ru.json index b1c1be229..93c0b389d 100644 --- a/src/i18n/locales/ru.json +++ b/src/i18n/locales/ru.json @@ -3070,5 +3070,7 @@ "Your choice applies now, but could not be saved.": "Ваш выбор применён, но сохранить его не удалось.", "Voice replies appear here.": "Здесь появляются голосовые ответы.", "Preview is off.": "Предпросмотр отключён.", - "Automatic stop is unavailable for this voice connection.": "Автоматическая остановка недоступна для этого голосового подключения." + "Automatic stop is unavailable for this voice connection.": "Автоматическая остановка недоступна для этого голосового подключения.", + "Cyclone request timed out": "Истекло время ожидания запроса о циклонах", + "Malformed cyclone snapshot": "Некорректный снимок данных о циклонах" } diff --git a/src/i18n/locales/zh-CN.json b/src/i18n/locales/zh-CN.json index 9bf76700c..854235f3d 100644 --- a/src/i18n/locales/zh-CN.json +++ b/src/i18n/locales/zh-CN.json @@ -2863,5 +2863,7 @@ "{count} placemarks": { "other": "{count} 个地标" }, - "S2 Underground publishes these KMZ products to GitHub. New uploads are detected within seconds and replace the previous edition automatically. Click a marker for its report.": "S2 Underground 在 GitHub 发布这些 KMZ 产品。新上传的内容会在数秒内被检测到,并自动替换旧版本。点击标记查看报告。" + "S2 Underground publishes these KMZ products to GitHub. New uploads are detected within seconds and replace the previous edition automatically. Click a marker for its report.": "S2 Underground 在 GitHub 发布这些 KMZ 产品。新上传的内容会在数秒内被检测到,并自动替换旧版本。点击标记查看报告。", + "Cyclone request timed out": "气旋请求超时", + "Malformed cyclone snapshot": "气旋快照格式错误" } diff --git a/src/i18n/locales/zh-Hant.json b/src/i18n/locales/zh-Hant.json index d95a18e39..113a79e65 100644 --- a/src/i18n/locales/zh-Hant.json +++ b/src/i18n/locales/zh-Hant.json @@ -2863,5 +2863,7 @@ "{count} placemarks": { "other": "{count} 個地標" }, - "S2 Underground publishes these KMZ products to GitHub. New uploads are detected within seconds and replace the previous edition automatically. Click a marker for its report.": "S2 Underground 在 GitHub 發布這些 KMZ 產品。新上傳的內容會在數秒內被檢測到,並自動替換舊版本。點擊標記查看報告。" + "S2 Underground publishes these KMZ products to GitHub. New uploads are detected within seconds and replace the previous edition automatically. Click a marker for its report.": "S2 Underground 在 GitHub 發布這些 KMZ 產品。新上傳的內容會在數秒內被檢測到,並自動替換舊版本。點擊標記查看報告。", + "Cyclone request timed out": "氣旋請求超時", + "Malformed cyclone snapshot": "氣旋快照格式錯誤" } diff --git a/src/i18n/same-as-english.json b/src/i18n/same-as-english.json index 4946512a3..d8a4247a7 100644 --- a/src/i18n/same-as-english.json +++ b/src/i18n/same-as-english.json @@ -27,6 +27,8 @@ "Dance", "Details", "Dubai", + "EXPORT", + "EXPORT {slot}", "FALLBACK", "FILTER", "FLIR", diff --git a/src/layers/cyclones/source.js b/src/layers/cyclones/source.js index 05c805fbd..84294620f 100644 --- a/src/layers/cyclones/source.js +++ b/src/layers/cyclones/source.js @@ -1,7 +1,11 @@ import { readResponseJsonCapped } from '../../sources/httpBody.js'; +// No i18n here, as in the wind source: the texts stay English data and the +// cyclone layer shows them translated. +const msg = (text) => text; + export const CYCLONE_RESPONSE_LIMIT = 4 * 1024 * 1024; -const malformed = () => new Error('Malformed cyclone snapshot'); +const malformed = () => new Error(msg('Malformed cyclone snapshot')); const text = (value, max = 160) => { if ( typeof value !== 'string' || @@ -215,7 +219,7 @@ export function createCycloneSource({ const abort = () => controller.abort(signal.reason); signal?.addEventListener('abort', abort, { once: true }); const timer = setTimeout( - () => controller.abort(new Error('Cyclone request timed out')), + () => controller.abort(new Error(msg('Cyclone request timed out'))), timeoutMs, ); try { From cdd90dac4bda4809a0e3d74936617cd55ee720f3 Mon Sep 17 00:00:00 2001 From: German Khokhlov Date: Wed, 28 Oct 2026 16:21:13 +0400 Subject: [PATCH 22/83] i18n(uk): fixes from the screenshot review MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Layer rows read «не оновлювалося» for a feed that never updated, not «ніколи». - The dock voice toggle label fits on one line (ПЕРЕМК.), the cockpit briefing title (НОВИНИ РЕГІОНУ) no longer truncates, Celestial is «Небо». - No-break spaces keep «24 год», «30 дн» and coordinate abbreviations (пн. ш., зх. д.) on one line. Co-Authored-By: Claude Opus 5.5 --- src/i18n/locales/uk.json | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/src/i18n/locales/uk.json b/src/i18n/locales/uk.json index 8a543e929..bc98109cf 100644 --- a/src/i18n/locales/uk.json +++ b/src/i18n/locales/uk.json @@ -186,7 +186,7 @@ "NEPAL · 26 AUG 2026": "НЕПАЛ · 26 СЕРП. 2026", "USGS INITIAL REPORT": "ПЕРВИННЕ ПОВІДОМЛЕННЯ USGS", "26 AUG 2026 · 08:37 NPT": "26 СЕРП. 2026 · 08:37 NPT", - "28.2710° N · 85.5150° E": "28,2710° ПН. Ш. · 85,5150° СХ. Д.", + "28.2710° N · 85.5150° E": "28,2710° ПН. Ш. · 85,5150° СХ. Д.", "INITIAL M4.4 · RECLASSIFIED M5.2 LANDSLIDE": "СПОЧАТКУ M4,4 · ПЕРЕКЛАСИФІКОВАНО: ЗСУВ M5,2", "USGS EVENT us7000tbwb · OPEN SOURCE": "ПОДІЯ USGS us7000tbwb · ВІДКРИТИ ДЖЕРЕЛО", "Open the USGS initial report for the 26 August 2026 Nepal landslide": "Відкрити первинне повідомлення USGS про зсув у Непалі 26 серпня 2026 року", @@ -725,10 +725,10 @@ "FIRES": "ПОЖЕЖІ", "max {value} MW": "макс. {value} МВт", "new {value}": "нова {value}", - "{value}°N": "{value}° пн. ш.", - "{value}°S": "{value}° пд. ш.", - "{value}°E": "{value}° сх. д.", - "{value}°W": "{value}° зх. д.", + "{value}°N": "{value}° пн. ш.", + "{value}°S": "{value}° пд. ш.", + "{value}°E": "{value}° сх. д.", + "{value}°W": "{value}° зх. д.", "just now": "щойно", "<1m ago": "<1 хв тому", "{count}m ago": "{count} хв тому", @@ -1226,7 +1226,7 @@ "Contiguous US · gaps ≠ no rain": "Континентальні США · прогалини ≠ немає дощу", "Americas + Pacific · not individual strikes": "Америка + Тихий океан · не окремі розряди", "Color: strikes/km²/min ×10³": "Колір: розрядів/км²/хв ×10³", - "60°S–60°N · typically 2–3 h delayed": "60° пд. ш.–60° пн. ш. · зазвичай затримка 2–3 год", + "60°S–60°N · typically 2–3 h delayed": "60° пд. ш.–60° пн. ш. · зазвичай затримка 2–3 год", "North America · infrared imagery": "Північна Америка · ІЧ-знімки", "Reduced motion · history playback unavailable": "Зменшення руху · відтворення історії недоступне", "Reduced motion · manual history available": "Зменшення руху · історію можна гортати вручну", @@ -1234,7 +1234,7 @@ "Lightning density · 15 min": "Щільність блискавок · 15 хв", "Satellite clouds": "Супутникова хмарність", "Americas + Pacific": "Америка + Тихий океан", - "Global · 60°S–60°N": "Глобально · 60° пд. ш.–60° пн. ш.", + "Global · 60°S–60°N": "Глобально · 60° пд. ш.–60° пн. ш.", "North America": "Північна Америка", "Source observations delayed": "Спостереження джерела затримуються", "Stale source": "Джерело застаріло", @@ -1259,7 +1259,7 @@ "{value} dBZ radar reflectivity": "Радіолокаційна відбивність: {value} dBZ", "STALE · cached source metadata": "ЗАСТАРІЛО · метадані джерела з кешу", "Map center is outside source coverage": "Центр карти поза зоною покриття джерела", - "NOAA/NWS 15-minute lightning density derived from Vaisala NLDN/GLD360. Coverage 110°E across the Pacific/Americas to 0°, 25°S–80°N. Not a live strike count, global coverage or a safety warning.": "15-хвилинна щільність блискавок NOAA/NWS на основі Vaisala NLDN/GLD360. Покриття — від 110° сх. д. через Тихий океан і Америку до 0°, 25° пд. ш.–80° пн. ш. Це не підрахунок розрядів у реальному часі, не глобальне покриття й не попередження про небезпеку.", + "NOAA/NWS 15-minute lightning density derived from Vaisala NLDN/GLD360. Coverage 110°E across the Pacific/Americas to 0°, 25°S–80°N. Not a live strike count, global coverage or a safety warning.": "15-хвилинна щільність блискавок NOAA/NWS на основі Vaisala NLDN/GLD360. Покриття — від 110° сх. д. через Тихий океан і Америку до 0°, 25° пд. ш.–80° пн. ш. Це не підрахунок розрядів у реальному часі, не глобальне покриття й не попередження про небезпеку.", "NOAA MRMS radar echoes indicate precipitation patterns, not rain rate, a storm warning or a future forecast. Native source approximately 1 km; display is limited to level 6. Frames use exact advertised observation times.": "Радіолокаційні відлуння NOAA MRMS показують картину опадів, а не їхню інтенсивність, штормове попередження чи прогноз. Вихідна роздільність близько 1 км; показ обмежено рівнем 6. Для кадрів використано точний заявлений час спостережень.", "GOES-19/18 longwave infrared Band 14 regional; NESDIS global longwave mosaic. Clouds only dims everything but bright, cold cloud tops; a brightness filter, not a cloud mask. Coverage and freshness differ by region.": "Регіональний довгохвильовий ІЧ-канал 14 GOES-19/18; глобальна довгохвильова мозаїка NESDIS. Режим «Лише хмари» затемнює все, крім яскравих холодних вершин хмар; це фільтр яскравості, а не маска хмарності. Покриття й актуальність різняться за регіонами.", "REGION": "РЕГІОН", @@ -1676,7 +1676,7 @@ "CLOUD {pct}%": "ХМАРНІСТЬ {pct}%", "CLOUD UNKNOWN": "ХМАРНІСТЬ НЕВІДОМА", "{source} · LOCATION QUERY": "{source} · ЗАПИТ ЗА РОЗТАШУВАННЯМ", - "REGIONAL NEWS": "РЕГІОНАЛЬНІ НОВИНИ", + "REGIONAL NEWS": "НОВИНИ РЕГІОНУ", "{label} · {radius} AIR/SEA WINDOW": "{label} · ВІКНО ПОВІТРЯ/МОРЕ {radius}", "{scope} · INSTALLATIONS {coverage}": "{scope} · ОБʼЄКТИ: {coverage}", "CONTEXT STANDBY": "КОНТЕКСТ: ОЧІКУВАННЯ", @@ -1823,9 +1823,9 @@ "{requirement}, or {offer}": "{requirement} або {offer}", "Live Flights": "Рейси онлайн", "Military Flights": "Військові рейси", - "Earthquakes (24h)": "Землетруси (24 год)", + "Earthquakes (24h)": "Землетруси (24 год)", "Satellites": "Супутники", - "Space Missions (30d)": "Космічні місії (30 дн)", + "Space Missions (30d)": "Космічні місії (30 дн)", "Street Traffic": "Вуличний рух", "CCTV": "CCTV", "Radio": "Радіо", @@ -1875,7 +1875,7 @@ "UNCERTAIN · {source} · lifecycle state requires reconciliation": "НЕВИЗНАЧЕНО · {source} · стан життєвого циклу потребує звірки", "{state} · {source} · {detail} · retry {seconds}s": "{state} · {source} · {detail} · повтор через {seconds} с", "{state} · {source} · {detail}": "{state} · {source} · {detail}", - "never": "ніколи", + "never": "не оновлювалося", "{source} · {loadingLabel}": "{source} · {loadingLabel}", "{accepted} of {raw} records accepted": "прийнято записів: {accepted} з {raw}", "incomplete snapshot": "неповний знімок", @@ -2367,7 +2367,7 @@ "STD": "СТД", "Estimated session cost": "Орієнтовна вартість сесії", "Voice control — activate to toggle voice; hold Space to speak": "Голосове керування — активуйте, щоб увімкнути або вимкнути голос; утримуйте Space, щоб говорити", - "ON/OFF": "УВІМК/ВИМК", + "ON/OFF": "ПЕРЕМК.", "VOICE STANDBY": "ГОЛОС ОЧІКУЄ", "VOICE CONTROL": "ГОЛОСОВЕ КЕРУВАННЯ", "Hold Space to speak · tap Space to activate focused controls": "Утримуйте Space, щоб говорити · натисніть Space, щоб активувати елемент у фокусі", @@ -2987,7 +2987,7 @@ "Import": "Імпорт", "Choose GeoJSON, KML, KMZ or GPX files": "Виберіть файли GeoJSON, KML, KMZ або GPX", "Imported files": "Імпортовані файли", - "Celestial": "Небесне", + "Celestial": "Небо", "Hide UI chrome": "Сховати оформлення інтерфейсу", "Clean UI": "Чистий інтерфейс", "Bloom / Glow": "Світіння / Ореол", From 4adb9113bcd71d47234548bfe2d3e195709bed05 Mon Sep 17 00:00:00 2001 From: German Khokhlov Date: Wed, 28 Oct 2026 16:40:53 +0400 Subject: [PATCH 23/83] i18n(fr): apply review round 1 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Apply the accepted findings from the three-model French review: ground track reads « route », wildfire containment « circonscrit », downrange « distance au sol », tankers « navire-citerne », plus wording fixes for lanes, timestamps, wind sector, radio, CCTV and voice strings. Shots rebuilt by a pack's legacy bootstrap carry no sourcePackId, so the first Nepal shot titles stayed English; the scene's applied-pack marker now vouches for the pack's required titles. Co-Authored-By: Claude Opus 5.5 --- docs/translations/fr.md | 116 ++++++++++---------- src/i18n/locales/fr.json | 148 +++++++++++++------------- src/scenes/recipes.js | 24 +++-- src/scenes/sceneTitleDisplay.test.mjs | 23 ++++ 4 files changed, 173 insertions(+), 138 deletions(-) diff --git a/docs/translations/fr.md b/docs/translations/fr.md index 948479e6a..695d1b48f 100644 --- a/docs/translations/fr.md +++ b/docs/translations/fr.md @@ -11,7 +11,7 @@ Translation source: abiyeenzo (#907); the French part of meirm's #312 was used f - Sentence case, not Title Case: "Live Flights" → « Vols en direct ». UPPERCASE English stays UPPERCASE, accents included: « ÉTAT », « PRÉC. ». - Typography: a narrow no-break space (U+202F) goes before `:` `;` `?` `!` and `%`, and inside « » quotes: `Supprimer le plan « {shot} » ?`. It keeps the sign on the same line as the word before it. Do not type a plain space there. Ellipsis is `…`, not `...`. Dashes keep their spaces: « flux indisponible — réessayez ». - Short labels, chips and HUD readouts stay short. A standard abbreviation with a period beats a wrapped line: PRÉC., SUIV., RÉINIT., ENREG., INDISP., DIST. -- The HUD codes HDG, BRG, CRS, FOV, DEST, SPD and ALT stay in English everywhere, as in cockpit avionics. Words are translated: RANGE → « PORTÉE », heading in a sentence → « cap ». +- The HUD codes HDG, BRG, CRS, FOV, DEST, SPD and ALT stay in English everywhere, as in cockpit avionics. Words are translated: RANGE → « PORTÉE », heading in a sentence → « cap », ground-track course → « route » (« ROUTE 270° »). - ON and OFF stay as they are on HUD toggles and chips (« CCTV ON », « PROJECTION OFF »); in a sentence use « activé » / « désactivé ». - Keyboard keys stay in English: Space, Esc, Enter, Tab, Shift, Backspace, H, 1–9 (« Maintenez Space pour parler », « ESC pour fermer »). - Units: km, m, km/h, m/s, nd (knots), ft (feet), h, min, s, with a space before the unit: « 250 km », « il y a 5 min »; in UPPERCASE text KM, KM/S, ND, FT, MIN. MW, dBZ, hPa and `°` stay. Decimal comma in fixed numbers: « 28,2710° N », « M4,4 ». Money: « 12 k$ », « 3 M$ », « 2 Md$ ». @@ -32,60 +32,60 @@ The `many` form is the `other` text with « de » (« d' » before a vowel) afte ## Glossary -| English | Français | -| ---------------------------------------------- | --------------------------------------------------------------- | -| layer / data layer / DATA LAYERS (panel title) | couche / couche de données / COUCHES | -| feed / source / data source | flux / source / source de données | -| LIVE (status) / live data | DIRECT / données en direct | -| SIMULATED | SIMULÉ | -| stale / degraded / unavailable | obsolète / dégradé / indisponible | -| retry / retrying | nouvel essai / réessayez | -| rate-limited | limite de requêtes atteinte | -| key (API key) / POWER UP / POWERED UP | clé (clé API) / ALLUMER / ALLUMÉ | -| Provider Settings | paramètres des fournisseurs | -| enable / disable | activer / désactiver | -| globe / map / map source / basemap / map stack | globe / carte / source de carte / fond de carte / fond de carte | -| tile (map) | tuile | -| aircraft / flight / military flights | aéronef (avion in short copy) / vol / vols militaires | -| vessel, ship | navire | -| satellite / shell (Starlink) / DENSE | satellite / couche de la constellation / DENSE | -| launch / launch site / space mission | lancement / site de lancement / mission spatiale | -| ascent / replay / payload / stage / downrange | ascension / rejeu / charge utile / étage / distance parcourue | -| contact / tracking / track (HUD) | contact / suivi / piste | -| installation / site | installation / site | -| mapped / observed | cartographié / observé | -| camera / CCTV camera / ALPR camera | caméra / caméra CCTV / caméra LAPI | -| earthquake | séisme | -| active fire (FIRMS detection) / wildfire | feu actif / incendie | -| contained (wildfire) | maîtrisé | -| advisory (NHC/CPHC cyclone) | bulletin | -| forecast / lead hours / valid / issued | prévision / échéances / valide / émise | -| AQHI (Canada) | CQAS (cote air santé) | -| radio station / tune | station / régler | -| bikeshare / transit | vélos partagés / transports en commun | -| route (directions) / turn (maneuver) | itinéraire / manœuvre | -| scene / shot / scene recipe | scène / plan / recette de scène | -| bundle / data pack / anchor | archive / paquet de données / ancre | -| story beat | étape du récit | -| briefing / panel / dock | briefing / panneau / dock | -| cockpit | cockpit | -| preset / visual preset | préréglage / préréglage visuel | -| Scope (circular viewport mask) / keyhole | lunette / ouverture | -| detection overlay | surcouche de détection | -| Clean UI | vue épurée | -| Street Level (layer) / Street View (Google) | Niveau rue / Street View | -| Recent Imagery / box | imagerie récente / zone | -| pin (Draw tool) / pin (Recent Imagery) | épingle / épingler | -| Cyber (HUD layout, effect) | Cyber | -| heading, course / altitude / ground speed | cap / altitude / vitesse sol | -| HDG / BRG / CRS / FOV / DEST / SPD / ALT | unchanged | -| RANGE / PITCH / HGT (CCTV calibration chips) | PORTÉE / INCL. / HAUT. | -| PREV / PREVIOUS / NEXT (chips) | PRÉC. / PRÉC. / SUIV. | -| Previous / Next (button text) | Précédent / Suivant | -| L / R (relative bearing) | G / D | -| SIG / NEWS / LOCAL (briefing tabs) | SIG / ACTUS / LOCAL | -| compass points (N, NNE, …, W, NW) | N, NNE, …, O, NO | -| NOT AN ALL-CLEAR | PAS UN FEU VERT | -| AI agent | agent IA | -| share (a view or link) | partager | -| click / click to … | cliquez / cliquer pour … | +| English | Français | +| --------------------------------------------------------- | ----------------------------------------------------------------------- | +| layer / data layer / DATA LAYERS (panel title) | couche / couche de données / COUCHES | +| feed / source / data source | flux / source / source de données | +| LIVE (status) / live data | DIRECT / données en direct | +| SIMULATED | SIMULÉ | +| stale / degraded / unavailable | obsolète / dégradé / indisponible | +| retry / retrying | nouvel essai / réessayez | +| rate-limited | limite de requêtes atteinte | +| key (API key) / POWER UP / POWERED UP | clé (clé API) / ALLUMER / ALLUMÉ | +| Provider Settings | paramètres des fournisseurs | +| enable / disable | activer / désactiver | +| globe / map / map source / basemap / map stack | globe / carte / source de carte / fond de carte / fond de carte | +| tile (map) | tuile | +| aircraft / flight / military flights | aéronef (avion in short copy) / vol / vols militaires | +| vessel, ship / tanker (AIS type) | navire / navire-citerne | +| satellite / shell (Starlink) / DENSE | satellite / couche de la constellation / DENSE | +| launch / launch site / space mission | lancement / site de lancement / mission spatiale | +| ascent / replay / payload / stage / downrange | ascension / rejeu / charge utile / étage / distance au sol (DIST. SOL) | +| contact / tracking / track (HUD) | contact / suivi / piste | +| installation / site | installation / site | +| mapped / observed | cartographié / observé | +| camera / CCTV camera / ALPR camera | caméra / caméra CCTV / caméra LAPI | +| earthquake | séisme | +| active fire (FIRMS detection) / wildfire | feu actif / incendie | +| contained / containment (wildfire) | circonscrit / part circonscrite (not « maîtrisé », which is controlled) | +| advisory (NHC/CPHC cyclone) | bulletin | +| forecast / lead hours / valid / issued | prévision / échéances / valide / émise | +| AQHI (Canada) | CQAS (cote air santé) | +| radio station / tune | station / régler | +| bikeshare / transit | vélos partagés / transports en commun | +| route (directions) / turn (maneuver) | itinéraire / manœuvre | +| scene / shot / scene recipe | scène / plan / recette de scène | +| bundle / data pack / anchor | archive / paquet de données / ancre | +| story beat | étape du récit | +| briefing / panel / dock | briefing / panneau / dock | +| cockpit | cockpit | +| preset / visual preset | préréglage / préréglage visuel | +| Scope (circular viewport mask) / keyhole | lunette / ouverture | +| detection overlay | surcouche de détection | +| Clean UI | vue épurée | +| Street Level (layer) / Street View (Google) | Niveau rue / Street View | +| Recent Imagery / box | imagerie récente / zone | +| pin (Draw tool) / pin (Recent Imagery) | épingle / épingler | +| Cyber (HUD layout, effect) | Cyber | +| heading / course (ground track) / altitude / ground speed | cap / route / altitude / vitesse sol | +| HDG / BRG / CRS / FOV / DEST / SPD / ALT | unchanged | +| RANGE / PITCH / HGT (CCTV calibration chips) | PORTÉE / INCL. / HAUT. | +| PREV / PREVIOUS / NEXT (chips) | PRÉC. / PRÉC. / SUIV. | +| Previous / Next (button text) | Précédent / Suivant | +| L / R (relative bearing) | G / D | +| SIG / NEWS / LOCAL (briefing tabs) | SIG / ACTUS / LOCAL | +| compass points (N, NNE, …, W, NW) | N, NNE, …, O, NO | +| NOT AN ALL-CLEAR | PAS UN FEU VERT | +| AI agent | agent IA | +| share (a view or link) | partager | +| click / click to … | cliquez / cliquer pour … | diff --git a/src/i18n/locales/fr.json b/src/i18n/locales/fr.json index 1ae43fb08..883621f94 100644 --- a/src/i18n/locales/fr.json +++ b/src/i18n/locales/fr.json @@ -3,9 +3,9 @@ "Enter to place the pin, Esc to cancel.": "Enter pour poser l'épingle, Esc pour annuler.", "Click where the pin goes.": "Cliquez à l'endroit où poser l'épingle.", "Click {count} more points.": { - "one": "Cliquez encore {count} point.", - "many": "Cliquez encore {count} de points.", - "other": "Cliquez encore {count} points." + "one": "Cliquez pour ajouter encore {count} point.", + "many": "Cliquez pour ajouter encore {count} de points.", + "other": "Cliquez pour ajouter encore {count} points." }, "Those points are in a line — move one off it to enclose an area.": "Ces points sont alignés — déplacez-en un hors de la ligne pour délimiter une zone.", "That line has no length — click somewhere further away.": "Cette ligne n'a pas de longueur — cliquez plus loin.", @@ -43,13 +43,13 @@ "General emergency": "Urgence générale", "Unlawful interference": "Intervention illicite", "Radio failure": "Panne radio", - "Downed aircraft": "Aéronef abattu", + "Downed aircraft": "Aéronef accidenté", "Minimum fuel": "Carburant minimum", "Lifeguard (medical priority)": "Lifeguard (priorité médicale)", "Rasuwagadhi witness video": "Vidéo d'un témoin à Rasuwagadhi", "Bhote Koshi valley footage": "Images de la vallée de la Bhote Koshi", "Flood footage": "Images de la crue", - "Compilation and casualty claims": "Compilation et bilans de victimes non vérifiés", + "Compilation and casualty claims": "Compilation et bilans de victimes", "SOURCE GEOCONFIRMED · WORLD-PINNED": "SOURCE GÉOCONFIRMÉE · ÉPINGLÉE SUR LA CARTE", "SOURCE CREDITED · LOCATION UNRESOLVED": "SOURCE CRÉDITÉE · LIEU NON DÉTERMINÉ", "REFERENCE ONLY · CLAIMS UNVERIFIED": "RÉFÉRENCE SEULEMENT · AFFIRMATIONS NON VÉRIFIÉES", @@ -62,7 +62,7 @@ "Second landslide": "Second glissement de terrain", "Gyirong border gate": "Poste frontière de Gyirong", "Border gate": "Poste frontière", - "Timure evidence cluster": "Groupe d'éléments de preuve de Timure", + "Timure evidence cluster": "Groupe de preuves de Timure", "Mailung / Upper Trishuli bridge": "Mailung / pont d'Upper Trishuli", "Dandagaun viewpoint restaurant": "Restaurant-belvédère de Dandagaun", "Dandagaun viewpoint": "Belvédère de Dandagaun", @@ -85,11 +85,11 @@ "LOADING X POST…": "CHARGEMENT DU POST X…", "The X post is unavailable or cannot be embedded.": "Le post X est indisponible ou ne peut pas être intégré.", "X POST · PROVIDER CONTROLS": "POST X · COMMANDES DU FOURNISSEUR", - "{reason} OPEN ORIGINAL.": "{reason} OUVREZ L'ORIGINAL.", + "{reason} OPEN ORIGINAL.": "{reason} OUVRIR L'ORIGINAL.", "X embed unavailable": "Intégration X indisponible", "FACEBOOK · PROVIDER CONTROLS": "FACEBOOK · COMMANDES DU FOURNISSEUR", "Facebook embed unavailable": "Intégration Facebook indisponible", - "AUTOPLAY BLOCKED · USE PROVIDER CONTROLS": "LECTURE AUTO BLOQUÉE · UTILISEZ LES COMMANDES DU FOURNISSEUR", + "AUTOPLAY BLOCKED · USE PROVIDER CONTROLS": "LECTURE AUTO BLOQUÉE · UTILISER LES COMMANDES DU FOURNISSEUR", "Embedded {provider} media for {source}": "Média {provider} intégré pour {source}", "witness source": "source témoin", "Witness source": "Source témoin", @@ -99,7 +99,7 @@ "{provider} · PROVIDER CONTROLS": "{provider} · COMMANDES DU FOURNISSEUR", "YOUTUBE {state} · OPEN ORIGINAL": "YOUTUBE {state} · OUVRIR L'ORIGINAL", "INITIATION": "DÉCLENCHEMENT", - "DAMMING": "OBSTRUCTION", + "DAMMING": "BARRAGE", "SECONDARY FAILURE": "RUPTURE SECONDAIRE", "BORDER ARRIVAL": "ARRIVÉE À LA FRONTIÈRE", "PROPAGATION": "PROPAGATION", @@ -293,7 +293,7 @@ "HIGH-SPEED": "GRANDE VITESSE", "PASSENGER": "PASSAGERS", "CARGO": "CARGO", - "TANKER": "PÉTROLIER", + "TANKER": "NAVIRE-CITERNE", "OTHER": "AUTRE", "Included in bundle": "Inclus dans l'archive", "Missing bundle file — reimport its bundle": "Fichier absent de l'archive — réimportez son archive", @@ -393,7 +393,7 @@ "Optional paid token — public access works without one": "Jeton payant facultatif — l'accès public fonctionne sans", "Free key — register, paste, done": "Clé gratuite — inscrivez-vous, collez-la, c'est tout", "browser-side": "côté navigateur", - "This key runs in the browser by design — restrict it at the provider (see SECURITY.md)": "Cette clé s'exécute dans le navigateur par conception — restreignez-la chez le fournisseur (voir SECURITY.md)", + "This key runs in the browser by design — restrict it at the provider (see SECURITY.md)": "Cette clé est conçue pour être utilisée dans le navigateur — restreignez son usage chez le fournisseur (voir SECURITY.md)", "configured externally": "configurée ailleurs", "Supplied by your environment, Keychain, or launcher — change it where it was set": "Fournie par votre environnement, le Trousseau ou le lanceur — modifiez-la là où elle a été définie", "MANAGE ↗": "GÉRER ↗", @@ -464,14 +464,14 @@ "Camera badges": "Badges de caméras", "Cyan cameras turn coral when selected. Wedges illustrate mapped direction, not measured coverage. Nearby cameras may be outside the screen.": "Les caméras cyan deviennent corail une fois sélectionnées. Les secteurs illustrent l'orientation cartographiée, pas une couverture mesurée. Des caméras proches peuvent être hors de l'écran.", "{count} nearby · {onScreen} on screen": { - "one": "{count} proche · {onScreen} à l'écran", - "many": "{count} de caméras proches · {onScreen} à l'écran", - "other": "{count} proches · {onScreen} à l'écran" + "one": "{count} à proximité · {onScreen} à l'écran", + "many": "{count} à proximité · {onScreen} à l'écran", + "other": "{count} à proximité · {onScreen} à l'écran" }, "{count} nearby": { - "one": "{count} proche", - "many": "{count} de caméras proches", - "other": "{count} proches" + "one": "{count} à proximité", + "many": "{count} à proximité", + "other": "{count} à proximité" }, "retrying mapped ALPR cameras": "nouvel essai des caméras LAPI cartographiées", "loading mapped ALPR cameras": "chargement des caméras LAPI cartographiées", @@ -489,7 +489,7 @@ "CONTEXT READY": "CONTEXTE PRÊT", "GLOBAL CONTEXT OFF": "CONTEXTE GLOBAL OFF", "SELECT A FLIGHT, VESSEL, OR MAPPED INSTALLATION": "CHOISIR UN VOL, UN NAVIRE OU UNE INSTALLATION CARTOGRAPHIÉE", - "ENABLE TO LOAD OBSERVED / MAPPED PROXIMITY": "ACTIVER POUR CHARGER LA PROXIMITÉ OBSERVÉE / CARTOGRAPHIÉE", + "ENABLE TO LOAD OBSERVED / MAPPED PROXIMITY": "ACTIVER POUR VOIR LES CONTACTS PROCHES OBSERVÉS / CARTOGRAPHIÉS", "Unavailable": "Indisponible", "Focus {label}": "Centrer sur {label}", "Global Context navigation": "Navigation du Contexte global", @@ -561,9 +561,9 @@ "many": "{count} de cyclones actifs", "other": "{count} cyclones actifs" }, - "Position as of {time}": "Position à {time}", + "Position as of {time}": "Position au {time}", "Maximum sustained wind: {wind} · Pressure: {pressure}": "Vent maximal soutenu : {wind} · Pression : {pressure}", - "{name} · {classification} · Advisory {number} · issued {time}": "{name} · {classification} · Bulletin {number} · émis à {time}", + "{name} · {classification} · Advisory {number} · issued {time}": "{name} · {classification} · Bulletin {number} · émis le {time}", "No active NHC/CPHC systems": "Aucun système actif NHC/CPHC", "Advisories unavailable": "Bulletins indisponibles", "Cyclones · NHC / CPHC": "Cyclones · NHC / CPHC", @@ -610,7 +610,7 @@ "lane direction|slightly right": "de droite", "lane direction|sharply left": "la plus à gauche", "lane direction|sharply right": "la plus à droite", - "lane direction|straight": "centrale", + "lane direction|straight": "qui va tout droit", "ordinal|{number}st": "{number}re", "ordinal|{number}nd": "{number}e", "ordinal|{number}rd": "{number}e", @@ -669,7 +669,7 @@ "Continue onto {road}": "Continuez sur {road}", "maneuver|Continue": "Continuez", "{mode} — reroute for {modeLower}": "{mode} — recalculer l'itinéraire : {modeLower}", - "CLICK MAP": "CLIQUEZ LA CARTE", + "CLICK MAP": "CLIQUER SUR LA CARTE", "SET A": "PLACER A", "Click a spot on the globe to place A (click again to cancel)": "Cliquez sur un point du globe pour placer A (cliquez à nouveau pour annuler)", "Then click the globe to place the start": "Puis cliquez sur le globe pour placer le départ", @@ -716,7 +716,7 @@ "FIRE": "FEU", "FIRES": "FEUX", "max {value} MW": "max {value} MW", - "new {value}": "nouveau {value}", + "new {value}": "dernier il y a {value}", "{value}°N": "{value}°N", "{value}°S": "{value}°S", "{value}°E": "{value}°E", @@ -742,7 +742,7 @@ "Kinetic 30d": "Cinétique 30 j", "Border Crisis": "Crise frontalière", "Iran Picture": "Situation Iran", - "Iran Kinetic": "Iran cinétique", + "Iran Kinetic": "Cinétique Iran", "Yemen FLOT": "FLOT Yémen", "Latest Drop": "Dernière publication", "GhostMaps file could not be read": "Impossible de lire le fichier GhostMaps", @@ -817,7 +817,7 @@ "UNSPECIFIED": "NON PRÉCISÉ", "+{count} additional payload records": "+{count} enregistrements de charge utile supplémentaires", "PAYLOAD DATA UNAVAILABLE": "DONNÉES DE CHARGE UTILE INDISPONIBLES", - "{value} KM DOWNRANGE": "{value} KM PARCOURUS", + "{value} KM DOWNRANGE": "DIST. SOL : {value} KM", "POSITION UNAVAILABLE": "POSITION INDISPONIBLE", "FLIGHT {count}": "VOL {count}", "REUSED": "RÉUTILISÉ", @@ -858,7 +858,7 @@ "SHOW ALL / DESELECT": "TOUT AFFICHER / DÉSÉLECTIONNER", "Pause replay": "Mettre le rejeu en pause", "Cancel replay": "Annuler le rejeu", - "EST. DOWNRANGE": "DIST. ESTIMÉE", + "EST. DOWNRANGE": "DIST. SOL ESTIMÉE", "PLANNED · ": "PRÉVU · ", "SUPPLIED TRAJECTORY POINTS": "POINTS DE TRAJECTOIRE FOURNIS", "RECONSTRUCTED ESTIMATE": "ESTIMATION RECONSTITUÉE", @@ -921,8 +921,8 @@ "many": "{acres} d'acres", "other": "{acres} acres" }, - "{percent}% contained": "maîtrisé à {percent} %", - "containment unknown": "maîtrise inconnue", + "{percent}% contained": "circonscrit à {percent} %", + "containment unknown": "part circonscrite inconnue", "{cause} cause": "cause : {cause}", "{personnel} personnel": { "one": "{personnel} intervenant", @@ -939,11 +939,11 @@ "Unnamed incident": "Incident sans nom", "Open {title} on InciWeb": "Ouvrir {title} sur InciWeb", "Perimeter source unavailable": "Source des périmètres indisponible", - "Not contained or unknown": "Non maîtrisé ou inconnu", - "Under 50% contained": "Maîtrisé à moins de 50 %", - "50–99% contained": "Maîtrisé à 50–99 %", - "Fully contained": "Entièrement maîtrisé", - "Colour shows reported containment. Perimeters are simplified to about 100 m.": "La couleur indique le niveau de maîtrise signalé. Les périmètres sont simplifiés à environ 100 m.", + "Not contained or unknown": "Non circonscrit ou inconnu", + "Under 50% contained": "Circonscrit à moins de 50 %", + "50–99% contained": "Circonscrit à 50–99 %", + "Fully contained": "Entièrement circonscrit", + "Colour shows reported containment. Perimeters are simplified to about 100 m.": "La couleur indique la part du périmètre déclarée circonscrite. Les périmètres sont simplifiés à environ 100 m.", "Malformed perimeter snapshot": "Instantané des périmètres mal formé", "radio tag|All": "Toutes", "News": "Actualités", @@ -1125,8 +1125,8 @@ "OpenFreeMap tiles timed out": "Délai dépassé pour les tuiles OpenFreeMap", "OpenFreeMap tiles unavailable": "Tuiles OpenFreeMap indisponibles", "occupancy|empty": "vide", - "occupancy|many seats available": "nombreuses places assises", - "occupancy|few seats available": "peu de places assises", + "occupancy|many seats available": "nombreuses places assises libres", + "occupancy|few seats available": "peu de places assises libres", "occupancy|standing room only": "places debout seulement", "occupancy|crushed standing room only": "bondé, places debout seulement", "occupancy|full": "complet", @@ -1184,7 +1184,7 @@ "Hidden by this map source · choose a globe map": "Masqué avec cette source de carte · choisissez une carte du globe", "Weather image HTTP {status}": "Image météo : HTTP {status}", "Weather HTTP {status}": "Météo : HTTP {status}", - "Frame unavailable; previous observation retained": "Image indisponible ; observation précédente conservée", + "Frame unavailable; previous observation retained": "Image indisponible ; précédente conservée", "Weather imagery unavailable": "Imagerie météo indisponible", "Weather source unavailable; previous observation retained": "Source météo indisponible ; observation précédente conservée", "Weather unavailable": "Météo indisponible", @@ -1217,7 +1217,7 @@ "Reduced motion · manual history available": "Animations réduites · historique parcourable manuellement", "Rain radar · US": "Radar de pluie · États-Unis", "Lightning density · 15 min": "Densité de foudre · 15 min", - "Satellite clouds": "Nuages satellite", + "Satellite clouds": "Nuages par satellite", "Americas + Pacific": "Amériques + Pacifique", "Global · 60°S–60°N": "Monde · 60°S–60°N", "North America": "Amérique du Nord", @@ -1231,11 +1231,11 @@ "Hourly global mosaic; usually 2–3 hours delayed": "Mosaïque mondiale horaire ; retard habituel de 2 à 3 heures", "GOES regional clouds; approximately 5-minute updates": "Nuages régionaux GOES ; mise à jour toutes les 5 minutes environ", "Clouds only": "Nuages seuls", - "Apply the full cloud brightness key; 100% filter strength": "Appliquer toute la clé de luminosité des nuages ; intensité du filtre 100 %", + "Apply the full cloud brightness key; 100% filter strength": "Appliquer pleinement le filtre de luminosité des nuages ; intensité du filtre 100 %", "Full": "Complète", "Show the complete infrared image; 0% filter strength": "Afficher l'image infrarouge complète ; intensité du filtre 0 %", - "Soft": "Douce", - "Vivid": "Vive", + "Soft": "Faible", + "Vivid": "Forte", "Image opacity; does not alter the observed values": "Opacité de l'image ; ne modifie pas les valeurs observées", "View US radar": "Voir le radar des États-Unis", "View Americas & Pacific": "Voir Amériques et Pacifique", @@ -1325,7 +1325,7 @@ "A location reading needs a loaded forecast and the Earth at the center of the view.": "Une lecture ponctuelle nécessite une prévision chargée et la Terre au centre de la vue.", "Interpolated model forecast on an approximately 1° grid. Broad weather patterns, not a street-level measurement.": "Prévision de modèle interpolée sur une grille d'environ 1°. Tendances météo générales, pas une mesure à l'échelle de la rue.", " · calm": " · calme", - " from {direction}": " de {direction}", + " from {direction}": " · secteur {direction}", "WIND AT {coordinates}": "VENT À {coordinates}", "{model} · valid {time}": "{model} · valide {time}", "Wind speed field unavailable": "Champ de vitesse du vent indisponible", @@ -1428,7 +1428,7 @@ "Upper Valley Collapse": "Effondrement dans la haute vallée", "Debris-Dammed Lake": "Lac de barrage formé par les débris", "Nepal-China Border Gate": "Poste frontière Népal-Chine", - "Timure Evidence Cluster": "Groupe d'éléments de preuve de Timure", + "Timure Evidence Cluster": "Groupe de preuves de Timure", "Syabru Besi Passage": "Passage à Syabru Besi", "Bidur / Trishuli Consequence": "Conséquences à Bidur / Trishuli", "Final view": "Vue finale", @@ -1597,14 +1597,14 @@ "FRAME · UNAVAILABLE": "IMAGE · INDISPONIBLE", "CALIBRATED": "CALIBRÉE", "CURATED": "SÉLECTIONNÉE", - "RAW PRIOR": "VALEUR BRUTE", + "RAW PRIOR": "ESTIM. INITIALE", "CCTV ON": "CCTV ON", "CCTV OFF": "CCTV OFF", "VIEWSHED ON": "ZONE VISIBLE ON", "COVERAGE ON": "COUVERTURE ON", "COVERAGE OFF": "COUVERTURE OFF", - "AUTO HOP ON": "AUTO-SAUT ON", - "AUTO HOP OFF": "AUTO-SAUT OFF", + "AUTO HOP ON": "SAUT AUTO ON", + "AUTO HOP OFF": "SAUT AUTO OFF", "PROJECTION ON": "PROJECTION ON", "PROJECTION OFF": "PROJECTION OFF", "CAL · EDITED (UNSAVED)": "CAL · MODIFIÉE (NON ENREGISTRÉE)", @@ -1622,7 +1622,7 @@ "many": "{count} de caméras chargées · activer CCTV pour les utiliser", "other": "{count} caméras chargées · activer CCTV pour les utiliser" }, - "Enable CCTV to load camera intersections": "Activez CCTV pour charger les intersections de caméras", + "Enable CCTV to load camera intersections": "Activez CCTV pour charger les carrefours équipés de caméras", "Enable CCTV to start camera-linked intelligence summaries.": "Activez CCTV pour lancer les résumés de renseignement liés aux caméras.", "No summary available.": "Aucun résumé disponible.", "loading frames": "chargement des images", @@ -1648,7 +1648,7 @@ "REGIONAL NEWS UNAVAILABLE": "ACTUS RÉGIONALES INDISPONIBLES", "RESOLVING REGION": "RÉSOLUTION DE LA RÉGION", "REGION UNAVAILABLE": "RÉGION INDISPONIBLE", - "NO RECENT LOCATION MATCHES": "AUCUNE CORRESPONDANCE RÉCENTE AU LIEU", + "NO RECENT LOCATION MATCHES": "AUCUNE ACTU RÉCENTE POUR CE LIEU", "{domain} · {age}": "{domain} · {age}", "{value} KM/H": "{value} KM/H", "CLOUD {pct}%": "NUAGES {pct} %", @@ -1685,7 +1685,7 @@ "LIVE TRACK": "PISTE EN DIRECT", "COMMERCIAL": "COMMERCIAL", "{aircraftClass} · {emergency} · {feedState}": "{aircraftClass} · {emergency} · {feedState}", - "{aircraftClass} · {feedState} · COURSE ALIGNED": "{aircraftClass} · {feedState} · CAP ALIGNÉ", + "{aircraftClass} · {feedState} · COURSE ALIGNED": "{aircraftClass} · {feedState} · ALIGNÉ SUR LA ROUTE", "ARROW · ESTIMATED DIRECTION": "FLÈCHE · DIRECTION ESTIMÉE", "ROUTE DATA UNAVAILABLE": "DONNÉES DE ROUTE INDISPONIBLES", "DEST {bearing}": "DEST {bearing}", @@ -1710,7 +1710,7 @@ "Expand briefing panel": "Développer le panneau de briefing", "OBSERVED / MAPPED PINGS": "PINGS OBSERVÉS / CARTOGRAPHIÉS", "SOURCE-BACKED EVENTS · NO SYNTHETIC NEWS": "ÉVÉNEMENTS SOURCÉS · AUCUNE ACTU SYNTHÉTIQUE", - "LATEST LOCATION-MATCHED REPORTING": "DERNIERS REPORTAGES SELON LE LIEU", + "LATEST LOCATION-MATCHED REPORTING": "DERNIÈRES ACTUS LIÉES AU LIEU", "{source} · LOCATION QUERY · RECENT": "{source} · REQUÊTE DE LIEU · RÉCENT", "LOCAL INFO": "INFOS LOCALES", "PLACE / CONDITIONS / POSITION": "LIEU / CONDITIONS / POSITION", @@ -1734,7 +1734,7 @@ "Restore real aircraft": "Restaurer l'aéronef réel", "Reclassify as TR-3B": "Reclasser en TR-3B", "TRACK ACQUIRED": "PISTE ACQUISE", - "{label} · COURSE {heading}°": "{label} · CAP {heading}°", + "{label} · COURSE {heading}°": "{label} · ROUTE {heading}°", "Context could not restore every layer; try again": "Le contexte n'a pas pu restaurer toutes les couches ; réessayez", "No selected data layers": "Aucune couche de données sélectionnée", "{count} data layers could not be cleared": { @@ -1843,7 +1843,7 @@ "Utilities": "Outils", "Other layers": "Autres couches", "{state} · {source}": "{state} · {source}", - "UNCERTAIN · {source} · lifecycle state requires reconciliation": "INCERTAIN · {source} · état du cycle de vie à réconcilier", + "UNCERTAIN · {source} · lifecycle state requires reconciliation": "INCERTAIN · {source} · état à rétablir", "{state} · {source} · {detail} · retry {seconds}s": "{state} · {source} · {detail} · nouvel essai {seconds} s", "{state} · {source} · {detail}": "{state} · {source} · {detail}", "never": "jamais", @@ -1960,10 +1960,10 @@ "Close compact Radio controls": "Fermer les commandes Radio compactes", "Open compact Radio controls": "Ouvrir les commandes Radio compactes", "SYNC": "SYNCHRO", - "RECONCILE": "RÉCONCILIER", + "RECONCILE": "RÉTABLIR", "DISABLE": "DÉSACTIVER", "ENABLE": "ACTIVER", - "Reconcile Radio — lifecycle uncertain": "Réconcilier la Radio — cycle de vie incertain", + "Reconcile Radio — lifecycle uncertain": "Rétablir la Radio — état incertain", "Disable Radio": "Désactiver la Radio", "Enable Radio": "Activer la Radio", "{category} ({count})": "{category} ({count})", @@ -2001,18 +2001,18 @@ " · muted during voice interaction": " · coupé pendant l'interaction vocale", " · restoring volume after voice": " · rétablissement du volume après la voix", " · static indicates no broadcaster audio": " · le grésillement indique l'absence de flux du diffuseur", - " · tuning static until broadcaster starts": " · grésillement de syntonisation jusqu'au démarrage du diffuseur", + " · tuning static until broadcaster starts": " · grésillement pendant le réglage, jusqu'au début de la diffusion", "Station unavailable after directory refresh — choose another channel": "Station indisponible après l'actualisation de l'annuaire — choisissez un autre canal", "Radio is enabling…": "Activation de la Radio…", "Radio is disabling…": "Désactivation de la Radio…", - "Radio lifecycle is uncertain — use Enable or Disable to reconcile": "Cycle de vie de la Radio incertain — utilisez Activer ou Désactiver pour réconcilier", - "Clear reading": "Effacer la lecture", + "Radio lifecycle is uncertain — use Enable or Disable to reconcile": "État de la Radio incertain — utilisez Activer ou Désactiver pour le rétablir", + "Clear reading": "Effacer le relevé", "Earlier observation": "Observation précédente", - "Observed history": "Historique observé", + "Observed history": "Historique des observations", "Later observation": "Observation suivante", "Latest": "Dernière", "Newest frame per product": "Image la plus récente par produit", - "Replay observed history": "Rejouer l'historique observé", + "Replay observed history": "Rejouer l'historique des observations", "Imagery on Esri · Google 3D returns when cleared": "Sur Esri · EFFACER rétablit Google 3D", "Point the camera at the ground to use the view": "Orientez la caméra vers le sol pour utiliser la vue", "That point cannot anchor a box": "Ce point ne peut pas ancrer une zone", @@ -2093,7 +2093,7 @@ "Download {slot} as a PNG": "Télécharger {slot} en PNG", "Download the image as a PNG": "Télécharger l'image en PNG", "Box {width} × {height} km": "Zone de {width} × {height} km", - "Acquired {time}": "Acquise le {time}", + "Acquired {time}": "Acquisition : {time}", "Coverage {coverage}": "Couverture {coverage}", "START HERE · {reason}": "COMMENCER ICI · {reason}", "Daily overview shows little detail in a box this small": "La vue quotidienne montre peu de détails dans une zone aussi petite", @@ -2321,7 +2321,7 @@ "Voice model tier — applies next session": "Niveau du modèle vocal — à la prochaine session", "STD": "STD", "Estimated session cost": "Coût estimé de la session", - "Voice control — activate to toggle voice; hold Space to speak": "Commande vocale — activez pour basculer la voix ; maintenez Space pour parler", + "Voice control — activate to toggle voice; hold Space to speak": "Commande vocale — activer/désactiver ; maintenez Space pour parler", "ON/OFF": "ON/OFF", "VOICE STANDBY": "VOIX EN VEILLE", "VOICE CONTROL": "COMMANDE VOCALE", @@ -2475,9 +2475,9 @@ "other": "{n} bus" }, "{n} bike share": { - "one": "{n} station de vélos en libre-service", - "many": "{n} de stations de vélos en libre-service", - "other": "{n} stations de vélos en libre-service" + "one": "{n} station de vélos partagés", + "many": "{n} de stations de vélos partagés", + "other": "{n} stations de vélos partagés" }, "{n} flock cameras": { "one": "{n} caméra LAPI", @@ -2528,7 +2528,7 @@ "{label} error": "{label} : erreur", "counted the first {returned} loaded records": "{returned} premiers enregistrements chargés comptés", "counted {returned} of {total} loaded records": "{returned} enregistrements chargés comptés sur {total}", - "{layers} just turned on — still loading, counts will rise": "{layers} : vient d'être activé — chargement en cours, les décomptes vont augmenter", + "{layers} just turned on — still loading, counts will rise": "{layers} : activation récente — chargement en cours, les décomptes vont augmenter", "Contacts panel snapshot at {time} — the same retained cohort supplies the card, speech, and follow-up memory": "Instantané du panneau Contacts ({time}) — le même groupe retenu alimente la fiche, la voix et la mémoire de suivi", "Contacts panel snapshot — the same retained cohort supplies the card, speech, and follow-up memory": "Instantané du panneau Contacts — le même groupe retenu alimente la fiche, la voix et la mémoire de suivi", "Fly below {km} km to a covered region": "Descendez sous {km} km au-dessus d'une région couverte", @@ -2544,7 +2544,7 @@ "unavailable": "indisponible", "Not answered: {layers}": "Sans réponse : {layers}", "Toggle voice control": "Activer/désactiver la commande vocale", - "Activate to toggle voice": "Activez pour basculer la voix", + "Activate to toggle voice": "Activer/désactiver la commande vocale", "Voice active": "Voix active", "Voice could not be started.": "Impossible de démarrer la voix.", "the active voice session": "la session vocale active", @@ -2701,7 +2701,7 @@ "GROUND SPEED · KTS": "VITESSE SOL · ND", "ALTITUDE · FT": "ALTITUDE · FT", "FIRST PERSON": "PREMIÈRE PERSONNE", - "LIVE TRACK · COURSE ALIGNED": "PISTE EN DIRECT · CAP ALIGNÉ", + "LIVE TRACK · COURSE ALIGNED": "PISTE EN DIRECT · ALIGNÉ SUR LA ROUTE", "Cockpit vision style": "Style de vision du cockpit", "Previous cockpit vision style": "Style de vision précédent du cockpit", "Previous vision style": "Style de vision précédent", @@ -2757,7 +2757,7 @@ "RADIO": "RADIO", "Cockpit compact Radio controls": "Commandes Radio compactes du cockpit", "Previous filtered radio station": "Station radio filtrée précédente", - "Play selected radio station": "Lire la station radio sélectionnée", + "Play selected radio station": "Écouter la station radio sélectionnée", "Next filtered radio station": "Station radio filtrée suivante", "VOLUME": "VOLUME", "Cockpit Radio volume": "Volume de la Radio du cockpit", @@ -2810,7 +2810,7 @@ "SEARCH NEARBY SITES": "CHERCHER SITES PROCHES", "Reclassify tracked contact as TR-3B": "Reclasser le contact suivi en TR-3B", "CONTACTS CONTEXT OFF": "CONTEXTE CONTACTS DÉSACTIVÉ", - "SELECT CONTACTS TO LOAD OBSERVED / MAPPED PROXIMITY": "CHOISIR CONTACTS POUR CHARGER LA PROXIMITÉ OBSERVÉE / CARTOGRAPHIÉE", + "SELECT CONTACTS TO LOAD OBSERVED / MAPPED PROXIMITY": "CHOISIR CONTACTS POUR VOIR LES CONTACTS PROCHES OBSERVÉS / CARTOGRAPHIÉS", "Available Space Missions": "Missions spatiales disponibles", "AVAILABLE MISSIONS": "MISSIONS DISPONIBLES", "SELECT A MISSION TO INSPECT": "CHOISIR UNE MISSION À EXAMINER", @@ -2821,13 +2821,13 @@ "Filter stations by station tag": "Filtrer les stations par tag de station", "All": "Tous", "Enable Radio, then choose a globe marker or use next.": "Activez la Radio, puis choisissez un marqueur sur le globe ou utilisez SUIV.", - "DRAG TO TUNE": "GLISSER POUR SYNTONISER", + "DRAG TO TUNE": "GLISSER POUR RÉGLER", "Tune available internet radio stations": "Écouter les stations de radio Internet disponibles", - "ALL · DRAG THE NEEDLE": "TOUTES · GLISSEZ L'AIGUILLE", + "ALL · DRAG THE NEEDLE": "TOUTES · DÉPLACER L'AIGUILLE", "SNAPS TO AVAILABLE STATIONS": "SE CALE SUR LES STATIONS DISPONIBLES", "Radio playback": "Lecture radio", "Previous filtered station": "Station filtrée précédente", - "Play selected station": "Lire la station sélectionnée", + "Play selected station": "Écouter la station sélectionnée", "Next filtered station": "Station filtrée suivante", "STOP": "ARRÊT", "Stop radio playback": "Arrêter la lecture radio", @@ -2887,7 +2887,7 @@ "World-overlay fade distance outside the keyhole as a percentage of its radius": "Distance de fondu de la surcouche hors de l'ouverture, en pourcentage de son rayon", "Outside": "Extérieur", "Detection opacity outside the keyhole": "Opacité de la détection hors de l'ouverture", - "World-overlay label and card opacity beyond the fade distance": "Opacité des étiquettes et cartes de la surcouche au-delà de la distance de fondu", + "World-overlay label and card opacity beyond the fade distance": "Opacité des étiquettes et fiches de la surcouche au-delà de la distance de fondu", "PARAMETERS": "PARAMÈTRES", "3D aircraft — flat icons zoomed out, 3D models up close": "Aéronefs 3D — icônes plates de loin, modèles 3D de près", "Models": "Modèles", @@ -2931,7 +2931,7 @@ "Initializing photorealistic world...": "Initialisation du monde photoréaliste…", "DATA LAYERS": "COUCHES", "ACQUIRING FRAME": "ACQUISITION DE L'IMAGE", - "NEAREST": "PROCHE", + "NEAREST": "LA PLUS PROCHE", "CCTV camera": "Caméra CCTV", "CALIBRATION": "CALIBRATION", "Drag the camera in the world: rings rotate, arrows move, handles set range/FOV": "Faites glisser la caméra dans le monde : les anneaux pivotent, les flèches déplacent, les poignées règlent portée/FOV", @@ -2979,7 +2979,7 @@ "GROUND STATION · PROVIDER SETTINGS": "STATION AU SOL · PARAMÈTRES DES FOURNISSEURS", "Close key setup": "Fermer la configuration des clés", "Power up the globe": "Allumer le globe", - "The globe already flies keyless. Every key below switches on another real feed — paste one and it's saved into this app's local configuration, then the server restarts itself. Server-side keys stay on this machine; Google Maps and Cesium ion run in the browser and must be provider-restricted. Keys you configured elsewhere are shown but never touched.": "Le globe fonctionne déjà sans clé. Chaque clé ci-dessous active un flux réel de plus : collez-en une et elle est enregistrée dans la configuration locale de l'application, puis le serveur redémarre. Les clés côté serveur restent sur cette machine ; Google Maps et Cesium ion s'exécutent dans le navigateur et doivent être restreintes au fournisseur. Les clés configurées ailleurs sont affichées mais jamais modifiées.", + "The globe already flies keyless. Every key below switches on another real feed — paste one and it's saved into this app's local configuration, then the server restarts itself. Server-side keys stay on this machine; Google Maps and Cesium ion run in the browser and must be provider-restricted. Keys you configured elsewhere are shown but never touched.": "Le globe fonctionne déjà sans clé. Chaque clé ci-dessous active un flux réel de plus : collez-en une et elle est enregistrée dans la configuration locale de l'application, puis le serveur redémarre. Les clés côté serveur restent sur cette machine ; les clés Google Maps et Cesium ion sont utilisées dans le navigateur et doivent être restreintes chez leur fournisseur. Les clés configurées ailleurs sont affichées mais jamais modifiées.", "SAVE KEYS": "ENREGISTRER LES CLÉS", "ESC to close": "ESC pour fermer", "The Google Maps key buys the photorealistic planet — everything else stacks on top.": "La clé Google Maps offre la planète photoréaliste, tout le reste s'y superpose.", diff --git a/src/scenes/recipes.js b/src/scenes/recipes.js index ba3940a57..0bb1d9e94 100644 --- a/src/scenes/recipes.js +++ b/src/scenes/recipes.js @@ -1069,17 +1069,29 @@ export function displaySceneTitle(scene) { export function displayShotTitle(title, shot = undefined, scene = undefined) { const text = typeof title === 'string' ? title : ''; const fromRecipe = shot - ? Boolean(shot.sourcePackId) || recipeDeclaresShotTitle(scene?.id, text) + ? Boolean(shot.sourcePackId) || recipeDeclaresShotTitle(scene, text) : true; if (fromRecipe && BUILTIN_SHOT_TITLES.has(text)) return t(text); const numbered = /^Shot ([1-9]\d*)$/.exec(text); return numbered ? t('Shot {n}', { n: numbered[1] }) : text; } -/** Whether the built-in recipe behind a scene declares a shot with this title. */ -function recipeDeclaresShotTitle(sceneId, title) { - const recipe = sceneId ? getSceneRecipeById(sceneId) : null; - return Boolean( - recipe?.cameraPath?.some((keyframe) => keyframe?.title === title), +/** + * Whether the built-in recipe behind a scene, or a shot pack applied to it, + * declares a shot with this title. A pack's legacy bootstrap rebuilds the + * first shots of an upgraded scene without a sourcePackId, so the pack's + * required titles vouch for them. + */ +function recipeDeclaresShotTitle(scene, title) { + const recipe = scene?.id ? getSceneRecipeById(scene.id) : null; + if (recipe?.cameraPath?.some((keyframe) => keyframe?.title === title)) + return true; + const packs = Array.isArray(scene?.appliedShotPacks) + ? scene.appliedShotPacks + : []; + return packs.some((entry) => + Boolean( + getSceneAppendRecipeById(entry?.id)?.requiredShotTitles?.includes(title), + ), ); } diff --git a/src/scenes/sceneTitleDisplay.test.mjs b/src/scenes/sceneTitleDisplay.test.mjs index 604e01c49..fae4abbd6 100644 --- a/src/scenes/sceneTitleDisplay.test.mjs +++ b/src/scenes/sceneTitleDisplay.test.mjs @@ -4,6 +4,7 @@ import test from 'node:test'; import assert from 'node:assert/strict'; import { + SCENE_APPEND_RECIPES, SCENE_RECIPES, displaySceneTitle, displayShotTitle, @@ -87,6 +88,28 @@ test('a built-in shot title localizes only for a recipe-sourced shot', () => { } }); +test('a shot rebuilt by an applied pack bootstrap localizes its built-in title', () => { + const pack = SCENE_APPEND_RECIPES.find( + (recipe) => recipe.requiredShotTitles?.length, + ); + if (!pack) return; + setLocale('ru'); + const title = pack.requiredShotTitles[0]; + const shot = { id: 'shot-bootstrap', title }; + // The legacy bootstrap rebuilds these shots without a sourcePackId; the + // scene's applied-pack marker vouches for them. + assert.equal( + displayShotTitle(title, shot, { + id: 'scene-upgraded', + appliedShotPacks: [{ id: pack.id, version: pack.version }], + }), + displayShotTitle(title), + ); + assert.notEqual(displayShotTitle(title), title); + // The same title in a scene without that pack stays as typed. + assert.equal(displayShotTitle(title, shot, { id: 'scene-user' }), title); +}); + test('the Scene status line shows an operator-typed shot title as typed', async () => { const { createScenePlaybackAdapter } = await import('./playbackAdapter.js'); const statuses = []; From 5e47a2afbdb5a66a86929cc1e0252555d8d2d2d5 Mon Sep 17 00:00:00 2001 From: German Khokhlov Date: Wed, 28 Oct 2026 17:02:55 +0400 Subject: [PATCH 24/83] i18n(it): apply review round 1 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Three-model review (astra, sol, fable): 53 findings accepted, 14 rejected or deferred. Fixes the meaning of "Downed aircraft", "Compilation", the satellite ground-distance caveat and the browser-key restriction note; agreement for Full, Provider Settings and Space Missions; fork directions that compose with every modifier; a radio aria label that reads as a phrase; imperative tooltips. Shortens the labels that clipped: ESP. A/B, search placeholder, QUOTA · FT, PREC, Esri imagery note. Co-Authored-By: Claude Opus 5.5 --- docs/translations/it.md | 12 +++- src/i18n/locales/it.json | 120 +++++++++++++++++----------------- src/i18n/same-as-english.json | 1 + 3 files changed, 70 insertions(+), 63 deletions(-) diff --git a/docs/translations/it.md b/docs/translations/it.md index 155c0e563..3b7bd2ec7 100644 --- a/docs/translations/it.md +++ b/docs/translations/it.md @@ -10,12 +10,13 @@ Translation source: abiyeenzo (#912). - Sentence case, not Title Case: "Live Flights" → «Voli live», "Space Missions" → «Missioni spaziali». UPPERCASE English stays UPPERCASE: «LIVE», «NON DISPONIBILE». - Quotes inside Italian text are straight double quotes: «Eliminare lo scatto "{shot}"?». Use the accented capitals (È, À) in UPPERCASE text: «VELOCITÀ», «CITTÀ». - Errors read as a statement, not a past participle on its own: "Search failed" → «Ricerca non riuscita»; "Could not …" → «Impossibile …». A dash that joins a cause and a hint becomes a colon: «Chiave API rifiutata: controlla AISSTREAM_API_KEY». -- Short labels, chips and HUD readouts stay short. A standard abbreviation with a period beats a wrapped line: REGOLAZ., RILEV., INCL., ALT., VEL., STIM.; PREC / SUCC for PREV / NEXT. -- The HUD codes HDG, BRG, CRS, FOV and DEST stay in English, as in cockpit avionics. RANGE is «PORTATA». Words used in a sentence are translated: heading → «prua» (aircraft) or «direzione» (camera), course → «rotta». +- Short labels, chips and HUD readouts stay short. A standard abbreviation with a period beats a wrapped line: REGOLAZ., RILEV., INCL., ALT., VEL., STIM., PROIEZ., ESP.; PREC / SUCC for PREV / NEXT and PREVIOUS / NEXT. +- The HUD codes HDG, BRG, CRS, FOV and DEST stay in English, as in cockpit avionics. RANGE is «PORTATA». Words used in a sentence are translated: heading → «prua» (aircraft, ships) or «direzione» (camera, buses, trams, trains), course → «rotta». - Keyboard keys stay in English: Space, Enter, Esc, Tab, Shift, Backspace, H, 1–9 («Tieni premuto Space per parlare», «Premi Enter per riprovare»). - Decimal comma in numbers written in the text: «28,2710° N». Numbers formatted by the code follow `Intl` and need nothing. - Units: km, m, km/h, m/s, kn (knots), ft (feet), h, min, s; in UPPERCASE text KM, KM/S, KT, FT, MIN, H. "m" is always metres, so minutes are «min» («5 min fa»). MW stays MW. `°` and `%` stay. - "ago" goes after the time: «{count} min fa». When a placeholder already holds a localized "ago" text (`{age}`, `{ago}`), do not add «fa» again. +- A feature name used as a sentence subject gets a head noun so the verb agrees: «La modalità Missioni spaziali isola…», «Il pannello Impostazioni provider è disattivato…». - English loanwords that Italian UIs use as they are stay in English: feed, live, cockpit, briefing, preset, overlay, layout, snapshot, tile, provider, timeout, payload, bloom, scope. ## Plurals @@ -36,7 +37,7 @@ The `many` form is the `other` text with «di» after the number when a noun fol | --------------------------------------------- | ------------------------------------------------------------ | | layer / data layer | livello / livello dati | | feed / source / data source | feed / fonte / fonte dati | -| LIVE (status) / live data | LIVE / dati live | +| LIVE (status) / live data / live (feed state) | LIVE / dati live / live | | SIMULATED | SIMULATO | | stale / degraded / unavailable | obsoleto / degradato / non disponibile | | retry / retrying | riprova / nuovo tentativo | @@ -78,6 +79,11 @@ The `many` form is the `other` text with «di» after the number when a noun fol | Recent Imagery | Immagini recenti | | Global Context / Context (panel) | Contesto globale / Contesto | | heading, course / altitude / ground speed | prua, rotta / altitudine / velocità al suolo (VEL. AL SUOLO) | +| altitude in short HUD captions / Alt unknown | QUOTA (QUOTA · FT) / Quota sconosciuta | +| fallback (FALLBACK, Street View fallback) | riserva / di riserva (SUPERFICIE DI RISERVA) | +| forecast track / advisory center (cyclones) | traccia prevista / centro del ciclone da bollettino | +| witness source / authored (scene) | fonte testimoniale / predefinito, definito dall'autore | +| explore manually | esplora manualmente | | HDG / BRG / CRS / FOV / DEST | HDG / BRG / CRS / FOV / DEST (unchanged) | | RANGE / PITCH / HGT (CCTV calibration) | PORTATA / INCL. / ALT. | | PREV / NEXT | PREC / SUCC | diff --git a/src/i18n/locales/it.json b/src/i18n/locales/it.json index 8618f52a2..7afaa6335 100644 --- a/src/i18n/locales/it.json +++ b/src/i18n/locales/it.json @@ -26,7 +26,7 @@ "Loading the keyless globe...": "Caricamento del globo senza chiave...", "Google 3D Tiles unavailable ({detail}). Loading the keyless globe...": "Google 3D Tiles non disponibile ({detail}). Caricamento del globo senza chiave...", "Initializing systems...": "Inizializzazione dei sistemi...", - "Space Missions isolates replay data. Exit the mode to enable {layer}.": "Missioni spaziali isola i dati del replay. Esci dalla modalità per attivare {layer}.", + "Space Missions isolates replay data. Exit the mode to enable {layer}.": "La modalità Missioni spaziali isola i dati del replay. Esci dalla modalità per attivare {layer}.", "Data attribution": "Attribuzione dei dati", "Data provided by:": "Dati forniti da:", "Close data attribution": "Chiudi le attribuzioni dei dati", @@ -43,13 +43,13 @@ "General emergency": "Emergenza generale", "Unlawful interference": "Interferenza illecita", "Radio failure": "Avaria radio", - "Downed aircraft": "Aeromobile abbattuto", + "Downed aircraft": "Aereo precipitato", "Minimum fuel": "Carburante minimo", "Lifeguard (medical priority)": "Lifeguard (priorità medica)", "Rasuwagadhi witness video": "Video del testimone a Rasuwagadhi", "Bhote Koshi valley footage": "Riprese della valle del Bhote Koshi", "Flood footage": "Riprese dell'alluvione", - "Compilation and casualty claims": "Compilazione e dichiarazioni sulle vittime", + "Compilation and casualty claims": "Raccolta di video e dichiarazioni sulle vittime", "SOURCE GEOCONFIRMED · WORLD-PINNED": "FONTE GEOCONFERMATA · ANCORATA AL MONDO", "SOURCE CREDITED · LOCATION UNRESOLVED": "FONTE CITATA · POSIZIONE NON RISOLTA", "REFERENCE ONLY · CLAIMS UNVERIFIED": "SOLO RIFERIMENTO · DICHIARAZIONI NON VERIFICATE", @@ -91,8 +91,8 @@ "Facebook embed unavailable": "Incorporamento di Facebook non disponibile", "AUTOPLAY BLOCKED · USE PROVIDER CONTROLS": "AUTOPLAY BLOCCATO · USA I CONTROLLI DEL PROVIDER", "Embedded {provider} media for {source}": "Contenuto {provider} incorporato per {source}", - "witness source": "fonte testimone", - "Witness source": "Fonte testimone", + "witness source": "fonte testimoniale", + "Witness source": "Fonte testimoniale", "{provider} · EMBEDDED SOURCE": "{provider} · FONTE INCORPORATA", "OPEN ORIGINAL ↗": "APRI L'ORIGINALE ↗", "{provider} media: {source}": "Contenuto {provider}: {source}", @@ -169,7 +169,7 @@ "other": "{count} FONTI" }, "OUTSIDE IMAGERY SWIPE": "FUORI DAL CONFRONTO IMMAGINI", - "{scene} / AUTHORED SHOT": "{scene} / SCATTO D'AUTORE", + "{scene} / AUTHORED SHOT": "{scene} / SCATTO PREDEFINITO", "NEPAL FLOOD INCIDENT": "ALLUVIONE IN NEPAL", "Play {shot}": "Riproduci {shot}", "current scene shot": "scatto della scena attuale", @@ -194,7 +194,7 @@ "PLACES": "LUOGHI", "Introduce the reconstruction scene key places from trigger to downstream": "Presenta i luoghi chiave della scena ricostruita, dall'innesco fino a valle", "PATH": "PERCORSO", - "Animate the sourced cyan river-centerline route to Trishuli Bazaar": "Anima il percorso ciano lungo l'asse del fiume, da fonti, fino a Trishuli Bazaar", + "Animate the sourced cyan river-centerline route to Trishuli Bazaar": "Anima il percorso ciano documentato dalle fonti lungo l'asse del fiume fino a Trishuli Bazaar", "OVERVIEW": "PANORAMICA", "Keep the completed flood path and location labels visible": "Mantieni visibili il percorso completo dell'alluvione e le etichette dei luoghi", "RECORD": "REGISTRO", @@ -308,7 +308,7 @@ "Live earthquakes and active fires, from USGS and NASA": "Terremoti e incendi attivi in tempo reale, da USGS e NASA", "It feels like a forbidden cockpit—then you realize the sources are public and the data is real.": "Sembra un cockpit proibito, poi capisci che le fonti sono pubbliche e i dati sono reali.", "Working…": "Operazione in corso…", - "Could not open that mission{detail}. Retry or explore manually.": "Impossibile aprire quella missione{detail}. Riprova o esplora a mano.", + "Could not open that mission{detail}. Retry or explore manually.": "Impossibile aprire quella missione{detail}. Riprova o esplora manualmente.", "This browser is blocking storage, so that could not be saved.": "Questo browser blocca l'archiviazione, quindi non è stato possibile salvare.", "NORMAL": "NORMALE", "CRT": "CRT", @@ -318,7 +318,7 @@ "NOIR": "NOIR", "SNOW": "NEVE", "ARCTIC": "ARTICO", - "ANTARCTIC": "ANTARTIDE", + "ANTARCTIC": "ANTARTICO", "NORTH AMERICA": "NORD AMERICA", "SOUTH AMERICA": "SUD AMERICA", "EUROPE": "EUROPA", @@ -343,7 +343,7 @@ "REC": "REC", "AIS: --": "AIS: --", "N/A": "N/D", - "{mode} {band} {locality} | {region} | ALT {alt} | WINDOW {window} | SUN {sun}° | ONA {ona}° | {zone}": " {mode} {band} {locality} | {region} | ALT {alt} | FINESTRA {window} | SOLE {sun}° | ONA {ona}° | {zone}", + "{mode} {band} {locality} | {region} | ALT {alt} | WINDOW {window} | SUN {sun}° | ONA {ona}° | {zone}": "{mode} {band} {locality} | {region} | ALT {alt} | FINESTRA {window} | SOLE {sun}° | ONA {ona}° | {zone}", "NEAR {poi} ({city}) {distance}": "VICINO A {poi} ({city}) {distance}", "SECTOR {lat} {lon}": "SETTORE {lat} {lon}", "hemisphere|N": "N", @@ -356,11 +356,11 @@ "other": "ACCENDI · {count} CHIAVI IN ATTESA" }, "POWERED UP": "ACCESO", - "Provider Settings does not answer proxied requests": "Impostazioni provider non risponde alle richieste tramite proxy", - "Provider Settings is disabled while sharing is enabled": "Impostazioni provider è disattivato mentre la condivisione è attiva", - "Provider Settings answers only the machine running the server": "Impostazioni provider risponde solo alla macchina su cui gira il server", - "Provider Settings answers only local hostnames": "Impostazioni provider risponde solo a nomi host locali", - "Provider Settings requires an exact local Origin": "Impostazioni provider richiede un'Origin locale esatta", + "Provider Settings does not answer proxied requests": "Il pannello Impostazioni provider non risponde alle richieste tramite proxy", + "Provider Settings is disabled while sharing is enabled": "Il pannello Impostazioni provider è disattivato mentre la condivisione è attiva", + "Provider Settings answers only the machine running the server": "Il pannello Impostazioni provider risponde solo alla macchina su cui gira il server", + "Provider Settings answers only local hostnames": "Il pannello Impostazioni provider risponde solo a nomi host locali", + "Provider Settings requires an exact local Origin": "Il pannello Impostazioni provider richiede un'Origin locale esatta", "Unrecognized Origin refused": "Origin non riconosciuta rifiutata", "Cross-origin requests are refused": "Le richieste cross-origin sono rifiutate", "Content-Type must be application/json": "Content-Type deve essere application/json", @@ -423,7 +423,7 @@ "Remove this key from your saved configuration?": "Rimuovere questa chiave dalla configurazione salvata?", "Removed from {store}. Restarting — this page reloads itself.": "Rimosso ({store}). Riavvio in corso: questa pagina si ricarica da sola.", "The photorealistic 3D planet, place search + Street View": "Il pianeta 3D fotorealistico, ricerca luoghi + Street View", - "Places context + Street View fallback; optional separate key": "Contesto luoghi + fallback Street View; chiave separata opzionale", + "Places context + Street View fallback; optional separate key": "Contesto luoghi + Street View di riserva; chiave separata opzionale", "Voice control — API key or ChatGPT OAuth": "Controllo vocale: chiave API o ChatGPT OAuth", "Gemini Live voice control": "Controllo vocale Gemini Live", "Live ships, worldwide": "Navi live, in tutto il mondo", @@ -494,7 +494,7 @@ "Focus {label}": "Focus su {label}", "Global Context navigation": "Navigazione Contesto globale", "Previous — prior visited contact in the 250 km window": "Precedente — contatto visitato in precedenza nella finestra di 250 km", - "PREVIOUS": "PRECEDENTE", + "PREVIOUS": "PREC", "FOCUS": "FOCUS", "Next — nearest unvisited contact in the 250 km window": "Successivo — contatto non visitato più vicino nella finestra di 250 km", "NEXT": "SUCC", @@ -534,8 +534,8 @@ "COVERAGE {value}km²": "COPERTURA {value}km²", "OVERLAP {count} cams": "SOVRAPP. {count} cam", "ISOLATED VIEW": "VISTA ISOLATA", - "PROJ MONITOR": "PROIEZ MONITOR", - "PROJ OFF": "PROIEZ OFF", + "PROJ MONITOR": "PROIEZ. MONITOR", + "PROJ OFF": "PROIEZ. OFF", "VIEWSHED": "VIEWSHED", "CAL {value}": "CAL {value}", "SRC {value}": "FONTE {value}", @@ -572,7 +572,7 @@ "Official advisory ↗": "Bollettino ufficiale ↗", "Active NHC and CPHC cyclone advisories": "Bollettini attivi sui cicloni di NHC e CPHC", "Wind unavailable": "Vento non disponibile", - "Advisory center / forecast track": "Centro del bollettino / traccia prevista", + "Advisory center / forecast track": "Centro del ciclone da bollettino / traccia prevista", "Center-track uncertainty cone": "Cono di incertezza della traccia del centro", "Select a storm on the map, or choose a storm in the list to select it and move the camera. Click empty map space to clear the selection. NOAA NHC/CPHC advisory context. The cone describes forecast center-track uncertainty, not storm size or the full hazard area. Forecast point labels are source lead hours, not times computed from advisory issuance. Geometry follows the surface; height is not weather altitude. Consult the official advisory.": "Seleziona una tempesta sulla mappa, o scegline una nell'elenco per selezionarla e spostare la camera. Fai clic su un punto vuoto della mappa per annullare la selezione. Contesto dai bollettini NOAA NHC/CPHC. Il cono descrive l'incertezza prevista sulla traccia del centro, non le dimensioni della tempesta né l'intera area di pericolo. Le etichette dei punti di previsione sono le ore di anticipo della fonte, non orari calcolati dall'emissione del bollettino. La geometria segue la superficie; l'altezza non è la quota meteorologica. Consulta il bollettino ufficiale.", "DRIVE": "AUTO", @@ -597,8 +597,8 @@ "direction|sharply right": "nettamente a destra", "direction|straight": "dritto", "direction|around": "in senso opposto", - "fork direction|left": "la sinistra", - "fork direction|right": "la destra", + "fork direction|left": "a sinistra", + "fork direction|right": "a destra", "fork direction|slightly left": "leggermente a sinistra", "fork direction|slightly right": "leggermente a destra", "fork direction|sharply left": "nettamente a sinistra", @@ -634,8 +634,8 @@ "At the end of the road, turn {direction}": "Alla fine della strada, svolta {direction}", "At the end of the road, continue onto {road}": "Alla fine della strada, prosegui su {road}", "At the end of the road, continue": "Alla fine della strada, prosegui", - "Keep {direction} at the fork onto {road}": "Al bivio, tieni {direction} verso {road}", - "Keep {direction} at the fork": "Al bivio, tieni {direction}", + "Keep {direction} at the fork onto {road}": "Al bivio, prosegui {direction} verso {road}", + "Keep {direction} at the fork": "Al bivio, prosegui {direction}", "Continue at the fork onto {road}": "Al bivio, prosegui verso {road}", "Continue at the fork": "Al bivio, prosegui", "Merge {direction} onto {road}": "Immettiti {direction} su {road}", @@ -773,7 +773,7 @@ "Retrying automatically at {time} UTC": "Nuovo tentativo automatico alle {time} UTC", "Retrying automatically after provider cooldown": "Nuovo tentativo automatico dopo la pausa del provider", "Updates automatically after pan or zoom and once a minute. The public feed covers a 250-nautical-mile circle around the view centre; zooming out does not make it a worldwide snapshot. Blank cells are outside sampled coverage or have insufficient observations.": "Si aggiorna automaticamente dopo uno spostamento o uno zoom e una volta al minuto. Il feed pubblico copre un cerchio di 250 miglia nautiche attorno al centro della vista; allontanare lo zoom non lo rende un'istantanea mondiale. Le celle vuote sono fuori dalla copertura campionata o hanno osservazioni insufficienti.", - "Low-accuracy score = 100 × max(0, bad − 1) / total: one aircraft is discounted, so this is not the raw share. Cells need {aircraft} aircraft over {minutes} minutes. Navigation-integrity anomalies are not a detection of jamming or spoofing.": "Indice di bassa precisione = 100 × max(0, anomali − 1) / totale: un aereo viene scontato, quindi non è la quota grezza. Le celle richiedono {aircraft} aerei in {minutes} minuti. Le anomalie di integrità della navigazione non indicano un rilevamento di jamming o spoofing.", + "Low-accuracy score = 100 × max(0, bad − 1) / total: one aircraft is discounted, so this is not the raw share. Cells need {aircraft} aircraft over {minutes} minutes. Navigation-integrity anomalies are not a detection of jamming or spoofing.": "Indice di bassa precisione = 100 × max(0, anomali − 1) / totale: dal conteggio degli aerei anomali si sottrae un aereo, quindi non è la percentuale grezza. Le celle richiedono {aircraft} aerei in {minutes} minuti. Le anomalie di integrità della navigazione non costituiscono un rilevamento di jamming o spoofing.", "GNSS snapshot needs a view anchor": "Lo snapshot GNSS richiede un punto di riferimento della vista", "GNSS feed rate limited (HTTP 429)": "Limite di richieste del feed GNSS raggiunto (HTTP 429)", "Malformed GNSS integrity snapshot": "Snapshot di integrità GNSS non valido", @@ -939,8 +939,8 @@ "Unnamed incident": "Incidente senza nome", "Open {title} on InciWeb": "Apri {title} su InciWeb", "Perimeter source unavailable": "Fonte dei perimetri non disponibile", - "Not contained or unknown": "Non contenuto o sconosciuto", - "Under 50% contained": "Contenuto meno del 50%", + "Not contained or unknown": "Non contenuto o dato non disponibile", + "Under 50% contained": "Contenuto sotto il 50%", "50–99% contained": "Contenuto al 50–99%", "Fully contained": "Completamente contenuto", "Colour shows reported containment. Perimeters are simplified to about 100 m.": "Il colore indica il contenimento riportato. I perimetri sono semplificati a circa 100 m.", @@ -950,7 +950,7 @@ "Talk": "Talk", "Weather / Emergency": "Meteo / Emergenza", "Public Safety": "Sicurezza pubblica", - "Aviation / Marine": "Aviazione / Marina", + "Aviation / Marine": "Aviazione / Nautica", "Traffic / Transit": "Traffico / Trasporti", "Music": "Musica", "Other": "Altro", @@ -1038,7 +1038,7 @@ "No street-level imagery within {radius} m of the view centre": "Nessuna immagine a livello stradale entro {radius} m dal centro della vista", "Zoom in to see street-level coverage": "Ingrandisci per vedere la copertura a livello stradale", "Point the camera at the ground for street-level coverage": "Punta la camera verso il suolo per la copertura a livello stradale", - "Coverage tile failed": "Tile di copertura non riuscito", + "Coverage tile failed": "Caricamento del tile di copertura non riuscito", "The photo could not be loaded": "Impossibile caricare la foto", "{name} photo. ← and → step along the sequence. On a 360° photo, drag or use Shift+← →, ↑ ↓ to look around, and + − to zoom": "Foto {name}. ← e → scorrono la sequenza. Su una foto a 360°, trascina o usa Shift+← →, ↑ ↓ per guardarti intorno, e + − per lo zoom", "{name} street-level photo": "Foto a livello stradale {name}", @@ -1139,7 +1139,7 @@ "Waiting for update": "In attesa di aggiornamento", "Moving": "In movimento", "reported {speed} km/h": "{speed} km/h riportati", - "reported hdg {heading}°": "prua {heading}° riportata", + "reported hdg {heading}°": "direzione {heading}° riportata", "Last report: stopped at stop {stop}": "Ultimo rapporto: fermo alla fermata {stop}", "Last report: arriving at stop {stop}": "Ultimo rapporto: in arrivo alla fermata {stop}", "Last report: next stop {stop}": "Ultimo rapporto: prossima fermata {stop}", @@ -1232,7 +1232,7 @@ "GOES regional clouds; approximately 5-minute updates": "Nuvole regionali GOES; aggiornamenti circa ogni 5 minuti", "Clouds only": "Solo nuvole", "Apply the full cloud brightness key; 100% filter strength": "Applica l'intera scala di luminosità delle nuvole; intensità del filtro 100%", - "Full": "Completo", + "Full": "Completa", "Show the complete infrared image; 0% filter strength": "Mostra l'intera immagine all'infrarosso; intensità del filtro 0%", "Soft": "Tenue", "Vivid": "Vivido", @@ -1280,7 +1280,7 @@ "Reduced motion": "Movimento ridotto", "Resume": "Riprendi", "Pause": "Pausa", - "Pause visual flow; forecast time does not advance with animation": "Mette in pausa il flusso visivo; l'ora della previsione non avanza con l'animazione", + "Pause visual flow; forecast time does not advance with animation": "Metti in pausa il flusso visivo; l'ora della previsione non avanza con l'animazione", "None": "Nessuno", "Speed": "Velocità", "Pressure": "Pressione", @@ -1480,7 +1480,7 @@ "Apply details": "Applica i dettagli", "Select a scene first": "Seleziona prima una scena", "Share selected scene": "Condividi la scena selezionata", - "Scene JSON preserves authored settings and attribution. It does not include asset files. Bundles include only pack files you choose here or previously imported bundle files.": "Il JSON della scena conserva le impostazioni d'autore e l'attribuzione. Non include i file delle risorse. I pacchetti includono solo i file dei pacchetti dati scelti qui o i file di pacchetti importati in precedenza.", + "Scene JSON preserves authored settings and attribution. It does not include asset files. Bundles include only pack files you choose here or previously imported bundle files.": "Il JSON della scena conserva le impostazioni definite dall'autore e l'attribuzione. Non include i file delle risorse. I pacchetti includono solo i file dei pacchetti dati scelti qui o i file di pacchetti importati in precedenza.", "Download scene JSON": "Scarica il JSON della scena", "Choose data-pack files": "Scegli i file del pacchetto dati", "Or choose a data-pack folder": "Oppure scegli una cartella del pacchetto dati", @@ -1515,7 +1515,7 @@ "FM signal found at {mhz} MHz": "Segnale FM trovato a {mhz} MHz", "No FM signal found": "Nessun segnale FM trovato", "Browser location is unavailable": "La posizione del browser non è disponibile", - "Receiver location was not granted": "Posizione del ricevitore non concessa", + "Receiver location was not granted": "Accesso alla posizione del ricevitore non concesso", "RTL-SDR disconnected": "RTL-SDR disconnesso", "Upstream response too large": "Risposta del servizio upstream troppo grande", "Vector tile request timed out": "La richiesta dei tile vettoriali è andata in timeout", @@ -1622,7 +1622,7 @@ "many": "{count} di telecamere caricate · attiva CCTV per attivarle", "other": "{count} telecamere caricate · attiva CCTV per attivarle" }, - "Enable CCTV to load camera intersections": "Attiva CCTV per caricare gli incroci delle telecamere", + "Enable CCTV to load camera intersections": "Attiva CCTV per caricare le telecamere agli incroci", "Enable CCTV to start camera-linked intelligence summaries.": "Attiva CCTV per avviare i riepiloghi intelligence collegati alle telecamere.", "No summary available.": "Nessun riepilogo disponibile.", "loading frames": "caricamento fotogrammi", @@ -1643,7 +1643,7 @@ "CYCLE ON": "CICLO ON", "CYCLE OFF": "CICLO OFF", "Stop automatic page cycling. Previous, Next, and the SIG/NEWS/LOCAL tabs stay available.": "Ferma lo scorrimento automatico delle pagine. Precedente, Successiva e le schede SIG/NOTIZIE/LOCALE restano disponibili.", - "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.": "Scorre automaticamente le pagine del briefing ogni 9 secondi (Segnali → Notizie → Locale). Si mette in pausa quando passi sul pannello o lo selezioni. I dati dei segnali live si aggiornano comunque di continuo.", + "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.": "Scorri automaticamente le pagine del briefing ogni 9 secondi (Segnali → Notizie → Locale). Lo scorrimento si interrompe quando passi sul pannello o lo selezioni. I dati dei segnali live si aggiornano comunque di continuo.", "ACQUIRING REGIONAL NEWS": "ACQUISIZIONE NOTIZIE REGIONALI", "REGIONAL NEWS UNAVAILABLE": "NOTIZIE REGIONALI NON DISPONIBILI", "RESOLVING REGION": "RISOLUZIONE REGIONE", @@ -1652,7 +1652,7 @@ "{domain} · {age}": "{domain} · {age}", "{value} KM/H": "{value} KM/H", "CLOUD {pct}%": "NUVOLE {pct}%", - "CLOUD UNKNOWN": "NUVOLE SCONOSCIUTE", + "CLOUD UNKNOWN": "NUVOLE N/D", "{source} · LOCATION QUERY": "{source} · QUERY PER POSIZIONE", "REGIONAL NEWS": "NOTIZIE REGIONALI", "{label} · {radius} AIR/SEA WINDOW": "{label} · ARIA/MARE {radius}", @@ -1680,7 +1680,7 @@ "ADS-B EMERGENCY · {status}": "EMERGENZA ADS-B · {status}", "AIRCRAFT": "AEREO", "ACQUIRING SURFACE": "ACQUISIZIONE SUPERFICIE", - "SURFACE FALLBACK": "FALLBACK SUPERFICIE", + "SURFACE FALLBACK": "SUPERFICIE DI RISERVA", "STALE FEED": "FEED OBSOLETO", "LIVE TRACK": "TRACCIA LIVE", "COMMERCIAL": "COMMERCIALE", @@ -1698,7 +1698,7 @@ "Anime": "Anime", "Noir": "Noir", "Snow": "Neve", - "Current cockpit vision style: {style}. Activate for next style.": "Stile di visione del cockpit attuale: {style}. Attiva per lo stile successivo.", + "Current cockpit vision style: {style}. Activate for next style.": "Stile di visione attuale del cockpit: {style}. Attiva per lo stile successivo.", "Current style: {style} — click for next": "Stile attuale: {style} — clic per il successivo", "Collapse Contact panel": "Comprimi il pannello Contatto", "Expand Contact panel": "Espandi il pannello Contatto", @@ -1804,7 +1804,7 @@ "Live AIS Vessels": "Navi AIS live", "Mapped Installations": "Installazioni mappate", "Global Context": "Contesto globale", - "Datacenters": "Data Center", + "Datacenters": "Data center", "Dams": "Dighe", "Submarine Cables": "Cavi sottomarini", "FIRMS Active Fires": "Incendi attivi FIRMS", @@ -1869,7 +1869,7 @@ "running": "in esecuzione", "suspended": "sospeso", "closed": "chiuso", - "feed status|live": "in diretta", + "feed status|live": "live", "feed status|stale": "obsoleto", "feed status|unreachable": "irraggiungibile", "feed status|invalid": "non valido", @@ -1980,7 +1980,7 @@ "PLAY": "PLAY", "selected": "selezionata", "nearest": "più vicina", - "{action} {target} radio station": "{action} stazione radio {target}", + "{action} {target} radio station": "{action}: stazione radio {target}", "RADIO STATE UNCERTAIN": "STATO RADIO INCERTO", "SYNCING DIRECTORY": "SINCRONIZZAZIONE ELENCO", "RADIO READY": "RADIO PRONTA", @@ -2013,7 +2013,7 @@ "Latest": "Più recente", "Newest frame per product": "Fotogramma più recente per prodotto", "Replay observed history": "Rivedi lo storico osservato", - "Imagery on Esri · Google 3D returns when cleared": "Immagini su Esri · Google 3D torna dopo la cancellazione", + "Imagery on Esri · Google 3D returns when cleared": "Immagini su Esri · Google 3D torna con CANCELLA", "Point the camera at the ground to use the view": "Punta la camera verso il suolo per usare la vista", "That point cannot anchor a box": "Quel punto non può ancorare un riquadro", "Imagery stops at ±{limit}° latitude": "Le immagini si fermano a ±{limit}° di latitudine", @@ -2088,7 +2088,7 @@ "Source off": "Fonte disattivata", "Unpin {slot}": "Sblocca {slot}", "Unpin the image": "Sblocca l'immagine", - "EXPORT {slot}": "ESPORTA {slot}", + "EXPORT {slot}": "ESP. {slot}", "EXPORT": "ESPORTA", "Download {slot} as a PNG": "Scarica {slot} come PNG", "Download the image as a PNG": "Scarica l'immagine come PNG", @@ -2261,7 +2261,7 @@ "Open {names} at the centre of the view": "Apri {names} al centro della vista", "Zoom in to a street to open {names} here": "Ingrandisci su una strada per aprire {names} qui", "Switch Street Level on to draw its coverage.": "Attiva Vista stradale per disegnarne la copertura.", - "Every provider is switched off: light a chip to draw its coverage.": "Tutti i provider sono disattivati: accendi un chip per disegnarne la copertura.", + "Every provider is switched off: light a chip to draw its coverage.": "Tutti i provider sono disattivati: attivane uno per visualizzarne la copertura.", "Loading this sequence…": "Caricamento di questa sequenza…", "{n} images in this sequence · Esc clears": { "one": "{n} immagine in questa sequenza · Esc cancella", @@ -2521,7 +2521,7 @@ "last 24 h": "ultime 24 h", "past 30 d and upcoming": "ultimi 30 g e prossimi", "the flights layer loads by viewport": "il livello voli si carica per vista", - "distance is ground distance, not overhead": "la distanza è al suolo, non in linea d'aria", + "distance is ground distance, not overhead": "la distanza è misurata al suolo fino al punto subsatellitare, non fino al satellite", "the count is a lower bound because at least one layer reached its retained limit.": "il conteggio è un limite inferiore perché almeno un livello ha raggiunto il suo limite di conservazione.", "{label} off": "{label} disattivato", "{label} loading": "{label} in caricamento", @@ -2570,7 +2570,7 @@ "{layer} is enabled on the {source} feed, but no airborne aircraft is loaded in the {place} view yet": "{layer} è attivo sul feed {source}, ma nessun aereo in volo è ancora caricato nella vista di {place}", "{layer} is enabled, but no airborne aircraft is loaded in the {place} view yet": "{layer} è attivo, ma nessun aereo in volo è ancora caricato nella vista di {place}", "{layer} is enabled, but its aircraft feed is unavailable": "{layer} è attivo, ma il suo feed di aerei non è disponibile", - "{layer} is enabled, but its destination refresh did not complete": "{layer} è attivo, ma l'aggiornamento delle destinazioni non è stato completato", + "{layer} is enabled, but its destination refresh did not complete": "{layer} è attivo, ma l'aggiornamento nel luogo di destinazione non è stato completato", "{layer} is enabled, but {source} is unavailable": "{layer} è attivo, ma {source} non è disponibile", "Could not arrive at {place}": "Impossibile arrivare a {place}", "{name} is no longer loaded": "{name} non è più caricato", @@ -2623,7 +2623,7 @@ "{origin} to {destination}": "Da {origin} a {destination}", "from {origin}": "da {origin}", "to {destination}": "a {destination}", - "Registration {registration}": "Immatricolazione {registration}", + "Registration {registration}": "Matricola {registration}", "View state": "Stato della vista", "Marked {count} places": { "one": "Segnato {count} luogo", @@ -2634,7 +2634,7 @@ "Not found: {places}": "Non trovati: {places}", "Tracing outlines": "Tracciamento dei contorni", "Frame flights": "Inquadra i voli", - "Frame military": "Inquadra i militari", + "Frame military": "Inquadra i voli militari", "Frame vessels": "Inquadra le navi", "Frame {target}": "Inquadra {target}", "Zoom out to globe": "Allontana fino al globo", @@ -2665,7 +2665,7 @@ "Fly to {place}": "Vola su {place}", "Fly to Location": "Vola sul luogo", "Nearest aircraft to {place}": "Aereo più vicino a {place}", - "Nearest aircraft to Here": "Aereo più vicino a qui", + "Nearest aircraft to Here": "Aereo più vicino a questo punto", "Layer on": "Livello attivato", "Layer off": "Livello disattivato", "Zoom out": "Allontana", @@ -2693,22 +2693,22 @@ "Recent speech": "Parlato recente", "HERE": "QUI", "Aircraft cockpit view": "Vista cockpit dell'aereo", - "LEVEL": "LIVELLO", + "LEVEL": "ORIZZONTE", "Estimated destination direction": "Direzione stimata della destinazione", "DEST ---°": "DEST ---°", "OPTICAL PLANE · 01": "PIANO OTTICO · 01", "VISOR LOCK · ACTIVE": "BLOCCO VISIERA · ATTIVO", "GROUND SPEED · KTS": "VEL. AL SUOLO · KTS", - "ALTITUDE · FT": "ALTITUDINE · FT", + "ALTITUDE · FT": "QUOTA · FT", "FIRST PERSON": "PRIMA PERSONA", "LIVE TRACK · COURSE ALIGNED": "TRACCIA LIVE · ROTTA ALLINEATA", "Cockpit vision style": "Stile di visione del cockpit", - "Previous cockpit vision style": "Stile di visione del cockpit precedente", + "Previous cockpit vision style": "Stile di visione precedente del cockpit", "Previous vision style": "Stile di visione precedente", - "Current cockpit vision style: NORMAL. Activate for next style.": "Stile di visione del cockpit attuale: NORMALE. Attiva per lo stile successivo.", + "Current cockpit vision style: NORMAL. Activate for next style.": "Stile di visione attuale del cockpit: NORMALE. Attiva per lo stile successivo.", "Current style: NORMAL — click for next": "Stile attuale: NORMALE — clic per il successivo", "CURRENT": "ATTUALE", - "Next cockpit vision style": "Stile di visione del cockpit successivo", + "Next cockpit vision style": "Stile di visione successivo del cockpit", "Next vision style": "Stile di visione successivo", "Current aircraft heading": "Prua attuale dell'aereo", "GROUND SPEED": "VEL. AL SUOLO", @@ -2778,7 +2778,7 @@ "Simulate FLIR-style thermal contrast. Turn up Ironbow for color.": "Simula il contrasto termico in stile FLIR. Alza Ironbow per il colore.", "Apply bright cel-shaded color and illustrated outlines.": "Applica colori vivaci cel-shaded e contorni illustrati.", "Apply high-contrast monochrome film-noir grading.": "Applica un color grading noir monocromatico ad alto contrasto.", - "Add a cold, snowy whiteout treatment to the scene.": "Aggiunge alla scena un effetto freddo di nevicata e whiteout.", + "Add a cold, snowy whiteout treatment to the scene.": "Aggiungi alla scena un effetto freddo di nevicata e whiteout.", "MAP SOURCE": "FONTE MAPPA", "Map source": "Fonte mappa", "Style": "Stile", @@ -2786,9 +2786,9 @@ "Collapse panel": "Comprimi pannello", "Pin location tray": "Fissa il pannello posizione", "Keep location tray open": "Mantieni aperto il pannello posizione", - "Search any location": "Cerca un luogo qualsiasi", + "Search any location": "Cerca un luogo", "Search location by name or coordinates": "Cerca un luogo per nome o coordinate", - "Search any location...": "Cerca un luogo qualsiasi...", + "Search any location...": "Cerca un luogo...", "WEATHER": "METEO", "Active weather products": "Prodotti meteo attivi", "RECENT IMAGERY": "IMMAGINI RECENTI", @@ -2979,7 +2979,7 @@ "GROUND STATION · PROVIDER SETTINGS": "STAZIONE A TERRA · IMPOSTAZIONI PROVIDER", "Close key setup": "Chiudi la configurazione delle chiavi", "Power up the globe": "Accendi il globo", - "The globe already flies keyless. Every key below switches on another real feed — paste one and it's saved into this app's local configuration, then the server restarts itself. Server-side keys stay on this machine; Google Maps and Cesium ion run in the browser and must be provider-restricted. Keys you configured elsewhere are shown but never touched.": "Il globo funziona già senza chiavi. Ogni chiave qui sotto attiva un altro feed reale: incollane una e verrà salvata nella configurazione locale di questa app, poi il server si riavvia da solo. Le chiavi lato server restano su questa macchina; Google Maps e Cesium ion funzionano nel browser e vanno limitate al provider. Le chiavi configurate altrove vengono mostrate ma mai modificate.", + "The globe already flies keyless. Every key below switches on another real feed — paste one and it's saved into this app's local configuration, then the server restarts itself. Server-side keys stay on this machine; Google Maps and Cesium ion run in the browser and must be provider-restricted. Keys you configured elsewhere are shown but never touched.": "Il globo funziona già senza chiavi. Ogni chiave qui sotto attiva un altro feed reale: incollane una e verrà salvata nella configurazione locale di questa app, poi il server si riavvia da solo. Le chiavi lato server restano su questa macchina; le chiavi di Google Maps e Cesium ion vengono usate nel browser e richiedono restrizioni configurate presso il provider. Le chiavi configurate altrove vengono mostrate ma mai modificate.", "SAVE KEYS": "SALVA CHIAVI", "ESC to close": "ESC per chiudere", "The Google Maps key buys the photorealistic planet — everything else stacks on top.": "La chiave Google Maps sblocca il pianeta fotorealistico: tutto il resto si aggiunge sopra.", @@ -2997,7 +2997,7 @@ "LIVE CONTACTS": "CONTATTI LIVE", "Aircraft, vessels and nearby intelligence": "Aerei, navi e intelligence nelle vicinanze", "Launches, spacecraft and orbital context": "Lanci, veicoli spaziali e contesto orbitale", - "EXPLORE MANUALLY": "ESPLORA A MANO", + "EXPLORE MANUALLY": "ESPLORA MANUALMENTE", "Begin with a clean globe": "Inizia con un globo pulito", "Don't show this again": "Non mostrare più", "ESC to dismiss": "ESC per chiudere", diff --git a/src/i18n/same-as-english.json b/src/i18n/same-as-english.json index be8a06f0c..81a6d1cc2 100644 --- a/src/i18n/same-as-english.json +++ b/src/i18n/same-as-english.json @@ -260,6 +260,7 @@ "World", "audio {state}", "dB", + "feed status|live", "ft", "hPa", "installation class|BASE", From 7a18e0093b78127eb5afe7c82c98baa30e843697 Mon Sep 17 00:00:00 2001 From: German Khokhlov Date: Wed, 28 Oct 2026 17:08:36 +0400 Subject: [PATCH 25/83] i18n(uk): apply review round 1 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Fix meaning errors flagged by the three-model review: downed aircraft (Аварія літака), fast jet, the straight-ahead lane, road traffic, pilot vessel, nearby contact counts, the low-accuracy score. - Terms: CRS/TRK → ШК (шляховий кут), ascent → виведення, booster flight → ПОЛІТ, session → сеанс, sequence → послідовність, place search → пошук місця, CCTV pitch → нахил, mapped sites → нанесені обʼєкти everywhere; glossary updated. - Grammar: case agreement in the radio aria label and the key-store message, «прицілу», у/в euphony, payload count after a colon, FIRES as ПОЖ. so any count reads correctly. - The cockpit current-style button widens to fit ЗВИЧАЙНИЙ; other languages keep the 58px minimum. Co-Authored-By: Claude Opus 5.5 --- docs/translations/uk.md | 95 ++++++++++-------- src/i18n/locales/uk.json | 204 +++++++++++++++++++------------------- src/ui/styles/cockpit.css | 3 +- 3 files changed, 155 insertions(+), 147 deletions(-) diff --git a/docs/translations/uk.md b/docs/translations/uk.md index cd90b7b01..765be0233 100644 --- a/docs/translations/uk.md +++ b/docs/translations/uk.md @@ -30,47 +30,54 @@ A `tn()` entry needs four forms. `Intl.PluralRules('uk')` picks: ## Glossary -| English | Українська | -| ------------------------------------------ | ---------------------------------------------------- | -| layer / data layer | шар / шар даних | -| feed | потік даних (short: потік) | -| source / data source | джерело / джерело даних | -| LIVE (status) / live data | ОНЛАЙН / у реальному часі | -| SIMULATED / SYNTHETIC | ІМІТАЦІЯ | -| stale / degraded / unavailable | застарів / з перебоями (chip: ПЕРЕБОЇ) / недоступний | -| retry | повтор | -| key (API key) / POWER UP | ключ / ЗАПУСК | -| Provider Settings / provider | Налаштування постачальників / постачальник | -| globe / map / map source / basemap | глобус / карта / джерело карти / підкладка | -| aircraft / flight / military flights | літак (short HUD: борт) / рейс / військові рейси | -| vessel, ship / vessels | судно / судна (gen. pl. суден) | -| satellite | супутник | -| launch (rocket) / space mission | запуск / космічна місія | -| contact / tracking | контакт / стеження | -| installation, site / mapped | обʼєкт / нанесений на карту | -| camera / CCTV camera | камера / камера CCTV | -| earthquake / active fire / fire perimeter | землетрус / активна пожежа / контур пожежі | -| advisory (NHC/CPHC cyclone) | зведення | -| scene / shot / scene recipe | сцена / кадр / рецепт сцени | -| briefing / panel / dock | брифінг / панель / док | -| preset / visual preset | пресет / візуальний пресет | -| Scope (circular viewport mask) | приціл | -| overlay (detection overlay) | накладка | -| heading / altitude / ground speed | курс / висота / шляхова швидкість | -| HDG / BRG / CRS / FOV / DEST / SPD / RANGE | КУРС / ПЕЛ. / ШЛЯХ / ОГЛЯД / ПРИЗН. / ШВИД / ДАЛЬН. | -| Street View (Google) | Перегляд вулиць (as in Ukrainian Google Maps) | -| Street Level (layer) | Вуличні знімки | -| imagery / recent imagery | знімки / свіжі знімки | -| radar reflectivity / lightning density | радіолокаційна відбивність / щільність блискавок | -| infrared | інфрачервоний (short: ІЧ) | -| receiver / gain / decoder | приймач / підсилення / декодер | -| broadcaster | мовник | -| CONUS, WHOT/BHOT, Ironbow, CRT, NVG, FLIR | без перекладу | -| PREV / NEXT (HUD) / Previous / Next | ПОПЕР. / ДАЛІ / Попередній / Наступний | -| anchor / data pack / bundle (scene) | якір / пакет даних / архів | -| box (Recent Imagery area) | область | -| camera move | переліт | -| SIG / NEWS / LOCAL (briefing tabs) | СИГН. / НОВИНИ / МІСЦ. | -| compass points (N, NNE, NE, …) | Пн, ПнПнСх, ПнСх, … | -| L / R (relative bearing) | Л / П | -| click / tap | клацнути / натиснути | +| English | Українська | +| ----------------------------------------------- | ---------------------------------------------------------------- | +| layer / data layer | шар / шар даних | +| feed | потік даних (short: потік) | +| source / data source | джерело / джерело даних | +| LIVE (status) / live data | ОНЛАЙН / у реальному часі | +| SIMULATED / SYNTHETIC | ІМІТАЦІЯ | +| stale / degraded / unavailable | застарів / з перебоями (chip: ПЕРЕБОЇ) / недоступний | +| retry | повтор | +| key (API key) / POWER UP | ключ / ЗАПУСК | +| Provider Settings / provider | Налаштування постачальників / постачальник | +| globe / map / map source / basemap | глобус / карта / джерело карти / підкладка | +| aircraft / flight / military flights | літак (short HUD: борт) / рейс / військові рейси | +| vessel, ship / vessels | судно / судна (gen. pl. суден) | +| satellite | супутник | +| launch (rocket) / space mission | запуск / космічна місія | +| ascent (rocket) / booster FLIGHT {n} | виведення / ПОЛІТ {n} (not рейс) | +| contact / tracking | контакт / стеження | +| installation, site / mapped | обʼєкт / нанесений на карту | +| camera / CCTV camera | камера / камера CCTV | +| earthquake / active fire / fire perimeter | землетрус / активна пожежа / контур пожежі | +| advisory (NHC/CPHC cyclone) | зведення | +| scene / shot / scene recipe | сцена / кадр / рецепт сцени | +| briefing / panel / dock | брифінг / панель / док | +| preset / visual preset | пресет / візуальний пресет | +| Scope (circular viewport mask) | приціл | +| overlay (detection overlay) | накладка | +| heading / altitude / ground speed | курс / висота / шляхова швидкість | +| HDG / BRG / CRS, TRK / FOV / DEST / SPD / RANGE | КУРС / ПЕЛ. / ШК (шляховий кут) / ОГЛЯД / ПРИЗН. / ШВИД / ДАЛЬН. | +| Street View (Google) | Перегляд вулиць (as in Ukrainian Google Maps) | +| Street Level (layer) | Вуличні знімки | +| imagery / recent imagery | знімки / свіжі знімки | +| radar reflectivity / lightning density | радіолокаційна відбивність / щільність блискавок | +| infrared | інфрачервоний (short: ІЧ) | +| receiver / gain / decoder | приймач / підсилення / декодер | +| broadcaster | мовник | +| CONUS, WHOT/BHOT, Ironbow, CRT, NVG, FLIR | без перекладу | +| PREV / NEXT (HUD) / Previous / Next | ПОПЕР. / ДАЛІ / Попередній / Наступний | +| anchor / data pack / bundle (scene) | якір / пакет даних / архів | +| box (Recent Imagery area) | область | +| camera move | переліт | +| SIG / NEWS / LOCAL (briefing tabs) | СИГН. / НОВИНИ / МІСЦ. | +| compass points (N, NNE, NE, …) | Пн, ПнПнСх, ПнСх, … | +| L / R (relative bearing) | Л / П | +| click / tap | клацнути / натиснути | +| session (voice, OAuth) | сеанс | +| sequence (street-level photos) | послідовність | +| search (place search) | пошук місця | +| pitch (CCTV camera pose) | нахил | +| traffic (road traffic layer) | дорожній рух | +| phosphor (CRT) | люмінофор | diff --git a/src/i18n/locales/uk.json b/src/i18n/locales/uk.json index bc98109cf..6467d0996 100644 --- a/src/i18n/locales/uk.json +++ b/src/i18n/locales/uk.json @@ -38,13 +38,13 @@ "Widebody": "Широкофюзеляжний літак", "Four-engine jet": "Чотиримоторний реактивний літак", "Helicopter": "Гелікоптер", - "Fast jet": "Високоманеврений літак", + "Fast jet": "Швидкісний реактивний літак", "Business jet": "Бізнес-джет", "Drone": "Безпілотник", "General emergency": "Загальна аварійна ситуація", "Unlawful interference": "Незаконне втручання", "Radio failure": "Відмова радіозвʼязку", - "Downed aircraft": "Вимушена посадка", + "Downed aircraft": "Аварія літака", "Minimum fuel": "Мінімальний залишок пального", "Lifeguard (medical priority)": "Санітарний рейс (медичний пріоритет)", "Rasuwagadhi witness video": "Відео очевидця в Rasuwagadhi", @@ -255,7 +255,7 @@ "Mapped sites loaded": "Нанесені обʼєкти завантажено", "Military airfield": "Військовий аеродром", "Naval base": "Військово-морська база", - "Firing range": "Стрільбище", + "Firing range": "Полігон", "Military land": "Військова територія", "Mapped installation": "Обʼєкт на карті", "Military area": "Військова зона", @@ -270,7 +270,7 @@ "Directions": "Маршрути", "Recent imagery": "Свіжі знімки", "STATION": "СТАНЦІЇ", - "Crewed stations and their visiting vehicles": "Пілотовані станції та кораблі відвідування", + "Crewed stations and their visiting vehicles": "Пілотовані станції та кораблі, що їх відвідують", "NAV": "НАВ", "GNSS navigation — GPS, GLONASS, Galileo": "Навігація GNSS — GPS, GLONASS, Galileo", "GEO": "ГЕО", @@ -286,7 +286,7 @@ "MILITARY": "ВІЙСЬКОВЕ", "SAILING": "ВІТРИЛЬНЕ", "PLEASURE": "ПРОГУЛКОВЕ", - "PILOT": "ЛОЦМАН", + "PILOT": "ЛОЦМАНСЬКЕ", "SAR": "РЯТУВАЛЬНЕ", "TUG": "БУКСИР", "PORT TENDER": "ПОРТОВИЙ КАТЕР", @@ -391,8 +391,8 @@ "VOICE AUTH · API KEY": "ГОЛОС: КЛЮЧ API", "USE API KEY": "ВИКОРИСТАТИ КЛЮЧ API", "USE CHATGPT OAUTH": "ВИКОРИСТАТИ CHATGPT OAUTH", - "Use OPENAI_API_KEY for the next cloud voice session": "Використати OPENAI_API_KEY для наступної хмарної голосової сесії", - "Use the signed-in local ChatGPT/Codex OAuth session for the next cloud voice session": "Використати локальну OAuth-сесію ChatGPT/Codex, у яку виконано вхід, для наступної хмарної голосової сесії", + "Use OPENAI_API_KEY for the next cloud voice session": "Використати OPENAI_API_KEY для наступного хмарного голосового сеансу", + "Use the signed-in local ChatGPT/Codex OAuth session for the next cloud voice session": "Використати локальний OAuth-сеанс ChatGPT/Codex, у який виконано вхід, для наступного хмарного голосового сеансу", "Metered — a billing-enabled account": "Платний — потрібен обліковий запис з увімкненою оплатою", "Optional paid token — public access works without one": "Необовʼязковий платний токен — публічний доступ працює без нього", "Free key — register, paste, done": "Безкоштовний ключ — зареєструйтеся, вставте, готово", @@ -413,8 +413,8 @@ "Saving…": "Збереження…", "Save failed: {detail}": "Не вдалося зберегти: {detail}", "Paste at least one key first.": "Спочатку вставте принаймні один ключ.", - "Saved to {store}. Restarting — this page reloads itself.": "Збережено в {store}. Перезапуск — сторінка перезавантажиться сама.", - "Cloud voice will use OPENAI_API_KEY on the next session.": "Наступна хмарна голосова сесія використовуватиме OPENAI_API_KEY.", + "Saved to {store}. Restarting — this page reloads itself.": "Збережено до {store}. Перезапуск — сторінка перезавантажиться сама.", + "Cloud voice will use OPENAI_API_KEY on the next session.": "Наступний хмарний голосовий сеанс використовуватиме OPENAI_API_KEY.", "Checking local ChatGPT OAuth sign-in…": "Перевірка локального входу в ChatGPT через OAuth…", "Could not check ChatGPT sign-in.": "Не вдалося перевірити вхід у ChatGPT.", "ChatGPT OAuth selected for cloud voice. Your API key stays saved and available.": "Для хмарного голосу вибрано ChatGPT OAuth. Ваш ключ API залишається збереженим і доступним.", @@ -423,7 +423,7 @@ "Could not start ChatGPT sign-in on this machine.": "Не вдалося почати вхід у ChatGPT на цьому компʼютері.", "Finish ChatGPT sign-in in the browser. Waiting for it to complete…": "Завершіть вхід у ChatGPT у браузері. Очікування завершення…", "ChatGPT sign-in timed out. Click {button} to try again.": "Час на вхід у ChatGPT минув. Натисніть «{button}», щоб спробувати ще раз.", - "ChatGPT sign-in complete. OAuth will be used for the next cloud voice session.": "Вхід у ChatGPT виконано. У наступній хмарній голосовій сесії використовуватиметься OAuth.", + "ChatGPT sign-in complete. OAuth will be used for the next cloud voice session.": "Вхід у ChatGPT виконано. У наступному хмарному голосовому сеансі використовуватиметься OAuth.", "Remove this key from your saved configuration?": "Видалити цей ключ із вашої збереженої конфігурації?", "Removed from {store}. Restarting — this page reloads itself.": "Видалено з {store}. Перезапуск — сторінка перезавантажиться сама.", "The photorealistic 3D planet, place search + Street View": "Фотореалістична 3D-планета, пошук місць + Перегляд вулиць", @@ -432,7 +432,7 @@ "Gemini Live voice control": "Голосове керування через Gemini Live", "Live ships, worldwide": "Судна в реальному часі по всьому світу", "Live active-fire detections": "Виявлення активних пожеж у реальному часі", - "Real live traffic (keyless runs a simulation)": "Справжні затори в реальному часі (без ключа — імітація)", + "Real live traffic (keyless runs a simulation)": "Дорожній рух у реальному часі (без ключа — імітація)", "Bing imagery map stacks + world terrain": "Знімки Bing + рельєф світу", "More flight-polling credits (anonymous works without)": "Вищий ліміт запитів рейсів (анонімно працює й без ключа)", "Street-level imagery and coverage in the Street Level layer. Free: register an app in the Mapillary developer dashboard and paste its Client Token": "Вуличні знімки й покриття в шарі «Вуличні знімки». Безкоштовно: зареєструйте застосунок у панелі розробника Mapillary і вставте його клієнтський токен (Client Token)", @@ -515,7 +515,7 @@ "HDG {value}°": "КУРС {value}°", "BRG {value}°": "ПЕЛ. {value}°", "BRG —": "ПЕЛ. —", - "CRS {value}°": "ШЛЯХ {value}°", + "CRS {value}°": "ШК {value}°", "CURRENT VIEWPORT ONLY": "ЛИШЕ ПОТОЧНА ОБЛАСТЬ ОГЛЯДУ", "WITHIN {km} KM": "У РАДІУСІ {km} КМ", "Flights": "Рейси", @@ -559,7 +559,7 @@ "Subtropical storm": "Субтропічний шторм", "Subtropical depression": "Субтропічна депресія", "Track and cone match this advisory": "Трек і конус відповідають цьому зведенню", - "Track/cone awaiting advisory {number}": "Трек і конус зʼявляться зі зведенням № {number}", + "Track/cone awaiting advisory {number}": "Очікуються трек і конус для зведення № {number}", "Track/cone unavailable": "Трек/конус недоступні", "Cached advisory · stale source": "Зведення з кешу · джерело застаріло", "Loading advisories…": "Завантаження зведень…", @@ -582,7 +582,7 @@ "Wind unavailable": "Вітер: немає даних", "Advisory center / forecast track": "Центр циклону за зведенням / прогнозний трек", "Center-track uncertainty cone": "Конус невизначеності треку центру", - "Select a storm on the map, or choose a storm in the list to select it and move the camera. Click empty map space to clear the selection. NOAA NHC/CPHC advisory context. The cone describes forecast center-track uncertainty, not storm size or the full hazard area. Forecast point labels are source lead hours, not times computed from advisory issuance. Geometry follows the surface; height is not weather altitude. Consult the official advisory.": "Виберіть шторм на карті або в списку, щоб виділити його й перемістити до нього камеру. Клацніть на порожньому місці карти, щоб зняти виділення. Контекст зведень NOAA NHC/CPHC. Конус описує невизначеність прогнозного треку центру, а не розмір шторму чи всю зону небезпеки. Підписи прогнозних точок — завчасність джерела в годинах, а не час, розрахований від випуску зведення. Геометрія повторює поверхню; висота не відображає висоту погодних явищ. Звіряйтеся з офіційним зведенням.", + "Select a storm on the map, or choose a storm in the list to select it and move the camera. Click empty map space to clear the selection. NOAA NHC/CPHC advisory context. The cone describes forecast center-track uncertainty, not storm size or the full hazard area. Forecast point labels are source lead hours, not times computed from advisory issuance. Geometry follows the surface; height is not weather altitude. Consult the official advisory.": "Виберіть шторм на карті або в списку, щоб виділити його й перемістити до нього камеру. Клацніть на порожньому місці карти, щоб зняти виділення. Контекст зведень NOAA NHC/CPHC. Конус описує невизначеність прогнозного треку центру, а не розмір шторму чи всю зону небезпеки. Підписи прогнозних точок показують завчасність прогнозу в годинах за даними джерела, а не час, розрахований від випуску зведення. Геометрія повторює поверхню; висота не відображає висоту погодних явищ. Звіряйтеся з офіційним зведенням.", "DRIVE": "АВТО", "Drive": "Автомобілем", "WALK": "ПІШКИ", @@ -618,7 +618,7 @@ "lane direction|slightly right": "праву", "lane direction|sharply left": "крайню ліву", "lane direction|sharply right": "крайню праву", - "lane direction|straight": "середню", + "lane direction|straight": "призначену для руху прямо", "ordinal|{number}st": "{number}-й", "ordinal|{number}nd": "{number}-й", "ordinal|{number}rd": "{number}-й", @@ -710,7 +710,7 @@ "Then: {instruction}": "Потім: {instruction}", "No route found between A and B": "Маршрут між A і B не знайдено", "Routing failed: {error}": "Не вдалося побудувати маршрут: {error}", - "Routing timed out": "Минув час побудови маршруту", + "Routing timed out": "Минув час очікування маршруту", "Routing unavailable — no response from the routing service": "Побудова маршруту недоступна — сервіс маршрутизації не відповідає", "Earthquake source unavailable": "Джерело даних про землетруси недоступне", "Focus fire detection {title}, {details}": "Фокус на виявленні пожежі {title}, {details}", @@ -722,9 +722,9 @@ "NIGHT": "НІЧ", "▲ {frp} MW": "▲ {frp} МВт", "FIRE": "ПОЖЕЖА", - "FIRES": "ПОЖЕЖІ", + "FIRES": "ПОЖ.", "max {value} MW": "макс. {value} МВт", - "new {value}": "нова {value}", + "new {value}": "останнє: {value} тому", "{value}°N": "{value}° пн. ш.", "{value}°S": "{value}° пд. ш.", "{value}°E": "{value}° сх. д.", @@ -746,11 +746,11 @@ "LIVE · updated {age}": "ОНЛАЙН · оновлено {age}", "Source snapshot time unavailable": "Час знімка джерела невідомий", "Live data unavailable": "Дані в реальному часі недоступні", - "Intel Picture": "Розвідкартина", - "Kinetic 30d": "Бойові 30 дн", + "Intel Picture": "Розвідувальна обстановка", + "Kinetic 30d": "Бойові дії, 30 дн", "Border Crisis": "Криза на кордоні", - "Iran Picture": "Іран: картина", - "Iran Kinetic": "Іран: бойові", + "Iran Picture": "Іран: обстановка", + "Iran Kinetic": "Іран: бойові дії", "Yemen FLOT": "Ємен: лінія фронту", "Latest Drop": "Новий випуск", "GhostMaps file could not be read": "Не вдалося прочитати файл GhostMaps", @@ -775,15 +775,15 @@ }, "S2 Underground publishes these KMZ products to GitHub. New uploads are detected within seconds and replace the previous edition automatically. Click a marker for its report.": "S2 Underground публікує ці продукти KMZ на GitHub. Нові файли виявляються за лічені секунди й автоматично замінюють попередній випуск. Клацніть мітку, щоб відкрити її зведення.", "Malformed GhostMaps catalog": "Пошкоджений каталог GhostMaps", - "Low-accuracy score < 2%": "Частка неточних < 2%", - "Low-accuracy score 2–10%": "Частка неточних 2–10%", - "Low-accuracy score > 10%": "Частка неточних > 10%", + "Low-accuracy score < 2%": "Показник неточності < 2%", + "Low-accuracy score 2–10%": "Показник неточності 2–10%", + "Low-accuracy score > 10%": "Показник неточності > 10%", "GNSS integrity source unavailable": "Джерело цілісності GNSS недоступне", - "Regional sample · 250 nm radius · cells from visited views over 30 min": "Регіональна вибірка · радіус 250 мор. миль · комірки з переглянутих видів за 30 хв", + "Regional sample · 250 nm radius · cells from visited views over 30 min": "Регіональна вибірка · радіус 250 мор. миль · комірки з переглянутих ділянок карти за 30 хв", "Retrying automatically at {time} UTC": "Автоматичний повтор о {time} UTC", "Retrying automatically after provider cooldown": "Автоматичний повтор після паузи постачальника", "Updates automatically after pan or zoom and once a minute. The public feed covers a 250-nautical-mile circle around the view centre; zooming out does not make it a worldwide snapshot. Blank cells are outside sampled coverage or have insufficient observations.": "Оновлюється автоматично після зсуву чи масштабування карти та раз на хвилину. Публічний потік даних охоплює коло радіусом 250 морських миль навколо центру вигляду; у разі віддалення карта не стає знімком усього світу. Порожні комірки — поза охопленням вибірки або з недостатньою кількістю спостережень.", - "Low-accuracy score = 100 × max(0, bad − 1) / total: one aircraft is discounted, so this is not the raw share. Cells need {aircraft} aircraft over {minutes} minutes. Navigation-integrity anomalies are not a detection of jamming or spoofing.": "Частка неточних = 100 × max(0, неточні − 1) / усього: один літак не враховується, тож це не пряма частка. Для комірки потрібно літаків: {aircraft} за {minutes} хв. Аномалії цілісності навігації — не виявлення глушіння чи підміни сигналу.", + "Low-accuracy score = 100 × max(0, bad − 1) / total: one aircraft is discounted, so this is not the raw share. Cells need {aircraft} aircraft over {minutes} minutes. Navigation-integrity anomalies are not a detection of jamming or spoofing.": "Показник неточності = 100 × max(0, неточні − 1) / усього: один літак не враховується, тож це не пряма частка неточних літаків. Для комірки потрібно літаків: {aircraft} за {minutes} хв. Аномалії цілісності навігації не означають виявлення глушіння чи підміни сигналу.", "GNSS snapshot needs a view anchor": "Для знімка GNSS потрібна опорна точка вигляду", "GNSS feed rate limited (HTTP 429)": "Потік GNSS: перевищено ліміт запитів (HTTP 429)", "Malformed GNSS integrity snapshot": "Некоректний знімок цілісності GNSS", @@ -821,17 +821,17 @@ "T−{time} · {mission}": "T−{time} · {mission}", "LAUNCH STANDBY": "ГОТОВНІСТЬ ДО ЗАПУСКУ", "LIFTOFF · {mission}": "СТАРТ · {mission}", - "ASCENT REPLAY · {mission}": "ПОВТОР ЗЛЬОТУ · {mission}", - "ASCENT ESTIMATE · {mission}": "РОЗРАХУНКОВИЙ ЗЛІТ · {mission}", + "ASCENT REPLAY · {mission}": "ПОВТОР ВИВЕДЕННЯ · {mission}", + "ASCENT ESTIMATE · {mission}": "РОЗРАХУНКОВЕ ВИВЕДЕННЯ · {mission}", "STAGE RE-ENTRY / RECOVERY · {mission}": "ВХІД В АТМОСФЕРУ / ПОВЕРНЕННЯ · {mission}", "ORBIT REPLAY · {mission}": "ПОВТОР ОРБІТИ · {mission}", "PAUSED · {title}": "ПАУЗА · {title}", "UNSPECIFIED": "НЕ ВКАЗАНО", - "+{count} additional payload records": "+{count} додаткових записів корисного навантаження", + "+{count} additional payload records": "Додаткові записи корисного навантаження: +{count}", "PAYLOAD DATA UNAVAILABLE": "ДАНІ КОРИСНОГО НАВАНТАЖЕННЯ НЕДОСТУПНІ", "{value} KM DOWNRANGE": "{value} КМ УЗДОВЖ ТРАСИ", "POSITION UNAVAILABLE": "ПОЗИЦІЯ НЕДОСТУПНА", - "FLIGHT {count}": "РЕЙС {count}", + "FLIGHT {count}": "ПОЛІТ {count}", "REUSED": "ПОВТОРНО ВИКОРИСТАНИЙ", "NO STAGE RE-ENTRY / RECOVERY DATA": "НЕМАЄ ДАНИХ ПРО ВХІД В АТМОСФЕРУ / ПОВЕРНЕННЯ", "{count} / 30D": "{count} / 30 ДН", @@ -863,7 +863,7 @@ "FINAL POSITION": "КІНЦЕВА ПОЗИЦІЯ", "REPLAY SPEED": "ШВИДКІСТЬ ПОВТОРУ", "Replay speed multiplier": "Множник швидкості повтору", - "REPLAY ASCENT": "ПОВТОР ЗЛЬОТУ", + "REPLAY ASCENT": "ПОВТОР ВИВЕДЕННЯ", "Previous mission": "Попередня місія", "PREV": "ПОПЕР.", "Next mission": "Наступна місія", @@ -874,12 +874,12 @@ "PLANNED · ": "ПЛАН · ", "SUPPLIED TRAJECTORY POINTS": "НАДАНІ ТОЧКИ ТРАЄКТОРІЇ", "RECONSTRUCTED ESTIMATE": "ВІДТВОРЕНА ОЦІНКА", - "Replay the estimated ascent with a following camera": "Відтворити розрахунковий зліт із камерою-супроводом", + "Replay the estimated ascent with a following camera": "Відтворити розрахункове виведення з камерою супроводу", "Resume replay": "Продовжити повтор", "T minus {seconds}": "T мінус {seconds}", "Preparing launch site": "Підготовка місця запуску", "Liftoff": "Старт", - "Ascent replay": "Повтор зльоту", + "Ascent replay": "Повтор виведення", "Orbit replay": "Повтор орбіти", ", paused": ", пауза", "Malformed launch snapshot": "Некоректний знімок запусків", @@ -892,7 +892,7 @@ "Your decoder feed": "Ваш потік декодера", "Your RTL-SDR receiver": "Ваш приймач RTL-SDR", "NO CALLSIGN": "БЕЗ ПОЗИВНОГО", - "ALT {altitude} FT · GS {speed} KT · TRK {track}": "ВИС. {altitude} ФТ · ШЛЯХ. ШВ. {speed} ВУЗ · ШЛЯХ {track}", + "ALT {altitude} FT · GS {speed} KT · TRK {track}": "ВИС. {altitude} ФТ · ШЛЯХ. ШВ. {speed} ВУЗ · ШК {track}", "V/S {rate}": "ВЕРТ. ШВ. {rate}", "V/S {rate} FPM": "ВЕРТ. ШВ. {rate} ФТ/ХВ", "POSITION {age}": "ПОЗИЦІЯ {age}", @@ -959,7 +959,7 @@ "50–99% contained": "Локалізовано на 50–99%", "Fully contained": "Повністю локалізовано", "Colour shows reported containment. Perimeters are simplified to about 100 m.": "Колір показує заявлений ступінь локалізації. Контури спрощено приблизно до 100 м.", - "Malformed perimeter snapshot": "Некоректний знімок периметрів", + "Malformed perimeter snapshot": "Некоректний знімок контурів пожеж", "radio tag|All": "Усі", "News": "Новини", "Talk": "Розмовні", @@ -982,7 +982,7 @@ "radio|MUSIC": "МУЗИКА", "radio|OTHER": "ІНШЕ", "Broadcaster stream is unavailable or blocked by the browser.": "Потік мовника недоступний або заблокований браузером.", - "Playback requires a direct click or tap.": "Щоб почати відтворення, натисніть кнопку відтворення.", + "Playback requires a direct click or tap.": "Для відтворення потрібне безпосереднє натискання.", "Broadcaster stream could not be started.": "Не вдалося запустити потік мовника.", "Alternative": "Альтернатива", "Ambient": "Ембієнт", @@ -1055,10 +1055,10 @@ "Point the camera at the ground for street-level coverage": "Спрямуйте камеру на землю, щоб побачити покриття вуличних знімків", "Coverage tile failed": "Не вдалося завантажити тайл покриття", "The photo could not be loaded": "Не вдалося завантажити фото", - "{name} photo. ← and → step along the sequence. On a 360° photo, drag or use Shift+← →, ↑ ↓ to look around, and + − to zoom": "Фото {name}. ← і → гортають зйомку. На 360°-фото перетягуйте або використовуйте Shift+← →, ↑ ↓ для огляду, + − для масштабу", + "{name} photo. ← and → step along the sequence. On a 360° photo, drag or use Shift+← →, ↑ ↓ to look around, and + − to zoom": "Фото {name}. ← і → гортають послідовність. На 360°-фото перетягуйте або використовуйте Shift+← →, ↑ ↓ для огляду, + − для масштабу", "{name} street-level photo": "Вуличне фото {name}", - "Previous photo in this sequence (←)": "Попереднє фото зйомки (←)", - "Next photo in this sequence (→)": "Наступне фото зйомки (→)", + "Previous photo in this sequence (←)": "Попереднє фото послідовності (←)", + "Next photo in this sequence (→)": "Наступне фото послідовності (→)", "Aim the middle of the view at a street to look for imagery there": "Наведіть центр вигляду на вулицю, щоб пошукати там знімки", "KEY REJECTED": "КЛЮЧ ВІДХИЛЕНО", "GOOGLE_MAPS_API_KEY is not set": "GOOGLE_MAPS_API_KEY не задано", @@ -1279,7 +1279,7 @@ "{source} HTTP {status}": "{source}: HTTP {status}", "Wind": "Вітер", "Wind source unavailable": "Джерело вітру недоступне", - "Forecast · does not follow history": "Прогноз · не йде за історією", + "Forecast · does not follow history": "Прогноз · не синхронізується з історією", "Wind motion": "Рух вітру", "Wind speed": "Швидкість вітру", "Sea-level pressure": "Тиск на рівні моря", @@ -1303,9 +1303,9 @@ "Wind trails with no field shading": "Сліди вітру без заливки поля", "How hard the surface wind is blowing": "Наскільки сильно дме приземний вітер", "Sea-level air pressure: broad highs and lows": "Тиск на рівні моря: великі області високого й низького тиску", - "Air temperature two meters above the surface": "Температура повітря за два метри над поверхнею", + "Air temperature two meters above the surface": "Температура повітря на висоті двох метрів над поверхнею", "Wind speed units": "Одиниці швидкості вітру", - "Read wind at map center": "Дізнатися вітер у центрі карти", + "Read wind at map center": "Показати вітер у центрі карти", "Read the forecast at the center of the map without changing selection": "Отримати прогноз у центрі карти, не змінюючи вибору", "{model} forecast · {field} ({unit})": "Прогноз {model} · {field} ({unit})", "Valid: {time}": "Чинний на: {time}", @@ -1426,14 +1426,14 @@ "Select a feature or use Tab and Enter to choose an action.": "Виберіть обʼєкт на карті або скористайтеся Tab і Enter, щоб вибрати дію.", "Selected feature: {feature}. Choose an action.": "Вибрано обʼєкт: {feature}. Виберіть дію.", "Running {index}/{total}: {scene} / {shot}": "Виконання {index}/{total}: {scene} / {shot}", - "Scene run complete": "Запуск сцени завершено", + "Scene run complete": "Відтворення сцени завершено", "Bhote Koshi Evidence Sequence": "Послідовність свідчень: Bhote Koshi", "Nepal Flood Incident": "Паводок у Непалі", "Global Flights Radar": "Глобальний радар польотів", "Orbital Watch": "Орбітальний нагляд", "Thermal Threat Board": "Панель теплових загроз", "City Overload": "Міське перевантаження", - "Omniscience Pullback": "Всевидючий відʼїзд", + "Omniscience Pullback": "Всевидющий відʼїзд", "Global Incident Context": "Глобальний контекст події", "Nepal-Focused Globe Rotation": "Поворот глобуса до Непалу", "Bhote Koshi Regional Approach": "Підліт до регіону Bhote Koshi", @@ -1578,7 +1578,7 @@ "North up": "Північ угорі", "CCTV calibration saved": "Калібрування CCTV збережено", "HDG": "КУРС", - "PITCH": "ТАНГАЖ", + "PITCH": "НАХИЛ", "FOV": "ОГЛЯД", "RANGE": "ДАЛЬН.", "HGT": "ВИС.", @@ -1609,7 +1609,7 @@ "No source configured": "Джерело не налаштовано", "Configured source": "Налаштоване джерело", "Configured Source": "Налаштоване джерело", - "Synthetic fallback": "Синтетичний резерв", + "Synthetic fallback": "Резервна імітація", "Upstream HTTP {status}": "Джерело: HTTP {status}", "Unexpected media type {type}": "Неочікуваний тип медіа: {type}", "SOURCE · UNKNOWN": "ДЖЕРЕЛО · НЕВІДОМЕ", @@ -1644,7 +1644,7 @@ "many": "{count} камер завантажено · увімкніть CCTV, щоб активувати", "other": "{count} камери завантажено · увімкніть CCTV, щоб активувати" }, - "Enable CCTV to load camera intersections": "Увімкніть CCTV, щоб завантажити перехрестя камер", + "Enable CCTV to load camera intersections": "Увімкніть CCTV, щоб завантажити камери на перехрестях", "Enable CCTV to start camera-linked intelligence summaries.": "Увімкніть CCTV, щоб почати зведення розвідки за камерами.", "No summary available.": "Зведення недоступне.", "loading frames": "завантаження кадрів", @@ -1659,7 +1659,7 @@ "DRIZZLE": "МЖИЧКА", "RAIN": "ДОЩ", "RAIN SHOWERS": "ЗЛИВИ", - "SNOW SHOWERS": "СНІЖНІ ЗЛИВИ", + "SNOW SHOWERS": "ЗЛИВОВИЙ СНІГ", "THUNDERSTORM": "ГРОЗА", "MIXED CONDITIONS": "ЗМІШАНІ УМОВИ", "CYCLE ON": "ЦИКЛ УВІМКНЕНО", @@ -1683,7 +1683,7 @@ "ENABLE GLOBAL CONTEXT FOR PROXIMITY PINGS": "УВІМКНІТЬ ГЛОБАЛЬНИЙ КОНТЕКСТ ДЛЯ ПІНГІВ БЛИЗЬКОСТІ", "CONTACT LOST · LAST KNOWN READOUT · NOT AN ALL-CLEAR": "КОНТАКТ ВТРАЧЕНО · ОСТАННІ ВІДОМІ ПОКАЗНИКИ · НЕ ОЗНАЧАЄ «УСЕ ЧИСТО»", "CONTACT LOST · {subject}": "КОНТАКТ ВТРАЧЕНО · {subject}", - "SUBJECT LEFT ITS FEED · READOUT HOLDING LAST KNOWN": "ОБʼЄКТ ЗНИК ІЗ ПОТОКУ · ПОКАЗНИКИ ОСТАННІ ВІДОМІ", + "SUBJECT LEFT ITS FEED · READOUT HOLDING LAST KNOWN": "ОБʼЄКТ ЗНИК ІЗ ПОТОКУ · ПОКАЗАНО ОСТАННІ ВІДОМІ ДАНІ", "{cohort} · {contact}": "{cohort} · {contact}", "NO AVAILABLE EXAMPLE": "НЕМАЄ ДОСТУПНОГО ПРИКЛАДУ", "{cohort}, Unavailable": "{cohort}, недоступно", @@ -1735,7 +1735,7 @@ "SOURCE-BACKED EVENTS · NO SYNTHETIC NEWS": "ПОДІЇ ПІДТВЕРДЖЕНІ ДЖЕРЕЛАМИ · БЕЗ ШТУЧНИХ НОВИН", "LATEST LOCATION-MATCHED REPORTING": "ОСТАННІ ПУБЛІКАЦІЇ ЗА РОЗТАШУВАННЯМ", "{source} · LOCATION QUERY · RECENT": "{source} · ЗАПИТ ЗА МІСЦЕМ · НЕЩОДАВНІ", - "LOCAL INFO": "МІСЦЕВА ІНФОРМАЦІЯ", + "LOCAL INFO": "МІСЦЕВІ ДАНІ", "PLACE / CONDITIONS / POSITION": "МІСЦЕ / УМОВИ / ПОЗИЦІЯ", "TIME UNKNOWN": "ЧАС НЕВІДОМИЙ", "{count}M AGO": "{count} ХВ ТОМУ", @@ -1826,10 +1826,10 @@ "Earthquakes (24h)": "Землетруси (24 год)", "Satellites": "Супутники", "Space Missions (30d)": "Космічні місії (30 дн)", - "Street Traffic": "Вуличний рух", + "Street Traffic": "Дорожній рух", "CCTV": "CCTV", "Radio": "Радіо", - "Bikeshare": "Велопрокат", + "Bikeshare": "Прокат велосипедів", "Live AIS Vessels": "Судна AIS онлайн", "Mapped Installations": "Нанесені обʼєкти", "Global Context": "Глобальний контекст", @@ -1940,8 +1940,8 @@ "📍 Location: --": "📍 Розташування: --", "Landmark: --": "Орієнтир: --", "Searched location": "Знайдене розташування", - "ORBIT": "ОРБІТА", - "Location not found": "Розташування не знайдено", + "ORBIT": "ОБЛІТ", + "Location not found": "Місце не знайдено", "Check the spelling and press Enter to search again.": "Перевірте написання й натисніть Enter, щоб повторити пошук.", "Search failed": "Пошук не вдався", "Press Enter to try again.": "Натисніть Enter, щоб спробувати знову.", @@ -2000,7 +2000,7 @@ "Enable Radio": "Увімкнути радіо", "{category} ({count})": "{category} ({count})", "DIRECTORY BAND": "ДІАПАЗОН КАТАЛОГУ", - "{category} BAND": "{category} ДІАПАЗОН", + "{category} BAND": "ДІАПАЗОН: {category}", "NO STATION SELECTED": "СТАНЦІЮ НЕ ВИБРАНО", "Directory metadata only": "Лише метадані каталогу", "Loading station directory…": "Завантаження каталогу станцій…", @@ -2010,9 +2010,9 @@ "PAUSE": "ПАУЗА", "RESUME": "ПРОДОВЖ.", "PLAY": "ВІДТВОРИТИ", - "selected": "вибрану", - "nearest": "найближчу", - "{action} {target} radio station": "{action} {target} радіостанцію", + "selected": "вибрана", + "nearest": "найближча", + "{action} {target} radio station": "{action}: {target} радіостанція", "RADIO STATE UNCERTAIN": "СТАН РАДІО НЕВИЗНАЧЕНИЙ", "SYNCING DIRECTORY": "СИНХРОНІЗАЦІЯ КАТАЛОГУ", "RADIO READY": "РАДІО ГОТОВЕ", @@ -2030,8 +2030,8 @@ "Playing {station}": "Відтворюється: {station}", "Paused {station}": "Пауза: {station}", "Broadcaster stream unavailable": "Потік мовника недоступний", - " · muted during voice interaction": " · приглушено під час голосової сесії", - " · restoring volume after voice": " · відновлення гучності після голосової сесії", + " · muted during voice interaction": " · приглушено під час голосового сеансу", + " · restoring volume after voice": " · відновлення гучності після голосового сеансу", " · static indicates no broadcaster audio": " · шум означає відсутність аудіо мовника", " · tuning static until broadcaster starts": " · шум налаштування, доки не почнеться мовлення", "Station unavailable after directory refresh — choose another channel": "Станція недоступна після оновлення каталогу — виберіть інший канал", @@ -2039,9 +2039,9 @@ "Radio is disabling…": "Радіо вимикається…", "Radio lifecycle is uncertain — use Enable or Disable to reconcile": "Стан радіо невизначений — звірте через «Увімкнути» або «Вимкнути»", "Clear reading": "Очистити покази", - "Earlier observation": "Раніше спостереження", + "Earlier observation": "Попереднє спостереження", "Observed history": "Історія спостережень", - "Later observation": "Пізніше спостереження", + "Later observation": "Наступне спостереження", "Latest": "Останні", "Newest frame per product": "Найсвіжіший кадр кожного продукту", "Replay observed history": "Відтворити історію спостережень", @@ -2192,10 +2192,10 @@ "LOAD COMPLETE": "ЗАВАНТАЖЕННЯ ЗАВЕРШЕНО", "LOAD CANCELLED": "ЗАВАНТАЖЕННЯ СКАСОВАНО", "LOAD FAILED": "ПОМИЛКА ЗАВАНТАЖЕННЯ", - "LIVE DATA OFF": "ДАНІ У РЕАЛЬНОМУ ЧАСІ ВИМКНЕНО", - "MAPPED SITES LOADED": "МІСЦЯ НА КАРТІ ЗАВАНТАЖЕНО", - "RETRYING MAPPED SITES": "ПОВТОРНЕ ЗАВАНТАЖЕННЯ МІСЦЬ НА КАРТІ", - "FETCHING MAPPED SITES": "ЗАВАНТАЖЕННЯ МІСЦЬ НА КАРТІ", + "LIVE DATA OFF": "ДАНІ В РЕАЛЬНОМУ ЧАСІ ВИМКНЕНО", + "MAPPED SITES LOADED": "НАНЕСЕНІ ОБʼЄКТИ ЗАВАНТАЖЕНО", + "RETRYING MAPPED SITES": "ПОВТОРНЕ ЗАВАНТАЖЕННЯ НАНЕСЕНИХ ОБʼЄКТІВ", + "FETCHING MAPPED SITES": "ЗАВАНТАЖЕННЯ НАНЕСЕНИХ ОБʼЄКТІВ", "RETRYING ALPR CAMERAS": "ПОВТОРНЕ ЗАВАНТАЖЕННЯ КАМЕР ALPR", "FETCHING ALPR CAMERAS": "ЗАВАНТАЖЕННЯ КАМЕР ALPR", "OVERPASS TEMPORARILY UNAVAILABLE": "OVERPASS ТИМЧАСОВО НЕДОСТУПНИЙ", @@ -2319,10 +2319,10 @@ "other": "{n} вулиці в кадрі · клацніть лінію, щоб відкрити найближче фото" }, "{n} sequences in view · click a line for its nearest photo": { - "one": "{n} зйомка в кадрі · клацніть лінію, щоб відкрити найближче фото", - "few": "{n} зйомки в кадрі · клацніть лінію, щоб відкрити найближче фото", - "many": "{n} зйомок у кадрі · клацніть лінію, щоб відкрити найближче фото", - "other": "{n} зйомки в кадрі · клацніть лінію, щоб відкрити найближче фото" + "one": "{n} послідовність у кадрі · клацніть лінію, щоб відкрити найближче фото", + "few": "{n} послідовності в кадрі · клацніть лінію, щоб відкрити найближче фото", + "many": "{n} послідовностей у кадрі · клацніть лінію, щоб відкрити найближче фото", + "other": "{n} послідовності в кадрі · клацніть лінію, щоб відкрити найближче фото" }, "{n} sequences in view · click a line for its photos": { "one": "{n} послідовність у кадрі · клацніть лінію, щоб відкрити знімки", @@ -2344,7 +2344,7 @@ "s": "с", "dB": "дБ", "Celestial ring — reveal the full globe": "Небесне кільце — показати весь глобус", - "Celestial ring — available in Normal style": "Небесне кільце — доступне у стилі «Звичайний»", + "Celestial ring — available in Normal style": "Небесне кільце — доступне в стилі «Звичайний»", "Detection overlay: {mode}": "Накладка виявлення: {mode}", "Detection overlay: off": "Накладка виявлення: вимк.", "DETECT": "ВИЯВЛЕННЯ", @@ -2352,7 +2352,7 @@ "Active weather": "Активні погодні шари", "LATEST · newest per product": "ОСТАННІ · найсвіжіші для кожного продукту", "Forecast · valid {valid} · issued {issued}": "Прогноз · чинний на {valid} · випущено {issued}", - "{detail} · Does not follow history": "{detail} · не йде за історією", + "{detail} · Does not follow history": "{detail} · не синхронізується з історією", "Forecast · valid {valid}": "Прогноз · чинний на {valid}", "voice|OFF": "ВИМК.", "voice|CONNECTING": "ЗʼЄДНАННЯ", @@ -2363,9 +2363,9 @@ "Changing provider reconnects voice if it is on.": "Зміна постачальника перепідключає голосовий режим, якщо його ввімкнено.", "Voice Settings": "Налаштування голосу", "AI AGENT": "ШІ-АГЕНТ", - "Voice model tier — applies next session": "Рівень голосової моделі — застосовується з наступної сесії", + "Voice model tier — applies next session": "Рівень голосової моделі — застосовується з наступного сеансу", "STD": "СТД", - "Estimated session cost": "Орієнтовна вартість сесії", + "Estimated session cost": "Орієнтовна вартість сеансу", "Voice control — activate to toggle voice; hold Space to speak": "Голосове керування — активуйте, щоб увімкнути або вимкнути голос; утримуйте Space, щоб говорити", "ON/OFF": "ПЕРЕМК.", "VOICE STANDBY": "ГОЛОС ОЧІКУЄ", @@ -2452,21 +2452,21 @@ "WebRTC microphone support unavailable": "Підтримка мікрофона WebRTC недоступна", "VOICE UNAVAILABLE": "ГОЛОС НЕДОСТУПНИЙ", "VOICE ACTIVE": "ГОЛОС АКТИВНИЙ", - "Voice session could not be started.": "Не вдалося запустити голосову сесію.", + "Voice session could not be started.": "Не вдалося запустити голосовий сеанс.", "MINI": "МІНІ", - "Next session: {pendingId} — this session stays on {modelId}": "Наступна сесія: {pendingId} — поточна залишається на {modelId}", - "Voice model: {pendingId} — click to switch to {target}; applies next session": "Голосова модель: {pendingId} — натисніть, щоб перейти на {target}; застосовується з наступної сесії", + "Next session: {pendingId} — this session stays on {modelId}": "Наступний сеанс: {pendingId} — поточний залишається на {modelId}", + "Voice model: {pendingId} — click to switch to {target}; applies next session": "Голосова модель: {pendingId} — натисніть, щоб перейти на {target}; застосовується з наступного сеансу", "standard": "стандартну", "mini": "міні", "COST UNKNOWN": "ВАРТІСТЬ НЕВІДОМА", - "ChatGPT OAuth session: {responses} response(s), {input} input and {output} output tokens, {captions} caption transcription(s) reported.": "Сесія ChatGPT OAuth: відповідей — {responses}, вхідних токенів — {input}, вихідних токенів — {output}, транскрипцій субтитрів — {captions}.", + "ChatGPT OAuth session: {responses} response(s), {input} input and {output} output tokens, {captions} caption transcription(s) reported.": "Сеанс ChatGPT OAuth: відповідей — {responses}, вхідних токенів — {input}, вихідних токенів — {output}, транскрипцій субтитрів — {captions}.", "USD cost and the API spend cap are unavailable for this auth mode.": "Вартість у USD і ліміт витрат API недоступні в цьому режимі авторизації.", - "Usage is incomplete because a response was still in flight when the session ended.": "Дані про використання неповні: на момент завершення сесії одну з відповідей ще не було отримано.", - "Estimated session cost on {modelId} — {responses} response(s). Warns at {warn}, ends the session at {cap}.": "Орієнтовна вартість сесії на {modelId} — відповідей: {responses}. Попереджає при {warn}, завершує сесію при {cap}.", - "Estimate is incomplete — a response was still in flight when the session ended, so its usage was never reported.": "Оцінка неповна: на момент завершення сесії одну з відповідей ще не було отримано, тому її використання не враховано.", + "Usage is incomplete because a response was still in flight when the session ended.": "Дані про використання неповні: на момент завершення сеансу одну з відповідей ще не було отримано.", + "Estimated session cost on {modelId} — {responses} response(s). Warns at {warn}, ends the session at {cap}.": "Орієнтовна вартість сеансу на {modelId} — відповідей: {responses}. Попереджає при {warn}, завершує сеанс при {cap}.", + "Estimate is incomplete — a response was still in flight when the session ended, so its usage was never reported.": "Оцінка неповна: на момент завершення сеансу одну з відповідей ще не було отримано, тому її використання не враховано.", "STANDARD": "СТАНДАРТ", - "{tier} applies next session": "{tier} застосовується з наступної сесії", - "Session ended — cost cap {cost}": "Сесію завершено — ліміт витрат {cost}", + "{tier} applies next session": "{tier} застосовується з наступного сеансу", + "Session ended — cost cap {cost}": "Сеанс завершено — ліміт витрат {cost}", "MIC": "МІК", "Radio did not start": "Радіо не запустилося", "{n} aircraft": { @@ -2610,7 +2610,7 @@ "Activate to toggle voice": "Активуйте, щоб увімкнути або вимкнути голос", "Voice active": "Голос активний", "Voice could not be started.": "Не вдалося запустити голос.", - "the active voice session": "активна голосова сесія", + "the active voice session": "активний голосовий сеанс", "{value} feet": "{value} фт", "Fire · FRP {frp} MW": "Пожежа · FRP {frp} МВт", "The flights layer is not enabled": "Шар рейсів не ввімкнено", @@ -2762,7 +2762,7 @@ "Recent speech": "Нещодавнє мовлення", "HERE": "ТУТ", "Aircraft cockpit view": "Вигляд кабіни повітряного судна", - "LEVEL": "РІВЕНЬ", + "LEVEL": "ГОРИЗОНТ", "Estimated destination direction": "Орієнтовний напрямок до пункту призначення", "DEST ---°": "ПРИЗН. ---°", "OPTICAL PLANE · 01": "ОПТИЧНА ПЛОЩИНА · 01", @@ -2789,7 +2789,7 @@ "CONTACTS · 250 KM": "КОНТАКТИ · 250 КМ", "Contact navigation": "Навігація контактами", "CONTEXT ONLY": "ЛИШЕ КОНТЕКСТ", - "Nearby cohort counts": "Кількість найближчих груп", + "Nearby cohort counts": "Кількість контактів поблизу за типами", "FLT": "РЕЙСИ", "MIL": "ВІЙСЬК.", "SITE": "ОБʼЄКТИ", @@ -2819,7 +2819,7 @@ "NEWS": "НОВИНИ", "Show Regional News": "Показати регіональні новини", "LOCAL": "МІСЦ.", - "Show Local Info": "Показати місцеву інформацію", + "Show Local Info": "Показати місцеві дані", "Cockpit display and Radio controls": "Керування дисплеєм і радіо кабіни", "DISPLAY": "ДИСПЛЕЙ", "Cockpit display options": "Параметри дисплея кабіни", @@ -2842,12 +2842,12 @@ "Pin visual presets": "Закріпити візуальні пресети", "Keep visual presets open": "Тримати візуальні пресети відкритими", "Show the globe without a visual filter.": "Показує глобус без візуального фільтра.", - "Emulate a green phosphor CRT with scanlines and screen curvature.": "Імітує CRT-монітор із зеленим фосфором, рядками розгортки та вигнутим екраном.", + "Emulate a green phosphor CRT with scanlines and screen curvature.": "Імітує CRT-монітор із зеленим люмінофором, рядками розгортки та вигнутим екраном.", "Simulate night-vision goggles with green intensification and a tube vignette.": "Імітує прилад нічного бачення з зеленим підсиленням та віньєткою туби.", "Simulate FLIR-style thermal contrast. Turn up Ironbow for color.": "Імітує термальний контраст у стилі FLIR. Для кольору збільште Ironbow.", "Apply bright cel-shaded color and illustrated outlines.": "Застосовує яскраву мультяшну заливку та ілюстровані контури.", "Apply high-contrast monochrome film-noir grading.": "Застосовує висококонтрастну чорно-білу обробку в стилі нуар.", - "Add a cold, snowy whiteout treatment to the scene.": "Додає до сцени холодний засніжений білий ефект.", + "Add a cold, snowy whiteout treatment to the scene.": "Додає до сцени холодний ефект снігової імли.", "MAP SOURCE": "ДЖЕРЕЛО КАРТИ", "Map source": "Джерело карти", "Style": "Стиль", @@ -2855,9 +2855,9 @@ "Collapse panel": "Згорнути панель", "Pin location tray": "Закріпити панель розташування", "Keep location tray open": "Тримати панель розташування відкритою", - "Search any location": "Шукати будь-яке розташування", - "Search location by name or coordinates": "Шукати розташування за назвою або координатами", - "Search any location...": "Шукати будь-яке розташування...", + "Search any location": "Пошук місця", + "Search location by name or coordinates": "Пошук місця за назвою або координатами", + "Search any location...": "Пошук місця...", "WEATHER": "ПОГОДА", "Active weather products": "Активні погодні продукти", "RECENT IMAGERY": "СВІЖІ ЗНІМКИ", @@ -2903,7 +2903,7 @@ "Radio volume": "Гучність радіо", "STATION SITE": "САЙТ СТАНЦІЇ", "DIRECTORY: RADIO BROWSER": "КАТАЛОГ: RADIO BROWSER", - "Audio connects directly to the broadcaster after you press play. Your IP is visible to that broadcaster.": "Після натискання відтворення аудіо зʼєднується напряму з мовником. Мовник бачить вашу IP-адресу.", + "Audio connects directly to the broadcaster after you press play. Your IP is visible to that broadcaster.": "Після натискання «Відтворити» звук надходить безпосередньо від мовника. Мовник бачить вашу IP-адресу.", "Local RTL-SDR receiver": "Локальний приймач RTL-SDR", "LOCAL RTL-SDR": "ЛОКАЛЬНИЙ RTL-SDR", "Chrome/Edge · WebUSB · one local tuner shared by FM and the Local ADS-B layer.": "Chrome/Edge · WebUSB · один локальний тюнер для FM і шару «Локальний ADS-B».", @@ -2949,7 +2949,7 @@ "Detection label density": "Щільність підписів виявлення", "Allocation": "Розподіл", "Detection label allocation": "Розподіл підписів виявлення", - "Elastic": "Пружний", + "Elastic": "Гнучкий", "Weighted": "Зважений", "Fade": "Згасання", "Detection fade distance": "Відстань згасання виявлення", @@ -2965,8 +2965,8 @@ "Scope — the circular viewport mask": "Приціл — кругла маска вікна перегляду", "Scope": "Приціл", "Feather": "Розмиття", - "Scope edge feather": "Розмиття краю приціла", - "Scope edge feather as a percentage of the keyhole radius": "Розмиття краю приціла у відсотках радіуса ілюмінатора", + "Scope edge feather": "Розмиття краю прицілу", + "Scope edge feather as a percentage of the keyhole radius": "Розмиття краю прицілу у відсотках від радіуса ілюмінатора", "Draw on the world — click vertices, double-click or Enter to finish, Esc to cancel": "Малювати на карті світу — клацайте вершини, подвійне клацання або Enter — завершити, Esc — скасувати", "Shape": "Фігура", "Shape to draw": "Фігура для малювання", @@ -2988,7 +2988,7 @@ "Choose GeoJSON, KML, KMZ or GPX files": "Виберіть файли GeoJSON, KML, KMZ або GPX", "Imported files": "Імпортовані файли", "Celestial": "Небо", - "Hide UI chrome": "Сховати оформлення інтерфейсу", + "Hide UI chrome": "Сховати елементи інтерфейсу", "Clean UI": "Чистий інтерфейс", "Bloom / Glow": "Світіння / Ореол", "Bloom intensity": "Інтенсивність світіння", @@ -3003,17 +3003,17 @@ "NEAREST": "НАЙБЛИЖЧА", "CCTV camera": "Камера CCTV", "CALIBRATION": "КАЛІБРУВАННЯ", - "Drag the camera in the world: rings rotate, arrows move, handles set range/FOV": "Перетягніть камеру у сцені: кільця обертаються, стрілки переміщуються, маркери задають дальність/FOV", + "Drag the camera in the world: rings rotate, arrows move, handles set range/FOV": "Перетягніть камеру в сцені: кільця — обертання, стрілки — переміщення, маркери — дальність/FOV", "Camera pose — click a value to type": "Позиція камери — клацніть значення, щоб увести", "Heading (compass °) — click to type": "Курс (° за компасом) — клацніть, щоб увести", - "Pitch (° up/down) — click to type": "Тангаж (° вгору/вниз) — клацніть, щоб увести", + "Pitch (° up/down) — click to type": "Нахил (° вгору/вниз) — клацніть, щоб увести", "Horizontal FOV (°) — click to type": "Горизонтальний FOV (°) — клацніть, щоб увести", "Range / monitor-plane distance (m) — click to type": "Дальність / відстань до площини монітора (м) — клацніть, щоб увести", "Mount height above ground (m) — click to type": "Висота кріплення над землею (м) — клацніть, щоб увести", "North offset from catalog position (m) — click to type": "Зміщення на північ від позиції каталогу (м) — клацніть, щоб увести", "East offset from catalog position (m) — click to type": "Зміщення на схід від позиції каталогу (м) — клацніть, щоб увести", - "SAVE CAL": "ЗБЕРЕГТИ КАЛ.", - "RESET CAL": "СКИНУТИ КАЛ.", + "SAVE CAL": "ЗБЕРЕГТИ КАЛІБР.", + "RESET CAL": "СКИНУТИ КАЛІБР.", "SCENE SUMMARY": "ЗВЕДЕННЯ СЦЕНИ", "STREET LEVEL": "ВУЛИЧНІ ЗНІМКИ", "Turn Street Level on or off": "Увімкнути або вимкнути «Вуличні знімки»", diff --git a/src/ui/styles/cockpit.css b/src/ui/styles/cockpit.css index d54e09f8d..8116380b3 100644 --- a/src/ui/styles/cockpit.css +++ b/src/ui/styles/cockpit.css @@ -730,7 +730,8 @@ html:not([lang='en']) .cockpit-roll-token.is-separator { } .cockpit-vision-controls { display: grid; - grid-template-columns: 48px 58px 48px; + /* The current style grows for a long translated name (ЗВИЧАЙНИЙ). */ + grid-template-columns: 48px minmax(58px, max-content) 48px; align-items: stretch; gap: 2px; margin-top: 2px; From 3c0c10d3b1259ada7945f7c1bec964707fe88d69 Mon Sep 17 00:00:00 2001 From: German Khokhlov Date: Wed, 28 Oct 2026 16:39:34 +0400 Subject: [PATCH 26/83] i18n(pt): apply review round 1 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Three-model review (astra, sol, fable): 51 of 52 findings applied, two of them in part. - pt: AQHI bands as health risk, NAVIO-TANQUE, CANDIDATO DO GOOGLE PLACES, Provider Settings agreement, retry/feed-down wording, NOTÍCIAS DA ÁREA (fits the briefing kicker), detection modes in the masculine, GS and REC kept on the HUD, EXPORTAR PREDEF., prepositions before times, and more (see docs/translations/pt.md). - Cyclone request timeout is now a catalog message (all locales). - Built-in Nepal base shots written by the legacy pack bootstrap now show their localized titles: displayShotTitle also trusts the legacy keyframes of an append pack the scene has applied. Co-Authored-By: Claude Opus 5.5 --- docs/translations/pt.md | 23 +++-- src/i18n/locales/es.json | 1 + src/i18n/locales/pt.json | 125 +++++++++++++------------- src/i18n/locales/ru.json | 1 + src/i18n/locales/zh-CN.json | 1 + src/i18n/locales/zh-Hant.json | 1 + src/i18n/same-as-english.json | 2 + src/layers/cyclones/source.js | 6 +- src/scenes/recipes.js | 29 ++++-- src/scenes/sceneTitleDisplay.test.mjs | 23 +++++ 10 files changed, 136 insertions(+), 76 deletions(-) diff --git a/docs/translations/pt.md b/docs/translations/pt.md index 7417fd64f..bf1208dce 100644 --- a/docs/translations/pt.md +++ b/docs/translations/pt.md @@ -9,12 +9,14 @@ Translation source: abiyeenzo (#909). - Brazilian Portuguese (pt-BR): câmera, tela, compartilhar, arquivo, baixar, ônibus, metrô. Every `pt` tag, `pt-PT` included, gets this catalog, so avoid slang and regionalisms. - Address the user with «você» imperatives: «Clique no mapa», «Ative o CCTV», «Tente novamente». Tooltips that name an action use the infinitive: «Expandir painel», «Redefinir a câmera». - Sentence case, not Title Case: "Live Flights" → «Voos ao vivo». UPPERCASE English stays UPPERCASE: «AO VIVO», «SEM DADOS». -- Quotes inside Portuguese text are straight double quotes: «Excluir o plano "{shot}"?». +- Quotes inside Portuguese text are straight double quotes: «Excluir o plano "{shot}"?». A sentence that names a panel uses «o painel "Configurações de provedores"», so the verb agrees. +- A dash between clauses is a spaced em dash « — », even where the English runs it in. +- A date or time after a participle takes a preposition: «emitido em {time}», «válida para {valid}», «Posição em {time}». - Short labels, chips and HUD readouts stay short. A standard abbreviation with a period beats a wrapped line: ANT., PRÓX., DESLIG., EXCL., INCL., ALT., VEL., câm. -- The HUD codes HDG, BRG, CRS, FOV, DEST, SPD, RANGE, ALT, GS and TRK stay in English, as in cockpit avionics. Words used in a sentence are translated: heading → «rumo», range → «alcance». +- The HUD codes HDG, BRG, CRS, FOV, DEST, SPD, RANGE, ALT, GS and TRK stay in English, as in cockpit avionics («ALT {altitude} FT · GS {speed} KT · TRK {track}»), and so does the HUD recording mark REC. Words used in a sentence are translated: heading → «rumo», range → «alcance». - Keyboard keys stay in English: Space, Esc, Enter, Tab, Shift, Backspace, H, 1–9 («Segure Space para falar»). - Common English tech words used in Brazil stay: feed, stream, snapshot, briefing, dock, layout, bloom, status, app, link, token. -- Units: km, m, km/h, m/s, kt (knots), ft (feet), h, min, s; in UPPERCASE text KM, KM/S, KT, FT, MIN, H. "m" is always metres, so minutes are «min» («há 5 min»). MW stays MW. `°` and `%` stay. Decimal comma in written numbers («M4,4»). +- Units: km, m, km/h, m/s, kt (knots), ft (feet), h, min, s, always spaced from the number («Terremotos (24 h)», «Missões espaciais (30 d)»); in UPPERCASE text KM, KM/S, KT, FT, MIN, H. "m" is always metres, so minutes are «min» («há 5 min»). MW stays MW. `°` and `%` stay. Decimal comma in written numbers («M4,4»). - "ago" goes before the time: «há {count} min». When a placeholder already holds a localized "ago" text (`{age}`, `{ago}`), do not add «há» again. - Money: «US$ {amount} mil / mi / bi» for thousands, millions and billions. - Compass points use Leste/Oeste: N, NNE, NE, ENE, L, ESE, SE, SSE, S, SSO, SO, OSO, O, ONO, NO, NNO; hemisphere letters N, S, L, O. @@ -41,6 +43,7 @@ The `many` form is the `other` text with «de» after the number: «{count} de c | SIMULATED | SIMULADO | | stale / degraded / unavailable | desatualizado / degradado / indisponível | | retry / retrying | nova tentativa / tentando de novo | +| retrying (a fetch) / retrying slowly | buscando de novo / tentando de novo em intervalos maiores | | key (API key) / POWER UP / POWERED UP | chave / ATIVAR / ATIVADO | | Provider Settings | Configurações de provedores | | ON / OFF (state chips) | ATIVO / INATIVO | @@ -48,23 +51,32 @@ The `many` form is the `other` text with «de» after the number: «{count} de c | globe / map / map source / map stack | globo / mapa / fonte do mapa / pilha de mapas | | basemap / tile | mapa base / bloco | | aircraft, plane / flight / military flights | aeronave, avião / voo / voos militares | -| vessel, ship | embarcação | +| vessel, ship / TANKER (AIS class) | embarcação / NAVIO-TANQUE | | satellite / shell (Starlink) / DENSE | satélite / camada orbital / DENSO | +| SPARSE / BALANCED / DENSE (detection modes) | ESPARSO / EQUILIBRADO / DENSO (o modo) | | launch (rocket) / launch site / space mission | lançamento / local de lançamento / missão espacial | +| KM DOWNRANGE / EST. DOWNRANGE | KM DO LOCAL DE LANÇAMENTO / EST. PELA DIST. DO LANÇAMENTO | | ascent / replay / payload / stage | subida / reprise / carga útil / estágio | | contact / tracking / track | contato / rastreamento / rastro | | installation / site | instalação / local | +| PLACES CANDIDATE (installation class) | CANDIDATO DO GOOGLE PLACES | | mapped / observed | mapeado / observado | | camera / CCTV camera | câmera / câmera de CCTV | +| CALIBRATED / CURATED (CCTV badge) | CALIBRADA / COM CURADORIA | +| AUTO HOP ON / OFF (CCTV) | TROCA AUTO. LIGADA / DESLIG. (as the other CCTV toggles) | | earthquake / active fire | terremoto / incêndio ativo | | advisory (NHC/CPHC cyclone) | boletim | +| weather (layer, card) / weather satellite | clima / meteorologia, meteorológico | +| FOG / cloud unknown | NEVOEIRO / nebulosidade desconhecida | +| AQHI bands Low … Very High | Risco baixo … Risco muito alto | | radio station / broadcaster | estação de rádio / emissora | +| Oldies / World (radio tags) | Flashback / Músicas do mundo | | road / flow (traffic) | via / fluxo | | Street Level (layer) | Nível da rua | | scene / shot / scene recipe | cena / plano / receita de cena | | briefing / panel / dock | briefing / painel / dock | | cockpit | cabine | -| preset / visual preset | predefinição / predefinição visual | +| preset / visual preset / EXPORT PRESETS | predefinição / predefinição visual / EXPORTAR PREDEF. | | Scope (circular viewport mask) / keyhole | mira / visor | | feather / fade | suavização / esmaecimento | | detection overlay | sobreposição de detecção | @@ -76,6 +88,7 @@ The `many` form is the `other` text with «de» after the number: «{count} de c | Previous / Next (button text) | Anterior / Próximo (Próxima) | | L / R (relative bearing) | E / D | | SIG / NEWS / LOCAL (briefing tabs) | SIG / NOTÍCIAS / LOCAL | +| REGIONAL NEWS (fits the 16-character kicker) | NOTÍCIAS DA ÁREA | | PITCH / HGT (CCTV calibration chips) | INCL. / ALT. | | NOT AN ALL-CLEAR | NÃO GARANTE SEGURANÇA | | turn-by-turn: turn left / keep left / lane | vire à esquerda / mantenha-se à esquerda / faixa da esquerda | diff --git a/src/i18n/locales/es.json b/src/i18n/locales/es.json index 0285917b0..3db1ff129 100644 --- a/src/i18n/locales/es.json +++ b/src/i18n/locales/es.json @@ -2226,6 +2226,7 @@ "GOOGLE_MAPS_API_KEY is not set": "GOOGLE_MAPS_API_KEY no está configurada", "The Google Maps JavaScript API could not load": "No se pudo cargar la API de Maps JavaScript de Google", "Weather request timed out": "La petición del clima agotó el tiempo de espera", + "Cyclone request timed out": "La petición de ciclones agotó el tiempo de espera", "Malformed weather manifest": "Manifiesto del clima mal formado", "Weather HTTP {status}": "Clima: HTTP {status}", "Weather image HTTP {status}": "Imagen del clima: HTTP {status}", diff --git a/src/i18n/locales/pt.json b/src/i18n/locales/pt.json index 5f260e65b..9f2bbe765 100644 --- a/src/i18n/locales/pt.json +++ b/src/i18n/locales/pt.json @@ -49,7 +49,7 @@ "Rasuwagadhi witness video": "Vídeo de testemunha em Rasuwagadhi", "Bhote Koshi valley footage": "Imagens do vale do Bhote Koshi", "Flood footage": "Imagens da inundação", - "Compilation and casualty claims": "Compilação e relatos de vítimas", + "Compilation and casualty claims": "Compilação e relatos sobre vítimas", "SOURCE GEOCONFIRMED · WORLD-PINNED": "FONTE GEOCONFIRMADA · FIXADA NO MAPA", "SOURCE CREDITED · LOCATION UNRESOLVED": "FONTE CREDITADA · LOCAL NÃO DETERMINADO", "REFERENCE ONLY · CLAIMS UNVERIFIED": "SÓ REFERÊNCIA · RELATOS NÃO VERIFICADOS", @@ -242,7 +242,7 @@ "Map tiles temporarily unavailable": "Blocos do mapa temporariamente indisponíveis", "Mapped names temporarily unavailable": "Nomes mapeados temporariamente indisponíveis", "Overpass temporarily unavailable": "Overpass temporariamente indisponível", - "Retrying mapped sites…": "Tentando de novo os locais mapeados…", + "Retrying mapped sites…": "Buscando de novo os locais mapeados…", "Fetching mapped sites…": "Buscando locais mapeados…", "{reason} — retrying in {seconds}s": "{reason} — nova tentativa em {seconds} s", "{reason} — retry pending": "{reason} — nova tentativa pendente", @@ -271,7 +271,7 @@ "NAV": "NAV", "GNSS navigation — GPS, GLONASS, Galileo": "Navegação GNSS — GPS, GLONASS, Galileo", "GEO": "GEO", - "Geostationary belt — comms and weather, fixed over the equator": "Cinturão geoestacionário — comunicações e clima, fixo sobre o equador", + "Geostationary belt — comms and weather, fixed over the equator": "Cinturão geoestacionário — comunicações e meteorologia, fixo sobre o equador", "VISUAL": "VISUAL", "Brightest naked-eye objects — CelesTrak visual group": "Objetos mais brilhantes a olho nu — grupo visual do CelesTrak", "COMMS": "TELECOM", @@ -293,7 +293,7 @@ "HIGH-SPEED": "ALTA VELOCIDADE", "PASSENGER": "PASSAGEIROS", "CARGO": "CARGUEIRO", - "TANKER": "PETROLEIRO", + "TANKER": "NAVIO-TANQUE", "OTHER": "OUTROS", "Included in bundle": "Incluído no pacote", "Missing bundle file — reimport its bundle": "Arquivo ausente no pacote — importe o pacote de novo", @@ -306,7 +306,7 @@ "Opening space missions…": "Abrindo missões espaciais…", "Scanning active events…": "Varrendo eventos ativos…", "Live earthquakes and active fires, from USGS and NASA": "Terremotos e incêndios ativos ao vivo, de USGS e NASA", - "It feels like a forbidden cockpit—then you realize the sources are public and the data is real.": "Parece uma cabine proibida—até você perceber que as fontes são públicas e os dados são reais.", + "It feels like a forbidden cockpit—then you realize the sources are public and the data is real.": "Parece uma cabine proibida — até você perceber que as fontes são públicas e os dados são reais.", "Working…": "Processando…", "Could not open that mission{detail}. Retry or explore manually.": "Não foi possível abrir essa missão{detail}. Tente novamente ou explore manualmente.", "This browser is blocking storage, so that could not be saved.": "Este navegador está bloqueando o armazenamento, então não foi possível salvar.", @@ -340,7 +340,7 @@ "view band|GLOBAL": "GLOBAL", "SUMMARY": "RESUMO", "Awaiting telemetry...": "Aguardando telemetria...", - "REC": "GRAV", + "REC": "REC", "AIS: --": "AIS: --", "N/A": "N/D", "{mode} {band} {locality} | {region} | ALT {alt} | WINDOW {window} | SUN {sun}° | ONA {ona}° | {zone}": "{mode} · {band} · {locality} | {region} | ALT {alt} | JANELA {window} | SOL {sun}° | ONA {ona}° | {zone}", @@ -356,11 +356,11 @@ "other": "ATIVAR · {count} CHAVES PENDENTES" }, "POWERED UP": "ATIVADO", - "Provider Settings does not answer proxied requests": "Configurações de provedores não responde a requisições via proxy", + "Provider Settings does not answer proxied requests": "O painel \"Configurações de provedores\" não responde a requisições via proxy", "Provider Settings is disabled while sharing is enabled": "O painel \"Configurações de provedores\" fica desativado enquanto o compartilhamento estiver ativo", - "Provider Settings answers only the machine running the server": "Configurações de provedores só responde à máquina que executa o servidor", - "Provider Settings answers only local hostnames": "Configurações de provedores só responde a nomes de host locais", - "Provider Settings requires an exact local Origin": "Configurações de provedores exige um Origin local exato", + "Provider Settings answers only the machine running the server": "O painel \"Configurações de provedores\" só responde à máquina que executa o servidor", + "Provider Settings answers only local hostnames": "O painel \"Configurações de provedores\" só responde a nomes de host locais", + "Provider Settings requires an exact local Origin": "O painel \"Configurações de provedores\" exige um Origin local exato", "Unrecognized Origin refused": "Origin não reconhecido: requisição recusada", "Cross-origin requests are refused": "Requisições de outra origem são recusadas", "Content-Type must be application/json": "Content-Type deve ser application/json", @@ -426,7 +426,7 @@ "Places context + Street View fallback; optional separate key": "Contexto de lugares + Street View como alternativa; chave separada opcional", "Voice control — API key or ChatGPT OAuth": "Controle por voz — chave de API ou OAuth do ChatGPT", "Gemini Live voice control": "Controle por voz com Gemini Live", - "Live ships, worldwide": "Navios ao vivo, no mundo todo", + "Live ships, worldwide": "Embarcações ao vivo, no mundo todo", "Live active-fire detections": "Detecções de incêndios ativos ao vivo", "Real live traffic (keyless runs a simulation)": "Trânsito real ao vivo (sem chave, roda uma simulação)", "Bing imagery map stacks + world terrain": "Pilhas de mapas com imagens do Bing + relevo mundial", @@ -442,13 +442,13 @@ "other": "{count} estações com dados" }, "Highest air-quality readings in view": "Leituras de qualidade do ar mais altas na vista", - "Low": "Baixa", + "Low": "Risco baixo", "Low health risk": "Risco baixo para a saúde", - "Moderate": "Moderada", + "Moderate": "Risco moderado", "Moderate health risk": "Risco moderado para a saúde", - "High": "Alta", + "High": "Risco alto", "High health risk": "Risco alto para a saúde", - "Very High": "Muito alta", + "Very High": "Risco muito alto", "Very High health risk": "Risco muito alto para a saúde", "Air quality": "Qualidade do ar", "Canada only · ECCC AQHI network": "Só Canadá · rede AQHI do ECCC", @@ -473,7 +473,7 @@ "many": "{count} de câmeras próximas", "other": "{count} próximas" }, - "retrying mapped ALPR cameras": "tentando de novo as câmeras ALPR mapeadas", + "retrying mapped ALPR cameras": "buscando de novo as câmeras ALPR mapeadas", "loading mapped ALPR cameras": "carregando câmeras ALPR mapeadas", "No ALPR data for this area — US and Canada only": "Sem dados ALPR para esta área — só EUA e Canadá", "Zoom in to load mapped cameras": "Aproxime o zoom para carregar as câmeras mapeadas", @@ -520,7 +520,7 @@ "GBFS fetch error": "erro ao obter dados GBFS", "Station {id}": "Estação {id}", "Station": "Estação", - "🚲 {bikes} avail · {docks} docks · {capacity} cap": "🚲 {bikes} disp · {docks} docas · {capacity} cap", + "🚲 {bikes} avail · {docks} docks · {capacity} cap": "🚲 {bikes} disp. · {docks} vagas · {capacity} cap.", "⚠️ Not installed": "⚠️ Não instalada", "⚠️ Not renting": "⚠️ Sem aluguel", "⚠️ Not returning": "⚠️ Sem devolução", @@ -561,9 +561,9 @@ "many": "{count} de ciclones ativos", "other": "{count} ciclones ativos" }, - "Position as of {time}": "Posição às {time}", + "Position as of {time}": "Posição em {time}", "Maximum sustained wind: {wind} · Pressure: {pressure}": "Vento máximo sustentado: {wind} · Pressão: {pressure}", - "{name} · {classification} · Advisory {number} · issued {time}": "{name} · {classification} · Boletim {number} · emitido {time}", + "{name} · {classification} · Advisory {number} · issued {time}": "{name} · {classification} · Boletim {number} · emitido em {time}", "No active NHC/CPHC systems": "Nenhum sistema ativo do NHC/CPHC", "Advisories unavailable": "Boletins indisponíveis", "Cyclones · NHC / CPHC": "Ciclones · NHC / CPHC", @@ -785,7 +785,7 @@ "installation class|BASE": "BASE", "installation class|BARRACKS": "QUARTEL", "installation class|TRAINING AREA": "ÁREA DE TREINAMENTO", - "installation class|PLACES CANDIDATE": "DO GOOGLE PLACES", + "installation class|PLACES CANDIDATE": "CANDIDATO DO GOOGLE PLACES", "installation class|INSTALLATION": "INSTALAÇÃO", "No mapped sites within {km} km of the contact": "Nenhum local mapeado a até {km} km do contato", "{count} mapped sites within {km} km of the contact": { @@ -817,7 +817,7 @@ "UNSPECIFIED": "NÃO ESPECIFICADO", "+{count} additional payload records": "+{count} registros de carga útil adicionais", "PAYLOAD DATA UNAVAILABLE": "DADOS DA CARGA ÚTIL INDISPONÍVEIS", - "{value} KM DOWNRANGE": "{value} KM DE PERCURSO", + "{value} KM DOWNRANGE": "A {value} KM DO LOCAL DE LANÇAMENTO", "POSITION UNAVAILABLE": "POSIÇÃO INDISPONÍVEL", "FLIGHT {count}": "VOO {count}", "REUSED": "REUTILIZADO", @@ -858,7 +858,7 @@ "SHOW ALL / DESELECT": "MOSTRAR TODAS / DESMARCAR", "Pause replay": "Pausar reprise", "Cancel replay": "Cancelar reprise", - "EST. DOWNRANGE": "DIST. ESTIMADA", + "EST. DOWNRANGE": "EST. PELA DIST. DO LANÇAMENTO", "PLANNED · ": "PLANEJADO · ", "SUPPLIED TRAJECTORY POINTS": "PONTOS DE TRAJETÓRIA FORNECIDOS", "RECONSTRUCTED ESTIMATE": "ESTIMATIVA RECONSTRUÍDA", @@ -880,7 +880,7 @@ "Your decoder feed": "Seu feed do decodificador", "Your RTL-SDR receiver": "Seu receptor RTL-SDR", "NO CALLSIGN": "SEM INDICATIVO", - "ALT {altitude} FT · GS {speed} KT · TRK {track}": "ALT {altitude} FT · VEL. SOLO {speed} KT · TRK {track}", + "ALT {altitude} FT · GS {speed} KT · TRK {track}": "ALT {altitude} FT · GS {speed} KT · TRK {track}", "V/S {rate}": "VEL. VERT. {rate}", "V/S {rate} FPM": "VEL. VERT. {rate} FT/MIN", "POSITION {age}": "POSIÇÃO {age}", @@ -984,7 +984,7 @@ "Jazz": "Jazz", "Latin": "Latina", "Metal": "Metal", - "Oldies": "Clássicos", + "Oldies": "Flashback", "Pop": "Pop", "Punk": "Punk", "R&B": "R&B", @@ -993,7 +993,7 @@ "Soul": "Soul", "Techno": "Techno", "Trance": "Trance", - "World": "Mundial", + "World": "Músicas do mundo", "overview": "visão geral", "cloud unknown": "nebulosidade desconhecida", "{percent}% scene cloud": "{percent}% de nuvens na cena", @@ -1176,9 +1176,9 @@ "API key rejected — check AISSTREAM_API_KEY": "Chave de API recusada — verifique a AISSTREAM_API_KEY", "feed silent {seconds}s — no AIS data": "feed em silêncio há {seconds} s — sem dados AIS", "feed silent — no AIS data": "feed em silêncio — sem dados AIS", - "feed down — retrying slowly (attempt {attempt})": "feed fora do ar — tentando de novo devagar (tentativa {attempt})", + "feed down — retrying slowly (attempt {attempt})": "feed fora do ar — tentando de novo em intervalos maiores (tentativa {attempt})", "reconnecting to feed… (attempt {attempt})": "reconectando ao feed… (tentativa {attempt})", - "feed down — retrying slowly": "feed fora do ar — tentando de novo devagar", + "feed down — retrying slowly": "feed fora do ar — tentando de novo em intervalos maiores", "reconnecting to feed…": "reconectando ao feed…", "Focus vessel {name}, MMSI {mmsi}": "Focar a embarcação {name}, MMSI {mmsi}", "Hidden by this map source · choose a globe map": "Oculto com esta fonte do mapa · escolha um mapa de globo", @@ -1258,6 +1258,7 @@ "Some weather tiles unavailable": "Alguns blocos meteorológicos indisponíveis", "Malformed weather manifest": "Manifesto do clima malformado", "Weather request timed out": "A requisição do clima excedeu o tempo limite", + "Cyclone request timed out": "A requisição de ciclones excedeu o tempo limite", "Temperature field unavailable": "Campo de temperatura indisponível", "Mean sea level pressure field unavailable": "Campo de pressão ao nível do mar indisponível", "Wind upstream unavailable": "Origem dos dados de vento indisponível", @@ -1287,7 +1288,7 @@ "Temperature": "Temperatura", "Wind trails with no field shading": "Rastros de vento sem sombreamento do campo", "How hard the surface wind is blowing": "Com que força o vento sopra na superfície", - "Sea-level air pressure: broad highs and lows": "Pressão do ar ao nível do mar: altas e baixas amplas", + "Sea-level air pressure: broad highs and lows": "Pressão do ar ao nível do mar: amplas áreas de alta e baixa pressão", "Air temperature two meters above the surface": "Temperatura do ar a dois metros acima da superfície", "Wind speed units": "Unidades de velocidade do vento", "Read wind at map center": "Ler o vento no centro do mapa", @@ -1327,7 +1328,7 @@ " · calm": " · calmo", " from {direction}": " de {direction}", "WIND AT {coordinates}": "VENTO EM {coordinates}", - "{model} · valid {time}": "{model} · válida {time}", + "{model} · valid {time}": "{model} · válida para {time}", "Wind speed field unavailable": "Campo de velocidade do vento indisponível", "Globe imagery unavailable": "Imagens do globo indisponíveis", "Globe field image unavailable": "Imagem do campo no globo indisponível", @@ -1339,7 +1340,7 @@ "Error: {message}": "Erro: {message}", "Needs {envVars} — add it in Provider Settings": "Requer {envVars} — adicione em Configurações de provedores", "{label} is unavailable": "{label} indisponível", - "This map stack": "Esta pilha de mapa", + "This map stack": "Esta pilha de mapas", "{label} unavailable: {hint}": "{label} indisponível: {hint}", "Google 3D tiles unavailable — check the key's API restrictions, quota, or network": "Google 3D Tiles indisponível — verifique as restrições de API da chave, a cota ou a rede", "Needs {envVars} — add it in Provider Settings — or a Cesium ion token for the ion-hosted route": "Requer {envVars} — adicione em Configurações de provedores — ou um token do Cesium ion para a rota hospedada no ion", @@ -1596,15 +1597,15 @@ "FRAME · LOADING": "QUADRO · CARREGANDO", "FRAME · UNAVAILABLE": "QUADRO · INDISPONÍVEL", "CALIBRATED": "CALIBRADA", - "CURATED": "CURADA", + "CURATED": "COM CURADORIA", "RAW PRIOR": "ESTIMATIVA BRUTA", "CCTV ON": "CCTV LIGADO", "CCTV OFF": "CCTV DESLIG.", "VIEWSHED ON": "ÁREA VISÍVEL LIGADA", "COVERAGE ON": "COBERTURA LIGADA", "COVERAGE OFF": "COBERTURA DESLIG.", - "AUTO HOP ON": "AUTO SALTO LIGADO", - "AUTO HOP OFF": "AUTO SALTO DESLIG.", + "AUTO HOP ON": "TROCA AUTO. LIGADA", + "AUTO HOP OFF": "TROCA AUTO. DESLIG.", "PROJECTION ON": "PROJEÇÃO LIGADA", "PROJECTION OFF": "PROJEÇÃO DESLIG.", "CAL · EDITED (UNSAVED)": "CAL · EDITADA (NÃO SALVA)", @@ -1633,7 +1634,7 @@ "CLEAR": "CÉU LIMPO", "PARTLY CLOUDY": "PARCIALMENTE NUBLADO", "OVERCAST": "ENCOBERTO", - "FOG": "NEBLINA", + "FOG": "NEVOEIRO", "DRIZZLE": "GAROA", "RAIN": "CHUVA", "RAIN SHOWERS": "PANCADAS DE CHUVA", @@ -1644,17 +1645,17 @@ "CYCLE OFF": "CICLO DESLIG.", "Stop automatic page cycling. Previous, Next, and the SIG/NEWS/LOCAL tabs stay available.": "Parar a rotação automática de páginas. Anterior, Próxima e as abas SIG/NOTÍCIAS/LOCAL continuam disponíveis.", "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.": "Alterna as páginas do briefing automaticamente a cada 9 segundos (Sinais → Notícias → Local). Pausa enquanto você passa o mouse ou foca o painel. Os dados de sinais ao vivo continuam atualizando de qualquer forma.", - "ACQUIRING REGIONAL NEWS": "OBTENDO NOTÍCIAS LOCAIS", - "REGIONAL NEWS UNAVAILABLE": "NOTÍCIAS LOCAIS INDISPONÍVEIS", + "ACQUIRING REGIONAL NEWS": "OBTENDO NOTÍCIAS DA ÁREA", + "REGIONAL NEWS UNAVAILABLE": "NOTÍCIAS DA ÁREA INDISPONÍVEIS", "RESOLVING REGION": "IDENTIFICANDO REGIÃO", "REGION UNAVAILABLE": "REGIÃO INDISPONÍVEL", "NO RECENT LOCATION MATCHES": "NENHUMA CORRESPONDÊNCIA RECENTE COM O LOCAL", "{domain} · {age}": "{domain} · {age}", "{value} KM/H": "{value} KM/H", "CLOUD {pct}%": "NUVENS {pct}%", - "CLOUD UNKNOWN": "NUVENS DESCONHECIDAS", + "CLOUD UNKNOWN": "NEBULOSIDADE DESCONHECIDA", "{source} · LOCATION QUERY": "{source} · CONSULTA POR LOCAL", - "REGIONAL NEWS": "NOTÍCIAS LOCAIS", + "REGIONAL NEWS": "NOTÍCIAS DA ÁREA", "{label} · {radius} AIR/SEA WINDOW": "{label} · AR/MAR {radius}", "{scope} · INSTALLATIONS {coverage}": "{scope} · INSTALAÇÕES: {coverage}", "CONTEXT STANDBY": "CONTEXTO EM ESPERA", @@ -1676,8 +1677,8 @@ }, "AVAILABLE INPUTS CURRENT · NOT AN ALL-CLEAR": "ENTRADAS DISPONÍVEIS ATUAIS · NÃO GARANTE SEGURANÇA", "SQUAWK {code} · {status}": "SQUAWK {code} · {status}", - "ADS-B PRIORITY · {status}": "ADS-B PRIORIDADE · {status}", - "ADS-B EMERGENCY · {status}": "ADS-B EMERGÊNCIA · {status}", + "ADS-B PRIORITY · {status}": "PRIORIDADE ADS-B · {status}", + "ADS-B EMERGENCY · {status}": "EMERGÊNCIA ADS-B · {status}", "AIRCRAFT": "AERONAVE", "ACQUIRING SURFACE": "ADQUIRINDO SUPERFÍCIE", "SURFACE FALLBACK": "SUPERFÍCIE ALTERNATIVA", @@ -1698,7 +1699,7 @@ "Anime": "Anime", "Noir": "Noir", "Snow": "Neve", - "Current cockpit vision style: {style}. Activate for next style.": "Estilo de visão da cabine atual: {style}. Ative para o próximo estilo.", + "Current cockpit vision style: {style}. Activate for next style.": "Estilo atual de visão da cabine: {style}. Ative para o próximo estilo.", "Current style: {style} — click for next": "Estilo atual: {style} — clique para o próximo", "Collapse Contact panel": "Recolher painel de contato", "Expand Contact panel": "Expandir painel de contato", @@ -1794,7 +1795,7 @@ "{requirement}, or {offer}": "{requirement}, ou {offer}", "Live Flights": "Voos ao vivo", "Military Flights": "Voos militares", - "Earthquakes (24h)": "Terremotos (24h)", + "Earthquakes (24h)": "Terremotos (24 h)", "Satellites": "Satélites", "Space Missions (30d)": "Missões espaciais (30 d)", "Street Traffic": "Trânsito urbano", @@ -2093,7 +2094,7 @@ "Download {slot} as a PNG": "Baixar {slot} como PNG", "Download the image as a PNG": "Baixar a imagem como PNG", "Box {width} × {height} km": "Área de {width} × {height} km", - "Acquired {time}": "Adquirida {time}", + "Acquired {time}": "Adquirida em {time}", "Coverage {coverage}": "Cobertura {coverage}", "START HERE · {reason}": "COMECE AQUI · {reason}", "Daily overview shows little detail in a box this small": "A visão geral diária mostra pouco detalhe em uma área tão pequena", @@ -2116,8 +2117,8 @@ "Delete scene \"{scene}\" and all shots?": "Excluir a cena \"{scene}\" e todos os planos?", "Delete shot \"{shot}\"?": "Excluir o plano \"{shot}\"?", "Stopped (Esc)": "Parado (Esc)", - "SPARSE": "ESPARSA", - "BALANCED": "EQUILIBRADA", + "SPARSE": "ESPARSO", + "BALANCED": "EQUILIBRADO", "No shots yet. Use CAPTURE SHOT to save current look.": "Ainda não há planos. Use CAPTURAR PLANO para salvar o visual atual.", "Double-click to rename": "Clique duplo para renomear", "Shot name": "Nome do plano", @@ -2155,14 +2156,14 @@ "SHARED {subject}": "COMPARTILHADO: {subject}", "subject": "alvo", "LOADING LIVE DATA": "CARREGANDO DADOS AO VIVO", - "LOAD COMPLETE": "CARGA CONCLUÍDA", - "LOAD CANCELLED": "CARGA CANCELADA", - "LOAD FAILED": "FALHA NA CARGA", + "LOAD COMPLETE": "CARREGAMENTO CONCLUÍDO", + "LOAD CANCELLED": "CARREGAMENTO CANCELADO", + "LOAD FAILED": "FALHA NO CARREGAMENTO", "LIVE DATA OFF": "DADOS AO VIVO DESLIGADOS", "MAPPED SITES LOADED": "LOCAIS MAPEADOS CARREGADOS", - "RETRYING MAPPED SITES": "TENTANDO DE NOVO OS LOCAIS MAPEADOS", + "RETRYING MAPPED SITES": "BUSCANDO DE NOVO OS LOCAIS MAPEADOS", "FETCHING MAPPED SITES": "BUSCANDO LOCAIS MAPEADOS", - "RETRYING ALPR CAMERAS": "TENTANDO DE NOVO AS CÂMERAS ALPR", + "RETRYING ALPR CAMERAS": "BUSCANDO DE NOVO AS CÂMERAS ALPR", "FETCHING ALPR CAMERAS": "BUSCANDO CÂMERAS ALPR", "OVERPASS TEMPORARILY UNAVAILABLE": "OVERPASS TEMPORARIAMENTE INDISPONÍVEL", "OVERPASS RATE-LIMITED": "OVERPASS COM LIMITE DE REQUISIÇÕES", @@ -2306,9 +2307,9 @@ "{time} · {minutes} min ago": "{time} · há {minutes} min", "Active weather": "Camadas de clima ativas", "LATEST · newest per product": "MAIS RECENTE · último por produto", - "Forecast · valid {valid} · issued {issued}": "Previsão · válida {valid} · emitida {issued}", + "Forecast · valid {valid} · issued {issued}": "Previsão · válida para {valid} · emitida em {issued}", "{detail} · Does not follow history": "{detail} · Não acompanha o histórico", - "Forecast · valid {valid}": "Previsão · válida {valid}", + "Forecast · valid {valid}": "Previsão · válida para {valid}", "voice|OFF": "DESLIG.", "voice|CONNECTING": "CONECT…", "voice|LISTENING": "OUVINDO", @@ -2703,9 +2704,9 @@ "FIRST PERSON": "PRIMEIRA PESSOA", "LIVE TRACK · COURSE ALIGNED": "RASTRO AO VIVO · CURSO ALINHADO", "Cockpit vision style": "Estilo de visão da cabine", - "Previous cockpit vision style": "Estilo de visão da cabine anterior", + "Previous cockpit vision style": "Estilo anterior de visão da cabine", "Previous vision style": "Estilo de visão anterior", - "Current cockpit vision style: NORMAL. Activate for next style.": "Estilo de visão da cabine atual: NORMAL. Ative para o próximo estilo.", + "Current cockpit vision style: NORMAL. Activate for next style.": "Estilo atual de visão da cabine: NORMAL. Ative para o próximo estilo.", "Current style: NORMAL — click for next": "Estilo atual: NORMAL — clique para o próximo", "CURRENT": "ATUAL", "Next cockpit vision style": "Próximo estilo de visão da cabine", @@ -2736,7 +2737,7 @@ "Previous briefing page": "Página anterior do briefing", "Next briefing page": "Próxima página do briefing", "Live signals": "Sinais ao vivo", - "Latest regional news": "Últimas notícias locais", + "Latest regional news": "Últimas notícias da área", "Location-based information": "Informações baseadas na localização", "TEMP": "TEMP", "WIND": "VENTO", @@ -2748,7 +2749,7 @@ "SIG": "SIG", "Show Live Signals": "Mostrar sinais ao vivo", "NEWS": "NOTÍCIAS", - "Show Regional News": "Mostrar notícias locais", + "Show Regional News": "Mostrar notícias da área", "LOCAL": "LOCAL", "Show Local Info": "Mostrar informações locais", "Cockpit display and Radio controls": "Controles de exibição e rádio da cabine", @@ -2819,7 +2820,7 @@ "Internet radio and local SDR": "Rádio pela internet e SDR local", "STATION TAG": "TAG DA ESTAÇÃO", "Filter stations by station tag": "Filtrar estações por tag", - "All": "Todas", + "All": "Todos", "Enable Radio, then choose a globe marker or use next.": "Ative o rádio e escolha um marcador no globo ou use Próxima.", "DRAG TO TUNE": "ARRASTE PARA SINTONIZAR", "Tune available internet radio stations": "Sintonizar as estações de rádio pela internet disponíveis", @@ -2834,7 +2835,7 @@ "Radio volume": "Volume do rádio", "STATION SITE": "SITE DA ESTAÇÃO", "DIRECTORY: RADIO BROWSER": "DIRETÓRIO: RADIO BROWSER", - "Audio connects directly to the broadcaster after you press play. Your IP is visible to that broadcaster.": "O áudio conecta direto à emissora depois que você aperta play. Seu IP fica visível para essa emissora.", + "Audio connects directly to the broadcaster after you press play. Your IP is visible to that broadcaster.": "O áudio conecta direto à emissora depois que você aperta \"Ouvir\". Seu IP fica visível para essa emissora.", "Local RTL-SDR receiver": "Receptor RTL-SDR local", "LOCAL RTL-SDR": "RTL-SDR LOCAL", "Chrome/Edge · WebUSB · one local tuner shared by FM and the Local ADS-B layer.": "Chrome/Edge · WebUSB · um sintonizador local compartilhado entre o FM e a camada ADS-B local.", @@ -2872,7 +2873,7 @@ "Sonar intensity": "Intensidade do sonar", "Opacity": "Opacidade", "Cyber contact and label opacity": "Opacidade de contatos e rótulos Ciber", - "Minimum opacity for map dots, icons, models, brackets, and labels between sonar passes": "Opacidade mínima de pontos, ícones, modelos, colchetes e rótulos do mapa entre as passagens do sonar", + "Minimum opacity for map dots, icons, models, brackets, and labels between sonar passes": "Opacidade mínima de pontos, ícones, modelos, marcadores de alvo e rótulos do mapa entre as passagens do sonar", "Sector": "Setor", "Sonar sector width": "Largura do setor do sonar", "Detection Overlay (D)": "Sobreposição de detecção (D)", @@ -2972,14 +2973,14 @@ "CAPTURE SHOT": "CAPTURAR PLANO", "UPDATE SHOT": "ATUALIZAR PLANO", "START": "INICIAR", - "EXPORT PRESETS": "EXPORTAR PREDEFINIÇÕES", + "EXPORT PRESETS": "EXPORTAR PREDEF.", "IMPORT": "IMPORTAR", "RUN LOG": "REGISTRO", "POWER UP": "ATIVAR", "GROUND STATION · PROVIDER SETTINGS": "ESTAÇÃO TERRESTRE · CONFIGURAÇÕES DE PROVEDORES", "Close key setup": "Fechar configuração de chaves", "Power up the globe": "Ative o globo", - "The globe already flies keyless. Every key below switches on another real feed — paste one and it's saved into this app's local configuration, then the server restarts itself. Server-side keys stay on this machine; Google Maps and Cesium ion run in the browser and must be provider-restricted. Keys you configured elsewhere are shown but never touched.": "O globo já voa sem chaves. Cada chave abaixo ativa mais uma fonte real — cole uma e ela será salva na configuração local deste app, e então o servidor reinicia sozinho. As chaves do servidor ficam nesta máquina; Google Maps e Cesium ion rodam no navegador e devem ser restritas ao provedor. Chaves configuradas em outro lugar são exibidas, mas nunca alteradas.", + "The globe already flies keyless. Every key below switches on another real feed — paste one and it's saved into this app's local configuration, then the server restarts itself. Server-side keys stay on this machine; Google Maps and Cesium ion run in the browser and must be provider-restricted. Keys you configured elsewhere are shown but never touched.": "O globo já voa sem chaves. Cada chave abaixo ativa mais uma fonte real — cole uma e ela será salva na configuração local deste app, e então o servidor reinicia sozinho. As chaves do servidor ficam nesta máquina; as chaves do Google Maps e do Cesium ion são usadas no navegador e precisam ter restrições de uso configuradas no respectivo provedor. Chaves configuradas em outro lugar são exibidas, mas nunca alteradas.", "SAVE KEYS": "SALVAR CHAVES", "ESC to close": "ESC para fechar", "The Google Maps key buys the photorealistic planet — everything else stacks on top.": "A chave do Google Maps libera o planeta fotorrealista — todo o resto se soma a ela.", @@ -2995,7 +2996,7 @@ "MISSION CONTROL · FIRST LAUNCH": "CENTRO DE CONTROLE · PRIMEIRO ACESSO", "Choose your first view": "Escolha sua primeira vista", "LIVE CONTACTS": "CONTATOS AO VIVO", - "Aircraft, vessels and nearby intelligence": "Aeronaves, embarcações e inteligência próxima", + "Aircraft, vessels and nearby intelligence": "Aeronaves, embarcações e informações da região", "Launches, spacecraft and orbital context": "Lançamentos, espaçonaves e contexto orbital", "EXPLORE MANUALLY": "EXPLORAR MANUALMENTE", "Begin with a clean globe": "Comece com um globo limpo", diff --git a/src/i18n/locales/ru.json b/src/i18n/locales/ru.json index b1c1be229..93e2b871d 100644 --- a/src/i18n/locales/ru.json +++ b/src/i18n/locales/ru.json @@ -2262,6 +2262,7 @@ "GOOGLE_MAPS_API_KEY is not set": "GOOGLE_MAPS_API_KEY не задан", "The Google Maps JavaScript API could not load": "Не удалось загрузить Google Maps JavaScript API", "Weather request timed out": "Истекло время ожидания запроса погоды", + "Cyclone request timed out": "Истекло время ожидания запроса циклонов", "Malformed weather manifest": "Некорректный манифест погоды", "Weather HTTP {status}": "Погода: HTTP {status}", "Weather image HTTP {status}": "Снимок погоды: HTTP {status}", diff --git a/src/i18n/locales/zh-CN.json b/src/i18n/locales/zh-CN.json index 9bf76700c..aca16f65a 100644 --- a/src/i18n/locales/zh-CN.json +++ b/src/i18n/locales/zh-CN.json @@ -1202,6 +1202,7 @@ "Some weather tiles unavailable": "部分天气瓦片不可用", "Malformed weather manifest": "天气清单格式错误", "Weather request timed out": "天气请求超时", + "Cyclone request timed out": "气旋请求超时", "Temperature field unavailable": "温度场不可用", "Mean sea level pressure field unavailable": "平均海平面气压场不可用", "Wind upstream unavailable": "风场上游数据源不可用", diff --git a/src/i18n/locales/zh-Hant.json b/src/i18n/locales/zh-Hant.json index d95a18e39..9fe469f6e 100644 --- a/src/i18n/locales/zh-Hant.json +++ b/src/i18n/locales/zh-Hant.json @@ -1197,6 +1197,7 @@ "Some weather tiles unavailable": "部分天氣瓦片不可用", "Malformed weather manifest": "天氣清單格式錯誤", "Weather request timed out": "天氣請求超時", + "Cyclone request timed out": "氣旋請求超時", "Temperature field unavailable": "溫度場不可用", "Mean sea level pressure field unavailable": "平均海平面氣壓場不可用", "Wind upstream unavailable": "風場上游數據源不可用", diff --git a/src/i18n/same-as-english.json b/src/i18n/same-as-english.json index 920016262..90abbc6a8 100644 --- a/src/i18n/same-as-english.json +++ b/src/i18n/same-as-english.json @@ -129,6 +129,7 @@ "978 MHz UAT", "AIS: --", "AIS: {name}", + "ALT {altitude} FT · GS {speed} KT · TRK {track}", "ALTITUDE", "ALTITUDE · FT", "ANIME", @@ -202,6 +203,7 @@ "Pop", "Punk", "RANGE", + "REC", "Reggae", "Rock", "S2 GhostMaps", diff --git a/src/layers/cyclones/source.js b/src/layers/cyclones/source.js index 05c805fbd..e0039a20e 100644 --- a/src/layers/cyclones/source.js +++ b/src/layers/cyclones/source.js @@ -1,5 +1,9 @@ import { readResponseJsonCapped } from '../../sources/httpBody.js'; +// Shared with the AI tools, so no i18n import: the timeout stays English here +// and the cyclones layer translates it where it shows it (translateKnown). +const msg = (text) => text; + export const CYCLONE_RESPONSE_LIMIT = 4 * 1024 * 1024; const malformed = () => new Error('Malformed cyclone snapshot'); const text = (value, max = 160) => { @@ -215,7 +219,7 @@ export function createCycloneSource({ const abort = () => controller.abort(signal.reason); signal?.addEventListener('abort', abort, { once: true }); const timer = setTimeout( - () => controller.abort(new Error('Cyclone request timed out')), + () => controller.abort(new Error(msg('Cyclone request timed out'))), timeoutMs, ); try { diff --git a/src/scenes/recipes.js b/src/scenes/recipes.js index ba3940a57..348579744 100644 --- a/src/scenes/recipes.js +++ b/src/scenes/recipes.js @@ -1062,24 +1062,37 @@ export function displaySceneTitle(scene) { * typed. Without `shot`, the title alone decides. * @param {string} title * @param {{sourcePackId?: string}} [shot] - * @param {{id?: string}} [scene] The shot's scene, for projects saved before - * shots recorded their source pack. + * @param {{id?: string, appliedShotPacks?: {id: string}[]}} [scene] The + * shot's scene, for shots without a source pack: projects saved before + * shots recorded one, and the legacy base shots a pack bootstrap rewrote. * @returns {string} */ export function displayShotTitle(title, shot = undefined, scene = undefined) { const text = typeof title === 'string' ? title : ''; const fromRecipe = shot - ? Boolean(shot.sourcePackId) || recipeDeclaresShotTitle(scene?.id, text) + ? Boolean(shot.sourcePackId) || recipeDeclaresShotTitle(scene, text) : true; if (fromRecipe && BUILTIN_SHOT_TITLES.has(text)) return t(text); const numbered = /^Shot ([1-9]\d*)$/.exec(text); return numbered ? t('Shot {n}', { n: numbered[1] }) : text; } -/** Whether the built-in recipe behind a scene declares a shot with this title. */ -function recipeDeclaresShotTitle(sceneId, title) { - const recipe = sceneId ? getSceneRecipeById(sceneId) : null; - return Boolean( - recipe?.cameraPath?.some((keyframe) => keyframe?.title === title), +/** + * Whether the built-in recipe behind a scene declares a shot with this title: + * its own keyframes, or the legacy base shots an applied append pack wrote + * (those carry no sourcePackId, see SceneDirector._bootstrapLegacyShotPacks). + */ +function recipeDeclaresShotTitle(scene, title) { + const declares = (cameraPath) => + Boolean(cameraPath?.some((keyframe) => keyframe?.title === title)); + const recipe = scene?.id ? getSceneRecipeById(scene.id) : null; + if (declares(recipe?.cameraPath)) return true; + const packs = Array.isArray(scene?.appliedShotPacks) + ? scene.appliedShotPacks + : []; + return packs.some((entry) => + declares( + getSceneAppendRecipeById(entry?.id)?.legacySceneBootstrap?.cameraPath, + ), ); } diff --git a/src/scenes/sceneTitleDisplay.test.mjs b/src/scenes/sceneTitleDisplay.test.mjs index 604e01c49..2a9aad9f9 100644 --- a/src/scenes/sceneTitleDisplay.test.mjs +++ b/src/scenes/sceneTitleDisplay.test.mjs @@ -141,3 +141,26 @@ test('the scene context of a shot carries its display title by provenance', asyn title, ); }); + +test('legacy base shots of an applied append pack show their built-in names', async () => { + const { SCENE_APPEND_RECIPES } = await import('./recipes.js'); + const pack = SCENE_APPEND_RECIPES.find( + (recipe) => recipe.legacySceneBootstrap?.cameraPath?.length, + ); + if (!pack) return; + setLocale('ru'); + const title = pack.legacySceneBootstrap.cameraPath[0].title; + const shot = { id: 'legacy-base', title }; + // The bootstrap writes these shots without sourcePackId, into a scene whose + // own recipe only declares "Shot N". + assert.equal( + displayShotTitle(title, shot, { + id: 'bhote-koshi-nepal-scene', + appliedShotPacks: [{ id: pack.id, version: pack.version }], + }), + displayShotTitle(title), + ); + assert.notEqual(displayShotTitle(title), title); + // Without the pack marker the same title in another scene stays as typed. + assert.equal(displayShotTitle(title, shot, { id: 'scene-user' }), title); +}); From 1eb9e06c49c6935e99f109d32ee7130083e1e2bb Mon Sep 17 00:00:00 2001 From: German Khokhlov Date: Wed, 28 Oct 2026 17:00:16 +0400 Subject: [PATCH 27/83] i18n(de): apply review round 1 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Meaning fixes: playback connects to the broadcaster when it starts, browser keys are restricted at the provider, clearing data layers switches them off (ausschalten, not löschen), cockpit inputs are Quellen, Electronic is Elektronische Musik, AIS types name vessels (SEGLER, LOTSENBOOT, SANITÄTSDIENST, SCHNELLSCHIFF), contiguous US excludes Alaska/Hawaii, wind and weather readings are model values, nearest frames are nearest in time, cloud imagery and the brightness filter say what they are. - NHC/CPHC advisories are Lageberichte, not Warnungen; cyclone strings use Wirbelsturm throughout. Glossary updated. - Grammar: " oder " keeps its space as a join separator, "{x} konnte nicht sauber beendet werden", Then: no longer doubles Dann, scene save reasons continue the sentence in lower case, neutral "Warten auf". - Spacing between numbers and units in the remaining nine readouts. - Reroute tooltip: German mode nouns keep their capital (Auto, Fahrrad). - Built-in Nepal shot titles localize in every language: the legacy scene upgrade rebuilds its base shots without sourcePackId, so the pack's own shots in the scene now vouch for them. - Layout: the layer status column no longer shrinks under a wide chip, and a mixed-case compound (ALPR-Kameras) may break at its hyphen; only capital codes (ADS-B, RTL-SDR) stay unbroken. WIRD AKTIVIERT overlapped the name. The Bhote step meta line may take a third line. Co-Authored-By: Claude Opus 5.5 --- docs/translations/de.md | 11 +- src/data/directions.test.mjs | 16 ++ src/i18n/locales/de.json | 246 +++++++++++++------------- src/layers/directions/index.js | 20 ++- src/scenes/recipes.js | 23 ++- src/scenes/sceneTitleDisplay.test.mjs | 22 +++ src/ui/layerPanel.js | 8 +- src/ui/layerPanel.test.mjs | 9 + src/ui/styles/bhote-koshi.css | 5 +- src/ui/styles/radio.css | 6 + 10 files changed, 232 insertions(+), 134 deletions(-) diff --git a/docs/translations/de.md b/docs/translations/de.md index a66141a58..7a1984f19 100644 --- a/docs/translations/de.md +++ b/docs/translations/de.md @@ -13,9 +13,10 @@ Translation source: abiyeenzo (#908). - Short labels, chips and HUD readouts stay short. German runs about a third longer than English, so prefer a short word or a standard abbreviation with a period over a wrapped line: REICHW., GESCHW., NIEDERSCHL., SONST., NACHR., VERST., VGL., KAL. - The avionics codes HDG, BRG, CRS, DEST, SPD, ALT, GS, TRK, V/S, FOV and SQUAWK stay in English, as in the cockpit. Words used in a sentence are translated: heading → «Kurs», bearing → «Peilung», range → «Reichweite». - A dash between clauses is a spaced en dash « – »; a colon is fine where it explains: «Feed ausgefallen – langsame Wiederholung», «SIMULIERT: Verkehrsdienst nicht erreichbar». Quotes are „…“. +- Status and waiting messages use the neutral infinitive too: «Warten auf Aktualisierung», not «Warte auf …». Reasons inserted after a dash stay lower case: «Szene nicht gespeichert – das Projekt ist größer als 5 MiB». - Keyboard keys are named as on German keyboards where they differ: Leertaste, Rücktaste, Umschalt; Esc, Enter, Tab and letter keys stay. - Decimal comma in fixed text: «M4,4», «28,2710° N». Thousands separator is a period: «1.000 km». Formatted numbers come from `Intl` and are already German. -- Units: km, m, km/h, m/s, kn (knots, also in the cockpit), ft (feet), hPa, MW, h, min, s, T (days, in short readouts); in UPPERCASE text KM, KM/H, KN, FT, MIN. A space between number and unit: «{value} m», «{count} min», «50 %». `°` sticks to the number. +- Units: km, m, km/h, m/s, kn (knots, also in the cockpit), ft (feet), hPa, MW, h, min, s, T (days, in short readouts); in UPPERCASE text KM, KM/H, KN, FT, MIN. A space between number and unit, in compact readouts too: «{value} m», «{count} min», «50 %», «{speed} KN», «{count} / 30 T». `°` sticks to the number. - "ago" goes before the time: «vor {count} min», «vor {value}». When a placeholder already holds a localized "ago" text (`{age}` in `STALE · cached {age}`, `{ago}`), do not add «vor» again. - Compass points use O for Ost: N, NNO, NO, ONO, O, OSO, SO, SSO, S, SSW, SW, WSW, W, WNW, NW, NNW; hemisphere letters N, S, O, W. - Routing: direction words are lowercase adverbs (links, leicht rechts, scharf links, geradeaus), so a sentence never starts with one: «Auf {road} {direction} abbiegen», «Dann {direction} abbiegen», «Weiter {direction}». Roundabout exits are ordinals with a period: «die {exit} Ausfahrt» → «die 2. Ausfahrt». @@ -36,7 +37,7 @@ Keep the verb in agreement: «{count} Station meldet» / «{count} Stationen mel | English | Deutsch | | ---------------------------------------------- | -------------------------------------------------------------------- | | layer / data layer | Ebene / Datenebene | -| feed / source / data source | Feed / Quelle / Datenquelle | +| feed / source / data source / input (cockpit) | Feed / Quelle / Datenquelle / Quelle | | LIVE (status) / live data | LIVE / Live-Daten | | SIMULATED | SIMULIERT | | stale / degraded / unavailable | veraltet / eingeschränkt / nicht verfügbar | @@ -57,7 +58,7 @@ Keep the verb in agreement: «{count} Station meldet» / «{count} Stationen mel | mapped / observed | kartiert / beobachtet | | camera / CCTV camera / camera badge | Kamera / CCTV-Kamera / Kamera-Markierung | | earthquake / active fire / fire perimeter | Erdbeben / aktiver Brand / Brandgrenze | -| cyclone / advisory (NHC/CPHC) / cone | Wirbelsturm / Warnung / Kegel | +| cyclone / advisory (NHC/CPHC) / cone | Wirbelsturm / Lagebericht (not «Warnung») / Kegel | | radio station | Sender | | broadcast FM | UKW | | road / flow (traffic) | Straße / Verkehrsfluss | @@ -88,3 +89,7 @@ Keep the verb in agreement: «{count} Station meldet» / «{count} Stationen mel | voice (control) / voice session | Sprachsteuerung / Sprachsitzung | | YOU / THIS / HERE (voice card labels) | EINGABE / DIES / HIER | | click / click to … | anklicken / … klicken | +| card (host card) / voice card | Eintrag (in hints), Infokarte / Sprachkarte | +| label (on the map) / clear (switch off layers) | Beschriftung / ausschalten (not «löschen») | +| station tag (radio filter) | Kategorie | +| MIC (dock button) | MIKRO | diff --git a/src/data/directions.test.mjs b/src/data/directions.test.mjs index bf6e2878e..42ed9382f 100644 --- a/src/data/directions.test.mjs +++ b/src/data/directions.test.mjs @@ -919,3 +919,19 @@ test('ramp and lane wording stays localized after choosing the maneuver form', ( ); } }); + +test('the reroute tooltip keeps German mode nouns capitalized', (t) => { + t.after(() => setLocale('en')); + const title = (id) => + directionsRowControls(idle).chips.find((chip) => chip.id === id).title; + assert.equal(title('mode-foot'), 'Walk — reroute for walk'); + setLocale('de'); + assert.equal( + title('mode-foot'), + 'Zu Fuß – Route im Modus „Zu Fuß“ neu berechnen', + ); + assert.equal( + title('mode-bike'), + 'Fahrrad – Route im Modus „Fahrrad“ neu berechnen', + ); +}); diff --git a/src/i18n/locales/de.json b/src/i18n/locales/de.json index 8acbc0f6f..6b9800310 100644 --- a/src/i18n/locales/de.json +++ b/src/i18n/locales/de.json @@ -9,7 +9,7 @@ "Close data attribution": "Datenquellenhinweis schließen", "UNAVAILABLE": "NICHT VERFÜGBAR", "SOURCE": "QUELLE", - "Overpass rate-limited": "Overpass-Ratenlimit erreicht", + "Overpass rate-limited": "Overpass-Anfragelimit erreicht", "Overpass timed out": "Zeitüberschreitung bei Overpass", "Overpass could not complete the query": "Overpass konnte die Abfrage nicht abschließen", "Overpass temporarily unavailable": "Overpass vorübergehend nicht verfügbar", @@ -26,13 +26,13 @@ "observed or mapped nearby context": "beobachteter oder kartierter Kontext in der Nähe", "no observed or mapped objects in current feeds": "keine beobachteten oder kartierten Objekte in den aktuellen Feeds", "STATION": "STATION", - "Crewed stations and their visiting vehicles": "Bemannte Stationen und ihre Besucherfahrzeuge", + "Crewed stations and their visiting vehicles": "Bemannte Stationen und angedockte Raumfahrzeuge", "NAV": "NAV", "GNSS navigation — GPS, GLONASS, Galileo": "GNSS-Navigation: GPS, GLONASS, Galileo", "GEO": "GEO", "Geostationary belt — comms and weather, fixed over the equator": "Geostationärer Gürtel: Kommunikation und Wetter, fest über dem Äquator", "VISUAL": "VISUELL", - "Brightest naked-eye objects — CelesTrak visual group": "Hellste Objekte mit bloßem Auge: CelesTrak-Gruppe visual", + "Brightest naked-eye objects — CelesTrak visual group": "Hellste mit bloßem Auge sichtbare Objekte: CelesTrak-Gruppe „visual“", "COMMS": "KOMM", "Broadband constellation shell — shown only in DENSE mode": "Breitband-Konstellationsschale: nur im Modus DICHT sichtbar", "FISHING": "FISCHEREI", @@ -40,16 +40,16 @@ "DREDGER": "BAGGER", "DIVE OPS": "TAUCHEINSATZ", "MILITARY": "MILITÄR", - "SAILING": "SEGELN", + "SAILING": "SEGLER", "PLEASURE": "SPORTBOOT", - "PILOT": "LOTSE", + "PILOT": "LOTSENBOOT", "SAR": "SAR", "TUG": "SCHLEPPER", "PORT TENDER": "HAFENTENDER", "ANTI-POLLUTION": "UMWELTSCHUTZ", "LAW ENFORCE": "POLIZEI", - "MEDICAL": "MEDIZIN", - "HIGH-SPEED": "SCHNELLFAHRT", + "MEDICAL": "SANITÄTSDIENST", + "HIGH-SPEED": "SCHNELLSCHIFF", "PASSENGER": "PASSAGIER", "CARGO": "FRACHT", "TANKER": "TANKER", @@ -75,7 +75,7 @@ "PARTIAL": "TEILWEISE", "FALLBACK": "FALLBACK", "SUMMARY": "ÜBERSICHT", - "Awaiting telemetry...": "Warte auf Telemetrie...", + "Awaiting telemetry...": "Warten auf Telemetrie...", "REC": "REC", "AIS: --": "AIS: --", "POWER UP · {count} KEYS WAITING": { @@ -103,7 +103,7 @@ "CONTEXT READY": "KONTEXT BEREIT", "GLOBAL CONTEXT OFF": "GLOBALER KONTEXT AUS", "SELECT A FLIGHT, VESSEL, OR MAPPED INSTALLATION": "FLUG, SCHIFF ODER KARTIERTE ANLAGE WÄHLEN", - "ENABLE TO LOAD OBSERVED / MAPPED PROXIMITY": "AKTIVIEREN, UM BEOBACHTETE / KARTIERTE NÄHE ZU LADEN", + "ENABLE TO LOAD OBSERVED / MAPPED PROXIMITY": "AKTIVIEREN FÜR BEOBACHTETE / KARTIERTE OBJEKTE IM UMKREIS", "Unavailable": "Nicht verfügbar", "Focus {label}": "{label} fokussieren", "Global Context navigation": "Navigation des globalen Kontexts", @@ -132,11 +132,11 @@ "⚠️ Not renting": "⚠️ Keine Ausleihe", "⚠️ Not returning": "⚠️ Keine Rückgabe", "HDG {value}° (ESTIMATED)": "HDG {value}° (GESCHÄTZT)", - "{count} CAMERAS STANDING BY · NO CAMERA SELECTED · CLICK A CAMERA TO ACTIVATE": "{count} KAMERAS BEREIT · KEINE KAMERA GEWÄHLT · KAMERA ANKLICKEN ZUM AKTIVIEREN", + "{count} CAMERAS STANDING BY · NO CAMERA SELECTED · CLICK A CAMERA TO ACTIVATE": "KAMERAS BEREIT: {count} · KEINE KAMERA GEWÄHLT · KAMERA ANKLICKEN ZUM AKTIVIEREN", "No cameras available in catalog.": "Keine Kameras im Katalog verfügbar.", "{city} CCTV": "{city} CCTV", "FOV {value}°": "FOV {value}°", - "COVERAGE {value}km²": "ABDECKUNG {value}km²", + "COVERAGE {value}km²": "ABDECKUNG {value} km²", "OVERLAP {count} cams": "ÜBERLAPPUNG {count} Kam.", "ISOLATED VIEW": "EINZELANSICHT", "PROJ MONITOR": "PROJ MONITOR", @@ -146,7 +146,7 @@ "SRC {value}": "QUELLE {value}", "{value} CONTEXT": "{value} KONTEXT", "Focus fire detection {title}, {details}": "Branderkennung {title} fokussieren, {details}", - "{value} conf": "{value} Konf.", + "{value} conf": "Konf. {value}", "{value} ago": "vor {value}", "sensor n/a": "Sensor k. A.", "FIRE · {frp} MW": "BRAND · {frp} MW", @@ -185,7 +185,7 @@ "FLIGHT {count}": "FLUG {count}", "REUSED": "WIEDERVERWENDET", "NO STAGE RE-ENTRY / RECOVERY DATA": "KEINE DATEN ZU STUFEN-WIEDEREINTRITT / BERGUNG", - "{count} / 30D": "{count} / 30T", + "{count} / 30D": "{count} / 30 T", "NO MISSIONS AVAILABLE IN THE CURRENT 30-DAY WINDOW": "KEINE MISSIONEN IM AKTUELLEN 30-TAGE-FENSTER", "DATE UNAVAILABLE": "DATUM NICHT VERFÜGBAR", "UNSPECIFIED OPERATOR": "BETREIBER NICHT ANGEGEBEN", @@ -224,7 +224,7 @@ "PLANNED · ": "GEPLANT · ", "SUPPLIED TRAJECTORY POINTS": "GELIEFERTE BAHNPUNKTE", "RECONSTRUCTED ESTIMATE": "REKONSTRUIERTE SCHÄTZUNG", - "Replay the estimated ascent with a following camera": "Geschätzten Aufstieg mit folgender Kamera abspielen", + "Replay the estimated ascent with a following camera": "Geschätzten Aufstieg mit einer mitfliegenden Kamera abspielen", "Resume replay": "Wiedergabe fortsetzen", "T minus {seconds}": "T minus {seconds}", "Preparing launch site": "Startplatz wird vorbereitet", @@ -255,7 +255,7 @@ "Classical": "Klassik", "Country": "Country", "Dance": "Dance", - "Electronic": "Elektronik", + "Electronic": "Elektronische Musik", "Folk": "Folk", "Funk": "Funk", "Hip-Hop": "Hip-Hop", @@ -278,18 +278,18 @@ "Loading the Starlink shell…": "Starlink-Schale wird geladen…", "Starlink {detail} — click to retry": "Starlink {detail}: zum erneuten Versuch klicken", "load failed": "Laden fehlgeschlagen", - "Showing the full Starlink shell — click for the core catalog only": "Komplette Starlink-Schale sichtbar: klicken für nur den Kernkatalog", + "Showing the full Starlink shell — click for the core catalog only": "Komplette Starlink-Schale sichtbar: klicken, um nur den Kernkatalog zu zeigen", "DENSE ···": "DICHT ···", "DENSE ✕": "DICHT ✕", "DENSE": "DICHT", "Syncing flow · Roads: {source}": "Verkehrsfluss wird synchronisiert · Straßen: {source}", "LIVE · Roads: {source} · Roads without flow hidden": "LIVE · Straßen: {source} · Straßen ohne Verkehrsdaten ausgeblendet", "LIVE · Roads: {source} · No flow roads in view": "LIVE · Straßen: {source} · Keine Straßen mit Verkehrsdaten im Bild", - "LIVE · Roads: {source} · Flow {percent}%": "LIVE · Straßen: {source} · Verkehr {percent}%", - "SIMULATED · Roads: {source} · Flow {percent}%": "SIMULIERT · Straßen: {source} · Verkehr {percent}%", + "LIVE · Roads: {source} · Flow {percent}%": "LIVE · Straßen: {source} · Verkehr {percent} %", + "SIMULATED · Roads: {source} · Flow {percent}%": "SIMULIERT · Straßen: {source} · Verkehr {percent} %", "Syncing flow · Roads: OpenStreetMap · Flow: TomTom · Unmatched: simulated": "Verkehrsfluss wird synchronisiert · Straßen: OpenStreetMap · Verkehr: TomTom · Ohne Zuordnung: simuliert", - "LIVE · Roads: OpenStreetMap · Flow: TomTom · {percent}% cov · Unmatched: simulated": "LIVE · Straßen: OpenStreetMap · Verkehr: TomTom · {percent}% Abd. · Ohne Zuordnung: simuliert", - "LIVE · Roads: OpenStreetMap · Flow: TomTom · {percent}% cov": "LIVE · Straßen: OpenStreetMap · Verkehr: TomTom · {percent}% Abd.", + "LIVE · Roads: OpenStreetMap · Flow: TomTom · {percent}% cov · Unmatched: simulated": "LIVE · Straßen: OpenStreetMap · Verkehr: TomTom · {percent} % Abd. · Ohne Zuordnung: simuliert", + "LIVE · Roads: OpenStreetMap · Flow: TomTom · {percent}% cov": "LIVE · Straßen: OpenStreetMap · Verkehr: TomTom · {percent} % Abd.", "SIMULATED · Roads: OpenStreetMap · Flow: TomTom (no matches)": "SIMULIERT · Straßen: OpenStreetMap · Verkehr: TomTom (keine Treffer)", "SIMULATED — traffic service unreachable": "SIMULIERT: Verkehrsdienst nicht erreichbar", "SIMULATED — add TomTom key for live": "SIMULIERT: TomTom-Schlüssel für Live-Daten hinzufügen", @@ -298,9 +298,9 @@ "VESSEL": "SCHIFF", "POS: LIVE": "POS: LIVE", "POS: {time}Z": "POS: {time}Z", - "awaiting first AIS position…": "warte auf erste AIS-Position…", - "awaiting usable AIS positions…": "warte auf nutzbare AIS-Positionen…", - "awaiting first AIS message…": "warte auf erste AIS-Nachricht…", + "awaiting first AIS position…": "warten auf erste AIS-Position…", + "awaiting usable AIS positions…": "warten auf nutzbare AIS-Positionen…", + "awaiting first AIS message…": "warten auf erste AIS-Nachricht…", "Resume": "Fortsetzen", "Pause": "Pause", "Error: {message}": "Fehler: {message}", @@ -363,7 +363,7 @@ "CAL · {badge}": "KAL · {badge}", "MONITOR": "MONITOR", "OFF": "AUS", - "{city} · HDG {heading} · FOV {fov} · RANGE {range}m · {projection}{calBadge} · {provider}{status}": "{city} · HDG {heading} · FOV {fov} · REICHW. {range}m · {projection}{calBadge} · {provider}{status}", + "{city} · HDG {heading} · FOV {fov} · RANGE {range}m · {projection}{calBadge} · {provider}{status}": "{city} · HDG {heading} · FOV {fov} · REICHW. {range} m · {projection}{calBadge} · {provider}{status}", "{count} cameras loaded · click a camera to activate": { "one": "{count} Kamera geladen · Kamera anklicken zum Aktivieren", "other": "{count} Kameras geladen · Kamera anklicken zum Aktivieren" @@ -377,8 +377,8 @@ "No summary available.": "Keine Zusammenfassung verfügbar.", "loading frames": "Frames werden geladen", "camera grid ready": "Kameraraster bereit", - "Clearing selected data layers": "Ausgewählte Datenebenen werden gelöscht", - "Clear selected data layers": "Ausgewählte Datenebenen löschen", + "Clearing selected data layers": "Ausgewählte Datenebenen werden ausgeschaltet", + "Clear selected data layers": "Ausgewählte Datenebenen ausschalten", "CONDITIONS UNKNOWN": "BEDINGUNGEN UNBEKANNT", "CLEAR": "KLAR", "PARTLY CLOUDY": "TEILS BEWÖLKT", @@ -393,14 +393,14 @@ "CYCLE ON": "WECHSEL EIN", "CYCLE OFF": "WECHSEL AUS", "Stop automatic page cycling. Previous, Next, and the SIG/NEWS/LOCAL tabs stay available.": "Automatischen Seitenwechsel stoppen. Zurück, Weiter und die Tabs SIG/NEWS/LOKAL bleiben verfügbar.", - "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.": "Briefing-Seiten automatisch alle 9 Sekunden wechseln (Signale → News → Lokal). Pausiert, solange der Bereich überfahren oder fokussiert ist. Live-Signaldaten werden in beiden Fällen laufend aktualisiert.", + "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.": "Briefing-Seiten automatisch alle 9 Sekunden wechseln (Signale → News → Lokal). Pausiert, solange sich der Mauszeiger über dem Bereich befindet oder dieser den Fokus hat. Live-Signaldaten werden in beiden Fällen laufend aktualisiert.", "ACQUIRING REGIONAL NEWS": "REGIONALE NEWS WERDEN ERFASST", "REGIONAL NEWS UNAVAILABLE": "REGIONALE NEWS NICHT VERFÜGBAR", "RESOLVING REGION": "REGION WIRD ERMITTELT", "REGION UNAVAILABLE": "REGION NICHT VERFÜGBAR", "NO RECENT LOCATION MATCHES": "KEINE AKTUELLEN ORTSTREFFER", "{domain} · {age}": "{domain} · {age}", - "CLOUD {pct}%": "WOLKEN {pct}%", + "CLOUD {pct}%": "WOLKEN {pct} %", "CLOUD UNKNOWN": "WOLKEN UNBEKANNT", "{source} · LOCATION QUERY": "{source} · ORTSABFRAGE", "REGIONAL NEWS": "REGIONALE NEWS", @@ -408,7 +408,7 @@ "ENABLE GLOBAL CONTEXT FOR PROXIMITY PINGS": "GLOBALEN KONTEXT FÜR NÄHE-PINGS AKTIVIEREN", "CONTACT LOST · LAST KNOWN READOUT · NOT AN ALL-CLEAR": "KONTAKT VERLOREN · LETZTER STAND · KEINE ENTWARNUNG", "CONTACT LOST · {subject}": "KONTAKT VERLOREN · {subject}", - "SUBJECT LEFT ITS FEED · READOUT HOLDING LAST KNOWN": "OBJEKT HAT SEINEN FEED VERLASSEN · ANZEIGE HÄLT LETZTEN STAND", + "SUBJECT LEFT ITS FEED · READOUT HOLDING LAST KNOWN": "OBJEKT NICHT MEHR IM FEED · ANZEIGE HÄLT LETZTEN STAND", "{cohort} · {contact}": "{cohort} · {contact}", "NO AVAILABLE EXAMPLE": "KEIN BEISPIEL VERFÜGBAR", "{cohort}, Unavailable": "{cohort}, nicht verfügbar", @@ -417,17 +417,17 @@ "L": "L", "R": "R", "{count} INPUTS UNKNOWN · NOT AN ALL-CLEAR": { - "one": "{count} EINGABE UNBEKANNT · KEINE ENTWARNUNG", - "other": "{count} EINGABEN UNBEKANNT · KEINE ENTWARNUNG" + "one": "STATUS UNKLAR: {count} QUELLE · KEINE ENTWARNUNG", + "other": "STATUS UNKLAR: {count} QUELLEN · KEINE ENTWARNUNG" }, - "AVAILABLE INPUTS CURRENT · NOT AN ALL-CLEAR": "VERFÜGBARE EINGABEN AKTUELL · KEINE ENTWARNUNG", + "AVAILABLE INPUTS CURRENT · NOT AN ALL-CLEAR": "VERFÜGBARE QUELLEN AKTUELL · KEINE ENTWARNUNG", "AIRCRAFT": "FLUGZEUG", "ACQUIRING SURFACE": "OBERFLÄCHE WIRD ERFASST", "SURFACE FALLBACK": "OBERFLÄCHEN-FALLBACK", "STALE FEED": "VERALTETER FEED", "LIVE TRACK": "LIVE-TRACK", "COMMERCIAL": "ZIVIL", - "{aircraftClass} · {feedState} · COURSE ALIGNED": "{aircraftClass} · {feedState} · KURS ANGEGLICHEN", + "{aircraftClass} · {feedState} · COURSE ALIGNED": "{aircraftClass} · {feedState} · IN KURSRICHTUNG", "ARROW · ESTIMATED DIRECTION": "PFEIL · GESCHÄTZTE RICHTUNG", "ROUTE DATA UNAVAILABLE": "ROUTENDATEN NICHT VERFÜGBAR", "DEST {bearing}": "DEST {bearing}", @@ -467,8 +467,8 @@ "{aircraftClass} · {distance}": "{aircraftClass} · {distance}", "DISTANCE UNKNOWN": "DISTANZ UNBEKANNT", "{count} INPUTS UNKNOWN": { - "one": "{count} EINGABE UNBEKANNT", - "other": "{count} EINGABEN UNBEKANNT" + "one": "STATUS UNKLAR: {count} QUELLE", + "other": "STATUS UNKLAR: {count} QUELLEN" }, "SOURCE STATUS UNAVAILABLE": "QUELLENSTATUS NICHT VERFÜGBAR", "Restore real aircraft": "Echtes Flugzeug wiederherstellen", @@ -478,14 +478,14 @@ "Context could not restore every layer; try again": "Kontext konnte nicht alle Ebenen wiederherstellen; erneut versuchen", "No selected data layers": "Keine Datenebenen ausgewählt", "{count} data layers could not be cleared": { - "one": "{count} Datenebene konnte nicht gelöscht werden", - "other": "{count} Datenebenen konnten nicht gelöscht werden" + "one": "{count} Datenebene konnte nicht ausgeschaltet werden", + "other": "{count} Datenebenen konnten nicht ausgeschaltet werden" }, "Cleared {count} data layers": { - "one": "{count} Datenebene gelöscht", - "other": "{count} Datenebenen gelöscht" + "one": "{count} Datenebene ausgeschaltet", + "other": "{count} Datenebenen ausgeschaltet" }, - "Selected data layers could not be cleared": "Ausgewählte Datenebenen konnten nicht gelöscht werden", + "Selected data layers could not be cleared": "Ausgewählte Datenebenen konnten nicht ausgeschaltet werden", "Space Missions could not complete the requested transition; try again": "Raummissionen konnten den gewünschten Wechsel nicht abschließen; erneut versuchen", "Nearby installations refreshed": "Anlagen in der Nähe aktualisiert", "Nearby installations could not be refreshed; try again": "Anlagen in der Nähe konnten nicht aktualisiert werden; erneut versuchen", @@ -493,7 +493,7 @@ "That layer is unavailable in the current Context mode": "Diese Ebene ist im aktuellen Kontextmodus nicht verfügbar", "{layerId} could not {action} cleanly": "{layerId} konnte nicht sauber {action}", "start": "starten", - "stop": "beenden", + "stop": "beendet werden", "{mode} could not start because another layer did not stop cleanly": "{mode}: Start nicht möglich, da eine andere Ebene nicht sauber beendet wurde", "Space Missions": "Raummissionen", "Context": "Kontext", @@ -512,7 +512,7 @@ "Datacenters": "Rechenzentren", "Dams": "Staudämme", "Submarine Cables": "Seekabel", - "FIRMS Active Fires": "FIRMS aktive Brände", + "FIRMS Active Fires": "Aktive Brände (FIRMS)", "ENABLING": "WIRD AKTIVIERT", "DISABLING": "WIRD DEAKTIVIERT", "{state} · {source}": "{state} · {source}", @@ -550,7 +550,7 @@ "Collapse Radio": "Radio einklappen", "Expand Radio section": "Radio-Bereich ausklappen", "Collapse Radio section": "Radio-Bereich einklappen", - "Panel layout updated — positions reset to new defaults": "Bereichslayout aktualisiert. Positionen auf neue Standards zurückgesetzt", + "Panel layout updated — positions reset to new defaults": "Bereichslayout aktualisiert – Positionen auf neue Standardwerte zurückgesetzt", "Collapse Cockpit display options": "Cockpit-Anzeigeoptionen einklappen", "Expand Cockpit display options": "Cockpit-Anzeigeoptionen ausklappen", "Collapse Cockpit Radio controls": "Cockpit-Radio-Steuerung einklappen", @@ -593,7 +593,7 @@ " · degraded directory": " · eingeschränktes Verzeichnis", " · stale directory": " · veraltetes Verzeichnis", " · outside current filter": " · außerhalb des aktuellen Filters", - "Ready — playback starts only from your action": "Bereit: Wiedergabe startet nur auf eigene Aktion", + "Ready — playback starts only from your action": "Bereit: Wiedergabe startet nur manuell", "Radio off": "Radio aus", "Connecting directly to broadcaster…": "Direktverbindung zum Sender wird aufgebaut…", "Buffering broadcaster stream…": "Sender-Stream wird gepuffert…", @@ -603,11 +603,11 @@ " · muted during voice interaction": " · stumm bei Sprachinteraktion", " · restoring volume after voice": " · Lautstärke wird nach Sprache wiederhergestellt", " · static indicates no broadcaster audio": " · Rauschen bedeutet: kein Sender-Audio", - " · tuning static until broadcaster starts": " · Rauschen bis der Sender startet", + " · tuning static until broadcaster starts": " · Rauschen, bis der Sender startet", "Station unavailable after directory refresh — choose another channel": "Sender nach Verzeichnisaktualisierung nicht verfügbar: anderen Kanal wählen", "Radio is enabling…": "Radio wird aktiviert…", "Radio is disabling…": "Radio wird deaktiviert…", - "Radio lifecycle is uncertain — use Enable or Disable to reconcile": "Radio-Lebenszyklus unklar: zum Abgleichen Aktivieren oder Deaktivieren nutzen", + "Radio lifecycle is uncertain — use Enable or Disable to reconcile": "Radio-Lebenszyklus unklar: zum Abgleichen EIN oder AUS wählen", "Scene action failed": "Szenenaktion fehlgeschlagen", "Delete shot \"{shot}\"?": "Aufnahme „{shot}“ löschen?", "SPARSE": "DÜNN", @@ -674,7 +674,7 @@ "GROUND SPEED · KTS": "GESCHW. ÜBER GRUND · KN", "ALTITUDE · FT": "HÖHE · FT", "FIRST PERSON": "EGO-PERSPEKTIVE", - "LIVE TRACK · COURSE ALIGNED": "LIVE-TRACK · KURS ANGEGLICHEN", + "LIVE TRACK · COURSE ALIGNED": "LIVE-TRACK · IN KURSRICHTUNG", "Cockpit vision style": "Sichtstil im Cockpit", "Previous cockpit vision style": "Vorheriger Cockpit-Sichtstil", "Previous vision style": "Vorheriger Sichtstil", @@ -692,8 +692,8 @@ "Contact navigation": "Kontaktnavigation", "CONTEXT ONLY": "NUR KONTEXT", "Nearby cohort counts": "Anzahl Kontakte in der Nähe", - "NEAREST OBSERVED / MAPPED": "NÄCHSTER BEOBACHTET / KARTIERT", - "AVAILABLE INPUTS ONLY · NOT AN ALL-CLEAR": "NUR VERFÜGBARE EINGABEN · KEINE ENTWARNUNG", + "NEAREST OBSERVED / MAPPED": "NÄCHSTES OBJEKT · BEOBACHTET / KARTIERT", + "AVAILABLE INPUTS ONLY · NOT AN ALL-CLEAR": "NUR VERFÜGBARE QUELLEN · KEINE ENTWARNUNG", "Cockpit briefing carousel": "Cockpit-Briefing-Karussell", "Estimated flight plan": "Geschätzter Flugplan", "ESTIMATED FLIGHT PLAN": "GESCHÄTZTER FLUGPLAN", @@ -733,8 +733,8 @@ "Pin visual presets": "Visuelle Presets anheften", "Keep visual presets open": "Visuelle Presets geöffnet lassen", "Show the globe without a visual filter.": "Globus ohne visuellen Filter anzeigen.", - "Emulate a green phosphor CRT with scanlines and screen curvature.": "Grüne Phosphor-Röhre mit Zeilen und Bildschirmkrümmung nachahmen.", - "Simulate night-vision goggles with green intensification and a tube vignette.": "Nachtsichtgerät mit grüner Aufhellung und Röhrenvignette simulieren.", + "Emulate a green phosphor CRT with scanlines and screen curvature.": "Grüne Phosphor-Röhre mit Scanlines und Bildschirmkrümmung nachahmen.", + "Simulate night-vision goggles with green intensification and a tube vignette.": "Nachtsichtgerät mit grüner Restlichtverstärkung und Röhrenvignette simulieren.", "Simulate FLIR-style thermal contrast. Turn up Ironbow for color.": "FLIR-artigen Wärmekontrast simulieren. Ironbow aufdrehen für Farbe.", "Apply bright cel-shaded color and illustrated outlines.": "Leuchtende Cel-Shading-Farben und gezeichnete Konturen anwenden.", "Apply high-contrast monochrome film-noir grading.": "Kontrastreiche monochrome Film-noir-Farbgebung anwenden.", @@ -767,15 +767,15 @@ "SEARCH NEARBY SITES": "STANDORTE IN DER NÄHE SUCHEN", "Reclassify tracked contact as TR-3B": "Verfolgten Kontakt als TR-3B umklassifizieren", "CONTACTS CONTEXT OFF": "KONTAKTKONTEXT AUS", - "SELECT CONTACTS TO LOAD OBSERVED / MAPPED PROXIMITY": "KONTAKTE WÄHLEN, UM BEOBACHTETE / KARTIERTE NÄHE ZU LADEN", + "SELECT CONTACTS TO LOAD OBSERVED / MAPPED PROXIMITY": "KONTAKTE WÄHLEN FÜR BEOBACHTETE / KARTIERTE OBJEKTE IM UMKREIS", "Available Space Missions": "Verfügbare Raummissionen", "AVAILABLE MISSIONS": "VERFÜGBARE MISSIONEN", "SELECT A MISSION TO INSPECT": "MISSION ZUM ANSEHEN WÄHLEN", "LOADING 30-DAY MISSION INDEX": "30-TAGE-MISSIONSINDEX WIRD GELADEN", - "TAB PREVIEWS · ENTER / SPACE SELECTS": "TAB VORSCHAU · ENTER / LEERTASTE WÄHLT", + "TAB PREVIEWS · ENTER / SPACE SELECTS": "TAB: VORSCHAU · ENTER / LEERTASTE: AUSWAHL", "Internet radio and local SDR": "Internetradio und lokales SDR", - "STATION TAG": "SENDER-TAG", - "Filter stations by station tag": "Sender nach Sender-Tag filtern", + "STATION TAG": "KATEGORIE", + "Filter stations by station tag": "Sender nach Kategorie filtern", "All": "Alle", "Enable Radio, then choose a globe marker or use next.": "Radio aktivieren, dann einen Globus-Marker wählen oder Weiter nutzen.", "DRAG TO TUNE": "ZUM ABSTIMMEN ZIEHEN", @@ -789,7 +789,7 @@ "Stop radio playback": "Radiowiedergabe stoppen", "Radio volume": "Radio-Lautstärke", "STATION SITE": "SENDERSTANDORT", - "Audio connects directly to the broadcaster after you press play. Your IP is visible to that broadcaster.": "Audio verbindet sich nach dem Abspielen direkt mit dem Sender. Die IP-Adresse ist für diesen Sender sichtbar.", + "Audio connects directly to the broadcaster after you press play. Your IP is visible to that broadcaster.": "Beim Starten der Wiedergabe wird eine direkte Verbindung zum Sender hergestellt. Die IP-Adresse ist für diesen Sender sichtbar.", "Intelligence HUD (H)": "Intelligence-HUD (H)", "Layout": "Layout", "HUD layout": "HUD-Layout", @@ -798,9 +798,9 @@ "Minimal": "Minimal", "Detection Overlay (D)": "Erkennungs-Overlay (D)", "Detection overlay": "Erkennungs-Overlay", - "Detection label density": "Dichte der Erkennungslabels", + "Detection label density": "Dichte der Erkennungsbeschriftungen", "Allocation": "Zuteilung", - "Detection label allocation": "Zuteilung der Erkennungslabels", + "Detection label allocation": "Zuteilung der Erkennungsbeschriftungen", "Elastic": "Elastisch", "Weighted": "Gewichtet", "Fade": "Ausblenden", @@ -808,7 +808,7 @@ "World-overlay fade distance outside the keyhole as a percentage of its radius": "Ausblendeabstand des Welt-Overlays außerhalb des Schlüssellochs, in Prozent seines Radius", "Outside": "Außen", "Detection opacity outside the keyhole": "Erkennungsdeckkraft außerhalb des Schlüssellochs", - "World-overlay label and card opacity beyond the fade distance": "Deckkraft von Welt-Overlay-Labels und -Karten jenseits des Ausblendeabstands", + "World-overlay label and card opacity beyond the fade distance": "Deckkraft von Beschriftungen und Infokarten im Welt-Overlay jenseits des Ausblendeabstands", "PARAMETERS": "PARAMETER", "3D aircraft — flat icons zoomed out, 3D models up close": "3D-Flugzeuge: flache Symbole bei Fernsicht, 3D-Modelle aus der Nähe", "Models": "Modelle", @@ -859,7 +859,7 @@ "GROUND STATION · PROVIDER SETTINGS": "BODENSTATION · ANBIETER-EINSTELLUNGEN", "Close key setup": "Schlüssel-Einrichtung schließen", "Power up the globe": "Globus hochfahren", - "The globe already flies keyless. Every key below switches on another real feed — paste one and it's saved into this app's local configuration, then the server restarts itself. Server-side keys stay on this machine; Google Maps and Cesium ion run in the browser and must be provider-restricted. Keys you configured elsewhere are shown but never touched.": "Der Globus fliegt bereits ohne Schlüssel. Jeder Schlüssel unten schaltet einen weiteren echten Feed frei: Einfügen genügt, er wird in der lokalen Konfiguration dieser App gespeichert, danach startet der Server selbst neu. Serverseitige Schlüssel bleiben auf diesem Rechner; Google Maps und Cesium ion laufen im Browser und müssen auf den Anbieter beschränkt sein. Anderswo konfigurierte Schlüssel werden angezeigt, aber nie verändert.", + "The globe already flies keyless. Every key below switches on another real feed — paste one and it's saved into this app's local configuration, then the server restarts itself. Server-side keys stay on this machine; Google Maps and Cesium ion run in the browser and must be provider-restricted. Keys you configured elsewhere are shown but never touched.": "Der Globus fliegt bereits ohne Schlüssel. Jeder Schlüssel unten schaltet einen weiteren echten Feed frei: Einfügen genügt, er wird in der lokalen Konfiguration dieser App gespeichert, danach startet der Server selbst neu. Serverseitige Schlüssel bleiben auf diesem Rechner; die Schlüssel für Google Maps und Cesium ion werden im Browser verwendet und müssen beim jeweiligen Anbieter eingeschränkt werden. Anderswo konfigurierte Schlüssel werden angezeigt, aber nie verändert.", "SAVE KEYS": "SCHLÜSSEL SPEICHERN", "ESC to close": "ESC zum Schließen", "The Google Maps key buys the photorealistic planet — everything else stacks on top.": "Der Google-Maps-Schlüssel liefert den fotorealistischen Planeten, alles andere kommt obendrauf.", @@ -868,17 +868,17 @@ "Globe actions": "Globus-Aktionen", "Turn off all selected data layers": "Alle ausgewählten Datenebenen ausschalten", "Copy share link": "Link zum Teilen kopieren", - "Reset camera and return to full globe view": "Kamera zurücksetzen und zur Vollglobus-Ansicht", + "Reset camera and return to full globe view": "Kamera zurücksetzen und zur Vollglobus-Ansicht zurückkehren", "MISSION CONTROL · FIRST LAUNCH": "MISSION CONTROL · ERSTER START", "Choose your first view": "Erste Ansicht wählen", "LIVE CONTACTS": "LIVE-KONTAKTE", - "Aircraft, vessels and nearby intelligence": "Flugzeuge, Schiffe und Aufklärung in der Nähe", + "Aircraft, vessels and nearby intelligence": "Flugzeuge, Schiffe und Lagebild der Umgebung", "Launches, spacecraft and orbital context": "Starts, Raumfahrzeuge und Orbit-Kontext", "EXPLORE MANUALLY": "MANUELL ERKUNDEN", "Begin with a clean globe": "Mit einem leeren Globus beginnen", "Don't show this again": "Nicht mehr anzeigen", "ESC to dismiss": "ESC zum Schließen", - "Tip: the GEV MIC button in the dock lets you talk to the map.": "Tipp: Mit der Taste GEV MIC im Dock lässt sich die Karte per Sprache steuern.", + "Tip: the GEV MIC button in the dock lets you talk to the map.": "Tipp: Mit der Mikrofontaste im Dock lässt sich die Karte per Sprache steuern.", "Pick a shape, then click the map.": "Form wählen, dann auf die Karte klicken.", "Enter to place the pin, Esc to cancel.": "Enter setzt den Pin, Esc bricht ab.", "Click where the pin goes.": "Auf die Stelle für den Pin klicken.", @@ -1035,7 +1035,7 @@ "one": "{count} QUELLE", "other": "{count} QUELLEN" }, - "OUTSIDE IMAGERY SWIPE": "AUSSERHALB DES BILDVERGLEICHS", + "OUTSIDE IMAGERY SWIPE": "NICHT IM BILDVERGLEICH", "{scene} / AUTHORED SHOT": "{scene} / GESTALTETE AUFNAHME", "NEPAL FLOOD INCIDENT": "FLUTEREIGNIS NEPAL", "Play {shot}": "{shot} abspielen", @@ -1101,7 +1101,7 @@ "That KMZ holds no KML document.": "Diese KMZ enthält kein KML-Dokument.", "That {format} file could not be read.": "Diese {format}-Datei konnte nicht gelesen werden.", "That file has {count} map objects; the limit is {limit}.": "Diese Datei hat {count} Kartenobjekte; das Limit ist {limit}.", - "Ground heights could not be read. Try that file again.": "Geländehöhen konnten nicht gelesen werden. Die Datei erneut versuchen.", + "Ground heights could not be read. Try that file again.": "Geländehöhen konnten nicht gelesen werden. Die Datei erneut laden.", "That file has invalid point graphics.": "Diese Datei enthält ungültige Punktgrafiken.", "Map tiles temporarily unavailable": "Kartenkacheln vorübergehend nicht verfügbar", "Mapped names temporarily unavailable": "Kartierte Namen vorübergehend nicht verfügbar", @@ -1200,7 +1200,7 @@ "ChatGPT sign-in expired. Opening sign-in again…": "ChatGPT-Anmeldung abgelaufen. Anmeldung wird erneut geöffnet…", "Opening ChatGPT sign-in in your browser…": "ChatGPT-Anmeldung wird im Browser geöffnet…", "Could not start ChatGPT sign-in on this machine.": "ChatGPT-Anmeldung konnte auf diesem Rechner nicht gestartet werden.", - "Finish ChatGPT sign-in in the browser. Waiting for it to complete…": "ChatGPT-Anmeldung im Browser abschließen. Warte auf Abschluss…", + "Finish ChatGPT sign-in in the browser. Waiting for it to complete…": "ChatGPT-Anmeldung im Browser abschließen. Warten auf Abschluss…", "ChatGPT sign-in timed out. Click {button} to try again.": "Zeitüberschreitung bei der ChatGPT-Anmeldung. Zum erneuten Versuch auf {button} klicken.", "ChatGPT sign-in complete. OAuth will be used for the next cloud voice session.": "ChatGPT-Anmeldung abgeschlossen. OAuth wird für die nächste Cloud-Sprachsitzung verwendet.", "The photorealistic 3D planet, place search + Street View": "Der fotorealistische 3D-Planet, Ortssuche + Street View", @@ -1215,7 +1215,7 @@ "one": "{count} Station meldet", "other": "{count} Stationen melden" }, - "Highest air-quality readings in view": "Höchste Luftqualitätswerte im Bild", + "Highest air-quality readings in view": "Schlechteste Luftqualitätswerte im Bild", "Low": "Niedrig", "Low health risk": "Geringes Gesundheitsrisiko", "Moderate": "Mäßig", @@ -1266,11 +1266,11 @@ "viewport feed is not a complete 250 km survey": "Feed des Bildausschnitts ist keine vollständige 250-km-Erfassung", "GBFS fetch error": "GBFS-Abruffehler", "FOV {value}° (DATASHEET)": "FOV {value}° (DATENBLATT)", - "SPEC FOV {span}° (CAPABILITY)": "SPEZ. FOV {span}° (LEISTUNG)", + "SPEC FOV {span}° (CAPABILITY)": "SPEZ. FOV {span}° (BEREICH)", "{spec} · SPECS: CCTV-DATABASE.COM": "{spec} · SPEZ.: CCTV-DATABASE.COM", "Atlantic and eastern/central North Pacific; not worldwide cyclone coverage.": "Atlantik und östlicher/zentraler Nordpazifik; keine weltweite Abdeckung von Wirbelstürmen.", - "Cyclone advisories unavailable": "Sturmwarnungen nicht verfügbar", - "Cyclone data unavailable": "Sturmdaten nicht verfügbar", + "Cyclone advisories unavailable": "Wirbelsturm-Lageberichte nicht verfügbar", + "Cyclone data unavailable": "Wirbelsturmdaten nicht verfügbar", "Potential tropical cyclone": "Potenzieller tropischer Wirbelsturm", "Post-tropical cyclone": "Posttropischer Wirbelsturm", "Hurricane": "Hurrikan", @@ -1278,29 +1278,29 @@ "Tropical depression": "Tropisches Tiefdruckgebiet", "Subtropical storm": "Subtropischer Sturm", "Subtropical depression": "Subtropisches Tiefdruckgebiet", - "Track and cone match this advisory": "Zugbahn und Kegel passen zu dieser Warnung", - "Track/cone awaiting advisory {number}": "Zugbahn/Kegel warten auf Warnung {number}", + "Track and cone match this advisory": "Zugbahn und Kegel passen zu diesem Lagebericht", + "Track/cone awaiting advisory {number}": "Zugbahn/Kegel warten auf Lagebericht {number}", "Track/cone unavailable": "Zugbahn/Kegel nicht verfügbar", - "Cached advisory · stale source": "Warnung aus dem Cache · Quelle veraltet", - "Loading advisories…": "Warnungen werden geladen…", + "Cached advisory · stale source": "Lagebericht aus dem Cache · Quelle veraltet", + "Loading advisories…": "Lageberichte werden geladen…", "{count} active storms": { "one": "{count} aktiver Sturm", "other": "{count} aktive Stürme" }, - "Position as of {time}": "Position mit Stand {time}", + "Position as of {time}": "Position, Stand {time}", "Maximum sustained wind: {wind} · Pressure: {pressure}": "Maximaler Dauerwind: {wind} · Luftdruck: {pressure}", - "{name} · {classification} · Advisory {number} · issued {time}": "{name} · {classification} · Warnung {number} · herausgegeben {time}", + "{name} · {classification} · Advisory {number} · issued {time}": "{name} · {classification} · Lagebericht {number} · herausgegeben {time}", "No active NHC/CPHC systems": "Keine aktiven NHC/CPHC-Systeme", - "Advisories unavailable": "Warnungen nicht verfügbar", + "Advisories unavailable": "Lageberichte nicht verfügbar", "Cyclones · NHC / CPHC": "Wirbelstürme · NHC / CPHC", "Atlantic · E/C Pacific": "Atlantik · östl./zentr. Pazifik", "{storms} · {name} selected": "{storms} · {name} ausgewählt", - "Official advisory ↗": "Offizielle Warnung ↗", - "Active NHC and CPHC cyclone advisories": "Aktive Wirbelsturmwarnungen von NHC und CPHC", + "Official advisory ↗": "Offizieller Lagebericht ↗", + "Active NHC and CPHC cyclone advisories": "Aktive Wirbelsturm-Lageberichte von NHC und CPHC", "Wind unavailable": "Wind nicht verfügbar", - "Advisory center / forecast track": "Zentrum laut Warnung / Vorhersagebahn", + "Advisory center / forecast track": "Zentrum laut Lagebericht / Vorhersagebahn", "Center-track uncertainty cone": "Unsicherheitskegel der Zentrumsbahn", - "Select a storm on the map, or choose a storm in the list to select it and move the camera. Click empty map space to clear the selection. NOAA NHC/CPHC advisory context. The cone describes forecast center-track uncertainty, not storm size or the full hazard area. Forecast point labels are source lead hours, not times computed from advisory issuance. Geometry follows the surface; height is not weather altitude. Consult the official advisory.": "Einen Sturm auf der Karte auswählen oder in der Liste wählen, um ihn auszuwählen und die Kamera dorthin zu bewegen. Auf eine leere Kartenstelle klicken, um die Auswahl aufzuheben. Kontext aus Warnungen von NOAA NHC/CPHC. Der Kegel beschreibt die Unsicherheit der vorhergesagten Zentrumsbahn, nicht die Sturmgröße oder das gesamte Gefahrengebiet. Die Beschriftungen der Vorhersagepunkte sind Vorlaufstunden der Quelle, keine aus dem Ausgabezeitpunkt berechneten Zeiten. Die Geometrie folgt der Oberfläche; die Höhe ist keine Wetterhöhe. Die offizielle Warnung beachten.", + "Select a storm on the map, or choose a storm in the list to select it and move the camera. Click empty map space to clear the selection. NOAA NHC/CPHC advisory context. The cone describes forecast center-track uncertainty, not storm size or the full hazard area. Forecast point labels are source lead hours, not times computed from advisory issuance. Geometry follows the surface; height is not weather altitude. Consult the official advisory.": "Einen Sturm auf der Karte auswählen oder in der Liste wählen, um ihn auszuwählen und die Kamera dorthin zu bewegen. Auf eine leere Kartenstelle klicken, um die Auswahl aufzuheben. Kontext aus Lageberichten von NOAA NHC/CPHC. Der Kegel beschreibt die Unsicherheit der vorhergesagten Zentrumsbahn, nicht die Sturmgröße oder das gesamte Gefahrengebiet. Die Beschriftungen der Vorhersagepunkte sind Vorlaufstunden der Quelle, keine aus dem Ausgabezeitpunkt berechneten Zeiten. Die Geometrie folgt der Oberfläche; die Höhe ist keine Wetterhöhe. Den offiziellen Lagebericht beachten.", "DRIVE": "AUTO", "Drive": "Auto", "WALK": "ZU FUSS", @@ -1394,7 +1394,7 @@ "Use the {direction} lane": "Die {direction} Spur benutzen", "Continue onto {road}": "Weiter auf {road}", "maneuver|Continue": "Weiter", - "{mode} — reroute for {modeLower}": "{mode} – Route für {modeLower} neu berechnen", + "{mode} — reroute for {modeLower}": "{mode} – Route im Modus „{modeLower}“ neu berechnen", "CLICK MAP": "KARTE ANKLICKEN", "SET A": "A SETZEN", "Click a spot on the globe to place A (click again to cancel)": "Auf eine Stelle des Globus klicken, um A zu setzen (erneut klicken zum Abbrechen)", @@ -1425,7 +1425,7 @@ "SET A, then click the globe": "A SETZEN, dann auf den Globus klicken", "Step {step} of {total} · then {leg}": "Schritt {step} von {total} · dann {leg}", "Step {step} of {total}": "Schritt {step} von {total}", - "Then: {instruction}": "Dann: {instruction}", + "Then: {instruction}": "Nächster Schritt: {instruction}", "No route found between A and B": "Keine Route zwischen A und B gefunden", "Routing failed: {error}": "Routing fehlgeschlagen: {error}", "Routing timed out": "Zeitüberschreitung beim Routing", @@ -1453,8 +1453,8 @@ "Latest Drop": "Neueste Ausgabe", "GhostMaps file could not be read": "GhostMaps-Datei konnte nicht gelesen werden", "{count} source links ↗ · click card to open the first": { - "one": "{count} Quelllink ↗ · Karte anklicken zum Öffnen", - "other": "{count} Quelllinks ↗ · Karte anklicken, um den ersten zu öffnen" + "one": "{count} Quelllink ↗ · Eintrag anklicken zum Öffnen", + "other": "{count} Quelllinks ↗ · Eintrag anklicken, um den ersten zu öffnen" }, "S2 · {name}": "S2 · {name}", "Report": "Bericht", @@ -1562,7 +1562,7 @@ "discovered {age} ago": "entdeckt vor {age}", "updated {age} ago": "aktualisiert vor {age}", "part of {complex}": "Teil von {complex}", - "InciWeb ↗ · click card to open": "InciWeb ↗ · Karte anklicken zum Öffnen", + "InciWeb ↗ · click card to open": "InciWeb ↗ · Eintrag anklicken zum Öffnen", "FIRE · {name}": "BRAND · {name}", "Unnamed incident": "Unbenannter Einsatz", "Open {title} on InciWeb": "{title} auf InciWeb öffnen", @@ -1593,7 +1593,7 @@ "Swipe needs a globe map": "Bildvergleich braucht eine Globuskarte", "Imagery stays on Esri · CLEAR to use Google 3D": "Bilder bleiben auf Esri · LÖSCHEN, um Google 3D zu verwenden", "Imagery catalog unavailable": "Bildkatalog nicht verfügbar", - "Catalog truncated · a newer clear day may exist": "Katalog gekürzt · ein neuerer klarer Tag ist möglich", + "Catalog truncated · a newer clear day may exist": "Katalog gekürzt · ein neuerer wolkenfreier Tag ist möglich", "{label} catalog unavailable · {detail}": "{label}-Katalog nicht verfügbar · {detail}", "Daily overview for today may still be empty until the pass": "Die tägliche Übersicht für heute kann bis zum Überflug noch leer sein", "Box and images cleared": "Bereich und Bilder gelöscht", @@ -1707,7 +1707,7 @@ "Vehicle {vehicle}": "Fahrzeug {vehicle}", "vehicle motion|Stopped": "Steht", "No recent fix": "Keine aktuelle Position", - "Waiting for update": "Warte auf Aktualisierung", + "Waiting for update": "Warten auf Aktualisierung", "Moving": "In Bewegung", "reported {speed} km/h": "gemeldet {speed} km/h", "reported hdg {heading}°": "gemeldeter Kurs {heading}°", @@ -1727,7 +1727,7 @@ "Train": "Zug", "Ferry": "Fähre", "Transit vehicle": "ÖPNV-Fahrzeug", - "{speed}KT": "{speed}KN", + "{speed}KT": "{speed} KN", "{heading}DEG": "{heading}°", "AIS live load failed": "AIS-Live-Daten konnten nicht geladen werden", "AISSTREAM_API_KEY not set": "AISSTREAM_API_KEY nicht gesetzt", @@ -1759,9 +1759,9 @@ "Observed": "Beobachtet", "History": "Verlauf", "Observation unavailable": "Beobachtung nicht verfügbar", - "Waiting for observation": "Warte auf Beobachtung", + "Waiting for observation": "Warten auf Beobachtung", "{detail} · synced": "{detail} · synchronisiert", - "{detail} · nearest": "{detail} · nächstgelegen", + "{detail} · nearest": "{detail} · zeitlich am nächsten", "RADAR REFLECTIVITY · dBZ": "RADARREFLEKTIVITÄT · dBZ", "LIGHTNING DENSITY · 15 min accumulation": "BLITZDICHTE · 15-min-Summe", "GLOBAL INFRARED · hourly": "GLOBALES INFRAROT · stündlich", @@ -1771,7 +1771,7 @@ "frame {index}/{total}": "Frame {index}/{total}", "loading": "lädt", "Observation: unavailable": "Beobachtung: nicht verfügbar", - "Contiguous US · gaps ≠ no rain": "USA (Festland) · Lücken ≠ kein Regen", + "Contiguous US · gaps ≠ no rain": "USA ohne Alaska/Hawaii · Lücken ≠ kein Regen", "Americas + Pacific · not individual strikes": "Amerika + Pazifik · keine Einzelblitze", "Color: strikes/km²/min ×10³": "Farbe: Blitze/km²/min ×10³", "60°S–60°N · typically 2–3 h delayed": "60°S–60°N · meist 2–3 h verzögert", @@ -1780,7 +1780,7 @@ "Reduced motion · manual history available": "Reduzierte Bewegung · manueller Verlauf verfügbar", "Rain radar · US": "Regenradar · USA", "Lightning density · 15 min": "Blitzdichte · 15 min", - "Satellite clouds": "Satellitenwolken", + "Satellite clouds": "Wolken (Satellit)", "Americas + Pacific": "Amerika + Pazifik", "Global · 60°S–60°N": "Global · 60°S–60°N", "North America": "Nordamerika", @@ -1792,9 +1792,9 @@ "N. America": "Nordamerika", "Global": "Global", "Hourly global mosaic; usually 2–3 hours delayed": "Stündliches globales Mosaik; meist 2–3 Stunden verzögert", - "GOES regional clouds; approximately 5-minute updates": "Regionale GOES-Wolken; Aktualisierung etwa alle 5 Minuten", + "GOES regional clouds; approximately 5-minute updates": "Regionale GOES-Wolkenbilder; Aktualisierung etwa alle 5 Minuten", "Clouds only": "Nur Wolken", - "Apply the full cloud brightness key; 100% filter strength": "Volle Wolkenhelligkeitsskala anwenden; Filterstärke 100 %", + "Apply the full cloud brightness key; 100% filter strength": "Helligkeitsfilter für Wolken vollständig anwenden; Filterstärke 100 %", "Full": "Voll", "Show the complete infrared image; 0% filter strength": "Vollständiges Infrarotbild zeigen; Filterstärke 0 %", "Soft": "Weich", @@ -1842,7 +1842,7 @@ "NOAA GFS surface forecast": "NOAA-GFS-Bodenvorhersage", "Reduced motion": "Reduzierte Bewegung", "Pause visual flow; forecast time does not advance with animation": "Visuelle Strömung pausieren; die Vorhersagezeit läuft mit der Animation nicht weiter", - "None": "Keine", + "None": "Ohne", "Speed": "Geschwindigkeit", "Pressure": "Luftdruck", "Temperature": "Temperatur", @@ -1881,7 +1881,7 @@ "WNW": "WNW", "NW": "NW", "NNW": "NNW", - "No surface reading": "Kein Bodenmesswert", + "No surface reading": "Kein bodennaher Wert", "Aim the map center at Earth": "Kartenmitte auf die Erde richten", "A location reading needs a loaded forecast and the Earth at the center of the view.": "Ein Ortswert braucht eine geladene Vorhersage und die Erde in der Bildmitte.", "Interpolated model forecast on an approximately 1° grid. Broad weather patterns, not a street-level measurement.": "Interpolierte Modellvorhersage auf einem Raster von etwa 1°. Großräumige Wetterlagen, keine Messung auf Straßenebene.", @@ -1969,11 +1969,11 @@ "Bidur / Trishuli Consequence": "Folgen in Bidur / Trishuli", "Final view": "Schlussansicht", "Scene {n}": "Szene {n}", - "the title of scene {scene} is empty or longer than {max} characters": "Der Titel von Szene {scene} ist leer oder länger als {max} Zeichen", - "the title of shot {shot} in scene {scene} is empty or longer than {max} characters": "Der Titel von Aufnahme {shot} in Szene {scene} ist leer oder länger als {max} Zeichen", - "the project is larger than 5 MiB": "Das Projekt ist größer als 5 MiB", - "the project has too many shots": "Das Projekt hat zu viele Aufnahmen", - "the scene data failed validation": "Die Szenendaten haben die Validierung nicht bestanden", + "the title of scene {scene} is empty or longer than {max} characters": "der Titel von Szene {scene} ist leer oder länger als {max} Zeichen", + "the title of shot {shot} in scene {scene} is empty or longer than {max} characters": "der Titel von Aufnahme {shot} in Szene {scene} ist leer oder länger als {max} Zeichen", + "the project is larger than 5 MiB": "das Projekt ist größer als 5 MiB", + "the project has too many shots": "das Projekt hat zu viele Aufnahmen", + "the scene data failed validation": "die Szenendaten haben die Validierung nicht bestanden", "Could not complete this action. Check the file, references and selected assets.": "Diese Aktion konnte nicht abgeschlossen werden. Datei, Verweise und ausgewählte Assets prüfen.", "{count} scenes": { "one": "{count} Szene", @@ -2032,7 +2032,7 @@ "SDR decoder stopped responding; receiver stopped": "SDR-Decoder reagiert nicht mehr; Empfänger gestoppt", "SDR decoder fell behind; receiver stopped": "SDR-Decoder kommt nicht hinterher; Empfänger gestoppt", "WebUSB requires desktop Chrome or Edge": "WebUSB braucht Chrome oder Edge auf dem Desktop", - "Waiting for an RTL-SDR device…": "Warte auf ein RTL-SDR-Gerät…", + "Waiting for an RTL-SDR device…": "Warten auf ein RTL-SDR-Gerät…", "Browser audio is suspended; press Connect again to resume it": "Browser-Audio ist angehalten; erneut auf Verbinden drücken, um es fortzusetzen", "RTL-SDR sample stream stopped": "RTL-SDR-Sample-Stream gestoppt", "Switching to {mode}…": "Wechsel zu {mode}…", @@ -2073,7 +2073,7 @@ "Link shared": "Link geteilt", "Return map to straight-down view": "Karte wieder senkrecht von oben zeigen", "Tilt map to oblique view": "Karte in Schrägansicht kippen", - "Reset map to north up. Current heading {heading} degrees": "Karte nach Norden ausrichten. Aktueller Kurs {heading} Grad", + "Reset map to north up. Current heading {heading} degrees": "Karte nach Norden ausrichten. Aktuelle Ausrichtung {heading} Grad", "Tilted view": "Schrägansicht", "Straight-down view": "Senkrechte Ansicht", "North up": "Norden oben", @@ -2117,7 +2117,7 @@ "{source} · LOCATION QUERY · RECENT": "{source} · ORTSABFRAGE · AKTUELL", "Rendered globe frames per second · toggle with `": "Gerenderte Globus-Frames pro Sekunde · umschalten mit `", "imported map files": "importierte Kartendateien", - "Ground heights could not be refreshed. Try the file again when the map has loaded.": "Geländehöhen konnten nicht aktualisiert werden. Die Datei erneut versuchen, wenn die Karte geladen ist.", + "Ground heights could not be refreshed. Try the file again when the map has loaded.": "Geländehöhen konnten nicht aktualisiert werden. Die Datei erneut laden, wenn die Karte geladen ist.", "{count} map objects": { "one": "{count} Kartenobjekt", "other": "{count} Kartenobjekte" @@ -2153,7 +2153,7 @@ "S2 GhostMaps": "S2 GhostMaps", "Rain radar": "Regenradar", "Lightning density": "Blitzdichte", - "Cyclone advisories": "Sturmwarnungen", + "Cyclone advisories": "Wirbelstürme", "ALPR Cameras": "ALPR-Kameras", "Live Vessels": "Live-Schiffe", "Bike Share": "Bikesharing", @@ -2192,7 +2192,7 @@ "feed status|stale": "veraltet", "feed status|unreachable": "nicht erreichbar", "feed status|invalid": "ungültig", - "waiting for IQ": "warte auf IQ", + "waiting for IQ": "warten auf IQ", "{count} messages": { "one": "{count} Nachricht", "other": "{count} Nachrichten" @@ -2245,14 +2245,14 @@ "{category} ({count})": "{category} ({count})", "PAUSE": "PAUSE", "RESUME": "WEITER", - "Clear reading": "Messwert löschen", + "Clear reading": "Wert ausblenden", "Earlier observation": "Frühere Beobachtung", "Observed history": "Beobachteter Verlauf", "Later observation": "Spätere Beobachtung", "Latest": "Neueste", "Newest frame per product": "Neuester Frame je Produkt", "Replay observed history": "Beobachteten Verlauf abspielen", - "Imagery on Esri · Google 3D returns when cleared": "Bilder auf Esri · Google 3D nach dem Löschen", + "Imagery on Esri · Google 3D returns when cleared": "Bilder auf Esri · nach LÖSCHEN wieder Google 3D", "Point the camera at the ground to use the view": "Kamera auf den Boden richten, um die Ansicht zu verwenden", "That point cannot anchor a box": "Dieser Punkt kann keinen Bereich verankern", "Imagery stops at ±{limit}° latitude": "Bilder enden bei ±{limit}° Breite", @@ -2265,7 +2265,7 @@ "Newest day covering this box · cloudier than 20%": "Neuester Tag mit Abdeckung dieses Bereichs · über 20 % Bewölkung", "Newest day with imagery for this box · partial coverage": "Neuester Tag mit Bildern für diesen Bereich · teilweise Abdeckung", "Newest daily overview for this box": "Neueste tägliche Übersicht für diesen Bereich", - "newest clear day": "neuester klarer Tag", + "newest clear day": "neuester wolkenfreier Tag", "newest day (cloudy)": "neuester Tag (bewölkt)", "newest day (partial coverage)": "neuester Tag (teilweise Abdeckung)", "newest overview": "neueste Übersicht", @@ -2377,13 +2377,13 @@ "Shared satellite is unavailable": "Geteilter Satellit ist nicht verfügbar", "{id} isn't reporting now — showing where it was last seen": "{id} sendet gerade nicht – letzte bekannte Position wird gezeigt", "{id} isn't reporting now — showing where it was at {time}": "{id} sendet gerade nicht – Position um {time} wird gezeigt", - "This share link can't be opened": "Dieser Link zum Teilen kann nicht geöffnet werden", + "This share link can't be opened": "Dieser Freigabelink kann nicht geöffnet werden", "Shared vessel is unavailable": "Geteiltes Schiff ist nicht verfügbar", "subject": "Objekt", "RETRYING ALPR CAMERAS": "ALPR-KAMERAS: NEUER VERSUCH", "FETCHING ALPR CAMERAS": "ALPR-KAMERAS WERDEN ABGERUFEN", "OVERPASS TEMPORARILY UNAVAILABLE": "OVERPASS VORÜBERGEHEND NICHT VERFÜGBAR", - "OVERPASS RATE-LIMITED": "OVERPASS-RATENLIMIT ERREICHT", + "OVERPASS RATE-LIMITED": "OVERPASS-ANFRAGELIMIT ERREICHT", "OVERPASS TIMED OUT": "ZEITÜBERSCHREITUNG BEI OVERPASS", "OVERPASS COULD NOT COMPLETE THE QUERY": "OVERPASS KONNTE DIE ABFRAGE NICHT ABSCHLIESSEN", "MAP TILES TEMPORARILY UNAVAILABLE": "KARTENKACHELN VORÜBERGEHEND NICHT VERFÜGBAR", @@ -2453,7 +2453,7 @@ "LAST 3 MONTHS": "LETZTE 3 MONATE", "LAST MONTH": "LETZTER MONAT", "LAST {count} DAYS": { - "one": "LETZTER {count} TAG", + "one": "{count} TAG", "other": "LETZTE {count} TAGE" }, "{window} · SINCE {date}": "{window} · SEIT {date}", @@ -2462,7 +2462,7 @@ "{name} imagery on": "{name}-Bilder an", "{name} imagery off": "{name}-Bilder aus", "Image by {creator}": "Bild von {creator}", - " or ": " oder", + " or ": " oder ", "OPEN {labels}": "{labels} ÖFFNEN", "Open {names} at the centre of the view": "{names} in der Bildmitte öffnen", "Zoom in to a street to open {names} here": "Auf eine Straße hineinzoomen, um hier {names} zu öffnen", @@ -2509,9 +2509,9 @@ "voice|OFF": "AUS", "voice|CONNECTING": "VERBINDET", "voice|ERROR": "FEHLER", - "Voice provider": "Sprachanbieter", + "Voice provider": "Anbieter der Sprachsteuerung", "Changing provider reconnects voice if it is on.": "Ein Anbieterwechsel verbindet die Sprachsteuerung neu, wenn sie an ist.", - "Voice Settings": "Spracheinstellungen", + "Voice Settings": "Einstellungen der Sprachsteuerung", "STD": "STD", "ON/OFF": "EIN/AUS", "VOICE": "SPRACHE", @@ -2592,7 +2592,7 @@ "Usage is incomplete because a response was still in flight when the session ended.": "Die Nutzung ist unvollständig, weil beim Sitzungsende noch eine Antwort unterwegs war.", "Estimate is incomplete — a response was still in flight when the session ended, so its usage was never reported.": "Schätzung unvollständig – beim Sitzungsende war noch eine Antwort unterwegs, ihre Nutzung wurde daher nie gemeldet.", "STANDARD": "STANDARD", - "MIC": "MIK", + "MIC": "MIKRO", "{n} aircraft": { "one": "{n} Luftfahrzeug", "other": "{n} Luftfahrzeuge" @@ -2673,7 +2673,7 @@ "last 24 h": "letzte 24 h", "past 30 d and upcoming": "letzte 30 Tage und anstehende", "the flights layer loads by viewport": "die Flugebene lädt nach Bildausschnitt", - "distance is ground distance, not overhead": "Entfernung ist Bodenentfernung, nicht über Kopf", + "distance is ground distance, not overhead": "Entfernung am Boden, ohne Berücksichtigung der Höhe", "the count is a lower bound because at least one layer reached its retained limit.": "die Anzahl ist eine Untergrenze, weil mindestens eine Ebene ihr Speicherlimit erreicht hat.", "{label} off": "{label} aus", "{label} loading": "{label} lädt", @@ -2681,8 +2681,8 @@ "counted the first {returned} loaded records": "die ersten {returned} geladenen Einträge gezählt", "counted {returned} of {total} loaded records": "{returned} von {total} geladenen Einträgen gezählt", "{layers} just turned on — still loading, counts will rise": "{layers} gerade eingeschaltet – lädt noch, die Zahlen steigen", - "Contacts panel snapshot at {time} — the same retained cohort supplies the card, speech, and follow-up memory": "Snapshot des Kontaktbereichs um {time} – dieselbe gespeicherte Auswahl liefert Karte, Sprachausgabe und Gedächtnis für Folgefragen", - "Contacts panel snapshot — the same retained cohort supplies the card, speech, and follow-up memory": "Snapshot des Kontaktbereichs – dieselbe gespeicherte Auswahl liefert Karte, Sprachausgabe und Gedächtnis für Folgefragen", + "Contacts panel snapshot at {time} — the same retained cohort supplies the card, speech, and follow-up memory": "Snapshot des Kontaktbereichs um {time} – dieselbe gespeicherte Auswahl liefert die Sprachkarte, die Sprachausgabe und das Gedächtnis für Folgefragen", + "Contacts panel snapshot — the same retained cohort supplies the card, speech, and follow-up memory": "Snapshot des Kontaktbereichs – dieselbe gespeicherte Auswahl liefert die Sprachkarte, die Sprachausgabe und das Gedächtnis für Folgefragen", "Fly below {km} km to a covered region": "Unter {km} km zu einer abgedeckten Region fliegen", "No feed here yet · {n} regions available": { "one": "Hier noch kein Feed · {n} Region verfügbar", @@ -2841,7 +2841,7 @@ "FT": "FT", "FLT": "FLÜGE", "MIL": "MIL", - "SITE": "ORTE", + "SITE": "STANDORTE", "WX": "WETTER", "MM": "MM", "Weather data by Open-Meteo.com": "Wetterdaten von Open-Meteo.com", @@ -2933,6 +2933,6 @@ "Toggle straight-down and tilted map views": "Zwischen senkrechter und geneigter Kartenansicht wechseln", "Reset map to north up": "Karte nach Norden ausrichten", "Reset map bearing to north": "Kartenausrichtung auf Norden zurücksetzen", - "Cyclone request timed out": "Zeitüberschreitung bei der Sturmabfrage", - "Malformed cyclone snapshot": "Fehlerhafter Sturm-Snapshot" + "Cyclone request timed out": "Zeitüberschreitung bei der Wirbelsturm-Abfrage", + "Malformed cyclone snapshot": "Fehlerhafter Wirbelsturm-Snapshot" } diff --git a/src/layers/directions/index.js b/src/layers/directions/index.js index b8cceff02..8b5400cda 100644 --- a/src/layers/directions/index.js +++ b/src/layers/directions/index.js @@ -18,7 +18,13 @@ import * as Cesium from 'cesium'; import { roadLabel } from '../../data/routeSteps.js'; -import { t, msg, formatNumber, translateKnown } from '../../i18n/index.js'; +import { + t, + msg, + formatNumber, + getLocale, + translateKnown, +} from '../../i18n/index.js'; import { pointerOwnerName } from '../../data/pointerOwnerNames.js'; import { formatQuantity } from '../../ui/unitLabels.js'; @@ -406,6 +412,16 @@ export function normalizeDirectionsParams(params = {}) { return out; } +/** + * A travel-mode word inside a sentence: lower case, except in German, where + * the words are nouns and keep their capital ("Auto", "Fahrrad"). + * @param {string} word Translated mode word. + * @returns {string} + */ +function modeWordInSentence(word) { + return getLocale() === 'de' ? word : word.toLowerCase(); +} + /** * Row chips for a given state. Pure so the chip logic is testable without a DOM. * @param {{mode:string, armed:null|'a'|'b', a:object|null, b:object|null, status:string, route:object|null}} state @@ -421,7 +437,7 @@ export function directionsRowControls(state) { state: mode === id ? 'active' : 'idle', title: t('{mode} — reroute for {modeLower}', { mode: t(spec.word), - modeLower: t(spec.word).toLowerCase(), + modeLower: modeWordInSentence(t(spec.word)), }), params: { mode: id }, })); diff --git a/src/scenes/recipes.js b/src/scenes/recipes.js index ba3940a57..081fa1db4 100644 --- a/src/scenes/recipes.js +++ b/src/scenes/recipes.js @@ -1069,13 +1069,34 @@ export function displaySceneTitle(scene) { export function displayShotTitle(title, shot = undefined, scene = undefined) { const text = typeof title === 'string' ? title : ''; const fromRecipe = shot - ? Boolean(shot.sourcePackId) || recipeDeclaresShotTitle(scene?.id, text) + ? Boolean(shot.sourcePackId) || + recipeDeclaresShotTitle(scene?.id, text) || + shotPackDeclaresBaseTitle(scene, text) : true; if (fromRecipe && BUILTIN_SHOT_TITLES.has(text)) return t(text); const numbered = /^Shot ([1-9]\d*)$/.exec(text); return numbered ? t('Shot {n}', { n: numbered[1] }) : text; } +/** + * Whether a shot pack that upgraded this scene declares the title for one of + * its legacy base shots. The upgrade rebuilds those shots without a + * sourcePackId (see SceneDirector._bootstrapLegacyShotPacks), so the pack's + * own shots in the scene vouch for them. + * @param {{shots?: Array<{sourcePackId?: string}>}} [scene] + * @param {string} title + * @returns {boolean} + */ +function shotPackDeclaresBaseTitle(scene, title) { + const shots = Array.isArray(scene?.shots) ? scene.shots : []; + return SCENE_APPEND_RECIPES.some( + (pack) => + pack.legacySceneBootstrap?.cameraPath?.some( + (keyframe) => keyframe?.title === title, + ) && shots.some((item) => item?.sourcePackId === pack.id), + ); +} + /** Whether the built-in recipe behind a scene declares a shot with this title. */ function recipeDeclaresShotTitle(sceneId, title) { const recipe = sceneId ? getSceneRecipeById(sceneId) : null; diff --git a/src/scenes/sceneTitleDisplay.test.mjs b/src/scenes/sceneTitleDisplay.test.mjs index 604e01c49..a5d157e64 100644 --- a/src/scenes/sceneTitleDisplay.test.mjs +++ b/src/scenes/sceneTitleDisplay.test.mjs @@ -4,6 +4,7 @@ import test from 'node:test'; import assert from 'node:assert/strict'; import { + SCENE_APPEND_RECIPES, SCENE_RECIPES, displaySceneTitle, displayShotTitle, @@ -141,3 +142,24 @@ test('the scene context of a shot carries its display title by provenance', asyn title, ); }); + +test('the base shots of a scene the Nepal pack upgraded localize', () => { + const pack = SCENE_APPEND_RECIPES.find( + (recipe) => recipe.legacySceneBootstrap?.cameraPath?.length, + ); + if (!pack) return; + setLocale('de'); + const title = pack.legacySceneBootstrap.cameraPath[0].title; + const base = { id: 'shot-base', title }; + const upgraded = { + id: 'scene-upgraded', + shots: [base, { id: 'shot-pack', title: 'x', sourcePackId: pack.id }], + }; + assert.equal(displayShotTitle(title, base, upgraded), displayShotTitle(title)); + assert.notEqual(displayShotTitle(title), title); + // The same title in a scene no pack touched stays as typed. + assert.equal( + displayShotTitle(title, base, { id: 'scene-user', shots: [base] }), + title, + ); +}); diff --git a/src/ui/layerPanel.js b/src/ui/layerPanel.js index 18b71dabf..afe255733 100644 --- a/src/ui/layerPanel.js +++ b/src/ui/layerPanel.js @@ -136,9 +136,11 @@ export function layerKeyRequirementTooltip(layer = {}) { const ROW_TEXT_SEPARATOR = ' · '; -// A short Latin code joined by hyphens. Longer runs (a URL, a token in an -// error) keep their break opportunities so they cannot overflow the rail. -const HYPHENATED_CODE = /[A-Za-z0-9]+(?:-[A-Za-z0-9]+)+/g; +// A short Latin code joined by hyphens: every part after a hyphen is capitals +// or digits (ADS-B, RTL-SDR, GTFS-RT). A compound such as "ALPR-Kameras" is a +// word, not a code, and may break at its hyphen. Longer runs (a URL, a token +// in an error) keep their break opportunities so they cannot overflow the rail. +const HYPHENATED_CODE = /\b[A-Za-z0-9]+(?:-[A-Z0-9]+)+(?![A-Za-z0-9])/g; const HYPHENATED_CODE_MAX = 16; /** A span for one run of row text; `keep` stops the browser breaking inside it. */ diff --git a/src/ui/layerPanel.test.mjs b/src/ui/layerPanel.test.mjs index b4b771e1a..5a6f78c8f 100644 --- a/src/ui/layerPanel.test.mjs +++ b/src/ui/layerPanel.test.mjs @@ -303,6 +303,15 @@ test('row text keeps a hyphenated code whole and never starts a line with the se assert.equal(plain.textContent, 'Satellites'); assert.equal(plain.children.length, 0); + const compound = element(); + setRowText(compound, 'Kartierte ALPR-Kameras · ADS-B-Flüge'); + assert.equal(text(compound), 'Kartierte ALPR-Kameras · ADS-B-Flüge'); + assert.deepEqual( + kept(compound), + [' ·', 'ADS-B'], + 'a compound may break at its hyphen; the code inside it stays whole', + ); + const long = element(); setRowText(long, 'see https-proxy-endpoint-config-x'); assert.deepEqual(kept(long), [], 'a long hyphenated run may still wrap'); diff --git a/src/ui/styles/bhote-koshi.css b/src/ui/styles/bhote-koshi.css index 21a0348f7..f9e9ea1d1 100644 --- a/src/ui/styles/bhote-koshi.css +++ b/src/ui/styles/bhote-koshi.css @@ -518,14 +518,15 @@ html:not([lang='en']) .bhote-event-story-current strong { -webkit-line-clamp: 2; } -/* Phase / time / sources run long in translation: allow a second line. */ +/* Phase / time / sources / imagery note run long in translation: allow up to + three lines so the last status is not cut off. */ html:not([lang='en']) .bhote-event-story-current small { display: -webkit-box; margin-top: 3px; text-overflow: clip; white-space: normal; -webkit-box-orient: vertical; - -webkit-line-clamp: 2; + -webkit-line-clamp: 3; } .bhote-event-actions { diff --git a/src/ui/styles/radio.css b/src/ui/styles/radio.css index 483321992..e7607c42c 100644 --- a/src/ui/styles/radio.css +++ b/src/ui/styles/radio.css @@ -688,6 +688,12 @@ html:not([lang='en']) .data-count { text-wrap: balance; } +/* The status column keeps its width, so a wide chip (WIRD AKTIVIERT) never + overlaps the name; the name wraps in the room left beside it. */ +html:not([lang='en']) .data-toggle-right { + flex: none; +} + /* Row text pieces that must not break inside: a hyphenated code (ADS-B) and the space before a " · " separator (see setRowText in layerPanel.js). */ html:not([lang='en']) .data-keep { From b96c1dee151b59e443c45e38697f443fecf750b8 Mon Sep 17 00:00:00 2001 From: German Khokhlov Date: Wed, 28 Oct 2026 17:41:29 +0400 Subject: [PATCH 28/83] i18n(it): apply review round 2 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Three-model review (astra, sol, fable): 42 findings accepted, 3 deferred (unmarked cyclone errors and the Chinese locale descriptors need new keys in every catalog). The USGS callout now reads as an action (APRI LA FONTE) because it opens the report. Layer, tool and card-title sentences agree with any feature name («Il livello {layer} è attivo», «Lo strumento {name}», «{label}: attivato»). The store write error is grammatical for both values. RADO/BILANCIATO agree with DENSO. Also fixes the meaning of viewpoint, fire incident, trigger record, transit report, FIRMS cell age, drizzle, widebody and fast-jet classes; Dissolvenza and CH replace the odd abbreviations; cause/hint dashes become colons. Fixes the Nepal scene showing shots 01-08 in English in every locale: displayShotTitle() now also trusts the bootstrap keyframes of the append recipe that upgrades a built-in scene (src/scenes/recipes.js, with a test). Co-Authored-By: Claude Opus 5.5 --- docs/translations/it.md | 11 ++- src/i18n/locales/it.json | 128 +++++++++++++------------- src/i18n/same-as-english.json | 1 + src/scenes/recipes.js | 12 ++- src/scenes/sceneTitleDisplay.test.mjs | 26 ++++++ 5 files changed, 111 insertions(+), 67 deletions(-) diff --git a/docs/translations/it.md b/docs/translations/it.md index 3b7bd2ec7..610d85b01 100644 --- a/docs/translations/it.md +++ b/docs/translations/it.md @@ -14,9 +14,10 @@ Translation source: abiyeenzo (#912). - The HUD codes HDG, BRG, CRS, FOV and DEST stay in English, as in cockpit avionics. RANGE is «PORTATA». Words used in a sentence are translated: heading → «prua» (aircraft, ships) or «direzione» (camera, buses, trams, trains), course → «rotta». - Keyboard keys stay in English: Space, Enter, Esc, Tab, Shift, Backspace, H, 1–9 («Tieni premuto Space per parlare», «Premi Enter per riprovare»). - Decimal comma in numbers written in the text: «28,2710° N». Numbers formatted by the code follow `Intl` and need nothing. +- Amounts: thousands, millions and billions are written out or abbreviated in Italian, not with K/M/B: «{amount} mila $», «{amount} mln $», «{amount} mld $». - Units: km, m, km/h, m/s, kn (knots), ft (feet), h, min, s; in UPPERCASE text KM, KM/S, KT, FT, MIN, H. "m" is always metres, so minutes are «min» («5 min fa»). MW stays MW. `°` and `%` stay. - "ago" goes after the time: «{count} min fa». When a placeholder already holds a localized "ago" text (`{age}`, `{ago}`), do not add «fa» again. -- A feature name used as a sentence subject gets a head noun so the verb agrees: «La modalità Missioni spaziali isola…», «Il pannello Impostazioni provider è disattivato…». +- A feature name used as a sentence subject gets a head noun so the verb agrees: «La modalità Missioni spaziali isola…», «Il pannello Impostazioni provider è disattivato…», «Il livello {layer} è attivo…», «Lo strumento {name} è attivo…». A short card title with a placeholder name puts the state after a colon: «{label}: attivato». - English loanwords that Italian UIs use as they are stay in English: feed, live, cockpit, briefing, preset, overlay, layout, snapshot, tile, provider, timeout, payload, bloom, scope. ## Plurals @@ -51,6 +52,9 @@ The `many` form is the `other` text with «di» after the number when a noun fol | aircraft, plane / flight / military flights | aereo / volo / voli militari | | vessel, ship | nave | | satellite / shell (Starlink) / DENSE | satellite / shell / DENSO | +| SPARSE / BALANCED / DENSE (detection modes) | RADO / BILANCIATO / DENSO (agree with «overlay») | +| broadband (Starlink shell) | a banda larga | +| VISUAL (CelesTrak group) | VISIBILI | | launch (rocket) / launch site / space mission | lancio / sito di lancio / missione spaziale | | ascent / replay / payload / stage | salita / replay / payload / stadio | | contact / tracking | contatto / tracciamento | @@ -58,10 +62,14 @@ The `many` form is the `other` text with «di» after the number when a noun fol | mapped / observed | mappato / osservato | | camera (view) / camera, CCTV camera | camera / telecamera, telecamera CCTV | | earthquake / active fire / fire perimeter | terremoto / incendio attivo / perimetro dell'incendio | +| incident (wildfire, Type N) / scene incident | evento (Evento di tipo N, Incendio senza nome) / evento | +| trigger record (USGS card) / OPEN SOURCE link | scheda / APRI LA FONTE | | advisory (NHC/CPHC cyclone) / cone | bollettino / cono di incertezza | | radio station / broadcaster | stazione radio / emittente | +| CH (radio channel readout) | CH (unchanged) | | road / flow (traffic) | strada / flusso | | transit / bike share | trasporto pubblico / bike sharing | +| last report (vehicle position) | ultima segnalazione | | scene / shot / scene recipe | scena / scatto / ricetta della scena | | anchor / data pack / bundle (scene) | ancora / pacchetto dati / pacchetto | | story beat | tappa del racconto | @@ -88,6 +96,7 @@ The `many` form is the `other` text with «di» after the number when a noun fol | RANGE / PITCH / HGT (CCTV calibration) | PORTATA / INCL. / ALT. | | PREV / NEXT | PREC / SUCC | | Previous / Next (button text) | Precedente / Successivo | +| Focus {target} (action, aria label) | Inquadra {target} (the FOCUS button stays FOCUS) | | L / R (relative bearing) | S / D | | SIG / NEWS / LOCAL (briefing tabs) | SIG / NOTIZIE / LOCALE | | compass points (N, NNE, …, W, NW) | N, NNE, …, O, NO (west is «O», ovest) | diff --git a/src/i18n/locales/it.json b/src/i18n/locales/it.json index 7afaa6335..ce5f7da1d 100644 --- a/src/i18n/locales/it.json +++ b/src/i18n/locales/it.json @@ -17,7 +17,7 @@ "That shape could not be placed.": "Impossibile posizionare quella forma.", "Could not place the shape: {error}": "Impossibile posizionare la forma: {error}", "Board cleared.": "Lavagna cancellata.", - "{owner} is using the pointer — close it first.": "{owner} sta usando il puntatore: chiudilo prima.", + "{owner} is using the pointer — close it first.": "Lo strumento {owner} sta usando il puntatore: chiudilo prima.", "{label} · Detailed outline unavailable": "{label} · Contorno dettagliato non disponibile", "Flying to Austin, TX...": "Volo verso Austin, TX...", "Restoring shared view...": "Ripristino della vista condivisa...", @@ -34,10 +34,10 @@ "Glider": "Aliante", "Turboprop": "Turboelica", "Airliner": "Aereo di linea", - "Widebody": "Fusoliera larga", + "Widebody": "Aereo a fusoliera larga", "Four-engine jet": "Quadrigetto", "Helicopter": "Elicottero", - "Fast jet": "Jet veloce", + "Fast jet": "Jet ad alte prestazioni", "Business jet": "Business jet", "Drone": "Drone", "General emergency": "Emergenza generale", @@ -51,12 +51,12 @@ "Flood footage": "Riprese dell'alluvione", "Compilation and casualty claims": "Raccolta di video e dichiarazioni sulle vittime", "SOURCE GEOCONFIRMED · WORLD-PINNED": "FONTE GEOCONFERMATA · ANCORATA AL MONDO", - "SOURCE CREDITED · LOCATION UNRESOLVED": "FONTE CITATA · POSIZIONE NON RISOLTA", + "SOURCE CREDITED · LOCATION UNRESOLVED": "FONTE CITATA · POSIZIONE NON DETERMINATA", "REFERENCE ONLY · CLAIMS UNVERIFIED": "SOLO RIFERIMENTO · DICHIARAZIONI NON VERIFICATE", "SOURCE GEOCONFIRMED": "FONTE GEOCONFERMATA", - "2021 historical reference versus 2026 post-event imagery; changes are cumulative and include the July 2025 Rasuwagadhi flood. Schematic downstream progression, not modeled arrival time; not an official hazard model.": "Riferimento storico 2021 contro immagini 2026 successive all'evento; i cambiamenti sono cumulativi e includono l'alluvione di Rasuwagadhi del luglio 2025. Progressione schematica a valle, non un tempo di arrivo modellato; non è un modello ufficiale di pericolosità.", - "Immediate collapse viewpoint": "Punto di vista sul crollo immediato", - "Collapse viewpoint": "Punto di vista sul crollo", + "2021 historical reference versus 2026 post-event imagery; changes are cumulative and include the July 2025 Rasuwagadhi flood. Schematic downstream progression, not modeled arrival time; not an official hazard model.": "Confronto tra il riferimento storico del 2021 e le immagini del 2026 successive all'evento; i cambiamenti sono cumulativi e includono l'alluvione di Rasuwagadhi del luglio 2025. Progressione schematica a valle, senza modellazione dei tempi di arrivo; non è un modello ufficiale di pericolosità.", + "Immediate collapse viewpoint": "Punto di osservazione ravvicinato sul crollo", + "Collapse viewpoint": "Punto di osservazione sul crollo", "Debris-dammed lake": "Lago di sbarramento da detriti", "Dammed lake": "Lago di sbarramento", "Second landslide": "Seconda frana", @@ -144,7 +144,7 @@ "FIELD REPORTS · {count}": "RAPPORTI DAL CAMPO · {count}", "GEOLOCATIONS · {credit}": "GEOLOCALIZZAZIONI · {credit}", "↗ OPEN PUBLIC MAP": "↗ APRI LA MAPPA PUBBLICA", - " Clouds are preserved from the source imagery.": " Le nuvole sono conservate dalle immagini di origine.", + " Clouds are preserved from the source imagery.": " Le nuvole presenti nelle immagini di origine non sono state rimosse.", "Rasuwagadhi witness": "Testimone a Rasuwagadhi", "Open original source for {source}; capture time unverified": "Apri la fonte originale per {source}; ora di acquisizione non verificata", "Historical reference and post-event image divider": "Divisore tra immagine storica di riferimento e immagine successiva all'evento", @@ -185,7 +185,7 @@ "26 AUG 2026 · 08:37 NPT": "26 AGO 2026 · 08:37 NPT", "28.2710° N · 85.5150° E": "28,2710° N · 85,5150° E", "INITIAL M4.4 · RECLASSIFIED M5.2 LANDSLIDE": "INIZIALE M4.4 · RICLASSIFICATO FRANA M5.2", - "USGS EVENT us7000tbwb · OPEN SOURCE": "EVENTO USGS us7000tbwb · FONTE APERTA", + "USGS EVENT us7000tbwb · OPEN SOURCE": "EVENTO USGS us7000tbwb · APRI LA FONTE", "Open the USGS initial report for the 26 August 2026 Nepal landslide": "Apri il rapporto iniziale USGS sulla frana del 26 agosto 2026 in Nepal", "Show the Nepal context callout without a border or country fill": "Mostra il riquadro di contesto sul Nepal senza confine né riempimento del paese", "Introduce Nepal, draw its border, then reveal the Bhote Koshi incident": "Presenta il Nepal, traccia il suo confine, poi mostra l'evento del Bhote Koshi", @@ -197,8 +197,8 @@ "Animate the sourced cyan river-centerline route to Trishuli Bazaar": "Anima il percorso ciano documentato dalle fonti lungo l'asse del fiume fino a Trishuli Bazaar", "OVERVIEW": "PANORAMICA", "Keep the completed flood path and location labels visible": "Mantieni visibili il percorso completo dell'alluvione e le etichette dei luoghi", - "RECORD": "REGISTRO", - "Reveal the trigger record while making a slow camera approach": "Mostra il registro dell'innesco con un lento avvicinamento della camera", + "RECORD": "SCHEDA", + "Reveal the trigger record while making a slow camera approach": "Mostra la scheda dell'innesco con un lento avvicinamento della camera", "{speed} kn": "{speed} kn", "That file is not valid JSON.": "Quel file non è un JSON valido.", "That JSON file is not GeoJSON.": "Quel file JSON non è GeoJSON.", @@ -272,10 +272,10 @@ "GNSS navigation — GPS, GLONASS, Galileo": "Navigazione GNSS — GPS, GLONASS, Galileo", "GEO": "GEO", "Geostationary belt — comms and weather, fixed over the equator": "Fascia geostazionaria — comunicazioni e meteo, fissi sopra l'equatore", - "VISUAL": "VISIVO", + "VISUAL": "VISIBILI", "Brightest naked-eye objects — CelesTrak visual group": "Oggetti più luminosi a occhio nudo — gruppo visual di CelesTrak", "COMMS": "TLC", - "Broadband constellation shell — shown only in DENSE mode": "Shell della costellazione broadband — mostrato solo in modalità DENSO", + "Broadband constellation shell — shown only in DENSE mode": "Shell della costellazione a banda larga — mostrato solo in modalità DENSO", "FISHING": "PESCA", "TOWING": "RIMORCHIO", "DREDGER": "DRAGA", @@ -379,7 +379,7 @@ "{name} is configured outside Provider Settings and can only be changed where it was set": "{name} è configurata fuori da Impostazioni provider e si può cambiare solo dove è stata impostata", "The key was not saved: could not restrict the credential file to your account; nothing was saved": "La chiave non è stata salvata: impossibile limitare il file delle credenziali al tuo account; non è stato salvato nulla", "The key was not saved: the existing configuration could not be read, so nothing was changed": "La chiave non è stata salvata: impossibile leggere la configurazione esistente, quindi non è cambiato nulla", - "Could not write the {store} store": "Impossibile scrivere nell'archivio {store}", + "Could not write the {store} store": "Impossibile salvare: {store} non è scrivibile", "Save failed ({status}).": "Salvataggio non riuscito ({status}).", "OAuth check failed: {detail}": "Verifica OAuth non riuscita: {detail}", "Could not check ChatGPT sign-in. Try again.": "Impossibile verificare l'accesso a ChatGPT. Riprova.", @@ -418,7 +418,7 @@ "Opening ChatGPT sign-in in your browser…": "Apertura dell'accesso a ChatGPT nel browser…", "Could not start ChatGPT sign-in on this machine.": "Impossibile avviare l'accesso a ChatGPT su questa macchina.", "Finish ChatGPT sign-in in the browser. Waiting for it to complete…": "Completa l'accesso a ChatGPT nel browser. In attesa del completamento…", - "ChatGPT sign-in timed out. Click {button} to try again.": "Accesso a ChatGPT scaduto. Fai clic su {button} per riprovare.", + "ChatGPT sign-in timed out. Click {button} to try again.": "Tempo scaduto per l'accesso a ChatGPT. Fai clic su {button} per riprovare.", "ChatGPT sign-in complete. OAuth will be used for the next cloud voice session.": "Accesso a ChatGPT completato. OAuth verrà usato per la prossima sessione vocale cloud.", "Remove this key from your saved configuration?": "Rimuovere questa chiave dalla configurazione salvata?", "Removed from {store}. Restarting — this page reloads itself.": "Rimosso ({store}). Riavvio in corso: questa pagina si ricarica da sola.", @@ -491,7 +491,7 @@ "SELECT A FLIGHT, VESSEL, OR MAPPED INSTALLATION": "SELEZIONA UN VOLO, UNA NAVE O UN'INSTALLAZIONE MAPPATA", "ENABLE TO LOAD OBSERVED / MAPPED PROXIMITY": "ATTIVA PER CARICARE LA PROSSIMITÀ OSSERVATA / MAPPATA", "Unavailable": "Non disponibile", - "Focus {label}": "Focus su {label}", + "Focus {label}": "Inquadra {label}", "Global Context navigation": "Navigazione Contesto globale", "Previous — prior visited contact in the 250 km window": "Precedente — contatto visitato in precedenza nella finestra di 250 km", "PREVIOUS": "PREC", @@ -561,7 +561,7 @@ "many": "{count} di tempeste attive", "other": "{count} tempeste attive" }, - "Position as of {time}": "Posizione alle {time}", + "Position as of {time}": "Posizione aggiornata al {time}", "Maximum sustained wind: {wind} · Pressure: {pressure}": "Vento massimo sostenuto: {wind} · Pressione: {pressure}", "{name} · {classification} · Advisory {number} · issued {time}": "{name} · {classification} · Bollettino {number} · emesso {time}", "No active NHC/CPHC systems": "Nessun sistema NHC/CPHC attivo", @@ -610,7 +610,7 @@ "lane direction|slightly right": "di destra", "lane direction|sharply left": "all'estrema sinistra", "lane direction|sharply right": "all'estrema destra", - "lane direction|straight": "centrale", + "lane direction|straight": "per proseguire dritto", "ordinal|{number}st": "{number}ª", "ordinal|{number}nd": "{number}ª", "ordinal|{number}rd": "{number}ª", @@ -685,8 +685,8 @@ "action|CLEAR": "CANCELLA", "Remove the route and both markers": "Rimuovi il percorso ed entrambi i marcatori", "press Escape twice to leave Draw": "premi Esc due volte per uscire da Disegno", - "{name} is active — turn {name} off, then set {endpoint}": "{name} è attivo: disattiva {name}, poi imposta {endpoint}", - "{name} is active — {leave}, then set {endpoint}": "{name} è attivo: {leave}, poi imposta {endpoint}", + "{name} is active — turn {name} off, then set {endpoint}": "Lo strumento {name} è attivo: disattiva {name}, poi imposta {endpoint}", + "{name} is active — {leave}, then set {endpoint}": "Lo strumento {name} è attivo: {leave}, poi imposta {endpoint}", "Only the first {count} turns of this route are shown": "Sono mostrate solo le prime {count} svolte di questo percorso", "Turn-by-turn directions": "Indicazioni passo passo", "Another map tool is using clicks — close it, then SET A again": "Un altro strumento della mappa sta usando i clic: chiudilo, poi IMPOSTA A di nuovo", @@ -705,7 +705,7 @@ "Routing timed out": "Il calcolo del percorso è andato in timeout", "Routing unavailable — no response from the routing service": "Calcolo del percorso non disponibile: nessuna risposta dal servizio", "Earthquake source unavailable": "Fonte dei terremoti non disponibile", - "Focus fire detection {title}, {details}": "Focus sul rilevamento incendio {title}, {details}", + "Focus fire detection {title}, {details}": "Inquadra il rilevamento d'incendio {title}, {details}", "live feed unavailable": "feed live non disponibile", "{value} conf": "{value} conf", "{value} ago": "{value} fa", @@ -716,7 +716,7 @@ "FIRE": "INCENDIO", "FIRES": "INCENDI", "max {value} MW": "max {value} MW", - "new {value}": "nuovo {value}", + "new {value}": "ultimo: {value} fa", "{value}°N": "{value}°N", "{value}°S": "{value}°S", "{value}°E": "{value}°E", @@ -903,7 +903,7 @@ "Type unknown": "Tipo sconosciuto", "Reg unknown": "Matricola sconosciuta", "Operator unknown": "Operatore sconosciuto", - "${amount}K": "{amount}K $", + "${amount}K": "{amount} mila $", "${amount}M": "{amount} mln $", "${amount}B": "{amount} mld $", "fire cause|Human": "Umana", @@ -914,7 +914,7 @@ "fire behavior|Moderate": "Moderato", "fire behavior|Active": "Attivo", "fire behavior|Extreme": "Estremo", - "Type {level} Incident": "Incidente di tipo {level}", + "Type {level} Incident": "Evento di tipo {level}", "age|{count}m": "{count} min", "{acres} ac": { "one": "{acres} acro", @@ -936,7 +936,7 @@ "part of {complex}": "parte di {complex}", "InciWeb ↗ · click card to open": "InciWeb ↗ · clic sulla scheda per aprirlo", "FIRE · {name}": "INCENDIO · {name}", - "Unnamed incident": "Incidente senza nome", + "Unnamed incident": "Incendio senza nome", "Open {title} on InciWeb": "Apri {title} su InciWeb", "Perimeter source unavailable": "Fonte dei perimetri non disponibile", "Not contained or unknown": "Non contenuto o dato non disponibile", @@ -1020,11 +1020,11 @@ "Longitudes must be within ±180°": "Le longitudini devono essere entro ±180°", "Select one side of the dateline": "Seleziona un solo lato della linea del cambio di data", "Box must enclose an area": "Il riquadro deve racchiudere un'area", - "Add the full Starlink broadband shell (thousands of extra points)": "Aggiungi l'intero shell broadband Starlink (migliaia di punti in più)", + "Add the full Starlink broadband shell (thousands of extra points)": "Aggiungi l'intero shell Starlink a banda larga (migliaia di punti in più)", "Loading the Starlink shell…": "Caricamento dello shell Starlink…", - "Starlink {detail} — click to retry": "Starlink {detail} — clic per riprovare", + "Starlink {detail} — click to retry": "Starlink {detail}: clic per riprovare", "load failed": "caricamento non riuscito", - "Showing the full Starlink shell — click for the core catalog only": "Mostra l'intero shell Starlink — clic per il solo catalogo principale", + "Showing the full Starlink shell — click for the core catalog only": "Shell Starlink completo visualizzato: clic per mostrare solo il catalogo principale", "DENSE ···": "DENSO ···", "DENSE ✕": "DENSO ✕", "DENSE": "DENSO", @@ -1131,7 +1131,7 @@ "occupancy|crushed standing room only": "solo posti in piedi, affollato", "occupancy|full": "pieno", "occupancy|not accepting passengers": "non accetta passeggeri", - "occupancy|not boardable": "non accessibile", + "occupancy|not boardable": "non è possibile salire", "Route {route}": "Linea {route}", "Vehicle {vehicle}": "Veicolo {vehicle}", "vehicle motion|Stopped": "Fermo", @@ -1140,9 +1140,9 @@ "Moving": "In movimento", "reported {speed} km/h": "{speed} km/h riportati", "reported hdg {heading}°": "direzione {heading}° riportata", - "Last report: stopped at stop {stop}": "Ultimo rapporto: fermo alla fermata {stop}", - "Last report: arriving at stop {stop}": "Ultimo rapporto: in arrivo alla fermata {stop}", - "Last report: next stop {stop}": "Ultimo rapporto: prossima fermata {stop}", + "Last report: stopped at stop {stop}": "Ultima segnalazione: fermo alla fermata {stop}", + "Last report: arriving at stop {stop}": "Ultima segnalazione: in arrivo alla fermata {stop}", + "Last report: next stop {stop}": "Ultima segnalazione: prossima fermata {stop}", "Shown at street level · depth not in the feed": "Mostrato a livello stradale · profondità non presente nel feed", "Reported {seconds} s ago": "Riportato {seconds} s fa", "Reported {minutes} min ago": "Riportato {minutes} min fa", @@ -1176,11 +1176,11 @@ "API key rejected — check AISSTREAM_API_KEY": "Chiave API rifiutata: controlla AISSTREAM_API_KEY", "feed silent {seconds}s — no AIS data": "feed silenzioso da {seconds}s: nessun dato AIS", "feed silent — no AIS data": "feed silenzioso: nessun dato AIS", - "feed down — retrying slowly (attempt {attempt})": "feed fermo: nuovi tentativi lenti (tentativo {attempt})", + "feed down — retrying slowly (attempt {attempt})": "feed inattivo: nuovi tentativi lenti (tentativo {attempt})", "reconnecting to feed… (attempt {attempt})": "riconnessione al feed… (tentativo {attempt})", - "feed down — retrying slowly": "feed fermo: nuovi tentativi lenti", + "feed down — retrying slowly": "feed inattivo: nuovi tentativi lenti", "reconnecting to feed…": "riconnessione al feed…", - "Focus vessel {name}, MMSI {mmsi}": "Focus sulla nave {name}, MMSI {mmsi}", + "Focus vessel {name}, MMSI {mmsi}": "Inquadra la nave {name}, MMSI {mmsi}", "Hidden by this map source · choose a globe map": "Nascosto da questa fonte mappa · scegli una mappa del globo", "Weather image HTTP {status}": "Immagine meteo HTTP {status}", "Weather HTTP {status}": "Meteo HTTP {status}", @@ -1188,8 +1188,8 @@ "Weather imagery unavailable": "Immagini meteo non disponibili", "Weather source unavailable; previous observation retained": "Fonte meteo non disponibile; mantenuta l'osservazione precedente", "Weather unavailable": "Meteo non disponibile", - "No frame within {gap} min of {time}": "Nessun fotogramma entro {gap} min dalle {time}", - "No frame within {gap} h of {time}": "Nessun fotogramma entro {gap} h dalle {time}", + "No frame within {gap} min of {time}": "Nessun fotogramma entro {gap} min da {time}", + "No frame within {gap} h of {time}": "Nessun fotogramma entro {gap} h da {time}", "{hours}h {minutes}m ago": "{hours} h {minutes} min fa", "{minutes}m ago": "{minutes} min fa", "{state} · {time} · {lag}": "{state} · {time} · {lag}", @@ -1462,7 +1462,7 @@ "Review scene import": "Rivedi l'importazione della scena", "Nothing is loaded or changed until you apply this file.": "Nulla viene caricato o modificato finché non applichi questo file.", "Ready to import": "Pronto per l'importazione", - "Apply replaces the current project. Export your current project first if you want to keep both.": "Applica sostituisce il progetto attuale. Esporta prima il progetto attuale se vuoi conservarli entrambi.", + "Apply replaces the current project. Export your current project first if you want to keep both.": "L'importazione sostituirà il progetto attuale. Esporta prima il progetto attuale se vuoi conservarli entrambi.", "Apply import": "Applica importazione", "Import was not applied. The current project may have changed.": "L'importazione non è stata applicata. Il progetto attuale potrebbe essere cambiato.", "Select a scene and shot first": "Seleziona prima una scena e uno scatto", @@ -1539,7 +1539,7 @@ "Ironbow": "Ironbow", "unsaved CCTV calibration": "calibrazione CCTV non salvata", "the open cockpit": "il cockpit aperto", - "Switching language reloads the page. This will be lost: {items}. Switch anyway?": "Cambiare lingua ricarica la pagina. Andrà perso: {items}. Cambiare comunque?", + "Switching language reloads the page. This will be lost: {items}. Switch anyway?": "Cambiare lingua ricarica la pagina. Perderai: {items}. Cambiare comunque?", "VISUAL PRESETS": "PRESET VISIVI", "LOCATION": "POSIZIONE", "CONTACTS — nearest planes · vessels · sites": "CONTATTI — aerei · navi · siti più vicini", @@ -1634,7 +1634,7 @@ "PARTLY CLOUDY": "POCO NUVOLOSO", "OVERCAST": "COPERTO", "FOG": "NEBBIA", - "DRIZZLE": "PIOGGERELLA", + "DRIZZLE": "PIOVIGGINE", "RAIN": "PIOGGIA", "RAIN SHOWERS": "ROVESCI DI PIOGGIA", "SNOW SHOWERS": "ROVESCI DI NEVE", @@ -1931,7 +1931,7 @@ "Collapse Radio": "Comprimi Radio", "Expand Radio section": "Espandi la sezione Radio", "Collapse Radio section": "Comprimi la sezione Radio", - "Panel layout updated — positions reset to new defaults": "Layout dei pannelli aggiornato — posizioni ripristinate ai nuovi valori predefiniti", + "Panel layout updated — positions reset to new defaults": "Layout dei pannelli aggiornato: posizioni ripristinate ai nuovi valori predefiniti", "Austin": "Austin", "San Francisco": "San Francisco", "New York": "New York", @@ -1946,7 +1946,7 @@ "Expand Cockpit display options": "Espandi le opzioni display del cockpit", "Collapse Cockpit Radio controls": "Comprimi i controlli Radio del cockpit", "Expand Cockpit Radio controls": "Espandi i controlli Radio del cockpit", - "CH {index} / {total}": "CAN {index} / {total}", + "CH {index} / {total}": "CH {index} / {total}", "NO STATIONS": "NESSUNA STAZIONE", "NO STATION AVAILABLE": "NESSUNA STAZIONE DISPONIBILE", "{name}, station {index} of {total}": "{name}, stazione {index} di {total}", @@ -1991,7 +1991,7 @@ " · degraded directory": " · elenco degradato", " · stale directory": " · elenco obsoleto", " · outside current filter": " · fuori dal filtro attuale", - "Ready — playback starts only from your action": "Pronta — la riproduzione parte solo su tua azione", + "Ready — playback starts only from your action": "Pronta: premi PLAY per avviare la riproduzione", "Radio off": "Radio spenta", "Connecting directly to broadcaster…": "Connessione diretta all'emittente…", "Buffering broadcaster stream…": "Buffering del flusso dell'emittente…", @@ -2002,10 +2002,10 @@ " · restoring volume after voice": " · ripristino del volume dopo la voce", " · static indicates no broadcaster audio": " · il rumore indica assenza di audio dall'emittente", " · tuning static until broadcaster starts": " · rumore di sintonia fino all'avvio dell'emittente", - "Station unavailable after directory refresh — choose another channel": "Stazione non disponibile dopo l'aggiornamento dell'elenco — scegli un altro canale", + "Station unavailable after directory refresh — choose another channel": "Stazione non disponibile dopo l'aggiornamento dell'elenco: scegli un altro canale", "Radio is enabling…": "Attivazione della Radio…", "Radio is disabling…": "Disattivazione della Radio…", - "Radio lifecycle is uncertain — use Enable or Disable to reconcile": "Il ciclo di vita della Radio è incerto — usa Attiva o Disattiva per riconciliare", + "Radio lifecycle is uncertain — use Enable or Disable to reconcile": "Il ciclo di vita della Radio è incerto: usa Attiva o Disattiva per riconciliare", "Clear reading": "Cancella la lettura", "Earlier observation": "Osservazione precedente", "Observed history": "Storico osservato", @@ -2017,7 +2017,7 @@ "Point the camera at the ground to use the view": "Punta la camera verso il suolo per usare la vista", "That point cannot anchor a box": "Quel punto non può ancorare un riquadro", "Imagery stops at ±{limit}° latitude": "Le immagini si fermano a ±{limit}° di latitudine", - "{owner} is using the pointer — close it first": "{owner} sta usando il puntatore: chiudilo prima", + "{owner} is using the pointer — close it first": "Lo strumento {owner} sta usando il puntatore: chiudilo prima", "Box is {size} wide · limit {limit}": "Il riquadro è largo {size} · limite {limit}", "View is {size} wide · limit {limit}": "La vista è larga {size} · limite {limit}", "VS BASEMAP": "VS MAPPA BASE", @@ -2080,10 +2080,10 @@ "start here": "inizia da qui", "No box": "Nessun riquadro", "Searching": "Ricerca", - "Every day is empty here": "Ogni giorno è vuoto qui", + "Every day is empty here": "Qui tutti i giorni sono vuoti", "Sources off": "Fonti disattivate", "VS": "VS", - "Not set": "Non impostato", + "Not set": "Nessuna immagine", "Basemap": "Mappa di base", "Source off": "Fonte disattivata", "Unpin {slot}": "Sblocca {slot}", @@ -2116,8 +2116,8 @@ "Delete scene \"{scene}\" and all shots?": "Eliminare la scena \"{scene}\" e tutti i suoi scatti?", "Delete shot \"{shot}\"?": "Eliminare lo scatto \"{shot}\"?", "Stopped (Esc)": "Fermato (Esc)", - "SPARSE": "RADA", - "BALANCED": "BILANCIATA", + "SPARSE": "RADO", + "BALANCED": "BILANCIATO", "No shots yet. Use CAPTURE SHOT to save current look.": "Ancora nessuno scatto. Usa CATTURA SCATTO per salvare l'aspetto attuale.", "Double-click to rename": "Doppio clic per rinominare", "Shot name": "Nome dello scatto", @@ -2145,7 +2145,7 @@ "Shared satellite is unavailable": "Il satellite condiviso non è disponibile", "entity": "elemento", "Shared {subject} follow expired": "Il tracciamento condiviso di {subject} è scaduto", - "Shared {subject} could not be restored — feed unavailable": "Impossibile ripristinare la condivisione di {subject} — feed non disponibile", + "Shared {subject} could not be restored — feed unavailable": "Impossibile ripristinare la condivisione di {subject}: feed non disponibile", "Shared {subject} is unavailable": "La condivisione di {subject} non è disponibile", "{id} isn't reporting now — showing where it was last seen": "{id} non sta trasmettendo ora: viene mostrata l'ultima posizione nota", "{id} isn't reporting now — showing where it was at {time}": "{id} non sta trasmettendo ora: viene mostrata la posizione alle {time}", @@ -2230,7 +2230,7 @@ "other": "{count} feed live" }, "{feed} {count} ({seconds}s old)": "{feed} {count} ({seconds}s fa)", - "Street Level toggle failed": "Attivazione di Vista stradale non riuscita", + "Street Level toggle failed": "Impossibile attivare o disattivare il livello Vista stradale", "Street Level could not start": "Impossibile avviare Vista stradale", "SHRINK": "RIDUCI", "EXPAND": "ESPANDI", @@ -2377,7 +2377,7 @@ "Requesting microphone": "Richiesta microfono", "Gemini could not submit this input. Start voice again.": "Gemini non ha potuto inviare questo input. Riavvia la voce.", "Connecting to Gemini": "Connessione a Gemini", - "Ask or command": "Chiedi o comanda", + "Ask or command": "Chiedi o dai un comando", "Gemini returned an oversized message": "Gemini ha restituito un messaggio troppo grande", "Gemini Live connection failed. Check network access, then start voice again.": "Connessione a Gemini Live non riuscita. Controlla l'accesso alla rete, poi riavvia la voce.", "Gemini Live connection ended. Start voice again for a new conversation.": "Connessione a Gemini Live terminata. Riavvia la voce per una nuova conversazione.", @@ -2520,10 +2520,10 @@ "{items} {scope}": "{items} {scope}", "last 24 h": "ultime 24 h", "past 30 d and upcoming": "ultimi 30 g e prossimi", - "the flights layer loads by viewport": "il livello voli si carica per vista", + "the flights layer loads by viewport": "il livello voli si carica in base alla vista", "distance is ground distance, not overhead": "la distanza è misurata al suolo fino al punto subsatellitare, non fino al satellite", "the count is a lower bound because at least one layer reached its retained limit.": "il conteggio è un limite inferiore perché almeno un livello ha raggiunto il suo limite di conservazione.", - "{label} off": "{label} disattivato", + "{label} off": "{label}: disattivato", "{label} loading": "{label} in caricamento", "{label} error": "{label} in errore", "counted the first {returned} loaded records": "contati i primi {returned} record caricati", @@ -2564,19 +2564,19 @@ "Could not arrive at the requested place": "Impossibile arrivare al luogo richiesto", "The nearest airborne aircraft could not be selected": "Impossibile selezionare l'aereo in volo più vicino", "No flights within {radius} of the current view": "Nessun volo entro {radius} dalla vista attuale", - "No military within {radius} of the current view": "Nessun mezzo militare entro {radius} dalla vista attuale", + "No military within {radius} of the current view": "Nessun aereo militare entro {radius} dalla vista attuale", "No satellites within {radius} of the current view": "Nessun satellite entro {radius} dalla vista attuale", "No vessels within {radius} of the current view": "Nessuna nave entro {radius} dalla vista attuale", - "{layer} is enabled on the {source} feed, but no airborne aircraft is loaded in the {place} view yet": "{layer} è attivo sul feed {source}, ma nessun aereo in volo è ancora caricato nella vista di {place}", - "{layer} is enabled, but no airborne aircraft is loaded in the {place} view yet": "{layer} è attivo, ma nessun aereo in volo è ancora caricato nella vista di {place}", - "{layer} is enabled, but its aircraft feed is unavailable": "{layer} è attivo, ma il suo feed di aerei non è disponibile", - "{layer} is enabled, but its destination refresh did not complete": "{layer} è attivo, ma l'aggiornamento nel luogo di destinazione non è stato completato", - "{layer} is enabled, but {source} is unavailable": "{layer} è attivo, ma {source} non è disponibile", + "{layer} is enabled on the {source} feed, but no airborne aircraft is loaded in the {place} view yet": "Il livello {layer} è attivo sul feed {source}, ma nessun aereo in volo è ancora caricato nella vista di {place}", + "{layer} is enabled, but no airborne aircraft is loaded in the {place} view yet": "Il livello {layer} è attivo, ma nessun aereo in volo è ancora caricato nella vista di {place}", + "{layer} is enabled, but its aircraft feed is unavailable": "Il livello {layer} è attivo, ma il suo feed di aerei non è disponibile", + "{layer} is enabled, but its destination refresh did not complete": "Il livello {layer} è attivo, ma l'aggiornamento nel luogo di destinazione non è stato completato", + "{layer} is enabled, but {source} is unavailable": "Il livello {layer} è attivo, ma {source} non è disponibile", "Could not arrive at {place}": "Impossibile arrivare a {place}", "{name} is no longer loaded": "{name} non è più caricato", "Unknown target layer: {target}": "Livello obiettivo sconosciuto: {target}", "nominal": "nominale", - "{label} on": "{label} attivato", + "{label} on": "{label}: attivato", "Frame aircraft": "Inquadra gli aerei", "Frame military aircraft": "Inquadra gli aerei militari", "Frame ships": "Inquadra le navi", @@ -2649,7 +2649,7 @@ "Change map stack": "Cambia lo stack mappa", "Adjust post-processing": "Regola la post-elaborazione", "Control scene": "Controlla la scena", - "Control CCTV": "Controlla le CCTV", + "Control CCTV": "Controlla le telecamere CCTV", "Control radio": "Controlla la radio", "Track contact": "Traccia il contatto", "Stop tracking": "Interrompi il tracciamento", @@ -2882,7 +2882,7 @@ "Detection label allocation": "Allocazione delle etichette di rilevamento", "Elastic": "Elastica", "Weighted": "Ponderata", - "Fade": "Dissolv.", + "Fade": "Dissolvenza", "Detection fade distance": "Distanza di dissolvenza del rilevamento", "World-overlay fade distance outside the keyhole as a percentage of its radius": "Distanza di dissolvenza dell'overlay fuori dal foro, come percentuale del suo raggio", "Outside": "Esterno", diff --git a/src/i18n/same-as-english.json b/src/i18n/same-as-english.json index 81a6d1cc2..6b0b9eb4d 100644 --- a/src/i18n/same-as-english.json +++ b/src/i18n/same-as-english.json @@ -152,6 +152,7 @@ "CCTV", "CCTV OFF", "CCTV ON", + "CH {index} / {total}", "COCKPIT", "CRS {value}°", "CRT", diff --git a/src/scenes/recipes.js b/src/scenes/recipes.js index ba3940a57..1a886c541 100644 --- a/src/scenes/recipes.js +++ b/src/scenes/recipes.js @@ -1079,7 +1079,15 @@ export function displayShotTitle(title, shot = undefined, scene = undefined) { /** Whether the built-in recipe behind a scene declares a shot with this title. */ function recipeDeclaresShotTitle(sceneId, title) { const recipe = sceneId ? getSceneRecipeById(sceneId) : null; - return Boolean( - recipe?.cameraPath?.some((keyframe) => keyframe?.title === title), + if (!recipe) return false; + const declares = (path) => + Array.isArray(path) && path.some((keyframe) => keyframe?.title === title); + if (declares(recipe.cameraPath)) return true; + // A bootstrap recipe seeds legacy "Shot N" keyframes; the upgrade replaces + // them with the append recipe's bootstrap shots, which carry no source pack. + return SCENE_APPEND_RECIPES.some( + (append) => + append.legacySceneBootstrap?.targetSceneTitle === recipe.title && + declares(append.legacySceneBootstrap.cameraPath), ); } diff --git a/src/scenes/sceneTitleDisplay.test.mjs b/src/scenes/sceneTitleDisplay.test.mjs index 604e01c49..758800137 100644 --- a/src/scenes/sceneTitleDisplay.test.mjs +++ b/src/scenes/sceneTitleDisplay.test.mjs @@ -4,6 +4,7 @@ import test from 'node:test'; import assert from 'node:assert/strict'; import { + SCENE_APPEND_RECIPES, SCENE_RECIPES, displaySceneTitle, displayShotTitle, @@ -141,3 +142,28 @@ test('the scene context of a shot carries its display title by provenance', asyn title, ); }); + +test('bootstrap shots of a built-in scene localize without a source pack', () => { + setLocale('ru'); + const append = SCENE_APPEND_RECIPES.find( + (recipe) => recipe.legacySceneBootstrap?.cameraPath?.length, + ); + if (!append) return; + const bootstrap = append.legacySceneBootstrap; + const scene = SCENE_RECIPES.find( + (recipe) => recipe.title === bootstrap.targetSceneTitle, + ); + if (!scene) return; + for (const { title } of bootstrap.cameraPath) { + // The upgrade copies these keyframes into the scene without sourcePackId. + assert.equal( + displayShotTitle(title, { id: 'shot-old', title }, { id: scene.id }), + displayShotTitle(title), + ); + // The same title in an operator's own scene stays as typed. + assert.equal( + displayShotTitle(title, { id: 'shot-user', title }, { id: 'scene-user' }), + title, + ); + } +}); From 8ca7f52d19ca4c24aaffbb02ca1156825a1b308f Mon Sep 17 00:00:00 2001 From: German Khokhlov Date: Wed, 28 Oct 2026 16:43:48 +0400 Subject: [PATCH 29/83] i18n(ja): apply review round 1 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Three-model review (astra, sol, Fable), round 1: - Meaning fixes: post-tropical cyclone, partly cloudy, upload-date basis, ground track (対地針路), spec FOV, voice credentials, Activate → 押す, bikeshare counts, NHC/CPHC empty state, absence caveat, regional-news empty state, route steps (件の案内), minimum fuel, microphone access. - Consistent terms: 範囲 for WINDOW, カバー範囲 for coverage, 封じ込め率 for fire containment, サイクロン for storms, 交通流 for TomTom flow, シグナル tab, インポート / エクスポート for projects and presets, 射撃場 for the RANGE class, か所 for sites, full-width colons. - Short forms where the re-shoot showed a wrap: エクスポート (Scenes), 提供元で操作 (embeds), 該当施設 (Contacts). - cjk.css: the Recent Imagery slot line wraps at its separators in Japanese, never inside プレビュー. - Glossary in docs/translations/ja.md updated to match. Co-Authored-By: Claude Opus 5.5 --- docs/translations/ja.md | 13 ++- src/i18n/locales/ja.json | 192 +++++++++++++++++++-------------------- src/ui/styles/cjk.css | 7 ++ 3 files changed, 114 insertions(+), 98 deletions(-) diff --git a/docs/translations/ja.md b/docs/translations/ja.md index 11ff3b541..0f94a6b08 100644 --- a/docs/translations/ja.md +++ b/docs/translations/ja.md @@ -50,7 +50,7 @@ Translation source: abiyeenzo (#913). | installation, site | 施設 | | camera / CCTV camera | カメラ / CCTVカメラ | | earthquake / active fire / fire perimeter | 地震 / 火災検知 / 延焼範囲 | -| contained (fire) | 鎮圧 | +| contained / containment (fire) | 封じ込め / 封じ込め率 | | scene / shot | シーン / ショット | | briefing / panel / dock | ブリーフィング / パネル / ドック | | preset / visual preset | プリセット / ビジュアルプリセット | @@ -59,6 +59,7 @@ Translation source: abiyeenzo (#913). | Clean UI | クリーンUI | | cockpit | コックピット | | heading / altitude / ground speed | 機首方位 / 高度 / 対地速度 | +| track (TRK, direction over the ground) | 対地針路 | | HDG / BRG / CRS / FOV | そのまま(HUDコード) | | squawk | スコーク | | map heading / North up | 方位 / 北を上に | @@ -67,20 +68,28 @@ Translation source: abiyeenzo (#913). | Global Context / Context (panel) | グローバルコンテキスト / コンテキスト | | radio (station) / tune / seek | ラジオ(局)/ 選局・同調 / シーク | | transit / bikeshare | 公共交通 / シェアサイクル | +| traffic flow (TomTom) | 交通流 | | Previous / Next | 前へ / 次へ | +| SIG / NEWS / LOCAL (briefing tabs) | シグナル / ニュース / ローカル | | compass points (N, NNE, NE, ENE, …) | 北, 北北東, 北東, 東北東, … | | weather field / FIELD (selector) | 要素 | | weather model / forecast lead hours | モデル / 予報時間 | | valid (forecast time) / issued | 対象時刻 / 発表 | | radar reflectivity / lightning density | レーダー反射強度 / 雷密度 | -| cyclone / advisory (NHC/CPHC) | サイクロン / 情報(第N報) | +| cyclone, storm (NHC/CPHC) / advisory | サイクロン / 情報(第N報) | | forecast uncertainty cone | 予報円 | | tropical storm / tropical depression | 熱帯暴風雨 / 熱帯低気圧 | | scene cloud / mosaic / daily overview | シーン雲量 / モザイク / 日次概観 | | box (Recent Imagery area) | 範囲 | +| WINDOW (search radius around a subject) | 範囲 | +| coverage / coverage % / full, partial | カバー範囲 / カバー率(%のみ)/ 全体, 一部 | | pin (Recent Imagery) | 固定 | | outline / mark (map annotation) | 輪郭 / マーク | | share (a view or link) | 共有 | +| import / export (project, presets) | インポート / エクスポート | +| EXPORT (image, PNG) | 書き出し | +| voice (the voice assistant) | 音声アシスタント / 音声機能 | +| activate (a control, screen-reader text) | 押す(「押すと…」) | | AI agent | AIエージェント | | frame (bring into view) | 視野に収める | | story beat / evidence beat | ストーリー区切り / 証拠の区切り | diff --git a/src/i18n/locales/ja.json b/src/i18n/locales/ja.json index 19069f601..b2f22124b 100644 --- a/src/i18n/locales/ja.json +++ b/src/i18n/locales/ja.json @@ -42,7 +42,7 @@ "Unlawful interference": "不法妨害", "Radio failure": "無線故障", "Downed aircraft": "墜落機", - "Minimum fuel": "最低燃料", + "Minimum fuel": "ミニマムフューエル", "Lifeguard (medical priority)": "救急飛行(医療優先)", "Rasuwagadhi witness video": "Rasuwagadhiの目撃映像", "Bhote Koshi valley footage": "Bhote Koshi渓谷の映像", @@ -82,19 +82,19 @@ "Preloading {provider} media": "{provider}のメディアを事前読み込み中", "LOADING X POST…": "Xの投稿を読み込み中…", "The X post is unavailable or cannot be embedded.": "このXの投稿は利用できないか、埋め込みできません。", - "X POST · PROVIDER CONTROLS": "Xの投稿 · 提供元の操作", + "X POST · PROVIDER CONTROLS": "Xの投稿 · 提供元で操作", "{reason} OPEN ORIGINAL.": "{reason}元の投稿を開いてください。", - "X embed unavailable": "X埋め込みを利用できません。", - "FACEBOOK · PROVIDER CONTROLS": "FACEBOOK · 提供元の操作", + "X embed unavailable": "Xの埋め込みを利用できません。", + "FACEBOOK · PROVIDER CONTROLS": "FACEBOOK · 提供元で操作", "Facebook embed unavailable": "Facebookの埋め込みを利用できません。", - "AUTOPLAY BLOCKED · USE PROVIDER CONTROLS": "自動再生ブロック · 提供元の操作を使用", + "AUTOPLAY BLOCKED · USE PROVIDER CONTROLS": "自動再生ブロック · 提供元で操作", "Embedded {provider} media for {source}": "{source}の埋め込み{provider}メディア", "witness source": "目撃ソース", "Witness source": "目撃ソース", "{provider} · EMBEDDED SOURCE": "{provider} · 埋め込みソース", "OPEN ORIGINAL ↗": "元の投稿を開く ↗", "{provider} media: {source}": "{provider}メディア:{source}", - "{provider} · PROVIDER CONTROLS": "{provider} · 提供元の操作", + "{provider} · PROVIDER CONTROLS": "{provider} · 提供元で操作", "YOUTUBE {state} · OPEN ORIGINAL": "YOUTUBE {state} · 元の投稿を開く", "INITIATION": "発生", "DAMMING": "せき止め", @@ -261,7 +261,7 @@ "Directions": "ルート案内", "Recent imagery": "最近の衛星画像", "STATION": "宇宙ステーション", - "Crewed stations and their visiting vehicles": "有人宇宙ステーションと来訪機", + "Crewed stations and their visiting vehicles": "有人宇宙ステーションと結合中の宇宙機", "NAV": "測位", "GNSS navigation — GPS, GLONASS, Galileo": "GNSS測位(GPS、GLONASS、Galileo)", "GEO": "GEO", @@ -294,7 +294,7 @@ "Source configured; file checked when loaded": "ソース設定済み。ファイルは読み込み時に確認します", "Source unavailable": "ソースを利用できません", "ENVIRONMENTAL": "環境", - "EARTH WATCH": "地球ウォッチ", + "EARTH WATCH": "地球監視", "ACTIVE EVENTS": "発生中のイベント", "Starting live contacts…": "ライブコンタクトを開始中…", "Opening space missions…": "宇宙ミッションを開いています…", @@ -375,8 +375,8 @@ "Save failed ({status}).": "保存に失敗しました({status})。", "OAuth check failed: {detail}": "OAuthの確認に失敗しました:{detail}", "Could not check ChatGPT sign-in. Try again.": "ChatGPTのサインイン状態を確認できませんでした。もう一度お試しください。", - "VOICE AUTH · CHATGPT OAUTH": "音声認証 · CHATGPT OAUTH", - "VOICE AUTH · API KEY": "音声認証 · APIキー", + "VOICE AUTH · CHATGPT OAUTH": "音声機能の認証 · CHATGPT OAUTH", + "VOICE AUTH · API KEY": "音声機能の認証 · APIキー", "USE API KEY": "APIキーを使用", "USE CHATGPT OAUTH": "CHATGPT OAUTHを使用", "Use OPENAI_API_KEY for the next cloud voice session": "次回のクラウド音声セッションでOPENAI_API_KEYを使用", @@ -410,7 +410,7 @@ "Opening ChatGPT sign-in in your browser…": "ブラウザーでChatGPTのサインインを開いています…", "Could not start ChatGPT sign-in on this machine.": "このマシンでChatGPTのサインインを開始できませんでした。", "Finish ChatGPT sign-in in the browser. Waiting for it to complete…": "ブラウザーでChatGPTのサインインを完了してください。完了を待っています…", - "ChatGPT sign-in timed out. Click {button} to try again.": "ChatGPTのサインインがタイムアウトしました。「{button}」をクリックしてもう一度お試しください。", + "ChatGPT sign-in timed out. Click {button} to try again.": "ChatGPTのサインインがタイムアウトしました。[{button}]をクリックしてもう一度お試しください。", "ChatGPT sign-in complete. OAuth will be used for the next cloud voice session.": "ChatGPTのサインインが完了しました。次回のクラウド音声セッションではOAuthを使用します。", "Remove this key from your saved configuration?": "このキーを保存済みの設定から削除しますか?", "Removed from {store}. Restarting — this page reloads itself.": "{store}から削除しました。再起動中です。このページは自動で再読み込みされます。", @@ -422,8 +422,8 @@ "Live active-fire detections": "火災のライブ検知", "Real live traffic (keyless runs a simulation)": "実際のライブ交通情報(キーなしはシミュレーション)", "Bing imagery map stacks + world terrain": "Bing画像のマップスタック + 全球地形", - "More flight-polling credits (anonymous works without)": "航空機ポーリングのクレジット増加(匿名でも利用可)", - "Street-level imagery and coverage in the Street Level layer. Free: register an app in the Mapillary developer dashboard and paste its Client Token": "ストリートレベルレイヤーのストリートレベル画像とカバレッジ。無料:Mapillary開発者ダッシュボードでアプリを登録し、そのClient Tokenを貼り付けてください", + "More flight-polling credits (anonymous works without)": "航空機データの取得枠を拡大(認証なしでも利用可)", + "Street-level imagery and coverage in the Street Level layer. Free: register an app in the Mapillary developer dashboard and paste its Client Token": "ストリートレベルレイヤーのストリートレベル画像とカバー範囲。無料:Mapillary開発者ダッシュボードでアプリを登録し、そのClient Tokenを貼り付けてください", "Public space-missions access needs no key. Leave blank for standard use; paid tokens only raise request limits.": "公開の宇宙ミッションデータにキーは不要です。通常の利用では空欄のままにしてください。有料トークンはリクエスト上限を引き上げるだけです。", "Air quality request failed": "大気質のリクエストに失敗しました", "No readings available": "測定値がありません", @@ -433,13 +433,13 @@ }, "Highest air-quality readings in view": "表示範囲内で大気質の値が最も高い局", "Low": "低", - "Low health risk": "健康リスク低", + "Low health risk": "健康リスク:低", "Moderate": "中", - "Moderate health risk": "健康リスク中", + "Moderate health risk": "健康リスク:中", "High": "高", - "High health risk": "健康リスク高", + "High health risk": "健康リスク:高", "Very High": "非常に高い", - "Very High health risk": "健康リスク非常に高い", + "Very High health risk": "健康リスク:非常に高い", "Air quality": "大気質", "Canada only · ECCC AQHI network": "カナダのみ · ECCC AQHI観測網", "ECCC request timed out": "ECCCのリクエストがタイムアウトしました", @@ -485,18 +485,18 @@ "Next — nearest unvisited contact in the 250 km window": "次へ:250 km圏内で最も近い未訪問のコンタクト", "NEXT": "次へ", "Named areas ({n})": "名前付きエリア({n})", - "{distance} FLIGHT / VESSEL WINDOW": "フライト / 船舶ウィンドウ {distance}", - "Open-source mapped/observed context. Missing broadcasts, unloaded map areas, or unmapped sites are not evidence of absence.": "オープンソースのマップ済み/観測済みコンテキストです。放送の欠落、未読込のマップ領域、未マップの施設は、不在の証拠ではありません。", - "mapped matches within {km} km of the subject": "対象から{km} km以内のマップ済み一致", - "none mapped within {km} km; not a complete 250 km survey": "{km} km以内にマップ済みのものなし(250 kmの完全な調査ではありません)", - "mapped matches from the loaded viewport": "読み込み済みの表示範囲からのマップ済み一致", + "{distance} FLIGHT / VESSEL WINDOW": "フライト / 船舶の範囲 {distance}", + "Open-source mapped/observed context. Missing broadcasts, unloaded map areas, or unmapped sites are not evidence of absence.": "公開情報に基づくマップ済み/観測済みのコンテキストです。位置送信の欠落、未読込の地図範囲、地図に未登録の施設は、対象が存在しない証拠にはなりません。", + "mapped matches within {km} km of the subject": "対象の{km} km圏内の該当施設", + "none mapped within {km} km; not a complete 250 km survey": "{km} km以内にマップ済み施設なし(250 kmの完全な調査ではありません)", + "mapped matches from the loaded viewport": "読み込み済みの表示範囲内の該当施設", "viewport feed is not a complete 250 km survey": "表示範囲のフィードは250 kmの完全な調査ではありません", "HDG {value}°": "HDG {value}°", "BRG {value}°": "BRG {value}°", "BRG —": "BRG —", "CRS {value}°": "CRS {value}°", "CURRENT VIEWPORT ONLY": "現在の表示範囲のみ", - "WITHIN {km} KM": "{km} KM以内", + "WITHIN {km} KM": "{km} km以内", "Flights": "フライト", "Military flights": "軍用機", "AIS vessels": "AIS船舶", @@ -506,7 +506,7 @@ "GBFS fetch error": "GBFS取得エラー", "Station {id}": "ステーション {id}", "Station": "ステーション", - "🚲 {bikes} avail · {docks} docks · {capacity} cap": "🚲 空き {bikes} · ドック {docks} · 容量 {capacity}", + "🚲 {bikes} avail · {docks} docks · {capacity} cap": "🚲 貸出可 {bikes}台 · 返却可 {docks}台 · 収容 {capacity}台", "⚠️ Not installed": "⚠️ 未設置", "⚠️ Not renting": "⚠️ 貸出停止中", "⚠️ Not returning": "⚠️ 返却不可", @@ -516,8 +516,8 @@ "{city} CCTV": "{city} CCTV", "FOV {value}° (DATASHEET)": "FOV {value}°(データシート)", "FOV {value}°": "FOV {value}°", - "SPEC FOV {span}° (CAPABILITY)": "仕様FOV {span}°(可動範囲)", - "COVERAGE {value}km²": "カバレッジ {value}km²", + "SPEC FOV {span}° (CAPABILITY)": "仕様FOV {span}°(対応画角)", + "COVERAGE {value}km²": "カバー範囲 {value}km²", "OVERLAP {count} cams": "重複 {count}台", "ISOLATED VIEW": "単独ビュー", "PROJ MONITOR": "投影 モニター", @@ -531,7 +531,7 @@ "Cyclone advisories unavailable": "サイクロン情報を取得できません", "Cyclone data unavailable": "サイクロンデータを取得できません", "Potential tropical cyclone": "潜在的熱帯サイクロン", - "Post-tropical cyclone": "温帯低気圧化したサイクロン", + "Post-tropical cyclone": "熱帯性を失ったサイクロン", "Hurricane": "ハリケーン", "Tropical storm": "熱帯暴風雨", "Tropical depression": "熱帯低気圧", @@ -543,12 +543,12 @@ "Cached advisory · stale source": "キャッシュの情報 · ソース更新遅延", "Loading advisories…": "情報を読み込み中…", "{count} active storms": { - "other": "発生中の嵐 {count}個" + "other": "発生中のサイクロン {count}個" }, "Position as of {time}": "{time}時点の位置", "Maximum sustained wind: {wind} · Pressure: {pressure}": "最大持続風速:{wind} · 気圧:{pressure}", "{name} · {classification} · Advisory {number} · issued {time}": "{name} · {classification} · 第{number}報 · {time}発表", - "No active NHC/CPHC systems": "発生中のNHC/CPHCシステムはありません", + "No active NHC/CPHC systems": "NHC/CPHCが監視中のサイクロンはありません", "Advisories unavailable": "情報を取得できません", "Cyclones · NHC / CPHC": "サイクロン · NHC / CPHC", "Atlantic · E/C Pacific": "大西洋 · 東部/中部太平洋", @@ -558,7 +558,7 @@ "Wind unavailable": "風のデータを取得できません", "Advisory center / forecast track": "発表時の中心 / 予報進路", "Center-track uncertainty cone": "中心進路の予報円", - "Select a storm on the map, or choose a storm in the list to select it and move the camera. Click empty map space to clear the selection. NOAA NHC/CPHC advisory context. The cone describes forecast center-track uncertainty, not storm size or the full hazard area. Forecast point labels are source lead hours, not times computed from advisory issuance. Geometry follows the surface; height is not weather altitude. Consult the official advisory.": "地図上で嵐を選択するか、リストから嵐を選ぶと選択してカメラが移動します。地図の何もない場所をクリックすると選択を解除します。NOAA NHC/CPHCの情報に基づく表示です。予報円は予報される中心進路の不確かさを示すもので、嵐の大きさや危険範囲全体ではありません。予報点のラベルはソースの予報時間で、発表時刻から計算した時刻ではありません。図形は地表に沿って表示され、高さは気象上の高度ではありません。公式情報を確認してください。", + "Select a storm on the map, or choose a storm in the list to select it and move the camera. Click empty map space to clear the selection. NOAA NHC/CPHC advisory context. The cone describes forecast center-track uncertainty, not storm size or the full hazard area. Forecast point labels are source lead hours, not times computed from advisory issuance. Geometry follows the surface; height is not weather altitude. Consult the official advisory.": "地図上でサイクロンを選択するか、リストから選ぶと、そのサイクロンが選択されてカメラが移動します。地図の何もない場所をクリックすると選択を解除します。NOAA NHC/CPHCの情報に基づく表示です。予報円は予報される中心進路の不確かさを示すもので、サイクロンの大きさや危険範囲全体ではありません。予報点のラベルはソースの予報時間で、発表時刻から計算した時刻ではありません。図形は地表に沿って表示され、高さは気象上の高度ではありません。公式情報を確認してください。", "DRIVE": "車", "Drive": "車", "WALK": "徒歩", @@ -668,15 +668,15 @@ "Place A and B first": "先にAとBを配置してください", "action|CLEAR": "消去", "Remove the route and both markers": "ルートと両方のマーカーを削除", - "press Escape twice to leave Draw": "Escapeを2回押して描画を終了してください", + "press Escape twice to leave Draw": "Escを2回押して描画を終了してください", "{name} is active — turn {name} off, then set {endpoint}": "{name}を使用中です。{name}をオフにしてから{endpoint}を設定してください", "{name} is active — {leave}, then set {endpoint}": "{name}を使用中です。先に{leave}。その後、{endpoint}を設定してください", - "Only the first {count} turns of this route are shown": "このルートは最初の{count}回の曲がり角のみ表示しています", + "Only the first {count} turns of this route are shown": "このルートは最初の{count}件の案内のみ表示しています", "Turn-by-turn directions": "ターンバイターンのルート案内", "Another map tool is using clicks — close it, then SET A again": "別の地図ツールがクリックを使用中です。そのツールを閉じてから、もう一度Aを設定してください", "Routing…": "ルート検索中…", "No route found": "ルートが見つかりません", - "{distance} · {duration} · {mode} · first {count} turns": "{distance} · {duration} · {mode} · 最初の{count}回の曲がり角", + "{distance} · {duration} · {mode} · first {count} turns": "{distance} · {duration} · {mode} · 最初の{count}件の案内", "{distance} · {duration} · {mode}": "{distance} · {duration} · {mode}", "Click the globe to place {endpoint}": "地球をクリックして{endpoint}を配置", "SET B, then click the globe": "Bを設定してから地球をクリック", @@ -749,7 +749,7 @@ "Low-accuracy score 2–10%": "低精度スコア 2–10%", "Low-accuracy score > 10%": "低精度スコア > 10%", "GNSS integrity source unavailable": "GNSSインテグリティのソースを利用できません", - "Regional sample · 250 nm radius · cells from visited views over 30 min": "地域サンプル · 半径250 nm · 30分以内に表示したビューのセル", + "Regional sample · 250 nm radius · cells from visited views over 30 min": "地域サンプル · 半径250海里 · 30分以内に表示したビューのセル", "Retrying automatically at {time} UTC": "{time} UTCに自動で再試行します", "Retrying automatically after provider cooldown": "プロバイダーのクールダウン後に自動で再試行します", "Updates automatically after pan or zoom and once a minute. The public feed covers a 250-nautical-mile circle around the view centre; zooming out does not make it a worldwide snapshot. Blank cells are outside sampled coverage or have insufficient observations.": "パンやズームの後、および1分ごとに自動で更新されます。公開フィードは表示中心から半径250海里の円をカバーします。ズームアウトしても全世界のスナップショットにはなりません。空白のセルは、サンプリング範囲外か観測が不十分です。", @@ -760,7 +760,7 @@ "GNSS integrity snapshot has no observation time": "GNSSインテグリティのスナップショットに観測時刻がありません", "installation class|AIRFIELD": "飛行場", "installation class|NAVAL BASE": "海軍基地", - "installation class|RANGE": "演習場", + "installation class|RANGE": "射撃場", "installation class|MILITARY LAND": "軍用地", "installation class|BASE": "基地", "installation class|BARRACKS": "兵舎", @@ -769,11 +769,11 @@ "installation class|INSTALLATION": "施設", "No mapped sites within {km} km of the contact": "コンタクトから{km} km以内にマップ済み施設はありません", "{count} mapped sites within {km} km of the contact": { - "other": "コンタクトから{km} km以内のマップ済み施設 {count}件" + "other": "コンタクトから{km} km以内のマップ済み施設 {count}か所" }, "No mapped sites in view": "表示範囲内にマップ済み施設はありません", "{count} mapped sites in view": { - "other": "表示範囲内のマップ済み施設 {count}件" + "other": "表示範囲内のマップ済み施設 {count}か所" }, "loading mapped installation context": "マップ済み施設のコンテキストを読み込み中", "Too many mapped sites in view to list them all": "表示範囲内のマップ済み施設が多すぎて、すべてを一覧表示できません", @@ -856,7 +856,7 @@ "Your decoder feed": "お使いのデコーダーフィード", "Your RTL-SDR receiver": "お使いのRTL-SDR受信機", "NO CALLSIGN": "コールサインなし", - "ALT {altitude} FT · GS {speed} KT · TRK {track}": "高度 {altitude} ft · 対地速度 {speed} kt · 航跡 {track}", + "ALT {altitude} FT · GS {speed} KT · TRK {track}": "高度 {altitude} ft · 対地速度 {speed} kt · 対地針路 {track}", "V/S {rate}": "昇降率 {rate}", "V/S {rate} FPM": "昇降率 {rate} ft/min", "POSITION {age}": "位置 {age}", @@ -887,14 +887,14 @@ "fire behavior|Minimal": "微弱", "fire behavior|Moderate": "中程度", "fire behavior|Active": "活発", - "fire behavior|Extreme": "極端", + "fire behavior|Extreme": "極めて活発", "Type {level} Incident": "タイプ{level}インシデント", "age|{count}m": "{count}分", "{acres} ac": { "other": "{acres}エーカー" }, - "{percent}% contained": "{percent}%鎮圧", - "containment unknown": "鎮圧率不明", + "{percent}% contained": "封じ込め率 {percent}%", + "containment unknown": "封じ込め率不明", "{cause} cause": "原因:{cause}", "{personnel} personnel": { "other": "人員{personnel}人" @@ -909,11 +909,11 @@ "Unnamed incident": "名称未設定の火災", "Open {title} on InciWeb": "InciWebで{title}を開く", "Perimeter source unavailable": "延焼範囲のソースを利用できません", - "Not contained or unknown": "未鎮圧または不明", - "Under 50% contained": "鎮圧50%未満", - "50–99% contained": "鎮圧50–99%", - "Fully contained": "完全鎮圧", - "Colour shows reported containment. Perimeters are simplified to about 100 m.": "色は報告された鎮圧率を示します。延焼範囲は約100 mに簡略化されています。", + "Not contained or unknown": "封じ込め率0%または不明", + "Under 50% contained": "封じ込め率50%未満", + "50–99% contained": "封じ込め率50–99%", + "Fully contained": "封じ込め率100%", + "Colour shows reported containment. Perimeters are simplified to about 100 m.": "色は報告された封じ込め率を示します。延焼範囲は約100 mに簡略化されています。", "Malformed perimeter snapshot": "延焼範囲スナップショットの形式が不正です", "radio tag|All": "すべて", "News": "ニュース", @@ -977,7 +977,7 @@ "{label} catalog unavailable · {detail}": "{label}のカタログを利用できません · {detail}", "Daily overview for today may still be empty until the pass": "今日の日次概観は、衛星の通過まで空の場合があります", "Box and images cleared": "範囲と画像を消去しました", - "MORE DETAIL · 30 m": "高詳細 · 30 m", + "MORE DETAIL · 30 m": "高精細 · 30 m", "Sentinel-2 and Landsat via HLS, 30 m, every 2–6 days": "HLS経由のSentinel-2とLandsat、30 m、2~6日ごと", "DAILY OVERVIEW · 250 m": "日次概観 · 250 m", "VIIRS daily mosaic, 250 m, follows broad changes; little detail under 25 km": "VIIRSの日次モザイク、250 m。広域の変化を追跡。25 km未満の詳細はほぼなし", @@ -992,7 +992,7 @@ "Box must enclose an area": "範囲は面積を囲む必要があります", "Add the full Starlink broadband shell (thousands of extra points)": "Starlinkブロードバンドシェル全体を追加(数千の追加ポイント)", "Loading the Starlink shell…": "Starlinkシェルを読み込み中…", - "Starlink {detail} — click to retry": "Starlink {detail}: クリックで再試行", + "Starlink {detail} — click to retry": "Starlink {detail}:クリックで再試行", "load failed": "読込失敗", "Showing the full Starlink shell — click for the core catalog only": "Starlinkシェル全体を表示中:クリックでコアカタログのみに戻す", "DENSE ···": "高密度 ···", @@ -1055,7 +1055,7 @@ "Panoramax sent an unreadable answer": "Panoramaxから読み取れない応答が返されました", "Sequence images unavailable": "シーケンス画像を利用できません", "No street-level imagery providers configured": "ストリートレベル画像のプロバイダーが設定されていません", - "(by upload date)": "(アップロード日順)", + "(by upload date)": "(アップロード日基準)", "Open the Street Level panel to view imagery": "画像を表示するには、ストリートレベルパネルを開いてください", "Image could not be opened": "画像を開けませんでした", "TeleGeography load failed": "TeleGeographyの読み込みに失敗しました", @@ -1080,15 +1080,15 @@ "TomTom upstream unreachable": "TomTomの上流サービスに接続できません", "TomTom flow unavailable": "TomTomの交通流を利用できません", "SIMULATED — {reason}": "シミュレーション:{reason}", - "Syncing flow · Roads: {source}": "フロー同期中 · 道路:{source}", - "LIVE · Roads: {source} · Roads without flow hidden": "ライブ · 道路:{source} · フローのない道路は非表示", - "LIVE · Roads: {source} · No flow roads in view": "ライブ · 道路:{source} · 表示範囲にフローのある道路なし", - "LIVE · Roads: {source} · Flow {percent}%": "ライブ · 道路:{source} · フロー {percent}%", - "SIMULATED · Roads: {source} · Flow {percent}%": "シミュレーション · 道路:{source} · フロー {percent}%", - "Syncing flow · Roads: OpenStreetMap · Flow: TomTom · Unmatched: simulated": "フロー同期中 · 道路:OpenStreetMap · フロー:TomTom · 未一致:シミュレーション", - "LIVE · Roads: OpenStreetMap · Flow: TomTom · {percent}% cov · Unmatched: simulated": "ライブ · 道路:OpenStreetMap · フロー:TomTom · カバー率 {percent}% · 未一致:シミュレーション", - "LIVE · Roads: OpenStreetMap · Flow: TomTom · {percent}% cov": "ライブ · 道路:OpenStreetMap · フロー:TomTom · カバー率 {percent}%", - "SIMULATED · Roads: OpenStreetMap · Flow: TomTom (no matches)": "シミュレーション · 道路:OpenStreetMap · フロー:TomTom(一致なし)", + "Syncing flow · Roads: {source}": "交通流を同期中 · 道路:{source}", + "LIVE · Roads: {source} · Roads without flow hidden": "ライブ · 道路:{source} · 交通流のない道路は非表示", + "LIVE · Roads: {source} · No flow roads in view": "ライブ · 道路:{source} · 表示範囲に交通流のある道路なし", + "LIVE · Roads: {source} · Flow {percent}%": "ライブ · 道路:{source} · 交通流 {percent}%", + "SIMULATED · Roads: {source} · Flow {percent}%": "シミュレーション · 道路:{source} · 交通流 {percent}%", + "Syncing flow · Roads: OpenStreetMap · Flow: TomTom · Unmatched: simulated": "交通流を同期中 · 道路:OpenStreetMap · 交通流:TomTom · 未一致:シミュレーション", + "LIVE · Roads: OpenStreetMap · Flow: TomTom · {percent}% cov · Unmatched: simulated": "ライブ · 道路:OpenStreetMap · 交通流:TomTom · カバー率 {percent}% · 未一致:シミュレーション", + "LIVE · Roads: OpenStreetMap · Flow: TomTom · {percent}% cov": "ライブ · 道路:OpenStreetMap · 交通流:TomTom · カバー率 {percent}%", + "SIMULATED · Roads: OpenStreetMap · Flow: TomTom (no matches)": "シミュレーション · 道路:OpenStreetMap · 交通流:TomTom(一致なし)", "SIMULATED — traffic service unreachable": "シミュレーション:交通サービスに接続できません", "SIMULATED — add TomTom key for live": "シミュレーション:ライブ表示にはTomTomキーを追加", "OpenFreeMap tiles rate-limited": "OpenFreeMapタイルがレート制限中", @@ -1183,8 +1183,8 @@ "Color: strikes/km²/min ×10³": "色:落雷数/km²/分 ×10³", "60°S–60°N · typically 2–3 h delayed": "60°S–60°N · 通常2~3時間遅れ", "North America · infrared imagery": "北米 · 赤外画像", - "Reduced motion · history playback unavailable": "動きを減らす · 履歴再生は利用不可", - "Reduced motion · manual history available": "動きを減らす · 手動で履歴を表示可能", + "Reduced motion · history playback unavailable": "動きを減らす設定 · 履歴再生は利用不可", + "Reduced motion · manual history available": "動きを減らす設定 · 履歴は手動で表示可能", "Rain radar · US": "降水レーダー · 米国", "Lightning density · 15 min": "雷密度 · 15分", "Satellite clouds": "衛星雲画像", @@ -1360,7 +1360,7 @@ "No shots to run": "実行するショットがありません", "Scene transition limit reached — load a shot to reset": "シーン切り替えの上限に達しました。リセットするにはショットを読み込んでください", "Export failed: {error}": "エクスポートに失敗しました:{error}", - "Project exported": "プロジェクトを書き出しました", + "Project exported": "プロジェクトをエクスポートしました", "Importing project": "プロジェクトをインポート中", "Imported {file}": "{file}をインポートしました", "Import failed: {error}": "インポートに失敗しました:{error}", @@ -1561,8 +1561,8 @@ "CCTV ON": "CCTV オン", "CCTV OFF": "CCTV オフ", "VIEWSHED ON": "可視域 オン", - "COVERAGE ON": "カバレッジ オン", - "COVERAGE OFF": "カバレッジ オフ", + "COVERAGE ON": "カバー範囲 オン", + "COVERAGE OFF": "カバー範囲 オフ", "AUTO HOP ON": "自動切替 オン", "AUTO HOP OFF": "自動切替 オフ", "PROJECTION ON": "投影 オン", @@ -1578,7 +1578,7 @@ "{count} cameras loaded · enable CCTV to activate": { "other": "カメラ {count}台を読込済み · CCTVを有効にして使用" }, - "Enable CCTV to load camera intersections": "CCTVを有効にすると、カメラの交差点を読み込みます", + "Enable CCTV to load camera intersections": "CCTVを有効にすると、カメラのある交差点を読み込みます", "Enable CCTV to start camera-linked intelligence summaries.": "CCTVを有効にすると、カメラ連動のインテリジェンス概要を開始します。", "No summary available.": "利用できる概要はありません。", "loading frames": "フレーム読込中", @@ -1587,7 +1587,7 @@ "Clear selected data layers": "選択中のデータレイヤーを解除", "CONDITIONS UNKNOWN": "気象状況不明", "CLEAR": "快晴", - "PARTLY CLOUDY": "晴れ時々曇り", + "PARTLY CLOUDY": "一部曇り", "OVERCAST": "曇天", "FOG": "霧", "DRIZZLE": "霧雨", @@ -1595,23 +1595,23 @@ "RAIN SHOWERS": "にわか雨", "SNOW SHOWERS": "にわか雪", "THUNDERSTORM": "雷雨", - "MIXED CONDITIONS": "混在した状況", + "MIXED CONDITIONS": "その他の気象状況", "CYCLE ON": "自動切替 オン", "CYCLE OFF": "自動切替 オフ", - "Stop automatic page cycling. Previous, Next, and the SIG/NEWS/LOCAL tabs stay available.": "ページの自動切り替えを停止します。前へ、次へ、SIG/NEWS/LOCALタブは引き続き使えます。", + "Stop automatic page cycling. Previous, Next, and the SIG/NEWS/LOCAL tabs stay available.": "ページの自動切り替えを停止します。[前へ]、[次へ]と[シグナル]/[ニュース]/[ローカル]タブは引き続き使えます。", "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.": "9秒ごとにブリーフィングページを自動で切り替えます(シグナル → ニュース → ローカル)。パネルにカーソルを合わせるかフォーカスしている間は一時停止します。ライブシグナルのデータは、どちらの場合も継続的に更新されます。", "ACQUIRING REGIONAL NEWS": "地域ニュースを取得中", "REGIONAL NEWS UNAVAILABLE": "地域ニュースを取得できません", "RESOLVING REGION": "地域を特定中", "REGION UNAVAILABLE": "地域を取得できません", - "NO RECENT LOCATION MATCHES": "最近の位置一致なし", + "NO RECENT LOCATION MATCHES": "この地域の最近のニュースなし", "{domain} · {age}": "{domain} · {age}", "{value} KM/H": "{value} KM/H", "CLOUD {pct}%": "雲量 {pct}%", "CLOUD UNKNOWN": "雲量不明", "{source} · LOCATION QUERY": "{source} · 位置クエリ", "REGIONAL NEWS": "地域ニュース", - "{label} · {radius} AIR/SEA WINDOW": "{label} · 空/海ウィンドウ {radius}", + "{label} · {radius} AIR/SEA WINDOW": "{label} · 航空機/船舶の範囲 {radius}", "{scope} · INSTALLATIONS {coverage}": "{scope} · 施設 {coverage}", "CONTEXT STANDBY": "コンテキスト待機", "ENABLE GLOBAL CONTEXT FOR PROXIMITY PINGS": "グローバルコンテキストを有効にすると近接ピングを表示", @@ -1652,7 +1652,7 @@ "Anime": "アニメ", "Noir": "ノワール", "Snow": "雪", - "Current cockpit vision style: {style}. Activate for next style.": "現在のコックピットビジョンスタイル:{style}。有効にすると次のスタイルへ。", + "Current cockpit vision style: {style}. Activate for next style.": "現在のコックピットビジョンスタイル:{style}。押すと次のスタイルに切り替わります。", "Current style: {style} — click for next": "現在のスタイル:{style} — クリックで次へ", "Collapse Contact panel": "コンタクトパネルを折りたたむ", "Expand Contact panel": "コンタクトパネルを展開", @@ -1799,7 +1799,7 @@ "UNCERTAIN": "不明確", "status chip|UNAVAILABLE": "利用不可", "Data source unavailable": "データソースを利用できません", - "{name}: {state}": "{name}: {state}", + "{name}: {state}": "{name}:{state}", "{count}s ago": "{count}秒前", "Local FM stopped: internet radio started": "ローカルFMを停止しました:インターネットラジオを開始しました", "IDLE": "待機", @@ -1937,7 +1937,7 @@ " · muted during voice interaction": " · 音声操作中はミュート", " · restoring volume after voice": " · 音声操作後に音量を復元中", " · static indicates no broadcaster audio": " · ノイズは放送局の音声がないことを示します", - " · tuning static until broadcaster starts": " · 放送局の開始までノイズで選局中", + " · tuning static until broadcaster starts": " · 放送が始まるまで選局ノイズを再生", "Station unavailable after directory refresh — choose another channel": "ディレクトリ更新後に局を利用できません。別のチャンネルを選んでください", "Radio is enabling…": "ラジオを有効化しています…", "Radio is disabling…": "ラジオを無効化しています…", @@ -2027,8 +2027,8 @@ "Download {slot} as a PNG": "{slot}をPNGでダウンロード", "Download the image as a PNG": "画像をPNGでダウンロード", "Box {width} × {height} km": "範囲 {width} × {height} km", - "Acquired {time}": "取得日時 {time}", - "Coverage {coverage}": "カバー率 {coverage}", + "Acquired {time}": "取得時刻 {time}", + "Coverage {coverage}": "カバー範囲 {coverage}", "START HERE · {reason}": "ここから開始 · {reason}", "Daily overview shows little detail in a box this small": "この小さな範囲では、日次概観にほとんど詳細が写りません", "Imagery: NASA GIBS and Worldview · HLS (Sentinel-2, Landsat 8/9) and VIIRS": "画像:NASA GIBSおよびWorldview · HLS(Sentinel-2、Landsat 8/9)とVIIRS", @@ -2096,10 +2096,10 @@ "FETCHING MAPPED SITES": "マップ済み施設を取得中", "RETRYING ALPR CAMERAS": "ALPRカメラを再試行中", "FETCHING ALPR CAMERAS": "ALPRカメラを取得中", - "OVERPASS TEMPORARILY UNAVAILABLE": "OVERPASSが一時的に利用不可", - "OVERPASS RATE-LIMITED": "OVERPASSがレート制限中", - "OVERPASS TIMED OUT": "OVERPASSがタイムアウト", - "OVERPASS COULD NOT COMPLETE THE QUERY": "OVERPASSがクエリを完了できません", + "OVERPASS TEMPORARILY UNAVAILABLE": "Overpassが一時的に利用不可", + "OVERPASS RATE-LIMITED": "Overpassがレート制限中", + "OVERPASS TIMED OUT": "Overpassがタイムアウト", + "OVERPASS COULD NOT COMPLETE THE QUERY": "Overpassがクエリを完了できません", "MAP TILES TEMPORARILY UNAVAILABLE": "地図タイルが一時的に利用不可", "MAPPED NAMES TEMPORARILY UNAVAILABLE": "地名が一時的に利用不可", "TURNING OFF LIVE DATA": "ライブデータをオフにしています", @@ -2187,13 +2187,13 @@ "No sequences in view match the filter": "表示範囲内にフィルターに一致するシーケンスはありません", "No coverage in view": "表示範囲内にカバー範囲がありません", "{n} streets in view · click a line for its nearest photo": { - "other": "表示範囲内の通り {n}本 · 線をクリックすると最寄りの写真を表示" + "other": "表示範囲内の通り {n}本 · 線をクリックで最寄りの写真を表示" }, "{n} sequences in view · click a line for its nearest photo": { - "other": "表示範囲内のシーケンス {n}件 · 線をクリックすると最寄りの写真を表示" + "other": "表示範囲内のシーケンス {n}件 · 線をクリックで最寄りの写真を表示" }, "{n} sequences in view · click a line for its photos": { - "other": "表示範囲内のシーケンス {n}件 · 線をクリックすると写真を表示" + "other": "表示範囲内のシーケンス {n}件 · 線をクリックで写真を表示" }, "km/h": "km/h", "m/s": "m/s", @@ -2231,7 +2231,7 @@ "Voice model tier — applies next session": "音声モデルのティア:次回セッションで適用", "STD": "標準", "Estimated session cost": "セッションの推定コスト", - "Voice control — activate to toggle voice; hold Space to speak": "音声コントロール:有効にすると音声のオン/オフを切り替え、Spaceを長押しで話す", + "Voice control — activate to toggle voice; hold Space to speak": "音声コントロール:押すと音声のオン/オフを切り替え、Spaceを長押しで話す", "ON/OFF": "オン/オフ", "VOICE STANDBY": "音声待機中", "VOICE CONTROL": "音声コントロール", @@ -2284,7 +2284,7 @@ "Gemini token response did not include a valid model": "Geminiのトークン応答に有効なモデルが含まれていません", "Gemini token response did not include session settings": "Geminiのトークン応答にセッション設定が含まれていません", "Gemini session settings do not match the input mode": "Geminiのセッション設定が入力モードと一致しません", - "Requesting microphone": "マイクを要求中", + "Requesting microphone": "マイクへのアクセスを要求中", "Gemini could not submit this input. Start voice again.": "Geminiがこの入力を送信できませんでした。音声をもう一度開始してください。", "Connecting to Gemini": "Geminiに接続中", "Ask or command": "質問またはコマンドをどうぞ", @@ -2388,7 +2388,7 @@ "anywhere in the loaded data": "読み込み済みデータ全体", "in view": "表示範囲内", "within {radius} of the view centre": "表示中心から{radius}以内", - "within {radius} of {place} (Contacts window)": "{place}から{radius}以内(コンタクトのウィンドウ)", + "within {radius} of {place} (Contacts window)": "{place}から{radius}以内(コンタクトの範囲)", "within {radius} of {place}": "{place}から{radius}以内", "within {radius}": "{radius}以内", "over {region}": "{region}全域", @@ -2397,7 +2397,7 @@ "last 24 h": "過去24時間", "past 30 d and upcoming": "過去30日間と今後", "the flights layer loads by viewport": "フライトレイヤーは表示範囲ごとに読み込まれます", - "distance is ground distance, not overhead": "距離は地上距離で、真上からの距離ではありません", + "distance is ground distance, not overhead": "距離は地表上の距離で、衛星までの直線距離ではありません", "the count is a lower bound because at least one layer reached its retained limit.": "少なくとも1つのレイヤーが保持上限に達したため、この件数は下限値です。", "{label} off": "{label} オフ", "{label} loading": "{label}読み込み中", @@ -2418,7 +2418,7 @@ "unavailable": "利用不可", "Not answered: {layers}": "応答なし:{layers}", "Toggle voice control": "音声コントロールを切り替え", - "Activate to toggle voice": "有効にすると音声を切り替え", + "Activate to toggle voice": "押すと音声のオン/オフを切り替え", "Voice active": "音声 オン", "Voice could not be started.": "音声を開始できませんでした。", "the active voice session": "有効な音声セッション", @@ -2539,7 +2539,7 @@ "Tracing outline": "輪郭を描画中", "Looking up place": "場所を照会中", "Flying": "移動中", - "Turning on layer": "レイヤーをオン中", + "Turning on layer": "レイヤーを有効化中", "Loading aircraft": "航空機を読み込み中", "Picking nearest": "最寄りを選択中", "Working": "処理中", @@ -2567,7 +2567,7 @@ "Cockpit vision style": "コックピットのビジョンスタイル", "Previous cockpit vision style": "前のコックピットビジョンスタイル", "Previous vision style": "前のビジョンスタイル", - "Current cockpit vision style: NORMAL. Activate for next style.": "現在のコックピットビジョンスタイル:標準。有効にすると次のスタイルへ。", + "Current cockpit vision style: NORMAL. Activate for next style.": "現在のコックピットビジョンスタイル:標準。押すと次のスタイルに切り替わります。", "Current style: NORMAL — click for next": "現在のスタイル:標準 — クリックで次へ", "CURRENT": "現在", "Next cockpit vision style": "次のコックピットビジョンスタイル", @@ -2602,12 +2602,12 @@ "Location-based information": "位置に基づく情報", "TEMP": "気温", "WIND": "風", - "SKY": "空", + "SKY": "天気", "PRECIP": "降水", "MM": "mm", "Weather data by Open-Meteo.com": "気象データ提供:Open-Meteo.com", "Cockpit briefing pages": "コックピットのブリーフィングページ", - "SIG": "信号", + "SIG": "シグナル", "Show Live Signals": "ライブシグナルを表示", "NEWS": "ニュース", "Show Regional News": "地域ニュースを表示", @@ -2696,7 +2696,7 @@ "Radio volume": "ラジオの音量", "STATION SITE": "放送局サイト", "DIRECTORY: RADIO BROWSER": "ディレクトリ:RADIO BROWSER", - "Audio connects directly to the broadcaster after you press play. Your IP is visible to that broadcaster.": "再生ボタンを押すと、音声は放送局に直接接続されます。IPアドレスは放送局に表示されます。", + "Audio connects directly to the broadcaster after you press play. Your IP is visible to that broadcaster.": "再生ボタンを押すと、音声は放送局に直接接続されます。お使いのIPアドレスは放送局側から見えます。", "Local RTL-SDR receiver": "ローカルRTL-SDR受信機", "LOCAL RTL-SDR": "ローカルRTL-SDR", "Chrome/Edge · WebUSB · one local tuner shared by FM and the Local ADS-B layer.": "Chrome/Edge · WebUSB · 1台のローカルチューナーをFMとローカルADS-Bレイヤーで共有します。", @@ -2776,7 +2776,7 @@ "Red": "赤", "Clear": "消去", "Remove every mark from the board": "ボードからすべてのマークを削除", - "Show your own GeoJSON, KML, KMZ or GPX files on the globe (or drop them onto it). File bytes stay on this device; overlays can appear in map screenshots shared with voice.": "手元のGeoJSON、KML、KMZ、GPXファイルを地球上に表示します(地球にドロップすることもできます)。ファイルのデータはこのデバイスから出ません。オーバーレイは、音声と共有される地図のスクリーンショットに写る場合があります。", + "Show your own GeoJSON, KML, KMZ or GPX files on the globe (or drop them onto it). File bytes stay on this device; overlays can appear in map screenshots shared with voice.": "手元のGeoJSON、KML、KMZ、GPXファイルを地球上に表示します(地球にドロップすることもできます)。ファイルのデータはこのデバイスから出ません。オーバーレイは、音声アシスタントと共有される地図のスクリーンショットに写る場合があります。", "Import": "インポート", "Choose GeoJSON, KML, KMZ or GPX files": "GeoJSON、KML、KMZ、GPXファイルを選択", "Imported files": "インポートしたファイル", @@ -2814,8 +2814,8 @@ "Image fit": "画像の表示方法", "FIT": "全体", "Fit: show the whole photo, with dark bars where its shape differs from the frame": "全体:写真全体を表示し、枠と縦横比が異なる部分は黒帯で埋めます", - "FILL": "フィル", - "Fill: fill the frame edge to edge, cropping the photo": "フィル:枠いっぱいに表示し、写真をトリミングします", + "FILL": "全面", + "Fill: fill the frame edge to edge, cropping the photo": "全面:枠いっぱいに表示し、写真をトリミングします", "Close the image and deselect it on the map": "画像を閉じて地図上の選択を解除", "Close the street-level image": "ストリートレベル画像を閉じる", "Street-level viewer": "ストリートレベルビューアー", @@ -2834,8 +2834,8 @@ "CAPTURE SHOT": "ショット取得", "UPDATE SHOT": "ショット更新", "START": "開始", - "EXPORT PRESETS": "プリセット書出", - "IMPORT": "読込", + "EXPORT PRESETS": "エクスポート", + "IMPORT": "インポート", "RUN LOG": "実行ログ", "POWER UP": "パワーアップ", "GROUND STATION · PROVIDER SETTINGS": "地上局 · プロバイダー設定", diff --git a/src/ui/styles/cjk.css b/src/ui/styles/cjk.css index d9cb9246d..1315a8d23 100644 --- a/src/ui/styles/cjk.css +++ b/src/ui/styles/cjk.css @@ -62,3 +62,10 @@ html:is(:lang(zh), :lang(ja)) .recent-imagery-readout .ri-card-sensor { white-space: normal; text-overflow: clip; } + +/* The Japanese imagery slot line wraps at its · separators, never inside a + word (プレ / ビュー); a run too long for the line still breaks. */ +html:lang(ja) .recent-imagery-readout .ri-slot-value { + word-break: keep-all; + overflow-wrap: break-word; +} From e87001d0db4e08341f80c01a091e5a130e1b8b5c Mon Sep 17 00:00:00 2001 From: German Khokhlov Date: Wed, 28 Oct 2026 17:55:20 +0400 Subject: [PATCH 30/83] i18n(fr): apply review round 2 Co-Authored-By: Claude Opus 5.5 --- docs/translations/fr.md | 124 ++++++++++++++++++---------------- src/i18n/locales/fr.json | 62 ++++++++--------- src/ui/radioBindings.js | 7 ++ src/ui/templates/context.html | 2 +- src/voice/speech.js | 5 +- src/voice/speech.test.mjs | 13 ++++ 6 files changed, 122 insertions(+), 91 deletions(-) diff --git a/docs/translations/fr.md b/docs/translations/fr.md index 695d1b48f..8a10804b0 100644 --- a/docs/translations/fr.md +++ b/docs/translations/fr.md @@ -28,64 +28,72 @@ A `tn()` entry needs three forms. `Intl.PluralRules('fr')` picks: | `many` | 1 000 000, 2 000 000… (exact millions) | 1 000 000 de caméras | | `other` | everything else: 2–999 999, 2,5… | 3 caméras | -The `many` form is the `other` text with « de » (« d' » before a vowel) after the number: « {count} de couches effacées », « {count} D'ENTRÉES INCONNUES ». When the words after the number cannot agree (an UPPERCASE readout, a list), put the number after a colon in every form: « CAPTÉS : {count} ». +The `many` form is the `other` text with « de » (« d' » before a vowel) after the number: « {count} de couches effacées », « {count} D'ENTRÉES INCONNUES ». When the words after the number cannot agree (an UPPERCASE readout, a list), put the number after a colon in every form: « CAPTÉS : {count} ». The same goes for a layer name whose gender and number vary: « Couche activée : {label} », not « {label} activé ». ## Glossary -| English | Français | -| --------------------------------------------------------- | ----------------------------------------------------------------------- | -| layer / data layer / DATA LAYERS (panel title) | couche / couche de données / COUCHES | -| feed / source / data source | flux / source / source de données | -| LIVE (status) / live data | DIRECT / données en direct | -| SIMULATED | SIMULÉ | -| stale / degraded / unavailable | obsolète / dégradé / indisponible | -| retry / retrying | nouvel essai / réessayez | -| rate-limited | limite de requêtes atteinte | -| key (API key) / POWER UP / POWERED UP | clé (clé API) / ALLUMER / ALLUMÉ | -| Provider Settings | paramètres des fournisseurs | -| enable / disable | activer / désactiver | -| globe / map / map source / basemap / map stack | globe / carte / source de carte / fond de carte / fond de carte | -| tile (map) | tuile | -| aircraft / flight / military flights | aéronef (avion in short copy) / vol / vols militaires | -| vessel, ship / tanker (AIS type) | navire / navire-citerne | -| satellite / shell (Starlink) / DENSE | satellite / couche de la constellation / DENSE | -| launch / launch site / space mission | lancement / site de lancement / mission spatiale | -| ascent / replay / payload / stage / downrange | ascension / rejeu / charge utile / étage / distance au sol (DIST. SOL) | -| contact / tracking / track (HUD) | contact / suivi / piste | -| installation / site | installation / site | -| mapped / observed | cartographié / observé | -| camera / CCTV camera / ALPR camera | caméra / caméra CCTV / caméra LAPI | -| earthquake | séisme | -| active fire (FIRMS detection) / wildfire | feu actif / incendie | -| contained / containment (wildfire) | circonscrit / part circonscrite (not « maîtrisé », which is controlled) | -| advisory (NHC/CPHC cyclone) | bulletin | -| forecast / lead hours / valid / issued | prévision / échéances / valide / émise | -| AQHI (Canada) | CQAS (cote air santé) | -| radio station / tune | station / régler | -| bikeshare / transit | vélos partagés / transports en commun | -| route (directions) / turn (maneuver) | itinéraire / manœuvre | -| scene / shot / scene recipe | scène / plan / recette de scène | -| bundle / data pack / anchor | archive / paquet de données / ancre | -| story beat | étape du récit | -| briefing / panel / dock | briefing / panneau / dock | -| cockpit | cockpit | -| preset / visual preset | préréglage / préréglage visuel | -| Scope (circular viewport mask) / keyhole | lunette / ouverture | -| detection overlay | surcouche de détection | -| Clean UI | vue épurée | -| Street Level (layer) / Street View (Google) | Niveau rue / Street View | -| Recent Imagery / box | imagerie récente / zone | -| pin (Draw tool) / pin (Recent Imagery) | épingle / épingler | -| Cyber (HUD layout, effect) | Cyber | -| heading / course (ground track) / altitude / ground speed | cap / route / altitude / vitesse sol | -| HDG / BRG / CRS / FOV / DEST / SPD / ALT | unchanged | -| RANGE / PITCH / HGT (CCTV calibration chips) | PORTÉE / INCL. / HAUT. | -| PREV / PREVIOUS / NEXT (chips) | PRÉC. / PRÉC. / SUIV. | -| Previous / Next (button text) | Précédent / Suivant | -| L / R (relative bearing) | G / D | -| SIG / NEWS / LOCAL (briefing tabs) | SIG / ACTUS / LOCAL | -| compass points (N, NNE, …, W, NW) | N, NNE, …, O, NO | -| NOT AN ALL-CLEAR | PAS UN FEU VERT | -| AI agent | agent IA | -| share (a view or link) | partager | -| click / click to … | cliquez / cliquer pour … | +| English | Français | +| ------------------------------------------------------------ | ----------------------------------------------------------------------- | +| layer / data layer / DATA LAYERS (panel title) | couche / couche de données / COUCHES | +| feed / source / data source | flux / source / source de données | +| LIVE (status) / live data | DIRECT / données en direct | +| SIMULATED | SIMULÉ | +| stale / degraded / unavailable | obsolète / dégradé / indisponible | +| retry / retrying (status: RETRYING X) | nouvel essai / réessayez (NOUVEL ESSAI : X) | +| rate-limited | limite de requêtes atteinte | +| key (API key) / POWER UP / POWERED UP | clé (clé API) / ALLUMER / ALLUMÉ | +| Provider Settings | paramètres des fournisseurs | +| enable / disable | activer / désactiver | +| globe / map / map source / basemap / map stack | globe / carte / source de carte / fond de carte / fond de carte | +| tile (map) | tuile | +| aircraft / flight / military flights | aéronef (avion in short copy) / vol / vols militaires | +| vessel, ship / tanker (AIS type) | navire / navire-citerne | +| satellite / shell (Starlink) / DENSE | satellite / couche de la constellation / DENSE | +| launch / launch site / space mission | lancement / site de lancement / mission spatiale | +| ascent / replay / payload / stage / downrange | ascension / rejeu / charge utile / étage / distance au sol (DIST. SOL) | +| contact / tracking / track (HUD) | contact / suivi / piste | +| installation / site | installation / site | +| mapped / observed | cartographié / observé | +| camera / CCTV camera / ALPR camera | caméra / caméra CCTV / caméra LAPI | +| earthquake | séisme | +| active fire (FIRMS detection) / wildfire | feu actif / incendie | +| contained / containment (wildfire) | circonscrit / part circonscrite (not « maîtrisé », which is controlled) | +| advisory (NHC/CPHC cyclone) | bulletin | +| forecast / lead hours / valid / issued | prévision / échéances / valide / émise | +| AQHI (Canada) | CQAS (cote air santé) | +| radio station / tune | station / régler | +| bikeshare / transit | vélos partagés / transports en commun | +| route (directions) / turn (maneuver) | itinéraire / manœuvre | +| scene / shot / scene recipe | scène / plan / recette de scène | +| bundle / data pack / anchor | archive / paquet de données / ancre | +| story beat | étape du récit | +| briefing / panel / dock | briefing / panneau / dock | +| cockpit | cockpit | +| preset / visual preset | préréglage / préréglage visuel | +| Scope (circular viewport mask) / keyhole | lunette / ouverture | +| detection overlay | surcouche de détection | +| Clean UI | vue épurée | +| Street Level (layer) / Street View (Google) | Niveau rue / Street View | +| Recent Imagery / box | imagerie récente / zone | +| pin (Draw tool) / pin (Recent Imagery) | épingle / épingler | +| Cyber (HUD layout, effect) | Cyber | +| heading / course (ground track) / altitude / ground speed | cap / route / altitude / vitesse sol | +| HDG / BRG / CRS / FOV / DEST / SPD / ALT | unchanged | +| RANGE / PITCH / HGT (CCTV calibration chips) | PORTÉE / INCL. / HAUT. | +| PREV / PREVIOUS / NEXT (chips) | PRÉC. / PRÉC. / SUIV. | +| Previous / Next (button text) | Précédent / Suivant | +| L / R (relative bearing) | G / D | +| SIG / NEWS / LOCAL (briefing tabs) | SIG / ACTUS / LOCAL | +| compass points (N, NNE, …, W, NW) | N, NNE, …, O, NO | +| NOT AN ALL-CLEAR | PAS UN FEU VERT | +| AI agent | agent IA | +| share (a view or link) | partager | +| click / click to … | cliquez / cliquer pour … | +| map heading (compass, north-up control) | orientation (de la carte) | +| subject (cockpit / shared contact) | cible | +| cloud cover / CLOUD (briefing readout) | nébulosité / NÉBULOSITÉ | +| LEVEL (cockpit horizon guide) | HORIZON | +| CALIBRATED / CURATED / RAW PRIOR (CCTV pose) | CALIBRÉE / VÉRIFIÉE / ESTIM. INITIALE | +| PORT TENDER (AIS type) | SERVITUDE PORT. (navire de servitude portuaire) | +| ChatGPT sign-in (action) / opening sign-in / sign-in expired | connexion / page de connexion / la session a expiré | +| authored shot (scene) | plan scénarisé | diff --git a/src/i18n/locales/fr.json b/src/i18n/locales/fr.json index 883621f94..f90c1d50e 100644 --- a/src/i18n/locales/fr.json +++ b/src/i18n/locales/fr.json @@ -169,7 +169,7 @@ "other": "{count} SOURCES" }, "OUTSIDE IMAGERY SWIPE": "HORS DE LA COMPARAISON D'IMAGES", - "{scene} / AUTHORED SHOT": "{scene} / PLAN CONÇU", + "{scene} / AUTHORED SHOT": "{scene} / PLAN SCÉNARISÉ", "NEPAL FLOOD INCIDENT": "CRUE AU NÉPAL", "Play {shot}": "Lire {shot}", "current scene shot": "le plan actuel de la scène", @@ -242,7 +242,7 @@ "Map tiles temporarily unavailable": "Tuiles de la carte temporairement indisponibles", "Mapped names temporarily unavailable": "Noms cartographiés temporairement indisponibles", "Overpass temporarily unavailable": "Overpass temporairement indisponible", - "Retrying mapped sites…": "Nouvel essai des sites cartographiés…", + "Retrying mapped sites…": "Nouvel essai : sites cartographiés…", "Fetching mapped sites…": "Récupération des sites cartographiés…", "{reason} — retrying in {seconds}s": "{reason} — nouvel essai dans {seconds} s", "{reason} — retry pending": "{reason} — nouvel essai en attente", @@ -286,7 +286,7 @@ "PILOT": "PILOTINE", "SAR": "SAR", "TUG": "REMORQUEUR", - "PORT TENDER": "SERVITUDE", + "PORT TENDER": "SERVITUDE PORT.", "ANTI-POLLUTION": "ANTIPOLLUTION", "LAW ENFORCE": "POLICE", "MEDICAL": "MÉDICAL", @@ -414,8 +414,8 @@ "Checking local ChatGPT OAuth sign-in…": "Vérification de la connexion OAuth ChatGPT locale…", "Could not check ChatGPT sign-in.": "Impossible de vérifier la connexion ChatGPT.", "ChatGPT OAuth selected for cloud voice. Your API key stays saved and available.": "OAuth ChatGPT sélectionné pour la voix cloud. Votre clé API reste enregistrée et disponible.", - "ChatGPT sign-in expired. Opening sign-in again…": "La connexion ChatGPT a expiré. Nouvelle ouverture de la connexion…", - "Opening ChatGPT sign-in in your browser…": "Ouverture de la connexion ChatGPT dans votre navigateur…", + "ChatGPT sign-in expired. Opening sign-in again…": "La session ChatGPT a expiré. Réouverture de la page de connexion…", + "Opening ChatGPT sign-in in your browser…": "Ouverture de la page de connexion ChatGPT dans votre navigateur…", "Could not start ChatGPT sign-in on this machine.": "Impossible de lancer la connexion ChatGPT sur cette machine.", "Finish ChatGPT sign-in in the browser. Waiting for it to complete…": "Terminez la connexion ChatGPT dans le navigateur. En attente de la fin…", "ChatGPT sign-in timed out. Click {button} to try again.": "Délai de connexion ChatGPT dépassé. Cliquez sur « {button} » pour réessayer.", @@ -473,7 +473,7 @@ "many": "{count} à proximité", "other": "{count} à proximité" }, - "retrying mapped ALPR cameras": "nouvel essai des caméras LAPI cartographiées", + "retrying mapped ALPR cameras": "nouvel essai : caméras LAPI cartographiées", "loading mapped ALPR cameras": "chargement des caméras LAPI cartographiées", "No ALPR data for this area — US and Canada only": "Aucune donnée LAPI pour cette zone — États-Unis et Canada seulement", "Zoom in to load mapped cameras": "Zoomez pour charger les caméras cartographiées", @@ -634,8 +634,8 @@ "At the end of the road, turn {direction}": "Au bout de la route, tournez {direction}", "At the end of the road, continue onto {road}": "Au bout de la route, continuez sur {road}", "At the end of the road, continue": "Au bout de la route, continuez", - "Keep {direction} at the fork onto {road}": "À l'embranchement, restez {direction} sur {road}", - "Keep {direction} at the fork": "À l'embranchement, restez {direction}", + "Keep {direction} at the fork onto {road}": "À l'embranchement, continuez {direction} sur {road}", + "Keep {direction} at the fork": "À l'embranchement, continuez {direction}", "Continue at the fork onto {road}": "À l'embranchement, continuez sur {road}", "Continue at the fork": "À l'embranchement, continuez", "Merge {direction} onto {road}": "Insérez-vous {direction} sur {road}", @@ -815,7 +815,7 @@ "ORBIT REPLAY · {mission}": "REJEU DE L'ORBITE · {mission}", "PAUSED · {title}": "PAUSE · {title}", "UNSPECIFIED": "NON PRÉCISÉ", - "+{count} additional payload records": "+{count} enregistrements de charge utile supplémentaires", + "+{count} additional payload records": "Enregistrements de charge utile supplémentaires : +{count}", "PAYLOAD DATA UNAVAILABLE": "DONNÉES DE CHARGE UTILE INDISPONIBLES", "{value} KM DOWNRANGE": "DIST. SOL : {value} KM", "POSITION UNAVAILABLE": "POSITION INDISPONIBLE", @@ -1005,7 +1005,7 @@ "Imagery catalog unavailable": "Catalogue d'images indisponible", "Catalog truncated · a newer clear day may exist": "Catalogue tronqué · un jour dégagé plus récent peut exister", "{label} catalog unavailable · {detail}": "Catalogue {label} indisponible · {detail}", - "Daily overview for today may still be empty until the pass": "La vue d'ensemble quotidienne peut rester vide jusqu'au passage du satellite", + "Daily overview for today may still be empty until the pass": "La vue quotidienne d'aujourd'hui peut rester vide jusqu'au passage du satellite", "Box and images cleared": "Zone et images effacées", "MORE DETAIL · 30 m": "PLUS DE DÉTAIL · 30 m", "Sentinel-2 and Landsat via HLS, 30 m, every 2–6 days": "Sentinel‑2 et Landsat via HLS, 30 m, tous les 2 à 6 jours", @@ -1238,7 +1238,7 @@ "Vivid": "Forte", "Image opacity; does not alter the observed values": "Opacité de l'image ; ne modifie pas les valeurs observées", "View US radar": "Voir le radar des États-Unis", - "View Americas & Pacific": "Voir Amériques et Pacifique", + "View Americas & Pacific": "Voir les Amériques et le Pacifique", "View coverage": "Voir la couverture", "{value} strikes/km²/min ×10³ (15-minute density)": "{value} impacts/km²/min ×10³ (densité sur 15 minutes)", "{value} dBZ radar reflectivity": "{value} dBZ de réflectivité radar", @@ -1246,7 +1246,7 @@ "Map center is outside source coverage": "Le centre de la carte est hors de la couverture de la source", "NOAA/NWS 15-minute lightning density derived from Vaisala NLDN/GLD360. Coverage 110°E across the Pacific/Americas to 0°, 25°S–80°N. Not a live strike count, global coverage or a safety warning.": "Densité de foudre sur 15 minutes de NOAA/NWS, dérivée de Vaisala NLDN/GLD360. Couverture de 110°E à 0° à travers le Pacifique et les Amériques, 25°S–80°N. Ce n'est ni un décompte d'impacts en direct, ni une couverture mondiale, ni une alerte de sécurité.", "NOAA MRMS radar echoes indicate precipitation patterns, not rain rate, a storm warning or a future forecast. Native source approximately 1 km; display is limited to level 6. Frames use exact advertised observation times.": "Les échos radar NOAA MRMS indiquent la structure des précipitations, pas l'intensité de la pluie, une alerte d'orage ou une prévision. Résolution native d'environ 1 km ; l'affichage est limité au niveau 6. Les images utilisent les heures d'observation exactes publiées.", - "GOES-19/18 longwave infrared Band 14 regional; NESDIS global longwave mosaic. Clouds only dims everything but bright, cold cloud tops; a brightness filter, not a cloud mask. Coverage and freshness differ by region.": "Infrarouge grandes longueurs d'onde GOES-19/18, bande 14, régional ; mosaïque mondiale grandes longueurs d'onde NESDIS. Nuages seuls assombrit tout sauf les sommets nuageux brillants et froids ; c'est un filtre de luminosité, pas un masque de nuages. La couverture et la fraîcheur varient selon la région.", + "GOES-19/18 longwave infrared Band 14 regional; NESDIS global longwave mosaic. Clouds only dims everything but bright, cold cloud tops; a brightness filter, not a cloud mask. Coverage and freshness differ by region.": "Infrarouge grandes longueurs d'onde GOES-19/18, bande 14, régional ; mosaïque mondiale grandes longueurs d'onde NESDIS. « Nuages seuls » assombrit tout sauf les sommets nuageux brillants et froids ; c'est un filtre de luminosité, pas un masque de nuages. La couverture et la fraîcheur varient selon la région.", "REGION": "RÉGION", "IMAGE": "IMAGE", "FILTER": "FILTRE", @@ -1254,7 +1254,7 @@ "OPACITY": "OPACITÉ", "Infrared decode failed": "Échec du décodage infrarouge", "Weather prefetch unavailable": "Préchargement météo indisponible", - "Weather tiles unavailable · previous frame retained": "Tuiles météo indisponibles · image précédente conservée", + "Weather tiles unavailable · previous frame retained": "Tuiles indisp. · image précédente conservée", "Some weather tiles unavailable": "Certaines tuiles météo indisponibles", "Malformed weather manifest": "Manifeste météo mal formé", "Weather request timed out": "Délai dépassé pour la requête météo", @@ -1552,7 +1552,7 @@ "Copy failed": "Échec de la copie", "Return map to straight-down view": "Remettre la carte en vue verticale", "Tilt map to oblique view": "Incliner la carte en vue oblique", - "Reset map to north up. Current heading {heading} degrees": "Réorienter la carte nord en haut. Cap actuel {heading} degrés", + "Reset map to north up. Current heading {heading} degrees": "Réorienter la carte nord en haut. Orientation actuelle : {heading} degrés", "Tilted view": "Vue inclinée", "Straight-down view": "Vue verticale", "North up": "Nord en haut", @@ -1596,7 +1596,7 @@ "FRAME · LOADING": "IMAGE · CHARGEMENT", "FRAME · UNAVAILABLE": "IMAGE · INDISPONIBLE", "CALIBRATED": "CALIBRÉE", - "CURATED": "SÉLECTIONNÉE", + "CURATED": "VÉRIFIÉE", "RAW PRIOR": "ESTIM. INITIALE", "CCTV ON": "CCTV ON", "CCTV OFF": "CCTV OFF", @@ -1651,17 +1651,17 @@ "NO RECENT LOCATION MATCHES": "AUCUNE ACTU RÉCENTE POUR CE LIEU", "{domain} · {age}": "{domain} · {age}", "{value} KM/H": "{value} KM/H", - "CLOUD {pct}%": "NUAGES {pct} %", - "CLOUD UNKNOWN": "NUAGES INCONNUS", + "CLOUD {pct}%": "NÉBULOSITÉ {pct} %", + "CLOUD UNKNOWN": "NÉBULOSITÉ INCONNUE", "{source} · LOCATION QUERY": "{source} · REQUÊTE DE LIEU", "REGIONAL NEWS": "ACTUS RÉGIONALES", "{label} · {radius} AIR/SEA WINDOW": "{label} · AIR/MER {radius}", "{scope} · INSTALLATIONS {coverage}": "{scope} · INSTALLATIONS : {coverage}", "CONTEXT STANDBY": "CONTEXTE EN VEILLE", "ENABLE GLOBAL CONTEXT FOR PROXIMITY PINGS": "ACTIVER LE CONTEXTE GLOBAL POUR LES PINGS DE PROXIMITÉ", - "CONTACT LOST · LAST KNOWN READOUT · NOT AN ALL-CLEAR": "CONTACT PERDU · DERNIÈRE POSITION CONNUE · PAS UN FEU VERT", + "CONTACT LOST · LAST KNOWN READOUT · NOT AN ALL-CLEAR": "CONTACT PERDU · DERNIER RELEVÉ CONNU · PAS UN FEU VERT", "CONTACT LOST · {subject}": "CONTACT PERDU · {subject}", - "SUBJECT LEFT ITS FEED · READOUT HOLDING LAST KNOWN": "SUJET SORTI DE SON FLUX · AFFICHAGE SUR LA DERNIÈRE POSITION CONNUE", + "SUBJECT LEFT ITS FEED · READOUT HOLDING LAST KNOWN": "CIBLE ABSENTE DU FLUX · DERNIER RELEVÉ CONSERVÉ", "{cohort} · {contact}": "{cohort} · {contact}", "NO AVAILABLE EXAMPLE": "AUCUN EXEMPLE DISPONIBLE", "{cohort}, Unavailable": "{cohort}, indisponible", @@ -1848,7 +1848,7 @@ "{state} · {source} · {detail}": "{state} · {source} · {detail}", "never": "jamais", "{source} · {loadingLabel}": "{source} · {loadingLabel}", - "{accepted} of {raw} records accepted": "{accepted} enregistrements acceptés sur {raw}", + "{accepted} of {raw} records accepted": "Enregistrements acceptés : {accepted} sur {raw}", "incomplete snapshot": "instantané incomplet", "{state} · {source} · {detail} · {ago}": "{state} · {source} · {detail} · {ago}", "{state} · {source} · {ago} · retrying in {seconds}s": "{state} · {source} · {ago} · nouvel essai dans {seconds} s", @@ -1980,7 +1980,7 @@ "PLAY": "LIRE", "selected": "sélectionnée", "nearest": "la plus proche", - "{action} {target} radio station": "{action} la station radio {target}", + "{action} {target} radio station": "{action} : station radio {target}", "RADIO STATE UNCERTAIN": "ÉTAT RADIO INCERTAIN", "SYNCING DIRECTORY": "SYNCHRO DE L'ANNUAIRE", "RADIO READY": "RADIO PRÊTE", @@ -2080,7 +2080,7 @@ "start here": "commencer ici", "No box": "Aucune zone", "Searching": "Recherche", - "Every day is empty here": "Tous les jours sont vides ici", + "Every day is empty here": "Aucune image trouvée ici", "Sources off": "Sources désactivées", "VS": "VS", "Not set": "Non défini", @@ -2102,7 +2102,7 @@ "Times, coverage, sources": "Heures, couverture, sources", "HIDE EMPTY DAYS": "MASQUER LES JOURS VIDES", "SHOW EMPTY DAYS · {count}": "AFFICHER LES JOURS VIDES · {count}", - "Days the probe found empty in this box": "Jours que la sonde a trouvés vides dans cette zone", + "Days the probe found empty in this box": "Jours sans image trouvée dans cette zone", "image": "image", "BASEMAP": "FOND DE CARTE", "The basemap": "Le fond de carte", @@ -2160,9 +2160,9 @@ "LOAD FAILED": "ÉCHEC DU CHARGEMENT", "LIVE DATA OFF": "DONNÉES EN DIRECT DÉSACTIVÉES", "MAPPED SITES LOADED": "SITES CARTOGRAPHIÉS CHARGÉS", - "RETRYING MAPPED SITES": "NOUVEL ESSAI SITES CARTOGRAPHIÉS", + "RETRYING MAPPED SITES": "NOUVEL ESSAI : SITES CARTOGRAPHIÉS", "FETCHING MAPPED SITES": "RÉCUPÉRATION DES SITES CARTOGRAPHIÉS", - "RETRYING ALPR CAMERAS": "NOUVEL ESSAI CAMÉRAS LAPI", + "RETRYING ALPR CAMERAS": "NOUVEL ESSAI : CAMÉRAS LAPI", "FETCHING ALPR CAMERAS": "RÉCUPÉRATION DES CAMÉRAS LAPI", "OVERPASS TEMPORARILY UNAVAILABLE": "OVERPASS TEMPORAIREMENT INDISPONIBLE", "OVERPASS RATE-LIMITED": "OVERPASS : LIMITE DE REQUÊTES ATTEINTE", @@ -2374,10 +2374,10 @@ "Gemini token response did not include a valid model": "La réponse de Gemini ne contenait pas de modèle valide", "Gemini token response did not include session settings": "La réponse de Gemini ne contenait pas les paramètres de session", "Gemini session settings do not match the input mode": "Les paramètres de session Gemini ne correspondent pas au mode de saisie", - "Requesting microphone": "Demande du microphone", + "Requesting microphone": "Demande d'accès au microphone", "Gemini could not submit this input. Start voice again.": "Gemini n'a pas pu envoyer cette saisie. Relancez la voix.", "Connecting to Gemini": "Connexion à Gemini", - "Ask or command": "Question ou ordre", + "Ask or command": "Question ou commande", "Gemini returned an oversized message": "Gemini a renvoyé un message trop volumineux", "Gemini Live connection failed. Check network access, then start voice again.": "Échec de la connexion à Gemini Live. Vérifiez l'accès au réseau, puis relancez la voix.", "Gemini Live connection ended. Start voice again for a new conversation.": "La connexion à Gemini Live est terminée. Relancez la voix pour une nouvelle conversation.", @@ -2394,7 +2394,7 @@ "Gemini action history is full. Start voice again for a fresh session.": "L'historique des actions de Gemini est plein. Relancez la voix pour une nouvelle session.", "Gemini requested too many simultaneous actions": "Gemini a demandé trop d'actions simultanées", "Running command": "Commande en cours", - "Voice text command is too long": "La commande vocale écrite est trop longue", + "Voice text command is too long": "La commande écrite est trop longue", "Gemini voice is not connected": "La voix Gemini n'est pas connectée", "Gemini interrupted input exceeded its buffer or wait limit. Start voice again.": "La saisie interrompue de Gemini a dépassé sa limite de tampon ou d'attente. Relancez la voix.", "Gemini Live connection is expiring. Start voice again for a new conversation.": "La connexion à Gemini Live expire. Relancez la voix pour une nouvelle conversation.", @@ -2523,7 +2523,7 @@ "the flights layer loads by viewport": "la couche des vols se charge selon la vue", "distance is ground distance, not overhead": "la distance est mesurée au sol jusqu'au point subsatellite, pas jusqu'au satellite", "the count is a lower bound because at least one layer reached its retained limit.": "le décompte est un minimum, car au moins une couche a atteint sa limite de rétention.", - "{label} off": "{label} : désactivé", + "{label} off": "Couche désactivée : {label}", "{label} loading": "{label} : chargement", "{label} error": "{label} : erreur", "counted the first {returned} loaded records": "{returned} premiers enregistrements chargés comptés", @@ -2576,7 +2576,7 @@ "{name} is no longer loaded": "{name} n'est plus chargé", "Unknown target layer: {target}": "Couche cible inconnue : {target}", "nominal": "nominal", - "{label} on": "{label} : activé", + "{label} on": "Couche activée : {label}", "Frame aircraft": "Cadrer les aéronefs", "Frame military aircraft": "Cadrer les aéronefs militaires", "Frame ships": "Cadrer les navires", @@ -2693,7 +2693,7 @@ "Recent speech": "Propos récents", "HERE": "ICI", "Aircraft cockpit view": "Vue cockpit de l'aéronef", - "LEVEL": "NIVEAU", + "LEVEL": "HORIZON", "Estimated destination direction": "Direction estimée de la destination", "DEST ---°": "DEST ---°", "OPTICAL PLANE · 01": "PLAN OPTIQUE · 01", diff --git a/src/ui/radioBindings.js b/src/ui/radioBindings.js index 88756d5bc..4e70764c6 100644 --- a/src/ui/radioBindings.js +++ b/src/ui/radioBindings.js @@ -9,6 +9,13 @@ import { /** Bind Radio input using a RadioControls receiver and supplied actions. */ export function bindRadioControls() { if (!this._radioPanel) return; + // The markup's placeholder option is the station-tag "All"; markup cannot + // carry the 'radio tag' context the loaded list uses, so set it here. + const allTagOption = this._radioFilter?.querySelector?.( + 'option[value="all"]', + ); + if (allTagOption) + allTagOption.textContent = t('All', { context: 'radio tag' }); const tunerListenerOptions = {}; const setRadioDisclosure = (expanded, { returnFocus = false } = {}) => { if (this.destroyed) return; diff --git a/src/ui/templates/context.html b/src/ui/templates/context.html index 9e88d20f4..e83d37aa1 100644 --- a/src/ui/templates/context.html +++ b/src/ui/templates/context.html @@ -122,7 +122,7 @@
diff --git a/src/voice/speech.js b/src/voice/speech.js index c53881595..cbfae621f 100644 --- a/src/voice/speech.js +++ b/src/voice/speech.js @@ -963,7 +963,10 @@ export function progressStepLabel(step, label) { : step ? spokenLabel(step, 24) : t('Working'); - return label ? `${base}: ${spokenLabel(label, 32)}` : base; + // The join is a catalog string so each language spaces its colon. + return label + ? t('{name}: {state}', { name: base, state: spokenLabel(label, 32) }) + : base; } /** diff --git a/src/voice/speech.test.mjs b/src/voice/speech.test.mjs index 36482290d..cc11fef6e 100644 --- a/src/voice/speech.test.mjs +++ b/src/voice/speech.test.mjs @@ -9,6 +9,7 @@ import { spokenLabel, } from './speech.js'; import { countWords, findHedges } from './speechLint.js'; +import { setLocale } from '../i18n/index.js'; function envelope(name, result, args) { return attachVoiceResult(name, result, args); @@ -459,3 +460,15 @@ test('labels are bounded and cleaned before they are spoken', () => { 'background steps stay on screen', ); }); + +test('progress step labels join through the catalog colon', () => { + setLocale('fr'); + try { + assert.equal( + progressStepLabel('resolve', 'Capitol'), + 'Recherche de lieux\u202f: Capitol', + ); + } finally { + setLocale('en'); + } +}); From 858ce827e50a7e9659e35a1dffc7c1a964ceebaf Mon Sep 17 00:00:00 2001 From: German Khokhlov Date: Wed, 28 Oct 2026 17:57:51 +0400 Subject: [PATCH 31/83] i18n(pt): apply review round 2 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Three-model review (astra, sol, fable), round 2: 29 of 30 findings applied, one of them in part. - pt: FIRMS «mais recente há», CCTV «cruzamentos», degraded radio directory, «{layers}: ativação recente» for any layer list, «Sem imagem», NIVELADO, AJUSTA-SE, quoted Provider Settings, V/S kept on the ADS-B card, no-break space in «(24 h)» / «(30 d)», and more (see docs/translations/pt.md). - Malformed cyclone snapshot is now a catalog message (all locales). - Markup supports data-i18n-context; the radio STATION TAG option uses "radio tag|All", so it no longer flips gender when the list loads. Co-Authored-By: Claude Opus 5.5 --- docs/I18N.md | 2 +- docs/translations/pt.md | 14 +++++--- scripts/i18n.mjs | 7 ++-- src/i18n/i18n.test.mjs | 15 ++++++++ src/i18n/index.js | 9 +++-- src/i18n/locales/es.json | 1 + src/i18n/locales/pt.json | 65 ++++++++++++++++++----------------- src/i18n/locales/ru.json | 1 + src/i18n/locales/zh-CN.json | 1 + src/i18n/locales/zh-Hant.json | 1 + src/i18n/same-as-english.json | 1 + src/layers/cyclones/source.js | 6 ++-- src/ui/templates/context.html | 2 +- 13 files changed, 79 insertions(+), 46 deletions(-) diff --git a/docs/I18N.md b/docs/I18N.md index 9b5220917..105fd5fb3 100644 --- a/docs/I18N.md +++ b/docs/I18N.md @@ -35,7 +35,7 @@ A module the server, tools or other portable code also imports must not load the ``` -`data-i18n` replaces the element's text, so put it on the element that directly holds the text, never on a parent with child elements. `data-i18n-title`, `data-i18n-aria-label` and `data-i18n-placeholder` translate that attribute. Markup is translated once at boot, and switching language reloads the page. A module that holds work a reload would lose (an unsaved edit, an open session) registers it with `registerUnsavedWork(() => busy ? msg('unsaved …') : null)` from `src/i18n/index.js`, and the language picker asks before reloading. +`data-i18n` replaces the element's text, so put it on the element that directly holds the text, never on a parent with child elements. `data-i18n-title`, `data-i18n-aria-label` and `data-i18n-placeholder` translate that attribute. `data-i18n-context="radio tag"` gives the element's text a context, the catalog entry `radio tag|All`, as `t('All', { context: 'radio tag' })` does in code. Markup is translated once at boot, and switching language reloads the page. A module that holds work a reload would lose (an unsaved edit, an open session) registers it with `registerUnsavedWork(() => busy ? msg('unsaved …') : null)` from `src/i18n/index.js`, and the language picker asks before reloading. ## Rules diff --git a/docs/translations/pt.md b/docs/translations/pt.md index bf1208dce..15d6291b5 100644 --- a/docs/translations/pt.md +++ b/docs/translations/pt.md @@ -9,15 +9,15 @@ Translation source: abiyeenzo (#909). - Brazilian Portuguese (pt-BR): câmera, tela, compartilhar, arquivo, baixar, ônibus, metrô. Every `pt` tag, `pt-PT` included, gets this catalog, so avoid slang and regionalisms. - Address the user with «você» imperatives: «Clique no mapa», «Ative o CCTV», «Tente novamente». Tooltips that name an action use the infinitive: «Expandir painel», «Redefinir a câmera». - Sentence case, not Title Case: "Live Flights" → «Voos ao vivo». UPPERCASE English stays UPPERCASE: «AO VIVO», «SEM DADOS». -- Quotes inside Portuguese text are straight double quotes: «Excluir o plano "{shot}"?». A sentence that names a panel uses «o painel "Configurações de provedores"», so the verb agrees. +- Quotes inside Portuguese text are straight double quotes: «Excluir o plano "{shot}"?». A sentence that names a panel quotes it: «o painel "Configurações de provedores"» as the subject, so the verb agrees, and «adicione em "Configurações de provedores"» after a preposition. - A dash between clauses is a spaced em dash « — », even where the English runs it in. -- A date or time after a participle takes a preposition: «emitido em {time}», «válida para {valid}», «Posição em {time}». +- A date or time after a participle takes a preposition: «emitido em {time}», «válida para {valid}», «Posição em {time}», «onde estava em {time}». Use «em», not «às», wherever {time} can include a date. - Short labels, chips and HUD readouts stay short. A standard abbreviation with a period beats a wrapped line: ANT., PRÓX., DESLIG., EXCL., INCL., ALT., VEL., câm. -- The HUD codes HDG, BRG, CRS, FOV, DEST, SPD, RANGE, ALT, GS and TRK stay in English, as in cockpit avionics («ALT {altitude} FT · GS {speed} KT · TRK {track}»), and so does the HUD recording mark REC. Words used in a sentence are translated: heading → «rumo», range → «alcance». +- The HUD codes HDG, BRG, CRS, FOV, DEST, SPD, RANGE, ALT, GS, TRK and V/S stay in English, as in cockpit avionics («ALT {altitude} FT · GS {speed} KT · TRK {track}», «V/S {rate} FT/MIN»), and so does the HUD recording mark REC. Words used in a sentence are translated: heading → «rumo», range → «alcance». - Keyboard keys stay in English: Space, Esc, Enter, Tab, Shift, Backspace, H, 1–9 («Segure Space para falar»). - Common English tech words used in Brazil stay: feed, stream, snapshot, briefing, dock, layout, bloom, status, app, link, token. -- Units: km, m, km/h, m/s, kt (knots), ft (feet), h, min, s, always spaced from the number («Terremotos (24 h)», «Missões espaciais (30 d)»); in UPPERCASE text KM, KM/S, KT, FT, MIN, H. "m" is always metres, so minutes are «min» («há 5 min»). MW stays MW. `°` and `%` stay. Decimal comma in written numbers («M4,4»). -- "ago" goes before the time: «há {count} min». When a placeholder already holds a localized "ago" text (`{age}`, `{ago}`), do not add «há» again. +- Units: km, m, km/h, m/s, kt (knots), ft (feet), h, min, s, always spaced from the number («Terremotos (24 h)», «Missões espaciais (30 d)»; in the layer names the space is a no-break space, U+00A0, so the unit never wraps away from the number); in UPPERCASE text KM, KM/S, KT, FT, MIN, H. "m" is always metres, so minutes are «min» («há 5 min»). MW stays MW. `°` and `%` stay. Decimal comma in written numbers («M4,4»). +- "ago" goes before the time: «há {count} min», «mais recente há {value}». When a placeholder already holds a localized "ago" text (`{age}`, `{ago}`), do not add «há» again. - Money: «US$ {amount} mil / mi / bi» for thousands, millions and billions. - Compass points use Leste/Oeste: N, NNE, NE, ENE, L, ESE, SE, SSE, S, SSO, SO, OSO, O, ONO, NO, NNO; hemisphere letters N, S, L, O. @@ -84,6 +84,7 @@ The `many` form is the `other` text with «de» after the number: «{count} de c | Cyber (HUD layout, effect) | Ciber | | heading / course / altitude / ground speed | rumo / curso / altitude / velocidade solo (VELOC. SOLO) | | HDG / BRG / CRS / FOV / DEST / SPD / RANGE | HDG / BRG / CRS / FOV / DEST / SPD / RANGE (unchanged) | +| V/S (vertical speed code) | V/S (unchanged) | | PREV / NEXT | ANT. / PRÓX. | | Previous / Next (button text) | Anterior / Próximo (Próxima) | | L / R (relative bearing) | E / D | @@ -91,4 +92,7 @@ The `many` form is the `other` text with «de» after the number: «{count} de c | REGIONAL NEWS (fits the 16-character kicker) | NOTÍCIAS DA ÁREA | | PITCH / HGT (CCTV calibration chips) | INCL. / ALT. | | NOT AN ALL-CLEAR | NÃO GARANTE SEGURANÇA | +| Last report (transit vehicle position) | Último registro | +| intersection (CCTV) | cruzamento | +| {layers} just turned on (any list of layers) | «{layers}: ativação recente» (no agreement needed) | | turn-by-turn: turn left / keep left / lane | vire à esquerda / mantenha-se à esquerda / faixa da esquerda | diff --git a/scripts/i18n.mjs b/scripts/i18n.mjs index 0ee5d60ec..c035c6bb2 100644 --- a/scripts/i18n.mjs +++ b/scripts/i18n.mjs @@ -125,8 +125,11 @@ export function extractMessages() { const html = readFileSync(path.join(ROOT, file), 'utf8'); for (const [, tag, attrs, text] of html.matchAll(TAG)) { const where = `${file} <${tag}>`; - if (/\sdata-i18n(\s|=|$)/.test(attrs)) - add(normalize(decodeHtml(text)), where); + if (/\sdata-i18n(\s|=|$)/.test(attrs)) { + const context = attrs.match(/\sdata-i18n-context="([^"]*)"/); + const message = normalize(decodeHtml(text)); + add(context ? `${decodeHtml(context[1])}|${message}` : message, where); + } for (const [, name] of attrs.matchAll( /\sdata-i18n-(title|aria-label|placeholder)\b/g, )) { diff --git a/src/i18n/i18n.test.mjs b/src/i18n/i18n.test.mjs index df6b4d000..8f9d50158 100644 --- a/src/i18n/i18n.test.mjs +++ b/src/i18n/i18n.test.mjs @@ -216,6 +216,21 @@ test('applyDocumentTranslations translates opted-in text and attributes in place assert.equal(unknown.textContent, 'No such message'); }); +test('applyDocumentTranslations reads data-i18n-context for element text', () => { + const option = fakeElement({ + text: 'All', + attributes: { 'data-i18n-context': 'radio tag' }, + }); + const doc = { + querySelectorAll: (selector) => + selector === '[data-i18n]' ? [option] : [], + }; + setLocale('pt'); + applyDocumentTranslations(doc); + assert.equal(option.textContent, t('All', { context: 'radio tag' })); + assert.notEqual(option.textContent, t('All')); +}); + test('persistLocaleAndReload keeps the choice in ?lang when storage is blocked', () => { const calls = []; const location = { diff --git a/src/i18n/index.js b/src/i18n/index.js index a6076bbd5..7d17afa03 100644 --- a/src/i18n/index.js +++ b/src/i18n/index.js @@ -228,7 +228,9 @@ function normalizeMarkupText(text) { * Markup opt-in: the element's own English text or attribute is the source. * Normal * - * Also data-i18n-aria-label and data-i18n-placeholder. + * Also data-i18n-aria-label and data-i18n-placeholder. data-i18n-context + * gives the element's text a context, as t(text, { context }) does: + * */ const DOCUMENT_TRANSLATION_TARGETS = Object.freeze([ ['data-i18n', null], @@ -253,7 +255,10 @@ export function applyDocumentTranslations(doc) { ? element.getAttribute(attribute) : normalizeMarkupText(element.textContent); if (!source) continue; - const text = t(source); + const context = attribute + ? null + : element.getAttribute?.('data-i18n-context'); + const text = context ? t(source, { context }) : t(source); if (text === source) continue; if (attribute) element.setAttribute(attribute, text); else element.textContent = text; diff --git a/src/i18n/locales/es.json b/src/i18n/locales/es.json index 3db1ff129..c322665fa 100644 --- a/src/i18n/locales/es.json +++ b/src/i18n/locales/es.json @@ -2227,6 +2227,7 @@ "The Google Maps JavaScript API could not load": "No se pudo cargar la API de Maps JavaScript de Google", "Weather request timed out": "La petición del clima agotó el tiempo de espera", "Cyclone request timed out": "La petición de ciclones agotó el tiempo de espera", + "Malformed cyclone snapshot": "Instantánea de ciclones mal formada", "Malformed weather manifest": "Manifiesto del clima mal formado", "Weather HTTP {status}": "Clima: HTTP {status}", "Weather image HTTP {status}": "Imagen del clima: HTTP {status}", diff --git a/src/i18n/locales/pt.json b/src/i18n/locales/pt.json index 9f2bbe765..fee5d1274 100644 --- a/src/i18n/locales/pt.json +++ b/src/i18n/locales/pt.json @@ -300,12 +300,12 @@ "Source configured; file checked when loaded": "Fonte configurada; o arquivo será verificado ao carregar", "Source unavailable": "Fonte indisponível", "ENVIRONMENTAL": "AMBIENTAL", - "EARTH WATCH": "VIGIA DA TERRA", + "EARTH WATCH": "VIGILÂNCIA DA TERRA", "ACTIVE EVENTS": "EVENTOS ATIVOS", "Starting live contacts…": "Iniciando contatos ao vivo…", "Opening space missions…": "Abrindo missões espaciais…", "Scanning active events…": "Varrendo eventos ativos…", - "Live earthquakes and active fires, from USGS and NASA": "Terremotos e incêndios ativos ao vivo, de USGS e NASA", + "Live earthquakes and active fires, from USGS and NASA": "Terremotos e incêndios ativos ao vivo, do USGS e da NASA", "It feels like a forbidden cockpit—then you realize the sources are public and the data is real.": "Parece uma cabine proibida — até você perceber que as fontes são públicas e os dados são reais.", "Working…": "Processando…", "Could not open that mission{detail}. Retry or explore manually.": "Não foi possível abrir essa missão{detail}. Tente novamente ou explore manualmente.", @@ -376,7 +376,7 @@ "{name} is longer than any real key ({limit} max)": "{name}: o valor é mais longo que qualquer chave real (máximo {limit})", "{name} may only contain printable characters with no spaces": "{name}: só são aceitos caracteres imprimíveis, sem espaços", "{name} contains a character that is not valid in a key (#, quotes, $, \\, or backtick)": "{name}: há um caractere inválido para uma chave (#, aspas, $, \\ ou crase)", - "{name} is configured outside Provider Settings and can only be changed where it was set": "{name} foi configurada fora de Configurações de provedores e só pode ser alterada onde foi definida", + "{name} is configured outside Provider Settings and can only be changed where it was set": "{name} foi configurada fora de \"Configurações de provedores\" e só pode ser alterada onde foi definida", "The key was not saved: could not restrict the credential file to your account; nothing was saved": "A chave não foi salva: não foi possível restringir o arquivo de credenciais à sua conta; nada foi salvo", "The key was not saved: the existing configuration could not be read, so nothing was changed": "A chave não foi salva: não foi possível ler a configuração existente, então nada foi alterado", "Could not write the {store} store": "Não foi possível gravar no armazenamento {store}", @@ -430,7 +430,7 @@ "Live active-fire detections": "Detecções de incêndios ativos ao vivo", "Real live traffic (keyless runs a simulation)": "Trânsito real ao vivo (sem chave, roda uma simulação)", "Bing imagery map stacks + world terrain": "Pilhas de mapas com imagens do Bing + relevo mundial", - "More flight-polling credits (anonymous works without)": "Mais créditos de consulta de voos (o acesso anônimo funciona sem)", + "More flight-polling credits (anonymous works without)": "Mais créditos de consulta de voos (opcional: o acesso anônimo também funciona)", "Street-level imagery and coverage in the Street Level layer. Free: register an app in the Mapillary developer dashboard and paste its Client Token": "Imagens e cobertura no nível da rua na camada \"Nível da rua\". Grátis: registre um app no painel de desenvolvedores do Mapillary e cole o token de cliente (Client Token)", "Public space-missions access needs no key. Leave blank for standard use; paid tokens only raise request limits.": "O acesso público às missões espaciais não precisa de chave. Deixe em branco para o uso padrão; tokens pagos só aumentam os limites de requisições.", "Air quality request failed": "Falha na requisição de qualidade do ar", @@ -716,7 +716,7 @@ "FIRE": "INCÊNDIO", "FIRES": "INCÊNDIOS", "max {value} MW": "máx {value} MW", - "new {value}": "novo {value}", + "new {value}": "mais recente há {value}", "{value}°N": "{value}°N", "{value}°S": "{value}°S", "{value}°E": "{value}°L", @@ -822,7 +822,7 @@ "FLIGHT {count}": "VOO {count}", "REUSED": "REUTILIZADO", "NO STAGE RE-ENTRY / RECOVERY DATA": "SEM DADOS DE REENTRADA / RECUPERAÇÃO DE ESTÁGIO", - "{count} / 30D": "{count} / 30D", + "{count} / 30D": "{count} / 30 D", "NO MISSIONS AVAILABLE IN THE CURRENT 30-DAY WINDOW": "NENHUMA MISSÃO DISPONÍVEL NA JANELA ATUAL DE 30 DIAS", "DATE UNAVAILABLE": "DATA INDISPONÍVEL", "UNSPECIFIED OPERATOR": "OPERADOR NÃO ESPECIFICADO", @@ -881,8 +881,8 @@ "Your RTL-SDR receiver": "Seu receptor RTL-SDR", "NO CALLSIGN": "SEM INDICATIVO", "ALT {altitude} FT · GS {speed} KT · TRK {track}": "ALT {altitude} FT · GS {speed} KT · TRK {track}", - "V/S {rate}": "VEL. VERT. {rate}", - "V/S {rate} FPM": "VEL. VERT. {rate} FT/MIN", + "V/S {rate}": "V/S {rate}", + "V/S {rate} FPM": "V/S {rate} FT/MIN", "POSITION {age}": "POSIÇÃO {age}", "POSITION {seconds} S AGO": "POSIÇÃO HÁ {seconds} S", "{count} MSGS": { @@ -954,8 +954,8 @@ "Traffic / Transit": "Trânsito / Transporte", "Music": "Música", "Other": "Outras", - "Directory refresh degraded; showing the previous station catalog.": "A atualização do diretório foi parcial; mostrando o catálogo de estações anterior.", - "Radio directory coverage is degraded.": "O diretório de rádio está funcionando com falhas.", + "Directory refresh degraded; showing the previous station catalog.": "A atualização do diretório retornou dados degradados; mostrando o catálogo de estações anterior.", + "Radio directory coverage is degraded.": "A cobertura do diretório de rádio está degradada.", "Directory refresh failed; showing the previous station catalog.": "A atualização do diretório falhou; mostrando o catálogo de estações anterior.", "Radio directory is temporarily unavailable.": "O diretório de rádio está temporariamente indisponível.", "radio|NEWS": "NOTÍCIAS", @@ -1069,7 +1069,7 @@ "KartaView sent too much data": "O KartaView enviou dados demais", "KartaView is rate-limiting requests — try again in a moment": "O KartaView está limitando as requisições — tente novamente em instantes", "KartaView has no such photo": "O KartaView não tem essa foto", - "Mapillary rejected MAPILLARY_CLIENT_TOKEN — replace it in Provider Settings": "O Mapillary recusou o MAPILLARY_CLIENT_TOKEN — substitua-o em Configurações de provedores", + "Mapillary rejected MAPILLARY_CLIENT_TOKEN — replace it in Provider Settings": "O Mapillary recusou o MAPILLARY_CLIENT_TOKEN — substitua-o em \"Configurações de provedores\"", "Coverage requests are being rate-limited — they resume on their own": "As requisições de cobertura estão sendo limitadas — elas são retomadas sozinhas", "The Panoramax photo could not be loaded": "Não foi possível carregar a foto do Panoramax", "Panoramax is busy — coverage resumes on its own": "O Panoramax está sobrecarregado — a cobertura volta sozinha", @@ -1120,7 +1120,7 @@ "LIVE · Roads: OpenStreetMap · Flow: TomTom · {percent}% cov": "AO VIVO · Vias: OpenStreetMap · Fluxo: TomTom · {percent}% cob", "SIMULATED · Roads: OpenStreetMap · Flow: TomTom (no matches)": "SIMULADO · Vias: OpenStreetMap · Fluxo: TomTom (sem correspondências)", "SIMULATED — traffic service unreachable": "SIMULADO — serviço de trânsito inacessível", - "SIMULATED — add TomTom key for live": "SIMULADO — adicione a chave TomTom para dados ao vivo", + "SIMULATED — add TomTom key for live": "SIMULADO — adicione a chave do TomTom para dados ao vivo", "OpenFreeMap tiles rate-limited": "Blocos do OpenFreeMap com limite de requisições", "OpenFreeMap tiles timed out": "Os blocos do OpenFreeMap excederam o tempo limite", "OpenFreeMap tiles unavailable": "Blocos do OpenFreeMap indisponíveis", @@ -1140,9 +1140,9 @@ "Moving": "Em movimento", "reported {speed} km/h": "velocidade informada: {speed} km/h", "reported hdg {heading}°": "rumo informado: {heading}°", - "Last report: stopped at stop {stop}": "Último relato: parado no ponto {stop}", - "Last report: arriving at stop {stop}": "Último relato: chegando ao ponto {stop}", - "Last report: next stop {stop}": "Último relato: próximo ponto {stop}", + "Last report: stopped at stop {stop}": "Último registro: parado no ponto {stop}", + "Last report: arriving at stop {stop}": "Último registro: chegando ao ponto {stop}", + "Last report: next stop {stop}": "Último registro: próximo ponto {stop}", "Shown at street level · depth not in the feed": "Exibido no nível da rua · o feed não informa a profundidade", "Reported {seconds} s ago": "Informado há {seconds} s", "Reported {minutes} min ago": "Informado há {minutes} min", @@ -1184,7 +1184,7 @@ "Hidden by this map source · choose a globe map": "Oculto com esta fonte do mapa · escolha um mapa de globo", "Weather image HTTP {status}": "Imagem do clima: HTTP {status}", "Weather HTTP {status}": "Clima: HTTP {status}", - "Frame unavailable; previous observation retained": "Quadro indisponível; a observação anterior foi mantida", + "Frame unavailable; previous observation retained": "Quadro indisponível; mantido o anterior", "Weather imagery unavailable": "Imagens meteorológicas indisponíveis", "Weather source unavailable; previous observation retained": "Fonte meteorológica indisponível; a observação anterior foi mantida", "Weather unavailable": "Clima indisponível", @@ -1259,6 +1259,7 @@ "Malformed weather manifest": "Manifesto do clima malformado", "Weather request timed out": "A requisição do clima excedeu o tempo limite", "Cyclone request timed out": "A requisição de ciclones excedeu o tempo limite", + "Malformed cyclone snapshot": "Snapshot de ciclones malformado", "Temperature field unavailable": "Campo de temperatura indisponível", "Mean sea level pressure field unavailable": "Campo de pressão ao nível do mar indisponível", "Wind upstream unavailable": "Origem dos dados de vento indisponível", @@ -1338,12 +1339,12 @@ "Malformed wind manifest": "Manifesto de vento malformado", "Malformed wind grid": "Grade de vento malformada", "Error: {message}": "Erro: {message}", - "Needs {envVars} — add it in Provider Settings": "Requer {envVars} — adicione em Configurações de provedores", + "Needs {envVars} — add it in Provider Settings": "Requer {envVars} — adicione em \"Configurações de provedores\"", "{label} is unavailable": "{label} indisponível", "This map stack": "Esta pilha de mapas", "{label} unavailable: {hint}": "{label} indisponível: {hint}", "Google 3D tiles unavailable — check the key's API restrictions, quota, or network": "Google 3D Tiles indisponível — verifique as restrições de API da chave, a cota ou a rede", - "Needs {envVars} — add it in Provider Settings — or a Cesium ion token for the ion-hosted route": "Requer {envVars} — adicione em Configurações de provedores — ou um token do Cesium ion para a rota hospedada no ion", + "Needs {envVars} — add it in Provider Settings — or a Cesium ion token for the ion-hosted route": "Requer {envVars} — adicione em \"Configurações de provedores\" — ou um token do Cesium ion para a rota hospedada no ion", "Exit cockpit to fly to a camera": "Saia da cabine para voar até uma câmera", "Exit cockpit to fly to a location": "Saia da cabine para voar até um local", "Exit cockpit to fly to a photo": "Saia da cabine para voar até uma foto", @@ -1384,7 +1385,7 @@ "many": "{count} de planos adicionados: {scene}", "other": "{count} planos adicionados: {scene}" }, - "Cannot capture shot: camera not ready": "Não foi possível capturar o plano: câmera não está pronta", + "Cannot capture shot: camera not ready": "Não foi possível capturar o plano: a câmera não está pronta", "Captured: {scene} / {shot}": "Capturado: {scene} / {shot}", "Select a shot first": "Selecione um plano primeiro", "Updated: {scene} / {shot}": "Atualizado: {scene} / {shot}", @@ -1623,7 +1624,7 @@ "many": "{count} de câmeras carregadas · ative o CCTV para usar", "other": "{count} câmeras carregadas · ative o CCTV para usar" }, - "Enable CCTV to load camera intersections": "Ative o CCTV para carregar interseções de câmeras", + "Enable CCTV to load camera intersections": "Ative o CCTV para carregar os cruzamentos com câmeras", "Enable CCTV to start camera-linked intelligence summaries.": "Ative o CCTV para iniciar resumos de inteligência vinculados às câmeras.", "No summary available.": "Nenhum resumo disponível.", "loading frames": "carregando quadros", @@ -1675,12 +1676,12 @@ "many": "{count} DE ENTRADAS DESCONHECIDAS · NÃO GARANTE SEGURANÇA", "other": "{count} ENTRADAS DESCONHECIDAS · NÃO GARANTE SEGURANÇA" }, - "AVAILABLE INPUTS CURRENT · NOT AN ALL-CLEAR": "ENTRADAS DISPONÍVEIS ATUAIS · NÃO GARANTE SEGURANÇA", + "AVAILABLE INPUTS CURRENT · NOT AN ALL-CLEAR": "ENTRADAS DISPONÍVEIS ATUALIZADAS · NÃO GARANTE SEGURANÇA", "SQUAWK {code} · {status}": "SQUAWK {code} · {status}", "ADS-B PRIORITY · {status}": "PRIORIDADE ADS-B · {status}", "ADS-B EMERGENCY · {status}": "EMERGÊNCIA ADS-B · {status}", "AIRCRAFT": "AERONAVE", - "ACQUIRING SURFACE": "ADQUIRINDO SUPERFÍCIE", + "ACQUIRING SURFACE": "CARREGANDO SUPERFÍCIE", "SURFACE FALLBACK": "SUPERFÍCIE ALTERNATIVA", "STALE FEED": "FEED DESATUALIZADO", "LIVE TRACK": "RASTRO AO VIVO", @@ -1795,9 +1796,9 @@ "{requirement}, or {offer}": "{requirement}, ou {offer}", "Live Flights": "Voos ao vivo", "Military Flights": "Voos militares", - "Earthquakes (24h)": "Terremotos (24 h)", + "Earthquakes (24h)": "Terremotos (24 h)", "Satellites": "Satélites", - "Space Missions (30d)": "Missões espaciais (30 d)", + "Space Missions (30d)": "Missões espaciais (30 d)", "Street Traffic": "Trânsito urbano", "CCTV": "CCTV", "Radio": "Rádio", @@ -1909,7 +1910,7 @@ "📍 Location: --": "📍 Local: --", "Landmark: --": "Ponto de referência: --", "Searched location": "Local pesquisado", - "ORBIT": "ÓRBITA", + "ORBIT": "ORBITANDO", "Location not found": "Local não encontrado", "Check the spelling and press Enter to search again.": "Verifique a grafia e pressione Enter para buscar de novo.", "Search failed": "Falha na busca", @@ -2084,7 +2085,7 @@ "Every day is empty here": "Todos os dias estão vazios aqui", "Sources off": "Fontes desativadas", "VS": "VS", - "Not set": "Não definido", + "Not set": "Sem imagem", "Basemap": "Mapa base", "Source off": "Fonte desativada", "Unpin {slot}": "Desafixar {slot}", @@ -2149,7 +2150,7 @@ "Shared {subject} could not be restored — feed unavailable": "Não foi possível restaurar o compartilhamento de {subject} — feed indisponível", "Shared {subject} is unavailable": "O compartilhamento de {subject} está indisponível", "{id} isn't reporting now — showing where it was last seen": "{id} não está transmitindo agora — mostrando onde foi visto pela última vez", - "{id} isn't reporting now — showing where it was at {time}": "{id} não está transmitindo agora — mostrando onde estava às {time}", + "{id} isn't reporting now — showing where it was at {time}": "{id} não está transmitindo agora — mostrando onde estava em {time}", "This share link can't be opened": "Não é possível abrir este link de compartilhamento", "Shared vessel is unavailable": "A embarcação compartilhada está indisponível", "ACQUIRING": "ADQUIRINDO", @@ -2358,7 +2359,7 @@ "Invalid Gemini connection endpoint": "Endpoint de conexão do Gemini inválido", "Gemini voice could not connect. Try again.": "Não foi possível conectar a voz do Gemini. Tente novamente.", "Gemini voice requires a same-origin app request": "A voz do Gemini exige uma requisição da mesma origem do app", - "Add a Gemini API key in Provider Settings": "Adicione uma chave de API do Gemini em Configurações de provedores", + "Add a Gemini API key in Provider Settings": "Adicione uma chave de API do Gemini em \"Configurações de provedores\"", "The Gemini Live model configuration is invalid": "A configuração do modelo do Gemini Live é inválida", "Gemini voice is starting too often. Try again shortly.": "A voz do Gemini está sendo iniciada com frequência demais. Tente novamente em breve.", "Gemini quota is unavailable. Try again later.": "A cota do Gemini está indisponível. Tente novamente mais tarde.", @@ -2529,7 +2530,7 @@ "{label} error": "{label}: erro", "counted the first {returned} loaded records": "foram contados os primeiros {returned} registros carregados", "counted {returned} of {total} loaded records": "foram contados {returned} de {total} registros carregados", - "{layers} just turned on — still loading, counts will rise": "{layers}: acabou de ser ativado — ainda carregando, as contagens vão subir", + "{layers} just turned on — still loading, counts will rise": "{layers}: ativação recente — ainda carregando, as contagens vão subir", "Contacts panel snapshot at {time} — the same retained cohort supplies the card, speech, and follow-up memory": "Snapshot do painel Contatos ({time}) — o mesmo grupo retido alimenta o cartão, a fala e a memória de acompanhamento", "Contacts panel snapshot — the same retained cohort supplies the card, speech, and follow-up memory": "Snapshot do painel Contatos — o mesmo grupo retido alimenta o cartão, a fala e a memória de acompanhamento", "Fly below {km} km to a covered region": "Desça abaixo de {km} km sobre uma região com cobertura", @@ -2662,7 +2663,7 @@ "Next satellite pass": "Próxima passagem do satélite", "Mark the map": "Marcar o mapa", "Mark {targets} +{more}": "Marcar {targets} +{more}", - "Mark {targets}": "Marcar: {targets}", + "Mark {targets}": "Marcar {targets}", "Fly to {place}": "Voar até {place}", "Fly to Location": "Voar até o local", "Nearest aircraft to {place}": "Aeronave mais próxima de {place}", @@ -2694,7 +2695,7 @@ "Recent speech": "Fala recente", "HERE": "AQUI", "Aircraft cockpit view": "Vista da cabine da aeronave", - "LEVEL": "NÍVEL", + "LEVEL": "NIVELADO", "Estimated destination direction": "Direção estimada do destino", "DEST ---°": "DEST ---°", "OPTICAL PLANE · 01": "PLANO ÓPTICO · 01", @@ -2825,7 +2826,7 @@ "DRAG TO TUNE": "ARRASTE PARA SINTONIZAR", "Tune available internet radio stations": "Sintonizar as estações de rádio pela internet disponíveis", "ALL · DRAG THE NEEDLE": "TODAS · ARRASTE A AGULHA", - "SNAPS TO AVAILABLE STATIONS": "AJUSTA ÀS ESTAÇÕES DISPONÍVEIS", + "SNAPS TO AVAILABLE STATIONS": "AJUSTA-SE ÀS ESTAÇÕES DISPONÍVEIS", "Radio playback": "Reprodução do rádio", "Previous filtered station": "Estação filtrada anterior", "Play selected station": "Reproduzir a estação selecionada", diff --git a/src/i18n/locales/ru.json b/src/i18n/locales/ru.json index 93e2b871d..13182cec1 100644 --- a/src/i18n/locales/ru.json +++ b/src/i18n/locales/ru.json @@ -2263,6 +2263,7 @@ "The Google Maps JavaScript API could not load": "Не удалось загрузить Google Maps JavaScript API", "Weather request timed out": "Истекло время ожидания запроса погоды", "Cyclone request timed out": "Истекло время ожидания запроса циклонов", + "Malformed cyclone snapshot": "Некорректный снимок циклонов", "Malformed weather manifest": "Некорректный манифест погоды", "Weather HTTP {status}": "Погода: HTTP {status}", "Weather image HTTP {status}": "Снимок погоды: HTTP {status}", diff --git a/src/i18n/locales/zh-CN.json b/src/i18n/locales/zh-CN.json index aca16f65a..3d83437b7 100644 --- a/src/i18n/locales/zh-CN.json +++ b/src/i18n/locales/zh-CN.json @@ -1203,6 +1203,7 @@ "Malformed weather manifest": "天气清单格式错误", "Weather request timed out": "天气请求超时", "Cyclone request timed out": "气旋请求超时", + "Malformed cyclone snapshot": "气旋快照格式错误", "Temperature field unavailable": "温度场不可用", "Mean sea level pressure field unavailable": "平均海平面气压场不可用", "Wind upstream unavailable": "风场上游数据源不可用", diff --git a/src/i18n/locales/zh-Hant.json b/src/i18n/locales/zh-Hant.json index 9fe469f6e..9fcab471b 100644 --- a/src/i18n/locales/zh-Hant.json +++ b/src/i18n/locales/zh-Hant.json @@ -1198,6 +1198,7 @@ "Malformed weather manifest": "天氣清單格式錯誤", "Weather request timed out": "天氣請求超時", "Cyclone request timed out": "氣旋請求超時", + "Malformed cyclone snapshot": "氣旋快照格式錯誤", "Temperature field unavailable": "溫度場不可用", "Mean sea level pressure field unavailable": "平均海平面氣壓場不可用", "Wind upstream unavailable": "風場上游數據源不可用", diff --git a/src/i18n/same-as-english.json b/src/i18n/same-as-english.json index 90abbc6a8..678b9a7b6 100644 --- a/src/i18n/same-as-english.json +++ b/src/i18n/same-as-english.json @@ -225,6 +225,7 @@ "Techno", "Trance", "USB {rate} msg/s", + "V/S {rate}", "VISUAL", "VOLUME", "VS", diff --git a/src/layers/cyclones/source.js b/src/layers/cyclones/source.js index e0039a20e..50aa24ad2 100644 --- a/src/layers/cyclones/source.js +++ b/src/layers/cyclones/source.js @@ -1,11 +1,11 @@ import { readResponseJsonCapped } from '../../sources/httpBody.js'; -// Shared with the AI tools, so no i18n import: the timeout stays English here -// and the cyclones layer translates it where it shows it (translateKnown). +// Shared with the AI tools, so no i18n import: these errors stay English here +// and the cyclones layer translates them where it shows them (translateKnown). const msg = (text) => text; export const CYCLONE_RESPONSE_LIMIT = 4 * 1024 * 1024; -const malformed = () => new Error('Malformed cyclone snapshot'); +const malformed = () => new Error(msg('Malformed cyclone snapshot')); const text = (value, max = 160) => { if ( typeof value !== 'string' || diff --git a/src/ui/templates/context.html b/src/ui/templates/context.html index 9e88d20f4..bb1947008 100644 --- a/src/ui/templates/context.html +++ b/src/ui/templates/context.html @@ -122,7 +122,7 @@
From b521f6a1fa06f04c0099ffb469935ba4a8995636 Mon Sep 17 00:00:00 2001 From: German Khokhlov Date: Wed, 28 Oct 2026 18:21:14 +0400 Subject: [PATCH 32/83] i18n(de): apply review round 2 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Meaning fixes: the radio link opens the broadcaster's website (SENDER-WEBSITE), a straight lane is «geradeaus führend», not the middle one, IDLE is INAKTIV (BEREIT is READY), the Gemini errors name the send queue, traffic percent is live coverage (Live-Abdeckung), the voice radius is measured from the Bildmitte, the AIS voice error names the Live-Schiffe layer, and the Bhote landslide is «Erdrutsch» throughout (not «Abbruch»). - Number-neutral status lines for feed and layer lists, and a payload count line that also reads correctly for +1. - Retry wording follows the glossary: «neue Versuche in größeren Abständen». - Weather history lines are shorter and fit the collapsed row: «Frame fehlt; letzter Stand bleibt erhalten», «Kein Frame in den {gap} min bis {time}» (the gap only looks back from the target time). - Shorter search placeholder «Ort suchen...», which was clipped. - Smaller wording: Himmelsring, Lagebild-HUD, SCHLEPPVERBAND, Minimum Fuel (Treibstoff knapp), Bloom / Leuchten, DOWNRANGE GESCHÄTZT, Places-Kontext, MELDUNG, Rückflug zur Weltübersicht, REALE BILDDATEN and others. - Glossary and routing notes updated. Co-Authored-By: Claude Opus 5.5 --- docs/translations/de.md | 125 ++++++++++++++++++++------------------- src/i18n/locales/de.json | 108 ++++++++++++++++----------------- 2 files changed, 118 insertions(+), 115 deletions(-) diff --git a/docs/translations/de.md b/docs/translations/de.md index 7a1984f19..7c1d602cc 100644 --- a/docs/translations/de.md +++ b/docs/translations/de.md @@ -12,14 +12,14 @@ Translation source: abiyeenzo (#908). - Compounds are written as one word or with a hyphen next to a name, code or English term: «Datenebene», «Wetterkacheln», «TomTom-Schlüssel», «AIS-Schiffe», «Street-View-Fallback». Do not split them with spaces. - Short labels, chips and HUD readouts stay short. German runs about a third longer than English, so prefer a short word or a standard abbreviation with a period over a wrapped line: REICHW., GESCHW., NIEDERSCHL., SONST., NACHR., VERST., VGL., KAL. - The avionics codes HDG, BRG, CRS, DEST, SPD, ALT, GS, TRK, V/S, FOV and SQUAWK stay in English, as in the cockpit. Words used in a sentence are translated: heading → «Kurs», bearing → «Peilung», range → «Reichweite». -- A dash between clauses is a spaced en dash « – »; a colon is fine where it explains: «Feed ausgefallen – langsame Wiederholung», «SIMULIERT: Verkehrsdienst nicht erreichbar». Quotes are „…“. +- A dash between clauses is a spaced en dash « – »; a colon is fine where it explains: «Feed ausgefallen – neue Versuche in größeren Abständen», «SIMULIERT: Verkehrsdienst nicht erreichbar». Quotes are „…“. - Status and waiting messages use the neutral infinitive too: «Warten auf Aktualisierung», not «Warte auf …». Reasons inserted after a dash stay lower case: «Szene nicht gespeichert – das Projekt ist größer als 5 MiB». - Keyboard keys are named as on German keyboards where they differ: Leertaste, Rücktaste, Umschalt; Esc, Enter, Tab and letter keys stay. - Decimal comma in fixed text: «M4,4», «28,2710° N». Thousands separator is a period: «1.000 km». Formatted numbers come from `Intl` and are already German. - Units: km, m, km/h, m/s, kn (knots, also in the cockpit), ft (feet), hPa, MW, h, min, s, T (days, in short readouts); in UPPERCASE text KM, KM/H, KN, FT, MIN. A space between number and unit, in compact readouts too: «{value} m», «{count} min», «50 %», «{speed} KN», «{count} / 30 T». `°` sticks to the number. - "ago" goes before the time: «vor {count} min», «vor {value}». When a placeholder already holds a localized "ago" text (`{age}` in `STALE · cached {age}`, `{ago}`), do not add «vor» again. - Compass points use O for Ost: N, NNO, NO, ONO, O, OSO, SO, SSO, S, SSW, SW, WSW, W, WNW, NW, NNW; hemisphere letters N, S, O, W. -- Routing: direction words are lowercase adverbs (links, leicht rechts, scharf links, geradeaus), so a sentence never starts with one: «Auf {road} {direction} abbiegen», «Dann {direction} abbiegen», «Weiter {direction}». Roundabout exits are ordinals with a period: «die {exit} Ausfahrt» → «die 2. Ausfahrt». +- Routing: direction words are lowercase adverbs (links, leicht rechts, scharf links, geradeaus), so a sentence never starts with one: «Auf {road} {direction} abbiegen», «Dann {direction} abbiegen», «Weiter {direction}». Roundabout exits are ordinals with a period: «die {exit} Ausfahrt» → «die 2. Ausfahrt». A straight lane is the one that leads straight on, not the middle one: «Die geradeaus führende Spur benutzen». ## Plurals @@ -34,62 +34,65 @@ Keep the verb in agreement: «{count} Station meldet» / «{count} Stationen mel ## Glossary -| English | Deutsch | -| ---------------------------------------------- | -------------------------------------------------------------------- | -| layer / data layer | Ebene / Datenebene | -| feed / source / data source / input (cockpit) | Feed / Quelle / Datenquelle / Quelle | -| LIVE (status) / live data | LIVE / Live-Daten | -| SIMULATED | SIMULIERT | -| stale / degraded / unavailable | veraltet / eingeschränkt / nicht verfügbar | -| retry / retrying | neuer Versuch / erneut versuchen | -| fallback | Fallback | -| key (API key) / POWER UP / POWERED UP | Schlüssel / STARTKLAR / HOCHGEFAHREN | -| Provider Settings | Anbieter-Einstellungen | -| ON / OFF (state chips) | EIN / AUS | -| enable / disable | aktivieren / deaktivieren | -| globe / map / map source / map stack / basemap | Globus / Karte / Kartenquelle / Kartenstapel / Basiskarte | -| aircraft / flight / military flights | Luftfahrzeug (HUD and short labels: Flugzeug) / Flug / Militärflüge | -| vessel, ship | Schiff | -| satellite / shell (Starlink) / DENSE | Satellit / Schale / DICHT | -| launch (rocket) / launch site / space mission | Start / Startplatz / Raummission | -| ascent / replay / payload / stage / downrange | Aufstieg / Replay, Wiedergabe / Nutzlast / Stufe / Downrange | -| contact / tracking | Kontakt / Verfolgung | -| installation / site | Anlage / Standort | -| mapped / observed | kartiert / beobachtet | -| camera / CCTV camera / camera badge | Kamera / CCTV-Kamera / Kamera-Markierung | -| earthquake / active fire / fire perimeter | Erdbeben / aktiver Brand / Brandgrenze | -| cyclone / advisory (NHC/CPHC) / cone | Wirbelsturm / Lagebericht (not «Warnung») / Kegel | -| radio station | Sender | -| broadcast FM | UKW | -| road / flow (traffic) | Straße / Verkehrsfluss | -| transit / bike share | ÖPNV / Bikesharing | -| scene / shot / scene recipe | Szene / Aufnahme / Szenenrezept | -| capture shot / camera move | Aufnahme speichern / Kameraflug | -| anchor / data pack / bundle | Anker / Datenpaket / Bundle | -| story beat / evidence beat | Story-Schritt / Beweisschritt | -| briefing / panel / dock | Briefing / Bereich / Dock | -| cockpit | Cockpit | -| preset / visual preset | Preset / visuelles Preset | -| Scope (circular viewport mask) / keyhole | Scope / Schlüsselloch | -| feather / fade | Weichzeichnung / Ausblenden | -| overlay / detection overlay | Overlay / Erkennungs-Overlay | -| Clean UI | Reine Ansicht | -| Night vision / Thermal / Snow (cockpit styles) | Nachtsicht / Wärmebild / Schnee | -| heading / altitude / ground speed | Kurs / Höhe / Geschwindigkeit über Grund (short: GESCHW. ÜBER GRUND) | -| HDG / BRG / CRS / DEST / SPD / FOV | unchanged | -| RANGE / PITCH / HGT (CCTV calibration chips) | REICHW. / NEIGUNG / HÖHE | -| PREV / NEXT | ZURÜCK / WEITER | -| L / R (relative bearing) | L / R | -| SIG / NEWS / LOCAL (briefing tabs) | SIG / NEWS / LOKAL | -| NOT AN ALL-CLEAR | KEINE ENTWARNUNG | -| Street Level / Street View (Google) | Straßenebene / Street View | -| Recent Imagery / box / pin (a day) | Aktuelle Bilddaten / Bereich / fixieren | -| frame (bring into view) | ins Bild nehmen | -| mark (map annotation) / outline | Markierung / Umriss | -| voice (control) / voice session | Sprachsteuerung / Sprachsitzung | -| YOU / THIS / HERE (voice card labels) | EINGABE / DIES / HIER | -| click / click to … | anklicken / … klicken | -| card (host card) / voice card | Eintrag (in hints), Infokarte / Sprachkarte | -| label (on the map) / clear (switch off layers) | Beschriftung / ausschalten (not «löschen») | -| station tag (radio filter) | Kategorie | -| MIC (dock button) | MIKRO | +| English | Deutsch | +| ---------------------------------------------- | ---------------------------------------------------------------------- | +| layer / data layer | Ebene / Datenebene | +| feed / source / data source / input (cockpit) | Feed / Quelle / Datenquelle / Quelle | +| LIVE (status) / live data | LIVE / Live-Daten | +| SIMULATED | SIMULIERT | +| stale / degraded / unavailable | veraltet / eingeschränkt / nicht verfügbar | +| retry / retrying / retrying slowly | neuer Versuch / erneut versuchen / neue Versuche in größeren Abständen | +| fallback | Fallback | +| key (API key) / POWER UP / POWERED UP | Schlüssel / STARTKLAR / HOCHGEFAHREN | +| Provider Settings | Anbieter-Einstellungen | +| ON / OFF (state chips) | EIN / AUS | +| enable / disable | aktivieren / deaktivieren | +| globe / map / map source / map stack / basemap | Globus / Karte / Kartenquelle / Kartenstapel / Basiskarte | +| aircraft / flight / military flights | Luftfahrzeug (HUD and short labels: Flugzeug) / Flug / Militärflüge | +| vessel, ship | Schiff | +| satellite / shell (Starlink) / DENSE | Satellit / Schale / DICHT | +| launch (rocket) / launch site / space mission | Start / Startplatz / Raummission | +| ascent / replay / payload / stage / downrange | Aufstieg / Replay, Wiedergabe / Nutzlast / Stufe / Downrange | +| contact / tracking | Kontakt / Verfolgung | +| installation / site | Anlage / Standort | +| mapped / observed | kartiert / beobachtet (Bhote chip OBSERVED IMAGERY: REALE BILDDATEN) | +| camera / CCTV camera / camera badge | Kamera / CCTV-Kamera / Kamera-Markierung | +| earthquake / active fire / fire perimeter | Erdbeben / aktiver Brand / Brandgrenze | +| cyclone / advisory (NHC/CPHC) / cone | Wirbelsturm / Lagebericht (not «Warnung») / Kegel | +| radio station | Sender | +| broadcast FM | UKW | +| road / flow (traffic) / flow coverage | Straße / Verkehrsfluss / Live-Abdeckung | +| transit / bike share | ÖPNV / Bikesharing | +| scene / shot / scene recipe | Szene / Aufnahme / Szenenrezept | +| capture shot / camera move | Aufnahme speichern / Kameraflug | +| anchor / data pack / bundle | Anker / Datenpaket / Bundle | +| story beat / evidence beat | Story-Schritt / Beweisschritt | +| briefing / panel / dock | Briefing / Bereich / Dock | +| cockpit | Cockpit | +| preset / visual preset | Preset / visuelles Preset | +| Scope (circular viewport mask) / keyhole | Scope / Schlüsselloch | +| feather / fade | Weichzeichnung / Ausblenden | +| overlay / detection overlay | Overlay / Erkennungs-Overlay | +| Clean UI | Reine Ansicht | +| Night vision / Thermal / Snow (cockpit styles) | Nachtsicht / Wärmebild / Schnee | +| heading / altitude / ground speed | Kurs / Höhe / Geschwindigkeit über Grund (short: GESCHW. ÜBER GRUND) | +| HDG / BRG / CRS / DEST / SPD / FOV | unchanged | +| RANGE / PITCH / HGT (CCTV calibration chips) | REICHW. / NEIGUNG / HÖHE | +| PREV / NEXT | ZURÜCK / WEITER | +| L / R (relative bearing) | L / R | +| SIG / NEWS / LOCAL (briefing tabs) | SIG / NEWS / LOKAL | +| NOT AN ALL-CLEAR | KEINE ENTWARNUNG | +| Street Level / Street View (Google) | Straßenebene / Street View | +| Recent Imagery / box / pin (a day) | Aktuelle Bilddaten / Bereich / fixieren | +| frame (bring into view) | ins Bild nehmen | +| mark (map annotation) / outline | Markierung / Umriss | +| voice (control) / voice session | Sprachsteuerung / Sprachsitzung | +| YOU / THIS / HERE (voice card labels) | EINGABE / DIES / HIER | +| click / click to … | anklicken / … klicken | +| card (host card) / voice card | Eintrag (in hints), Infokarte / Sprachkarte | +| label (on the map) / clear (switch off layers) | Beschriftung / ausschalten (not «löschen») | +| station tag (radio filter) | Kategorie | +| MIC (dock button) | MIKRO | +| frame (weather, video) / image | Frame / Bild | +| collapse / landslide (Bhote Koshi) | Erdrutsch (not «Abbruch», which reads as "cancel") | +| website (radio station) | Website (SENDER-WEBSITE; «Standort» is a physical site) | diff --git a/src/i18n/locales/de.json b/src/i18n/locales/de.json index 6b9800310..ef333f5d2 100644 --- a/src/i18n/locales/de.json +++ b/src/i18n/locales/de.json @@ -36,7 +36,7 @@ "COMMS": "KOMM", "Broadband constellation shell — shown only in DENSE mode": "Breitband-Konstellationsschale: nur im Modus DICHT sichtbar", "FISHING": "FISCHEREI", - "TOWING": "SCHLEPPEN", + "TOWING": "SCHLEPPVERBAND", "DREDGER": "BAGGER", "DIVE OPS": "TAUCHEINSATZ", "MILITARY": "MILITÄR", @@ -94,11 +94,11 @@ "Saved to {store}. Restarting — this page reloads itself.": "In {store} gespeichert. Neustart läuft, diese Seite lädt sich selbst neu.", "Remove this key from your saved configuration?": "Diesen Schlüssel aus der gespeicherten Konfiguration entfernen?", "Removed from {store}. Restarting — this page reloads itself.": "Aus {store} entfernt. Neustart läuft, diese Seite lädt sich selbst neu.", - "Places context + Street View fallback; optional separate key": "Orts-Kontext + Street-View-Fallback; optional eigener Schlüssel", + "Places context + Street View fallback; optional separate key": "Places-Kontext + Street-View-Fallback; optional eigener Schlüssel", "Live ships, worldwide": "Live-Schiffe, weltweit", "Live active-fire detections": "Live-Erkennung aktiver Brände", "Real live traffic (keyless runs a simulation)": "Echter Live-Verkehr (ohne Schlüssel: Simulation)", - "Bing imagery map stacks + world terrain": "Bing-Bildmaterial als Kartenstapel + Weltgelände", + "Bing imagery map stacks + world terrain": "Bing-Bildmaterial als Kartenstapel + globales Geländemodell", "More flight-polling credits (anonymous works without)": "Mehr Abfrage-Credits für Flüge (anonym geht es auch ohne)", "CONTEXT READY": "KONTEXT BEREIT", "GLOBAL CONTEXT OFF": "GLOBALER KONTEXT AUS", @@ -178,7 +178,7 @@ "ORBIT REPLAY · {mission}": "ORBIT-REPLAY · {mission}", "PAUSED · {title}": "PAUSIERT · {title}", "UNSPECIFIED": "NICHT ANGEGEBEN", - "+{count} additional payload records": "+{count} weitere Nutzlast-Einträge", + "+{count} additional payload records": "Weitere Nutzlast-Einträge: +{count}", "PAYLOAD DATA UNAVAILABLE": "NUTZLASTDATEN NICHT VERFÜGBAR", "{value} KM DOWNRANGE": "{value} KM DOWNRANGE", "POSITION UNAVAILABLE": "POSITION NICHT VERFÜGBAR", @@ -220,7 +220,7 @@ "SHOW ALL / DESELECT": "ALLE ZEIGEN / ABWÄHLEN", "Pause replay": "Wiedergabe pausieren", "Cancel replay": "Wiedergabe abbrechen", - "EST. DOWNRANGE": "GESCH. DOWNRANGE", + "EST. DOWNRANGE": "DOWNRANGE GESCHÄTZT", "PLANNED · ": "GEPLANT · ", "SUPPLIED TRAJECTORY POINTS": "GELIEFERTE BAHNPUNKTE", "RECONSTRUCTED ESTIMATE": "REKONSTRUIERTE SCHÄTZUNG", @@ -276,7 +276,7 @@ "World": "Weltmusik", "Add the full Starlink broadband shell (thousands of extra points)": "Komplette Starlink-Breitbandschale hinzufügen (Tausende zusätzliche Punkte)", "Loading the Starlink shell…": "Starlink-Schale wird geladen…", - "Starlink {detail} — click to retry": "Starlink {detail}: zum erneuten Versuch klicken", + "Starlink {detail} — click to retry": "Starlink: {detail} – zum erneuten Versuch klicken", "load failed": "Laden fehlgeschlagen", "Showing the full Starlink shell — click for the core catalog only": "Komplette Starlink-Schale sichtbar: klicken, um nur den Kernkatalog zu zeigen", "DENSE ···": "DICHT ···", @@ -285,12 +285,12 @@ "Syncing flow · Roads: {source}": "Verkehrsfluss wird synchronisiert · Straßen: {source}", "LIVE · Roads: {source} · Roads without flow hidden": "LIVE · Straßen: {source} · Straßen ohne Verkehrsdaten ausgeblendet", "LIVE · Roads: {source} · No flow roads in view": "LIVE · Straßen: {source} · Keine Straßen mit Verkehrsdaten im Bild", - "LIVE · Roads: {source} · Flow {percent}%": "LIVE · Straßen: {source} · Verkehr {percent} %", - "SIMULATED · Roads: {source} · Flow {percent}%": "SIMULIERT · Straßen: {source} · Verkehr {percent} %", - "Syncing flow · Roads: OpenStreetMap · Flow: TomTom · Unmatched: simulated": "Verkehrsfluss wird synchronisiert · Straßen: OpenStreetMap · Verkehr: TomTom · Ohne Zuordnung: simuliert", - "LIVE · Roads: OpenStreetMap · Flow: TomTom · {percent}% cov · Unmatched: simulated": "LIVE · Straßen: OpenStreetMap · Verkehr: TomTom · {percent} % Abd. · Ohne Zuordnung: simuliert", - "LIVE · Roads: OpenStreetMap · Flow: TomTom · {percent}% cov": "LIVE · Straßen: OpenStreetMap · Verkehr: TomTom · {percent} % Abd.", - "SIMULATED · Roads: OpenStreetMap · Flow: TomTom (no matches)": "SIMULIERT · Straßen: OpenStreetMap · Verkehr: TomTom (keine Treffer)", + "LIVE · Roads: {source} · Flow {percent}%": "LIVE · Straßen: {source} · Live-Abdeckung {percent} %", + "SIMULATED · Roads: {source} · Flow {percent}%": "SIMULIERT · Straßen: {source} · Live-Abdeckung {percent} %", + "Syncing flow · Roads: OpenStreetMap · Flow: TomTom · Unmatched: simulated": "Verkehrsfluss wird synchronisiert · Straßen: OpenStreetMap · Verkehrsfluss: TomTom · Ohne Zuordnung: simuliert", + "LIVE · Roads: OpenStreetMap · Flow: TomTom · {percent}% cov · Unmatched: simulated": "LIVE · Straßen: OpenStreetMap · Verkehrsfluss: TomTom · {percent} % Abd. · Ohne Zuordnung: simuliert", + "LIVE · Roads: OpenStreetMap · Flow: TomTom · {percent}% cov": "LIVE · Straßen: OpenStreetMap · Verkehrsfluss: TomTom · {percent} % Abd.", + "SIMULATED · Roads: OpenStreetMap · Flow: TomTom (no matches)": "SIMULIERT · Straßen: OpenStreetMap · Verkehrsfluss: TomTom (keine Treffer)", "SIMULATED — traffic service unreachable": "SIMULIERT: Verkehrsdienst nicht erreichbar", "SIMULATED — add TomTom key for live": "SIMULIERT: TomTom-Schlüssel für Live-Daten hinzufügen", "AIS: {name}": "AIS: {name}", @@ -325,7 +325,7 @@ "Orbital Watch": "Orbitalwache", "Thermal Threat Board": "Thermische Bedrohungslage", "City Overload": "Stadt-Überlast", - "Omniscience Pullback": "Allwissenheits-Rückzug", + "Omniscience Pullback": "Rückflug zur Weltübersicht", "Shot {n}": "Aufnahme {n}", "Density": "Dichte", "Bloom": "Bloom", @@ -748,7 +748,7 @@ "Keep location tray open": "Standortleiste geöffnet lassen", "Search any location": "Beliebigen Ort suchen", "Search location by name or coordinates": "Ort nach Name oder Koordinaten suchen", - "Search any location...": "Beliebigen Ort suchen...", + "Search any location...": "Ort suchen...", "WEATHER": "WETTER", "CONTEXT": "KONTEXT", "Compact Radio controls": "Kompakte Radio-Steuerung", @@ -780,7 +780,7 @@ "Enable Radio, then choose a globe marker or use next.": "Radio aktivieren, dann einen Globus-Marker wählen oder Weiter nutzen.", "DRAG TO TUNE": "ZUM ABSTIMMEN ZIEHEN", "ALL · DRAG THE NEEDLE": "ALLE · NADEL ZIEHEN", - "SNAPS TO AVAILABLE STATIONS": "RASTET AUF VERFÜGBARE SENDER EIN", + "SNAPS TO AVAILABLE STATIONS": "RASTET BEI VERFÜGBAREN SENDERN EIN", "Radio playback": "Radiowiedergabe", "Previous filtered station": "Vorheriger gefilterter Sender", "Play selected station": "Gewählten Sender abspielen", @@ -788,9 +788,9 @@ "STOP": "STOPP", "Stop radio playback": "Radiowiedergabe stoppen", "Radio volume": "Radio-Lautstärke", - "STATION SITE": "SENDERSTANDORT", + "STATION SITE": "SENDER-WEBSITE", "Audio connects directly to the broadcaster after you press play. Your IP is visible to that broadcaster.": "Beim Starten der Wiedergabe wird eine direkte Verbindung zum Sender hergestellt. Die IP-Adresse ist für diesen Sender sichtbar.", - "Intelligence HUD (H)": "Intelligence-HUD (H)", + "Intelligence HUD (H)": "Lagebild-HUD (H)", "Layout": "Layout", "HUD layout": "HUD-Layout", "Tactical": "Taktisch", @@ -819,10 +819,10 @@ "Feather": "Weichzeichnung", "Scope edge feather": "Weichzeichnung des Scope-Rands", "Scope edge feather as a percentage of the keyhole radius": "Weichzeichnung des Scope-Rands in Prozent des Schlüsselloch-Radius", - "Celestial": "Himmel", + "Celestial": "Himmelsring", "Hide UI chrome": "Oberfläche ausblenden", "Clean UI": "Reine Ansicht", - "Bloom / Glow": "Bloom / Glühen", + "Bloom / Glow": "Bloom / Leuchten", "Bloom intensity": "Bloom-Stärke", "Sharpening": "Schärfen", "Sharpen": "Schärfen", @@ -915,7 +915,7 @@ "Unlawful interference": "Widerrechtlicher Eingriff", "Radio failure": "Funkausfall", "Downed aircraft": "Abgestürztes Luftfahrzeug", - "Minimum fuel": "Mindesttreibstoff", + "Minimum fuel": "Minimum Fuel (Treibstoff knapp)", "Lifeguard (medical priority)": "Lifeguard (medizinische Priorität)", "Rasuwagadhi witness video": "Augenzeugenvideo Rasuwagadhi", "Bhote Koshi valley footage": "Aufnahmen aus dem Bhote-Koshi-Tal", @@ -926,8 +926,8 @@ "REFERENCE ONLY · CLAIMS UNVERIFIED": "NUR REFERENZ · ANGABEN UNBESTÄTIGT", "SOURCE GEOCONFIRMED": "QUELLE GEOVERIFIZIERT", "2021 historical reference versus 2026 post-event imagery; changes are cumulative and include the July 2025 Rasuwagadhi flood. Schematic downstream progression, not modeled arrival time; not an official hazard model.": "Historische Referenz von 2021 gegenüber Bildern nach dem Ereignis von 2026; die Veränderungen sind kumulativ und umfassen die Rasuwagadhi-Flut vom Juli 2025. Schematischer Verlauf flussabwärts, keine modellierte Ankunftszeit; kein offizielles Gefahrenmodell.", - "Immediate collapse viewpoint": "Blickpunkt direkt am Abbruch", - "Collapse viewpoint": "Blickpunkt Abbruch", + "Immediate collapse viewpoint": "Blickpunkt direkt am Erdrutsch", + "Collapse viewpoint": "Blickpunkt Erdrutsch", "Debris-dammed lake": "Durch Geröll aufgestauter See", "Dammed lake": "Aufgestauter See", "Second landslide": "Zweiter Erdrutsch", @@ -991,7 +991,7 @@ "EVENT RECONSTRUCTION · 26 AUG 2026": "REKONSTRUKTION DES EREIGNISSES · 26. AUG. 2026", "BHOTE KOSHI OUTBURST FLOOD": "AUSBRUCHSFLUT BHOTE KOSHI", "Close event layer": "Ereignisebene schließen", - "OBSERVED IMAGERY": "BEOBACHTETE BILDER", + "OBSERVED IMAGERY": "REALE BILDDATEN", "SCHEMATIC CORRIDOR": "SCHEMATISCHER KORRIDOR", "2021 HISTORICAL REFERENCE / 2026 POST-EVENT": "HISTORISCHE REFERENZ 2021 / NACH DEM EREIGNIS 2026", "Historical reference and post-event image split": "Bildvergleich: historische Referenz und nach dem Ereignis", @@ -1064,8 +1064,8 @@ "Animate the sourced cyan river-centerline route to Trishuli Bazaar": "Die belegte cyanfarbene Flussmittellinie bis Trishuli Bazaar animieren", "OVERVIEW": "ÜBERSICHT", "Keep the completed flood path and location labels visible": "Fertigen Flutpfad und Ortsnamen sichtbar lassen", - "RECORD": "AUFZEICHNUNG", - "Reveal the trigger record while making a slow camera approach": "Auslöser-Aufzeichnung zeigen, während die Kamera sich langsam nähert", + "RECORD": "MELDUNG", + "Reveal the trigger record while making a slow camera approach": "USGS-Meldung zum auslösenden Ereignis zeigen, während sich die Kamera langsam nähert", "{speed} kn": "{speed} kn", "That file is not valid JSON.": "Diese Datei ist kein gültiges JSON.", "That JSON file is not GeoJSON.": "Diese JSON-Datei ist kein GeoJSON.", @@ -1336,7 +1336,7 @@ "lane direction|slightly right": "halbrechte", "lane direction|sharply left": "äußerst linke", "lane direction|sharply right": "äußerst rechte", - "lane direction|straight": "mittlere", + "lane direction|straight": "geradeaus führende", "ordinal|{number}st": "{number}.", "ordinal|{number}nd": "{number}.", "ordinal|{number}rd": "{number}.", @@ -1643,7 +1643,7 @@ "KartaView is rate-limiting requests — they resume on their own": "KartaView begrenzt die Anfragen – sie laufen von selbst weiter", "KartaView’s photos here are archived and cannot be shown": "Die KartaView-Fotos hier sind archiviert und können nicht angezeigt werden", "KartaView did not filter this area in time — move the map to ask again": "KartaView hat dieses Gebiet nicht rechtzeitig gefiltert – Karte verschieben, um erneut anzufragen", - "None of KartaView’s photos here pass the imagery filter": "Keines der KartaView-Fotos hier besteht den Bildfilter", + "None of KartaView’s photos here pass the imagery filter": "Keines der KartaView-Fotos hier passt zum Bildfilter", "KartaView did not answer in time — try again": "KartaView hat nicht rechtzeitig geantwortet – erneut versuchen", "KartaView could not be reached — check the network": "KartaView ist nicht erreichbar – Netzwerk prüfen", "KartaView sent an answer that could not be read": "KartaView hat eine unlesbare Antwort gesendet", @@ -1739,20 +1739,20 @@ "API key rejected — check AISSTREAM_API_KEY": "API-Schlüssel abgelehnt – AISSTREAM_API_KEY prüfen", "feed silent {seconds}s — no AIS data": "Feed stumm seit {seconds} s – keine AIS-Daten", "feed silent — no AIS data": "Feed stumm – keine AIS-Daten", - "feed down — retrying slowly (attempt {attempt})": "Feed ausgefallen – langsame Wiederholung (Versuch {attempt})", + "feed down — retrying slowly (attempt {attempt})": "Feed ausgefallen – neue Versuche in größeren Abständen (Versuch {attempt})", "reconnecting to feed… (attempt {attempt})": "Verbindung zum Feed wird wiederhergestellt… (Versuch {attempt})", - "feed down — retrying slowly": "Feed ausgefallen – langsame Wiederholung", + "feed down — retrying slowly": "Feed ausgefallen – neue Versuche in größeren Abständen", "reconnecting to feed…": "Verbindung zum Feed wird wiederhergestellt…", "Focus vessel {name}, MMSI {mmsi}": "Schiff {name} fokussieren, MMSI {mmsi}", "Hidden by this map source · choose a globe map": "Von dieser Kartenquelle ausgeblendet · eine Globuskarte wählen", "Weather image HTTP {status}": "Wetterbild HTTP {status}", "Weather HTTP {status}": "Wetter HTTP {status}", - "Frame unavailable; previous observation retained": "Frame nicht verfügbar; vorherige Beobachtung bleibt erhalten", + "Frame unavailable; previous observation retained": "Frame fehlt; letzter Stand bleibt erhalten", "Weather imagery unavailable": "Wetterbilder nicht verfügbar", "Weather source unavailable; previous observation retained": "Wetterquelle nicht verfügbar; vorherige Beobachtung bleibt erhalten", "Weather unavailable": "Wetter nicht verfügbar", - "No frame within {gap} min of {time}": "Kein Frame innerhalb von {gap} min um {time}", - "No frame within {gap} h of {time}": "Kein Frame innerhalb von {gap} h um {time}", + "No frame within {gap} min of {time}": "Kein Frame in den {gap} min bis {time}", + "No frame within {gap} h of {time}": "Kein Frame in den {gap} h bis {time}", "{hours}h {minutes}m ago": "vor {hours} h {minutes} min", "{minutes}m ago": "vor {minutes} min", "{state} · {time} · {lag}": "{state} · {time} · {lag}", @@ -1961,7 +1961,7 @@ "Bhote Koshi Flood Path": "Bhote Koshi: Flutpfad", "Bhote Koshi Corridor Overview": "Bhote Koshi: Korridor im Überblick", "Bhote Koshi Upper Valley": "Bhote Koshi: oberes Tal", - "Upper Valley Collapse": "Abbruch im oberen Tal", + "Upper Valley Collapse": "Erdrutsch im oberen Tal", "Debris-Dammed Lake": "Durch Geröll aufgestauter See", "Nepal-China Border Gate": "Grenzübergang Nepal–China", "Timure Evidence Cluster": "Beweiscluster Timure", @@ -2001,12 +2001,12 @@ "Edit scene details": "Szenendetails bearbeiten", "Camera positions use degrees and meters above the ellipsoid. Drafts are validated before they replace your saved scene.": "Kamerapositionen verwenden Grad und Meter über dem Ellipsoid. Entwürfe werden geprüft, bevor sie die gespeicherte Szene ersetzen.", "Anchors and data packs": "Anker und Datenpakete", - "Shot camera, timing, packs and actions": "Aufnahmekamera, Timing, Pakete und Aktionen", + "Shot camera, timing, packs and actions": "Aufnahme: Kamera, Zeitablauf, Datenpakete und Aktionen", "New anchor ID": "Neue Anker-ID", "Capture camera as anchor": "Kamera als Anker erfassen", "Anchor added to draft": "Anker zum Entwurf hinzugefügt", "Set move start to current camera": "Startpunkt des Flugs auf aktuelle Kamera setzen", - "Move added to draft; destination remains the shot camera": "Flug zum Entwurf hinzugefügt; das Ziel bleibt die Aufnahmekamera", + "Move added to draft; destination remains the shot camera": "Flug zum Entwurf hinzugefügt; das Ziel bleibt die Kameraposition der Aufnahme", "Use ordinary flight": "Normalen Flug verwenden", "Invalid shot JSON": "Ungültiges Aufnahme-JSON", "Apply details": "Details anwenden", @@ -2036,7 +2036,7 @@ "Browser audio is suspended; press Connect again to resume it": "Browser-Audio ist angehalten; erneut auf Verbinden drücken, um es fortzusetzen", "RTL-SDR sample stream stopped": "RTL-SDR-Sample-Stream gestoppt", "Switching to {mode}…": "Wechsel zu {mode}…", - "Browser audio is suspended; select FM again to resume it": "Browser-Audio ist angehalten; erneut UKW wählen, um es fortzusetzen", + "Browser audio is suspended; select FM again to resume it": "Browser-Audio ist angehalten; erneut FM wählen, um es fortzusetzen", "RTL-SDR gain change failed": "Verstärkung des RTL-SDR konnte nicht geändert werden", "Tuned to {mhz} MHz FM": "Abgestimmt auf {mhz} MHz UKW", "Seeking up…": "Suchlauf aufwärts…", @@ -2180,8 +2180,8 @@ "status chip|UNAVAILABLE": "NICHT VERFÜGBAR", "Data source unavailable": "Datenquelle nicht verfügbar", "Local FM stopped: internet radio started": "Lokales UKW gestoppt: Internetradio gestartet", - "IDLE": "BEREIT", - "TUNING": "ABSTIMMUNG", + "IDLE": "INAKTIV", + "TUNING": "STIMMT AB", "STREAMING": "STREAMT", "UNSUPPORTED": "NICHT UNTERSTÜTZT", "idle": "inaktiv", @@ -2301,7 +2301,7 @@ "SWAP": "TAUSCHEN", "Trade the two sides of the divider": "Die beiden Seiten der Trennlinie tauschen", "SELECT BOX": "BEREICH WÄHLEN", - "Drag a box on the map (Esc cancels)": "Einen Bereich auf die Karte ziehen (Esc bricht ab)", + "Drag a box on the map (Esc cancels)": "Auf der Karte einen Bereich aufziehen (Esc bricht ab)", "USE VIEW": "ANSICHT NUTZEN", "Use the current view as the box": "Die aktuelle Ansicht als Bereich verwenden", "Forget the box and its images": "Bereich und Bilder verwerfen", @@ -2318,7 +2318,7 @@ "start here": "hier starten", "No box": "Kein Bereich", "Searching": "Suche läuft", - "Every day is empty here": "Hier ist jeder Tag leer", + "Every day is empty here": "Keine Bilddaten an den geprüften Tagen", "Sources off": "Quellen aus", "VS": "VGL.", "Not set": "Nicht gesetzt", @@ -2340,7 +2340,7 @@ "Times, coverage, sources": "Zeiten, Abdeckung, Quellen", "HIDE EMPTY DAYS": "LEERE TAGE AUSBLENDEN", "SHOW EMPTY DAYS · {count}": "LEERE TAGE ZEIGEN · {count}", - "Days the probe found empty in this box": "Tage, die die Abfrage in diesem Bereich leer fand", + "Days the probe found empty in this box": "Tage, für die die Abfrage in diesem Bereich keine Bilddaten fand", "image": "Bild", "BASEMAP": "BASISKARTE", "The basemap": "Die Basiskarte", @@ -2425,7 +2425,7 @@ "one": "Feed {names} ungültig", "other": "Feeds {names} ungültig" }, - "Loading {feeds}": "{feeds} wird geladen", + "Loading {feeds}": "Wird geladen: {feeds}", "{count} heard": { "one": "{count} empfangen", "other": "{count} empfangen" @@ -2470,8 +2470,8 @@ "Every provider is switched off: light a chip to draw its coverage.": "Alle Anbieter sind ausgeschaltet: einen Chip einschalten, um seine Abdeckung zu zeichnen.", "Loading this sequence…": "Diese Sequenz wird geladen…", "{n} images in this sequence · Esc clears": { - "one": "{n} Bild in dieser Sequenz · Esc leert", - "other": "{n} Bilder in dieser Sequenz · Esc leert" + "one": "{n} Bild in dieser Sequenz · Esc hebt die Auswahl auf", + "other": "{n} Bilder in dieser Sequenz · Esc hebt die Auswahl auf" }, "No sequences in view match the filter": "Keine Sequenzen im Bild passen zum Filter", "No coverage in view": "Keine Abdeckung im Bild", @@ -2551,8 +2551,8 @@ "Token request is too large": "Token-Anfrage ist zu groß", "Use an empty JSON token request": "Eine leere JSON-Token-Anfrage verwenden", "Voice command context is too large": "Kontext des Sprachbefehls ist zu groß", - "Gemini reliable transport exceeded its queue limit. Start voice again.": "Der zuverlässige Gemini-Transport hat sein Warteschlangenlimit überschritten. Sprachsteuerung neu starten.", - "Gemini reliable transport did not drain. Start voice again.": "Der zuverlässige Gemini-Transport wurde nicht geleert. Sprachsteuerung neu starten.", + "Gemini reliable transport exceeded its queue limit. Start voice again.": "Die Gemini-Sendewarteschlange ist voll. Sprachsteuerung neu starten.", + "Gemini reliable transport did not drain. Start voice again.": "Gemini-Nachrichten konnten nicht rechtzeitig gesendet werden. Sprachsteuerung neu starten.", "Gemini token request failed (HTTP {status})": "Gemini-Token-Anfrage fehlgeschlagen (HTTP {status})", "Gemini token response did not include a valid model": "Die Gemini-Token-Antwort enthielt kein gültiges Modell", "Gemini token response did not include session settings": "Die Gemini-Token-Antwort enthielt keine Sitzungseinstellungen", @@ -2680,7 +2680,7 @@ "{label} error": "{label} Fehler", "counted the first {returned} loaded records": "die ersten {returned} geladenen Einträge gezählt", "counted {returned} of {total} loaded records": "{returned} von {total} geladenen Einträgen gezählt", - "{layers} just turned on — still loading, counts will rise": "{layers} gerade eingeschaltet – lädt noch, die Zahlen steigen", + "{layers} just turned on — still loading, counts will rise": "{layers} gerade eingeschaltet – Daten werden noch geladen, die Zahlen steigen", "Contacts panel snapshot at {time} — the same retained cohort supplies the card, speech, and follow-up memory": "Snapshot des Kontaktbereichs um {time} – dieselbe gespeicherte Auswahl liefert die Sprachkarte, die Sprachausgabe und das Gedächtnis für Folgefragen", "Contacts panel snapshot — the same retained cohort supplies the card, speech, and follow-up memory": "Snapshot des Kontaktbereichs – dieselbe gespeicherte Auswahl liefert die Sprachkarte, die Sprachausgabe und das Gedächtnis für Folgefragen", "Fly below {km} km to a covered region": "Unter {km} km zu einer abgedeckten Region fliegen", @@ -2704,7 +2704,7 @@ "The flights layer is not enabled": "Die Ebene Flüge ist nicht aktiviert", "The military layer is not enabled": "Die Militär-Ebene ist nicht aktiviert", "The satellites layer is not enabled": "Die Ebene Satelliten ist nicht aktiviert", - "The ais-live-vessels layer is not enabled": "Die Ebene ais-live-vessels ist nicht aktiviert", + "The ais-live-vessels layer is not enabled": "Die Ebene „Live-Schiffe“ ist nicht aktiviert", "Could not enable the requested layer": "Die angeforderte Ebene konnte nicht aktiviert werden", "Could not disable the requested layer": "Die angeforderte Ebene konnte nicht deaktiviert werden", "Radio layer unavailable": "Radio-Ebene nicht verfügbar", @@ -2714,10 +2714,10 @@ "Nearest-aircraft selection needs a preset, place name, or latitude and longitude": "Die Auswahl des nächsten Luftfahrzeugs braucht ein Preset, einen Ortsnamen oder Breite und Länge", "Could not arrive at the requested place": "Der angeforderte Ort konnte nicht erreicht werden", "The nearest airborne aircraft could not be selected": "Das nächste Luftfahrzeug in der Luft konnte nicht ausgewählt werden", - "No flights within {radius} of the current view": "Keine Flüge im Umkreis von {radius} um die aktuelle Ansicht", - "No military within {radius} of the current view": "Keine Militärflüge im Umkreis von {radius} um die aktuelle Ansicht", - "No satellites within {radius} of the current view": "Keine Satelliten im Umkreis von {radius} um die aktuelle Ansicht", - "No vessels within {radius} of the current view": "Keine Schiffe im Umkreis von {radius} um die aktuelle Ansicht", + "No flights within {radius} of the current view": "Keine Flüge im Umkreis von {radius} um die Bildmitte", + "No military within {radius} of the current view": "Keine Militärflüge im Umkreis von {radius} um die Bildmitte", + "No satellites within {radius} of the current view": "Keine Satelliten im Umkreis von {radius} um die Bildmitte", + "No vessels within {radius} of the current view": "Keine Schiffe im Umkreis von {radius} um die Bildmitte", "{layer} is enabled on the {source} feed, but no airborne aircraft is loaded in the {place} view yet": "{layer} ist mit dem Feed {source} aktiviert, aber in der Ansicht {place} ist noch kein Luftfahrzeug in der Luft geladen", "{layer} is enabled, but no airborne aircraft is loaded in the {place} view yet": "{layer} ist aktiviert, aber in der Ansicht {place} ist noch kein Luftfahrzeug in der Luft geladen", "{layer} is enabled, but its aircraft feed is unavailable": "{layer} ist aktiviert, aber der Flugzeug-Feed ist nicht verfügbar", @@ -2761,9 +2761,9 @@ "Layer": "Ebene", "there": "dort", "Camera range {range}": "Kameraentfernung {range}", - "Within {radius} of the view": "Im Umkreis von {radius} um die Ansicht", + "Within {radius} of the view": "Im Umkreis von {radius} um die Bildmitte", "Labels on": "Beschriftungen an", - "Framing uses the nearest 80 loaded contacts": "Die Bildauswahl nutzt die 80 nächsten geladenen Kontakte", + "Framing uses the nearest 80 loaded contacts": "Ins Bild genommen werden höchstens die 80 nächsten geladenen Kontakte", "{distance} from {location}": "{distance} von {location}", "Altitude {altitude}": "Höhe {altitude}", "{origin} to {destination}": "{origin} nach {destination}", From cd1f57364724952141be3d110f1ab723012a1f2f Mon Sep 17 00:00:00 2001 From: German Khokhlov Date: Wed, 28 Oct 2026 22:06:29 +0400 Subject: [PATCH 33/83] i18n(ja): apply review round 2 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Catalog fixes from the second review round (squawk 7600/7700 names, transit occupancy, radio category, cyclone advisory wording, Orbital Watch, validation and hint texts), cockpit distances keep "km" in Japanese as in Chinese, the CCTV context line uses the translated view band, and the Japanese layer status line no longer splits "1分以内". Co-Authored-By: Claude Opus 5.5 --- docs/translations/ja.md | 9 ++++- src/i18n/ja-display.test.mjs | 21 ++++++++++ src/i18n/locales/ja.json | 70 ++++++++++++++++----------------- src/layers/cctv/presentation.js | 18 ++++++++- src/ui/cockpitContext.js | 9 +++-- src/ui/cockpitPresentation.js | 10 ++++- src/ui/styles/cjk.css | 8 ++++ 7 files changed, 103 insertions(+), 42 deletions(-) create mode 100644 src/i18n/ja-display.test.mjs diff --git a/docs/translations/ja.md b/docs/translations/ja.md index 0f94a6b08..a790d329c 100644 --- a/docs/translations/ja.md +++ b/docs/translations/ja.md @@ -17,7 +17,7 @@ Translation source: abiyeenzo (#913). ## Numbers, units and dates -- Units: km, m, km/h, m/s, kt, ft, mph, hPa, MW, dB, °, % stay as written, with the English spacing (「250 km」, 「{frp} MW」, 「95 kt」). +- Units: km, m, km/h, m/s, kt, ft, mph, hPa, MW, dB, °, % stay as written, with the English spacing (「250 km」, 「{frp} MW」, 「95 kt」). Code-built cockpit distances follow this too (`cockpitUnitCase` skips the HUD upper-casing for ja, as for zh). The cockpit's own speed caption is the HUD code KT, in 対地速度 · KT and under the readout. - Time units are words written straight after the number: 秒, 分, 時間, 日 (「5分前」, 「{count}時間」, 「1時間5分」). `formatQuantity` and `formatRelativeTime` drop the space for Japanese unit words, so code-built values match the catalog. - Counters follow the thing counted: 機 (aircraft), 隻 (ships), 基 (satellites), 台 (cameras, vehicles), 局 (stations), 件 (records, results, events), か所 (sites), 個 (generic). Prefer a counter to a bare number. - Dates come from `Intl` and read year first: 2026年8月26日. Coordinates in prose are 北緯 / 東経; HUD hemisphere letters stay N, S, E, W. @@ -62,12 +62,15 @@ Translation source: abiyeenzo (#913). | track (TRK, direction over the ground) | 対地針路 | | HDG / BRG / CRS / FOV | そのまま(HUDコード) | | squawk | スコーク | +| radio failure / emergency (7600 / 7700) | 通信機故障 / 緊急事態 | | map heading / North up | 方位 / 北を上に | | Street Level / Street View (Google) | ストリートレベル / ストリートビュー | | Recent Imagery | 最近の衛星画像 | | Global Context / Context (panel) | グローバルコンテキスト / コンテキスト | | radio (station) / tune / seek | ラジオ(局)/ 選局・同調 / シーク | +| Public Safety / SAFETY (radio category) | 警察・消防 | | transit / bikeshare | 公共交通 / シェアサイクル | +| occupancy: empty / standing room only / crushed | 乗客なし / 立ち乗りのみ / 非常に混雑 | | traffic flow (TomTom) | 交通流 | | Previous / Next | 前へ / 次へ | | SIG / NEWS / LOCAL (briefing tabs) | シグナル / ニュース / ローカル | @@ -76,7 +79,8 @@ Translation source: abiyeenzo (#913). | weather model / forecast lead hours | モデル / 予報時間 | | valid (forecast time) / issued | 対象時刻 / 発表 | | radar reflectivity / lightning density | レーダー反射強度 / 雷密度 | -| cyclone, storm (NHC/CPHC) / advisory | サイクロン / 情報(第N報) | +| cyclone, storm (NHC/CPHC) / advisory | サイクロン / 情報(第N報); alone: サイクロン情報 | +| potential tropical cyclone (NHC PC) | サイクロン化のおそれがある擾乱 | | forecast uncertainty cone | 予報円 | | tropical storm / tropical depression | 熱帯暴風雨 / 熱帯低気圧 | | scene cloud / mosaic / daily overview | シーン雲量 / モザイク / 日次概観 | @@ -97,3 +101,4 @@ Translation source: abiyeenzo (#913). | roundabout / ramp / exit | ロータリー / ランプ / 出口 | | reduced motion | 動きを減らす | | NOT AN ALL-CLEAR | 安全の保証ではありません | +| … Watch (scene titles: Earth, Orbital) | 監視(地球監視, 軌道監視) | diff --git a/src/i18n/ja-display.test.mjs b/src/i18n/ja-display.test.mjs new file mode 100644 index 000000000..ade04f519 --- /dev/null +++ b/src/i18n/ja-display.test.mjs @@ -0,0 +1,21 @@ +import test from 'node:test'; +import assert from 'node:assert/strict'; +import { setLocale } from './index.js'; +import { + cockpitUnitCase, + formatCockpitDistance, +} from '../ui/cockpitPresentation.js'; + +test('Japanese cockpit distances keep the unit in its own case', () => { + try { + setLocale('ja'); + assert.equal(formatCockpitDistance(14000), '14 km'); + assert.equal(formatCockpitDistance(9500), '9.5 km'); + assert.equal(cockpitUnitCase('km'), 'km'); + setLocale('en'); + assert.equal(formatCockpitDistance(14000), '14 KM'); + assert.equal(cockpitUnitCase('km'), 'KM'); + } finally { + setLocale('en'); + } +}); diff --git a/src/i18n/locales/ja.json b/src/i18n/locales/ja.json index b2f22124b..4020b3874 100644 --- a/src/i18n/locales/ja.json +++ b/src/i18n/locales/ja.json @@ -38,9 +38,9 @@ "Fast jet": "高速ジェット機", "Business jet": "ビジネスジェット", "Drone": "ドローン", - "General emergency": "一般緊急事態", + "General emergency": "緊急事態", "Unlawful interference": "不法妨害", - "Radio failure": "無線故障", + "Radio failure": "通信機故障", "Downed aircraft": "墜落機", "Minimum fuel": "ミニマムフューエル", "Lifeguard (medical priority)": "救急飛行(医療優先)", @@ -234,7 +234,7 @@ "Overpass timed out": "Overpassがタイムアウトしました", "Overpass could not complete the query": "Overpassがクエリを完了できませんでした", "Map tiles temporarily unavailable": "地図タイルが一時的に利用できません", - "Mapped names temporarily unavailable": "地名が一時的に利用できません", + "Mapped names temporarily unavailable": "施設名を一時的に取得できません", "Overpass temporarily unavailable": "Overpassが一時的に利用できません", "Retrying mapped sites…": "マップ済み施設を再試行中…", "Fetching mapped sites…": "マップ済み施設を取得中…", @@ -267,7 +267,7 @@ "GEO": "GEO", "Geostationary belt — comms and weather, fixed over the equator": "静止軌道帯:通信と気象、赤道上空に固定", "VISUAL": "可視", - "Brightest naked-eye objects — CelesTrak visual group": "肉眼で見える最も明るい天体(CelesTrak visualグループ)", + "Brightest naked-eye objects — CelesTrak visual group": "肉眼で見える特に明るい衛星(CelesTrak visualグループ)", "COMMS": "通信", "Broadband constellation shell — shown only in DENSE mode": "ブロードバンドコンステレーションのシェル:高密度モードでのみ表示", "FISHING": "漁船", @@ -336,7 +336,7 @@ "Awaiting telemetry...": "テレメトリー待機中…", "REC": "REC", "AIS: --": "AIS: --", - "N/A": "なし", + "N/A": "不明", "{mode} {band} {locality} | {region} | ALT {alt} | WINDOW {window} | SUN {sun}° | ONA {ona}° | {zone}": "{mode} {band} {locality} | {region} | ALT {alt} | 範囲 {window} | SUN {sun}° | ONA {ona}° | {zone}", "NEAR {poi} ({city}) {distance}": "{poi}({city})付近 {distance}", "SECTOR {lat} {lon}": "セクター {lat} {lon}", @@ -502,7 +502,7 @@ "AIS vessels": "AIS船舶", "Mapped installations": "マップ済み施設", "syncing {count} city feeds...": "{count}都市のフィードを同期中…", - "scanning nearby systems...": "周辺のシステムをスキャン中…", + "scanning nearby systems...": "周辺のシェアサイクルを検索中…", "GBFS fetch error": "GBFS取得エラー", "Station {id}": "ステーション {id}", "Station": "ステーション", @@ -519,7 +519,7 @@ "SPEC FOV {span}° (CAPABILITY)": "仕様FOV {span}°(対応画角)", "COVERAGE {value}km²": "カバー範囲 {value}km²", "OVERLAP {count} cams": "重複 {count}台", - "ISOLATED VIEW": "単独ビュー", + "ISOLATED VIEW": "重複なし", "PROJ MONITOR": "投影 モニター", "PROJ OFF": "投影 オフ", "VIEWSHED": "可視域", @@ -530,7 +530,7 @@ "Atlantic and eastern/central North Pacific; not worldwide cyclone coverage.": "大西洋と北太平洋東部・中部のみです。全世界のサイクロンを網羅するものではありません。", "Cyclone advisories unavailable": "サイクロン情報を取得できません", "Cyclone data unavailable": "サイクロンデータを取得できません", - "Potential tropical cyclone": "潜在的熱帯サイクロン", + "Potential tropical cyclone": "サイクロン化のおそれがある擾乱", "Post-tropical cyclone": "熱帯性を失ったサイクロン", "Hurricane": "ハリケーン", "Tropical storm": "熱帯暴風雨", @@ -540,8 +540,8 @@ "Track and cone match this advisory": "進路と予報円はこの情報と一致しています", "Track/cone awaiting advisory {number}": "進路/予報円は第{number}報を待機中", "Track/cone unavailable": "進路/予報円を取得できません", - "Cached advisory · stale source": "キャッシュの情報 · ソース更新遅延", - "Loading advisories…": "情報を読み込み中…", + "Cached advisory · stale source": "キャッシュのサイクロン情報 · ソース更新遅延", + "Loading advisories…": "サイクロン情報を読み込み中…", "{count} active storms": { "other": "発生中のサイクロン {count}個" }, @@ -549,7 +549,7 @@ "Maximum sustained wind: {wind} · Pressure: {pressure}": "最大持続風速:{wind} · 気圧:{pressure}", "{name} · {classification} · Advisory {number} · issued {time}": "{name} · {classification} · 第{number}報 · {time}発表", "No active NHC/CPHC systems": "NHC/CPHCが監視中のサイクロンはありません", - "Advisories unavailable": "情報を取得できません", + "Advisories unavailable": "サイクロン情報を取得できません", "Cyclones · NHC / CPHC": "サイクロン · NHC / CPHC", "Atlantic · E/C Pacific": "大西洋 · 東部/中部太平洋", "{storms} · {name} selected": "{storms} · {name}を選択中", @@ -679,8 +679,8 @@ "{distance} · {duration} · {mode} · first {count} turns": "{distance} · {duration} · {mode} · 最初の{count}件の案内", "{distance} · {duration} · {mode}": "{distance} · {duration} · {mode}", "Click the globe to place {endpoint}": "地球をクリックして{endpoint}を配置", - "SET B, then click the globe": "Bを設定してから地球をクリック", - "SET A, then click the globe": "Aを設定してから地球をクリック", + "SET B, then click the globe": "[Bを設定]を押してから地球をクリック", + "SET A, then click the globe": "[Aを設定]を押してから地球をクリック", "Step {step} of {total} · then {leg}": "ステップ {step}/{total} · 次に{leg}", "Step {step} of {total}": "ステップ {step}/{total}", "Then: {instruction}": "次:{instruction}", @@ -913,13 +913,13 @@ "Under 50% contained": "封じ込め率50%未満", "50–99% contained": "封じ込め率50–99%", "Fully contained": "封じ込め率100%", - "Colour shows reported containment. Perimeters are simplified to about 100 m.": "色は報告された封じ込め率を示します。延焼範囲は約100 mに簡略化されています。", + "Colour shows reported containment. Perimeters are simplified to about 100 m.": "色は報告された封じ込め率を示します。延焼範囲の輪郭は約100 mの精度で簡略化されています。", "Malformed perimeter snapshot": "延焼範囲スナップショットの形式が不正です", "radio tag|All": "すべて", "News": "ニュース", "Talk": "トーク", "Weather / Emergency": "気象 / 緊急", - "Public Safety": "公共安全", + "Public Safety": "警察・消防", "Aviation / Marine": "航空 / 海事", "Traffic / Transit": "交通 / 公共交通", "Music": "音楽", @@ -931,7 +931,7 @@ "radio|NEWS": "ニュース", "radio|TALK": "トーク", "radio|WEATHER": "気象", - "radio|SAFETY": "安全", + "radio|SAFETY": "警察・消防", "radio|AIR / SEA": "航空 / 海事", "radio|TRANSIT": "交通", "radio|MUSIC": "音楽", @@ -989,7 +989,7 @@ "Box edges must be finite": "範囲の端は有限の値である必要があります", "Longitudes must be within ±180°": "経度は±180°以内である必要があります", "Select one side of the dateline": "日付変更線の片側を選択してください", - "Box must enclose an area": "範囲は面積を囲む必要があります", + "Box must enclose an area": "幅と高さのある範囲を選択してください", "Add the full Starlink broadband shell (thousands of extra points)": "Starlinkブロードバンドシェル全体を追加(数千の追加ポイント)", "Loading the Starlink shell…": "Starlinkシェルを読み込み中…", "Starlink {detail} — click to retry": "Starlink {detail}:クリックで再試行", @@ -1094,11 +1094,11 @@ "OpenFreeMap tiles rate-limited": "OpenFreeMapタイルがレート制限中", "OpenFreeMap tiles timed out": "OpenFreeMapタイルがタイムアウトしました", "OpenFreeMap tiles unavailable": "OpenFreeMapタイルを利用できません", - "occupancy|empty": "空車", + "occupancy|empty": "乗客なし", "occupancy|many seats available": "空席多数", "occupancy|few seats available": "空席わずか", - "occupancy|standing room only": "立ち席のみ", - "occupancy|crushed standing room only": "満員に近い立ち席のみ", + "occupancy|standing room only": "立ち乗りのみ", + "occupancy|crushed standing room only": "非常に混雑", "occupancy|full": "満員", "occupancy|not accepting passengers": "乗車不可", "occupancy|not boardable": "乗車できません", @@ -1111,7 +1111,7 @@ "reported {speed} km/h": "報告速度 {speed} km/h", "reported hdg {heading}°": "報告方位 {heading}°", "Last report: stopped at stop {stop}": "最終報告:停留所{stop}に停車中", - "Last report: arriving at stop {stop}": "最終報告:停留所{stop}に到着中", + "Last report: arriving at stop {stop}": "最終報告:停留所{stop}に接近中", "Last report: next stop {stop}": "最終報告:次の停留所{stop}", "Shown at street level · depth not in the feed": "地表の高さで表示 · フィードに深さ情報なし", "Reported {seconds} s ago": "{seconds}秒前に報告", @@ -1379,7 +1379,7 @@ "Bhote Koshi Evidence Sequence": "Bhote Koshi証拠シーケンス", "Nepal Flood Incident": "ネパール洪水インシデント", "Global Flights Radar": "グローバル航空レーダー", - "Orbital Watch": "軌道ウォッチ", + "Orbital Watch": "軌道監視", "Thermal Threat Board": "熱源脅威ボード", "City Overload": "シティオーバーロード", "Omniscience Pullback": "オムニサイエンス・プルバック", @@ -1498,7 +1498,7 @@ "WHOT/BHOT": "WHOT/BHOT", "Ironbow": "Ironbow", "unsaved CCTV calibration": "未保存のCCTVキャリブレーション", - "the open cockpit": "開いているコックピット", + "the open cockpit": "表示中のコックピット", "Switching language reloads the page. This will be lost: {items}. Switch anyway?": "言語を切り替えるとページが再読み込みされます。次の内容は失われます:{items}。切り替えますか?", "VISUAL PRESETS": "ビジュアルプリセット", "LOCATION": "位置", @@ -1653,7 +1653,7 @@ "Noir": "ノワール", "Snow": "雪", "Current cockpit vision style: {style}. Activate for next style.": "現在のコックピットビジョンスタイル:{style}。押すと次のスタイルに切り替わります。", - "Current style: {style} — click for next": "現在のスタイル:{style} — クリックで次へ", + "Current style: {style} — click for next": "現在のスタイル:{style}。クリックで次へ", "Collapse Contact panel": "コンタクトパネルを折りたたむ", "Expand Contact panel": "コンタクトパネルを展開", "Collapse contact panel": "コンタクトパネルを折りたたむ", @@ -1730,10 +1730,10 @@ "Some KML content was left out.": "KMLの一部の内容は読み込まれませんでした。", "Press on the ground, not the sky": "空ではなく地表を押してください", "Drag to size the box": "ドラッグして範囲の大きさを決めてください", - "light {source} to use your {name} key": "{source}をオンにして{name}キーを使用", + "light {source} to use your {name} key": "{source}をオンにして{name}キーを使う", "light {source}": "{source}をオンにする", - ", or ": "、または", - "{requirement}, or {offer}": "{requirement}。または、{offer}", + ", or ": "か、", + "{requirement}, or {offer}": "{requirement}。または{offer}", "Live Flights": "ライブフライト", "Military Flights": "軍用機", "Earthquakes (24h)": "地震(24時間)", @@ -1983,7 +1983,7 @@ "Select a box or use the view": "範囲を選択するか、現在のビューを使用してください", "Searching the last 30 days": "過去30日間を検索中", "No days to show for this box": "この範囲で表示できる日がありません", - "Drag the divider · SWAP trades sides": "境界線をドラッグ · 入れ替えで左右を交換", + "Drag the divider · SWAP trades sides": "境界線をドラッグ · [入れ替え]で左右を交換", "← → preview · A or B pins the focused day": "← → でプレビュー · AまたはBで選択中の日を固定", "← → preview the other side · A or B pins it": "← → で反対側をプレビュー · AまたはBで固定", "S on another day replaces it · × unpins": "別の日でSを押すと置き換え · ×で固定を解除", @@ -2101,7 +2101,7 @@ "OVERPASS TIMED OUT": "Overpassがタイムアウト", "OVERPASS COULD NOT COMPLETE THE QUERY": "Overpassがクエリを完了できません", "MAP TILES TEMPORARILY UNAVAILABLE": "地図タイルが一時的に利用不可", - "MAPPED NAMES TEMPORARILY UNAVAILABLE": "地名が一時的に利用不可", + "MAPPED NAMES TEMPORARILY UNAVAILABLE": "施設名が一時的に利用不可", "TURNING OFF LIVE DATA": "ライブデータをオフにしています", "REFRESHING LIVE DATA": "ライブデータを更新中", "syncing road network": "道路網を同期中", @@ -2314,7 +2314,7 @@ "Automatic stop is unavailable for this voice connection.": "この音声接続では自動停止を利用できません。", "Preview is off.": "プレビューはオフです。", "Your choice applies now, but could not be saved.": "選択は適用されましたが、保存できませんでした。", - "WebRTC microphone support unavailable": "WebRTCマイクに対応していません", + "WebRTC microphone support unavailable": "このブラウザーではWebRTCでマイクを使用できません", "VOICE UNAVAILABLE": "音声利用不可", "VOICE ACTIVE": "音声 オン", "Voice session could not be started.": "音声セッションを開始できませんでした。", @@ -2421,7 +2421,7 @@ "Activate to toggle voice": "押すと音声のオン/オフを切り替え", "Voice active": "音声 オン", "Voice could not be started.": "音声を開始できませんでした。", - "the active voice session": "有効な音声セッション", + "the active voice session": "進行中の音声セッション", "{value} feet": "{value}フィート", "Fire · FRP {frp} MW": "火災 · FRP {frp} MW", "The flights layer is not enabled": "フライトレイヤーが有効になっていません", @@ -2560,7 +2560,7 @@ "DEST ---°": "目的地 ---°", "OPTICAL PLANE · 01": "光学面 · 01", "VISOR LOCK · ACTIVE": "バイザーロック · 有効", - "GROUND SPEED · KTS": "対地速度 · KTS", + "GROUND SPEED · KTS": "対地速度 · KT", "ALTITUDE · FT": "高度 · FT", "FIRST PERSON": "一人称視点", "LIVE TRACK · COURSE ALIGNED": "ライブ追跡 · 針路一致", @@ -2568,7 +2568,7 @@ "Previous cockpit vision style": "前のコックピットビジョンスタイル", "Previous vision style": "前のビジョンスタイル", "Current cockpit vision style: NORMAL. Activate for next style.": "現在のコックピットビジョンスタイル:標準。押すと次のスタイルに切り替わります。", - "Current style: NORMAL — click for next": "現在のスタイル:標準 — クリックで次へ", + "Current style: NORMAL — click for next": "現在のスタイル:標準。クリックで次へ", "CURRENT": "現在", "Next cockpit vision style": "次のコックピットビジョンスタイル", "Next vision style": "次のビジョンスタイル", @@ -2730,7 +2730,7 @@ "Sonar ring count": "ソナーのリング数", "Range": "範囲", "Sonar ring range": "ソナーのリング範囲", - "Power": "強さ", + "Power": "強度", "Sonar intensity": "ソナーの強度", "Opacity": "不透明度", "Cyber contact and label opacity": "サイバーのコンタクトとラベルの不透明度", @@ -2863,5 +2863,5 @@ "Begin with a clean globe": "まっさらな地球儀から始める", "Don't show this again": "今後表示しない", "ESC to dismiss": "ESCで閉じる", - "Tip: the GEV MIC button in the dock lets you talk to the map.": "ヒント:ドックのGEV MICボタンで地図に話しかけられます。" + "Tip: the GEV MIC button in the dock lets you talk to the map.": "ヒント:ドックの[マイク]ボタンで地図に話しかけられます。" } diff --git a/src/layers/cctv/presentation.js b/src/layers/cctv/presentation.js index e47e08194..948317b05 100644 --- a/src/layers/cctv/presentation.js +++ b/src/layers/cctv/presentation.js @@ -8,6 +8,22 @@ import { isDatasheetFov, } from './modelSpecs.js'; +/** The camera's zoom bucket (cctv model) in the HUD's view-band words. */ +function viewBandLabel(band) { + switch (band) { + case 'street': + return t('STREET', { context: 'view band' }); + case 'city': + return t('CITY', { context: 'view band' }); + case 'regional': + return t('REGIONAL', { context: 'view band' }); + case 'global': + return t('GLOBAL', { context: 'view band' }); + default: + return band.toUpperCase(); + } +} + export function createPresentation({ state: layerState, services, @@ -82,7 +98,7 @@ export function createPresentation({ : t('SRC {value}', { value: String(active.camera.feedType || 'image').toUpperCase(), }), - t('{value} CONTEXT', { value: viewBand.toUpperCase() }), + t('{value} CONTEXT', { value: viewBandLabel(viewBand) }), // Identified hardware: append the model's datasheet specs + attribution. active.camera.spec ? t('{spec} · SPECS: CCTV-DATABASE.COM', { diff --git a/src/ui/cockpitContext.js b/src/ui/cockpitContext.js index 2c65d3bf6..792dfdc2e 100644 --- a/src/ui/cockpitContext.js +++ b/src/ui/cockpitContext.js @@ -1,6 +1,6 @@ /** Contact readouts and nearby-signal presentation for the Cockpit controller. */ import * as Cesium from 'cesium'; -import { formatNumber, getLocale, t, tn } from '../i18n/index.js'; +import { formatNumber, t, tn } from '../i18n/index.js'; import { unitLabel } from './unitLabels.js'; import { bearingBetweenCoordinates, @@ -8,14 +8,17 @@ import { relativeBearing, resolveCockpitContextReadout, } from '../cockpitMath.js'; -import { formatCockpitDistance } from './cockpitPresentation.js'; +import { + cockpitUnitCase, + formatCockpitDistance, +} from './cockpitPresentation.js'; /** The Context scope line in the active language (see cockpitMath.js). */ const LOCALIZED_CONTEXT_SCOPE = Object.freeze({ window: ({ label, radiusKm }) => t('{label} · {radius} AIR/SEA WINDOW', { label, - radius: `${radiusKm === null ? '—' : formatNumber(radiusKm)}\u00a0${getLocale().startsWith('zh-') ? unitLabel('km') : unitLabel('km').toUpperCase()}`, + radius: `${radiusKm === null ? '—' : formatNumber(radiusKm)}\u00a0${cockpitUnitCase(unitLabel('km'))}`, }), installations: ({ scope, coverage }) => t('{scope} · INSTALLATIONS {coverage}', { scope, coverage }), diff --git a/src/ui/cockpitPresentation.js b/src/ui/cockpitPresentation.js index 4f3faac9d..40602c7b3 100644 --- a/src/ui/cockpitPresentation.js +++ b/src/ui/cockpitPresentation.js @@ -149,7 +149,15 @@ export function formatCockpitDistance(distanceM) { minimumFractionDigits: digits, maximumFractionDigits: digits, }); - return getLocale().startsWith('zh-') ? distance : distance.toUpperCase(); + return cockpitUnitCase(distance); +} + +/** + * Upper-case a cockpit unit the HUD way (`9.5 KM`), except in Chinese and + * Japanese, which have no case and keep units as the catalog writes them. + */ +export function cockpitUnitCase(text) { + return /^(zh|ja)(-|$)/.test(getLocale()) ? text : text.toUpperCase(); } export function formatCockpitWindDirection(value) { diff --git a/src/ui/styles/cjk.css b/src/ui/styles/cjk.css index 1315a8d23..85e3081b3 100644 --- a/src/ui/styles/cjk.css +++ b/src/ui/styles/cjk.css @@ -69,3 +69,11 @@ html:lang(ja) .recent-imagery-readout .ri-slot-value { word-break: keep-all; overflow-wrap: break-word; } + +/* Japanese layer status lines wrap at their spaces and · separators, so an + age such as 1分以内 stays whole (更新 1 / 分以内); a run too long for the + line still breaks. */ +html:lang(ja) .data-toggle-meta { + word-break: keep-all; + overflow-wrap: break-word; +} From 6cf47c6ca84484b50c44d31a9b39495b3945b643 Mon Sep 17 00:00:00 2001 From: German Khokhlov Date: Wed, 28 Oct 2026 22:35:44 +0400 Subject: [PATCH 34/83] i18n(it): apply review round 3 Co-Authored-By: Claude Opus 5.5 --- docs/translations/it.md | 6 +- src/i18n/locales/it.json | 126 +++++++++++++++++++-------------------- 2 files changed, 67 insertions(+), 65 deletions(-) diff --git a/docs/translations/it.md b/docs/translations/it.md index 610d85b01..58d7bb427 100644 --- a/docs/translations/it.md +++ b/docs/translations/it.md @@ -13,11 +13,11 @@ Translation source: abiyeenzo (#912). - Short labels, chips and HUD readouts stay short. A standard abbreviation with a period beats a wrapped line: REGOLAZ., RILEV., INCL., ALT., VEL., STIM., PROIEZ., ESP.; PREC / SUCC for PREV / NEXT and PREVIOUS / NEXT. - The HUD codes HDG, BRG, CRS, FOV and DEST stay in English, as in cockpit avionics. RANGE is «PORTATA». Words used in a sentence are translated: heading → «prua» (aircraft, ships) or «direzione» (camera, buses, trams, trains), course → «rotta». - Keyboard keys stay in English: Space, Enter, Esc, Tab, Shift, Backspace, H, 1–9 («Tieni premuto Space per parlare», «Premi Enter per riprovare»). -- Decimal comma in numbers written in the text: «28,2710° N». Numbers formatted by the code follow `Intl` and need nothing. +- Decimal comma in numbers written in the text, magnitudes included: «28,2710° N», «M5,2». Numbers formatted by the code follow `Intl` and need nothing. - Amounts: thousands, millions and billions are written out or abbreviated in Italian, not with K/M/B: «{amount} mila $», «{amount} mln $», «{amount} mld $». - Units: km, m, km/h, m/s, kn (knots), ft (feet), h, min, s; in UPPERCASE text KM, KM/S, KT, FT, MIN, H. "m" is always metres, so minutes are «min» («5 min fa»). MW stays MW. `°` and `%` stay. - "ago" goes after the time: «{count} min fa». When a placeholder already holds a localized "ago" text (`{age}`, `{ago}`), do not add «fa» again. -- A feature name used as a sentence subject gets a head noun so the verb agrees: «La modalità Missioni spaziali isola…», «Il pannello Impostazioni provider è disattivato…», «Il livello {layer} è attivo…», «Lo strumento {name} è attivo…». A short card title with a placeholder name puts the state after a colon: «{label}: attivato». +- A feature name used as a sentence subject gets a head noun so the verb agrees: «La modalità Missioni spaziali isola…», «Il pannello Impostazioni provider è disattivato…», «Il livello {layer} è attivo…», «Lo strumento {name} è attivo…». A short card title with a placeholder name puts the state after a colon: «{label}: attivato». The same goes for a placeholder list of names: «Attivazione recente: {layers}». A count in a plain `t()` entry (no plural forms) that can be 1 goes after a label, so nothing has to agree with it: «Record accettati: {accepted} su {raw}». - English loanwords that Italian UIs use as they are stay in English: feed, live, cockpit, briefing, preset, overlay, layout, snapshot, tile, provider, timeout, payload, bloom, scope. ## Plurals @@ -62,9 +62,11 @@ The `many` form is the `other` text with «di» after the number when a noun fol | mapped / observed | mappato / osservato | | camera (view) / camera, CCTV camera | camera / telecamera, telecamera CCTV | | earthquake / active fire / fire perimeter | terremoto / incendio attivo / perimetro dell'incendio | +| lightning strike / cloud (cover, %) | fulmine / nuvole («non singoli fulmini», «20% di nuvole») | | incident (wildfire, Type N) / scene incident | evento (Evento di tipo N, Incendio senza nome) / evento | | trigger record (USGS card) / OPEN SOURCE link | scheda / APRI LA FONTE | | advisory (NHC/CPHC cyclone) / cone | bollettino / cono di incertezza | +| forecast lead hours (cyclone points) | scadenze di previsione in ore | | radio station / broadcaster | stazione radio / emittente | | CH (radio channel readout) | CH (unchanged) | | road / flow (traffic) | strada / flusso | diff --git a/src/i18n/locales/it.json b/src/i18n/locales/it.json index ce5f7da1d..cdfd7ae98 100644 --- a/src/i18n/locales/it.json +++ b/src/i18n/locales/it.json @@ -148,7 +148,7 @@ "Rasuwagadhi witness": "Testimone a Rasuwagadhi", "Open original source for {source}; capture time unverified": "Apri la fonte originale per {source}; ora di acquisizione non verificata", "Historical reference and post-event image divider": "Divisore tra immagine storica di riferimento e immagine successiva all'evento", - "A historical reference {before} percent, B post-event {after} percent": "A riferimento storico {before} percento, B dopo l'evento {after} percento", + "A historical reference {before} percent, B post-event {after} percent": "A riferimento storico {before} per cento, B dopo l'evento {after} per cento", "■ RELEASE CAMERA": "■ RILASCIA LA CAMERA", "Seek Nepal scene clock": "Scorri l'orologio della scena in Nepal", "NEPAL SCENE CLOCK": "OROLOGIO SCENA NEPAL", @@ -176,7 +176,7 @@ "Play reconstruction": "Riproduci la ricostruzione", "Load previous scene shot": "Carica lo scatto precedente della scena", "Load next scene shot": "Carica lo scatto successivo della scena", - "SCHEMATIC CORRIDOR, NOT MODELED ARRIVAL TIME.": "CORRIDOIO SCHEMATICO, NON UN TEMPO DI ARRIVO MODELLATO.", + "SCHEMATIC CORRIDOR, NOT MODELED ARRIVAL TIME.": "CORRIDOIO SCHEMATICO: TEMPI DI ARRIVO NON MODELLATI.", "Rasuwa · 26 Aug 2026": "Rasuwa · 26 ago 2026", "Event reconstruction": "Ricostruzione dell'evento", "BHOTE KOSHI FLOOD INCIDENT": "ALLUVIONE DEL BHOTE KOSHI", @@ -184,7 +184,7 @@ "USGS INITIAL REPORT": "RAPPORTO INIZIALE USGS", "26 AUG 2026 · 08:37 NPT": "26 AGO 2026 · 08:37 NPT", "28.2710° N · 85.5150° E": "28,2710° N · 85,5150° E", - "INITIAL M4.4 · RECLASSIFIED M5.2 LANDSLIDE": "INIZIALE M4.4 · RICLASSIFICATO FRANA M5.2", + "INITIAL M4.4 · RECLASSIFIED M5.2 LANDSLIDE": "INIZIALE M4,4 · RICLASSIFICATO COME FRANA M5,2", "USGS EVENT us7000tbwb · OPEN SOURCE": "EVENTO USGS us7000tbwb · APRI LA FONTE", "Open the USGS initial report for the 26 August 2026 Nepal landslide": "Apri il rapporto iniziale USGS sulla frana del 26 agosto 2026 in Nepal", "Show the Nepal context callout without a border or country fill": "Mostra il riquadro di contesto sul Nepal senza confine né riempimento del paese", @@ -235,7 +235,7 @@ "That {format} file could not be read.": "Impossibile leggere quel file {format}.", "That file has {count} map objects; the limit is {limit}.": "Quel file ha {count} oggetti sulla mappa; il limite è {limit}.", "Ground heights could not be read. Try that file again.": "Impossibile leggere le quote del terreno. Riprova con quel file.", - "That file has invalid point graphics.": "Quel file ha grafiche dei punti non valide.", + "That file has invalid point graphics.": "Quel file ha simboli dei punti non validi.", "Overpass rate-limited": "Overpass ha limitato le richieste", "Overpass timed out": "Overpass è andato in timeout", "Overpass could not complete the query": "Overpass non ha potuto completare la query", @@ -244,8 +244,8 @@ "Overpass temporarily unavailable": "Overpass temporaneamente non disponibile", "Retrying mapped sites…": "Nuovo tentativo sui siti mappati…", "Fetching mapped sites…": "Ricerca dei siti mappati…", - "{reason} — retrying in {seconds}s": "{reason} — nuovo tentativo tra {seconds}s", - "{reason} — retry pending": "{reason} — nuovo tentativo in sospeso", + "{reason} — retrying in {seconds}s": "{reason}: nuovo tentativo tra {seconds}s", + "{reason} — retry pending": "{reason}: nuovo tentativo in sospeso", "Zoom in to search mapped installations": "Ingrandisci per cercare le installazioni mappate", "Showing cached mapped sites": "Siti mappati in cache", "Mapped sites not loaded": "Siti mappati non caricati", @@ -271,7 +271,7 @@ "NAV": "NAV", "GNSS navigation — GPS, GLONASS, Galileo": "Navigazione GNSS — GPS, GLONASS, Galileo", "GEO": "GEO", - "Geostationary belt — comms and weather, fixed over the equator": "Fascia geostazionaria — comunicazioni e meteo, fissi sopra l'equatore", + "Geostationary belt — comms and weather, fixed over the equator": "Fascia geostazionaria — satelliti per comunicazioni e meteo, fissi sopra l'equatore", "VISUAL": "VISIBILI", "Brightest naked-eye objects — CelesTrak visual group": "Oggetti più luminosi a occhio nudo — gruppo visual di CelesTrak", "COMMS": "TLC", @@ -286,9 +286,9 @@ "PILOT": "PILOTINA", "SAR": "SAR", "TUG": "RIMORCHIATORE", - "PORT TENDER": "TENDER PORTO", + "PORT TENDER": "TENDER PORTUALE", "ANTI-POLLUTION": "ANTINQUINAMENTO", - "LAW ENFORCE": "FORZE ORDINE", + "LAW ENFORCE": "FORZE DELL'ORDINE", "MEDICAL": "MEDICA", "HIGH-SPEED": "ALTA VELOCITÀ", "PASSENGER": "PASSEGGERI", @@ -361,7 +361,7 @@ "Provider Settings answers only the machine running the server": "Il pannello Impostazioni provider risponde solo alla macchina su cui gira il server", "Provider Settings answers only local hostnames": "Il pannello Impostazioni provider risponde solo a nomi host locali", "Provider Settings requires an exact local Origin": "Il pannello Impostazioni provider richiede un'Origin locale esatta", - "Unrecognized Origin refused": "Origin non riconosciuta rifiutata", + "Unrecognized Origin refused": "Origin non riconosciuta: richiesta rifiutata", "Cross-origin requests are refused": "Le richieste cross-origin sono rifiutate", "Content-Type must be application/json": "Content-Type deve essere application/json", "Method not allowed": "Metodo non consentito", @@ -393,7 +393,7 @@ "Optional paid token — public access works without one": "Token a pagamento opzionale: l'accesso pubblico funziona anche senza", "Free key — register, paste, done": "Chiave gratuita: registrati, incolla, fatto", "browser-side": "lato browser", - "This key runs in the browser by design — restrict it at the provider (see SECURITY.md)": "Questa chiave gira nel browser per progettazione: limitala presso il provider (vedi SECURITY.md)", + "This key runs in the browser by design — restrict it at the provider (see SECURITY.md)": "Questa chiave viene usata nel browser per scelta progettuale: imposta le restrizioni presso il provider (vedi SECURITY.md)", "configured externally": "configurata esternamente", "Supplied by your environment, Keychain, or launcher — change it where it was set": "Fornita dal tuo ambiente, dal Portachiavi o dal launcher: cambiala dove è stata impostata", "MANAGE ↗": "GESTISCI ↗", @@ -473,8 +473,8 @@ "many": "{count} vicine", "other": "{count} vicine" }, - "retrying mapped ALPR cameras": "nuovo tentativo telecamere ALPR mappate", - "loading mapped ALPR cameras": "caricamento telecamere ALPR mappate", + "retrying mapped ALPR cameras": "nuovo tentativo sulle telecamere ALPR mappate", + "loading mapped ALPR cameras": "caricamento delle telecamere ALPR mappate", "No ALPR data for this area — US and Canada only": "Nessun dato ALPR per quest'area: solo USA e Canada", "Zoom in to load mapped cameras": "Ingrandisci per caricare le telecamere mappate", "Showing cached locations": "Posizioni in cache", @@ -489,7 +489,7 @@ "CONTEXT READY": "CONTESTO PRONTO", "GLOBAL CONTEXT OFF": "CONTESTO GLOBALE OFF", "SELECT A FLIGHT, VESSEL, OR MAPPED INSTALLATION": "SELEZIONA UN VOLO, UNA NAVE O UN'INSTALLAZIONE MAPPATA", - "ENABLE TO LOAD OBSERVED / MAPPED PROXIMITY": "ATTIVA PER CARICARE LA PROSSIMITÀ OSSERVATA / MAPPATA", + "ENABLE TO LOAD OBSERVED / MAPPED PROXIMITY": "ATTIVA PER CARICARE I DATI OSSERVATI / MAPPATI NELLE VICINANZE", "Unavailable": "Non disponibile", "Focus {label}": "Inquadra {label}", "Global Context navigation": "Navigazione Contesto globale", @@ -525,7 +525,7 @@ "⚠️ Not renting": "⚠️ Noleggio non attivo", "⚠️ Not returning": "⚠️ Restituzione non attiva", "HDG {value}° (ESTIMATED)": "HDG {value}° (STIMATO)", - "{count} CAMERAS STANDING BY · NO CAMERA SELECTED · CLICK A CAMERA TO ACTIVATE": "{count} TELECAMERE IN ATTESA · NESSUNA TELECAMERA SELEZIONATA · CLIC SU UNA TELECAMERA PER ATTIVARLA", + "{count} CAMERAS STANDING BY · NO CAMERA SELECTED · CLICK A CAMERA TO ACTIVATE": "TELECAMERE IN ATTESA: {count} · NESSUNA TELECAMERA SELEZIONATA · CLIC SU UNA TELECAMERA PER ATTIVARLA", "No cameras available in catalog.": "Nessuna telecamera disponibile nel catalogo.", "{city} CCTV": "CCTV {city}", "FOV {value}° (DATASHEET)": "FOV {value}° (SCHEDA TECNICA)", @@ -568,13 +568,13 @@ "Advisories unavailable": "Bollettini non disponibili", "Cyclones · NHC / CPHC": "Cicloni · NHC / CPHC", "Atlantic · E/C Pacific": "Atlantico · Pacifico E/C", - "{storms} · {name} selected": "{storms} · {name} selezionata", + "{storms} · {name} selected": "{storms} · selezione: {name}", "Official advisory ↗": "Bollettino ufficiale ↗", "Active NHC and CPHC cyclone advisories": "Bollettini attivi sui cicloni di NHC e CPHC", "Wind unavailable": "Vento non disponibile", "Advisory center / forecast track": "Centro del ciclone da bollettino / traccia prevista", "Center-track uncertainty cone": "Cono di incertezza della traccia del centro", - "Select a storm on the map, or choose a storm in the list to select it and move the camera. Click empty map space to clear the selection. NOAA NHC/CPHC advisory context. The cone describes forecast center-track uncertainty, not storm size or the full hazard area. Forecast point labels are source lead hours, not times computed from advisory issuance. Geometry follows the surface; height is not weather altitude. Consult the official advisory.": "Seleziona una tempesta sulla mappa, o scegline una nell'elenco per selezionarla e spostare la camera. Fai clic su un punto vuoto della mappa per annullare la selezione. Contesto dai bollettini NOAA NHC/CPHC. Il cono descrive l'incertezza prevista sulla traccia del centro, non le dimensioni della tempesta né l'intera area di pericolo. Le etichette dei punti di previsione sono le ore di anticipo della fonte, non orari calcolati dall'emissione del bollettino. La geometria segue la superficie; l'altezza non è la quota meteorologica. Consulta il bollettino ufficiale.", + "Select a storm on the map, or choose a storm in the list to select it and move the camera. Click empty map space to clear the selection. NOAA NHC/CPHC advisory context. The cone describes forecast center-track uncertainty, not storm size or the full hazard area. Forecast point labels are source lead hours, not times computed from advisory issuance. Geometry follows the surface; height is not weather altitude. Consult the official advisory.": "Seleziona una tempesta sulla mappa, o scegline una nell'elenco per selezionarla e spostare la camera. Fai clic su un punto vuoto della mappa per annullare la selezione. Contesto dai bollettini NOAA NHC/CPHC. Il cono descrive l'incertezza prevista sulla traccia del centro, non le dimensioni della tempesta né l'intera area di pericolo. Le etichette dei punti di previsione indicano le scadenze di previsione in ore fornite dalla fonte, non orari calcolati dall'emissione del bollettino. La geometria segue la superficie; l'altezza non è la quota meteorologica. Consulta il bollettino ufficiale.", "DRIVE": "AUTO", "Drive": "In auto", "WALK": "A PIEDI", @@ -815,7 +815,7 @@ "ORBIT REPLAY · {mission}": "REPLAY ORBITA · {mission}", "PAUSED · {title}": "IN PAUSA · {title}", "UNSPECIFIED": "NON SPECIFICATO", - "+{count} additional payload records": "+{count} record payload aggiuntivi", + "+{count} additional payload records": "Record payload aggiuntivi: +{count}", "PAYLOAD DATA UNAVAILABLE": "DATI PAYLOAD NON DISPONIBILI", "{value} KM DOWNRANGE": "{value} KM DOWNRANGE", "POSITION UNAVAILABLE": "POSIZIONE NON DISPONIBILE", @@ -859,7 +859,7 @@ "Pause replay": "Metti in pausa il replay", "Cancel replay": "Annulla il replay", "EST. DOWNRANGE": "DOWNRANGE STIM.", - "PLANNED · ": "PIANIFICATO · ", + "PLANNED · ": "PREVISTA · ", "SUPPLIED TRAJECTORY POINTS": "PUNTI DI TRAIETTORIA FORNITI", "RECONSTRUCTED ESTIMATE": "STIMA RICOSTRUITA", "Replay the estimated ascent with a following camera": "Rivedi la salita stimata con una camera che segue il razzo", @@ -906,10 +906,10 @@ "${amount}K": "{amount} mila $", "${amount}M": "{amount} mln $", "${amount}B": "{amount} mld $", - "fire cause|Human": "Umana", - "fire cause|Natural": "Naturale", - "fire cause|Undetermined": "Indeterminata", - "fire cause|Unknown": "Sconosciuta", + "fire cause|Human": "umana", + "fire cause|Natural": "naturale", + "fire cause|Undetermined": "indeterminata", + "fire cause|Unknown": "sconosciuta", "fire behavior|Minimal": "Minimo", "fire behavior|Moderate": "Moderato", "fire behavior|Active": "Attivo", @@ -940,7 +940,7 @@ "Open {title} on InciWeb": "Apri {title} su InciWeb", "Perimeter source unavailable": "Fonte dei perimetri non disponibile", "Not contained or unknown": "Non contenuto o dato non disponibile", - "Under 50% contained": "Contenuto sotto il 50%", + "Under 50% contained": "Contenuto a meno del 50%", "50–99% contained": "Contenuto al 50–99%", "Fully contained": "Completamente contenuto", "Colour shows reported containment. Perimeters are simplified to about 100 m.": "Il colore indica il contenimento riportato. I perimetri sono semplificati a circa 100 m.", @@ -996,8 +996,8 @@ "World": "World", "overview": "panoramica", "cloud unknown": "nuvolosità sconosciuta", - "{percent}% scene cloud": "{percent}% di nubi nella scena", - "{min}–{max}% scene cloud": "{min}–{max}% di nubi nella scena", + "{percent}% scene cloud": "{percent}% di nuvole nella scena", + "{min}–{max}% scene cloud": "{min}–{max}% di nuvole nella scena", "Comparison in use by another scene": "Confronto in uso da un'altra scena", "Esri map unavailable · no swipe": "Mappa Esri non disponibile · niente confronto", "Swipe needs a globe map": "Il confronto richiede una mappa del globo", @@ -1016,7 +1016,7 @@ "Landsat 8/9": "Landsat 8/9", "Landsat 8/9 via HLS": "Landsat 8/9 tramite HLS", "Daily overview": "Panoramica giornaliera", - "Box edges must be finite": "I bordi del riquadro devono essere finiti", + "Box edges must be finite": "Le coordinate dei bordi del riquadro devono essere numeri finiti", "Longitudes must be within ±180°": "Le longitudini devono essere entro ±180°", "Select one side of the dateline": "Seleziona un solo lato della linea del cambio di data", "Box must enclose an area": "Il riquadro deve racchiudere un'area", @@ -1092,9 +1092,9 @@ "UNAVAILABLE · {source} · Roads unavailable": "NON DISPONIBILE · {source} · Strade non disponibili", "Roads: {source}": "Strade: {source}", "TomTom roads unavailable while the traffic service is unreachable": "Strade TomTom non disponibili mentre il servizio traffico è irraggiungibile", - "Hybrid unavailable while the traffic service is unreachable": "Ibrido non disponibile mentre il servizio traffico è irraggiungibile", + "Hybrid unavailable while the traffic service is unreachable": "Modalità Ibrido non disponibile mentre il servizio traffico è irraggiungibile", "TomTom roads need a TomTom key": "Le strade TomTom richiedono una chiave TomTom", - "Hybrid needs a TomTom key": "Ibrido richiede una chiave TomTom", + "Hybrid needs a TomTom key": "La modalità Ibrido richiede una chiave TomTom", "Local surface still loading": "Superficie locale ancora in caricamento", "Partial coverage": "Copertura parziale", "Detailed roads unavailable": "Strade dettagliate non disponibili", @@ -1109,18 +1109,18 @@ "TomTom daily budget reached": "Budget giornaliero TomTom esaurito", "TomTom upstream unreachable": "Servizio TomTom irraggiungibile", "TomTom flow unavailable": "Flusso TomTom non disponibile", - "SIMULATED — {reason}": "SIMULATO — {reason}", + "SIMULATED — {reason}": "SIMULATO: {reason}", "Syncing flow · Roads: {source}": "Sincronizzazione flusso · Strade: {source}", "LIVE · Roads: {source} · Roads without flow hidden": "LIVE · Strade: {source} · Strade senza flusso nascoste", "LIVE · Roads: {source} · No flow roads in view": "LIVE · Strade: {source} · Nessuna strada con flusso in vista", "LIVE · Roads: {source} · Flow {percent}%": "LIVE · Strade: {source} · Flusso {percent}%", "SIMULATED · Roads: {source} · Flow {percent}%": "SIMULATO · Strade: {source} · Flusso {percent}%", "Syncing flow · Roads: OpenStreetMap · Flow: TomTom · Unmatched: simulated": "Sincronizzazione flusso · Strade: OpenStreetMap · Flusso: TomTom · Non abbinate: simulate", - "LIVE · Roads: OpenStreetMap · Flow: TomTom · {percent}% cov · Unmatched: simulated": "LIVE · Strade: OpenStreetMap · Flusso: TomTom · {percent}% cop · Non abbinate: simulate", - "LIVE · Roads: OpenStreetMap · Flow: TomTom · {percent}% cov": "LIVE · Strade: OpenStreetMap · Flusso: TomTom · {percent}% cop", + "LIVE · Roads: OpenStreetMap · Flow: TomTom · {percent}% cov · Unmatched: simulated": "LIVE · Strade: OpenStreetMap · Flusso: TomTom · {percent}% cop. · Non abbinate: simulate", + "LIVE · Roads: OpenStreetMap · Flow: TomTom · {percent}% cov": "LIVE · Strade: OpenStreetMap · Flusso: TomTom · {percent}% cop.", "SIMULATED · Roads: OpenStreetMap · Flow: TomTom (no matches)": "SIMULATO · Strade: OpenStreetMap · Flusso: TomTom (nessuna corrispondenza)", - "SIMULATED — traffic service unreachable": "SIMULATO — servizio traffico irraggiungibile", - "SIMULATED — add TomTom key for live": "SIMULATO — aggiungi la chiave TomTom per il live", + "SIMULATED — traffic service unreachable": "SIMULATO: servizio traffico irraggiungibile", + "SIMULATED — add TomTom key for live": "SIMULATO: aggiungi la chiave TomTom per il live", "OpenFreeMap tiles rate-limited": "Tile OpenFreeMap con limite di richieste", "OpenFreeMap tiles timed out": "Tile OpenFreeMap in timeout", "OpenFreeMap tiles unavailable": "Tile OpenFreeMap non disponibili", @@ -1209,7 +1209,7 @@ "loading": "caricamento", "Observation: unavailable": "Osservazione: non disponibile", "Contiguous US · gaps ≠ no rain": "USA contigui · lacune ≠ assenza di pioggia", - "Americas + Pacific · not individual strikes": "Americhe + Pacifico · non singole fulminazioni", + "Americas + Pacific · not individual strikes": "Americhe + Pacifico · non singoli fulmini", "Color: strikes/km²/min ×10³": "Colore: fulmini/km²/min ×10³", "60°S–60°N · typically 2–3 h delayed": "60°S–60°N · di solito 2–3 h di ritardo", "North America · infrared imagery": "Nord America · immagini all'infrarosso", @@ -1231,11 +1231,11 @@ "Hourly global mosaic; usually 2–3 hours delayed": "Mosaico globale orario; di solito 2–3 ore di ritardo", "GOES regional clouds; approximately 5-minute updates": "Nuvole regionali GOES; aggiornamenti circa ogni 5 minuti", "Clouds only": "Solo nuvole", - "Apply the full cloud brightness key; 100% filter strength": "Applica l'intera scala di luminosità delle nuvole; intensità del filtro 100%", + "Apply the full cloud brightness key; 100% filter strength": "Applica al massimo il filtro basato sulla luminosità delle nuvole; intensità del filtro 100%", "Full": "Completa", "Show the complete infrared image; 0% filter strength": "Mostra l'intera immagine all'infrarosso; intensità del filtro 0%", "Soft": "Tenue", - "Vivid": "Vivido", + "Vivid": "Vivida", "Image opacity; does not alter the observed values": "Opacità dell'immagine; non altera i valori osservati", "View US radar": "Vedi il radar USA", "View Americas & Pacific": "Vedi Americhe e Pacifico", @@ -1244,7 +1244,7 @@ "{value} dBZ radar reflectivity": "{value} dBZ di riflettività radar", "STALE · cached source metadata": "OBSOLETO · metadati della fonte in cache", "Map center is outside source coverage": "Il centro della mappa è fuori dalla copertura della fonte", - "NOAA/NWS 15-minute lightning density derived from Vaisala NLDN/GLD360. Coverage 110°E across the Pacific/Americas to 0°, 25°S–80°N. Not a live strike count, global coverage or a safety warning.": "Densità di fulmini a 15 minuti NOAA/NWS derivata da Vaisala NLDN/GLD360. Copertura da 110°E attraverso il Pacifico e le Americhe fino a 0°, 25°S–80°N. Non è un conteggio live delle fulminazioni, né una copertura globale né un avviso di sicurezza.", + "NOAA/NWS 15-minute lightning density derived from Vaisala NLDN/GLD360. Coverage 110°E across the Pacific/Americas to 0°, 25°S–80°N. Not a live strike count, global coverage or a safety warning.": "Densità di fulmini a 15 minuti NOAA/NWS derivata da Vaisala NLDN/GLD360. Copertura da 110°E attraverso il Pacifico e le Americhe fino a 0°, 25°S–80°N. Non è un conteggio live dei fulmini, né una copertura globale né un avviso di sicurezza.", "NOAA MRMS radar echoes indicate precipitation patterns, not rain rate, a storm warning or a future forecast. Native source approximately 1 km; display is limited to level 6. Frames use exact advertised observation times.": "Gli echi radar NOAA MRMS indicano la distribuzione delle precipitazioni, non l'intensità della pioggia, un avviso di tempesta o una previsione. Risoluzione nativa della fonte circa 1 km; la visualizzazione è limitata al livello 6. I fotogrammi usano gli orari esatti di osservazione dichiarati.", "GOES-19/18 longwave infrared Band 14 regional; NESDIS global longwave mosaic. Clouds only dims everything but bright, cold cloud tops; a brightness filter, not a cloud mask. Coverage and freshness differ by region.": "Infrarosso a onda lunga GOES-19/18 Banda 14 regionale; mosaico globale a onda lunga NESDIS. Solo nuvole attenua tutto tranne le sommità nuvolose fredde e luminose; è un filtro di luminosità, non una maschera delle nuvole. Copertura e aggiornamento variano per regione.", "REGION": "REGIONE", @@ -1457,7 +1457,7 @@ }, "{scene} / {pack}: {status}. File: {path}. {attribution} · {license}": "{scene} / {pack}: {status}. File: {path}. {attribution} · {license}", "Unavailable layers: {layers}": "Livelli non disponibili: {layers}", - "Uses registered content or linked media. Those external files are not included in a scene bundle. Their original notices still apply.": "Usa contenuti registrati o media collegati. Quei file esterni non sono inclusi nel pacchetto della scena. Valgono ancora le loro note originali.", + "Uses registered content or linked media. Those external files are not included in a scene bundle. Their original notices still apply.": "La scena usa contenuti registrati o media collegati. Quei file esterni non sono inclusi nel pacchetto della scena. Restano valide le loro note legali originali.", "{bytes} bundled bytes verified. Files stay in memory for this session. Reimport the bundle after reloading the app.": "{bytes} byte nel pacchetto verificati. I file restano in memoria per questa sessione. Reimporta il pacchetto dopo aver ricaricato l'app.", "Review scene import": "Rivedi l'importazione della scena", "Nothing is loaded or changed until you apply this file.": "Nulla viene caricato o modificato finché non applichi questo file.", @@ -1471,9 +1471,9 @@ "Anchors and data packs": "Ancore e pacchetti dati", "Shot camera, timing, packs and actions": "Camera, tempi, pacchetti e azioni dello scatto", "New anchor ID": "ID nuova ancora", - "Capture camera as anchor": "Cattura la camera come ancora", + "Capture camera as anchor": "Salva la posizione della camera come ancora", "Anchor added to draft": "Ancora aggiunta alla bozza", - "Set move start to current camera": "Imposta l'inizio del movimento sulla camera attuale", + "Set move start to current camera": "Usa la vista attuale come inizio del movimento", "Move added to draft; destination remains the shot camera": "Movimento aggiunto alla bozza; la destinazione resta la camera dello scatto", "Use ordinary flight": "Usa il volo normale", "Invalid shot JSON": "JSON dello scatto non valido", @@ -1646,7 +1646,7 @@ "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.": "Scorri automaticamente le pagine del briefing ogni 9 secondi (Segnali → Notizie → Locale). Lo scorrimento si interrompe quando passi sul pannello o lo selezioni. I dati dei segnali live si aggiornano comunque di continuo.", "ACQUIRING REGIONAL NEWS": "ACQUISIZIONE NOTIZIE REGIONALI", "REGIONAL NEWS UNAVAILABLE": "NOTIZIE REGIONALI NON DISPONIBILI", - "RESOLVING REGION": "RISOLUZIONE REGIONE", + "RESOLVING REGION": "IDENTIFICAZIONE REGIONE", "REGION UNAVAILABLE": "REGIONE NON DISPONIBILE", "NO RECENT LOCATION MATCHES": "NESSUNA CORRISPONDENZA RECENTE PER POSIZIONE", "{domain} · {age}": "{domain} · {age}", @@ -1661,7 +1661,7 @@ "ENABLE GLOBAL CONTEXT FOR PROXIMITY PINGS": "ATTIVA IL CONTESTO GLOBALE PER I PING DI PROSSIMITÀ", "CONTACT LOST · LAST KNOWN READOUT · NOT AN ALL-CLEAR": "CONTATTO PERSO · ULTIMA LETTURA NOTA · NON È UN VIA LIBERA", "CONTACT LOST · {subject}": "CONTATTO PERSO · {subject}", - "SUBJECT LEFT ITS FEED · READOUT HOLDING LAST KNOWN": "IL SOGGETTO HA LASCIATO IL FEED · LETTURA ALL'ULTIMO VALORE NOTO", + "SUBJECT LEFT ITS FEED · READOUT HOLDING LAST KNOWN": "IL SOGGETTO NON È PIÙ NEL FEED · LETTURA FERMA ALL'ULTIMO VALORE NOTO", "{cohort} · {contact}": "{cohort} · {contact}", "NO AVAILABLE EXAMPLE": "NESSUN ESEMPIO DISPONIBILE", "{cohort}, Unavailable": "{cohort}, non disponibile", @@ -1699,7 +1699,7 @@ "Noir": "Noir", "Snow": "Neve", "Current cockpit vision style: {style}. Activate for next style.": "Stile di visione attuale del cockpit: {style}. Attiva per lo stile successivo.", - "Current style: {style} — click for next": "Stile attuale: {style} — clic per il successivo", + "Current style: {style} — click for next": "Stile attuale: {style}. Clic per il successivo", "Collapse Contact panel": "Comprimi il pannello Contatto", "Expand Contact panel": "Espandi il pannello Contatto", "Collapse contact panel": "Comprimi pannello contatto", @@ -1848,7 +1848,7 @@ "{state} · {source} · {detail}": "{state} · {source} · {detail}", "never": "mai", "{source} · {loadingLabel}": "{source} · {loadingLabel}", - "{accepted} of {raw} records accepted": "{accepted} record accettati su {raw}", + "{accepted} of {raw} records accepted": "Record accettati: {accepted} su {raw}", "incomplete snapshot": "snapshot incompleto", "{state} · {source} · {detail} · {ago}": "{state} · {source} · {detail} · {ago}", "{state} · {source} · {ago} · retrying in {seconds}s": "{state} · {source} · {ago} · nuovo tentativo tra {seconds}s", @@ -1963,7 +1963,7 @@ "RECONCILE": "RICONCILIA", "DISABLE": "DISATTIVA", "ENABLE": "ATTIVA", - "Reconcile Radio — lifecycle uncertain": "Riconcilia la Radio — ciclo di vita incerto", + "Reconcile Radio — lifecycle uncertain": "Riconcilia la Radio: ciclo di vita incerto", "Disable Radio": "Disattiva la Radio", "Enable Radio": "Attiva la Radio", "{category} ({count})": "{category} ({count})", @@ -2036,8 +2036,8 @@ "coverage|partial": "parziale", "unknown": "sconosciuta", "no imagery": "nessuna immagine", - "{percent}% cloud": "{percent}% di nubi", - "{min}–{max}% cloud": "{min}–{max}% di nubi", + "{percent}% cloud": "{percent}% di nuvole", + "{min}–{max}% cloud": "{min}–{max}% di nuvole", "NO BOX": "NESSUN RIQUADRO", "SEARCHING": "RICERCA", "{count} DAYS": { @@ -2066,7 +2066,7 @@ "Drag a box on the map (Esc cancels)": "Trascina un riquadro sulla mappa (Esc annulla)", "USE VIEW": "USA VISTA", "Use the current view as the box": "Usa la vista attuale come riquadro", - "Forget the box and its images": "Dimentica il riquadro e le sue immagini", + "Forget the box and its images": "Cancella il riquadro e le sue immagini", "START HERE": "INIZIA DA QUI", "Checking": "Verifica", "PREVIEW": "ANTEPRIMA", @@ -2109,7 +2109,7 @@ "basemap": "mappa di base", "Recent imagery against the basemap divider": "Divisore tra immagini recenti e mappa di base", "Recent imagery A and B divider": "Divisore tra immagini recenti A e B", - "{before} {left} percent, {after} {right} percent": "{before} {left} percento, {after} {right} percento", + "{before} {left} percent, {after} {right} percent": "{before} {left} per cento, {after} {right} per cento", "Export failed · {error}": "Esportazione non riuscita · {error}", "Scene action failed": "Azione sulla scena non riuscita", "New scene name": "Nome della nuova scena", @@ -2148,7 +2148,7 @@ "Shared {subject} could not be restored — feed unavailable": "Impossibile ripristinare la condivisione di {subject}: feed non disponibile", "Shared {subject} is unavailable": "La condivisione di {subject} non è disponibile", "{id} isn't reporting now — showing where it was last seen": "{id} non sta trasmettendo ora: viene mostrata l'ultima posizione nota", - "{id} isn't reporting now — showing where it was at {time}": "{id} non sta trasmettendo ora: viene mostrata la posizione alle {time}", + "{id} isn't reporting now — showing where it was at {time}": "{id} non sta trasmettendo ora: viene mostrata l'ultima posizione nota ({time})", "This share link can't be opened": "Impossibile aprire questo link di condivisione", "Shared vessel is unavailable": "La nave condivisa non è disponibile", "ACQUIRING": "ACQUISIZIONE", @@ -2414,10 +2414,10 @@ "standard": "standard", "mini": "mini", "COST UNKNOWN": "COSTO SCONOSCIUTO", - "ChatGPT OAuth session: {responses} response(s), {input} input and {output} output tokens, {captions} caption transcription(s) reported.": "Sessione ChatGPT OAuth: {responses} risposta/e, {input} token di input e {output} di output, {captions} trascrizione/i di sottotitoli riportate.", + "ChatGPT OAuth session: {responses} response(s), {input} input and {output} output tokens, {captions} caption transcription(s) reported.": "Sessione ChatGPT OAuth. Risposte: {responses}; token di input: {input}; token di output: {output}; trascrizioni dei sottotitoli riportate: {captions}.", "USD cost and the API spend cap are unavailable for this auth mode.": "Il costo in USD e il limite di spesa API non sono disponibili per questa modalità di autenticazione.", "Usage is incomplete because a response was still in flight when the session ended.": "L'utilizzo è incompleto perché una risposta era ancora in corso quando la sessione è terminata.", - "Estimated session cost on {modelId} — {responses} response(s). Warns at {warn}, ends the session at {cap}.": "Costo stimato della sessione su {modelId}: {responses} risposta/e. Avviso a {warn}, la sessione termina a {cap}.", + "Estimated session cost on {modelId} — {responses} response(s). Warns at {warn}, ends the session at {cap}.": "Costo stimato della sessione su {modelId}. Risposte: {responses}. Avviso a {warn}; la sessione termina a {cap}.", "Estimate is incomplete — a response was still in flight when the session ended, so its usage was never reported.": "Stima incompleta: una risposta era ancora in corso quando la sessione è terminata, quindi il suo utilizzo non è mai stato riportato.", "STANDARD": "STANDARD", "{tier} applies next session": "{tier} si applica alla prossima sessione", @@ -2519,16 +2519,16 @@ "At least {items}": "Almeno {items}", "{items} {scope}": "{items} {scope}", "last 24 h": "ultime 24 h", - "past 30 d and upcoming": "ultimi 30 g e prossimi", + "past 30 d and upcoming": "ultimi 30 g e in programma", "the flights layer loads by viewport": "il livello voli si carica in base alla vista", "distance is ground distance, not overhead": "la distanza è misurata al suolo fino al punto subsatellitare, non fino al satellite", "the count is a lower bound because at least one layer reached its retained limit.": "il conteggio è un limite inferiore perché almeno un livello ha raggiunto il suo limite di conservazione.", "{label} off": "{label}: disattivato", - "{label} loading": "{label} in caricamento", - "{label} error": "{label} in errore", - "counted the first {returned} loaded records": "contati i primi {returned} record caricati", - "counted {returned} of {total} loaded records": "contati {returned} di {total} record caricati", - "{layers} just turned on — still loading, counts will rise": "{layers} appena attivati: ancora in caricamento, i conteggi aumenteranno", + "{label} loading": "{label}: in caricamento", + "{label} error": "{label}: errore", + "counted the first {returned} loaded records": "conteggio limitato ai primi record caricati: {returned}", + "counted {returned} of {total} loaded records": "record conteggiati: {returned} su {total} caricati", + "{layers} just turned on — still loading, counts will rise": "Attivazione recente: {layers}. Caricamento ancora in corso: i conteggi aumenteranno", "Contacts panel snapshot at {time} — the same retained cohort supplies the card, speech, and follow-up memory": "Snapshot del pannello Contatti alle {time}: lo stesso gruppo conservato fornisce la scheda, il parlato e la memoria per le domande successive", "Contacts panel snapshot — the same retained cohort supplies the card, speech, and follow-up memory": "Snapshot del pannello Contatti: lo stesso gruppo conservato fornisce la scheda, il parlato e la memoria per le domande successive", "Fly below {km} km to a covered region": "Scendi sotto {km} km su una regione coperta", @@ -2630,7 +2630,7 @@ "many": "Segnati {count} di luoghi", "other": "Segnati {count} luoghi" }, - "Nothing marked": "Nulla di segnato", + "Nothing marked": "Nessun luogo segnato", "Not found: {places}": "Non trovati: {places}", "Tracing outlines": "Tracciamento dei contorni", "Frame flights": "Inquadra i voli", @@ -2706,7 +2706,7 @@ "Previous cockpit vision style": "Stile di visione precedente del cockpit", "Previous vision style": "Stile di visione precedente", "Current cockpit vision style: NORMAL. Activate for next style.": "Stile di visione attuale del cockpit: NORMALE. Attiva per lo stile successivo.", - "Current style: NORMAL — click for next": "Stile attuale: NORMALE — clic per il successivo", + "Current style: NORMAL — click for next": "Stile attuale: NORMALE. Clic per il successivo", "CURRENT": "ATTUALE", "Next cockpit vision style": "Stile di visione successivo del cockpit", "Next vision style": "Stile di visione successivo", @@ -2798,7 +2798,7 @@ "Open detailed Radio controls": "Apri i controlli Radio dettagliati", "Previous station": "Stazione precedente", "Next station": "Stazione successiva", - "Compact Radio volume": "Volume Radio compatto", + "Compact Radio volume": "Volume Radio (controlli compatti)", "Expand panel": "Espandi pannello", "Context mode": "Modalità contesto", "CONTACTS": "CONTATTI", @@ -2810,7 +2810,7 @@ "SEARCH NEARBY SITES": "CERCA SITI VICINI", "Reclassify tracked contact as TR-3B": "Riclassifica il contatto tracciato come TR-3B", "CONTACTS CONTEXT OFF": "CONTESTO CONTATTI DISATTIVATO", - "SELECT CONTACTS TO LOAD OBSERVED / MAPPED PROXIMITY": "SELEZIONA CONTATTI PER CARICARE LA PROSSIMITÀ OSSERVATA / MAPPATA", + "SELECT CONTACTS TO LOAD OBSERVED / MAPPED PROXIMITY": "SELEZIONA CONTATTI PER CARICARE I DATI OSSERVATI / MAPPATI NELLE VICINANZE", "Available Space Missions": "Missioni spaziali disponibili", "AVAILABLE MISSIONS": "MISSIONI DISPONIBILI", "SELECT A MISSION TO INSPECT": "SELEZIONA UNA MISSIONE DA ESAMINARE", From beacb6d9d3a5114256e3ff663a7323f39fe54beb Mon Sep 17 00:00:00 2001 From: German Khokhlov Date: Wed, 28 Oct 2026 22:38:32 +0400 Subject: [PATCH 35/83] i18n(uk): apply review round 2 Co-Authored-By: Claude Opus 5.5 --- docs/translations/uk.md | 16 ++- src/i18n/locales/uk.json | 240 +++++++++++++++++++-------------------- 2 files changed, 133 insertions(+), 123 deletions(-) diff --git a/docs/translations/uk.md b/docs/translations/uk.md index 765be0233..fcd086f98 100644 --- a/docs/translations/uk.md +++ b/docs/translations/uk.md @@ -8,7 +8,7 @@ Translation source: meirm (#312). - Address the user with polite imperatives: «Натисніть», «Увімкніть», «Спробуйте ще раз». - Sentence case, not Title Case: "Live Flights" → «Рейси онлайн». -- Ukrainian norms, not Russian calques: «у радіусі», «за посиланням», «надто довгий», «потім», «вигляд» (view), «стеження» (tracking); prepositions alternate у/в and і/й by euphony. +- Ukrainian norms, not Russian calques: «у радіусі», «за посиланням», «надто довгий», «потім», «вигляд» (a camera view: «вигляд згори»), «стеження» (tracking); prepositions alternate у/в and і/й by euphony. - The apostrophe is always ʼ (U+02BC): обʼєкт, звʼязок, памʼять. Not ' or ’. - Quotes inside Ukrainian text are «ялинки»; a button or layer name inside a sentence goes in them: Увімкніть «Вуличні знімки». - In short labels, a standard abbreviation with a period beats a wrapped line: ПОПЕР., ДАЛЬН., КАЛІБР. @@ -35,7 +35,7 @@ A `tn()` entry needs four forms. `Intl.PluralRules('uk')` picks: | layer / data layer | шар / шар даних | | feed | потік даних (short: потік) | | source / data source | джерело / джерело даних | -| LIVE (status) / live data | ОНЛАЙН / у реальному часі | +| LIVE (status) / live data | ОНЛАЙН / у реальному часі (status chip: ДАНІ ОНЛАЙН) | | SIMULATED / SYNTHETIC | ІМІТАЦІЯ | | stale / degraded / unavailable | застарів / з перебоями (chip: ПЕРЕБОЇ) / недоступний | | retry | повтор | @@ -48,7 +48,7 @@ A `tn()` entry needs four forms. `Intl.PluralRules('uk')` picks: | launch (rocket) / space mission | запуск / космічна місія | | ascent (rocket) / booster FLIGHT {n} | виведення / ПОЛІТ {n} (not рейс) | | contact / tracking | контакт / стеження | -| installation, site / mapped | обʼєкт / нанесений на карту | +| installation, site / mapped | обʼєкт / нанесений (обʼєкт, контакт) | | camera / CCTV camera | камера / камера CCTV | | earthquake / active fire / fire perimeter | землетрус / активна пожежа / контур пожежі | | advisory (NHC/CPHC cyclone) | зведення | @@ -81,3 +81,13 @@ A `tn()` entry needs four forms. `Intl.PluralRules('uk')` picks: | pitch (CCTV camera pose) | нахил | | traffic (road traffic layer) | дорожній рух | | phosphor (CRT) | люмінофор | +| view (map extent) / view centre / in view | видима область (карти) / центр карти / у кадрі | +| select (verb) / selected | вибрати / вибраний (not обрати) | +| ping (cockpit proximity contacts) | контакт | +| merge (turn-by-turn) / on ramp | влитися в потік / вʼїзд (off ramp: зʼїзд) | +| watch (Earth/Orbital Watch) | спостереження | +| timeout | тайм-аут | +| icon | значок (not іконка) | +| run (scene playback) / RUN LOG | відтворення / ЖУРНАЛ ВІДТВОРЕННЯ (запуск is a rocket launch) | +| Preview (voice panel replies) | відповіді | +| Marine (radio tag) / pleasure craft | море (not флот) / прогулянкове судно | diff --git a/src/i18n/locales/uk.json b/src/i18n/locales/uk.json index 6467d0996..62a46aa89 100644 --- a/src/i18n/locales/uk.json +++ b/src/i18n/locales/uk.json @@ -57,7 +57,7 @@ "SOURCE GEOCONFIRMED": "МІСЦЕ ЗЙОМКИ ПІДТВЕРДЖЕНО", "2021 historical reference versus 2026 post-event imagery; changes are cumulative and include the July 2025 Rasuwagadhi flood. Schematic downstream progression, not modeled arrival time; not an official hazard model.": "Історичний знімок 2021 року порівняно зі знімками 2026 року після події; зміни показано сумарно за весь період, вони охоплюють і паводок у Rasuwagadhi в липні 2025 року. Схематичне просування вниз за течією, а не змодельований час добігання паводка; не офіційна модель небезпеки.", "Immediate collapse viewpoint": "Точка огляду біля місця обвалу", - "Collapse viewpoint": "Вигляд на обвал", + "Collapse viewpoint": "Точка огляду обвалу", "Debris-dammed lake": "Озеро, загачене уламками", "Dammed lake": "Загачене озеро", "Second landslide": "Другий зсув", @@ -78,7 +78,7 @@ "X embed could not load.": "Не вдалося завантажити вбудовування X.", "X embed timed out.": "Минув час очікування вбудовування X.", "UNAVAILABLE": "НЕДОСТУПНО", - "TIMEOUT": "ТАЙМАУТ", + "TIMEOUT": "ТАЙМ-АУТ", "BLOCKED": "ЗАБЛОКОВАНО", "SOURCE": "ДЖЕРЕЛО", "Facebook embed unavailable. The post may be private, removed, region-restricted, or blocked.": "Вбудовування Facebook недоступне. Допис може бути приватним, видаленим, обмеженим за регіоном або заблокованим.", @@ -101,15 +101,15 @@ "YOUTUBE {state} · OPEN ORIGINAL": "YOUTUBE {state} · ВІДКРИТИ ОРИГІНАЛ", "INITIATION": "ЗАРОДЖЕННЯ", "DAMMING": "ЗАГАТА", - "SECONDARY FAILURE": "ВТОРИННИЙ ПРОРИВ", + "SECONDARY FAILURE": "ПОВТОРНИЙ ЗСУВ", "BORDER ARRIVAL": "ДОСЯГНЕННЯ КОРДОНУ", "PROPAGATION": "ПОШИРЕННЯ", "DOWNSTREAM PASSAGE": "ПРОХОДЖЕННЯ ВНИЗ ЗА ТЕЧІЄЮ", "CONSEQUENCE": "НАСЛІДКИ", "DOWNSTREAM CONSEQUENCE": "НАСЛІДКИ НИЖЧЕ ЗА ТЕЧІЄЮ", "EVIDENCE": "СВІДЧЕННЯ", - "{year} HISTORICAL REFERENCE": "{year} ІСТОРИЧНИЙ ЗНІМОК", - "{year} POST-EVENT": "{year} ПІСЛЯ ПОДІЇ", + "{year} HISTORICAL REFERENCE": "ІСТОРИЧНИЙ ЗНІМОК {year}", + "{year} POST-EVENT": "ПІСЛЯ ПОДІЇ {year}", "{count} GEOLOCATED SOURCE-MAP PLACEMENTS": { "one": "{count} ГЕОПРИВʼЯЗАНА МІТКА НА КАРТІ ДЖЕРЕЛ", "few": "{count} ГЕОПРИВʼЯЗАНІ МІТКИ НА КАРТІ ДЖЕРЕЛ", @@ -127,7 +127,7 @@ "Close event layer": "Закрити шар події", "OBSERVED IMAGERY": "ФАКТИЧНІ ЗНІМКИ", "SCHEMATIC CORRIDOR": "СХЕМАТИЧНИЙ КОРИДОР", - "2021 HISTORICAL REFERENCE / 2026 POST-EVENT": "2021 ІСТОРИЧНИЙ ЗНІМОК / 2026 ПІСЛЯ ПОДІЇ", + "2021 HISTORICAL REFERENCE / 2026 POST-EVENT": "ІСТОРИЧНИЙ ЗНІМОК 2021 / ПІСЛЯ ПОДІЇ 2026", "Historical reference and post-event image split": "Порівняння історичного знімка та знімка після події", "RECONSTRUCTION CLOCK": "ЧАС РЕКОНСТРУКЦІЇ", "Schematic downstream progression": "Схематичне просування вниз за течією", @@ -257,14 +257,14 @@ "Naval base": "Військово-морська база", "Firing range": "Полігон", "Military land": "Військова територія", - "Mapped installation": "Обʼєкт на карті", + "Mapped installation": "Нанесений обʼєкт", "Military area": "Військова зона", "flight": "рейс", "military flight": "військовий рейс", "satellite": "супутник", "feed unavailable": "потік даних недоступний", "feed stale": "потік даних застарів", - "observed or mapped nearby context": "спостережений або нанесений контекст поблизу", + "observed or mapped nearby context": "дані про спостережені або нанесені обʼєкти поблизу", "no observed or mapped objects in current feeds": "немає спостережених або нанесених обʼєктів у поточних потоках даних", "Draw": "Малювання", "Directions": "Маршрути", @@ -280,12 +280,12 @@ "COMMS": "ЗВʼЯЗОК", "Broadband constellation shell — shown only in DENSE mode": "Оболонка широкосмугового угруповання — лише в режимі ЩІЛЬНО", "FISHING": "РИБАЛЬСЬКЕ", - "TOWING": "БУКСИРУВАННЯ", + "TOWING": "БУКСИРУВАЛЬНЕ", "DREDGER": "ЗЕМСНАРЯД", "DIVE OPS": "ВОДОЛАЗНЕ", "MILITARY": "ВІЙСЬКОВЕ", "SAILING": "ВІТРИЛЬНЕ", - "PLEASURE": "ПРОГУЛКОВЕ", + "PLEASURE": "ПРОГУЛЯНКОВЕ", "PILOT": "ЛОЦМАНСЬКЕ", "SAR": "РЯТУВАЛЬНЕ", "TUG": "БУКСИР", @@ -303,13 +303,13 @@ "Source configured; file checked when loaded": "Джерело налаштовано; файл буде перевірено під час завантаження", "Source unavailable": "Джерело недоступне", "ENVIRONMENTAL": "ДОВКІЛЛЯ", - "EARTH WATCH": "НАГЛЯД ЗА ЗЕМЛЕЮ", + "EARTH WATCH": "СПОСТЕРЕЖЕННЯ ЗА ЗЕМЛЕЮ", "ACTIVE EVENTS": "АКТИВНІ ПОДІЇ", "Starting live contacts…": "Запуск контактів у реальному часі…", "Opening space missions…": "Відкриття космічних місій…", "Scanning active events…": "Сканування активних подій…", "Live earthquakes and active fires, from USGS and NASA": "Землетруси в реальному часі й активні пожежі від USGS та NASA", - "It feels like a forbidden cockpit—then you realize the sources are public and the data is real.": "Немов заборонена кабіна — а потім ви усвідомлюєте: джерела публічні, а дані — справжні.", + "It feels like a forbidden cockpit—then you realize the sources are public and the data is real.": "Наче ви потрапили до секретної кабіни — а потім розумієте: джерела відкриті, а дані — справжні.", "Working…": "Працюємо…", "Could not open that mission{detail}. Retry or explore manually.": "Не вдалося відкрити цю місію{detail}. Повторіть спробу або дослідіть вручну.", "This browser is blocking storage, so that could not be saved.": "Цей браузер блокує сховище, тож зберегти не вдалося.", @@ -381,7 +381,7 @@ "{name} may only contain printable characters with no spaces": "{name}: допустимі лише друковані символи без пробілів", "{name} contains a character that is not valid in a key (#, quotes, $, \\, or backtick)": "{name}: недопустимий для ключа символ (#, лапки, $, \\ або зворотний апостроф)", "{name} is configured outside Provider Settings and can only be changed where it was set": "{name}: задано поза «Налаштуваннями постачальників», змінити його можна лише там, де його задали", - "The key was not saved: could not restrict the credential file to your account; nothing was saved": "Ключ не збережено: не вдалося закрити файл облікових даних від усіх, крім вашого облікового запису; нічого не збережено", + "The key was not saved: could not restrict the credential file to your account; nothing was saved": "Ключ не збережено: не вдалося обмежити доступ до файлу облікових даних лише вашим обліковим записом; нічого не збережено", "The key was not saved: the existing configuration could not be read, so nothing was changed": "Ключ не збережено: не вдалося прочитати поточну конфігурацію, тому нічого не змінено", "Could not write the {store} store": "Не вдалося записати сховище {store}", "Save failed ({status}).": "Не вдалося зберегти ({status}).", @@ -446,7 +446,7 @@ "many": "{count} станцій передають дані", "other": "{count} станції передають дані" }, - "Highest air-quality readings in view": "Найвищі показники якості повітря в полі зору", + "Highest air-quality readings in view": "Найвищі значення індексу якості повітря в кадрі", "Low": "Низький", "Low health risk": "Низький ризик для здоровʼя", "Moderate": "Помірний", @@ -496,14 +496,14 @@ "CONTEXT READY": "КОНТЕКСТ ГОТОВИЙ", "GLOBAL CONTEXT OFF": "ГЛОБАЛЬНИЙ КОНТЕКСТ ВИМК.", "SELECT A FLIGHT, VESSEL, OR MAPPED INSTALLATION": "ВИБЕРІТЬ ЛІТАК, СУДНО ЧИ НАНЕСЕНИЙ ОБʼЄКТ", - "ENABLE TO LOAD OBSERVED / MAPPED PROXIMITY": "УВІМКНІТЬ, ЩОБ ЗАВАНТАЖИТИ СПОСТЕРЕЖЕНЕ / НАНЕСЕНЕ ПОБЛИЗУ", + "ENABLE TO LOAD OBSERVED / MAPPED PROXIMITY": "УВІМКНІТЬ, ЩОБ ЗАВАНТАЖИТИ СПОСТЕРЕЖЕНІ / НАНЕСЕНІ ОБʼЄКТИ ПОБЛИЗУ", "Unavailable": "Недоступно", "Focus {label}": "Фокус: {label}", "Global Context navigation": "Навігація глобального контексту", - "Previous — prior visited contact in the 250 km window": "Назад — попередній відвіданий контакт у вікні 250 км", + "Previous — prior visited contact in the 250 km window": "Назад — попередній переглянутий контакт у радіусі 250 км", "PREVIOUS": "НАЗАД", "FOCUS": "ФОКУС", - "Next — nearest unvisited contact in the 250 km window": "Далі — найближчий невідвіданий контакт у вікні 250 км", + "Next — nearest unvisited contact in the 250 km window": "Далі — найближчий ще не переглянутий контакт у радіусі 250 км", "NEXT": "ДАЛІ", "Named areas ({n})": "Іменовані зони ({n})", "{distance} FLIGHT / VESSEL WINDOW": "РАДІУС РЕЙСІВ / СУДЕН {distance}", @@ -516,7 +516,7 @@ "BRG {value}°": "ПЕЛ. {value}°", "BRG —": "ПЕЛ. —", "CRS {value}°": "ШК {value}°", - "CURRENT VIEWPORT ONLY": "ЛИШЕ ПОТОЧНА ОБЛАСТЬ ОГЛЯДУ", + "CURRENT VIEWPORT ONLY": "ЛИШЕ ВИДИМА ОБЛАСТЬ", "WITHIN {km} KM": "У РАДІУСІ {km} КМ", "Flights": "Рейси", "Military flights": "Військові рейси", @@ -546,7 +546,7 @@ "VIEWSHED": "ЗОНА ВИДИМОСТІ", "CAL {value}": "КАЛІБР. {value}", "SRC {value}": "ДЖЕР. {value}", - "{value} CONTEXT": "{value} КОНТЕКСТ", + "{value} CONTEXT": "КОНТЕКСТ: {value}", "{spec} · SPECS: CCTV-DATABASE.COM": "{spec} · ХАРАКТЕРИСТИКИ: CCTV-DATABASE.COM", "Atlantic and eastern/central North Pacific; not worldwide cyclone coverage.": "Атлантика та східна/центральна частина північного Тихого океану; покриття циклонів не глобальне.", "Cyclone advisories unavailable": "Зведення про циклони недоступні", @@ -570,7 +570,7 @@ "other": "{count} активного шторму" }, "Position as of {time}": "Положення на {time}", - "Maximum sustained wind: {wind} · Pressure: {pressure}": "Макс. стійкий вітер: {wind} · Тиск: {pressure}", + "Maximum sustained wind: {wind} · Pressure: {pressure}": "Макс. стала швидкість вітру: {wind} · Тиск: {pressure}", "{name} · {classification} · Advisory {number} · issued {time}": "{name} · {classification} · Зведення № {number} · випущено {time}", "No active NHC/CPHC systems": "Немає активних систем NHC/CPHC", "Advisories unavailable": "Зведення недоступні", @@ -590,7 +590,7 @@ "BIKE": "ВЕЛО", "Bike": "Велосипедом", "rate limited": "перевищено ліміт запитів", - "routing service is rate limited": "сервіс маршрутизації перевищив ліміт запитів", + "routing service is rate limited": "перевищено ліміт запитів до сервісу маршрутизації", "route leg too long": "ділянка маршруту надто довга", "route too long": "маршрут надто довгий", "{error} — try again in a moment": "{error} — спробуйте ще раз трохи згодом", @@ -611,7 +611,7 @@ "fork direction|slightly right": "трохи правіше", "fork direction|sharply left": "лівіше", "fork direction|sharply right": "правіше", - "fork direction|straight": "прямо", + "fork direction|straight": "прямого напрямку", "lane direction|left": "ліву", "lane direction|right": "праву", "lane direction|slightly left": "ліву", @@ -646,16 +646,16 @@ "Keep {direction} at the fork": "На розвилці тримайтеся {direction}", "Continue at the fork onto {road}": "На розвилці продовжуйте рух на {road}", "Continue at the fork": "На розвилці продовжуйте рух", - "Merge {direction} onto {road}": "Перешикуйтеся {direction} на {road}", - "Merge {direction}": "Перешикуйтеся {direction}", + "Merge {direction} onto {road}": "Влийтеся в потік {direction} на {road}", + "Merge {direction}": "Влийтеся в потік {direction}", "Merge onto {road}": "Виїжджайте на {road}", - "maneuver|Merge": "Перешикуйтеся", - "Take the ramp on the {direction} onto {road}": "Зʼїжджайте {direction} на {road}", - "Take the ramp on the {direction}": "Зʼїжджайте {direction}", - "Take the ramp {direction} onto {road}": "Зʼїжджайте {direction} на {road}", - "Take the ramp {direction}": "Зʼїжджайте {direction}", - "Take the ramp onto {road}": "Скористайтеся зʼїздом на {road}", - "Take the ramp": "Скористайтеся зʼїздом", + "maneuver|Merge": "Влийтеся в потік", + "Take the ramp on the {direction} onto {road}": "Вʼїжджайте {direction} на {road}", + "Take the ramp on the {direction}": "Вʼїжджайте {direction}", + "Take the ramp {direction} onto {road}": "Вʼїжджайте {direction} на {road}", + "Take the ramp {direction}": "Вʼїжджайте {direction}", + "Take the ramp onto {road}": "Скористайтеся вʼїздом на {road}", + "Take the ramp": "Скористайтеся вʼїздом", "Take the exit on the {direction} onto {road}": "Поверніть на зʼїзд {direction} на {road}", "Take the exit on the {direction}": "Поверніть на зʼїзд {direction}", "Take the exit {direction} onto {road}": "Поверніть на зʼїзд {direction} на {road}", @@ -782,9 +782,9 @@ "Regional sample · 250 nm radius · cells from visited views over 30 min": "Регіональна вибірка · радіус 250 мор. миль · комірки з переглянутих ділянок карти за 30 хв", "Retrying automatically at {time} UTC": "Автоматичний повтор о {time} UTC", "Retrying automatically after provider cooldown": "Автоматичний повтор після паузи постачальника", - "Updates automatically after pan or zoom and once a minute. The public feed covers a 250-nautical-mile circle around the view centre; zooming out does not make it a worldwide snapshot. Blank cells are outside sampled coverage or have insufficient observations.": "Оновлюється автоматично після зсуву чи масштабування карти та раз на хвилину. Публічний потік даних охоплює коло радіусом 250 морських миль навколо центру вигляду; у разі віддалення карта не стає знімком усього світу. Порожні комірки — поза охопленням вибірки або з недостатньою кількістю спостережень.", + "Updates automatically after pan or zoom and once a minute. The public feed covers a 250-nautical-mile circle around the view centre; zooming out does not make it a worldwide snapshot. Blank cells are outside sampled coverage or have insufficient observations.": "Оновлюється автоматично після зсуву чи масштабування карти та раз на хвилину. Публічний потік даних охоплює коло радіусом 250 морських миль навколо центру карти; у разі віддалення карта не стає знімком усього світу. Порожні комірки — поза охопленням вибірки або з недостатньою кількістю спостережень.", "Low-accuracy score = 100 × max(0, bad − 1) / total: one aircraft is discounted, so this is not the raw share. Cells need {aircraft} aircraft over {minutes} minutes. Navigation-integrity anomalies are not a detection of jamming or spoofing.": "Показник неточності = 100 × max(0, неточні − 1) / усього: один літак не враховується, тож це не пряма частка неточних літаків. Для комірки потрібно літаків: {aircraft} за {minutes} хв. Аномалії цілісності навігації не означають виявлення глушіння чи підміни сигналу.", - "GNSS snapshot needs a view anchor": "Для знімка GNSS потрібна опорна точка вигляду", + "GNSS snapshot needs a view anchor": "Для знімка GNSS потрібна опорна точка на карті", "GNSS feed rate limited (HTTP 429)": "Потік GNSS: перевищено ліміт запитів (HTTP 429)", "Malformed GNSS integrity snapshot": "Некоректний знімок цілісності GNSS", "GNSS integrity snapshot has no observation time": "У знімку цілісності GNSS немає часу спостереження", @@ -965,7 +965,7 @@ "Talk": "Розмовні", "Weather / Emergency": "Погода / Надзвичайні події", "Public Safety": "Громадська безпека", - "Aviation / Marine": "Авіація / Флот", + "Aviation / Marine": "Авіація / Море", "Traffic / Transit": "Рух / Транспорт", "Music": "Музика", "Other": "Інше", @@ -977,7 +977,7 @@ "radio|TALK": "РОЗМОВНІ", "radio|WEATHER": "ПОГОДА", "radio|SAFETY": "БЕЗПЕКА", - "radio|AIR / SEA": "АВІА / ФЛОТ", + "radio|AIR / SEA": "АВІА / МОРЕ", "radio|TRANSIT": "ТРАНСПОРТ", "radio|MUSIC": "МУЗИКА", "radio|OTHER": "ІНШЕ", @@ -1050,7 +1050,7 @@ "zoom in to a street to open {name}": "наблизьтеся до вулиці, щоб відкрити {name}", "loading coverage...": "завантаження покриття...", "No street-level imagery within {radius} m of that point": "У радіусі {radius} м від цієї точки вуличних знімків немає", - "No street-level imagery within {radius} m of the view centre": "У радіусі {radius} м від центру вигляду вуличних знімків немає", + "No street-level imagery within {radius} m of the view centre": "У радіусі {radius} м від центру карти вуличних знімків немає", "Zoom in to see street-level coverage": "Наблизьтеся, щоб побачити покриття вуличних знімків", "Point the camera at the ground for street-level coverage": "Спрямуйте камеру на землю, щоб побачити покриття вуличних знімків", "Coverage tile failed": "Не вдалося завантажити тайл покриття", @@ -1059,7 +1059,7 @@ "{name} street-level photo": "Вуличне фото {name}", "Previous photo in this sequence (←)": "Попереднє фото послідовності (←)", "Next photo in this sequence (→)": "Наступне фото послідовності (→)", - "Aim the middle of the view at a street to look for imagery there": "Наведіть центр вигляду на вулицю, щоб пошукати там знімки", + "Aim the middle of the view at a street to look for imagery there": "Розмістіть вулицю в центрі карти, щоб пошукати там знімки", "KEY REJECTED": "КЛЮЧ ВІДХИЛЕНО", "GOOGLE_MAPS_API_KEY is not set": "GOOGLE_MAPS_API_KEY не задано", "The Google Maps JavaScript API could not load": "Не вдалося завантажити Google Maps JavaScript API", @@ -1072,7 +1072,7 @@ "KartaView has no position for this photo": "KartaView не має координат цього фото", "The KartaView photo could not be loaded": "Не вдалося завантажити фото KartaView", "zoom in to see KartaView coverage": "наблизьтеся, щоб побачити покриття KartaView", - "no KartaView photos in view": "фото KartaView у полі зору немає", + "no KartaView photos in view": "фото KartaView у кадрі немає", "KartaView is rate-limiting requests — they resume on their own": "KartaView обмежує частоту запитів — вони відновляться самі", "KartaView’s photos here are archived and cannot be shown": "Фото KartaView тут в архіві, показати їх не можна", "KartaView did not filter this area in time — move the map to ask again": "KartaView не встиг відфільтрувати цю область — зсуньте карту, щоб запитати знову", @@ -1088,7 +1088,7 @@ "Coverage requests are being rate-limited — they resume on their own": "Запити покриття обмежено за частотою — вони відновляться самі", "The Panoramax photo could not be loaded": "Не вдалося завантажити фото Panoramax", "Panoramax is busy — coverage resumes on its own": "Panoramax перевантажений — покриття завантажиться само", - "no Panoramax photos in view": "фото Panoramax у полі зору немає", + "no Panoramax photos in view": "фото Panoramax у кадрі немає", "no Panoramax photos here match the filters": "тут немає фото Panoramax, що відповідають фільтрам", "Panoramax sent a map tile that could not be read": "Panoramax надіслав тайл карти, який не вдалося прочитати", "This Panoramax photo is no longer available": "Це фото Panoramax більше недоступне", @@ -1223,7 +1223,7 @@ "frame {index}/{total}": "кадр {index}/{total}", "loading": "завантаження", "Observation: unavailable": "Спостереження: недоступне", - "Contiguous US · gaps ≠ no rain": "Континентальні США · прогалини ≠ немає дощу", + "Contiguous US · gaps ≠ no rain": "48 суміжних штатів США · прогалини ≠ немає дощу", "Americas + Pacific · not individual strikes": "Америка + Тихий океан · не окремі розряди", "Color: strikes/km²/min ×10³": "Колір: розрядів/км²/хв ×10³", "60°S–60°N · typically 2–3 h delayed": "60° пд. ш.–60° пн. ш. · зазвичай затримка 2–3 год", @@ -1340,7 +1340,7 @@ "A location reading needs a loaded forecast and the Earth at the center of the view.": "Щоб отримати дані в точці, завантажте прогноз і розмістіть Землю в центрі екрана.", "Interpolated model forecast on an approximately 1° grid. Broad weather patterns, not a street-level measurement.": "Інтерпольований модельний прогноз на сітці близько 1°. Загальна погодна картина, а не вимірювання на рівні вулиці.", " · calm": " · штиль", - " from {direction}": " з {direction}", + " from {direction}": " із {direction}", "WIND AT {coordinates}": "ВІТЕР У ТОЧЦІ {coordinates}", "{model} · valid {time}": "{model} · на {time}", "Wind speed field unavailable": "Поле швидкості вітру недоступне", @@ -1361,7 +1361,7 @@ "Exit cockpit to fly to a camera": "Вийдіть із кабіни, щоб перелетіти до камери", "Exit cockpit to fly to a location": "Вийдіть із кабіни, щоб перелетіти до місця", "Exit cockpit to fly to a photo": "Вийдіть із кабіни, щоб перелетіти до фото", - "Exit cockpit to fly to a shared view": "Вийдіть із кабіни, щоб перелетіти до вигляду за посиланням", + "Exit cockpit to fly to a shared view": "Вийдіть із кабіни, щоб перелетіти до місця за посиланням", "Exit cockpit to fly to a target": "Вийдіть із кабіни, щоб перелетіти до цілі", "Exit cockpit to fly to a vessel": "Вийдіть із кабіни, щоб перелетіти до судна", "Exit cockpit to fly to a fire": "Вийдіть із кабіни, щоб перелетіти до пожежі", @@ -1402,7 +1402,7 @@ }, "Cannot capture shot: camera not ready": "Не вдалося зняти кадр: камера не готова", "Captured: {scene} / {shot}": "Знято: {scene} / {shot}", - "Select a shot first": "Спочатку оберіть кадр", + "Select a shot first": "Спочатку виберіть кадр", "Updated: {scene} / {shot}": "Оновлено: {scene} / {shot}", "Could not leave scene: {scene}": "Не вдалося вийти зі сцени: {scene}", "Seeked: {scene} / {shot}": "Перемотано: {scene} / {shot}", @@ -1430,7 +1430,7 @@ "Bhote Koshi Evidence Sequence": "Послідовність свідчень: Bhote Koshi", "Nepal Flood Incident": "Паводок у Непалі", "Global Flights Radar": "Глобальний радар польотів", - "Orbital Watch": "Орбітальний нагляд", + "Orbital Watch": "Орбітальне спостереження", "Thermal Threat Board": "Панель теплових загроз", "City Overload": "Міське перевантаження", "Omniscience Pullback": "Всевидющий відʼїзд", @@ -1559,13 +1559,13 @@ "Ironbow": "Ironbow", "unsaved CCTV calibration": "незбережене калібрування CCTV", "the open cockpit": "відкрита кабіна", - "Switching language reloads the page. This will be lost: {items}. Switch anyway?": "Зміна мови перезавантажить сторінку. Буде втрачено: {items}. Однаково змінити мову?", + "Switching language reloads the page. This will be lost: {items}. Switch anyway?": "Зміна мови перезавантажить сторінку. Буде втрачено: {items}. Усе одно змінити мову?", "VISUAL PRESETS": "ВІЗУАЛЬНІ ПРЕСЕТИ", "LOCATION": "РОЗТАШУВАННЯ", "CONTACTS — nearest planes · vessels · sites": "КОНТАКТИ — найближчі літаки · судна · обʼєкти", "SPACE MISSIONS — launches & orbital assets": "КОСМІЧНІ МІСІЇ — запуски та орбітальні апарати", "LIVE SIGNALS": "СИГНАЛИ ОНЛАЙН", - "Contacts could not complete the requested transition; try again": "Контакти не змогли завершити запитаний перехід; спробуйте ще раз", + "Contacts could not complete the requested transition; try again": "Режим «Контакти» не зміг завершити запитаний перехід; спробуйте ще раз", "CCTV layer unavailable": "Шар CCTV недоступний", "Link shared": "Посилання надіслано", "Link copied!": "Посилання скопійовано!", @@ -1645,11 +1645,11 @@ "other": "{count} камери завантажено · увімкніть CCTV, щоб активувати" }, "Enable CCTV to load camera intersections": "Увімкніть CCTV, щоб завантажити камери на перехрестях", - "Enable CCTV to start camera-linked intelligence summaries.": "Увімкніть CCTV, щоб почати зведення розвідки за камерами.", + "Enable CCTV to start camera-linked intelligence summaries.": "Увімкніть CCTV, щоб отримувати розвідувальні зведення за даними камер.", "No summary available.": "Зведення недоступне.", "loading frames": "завантаження кадрів", "camera grid ready": "сітка камер готова", - "Clearing selected data layers": "Очищення обраних шарів даних", + "Clearing selected data layers": "Очищення вибраних шарів даних", "Clear selected data layers": "Очистити вибрані шари даних", "CONDITIONS UNKNOWN": "УМОВИ НЕВІДОМІ", "CLEAR": "ЯСНО", @@ -1665,7 +1665,7 @@ "CYCLE ON": "ЦИКЛ УВІМКНЕНО", "CYCLE OFF": "ЦИКЛ ВИМКНЕНО", "Stop automatic page cycling. Previous, Next, and the SIG/NEWS/LOCAL tabs stay available.": "Зупинити автоматичне гортання сторінок. Кнопки ПОПЕР./ДАЛІ та вкладки СИГН./НОВИНИ/МІСЦ. залишаються доступними.", - "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.": "Автоматично гортає сторінки брифінгу кожні 9 секунд (Сигнали → Новини → Місцеве). Пауза, доки ви наводите вказівник на панель або вона у фокусі. Дані сигналів у реальному часі однаково оновлюються безперервно.", + "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.": "Автоматично гортає сторінки брифінгу кожні 9 секунд (Сигнали → Новини → Місцеві дані). Пауза, доки ви наводите вказівник на панель або вона у фокусі. Дані сигналів у реальному часі однаково оновлюються безперервно.", "ACQUIRING REGIONAL NEWS": "ОТРИМАННЯ РЕГІОНАЛЬНИХ НОВИН", "REGIONAL NEWS UNAVAILABLE": "РЕГІОНАЛЬНІ НОВИНИ НЕДОСТУПНІ", "RESOLVING REGION": "ВИЗНАЧЕННЯ РЕГІОНУ", @@ -1677,10 +1677,10 @@ "CLOUD UNKNOWN": "ХМАРНІСТЬ НЕВІДОМА", "{source} · LOCATION QUERY": "{source} · ЗАПИТ ЗА РОЗТАШУВАННЯМ", "REGIONAL NEWS": "НОВИНИ РЕГІОНУ", - "{label} · {radius} AIR/SEA WINDOW": "{label} · ВІКНО ПОВІТРЯ/МОРЕ {radius}", + "{label} · {radius} AIR/SEA WINDOW": "{label} · ПОВІТРЯ/МОРЕ · РАДІУС {radius}", "{scope} · INSTALLATIONS {coverage}": "{scope} · ОБʼЄКТИ: {coverage}", "CONTEXT STANDBY": "КОНТЕКСТ: ОЧІКУВАННЯ", - "ENABLE GLOBAL CONTEXT FOR PROXIMITY PINGS": "УВІМКНІТЬ ГЛОБАЛЬНИЙ КОНТЕКСТ ДЛЯ ПІНГІВ БЛИЗЬКОСТІ", + "ENABLE GLOBAL CONTEXT FOR PROXIMITY PINGS": "УВІМКНІТЬ ГЛОБАЛЬНИЙ КОНТЕКСТ, ЩОБ БАЧИТИ КОНТАКТИ ПОБЛИЗУ", "CONTACT LOST · LAST KNOWN READOUT · NOT AN ALL-CLEAR": "КОНТАКТ ВТРАЧЕНО · ОСТАННІ ВІДОМІ ПОКАЗНИКИ · НЕ ОЗНАЧАЄ «УСЕ ЧИСТО»", "CONTACT LOST · {subject}": "КОНТАКТ ВТРАЧЕНО · {subject}", "SUBJECT LEFT ITS FEED · READOUT HOLDING LAST KNOWN": "ОБʼЄКТ ЗНИК ІЗ ПОТОКУ · ПОКАЗАНО ОСТАННІ ВІДОМІ ДАНІ", @@ -1702,13 +1702,13 @@ "ADS-B PRIORITY · {status}": "ADS-B ПРІОРИТЕТ · {status}", "ADS-B EMERGENCY · {status}": "ADS-B АВАРІЯ · {status}", "AIRCRAFT": "БОРТ", - "ACQUIRING SURFACE": "ОТРИМАННЯ НАЗЕМНИХ ДАНИХ", - "SURFACE FALLBACK": "РЕЗЕРВ НАЗЕМНИХ ДАНИХ", + "ACQUIRING SURFACE": "ЗАВАНТАЖЕННЯ ПОВЕРХНІ", + "SURFACE FALLBACK": "РЕЗЕРВНА ПОВЕРХНЯ", "STALE FEED": "ЗАСТАРІЛИЙ ПОТІК", "LIVE TRACK": "ТРЕК ОНЛАЙН", "COMMERCIAL": "КОМЕРЦІЙНИЙ", "{aircraftClass} · {emergency} · {feedState}": "{aircraftClass} · {emergency} · {feedState}", - "{aircraftClass} · {feedState} · COURSE ALIGNED": "{aircraftClass} · {feedState} · КУРС ВИРІВНЯНО", + "{aircraftClass} · {feedState} · COURSE ALIGNED": "{aircraftClass} · {feedState} · КАМЕРА ЗА КУРСОМ", "ARROW · ESTIMATED DIRECTION": "СТРІЛКА · ОРІЄНТОВНИЙ НАПРЯМОК", "ROUTE DATA UNAVAILABLE": "ДАНІ МАРШРУТУ НЕДОСТУПНІ", "DEST {bearing}": "ПРИЗН. {bearing}", @@ -1721,7 +1721,7 @@ "Anime": "Аніме", "Noir": "Нуар", "Snow": "Сніг", - "Current cockpit vision style: {style}. Activate for next style.": "Поточний стиль бачення кабіни: {style}. Активуйте для наступного стилю.", + "Current cockpit vision style: {style}. Activate for next style.": "Поточний візуальний стиль у кабіні: {style}. Активуйте, щоб перейти до наступного.", "Current style: {style} — click for next": "Поточний стиль: {style} — клацніть для наступного", "Collapse Contact panel": "Згорнути панель контактів", "Expand Contact panel": "Розгорнути панель контактів", @@ -1731,10 +1731,10 @@ "Expand cockpit briefing panel": "Розгорнути панель брифінгу кабіни", "Collapse briefing panel": "Згорнути панель брифінгу", "Expand briefing panel": "Розгорнути панель брифінгу", - "OBSERVED / MAPPED PINGS": "СПОСТЕРЕЖЕНІ / НАНЕСЕНІ ПІНГИ", - "SOURCE-BACKED EVENTS · NO SYNTHETIC NEWS": "ПОДІЇ ПІДТВЕРДЖЕНІ ДЖЕРЕЛАМИ · БЕЗ ШТУЧНИХ НОВИН", + "OBSERVED / MAPPED PINGS": "СПОСТЕРЕЖЕНІ / НАНЕСЕНІ КОНТАКТИ", + "SOURCE-BACKED EVENTS · NO SYNTHETIC NEWS": "ПОДІЇ ПІДТВЕРДЖЕНІ ДЖЕРЕЛАМИ · БЕЗ ІМІТОВАНИХ НОВИН", "LATEST LOCATION-MATCHED REPORTING": "ОСТАННІ ПУБЛІКАЦІЇ ЗА РОЗТАШУВАННЯМ", - "{source} · LOCATION QUERY · RECENT": "{source} · ЗАПИТ ЗА МІСЦЕМ · НЕЩОДАВНІ", + "{source} · LOCATION QUERY · RECENT": "{source} · ЗАПИТ ЗА РОЗТАШУВАННЯМ · НЕЩОДАВНІ", "LOCAL INFO": "МІСЦЕВІ ДАНІ", "PLACE / CONDITIONS / POSITION": "МІСЦЕ / УМОВИ / ПОЗИЦІЯ", "TIME UNKNOWN": "ЧАС НЕВІДОМИЙ", @@ -1765,19 +1765,19 @@ "one": "Не вдалося очистити {count} шар даних", "few": "Не вдалося очистити {count} шари даних", "many": "Не вдалося очистити {count} шарів даних", - "other": "Не вдалося очистити {count} шара даних" + "other": "Не вдалося очистити {count} шару даних" }, "Cleared {count} data layers": { "one": "Очищено {count} шар даних", "few": "Очищено {count} шари даних", "many": "Очищено {count} шарів даних", - "other": "Очищено {count} шара даних" + "other": "Очищено {count} шару даних" }, - "Selected data layers could not be cleared": "Не вдалося очистити обрані шари даних", - "Space Missions could not complete the requested transition; try again": "Космічні місії не змогли завершити запитаний перехід; спробуйте ще раз", + "Selected data layers could not be cleared": "Не вдалося очистити вибрані шари даних", + "Space Missions could not complete the requested transition; try again": "Режим «Космічні місії» не зміг завершити запитаний перехід; спробуйте ще раз", "Nearby installations refreshed": "Найближчі обʼєкти оновлено", "Nearby installations could not be refreshed; try again": "Не вдалося оновити найближчі обʼєкти; спробуйте ще раз", - "Space Missions cancellation could not restore the previous layer state": "Скасування Космічних місій не змогло відновити попередній стан шарів", + "Space Missions cancellation could not restore the previous layer state": "Скасування режиму «Космічні місії» не відновило попередній стан шарів", "That layer is unavailable in the current Context mode": "Цей шар недоступний у поточному режимі контексту", "{layerId} could not {action} cleanly": "{layerId}: не вдалося коректно {action}", "start": "запустити", @@ -1819,7 +1819,7 @@ "Drag to size the box": "Потягніть, щоб задати розмір області", "light {source} to use your {name} key": "увімкніть {source}, щоб використати свій ключ {name}", "light {source}": "увімкніть {source}", - ", or ": " або ", + ", or ": ", або ", "{requirement}, or {offer}": "{requirement} або {offer}", "Live Flights": "Рейси онлайн", "Military Flights": "Військові рейси", @@ -1929,7 +1929,7 @@ "CONNECT": "ПІДКЛЮЧИТИ", "LOCATING…": "ВИЗНАЧЕННЯ…", "LOCATED": "ВИЗНАЧЕНО", - "LOCATE": "ГЕОПОЗИЦІЯ", + "LOCATE": "МОЄ МІСЦЕ", " · read while Local ADS-B is on": " · зчитуються, коли ввімкнено шар «Локальний ADS-B»", "Decoder feeds: {feeds}": "Потоки декодера: {feeds}", "Language: {language}": "Мова: {language}", @@ -2046,22 +2046,22 @@ "Newest frame per product": "Найсвіжіший кадр кожного продукту", "Replay observed history": "Відтворити історію спостережень", "Imagery on Esri · Google 3D returns when cleared": "Підкладка: Esri · скидання поверне Google 3D", - "Point the camera at the ground to use the view": "Наведіть камеру на землю, щоб використати вигляд", + "Point the camera at the ground to use the view": "Для видимої області наведіть камеру на землю", "That point cannot anchor a box": "Від цієї точки не можна побудувати область", "Imagery stops at ±{limit}° latitude": "Знімки є лише до ±{limit}° широти", "{owner} is using the pointer — close it first": "Вказівник зайнятий: «{owner}». Спершу закрийте його", "Box is {size} wide · limit {limit}": "Область завширшки {size} · межа {limit}", - "View is {size} wide · limit {limit}": "Вигляд завширшки {size} · межа {limit}", + "View is {size} wide · limit {limit}": "Видима ширина {size} · межа {limit}", "VS BASEMAP": "З ПІДКЛАДКОЮ", "A / B": "A / B", - "Newest low-cloud day for this box · scene cloud, not box cloud": "Найсвіжіший малохмарний день для цієї області · хмарність усієї сцени, а не області", - "Newest day covering this box · cloudier than 20%": "Найсвіжіший день із покриттям цієї області · хмарність понад 20%", - "Newest day with imagery for this box · partial coverage": "Найсвіжіший день зі знімками цієї області · часткове покриття", - "Newest daily overview for this box": "Найсвіжіший щоденний огляд для цієї області", - "newest clear day": "найсвіжіший ясний день", - "newest day (cloudy)": "найсвіжіший день (хмарно)", - "newest day (partial coverage)": "найсвіжіший день (часткове покриття)", - "newest overview": "найсвіжіший огляд", + "Newest low-cloud day for this box · scene cloud, not box cloud": "Останній малохмарний день для цієї області · хмарність усієї сцени, а не області", + "Newest day covering this box · cloudier than 20%": "Останній день із покриттям цієї області · хмарність понад 20%", + "Newest day with imagery for this box · partial coverage": "Останній день зі знімками цієї області · часткове покриття", + "Newest daily overview for this box": "Останній щоденний огляд для цієї області", + "newest clear day": "останній ясний день", + "newest day (cloudy)": "останній день (хмарно)", + "newest day (partial coverage)": "останній день (часткове покриття)", + "newest overview": "останній огляд", "No imagery": "Немає знімків", "Loading": "Завантаження", "coverage|full": "повне", @@ -2079,7 +2079,7 @@ "other": "{count} ДНЯ" }, "Zoom in or draw a smaller box": "Наблизьте карту або виділіть меншу область", - "Select a box or use the view": "Виділіть область або використайте поточний вигляд", + "Select a box or use the view": "Виділіть область або натисніть «З екрана»", "Searching the last 30 days": "Пошук за останні 30 днів", "No days to show for this box": "Для цієї області немає чого показати", "Drag the divider · SWAP trades sides": "Тягніть роздільник · «ПОМІНЯТИ» — зміна сторін", @@ -2088,7 +2088,7 @@ "S on another day replaces it · × unpins": "S на іншому дні замінює його · × відкріплює", "← → preview · S shows the focused day": "← → перегляд · S показує вибраний день", "ZOOM IN": "НАБЛИЗИТИ", - "Fly in until the view fits the 1,000 km limit": "Наближайтеся, доки вигляд не вміститься в межу 1000 км", + "Fly in until the view fits the 1,000 km limit": "Наблизьте карту, щоб видима область вмістилася в межу 1000 км", "Imagery days, newest first · arrows move, S or A and B pin": "Дні зі знімками, спершу нові · стрілки — переміщення, S або A і B — закріпити", "On the map": "На карті", "Mode": "Режим", @@ -2097,13 +2097,13 @@ "Trade the two sides of the divider": "Поміняти місцями сторони роздільника", "SELECT BOX": "ВИДІЛИТИ", "Drag a box on the map (Esc cancels)": "Виділіть область на карті (Esc — скасування)", - "USE VIEW": "ЗА ВИГЛЯДОМ", - "Use the current view as the box": "Використати поточний вигляд як область", + "USE VIEW": "З ЕКРАНА", + "Use the current view as the box": "Вибрати видиму область карти", "Forget the box and its images": "Скинути область і її знімки", "START HERE": "ПОЧНІТЬ ТУТ", "Checking": "Перевірка", "PREVIEW": "ПЕРЕГЛЯД", - "Newest day with imagery for this box": "Найсвіжіший день зі знімками цієї області", + "Newest day with imagery for this box": "Останній день зі знімками цієї області", "SHOW": "ПОКАЗАТИ", "Pin {day} as {slot}": "Закріпити {day} як {slot}", "Show {day}": "Показати {day}", @@ -2188,11 +2188,11 @@ "ACQUIRING": "ОТРИМАННЯ", "SHARED {subject}": "ЗА ПОСИЛАННЯМ: {subject}", "subject": "обʼєкт", - "LOADING LIVE DATA": "ЗАВАНТАЖЕННЯ ДАНИХ У РЕАЛЬНОМУ ЧАСІ", + "LOADING LIVE DATA": "ЗАВАНТАЖЕННЯ ДАНИХ ОНЛАЙН", "LOAD COMPLETE": "ЗАВАНТАЖЕННЯ ЗАВЕРШЕНО", "LOAD CANCELLED": "ЗАВАНТАЖЕННЯ СКАСОВАНО", "LOAD FAILED": "ПОМИЛКА ЗАВАНТАЖЕННЯ", - "LIVE DATA OFF": "ДАНІ В РЕАЛЬНОМУ ЧАСІ ВИМКНЕНО", + "LIVE DATA OFF": "ДАНІ ОНЛАЙН ВИМКНЕНО", "MAPPED SITES LOADED": "НАНЕСЕНІ ОБʼЄКТИ ЗАВАНТАЖЕНО", "RETRYING MAPPED SITES": "ПОВТОРНЕ ЗАВАНТАЖЕННЯ НАНЕСЕНИХ ОБʼЄКТІВ", "FETCHING MAPPED SITES": "ЗАВАНТАЖЕННЯ НАНЕСЕНИХ ОБʼЄКТІВ", @@ -2204,8 +2204,8 @@ "OVERPASS COULD NOT COMPLETE THE QUERY": "OVERPASS: НЕ ВДАЛОСЯ ЗАВЕРШИТИ ЗАПИТ", "MAP TILES TEMPORARILY UNAVAILABLE": "ТАЙЛИ КАРТИ ТИМЧАСОВО НЕДОСТУПНІ", "MAPPED NAMES TEMPORARILY UNAVAILABLE": "НАЗВИ ОБʼЄКТІВ ТИМЧАСОВО НЕДОСТУПНІ", - "TURNING OFF LIVE DATA": "ВИМКНЕННЯ ДАНИХ У РЕАЛЬНОМУ ЧАСІ", - "REFRESHING LIVE DATA": "ОНОВЛЕННЯ ДАНИХ У РЕАЛЬНОМУ ЧАСІ", + "TURNING OFF LIVE DATA": "ВИМКНЕННЯ ДАНИХ ОНЛАЙН", + "REFRESHING LIVE DATA": "ОНОВЛЕННЯ ДАНИХ ОНЛАЙН", "syncing road network": "синхронізація дорожньої мережі", "retry pending": "очікується повтор", "retrying in {seconds}s": "повтор через {seconds} с", @@ -2299,7 +2299,7 @@ "Image by {creator}": "Автор знімка: {creator}", " or ": " або ", "OPEN {labels}": "ВІДКРИТИ {labels}", - "Open {names} at the centre of the view": "Відкрити {names} у центрі вигляду", + "Open {names} at the centre of the view": "Відкрити {names} у центрі карти", "Zoom in to a street to open {names} here": "Наблизьтеся до вулиці, щоб відкрити тут {names}", "Switch Street Level on to draw its coverage.": "Увімкніть «Вуличні знімки», щоб показати покриття.", "Every provider is switched off: light a chip to draw its coverage.": "Усі джерела вимкнено: увімкніть одне, щоб показати його покриття.", @@ -2372,7 +2372,7 @@ "VOICE CONTROL": "ГОЛОСОВЕ КЕРУВАННЯ", "Hold Space to speak · tap Space to activate focused controls": "Утримуйте Space, щоб говорити · натисніть Space, щоб активувати елемент у фокусі", "VOICE": "ГОЛОС", - "Preview": "Попередній перегляд", + "Preview": "Відповіді", "Settings": "Налаштування", "Close voice panel": "Закрити голосову панель", "Voice replies appear here.": "Тут зʼявляються голосові відповіді.", @@ -2383,9 +2383,9 @@ "Plan": "План", "Referenced items": "Згадані обʼєкти", "NOTES & SOURCES": "НОТАТКИ Й ДЖЕРЕЛА", - "Show Voice Preview": "Показувати попередній перегляд голосу", + "Show Voice Preview": "Показувати відповіді асистента", "Voice inactivity timeout": "Тайм-аут бездіяльності голосу", - "Minutes": "Хвилини", + "Minutes": "хв", "Custom": "Інше", "These preferences stay in this browser.": "Ці налаштування зберігаються в цьому браузері.", "VOICE SYSTEM ERROR": "ПОМИЛКА ГОЛОСОВОЇ СИСТЕМИ", @@ -2433,7 +2433,7 @@ "Gemini connection timed out. Try again.": "Минув час очікування підключення до Gemini. Спробуйте ще раз.", "Gemini voice could not start": "Не вдалося запустити голосовий режим Gemini", "Gemini did not finish the interrupted reply. Start voice again.": "Gemini не завершив перервану відповідь. Запустіть голосовий режим знову.", - "Gemini session expiring; finishing the current reply": "Сеанс Gemini спливає; завершується поточна відповідь", + "Gemini session expiring; finishing the current reply": "Термін дії сеансу Gemini спливає; завершується поточна відповідь", "Gemini rejected the voice session. Start voice again to request a fresh session.": "Gemini відхилив голосовий сеанс. Запустіть голосовий режим знову, щоб запитати новий сеанс.", "Start voice again for a fresh session credential. If it repeats, check Gemini model and API access.": "Запустіть голосовий режим знову, щоб отримати нові облікові дані. Якщо помилка повториться, перевірте модель Gemini і доступ до API.", "Gemini action history is full. Start voice again for a fresh session.": "Історія дій Gemini заповнена. Запустіть голосовий режим знову для нового сеансу.", @@ -2442,12 +2442,12 @@ "Voice text command is too long": "Текст голосової команди задовгий", "Gemini voice is not connected": "Голосовий режим Gemini не підключено", "Gemini interrupted input exceeded its buffer or wait limit. Start voice again.": "Перерване введення Gemini перевищило ліміт буфера або очікування. Запустіть голосовий режим знову.", - "Gemini Live connection is expiring. Start voice again for a new conversation.": "Зʼєднання з Gemini Live спливає. Запустіть голосовий режим знову для нової розмови.", + "Gemini Live connection is expiring. Start voice again for a new conversation.": "Термін дії зʼєднання з Gemini Live спливає. Запустіть голосовий режим знову для нової розмови.", "Voice off": "Голос вимкнено", - "Gemini voice sessions have a time limit. When a session expires, start voice again for a new conversation.": "Час голосових сеансів Gemini обмежений. Коли сеанс спливе, запустіть голосовий режим знову для нової розмови.", + "Gemini voice sessions have a time limit. When a session expires, start voice again for a new conversation.": "Тривалість голосових сеансів Gemini обмежена. Коли сеанс завершиться, запустіть голосовий режим знову для нової розмови.", "Stopped by voice": "Зупинено голосовою командою", "Automatic stop is unavailable for this voice connection.": "Автоматична зупинка недоступна для цього голосового підключення.", - "Preview is off.": "Попередній перегляд вимкнено.", + "Preview is off.": "Показ відповідей вимкнено.", "Your choice applies now, but could not be saved.": "Ваш вибір застосовано, але зберегти його не вдалося.", "WebRTC microphone support unavailable": "Підтримка мікрофона WebRTC недоступна", "VOICE UNAVAILABLE": "ГОЛОС НЕДОСТУПНИЙ", @@ -2573,8 +2573,8 @@ }, "anywhere in the loaded data": "в усіх завантажених даних", "in view": "у кадрі", - "within {radius} of the view centre": "у радіусі {radius} від центру вигляду", - "within {radius} of {place} (Contacts window)": "у радіусі {radius} — {place} (вікно «Контактів»)", + "within {radius} of the view centre": "у радіусі {radius} від центру карти", + "within {radius} of {place} (Contacts window)": "у радіусі {radius} — {place} (режим «Контакти»)", "within {radius} of {place}": "у радіусі {radius} — {place}", "within {radius}": "у радіусі {radius}", "over {region}": "у регіоні {region}", @@ -2582,7 +2582,7 @@ "{items} {scope}": "{items} {scope}", "last 24 h": "за останні 24 год", "past 30 d and upcoming": "за останні 30 дн і майбутні", - "the flights layer loads by viewport": "шар рейсів завантажується за областю вигляду", + "the flights layer loads by viewport": "шар рейсів завантажується для видимої області карти", "distance is ground distance, not overhead": "відстань — поверхнею землі до підсупутникової точки, а не до самого апарата", "the count is a lower bound because at least one layer reached its retained limit.": "це нижня межа: принаймні один шар досяг ліміту збережених записів.", "{label} off": "{label}: вимк.", @@ -2626,12 +2626,12 @@ "Nearest-aircraft selection needs a preset, place name, or latitude and longitude": "Для вибору найближчого літака потрібен пресет, назва місця або широта й довгота", "Could not arrive at the requested place": "Не вдалося долетіти до запитаного місця", "The nearest airborne aircraft could not be selected": "Не вдалося вибрати найближчий літак у повітрі", - "No flights within {radius} of the current view": "У радіусі {radius} від поточного вигляду немає рейсів", - "No military within {radius} of the current view": "У радіусі {radius} від поточного вигляду немає військових рейсів", - "No satellites within {radius} of the current view": "У радіусі {radius} від поточного вигляду немає супутників", - "No vessels within {radius} of the current view": "У радіусі {radius} від поточного вигляду немає суден", - "{layer} is enabled on the {source} feed, but no airborne aircraft is loaded in the {place} view yet": "{layer}: увімкнено (потік {source}), але у вигляді «{place}» ще не завантажено жодного літака в повітрі", - "{layer} is enabled, but no airborne aircraft is loaded in the {place} view yet": "{layer}: увімкнено, але у вигляді «{place}» ще не завантажено жодного літака в повітрі", + "No flights within {radius} of the current view": "У радіусі {radius} від центру карти немає рейсів", + "No military within {radius} of the current view": "У радіусі {radius} від центру карти немає військових рейсів", + "No satellites within {radius} of the current view": "У радіусі {radius} від центру карти немає супутників", + "No vessels within {radius} of the current view": "У радіусі {radius} від центру карти немає суден", + "{layer} is enabled on the {source} feed, but no airborne aircraft is loaded in the {place} view yet": "{layer}: увімкнено (потік {source}), але у видимій області ({place}) ще не завантажено жодного літака в повітрі", + "{layer} is enabled, but no airborne aircraft is loaded in the {place} view yet": "{layer}: увімкнено, але у видимій області ({place}) ще не завантажено жодного літака в повітрі", "{layer} is enabled, but its aircraft feed is unavailable": "{layer}: увімкнено, але потік даних про літаки недоступний", "{layer} is enabled, but its destination refresh did not complete": "{layer}: увімкнено, але оновлення в точці призначення не завершилося", "{layer} is enabled, but {source} is unavailable": "{layer}: увімкнено, але джерело {source} недоступне", @@ -2683,7 +2683,7 @@ "Layer": "Шар", "there": "там", "Camera range {range}": "Дальність камери: {range}", - "Within {radius} of the view": "У радіусі {radius} від вигляду", + "Within {radius} of the view": "У радіусі {radius} від центру карти", "Labels on": "Підписи ввімкнено", "Framing uses the nearest 80 loaded contacts": "У кадр потрапляють 80 найближчих завантажених контактів", "{distance} from {location}": "{location}: {distance}", @@ -2770,15 +2770,15 @@ "GROUND SPEED · KTS": "ШЛЯХОВА ШВИДКІСТЬ · ВУЗ", "ALTITUDE · FT": "ВИСОТА · ФТ", "FIRST PERSON": "ВІД ПЕРШОЇ ОСОБИ", - "LIVE TRACK · COURSE ALIGNED": "ТРЕК ОНЛАЙН · КУРС ВИРІВНЯНО", - "Cockpit vision style": "Стиль бачення кабіни", - "Previous cockpit vision style": "Попередній стиль бачення кабіни", - "Previous vision style": "Попередній стиль бачення", - "Current cockpit vision style: NORMAL. Activate for next style.": "Поточний стиль бачення кабіни: ЗВИЧАЙНИЙ. Активуйте для наступного стилю.", + "LIVE TRACK · COURSE ALIGNED": "ТРЕК ОНЛАЙН · КАМЕРА ЗА КУРСОМ", + "Cockpit vision style": "Візуальний стиль у кабіні", + "Previous cockpit vision style": "Попередній візуальний стиль у кабіні", + "Previous vision style": "Попередній візуальний стиль", + "Current cockpit vision style: NORMAL. Activate for next style.": "Поточний візуальний стиль у кабіні: ЗВИЧАЙНИЙ. Активуйте, щоб перейти до наступного.", "Current style: NORMAL — click for next": "Поточний стиль: ЗВИЧАЙНИЙ — клацніть для наступного", "CURRENT": "ПОТОЧНИЙ", - "Next cockpit vision style": "Наступний стиль бачення кабіни", - "Next vision style": "Наступний стиль бачення", + "Next cockpit vision style": "Наступний візуальний стиль у кабіні", + "Next vision style": "Наступний візуальний стиль", "Current aircraft heading": "Поточний курс повітряного судна", "GROUND SPEED": "ШЛЯХОВА ШВИДКІСТЬ", "KTS": "ВУЗ", @@ -2826,7 +2826,7 @@ "RADIO": "РАДІО", "Cockpit compact Radio controls": "Компактне керування радіо кабіни", "Previous filtered radio station": "Попередня відфільтрована радіостанція", - "Play selected radio station": "Відтворити обрану радіостанцію", + "Play selected radio station": "Відтворити вибрану радіостанцію", "Next filtered radio station": "Наступна відфільтрована радіостанція", "VOLUME": "ГУЧНІСТЬ", "Cockpit Radio volume": "Гучність радіо кабіни", @@ -2843,7 +2843,7 @@ "Keep visual presets open": "Тримати візуальні пресети відкритими", "Show the globe without a visual filter.": "Показує глобус без візуального фільтра.", "Emulate a green phosphor CRT with scanlines and screen curvature.": "Імітує CRT-монітор із зеленим люмінофором, рядками розгортки та вигнутим екраном.", - "Simulate night-vision goggles with green intensification and a tube vignette.": "Імітує прилад нічного бачення з зеленим підсиленням та віньєткою туби.", + "Simulate night-vision goggles with green intensification and a tube vignette.": "Імітує прилад нічного бачення: підсилене зелене зображення й затемнення по краях поля зору.", "Simulate FLIR-style thermal contrast. Turn up Ironbow for color.": "Імітує термальний контраст у стилі FLIR. Для кольору збільште Ironbow.", "Apply bright cel-shaded color and illustrated outlines.": "Застосовує яскраву мультяшну заливку та ілюстровані контури.", "Apply high-contrast monochrome film-noir grading.": "Застосовує висококонтрастну чорно-білу обробку в стилі нуар.", @@ -2871,18 +2871,18 @@ "Expand panel": "Розгорнути панель", "Context mode": "Режим контексту", "CONTACTS": "КОНТАКТИ", - "Cycles the nearest contacts of whatever type you select — planes, vessels, installations. Satellites track independently.": "Гортає найближчі контакти обраного вами типу — літаки, судна, обʼєкти. Супутники відстежуються окремо.", + "Cycles the nearest contacts of whatever type you select — planes, vessels, installations. Satellites track independently.": "Гортає найближчі контакти вибраного вами типу — літаки, судна, обʼєкти. Супутники відстежуються окремо.", "SPACE MISSIONS": "КОСМІЧНІ МІСІЇ", - "SELECT CONTEXT": "ОБЕРІТЬ КОНТЕКСТ", + "SELECT CONTEXT": "ВИБЕРІТЬ КОНТЕКСТ", "Contact Context actions": "Дії контексту контактів", "COCKPIT": "КАБІНА", "SEARCH NEARBY SITES": "ПОШУК НАЙБЛИЖЧИХ ОБʼЄКТІВ", "Reclassify tracked contact as TR-3B": "Перекласифікувати відстежуваний контакт як TR-3B", "CONTACTS CONTEXT OFF": "КОНТЕКСТ КОНТАКТІВ ВИМКНЕНО", - "SELECT CONTACTS TO LOAD OBSERVED / MAPPED PROXIMITY": "ВИБЕРІТЬ КОНТАКТИ, ЩОБ ЗАВАНТАЖИТИ СПОСТЕРЕЖЕНЕ / НАНЕСЕНЕ ПОБЛИЗУ", + "SELECT CONTACTS TO LOAD OBSERVED / MAPPED PROXIMITY": "ВИБЕРІТЬ «КОНТАКТИ», ЩОБ ЗАВАНТАЖИТИ СПОСТЕРЕЖЕНІ / НАНЕСЕНІ ОБʼЄКТИ ПОБЛИЗУ", "Available Space Missions": "Доступні космічні місії", "AVAILABLE MISSIONS": "ДОСТУПНІ МІСІЇ", - "SELECT A MISSION TO INSPECT": "ОБЕРІТЬ МІСІЮ ДЛЯ ПЕРЕГЛЯДУ", + "SELECT A MISSION TO INSPECT": "ВИБЕРІТЬ МІСІЮ ДЛЯ ПЕРЕГЛЯДУ", "LOADING 30-DAY MISSION INDEX": "ЗАВАНТАЖЕННЯ ІНДЕКСУ МІСІЙ ЗА 30 ДНІВ", "TAB PREVIEWS · ENTER / SPACE SELECTS": "TAB — ОГЛЯД · ENTER / SPACE — ВИБІР", "Internet radio and local SDR": "Інтернет-радіо та локальний SDR", @@ -2893,7 +2893,7 @@ "DRAG TO TUNE": "ТЯГНІТЬ ДЛЯ НАЛАШТУВАННЯ", "Tune available internet radio stations": "Налаштування на доступні інтернет-радіостанції", "ALL · DRAG THE NEEDLE": "УСІ · ПОТЯГНІТЬ СТРІЛКУ", - "SNAPS TO AVAILABLE STATIONS": "ПРИЛИПАЄ ДО ДОСТУПНИХ СТАНЦІЙ", + "SNAPS TO AVAILABLE STATIONS": "ФІКСУЄТЬСЯ НА ДОСТУПНИХ СТАНЦІЯХ", "Radio playback": "Відтворення радіо", "Previous filtered station": "Попередня станція у фільтрі", "Play selected station": "Відтворити вибрану станцію", @@ -2958,7 +2958,7 @@ "Detection opacity outside the keyhole": "Непрозорість виявлення за межами ілюмінатора", "World-overlay label and card opacity beyond the fade distance": "Непрозорість підписів і карток накладки світу за межею згасання", "PARAMETERS": "ПАРАМЕТРИ", - "3D aircraft — flat icons zoomed out, 3D models up close": "3D літаки — плоскі іконки здалеку, 3D-моделі зблизька", + "3D aircraft — flat icons zoomed out, 3D models up close": "3D літаки — плоскі значки здалеку, 3D-моделі зблизька", "Models": "Моделі", "3D model coverage": "Охоплення 3D-моделей", "Proximity": "Поблизу", @@ -3043,7 +3043,7 @@ "START": "СТАРТ", "EXPORT PRESETS": "ЕКСПОРТУВАТИ ПРЕСЕТИ", "IMPORT": "ІМПОРТУВАТИ", - "RUN LOG": "ЖУРНАЛ ЗАПУСКІВ", + "RUN LOG": "ЖУРНАЛ ВІДТВОРЕННЯ", "POWER UP": "ЗАПУСК", "GROUND STATION · PROVIDER SETTINGS": "НАЗЕМНА СТАНЦІЯ · НАЛАШТУВАННЯ ПОСТАЧАЛЬНИКІВ", "Close key setup": "Закрити налаштування ключів", @@ -3062,9 +3062,9 @@ "Reset map bearing to north": "Скинути азимут карти на північ", "Reset camera and return to full globe view": "Скинути камеру та повернутися до загального вигляду глобуса", "MISSION CONTROL · FIRST LAUNCH": "ЦЕНТР КЕРУВАННЯ · ПЕРШИЙ ЗАПУСК", - "Choose your first view": "Оберіть свій перший вигляд", + "Choose your first view": "Виберіть, із чого почати", "LIVE CONTACTS": "КОНТАКТИ ОНЛАЙН", - "Aircraft, vessels and nearby intelligence": "Літаки, судна та розвідка поблизу", + "Aircraft, vessels and nearby intelligence": "Літаки, судна й розвіддані поблизу", "Launches, spacecraft and orbital context": "Запуски, космічні апарати та орбітальний контекст", "EXPLORE MANUALLY": "ДОСЛІДИТИ ВРУЧНУ", "Begin with a clean globe": "Почніть із чистого глобуса", From 40485359215c086b1de0fae45820c3023c5bb33b Mon Sep 17 00:00:00 2001 From: German Khokhlov Date: Wed, 28 Oct 2026 22:40:38 +0400 Subject: [PATCH 36/83] i18n(pt): apply review round 3 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Three-model review (astra, sol, fable), round 3: 17 of 18 findings applied (some in own wording, one in part); "Missões espac." rejected. - pt: layer cards «{label}: camada ativada/desativada», pointer and Directions toasts name «A ferramenta "{owner}"», counters after a colon where the count can be 1, traffic «sem dados de fluxo» and «Fluxo: {percent}% cob», «limite de requisições atingido», FECHAR, ANT., PREDEF. VISUAIS, quoted "Nível da rua", infinitive tooltips, and more (see docs/translations/pt.md). - CCTV summary line localizes its CAL, SRC and CONTEXT values through existing catalog keys (all locales); codes stay underneath. Co-Authored-By: Claude Opus 5.5 --- docs/translations/pt.md | 8 +++ src/i18n/locales/pt.json | 92 +++++++++++++-------------- src/layers/cctv/presentation.js | 71 +++++++++++++++++---- src/layers/cctv/presentation.test.mjs | 38 +++++++++++ 4 files changed, 152 insertions(+), 57 deletions(-) create mode 100644 src/layers/cctv/presentation.test.mjs diff --git a/docs/translations/pt.md b/docs/translations/pt.md index 15d6291b5..e71023b31 100644 --- a/docs/translations/pt.md +++ b/docs/translations/pt.md @@ -12,6 +12,8 @@ Translation source: abiyeenzo (#909). - Quotes inside Portuguese text are straight double quotes: «Excluir o plano "{shot}"?». A sentence that names a panel quotes it: «o painel "Configurações de provedores"» as the subject, so the verb agrees, and «adicione em "Configurações de provedores"» after a preposition. - A dash between clauses is a spaced em dash « — », even where the English runs it in. - A date or time after a participle takes a preposition: «emitido em {time}», «válida para {valid}», «Posição em {time}», «onde estava em {time}». Use «em», not «às», wherever {time} can include a date. +- A count in a string with no plural form (no `tn()`) goes after a colon, so it reads right for 1: «sincronizando feeds de cidades: {count}...», «CÂMERAS EM ESPERA: {count}». +- A placeholder that holds a layer or tool name of unknown gender and number gets a noun to agree with: «{label}: camada ativada», «A ferramenta "{owner}" está usando o ponteiro — feche-a primeiro». - Short labels, chips and HUD readouts stay short. A standard abbreviation with a period beats a wrapped line: ANT., PRÓX., DESLIG., EXCL., INCL., ALT., VEL., câm. - The HUD codes HDG, BRG, CRS, FOV, DEST, SPD, RANGE, ALT, GS, TRK and V/S stay in English, as in cockpit avionics («ALT {altitude} FT · GS {speed} KT · TRK {track}», «V/S {rate} FT/MIN»), and so does the HUD recording mark REC. Words used in a sentence are translated: heading → «rumo», range → «alcance». - Keyboard keys stay in English: Space, Esc, Enter, Tab, Shift, Backspace, H, 1–9 («Segure Space para falar»). @@ -44,6 +46,8 @@ The `many` form is the `other` text with «de» after the number: «{count} de c | stale / degraded / unavailable | desatualizado / degradado / indisponível | | retry / retrying | nova tentativa / tentando de novo | | retrying (a fetch) / retrying slowly | buscando de novo / tentando de novo em intervalos maiores | +| rate-limited | «X: limite de requisições atingido» | +| dismiss (window, card, error) | fechar | | key (API key) / POWER UP / POWERED UP | chave / ATIVAR / ATIVADO | | Provider Settings | Configurações de provedores | | ON / OFF (state chips) | ATIVO / INATIVO | @@ -71,18 +75,21 @@ The `many` form is the `other` text with «de» after the number: «{count} de c | AQHI bands Low … Very High | Risco baixo … Risco muito alto | | radio station / broadcaster | estação de rádio / emissora | | Oldies / World (radio tags) | Flashback / Músicas do mundo | +| radio genre tags agree with «música» | Alternativa, Clássica, Eletrônica, Latina | | road / flow (traffic) | via / fluxo | | Street Level (layer) | Nível da rua | | scene / shot / scene recipe | cena / plano / receita de cena | | briefing / panel / dock | briefing / painel / dock | | cockpit | cabine | | preset / visual preset / EXPORT PRESETS | predefinição / predefinição visual / EXPORTAR PREDEF. | +| VISUAL PRESETS (dock caption) | PREDEF. VISUAIS | | Scope (circular viewport mask) / keyhole | mira / visor | | feather / fade | suavização / esmaecimento | | detection overlay | sobreposição de detecção | | pin (Draw tool) / box (Recent Imagery) | marcador / área | | Cyber (HUD layout, effect) | Ciber | | heading / course / altitude / ground speed | rumo / curso / altitude / velocidade solo (VELOC. SOLO) | +| map heading / bearing (compass, north up) | orientação (do mapa) | | HDG / BRG / CRS / FOV / DEST / SPD / RANGE | HDG / BRG / CRS / FOV / DEST / SPD / RANGE (unchanged) | | V/S (vertical speed code) | V/S (unchanged) | | PREV / NEXT | ANT. / PRÓX. | @@ -95,4 +102,5 @@ The `many` form is the `other` text with «de» after the number: «{count} de c | Last report (transit vehicle position) | Último registro | | intersection (CCTV) | cruzamento | | {layers} just turned on (any list of layers) | «{layers}: ativação recente» (no agreement needed) | +| {label} on / off (one layer) | «{label}: camada ativada / desativada» | | turn-by-turn: turn left / keep left / lane | vire à esquerda / mantenha-se à esquerda / faixa da esquerda | diff --git a/src/i18n/locales/pt.json b/src/i18n/locales/pt.json index fee5d1274..722bc6a74 100644 --- a/src/i18n/locales/pt.json +++ b/src/i18n/locales/pt.json @@ -17,7 +17,7 @@ "That shape could not be placed.": "Não foi possível colocar essa forma.", "Could not place the shape: {error}": "Não foi possível colocar a forma: {error}", "Board cleared.": "Quadro limpo.", - "{owner} is using the pointer — close it first.": "Ponteiro em uso: {owner}. Feche-o primeiro.", + "{owner} is using the pointer — close it first.": "A ferramenta \"{owner}\" está usando o ponteiro — feche-a primeiro.", "{label} · Detailed outline unavailable": "{label} · Contorno detalhado indisponível", "Flying to Austin, TX...": "Voando para Austin, TX...", "Restoring shared view...": "Restaurando a vista compartilhada...", @@ -187,18 +187,18 @@ "INITIAL M4.4 · RECLASSIFIED M5.2 LANDSLIDE": "INICIAL M4,4 · RECLASSIFICADO COMO DESLIZAMENTO M5,2", "USGS EVENT us7000tbwb · OPEN SOURCE": "EVENTO USGS us7000tbwb · ABRIR FONTE", "Open the USGS initial report for the 26 August 2026 Nepal landslide": "Abrir o relatório inicial do USGS sobre o deslizamento de 26 de agosto de 2026 no Nepal", - "Show the Nepal context callout without a border or country fill": "Mostra o destaque de contexto do Nepal sem fronteira nem preenchimento do país", - "Introduce Nepal, draw its border, then reveal the Bhote Koshi incident": "Apresenta o Nepal, desenha sua fronteira e depois revela o incidente do Bhote Koshi", + "Show the Nepal context callout without a border or country fill": "Mostrar o destaque de contexto do Nepal sem fronteira nem preenchimento do país", + "Introduce Nepal, draw its border, then reveal the Bhote Koshi incident": "Apresentar o Nepal, desenhar sua fronteira e depois revelar o incidente do Bhote Koshi", "CITIES": "CIDADES", - "Keep the regional incident context and introduce nearby city labels": "Mantém o contexto regional do incidente e apresenta os rótulos das cidades próximas", + "Keep the regional incident context and introduce nearby city labels": "Manter o contexto regional do incidente e apresentar os rótulos das cidades próximas", "PLACES": "LUGARES", - "Introduce the reconstruction scene key places from trigger to downstream": "Apresenta os lugares-chave da cena de reconstrução, do gatilho até rio abaixo", + "Introduce the reconstruction scene key places from trigger to downstream": "Apresentar os lugares-chave da cena de reconstrução, do gatilho até rio abaixo", "PATH": "PERCURSO", - "Animate the sourced cyan river-centerline route to Trishuli Bazaar": "Anima a rota ciano documentada pelo eixo do rio até Trishuli Bazaar", + "Animate the sourced cyan river-centerline route to Trishuli Bazaar": "Animar a rota ciano documentada pelo eixo do rio até Trishuli Bazaar", "OVERVIEW": "VISÃO GERAL", - "Keep the completed flood path and location labels visible": "Mantém visíveis o percurso completo da inundação e os rótulos dos locais", + "Keep the completed flood path and location labels visible": "Manter visíveis o percurso completo da inundação e os rótulos dos locais", "RECORD": "REGISTRO", - "Reveal the trigger record while making a slow camera approach": "Revela o registro do gatilho com uma aproximação lenta da câmera", + "Reveal the trigger record while making a slow camera approach": "Revelar o registro do gatilho com uma aproximação lenta da câmera", "{speed} kn": "{speed} kt", "That file is not valid JSON.": "Esse arquivo não é um JSON válido.", "That JSON file is not GeoJSON.": "Esse arquivo JSON não é GeoJSON.", @@ -210,7 +210,7 @@ "That file creates more than {limit} map objects (the limit).": "Esse arquivo cria mais de {limit} objetos no mapa (o limite).", "That file has more than {limit} style definitions and image links after cleanup (the limit).": "Após a limpeza, esse arquivo tem mais de {limit} definições de estilo e links de imagem (o limite).", "That file has more than {limit} features (the limit).": "Esse arquivo tem mais de {limit} elementos (o limite).", - "That file has more than {limit} points (the limit) across {features} features.": "Esse arquivo tem mais de {limit} pontos (o limite) em {features} elementos.", + "That file has more than {limit} points (the limit) across {features} features.": "Esse arquivo tem mais de {limit} pontos (o limite). Total de elementos: {features}.", "That file has more than {limit} points (the limit).": "Esse arquivo tem mais de {limit} pontos (o limite).", "That KMZ unpacks to more than the import limit.": "Descompactado, esse KMZ ultrapassa o limite de importação.", "That KMZ is damaged and could not be unpacked.": "Esse KMZ está danificado e não pôde ser descompactado.", @@ -236,7 +236,7 @@ "That file has {count} map objects; the limit is {limit}.": "Esse arquivo tem {count} objetos no mapa; o limite é {limit}.", "Ground heights could not be read. Try that file again.": "Não foi possível ler as altitudes do terreno. Tente esse arquivo de novo.", "That file has invalid point graphics.": "Esse arquivo tem gráficos de pontos inválidos.", - "Overpass rate-limited": "Overpass com limite de requisições", + "Overpass rate-limited": "Overpass: limite de requisições atingido", "Overpass timed out": "Tempo esgotado no Overpass", "Overpass could not complete the query": "Overpass não conseguiu concluir a consulta", "Map tiles temporarily unavailable": "Blocos do mapa temporariamente indisponíveis", @@ -494,7 +494,7 @@ "Focus {label}": "Focar {label}", "Global Context navigation": "Navegação do contexto global", "Previous — prior visited contact in the 250 km window": "Anterior — contato visitado anteriormente na janela de 250 km", - "PREVIOUS": "ANTERIOR", + "PREVIOUS": "ANT.", "FOCUS": "FOCAR", "Next — nearest unvisited contact in the 250 km window": "Próximo — contato não visitado mais próximo na janela de 250 km", "NEXT": "PRÓX.", @@ -515,7 +515,7 @@ "Military flights": "Voos militares", "AIS vessels": "Embarcações AIS", "Mapped installations": "Instalações mapeadas", - "syncing {count} city feeds...": "sincronizando {count} feeds de cidades...", + "syncing {count} city feeds...": "sincronizando feeds de cidades: {count}...", "scanning nearby systems...": "buscando sistemas próximos...", "GBFS fetch error": "erro ao obter dados GBFS", "Station {id}": "Estação {id}", @@ -525,7 +525,7 @@ "⚠️ Not renting": "⚠️ Sem aluguel", "⚠️ Not returning": "⚠️ Sem devolução", "HDG {value}° (ESTIMATED)": "HDG {value}° (ESTIMADO)", - "{count} CAMERAS STANDING BY · NO CAMERA SELECTED · CLICK A CAMERA TO ACTIVATE": "{count} CÂMERAS EM ESPERA · NENHUMA CÂMERA SELECIONADA · CLIQUE EM UMA CÂMERA PARA ATIVAR", + "{count} CAMERAS STANDING BY · NO CAMERA SELECTED · CLICK A CAMERA TO ACTIVATE": "CÂMERAS EM ESPERA: {count} · NENHUMA CÂMERA SELECIONADA · CLIQUE EM UMA CÂMERA PARA ATIVAR", "No cameras available in catalog.": "Nenhuma câmera disponível no catálogo.", "{city} CCTV": "CCTV {city}", "FOV {value}° (DATASHEET)": "FOV {value}° (FICHA TÉCNICA)", @@ -684,9 +684,9 @@ "Place A and B first": "Coloque A e B primeiro", "action|CLEAR": "LIMPAR", "Remove the route and both markers": "Remover a rota e os dois marcadores", - "press Escape twice to leave Draw": "pressione Esc duas vezes para sair de Desenho", - "{name} is active — turn {name} off, then set {endpoint}": "{name} está ativo — desative {name} e depois defina {endpoint}", - "{name} is active — {leave}, then set {endpoint}": "{name} está ativo — {leave} e depois defina {endpoint}", + "press Escape twice to leave Draw": "pressione Esc duas vezes para sair de \"Desenho\"", + "{name} is active — turn {name} off, then set {endpoint}": "A ferramenta \"{name}\" está ativa — desative \"{name}\" e depois defina {endpoint}", + "{name} is active — {leave}, then set {endpoint}": "A ferramenta \"{name}\" está ativa — {leave} e depois defina {endpoint}", "Only the first {count} turns of this route are shown": "Só as primeiras {count} conversões desta rota são mostradas", "Turn-by-turn directions": "Instruções passo a passo", "Another map tool is using clicks — close it, then SET A again": "Outra ferramenta do mapa está usando os cliques — feche-a e pressione DEFINIR A de novo", @@ -815,7 +815,7 @@ "ORBIT REPLAY · {mission}": "REPRISE DA ÓRBITA · {mission}", "PAUSED · {title}": "PAUSADO · {title}", "UNSPECIFIED": "NÃO ESPECIFICADO", - "+{count} additional payload records": "+{count} registros de carga útil adicionais", + "+{count} additional payload records": "Outros registros de carga útil: {count}", "PAYLOAD DATA UNAVAILABLE": "DADOS DA CARGA ÚTIL INDISPONÍVEIS", "{value} KM DOWNRANGE": "A {value} KM DO LOCAL DE LANÇAMENTO", "POSITION UNAVAILABLE": "POSIÇÃO INDISPONÍVEL", @@ -895,7 +895,7 @@ "opening receiver": "abrindo o receptor", "checking decoder feeds": "verificando os feeds do decodificador", "WebUSB needs desktop Chrome or Edge": "O WebUSB requer Chrome ou Edge para desktop", - "connect a receiver in Radio": "conecte um receptor em Rádio", + "connect a receiver in Radio": "conecte um receptor em \"Rádio\"", "receiver is in FM mode": "o receptor está no modo FM", "listening": "escutando", "USB error": "erro de USB", @@ -969,7 +969,7 @@ "Broadcaster stream is unavailable or blocked by the browser.": "O stream da emissora está indisponível ou foi bloqueado pelo navegador.", "Playback requires a direct click or tap.": "A reprodução exige um clique ou toque direto.", "Broadcaster stream could not be started.": "Não foi possível iniciar o stream da emissora.", - "Alternative": "Alternativo", + "Alternative": "Alternativa", "Ambient": "Ambiente", "Blues": "Blues", "Classical": "Clássica", @@ -1032,7 +1032,7 @@ "DOCKED · {name} · +{extra}": "ACOPLADO · {name} · +{extra}", "DOCKED · {name}": "ACOPLADO · {name}", "{name} needs the Google 3D map: choose it under MAP SOURCE": "{name} requer o mapa Google 3D: escolha-o em FONTE DO MAPA", - "zoom in to a street to open {name}": "aproxime-se de uma rua para abrir {name}", + "zoom in to a street to open {name}": "aproxime-se de uma rua para abrir o {name}", "loading coverage...": "carregando cobertura...", "No street-level imagery within {radius} m of that point": "Nenhuma imagem no nível da rua a até {radius} m desse ponto", "No street-level imagery within {radius} m of the view centre": "Nenhuma imagem no nível da rua a até {radius} m do centro da vista", @@ -1111,17 +1111,17 @@ "TomTom flow unavailable": "Fluxo do TomTom indisponível", "SIMULATED — {reason}": "SIMULADO — {reason}", "Syncing flow · Roads: {source}": "Sincronizando fluxo · Vias: {source}", - "LIVE · Roads: {source} · Roads without flow hidden": "AO VIVO · Vias: {source} · Vias sem fluxo ocultas", - "LIVE · Roads: {source} · No flow roads in view": "AO VIVO · Vias: {source} · Nenhuma via com fluxo na vista", - "LIVE · Roads: {source} · Flow {percent}%": "AO VIVO · Vias: {source} · Fluxo {percent}%", - "SIMULATED · Roads: {source} · Flow {percent}%": "SIMULADO · Vias: {source} · Fluxo {percent}%", + "LIVE · Roads: {source} · Roads without flow hidden": "AO VIVO · Vias: {source} · Vias sem dados de fluxo ocultas", + "LIVE · Roads: {source} · No flow roads in view": "AO VIVO · Vias: {source} · Nenhuma via com dados de fluxo na vista", + "LIVE · Roads: {source} · Flow {percent}%": "AO VIVO · Vias: {source} · Fluxo: {percent}% cob", + "SIMULATED · Roads: {source} · Flow {percent}%": "SIMULADO · Vias: {source} · Fluxo: {percent}% cob", "Syncing flow · Roads: OpenStreetMap · Flow: TomTom · Unmatched: simulated": "Sincronizando fluxo · Vias: OpenStreetMap · Fluxo: TomTom · Sem correspondência: simulado", "LIVE · Roads: OpenStreetMap · Flow: TomTom · {percent}% cov · Unmatched: simulated": "AO VIVO · Vias: OpenStreetMap · Fluxo: TomTom · {percent}% cob · Sem correspondência: simulado", "LIVE · Roads: OpenStreetMap · Flow: TomTom · {percent}% cov": "AO VIVO · Vias: OpenStreetMap · Fluxo: TomTom · {percent}% cob", "SIMULATED · Roads: OpenStreetMap · Flow: TomTom (no matches)": "SIMULADO · Vias: OpenStreetMap · Fluxo: TomTom (sem correspondências)", "SIMULATED — traffic service unreachable": "SIMULADO — serviço de trânsito inacessível", "SIMULATED — add TomTom key for live": "SIMULADO — adicione a chave do TomTom para dados ao vivo", - "OpenFreeMap tiles rate-limited": "Blocos do OpenFreeMap com limite de requisições", + "OpenFreeMap tiles rate-limited": "Blocos do OpenFreeMap: limite de requisições atingido", "OpenFreeMap tiles timed out": "Os blocos do OpenFreeMap excederam o tempo limite", "OpenFreeMap tiles unavailable": "Blocos do OpenFreeMap indisponíveis", "occupancy|empty": "vazio", @@ -1231,9 +1231,9 @@ "Hourly global mosaic; usually 2–3 hours delayed": "Mosaico global por hora; normalmente com 2–3 horas de atraso", "GOES regional clouds; approximately 5-minute updates": "Nuvens regionais do GOES; atualizações a cada 5 minutos aproximadamente", "Clouds only": "Só nuvens", - "Apply the full cloud brightness key; 100% filter strength": "Aplica o filtro completo de brilho das nuvens; intensidade do filtro 100%", + "Apply the full cloud brightness key; 100% filter strength": "Aplicar o filtro completo de brilho das nuvens; intensidade do filtro 100%", "Full": "Completa", - "Show the complete infrared image; 0% filter strength": "Mostra a imagem infravermelha completa; intensidade do filtro 0%", + "Show the complete infrared image; 0% filter strength": "Mostrar a imagem infravermelha completa; intensidade do filtro 0%", "Soft": "Suave", "Vivid": "Intensa", "Image opacity; does not alter the observed values": "Opacidade da imagem; não altera os valores observados", @@ -1282,7 +1282,7 @@ "Reduced motion": "Movimento reduzido", "Resume": "Retomar", "Pause": "Pausar", - "Pause visual flow; forecast time does not advance with animation": "Pausa o fluxo visual; o horário da previsão não avança com a animação", + "Pause visual flow; forecast time does not advance with animation": "Pausar o fluxo visual; o horário da previsão não avança com a animação", "None": "Nenhum", "Speed": "Velocidade", "Pressure": "Pressão", @@ -1475,7 +1475,7 @@ "New anchor ID": "ID da nova âncora", "Capture camera as anchor": "Capturar a câmera como âncora", "Anchor added to draft": "Âncora adicionada ao rascunho", - "Set move start to current camera": "Definir o início do movimento na câmera atual", + "Set move start to current camera": "Usar a câmera atual como início do movimento", "Move added to draft; destination remains the shot camera": "Movimento adicionado ao rascunho; o destino continua sendo a câmera do plano", "Use ordinary flight": "Usar voo comum", "Invalid shot JSON": "JSON de plano inválido", @@ -1500,7 +1500,7 @@ "SDR decoder worker failed": "Falha no processo do decodificador SDR", "SDR decoder did not start; receiver stopped": "O decodificador SDR não iniciou; receptor parado", "SDR decoder stopped responding; receiver stopped": "O decodificador SDR parou de responder; receptor parado", - "SDR decoder fell behind; receiver stopped": "O decodificador SDR ficou para trás; receptor parado", + "SDR decoder fell behind; receiver stopped": "O decodificador SDR não acompanhou os dados recebidos; receptor parado", "WebUSB requires desktop Chrome or Edge": "O WebUSB requer Chrome ou Edge para desktop", "Waiting for an RTL-SDR device…": "Aguardando um dispositivo RTL-SDR…", "Browser audio is suspended; press Connect again to resume it": "O áudio do navegador está suspenso; pressione Conectar de novo para retomá-lo", @@ -1542,7 +1542,7 @@ "unsaved CCTV calibration": "a calibração de CCTV não salva", "the open cockpit": "a cabine aberta", "Switching language reloads the page. This will be lost: {items}. Switch anyway?": "Mudar de idioma recarrega a página. Isto será perdido: {items}. Mudar mesmo assim?", - "VISUAL PRESETS": "PREDEFINIÇÕES VISUAIS", + "VISUAL PRESETS": "PREDEF. VISUAIS", "LOCATION": "LOCAL", "CONTACTS — nearest planes · vessels · sites": "CONTATOS — aviões · embarcações · locais mais próximos", "SPACE MISSIONS — launches & orbital assets": "MISSÕES ESPACIAIS — lançamentos e ativos orbitais", @@ -1554,7 +1554,7 @@ "Copy failed": "Falha ao copiar", "Return map to straight-down view": "Voltar o mapa à vista de cima", "Tilt map to oblique view": "Inclinar o mapa para uma vista oblíqua", - "Reset map to north up. Current heading {heading} degrees": "Orientar o mapa com o norte para cima. Rumo atual: {heading} graus", + "Reset map to north up. Current heading {heading} degrees": "Orientar o mapa com o norte para cima. Orientação atual: {heading} graus", "Tilted view": "Vista inclinada", "Straight-down view": "Vista de cima", "North up": "Norte para cima", @@ -1645,7 +1645,7 @@ "CYCLE ON": "CICLO LIGADO", "CYCLE OFF": "CICLO DESLIG.", "Stop automatic page cycling. Previous, Next, and the SIG/NEWS/LOCAL tabs stay available.": "Parar a rotação automática de páginas. Anterior, Próxima e as abas SIG/NOTÍCIAS/LOCAL continuam disponíveis.", - "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.": "Alterna as páginas do briefing automaticamente a cada 9 segundos (Sinais → Notícias → Local). Pausa enquanto você passa o mouse ou foca o painel. Os dados de sinais ao vivo continuam atualizando de qualquer forma.", + "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.": "Alternar as páginas do briefing automaticamente a cada 9 segundos (Sinais → Notícias → Local). A alternância pausa enquanto você passa o mouse ou foca o painel. Os dados de sinais ao vivo continuam sendo atualizados de qualquer forma.", "ACQUIRING REGIONAL NEWS": "OBTENDO NOTÍCIAS DA ÁREA", "REGIONAL NEWS UNAVAILABLE": "NOTÍCIAS DA ÁREA INDISPONÍVEIS", "RESOLVING REGION": "IDENTIFICANDO REGIÃO", @@ -1958,7 +1958,7 @@ "Station unavailable after directory refresh": "Estação indisponível após atualizar o diretório", "Radio could not {action} cleanly": "Não foi possível {action} o rádio corretamente", "Go to expanded Radio section": "Ir para a seção de rádio expandida", - "Expand Radio section in Context": "Expandir a seção de rádio em Contexto", + "Expand Radio section in Context": "Expandir a seção de rádio em \"Contexto\"", "Close compact Radio controls": "Fechar controles compactos do rádio", "Open compact Radio controls": "Abrir controles compactos do rádio", "SYNC": "SINC", @@ -2019,7 +2019,7 @@ "Point the camera at the ground to use the view": "Aponte a câmera para o chão para usar a vista", "That point cannot anchor a box": "Esse ponto não pode ancorar uma área", "Imagery stops at ±{limit}° latitude": "As imagens vão até ±{limit}° de latitude", - "{owner} is using the pointer — close it first": "Ponteiro em uso: {owner}. Feche-o primeiro", + "{owner} is using the pointer — close it first": "A ferramenta \"{owner}\" está usando o ponteiro — feche-a primeiro", "Box is {size} wide · limit {limit}": "A área tem {size} de largura · limite {limit}", "View is {size} wide · limit {limit}": "A vista tem {size} de largura · limite {limit}", "VS BASEMAP": "VS MAPA BASE", @@ -2167,7 +2167,7 @@ "RETRYING ALPR CAMERAS": "BUSCANDO DE NOVO AS CÂMERAS ALPR", "FETCHING ALPR CAMERAS": "BUSCANDO CÂMERAS ALPR", "OVERPASS TEMPORARILY UNAVAILABLE": "OVERPASS TEMPORARIAMENTE INDISPONÍVEL", - "OVERPASS RATE-LIMITED": "OVERPASS COM LIMITE DE REQUISIÇÕES", + "OVERPASS RATE-LIMITED": "OVERPASS: LIMITE DE REQUISIÇÕES ATINGIDO", "OVERPASS TIMED OUT": "TEMPO ESGOTADO NO OVERPASS", "OVERPASS COULD NOT COMPLETE THE QUERY": "OVERPASS NÃO CONSEGUIU CONCLUIR A CONSULTA", "MAP TILES TEMPORARILY UNAVAILABLE": "BLOCOS DO MAPA TEMPORARIAMENTE INDISPONÍVEIS", @@ -2232,8 +2232,8 @@ "other": "{count} feeds ao vivo" }, "{feed} {count} ({seconds}s old)": "{feed} {count} (há {seconds} s)", - "Street Level toggle failed": "Não foi possível ativar ou desativar a camada Nível da rua", - "Street Level could not start": "Não foi possível iniciar Nível da rua", + "Street Level toggle failed": "Não foi possível ativar ou desativar a camada \"Nível da rua\"", + "Street Level could not start": "Não foi possível iniciar a camada \"Nível da rua\"", "SHRINK": "REDUZIR", "EXPAND": "AMPLIAR", "Shrink": "Reduzir", @@ -2253,8 +2253,8 @@ "other": "ÚLTIMOS {count} DIAS" }, "{window} · SINCE {date}": "{window} · DESDE {date}", - "Turn Street Level off": "Desativar Nível da rua", - "Turn Street Level on": "Ativar Nível da rua", + "Turn Street Level off": "Desativar \"Nível da rua\"", + "Turn Street Level on": "Ativar \"Nível da rua\"", "{name} imagery on": "Imagens do {name} ativadas", "{name} imagery off": "Imagens do {name} desativadas", "Image by {creator}": "Imagem de {creator}", @@ -2262,7 +2262,7 @@ "OPEN {labels}": "ABRIR {labels}", "Open {names} at the centre of the view": "Abrir {names} no centro da vista", "Zoom in to a street to open {names} here": "Aproxime-se de uma rua para abrir {names} aqui", - "Switch Street Level on to draw its coverage.": "Ative Nível da rua para desenhar a cobertura.", + "Switch Street Level on to draw its coverage.": "Ative \"Nível da rua\" para desenhar a cobertura.", "Every provider is switched off: light a chip to draw its coverage.": "Todos os provedores estão desligados: ative um para desenhar a cobertura dele.", "Loading this sequence…": "Carregando esta sequência…", "{n} images in this sequence · Esc clears": { @@ -2346,7 +2346,7 @@ "Custom": "Personalizado", "These preferences stay in this browser.": "Estas preferências ficam neste navegador.", "VOICE SYSTEM ERROR": "ERRO NO SISTEMA DE VOZ", - "DISMISS": "DISPENSAR", + "DISMISS": "FECHAR", "Check microphone permission and network access, then try again.": "Verifique a permissão do microfone e o acesso à rede, e tente novamente.", "Gemini returned an oversized audio chunk": "O Gemini retornou um trecho de áudio grande demais", "Gemini returned an unsupported audio format": "O Gemini retornou um formato de áudio não suportado", @@ -2525,7 +2525,7 @@ "the flights layer loads by viewport": "a camada de voos carrega conforme a vista", "distance is ground distance, not overhead": "a distância é medida no solo até o ponto subsatélite, não até o satélite", "the count is a lower bound because at least one layer reached its retained limit.": "a contagem é um mínimo porque pelo menos uma camada atingiu o limite de retenção.", - "{label} off": "{label}: desativado", + "{label} off": "{label}: camada desativada", "{label} loading": "{label}: carregando", "{label} error": "{label}: erro", "counted the first {returned} loaded records": "foram contados os primeiros {returned} registros carregados", @@ -2578,7 +2578,7 @@ "{name} is no longer loaded": "{name} não está mais carregado", "Unknown target layer: {target}": "Camada de destino desconhecida: {target}", "nominal": "nominal", - "{label} on": "{label}: ativado", + "{label} on": "{label}: camada ativada", "Frame aircraft": "Enquadrar aeronaves", "Frame military aircraft": "Enquadrar aeronaves militares", "Frame ships": "Enquadrar embarcações", @@ -2949,7 +2949,7 @@ "RESET CAL": "REDEFINIR CAL", "SCENE SUMMARY": "RESUMO DA CENA", "STREET LEVEL": "NÍVEL DA RUA", - "Turn Street Level on or off": "Ativar ou desativar Nível da rua", + "Turn Street Level on or off": "Ativar ou desativar \"Nível da rua\"", "Show the street-level view full screen (Esc shrinks it)": "Mostrar a vista no nível da rua em tela cheia (Esc reduz)", "Image fit": "Ajuste da imagem", "FIT": "AJUSTAR", @@ -3002,6 +3002,6 @@ "EXPLORE MANUALLY": "EXPLORAR MANUALMENTE", "Begin with a clean globe": "Comece com um globo limpo", "Don't show this again": "Não mostrar novamente", - "ESC to dismiss": "ESC para dispensar", + "ESC to dismiss": "ESC para fechar", "Tip: the GEV MIC button in the dock lets you talk to the map.": "Dica: o botão GEV MIC no dock permite falar com o mapa." } diff --git a/src/layers/cctv/presentation.js b/src/layers/cctv/presentation.js index e47e08194..898e4605c 100644 --- a/src/layers/cctv/presentation.js +++ b/src/layers/cctv/presentation.js @@ -1,5 +1,5 @@ import { CCTV_AMBIENT_CARD_MAX } from '../../data/cctvLod.js'; -import { t } from '../../i18n/index.js'; +import { msg, t } from '../../i18n/index.js'; import { ACTIVE_FRAME_REFRESH_MS, IDLE_FRAME_REFRESH_MS } from './policy.js'; import { headingHudToken, isHeadingEstimated } from './headingConfidence.js'; import { @@ -8,6 +8,59 @@ import { isDatasheetFov, } from './modelSpecs.js'; +// The summary line names the CAL badge, the source kind and the view band in +// the page language; the codes underneath stay English. +const CAL_BADGE_LABELS = Object.freeze({ + calibrated: msg('CALIBRATED'), + curated: msg('CURATED'), + 'raw-prior': msg('RAW PRIOR'), +}); + +// The same source-kind words as the CCTV panel (src/ui/cctvFrames.js). +const SOURCE_KIND_LABELS = Object.freeze({ + snapshot: msg('SNAPSHOT'), + live: msg('LIVE'), + fallback: msg('FALLBACK'), + upstream: msg('UPSTREAM'), + synthetic: msg('SYNTHETIC'), + configured: msg('CONFIGURED'), + seed: msg('SEED'), + image: msg('IMAGE'), + unknown: msg('UNKNOWN'), +}); + +/** CAL badge id ('raw-prior') as the summary shows it; unknown ids stay codes. */ +export function summaryCalLabel(badge) { + const key = String(badge || ''); + return CAL_BADGE_LABELS[key] + ? t(CAL_BADGE_LABELS[key]) + : key.replace('-', ' ').toUpperCase(); +} + +/** Source kind ('image', 'snapshot') for the summary; HLS, MJPEG… stay codes. */ +export function summarySourceLabel(kind) { + const key = String(kind || 'image').toLowerCase(); + return SOURCE_KIND_LABELS[key] + ? t(SOURCE_KIND_LABELS[key]) + : key.toUpperCase(); +} + +/** View band id ('street', 'city'…) as the HUD names it. */ +export function summaryViewBandLabel(band) { + switch (band) { + case 'street': + return t('STREET', { context: 'view band' }); + case 'city': + return t('CITY', { context: 'view band' }); + case 'regional': + return t('REGIONAL', { context: 'view band' }); + case 'global': + return t('GLOBAL', { context: 'view band' }); + default: + return String(band || '').toUpperCase(); + } +} + export function createPresentation({ state: layerState, services, @@ -72,17 +125,13 @@ export function createPresentation({ : t('ISOLATED VIEW'), layerState._showProjection ? t('PROJ MONITOR') : t('PROJ OFF'), layerState._coverageMode === 'viewshed' ? t('VIEWSHED') : null, - t('CAL {value}', { - value: calBadge.replace('-', ' ').toUpperCase(), + t('CAL {value}', { value: summaryCalLabel(calBadge) }), + t('SRC {value}', { + value: summarySourceLabel( + health?.sourceKind || active.camera.feedType || 'image', + ), }), - health?.sourceKind - ? t('SRC {value}', { - value: String(health.sourceKind).toUpperCase(), - }) - : t('SRC {value}', { - value: String(active.camera.feedType || 'image').toUpperCase(), - }), - t('{value} CONTEXT', { value: viewBand.toUpperCase() }), + t('{value} CONTEXT', { value: summaryViewBandLabel(viewBand) }), // Identified hardware: append the model's datasheet specs + attribution. active.camera.spec ? t('{spec} · SPECS: CCTV-DATABASE.COM', { diff --git a/src/layers/cctv/presentation.test.mjs b/src/layers/cctv/presentation.test.mjs new file mode 100644 index 000000000..a0600f9a4 --- /dev/null +++ b/src/layers/cctv/presentation.test.mjs @@ -0,0 +1,38 @@ +// The CCTV summary line names the CAL badge, the source kind and the view +// band in the page language; unknown codes stay as uppercase codes. +import assert from 'node:assert/strict'; +import test from 'node:test'; +import { setLocale } from '../../i18n/index.js'; +import { + summaryCalLabel, + summarySourceLabel, + summaryViewBandLabel, +} from './presentation.js'; + +function inLocale(locale, run) { + setLocale(locale); + try { + return run(); + } finally { + setLocale('en'); + } +} + +test('English keeps the summary codes', () => { + assert.equal(summaryCalLabel('raw-prior'), 'RAW PRIOR'); + assert.equal(summarySourceLabel('image'), 'IMAGE'); + assert.equal(summarySourceLabel('hls'), 'HLS'); + assert.equal(summaryViewBandLabel('street'), 'STREET'); + assert.equal(summaryViewBandLabel('none'), 'NONE'); +}); + +test('Portuguese summary values are translated', () => { + inLocale('pt', () => { + assert.equal(summaryCalLabel('raw-prior'), 'ESTIMATIVA BRUTA'); + assert.equal(summaryCalLabel('calibrated'), 'CALIBRADA'); + assert.equal(summarySourceLabel('IMAGE'), 'IMAGEM'); + assert.equal(summarySourceLabel('mjpeg'), 'MJPEG'); + assert.equal(summaryViewBandLabel('street'), 'RUA'); + assert.equal(summaryViewBandLabel('city'), 'CIDADE'); + }); +}); From bceeb37836439b72c773c2571aaadb165d113b6b Mon Sep 17 00:00:00 2001 From: German Khokhlov Date: Wed, 28 Oct 2026 22:44:25 +0400 Subject: [PATCH 37/83] i18n(de): apply review round 3 Co-Authored-By: Claude Opus 5.5 --- docs/translations/de.md | 11 ++++- src/data/bhoteKoshiEmbeddedMedia.js | 1 + src/i18n/locales/de.json | 63 +++++++++++++++-------------- src/i18n/locales/es.json | 1 + src/i18n/locales/ru.json | 1 + src/i18n/locales/zh-CN.json | 1 + src/i18n/locales/zh-Hant.json | 1 + src/i18n/same-as-english.json | 4 ++ 8 files changed, 50 insertions(+), 33 deletions(-) diff --git a/docs/translations/de.md b/docs/translations/de.md index 7c1d602cc..62e7420a3 100644 --- a/docs/translations/de.md +++ b/docs/translations/de.md @@ -10,16 +10,18 @@ Translation source: abiyeenzo (#908). - No direct address: neither «Sie» nor «du». Actions and hints use the neutral infinitive: «Erneut versuchen», «Kamera anklicken zum Aktivieren», «Zuerst eine Aufnahme wählen», «Mikrofonzugriff erlauben und erneut versuchen». "Your" becomes the article or «eigene»: «Eigener RTL-SDR-Empfänger», «Die IP-Adresse ist für diesen Sender sichtbar». - Nouns are capitalized, as German requires; otherwise sentence case, not Title Case: "Live Flights" → «Live-Flüge», "Provider Settings" → «Anbieter-Einstellungen». UPPERCASE English stays UPPERCASE: «LIVE-DATEN AUS», «KEINE ENTWARNUNG». In UPPERCASE, ß is written SS: «SCHLIESSEN», «STRASSENEBENE». - Compounds are written as one word or with a hyphen next to a name, code or English term: «Datenebene», «Wetterkacheln», «TomTom-Schlüssel», «AIS-Schiffe», «Street-View-Fallback». Do not split them with spaces. -- Short labels, chips and HUD readouts stay short. German runs about a third longer than English, so prefer a short word or a standard abbreviation with a period over a wrapped line: REICHW., GESCHW., NIEDERSCHL., SONST., NACHR., VERST., VGL., KAL. +- Short labels, chips and HUD readouts stay short. German runs about a third longer than English, so prefer a short word or a standard abbreviation with a period over a wrapped line: REICHW., GESCHW., NIEDERSCHL., SONST., NACHR., VERST., VGL., KAL., KOMM. (a bare «KOMM» reads as the imperative) - The avionics codes HDG, BRG, CRS, DEST, SPD, ALT, GS, TRK, V/S, FOV and SQUAWK stay in English, as in the cockpit. Words used in a sentence are translated: heading → «Kurs», bearing → «Peilung», range → «Reichweite». - A dash between clauses is a spaced en dash « – »; a colon is fine where it explains: «Feed ausgefallen – neue Versuche in größeren Abständen», «SIMULIERT: Verkehrsdienst nicht erreichbar». Quotes are „…“. - Status and waiting messages use the neutral infinitive too: «Warten auf Aktualisierung», not «Warte auf …». Reasons inserted after a dash stay lower case: «Szene nicht gespeichert – das Projekt ist größer als 5 MiB». +- A layer named in a sentence takes its panel name in quotes: «Die Ebene „Live-Flüge“ ist nicht aktiviert», «die Ebene „Live-Flüge“ lädt Daten für den jeweiligen Bildausschnitt». +- Rolling time windows say their length, so they cannot read as the previous calendar period: LAST YEAR → «LETZTE 12 MONATE», LAST MONTH → «LETZTE 30 TAGE». - Keyboard keys are named as on German keyboards where they differ: Leertaste, Rücktaste, Umschalt; Esc, Enter, Tab and letter keys stay. - Decimal comma in fixed text: «M4,4», «28,2710° N». Thousands separator is a period: «1.000 km». Formatted numbers come from `Intl` and are already German. - Units: km, m, km/h, m/s, kn (knots, also in the cockpit), ft (feet), hPa, MW, h, min, s, T (days, in short readouts); in UPPERCASE text KM, KM/H, KN, FT, MIN. A space between number and unit, in compact readouts too: «{value} m», «{count} min», «50 %», «{speed} KN», «{count} / 30 T». `°` sticks to the number. - "ago" goes before the time: «vor {count} min», «vor {value}». When a placeholder already holds a localized "ago" text (`{age}` in `STALE · cached {age}`, `{ago}`), do not add «vor» again. - Compass points use O for Ost: N, NNO, NO, ONO, O, OSO, SO, SSO, S, SSW, SW, WSW, W, WNW, NW, NNW; hemisphere letters N, S, O, W. -- Routing: direction words are lowercase adverbs (links, leicht rechts, scharf links, geradeaus), so a sentence never starts with one: «Auf {road} {direction} abbiegen», «Dann {direction} abbiegen», «Weiter {direction}». Roundabout exits are ordinals with a period: «die {exit} Ausfahrt» → «die 2. Ausfahrt». A straight lane is the one that leads straight on, not the middle one: «Die geradeaus führende Spur benutzen». +- Routing: direction words are lowercase adverbs (links, leicht rechts, scharf links, geradeaus), so a sentence never starts with one: «Auf {road} {direction} abbiegen», «Dann {direction} abbiegen», «Weiter {direction}». Roundabout exits are ordinals with a period: «die {exit} Ausfahrt» → «die 2. Ausfahrt». A lane is named by where it leads, not by its position: «Die geradeaus führende Spur benutzen», «die leicht nach links führende», «die scharf nach rechts führende» (not «halblinke» or «äußerst linke»). ## Plurals @@ -59,6 +61,7 @@ Keep the verb in agreement: «{count} Station meldet» / «{count} Stationen mel | camera / CCTV camera / camera badge | Kamera / CCTV-Kamera / Kamera-Markierung | | earthquake / active fire / fire perimeter | Erdbeben / aktiver Brand / Brandgrenze | | cyclone / advisory (NHC/CPHC) / cone | Wirbelsturm / Lagebericht (not «Warnung») / Kegel | +| issued (advisory, forecast) | ausgegeben | | radio station | Sender | | broadcast FM | UKW | | road / flow (traffic) / flow coverage | Straße / Verkehrsfluss / Live-Abdeckung | @@ -79,6 +82,9 @@ Keep the verb in agreement: «{count} Station meldet» / «{count} Stationen mel | HDG / BRG / CRS / DEST / SPD / FOV | unchanged | | RANGE / PITCH / HGT (CCTV calibration chips) | REICHW. / NEIGUNG / HÖHE | | PREV / NEXT | ZURÜCK / WEITER | +| RESUME (radio transport button) | FORTSETZEN (not «WEITER», which is NEXT in the same row) | +| nearest (spatial) | nächstgelegen (where «nächste» could read as NEXT) | +| expand / collapse (sections) | ausklappen / einklappen | | L / R (relative bearing) | L / R | | SIG / NEWS / LOCAL (briefing tabs) | SIG / NEWS / LOKAL | | NOT AN ALL-CLEAR | KEINE ENTWARNUNG | @@ -92,6 +98,7 @@ Keep the verb in agreement: «{count} Station meldet» / «{count} Stationen mel | card (host card) / voice card | Eintrag (in hints), Infokarte / Sprachkarte | | label (on the map) / clear (switch off layers) | Beschriftung / ausschalten (not «löschen») | | station tag (radio filter) | Kategorie | +| DIRECTORY BAND / {category} BAND (radio dial) | SENDERSKALA / SENDERSKALA · {category} (not «-BAND»: «ROCK-BAND») | | MIC (dock button) | MIKRO | | frame (weather, video) / image | Frame / Bild | | collapse / landslide (Bhote Koshi) | Erdrutsch (not «Abbruch», which reads as "cancel") | diff --git a/src/data/bhoteKoshiEmbeddedMedia.js b/src/data/bhoteKoshiEmbeddedMedia.js index 1ea0ccec9..49f704066 100644 --- a/src/data/bhoteKoshiEmbeddedMedia.js +++ b/src/data/bhoteKoshiEmbeddedMedia.js @@ -66,6 +66,7 @@ const EVENT_PACK_TEXT = new Set([ msg('Border gate'), msg('Timure evidence cluster'), msg('Mailung / Upper Trishuli bridge'), + msg('Upper Trishuli'), msg('Dandagaun viewpoint restaurant'), msg('Dandagaun viewpoint'), msg('Bidur - Trishuli bridge'), diff --git a/src/i18n/locales/de.json b/src/i18n/locales/de.json index ef333f5d2..7bdcf73af 100644 --- a/src/i18n/locales/de.json +++ b/src/i18n/locales/de.json @@ -33,7 +33,7 @@ "Geostationary belt — comms and weather, fixed over the equator": "Geostationärer Gürtel: Kommunikation und Wetter, fest über dem Äquator", "VISUAL": "VISUELL", "Brightest naked-eye objects — CelesTrak visual group": "Hellste mit bloßem Auge sichtbare Objekte: CelesTrak-Gruppe „visual“", - "COMMS": "KOMM", + "COMMS": "KOMM.", "Broadband constellation shell — shown only in DENSE mode": "Breitband-Konstellationsschale: nur im Modus DICHT sichtbar", "FISHING": "FISCHEREI", "TOWING": "SCHLEPPVERBAND", @@ -123,7 +123,7 @@ "Military flights": "Militärflüge", "AIS vessels": "AIS-Schiffe", "Mapped installations": "Kartierte Anlagen", - "syncing {count} city feeds...": "{count} Stadt-Feeds werden synchronisiert...", + "syncing {count} city feeds...": "Synchronisierung der Stadt-Feeds ({count})...", "scanning nearby systems...": "Systeme in der Nähe werden gesucht...", "Station {id}": "Station {id}", "Station": "Station", @@ -571,8 +571,8 @@ "Reconcile Radio — lifecycle uncertain": "Radio abgleichen: Lebenszyklus unklar", "Disable Radio": "Radio deaktivieren", "Enable Radio": "Radio aktivieren", - "DIRECTORY BAND": "VERZEICHNISBAND", - "{category} BAND": "{category}-BAND", + "DIRECTORY BAND": "SENDERSKALA", + "{category} BAND": "SENDERSKALA · {category}", "NO STATION SELECTED": "KEIN SENDER GEWÄHLT", "Directory metadata only": "Nur Verzeichnis-Metadaten", "Loading station directory…": "Senderverzeichnis wird geladen…", @@ -581,7 +581,7 @@ "Play": "Abspielen", "PLAY": "PLAY", "selected": "gewählter", - "nearest": "nächster", + "nearest": "nächstgelegener", "{action} {target} radio station": "{action}: {target} Radiosender", "RADIO STATE UNCERTAIN": "RADIOSTATUS UNKLAR", "SYNCING DIRECTORY": "VERZEICHNIS WIRD SYNCHRONISIERT", @@ -601,7 +601,7 @@ "Paused {station}": "{station} pausiert", "Broadcaster stream unavailable": "Sender-Stream nicht verfügbar", " · muted during voice interaction": " · stumm bei Sprachinteraktion", - " · restoring volume after voice": " · Lautstärke wird nach Sprache wiederhergestellt", + " · restoring volume after voice": " · Lautstärke wird nach der Sprachinteraktion wiederhergestellt", " · static indicates no broadcaster audio": " · Rauschen bedeutet: kein Sender-Audio", " · tuning static until broadcaster starts": " · Rauschen, bis der Sender startet", "Station unavailable after directory refresh — choose another channel": "Sender nach Verzeichnisaktualisierung nicht verfügbar: anderen Kanal wählen", @@ -615,7 +615,7 @@ "DEL": "ENTF.", "entity": "Objekt", "Shared {subject} follow expired": "Geteilte Verfolgung abgelaufen: {subject}", - "Shared {subject} could not be restored — feed unavailable": "Geteilt: {subject} konnte nicht wiederhergestellt werden, Feed nicht verfügbar", + "Shared {subject} could not be restored — feed unavailable": "Geteilt: {subject} konnte nicht wiederhergestellt werden – Feed nicht verfügbar", "Shared {subject} is unavailable": "Geteilt: {subject} ist nicht verfügbar", "ACQUIRING": "ERFASSUNG", "SHARED {subject}": "GETEILT: {subject}", @@ -747,7 +747,7 @@ "Pin location tray": "Standortleiste anheften", "Keep location tray open": "Standortleiste geöffnet lassen", "Search any location": "Beliebigen Ort suchen", - "Search location by name or coordinates": "Ort nach Name oder Koordinaten suchen", + "Search location by name or coordinates": "Ort nach Namen oder Koordinaten suchen", "Search any location...": "Ort suchen...", "WEATHER": "WETTER", "CONTEXT": "KONTEXT", @@ -935,6 +935,7 @@ "Border gate": "Grenzübergang", "Timure evidence cluster": "Beweiscluster Timure", "Mailung / Upper Trishuli bridge": "Mailung / Brücke am oberen Trishuli", + "Upper Trishuli": "Oberer Trishuli", "Dandagaun viewpoint restaurant": "Aussichtsrestaurant Dandagaun", "Dandagaun viewpoint": "Aussichtspunkt Dandagaun", "Bidur - Trishuli bridge": "Bidur – Trishuli-Brücke", @@ -994,7 +995,7 @@ "OBSERVED IMAGERY": "REALE BILDDATEN", "SCHEMATIC CORRIDOR": "SCHEMATISCHER KORRIDOR", "2021 HISTORICAL REFERENCE / 2026 POST-EVENT": "HISTORISCHE REFERENZ 2021 / NACH DEM EREIGNIS 2026", - "Historical reference and post-event image split": "Bildvergleich: historische Referenz und nach dem Ereignis", + "Historical reference and post-event image split": "Bildvergleich: historische Referenz und Bild nach dem Ereignis", "RECONSTRUCTION CLOCK": "REKONSTRUKTIONSUHR", "Schematic downstream progression": "Schematischer Verlauf flussabwärts", "Story beat navigation": "Navigation durch die Story", @@ -1289,7 +1290,7 @@ }, "Position as of {time}": "Position, Stand {time}", "Maximum sustained wind: {wind} · Pressure: {pressure}": "Maximaler Dauerwind: {wind} · Luftdruck: {pressure}", - "{name} · {classification} · Advisory {number} · issued {time}": "{name} · {classification} · Lagebericht {number} · herausgegeben {time}", + "{name} · {classification} · Advisory {number} · issued {time}": "{name} · {classification} · Lagebericht {number} · ausgegeben {time}", "No active NHC/CPHC systems": "Keine aktiven NHC/CPHC-Systeme", "Advisories unavailable": "Lageberichte nicht verfügbar", "Cyclones · NHC / CPHC": "Wirbelstürme · NHC / CPHC", @@ -1332,10 +1333,10 @@ "fork direction|straight": "geradeaus", "lane direction|left": "linke", "lane direction|right": "rechte", - "lane direction|slightly left": "halblinke", - "lane direction|slightly right": "halbrechte", - "lane direction|sharply left": "äußerst linke", - "lane direction|sharply right": "äußerst rechte", + "lane direction|slightly left": "leicht nach links führende", + "lane direction|slightly right": "leicht nach rechts führende", + "lane direction|sharply left": "scharf nach links führende", + "lane direction|sharply right": "scharf nach rechts führende", "lane direction|straight": "geradeaus führende", "ordinal|{number}st": "{number}.", "ordinal|{number}nd": "{number}.", @@ -2005,14 +2006,14 @@ "New anchor ID": "Neue Anker-ID", "Capture camera as anchor": "Kamera als Anker erfassen", "Anchor added to draft": "Anker zum Entwurf hinzugefügt", - "Set move start to current camera": "Startpunkt des Flugs auf aktuelle Kamera setzen", + "Set move start to current camera": "Aktuelle Kameraposition als Startpunkt des Flugs übernehmen", "Move added to draft; destination remains the shot camera": "Flug zum Entwurf hinzugefügt; das Ziel bleibt die Kameraposition der Aufnahme", "Use ordinary flight": "Normalen Flug verwenden", "Invalid shot JSON": "Ungültiges Aufnahme-JSON", "Apply details": "Details anwenden", "Select a scene first": "Zuerst eine Szene wählen", "Share selected scene": "Gewählte Szene teilen", - "Scene JSON preserves authored settings and attribution. It does not include asset files. Bundles include only pack files you choose here or previously imported bundle files.": "Szenen-JSON bewahrt die gestalteten Einstellungen und Quellenangaben. Asset-Dateien sind nicht enthalten. Bundles enthalten nur die hier gewählten Paketdateien oder zuvor importierte Bundle-Dateien.", + "Scene JSON preserves authored settings and attribution. It does not include asset files. Bundles include only pack files you choose here or previously imported bundle files.": "Szenen-JSON bewahrt die festgelegten Einstellungen und Quellenangaben. Asset-Dateien sind nicht enthalten. Bundles enthalten nur die hier gewählten Paketdateien oder zuvor importierte Bundle-Dateien.", "Download scene JSON": "Szenen-JSON herunterladen", "Choose data-pack files": "Datenpaket-Dateien wählen", "Or choose a data-pack folder": "Oder einen Datenpaket-Ordner wählen", @@ -2069,7 +2070,7 @@ "Ironbow": "Ironbow", "unsaved CCTV calibration": "ungespeicherte CCTV-Kalibrierung", "the open cockpit": "das geöffnete Cockpit", - "Switching language reloads the page. This will be lost: {items}. Switch anyway?": "Ein Sprachwechsel lädt die Seite neu. Dabei geht verloren: {items}. Trotzdem wechseln?", + "Switching language reloads the page. This will be lost: {items}. Switch anyway?": "Ein Sprachwechsel lädt die Seite neu. Dabei geht Folgendes verloren: {items}. Trotzdem wechseln?", "Link shared": "Link geteilt", "Return map to straight-down view": "Karte wieder senkrecht von oben zeigen", "Tilt map to oblique view": "Karte in Schrägansicht kippen", @@ -2240,11 +2241,11 @@ "Los Angeles": "Los Angeles", "CH {index} / {total}": "KAN {index} / {total}", "Station unavailable after directory refresh": "Sender nach Verzeichnisaktualisierung nicht verfügbar", - "Go to expanded Radio section": "Zum erweiterten Radiobereich", - "Expand Radio section in Context": "Radiobereich im Kontext erweitern", + "Go to expanded Radio section": "Zum ausgeklappten Radio-Bereich", + "Expand Radio section in Context": "Radio-Bereich in „Kontext“ ausklappen", "{category} ({count})": "{category} ({count})", "PAUSE": "PAUSE", - "RESUME": "WEITER", + "RESUME": "FORTSETZEN", "Clear reading": "Wert ausblenden", "Earlier observation": "Frühere Beobachtung", "Observed history": "Beobachteter Verlauf", @@ -2448,10 +2449,10 @@ "LAST 5 YEARS": "LETZTE 5 JAHRE", "LAST 3 YEARS": "LETZTE 3 JAHRE", "LAST 2 YEARS": "LETZTE 2 JAHRE", - "LAST YEAR": "LETZTES JAHR", + "LAST YEAR": "LETZTE 12 MONATE", "LAST 6 MONTHS": "LETZTE 6 MONATE", "LAST 3 MONTHS": "LETZTE 3 MONATE", - "LAST MONTH": "LETZTER MONAT", + "LAST MONTH": "LETZTE 30 TAGE", "LAST {count} DAYS": { "one": "{count} TAG", "other": "LETZTE {count} TAGE" @@ -2476,12 +2477,12 @@ "No sequences in view match the filter": "Keine Sequenzen im Bild passen zum Filter", "No coverage in view": "Keine Abdeckung im Bild", "{n} streets in view · click a line for its nearest photo": { - "one": "{n} Straße im Bild · Linie anklicken für das nächste Foto", - "other": "{n} Straßen im Bild · Linie anklicken für das nächste Foto" + "one": "{n} Straße im Bild · Linie anklicken für das nächstgelegene Foto", + "other": "{n} Straßen im Bild · Linie anklicken für das nächstgelegene Foto" }, "{n} sequences in view · click a line for its nearest photo": { - "one": "{n} Sequenz im Bild · Linie anklicken für das nächste Foto", - "other": "{n} Sequenzen im Bild · Linie anklicken für das nächste Foto" + "one": "{n} Sequenz im Bild · Linie anklicken für das nächstgelegene Foto", + "other": "{n} Sequenzen im Bild · Linie anklicken für das nächstgelegene Foto" }, "{n} sequences in view · click a line for its photos": { "one": "{n} Sequenz im Bild · Linie anklicken für ihre Fotos", @@ -2672,7 +2673,7 @@ "{items} {scope}": "{items} {scope}", "last 24 h": "letzte 24 h", "past 30 d and upcoming": "letzte 30 Tage und anstehende", - "the flights layer loads by viewport": "die Flugebene lädt nach Bildausschnitt", + "the flights layer loads by viewport": "die Ebene „Live-Flüge“ lädt Daten für den jeweiligen Bildausschnitt", "distance is ground distance, not overhead": "Entfernung am Boden, ohne Berücksichtigung der Höhe", "the count is a lower bound because at least one layer reached its retained limit.": "die Anzahl ist eine Untergrenze, weil mindestens eine Ebene ihr Speicherlimit erreicht hat.", "{label} off": "{label} aus", @@ -2683,7 +2684,7 @@ "{layers} just turned on — still loading, counts will rise": "{layers} gerade eingeschaltet – Daten werden noch geladen, die Zahlen steigen", "Contacts panel snapshot at {time} — the same retained cohort supplies the card, speech, and follow-up memory": "Snapshot des Kontaktbereichs um {time} – dieselbe gespeicherte Auswahl liefert die Sprachkarte, die Sprachausgabe und das Gedächtnis für Folgefragen", "Contacts panel snapshot — the same retained cohort supplies the card, speech, and follow-up memory": "Snapshot des Kontaktbereichs – dieselbe gespeicherte Auswahl liefert die Sprachkarte, die Sprachausgabe und das Gedächtnis für Folgefragen", - "Fly below {km} km to a covered region": "Unter {km} km zu einer abgedeckten Region fliegen", + "Fly below {km} km to a covered region": "Unter {km} km Höhe zu einer abgedeckten Region fliegen", "No feed here yet · {n} regions available": { "one": "Hier noch kein Feed · {n} Region verfügbar", "other": "Hier noch kein Feed · {n} Regionen verfügbar" @@ -2701,9 +2702,9 @@ "the active voice session": "die aktive Sprachsitzung", "{value} feet": "{value} Fuß", "Fire · FRP {frp} MW": "Brand · FRP {frp} MW", - "The flights layer is not enabled": "Die Ebene Flüge ist nicht aktiviert", - "The military layer is not enabled": "Die Militär-Ebene ist nicht aktiviert", - "The satellites layer is not enabled": "Die Ebene Satelliten ist nicht aktiviert", + "The flights layer is not enabled": "Die Ebene „Live-Flüge“ ist nicht aktiviert", + "The military layer is not enabled": "Die Ebene „Militärflüge“ ist nicht aktiviert", + "The satellites layer is not enabled": "Die Ebene „Satelliten“ ist nicht aktiviert", "The ais-live-vessels layer is not enabled": "Die Ebene „Live-Schiffe“ ist nicht aktiviert", "Could not enable the requested layer": "Die angeforderte Ebene konnte nicht aktiviert werden", "Could not disable the requested layer": "Die angeforderte Ebene konnte nicht deaktiviert werden", diff --git a/src/i18n/locales/es.json b/src/i18n/locales/es.json index 79780cb40..b1e4d259a 100644 --- a/src/i18n/locales/es.json +++ b/src/i18n/locales/es.json @@ -1991,6 +1991,7 @@ "Border gate": "Paso fronterizo", "Timure evidence cluster": "Grupo de evidencias de Timure", "Mailung / Upper Trishuli bridge": "Mailung / puente de Upper Trishuli", + "Upper Trishuli": "Upper Trishuli", "Dandagaun viewpoint restaurant": "Restaurante mirador de Dandagaun", "Dandagaun viewpoint": "Mirador de Dandagaun", "Bidur - Trishuli bridge": "Puente Bidur - Trishuli", diff --git a/src/i18n/locales/ru.json b/src/i18n/locales/ru.json index 93c0b389d..68856057a 100644 --- a/src/i18n/locales/ru.json +++ b/src/i18n/locales/ru.json @@ -2024,6 +2024,7 @@ "Border gate": "Погранпереход", "Timure evidence cluster": "Группа свидетельств у Timure", "Mailung / Upper Trishuli bridge": "Mailung / мост Upper Trishuli", + "Upper Trishuli": "Upper Trishuli", "Dandagaun viewpoint restaurant": "Ресторан со смотровой площадкой, Dandagaun", "Dandagaun viewpoint": "Смотровая площадка Dandagaun", "Bidur - Trishuli bridge": "Мост Bidur — Trishuli", diff --git a/src/i18n/locales/zh-CN.json b/src/i18n/locales/zh-CN.json index 854235f3d..93c11a8a9 100644 --- a/src/i18n/locales/zh-CN.json +++ b/src/i18n/locales/zh-CN.json @@ -62,6 +62,7 @@ "Border gate": "边境口岸", "Timure evidence cluster": "Timure 证据群", "Mailung / Upper Trishuli bridge": "Mailung / Upper Trishuli 桥", + "Upper Trishuli": "Upper Trishuli", "Dandagaun viewpoint restaurant": "Dandagaun 观景餐厅", "Dandagaun viewpoint": "Dandagaun 观景点", "Bidur - Trishuli bridge": "Bidur - Trishuli 桥", diff --git a/src/i18n/locales/zh-Hant.json b/src/i18n/locales/zh-Hant.json index 113a79e65..69e91f624 100644 --- a/src/i18n/locales/zh-Hant.json +++ b/src/i18n/locales/zh-Hant.json @@ -62,6 +62,7 @@ "Border gate": "邊境口岸", "Timure evidence cluster": "Timure 證據群", "Mailung / Upper Trishuli bridge": "Mailung / Upper Trishuli 橋", + "Upper Trishuli": "Upper Trishuli", "Dandagaun viewpoint restaurant": "Dandagaun 觀景餐廳", "Dandagaun viewpoint": "Dandagaun 觀景點", "Bidur - Trishuli bridge": "Bidur - Trishuli 橋", diff --git a/src/i18n/same-as-english.json b/src/i18n/same-as-english.json index d8a4247a7..3a136d79d 100644 --- a/src/i18n/same-as-english.json +++ b/src/i18n/same-as-english.json @@ -258,6 +258,7 @@ "Techno", "Trance", "USB {rate} msg/s", + "Upper Trishuli", "VISUAL", "VS", "WHOT/BHOT", @@ -305,6 +306,7 @@ "REC", "S2 GhostMaps", "S2 · {name}", + "Upper Trishuli", "VS", "WHOT/BHOT" ], @@ -341,6 +343,7 @@ "Techno", "Trance", "USB {rate} msg/s", + "Upper Trishuli", "WHOT/BHOT", "dB", "ft", @@ -398,6 +401,7 @@ "Techno", "Trance", "USB {rate} msg/s", + "Upper Trishuli", "WHOT/BHOT", "dB", "ft", From 6b3876b176c9005225f8e504f74741313b4a23b2 Mon Sep 17 00:00:00 2001 From: German Khokhlov Date: Wed, 28 Oct 2026 22:48:00 +0400 Subject: [PATCH 38/83] i18n(ja): apply review round 3 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Catalog fixes from the third review round: booster flight count ({count}回目の飛行), 晴れ for PARTLY CLOUDY, 配信元 for upstream, 部分的 for the PARTIAL feed state, または between provider names, POS kept as a HUD code, product names in their own case (YouTube, Facebook, Radio Browser, ChatGPT OAuth, Googleストリートビュー), Esc, bracketed button names, en-dash ranges, 土砂ダム湖 for both lake labels and smaller wording fixes. Guide: range rule and new glossary rows. Co-Authored-By: Claude Opus 5.5 --- docs/translations/ja.md | 6 ++- src/i18n/locales/ja.json | 88 +++++++++++++++++------------------ src/i18n/same-as-english.json | 1 + 3 files changed, 50 insertions(+), 45 deletions(-) diff --git a/docs/translations/ja.md b/docs/translations/ja.md index a790d329c..980a69a3d 100644 --- a/docs/translations/ja.md +++ b/docs/translations/ja.md @@ -18,6 +18,7 @@ Translation source: abiyeenzo (#913). ## Numbers, units and dates - Units: km, m, km/h, m/s, kt, ft, mph, hPa, MW, dB, °, % stay as written, with the English spacing (「250 km」, 「{frp} MW」, 「95 kt」). Code-built cockpit distances follow this too (`cockpitUnitCase` skips the HUD upper-casing for ja, as for zh). The cockpit's own speed caption is the HUD code KT, in 対地速度 · KT and under the readout. +- Number ranges keep the English en dash, not ~: 「2–6日ごと」, 「50–99%」, 「南緯25°–北緯80°」. - Time units are words written straight after the number: 秒, 分, 時間, 日 (「5分前」, 「{count}時間」, 「1時間5分」). `formatQuantity` and `formatRelativeTime` drop the space for Japanese unit words, so code-built values match the catalog. - Counters follow the thing counted: 機 (aircraft), 隻 (ships), 基 (satellites), 台 (cameras, vehicles), 局 (stations), 件 (records, results, events), か所 (sites), 個 (generic). Prefer a counter to a bare number. - Dates come from `Intl` and read year first: 2026年8月26日. Coordinates in prose are 北緯 / 東経; HUD hemisphere letters stay N, S, E, W. @@ -36,12 +37,15 @@ Translation source: abiyeenzo (#913). | LIVE (status) / live data | ライブ / ライブデータ | | SIMULATED | シミュレーション | | stale / degraded / unavailable | 更新遅延 / 性能低下 / 利用不可 | +| PARTIAL (feed state) | 部分的 | +| upstream (remote data source) | 配信元 | | retry | 再試行 | | key (API key) / POWER UP | キー(APIキー)/ パワーアップ | | Provider Settings | プロバイダー設定 | | globe / map / map source / basemap | 地球儀 / 地図 / マップソース / ベースマップ | | mapped (OSM-mapped sites) | マップ済み | | aircraft / flight / military flights | 航空機 / フライト / 軍用機 | +| FLIGHT {count} (a rocket stage's nth flight) | {count}回目の飛行 | | vessel, ship | 船舶 | | satellite | 衛星 | | launch (rocket) / space mission | 打ち上げ / 宇宙ミッション | @@ -60,7 +64,7 @@ Translation source: abiyeenzo (#913). | cockpit | コックピット | | heading / altitude / ground speed | 機首方位 / 高度 / 対地速度 | | track (TRK, direction over the ground) | 対地針路 | -| HDG / BRG / CRS / FOV | そのまま(HUDコード) | +| HDG / BRG / CRS / FOV / SPD / POS | そのまま(HUDコード) | | squawk | スコーク | | radio failure / emergency (7600 / 7700) | 通信機故障 / 緊急事態 | | map heading / North up | 方位 / 北を上に | diff --git a/src/i18n/locales/ja.json b/src/i18n/locales/ja.json index 4020b3874..e9f608cdb 100644 --- a/src/i18n/locales/ja.json +++ b/src/i18n/locales/ja.json @@ -56,7 +56,7 @@ "Immediate collapse viewpoint": "崩壊地点直近の視点", "Collapse viewpoint": "崩壊地点の視点", "Debris-dammed lake": "土砂ダム湖", - "Dammed lake": "せき止め湖", + "Dammed lake": "土砂ダム湖", "Second landslide": "第2の地すべり", "Gyirong border gate": "Gyirong国境ゲート", "Border gate": "国境ゲート", @@ -85,7 +85,7 @@ "X POST · PROVIDER CONTROLS": "Xの投稿 · 提供元で操作", "{reason} OPEN ORIGINAL.": "{reason}元の投稿を開いてください。", "X embed unavailable": "Xの埋め込みを利用できません。", - "FACEBOOK · PROVIDER CONTROLS": "FACEBOOK · 提供元で操作", + "FACEBOOK · PROVIDER CONTROLS": "Facebook · 提供元で操作", "Facebook embed unavailable": "Facebookの埋め込みを利用できません。", "AUTOPLAY BLOCKED · USE PROVIDER CONTROLS": "自動再生ブロック · 提供元で操作", "Embedded {provider} media for {source}": "{source}の埋め込み{provider}メディア", @@ -95,7 +95,7 @@ "OPEN ORIGINAL ↗": "元の投稿を開く ↗", "{provider} media: {source}": "{provider}メディア:{source}", "{provider} · PROVIDER CONTROLS": "{provider} · 提供元で操作", - "YOUTUBE {state} · OPEN ORIGINAL": "YOUTUBE {state} · 元の投稿を開く", + "YOUTUBE {state} · OPEN ORIGINAL": "YouTube {state} · 元の投稿を開く", "INITIATION": "発生", "DAMMING": "せき止め", "SECONDARY FAILURE": "二次崩壊", @@ -238,8 +238,8 @@ "Overpass temporarily unavailable": "Overpassが一時的に利用できません", "Retrying mapped sites…": "マップ済み施設を再試行中…", "Fetching mapped sites…": "マップ済み施設を取得中…", - "{reason} — retrying in {seconds}s": "{reason} — {seconds}秒後に再試行", - "{reason} — retry pending": "{reason} — 再試行待ち", + "{reason} — retrying in {seconds}s": "{reason}:{seconds}秒後に再試行", + "{reason} — retry pending": "{reason}:再試行待ち", "Zoom in to search mapped installations": "ズームインして、マップ済み施設を検索してください", "Showing cached mapped sites": "キャッシュ済みのマップ済み施設を表示中", "Mapped sites not loaded": "マップ済み施設は未読込です", @@ -261,7 +261,7 @@ "Directions": "ルート案内", "Recent imagery": "最近の衛星画像", "STATION": "宇宙ステーション", - "Crewed stations and their visiting vehicles": "有人宇宙ステーションと結合中の宇宙機", + "Crewed stations and their visiting vehicles": "有人宇宙ステーションと、そこを訪れる宇宙機", "NAV": "測位", "GNSS navigation — GPS, GLONASS, Galileo": "GNSS測位(GPS、GLONASS、Galileo)", "GEO": "GEO", @@ -324,7 +324,7 @@ "LOADING": "読込中", "DEGRADED": "性能低下", "STALE": "更新遅延", - "PARTIAL": "一部", + "PARTIAL": "部分的", "FALLBACK": "フォールバック", "{state} {layers}": "{state} {layers}", "view band|STREET": "街路", @@ -365,7 +365,7 @@ "Unknown key: {name}": "不明なキー:{name}", "{name} must be a string": "{name}は文字列である必要があります", "{name} is empty": "{name}が空です", - "{name} is longer than any real key ({limit} max)": "{name}は実在するどのキーよりも長すぎます(最大{limit}文字)", + "{name} is longer than any real key ({limit} max)": "{name}は実在するどのキーよりも長くなっています(最大{limit}文字)", "{name} may only contain printable characters with no spaces": "{name}には空白を含まない印字可能文字のみ使用できます", "{name} contains a character that is not valid in a key (#, quotes, $, \\, or backtick)": "{name}にキーで使用できない文字(#、引用符、$、\\、バッククォート)が含まれています", "{name} is configured outside Provider Settings and can only be changed where it was set": "{name}はプロバイダー設定の外で設定されているため、設定した場所でのみ変更できます", @@ -375,10 +375,10 @@ "Save failed ({status}).": "保存に失敗しました({status})。", "OAuth check failed: {detail}": "OAuthの確認に失敗しました:{detail}", "Could not check ChatGPT sign-in. Try again.": "ChatGPTのサインイン状態を確認できませんでした。もう一度お試しください。", - "VOICE AUTH · CHATGPT OAUTH": "音声機能の認証 · CHATGPT OAUTH", + "VOICE AUTH · CHATGPT OAUTH": "音声機能の認証 · ChatGPT OAuth", "VOICE AUTH · API KEY": "音声機能の認証 · APIキー", "USE API KEY": "APIキーを使用", - "USE CHATGPT OAUTH": "CHATGPT OAUTHを使用", + "USE CHATGPT OAUTH": "ChatGPT OAuthを使用", "Use OPENAI_API_KEY for the next cloud voice session": "次回のクラウド音声セッションでOPENAI_API_KEYを使用", "Use the signed-in local ChatGPT/Codex OAuth session for the next cloud voice session": "次回のクラウド音声セッションで、このマシンでサインイン済みのChatGPT/Codex OAuthセッションを使用", "Metered — a billing-enabled account": "従量課金:請求が有効なアカウントが必要", @@ -673,7 +673,7 @@ "{name} is active — {leave}, then set {endpoint}": "{name}を使用中です。先に{leave}。その後、{endpoint}を設定してください", "Only the first {count} turns of this route are shown": "このルートは最初の{count}件の案内のみ表示しています", "Turn-by-turn directions": "ターンバイターンのルート案内", - "Another map tool is using clicks — close it, then SET A again": "別の地図ツールがクリックを使用中です。そのツールを閉じてから、もう一度Aを設定してください", + "Another map tool is using clicks — close it, then SET A again": "別の地図ツールがクリックを使用中です。そのツールを閉じてから、もう一度[Aを設定]を押してください", "Routing…": "ルート検索中…", "No route found": "ルートが見つかりません", "{distance} · {duration} · {mode} · first {count} turns": "{distance} · {duration} · {mode} · 最初の{count}件の案内", @@ -712,7 +712,7 @@ "fire confidence|high": "高", "fire confidence|nominal": "中", "fire confidence|low": "低", - "age|<1h": "<1時間", + "age|<1h": "1時間以内", "age|{count}h": "{count}時間", "age|{count}d": "{count}日", "STALE · cached {age}": "更新遅延 · キャッシュ {age}", @@ -753,7 +753,7 @@ "Retrying automatically at {time} UTC": "{time} UTCに自動で再試行します", "Retrying automatically after provider cooldown": "プロバイダーのクールダウン後に自動で再試行します", "Updates automatically after pan or zoom and once a minute. The public feed covers a 250-nautical-mile circle around the view centre; zooming out does not make it a worldwide snapshot. Blank cells are outside sampled coverage or have insufficient observations.": "パンやズームの後、および1分ごとに自動で更新されます。公開フィードは表示中心から半径250海里の円をカバーします。ズームアウトしても全世界のスナップショットにはなりません。空白のセルは、サンプリング範囲外か観測が不十分です。", - "Low-accuracy score = 100 × max(0, bad − 1) / total: one aircraft is discounted, so this is not the raw share. Cells need {aircraft} aircraft over {minutes} minutes. Navigation-integrity anomalies are not a detection of jamming or spoofing.": "低精度スコア = 100 × max(0, bad − 1) / total:航空機1機分を差し引くため、単純な割合ではありません。セルには{minutes}分間で{aircraft}機の航空機が必要です。航法インテグリティの異常は、妨害(ジャミング)やなりすまし(スプーフィング)を検出したことを意味しません。", + "Low-accuracy score = 100 × max(0, bad − 1) / total: one aircraft is discounted, so this is not the raw share. Cells need {aircraft} aircraft over {minutes} minutes. Navigation-integrity anomalies are not a detection of jamming or spoofing.": "低精度スコア = 100 × max(0, bad − 1) / total:航空機1機分を差し引くため、単純な割合ではありません。セルには{minutes}分間で{aircraft}機の航空機が必要です。航法インテグリティの異常は、妨害(ジャミング)やなりすまし(スプーフィング)を検出したことを意味しません。", "GNSS snapshot needs a view anchor": "GNSSスナップショットにはビューのアンカーが必要です", "GNSS feed rate limited (HTTP 429)": "GNSSフィードがレート制限中です(HTTP 429)", "Malformed GNSS integrity snapshot": "GNSSインテグリティのスナップショットの形式が不正です", @@ -795,7 +795,7 @@ "PAYLOAD DATA UNAVAILABLE": "ペイロードデータなし", "{value} KM DOWNRANGE": "ダウンレンジ {value} KM", "POSITION UNAVAILABLE": "位置を取得できません", - "FLIGHT {count}": "フライト {count}", + "FLIGHT {count}": "{count}回目の飛行", "REUSED": "再使用", "NO STAGE RE-ENTRY / RECOVERY DATA": "段の再突入 / 回収データなし", "{count} / 30D": "{count} / 30日", @@ -971,16 +971,16 @@ "Comparison in use by another scene": "比較機能は別のシーンで使用中です", "Esri map unavailable · no swipe": "Esriマップ利用不可 · スワイプ比較不可", "Swipe needs a globe map": "スワイプ比較には地球儀マップが必要です", - "Imagery stays on Esri · CLEAR to use Google 3D": "画像はEsriのまま · 消去するとGoogle 3Dを使用", + "Imagery stays on Esri · CLEAR to use Google 3D": "画像はEsriのまま · [消去]でGoogle 3Dを使用", "Imagery catalog unavailable": "画像カタログを利用できません", "Catalog truncated · a newer clear day may exist": "カタログ省略あり · より新しい晴天日がある可能性", "{label} catalog unavailable · {detail}": "{label}のカタログを利用できません · {detail}", "Daily overview for today may still be empty until the pass": "今日の日次概観は、衛星の通過まで空の場合があります", "Box and images cleared": "範囲と画像を消去しました", "MORE DETAIL · 30 m": "高精細 · 30 m", - "Sentinel-2 and Landsat via HLS, 30 m, every 2–6 days": "HLS経由のSentinel-2とLandsat、30 m、2~6日ごと", + "Sentinel-2 and Landsat via HLS, 30 m, every 2–6 days": "HLS経由のSentinel-2とLandsat、30 m、2–6日ごと", "DAILY OVERVIEW · 250 m": "日次概観 · 250 m", - "VIIRS daily mosaic, 250 m, follows broad changes; little detail under 25 km": "VIIRSの日次モザイク、250 m。広域の変化を追跡。25 km未満の詳細はほぼなし", + "VIIRS daily mosaic, 250 m, follows broad changes; little detail under 25 km": "VIIRSの日次モザイク、250 m。広域の変化を追跡。25 km未満の範囲では細部をほぼ判別できない", "Sentinel-2": "Sentinel-2", "Sentinel-2 via HLS": "Sentinel-2(HLS経由)", "Landsat 8/9": "Landsat 8/9", @@ -1019,7 +1019,7 @@ "GOOGLE_MAPS_API_KEY is not set": "GOOGLE_MAPS_API_KEYが設定されていません", "The Google Maps JavaScript API could not load": "Google Maps JavaScript APIを読み込めませんでした", "Google Street View": "Googleストリートビュー", - "GOOGLE STREET VIEW": "GOOGLEストリートビュー", + "GOOGLE STREET VIEW": "Googleストリートビュー", "Google refused GOOGLE_MAPS_API_KEY for Street View — check that the Maps JavaScript API is enabled for it and this site is an allowed referrer": "GoogleがストリートビューへのGOOGLE_MAPS_API_KEYを拒否しました。このキーでMaps JavaScript APIが有効になっていること、このサイトが許可されたリファラーであることを確認してください", "Street View did not answer — check the network, and that the Maps JavaScript API is enabled for GOOGLE_MAPS_API_KEY": "ストリートビューから応答がありません。ネットワーク、およびGOOGLE_MAPS_API_KEYでMaps JavaScript APIが有効になっていることを確認してください", "click a street to open Street View": "通りをクリックしてストリートビューを開く", @@ -1042,7 +1042,7 @@ "Mapillary rejected MAPILLARY_CLIENT_TOKEN — replace it in Provider Settings": "MapillaryがMAPILLARY_CLIENT_TOKENを拒否しました。プロバイダー設定で置き換えてください", "Coverage requests are being rate-limited — they resume on their own": "カバー範囲のリクエストがレート制限中です。自動的に再開されます", "The Panoramax photo could not be loaded": "Panoramaxの写真を読み込めませんでした", - "Panoramax is busy — coverage resumes on its own": "Panoramaxが混雑しています。カバー範囲は自動的に再開されます", + "Panoramax is busy — coverage resumes on its own": "Panoramaxが混雑しています。カバー範囲の取得は自動的に再開されます", "no Panoramax photos in view": "表示範囲内にPanoramaxの写真はありません", "no Panoramax photos here match the filters": "この場所にフィルターに一致するPanoramaxの写真はありません", "Panoramax sent a map tile that could not be read": "Panoramaxから読み取れない地図タイルが返されました", @@ -1068,7 +1068,7 @@ "Local surface still loading": "周辺の路面を読み込み中", "Partial coverage": "一部のみカバー", "Detailed roads unavailable": "詳細な道路を利用できません", - "Reduced detail coverage": "詳細なカバー範囲が限定的", + "Reduced detail coverage": "詳細データのカバー範囲が限定的", "TomTom roads only, each with its live flow": "TomTomの道路のみ(各道路にライブの交通流)", "TomTom roads only, each with its live flow (needs a TomTom key)": "TomTomの道路のみ(各道路にライブの交通流、TomTomキーが必要)", "OpenStreetMap roads, with TomTom flow matched when available": "OpenStreetMapの道路(利用可能な場合はTomTomの交通流を照合)", @@ -1077,7 +1077,7 @@ "Hybrid": "ハイブリッド", "TomTom key unavailable": "TomTomキーを利用できません", "TomTom daily budget reached": "TomTomの1日の上限に達しました", - "TomTom upstream unreachable": "TomTomの上流サービスに接続できません", + "TomTom upstream unreachable": "TomTomのサービスに接続できません", "TomTom flow unavailable": "TomTomの交通流を利用できません", "SIMULATED — {reason}": "シミュレーション:{reason}", "Syncing flow · Roads: {source}": "交通流を同期中 · 道路:{source}", @@ -1131,8 +1131,8 @@ "VESSEL": "船舶", "{speed}KT": "{speed} kt", "{heading}DEG": "{heading}°", - "POS: LIVE": "位置:ライブ", - "POS: {time}Z": "位置:{time}Z", + "POS: LIVE": "POS: ライブ", + "POS: {time}Z": "POS: {time}Z", "AIS live load failed": "AISライブデータの読み込みに失敗しました", "awaiting first AIS position…": "最初のAIS位置を待機中…", "awaiting usable AIS positions…": "利用可能なAIS位置を待機中…", @@ -1181,7 +1181,7 @@ "Contiguous US · gaps ≠ no rain": "米国本土 · 欠測 ≠ 降水なし", "Americas + Pacific · not individual strikes": "南北アメリカ + 太平洋 · 個々の落雷ではありません", "Color: strikes/km²/min ×10³": "色:落雷数/km²/分 ×10³", - "60°S–60°N · typically 2–3 h delayed": "60°S–60°N · 通常2~3時間遅れ", + "60°S–60°N · typically 2–3 h delayed": "60°S–60°N · 通常2–3時間遅れ", "North America · infrared imagery": "北米 · 赤外画像", "Reduced motion · history playback unavailable": "動きを減らす設定 · 履歴再生は利用不可", "Reduced motion · manual history available": "動きを減らす設定 · 履歴は手動で表示可能", @@ -1198,7 +1198,7 @@ "strikes/km²/min ×10³": "落雷数/km²/分 ×10³", "N. America": "北米", "Global": "全球", - "Hourly global mosaic; usually 2–3 hours delayed": "1時間ごとの全球モザイク。通常2~3時間遅れ", + "Hourly global mosaic; usually 2–3 hours delayed": "1時間ごとの全球モザイク。通常2–3時間遅れ", "GOES regional clouds; approximately 5-minute updates": "GOESの地域雲画像。約5分ごとに更新", "Clouds only": "雲のみ", "Apply the full cloud brightness key; 100% filter strength": "雲の輝度キーを完全に適用。フィルター強度100%", @@ -1214,7 +1214,7 @@ "{value} dBZ radar reflectivity": "{value} dBZレーダー反射強度", "STALE · cached source metadata": "更新遅延 · キャッシュ済みのソースメタデータ", "Map center is outside source coverage": "地図の中心がソースのカバー範囲外です", - "NOAA/NWS 15-minute lightning density derived from Vaisala NLDN/GLD360. Coverage 110°E across the Pacific/Americas to 0°, 25°S–80°N. Not a live strike count, global coverage or a safety warning.": "Vaisala NLDN/GLD360から算出したNOAA/NWSの15分間雷密度。カバー範囲は東経110°から太平洋・南北アメリカを経て0°まで、南緯25°~北緯80°。リアルタイムの落雷数、全球カバー、安全上の警報ではありません。", + "NOAA/NWS 15-minute lightning density derived from Vaisala NLDN/GLD360. Coverage 110°E across the Pacific/Americas to 0°, 25°S–80°N. Not a live strike count, global coverage or a safety warning.": "Vaisala NLDN/GLD360から算出したNOAA/NWSの15分間雷密度。カバー範囲は東経110°から太平洋・南北アメリカを経て0°まで、南緯25°–北緯80°。リアルタイムの落雷数、全球カバー、安全上の警報ではありません。", "NOAA MRMS radar echoes indicate precipitation patterns, not rain rate, a storm warning or a future forecast. Native source approximately 1 km; display is limited to level 6. Frames use exact advertised observation times.": "NOAA MRMSのレーダーエコーは降水のパターンを示すもので、降水強度、嵐の警報、将来の予報ではありません。元データの解像度は約1 km、表示はズームレベル6までです。各フレームは公表された正確な観測時刻を使用します。", "GOES-19/18 longwave infrared Band 14 regional; NESDIS global longwave mosaic. Clouds only dims everything but bright, cold cloud tops; a brightness filter, not a cloud mask. Coverage and freshness differ by region.": "GOES-19/18長波赤外バンド14の地域画像と、NESDISの全球長波モザイク。「雲のみ」は明るく冷たい雲頂以外をすべて暗くします。これは輝度フィルターであり、雲マスクではありません。カバー範囲と鮮度は地域によって異なります。", "REGION": "地域", @@ -1230,7 +1230,7 @@ "Weather request timed out": "気象リクエストがタイムアウトしました", "Temperature field unavailable": "気温場を利用できません", "Mean sea level pressure field unavailable": "平均海面気圧場を利用できません", - "Wind upstream unavailable": "風の上流ソースを利用できません", + "Wind upstream unavailable": "風データの配信元を利用できません", "{source} HTTP {status}": "{source} HTTP {status}", "Wind": "風", "Wind source unavailable": "風のソースを利用できません", @@ -1477,7 +1477,7 @@ "Browser location is unavailable": "ブラウザーの位置情報を利用できません", "Receiver location was not granted": "受信機の位置情報が許可されませんでした", "RTL-SDR disconnected": "RTL-SDRが切断されました", - "Upstream response too large": "上流の応答が大きすぎます", + "Upstream response too large": "配信元からの応答が大きすぎます", "Vector tile request timed out": "ベクタータイルのリクエストがタイムアウトしました", "Vector tiles unavailable": "ベクタータイルを利用できません", "Vector tile metadata unavailable": "ベクタータイルのメタデータを利用できません", @@ -1503,7 +1503,7 @@ "VISUAL PRESETS": "ビジュアルプリセット", "LOCATION": "位置", "CONTACTS — nearest planes · vessels · sites": "コンタクト:最寄りの航空機 · 船舶 · 施設", - "SPACE MISSIONS — launches & orbital assets": "宇宙ミッション:打ち上げと軌道上の資産", + "SPACE MISSIONS — launches & orbital assets": "宇宙ミッション:打ち上げと軌道上の宇宙機", "LIVE SIGNALS": "ライブシグナル", "Contacts could not complete the requested transition; try again": "コンタクトが要求された切り替えを完了できませんでした。もう一度お試しください", "CCTV layer unavailable": "CCTVレイヤーを利用できません", @@ -1530,7 +1530,7 @@ "ADJUST": "調整", "SNAPSHOT": "スナップショット", "LIVE": "ライブ", - "UPSTREAM": "上流", + "UPSTREAM": "配信元", "SYNTHETIC": "合成", "CONFIGURED": "設定済み", "SEED": "初期データ", @@ -1543,14 +1543,14 @@ "Live stream connected": "ライブストリーム接続済み", "Snapshot feed connected": "スナップショットフィード接続済み", "Media fetch failed": "メディアの取得に失敗しました", - "Upstream snapshot active": "上流のスナップショットを使用中", + "Upstream snapshot active": "配信元のスナップショットを使用中", "Fallback Street View frame": "代替のストリートビュー画像", - "Upstream unavailable": "上流を利用できません", + "Upstream unavailable": "配信元を利用できません", "No source configured": "ソースが設定されていません", "Configured source": "設定済みのソース", "Configured Source": "設定済みのソース", "Synthetic fallback": "合成による代替", - "Upstream HTTP {status}": "上流 HTTP {status}", + "Upstream HTTP {status}": "配信元 HTTP {status}", "Unexpected media type {type}": "予期しないメディアタイプ {type}", "SOURCE · UNKNOWN": "ソース · 不明", "FRAME · LOADING": "フレーム · 読込中", @@ -1587,7 +1587,7 @@ "Clear selected data layers": "選択中のデータレイヤーを解除", "CONDITIONS UNKNOWN": "気象状況不明", "CLEAR": "快晴", - "PARTLY CLOUDY": "一部曇り", + "PARTLY CLOUDY": "晴れ", "OVERCAST": "曇天", "FOG": "霧", "DRIZZLE": "霧雨", @@ -1667,14 +1667,14 @@ "LATEST LOCATION-MATCHED REPORTING": "位置に一致する最新の報道", "{source} · LOCATION QUERY · RECENT": "{source} · 位置クエリ · 最近", "LOCAL INFO": "ローカル情報", - "PLACE / CONDITIONS / POSITION": "場所 / 状況 / 位置", + "PLACE / CONDITIONS / POSITION": "場所 / 天候 / 位置", "TIME UNKNOWN": "時刻不明", "{count}M AGO": "{count}分前", "{count}H AGO": "{count}時間前", "{count}D AGO": "{count}日前", "DIR UNKNOWN": "風向不明", "Select flight {title}": "フライト{title}を選択", - "{aircraftClass} · CURRENT": "{aircraftClass} · 現在", + "{aircraftClass} · CURRENT": "{aircraftClass} · 追跡中", "MILITARY FLIGHT": "軍用機", "COMMERCIAL FLIGHT": "民間機", "{aircraftClass} · {distance}": "{aircraftClass} · {distance}", @@ -1707,7 +1707,7 @@ "{mode} could not start because another layer did not stop cleanly": "別のレイヤーが正常に停止しなかったため、{mode}を開始できませんでした", "Space Missions": "宇宙ミッション", "Context": "コンテキスト", - "Rendered globe frames per second · toggle with `": "地球儀の描画フレームレート(毎秒)· `キーで切り替え", + "Rendered globe frames per second · toggle with `": "地球儀の描画フレームレート(毎秒) · `キーで切り替え", "imported map files": "インポートした地図ファイル", "Ground heights could not be refreshed. Try the file again when the map has loaded.": "地表高を更新できませんでした。地図の読み込み後に、もう一度このファイルをお試しください。", "{count} map objects": { @@ -2174,7 +2174,7 @@ "{name} imagery on": "{name}の画像 オン", "{name} imagery off": "{name}の画像 オフ", "Image by {creator}": "撮影者:{creator}", - " or ": "、", + " or ": "または", "OPEN {labels}": "{labels}を開く", "Open {names} at the centre of the view": "表示の中心で{names}を開く", "Zoom in to a street to open {names} here": "ここで{names}を開くには通りまでズームイン", @@ -2413,7 +2413,7 @@ }, "degraded": "性能低下", "stale": "更新遅延", - "partial": "一部", + "partial": "部分的", "fallback": "フォールバック", "unavailable": "利用不可", "Not answered: {layers}": "応答なし:{layers}", @@ -2532,7 +2532,7 @@ "Layer off": "レイヤー オフ", "Zoom out": "ズームアウト", "Zoom in": "ズームイン", - "Read the view": "ビューを読み上げ", + "Read the view": "ビューの内容を読み取り", "Check view state": "ビューの状態を確認", "Action": "操作", "Finding places": "場所を検索中", @@ -2579,7 +2579,7 @@ "FT": "FT", "Contact cockpit summary": "コンタクトのコックピット概要", "CONTACT": "コンタクト", - "CONTACTS · 250 KM": "コンタクト · 250 KM", + "CONTACTS · 250 KM": "コンタクト · 250 km", "Contact navigation": "コンタクトナビゲーション", "CONTEXT ONLY": "参考情報のみ", "Nearby cohort counts": "周辺の種別ごとの件数", @@ -2695,7 +2695,7 @@ "Stop radio playback": "ラジオ再生を停止", "Radio volume": "ラジオの音量", "STATION SITE": "放送局サイト", - "DIRECTORY: RADIO BROWSER": "ディレクトリ:RADIO BROWSER", + "DIRECTORY: RADIO BROWSER": "ディレクトリ:Radio Browser", "Audio connects directly to the broadcaster after you press play. Your IP is visible to that broadcaster.": "再生ボタンを押すと、音声は放送局に直接接続されます。お使いのIPアドレスは放送局側から見えます。", "Local RTL-SDR receiver": "ローカルRTL-SDR受信機", "LOCAL RTL-SDR": "ローカルRTL-SDR", @@ -2843,7 +2843,7 @@ "Power up the globe": "地球儀をパワーアップ", "The globe already flies keyless. Every key below switches on another real feed — paste one and it's saved into this app's local configuration, then the server restarts itself. Server-side keys stay on this machine; Google Maps and Cesium ion run in the browser and must be provider-restricted. Keys you configured elsewhere are shown but never touched.": "地球儀はキーなしでもそのまま使えます。下の各キーは、それぞれ別の実データフィードを有効にします。キーを貼り付けるとこのアプリのローカル設定に保存され、サーバーが自動で再起動します。サーバー側のキーはこのマシンから出ません。Google MapsとCesium ionはブラウザーで動作するため、プロバイダー側で利用制限を設定してください。他の場所で設定済みのキーは表示のみで、変更されません。", "SAVE KEYS": "キーを保存", - "ESC to close": "ESCで閉じる", + "ESC to close": "Escで閉じる", "The Google Maps key buys the photorealistic planet — everything else stacks on top.": "Google Mapsのキーでフォトリアルな地球が使えるようになり、他のすべてはその上に重なります。", "NO PLACE LEFT BEHIND": "取り残される場所はない", "ACTIVE STYLE": "現在のスタイル", @@ -2862,6 +2862,6 @@ "EXPLORE MANUALLY": "手動で探索", "Begin with a clean globe": "まっさらな地球儀から始める", "Don't show this again": "今後表示しない", - "ESC to dismiss": "ESCで閉じる", + "ESC to dismiss": "Escで閉じる", "Tip: the GEV MIC button in the dock lets you talk to the map.": "ヒント:ドックの[マイク]ボタンで地図に話しかけられます。" } diff --git a/src/i18n/same-as-english.json b/src/i18n/same-as-english.json index 7938d74a3..9ee97a600 100644 --- a/src/i18n/same-as-english.json +++ b/src/i18n/same-as-english.json @@ -150,6 +150,7 @@ "Landsat 8/9", "MSG/S", "NVG", + "POS: {time}Z", "REC", "S2 GhostMaps", "SRC {value}", From 7e55ee45fe8a583fbb3b0647ef04dbccfc2c3852 Mon Sep 17 00:00:00 2001 From: German Khokhlov Date: Wed, 28 Oct 2026 22:50:19 +0400 Subject: [PATCH 39/83] i18n(fr): apply review round 3 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Apply the accepted findings from the third three-model French review: tool-name agreement (« Outil actif : {name} »), elision before ADS-B, « GORGE AVAL », « CLASSIQUES », « EN SURVOL », one name for the VIIRS daily overview, U+202F thousands separator, and wording fixes for the scene editor, directions, radio tuner and status strings. The CCTV HUD summary now shows its CAL badge, source kind and view band through existing catalog entries, so French reads « CAL ESTIM. INITIALE · SRC AMONT · CONTEXTE RUE »; English output and unknown codes are unchanged. presentation.js matches the pt branch's round-3 version byte for byte, so the two branches merge cleanly. Co-Authored-By: Claude Opus 5.5 --- docs/translations/fr.md | 6 +- src/i18n/locales/fr.json | 34 +++++------ src/layers/cctv/presentation.i18n.test.mjs | 58 ++++++++++++++++++ src/layers/cctv/presentation.js | 71 ++++++++++++++++++---- 4 files changed, 139 insertions(+), 30 deletions(-) create mode 100644 src/layers/cctv/presentation.i18n.test.mjs diff --git a/docs/translations/fr.md b/docs/translations/fr.md index 8a10804b0..34ba9c9cb 100644 --- a/docs/translations/fr.md +++ b/docs/translations/fr.md @@ -9,7 +9,7 @@ Translation source: abiyeenzo (#907); the French part of meirm's #312 was used f - Standard French that reads naturally in France, Belgium, Switzerland and Canada; avoid regionalisms. - Address the user with "vous" imperatives: « Cliquez », « Activez », « Réessayez ». Tooltips that name an action use the infinitive: « Réduire le panneau », « Réinitialiser la caméra ». UPPERCASE HUD instructions also use the infinitive: « CLIQUER SUR UNE CAMÉRA POUR L'ACTIVER ». - Sentence case, not Title Case: "Live Flights" → « Vols en direct ». UPPERCASE English stays UPPERCASE, accents included: « ÉTAT », « PRÉC. ». -- Typography: a narrow no-break space (U+202F) goes before `:` `;` `?` `!` and `%`, and inside « » quotes: `Supprimer le plan « {shot} » ?`. It keeps the sign on the same line as the word before it. Do not type a plain space there. Ellipsis is `…`, not `...`. Dashes keep their spaces: « flux indisponible — réessayez ». +- Typography: a narrow no-break space (U+202F) goes before `:` `;` `?` `!` and `%`, and inside « » quotes: `Supprimer le plan « {shot} » ?`. It keeps the sign on the same line as the word before it. Do not type a plain space there. The same narrow no-break space separates thousands in a number written into the text: « 1 000 km ». Ellipsis is `…`, not `...`. Dashes keep their spaces: « flux indisponible — réessayez ». - Short labels, chips and HUD readouts stay short. A standard abbreviation with a period beats a wrapped line: PRÉC., SUIV., RÉINIT., ENREG., INDISP., DIST. - The HUD codes HDG, BRG, CRS, FOV, DEST, SPD and ALT stay in English everywhere, as in cockpit avionics. Words are translated: RANGE → « PORTÉE », heading in a sentence → « cap », ground-track course → « route » (« ROUTE 270° »). - ON and OFF stay as they are on HUD toggles and chips (« CCTV ON », « PROJECTION OFF »); in a sentence use « activé » / « désactivé ». @@ -28,7 +28,7 @@ A `tn()` entry needs three forms. `Intl.PluralRules('fr')` picks: | `many` | 1 000 000, 2 000 000… (exact millions) | 1 000 000 de caméras | | `other` | everything else: 2–999 999, 2,5… | 3 caméras | -The `many` form is the `other` text with « de » (« d' » before a vowel) after the number: « {count} de couches effacées », « {count} D'ENTRÉES INCONNUES ». When the words after the number cannot agree (an UPPERCASE readout, a list), put the number after a colon in every form: « CAPTÉS : {count} ». The same goes for a layer name whose gender and number vary: « Couche activée : {label} », not « {label} activé ». +The `many` form is the `other` text with « de » (« d' » before a vowel) after the number: « {count} de couches effacées », « {count} D'ENTRÉES INCONNUES ». When the words after the number cannot agree (an UPPERCASE readout, a list), put the number after a colon in every form: « CAPTÉS : {count} ». The same goes for a layer name whose gender and number vary: « Couche activée : {label} », not « {label} activé », or a tool name: « Outil actif : {name} », not « {name} est actif ». ## Glossary @@ -66,6 +66,7 @@ The `many` form is the `other` text with « de » (« d' » before a vowel) afte | route (directions) / turn (maneuver) | itinéraire / manœuvre | | scene / shot / scene recipe | scène / plan / recette de scène | | bundle / data pack / anchor | archive / paquet de données / ancre | +| capture camera as anchor / set move start (scene editor) | ancre à la position de la caméra / vue actuelle comme départ | | story beat | étape du récit | | briefing / panel / dock | briefing / panneau / dock | | cockpit | cockpit | @@ -75,6 +76,7 @@ The `many` form is the `other` text with « de » (« d' » before a vowel) afte | Clean UI | vue épurée | | Street Level (layer) / Street View (Google) | Niveau rue / Street View | | Recent Imagery / box | imagerie récente / zone | +| Daily overview / overview (Recent Imagery VIIRS product) | vue quotidienne (one name for the product, not « vue d'ensemble ») | | pin (Draw tool) / pin (Recent Imagery) | épingle / épingler | | Cyber (HUD layout, effect) | Cyber | | heading / course (ground track) / altitude / ground speed | cap / route / altitude / vitesse sol | diff --git a/src/i18n/locales/fr.json b/src/i18n/locales/fr.json index f90c1d50e..b63ee45f6 100644 --- a/src/i18n/locales/fr.json +++ b/src/i18n/locales/fr.json @@ -140,7 +140,7 @@ "◉ CINEMATIC": "◉ CINÉMATIQUE", "↺ FULL STORY": "↺ RÉCIT COMPLET", "↗ OPEN ORIGINAL": "↗ OUVRIR L'ORIGINAL", - "⌖ LOWER GORGE": "⌖ GORGE INFÉRIEURE", + "⌖ LOWER GORGE": "⌖ GORGE AVAL", "FIELD REPORTS · {count}": "RAPPORTS DE TERRAIN · {count}", "GEOLOCATIONS · {credit}": "GÉOLOCALISATIONS · {credit}", "↗ OPEN PUBLIC MAP": "↗ OUVRIR LA CARTE PUBLIQUE", @@ -184,7 +184,7 @@ "USGS INITIAL REPORT": "RAPPORT INITIAL DE L'USGS", "26 AUG 2026 · 08:37 NPT": "26 AOÛT 2026 · 08:37 NPT", "28.2710° N · 85.5150° E": "28,2710° N · 85,5150° E", - "INITIAL M4.4 · RECLASSIFIED M5.2 LANDSLIDE": "M4,4 INITIALE · RECLASSÉ EN GLISSEMENT DE TERRAIN M5,2", + "INITIAL M4.4 · RECLASSIFIED M5.2 LANDSLIDE": "INITIALEMENT M4,4 · RECLASSÉ EN GLISSEMENT DE TERRAIN M5,2", "USGS EVENT us7000tbwb · OPEN SOURCE": "ÉVÉNEMENT USGS us7000tbwb · OUVRIR LA SOURCE", "Open the USGS initial report for the 26 August 2026 Nepal landslide": "Ouvrir le rapport initial de l'USGS sur le glissement de terrain du 26 août 2026 au Népal", "Show the Nepal context callout without a border or country fill": "Afficher l'encart de contexte du Népal sans frontière ni remplissage du pays", @@ -271,7 +271,7 @@ "NAV": "NAV", "GNSS navigation — GPS, GLONASS, Galileo": "Navigation GNSS — GPS, GLONASS, Galileo", "GEO": "GEO", - "Geostationary belt — comms and weather, fixed over the equator": "Ceinture géostationnaire — télécoms et météo, fixes au-dessus de l'équateur", + "Geostationary belt — comms and weather, fixed over the equator": "Ceinture géostationnaire — télécoms et météo, en position fixe au-dessus de l'équateur", "VISUAL": "VISUEL", "Brightest naked-eye objects — CelesTrak visual group": "Objets les plus brillants à l'œil nu — groupe visuel CelesTrak", "COMMS": "TÉLÉCOM", @@ -668,7 +668,7 @@ "Use the {direction} lane": "Prenez la voie {direction}", "Continue onto {road}": "Continuez sur {road}", "maneuver|Continue": "Continuez", - "{mode} — reroute for {modeLower}": "{mode} — recalculer l'itinéraire : {modeLower}", + "{mode} — reroute for {modeLower}": "{mode} — recalculer l'itinéraire {modeLower}", "CLICK MAP": "CLIQUER SUR LA CARTE", "SET A": "PLACER A", "Click a spot on the globe to place A (click again to cancel)": "Cliquez sur un point du globe pour placer A (cliquez à nouveau pour annuler)", @@ -678,14 +678,14 @@ "Then click the globe to place the destination": "Puis cliquez sur le globe pour placer la destination", "Swap A and B": "Inverser A et B", "FLY ···": "SURVOL ···", - "FLYING": "SURVOL EN COURS", + "FLYING": "EN SURVOL", "FLY": "SURVOLER", "Fly the camera along the route": "Faire voler la caméra le long de l'itinéraire", "Place A and B first": "Placez d'abord A et B", "action|CLEAR": "EFFACER", "Remove the route and both markers": "Supprimer l'itinéraire et les deux marqueurs", "press Escape twice to leave Draw": "appuyez deux fois sur Esc pour quitter Dessin", - "{name} is active — turn {name} off, then set {endpoint}": "{name} est actif — désactivez {name}, puis placez {endpoint}", + "{name} is active — turn {name} off, then set {endpoint}": "Outil actif : {name} — désactivez {name}, puis placez {endpoint}", "{name} is active — {leave}, then set {endpoint}": "{name} est actif — {leave}, puis placez {endpoint}", "Only the first {count} turns of this route are shown": "Seules les {count} premières manœuvres de cet itinéraire sont affichées", "Turn-by-turn directions": "Instructions pas à pas", @@ -994,7 +994,7 @@ "Techno": "Techno", "Trance": "Trance", "World": "Musiques du monde", - "overview": "vue d'ensemble", + "overview": "vue quotidienne", "cloud unknown": "nébulosité inconnue", "{percent}% scene cloud": "{percent} % de nuages sur la scène", "{min}–{max}% scene cloud": "{min}–{max} % de nuages sur la scène", @@ -1198,7 +1198,7 @@ "Observation unavailable": "Observation indisponible", "Waiting for observation": "En attente d'observation", "{detail} · synced": "{detail} · synchro", - "{detail} · nearest": "{detail} · la plus proche", + "{detail} · nearest": "{detail} · plus proche", "RADAR REFLECTIVITY · dBZ": "RÉFLECTIVITÉ RADAR · dBZ", "LIGHTNING DENSITY · 15 min accumulation": "DENSITÉ DE FOUDRE · cumul sur 15 min", "GLOBAL INFRARED · hourly": "INFRAROUGE MONDIAL · horaire", @@ -1471,9 +1471,9 @@ "Anchors and data packs": "Ancres et paquets de données", "Shot camera, timing, packs and actions": "Caméra, minutage, paquets et actions du plan", "New anchor ID": "ID de la nouvelle ancre", - "Capture camera as anchor": "Capturer la caméra comme ancre", + "Capture camera as anchor": "Créer une ancre à la position de la caméra", "Anchor added to draft": "Ancre ajoutée au brouillon", - "Set move start to current camera": "Définir le début du mouvement sur la caméra actuelle", + "Set move start to current camera": "Utiliser la vue actuelle comme départ du mouvement", "Move added to draft; destination remains the shot camera": "Mouvement ajouté au brouillon ; la destination reste la caméra du plan", "Use ordinary flight": "Utiliser un vol normal", "Invalid shot JSON": "JSON de plan non valide", @@ -1542,7 +1542,7 @@ "Switching language reloads the page. This will be lost: {items}. Switch anyway?": "Changer de langue recharge la page. Ceci sera perdu : {items}. Changer quand même ?", "VISUAL PRESETS": "PRÉRÉGLAGES VISUELS", "LOCATION": "LIEU", - "CONTACTS — nearest planes · vessels · sites": "CONTACTS — avions · navires · sites les plus proches", + "CONTACTS — nearest planes · vessels · sites": "CONTACTS — avions, navires et sites les plus proches", "SPACE MISSIONS — launches & orbital assets": "MISSIONS SPATIALES — lancements et objets orbitaux", "LIVE SIGNALS": "SIGNAUX EN DIRECT", "Contacts could not complete the requested transition; try again": "Les contacts n'ont pas pu effectuer la transition demandée ; réessayez", @@ -1844,7 +1844,7 @@ "Other layers": "Autres couches", "{state} · {source}": "{state} · {source}", "UNCERTAIN · {source} · lifecycle state requires reconciliation": "INCERTAIN · {source} · état à rétablir", - "{state} · {source} · {detail} · retry {seconds}s": "{state} · {source} · {detail} · nouvel essai {seconds} s", + "{state} · {source} · {detail} · retry {seconds}s": "{state} · {source} · {detail} · nouvel essai dans {seconds} s", "{state} · {source} · {detail}": "{state} · {source} · {detail}", "never": "jamais", "{source} · {loadingLabel}": "{source} · {loadingLabel}", @@ -1898,7 +1898,7 @@ "LOCATING…": "LOCALISATION…", "LOCATED": "LOCALISÉ", "LOCATE": "LOCALISER", - " · read while Local ADS-B is on": " · lus tant que ADS-B local est activé", + " · read while Local ADS-B is on": " · lus tant qu'ADS-B local est activé", "Decoder feeds: {feeds}": "Flux du décodeur : {feeds}", "Language: {language}": "Langue : {language}", "Change the interface language": "Changer la langue de l'interface", @@ -2055,7 +2055,7 @@ "S on another day replaces it · × unpins": "S sur un autre jour le remplace · × le désépingle", "← → preview · S shows the focused day": "← → aperçu · S affiche le jour ciblé", "ZOOM IN": "ZOOMER", - "Fly in until the view fits the 1,000 km limit": "Rapprochez-vous jusqu'à ce que la vue tienne dans la limite de 1 000 km", + "Fly in until the view fits the 1,000 km limit": "Rapprochez-vous jusqu'à ce que la vue tienne dans la limite de 1 000 km", "Imagery days, newest first · arrows move, S or A and B pin": "Jours d'imagerie, du plus récent au plus ancien · les flèches déplacent, S ou A et B épinglent", "On the map": "Sur la carte", "Mode": "Mode", @@ -2660,7 +2660,7 @@ "Next ISS pass": "Prochain passage de l'ISS", "Next satellite pass": "Prochain passage du satellite", "Mark the map": "Marquer la carte", - "Mark {targets} +{more}": "Marquer {targets} +{more}", + "Mark {targets} +{more}": "Marquer : {targets} +{more}", "Mark {targets}": "Marquer : {targets}", "Fly to {place}": "Rejoindre {place}", "Fly to Location": "Rejoindre le lieu", @@ -2822,7 +2822,7 @@ "All": "Tous", "Enable Radio, then choose a globe marker or use next.": "Activez la Radio, puis choisissez un marqueur sur le globe ou utilisez SUIV.", "DRAG TO TUNE": "GLISSER POUR RÉGLER", - "Tune available internet radio stations": "Écouter les stations de radio Internet disponibles", + "Tune available internet radio stations": "Régler sur une station de radio Internet disponible", "ALL · DRAG THE NEEDLE": "TOUTES · DÉPLACER L'AIGUILLE", "SNAPS TO AVAILABLE STATIONS": "SE CALE SUR LES STATIONS DISPONIBLES", "Radio playback": "Lecture radio", @@ -2964,7 +2964,7 @@ "IMAGERY": "IMAGES", "Panorama filter": "Filtre de panoramas", "ALL": "TOUTES", - "FLAT": "PLATES", + "FLAT": "CLASSIQUES", "SINCE": "DEPUIS", "SCENES": "SCÈNES", "Scene recipe": "Recette de scène", diff --git a/src/layers/cctv/presentation.i18n.test.mjs b/src/layers/cctv/presentation.i18n.test.mjs new file mode 100644 index 000000000..4bfa5186b --- /dev/null +++ b/src/layers/cctv/presentation.i18n.test.mjs @@ -0,0 +1,58 @@ +// The CCTV HUD summary shows the CAL badge, source kind and view band in the +// UI language; English keeps its codes, and unknown source codes stay codes. +import test from 'node:test'; +import assert from 'node:assert/strict'; +import { setLocale } from '../../i18n/index.js'; +import { createPresentation } from './presentation.js'; + +function summary(sourceKind) { + const camera = { + id: 'c1', + city: 'Austin', + name: 'Cam', + rangeM: 100, + fovDeg: 60, + feedType: 'image', + }; + const record = { camera }; + const presentation = createPresentation({ + state: { + _records: [record], + _healthById: new Map(sourceKind ? [['c1', { sourceKind }]] : []), + _showProjection: false, + _coverageMode: 'sector', + }, + services: {}, + parts: { + selection: { getActiveRecord: () => record }, + model: { + sectorAreaKm2: () => 1, + currentViewContext: () => 'street:1:2', + }, + geometry: { coverageNeighborCount: () => 0 }, + calibration: { deriveCalBadge: () => 'raw-prior' }, + }, + source: {}, + }); + return presentation.buildSummaryText(); +} + +test('en: CAL, SRC and CONTEXT keep their English codes', () => { + setLocale('en'); + assert.match(summary('upstream'), /CAL RAW PRIOR · SRC UPSTREAM/); + assert.match(summary(null), /SRC IMAGE · STREET CONTEXT/); + assert.match(summary('upstream-image'), /SRC UPSTREAM-IMAGE/); +}); + +test('fr: CAL, SRC and CONTEXT values are translated', () => { + setLocale('fr'); + try { + assert.match( + summary('upstream'), + /CAL ESTIM\. INITIALE · SRC AMONT · CONTEXTE RUE/, + ); + assert.match(summary('upstream-image'), /SRC UPSTREAM-IMAGE/); + } finally { + setLocale('en'); + } +}); diff --git a/src/layers/cctv/presentation.js b/src/layers/cctv/presentation.js index e47e08194..898e4605c 100644 --- a/src/layers/cctv/presentation.js +++ b/src/layers/cctv/presentation.js @@ -1,5 +1,5 @@ import { CCTV_AMBIENT_CARD_MAX } from '../../data/cctvLod.js'; -import { t } from '../../i18n/index.js'; +import { msg, t } from '../../i18n/index.js'; import { ACTIVE_FRAME_REFRESH_MS, IDLE_FRAME_REFRESH_MS } from './policy.js'; import { headingHudToken, isHeadingEstimated } from './headingConfidence.js'; import { @@ -8,6 +8,59 @@ import { isDatasheetFov, } from './modelSpecs.js'; +// The summary line names the CAL badge, the source kind and the view band in +// the page language; the codes underneath stay English. +const CAL_BADGE_LABELS = Object.freeze({ + calibrated: msg('CALIBRATED'), + curated: msg('CURATED'), + 'raw-prior': msg('RAW PRIOR'), +}); + +// The same source-kind words as the CCTV panel (src/ui/cctvFrames.js). +const SOURCE_KIND_LABELS = Object.freeze({ + snapshot: msg('SNAPSHOT'), + live: msg('LIVE'), + fallback: msg('FALLBACK'), + upstream: msg('UPSTREAM'), + synthetic: msg('SYNTHETIC'), + configured: msg('CONFIGURED'), + seed: msg('SEED'), + image: msg('IMAGE'), + unknown: msg('UNKNOWN'), +}); + +/** CAL badge id ('raw-prior') as the summary shows it; unknown ids stay codes. */ +export function summaryCalLabel(badge) { + const key = String(badge || ''); + return CAL_BADGE_LABELS[key] + ? t(CAL_BADGE_LABELS[key]) + : key.replace('-', ' ').toUpperCase(); +} + +/** Source kind ('image', 'snapshot') for the summary; HLS, MJPEG… stay codes. */ +export function summarySourceLabel(kind) { + const key = String(kind || 'image').toLowerCase(); + return SOURCE_KIND_LABELS[key] + ? t(SOURCE_KIND_LABELS[key]) + : key.toUpperCase(); +} + +/** View band id ('street', 'city'…) as the HUD names it. */ +export function summaryViewBandLabel(band) { + switch (band) { + case 'street': + return t('STREET', { context: 'view band' }); + case 'city': + return t('CITY', { context: 'view band' }); + case 'regional': + return t('REGIONAL', { context: 'view band' }); + case 'global': + return t('GLOBAL', { context: 'view band' }); + default: + return String(band || '').toUpperCase(); + } +} + export function createPresentation({ state: layerState, services, @@ -72,17 +125,13 @@ export function createPresentation({ : t('ISOLATED VIEW'), layerState._showProjection ? t('PROJ MONITOR') : t('PROJ OFF'), layerState._coverageMode === 'viewshed' ? t('VIEWSHED') : null, - t('CAL {value}', { - value: calBadge.replace('-', ' ').toUpperCase(), + t('CAL {value}', { value: summaryCalLabel(calBadge) }), + t('SRC {value}', { + value: summarySourceLabel( + health?.sourceKind || active.camera.feedType || 'image', + ), }), - health?.sourceKind - ? t('SRC {value}', { - value: String(health.sourceKind).toUpperCase(), - }) - : t('SRC {value}', { - value: String(active.camera.feedType || 'image').toUpperCase(), - }), - t('{value} CONTEXT', { value: viewBand.toUpperCase() }), + t('{value} CONTEXT', { value: summaryViewBandLabel(viewBand) }), // Identified hardware: append the model's datasheet specs + attribution. active.camera.spec ? t('{spec} · SPECS: CCTV-DATABASE.COM', { From 226600a67a929b63dc661cc9501bdc63953c6687 Mon Sep 17 00:00:00 2001 From: German Khokhlov Date: Wed, 28 Oct 2026 23:13:44 +0400 Subject: [PATCH 40/83] i18n(uk): apply review round 3 Co-Authored-By: Claude Opus 5.5 --- docs/translations/uk.md | 10 ++++-- src/i18n/locales/uk.json | 76 ++++++++++++++++++++-------------------- 2 files changed, 46 insertions(+), 40 deletions(-) diff --git a/docs/translations/uk.md b/docs/translations/uk.md index fcd086f98..b960ab3a9 100644 --- a/docs/translations/uk.md +++ b/docs/translations/uk.md @@ -55,9 +55,10 @@ A `tn()` entry needs four forms. `Intl.PluralRules('uk')` picks: | scene / shot / scene recipe | сцена / кадр / рецепт сцени | | briefing / panel / dock | брифінг / панель / док | | preset / visual preset | пресет / візуальний пресет | -| Scope (circular viewport mask) | приціл | -| overlay (detection overlay) | накладка | +| Scope, keyhole (circular viewport mask) | приціл | +| overlay (detection overlay) / world overlay | накладка / накладка на глобусі | | heading / altitude / ground speed | курс / висота / шляхова швидкість | +| map bearing, map heading | азимут карти | | HDG / BRG / CRS, TRK / FOV / DEST / SPD / RANGE | КУРС / ПЕЛ. / ШК (шляховий кут) / ОГЛЯД / ПРИЗН. / ШВИД / ДАЛЬН. | | Street View (Google) | Перегляд вулиць (as in Ukrainian Google Maps) | | Street Level (layer) | Вуличні знімки | @@ -91,3 +92,8 @@ A `tn()` entry needs four forms. `Intl.PluralRules('uk')` picks: | run (scene playback) / RUN LOG | відтворення / ЖУРНАЛ ВІДТВОРЕННЯ (запуск is a rocket launch) | | Preview (voice panel replies) | відповіді | | Marine (radio tag) / pleasure craft | море (not флот) / прогулянкове судно | +| emergency (ADS-B) / Emergency (radio tag) | аварійний стан / надзвичайні ситуації | +| confidence (FIRMS fire detection) | достовірність (short: достов.) | +| thermal (FLIR-style imaging) | тепловий (not термальний) | +| map stack | набір карт | +| stage (rocket) re-entry / recovery | вхід ступеня в атмосферу / повернення | diff --git a/src/i18n/locales/uk.json b/src/i18n/locales/uk.json index 62a46aa89..a7a5f2634 100644 --- a/src/i18n/locales/uk.json +++ b/src/i18n/locales/uk.json @@ -13,7 +13,7 @@ " · {max}-point limit reached": " · досягнуто ліміту точок: {max}", "{measure} · double-click or Enter to finish, Backspace undoes, Esc cancels.{full}": "{measure} · подвійне клацання або Enter — завершити, Backspace — скасувати точку, Esc — скасувати.{full}", "drawings on the map": "малюнки на карті", - "That shape already has {count} points — finish it or press Backspace.": "У цій фігурі вже точок: {count} — завершіть її або натисніть Backspace.", + "That shape already has {count} points — finish it or press Backspace.": "Фігура вже має максимальну кількість точок ({count}) — завершіть її або натисніть Backspace.", "That point is off the globe — click on the world.": "Ця точка поза глобусом — клацніть на Землі.", "That shape could not be placed.": "Не вдалося розмістити фігуру.", "Could not place the shape: {error}": "Не вдалося розмістити фігуру: {error}", @@ -434,7 +434,7 @@ "Live active-fire detections": "Виявлення активних пожеж у реальному часі", "Real live traffic (keyless runs a simulation)": "Дорожній рух у реальному часі (без ключа — імітація)", "Bing imagery map stacks + world terrain": "Знімки Bing + рельєф світу", - "More flight-polling credits (anonymous works without)": "Вищий ліміт запитів рейсів (анонімно працює й без ключа)", + "More flight-polling credits (anonymous works without)": "Вищий ліміт запитів даних про рейси (анонімно працює й без ключа)", "Street-level imagery and coverage in the Street Level layer. Free: register an app in the Mapillary developer dashboard and paste its Client Token": "Вуличні знімки й покриття в шарі «Вуличні знімки». Безкоштовно: зареєструйте застосунок у панелі розробника Mapillary і вставте його клієнтський токен (Client Token)", "Public space-missions access needs no key. Leave blank for standard use; paid tokens only raise request limits.": "Загальнодоступні дані космічних місій не потребують ключа. Для звичайного використання залиште поле порожнім; платні токени лише підвищують ліміти запитів.", "Air quality request failed": "Не вдалося запитати дані про якість повітря", @@ -506,8 +506,8 @@ "Next — nearest unvisited contact in the 250 km window": "Далі — найближчий ще не переглянутий контакт у радіусі 250 км", "NEXT": "ДАЛІ", "Named areas ({n})": "Іменовані зони ({n})", - "{distance} FLIGHT / VESSEL WINDOW": "РАДІУС РЕЙСІВ / СУДЕН {distance}", - "Open-source mapped/observed context. Missing broadcasts, unloaded map areas, or unmapped sites are not evidence of absence.": "Контекст із відкритих джерел (нанесений/спостережений). Відсутність трансляцій, незавантажені ділянки карти або ненанесені обʼєкти не є доказом відсутності.", + "{distance} FLIGHT / VESSEL WINDOW": "РЕЙСИ / СУДНА · РАДІУС {distance}", + "Open-source mapped/observed context. Missing broadcasts, unloaded map areas, or unmapped sites are not evidence of absence.": "Контекст із відкритих джерел (нанесений/спостережений). Відсутність сигналів, незавантажені ділянки карти або ненанесені обʼєкти не є доказом відсутності.", "mapped matches within {km} km of the subject": "збіги на карті в радіусі {km} км від обʼєкта", "none mapped within {km} km; not a complete 250 km survey": "на карті немає в радіусі {km} км; це не повний огляд на 250 км", "mapped matches from the loaded viewport": "збіги на карті в завантаженій області", @@ -523,7 +523,7 @@ "AIS vessels": "Судна AIS", "Mapped installations": "Нанесені обʼєкти", "syncing {count} city feeds...": "синхронізація міських потоків: {count}...", - "scanning nearby systems...": "пошук ближніх систем...", + "scanning nearby systems...": "пошук систем поблизу...", "GBFS fetch error": "помилка завантаження GBFS", "Station {id}": "Станція {id}", "Station": "Станція", @@ -540,7 +540,7 @@ "SPEC FOV {span}° (CAPABILITY)": "ОГЛЯД ЗА ПАСПОРТОМ {span}° (МОЖЛИВОСТІ)", "COVERAGE {value}km²": "ОХОПЛЕННЯ {value} КМ²", "OVERLAP {count} cams": "ПЕРЕКРИТТЯ {count} КАМ.", - "ISOLATED VIEW": "ОКРЕМИЙ ВИГЛЯД", + "ISOLATED VIEW": "БЕЗ ПЕРЕКРИТТЯ", "PROJ MONITOR": "ПРОЄКЦ. МОНІТОР", "PROJ OFF": "ПРОЄКЦ. ВИМК.", "VIEWSHED": "ЗОНА ВИДИМОСТІ", @@ -570,7 +570,7 @@ "other": "{count} активного шторму" }, "Position as of {time}": "Положення на {time}", - "Maximum sustained wind: {wind} · Pressure: {pressure}": "Макс. стала швидкість вітру: {wind} · Тиск: {pressure}", + "Maximum sustained wind: {wind} · Pressure: {pressure}": "Макс. середня швидкість вітру: {wind} · Тиск: {pressure}", "{name} · {classification} · Advisory {number} · issued {time}": "{name} · {classification} · Зведення № {number} · випущено {time}", "No active NHC/CPHC systems": "Немає активних систем NHC/CPHC", "Advisories unavailable": "Зведення недоступні", @@ -609,8 +609,8 @@ "fork direction|right": "правіше", "fork direction|slightly left": "трохи лівіше", "fork direction|slightly right": "трохи правіше", - "fork direction|sharply left": "лівіше", - "fork direction|sharply right": "правіше", + "fork direction|sharply left": "якомога лівіше", + "fork direction|sharply right": "якомога правіше", "fork direction|straight": "прямого напрямку", "lane direction|left": "ліву", "lane direction|right": "праву", @@ -715,7 +715,7 @@ "Earthquake source unavailable": "Джерело даних про землетруси недоступне", "Focus fire detection {title}, {details}": "Фокус на виявленні пожежі {title}, {details}", "live feed unavailable": "потік даних у реальному часі недоступний", - "{value} conf": "впевн.: {value}", + "{value} conf": "достов.: {value}", "{value} ago": "{value} тому", "sensor n/a": "датчик н/д", "FIRE · {frp} MW": "ПОЖЕЖА · {frp} МВт", @@ -783,7 +783,7 @@ "Retrying automatically at {time} UTC": "Автоматичний повтор о {time} UTC", "Retrying automatically after provider cooldown": "Автоматичний повтор після паузи постачальника", "Updates automatically after pan or zoom and once a minute. The public feed covers a 250-nautical-mile circle around the view centre; zooming out does not make it a worldwide snapshot. Blank cells are outside sampled coverage or have insufficient observations.": "Оновлюється автоматично після зсуву чи масштабування карти та раз на хвилину. Публічний потік даних охоплює коло радіусом 250 морських миль навколо центру карти; у разі віддалення карта не стає знімком усього світу. Порожні комірки — поза охопленням вибірки або з недостатньою кількістю спостережень.", - "Low-accuracy score = 100 × max(0, bad − 1) / total: one aircraft is discounted, so this is not the raw share. Cells need {aircraft} aircraft over {minutes} minutes. Navigation-integrity anomalies are not a detection of jamming or spoofing.": "Показник неточності = 100 × max(0, неточні − 1) / усього: один літак не враховується, тож це не пряма частка неточних літаків. Для комірки потрібно літаків: {aircraft} за {minutes} хв. Аномалії цілісності навігації не означають виявлення глушіння чи підміни сигналу.", + "Low-accuracy score = 100 × max(0, bad − 1) / total: one aircraft is discounted, so this is not the raw share. Cells need {aircraft} aircraft over {minutes} minutes. Navigation-integrity anomalies are not a detection of jamming or spoofing.": "Показник неточності = 100 × max(0, неточні − 1) / усього: один літак не враховується, тож це не пряма частка літаків із неточними навігаційними даними. Мінімальна кількість літаків у комірці за {minutes} хв: {aircraft}. Аномалії цілісності навігації не означають виявлення глушіння чи підміни сигналу.", "GNSS snapshot needs a view anchor": "Для знімка GNSS потрібна опорна точка на карті", "GNSS feed rate limited (HTTP 429)": "Потік GNSS: перевищено ліміт запитів (HTTP 429)", "Malformed GNSS integrity snapshot": "Некоректний знімок цілісності GNSS", @@ -823,7 +823,7 @@ "LIFTOFF · {mission}": "СТАРТ · {mission}", "ASCENT REPLAY · {mission}": "ПОВТОР ВИВЕДЕННЯ · {mission}", "ASCENT ESTIMATE · {mission}": "РОЗРАХУНКОВЕ ВИВЕДЕННЯ · {mission}", - "STAGE RE-ENTRY / RECOVERY · {mission}": "ВХІД В АТМОСФЕРУ / ПОВЕРНЕННЯ · {mission}", + "STAGE RE-ENTRY / RECOVERY · {mission}": "ВХІД СТУПЕНЯ В АТМОСФЕРУ / ПОВЕРНЕННЯ · {mission}", "ORBIT REPLAY · {mission}": "ПОВТОР ОРБІТИ · {mission}", "PAUSED · {title}": "ПАУЗА · {title}", "UNSPECIFIED": "НЕ ВКАЗАНО", @@ -833,7 +833,7 @@ "POSITION UNAVAILABLE": "ПОЗИЦІЯ НЕДОСТУПНА", "FLIGHT {count}": "ПОЛІТ {count}", "REUSED": "ПОВТОРНО ВИКОРИСТАНИЙ", - "NO STAGE RE-ENTRY / RECOVERY DATA": "НЕМАЄ ДАНИХ ПРО ВХІД В АТМОСФЕРУ / ПОВЕРНЕННЯ", + "NO STAGE RE-ENTRY / RECOVERY DATA": "НЕМАЄ ДАНИХ ПРО ВХІД СТУПЕНЯ В АТМОСФЕРУ / ПОВЕРНЕННЯ", "{count} / 30D": "{count} / 30 ДН", "NO MISSIONS AVAILABLE IN THE CURRENT 30-DAY WINDOW": "НЕМАЄ МІСІЙ У ПОТОЧНОМУ 30-ДЕННОМУ ВІКНІ", "DATE UNAVAILABLE": "ДАТА НЕДОСТУПНА", @@ -873,7 +873,7 @@ "EST. DOWNRANGE": "РОЗРАХ. ДАЛЬНІСТЬ", "PLANNED · ": "ПЛАН · ", "SUPPLIED TRAJECTORY POINTS": "НАДАНІ ТОЧКИ ТРАЄКТОРІЇ", - "RECONSTRUCTED ESTIMATE": "ВІДТВОРЕНА ОЦІНКА", + "RECONSTRUCTED ESTIMATE": "РЕКОНСТРУЙОВАНА ОЦІНКА", "Replay the estimated ascent with a following camera": "Відтворити розрахункове виведення з камерою супроводу", "Resume replay": "Продовжити повтор", "T minus {seconds}": "T мінус {seconds}", @@ -963,7 +963,7 @@ "radio tag|All": "Усі", "News": "Новини", "Talk": "Розмовні", - "Weather / Emergency": "Погода / Надзвичайні події", + "Weather / Emergency": "Погода / Надзвичайні ситуації", "Public Safety": "Громадська безпека", "Aviation / Marine": "Авіація / Море", "Traffic / Transit": "Рух / Транспорт", @@ -1170,7 +1170,7 @@ "Subway": "Метро", "Train": "Поїзд", "Ferry": "Пором", - "Transit vehicle": "Громадський транспорт", + "Transit vehicle": "Транспортний засіб", "AIS: {name}": "AIS: {name}", "{type} SPD: {speed} HDG: {heading}": "{type} ШВИД: {speed} КУРС: {heading}", "VESSEL": "СУДНО", @@ -1354,7 +1354,7 @@ "Error: {message}": "Помилка: {message}", "Needs {envVars} — add it in Provider Settings": "Потрібен {envVars} — додайте його в «Налаштуваннях постачальників»", "{label} is unavailable": "{label} — недоступно", - "This map stack": "Цей стек карт", + "This map stack": "Цей набір карт", "{label} unavailable: {hint}": "{label} — недоступно: {hint}", "Google 3D tiles unavailable — check the key's API restrictions, quota, or network": "Тайли Google 3D недоступні — перевірте обмеження API ключа, квоту або мережу", "Needs {envVars} — add it in Provider Settings — or a Cesium ion token for the ion-hosted route": "Потрібен {envVars} — додайте його в «Налаштуваннях постачальників» — або токен Cesium ion для варіанта через ion", @@ -1408,7 +1408,7 @@ "Seeked: {scene} / {shot}": "Перемотано: {scene} / {shot}", "Seeking scene clock": "Перемотування сцени", "Camera unavailable — exit cockpit first": "Камера недоступна — спершу вийдіть із кабіни", - "No shots to run": "Немає кадрів для запуску", + "No shots to run": "Немає кадрів для відтворення", "Scene transition limit reached — load a shot to reset": "Досягнуто ліміту переходів сцени — завантажте кадр, щоб скинути лічильник", "Export failed: {error}": "Помилка експорту: {error}", "Project exported": "Проєкт експортовано", @@ -1425,7 +1425,7 @@ "Scene actions": "Дії сцени", "Select a feature or use Tab and Enter to choose an action.": "Виберіть обʼєкт на карті або скористайтеся Tab і Enter, щоб вибрати дію.", "Selected feature: {feature}. Choose an action.": "Вибрано обʼєкт: {feature}. Виберіть дію.", - "Running {index}/{total}: {scene} / {shot}": "Виконання {index}/{total}: {scene} / {shot}", + "Running {index}/{total}: {scene} / {shot}": "Відтворення {index}/{total}: {scene} / {shot}", "Scene run complete": "Відтворення сцени завершено", "Bhote Koshi Evidence Sequence": "Послідовність свідчень: Bhote Koshi", "Nepal Flood Incident": "Паводок у Непалі", @@ -1572,7 +1572,7 @@ "Copy failed": "Не вдалося скопіювати", "Return map to straight-down view": "Повернути карту до вигляду згори", "Tilt map to oblique view": "Нахилити карту в перспективний вигляд", - "Reset map to north up. Current heading {heading} degrees": "Повернути карту північчю вгору. Поточний курс: {heading}°", + "Reset map to north up. Current heading {heading} degrees": "Повернути карту північчю вгору. Поточний азимут: {heading}°", "Tilted view": "Вигляд із нахилом", "Straight-down view": "Вигляд згори", "North up": "Північ угорі", @@ -1676,7 +1676,7 @@ "CLOUD {pct}%": "ХМАРНІСТЬ {pct}%", "CLOUD UNKNOWN": "ХМАРНІСТЬ НЕВІДОМА", "{source} · LOCATION QUERY": "{source} · ЗАПИТ ЗА РОЗТАШУВАННЯМ", - "REGIONAL NEWS": "НОВИНИ РЕГІОНУ", + "REGIONAL NEWS": "РЕГІОНАЛЬНІ НОВИНИ", "{label} · {radius} AIR/SEA WINDOW": "{label} · ПОВІТРЯ/МОРЕ · РАДІУС {radius}", "{scope} · INSTALLATIONS {coverage}": "{scope} · ОБʼЄКТИ: {coverage}", "CONTEXT STANDBY": "КОНТЕКСТ: ОЧІКУВАННЯ", @@ -1692,15 +1692,15 @@ "L": "Л", "R": "П", "{count} INPUTS UNKNOWN · NOT AN ALL-CLEAR": { - "one": "{count} НЕВІДОМИЙ ПАРАМЕТР · НЕ ОЗНАЧАЄ «УСЕ ЧИСТО»", - "few": "{count} НЕВІДОМІ ПАРАМЕТРИ · НЕ ОЗНАЧАЄ «УСЕ ЧИСТО»", - "many": "{count} НЕВІДОМИХ ПАРАМЕТРІВ · НЕ ОЗНАЧАЄ «УСЕ ЧИСТО»", - "other": "{count} НЕВІДОМОГО ПАРАМЕТРА · НЕ ОЗНАЧАЄ «УСЕ ЧИСТО»" + "one": "{count} ПОТІК БЕЗ ДАНИХ · НЕ ОЗНАЧАЄ «УСЕ ЧИСТО»", + "few": "{count} ПОТОКИ БЕЗ ДАНИХ · НЕ ОЗНАЧАЄ «УСЕ ЧИСТО»", + "many": "{count} ПОТОКІВ БЕЗ ДАНИХ · НЕ ОЗНАЧАЄ «УСЕ ЧИСТО»", + "other": "{count} ПОТОКУ БЕЗ ДАНИХ · НЕ ОЗНАЧАЄ «УСЕ ЧИСТО»" }, "AVAILABLE INPUTS CURRENT · NOT AN ALL-CLEAR": "ДОСТУПНІ ВХІДНІ ДАНІ АКТУАЛЬНІ · НЕ ОЗНАЧАЄ «УСЕ ЧИСТО»", "SQUAWK {code} · {status}": "СКВОК {code} · {status}", "ADS-B PRIORITY · {status}": "ADS-B ПРІОРИТЕТ · {status}", - "ADS-B EMERGENCY · {status}": "ADS-B АВАРІЯ · {status}", + "ADS-B EMERGENCY · {status}": "ADS-B АВАРІЙНИЙ СТАН · {status}", "AIRCRAFT": "БОРТ", "ACQUIRING SURFACE": "ЗАВАНТАЖЕННЯ ПОВЕРХНІ", "SURFACE FALLBACK": "РЕЗЕРВНА ПОВЕРХНЯ", @@ -1749,10 +1749,10 @@ "{aircraftClass} · {distance}": "{aircraftClass} · {distance}", "DISTANCE UNKNOWN": "ВІДСТАНЬ НЕВІДОМА", "{count} INPUTS UNKNOWN": { - "one": "{count} НЕВІДОМИЙ ПАРАМЕТР", - "few": "{count} НЕВІДОМІ ПАРАМЕТРИ", - "many": "{count} НЕВІДОМИХ ПАРАМЕТРІВ", - "other": "{count} НЕВІДОМОГО ПАРАМЕТРА" + "one": "{count} ПОТІК БЕЗ ДАНИХ", + "few": "{count} ПОТОКИ БЕЗ ДАНИХ", + "many": "{count} ПОТОКІВ БЕЗ ДАНИХ", + "other": "{count} ПОТОКУ БЕЗ ДАНИХ" }, "SOURCE STATUS UNAVAILABLE": "СТАТУС ДЖЕРЕЛА НЕДОСТУПНИЙ", "Restore real aircraft": "Повернути справжній літак", @@ -2462,7 +2462,7 @@ "ChatGPT OAuth session: {responses} response(s), {input} input and {output} output tokens, {captions} caption transcription(s) reported.": "Сеанс ChatGPT OAuth: відповідей — {responses}, вхідних токенів — {input}, вихідних токенів — {output}, транскрипцій субтитрів — {captions}.", "USD cost and the API spend cap are unavailable for this auth mode.": "Вартість у USD і ліміт витрат API недоступні в цьому режимі авторизації.", "Usage is incomplete because a response was still in flight when the session ended.": "Дані про використання неповні: на момент завершення сеансу одну з відповідей ще не було отримано.", - "Estimated session cost on {modelId} — {responses} response(s). Warns at {warn}, ends the session at {cap}.": "Орієнтовна вартість сеансу на {modelId} — відповідей: {responses}. Попереджає при {warn}, завершує сеанс при {cap}.", + "Estimated session cost on {modelId} — {responses} response(s). Warns at {warn}, ends the session at {cap}.": "Орієнтовна вартість сеансу на {modelId} — відповідей: {responses}. Попередження на {warn}, завершення сеансу на {cap}.", "Estimate is incomplete — a response was still in flight when the session ended, so its usage was never reported.": "Оцінка неповна: на момент завершення сеансу одну з відповідей ще не було отримано, тому її використання не враховано.", "STANDARD": "СТАНДАРТ", "{tier} applies next session": "{tier} застосовується з наступного сеансу", @@ -2844,7 +2844,7 @@ "Show the globe without a visual filter.": "Показує глобус без візуального фільтра.", "Emulate a green phosphor CRT with scanlines and screen curvature.": "Імітує CRT-монітор із зеленим люмінофором, рядками розгортки та вигнутим екраном.", "Simulate night-vision goggles with green intensification and a tube vignette.": "Імітує прилад нічного бачення: підсилене зелене зображення й затемнення по краях поля зору.", - "Simulate FLIR-style thermal contrast. Turn up Ironbow for color.": "Імітує термальний контраст у стилі FLIR. Для кольору збільште Ironbow.", + "Simulate FLIR-style thermal contrast. Turn up Ironbow for color.": "Імітує тепловий контраст у стилі FLIR. Для кольору збільште Ironbow.", "Apply bright cel-shaded color and illustrated outlines.": "Застосовує яскраву мультяшну заливку та ілюстровані контури.", "Apply high-contrast monochrome film-noir grading.": "Застосовує висококонтрастну чорно-білу обробку в стилі нуар.", "Add a cold, snowy whiteout treatment to the scene.": "Додає до сцени холодний ефект снігової імли.", @@ -2952,11 +2952,11 @@ "Elastic": "Гнучкий", "Weighted": "Зважений", "Fade": "Згасання", - "Detection fade distance": "Відстань згасання виявлення", - "World-overlay fade distance outside the keyhole as a percentage of its radius": "Відстань згасання накладки світу за межами ілюмінатора у відсотках його радіуса", + "Detection fade distance": "Відстань згасання накладки виявлення", + "World-overlay fade distance outside the keyhole as a percentage of its radius": "Відстань згасання накладки на глобусі за межами прицілу у відсотках від його радіуса", "Outside": "Ззовні", - "Detection opacity outside the keyhole": "Непрозорість виявлення за межами ілюмінатора", - "World-overlay label and card opacity beyond the fade distance": "Непрозорість підписів і карток накладки світу за межею згасання", + "Detection opacity outside the keyhole": "Непрозорість накладки виявлення за межами прицілу", + "World-overlay label and card opacity beyond the fade distance": "Непрозорість підписів і карток накладки на глобусі за межею згасання", "PARAMETERS": "ПАРАМЕТРИ", "3D aircraft — flat icons zoomed out, 3D models up close": "3D літаки — плоскі значки здалеку, 3D-моделі зблизька", "Models": "Моделі", @@ -2966,7 +2966,7 @@ "Scope": "Приціл", "Feather": "Розмиття", "Scope edge feather": "Розмиття краю прицілу", - "Scope edge feather as a percentage of the keyhole radius": "Розмиття краю прицілу у відсотках від радіуса ілюмінатора", + "Scope edge feather as a percentage of the keyhole radius": "Розмиття краю прицілу у відсотках від його радіуса", "Draw on the world — click vertices, double-click or Enter to finish, Esc to cancel": "Малювати на карті світу — клацайте вершини, подвійне клацання або Enter — завершити, Esc — скасувати", "Shape": "Фігура", "Shape to draw": "Фігура для малювання", @@ -3004,7 +3004,7 @@ "CCTV camera": "Камера CCTV", "CALIBRATION": "КАЛІБРУВАННЯ", "Drag the camera in the world: rings rotate, arrows move, handles set range/FOV": "Перетягніть камеру в сцені: кільця — обертання, стрілки — переміщення, маркери — дальність/FOV", - "Camera pose — click a value to type": "Позиція камери — клацніть значення, щоб увести", + "Camera pose — click a value to type": "Положення й орієнтація камери — клацніть значення, щоб увести нове", "Heading (compass °) — click to type": "Курс (° за компасом) — клацніть, щоб увести", "Pitch (° up/down) — click to type": "Нахил (° вгору/вниз) — клацніть, щоб увести", "Horizontal FOV (°) — click to type": "Горизонтальний FOV (°) — клацніть, щоб увести", From 4c80c38e2c7ae7617722447283bd489036210dd2 Mon Sep 17 00:00:00 2001 From: German Khokhlov Date: Wed, 28 Oct 2026 23:43:22 +0400 Subject: [PATCH 41/83] i18n(it): apply review round 4 Co-Authored-By: Claude Opus 5.5 --- docs/translations/it.md | 3 ++- src/i18n/locales/it.json | 44 ++++++++++++++++++++-------------------- 2 files changed, 24 insertions(+), 23 deletions(-) diff --git a/docs/translations/it.md b/docs/translations/it.md index 58d7bb427..81854d6fe 100644 --- a/docs/translations/it.md +++ b/docs/translations/it.md @@ -9,7 +9,7 @@ Translation source: abiyeenzo (#912). - Standard Italian as in Italian software UIs. Address the user with informal "tu" imperatives: «Aggiungi», «Attiva», «Scegli», «Incolla», «Riprova». Tooltips that name an action use the same imperative: «Espandi il pannello», «Ripristina la camera». - Sentence case, not Title Case: "Live Flights" → «Voli live», "Space Missions" → «Missioni spaziali». UPPERCASE English stays UPPERCASE: «LIVE», «NON DISPONIBILE». - Quotes inside Italian text are straight double quotes: «Eliminare lo scatto "{shot}"?». Use the accented capitals (È, À) in UPPERCASE text: «VELOCITÀ», «CITTÀ». -- Errors read as a statement, not a past participle on its own: "Search failed" → «Ricerca non riuscita»; "Could not …" → «Impossibile …». A dash that joins a cause and a hint becomes a colon: «Chiave API rifiutata: controlla AISSTREAM_API_KEY». +- Errors read as a statement, not a past participle on its own: "Search failed" → «Ricerca non riuscita»; "Could not …" → «Impossibile …». A dash that joins a cause and a hint becomes a colon: «Chiave API rifiutata: controlla AISSTREAM_API_KEY». The same goes for a label and its hint in a tooltip: «Direzione (bussola °): clic per digitare». - Short labels, chips and HUD readouts stay short. A standard abbreviation with a period beats a wrapped line: REGOLAZ., RILEV., INCL., ALT., VEL., STIM., PROIEZ., ESP.; PREC / SUCC for PREV / NEXT and PREVIOUS / NEXT. - The HUD codes HDG, BRG, CRS, FOV and DEST stay in English, as in cockpit avionics. RANGE is «PORTATA». Words used in a sentence are translated: heading → «prua» (aircraft, ships) or «direzione» (camera, buses, trams, trains), course → «rotta». - Keyboard keys stay in English: Space, Enter, Esc, Tab, Shift, Backspace, H, 1–9 («Tieni premuto Space per parlare», «Premi Enter per riprovare»). @@ -67,6 +67,7 @@ The `many` form is the `other` text with «di» after the number when a noun fol | trigger record (USGS card) / OPEN SOURCE link | scheda / APRI LA FONTE | | advisory (NHC/CPHC cyclone) / cone | bollettino / cono di incertezza | | forecast lead hours (cyclone points) | scadenze di previsione in ore | +| AIR / SEA (radio category) / ground station | ARIA / MARE / stazione di terra | | radio station / broadcaster | stazione radio / emittente | | CH (radio channel readout) | CH (unchanged) | | road / flow (traffic) | strada / flusso | diff --git a/src/i18n/locales/it.json b/src/i18n/locales/it.json index cdfd7ae98..269100030 100644 --- a/src/i18n/locales/it.json +++ b/src/i18n/locales/it.json @@ -574,7 +574,7 @@ "Wind unavailable": "Vento non disponibile", "Advisory center / forecast track": "Centro del ciclone da bollettino / traccia prevista", "Center-track uncertainty cone": "Cono di incertezza della traccia del centro", - "Select a storm on the map, or choose a storm in the list to select it and move the camera. Click empty map space to clear the selection. NOAA NHC/CPHC advisory context. The cone describes forecast center-track uncertainty, not storm size or the full hazard area. Forecast point labels are source lead hours, not times computed from advisory issuance. Geometry follows the surface; height is not weather altitude. Consult the official advisory.": "Seleziona una tempesta sulla mappa, o scegline una nell'elenco per selezionarla e spostare la camera. Fai clic su un punto vuoto della mappa per annullare la selezione. Contesto dai bollettini NOAA NHC/CPHC. Il cono descrive l'incertezza prevista sulla traccia del centro, non le dimensioni della tempesta né l'intera area di pericolo. Le etichette dei punti di previsione indicano le scadenze di previsione in ore fornite dalla fonte, non orari calcolati dall'emissione del bollettino. La geometria segue la superficie; l'altezza non è la quota meteorologica. Consulta il bollettino ufficiale.", + "Select a storm on the map, or choose a storm in the list to select it and move the camera. Click empty map space to clear the selection. NOAA NHC/CPHC advisory context. The cone describes forecast center-track uncertainty, not storm size or the full hazard area. Forecast point labels are source lead hours, not times computed from advisory issuance. Geometry follows the surface; height is not weather altitude. Consult the official advisory.": "Seleziona una tempesta sulla mappa, o scegline una nell'elenco per selezionarla e spostare la camera. Fai clic su un punto vuoto della mappa per annullare la selezione. Contesto dai bollettini NOAA NHC/CPHC. Il cono descrive l'incertezza sulla traccia prevista del centro, non le dimensioni della tempesta né l'intera area di pericolo. Le etichette dei punti di previsione indicano le scadenze di previsione in ore fornite dalla fonte, non orari calcolati dall'emissione del bollettino. La geometria segue la superficie; l'altezza non è la quota meteorologica. Consulta il bollettino ufficiale.", "DRIVE": "AUTO", "Drive": "In auto", "WALK": "A PIEDI", @@ -962,7 +962,7 @@ "radio|TALK": "TALK", "radio|WEATHER": "METEO", "radio|SAFETY": "SICUREZZA", - "radio|AIR / SEA": "AERO / MARE", + "radio|AIR / SEA": "ARIA / MARE", "radio|TRANSIT": "TRASPORTI", "radio|MUSIC": "MUSICA", "radio|OTHER": "ALTRO", @@ -1010,7 +1010,7 @@ "MORE DETAIL · 30 m": "PIÙ DETTAGLIO · 30 m", "Sentinel-2 and Landsat via HLS, 30 m, every 2–6 days": "Sentinel-2 e Landsat tramite HLS, 30 m, ogni 2–6 giorni", "DAILY OVERVIEW · 250 m": "PANORAMICA GIORNALIERA · 250 m", - "VIIRS daily mosaic, 250 m, follows broad changes; little detail under 25 km": "Mosaico giornaliero VIIRS, 250 m, segue i cambiamenti ampi; pochi dettagli sotto i 25 km", + "VIIRS daily mosaic, 250 m, follows broad changes; little detail under 25 km": "Mosaico giornaliero VIIRS, 250 m, mostra i cambiamenti su vasta scala; pochi dettagli sotto i 25 km", "Sentinel-2": "Sentinel-2", "Sentinel-2 via HLS": "Sentinel-2 tramite HLS", "Landsat 8/9": "Landsat 8/9", @@ -1120,7 +1120,7 @@ "LIVE · Roads: OpenStreetMap · Flow: TomTom · {percent}% cov": "LIVE · Strade: OpenStreetMap · Flusso: TomTom · {percent}% cop.", "SIMULATED · Roads: OpenStreetMap · Flow: TomTom (no matches)": "SIMULATO · Strade: OpenStreetMap · Flusso: TomTom (nessuna corrispondenza)", "SIMULATED — traffic service unreachable": "SIMULATO: servizio traffico irraggiungibile", - "SIMULATED — add TomTom key for live": "SIMULATO: aggiungi la chiave TomTom per il live", + "SIMULATED — add TomTom key for live": "SIMULATO: aggiungi la chiave TomTom per i dati live", "OpenFreeMap tiles rate-limited": "Tile OpenFreeMap con limite di richieste", "OpenFreeMap tiles timed out": "Tile OpenFreeMap in timeout", "OpenFreeMap tiles unavailable": "Tile OpenFreeMap non disponibili", @@ -1702,12 +1702,12 @@ "Current style: {style} — click for next": "Stile attuale: {style}. Clic per il successivo", "Collapse Contact panel": "Comprimi il pannello Contatto", "Expand Contact panel": "Espandi il pannello Contatto", - "Collapse contact panel": "Comprimi pannello contatto", - "Expand contact panel": "Espandi pannello contatto", + "Collapse contact panel": "Comprimi il pannello contatto", + "Expand contact panel": "Espandi il pannello contatto", "Collapse cockpit briefing panel": "Comprimi il pannello briefing del cockpit", "Expand cockpit briefing panel": "Espandi il pannello briefing del cockpit", - "Collapse briefing panel": "Comprimi pannello briefing", - "Expand briefing panel": "Espandi pannello briefing", + "Collapse briefing panel": "Comprimi il pannello briefing", + "Expand briefing panel": "Espandi il pannello briefing", "OBSERVED / MAPPED PINGS": "PING OSSERVATI / MAPPATI", "SOURCE-BACKED EVENTS · NO SYNTHETIC NEWS": "EVENTI DA FONTI · NESSUNA NOTIZIA SINTETICA", "LATEST LOCATION-MATCHED REPORTING": "ULTIME NOTIZIE PER POSIZIONE", @@ -2198,7 +2198,7 @@ "{source} rate limited (anonymous)": "{source}: limite di richieste (anonimo)", "{source} rate limited": "{source}: limite di richieste", "{source} network error": "{source}: errore di rete", - "Malformed {source} aircraft rows": "Righe aereo di {source} non valide", + "Malformed {source} aircraft rows": "Righe degli aerei di {source} non valide", "Malformed {source} response": "Risposta di {source} non valida", "entry {n}": "voce {n}", "feeds {names} stale": { @@ -2783,7 +2783,7 @@ "Map source": "Fonte mappa", "Style": "Stile", "Expand LOCATION": "Espandi POSIZIONE", - "Collapse panel": "Comprimi pannello", + "Collapse panel": "Comprimi il pannello", "Pin location tray": "Fissa il pannello posizione", "Keep location tray open": "Mantieni aperto il pannello posizione", "Search any location": "Cerca un luogo", @@ -2799,7 +2799,7 @@ "Previous station": "Stazione precedente", "Next station": "Stazione successiva", "Compact Radio volume": "Volume Radio (controlli compatti)", - "Expand panel": "Espandi pannello", + "Expand panel": "Espandi il pannello", "Context mode": "Modalità contesto", "CONTACTS": "CONTATTI", "Cycles the nearest contacts of whatever type you select — planes, vessels, installations. Satellites track independently.": "Scorre i contatti più vicini del tipo selezionato: aerei, navi, installazioni. I satelliti vengono tracciati in modo indipendente.", @@ -2926,7 +2926,7 @@ "Sharpening": "Nitidezza", "Sharpen": "Nitidezza", "Sharpen intensity": "Intensità della nitidezza", - "EXIT CLEAN VIEW": "ESCI DA VISTA PULITA", + "EXIT CLEAN VIEW": "ESCI DALLA VISTA PULITA", "Return UI controls": "Ripristina i controlli UI", "Initializing photorealistic world...": "Inizializzazione del mondo fotorealistico...", "DATA LAYERS": "LIVELLI DATI", @@ -2935,14 +2935,14 @@ "CCTV camera": "Telecamera CCTV", "CALIBRATION": "CALIBRAZIONE", "Drag the camera in the world: rings rotate, arrows move, handles set range/FOV": "Trascina la telecamera nel mondo: gli anelli ruotano, le frecce spostano, i punti di controllo impostano portata/FOV", - "Camera pose — click a value to type": "Posa della telecamera — clic su un valore per digitare", - "Heading (compass °) — click to type": "Direzione (bussola °) — clic per digitare", - "Pitch (° up/down) — click to type": "Inclinazione (° su/giù) — clic per digitare", - "Horizontal FOV (°) — click to type": "FOV orizzontale (°) — clic per digitare", - "Range / monitor-plane distance (m) — click to type": "Portata / distanza del piano monitor (m) — clic per digitare", - "Mount height above ground (m) — click to type": "Altezza di montaggio dal suolo (m) — clic per digitare", - "North offset from catalog position (m) — click to type": "Scostamento a nord dalla posizione a catalogo (m) — clic per digitare", - "East offset from catalog position (m) — click to type": "Scostamento a est dalla posizione a catalogo (m) — clic per digitare", + "Camera pose — click a value to type": "Posa della telecamera: clic su un valore per digitare", + "Heading (compass °) — click to type": "Direzione (bussola °): clic per digitare", + "Pitch (° up/down) — click to type": "Inclinazione (° su/giù): clic per digitare", + "Horizontal FOV (°) — click to type": "FOV orizzontale (°): clic per digitare", + "Range / monitor-plane distance (m) — click to type": "Portata / distanza del piano monitor (m): clic per digitare", + "Mount height above ground (m) — click to type": "Altezza di montaggio dal suolo (m): clic per digitare", + "North offset from catalog position (m) — click to type": "Scostamento a nord dalla posizione a catalogo (m): clic per digitare", + "East offset from catalog position (m) — click to type": "Scostamento a est dalla posizione a catalogo (m): clic per digitare", "SAVE CAL": "SALVA CAL", "RESET CAL": "RESET CAL", "SCENE SUMMARY": "RIEPILOGO SCENA", @@ -2953,7 +2953,7 @@ "FIT": "ADATTA", "Fit: show the whole photo, with dark bars where its shape differs from the frame": "Adatta: mostra l'intera foto, con bande scure dove la sua forma differisce dal riquadro", "FILL": "RIEMPI", - "Fill: fill the frame edge to edge, cropping the photo": "Riempi: riempie il riquadro da bordo a bordo, ritagliando la foto", + "Fill: fill the frame edge to edge, cropping the photo": "Riempi: copri il riquadro da bordo a bordo, ritagliando la foto", "Close the image and deselect it on the map": "Chiudi l'immagine e deselezionala sulla mappa", "Close the street-level image": "Chiudi l'immagine a livello stradale", "Street-level viewer": "Visualizzatore a livello stradale", @@ -2976,7 +2976,7 @@ "IMPORT": "IMPORTA", "RUN LOG": "LOG ESECUZIONE", "POWER UP": "ACCENDI", - "GROUND STATION · PROVIDER SETTINGS": "STAZIONE A TERRA · IMPOSTAZIONI PROVIDER", + "GROUND STATION · PROVIDER SETTINGS": "STAZIONE DI TERRA · IMPOSTAZIONI PROVIDER", "Close key setup": "Chiudi la configurazione delle chiavi", "Power up the globe": "Accendi il globo", "The globe already flies keyless. Every key below switches on another real feed — paste one and it's saved into this app's local configuration, then the server restarts itself. Server-side keys stay on this machine; Google Maps and Cesium ion run in the browser and must be provider-restricted. Keys you configured elsewhere are shown but never touched.": "Il globo funziona già senza chiavi. Ogni chiave qui sotto attiva un altro feed reale: incollane una e verrà salvata nella configurazione locale di questa app, poi il server si riavvia da solo. Le chiavi lato server restano su questa macchina; le chiavi di Google Maps e Cesium ion vengono usate nel browser e richiedono restrizioni configurate presso il provider. Le chiavi configurate altrove vengono mostrate ma mai modificate.", From 3d32a0c45c15ab639e0b4ee071e9f920fa5ecde4 Mon Sep 17 00:00:00 2001 From: German Khokhlov Date: Wed, 28 Oct 2026 23:43:23 +0400 Subject: [PATCH 42/83] i18n(fr): apply review round 4 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Apply the accepted findings from the fourth three-model French review: « Fermez d'abord cet outil » in the pointer-busy notices, the colon form « Outil actif : {name} » for the directions notice, « FOV CONSTRUCTEUR », « RAPPORT » for the USGS trigger chip, « CONTEXTE GLOBAL DÉSACTIVÉ », and wording fixes for the radio, recent imagery, bundle preview and draw label strings. The guide gains glossary rows for the datasheet FOV and for rapport versus relevé. Co-Authored-By: Claude Opus 5.5 --- docs/translations/fr.md | 2 ++ src/i18n/locales/fr.json | 22 +++++++++++----------- 2 files changed, 13 insertions(+), 11 deletions(-) diff --git a/docs/translations/fr.md b/docs/translations/fr.md index 34ba9c9cb..94f7c3317 100644 --- a/docs/translations/fr.md +++ b/docs/translations/fr.md @@ -96,6 +96,8 @@ The `many` form is the `other` text with « de » (« d' » before a vowel) afte | cloud cover / CLOUD (briefing readout) | nébulosité / NÉBULOSITÉ | | LEVEL (cockpit horizon guide) | HORIZON | | CALIBRATED / CURATED / RAW PRIOR (CCTV pose) | CALIBRÉE / VÉRIFIÉE / ESTIM. INITIALE | +| DATASHEET / SPEC FOV (CCTV lens range) | FICHE TECHNIQUE / FOV CONSTRUCTEUR | | PORT TENDER (AIS type) | SERVITUDE PORT. (navire de servitude portuaire) | | ChatGPT sign-in (action) / opening sign-in / sign-in expired | connexion / page de connexion / la session a expiré | | authored shot (scene) | plan scénarisé | +| report / record (USGS event card) / readout, reading | rapport / relevé (a measured value only) | diff --git a/src/i18n/locales/fr.json b/src/i18n/locales/fr.json index b63ee45f6..02f160c4f 100644 --- a/src/i18n/locales/fr.json +++ b/src/i18n/locales/fr.json @@ -17,7 +17,7 @@ "That shape could not be placed.": "Impossible de placer cette forme.", "Could not place the shape: {error}": "Impossible de placer la forme : {error}", "Board cleared.": "Tableau effacé.", - "{owner} is using the pointer — close it first.": "Pointeur utilisé par : {owner}. Fermez-le d'abord.", + "{owner} is using the pointer — close it first.": "Pointeur utilisé par : {owner}. Fermez d'abord cet outil.", "{label} · Detailed outline unavailable": "{label} · Contour détaillé indisponible", "Flying to Austin, TX...": "En route vers Austin, Texas…", "Restoring shared view...": "Restauration de la vue partagée…", @@ -197,8 +197,8 @@ "Animate the sourced cyan river-centerline route to Trishuli Bazaar": "Animer le tracé cyan sourcé de l'axe de la rivière jusqu'à Trishuli Bazaar", "OVERVIEW": "VUE D'ENSEMBLE", "Keep the completed flood path and location labels visible": "Garder visibles le tracé complet de la crue et les noms de lieux", - "RECORD": "RELEVÉ", - "Reveal the trigger record while making a slow camera approach": "Révéler le relevé du déclenchement pendant une lente approche de la caméra", + "RECORD": "RAPPORT", + "Reveal the trigger record while making a slow camera approach": "Révéler le rapport sur l'événement déclencheur pendant une lente approche de la caméra", "{speed} kn": "{speed} nd", "That file is not valid JSON.": "Ce fichier n'est pas un JSON valide.", "That JSON file is not GeoJSON.": "Ce fichier JSON n'est pas du GeoJSON.", @@ -296,7 +296,7 @@ "TANKER": "NAVIRE-CITERNE", "OTHER": "AUTRE", "Included in bundle": "Inclus dans l'archive", - "Missing bundle file — reimport its bundle": "Fichier absent de l'archive — réimportez son archive", + "Missing bundle file — reimport its bundle": "Fichier de l'archive manquant — réimportez l'archive", "Source configured; file checked when loaded": "Source configurée ; fichier vérifié au chargement", "Source unavailable": "Source indisponible", "ENVIRONMENTAL": "ENVIRONNEMENT", @@ -487,7 +487,7 @@ "Overpass returned an incomplete camera response": "Overpass a renvoyé une réponse incomplète pour les caméras", "At least {count}": "Au moins {count}", "CONTEXT READY": "CONTEXTE PRÊT", - "GLOBAL CONTEXT OFF": "CONTEXTE GLOBAL OFF", + "GLOBAL CONTEXT OFF": "CONTEXTE GLOBAL DÉSACTIVÉ", "SELECT A FLIGHT, VESSEL, OR MAPPED INSTALLATION": "CHOISIR UN VOL, UN NAVIRE OU UNE INSTALLATION CARTOGRAPHIÉE", "ENABLE TO LOAD OBSERVED / MAPPED PROXIMITY": "ACTIVER POUR VOIR LES CONTACTS PROCHES OBSERVÉS / CARTOGRAPHIÉS", "Unavailable": "Indisponible", @@ -530,7 +530,7 @@ "{city} CCTV": "CCTV {city}", "FOV {value}° (DATASHEET)": "FOV {value}° (FICHE TECHNIQUE)", "FOV {value}°": "FOV {value}°", - "SPEC FOV {span}° (CAPABILITY)": "FOV FICHE {span}° (CAPACITÉ)", + "SPEC FOV {span}° (CAPABILITY)": "FOV CONSTRUCTEUR {span}° (CAPACITÉ)", "COVERAGE {value}km²": "COUVERTURE {value} km²", "OVERLAP {count} cams": "CHEVAUCHEMENT {count} cam.", "ISOLATED VIEW": "VUE ISOLÉE", @@ -686,7 +686,7 @@ "Remove the route and both markers": "Supprimer l'itinéraire et les deux marqueurs", "press Escape twice to leave Draw": "appuyez deux fois sur Esc pour quitter Dessin", "{name} is active — turn {name} off, then set {endpoint}": "Outil actif : {name} — désactivez {name}, puis placez {endpoint}", - "{name} is active — {leave}, then set {endpoint}": "{name} est actif — {leave}, puis placez {endpoint}", + "{name} is active — {leave}, then set {endpoint}": "Outil actif : {name} — {leave}, puis placez {endpoint}", "Only the first {count} turns of this route are shown": "Seules les {count} premières manœuvres de cet itinéraire sont affichées", "Turn-by-turn directions": "Instructions pas à pas", "Another map tool is using clicks — close it, then SET A again": "Un autre outil de carte utilise les clics — fermez-le, puis refaites PLACER A", @@ -1991,7 +1991,7 @@ " · degraded directory": " · annuaire dégradé", " · stale directory": " · annuaire obsolète", " · outside current filter": " · hors du filtre actuel", - "Ready — playback starts only from your action": "Prêt — la lecture ne démarre que sur votre action", + "Ready — playback starts only from your action": "Prêt — la lecture ne démarre qu'à votre demande", "Radio off": "Radio désactivée", "Connecting directly to broadcaster…": "Connexion directe au diffuseur…", "Buffering broadcaster stream…": "Mise en mémoire tampon du flux du diffuseur…", @@ -2017,12 +2017,12 @@ "Point the camera at the ground to use the view": "Orientez la caméra vers le sol pour utiliser la vue", "That point cannot anchor a box": "Ce point ne peut pas ancrer une zone", "Imagery stops at ±{limit}° latitude": "L'imagerie s'arrête à ±{limit}° de latitude", - "{owner} is using the pointer — close it first": "Pointeur utilisé par : {owner}. Fermez-le d'abord", + "{owner} is using the pointer — close it first": "Pointeur utilisé par : {owner}. Fermez d'abord cet outil", "Box is {size} wide · limit {limit}": "La zone fait {size} de large · limite {limit}", "View is {size} wide · limit {limit}": "La vue fait {size} de large · limite {limit}", "VS BASEMAP": "VS CARTE", "A / B": "A / B", - "Newest low-cloud day for this box · scene cloud, not box cloud": "Jour le plus récent peu nuageux pour cette zone · nuages de la scène, pas de la zone", + "Newest low-cloud day for this box · scene cloud, not box cloud": "Jour peu nuageux le plus récent pour cette zone · nuages de la scène, pas de la zone", "Newest day covering this box · cloudier than 20%": "Jour le plus récent couvrant cette zone · plus de 20 % de nuages", "Newest day with imagery for this box · partial coverage": "Jour le plus récent avec des images pour cette zone · couverture partielle", "Newest daily overview for this box": "Vue quotidienne la plus récente pour cette zone", @@ -2904,7 +2904,7 @@ "Area": "Zone", "Line": "Ligne", "Pin": "Épingle", - "Label (optional)": "Étiquette (facultatif)", + "Label (optional)": "Étiquette (facultative)", "Label for the drawn shape": "Étiquette de la forme dessinée", "Colour of the drawn shape": "Couleur de la forme dessinée", "Primary": "Principale", From 423452095c1655750c643f602668299c990c4483 Mon Sep 17 00:00:00 2001 From: German Khokhlov Date: Wed, 28 Oct 2026 23:46:55 +0400 Subject: [PATCH 43/83] i18n(de): apply review round 4 Co-Authored-By: Claude Opus 5.5 --- docs/translations/de.md | 8 +++-- src/i18n/locales/de.json | 76 ++++++++++++++++++++-------------------- 2 files changed, 43 insertions(+), 41 deletions(-) diff --git a/docs/translations/de.md b/docs/translations/de.md index 62e7420a3..444d0741f 100644 --- a/docs/translations/de.md +++ b/docs/translations/de.md @@ -18,10 +18,10 @@ Translation source: abiyeenzo (#908). - Rolling time windows say their length, so they cannot read as the previous calendar period: LAST YEAR → «LETZTE 12 MONATE», LAST MONTH → «LETZTE 30 TAGE». - Keyboard keys are named as on German keyboards where they differ: Leertaste, Rücktaste, Umschalt; Esc, Enter, Tab and letter keys stay. - Decimal comma in fixed text: «M4,4», «28,2710° N». Thousands separator is a period: «1.000 km». Formatted numbers come from `Intl` and are already German. -- Units: km, m, km/h, m/s, kn (knots, also in the cockpit), ft (feet), hPa, MW, h, min, s, T (days, in short readouts); in UPPERCASE text KM, KM/H, KN, FT, MIN. A space between number and unit, in compact readouts too: «{value} m», «{count} min», «50 %», «{speed} KN», «{count} / 30 T». `°` sticks to the number. +- Units: km, m, km/h, m/s, kn (knots, also in the cockpit), ft (feet), hPa, MW, h, min, s, T (days, in short readouts); in UPPERCASE text KM, KM/H, KN, FT, MIN, H, T («VOR {count} H»). A space between number and unit, in compact readouts too: «{value} m», «{count} min», «50 %», «{speed} KN», «{count} / 30 T». `°` sticks to the number. - "ago" goes before the time: «vor {count} min», «vor {value}». When a placeholder already holds a localized "ago" text (`{age}` in `STALE · cached {age}`, `{ago}`), do not add «vor» again. - Compass points use O for Ost: N, NNO, NO, ONO, O, OSO, SO, SSO, S, SSW, SW, WSW, W, WNW, NW, NNW; hemisphere letters N, S, O, W. -- Routing: direction words are lowercase adverbs (links, leicht rechts, scharf links, geradeaus), so a sentence never starts with one: «Auf {road} {direction} abbiegen», «Dann {direction} abbiegen», «Weiter {direction}». Roundabout exits are ordinals with a period: «die {exit} Ausfahrt» → «die 2. Ausfahrt». A lane is named by where it leads, not by its position: «Die geradeaus führende Spur benutzen», «die leicht nach links führende», «die scharf nach rechts führende» (not «halblinke» or «äußerst linke»). +- Routing: direction words are lowercase adverbs (links, leicht rechts, scharf links, geradeaus), so a sentence never starts with one: «Auf {road} {direction} abbiegen», «Hier {direction} abbiegen», «Weiter {direction}». «Hier», not «Dann»: the step card already says «dann {leg}» and «Nächster Schritt: …». At a fork the verb is «weiter», which also works with «geradeaus»: «An der Gabelung {direction} weiter». Roundabout exits are ordinals with a period: «die {exit} Ausfahrt» → «die 2. Ausfahrt». A lane is named by where it leads, not by its position: «Die geradeaus führende Spur benutzen», «die leicht nach links führende», «die scharf nach rechts führende» (not «halblinke» or «äußerst linke»). ## Plurals @@ -83,7 +83,7 @@ Keep the verb in agreement: «{count} Station meldet» / «{count} Stationen mel | RANGE / PITCH / HGT (CCTV calibration chips) | REICHW. / NEIGUNG / HÖHE | | PREV / NEXT | ZURÜCK / WEITER | | RESUME (radio transport button) | FORTSETZEN (not «WEITER», which is NEXT in the same row) | -| nearest (spatial) | nächstgelegen (where «nächste» could read as NEXT) | +| nearest (spatial) | nächstgelegen (always; «nächste» is NEXT) | | expand / collapse (sections) | ausklappen / einklappen | | L / R (relative bearing) | L / R | | SIG / NEWS / LOCAL (briefing tabs) | SIG / NEWS / LOKAL | @@ -95,6 +95,8 @@ Keep the verb in agreement: «{count} Station meldet» / «{count} Stationen mel | voice (control) / voice session | Sprachsteuerung / Sprachsitzung | | YOU / THIS / HERE (voice card labels) | EINGABE / DIES / HIER | | click / click to … | anklicken / … klicken | +| tap (touch) | Antippen (not «Tipp», which is a hint) | +| tilted view | Schrägansicht | | card (host card) / voice card | Eintrag (in hints), Infokarte / Sprachkarte | | label (on the map) / clear (switch off layers) | Beschriftung / ausschalten (not «löschen») | | station tag (radio filter) | Kategorie | diff --git a/src/i18n/locales/de.json b/src/i18n/locales/de.json index 7bdcf73af..ea302b7bf 100644 --- a/src/i18n/locales/de.json +++ b/src/i18n/locales/de.json @@ -110,7 +110,7 @@ "Previous — prior visited contact in the 250 km window": "Zurück: zuvor besuchter Kontakt im 250-km-Fenster", "PREVIOUS": "ZURÜCK", "FOCUS": "FOKUS", - "Next — nearest unvisited contact in the 250 km window": "Weiter: nächster unbesuchter Kontakt im 250-km-Fenster", + "Next — nearest unvisited contact in the 250 km window": "Weiter: nächstgelegener unbesuchter Kontakt im 250-km-Fenster", "NEXT": "WEITER", "Open-source mapped/observed context. Missing broadcasts, unloaded map areas, or unmapped sites are not evidence of absence.": "Kontext aus offenen Quellen, kartiert/beobachtet. Fehlende Funksignale, nicht geladene Kartenbereiche oder nicht kartierte Standorte sind kein Beleg für Abwesenheit.", "HDG {value}°": "HDG {value}°", @@ -142,7 +142,7 @@ "PROJ MONITOR": "PROJ MONITOR", "PROJ OFF": "PROJ AUS", "VIEWSHED": "SICHTBEREICH", - "CAL {value}": "KAL {value}", + "CAL {value}": "KAL. {value}", "SRC {value}": "QUELLE {value}", "{value} CONTEXT": "{value} KONTEXT", "Focus fire detection {title}, {details}": "Branderkennung {title} fokussieren, {details}", @@ -331,7 +331,7 @@ "Bloom": "Bloom", "VISUAL PRESETS": "VISUELLE PRESETS", "LOCATION": "STANDORT", - "CONTACTS — nearest planes · vessels · sites": "KONTAKTE: nächste Flugzeuge · Schiffe · Standorte", + "CONTACTS — nearest planes · vessels · sites": "KONTAKTE: nächstgelegene Flugzeuge · Schiffe · Standorte", "SPACE MISSIONS — launches & orbital assets": "RAUMMISSIONEN: Starts & Orbit-Objekte", "LIVE SIGNALS": "LIVE-SIGNALE", "Contacts could not complete the requested transition; try again": "Kontakte konnten den gewünschten Wechsel nicht abschließen; erneut versuchen", @@ -359,8 +359,8 @@ "AUTO HOP OFF": "AUTO-WECHSEL AUS", "PROJECTION ON": "PROJEKTION EIN", "PROJECTION OFF": "PROJEKTION AUS", - "CAL · EDITED (UNSAVED)": "KAL · GEÄNDERT (UNGESPEICHERT)", - "CAL · {badge}": "KAL · {badge}", + "CAL · EDITED (UNSAVED)": "KAL. · GEÄNDERT (UNGESPEICHERT)", + "CAL · {badge}": "KAL. · {badge}", "MONITOR": "MONITOR", "OFF": "AUS", "{city} · HDG {heading} · FOV {fov} · RANGE {range}m · {projection}{calBadge} · {provider}{status}": "{city} · HDG {heading} · FOV {fov} · REICHW. {range} m · {projection}{calBadge} · {provider}{status}", @@ -457,7 +457,7 @@ "PLACE / CONDITIONS / POSITION": "ORT / BEDINGUNGEN / POSITION", "TIME UNKNOWN": "ZEIT UNBEKANNT", "{count}M AGO": "VOR {count} MIN", - "{count}H AGO": "VOR {count} STD", + "{count}H AGO": "VOR {count} H", "{count}D AGO": "VOR {count} T", "DIR UNKNOWN": "RICHTUNG UNBEKANNT", "Select flight {title}": "Flug {title} auswählen", @@ -465,7 +465,7 @@ "MILITARY FLIGHT": "MILITÄRFLUG", "COMMERCIAL FLIGHT": "ZIVILFLUG", "{aircraftClass} · {distance}": "{aircraftClass} · {distance}", - "DISTANCE UNKNOWN": "DISTANZ UNBEKANNT", + "DISTANCE UNKNOWN": "ENTFERNUNG UNBEKANNT", "{count} INPUTS UNKNOWN": { "one": "STATUS UNKLAR: {count} QUELLE", "other": "STATUS UNKLAR: {count} QUELLEN" @@ -651,7 +651,7 @@ "Check microphone permission and network access, then try again.": "Mikrofonberechtigung und Netzwerkzugriff prüfen, dann erneut versuchen.", "Release Space to send": "Leertaste loslassen zum Senden", "Hold Space to talk": "Leertaste halten zum Sprechen", - "Requesting microphone": "Mikrofon wird angefragt", + "Requesting microphone": "Mikrofonzugriff wird angefordert", "Ask or command": "Fragen oder Befehl geben", "Running command": "Befehl läuft", "Voice off": "Sprache aus", @@ -692,7 +692,7 @@ "Contact navigation": "Kontaktnavigation", "CONTEXT ONLY": "NUR KONTEXT", "Nearby cohort counts": "Anzahl Kontakte in der Nähe", - "NEAREST OBSERVED / MAPPED": "NÄCHSTES OBJEKT · BEOBACHTET / KARTIERT", + "NEAREST OBSERVED / MAPPED": "NÄCHSTGELEGENES OBJEKT · BEOBACHTET / KARTIERT", "AVAILABLE INPUTS ONLY · NOT AN ALL-CLEAR": "NUR VERFÜGBARE QUELLEN · KEINE ENTWARNUNG", "Cockpit briefing carousel": "Cockpit-Briefing-Karussell", "Estimated flight plan": "Geschätzter Flugplan", @@ -759,7 +759,7 @@ "Expand panel": "Bereich ausklappen", "Context mode": "Kontextmodus", "CONTACTS": "KONTAKTE", - "Cycles the nearest contacts of whatever type you select — planes, vessels, installations. Satellites track independently.": "Wechselt durch die nächsten Kontakte des gewählten Typs: Flugzeuge, Schiffe, Anlagen. Satelliten werden unabhängig verfolgt.", + "Cycles the nearest contacts of whatever type you select — planes, vessels, installations. Satellites track independently.": "Wechselt zwischen den nächstgelegenen Kontakten des gewählten Typs: Flugzeuge, Schiffe, Anlagen. Satelliten werden unabhängig verfolgt.", "SPACE MISSIONS": "RAUMMISSIONEN", "SELECT CONTEXT": "KONTEXT WÄHLEN", "Contact Context actions": "Aktionen für Kontaktkontext", @@ -810,7 +810,7 @@ "Detection opacity outside the keyhole": "Erkennungsdeckkraft außerhalb des Schlüssellochs", "World-overlay label and card opacity beyond the fade distance": "Deckkraft von Beschriftungen und Infokarten im Welt-Overlay jenseits des Ausblendeabstands", "PARAMETERS": "PARAMETER", - "3D aircraft — flat icons zoomed out, 3D models up close": "3D-Flugzeuge: flache Symbole bei Fernsicht, 3D-Modelle aus der Nähe", + "3D aircraft — flat icons zoomed out, 3D models up close": "3D-Flugzeuge: flache Symbole aus der Ferne, 3D-Modelle aus der Nähe", "Models": "Modelle", "3D model coverage": "3D-Modellabdeckung", "Proximity": "Nähe", @@ -831,7 +831,7 @@ "Return UI controls": "Bedienelemente wieder einblenden", "Initializing photorealistic world...": "Fotorealistische Welt wird initialisiert...", "DATA LAYERS": "DATENEBENEN", - "NEAREST": "NÄCHSTE", + "NEAREST": "NÄCHSTGELEGENE", "CCTV camera": "CCTV-Kamera", "CALIBRATION": "KALIBRIERUNG", "Drag the camera in the world: rings rotate, arrows move, handles set range/FOV": "Kamera in der Welt ziehen: Ringe drehen, Pfeile verschieben, Griffe setzen Reichweite/FOV", @@ -843,8 +843,8 @@ "Mount height above ground (m) — click to type": "Montagehöhe über Grund (m): anklicken zum Eingeben", "North offset from catalog position (m) — click to type": "Nordversatz zur Katalogposition (m): anklicken zum Eingeben", "East offset from catalog position (m) — click to type": "Ostversatz zur Katalogposition (m): anklicken zum Eingeben", - "SAVE CAL": "KAL SPEICHERN", - "RESET CAL": "KAL ZURÜCKSETZEN", + "SAVE CAL": "KAL. SPEICHERN", + "RESET CAL": "KAL. ZURÜCKSETZEN", "SCENE SUMMARY": "SZENEN-ÜBERSICHT", "SCENES": "SZENEN", "Scene recipe": "Szenenrezept", @@ -1233,9 +1233,9 @@ "Malformed AQHI observation response": "Fehlerhafte Antwort der AQHI-Beobachtungen", "Camera source temporarily unavailable": "Kameraquelle vorübergehend nicht verfügbar", "Mapped camera locations": "Kartierte Kamerastandorte", - "SHOW NEAREST": "NÄCHSTE ZEIGEN", + "SHOW NEAREST": "NÄCHSTGELEGENE ZEIGEN", "Stop following the current object before navigating to a camera": "Vor dem Wechsel zu einer Kamera das Verfolgen des aktuellen Objekts beenden", - "Move to the nearest loaded camera and show its details": "Zur nächsten geladenen Kamera wechseln und Details zeigen", + "Move to the nearest loaded camera and show its details": "Zur nächstgelegenen geladenen Kamera wechseln und Details zeigen", "Camera badges": "Kamera-Markierungen", "Cyan cameras turn coral when selected. Wedges illustrate mapped direction, not measured coverage. Nearby cameras may be outside the screen.": "Cyanfarbene Kameras werden bei Auswahl korallenrot. Keile zeigen die kartierte Blickrichtung, keine gemessene Abdeckung. Kameras in der Nähe können außerhalb des Bildschirms liegen.", "{count} nearby · {onScreen} on screen": { @@ -1301,7 +1301,7 @@ "Wind unavailable": "Wind nicht verfügbar", "Advisory center / forecast track": "Zentrum laut Lagebericht / Vorhersagebahn", "Center-track uncertainty cone": "Unsicherheitskegel der Zentrumsbahn", - "Select a storm on the map, or choose a storm in the list to select it and move the camera. Click empty map space to clear the selection. NOAA NHC/CPHC advisory context. The cone describes forecast center-track uncertainty, not storm size or the full hazard area. Forecast point labels are source lead hours, not times computed from advisory issuance. Geometry follows the surface; height is not weather altitude. Consult the official advisory.": "Einen Sturm auf der Karte auswählen oder in der Liste wählen, um ihn auszuwählen und die Kamera dorthin zu bewegen. Auf eine leere Kartenstelle klicken, um die Auswahl aufzuheben. Kontext aus Lageberichten von NOAA NHC/CPHC. Der Kegel beschreibt die Unsicherheit der vorhergesagten Zentrumsbahn, nicht die Sturmgröße oder das gesamte Gefahrengebiet. Die Beschriftungen der Vorhersagepunkte sind Vorlaufstunden der Quelle, keine aus dem Ausgabezeitpunkt berechneten Zeiten. Die Geometrie folgt der Oberfläche; die Höhe ist keine Wetterhöhe. Den offiziellen Lagebericht beachten.", + "Select a storm on the map, or choose a storm in the list to select it and move the camera. Click empty map space to clear the selection. NOAA NHC/CPHC advisory context. The cone describes forecast center-track uncertainty, not storm size or the full hazard area. Forecast point labels are source lead hours, not times computed from advisory issuance. Geometry follows the surface; height is not weather altitude. Consult the official advisory.": "Einen Sturm auf der Karte auswählen oder in der Liste wählen, um ihn auszuwählen und die Kamera dorthin zu bewegen. Auf eine leere Kartenstelle klicken, um die Auswahl aufzuheben. Kontext aus Lageberichten von NOAA NHC/CPHC. Der Kegel beschreibt die Unsicherheit der vorhergesagten Zentrumsbahn, nicht die Sturmgröße oder das gesamte Gefahrengebiet. Die Beschriftungen der Vorhersagepunkte sind Vorlaufstunden der Quelle, keine aus dem Ausgabezeitpunkt berechneten Zeiten. Die Geometrie folgt der Oberfläche; die Darstellungshöhe hat keine meteorologische Bedeutung. Den offiziellen Lagebericht beachten.", "DRIVE": "AUTO", "Drive": "Auto", "WALK": "ZU FUSS", @@ -1352,7 +1352,7 @@ "Continue straight onto {road}": "Geradeaus weiter auf {road}", "Continue straight": "Geradeaus weiter", "Turn {direction} onto {road}": "Auf {road} {direction} abbiegen", - "Turn {direction}": "Dann {direction} abbiegen", + "Turn {direction}": "Hier {direction} abbiegen", "Turn onto {road}": "Auf {road} abbiegen", "maneuver|Turn": "Abbiegen", "Continue {direction} onto {road}": "Weiter {direction} auf {road}", @@ -1361,12 +1361,12 @@ "At the end of the road, turn {direction}": "Am Ende der Straße {direction} abbiegen", "At the end of the road, continue onto {road}": "Am Ende der Straße weiter auf {road}", "At the end of the road, continue": "Am Ende der Straße weiter", - "Keep {direction} at the fork onto {road}": "An der Gabelung {direction} halten, weiter auf {road}", - "Keep {direction} at the fork": "An der Gabelung {direction} halten", + "Keep {direction} at the fork onto {road}": "An der Gabelung {direction} weiter auf {road}", + "Keep {direction} at the fork": "An der Gabelung {direction} weiter", "Continue at the fork onto {road}": "An der Gabelung weiter auf {road}", "Continue at the fork": "An der Gabelung weiter", "Merge {direction} onto {road}": "Auf {road} {direction} einfädeln", - "Merge {direction}": "Dann {direction} einfädeln", + "Merge {direction}": "Hier {direction} einfädeln", "Merge onto {road}": "Auf {road} einfädeln", "maneuver|Merge": "Einfädeln", "Take the ramp on the {direction} onto {road}": "Die Auffahrt {direction} auf {road} nehmen", @@ -1583,7 +1583,7 @@ "radio|WEATHER": "WETTER", "radio|OTHER": "SONST.", "Broadcaster stream is unavailable or blocked by the browser.": "Der Stream des Senders ist nicht verfügbar oder wird vom Browser blockiert.", - "Playback requires a direct click or tap.": "Die Wiedergabe erfordert einen direkten Klick oder Tipp.", + "Playback requires a direct click or tap.": "Die Wiedergabe muss direkt per Klick oder Antippen gestartet werden.", "Broadcaster stream could not be started.": "Der Stream des Senders konnte nicht gestartet werden.", "overview": "Übersicht", "cloud unknown": "Bewölkung unbekannt", @@ -1860,7 +1860,7 @@ "Issued: {time}": "Ausgegeben: {time}", "Selected field unavailable · wind remains visible": "Gewähltes Feld nicht verfügbar · Wind bleibt sichtbar", "{error} · wind remains visible": "{error} · Wind bleibt sichtbar", - "Surface wind at 10 m. Approximately 1° global grid. Curves follow the 10 m wind field, lifted 12 km for visibility; display height is not weather altitude. View lighting is for readability. Animation shows flow through one fixed forecast; it does not advance time. Color fields drape the globe basemap or the active photorealistic 3D Tiles.": "Bodenwind in 10 m Höhe. Globales Raster von etwa 1°. Die Kurven folgen dem 10-m-Windfeld, zur Sichtbarkeit 12 km angehoben; die Anzeigehöhe ist keine Wetterhöhe. Die Beleuchtung dient der Lesbarkeit. Die Animation zeigt die Strömung einer festen Vorhersage; die Zeit läuft nicht weiter. Farbfelder liegen auf der Globus-Basiskarte oder den aktiven fotorealistischen 3D Tiles.", + "Surface wind at 10 m. Approximately 1° global grid. Curves follow the 10 m wind field, lifted 12 km for visibility; display height is not weather altitude. View lighting is for readability. Animation shows flow through one fixed forecast; it does not advance time. Color fields drape the globe basemap or the active photorealistic 3D Tiles.": "Bodenwind in 10 m Höhe. Globales Raster von etwa 1°. Die Kurven folgen dem 10-m-Windfeld, zur Sichtbarkeit 12 km angehoben; die Darstellungshöhe hat keine meteorologische Bedeutung. Die Beleuchtung dient der Lesbarkeit. Die Animation zeigt die Strömung einer festen Vorhersage; die Zeit läuft nicht weiter. Farbfelder liegen auf der Globus-Basiskarte oder den aktiven fotorealistischen 3D Tiles.", "MODEL": "MODELL", "FIELD": "FELD", "UNITS": "EINHEITEN", @@ -2215,7 +2215,7 @@ "LOCATING…": "ORTUNG…", "LOCATED": "GEORTET", "LOCATE": "ORTEN", - " · read while Local ADS-B is on": " · gelesen, solange Lokales ADS-B an ist", + " · read while Local ADS-B is on": " · gelesen, solange „Lokales ADS-B“ an ist", "Decoder feeds: {feeds}": "Decoder-Feeds: {feeds}", "Language: {language}": "Sprache: {language}", "Change the interface language": "Sprache der Oberfläche ändern", @@ -2711,10 +2711,10 @@ "Radio layer unavailable": "Radio-Ebene nicht verfügbar", "Camera navigation is unavailable in the current view": "Kameranavigation ist in der aktuellen Ansicht nicht verfügbar", "Camera navigation policy unavailable": "Richtlinie für die Kameranavigation nicht verfügbar", - "Nearest-aircraft selection supports Flights or Military Flights only": "Die Auswahl des nächsten Luftfahrzeugs unterstützt nur Flüge oder Militärflüge", - "Nearest-aircraft selection needs a preset, place name, or latitude and longitude": "Die Auswahl des nächsten Luftfahrzeugs braucht ein Preset, einen Ortsnamen oder Breite und Länge", + "Nearest-aircraft selection supports Flights or Military Flights only": "Die Auswahl des nächstgelegenen Luftfahrzeugs unterstützt nur „Live-Flüge“ oder „Militärflüge“", + "Nearest-aircraft selection needs a preset, place name, or latitude and longitude": "Die Auswahl des nächstgelegenen Luftfahrzeugs braucht ein Preset, einen Ortsnamen oder Breite und Länge", "Could not arrive at the requested place": "Der angeforderte Ort konnte nicht erreicht werden", - "The nearest airborne aircraft could not be selected": "Das nächste Luftfahrzeug in der Luft konnte nicht ausgewählt werden", + "The nearest airborne aircraft could not be selected": "Das nächstgelegene Luftfahrzeug in der Luft konnte nicht ausgewählt werden", "No flights within {radius} of the current view": "Keine Flüge im Umkreis von {radius} um die Bildmitte", "No military within {radius} of the current view": "Keine Militärflüge im Umkreis von {radius} um die Bildmitte", "No satellites within {radius} of the current view": "Keine Satelliten im Umkreis von {radius} um die Bildmitte", @@ -2754,17 +2754,17 @@ "one": "{count} Kontakt im Bild", "other": "{count} Kontakte im Bild" }, - "Nearest military aircraft": "Nächste Militärluftfahrzeuge", - "Nearest ships": "Nächste Schiffe", - "Nearest satellites": "Nächste Satelliten", - "Nearest aircraft": "Nächste Luftfahrzeuge", + "Nearest military aircraft": "Nächstgelegene Militärluftfahrzeuge", + "Nearest ships": "Nächstgelegene Schiffe", + "Nearest satellites": "Nächstgelegene Satelliten", + "Nearest aircraft": "Nächstgelegene Luftfahrzeuge", "{first} and {second}": "{first} und {second}", "Layer": "Ebene", "there": "dort", "Camera range {range}": "Kameraentfernung {range}", "Within {radius} of the view": "Im Umkreis von {radius} um die Bildmitte", "Labels on": "Beschriftungen an", - "Framing uses the nearest 80 loaded contacts": "Ins Bild genommen werden höchstens die 80 nächsten geladenen Kontakte", + "Framing uses the nearest 80 loaded contacts": "Ins Bild genommen werden höchstens die 80 nächstgelegenen geladenen Kontakte", "{distance} from {location}": "{distance} von {location}", "Altitude {altitude}": "Höhe {altitude}", "{origin} to {destination}": "{origin} nach {destination}", @@ -2780,7 +2780,7 @@ "Not found: {places}": "Nicht gefunden: {places}", "Tracing outlines": "Umrisse werden nachgezeichnet", "Frame flights": "Flüge ins Bild nehmen", - "Frame military": "Militär ins Bild nehmen", + "Frame military": "Militärflüge ins Bild nehmen", "Frame vessels": "Schiffe ins Bild nehmen", "Frame {target}": "{target} ins Bild nehmen", "Zoom out to globe": "Auf den Globus herauszoomen", @@ -2810,8 +2810,8 @@ "Mark {targets}": "{targets} markieren", "Fly to {place}": "Zu {place} fliegen", "Fly to Location": "Zu einem Ort fliegen", - "Nearest aircraft to {place}": "Nächstes Luftfahrzeug bei {place}", - "Nearest aircraft to Here": "Nächstes Luftfahrzeug hier", + "Nearest aircraft to {place}": "Nächstgelegenes Luftfahrzeug bei {place}", + "Nearest aircraft to Here": "Nächstgelegenes Luftfahrzeug hier", "Layer on": "Ebene an", "Layer off": "Ebene aus", "Zoom out": "Herauszoomen", @@ -2825,7 +2825,7 @@ "Flying": "Im Flug", "Turning on layer": "Ebene wird eingeschaltet", "Loading aircraft": "Luftfahrzeuge werden geladen", - "Picking nearest": "Nächstes wird ausgewählt", + "Picking nearest": "Nächstgelegenes wird ausgewählt", "Working": "In Arbeit", "in progress": "läuft", "done": "erledigt", @@ -2858,7 +2858,7 @@ "DIRECTORY: RADIO BROWSER": "VERZEICHNIS: RADIO BROWSER", "Local RTL-SDR receiver": "Lokaler RTL-SDR-Empfänger", "LOCAL RTL-SDR": "LOKALES RTL-SDR", - "Chrome/Edge · WebUSB · one local tuner shared by FM and the Local ADS-B layer.": "Chrome/Edge · WebUSB · ein lokaler Tuner, den UKW und die Ebene Lokales ADS-B gemeinsam nutzen.", + "Chrome/Edge · WebUSB · one local tuner shared by FM and the Local ADS-B layer.": "Chrome/Edge · WebUSB · ein lokaler Tuner, den UKW und die Ebene „Lokales ADS-B“ gemeinsam nutzen.", "Use your location for faster ADS-B position decoding": "Eigenen Standort für schnellere Dekodierung von ADS-B-Positionen verwenden", "CHANGE DEVICE": "GERÄT WECHSELN", "Choose a different RTL-SDR or receiver channel": "Ein anderes RTL-SDR oder einen anderen Empfängerkanal wählen", @@ -2931,7 +2931,7 @@ "ALL": "ALLE", "FLAT": "FLACH", "SINCE": "SEIT", - "Toggle straight-down and tilted map views": "Zwischen senkrechter und geneigter Kartenansicht wechseln", + "Toggle straight-down and tilted map views": "Zwischen senkrechter Ansicht und Schrägansicht wechseln", "Reset map to north up": "Karte nach Norden ausrichten", "Reset map bearing to north": "Kartenausrichtung auf Norden zurücksetzen", "Cyclone request timed out": "Zeitüberschreitung bei der Wirbelsturm-Abfrage", From a96ad30c996407c47c2a764982a3eb7aecd2c413 Mon Sep 17 00:00:00 2001 From: German Khokhlov Date: Wed, 28 Oct 2026 23:47:45 +0400 Subject: [PATCH 44/83] i18n(pt): apply review round 4 Co-Authored-By: Claude Opus 5.5 --- docs/translations/pt.md | 1 + src/i18n/locales/pt.json | 14 +++++++------- 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/docs/translations/pt.md b/docs/translations/pt.md index e71023b31..682c0a3b9 100644 --- a/docs/translations/pt.md +++ b/docs/translations/pt.md @@ -70,6 +70,7 @@ The `many` form is the `other` text with «de» after the number: «{count} de c | AUTO HOP ON / OFF (CCTV) | TROCA AUTO. LIGADA / DESLIG. (as the other CCTV toggles) | | earthquake / active fire | terremoto / incêndio ativo | | advisory (NHC/CPHC cyclone) | boletim | +| E/C Pacific (NHC/CPHC coverage) | Pacífico Leste/Central (no «L/C») | | weather (layer, card) / weather satellite | clima / meteorologia, meteorológico | | FOG / cloud unknown | NEVOEIRO / nebulosidade desconhecida | | AQHI bands Low … Very High | Risco baixo … Risco muito alto | diff --git a/src/i18n/locales/pt.json b/src/i18n/locales/pt.json index 722bc6a74..136d57db2 100644 --- a/src/i18n/locales/pt.json +++ b/src/i18n/locales/pt.json @@ -567,7 +567,7 @@ "No active NHC/CPHC systems": "Nenhum sistema ativo do NHC/CPHC", "Advisories unavailable": "Boletins indisponíveis", "Cyclones · NHC / CPHC": "Ciclones · NHC / CPHC", - "Atlantic · E/C Pacific": "Atlântico · Pacífico L/C", + "Atlantic · E/C Pacific": "Atlântico · Pacífico Leste/Central", "{storms} · {name} selected": "{storms} · {name} selecionado", "Official advisory ↗": "Boletim oficial ↗", "Active NHC and CPHC cyclone advisories": "Boletins de ciclones ativos do NHC e do CPHC", @@ -2197,8 +2197,8 @@ }, "{feed} feed unavailable": "Feed {feed} indisponível", "Source snapshot {minutes} min old": "O snapshot da fonte tem {minutes} min", - "{source} rate limited (anonymous)": "{source}: limite de requisições (anônimo)", - "{source} rate limited": "{source}: limite de requisições", + "{source} rate limited (anonymous)": "{source}: limite de requisições atingido (acesso anônimo)", + "{source} rate limited": "{source}: limite de requisições atingido", "{source} network error": "{source}: erro de rede", "Malformed {source} aircraft rows": "{source}: linhas de aeronaves malformadas", "Malformed {source} response": "{source}: resposta malformada", @@ -2722,7 +2722,7 @@ "CONTACTS · 250 KM": "CONTATOS · 250 KM", "Contact navigation": "Navegação de contatos", "CONTEXT ONLY": "SÓ CONTEXTO", - "Nearby cohort counts": "Contagem de grupos próximos", + "Nearby cohort counts": "Contagens por categoria nas proximidades", "FLT": "FLT", "MIL": "MIL", "SITE": "LOCAIS", @@ -2840,9 +2840,9 @@ "Local RTL-SDR receiver": "Receptor RTL-SDR local", "LOCAL RTL-SDR": "RTL-SDR LOCAL", "Chrome/Edge · WebUSB · one local tuner shared by FM and the Local ADS-B layer.": "Chrome/Edge · WebUSB · um sintonizador local compartilhado entre o FM e a camada ADS-B local.", - "Use your location for faster ADS-B position decoding": "Use sua localização para decodificar as posições ADS-B mais rápido", + "Use your location for faster ADS-B position decoding": "Usar sua localização para decodificar as posições ADS-B mais rápido", "CHANGE DEVICE": "TROCAR", - "Choose a different RTL-SDR or receiver channel": "Escolha outro RTL-SDR ou outro canal do receptor", + "Choose a different RTL-SDR or receiver channel": "Escolher outro RTL-SDR ou outro canal do receptor", "RTL-SDR receiver mode": "Modo do receptor RTL-SDR", "GAIN": "GANHO", "RTL-SDR tuner gain for the current mode": "Ganho do sintonizador RTL-SDR para o modo atual", @@ -2900,7 +2900,7 @@ "Feather": "Suavização", "Scope edge feather": "Suavização da borda da mira", "Scope edge feather as a percentage of the keyhole radius": "Suavização da borda da mira, em porcentagem do raio do visor", - "Draw on the world — click vertices, double-click or Enter to finish, Esc to cancel": "Desenhe sobre o mundo — clique nos vértices, clique duplo ou Enter para concluir, Esc para cancelar", + "Draw on the world — click vertices, double-click or Enter to finish, Esc to cancel": "Desenhar sobre o mundo — clique nos vértices, clique duplo ou Enter para concluir, Esc para cancelar", "Shape": "Forma", "Shape to draw": "Forma a desenhar", "Area": "Área", From d243177d11f9f0cc161ad57f09da5cc3c1a3aa6a Mon Sep 17 00:00:00 2001 From: German Khokhlov Date: Wed, 28 Oct 2026 23:55:16 +0400 Subject: [PATCH 45/83] i18n(uk): apply review round 4 Co-Authored-By: Claude Opus 5.5 --- docs/translations/uk.md | 7 +++++++ src/i18n/locales/uk.json | 44 ++++++++++++++++++++-------------------- 2 files changed, 29 insertions(+), 22 deletions(-) diff --git a/docs/translations/uk.md b/docs/translations/uk.md index b960ab3a9..673748f42 100644 --- a/docs/translations/uk.md +++ b/docs/translations/uk.md @@ -97,3 +97,10 @@ A `tn()` entry needs four forms. `Intl.PluralRules('uk')` picks: | thermal (FLIR-style imaging) | тепловий (not термальний) | | map stack | набір карт | | stage (rocket) re-entry / recovery | вхід ступеня в атмосферу / повернення | +| ON / OFF (toggle chips) | УВІМК. / ВИМК. | +| Clean UI / EXIT CLEAN VIEW | чистий інтерфейс / ПОВЕРНУТИ ІНТЕРФЕЙС | +| full globe view | вигляд всього глобуса | +| inputs (cockpit context chip) | потоки (not вхідні дані) | +| downrange (rocket stage) | дальність | +| resolution (spatial) | роздільна здатність (not роздільність) | +| shared follow expired | посилання на стеження застаріло | diff --git a/src/i18n/locales/uk.json b/src/i18n/locales/uk.json index a7a5f2634..530a91267 100644 --- a/src/i18n/locales/uk.json +++ b/src/i18n/locales/uk.json @@ -99,7 +99,7 @@ "{provider} media: {source}": "Медіа {provider}: {source}", "{provider} · PROVIDER CONTROLS": "{provider} · ВБУДОВАНИЙ ПЛЕЄР", "YOUTUBE {state} · OPEN ORIGINAL": "YOUTUBE {state} · ВІДКРИТИ ОРИГІНАЛ", - "INITIATION": "ЗАРОДЖЕННЯ", + "INITIATION": "ПОЧАТОК", "DAMMING": "ЗАГАТА", "SECONDARY FAILURE": "ПОВТОРНИЙ ЗСУВ", "BORDER ARRIVAL": "ДОСЯГНЕННЯ КОРДОНУ", @@ -778,7 +778,7 @@ "Low-accuracy score < 2%": "Показник неточності < 2%", "Low-accuracy score 2–10%": "Показник неточності 2–10%", "Low-accuracy score > 10%": "Показник неточності > 10%", - "GNSS integrity source unavailable": "Джерело цілісності GNSS недоступне", + "GNSS integrity source unavailable": "Джерело даних про цілісність GNSS недоступне", "Regional sample · 250 nm radius · cells from visited views over 30 min": "Регіональна вибірка · радіус 250 мор. миль · комірки з переглянутих ділянок карти за 30 хв", "Retrying automatically at {time} UTC": "Автоматичний повтор о {time} UTC", "Retrying automatically after provider cooldown": "Автоматичний повтор після паузи постачальника", @@ -829,7 +829,7 @@ "UNSPECIFIED": "НЕ ВКАЗАНО", "+{count} additional payload records": "Додаткові записи корисного навантаження: +{count}", "PAYLOAD DATA UNAVAILABLE": "ДАНІ КОРИСНОГО НАВАНТАЖЕННЯ НЕДОСТУПНІ", - "{value} KM DOWNRANGE": "{value} КМ УЗДОВЖ ТРАСИ", + "{value} KM DOWNRANGE": "ДАЛЬНІСТЬ {value} КМ", "POSITION UNAVAILABLE": "ПОЗИЦІЯ НЕДОСТУПНА", "FLIGHT {count}": "ПОЛІТ {count}", "REUSED": "ПОВТОРНО ВИКОРИСТАНИЙ", @@ -1135,7 +1135,7 @@ "LIVE · Roads: OpenStreetMap · Flow: TomTom · {percent}% cov": "ОНЛАЙН · Дороги: OpenStreetMap · Потік: TomTom · охоплення {percent}%", "SIMULATED · Roads: OpenStreetMap · Flow: TomTom (no matches)": "ІМІТАЦІЯ · Дороги: OpenStreetMap · Потік: TomTom (немає збігів)", "SIMULATED — traffic service unreachable": "ІМІТАЦІЯ — сервіс руху недоступний", - "SIMULATED — add TomTom key for live": "ІМІТАЦІЯ — додайте ключ TomTom для реального часу", + "SIMULATED — add TomTom key for live": "ІМІТАЦІЯ — додайте ключ TomTom для даних у реальному часі", "OpenFreeMap tiles rate-limited": "Тайли OpenFreeMap: перевищено ліміт запитів", "OpenFreeMap tiles timed out": "Тайли OpenFreeMap: минув час очікування", "OpenFreeMap tiles unavailable": "Тайли OpenFreeMap недоступні", @@ -1260,7 +1260,7 @@ "STALE · cached source metadata": "ЗАСТАРІЛО · метадані джерела з кешу", "Map center is outside source coverage": "Центр карти поза зоною покриття джерела", "NOAA/NWS 15-minute lightning density derived from Vaisala NLDN/GLD360. Coverage 110°E across the Pacific/Americas to 0°, 25°S–80°N. Not a live strike count, global coverage or a safety warning.": "15-хвилинна щільність блискавок NOAA/NWS на основі Vaisala NLDN/GLD360. Покриття — від 110° сх. д. через Тихий океан і Америку до 0°, 25° пд. ш.–80° пн. ш. Це не підрахунок розрядів у реальному часі, не глобальне покриття й не попередження про небезпеку.", - "NOAA MRMS radar echoes indicate precipitation patterns, not rain rate, a storm warning or a future forecast. Native source approximately 1 km; display is limited to level 6. Frames use exact advertised observation times.": "Радіолокаційні відлуння NOAA MRMS показують картину опадів, а не їхню інтенсивність, штормове попередження чи прогноз. Вихідна роздільність близько 1 км; показ обмежено рівнем 6. Для кадрів використано точний заявлений час спостережень.", + "NOAA MRMS radar echoes indicate precipitation patterns, not rain rate, a storm warning or a future forecast. Native source approximately 1 km; display is limited to level 6. Frames use exact advertised observation times.": "Радіолокаційні відлуння NOAA MRMS показують картину опадів, а не їхню інтенсивність, штормове попередження чи прогноз. Вихідна роздільна здатність близько 1 км; показ обмежено рівнем 6. Для кадрів використано точний заявлений час спостережень.", "GOES-19/18 longwave infrared Band 14 regional; NESDIS global longwave mosaic. Clouds only dims everything but bright, cold cloud tops; a brightness filter, not a cloud mask. Coverage and freshness differ by region.": "Регіональний довгохвильовий ІЧ-канал 14 GOES-19/18; глобальна довгохвильова мозаїка NESDIS. Режим «Лише хмари» затемнює все, крім яскравих холодних вершин хмар; це фільтр яскравості, а не маска хмарності. Покриття й актуальність різняться за регіонами.", "REGION": "РЕГІОН", "IMAGE": "ЗНІМОК", @@ -1313,7 +1313,7 @@ "Issued: {time}": "Випущено: {time}", "Selected field unavailable · wind remains visible": "Вибране поле недоступне · вітер залишається видимим", "{error} · wind remains visible": "{error} · вітер залишається видимим", - "Surface wind at 10 m. Approximately 1° global grid. Curves follow the 10 m wind field, lifted 12 km for visibility; display height is not weather altitude. View lighting is for readability. Animation shows flow through one fixed forecast; it does not advance time. Color fields drape the globe basemap or the active photorealistic 3D Tiles.": "Приземний вітер на висоті 10 м. Глобальна сітка близько 1°. Лінії повторюють поле вітру на 10 м і підняті на 12 км для наочності; висота показу не є висотою погодних явищ. Освітлення вигляду — для зручності читання. Анімація показує потік в одному фіксованому прогнозі й не зсуває час. Кольорові поля накладаються на підкладку глобуса або на активні фотореалістичні 3D Tiles.", + "Surface wind at 10 m. Approximately 1° global grid. Curves follow the 10 m wind field, lifted 12 km for visibility; display height is not weather altitude. View lighting is for readability. Animation shows flow through one fixed forecast; it does not advance time. Color fields drape the globe basemap or the active photorealistic 3D Tiles.": "Приземний вітер на висоті 10 м. Глобальна сітка близько 1°. Лінії повторюють поле вітру на 10 м і підняті на 12 км для наочності; висота показу не є висотою погодних явищ. Освітлення сцени підібрано для зручності читання. Анімація показує потік в одному фіксованому прогнозі й не зсуває час. Кольорові поля накладаються на підкладку глобуса або на активні фотореалістичні 3D Tiles.", "MODEL": "МОДЕЛЬ", "FIELD": "ПОЛЕ", "UNITS": "ОДИНИЦІ", @@ -1487,7 +1487,7 @@ "Import was not applied. The current project may have changed.": "Імпорт не застосовано. Можливо, поточний проєкт змінився.", "Select a scene and shot first": "Спершу виберіть сцену й кадр", "Edit scene details": "Змінити параметри сцени", - "Camera positions use degrees and meters above the ellipsoid. Drafts are validated before they replace your saved scene.": "Положення камери задаються в градусах і метрах над еліпсоїдом. Перш ніж замінити збережену сцену, чернетку перевіряють.", + "Camera positions use degrees and meters above the ellipsoid. Drafts are validated before they replace your saved scene.": "Положення камери задаються в градусах і метрах над еліпсоїдом. Перш ніж замінити збережену сцену, чернетка проходить перевірку.", "Anchors and data packs": "Якорі й пакети даних", "Shot camera, timing, packs and actions": "Камера кадру, таймінг, пакети й дії", "New anchor ID": "ID нового якоря", @@ -1662,8 +1662,8 @@ "SNOW SHOWERS": "ЗЛИВОВИЙ СНІГ", "THUNDERSTORM": "ГРОЗА", "MIXED CONDITIONS": "ЗМІШАНІ УМОВИ", - "CYCLE ON": "ЦИКЛ УВІМКНЕНО", - "CYCLE OFF": "ЦИКЛ ВИМКНЕНО", + "CYCLE ON": "ЦИКЛ УВІМК.", + "CYCLE OFF": "ЦИКЛ ВИМК.", "Stop automatic page cycling. Previous, Next, and the SIG/NEWS/LOCAL tabs stay available.": "Зупинити автоматичне гортання сторінок. Кнопки ПОПЕР./ДАЛІ та вкладки СИГН./НОВИНИ/МІСЦ. залишаються доступними.", "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.": "Автоматично гортає сторінки брифінгу кожні 9 секунд (Сигнали → Новини → Місцеві дані). Пауза, доки ви наводите вказівник на панель або вона у фокусі. Дані сигналів у реальному часі однаково оновлюються безперервно.", "ACQUIRING REGIONAL NEWS": "ОТРИМАННЯ РЕГІОНАЛЬНИХ НОВИН", @@ -1677,7 +1677,7 @@ "CLOUD UNKNOWN": "ХМАРНІСТЬ НЕВІДОМА", "{source} · LOCATION QUERY": "{source} · ЗАПИТ ЗА РОЗТАШУВАННЯМ", "REGIONAL NEWS": "РЕГІОНАЛЬНІ НОВИНИ", - "{label} · {radius} AIR/SEA WINDOW": "{label} · ПОВІТРЯ/МОРЕ · РАДІУС {radius}", + "{label} · {radius} AIR/SEA WINDOW": "{label} · РЕЙСИ / СУДНА · РАДІУС {radius}", "{scope} · INSTALLATIONS {coverage}": "{scope} · ОБʼЄКТИ: {coverage}", "CONTEXT STANDBY": "КОНТЕКСТ: ОЧІКУВАННЯ", "ENABLE GLOBAL CONTEXT FOR PROXIMITY PINGS": "УВІМКНІТЬ ГЛОБАЛЬНИЙ КОНТЕКСТ, ЩОБ БАЧИТИ КОНТАКТИ ПОБЛИЗУ", @@ -1697,7 +1697,7 @@ "many": "{count} ПОТОКІВ БЕЗ ДАНИХ · НЕ ОЗНАЧАЄ «УСЕ ЧИСТО»", "other": "{count} ПОТОКУ БЕЗ ДАНИХ · НЕ ОЗНАЧАЄ «УСЕ ЧИСТО»" }, - "AVAILABLE INPUTS CURRENT · NOT AN ALL-CLEAR": "ДОСТУПНІ ВХІДНІ ДАНІ АКТУАЛЬНІ · НЕ ОЗНАЧАЄ «УСЕ ЧИСТО»", + "AVAILABLE INPUTS CURRENT · NOT AN ALL-CLEAR": "ДОСТУПНІ ПОТОКИ АКТУАЛЬНІ · НЕ ОЗНАЧАЄ «УСЕ ЧИСТО»", "SQUAWK {code} · {status}": "СКВОК {code} · {status}", "ADS-B PRIORITY · {status}": "ADS-B ПРІОРИТЕТ · {status}", "ADS-B EMERGENCY · {status}": "ADS-B АВАРІЙНИЙ СТАН · {status}", @@ -1947,7 +1947,7 @@ "Press Enter to try again.": "Натисніть Enter, щоб спробувати знову.", "Detailed outline unavailable": "Докладний контур недоступний", "Fly to a POI first": "Спершу полетіть до орієнтира", - "Reset to full globe view": "Скинути до загального вигляду глобуса", + "Reset to full globe view": "Скинути до вигляду всього глобуса", "Reset cockpit to full globe view": "Скинути кабіну до вигляду всього глобуса", "Resetting to full globe view": "Скидання до вигляду всього глобуса", "Resetting cockpit to full globe view": "Скидання кабіни до вигляду всього глобуса", @@ -2023,7 +2023,7 @@ " · degraded directory": " · каталог з перебоями", " · stale directory": " · каталог застарів", " · outside current filter": " · поза поточним фільтром", - "Ready — playback starts only from your action": "Готово — відтворення починається лише за вашою дією", + "Ready — playback starts only from your action": "Готово — відтворення почнеться лише після вашої дії", "Radio off": "Радіо вимкнено", "Connecting directly to broadcaster…": "Пряме зʼєднання з мовником…", "Buffering broadcaster stream…": "Буферизація потоку мовника…", @@ -2046,7 +2046,7 @@ "Newest frame per product": "Найсвіжіший кадр кожного продукту", "Replay observed history": "Відтворити історію спостережень", "Imagery on Esri · Google 3D returns when cleared": "Підкладка: Esri · скидання поверне Google 3D", - "Point the camera at the ground to use the view": "Для видимої області наведіть камеру на землю", + "Point the camera at the ground to use the view": "Наведіть камеру на землю, щоб вибрати видиму область", "That point cannot anchor a box": "Від цієї точки не можна побудувати область", "Imagery stops at ±{limit}° latitude": "Знімки є лише до ±{limit}° широти", "{owner} is using the pointer — close it first": "Вказівник зайнятий: «{owner}». Спершу закрийте його", @@ -2168,9 +2168,9 @@ "Cancel": "Скасувати", "EDIT DETAILS": "ЗМІНИТИ ПАРАМЕТРИ", "SHARE SCENE": "ПОДІЛИТИСЯ СЦЕНОЮ", - "Shared flight follow expired": "Термін стеження за рейсом за посиланням минув", - "Shared military flight follow expired": "Термін стеження за військовим рейсом за посиланням минув", - "Shared satellite follow expired": "Термін стеження за супутником за посиланням минув", + "Shared flight follow expired": "Посилання на стеження за рейсом застаріло", + "Shared military flight follow expired": "Посилання на стеження за військовим рейсом застаріло", + "Shared satellite follow expired": "Посилання на стеження за супутником застаріло", "Shared flight could not be restored — feed unavailable": "Не вдалося відновити рейс за посиланням — потік даних недоступний", "Shared military flight could not be restored — feed unavailable": "Не вдалося відновити військовий рейс за посиланням — потік даних недоступний", "Shared satellite could not be restored — feed unavailable": "Не вдалося відновити супутник за посиланням — потік даних недоступний", @@ -2178,7 +2178,7 @@ "Shared military flight is unavailable": "Військовий рейс за посиланням недоступний", "Shared satellite is unavailable": "Супутник за посиланням недоступний", "entity": "обʼєкт", - "Shared {subject} follow expired": "Стеження за посиланням завершено: {subject}", + "Shared {subject} follow expired": "Посилання на стеження застаріло: {subject}", "Shared {subject} could not be restored — feed unavailable": "Не вдалося відновити за посиланням: {subject} — потік даних недоступний", "Shared {subject} is unavailable": "Недоступно за посиланням: {subject}", "{id} isn't reporting now — showing where it was last seen": "{id} зараз не передає даних — показано останнє відоме місце", @@ -2384,7 +2384,7 @@ "Referenced items": "Згадані обʼєкти", "NOTES & SOURCES": "НОТАТКИ Й ДЖЕРЕЛА", "Show Voice Preview": "Показувати відповіді асистента", - "Voice inactivity timeout": "Тайм-аут бездіяльності голосу", + "Voice inactivity timeout": "Тайм-аут бездіяльності голосового режиму", "Minutes": "хв", "Custom": "Інше", "These preferences stay in this browser.": "Ці налаштування зберігаються в цьому браузері.", @@ -2794,7 +2794,7 @@ "MIL": "ВІЙСЬК.", "SITE": "ОБʼЄКТИ", "NEAREST OBSERVED / MAPPED": "НАЙБЛИЖЧІ СПОСТЕРЕЖЕНІ / НАНЕСЕНІ", - "AVAILABLE INPUTS ONLY · NOT AN ALL-CLEAR": "ЛИШЕ ДОСТУПНІ ВХІДНІ ДАНІ · НЕ ОЗНАЧАЄ «УСЕ ЧИСТО»", + "AVAILABLE INPUTS ONLY · NOT AN ALL-CLEAR": "ЛИШЕ ДОСТУПНІ ПОТОКИ · НЕ ОЗНАЧАЄ «УСЕ ЧИСТО»", "WX": "ПОГОДА", "Cockpit briefing carousel": "Карусель брифінгу кабіни", "Estimated flight plan": "Орієнтовний план польоту", @@ -2995,7 +2995,7 @@ "Sharpening": "Підвищення різкості", "Sharpen": "Різкість", "Sharpen intensity": "Інтенсивність різкості", - "EXIT CLEAN VIEW": "ВИЙТИ З ЧИСТОГО ВИГЛЯДУ", + "EXIT CLEAN VIEW": "ПОВЕРНУТИ ІНТЕРФЕЙС", "Return UI controls": "Повернути елементи керування", "Initializing photorealistic world...": "Ініціалізація фотореалістичного світу...", "DATA LAYERS": "ШАРИ ДАНИХ", @@ -3060,7 +3060,7 @@ "Toggle straight-down and tilted map views": "Перемкнути вигляд карти: згори або з нахилом", "Reset map to north up": "Повернути карту північчю вгору", "Reset map bearing to north": "Скинути азимут карти на північ", - "Reset camera and return to full globe view": "Скинути камеру та повернутися до загального вигляду глобуса", + "Reset camera and return to full globe view": "Скинути камеру та повернутися до вигляду всього глобуса", "MISSION CONTROL · FIRST LAUNCH": "ЦЕНТР КЕРУВАННЯ · ПЕРШИЙ ЗАПУСК", "Choose your first view": "Виберіть, із чого почати", "LIVE CONTACTS": "КОНТАКТИ ОНЛАЙН", From a312414d0b8f8dc6467cd291f1c212d49c36d4d1 Mon Sep 17 00:00:00 2001 From: German Khokhlov Date: Wed, 28 Oct 2026 23:59:04 +0400 Subject: [PATCH 46/83] i18n(fr): apply review round 5 Co-Authored-By: Claude Opus 5.5 --- docs/translations/fr.md | 2 ++ src/i18n/locales/fr.json | 32 ++++++++++++++++---------------- 2 files changed, 18 insertions(+), 16 deletions(-) diff --git a/docs/translations/fr.md b/docs/translations/fr.md index 94f7c3317..e2f506988 100644 --- a/docs/translations/fr.md +++ b/docs/translations/fr.md @@ -52,6 +52,7 @@ The `many` form is the `other` text with « de » (« d' » before a vowel) afte | launch / launch site / space mission | lancement / site de lancement / mission spatiale | | ascent / replay / payload / stage / downrange | ascension / rejeu / charge utile / étage / distance au sol (DIST. SOL) | | contact / tracking / track (HUD) | contact / suivi / piste | +| brackets (HUD corner brackets around contacts) | cadres de ciblage | | installation / site | installation / site | | mapped / observed | cartographié / observé | | camera / CCTV camera / ALPR camera | caméra / caméra CCTV / caméra LAPI | @@ -66,6 +67,7 @@ The `many` form is the `other` text with « de » (« d' » before a vowel) afte | route (directions) / turn (maneuver) | itinéraire / manœuvre | | scene / shot / scene recipe | scène / plan / recette de scène | | bundle / data pack / anchor | archive / paquet de données / ancre | +| import / export (noun: file, scene, project) | importation / exportation (not « import » / « export ») | | capture camera as anchor / set move start (scene editor) | ancre à la position de la caméra / vue actuelle comme départ | | story beat | étape du récit | | briefing / panel / dock | briefing / panneau / dock | diff --git a/src/i18n/locales/fr.json b/src/i18n/locales/fr.json index 02f160c4f..617a63c3b 100644 --- a/src/i18n/locales/fr.json +++ b/src/i18n/locales/fr.json @@ -839,7 +839,7 @@ "LAUNCH TIME · ": "HEURE DE LANCEMENT · ", "ORBIT · ": "ORBITE · ", "ASCENT PATH · ": "TRAJECTOIRE D'ASCENSION · ", - "CURRENT DISTANCE FROM EARTH · ": "DISTANCE ACTUELLE DE LA TERRE · ", + "CURRENT DISTANCE FROM EARTH · ": "DISTANCE ACTUELLE À LA TERRE · ", "SATELLITE SPEED · ": "VITESSE DU SATELLITE · ", "PAYLOAD": "CHARGE UTILE", "NAME": "NOM", @@ -1393,12 +1393,12 @@ "Camera unavailable — exit cockpit first": "Caméra indisponible — quittez d'abord le cockpit", "No shots to run": "Aucun plan à lancer", "Scene transition limit reached — load a shot to reset": "Limite de transitions de scène atteinte — chargez un plan pour réinitialiser", - "Export failed: {error}": "Échec de l'export : {error}", + "Export failed: {error}": "Échec de l'exportation : {error}", "Project exported": "Projet exporté", - "Importing project": "Import du projet", + "Importing project": "Importation du projet", "Imported {file}": "Importé : {file}", - "Import failed: {error}": "Échec de l'import : {error}", - "Import failed (could not read JSON file)": "Échec de l'import (fichier JSON illisible)", + "Import failed: {error}": "Échec de l'importation : {error}", + "Import failed (could not read JSON file)": "Échec de l'importation (fichier JSON illisible)", "Layers refused: {layers}": "Couches refusées : {layers}", "Could not exit {mode} — scene layers may be refused": "Impossible de quitter {mode} — les couches de la scène peuvent être refusées", "Camera move interrupted": "Mouvement de caméra interrompu", @@ -1459,12 +1459,12 @@ "Unavailable layers: {layers}": "Couches indisponibles : {layers}", "Uses registered content or linked media. Those external files are not included in a scene bundle. Their original notices still apply.": "Utilise du contenu enregistré ou des médias liés. Ces fichiers externes ne sont pas inclus dans une archive de scène. Leurs mentions d'origine restent applicables.", "{bytes} bundled bytes verified. Files stay in memory for this session. Reimport the bundle after reloading the app.": "{bytes} octets de l'archive vérifiés. Les fichiers restent en mémoire pour cette session. Réimportez l'archive après avoir rechargé l'application.", - "Review scene import": "Vérifier l'import de scène", + "Review scene import": "Vérifier l'importation de scène", "Nothing is loaded or changed until you apply this file.": "Rien n'est chargé ni modifié tant que vous n'appliquez pas ce fichier.", "Ready to import": "Prêt à importer", - "Apply replaces the current project. Export your current project first if you want to keep both.": "Appliquer remplace le projet actuel. Exportez d'abord votre projet actuel si vous voulez garder les deux.", - "Apply import": "Appliquer l'import", - "Import was not applied. The current project may have changed.": "L'import n'a pas été appliqué. Le projet actuel a peut-être changé.", + "Apply replaces the current project. Export your current project first if you want to keep both.": "L'importation remplacera le projet actuel. Exportez d'abord votre projet actuel si vous voulez garder les deux.", + "Apply import": "Appliquer l'importation", + "Import was not applied. The current project may have changed.": "L'importation n'a pas été appliquée. Le projet actuel a peut-être changé.", "Select a scene and shot first": "Sélectionnez d'abord une scène et un plan", "Edit scene details": "Modifier les détails de la scène", "Camera positions use degrees and meters above the ellipsoid. Drafts are validated before they replace your saved scene.": "Les positions de caméra sont en degrés et en mètres au-dessus de l'ellipsoïde. Les brouillons sont validés avant de remplacer votre scène enregistrée.", @@ -1646,7 +1646,7 @@ "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.": "Faire défiler automatiquement les pages du briefing toutes les 9 secondes (Signaux → Actus → Local). Pause pendant le survol ou quand le panneau a le focus. Les signaux en direct s'actualisent en continu dans les deux cas.", "ACQUIRING REGIONAL NEWS": "ACQUISITION DES ACTUS RÉGIONALES", "REGIONAL NEWS UNAVAILABLE": "ACTUS RÉGIONALES INDISPONIBLES", - "RESOLVING REGION": "RÉSOLUTION DE LA RÉGION", + "RESOLVING REGION": "IDENTIFICATION DE LA RÉGION", "REGION UNAVAILABLE": "RÉGION INDISPONIBLE", "NO RECENT LOCATION MATCHES": "AUCUNE ACTU RÉCENTE POUR CE LIEU", "{domain} · {age}": "{domain} · {age}", @@ -2110,7 +2110,7 @@ "Recent imagery against the basemap divider": "Séparateur imagerie récente / fond de carte", "Recent imagery A and B divider": "Séparateur A / B de l'imagerie récente", "{before} {left} percent, {after} {right} percent": "{before} {left} pour cent, {after} {right} pour cent", - "Export failed · {error}": "Échec de l'export · {error}", + "Export failed · {error}": "Échec de l'exportation · {error}", "Scene action failed": "Échec de l'action sur la scène", "New scene name": "Nom de la nouvelle scène", "Delete scene \"{scene}\" and all shots?": "Supprimer la scène « {scene} » et tous ses plans ?", @@ -2144,8 +2144,8 @@ "Shared military flight is unavailable": "Le vol militaire partagé est indisponible", "Shared satellite is unavailable": "Le satellite partagé est indisponible", "entity": "entité", - "Shared {subject} follow expired": "Le suivi partagé de {subject} a expiré", - "Shared {subject} could not be restored — feed unavailable": "Impossible de restaurer le suivi partagé de {subject} — flux indisponible", + "Shared {subject} follow expired": "Suivi partagé expiré : {subject}", + "Shared {subject} could not be restored — feed unavailable": "Suivi partagé non restauré : {subject} — flux indisponible", "Shared {subject} is unavailable": "Partage indisponible : {subject}", "{id} isn't reporting now — showing where it was last seen": "{id} n'émet pas actuellement — affichage de sa dernière position connue", "{id} isn't reporting now — showing where it was at {time}": "{id} n'émet pas actuellement — affichage de sa position à {time}", @@ -2241,10 +2241,10 @@ "LAST 5 YEARS": "5 DERNIÈRES ANNÉES", "LAST 3 YEARS": "3 DERNIÈRES ANNÉES", "LAST 2 YEARS": "2 DERNIÈRES ANNÉES", - "LAST YEAR": "DERNIÈRE ANNÉE", + "LAST YEAR": "12 DERNIERS MOIS", "LAST 6 MONTHS": "6 DERNIERS MOIS", "LAST 3 MONTHS": "3 DERNIERS MOIS", - "LAST MONTH": "DERNIER MOIS", + "LAST MONTH": "30 DERNIERS JOURS", "LAST {count} DAYS": { "one": "{count} DERNIER JOUR", "many": "{count} DERNIERS JOURS", @@ -2872,7 +2872,7 @@ "Sonar intensity": "Intensité du sonar", "Opacity": "Opacité", "Cyber contact and label opacity": "Opacité des contacts et étiquettes Cyber", - "Minimum opacity for map dots, icons, models, brackets, and labels between sonar passes": "Opacité minimale des points, icônes, modèles, crochets et étiquettes de la carte entre deux balayages du sonar", + "Minimum opacity for map dots, icons, models, brackets, and labels between sonar passes": "Opacité minimale des points, icônes, modèles, cadres de ciblage et étiquettes de la carte entre deux balayages du sonar", "Sector": "Secteur", "Sonar sector width": "Largeur du secteur du sonar", "Detection Overlay (D)": "Surcouche de détection (D)", From d01be22b4452e32230198d48c2540af2f6bdc3b9 Mon Sep 17 00:00:00 2001 From: German Khokhlov Date: Wed, 28 Oct 2026 23:59:22 +0400 Subject: [PATCH 47/83] i18n(de): apply review round 5 Co-Authored-By: Claude Opus 5.5 --- docs/translations/de.md | 1 + src/i18n/locales/de.json | 18 +++++++++--------- 2 files changed, 10 insertions(+), 9 deletions(-) diff --git a/docs/translations/de.md b/docs/translations/de.md index 444d0741f..86032a238 100644 --- a/docs/translations/de.md +++ b/docs/translations/de.md @@ -96,6 +96,7 @@ Keep the verb in agreement: «{count} Station meldet» / «{count} Stationen mel | YOU / THIS / HERE (voice card labels) | EINGABE / DIES / HIER | | click / click to … | anklicken / … klicken | | tap (touch) | Antippen (not «Tipp», which is a hint) | +| press / tap a key | Taste drücken / kurz drücken (never «tippen» for keys) | | tilted view | Schrägansicht | | card (host card) / voice card | Eintrag (in hints), Infokarte / Sprachkarte | | label (on the map) / clear (switch off layers) | Beschriftung / ausschalten (not «löschen») | diff --git a/src/i18n/locales/de.json b/src/i18n/locales/de.json index ea302b7bf..b4cf0d3b1 100644 --- a/src/i18n/locales/de.json +++ b/src/i18n/locales/de.json @@ -144,7 +144,7 @@ "VIEWSHED": "SICHTBEREICH", "CAL {value}": "KAL. {value}", "SRC {value}": "QUELLE {value}", - "{value} CONTEXT": "{value} KONTEXT", + "{value} CONTEXT": "KONTEXT {value}", "Focus fire detection {title}, {details}": "Branderkennung {title} fokussieren, {details}", "{value} conf": "Konf. {value}", "{value} ago": "vor {value}", @@ -155,7 +155,7 @@ "FIRE": "BRAND", "FIRES": "BRÄNDE", "max {value} MW": "max. {value} MW", - "new {value}": "neu {value}", + "new {value}": "zuletzt vor {value}", "just now": "gerade eben", "<1m ago": "vor <1 min", "{count}m ago": "vor {count} min", @@ -372,7 +372,7 @@ "one": "{count} Kamera geladen · CCTV aktivieren", "other": "{count} Kameras geladen · CCTV aktivieren" }, - "Enable CCTV to load camera intersections": "CCTV aktivieren, um Kreuzungen mit Kameras zu laden", + "Enable CCTV to load camera intersections": "CCTV aktivieren, um Kreuzungskameras zu laden", "Enable CCTV to start camera-linked intelligence summaries.": "CCTV aktivieren, um kameragestützte Lagezusammenfassungen zu starten.", "No summary available.": "Keine Zusammenfassung verfügbar.", "loading frames": "Frames werden geladen", @@ -645,7 +645,7 @@ "Voice control — activate to toggle voice; hold Space to speak": "Sprachsteuerung: aktivieren zum Umschalten; Leertaste halten zum Sprechen", "VOICE STANDBY": "SPRACHE STANDBY", "VOICE CONTROL": "SPRACHSTEUERUNG", - "Hold Space to speak · tap Space to activate focused controls": "Leertaste halten zum Sprechen · Leertaste tippen für fokussierte Elemente", + "Hold Space to speak · tap Space to activate focused controls": "Leertaste halten zum Sprechen · kurz drücken, um fokussierte Elemente zu aktivieren", "VOICE SYSTEM ERROR": "SPRACHSYSTEM-FEHLER", "DISMISS": "SCHLIESSEN", "Check microphone permission and network access, then try again.": "Mikrofonberechtigung und Netzwerkzugriff prüfen, dann erneut versuchen.", @@ -1700,7 +1700,7 @@ "occupancy|many seats available": "viele Sitzplätze frei", "occupancy|few seats available": "wenige Sitzplätze frei", "occupancy|standing room only": "nur Stehplätze", - "occupancy|crushed standing room only": "nur noch enge Stehplätze", + "occupancy|crushed standing room only": "nur Stehplätze, dicht gedrängt", "occupancy|full": "voll", "occupancy|not accepting passengers": "keine Fahrgastaufnahme", "occupancy|not boardable": "kein Einstieg möglich", @@ -2000,7 +2000,7 @@ "Import was not applied. The current project may have changed.": "Der Import wurde nicht angewendet. Das aktuelle Projekt hat sich möglicherweise geändert.", "Select a scene and shot first": "Zuerst eine Szene und eine Aufnahme wählen", "Edit scene details": "Szenendetails bearbeiten", - "Camera positions use degrees and meters above the ellipsoid. Drafts are validated before they replace your saved scene.": "Kamerapositionen verwenden Grad und Meter über dem Ellipsoid. Entwürfe werden geprüft, bevor sie die gespeicherte Szene ersetzen.", + "Camera positions use degrees and meters above the ellipsoid. Drafts are validated before they replace your saved scene.": "Kamerapositionen werden in Grad und Metern über dem Ellipsoid angegeben. Entwürfe werden geprüft, bevor sie die gespeicherte Szene ersetzen.", "Anchors and data packs": "Anker und Datenpakete", "Shot camera, timing, packs and actions": "Aufnahme: Kamera, Zeitablauf, Datenpakete und Aktionen", "New anchor ID": "Neue Anker-ID", @@ -2140,7 +2140,7 @@ "other": "{count} Dateien konnten nicht hinzugefügt werden ({name}: {error})" }, "Some KML content was left out.": "Einige KML-Inhalte wurden ausgelassen.", - "Press on the ground, not the sky": "Auf den Boden drücken, nicht auf den Himmel", + "Press on the ground, not the sky": "Auf den Boden klicken, nicht in den Himmel", "Drag to size the box": "Ziehen, um die Größe des Bereichs festzulegen", "light {source} to use your {name} key": "{source} einschalten, um den eigenen {name}-Schlüssel zu nutzen", "light {source}": "{source} einschalten", @@ -2678,7 +2678,7 @@ "the count is a lower bound because at least one layer reached its retained limit.": "die Anzahl ist eine Untergrenze, weil mindestens eine Ebene ihr Speicherlimit erreicht hat.", "{label} off": "{label} aus", "{label} loading": "{label} lädt", - "{label} error": "{label} Fehler", + "{label} error": "{label}: Fehler", "counted the first {returned} loaded records": "die ersten {returned} geladenen Einträge gezählt", "counted {returned} of {total} loaded records": "{returned} von {total} geladenen Einträgen gezählt", "{layers} just turned on — still loading, counts will rise": "{layers} gerade eingeschaltet – Daten werden noch geladen, die Zahlen steigen", @@ -2765,7 +2765,7 @@ "Within {radius} of the view": "Im Umkreis von {radius} um die Bildmitte", "Labels on": "Beschriftungen an", "Framing uses the nearest 80 loaded contacts": "Ins Bild genommen werden höchstens die 80 nächstgelegenen geladenen Kontakte", - "{distance} from {location}": "{distance} von {location}", + "{distance} from {location}": "{distance} von {location} entfernt", "Altitude {altitude}": "Höhe {altitude}", "{origin} to {destination}": "{origin} nach {destination}", "from {origin}": "von {origin}", From 8da577dab7914d8bf7275b53e4b590c8dbbf400f Mon Sep 17 00:00:00 2001 From: German Khokhlov Date: Thu, 29 Oct 2026 00:04:33 +0400 Subject: [PATCH 48/83] i18n(ja): apply review round 4 Co-Authored-By: Claude Opus 5.5 --- docs/translations/ja.md | 4 ++++ src/i18n/locales/ja.json | 38 +++++++++++++++++++------------------- 2 files changed, 23 insertions(+), 19 deletions(-) diff --git a/docs/translations/ja.md b/docs/translations/ja.md index 980a69a3d..2253bdc45 100644 --- a/docs/translations/ja.md +++ b/docs/translations/ja.md @@ -12,6 +12,8 @@ Translation source: abiyeenzo (#913). - Button names cited in running text go in []: [次へ]を使ってください. - No space between Japanese and Latin letters, digits or a `{placeholder}`: 「AIS船舶」, 「Spaceを長押しで話す」, 「{count}件」, 「{name}を表示」. - Two exceptions keep the space: a Japanese label before its value in a readout (「雲量 {pct}%」, 「ステーション {id}」, 「高度 {altitude}」), and the state words in toggles (「CCTV オン」, 「ラジオ オフ」). +- Waiting states are 「X待ち」, not 「Xを待機中」: 「観測データ待ち」, 「進路/予報円は第{number}報待ち」, 「RTL-SDRデバイスの接続待ち…」. 待機中 is for something on standby with no object: 「フィード待機中」, 「音声待機中」. +- Key names keep their own case in running text and hints: Tab, Enter, Space, Esc (「Tabでプレビュー · Enter / Spaceで選択」). Text that CSS upper-cases shows them in capitals, as in English. - Loanwords are katakana with the long-vowel mark, as in Microsoft and Apple style: ユーザー, ブラウザー, ビューアー, プロバイダー, レイヤー, フィルター, モニター, パラメーター. Pick one katakana form per term and keep it (see the glossary). - Product, provider and dataset names stay in Latin script: Google Maps, Cesium ion, OpenSky, CelesTrak, NASA FIRMS, Sentinel-2, KartaView. Google's own product names use Google's Japanese, joined like any Latin word: Googleストリートビュー. Nepal place names in the Bhote Koshi scenes stay in Latin script, as in zh-CN; country and well-known city names are translated (ネパール, 東京, オースティン). @@ -37,6 +39,7 @@ Translation source: abiyeenzo (#913). | LIVE (status) / live data | ライブ / ライブデータ | | SIMULATED | シミュレーション | | stale / degraded / unavailable | 更新遅延 / 性能低下 / 利用不可 | +| cached (status) | キャッシュの(キャッシュの予報) | | PARTIAL (feed state) | 部分的 | | upstream (remote data source) | 配信元 | | retry | 再試行 | @@ -92,6 +95,7 @@ Translation source: abiyeenzo (#913). | WINDOW (search radius around a subject) | 範囲 | | coverage / coverage % / full, partial | カバー範囲 / カバー率(%のみ)/ 全体, 一部 | | pin (Recent Imagery) | 固定 | +| clear day (Recent Imagery) | 雲の少ない日 | | outline / mark (map annotation) | 輪郭 / マーク | | share (a view or link) | 共有 | | import / export (project, presets) | インポート / エクスポート | diff --git a/src/i18n/locales/ja.json b/src/i18n/locales/ja.json index e9f608cdb..d8b2cf4c8 100644 --- a/src/i18n/locales/ja.json +++ b/src/i18n/locales/ja.json @@ -241,7 +241,7 @@ "{reason} — retrying in {seconds}s": "{reason}:{seconds}秒後に再試行", "{reason} — retry pending": "{reason}:再試行待ち", "Zoom in to search mapped installations": "ズームインして、マップ済み施設を検索してください", - "Showing cached mapped sites": "キャッシュ済みのマップ済み施設を表示中", + "Showing cached mapped sites": "キャッシュのマップ済み施設を表示中", "Mapped sites not loaded": "マップ済み施設は未読込です", "Mapped sites loaded": "マップ済み施設を読み込みました", "Military airfield": "軍用飛行場", @@ -333,7 +333,7 @@ "view band|REGIONAL": "地域", "view band|GLOBAL": "全球", "SUMMARY": "概要", - "Awaiting telemetry...": "テレメトリー待機中…", + "Awaiting telemetry...": "テレメトリー待ち…", "REC": "REC", "AIS: --": "AIS: --", "N/A": "不明", @@ -463,7 +463,7 @@ "loading mapped ALPR cameras": "マップ済みのALPRカメラを読み込み中", "No ALPR data for this area — US and Canada only": "この地域のALPRデータはありません(米国とカナダのみ)", "Zoom in to load mapped cameras": "ズームインしてマップ済みのカメラを読み込み", - "Showing cached locations": "キャッシュ済みの位置を表示中", + "Showing cached locations": "キャッシュの位置を表示中", "Coverage limited — zoom in": "カバー範囲が限られています。ズームインしてください", "No ALPR data for this area": "この地域のALPRデータはありません", "None on screen — nearby cameras are outside the view": "画面内になし:周辺のカメラは表示範囲外です", @@ -538,7 +538,7 @@ "Subtropical storm": "亜熱帯暴風雨", "Subtropical depression": "亜熱帯低気圧", "Track and cone match this advisory": "進路と予報円はこの情報と一致しています", - "Track/cone awaiting advisory {number}": "進路/予報円は第{number}報を待機中", + "Track/cone awaiting advisory {number}": "進路/予報円は第{number}報待ち", "Track/cone unavailable": "進路/予報円を取得できません", "Cached advisory · stale source": "キャッシュのサイクロン情報 · ソース更新遅延", "Loading advisories…": "サイクロン情報を読み込み中…", @@ -793,7 +793,7 @@ "UNSPECIFIED": "未指定", "+{count} additional payload records": "追加のペイロード記録 +{count}件", "PAYLOAD DATA UNAVAILABLE": "ペイロードデータなし", - "{value} KM DOWNRANGE": "ダウンレンジ {value} KM", + "{value} KM DOWNRANGE": "ダウンレンジ {value} km", "POSITION UNAVAILABLE": "位置を取得できません", "FLIGHT {count}": "{count}回目の飛行", "REUSED": "再使用", @@ -973,7 +973,7 @@ "Swipe needs a globe map": "スワイプ比較には地球儀マップが必要です", "Imagery stays on Esri · CLEAR to use Google 3D": "画像はEsriのまま · [消去]でGoogle 3Dを使用", "Imagery catalog unavailable": "画像カタログを利用できません", - "Catalog truncated · a newer clear day may exist": "カタログ省略あり · より新しい晴天日がある可能性", + "Catalog truncated · a newer clear day may exist": "カタログ省略あり · より新しい雲の少ない日がある可能性", "{label} catalog unavailable · {detail}": "{label}のカタログを利用できません · {detail}", "Daily overview for today may still be empty until the pass": "今日の日次概観は、衛星の通過まで空の場合があります", "Box and images cleared": "範囲と画像を消去しました", @@ -1065,7 +1065,7 @@ "Hybrid unavailable while the traffic service is unreachable": "交通サービスに接続できない間はハイブリッドを利用できません", "TomTom roads need a TomTom key": "TomTomの道路にはTomTomキーが必要です", "Hybrid needs a TomTom key": "ハイブリッドにはTomTomキーが必要です", - "Local surface still loading": "周辺の路面を読み込み中", + "Local surface still loading": "周辺の道路を読み込み中", "Partial coverage": "一部のみカバー", "Detailed roads unavailable": "詳細な道路を利用できません", "Reduced detail coverage": "詳細データのカバー範囲が限定的", @@ -1134,9 +1134,9 @@ "POS: LIVE": "POS: ライブ", "POS: {time}Z": "POS: {time}Z", "AIS live load failed": "AISライブデータの読み込みに失敗しました", - "awaiting first AIS position…": "最初のAIS位置を待機中…", - "awaiting usable AIS positions…": "利用可能なAIS位置を待機中…", - "awaiting first AIS message…": "最初のAISメッセージを待機中…", + "awaiting first AIS position…": "最初のAIS位置情報待ち…", + "awaiting usable AIS positions…": "利用可能なAIS位置情報待ち…", + "awaiting first AIS message…": "最初のAISメッセージ待ち…", "AISSTREAM_API_KEY not set": "AISSTREAM_API_KEYが設定されていません", "live feed unsupported": "ライブフィード非対応", "connecting to feed…": "フィードに接続中…", @@ -1166,7 +1166,7 @@ "Observed": "観測", "History": "履歴", "Observation unavailable": "観測を利用できません", - "Waiting for observation": "観測を待機中", + "Waiting for observation": "観測データ待ち", "{detail} · synced": "{detail} · 同期済み", "{detail} · nearest": "{detail} · 最も近いフレーム", "RADAR REFLECTIVITY · dBZ": "レーダー反射強度 · dBZ", @@ -1210,9 +1210,9 @@ "View US radar": "米国のレーダーを表示", "View Americas & Pacific": "南北アメリカと太平洋を表示", "View coverage": "カバー範囲を表示", - "{value} strikes/km²/min ×10³ (15-minute density)": "{value}落雷数/km²/分 ×10³(15分間の密度)", - "{value} dBZ radar reflectivity": "{value} dBZレーダー反射強度", - "STALE · cached source metadata": "更新遅延 · キャッシュ済みのソースメタデータ", + "{value} strikes/km²/min ×10³ (15-minute density)": "落雷数 {value}/km²/分 ×10³(15分間の密度)", + "{value} dBZ radar reflectivity": "レーダー反射強度 {value} dBZ", + "STALE · cached source metadata": "更新遅延 · キャッシュのソースメタデータ", "Map center is outside source coverage": "地図の中心がソースのカバー範囲外です", "NOAA/NWS 15-minute lightning density derived from Vaisala NLDN/GLD360. Coverage 110°E across the Pacific/Americas to 0°, 25°S–80°N. Not a live strike count, global coverage or a safety warning.": "Vaisala NLDN/GLD360から算出したNOAA/NWSの15分間雷密度。カバー範囲は東経110°から太平洋・南北アメリカを経て0°まで、南緯25°–北緯80°。リアルタイムの落雷数、全球カバー、安全上の警報ではありません。", "NOAA MRMS radar echoes indicate precipitation patterns, not rain rate, a storm warning or a future forecast. Native source approximately 1 km; display is limited to level 6. Frames use exact advertised observation times.": "NOAA MRMSのレーダーエコーは降水のパターンを示すもので、降水強度、嵐の警報、将来の予報ではありません。元データの解像度は約1 km、表示はズームレベル6までです。各フレームは公表された正確な観測時刻を使用します。", @@ -1460,7 +1460,7 @@ "SDR decoder stopped responding; receiver stopped": "SDRデコーダーが応答しなくなりました。受信機を停止しました", "SDR decoder fell behind; receiver stopped": "SDRデコーダーの処理が追いつきません。受信機を停止しました", "WebUSB requires desktop Chrome or Edge": "WebUSBにはデスクトップ版ChromeまたはEdgeが必要です", - "Waiting for an RTL-SDR device…": "RTL-SDRデバイスを待機中…", + "Waiting for an RTL-SDR device…": "RTL-SDRデバイスの接続待ち…", "Browser audio is suspended; press Connect again to resume it": "ブラウザーの音声が一時停止しています。再開するにはもう一度[接続]を押してください", "RTL-SDR sample stream stopped": "RTL-SDRのサンプルストリームが停止しました", "Switching to {mode}…": "{mode}に切り替え中…", @@ -1815,7 +1815,7 @@ "feed status|stale": "更新遅延", "feed status|unreachable": "接続不可", "feed status|invalid": "無効", - "waiting for IQ": "IQデータ待機中", + "waiting for IQ": "IQデータ待ち", "{count} messages": { "other": "メッセージ {count}件" }, @@ -1990,7 +1990,7 @@ "← → preview · S shows the focused day": "← → でプレビュー · Sで選択中の日を表示", "ZOOM IN": "ズームイン", "Fly in until the view fits the 1,000 km limit": "表示が上限の1,000 kmに収まるまで近づいてください", - "Imagery days, newest first · arrows move, S or A and B pin": "画像のある日(新しい順)· 矢印キーで移動、SまたはA・Bで固定", + "Imagery days, newest first · arrows move, S or A and B pin": "画像のある日(新しい順) · 矢印キーで移動、SまたはA・Bで固定", "On the map": "地図上", "Mode": "モード", "Imagery opacity": "画像の不透明度", @@ -2677,7 +2677,7 @@ "AVAILABLE MISSIONS": "利用可能なミッション", "SELECT A MISSION TO INSPECT": "ミッションを選択して詳細を表示", "LOADING 30-DAY MISSION INDEX": "30日間のミッション一覧を読込中", - "TAB PREVIEWS · ENTER / SPACE SELECTS": "TABでプレビュー · ENTER / SPACEで選択", + "TAB PREVIEWS · ENTER / SPACE SELECTS": "Tabでプレビュー · Enter / Spaceで選択", "Internet radio and local SDR": "インターネットラジオとローカルSDR", "STATION TAG": "局タグ", "Filter stations by station tag": "局タグで局を絞り込み", @@ -2699,7 +2699,7 @@ "Audio connects directly to the broadcaster after you press play. Your IP is visible to that broadcaster.": "再生ボタンを押すと、音声は放送局に直接接続されます。お使いのIPアドレスは放送局側から見えます。", "Local RTL-SDR receiver": "ローカルRTL-SDR受信機", "LOCAL RTL-SDR": "ローカルRTL-SDR", - "Chrome/Edge · WebUSB · one local tuner shared by FM and the Local ADS-B layer.": "Chrome/Edge · WebUSB · 1台のローカルチューナーをFMとローカルADS-Bレイヤーで共有します。", + "Chrome/Edge · WebUSB · one local tuner shared by FM and the Local ADS-B layer.": "Chrome/Edge · WebUSB · FMとローカルADS-Bレイヤーで1台のローカルチューナーを共有します。", "Use your location for faster ADS-B position decoding": "位置情報を使ってADS-Bの位置デコードを高速化", "CHANGE DEVICE": "デバイスを変更", "Choose a different RTL-SDR or receiver channel": "別のRTL-SDRまたは受信チャンネルを選択", From a0c8b6f893e943d0dfeda82b32f78306c17f856e Mon Sep 17 00:00:00 2001 From: German Khokhlov Date: Thu, 29 Oct 2026 14:12:10 +0400 Subject: [PATCH 49/83] i18n(de): translate strings new in main Co-Authored-By: Claude Opus 5.5 --- src/i18n/locales/de.json | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/i18n/locales/de.json b/src/i18n/locales/de.json index b4cf0d3b1..90c504d37 100644 --- a/src/i18n/locales/de.json +++ b/src/i18n/locales/de.json @@ -2935,5 +2935,8 @@ "Reset map to north up": "Karte nach Norden ausrichten", "Reset map bearing to north": "Kartenausrichtung auf Norden zurücksetzen", "Cyclone request timed out": "Zeitüberschreitung bei der Wirbelsturm-Abfrage", - "Malformed cyclone snapshot": "Fehlerhafter Wirbelsturm-Snapshot" + "Malformed cyclone snapshot": "Fehlerhafter Wirbelsturm-Snapshot", + "STALE · Roads: {source} · Flow: cached TomTom tiles": "VERALTET · Straßen: {source} · Verkehrsfluss: TomTom-Kacheln aus dem Cache", + "routing busy — too many routes at once": "Routing-Dienst ausgelastet – zu viele Routen gleichzeitig", + "route proxy error": "Fehler des Routen-Proxys" } From ed26fa12d8fa26e47665e359301f4cf0d2dd7253 Mon Sep 17 00:00:00 2001 From: German Khokhlov Date: Thu, 29 Oct 2026 14:18:40 +0400 Subject: [PATCH 50/83] i18n(fr): translate strings new in main Co-Authored-By: Claude Opus 5.5 --- src/i18n/locales/fr.json | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/i18n/locales/fr.json b/src/i18n/locales/fr.json index 617a63c3b..fd6e62052 100644 --- a/src/i18n/locales/fr.json +++ b/src/i18n/locales/fr.json @@ -585,6 +585,8 @@ "routing service is rate limited": "le service d'itinéraire a atteint sa limite de requêtes", "route leg too long": "tronçon d'itinéraire trop long", "route too long": "itinéraire trop long", + "routing busy — too many routes at once": "service d'itinéraire occupé — trop d'itinéraires à la fois", + "route proxy error": "erreur du proxy d'itinéraire", "{error} — try again in a moment": "{error} — réessayez dans un instant", "Routing is rate limited — try again in a moment": "Limite de requêtes d'itinéraire atteinte — réessayez dans un instant", "Routing unavailable (HTTP {status})": "Itinéraire indisponible (HTTP {status})", @@ -1115,6 +1117,7 @@ "LIVE · Roads: {source} · No flow roads in view": "DIRECT · Routes : {source} · Aucune route avec flux dans la vue", "LIVE · Roads: {source} · Flow {percent}%": "DIRECT · Routes : {source} · Flux {percent} %", "SIMULATED · Roads: {source} · Flow {percent}%": "SIMULÉ · Routes : {source} · Flux {percent} %", + "STALE · Roads: {source} · Flow: cached TomTom tiles": "OBSOLÈTE · Routes : {source} · Flux : tuiles TomTom en cache", "Syncing flow · Roads: OpenStreetMap · Flow: TomTom · Unmatched: simulated": "Synchro du flux · Routes : OpenStreetMap · Flux : TomTom · Non appariées : simulées", "LIVE · Roads: OpenStreetMap · Flow: TomTom · {percent}% cov · Unmatched: simulated": "DIRECT · Routes : OpenStreetMap · Flux : TomTom · couv. {percent} % · Non appariées : simulées", "LIVE · Roads: OpenStreetMap · Flow: TomTom · {percent}% cov": "DIRECT · Routes : OpenStreetMap · Flux : TomTom · couv. {percent} %", From eb76d5265b6946a17fcc838137259d59d49ba0b2 Mon Sep 17 00:00:00 2001 From: German Khokhlov Date: Thu, 29 Oct 2026 14:19:24 +0400 Subject: [PATCH 51/83] i18n(uk): translate strings new in main Co-Authored-By: Claude Opus 5.5 --- src/i18n/locales/uk.json | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/i18n/locales/uk.json b/src/i18n/locales/uk.json index 530a91267..fe0f3ccac 100644 --- a/src/i18n/locales/uk.json +++ b/src/i18n/locales/uk.json @@ -593,6 +593,8 @@ "routing service is rate limited": "перевищено ліміт запитів до сервісу маршрутизації", "route leg too long": "ділянка маршруту надто довга", "route too long": "маршрут надто довгий", + "routing busy — too many routes at once": "сервіс маршрутизації перевантажений — забагато маршрутів одночасно", + "route proxy error": "помилка проксі маршрутизації", "{error} — try again in a moment": "{error} — спробуйте ще раз трохи згодом", "Routing is rate limited — try again in a moment": "Побудова маршруту: перевищено ліміт запитів — спробуйте ще раз трохи згодом", "Routing unavailable (HTTP {status})": "Побудова маршруту недоступна (HTTP {status})", @@ -1130,6 +1132,7 @@ "LIVE · Roads: {source} · No flow roads in view": "ОНЛАЙН · Дороги: {source} · У кадрі немає доріг із потоком", "LIVE · Roads: {source} · Flow {percent}%": "ОНЛАЙН · Дороги: {source} · Потік {percent}%", "SIMULATED · Roads: {source} · Flow {percent}%": "ІМІТАЦІЯ · Дороги: {source} · Потік {percent}%", + "STALE · Roads: {source} · Flow: cached TomTom tiles": "ЗАСТАРІЛО · Дороги: {source} · Потік: тайли TomTom із кешу", "Syncing flow · Roads: OpenStreetMap · Flow: TomTom · Unmatched: simulated": "Синхронізація потоку · Дороги: OpenStreetMap · Потік: TomTom · Без збігів: імітація", "LIVE · Roads: OpenStreetMap · Flow: TomTom · {percent}% cov · Unmatched: simulated": "ОНЛАЙН · Дороги: OpenStreetMap · Потік: TomTom · охоплення {percent}% · Без збігів: імітація", "LIVE · Roads: OpenStreetMap · Flow: TomTom · {percent}% cov": "ОНЛАЙН · Дороги: OpenStreetMap · Потік: TomTom · охоплення {percent}%", From eab96327389db8cf36506ec3c6ca4bd7c2ee4134 Mon Sep 17 00:00:00 2001 From: German Khokhlov Date: Thu, 29 Oct 2026 14:23:04 +0400 Subject: [PATCH 52/83] i18n(ja): translate strings new in main Co-Authored-By: Claude Opus 5.5 --- src/i18n/locales/ja.json | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/i18n/locales/ja.json b/src/i18n/locales/ja.json index d8b2cf4c8..02e49d22a 100644 --- a/src/i18n/locales/ja.json +++ b/src/i18n/locales/ja.json @@ -1085,6 +1085,7 @@ "LIVE · Roads: {source} · No flow roads in view": "ライブ · 道路:{source} · 表示範囲に交通流のある道路なし", "LIVE · Roads: {source} · Flow {percent}%": "ライブ · 道路:{source} · 交通流 {percent}%", "SIMULATED · Roads: {source} · Flow {percent}%": "シミュレーション · 道路:{source} · 交通流 {percent}%", + "STALE · Roads: {source} · Flow: cached TomTom tiles": "更新遅延 · 道路:{source} · 交通流:キャッシュのTomTomタイル", "Syncing flow · Roads: OpenStreetMap · Flow: TomTom · Unmatched: simulated": "交通流を同期中 · 道路:OpenStreetMap · 交通流:TomTom · 未一致:シミュレーション", "LIVE · Roads: OpenStreetMap · Flow: TomTom · {percent}% cov · Unmatched: simulated": "ライブ · 道路:OpenStreetMap · 交通流:TomTom · カバー率 {percent}% · 未一致:シミュレーション", "LIVE · Roads: OpenStreetMap · Flow: TomTom · {percent}% cov": "ライブ · 道路:OpenStreetMap · 交通流:TomTom · カバー率 {percent}%", @@ -2863,5 +2864,7 @@ "Begin with a clean globe": "まっさらな地球儀から始める", "Don't show this again": "今後表示しない", "ESC to dismiss": "Escで閉じる", - "Tip: the GEV MIC button in the dock lets you talk to the map.": "ヒント:ドックの[マイク]ボタンで地図に話しかけられます。" + "Tip: the GEV MIC button in the dock lets you talk to the map.": "ヒント:ドックの[マイク]ボタンで地図に話しかけられます。", + "routing busy — too many routes at once": "ルート検索サービスが混雑しています。同時に要求されたルートが多すぎます", + "route proxy error": "ルート検索プロキシでエラーが発生しました" } From 6c524b229c6640cc12e48e8bb817363063f8bf64 Mon Sep 17 00:00:00 2001 From: German Khokhlov Date: Thu, 29 Oct 2026 14:24:50 +0400 Subject: [PATCH 53/83] i18n(pt): translate strings new in main Co-Authored-By: Claude Opus 5.5 --- src/i18n/locales/pt.json | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/i18n/locales/pt.json b/src/i18n/locales/pt.json index 136d57db2..087aeb106 100644 --- a/src/i18n/locales/pt.json +++ b/src/i18n/locales/pt.json @@ -1115,6 +1115,7 @@ "LIVE · Roads: {source} · No flow roads in view": "AO VIVO · Vias: {source} · Nenhuma via com dados de fluxo na vista", "LIVE · Roads: {source} · Flow {percent}%": "AO VIVO · Vias: {source} · Fluxo: {percent}% cob", "SIMULATED · Roads: {source} · Flow {percent}%": "SIMULADO · Vias: {source} · Fluxo: {percent}% cob", + "STALE · Roads: {source} · Flow: cached TomTom tiles": "DESATUALIZADO · Vias: {source} · Fluxo: blocos do TomTom em cache", "Syncing flow · Roads: OpenStreetMap · Flow: TomTom · Unmatched: simulated": "Sincronizando fluxo · Vias: OpenStreetMap · Fluxo: TomTom · Sem correspondência: simulado", "LIVE · Roads: OpenStreetMap · Flow: TomTom · {percent}% cov · Unmatched: simulated": "AO VIVO · Vias: OpenStreetMap · Fluxo: TomTom · {percent}% cob · Sem correspondência: simulado", "LIVE · Roads: OpenStreetMap · Flow: TomTom · {percent}% cov": "AO VIVO · Vias: OpenStreetMap · Fluxo: TomTom · {percent}% cob", @@ -2404,6 +2405,8 @@ "Gemini voice sessions have a time limit. When a session expires, start voice again for a new conversation.": "As sessões de voz do Gemini têm limite de tempo. Quando uma sessão expirar, inicie a voz de novo para uma nova conversa.", "Stopped by voice": "Parado por voz", "Automatic stop is unavailable for this voice connection.": "A parada automática não está disponível para esta conexão de voz.", + "routing busy — too many routes at once": "serviço de rotas ocupado — rotas demais ao mesmo tempo", + "route proxy error": "erro do proxy de rotas", "Preview is off.": "A prévia está desativada.", "Your choice applies now, but could not be saved.": "Sua escolha vale agora, mas não pôde ser salva.", "WebRTC microphone support unavailable": "Suporte a microfone WebRTC indisponível", From d383f25bb38619985c0f536ca29f250e50ef2f60 Mon Sep 17 00:00:00 2001 From: German Khokhlov Date: Thu, 29 Oct 2026 14:31:34 +0400 Subject: [PATCH 54/83] i18n(it): translate strings new in main Co-Authored-By: Claude Opus 5.5 --- src/i18n/locales/it.json | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/i18n/locales/it.json b/src/i18n/locales/it.json index 269100030..86adc85d4 100644 --- a/src/i18n/locales/it.json +++ b/src/i18n/locales/it.json @@ -583,6 +583,8 @@ "Bike": "In bici", "rate limited": "limite di richieste raggiunto", "routing service is rate limited": "il servizio di percorsi ha raggiunto il limite di richieste", + "routing busy — too many routes at once": "servizio di percorsi occupato: troppi percorsi contemporaneamente", + "route proxy error": "errore del proxy dei percorsi", "route leg too long": "tratta del percorso troppo lunga", "route too long": "percorso troppo lungo", "{error} — try again in a moment": "{error}: riprova tra un momento", @@ -1115,6 +1117,7 @@ "LIVE · Roads: {source} · No flow roads in view": "LIVE · Strade: {source} · Nessuna strada con flusso in vista", "LIVE · Roads: {source} · Flow {percent}%": "LIVE · Strade: {source} · Flusso {percent}%", "SIMULATED · Roads: {source} · Flow {percent}%": "SIMULATO · Strade: {source} · Flusso {percent}%", + "STALE · Roads: {source} · Flow: cached TomTom tiles": "OBSOLETO · Strade: {source} · Flusso: tile TomTom in cache", "Syncing flow · Roads: OpenStreetMap · Flow: TomTom · Unmatched: simulated": "Sincronizzazione flusso · Strade: OpenStreetMap · Flusso: TomTom · Non abbinate: simulate", "LIVE · Roads: OpenStreetMap · Flow: TomTom · {percent}% cov · Unmatched: simulated": "LIVE · Strade: OpenStreetMap · Flusso: TomTom · {percent}% cop. · Non abbinate: simulate", "LIVE · Roads: OpenStreetMap · Flow: TomTom · {percent}% cov": "LIVE · Strade: OpenStreetMap · Flusso: TomTom · {percent}% cop.", From 8b2c6993702d01cfcbf162379171b684c665364e Mon Sep 17 00:00:00 2001 From: Said Turksever Date: Thu, 29 Oct 2026 10:41:58 +0000 Subject: [PATCH 55/83] Remove the Operator HUD layout Display > HUD > Layout and the set_hud voice action now offer Tactical, Minimal and Cyber. The Operator option, its CSS and its QA coverage are removed, and the unused "Operator" translations are pruned. Share-link codes are append-only, so operator keeps its hudVariant code. A link, scene or saved state that names it restores the default Tactical layout. The voice schema pins keep their legacy digests by restoring the retired value before comparing; the full-payload digest is re-derived. --- docs/CURRENT-STATE.md | 11 +++- docs/SHARE-LINK-FORMAT.md | 3 ++ scripts/qa-cockpit-utility.mjs | 4 +- scripts/qa-radio.mjs | 2 +- scripts/qa-scope-hud.mjs | 15 ++---- server/providers/openai/instructions.js | 4 +- src/firstRunExperience.test.mjs | 12 ++--- src/hud.js | 4 +- src/hudLayoutPolicy.js | 7 +-- src/i18n/locales/es.json | 1 - src/i18n/locales/ru.json | 1 - src/i18n/locales/zh-CN.json | 1 - src/i18n/locales/zh-Hant.json | 1 - src/keySetup.test.mjs | 2 +- src/radioMarkup.test.mjs | 7 +-- src/share/viewCodec.test.mjs | 9 ++-- src/ui/applicationShell.js | 2 +- src/ui/cyberPanelDisclosure.test.mjs | 2 +- src/ui/cyberSonarControls.test.mjs | 2 +- src/ui/cyberTheme.test.mjs | 37 +++++++------ src/ui/panelRails.test.mjs | 2 +- src/ui/styles/command-dock-trays.css | 9 +--- src/ui/styles/overlays.css | 71 ++++--------------------- src/ui/styles/responsive.css | 7 --- src/ui/templates/display-controls.html | 1 - src/voice/actionSchemas.test.mjs | 8 +-- 26 files changed, 78 insertions(+), 147 deletions(-) diff --git a/docs/CURRENT-STATE.md b/docs/CURRENT-STATE.md index 146e157d8..bdb0d97f3 100644 --- a/docs/CURRENT-STATE.md +++ b/docs/CURRENT-STATE.md @@ -221,7 +221,7 @@ from 0–200%. OFF disables the slider while retaining its value. HUD layout changes preserve both settings; share links and scenes restore them. The historical missing-`scf` fallback remains 35%; explicit 0% keeps the hard edge. -With Scope OFF, Tactical, Operator and Minimal add text-sized black backplates +With Scope OFF, Tactical and Minimal add text-sized black backplates at 70% opacity behind telemetry, vertical metadata and scene chrome. Original HUD text color, glow and opacity are preserved. Scope OFF brightens the tagline and Active Style label with the shared secondary text color. The title plate @@ -231,6 +231,13 @@ the original HUD presentation; Cyber retains its existing skin. `node scripts/qa-scope-hud.mjs` checks native input, range, layout persistence, restoration and both Scope presentations. `QA_SCREENSHOT_DIR` saves screenshots. +## HUD layouts — October 29, 2026 + +Display > HUD > Layout offers Tactical, Minimal and Cyber; the `set_hud` voice +action accepts the same three. The Operator layout is retired. Share links +keep its enum code so older links still parse, and a link, scene or saved state +that names Operator restores the default Tactical layout. + ## Cyber HUD — September 30, 2026 Display > HUD > Layout includes Cyber, also available through the HUD voice @@ -2927,7 +2934,7 @@ down | auth-failed` (plus the unchanged `missing-key`/`unsupported`) with > corridor). Its minimal Display popover exposes Intel HUD, > Detection, Parameters, and 3D aircraft. During Cockpit, those existing > standard Display controls move into the Cockpit popover and retain their normal -> nested interaction: HUD plus Tactical/Operator/Minimal layout, Detection plus +> nested interaction: HUD plus Tactical/Minimal/Cyber layout, Detection plus > Density/Allocation/Fade/Outside tuning, and 3D plus Proximity/All mode. The > same nodes and state return to the map Display on exit, so Cockpit does not > maintain a second control state. **Detection is owned by the CONTACTS diff --git a/docs/SHARE-LINK-FORMAT.md b/docs/SHARE-LINK-FORMAT.md index cfb6d50fb..6e1129830 100644 --- a/docs/SHARE-LINK-FORMAT.md +++ b/docs/SHARE-LINK-FORMAT.md @@ -129,6 +129,9 @@ table learns its code. A new style's settings are encoded against its own defaults, while a decoder that does not know the style uses Normal's; adding a style also extends the pinned style-defaults table. +`hudVariant` code 1 (`operator`) is retired: the app no longer offers that +layout and restores it as `tactical`. The code stays reserved. + Flag bits (field 9): 0 `bloom`, 1 `sharpen`, 2 `hudVisible`, 3 `celestialRing` (each defaulting by style), 4 `scopeEnabled` (default on). diff --git a/scripts/qa-cockpit-utility.mjs b/scripts/qa-cockpit-utility.mjs index cb3515ed2..a601aa929 100644 --- a/scripts/qa-cockpit-utility.mjs +++ b/scripts/qa-cockpit-utility.mjs @@ -1751,7 +1751,7 @@ try { return state; }, { variantName: variant, kind: openKind }); - for (const variant of ['off', 'minimal', 'tactical', 'operator']) { + for (const variant of ['off', 'minimal', 'tactical']) { for (const kind of ['display', 'radio']) { const state = await desktopState(variant, kind); check( @@ -2081,7 +2081,7 @@ try { await page.screenshot({ path: path.join(shotsDir, `cyber-resize-${height}.png`) }); } } - await page.evaluate(() => window.__godsEyeView.styleManager._setHudVariant('operator')); + await page.evaluate(() => window.__godsEyeView.styleManager._setHudVariant('tactical')); const signalTransition = await page.evaluate(() => { const manager = window.__godsEyeView.styleManager; diff --git a/scripts/qa-radio.mjs b/scripts/qa-radio.mjs index d78c3dbcc..98aa95fda 100644 --- a/scripts/qa-radio.mjs +++ b/scripts/qa-radio.mjs @@ -2159,7 +2159,7 @@ async function main() { recordLayoutStep(); if (index < 4) { if (index < 2) { - hudLayout.value = index === 0 ? 'operator' : 'minimal'; + hudLayout.value = index === 0 ? 'minimal' : 'tactical'; hudLayout.dispatchEvent(new Event('change', { bubbles: true })); } else { hudToggle.click(); diff --git a/scripts/qa-scope-hud.mjs b/scripts/qa-scope-hud.mjs index 7fece45ee..38444ca18 100644 --- a/scripts/qa-scope-hud.mjs +++ b/scripts/qa-scope-hud.mjs @@ -345,7 +345,7 @@ try { (await readScope()).feather === 2, ); await page.click('#scope-toggle'); - for (const layout of ['minimal', 'operator', 'cyber', 'tactical']) { + for (const layout of ['minimal', 'cyber', 'tactical']) { await page.select('#hud-layout-select', layout); const state = await readScope(); check( @@ -395,7 +395,7 @@ try { restored, ); - for (const layout of ['minimal', 'operator', 'tactical']) { + for (const layout of ['minimal', 'tactical']) { await page.select('#hud-layout-select', layout); await page.evaluate(() => window.__godsEyeView.styleManager.applyVisualState({ @@ -429,20 +429,13 @@ try { wrappersTransparent: wrappers.every( (el) => getComputedStyle(el).display === 'contents', ), - operatorFrame: - hud.dataset.variant !== 'operator' || - (getComputedStyle(hud.querySelector('.hud-corner')) - .backgroundColor === 'rgba(0, 0, 0, 0.36)' && - getComputedStyle(hud.querySelector('.hud-top-bar')) - .backgroundImage !== 'none'), }; }); check( `${layout}: Scope ON retains the original presentation without new backplates`, original.markerAbsent && original.unbacked && - original.wrappersTransparent && - original.operatorFrame, + original.wrappersTransparent, original, ); check( @@ -656,7 +649,7 @@ try { }), ); check('narrow HUD text backings stay within the viewport', narrow); - for (const layout of ['minimal', 'operator', 'tactical']) { + for (const layout of ['minimal', 'tactical']) { await page.select('#hud-layout-select', layout); await page.evaluate(() => window.__godsEyeView.styleManager.applyVisualState({ diff --git a/server/providers/openai/instructions.js b/server/providers/openai/instructions.js index c9c4a43b4..c6182eb8c 100644 --- a/server/providers/openai/instructions.js +++ b/server/providers/openai/instructions.js @@ -48,13 +48,13 @@ function realtimeInstructions( 'For visual filter requests, call set_visual_style with one of the allowed style IDs.', 'SHIPS vs STYLES: "vessels" is easily heard as "visuals". "Show me vessels", "turn on vessels", "the vessels", "visuals" or "vestibules" said WITHOUT a style name means the ships layer: set_layer_visibility{layerId:"ais-live-vessels"}, exactly as "ships" or "boats" does. Call set_visual_style only when the user names a style (retro/CRT, surveillance/night vision, thermal, anime, noir, snow, normal) or says filter, effect or look. Never turn on a different data layer (such as fires) for a ships request.', 'Disambiguation table — basemap vs layer vs style: basemap switching requires an explicit stack name — "Bing aerial" means set_map_stack bing-aerial, "aerial with labels" means bing-labels, "OSM"/"road map" means osm, "Esri"/"Esri imagery" means esri-imagery, "Google 3D"/"photorealistic" means photoreal. Any other mention of "satellite" or "satellites" means the satellites DATA LAYER via set_layer_visibility, never a basemap — except "recent/latest satellite imagery" (the recent-imagery layer) and "weather satellite"/clouds (weather-satellite). "surveillance"/"night vision"/"thermal" are visual STYLES via set_visual_style.', - 'HUD requests ("hud on/off", "switch to operator/minimal/tactical/cyber layout") use set_hud. Detection requests ("detection on", "dense mode", "balanced mode", "sparse mode", "set density to 25", "use weighted allocation") use set_detection. Density snaps to 0/25/50/75/100 and derives Sparse/Balanced/Dense; panoptic is a legacy alias for Dense.', + 'HUD requests ("hud on/off", "switch to minimal/tactical/cyber layout") use set_hud. Detection requests ("detection on", "dense mode", "balanced mode", "sparse mode", "set density to 25", "use weighted allocation") use set_detection. Density snaps to 0/25/50/75/100 and derives Sparse/Balanced/Dense; panoptic is a legacy alias for Dense.', 'Cyber sonar requests use set_cyber_sonar: enabled, rings, rangePct, intensityPct (Power), opacityPct, sectorDeg. For settings questions read get_current_view_state.controls.hud.sonar. Sonar is not detection. Do not silently switch themes, reveal the HUD or enable sonar when changing a slider. If the user explicitly requests Cyber plus sonar settings, call set_hud first, wait for success, then set_cyber_sonar. Confirm returned values; mapSweepActive and contactSweepActive distinguish saved settings from active map effects, including in Cockpit or reduced motion. Do not claim visible contacts solely because enabled is true.', 'Bloom/sharpen requests use set_post_processing. Scene requests ("play orbital watch", "stop the scene", "what scenes are there") use control_scene. CCTV camera requests ("next camera", "nearest camera", "select the Congress camera", "show coverage") use control_cctv — the CCTV layer must be enabled first.', 'Radio playback requests use control_radio. "Turn on/start the radio" means action=play; action=enable only reveals Radio markers and must be reserved for explicit "show/enable the Radio layer/markers" requests. After a prepared playback result, briefly confirm any other completed actions and say "Turning on the radio"—never claim it is already playing. The client keeps Radio muted until playback is verified, then closes voice before restoring Radio volume. Examples: "play news near Austin" → select category=news locationId=austin; "play US news" → select category=news country=US; "Radio volume 30" → volume; pause/resume/stop/next/previous use the matching action. Radio selection never moves the camera.', '"Track/follow " (a callsign, ship name, satellite name) uses track_entity. "Take me to the biggest fire" uses track_entity with query "biggest fire" (the fires layer must be enabled). Bare "orbit" means camera orbit of the current landmark. "Stop following/tracking" uses stop_tracking.', '"Show me which planes are overhead"/"frame the ships"/"show me the satellites above" use frame_overhead with the matching target.', - 'Confirmations echo the RESULTING state, never the request: "HUD operator layout", "Density twenty-five percent", "Bing aerial imagery", "Tracking UAL428", "Framed fourteen aircraft". On ok=false, state the failure plainly: "Nothing matched UAL999", "No ships within 120 kilometers". Never claim an action without ok=true in the tool result.', + 'Confirmations echo the RESULTING state, never the request: "HUD minimal layout", "Density twenty-five percent", "Bing aerial imagery", "Tracking UAL428", "Framed fourteen aircraft". On ok=false, state the failure plainly: "Nothing matched UAL999", "No ships within 120 kilometers". Never claim an action without ok=true in the tool result.', 'For destination requests such as "take me to Italy", "go to NYC", or "show me the Eiffel Tower", call fly_to_location. Prefer known city IDs when available; otherwise pass the plain place query.', 'Navigation-only requests ("take me to X", "go to X", "fly to X") are NOT descriptions: call fly_to_location alone and do NOT also call annotate_map, unless the user explicitly asks to mark the place or you go on to explain specific places there. Never drop a point pin on a region-scale natural feature (a mountain range, desert, sea, or forest) — a single point in the middle of the Rockies is meaningless. If the user explicitly asks to mark such a region, prefer type=area.', 'For country and city destinations, omit rangeM so GEV frames the whole country or city in view. For landmarks and buildings, omit rangeM so GEV chooses a close landmark view.', diff --git a/src/firstRunExperience.test.mjs b/src/firstRunExperience.test.mjs index d76a48458..bc9a22894 100644 --- a/src/firstRunExperience.test.mjs +++ b/src/firstRunExperience.test.mjs @@ -1022,14 +1022,10 @@ test('the voice TOOL SCHEMA matches the pinned contract — the mission mapping ); const hudLayout = legacyTools.find((tool) => tool.name === 'set_hud') .parameters.properties.layout; - assert.deepEqual(hudLayout.enum, [ - 'tactical', - 'operator', - 'minimal', - 'cyber', - ]); - // Cyber deliberately adds one layout; first-run missions still change no tools. - hudLayout.enum = hudLayout.enum.filter((layout) => layout !== 'cyber'); + assert.deepEqual(hudLayout.enum, ['tactical', 'minimal', 'cyber']); + // Cyber deliberately adds one layout and Operator was retired; first-run + // missions still change no tools. + hudLayout.enum = ['tactical', 'operator', 'minimal']; const cameraMotion = legacyTools.find((tool) => tool.name === 'move_camera') .parameters.properties.motion; assert.deepEqual(cameraMotion.enum, [ diff --git a/src/hud.js b/src/hud.js index 011b53691..ce432a03f 100644 --- a/src/hud.js +++ b/src/hud.js @@ -9,7 +9,7 @@ import { applicationServices } from './services/application.js'; * real-time at configurable cadences. * * The HUD auto-activates when a military-style shader (NVG, FLIR, CRT) is - * selected and supports three layout variants: tactical, operator, minimal. + * selected and supports the layout variants: tactical, minimal, cyber. * * Color theming is driven by the active shader mode via CSS custom properties. */ @@ -1063,7 +1063,7 @@ export class IntelHUD { * Switch the HUD layout variant. Falls back to `'tactical'` if the * name is unrecognized. Cyber also applies a coordinated skin to the full * application shell; leaving Cyber restores the standard shell tokens. - * @param {string} variantName - One of `'tactical'`, `'operator'`, `'minimal'`, `'cyber'`. + * @param {string} variantName - One of `'tactical'`, `'minimal'`, `'cyber'`. */ setVariant(variantName) { this._variant = normalizeHudLayout(variantName); diff --git a/src/hudLayoutPolicy.js b/src/hudLayoutPolicy.js index 6b3e2287b..81a64b782 100644 --- a/src/hudLayoutPolicy.js +++ b/src/hudLayoutPolicy.js @@ -1,7 +1,2 @@ /** Browser-free layout vocabulary shared by UI and server-side voice tools. */ -export const HUD_LAYOUTS = Object.freeze([ - 'tactical', - 'operator', - 'minimal', - 'cyber', -]); +export const HUD_LAYOUTS = Object.freeze(['tactical', 'minimal', 'cyber']); diff --git a/src/i18n/locales/es.json b/src/i18n/locales/es.json index 696233f86..f1a0a5ad8 100644 --- a/src/i18n/locales/es.json +++ b/src/i18n/locales/es.json @@ -76,7 +76,6 @@ "Layout": "Disposición", "HUD layout": "Disposición del HUD", "Tactical": "Táctica", - "Operator": "De operador", "Minimal": "Mínima", "Detection Overlay (D)": "Superposición de detección (D)", "Detection overlay": "Superposición de detección", diff --git a/src/i18n/locales/ru.json b/src/i18n/locales/ru.json index 8764d9d06..6c2e9d4d7 100644 --- a/src/i18n/locales/ru.json +++ b/src/i18n/locales/ru.json @@ -777,7 +777,6 @@ "Fade": "Затухание", "Outside": "Снаружи", "Tactical": "Тактический", - "Operator": "Операторский", "Minimal": "Минимальный", "HUD layout": "Макет HUD", "Layout": "Макет", diff --git a/src/i18n/locales/zh-CN.json b/src/i18n/locales/zh-CN.json index 2e7db6b8f..044aca844 100644 --- a/src/i18n/locales/zh-CN.json +++ b/src/i18n/locales/zh-CN.json @@ -2616,7 +2616,6 @@ "Layout": "布局", "HUD layout": "HUD 布局", "Tactical": "战术", - "Operator": "操作员", "Minimal": "精简", "Cyber": "赛博", "Sonar": "声呐", diff --git a/src/i18n/locales/zh-Hant.json b/src/i18n/locales/zh-Hant.json index 1477acd51..16705376d 100644 --- a/src/i18n/locales/zh-Hant.json +++ b/src/i18n/locales/zh-Hant.json @@ -2604,7 +2604,6 @@ "Layout": "佈局", "HUD layout": "HUD 佈局", "Tactical": "戰術", - "Operator": "操作員", "Minimal": "精簡", "Cyber": "賽博", "Sonar": "聲吶", diff --git a/src/keySetup.test.mjs b/src/keySetup.test.mjs index e7e6c70ae..013dbbd87 100644 --- a/src/keySetup.test.mjs +++ b/src/keySetup.test.mjs @@ -48,7 +48,7 @@ test('setup placement moves the same button only in Cyber and disconnects on tea chip, ); assert.equal(chip.parentNode, home); - for (const variant of ['cyber', 'operator', 'cyber', 'minimal']) { + for (const variant of ['cyber', 'tactical', 'cyber', 'minimal']) { theme.dataset.uiTheme = variant; notify(); assert.equal(chip.parentNode, variant === 'cyber' ? toolbar : home); diff --git a/src/radioMarkup.test.mjs b/src/radioMarkup.test.mjs index dfe5b4257..a60524b5e 100644 --- a/src/radioMarkup.test.mjs +++ b/src/radioMarkup.test.mjs @@ -206,10 +206,11 @@ test('no unchanged Realtime tool definition drifts silently', () => { .sort((a, b) => a.name.localeCompare(b.name)) .map((tool) => structuredClone(tool)) .filter((tool) => tool.name !== 'set_cyber_sonar'); - // Cyber adds one HUD choice and the sonar tool; retain the existing pin for every legacy field. + // Cyber adds one HUD choice and the sonar tool, and Operator was retired; + // retain the existing pin for every legacy field. const hudLayout = unchanged.find((tool) => tool.name === 'set_hud').parameters.properties.layout; - assert.deepEqual(hudLayout.enum, ['tactical', 'operator', 'minimal', 'cyber']); - hudLayout.enum = hudLayout.enum.filter((layout) => layout !== 'cyber'); + assert.deepEqual(hudLayout.enum, ['tactical', 'minimal', 'cyber']); + hudLayout.enum = ['tactical', 'operator', 'minimal']; // Globe rotation adds one motion and clarifies the two affected descriptions. // Check those edits explicitly, then keep the legacy pin for every other field. const camera = unchanged.find((tool) => tool.name === 'move_camera'); diff --git a/src/share/viewCodec.test.mjs b/src/share/viewCodec.test.mjs index 4ec2b967c..4bd685047 100644 --- a/src/share/viewCodec.test.mjs +++ b/src/share/viewCodec.test.mjs @@ -437,9 +437,12 @@ test('defaults travel as frozen meanings that match today’s app defaults', () assert.equal(defaults.bloomIntensity, BLOOM_INTENSITY_DEFAULT); assert.equal(defaults.bloomVersion, BLOOM_SCALE_VERSION); assert.equal(defaults.hudVariant, HUD_LAYOUTS[0]); - assert.deepEqual(SHARE_VIEW_ENUMS.hudVariant.slice(0, HUD_LAYOUTS.length), [ - ...HUD_LAYOUTS, - ]); + // Codes are append-only: the retired Operator layout keeps its code so old + // links still parse, and the app restores them as Tactical. + assert.deepEqual( + SHARE_VIEW_ENUMS.hudVariant.filter((variant) => variant !== 'operator'), + [...HUD_LAYOUTS], + ); assert.deepEqual(SHARE_VIEW_ENUMS.style, [...VIEW_STYLES]); assert.deepEqual(SHARE_VIEW_ENUMS.mapStack, [...VIEW_MAPS]); assert.deepEqual(SHARE_VIEW_ENUMS.detectionAllocation, [ diff --git a/src/ui/applicationShell.js b/src/ui/applicationShell.js index 4b999a75f..4e29fca4e 100644 --- a/src/ui/applicationShell.js +++ b/src/ui/applicationShell.js @@ -1337,7 +1337,7 @@ export class StyleManager extends ShellFacade { /** * Switches the HUD layout variant. - * @param {'tactical'|'operator'|'minimal'|'cyber'} variantName - Layout variant. + * @param {'tactical'|'minimal'|'cyber'} variantName - Layout variant. * @returns {{ok: boolean, layout?: string, visible?: boolean, error?: string}} */ setHudLayout(variantName) { diff --git a/src/ui/cyberPanelDisclosure.test.mjs b/src/ui/cyberPanelDisclosure.test.mjs index ae0256d4c..e2a666ba5 100644 --- a/src/ui/cyberPanelDisclosure.test.mjs +++ b/src/ui/cyberPanelDisclosure.test.mjs @@ -72,7 +72,7 @@ test('opening already-expanded Radio reveals Context and closes Display', () => }); test('non-Cyber explicit panels and restored preferences retain their existing policy', () => { - for (const theme of ['tactical', 'operator', 'minimal', 'cyber']) { + for (const theme of ['tactical', 'minimal', 'cyber']) { const f = fixture(theme), prior = globalThis.document; globalThis.document = f.doc; try { diff --git a/src/ui/cyberSonarControls.test.mjs b/src/ui/cyberSonarControls.test.mjs index b819d6f3d..7636d76b7 100644 --- a/src/ui/cyberSonarControls.test.mjs +++ b/src/ui/cyberSonarControls.test.mjs @@ -132,7 +132,7 @@ test('rejects the whole invalid request before any mutation', () => { }); test('requires Cyber and preserves off state and every omitted setting', () => { - for (const theme of ['tactical', 'operator', 'minimal']) { + for (const theme of ['tactical', 'minimal']) { const f = fixture(theme); assert.equal(setCyberSonarControls(f.owner, { enabled: true }, f.doc).ok, false); assert.deepEqual(f.calls, []); diff --git a/src/ui/cyberTheme.test.mjs b/src/ui/cyberTheme.test.mjs index 03ee75f08..340dd0204 100644 --- a/src/ui/cyberTheme.test.mjs +++ b/src/ui/cyberTheme.test.mjs @@ -54,7 +54,8 @@ function styleOwner(t, initialVariant = 'cyber') { const hud = { getVariant: () => variant, setVariant: (value) => { - variant = value; + // Normalize like the real HUD so retired layouts fall back. + variant = normalizeHudLayout(value); applyHudUiTheme(root, value); }, setMode: (value) => calls.push(['mode', value]), @@ -131,7 +132,7 @@ test('visual styles retain Cyber through real preset application without droppin test('non-Cyber style presets and explicit HUD choices remain authoritative', (t) => { const { owner, hud, root } = styleOwner(t); - for (const variant of ['tactical', 'operator', 'minimal']) { + for (const variant of ['tactical', 'minimal']) { owner._setHudVariant(variant); assert.equal(hud.getVariant(), variant); assert.equal(root.dataset.uiTheme, undefined); @@ -150,8 +151,8 @@ test('leaving Cyber without a preset choice restores the prior visual preset', ( assert.equal(owner._preCyberStyle, 'noir'); assert.equal(owner._cyberStyleUserSelected, false); - owner._setHudVariant('operator', { applyVisualDefaults: true }); - assert.equal(hud.getVariant(), 'operator'); + owner._setHudVariant('minimal', { applyVisualDefaults: true }); + assert.equal(hud.getVariant(), 'minimal'); assert.equal(owner.activeStyle, 'noir'); assert.equal(owner._preCyberStyle, null); assert.equal(owner._cyberStyleUserSelected, false); @@ -170,8 +171,8 @@ test('a preset explicitly selected in Cyber survives exit and resets for re-entr // Reselecting the active mode must not erase the user's preset intent. owner._setHudVariant('cyber', { applyVisualDefaults: true }); assert.equal(owner._preCyberStyle, 'noir'); - owner._setHudVariant('operator', { applyVisualDefaults: true }); - assert.equal(hud.getVariant(), 'operator'); + owner._setHudVariant('minimal', { applyVisualDefaults: true }); + assert.equal(hud.getVariant(), 'minimal'); assert.equal(owner.activeStyle, 'snow'); assert.equal(owner._preCyberStyle, null); assert.equal(owner._cyberStyleUserSelected, false); @@ -192,7 +193,7 @@ test('an explicit same-value FLIR choice is preserved on Cyber exit', (t) => { owner.setStyle('thermal', { userInitiated: true }); assert.equal(owner.activeStyle, 'thermal'); assert.equal(owner._cyberStyleUserSelected, true); - owner._setHudVariant('operator', { applyVisualDefaults: true }); + owner._setHudVariant('minimal', { applyVisualDefaults: true }); assert.equal(owner.activeStyle, 'thermal'); }); @@ -207,7 +208,7 @@ test('an authoritative same-Cyber reset clears local preset ownership', (t) => { assert.equal(owner.activeStyle, 'snow'); assert.equal(owner._preCyberStyle, null); assert.equal(owner._cyberStyleUserSelected, false); - owner._setHudVariant('operator', { applyVisualDefaults: true }); + owner._setHudVariant('minimal', { applyVisualDefaults: true }); assert.equal(owner.activeStyle, 'snow'); }); @@ -241,9 +242,9 @@ test('Display and voice HUD routes preserve explicit Cyber entry and exit author assert.equal(display.owner.activeStyle, 'thermal'); snowButton.dispatchEvent(new Event('click')); assert.equal(display.owner.activeStyle, 'snow'); - hudLayout.value = 'operator'; + hudLayout.value = 'minimal'; hudLayout.dispatchEvent(new Event('change')); - assert.equal(display.hud.getVariant(), 'operator'); + assert.equal(display.hud.getVariant(), 'minimal'); assert.equal(display.owner.activeStyle, 'snow'); controls.destroy(); @@ -266,9 +267,9 @@ test('Display and voice HUD routes preserve explicit Cyber entry and exit author const selected = await runVoiceAction('set_visual_style', { style: 'snow' }); assert.equal(selected.ok, true); assert.equal(voice.owner.activeStyle, 'snow'); - const exited = await runVoiceAction('set_hud', { layout: 'operator' }); + const exited = await runVoiceAction('set_hud', { layout: 'minimal' }); assert.equal(exited.ok, true); - assert.equal(voice.hud.getVariant(), 'operator'); + assert.equal(voice.hud.getVariant(), 'minimal'); assert.equal(voice.owner.activeStyle, 'snow'); }); @@ -284,7 +285,7 @@ test('scope choice and expanded feather survive every HUD layout and both restor assert.equal(owner._scopeBtn.checked, false); assert.equal(owner._scopeFeatherSlider.disabled, true); assert.equal(owner._scopeFeatherSlider.value, '200'); - for (const layout of ['minimal', 'operator', 'cyber', 'tactical']) { + for (const layout of ['minimal', 'cyber', 'tactical']) { owner._setHudVariant(layout, { applyVisualDefaults: true }); assert.equal(isScopeMaskEnabled(), false, layout); assert.equal(getScopeMaskFeather(), 2, layout); @@ -313,7 +314,7 @@ test('scene and share HUD transitions do not restore a local pre-Cyber preset', assert.equal(owner.activeStyle, 'retro'); assert.equal(owner._preCyberStyle, null); assert.equal(owner._cyberStyleUserSelected, false); - owner._setHudVariant('operator', { applyVisualDefaults: true }); + owner._setHudVariant('minimal', { applyVisualDefaults: true }); assert.equal(owner.activeStyle, 'retro'); owner.setStyle('surveillance'); @@ -342,7 +343,8 @@ test('scene and share restoration override Cyber and preserve restored Cyber par style: 'surveillance', hudVariant: 'operator', }); - assert.equal(hud.getVariant(), 'operator'); + // A link saved with the retired Operator layout restores as Tactical. + assert.equal(hud.getVariant(), 'tactical'); await owner.restoreShareState({ style: 'thermal', hudVariant: 'cyber', @@ -564,8 +566,9 @@ test('Cyber side panels share one width and one framed surface material', () => }); test('Cyber is a canonical HUD layout with a safe Tactical fallback', () => { - assert.deepEqual(HUD_LAYOUTS, ['tactical', 'operator', 'minimal', 'cyber']); + assert.deepEqual(HUD_LAYOUTS, ['tactical', 'minimal', 'cyber']); assert.equal(normalizeHudLayout('CYBER'), 'cyber'); + assert.equal(normalizeHudLayout('operator'), 'tactical'); assert.equal(normalizeHudLayout('unknown'), 'tactical'); }); @@ -597,7 +600,7 @@ test('an explicit transition into Cyber selects FLIR with Ironbow 0.42 once', () ); assert.equal(cyberVisualDefaultsForHudTransition('tactical', 'cyber'), null); assert.equal( - cyberVisualDefaultsForHudTransition('cyber', 'operator', { + cyberVisualDefaultsForHudTransition('cyber', 'minimal', { explicit: true, }), null, diff --git a/src/ui/panelRails.test.mjs b/src/ui/panelRails.test.mjs index 270ba61f5..f144ec0e7 100644 --- a/src/ui/panelRails.test.mjs +++ b/src/ui/panelRails.test.mjs @@ -39,7 +39,7 @@ test('Cyber restores one expanded owner, keeps launchers, and restores other the true, 'layout does not reopen a peer', ); - f.options.hud.variant = 'operator'; + f.options.hud.variant = 'minimal'; f.run(); assert.equal(f.first.classList.contains('collapsed'), false); assert.equal( diff --git a/src/ui/styles/command-dock-trays.css b/src/ui/styles/command-dock-trays.css index 547037de7..e3607a8ce 100644 --- a/src/ui/styles/command-dock-trays.css +++ b/src/ui/styles/command-dock-trays.css @@ -463,17 +463,10 @@ body:not(.ui-clean-view):not(.recording-mode):has( } #intel-hud[data-variant='tactical'] .hud-bottom-left, -#intel-hud[data-variant='tactical'] .hud-bottom-right, -#intel-hud[data-variant='operator'] .hud-bottom-left, -#intel-hud[data-variant='operator'] .hud-bottom-right { +#intel-hud[data-variant='tactical'] .hud-bottom-right { bottom: calc(2vh + 6.5rem); } -#intel-hud[data-variant='operator'] .hud-bottom-bar { - bottom: calc(2vh + 9.8rem); - width: min(48vw, 680px); -} - #intel-hud[data-variant='minimal'] .hud-bottom-left { bottom: calc(2vh + 5.4rem); } diff --git a/src/ui/styles/overlays.css b/src/ui/styles/overlays.css index 7f491439b..f406b1294 100644 --- a/src/ui/styles/overlays.css +++ b/src/ui/styles/overlays.css @@ -303,49 +303,11 @@ display: none; } -#intel-hud[data-variant='operator'] .hud-top-bar, -#intel-hud[data-variant='operator'] .hud-bottom-bar { - display: flex; -} - -#intel-hud[data-variant='operator'] .hud-top-bar { - top: max(10vh, 90px); - left: 50%; - right: auto; - width: min(52vw, 720px); - transform: translateX(-50%); - border-color: rgba(255, 255, 255, 0.24); - background: linear-gradient(90deg, rgba(0, 0, 0, 0.56), rgba(8, 26, 34, 0.5)); - box-shadow: 0 0 24px rgba(0, 255, 255, 0.08); -} - #intel-hud[data-variant='tactical'] .hud-top-left, -#intel-hud[data-variant='tactical'] .hud-top-right, -#intel-hud[data-variant='operator'] .hud-top-left, -#intel-hud[data-variant='operator'] .hud-top-right { +#intel-hud[data-variant='tactical'] .hud-top-right { top: max(14vh, 136px); } -#intel-hud[data-variant='operator'] .hud-bottom-bar { - border-color: rgba(255, 255, 255, 0.2); - background: linear-gradient( - 90deg, - rgba(0, 0, 0, 0.52), - rgba(8, 22, 18, 0.52) - ); -} - -#intel-hud[data-variant='operator'] .hud-corner { - padding: 8px 10px; - border: 1px solid rgba(255, 255, 255, 0.16); - border-radius: 8px; - background: rgba(0, 0, 0, 0.36); -} - -#intel-hud[data-variant='operator'] .hud-bracket { - display: none; -} - #intel-hud[data-variant='minimal'] .hud-top-right, #intel-hud[data-variant='minimal'] .hud-bottom-right, #intel-hud[data-variant='minimal'] .hud-left-edge, @@ -378,11 +340,7 @@ } :root[data-scope-mask='off'] - #intel-hud:is( - [data-variant='minimal'], - [data-variant='operator'], - [data-variant='tactical'] - ) + #intel-hud:is([data-variant='minimal'], [data-variant='tactical']) .hud-readout, :root[data-scope-mask='off']:not([data-ui-theme='cyber']) .scene-text-holdout { background: rgba(0, 0, 0, 0.7); @@ -399,11 +357,7 @@ } :root[data-scope-mask='off'] - #intel-hud:is( - [data-variant='minimal'], - [data-variant='operator'], - [data-variant='tactical'] - ) + #intel-hud:is([data-variant='minimal'], [data-variant='tactical']) .hud-readout { display: block; width: max-content; @@ -413,11 +367,7 @@ } :root[data-scope-mask='off'] - #intel-hud:is( - [data-variant='minimal'], - [data-variant='operator'], - [data-variant='tactical'] - ) + #intel-hud:is([data-variant='minimal'], [data-variant='tactical']) :is(.hud-top-right, .hud-bottom-right) .hud-readout, :root[data-scope-mask='off']:not([data-ui-theme='cyber']) @@ -427,29 +377,26 @@ } /* Preserve glyph opacity without dimming the vertical backplates. */ -:root[data-scope-mask='off'] - #intel-hud:is([data-variant='operator'], [data-variant='tactical']) - .hud-edge { +:root[data-scope-mask='off'] #intel-hud[data-variant='tactical'] .hud-edge { opacity: 1; } :root[data-scope-mask='off'] - #intel-hud:is([data-variant='operator'], [data-variant='tactical']) + #intel-hud[data-variant='tactical'] .hud-edge .hud-readout > * { opacity: 0.5; } -:root[data-scope-mask='off'] #intel-hud[data-variant='operator'] .hud-corner, :root[data-scope-mask='off'] - #intel-hud:is([data-variant='minimal'], [data-variant='operator']) + #intel-hud[data-variant='minimal'] :is(.hud-top-bar, .hud-bottom-bar) { background: transparent; } :root[data-scope-mask='off'] - #intel-hud:is([data-variant='minimal'], [data-variant='operator']) + #intel-hud[data-variant='minimal'] :is(.hud-top-bar, .hud-bottom-bar) { width: fit-content; max-width: calc(100vw - 120px); @@ -457,7 +404,7 @@ } :root[data-scope-mask='off'] - #intel-hud:is([data-variant='minimal'], [data-variant='operator']) + #intel-hud[data-variant='minimal'] :is(.hud-top-bar, .hud-bottom-bar) .hud-readout { overflow: hidden; diff --git a/src/ui/styles/responsive.css b/src/ui/styles/responsive.css index 8278b51a7..001c3ab3a 100644 --- a/src/ui/styles/responsive.css +++ b/src/ui/styles/responsive.css @@ -110,13 +110,6 @@ font-size: 9px; } - #intel-hud[data-variant='operator'] .hud-top-bar { - left: 12px; - right: auto; - width: calc(100vw - 24px); - transform: none; - } - .hud-bottom-bar { bottom: 90px; font-size: 9px; diff --git a/src/ui/templates/display-controls.html b/src/ui/templates/display-controls.html index f6af31127..458a2fcd8 100644 --- a/src/ui/templates/display-controls.html +++ b/src/ui/templates/display-controls.html @@ -15,7 +15,6 @@ Layout diff --git a/src/voice/actionSchemas.test.mjs b/src/voice/actionSchemas.test.mjs index 97e5004b5..e08505146 100644 --- a/src/voice/actionSchemas.test.mjs +++ b/src/voice/actionSchemas.test.mjs @@ -45,7 +45,8 @@ test('the complete Realtime tool payload pins the manifest-generated layer relea // S2 GhostMaps extends the generated layer enums. // Panel adds named voice targets and timeout; shared Panel/Cockpit guidance // is consolidated without changing either feature's arguments. - '9ee82c4214499280c208c93751b19d7b724c81b7727a2d0c6dab0184749fbe15', + // The Operator HUD layout leaves set_hud's layout enum. + '8c3c26336e4820b4b0828ab2bedf70050eca91ea3b0517a62cd8b69ea4fefc92', ); }); @@ -166,9 +167,10 @@ test('all legacy action arguments are byte-identical after removing the delibera delete center.properties[axis].minimum; delete center.properties[axis].maximum; } - // Cyber adds one HUD layout. + // Cyber adds one HUD layout and Operator was retired. const hud = property('set_hud').layout; - hud.enum = hud.enum.filter((layout) => layout !== 'cyber'); + assert.deepEqual(hud.enum, ['tactical', 'minimal', 'cyber']); + hud.enum = ['tactical', 'operator', 'minimal']; // Derived by applying the same removals to the 4b56d0e9 actionSchemas. assert.equal( createHash('sha256').update(JSON.stringify(legacy)).digest('hex'), From e693e665a6a2d83b0524f6e5cd31b792c77c0726 Mon Sep 17 00:00:00 2001 From: Said Turksever Date: Thu, 29 Oct 2026 10:42:38 +0000 Subject: [PATCH 56/83] Add the changelog entry for removing the Operator HUD layout --- changelog.d/1467-remove-operator-hud-layout.md | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 changelog.d/1467-remove-operator-hud-layout.md diff --git a/changelog.d/1467-remove-operator-hud-layout.md b/changelog.d/1467-remove-operator-hud-layout.md new file mode 100644 index 000000000..556d551ee --- /dev/null +++ b/changelog.d/1467-remove-operator-hud-layout.md @@ -0,0 +1,3 @@ +- Remove the Operator HUD layout. Display > HUD > Layout and the HUD voice + action now offer Tactical, Minimal and Cyber; share links, scenes and saved + views that name Operator open in Tactical (asturksever, #1467). From a1d9847976cbaf8a25225f0b284281fa8fc0c161 Mon Sep 17 00:00:00 2001 From: German Khokhlov Date: Thu, 29 Oct 2026 14:47:58 +0400 Subject: [PATCH 57/83] i18n(ja): address code review findings Japanese has no letter case, so the HUD summary keeps units as the catalog writes them (13 km), matching the cockpit and the ja HUD CSS. The ja '{value} KM', '{value} KM/H' and '{value} KM/S' strings are now lower-case like zh-CN. Co-Authored-By: Claude Opus 5.5 --- src/hudLocalityFormat.js | 7 +++++-- src/i18n/ja-hud-units.test.mjs | 22 ++++++++++++++++++++++ src/i18n/locales/ja.json | 6 +++--- src/i18n/same-as-english.json | 3 --- src/i18n/zh-CN-display.test.mjs | 3 +++ 5 files changed, 33 insertions(+), 8 deletions(-) create mode 100644 src/i18n/ja-hud-units.test.mjs diff --git a/src/hudLocalityFormat.js b/src/hudLocalityFormat.js index 697075a82..b9b8c3ea0 100644 --- a/src/hudLocalityFormat.js +++ b/src/hudLocalityFormat.js @@ -8,7 +8,10 @@ import { formatNumber, getLocale, t } from './i18n/index.js'; import { unitLabel } from './ui/unitLabels.js'; import { localizePlaceName } from './ui/placeNames.js'; -/** An upper-case HUD quantity such as `13KM` / `13КМ`, in the active language. */ +/** + * An upper-case HUD quantity such as `13KM` / `13КМ`, in the active language. + * Chinese and Japanese have no case and keep the catalog's `13 km`. + */ export function hudQuantity(value, unit, digits = 0) { const number = formatNumber(value, { useGrouping: false, @@ -16,7 +19,7 @@ export function hudQuantity(value, unit, digits = 0) { maximumFractionDigits: digits, }); const label = unitLabel(unit); - if (getLocale().startsWith('zh-')) + if (/^(zh|ja)(-|$)/.test(getLocale())) return label ? `${number} ${label}` : number; return `${number}${label.toUpperCase()}`; } diff --git a/src/i18n/ja-hud-units.test.mjs b/src/i18n/ja-hud-units.test.mjs new file mode 100644 index 000000000..73568d0ce --- /dev/null +++ b/src/i18n/ja-hud-units.test.mjs @@ -0,0 +1,22 @@ +import test from 'node:test'; +import assert from 'node:assert/strict'; +import { setLocale } from './index.js'; +import { hudQuantity, LOCALIZED_LOCALITY } from '../hudLocalityFormat.js'; +import { formatCockpitDistance } from '../ui/cockpitPresentation.js'; + +// revmain-opus-ja-i1-1: ja has no case, so HUD units keep the catalog case +// (km), as the cockpit already does and docs/translations/ja.md requires. +test('Japanese HUD units keep their case, like the cockpit', () => { + try { + setLocale('ja'); + assert.equal(formatCockpitDistance(14000), '14 km'); + assert.equal(hudQuantity(13, 'km'), '13 km'); + assert.equal(hudQuantity(1.5, 'km', 1), '1.5 km'); + assert.equal( + LOCALIZED_LOCALITY.near({ poi: 'Shibuya', city: 'Tokyo', distKm: 13 }), + 'SHIBUYA(東京)付近 13 km', + ); + } finally { + setLocale('en'); + } +}); diff --git a/src/i18n/locales/ja.json b/src/i18n/locales/ja.json index 02e49d22a..b7c045555 100644 --- a/src/i18n/locales/ja.json +++ b/src/i18n/locales/ja.json @@ -803,8 +803,8 @@ "DATE UNAVAILABLE": "日付不明", "UNSPECIFIED OPERATOR": "運用者未指定", "Select {mission}": "{mission}を選択", - "{value} KM": "{value} KM", - "{value} KM/S": "{value} KM/S", + "{value} KM": "{value} km", + "{value} KM/S": "{value} km/s", "Selected Space Mission": "選択中の宇宙ミッション", "SELECTED SPACE MISSION": "選択中の宇宙ミッション", "Show all missions": "すべてのミッションを表示", @@ -1607,7 +1607,7 @@ "REGION UNAVAILABLE": "地域を取得できません", "NO RECENT LOCATION MATCHES": "この地域の最近のニュースなし", "{domain} · {age}": "{domain} · {age}", - "{value} KM/H": "{value} KM/H", + "{value} KM/H": "{value} km/h", "CLOUD {pct}%": "雲量 {pct}%", "CLOUD UNKNOWN": "雲量不明", "{source} · LOCATION QUERY": "{source} · 位置クエリ", diff --git a/src/i18n/same-as-english.json b/src/i18n/same-as-english.json index 9ee97a600..73443c29e 100644 --- a/src/i18n/same-as-english.json +++ b/src/i18n/same-as-english.json @@ -169,9 +169,6 @@ "{source} HTTP {status}", "{speed} kn", "{type} SPD: {speed} HDG: {heading}", - "{value} KM", - "{value} KM/H", - "{value} KM/S", "ΔE", "ΔN", "▲ {frp} MW" diff --git a/src/i18n/zh-CN-display.test.mjs b/src/i18n/zh-CN-display.test.mjs index b9e55058d..db85662c4 100644 --- a/src/i18n/zh-CN-display.test.mjs +++ b/src/i18n/zh-CN-display.test.mjs @@ -17,6 +17,9 @@ test('Chinese HUD and cockpit units keep their case without spacing coordinates' assert.equal(formatCockpitDistance(14000), '14\u00a0km'); assert.equal(LOCALIZED_LOCALITY.sector({ latDeg: 21.33, lonDeg: -77.5 }), '扇区 21.33N 77.50W'); + setLocale('ja'); + assert.equal(hudQuantity(13, 'km'), '13 km'); + assert.equal(hudQuantity(1.5, 'km', 1), '1.5 km'); setLocale('en'); assert.equal(hudQuantity(0, 'km'), '0KM'); assert.equal(hudQuantity(2069, 'km', 1), '2069.0KM'); From d034e7355d27d3032702c3c91bcfcc942cc8cbc6 Mon Sep 17 00:00:00 2001 From: German Khokhlov Date: Thu, 29 Oct 2026 14:48:09 +0400 Subject: [PATCH 58/83] i18n(fr): address code review findings Localize a pack shot title only for the shot the pack marker binds to that title, so an operator's shot named like a pack shot shows as typed. Markers saved without shotBindings keep the title-only check. Co-Authored-By: Claude Opus 5.5 --- src/scenes/director.test.mjs | 23 ++++++++++++++++++++++- src/scenes/recipes.js | 18 ++++++++++++------ 2 files changed, 34 insertions(+), 7 deletions(-) diff --git a/src/scenes/director.test.mjs b/src/scenes/director.test.mjs index fd8db6149..880c25bdf 100644 --- a/src/scenes/director.test.mjs +++ b/src/scenes/director.test.mjs @@ -17,7 +17,8 @@ import test from 'node:test'; import { LayerLifecycle } from '../data/lifecycle.js'; import { SceneDirector } from './director.js'; import { SCENE_TRACKING_PARAM_KEYS } from './scenePolicy.js'; -import { SCENE_RECIPES, getSceneAppendRecipeById } from './recipes.js'; +import { SCENE_RECIPES, displayShotTitle, getSceneAppendRecipeById } from './recipes.js'; +import { setLocale } from '../i18n/index.js'; const NEPAL_ORIGINAL_SHOT_TITLES = [ 'Global Incident Context', @@ -2019,3 +2020,23 @@ test('a caught run failure resolves as run-failed, not success (#971)', async () ); } finally { console.warn = warn; await director.destroy(); restore(); } }); + +test('a user shot whose title matches an applied pack title keeps the typed title', () => { + const { director, restore } = makeDirector({ project: legacyThreeShotNepalProjectFixture() }); + try { + const scene = director._project.scenes[0]; + setLocale('ru'); + // The bootstrap-rebuilt shot (no sourcePackId, bound by the pack marker) still localizes. + const bootstrap = scene.shots[0]; + assert.equal(bootstrap.sourcePackId, undefined); + assert.notEqual(displayShotTitle(bootstrap.title, bootstrap, scene), bootstrap.title); + // A shot the operator added and named like a pack shot shows as typed. + for (const title of ['Final view', 'Global Incident Context']) { + const userShot = { id: `user-shot-${title}`, title }; + assert.equal(displayShotTitle(title, userShot, scene), title); + } + } finally { + setLocale('en'); + restore(); + } +}); diff --git a/src/scenes/recipes.js b/src/scenes/recipes.js index 0bb1d9e94..963dbde6c 100644 --- a/src/scenes/recipes.js +++ b/src/scenes/recipes.js @@ -1069,7 +1069,7 @@ export function displaySceneTitle(scene) { export function displayShotTitle(title, shot = undefined, scene = undefined) { const text = typeof title === 'string' ? title : ''; const fromRecipe = shot - ? Boolean(shot.sourcePackId) || recipeDeclaresShotTitle(scene, text) + ? Boolean(shot.sourcePackId) || recipeDeclaresShotTitle(scene, text, shot) : true; if (fromRecipe && BUILTIN_SHOT_TITLES.has(text)) return t(text); const numbered = /^Shot ([1-9]\d*)$/.exec(text); @@ -1080,9 +1080,11 @@ export function displayShotTitle(title, shot = undefined, scene = undefined) { * Whether the built-in recipe behind a scene, or a shot pack applied to it, * declares a shot with this title. A pack's legacy bootstrap rebuilds the * first shots of an upgraded scene without a sourcePackId, so the pack's - * required titles vouch for them. + * required titles vouch for them: through the marker's shotBindings when it + * has them, so an operator's shot named like a pack shot stays as typed, and + * by title alone for markers saved before bindings. */ -function recipeDeclaresShotTitle(scene, title) { +function recipeDeclaresShotTitle(scene, title, shot) { const recipe = scene?.id ? getSceneRecipeById(scene.id) : null; if (recipe?.cameraPath?.some((keyframe) => keyframe?.title === title)) return true; @@ -1090,8 +1092,12 @@ function recipeDeclaresShotTitle(scene, title) { ? scene.appliedShotPacks : []; return packs.some((entry) => - Boolean( - getSceneAppendRecipeById(entry?.id)?.requiredShotTitles?.includes(title), - ), + entry?.shotBindings + ? entry.shotBindings[title] === shot?.id + : Boolean( + getSceneAppendRecipeById(entry?.id)?.requiredShotTitles?.includes( + title, + ), + ), ); } From eab345a46534d42109439781525d886e84899fec Mon Sep 17 00:00:00 2001 From: German Khokhlov Date: Thu, 29 Oct 2026 14:50:08 +0400 Subject: [PATCH 59/83] i18n(pt): address code review findings A pack marker with shotBindings now vouches only for the shot bound to a legacy bootstrap title, so a user shot typed with the same title keeps its text instead of showing the localized built-in name. Co-Authored-By: Claude Opus 5.5 --- src/scenes/recipes.js | 16 ++++++++----- src/scenes/sceneTitleDisplay.test.mjs | 16 +++++++++++++ src/scenes/shotTitleProvenance.test.mjs | 30 +++++++++++++++++++++++++ 3 files changed, 56 insertions(+), 6 deletions(-) create mode 100644 src/scenes/shotTitleProvenance.test.mjs diff --git a/src/scenes/recipes.js b/src/scenes/recipes.js index 348579744..aa10648e4 100644 --- a/src/scenes/recipes.js +++ b/src/scenes/recipes.js @@ -1070,7 +1070,7 @@ export function displaySceneTitle(scene) { export function displayShotTitle(title, shot = undefined, scene = undefined) { const text = typeof title === 'string' ? title : ''; const fromRecipe = shot - ? Boolean(shot.sourcePackId) || recipeDeclaresShotTitle(scene, text) + ? Boolean(shot.sourcePackId) || recipeDeclaresShotTitle(scene, text, shot) : true; if (fromRecipe && BUILTIN_SHOT_TITLES.has(text)) return t(text); const numbered = /^Shot ([1-9]\d*)$/.exec(text); @@ -1081,8 +1081,10 @@ export function displayShotTitle(title, shot = undefined, scene = undefined) { * Whether the built-in recipe behind a scene declares a shot with this title: * its own keyframes, or the legacy base shots an applied append pack wrote * (those carry no sourcePackId, see SceneDirector._bootstrapLegacyShotPacks). + * A pack marker with shotBindings vouches only for the shot bound to the + * title, so a later shot typed with the same title stays as typed. */ -function recipeDeclaresShotTitle(scene, title) { +function recipeDeclaresShotTitle(scene, title, shot) { const declares = (cameraPath) => Boolean(cameraPath?.some((keyframe) => keyframe?.title === title)); const recipe = scene?.id ? getSceneRecipeById(scene.id) : null; @@ -1090,9 +1092,11 @@ function recipeDeclaresShotTitle(scene, title) { const packs = Array.isArray(scene?.appliedShotPacks) ? scene.appliedShotPacks : []; - return packs.some((entry) => - declares( - getSceneAppendRecipeById(entry?.id)?.legacySceneBootstrap?.cameraPath, - ), + return packs.some( + (entry) => + declares( + getSceneAppendRecipeById(entry?.id)?.legacySceneBootstrap?.cameraPath, + ) && + (!entry.shotBindings || entry.shotBindings[title] === shot?.id), ); } diff --git a/src/scenes/sceneTitleDisplay.test.mjs b/src/scenes/sceneTitleDisplay.test.mjs index 2a9aad9f9..972ac9702 100644 --- a/src/scenes/sceneTitleDisplay.test.mjs +++ b/src/scenes/sceneTitleDisplay.test.mjs @@ -163,4 +163,20 @@ test('legacy base shots of an applied append pack show their built-in names', as assert.notEqual(displayShotTitle(title), title); // Without the pack marker the same title in another scene stays as typed. assert.equal(displayShotTitle(title, shot, { id: 'scene-user' }), title); + // A marker with shotBindings still localizes the shot bound to the title + // (a typed one stays as typed: shotTitleProvenance.test.mjs). + const boundScene = { + id: 'bhote-koshi-nepal-scene', + appliedShotPacks: [ + { + id: pack.id, + version: pack.version, + shotBindings: { [title]: shot.id }, + }, + ], + }; + assert.equal( + displayShotTitle(title, shot, boundScene), + displayShotTitle(title), + ); }); diff --git a/src/scenes/shotTitleProvenance.test.mjs b/src/scenes/shotTitleProvenance.test.mjs new file mode 100644 index 000000000..c75108a96 --- /dev/null +++ b/src/scenes/shotTitleProvenance.test.mjs @@ -0,0 +1,30 @@ +// A user-made shot (no sourcePackId) typed as a legacy bootstrap title keeps +// its text even though its scene carries the evidence-pack marker. +import test from 'node:test'; +import assert from 'node:assert/strict'; +import { SCENE_APPEND_RECIPES, displayShotTitle } from './recipes.js'; +import { setLocale } from '../i18n/index.js'; + +test.afterEach(() => setLocale('en')); + +test('a new user shot typed as a bootstrap title keeps its text in a pack scene', () => { + setLocale('ru'); + const pack = SCENE_APPEND_RECIPES.find( + (recipe) => recipe.legacySceneBootstrap?.cameraPath?.length, + ); + assert.ok(pack); + const title = 'Global Incident Context'; + const scene = { + id: 'bhote-koshi-nepal-scene', + appliedShotPacks: [ + { + id: pack.id, + version: pack.version, + // The bootstrap binds this title to the original base shot. + shotBindings: { [title]: 'legacy-base-1' }, + }, + ], + }; + const userShot = { id: 'shot-user-new', title }; // no sourcePackId + assert.equal(displayShotTitle(title, userShot, scene), title); +}); From 0e45bcdf14df1bad02ed31d523ee445e986e2314 Mon Sep 17 00:00:00 2001 From: German Khokhlov Date: Thu, 29 Oct 2026 14:52:45 +0400 Subject: [PATCH 60/83] i18n(de): address code review findings Localize a legacy Nepal base shot only when the applied pack marker binds that title to this exact shot id, so a user shot renamed to a built-in title stays as typed in every locale. Co-Authored-By: Claude Opus 5.5 --- src/scenes/recipes.js | 27 ++++++------- src/scenes/sceneTitleDisplay.test.mjs | 17 ++++++++- src/scenes/shotTitleProvenance.test.mjs | 51 +++++++++++++++++++++++++ 3 files changed, 80 insertions(+), 15 deletions(-) create mode 100644 src/scenes/shotTitleProvenance.test.mjs diff --git a/src/scenes/recipes.js b/src/scenes/recipes.js index 081fa1db4..a5938af40 100644 --- a/src/scenes/recipes.js +++ b/src/scenes/recipes.js @@ -1071,7 +1071,7 @@ export function displayShotTitle(title, shot = undefined, scene = undefined) { const fromRecipe = shot ? Boolean(shot.sourcePackId) || recipeDeclaresShotTitle(scene?.id, text) || - shotPackDeclaresBaseTitle(scene, text) + shotPackBindsShot(scene, text, shot) : true; if (fromRecipe && BUILTIN_SHOT_TITLES.has(text)) return t(text); const numbered = /^Shot ([1-9]\d*)$/.exec(text); @@ -1079,21 +1079,22 @@ export function displayShotTitle(title, shot = undefined, scene = undefined) { } /** - * Whether a shot pack that upgraded this scene declares the title for one of - * its legacy base shots. The upgrade rebuilds those shots without a - * sourcePackId (see SceneDirector._bootstrapLegacyShotPacks), so the pack's - * own shots in the scene vouch for them. - * @param {{shots?: Array<{sourcePackId?: string}>}} [scene] + * Whether a shot pack applied to this scene binds this title to this exact + * shot. The legacy upgrade rebuilds the base shots without a sourcePackId + * (see SceneDirector._bootstrapLegacyShotPacks), but the pack marker records + * their ids, so a user shot that only shares the title is not vouched for. + * @param {{appliedShotPacks?: Array<{shotBindings?: Object}>}} [scene] * @param {string} title + * @param {{id?: string}} shot * @returns {boolean} */ -function shotPackDeclaresBaseTitle(scene, title) { - const shots = Array.isArray(scene?.shots) ? scene.shots : []; - return SCENE_APPEND_RECIPES.some( - (pack) => - pack.legacySceneBootstrap?.cameraPath?.some( - (keyframe) => keyframe?.title === title, - ) && shots.some((item) => item?.sourcePackId === pack.id), +function shotPackBindsShot(scene, title, shot) { + const packs = Array.isArray(scene?.appliedShotPacks) + ? scene.appliedShotPacks + : []; + return ( + Boolean(shot?.id) && + packs.some((pack) => pack?.shotBindings?.[title] === shot.id) ); } diff --git a/src/scenes/sceneTitleDisplay.test.mjs b/src/scenes/sceneTitleDisplay.test.mjs index a5d157e64..f7e626ccc 100644 --- a/src/scenes/sceneTitleDisplay.test.mjs +++ b/src/scenes/sceneTitleDisplay.test.mjs @@ -151,12 +151,25 @@ test('the base shots of a scene the Nepal pack upgraded localize', () => { setLocale('de'); const title = pack.legacySceneBootstrap.cameraPath[0].title; const base = { id: 'shot-base', title }; + // A user shot renamed to the same built-in title is not the bound one. + const renamed = { id: 'shot-user', title }; const upgraded = { id: 'scene-upgraded', - shots: [base, { id: 'shot-pack', title: 'x', sourcePackId: pack.id }], + shots: [ + base, + { id: 'shot-pack', title: 'x', sourcePackId: pack.id }, + renamed, + ], + appliedShotPacks: [ + { id: pack.id, version: 1, shotBindings: { [title]: base.id } }, + ], }; - assert.equal(displayShotTitle(title, base, upgraded), displayShotTitle(title)); + assert.equal( + displayShotTitle(title, base, upgraded), + displayShotTitle(title), + ); assert.notEqual(displayShotTitle(title), title); + assert.equal(displayShotTitle(title, renamed, upgraded), title); // The same title in a scene no pack touched stays as typed. assert.equal( displayShotTitle(title, base, { id: 'scene-user', shots: [base] }), diff --git a/src/scenes/shotTitleProvenance.test.mjs b/src/scenes/shotTitleProvenance.test.mjs new file mode 100644 index 000000000..8edd877cd --- /dev/null +++ b/src/scenes/shotTitleProvenance.test.mjs @@ -0,0 +1,51 @@ +// Reproduction: a user-authored shot whose typed title equals a legacy base +// title of the Nepal pack must stay as typed in an upgraded scene. +import test from 'node:test'; +import assert from 'node:assert/strict'; +import { SCENE_APPEND_RECIPES, displayShotTitle } from './recipes.js'; +import { setLocale } from '../i18n/index.js'; + +test.afterEach(() => setLocale('en')); + +test('a user shot named like a legacy base shot stays as typed in an upgraded scene', () => { + const pack = SCENE_APPEND_RECIPES.find( + (recipe) => recipe.legacySceneBootstrap?.cameraPath?.length, + ); + assert.ok(pack, 'Nepal append pack with legacy bootstrap'); + const baseTitles = pack.legacySceneBootstrap.cameraPath.map((k) => k.title); + // Shape written by SceneDirector._bootstrapLegacyShotPacks + appendShotPack: + // base shots without sourcePackId, pack shots with it, marker bindings. + const base = baseTitles.map((title, i) => ({ id: `base-${i}`, title })); + const packShot = { + id: 'pack-0', + title: 'Upper Valley Collapse', + sourcePackId: pack.id, + }; + // Captured by captureShot ("Shot 10"), then renamed by the user. + const userShot = { id: 'user-1', title: 'Bhote Koshi Flood Path' }; + const scene = { + id: 'scene-user-upgraded', + shots: [...base, packShot, userShot], + appliedShotPacks: [ + { + id: pack.id, + version: Number(pack.version) || 1, + shotBindings: Object.fromEntries(base.map((s) => [s.title, s.id])), + }, + ], + }; + for (const locale of ['de', 'ru', 'es']) { + setLocale(locale); + // The real base shot localizes (intended by the branch). + assert.notEqual( + displayShotTitle(base[5].title, base[5], scene), + base[5].title, + ); + // The user's shot must stay as typed. + assert.equal( + displayShotTitle(userShot.title, userShot, scene), + userShot.title, + `${locale}: user-typed title was translated`, + ); + } +}); From f8e96e1484afe1bce4644b008a3f319c3f27b6ef Mon Sep 17 00:00:00 2001 From: German Khokhlov Date: Thu, 29 Oct 2026 14:54:44 +0400 Subject: [PATCH 61/83] i18n(it): address code review findings Localize a bootstrap shot title without a source pack only when the Nepal pack marker binds that title to the shot's id, so an operator shot renamed to a bootstrap title in the built-in scene stays as typed. Co-Authored-By: Claude Opus 5.5 --- src/scenes/bootstrapTitleProvenance.test.mjs | 20 +++++++++++++++ src/scenes/director.test.mjs | 4 +++ src/scenes/recipes.js | 27 ++++++++++++++------ src/scenes/sceneTitleDisplay.test.mjs | 16 ++++++++++-- 4 files changed, 57 insertions(+), 10 deletions(-) create mode 100644 src/scenes/bootstrapTitleProvenance.test.mjs diff --git a/src/scenes/bootstrapTitleProvenance.test.mjs b/src/scenes/bootstrapTitleProvenance.test.mjs new file mode 100644 index 000000000..0d402dbbd --- /dev/null +++ b/src/scenes/bootstrapTitleProvenance.test.mjs @@ -0,0 +1,20 @@ +import test from 'node:test'; +import assert from 'node:assert/strict'; +import { SCENE_RECIPES, displayShotTitle } from './recipes.js'; +import { setLocale } from '../i18n/index.js'; + +test('an operator-typed title in the built-in Nepal scene stays as typed', () => { + const scene = SCENE_RECIPES.find((r) => r.id === 'bhote-koshi-nepal-scene'); + assert.ok(scene, 'built-in bootstrap scene exists'); + for (const locale of ['ru', 'es', 'it', 'zh-CN', 'zh-Hant']) { + setLocale(locale); + const title = 'Global Incident Context'; + // A shot captured by the operator: no sourcePackId, renamed to this title. + const shown = displayShotTitle( + title, + { id: 'shot-user', title }, + { id: scene.id }, + ); + assert.equal(shown, title, `${locale}: got ${shown}`); + } +}); diff --git a/src/scenes/director.test.mjs b/src/scenes/director.test.mjs index fd8db6149..7b59507be 100644 --- a/src/scenes/director.test.mjs +++ b/src/scenes/director.test.mjs @@ -712,6 +712,10 @@ test('a legacy three-shot Nepal browser project bootstraps to the current 25-sho assert.deepEqual(scene.shots.slice(0, 3).map(({ camera }) => camera), originalCameras); assert.equal(scene.appliedShotPacks[0].id, 'bhote-koshi-nepal-evidence-pack'); assert.equal(scene.appliedShotPacks[0].version, 18); + // displayShotTitle trusts these bindings to localize the bootstrap shots. + for (const shot of scene.shots.slice(0, 8)) { + assert.equal(scene.appliedShotPacks[0].shotBindings[shot.title], shot.id); + } assert.equal(director._selectedSceneId, scene.id); assert.equal(director._selectedShotId, scene.shots[0].id); } finally { diff --git a/src/scenes/recipes.js b/src/scenes/recipes.js index 1a886c541..37eed431b 100644 --- a/src/scenes/recipes.js +++ b/src/scenes/recipes.js @@ -1061,33 +1061,44 @@ export function displaySceneTitle(scene) { * (`sourcePackId`), so a typed title that matches a built-in one stays as * typed. Without `shot`, the title alone decides. * @param {string} title - * @param {{sourcePackId?: string}} [shot] - * @param {{id?: string}} [scene] The shot's scene, for projects saved before - * shots recorded their source pack. + * @param {{id?: string, sourcePackId?: string}} [shot] + * @param {{id?: string, appliedShotPacks?: Array<{id?: string, shotBindings?: Object}>}} [scene] + * The shot's scene, for projects saved before shots recorded their source + * pack. * @returns {string} */ export function displayShotTitle(title, shot = undefined, scene = undefined) { const text = typeof title === 'string' ? title : ''; const fromRecipe = shot - ? Boolean(shot.sourcePackId) || recipeDeclaresShotTitle(scene?.id, text) + ? Boolean(shot.sourcePackId) || recipeDeclaresShotTitle(scene, shot, text) : true; if (fromRecipe && BUILTIN_SHOT_TITLES.has(text)) return t(text); const numbered = /^Shot ([1-9]\d*)$/.exec(text); return numbered ? t('Shot {n}', { n: numbered[1] }) : text; } -/** Whether the built-in recipe behind a scene declares a shot with this title. */ -function recipeDeclaresShotTitle(sceneId, title) { - const recipe = sceneId ? getSceneRecipeById(sceneId) : null; +/** Whether the built-in recipe behind a scene declares this shot's title. */ +function recipeDeclaresShotTitle(scene, shot, title) { + const recipe = scene?.id ? getSceneRecipeById(scene.id) : null; if (!recipe) return false; const declares = (path) => Array.isArray(path) && path.some((keyframe) => keyframe?.title === title); if (declares(recipe.cameraPath)) return true; // A bootstrap recipe seeds legacy "Shot N" keyframes; the upgrade replaces // them with the append recipe's bootstrap shots, which carry no source pack. + // The pack marker binds each of those titles to its shot id, so a shot the + // operator later gave the same title stays as typed. return SCENE_APPEND_RECIPES.some( (append) => append.legacySceneBootstrap?.targetSceneTitle === recipe.title && - declares(append.legacySceneBootstrap.cameraPath), + declares(append.legacySceneBootstrap.cameraPath) && + Boolean(shot?.id) && + (Array.isArray(scene.appliedShotPacks) + ? scene.appliedShotPacks + : [] + ).some( + (marker) => + marker?.id === append.id && marker.shotBindings?.[title] === shot.id, + ), ); } diff --git a/src/scenes/sceneTitleDisplay.test.mjs b/src/scenes/sceneTitleDisplay.test.mjs index 758800137..c476a2000 100644 --- a/src/scenes/sceneTitleDisplay.test.mjs +++ b/src/scenes/sceneTitleDisplay.test.mjs @@ -155,11 +155,23 @@ test('bootstrap shots of a built-in scene localize without a source pack', () => ); if (!scene) return; for (const { title } of bootstrap.cameraPath) { - // The upgrade copies these keyframes into the scene without sourcePackId. + // The upgrade copies these keyframes into the scene without sourcePackId + // and binds each title to its shot in the pack marker. + const upgraded = { + id: scene.id, + appliedShotPacks: [ + { id: append.id, version: 1, shotBindings: { [title]: 'shot-old' } }, + ], + }; assert.equal( - displayShotTitle(title, { id: 'shot-old', title }, { id: scene.id }), + displayShotTitle(title, { id: 'shot-old', title }, upgraded), displayShotTitle(title), ); + // Another shot the operator gave the same title stays as typed. + assert.equal( + displayShotTitle(title, { id: 'shot-user', title }, upgraded), + title, + ); // The same title in an operator's own scene stays as typed. assert.equal( displayShotTitle(title, { id: 'shot-user', title }, { id: 'scene-user' }), From 39a60b4034e12e572897c8095c3d22809fa57201 Mon Sep 17 00:00:00 2001 From: Said Turksever <28983926+asturksever@users.noreply.github.com> Date: Thu, 29 Oct 2026 11:20:49 +0000 Subject: [PATCH 62/83] Remove the Snow visual preset Snow is no longer offered anywhere a style can be chosen: the Visual Presets tray, keyboard shortcut 7, the Cockpit vision carousel, and the set_visual_style voice action. The shader and its labels go with it; weather snowfall and the SNOW weather condition are unaffected. Share links keep working. Snow's enum code (6) stays reserved, so a compact or long-form link that names it opens on Normal and drops the Snow shader parameters without reporting them as unknown. A Scene Director shot saved with Snow plays on Normal too. Snow's frozen share defaults matched Normal's apart from those parameters, so no other setting in an old link changes meaning. The legacy voice-schema pins restore Snow before hashing, so the unchanged pins still prove nothing else moved; the complete Realtime payload digest is re-derived. --- README.md | 2 +- docs/CURRENT-STATE.md | 14 ++-- docs/PERFORMANCE.md | 3 +- docs/SHARE-LINK-FORMAT.md | 64 ++++++++-------- scripts/format-scope.json | 1 - scripts/package-boundaries.json | 5 -- scripts/qa-cockpit-utility.mjs | 34 ++++----- scripts/qa-map-source-tray.mjs | 16 ++-- scripts/qa-visual-effects.mjs | 1 - server/providers/openai/instructions.js | 2 +- src/celestialRing.test.mjs | 2 +- src/cockpitMarkup.test.mjs | 2 +- src/cockpitVisionPolicy.js | 3 - src/cockpitVisionPolicy.test.mjs | 3 +- src/data/trafficPresetStyle.js | 2 +- src/data/trafficPresetStyle.test.mjs | 2 +- src/data/transitPresetStyle.js | 2 +- src/data/transitPresetStyle.test.mjs | 1 - src/firstRunExperience.test.mjs | 13 ++++ src/hud.js | 1 - src/i18n/locales/es.json | 2 - src/i18n/locales/ru.json | 2 - src/i18n/locales/zh-CN.json | 2 - src/i18n/locales/zh-Hant.json | 2 - src/radioMarkup.test.mjs | 13 ++++ src/share/legacyShareState.test.mjs | 7 ++ src/share/viewCodec.js | 15 ++-- src/share/viewCodec.test.mjs | 28 ++++++- src/styles/snow.js | 97 ------------------------- src/ui/applicationShell.js | 2 +- src/ui/applicationShortcuts.js | 1 - src/ui/cockpitInstruments.js | 2 - src/ui/cyberTheme.test.mjs | 46 +++++++----- src/ui/scenePresentation.js | 1 - src/ui/styles/cyber.css | 6 -- src/ui/templates/command-dock.html | 5 -- src/ui/visualEffects.test.mjs | 8 +- src/ui/visualInput.test.mjs | 4 +- src/ui/visualPresets.js | 9 ++- src/ui/visualSettings.js | 7 +- src/view/index.js | 1 - src/voice/actionSchemas.js | 10 +-- src/voice/actionSchemas.test.mjs | 15 +++- src/voice/gevActions.js | 1 - 44 files changed, 200 insertions(+), 259 deletions(-) delete mode 100644 src/styles/snow.js diff --git a/README.md b/README.md index 0a7509efa..ceb66787a 100644 --- a/README.md +++ b/README.md @@ -61,7 +61,7 @@ Start with the included data sources, then add your own. Each layer is a separat - **🎯 Click-to-track anything:** Camera locks on, draws a fading trail, surfaces full metadata — and a tracked fire or vessel hands you off to the nearest live camera in one click. - **🖊️ Voice whiteboard:** Speak annotations onto the world — real boundary polygons, marks, and routes. - **🛫 3D hangar:** Real per-class aircraft models — 787, ATR-72, Citation, Bell 206, MQ-9 — and a tracked contact swaps from glyph to 3D model as you close in. -- **🎨 Reskin reality:** GLSL sensor looks over the normal globe — CRT, NVG, FLIR/thermal, Noir, Snow. +- **🎨 Reskin reality:** GLSL sensor looks over the normal globe — CRT, NVG, FLIR/thermal, Noir. - **🟩 Detection overlay:** Screen-space bounding boxes and IDs on everything in view. - **🎖️ Military HUD:** Tactical heads-up display with intelligence-style telemetry. - **🌐 Global Context:** Stage the full situational picture with one switch — and get your exact view back when you leave. diff --git a/docs/CURRENT-STATE.md b/docs/CURRENT-STATE.md index 146e157d8..690024d28 100644 --- a/docs/CURRENT-STATE.md +++ b/docs/CURRENT-STATE.md @@ -1392,8 +1392,8 @@ and sharpen. Display supplies actions and renders settings; effect execution has no DOM dependency. Existing presets and the 500 ms transition remain unchanged. Stopping the controller revokes animation before asynchronous UI teardown; final destruction removes its stages and restores the borrowed bloom configuration. -Snow's sideways sway stays within a fixed range at any session age; Wind scales -its amplitude. +Snow is no longer a visual preset. A share link that names it, in either the +long or compact form, opens on Normal and drops the Snow shader parameters. Sharpen runs only when enabled with intensity above 0.001. At slider zero its stage is disabled; raising the slider resumes it when sharpen is enabled. @@ -2831,7 +2831,7 @@ down | auth-failed` (plus the unchanged `missing-key`/`unsupported`) with > failed searches leave the current camera owner untouched, and Context Focus > can return to the preserved Contact. Focus also restores the selected > aircraft's canonical follow frame after a manual zoom-away. -> Visual presets retain the order Normal, CRT, NVG, FLIR, Anime, Noir, Snow. +> Visual presets retain the order Normal, CRT, NVG, FLIR, Anime, Noir. > Configurable preset selection—including same-style reselection—opens the > shared Parameters surface directly below Detection and scrolls it into > view; share-link restoration @@ -2883,7 +2883,7 @@ down | auth-failed` (plus the unchanged `missing-key`/`unsupported`) with > Inside Cockpit, the focused summary card is titled Contact in both visible > copy and its accessible control labels. > The top-center Cockpit vision cycle is the fixed, duplicate-free sequence -> Normal, CRT, NVG, FLIR, Anime, Noir, and Snow. Entry selects the map preset +> Normal, CRT, NVG, FLIR, Anime, and Noir. Entry selects the map preset > already in use, so a FLIR map opens on the existing FLIR item while > Normal remains available exactly once. NONE is not offered. Cockpit choices > temporarily override the map preset, while Exit Cockpit and Reset both restore @@ -5172,8 +5172,8 @@ and unreachable upstream (502/504) separately from road geometry. first, activates the Contacts sub-view, and returns the settled 250 km window. Its `aircraft` count is the exact civilian-plus-military total when both feeds can answer, or `unknown` when either component is unavailable. -- Cockpit's top vision switch cycles all seven map looks: Normal, CRT, NVG, - FLIR, Anime, Noir, and Snow. Entry selects the matching map style without adding +- Cockpit's top vision switch cycles all six map looks: Normal, CRT, NVG, + FLIR, Anime, and Noir. Entry selects the matching map style without adding a duplicate carousel item. There is no empty `NONE` entry. ### Live AIS Vessels (June 2026) @@ -5659,7 +5659,7 @@ apply to `public/` assets or built-preview serving. - **Cockpit left-panel clearance:** the Cockpit Contact card and peripheral HUD participate in the adaptive left accordion's live obstacle measurements, including live viewport-height changes. Expanding Layers or Scenes keeps the active panel in the available upper-left corridor with internal scrolling; it does not cover the Contact card, lower Cockpit controls, or Cesium credit line. Outside Cockpit the hidden card does not alter the normal corridor. - **Cockpit Context scope:** the 250 km radius applies to the air/sea proximity cohorts. Installation counts come only from the currently loaded viewport and are labeled `CURRENT VIEWPORT ONLY` in the cockpit as well as the normal Context panel; neither surface presents them as a complete 250 km installation survey. - **Cockpit camera anchor:** first-person mode does not write feed-boundary corrections directly into the camera. A cockpit-only inertial anchor advances from the selected aircraft's displayed course and speed, then converges toward the authoritative delayed track with correction capped below forward motion. The displayed kinematics are derived from the same consecutive fix segment as the rendered position, with raw feed speed/course used only as fallback; a transient zero/missing feed speed therefore cannot freeze a visibly moving aircraft after layer enable or a map/cockpit handoff. Rendered altitude continues to come from that interpolated track position. Late ADS-B fixes and short render stalls can remove drift without accelerating or reversing the view. Camera placement runs before scene update/culling at a bounded 20 Hz so a moving cockpit does not force Photoreal 3D Tiles to retraverse on every display frame; textual instruments update at 10 Hz and context/layout work at 4 Hz. Every far Cockpit contact pip shares one stable Cesium texture-atlas entry and skips unused screen-projected course calculations, while only in-range 2D aircraft silhouettes pay the screen-projected rotation cost; ambient glTF collections are hidden/retained rather than synchronously destroyed at cockpit entry, and context rails lay out only on explicit content/state changes and viewport resize. The deliberate 15/30-second layer interpolation delays and per-Cesium-frame position caches remain unchanged. -- **Cockpit route, vision, and view controls:** visible on-screen `COCKPIT`, `RESET`, and `EXIT COCKPIT` controls replace reliance on the `C` shortcut. RESET uses the same canonical globe route as the map and voice actions, exits Cockpit, and releases its camera ownership rather than exposing the hidden map-style top action. When the tracked commercial flight has a plausible ADSBDB route, the top of the right briefing rail shows a compact `FROM → TO` airport strip and the visor shows a centered estimated-destination chevron with its relative bearing; its destination label rounds to whole degrees in 000–359, wrapping rounded north to 000° while the chevron continues to use the relative bearing independently of label rounding; absent or implausible route data hides the strip and cue rather than guessing. The cockpit-local vision control is an interactive `PREV / CURRENT / NEXT` carousel over `NORMAL`, `CRT`, `NVG`, `FLIR`, `ANIME`, `NOIR`, and `SNOW`; its previous/next actions wrap, and activating the current value advances to the next style. Cockpit enters on the active map preset, so a Cyber FLIR map opens Cockpit on FLIR while Normal remains a distinct option instead of producing a second FLIR entry. Cockpit choices temporarily activate the existing Cesium post-process stages, while exiting Cockpit through either EXIT or RESET restores the pre-entry map style. The regional-news page uses a free Google News RSS locality query first, with the existing GDELT query retained only as a fail-soft fallback; linked headlines remain reporting, not verified incidents or risk intelligence. +- **Cockpit route, vision, and view controls:** visible on-screen `COCKPIT`, `RESET`, and `EXIT COCKPIT` controls replace reliance on the `C` shortcut. RESET uses the same canonical globe route as the map and voice actions, exits Cockpit, and releases its camera ownership rather than exposing the hidden map-style top action. When the tracked commercial flight has a plausible ADSBDB route, the top of the right briefing rail shows a compact `FROM → TO` airport strip and the visor shows a centered estimated-destination chevron with its relative bearing; its destination label rounds to whole degrees in 000–359, wrapping rounded north to 000° while the chevron continues to use the relative bearing independently of label rounding; absent or implausible route data hides the strip and cue rather than guessing. The cockpit-local vision control is an interactive `PREV / CURRENT / NEXT` carousel over `NORMAL`, `CRT`, `NVG`, `FLIR`, `ANIME`, and `NOIR`; its previous/next actions wrap, and activating the current value advances to the next style. Cockpit enters on the active map preset, so a Cyber FLIR map opens Cockpit on FLIR while Normal remains a distinct option instead of producing a second FLIR entry. Cockpit choices temporarily activate the existing Cesium post-process stages, while exiting Cockpit through either EXIT or RESET restores the pre-entry map style. The regional-news page uses a free Google News RSS locality query first, with the existing GDELT query retained only as a fail-soft fallback; linked headlines remain reporting, not verified incidents or risk intelligence. - Cockpit wind-direction labels wrap after rounding to whole degrees, so a direction of 359.5° displays as `N · 0°` rather than `N · 360°`. - **Cockpit missing observations:** missing local weather observations remain unknown rather than being converted to zero or clear skies, in the briefing and in the cloud effects; a missing temperature drops the whole local weather record, including its wind and condition. - **Cockpit weather status:** the earlier multi-canvas atmospheric compositor remains fail-closed and is not attached to the live viewer. Cockpit clouds are a separate transparent WebGL pass with a capped 520×320 framebuffer, 24 ray steps, three FBM octaves, and a 12 FPS ceiling. It defaults off and starts only when local storage explicitly contains the persisted `WX ON` opt-in (`'1'`). When opted in, observations refresh after five minutes or 25 km of aircraft movement, fail transparent when unavailable or clear, and stop on exit or disable. `WX OFF` governs atmospheric rendering only: the briefing still fetches source-backed Natural Earth region, headline, and Open-Meteo local-information data, aborting and replacing any in-flight request when the selected aircraft changes. No weather effect runs in map mode and no synthetic fallback is shown. diff --git a/docs/PERFORMANCE.md b/docs/PERFORMANCE.md index 65d0abae9..7bf6d3751 100644 --- a/docs/PERFORMANCE.md +++ b/docs/PERFORMANCE.md @@ -97,7 +97,8 @@ operational sample contained 3,909 observations and two selected labels, but its live aircraft and traffic rows were empty, so it remains a limited stress case. Snow, Noir, dense detection, and text-heavy combined layers are the clearest -controlled comparison points for later optimization work. +controlled comparison points for later optimization work. Snow has since been +retired as a visual preset; its row records the measurement as taken. ## Keyed live sources diff --git a/docs/SHARE-LINK-FORMAT.md b/docs/SHARE-LINK-FORMAT.md index cfb6d50fb..ea5636f39 100644 --- a/docs/SHARE-LINK-FORMAT.md +++ b/docs/SHARE-LINK-FORMAT.md @@ -90,35 +90,35 @@ probability of about 255 in 256 (many of them already fail as base64url). ## Field registry (top level) -| # | State key | Type | Default | Encoding | -| --- | ---------------------------- | ----- | ----------- | ------------------------------------------------------- | -| 1 | `view.kind` | enum | see below | 0 place, 1 thing | -| 2 | `lat` | coord | 0 | zigzag of degrees × 10⁴ | -| 3 | `lon` | coord | 0 | zigzag of degrees × 10⁴ | -| 4 | `alt` | sint | 800 | whole metres | -| 5 | `heading` | angle | 0 | whole degrees, see angles | -| 6 | `pitch` | sint | −35 | whole degrees | -| 7 | `roll` | angle | 0 | whole degrees | -| 8 | `sharedAtMs` | epoch | none | zigzag seconds since 2026-01-01T00:00:00Z | -| 9 | booleans | flags | 0 | bit set when the value differs from default | -| 10 | `layerState.enabledLayerIds` | LEN | none | layer bitset, see layers | -| 11 | `layerState.options` | LEN | none | packed option triples, see layers | -| 12 | `panelState` | LEN | none | packed panel entries, see panels | -| 13 | thing | LEN | none | sub-message, see thing views | -| 14 | `style` | enum | `normal` | normal, retro, surveillance, thermal, anime, noir, snow | -| 15 | `mapStack` | enum | `photoreal` | photoreal, bing-aerial, bing-labels, esri-imagery, osm | -| 16 | `hudVariant` | enum | style | tactical, operator, minimal, cyber | -| 17 | `bloomIntensity` | uint | style | | -| 18 | `bloomVersion` | uint | 2 | | -| 19 | `sharpenIntensity` | uint | style | | -| 20 | `detectionMode` | enum | style | OFF, SPARSE, BALANCED, DENSE | -| 21 | `detectionDensity` | uint | style | one of 0, 25, 50, 75, 100 | -| 22 | `detectionAllocation` | enum | style | ELASTIC, WEIGHTED | -| 23 | `detectionFadePct` | uint | style | 0–40 | -| 24 | `detectionOutsideOpacityPct` | uint | style | 0–100 | -| 25 | `scopeFeatherPct` | uint | 100 | 0–200 | -| 26 | `scopeTerminusPct` | uint | none | 94–100; absent is the adaptive terminus | -| 27 | `styleParams` | LEN | style | packed `(token, value × 100)` pairs | +| # | State key | Type | Default | Encoding | +| --- | ---------------------------- | ----- | ----------- | ----------------------------------------------------------------- | +| 1 | `view.kind` | enum | see below | 0 place, 1 thing | +| 2 | `lat` | coord | 0 | zigzag of degrees × 10⁴ | +| 3 | `lon` | coord | 0 | zigzag of degrees × 10⁴ | +| 4 | `alt` | sint | 800 | whole metres | +| 5 | `heading` | angle | 0 | whole degrees, see angles | +| 6 | `pitch` | sint | −35 | whole degrees | +| 7 | `roll` | angle | 0 | whole degrees | +| 8 | `sharedAtMs` | epoch | none | zigzag seconds since 2026-01-01T00:00:00Z | +| 9 | booleans | flags | 0 | bit set when the value differs from default | +| 10 | `layerState.enabledLayerIds` | LEN | none | layer bitset, see layers | +| 11 | `layerState.options` | LEN | none | packed option triples, see layers | +| 12 | `panelState` | LEN | none | packed panel entries, see panels | +| 13 | thing | LEN | none | sub-message, see thing views | +| 14 | `style` | enum | `normal` | normal, retro, surveillance, thermal, anime, noir, snow (retired) | +| 15 | `mapStack` | enum | `photoreal` | photoreal, bing-aerial, bing-labels, esri-imagery, osm | +| 16 | `hudVariant` | enum | style | tactical, operator, minimal, cyber | +| 17 | `bloomIntensity` | uint | style | | +| 18 | `bloomVersion` | uint | 2 | | +| 19 | `sharpenIntensity` | uint | style | | +| 20 | `detectionMode` | enum | style | OFF, SPARSE, BALANCED, DENSE | +| 21 | `detectionDensity` | uint | style | one of 0, 25, 50, 75, 100 | +| 22 | `detectionAllocation` | enum | style | ELASTIC, WEIGHTED | +| 23 | `detectionFadePct` | uint | style | 0–40 | +| 24 | `detectionOutsideOpacityPct` | uint | style | 0–100 | +| 25 | `scopeFeatherPct` | uint | 100 | 0–200 | +| 26 | `scopeTerminusPct` | uint | none | 94–100; absent is the adaptive terminus | +| 27 | `styleParams` | LEN | style | packed `(token, value × 100)` pairs | Field 1 absent means `thing` when field 13 is present and `place` otherwise, so v1 never writes it; a later view kind writes its code. @@ -163,7 +163,7 @@ for it.) In v1: | thermal | sensitivity 0.85, bloom 0.2, mode 0.33, pixelation 1, palette 0 | | anime | saturation 1, edgeThick 0.5 | | noir | contrastAmt 1.2, grainAmt 0.5, vignetteAmt 0.5 | -| snow | density 0.6, wind 0.5 | +| snow | retired: decodes as normal; its parameters are dropped | These are frozen like every other default: the codec reads them from the app's tables today, and a test pins them, so if a table moves the old values @@ -342,7 +342,9 @@ the app that can open it. values in the codec (see Style defaults). The same applies to `SHARE_VIEW_LAYER_OPTION_ABSENT` and the panel defaults. 4. **Codes are append-only.** Enum lists, entity kinds, flag bits, panel - numbers and style parameter tokens only grow. + numbers and style parameter tokens only grow. A style the app no longer + offers keeps its code: `snow` (6) is retired, so a link that names it + opens as Normal and the parameters written for it are dropped. 5. **Add, don't change.** A new setting takes the next free field number (28 onwards; fields 1–15 have one-byte tags and are all taken). A new boolean takes the next flag bit instead, which costs nothing when it is at diff --git a/scripts/format-scope.json b/scripts/format-scope.json index 5947f8811..228bf6a98 100644 --- a/scripts/format-scope.json +++ b/scripts/format-scope.json @@ -212,7 +212,6 @@ "src/styles/thermal.js", "src/styles/anime.js", "src/styles/noir.js", - "src/styles/snow.js", "scripts/qa-visual-effects.mjs", "scripts/qa-draw-tool.mjs", "scripts/qa-geo-import.mjs", diff --git a/scripts/package-boundaries.json b/scripts/package-boundaries.json index 4b63663ce..4df7229b4 100644 --- a/scripts/package-boundaries.json +++ b/scripts/package-boundaries.json @@ -463,7 +463,6 @@ "src/styles/thermal.js", "src/styles/anime.js", "src/styles/noir.js", - "src/styles/snow.js", "src/i18n/marker.js" ], "external": ["cesium"] @@ -697,7 +696,6 @@ "src/styles/anime.js", "src/styles/noir.js", "src/styles/retro.js", - "src/styles/snow.js", "src/styles/surveillance.js", "src/styles/thermal.js", "src/ui/applicationShell.js", @@ -2240,7 +2238,6 @@ "src/styles/anime.js", "src/styles/noir.js", "src/styles/retro.js", - "src/styles/snow.js", "src/styles/surveillance.js", "src/styles/thermal.js", "src/ui/applicationShell.js", @@ -3347,7 +3344,6 @@ "src/styles/anime.js", "src/styles/noir.js", "src/styles/retro.js", - "src/styles/snow.js", "src/styles/surveillance.js", "src/styles/thermal.js", "src/ui/applicationShortcuts.js", @@ -3937,7 +3933,6 @@ "src/styles/anime.js", "src/styles/noir.js", "src/styles/retro.js", - "src/styles/snow.js", "src/styles/surveillance.js", "src/styles/thermal.js", "src/view/index.js", diff --git a/scripts/qa-cockpit-utility.mjs b/scripts/qa-cockpit-utility.mjs index cb3515ed2..2bfc1ca41 100644 --- a/scripts/qa-cockpit-utility.mjs +++ b/scripts/qa-cockpit-utility.mjs @@ -1603,7 +1603,7 @@ try { cockpit.setVisionMode('optical'); current.focus({ preventScroll: true }); const states = [read()]; - for (let index = 0; index < 7; index += 1) { + for (let index = 0; index < 6; index += 1) { current.click(); states.push(read()); } @@ -1637,36 +1637,36 @@ try { reentered, }; }); - const cycleModes = ['optical', 'crt', 'nvg', 'thermal', 'anime', 'noir', 'snow', 'optical']; - const cycleLabels = ['NORMAL', 'CRT', 'NVG', 'FLIR', 'ANIME', 'NOIR', 'SNOW', 'NORMAL']; + const cycleModes = ['optical', 'crt', 'nvg', 'thermal', 'anime', 'noir', 'optical']; + const cycleLabels = ['NORMAL', 'CRT', 'NVG', 'FLIR', 'ANIME', 'NOIR', 'NORMAL']; check( - 'Cockpit vision control exposes Normal, CRT, NVG, FLIR, Anime, Noir and Snow before wrapping', + 'Cockpit vision control exposes Normal, CRT, NVG, FLIR, Anime and Noir before wrapping', JSON.stringify(visionCycle.states.map((state) => state.mode)) === JSON.stringify(cycleModes) && JSON.stringify(visionCycle.states.map((state) => state.label)) === JSON.stringify(cycleLabels) && visionCycle.states[5]?.aria === 'Current cockpit vision style: Noir. Activate for next style.' - && visionCycle.states[7]?.aria === 'Current cockpit vision style: Normal. Activate for next style.', + && visionCycle.states[6]?.aria === 'Current cockpit vision style: Normal. Activate for next style.', JSON.stringify(visionCycle.states.map(({ mode, label, aria }) => ({ mode, label, aria }))), ); check( 'user vision changes open Display for every temporary treatment and retain selector focus', - visionCycle.states.slice(1, 7).every((state) => state.displayOpen === 'true') - && visionCycle.states.slice(1, 7).every((state) => state.radioOpen === 'false') - && visionCycle.states.slice(1, 7).every((state) => state.parametersActive) - && visionCycle.states.slice(1, 7).every((state) => !state.parametersCollapsed) - && visionCycle.states.slice(1, 7).every((state) => state.signalCollapsed) + visionCycle.states.slice(1, 6).every((state) => state.displayOpen === 'true') + && visionCycle.states.slice(1, 6).every((state) => state.radioOpen === 'false') + && visionCycle.states.slice(1, 6).every((state) => state.parametersActive) + && visionCycle.states.slice(1, 6).every((state) => !state.parametersCollapsed) + && visionCycle.states.slice(1, 6).every((state) => state.signalCollapsed) && visionCycle.states.every((state) => state.focusRetained), JSON.stringify(visionCycle.states), ); check( 'each Cockpit vision mode drives only its own shader and Normal clears them all', - visionCycle.states.slice(1, 7).every((state) => { + visionCycle.states.slice(1, 6).every((state) => { const target = { - crt: 'retro', nvg: 'surveillance', thermal: 'thermal', anime: 'anime', noir: 'noir', snow: 'snow', + crt: 'retro', nvg: 'surveillance', thermal: 'thermal', anime: 'anime', noir: 'noir', }[state.mode]; return Object.entries(state.intensities).every(([name, value]) => name === target ? value > 0 : value === 0); }) - && Object.values(visionCycle.states[7].intensities).every((value) => value === 0), + && Object.values(visionCycle.states[6].intensities).every((value) => value === 0), JSON.stringify(visionCycle.states.map(({ mode, intensities }) => ({ mode, intensities }))), ); check( @@ -2317,13 +2317,13 @@ try { const styleManager = window.__godsEyeView.styleManager; const styleBefore = styleManager.activeStyle; // A Cockpit-only choice that Reset must undo. - styleManager.cockpitView.setVisionMode('snow'); + styleManager.cockpitView.setVisionMode('anime'); window.__qaCockpitReset = { calls: 0, original: manager.resetToGlobeView, subjectId: awareness?.getContextSnapshot?.()?.subject?.id || null, styleBefore, - snowDuringCockpit: styleManager.stages?.snow?.uniforms?.intensity, + animeDuringCockpit: styleManager.stages?.anime?.uniforms?.intensity, }; manager.resetToGlobeView = function qaCountedCockpitReset(...args) { window.__qaCockpitReset.calls += 1; @@ -2360,7 +2360,7 @@ try { height, subjectPreserved: Boolean(qa.subjectId && subjectId === qa.subjectId), styleRestored: gev.styleManager.activeStyle === qa.styleBefore, - snowDuringCockpit: qa.snowDuringCockpit, + animeDuringCockpit: qa.animeDuringCockpit, // Cockpit-time intensities are Cockpit's own, so check against the map preset. visionRestored: Object.entries(gev.styleManager.stages || {}).every(([name, stage]) => name === gev.styleManager.activeStyle @@ -2376,7 +2376,7 @@ try { && resetState.resetHidden && Math.abs(resetState.height - 18_000_000) < 150_000 && resetState.subjectPreserved - && resetState.snowDuringCockpit > 0 + && resetState.animeDuringCockpit > 0 && resetState.styleRestored && resetState.visionRestored, JSON.stringify(resetState), diff --git a/scripts/qa-map-source-tray.mjs b/scripts/qa-map-source-tray.mjs index 2876e0cac..8a0c0b7fd 100644 --- a/scripts/qa-map-source-tray.mjs +++ b/scripts/qa-map-source-tray.mjs @@ -200,8 +200,8 @@ const checkResponsiveStyleFocus = async (width) => { await page.focus('#control-panel-toggle'); await pressTabs(2); // disclosure -> pin -> Normal } - for (const [index, style] of ['normal', 'thermal', 'snow'].entries()) { - if (index) await pressTabs(3); + for (const [tabs, style] of [[0, 'normal'], [3, 'thermal'], [2, 'noir']]) { + if (tabs) await pressTabs(tabs); const state = await styleFocusMetrics(); check(`${width} px ${style} keyboard ring is visible and unclipped`, hasVisibleStyleFocus(state, style) && state.selectedStyle === 'normal' @@ -567,13 +567,13 @@ try { // Visual Styles precede the five Map Source tiles. Keep the existing opening // handoff to selected OSM, then use the user's real Shift+Tab path into styles. await pressTabs(5, true); - const snowFocus = await styleFocusMetrics(); - check('Shift+Tab reaches Snow with a visible ring while Normal and OSM stay selected', - hasVisibleStyleFocus(snowFocus, 'snow') && !snowFocus.selected - && snowFocus.selectedStyle === 'normal' && snowFocus.selectedMap === 'osm', - JSON.stringify(snowFocus)); + const noirFocus = await styleFocusMetrics(); + check('Shift+Tab reaches Noir with a visible ring while Normal and OSM stay selected', + hasVisibleStyleFocus(noirFocus, 'noir') && !noirFocus.selected + && noirFocus.selectedStyle === 'normal' && noirFocus.selectedMap === 'osm', + JSON.stringify(noirFocus)); await page.screenshot({ path: path.join(shotsDir, 'keyboard-style-focus.png') }); - await pressTabs(3, true); + await pressTabs(2, true); const middleFocus = await styleFocusMetrics(); check('Shift+Tab traverses the middle FLIR style without activating it', hasVisibleStyleFocus(middleFocus, 'thermal') && !middleFocus.selected diff --git a/scripts/qa-visual-effects.mjs b/scripts/qa-visual-effects.mjs index db0696e08..f3b9ab8bd 100644 --- a/scripts/qa-visual-effects.mjs +++ b/scripts/qa-visual-effects.mjs @@ -80,7 +80,6 @@ try { 'thermal', 'anime', 'noir', - 'snow', 'normal', ]) { await page.evaluate( diff --git a/server/providers/openai/instructions.js b/server/providers/openai/instructions.js index c9c4a43b4..2841df78a 100644 --- a/server/providers/openai/instructions.js +++ b/server/providers/openai/instructions.js @@ -46,7 +46,7 @@ function realtimeInstructions( // string is the whole rollback. 'NAMED VIEWS are shorthand for tool calls you already have — there is no "mode" tool for them. Treat ONLY these as the shorthand: "infrastructure mode" / "the infrastructure view" / "show me global infrastructure" means three set_layer_visibility calls (local-datacenters, local-dams, telegeography-submarine-cables) plus zoom_to_globe; "environmental mode" / "earth watch" / "active events", said as the name of a view, means set_layer_visibility for local-firms and earthquakes plus zoom_to_globe. Anything vaguer is NOT this shorthand — an open-ended question about the world or the news is an ordinary question: answer it, or use analyst_query over the layers already on. Never switch a whole view on to answer a question nobody asked to see. When you do run one, make every call before speaking, then give one confirmation naming the resulting state; if the fires layer comes back unavailable because no FIRMS key is configured, say so plainly — the earthquakes still loaded. "Live contacts" and "space missions" are NOT this pattern: they stay set_context_mode{mode:"contacts"} and set_context_mode{mode:"space-missions"}.', 'For visual filter requests, call set_visual_style with one of the allowed style IDs.', - 'SHIPS vs STYLES: "vessels" is easily heard as "visuals". "Show me vessels", "turn on vessels", "the vessels", "visuals" or "vestibules" said WITHOUT a style name means the ships layer: set_layer_visibility{layerId:"ais-live-vessels"}, exactly as "ships" or "boats" does. Call set_visual_style only when the user names a style (retro/CRT, surveillance/night vision, thermal, anime, noir, snow, normal) or says filter, effect or look. Never turn on a different data layer (such as fires) for a ships request.', + 'SHIPS vs STYLES: "vessels" is easily heard as "visuals". "Show me vessels", "turn on vessels", "the vessels", "visuals" or "vestibules" said WITHOUT a style name means the ships layer: set_layer_visibility{layerId:"ais-live-vessels"}, exactly as "ships" or "boats" does. Call set_visual_style only when the user names a style (retro/CRT, surveillance/night vision, thermal, anime, noir, normal) or says filter, effect or look. Never turn on a different data layer (such as fires) for a ships request.', 'Disambiguation table — basemap vs layer vs style: basemap switching requires an explicit stack name — "Bing aerial" means set_map_stack bing-aerial, "aerial with labels" means bing-labels, "OSM"/"road map" means osm, "Esri"/"Esri imagery" means esri-imagery, "Google 3D"/"photorealistic" means photoreal. Any other mention of "satellite" or "satellites" means the satellites DATA LAYER via set_layer_visibility, never a basemap — except "recent/latest satellite imagery" (the recent-imagery layer) and "weather satellite"/clouds (weather-satellite). "surveillance"/"night vision"/"thermal" are visual STYLES via set_visual_style.', 'HUD requests ("hud on/off", "switch to operator/minimal/tactical/cyber layout") use set_hud. Detection requests ("detection on", "dense mode", "balanced mode", "sparse mode", "set density to 25", "use weighted allocation") use set_detection. Density snaps to 0/25/50/75/100 and derives Sparse/Balanced/Dense; panoptic is a legacy alias for Dense.', 'Cyber sonar requests use set_cyber_sonar: enabled, rings, rangePct, intensityPct (Power), opacityPct, sectorDeg. For settings questions read get_current_view_state.controls.hud.sonar. Sonar is not detection. Do not silently switch themes, reveal the HUD or enable sonar when changing a slider. If the user explicitly requests Cyber plus sonar settings, call set_hud first, wait for success, then set_cyber_sonar. Confirm returned values; mapSweepActive and contactSweepActive distinguish saved settings from active map effects, including in Cockpit or reduced motion. Do not claim visible contacts solely because enabled is true.', diff --git a/src/celestialRing.test.mjs b/src/celestialRing.test.mjs index 7260c99fc..6ee9648b3 100644 --- a/src/celestialRing.test.mjs +++ b/src/celestialRing.test.mjs @@ -87,7 +87,7 @@ test('circular angle distance remains small across the wrap point', () => { test('celestial ring is available only in Normal style', () => { assert.equal(isCelestialRingStyleSupported('normal'), true); - for (const style of ['retro', 'surveillance', 'thermal', 'anime', 'noir', 'snow']) { + for (const style of ['retro', 'surveillance', 'thermal', 'anime', 'noir']) { assert.equal(isCelestialRingStyleSupported(style), false); } }); diff --git a/src/cockpitMarkup.test.mjs b/src/cockpitMarkup.test.mjs index 0b376d9fc..c47b29c5c 100644 --- a/src/cockpitMarkup.test.mjs +++ b/src/cockpitMarkup.test.mjs @@ -151,7 +151,7 @@ test('Cockpit vision cycle exposes every map preset exactly once', () => { ); assert.match( setVisionMode.toString(), - /const labels = \{\s*optical: t\('NORMAL'\),\s*crt: t\('CRT'\),\s*nvg: t\('NVG'\),\s*thermal: t\('FLIR'\),\s*anime: t\('ANIME'\),\s*noir: t\('NOIR'\),\s*snow: t\('SNOW'\),?\s*\};/, + /const labels = \{\s*optical: t\('NORMAL'\),\s*crt: t\('CRT'\),\s*nvg: t\('NVG'\),\s*thermal: t\('FLIR'\),\s*anime: t\('ANIME'\),\s*noir: t\('NOIR'\),?\s*\};/, ); assert.doesNotMatch(setVisionMode.toString(), /none: 'NONE'/); assert.doesNotMatch(ui, /getInheritedVisionLabel/); diff --git a/src/cockpitVisionPolicy.js b/src/cockpitVisionPolicy.js index 1b1c4e4b8..a6c319269 100644 --- a/src/cockpitVisionPolicy.js +++ b/src/cockpitVisionPolicy.js @@ -5,7 +5,6 @@ export const COCKPIT_VISION_MODES = Object.freeze([ 'thermal', 'anime', 'noir', - 'snow', ]); const TARGET_STYLE_BY_MODE = Object.freeze({ @@ -14,7 +13,6 @@ const TARGET_STYLE_BY_MODE = Object.freeze({ thermal: 'thermal', anime: 'anime', noir: 'noir', - snow: 'snow', }); const COCKPIT_MODE_BY_STYLE = Object.freeze({ @@ -24,7 +22,6 @@ const COCKPIT_MODE_BY_STYLE = Object.freeze({ thermal: 'thermal', anime: 'anime', noir: 'noir', - snow: 'snow', }); /** Normalize a requested Cockpit vision mode to the unfiltered Normal entry. */ diff --git a/src/cockpitVisionPolicy.test.mjs b/src/cockpitVisionPolicy.test.mjs index 3e5607543..be1ebceab 100644 --- a/src/cockpitVisionPolicy.test.mjs +++ b/src/cockpitVisionPolicy.test.mjs @@ -23,7 +23,6 @@ test('Cockpit vision order mirrors the unique map preset order', () => { 'thermal', 'anime', 'noir', - 'snow', ]); assert.equal(normalizeCockpitVisionMode('none'), 'optical'); assert.equal(normalizeCockpitVisionMode('unknown'), 'optical'); @@ -36,7 +35,7 @@ test('Cockpit entry selects the vision mode equivalent to the active map style', assert.equal(cockpitVisionModeForStyle('thermal'), 'thermal'); assert.equal(cockpitVisionModeForStyle('anime'), 'anime'); assert.equal(cockpitVisionModeForStyle('noir'), 'noir'); - assert.equal(cockpitVisionModeForStyle('snow'), 'snow'); + assert.equal(cockpitVisionModeForStyle('snow'), 'optical'); assert.equal(cockpitVisionModeForStyle('unsupported'), 'optical'); }); diff --git a/src/data/trafficPresetStyle.js b/src/data/trafficPresetStyle.js index 2f16a4b33..bac391232 100644 --- a/src/data/trafficPresetStyle.js +++ b/src/data/trafficPresetStyle.js @@ -20,7 +20,7 @@ * jam keeps a size bump so queues read as fat beads. * - `crt` (retro): saturated primaries that survive 10-level posterization * plus an all-bucket size boost to out-shout the pixel grid. - * - `normal` (normal/anime/snow/unknown): every lookup returns null/0 — + * - `normal` (normal/anime/unknown): every lookup returns null/0 — * the shipped palette and sizing apply untouched. * * Sim/uncovered dots (bucket null/'sim') are NEVER restyled under any diff --git a/src/data/trafficPresetStyle.test.mjs b/src/data/trafficPresetStyle.test.mjs index 7dd88e1a0..a05040a66 100644 --- a/src/data/trafficPresetStyle.test.mjs +++ b/src/data/trafficPresetStyle.test.mjs @@ -13,7 +13,7 @@ const luma = ([r, g, b]) => (0.299 * r + 0.587 * g + 0.114 * b) / 255; const BUCKETS = ['free', 'slow', 'jam']; const MONO_STYLES = ['surveillance', 'thermal', 'noir']; -const NORMAL_STYLES = ['normal', 'anime', 'snow', 'does-not-exist', '', undefined, null]; +const NORMAL_STYLES = ['normal', 'anime', 'does-not-exist', '', undefined, null]; test('profile mapping: NVG/FLIR/noir are mono, retro is crt, everything else normal', () => { for (const s of MONO_STYLES) assert.equal(trafficStyleProfile(s), 'mono', s); diff --git a/src/data/transitPresetStyle.js b/src/data/transitPresetStyle.js index 8c79d7c05..5996d4d97 100644 --- a/src/data/transitPresetStyle.js +++ b/src/data/transitPresetStyle.js @@ -18,7 +18,7 @@ * black sprite with a light ring is what a hot object looks like there. * - `crt` (retro): saturated per-mode colours that survive posterisation, * a size boost to out-shout the pixel grid, and a thinner halo. - * - `normal` (normal/anime/snow/unknown): every lookup returns the shipped + * - `normal` (normal/anime/unknown): every lookup returns the shipped * value — mode colour, shipped size, hairline edge only. * * Brackets are a different matter. The detection canvas composites ABOVE the diff --git a/src/data/transitPresetStyle.test.mjs b/src/data/transitPresetStyle.test.mjs index fc8e81323..7cbb2dcbf 100644 --- a/src/data/transitPresetStyle.test.mjs +++ b/src/data/transitPresetStyle.test.mjs @@ -17,7 +17,6 @@ test('profile mapping: NVG/FLIR/noir and cockpit nvg are mono, retro is crt, eve for (const plain of [ 'normal', 'anime', - 'snow', 'minecraft', '', null, diff --git a/src/firstRunExperience.test.mjs b/src/firstRunExperience.test.mjs index d76a48458..6629536e2 100644 --- a/src/firstRunExperience.test.mjs +++ b/src/firstRunExperience.test.mjs @@ -1040,6 +1040,19 @@ test('the voice TOOL SCHEMA matches the pinned contract — the mission mapping 'rotate_globe', 'stop', ]); + // Snow is retired from set_visual_style; restore it to keep the legacy pin. + const visualStyle = legacyTools.find( + (tool) => tool.name === 'set_visual_style', + ).parameters.properties.style; + assert.deepEqual(visualStyle.enum, [ + 'normal', + 'retro', + 'surveillance', + 'thermal', + 'anime', + 'noir', + ]); + visualStyle.enum = [...visualStyle.enum, 'snow']; const block = JSON.stringify(legacyTools); // Re-derived for the voice layer manifest (generated layer enums, alias and // field hints), point-and-ask's pointer/referent arguments and the prompt diff --git a/src/hud.js b/src/hud.js index 011b53691..023d617dc 100644 --- a/src/hud.js +++ b/src/hud.js @@ -76,7 +76,6 @@ const MODE_LABELS = Object.freeze({ thermal: msg('FLIR'), anime: msg('ANIME'), noir: msg('NOIR'), - snow: msg('SNOW'), }); /** Region ids from _regionLabel() and the name shown for each. */ diff --git a/src/i18n/locales/es.json b/src/i18n/locales/es.json index 696233f86..3de09e620 100644 --- a/src/i18n/locales/es.json +++ b/src/i18n/locales/es.json @@ -66,8 +66,6 @@ "Anime": "Anime", "Apply high-contrast monochrome film-noir grading.": "Aplica una gradación monocroma de alto contraste estilo film noir.", "Noir": "Noir", - "Add a cold, snowy whiteout treatment to the scene.": "Añade a la escena un tratamiento frío de ventisca blanca.", - "Snow": "Nieve", "MAP SOURCE": "FUENTE DEL MAPA", "Map source": "Fuente del mapa", "Style": "Estilo", diff --git a/src/i18n/locales/ru.json b/src/i18n/locales/ru.json index 8764d9d06..7849efd57 100644 --- a/src/i18n/locales/ru.json +++ b/src/i18n/locales/ru.json @@ -416,7 +416,6 @@ "Thermal": "Тепловизор", "Anime": "Аниме", "Noir": "Нуар", - "Snow": "Снег", "Current cockpit vision style: {style}. Activate for next style.": "Текущий стиль обзора кабины: {style}. Активируйте, чтобы переключить на следующий.", "Current style: {style} — click for next": "Текущий стиль: {style} — нажмите для следующего", "AIRCRAFT": "САМОЛЁТ", @@ -690,7 +689,6 @@ "Simulate FLIR-style thermal contrast. Turn up Ironbow for color.": "Имитирует тепловой контраст в стиле FLIR. Для цвета увеличьте Ironbow.", "Apply bright cel-shaded color and illustrated outlines.": "Применяет яркие cel-shading-цвета и рисованные контуры.", "Apply high-contrast monochrome film-noir grading.": "Применяет высококонтрастную монохромную цветокоррекцию в стиле нуар.", - "Add a cold, snowy whiteout treatment to the scene.": "Добавляет в сцену холодный снежный эффект «белой мглы».", "Expand LOCATION": "Развернуть панель «Место»", "Collapse panel": "Свернуть панель", "Pin location tray": "Закрепить панель места", diff --git a/src/i18n/locales/zh-CN.json b/src/i18n/locales/zh-CN.json index 2e7db6b8f..13c7c97af 100644 --- a/src/i18n/locales/zh-CN.json +++ b/src/i18n/locales/zh-CN.json @@ -1624,7 +1624,6 @@ "Thermal": "热成像", "Anime": "动漫", "Noir": "黑白", - "Snow": "雪景", "Current cockpit vision style: {style}. Activate for next style.": "当前座舱视觉样式:{style}。点击可切换到下一个样式。", "Current style: {style} — click for next": "当前样式:{style}——点击切换到下一个", "Collapse Contact panel": "收起目标面板", @@ -2535,7 +2534,6 @@ "Simulate FLIR-style thermal contrast. Turn up Ironbow for color.": "模拟 FLIR 风格的热成像对比。调高 Ironbow 可显示色彩。", "Apply bright cel-shaded color and illustrated outlines.": "应用明亮的赛璐珞色彩和插画轮廓线。", "Apply high-contrast monochrome film-noir grading.": "应用高对比度的黑白电影风格调色。", - "Add a cold, snowy whiteout treatment to the scene.": "为场景添加寒冷的暴雪白化效果。", "MAP SOURCE": "地图源", "Map source": "地图源", "Style": "样式", diff --git a/src/i18n/locales/zh-Hant.json b/src/i18n/locales/zh-Hant.json index 1477acd51..5be126d52 100644 --- a/src/i18n/locales/zh-Hant.json +++ b/src/i18n/locales/zh-Hant.json @@ -1614,7 +1614,6 @@ "Thermal": "熱成像", "Anime": "動漫", "Noir": "黑白", - "Snow": "雪景", "Current cockpit vision style: {style}. Activate for next style.": "當前座艙視覺樣式:{style}。點擊可切換到下一個樣式。", "Current style: {style} — click for next": "當前樣式:{style}——點擊切換到下一個", "Collapse Contact panel": "收起目標面板", @@ -2523,7 +2522,6 @@ "Simulate FLIR-style thermal contrast. Turn up Ironbow for color.": "模擬 FLIR 風格的熱成像對比。調高 Ironbow 可顯示色彩。", "Apply bright cel-shaded color and illustrated outlines.": "應用明亮的賽璐珞色彩和插畫輪廓線。", "Apply high-contrast monochrome film-noir grading.": "應用高對比度的黑白電影風格調色。", - "Add a cold, snowy whiteout treatment to the scene.": "為場景添加寒冷的暴雪白化效果。", "MAP SOURCE": "地圖源", "Map source": "地圖源", "Style": "樣式", diff --git a/src/radioMarkup.test.mjs b/src/radioMarkup.test.mjs index dfe5b4257..9d9ae45ed 100644 --- a/src/radioMarkup.test.mjs +++ b/src/radioMarkup.test.mjs @@ -239,6 +239,19 @@ test('no unchanged Realtime tool definition drifts silently', () => { 'Direct the camera like a drone operator: orbit the current view target, pan, tilt, or rotate — one bounded nudge (mode=once) or continuous motion until stopped (mode=continuous). Continuous motion also stops on any manual camera input or when a navigation tool runs. Say the RESULTING state when confirming ("Orbiting slowly").'; camera.parameters.properties.direction.description = 'Required except for orbit (defaults right/clockwise) and stop.'; + // Snow is retired from set_visual_style; restore it to keep the legacy pin. + const visualStyle = unchanged.find( + (tool) => tool.name === 'set_visual_style', + ).parameters.properties.style; + assert.deepEqual(visualStyle.enum, [ + 'normal', + 'retro', + 'surveillance', + 'thermal', + 'anime', + 'noir', + ]); + visualStyle.enum = [...visualStyle.enum, 'snow']; assert.equal(unchanged.length, 14); const digest = createHash('sha256') .update(JSON.stringify(unchanged)) diff --git a/src/share/legacyShareState.test.mjs b/src/share/legacyShareState.test.mjs index cde3a9ed6..f48c7adeb 100644 --- a/src/share/legacyShareState.test.mjs +++ b/src/share/legacyShareState.test.mjs @@ -107,6 +107,13 @@ test('the HAL example survives the round trip and shrinks to 39 characters', () ); }); +test('a long-form link to the retired Snow style opens as Normal', () => { + const snow = parseLegacy('v=2&lat=1&lon=2&style=snow&sp=d.90_w.20'); + const normal = parseLegacy('v=2&lat=1&lon=2'); + assert.equal(snow.style, 'normal'); + assert.deepEqual(snow.styleParams, normal.styleParams); +}); + test('links from earlier long-form versions keep their historical meaning', () => { for (const hash of [ 'lat=10&lon=20', diff --git a/src/share/viewCodec.js b/src/share/viewCodec.js index 84ba8fbc1..bb5f6d440 100644 --- a/src/share/viewCodec.js +++ b/src/share/viewCodec.js @@ -33,6 +33,7 @@ import { clampScopeFeatherPct } from '../scopeMaskPolicy.js'; import { VIEW_STYLES } from '../view/index.js'; import { GLOBAL_POST_DEFAULTS, + RETIRED_STYLES, STYLE_PRESET_DEFAULTS, STYLES, } from '../ui/visualPresets.js'; @@ -101,7 +102,7 @@ export const SHARE_VIEW_ENUMS = Object.freeze({ 'thermal', 'anime', 'noir', - 'snow', + 'snow', // retired (RETIRED_STYLES): decodes as Normal ]), mapStack: Object.freeze([ 'photoreal', @@ -221,10 +222,6 @@ export const SHARE_VIEW_STYLE_PARAMS = Object.freeze({ { key: 'grainAmt', token: 'g', min: 0, max: 1 }, { key: 'vignetteAmt', token: 'v', min: 0, max: 1 }, ]), - snow: freezeAll([ - { key: 'density', token: 'd', min: 0, max: 1 }, - { key: 'wind', token: 'w', min: 0, max: 1 }, - ]), }); /** @@ -1321,8 +1318,12 @@ export function decodeShareView(code, { nowMs = Date.now() } = {}) { return { ok: false, reason: 'out-of-range' }; } + // A retired style's code stays reserved: the view opens on Normal, and + // parameters written for it are dropped rather than reported as unknown. + const retiredStyle = RETIRED_STYLES.includes(raw.style); if (raw.style !== undefined && !VIEW_STYLES.includes(raw.style)) { - if (get('style').len) unknown.code('enum:style', raw.style); + if (get('style').len && !retiredStyle) + unknown.code('enum:style', raw.style); raw.style = undefined; } for (const key of ['hudVariant', 'mapStack']) { @@ -1357,7 +1358,7 @@ export function decodeShareView(code, { nowMs = Date.now() } = {}) { unknown.code('layer-option', 'without-layers'); if (get('panelState')) raw.panelState = decodePanels(get('panelState').len, unknown); - if (get('styleParams')) + if (get('styleParams') && !retiredStyle) raw.styleParams = decodeStyleParams( get('styleParams').len, raw.style ?? 'normal', diff --git a/src/share/viewCodec.test.mjs b/src/share/viewCodec.test.mjs index 4ec2b967c..4449ceb19 100644 --- a/src/share/viewCodec.test.mjs +++ b/src/share/viewCodec.test.mjs @@ -2,6 +2,7 @@ import { test } from 'node:test'; import assert from 'node:assert/strict'; import { LAYER_STATE_REGISTRY, + LAYER_STATE_TOKEN_ALPHABET, LAYER_STATE_TOKEN_RESERVATIONS, REGISTERED_LAYER_IDS, createDefaultLayerState, @@ -440,7 +441,8 @@ test('defaults travel as frozen meanings that match today’s app defaults', () assert.deepEqual(SHARE_VIEW_ENUMS.hudVariant.slice(0, HUD_LAYOUTS.length), [ ...HUD_LAYOUTS, ]); - assert.deepEqual(SHARE_VIEW_ENUMS.style, [...VIEW_STYLES]); + // Snow is retired; its code stays reserved (see the retired-style test). + assert.deepEqual(SHARE_VIEW_ENUMS.style, [...VIEW_STYLES, 'snow']); assert.deepEqual(SHARE_VIEW_ENUMS.mapStack, [...VIEW_MAPS]); assert.deepEqual(SHARE_VIEW_ENUMS.detectionAllocation, [ ...ALLOCATION_STRATEGIES, @@ -549,7 +551,6 @@ test('the field registry is well formed and permanent', () => { ...common, styleParams: { contrastAmt: 1.2, grainAmt: 0.5, vignetteAmt: 0.5 }, }, - snow: { ...common, styleParams: { density: 0.6, wind: 0.5 } }, }); assert.deepEqual( SHARE_VIEW_ENTITY_KINDS.map((e) => [e.code, e.kind]), @@ -966,6 +967,29 @@ test('enum names outside the code tables travel as text', () => { ]); }); +test('links to the retired Snow style open as Normal', () => { + const snowCode = SHARE_VIEW_ENUMS.style.indexOf('snow'); + assert.equal(snowCode, 6, 'a retired code is never reused'); + const params = new WireWriter() + .varint(LAYER_STATE_TOKEN_ALPHABET.indexOf('d')) + .varint(90) + .varint(LAYER_STATE_TOKEN_ALPHABET.indexOf('w')) + .varint(20) + .finish(); + for (const writeStyle of [ + (writer) => writer.uintField(14, snowCode), + (writer) => writer.textField(14, 'snow'), + ]) { + const writer = new WireWriter(); + writer.bytes.push(1); + writeStyle(writer); + writer.bytesField(27, params); + const { state, unknownFields } = decodeOk(hashOf(writer.finish())); + assert.deepEqual(state, normalizeShareViewState({})); + assert.equal(unknownFields, undefined); + } +}); + /* ---------------- integrity ---------------- */ test('malformed input is rejected with a reason, never thrown', () => { diff --git a/src/styles/snow.js b/src/styles/snow.js deleted file mode 100644 index a4db0a029..000000000 --- a/src/styles/snow.js +++ /dev/null @@ -1,97 +0,0 @@ -import { msg } from '../i18n/marker.js'; - -/** - * Snow Style — White overlay + Desaturation + Falling particles - * Transforms the world into a winter wonderland - */ -export const snowShader = { - name: 'snow', - uniforms: { - density: { default: 0.6, min: 0, max: 1, label: msg('Density') }, - wind: { default: 0.5, min: 0, max: 1, label: msg('Wind') }, - }, - fragmentShader: /* glsl */ ` - uniform sampler2D colorTexture; - uniform vec2 colorTextureDimensions; - uniform float intensity; - uniform float time; - uniform float density; - uniform float wind; - in vec2 v_textureCoordinates; - - // Hash function for pseudo-random snow - float hash(vec2 p) { - p = fract(p * vec2(123.34, 456.21)); - p += dot(p, p + 45.32); - return fract(p.x * p.y); - } - - // Layered snow particles - float snowLayer(vec2 uv, float layer) { - float depth = 0.5 + layer * 0.5; - float speed = 0.4 + layer * 0.3; - float size = mix(0.01, 0.025, layer); - float windForce = 0.05 + wind * 0.2; - - vec2 snowUV = uv * vec2(1.0, 0.5) * (4.0 + layer * 4.0); - snowUV.y += time * speed; - // Offset is the integral of a swaying velocity sin(time * 0.5 + phase) * windForce, - // so the sway stays bounded however long the app has been running. - snowUV.x -= 2.0 * cos(time * 0.5 + layer * 3.14) * windForce; - - vec2 cell = floor(snowUV); - vec2 f = fract(snowUV); - - float snow = 0.0; - // Check neighboring cells for smooth particles - for (int y = -1; y <= 1; y++) { - for (int x = -1; x <= 1; x++) { - vec2 neighbor = vec2(float(x), float(y)); - vec2 point = vec2(hash(cell + neighbor), hash(cell + neighbor + 100.0)); - // Animate particle position slightly - point = 0.5 + 0.4 * sin(time * 0.3 + 6.2831 * point); - float d = length(f - neighbor - point); - snow += smoothstep(size, 0.0, d) * depth; - } - } - return snow; - } - - void main() { - vec2 uv = v_textureCoordinates; - vec4 color = texture(colorTexture, uv); - - // Cool/blue color shift - vec3 cool = color.rgb * vec3(0.85, 0.9, 1.1); - - // Desaturate partially - float luma = dot(cool, vec3(0.299, 0.587, 0.114)); - vec3 desaturated = mix(cool, vec3(luma), 0.4 * intensity); - - // Brighten (snow coverage lightens everything) - vec3 brightened = mix(desaturated, vec3(1.0), 0.15 * intensity); - - // Add white frost overlay on brighter areas - float frostMask = smoothstep(0.3, 0.8, luma); - vec3 frosted = mix(brightened, vec3(0.95, 0.97, 1.0), frostMask * 0.25 * intensity); - - // Accumulate snow particle layers (density controls amount) - float snow = 0.0; - snow += snowLayer(uv, 0.0) * 0.5; - snow += snowLayer(uv, 0.25) * 0.6; - snow += snowLayer(uv, 0.5) * 0.7; - snow += snowLayer(uv, 0.75) * 0.8; - snow += snowLayer(uv, 1.0) * 1.0; - snow = clamp(snow * (0.4 + density * 1.2), 0.0, 1.0); - - // Composite snow particles - vec3 result = frosted + snow * 0.8 * intensity; - - // Subtle fog in lower areas - float fog = smoothstep(0.0, 0.4, 1.0 - uv.y) * 0.1 * intensity; - result = mix(result, vec3(0.85, 0.88, 0.95), fog); - - out_FragColor = vec4(mix(color.rgb, result, intensity), color.a); - } - `, -}; diff --git a/src/ui/applicationShell.js b/src/ui/applicationShell.js index 4b999a75f..1ff3b45ac 100644 --- a/src/ui/applicationShell.js +++ b/src/ui/applicationShell.js @@ -1598,7 +1598,7 @@ export class StyleManager extends ShellFacade { * 2. Crossfades the new shader stage intensity to 1. * 3. Applies style preset defaults (bloom/sharpen/HUD) if applyPreset is true. * 4. Updates button highlights, style indicator, slider panel, HUD, and detection overlay. - * @param {string} styleName - Target style ('normal'|'retro'|'surveillance'|'thermal'|'anime'|'noir'|'snow'). + * @param {string} styleName - Target style ('normal'|'retro'|'surveillance'|'thermal'|'anime'|'noir'). * @param {object} [options] * @param {boolean} [options.applyPreset=true] - Whether to apply STYLE_PRESET_DEFAULTS for the new style. * @param {boolean} [options.userInitiated=false] - Whether a direct user preset choice owns the Cyber exit style. diff --git a/src/ui/applicationShortcuts.js b/src/ui/applicationShortcuts.js index 010b6b620..57214a570 100644 --- a/src/ui/applicationShortcuts.js +++ b/src/ui/applicationShortcuts.js @@ -5,7 +5,6 @@ const STYLE_KEYS = Object.freeze({ 4: 'thermal', 5: 'anime', 6: 'noir', - 7: 'snow', }); /** diff --git a/src/ui/cockpitInstruments.js b/src/ui/cockpitInstruments.js index 77a4bea7d..a4f843c4c 100644 --- a/src/ui/cockpitInstruments.js +++ b/src/ui/cockpitInstruments.js @@ -268,7 +268,6 @@ export function setVisionMode(mode, { revealParameters = false } = {}) { thermal: t('FLIR'), anime: t('ANIME'), noir: t('NOIR'), - snow: t('SNOW'), }; const names = { optical: t('Normal'), @@ -277,7 +276,6 @@ export function setVisionMode(mode, { revealParameters = false } = {}) { thermal: t('Thermal'), anime: t('Anime'), noir: t('Noir'), - snow: t('Snow'), }; if (this.visionCurrent) { this.visionCurrent.dataset.cockpitVision = next; diff --git a/src/ui/cyberTheme.test.mjs b/src/ui/cyberTheme.test.mjs index 03ee75f08..f316d219c 100644 --- a/src/ui/cyberTheme.test.mjs +++ b/src/ui/cyberTheme.test.mjs @@ -105,7 +105,6 @@ test('visual styles retain Cyber through real preset application without droppin 'normal', 'noir', 'anime', - 'snow', 'thermal', 'retro', ]) { @@ -162,8 +161,8 @@ test('a preset explicitly selected in Cyber survives exit and resets for re-entr owner.setStyle('noir'); owner._setHudVariant('cyber', { applyVisualDefaults: true }); - owner.setStyle('snow', { userInitiated: true }); - assert.equal(owner.activeStyle, 'snow'); + owner.setStyle('anime', { userInitiated: true }); + assert.equal(owner.activeStyle, 'anime'); assert.equal(owner._preCyberStyle, 'noir'); assert.equal(owner._cyberStyleUserSelected, true); @@ -172,16 +171,16 @@ test('a preset explicitly selected in Cyber survives exit and resets for re-entr assert.equal(owner._preCyberStyle, 'noir'); owner._setHudVariant('operator', { applyVisualDefaults: true }); assert.equal(hud.getVariant(), 'operator'); - assert.equal(owner.activeStyle, 'snow'); + assert.equal(owner.activeStyle, 'anime'); assert.equal(owner._preCyberStyle, null); assert.equal(owner._cyberStyleUserSelected, false); // A later untouched Cyber round trip restores the new pre-Cyber preset. owner._setHudVariant('cyber', { applyVisualDefaults: true }); assert.equal(owner.activeStyle, 'thermal'); - assert.equal(owner._preCyberStyle, 'snow'); + assert.equal(owner._preCyberStyle, 'anime'); owner._setHudVariant('minimal', { applyVisualDefaults: true }); - assert.equal(owner.activeStyle, 'snow'); + assert.equal(owner.activeStyle, 'anime'); }); test('an explicit same-value FLIR choice is preserved on Cyber exit', (t) => { @@ -200,15 +199,15 @@ test('an authoritative same-Cyber reset clears local preset ownership', (t) => { const { owner } = styleOwner(t, 'tactical'); owner.setStyle('noir'); owner._setHudVariant('cyber', { applyVisualDefaults: true }); - owner.setStyle('snow', { userInitiated: true }); + owner.setStyle('anime', { userInitiated: true }); assert.equal(owner._cyberStyleUserSelected, true); owner._setHudVariant('cyber'); - assert.equal(owner.activeStyle, 'snow'); + assert.equal(owner.activeStyle, 'anime'); assert.equal(owner._preCyberStyle, null); assert.equal(owner._cyberStyleUserSelected, false); owner._setHudVariant('operator', { applyVisualDefaults: true }); - assert.equal(owner.activeStyle, 'snow'); + assert.equal(owner.activeStyle, 'anime'); }); test('Display and voice HUD routes preserve explicit Cyber entry and exit authority', async (t) => { @@ -226,10 +225,10 @@ test('Display and voice HUD routes preserve explicit Cyber entry and exit author const display = makeOwner(); const hudLayout = new EventTarget(); hudLayout.value = 'cyber'; - const snowButton = new EventTarget(); - snowButton.dataset = { style: 'snow' }; + const animeButton = new EventTarget(); + animeButton.dataset = { style: 'anime' }; const controls = bindDisplayControls({ - elements: { hudLayout, styleButtons: [snowButton] }, + elements: { hudLayout, styleButtons: [animeButton] }, actions: { setHudLayout: (value) => display.owner.setHudLayout(value), setStyle: (value) => @@ -239,12 +238,12 @@ test('Display and voice HUD routes preserve explicit Cyber entry and exit author hudLayout.dispatchEvent(new Event('change')); assert.equal(display.hud.getVariant(), 'cyber'); assert.equal(display.owner.activeStyle, 'thermal'); - snowButton.dispatchEvent(new Event('click')); - assert.equal(display.owner.activeStyle, 'snow'); + animeButton.dispatchEvent(new Event('click')); + assert.equal(display.owner.activeStyle, 'anime'); hudLayout.value = 'operator'; hudLayout.dispatchEvent(new Event('change')); assert.equal(display.hud.getVariant(), 'operator'); - assert.equal(display.owner.activeStyle, 'snow'); + assert.equal(display.owner.activeStyle, 'anime'); controls.destroy(); const voice = makeOwner(); @@ -263,13 +262,13 @@ test('Display and voice HUD routes preserve explicit Cyber entry and exit author assert.equal(entered.ok, true); assert.equal(voice.hud.getVariant(), 'cyber'); assert.equal(voice.owner.activeStyle, 'thermal'); - const selected = await runVoiceAction('set_visual_style', { style: 'snow' }); + const selected = await runVoiceAction('set_visual_style', { style: 'anime' }); assert.equal(selected.ok, true); - assert.equal(voice.owner.activeStyle, 'snow'); + assert.equal(voice.owner.activeStyle, 'anime'); const exited = await runVoiceAction('set_hud', { layout: 'operator' }); assert.equal(exited.ok, true); assert.equal(voice.hud.getVariant(), 'operator'); - assert.equal(voice.owner.activeStyle, 'snow'); + assert.equal(voice.owner.activeStyle, 'anime'); }); test('scope choice and expanded feather survive every HUD layout and both restore paths', async (t) => { @@ -301,11 +300,18 @@ test('scope choice and expanded feather survive every HUD layout and both restor assert.equal(owner._scopeFeatherSlider.value, '200'); }); +test('a scene shot saved with the retired Snow style plays on Normal', async (t) => { + const { owner } = styleOwner(t, 'tactical'); + owner.setStyle('noir'); + await owner.applyVisualState({ style: 'snow' }); + assert.equal(owner.activeStyle, 'normal'); +}); + test('scene and share HUD transitions do not restore a local pre-Cyber preset', async (t) => { const { owner, hud } = styleOwner(t, 'tactical'); owner.setStyle('noir'); owner._setHudVariant('cyber', { applyVisualDefaults: true }); - owner.setStyle('snow', { userInitiated: true }); + owner.setStyle('anime', { userInitiated: true }); assert.equal(owner._cyberStyleUserSelected, true); await owner.applyVisualState({ style: 'retro', hud: { variant: 'cyber' } }); @@ -319,7 +325,7 @@ test('scene and share HUD transitions do not restore a local pre-Cyber preset', owner.setStyle('surveillance'); owner._setHudVariant('cyber', { applyVisualDefaults: true }); assert.equal(owner._preCyberStyle, 'surveillance'); - owner.setStyle('snow', { userInitiated: true }); + owner.setStyle('anime', { userInitiated: true }); await owner.restoreShareState({ style: 'thermal', hudVariant: 'cyber', diff --git a/src/ui/scenePresentation.js b/src/ui/scenePresentation.js index 52e99796e..eb1800e75 100644 --- a/src/ui/scenePresentation.js +++ b/src/ui/scenePresentation.js @@ -12,7 +12,6 @@ const STYLE_LABELS = Object.freeze({ thermal: msg('FLIR'), anime: msg('ANIME'), noir: msg('NOIR'), - snow: msg('SNOW'), }); const DETECTION_MODE_LABELS = Object.freeze({ diff --git a/src/ui/styles/cyber.css b/src/ui/styles/cyber.css index e25bbae2d..f19bb3315 100644 --- a/src/ui/styles/cyber.css +++ b/src/ui/styles/cyber.css @@ -747,12 +747,6 @@ .btn-icon::before { content: '◐'; } -:root[data-ui-theme='cyber'] - #command-dock - .style-btn[data-style='snow'] - .btn-icon::before { - content: '❄︎'; -} :root[data-ui-theme='cyber'] :where(#bloom-toggle, #sharpen-toggle) { font-size: 0; diff --git a/src/ui/templates/command-dock.html b/src/ui/templates/command-dock.html index 3dac977ae..fa066f9da 100644 --- a/src/ui/templates/command-dock.html +++ b/src/ui/templates/command-dock.html @@ -43,11 +43,6 @@ Noir 6 -
diff --git a/src/ui/visualEffects.test.mjs b/src/ui/visualEffects.test.mjs index 9e9542c52..142bbbe4f 100644 --- a/src/ui/visualEffects.test.mjs +++ b/src/ui/visualEffects.test.mjs @@ -77,7 +77,7 @@ test('construction is inert and initialization creates one owned pipeline', () = assert.equal(f.frames.size, 0); f.effects.initStyles(); f.effects.initPostProcess(); - assert.equal(f.stages.size, 7); + assert.equal(f.stages.size, 6); assert.ok( Object.values(f.effects.stages).every( (stage) => !stage.enabled && stage.uniforms.intensity === 0, @@ -85,7 +85,7 @@ test('construction is inert and initialization creates one owned pipeline', () = ); f.effects.initStyles(); f.effects.initPostProcess(); - assert.equal(f.stages.size, 7); + assert.equal(f.stages.size, 6); f.effects.destroy(); }); @@ -252,7 +252,7 @@ test('stop revokes pending work immediately but retains stages until final destr assert.equal(f.frames.size, 0); assert.equal( f.stages.size, - 7, + 6, 'Context and Cockpit may still be releasing these stages', ); const intensity = f.effects.stages.retro.uniforms.intensity; @@ -281,7 +281,7 @@ test('destroying one instance does not remove another pipeline or clock', () => a.effects.destroy(); b.tick(250); assert.equal(a.stages.size, 0); - assert.equal(b.stages.size, 6); + assert.equal(b.stages.size, 5); assert.equal(b.effects.stages.retro.uniforms.intensity, 0.5); b.effects.destroy(); }); diff --git a/src/ui/visualInput.test.mjs b/src/ui/visualInput.test.mjs index c69c935ba..a87c9c815 100644 --- a/src/ui/visualInput.test.mjs +++ b/src/ui/visualInput.test.mjs @@ -73,13 +73,13 @@ function shortcuts() { return { documentRef, searchInput, calls, controller, press }; } -test('number keys retain the seven style mappings', () => { +test('number keys retain the six style mappings', () => { const f = shortcuts(); for (const key of ['1', '2', '3', '4', '5', '6', '7', '8', 'Space']) f.press(key); assert.deepEqual( f.calls, - ['normal', 'retro', 'surveillance', 'thermal', 'anime', 'noir', 'snow'].map( + ['normal', 'retro', 'surveillance', 'thermal', 'anime', 'noir'].map( (style) => ['setStyle', style], ), ); diff --git a/src/ui/visualPresets.js b/src/ui/visualPresets.js index e3830601a..90d89e2f0 100644 --- a/src/ui/visualPresets.js +++ b/src/ui/visualPresets.js @@ -1,7 +1,6 @@ import { retroShader } from '../styles/retro.js'; import { animeShader } from '../styles/anime.js'; import { noirShader } from '../styles/noir.js'; -import { snowShader } from '../styles/snow.js'; import { nightVisionShader } from '../styles/surveillance.js'; import { thermalShader } from '../styles/thermal.js'; import { BLOOM_INTENSITY_DEFAULT } from '../bloom.js'; @@ -16,9 +15,14 @@ export const STYLES = { thermal: thermalShader, anime: animeShader, noir: noirShader, - snow: snowShader, }; +/** + * Styles the app no longer offers. A share link, scene or shot that names one + * opens on Normal instead of keeping whatever style was already showing. + */ +export const RETIRED_STYLES = Object.freeze(['snow']); + /** * The tactical detection look: Dense at 75%. * @@ -156,5 +160,4 @@ export const STYLE_STATUS_LABELS = { thermal: msg('FLIR'), anime: msg('ANIME'), noir: msg('NOIR'), - snow: msg('SNOW'), }; diff --git a/src/ui/visualSettings.js b/src/ui/visualSettings.js index a6f7b5674..11974307e 100644 --- a/src/ui/visualSettings.js +++ b/src/ui/visualSettings.js @@ -1,6 +1,6 @@ import { clampScopeFeatherPct } from '../scopeMaskPolicy.js'; import { syncScopeControls } from './displayControls.js'; -import { STYLE_STATUS_LABELS } from './visualPresets.js'; +import { RETIRED_STYLES, STYLE_STATUS_LABELS } from './visualPresets.js'; import { syncSegmentedControl } from './segmentedControl.js'; import { t } from '../i18n/index.js'; import { UiLifetime } from './uiLifetime.js'; @@ -1272,8 +1272,9 @@ export class VisualSettings { const superseded = () => typeof isCurrent === 'function' && !isCurrent(); if (superseded()) return false; - if (state.style && state.style !== this.activeStyle) { - this.setStyle(state.style, { applyPreset: false }); + const style = RETIRED_STYLES.includes(state.style) ? 'normal' : state.style; + if (style && style !== this.activeStyle) { + this.setStyle(style, { applyPreset: false }); } const bloomState = state.bloom || {}; diff --git a/src/view/index.js b/src/view/index.js index fc5385aaa..221c4e0a1 100644 --- a/src/view/index.js +++ b/src/view/index.js @@ -20,7 +20,6 @@ export const STYLE_URL_NAMES = Object.freeze({ thermal: 'flir', anime: 'anime', noir: 'noir', - snow: 'snow', }); const STYLES_BY_URL_NAME = Object.freeze( diff --git a/src/voice/actionSchemas.js b/src/voice/actionSchemas.js index bf7e2f66d..a27907666 100644 --- a/src/voice/actionSchemas.js +++ b/src/voice/actionSchemas.js @@ -248,15 +248,7 @@ const schemas = [ properties: { style: { type: 'string', - enum: [ - 'normal', - 'retro', - 'surveillance', - 'thermal', - 'anime', - 'noir', - 'snow', - ], + enum: ['normal', 'retro', 'surveillance', 'thermal', 'anime', 'noir'], }, }, required: ['style'], diff --git a/src/voice/actionSchemas.test.mjs b/src/voice/actionSchemas.test.mjs index 97e5004b5..3bf9cfcd9 100644 --- a/src/voice/actionSchemas.test.mjs +++ b/src/voice/actionSchemas.test.mjs @@ -45,7 +45,8 @@ test('the complete Realtime tool payload pins the manifest-generated layer relea // S2 GhostMaps extends the generated layer enums. // Panel adds named voice targets and timeout; shared Panel/Cockpit guidance // is consolidated without changing either feature's arguments. - '9ee82c4214499280c208c93751b19d7b724c81b7727a2d0c6dab0184749fbe15', + // Snow leaves the set_visual_style enum. + '724a82b538a12a994401fc941e175625b032bfb96109934e091d3ef5b9600909', ); }); @@ -169,6 +170,18 @@ test('all legacy action arguments are byte-identical after removing the delibera // Cyber adds one HUD layout. const hud = property('set_hud').layout; hud.enum = hud.enum.filter((layout) => layout !== 'cyber'); + // Snow is retired from set_visual_style; restore it to keep the legacy pin. + const visualStyle = legacy.find((tool) => tool.name === 'set_visual_style') + .parameters.properties.style; + assert.deepEqual(visualStyle.enum, [ + 'normal', + 'retro', + 'surveillance', + 'thermal', + 'anime', + 'noir', + ]); + visualStyle.enum = [...visualStyle.enum, 'snow']; // Derived by applying the same removals to the 4b56d0e9 actionSchemas. assert.equal( createHash('sha256').update(JSON.stringify(legacy)).digest('hex'), diff --git a/src/voice/gevActions.js b/src/voice/gevActions.js index 0a43f02f1..0fd17dc77 100644 --- a/src/voice/gevActions.js +++ b/src/voice/gevActions.js @@ -66,7 +66,6 @@ const ALLOWED_STYLES = new Set([ 'thermal', 'anime', 'noir', - 'snow', ]); const PANEL_ALIASES = new Map([ ['data', 'data-panel'], From 2b5770c6a2d1abcc10987046123faf7ea87669dd Mon Sep 17 00:00:00 2001 From: Said Turksever <28983926+asturksever@users.noreply.github.com> Date: Thu, 29 Oct 2026 11:21:37 +0000 Subject: [PATCH 63/83] Add the changelog entry for the Snow removal --- changelog.d/1468-remove-snow-preset.md | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 changelog.d/1468-remove-snow-preset.md diff --git a/changelog.d/1468-remove-snow-preset.md b/changelog.d/1468-remove-snow-preset.md new file mode 100644 index 000000000..2bd1cb161 --- /dev/null +++ b/changelog.d/1468-remove-snow-preset.md @@ -0,0 +1,4 @@ +- Remove the Snow visual preset. Visual Presets, keyboard shortcuts, the + Cockpit vision carousel and the visual-style voice action now offer Normal, + CRT, NVG, FLIR, Anime and Noir; share links and scene shots that name Snow + open on Normal (asturksever, #1468). From 1abe8cbb516a7a3518248b436bd20724a831538d Mon Sep 17 00:00:00 2001 From: German Khokhlov Date: Thu, 29 Oct 2026 15:22:15 +0400 Subject: [PATCH 64/83] changelog: Ukrainian (#1470) Co-Authored-By: Claude Opus 5.5 --- changelog.d/1470-ukrainian.md | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 changelog.d/1470-ukrainian.md diff --git a/changelog.d/1470-ukrainian.md b/changelog.d/1470-ukrainian.md new file mode 100644 index 000000000..9f64e3081 --- /dev/null +++ b/changelog.d/1470-ukrainian.md @@ -0,0 +1,3 @@ +- Add Ukrainian (uk) to the language picker: the whole interface in Ukrainian, + with its four plural forms and Cyrillic HUD units. Based on the Ukrainian + translation by @meirm (#312) (German, @gekh, #1470). From e12614a13a3706809837d7f763da00e83c7a9fb8 Mon Sep 17 00:00:00 2001 From: Said Turksever Date: Thu, 29 Oct 2026 11:29:20 +0000 Subject: [PATCH 65/83] Pin the retired Operator code and test the live HUD fallback qa-radio cycles Minimal, off, on, then Tactical, so the HUD toggle must restore a non-default layout, and expects that sequence instead of the removed Operator step. The share-link test pins the exact hudVariant codes, so dropping or moving operator's reserved code fails it. A live IntelHUD test checks that a retired Operator layout falls back to Tactical, and the Cyber test stub themes from the normalized value. The share-link table marks operator as retired, and the zh-CN glossary drops the removed string. --- docs/SHARE-LINK-FORMAT.md | 2 +- docs/translations/zh-CN.md | 2 +- scripts/qa-radio.mjs | 10 ++++++---- src/hudAltitudeDatum.test.mjs | 22 ++++++++++++++++++++++ src/share/viewCodec.test.mjs | 8 +++++++- src/ui/cyberTheme.test.mjs | 2 +- 6 files changed, 38 insertions(+), 8 deletions(-) diff --git a/docs/SHARE-LINK-FORMAT.md b/docs/SHARE-LINK-FORMAT.md index 6e1129830..23a143c1c 100644 --- a/docs/SHARE-LINK-FORMAT.md +++ b/docs/SHARE-LINK-FORMAT.md @@ -107,7 +107,7 @@ probability of about 255 in 256 (many of them already fail as base64url). | 13 | thing | LEN | none | sub-message, see thing views | | 14 | `style` | enum | `normal` | normal, retro, surveillance, thermal, anime, noir, snow | | 15 | `mapStack` | enum | `photoreal` | photoreal, bing-aerial, bing-labels, esri-imagery, osm | -| 16 | `hudVariant` | enum | style | tactical, operator, minimal, cyber | +| 16 | `hudVariant` | enum | style | tactical, operator (retired), minimal, cyber | | 17 | `bloomIntensity` | uint | style | | | 18 | `bloomVersion` | uint | 2 | | | 19 | `sharpenIntensity` | uint | style | | diff --git a/docs/translations/zh-CN.md b/docs/translations/zh-CN.md index e3b7bcad1..b3a3f973a 100644 --- a/docs/translations/zh-CN.md +++ b/docs/translations/zh-CN.md @@ -43,7 +43,7 @@ Translation sources: abiyeenzo (#914) and EDIT-Aeterna (#979). | briefing / panel / dock | 简报 / 面板 / 停靠栏 | | preset / visual preset | 预设 / 视觉预设 | | Display / HUD layout | 显示 / HUD 布局 | -| Tactical / Operator / Minimal / Cyber | 战术 / 操作员 / 精简 / 赛博 | +| Tactical / Minimal / Cyber | 战术 / 精简 / 赛博 | | Scope (circular viewport mask) / keyhole | 视域 | | Clean UI | 纯净界面 | | cockpit | 座舱 | diff --git a/scripts/qa-radio.mjs b/scripts/qa-radio.mjs index 98aa95fda..ec95046db 100644 --- a/scripts/qa-radio.mjs +++ b/scripts/qa-radio.mjs @@ -2158,11 +2158,13 @@ async function main() { for (let index = 0; index < 5; index += 1) { recordLayoutStep(); if (index < 4) { - if (index < 2) { + // Off and back on in Minimal, so the toggle must restore a + // non-default layout before the cycle returns to Tactical. + if (index === 1 || index === 2) { + hudToggle.click(); + } else { hudLayout.value = index === 0 ? 'minimal' : 'tactical'; hudLayout.dispatchEvent(new Event('change', { bubbles: true })); - } else { - hudToggle.click(); } await waitForHudSettle(); } @@ -2331,7 +2333,7 @@ async function main() { scenesHidden, mapProviderUtilityStable, hudInteractionsExact: layoutSteps.map((step) => step.hud).join('>') - === 'TACTICAL>OPERATOR>MINIMAL>OFF>MINIMAL', + === 'TACTICAL>MINIMAL>OFF>MINIMAL>TACTICAL', // The accordion clears the topline, Cockpit cards, and Cesium credits // across every HUD layout. Its list owns any overflow internally. leftLaneClearAcrossHudCycle: layoutSteps.every((step) => ( diff --git a/src/hudAltitudeDatum.test.mjs b/src/hudAltitudeDatum.test.mjs index ca14569e5..18ed56f92 100644 --- a/src/hudAltitudeDatum.test.mjs +++ b/src/hudAltitudeDatum.test.mjs @@ -575,3 +575,25 @@ test('a summary interrupted while typing can retry unchanged context', async (t) env.restore(); } }); + +// ── Retired layouts ───────────────────────────────────────────────────────── +// +// Share links keep the retired Operator code, so old links still name it. The +// real HUD, not a caller, is what turns it into the default Tactical layout. + +test('a retired Operator layout falls back to Tactical in the live HUD', () => { + const env = installHudEnvironment(); + let hud; + try { + hud = new IntelHUD(env.viewer); + hud._el = { dataset: {} }; + hud.setVariant('minimal'); + assert.equal(hud.getVariant(), 'minimal'); + hud.setVariant('operator'); + assert.equal(hud.getVariant(), 'tactical'); + assert.equal(hud._el.dataset.variant, 'tactical'); + } finally { + hud?.destroy(); + env.restore(); + } +}); diff --git a/src/share/viewCodec.test.mjs b/src/share/viewCodec.test.mjs index 4bd685047..670a58f20 100644 --- a/src/share/viewCodec.test.mjs +++ b/src/share/viewCodec.test.mjs @@ -437,8 +437,14 @@ test('defaults travel as frozen meanings that match today’s app defaults', () assert.equal(defaults.bloomIntensity, BLOOM_INTENSITY_DEFAULT); assert.equal(defaults.bloomVersion, BLOOM_SCALE_VERSION); assert.equal(defaults.hudVariant, HUD_LAYOUTS[0]); - // Codes are append-only: the retired Operator layout keeps its code so old + // Codes are append-only: the retired Operator layout keeps code 1 so old // links still parse, and the app restores them as Tactical. + assert.deepEqual(SHARE_VIEW_ENUMS.hudVariant, [ + 'tactical', + 'operator', + 'minimal', + 'cyber', + ]); assert.deepEqual( SHARE_VIEW_ENUMS.hudVariant.filter((variant) => variant !== 'operator'), [...HUD_LAYOUTS], diff --git a/src/ui/cyberTheme.test.mjs b/src/ui/cyberTheme.test.mjs index 340dd0204..b75874390 100644 --- a/src/ui/cyberTheme.test.mjs +++ b/src/ui/cyberTheme.test.mjs @@ -56,7 +56,7 @@ function styleOwner(t, initialVariant = 'cyber') { setVariant: (value) => { // Normalize like the real HUD so retired layouts fall back. variant = normalizeHudLayout(value); - applyHudUiTheme(root, value); + applyHudUiTheme(root, variant); }, setMode: (value) => calls.push(['mode', value]), onStyleChange: (value) => calls.push(['style', value]), From 3b6111be0672d86647e35674fded12211d3fdc87 Mon Sep 17 00:00:00 2001 From: Said Turksever <28983926+asturksever@users.noreply.github.com> Date: Thu, 29 Oct 2026 11:34:19 +0000 Subject: [PATCH 66/83] Open views naming the retired Snow style on Normal createView threw on style 'snow', so an embed host or a show_in_gods_eye_view call holding a view from before Snow was retired was refused outright, camera and layers included. viewFromParams read style=snow as the recipient's own style, while the app opened the same link on Normal. Both now read a retired style as Normal; truly unknown names still throw. The retired list moves to a browser-free module shared by the view API, the share codec and visual settings. --- docs/CURRENT-STATE.md | 4 +++- docs/TOOLS.md | 3 ++- scripts/package-boundaries.json | 18 ++++++++++++------ src/app/embed.test.mjs | 14 ++++++++++++++ src/share/viewCodec.js | 2 +- src/ui/visualPresets.js | 6 ------ src/ui/visualSettings.js | 3 ++- src/view/index.js | 10 +++++++--- src/view/index.test.mjs | 8 ++++++++ src/visualStylePolicy.js | 7 +++++++ 10 files changed, 56 insertions(+), 19 deletions(-) create mode 100644 src/visualStylePolicy.js diff --git a/docs/CURRENT-STATE.md b/docs/CURRENT-STATE.md index 690024d28..4f3acfc1b 100644 --- a/docs/CURRENT-STATE.md +++ b/docs/CURRENT-STATE.md @@ -1393,7 +1393,9 @@ no DOM dependency. Existing presets and the 500 ms transition remain unchanged. Stopping the controller revokes animation before asynchronous UI teardown; final destruction removes its stages and restores the borrowed bloom configuration. Snow is no longer a visual preset. A share link that names it, in either the -long or compact form, opens on Normal and drops the Snow shader parameters. +long or compact form, opens on Normal and drops the Snow shader parameters. A +view passed to embed mode or `show_in_gods_eye_view`, and a saved scene shot, +that names Snow also open on Normal. Sharpen runs only when enabled with intensity above 0.001. At slider zero its stage is disabled; raising the slider resumes it when sharpen is enabled. diff --git a/docs/TOOLS.md b/docs/TOOLS.md index 45ee62546..80fd80b13 100644 --- a/docs/TOOLS.md +++ b/docs/TOOLS.md @@ -92,7 +92,8 @@ pitch), data layers, visual style, map imagery, and an aircraft, military aircraft or satellite to follow. `createView` builds and bounds one, `viewToParams` and `viewFromParams` write and read it in the share-link format the app restores, and `viewUrl` gives the address that opens it. The -style names are the ones share links use. Ships cannot be followed from a +style names are the ones share links use; a retired style (`snow`) is read +as `normal`. Ships cannot be followed from a link yet. An aircraft's `follow` may ask for its cockpit view (`cockpit: true`); links cannot carry that and open the app following it. diff --git a/scripts/package-boundaries.json b/scripts/package-boundaries.json index 4df7229b4..9b46899d7 100644 --- a/scripts/package-boundaries.json +++ b/scripts/package-boundaries.json @@ -813,7 +813,8 @@ "src/ui/layerNames.js", "src/ui/statusText.js", "src/ui/statusBadge.js", - "src/scopeMaskPolicy.js" + "src/scopeMaskPolicy.js", + "src/visualStylePolicy.js" ], "external": ["cesium"] }, @@ -2627,7 +2628,8 @@ "src/voice/geminiCaptureWorklet.js", "src/ui/statusBadge.js", "src/sceneCommandRelease.js", - "src/scopeMaskPolicy.js" + "src/scopeMaskPolicy.js", + "src/visualStylePolicy.js" ], "external": [ "hls.js", @@ -3364,7 +3366,8 @@ "src/i18n/locales/zh-CN.json", "src/i18n/locales/zh-Hant.json", "src/scopeMaskPolicy.js", - "src/ui/displayControls.js" + "src/ui/displayControls.js", + "src/visualStylePolicy.js" ], "external": ["cesium"] }, @@ -3941,7 +3944,8 @@ "src/data/idSwitches.js", "src/data/detectionPolicy.js", "src/scopeMaskPolicy.js", - "src/i18n/marker.js" + "src/i18n/marker.js", + "src/visualStylePolicy.js" ], "external": [] }, @@ -4045,7 +4049,8 @@ "src/tools/views.js", "src/tools/globePanel.js", "src/tools/queries/panelRequest.js", - "src/geoDistance.js" + "src/geoDistance.js", + "src/visualStylePolicy.js" ], "external": ["satellite.js"] }, @@ -4146,7 +4151,8 @@ "src/view/index.js", "src/data/idSwitches.js", "src/data/layerState.js", - "src/data/layerStateTokenReservations.json" + "src/data/layerStateTokenReservations.json", + "src/visualStylePolicy.js" ], "external": [] }, diff --git a/src/app/embed.test.mjs b/src/app/embed.test.mjs index 54799567e..5fa949342 100644 --- a/src/app/embed.test.mjs +++ b/src/app/embed.test.mjs @@ -146,6 +146,12 @@ test('an embedded page takes views only from its parent and answers it', async ( id: 3, view: { camera: { lat: 1, lon: 2 }, layers: ['flights'] }, }); + // A view kept from before Snow was retired still applies, on Normal. + send(parent, { + type: 'gev:view', + id: 4, + view: { camera: { lat: 1, lon: 2 }, style: 'snow' }, + }); await new Promise((resolve) => setTimeout(resolve, 10)); assert.deepEqual(posted[1], { type: 'gev:view-applied', @@ -161,6 +167,13 @@ test('an embedded page takes views only from its parent and answers it', async ( name === 'set_layer_visibility' && args.layerId === 'flights', ), ); + assert.equal(posted[3].id, 4); + assert.equal(posted[3].ok, true); + assert.ok( + calls.some( + ([name, args]) => name === 'set_visual_style' && args.style === 'normal', + ), + ); assert.equal(posted.filter((message) => message.id === 1).length, 0); // Ready names no data and goes to any parent; answers go only to the // origin that asked. @@ -168,6 +181,7 @@ test('an embedded page takes views only from its parent and answers it', async ( '*', 'https://host.example', 'https://host.example', + 'https://host.example', ]); remove(); }); diff --git a/src/share/viewCodec.js b/src/share/viewCodec.js index bb5f6d440..b72f79d34 100644 --- a/src/share/viewCodec.js +++ b/src/share/viewCodec.js @@ -31,9 +31,9 @@ import { } from '../data/detectionPolicy.js'; import { clampScopeFeatherPct } from '../scopeMaskPolicy.js'; import { VIEW_STYLES } from '../view/index.js'; +import { RETIRED_STYLES } from '../visualStylePolicy.js'; import { GLOBAL_POST_DEFAULTS, - RETIRED_STYLES, STYLE_PRESET_DEFAULTS, STYLES, } from '../ui/visualPresets.js'; diff --git a/src/ui/visualPresets.js b/src/ui/visualPresets.js index 90d89e2f0..ca251e48c 100644 --- a/src/ui/visualPresets.js +++ b/src/ui/visualPresets.js @@ -17,12 +17,6 @@ export const STYLES = { noir: noirShader, }; -/** - * Styles the app no longer offers. A share link, scene or shot that names one - * opens on Normal instead of keeping whatever style was already showing. - */ -export const RETIRED_STYLES = Object.freeze(['snow']); - /** * The tactical detection look: Dense at 75%. * diff --git a/src/ui/visualSettings.js b/src/ui/visualSettings.js index 11974307e..7c5a881eb 100644 --- a/src/ui/visualSettings.js +++ b/src/ui/visualSettings.js @@ -1,6 +1,7 @@ import { clampScopeFeatherPct } from '../scopeMaskPolicy.js'; import { syncScopeControls } from './displayControls.js'; -import { RETIRED_STYLES, STYLE_STATUS_LABELS } from './visualPresets.js'; +import { STYLE_STATUS_LABELS } from './visualPresets.js'; +import { RETIRED_STYLES } from '../visualStylePolicy.js'; import { syncSegmentedControl } from './segmentedControl.js'; import { t } from '../i18n/index.js'; import { UiLifetime } from './uiLifetime.js'; diff --git a/src/view/index.js b/src/view/index.js index 221c4e0a1..022914277 100644 --- a/src/view/index.js +++ b/src/view/index.js @@ -11,6 +11,7 @@ import { decodeLayerStateParams, encodeLayerStateParams, } from '../data/layerState.js'; +import { RETIRED_STYLES } from '../visualStylePolicy.js'; /** Visual styles by internal name, with the name share links use. */ export const STYLE_URL_NAMES = Object.freeze({ @@ -253,6 +254,7 @@ export function createView({ } = {}) { if (!Number.isFinite(camera?.lat) || !Number.isFinite(camera?.lon)) throw new TypeError('A view needs a camera lat and lon'); + if (RETIRED_STYLES.includes(style)) style = 'normal'; if (style !== null && !VIEW_STYLES.includes(style)) throw new TypeError(`Unknown view style: ${style}`); if (map !== null && !VIEW_MAPS.includes(map)) @@ -369,9 +371,11 @@ export function viewFromParams(params) { pitch_deg: number('pitch'), }, layers: state?.enabledLayerIds ?? [], - style: Object.hasOwn(STYLES_BY_URL_NAME, params.get('style')) - ? STYLES_BY_URL_NAME[params.get('style')] - : null, + style: RETIRED_STYLES.includes(params.get('style')) + ? 'normal' + : Object.hasOwn(STYLES_BY_URL_NAME, params.get('style')) + ? STYLES_BY_URL_NAME[params.get('style')] + : null, map: VIEW_MAPS.includes(map) ? map : null, follow, annotations: annotationsFromParams(params), diff --git a/src/view/index.test.mjs b/src/view/index.test.mjs index 34299c498..66630e6a0 100644 --- a/src/view/index.test.mjs +++ b/src/view/index.test.mjs @@ -127,6 +127,14 @@ test('annotations travel in the link, keeping only what the app draws', async () assert.equal(viewToParams(many).has('an'), false); }); +test('a view naming the retired Snow style opens on Normal', () => { + const camera = { lat: 1, lon: 2 }; + assert.equal(createView({ camera, style: 'snow' }).style, 'normal'); + const view = viewFromParams(new URLSearchParams('lat=1&lon=2&style=snow')); + assert.equal(view.style, 'normal'); + assert.equal(viewToParams(view).get('style'), 'normal'); +}); + test('inherited and unknown style keys do not corrupt a restored view', () => { for (const style of [ 'constructor', diff --git a/src/visualStylePolicy.js b/src/visualStylePolicy.js new file mode 100644 index 000000000..1a384a7a8 --- /dev/null +++ b/src/visualStylePolicy.js @@ -0,0 +1,7 @@ +/** + * Browser-free style vocabulary shared by views, share links and the UI. + * Styles the app no longer offers, by the name share links used: a view, + * link, scene or shot that names one opens on Normal instead of keeping + * whatever style was already showing. + */ +export const RETIRED_STYLES = Object.freeze(['snow']); From cf1ef368d02aec3be9dbdaba2055c49425ad7895 Mon Sep 17 00:00:00 2001 From: German Khokhlov Date: Thu, 29 Oct 2026 17:06:00 +0400 Subject: [PATCH 67/83] changelog: Italian (#1473) Co-Authored-By: Claude Opus 5.5 --- changelog.d/1473-italian.md | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 changelog.d/1473-italian.md diff --git a/changelog.d/1473-italian.md b/changelog.d/1473-italian.md new file mode 100644 index 000000000..c1af8f021 --- /dev/null +++ b/changelog.d/1473-italian.md @@ -0,0 +1,3 @@ +- Add Italian (it) to the language picker: the whole interface in Italian, + with Italian plural forms and labels shortened to fit the panels. Based on + the translation by @abiyeenzo (#912) (German, @gekh, #1473). From b0f0837c101a04f5edc2d076edd3dbe3b6f6b7e4 Mon Sep 17 00:00:00 2001 From: German Khokhlov Date: Thu, 29 Oct 2026 17:42:05 +0400 Subject: [PATCH 68/83] i18n(it, uk): translate the cyclone source errors Co-Authored-By: Claude Opus 5.5 --- src/i18n/locales/it.json | 4 +++- src/i18n/locales/uk.json | 4 +++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/src/i18n/locales/it.json b/src/i18n/locales/it.json index 86adc85d4..4594275cc 100644 --- a/src/i18n/locales/it.json +++ b/src/i18n/locales/it.json @@ -3004,5 +3004,7 @@ "Begin with a clean globe": "Inizia con un globo pulito", "Don't show this again": "Non mostrare più", "ESC to dismiss": "ESC per chiudere", - "Tip: the GEV MIC button in the dock lets you talk to the map.": "Suggerimento: il pulsante GEV MIC nel dock ti permette di parlare con la mappa." + "Tip: the GEV MIC button in the dock lets you talk to the map.": "Suggerimento: il pulsante GEV MIC nel dock ti permette di parlare con la mappa.", + "Malformed cyclone snapshot": "Snapshot dei cicloni non valido", + "Cyclone request timed out": "La richiesta dei cicloni è andata in timeout" } diff --git a/src/i18n/locales/uk.json b/src/i18n/locales/uk.json index fe0f3ccac..338a4fcc7 100644 --- a/src/i18n/locales/uk.json +++ b/src/i18n/locales/uk.json @@ -3073,5 +3073,7 @@ "Begin with a clean globe": "Почніть із чистого глобуса", "Don't show this again": "Більше не показувати", "ESC to dismiss": "ESC — приховати", - "Tip: the GEV MIC button in the dock lets you talk to the map.": "Порада: кнопка МІК у доку дає змогу говорити з картою." + "Tip: the GEV MIC button in the dock lets you talk to the map.": "Порада: кнопка МІК у доку дає змогу говорити з картою.", + "Malformed cyclone snapshot": "Некоректний знімок циклонів", + "Cyclone request timed out": "Минув час очікування запиту циклонів" } From 01a097caae3be57b408c4593848184df79416852 Mon Sep 17 00:00:00 2001 From: German Khokhlov Date: Thu, 29 Oct 2026 17:42:57 +0400 Subject: [PATCH 69/83] changelog: Brazilian Portuguese (#1475) Co-Authored-By: Claude Opus 5.5 --- changelog.d/1475-brazilian-portuguese.md | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 changelog.d/1475-brazilian-portuguese.md diff --git a/changelog.d/1475-brazilian-portuguese.md b/changelog.d/1475-brazilian-portuguese.md new file mode 100644 index 000000000..1705d628a --- /dev/null +++ b/changelog.d/1475-brazilian-portuguese.md @@ -0,0 +1,4 @@ +- Add Brazilian Portuguese (pt) to the language picker, with every screen + translated and Portuguese plural forms. The CCTV summary line now names its + calibration, source and view in the page language. Based on translations by + @abiyeenzo (#909) (German, @gekh, #1475). From f9af9e758c2d8c286ed133790743f46f70b15ea9 Mon Sep 17 00:00:00 2001 From: German Khokhlov Date: Thu, 29 Oct 2026 17:55:01 +0400 Subject: [PATCH 70/83] i18n(fr): translate strings new in main Co-Authored-By: Claude Opus 5.5 --- src/i18n/locales/fr.json | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/i18n/locales/fr.json b/src/i18n/locales/fr.json index fd6e62052..68392f67d 100644 --- a/src/i18n/locales/fr.json +++ b/src/i18n/locales/fr.json @@ -3004,5 +3004,7 @@ "Begin with a clean globe": "Commencer avec un globe vierge", "Don't show this again": "Ne plus afficher", "ESC to dismiss": "ESC pour fermer", - "Tip: the GEV MIC button in the dock lets you talk to the map.": "Astuce : le bouton GEV MIC du dock permet de parler à la carte." + "Tip: the GEV MIC button in the dock lets you talk to the map.": "Astuce : le bouton GEV MIC du dock permet de parler à la carte.", + "Malformed cyclone snapshot": "Instantané cyclonique mal formé", + "Cyclone request timed out": "Délai dépassé pour la requête cyclonique" } From e44d15cd34b5769d203cd67ef405dea0e903518f Mon Sep 17 00:00:00 2001 From: German Khokhlov Date: Thu, 29 Oct 2026 17:55:31 +0400 Subject: [PATCH 71/83] changelog: French (#1476) Co-Authored-By: Claude Opus 5.5 --- changelog.d/1476-french.md | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 changelog.d/1476-french.md diff --git a/changelog.d/1476-french.md b/changelog.d/1476-french.md new file mode 100644 index 000000000..30d0b8c89 --- /dev/null +++ b/changelog.d/1476-french.md @@ -0,0 +1,4 @@ +- Add French (fr) to the language picker, with French typography and plural + forms. With nine languages the picker now shows its search field. Based on + the translation by @abiyeenzo (#907), checked against @meirm's French + catalog (#312) (German, @gekh, #1476). From 32125384fe8287865187088d257ff54cbaac82a6 Mon Sep 17 00:00:00 2001 From: Said Turksever <28983926+asturksever@users.noreply.github.com> Date: Thu, 29 Oct 2026 14:04:11 +0000 Subject: [PATCH 72/83] Drop Snow from the new catalogs and migrate saved Snow shots The it, pt and uk catalogs merged from main still carried the two Snow button strings, which the catalog tests report as stale. They are pruned with npm run i18n -- --prune. A Scene Director shot saved with Snow now normalizes to Normal when the project loads, so the shot list shows NORMAL rather than an untranslated SNOW for a shot that plays on Normal. The README's style keys read 1-6. --- README.md | 4 ++-- scripts/package-boundaries.json | 3 ++- src/director/document.test.mjs | 9 +++++++++ src/i18n/locales/it.json | 2 -- src/i18n/locales/pt.json | 2 -- src/i18n/locales/uk.json | 2 -- src/scenes/project.js | 5 ++++- 7 files changed, 17 insertions(+), 10 deletions(-) diff --git a/README.md b/README.md index ceb66787a..745bec3d8 100644 --- a/README.md +++ b/README.md @@ -294,14 +294,14 @@ Choose a first-run mission, or try these in order. The GIFs show Google Photorea ![Tracking the ISS along its orbital path as it crosses over Ukraine](docs/media/14-iss-over-ukraine.gif) -6. **Switch the optics.** Tap `1`–`7` — CRT, NVG, FLIR — and the whole live planet re-renders through a different sensor. +6. **Switch the optics.** Tap `1`–`6` — CRT, NVG, FLIR — and the whole live planet re-renders through a different sensor. ![Cycling a dense live globe through CRT, FLIR, and NVG in one continuous view](docs/media/01-style-sweep.gif) 7. **Talk to it** _(needs an OpenAI key)_: _"Take me to LAX and select the nearest airborne aircraft."_ 8. **Come home.** Hit **Reset Globe** — or just say _"zoom out to a globe view."_ -**Keyboard:** `1`–`7` visual styles · `H` HUD · `D` detection · `C` cockpit · `` ` `` frame rate · `Esc` out. Trackpad pinch zooms the globe. +**Keyboard:** `1`–`6` visual styles · `H` HUD · `D` detection · `C` cockpit · `` ` `` frame rate · `Esc` out. Trackpad pinch zooms the globe. --- diff --git a/scripts/package-boundaries.json b/scripts/package-boundaries.json index 8aabedc08..b49872430 100644 --- a/scripts/package-boundaries.json +++ b/scripts/package-boundaries.json @@ -964,7 +964,8 @@ "src/i18n/locales/uk.json", "src/i18n/locales/zh-CN.json", "src/i18n/locales/zh-Hant.json", - "src/ui/unitLabels.js" + "src/ui/unitLabels.js", + "src/visualStylePolicy.js" ], "external": ["cesium"] }, diff --git a/src/director/document.test.mjs b/src/director/document.test.mjs index c0b8b0935..9294abb7b 100644 --- a/src/director/document.test.mjs +++ b/src/director/document.test.mjs @@ -135,6 +135,15 @@ test('document byte, nesting, collection, finite-number and string bounds are en ); }); +test('a shot saved with the retired Snow style migrates to Normal', () => { + const project = fixture(); + project.scenes[0].shots[0].visual = { style: 'snow' }; + const migrated = normalizeProject( + parseSceneDocument(JSON.stringify(project)), + ); + assert.equal(migrated.scenes[0].shots[0].visual.style, 'normal'); +}); + test('captured scope and extended detection edits survive migration', () => { const project = fixture(); project.scenes[0].shots[0].visual = { diff --git a/src/i18n/locales/it.json b/src/i18n/locales/it.json index 4594275cc..502b50605 100644 --- a/src/i18n/locales/it.json +++ b/src/i18n/locales/it.json @@ -1700,7 +1700,6 @@ "Thermal": "Termico", "Anime": "Anime", "Noir": "Noir", - "Snow": "Neve", "Current cockpit vision style: {style}. Activate for next style.": "Stile di visione attuale del cockpit: {style}. Attiva per lo stile successivo.", "Current style: {style} — click for next": "Stile attuale: {style}. Clic per il successivo", "Collapse Contact panel": "Comprimi il pannello Contatto", @@ -2781,7 +2780,6 @@ "Simulate FLIR-style thermal contrast. Turn up Ironbow for color.": "Simula il contrasto termico in stile FLIR. Alza Ironbow per il colore.", "Apply bright cel-shaded color and illustrated outlines.": "Applica colori vivaci cel-shaded e contorni illustrati.", "Apply high-contrast monochrome film-noir grading.": "Applica un color grading noir monocromatico ad alto contrasto.", - "Add a cold, snowy whiteout treatment to the scene.": "Aggiungi alla scena un effetto freddo di nevicata e whiteout.", "MAP SOURCE": "FONTE MAPPA", "Map source": "Fonte mappa", "Style": "Stile", diff --git a/src/i18n/locales/pt.json b/src/i18n/locales/pt.json index 087aeb106..f139e517a 100644 --- a/src/i18n/locales/pt.json +++ b/src/i18n/locales/pt.json @@ -1700,7 +1700,6 @@ "Thermal": "Térmico", "Anime": "Anime", "Noir": "Noir", - "Snow": "Neve", "Current cockpit vision style: {style}. Activate for next style.": "Estilo atual de visão da cabine: {style}. Ative para o próximo estilo.", "Current style: {style} — click for next": "Estilo atual: {style} — clique para o próximo", "Collapse Contact panel": "Recolher painel de contato", @@ -2783,7 +2782,6 @@ "Simulate FLIR-style thermal contrast. Turn up Ironbow for color.": "Simular contraste térmico estilo FLIR. Aumente o Ironbow para ter cor.", "Apply bright cel-shaded color and illustrated outlines.": "Aplicar cores vivas em cel shading e contornos ilustrados.", "Apply high-contrast monochrome film-noir grading.": "Aplicar gradação monocromática de filme noir com alto contraste.", - "Add a cold, snowy whiteout treatment to the scene.": "Adicionar à cena um efeito frio de nevasca branca.", "MAP SOURCE": "FONTE DO MAPA", "Map source": "Fonte do mapa", "Style": "Estilo", diff --git a/src/i18n/locales/uk.json b/src/i18n/locales/uk.json index 338a4fcc7..2e6fa95c0 100644 --- a/src/i18n/locales/uk.json +++ b/src/i18n/locales/uk.json @@ -1723,7 +1723,6 @@ "Thermal": "Тепловізор", "Anime": "Аніме", "Noir": "Нуар", - "Snow": "Сніг", "Current cockpit vision style: {style}. Activate for next style.": "Поточний візуальний стиль у кабіні: {style}. Активуйте, щоб перейти до наступного.", "Current style: {style} — click for next": "Поточний стиль: {style} — клацніть для наступного", "Collapse Contact panel": "Згорнути панель контактів", @@ -2850,7 +2849,6 @@ "Simulate FLIR-style thermal contrast. Turn up Ironbow for color.": "Імітує тепловий контраст у стилі FLIR. Для кольору збільште Ironbow.", "Apply bright cel-shaded color and illustrated outlines.": "Застосовує яскраву мультяшну заливку та ілюстровані контури.", "Apply high-contrast monochrome film-noir grading.": "Застосовує висококонтрастну чорно-білу обробку в стилі нуар.", - "Add a cold, snowy whiteout treatment to the scene.": "Додає до сцени холодний ефект снігової імли.", "MAP SOURCE": "ДЖЕРЕЛО КАРТИ", "Map source": "Джерело карти", "Style": "Стиль", diff --git a/src/scenes/project.js b/src/scenes/project.js index eb3084962..f2297afaf 100644 --- a/src/scenes/project.js +++ b/src/scenes/project.js @@ -7,6 +7,7 @@ import { BLOOM_SCALE_VERSION, decodeBloomIntensity, } from '../bloom.js'; +import { RETIRED_STYLES } from '../visualStylePolicy.js'; /** @constant {number} Current schema version for project migration */ export const PROJECT_VERSION = SCENE_DOCUMENT_VERSION; @@ -262,7 +263,9 @@ export function normalizeShot( ...(rawShot?.dataPackIds ? { dataPackIds: [...rawShot.dataPackIds] } : {}), ...(rawShot?.move ? { move: deepClone(rawShot.move) } : {}), visual: { - style: visual.style || 'normal', + style: RETIRED_STYLES.includes(visual.style) + ? 'normal' + : visual.style || 'normal', bloom: normalizeBloomState(bloom, { projectVersion, fallbackIntensity: 50, From 607cd7708cf7803e54d568c87cffe760d3ad8563 Mon Sep 17 00:00:00 2001 From: Said Turksever Date: Thu, 29 Oct 2026 14:04:28 +0000 Subject: [PATCH 73/83] Drop the Operator string from the Italian, Portuguese and Ukrainian catalogs The catalogs merged from main still carried the retired layout's label, so the catalog tests failed. The Italian glossary drops it too. --- docs/translations/it.md | 2 +- src/i18n/locales/it.json | 1 - src/i18n/locales/pt.json | 1 - src/i18n/locales/uk.json | 1 - 4 files changed, 1 insertion(+), 4 deletions(-) diff --git a/docs/translations/it.md b/docs/translations/it.md index 81854d6fe..722916101 100644 --- a/docs/translations/it.md +++ b/docs/translations/it.md @@ -79,7 +79,7 @@ The `many` form is the `other` text with «di» after the number when a noun fol | briefing / panel / dock | briefing / pannello / dock | | cockpit | cockpit | | preset / visual preset | preset / preset visivo | -| Tactical / Operator / Minimal / Cyber | Tattico / Operatore / Minimale / Cyber | +| Tactical / Minimal / Cyber | Tattico / Minimale / Cyber | | Scope (circular viewport mask) / keyhole | scope / foro | | feather / fade | sfumatura / dissolvenza | | detection overlay | overlay di rilevamento | diff --git a/src/i18n/locales/it.json b/src/i18n/locales/it.json index 4594275cc..f157ebec1 100644 --- a/src/i18n/locales/it.json +++ b/src/i18n/locales/it.json @@ -2862,7 +2862,6 @@ "Layout": "Layout", "HUD layout": "Layout HUD", "Tactical": "Tattico", - "Operator": "Operatore", "Minimal": "Minimale", "Cyber": "Cyber", "Sonar": "Sonar", diff --git a/src/i18n/locales/pt.json b/src/i18n/locales/pt.json index 087aeb106..5fa3ded6b 100644 --- a/src/i18n/locales/pt.json +++ b/src/i18n/locales/pt.json @@ -2864,7 +2864,6 @@ "Layout": "Layout", "HUD layout": "Layout do HUD", "Tactical": "Tático", - "Operator": "Operador", "Minimal": "Mínimo", "Cyber": "Ciber", "Sonar": "Sonar", diff --git a/src/i18n/locales/uk.json b/src/i18n/locales/uk.json index 338a4fcc7..93b53e7fc 100644 --- a/src/i18n/locales/uk.json +++ b/src/i18n/locales/uk.json @@ -2931,7 +2931,6 @@ "Layout": "Компонування", "HUD layout": "Компонування HUD", "Tactical": "Тактичне", - "Operator": "Операторське", "Minimal": "Мінімальне", "Cyber": "Кібер", "Sonar": "Сонар", From aa0f6d4e52d309f516d3ce2ed480546b379c6e33 Mon Sep 17 00:00:00 2001 From: Said Turksever Date: Thu, 29 Oct 2026 14:04:28 +0000 Subject: [PATCH 74/83] Remove the HUD top bar that no layout shows Operator was the only layout that displayed the top banner bar. Its markup, styles and keep-out selectors are removed, and the Cyber style test now checks that none remain. --- docs/CURRENT-STATE.md | 4 +++- scripts/qa-scope-hud.mjs | 2 +- src/hud.js | 6 ------ src/overlays/worldOverlay.js | 1 - src/ui/cyberTheme.test.mjs | 5 +---- src/ui/panelLayoutController.js | 2 -- src/ui/styles/cyber.css | 5 ----- src/ui/styles/mobile-shell.css | 1 - src/ui/styles/overlays.css | 21 +++------------------ src/ui/styles/responsive.css | 6 ------ 10 files changed, 8 insertions(+), 45 deletions(-) diff --git a/docs/CURRENT-STATE.md b/docs/CURRENT-STATE.md index b22e9618b..f07cf2042 100644 --- a/docs/CURRENT-STATE.md +++ b/docs/CURRENT-STATE.md @@ -236,7 +236,9 @@ restoration and both Scope presentations. `QA_SCREENSHOT_DIR` saves screenshots. Display > HUD > Layout offers Tactical, Minimal and Cyber; the `set_hud` voice action accepts the same three. The Operator layout is retired. Share links keep its enum code so older links still parse, and a link, scene or saved state -that names Operator restores the default Tactical layout. +that names Operator restores the default Tactical layout. Operator was the +only layout that showed the HUD's top banner bar, so its markup and styles are +removed too. ## Cyber HUD — September 30, 2026 diff --git a/scripts/qa-scope-hud.mjs b/scripts/qa-scope-hud.mjs index 38444ca18..1607b2631 100644 --- a/scripts/qa-scope-hud.mjs +++ b/scripts/qa-scope-hud.mjs @@ -564,7 +564,7 @@ try { ); }); const broadBackings = [ - ...hud.querySelectorAll('.hud-corner, .hud-top-bar, .hud-bottom-bar'), + ...hud.querySelectorAll('.hud-corner, .hud-bottom-bar'), ].filter( (el) => el.offsetWidth > 0 && diff --git a/src/hud.js b/src/hud.js index ce432a03f..198d34c7f 100644 --- a/src/hud.js +++ b/src/hud.js @@ -288,12 +288,6 @@ export class IntelHUD { this._el.innerHTML = ` -
- TOP SECRET // SI-TK // NOFORN - ${this._missionId} - PAGE 1/1 -
-
┌
diff --git a/src/overlays/worldOverlay.js b/src/overlays/worldOverlay.js index ccf3cbd59..1fcfdd8dc 100644 --- a/src/overlays/worldOverlay.js +++ b/src/overlays/worldOverlay.js @@ -114,7 +114,6 @@ export const WORLD_OVERLAY_OCCLUDER_SELECTORS = Object.freeze([ '.hud-top-right', '.hud-bottom-left', '.hud-bottom-right', - '.hud-top-bar', '.hud-bottom-bar', '#space-mission-panel', '#space-mission-panel-host', diff --git a/src/ui/cyberTheme.test.mjs b/src/ui/cyberTheme.test.mjs index b75874390..266942a05 100644 --- a/src/ui/cyberTheme.test.mjs +++ b/src/ui/cyberTheme.test.mjs @@ -717,10 +717,7 @@ test('the Display selector, voice schema and final stylesheet expose Cyber', () assert.match(cyberStyles, /\.hud-top-left/); assert.match(cyberStyles, /transparent 0 min\(40vw, 52vh\)/); assert.match(cyberStyles, /\.hud-bottom-bar \{\s*display: none;/); - assert.match( - cyberStyles, - /#intel-hud\[data-variant='cyber'\] \.hud-top-bar \{\s*display: none;/, - ); + assert.doesNotMatch(cyberStyles, /\.hud-top-bar/); // Cyber shares the measured rail/credit keep-out rather than overriding it. assert.doesNotMatch( cyberStyles, diff --git a/src/ui/panelLayoutController.js b/src/ui/panelLayoutController.js index 25b4b3910..0c2a2ad3a 100644 --- a/src/ui/panelLayoutController.js +++ b/src/ui/panelLayoutController.js @@ -20,7 +20,6 @@ const LEFT_STACK_OBSTACLE_SELECTOR = [ '#intel-hud .hud-top-right', '#intel-hud .hud-bottom-left', '#intel-hud .hud-bottom-right', - '#intel-hud .hud-top-bar', '#intel-hud .hud-bottom-bar', '#intel-hud .hud-left-edge', '#intel-hud .hud-right-edge', @@ -50,7 +49,6 @@ const RIGHT_STACK_OBSTACLE_SELECTOR = [ '#intel-hud .hud-top-right', '#intel-hud .hud-bottom-left', '#intel-hud .hud-bottom-right', - '#intel-hud .hud-top-bar', '#intel-hud .hud-bottom-bar', '#intel-hud .hud-left-edge', '#intel-hud .hud-right-edge', diff --git a/src/ui/styles/cyber.css b/src/ui/styles/cyber.css index e25bbae2d..d893b6cc7 100644 --- a/src/ui/styles/cyber.css +++ b/src/ui/styles/cyber.css @@ -1558,10 +1558,6 @@ clip-path: polygon(12px 0, 100% 0, calc(100% - 12px) 100%, 0 100%); } -#intel-hud[data-variant='cyber'] .hud-top-bar { - display: none; -} - /* Cyber keeps the useful style and locality readouts, not fictional IDs. */ #intel-hud[data-variant='cyber'] .hud-top-left .hud-classification, #intel-hud[data-variant='cyber'] .hud-top-left .hud-system { @@ -1861,7 +1857,6 @@ background-size: 78px 78px; } - #intel-hud[data-variant='cyber'] .hud-top-bar, #intel-hud[data-variant='cyber'] .hud-bottom-bar { display: none; } diff --git a/src/ui/styles/mobile-shell.css b/src/ui/styles/mobile-shell.css index aecfdf8d4..a406b8f3b 100644 --- a/src/ui/styles/mobile-shell.css +++ b/src/ui/styles/mobile-shell.css @@ -107,7 +107,6 @@ body.mobile-shell #top-center-actions { /* ── HUD: one compact readout under the top bar ────────────────────────── */ body.mobile-shell #intel-hud .hud-edge, body.mobile-shell #intel-hud .hud-corner, -body.mobile-shell #intel-hud .hud-top-bar, body.mobile-shell #intel-hud .hud-bottom-bar { display: none; } diff --git a/src/ui/styles/overlays.css b/src/ui/styles/overlays.css index f406b1294..85aaafa06 100644 --- a/src/ui/styles/overlays.css +++ b/src/ui/styles/overlays.css @@ -124,7 +124,6 @@ line-height: 1.6; } -.hud-top-bar, .hud-bottom-bar { display: none; position: absolute; @@ -141,24 +140,11 @@ pointer-events: none; } -.hud-top-bar { - top: 70px; -} - .hud-bottom-bar { bottom: 110px; justify-content: center; } -.hud-top-bar-center { - opacity: 0.84; -} - -.hud-top-bar-left, -.hud-top-bar-right { - opacity: 0.6; -} - /* Corner blocks */ .hud-corner { position: absolute; @@ -298,7 +284,6 @@ gap: 20px; } -#intel-hud[data-variant='tactical'] .hud-top-bar, #intel-hud[data-variant='tactical'] .hud-bottom-bar { display: none; } @@ -391,13 +376,13 @@ :root[data-scope-mask='off'] #intel-hud[data-variant='minimal'] - :is(.hud-top-bar, .hud-bottom-bar) { + .hud-bottom-bar { background: transparent; } :root[data-scope-mask='off'] #intel-hud[data-variant='minimal'] - :is(.hud-top-bar, .hud-bottom-bar) { + .hud-bottom-bar { width: fit-content; max-width: calc(100vw - 120px); gap: 24px; @@ -405,7 +390,7 @@ :root[data-scope-mask='off'] #intel-hud[data-variant='minimal'] - :is(.hud-top-bar, .hud-bottom-bar) + .hud-bottom-bar .hud-readout { overflow: hidden; white-space: nowrap; diff --git a/src/ui/styles/responsive.css b/src/ui/styles/responsive.css index 001c3ab3a..7a77eb665 100644 --- a/src/ui/styles/responsive.css +++ b/src/ui/styles/responsive.css @@ -98,18 +98,12 @@ display: none; } - .hud-top-bar, .hud-bottom-bar { width: calc(100vw - 24px); left: 12px; transform: none; } - .hud-top-bar { - top: 54px; - font-size: 9px; - } - .hud-bottom-bar { bottom: 90px; font-size: 9px; From ce47af6f0db279db640e5fe6ee71111a54ac11e8 Mon Sep 17 00:00:00 2001 From: Said Turksever Date: Thu, 29 Oct 2026 14:33:17 +0000 Subject: [PATCH 75/83] Restore the Snow retirement in tests the main merge overwrote The merge from main kept this branch's side of four conflicts, which dropped the Snow PR's changes: tests expected Snow again, the share-link table lost its retired mark, and the voice pins lost the Snow restore. Keep both retirements, and re-derive the full-payload digest for both enum removals. --- docs/SHARE-LINK-FORMAT.md | 58 ++++++++++++++++---------------- src/share/viewCodec.test.mjs | 3 +- src/ui/cyberTheme.test.mjs | 14 ++++---- src/voice/actionSchemas.test.mjs | 15 ++++++++- 4 files changed, 52 insertions(+), 38 deletions(-) diff --git a/docs/SHARE-LINK-FORMAT.md b/docs/SHARE-LINK-FORMAT.md index 510e71508..5728d1ec3 100644 --- a/docs/SHARE-LINK-FORMAT.md +++ b/docs/SHARE-LINK-FORMAT.md @@ -90,35 +90,35 @@ probability of about 255 in 256 (many of them already fail as base64url). ## Field registry (top level) -| # | State key | Type | Default | Encoding | -| --- | ---------------------------- | ----- | ----------- | ------------------------------------------------------- | -| 1 | `view.kind` | enum | see below | 0 place, 1 thing | -| 2 | `lat` | coord | 0 | zigzag of degrees × 10⁴ | -| 3 | `lon` | coord | 0 | zigzag of degrees × 10⁴ | -| 4 | `alt` | sint | 800 | whole metres | -| 5 | `heading` | angle | 0 | whole degrees, see angles | -| 6 | `pitch` | sint | −35 | whole degrees | -| 7 | `roll` | angle | 0 | whole degrees | -| 8 | `sharedAtMs` | epoch | none | zigzag seconds since 2026-01-01T00:00:00Z | -| 9 | booleans | flags | 0 | bit set when the value differs from default | -| 10 | `layerState.enabledLayerIds` | LEN | none | layer bitset, see layers | -| 11 | `layerState.options` | LEN | none | packed option triples, see layers | -| 12 | `panelState` | LEN | none | packed panel entries, see panels | -| 13 | thing | LEN | none | sub-message, see thing views | -| 14 | `style` | enum | `normal` | normal, retro, surveillance, thermal, anime, noir, snow | -| 15 | `mapStack` | enum | `photoreal` | photoreal, bing-aerial, bing-labels, esri-imagery, osm | -| 16 | `hudVariant` | enum | style | tactical, operator (retired), minimal, cyber | -| 17 | `bloomIntensity` | uint | style | | -| 18 | `bloomVersion` | uint | 2 | | -| 19 | `sharpenIntensity` | uint | style | | -| 20 | `detectionMode` | enum | style | OFF, SPARSE, BALANCED, DENSE | -| 21 | `detectionDensity` | uint | style | one of 0, 25, 50, 75, 100 | -| 22 | `detectionAllocation` | enum | style | ELASTIC, WEIGHTED | -| 23 | `detectionFadePct` | uint | style | 0–40 | -| 24 | `detectionOutsideOpacityPct` | uint | style | 0–100 | -| 25 | `scopeFeatherPct` | uint | 100 | 0–200 | -| 26 | `scopeTerminusPct` | uint | none | 94–100; absent is the adaptive terminus | -| 27 | `styleParams` | LEN | style | packed `(token, value × 100)` pairs | +| # | State key | Type | Default | Encoding | +| --- | ---------------------------- | ----- | ----------- | ----------------------------------------------------------------- | +| 1 | `view.kind` | enum | see below | 0 place, 1 thing | +| 2 | `lat` | coord | 0 | zigzag of degrees × 10⁴ | +| 3 | `lon` | coord | 0 | zigzag of degrees × 10⁴ | +| 4 | `alt` | sint | 800 | whole metres | +| 5 | `heading` | angle | 0 | whole degrees, see angles | +| 6 | `pitch` | sint | −35 | whole degrees | +| 7 | `roll` | angle | 0 | whole degrees | +| 8 | `sharedAtMs` | epoch | none | zigzag seconds since 2026-01-01T00:00:00Z | +| 9 | booleans | flags | 0 | bit set when the value differs from default | +| 10 | `layerState.enabledLayerIds` | LEN | none | layer bitset, see layers | +| 11 | `layerState.options` | LEN | none | packed option triples, see layers | +| 12 | `panelState` | LEN | none | packed panel entries, see panels | +| 13 | thing | LEN | none | sub-message, see thing views | +| 14 | `style` | enum | `normal` | normal, retro, surveillance, thermal, anime, noir, snow (retired) | +| 15 | `mapStack` | enum | `photoreal` | photoreal, bing-aerial, bing-labels, esri-imagery, osm | +| 16 | `hudVariant` | enum | style | tactical, operator (retired), minimal, cyber | +| 17 | `bloomIntensity` | uint | style | | +| 18 | `bloomVersion` | uint | 2 | | +| 19 | `sharpenIntensity` | uint | style | | +| 20 | `detectionMode` | enum | style | OFF, SPARSE, BALANCED, DENSE | +| 21 | `detectionDensity` | uint | style | one of 0, 25, 50, 75, 100 | +| 22 | `detectionAllocation` | enum | style | ELASTIC, WEIGHTED | +| 23 | `detectionFadePct` | uint | style | 0–40 | +| 24 | `detectionOutsideOpacityPct` | uint | style | 0–100 | +| 25 | `scopeFeatherPct` | uint | 100 | 0–200 | +| 26 | `scopeTerminusPct` | uint | none | 94–100; absent is the adaptive terminus | +| 27 | `styleParams` | LEN | style | packed `(token, value × 100)` pairs | Field 1 absent means `thing` when field 13 is present and `place` otherwise, so v1 never writes it; a later view kind writes its code. diff --git a/src/share/viewCodec.test.mjs b/src/share/viewCodec.test.mjs index e2b298fbd..6cc6fd9b1 100644 --- a/src/share/viewCodec.test.mjs +++ b/src/share/viewCodec.test.mjs @@ -450,7 +450,8 @@ test('defaults travel as frozen meanings that match today’s app defaults', () SHARE_VIEW_ENUMS.hudVariant.filter((variant) => variant !== 'operator'), [...HUD_LAYOUTS], ); - assert.deepEqual(SHARE_VIEW_ENUMS.style, [...VIEW_STYLES]); + // Snow is retired; its code stays reserved (see the retired-style test). + assert.deepEqual(SHARE_VIEW_ENUMS.style, [...VIEW_STYLES, 'snow']); assert.deepEqual(SHARE_VIEW_ENUMS.mapStack, [...VIEW_MAPS]); assert.deepEqual(SHARE_VIEW_ENUMS.detectionAllocation, [ ...ALLOCATION_STRATEGIES, diff --git a/src/ui/cyberTheme.test.mjs b/src/ui/cyberTheme.test.mjs index 733064e2d..ec9795046 100644 --- a/src/ui/cyberTheme.test.mjs +++ b/src/ui/cyberTheme.test.mjs @@ -172,7 +172,7 @@ test('a preset explicitly selected in Cyber survives exit and resets for re-entr assert.equal(owner._preCyberStyle, 'noir'); owner._setHudVariant('minimal', { applyVisualDefaults: true }); assert.equal(hud.getVariant(), 'minimal'); - assert.equal(owner.activeStyle, 'snow'); + assert.equal(owner.activeStyle, 'anime'); assert.equal(owner._preCyberStyle, null); assert.equal(owner._cyberStyleUserSelected, false); @@ -208,7 +208,7 @@ test('an authoritative same-Cyber reset clears local preset ownership', (t) => { assert.equal(owner._preCyberStyle, null); assert.equal(owner._cyberStyleUserSelected, false); owner._setHudVariant('minimal', { applyVisualDefaults: true }); - assert.equal(owner.activeStyle, 'snow'); + assert.equal(owner.activeStyle, 'anime'); }); test('Display and voice HUD routes preserve explicit Cyber entry and exit authority', async (t) => { @@ -239,12 +239,12 @@ test('Display and voice HUD routes preserve explicit Cyber entry and exit author hudLayout.dispatchEvent(new Event('change')); assert.equal(display.hud.getVariant(), 'cyber'); assert.equal(display.owner.activeStyle, 'thermal'); - snowButton.dispatchEvent(new Event('click')); - assert.equal(display.owner.activeStyle, 'snow'); + animeButton.dispatchEvent(new Event('click')); + assert.equal(display.owner.activeStyle, 'anime'); hudLayout.value = 'minimal'; hudLayout.dispatchEvent(new Event('change')); assert.equal(display.hud.getVariant(), 'minimal'); - assert.equal(display.owner.activeStyle, 'snow'); + assert.equal(display.owner.activeStyle, 'anime'); controls.destroy(); const voice = makeOwner(); @@ -265,11 +265,11 @@ test('Display and voice HUD routes preserve explicit Cyber entry and exit author assert.equal(voice.owner.activeStyle, 'thermal'); const selected = await runVoiceAction('set_visual_style', { style: 'anime' }); assert.equal(selected.ok, true); - assert.equal(voice.owner.activeStyle, 'snow'); + assert.equal(voice.owner.activeStyle, 'anime'); const exited = await runVoiceAction('set_hud', { layout: 'minimal' }); assert.equal(exited.ok, true); assert.equal(voice.hud.getVariant(), 'minimal'); - assert.equal(voice.owner.activeStyle, 'snow'); + assert.equal(voice.owner.activeStyle, 'anime'); }); test('scope choice and expanded feather survive every HUD layout and both restore paths', async (t) => { diff --git a/src/voice/actionSchemas.test.mjs b/src/voice/actionSchemas.test.mjs index e08505146..4e6586729 100644 --- a/src/voice/actionSchemas.test.mjs +++ b/src/voice/actionSchemas.test.mjs @@ -45,8 +45,9 @@ test('the complete Realtime tool payload pins the manifest-generated layer relea // S2 GhostMaps extends the generated layer enums. // Panel adds named voice targets and timeout; shared Panel/Cockpit guidance // is consolidated without changing either feature's arguments. + // Snow leaves the set_visual_style enum. // The Operator HUD layout leaves set_hud's layout enum. - '8c3c26336e4820b4b0828ab2bedf70050eca91ea3b0517a62cd8b69ea4fefc92', + 'f47a7f78f13b1f79978fa524fad2618e32bd813e1a5dfd746bf35d29909fc91b', ); }); @@ -171,6 +172,18 @@ test('all legacy action arguments are byte-identical after removing the delibera const hud = property('set_hud').layout; assert.deepEqual(hud.enum, ['tactical', 'minimal', 'cyber']); hud.enum = ['tactical', 'operator', 'minimal']; + // Snow is retired from set_visual_style; restore it to keep the legacy pin. + const visualStyle = legacy.find((tool) => tool.name === 'set_visual_style') + .parameters.properties.style; + assert.deepEqual(visualStyle.enum, [ + 'normal', + 'retro', + 'surveillance', + 'thermal', + 'anime', + 'noir', + ]); + visualStyle.enum = [...visualStyle.enum, 'snow']; // Derived by applying the same removals to the 4b56d0e9 actionSchemas. assert.equal( createHash('sha256').update(JSON.stringify(legacy)).digest('hex'), From 48a2cc069091ae1cb0395aa93b2f8fe2052af308 Mon Sep 17 00:00:00 2001 From: German Khokhlov Date: Thu, 29 Oct 2026 18:36:29 +0400 Subject: [PATCH 76/83] i18n(fr): drop the Snow strings removed in main --- src/i18n/locales/fr.json | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/i18n/locales/fr.json b/src/i18n/locales/fr.json index 68392f67d..f7c362161 100644 --- a/src/i18n/locales/fr.json +++ b/src/i18n/locales/fr.json @@ -1700,7 +1700,6 @@ "Thermal": "Thermique", "Anime": "Anime", "Noir": "Noir", - "Snow": "Neige", "Current cockpit vision style: {style}. Activate for next style.": "Style de vision actuel du cockpit : {style}. Activer pour le style suivant.", "Current style: {style} — click for next": "Style actuel : {style} — cliquer pour le suivant", "Collapse Contact panel": "Réduire le panneau Contact", @@ -2781,7 +2780,6 @@ "Simulate FLIR-style thermal contrast. Turn up Ironbow for color.": "Simuler un contraste thermique de type FLIR. Montez Ironbow pour la couleur.", "Apply bright cel-shaded color and illustrated outlines.": "Appliquer des couleurs vives en cel-shading et des contours illustrés.", "Apply high-contrast monochrome film-noir grading.": "Appliquer un étalonnage film noir monochrome à fort contraste.", - "Add a cold, snowy whiteout treatment to the scene.": "Ajouter un effet de voile blanc, froid et enneigé à la scène.", "MAP SOURCE": "SOURCE CARTE", "Map source": "Source de la carte", "Style": "Style", From aaadf708bac7280aaf945686381f29d6d8953306 Mon Sep 17 00:00:00 2001 From: German Khokhlov Date: Thu, 29 Oct 2026 19:00:19 +0400 Subject: [PATCH 77/83] i18n: Upper Trishuli in fr, it, pt and uk; drop Snow from de --- src/i18n/locales/de.json | 2 -- src/i18n/locales/fr.json | 3 ++- src/i18n/locales/it.json | 3 ++- src/i18n/locales/pt.json | 3 ++- src/i18n/locales/uk.json | 3 ++- src/i18n/same-as-english.json | 3 +++ 6 files changed, 11 insertions(+), 6 deletions(-) diff --git a/src/i18n/locales/de.json b/src/i18n/locales/de.json index 90c504d37..1612f12f0 100644 --- a/src/i18n/locales/de.json +++ b/src/i18n/locales/de.json @@ -439,7 +439,6 @@ "Thermal": "Wärmebild", "Anime": "Anime", "Noir": "Noir", - "Snow": "Schnee", "Current cockpit vision style: {style}. Activate for next style.": "Aktueller Cockpit-Sichtstil: {style}. Aktivieren für den nächsten Stil.", "Current style: {style} — click for next": "Aktueller Stil: {style}. Klicken für den nächsten", "Collapse Contact panel": "Kontaktbereich einklappen", @@ -738,7 +737,6 @@ "Simulate FLIR-style thermal contrast. Turn up Ironbow for color.": "FLIR-artigen Wärmekontrast simulieren. Ironbow aufdrehen für Farbe.", "Apply bright cel-shaded color and illustrated outlines.": "Leuchtende Cel-Shading-Farben und gezeichnete Konturen anwenden.", "Apply high-contrast monochrome film-noir grading.": "Kontrastreiche monochrome Film-noir-Farbgebung anwenden.", - "Add a cold, snowy whiteout treatment to the scene.": "Kalten, verschneiten Whiteout-Effekt auf die Szene legen.", "MAP SOURCE": "KARTENQUELLE", "Map source": "Kartenquelle", "Style": "Stil", diff --git a/src/i18n/locales/fr.json b/src/i18n/locales/fr.json index f7c362161..58b918b34 100644 --- a/src/i18n/locales/fr.json +++ b/src/i18n/locales/fr.json @@ -3004,5 +3004,6 @@ "ESC to dismiss": "ESC pour fermer", "Tip: the GEV MIC button in the dock lets you talk to the map.": "Astuce : le bouton GEV MIC du dock permet de parler à la carte.", "Malformed cyclone snapshot": "Instantané cyclonique mal formé", - "Cyclone request timed out": "Délai dépassé pour la requête cyclonique" + "Cyclone request timed out": "Délai dépassé pour la requête cyclonique", + "Upper Trishuli": "Upper Trishuli" } diff --git a/src/i18n/locales/it.json b/src/i18n/locales/it.json index 502b50605..cb81e7066 100644 --- a/src/i18n/locales/it.json +++ b/src/i18n/locales/it.json @@ -3004,5 +3004,6 @@ "ESC to dismiss": "ESC per chiudere", "Tip: the GEV MIC button in the dock lets you talk to the map.": "Suggerimento: il pulsante GEV MIC nel dock ti permette di parlare con la mappa.", "Malformed cyclone snapshot": "Snapshot dei cicloni non valido", - "Cyclone request timed out": "La richiesta dei cicloni è andata in timeout" + "Cyclone request timed out": "La richiesta dei cicloni è andata in timeout", + "Upper Trishuli": "Alto Trishuli" } diff --git a/src/i18n/locales/pt.json b/src/i18n/locales/pt.json index f139e517a..eaf4c74f3 100644 --- a/src/i18n/locales/pt.json +++ b/src/i18n/locales/pt.json @@ -3004,5 +3004,6 @@ "Begin with a clean globe": "Comece com um globo limpo", "Don't show this again": "Não mostrar novamente", "ESC to dismiss": "ESC para fechar", - "Tip: the GEV MIC button in the dock lets you talk to the map.": "Dica: o botão GEV MIC no dock permite falar com o mapa." + "Tip: the GEV MIC button in the dock lets you talk to the map.": "Dica: o botão GEV MIC no dock permite falar com o mapa.", + "Upper Trishuli": "Upper Trishuli" } diff --git a/src/i18n/locales/uk.json b/src/i18n/locales/uk.json index 2e6fa95c0..ecbd84301 100644 --- a/src/i18n/locales/uk.json +++ b/src/i18n/locales/uk.json @@ -3073,5 +3073,6 @@ "ESC to dismiss": "ESC — приховати", "Tip: the GEV MIC button in the dock lets you talk to the map.": "Порада: кнопка МІК у доку дає змогу говорити з картою.", "Malformed cyclone snapshot": "Некоректний знімок циклонів", - "Cyclone request timed out": "Минув час очікування запиту циклонів" + "Cyclone request timed out": "Минув час очікування запиту циклонів", + "Upper Trishuli": "Upper Trishuli" } diff --git a/src/i18n/same-as-english.json b/src/i18n/same-as-english.json index 8dcb1b8af..4b047818f 100644 --- a/src/i18n/same-as-english.json +++ b/src/i18n/same-as-english.json @@ -435,6 +435,7 @@ "Train", "Trance", "USB {rate} msg/s", + "Upper Trishuli", "VOLUME", "VS", "WHOT/BHOT", @@ -740,6 +741,7 @@ "Techno", "Trance", "USB {rate} msg/s", + "Upper Trishuli", "V/S {rate}", "VISUAL", "VOLUME", @@ -797,6 +799,7 @@ "NVG", "REC", "S2 GhostMaps", + "Upper Trishuli", "WHOT/BHOT" ], "zh-CN": [ From 6ab9432a2a5369d25dce266c2c1016c4ef11913c Mon Sep 17 00:00:00 2001 From: German Khokhlov Date: Thu, 29 Oct 2026 19:01:00 +0400 Subject: [PATCH 78/83] changelog: German (#1477) --- changelog.d/1477-german.md | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 changelog.d/1477-german.md diff --git a/changelog.d/1477-german.md b/changelog.d/1477-german.md new file mode 100644 index 000000000..77d7717b6 --- /dev/null +++ b/changelog.d/1477-german.md @@ -0,0 +1,3 @@ +- Add German (de) to the language picker, with a full translation of the + interface and a German style guide in docs/translations/de.md. Based on + translations by @abiyeenzo (#908) (German, @gekh, #1477). From 56ca3402580211efbb2c629c11358af02cb38f85 Mon Sep 17 00:00:00 2001 From: German Khokhlov Date: Thu, 29 Oct 2026 19:36:02 +0400 Subject: [PATCH 79/83] i18n: keep Upper Trishuli as a place name; drop duplicate cyclone keys --- src/data/bhoteKoshiEmbeddedMedia.js | 1 - src/i18n/locales/de.json | 3 +-- src/i18n/locales/es.json | 3 --- src/i18n/locales/fr.json | 3 +-- src/i18n/locales/it.json | 5 ++--- src/i18n/locales/pt.json | 3 +-- src/i18n/locales/ru.json | 3 --- src/i18n/locales/uk.json | 3 +-- src/i18n/locales/zh-CN.json | 3 --- src/i18n/locales/zh-Hant.json | 3 --- src/i18n/same-as-english.json | 7 ------- 11 files changed, 6 insertions(+), 31 deletions(-) diff --git a/src/data/bhoteKoshiEmbeddedMedia.js b/src/data/bhoteKoshiEmbeddedMedia.js index 49f704066..1ea0ccec9 100644 --- a/src/data/bhoteKoshiEmbeddedMedia.js +++ b/src/data/bhoteKoshiEmbeddedMedia.js @@ -66,7 +66,6 @@ const EVENT_PACK_TEXT = new Set([ msg('Border gate'), msg('Timure evidence cluster'), msg('Mailung / Upper Trishuli bridge'), - msg('Upper Trishuli'), msg('Dandagaun viewpoint restaurant'), msg('Dandagaun viewpoint'), msg('Bidur - Trishuli bridge'), diff --git a/src/i18n/locales/de.json b/src/i18n/locales/de.json index 1612f12f0..143788867 100644 --- a/src/i18n/locales/de.json +++ b/src/i18n/locales/de.json @@ -932,8 +932,7 @@ "Gyirong border gate": "Grenzübergang Gyirong", "Border gate": "Grenzübergang", "Timure evidence cluster": "Beweiscluster Timure", - "Mailung / Upper Trishuli bridge": "Mailung / Brücke am oberen Trishuli", - "Upper Trishuli": "Oberer Trishuli", + "Mailung / Upper Trishuli bridge": "Mailung / Brücke am Upper Trishuli", "Dandagaun viewpoint restaurant": "Aussichtsrestaurant Dandagaun", "Dandagaun viewpoint": "Aussichtspunkt Dandagaun", "Bidur - Trishuli bridge": "Bidur – Trishuli-Brücke", diff --git a/src/i18n/locales/es.json b/src/i18n/locales/es.json index 8903e4b04..8cbdf6ab5 100644 --- a/src/i18n/locales/es.json +++ b/src/i18n/locales/es.json @@ -1990,7 +1990,6 @@ "Border gate": "Paso fronterizo", "Timure evidence cluster": "Grupo de evidencias de Timure", "Mailung / Upper Trishuli bridge": "Mailung / puente de Upper Trishuli", - "Upper Trishuli": "Upper Trishuli", "Dandagaun viewpoint restaurant": "Restaurante mirador de Dandagaun", "Dandagaun viewpoint": "Mirador de Dandagaun", "Bidur - Trishuli bridge": "Puente Bidur - Trishuli", @@ -3004,8 +3003,6 @@ "Voice replies appear here.": "Las respuestas de voz aparecen aquí.", "Preview is off.": "La vista previa está desactivada.", "Automatic stop is unavailable for this voice connection.": "La parada automática no está disponible para esta conexión de voz.", - "Cyclone request timed out": "La petición de ciclones agotó el tiempo de espera", - "Malformed cyclone snapshot": "Instantánea de ciclones mal formada", "routing busy — too many routes at once": "servicio de rutas ocupado: demasiadas rutas a la vez", "route proxy error": "error del proxy de rutas" } diff --git a/src/i18n/locales/fr.json b/src/i18n/locales/fr.json index 58b918b34..f7c362161 100644 --- a/src/i18n/locales/fr.json +++ b/src/i18n/locales/fr.json @@ -3004,6 +3004,5 @@ "ESC to dismiss": "ESC pour fermer", "Tip: the GEV MIC button in the dock lets you talk to the map.": "Astuce : le bouton GEV MIC du dock permet de parler à la carte.", "Malformed cyclone snapshot": "Instantané cyclonique mal formé", - "Cyclone request timed out": "Délai dépassé pour la requête cyclonique", - "Upper Trishuli": "Upper Trishuli" + "Cyclone request timed out": "Délai dépassé pour la requête cyclonique" } diff --git a/src/i18n/locales/it.json b/src/i18n/locales/it.json index cb81e7066..96c319129 100644 --- a/src/i18n/locales/it.json +++ b/src/i18n/locales/it.json @@ -63,7 +63,7 @@ "Gyirong border gate": "Valico di frontiera di Gyirong", "Border gate": "Valico di frontiera", "Timure evidence cluster": "Gruppo di prove di Timure", - "Mailung / Upper Trishuli bridge": "Ponte di Mailung / Alto Trishuli", + "Mailung / Upper Trishuli bridge": "Ponte di Mailung / Upper Trishuli", "Dandagaun viewpoint restaurant": "Ristorante panoramico di Dandagaun", "Dandagaun viewpoint": "Punto panoramico di Dandagaun", "Bidur - Trishuli bridge": "Ponte di Bidur - Trishuli", @@ -3004,6 +3004,5 @@ "ESC to dismiss": "ESC per chiudere", "Tip: the GEV MIC button in the dock lets you talk to the map.": "Suggerimento: il pulsante GEV MIC nel dock ti permette di parlare con la mappa.", "Malformed cyclone snapshot": "Snapshot dei cicloni non valido", - "Cyclone request timed out": "La richiesta dei cicloni è andata in timeout", - "Upper Trishuli": "Alto Trishuli" + "Cyclone request timed out": "La richiesta dei cicloni è andata in timeout" } diff --git a/src/i18n/locales/pt.json b/src/i18n/locales/pt.json index eaf4c74f3..f139e517a 100644 --- a/src/i18n/locales/pt.json +++ b/src/i18n/locales/pt.json @@ -3004,6 +3004,5 @@ "Begin with a clean globe": "Comece com um globo limpo", "Don't show this again": "Não mostrar novamente", "ESC to dismiss": "ESC para fechar", - "Tip: the GEV MIC button in the dock lets you talk to the map.": "Dica: o botão GEV MIC no dock permite falar com o mapa.", - "Upper Trishuli": "Upper Trishuli" + "Tip: the GEV MIC button in the dock lets you talk to the map.": "Dica: o botão GEV MIC no dock permite falar com o mapa." } diff --git a/src/i18n/locales/ru.json b/src/i18n/locales/ru.json index 5d143a66b..0e8632bf3 100644 --- a/src/i18n/locales/ru.json +++ b/src/i18n/locales/ru.json @@ -2023,7 +2023,6 @@ "Border gate": "Погранпереход", "Timure evidence cluster": "Группа свидетельств у Timure", "Mailung / Upper Trishuli bridge": "Mailung / мост Upper Trishuli", - "Upper Trishuli": "Upper Trishuli", "Dandagaun viewpoint restaurant": "Ресторан со смотровой площадкой, Dandagaun", "Dandagaun viewpoint": "Смотровая площадка Dandagaun", "Bidur - Trishuli bridge": "Мост Bidur — Trishuli", @@ -3073,8 +3072,6 @@ "Voice replies appear here.": "Здесь появляются голосовые ответы.", "Preview is off.": "Предпросмотр отключён.", "Automatic stop is unavailable for this voice connection.": "Автоматическая остановка недоступна для этого голосового подключения.", - "Cyclone request timed out": "Истекло время ожидания запроса о циклонах", - "Malformed cyclone snapshot": "Некорректный снимок данных о циклонах", "routing busy — too many routes at once": "сервис маршрутов занят: слишком много маршрутов одновременно", "route proxy error": "ошибка прокси маршрутов" } diff --git a/src/i18n/locales/uk.json b/src/i18n/locales/uk.json index ecbd84301..2e6fa95c0 100644 --- a/src/i18n/locales/uk.json +++ b/src/i18n/locales/uk.json @@ -3073,6 +3073,5 @@ "ESC to dismiss": "ESC — приховати", "Tip: the GEV MIC button in the dock lets you talk to the map.": "Порада: кнопка МІК у доку дає змогу говорити з картою.", "Malformed cyclone snapshot": "Некоректний знімок циклонів", - "Cyclone request timed out": "Минув час очікування запиту циклонів", - "Upper Trishuli": "Upper Trishuli" + "Cyclone request timed out": "Минув час очікування запиту циклонів" } diff --git a/src/i18n/locales/zh-CN.json b/src/i18n/locales/zh-CN.json index 2c3acc495..06fa38a18 100644 --- a/src/i18n/locales/zh-CN.json +++ b/src/i18n/locales/zh-CN.json @@ -62,7 +62,6 @@ "Border gate": "边境口岸", "Timure evidence cluster": "Timure 证据群", "Mailung / Upper Trishuli bridge": "Mailung / Upper Trishuli 桥", - "Upper Trishuli": "Upper Trishuli", "Dandagaun viewpoint restaurant": "Dandagaun 观景餐厅", "Dandagaun viewpoint": "Dandagaun 观景点", "Bidur - Trishuli bridge": "Bidur - Trishuli 桥", @@ -2866,8 +2865,6 @@ "other": "{count} 个地标" }, "S2 Underground publishes these KMZ products to GitHub. New uploads are detected within seconds and replace the previous edition automatically. Click a marker for its report.": "S2 Underground 在 GitHub 发布这些 KMZ 产品。新上传的内容会在数秒内被检测到,并自动替换旧版本。点击标记查看报告。", - "Cyclone request timed out": "气旋请求超时", - "Malformed cyclone snapshot": "气旋快照格式错误", "routing busy — too many routes at once": "路线服务繁忙:同时请求的路线过多", "route proxy error": "路线代理出错" } diff --git a/src/i18n/locales/zh-Hant.json b/src/i18n/locales/zh-Hant.json index 23ce082a4..d594f0212 100644 --- a/src/i18n/locales/zh-Hant.json +++ b/src/i18n/locales/zh-Hant.json @@ -62,7 +62,6 @@ "Border gate": "邊境口岸", "Timure evidence cluster": "Timure 證據群", "Mailung / Upper Trishuli bridge": "Mailung / Upper Trishuli 橋", - "Upper Trishuli": "Upper Trishuli", "Dandagaun viewpoint restaurant": "Dandagaun 觀景餐廳", "Dandagaun viewpoint": "Dandagaun 觀景點", "Bidur - Trishuli bridge": "Bidur - Trishuli 橋", @@ -2866,8 +2865,6 @@ "other": "{count} 個地標" }, "S2 Underground publishes these KMZ products to GitHub. New uploads are detected within seconds and replace the previous edition automatically. Click a marker for its report.": "S2 Underground 在 GitHub 發布這些 KMZ 產品。新上傳的內容會在數秒內被檢測到,並自動替換舊版本。點擊標記查看報告。", - "Cyclone request timed out": "氣旋請求超時", - "Malformed cyclone snapshot": "氣旋快照格式錯誤", "routing busy — too many routes at once": "路線服務繁忙:同時請求的路線過多", "route proxy error": "路線代理出錯" } diff --git a/src/i18n/same-as-english.json b/src/i18n/same-as-english.json index 4b047818f..6023b6502 100644 --- a/src/i18n/same-as-english.json +++ b/src/i18n/same-as-english.json @@ -258,7 +258,6 @@ "Techno", "Trance", "USB {rate} msg/s", - "Upper Trishuli", "VISUAL", "VS", "WHOT/BHOT", @@ -435,7 +434,6 @@ "Train", "Trance", "USB {rate} msg/s", - "Upper Trishuli", "VOLUME", "VS", "WHOT/BHOT", @@ -741,7 +739,6 @@ "Techno", "Trance", "USB {rate} msg/s", - "Upper Trishuli", "V/S {rate}", "VISUAL", "VOLUME", @@ -784,7 +781,6 @@ "REC", "S2 GhostMaps", "S2 · {name}", - "Upper Trishuli", "VS", "WHOT/BHOT" ], @@ -799,7 +795,6 @@ "NVG", "REC", "S2 GhostMaps", - "Upper Trishuli", "WHOT/BHOT" ], "zh-CN": [ @@ -835,7 +830,6 @@ "Techno", "Trance", "USB {rate} msg/s", - "Upper Trishuli", "WHOT/BHOT", "dB", "ft", @@ -893,7 +887,6 @@ "Techno", "Trance", "USB {rate} msg/s", - "Upper Trishuli", "WHOT/BHOT", "dB", "ft", From 32d6ce4ea56bff8ff4bf6b8576de44eacfbf5c8a Mon Sep 17 00:00:00 2001 From: German Khokhlov Date: Thu, 29 Oct 2026 19:47:54 +0400 Subject: [PATCH 80/83] i18n(ja): translate strings new in main, drop Snow --- src/i18n/locales/ja.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/i18n/locales/ja.json b/src/i18n/locales/ja.json index b7c045555..6844a967e 100644 --- a/src/i18n/locales/ja.json +++ b/src/i18n/locales/ja.json @@ -1652,7 +1652,6 @@ "Thermal": "サーマル", "Anime": "アニメ", "Noir": "ノワール", - "Snow": "雪", "Current cockpit vision style: {style}. Activate for next style.": "現在のコックピットビジョンスタイル:{style}。押すと次のスタイルに切り替わります。", "Current style: {style} — click for next": "現在のスタイル:{style}。クリックで次へ", "Collapse Contact panel": "コンタクトパネルを折りたたむ", @@ -2641,7 +2640,6 @@ "Simulate FLIR-style thermal contrast. Turn up Ironbow for color.": "FLIR風の熱コントラストを再現します。色を付けるにはIronbowを上げてください。", "Apply bright cel-shaded color and illustrated outlines.": "明るいセルシェーディングの色と輪郭線を適用します。", "Apply high-contrast monochrome film-noir grading.": "コントラストの強いモノクロのフィルムノワール調に仕上げます。", - "Add a cold, snowy whiteout treatment to the scene.": "冷たい雪のホワイトアウト効果をシーンに加えます。", "MAP SOURCE": "マップソース", "Map source": "マップソース", "Style": "スタイル", @@ -2866,5 +2864,7 @@ "ESC to dismiss": "Escで閉じる", "Tip: the GEV MIC button in the dock lets you talk to the map.": "ヒント:ドックの[マイク]ボタンで地図に話しかけられます。", "routing busy — too many routes at once": "ルート検索サービスが混雑しています。同時に要求されたルートが多すぎます", - "route proxy error": "ルート検索プロキシでエラーが発生しました" + "route proxy error": "ルート検索プロキシでエラーが発生しました", + "Malformed cyclone snapshot": "サイクロンのスナップショットの形式が不正です", + "Cyclone request timed out": "サイクロンのリクエストがタイムアウトしました" } From 29692ac7a13fa661709643a1af8c95c2f5049abe Mon Sep 17 00:00:00 2001 From: German Khokhlov Date: Thu, 29 Oct 2026 19:48:33 +0400 Subject: [PATCH 81/83] changelog: Japanese (#1478) --- changelog.d/1478-japanese.md | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 changelog.d/1478-japanese.md diff --git a/changelog.d/1478-japanese.md b/changelog.d/1478-japanese.md new file mode 100644 index 000000000..376853e24 --- /dev/null +++ b/changelog.d/1478-japanese.md @@ -0,0 +1,4 @@ +- Add Japanese (ja) to the language picker, with year-first dates, Japanese + counters, unit words joined to their numbers (5分前, 1時間5分) and CJK label + rules for Japanese text. Based on translations by @abiyeenzo (#913) + (German, @gekh, #1478). From 151e7ad5fd5fc5cb7e5b68de7bdf34dd2723fa8c Mon Sep 17 00:00:00 2001 From: Said Turksever Date: Thu, 29 Oct 2026 15:54:40 +0000 Subject: [PATCH 82/83] Drop the Operator string from the German and French catalogs The catalogs merged from main still carried the retired layout's label, so the catalog tests failed. --- src/i18n/locales/de.json | 1 - src/i18n/locales/fr.json | 1 - 2 files changed, 2 deletions(-) diff --git a/src/i18n/locales/de.json b/src/i18n/locales/de.json index 143788867..84306d25c 100644 --- a/src/i18n/locales/de.json +++ b/src/i18n/locales/de.json @@ -792,7 +792,6 @@ "Layout": "Layout", "HUD layout": "HUD-Layout", "Tactical": "Taktisch", - "Operator": "Operator", "Minimal": "Minimal", "Detection Overlay (D)": "Erkennungs-Overlay (D)", "Detection overlay": "Erkennungs-Overlay", diff --git a/src/i18n/locales/fr.json b/src/i18n/locales/fr.json index f7c362161..1487c7f5b 100644 --- a/src/i18n/locales/fr.json +++ b/src/i18n/locales/fr.json @@ -2860,7 +2860,6 @@ "Layout": "Disposition", "HUD layout": "Disposition du HUD", "Tactical": "Tactique", - "Operator": "Opérateur", "Minimal": "Minimal", "Cyber": "Cyber", "Sonar": "Sonar", From a8127c968b59b9953d980d75c0b856926c32e497 Mon Sep 17 00:00:00 2001 From: Said Turksever Date: Thu, 29 Oct 2026 16:29:42 +0000 Subject: [PATCH 83/83] Drop the Operator string from the Japanese catalog The catalog merged from main still carried the retired layout's label, so the catalog test failed. The Japanese glossary drops it too. --- docs/translations/ja.md | 2 +- src/i18n/locales/ja.json | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/docs/translations/ja.md b/docs/translations/ja.md index 2253bdc45..9e612e8e4 100644 --- a/docs/translations/ja.md +++ b/docs/translations/ja.md @@ -61,7 +61,7 @@ Translation source: abiyeenzo (#913). | scene / shot | シーン / ショット | | briefing / panel / dock | ブリーフィング / パネル / ドック | | preset / visual preset | プリセット / ビジュアルプリセット | -| Tactical / Operator / Minimal / Cyber | タクティカル / オペレーター / ミニマル / サイバー | +| Tactical / Minimal / Cyber | タクティカル / ミニマル / サイバー | | Scope (circular viewport mask) / keyhole | スコープ / キーホール | | Clean UI | クリーンUI | | cockpit | コックピット | diff --git a/src/i18n/locales/ja.json b/src/i18n/locales/ja.json index 6844a967e..0e33ea4a4 100644 --- a/src/i18n/locales/ja.json +++ b/src/i18n/locales/ja.json @@ -2720,7 +2720,6 @@ "Layout": "レイアウト", "HUD layout": "HUDレイアウト", "Tactical": "タクティカル", - "Operator": "オペレーター", "Minimal": "ミニマル", "Cyber": "サイバー", "Sonar": "ソナー",