diff --git a/src/hud.js b/src/hud.js index 6c157ddd3..400a4d51e 100644 --- a/src/hud.js +++ b/src/hud.js @@ -113,7 +113,7 @@ function localizedProvenanceTag(provenance) { ? t(FEED_STATE_LABELS[provenance.state]) : provenance.state.toUpperCase(); if (!provenance.names.length) return state; - return t('{state}: {layers}', { + return t('{state} {layers}', { state, layers: provenance.names .map((name) => localizeLayerName(name).toUpperCase()) diff --git a/src/i18n/locales/es.json b/src/i18n/locales/es.json index 4245a62e3..c9459c31c 100644 --- a/src/i18n/locales/es.json +++ b/src/i18n/locales/es.json @@ -2010,7 +2010,6 @@ "Box and images cleared": "Recuadro e imágenes borrados", "Box is {size} wide · limit {limit}": "El recuadro mide {size} · límite {limit}", "View is {size} wide · limit {limit}": "La vista mide {size} · límite {limit}", - "{state}: {layers}": "{state}: {layers}", "{mode} · {band} · {locality} | {region} | ALT {alt} | WINDOW {window} | SUN {sun}° | ONA {ona}° | {zone}": "{mode} · {band} · {locality} | {region} | ALT {alt} | VENTANA {window} | SUN {sun}° | ONA {ona}° | {zone}", "Frame unavailable; previous observation retained": "Fotograma no disponible; se mantiene la observación anterior", "Weather imagery unavailable": "Imágenes meteorológicas no disponibles", @@ -2023,5 +2022,8 @@ "Globe imagery unavailable": "Imágenes del globo no disponibles", "Globe field image unavailable": "Imagen del campo en el globo no disponible", "status chip|UNAVAILABLE": "NO DISP.", - "Uses registered content or linked media. Those external files are not included in a scene bundle. Their original notices still apply.": "Usa contenido registrado o medios vinculados. Esos archivos externos no se incluyen en un paquete de escena. Sus avisos originales siguen vigentes." + "Uses registered content or linked media. Those external files are not included in a scene bundle. Their original notices still apply.": "Usa contenido registrado o medios vinculados. Esos archivos externos no se incluyen en un paquete de escena. Sus avisos originales siguen vigentes.", + "{state} {layers}": "{state}: {layers}", + "Selected Space Mission": "Misión espacial seleccionada", + "{duration}s + {hold}s": "{duration} s + {hold} s" } diff --git a/src/i18n/locales/ru.json b/src/i18n/locales/ru.json index 223db7d44..bb32eb792 100644 --- a/src/i18n/locales/ru.json +++ b/src/i18n/locales/ru.json @@ -2042,7 +2042,6 @@ "Box and images cleared": "Область и снимки сброшены", "Box is {size} wide · limit {limit}": "Область шириной {size} · предел {limit}", "View is {size} wide · limit {limit}": "Вид шириной {size} · предел {limit}", - "{state}: {layers}": "{state}: {layers}", "{mode} · {band} · {locality} | {region} | ALT {alt} | WINDOW {window} | SUN {sun}° | ONA {ona}° | {zone}": "{mode} · {band} · {locality} | {region} | ALT {alt} | ОКНО {window} | SUN {sun}° | ONA {ona}° | {zone}", "Frame unavailable; previous observation retained": "Кадр недоступен; показано предыдущее наблюдение", "Weather imagery unavailable": "Погодные снимки недоступны", @@ -2055,5 +2054,8 @@ "Globe imagery unavailable": "Снимки глобуса недоступны", "Globe field image unavailable": "Изображение поля на глобусе недоступно", "status chip|UNAVAILABLE": "НЕДОСТ.", - "Uses registered content or linked media. Those external files are not included in a scene bundle. Their original notices still apply.": "Используется зарегистрированный контент или связанные медиафайлы. Эти внешние файлы не входят в архив сцены. Их исходные уведомления по-прежнему действуют." + "Uses registered content or linked media. Those external files are not included in a scene bundle. Their original notices still apply.": "Используется зарегистрированный контент или связанные медиафайлы. Эти внешние файлы не входят в архив сцены. Их исходные уведомления по-прежнему действуют.", + "{state} {layers}": "{state}: {layers}", + "Selected Space Mission": "Выбранная космическая миссия", + "{duration}s + {hold}s": "{duration} с + {hold} с" } diff --git a/src/layers/launches/panel.js b/src/layers/launches/panel.js index 65ee3fbdc..291a0ecba 100644 --- a/src/layers/launches/panel.js +++ b/src/layers/launches/panel.js @@ -470,7 +470,7 @@ export function createPanel({ state: layerState, services, parts, source }) { layerState._missionPanel.className = 'context-space-mission-detail'; layerState._missionPanel.setAttribute( 'aria-label', - t('SELECTED SPACE MISSION'), + t('Selected Space Mission'), ); layerState._missionPanel.innerHTML = `
${t('SELECTED SPACE MISSION')}
${t('MISSION')}${t('STATUS · ')}${t('LAUNCH SITE · ')}${t('LAUNCH TIME · ')}${t('ORBIT · ')}${t('ASCENT PATH · ')}${t('CURRENT DISTANCE FROM EARTH · ')}${t('SATELLITE SPEED · ')}

${t('PAYLOAD')}

${t('NAME')}${t('TYPE')}${t('DESTINATION')}

${t('STAGE / RE-ENTRY / RECOVERY')}

${t('STAGE')}${t('STATUS')}${t('FINAL POSITION')}
1×
—
`; layerState._missionPanel diff --git a/src/ui/layerPanel.js b/src/ui/layerPanel.js index f32cb2b73..75cecad62 100644 --- a/src/ui/layerPanel.js +++ b/src/ui/layerPanel.js @@ -129,10 +129,11 @@ const PANEL_LABELS = { 'local-firms': msg('Active Fires'), }; +// The panel's own English names win, as before i18n; module names otherwise. function panelLabel(layer) { + if (PANEL_LABELS[layer.id]) return t(PANEL_LABELS[layer.id]); const key = LAYER_NAME_KEYS[layer.id]; - if (key) return t(key); - return PANEL_LABELS[layer.id] ? t(PANEL_LABELS[layer.id]) : layer.name; + return key ? t(key) : layer.name; } // English module names (layer.name) that other surfaces print, such as the diff --git a/src/ui/layerPanel.test.mjs b/src/ui/layerPanel.test.mjs index aa4d30f28..5e7305f80 100644 --- a/src/ui/layerPanel.test.mjs +++ b/src/ui/layerPanel.test.mjs @@ -327,5 +327,5 @@ test('the unavailable chip may abbreviate, but its accessible name keeps the ful }); assert.equal(button.textContent, 'UNAVAILABLE'); assert.equal(button.dataset.feedState, 'unavailable'); - assert.match(attrs.get('aria-label'), /^FIRMS Active Fires: UNAVAILABLE\./); + assert.match(attrs.get('aria-label'), /^Active Fires: UNAVAILABLE\./); }); diff --git a/src/ui/scenePresentation.js b/src/ui/scenePresentation.js index 727975a6b..258ee5059 100644 --- a/src/ui/scenePresentation.js +++ b/src/ui/scenePresentation.js @@ -1,6 +1,5 @@ /** Scene panel elements and text-only project presentation. */ -import { msg, t } from '../i18n/index.js'; -import { formatQuantity } from './unitLabels.js'; +import { formatNumber, msg, t } from '../i18n/index.js'; // Labels for what a shot stores; anything else shows as stored. Style names // match STYLE_STATUS_LABELS in visualPresets.js, which this package cannot @@ -145,11 +144,16 @@ export function renderSceneShots( ? t(DETECTION_MODE_LABELS[mode]) : mode; const seconds = (value) => - formatQuantity(value, 's', { + formatNumber(value, { minimumFractionDigits: 1, maximumFractionDigits: 1, }); - meta.textContent = `${styleLabel} · ${modeLabel} · ${seconds(shot.durationSec)} + ${seconds(shot.holdSec)}`; + // English keeps its compact "4.0s + 0.9s"; other languages space the unit. + const timing = t('{duration}s + {hold}s', { + duration: seconds(shot.durationSec), + hold: seconds(shot.holdSec), + }); + meta.textContent = `${styleLabel} · ${modeLabel} · ${timing}`; row.appendChild(top); row.appendChild(meta); element.appendChild(row);