i18n(pt): apply review round 1

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 <[email protected]>
This commit is contained in:
German KhokhlovandClaude Opus 5.5 committed 2026-10-28 17:17:23 +04:00
1 parent 56a36df006
commit 3c0c10d3b1
10 files changed
+136 -76

No files matched your search

+18 -5
View File
@@ -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 |
+1
View File
@@ -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}",
+63 -62
View File
@@ -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",
+1
View File
@@ -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}",
+1
View File
@@ -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": "风场上游数据源不可用",
+1
View File
@@ -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": "風場上游數據源不可用",
+2
View File
@@ -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",
+5 -1
View File
@@ -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 {
+21 -8
View File
@@ -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,
),
);
}
+23
View File
@@ -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);
});