From 978cd72ac246cf6cb3ad1c4f7c83c09e174b32f9 Mon Sep 17 00:00:00 2001 From: Enzo Abyie Date: Wed, 28 Oct 2026 12:36:27 +0400 Subject: [PATCH 01/26] 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 ce17d0cade1b6f35bb8a4c68c09d5522c9078a7b Mon Sep 17 00:00:00 2001 From: Enzo Abyie Date: Wed, 28 Oct 2026 12:37:19 +0400 Subject: [PATCH 02/26] 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 2172183dc7581c3d1010c57dfea3064903eb6dc4 Mon Sep 17 00:00:00 2001 From: German Khokhlov Date: Wed, 28 Oct 2026 12:51:02 +0400 Subject: [PATCH 03/26] 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 04/26] 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 05/26] 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 9de9106883d87f038d41286d2acec24d966e62c0 Mon Sep 17 00:00:00 2001 From: German Khokhlov Date: Wed, 28 Oct 2026 15:03:34 +0400 Subject: [PATCH 06/26] 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 56a36df006780a4b0ee551f25bfd463b3129b506 Mon Sep 17 00:00:00 2001 From: German Khokhlov Date: Wed, 28 Oct 2026 15:10:32 +0400 Subject: [PATCH 07/26] 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 5e47a2afbdb5a66a86929cc1e0252555d8d2d2d5 Mon Sep 17 00:00:00 2001 From: German Khokhlov Date: Wed, 28 Oct 2026 17:02:55 +0400 Subject: [PATCH 08/26] 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 3c0c10d3b1259ada7945f7c1bec964707fe88d69 Mon Sep 17 00:00:00 2001 From: German Khokhlov Date: Wed, 28 Oct 2026 16:39:34 +0400 Subject: [PATCH 09/26] 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 b96c1dee151b59e443c45e38697f443fecf750b8 Mon Sep 17 00:00:00 2001 From: German Khokhlov Date: Wed, 28 Oct 2026 17:41:29 +0400 Subject: [PATCH 10/26] 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 858ce827e50a7e9659e35a1dffc7c1a964ceebaf Mon Sep 17 00:00:00 2001 From: German Khokhlov Date: Wed, 28 Oct 2026 17:57:51 +0400 Subject: [PATCH 11/26] 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 6cf47c6ca84484b50c44d31a9b39495b3945b643 Mon Sep 17 00:00:00 2001 From: German Khokhlov Date: Wed, 28 Oct 2026 22:35:44 +0400 Subject: [PATCH 12/26] 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 40485359215c086b1de0fae45820c3023c5bb33b Mon Sep 17 00:00:00 2001 From: German Khokhlov Date: Wed, 28 Oct 2026 22:40:38 +0400 Subject: [PATCH 13/26] 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 4c80c38e2c7ae7617722447283bd489036210dd2 Mon Sep 17 00:00:00 2001 From: German Khokhlov Date: Wed, 28 Oct 2026 23:43:22 +0400 Subject: [PATCH 14/26] 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 a96ad30c996407c47c2a764982a3eb7aecd2c413 Mon Sep 17 00:00:00 2001 From: German Khokhlov Date: Wed, 28 Oct 2026 23:47:45 +0400 Subject: [PATCH 15/26] 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 6c524b229c6640cc12e48e8bb817363063f8bf64 Mon Sep 17 00:00:00 2001 From: German Khokhlov Date: Thu, 29 Oct 2026 14:24:50 +0400 Subject: [PATCH 16/26] 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 17/26] 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 eab345a46534d42109439781525d886e84899fec Mon Sep 17 00:00:00 2001 From: German Khokhlov Date: Thu, 29 Oct 2026 14:50:08 +0400 Subject: [PATCH 18/26] 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 f8e96e1484afe1bce4644b008a3f319c3f27b6ef Mon Sep 17 00:00:00 2001 From: German Khokhlov Date: Thu, 29 Oct 2026 14:54:44 +0400 Subject: [PATCH 19/26] 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 20/26] 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 21/26] 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 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 22/26] 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 23/26] 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 24/26] 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 25/26] 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 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 26/26] 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,