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')}
0.25×1×4×
—
`;
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);