mirror of
https://github.com/bilawalsidhu/gods-eye-view.git
synced 2026-11-06 11:24:00 +00:00
Merge main into the Utilities panel, rebuilt on the Vue panel rail
main moved the panels to Vue views and a one-open-panel rail, and removed
the two templates this branch edited. This merge carries the branch onto
that architecture; it adds no behaviour of its own beyond the port.
- The Utilities panel is a RailPanel in LayerPanelsView with its own rail
item (handyman). LayerPanel renders the Directions rows into its list with
LayerRows, and falls back to Data Layers without it.
- Draw leaves DisplayPanel for DrawControls, DrawMarkList and DrawSwatches,
which render what the draw tool publishes to the display store and call
its actions, as GeoImport does. drawMarks.js words the rows; the DOM-built
drawMarkList.js is gone. A row's fly-to is an immediate navigation like
Import's ('drawing' gets its Cockpit refusal), the name field keeps a
draft through v-field-value, and the colours are one radio group with a
single tab stop.
- UiSegmented draws an option's icon, named by its label, for the shape
buttons.
- The catalogs take main's languages with this branch's strings, Arabic
included, and the tests follow the views to their new homes.
This commit is contained in:
commit
4ebb287d36
699 files changed
+46673
-20476
No files matched your search
@@ -0,0 +1,206 @@
|
||||
import test from 'node:test';
|
||||
import assert from 'node:assert/strict';
|
||||
import {
|
||||
formatDate,
|
||||
formatNumber,
|
||||
getLocale,
|
||||
keepCodesWithValues,
|
||||
setLocale,
|
||||
t,
|
||||
tn,
|
||||
} from './index.js';
|
||||
import {
|
||||
applyDocumentLanguage,
|
||||
intlLocale,
|
||||
LOCALE_STORAGE_KEY,
|
||||
resolveLocale,
|
||||
} from './locale.js';
|
||||
import { hudQuantity, LOCALIZED_LOCALITY } from '../hudLocalityFormat.js';
|
||||
import { formatCockpitDistance } from '../ui/cockpitPresentation.js';
|
||||
import { READOUT_WORDS } from '../layers/recentImagery/display.js';
|
||||
import { createPresentation as createCctvPresentation } from '../layers/cctv/presentation.js';
|
||||
import {
|
||||
formatQuantity,
|
||||
formatScaleLabel,
|
||||
formatScaleRange,
|
||||
} from '../ui/unitLabels.js';
|
||||
|
||||
test('Arabic resolves from URL, saved preference and browser language', () => {
|
||||
assert.equal(
|
||||
resolveLocale({
|
||||
location: { search: '?lang=ar-EG' },
|
||||
storage: { getItem: () => 'en' },
|
||||
languages: ['en'],
|
||||
}),
|
||||
'ar',
|
||||
);
|
||||
assert.equal(
|
||||
resolveLocale({
|
||||
location: { search: '' },
|
||||
storage: {
|
||||
getItem: (key) => (key === LOCALE_STORAGE_KEY ? 'ar' : null),
|
||||
},
|
||||
languages: ['en'],
|
||||
}),
|
||||
'ar',
|
||||
);
|
||||
assert.equal(
|
||||
resolveLocale({
|
||||
location: { search: '' },
|
||||
storage: { getItem: () => null },
|
||||
languages: ['ar-SA', 'en'],
|
||||
}),
|
||||
'ar',
|
||||
);
|
||||
});
|
||||
|
||||
test('Arabic turns the page right-to-left; other languages stay left-to-right', () => {
|
||||
const doc = { documentElement: {} };
|
||||
applyDocumentLanguage(doc, 'ar');
|
||||
assert.deepEqual(doc.documentElement, { lang: 'ar', dir: 'rtl' });
|
||||
applyDocumentLanguage(doc, 'zh-CN');
|
||||
assert.deepEqual(doc.documentElement, { lang: 'zh-CN', dir: 'ltr' });
|
||||
});
|
||||
|
||||
test('Arabic formats with Western digits whatever ICU defaults to', () => {
|
||||
assert.equal(intlLocale('ar'), 'ar-u-nu-latn');
|
||||
assert.equal(intlLocale('ru'), 'ru');
|
||||
const previous = getLocale();
|
||||
try {
|
||||
setLocale('ar');
|
||||
assert.equal(formatNumber(1234.5), '1,234.5');
|
||||
assert.equal(
|
||||
formatDate(Date.UTC(2026, 7, 26), {
|
||||
day: 'numeric',
|
||||
month: 'long',
|
||||
year: 'numeric',
|
||||
timeZone: 'UTC',
|
||||
}),
|
||||
'26 أغسطس 2026',
|
||||
);
|
||||
assert.doesNotMatch(formatNumber(9876543210), /[٠-٩]/);
|
||||
} finally {
|
||||
setLocale(previous);
|
||||
}
|
||||
});
|
||||
|
||||
/** The text without the bidi isolates t() puts around values in RTL. */
|
||||
const plain = (text) => text.replace(/[\u2068\u2069]/g, '');
|
||||
|
||||
test('Arabic uses all six plural forms and spaced HUD units', () => {
|
||||
const previous = getLocale();
|
||||
try {
|
||||
setLocale('ar');
|
||||
assert.deepEqual(
|
||||
[0, 1, 2, 3, 11, 100].map((n) =>
|
||||
plain(tn(n, '{count} SOURCE', '{count} SOURCES')),
|
||||
),
|
||||
[
|
||||
'0 مصدر',
|
||||
'مصدر واحد (1)',
|
||||
'مصدران (2)',
|
||||
'3 مصادر',
|
||||
'11 مصدرًا',
|
||||
'100 مصدر',
|
||||
],
|
||||
);
|
||||
assert.equal(hudQuantity(2069, 'km', 1), '2069.0 كم');
|
||||
// Isolated, so the number keeps its unit next to Latin words.
|
||||
assert.equal(formatCockpitDistance(14000), '\u206814\u00a0كم\u2069');
|
||||
assert.equal(
|
||||
`Sentinel-2 · ${formatQuantity(30, 'm')}`,
|
||||
'Sentinel-2 · \u206830\u00a0م\u2069',
|
||||
);
|
||||
assert.equal(
|
||||
plain(LOCALIZED_LOCALITY.sector({ latDeg: 21.33, lonDeg: -77.5 })),
|
||||
'القطاع 21.33ش 77.50غ',
|
||||
);
|
||||
assert.equal(READOUT_WORDS.daysAgo(9), 'قبل 9 أيام');
|
||||
assert.equal(t('SAVE KEYS'), 'حفظ المفاتيح');
|
||||
// Each value is isolated, so a time keeps its order inside Arabic text.
|
||||
assert.equal(
|
||||
t('Issued: {time}', { time: '10/28 00:00 UTC' }),
|
||||
'صدر: \u206810/28 00:00 UTC\u2069',
|
||||
);
|
||||
// A Latin code stays beside its own value: HDG 68° · FOV 44°.
|
||||
assert.equal(
|
||||
keepCodesWithValues(
|
||||
t('{city} · HDG {heading} · FOV {fov}', {
|
||||
city: 'Austin',
|
||||
heading: '68°',
|
||||
fov: '44°',
|
||||
}),
|
||||
),
|
||||
'\u2068Austin\u2069 · \u2068HDG \u206868°\u2069\u2069 · \u2068FOV \u206844°\u2069\u2069',
|
||||
);
|
||||
// A legend's open bound keeps its plus on the written side: 300+.
|
||||
assert.deepEqual(['300+', '0.1'].map(formatScaleLabel), [
|
||||
'\u2068300+\u2069',
|
||||
'\u20680.1\u2069',
|
||||
]);
|
||||
// A Latin unit after the range keeps its order: °C, not C°.
|
||||
assert.equal(
|
||||
formatScaleRange('-40', '50+', '°C'),
|
||||
`${formatScaleLabel('-40')} — \u206850+\u2069\u00a0\u2068°C\u2069`,
|
||||
);
|
||||
// Counted minutes agree with the number (3–10 plural, 11+ singular).
|
||||
assert.deepEqual(
|
||||
[3, 15].map((n) =>
|
||||
formatNumber(n, {
|
||||
style: 'unit',
|
||||
unit: 'minute',
|
||||
unitDisplay: 'long',
|
||||
}),
|
||||
),
|
||||
['3 دقائق', '15 دقيقة'],
|
||||
);
|
||||
setLocale('ru');
|
||||
assert.equal(keepCodesWithValues('HDG 68°'), 'HDG 68°');
|
||||
assert.equal(formatCockpitDistance(14000), '14 КМ');
|
||||
} finally {
|
||||
setLocale(previous);
|
||||
}
|
||||
});
|
||||
|
||||
test('Arabic keeps each CCTV summary code beside its own value', () => {
|
||||
const camera = {
|
||||
id: 'cam-1',
|
||||
city: 'Austin',
|
||||
name: 'Congress Ave',
|
||||
headingDeg: 68,
|
||||
fovDeg: 44,
|
||||
rangeM: 120,
|
||||
feedType: 'image',
|
||||
};
|
||||
const active = { camera };
|
||||
const presentation = createCctvPresentation({
|
||||
state: {
|
||||
_records: [active],
|
||||
_healthById: new Map(),
|
||||
_showProjection: true,
|
||||
_coverageMode: 'sector',
|
||||
},
|
||||
parts: {
|
||||
selection: { getActiveRecord: () => active },
|
||||
model: {
|
||||
sectorAreaKm2: () => 0.01,
|
||||
currentViewContext: () => 'street:1',
|
||||
},
|
||||
geometry: { coverageNeighborCount: () => 0 },
|
||||
calibration: { deriveCalBadge: () => 'auto' },
|
||||
},
|
||||
});
|
||||
const previous = getLocale();
|
||||
try {
|
||||
setLocale('ar');
|
||||
const parts = presentation.buildSummaryText().split(' · ');
|
||||
// Each part is its own isolate: «HDG 68° · FOV 44°» cannot form one
|
||||
// left-to-right run that hands 44° to the HDG side.
|
||||
for (const part of parts) assert.match(part, /^\u2068[\s\S]*\u2069$/);
|
||||
assert.ok(parts.includes('\u2068FOV \u206844\u2069°\u2069'), parts.join(' | '));
|
||||
setLocale('en');
|
||||
assert.doesNotMatch(presentation.buildSummaryText(), /[\u2068\u2069]/);
|
||||
} finally {
|
||||
setLocale(previous);
|
||||
}
|
||||
});
|
||||
@@ -5,6 +5,7 @@ import {
|
||||
checkCatalog,
|
||||
extractMessages,
|
||||
findUnmarked,
|
||||
markedTemplate,
|
||||
readCatalog,
|
||||
shippedLocales,
|
||||
unmarkedMarkup,
|
||||
@@ -111,6 +112,32 @@ test('unmarkedMarkup finds text and attributes without data-i18n*', () => {
|
||||
assert.deepEqual(texts('<!-- Note --><span>— 42 —</span>'), []);
|
||||
});
|
||||
|
||||
test('markedTemplate rejects data-i18n* attributes in a Vue template', () => {
|
||||
const view = [
|
||||
'<script setup>',
|
||||
"const note = 'data-i18n';",
|
||||
'</script>',
|
||||
'<template>',
|
||||
' <!-- no data-i18n here -->',
|
||||
' <span data-i18n>Normal</span>',
|
||||
' <b title="Explains data-i18n" data-i18n-title>{{ t(\'Go\') }}</b>',
|
||||
' <i :data-i18n="true" />',
|
||||
'</template>',
|
||||
].join('\n');
|
||||
assert.deepEqual(markedTemplate('View.vue', view), [
|
||||
{ where: 'View.vue:6', text: 'data-i18n: use t() in a Vue template' },
|
||||
{ where: 'View.vue:7', text: 'data-i18n-title: use t() in a Vue template' },
|
||||
{ where: 'View.vue:8', text: 'data-i18n: use t() in a Vue template' },
|
||||
]);
|
||||
assert.deepEqual(
|
||||
markedTemplate(
|
||||
'View.vue',
|
||||
'<template><b :title="t(\'Pin\')">x</b></template>',
|
||||
),
|
||||
[],
|
||||
);
|
||||
});
|
||||
|
||||
test('unmarkedScript finds literals that reach the page without t/tn/msg', () => {
|
||||
const texts = (js) => unmarkedScript('f.js', js).map((f) => f.text);
|
||||
assert.deepEqual(texts("el.textContent = 'Saved';"), ['Saved']);
|
||||
|
||||
+58
-26
@@ -7,7 +7,8 @@ import {
|
||||
formatNumber,
|
||||
formatRelativeTime,
|
||||
msg,
|
||||
persistLocaleAndReload,
|
||||
onLocaleChange,
|
||||
persistLocale,
|
||||
setLocale,
|
||||
t,
|
||||
tn,
|
||||
@@ -63,6 +64,9 @@ test('normalizeLocale folds regional variants and rejects unshipped tags', () =>
|
||||
assert.equal(normalizeLocale('zh-Hant-CN'), 'zh-Hant');
|
||||
assert.equal(normalizeLocale('zh_HK'), 'zh-Hant');
|
||||
assert.equal(normalizeLocale('zh-MO'), 'zh-Hant');
|
||||
assert.equal(normalizeLocale('ar'), 'ar');
|
||||
assert.equal(normalizeLocale('ar-EG'), 'ar');
|
||||
assert.equal(normalizeLocale(' AR_sa '), 'ar');
|
||||
assert.equal(normalizeLocale(undefined), null);
|
||||
});
|
||||
|
||||
@@ -126,6 +130,10 @@ test('applyDocumentLanguage sets lang and dir', () => {
|
||||
const doc = { documentElement: {} };
|
||||
applyDocumentLanguage(doc, 'ru-RU');
|
||||
assert.deepEqual(doc.documentElement, { lang: 'ru', dir: 'ltr' });
|
||||
applyDocumentLanguage(doc, 'ar-EG');
|
||||
assert.deepEqual(doc.documentElement, { lang: 'ar', dir: 'rtl' });
|
||||
applyDocumentLanguage(doc, 'en');
|
||||
assert.deepEqual(doc.documentElement, { lang: 'en', dir: 'ltr' });
|
||||
});
|
||||
|
||||
test('t() returns English text in English and translates in Russian', () => {
|
||||
@@ -258,6 +266,40 @@ test('applyDocumentTranslations translates opted-in text and attributes in place
|
||||
assert.equal(label.textContent, t('POWERED UP'));
|
||||
assert.equal(pin.attrs.get('title'), t('POWERED UP'));
|
||||
assert.equal(unknown.textContent, 'No such message');
|
||||
// A later pass starts from the English source, so every switch applies.
|
||||
setLocale('de');
|
||||
applyDocumentTranslations(doc);
|
||||
assert.equal(label.textContent, t('POWERED UP'));
|
||||
setLocale('en');
|
||||
assert.equal(applyDocumentTranslations(doc), 2, 'English restores');
|
||||
assert.equal(label.textContent, 'POWERED UP');
|
||||
assert.equal(pin.attrs.get('title'), 'POWERED UP');
|
||||
// Text that code wrote since is the new source; a pass leaves it alone.
|
||||
label.textContent = 'Error: offline';
|
||||
setLocale('ru');
|
||||
applyDocumentTranslations(doc);
|
||||
assert.equal(label.textContent, 'Error: offline');
|
||||
});
|
||||
|
||||
test('onLocaleChange listeners hear each change until removed', () => {
|
||||
const heard = [];
|
||||
const off = onLocaleChange(() => heard.push(t('POWERED UP')));
|
||||
const broken = onLocaleChange(() => {
|
||||
throw new Error('broken listener');
|
||||
});
|
||||
const error = console.error;
|
||||
console.error = () => {};
|
||||
try {
|
||||
setLocale('ru');
|
||||
setLocale('ru');
|
||||
assert.deepEqual(heard, [t('POWERED UP')], 'once, in the new locale');
|
||||
off();
|
||||
setLocale('en');
|
||||
assert.equal(heard.length, 1);
|
||||
} finally {
|
||||
console.error = error;
|
||||
broken();
|
||||
}
|
||||
});
|
||||
|
||||
test('applyDocumentTranslations reads data-i18n-context for element text', () => {
|
||||
@@ -275,13 +317,9 @@ test('applyDocumentTranslations reads data-i18n-context for element text', () =>
|
||||
assert.notEqual(option.textContent, t('All'));
|
||||
});
|
||||
|
||||
test('persistLocaleAndReload keeps the choice in ?lang when storage is blocked', () => {
|
||||
test('persistLocale keeps the choice in ?lang when storage is blocked', () => {
|
||||
const calls = [];
|
||||
const location = {
|
||||
href: 'https://gev.local/?x=1#scene=a',
|
||||
assign: (url) => calls.push(['assign', url]),
|
||||
reload: () => calls.push(['reload']),
|
||||
};
|
||||
const location = { href: 'https://gev.local/?x=1#scene=a' };
|
||||
const history = {
|
||||
replaceState: (_s, _t, url) => calls.push(['replace', url]),
|
||||
};
|
||||
@@ -290,36 +328,30 @@ test('persistLocaleAndReload keeps the choice in ?lang when storage is blocked',
|
||||
throw new Error('blocked');
|
||||
},
|
||||
};
|
||||
assert.equal(
|
||||
persistLocaleAndReload('ru', { location, history, storage }),
|
||||
true,
|
||||
);
|
||||
assert.equal(persistLocale('ru', { location, history, storage }), 'ru');
|
||||
assert.deepEqual(calls, [
|
||||
['replace', 'https://gev.local/?x=1&lang=ru#scene=a'],
|
||||
['reload'],
|
||||
]);
|
||||
});
|
||||
|
||||
test('persistLocaleAndReload stores the choice, keeps the hash, strips ?lang', () => {
|
||||
test('persistLocale stores the choice, keeps the hash, strips ?lang', () => {
|
||||
const storage = memoryStorage();
|
||||
const calls = [];
|
||||
const location = {
|
||||
href: 'https://gev.local/?lang=en&x=1#scene=a',
|
||||
assign: (url) => calls.push(['assign', url]),
|
||||
reload: () => calls.push(['reload']),
|
||||
};
|
||||
const location = { href: 'https://gev.local/?lang=en&x=1#scene=a' };
|
||||
const history = {
|
||||
replaceState: (_s, _t, url) => calls.push(['replace', url]),
|
||||
};
|
||||
assert.equal(
|
||||
persistLocaleAndReload('ru', { location, history, storage }),
|
||||
true,
|
||||
);
|
||||
assert.equal(persistLocale('ru', { location, history, storage }), 'ru');
|
||||
assert.equal(storage.data.get(LOCALE_STORAGE_KEY), 'ru');
|
||||
assert.deepEqual(calls, [
|
||||
['replace', 'https://gev.local/?x=1#scene=a'],
|
||||
['reload'],
|
||||
]);
|
||||
assert.deepEqual(calls, [['replace', 'https://gev.local/?x=1#scene=a']]);
|
||||
// An address without ?lang is left as it is.
|
||||
calls.length = 0;
|
||||
persistLocale('de', {
|
||||
location: { href: 'https://gev.local/#scene=a' },
|
||||
history,
|
||||
storage,
|
||||
});
|
||||
assert.deepEqual(calls, []);
|
||||
});
|
||||
|
||||
test('tn() shows a caller-formatted count and still picks the form by number', () => {
|
||||
|
||||
+134
-82
@@ -13,9 +13,12 @@
|
||||
// `npm run i18n` keeps the catalogs in step with the code. Guide: docs/I18N.md.
|
||||
import {
|
||||
DEFAULT_LOCALE,
|
||||
intlLocale,
|
||||
isRtlLocale,
|
||||
normalizeLocale,
|
||||
writeStoredLocale,
|
||||
} from './locale.js';
|
||||
import ar from './locales/ar.json' with { type: 'json' };
|
||||
import de from './locales/de.json' with { type: 'json' };
|
||||
import es from './locales/es.json' with { type: 'json' };
|
||||
import fr from './locales/fr.json' with { type: 'json' };
|
||||
@@ -28,6 +31,7 @@ import zhCN from './locales/zh-CN.json' with { type: 'json' };
|
||||
import zhHant from './locales/zh-Hant.json' with { type: 'json' };
|
||||
|
||||
const CATALOGS = Object.freeze({
|
||||
ar,
|
||||
de,
|
||||
es,
|
||||
fr,
|
||||
@@ -40,37 +44,114 @@ const CATALOGS = Object.freeze({
|
||||
'zh-Hant': zhHant,
|
||||
});
|
||||
|
||||
let currentLocale = DEFAULT_LOCALE;
|
||||
// The page's locale. The UI binds it to its vue-i18n instance's
|
||||
// (src/ui/i18n.js), so a Vue render that translates re-renders when it
|
||||
// changes; until then, and in portable code, it is plain state.
|
||||
let pageLocale = { value: DEFAULT_LOCALE };
|
||||
|
||||
/**
|
||||
* Keep the active locale in `locale`, a ref such as a vue-i18n composer's
|
||||
* `locale`. It takes the current locale; switch with setLocale afterwards.
|
||||
* @param {{value: string}} locale
|
||||
*/
|
||||
export function bindLocale(locale) {
|
||||
locale.value = pageLocale.value;
|
||||
pageLocale = locale;
|
||||
bound = true;
|
||||
}
|
||||
|
||||
let bound = false;
|
||||
const localeListeners = new Set();
|
||||
|
||||
/**
|
||||
* Call `listener` after the active locale changes, so code that shows text it
|
||||
* translated itself (a status line, a count, a time) shows it again. Text a
|
||||
* Vue view translates while rendering follows the locale without this.
|
||||
* @param {() => void} listener
|
||||
* @returns {() => void} Stops listening.
|
||||
*/
|
||||
export function onLocaleChange(listener) {
|
||||
if (typeof listener !== 'function') return () => {};
|
||||
localeListeners.add(listener);
|
||||
return () => localeListeners.delete(listener);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tell the listeners the locale changed. setLocale does this for an unbound
|
||||
* locale; the owner of a bound ref calls it when the ref changes.
|
||||
*/
|
||||
export function notifyLocaleChange() {
|
||||
for (const listener of [...localeListeners]) {
|
||||
try {
|
||||
listener();
|
||||
} catch (error) {
|
||||
console.error('[i18n] locale listener failed', error);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** The catalog for a locale; null for English and unknown codes. */
|
||||
export function getCatalog(locale) {
|
||||
return CATALOGS[normalizeLocale(locale)] ?? null;
|
||||
}
|
||||
|
||||
/** Active locale. */
|
||||
let boundValue = DEFAULT_LOCALE;
|
||||
let activeLocale = DEFAULT_LOCALE;
|
||||
|
||||
/** Active locale, normalized: a bound ref may be set to any language tag. */
|
||||
export function getLocale() {
|
||||
return currentLocale;
|
||||
const value = pageLocale.value;
|
||||
if (value !== boundValue) {
|
||||
boundValue = value;
|
||||
activeLocale = normalizeLocale(value) || DEFAULT_LOCALE;
|
||||
}
|
||||
return activeLocale;
|
||||
}
|
||||
|
||||
/**
|
||||
* Switch the active locale. Pure state change: call applyDocumentLanguage /
|
||||
* applyDocumentTranslations to reflect it in the DOM.
|
||||
* A value inserted into right-to-left text as one unit: `30 م` next to
|
||||
* `Sentinel-2` would otherwise lend its digits to the Latin run and leave the
|
||||
* unit stranded. First-strong isolates (U+2068…U+2069) in RTL locales only.
|
||||
*/
|
||||
export function isolate(text) {
|
||||
return isRtlLocale(getLocale()) ? `\u2068${text}\u2069` : String(text);
|
||||
}
|
||||
|
||||
const CODE_BEFORE_VALUE =
|
||||
/(?<![\p{L}\p{N}])([A-Z][A-Z0-9/]+) (\u2068[^\u2068\u2069]*\u2069)/gu;
|
||||
|
||||
/**
|
||||
* A Latin code and the isolated value after it ("HDG 68\u00b0") as one unit in
|
||||
* right-to-left text. Two codes in a row (HDG 68\u00b0 \u00b7 FOV 44\u00b0) otherwise form a
|
||||
* single left-to-right run and the second code ends up beside the first
|
||||
* value. Applies to t() output; a no-op outside RTL locales.
|
||||
*/
|
||||
export function keepCodesWithValues(text) {
|
||||
if (!isRtlLocale(getLocale())) return text;
|
||||
return String(text).replace(CODE_BEFORE_VALUE, '\u2068$1 $2\u2069');
|
||||
}
|
||||
|
||||
/**
|
||||
* Switch the active locale. Views re-render and onLocaleChange listeners
|
||||
* word their text again; the application keeps <html lang>/<html dir> and
|
||||
* the page's data-i18n markup in step.
|
||||
* @returns {string} The locale actually applied (normalized).
|
||||
*/
|
||||
export function setLocale(locale) {
|
||||
const normalized = normalizeLocale(locale) || DEFAULT_LOCALE;
|
||||
if (normalized !== currentLocale) {
|
||||
currentLocale = normalized;
|
||||
if (normalized !== pageLocale.value) {
|
||||
pageLocale.value = normalized;
|
||||
formatterCache.clear();
|
||||
if (!bound) notifyLocaleChange();
|
||||
}
|
||||
return currentLocale;
|
||||
return normalized;
|
||||
}
|
||||
|
||||
/** Development-only warning; silent under node:test and in production. */
|
||||
function warnMissing(text) {
|
||||
if (import.meta.env?.DEV !== true) return;
|
||||
console.warn(
|
||||
`[i18n] no ${currentLocale} translation for ${JSON.stringify(text)}`,
|
||||
`[i18n] no ${getLocale()} translation for ${JSON.stringify(text)}`,
|
||||
);
|
||||
}
|
||||
|
||||
@@ -80,16 +161,20 @@ const PLACEHOLDER_PATTERN = /\{([A-Za-z0-9_]+)\}/g;
|
||||
* stays visible instead of silently vanishing. */
|
||||
function interpolate(pattern, values) {
|
||||
if (!values) return pattern;
|
||||
return pattern.replace(PLACEHOLDER_PATTERN, (literal, name) =>
|
||||
Object.hasOwn(values, name) ? String(values[name]) : literal,
|
||||
);
|
||||
// In a right-to-left page each value is isolated: a time, a code or an
|
||||
// English name keeps its own order instead of mixing with the sentence.
|
||||
return pattern.replace(PLACEHOLDER_PATTERN, (literal, name) => {
|
||||
if (!Object.hasOwn(values, name)) return literal;
|
||||
const value = String(values[name]);
|
||||
return value === '' ? value : isolate(value);
|
||||
});
|
||||
}
|
||||
|
||||
/** A catalog string with something to show; an empty one counts as missing. */
|
||||
const filled = (value) => typeof value === 'string' && value.trim() !== '';
|
||||
|
||||
function lookup(text) {
|
||||
const catalog = CATALOGS[currentLocale];
|
||||
const catalog = CATALOGS[getLocale()];
|
||||
if (!catalog) return undefined;
|
||||
const entry = Object.hasOwn(catalog, text) ? catalog[text] : undefined;
|
||||
if (filled(entry) || (entry && typeof entry === 'object')) return entry;
|
||||
@@ -124,7 +209,7 @@ export function t(text, values) {
|
||||
*/
|
||||
export function tn(count, one, other, values) {
|
||||
const entry = lookup(other);
|
||||
const category = pluralRules(currentLocale).select(count);
|
||||
const category = pluralRules(getLocale()).select(count);
|
||||
let pattern;
|
||||
const forms = entry && typeof entry === 'object' ? entry : null;
|
||||
if (forms && (filled(forms[category]) || filled(forms.other))) {
|
||||
@@ -141,7 +226,7 @@ export function tn(count, one, other, values) {
|
||||
* missing-translation warning.
|
||||
*/
|
||||
export function translateKnown(text) {
|
||||
const catalog = CATALOGS[currentLocale];
|
||||
const catalog = CATALOGS[getLocale()];
|
||||
if (!catalog || typeof text !== 'string') return text;
|
||||
const entry = Object.hasOwn(catalog, text) ? catalog[text] : undefined;
|
||||
return filled(entry) ? entry : text;
|
||||
@@ -171,10 +256,10 @@ function pluralRules(locale) {
|
||||
const formatterCache = new Map();
|
||||
|
||||
function cachedFormatter(kind, Constructor, options) {
|
||||
const cacheKey = `${kind}|${currentLocale}|${options ? JSON.stringify(options) : ''}`;
|
||||
const cacheKey = `${kind}|${getLocale()}|${options ? JSON.stringify(options) : ''}`;
|
||||
let formatter = formatterCache.get(cacheKey);
|
||||
if (!formatter) {
|
||||
formatter = new Constructor(currentLocale, options);
|
||||
formatter = new Constructor(intlLocale(getLocale()), options);
|
||||
formatterCache.set(cacheKey, formatter);
|
||||
}
|
||||
return formatter;
|
||||
@@ -210,7 +295,7 @@ export function formatUtcDayMonth(value) {
|
||||
? Date.UTC(Number(written[1]), Number(written[2]) - 1, Number(written[3]))
|
||||
: new Date(value).getTime();
|
||||
if (!Number.isFinite(time)) return '';
|
||||
if (currentLocale === 'en') return new Date(time).toISOString().slice(5, 10);
|
||||
if (getLocale() === 'en') return new Date(time).toISOString().slice(5, 10);
|
||||
return cachedFormatter('date', Intl.DateTimeFormat, UTC_DAY_MONTH).format(
|
||||
time,
|
||||
);
|
||||
@@ -228,7 +313,7 @@ export function formatRelativeTime(value, unit = 'second', options) {
|
||||
}).format(value, unit);
|
||||
// CLDR spaces Japanese (5 分前); the ja catalog writes the number and its
|
||||
// unit together (5分前), so the two must not differ on one screen.
|
||||
return currentLocale === 'ja'
|
||||
return getLocale() === 'ja'
|
||||
? text.replace(/(?<=\d) (?=\p{Script=Han})/gu, '')
|
||||
: text;
|
||||
}
|
||||
@@ -255,75 +340,57 @@ const DOCUMENT_TRANSLATION_TARGETS = Object.freeze([
|
||||
['data-i18n-placeholder', 'placeholder'],
|
||||
]);
|
||||
|
||||
// Per element, the English source a pass read and the text it wrote, so a
|
||||
// later pass in another locale, English included, starts from the source
|
||||
// rather than from that text. Text that code wrote since is the new source.
|
||||
const documentSources = new WeakMap();
|
||||
|
||||
/**
|
||||
* Translate every opted-in element in `doc`. Runs once at boot; switching
|
||||
* locale reloads the page.
|
||||
* Translate every opted-in element in `doc` into the active locale. Runs at
|
||||
* boot and again after every locale change (the page's own markup, such as
|
||||
* a host's, is not rendered by a view).
|
||||
* @param {Document|Element} doc
|
||||
* @returns {number} Count of element/attribute writes performed.
|
||||
*/
|
||||
export function applyDocumentTranslations(doc) {
|
||||
if (typeof doc?.querySelectorAll !== 'function') return 0;
|
||||
if (!CATALOGS[currentLocale]) return 0;
|
||||
let applied = 0;
|
||||
for (const [marker, attribute] of DOCUMENT_TRANSLATION_TARGETS) {
|
||||
for (const element of doc.querySelectorAll(`[${marker}]`)) {
|
||||
const source = attribute
|
||||
? element.getAttribute(attribute)
|
||||
: normalizeMarkupText(element.textContent);
|
||||
const read = () =>
|
||||
attribute
|
||||
? element.getAttribute(attribute)
|
||||
: normalizeMarkupText(element.textContent);
|
||||
let sources = documentSources.get(element);
|
||||
if (!sources) documentSources.set(element, (sources = {}));
|
||||
const shown = read();
|
||||
const known = sources[marker];
|
||||
const source = known && shown === known.written ? known.source : shown;
|
||||
sources[marker] = { source, written: shown };
|
||||
if (!source) continue;
|
||||
const context = attribute
|
||||
? null
|
||||
: element.getAttribute?.('data-i18n-context');
|
||||
const text = context ? t(source, { context }) : t(source);
|
||||
if (text === source) continue;
|
||||
if (text === shown) continue;
|
||||
if (attribute) element.setAttribute(attribute, text);
|
||||
else element.textContent = text;
|
||||
sources[marker].written = read();
|
||||
applied += 1;
|
||||
}
|
||||
}
|
||||
return applied;
|
||||
}
|
||||
|
||||
const unsavedWorkChecks = new Set();
|
||||
|
||||
/**
|
||||
* Name work that switching language would lose: the switch reloads the page,
|
||||
* and the language switch asks first while any check reports something.
|
||||
* @param {() => string|null|undefined} check Returns a msg() label (e.g.
|
||||
* msg('unsaved CCTV calibration')) while there is such work, else nothing.
|
||||
* @returns {() => void} Removes the check.
|
||||
* Store a locale choice for the next visit and keep the address in step
|
||||
* without reloading: ?lang is dropped once the choice is stored, or carries
|
||||
* the choice where storage is blocked (share links drop it:
|
||||
* ShareLinkManager.copyLink). The hash is kept exactly. setLocale applies
|
||||
* the choice to the page.
|
||||
* @returns {string} The normalized locale.
|
||||
*/
|
||||
export function registerUnsavedWork(check) {
|
||||
if (typeof check !== 'function') return () => {};
|
||||
unsavedWorkChecks.add(check);
|
||||
return () => unsavedWorkChecks.delete(check);
|
||||
}
|
||||
|
||||
/**
|
||||
* What a reload would lose right now, translated, without repeats.
|
||||
* @returns {string[]}
|
||||
*/
|
||||
export function describeUnsavedWork() {
|
||||
const labels = new Set();
|
||||
for (const check of unsavedWorkChecks) {
|
||||
try {
|
||||
const label = check();
|
||||
if (typeof label === 'string' && label) labels.add(t(label));
|
||||
} catch {
|
||||
// A failing check must not block the switch.
|
||||
}
|
||||
}
|
||||
return [...labels];
|
||||
}
|
||||
|
||||
/**
|
||||
* Persist a locale choice, then reload preserving window.location.hash exactly
|
||||
* and stripping ?lang from the search string, so the stored choice applies.
|
||||
* Where storage is blocked, ?lang carries the choice instead (share links
|
||||
* drop it: ShareLinkManager.copyLink).
|
||||
* @returns {boolean} true when a reload was triggered.
|
||||
*/
|
||||
export function persistLocaleAndReload(
|
||||
export function persistLocale(
|
||||
locale,
|
||||
{
|
||||
location = globalThis.location,
|
||||
@@ -333,28 +400,13 @@ export function persistLocaleAndReload(
|
||||
) {
|
||||
const normalized = normalizeLocale(locale) || DEFAULT_LOCALE;
|
||||
const stored = writeStoredLocale(normalized, storage);
|
||||
if (!location || typeof location.assign !== 'function') return false;
|
||||
let target = location.href;
|
||||
try {
|
||||
// Without storage the choice only survives in the URL, so keep it there.
|
||||
const url = new URL(location.href);
|
||||
if (stored) url.searchParams.delete('lang');
|
||||
else url.searchParams.set('lang', normalized);
|
||||
target = url.href;
|
||||
if (url.href !== location.href) history?.replaceState?.(null, '', url.href);
|
||||
} catch {
|
||||
// Keep the current href.
|
||||
// Without a location or history the stored choice still applies.
|
||||
}
|
||||
// location.assign() to the identical URL does not navigate, so strip ?lang
|
||||
// in place and force a real reload instead.
|
||||
try {
|
||||
history?.replaceState?.(null, '', target);
|
||||
} catch {
|
||||
// replaceState is best-effort; the reload below still applies.
|
||||
}
|
||||
if (typeof location.reload === 'function') {
|
||||
location.reload();
|
||||
} else {
|
||||
location.assign(target);
|
||||
}
|
||||
return true;
|
||||
return normalized;
|
||||
}
|
||||
+22
-1
@@ -10,6 +10,7 @@ export const DEFAULT_LOCALE = 'en';
|
||||
/** Shipped locales; order does not matter. Adding one: docs/TRANSLATORS.md. */
|
||||
export const LOCALES = Object.freeze([
|
||||
'en',
|
||||
'ar',
|
||||
'de',
|
||||
'es',
|
||||
'fr',
|
||||
@@ -25,6 +26,7 @@ export const LOCALES = Object.freeze([
|
||||
/** Each locale named in its own language, for the selector. */
|
||||
export const LOCALE_NAMES = Object.freeze({
|
||||
en: 'English',
|
||||
ar: 'العربية',
|
||||
de: 'Deutsch',
|
||||
es: 'Español',
|
||||
fr: 'Français',
|
||||
@@ -38,10 +40,29 @@ export const LOCALE_NAMES = Object.freeze({
|
||||
});
|
||||
|
||||
/** Right-to-left locales. */
|
||||
const RTL_LOCALES = Object.freeze([]);
|
||||
const RTL_LOCALES = Object.freeze(['ar']);
|
||||
|
||||
/** Whether a shipped locale reads right to left. */
|
||||
export function isRtlLocale(locale) {
|
||||
return RTL_LOCALES.includes(normalizeLocale(locale));
|
||||
}
|
||||
|
||||
/**
|
||||
* Tags for Intl formatters where the locale code alone is not enough. Arabic
|
||||
* keeps Western digits (0–9) like its catalog: ICU picks Arabic-Indic digits
|
||||
* (٠–٩) for some Arabic regions and browsers, and a HUD that mixes both
|
||||
* misreads.
|
||||
*/
|
||||
const INTL_TAGS = Object.freeze({ ar: 'ar-u-nu-latn' });
|
||||
|
||||
/** The tag to hand Intl.NumberFormat, DateTimeFormat and the like. */
|
||||
export function intlLocale(locale) {
|
||||
return INTL_TAGS[locale] ?? locale;
|
||||
}
|
||||
|
||||
/**
|
||||
* Map any language tag to a shipped locale: 'ru-RU' and 'RU' → 'ru',
|
||||
* 'ar-EG' and 'ar-SA' → 'ar',
|
||||
* 'de-AT' and 'de_CH' → 'de', 'ja-JP' → 'ja',
|
||||
* 'pt-BR' and 'pt-PT' → 'pt' (Brazilian Portuguese),
|
||||
* 'zh', 'zh-CN' and 'zh-Hans-SG' → 'zh-CN';
|
||||
|
||||
File diff suppressed because it is too large.
Load diff
+36
-22
@@ -153,7 +153,6 @@
|
||||
"NIGHT": "NACHT",
|
||||
"▲ {frp} MW": "▲ {frp} MW",
|
||||
"FIRE": "BRAND",
|
||||
"FIRES": "BRÄNDE",
|
||||
"max {value} MW": "max. {value} MW",
|
||||
"new {value}": "zuletzt vor {value}",
|
||||
"just now": "gerade eben",
|
||||
@@ -676,8 +675,6 @@
|
||||
"Cockpit vision style": "Sichtstil im Cockpit",
|
||||
"Previous cockpit vision style": "Vorheriger Cockpit-Sichtstil",
|
||||
"Previous vision style": "Vorheriger Sichtstil",
|
||||
"Current cockpit vision style: NORMAL. Activate for next style.": "Aktueller Cockpit-Sichtstil: NORMAL. Aktivieren für den nächsten Stil.",
|
||||
"Current style: NORMAL — click for next": "Aktueller Stil: NORMAL. Klicken für den nächsten",
|
||||
"CURRENT": "AKTUELL",
|
||||
"Next cockpit vision style": "Nächster Cockpit-Sichtstil",
|
||||
"Next vision style": "Nächster Sichtstil",
|
||||
@@ -748,7 +745,6 @@
|
||||
"Search any location...": "Ort suchen...",
|
||||
"WEATHER": "WETTER",
|
||||
"CONTEXT": "KONTEXT",
|
||||
"Expand panel": "Bereich ausklappen",
|
||||
"Context mode": "Kontextmodus",
|
||||
"CONTACTS": "KONTAKTE",
|
||||
"Cycles the nearest contacts of whatever type you select — planes, vessels, installations. Satellites track independently.": "Wechselt zwischen den nächstgelegenen Kontakten des gewählten Typs: Flugzeuge, Schiffe, Anlagen. Satelliten werden unabhängig verfolgt.",
|
||||
@@ -837,13 +833,7 @@
|
||||
"SAVE CAL": "KAL. SPEICHERN",
|
||||
"RESET CAL": "KAL. ZURÜCKSETZEN",
|
||||
"SCENE SUMMARY": "SZENEN-ÜBERSICHT",
|
||||
"SCENES": "SZENEN",
|
||||
"Scene recipe": "Szenenrezept",
|
||||
"NEW": "NEU",
|
||||
"CAPTURE SHOT": "AUFNAHME SPEICHERN",
|
||||
"UPDATE SHOT": "AUFNAHME AKTUALISIEREN",
|
||||
"START": "START",
|
||||
"EXPORT PRESETS": "PRESETS EXPORTIEREN",
|
||||
"IMPORT": "IMPORTIEREN",
|
||||
"RUN LOG": "PROTOKOLL",
|
||||
"POWER UP": "STARTKLAR",
|
||||
@@ -881,7 +871,6 @@
|
||||
"That line has no length — click somewhere further away.": "Diese Linie hat keine Länge – weiter entfernt klicken.",
|
||||
" · {max}-point limit reached": " · Limit von {max} Punkten erreicht",
|
||||
"{measure} · double-click or Enter to finish, Backspace undoes, Esc cancels.{full}": "{measure} · Doppelklick oder Enter beendet, Rücktaste macht rückgängig, Esc bricht ab.{full}",
|
||||
"drawings on the map": "Zeichnungen auf der Karte",
|
||||
"That shape already has {count} points — finish it or press Backspace.": "Diese Form hat bereits {count} Punkte – abschließen oder Rücktaste drücken.",
|
||||
"That point is off the globe — click on the world.": "Dieser Punkt liegt außerhalb des Globus – auf die Erde klicken.",
|
||||
"That shape could not be placed.": "Diese Form konnte nicht platziert werden.",
|
||||
@@ -1182,7 +1171,6 @@
|
||||
"GET KEY ↗": "SCHLÜSSEL HOLEN ↗",
|
||||
"{envVar} saved — paste to replace": "{envVar} gespeichert – zum Ersetzen einfügen",
|
||||
"paste {envVar}": "{envVar} einfügen",
|
||||
"unsaved provider keys": "ungespeicherte Anbieter-Schlüssel",
|
||||
"Project keys: {status}": "Projektschlüssel: {status}",
|
||||
"Cloud voice will use OPENAI_API_KEY on the next session.": "Die Cloud-Sprachsteuerung verwendet ab der nächsten Sitzung OPENAI_API_KEY.",
|
||||
"Checking local ChatGPT OAuth sign-in…": "Lokale ChatGPT-OAuth-Anmeldung wird geprüft…",
|
||||
@@ -1464,7 +1452,7 @@
|
||||
"Low-accuracy score 2–10%": "Ungenauigkeitswert 2–10 %",
|
||||
"Low-accuracy score > 10%": "Ungenauigkeitswert > 10 %",
|
||||
"GNSS integrity source unavailable": "GNSS-Integritätsquelle nicht verfügbar",
|
||||
"Regional sample · 250 nm radius · cells from visited views over 30 min": "Regionale Stichprobe · Radius 250 NM · Zellen aus besuchten Ansichten über 30 min",
|
||||
"Regional sample · 250 nm radius · cells from visited views over {minutes} min": "Regionale Stichprobe · Radius 250 NM · Zellen aus besuchten Ansichten über {minutes} min",
|
||||
"Retrying automatically at {time} UTC": "Automatischer neuer Versuch um {time} UTC",
|
||||
"Retrying automatically after provider cooldown": "Automatischer neuer Versuch nach der Sperrzeit des Anbieters",
|
||||
"Updates automatically after pan or zoom and once a minute. The public feed covers a 250-nautical-mile circle around the view centre; zooming out does not make it a worldwide snapshot. Blank cells are outside sampled coverage or have insufficient observations.": "Aktualisiert sich nach Schwenken oder Zoomen und einmal pro Minute automatisch. Der öffentliche Feed deckt einen Kreis von 250 Seemeilen um die Bildmitte ab; Herauszoomen macht daraus keinen weltweiten Snapshot. Leere Zellen liegen außerhalb der Stichprobe oder haben zu wenige Beobachtungen.",
|
||||
@@ -1765,6 +1753,8 @@
|
||||
"Contiguous US · gaps ≠ no rain": "USA ohne Alaska/Hawaii · Lücken ≠ kein Regen",
|
||||
"Americas + Pacific · not individual strikes": "Amerika + Pazifik · keine Einzelblitze",
|
||||
"Color: strikes/km²/min ×10³": "Farbe: Blitze/km²/min ×10³",
|
||||
"Color: {units}": "Farbe: {units}",
|
||||
"RADAR · {units}": "RADAR · {units}",
|
||||
"60°S–60°N · typically 2–3 h delayed": "60°S–60°N · meist 2–3 h verzögert",
|
||||
"North America · infrared imagery": "Nordamerika · Infrarotbilder",
|
||||
"Reduced motion · history playback unavailable": "Reduzierte Bewegung · Verlaufswiedergabe nicht verfügbar",
|
||||
@@ -2058,9 +2048,6 @@
|
||||
"Sensitivity": "Empfindlichkeit",
|
||||
"WHOT/BHOT": "WHOT/BHOT",
|
||||
"Ironbow": "Ironbow",
|
||||
"unsaved CCTV calibration": "ungespeicherte CCTV-Kalibrierung",
|
||||
"the open cockpit": "das geöffnete Cockpit",
|
||||
"Switching language reloads the page. This will be lost: {items}. Switch anyway?": "Ein Sprachwechsel lädt die Seite neu. Dabei geht Folgendes verloren: {items}. Trotzdem wechseln?",
|
||||
"Link shared": "Link geteilt",
|
||||
"Return map to straight-down view": "Karte wieder senkrecht von oben zeigen",
|
||||
"Tilt map to oblique view": "Karte in Schrägansicht kippen",
|
||||
@@ -2107,7 +2094,6 @@
|
||||
"{aircraftClass} · {emergency} · {feedState}": "{aircraftClass} · {emergency} · {feedState}",
|
||||
"{source} · LOCATION QUERY · RECENT": "{source} · ORTSABFRAGE · AKTUELL",
|
||||
"Rendered globe frames per second · toggle with `": "Gerenderte Globus-Frames pro Sekunde · umschalten mit `",
|
||||
"imported map files": "importierte Kartendateien",
|
||||
"Ground heights could not be refreshed. Try the file again when the map has loaded.": "Geländehöhen konnten nicht aktualisiert werden. Die Datei erneut laden, wenn die Karte geladen ist.",
|
||||
"{count} map objects": {
|
||||
"one": "{count} Kartenobjekt",
|
||||
@@ -2687,7 +2673,6 @@
|
||||
"Activate to toggle voice": "Aktivieren, um die Sprachsteuerung umzuschalten",
|
||||
"Voice active": "Sprachsteuerung aktiv",
|
||||
"Voice could not be started.": "Sprachsteuerung konnte nicht gestartet werden.",
|
||||
"the active voice session": "die aktive Sprachsitzung",
|
||||
"{value} feet": "{value} Fuß",
|
||||
"Fire · FRP {frp} MW": "Brand · FRP {frp} MW",
|
||||
"The flights layer is not enabled": "Die Ebene „Live-Flüge“ ist nicht aktiviert",
|
||||
@@ -2923,11 +2908,40 @@
|
||||
"STALE · Roads: {source} · Flow: cached TomTom tiles": "VERALTET · Straßen: {source} · Verkehrsfluss: TomTom-Kacheln aus dem Cache",
|
||||
"routing busy — too many routes at once": "Routing-Dienst ausgelastet – zu viele Routen gleichzeitig",
|
||||
"route proxy error": "Fehler des Routen-Proxys",
|
||||
"Colour of {name}": "Farbe von {name}",
|
||||
"Change the colour of {name}": "Farbe von {name} ändern",
|
||||
"scene|PLAY": "START",
|
||||
"AUTHORING": "ERSTELLUNG",
|
||||
"Create and edit scenes": "Szenen erstellen und bearbeiten",
|
||||
"SCENE": "SZENE",
|
||||
"Scene": "Szene",
|
||||
"NEW SCENE": "NEUE SZENE",
|
||||
"Start a new, empty scene": "Neue, leere Szene beginnen",
|
||||
"DELETE": "LÖSCHEN",
|
||||
"Delete this scene and all of its shots": "Diese Szene mit allen Aufnahmen löschen",
|
||||
"SHOTS": "AUFNAHMEN",
|
||||
"+ CAPTURE SHOT": "+ AUFNAHME SPEICHERN",
|
||||
"Add the current view, style and layers as the next shot": "Aktuelle Ansicht, Stil und Ebenen als nächste Aufnahme hinzufügen",
|
||||
"Replace the selected shot with the current view": "Ausgewählte Aufnahme durch die aktuelle Ansicht ersetzen",
|
||||
"Click a shot to select it, double-click to rename.": "Aufnahme anklicken zum Auswählen, Doppelklick zum Umbenennen.",
|
||||
"Play from this scene through the rest of the project": "Ab dieser Szene bis zum Ende des Projekts abspielen",
|
||||
"Stop playback (Esc)": "Wiedergabe stoppen (Esc)",
|
||||
"Play the shot after the selected one, moving on to the next scene when needed": "Aufnahme nach der ausgewählten abspielen, bei Bedarf in der nächsten Szene",
|
||||
"SAVE & SHARE": "SPEICHERN & TEILEN",
|
||||
"Download every scene as a JSON file you can import later": "Alle Szenen als JSON-Datei zum späteren Import herunterladen",
|
||||
"Load scenes from an exported JSON file": "Szenen aus einer exportierten JSON-Datei laden",
|
||||
"Download the timing log of the last play": "Zeitprotokoll der letzten Wiedergabe herunterladen",
|
||||
"Edit anchors, data packs and shot details": "Anker, Datenpakete und Aufnahmedetails bearbeiten",
|
||||
"Download this scene as JSON or an asset bundle": "Diese Szene als JSON oder Asset-Bundle herunterladen",
|
||||
"Left panels": "Linke Panels",
|
||||
"Right panels": "Rechte Panels",
|
||||
"CONFIRMED": "BESTÄTIGT",
|
||||
"PAD / RTLS": "STARTPLATZ / RTLS",
|
||||
"Name of {name}": "Name von {name}",
|
||||
"Change the colour of {name}": "Farbe von {name} ändern",
|
||||
"Colour of {name}": "Farbe von {name}",
|
||||
"Colour of the next shape": "Farbe der nächsten Form",
|
||||
"Drawn shapes": "Gezeichnete Formen",
|
||||
"Audio": "Audio",
|
||||
"UTILITIES": "WERKZEUGE",
|
||||
"Colour of the next shape": "Farbe der nächsten Form",
|
||||
"Drawn shapes": "Gezeichnete Formen"
|
||||
"Exit cockpit to fly to a drawing": "Cockpit verlassen, um zu einer Zeichnung zu fliegen",
|
||||
"Directions, drawing and your own files": "Route, Zeichnen und eigene Dateien"
|
||||
}
|
||||
+34
-20
@@ -129,8 +129,6 @@
|
||||
"PREV": "ANT.",
|
||||
"Previous cockpit vision style": "Estilo de visión de cabina anterior",
|
||||
"Previous vision style": "Estilo de visión anterior",
|
||||
"Current cockpit vision style: NORMAL. Activate for next style.": "Estilo de visión de cabina actual: NORMAL. Actívalo para pasar al siguiente estilo.",
|
||||
"Current style: NORMAL — click for next": "Estilo actual: NORMAL — haz clic para el siguiente",
|
||||
"NEXT": "SIG.",
|
||||
"Next cockpit vision style": "Siguiente estilo de visión de cabina",
|
||||
"Next vision style": "Siguiente estilo de visión",
|
||||
@@ -178,7 +176,6 @@
|
||||
"AVAILABLE INPUTS ONLY · NOT AN ALL-CLEAR": "SOLO DATOS DISPONIBLES · NO IMPLICA TODO DESPEJADO",
|
||||
"Enable cockpit weather effects": "Activar los efectos climáticos de la cabina",
|
||||
"CONTEXT": "CONTEXTO",
|
||||
"Expand panel": "Expandir panel",
|
||||
"Context mode": "Modo de contexto",
|
||||
"CONTACTS": "CONTACTOS",
|
||||
"Cycles the nearest contacts of whatever type you select — planes, vessels, installations. Satellites track independently.": "Recorre los contactos más cercanos del tipo que elijas — aeronaves, buques, instalaciones. Los satélites se rastrean por separado.",
|
||||
@@ -665,7 +662,6 @@
|
||||
"FIRE · {frp} MW": "INCENDIO · {frp} MW",
|
||||
"▲ {frp} MW": "▲ {frp} MW",
|
||||
"FIRE": "INCENDIO",
|
||||
"FIRES": "INCENDIOS",
|
||||
"{value} conf": "confianza {value}",
|
||||
"{value} ago": "hace {value}",
|
||||
"max {value} MW": "máx {value} MW",
|
||||
@@ -732,6 +728,8 @@
|
||||
"awaiting usable AIS positions…": "esperando posiciones AIS utilizables…",
|
||||
"awaiting first AIS message…": "esperando el primer mensaje AIS…",
|
||||
"EST. DOWNRANGE": "DIST. ESTIMADA",
|
||||
"CONFIRMED": "CONFIRMADA",
|
||||
"PAD / RTLS": "PLATAFORMA / RTLS",
|
||||
"MISSION CONTROL · FIRST LAUNCH": "CENTRO DE MANDO · PRIMER INICIO",
|
||||
"Choose your first view": "Elige tu primera vista",
|
||||
"LIVE CONTACTS": "CONTACTOS EN VIVO",
|
||||
@@ -752,15 +750,8 @@
|
||||
"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 funciona 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 restringirse en la consola del proveedor. Las claves que configuraste en otro lugar se muestran, pero nunca se modifican.",
|
||||
"ESC to close": "ESC para cerrar",
|
||||
"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",
|
||||
"UTILITIES": "UTILIDADES",
|
||||
"Scene recipe": "Receta de escena",
|
||||
"NEW": "NUEVA",
|
||||
"DEL": "BORRAR",
|
||||
"CAPTURE SHOT": "CAPTURAR PLANO",
|
||||
"UPDATE SHOT": "ACTUALIZAR PLANO",
|
||||
"START": "INICIAR",
|
||||
"EXPORT PRESETS": "EXPORTAR PREAJUSTES",
|
||||
"IMPORT": "IMPORTAR",
|
||||
"RUN LOG": "REGISTRO DE EJECUCIÓN",
|
||||
"Starting live contacts…": "Iniciando contactos en vivo…",
|
||||
@@ -1268,6 +1259,8 @@
|
||||
"Contiguous US · gaps ≠ no rain": "EE. UU. contiguos · huecos ≠ sin lluvia",
|
||||
"Americas + Pacific · not individual strikes": "América + Pacífico · no son rayos individuales",
|
||||
"Color: strikes/km²/min ×10³": "Color: rayos/km²/min ×10³",
|
||||
"Color: {units}": "Color: {units}",
|
||||
"RADAR · {units}": "RADAR · {units}",
|
||||
"60°S–60°N · typically 2–3 h delayed": "60°S–60°N · normalmente con 2–3 h de retraso",
|
||||
"North America · infrared imagery": "Norteamérica · imágenes infrarrojas",
|
||||
"Reduced motion · history playback unavailable": "Movimiento reducido · reproducción del historial no disponible",
|
||||
@@ -2167,7 +2160,7 @@
|
||||
"Low-accuracy score 2–10%": "Índice de baja precisión 2–10%",
|
||||
"Low-accuracy score > 10%": "Índice de baja precisión > 10%",
|
||||
"GNSS integrity source unavailable": "Fuente de integridad GNSS no disponible",
|
||||
"Regional sample · 250 nm radius · cells from visited views over 30 min": "Muestra regional · radio de 250 NM · celdas de las vistas visitadas en 30 min",
|
||||
"Regional sample · 250 nm radius · cells from visited views over {minutes} min": "Muestra regional · radio de 250 NM · celdas de las vistas visitadas en {minutes} min",
|
||||
"Retrying automatically at {time} UTC": "Reintento automático a las {time} UTC",
|
||||
"Retrying automatically after provider cooldown": "Reintento automático tras la pausa del proveedor",
|
||||
"Updates automatically after pan or zoom and once a minute. The public feed covers a 250-nautical-mile circle around the view centre; zooming out does not make it a worldwide snapshot. Blank cells are outside sampled coverage or have insufficient observations.": "Se actualiza automáticamente al desplazar o hacer zoom y una vez por minuto. El feed público cubre un círculo de 250 millas náuticas alrededor del centro de la vista; alejarte no lo convierte en una instantánea mundial. Las celdas vacías están fuera de la cobertura muestreada o no tienen observaciones suficientes.",
|
||||
@@ -2478,9 +2471,6 @@
|
||||
"ChatGPT sign-in timed out. Click {button} to try again.": "Se agotó el tiempo para iniciar sesión en ChatGPT. Haz clic en \"{button}\" para intentarlo de nuevo.",
|
||||
"ChatGPT sign-in complete. OAuth will be used for the next cloud voice session.": "Sesión de ChatGPT iniciada. Se usará OAuth en la próxima sesión de voz en la nube.",
|
||||
"OAuth check failed: {detail}": "Error al comprobar OAuth: {detail}",
|
||||
"unsaved CCTV calibration": "la calibración de CCTV sin guardar",
|
||||
"the open cockpit": "la cabina abierta",
|
||||
"Switching language reloads the page. This will be lost: {items}. Switch anyway?": "Cambiar de idioma recarga la página. Se perderá lo siguiente: {items}. ¿Cambiar de todos modos?",
|
||||
"Wind upstream unavailable": "Origen de datos de viento no disponible",
|
||||
"WebUSB needs desktop Chrome or Edge": "WebUSB requiere Chrome o Edge de escritorio",
|
||||
"connect a receiver in Radio": "conecta un receptor en Radio",
|
||||
@@ -2666,9 +2656,6 @@
|
||||
"KartaView answered HTTP {status}": "KartaView respondió HTTP {status}",
|
||||
"KartaView refused the request (code {code})": "KartaView rechazó la petición (código {code})",
|
||||
"Stopped by voice": "Detenido por voz",
|
||||
"drawings on the map": "los dibujos del mapa",
|
||||
"imported map files": "los archivos importados en el mapa",
|
||||
"the active voice session": "la sesión de voz activa",
|
||||
"Light aircraft": "Avioneta",
|
||||
"Glider": "Planeador",
|
||||
"Turboprop": "Turbohélice",
|
||||
@@ -2869,7 +2856,6 @@
|
||||
"many": "fuentes {names} no válidas",
|
||||
"other": "fuentes {names} no válidas"
|
||||
},
|
||||
"unsaved provider keys": "las claves de proveedores sin guardar",
|
||||
"Exit cockpit to fly to an aircraft": "Sal de la cabina para volar a una aeronave",
|
||||
"Exit cockpit to fly to a satellite": "Sal de la cabina para volar a un satélite",
|
||||
"Exit cockpit to frame contacts": "Sal de la cabina para encuadrar contactos",
|
||||
@@ -2999,5 +2985,33 @@
|
||||
"Preview is off.": "La vista previa está desactivada.",
|
||||
"Automatic stop is unavailable for this voice connection.": "La parada automática no está disponible para esta conexión de voz.",
|
||||
"routing busy — too many routes at once": "servicio de rutas ocupado: demasiadas rutas a la vez",
|
||||
"route proxy error": "error del proxy de rutas"
|
||||
"route proxy error": "error del proxy de rutas",
|
||||
"AUTHORING": "CREACIÓN",
|
||||
"Create and edit scenes": "Crea y edita escenas",
|
||||
"SCENE": "ESCENA",
|
||||
"Scene": "Escena",
|
||||
"NEW SCENE": "NUEVA ESCENA",
|
||||
"Start a new, empty scene": "Empieza una escena nueva y vacía",
|
||||
"DELETE": "ELIMINAR",
|
||||
"Delete this scene and all of its shots": "Elimina esta escena y todos sus planos",
|
||||
"SHOTS": "PLANOS",
|
||||
"+ CAPTURE SHOT": "+ CAPTURAR PLANO",
|
||||
"Add the current view, style and layers as the next shot": "Añade la vista, el estilo y las capas actuales como el siguiente plano",
|
||||
"Replace the selected shot with the current view": "Sustituye el plano seleccionado por la vista actual",
|
||||
"Click a shot to select it, double-click to rename.": "Haz clic en un plano para seleccionarlo y doble clic para cambiarle el nombre.",
|
||||
"scene|PLAY": "REPROD.",
|
||||
"Stop playback (Esc)": "Detén la reproducción (Esc)",
|
||||
"SAVE & SHARE": "GUARDAR Y COMPARTIR",
|
||||
"Download every scene as a JSON file you can import later": "Descarga todas las escenas como un archivo JSON que puedes importar más tarde",
|
||||
"Load scenes from an exported JSON file": "Carga escenas desde un archivo JSON exportado",
|
||||
"Download the timing log of the last play": "Descarga el registro de tiempos de la última reproducción",
|
||||
"Play from this scene through the rest of the project": "Reproduce desde esta escena hasta el resto del proyecto",
|
||||
"Play the shot after the selected one, moving on to the next scene when needed": "Reproduce el plano posterior al seleccionado y pasa a la siguiente escena si hace falta",
|
||||
"Edit anchors, data packs and shot details": "Edita anclas, paquetes de datos y detalles de los planos",
|
||||
"Download this scene as JSON or an asset bundle": "Descarga esta escena como JSON o como paquete de recursos",
|
||||
"Left panels": "Paneles izquierdos",
|
||||
"Right panels": "Paneles derechos",
|
||||
"UTILITIES": "UTILIDADES",
|
||||
"Exit cockpit to fly to a drawing": "Sal de la cabina para volar a un dibujo",
|
||||
"Directions, drawing and your own files": "Indicaciones, dibujo y tus propios archivos"
|
||||
}
|
||||
+36
-22
@@ -11,7 +11,6 @@
|
||||
"That line has no length — click somewhere further away.": "Cette ligne n'a pas de longueur — cliquez plus loin.",
|
||||
" · {max}-point limit reached": " · limite de {max} points atteinte",
|
||||
"{measure} · double-click or Enter to finish, Backspace undoes, Esc cancels.{full}": "{measure} · double-clic ou Enter pour terminer, Backspace annule le dernier point, Esc annule.{full}",
|
||||
"drawings on the map": "les dessins sur la carte",
|
||||
"That shape already has {count} points — finish it or press Backspace.": "Cette forme a déjà {count} points — terminez-la ou appuyez sur Backspace.",
|
||||
"That point is off the globe — click on the world.": "Ce point est hors du globe — cliquez sur la Terre.",
|
||||
"That shape could not be placed.": "Impossible de placer cette forme.",
|
||||
@@ -402,7 +401,6 @@
|
||||
"paste {envVar}": "collez {envVar}",
|
||||
"REMOVE": "SUPPRIMER",
|
||||
"Remove {title} from this app's saved keys": "Supprimer {title} des clés enregistrées de l'application",
|
||||
"unsaved provider keys": "les clés de fournisseurs non enregistrées",
|
||||
"Project keys: {status}": "Clés du projet : {status}",
|
||||
"your app configuration": "la configuration de votre application",
|
||||
"your local .env": "votre .env local",
|
||||
@@ -716,7 +714,6 @@
|
||||
"NIGHT": "NUIT",
|
||||
"▲ {frp} MW": "▲ {frp} MW",
|
||||
"FIRE": "FEU",
|
||||
"FIRES": "FEUX",
|
||||
"max {value} MW": "max {value} MW",
|
||||
"new {value}": "dernier il y a {value}",
|
||||
"{value}°N": "{value}°N",
|
||||
@@ -771,7 +768,7 @@
|
||||
"Low-accuracy score 2–10%": "Indice de faible précision 2–10 %",
|
||||
"Low-accuracy score > 10%": "Indice de faible précision > 10 %",
|
||||
"GNSS integrity source unavailable": "Source d'intégrité GNSS indisponible",
|
||||
"Regional sample · 250 nm radius · cells from visited views over 30 min": "Échantillon régional · rayon de 250 NM · cellules des vues visitées sur 30 min",
|
||||
"Regional sample · 250 nm radius · cells from visited views over {minutes} min": "Échantillon régional · rayon de 250 NM · cellules des vues visitées sur {minutes} min",
|
||||
"Retrying automatically at {time} UTC": "Nouvel essai automatique à {time} UTC",
|
||||
"Retrying automatically after provider cooldown": "Nouvel essai automatique après la pause du fournisseur",
|
||||
"Updates automatically after pan or zoom and once a minute. The public feed covers a 250-nautical-mile circle around the view centre; zooming out does not make it a worldwide snapshot. Blank cells are outside sampled coverage or have insufficient observations.": "Mise à jour automatique après un déplacement ou un zoom, et une fois par minute. Le flux public couvre un cercle de 250 milles nautiques autour du centre de la vue ; dézoomer n'en fait pas un instantané mondial. Les cellules vides sont hors de la couverture échantillonnée ou manquent d'observations.",
|
||||
@@ -1214,6 +1211,8 @@
|
||||
"Contiguous US · gaps ≠ no rain": "États-Unis contigus · lacunes ≠ absence de pluie",
|
||||
"Americas + Pacific · not individual strikes": "Amériques + Pacifique · pas des impacts individuels",
|
||||
"Color: strikes/km²/min ×10³": "Couleur : impacts/km²/min ×10³",
|
||||
"Color: {units}": "Couleur : {units}",
|
||||
"RADAR · {units}": "RADAR · {units}",
|
||||
"60°S–60°N · typically 2–3 h delayed": "60°S–60°N · retard habituel de 2 à 3 h",
|
||||
"North America · infrared imagery": "Amérique du Nord · imagerie infrarouge",
|
||||
"Reduced motion · history playback unavailable": "Animations réduites · lecture de l'historique indisponible",
|
||||
@@ -1540,9 +1539,6 @@
|
||||
"Sensitivity": "Sensibilité",
|
||||
"WHOT/BHOT": "WHOT/BHOT",
|
||||
"Ironbow": "Ironbow",
|
||||
"unsaved CCTV calibration": "la calibration CCTV non enregistrée",
|
||||
"the open cockpit": "le cockpit ouvert",
|
||||
"Switching language reloads the page. This will be lost: {items}. Switch anyway?": "Changer de langue recharge la page. Ceci sera perdu : {items}. Changer quand même ?",
|
||||
"VISUAL PRESETS": "PRÉRÉGLAGES VISUELS",
|
||||
"LOCATION": "LIEU",
|
||||
"CONTACTS — nearest planes · vessels · sites": "CONTACTS — avions, navires et sites les plus proches",
|
||||
@@ -1767,7 +1763,6 @@
|
||||
"Space Missions": "Missions spatiales",
|
||||
"Context": "Contexte",
|
||||
"Rendered globe frames per second · toggle with `": "Images du globe rendues par seconde · basculer avec `",
|
||||
"imported map files": "les fichiers importés sur la carte",
|
||||
"Ground heights could not be refreshed. Try the file again when the map has loaded.": "Impossible d'actualiser les altitudes du sol. Réessayez avec le fichier une fois la carte chargée.",
|
||||
"{count} map objects": {
|
||||
"one": "{count} objet cartographique",
|
||||
@@ -2547,7 +2542,6 @@
|
||||
"Activate to toggle voice": "Activer/désactiver la commande vocale",
|
||||
"Voice active": "Voix active",
|
||||
"Voice could not be started.": "Impossible de démarrer la voix.",
|
||||
"the active voice session": "la session vocale active",
|
||||
"{value} feet": "{value} pieds",
|
||||
"Fire · FRP {frp} MW": "Feu · FRP {frp} MW",
|
||||
"The flights layer is not enabled": "La couche des vols n'est pas activée",
|
||||
@@ -2705,8 +2699,6 @@
|
||||
"Cockpit vision style": "Style de vision du cockpit",
|
||||
"Previous cockpit vision style": "Style de vision précédent du cockpit",
|
||||
"Previous vision style": "Style de vision précédent",
|
||||
"Current cockpit vision style: NORMAL. Activate for next style.": "Style de vision actuel du cockpit : NORMAL. Activer pour le style suivant.",
|
||||
"Current style: NORMAL — click for next": "Style actuel : NORMAL — cliquer pour le suivant",
|
||||
"CURRENT": "ACTUEL",
|
||||
"Next cockpit vision style": "Style de vision suivant du cockpit",
|
||||
"Next vision style": "Style de vision suivant",
|
||||
@@ -2793,7 +2785,6 @@
|
||||
"RECENT IMAGERY": "IMAGERIE RÉCENTE",
|
||||
"Imagery days in the box": "Jours d'imagerie dans la zone",
|
||||
"CONTEXT": "CONTEXTE",
|
||||
"Expand panel": "Développer le panneau",
|
||||
"Context mode": "Mode de contexte",
|
||||
"CONTACTS": "CONTACTS",
|
||||
"Cycles the nearest contacts of whatever type you select — planes, vessels, installations. Satellites track independently.": "Parcourt les contacts les plus proches du type sélectionné — avions, navires, installations. Les satellites sont suivis séparément.",
|
||||
@@ -2955,13 +2946,7 @@
|
||||
"ALL": "TOUTES",
|
||||
"FLAT": "CLASSIQUES",
|
||||
"SINCE": "DEPUIS",
|
||||
"SCENES": "SCÈNES",
|
||||
"Scene recipe": "Recette de scène",
|
||||
"NEW": "NOUV.",
|
||||
"CAPTURE SHOT": "CAPTURER UN PLAN",
|
||||
"UPDATE SHOT": "MAJ DU PLAN",
|
||||
"START": "LANCER",
|
||||
"EXPORT PRESETS": "EXPORTER LES PRÉRÉGLAGES",
|
||||
"IMPORT": "IMPORTER",
|
||||
"RUN LOG": "JOURNAL",
|
||||
"POWER UP": "ALLUMER",
|
||||
@@ -2993,11 +2978,40 @@
|
||||
"Tip: the GEV MIC button in the dock lets you talk to the map.": "Astuce : le bouton GEV MIC du dock permet de parler à la carte.",
|
||||
"Malformed cyclone snapshot": "Instantané cyclonique mal formé",
|
||||
"Cyclone request timed out": "Délai dépassé pour la requête cyclonique",
|
||||
"Colour of {name}": "Couleur de {name}",
|
||||
"Change the colour of {name}": "Changer la couleur de {name}",
|
||||
"scene|PLAY": "LIRE",
|
||||
"AUTHORING": "CRÉATION",
|
||||
"Create and edit scenes": "Créer et modifier des scènes",
|
||||
"SCENE": "SCÈNE",
|
||||
"Scene": "Scène",
|
||||
"NEW SCENE": "NOUVELLE SCÈNE",
|
||||
"Start a new, empty scene": "Commencer une nouvelle scène vide",
|
||||
"DELETE": "SUPPRIMER",
|
||||
"Delete this scene and all of its shots": "Supprimer cette scène et tous ses plans",
|
||||
"SHOTS": "PLANS",
|
||||
"+ CAPTURE SHOT": "+ CAPTURER UN PLAN",
|
||||
"Add the current view, style and layers as the next shot": "Ajouter la vue, le style et les couches actuels comme plan suivant",
|
||||
"Replace the selected shot with the current view": "Remplacer le plan sélectionné par la vue actuelle",
|
||||
"Click a shot to select it, double-click to rename.": "Cliquez sur un plan pour le sélectionner, double-cliquez pour le renommer.",
|
||||
"Play from this scene through the rest of the project": "Lire de cette scène jusqu'à la fin du projet",
|
||||
"Stop playback (Esc)": "Arrêter la lecture (Esc)",
|
||||
"Play the shot after the selected one, moving on to the next scene when needed": "Lire le plan qui suit la sélection, en passant à la scène suivante si besoin",
|
||||
"SAVE & SHARE": "ENREGISTRER ET PARTAGER",
|
||||
"Download every scene as a JSON file you can import later": "Télécharger toutes les scènes dans un fichier JSON à importer plus tard",
|
||||
"Load scenes from an exported JSON file": "Charger des scènes depuis un fichier JSON exporté",
|
||||
"Download the timing log of the last play": "Télécharger le journal de minutage de la dernière lecture",
|
||||
"Edit anchors, data packs and shot details": "Modifier les ancres, les paquets de données et les détails des plans",
|
||||
"Download this scene as JSON or an asset bundle": "Télécharger cette scène en JSON ou en archive de ressources",
|
||||
"Left panels": "Panneaux de gauche",
|
||||
"Right panels": "Panneaux de droite",
|
||||
"CONFIRMED": "CONFIRMÉE",
|
||||
"PAD / RTLS": "PAS DE TIR / RTLS",
|
||||
"Name of {name}": "Nom de {name}",
|
||||
"Change the colour of {name}": "Changer la couleur de {name}",
|
||||
"Colour of {name}": "Couleur de {name}",
|
||||
"Colour of the next shape": "Couleur de la prochaine forme",
|
||||
"Drawn shapes": "Formes dessinées",
|
||||
"Audio": "Audio",
|
||||
"UTILITIES": "OUTILS",
|
||||
"Colour of the next shape": "Couleur de la prochaine forme",
|
||||
"Drawn shapes": "Formes dessinées"
|
||||
"Exit cockpit to fly to a drawing": "Quittez le cockpit pour rejoindre un dessin",
|
||||
"Directions, drawing and your own files": "Itinéraire, dessin et vos propres fichiers"
|
||||
}
|
||||
+36
-22
@@ -11,7 +11,6 @@
|
||||
"That line has no length — click somewhere further away.": "Quella linea non ha lunghezza: fai clic più lontano.",
|
||||
" · {max}-point limit reached": " · raggiunto il limite di {max} punti",
|
||||
"{measure} · double-click or Enter to finish, Backspace undoes, Esc cancels.{full}": "{measure} · doppio clic o Enter per finire, Backspace torna indietro, Esc annulla.{full}",
|
||||
"drawings on the map": "disegni sulla mappa",
|
||||
"That shape already has {count} points — finish it or press Backspace.": "Quella forma ha già {count} punti: finiscila o premi Backspace.",
|
||||
"That point is off the globe — click on the world.": "Quel punto è fuori dal globo: fai clic sul mondo.",
|
||||
"That shape could not be placed.": "Impossibile posizionare quella forma.",
|
||||
@@ -402,7 +401,6 @@
|
||||
"paste {envVar}": "incolla {envVar}",
|
||||
"REMOVE": "RIMUOVI",
|
||||
"Remove {title} from this app's saved keys": "Rimuovi {title} dalle chiavi salvate di questa app",
|
||||
"unsaved provider keys": "chiavi provider non salvate",
|
||||
"Project keys: {status}": "Chiavi del progetto: {status}",
|
||||
"your app configuration": "la configurazione della tua app",
|
||||
"your local .env": "il tuo .env locale",
|
||||
@@ -716,7 +714,6 @@
|
||||
"NIGHT": "NOTTE",
|
||||
"▲ {frp} MW": "▲ {frp} MW",
|
||||
"FIRE": "INCENDIO",
|
||||
"FIRES": "INCENDI",
|
||||
"max {value} MW": "max {value} MW",
|
||||
"new {value}": "ultimo: {value} fa",
|
||||
"{value}°N": "{value}°N",
|
||||
@@ -771,7 +768,7 @@
|
||||
"Low-accuracy score 2–10%": "Indice di bassa precisione 2–10%",
|
||||
"Low-accuracy score > 10%": "Indice di bassa precisione > 10%",
|
||||
"GNSS integrity source unavailable": "Fonte di integrità GNSS non disponibile",
|
||||
"Regional sample · 250 nm radius · cells from visited views over 30 min": "Campione regionale · raggio di 250 NM · celle dalle viste visitate negli ultimi 30 min",
|
||||
"Regional sample · 250 nm radius · cells from visited views over {minutes} min": "Campione regionale · raggio di 250 NM · celle dalle viste visitate negli ultimi {minutes} min",
|
||||
"Retrying automatically at {time} UTC": "Nuovo tentativo automatico alle {time} UTC",
|
||||
"Retrying automatically after provider cooldown": "Nuovo tentativo automatico dopo la pausa del provider",
|
||||
"Updates automatically after pan or zoom and once a minute. The public feed covers a 250-nautical-mile circle around the view centre; zooming out does not make it a worldwide snapshot. Blank cells are outside sampled coverage or have insufficient observations.": "Si aggiorna automaticamente dopo uno spostamento o uno zoom e una volta al minuto. Il feed pubblico copre un cerchio di 250 miglia nautiche attorno al centro della vista; allontanare lo zoom non lo rende un'istantanea mondiale. Le celle vuote sono fuori dalla copertura campionata o hanno osservazioni insufficienti.",
|
||||
@@ -1214,6 +1211,8 @@
|
||||
"Contiguous US · gaps ≠ no rain": "USA contigui · lacune ≠ assenza di pioggia",
|
||||
"Americas + Pacific · not individual strikes": "Americhe + Pacifico · non singoli fulmini",
|
||||
"Color: strikes/km²/min ×10³": "Colore: fulmini/km²/min ×10³",
|
||||
"Color: {units}": "Colore: {units}",
|
||||
"RADAR · {units}": "RADAR · {units}",
|
||||
"60°S–60°N · typically 2–3 h delayed": "60°S–60°N · di solito 2–3 h di ritardo",
|
||||
"North America · infrared imagery": "Nord America · immagini all'infrarosso",
|
||||
"Reduced motion · history playback unavailable": "Movimento ridotto · riproduzione dello storico non disponibile",
|
||||
@@ -1540,9 +1539,6 @@
|
||||
"Sensitivity": "Sensibilità",
|
||||
"WHOT/BHOT": "WHOT/BHOT",
|
||||
"Ironbow": "Ironbow",
|
||||
"unsaved CCTV calibration": "calibrazione CCTV non salvata",
|
||||
"the open cockpit": "il cockpit aperto",
|
||||
"Switching language reloads the page. This will be lost: {items}. Switch anyway?": "Cambiare lingua ricarica la pagina. Perderai: {items}. Cambiare comunque?",
|
||||
"VISUAL PRESETS": "PRESET VISIVI",
|
||||
"LOCATION": "POSIZIONE",
|
||||
"CONTACTS — nearest planes · vessels · sites": "CONTATTI — aerei · navi · siti più vicini",
|
||||
@@ -1767,7 +1763,6 @@
|
||||
"Space Missions": "Missioni spaziali",
|
||||
"Context": "Contesto",
|
||||
"Rendered globe frames per second · toggle with `": "Fotogrammi al secondo del globo · attiva/disattiva con `",
|
||||
"imported map files": "file di mappa importati",
|
||||
"Ground heights could not be refreshed. Try the file again when the map has loaded.": "Impossibile aggiornare le quote del terreno. Riprova con il file quando la mappa è caricata.",
|
||||
"{count} map objects": {
|
||||
"one": "{count} oggetto sulla mappa",
|
||||
@@ -2547,7 +2542,6 @@
|
||||
"Activate to toggle voice": "Attiva per abilitare o disabilitare la voce",
|
||||
"Voice active": "Voce attiva",
|
||||
"Voice could not be started.": "Impossibile avviare la voce.",
|
||||
"the active voice session": "la sessione vocale attiva",
|
||||
"{value} feet": "{value} piedi",
|
||||
"Fire · FRP {frp} MW": "Incendio · FRP {frp} MW",
|
||||
"The flights layer is not enabled": "Il livello voli non è attivo",
|
||||
@@ -2705,8 +2699,6 @@
|
||||
"Cockpit vision style": "Stile di visione del cockpit",
|
||||
"Previous cockpit vision style": "Stile di visione precedente del cockpit",
|
||||
"Previous vision style": "Stile di visione precedente",
|
||||
"Current cockpit vision style: NORMAL. Activate for next style.": "Stile di visione attuale del cockpit: NORMALE. Attiva per lo stile successivo.",
|
||||
"Current style: NORMAL — click for next": "Stile attuale: NORMALE. Clic per il successivo",
|
||||
"CURRENT": "ATTUALE",
|
||||
"Next cockpit vision style": "Stile di visione successivo del cockpit",
|
||||
"Next vision style": "Stile di visione successivo",
|
||||
@@ -2793,7 +2785,6 @@
|
||||
"RECENT IMAGERY": "IMMAGINI RECENTI",
|
||||
"Imagery days in the box": "Giorni con immagini nel riquadro",
|
||||
"CONTEXT": "CONTESTO",
|
||||
"Expand panel": "Espandi il pannello",
|
||||
"Context mode": "Modalità contesto",
|
||||
"CONTACTS": "CONTATTI",
|
||||
"Cycles the nearest contacts of whatever type you select — planes, vessels, installations. Satellites track independently.": "Scorre i contatti più vicini del tipo selezionato: aerei, navi, installazioni. I satelliti vengono tracciati in modo indipendente.",
|
||||
@@ -2955,13 +2946,7 @@
|
||||
"ALL": "TUTTE",
|
||||
"FLAT": "PIATTE",
|
||||
"SINCE": "DAL",
|
||||
"SCENES": "SCENE",
|
||||
"Scene recipe": "Ricetta della scena",
|
||||
"NEW": "NUOVA",
|
||||
"CAPTURE SHOT": "CATTURA SCATTO",
|
||||
"UPDATE SHOT": "AGGIORNA SCATTO",
|
||||
"START": "AVVIA",
|
||||
"EXPORT PRESETS": "ESPORTA PRESET",
|
||||
"IMPORT": "IMPORTA",
|
||||
"RUN LOG": "LOG ESECUZIONE",
|
||||
"POWER UP": "ACCENDI",
|
||||
@@ -2993,11 +2978,40 @@
|
||||
"Tip: the GEV MIC button in the dock lets you talk to the map.": "Suggerimento: il pulsante GEV MIC nel dock ti permette di parlare con la mappa.",
|
||||
"Malformed cyclone snapshot": "Snapshot dei cicloni non valido",
|
||||
"Cyclone request timed out": "La richiesta dei cicloni è andata in timeout",
|
||||
"Colour of {name}": "Colore di {name}",
|
||||
"Change the colour of {name}": "Cambia il colore di {name}",
|
||||
"scene|PLAY": "AVVIA",
|
||||
"AUTHORING": "CREAZIONE",
|
||||
"Create and edit scenes": "Crea e modifica le scene",
|
||||
"SCENE": "SCENA",
|
||||
"Scene": "Scena",
|
||||
"NEW SCENE": "NUOVA SCENA",
|
||||
"Start a new, empty scene": "Inizia una nuova scena vuota",
|
||||
"DELETE": "ELIMINA",
|
||||
"Delete this scene and all of its shots": "Elimina questa scena e tutti i suoi scatti",
|
||||
"SHOTS": "SCATTI",
|
||||
"+ CAPTURE SHOT": "+ CATTURA SCATTO",
|
||||
"Add the current view, style and layers as the next shot": "Aggiungi la vista, lo stile e i livelli attuali come scatto successivo",
|
||||
"Replace the selected shot with the current view": "Sostituisci lo scatto selezionato con la vista attuale",
|
||||
"Click a shot to select it, double-click to rename.": "Fai clic su uno scatto per selezionarlo, doppio clic per rinominarlo.",
|
||||
"Play from this scene through the rest of the project": "Riproduci da questa scena fino alla fine del progetto",
|
||||
"Stop playback (Esc)": "Interrompi la riproduzione (Esc)",
|
||||
"Play the shot after the selected one, moving on to the next scene when needed": "Riproduci lo scatto dopo quello selezionato, passando alla scena successiva se serve",
|
||||
"SAVE & SHARE": "SALVA E CONDIVIDI",
|
||||
"Download every scene as a JSON file you can import later": "Scarica tutte le scene in un file JSON da importare in seguito",
|
||||
"Load scenes from an exported JSON file": "Carica le scene da un file JSON esportato",
|
||||
"Download the timing log of the last play": "Scarica il log dei tempi dell'ultima riproduzione",
|
||||
"Edit anchors, data packs and shot details": "Modifica ancore, pacchetti dati e dettagli degli scatti",
|
||||
"Download this scene as JSON or an asset bundle": "Scarica questa scena come JSON o pacchetto di risorse",
|
||||
"Left panels": "Pannelli a sinistra",
|
||||
"Right panels": "Pannelli a destra",
|
||||
"CONFIRMED": "CONFERMATA",
|
||||
"PAD / RTLS": "SITO DI LANCIO / RTLS",
|
||||
"Name of {name}": "Nome di {name}",
|
||||
"Change the colour of {name}": "Cambia il colore di {name}",
|
||||
"Colour of {name}": "Colore di {name}",
|
||||
"Colour of the next shape": "Colore della prossima forma",
|
||||
"Drawn shapes": "Forme disegnate",
|
||||
"Audio": "Audio",
|
||||
"UTILITIES": "STRUMENTI",
|
||||
"Colour of the next shape": "Colore della prossima forma",
|
||||
"Drawn shapes": "Forme disegnate"
|
||||
"Exit cockpit to fly to a drawing": "Esci dal cockpit per volare a un disegno",
|
||||
"Directions, drawing and your own files": "Indicazioni, disegno e i tuoi file"
|
||||
}
|
||||
+36
-22
@@ -9,7 +9,6 @@
|
||||
"That line has no length — click somewhere further away.": "線の長さがゼロです。もっと離れた場所をクリックしてください。",
|
||||
" · {max}-point limit reached": " · 上限の{max}点に達しました",
|
||||
"{measure} · double-click or Enter to finish, Backspace undoes, Esc cancels.{full}": "{measure} · ダブルクリックまたはEnterで完了、Backspaceで元に戻す、Escでキャンセル。{full}",
|
||||
"drawings on the map": "地図上の描画",
|
||||
"That shape already has {count} points — finish it or press Backspace.": "この図形はすでに{count}点あります。完了するか、Backspaceを押してください。",
|
||||
"That point is off the globe — click on the world.": "その点は地球の外です。地表をクリックしてください。",
|
||||
"That shape could not be placed.": "図形を配置できませんでした。",
|
||||
@@ -394,7 +393,6 @@
|
||||
"paste {envVar}": "{envVar}を貼り付け",
|
||||
"REMOVE": "削除",
|
||||
"Remove {title} from this app's saved keys": "{title}をこのアプリの保存済みキーから削除",
|
||||
"unsaved provider keys": "未保存のプロバイダーキー",
|
||||
"Project keys: {status}": "プロジェクトのキー:{status}",
|
||||
"your app configuration": "アプリの設定",
|
||||
"your local .env": "ローカルの .env",
|
||||
@@ -698,7 +696,6 @@
|
||||
"NIGHT": "夜間",
|
||||
"▲ {frp} MW": "▲ {frp} MW",
|
||||
"FIRE": "火災",
|
||||
"FIRES": "火災",
|
||||
"max {value} MW": "最大 {value} MW",
|
||||
"new {value}": "新規 {value}",
|
||||
"{value}°N": "{value}°N",
|
||||
@@ -749,7 +746,7 @@
|
||||
"Low-accuracy score 2–10%": "低精度スコア 2–10%",
|
||||
"Low-accuracy score > 10%": "低精度スコア > 10%",
|
||||
"GNSS integrity source unavailable": "GNSSインテグリティのソースを利用できません",
|
||||
"Regional sample · 250 nm radius · cells from visited views over 30 min": "地域サンプル · 半径250海里 · 30分以内に表示したビューのセル",
|
||||
"Regional sample · 250 nm radius · cells from visited views over {minutes} min": "地域サンプル · 半径250海里 · {minutes}分以内に表示したビューのセル",
|
||||
"Retrying automatically at {time} UTC": "{time} UTCに自動で再試行します",
|
||||
"Retrying automatically after provider cooldown": "プロバイダーのクールダウン後に自動で再試行します",
|
||||
"Updates automatically after pan or zoom and once a minute. The public feed covers a 250-nautical-mile circle around the view centre; zooming out does not make it a worldwide snapshot. Blank cells are outside sampled coverage or have insufficient observations.": "パンやズームの後、および1分ごとに自動で更新されます。公開フィードは表示中心から半径250海里の円をカバーします。ズームアウトしても全世界のスナップショットにはなりません。空白のセルは、サンプリング範囲外か観測が不十分です。",
|
||||
@@ -1182,6 +1179,8 @@
|
||||
"Contiguous US · gaps ≠ no rain": "米国本土 · 欠測 ≠ 降水なし",
|
||||
"Americas + Pacific · not individual strikes": "南北アメリカ + 太平洋 · 個々の落雷ではありません",
|
||||
"Color: strikes/km²/min ×10³": "色:落雷数/km²/分 ×10³",
|
||||
"Color: {units}": "色:{units}",
|
||||
"RADAR · {units}": "レーダー · {units}",
|
||||
"60°S–60°N · typically 2–3 h delayed": "60°S–60°N · 通常2–3時間遅れ",
|
||||
"North America · infrared imagery": "北米 · 赤外画像",
|
||||
"Reduced motion · history playback unavailable": "動きを減らす設定 · 履歴再生は利用不可",
|
||||
@@ -1498,9 +1497,6 @@
|
||||
"Sensitivity": "感度",
|
||||
"WHOT/BHOT": "WHOT/BHOT",
|
||||
"Ironbow": "Ironbow",
|
||||
"unsaved CCTV calibration": "未保存のCCTVキャリブレーション",
|
||||
"the open cockpit": "表示中のコックピット",
|
||||
"Switching language reloads the page. This will be lost: {items}. Switch anyway?": "言語を切り替えるとページが再読み込みされます。次の内容は失われます:{items}。切り替えますか?",
|
||||
"VISUAL PRESETS": "ビジュアルプリセット",
|
||||
"LOCATION": "位置",
|
||||
"CONTACTS — nearest planes · vessels · sites": "コンタクト:最寄りの航空機 · 船舶 · 施設",
|
||||
@@ -1711,7 +1707,6 @@
|
||||
"Space Missions": "宇宙ミッション",
|
||||
"Context": "コンテキスト",
|
||||
"Rendered globe frames per second · toggle with `": "地球儀の描画フレームレート(毎秒) · `キーで切り替え",
|
||||
"imported map files": "インポートした地図ファイル",
|
||||
"Ground heights could not be refreshed. Try the file again when the map has loaded.": "地表高を更新できませんでした。地図の読み込み後に、もう一度このファイルをお試しください。",
|
||||
"{count} map objects": {
|
||||
"other": "地図オブジェクト{count}個"
|
||||
@@ -2417,7 +2412,6 @@
|
||||
"Activate to toggle voice": "押すと音声のオン/オフを切り替え",
|
||||
"Voice active": "音声 オン",
|
||||
"Voice could not be started.": "音声を開始できませんでした。",
|
||||
"the active voice session": "進行中の音声セッション",
|
||||
"{value} feet": "{value}フィート",
|
||||
"Fire · FRP {frp} MW": "火災 · FRP {frp} MW",
|
||||
"The flights layer is not enabled": "フライトレイヤーが有効になっていません",
|
||||
@@ -2563,8 +2557,6 @@
|
||||
"Cockpit vision style": "コックピットのビジョンスタイル",
|
||||
"Previous cockpit vision style": "前のコックピットビジョンスタイル",
|
||||
"Previous vision style": "前のビジョンスタイル",
|
||||
"Current cockpit vision style: NORMAL. Activate for next style.": "現在のコックピットビジョンスタイル:標準。押すと次のスタイルに切り替わります。",
|
||||
"Current style: NORMAL — click for next": "現在のスタイル:標準。クリックで次へ",
|
||||
"CURRENT": "現在",
|
||||
"Next cockpit vision style": "次のコックピットビジョンスタイル",
|
||||
"Next vision style": "次のビジョンスタイル",
|
||||
@@ -2651,7 +2643,6 @@
|
||||
"RECENT IMAGERY": "最近の衛星画像",
|
||||
"Imagery days in the box": "範囲内の画像のある日",
|
||||
"CONTEXT": "コンテキスト",
|
||||
"Expand panel": "パネルを展開",
|
||||
"Context mode": "コンテキストモード",
|
||||
"CONTACTS": "コンタクト",
|
||||
"Cycles the nearest contacts of whatever type you select — planes, vessels, installations. Satellites track independently.": "選択した種類(航空機、船舶、施設)の最寄りのコンタクトを順に切り替えます。衛星は独立して追跡されます。",
|
||||
@@ -2813,13 +2804,7 @@
|
||||
"ALL": "すべて",
|
||||
"FLAT": "平面",
|
||||
"SINCE": "期間",
|
||||
"SCENES": "シーン",
|
||||
"Scene recipe": "シーンレシピ",
|
||||
"NEW": "新規",
|
||||
"CAPTURE SHOT": "ショット取得",
|
||||
"UPDATE SHOT": "ショット更新",
|
||||
"START": "開始",
|
||||
"EXPORT PRESETS": "エクスポート",
|
||||
"IMPORT": "インポート",
|
||||
"RUN LOG": "実行ログ",
|
||||
"POWER UP": "パワーアップ",
|
||||
@@ -2853,11 +2838,40 @@
|
||||
"route proxy error": "ルート検索プロキシでエラーが発生しました",
|
||||
"Malformed cyclone snapshot": "サイクロンのスナップショットの形式が不正です",
|
||||
"Cyclone request timed out": "サイクロンのリクエストがタイムアウトしました",
|
||||
"Colour of {name}": "{name}の色",
|
||||
"Change the colour of {name}": "{name}の色を変更",
|
||||
"scene|PLAY": "再生",
|
||||
"AUTHORING": "作成",
|
||||
"Create and edit scenes": "シーンを作成・編集",
|
||||
"SCENE": "シーン",
|
||||
"Scene": "シーン",
|
||||
"NEW SCENE": "新規シーン",
|
||||
"Start a new, empty scene": "空の新しいシーンを作成",
|
||||
"DELETE": "削除",
|
||||
"Delete this scene and all of its shots": "このシーンとすべてのショットを削除",
|
||||
"SHOTS": "ショット",
|
||||
"+ CAPTURE SHOT": "+ ショット取得",
|
||||
"Add the current view, style and layers as the next shot": "現在の視点・スタイル・レイヤーを次のショットとして追加",
|
||||
"Replace the selected shot with the current view": "選択中のショットを現在の視点で置き換え",
|
||||
"Click a shot to select it, double-click to rename.": "ショットをクリックして選択、ダブルクリックで名前を変更します。",
|
||||
"Play from this scene through the rest of the project": "このシーンからプロジェクトの最後まで再生",
|
||||
"Stop playback (Esc)": "再生を停止(Esc)",
|
||||
"Play the shot after the selected one, moving on to the next scene when needed": "選択中の次のショットを再生(必要に応じて次のシーンへ進む)",
|
||||
"SAVE & SHARE": "保存と共有",
|
||||
"Download every scene as a JSON file you can import later": "すべてのシーンを、後でインポートできるJSONファイルとしてダウンロード",
|
||||
"Load scenes from an exported JSON file": "書き出したJSONファイルからシーンを読み込む",
|
||||
"Download the timing log of the last play": "前回の再生のタイミングログをダウンロード",
|
||||
"Edit anchors, data packs and shot details": "アンカー、データパック、ショットの詳細を編集",
|
||||
"Download this scene as JSON or an asset bundle": "このシーンをJSONまたはアセットバンドルとしてダウンロード",
|
||||
"Left panels": "左パネル",
|
||||
"Right panels": "右パネル",
|
||||
"CONFIRMED": "確認済み",
|
||||
"PAD / RTLS": "射場 / RTLS",
|
||||
"Name of {name}": "{name}の名前",
|
||||
"Change the colour of {name}": "{name}の色を変更",
|
||||
"Colour of {name}": "{name}の色",
|
||||
"Colour of the next shape": "次の図形の色",
|
||||
"Drawn shapes": "描いた図形",
|
||||
"Audio": "オーディオ",
|
||||
"UTILITIES": "ユーティリティ",
|
||||
"Colour of the next shape": "次の図形の色",
|
||||
"Drawn shapes": "描いた図形"
|
||||
"Exit cockpit to fly to a drawing": "描画の位置へ移動するにはコックピットを終了してください",
|
||||
"Directions, drawing and your own files": "ルート案内、描画、自分のファイル"
|
||||
}
|
||||
+36
-22
@@ -11,7 +11,6 @@
|
||||
"That line has no length — click somewhere further away.": "Essa linha não tem comprimento — clique em um ponto mais distante.",
|
||||
" · {max}-point limit reached": " · limite de {max} pontos atingido",
|
||||
"{measure} · double-click or Enter to finish, Backspace undoes, Esc cancels.{full}": "{measure} · clique duplo ou Enter para concluir, Backspace desfaz, Esc cancela.{full}",
|
||||
"drawings on the map": "os desenhos no mapa",
|
||||
"That shape already has {count} points — finish it or press Backspace.": "Essa forma já tem {count} pontos — conclua-a ou pressione Backspace.",
|
||||
"That point is off the globe — click on the world.": "Esse ponto está fora do globo — clique sobre o mundo.",
|
||||
"That shape could not be placed.": "Não foi possível colocar essa forma.",
|
||||
@@ -402,7 +401,6 @@
|
||||
"paste {envVar}": "cole {envVar}",
|
||||
"REMOVE": "REMOVER",
|
||||
"Remove {title} from this app's saved keys": "Remover {title} das chaves salvas deste app",
|
||||
"unsaved provider keys": "chaves de provedores não salvas",
|
||||
"Project keys: {status}": "Chaves do projeto: {status}",
|
||||
"your app configuration": "sua configuração do app",
|
||||
"your local .env": "seu .env local",
|
||||
@@ -714,7 +712,6 @@
|
||||
"NIGHT": "NOITE",
|
||||
"▲ {frp} MW": "▲ {frp} MW",
|
||||
"FIRE": "INCÊNDIO",
|
||||
"FIRES": "INCÊNDIOS",
|
||||
"max {value} MW": "máx {value} MW",
|
||||
"new {value}": "mais recente há {value}",
|
||||
"{value}°N": "{value}°N",
|
||||
@@ -769,7 +766,7 @@
|
||||
"Low-accuracy score 2–10%": "Índice de baixa precisão 2–10%",
|
||||
"Low-accuracy score > 10%": "Índice de baixa precisão > 10%",
|
||||
"GNSS integrity source unavailable": "Fonte de integridade GNSS indisponível",
|
||||
"Regional sample · 250 nm radius · cells from visited views over 30 min": "Amostra regional · raio de 250 NM · células das vistas visitadas em 30 min",
|
||||
"Regional sample · 250 nm radius · cells from visited views over {minutes} min": "Amostra regional · raio de 250 NM · células das vistas visitadas em {minutes} min",
|
||||
"Retrying automatically at {time} UTC": "Nova tentativa automática às {time} UTC",
|
||||
"Retrying automatically after provider cooldown": "Nova tentativa automática após a pausa do provedor",
|
||||
"Updates automatically after pan or zoom and once a minute. The public feed covers a 250-nautical-mile circle around the view centre; zooming out does not make it a worldwide snapshot. Blank cells are outside sampled coverage or have insufficient observations.": "Atualiza automaticamente após mover ou dar zoom e uma vez por minuto. O feed público cobre um círculo de 250 milhas náuticas ao redor do centro da vista; afastar o zoom não o transforma em um snapshot mundial. Células vazias estão fora da cobertura amostrada ou não têm observações suficientes.",
|
||||
@@ -1212,6 +1209,8 @@
|
||||
"Contiguous US · gaps ≠ no rain": "EUA contíguos · lacunas ≠ sem chuva",
|
||||
"Americas + Pacific · not individual strikes": "Américas + Pacífico · não são raios individuais",
|
||||
"Color: strikes/km²/min ×10³": "Cor: raios/km²/min ×10³",
|
||||
"Color: {units}": "Cor: {units}",
|
||||
"RADAR · {units}": "RADAR · {units}",
|
||||
"60°S–60°N · typically 2–3 h delayed": "60°S–60°N · normalmente com 2–3 h de atraso",
|
||||
"North America · infrared imagery": "América do Norte · imagens infravermelhas",
|
||||
"Reduced motion · history playback unavailable": "Movimento reduzido · reprodução do histórico indisponível",
|
||||
@@ -1540,9 +1539,6 @@
|
||||
"Sensitivity": "Sensibilidade",
|
||||
"WHOT/BHOT": "WHOT/BHOT",
|
||||
"Ironbow": "Ironbow",
|
||||
"unsaved CCTV calibration": "a calibração de CCTV não salva",
|
||||
"the open cockpit": "a cabine aberta",
|
||||
"Switching language reloads the page. This will be lost: {items}. Switch anyway?": "Mudar de idioma recarrega a página. Isto será perdido: {items}. Mudar mesmo assim?",
|
||||
"VISUAL PRESETS": "PREDEF. VISUAIS",
|
||||
"LOCATION": "LOCAL",
|
||||
"CONTACTS — nearest planes · vessels · sites": "CONTATOS — aviões · embarcações · locais mais próximos",
|
||||
@@ -1767,7 +1763,6 @@
|
||||
"Space Missions": "Missões espaciais",
|
||||
"Context": "Contexto",
|
||||
"Rendered globe frames per second · toggle with `": "Quadros por segundo renderizados do globo · alterne com `",
|
||||
"imported map files": "os arquivos importados no mapa",
|
||||
"Ground heights could not be refreshed. Try the file again when the map has loaded.": "Não foi possível atualizar as altitudes do terreno. Tente o arquivo de novo quando o mapa tiver carregado.",
|
||||
"{count} map objects": {
|
||||
"one": "{count} objeto no mapa",
|
||||
@@ -2549,7 +2544,6 @@
|
||||
"Activate to toggle voice": "Ative para ligar ou desligar a voz",
|
||||
"Voice active": "Voz ativa",
|
||||
"Voice could not be started.": "Não foi possível iniciar a voz.",
|
||||
"the active voice session": "a sessão de voz ativa",
|
||||
"{value} feet": "{value} pés",
|
||||
"Fire · FRP {frp} MW": "Incêndio · FRP {frp} MW",
|
||||
"The flights layer is not enabled": "A camada de voos não está ativada",
|
||||
@@ -2707,8 +2701,6 @@
|
||||
"Cockpit vision style": "Estilo de visão da cabine",
|
||||
"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 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",
|
||||
"Next vision style": "Próximo estilo de visão",
|
||||
@@ -2795,7 +2787,6 @@
|
||||
"RECENT IMAGERY": "IMAGENS RECENTES",
|
||||
"Imagery days in the box": "Dias com imagens na área",
|
||||
"CONTEXT": "CONTEXTO",
|
||||
"Expand panel": "Expandir painel",
|
||||
"Context mode": "Modo de contexto",
|
||||
"CONTACTS": "CONTATOS",
|
||||
"Cycles the nearest contacts of whatever type you select — planes, vessels, installations. Satellites track independently.": "Percorre os contatos mais próximos do tipo que você selecionar — aviões, embarcações, instalações. Os satélites são rastreados de forma independente.",
|
||||
@@ -2957,13 +2948,7 @@
|
||||
"ALL": "TODAS",
|
||||
"FLAT": "PLANAS",
|
||||
"SINCE": "DESDE",
|
||||
"SCENES": "CENAS",
|
||||
"Scene recipe": "Receita de cena",
|
||||
"NEW": "NOVA",
|
||||
"CAPTURE SHOT": "CAPTURAR PLANO",
|
||||
"UPDATE SHOT": "ATUALIZAR PLANO",
|
||||
"START": "INICIAR",
|
||||
"EXPORT PRESETS": "EXPORTAR PREDEF.",
|
||||
"IMPORT": "IMPORTAR",
|
||||
"RUN LOG": "REGISTRO",
|
||||
"POWER UP": "ATIVAR",
|
||||
@@ -2993,11 +2978,40 @@
|
||||
"Don't show this again": "Não mostrar novamente",
|
||||
"ESC to dismiss": "ESC para fechar",
|
||||
"Tip: the GEV MIC button in the dock lets you talk to the map.": "Dica: o botão GEV MIC no dock permite falar com o mapa.",
|
||||
"Colour of {name}": "Cor de {name}",
|
||||
"Change the colour of {name}": "Mudar a cor de {name}",
|
||||
"scene|PLAY": "INICIAR",
|
||||
"AUTHORING": "CRIAÇÃO",
|
||||
"Create and edit scenes": "Criar e editar cenas",
|
||||
"SCENE": "CENA",
|
||||
"Scene": "Cena",
|
||||
"NEW SCENE": "NOVA CENA",
|
||||
"Start a new, empty scene": "Começar uma nova cena vazia",
|
||||
"DELETE": "EXCLUIR",
|
||||
"Delete this scene and all of its shots": "Excluir esta cena e todos os seus planos",
|
||||
"SHOTS": "PLANOS",
|
||||
"+ CAPTURE SHOT": "+ CAPTURAR PLANO",
|
||||
"Add the current view, style and layers as the next shot": "Adicionar a vista, o estilo e as camadas atuais como próximo plano",
|
||||
"Replace the selected shot with the current view": "Substituir o plano selecionado pela vista atual",
|
||||
"Click a shot to select it, double-click to rename.": "Clique em um plano para selecioná-lo e clique duas vezes para renomeá-lo.",
|
||||
"Play from this scene through the rest of the project": "Reproduzir desta cena até o fim do projeto",
|
||||
"Stop playback (Esc)": "Parar a reprodução (Esc)",
|
||||
"Play the shot after the selected one, moving on to the next scene when needed": "Reproduzir o plano após o selecionado, passando à próxima cena se necessário",
|
||||
"SAVE & SHARE": "SALVAR E COMPARTILHAR",
|
||||
"Download every scene as a JSON file you can import later": "Baixar todas as cenas em um arquivo JSON para importar depois",
|
||||
"Load scenes from an exported JSON file": "Carregar cenas de um arquivo JSON exportado",
|
||||
"Download the timing log of the last play": "Baixar o registro de tempos da última reprodução",
|
||||
"Edit anchors, data packs and shot details": "Editar âncoras, pacotes de dados e detalhes dos planos",
|
||||
"Download this scene as JSON or an asset bundle": "Baixar esta cena como JSON ou pacote de recursos",
|
||||
"Left panels": "Painéis à esquerda",
|
||||
"Right panels": "Painéis à direita",
|
||||
"CONFIRMED": "CONFIRMADA",
|
||||
"PAD / RTLS": "PLATAFORMA / RTLS",
|
||||
"Name of {name}": "Nome de {name}",
|
||||
"Change the colour of {name}": "Mudar a cor de {name}",
|
||||
"Colour of {name}": "Cor de {name}",
|
||||
"Colour of the next shape": "Cor da próxima forma",
|
||||
"Drawn shapes": "Formas desenhadas",
|
||||
"Audio": "Áudio",
|
||||
"UTILITIES": "UTILITÁRIOS",
|
||||
"Colour of the next shape": "Cor da próxima forma",
|
||||
"Drawn shapes": "Formas desenhadas"
|
||||
"Exit cockpit to fly to a drawing": "Saia da cabine para voar até um desenho",
|
||||
"Directions, drawing and your own files": "Rotas, desenho e seus próprios arquivos"
|
||||
}
|
||||
+34
-20
@@ -135,7 +135,6 @@
|
||||
"NIGHT": "НОЧЬ",
|
||||
"▲ {frp} MW": "▲ {frp} МВт",
|
||||
"FIRE": "ПОЖАР",
|
||||
"FIRES": "ПОЖ.",
|
||||
"max {value} MW": "макс. {value} МВт",
|
||||
"new {value}": "последний {value}",
|
||||
"just now": "только что",
|
||||
@@ -217,6 +216,8 @@
|
||||
"Pause replay": "Приостановить повтор",
|
||||
"Cancel replay": "Отменить повтор",
|
||||
"EST. DOWNRANGE": "РАСЧЁТ ПО ТРАССЕ",
|
||||
"CONFIRMED": "ПОДТВЕРЖДЕНО",
|
||||
"PAD / RTLS": "СТАРТОВАЯ ПЛОЩАДКА / RTLS",
|
||||
"PLANNED · ": "ПЛАН · ",
|
||||
"SUPPLIED TRAJECTORY POINTS": "ПРЕДОСТАВЛЕННЫЕ ТОЧКИ ТРАЕКТОРИИ",
|
||||
"RECONSTRUCTED ESTIMATE": "РЕКОНСТРУИРОВАННАЯ ОЦЕНКА",
|
||||
@@ -626,8 +627,6 @@
|
||||
"Cockpit display and Radio controls": "Управление экраном и радио кабины",
|
||||
"Previous cockpit vision style": "Предыдущий стиль обзора кабины",
|
||||
"Previous vision style": "Предыдущий стиль обзора",
|
||||
"Current cockpit vision style: NORMAL. Activate for next style.": "Текущий стиль обзора кабины: ОБЫЧНЫЙ. Активируйте для следующего стиля.",
|
||||
"Current style: NORMAL — click for next": "Текущий стиль: ОБЫЧНЫЙ — нажмите для следующего",
|
||||
"Next cockpit vision style": "Следующий стиль обзора кабины",
|
||||
"Next vision style": "Следующий стиль обзора",
|
||||
"Previous briefing page": "Предыдущая страница брифинга",
|
||||
@@ -709,7 +708,6 @@
|
||||
"FLIR": "FLIR",
|
||||
"Style": "Стиль",
|
||||
"STATION SITE": "САЙТ СТАНЦИИ",
|
||||
"Expand panel": "Развернуть панель",
|
||||
"CONTACTS": "КОНТАКТЫ",
|
||||
"Cycles the nearest contacts of whatever type you select — planes, vessels, installations. Satellites track independently.": "Перебирает ближайшие контакты выбранного типа — самолёты, суда, объекты. Спутники отслеживаются отдельно.",
|
||||
"SEARCH NEARBY SITES": "ПОИСК ОБЪЕКТОВ РЯДОМ",
|
||||
@@ -795,22 +793,15 @@
|
||||
"East offset from catalog position (m) — click to type": "Смещение на восток от позиции каталога (м) — нажмите для ввода",
|
||||
"SAVE CAL": "СОХРАНИТЬ КАЛИБР.",
|
||||
"RESET CAL": "СБРОСИТЬ КАЛИБР.",
|
||||
"NEW": "НОВАЯ",
|
||||
"DEL": "УДАЛ.",
|
||||
"CAPTURE SHOT": "СДЕЛАТЬ КАДР",
|
||||
"UPDATE SHOT": "ОБНОВИТЬ КАДР",
|
||||
"START": "СТАРТ",
|
||||
"EXPORT PRESETS": "ЭКСПОРТ ПРЕСЕТОВ",
|
||||
"IMPORT": "ИМПОРТ",
|
||||
"RUN LOG": "ЖУРНАЛ ЗАПУСКОВ",
|
||||
"CALIBRATION": "КАЛИБРОВКА",
|
||||
"Camera pose — click a value to type": "Поза камеры — щёлкните по значению, чтобы ввести",
|
||||
"SCENE SUMMARY": "СВОДКА ПО СЦЕНЕ",
|
||||
"CCTV camera": "Камера CCTV",
|
||||
"Scene recipe": "Рецепт сцены",
|
||||
"DATA LAYERS": "СЛОИ ДАННЫХ",
|
||||
"SCENES": "СЦЕНЫ",
|
||||
"UTILITIES": "ИНСТРУМЕНТЫ",
|
||||
"Close key setup": "Закрыть настройку ключей",
|
||||
"SAVE KEYS": "СОХРАНИТЬ КЛЮЧИ",
|
||||
"Power up the globe": "Подключите потоки данных",
|
||||
@@ -1286,6 +1277,8 @@
|
||||
"Contiguous US · gaps ≠ no rain": "Континентальные США · пробелы ≠ нет дождя",
|
||||
"Americas + Pacific · not individual strikes": "Америка + Тихий океан · не отдельные разряды",
|
||||
"Color: strikes/km²/min ×10³": "Цвет: разрядов/км²/мин ×10³",
|
||||
"Color: {units}": "Цвет: {units}",
|
||||
"RADAR · {units}": "РАДАР · {units}",
|
||||
"60°S–60°N · typically 2–3 h delayed": "60° ю. ш.–60° с. ш. · обычно задержка 2–3 ч",
|
||||
"North America · infrared imagery": "Северная Америка · ИК-снимки",
|
||||
"Reduced motion · history playback unavailable": "Уменьшение движения · воспроизведение истории недоступно",
|
||||
@@ -2201,7 +2194,7 @@
|
||||
"Low-accuracy score 2–10%": "Доля неточных 2–10%",
|
||||
"Low-accuracy score > 10%": "Доля неточных > 10%",
|
||||
"GNSS integrity source unavailable": "Источник целостности GNSS недоступен",
|
||||
"Regional sample · 250 nm radius · cells from visited views over 30 min": "Региональная выборка · радиус 250 мор. миль · ячейки из просмотренных видов за 30 мин",
|
||||
"Regional sample · 250 nm radius · cells from visited views over {minutes} min": "Региональная выборка · радиус 250 мор. миль · ячейки из просмотренных видов за {minutes} мин",
|
||||
"Retrying automatically at {time} UTC": "Автоматический повтор в {time} UTC",
|
||||
"Retrying automatically after provider cooldown": "Автоматический повтор после паузы провайдера",
|
||||
"Updates automatically after pan or zoom and once a minute. The public feed covers a 250-nautical-mile circle around the view centre; zooming out does not make it a worldwide snapshot. Blank cells are outside sampled coverage or have insufficient observations.": "Обновляется автоматически после сдвига или масштабирования карты и раз в минуту. Публичный поток данных охватывает круг радиусом 250 морских миль вокруг центра вида; при отдалении карта не становится снимком всего мира. Пустые ячейки — вне охвата выборки или с недостаточным числом наблюдений.",
|
||||
@@ -2520,9 +2513,6 @@
|
||||
"ChatGPT sign-in timed out. Click {button} to try again.": "Время на вход в ChatGPT истекло. Нажмите «{button}», чтобы попробовать ещё раз.",
|
||||
"ChatGPT sign-in complete. OAuth will be used for the next cloud voice session.": "Вход в ChatGPT выполнен. В следующей облачной голосовой сессии будет использоваться OAuth.",
|
||||
"OAuth check failed: {detail}": "Не удалось проверить OAuth: {detail}",
|
||||
"unsaved CCTV calibration": "несохранённая калибровка CCTV",
|
||||
"the open cockpit": "открытая кабина",
|
||||
"Switching language reloads the page. This will be lost: {items}. Switch anyway?": "Смена языка перезагрузит страницу. Будет потеряно: {items}. Всё равно сменить язык?",
|
||||
"Wind upstream unavailable": "Источник данных о ветре недоступен",
|
||||
"WebUSB needs desktop Chrome or Edge": "Для WebUSB нужен настольный Chrome или Edge",
|
||||
"connect a receiver in Radio": "подключите приёмник в разделе «Радио»",
|
||||
@@ -2724,9 +2714,6 @@
|
||||
"KartaView answered HTTP {status}": "KartaView ответил: HTTP {status}",
|
||||
"KartaView refused the request (code {code})": "KartaView отклонил запрос (код {code})",
|
||||
"Stopped by voice": "Остановлено голосовой командой",
|
||||
"drawings on the map": "рисунки на карте",
|
||||
"imported map files": "импортированные файлы на карте",
|
||||
"the active voice session": "активная голосовая сессия",
|
||||
"Light aircraft": "Лёгкий самолёт",
|
||||
"Glider": "Планёр",
|
||||
"Turboprop": "Турбовинтовой самолёт",
|
||||
@@ -2937,7 +2924,6 @@
|
||||
"many": "потоки {names} некорректны",
|
||||
"other": "потоки {names} некорректны"
|
||||
},
|
||||
"unsaved provider keys": "несохранённые ключи провайдеров",
|
||||
"Exit cockpit to fly to an aircraft": "Выйдите из кабины, чтобы перелететь к самолёту",
|
||||
"Exit cockpit to fly to a satellite": "Выйдите из кабины, чтобы перелететь к спутнику",
|
||||
"Exit cockpit to frame contacts": "Выйдите из кабины, чтобы показать контакты в кадре",
|
||||
@@ -3069,5 +3055,33 @@
|
||||
"Preview is off.": "Предпросмотр отключён.",
|
||||
"Automatic stop is unavailable for this voice connection.": "Автоматическая остановка недоступна для этого голосового подключения.",
|
||||
"routing busy — too many routes at once": "сервис маршрутов занят: слишком много маршрутов одновременно",
|
||||
"route proxy error": "ошибка прокси маршрутов"
|
||||
"route proxy error": "ошибка прокси маршрутов",
|
||||
"AUTHORING": "РЕДАКТОР",
|
||||
"Create and edit scenes": "Создание и редактирование сцен",
|
||||
"SCENE": "СЦЕНА",
|
||||
"Scene": "Сцена",
|
||||
"NEW SCENE": "НОВАЯ СЦЕНА",
|
||||
"Start a new, empty scene": "Создать новую пустую сцену",
|
||||
"DELETE": "УДАЛИТЬ",
|
||||
"Delete this scene and all of its shots": "Удалить эту сцену и все её кадры",
|
||||
"SHOTS": "КАДРЫ",
|
||||
"+ CAPTURE SHOT": "+ СДЕЛАТЬ КАДР",
|
||||
"Add the current view, style and layers as the next shot": "Добавить текущий вид, стиль и слои следующим кадром",
|
||||
"Replace the selected shot with the current view": "Заменить выбранный кадр текущим видом",
|
||||
"Click a shot to select it, double-click to rename.": "Щёлкните кадр, чтобы выбрать его, дважды — чтобы переименовать.",
|
||||
"scene|PLAY": "ПУСК",
|
||||
"Stop playback (Esc)": "Остановить воспроизведение (Esc)",
|
||||
"SAVE & SHARE": "СОХРАНИТЬ И ПОДЕЛИТЬСЯ",
|
||||
"Download every scene as a JSON file you can import later": "Скачать все сцены файлом JSON для последующего импорта",
|
||||
"Load scenes from an exported JSON file": "Загрузить сцены из экспортированного файла JSON",
|
||||
"Download the timing log of the last play": "Скачать журнал таймингов последнего воспроизведения",
|
||||
"Play from this scene through the rest of the project": "Воспроизвести с этой сцены и далее по всему проекту",
|
||||
"Play the shot after the selected one, moving on to the next scene when needed": "Воспроизвести кадр после выбранного, при необходимости перейдя к следующей сцене",
|
||||
"Edit anchors, data packs and shot details": "Изменить якоря, пакеты данных и параметры кадров",
|
||||
"Download this scene as JSON or an asset bundle": "Скачать эту сцену в формате JSON или архивом ресурсов",
|
||||
"Left panels": "Левые панели",
|
||||
"Right panels": "Правые панели",
|
||||
"UTILITIES": "ИНСТРУМЕНТЫ",
|
||||
"Exit cockpit to fly to a drawing": "Выйдите из кабины, чтобы перелететь к рисунку",
|
||||
"Directions, drawing and your own files": "Маршруты, рисование и ваши файлы"
|
||||
}
|
||||
+36
-22
@@ -12,7 +12,6 @@
|
||||
"That line has no length — click somewhere further away.": "Лінія не має довжини — клацніть далі.",
|
||||
" · {max}-point limit reached": " · досягнуто ліміту точок: {max}",
|
||||
"{measure} · double-click or Enter to finish, Backspace undoes, Esc cancels.{full}": "{measure} · подвійне клацання або Enter — завершити, Backspace — скасувати точку, Esc — скасувати.{full}",
|
||||
"drawings on the map": "малюнки на карті",
|
||||
"That shape already has {count} points — finish it or press Backspace.": "Фігура вже має максимальну кількість точок ({count}) — завершіть її або натисніть Backspace.",
|
||||
"That point is off the globe — click on the world.": "Ця точка поза глобусом — клацніть на Землі.",
|
||||
"That shape could not be placed.": "Не вдалося розмістити фігуру.",
|
||||
@@ -406,7 +405,6 @@
|
||||
"paste {envVar}": "вставте {envVar}",
|
||||
"REMOVE": "ВИДАЛИТИ",
|
||||
"Remove {title} from this app's saved keys": "Видалити {title} зі збережених ключів застосунку",
|
||||
"unsaved provider keys": "незбережені ключі постачальників",
|
||||
"Project keys: {status}": "Ключі проєкту: {status}",
|
||||
"your app configuration": "вашої конфігурації застосунку",
|
||||
"your local .env": "вашого локального .env",
|
||||
@@ -724,7 +722,6 @@
|
||||
"NIGHT": "НІЧ",
|
||||
"▲ {frp} MW": "▲ {frp} МВт",
|
||||
"FIRE": "ПОЖЕЖА",
|
||||
"FIRES": "ПОЖ.",
|
||||
"max {value} MW": "макс. {value} МВт",
|
||||
"new {value}": "останнє: {value} тому",
|
||||
"{value}°N": "{value}° пн. ш.",
|
||||
@@ -781,7 +778,7 @@
|
||||
"Low-accuracy score 2–10%": "Показник неточності 2–10%",
|
||||
"Low-accuracy score > 10%": "Показник неточності > 10%",
|
||||
"GNSS integrity source unavailable": "Джерело даних про цілісність GNSS недоступне",
|
||||
"Regional sample · 250 nm radius · cells from visited views over 30 min": "Регіональна вибірка · радіус 250 мор. миль · комірки з переглянутих ділянок карти за 30 хв",
|
||||
"Regional sample · 250 nm radius · cells from visited views over {minutes} min": "Регіональна вибірка · радіус 250 мор. миль · комірки з переглянутих ділянок карти за {minutes} хв",
|
||||
"Retrying automatically at {time} UTC": "Автоматичний повтор о {time} UTC",
|
||||
"Retrying automatically after provider cooldown": "Автоматичний повтор після паузи постачальника",
|
||||
"Updates automatically after pan or zoom and once a minute. The public feed covers a 250-nautical-mile circle around the view centre; zooming out does not make it a worldwide snapshot. Blank cells are outside sampled coverage or have insufficient observations.": "Оновлюється автоматично після зсуву чи масштабування карти та раз на хвилину. Публічний потік даних охоплює коло радіусом 250 морських миль навколо центру карти; у разі віддалення карта не стає знімком усього світу. Порожні комірки — поза охопленням вибірки або з недостатньою кількістю спостережень.",
|
||||
@@ -1229,6 +1226,8 @@
|
||||
"Contiguous US · gaps ≠ no rain": "48 суміжних штатів США · прогалини ≠ немає дощу",
|
||||
"Americas + Pacific · not individual strikes": "Америка + Тихий океан · не окремі розряди",
|
||||
"Color: strikes/km²/min ×10³": "Колір: розрядів/км²/хв ×10³",
|
||||
"Color: {units}": "Колір: {units}",
|
||||
"RADAR · {units}": "РАДАР · {units}",
|
||||
"60°S–60°N · typically 2–3 h delayed": "60° пд. ш.–60° пн. ш. · зазвичай затримка 2–3 год",
|
||||
"North America · infrared imagery": "Північна Америка · ІЧ-знімки",
|
||||
"Reduced motion · history playback unavailable": "Зменшення руху · відтворення історії недоступне",
|
||||
@@ -1560,9 +1559,6 @@
|
||||
"Sensitivity": "Чутливість",
|
||||
"WHOT/BHOT": "WHOT/BHOT",
|
||||
"Ironbow": "Ironbow",
|
||||
"unsaved CCTV calibration": "незбережене калібрування CCTV",
|
||||
"the open cockpit": "відкрита кабіна",
|
||||
"Switching language reloads the page. This will be lost: {items}. Switch anyway?": "Зміна мови перезавантажить сторінку. Буде втрачено: {items}. Усе одно змінити мову?",
|
||||
"VISUAL PRESETS": "ВІЗУАЛЬНІ ПРЕСЕТИ",
|
||||
"LOCATION": "РОЗТАШУВАННЯ",
|
||||
"CONTACTS — nearest planes · vessels · sites": "КОНТАКТИ — найближчі літаки · судна · обʼєкти",
|
||||
@@ -1794,7 +1790,6 @@
|
||||
"Space Missions": "Космічні місії",
|
||||
"Context": "Контекст",
|
||||
"Rendered globe frames per second · toggle with `": "Кадрів глобуса за секунду · перемикання клавішею `",
|
||||
"imported map files": "імпортовані файли на карті",
|
||||
"Ground heights could not be refreshed. Try the file again when the map has loaded.": "Не вдалося оновити висоти рельєфу. Спробуйте імпортувати файл ще раз, коли карта завантажиться.",
|
||||
"{count} map objects": {
|
||||
"one": "{count} обʼєкт на карті",
|
||||
@@ -2611,7 +2606,6 @@
|
||||
"Activate to toggle voice": "Активуйте, щоб увімкнути або вимкнути голос",
|
||||
"Voice active": "Голос активний",
|
||||
"Voice could not be started.": "Не вдалося запустити голос.",
|
||||
"the active voice session": "активний голосовий сеанс",
|
||||
"{value} feet": "{value} фт",
|
||||
"Fire · FRP {frp} MW": "Пожежа · FRP {frp} МВт",
|
||||
"The flights layer is not enabled": "Шар рейсів не ввімкнено",
|
||||
@@ -2775,8 +2769,6 @@
|
||||
"Cockpit vision style": "Візуальний стиль у кабіні",
|
||||
"Previous cockpit vision style": "Попередній візуальний стиль у кабіні",
|
||||
"Previous vision style": "Попередній візуальний стиль",
|
||||
"Current cockpit vision style: NORMAL. Activate for next style.": "Поточний візуальний стиль у кабіні: ЗВИЧАЙНИЙ. Активуйте, щоб перейти до наступного.",
|
||||
"Current style: NORMAL — click for next": "Поточний стиль: ЗВИЧАЙНИЙ — клацніть для наступного",
|
||||
"CURRENT": "ПОТОЧНИЙ",
|
||||
"Next cockpit vision style": "Наступний візуальний стиль у кабіні",
|
||||
"Next vision style": "Наступний візуальний стиль",
|
||||
@@ -2863,7 +2855,6 @@
|
||||
"RECENT IMAGERY": "СВІЖІ ЗНІМКИ",
|
||||
"Imagery days in the box": "Дні зі знімками в області",
|
||||
"CONTEXT": "КОНТЕКСТ",
|
||||
"Expand panel": "Розгорнути панель",
|
||||
"Context mode": "Режим контексту",
|
||||
"CONTACTS": "КОНТАКТИ",
|
||||
"Cycles the nearest contacts of whatever type you select — planes, vessels, installations. Satellites track independently.": "Гортає найближчі контакти вибраного вами типу — літаки, судна, обʼєкти. Супутники відстежуються окремо.",
|
||||
@@ -3025,13 +3016,7 @@
|
||||
"ALL": "УСІ",
|
||||
"FLAT": "ПЛОСКІ",
|
||||
"SINCE": "З ДАТИ",
|
||||
"SCENES": "СЦЕНИ",
|
||||
"Scene recipe": "Рецепт сцени",
|
||||
"NEW": "НОВА",
|
||||
"CAPTURE SHOT": "ЗНЯТИ КАДР",
|
||||
"UPDATE SHOT": "ОНОВИТИ КАДР",
|
||||
"START": "СТАРТ",
|
||||
"EXPORT PRESETS": "ЕКСПОРТУВАТИ ПРЕСЕТИ",
|
||||
"IMPORT": "ІМПОРТУВАТИ",
|
||||
"RUN LOG": "ЖУРНАЛ ВІДТВОРЕННЯ",
|
||||
"POWER UP": "ЗАПУСК",
|
||||
@@ -3063,11 +3048,40 @@
|
||||
"Tip: the GEV MIC button in the dock lets you talk to the map.": "Порада: кнопка МІК у доку дає змогу говорити з картою.",
|
||||
"Malformed cyclone snapshot": "Некоректний знімок циклонів",
|
||||
"Cyclone request timed out": "Минув час очікування запиту циклонів",
|
||||
"Colour of {name}": "Колір: {name}",
|
||||
"Change the colour of {name}": "Змінити колір: {name}",
|
||||
"scene|PLAY": "СТАРТ",
|
||||
"AUTHORING": "РЕДАКТОР",
|
||||
"Create and edit scenes": "Створення й редагування сцен",
|
||||
"SCENE": "СЦЕНА",
|
||||
"Scene": "Сцена",
|
||||
"NEW SCENE": "НОВА СЦЕНА",
|
||||
"Start a new, empty scene": "Створити нову порожню сцену",
|
||||
"DELETE": "ВИДАЛИТИ",
|
||||
"Delete this scene and all of its shots": "Видалити цю сцену з усіма кадрами",
|
||||
"SHOTS": "КАДРИ",
|
||||
"+ CAPTURE SHOT": "+ ЗНЯТИ КАДР",
|
||||
"Add the current view, style and layers as the next shot": "Додати поточний вигляд, стиль і шари як наступний кадр",
|
||||
"Replace the selected shot with the current view": "Замінити вибраний кадр поточним виглядом",
|
||||
"Click a shot to select it, double-click to rename.": "Натисніть кадр, щоб вибрати його, двічі — щоб перейменувати.",
|
||||
"Play from this scene through the rest of the project": "Відтворити від цієї сцени до кінця проєкту",
|
||||
"Stop playback (Esc)": "Зупинити відтворення (Esc)",
|
||||
"Play the shot after the selected one, moving on to the next scene when needed": "Відтворити кадр після вибраного, за потреби перейшовши до наступної сцени",
|
||||
"SAVE & SHARE": "ЗБЕРЕГТИ Й ПОДІЛИТИСЯ",
|
||||
"Download every scene as a JSON file you can import later": "Завантажити всі сцени файлом JSON для подальшого імпорту",
|
||||
"Load scenes from an exported JSON file": "Завантажити сцени з експортованого файлу JSON",
|
||||
"Download the timing log of the last play": "Завантажити журнал таймінгів останнього відтворення",
|
||||
"Edit anchors, data packs and shot details": "Змінити якорі, пакети даних і параметри кадрів",
|
||||
"Download this scene as JSON or an asset bundle": "Завантажити цю сцену у форматі JSON або архівом ресурсів",
|
||||
"Left panels": "Ліві панелі",
|
||||
"Right panels": "Праві панелі",
|
||||
"CONFIRMED": "ПІДТВЕРДЖЕНО",
|
||||
"PAD / RTLS": "МІСЦЕ ЗАПУСКУ / RTLS",
|
||||
"Name of {name}": "Назва: {name}",
|
||||
"Change the colour of {name}": "Змінити колір: {name}",
|
||||
"Colour of {name}": "Колір: {name}",
|
||||
"Colour of the next shape": "Колір наступної фігури",
|
||||
"Drawn shapes": "Намальовані фігури",
|
||||
"Audio": "Аудіо",
|
||||
"UTILITIES": "ІНСТРУМЕНТИ",
|
||||
"Colour of the next shape": "Колір наступної фігури",
|
||||
"Drawn shapes": "Намальовані фігури"
|
||||
"Exit cockpit to fly to a drawing": "Вийдіть із кабіни, щоб перелетіти до малюнка",
|
||||
"Directions, drawing and your own files": "Маршрути, малювання та ваші файли"
|
||||
}
|
||||
+34
-20
@@ -9,7 +9,6 @@
|
||||
"That line has no length — click somewhere further away.": "这条线没有长度——请在更远处点击。",
|
||||
" · {max}-point limit reached": " · 已达 {max} 个点上限",
|
||||
"{measure} · double-click or Enter to finish, Backspace undoes, Esc cancels.{full}": "{measure} · 双击或按 Enter 完成,按 Backspace 撤销,按 Esc 取消。{full}",
|
||||
"drawings on the map": "地图上的绘图",
|
||||
"That shape already has {count} points — finish it or press Backspace.": "该形状已有 {count} 个点——请完成绘制或按 Backspace。",
|
||||
"That point is off the globe — click on the world.": "该点在地球之外——请点击地球上的位置。",
|
||||
"That shape could not be placed.": "该形状无法放置。",
|
||||
@@ -394,7 +393,6 @@
|
||||
"paste {envVar}": "粘贴 {envVar}",
|
||||
"REMOVE": "移除",
|
||||
"Remove {title} from this app's saved keys": "从本应用已保存的密钥中移除 {title}",
|
||||
"unsaved provider keys": "未保存的服务商密钥",
|
||||
"Project keys: {status}": "项目密钥:{status}",
|
||||
"your app configuration": "你的应用配置",
|
||||
"your local .env": "你的本地 .env",
|
||||
@@ -697,7 +695,6 @@
|
||||
"NIGHT": "夜间",
|
||||
"▲ {frp} MW": "▲ {frp} MW",
|
||||
"FIRE": "火点",
|
||||
"FIRES": "火点",
|
||||
"max {value} MW": "最大 {value} MW",
|
||||
"new {value}": "最新({value}前)",
|
||||
"{value}°N": "{value}°N",
|
||||
@@ -726,7 +723,7 @@
|
||||
"Low-accuracy score 2–10%": "低精度评分 2–10%",
|
||||
"Low-accuracy score > 10%": "低精度评分 > 10%",
|
||||
"GNSS integrity source unavailable": "GNSS 完好性数据源不可用",
|
||||
"Regional sample · 250 nm radius · cells from visited views over 30 min": "区域采样 · 半径 250 海里 · 30 分钟内已访问视图中的网格",
|
||||
"Regional sample · 250 nm radius · cells from visited views over {minutes} min": "区域采样 · 半径 250 海里 · {minutes} 分钟内已访问视图中的网格",
|
||||
"Retrying automatically at {time} UTC": "将于 {time} UTC 自动重试",
|
||||
"Retrying automatically after provider cooldown": "服务商冷却结束后自动重试",
|
||||
"Updates automatically after pan or zoom and once a minute. The public feed covers a 250-nautical-mile circle around the view centre; zooming out does not make it a worldwide snapshot. Blank cells are outside sampled coverage or have insufficient observations.": "平移或缩放后以及每分钟自动更新。公共数据源覆盖以视野中心为圆心、半径 250 海里的范围;缩小地图并不会使其成为全球快照。空白网格位于采样覆盖范围之外,或观测数据不足。",
|
||||
@@ -812,6 +809,8 @@
|
||||
"Pause replay": "暂停回放",
|
||||
"Cancel replay": "取消回放",
|
||||
"EST. DOWNRANGE": "预估落点距离",
|
||||
"CONFIRMED": "已确认",
|
||||
"PAD / RTLS": "发射台 / RTLS",
|
||||
"PLANNED · ": "计划 · ",
|
||||
"SUPPLIED TRAJECTORY POINTS": "提供的轨迹点",
|
||||
"RECONSTRUCTED ESTIMATE": "重建估算",
|
||||
@@ -1156,6 +1155,8 @@
|
||||
"Contiguous US · gaps ≠ no rain": "美国本土 · 数据缺失 ≠ 无降雨",
|
||||
"Americas + Pacific · not individual strikes": "美洲与太平洋 · 非单次闪击",
|
||||
"Color: strikes/km²/min ×10³": "颜色:闪击次数/km²/分钟 ×10³",
|
||||
"Color: {units}": "颜色:{units}",
|
||||
"RADAR · {units}": "雷达 · {units}",
|
||||
"60°S–60°N · typically 2–3 h delayed": "60°S–60°N · 通常延迟 2–3 小时",
|
||||
"North America · infrared imagery": "北美洲 · 红外影像",
|
||||
"Reduced motion · history playback unavailable": "减弱动效 · 历史回放不可用",
|
||||
@@ -1470,9 +1471,6 @@
|
||||
"Sensitivity": "灵敏度",
|
||||
"WHOT/BHOT": "WHOT/BHOT",
|
||||
"Ironbow": "Ironbow",
|
||||
"unsaved CCTV calibration": "未保存的 CCTV 校准",
|
||||
"the open cockpit": "当前打开的座舱",
|
||||
"Switching language reloads the page. This will be lost: {items}. Switch anyway?": "切换语言会重新加载页面。以下内容将会丢失:{items}。仍要切换吗?",
|
||||
"VISUAL PRESETS": "视觉预设",
|
||||
"LOCATION": "位置",
|
||||
"CONTACTS — nearest planes · vessels · sites": "目标:最近的飞机 · 船舶 · 设施",
|
||||
@@ -1686,7 +1684,6 @@
|
||||
"Space Missions": "太空任务",
|
||||
"Context": "态势",
|
||||
"Rendered globe frames per second · toggle with `": "每秒渲染的地球帧数 · 按 ` 键切换",
|
||||
"imported map files": "已导入的地图文件",
|
||||
"Ground heights could not be refreshed. Try the file again when the map has loaded.": "无法刷新地面高度。请在地图加载完成后重新尝试该文件。",
|
||||
"{count} map objects": {
|
||||
"other": "{count} 个地图对象"
|
||||
@@ -2316,7 +2313,6 @@
|
||||
"Activate to toggle voice": "点击切换语音",
|
||||
"Voice active": "语音已启用",
|
||||
"Voice could not be started.": "无法启动语音。",
|
||||
"the active voice session": "当前语音会话",
|
||||
"{value} feet": "{value} 英尺",
|
||||
"The flights layer is not enabled": "航班图层未开启",
|
||||
"The military layer is not enabled": "军用航班图层未开启",
|
||||
@@ -2460,8 +2456,6 @@
|
||||
"Cockpit vision style": "座舱视觉样式",
|
||||
"Previous cockpit vision style": "上一个座舱视觉样式",
|
||||
"Previous vision style": "上一个视觉样式",
|
||||
"Current cockpit vision style: NORMAL. Activate for next style.": "当前座舱视觉样式:常规。点击可切换到下一个样式。",
|
||||
"Current style: NORMAL — click for next": "当前样式:常规——点击切换到下一个",
|
||||
"CURRENT": "当前",
|
||||
"Next cockpit vision style": "下一个座舱视觉样式",
|
||||
"Next vision style": "下一个视觉样式",
|
||||
@@ -2548,7 +2542,6 @@
|
||||
"RECENT IMAGERY": "近期影像",
|
||||
"Imagery days in the box": "视野内的影像天数",
|
||||
"CONTEXT": "态势",
|
||||
"Expand panel": "展开面板",
|
||||
"Context mode": "态势模式",
|
||||
"CONTACTS": "目标",
|
||||
"Cycles the nearest contacts of whatever type you select — planes, vessels, installations. Satellites track independently.": "循环切换你所选类型中最近的目标,包括飞机、船舶、设施。卫星独立跟踪。",
|
||||
@@ -2714,14 +2707,7 @@
|
||||
"ALL": "全部",
|
||||
"FLAT": "平面",
|
||||
"SINCE": "起始时间",
|
||||
"SCENES": "场景",
|
||||
"UTILITIES": "工具",
|
||||
"Scene recipe": "场景方案",
|
||||
"NEW": "新建",
|
||||
"CAPTURE SHOT": "保存镜头",
|
||||
"UPDATE SHOT": "更新镜头",
|
||||
"START": "启动",
|
||||
"EXPORT PRESETS": "导出预设",
|
||||
"IMPORT": "导入",
|
||||
"RUN LOG": "运行日志",
|
||||
"POWER UP": "增强",
|
||||
@@ -2859,5 +2845,33 @@
|
||||
},
|
||||
"S2 Underground publishes these KMZ products to GitHub. New uploads are detected within seconds and replace the previous edition automatically. Click a marker for its report.": "S2 Underground 在 GitHub 发布这些 KMZ 产品。新上传的内容会在数秒内被检测到,并自动替换旧版本。点击标记查看报告。",
|
||||
"routing busy — too many routes at once": "路线服务繁忙:同时请求的路线过多",
|
||||
"route proxy error": "路线代理出错"
|
||||
"route proxy error": "路线代理出错",
|
||||
"AUTHORING": "创作",
|
||||
"Create and edit scenes": "创建和编辑场景",
|
||||
"SCENE": "场景",
|
||||
"Scene": "场景",
|
||||
"NEW SCENE": "新建场景",
|
||||
"Start a new, empty scene": "新建一个空场景",
|
||||
"DELETE": "删除",
|
||||
"Delete this scene and all of its shots": "删除此场景及其所有镜头",
|
||||
"SHOTS": "镜头",
|
||||
"+ CAPTURE SHOT": "+ 保存镜头",
|
||||
"Add the current view, style and layers as the next shot": "将当前视角、样式和图层添加为下一个镜头",
|
||||
"Replace the selected shot with the current view": "用当前视角替换所选镜头",
|
||||
"Click a shot to select it, double-click to rename.": "单击镜头即可选中,双击可重命名。",
|
||||
"scene|PLAY": "播放",
|
||||
"Stop playback (Esc)": "停止播放(Esc)",
|
||||
"SAVE & SHARE": "保存与分享",
|
||||
"Download every scene as a JSON file you can import later": "将所有场景下载为 JSON 文件,以便日后导入",
|
||||
"Load scenes from an exported JSON file": "从导出的 JSON 文件加载场景",
|
||||
"Download the timing log of the last play": "下载上次播放的计时日志",
|
||||
"Play from this scene through the rest of the project": "从此场景开始播放项目中的其余场景",
|
||||
"Play the shot after the selected one, moving on to the next scene when needed": "播放所选镜头的下一个镜头,必要时进入下一个场景",
|
||||
"Edit anchors, data packs and shot details": "编辑锚点、数据包和镜头详情",
|
||||
"Download this scene as JSON or an asset bundle": "将此场景下载为 JSON 或资源包",
|
||||
"Left panels": "左侧面板",
|
||||
"Right panels": "右侧面板",
|
||||
"UTILITIES": "工具",
|
||||
"Exit cockpit to fly to a drawing": "请先退出座舱,再飞往绘制位置",
|
||||
"Directions, drawing and your own files": "路线导航、绘制和你自己的文件"
|
||||
}
|
||||
@@ -9,7 +9,6 @@
|
||||
"That line has no length — click somewhere further away.": "這條線沒有長度——請在更遠處點擊。",
|
||||
" · {max}-point limit reached": " · 已達 {max} 個點上限",
|
||||
"{measure} · double-click or Enter to finish, Backspace undoes, Esc cancels.{full}": "{measure} · 雙擊或按 Enter 完成,按 Backspace 撤銷,按 Esc 取消。{full}",
|
||||
"drawings on the map": "地圖上的繪圖",
|
||||
"That shape already has {count} points — finish it or press Backspace.": "該形狀已有 {count} 個點——請完成繪製或按 Backspace。",
|
||||
"That point is off the globe — click on the world.": "該點在地球之外——請點擊地球上的位置。",
|
||||
"That shape could not be placed.": "該形狀無法放置。",
|
||||
@@ -394,7 +393,6 @@
|
||||
"paste {envVar}": "粘貼 {envVar}",
|
||||
"REMOVE": "移除",
|
||||
"Remove {title} from this app's saved keys": "從本應用已保存的密鑰中移除 {title}",
|
||||
"unsaved provider keys": "未保存的服務商密鑰",
|
||||
"Project keys: {status}": "項目密鑰:{status}",
|
||||
"your app configuration": "你的應用配置",
|
||||
"your local .env": "你的本地 .env",
|
||||
@@ -692,7 +690,6 @@
|
||||
"NIGHT": "夜間",
|
||||
"▲ {frp} MW": "▲ {frp} MW",
|
||||
"FIRE": "火點",
|
||||
"FIRES": "火點",
|
||||
"max {value} MW": "最大 {value} MW",
|
||||
"new {value}": "最新({value}前)",
|
||||
"{value}°N": "{value}°N",
|
||||
@@ -721,7 +718,7 @@
|
||||
"Low-accuracy score 2–10%": "低精度評分 2–10%",
|
||||
"Low-accuracy score > 10%": "低精度評分 > 10%",
|
||||
"GNSS integrity source unavailable": "GNSS 完好性數據源不可用",
|
||||
"Regional sample · 250 nm radius · cells from visited views over 30 min": "區域採樣 · 半徑 250 海里 · 30 分鐘內已訪問視圖中的網格",
|
||||
"Regional sample · 250 nm radius · cells from visited views over {minutes} min": "區域採樣 · 半徑 250 海里 · {minutes} 分鐘內已訪問視圖中的網格",
|
||||
"Retrying automatically at {time} UTC": "將於 {time} UTC 自動重試",
|
||||
"Retrying automatically after provider cooldown": "服務商冷卻結束後自動重試",
|
||||
"Updates automatically after pan or zoom and once a minute. The public feed covers a 250-nautical-mile circle around the view centre; zooming out does not make it a worldwide snapshot. Blank cells are outside sampled coverage or have insufficient observations.": "平移或縮放後以及每分鐘自動更新。公共數據源覆蓋以視野中心為圓心、半徑 250 海里的範圍;縮小地圖並不會使其成為全球快照。空白網格位於採樣覆蓋範圍之外,或觀測數據不足。",
|
||||
@@ -807,6 +804,8 @@
|
||||
"Pause replay": "暫停回放",
|
||||
"Cancel replay": "取消回放",
|
||||
"EST. DOWNRANGE": "預估落點距離",
|
||||
"CONFIRMED": "已確認",
|
||||
"PAD / RTLS": "發射臺 / RTLS",
|
||||
"PLANNED · ": "計劃 · ",
|
||||
"SUPPLIED TRAJECTORY POINTS": "提供的軌跡點",
|
||||
"RECONSTRUCTED ESTIMATE": "重建估算",
|
||||
@@ -1151,6 +1150,8 @@
|
||||
"Contiguous US · gaps ≠ no rain": "美國本土 · 數據缺失 ≠ 無降雨",
|
||||
"Americas + Pacific · not individual strikes": "美洲與太平洋 · 非單次閃擊",
|
||||
"Color: strikes/km²/min ×10³": "顏色:閃擊次數/km²/分鐘 ×10³",
|
||||
"Color: {units}": "顏色:{units}",
|
||||
"RADAR · {units}": "雷達 · {units}",
|
||||
"60°S–60°N · typically 2–3 h delayed": "60°S–60°N · 通常延遲 2–3 小時",
|
||||
"North America · infrared imagery": "北美洲 · 紅外影像",
|
||||
"Reduced motion · history playback unavailable": "減弱動效 · 歷史回放不可用",
|
||||
@@ -1465,9 +1466,6 @@
|
||||
"Sensitivity": "靈敏度",
|
||||
"WHOT/BHOT": "WHOT/BHOT",
|
||||
"Ironbow": "Ironbow",
|
||||
"unsaved CCTV calibration": "未保存的 CCTV 校準",
|
||||
"the open cockpit": "當前打開的座艙",
|
||||
"Switching language reloads the page. This will be lost: {items}. Switch anyway?": "切換語言會重新加載頁面。以下內容將會丟失:{items}。仍要切換嗎?",
|
||||
"VISUAL PRESETS": "視覺預設",
|
||||
"LOCATION": "位置",
|
||||
"CONTACTS — nearest planes · vessels · sites": "目標:最近的飛機 · 船舶 · 設施",
|
||||
@@ -1676,7 +1674,6 @@
|
||||
"Space Missions": "太空任務",
|
||||
"Context": "態勢",
|
||||
"Rendered globe frames per second · toggle with `": "每秒渲染的地球幀數 · 按 ` 鍵切換",
|
||||
"imported map files": "已導入的地圖文件",
|
||||
"Ground heights could not be refreshed. Try the file again when the map has loaded.": "無法刷新地面高度。請在地圖加載完成後重新嘗試該文件。",
|
||||
"{count} map objects": {
|
||||
"other": "{count} 個地圖對象"
|
||||
@@ -2304,7 +2301,6 @@
|
||||
"Activate to toggle voice": "點擊切換語音",
|
||||
"Voice active": "語音已啟用",
|
||||
"Voice could not be started.": "無法啟動語音。",
|
||||
"the active voice session": "當前語音會話",
|
||||
"{value} feet": "{value} 英尺",
|
||||
"The flights layer is not enabled": "航班圖層未開啟",
|
||||
"The military layer is not enabled": "軍用航班圖層未開啟",
|
||||
@@ -2448,8 +2444,6 @@
|
||||
"Cockpit vision style": "座艙視覺樣式",
|
||||
"Previous cockpit vision style": "上一個座艙視覺樣式",
|
||||
"Previous vision style": "上一個視覺樣式",
|
||||
"Current cockpit vision style: NORMAL. Activate for next style.": "當前座艙視覺樣式:常規。點擊可切換到下一個樣式。",
|
||||
"Current style: NORMAL — click for next": "當前樣式:常規——點擊切換到下一個",
|
||||
"CURRENT": "當前",
|
||||
"Next cockpit vision style": "下一個座艙視覺樣式",
|
||||
"Next vision style": "下一個視覺樣式",
|
||||
@@ -2536,7 +2530,6 @@
|
||||
"RECENT IMAGERY": "近期影像",
|
||||
"Imagery days in the box": "視野內的影像天數",
|
||||
"CONTEXT": "態勢",
|
||||
"Expand panel": "展開面板",
|
||||
"Context mode": "態勢模式",
|
||||
"CONTACTS": "目標",
|
||||
"Cycles the nearest contacts of whatever type you select — planes, vessels, installations. Satellites track independently.": "循環切換你所選類型中最近的目標,包括飛機、船舶、設施。衛星獨立跟蹤。",
|
||||
@@ -2702,14 +2695,7 @@
|
||||
"ALL": "全部",
|
||||
"FLAT": "平面",
|
||||
"SINCE": "起始時間",
|
||||
"SCENES": "場景",
|
||||
"UTILITIES": "工具",
|
||||
"Scene recipe": "場景方案",
|
||||
"NEW": "新建",
|
||||
"CAPTURE SHOT": "保存鏡頭",
|
||||
"UPDATE SHOT": "更新鏡頭",
|
||||
"START": "啟動",
|
||||
"EXPORT PRESETS": "導出預設",
|
||||
"IMPORT": "導入",
|
||||
"RUN LOG": "運行日誌",
|
||||
"POWER UP": "增強",
|
||||
@@ -2859,5 +2845,33 @@
|
||||
},
|
||||
"S2 Underground publishes these KMZ products to GitHub. New uploads are detected within seconds and replace the previous edition automatically. Click a marker for its report.": "S2 Underground 在 GitHub 發布這些 KMZ 產品。新上傳的內容會在數秒內被檢測到,並自動替換舊版本。點擊標記查看報告。",
|
||||
"routing busy — too many routes at once": "路線服務繁忙:同時請求的路線過多",
|
||||
"route proxy error": "路線代理出錯"
|
||||
"route proxy error": "路線代理出錯",
|
||||
"AUTHORING": "創作",
|
||||
"Create and edit scenes": "創建和編輯場景",
|
||||
"SCENE": "場景",
|
||||
"Scene": "場景",
|
||||
"NEW SCENE": "新建場景",
|
||||
"Start a new, empty scene": "新建一個空場景",
|
||||
"DELETE": "刪除",
|
||||
"Delete this scene and all of its shots": "刪除此場景及其所有鏡頭",
|
||||
"SHOTS": "鏡頭",
|
||||
"+ CAPTURE SHOT": "+ 保存鏡頭",
|
||||
"Add the current view, style and layers as the next shot": "將當前視角、樣式和圖層添加為下一個鏡頭",
|
||||
"Replace the selected shot with the current view": "用當前視角替換所選鏡頭",
|
||||
"Click a shot to select it, double-click to rename.": "單擊鏡頭即可選中,雙擊可重命名。",
|
||||
"scene|PLAY": "播放",
|
||||
"Stop playback (Esc)": "停止播放(Esc)",
|
||||
"SAVE & SHARE": "保存與分享",
|
||||
"Download every scene as a JSON file you can import later": "將所有場景下載為 JSON 文件,以便日後導入",
|
||||
"Load scenes from an exported JSON file": "從導出的 JSON 文件加載場景",
|
||||
"Download the timing log of the last play": "下載上次播放的計時日誌",
|
||||
"Play from this scene through the rest of the project": "從此場景開始播放項目中的其餘場景",
|
||||
"Play the shot after the selected one, moving on to the next scene when needed": "播放所選鏡頭的下一個鏡頭,必要時進入下一個場景",
|
||||
"Edit anchors, data packs and shot details": "編輯錨點、數據包和鏡頭詳情",
|
||||
"Download this scene as JSON or an asset bundle": "將此場景下載為 JSON 或資源包",
|
||||
"Left panels": "左側面板",
|
||||
"Right panels": "右側面板",
|
||||
"UTILITIES": "工具",
|
||||
"Exit cockpit to fly to a drawing": "請先退出座艙,再飛往繪製位置",
|
||||
"Directions, drawing and your own files": "路線導航、繪製和你自己的文件"
|
||||
}
|
||||
@@ -1,4 +1,38 @@
|
||||
{
|
||||
"ar": [
|
||||
"1090 MHz",
|
||||
"978 MHz UAT",
|
||||
"AIS: --",
|
||||
"AIS: {name}",
|
||||
"BRG {value}°",
|
||||
"BRG —",
|
||||
"CAL {value}",
|
||||
"CAL · {badge}",
|
||||
"CCTV",
|
||||
"CRS {value}°",
|
||||
"CRT",
|
||||
"FLIR",
|
||||
"FOV",
|
||||
"FOV {value}°",
|
||||
"GEO",
|
||||
"GOOGLE STREET VIEW",
|
||||
"Google Street View",
|
||||
"HDG",
|
||||
"HDG {value}°",
|
||||
"Ironbow",
|
||||
"Landsat 8/9",
|
||||
"NVG",
|
||||
"REC",
|
||||
"S2 GhostMaps",
|
||||
"SQUAWK {code} · {status}",
|
||||
"SRC {value}",
|
||||
"Sentinel-2",
|
||||
"WHOT/BHOT",
|
||||
"dB",
|
||||
"hPa",
|
||||
"{source} HTTP {status}",
|
||||
"▲ {frp} MW"
|
||||
],
|
||||
"de": [
|
||||
"1090 MHz",
|
||||
"978 MHz UAT",
|
||||
@@ -94,6 +128,7 @@
|
||||
"Plan",
|
||||
"Pop",
|
||||
"Punk",
|
||||
"RADAR · {units}",
|
||||
"RADIO",
|
||||
"REC",
|
||||
"REGION",
|
||||
@@ -186,6 +221,7 @@
|
||||
"CCTV",
|
||||
"CRS {value}°",
|
||||
"CRT",
|
||||
"Color: {units}",
|
||||
"Country",
|
||||
"DEST ---°",
|
||||
"DEST {bearing}",
|
||||
@@ -237,6 +273,7 @@
|
||||
"Pop",
|
||||
"Punk",
|
||||
"R&B",
|
||||
"RADAR · {units}",
|
||||
"RADIO",
|
||||
"RANGE",
|
||||
"REC",
|
||||
@@ -403,6 +440,7 @@
|
||||
"Plan",
|
||||
"Pop",
|
||||
"Punk",
|
||||
"RADAR · {units}",
|
||||
"RADIO",
|
||||
"REC",
|
||||
"Radio",
|
||||
@@ -566,6 +604,7 @@
|
||||
"PRECIP",
|
||||
"Pop",
|
||||
"Punk",
|
||||
"RADAR · {units}",
|
||||
"RADIO",
|
||||
"REC",
|
||||
"RESET",
|
||||
@@ -769,6 +808,7 @@
|
||||
"Paris",
|
||||
"Pop",
|
||||
"Punk",
|
||||
"RADAR · {units}",
|
||||
"RANGE",
|
||||
"REC",
|
||||
"Reggae",
|
||||
|
||||
@@ -89,17 +89,18 @@ test('radio option text and accessible name use the same localized parentheses',
|
||||
try {
|
||||
for (const [locale, label, expected] of [['zh-CN', '全部', '全部(750)'], ['en', 'All', 'All (750)']]) {
|
||||
setLocale(locale);
|
||||
let shown = null;
|
||||
const host = {
|
||||
_radioPanel: element(), _radioFilter: element(),
|
||||
_radioPanel: element(),
|
||||
store: { publish: (view) => (shown = view), publishTuner() {} },
|
||||
actions: { getLifecycle: () => null, scheduleLayout() {} },
|
||||
};
|
||||
renderRadioState.call(host, {
|
||||
enabled: true, categories: [{ id: 'all', label, count: 750, color: '' }],
|
||||
filter: 'all', filteredCount: 750, stationCount: 750, volume: 1,
|
||||
});
|
||||
const option = host._radioFilter.children[0];
|
||||
assert.equal(option.textContent, `● ${expected}`);
|
||||
assert.equal(option.attributes['aria-label'], expected);
|
||||
// The Radio panel shows it as `● label` and names the option `label`.
|
||||
assert.equal(shown.filter.options[0].label, expected);
|
||||
}
|
||||
} finally {
|
||||
globalThis.document = originalDocument;
|
||||
|
||||
Reference in new issue
Block a user