mirror of
https://github.com/bilawalsidhu/gods-eye-view.git
synced 2026-11-06 11:24:00 +00:00
fix(i18n): Spanish review fixes; report translations left in English
A screenshot review of the Spanish UI found: - Text left in English. Catalog entries copied from English (Bloom, Cyber, Pin, NEWS, SITE, ON/OFF, RANGE, PITCH, HGT…) and the radio music genres, which never went through t(). The genres are translated in es and ru now. - Wording: gender agreement, calques of the English, hints that name buttons that do not exist, and one concept worded two ways. - Layout: the DESACTIVADO pill squeezed layer names until words broke mid-word; the scene and camera selects showed one word; a collapsed rail title pushed its button out of the card; the image slot line and a comparison readout were cut or split. The layout fixes are scoped to languages other than English, so English stays pixel-identical. Visual-style slider values now use the locale's decimal separator (0,85). npm run i18n now reports a translation that is identical to the English, unless src/i18n/same-as-english.json lists it for that language (codes, product names, words spelled the same). Co-Authored-By: Claude Opus 5.5 <[email protected]>
This commit is contained in:
1 parent
9f1e409193
commit
7db0abc396
16 files changed
+400
-104
No files matched your search
+4
-1
@@ -58,6 +58,8 @@ Changing the English changes the key, so the old translation goes unused and the
|
|||||||
|
|
||||||
To see a language, open the app with `?lang=ru`, or use the language switch in the Visual Presets dock.
|
To see a language, open the app with `?lang=ru`, or use the language switch in the Visual Presets dock.
|
||||||
|
|
||||||
|
A translation that is exactly the English ("Bloom" → "Bloom") is reported as still English. When it is right on purpose, such as a code (HDG, CRT), a product name or a word spelled the same in that language, list it under the language in `src/i18n/same-as-english.json`.
|
||||||
|
|
||||||
## Text the check reports as unmarked
|
## Text the check reports as unmarked
|
||||||
|
|
||||||
`npm run i18n` also lists UI text that is not marked at all, and fails while there is any; `npm test` runs the same check:
|
`npm run i18n` also lists UI text that is not marked at all, and fails while there is any; `npm test` runs the same check:
|
||||||
@@ -78,9 +80,10 @@ Icons (`aria-hidden="true"`, Material Symbols), comments, CSS values and lowerca
|
|||||||
## Where things live
|
## Where things live
|
||||||
|
|
||||||
| File | What it holds |
|
| File | What it holds |
|
||||||
| ------------------------------ | ------------------------------------------------------------------------------ |
|
| ------------------------------- | ------------------------------------------------------------------------------ |
|
||||||
| `src/i18n/index.js` | `t`, `tn`, `msg`, the Intl formatters, markup translation, switching language |
|
| `src/i18n/index.js` | `t`, `tn`, `msg`, the Intl formatters, markup translation, switching language |
|
||||||
| `src/i18n/locale.js` | shipped languages, their names, choosing the language at boot |
|
| `src/i18n/locale.js` | shipped languages, their names, choosing the language at boot |
|
||||||
| `src/i18n/locales/<code>.json` | one catalog per language, keyed by English text |
|
| `src/i18n/locales/<code>.json` | one catalog per language, keyed by English text |
|
||||||
|
| `src/i18n/same-as-english.json` | per language, the entries that stay as in English on purpose |
|
||||||
| `scripts/i18n.mjs` | `npm run i18n`: extracts messages, checks the catalogs, finds unmarked UI text |
|
| `scripts/i18n.mjs` | `npm run i18n`: extracts messages, checks the catalogs, finds unmarked UI text |
|
||||||
| `src/i18n/catalog.test.mjs` | runs that check under `npm test` |
|
| `src/i18n/catalog.test.mjs` | runs that check under `npm test` |
|
||||||
+1
-1
@@ -32,7 +32,7 @@ npm run i18n -- --missing ru # missing ru entries as JSON, ready to transla
|
|||||||
npm run i18n -- --prune # drop entries the code no longer uses
|
npm run i18n -- --prune # drop entries the code no longer uses
|
||||||
```
|
```
|
||||||
|
|
||||||
`npm test` runs the same check (`src/i18n/catalog.test.mjs`). It fails when a translation is missing, when an entry is no longer used, when placeholders differ from the English, or when a plural entry lacks a form.
|
`npm test` runs the same check (`src/i18n/catalog.test.mjs`). It fails when a translation is missing, when an entry is no longer used, when placeholders differ from the English, when a plural entry lacks a form, or when a translation is still the English text. If an entry is right as it is in English (a code such as HDG, a product name, a word spelled the same in your language), add it under your language code in `src/i18n/same-as-english.json`.
|
||||||
|
|
||||||
Changing English text changes its key: the old translation becomes unused and the new text shows as missing. Translate it and prune.
|
Changing English text changes its key: the old translation becomes unused and the new text shows as missing. Translate it and prune.
|
||||||
|
|
||||||
|
|||||||
+29
-1
@@ -4,6 +4,10 @@
|
|||||||
// npm run i18n -- --prune also drop entries the code no longer uses
|
// npm run i18n -- --prune also drop entries the code no longer uses
|
||||||
// npm run i18n -- --missing ru print what ru lacks, as JSON to translate
|
// npm run i18n -- --missing ru print what ru lacks, as JSON to translate
|
||||||
//
|
//
|
||||||
|
// A translation identical to the English is reported too, unless it is
|
||||||
|
// listed for that locale in src/i18n/same-as-english.json (codes, product
|
||||||
|
// names, words spelled the same in both languages).
|
||||||
|
//
|
||||||
// Messages are the English literals passed to t(), tn() and msg() in src/,
|
// Messages are the English literals passed to t(), tn() and msg() in src/,
|
||||||
// plus the markup opted in with data-i18n* in src/ui/templates and index.html.
|
// plus the markup opted in with data-i18n* in src/ui/templates and index.html.
|
||||||
// It also lists UI text that is not marked at all (see findUnmarked).
|
// It also lists UI text that is not marked at all (see findUnmarked).
|
||||||
@@ -14,6 +18,7 @@ import { fileURLToPath } from 'node:url';
|
|||||||
|
|
||||||
const ROOT = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..');
|
const ROOT = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..');
|
||||||
const LOCALES_DIR = path.join(ROOT, 'src/i18n/locales');
|
const LOCALES_DIR = path.join(ROOT, 'src/i18n/locales');
|
||||||
|
const SAME_AS_ENGLISH = path.join(ROOT, 'src/i18n/same-as-english.json');
|
||||||
|
|
||||||
const STRING = String.raw`'(?:\\.|[^'\\\n])*'|"(?:\\.|[^"\\\n])*"|\`(?:\\.|[^\`\\$])*\``;
|
const STRING = String.raw`'(?:\\.|[^'\\\n])*'|"(?:\\.|[^"\\\n])*"|\`(?:\\.|[^\`\\$])*\``;
|
||||||
const CALL = new RegExp(
|
const CALL = new RegExp(
|
||||||
@@ -424,11 +429,26 @@ export function shippedLocales() {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Messages a locale keeps exactly as in English, on purpose. */
|
||||||
|
export function readSameAsEnglish(locale) {
|
||||||
|
const lists = JSON.parse(readFileSync(SAME_AS_ENGLISH, 'utf8'));
|
||||||
|
return new Set(lists[locale] || []);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** The English a message shows: its text without the "context|" prefix. */
|
||||||
|
const englishOf = (text) => text.slice(text.indexOf('|') + 1);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Compare one catalog with the extracted messages.
|
* Compare one catalog with the extracted messages.
|
||||||
|
* @param {Set<string>} [sameAsEnglish] Messages allowed to read as English.
|
||||||
* @returns {{missing: string[], stale: string[], errors: string[]}}
|
* @returns {{missing: string[], stale: string[], errors: string[]}}
|
||||||
*/
|
*/
|
||||||
export function checkCatalog(locale, catalog, messages) {
|
export function checkCatalog(
|
||||||
|
locale,
|
||||||
|
catalog,
|
||||||
|
messages,
|
||||||
|
sameAsEnglish = readSameAsEnglish(locale),
|
||||||
|
) {
|
||||||
const categories = new Intl.PluralRules(locale).resolvedOptions()
|
const categories = new Intl.PluralRules(locale).resolvedOptions()
|
||||||
.pluralCategories;
|
.pluralCategories;
|
||||||
const missing = [];
|
const missing = [];
|
||||||
@@ -456,6 +476,14 @@ export function checkCatalog(locale, catalog, messages) {
|
|||||||
errors.push(`"${text}" must be a string`);
|
errors.push(`"${text}" must be a string`);
|
||||||
} else if (placeholders(entry) !== placeholders(text)) {
|
} else if (placeholders(entry) !== placeholders(text)) {
|
||||||
errors.push(`"${text}" placeholders differ: ${entry}`);
|
errors.push(`"${text}" placeholders differ: ${entry}`);
|
||||||
|
} else if (
|
||||||
|
entry === englishOf(text) &&
|
||||||
|
/\p{L}{2}/u.test(entry.replace(/\{[^}]*\}/g, '')) &&
|
||||||
|
!sameAsEnglish.has(text)
|
||||||
|
) {
|
||||||
|
errors.push(
|
||||||
|
`"${text}" is still English: translate it, or list it under "${locale}" in src/i18n/same-as-english.json`,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
const stale = Object.keys(catalog).filter((text) => !messages.has(text));
|
const stale = Object.keys(catalog).filter((text) => !messages.has(text));
|
||||||
|
|||||||
@@ -66,6 +66,28 @@ test('checkCatalog reports missing, stale, placeholder and plural problems', ()
|
|||||||
assert.equal(result.errors.length, 2);
|
assert.equal(result.errors.length, 2);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('checkCatalog reports a translation left in English unless it is allowed', () => {
|
||||||
|
const fixture = new Map([
|
||||||
|
['Bloom', { plural: false }],
|
||||||
|
['HDG', { plural: false }],
|
||||||
|
['voice|READY', { plural: false }],
|
||||||
|
['{state} · {source}', { plural: false }],
|
||||||
|
]);
|
||||||
|
const catalog = {
|
||||||
|
Bloom: 'Bloom',
|
||||||
|
HDG: 'HDG',
|
||||||
|
'voice|READY': 'READY',
|
||||||
|
'{state} · {source}': '{state} · {source}',
|
||||||
|
};
|
||||||
|
const errors = (allowed) =>
|
||||||
|
checkCatalog('es', catalog, fixture, new Set(allowed)).errors;
|
||||||
|
assert.deepEqual(
|
||||||
|
errors([]).map((error) => error.split(' is still English')[0]),
|
||||||
|
['"Bloom"', '"HDG"', '"voice|READY"'],
|
||||||
|
);
|
||||||
|
assert.deepEqual(errors(['Bloom', 'HDG', 'voice|READY']), []);
|
||||||
|
});
|
||||||
|
|
||||||
test('unmarkedMarkup finds text and attributes without data-i18n*', () => {
|
test('unmarkedMarkup finds text and attributes without data-i18n*', () => {
|
||||||
const texts = (html) => unmarkedMarkup('f.html', html).map((f) => f.text);
|
const texts = (html) => unmarkedMarkup('f.html', html).map((f) => f.text);
|
||||||
assert.deepEqual(texts('<span>Close</span>'), ['Close']);
|
assert.deepEqual(texts('<span>Close</span>'), ['Close']);
|
||||||
|
|||||||
+92
-66
@@ -31,7 +31,7 @@
|
|||||||
"RETRYING MAPPED SITES": "REINTENTANDO SITIOS MAPEADOS",
|
"RETRYING MAPPED SITES": "REINTENTANDO SITIOS MAPEADOS",
|
||||||
"FETCHING MAPPED SITES": "OBTENIENDO SITIOS MAPEADOS",
|
"FETCHING MAPPED SITES": "OBTENIENDO SITIOS MAPEADOS",
|
||||||
"TURNING OFF LIVE DATA": "DESACTIVANDO DATOS EN VIVO",
|
"TURNING OFF LIVE DATA": "DESACTIVANDO DATOS EN VIVO",
|
||||||
"REFRESHING LIVE DATA": "ACTUALIZANDO DATOS EN VIVO",
|
"REFRESHING LIVE DATA": "ACTUALIZANDO DATOS",
|
||||||
"Close data attribution": "Cerrar la atribución de datos",
|
"Close data attribution": "Cerrar la atribución de datos",
|
||||||
"Aircraft cockpit view": "Vista de cabina de la aeronave",
|
"Aircraft cockpit view": "Vista de cabina de la aeronave",
|
||||||
"EXIT COCKPIT": "SALIR DE CABINA",
|
"EXIT COCKPIT": "SALIR DE CABINA",
|
||||||
@@ -103,8 +103,8 @@
|
|||||||
"Celestial": "Celeste",
|
"Celestial": "Celeste",
|
||||||
"Hide UI chrome": "Ocultar los elementos de la interfaz",
|
"Hide UI chrome": "Ocultar los elementos de la interfaz",
|
||||||
"Clean UI": "Interfaz limpia",
|
"Clean UI": "Interfaz limpia",
|
||||||
"Bloom / Glow": "Bloom / Resplandor",
|
"Bloom / Glow": "Resplandor",
|
||||||
"Bloom": "Bloom",
|
"Bloom": "Resplandor",
|
||||||
"Sharpening": "Nitidez",
|
"Sharpening": "Nitidez",
|
||||||
"Sharpen": "Nitidez",
|
"Sharpen": "Nitidez",
|
||||||
"LOCATION": "UBICACIÓN",
|
"LOCATION": "UBICACIÓN",
|
||||||
@@ -222,8 +222,8 @@
|
|||||||
"Collapse Radio section": "Contraer la sección de Radio",
|
"Collapse Radio section": "Contraer la sección de Radio",
|
||||||
"Searched location": "Ubicación buscada",
|
"Searched location": "Ubicación buscada",
|
||||||
"Disable cockpit weather effects": "Desactivar los efectos climáticos de la cabina",
|
"Disable cockpit weather effects": "Desactivar los efectos climáticos de la cabina",
|
||||||
"ON": "ACTIVADO",
|
"ON": "ACTIVO",
|
||||||
"OFF": "DESACTIVADO",
|
"OFF": "INACTIVO",
|
||||||
"Restore real aircraft": "Restaurar la aeronave real",
|
"Restore real aircraft": "Restaurar la aeronave real",
|
||||||
"Night vision": "Visión nocturna",
|
"Night vision": "Visión nocturna",
|
||||||
"Thermal": "Térmica",
|
"Thermal": "Térmica",
|
||||||
@@ -277,8 +277,8 @@
|
|||||||
"Expand briefing panel": "Expandir el panel de información",
|
"Expand briefing panel": "Expandir el panel de información",
|
||||||
"CYCLE ON": "CICLO: SÍ",
|
"CYCLE ON": "CICLO: SÍ",
|
||||||
"CYCLE OFF": "CICLO: NO",
|
"CYCLE OFF": "CICLO: NO",
|
||||||
"Stop automatic page cycling. Previous, Next, and the SIG/NEWS/LOCAL tabs stay available.": "Detén el cambio automático de páginas. Anterior, Siguiente y las pestañas SIG/NEWS/LOCAL siguen disponibles.",
|
"Stop automatic page cycling. Previous, Next, and the SIG/NEWS/LOCAL tabs stay available.": "Detén el cambio automático de páginas. Anterior, Siguiente y las pestañas SIG/NOTICIAS/LOCAL siguen disponibles.",
|
||||||
"REGIONAL NEWS": "NOTICIAS REGIONALES",
|
"REGIONAL NEWS": "NOTICIAS DE ZONA",
|
||||||
"LOCAL INFO": "INFORMACIÓN LOCAL",
|
"LOCAL INFO": "INFORMACIÓN LOCAL",
|
||||||
"LATEST LOCATION-MATCHED REPORTING": "ÚLTIMOS REPORTES SEGÚN UBICACIÓN",
|
"LATEST LOCATION-MATCHED REPORTING": "ÚLTIMOS REPORTES SEGÚN UBICACIÓN",
|
||||||
"PLACE / CONDITIONS / POSITION": "LUGAR / CLIMA / POSICIÓN",
|
"PLACE / CONDITIONS / POSITION": "LUGAR / CLIMA / POSICIÓN",
|
||||||
@@ -358,9 +358,9 @@
|
|||||||
"CAL · {badge}": "CAL · {badge}",
|
"CAL · {badge}": "CAL · {badge}",
|
||||||
"CALIBRATED": "CALIBRADA",
|
"CALIBRATED": "CALIBRADA",
|
||||||
"CURATED": "CURADA",
|
"CURATED": "CURADA",
|
||||||
"RAW PRIOR": "PREVIA SIN PROCESAR",
|
"RAW PRIOR": "ESTIMACIÓN INICIAL",
|
||||||
"MONITOR": "MONITOR",
|
"MONITOR": "MONITOR",
|
||||||
"{city} · HDG {heading} · FOV {fov} · RANGE {range}m · {projection}{calBadge} · {provider}{status}": "{city} · HDG {heading} · FOV {fov} · RANGE {range} m · {projection}{calBadge} · {provider}{status}",
|
"{city} · HDG {heading} · FOV {fov} · RANGE {range}m · {projection}{calBadge} · {provider}{status}": "{city} · HDG {heading} · FOV {fov} · DIST. {range} m · {projection}{calBadge} · {provider}{status}",
|
||||||
"{count} cameras loaded · click a camera to activate": {
|
"{count} cameras loaded · click a camera to activate": {
|
||||||
"one": "{count} cámara cargada · haz clic en una cámara para activarla",
|
"one": "{count} cámara cargada · haz clic en una cámara para activarla",
|
||||||
"many": "{count} de cámaras cargadas · haz clic en una cámara para activarla",
|
"many": "{count} de cámaras cargadas · haz clic en una cámara para activarla",
|
||||||
@@ -385,7 +385,7 @@
|
|||||||
"Awaiting telemetry...": "Esperando telemetría...",
|
"Awaiting telemetry...": "Esperando telemetría...",
|
||||||
"REC": "REC",
|
"REC": "REC",
|
||||||
"Scope edge feather": "Difuminado del borde de la mirilla",
|
"Scope edge feather": "Difuminado del borde de la mirilla",
|
||||||
"Bloom intensity": "Intensidad del bloom",
|
"Bloom intensity": "Intensidad del resplandor",
|
||||||
"Sharpen intensity": "Intensidad de la nitidez",
|
"Sharpen intensity": "Intensidad de la nitidez",
|
||||||
"Search location by name or coordinates": "Buscar ubicación por nombre o coordenadas",
|
"Search location by name or coordinates": "Buscar ubicación por nombre o coordenadas",
|
||||||
"Expand LOCATION": "Expandir UBICACIÓN",
|
"Expand LOCATION": "Expandir UBICACIÓN",
|
||||||
@@ -412,7 +412,7 @@
|
|||||||
"CCTV camera": "Cámara CCTV",
|
"CCTV camera": "Cámara CCTV",
|
||||||
"FOCUS": "ENFOCAR",
|
"FOCUS": "ENFOCAR",
|
||||||
"COVERAGE OFF": "COBERTURA DESACTIVADA",
|
"COVERAGE OFF": "COBERTURA DESACTIVADA",
|
||||||
"AUTO HOP OFF": "AUTOSALTO DESACTIVADO",
|
"AUTO HOP OFF": "SALTO AUTOMÁTICO: NO",
|
||||||
"PROJECTION ON": "PROYECCIÓN ACTIVADA",
|
"PROJECTION ON": "PROYECCIÓN ACTIVADA",
|
||||||
"CALIBRATION": "CALIBRACIÓN",
|
"CALIBRATION": "CALIBRACIÓN",
|
||||||
"ADJUST": "AJUSTAR",
|
"ADJUST": "AJUSTAR",
|
||||||
@@ -435,7 +435,7 @@
|
|||||||
"STATION TAG": "ETIQUETA DE EMISORA",
|
"STATION TAG": "ETIQUETA DE EMISORA",
|
||||||
"Filter stations by station tag": "Filtrar emisoras por etiqueta de emisora",
|
"Filter stations by station tag": "Filtrar emisoras por etiqueta de emisora",
|
||||||
"NO STATION SELECTED": "NINGUNA EMISORA SELECCIONADA",
|
"NO STATION SELECTED": "NINGUNA EMISORA SELECCIONADA",
|
||||||
"Enable Radio, then choose a globe marker or use next.": "Activa Radio y elige un marcador del globo o usa siguiente.",
|
"Enable Radio, then choose a globe marker or use next.": "Activa Radio y elige un marcador del globo o pulsa SIG.",
|
||||||
"DIRECTORY BAND": "BANDA DEL DIRECTORIO",
|
"DIRECTORY BAND": "BANDA DEL DIRECTORIO",
|
||||||
"DRAG TO TUNE": "ARRASTRA PARA SINTONIZAR",
|
"DRAG TO TUNE": "ARRASTRA PARA SINTONIZAR",
|
||||||
"ALL · DRAG THE NEEDLE": "TODAS · ARRASTRA LA AGUJA",
|
"ALL · DRAG THE NEEDLE": "TODAS · ARRASTRA LA AGUJA",
|
||||||
@@ -450,7 +450,7 @@
|
|||||||
"Radio volume": "Volumen de Radio",
|
"Radio volume": "Volumen de Radio",
|
||||||
"Radio off": "Radio desactivada",
|
"Radio off": "Radio desactivada",
|
||||||
"STATION SITE": "SITIO DE LA EMISORA",
|
"STATION SITE": "SITIO DE LA EMISORA",
|
||||||
"Audio connects directly to the broadcaster after you press play. Your IP is visible to that broadcaster.": "El audio se conecta directamente con la emisora después de pulsar reproducir. Tu IP es visible para esa emisora.",
|
"Audio connects directly to the broadcaster after you press play. Your IP is visible to that broadcaster.": "El audio se conecta directamente con la emisora después de pulsar ESCUCHAR. Tu IP es visible para esa emisora.",
|
||||||
"LOADING": "CARGANDO",
|
"LOADING": "CARGANDO",
|
||||||
"DEGRADED": "DEGRADADO",
|
"DEGRADED": "DEGRADADO",
|
||||||
"STALE": "DESACTUALIZADO",
|
"STALE": "DESACTUALIZADO",
|
||||||
@@ -458,7 +458,7 @@
|
|||||||
"PARTIAL": "PARCIAL",
|
"PARTIAL": "PARCIAL",
|
||||||
"UNCERTAIN": "INCIERTO",
|
"UNCERTAIN": "INCIERTO",
|
||||||
"ENABLING": "ACTIVANDO",
|
"ENABLING": "ACTIVANDO",
|
||||||
"DISABLING": "DESACTIVANDO",
|
"DISABLING": "APAGANDO",
|
||||||
"Military Flights": "Vuelos militares",
|
"Military Flights": "Vuelos militares",
|
||||||
"Satellites": "Satélites",
|
"Satellites": "Satélites",
|
||||||
"Space Missions (30d)": "Misiones espaciales (30d)",
|
"Space Missions (30d)": "Misiones espaciales (30d)",
|
||||||
@@ -476,7 +476,7 @@
|
|||||||
"{count}s ago": "hace {count}s",
|
"{count}s ago": "hace {count}s",
|
||||||
"{count}m ago": "hace {count} min",
|
"{count}m ago": "hace {count} min",
|
||||||
"{count}h ago": "hace {count} h",
|
"{count}h ago": "hace {count} h",
|
||||||
"never": "nunca",
|
"never": "sin actualizar",
|
||||||
"loading...": "cargando...",
|
"loading...": "cargando...",
|
||||||
"UNCERTAIN · {source} · lifecycle state requires reconciliation": "INCIERTO · {source} · el estado del ciclo de vida requiere reconciliación",
|
"UNCERTAIN · {source} · lifecycle state requires reconciliation": "INCIERTO · {source} · el estado del ciclo de vida requiere reconciliación",
|
||||||
"{state} · {source}": "{state} · {source}",
|
"{state} · {source}": "{state} · {source}",
|
||||||
@@ -517,11 +517,11 @@
|
|||||||
"POS: {time}Z": "POS: {time}Z",
|
"POS: {time}Z": "POS: {time}Z",
|
||||||
"AIS: --": "AIS: --",
|
"AIS: --": "AIS: --",
|
||||||
"AIS: {name}": "AIS: {name}",
|
"AIS: {name}": "AIS: {name}",
|
||||||
"{type} SPD: {speed} HDG: {heading}": "{type} SPD: {speed} HDG: {heading}",
|
"{type} SPD: {speed} HDG: {heading}": "{type} VEL: {speed} HDG: {heading}",
|
||||||
"awaiting first AIS position…": "esperando la primera posición AIS…",
|
"awaiting first AIS position…": "esperando la primera posición AIS…",
|
||||||
"CCTV ON": "CCTV ACTIVADO",
|
"CCTV ON": "CCTV ACTIVADO",
|
||||||
"COVERAGE ON": "COBERTURA ACTIVADA",
|
"COVERAGE ON": "COBERTURA ACTIVADA",
|
||||||
"AUTO HOP ON": "AUTOSALTO ACTIVADO",
|
"AUTO HOP ON": "SALTO AUTOMÁTICO: SÍ",
|
||||||
"PROJECTION OFF": "PROYECCIÓN DESACTIVADA",
|
"PROJECTION OFF": "PROYECCIÓN DESACTIVADA",
|
||||||
"ADJUST ON": "AJUSTE ACTIVADO",
|
"ADJUST ON": "AJUSTE ACTIVADO",
|
||||||
"{count} CAMERAS STANDING BY · NO CAMERA SELECTED · CLICK A CAMERA TO ACTIVATE": "{count} CÁMARAS EN ESPERA · NINGUNA CÁMARA SELECCIONADA · CLIC EN UNA CÁMARA PARA ACTIVARLA",
|
"{count} CAMERAS STANDING BY · NO CAMERA SELECTED · CLICK A CAMERA TO ACTIVATE": "{count} CÁMARAS EN ESPERA · NINGUNA CÁMARA SELECCIONADA · CLIC EN UNA CÁMARA PARA ACTIVARLA",
|
||||||
@@ -555,9 +555,9 @@
|
|||||||
"Reconcile Radio — lifecycle uncertain": "Reconciliar Radio — ciclo de vida incierto",
|
"Reconcile Radio — lifecycle uncertain": "Reconciliar Radio — ciclo de vida incierto",
|
||||||
"Loading station directory…": "Cargando el directorio de emisoras…",
|
"Loading station directory…": "Cargando el directorio de emisoras…",
|
||||||
"Directory metadata only": "Solo metadatos del directorio",
|
"Directory metadata only": "Solo metadatos del directorio",
|
||||||
"Choose a globe marker or use next.": "Elige un marcador del globo o usa siguiente.",
|
"Choose a globe marker or use next.": "Elige un marcador del globo o pulsa SIG.",
|
||||||
"TAGS · {tags}": "ETIQUETAS · {tags}",
|
"TAGS · {tags}": "ETIQUETAS · {tags}",
|
||||||
"Ready — playback starts only from your action": "Lista — la reproducción comienza solo con tu acción",
|
"Ready — playback starts only from your action": "Preparada: la reproducción empieza cuando pulses ESCUCHAR",
|
||||||
"Connecting directly to broadcaster…": "Conectando directamente con la emisora…",
|
"Connecting directly to broadcaster…": "Conectando directamente con la emisora…",
|
||||||
"Buffering broadcaster stream…": "Almacenando en búfer el flujo de la emisora…",
|
"Buffering broadcaster stream…": "Almacenando en búfer el flujo de la emisora…",
|
||||||
"Playing {station}": "Reproduciendo {station}",
|
"Playing {station}": "Reproduciendo {station}",
|
||||||
@@ -655,7 +655,7 @@
|
|||||||
"COMMS": "TELECOM",
|
"COMMS": "TELECOM",
|
||||||
"Broadband constellation shell — shown only in DENSE mode": "Capa de constelación de banda ancha — visible solo en modo DENSO",
|
"Broadband constellation shell — shown only in DENSE mode": "Capa de constelación de banda ancha — visible solo en modo DENSO",
|
||||||
"refreshing...": "actualizando...",
|
"refreshing...": "actualizando...",
|
||||||
"KEY REQUIRED": "CLAVE REQUERIDA",
|
"KEY REQUIRED": "CLAVE REQUERIDA",
|
||||||
"STALE · cached {age}": "DESACTUALIZADO · en caché hace {age}",
|
"STALE · cached {age}": "DESACTUALIZADO · en caché hace {age}",
|
||||||
"LIVE · updated {age}": "EN VIVO · actualizado {age}",
|
"LIVE · updated {age}": "EN VIVO · actualizado {age}",
|
||||||
"<1m ago": "hace <1 min",
|
"<1m ago": "hace <1 min",
|
||||||
@@ -663,7 +663,7 @@
|
|||||||
"▲ {frp} MW": "▲ {frp} MW",
|
"▲ {frp} MW": "▲ {frp} MW",
|
||||||
"FIRE": "INCENDIO",
|
"FIRE": "INCENDIO",
|
||||||
"FIRES": "INCENDIOS",
|
"FIRES": "INCENDIOS",
|
||||||
"{value} conf": "{value} conf",
|
"{value} conf": "{value} de confianza",
|
||||||
"{value} ago": "hace {value}",
|
"{value} ago": "hace {value}",
|
||||||
"max {value} MW": "máx {value} MW",
|
"max {value} MW": "máx {value} MW",
|
||||||
"new {value}": "nueva hace {value}",
|
"new {value}": "nueva hace {value}",
|
||||||
@@ -748,7 +748,7 @@
|
|||||||
"Close key setup": "Cerrar la configuración de claves",
|
"Close key setup": "Cerrar la configuración de claves",
|
||||||
"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.": "El globo ya vuela sin claves. Cada clave de abajo activa otra fuente real — pega una y queda guardada en la configuración local de esta app, y luego el servidor se reinicia solo. Las claves del servidor se quedan en esta máquina; Google Maps y Cesium ion funcionan en el navegador y sus claves deben estar restringidas por el proveedor. Las claves que configuraste en otro lugar se muestran, pero nunca se modifican.",
|
"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.": "El globo ya vuela sin claves. Cada clave de abajo activa otra fuente real — pega una y queda guardada en la configuración local de esta app, y luego el servidor se reinicia solo. Las claves del servidor se quedan en esta máquina; Google Maps y Cesium ion funcionan en el navegador y sus claves deben estar restringidas por el proveedor. Las claves que configuraste en otro lugar se muestran, pero nunca se modifican.",
|
||||||
"ESC to close": "ESC para cerrar",
|
"ESC to close": "ESC para cerrar",
|
||||||
"The Google Maps key buys the photorealistic planet — everything else stacks on top.": "La clave de Google Maps compra el planeta fotorrealista — todo lo demás se monta encima.",
|
"The Google Maps key buys the photorealistic planet — everything else stacks on top.": "La clave de Google Maps activa el planeta fotorrealista; todo lo demás se superpone.",
|
||||||
"SCENES": "ESCENAS",
|
"SCENES": "ESCENAS",
|
||||||
"Scene recipe": "Receta de escena",
|
"Scene recipe": "Receta de escena",
|
||||||
"NEW": "NUEVA",
|
"NEW": "NUEVA",
|
||||||
@@ -831,7 +831,7 @@
|
|||||||
"Could not exit {mode} — scene layers may be refused": "No se pudo salir de {mode} — las capas de la escena pueden rechazarse",
|
"Could not exit {mode} — scene layers may be refused": "No se pudo salir de {mode} — las capas de la escena pueden rechazarse",
|
||||||
"REMOVE": "ELIMINAR",
|
"REMOVE": "ELIMINAR",
|
||||||
"Remove {title} from this app's saved keys": "Elimina {title} de las claves guardadas de esta app",
|
"Remove {title} from this app's saved keys": "Elimina {title} de las claves guardadas de esta app",
|
||||||
"Needs {envVars} — add it in Provider Settings": "Necesita {envVars} — añádela en Ajustes de proveedores",
|
"Needs {envVars} — add it in Provider Settings": "Necesita {envVars} — se añade en Ajustes de proveedores",
|
||||||
"Places context + Street View fallback; optional separate key": "Contexto de Places + respaldo de Street View; clave separada opcional",
|
"Places context + Street View fallback; optional separate key": "Contexto de Places + respaldo de Street View; clave separada opcional",
|
||||||
"Live ships, worldwide": "Buques en vivo, en todo el mundo",
|
"Live ships, worldwide": "Buques en vivo, en todo el mundo",
|
||||||
"Live active-fire detections": "Detecciones de incendios activos en vivo",
|
"Live active-fire detections": "Detecciones de incendios activos en vivo",
|
||||||
@@ -872,8 +872,8 @@
|
|||||||
"WHOT/BHOT": "WHOT/BHOT",
|
"WHOT/BHOT": "WHOT/BHOT",
|
||||||
"Ironbow": "Ironbow",
|
"Ironbow": "Ironbow",
|
||||||
"Pick a shape, then click the map.": "Elige una forma y haz clic en el mapa.",
|
"Pick a shape, then click the map.": "Elige una forma y haz clic en el mapa.",
|
||||||
"Enter to place the pin, Esc to cancel.": "Enter para colocar el pin, Esc para cancelar.",
|
"Enter to place the pin, Esc to cancel.": "Enter para colocar el marcador, Esc para cancelar.",
|
||||||
"Click where the pin goes.": "Haz clic donde va el pin.",
|
"Click where the pin goes.": "Haz clic donde quieras colocar el marcador.",
|
||||||
"Click {count} more points.": {
|
"Click {count} more points.": {
|
||||||
"one": "Haz clic en {count} punto más.",
|
"one": "Haz clic en {count} punto más.",
|
||||||
"many": "Haz clic en {count} de puntos más.",
|
"many": "Haz clic en {count} de puntos más.",
|
||||||
@@ -892,7 +892,7 @@
|
|||||||
"Shape to draw": "Forma a dibujar",
|
"Shape to draw": "Forma a dibujar",
|
||||||
"Area": "Área",
|
"Area": "Área",
|
||||||
"Line": "Línea",
|
"Line": "Línea",
|
||||||
"Pin": "Pin",
|
"Pin": "Marcador",
|
||||||
"Label (optional)": "Etiqueta (opcional)",
|
"Label (optional)": "Etiqueta (opcional)",
|
||||||
"Label for the drawn shape": "Etiqueta de la forma dibujada",
|
"Label for the drawn shape": "Etiqueta de la forma dibujada",
|
||||||
"Colour of the drawn shape": "Color de la forma dibujada",
|
"Colour of the drawn shape": "Color de la forma dibujada",
|
||||||
@@ -910,7 +910,7 @@
|
|||||||
"Bike Share": "Bicis compartidas",
|
"Bike Share": "Bicis compartidas",
|
||||||
"Cameras": "Cámaras",
|
"Cameras": "Cámaras",
|
||||||
"Street Level": "A pie de calle",
|
"Street Level": "A pie de calle",
|
||||||
"Mapped ALPR Cameras": "Cámaras ALPR cartografiadas",
|
"Mapped ALPR Cameras": "Cámaras ALPR mapeadas",
|
||||||
"Data Centers": "Centros de datos",
|
"Data Centers": "Centros de datos",
|
||||||
"Active Fires": "Incendios activos",
|
"Active Fires": "Incendios activos",
|
||||||
"Street Level could not start": "No se pudo iniciar A pie de calle",
|
"Street Level could not start": "No se pudo iniciar A pie de calle",
|
||||||
@@ -946,9 +946,9 @@
|
|||||||
"Switch a provider on to draw its coverage.": "Activa un proveedor para dibujar su cobertura.",
|
"Switch a provider on to draw its coverage.": "Activa un proveedor para dibujar su cobertura.",
|
||||||
"Loading this sequence…": "Cargando esta secuencia…",
|
"Loading this sequence…": "Cargando esta secuencia…",
|
||||||
"{n} images in this sequence · Esc clears": {
|
"{n} images in this sequence · Esc clears": {
|
||||||
"one": "{n} imagen en esta secuencia · Esc la quita",
|
"one": "{n} imagen en esta secuencia · Esc quita la selección",
|
||||||
"many": "{n} de imágenes en esta secuencia · Esc la quita",
|
"many": "{n} de imágenes en esta secuencia · Esc quita la selección",
|
||||||
"other": "{n} imágenes en esta secuencia · Esc la quita"
|
"other": "{n} imágenes en esta secuencia · Esc quita la selección"
|
||||||
},
|
},
|
||||||
"{n} sequences in view · click a line for its photos": {
|
"{n} sequences in view · click a line for its photos": {
|
||||||
"one": "{n} secuencia a la vista · haz clic en una línea para ver sus fotos",
|
"one": "{n} secuencia a la vista · haz clic en una línea para ver sus fotos",
|
||||||
@@ -1038,7 +1038,7 @@
|
|||||||
"Play reconstruction": "Reproducir la reconstrucción",
|
"Play reconstruction": "Reproducir la reconstrucción",
|
||||||
"Load previous scene shot": "Cargar el plano anterior de la escena",
|
"Load previous scene shot": "Cargar el plano anterior de la escena",
|
||||||
"Load next scene shot": "Cargar el siguiente plano de la escena",
|
"Load next scene shot": "Cargar el siguiente plano de la escena",
|
||||||
"SCHEMATIC CORRIDOR, NOT MODELED ARRIVAL TIME.": "CORREDOR ESQUEMÁTICO, NO TIEMPO DE LLEGADA MODELADO.",
|
"SCHEMATIC CORRIDOR, NOT MODELED ARRIVAL TIME.": "CORREDOR ESQUEMÁTICO; NO ES UN TIEMPO DE LLEGADA MODELADO.",
|
||||||
"Rasuwa · 26 Aug 2026": "Rasuwa · 26 ago 2026",
|
"Rasuwa · 26 Aug 2026": "Rasuwa · 26 ago 2026",
|
||||||
"Event reconstruction": "Reconstrucción del evento",
|
"Event reconstruction": "Reconstrucción del evento",
|
||||||
"INITIATION": "INICIO",
|
"INITIATION": "INICIO",
|
||||||
@@ -1047,8 +1047,8 @@
|
|||||||
"BORDER ARRIVAL": "LLEGADA A LA FRONTERA",
|
"BORDER ARRIVAL": "LLEGADA A LA FRONTERA",
|
||||||
"PROPAGATION": "PROPAGACIÓN",
|
"PROPAGATION": "PROPAGACIÓN",
|
||||||
"DOWNSTREAM PASSAGE": "PASO AGUAS ABAJO",
|
"DOWNSTREAM PASSAGE": "PASO AGUAS ABAJO",
|
||||||
"CONSEQUENCE": "CONSECUENCIA",
|
"CONSEQUENCE": "SECUELAS",
|
||||||
"DOWNSTREAM CONSEQUENCE": "CONSECUENCIA AGUAS ABAJO",
|
"DOWNSTREAM CONSEQUENCE": "SECUELAS AGUAS ABAJO",
|
||||||
"EVIDENCE": "EVIDENCIA",
|
"EVIDENCE": "EVIDENCIA",
|
||||||
"{count} GEOLOCATED SOURCE-MAP PLACEMENTS": {
|
"{count} GEOLOCATED SOURCE-MAP PLACEMENTS": {
|
||||||
"one": "{count} UBICACIÓN GEOLOCALIZADA EN EL MAPA DE FUENTES",
|
"one": "{count} UBICACIÓN GEOLOCALIZADA EN EL MAPA DE FUENTES",
|
||||||
@@ -1064,7 +1064,7 @@
|
|||||||
"Close event layer": "Cerrar la capa del evento",
|
"Close event layer": "Cerrar la capa del evento",
|
||||||
"OBSERVED IMAGERY": "IMÁGENES OBSERVADAS",
|
"OBSERVED IMAGERY": "IMÁGENES OBSERVADAS",
|
||||||
"SCHEMATIC CORRIDOR": "CORREDOR ESQUEMÁTICO",
|
"SCHEMATIC CORRIDOR": "CORREDOR ESQUEMÁTICO",
|
||||||
"2021 HISTORICAL REFERENCE / 2026 POST-EVENT": "REFERENCIA HISTÓRICA 2021 / POSTERIOR AL EVENTO 2026",
|
"2021 HISTORICAL REFERENCE / 2026 POST-EVENT": "HISTÓRICA 2021 / TRAS EL EVENTO 2026",
|
||||||
"Historical reference and post-event image split": "División entre la imagen de referencia histórica y la posterior al evento",
|
"Historical reference and post-event image split": "División entre la imagen de referencia histórica y la posterior al evento",
|
||||||
"RECONSTRUCTION CLOCK": "RELOJ DE LA RECONSTRUCCIÓN",
|
"RECONSTRUCTION CLOCK": "RELOJ DE LA RECONSTRUCCIÓN",
|
||||||
"Schematic downstream progression": "Avance esquemático aguas abajo",
|
"Schematic downstream progression": "Avance esquemático aguas abajo",
|
||||||
@@ -1123,12 +1123,12 @@
|
|||||||
"{envVar} saved — paste to replace": "{envVar} guardada — pega otra para reemplazarla",
|
"{envVar} saved — paste to replace": "{envVar} guardada — pega otra para reemplazarla",
|
||||||
"paste {envVar}": "pega {envVar}",
|
"paste {envVar}": "pega {envVar}",
|
||||||
"Project keys: {status}": "Claves del proyecto: {status}",
|
"Project keys: {status}": "Claves del proyecto: {status}",
|
||||||
"Mapped camera locations": "Ubicaciones de cámaras cartografiadas",
|
"Mapped camera locations": "Ubicaciones de cámaras mapeadas",
|
||||||
"SHOW NEAREST": "MOSTRAR LA MÁS CERCANA",
|
"SHOW NEAREST": "MOSTRAR LA MÁS CERCANA",
|
||||||
"Stop following the current object before navigating to a camera": "Deja de seguir el objeto actual antes de ir a una cámara",
|
"Stop following the current object before navigating to a camera": "Deja de seguir el objeto actual antes de ir a una cámara",
|
||||||
"Move to the nearest loaded camera and show its details": "Ir a la cámara cargada más cercana y mostrar sus detalles",
|
"Move to the nearest loaded camera and show its details": "Ir a la cámara cargada más cercana y mostrar sus detalles",
|
||||||
"Camera badges": "Iconos de cámaras",
|
"Camera badges": "Iconos de cámaras",
|
||||||
"Cyan cameras turn coral when selected. Wedges illustrate mapped direction, not measured coverage. Nearby cameras may be outside the screen.": "Las cámaras cian se vuelven coral al seleccionarlas. Las cuñas ilustran la dirección cartografiada, no la cobertura medida. Las cámaras cercanas pueden estar fuera de la pantalla.",
|
"Cyan cameras turn coral when selected. Wedges illustrate mapped direction, not measured coverage. Nearby cameras may be outside the screen.": "Las cámaras cian se vuelven coral al seleccionarlas. Las cuñas ilustran la dirección mapeada, no la cobertura medida. Las cámaras cercanas pueden estar fuera de la pantalla.",
|
||||||
"{count} nearby · {onScreen} on screen": {
|
"{count} nearby · {onScreen} on screen": {
|
||||||
"one": "{count} cercana · {onScreen} en pantalla",
|
"one": "{count} cercana · {onScreen} en pantalla",
|
||||||
"many": "{count} de cámaras cercanas · {onScreen} en pantalla",
|
"many": "{count} de cámaras cercanas · {onScreen} en pantalla",
|
||||||
@@ -1139,16 +1139,16 @@
|
|||||||
"many": "{count} de cámaras cercanas",
|
"many": "{count} de cámaras cercanas",
|
||||||
"other": "{count} cercanas"
|
"other": "{count} cercanas"
|
||||||
},
|
},
|
||||||
"retrying mapped ALPR cameras": "reintentando cámaras ALPR cartografiadas",
|
"retrying mapped ALPR cameras": "reintentando cámaras ALPR mapeadas",
|
||||||
"loading mapped ALPR cameras": "cargando cámaras ALPR cartografiadas",
|
"loading mapped ALPR cameras": "cargando cámaras ALPR mapeadas",
|
||||||
"No ALPR data for this area — US and Canada only": "Sin datos ALPR para esta zona — solo EE. UU. y Canadá",
|
"No ALPR data for this area — US and Canada only": "Sin datos ALPR para esta zona — solo EE. UU. y Canadá",
|
||||||
"Zoom in to load mapped cameras": "Haz zoom para cargar las cámaras cartografiadas",
|
"Zoom in to load mapped cameras": "Haz zoom para cargar las cámaras mapeadas",
|
||||||
"Showing cached locations": "Mostrando ubicaciones en caché",
|
"Showing cached locations": "Mostrando ubicaciones en caché",
|
||||||
"Coverage limited — zoom in": "Cobertura limitada — haz zoom",
|
"Coverage limited — zoom in": "Cobertura limitada — haz zoom",
|
||||||
"No ALPR data for this area": "Sin datos ALPR para esta zona",
|
"No ALPR data for this area": "Sin datos ALPR para esta zona",
|
||||||
"None on screen — nearby cameras are outside the view": "Ninguna en pantalla — las cámaras cercanas están fuera de la vista",
|
"None on screen — nearby cameras are outside the view": "Ninguna en pantalla — las cámaras cercanas están fuera de la vista",
|
||||||
"ALPR camera": "Cámara ALPR",
|
"ALPR camera": "Cámara ALPR",
|
||||||
"OpenStreetMap · community mapped": "OpenStreetMap · cartografiado por la comunidad",
|
"OpenStreetMap · community mapped": "OpenStreetMap · mapeado por la comunidad",
|
||||||
"Atlantic and eastern/central North Pacific; not worldwide cyclone coverage.": "Atlántico y Pacífico Norte oriental/central; no es una cobertura mundial de ciclones.",
|
"Atlantic and eastern/central North Pacific; not worldwide cyclone coverage.": "Atlántico y Pacífico Norte oriental/central; no es una cobertura mundial de ciclones.",
|
||||||
"Potential tropical cyclone": "Posible ciclón tropical",
|
"Potential tropical cyclone": "Posible ciclón tropical",
|
||||||
"Hurricane": "Huracán",
|
"Hurricane": "Huracán",
|
||||||
@@ -1231,17 +1231,17 @@
|
|||||||
"Fully contained": "Totalmente contenido",
|
"Fully contained": "Totalmente contenido",
|
||||||
"Colour shows reported containment. Perimeters are simplified to about 100 m.": "El color indica la contención notificada. Los perímetros se simplifican a unos 100 m.",
|
"Colour shows reported containment. Perimeters are simplified to about 100 m.": "El color indica la contención notificada. Los perímetros se simplifican a unos 100 m.",
|
||||||
"MORE DETAIL · 30 m": "MÁS DETALLE · 30 m",
|
"MORE DETAIL · 30 m": "MÁS DETALLE · 30 m",
|
||||||
"Sentinel-2 and Landsat via HLS, 30 m, every 2–6 days": "Sentinel-2 y Landsat vía HLS, 30 m, cada 2–6 días",
|
"Sentinel-2 and Landsat via HLS, 30 m, every 2–6 days": "Sentinel‑2 y Landsat vía HLS, 30 m, cada 2–6 días",
|
||||||
"DAILY OVERVIEW · 250 m": "VISTA GENERAL DIARIA · 250 m",
|
"DAILY OVERVIEW · 250 m": "VISTA GENERAL DIARIA · 250 m",
|
||||||
"VIIRS daily mosaic, 250 m, follows broad changes; little detail under 25 km": "Mosaico diario de VIIRS, 250 m, sigue los cambios amplios; poco detalle por debajo de 25 km",
|
"VIIRS daily mosaic, 250 m, follows broad changes; little detail under 25 km": "Mosaico diario de VIIRS, 250 m, sigue los cambios amplios; poco detalle por debajo de 25 km",
|
||||||
"Catalog truncated · a newer clear day may exist": "Catálogo truncado · puede existir un día despejado más reciente",
|
"Catalog truncated · a newer clear day may exist": "Catálogo truncado · puede existir un día despejado más reciente",
|
||||||
"{label} catalog unavailable · {detail}": "Catálogo de {label} no disponible · {detail}",
|
"{label} catalog unavailable · {detail}": "Catálogo de {label} no disponible · {detail}",
|
||||||
"Daily overview for today may still be empty until the pass": "La vista general diaria de hoy puede seguir vacía hasta el paso del satélite",
|
"Daily overview for today may still be empty until the pass": "La vista general diaria de hoy puede seguir vacía hasta el paso del satélite",
|
||||||
"Sentinel-2": "Sentinel-2",
|
"Sentinel-2": "Sentinel‑2",
|
||||||
"Landsat 8/9": "Landsat 8/9",
|
"Landsat 8/9": "Landsat 8/9",
|
||||||
"Daily overview": "Vista general diaria",
|
"Daily overview": "Vista general diaria",
|
||||||
"No frame within {gap} min of {time}": "Ningún fotograma a menos de {gap} min de {time}",
|
"No frame within {gap} min of {time}": "Sin fotograma a ±{gap} min de {time}",
|
||||||
"No frame within {gap} h of {time}": "Ningún fotograma a menos de {gap} h de {time}",
|
"No frame within {gap} h of {time}": "Sin fotograma a ±{gap} h de {time}",
|
||||||
"{hours}h {minutes}m ago": "hace {hours} h {minutes} min",
|
"{hours}h {minutes}m ago": "hace {hours} h {minutes} min",
|
||||||
"{minutes}m ago": "hace {minutes} min",
|
"{minutes}m ago": "hace {minutes} min",
|
||||||
"{state} · {time} · {lag}": "{state} · {time} · {lag}",
|
"{state} · {time} · {lag}": "{state} · {time} · {lag}",
|
||||||
@@ -1451,10 +1451,10 @@
|
|||||||
"Tilt map to oblique view": "Inclinar el mapa a una vista oblicua",
|
"Tilt map to oblique view": "Inclinar el mapa a una vista oblicua",
|
||||||
"Reset map to north up. Current heading {heading} degrees": "Orientar el mapa al norte. Rumbo actual: {heading} grados",
|
"Reset map to north up. Current heading {heading} degrees": "Orientar el mapa al norte. Rumbo actual: {heading} grados",
|
||||||
"HDG": "HDG",
|
"HDG": "HDG",
|
||||||
"PITCH": "PITCH",
|
"PITCH": "INCL.",
|
||||||
"FOV": "FOV",
|
"FOV": "FOV",
|
||||||
"RANGE": "RANGE",
|
"RANGE": "DIST.",
|
||||||
"HGT": "HGT",
|
"HGT": "ALT.",
|
||||||
"{value} KM/H": "{value} KM/H",
|
"{value} KM/H": "{value} KM/H",
|
||||||
"NORMAL": "NORMAL",
|
"NORMAL": "NORMAL",
|
||||||
"ANIME": "ANIME",
|
"ANIME": "ANIME",
|
||||||
@@ -1515,7 +1515,7 @@
|
|||||||
"Mode": "Modo",
|
"Mode": "Modo",
|
||||||
"Imagery on Esri · Google 3D returns when cleared": "Imágenes sobre Esri · Google 3D vuelve al borrarlas",
|
"Imagery on Esri · Google 3D returns when cleared": "Imágenes sobre Esri · Google 3D vuelve al borrarlas",
|
||||||
"Imagery opacity": "Opacidad de las imágenes",
|
"Imagery opacity": "Opacidad de las imágenes",
|
||||||
"SWAP": "CAMBIO",
|
"SWAP": "INVERTIR",
|
||||||
"VS BASEMAP": "VS MAPA BASE",
|
"VS BASEMAP": "VS MAPA BASE",
|
||||||
"Trade the two sides of the divider": "Intercambiar los dos lados del divisor",
|
"Trade the two sides of the divider": "Intercambiar los dos lados del divisor",
|
||||||
"A / B": "A / B",
|
"A / B": "A / B",
|
||||||
@@ -1568,7 +1568,7 @@
|
|||||||
"START HERE · {reason}": "EMPIEZA AQUÍ · {reason}",
|
"START HERE · {reason}": "EMPIEZA AQUÍ · {reason}",
|
||||||
"Daily overview shows little detail in a box this small": "La vista general diaria muestra poco detalle en un recuadro tan pequeño",
|
"Daily overview shows little detail in a box this small": "La vista general diaria muestra poco detalle en un recuadro tan pequeño",
|
||||||
"{percent}% cloud": "{percent}% de nubes",
|
"{percent}% cloud": "{percent}% de nubes",
|
||||||
"Imagery: NASA GIBS and Worldview · HLS (Sentinel-2, Landsat 8/9) and VIIRS": "Imágenes: NASA GIBS y Worldview · HLS (Sentinel-2, Landsat 8/9) y VIIRS",
|
"Imagery: NASA GIBS and Worldview · HLS (Sentinel-2, Landsat 8/9) and VIIRS": "Imágenes: NASA GIBS y Worldview · HLS (Sentinel‑2, Landsat 8/9) y VIIRS",
|
||||||
"{min}–{max}% cloud": "{min}–{max}% de nubes",
|
"{min}–{max}% cloud": "{min}–{max}% de nubes",
|
||||||
"Details": "Detalles",
|
"Details": "Detalles",
|
||||||
"Times, coverage, sources": "Horas, cobertura, fuentes",
|
"Times, coverage, sources": "Horas, cobertura, fuentes",
|
||||||
@@ -1593,7 +1593,7 @@
|
|||||||
"Select a box or use the view": "Selecciona un recuadro o usa la vista",
|
"Select a box or use the view": "Selecciona un recuadro o usa la vista",
|
||||||
"Searching the last 30 days": "Buscando en los últimos 30 días",
|
"Searching the last 30 days": "Buscando en los últimos 30 días",
|
||||||
"No days to show for this box": "No hay días que mostrar para este recuadro",
|
"No days to show for this box": "No hay días que mostrar para este recuadro",
|
||||||
"Drag the divider · SWAP trades sides": "Arrastra el divisor · CAMBIO invierte los lados",
|
"Drag the divider · SWAP trades sides": "Arrastra el divisor · INVERTIR cambia los lados",
|
||||||
"Export failed · {error}": "La exportación falló · {error}",
|
"Export failed · {error}": "La exportación falló · {error}",
|
||||||
"← → preview · A or B pins the focused day": "← → vista previa · A o B fija el día enfocado",
|
"← → preview · A or B pins the focused day": "← → vista previa · A o B fija el día enfocado",
|
||||||
"← → preview the other side · A or B pins it": "← → vista previa del otro lado · A o B lo fija",
|
"← → preview the other side · A or B pins it": "← → vista previa del otro lado · A o B lo fija",
|
||||||
@@ -1608,7 +1608,7 @@
|
|||||||
"ESC EXIT": "ESC SALIR",
|
"ESC EXIT": "ESC SALIR",
|
||||||
"C TOGGLE": "C ALTERNAR",
|
"C TOGGLE": "C ALTERNAR",
|
||||||
"SIG": "SIG",
|
"SIG": "SIG",
|
||||||
"NEWS": "NEWS",
|
"NEWS": "NOTICIAS",
|
||||||
"LOCAL": "LOCAL",
|
"LOCAL": "LOCAL",
|
||||||
"Cockpit briefing pages": "Páginas de información de la cabina",
|
"Cockpit briefing pages": "Páginas de información de la cabina",
|
||||||
"MM": "MM",
|
"MM": "MM",
|
||||||
@@ -1616,11 +1616,11 @@
|
|||||||
"FT": "FT",
|
"FT": "FT",
|
||||||
"FLT": "FLT",
|
"FLT": "FLT",
|
||||||
"MIL": "MIL",
|
"MIL": "MIL",
|
||||||
"SITE": "SITE",
|
"SITE": "SITIOS",
|
||||||
"WX": "WX",
|
"WX": "WX",
|
||||||
"DIRECTORY: RADIO BROWSER": "DIRECTORIO: RADIO BROWSER",
|
"DIRECTORY: RADIO BROWSER": "DIRECTORIO: RADIO BROWSER",
|
||||||
"Use your location for faster ADS-B position decoding": "Usa tu ubicación para decodificar más rápido las posiciones ADS-B",
|
"Use your location for faster ADS-B position decoding": "Usa tu ubicación para decodificar más rápido las posiciones ADS-B",
|
||||||
"CHANGE DEVICE": "CAMBIAR DISPOSITIVO",
|
"CHANGE DEVICE": "CAMBIAR",
|
||||||
"Choose a different RTL-SDR or receiver channel": "Elige otro RTL-SDR u otro canal del receptor",
|
"Choose a different RTL-SDR or receiver channel": "Elige otro RTL-SDR u otro canal del receptor",
|
||||||
"TUNE": "SINTONIZAR",
|
"TUNE": "SINTONIZAR",
|
||||||
"◀ SEEK": "◀ BUSCAR",
|
"◀ SEEK": "◀ BUSCAR",
|
||||||
@@ -1644,11 +1644,11 @@
|
|||||||
"POSITIONED": "POSICIONADAS",
|
"POSITIONED": "POSICIONADAS",
|
||||||
"SDR VOL": "VOL. SDR",
|
"SDR VOL": "VOL. SDR",
|
||||||
"LOCAL RTL-SDR": "RTL-SDR LOCAL",
|
"LOCAL RTL-SDR": "RTL-SDR LOCAL",
|
||||||
"Cyber sonar contact scanner": "Escáner sonar de contactos Cyber",
|
"Cyber sonar contact scanner": "Escáner sonar de contactos Ciber",
|
||||||
"Sonar ring count": "Número de anillos del sonar",
|
"Sonar ring count": "Número de anillos del sonar",
|
||||||
"Sonar ring range": "Alcance de los anillos del sonar",
|
"Sonar ring range": "Alcance de los anillos del sonar",
|
||||||
"Sonar intensity": "Intensidad del sonar",
|
"Sonar intensity": "Intensidad del sonar",
|
||||||
"Cyber contact and label opacity": "Opacidad de contactos y etiquetas Cyber",
|
"Cyber contact and label opacity": "Opacidad de contactos y etiquetas Ciber",
|
||||||
"Minimum opacity for map dots, icons, models, brackets, and labels between sonar passes": "Opacidad mínima de puntos, iconos, modelos, corchetes y etiquetas del mapa entre pasadas del sonar",
|
"Minimum opacity for map dots, icons, models, brackets, and labels between sonar passes": "Opacidad mínima de puntos, iconos, modelos, corchetes y etiquetas del mapa entre pasadas del sonar",
|
||||||
"Sonar sector width": "Ancho del sector del sonar",
|
"Sonar sector width": "Ancho del sector del sonar",
|
||||||
"Rings": "Anillos",
|
"Rings": "Anillos",
|
||||||
@@ -1656,7 +1656,7 @@
|
|||||||
"Power": "Potencia",
|
"Power": "Potencia",
|
||||||
"Opacity": "Opacidad",
|
"Opacity": "Opacidad",
|
||||||
"Sector": "Sector",
|
"Sector": "Sector",
|
||||||
"Cyber": "Cyber",
|
"Cyber": "Ciber",
|
||||||
"Sonar": "Sonar",
|
"Sonar": "Sonar",
|
||||||
"Turn Street Level on or off": "Activar o desactivar A pie de calle",
|
"Turn Street Level on or off": "Activar o desactivar A pie de calle",
|
||||||
"Toggle straight-down and tilted map views": "Alternar entre la vista cenital y la vista inclinada del mapa",
|
"Toggle straight-down and tilted map views": "Alternar entre la vista cenital y la vista inclinada del mapa",
|
||||||
@@ -1671,7 +1671,7 @@
|
|||||||
"{time} · {minutes} min ago": "{time} · hace {minutes} min",
|
"{time} · {minutes} min ago": "{time} · hace {minutes} min",
|
||||||
"Active weather": "Clima activo",
|
"Active weather": "Clima activo",
|
||||||
"MINI": "MINI",
|
"MINI": "MINI",
|
||||||
"STD": "STD",
|
"STD": "EST.",
|
||||||
"standard": "estándar",
|
"standard": "estándar",
|
||||||
"mini": "mini",
|
"mini": "mini",
|
||||||
"COST UNKNOWN": "COSTO DESCONOCIDO",
|
"COST UNKNOWN": "COSTO DESCONOCIDO",
|
||||||
@@ -1786,7 +1786,7 @@
|
|||||||
"Cyclone advisories": "Avisos de ciclones",
|
"Cyclone advisories": "Avisos de ciclones",
|
||||||
"EDIT DETAILS": "EDITAR DETALLES",
|
"EDIT DETAILS": "EDITAR DETALLES",
|
||||||
"SHARE SCENE": "COMPARTIR ESCENA",
|
"SHARE SCENE": "COMPARTIR ESCENA",
|
||||||
"ON/OFF": "ON/OFF",
|
"ON/OFF": "ENC./APAG.",
|
||||||
"Voice assistant": "Asistente de voz",
|
"Voice assistant": "Asistente de voz",
|
||||||
"VOICE": "VOZ",
|
"VOICE": "VOZ",
|
||||||
"Dismiss voice card": "Cerrar la tarjeta de voz",
|
"Dismiss voice card": "Cerrar la tarjeta de voz",
|
||||||
@@ -1811,7 +1811,7 @@
|
|||||||
"overview": "vista general",
|
"overview": "vista general",
|
||||||
"{percent}% scene cloud": "{percent}% de nubes en la escena",
|
"{percent}% scene cloud": "{percent}% de nubes en la escena",
|
||||||
"{min}–{max}% scene cloud": "{min}–{max}% de nubes en la escena",
|
"{min}–{max}% scene cloud": "{min}–{max}% de nubes en la escena",
|
||||||
"Sentinel-2 via HLS": "Sentinel-2 vía HLS",
|
"Sentinel-2 via HLS": "Sentinel‑2 vía HLS",
|
||||||
"Landsat 8/9 via HLS": "Landsat 8/9 vía HLS",
|
"Landsat 8/9 via HLS": "Landsat 8/9 vía HLS",
|
||||||
"coverage|full": "completa",
|
"coverage|full": "completa",
|
||||||
"coverage|partial": "parcial",
|
"coverage|partial": "parcial",
|
||||||
@@ -1887,13 +1887,13 @@
|
|||||||
"Use the {direction} lane": "Usa el carril {direction}",
|
"Use the {direction} lane": "Usa el carril {direction}",
|
||||||
"Use the {direction} lane onto {road}": "Usa el carril {direction} hacia {road}",
|
"Use the {direction} lane onto {road}": "Usa el carril {direction} hacia {road}",
|
||||||
"voice|OFF": "APAG.",
|
"voice|OFF": "APAG.",
|
||||||
"voice|CONNECTING": "CONEX…",
|
"voice|CONNECTING": "CONECT.",
|
||||||
"voice|LISTENING": "OYENDO",
|
"voice|LISTENING": "ESCUCHO",
|
||||||
"voice|EXECUTING": "ACCIÓN",
|
"voice|EXECUTING": "ACCIÓN",
|
||||||
"voice|ERROR": "ERROR",
|
"voice|ERROR": "ERROR",
|
||||||
"MIC": "MIC",
|
"MIC": "MIC",
|
||||||
"WORKING": "EN CURSO",
|
"WORKING": "EN CURSO",
|
||||||
"DONE": "LISTO",
|
"DONE": "HECHO",
|
||||||
"Outline traced": "Contorno trazado",
|
"Outline traced": "Contorno trazado",
|
||||||
"Outline unavailable": "Contorno no disponible",
|
"Outline unavailable": "Contorno no disponible",
|
||||||
"in progress": "en curso",
|
"in progress": "en curso",
|
||||||
@@ -2020,7 +2020,7 @@
|
|||||||
"Globe imagery unavailable": "Imágenes del globo no disponibles",
|
"Globe imagery unavailable": "Imágenes del globo no disponibles",
|
||||||
"Globe field image unavailable": "Imagen del campo en el globo no disponible",
|
"Globe field image unavailable": "Imagen del campo en el globo no disponible",
|
||||||
"status chip|UNAVAILABLE": "NO DISP.",
|
"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.": "Incluye 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}",
|
"{state} {layers}": "{state}: {layers}",
|
||||||
"Selected Space Mission": "Misión espacial seleccionada",
|
"Selected Space Mission": "Misión espacial seleccionada",
|
||||||
"{duration}s + {hold}s": "{duration} s + {hold} s",
|
"{duration}s + {hold}s": "{duration} s + {hold} s",
|
||||||
@@ -2028,7 +2028,7 @@
|
|||||||
"subject": "sujeto",
|
"subject": "sujeto",
|
||||||
"{value}m": "{value} m",
|
"{value}m": "{value} m",
|
||||||
"Google 3D tiles unavailable — check the key's API restrictions, quota, or network": "Teselas de Google 3D no disponibles: revisa las restricciones de API de la clave, la cuota o la red",
|
"Google 3D tiles unavailable — check the key's API restrictions, quota, or network": "Teselas de Google 3D no disponibles: revisa las restricciones de API de la clave, la cuota o la red",
|
||||||
"Needs {envVars} — add it in Provider Settings — or a Cesium ion token for the ion-hosted route": "Necesita {envVars} — añádela en Ajustes de proveedores — o un token de Cesium ion para la ruta alojada en ion",
|
"Needs {envVars} — add it in Provider Settings — or a Cesium ion token for the ion-hosted route": "Necesita {envVars} — se añade en Ajustes de proveedores — o un token de Cesium ion para la ruta alojada en ion",
|
||||||
"Comparison in use by another scene": "La comparación está en uso por otra escena",
|
"Comparison in use by another scene": "La comparación está en uso por otra escena",
|
||||||
"A location reading needs a loaded forecast and the Earth at the center of the view.": "Una lectura en un punto necesita un pronóstico cargado y la Tierra en el centro de la vista.",
|
"A location reading needs a loaded forecast and the Earth at the center of the view.": "Una lectura en un punto necesita un pronóstico cargado y la Tierra en el centro de la vista.",
|
||||||
"{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}",
|
"{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}",
|
||||||
@@ -2041,11 +2041,37 @@
|
|||||||
"zoom in to a street to open {name}": "acércate a una calle para abrir {name}",
|
"zoom in to a street to open {name}": "acércate a una calle para abrir {name}",
|
||||||
"Google Street View": "Google Street View",
|
"Google Street View": "Google Street View",
|
||||||
"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 rechazó GOOGLE_MAPS_API_KEY para Street View — comprueba que la API Maps JavaScript esté habilitada para ella y que este sitio sea un referente permitido",
|
"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 rechazó GOOGLE_MAPS_API_KEY para Street View — comprueba que la clave tenga habilitada la API Maps JavaScript y que este sitio figure entre sus referentes HTTP permitidos",
|
||||||
"Street View did not answer — check the network, and that the Maps JavaScript API is enabled for GOOGLE_MAPS_API_KEY": "Street View no respondió — comprueba la red y que la API Maps JavaScript esté habilitada para GOOGLE_MAPS_API_KEY",
|
"Street View did not answer — check the network, and that the Maps JavaScript API is enabled for GOOGLE_MAPS_API_KEY": "Street View no respondió — comprueba la red y que la API Maps JavaScript esté habilitada para GOOGLE_MAPS_API_KEY",
|
||||||
"click a street to open Street View": "haz clic en una calle para abrir Street View",
|
"click a street to open Street View": "haz clic en una calle para abrir Street View",
|
||||||
" or ": " o ",
|
" or ": " o ",
|
||||||
"OPEN {labels}": "ABRIR {labels}",
|
"OPEN {labels}": "ABRIR {labels}",
|
||||||
"Open {names} at the centre of the view": "Abrir {names} en el centro de la vista",
|
"Open {names} at the centre of the view": "Abrir {names} en el centro de la vista",
|
||||||
"Zoom in to a street to open {names} here": "Acércate a una calle para abrir {names} aquí"
|
"Zoom in to a street to open {names} here": "Acércate a una calle para abrir {names} aquí",
|
||||||
|
"radio tag|All": "Todas",
|
||||||
|
"Alternative": "Alternativa",
|
||||||
|
"Ambient": "Ambiental",
|
||||||
|
"Blues": "Blues",
|
||||||
|
"Classical": "Clásica",
|
||||||
|
"Country": "Country",
|
||||||
|
"Dance": "Dance",
|
||||||
|
"Electronic": "Electrónica",
|
||||||
|
"Folk": "Folk",
|
||||||
|
"Funk": "Funk",
|
||||||
|
"Hip-Hop": "Hip-Hop",
|
||||||
|
"House": "House",
|
||||||
|
"Indie": "Indie",
|
||||||
|
"Jazz": "Jazz",
|
||||||
|
"Latin": "Latina",
|
||||||
|
"Metal": "Metal",
|
||||||
|
"Oldies": "Clásicos de siempre",
|
||||||
|
"Pop": "Pop",
|
||||||
|
"Punk": "Punk",
|
||||||
|
"R&B": "R&B",
|
||||||
|
"Reggae": "Reggae",
|
||||||
|
"Rock": "Rock",
|
||||||
|
"Soul": "Soul",
|
||||||
|
"Techno": "Techno",
|
||||||
|
"Trance": "Trance",
|
||||||
|
"World": "Músicas del mundo"
|
||||||
}
|
}
|
||||||
@@ -1247,13 +1247,13 @@
|
|||||||
"Fully contained": "Полностью локализован",
|
"Fully contained": "Полностью локализован",
|
||||||
"Colour shows reported containment. Perimeters are simplified to about 100 m.": "Цвет показывает заявленную степень локализации. Контуры упрощены примерно до 100 м.",
|
"Colour shows reported containment. Perimeters are simplified to about 100 m.": "Цвет показывает заявленную степень локализации. Контуры упрощены примерно до 100 м.",
|
||||||
"MORE DETAIL · 30 m": "БОЛЬШЕ ДЕТАЛЕЙ · 30 м",
|
"MORE DETAIL · 30 m": "БОЛЬШЕ ДЕТАЛЕЙ · 30 м",
|
||||||
"Sentinel-2 and Landsat via HLS, 30 m, every 2–6 days": "Sentinel-2 и Landsat через HLS, 30 м, каждые 2–6 дней",
|
"Sentinel-2 and Landsat via HLS, 30 m, every 2–6 days": "Sentinel‑2 и Landsat через HLS, 30 м, каждые 2–6 дней",
|
||||||
"DAILY OVERVIEW · 250 m": "ЕЖЕДНЕВНЫЙ ОБЗОР · 250 м",
|
"DAILY OVERVIEW · 250 m": "ЕЖЕДНЕВНЫЙ ОБЗОР · 250 м",
|
||||||
"VIIRS daily mosaic, 250 m, follows broad changes; little detail under 25 km": "Ежедневная мозаика VIIRS, 250 м, показывает крупные изменения; мало деталей в масштабе менее 25 км",
|
"VIIRS daily mosaic, 250 m, follows broad changes; little detail under 25 km": "Ежедневная мозаика VIIRS, 250 м, показывает крупные изменения; мало деталей в масштабе менее 25 км",
|
||||||
"Catalog truncated · a newer clear day may exist": "Каталог усечён · может быть более новый ясный день",
|
"Catalog truncated · a newer clear day may exist": "Каталог усечён · может быть более новый ясный день",
|
||||||
"{label} catalog unavailable · {detail}": "Каталог {label} недоступен · {detail}",
|
"{label} catalog unavailable · {detail}": "Каталог {label} недоступен · {detail}",
|
||||||
"Daily overview for today may still be empty until the pass": "Ежедневный обзор за сегодня может оставаться пустым до пролёта спутника",
|
"Daily overview for today may still be empty until the pass": "Ежедневный обзор за сегодня может оставаться пустым до пролёта спутника",
|
||||||
"Sentinel-2": "Sentinel-2",
|
"Sentinel-2": "Sentinel‑2",
|
||||||
"Landsat 8/9": "Landsat 8/9",
|
"Landsat 8/9": "Landsat 8/9",
|
||||||
"Daily overview": "Ежедневный обзор",
|
"Daily overview": "Ежедневный обзор",
|
||||||
"No frame within {gap} min of {time}": "Нет кадра в пределах {gap} мин от {time}",
|
"No frame within {gap} min of {time}": "Нет кадра в пределах {gap} мин от {time}",
|
||||||
@@ -1592,7 +1592,7 @@
|
|||||||
"START HERE · {reason}": "НАЧНИТЕ ЗДЕСЬ · {reason}",
|
"START HERE · {reason}": "НАЧНИТЕ ЗДЕСЬ · {reason}",
|
||||||
"Daily overview shows little detail in a box this small": "В такой маленькой области ежедневный обзор почти не показывает деталей",
|
"Daily overview shows little detail in a box this small": "В такой маленькой области ежедневный обзор почти не показывает деталей",
|
||||||
"{percent}% cloud": "облачность {percent}%",
|
"{percent}% cloud": "облачность {percent}%",
|
||||||
"Imagery: NASA GIBS and Worldview · HLS (Sentinel-2, Landsat 8/9) and VIIRS": "Снимки: NASA GIBS и Worldview · HLS (Sentinel-2, Landsat 8/9) и VIIRS",
|
"Imagery: NASA GIBS and Worldview · HLS (Sentinel-2, Landsat 8/9) and VIIRS": "Снимки: NASA GIBS и Worldview · HLS (Sentinel‑2, Landsat 8/9) и VIIRS",
|
||||||
"{min}–{max}% cloud": "облачность {min}–{max}%",
|
"{min}–{max}% cloud": "облачность {min}–{max}%",
|
||||||
"Details": "Подробности",
|
"Details": "Подробности",
|
||||||
"Times, coverage, sources": "Время, покрытие, источники",
|
"Times, coverage, sources": "Время, покрытие, источники",
|
||||||
@@ -1842,7 +1842,7 @@
|
|||||||
"overview": "обзор",
|
"overview": "обзор",
|
||||||
"{percent}% scene cloud": "облачность сцены {percent}%",
|
"{percent}% scene cloud": "облачность сцены {percent}%",
|
||||||
"{min}–{max}% scene cloud": "облачность сцены {min}–{max}%",
|
"{min}–{max}% scene cloud": "облачность сцены {min}–{max}%",
|
||||||
"Sentinel-2 via HLS": "Sentinel-2 через HLS",
|
"Sentinel-2 via HLS": "Sentinel‑2 через HLS",
|
||||||
"Landsat 8/9 via HLS": "Landsat 8/9 через HLS",
|
"Landsat 8/9 via HLS": "Landsat 8/9 через HLS",
|
||||||
"coverage|full": "полное",
|
"coverage|full": "полное",
|
||||||
"coverage|partial": "частичное",
|
"coverage|partial": "частичное",
|
||||||
@@ -2079,5 +2079,31 @@
|
|||||||
" or ": " или ",
|
" or ": " или ",
|
||||||
"OPEN {labels}": "ОТКРЫТЬ {labels}",
|
"OPEN {labels}": "ОТКРЫТЬ {labels}",
|
||||||
"Open {names} at the centre of the view": "Открыть {names} в центре вида",
|
"Open {names} at the centre of the view": "Открыть {names} в центре вида",
|
||||||
"Zoom in to a street to open {names} here": "Приблизьтесь к улице, чтобы открыть здесь {names}"
|
"Zoom in to a street to open {names} here": "Приблизьтесь к улице, чтобы открыть здесь {names}",
|
||||||
|
"radio tag|All": "Все",
|
||||||
|
"Alternative": "Альтернатива",
|
||||||
|
"Ambient": "Эмбиент",
|
||||||
|
"Blues": "Блюз",
|
||||||
|
"Classical": "Классика",
|
||||||
|
"Country": "Кантри",
|
||||||
|
"Dance": "Танцевальная",
|
||||||
|
"Electronic": "Электроника",
|
||||||
|
"Folk": "Фолк",
|
||||||
|
"Funk": "Фанк",
|
||||||
|
"Hip-Hop": "Хип-хоп",
|
||||||
|
"House": "Хаус",
|
||||||
|
"Indie": "Инди",
|
||||||
|
"Jazz": "Джаз",
|
||||||
|
"Latin": "Латиноамериканская",
|
||||||
|
"Metal": "Метал",
|
||||||
|
"Oldies": "Ретро",
|
||||||
|
"Pop": "Поп",
|
||||||
|
"Punk": "Панк",
|
||||||
|
"R&B": "R&B",
|
||||||
|
"Reggae": "Регги",
|
||||||
|
"Rock": "Рок",
|
||||||
|
"Soul": "Соул",
|
||||||
|
"Techno": "Техно",
|
||||||
|
"Trance": "Транс",
|
||||||
|
"World": "Музыка мира"
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,126 @@
|
|||||||
|
{
|
||||||
|
"es": [
|
||||||
|
"AIS: --",
|
||||||
|
"AIS: {name}",
|
||||||
|
"ANIME",
|
||||||
|
"ASIA",
|
||||||
|
"AUTO",
|
||||||
|
"Anime",
|
||||||
|
"BRG {value}°",
|
||||||
|
"BRG —",
|
||||||
|
"Blues",
|
||||||
|
"CAL {value}",
|
||||||
|
"CAL · {badge}",
|
||||||
|
"CCTV",
|
||||||
|
"CRS {value}°",
|
||||||
|
"CRT",
|
||||||
|
"Country",
|
||||||
|
"DEST ---°",
|
||||||
|
"DEST {bearing}",
|
||||||
|
"Dance",
|
||||||
|
"ENE",
|
||||||
|
"ERROR",
|
||||||
|
"ESE",
|
||||||
|
"Error: {message}",
|
||||||
|
"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",
|
||||||
|
"MIC",
|
||||||
|
"MIL",
|
||||||
|
"MINI",
|
||||||
|
"MM",
|
||||||
|
"MONITOR",
|
||||||
|
"MSG/S",
|
||||||
|
"Metal",
|
||||||
|
"NAV",
|
||||||
|
"NE",
|
||||||
|
"NNE",
|
||||||
|
"NOIR",
|
||||||
|
"NORMAL",
|
||||||
|
"NVG",
|
||||||
|
"Noir",
|
||||||
|
"Normal",
|
||||||
|
"POS: {time}Z",
|
||||||
|
"PRECIP",
|
||||||
|
"Plan",
|
||||||
|
"Pop",
|
||||||
|
"Punk",
|
||||||
|
"R&B",
|
||||||
|
"RADIO",
|
||||||
|
"REC",
|
||||||
|
"Radio",
|
||||||
|
"Reggae",
|
||||||
|
"Rock",
|
||||||
|
"SAR",
|
||||||
|
"SE",
|
||||||
|
"SECTOR {lat} {lon}",
|
||||||
|
"SIG",
|
||||||
|
"SRC {value}",
|
||||||
|
"SSE",
|
||||||
|
"Sector",
|
||||||
|
"Sonar",
|
||||||
|
"Soul",
|
||||||
|
"TEMP",
|
||||||
|
"Techno",
|
||||||
|
"Trance",
|
||||||
|
"VISUAL",
|
||||||
|
"VS",
|
||||||
|
"WHOT/BHOT",
|
||||||
|
"WX",
|
||||||
|
"audio {state}",
|
||||||
|
"dB",
|
||||||
|
"ft",
|
||||||
|
"hPa",
|
||||||
|
"km",
|
||||||
|
"km/h",
|
||||||
|
"min",
|
||||||
|
"mini",
|
||||||
|
"mph",
|
||||||
|
"nominal",
|
||||||
|
"panel",
|
||||||
|
"view band|GLOBAL",
|
||||||
|
"voice|ERROR",
|
||||||
|
"{value} KM",
|
||||||
|
"{value} KM/H",
|
||||||
|
"{value} KM/S",
|
||||||
|
"ΔE",
|
||||||
|
"ΔN",
|
||||||
|
"▲ {frp} MW"
|
||||||
|
],
|
||||||
|
"ru": [
|
||||||
|
"AIS: --",
|
||||||
|
"AIS: {name}",
|
||||||
|
"CCTV",
|
||||||
|
"CRT",
|
||||||
|
"FLIR",
|
||||||
|
"GEO",
|
||||||
|
"Ironbow",
|
||||||
|
"Landsat 8/9",
|
||||||
|
"NAV",
|
||||||
|
"NVG",
|
||||||
|
"R&B",
|
||||||
|
"REC",
|
||||||
|
"VS",
|
||||||
|
"WHOT/BHOT",
|
||||||
|
"mini"
|
||||||
|
]
|
||||||
|
}
|
||||||
@@ -70,7 +70,7 @@ export function createCategories({
|
|||||||
function buildRadioCategories(stations) {
|
function buildRadioCategories(stations) {
|
||||||
const rows = Array.isArray(stations) ? stations : [];
|
const rows = Array.isArray(stations) ? stations : [];
|
||||||
const categories = [
|
const categories = [
|
||||||
{ id: 'all', label: t('All') },
|
{ id: 'all', label: t('All', { context: 'radio tag' }) },
|
||||||
{ id: 'news', label: t('News') },
|
{ id: 'news', label: t('News') },
|
||||||
{ id: 'talk', label: t('Talk') },
|
{ id: 'talk', label: t('Talk') },
|
||||||
{ id: 'weather', label: t('Weather / Emergency') },
|
{ id: 'weather', label: t('Weather / Emergency') },
|
||||||
@@ -89,7 +89,7 @@ export function createCategories({
|
|||||||
for (const [genre, label] of MUSIC_GENRES) {
|
for (const [genre, label] of MUSIC_GENRES) {
|
||||||
const id = `genre:${genre}`;
|
const id = `genre:${genre}`;
|
||||||
if (rows.some((station) => stationMatchesRadioCategory(station, id))) {
|
if (rows.some((station) => stationMatchesRadioCategory(station, id))) {
|
||||||
categories.push({ id, label });
|
categories.push({ id, label: t(label) });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
categories.push({ id: 'other', label: t('Other') });
|
categories.push({ id: 'other', label: t('Other') });
|
||||||
|
|||||||
+29
-25
@@ -62,32 +62,36 @@ export const DEFAULT_RADIO_FILTER = 'all';
|
|||||||
|
|
||||||
export const GLOBAL_RADIO_ALTITUDE_M = 2_000_000;
|
export const GLOBAL_RADIO_ALTITUDE_M = 2_000_000;
|
||||||
|
|
||||||
|
// Genre labels are marked for i18n extraction; categories.js translates them.
|
||||||
|
// Kept local so this module stays free of the i18n import.
|
||||||
|
const msg = (text) => text;
|
||||||
|
|
||||||
export const MUSIC_GENRES = Object.freeze([
|
export const MUSIC_GENRES = Object.freeze([
|
||||||
['alternative', 'Alternative'],
|
['alternative', msg('Alternative')],
|
||||||
['ambient', 'Ambient'],
|
['ambient', msg('Ambient')],
|
||||||
['blues', 'Blues'],
|
['blues', msg('Blues')],
|
||||||
['classical', 'Classical'],
|
['classical', msg('Classical')],
|
||||||
['country', 'Country'],
|
['country', msg('Country')],
|
||||||
['dance', 'Dance'],
|
['dance', msg('Dance')],
|
||||||
['electronic', 'Electronic'],
|
['electronic', msg('Electronic')],
|
||||||
['folk', 'Folk'],
|
['folk', msg('Folk')],
|
||||||
['funk', 'Funk'],
|
['funk', msg('Funk')],
|
||||||
['hip hop', 'Hip-Hop'],
|
['hip hop', msg('Hip-Hop')],
|
||||||
['house', 'House'],
|
['house', msg('House')],
|
||||||
['indie', 'Indie'],
|
['indie', msg('Indie')],
|
||||||
['jazz', 'Jazz'],
|
['jazz', msg('Jazz')],
|
||||||
['latin', 'Latin'],
|
['latin', msg('Latin')],
|
||||||
['metal', 'Metal'],
|
['metal', msg('Metal')],
|
||||||
['oldies', 'Oldies'],
|
['oldies', msg('Oldies')],
|
||||||
['pop', 'Pop'],
|
['pop', msg('Pop')],
|
||||||
['punk', 'Punk'],
|
['punk', msg('Punk')],
|
||||||
['r&b', 'R&B'],
|
['r&b', msg('R&B')],
|
||||||
['reggae', 'Reggae'],
|
['reggae', msg('Reggae')],
|
||||||
['rock', 'Rock'],
|
['rock', msg('Rock')],
|
||||||
['soul', 'Soul'],
|
['soul', msg('Soul')],
|
||||||
['techno', 'Techno'],
|
['techno', msg('Techno')],
|
||||||
['trance', 'Trance'],
|
['trance', msg('Trance')],
|
||||||
['world', 'World'],
|
['world', msg('World')],
|
||||||
]);
|
]);
|
||||||
|
|
||||||
export const CATEGORY_MATCHERS = Object.freeze({
|
export const CATEGORY_MATCHERS = Object.freeze({
|
||||||
|
|||||||
@@ -1,4 +1,12 @@
|
|||||||
import { t } from '../i18n/index.js';
|
import { formatNumber, t } from '../i18n/index.js';
|
||||||
|
|
||||||
|
/** A slider value in the UI language: 0.85 in English, 0,85 in Spanish. */
|
||||||
|
const formatParam = (value, digits) =>
|
||||||
|
formatNumber(value, {
|
||||||
|
minimumFractionDigits: digits,
|
||||||
|
maximumFractionDigits: digits,
|
||||||
|
useGrouping: false,
|
||||||
|
});
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Own generated parameter rows and their input listeners.
|
* Own generated parameter rows and their input listeners.
|
||||||
@@ -44,11 +52,14 @@ export function createStyleParameters({
|
|||||||
const digits = metadata.max <= 1 ? 2 : 1;
|
const digits = metadata.max <= 1 ? 2 : 1;
|
||||||
const valueDisplay = documentRef.createElement('span');
|
const valueDisplay = documentRef.createElement('span');
|
||||||
valueDisplay.className = 'param-value';
|
valueDisplay.className = 'param-value';
|
||||||
valueDisplay.textContent = parseFloat(slider.value).toFixed(digits);
|
valueDisplay.textContent = formatParam(
|
||||||
|
parseFloat(slider.value),
|
||||||
|
digits,
|
||||||
|
);
|
||||||
const onInput = () => {
|
const onInput = () => {
|
||||||
const value = parseFloat(slider.value);
|
const value = parseFloat(slider.value);
|
||||||
writeValue(name, value);
|
writeValue(name, value);
|
||||||
valueDisplay.textContent = value.toFixed(digits);
|
valueDisplay.textContent = formatParam(value, digits);
|
||||||
onChange();
|
onChange();
|
||||||
};
|
};
|
||||||
slider.addEventListener('input', onInput);
|
slider.addEventListener('input', onInput);
|
||||||
|
|||||||
@@ -399,6 +399,12 @@
|
|||||||
color: rgba(222, 240, 245, 0.88);
|
color: rgba(222, 240, 245, 0.88);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* A longer translated heading wraps; the readout beside it stays one piece. */
|
||||||
|
html:not([lang='en']) .bhote-event-section-head span:last-child {
|
||||||
|
flex: none;
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
|
||||||
.bhote-event-range {
|
.bhote-event-range {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 4px;
|
height: 4px;
|
||||||
|
|||||||
@@ -404,3 +404,13 @@ html:not([lang='en']) #cctv-camera-select {
|
|||||||
font-size: 10px;
|
font-size: 10px;
|
||||||
letter-spacing: 0.04em;
|
letter-spacing: 0.04em;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* The camera name gets its own row; PREV / NEXT share the row below it. */
|
||||||
|
html:not([lang='en']) .cctv-controls:has(#cctv-camera-select) {
|
||||||
|
flex-wrap: wrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
html:not([lang='en']) #cctv-camera-select {
|
||||||
|
flex: 1 1 100%;
|
||||||
|
order: -1;
|
||||||
|
}
|
||||||
@@ -221,6 +221,18 @@
|
|||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* A longer translated title in a collapsed rail launcher tightens its
|
||||||
|
tracking rather than pushing the disclosure button out of the card. */
|
||||||
|
html:not([lang='en'])
|
||||||
|
#right-context-rail
|
||||||
|
.panel-collapsible.collapsed
|
||||||
|
.panel-title {
|
||||||
|
min-width: 0;
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
letter-spacing: 2px;
|
||||||
|
}
|
||||||
|
|
||||||
.panel-divider {
|
.panel-divider {
|
||||||
flex: 1;
|
flex: 1;
|
||||||
height: 1px;
|
height: 1px;
|
||||||
|
|||||||
@@ -647,6 +647,13 @@
|
|||||||
overflow-wrap: anywhere;
|
overflow-wrap: anywhere;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Translated layer names are longer: break between words, and hyphenate a
|
||||||
|
word that still does not fit instead of splitting it anywhere. */
|
||||||
|
html:not([lang='en']) .data-name {
|
||||||
|
overflow-wrap: break-word;
|
||||||
|
hyphens: auto;
|
||||||
|
}
|
||||||
|
|
||||||
.data-toggle-right {
|
.data-toggle-right {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex: 0 1 auto;
|
flex: 0 1 auto;
|
||||||
|
|||||||
@@ -366,6 +366,15 @@
|
|||||||
color: var(--text-secondary);
|
color: var(--text-secondary);
|
||||||
font-style: italic;
|
font-style: italic;
|
||||||
}
|
}
|
||||||
|
/* A translated slot line (date · source · resolution · state) is longer:
|
||||||
|
let it take a second line rather than cut off the state at the end. */
|
||||||
|
html:not([lang='en']) .recent-imagery-readout .ri-slot {
|
||||||
|
height: auto;
|
||||||
|
min-height: 20px;
|
||||||
|
}
|
||||||
|
html:not([lang='en']) .recent-imagery-readout .ri-slot-value {
|
||||||
|
white-space: normal;
|
||||||
|
}
|
||||||
.recent-imagery-readout .ri-unpin {
|
.recent-imagery-readout .ri-unpin {
|
||||||
width: 22px;
|
width: 22px;
|
||||||
padding: 0;
|
padding: 0;
|
||||||
|
|||||||
@@ -471,3 +471,9 @@ html:not([lang='en']) #scene-select {
|
|||||||
font-size: 10px;
|
font-size: 10px;
|
||||||
letter-spacing: 0.04em;
|
letter-spacing: 0.04em;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* A translated scene name needs the width: the select takes its own row and
|
||||||
|
NEW / DELETE share the next one. */
|
||||||
|
html:not([lang='en']) #scene-select {
|
||||||
|
flex: 1 1 100%;
|
||||||
|
}
|
||||||
Reference in new issue
Block a user