From 6b3e8bada3b600fae1a2908eff83ffad4614e8f8 Mon Sep 17 00:00:00 2001 From: German Khokhlov Date: Fri, 23 Oct 2026 22:52:48 +0400 Subject: [PATCH 01/11] i18n: add Traditional Chinese (zh-TW) Add a complete Taiwan Traditional Chinese catalog, locale selection, Chinese readout formatting, translation notes and regression coverage. Seed translations from #724 and #652 and adapt the zh-CN catalog. Co-authored-by: caxer Co-authored-by: tbdavid2019 Co-authored-by: Enzo Abyie <93532759+abiyeenzo@users.noreply.github.com> Co-authored-by: EDIT-Aeterna <73235923+EDIT-Aeterna@users.noreply.github.com> --- docs/CURRENT-STATE.md | 6 +- docs/TRANSLATORS.md | 4 +- docs/translations/zh-TW.md | 36 + scripts/package-boundaries.json | 87 +- src/hudLocalityFormat.js | 3 +- src/i18n/firms-live-zh.test.mjs | 10 +- src/i18n/i18n.test.mjs | 10 +- src/i18n/index.js | 3 +- src/i18n/locale.js | 10 +- src/i18n/locales/zh-TW.json | 2817 +++++++++++++++++++++++++++ src/i18n/same-as-english.json | 55 + src/i18n/zh-TW-display.test.mjs | 60 + src/layers/recentImagery/display.js | 4 +- src/ui/cockpitContext.js | 2 +- src/ui/cockpitPresentation.js | 2 +- src/ui/localePicker.test.mjs | 8 +- 16 files changed, 3070 insertions(+), 47 deletions(-) create mode 100644 docs/translations/zh-TW.md create mode 100644 src/i18n/locales/zh-TW.json create mode 100644 src/i18n/zh-TW-display.test.mjs diff --git a/docs/CURRENT-STATE.md b/docs/CURRENT-STATE.md index b10f43f3b..69139e6bb 100644 --- a/docs/CURRENT-STATE.md +++ b/docs/CURRENT-STATE.md @@ -3583,7 +3583,7 @@ test:track` 43 tracking invariants · headless QA harnesses under ### Interface localization (October 2026) -Shipped locales: **en** (source and fallback), **es**, **ru** and **zh-CN**. The code lives in +Shipped locales: **en** (source and fallback), **es**, **ru**, **zh-CN** and **zh-TW**. The code lives in `src/i18n/`. How to mark UI text: [`docs/I18N.md`](./I18N.md); translator workflow: [`docs/TRANSLATORS.md`](./TRANSLATORS.md). @@ -3594,8 +3594,8 @@ Shipped locales: **en** (source and fallback), **es**, **ru** and **zh-CN**. The value). English has no catalog; every other locale is `src/i18n/locales/.json`, and a missing entry falls back to English. - **Locale choice.** `?lang=` → stored choice (`gev:locale:v1`) → - `navigator.languages` → English. Chinese tags map to `zh-CN`; tags containing - `Hant`, `TW`, `HK` or `MO` are skipped. `?lang=` is not stored, and share links drop + `navigator.languages` → English. Chinese tags default to `zh-CN`; `Hant`, `TW`, `HK` and `MO` + select `zh-TW`. Explicit `Hans` selects `zh-CN` regardless of region. `?lang=` is not stored, and share links drop it, so a recipient keeps their own language. The globe picker in the bottom-right corner (`src/ui/localePicker.js`) stores the choice, drops `?lang=` (keeps it only when storage is blocked) and reloads. It asks first diff --git a/docs/TRANSLATORS.md b/docs/TRANSLATORS.md index 538f8c50e..5122afa9f 100644 --- a/docs/TRANSLATORS.md +++ b/docs/TRANSLATORS.md @@ -1,6 +1,6 @@ # Translating God's Eye View -Shipped languages: **English** (source and fallback), **Spanish** (`es`), **Russian** (`ru`) and **Simplified Chinese** (`zh-CN`). +Shipped languages: **English** (source and fallback), **Spanish** (`es`), **Russian** (`ru`), **Simplified Chinese** (`zh-CN`) and **Traditional Chinese** (`zh-TW`). ## How it works @@ -63,4 +63,4 @@ These are contracts, not copy: layer ids and registry keys, status enums and oth ## Language notes -Each language keeps its glossary, plural forms, units and style in its own file, `docs/translations/.md`: [Spanish](./translations/es.md), [Russian](./translations/ru.md), [Simplified Chinese](./translations/zh-CN.md). Read it before translating, and add a term there when you settle on one. +Each language keeps its glossary, plural forms, units and style in its own file, `docs/translations/.md`: [Spanish](./translations/es.md), [Russian](./translations/ru.md), [Simplified Chinese](./translations/zh-CN.md), [Traditional Chinese](./translations/zh-TW.md). Read it before translating, and add a term there when you settle on one. diff --git a/docs/translations/zh-TW.md b/docs/translations/zh-TW.md new file mode 100644 index 000000000..8e25c8540 --- /dev/null +++ b/docs/translations/zh-TW.md @@ -0,0 +1,36 @@ +# Traditional Chinese (`zh-TW`) + +Catalog: `src/i18n/locales/zh-TW.json`. General rules: [TRANSLATORS.md](../TRANSLATORS.md). + +Sources: caxer (#724), tbdavid2019 (#652), and the zh-CN catalog credited to abiyeenzo (#914) and EDIT-Aeterna (#979). The remaining entries were seeded with OpenCC s2twp and edited for Taiwan usage. + +## Style + +- Use Traditional characters and Taiwan terminology. Prefer short, neutral instructions: 「點選地圖」、「儲存金鑰」. +- Use full-width Chinese punctuation and 「」 for quotations. Keep `·`, `…`, provider names, codes and placeholders unchanged. +- Separate Chinese from Latin letters and numbers with a space: 「AIS 船舶」、「24 小時」. Keep unit symbols unchanged: km, m, km/h, m/s, kn, ft, MW, °, %. +- Chinese labels have no uppercase variant. Keep button labels short and avoid splitting short words across lines. +- Browser tags with Hant or TW/HK/MO select this Taiwan catalog. Explicit Hans selects Simplified Chinese, including Hans-TW. This is not a separate Hong Kong localization. + +## Plurals + +`Intl.PluralRules('zh-TW')` uses only `other`. Keep suitable measure words: 「{count} 架飛機」、「{count} 艘船」、「{count} 個金鑰」. + +## Taiwan terminology + +| English | Taiwan | Mainland | +| -------------------- | --------------------- | ------------------- | +| data / information | 資料 / 資訊 | 数据 / 信息 | +| file / folder | 檔案 / 資料夾 | 文件 / 文件夹 | +| settings / save | 設定 / 儲存 | 设置 / 保存 | +| API key / token | API 金鑰 / 權杖 | API 密钥 / 令牌 | +| live / load | 即時 / 載入 | 实时 / 加载 | +| camera / video | 攝影機 / 影片 | 摄像头 / 视频 | +| network / link | 網路 / 連結 | 网络 / 链接 | +| image / imagery | 圖像 / 影像 | 图像 / 影像 | +| click / double-click | 點選 / 按兩下 | 点击 / 双击 | +| response / timeout | 回應 / 逾時 | 响应 / 超时 | +| layer / data layer | 圖層 / 資料圖層 | 图层 / 数据图层 | +| cockpit / context | 駕駛艙 / 態勢 | 座舱 / 态势 | +| air quality | 空氣品質 | 空气质量 | +| transit / bikeshare | 大眾運輸 / 公共自行車 | 公共交通 / 共享单车 | diff --git a/scripts/package-boundaries.json b/scripts/package-boundaries.json index 4a756f656..4f88e858e 100644 --- a/scripts/package-boundaries.json +++ b/scripts/package-boundaries.json @@ -441,7 +441,8 @@ "src/i18n/locale.js", "src/i18n/locales/es.json", "src/i18n/locales/ru.json", - "src/i18n/locales/zh-CN.json" + "src/i18n/locales/zh-CN.json", + "src/i18n/locales/zh-TW.json" ], "external": [] }, @@ -467,7 +468,8 @@ "src/i18n/locale.js", "src/i18n/locales/es.json", "src/i18n/locales/ru.json", - "src/i18n/locales/zh-CN.json" + "src/i18n/locales/zh-CN.json", + "src/i18n/locales/zh-TW.json" ], "external": ["cesium"] }, @@ -484,7 +486,8 @@ "src/i18n/locale.js", "src/i18n/locales/es.json", "src/i18n/locales/ru.json", - "src/i18n/locales/zh-CN.json" + "src/i18n/locales/zh-CN.json", + "src/i18n/locales/zh-TW.json" ], "external": [] }, @@ -514,6 +517,7 @@ "src/i18n/locales/es.json", "src/i18n/locales/ru.json", "src/i18n/locales/zh-CN.json", + "src/i18n/locales/zh-TW.json", "src/ui/unitLabels.js", "src/ui/keyGuidance.js", "src/ui/statusText.js", @@ -534,7 +538,8 @@ "src/i18n/locale.js", "src/i18n/locales/es.json", "src/i18n/locales/ru.json", - "src/i18n/locales/zh-CN.json" + "src/i18n/locales/zh-CN.json", + "src/i18n/locales/zh-TW.json" ], "external": [] }, @@ -550,7 +555,8 @@ "src/i18n/locale.js", "src/i18n/locales/es.json", "src/i18n/locales/ru.json", - "src/i18n/locales/zh-CN.json" + "src/i18n/locales/zh-CN.json", + "src/i18n/locales/zh-TW.json" ], "external": [] }, @@ -570,6 +576,7 @@ "src/i18n/locales/es.json", "src/i18n/locales/ru.json", "src/i18n/locales/zh-CN.json", + "src/i18n/locales/zh-TW.json", "src/ui/unitLabels.js", "src/ui/statusBadge.js" ], @@ -596,6 +603,7 @@ "src/i18n/locales/es.json", "src/i18n/locales/ru.json", "src/i18n/locales/zh-CN.json", + "src/i18n/locales/zh-TW.json", "src/ui/layerNames.js" ], "external": [] @@ -630,6 +638,7 @@ "src/i18n/locales/es.json", "src/i18n/locales/ru.json", "src/i18n/locales/zh-CN.json", + "src/i18n/locales/zh-TW.json", "src/ui/unitLabels.js" ], "external": ["cesium"] @@ -646,6 +655,7 @@ "src/i18n/locales/es.json", "src/i18n/locales/ru.json", "src/i18n/locales/zh-CN.json", + "src/i18n/locales/zh-TW.json", "src/ui/unitLabels.js" ], "external": [] @@ -801,6 +811,7 @@ "src/i18n/locales/es.json", "src/i18n/locales/ru.json", "src/i18n/locales/zh-CN.json", + "src/i18n/locales/zh-TW.json", "src/ui/unitLabels.js", "src/ui/keyGuidance.js", "src/ui/layerNames.js", @@ -921,6 +932,7 @@ "src/i18n/locales/es.json", "src/i18n/locales/ru.json", "src/i18n/locales/zh-CN.json", + "src/i18n/locales/zh-TW.json", "src/ui/unitLabels.js" ], "external": ["cesium"] @@ -987,6 +999,7 @@ "src/i18n/locales/es.json", "src/i18n/locales/ru.json", "src/i18n/locales/zh-CN.json", + "src/i18n/locales/zh-TW.json", "src/ui/unitLabels.js" ], "external": ["cesium"] @@ -1033,7 +1046,8 @@ "src/i18n/locale.js", "src/i18n/locales/es.json", "src/i18n/locales/ru.json", - "src/i18n/locales/zh-CN.json" + "src/i18n/locales/zh-CN.json", + "src/i18n/locales/zh-TW.json" ], "external": ["cesium"] }, @@ -1094,7 +1108,8 @@ "src/i18n/locale.js", "src/i18n/locales/es.json", "src/i18n/locales/ru.json", - "src/i18n/locales/zh-CN.json" + "src/i18n/locales/zh-CN.json", + "src/i18n/locales/zh-TW.json" ], "external": ["cesium"] }, @@ -1124,6 +1139,7 @@ "src/i18n/locales/es.json", "src/i18n/locales/ru.json", "src/i18n/locales/zh-CN.json", + "src/i18n/locales/zh-TW.json", "src/ui/unitLabels.js", "src/layers/recentImagery/display.js" ], @@ -1153,7 +1169,8 @@ "src/i18n/locale.js", "src/i18n/locales/es.json", "src/i18n/locales/ru.json", - "src/i18n/locales/zh-CN.json" + "src/i18n/locales/zh-CN.json", + "src/i18n/locales/zh-TW.json" ], "external": ["cesium"] }, @@ -1185,6 +1202,7 @@ "src/i18n/locales/es.json", "src/i18n/locales/ru.json", "src/i18n/locales/zh-CN.json", + "src/i18n/locales/zh-TW.json", "src/ui/unitLabels.js" ], "external": ["cesium", "satellite.js"] @@ -1217,7 +1235,8 @@ "src/i18n/locale.js", "src/i18n/locales/es.json", "src/i18n/locales/ru.json", - "src/i18n/locales/zh-CN.json" + "src/i18n/locales/zh-CN.json", + "src/i18n/locales/zh-TW.json" ], "external": ["cesium"] }, @@ -1260,6 +1279,7 @@ "src/i18n/locales/es.json", "src/i18n/locales/ru.json", "src/i18n/locales/zh-CN.json", + "src/i18n/locales/zh-TW.json", "src/layers/installations/classLabel.js" ], "external": ["cesium", "@mapbox/vector-tile", "pbf"] @@ -1295,6 +1315,7 @@ "src/i18n/locales/es.json", "src/i18n/locales/ru.json", "src/i18n/locales/zh-CN.json", + "src/i18n/locales/zh-TW.json", "src/ui/unitLabels.js" ], "external": ["cesium"] @@ -1344,7 +1365,8 @@ "src/i18n/locale.js", "src/i18n/locales/es.json", "src/i18n/locales/ru.json", - "src/i18n/locales/zh-CN.json" + "src/i18n/locales/zh-CN.json", + "src/i18n/locales/zh-TW.json" ], "external": ["cesium", "pbf", "@mapbox/vector-tile"] }, @@ -1373,7 +1395,8 @@ "src/i18n/locale.js", "src/i18n/locales/es.json", "src/i18n/locales/ru.json", - "src/i18n/locales/zh-CN.json" + "src/i18n/locales/zh-CN.json", + "src/i18n/locales/zh-TW.json" ], "external": ["cesium"] }, @@ -1421,7 +1444,8 @@ "src/i18n/locale.js", "src/i18n/locales/es.json", "src/i18n/locales/ru.json", - "src/i18n/locales/zh-CN.json" + "src/i18n/locales/zh-CN.json", + "src/i18n/locales/zh-TW.json" ], "external": ["hls.js", "cesium"] }, @@ -1485,6 +1509,7 @@ "src/i18n/locales/es.json", "src/i18n/locales/ru.json", "src/i18n/locales/zh-CN.json", + "src/i18n/locales/zh-TW.json", "src/layers/streetLevel/providers/mapillary/policy.js" ], "external": ["cesium", "pbf", "@mapbox/vector-tile", "mapillary-js"] @@ -1513,7 +1538,8 @@ "src/i18n/locale.js", "src/i18n/locales/es.json", "src/i18n/locales/ru.json", - "src/i18n/locales/zh-CN.json" + "src/i18n/locales/zh-CN.json", + "src/i18n/locales/zh-TW.json" ], "external": ["cesium", "@mapbox/vector-tile", "pbf"] }, @@ -1553,7 +1579,8 @@ "src/i18n/locale.js", "src/i18n/locales/es.json", "src/i18n/locales/ru.json", - "src/i18n/locales/zh-CN.json" + "src/i18n/locales/zh-CN.json", + "src/i18n/locales/zh-TW.json" ], "external": ["cesium"] }, @@ -1575,7 +1602,8 @@ "src/i18n/locale.js", "src/i18n/locales/es.json", "src/i18n/locales/ru.json", - "src/i18n/locales/zh-CN.json" + "src/i18n/locales/zh-CN.json", + "src/i18n/locales/zh-TW.json" ], "external": ["cesium"] }, @@ -1631,7 +1659,8 @@ "src/i18n/locale.js", "src/i18n/locales/es.json", "src/i18n/locales/ru.json", - "src/i18n/locales/zh-CN.json" + "src/i18n/locales/zh-CN.json", + "src/i18n/locales/zh-TW.json" ], "external": ["cesium"] }, @@ -1688,6 +1717,7 @@ "src/i18n/locales/es.json", "src/i18n/locales/ru.json", "src/i18n/locales/zh-CN.json", + "src/i18n/locales/zh-TW.json", "src/ui/statusText.js", "src/voice/providerCommands.js", "src/voice/providerCapabilities.js", @@ -2552,6 +2582,7 @@ "src/i18n/locales/es.json", "src/i18n/locales/ru.json", "src/i18n/locales/zh-CN.json", + "src/i18n/locales/zh-TW.json", "src/ui/unitLabels.js", "src/layers/recentImagery/display.js", "src/ui/keyGuidance.js", @@ -3128,6 +3159,7 @@ "src/i18n/locales/es.json", "src/i18n/locales/ru.json", "src/i18n/locales/zh-CN.json", + "src/i18n/locales/zh-TW.json", "src/ui/unitLabels.js", "src/layers/recentImagery/display.js", "src/layers/installations/classLabel.js", @@ -3235,6 +3267,7 @@ "src/i18n/locales/es.json", "src/i18n/locales/ru.json", "src/i18n/locales/zh-CN.json", + "src/i18n/locales/zh-TW.json", "src/i18n/index.js" ], "external": ["cesium"] @@ -3256,7 +3289,8 @@ "src/i18n/locale.js", "src/i18n/locales/es.json", "src/i18n/locales/ru.json", - "src/i18n/locales/zh-CN.json" + "src/i18n/locales/zh-CN.json", + "src/i18n/locales/zh-TW.json" ], "external": [] }, @@ -3291,7 +3325,8 @@ "src/i18n/locale.js", "src/i18n/locales/es.json", "src/i18n/locales/ru.json", - "src/i18n/locales/zh-CN.json" + "src/i18n/locales/zh-CN.json", + "src/i18n/locales/zh-TW.json" ], "external": ["cesium"] }, @@ -3315,7 +3350,8 @@ "src/i18n/locale.js", "src/i18n/locales/es.json", "src/i18n/locales/ru.json", - "src/i18n/locales/zh-CN.json" + "src/i18n/locales/zh-CN.json", + "src/i18n/locales/zh-TW.json" ], "external": [] }, @@ -3407,6 +3443,7 @@ "src/i18n/locales/es.json", "src/i18n/locales/ru.json", "src/i18n/locales/zh-CN.json", + "src/i18n/locales/zh-TW.json", "src/ui/unitLabels.js" ], "external": ["cesium"] @@ -3462,6 +3499,7 @@ "src/i18n/locales/es.json", "src/i18n/locales/ru.json", "src/i18n/locales/zh-CN.json", + "src/i18n/locales/zh-TW.json", "src/ui/statusText.js", "src/voice/providerCapabilities.js" ], @@ -3715,7 +3753,8 @@ "src/i18n/locale.js", "src/i18n/locales/es.json", "src/i18n/locales/ru.json", - "src/i18n/locales/zh-CN.json" + "src/i18n/locales/zh-CN.json", + "src/i18n/locales/zh-TW.json" ], "external": ["cesium", "egm96-universal", "pbf"] }, @@ -3758,7 +3797,8 @@ "src/i18n/locale.js", "src/i18n/locales/es.json", "src/i18n/locales/ru.json", - "src/i18n/locales/zh-CN.json" + "src/i18n/locales/zh-CN.json", + "src/i18n/locales/zh-TW.json" ], "external": ["cesium", "pbf"] }, @@ -3811,7 +3851,8 @@ "src/i18n/locale.js", "src/i18n/locales/es.json", "src/i18n/locales/ru.json", - "src/i18n/locales/zh-CN.json" + "src/i18n/locales/zh-CN.json", + "src/i18n/locales/zh-TW.json" ], "external": ["cesium"] }, @@ -3828,6 +3869,7 @@ "src/i18n/locales/es.json", "src/i18n/locales/ru.json", "src/i18n/locales/zh-CN.json", + "src/i18n/locales/zh-TW.json", "src/ui/statusText.js", "src/ui/layerNames.js" ], @@ -4021,6 +4063,7 @@ "src/i18n/locales/es.json", "src/i18n/locales/ru.json", "src/i18n/locales/zh-CN.json", + "src/i18n/locales/zh-TW.json", "src/ui/statusText.js", "src/ui/layerNames.js" ], diff --git a/src/hudLocalityFormat.js b/src/hudLocalityFormat.js index b508f8d59..697075a82 100644 --- a/src/hudLocalityFormat.js +++ b/src/hudLocalityFormat.js @@ -16,7 +16,8 @@ export function hudQuantity(value, unit, digits = 0) { maximumFractionDigits: digits, }); const label = unitLabel(unit); - if (getLocale() === 'zh-CN') return label ? `${number} ${label}` : number; + if (getLocale().startsWith('zh-')) + return label ? `${number} ${label}` : number; return `${number}${label.toUpperCase()}`; } diff --git a/src/i18n/firms-live-zh.test.mjs b/src/i18n/firms-live-zh.test.mjs index 649842e7f..9698d5dd6 100644 --- a/src/i18n/firms-live-zh.test.mjs +++ b/src/i18n/firms-live-zh.test.mjs @@ -5,12 +5,12 @@ import { createModel } from '../layers/firms/model.js'; import { createQueries } from '../layers/firms/queries.js'; const cases = [ - [0, '不到 1 分钟前', '<1m ago'], - [120000, '2 分钟前', '2m ago'], - [7200000, '2 小时前', '2h ago'], + [0, '不到 1 分钟前', '<1m ago', '不到 1 分鐘前'], + [120000, '2 分钟前', '2m ago', '2 分鐘前'], + [7200000, '2 小时前', '2h ago', '2 小時前'], ]; -for (const [age, zh, en] of cases) { +for (const [age, zh, en, tw] of cases) { test(`FIRMS live age ${age} ms has one relative-time suffix`, (context) => { const now = 1800000000000; context.mock.method(Date, 'now', () => now); @@ -36,6 +36,8 @@ for (const [age, zh, en] of cases) { assert.equal(methods.getStats().loadingLabel, `LIVE · updated ${en}`); setLocale('zh-CN'); assert.equal(methods.getStats().loadingLabel, `实时 · 更新于 ${zh}`); + setLocale('zh-TW'); + assert.equal(methods.getStats().loadingLabel, `即時 · 更新於 ${tw}`); } finally { setLocale(previousLocale); } diff --git a/src/i18n/i18n.test.mjs b/src/i18n/i18n.test.mjs index 70eaf7e86..87eeed24a 100644 --- a/src/i18n/i18n.test.mjs +++ b/src/i18n/i18n.test.mjs @@ -35,12 +35,16 @@ test('normalizeLocale folds regional variants and rejects unshipped tags', () => assert.equal(normalizeLocale(' RU '), 'ru'); assert.equal(normalizeLocale('en_GB'), 'en'); assert.equal(normalizeLocale('xx'), null); - // Simplified Chinese by default; Traditional tags wait for zh-TW. + // Explicit script tags take precedence over regional defaults. assert.equal(normalizeLocale('zh'), 'zh-CN'); assert.equal(normalizeLocale('zh-CN'), 'zh-CN'); assert.equal(normalizeLocale('zh-Hans-SG'), 'zh-CN'); - assert.equal(normalizeLocale('zh-TW'), null); - assert.equal(normalizeLocale('zh-Hant-HK'), null); + assert.equal(normalizeLocale('zh-TW'), 'zh-TW'); + assert.equal(normalizeLocale('zh-Hant-HK'), 'zh-TW'); + assert.equal(normalizeLocale('zh-Hans-TW'), 'zh-CN'); + assert.equal(normalizeLocale('zh-Hant-CN'), 'zh-TW'); + assert.equal(normalizeLocale('zh_HK'), 'zh-TW'); + assert.equal(normalizeLocale('zh-MO'), 'zh-TW'); assert.equal(normalizeLocale(undefined), null); }); diff --git a/src/i18n/index.js b/src/i18n/index.js index 48b63b2f6..84776e7dd 100644 --- a/src/i18n/index.js +++ b/src/i18n/index.js @@ -19,8 +19,9 @@ import { import es from './locales/es.json' with { type: 'json' }; import ru from './locales/ru.json' with { type: 'json' }; import zhCN from './locales/zh-CN.json' with { type: 'json' }; +import zhTW from './locales/zh-TW.json' with { type: 'json' }; -const CATALOGS = Object.freeze({ es, ru, 'zh-CN': zhCN }); +const CATALOGS = Object.freeze({ es, ru, 'zh-CN': zhCN, 'zh-TW': zhTW }); let currentLocale = DEFAULT_LOCALE; diff --git a/src/i18n/locale.js b/src/i18n/locale.js index fab95e5cc..4efd4f589 100644 --- a/src/i18n/locale.js +++ b/src/i18n/locale.js @@ -8,7 +8,7 @@ export const LOCALE_STORAGE_KEY = 'gev:locale:v1'; export const DEFAULT_LOCALE = 'en'; /** Shipped locales; order does not matter. Adding one: docs/TRANSLATORS.md. */ -export const LOCALES = Object.freeze(['en', 'es', 'ru', 'zh-CN']); +export const LOCALES = Object.freeze(['en', 'es', 'ru', 'zh-CN', 'zh-TW']); /** Each locale named in its own language, for the selector. */ export const LOCALE_NAMES = Object.freeze({ @@ -16,6 +16,7 @@ export const LOCALE_NAMES = Object.freeze({ es: 'Español', ru: 'Русский', 'zh-CN': '简体中文', + 'zh-TW': '繁體中文', }); /** Right-to-left locales. */ @@ -29,11 +30,12 @@ const RTL_LOCALES = Object.freeze([]); export function normalizeLocale(candidate) { if (typeof candidate !== 'string') return null; const [primary, ...rest] = candidate.trim().toLowerCase().split(/[-_]/); - // Traditional Chinese readers are not given Simplified: no zh-TW yet. - if (primary === 'zh') + if (primary === 'zh') { + if (rest.includes('hans')) return 'zh-CN'; return rest.some((part) => ['hant', 'tw', 'hk', 'mo'].includes(part)) - ? null + ? 'zh-TW' : 'zh-CN'; + } return LOCALES.includes(primary) ? primary : null; } diff --git a/src/i18n/locales/zh-TW.json b/src/i18n/locales/zh-TW.json new file mode 100644 index 000000000..6677a9c5d --- /dev/null +++ b/src/i18n/locales/zh-TW.json @@ -0,0 +1,2817 @@ +{ + "Pick a shape, then click the map.": "選擇形狀,然後點選地圖。", + "Enter to place the pin, Esc to cancel.": "按 Enter 放置圖釘,按 Esc 取消。", + "Click where the pin goes.": "點選圖釘的放置位置。", + "Click {count} more points.": { + "other": "再點選 {count} 個點。" + }, + "Those points are in a line — move one off it to enclose an area.": "這些點都在同一條直線上——請移開其中一個點才能圍出區域。", + "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.": "該形狀無法放置。", + "Could not place the shape: {error}": "無法放置形狀:{error}", + "Board cleared.": "畫板已清除。", + "{owner} is using the pointer — close it first.": "{owner} 正在使用指標——請先關閉它。", + "{label} · Detailed outline unavailable": "{label} · 無法取得詳細輪廓", + "Flying to Austin, TX...": "正在飛往德州奧斯汀…", + "Restoring shared view...": "正在還原分享的視角…", + "Configuring viewer...": "正在設定檢視器…", + "Loading Google 3D Tiles...": "正在載入 Google 3D Tiles…", + "Loading the keyless globe...": "正在載入免金鑰地球…", + "Google 3D Tiles unavailable ({detail}). Loading the keyless globe...": "Google 3D Tiles 不可用({detail})。正在載入免金鑰地球…", + "Initializing systems...": "系統初始化中…", + "Space Missions isolates replay data. Exit the mode to enable {layer}.": "太空任務模式會隔離回放資料。退出該模式後才能啟用「{layer}」。", + "Data attribution": "資料來源", + "Data provided by:": "資料提供:", + "Close data attribution": "關閉資料來源", + "Light aircraft": "輕型飛機", + "Glider": "滑翔機", + "Turboprop": "渦槳飛機", + "Airliner": "民航客機", + "Widebody": "寬體機", + "Four-engine jet": "四發噴射機", + "Helicopter": "直升機", + "Fast jet": "噴射戰機", + "Business jet": "公務機", + "Drone": "無人機", + "General emergency": "一般緊急情況", + "Unlawful interference": "非法干擾", + "Radio failure": "無線電失效", + "Downed aircraft": "飛機墜毀", + "Minimum fuel": "最低油量", + "Lifeguard (medical priority)": "救護飛行(醫療優先)", + "Rasuwagadhi witness video": "Rasuwagadhi 目擊影片", + "Bhote Koshi valley footage": "Bhote Koshi 河谷畫面", + "Flood footage": "洪水畫面", + "Compilation and casualty claims": "影片合集與傷亡說法", + "SOURCE GEOCONFIRMED · WORLD-PINNED": "來源位置已核實 · 已在地圖上標註", + "SOURCE CREDITED · LOCATION UNRESOLVED": "來源已署名 · 位置未確定", + "REFERENCE ONLY · CLAIMS UNVERIFIED": "僅供參考 · 說法未核實", + "SOURCE GEOCONFIRMED": "來源位置已核實", + "2021 historical reference versus 2026 post-event imagery; changes are cumulative and include the July 2025 Rasuwagadhi flood. Schematic downstream progression, not modeled arrival time; not an official hazard model.": "2021 年歷史參考影像與 2026 年災後影像對比;變化為累計結果,包含 2025 年 7 月的 Rasuwagadhi 洪水。下游演進為示意,並非模擬的到達時間;也不是官方災害模型。", + "Immediate collapse viewpoint": "近距離崩塌觀察點", + "Collapse viewpoint": "崩塌觀察點", + "Debris-dammed lake": "碎屑堰塞湖", + "Dammed lake": "堰塞湖", + "Second landslide": "第二次滑坡", + "Gyirong border gate": "Gyirong 邊境口岸", + "Border gate": "邊境口岸", + "Timure evidence cluster": "Timure 證據群", + "Mailung / Upper Trishuli bridge": "Mailung / Upper Trishuli 橋", + "Dandagaun viewpoint restaurant": "Dandagaun 觀景餐廳", + "Dandagaun viewpoint": "Dandagaun 觀景點", + "Bidur - Trishuli bridge": "Bidur - Trishuli 橋", + "Bidur bridge": "Bidur 橋", + "Devighat / Taadi Khola Bridge": "Devighat / Taadi Khola 橋", + "Devighat bridge": "Devighat 橋", + "Facebook player API did not initialize.": "Facebook 播放器 API 未能初始化。", + "Facebook player API could not load.": "無法載入 Facebook 播放器 API。", + "Facebook player API timed out.": "Facebook 播放器 API 逾時。", + "X embed API did not initialize.": "X 嵌入 API 未能初始化。", + "X embed could not load.": "無法載入 X 嵌入內容。", + "X embed timed out.": "X 嵌入內容逾時。", + "UNAVAILABLE": "無法使用", + "TIMEOUT": "逾時", + "BLOCKED": "被攔截", + "SOURCE": "來源", + "Facebook embed unavailable. The post may be private, removed, region-restricted, or blocked.": "Facebook 嵌入內容不可用。該貼文可能為私密、已刪除、受地區限制或被攔截。", + "Preloading {provider} media": "正在預載入 {provider} 媒體", + "LOADING X POST…": "正在載入 X 貼文…", + "The X post is unavailable or cannot be embedded.": "該 X 貼文不可用或無法嵌入。", + "X POST · PROVIDER CONTROLS": "X 貼文 · 平台控制元件", + "{reason} OPEN ORIGINAL.": "{reason} 請開啟原始來源。", + "X embed unavailable": "X 嵌入內容不可用。", + "FACEBOOK · PROVIDER CONTROLS": "FACEBOOK · 平台控制元件", + "Facebook embed unavailable": "Facebook 嵌入內容不可用。", + "AUTOPLAY BLOCKED · USE PROVIDER CONTROLS": "自動播放被攔截 · 請使用平台控制元件", + "Embedded {provider} media for {source}": "{source} 的嵌入 {provider} 媒體", + "witness source": "目擊來源", + "Witness source": "目擊來源", + "{provider} · EMBEDDED SOURCE": "{provider} · 嵌入來源", + "OPEN ORIGINAL ↗": "開啟原始來源 ↗", + "{provider} media: {source}": "{provider} 媒體:{source}", + "{provider} · PROVIDER CONTROLS": "{provider} · 平台控制元件", + "YOUTUBE {state} · OPEN ORIGINAL": "YOUTUBE {state} · 開啟原始來源", + "INITIATION": "起始", + "DAMMING": "堰塞", + "SECONDARY FAILURE": "第二次滑坡", + "BORDER ARRIVAL": "抵達邊境", + "PROPAGATION": "演進", + "DOWNSTREAM PASSAGE": "向下游推進", + "CONSEQUENCE": "後果", + "DOWNSTREAM CONSEQUENCE": "下游後果", + "EVIDENCE": "證據", + "{year} HISTORICAL REFERENCE": "{year} 年歷史參考", + "{year} POST-EVENT": "{year} 年災後", + "{count} GEOLOCATED SOURCE-MAP PLACEMENTS": { + "other": "{count} 個地理定位來源點位" + }, + "NO PREVIEW": "無預覽", + "YouTube source": "YouTube 來源", + "Facebook source": "Facebook 來源", + "SOURCE LINK": "來源連結", + "{publisher} / OPEN": "{publisher} / 開啟", + "Bhote Koshi flood reconstruction controls": "Bhote Koshi 洪水重構控制", + "EVENT RECONSTRUCTION · 26 AUG 2026": "事件重構 · 2026-08-26", + "BHOTE KOSHI OUTBURST FLOOD": "BHOTE KOSHI 潰決洪水", + "Close event layer": "關閉事件圖層", + "OBSERVED IMAGERY": "觀測影像", + "SCHEMATIC CORRIDOR": "示意走廊", + "2021 HISTORICAL REFERENCE / 2026 POST-EVENT": "2021 年歷史參考 / 2026 年災後", + "Historical reference and post-event image split": "歷史參考與災後影像的分割", + "RECONSTRUCTION CLOCK": "重構時鐘", + "Schematic downstream progression": "下游演進示意", + "Story beat navigation": "事件節點導航", + "Previous story beat": "上一個事件節點", + "CAUSE": "成因", + "CAPTURE TIME UNVERIFIED": "拍攝時間未核實", + "Next story beat": "下一個事件節點", + "▶ PLAY": "▶ 播放", + "Play the next shot and continue through this scene": "播放下一個鏡頭,繼續播放整個場景", + "▶ PLAY SCENE": "▶ 播放場景", + "◉ CINEMATIC": "◉ 運鏡", + "↺ FULL STORY": "↺ 完整故事", + "↗ OPEN ORIGINAL": "↗ 開啟原始來源", + "⌖ LOWER GORGE": "⌖ 下游峽谷", + "FIELD REPORTS · {count}": "現場報道 · {count}", + "GEOLOCATIONS · {credit}": "地理定位 · {credit}", + "↗ OPEN PUBLIC MAP": "↗ 開啟公共地圖", + " Clouds are preserved from the source imagery.": "雲層按源影像原樣保留。", + "Rasuwagadhi witness": "Rasuwagadhi 目擊者", + "Open original source for {source}; capture time unverified": "開啟 {source} 的原始來源;拍攝時間未核實", + "Historical reference and post-event image divider": "歷史參考與災後影像的分割線", + "A historical reference {before} percent, B post-event {after} percent": "A 歷史參考 {before}%,B 災後 {after}%", + "■ RELEASE CAMERA": "■ 釋放相機", + "Seek Nepal scene clock": "定位尼泊爾場景時鐘", + "NEPAL SCENE CLOCK": "尼泊爾場景時鐘", + "… PLAYING SHOT": "… 鏡頭播放中", + "▶ PLAY SHOT": "▶ 播放鏡頭", + "Ⅱ PAUSE": "Ⅱ 暫停", + "↺ REPLAY CINEMATIC": "↺ 重播運鏡", + "↺ REPLAY": "↺ 重播", + "… PLAYING SCENE": "… 場景播放中", + "Continue {scene} from next shot": "從下一鏡頭繼續播放 {scene}", + "current scene": "目前場景", + "Replay the full reconstruction": "重播完整重構", + "SCENE SHOT": "場景鏡頭", + "TIME UNVERIFIED": "拍攝時間未核實", + "{count} SOURCES": { + "other": "{count} 個來源" + }, + "OUTSIDE IMAGERY SWIPE": "不在影像對比範圍內", + "{scene} / AUTHORED SHOT": "{scene} / 編排鏡頭", + "NEPAL FLOOD INCIDENT": "尼泊爾洪水事件", + "Play {shot}": "播放 {shot}", + "current scene shot": "目前場景鏡頭", + "Play reconstruction": "播放重構", + "Load previous scene shot": "載入上一個場景鏡頭", + "Load next scene shot": "載入下一個場景鏡頭", + "SCHEMATIC CORRIDOR, NOT MODELED ARRIVAL TIME.": "示意走廊,並非模擬的到達時間。", + "Rasuwa · 26 Aug 2026": "Rasuwa · 2026-08-26", + "Event reconstruction": "事件重構", + "BHOTE KOSHI FLOOD INCIDENT": "BHOTE KOSHI 洪水事件", + "NEPAL · 26 AUG 2026": "尼泊爾 · 2026-08-26", + "USGS INITIAL REPORT": "USGS 初始報告", + "26 AUG 2026 · 08:37 NPT": "2026-08-26 · 08:37 NPT", + "28.2710° N · 85.5150° E": "北緯 28.2710° · 東經 85.5150°", + "INITIAL M4.4 · RECLASSIFIED M5.2 LANDSLIDE": "初報 M4.4 · 重新歸類為 M5.2 滑坡", + "USGS EVENT us7000tbwb · OPEN SOURCE": "USGS 事件 us7000tbwb · 開啟來源", + "Open the USGS initial report for the 26 August 2026 Nepal landslide": "開啟 USGS 關於 2026 年 8 月 26 日尼泊爾滑坡的初始報告", + "Show the Nepal context callout without a border or country fill": "顯示尼泊爾背景標註,不繪製邊界和國家填充", + "Introduce Nepal, draw its border, then reveal the Bhote Koshi incident": "介紹尼泊爾,繪製其邊界,再展示 Bhote Koshi 事件", + "CITIES": "城市", + "Keep the regional incident context and introduce nearby city labels": "保留區域事件背景,並加入附近城市標註", + "PLACES": "地點", + "Introduce the reconstruction scene key places from trigger to downstream": "依次介紹重構場景的關鍵地點,從觸發點到下游", + "PATH": "路徑", + "Animate the sourced cyan river-centerline route to Trishuli Bazaar": "以動畫展示有來源依據的青色河道中線路徑,直至 Trishuli Bazaar", + "OVERVIEW": "總覽", + "Keep the completed flood path and location labels visible": "保持完整的洪水路徑和地點標註可見", + "RECORD": "記錄", + "Reveal the trigger record while making a slow camera approach": "鏡頭緩慢推近,同時展示觸發事件記錄", + "{speed} kn": "{speed} kn", + "That file is not valid JSON.": "該檔案不是有效的 JSON。", + "That JSON file is not GeoJSON.": "該 JSON 檔案不是 GeoJSON。", + "That FeatureCollection has no features list.": "該 FeatureCollection 沒有 features 清單。", + "Every GeoJSON feature must have type Feature.": "每個 GeoJSON 要素的型別都必須是 Feature。", + "That GeoJSON has invalid geometries.": "該 GeoJSON 包含無效的幾何圖形。", + "That GeoJSON contains an unsupported geometry.": "該 GeoJSON 包含不受支援的幾何圖形。", + "That GeoJSON has invalid coordinates.": "該 GeoJSON 包含無效座標。", + "That file creates more than {limit} map objects (the limit).": "該檔案生成的地圖物件超過上限 {limit} 個。", + "That file has more than {limit} style definitions and image links after cleanup (the limit).": "清理後,該檔案的樣式定義和圖像連結仍超過上限 {limit} 個。", + "That file has more than {limit} features (the limit).": "該檔案的要素超過上限 {limit} 個。", + "That file has more than {limit} points (the limit) across {features} features.": "該檔案的點數超過上限 {limit} 個(共 {features} 個要素)。", + "That file has more than {limit} points (the limit).": "該檔案的點數超過上限 {limit} 個。", + "That KMZ unpacks to more than the import limit.": "該 KMZ 解壓後超過匯入上限。", + "That KMZ is damaged and could not be unpacked.": "該 KMZ 已損壞,無法解壓。", + "That KMZ is not a readable zip archive.": "該 KMZ 不是可讀取的 zip 壓縮包。", + "That KMZ uses a zip format this import does not read.": "該 KMZ 使用的 zip 格式無法匯入。", + "That KMZ is encrypted.": "該 KMZ 已加密。", + "That KMZ uses a compression method this import does not read.": "該 KMZ 使用的壓縮方式無法匯入。", + "That KML has invalid geometry bounds.": "該 KML 的幾何範圍無效。", + "That KML has invalid coordinates.": "該 KML 包含無效座標。", + "That GPX file has no document.": "該 GPX 檔案沒有 文件。", + "That {format} file is not valid XML.": "該 {format} 檔案不是有效的 XML。", + "That file has an unreadable image or exceeds the 16-megapixel image limit.": "該檔案包含無法讀取的圖像,或圖像超過 1600 萬像素上限。", + "That KML could not be read.": "無法讀取該 KML。", + "That file has invalid point coordinates.": "該檔案的點座標無效。", + "Ground heights are not available for that file. Try again when the map has loaded.": "無法取得該檔案的地面高度。請在地圖載入完成後重試。", + "That file took too long to read.": "讀取該檔案耗時過長。", + "Nothing to import.": "沒有可匯入的內容。", + "That file is larger than {size} MiB.": "該檔案大於 {size} MiB。", + "Only GeoJSON, KML, KMZ and GPX files can be imported.": "只能匯入 GeoJSON、KML、KMZ 和 GPX 檔案。", + "That file has nothing to draw.": "該檔案沒有可在地圖上繪製的內容。", + "That KMZ holds no KML document.": "該 KMZ 中沒有 KML 文件。", + "That {format} file could not be read.": "無法讀取該 {format} 檔案。", + "That file has {count} map objects; the limit is {limit}.": "該檔案有 {count} 個地圖物件,上限為 {limit} 個。", + "Ground heights could not be read. Try that file again.": "無法讀取地面高度。請重新匯入該檔案。", + "That file has invalid point graphics.": "該檔案的點樣式無效。", + "Overpass rate-limited": "Overpass 已被限流", + "Overpass timed out": "Overpass 逾時", + "Overpass could not complete the query": "Overpass 無法完成查詢", + "Map tiles temporarily unavailable": "地圖瓦片暫時不可用", + "Mapped names temporarily unavailable": "地點名稱暫時不可用", + "Overpass temporarily unavailable": "Overpass 暫時不可用", + "Retrying mapped sites…": "正在重試載入地圖標註設施…", + "Fetching mapped sites…": "正在取得地圖標註設施…", + "{reason} — retrying in {seconds}s": "{reason}——{seconds} 秒後重試", + "{reason} — retry pending": "{reason}——等待重試", + "Zoom in to search mapped installations": "請放大地圖以搜尋地圖標註的設施", + "Showing cached mapped sites": "正在顯示快取的地圖標註設施", + "Mapped sites not loaded": "地圖標註設施未載入", + "Mapped sites loaded": "已載入地圖標註設施", + "Military airfield": "軍用機場", + "Naval base": "海軍基地", + "Firing range": "靶場", + "Military land": "軍事用地", + "Mapped installation": "地圖標註設施", + "Military area": "軍事區域", + "flight": "航班", + "military flight": "軍用航班", + "satellite": "衛星", + "feed unavailable": "資料來源不可用", + "feed stale": "資料來源過期", + "observed or mapped nearby context": "附近的觀測或地圖標註態勢", + "no observed or mapped objects in current feeds": "目前資料來源中沒有觀測或地圖標註的物件", + "Draw": "繪製", + "Directions": "路線規劃", + "Recent imagery": "近期影像", + "STATION": "太空站", + "Crewed stations and their visiting vehicles": "載人太空站與來訪載具", + "NAV": "導航", + "GNSS navigation — GPS, GLONASS, Galileo": "GNSS 導航衛星 — GPS、GLONASS、Galileo", + "GEO": "GEO", + "Geostationary belt — comms and weather, fixed over the equator": "地球同步軌道帶 — 通訊與氣象衛星,固定於赤道上空", + "VISUAL": "目視可見", + "Brightest naked-eye objects — CelesTrak visual group": "肉眼最亮天體 — CelesTrak 目視群組", + "COMMS": "通訊", + "Broadband constellation shell — shown only in DENSE mode": "寬頻星座殼層——僅在「密集」模式下顯示", + "FISHING": "漁船", + "TOWING": "拖帶", + "DREDGER": "挖泥船", + "DIVE OPS": "潛水作業", + "MILITARY": "軍用", + "SAILING": "帆船", + "PLEASURE": "遊艇", + "PILOT": "引航", + "SAR": "搜救", + "TUG": "拖輪", + "PORT TENDER": "港口供應船", + "ANTI-POLLUTION": "防汙染", + "LAW ENFORCE": "執法", + "MEDICAL": "醫療", + "HIGH-SPEED": "高速", + "PASSENGER": "客船", + "CARGO": "貨船", + "TANKER": "油輪", + "OTHER": "其他", + "Included in bundle": "已包含在資源包中", + "Missing bundle file — reimport its bundle": "缺少資源包檔案——請重新匯入其資源包", + "Source configured; file checked when loaded": "資料來源已配置;檔案在載入時校驗", + "Source unavailable": "資料來源不可用", + "ENVIRONMENTAL": "環境", + "EARTH WATCH": "地球監測", + "ACTIVE EVENTS": "進行中事件", + "Starting live contacts…": "正在接入即時目標…", + "Opening space missions…": "正在開啟太空任務…", + "Scanning active events…": "正在掃描活躍事件…", + "Live earthquakes and active fires, from USGS and NASA": "來自 USGS 與 NASA 的即時地震與野火", + "It feels like a forbidden cockpit—then you realize the sources are public and the data is real.": "像是闖進了禁區駕駛艙——接著你才發現,所有來源都是公開的,資料也都是真的。", + "Working…": "處理中…", + "Could not open that mission{detail}. Retry or explore manually.": "無法開啟該任務{detail}。請重試或手動探索。", + "This browser is blocking storage, so that could not be saved.": "此瀏覽器阻止了儲存,因此無法儲存。", + "NORMAL": "一般", + "CRT": "CRT", + "NVG": "NVG", + "FLIR": "FLIR", + "ANIME": "動漫", + "NOIR": "黑白", + "SNOW": "雪景", + "ARCTIC": "北極", + "ANTARCTIC": "南極", + "NORTH AMERICA": "北美洲", + "SOUTH AMERICA": "南美洲", + "EUROPE": "歐洲", + "AFRICA": "非洲", + "ASIA": "亞洲", + "OCEANIA": "大洋洲", + "NORTHERN OCEANIC GRID": "北方海洋網格", + "SOUTHERN OCEANIC GRID": "南方海洋網格", + "LOADING": "載入中", + "DEGRADED": "效能受限", + "STALE": "資料過期", + "PARTIAL": "部分可用", + "FALLBACK": "備用模式", + "{state} {layers}": "{state} {layers}", + "view band|STREET": "街道", + "view band|CITY": "城市", + "view band|METRO": "都市圈", + "view band|REGIONAL": "區域", + "view band|GLOBAL": "全球", + "SUMMARY": "摘要", + "Awaiting telemetry...": "等待遙測資料…", + "REC": "REC", + "AIS: --": "AIS: --", + "N/A": "無", + "{mode} {band} {locality} | {region} | ALT {alt} | WINDOW {window} | SUN {sun}° | ONA {ona}° | {zone}": "{mode} {band} {locality} | {region} | ALT {alt} | 視窗 {window} | SUN {sun}° | ONA {ona}° | {zone}", + "NEAR {poi} ({city}) {distance}": "{poi}({city})附近 {distance}", + "SECTOR {lat} {lon}": "扇區 {lat} {lon}", + "N": "北", + "S": "南", + "E": "東", + "W": "西", + "POWER UP · {count} KEYS WAITING": { + "other": "增強 · {count} 個金鑰待配置" + }, + "POWERED UP": "已全面強化", + "Provider Settings does not answer proxied requests": "服務供應商設定不回應經代理的請求", + "Provider Settings is disabled while sharing is enabled": "啟用分享時,服務供應商設定不可用", + "Provider Settings answers only the machine running the server": "服務供應商設定僅回應執行伺服器的那臺機器", + "Provider Settings answers only local hostnames": "服務供應商設定只回應本機主機名", + "Provider Settings requires an exact local Origin": "服務供應商設定要求完全匹配的本機 Origin", + "Unrecognized Origin refused": "已拒絕無法識別的 Origin", + "Cross-origin requests are refused": "拒絕跨源請求", + "Content-Type must be application/json": "Content-Type 必須為 application/json", + "Method not allowed": "不允許的方法", + "Request too large": "請求過大", + "Invalid JSON": "無效的 JSON", + "Body must be a JSON object of {ENV_VAR: value}": "請求體必須是 {ENV_VAR: value} 形式的 JSON 物件", + "No keys provided": "未提供金鑰", + "At most {limit} keys per save": "每次最多儲存 {limit} 個金鑰", + "Unknown key: {name}": "未知金鑰:{name}", + "{name} must be a string": "{name} 必須是字串", + "{name} is empty": "{name} 為空", + "{name} is longer than any real key ({limit} max)": "{name} 比任何真實金鑰都長(最多 {limit} 個字元)", + "{name} may only contain printable characters with no spaces": "{name} 只能包含可列印字元,且不能有空格", + "{name} contains a character that is not valid in a key (#, quotes, $, \\, or backtick)": "{name} 包含金鑰中不允許的字元(#、引號、$、\\ 或反引號)", + "{name} is configured outside Provider Settings and can only be changed where it was set": "{name} 是在服務供應商設定之外配置的,只能在原設定處修改", + "The key was not saved: could not restrict the credential file to your account; nothing was saved": "金鑰未儲存:無法將憑據檔案限制為僅你的賬戶可訪問;未儲存任何內容", + "The key was not saved: the existing configuration could not be read, so nothing was changed": "金鑰未儲存:無法讀取現有配置,因此未做任何更改", + "Could not write the {store} store": "無法寫入 {store} 儲存", + "Save failed ({status}).": "儲存失敗({status})。", + "OAuth check failed: {detail}": "OAuth 檢查失敗:{detail}", + "Could not check ChatGPT sign-in. Try again.": "無法檢查 ChatGPT 登入狀態,請重試。", + "VOICE AUTH · CHATGPT OAUTH": "語音認證 · CHATGPT OAUTH", + "VOICE AUTH · API KEY": "語音認證 · API 金鑰", + "USE API KEY": "使用 API 金鑰", + "USE CHATGPT OAUTH": "使用 CHATGPT OAUTH", + "Use OPENAI_API_KEY for the next cloud voice session": "下次雲語音工作階段使用 OPENAI_API_KEY", + "Use the signed-in local ChatGPT/Codex OAuth session for the next cloud voice session": "下次雲語音工作階段使用本機已登入的 ChatGPT/Codex OAuth 工作階段", + "Metered — a billing-enabled account": "計費 — 需啟用帳單的帳戶", + "Optional paid token — public access works without one": "可選的付費權杖——無需權杖也可公開訪問", + "Free key — register, paste, done": "免費金鑰 — 註冊、貼上、完成", + "browser-side": "瀏覽器端", + "This key runs in the browser by design — restrict it at the provider (see SECURITY.md)": "此金鑰設計上在瀏覽器執行 — 請在供應商端設定限制(見 SECURITY.md)", + "configured externally": "已在外部設定", + "Supplied by your environment, Keychain, or launcher — change it where it was set": "由你的環境、鑰匙串或啟動器提供——請在原設定處修改", + "MANAGE ↗": "管理 ↗", + "GET KEY ↗": "取得金鑰 ↗", + "{envVar} saved — paste to replace": "{envVar} 已儲存——貼上可替換", + "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", + "Saving…": "正在儲存…", + "Save failed: {detail}": "儲存失敗:{detail}", + "Paste at least one key first.": "請先貼上至少一個金鑰。", + "Saved to {store}. Restarting — this page reloads itself.": "已儲存到 {store}。正在重啟——本頁面將自動重新載入。", + "Cloud voice will use OPENAI_API_KEY on the next session.": "雲語音將在下次工作階段使用 OPENAI_API_KEY。", + "Checking local ChatGPT OAuth sign-in…": "正在檢查本機 ChatGPT OAuth 登入…", + "Could not check ChatGPT sign-in.": "無法檢查 ChatGPT 登入狀態。", + "ChatGPT OAuth selected for cloud voice. Your API key stays saved and available.": "已為雲語音選擇 ChatGPT OAuth。你的 API 金鑰仍會保留並可用。", + "ChatGPT sign-in expired. Opening sign-in again…": "ChatGPT 登入已過期。正在重新開啟登入…", + "Opening ChatGPT sign-in in your browser…": "正在瀏覽器中開啟 ChatGPT 登入…", + "Could not start ChatGPT sign-in on this machine.": "無法在本機啟動 ChatGPT 登入。", + "Finish ChatGPT sign-in in the browser. Waiting for it to complete…": "請在瀏覽器中完成 ChatGPT 登入,正在等待其完成…", + "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。", + "Remove this key from your saved configuration?": "要從已儲存的配置中移除此金鑰嗎?", + "Removed from {store}. Restarting — this page reloads itself.": "已從 {store} 中移除。正在重啟——本頁面將自動重新載入。", + "The photorealistic 3D planet, place search + Street View": "照片級逼真 3D 地球、地點搜尋 + 街景", + "Places context + Street View fallback; optional separate key": "地點資訊 + 街景備援;可選用獨立金鑰", + "Voice control — API key or ChatGPT OAuth": "語音控制——API 金鑰或 ChatGPT OAuth", + "Live ships, worldwide": "全球即時船舶", + "Live active-fire detections": "即時野火偵測", + "Real live traffic (keyless runs a simulation)": "真實即時路況(無金鑰時為模擬)", + "Bing imagery map stacks + world terrain": "Bing 影像圖層 + 全球地形", + "More flight-polling credits (anonymous works without)": "更多航班查詢額度(匿名也可使用)", + "Street-level imagery and coverage in the Street Level layer. Free: register an app in the Mapillary developer dashboard and paste its Client Token": "街景影像與街景圖層中的覆蓋範圍。免費:在 Mapillary 開發者控制檯註冊一個應用,並貼上其 Client Token", + "Public space-missions access needs no key. Leave blank for standard use; paid tokens only raise request limits.": "公開的太空任務資料無需金鑰。常規使用請留空;付費權杖只會提高請求上限。", + "Air quality request failed": "空氣品質請求失敗", + "No readings available": "暫無讀數", + "No current readings": "暫無最新讀數", + "{count} stations reporting": { + "other": "{count} 個站點上報資料" + }, + "Highest air-quality readings in view": "視野內空氣品質讀數最高的站點", + "Low": "低", + "Low health risk": "低健康風險", + "Moderate": "中等", + "Moderate health risk": "中等健康風險", + "High": "高", + "High health risk": "高健康風險", + "Very High": "極高", + "Very High health risk": "極高健康風險", + "Air quality": "空氣品質", + "Canada only · ECCC AQHI network": "僅限加拿大 · ECCC AQHI 站網", + "ECCC request timed out": "ECCC 請求逾時", + "Malformed AQHI station response": "AQHI 站點回應格式錯誤", + "No AQHI stations available": "沒有可用的 AQHI 站點", + "Malformed AQHI observation response": "AQHI 觀測回應格式錯誤", + "Camera source temporarily unavailable": "攝影機資料來源暫時不可用", + "Mapped camera locations": "地圖標註的攝影機位置", + "SHOW NEAREST": "顯示最近", + "Stop following the current object before navigating to a camera": "請先停止追蹤目前目標,再前往攝影機", + "Move to the nearest loaded camera and show its details": "前往最近已載入的攝影機並顯示詳情", + "Camera badges": "攝影機標章", + "Cyan cameras turn coral when selected. Wedges illustrate mapped direction, not measured coverage. Nearby cameras may be outside the screen.": "選中後青色攝影機變為珊瑚色。扇形僅示意已標繪方向,並非實測覆蓋範圍。附近的攝影機可能不在螢幕內。", + "{count} nearby · {onScreen} on screen": { + "other": "附近 {count} 個 · 螢幕上 {onScreen} 個" + }, + "{count} nearby": { + "other": "附近 {count} 個" + }, + "retrying mapped ALPR cameras": "正在重試載入地圖標註的 ALPR 攝影機", + "loading mapped ALPR cameras": "正在載入地圖標註的 ALPR 攝影機", + "No ALPR data for this area — US and Canada only": "此區域沒有 ALPR 資料——僅覆蓋美國和加拿大", + "Zoom in to load mapped cameras": "放大以載入地圖標註的攝影機", + "Showing cached locations": "目前顯示的是快取位置", + "Coverage limited — zoom in": "覆蓋受限——請放大", + "No ALPR data for this area": "此區域沒有 ALPR 資料", + "None on screen — nearby cameras are outside the view": "螢幕上沒有攝影機——附近的攝影機在視野之外", + "ALPR camera": "車牌辨識攝影機", + "Camera coverage unavailable": "攝影機覆蓋範圍不可用", + "OpenStreetMap · community mapped": "OpenStreetMap · 社群標註", + "Overpass returned an incomplete camera response": "Overpass 返回的攝影機資料不完整", + "At least {count}": "至少 {count}", + "CONTEXT READY": "態勢就緒", + "GLOBAL CONTEXT OFF": "全域態勢已關閉", + "SELECT A FLIGHT, VESSEL, OR MAPPED INSTALLATION": "選擇航班、船舶或地圖標註設施", + "ENABLE TO LOAD OBSERVED / MAPPED PROXIMITY": "啟用以載入觀測 / 地圖標註的鄰近資訊", + "Unavailable": "不可用", + "Focus {label}": "聚焦 {label}", + "Global Context navigation": "全域態勢導航", + "Previous — prior visited contact in the 250 km window": "上一個 — 250 公里範圍內先前造訪的目標", + "PREVIOUS": "上一個", + "FOCUS": "聚焦", + "Next — nearest unvisited contact in the 250 km window": "下一個 — 250 公里範圍內最近的未造訪目標", + "NEXT": "下一個", + "Named areas ({n})": "已命名區域({n})", + "{distance} FLIGHT / VESSEL WINDOW": "{distance} 航班 / 船舶監視視窗", + "Open-source mapped/observed context. Missing broadcasts, unloaded map areas, or unmapped sites are not evidence of absence.": "開源的地圖標註/觀測態勢資訊。缺失的廣播、未載入的地圖區域或未標註的設施不能作為不存在的證據。", + "mapped matches within {km} km of the subject": "所選物件 {km} km 內的地圖標註匹配", + "none mapped within {km} km; not a complete 250 km survey": "{km} km 內無地圖標註;並非完整的 250 km 普查", + "mapped matches from the loaded viewport": "來自已載入視口的地圖標註匹配", + "viewport feed is not a complete 250 km survey": "視口資料來源並非完整的 250 km 普查", + "HDG {value}°": "HDG {value}°", + "BRG {value}°": "BRG {value}°", + "BRG —": "BRG —", + "CRS {value}°": "CRS {value}°", + "CURRENT VIEWPORT ONLY": "僅限目前視口", + "WITHIN {km} KM": "{km} km 以內", + "Flights": "航班", + "Military flights": "軍機", + "AIS vessels": "AIS 船舶", + "Mapped installations": "已標記軍事設施", + "syncing {count} city feeds...": "正在同步 {count} 個城市資料來源…", + "scanning nearby systems...": "正在掃描附近系統…", + "GBFS fetch error": "GBFS 取得錯誤", + "Station {id}": "站點 {id}", + "Station": "站點", + "🚲 {bikes} avail · {docks} docks · {capacity} cap": "🚲 可用 {bikes} · 車樁 {docks} · 容量 {capacity}", + "⚠️ Not installed": "⚠️ 未安裝", + "⚠️ Not renting": "⚠️ 暫停租車", + "⚠️ Not returning": "⚠️ 暫停還車", + "HDG {value}° (ESTIMATED)": "HDG {value}°(估算)", + "{count} CAMERAS STANDING BY · NO CAMERA SELECTED · CLICK A CAMERA TO ACTIVATE": "{count} 個攝影機待命 · 未選擇攝影機 · 點選攝影機以啟用", + "No cameras available in catalog.": "目錄中沒有可用的攝影機。", + "{city} CCTV": "{city} CCTV", + "FOV {value}° (DATASHEET)": "FOV {value}°(規格書)", + "FOV {value}°": "FOV {value}°", + "SPEC FOV {span}° (CAPABILITY)": "規格 FOV {span}°(可調範圍)", + "COVERAGE {value}km²": "覆蓋 {value}km²", + "OVERLAP {count} cams": "重疊 {count} 個攝影機", + "ISOLATED VIEW": "獨立視角", + "PROJ MONITOR": "投影:監視器", + "PROJ OFF": "投影:關", + "VIEWSHED": "可視域", + "CAL {value}": "CAL {value}", + "SRC {value}": "SRC {value}", + "{value} CONTEXT": "{value} 態勢", + "{spec} · SPECS: CCTV-DATABASE.COM": "{spec} · 規格:CCTV-DATABASE.COM", + "Atlantic and eastern/central North Pacific; not worldwide cyclone coverage.": "僅覆蓋大西洋及北太平洋東部和中部,並非全球氣旋覆蓋。", + "Cyclone advisories unavailable": "氣旋公告不可用", + "Cyclone data unavailable": "氣旋資料不可用", + "Potential tropical cyclone": "潛在熱帶氣旋", + "Hurricane": "颶風", + "Tropical storm": "熱帶風暴", + "Tropical depression": "熱帶低壓", + "Subtropical storm": "亞熱帶風暴", + "Subtropical depression": "亞熱帶低壓", + "Track and cone match this advisory": "路徑和預報不確定範圍與本期公告一致", + "Track/cone awaiting advisory {number}": "路徑/預報不確定範圍等待第 {number} 號公告", + "Track/cone unavailable": "路徑/預報不確定範圍不可用", + "Cached advisory · stale source": "快取公告 · 資料來源已過期", + "Loading advisories…": "正在載入公告…", + "{count} active storms": { + "other": "{count} 個活躍氣旋" + }, + "Position as of {time}": "位置(截至 {time})", + "Maximum sustained wind: {wind} · Pressure: {pressure}": "最大持續風速:{wind} · 氣壓:{pressure}", + "{name} · {classification} · Advisory {number} · issued {time}": "{name} · {classification} · 第 {number} 號公告 · 釋出於 {time}", + "No active NHC/CPHC systems": "目前沒有活躍的 NHC/CPHC 氣旋", + "Advisories unavailable": "公告不可用", + "Cyclones · NHC / CPHC": "氣旋 · NHC / CPHC", + "Atlantic · E/C Pacific": "大西洋 · 東/中太平洋", + "{storms} · {name} selected": "{storms} · 已選擇 {name}", + "Official advisory ↗": "官方公告 ↗", + "Active NHC and CPHC cyclone advisories": "活躍的 NHC 與 CPHC 氣旋公告", + "Wind unavailable": "風場資料不可用", + "Advisory center / forecast track": "公告中的氣旋中心 / 預報路徑", + "Center-track uncertainty cone": "中心路徑預報不確定範圍", + "Select a storm on the map, or choose a storm in the list to select it and move the camera. Click empty map space to clear the selection. NOAA NHC/CPHC advisory context. The cone describes forecast center-track uncertainty, not storm size or the full hazard area. Forecast point labels are source lead hours, not times computed from advisory issuance. Geometry follows the surface; height is not weather altitude. Consult the official advisory.": "在地圖上點選氣旋,或在清單中點選氣旋,即可選中並移動相機。點選空白地圖區域可清除選擇。內容來自 NOAA NHC/CPHC 公告。該區域表示氣旋中心路徑預報的不確定範圍,不代表氣旋大小或全部災害影響範圍。預報點標註的是資料來源的預報時效(小時),不是按公告發布時刻推算的時間。幾何圖形貼地顯示;顯示高度並非氣象高度。請以官方公告為準。", + "DRIVE": "駕車", + "Drive": "駕車", + "WALK": "步行", + "Walk": "步行", + "BIKE": "騎行", + "Bike": "騎行", + "rate limited": "已被限流", + "routing service is rate limited": "路線服務已被限流", + "route leg too long": "路段過長", + "route too long": "路線過長", + "{error} — try again in a moment": "{error}——請稍後重試", + "Routing is rate limited — try again in a moment": "路線請求過於頻繁——請稍後重試", + "Routing unavailable (HTTP {status})": "路線規劃不可用(HTTP {status})", + "Routing unavailable": "路線規劃不可用", + "direction|left": "向左", + "direction|right": "向右", + "direction|slightly left": "向左前方", + "direction|slightly right": "向右前方", + "direction|sharply left": "向左後方", + "direction|sharply right": "向右後方", + "direction|straight": "向前", + "direction|around": "向後", + "fork direction|left": "靠左行駛", + "fork direction|right": "靠右行駛", + "fork direction|slightly left": "稍靠左行駛", + "fork direction|slightly right": "稍靠右行駛", + "fork direction|sharply left": "向左後方行駛", + "fork direction|sharply right": "向右後方行駛", + "fork direction|straight": "直行", + "lane direction|left": "左轉", + "lane direction|right": "右轉", + "lane direction|slightly left": "稍左轉", + "lane direction|slightly right": "稍右轉", + "lane direction|sharply left": "急左轉", + "lane direction|sharply right": "急右轉", + "lane direction|straight": "直行", + "ordinal|{number}st": "第 {number} 個", + "ordinal|{number}nd": "第 {number} 個", + "ordinal|{number}rd": "第 {number} 個", + "ordinal|{number}th": "第 {number} 個", + "Head out on {road}": "沿 {road} 出發", + "Head out": "出發", + "Arrive at your destination, on the left": "到達目的地,位於左側", + "Arrive at your destination, on the right": "到達目的地,位於右側", + "Arrive at your destination": "到達目的地", + "Make a U-turn onto {road}": "掉頭進入 {road}", + "Make a U-turn": "掉頭", + "Continue straight onto {road}": "直行進入 {road}", + "Continue straight": "繼續直行", + "Turn {direction} onto {road}": "{direction}轉,進入 {road}", + "Turn {direction}": "{direction}轉", + "Turn onto {road}": "轉彎進入 {road}", + "maneuver|Turn": "轉彎", + "Continue {direction} onto {road}": "繼續{direction}行駛,進入 {road}", + "Continue {direction}": "繼續{direction}行駛", + "At the end of the road, turn {direction} onto {road}": "在道路盡頭{direction}轉,進入 {road}", + "At the end of the road, turn {direction}": "在道路盡頭{direction}轉", + "At the end of the road, continue onto {road}": "在道路盡頭繼續行駛,進入 {road}", + "At the end of the road, continue": "在道路盡頭繼續行駛", + "Keep {direction} at the fork onto {road}": "在岔路口{direction},進入 {road}", + "Keep {direction} at the fork": "在岔路口{direction}", + "Continue at the fork onto {road}": "在岔路口繼續行駛,進入 {road}", + "Continue at the fork": "在岔路口繼續行駛", + "Merge {direction} onto {road}": "{direction}並道,進入 {road}", + "Merge {direction}": "{direction}並道", + "Merge onto {road}": "併入 {road}", + "maneuver|Merge": "並道", + "Take the ramp on the {direction} onto {road}": "{direction}駛入匝道,進入 {road}", + "Take the ramp on the {direction}": "{direction}駛入匝道", + "Take the ramp onto {road}": "駛入匝道,進入 {road}", + "Take the ramp": "駛入匝道", + "Take the exit on the {direction} onto {road}": "從出口{direction}駛出,進入 {road}", + "Take the exit on the {direction}": "從出口{direction}駛出", + "Take the exit onto {road}": "從出口駛出,進入 {road}", + "Take the exit": "從出口駛出", + "At the roundabout, take the {exit} exit onto {road}": "在環島從{exit}出口駛出,進入 {road}", + "At the roundabout, take the {exit} exit": "在環島從{exit}出口駛出", + "Enter the roundabout onto {road}": "駛入環島,進入 {road}", + "Enter the roundabout": "駛入環島", + "At the roundabout, turn {direction} onto {road}": "在環島{direction}轉,進入 {road}", + "At the roundabout, turn {direction}": "在環島{direction}轉", + "At the roundabout, continue onto {road}": "在環島繼續行駛,進入 {road}", + "At the roundabout, continue": "在環島繼續行駛", + "Exit the roundabout onto {road}": "駛出環島,進入 {road}", + "Exit the roundabout": "駛出環島", + "Use the {direction} lane onto {road}": "使用{direction}車道,進入 {road}", + "Use the {direction} lane": "使用{direction}車道", + "Continue onto {road}": "繼續行駛,進入 {road}", + "maneuver|Continue": "繼續行駛", + "{mode} — reroute for {modeLower}": "{mode}——按{modeLower}重新規劃路線", + "CLICK MAP": "點選地圖", + "SET A": "設定 A", + "Click a spot on the globe to place A (click again to cancel)": "點選地球上的位置放置 A(再次點選取消)", + "Then click the globe to place the start": "然後點選地球放置起點", + "SET B": "設定 B", + "Click a spot on the globe to place B (click again to cancel)": "點選地球上的位置放置 B(再次點選取消)", + "Then click the globe to place the destination": "然後點選地球放置終點", + "Swap A and B": "交換 A 與 B", + "FLY ···": "飛行 ···", + "FLYING": "飛行中", + "FLY": "飛行", + "Fly the camera along the route": "讓相機沿路線飛行", + "Place A and B first": "請先放置 A 和 B", + "action|CLEAR": "清除", + "Remove the route and both markers": "移除路線與兩端標記", + "press Escape twice to leave Draw": "按兩次 Escape 退出「繪製」", + "{name} is active — turn {name} off, then set {endpoint}": "{name} 正在使用——請先關閉 {name},再設定 {endpoint}", + "{name} is active — {leave}, then set {endpoint}": "{name} 正在使用——請先{leave},再設定 {endpoint}", + "Only the first {count} turns of this route are shown": "此路線僅顯示前 {count} 個轉向", + "Turn-by-turn directions": "逐步導航", + "Another map tool is using clicks — close it, then SET A again": "另一個地圖工具正在攔截點選——請先關閉它,再重新設定 A", + "Routing…": "正在規劃路線…", + "No route found": "未找到路線", + "{distance} · {duration} · {mode} · first {count} turns": "{distance} · {duration} · {mode} · 前 {count} 個轉向", + "{distance} · {duration} · {mode}": "{distance} · {duration} · {mode}", + "Click the globe to place {endpoint}": "點選地球放置 {endpoint}", + "SET B, then click the globe": "設定 B,然後點選地球", + "SET A, then click the globe": "設定 A,然後點選地球", + "Step {step} of {total} · then {leg}": "第 {step}/{total} 步 · 隨後 {leg}", + "Step {step} of {total}": "第 {step} 步,共 {total} 步", + "Then: {instruction}": "接下來:{instruction}", + "No route found between A and B": "在 A 和 B 之間未找到路線", + "Routing failed: {error}": "路線規劃失敗:{error}", + "Routing timed out": "路線規劃逾時", + "Routing unavailable — no response from the routing service": "路線規劃不可用——路線服務無回應", + "Earthquake source unavailable": "地震資料來源不可用", + "Focus fire detection {title}, {details}": "聚焦火點探測 {title},{details}", + "live feed unavailable": "即時資料來源不可用", + "{value} conf": "置信度 {value}", + "{value} ago": "{value}前", + "sensor n/a": "感測器 n/a", + "FIRE · {frp} MW": "火點 · {frp} MW", + "NIGHT": "夜間", + "▲ {frp} MW": "▲ {frp} MW", + "FIRE": "火點", + "FIRES": "火點", + "max {value} MW": "最大 {value} MW", + "new {value}": "最新({value}前)", + "{value}°N": "{value}°N", + "{value}°S": "{value}°S", + "{value}°E": "{value}°E", + "{value}°W": "{value}°W", + "just now": "剛剛", + "<1m ago": "不到 1 分鐘前", + "{count}m ago": "{count} 分鐘前", + "{count}h ago": "{count} 小時前", + "fire confidence|high": "高", + "fire confidence|nominal": "中", + "fire confidence|low": "低", + "age|<1h": "不到 1 小時", + "age|{count}h": "{count} 小時", + "age|{count}d": "{count} 天", + "Fire · FRP {frp} MW": "火點 · FRP {frp} MW", + "STALE · cached {age}": "過期 · {age}前快取", + "refreshing...": "重新整理中…", + "loading...": "載入中…", + "KEY REQUIRED": "需要金鑰", + "LIVE · updated {age}": "即時 · 更新於 {age}", + "Source snapshot time unavailable": "來源快照時間不可用", + "Live data unavailable": "即時資料不可用", + "Low-accuracy score < 2%": "低精度評分 < 2%", + "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 分鐘內已訪問檢視中的網格", + "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 海里的範圍;縮小地圖並不會使其成為全球快照。空白網格位於取樣覆蓋範圍之外,或觀測資料不足。", + "Low-accuracy score = 100 × max(0, bad − 1) / total: one aircraft is discounted, so this is not the raw share. Cells need {aircraft} aircraft over {minutes} minutes. Navigation-integrity anomalies are not a detection of jamming or spoofing.": "低精度評分 = 100 × max(0, bad − 1) / total:扣除一架飛機,因此並非原始佔比。每個網格需在 {minutes} 分鐘內有 {aircraft} 架飛機。導航完好性異常不等於檢測到干擾或欺騙。", + "GNSS snapshot needs a view anchor": "GNSS 快照需要檢視錨點", + "GNSS feed rate limited (HTTP 429)": "GNSS 資料來源已被限流(HTTP 429)", + "Malformed GNSS integrity snapshot": "GNSS 完好性快照格式錯誤", + "GNSS integrity snapshot has no observation time": "GNSS 完好性快照缺少觀測時間", + "installation class|AIRFIELD": "機場", + "installation class|NAVAL BASE": "海軍基地", + "installation class|RANGE": "靶場", + "installation class|MILITARY LAND": "軍事用地", + "installation class|BASE": "基地", + "installation class|BARRACKS": "營房", + "installation class|TRAINING AREA": "訓練區", + "installation class|PLACES CANDIDATE": "Places 候選", + "installation class|INSTALLATION": "設施", + "No mapped sites within {km} km of the contact": "目標 {km} km 內無地圖標註設施", + "{count} mapped sites within {km} km of the contact": { + "other": "目標 {km} km 內有 {count} 個地圖標註設施" + }, + "No mapped sites in view": "視野內無地圖標註設施", + "{count} mapped sites in view": { + "other": "視野內有 {count} 個地圖標註設施" + }, + "loading mapped installation context": "正在載入地圖標註設施資訊", + "Too many mapped sites in view to list them all": "視野內地圖標註設施過多,無法全部列出", + "Installation context unavailable": "設施資訊不可用", + "MAPPED INSTALLATION": "地圖標註設施", + "Unknown": "未知", + "LAUNCH SITE · {site}": "發射場 · {site}", + "LAUNCH SITE": "發射場", + "T−{time} · {mission}": "T−{time} · {mission}", + "LAUNCH STANDBY": "發射待命", + "LIFTOFF · {mission}": "點火升空 · {mission}", + "ASCENT REPLAY · {mission}": "上升回放 · {mission}", + "ASCENT ESTIMATE · {mission}": "上升估算 · {mission}", + "STAGE RE-ENTRY / RECOVERY · {mission}": "子級再入 / 回收 · {mission}", + "ORBIT REPLAY · {mission}": "軌道回放 · {mission}", + "PAUSED · {title}": "已暫停 · {title}", + "UNSPECIFIED": "未指明", + "+{count} additional payload records": "另有 {count} 條有效載荷記錄", + "PAYLOAD DATA UNAVAILABLE": "有效載荷資料不可用", + "{value} KM DOWNRANGE": "落點距離 {value} km", + "POSITION UNAVAILABLE": "無法取得位置", + "FLIGHT {count}": "第 {count} 次飛行", + "REUSED": "複用", + "NO STAGE RE-ENTRY / RECOVERY DATA": "無子級再入 / 回收資料", + "{count} / 30D": "{count} / 30 天", + "NO MISSIONS AVAILABLE IN THE CURRENT 30-DAY WINDOW": "目前 30 天視窗內沒有可用任務", + "DATE UNAVAILABLE": "日期不可用", + "UNSPECIFIED OPERATOR": "營運方未指明", + "Select {mission}": "選擇 {mission}", + "{value} KM": "{value} km", + "{value} KM/S": "{value} km/s", + "Selected Space Mission": "已選太空任務", + "SELECTED SPACE MISSION": "已選太空任務", + "Show all missions": "顯示所有任務", + "Deselect mission": "取消選擇任務", + "MISSION": "任務", + "STATUS · ": "狀態 · ", + "LAUNCH SITE · ": "發射場 · ", + "LAUNCH TIME · ": "發射時間 · ", + "ORBIT · ": "軌道 · ", + "ASCENT PATH · ": "上升軌跡 · ", + "CURRENT DISTANCE FROM EARTH · ": "目前與地球的距離 · ", + "SATELLITE SPEED · ": "衛星速度 · ", + "PAYLOAD": "有效載荷", + "NAME": "名稱", + "TYPE": "型別", + "DESTINATION": "目的地", + "STAGE / RE-ENTRY / RECOVERY": "子級 / 再入 / 回收", + "STAGE": "子級", + "STATUS": "狀態", + "FINAL POSITION": "最終位置", + "REPLAY SPEED": "回放速度", + "Replay speed multiplier": "回放速度倍率", + "REPLAY ASCENT": "重播升空", + "Previous mission": "上一個任務", + "PREV": "上一個", + "Next mission": "下一個任務", + "SHOW ALL / DESELECT": "顯示全部 / 取消選擇", + "Pause replay": "暫停回放", + "Cancel replay": "取消回放", + "EST. DOWNRANGE": "預估落點距離", + "PLANNED · ": "計畫 · ", + "SUPPLIED TRAJECTORY POINTS": "提供的軌跡點", + "RECONSTRUCTED ESTIMATE": "重建估算", + "Replay the estimated ascent with a following camera": "以跟隨鏡頭重播推估的升空過程", + "Resume replay": "繼續回放", + "T minus {seconds}": "T−{seconds}", + "Preparing launch site": "正在準備發射場", + "Liftoff": "點火升空", + "Ascent replay": "上升回放", + "Orbit replay": "軌道回放", + ", paused": ",已暫停", + "Malformed launch snapshot": "發射快照格式錯誤", + "Heard by your receiver": "由你的接收機接收", + "1090 MHz": "1090 MHz", + "978 MHz UAT": "978 MHz UAT", + "browser SDR": "瀏覽器 SDR", + "decoder feed": "解碼器資料來源", + "Your RTL-SDR receiver and decoder feed": "你的 RTL-SDR 接收機和解碼器資料來源", + "Your decoder feed": "你的解碼器資料來源", + "Your RTL-SDR receiver": "你的 RTL-SDR 接收機", + "NO CALLSIGN": "無呼號", + "ALT {altitude} FT · GS {speed} KT · TRK {track}": "高度 {altitude} ft · 地速 {speed} kn · 航跡角 {track}", + "V/S {rate}": "升降率 {rate}", + "V/S {rate} FPM": "升降率 {rate} ft/min", + "POSITION {age}": "位置 {age}前", + "POSITION {seconds} S AGO": "位置 {seconds} 秒前", + "{count} MSGS": { + "other": "{count} 條訊息" + }, + "Decoder feeds": "解碼器資料來源", + "WebUSB + decoder feeds": "WebUSB + 解碼器資料來源", + "opening receiver": "正在開啟接收機", + "checking decoder feeds": "正在檢查解碼器資料來源", + "WebUSB needs desktop Chrome or Edge": "WebUSB 需要桌面版 Chrome 或 Edge", + "connect a receiver in Radio": "在電台面板連線接收機", + "receiver is in FM mode": "接收機處於 FM 模式", + "listening": "監聽中", + "USB error": "USB 錯誤", + "Alt unknown": "高度未知", + "Type unknown": "型別未知", + "Reg unknown": "註冊號未知", + "Operator unknown": "營運方未知", + "${amount}K": "{amount}K 美元", + "${amount}M": "{amount}M 美元", + "${amount}B": "{amount}B 美元", + "fire cause|Human": "人為", + "fire cause|Natural": "自然", + "fire cause|Undetermined": "待定", + "fire cause|Unknown": "未知", + "fire behavior|Minimal": "微弱", + "fire behavior|Moderate": "中等", + "fire behavior|Active": "活躍", + "fire behavior|Extreme": "極端", + "Type {level} Incident": "{level} 類事件", + "age|{count}m": "{count} 分鐘", + "{acres} ac": { + "other": "{acres} 英畝" + }, + "{percent}% contained": "已控制 {percent}%", + "containment unknown": "控制比例未知", + "{cause} cause": "起火原因:{cause}", + "{personnel} personnel": { + "other": "{personnel} 名人員" + }, + "{county} County": "{county} 縣", + "{cost} to date": "迄今撲救費用 {cost}", + "discovered {age} ago": "發現於 {age}前", + "updated {age} ago": "更新於 {age}前", + "part of {complex}": "屬於 {complex} 複合火場", + "InciWeb ↗ · click card to open": "InciWeb ↗ · 點選卡片開啟", + "FIRE · {name}": "火場 · {name}", + "Unnamed incident": "未命名火情", + "Open {title} on InciWeb": "在 InciWeb 上開啟 {title}", + "Perimeter source unavailable": "周界資料來源不可用", + "Not contained or unknown": "未控制或未知", + "Under 50% contained": "控制低於 50%", + "50–99% contained": "控制 50–99%", + "Fully contained": "已全部控制", + "Colour shows reported containment. Perimeters are simplified to about 100 m.": "顏色表示報告的控制比例。周界簡化至約 100 m。", + "Malformed perimeter snapshot": "周界快照格式錯誤", + "radio tag|All": "全部", + "News": "新聞", + "Talk": "談話", + "Weather / Emergency": "氣象/緊急", + "Public Safety": "公共安全", + "Aviation / Marine": "航空/海事", + "Traffic / Transit": "交通/運輸", + "Music": "音樂", + "Other": "其他", + "Directory refresh degraded; showing the previous station catalog.": "目錄重新整理降級;正在顯示上一次的電台目錄。", + "Radio directory coverage is degraded.": "電台目錄覆蓋已降級。", + "Directory refresh failed; showing the previous station catalog.": "目錄重新整理失敗;正在顯示上一次的電台目錄。", + "Radio directory is temporarily unavailable.": "電台目錄暫時無法使用。", + "radio|NEWS": "新聞", + "radio|TALK": "談話", + "radio|WEATHER": "天氣", + "radio|SAFETY": "安全", + "radio|AIR / SEA": "航空 / 海事", + "radio|TRANSIT": "大眾運輸", + "radio|MUSIC": "音樂", + "radio|OTHER": "其他", + "Broadcaster stream is unavailable or blocked by the browser.": "廣播串流不可用,或被瀏覽器阻止。", + "Playback requires a direct click or tap.": "需直接點選或輕觸才能播放。", + "Broadcaster stream could not be started.": "無法啟動廣播串流。", + "Alternative": "另類", + "Ambient": "氛圍", + "Blues": "藍調", + "Classical": "古典", + "Country": "鄉村", + "Dance": "舞曲", + "Electronic": "電子", + "Folk": "民謠", + "Funk": "放克", + "Hip-Hop": "嘻哈", + "House": "House", + "Indie": "獨立音樂", + "Jazz": "爵士", + "Latin": "拉丁", + "Metal": "金屬樂", + "Oldies": "懷舊金曲", + "Pop": "流行", + "Punk": "龐克", + "R&B": "R&B", + "Reggae": "雷鬼", + "Rock": "搖滾", + "Soul": "靈魂樂", + "Techno": "Techno", + "Trance": "Trance", + "World": "世界音樂", + "overview": "概覽", + "cloud unknown": "雲量未知", + "{percent}% scene cloud": "整景雲量 {percent}%", + "{min}–{max}% scene cloud": "整景雲量 {min}–{max}%", + "Comparison in use by another scene": "對比功能正被另一個場景佔用", + "Esri map unavailable · no swipe": "Esri 地圖不可用 · 無法滑動對比", + "Swipe needs a globe map": "滑動對比需要地球地圖", + "Imagery stays on Esri · CLEAR to use Google 3D": "影像保留在 Esri · 清除後改用 Google 3D", + "Imagery catalog unavailable": "影像目錄不可用", + "Catalog truncated · a newer clear day may exist": "目錄已截斷 · 可能還有更近的少雲日期", + "{label} catalog unavailable · {detail}": "{label} 目錄不可用 · {detail}", + "Daily overview for today may still be empty until the pass": "衛星過境前,今天的每日概覽可能仍為空", + "Box and images cleared": "框選及影像已清除", + "MORE DETAIL · 30 m": "更多細節 · 30 m", + "Sentinel-2 and Landsat via HLS, 30 m, every 2–6 days": "Sentinel-2 與 Landsat,經 HLS,30 m,每 2–6 天", + "DAILY OVERVIEW · 250 m": "每日概覽 · 250 m", + "VIIRS daily mosaic, 250 m, follows broad changes; little detail under 25 km": "VIIRS 每日鑲嵌圖,250 m,反映大範圍變化;25 km 以下幾乎沒有細節", + "Sentinel-2": "Sentinel-2", + "Sentinel-2 via HLS": "Sentinel-2(經 HLS)", + "Landsat 8/9": "Landsat 8/9", + "Landsat 8/9 via HLS": "Landsat 8/9(經 HLS)", + "Daily overview": "每日概覽", + "Box edges must be finite": "框選邊界必須是有限值", + "Longitudes must be within ±180°": "經度必須在 ±180° 以內", + "Select one side of the dateline": "請只選擇日界線的一側", + "Box must enclose an area": "框選必須包含一定面積", + "Add the full Starlink broadband shell (thousands of extra points)": "加入完整 Starlink 寬頻星座(額外數千個點)", + "Loading the Starlink shell…": "正在載入 Starlink 星座…", + "Starlink {detail} — click to retry": "Starlink {detail}——點選重試", + "load failed": "載入失敗", + "Showing the full Starlink shell — click for the core catalog only": "正在顯示完整的 Starlink 星座——點選僅顯示核心目錄", + "DENSE ···": "密集 ···", + "DENSE ✕": "密集 ✕", + "DENSE": "密集", + "CelesTrak unreachable": "CelesTrak 無法連線", + "DOCKED · {name} · +{extra}": "對接 · {name} · +{extra}", + "DOCKED · {name}": "對接 · {name}", + "{name} needs the Google 3D map: choose it under MAP SOURCE": "{name} 需要 Google 3D 地圖:請在地圖源(MAP SOURCE)中選擇", + "zoom in to a street to open {name}": "放大到街道以開啟 {name}", + "KEY REJECTED": "金鑰被拒絕", + "loading coverage...": "正在載入覆蓋範圍…", + "No street-level imagery within {radius} m of that point": "該點 {radius} m 範圍內沒有街景影像", + "No street-level imagery within {radius} m of the view centre": "視野中心 {radius} m 範圍內沒有街景影像", + "Coverage tile failed": "覆蓋瓦片載入失敗", + "The photo could not be loaded": "照片無法載入", + "{name} photo. ← and → step along the sequence. On a 360° photo, drag or use Shift+← →, ↑ ↓ to look around, and + − to zoom": "{name} 照片。← 和 → 沿序列切換。在 360° 照片上,拖動或使用 Shift+← →、↑ ↓ 環視,+ − 縮放", + "{name} street-level photo": "{name} 街景照片", + "Previous photo in this sequence (←)": "此序列中的上一張照片(←)", + "Next photo in this sequence (→)": "此序列中的下一張照片(→)", + "Aim the middle of the view at a street to look for imagery there": "將視野中心對準街道以查詢該處影像", + "GOOGLE_MAPS_API_KEY is not set": "未設定 GOOGLE_MAPS_API_KEY", + "The Google Maps JavaScript API could not load": "Google Maps JavaScript API 無法載入", + "Google Street View": "Google 街景", + "GOOGLE STREET VIEW": "Google 街景", + "Google refused GOOGLE_MAPS_API_KEY for Street View — check that the Maps JavaScript API is enabled for it and this site is an allowed referrer": "Google 拒絕了用於街景的 GOOGLE_MAPS_API_KEY——請確認已為該金鑰啟用 Maps JavaScript API,且本站點在允許的引薦來源(referrer)中", + "Street View did not answer — check the network, and that the Maps JavaScript API is enabled for GOOGLE_MAPS_API_KEY": "街景無回應——請檢查網路,並確認 GOOGLE_MAPS_API_KEY 已啟用 Maps JavaScript API", + "click a street to open Street View": "點選街道以開啟街景", + "Street View has no imagery for this place": "街景沒有此地的影像", + "KartaView has no position for this photo": "KartaView 沒有此照片的位置", + "The KartaView photo could not be loaded": "KartaView 照片無法載入", + "zoom in to see KartaView coverage": "放大以檢視 KartaView 覆蓋範圍", + "no KartaView photos in view": "視野內沒有 KartaView 照片", + "KartaView is rate-limiting requests — they resume on their own": "KartaView 已被限流——稍後會自動恢復", + "KartaView’s photos here are archived and cannot be shown": "KartaView 在此處的照片已歸檔,無法顯示", + "KartaView did not filter this area in time — move the map to ask again": "KartaView 未能及時篩選此區域——移動地圖以重新請求", + "None of KartaView’s photos here pass the imagery filter": "此處沒有 KartaView 照片透過影像篩選", + "KartaView did not answer in time — try again": "KartaView 未及時回應——請重試", + "KartaView could not be reached — check the network": "無法連線 KartaView——請檢查網路", + "KartaView sent an answer that could not be read": "KartaView 返回的回應無法讀取", + "KartaView is rate-limiting requests": "KartaView 已被限流", + "KartaView sent too much data": "KartaView 返回的資料過多", + "KartaView is rate-limiting requests — try again in a moment": "KartaView 已被限流——請稍後重試", + "KartaView has no such photo": "KartaView 沒有這張照片", + "Mapillary rejected MAPILLARY_CLIENT_TOKEN — replace it in Provider Settings": "Mapillary 拒絕了 MAPILLARY_CLIENT_TOKEN——請在服務供應商設定中更換", + "Coverage requests are being rate-limited — they resume on their own": "覆蓋範圍請求已被限流——稍後會自動恢復", + "The Panoramax photo could not be loaded": "Panoramax 照片無法載入", + "Panoramax is busy — coverage resumes on its own": "Panoramax 繁忙——覆蓋範圍稍後會自動恢復", + "no Panoramax photos in view": "視野內沒有 Panoramax 照片", + "no Panoramax photos here match the filters": "此處沒有符合篩選條件的 Panoramax 照片", + "Panoramax sent a map tile that could not be read": "Panoramax 返回的地圖瓦片無法讀取", + "This Panoramax photo is no longer available": "這張 Panoramax 照片已不可用", + "zoom in to see Panoramax coverage": "放大以檢視 Panoramax 覆蓋範圍", + "Panoramax did not answer in time — try again": "Panoramax 未及時回應——請重試", + "Panoramax could not be reached — check the connection": "無法連線 Panoramax——請檢查網路連線", + "Panoramax sent too much data": "Panoramax 返回的資料過多", + "Panoramax is busy": "Panoramax 繁忙", + "Panoramax sent an unreadable answer": "Panoramax 返回的回應無法讀取", + "No street-level imagery providers configured": "未配置街景影像服務供應商", + "(by upload date)": "(按上傳日期)", + "Open the Street Level panel to view imagery": "開啟街景面板以檢視影像", + "Image could not be opened": "圖像無法開啟", + "TeleGeography load failed": "TeleGeography 載入失敗", + "UNAVAILABLE · {source} · Roads unavailable": "不可用 · {source} · 道路不可用", + "Roads: {source}": "道路:{source}", + "TomTom roads unavailable while the traffic service is unreachable": "交通服務無法連線期間,TomTom 道路不可用", + "Hybrid unavailable while the traffic service is unreachable": "交通服務無法連線期間,混合模式不可用", + "TomTom roads need a TomTom key": "TomTom 道路需要 TomTom 金鑰", + "Hybrid needs a TomTom key": "混合模式需要 TomTom 金鑰", + "Local surface still loading": "本機路面仍在載入", + "Partial coverage": "部分覆蓋", + "Detailed roads unavailable": "詳細道路不可用", + "Reduced detail coverage": "詳細覆蓋範圍受限", + "TomTom roads only, each with its live flow": "僅 TomTom 道路,各自帶即時路況", + "TomTom roads only, each with its live flow (needs a TomTom key)": "僅 TomTom 道路,各自帶即時路況(需要 TomTom 金鑰)", + "OpenStreetMap roads, with TomTom flow matched when available": "OpenStreetMap 道路,可用時匹配 TomTom 路況", + "TomTom roads first; OpenStreetMap fills the rest, simulated": "優先使用 TomTom 道路及即時路況;缺失路段由 OpenStreetMap 補充,並模擬其路況", + "TomTom roads first; OpenStreetMap fills the rest, simulated (needs a TomTom key)": "優先使用 TomTom 道路及即時路況;缺失路段由 OpenStreetMap 補充,並模擬其路況(需要 TomTom 金鑰)", + "Hybrid": "混合", + "TomTom key unavailable": "TomTom 金鑰不可用", + "TomTom daily budget reached": "已達 TomTom 每日配額", + "TomTom upstream unreachable": "TomTom 上游服務無法連線", + "TomTom flow unavailable": "TomTom 路況不可用", + "SIMULATED — {reason}": "模擬——{reason}", + "Syncing flow · Roads: {source}": "正在同步路況 · 道路:{source}", + "LIVE · Roads: {source} · Roads without flow hidden": "即時 · 道路:{source} · 已隱藏無路況道路", + "LIVE · Roads: {source} · No flow roads in view": "即時 · 道路:{source} · 視野內沒有帶路況資料的道路", + "LIVE · Roads: {source} · Flow {percent}%": "即時 · 道路:{source} · 路況 {percent}%", + "SIMULATED · Roads: {source} · Flow {percent}%": "模擬 · 道路:{source} · 路況 {percent}%", + "Syncing flow · Roads: OpenStreetMap · Flow: TomTom · Unmatched: simulated": "正在同步路況 · 道路:OpenStreetMap · 路況:TomTom · 未匹配:模擬", + "LIVE · Roads: OpenStreetMap · Flow: TomTom · {percent}% cov · Unmatched: simulated": "即時 · 道路:OpenStreetMap · 路況:TomTom · 覆蓋 {percent}% · 未匹配:模擬", + "LIVE · Roads: OpenStreetMap · Flow: TomTom · {percent}% cov": "即時 · 道路:OpenStreetMap · 路況:TomTom · 覆蓋 {percent}%", + "SIMULATED · Roads: OpenStreetMap · Flow: TomTom (no matches)": "模擬 · 道路:OpenStreetMap · 路況:TomTom(無匹配)", + "SIMULATED — traffic service unreachable": "模擬——交通服務無法連線", + "SIMULATED — add TomTom key for live": "模擬中 — 加入 TomTom 金鑰以取得即時路況", + "OpenFreeMap tiles rate-limited": "OpenFreeMap 瓦片已被限流", + "OpenFreeMap tiles timed out": "OpenFreeMap 瓦片逾時", + "OpenFreeMap tiles unavailable": "OpenFreeMap 瓦片不可用", + "occupancy|empty": "空載", + "occupancy|many seats available": "空座較多", + "occupancy|few seats available": "空座較少", + "occupancy|standing room only": "僅剩站位", + "occupancy|crushed standing room only": "極度擁擠,僅剩站位", + "occupancy|full": "已滿", + "occupancy|not accepting passengers": "不載客", + "occupancy|not boardable": "無法上車", + "Route {route}": "線路 {route}", + "Vehicle {vehicle}": "車輛 {vehicle}", + "vehicle motion|Stopped": "已停車", + "No recent fix": "無近期定位", + "Waiting for update": "等待更新", + "Moving": "行駛中", + "reported {speed} km/h": "上報 {speed} km/h", + "reported hdg {heading}°": "上報航向 {heading}°", + "Last report: stopped at stop {stop}": "最近上報:停靠站點 {stop}", + "Last report: arriving at stop {stop}": "最近上報:即將到達站點 {stop}", + "Last report: next stop {stop}": "最近上報:下一站 {stop}", + "Shown at street level · depth not in the feed": "按地面高度顯示 · 資料來源未提供深度", + "Reported {seconds} s ago": "{seconds} 秒前上報", + "Reported {minutes} min ago": "{minutes} 分鐘前上報", + "shown {seconds} s behind": "顯示滯後 {seconds} 秒", + "{reported} (feed time)": "{reported}(資料來源時間)", + "Available trail: {minutes} min (limited)": "可用軌跡:{minutes} 分鐘(受限)", + "Available trail: {minutes} min": "可用軌跡:{minutes} 分鐘", + "Bus": "公車", + "Tram": "路面電車", + "Subway": "地鐵", + "Train": "火車", + "Ferry": "渡輪", + "Transit vehicle": "大眾運輸車輛", + "AIS: {name}": "AIS: {name}", + "{type} SPD: {speed} HDG: {heading}": "{type} SPD: {speed} HDG: {heading}", + "VESSEL": "船舶", + "{speed}KT": "{speed} kn", + "{heading}DEG": "{heading}°", + "POS: LIVE": "POS:即時", + "POS: {time}Z": "POS:{time}Z", + "AIS live load failed": "AIS 即時資料載入失敗", + "awaiting first AIS position…": "等待首個 AIS 位置…", + "awaiting usable AIS positions…": "等待可用的 AIS 位置…", + "awaiting first AIS message…": "等待首條 AIS 訊息…", + "AISSTREAM_API_KEY not set": "未設定 AISSTREAM_API_KEY", + "live feed unsupported": "不支援即時資料來源", + "connecting to feed…": "正在連線資料來源…", + "feed disconnected": "資料來源已斷開", + "feed down": "資料來源中斷", + "feed idle": "資料來源空閒", + "API key rejected — check AISSTREAM_API_KEY": "API 金鑰被拒絕——請檢查 AISSTREAM_API_KEY", + "feed silent {seconds}s — no AIS data": "資料來源已靜默 {seconds} 秒——無 AIS 資料", + "feed silent — no AIS data": "資料來源已靜默——無 AIS 資料", + "feed down — retrying slowly (attempt {attempt})": "資料來源中斷——正在低頻重試(第 {attempt} 次)", + "reconnecting to feed… (attempt {attempt})": "正在重新連線資料來源…(第 {attempt} 次)", + "feed down — retrying slowly": "資料來源中斷——正在低頻重試", + "reconnecting to feed…": "正在重新連線資料來源…", + "Focus vessel {name}, MMSI {mmsi}": "聚焦船舶 {name},MMSI {mmsi}", + "Hidden by this map source · choose a globe map": "已被目前地圖源隱藏 · 請選擇地球地圖", + "Weather image HTTP {status}": "天氣圖像 HTTP {status}", + "Weather HTTP {status}": "天氣 HTTP {status}", + "Frame unavailable; previous observation retained": "幀不可用;保留上一幀觀測", + "Weather imagery unavailable": "天氣影像不可用", + "Weather source unavailable; previous observation retained": "天氣資料來源不可用;保留上一幀觀測", + "Weather unavailable": "天氣資料不可用", + "No frame within {gap} min of {time}": "{time} 前後 {gap} 分鐘內沒有幀", + "No frame within {gap} h of {time}": "{time} 前後 {gap} 小時內沒有幀", + "{hours}h {minutes}m ago": "{hours} 小時 {minutes} 分鐘前", + "{minutes}m ago": "{minutes} 分鐘前", + "{state} · {time} · {lag}": "{state} · {time} · {lag}", + "Observed": "觀測", + "History": "歷史", + "Observation unavailable": "觀測不可用", + "Waiting for observation": "等待觀測資料", + "{detail} · synced": "{detail} · 已同步", + "{detail} · nearest": "{detail} · 最接近", + "RADAR REFLECTIVITY · dBZ": "雷達反射率 · dBZ", + "LIGHTNING DENSITY · 15 min accumulation": "閃電密度 · 15 分鐘累計", + "GLOBAL INFRARED · hourly": "全球紅外 · 每小時", + "GOES INFRARED · ~5 min": "GOES 紅外 · 約 5 分鐘", + "{state}: {time}": "{state}:{time}", + "Latest observation": "最新觀測", + "frame {index}/{total}": "第 {index}/{total} 幀", + "loading": "載入中", + "Observation: unavailable": "觀測:不可用", + "Contiguous US · gaps ≠ no rain": "美國本土 · 資料缺失 ≠ 無降雨", + "Americas + Pacific · not individual strikes": "美洲與太平洋 · 非單次閃擊", + "Color: strikes/km²/min ×10³": "顏色:閃擊次數/km²/分鐘 ×10³", + "60°S–60°N · typically 2–3 h delayed": "60°S–60°N · 通常延遲 2–3 小時", + "North America · infrared imagery": "北美洲 · 紅外影像", + "Reduced motion · history playback unavailable": "減弱動效 · 歷史回放不可用", + "Reduced motion · manual history available": "減弱動效 · 可手動瀏覽歷史", + "Rain radar · US": "降雨雷達 · 美國", + "Lightning density · 15 min": "閃電密度 · 15 分鐘", + "Satellite clouds": "衛星雲圖", + "Americas + Pacific": "美洲與太平洋", + "Global · 60°S–60°N": "全球 · 60°S–60°N", + "North America": "北美洲", + "Source observations delayed": "資料來源觀測延遲", + "Stale source": "資料來源已過期", + "Loading next frame…": "正在載入下一幀…", + "Map center outside coverage": "地圖中心在覆蓋範圍之外", + "strikes/km²/min ×10³": "閃擊次數/km²/分鐘 ×10³", + "N. America": "北美", + "Global": "全球", + "Hourly global mosaic; usually 2–3 hours delayed": "每小時全球鑲嵌圖;通常延遲 2–3 小時", + "GOES regional clouds; approximately 5-minute updates": "GOES 區域雲圖;約 5 分鐘更新", + "Clouds only": "僅雲區", + "Apply the full cloud brightness key; 100% filter strength": "應用完整的雲層亮度對映;濾鏡強度 100%", + "Full": "完整", + "Show the complete infrared image; 0% filter strength": "顯示完整紅外圖像;濾鏡強度 0%", + "Soft": "柔和", + "Vivid": "鮮明", + "Image opacity; does not alter the observed values": "圖像不透明度;不改變觀測值", + "View US radar": "檢視美國雷達", + "View Americas & Pacific": "檢視美洲與太平洋", + "View coverage": "檢視覆蓋範圍", + "{value} strikes/km²/min ×10³ (15-minute density)": "{value} 次閃擊/km²/分鐘 ×10³(15 分鐘密度)", + "{value} dBZ radar reflectivity": "{value} dBZ 雷達反射率", + "STALE · cached source metadata": "已過期 · 資料來源後設資料來自快取", + "Map center is outside source coverage": "地圖中心在資料來源覆蓋範圍之外", + "NOAA/NWS 15-minute lightning density derived from Vaisala NLDN/GLD360. Coverage 110°E across the Pacific/Americas to 0°, 25°S–80°N. Not a live strike count, global coverage or a safety warning.": "NOAA/NWS 15 分鐘閃電密度,來源為 Vaisala NLDN/GLD360。覆蓋自 110°E 經太平洋/美洲至 0°,25°S–80°N。不是即時閃擊計數、不是全球覆蓋,也不構成安全警示。", + "NOAA MRMS radar echoes indicate precipitation patterns, not rain rate, a storm warning or a future forecast. Native source approximately 1 km; display is limited to level 6. Frames use exact advertised observation times.": "NOAA MRMS 雷達回波反映降水形態,不代表降雨強度、風暴警報或未來預報。原始資料解析度約 1 km;顯示僅限縮放級別 6。各幀使用資料來源公佈的精確觀測時間。", + "GOES-19/18 longwave infrared Band 14 regional; NESDIS global longwave mosaic. Clouds only dims everything but bright, cold cloud tops; a brightness filter, not a cloud mask. Coverage and freshness differ by region.": "GOES-19/18 第 14 波段長波紅外區域圖;NESDIS 全球長波鑲嵌圖。「僅雲區」會調暗除明亮冷雲頂之外的一切;這是亮度濾鏡,不是雲掩膜。覆蓋範圍與新鮮度因區域而異。", + "REGION": "區域", + "IMAGE": "圖像", + "FILTER": "濾鏡", + "Cloud filter strength": "雲層濾鏡強度", + "OPACITY": "不透明度", + "Infrared decode failed": "紅外圖像解碼失敗", + "Weather prefetch unavailable": "天氣預取不可用", + "Weather tiles unavailable · previous frame retained": "天氣瓦片不可用 · 保留上一幀", + "Some weather tiles unavailable": "部分天氣瓦片不可用", + "Malformed weather manifest": "天氣清單格式錯誤", + "Weather request timed out": "天氣請求逾時", + "Temperature field unavailable": "溫度場不可用", + "Mean sea level pressure field unavailable": "平均海平面氣壓場不可用", + "Wind upstream unavailable": "風場上游資料來源不可用", + "{source} HTTP {status}": "{source} HTTP {status}", + "Wind": "風", + "Wind source unavailable": "風場資料來源不可用", + "Forecast · does not follow history": "預報 · 不隨觀測歷史變化", + "Wind motion": "風場運動", + "Wind speed": "風速", + "Sea-level pressure": "海平面氣壓", + "Air temperature · 2 m": "氣溫 · 2 m", + "Global · 1° grid": "全球 · 1° 網格", + "{model} forecast · {time}": "{model} 預報 · {time}", + "Loading forecast": "正在載入預報", + "Preparing flow": "正在準備流場", + "Selected field unavailable": "所選氣象場不可用", + "Cached forecast · stale": "快取預報 · 已過期", + "ECMWF IFS surface forecast": "ECMWF IFS 地面預報", + "NOAA GFS surface forecast": "NOAA GFS 地面預報", + "Reduced motion": "減弱動效", + "Resume": "繼續", + "Pause": "暫停", + "Pause visual flow; forecast time does not advance with animation": "暫停流動動畫;預報時次不會隨動畫推進", + "None": "無", + "Speed": "風速", + "Pressure": "氣壓", + "Temperature": "氣溫", + "Wind trails with no field shading": "僅顯示風場流線,不疊加氣象場填色", + "How hard the surface wind is blowing": "地面風有多大", + "Sea-level air pressure: broad highs and lows": "海平面氣壓:大範圍的高壓與低壓", + "Air temperature two meters above the surface": "地面以上兩米的氣溫", + "Wind speed units": "風速單位", + "Read wind at map center": "讀取地圖中心風況", + "Read the forecast at the center of the map without changing selection": "讀取地圖中心的預報值,不改變目前選擇", + "{model} forecast · {field} ({unit})": "{model} 預報 · {field}({unit})", + "Valid: {time}": "有效時間:{time}", + "preparing": "準備中", + "Issued: {time}": "釋出時間:{time}", + "Selected field unavailable · wind remains visible": "所選氣象場不可用 · 風場仍可見", + "{error} · wind remains visible": "{error} · 風場仍可見", + "Surface wind at 10 m. Approximately 1° global grid. Curves follow the 10 m wind field, lifted 12 km for visibility; display height is not weather altitude. View lighting is for readability. Animation shows flow through one fixed forecast; it does not advance time. Color fields drape the globe basemap or the active photorealistic 3D Tiles.": "10 m 高度的地面風。約 1° 全球網格。流線沿 10 m 風場繪製,為便於觀看抬升至 12 km;顯示高度並非氣象高度。檢視光照僅為提高可讀性。動畫展示的是單一固定預報內的流場,不推進時間。氣象場填色疊加於地球底圖或目前的照片級逼真 3D Tiles。", + "MODEL": "模式", + "FIELD": "要素", + "UNITS": "單位", + "MOTION": "運動", + "Forecast": "預報", + "NNE": "北東北", + "NE": "東北", + "ENE": "東東北", + "ESE": "東東南", + "SE": "東南", + "SSE": "南東南", + "SSW": "南西南", + "SW": "西南", + "WSW": "西西南", + "WNW": "西西北", + "NW": "西北", + "NNW": "北西北", + "No surface reading": "暫無地表讀數", + "Aim the map center at Earth": "請將地圖中心對準地球", + "A location reading needs a loaded forecast and the Earth at the center of the view.": "位置讀數需要已載入的預報,且地圖中心對準地球。", + "Interpolated model forecast on an approximately 1° grid. Broad weather patterns, not a street-level measurement.": "按約 1° 網格插值的模式預報。反映大範圍天氣形勢,不是街道級實測。", + " · calm": " · 靜風", + " from {direction}": ",{direction}風", + "WIND AT {coordinates}": "{coordinates} 的風", + "{model} · valid {time}": "{model} · 有效時間 {time}", + "Wind speed field unavailable": "風速場不可用", + "Globe imagery unavailable": "地球影像不可用", + "Globe field image unavailable": "地球氣象場圖像不可用", + "Unknown wind model": "未知風場模式", + "Unknown weather overlay": "未知天氣疊加層", + "Wind request timed out": "風場請求逾時", + "Malformed wind manifest": "風場清單格式錯誤", + "Malformed wind grid": "風場網格格式錯誤", + "Error: {message}": "錯誤:{message}", + "Needs {envVars} — add it in Provider Settings": "需要 {envVars},請在服務供應商設定中新增", + "{label} is unavailable": "{label} 不可用", + "This map stack": "此地圖組合", + "{label} unavailable: {hint}": "{label} 不可用:{hint}", + "Google 3D tiles unavailable — check the key's API restrictions, quota, or network": "Google 3D 瓦片不可用——請檢查金鑰的 API 限制、配額或網路", + "Needs {envVars} — add it in Provider Settings — or a Cesium ion token for the ion-hosted route": "需要 {envVars}(請在服務供應商設定中新增),或使用 Cesium ion 權杖走 ion 託管通道", + "Exit cockpit to fly to a camera": "請先退出駕駛艙,再飛往攝影機", + "Exit cockpit to fly to a location": "請先退出駕駛艙,再飛往該地點", + "Exit cockpit to fly to a photo": "請先退出駕駛艙,再飛往照片", + "Exit cockpit to fly to a shared view": "請先退出駕駛艙,再飛往分享的檢視", + "Exit cockpit to fly to a target": "請先退出駕駛艙,再飛往目標", + "Exit cockpit to fly to a vessel": "請先退出駕駛艙,再飛往船舶", + "Exit cockpit to fly to a fire": "請先退出駕駛艙,再飛往火點", + "Exit cockpit to fly to a route": "請先退出駕駛艙,再飛往路線", + "Exit cockpit to fly to a file": "請先退出駕駛艙,再飛往檔案位置", + "Exit cockpit to fly to a scene": "請先退出駕駛艙,再飛往場景", + "Exit cockpit to view weather coverage": "請先退出駕駛艙,再檢視天氣覆蓋範圍", + "Exit cockpit to fly to a cyclone": "請先退出駕駛艙,再飛往氣旋", + "Exit cockpit to fly to an aircraft": "請先退出駕駛艙,再飛往飛機", + "Exit cockpit to fly to a satellite": "請先退出駕駛艙,再飛往衛星", + "Exit cockpit to frame contacts": "請先退出駕駛艙,再將目標納入視野", + "Visible map targets": "可見地圖目標", + "Focusing {label}": "正在聚焦 {label}", + "Source": "來源", + "Camera ownership changed": "相機控制權已變更", + "Saved project could not be read; storage preserved. Import a valid file to resume saving.": "已儲存的專案無法讀取;儲存已保留。請匯入有效檔案以恢復儲存。", + "Ready": "就緒", + "Scene layer turned off": "場景圖層已關閉", + "Stopped": "已停止", + "Scene not saved — existing saved project could not be read. Export edits or import a valid file.": "場景未儲存——已儲存的專案無法讀取。請先匯出修改或匯入有效檔案。", + "Scene not saved — {reason}": "場景未儲存——{reason}", + "Scene not saved — browser storage unavailable": "場景未儲存——瀏覽器儲存不可用", + "Loaded: {scene} / {shot}": "已載入:{scene} / {shot}", + "Cannot update {scene}: shot inventory changed": "無法更新 {scene}:鏡頭清單已變化", + "Cannot update {scene}: evidence beats changed": "無法更新 {scene}:證據節點已變化", + "Cannot update {scene}: shot bindings are incomplete": "無法更新 {scene}:鏡頭繫結不完整", + "Updated {count} shots: {scene}": { + "other": "已更新 {count} 個鏡頭:{scene}" + }, + "Appended {count} shots: {scene}": { + "other": "已追加 {count} 個鏡頭:{scene}" + }, + "Cannot capture shot: camera not ready": "無法儲存鏡頭:相機未就緒", + "Captured: {scene} / {shot}": "已儲存:{scene} / {shot}", + "Select a shot first": "請先選擇一個鏡頭", + "Updated: {scene} / {shot}": "已更新:{scene} / {shot}", + "Could not leave scene: {scene}": "無法離開場景:{scene}", + "Seeked: {scene} / {shot}": "已定位:{scene} / {shot}", + "Seeking scene clock": "正在定位場景時鐘", + "Camera unavailable — exit cockpit first": "相機不可用——請先退出駕駛艙", + "No shots to run": "沒有可執行的鏡頭", + "Scene transition limit reached — load a shot to reset": "已達到場景切換上限——請載入一個鏡頭以重置", + "Export failed: {error}": "匯出失敗:{error}", + "Project exported": "專案已匯出", + "Importing project": "正在匯入專案", + "Imported {file}": "已匯入 {file}", + "Import failed: {error}": "匯入失敗:{error}", + "Import failed (could not read JSON file)": "匯入失敗(無法讀取 JSON 檔案)", + "Layers refused: {layers}": "被拒絕的圖層:{layers}", + "Could not exit {mode} — scene layers may be refused": "無法退出 {mode}——場景圖層可能被拒絕", + "Camera move interrupted": "相機移動被中斷", + "Scene media timed out": "場景媒體播放逾時", + "Action complete": "動作已完成", + "Action unavailable or cancelled": "動作不可用或已取消", + "Scene actions": "場景動作", + "Select a feature or use Tab and Enter to choose an action.": "選擇一個要素,或使用 Tab 和 Enter 選擇動作。", + "Selected feature: {feature}. Choose an action.": "已選要素:{feature}。請選擇動作。", + "Running {index}/{total}: {scene} / {shot}": "正在執行 {index}/{total}:{scene} / {shot}", + "Scene run complete": "場景執行完成", + "Bhote Koshi Evidence Sequence": "Bhote Koshi 證據序列", + "Nepal Flood Incident": "尼泊爾洪水事件", + "Global Flights Radar": "全球航班雷達", + "Orbital Watch": "軌道監看", + "Thermal Threat Board": "熱源威脅看板", + "City Overload": "城市過載", + "Omniscience Pullback": "全知拉遠", + "Global Incident Context": "全球事件情境", + "Nepal-Focused Globe Rotation": "聚焦尼泊爾的地球旋轉", + "Bhote Koshi Regional Approach": "Bhote Koshi 區域推近", + "Bhote Koshi Nearby Cities": "Bhote Koshi 周邊城市", + "Bhote Koshi Incident Corridor": "Bhote Koshi 事件走廊", + "Bhote Koshi Flood Path": "Bhote Koshi 洪水路徑", + "Bhote Koshi Corridor Overview": "Bhote Koshi 走廊概覽", + "Bhote Koshi Upper Valley": "Bhote Koshi 上游河谷", + "Upper Valley Collapse": "上游河谷崩塌", + "Debris-Dammed Lake": "碎屑堰塞湖", + "Nepal-China Border Gate": "中尼邊境口岸", + "Timure Evidence Cluster": "Timure 證據群", + "Syabru Besi Passage": "Syabru Besi 通道", + "Bidur / Trishuli Consequence": "Bidur / Trishuli 後果", + "Final view": "最終視角", + "Scene {n}": "場景 {n}", + "Shot {n}": "鏡頭 {n}", + "the title of scene {scene} is empty or longer than {max} characters": "場景 {scene} 的標題為空或超過 {max} 個字元", + "the title of shot {shot} in scene {scene} is empty or longer than {max} characters": "場景 {scene} 中鏡頭 {shot} 的標題為空或超過 {max} 個字元", + "the project is larger than 5 MiB": "專案大於 5 MiB", + "the project has too many shots": "專案中的鏡頭過多", + "the scene data failed validation": "場景資料未透過校驗", + "Could not complete this action. Check the file, references and selected assets.": "無法完成此操作。請檢查檔案、引用和所選資源。", + "{count} scenes": { + "other": "{count} 個場景" + }, + "{count} shots": { + "other": "{count} 個鏡頭" + }, + "{count} data packs": { + "other": "{count} 個資料包" + }, + "{scene} / {pack}: {status}. File: {path}. {attribution} · {license}": "{scene} / {pack}:{status}。檔案:{path}。{attribution} · {license}", + "Unavailable layers: {layers}": "不可用圖層:{layers}", + "Uses registered content or linked media. Those external files are not included in a scene bundle. Their original notices still apply.": "使用了已註冊內容或連結媒體。這些外部檔案不包含在場景資源包中。其原始宣告仍然適用。", + "{bytes} bundled bytes verified. Files stay in memory for this session. Reimport the bundle after reloading the app.": "已校驗打包內容 {bytes} 位元組。檔案僅保留在本次工作階段的記憶體中。重新載入應用後請再次匯入資源包。", + "Review scene import": "場景匯入預覽", + "Nothing is loaded or changed until you apply this file.": "確認匯入此檔案前,不會載入或更改任何內容。", + "Ready to import": "可以匯入", + "Apply replaces the current project. Export your current project first if you want to keep both.": "應用後將替換目前專案。如需同時保留兩者,請先匯出目前專案。", + "Apply import": "確認匯入", + "Import was not applied. The current project may have changed.": "未執行匯入。目前專案可能已發生變化。", + "Select a scene and shot first": "請先選擇場景和鏡頭", + "Edit scene details": "編輯場景詳情", + "Camera positions use degrees and meters above the ellipsoid. Drafts are validated before they replace your saved scene.": "相機經緯度以度為單位,高度以米為單位(相對橢球面)。草稿透過校驗後才會替換已儲存的場景。", + "Anchors and data packs": "錨點與資料包", + "Shot camera, timing, packs and actions": "鏡頭相機、時序、資料包與動作", + "New anchor ID": "新錨點 ID", + "Capture camera as anchor": "將目前相機位置設為錨點", + "Anchor added to draft": "錨點已加入草稿", + "Set move start to current camera": "將運鏡起點設為目前相機位置", + "Move added to draft; destination remains the shot camera": "運鏡已加入草稿;終點仍為該鏡頭的相機位置", + "Use ordinary flight": "使用普通飛行", + "Invalid shot JSON": "鏡頭 JSON 無效", + "Apply details": "應用詳情", + "Select a scene first": "請先選擇一個場景", + "Share selected scene": "分享所選場景", + "Scene JSON preserves authored settings and attribution. It does not include asset files. Bundles include only pack files you choose here or previously imported bundle files.": "場景 JSON 保留創作設定與署名資訊。它不包含資源檔案。資源包僅包含你在此選擇的包檔案或先前匯入的資源包檔案。", + "Download scene JSON": "下載場景 JSON", + "Choose data-pack files": "選擇資料包檔案", + "Or choose a data-pack folder": "或選擇資料包資料夾", + "Download asset bundle": "下載資源包", + "Asset bundle downloaded": "資源包已下載", + "No RTL-SDR device selected": "未選擇 RTL-SDR 裝置", + "WebUSB requires desktop Chrome or Edge on localhost/HTTPS": "WebUSB 需要在 localhost/HTTPS 上使用桌面版 Chrome 或 Edge", + "RTL-SDR access failed; close other SDR apps and check USB permissions": "RTL-SDR 訪問失敗;請關閉其他 SDR 應用並檢查 USB 權限", + "RTL-SDR connection failed": "RTL-SDR 連線失敗", + "Receiving 1090 MHz ADS-B": "正在接收 1090 MHz ADS-B", + "Receiving broadcast FM": "正在接收廣播 FM", + "Connect an RTL-SDR to begin.": "連線 RTL-SDR 即可開始。", + "WebUSB is unavailable in this browser": "此瀏覽器不支援 WebUSB", + "USB work abandoned after a stalled transfer": "USB 傳輸停滯,已放棄操作", + "SDR decoder worker failed": "SDR 解碼器工作執行緒失敗", + "SDR decoder did not start; receiver stopped": "SDR 解碼器未能啟動;接收機已停止", + "SDR decoder stopped responding; receiver stopped": "SDR 解碼器停止回應;接收機已停止", + "SDR decoder fell behind; receiver stopped": "SDR 解碼器處理滯後;接收機已停止", + "WebUSB requires desktop Chrome or Edge": "WebUSB 需要桌面版 Chrome 或 Edge", + "Waiting for an RTL-SDR device…": "正在等待 RTL-SDR 裝置…", + "Browser audio is suspended; press Connect again to resume it": "瀏覽器音訊已掛起;再次按「連線」以恢復", + "RTL-SDR sample stream stopped": "RTL-SDR 取樣流已停止", + "Switching to {mode}…": "正在切換到 {mode}…", + "Browser audio is suspended; select FM again to resume it": "瀏覽器音訊已掛起;再次選擇 FM 以恢復", + "RTL-SDR gain change failed": "RTL-SDR 增益調整失敗", + "Tuned to {mhz} MHz FM": "已調諧到 FM {mhz} MHz", + "Seeking up…": "正在向上搜臺…", + "Seeking down…": "正在向下搜臺…", + "Seek stopped": "搜臺已停止", + "Scanning {mhz} MHz…": "正在掃描 {mhz} MHz…", + "Found {mhz} MHz · {snr} dB": "找到 {mhz} MHz · {snr} dB", + "FM signal found at {mhz} MHz": "在 {mhz} MHz 找到 FM 訊號", + "No FM signal found": "未找到 FM 訊號", + "Browser location is unavailable": "瀏覽器位置不可用", + "Receiver location was not granted": "未授予接收機位置權限", + "RTL-SDR disconnected": "RTL-SDR 已斷開", + "Upstream response too large": "上游回應過大", + "Vector tile request timed out": "向量瓦片請求逾時", + "Vector tiles unavailable": "向量瓦片不可用", + "Vector tile metadata unavailable": "向量瓦片後設資料不可用", + "Zoom in for vector tile coverage": "放大以檢視向量瓦片覆蓋", + "Saturation": "飽和度", + "Edge Thickness": "描邊粗細", + "Contrast": "對比度", + "Grain": "顆粒", + "Vignette": "暗角", + "Pixelation": "像素化", + "Distortion": "畸變", + "Instability": "抖動", + "Density": "密度", + "Gain": "增益", + "Bloom": "光暈", + "Scanlines": "掃描線", + "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": "目標 — 最近的飛機 · 船舶 · 設施", + "SPACE MISSIONS — launches & orbital assets": "太空任務 — 發射與軌道資產", + "LIVE SIGNALS": "即時訊號", + "CCTV layer unavailable": "CCTV 圖層不可用", + "Link copied!": "連結已複製!", + "Copy failed": "複製失敗", + "Return map to straight-down view": "地圖回到正俯視", + "Tilt map to oblique view": "將地圖傾斜為斜視角", + "Reset map to north up. Current heading {heading} degrees": "將地圖重置為正北朝上。目前方位 {heading} 度", + "Tilted view": "傾斜視角", + "Straight-down view": "垂直俯視", + "North up": "正北朝上", + "CCTV calibration saved": "CCTV 校準已儲存", + "HDG": "HDG", + "PITCH": "俯仰", + "FOV": "FOV", + "RANGE": "距離", + "HGT": "高度", + "ΔN": "ΔN", + "ΔE": "ΔE", + "{value}m": "{value} m", + "CCTV calibration reset": "CCTV 校準已重置", + "ADJUST ON": "調整開", + "ADJUST": "調整", + "SNAPSHOT": "快照", + "LIVE": "即時", + "UPSTREAM": "上游", + "SYNTHETIC": "合成", + "CONFIGURED": "已配置", + "SEED": "預置", + "UNKNOWN": "未知", + "ERROR": "錯誤", + "Live HLS connected": "即時 HLS 已連線", + "Live HLS unavailable": "即時 HLS 不可用", + "No stream URL configured": "未設定串流網址", + "Live stream connected": "即時串流已連線", + "Snapshot feed connected": "快照來源已連線", + "Media fetch failed": "媒體取得失敗", + "Upstream snapshot active": "上游快照運作中", + "Fallback Street View frame": "備援街景畫面", + "Upstream unavailable": "上游無法使用", + "No source configured": "未設定來源", + "Configured source": "已配置來源", + "Configured Source": "已配置資料來源", + "Synthetic fallback": "合成備用", + "Upstream HTTP {status}": "上游 HTTP {status}", + "Unexpected media type {type}": "意外的媒體型別 {type}", + "SOURCE · UNKNOWN": "來源 · 未知", + "FRAME · LOADING": "畫面 · 載入中", + "FRAME · UNAVAILABLE": "畫面 · 無法使用", + "CALIBRATED": "已校準", + "CURATED": "精選", + "RAW PRIOR": "原始預設", + "CCTV ON": "監視器 開", + "CCTV OFF": "監視器 關", + "VIEWSHED ON": "可視域開", + "COVERAGE ON": "覆蓋範圍 開", + "COVERAGE OFF": "覆蓋範圍 關", + "AUTO HOP ON": "自動輪播 開", + "AUTO HOP OFF": "自動輪播 關", + "PROJECTION ON": "投影 開", + "PROJECTION OFF": "投影 關", + "CAL · EDITED (UNSAVED)": "CAL · 已編輯(未儲存)", + "CAL · {badge}": "CAL · {badge}", + "MONITOR": "螢幕", + "OFF": "關", + "{city} · HDG {heading} · FOV {fov} · RANGE {range}m · {projection}{calBadge} · {provider}{status}": "{city} · HDG {heading} · FOV {fov} · 範圍 {range} m · {projection}{calBadge} · {provider}{status}", + "{count} cameras loaded · click a camera to activate": { + "other": "已載入 {count} 個攝影機 · 點選攝影機以啟用" + }, + "{count} cameras loaded · enable CCTV to activate": { + "other": "已載入 {count} 個攝影機 · 啟用 CCTV 以啟用" + }, + "Enable CCTV to load camera intersections": "啟用監視器以載入路口攝影機", + "Enable CCTV to start camera-linked intelligence summaries.": "啟用監視器以開始產生攝影機情資摘要。", + "No summary available.": "尚無摘要。", + "loading frames": "載入畫面", + "camera grid ready": "攝影機網格就緒", + "Clearing selected data layers": "正在清除已選資料圖層", + "Clear selected data layers": "清除已選資料圖層", + "CONDITIONS UNKNOWN": "天氣狀況未知", + "CLEAR": "清除", + "PARTLY CLOUDY": "晴間多雲", + "OVERCAST": "陰", + "FOG": "霧", + "DRIZZLE": "毛毛雨", + "RAIN": "雨", + "RAIN SHOWERS": "陣雨", + "SNOW SHOWERS": "陣雪", + "THUNDERSTORM": "雷暴", + "MIXED CONDITIONS": "混合天氣", + "CYCLE ON": "輪播 開", + "CYCLE OFF": "輪播 關", + "Stop automatic page cycling. Previous, Next, and the SIG/NEWS/LOCAL tabs stay available.": "停止自動翻頁。上一頁、下一頁以及「訊號」「新聞」「本機」標籤頁仍可使用。", + "Cycle briefing pages automatically every 9 seconds (Signals → News → Local). Pauses while you hover or focus the panel. Live signal data refreshes continuously either way.": "每 9 秒自動輪播簡報頁(訊號 → 新聞 → 在地)。滑鼠停留或聚焦面板時暫停;即時訊號資料會持續更新。", + "ACQUIRING REGIONAL NEWS": "取得區域新聞中", + "REGIONAL NEWS UNAVAILABLE": "地區新聞不可用", + "RESOLVING REGION": "解析區域中", + "REGION UNAVAILABLE": "無法取得區域", + "NO RECENT LOCATION MATCHES": "暫無近期位置匹配結果", + "{domain} · {age}": "{domain} · {age}", + "{value} KM/H": "{value} km/h", + "CLOUD {pct}%": "雲量 {pct}%", + "CLOUD UNKNOWN": "雲量未知", + "{source} · LOCATION QUERY": "{source} · 位置查詢", + "REGIONAL NEWS": "地區新聞", + "{label} · {radius} AIR/SEA WINDOW": "{label} · {radius} 空/海監視視窗", + "{scope} · INSTALLATIONS {coverage}": "{scope} · 設施 {coverage}", + "CONTEXT STANDBY": "態勢待機", + "ENABLE GLOBAL CONTEXT FOR PROXIMITY PINGS": "啟用全域態勢以接收鄰近目標提醒", + "CONTACT LOST · LAST KNOWN READOUT · NOT AN ALL-CLEAR": "目標丟失 · 最後已知讀數 · 不代表安全無虞", + "CONTACT LOST · {subject}": "目標丟失 · {subject}", + "SUBJECT LEFT ITS FEED · READOUT HOLDING LAST KNOWN": "目標已脫離其資料來源 · 讀數保持最後已知值", + "{cohort} · {contact}": "{cohort} · {contact}", + "NO AVAILABLE EXAMPLE": "沒有可用範例", + "{cohort}, Unavailable": "{cohort},不可用", + "AHEAD": "前方", + "{side} {angle}": "{side} {angle}", + "L": "左", + "R": "右", + "{count} INPUTS UNKNOWN · NOT AN ALL-CLEAR": { + "other": "{count} 項輸入未知 · 不代表安全無虞" + }, + "AVAILABLE INPUTS CURRENT · NOT AN ALL-CLEAR": "可用輸入均為最新 · 不代表安全無虞", + "SQUAWK {code} · {status}": "應答碼 {code} · {status}", + "ADS-B PRIORITY · {status}": "ADS-B 優先順序 · {status}", + "ADS-B EMERGENCY · {status}": "ADS-B 緊急 · {status}", + "AIRCRAFT": "飛機", + "ACQUIRING SURFACE": "正在取得地面資料", + "SURFACE FALLBACK": "地面資料備用", + "STALE FEED": "資料來源過期", + "LIVE TRACK": "即時航跡", + "COMMERCIAL": "商用", + "{aircraftClass} · {emergency} · {feedState}": "{aircraftClass} · {emergency} · {feedState}", + "{aircraftClass} · {feedState} · COURSE ALIGNED": "{aircraftClass} · {feedState} · 航向對準", + "ARROW · ESTIMATED DIRECTION": "箭頭 · 預估方向", + "ROUTE DATA UNAVAILABLE": "無航線資料", + "DEST {bearing}": "目的地 {bearing}", + "Disable cockpit weather effects": "停用駕駛艙天氣效果", + "Enable cockpit weather effects": "啟用駕駛艙天氣效果", + "ON": "開", + "Normal": "一般", + "Night vision": "夜視", + "Thermal": "熱成像", + "Anime": "動畫", + "Noir": "黑色電影", + "Snow": "雪景", + "Current cockpit vision style: {style}. Activate for next style.": "目前駕駛艙視覺樣式:{style}。點選可切換到下一個樣式。", + "Current style: {style} — click for next": "目前樣式:{style}——點選切換到下一個", + "Collapse Contact panel": "收合目標面板", + "Expand Contact panel": "展開目標面板", + "Collapse contact panel": "收合目標面板", + "Expand contact panel": "展開目標面板", + "Collapse cockpit briefing panel": "收合駕駛艙簡報面板", + "Expand cockpit briefing panel": "展開駕駛艙簡報面板", + "Collapse briefing panel": "收合簡報面板", + "Expand briefing panel": "展開簡報面板", + "OBSERVED / MAPPED PINGS": "觀測/標記訊號", + "SOURCE-BACKED EVENTS · NO SYNTHETIC NEWS": "有來源佐證的事件 · 無合成新聞", + "LATEST LOCATION-MATCHED REPORTING": "最新在地相關報導", + "{source} · LOCATION QUERY · RECENT": "{source} · 位置查詢 · 近期", + "LOCAL INFO": "本機資訊", + "PLACE / CONDITIONS / POSITION": "地點/天候/位置", + "TIME UNKNOWN": "時間未知", + "{count}M AGO": "{count} 分鐘前", + "{count}H AGO": "{count} 小時前", + "{count}D AGO": "{count} 天前", + "DIR UNKNOWN": "風向未知", + "Select flight {title}": "選擇航班 {title}", + "{aircraftClass} · CURRENT": "{aircraftClass} · 目前", + "MILITARY FLIGHT": "軍用航班", + "COMMERCIAL FLIGHT": "商用航班", + "{aircraftClass} · {distance}": "{aircraftClass} · {distance}", + "DISTANCE UNKNOWN": "距離未知", + "{count} INPUTS UNKNOWN": { + "other": "{count} 項輸入未知" + }, + "SOURCE STATUS UNAVAILABLE": "資料來源狀態不可用", + "Restore real aircraft": "恢復真實飛機", + "Reclassify as TR-3B": "重新分類為 TR-3B", + "TRACK ACQUIRED": "已取得航跡", + "{label} · COURSE {heading}°": "{label} · 航向 {heading}°", + "Context could not restore every layer; try again": "態勢未能恢復所有圖層,請重試", + "No selected data layers": "沒有已選資料圖層", + "{count} data layers could not be cleared": { + "other": "{count} 個資料圖層無法清除" + }, + "Cleared {count} data layers": { + "other": "已清除 {count} 個資料圖層" + }, + "Selected data layers could not be cleared": "無法清除已選資料圖層", + "Contacts could not complete the requested transition; try again": "目標未能完成所請求的切換,請重試", + "Space Missions could not complete the requested transition; try again": "太空任務未能完成所請求的切換,請重試", + "Nearby installations refreshed": "附近設施已重新整理", + "Nearby installations could not be refreshed; try again": "無法重新整理附近設施,請重試", + "Space Missions cancellation could not restore the previous layer state": "取消太空任務後無法恢復先前的圖層狀態", + "That layer is unavailable in the current Context mode": "該圖層在目前態勢模式下不可用", + "{layerId} could not {action} cleanly": "{layerId} 未能正常{action}", + "start": "啟動", + "stop": "停止", + "{mode} could not start because another layer did not stop cleanly": "{mode} 無法啟動,因為另一個圖層未能正常停止", + "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} 個地圖物件" + }, + ", drawn with its own styles": ",使用其自帶樣式繪製", + "Hide {name}": "隱藏 {name}", + "Show {name}": "顯示 {name}", + "Fly to {name}": "飛往 {name}", + "Remove {name}": "移除 {name}", + "At most {count} files at once — remove one first.": "一次最多 {count} 個檔案——請先移除一個。", + "Reading {name}…": "正在讀取 {name}…", + "That file could not be read.": "無法讀取該檔案。", + "Added {count} files.": { + "other": "已新增 {count} 個檔案。" + }, + "{count} files could not be added ({name}: {error})": { + "other": "{count} 個檔案無法新增({name}:{error})" + }, + "Some KML content was left out.": "部分 KML 內容未被匯入。", + "Press on the ground, not the sky": "請按在地面,而不是天空", + "Drag to size the box": "拖動以調整框選大小", + "light {source} to use your {name} key": "開啟 {source} 以使用你的 {name} 金鑰", + "light {source}": "開啟 {source}", + ", or ": ",或", + "{requirement}, or {offer}": "{requirement},或{offer}", + "Live Flights": "即時航班", + "Military Flights": "軍機", + "Earthquakes (24h)": "全球地震 (24小時)", + "Satellites": "衛星", + "Space Missions (30d)": "太空發射任務 (30天)", + "Street Traffic": "道路交通", + "CCTV": "CCTV", + "Radio": "廣播電台", + "Bikeshare": "公共自行車", + "Live AIS Vessels": "即時 AIS 船舶", + "Mapped Installations": "已標記軍事設施", + "Global Context": "全域態勢", + "Datacenters": "資料中心", + "Dams": "水壩", + "Submarine Cables": "海底電纜", + "FIRMS Active Fires": "FIRMS 野火熱點", + "Local ADS-B": "本機 ADS-B", + "Transit": "大眾運輸", + "Recent Imagery": "近期影像", + "Fire Perimeters": "火場周界", + "GNSS Integrity": "GNSS 完好性", + "Rain radar": "降雨雷達", + "Lightning density": "閃電密度", + "Cyclone advisories": "氣旋預警", + "ALPR Cameras": "ALPR 攝影機", + "Live Vessels": "即時船舶", + "Bike Share": "公共自行車", + "Cameras": "攝影機", + "Street Level": "街景", + "Mapped ALPR Cameras": "已標記車牌辨識攝影機", + "Data Centers": "資料中心", + "Active Fires": "野火熱點", + "Military aircraft": "軍用飛機", + "Vessels": "船舶", + "CCTV + Street View fallback": "CCTV + 街景備用", + "OpenStreetMap + optional Google Maps Places": "OpenStreetMap + 可選 Google Maps Places", + "GFS / ECMWF IFS · FORECAST": "GFS / ECMWF IFS · 預報", + "NOAA nowCOAST · OBSERVED": "NOAA nowCOAST · 觀測", + "NASA FIRMS · LIVE": "NASA FIRMS · 即時", + "OSM routing": "OSM 路線規劃", + "data source|Local": "本機", + "ENABLING": "啟動中", + "DISABLING": "關閉中", + "Movement": "移動目標", + "Infrastructure": "基礎設施", + "Events": "事件", + "Weather": "天氣", + "Utilities": "公用設施", + "Other layers": "其他圖層", + "{state} · {source}": "{state} · {source}", + "UNCERTAIN · {source} · lifecycle state requires reconciliation": "不確定 · {source} · 生命週期狀態需要核對", + "{state} · {source} · {detail} · retry {seconds}s": "{state} · {source} · {detail} · {seconds} 秒後重試", + "{state} · {source} · {detail}": "{state} · {source} · {detail}", + "never": "從未", + "{source} · {loadingLabel}": "{source} · {loadingLabel}", + "{accepted} of {raw} records accepted": "已接受 {accepted} / {raw} 條記錄", + "incomplete snapshot": "快照不完整", + "{state} · {source} · {detail} · {ago}": "{state} · {source} · {detail} · {ago}", + "{state} · {source} · {ago} · retrying in {seconds}s": "{state} · {source} · {ago} · {seconds} 秒後重試", + "{state} · {source} · {ago}": "{state} · {source} · {ago}", + "{source} · {ago}": "{source} · {ago}", + "UNCERTAIN": "狀態未知", + "status chip|UNAVAILABLE": "不可用", + "Data source unavailable": "資料來源不可用", + "{name}: {state}": "{name}:{state}", + "{count}s ago": "{count} 秒前", + "Local FM stopped: internet radio started": "本機 FM 已停止:網路電台已開始播放", + "IDLE": "空閒", + "CONNECTING": "連線中", + "TUNING": "調諧中", + "STREAMING": "接收中", + "UNSUPPORTED": "不支援", + "idle": "空閒", + "running": "執行中", + "suspended": "已掛起", + "closed": "已關閉", + "feed status|live": "即時", + "feed status|stale": "過期", + "feed status|unreachable": "無法連線", + "feed status|invalid": "無效", + "waiting for IQ": "等待 IQ 資料", + "{count} messages": { + "other": "{count} 條訊息" + }, + "DSP {count} blocks": { + "other": "DSP {count} 個資料塊" + }, + "DSP waiting": "DSP 等待中", + "{level} dBFS audio": "音訊 {level} dBFS", + "audio signal --": "音訊訊號 --", + "audio {state}": "音訊 {state}", + "{count} HEARD": { + "other": "已接收 {count} 架飛機的訊號" + }, + "DISCONNECT": "斷開連線", + "CONNECT": "連線", + "LOCATING…": "定位中…", + "LOCATED": "已定位", + "LOCATE": "定位", + " · read while Local ADS-B is on": " · 僅在本機 ADS-B 開啟時讀取", + "Decoder feeds: {feeds}": "解碼器資料來源:{feeds}", + "Language: {language}": "語言:{language}", + "Change the interface language": "更改介面語言", + "Interface language": "介面語言", + "Search languages": "搜尋語言", + "No matching languages": "沒有匹配的語言", + "📍 Location: --": "📍 位置:--", + "Landmark: --": "地標:--", + "Searched location": "已搜尋的位置", + "ORBIT": "軌道", + "Location not found": "未找到位置", + "Search failed": "搜尋失敗", + "Detailed outline unavailable": "無法取得詳細輪廓", + "Fly to a POI first": "請先飛往一個 POI", + "Reset to full globe view": "重設為完整地球視角", + "Reset cockpit to full globe view": "駕駛艙重設為完整地球視角", + "Resetting to full globe view": "正在重置為完整地球檢視", + "Resetting cockpit to full globe view": "正在將駕駛艙重置為完整地球檢視", + "MAP": "地圖", + "panel": "面板", + "Expand {name}": "展開 {name}", + "Collapse {name}": "收起 {name}", + "Expand Radio": "展開電台", + "Collapse Radio": "收起電台", + "Expand Radio section": "展開電台區域", + "Collapse Radio section": "收起電台區域", + "Panel layout updated — positions reset to new defaults": "面板佈局已更新——位置已重置為新的預設值", + "Austin": "奧斯汀", + "San Francisco": "舊金山", + "New York": "紐約", + "Tokyo": "東京", + "London": "倫敦", + "Paris": "巴黎", + "Dubai": "杜拜", + "Washington DC": "華盛頓特區", + "Tallinn": "塔林", + "Los Angeles": "洛杉磯", + "Collapse Cockpit display options": "收起駕駛艙顯示選項", + "Expand Cockpit display options": "展開駕駛艙顯示選項", + "Collapse Cockpit Radio controls": "收起駕駛艙電台控制元件", + "Expand Cockpit Radio controls": "展開駕駛艙廣播控制", + "CH {index} / {total}": "頻道 {index} / {total}", + "NO STATIONS": "無電台", + "NO STATION AVAILABLE": "無可用電台", + "{name}, station {index} of {total}": "{name},第 {index} 個電台,共 {total} 個", + "No station available": "沒有可用電台", + "OFF AIR": "未播出", + "STATION UNAVAILABLE": "電台無法使用", + "Station unavailable after directory refresh": "目錄重新整理後該電台不可用", + "Radio could not {action} cleanly": "電台未能正常{action}", + "Go to expanded Radio section": "前往展開的電台區域", + "Expand Radio section in Context": "在態勢面板中展開電台區域", + "Close compact Radio controls": "關閉精簡廣播控制", + "Open compact Radio controls": "開啟精簡廣播控制", + "SYNC": "同步", + "RECONCILE": "核對", + "DISABLE": "停用", + "ENABLE": "啟用", + "Reconcile Radio — lifecycle uncertain": "核對電台——生命週期狀態不確定", + "Disable Radio": "停用廣播", + "Enable Radio": "啟用廣播", + "DIRECTORY BAND": "目錄頻段", + "{category} BAND": "{category} 頻段", + "NO STATION SELECTED": "未選擇電台", + "Directory metadata only": "僅目錄後設資料", + "Loading station directory…": "正在載入電台目錄…", + "Choose a globe marker or use next.": "選擇地球上的標記或按「下一個」。", + "TAGS · {tags}": "標籤 · {tags}", + "Play": "播放", + "PAUSE": "暫停", + "RESUME": "繼續", + "PLAY": "播放", + "selected": "所選", + "nearest": "最近", + "{action} {target} radio station": "{action}{target}電台", + "RADIO STATE UNCERTAIN": "電台狀態不確定", + "SYNCING DIRECTORY": "正在同步目錄", + "RADIO READY": "廣播就緒", + "SYNCING": "同步中", + "READY": "就緒", + "station": "電台", + " · stale/degraded directory": " · 目錄過期/降級", + " · degraded directory": " · 目錄降級", + " · stale directory": " · 目錄過期", + " · outside current filter": " · 不在目前篩選範圍內", + "Ready — playback starts only from your action": "就緒——手動操作後開始播放", + "Radio off": "廣播關閉", + "Connecting directly to broadcaster…": "正在直接連線廣播方…", + "Buffering broadcaster stream…": "正在緩衝廣播串流…", + "Playing {station}": "正在播放 {station}", + "Paused {station}": "已暫停 {station}", + "Broadcaster stream unavailable": "廣播串流不可用", + " · muted during voice interaction": " · 語音互動期間已靜音", + " · restoring volume after voice": " · 語音結束後正在恢復音量", + " · static indicates no broadcaster audio": " · 雜音表示廣播方沒有音訊", + " · tuning static until broadcaster starts": " · 廣播方啟動前為調諧雜音", + "Station unavailable after directory refresh — choose another channel": "目錄重新整理後電台不可用——請選擇其他頻道", + "Radio is enabling…": "電台正在啟用…", + "Radio is disabling…": "電台正在停用…", + "Radio lifecycle is uncertain — use Enable or Disable to reconcile": "電台生命週期狀態不確定——請使用「啟用」或「停用」進行核對", + "Clear reading": "清除讀數", + "Earlier observation": "較早觀測", + "Observed history": "觀測歷史", + "Later observation": "較晚觀測", + "Latest": "最新", + "Newest frame per product": "每個產品的最新一幀", + "Replay observed history": "回放觀測歷史", + "Imagery on Esri · Google 3D returns when cleared": "影像顯示在 Esri 底圖上 · 清除後恢復 Google 3D", + "Point the camera at the ground to use the view": "將相機對準地面才能使用目前視野", + "That point cannot anchor a box": "該點無法作為框選錨點", + "Imagery stops at ±{limit}° latitude": "影像僅覆蓋到緯度 ±{limit}°", + "{owner} is using the pointer — close it first": "{owner} 正在使用指標——請先將其關閉", + "Box is {size} wide · limit {limit}": "框選寬 {size} · 上限 {limit}", + "View is {size} wide · limit {limit}": "視野寬 {size} · 上限 {limit}", + "VS BASEMAP": "對比底圖", + "A / B": "A / B", + "Newest low-cloud day for this box · scene cloud, not box cloud": "框選區域內最近的少雲日期 · 雲量指整景影像,並非框選區域", + "Newest day covering this box · cloudier than 20%": "覆蓋此框選的最新一天 · 雲量高於 20%", + "Newest day with imagery for this box · partial coverage": "此框選有影像的最新一天 · 部分覆蓋", + "Newest daily overview for this box": "此框選的最新每日概覽", + "newest clear day": "最近少雲日期", + "newest day (cloudy)": "最新一天(多雲)", + "newest day (partial coverage)": "最新一天(部分覆蓋)", + "newest overview": "最新概覽", + "No imagery": "無影像", + "Loading": "載入中", + "coverage|full": "完整", + "coverage|partial": "部分", + "unknown": "未知", + "no imagery": "無影像", + "{percent}% cloud": "{percent}% 雲量", + "{min}–{max}% cloud": "{min}–{max}% 雲量", + "NO BOX": "無框選", + "SEARCHING": "搜尋中", + "{count} DAYS": { + "other": "{count} 天" + }, + "Zoom in or draw a smaller box": "放大或繪製更小的框選", + "Select a box or use the view": "框選區域,或使用目前視野", + "Searching the last 30 days": "正在搜尋最近 30 天", + "No days to show for this box": "此框選沒有可顯示的日期", + "Drag the divider · SWAP trades sides": "拖動分割線 · 「交換」可互換兩側", + "← → preview · A or B pins the focused day": "← → 預覽 · A 或 B 固定目前所選日期", + "← → preview the other side · A or B pins it": "← → 預覽另一側 · A 或 B 將其固定", + "S on another day replaces it · × unpins": "在其他日期按 S 替換 · × 取消固定", + "← → preview · S shows the focused day": "← → 預覽 · S 顯示目前所選日期", + "ZOOM IN": "放大", + "Fly in until the view fits the 1,000 km limit": "拉近直到視野不超過 1,000 km 上限", + "Imagery days, newest first · arrows move, S or A and B pin": "影像日期(最新在前)· 方向鍵移動,S、A、B 固定", + "On the map": "地圖上", + "Mode": "模式", + "Imagery opacity": "影像不透明度", + "SWAP": "交換", + "Trade the two sides of the divider": "互換分割線兩側", + "SELECT BOX": "框選區域", + "Drag a box on the map (Esc cancels)": "在地圖上拖出框選(Esc 取消)", + "USE VIEW": "使用視野", + "Use the current view as the box": "以目前視野作為框選", + "Forget the box and its images": "清除框選及其影像", + "START HERE": "從此開始", + "Checking": "檢查中", + "PREVIEW": "預覽", + "Newest day with imagery for this box": "此框選有影像的最新一天", + "SHOW": "顯示", + "Pin {day} as {slot}": "將 {day} 固定為 {slot}", + "Show {day}": "顯示 {day}", + "pinned {slot}": "已固定為 {slot}", + "shown": "顯示中", + "preview": "預覽", + "start here": "從此開始", + "No box": "無框選", + "Searching": "搜尋中", + "Every day is empty here": "此處每天都為空", + "Sources off": "資料來源已關閉", + "VS": "對比", + "Not set": "未設定", + "Basemap": "底圖", + "Source off": "資料來源已關閉", + "Unpin {slot}": "取消固定 {slot}", + "Unpin the image": "取消固定圖像", + "EXPORT {slot}": "匯出 {slot}", + "EXPORT": "匯出", + "Download {slot} as a PNG": "將 {slot} 下載為 PNG", + "Download the image as a PNG": "將圖像下載為 PNG", + "Box {width} × {height} km": "框選 {width} × {height} km", + "Acquired {time}": "取得於 {time}", + "Coverage {coverage}": "覆蓋 {coverage}", + "START HERE · {reason}": "從此開始 · {reason}", + "Daily overview shows little detail in a box this small": "在這麼小的框選內,每日概覽幾乎看不出細節", + "Imagery: NASA GIBS and Worldview · HLS (Sentinel-2, Landsat 8/9) and VIIRS": "影像:NASA GIBS 與 Worldview · HLS(Sentinel-2、Landsat 8/9)與 VIIRS", + "Details": "詳情", + "Times, coverage, sources": "時間、覆蓋與資料來源", + "HIDE EMPTY DAYS": "隱藏空白日", + "SHOW EMPTY DAYS · {count}": "顯示空白日 · {count}", + "Days the probe found empty in this box": "探測發現此框選內為空的日期", + "image": "圖像", + "BASEMAP": "底圖", + "The basemap": "底圖", + "basemap": "底圖", + "Recent imagery against the basemap divider": "近期影像與底圖對比分割線", + "Recent imagery A and B divider": "近期影像 A / B 分割線", + "{before} {left} percent, {after} {right} percent": "{before} {left}%,{after} {right}%", + "Export failed · {error}": "匯出失敗 · {error}", + "Scene action failed": "場景操作失敗", + "New scene name": "新場景名稱", + "Delete scene \"{scene}\" and all shots?": "刪除場景「{scene}」及其全部鏡頭?", + "Delete shot \"{shot}\"?": "刪除鏡頭「{shot}」?", + "Stopped (Esc)": "已停止(Esc)", + "SPARSE": "稀疏", + "BALANCED": "平衡", + "No shots yet. Use CAPTURE SHOT to save current look.": "尚無鏡頭。使用「擷取鏡頭」儲存目前畫面。", + "Double-click to rename": "按兩下以重新命名", + "Shot name": "鏡頭名稱", + "LOAD": "載入", + "DEL": "刪除", + "{duration}s + {hold}s": "{duration} 秒 + {hold} 秒", + "Choose files": "選擇檔案", + "{count} files selected": { + "other": "已選擇 {count} 個檔案" + }, + "No file chosen": "未選擇檔案", + "Cancel": "取消", + "EDIT DETAILS": "編輯詳細資料", + "SHARE SCENE": "分享場景", + "Shared flight follow expired": "分享的航班跟隨已過期", + "Shared military flight follow expired": "分享的軍用航班跟隨已過期", + "Shared satellite follow expired": "分享的衛星跟隨已過期", + "Shared flight could not be restored — feed unavailable": "無法恢復分享的航班——資料來源不可用", + "Shared military flight could not be restored — feed unavailable": "無法恢復分享的軍用航班——資料來源不可用", + "Shared satellite could not be restored — feed unavailable": "無法恢復分享的衛星——資料來源不可用", + "Shared flight is unavailable": "分享的航班不可用", + "Shared military flight is unavailable": "分享的軍用航班不可用", + "Shared satellite is unavailable": "分享的衛星不可用", + "entity": "實體", + "Shared {subject} follow expired": "分享的 {subject} 跟隨已過期", + "Shared {subject} could not be restored — feed unavailable": "無法恢復分享的 {subject}——資料來源不可用", + "Shared {subject} is unavailable": "分享的 {subject} 不可用", + "ACQUIRING": "取得中", + "SHARED {subject}": "分享的 {subject}", + "subject": "目標", + "LOADING LIVE DATA": "載入即時資料", + "LOAD COMPLETE": "載入完成", + "LOAD CANCELLED": "載入已取消", + "LOAD FAILED": "載入失敗", + "LIVE DATA OFF": "即時資料已關閉", + "MAPPED SITES LOADED": "已載入地圖標註設施", + "RETRYING MAPPED SITES": "正在重試地圖標註設施", + "FETCHING MAPPED SITES": "正在取得地圖標註設施", + "RETRYING ALPR CAMERAS": "正在重試 ALPR 攝影機", + "FETCHING ALPR CAMERAS": "正在取得 ALPR 攝影機", + "OVERPASS TEMPORARILY UNAVAILABLE": "Overpass 暫時不可用", + "OVERPASS RATE-LIMITED": "Overpass 已被限流", + "OVERPASS TIMED OUT": "Overpass 逾時", + "OVERPASS COULD NOT COMPLETE THE QUERY": "Overpass 無法完成查詢", + "MAP TILES TEMPORARILY UNAVAILABLE": "地圖瓦片暫時不可用", + "MAPPED NAMES TEMPORARILY UNAVAILABLE": "地點名稱暫時不可用", + "TURNING OFF LIVE DATA": "正在關閉即時資料", + "REFRESHING LIVE DATA": "更新即時資料", + "syncing road network": "同步道路網路", + "retry pending": "等待重試", + "retrying in {seconds}s": "{seconds} 秒後重試", + "ALPR cameras": "ALPR 攝影機", + "OpenSky OAuth client missing/invalid": "OpenSky OAuth 客戶端缺失/無效", + "OpenSky OAuth rejected credentials": "OpenSky OAuth 拒絕了憑據", + "OpenSky username/password rejected": "OpenSky 使用者名稱/密碼被拒絕", + "OpenSky auth missing": "OpenSky 缺少認證", + "OpenSky auth required": "OpenSky 需要認證", + "OpenSky auth invalid": "OpenSky 認證無效", + "OpenSky auth failed": "OpenSky 認證失敗", + "KartaView answered HTTP {status}": "KartaView 返回 HTTP {status}", + "Panoramax answered HTTP {status}": "Panoramax 返回 HTTP {status}", + "KartaView refused the request (code {code})": "KartaView 拒絕了請求(代碼 {code})", + "Vector tiles unavailable (HTTP {status})": "向量瓦片不可用(HTTP {status})", + "GNSS feed unavailable (HTTP {status})": "GNSS 資料來源不可用(HTTP {status})", + "{count} CelesTrak groups unavailable": { + "other": "{count} 個 CelesTrak 分組不可用" + }, + "{feed} feed unavailable": "{feed} 資料來源不可用", + "Source snapshot {minutes} min old": "資料來源快照:{minutes} 分鐘前", + "{source} rate limited (anonymous)": "{source} 已被限流(匿名)", + "{source} rate limited": "{source} 已被限流", + "{source} network error": "{source} 網路錯誤", + "Malformed {source} aircraft rows": "{source} 飛機資料行格式錯誤", + "Malformed {source} response": "{source} 回應格式錯誤", + "entry {n}": "條目 {n}", + "feeds {names} stale": { + "other": "資料來源 {names} 過期" + }, + "feeds {names} unreachable": { + "other": "資料來源 {names} 無法連線" + }, + "feeds {names} invalid": { + "other": "資料來源 {names} 無效" + }, + "Loading {feeds}": "正在載入 {feeds}", + "{count} heard": { + "other": "已接收 {count} 架飛機的訊號" + }, + "USB {rate} msg/s": "USB {rate} msg/s", + "{rate} msg/s": "{rate} msg/s", + "{count} feeds live": { + "other": "即時資料來源 {count} 個" + }, + "{feed} {count} ({seconds}s old)": "{feed} {count}({seconds} 秒前)", + "Street Level could not start": "街景未能啟動", + "Street Level toggle failed": "街景切換失敗", + "SHRINK": "縮小", + "EXPAND": "展開", + "Shrink": "縮小", + "Expand": "展開", + "ANY DATE": "任意日期", + "LAST 10 YEARS": "最近 10 年", + "LAST 5 YEARS": "最近 5 年", + "LAST 3 YEARS": "最近 3 年", + "LAST 2 YEARS": "最近 2 年", + "LAST YEAR": "最近一年", + "LAST 6 MONTHS": "最近 6 個月", + "LAST 3 MONTHS": "最近 3 個月", + "LAST MONTH": "最近一個月", + "LAST {count} DAYS": { + "other": "最近 {count} 天" + }, + "{window} · SINCE {date}": "{window} · 自 {date} 起", + "Turn Street Level off": "關閉街景", + "Turn Street Level on": "開啟街景", + "{name} imagery on": "{name} 影像已開啟", + "{name} imagery off": "{name} 影像已關閉", + "Image by {creator}": "圖像作者:{creator}", + " or ": " 或 ", + "OPEN {labels}": "開啟 {labels}", + "Open {names} at the centre of the view": "在視野中心開啟 {names}", + "Zoom in to a street to open {names} here": "放大到街道以在此處開啟 {names}", + "Loading this sequence…": "正在載入此序列…", + "{n} images in this sequence · Esc clears": { + "other": "此序列共 {n} 張圖像 · Esc 清除" + }, + "{n} streets in view · click a line for its nearest photo": { + "other": "視野內共 {n} 條街道 · 點選線段檢視距其最近的照片" + }, + "{n} sequences in view · click a line for its nearest photo": { + "other": "視野內共 {n} 條序列 · 點選線段檢視距其最近的照片" + }, + "{n} sequences in view · click a line for its photos": { + "other": "視野內共 {n} 條序列 · 點選線段檢視其照片" + }, + "km/h": "km/h", + "m/s": "m/s", + "mph": "mph", + "hPa": "hPa", + "kt": "kn", + "kts": "kn", + "ft": "ft", + "km": "km", + "m": "m", + "h": "小時", + "min": "分鐘", + "s": "秒", + "dB": "dB", + "Celestial ring — reveal the full globe": "天體環 — 顯示完整地球", + "Celestial ring — available in Normal style": "天球環——僅在常規樣式下可用", + "Detection overlay: {mode}": "探測疊加層:{mode}", + "Detection overlay: off": "探測疊加層:關閉", + "DETECT": "偵測", + "{time} · {minutes} min ago": "{time} · {minutes} 分鐘前", + "Active weather": "已啟用的天氣圖層", + "LATEST · newest per product": "最新 · 每個產品的最新一幀", + "Forecast · valid {valid} · issued {issued}": "預報 · 有效時間 {valid} · 釋出時間 {issued}", + "{detail} · Does not follow history": "{detail} · 不隨觀測歷史變化", + "Forecast · valid {valid}": "預報 · 有效時間 {valid}", + "voice|OFF": "關", + "voice|CONNECTING": "連線中", + "voice|LISTENING": "聆聽中", + "voice|EXECUTING": "執行中", + "voice|ERROR": "錯誤", + "AI AGENT": "AI 助理", + "Voice model tier — applies next session": "語音模型等級 — 於下次工作階段生效", + "STD": "標準", + "Estimated session cost": "預估工作階段費用", + "Voice control — activate to toggle voice; hold Space to speak": "語音控制 — 啟用以切換語音;按住空白鍵說話", + "ON/OFF": "開/關", + "VOICE STANDBY": "語音待命", + "VOICE CONTROL": "語音控制", + "Hold Space to speak · tap Space to activate focused controls": "按住空白鍵說話 · 輕按空白鍵啟用聚焦的控制項", + "Voice assistant": "語音助手", + "VOICE": "語音", + "Dismiss voice card": "關閉語音卡片", + "YOU": "你", + "THIS": "所指", + "Plan": "計畫", + "Referenced items": "引用條目", + "NOTES & SOURCES": "說明與來源", + "VOICE SYSTEM ERROR": "語音系統錯誤", + "DISMISS": "關閉", + "Check microphone permission and network access, then try again.": "請檢查麥克風權限與網路連線後再試一次。", + "Stopped by voice": "已透過語音停止", + "WebRTC microphone support unavailable": "目前瀏覽器不支援透過 WebRTC 使用麥克風", + "Requesting microphone": "正在請求麥克風", + "Release Space to send": "鬆開空白鍵傳送", + "Hold Space to talk": "按住空白鍵說話", + "Ask or command": "提問或下達指令", + "Voice off": "語音已關閉", + "VOICE UNAVAILABLE": "語音不可用", + "VOICE ACTIVE": "語音已啟用", + "Voice session could not be started.": "無法啟動語音工作階段。", + "MINI": "輕量", + "Next session: {pendingId} — this session stays on {modelId}": "下次工作階段:{pendingId}——本次工作階段仍使用 {modelId}", + "Voice model: {pendingId} — click to switch to {target}; applies next session": "語音模型:{pendingId}——點選切換到 {target};下次工作階段生效", + "standard": "標準", + "mini": "輕量", + "COST UNKNOWN": "費用未知", + "ChatGPT OAuth session: {responses} response(s), {input} input and {output} output tokens, {captions} caption transcription(s) reported.": "ChatGPT OAuth 工作階段:已報告 {responses} 個回應、{input} 個輸入 token、{output} 個輸出 token、{captions} 次字幕轉寫。", + "USD cost and the API spend cap are unavailable for this auth mode.": "此認證模式下無法提供美元費用與 API 消費上限。", + "Usage is incomplete because a response was still in flight when the session ended.": "用量不完整,因為工作階段結束時仍有回應在處理中。", + "Estimated session cost on {modelId} — {responses} response(s). Warns at {warn}, ends the session at {cap}.": "{modelId} 的預估工作階段費用——{responses} 次回應。達到 {warn} 時警告,達到 {cap} 時結束工作階段。", + "Estimate is incomplete — a response was still in flight when the session ended, so its usage was never reported.": "估算不完整——工作階段結束時仍有回應在處理中,因此其用量從未上報。", + "STANDARD": "標準", + "{tier} applies next session": "{tier} 將在下次工作階段生效", + "Session ended — cost cap {cost}": "工作階段已結束——已達費用上限 {cost}", + "MIC": "麥克風", + "Radio did not start": "電台未能啟動", + "Running command": "正在執行指令", + "{n} aircraft": { + "other": "{n} 架飛機" + }, + "{n} military aircraft": { + "other": "{n} 架軍用飛機" + }, + "{n} ships": { + "other": "{n} 艘船舶" + }, + "{n} satellites": { + "other": "{n} 顆衛星" + }, + "{n} launches": { + "other": "{n} 次發射" + }, + "{n} earthquakes": { + "other": "{n} 次地震" + }, + "{n} fires": { + "other": "{n} 處火點" + }, + "{n} fire perimeters": { + "other": "{n} 處火場周界" + }, + "{n} cyclones": { + "other": "{n} 個氣旋" + }, + "{n} buses": { + "other": "{n} 輛公車" + }, + "{n} bike share": { + "other": "{n} 個公共自行車站點" + }, + "{n} flock cameras": { + "other": "{n} 個 Flock 攝影機" + }, + "{n} military bases": { + "other": "{n} 處軍事基地" + }, + "{n} datacenters": { + "other": "{n} 個資料中心" + }, + "{n} dams": { + "other": "{n} 座水壩" + }, + "{n} air quality": { + "other": "{n} 個空氣品質站點" + }, + "{n} results": { + "other": "{n} 條結果" + }, + "anywhere in the loaded data": "已載入資料中的任意位置", + "in view": "視野內", + "within {radius} of the view centre": "視野中心 {radius} 範圍內", + "within {radius} of {place} (Contacts window)": "{place} {radius} 範圍內(目標視窗)", + "within {radius} of {place}": "{place} {radius} 範圍內", + "within {radius}": "{radius} 範圍內", + "over {region}": "{region} 範圍內", + "At least {items}": "至少 {items}", + "{items} {scope}": "{items} {scope}", + "last 24 h": "過去 24 小時", + "past 30 d and upcoming": "過去 30 天及未來", + "the flights layer loads by viewport": "航班圖層按視口載入", + "distance is ground distance, not overhead": "距離為地面距離,而非空中直線距離", + "the count is a lower bound because at least one layer reached its retained limit.": "該計數為下限,因為至少一個圖層已達到其保留上限。", + "{label} off": "{label} 已關閉", + "{label} loading": "{label} 載入中", + "{label} error": "{label} 出錯", + "counted the first {returned} loaded records": "已統計最先載入的 {returned} 條記錄", + "counted {returned} of {total} loaded records": "已統計 {total} 條已載入記錄中的 {returned} 條", + "{layers} just turned on — still loading, counts will rise": "{layers} 剛開啟——仍在載入,計數還會增加", + "Contacts panel snapshot at {time} — the same retained cohort supplies the card, speech, and follow-up memory": "目標面板快照({time})——卡片、語音播報和後續追問記憶均來自同一組保留目標", + "Contacts panel snapshot — the same retained cohort supplies the card, speech, and follow-up memory": "目標面板快照——卡片、語音播報和後續追問記憶均來自同一組保留目標", + "Fly below {km} km to a covered region": "請降至 {km} km 以下並飛往有覆蓋的區域", + "No feed here yet · {n} regions available": { + "other": "此處暫無資料來源 · 有 {n} 個覆蓋區域" + }, + "degraded": "降級", + "stale": "過期", + "partial": "部分可用", + "fallback": "備用", + "unavailable": "不可用", + "Not answered: {layers}": "未回應:{layers}", + "Toggle voice control": "切換語音控制", + "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": "軍用航班圖層未開啟", + "The satellites layer is not enabled": "衛星圖層未開啟", + "The ais-live-vessels layer is not enabled": "即時 AIS 船舶圖層未開啟", + "Could not enable the requested layer": "無法開啟所請求的圖層", + "Could not disable the requested layer": "無法關閉所請求的圖層", + "Radio layer unavailable": "電台圖層不可用", + "Camera navigation is unavailable in the current view": "目前檢視下無法進行相機導航", + "Camera navigation policy unavailable": "相機導航策略不可用", + "Nearest-aircraft selection supports Flights or Military Flights only": "最近飛機選擇僅支援航班或軍用航班", + "Nearest-aircraft selection needs a preset, place name, or latitude and longitude": "最近飛機選擇需要預設、地名或經緯度", + "Could not arrive at the requested place": "無法抵達所請求的地點", + "The nearest airborne aircraft could not be selected": "無法選中最近的空中飛機", + "No flights within {radius} of the current view": "目前視野 {radius} 範圍內沒有航班", + "No military within {radius} of the current view": "目前視野 {radius} 範圍內沒有軍用航班", + "No satellites within {radius} of the current view": "目前視野 {radius} 範圍內沒有衛星", + "No vessels within {radius} of the current view": "目前視野 {radius} 範圍內沒有船舶", + "{layer} is enabled on the {source} feed, but no airborne aircraft is loaded in the {place} view yet": "{layer} 已在 {source} 資料來源上開啟,但 {place} 視野中尚未載入空中飛機", + "{layer} is enabled, but no airborne aircraft is loaded in the {place} view yet": "{layer} 已開啟,但 {place} 視野中尚未載入空中飛機", + "{layer} is enabled, but its aircraft feed is unavailable": "{layer} 已開啟,但其飛機資料來源不可用", + "{layer} is enabled, but its destination refresh did not complete": "{layer} 已開啟,但目的地重新整理未完成", + "{layer} is enabled, but {source} is unavailable": "{layer} 已開啟,但 {source} 不可用", + "Could not arrive at {place}": "無法抵達 {place}", + "{name} is no longer loaded": "{name} 已不在載入資料中", + "Unknown target layer: {target}": "未知的目標圖層:{target}", + "nominal": "正常", + "{label} on": "{label} 已開啟", + "Frame aircraft": "將飛機納入視野", + "Frame military aircraft": "將軍用飛機納入視野", + "Frame ships": "將船舶納入視野", + "Frame satellites": "將衛星納入視野", + "Frame contacts": "將目標納入視野", + "{count} aircraft in frame": { + "other": "畫面中 {count} 架飛機" + }, + "{count} military aircraft in frame": { + "other": "畫面中 {count} 架軍用飛機" + }, + "{count} ships in frame": { + "other": "畫面中 {count} 艘船舶" + }, + "{count} satellites in frame": { + "other": "畫面中 {count} 顆衛星" + }, + "{count} contacts in frame": { + "other": "畫面中 {count} 個目標" + }, + "Nearest military aircraft": "最近的軍用飛機", + "Nearest ships": "最近的船舶", + "Nearest satellites": "最近的衛星", + "Nearest aircraft": "最近的飛機", + "{first} and {second}": "{first} 和 {second}", + "Layer": "圖層", + "there": "那裡", + "Camera range {range}": "相機距離 {range}", + "Within {radius} of the view": "目前視野 {radius} 範圍內", + "Labels on": "標籤已開啟", + "Framing uses the nearest 80 loaded contacts": "調整視野時僅包含已載入的最近 80 個目標", + "{distance} from {location}": "距 {location} {distance}", + "Altitude {altitude}": "高度 {altitude}", + "{origin} to {destination}": "{origin} 至 {destination}", + "from {origin}": "從 {origin} 出發", + "to {destination}": "前往 {destination}", + "Registration {registration}": "註冊號 {registration}", + "View state": "視野狀態", + "Marked {count} places": { + "other": "已標註 {count} 個地點" + }, + "Nothing marked": "沒有標註", + "Not found: {places}": "未找到:{places}", + "Tracing outlines": "正在繪製輪廓", + "Frame flights": "將航班納入視野", + "Frame military": "將軍用航班納入視野", + "Frame vessels": "將船舶納入視野", + "Frame {target}": "將 {target} 納入視野", + "Zoom out to globe": "縮小至地球檢視", + "Open data layers": "開啟資料圖層", + "Open or close a panel": "開啟或關閉面板", + "Change context mode": "切換態勢模式", + "Control cockpit": "控制駕駛艙", + "Change visual style": "切換視覺樣式", + "Adjust HUD": "調整 HUD", + "Adjust cyber sonar": "調整賽博聲納", + "Adjust detection overlay": "調整探測疊加層", + "Change map stack": "切換地圖組合", + "Adjust post-processing": "調整後期處理", + "Control scene": "控制場景", + "Control CCTV": "控制 CCTV", + "Control radio": "控制電台", + "Track contact": "追蹤目標", + "Stop tracking": "停止追蹤", + "Clear marks": "清除標註", + "Move camera": "移動相機", + "Fly route": "沿路線飛行", + "Analyst query": "分析查詢", + "Next ISS pass": "下一次 ISS 過境", + "Next satellite pass": "下一次衛星過境", + "Mark the map": "在地圖上標註", + "Mark {targets} +{more}": "標註 {targets} +{more}", + "Mark {targets}": "標註 {targets}", + "Fly to {place}": "飛往 {place}", + "Fly to Location": "飛往地點", + "Nearest aircraft to {place}": "距離 {place} 最近的飛機", + "Nearest aircraft to Here": "距離此處最近的飛機", + "Layer on": "圖層已開啟", + "Layer off": "圖層已關閉", + "Zoom out": "縮小", + "Zoom in": "放大", + "Read the view": "播報目前視野", + "Check view state": "檢查視野狀態", + "Action": "操作", + "Finding places": "正在查詢地點", + "Tracing outline": "正在繪製輪廓", + "Looking up place": "正在查詢地點", + "Flying": "飛行中", + "Turning on layer": "正在開啟圖層", + "Loading aircraft": "正在載入飛機", + "Picking nearest": "正在選取最近目標", + "Working": "處理中", + "in progress": "進行中", + "done": "完成", + "failed": "失敗", + "cancelled": "已取消", + "Outline traced": "輪廓已繪製", + "Outline unavailable": "輪廓不可用", + "Source: {label}": "來源:{label}", + "WORKING": "處理中", + "DONE": "完成", + "HERE": "此處", + "Aircraft cockpit view": "飛機駕駛艙視角", + "LEVEL": "水平", + "Estimated destination direction": "推估目的地方向", + "DEST ---°": "目的地 ---°", + "OPTICAL PLANE · 01": "光學平面 · 01", + "VISOR LOCK · ACTIVE": "護目鏡鎖定 · 啟用", + "GROUND SPEED · KTS": "地速 · 節", + "ALTITUDE · FT": "高度 · 英尺", + "FIRST PERSON": "第一人稱", + "LIVE TRACK · COURSE ALIGNED": "即時追蹤 · 航向對齊", + "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": "下一個視覺風格", + "Current aircraft heading": "目前飛機航向", + "GROUND SPEED": "地速", + "KTS": "kn", + "ALTITUDE": "高度", + "FT": "ft", + "Contact cockpit summary": "目標駕駛艙摘要", + "CONTACT": "目標", + "CONTACTS · 250 KM": "目標 · 250 公里", + "Contact navigation": "目標導覽", + "CONTEXT ONLY": "僅供態勢參考", + "Nearby cohort counts": "周邊目標數量", + "FLT": "航班", + "MIL": "軍用", + "SITE": "設施", + "NEAREST OBSERVED / MAPPED": "最近的觀測/標記目標", + "AVAILABLE INPUTS ONLY · NOT AN ALL-CLEAR": "僅依現有資料 · 不代表安全無虞", + "WX": "天氣", + "Cockpit briefing carousel": "駕駛艙簡報輪播", + "Estimated flight plan": "推估飛行計畫", + "ESTIMATED FLIGHT PLAN": "推估飛行計畫", + "FROM": "出發", + "TO": "目的", + "Cockpit briefing controls": "駕駛艙簡報控制", + "Previous briefing page": "上一頁簡報", + "Next briefing page": "下一頁簡報", + "Live signals": "即時訊號", + "Latest regional news": "最新區域新聞", + "Location-based information": "在地資訊", + "TEMP": "溫度", + "WIND": "風", + "SKY": "天空", + "PRECIP": "降水", + "MM": "mm", + "Weather data by Open-Meteo.com": "天氣資料來自 Open-Meteo.com", + "Cockpit briefing pages": "駕駛艙簡報頁", + "SIG": "訊號", + "Show Live Signals": "顯示即時訊號", + "NEWS": "新聞", + "Show Regional News": "顯示區域新聞", + "LOCAL": "在地", + "Show Local Info": "顯示在地資訊", + "Cockpit display and Radio controls": "駕駛艙顯示與廣播控制", + "DISPLAY": "顯示", + "Cockpit display options": "駕駛艙顯示選項", + "RADIO": "廣播", + "Cockpit compact Radio controls": "駕駛艙精簡廣播控制", + "Previous filtered radio station": "上一個篩選電台", + "Play selected radio station": "播放所選電台", + "Next filtered radio station": "下一個篩選電台", + "VOLUME": "音量", + "Cockpit Radio volume": "駕駛艙廣播音量", + "ESC EXIT": "ESC 離開", + "C TOGGLE": "C 切換", + "View switcher": "視角切換", + "Exit cockpit and return to full globe view": "離開駕駛艙並回到完整地球視角", + "RESET": "重設", + "Exit cockpit view": "離開駕駛艙視角", + "EXIT COCKPIT": "離開駕駛艙", + "Navigation, voice, and visual preset controls": "導航、語音與視覺預設控制", + "Expand Visual Presets": "展開視覺預設", + "Pin visual presets": "釘選視覺預設", + "Keep visual presets open": "保持視覺預設開啟", + "Show the globe without a visual filter.": "不套用任何視覺濾鏡顯示地球。", + "Emulate a green phosphor CRT with scanlines and screen curvature.": "模擬帶有掃描線與螢幕弧度的綠色磷光 CRT。", + "Simulate night-vision goggles with green intensification and a tube vignette.": "模擬綠色增光與鏡筒暗角的夜視鏡。", + "Simulate FLIR-style thermal contrast. Turn up Ironbow for color.": "模擬 FLIR 熱成像對比。調高 Ironbow 可顯示色彩。", + "Apply bright cel-shaded color and illustrated outlines.": "套用明亮的賽璐璐上色與插畫描邊。", + "Apply high-contrast monochrome film-noir grading.": "套用高對比黑白黑色電影調色。", + "Add a cold, snowy whiteout treatment to the scene.": "為場景加上冰冷的白茫雪景效果。", + "MAP SOURCE": "地圖來源", + "Map source": "地圖來源", + "Style": "樣式", + "Expand LOCATION": "展開地理位置面板", + "Collapse panel": "收合面板", + "Pin location tray": "釘選位置面板", + "Keep location tray open": "保持位置面板開啟", + "Search any location": "搜尋任何地點", + "Search location by name or coordinates": "依名稱或座標搜尋地點", + "Search any location...": "搜尋任何地點…", + "WEATHER": "天氣", + "Active weather products": "已啟用的天氣產品", + "RECENT IMAGERY": "近期影像", + "Imagery days in the box": "視野內的影像天數", + "CONTEXT": "態勢", + "Compact Radio controls": "精簡廣播控制", + "Open detailed Radio controls": "開啟詳細廣播控制", + "Previous station": "上一個電台", + "Next station": "下一個電台", + "Compact Radio volume": "精簡廣播音量", + "Expand panel": "展開面板", + "Context mode": "態勢模式", + "CONTACTS": "目標", + "Cycles the nearest contacts of whatever type you select — planes, vessels, installations. Satellites track independently.": "輪流切換所選類型的最近目標 — 飛機、船舶、設施。衛星獨立追蹤。", + "SPACE MISSIONS": "太空任務", + "SELECT CONTEXT": "選擇態勢", + "Contact Context actions": "目標情境操作", + "COCKPIT": "駕駛艙", + "SEARCH NEARBY SITES": "搜尋附近設施", + "Reclassify tracked contact as TR-3B": "將追蹤目標重新分類為 TR-3B", + "CONTACTS CONTEXT OFF": "目標態勢已關閉", + "SELECT CONTACTS TO LOAD OBSERVED / MAPPED PROXIMITY": "選擇「目標」以載入觀測/標記的鄰近資訊", + "Available Space Missions": "可用太空任務", + "AVAILABLE MISSIONS": "可用任務", + "SELECT A MISSION TO INSPECT": "選擇要檢視的任務", + "LOADING 30-DAY MISSION INDEX": "載入 30 天任務索引", + "TAB PREVIEWS · ENTER / SPACE SELECTS": "TAB 預覽 · ENTER/空白鍵 選取", + "Internet radio and local SDR": "網路電台與本機 SDR", + "STATION TAG": "電台標籤", + "Filter stations by station tag": "依電台標籤篩選", + "All": "全部", + "Enable Radio, then choose a globe marker or use next.": "啟用廣播,再選擇地球上的標記或按「下一個」。", + "DRAG TO TUNE": "拖曳調頻", + "Tune available internet radio stations": "調整可用網路電台", + "ALL · DRAG THE NEEDLE": "全部 · 拖曳指針", + "SNAPS TO AVAILABLE STATIONS": "自動對齊可用電台", + "Radio playback": "廣播播放", + "Previous filtered station": "上一個篩選電台", + "Play selected station": "播放所選電台", + "Next filtered station": "下一個篩選電台", + "STOP": "停止", + "Stop radio playback": "停止廣播播放", + "Radio volume": "廣播音量", + "STATION SITE": "電台位置", + "DIRECTORY: RADIO BROWSER": "目錄:RADIO BROWSER", + "Audio connects directly to the broadcaster after you press play. Your IP is visible to that broadcaster.": "按下播放後會直接連線到廣播電台,你的 IP 位址會被該電台看到。", + "Local RTL-SDR receiver": "本機 RTL-SDR 接收機", + "LOCAL RTL-SDR": "本機 RTL-SDR", + "Chrome/Edge · WebUSB · one local tuner shared by FM and the Local ADS-B layer.": "Chrome/Edge · WebUSB · 一個本機調諧器由 FM 與本機 ADS-B 圖層共享。", + "Use your location for faster ADS-B position decoding": "使用你的位置,加快 ADS-B 位置解碼", + "CHANGE DEVICE": "更換裝置", + "Choose a different RTL-SDR or receiver channel": "選擇其他 RTL-SDR 或接收通道", + "RTL-SDR receiver mode": "RTL-SDR 接收模式", + "GAIN": "增益", + "RTL-SDR tuner gain for the current mode": "目前模式下的 RTL-SDR 調諧器增益", + "AUTO": "自動", + "MSG/S": "msg/s", + "HEARD": "已接收訊號", + "POSITIONED": "已定位", + "FM MHZ": "FM MHz", + "TUNE": "調諧", + "Seek broadcast FM stations": "搜尋廣播 FM 電台", + "◀ SEEK": "◀ 搜臺", + "SEEK ▶": "搜臺 ▶", + "SDR VOL": "SDR 音量", + "Local SDR volume": "本機 SDR 音量", + "Intelligence HUD (H)": "情報抬頭顯示 (H)", + "Layout": "版面", + "HUD layout": "HUD 版面", + "Tactical": "戰術", + "Operator": "操作員", + "Minimal": "極簡", + "Cyber": "賽博", + "Sonar": "聲納", + "Cyber sonar contact scanner": "賽博聲納目標掃描器", + "Rings": "圈數", + "Sonar ring count": "聲納圈數", + "Range": "範圍", + "Sonar ring range": "聲納圈範圍", + "Power": "強度", + "Sonar intensity": "聲納強度", + "Opacity": "不透明度", + "Cyber contact and label opacity": "賽博目標與標籤不透明度", + "Minimum opacity for map dots, icons, models, brackets, and labels between sonar passes": "兩次聲納掃描之間地圖點、圖示、模型、括號標記與標籤的最低不透明度", + "Sector": "扇區", + "Sonar sector width": "聲納扇區寬度", + "Detection Overlay (D)": "偵測疊加 (D)", + "Detection overlay": "偵測疊加", + "Detection label density": "偵測標籤密度", + "Allocation": "分配", + "Detection label allocation": "偵測標籤分配", + "Elastic": "彈性", + "Weighted": "加權", + "Fade": "淡出", + "Detection fade distance": "偵測淡出距離", + "World-overlay fade distance outside the keyhole as a percentage of its radius": "瞄準孔外世界疊加層的淡出距離(半徑百分比)", + "Outside": "外圍", + "Detection opacity outside the keyhole": "瞄準孔外的偵測不透明度", + "World-overlay label and card opacity beyond the fade distance": "超過淡出距離後世界疊加標籤與卡片的不透明度", + "PARAMETERS": "參數", + "3D aircraft — flat icons zoomed out, 3D models up close": "3D 飛機 — 拉遠為平面圖示,拉近為 3D 模型", + "Models": "模型", + "3D model coverage": "3D 模型範圍", + "Proximity": "鄰近", + "Scope — the circular viewport mask": "視域 — 圓形檢視範圍遮罩", + "Scope": "視域", + "Feather": "羽化", + "Scope edge feather": "視域邊緣羽化", + "Scope edge feather as a percentage of the keyhole radius": "瞄準鏡邊緣羽化(瞄準孔半徑百分比)", + "Draw on the world — click vertices, double-click or Enter to finish, Esc to cancel": "在世界上繪圖 — 點選頂點,按兩下或 Enter 完成,Esc 取消", + "Shape": "形狀", + "Shape to draw": "要繪製的形狀", + "Area": "區域", + "Line": "線", + "Pin": "圖釘", + "Label (optional)": "標籤(選填)", + "Label for the drawn shape": "繪製形狀的標籤", + "Colour of the drawn shape": "繪製形狀的顏色", + "Primary": "主色", + "Amber": "琥珀", + "Cyan": "青", + "Green": "綠", + "Red": "紅", + "Clear": "清除", + "Remove every mark from the board": "清除畫板上所有標記", + "Show your own GeoJSON, KML, KMZ or GPX files on the globe (or drop them onto it). File bytes stay on this device; overlays can appear in map screenshots shared with voice.": "在地球上顯示自己的 GeoJSON、KML、KMZ 或 GPX 檔案(也可直接拖放到地球上)。檔案內容僅保留在本裝置上;疊加層可能出現在隨語音分享的地圖截圖中。", + "Import": "匯入", + "Choose GeoJSON, KML, KMZ or GPX files": "選擇 GeoJSON、KML、KMZ 或 GPX 檔案", + "Imported files": "已匯入的檔案", + "Celestial": "天體環", + "Hide UI chrome": "隱藏介面框架", + "Clean UI": "簡潔介面", + "Bloom / Glow": "光暈/輝光", + "Bloom intensity": "光暈強度", + "Sharpening": "銳利化", + "Sharpen": "銳利化", + "Sharpen intensity": "銳利化強度", + "EXIT CLEAN VIEW": "離開簡潔檢視", + "Return UI controls": "恢復介面控制項", + "Initializing photorealistic world...": "正在初始化擬真世界…", + "DATA LAYERS": "資料圖層", + "ACQUIRING FRAME": "擷取畫面中", + "NEAREST": "最近", + "CCTV camera": "監視器攝影機", + "CALIBRATION": "校正", + "Drag the camera in the world: rings rotate, arrows move, handles set range/FOV": "在世界中拖曳攝影機:圓環旋轉、箭頭移動、把手調整距離/視角", + "Camera pose — click a value to type": "攝影機姿態 — 點選數值即可輸入", + "Heading (compass °) — click to type": "方位角(羅盤 °)— 點選輸入", + "Pitch (° up/down) — click to type": "俯仰角(° 上/下)— 點選輸入", + "Horizontal FOV (°) — click to type": "水平視角(°)— 點選輸入", + "Range / monitor-plane distance (m) — click to type": "距離/投影平面距離(公尺)— 點選輸入", + "Mount height above ground (m) — click to type": "架設離地高度(公尺)— 點選輸入", + "North offset from catalog position (m) — click to type": "相對目錄位置的北向偏移(公尺)— 點選輸入", + "East offset from catalog position (m) — click to type": "相對目錄位置的東向偏移(公尺)— 點選輸入", + "SAVE CAL": "儲存校正", + "RESET CAL": "重設校正", + "SCENE SUMMARY": "場景摘要", + "STREET LEVEL": "街景", + "Turn Street Level on or off": "開啟或關閉街景", + "Image fit": "圖像縮放方式", + "FIT": "完整顯示", + "Fit: show the whole photo, with dark bars where its shape differs from the frame": "適應:顯示整張照片,在比例與畫框不符處留黑邊", + "FILL": "填滿", + "Fill: fill the frame edge to edge, cropping the photo": "填充:圖像鋪滿畫框並裁剪照片", + "Close the image and deselect it on the map": "關閉圖像並取消其在地圖上的選中狀態", + "Close the street-level image": "關閉街景圖像", + "Street-level viewer": "街景檢視器", + "Open this image on the provider's site": "在服務供應商網站上開啟此圖像", + "Imagery providers": "影像服務供應商", + "PROVIDERS": "服務供應商", + "Imagery filters": "影像篩選", + "IMAGERY": "影像", + "Panorama filter": "全景篩選", + "ALL": "全部", + "FLAT": "平面", + "SINCE": "起始時間", + "SCENES": "場景", + "Scene recipe": "場景配方", + "NEW": "新增", + "CAPTURE SHOT": "擷取鏡頭", + "UPDATE SHOT": "更新鏡頭", + "START": "開始", + "EXPORT PRESETS": "匯出預設", + "IMPORT": "匯入", + "RUN LOG": "執行紀錄", + "POWER UP": "強化功能", + "GROUND STATION · PROVIDER SETTINGS": "地面站 · 服務供應商設定", + "Close key setup": "關閉金鑰設定", + "Power up the globe": "強化你的地球", + "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.": "不需任何金鑰地球就能運作。下方每一組金鑰都會開啟另一個真實資料來源 — 貼上後會存入本機設定,伺服器隨即自動重新啟動。伺服器端金鑰只留在本機;Google Maps 與 Cesium ion 在瀏覽器中執行,務必在供應商端設定使用限制。在其他地方設定的金鑰只會顯示,不會被修改。", + "SAVE KEYS": "儲存金鑰", + "ESC to close": "ESC 關閉", + "The Google Maps key buys the photorealistic planet — everything else stacks on top.": "Google Maps 金鑰帶來擬真地球 — 其他功能都疊加在它之上。", + "NO PLACE LEFT BEHIND": "無處遁形", + "ACTIVE STYLE": "目前風格", + "Globe actions": "地球操作", + "Turn off all selected data layers": "關閉所有已選資料圖層", + "Copy share link": "複製分享連結", + "Toggle straight-down and tilted map views": "切換俯視/傾斜地圖視角", + "Reset map to north up": "地圖重設為北方朝上", + "Reset map bearing to north": "重設地圖方位為正北", + "Reset camera and return to full globe view": "重設鏡頭並回到完整地球視角", + "MISSION CONTROL · FIRST LAUNCH": "任務控制 · 首次啟動", + "Choose your first view": "選擇你的第一個視角", + "LIVE CONTACTS": "即時目標", + "Aircraft, vessels and nearby intelligence": "飛機、船舶與周邊情資", + "Launches, spacecraft and orbital context": "發射、太空載具與軌道資訊", + "EXPLORE MANUALLY": "自由探索", + "Begin with a clean globe": "從乾淨的地球開始", + "Don't show this again": "不再顯示", + "ESC to dismiss": "ESC 關閉", + "Tip: the GEV MIC button in the dock lets you talk to the map.": "提示:按下底部的 GEV 麥克風按鈕,就能用語音操控地圖。", + "hemisphere|N": "N", + "hemisphere|S": "S", + "hemisphere|E": "E", + "hemisphere|W": "W", + "Gemini Live voice control": "Gemini Live 語音控制", + "Zoom in to see street-level coverage": "放大地圖以檢視街景覆蓋範圍", + "Point the camera at the ground for street-level coverage": "將相機朝向地面以檢視街景覆蓋範圍", + "Sequence images unavailable": "序列影像不可用", + "Switch Street Level on to draw its coverage.": "開啟「街景」以繪製其覆蓋範圍。", + "Every provider is switched off: light a chip to draw its coverage.": "所有服務供應商均已關閉:點亮一個標籤即可繪製其覆蓋範圍。", + "No sequences in view match the filter": "視野內沒有符合篩選條件的序列", + "No coverage in view": "視野內無覆蓋範圍", + "Voice provider": "語音服務供應商", + "Changing provider reconnects voice if it is on.": "如語音已開啟,切換服務供應商會重新連線語音。", + "Gemini returned an oversized audio chunk": "Gemini 返回的音訊塊過大", + "Gemini returned an unsupported audio format": "Gemini 返回了不支援的音訊格式", + "Gemini returned an invalid audio sample rate": "Gemini 返回了無效的音訊取樣率", + "Gemini returned incomplete PCM audio": "Gemini 返回的 PCM 音訊不完整", + "This browser does not support Gemini microphone audio": "目前瀏覽器不支援 Gemini 麥克風音訊", + "Microphone audio processing failed": "麥克風音訊處理失敗", + "Gemini audio playback fell behind. Reconnect to continue.": "Gemini 音訊播放滯後。請重新連線以繼續。", + "Gemini token response did not include an ephemeral credential": "Gemini 權杖回應中沒有臨時憑據", + "Invalid Gemini connection endpoint": "Gemini 連線端點無效", + "Gemini voice could not connect. Try again.": "Gemini 語音無法連線。請重試。", + "Gemini voice requires a same-origin app request": "Gemini 語音需要與本應用同源的請求", + "Add a Gemini API key in Provider Settings": "請在服務供應商設定中新增 Gemini API 金鑰", + "The Gemini Live model configuration is invalid": "Gemini Live 模型配置無效", + "Gemini voice is starting too often. Try again shortly.": "Gemini 語音啟動過於頻繁。請稍後重試。", + "Gemini quota is unavailable. Try again later.": "Gemini 配額不可用。請稍後重試。", + "Gemini access was refused. Check the API key and model access.": "Gemini 拒絕了訪問。請檢查 API 金鑰和模型訪問權限。", + "Gemini Live is unavailable for the configured model.": "所配置的模型無法使用 Gemini Live。", + "Token request is too large": "權杖請求過大", + "Use an empty JSON token request": "請使用空的 JSON 權杖請求", + "Voice command context is too large": "語音命令上下文過大", + "Gemini reliable transport exceeded its queue limit. Start voice again.": "Gemini 可靠傳輸超出了佇列上限。請重新啟動語音。", + "Gemini reliable transport did not drain. Start voice again.": "Gemini 可靠傳輸的佇列未能清空。請重新啟動語音。", + "Gemini token request failed (HTTP {status})": "Gemini 權杖請求失敗(HTTP {status})", + "Gemini token response did not include a valid model": "Gemini 權杖回應中沒有有效的模型", + "Gemini token response did not include session settings": "Gemini 權杖回應中沒有工作階段設定", + "Gemini session settings do not match the input mode": "Gemini 工作階段設定與輸入模式不匹配", + "Gemini could not submit this input. Start voice again.": "Gemini 無法提交此輸入。請重新啟動語音。", + "Connecting to Gemini": "正在連線 Gemini", + "Gemini returned an oversized message": "Gemini 返回的訊息過大", + "Gemini Live connection failed. Check network access, then start voice again.": "Gemini Live 連線失敗。請檢查網路連線,然後重新啟動語音。", + "Gemini Live connection ended. Start voice again for a new conversation.": "Gemini Live 連線已結束。請重新啟動語音以開始新對話。", + "Gemini Live could not start. Start voice again to request a fresh session.": "Gemini Live 無法啟動。請重新啟動語音以申請新的工作階段。", + "Start voice again for a fresh token and a new conversation.": "請重新啟動語音,以取得新權杖並開始新對話。", + "Start voice again to request a fresh session credential.": "請重新啟動語音以申請新的工作階段憑據。", + "Microphone permission was denied. Allow microphone access and try again.": "麥克風權限被拒絕。請允許訪問麥克風後重試。", + "Gemini connection timed out. Try again.": "Gemini 連線逾時。請重試。", + "Gemini voice could not start": "Gemini 語音無法啟動", + "Gemini did not finish the interrupted reply. Start voice again.": "Gemini 未能完成被打斷的回覆。請重新啟動語音。", + "Gemini session expiring; finishing the current reply": "Gemini 工作階段即將到期,正在完成目前回覆", + "Gemini rejected the voice session. Start voice again to request a fresh session.": "Gemini 拒絕了語音工作階段。請重新啟動語音以申請新的工作階段。", + "Start voice again for a fresh session credential. If it repeats, check Gemini model and API access.": "請重新啟動語音以取得新的工作階段憑據。如問題重複出現,請檢查 Gemini 模型和 API 訪問權限。", + "Gemini action history is full. Start voice again for a fresh session.": "Gemini 操作歷史已滿。請重新啟動語音以開始新的工作階段。", + "Gemini requested too many simultaneous actions": "Gemini 請求的同時操作過多", + "Voice text command is too long": "語音文字命令過長", + "Gemini voice is not connected": "Gemini 語音未連線", + "Gemini interrupted input exceeded its buffer or wait limit. Start voice again.": "Gemini 被打斷的輸入超出了緩衝區或等待上限。請重新啟動語音。", + "Gemini Live connection is expiring. Start voice again for a new conversation.": "Gemini Live 連線即將到期。請重新啟動語音以開始新對話。", + "Gemini voice sessions have a time limit. When a session expires, start voice again for a new conversation.": "Gemini 語音工作階段有時長限制。工作階段到期後,請重新啟動語音以開始新對話。", + "Show the street-level view full screen (Esc shrinks it)": "全屏顯示街景檢視(按 Esc 縮小)", + "OK": "正常", + "{category} ({count})": "{category}({count})", + "Layers": "圖層", + "Search": "搜尋", + "More": "更多", + "Panels": "面板" +} diff --git a/src/i18n/same-as-english.json b/src/i18n/same-as-english.json index c331cd070..48688a0c7 100644 --- a/src/i18n/same-as-english.json +++ b/src/i18n/same-as-english.json @@ -192,5 +192,60 @@ "ΔE", "ΔN", "▲ {frp} MW" + ], + "zh-TW": [ + "1090 MHz", + "978 MHz UAT", + "AIS: --", + "AIS: {name}", + "BRG {value}°", + "BRG —", + "CAL {value}", + "CAL · {badge}", + "CCTV", + "CRS {value}°", + "CRT", + "FLIR", + "FOV", + "FOV {value}°", + "FT", + "GEO", + "HDG", + "HDG {value}°", + "House", + "Ironbow", + "KTS", + "Landsat 8/9", + "MM", + "NVG", + "REC", + "SRC {value}", + "Sentinel-2", + "Techno", + "Trance", + "USB {rate} msg/s", + "WHOT/BHOT", + "dB", + "ft", + "hPa", + "hemisphere|E", + "hemisphere|N", + "hemisphere|S", + "hemisphere|W", + "km", + "km/h", + "kt", + "kts", + "mph", + "{city} CCTV", + "{rate} msg/s", + "{source} HTTP {status}", + "{speed} kn", + "{type} SPD: {speed} HDG: {heading}", + "{value} KM", + "{value} KM/S", + "ΔE", + "ΔN", + "▲ {frp} MW" ] } diff --git a/src/i18n/zh-TW-display.test.mjs b/src/i18n/zh-TW-display.test.mjs new file mode 100644 index 000000000..74b2f714a --- /dev/null +++ b/src/i18n/zh-TW-display.test.mjs @@ -0,0 +1,60 @@ +import test from 'node:test'; +import assert from 'node:assert/strict'; +import { setLocale, t, tn, getLocale } from './index.js'; +import { resolveLocale, LOCALE_STORAGE_KEY } 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 { cctvSourceStatusLabel } from '../ui/cctvFrames.js'; + +test('Traditional Chinese resolves from URL, saved preference and browser language', () => { + assert.equal( + resolveLocale({ + location: { search: '?lang=zh-TW' }, + storage: { getItem: () => 'en' }, + languages: ['en'], + }), + 'zh-TW', + ); + assert.equal( + resolveLocale({ + location: { search: '' }, + storage: { + getItem: (key) => (key === LOCALE_STORAGE_KEY ? 'zh-TW' : null), + }, + languages: ['en'], + }), + 'zh-TW', + ); + assert.equal( + resolveLocale({ + location: { search: '' }, + storage: { getItem: () => null }, + languages: ['zh-Hant', 'en'], + }), + 'zh-TW', + ); +}); + +test('Traditional Chinese readouts preserve unit case, coordinates and natural relative dates', () => { + const previous = getLocale(); + try { + setLocale('zh-TW'); + assert.equal(hudQuantity(2069, 'km', 1), '2069.0 km'); + assert.equal(formatCockpitDistance(14000), '14\u00a0km'); + assert.equal( + LOCALIZED_LOCALITY.sector({ latDeg: 21.33, lonDeg: -77.5 }), + '扇區 21.33N 77.50W', + ); + assert.equal(READOUT_WORDS.daysAgo(9), '9 天前'); + assert.equal(READOUT_WORDS.daysAgo(0), '今天'); + assert.equal(cctvSourceStatusLabel('ok'), '正常'); + assert.equal(t('SAVE KEYS'), '儲存金鑰'); + assert.equal( + tn(2, 'Click {count} more point.', 'Click {count} more points.'), + '再點選 2 個點。', + ); + } finally { + setLocale(previous); + } +}); diff --git a/src/layers/recentImagery/display.js b/src/layers/recentImagery/display.js index 5c18d8b3f..33a0785b5 100644 --- a/src/layers/recentImagery/display.js +++ b/src/layers/recentImagery/display.js @@ -33,7 +33,9 @@ export const READOUT_WORDS = Object.freeze({ date: (day) => displayDay(day, LONG_DAY), daysAgo: (delta) => { const text = formatRelativeTime(delta > 0 ? -delta : 0, 'day'); - return getLocale() === 'zh-CN' ? text.replace(/(\d)(?=天)/g, '$1 ') : text; + return getLocale().startsWith('zh-') + ? text.replace(/(\d)(?=天)/g, '$1 ') + : text; }, // "Sentinel-2" never breaks at its hyphen: a word joiner follows it // (JetBrains Mono has no U+2011 non-breaking hyphen). diff --git a/src/ui/cockpitContext.js b/src/ui/cockpitContext.js index 852cc32a8..2c65d3bf6 100644 --- a/src/ui/cockpitContext.js +++ b/src/ui/cockpitContext.js @@ -15,7 +15,7 @@ const LOCALIZED_CONTEXT_SCOPE = Object.freeze({ window: ({ label, radiusKm }) => t('{label} · {radius} AIR/SEA WINDOW', { label, - radius: `${radiusKm === null ? '—' : formatNumber(radiusKm)}\u00a0${getLocale() === 'zh-CN' ? unitLabel('km') : unitLabel('km').toUpperCase()}`, + radius: `${radiusKm === null ? '—' : formatNumber(radiusKm)}\u00a0${getLocale().startsWith('zh-') ? unitLabel('km') : unitLabel('km').toUpperCase()}`, }), installations: ({ scope, coverage }) => t('{scope} · INSTALLATIONS {coverage}', { scope, coverage }), diff --git a/src/ui/cockpitPresentation.js b/src/ui/cockpitPresentation.js index 8285b74b3..582d2435a 100644 --- a/src/ui/cockpitPresentation.js +++ b/src/ui/cockpitPresentation.js @@ -149,7 +149,7 @@ export function formatCockpitDistance(distanceM) { minimumFractionDigits: digits, maximumFractionDigits: digits, }); - return getLocale() === 'zh-CN' ? distance : distance.toUpperCase(); + return getLocale().startsWith('zh-') ? distance : distance.toUpperCase(); } export function formatCockpitWindDirection(value) { diff --git a/src/ui/localePicker.test.mjs b/src/ui/localePicker.test.mjs index 7f6d11f9b..5151ad4fc 100644 --- a/src/ui/localePicker.test.mjs +++ b/src/ui/localePicker.test.mjs @@ -40,7 +40,7 @@ test('the current language comes first, the rest by their own names', () => { nativeNames: LOCALE_NAMES, }), ), - ['ru', 'en', 'es', 'zh-CN'], + ['ru', 'en', 'es', 'zh-CN', 'zh-TW'], ); assert.deepEqual( codes( @@ -50,7 +50,7 @@ test('the current language comes first, the rest by their own names', () => { nativeNames: LOCALE_NAMES, }), ), - ['es', 'en', 'ru', 'zh-CN'], + ['es', 'en', 'ru', 'zh-CN', 'zh-TW'], ); assert.deepEqual( codes( @@ -60,7 +60,7 @@ test('the current language comes first, the rest by their own names', () => { nativeNames: LOCALE_NAMES, }), ), - ['en', 'es', 'ru', 'zh-CN'], + ['en', 'es', 'ru', 'zh-CN', 'zh-TW'], ); const rows = buildLocaleOptions({ locales: MANY, @@ -263,7 +263,7 @@ test('keyboard model: open on the current language, move, choose, close', () => assert.deepEqual(model.keydown({ key: 'ArrowDown' }), { handled: true }); assert.equal(model.activeOption.code, 'en'); model.keydown({ key: 'End' }); - assert.equal(model.activeOption.code, 'zh-CN'); + assert.equal(model.activeOption.code, 'zh-TW'); model.keydown({ key: 'Home' }); assert.equal(model.activeOption.code, 'ru'); model.keydown({ key: 'ArrowUp' }); From ddae593bb777cf0f60ff5702de965f0101b60cb9 Mon Sep 17 00:00:00 2001 From: German Khokhlov Date: Fri, 23 Oct 2026 22:53:15 +0400 Subject: [PATCH 02/11] docs: credit Traditional Chinese translation sources --- changelog.d/1336-traditional-chinese.md | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 changelog.d/1336-traditional-chinese.md diff --git a/changelog.d/1336-traditional-chinese.md b/changelog.d/1336-traditional-chinese.md new file mode 100644 index 000000000..386fd8ed4 --- /dev/null +++ b/changelog.d/1336-traditional-chinese.md @@ -0,0 +1,4 @@ +- Add Traditional Chinese (zh-TW) with Taiwan terminology, language selection, + and localized Chinese readouts. Based on translations by @caxer (#724), + @tbdavid2019 (#652), @abiyeenzo (#914), and @EDIT-Aeterna (#979) + (German, @gekh, #1336). From 8f16cf263bf1f98f5012d72c202f3a69450fd9ca Mon Sep 17 00:00:00 2001 From: German Khokhlov Date: Tue, 27 Oct 2026 10:20:54 +0400 Subject: [PATCH 03/11] i18n: use zh-Hant for Chinese (Traditional) --- changelog.d/1336-traditional-chinese.md | 2 +- docs/CURRENT-STATE.md | 4 +- docs/TRANSLATORS.md | 4 +- docs/translations/zh-Hant.md | 36 ++++++++ docs/translations/zh-TW.md | 36 -------- scripts/package-boundaries.json | 86 +++++++++---------- src/i18n/firms-live-zh.test.mjs | 2 +- src/i18n/i18n.test.mjs | 12 +-- src/i18n/index.js | 4 +- src/i18n/locale.js | 11 +-- src/i18n/locales/{zh-TW.json => zh-Hant.json} | 0 src/i18n/same-as-english.json | 2 +- ...play.test.mjs => zh-Hant-display.test.mjs} | 30 +++++-- src/ui/localePicker.js | 12 ++- src/ui/localePicker.test.mjs | 8 +- 15 files changed, 139 insertions(+), 110 deletions(-) create mode 100644 docs/translations/zh-Hant.md delete mode 100644 docs/translations/zh-TW.md rename src/i18n/locales/{zh-TW.json => zh-Hant.json} (100%) rename src/i18n/{zh-TW-display.test.mjs => zh-Hant-display.test.mjs} (72%) diff --git a/changelog.d/1336-traditional-chinese.md b/changelog.d/1336-traditional-chinese.md index 386fd8ed4..c3969d44e 100644 --- a/changelog.d/1336-traditional-chinese.md +++ b/changelog.d/1336-traditional-chinese.md @@ -1,4 +1,4 @@ -- Add Traditional Chinese (zh-TW) with Taiwan terminology, language selection, +- Add Traditional Chinese (zh-Hant) with language selection, and localized Chinese readouts. Based on translations by @caxer (#724), @tbdavid2019 (#652), @abiyeenzo (#914), and @EDIT-Aeterna (#979) (German, @gekh, #1336). diff --git a/docs/CURRENT-STATE.md b/docs/CURRENT-STATE.md index 69139e6bb..c3cbacba0 100644 --- a/docs/CURRENT-STATE.md +++ b/docs/CURRENT-STATE.md @@ -3583,7 +3583,7 @@ test:track` 43 tracking invariants · headless QA harnesses under ### Interface localization (October 2026) -Shipped locales: **en** (source and fallback), **es**, **ru**, **zh-CN** and **zh-TW**. The code lives in +Shipped locales: **en** (source and fallback), **es**, **ru**, **zh-CN** and **zh-Hant**. The code lives in `src/i18n/`. How to mark UI text: [`docs/I18N.md`](./I18N.md); translator workflow: [`docs/TRANSLATORS.md`](./TRANSLATORS.md). @@ -3595,7 +3595,7 @@ Shipped locales: **en** (source and fallback), **es**, **ru**, **zh-CN** and **z `src/i18n/locales/.json`, and a missing entry falls back to English. - **Locale choice.** `?lang=` → stored choice (`gev:locale:v1`) → `navigator.languages` → English. Chinese tags default to `zh-CN`; `Hant`, `TW`, `HK` and `MO` - select `zh-TW`. Explicit `Hans` selects `zh-CN` regardless of region. `?lang=` is not stored, and share links drop + select `zh-Hant`. Explicit `Hans` selects `zh-CN` regardless of region. `?lang=` is not stored, and share links drop it, so a recipient keeps their own language. The globe picker in the bottom-right corner (`src/ui/localePicker.js`) stores the choice, drops `?lang=` (keeps it only when storage is blocked) and reloads. It asks first diff --git a/docs/TRANSLATORS.md b/docs/TRANSLATORS.md index 5122afa9f..830ca155e 100644 --- a/docs/TRANSLATORS.md +++ b/docs/TRANSLATORS.md @@ -1,6 +1,6 @@ # Translating God's Eye View -Shipped languages: **English** (source and fallback), **Spanish** (`es`), **Russian** (`ru`), **Simplified Chinese** (`zh-CN`) and **Traditional Chinese** (`zh-TW`). +Shipped languages: **English** (source and fallback), **Spanish** (`es`), **Russian** (`ru`), **Simplified Chinese** (`zh-CN`) and **Traditional Chinese** (`zh-Hant`). ## How it works @@ -63,4 +63,4 @@ These are contracts, not copy: layer ids and registry keys, status enums and oth ## Language notes -Each language keeps its glossary, plural forms, units and style in its own file, `docs/translations/.md`: [Spanish](./translations/es.md), [Russian](./translations/ru.md), [Simplified Chinese](./translations/zh-CN.md), [Traditional Chinese](./translations/zh-TW.md). Read it before translating, and add a term there when you settle on one. +Each language keeps its glossary, plural forms, units and style in its own file, `docs/translations/.md`: [Spanish](./translations/es.md), [Russian](./translations/ru.md), [Simplified Chinese](./translations/zh-CN.md), [Traditional Chinese](./translations/zh-Hant.md). Read it before translating, and add a term there when you settle on one. diff --git a/docs/translations/zh-Hant.md b/docs/translations/zh-Hant.md new file mode 100644 index 000000000..9e3bbfeba --- /dev/null +++ b/docs/translations/zh-Hant.md @@ -0,0 +1,36 @@ +# Traditional Chinese (`zh-Hant`) + +Catalog: `src/i18n/locales/zh-Hant.json`. General rules: [TRANSLATORS.md](../TRANSLATORS.md). + +Sources: caxer (#724), tbdavid2019 (#652), and the zh-CN catalog credited to abiyeenzo (#914) and EDIT-Aeterna (#979). The remaining entries were seeded with OpenCC s2twp and edited for consistency. The catalog retains terminology from these Taiwan-oriented sources; `zh-Hant` identifies the writing system and does not promise separate regional vocabulary. + +## Style + +- Use Traditional characters and consistent terminology from the glossary below. Prefer short, neutral instructions: 「點選地圖」、「儲存金鑰」. +- Use full-width Chinese punctuation and 「」 for quotations. Keep `·`, `…`, provider names, codes and placeholders unchanged. +- Separate Chinese from Latin letters and numbers with a space: 「AIS 船舶」、「24 小時」. Keep unit symbols unchanged: km, m, km/h, m/s, kn, ft, MW, °, %. +- Chinese labels have no uppercase variant. Keep button labels short and avoid splitting short words across lines. +- The picker displays 中文(繁體) / Chinese (Traditional). Browser tags with Hant or TW/HK/MO select the shared `zh-Hant` catalog. Existing `zh-TW` links and saved choices remain supported. Explicit Hans selects Simplified Chinese, including Hans-TW. + +## Plurals + +`Intl.PluralRules('zh-Hant')` uses only `other`. Keep suitable measure words: 「{count} 架飛機」、「{count} 艘船」、「{count} 個金鑰」. + +## Catalog terminology + +| English | Traditional Chinese | +| --- | --- | +| data / information | 資料 / 資訊 | +| file / folder | 檔案 / 資料夾 | +| settings / save | 設定 / 儲存 | +| API key / token | API 金鑰 / 權杖 | +| live / load | 即時 / 載入 | +| camera / video | 攝影機 / 影片 | +| network / link | 網路 / 連結 | +| image / imagery | 圖像 / 影像 | +| click / double-click | 點選 / 按兩下 | +| response / timeout | 回應 / 逾時 | +| layer / data layer | 圖層 / 資料圖層 | +| cockpit / context | 駕駛艙 / 態勢 | +| air quality | 空氣品質 | +| transit / bikeshare | 大眾運輸 / 公共自行車 | diff --git a/docs/translations/zh-TW.md b/docs/translations/zh-TW.md deleted file mode 100644 index 8e25c8540..000000000 --- a/docs/translations/zh-TW.md +++ /dev/null @@ -1,36 +0,0 @@ -# Traditional Chinese (`zh-TW`) - -Catalog: `src/i18n/locales/zh-TW.json`. General rules: [TRANSLATORS.md](../TRANSLATORS.md). - -Sources: caxer (#724), tbdavid2019 (#652), and the zh-CN catalog credited to abiyeenzo (#914) and EDIT-Aeterna (#979). The remaining entries were seeded with OpenCC s2twp and edited for Taiwan usage. - -## Style - -- Use Traditional characters and Taiwan terminology. Prefer short, neutral instructions: 「點選地圖」、「儲存金鑰」. -- Use full-width Chinese punctuation and 「」 for quotations. Keep `·`, `…`, provider names, codes and placeholders unchanged. -- Separate Chinese from Latin letters and numbers with a space: 「AIS 船舶」、「24 小時」. Keep unit symbols unchanged: km, m, km/h, m/s, kn, ft, MW, °, %. -- Chinese labels have no uppercase variant. Keep button labels short and avoid splitting short words across lines. -- Browser tags with Hant or TW/HK/MO select this Taiwan catalog. Explicit Hans selects Simplified Chinese, including Hans-TW. This is not a separate Hong Kong localization. - -## Plurals - -`Intl.PluralRules('zh-TW')` uses only `other`. Keep suitable measure words: 「{count} 架飛機」、「{count} 艘船」、「{count} 個金鑰」. - -## Taiwan terminology - -| English | Taiwan | Mainland | -| -------------------- | --------------------- | ------------------- | -| data / information | 資料 / 資訊 | 数据 / 信息 | -| file / folder | 檔案 / 資料夾 | 文件 / 文件夹 | -| settings / save | 設定 / 儲存 | 设置 / 保存 | -| API key / token | API 金鑰 / 權杖 | API 密钥 / 令牌 | -| live / load | 即時 / 載入 | 实时 / 加载 | -| camera / video | 攝影機 / 影片 | 摄像头 / 视频 | -| network / link | 網路 / 連結 | 网络 / 链接 | -| image / imagery | 圖像 / 影像 | 图像 / 影像 | -| click / double-click | 點選 / 按兩下 | 点击 / 双击 | -| response / timeout | 回應 / 逾時 | 响应 / 超时 | -| layer / data layer | 圖層 / 資料圖層 | 图层 / 数据图层 | -| cockpit / context | 駕駛艙 / 態勢 | 座舱 / 态势 | -| air quality | 空氣品質 | 空气质量 | -| transit / bikeshare | 大眾運輸 / 公共自行車 | 公共交通 / 共享单车 | diff --git a/scripts/package-boundaries.json b/scripts/package-boundaries.json index 4f88e858e..ae30a8c49 100644 --- a/scripts/package-boundaries.json +++ b/scripts/package-boundaries.json @@ -442,7 +442,7 @@ "src/i18n/locales/es.json", "src/i18n/locales/ru.json", "src/i18n/locales/zh-CN.json", - "src/i18n/locales/zh-TW.json" + "src/i18n/locales/zh-Hant.json" ], "external": [] }, @@ -469,7 +469,7 @@ "src/i18n/locales/es.json", "src/i18n/locales/ru.json", "src/i18n/locales/zh-CN.json", - "src/i18n/locales/zh-TW.json" + "src/i18n/locales/zh-Hant.json" ], "external": ["cesium"] }, @@ -487,7 +487,7 @@ "src/i18n/locales/es.json", "src/i18n/locales/ru.json", "src/i18n/locales/zh-CN.json", - "src/i18n/locales/zh-TW.json" + "src/i18n/locales/zh-Hant.json" ], "external": [] }, @@ -517,7 +517,7 @@ "src/i18n/locales/es.json", "src/i18n/locales/ru.json", "src/i18n/locales/zh-CN.json", - "src/i18n/locales/zh-TW.json", + "src/i18n/locales/zh-Hant.json", "src/ui/unitLabels.js", "src/ui/keyGuidance.js", "src/ui/statusText.js", @@ -539,7 +539,7 @@ "src/i18n/locales/es.json", "src/i18n/locales/ru.json", "src/i18n/locales/zh-CN.json", - "src/i18n/locales/zh-TW.json" + "src/i18n/locales/zh-Hant.json" ], "external": [] }, @@ -556,7 +556,7 @@ "src/i18n/locales/es.json", "src/i18n/locales/ru.json", "src/i18n/locales/zh-CN.json", - "src/i18n/locales/zh-TW.json" + "src/i18n/locales/zh-Hant.json" ], "external": [] }, @@ -576,7 +576,7 @@ "src/i18n/locales/es.json", "src/i18n/locales/ru.json", "src/i18n/locales/zh-CN.json", - "src/i18n/locales/zh-TW.json", + "src/i18n/locales/zh-Hant.json", "src/ui/unitLabels.js", "src/ui/statusBadge.js" ], @@ -603,7 +603,7 @@ "src/i18n/locales/es.json", "src/i18n/locales/ru.json", "src/i18n/locales/zh-CN.json", - "src/i18n/locales/zh-TW.json", + "src/i18n/locales/zh-Hant.json", "src/ui/layerNames.js" ], "external": [] @@ -638,7 +638,7 @@ "src/i18n/locales/es.json", "src/i18n/locales/ru.json", "src/i18n/locales/zh-CN.json", - "src/i18n/locales/zh-TW.json", + "src/i18n/locales/zh-Hant.json", "src/ui/unitLabels.js" ], "external": ["cesium"] @@ -655,7 +655,7 @@ "src/i18n/locales/es.json", "src/i18n/locales/ru.json", "src/i18n/locales/zh-CN.json", - "src/i18n/locales/zh-TW.json", + "src/i18n/locales/zh-Hant.json", "src/ui/unitLabels.js" ], "external": [] @@ -811,7 +811,7 @@ "src/i18n/locales/es.json", "src/i18n/locales/ru.json", "src/i18n/locales/zh-CN.json", - "src/i18n/locales/zh-TW.json", + "src/i18n/locales/zh-Hant.json", "src/ui/unitLabels.js", "src/ui/keyGuidance.js", "src/ui/layerNames.js", @@ -932,7 +932,7 @@ "src/i18n/locales/es.json", "src/i18n/locales/ru.json", "src/i18n/locales/zh-CN.json", - "src/i18n/locales/zh-TW.json", + "src/i18n/locales/zh-Hant.json", "src/ui/unitLabels.js" ], "external": ["cesium"] @@ -999,7 +999,7 @@ "src/i18n/locales/es.json", "src/i18n/locales/ru.json", "src/i18n/locales/zh-CN.json", - "src/i18n/locales/zh-TW.json", + "src/i18n/locales/zh-Hant.json", "src/ui/unitLabels.js" ], "external": ["cesium"] @@ -1047,7 +1047,7 @@ "src/i18n/locales/es.json", "src/i18n/locales/ru.json", "src/i18n/locales/zh-CN.json", - "src/i18n/locales/zh-TW.json" + "src/i18n/locales/zh-Hant.json" ], "external": ["cesium"] }, @@ -1109,7 +1109,7 @@ "src/i18n/locales/es.json", "src/i18n/locales/ru.json", "src/i18n/locales/zh-CN.json", - "src/i18n/locales/zh-TW.json" + "src/i18n/locales/zh-Hant.json" ], "external": ["cesium"] }, @@ -1139,7 +1139,7 @@ "src/i18n/locales/es.json", "src/i18n/locales/ru.json", "src/i18n/locales/zh-CN.json", - "src/i18n/locales/zh-TW.json", + "src/i18n/locales/zh-Hant.json", "src/ui/unitLabels.js", "src/layers/recentImagery/display.js" ], @@ -1170,7 +1170,7 @@ "src/i18n/locales/es.json", "src/i18n/locales/ru.json", "src/i18n/locales/zh-CN.json", - "src/i18n/locales/zh-TW.json" + "src/i18n/locales/zh-Hant.json" ], "external": ["cesium"] }, @@ -1202,7 +1202,7 @@ "src/i18n/locales/es.json", "src/i18n/locales/ru.json", "src/i18n/locales/zh-CN.json", - "src/i18n/locales/zh-TW.json", + "src/i18n/locales/zh-Hant.json", "src/ui/unitLabels.js" ], "external": ["cesium", "satellite.js"] @@ -1236,7 +1236,7 @@ "src/i18n/locales/es.json", "src/i18n/locales/ru.json", "src/i18n/locales/zh-CN.json", - "src/i18n/locales/zh-TW.json" + "src/i18n/locales/zh-Hant.json" ], "external": ["cesium"] }, @@ -1279,7 +1279,7 @@ "src/i18n/locales/es.json", "src/i18n/locales/ru.json", "src/i18n/locales/zh-CN.json", - "src/i18n/locales/zh-TW.json", + "src/i18n/locales/zh-Hant.json", "src/layers/installations/classLabel.js" ], "external": ["cesium", "@mapbox/vector-tile", "pbf"] @@ -1315,7 +1315,7 @@ "src/i18n/locales/es.json", "src/i18n/locales/ru.json", "src/i18n/locales/zh-CN.json", - "src/i18n/locales/zh-TW.json", + "src/i18n/locales/zh-Hant.json", "src/ui/unitLabels.js" ], "external": ["cesium"] @@ -1366,7 +1366,7 @@ "src/i18n/locales/es.json", "src/i18n/locales/ru.json", "src/i18n/locales/zh-CN.json", - "src/i18n/locales/zh-TW.json" + "src/i18n/locales/zh-Hant.json" ], "external": ["cesium", "pbf", "@mapbox/vector-tile"] }, @@ -1396,7 +1396,7 @@ "src/i18n/locales/es.json", "src/i18n/locales/ru.json", "src/i18n/locales/zh-CN.json", - "src/i18n/locales/zh-TW.json" + "src/i18n/locales/zh-Hant.json" ], "external": ["cesium"] }, @@ -1445,7 +1445,7 @@ "src/i18n/locales/es.json", "src/i18n/locales/ru.json", "src/i18n/locales/zh-CN.json", - "src/i18n/locales/zh-TW.json" + "src/i18n/locales/zh-Hant.json" ], "external": ["hls.js", "cesium"] }, @@ -1509,7 +1509,7 @@ "src/i18n/locales/es.json", "src/i18n/locales/ru.json", "src/i18n/locales/zh-CN.json", - "src/i18n/locales/zh-TW.json", + "src/i18n/locales/zh-Hant.json", "src/layers/streetLevel/providers/mapillary/policy.js" ], "external": ["cesium", "pbf", "@mapbox/vector-tile", "mapillary-js"] @@ -1539,7 +1539,7 @@ "src/i18n/locales/es.json", "src/i18n/locales/ru.json", "src/i18n/locales/zh-CN.json", - "src/i18n/locales/zh-TW.json" + "src/i18n/locales/zh-Hant.json" ], "external": ["cesium", "@mapbox/vector-tile", "pbf"] }, @@ -1580,7 +1580,7 @@ "src/i18n/locales/es.json", "src/i18n/locales/ru.json", "src/i18n/locales/zh-CN.json", - "src/i18n/locales/zh-TW.json" + "src/i18n/locales/zh-Hant.json" ], "external": ["cesium"] }, @@ -1603,7 +1603,7 @@ "src/i18n/locales/es.json", "src/i18n/locales/ru.json", "src/i18n/locales/zh-CN.json", - "src/i18n/locales/zh-TW.json" + "src/i18n/locales/zh-Hant.json" ], "external": ["cesium"] }, @@ -1660,7 +1660,7 @@ "src/i18n/locales/es.json", "src/i18n/locales/ru.json", "src/i18n/locales/zh-CN.json", - "src/i18n/locales/zh-TW.json" + "src/i18n/locales/zh-Hant.json" ], "external": ["cesium"] }, @@ -1717,7 +1717,7 @@ "src/i18n/locales/es.json", "src/i18n/locales/ru.json", "src/i18n/locales/zh-CN.json", - "src/i18n/locales/zh-TW.json", + "src/i18n/locales/zh-Hant.json", "src/ui/statusText.js", "src/voice/providerCommands.js", "src/voice/providerCapabilities.js", @@ -2582,7 +2582,7 @@ "src/i18n/locales/es.json", "src/i18n/locales/ru.json", "src/i18n/locales/zh-CN.json", - "src/i18n/locales/zh-TW.json", + "src/i18n/locales/zh-Hant.json", "src/ui/unitLabels.js", "src/layers/recentImagery/display.js", "src/ui/keyGuidance.js", @@ -3159,7 +3159,7 @@ "src/i18n/locales/es.json", "src/i18n/locales/ru.json", "src/i18n/locales/zh-CN.json", - "src/i18n/locales/zh-TW.json", + "src/i18n/locales/zh-Hant.json", "src/ui/unitLabels.js", "src/layers/recentImagery/display.js", "src/layers/installations/classLabel.js", @@ -3267,7 +3267,7 @@ "src/i18n/locales/es.json", "src/i18n/locales/ru.json", "src/i18n/locales/zh-CN.json", - "src/i18n/locales/zh-TW.json", + "src/i18n/locales/zh-Hant.json", "src/i18n/index.js" ], "external": ["cesium"] @@ -3290,7 +3290,7 @@ "src/i18n/locales/es.json", "src/i18n/locales/ru.json", "src/i18n/locales/zh-CN.json", - "src/i18n/locales/zh-TW.json" + "src/i18n/locales/zh-Hant.json" ], "external": [] }, @@ -3326,7 +3326,7 @@ "src/i18n/locales/es.json", "src/i18n/locales/ru.json", "src/i18n/locales/zh-CN.json", - "src/i18n/locales/zh-TW.json" + "src/i18n/locales/zh-Hant.json" ], "external": ["cesium"] }, @@ -3351,7 +3351,7 @@ "src/i18n/locales/es.json", "src/i18n/locales/ru.json", "src/i18n/locales/zh-CN.json", - "src/i18n/locales/zh-TW.json" + "src/i18n/locales/zh-Hant.json" ], "external": [] }, @@ -3443,7 +3443,7 @@ "src/i18n/locales/es.json", "src/i18n/locales/ru.json", "src/i18n/locales/zh-CN.json", - "src/i18n/locales/zh-TW.json", + "src/i18n/locales/zh-Hant.json", "src/ui/unitLabels.js" ], "external": ["cesium"] @@ -3499,7 +3499,7 @@ "src/i18n/locales/es.json", "src/i18n/locales/ru.json", "src/i18n/locales/zh-CN.json", - "src/i18n/locales/zh-TW.json", + "src/i18n/locales/zh-Hant.json", "src/ui/statusText.js", "src/voice/providerCapabilities.js" ], @@ -3754,7 +3754,7 @@ "src/i18n/locales/es.json", "src/i18n/locales/ru.json", "src/i18n/locales/zh-CN.json", - "src/i18n/locales/zh-TW.json" + "src/i18n/locales/zh-Hant.json" ], "external": ["cesium", "egm96-universal", "pbf"] }, @@ -3798,7 +3798,7 @@ "src/i18n/locales/es.json", "src/i18n/locales/ru.json", "src/i18n/locales/zh-CN.json", - "src/i18n/locales/zh-TW.json" + "src/i18n/locales/zh-Hant.json" ], "external": ["cesium", "pbf"] }, @@ -3852,7 +3852,7 @@ "src/i18n/locales/es.json", "src/i18n/locales/ru.json", "src/i18n/locales/zh-CN.json", - "src/i18n/locales/zh-TW.json" + "src/i18n/locales/zh-Hant.json" ], "external": ["cesium"] }, @@ -3869,7 +3869,7 @@ "src/i18n/locales/es.json", "src/i18n/locales/ru.json", "src/i18n/locales/zh-CN.json", - "src/i18n/locales/zh-TW.json", + "src/i18n/locales/zh-Hant.json", "src/ui/statusText.js", "src/ui/layerNames.js" ], @@ -4063,7 +4063,7 @@ "src/i18n/locales/es.json", "src/i18n/locales/ru.json", "src/i18n/locales/zh-CN.json", - "src/i18n/locales/zh-TW.json", + "src/i18n/locales/zh-Hant.json", "src/ui/statusText.js", "src/ui/layerNames.js" ], diff --git a/src/i18n/firms-live-zh.test.mjs b/src/i18n/firms-live-zh.test.mjs index 9698d5dd6..11878e790 100644 --- a/src/i18n/firms-live-zh.test.mjs +++ b/src/i18n/firms-live-zh.test.mjs @@ -36,7 +36,7 @@ for (const [age, zh, en, tw] of cases) { assert.equal(methods.getStats().loadingLabel, `LIVE · updated ${en}`); setLocale('zh-CN'); assert.equal(methods.getStats().loadingLabel, `实时 · 更新于 ${zh}`); - setLocale('zh-TW'); + setLocale('zh-Hant'); assert.equal(methods.getStats().loadingLabel, `即時 · 更新於 ${tw}`); } finally { setLocale(previousLocale); diff --git a/src/i18n/i18n.test.mjs b/src/i18n/i18n.test.mjs index 87eeed24a..031d4f85e 100644 --- a/src/i18n/i18n.test.mjs +++ b/src/i18n/i18n.test.mjs @@ -39,12 +39,14 @@ test('normalizeLocale folds regional variants and rejects unshipped tags', () => assert.equal(normalizeLocale('zh'), 'zh-CN'); assert.equal(normalizeLocale('zh-CN'), 'zh-CN'); assert.equal(normalizeLocale('zh-Hans-SG'), 'zh-CN'); - assert.equal(normalizeLocale('zh-TW'), 'zh-TW'); - assert.equal(normalizeLocale('zh-Hant-HK'), 'zh-TW'); + assert.equal(normalizeLocale('zh-Hant'), 'zh-Hant'); + assert.equal(normalizeLocale(' ZH_hant '), 'zh-Hant'); + assert.equal(normalizeLocale('zh-TW'), 'zh-Hant'); + assert.equal(normalizeLocale('zh-Hant-HK'), 'zh-Hant'); assert.equal(normalizeLocale('zh-Hans-TW'), 'zh-CN'); - assert.equal(normalizeLocale('zh-Hant-CN'), 'zh-TW'); - assert.equal(normalizeLocale('zh_HK'), 'zh-TW'); - assert.equal(normalizeLocale('zh-MO'), 'zh-TW'); + 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(undefined), null); }); diff --git a/src/i18n/index.js b/src/i18n/index.js index 84776e7dd..6fc4becc9 100644 --- a/src/i18n/index.js +++ b/src/i18n/index.js @@ -19,9 +19,9 @@ import { import es from './locales/es.json' with { type: 'json' }; import ru from './locales/ru.json' with { type: 'json' }; import zhCN from './locales/zh-CN.json' with { type: 'json' }; -import zhTW from './locales/zh-TW.json' with { type: 'json' }; +import zhHant from './locales/zh-Hant.json' with { type: 'json' }; -const CATALOGS = Object.freeze({ es, ru, 'zh-CN': zhCN, 'zh-TW': zhTW }); +const CATALOGS = Object.freeze({ es, ru, 'zh-CN': zhCN, 'zh-Hant': zhHant }); let currentLocale = DEFAULT_LOCALE; diff --git a/src/i18n/locale.js b/src/i18n/locale.js index 4efd4f589..55ed71163 100644 --- a/src/i18n/locale.js +++ b/src/i18n/locale.js @@ -8,15 +8,15 @@ export const LOCALE_STORAGE_KEY = 'gev:locale:v1'; export const DEFAULT_LOCALE = 'en'; /** Shipped locales; order does not matter. Adding one: docs/TRANSLATORS.md. */ -export const LOCALES = Object.freeze(['en', 'es', 'ru', 'zh-CN', 'zh-TW']); +export const LOCALES = Object.freeze(['en', 'es', 'ru', 'zh-CN', 'zh-Hant']); /** Each locale named in its own language, for the selector. */ export const LOCALE_NAMES = Object.freeze({ en: 'English', es: 'Español', ru: 'Русский', - 'zh-CN': '简体中文', - 'zh-TW': '繁體中文', + 'zh-CN': '中文(简体)', + 'zh-Hant': '中文(繁體)', }); /** Right-to-left locales. */ @@ -24,7 +24,8 @@ const RTL_LOCALES = Object.freeze([]); /** * Map any language tag to a shipped locale: 'ru-RU' and 'RU' → 'ru', - * 'zh', 'zh-CN' and 'zh-Hans-SG' → 'zh-CN'. + * 'zh', 'zh-CN' and 'zh-Hans-SG' → 'zh-CN'; + * 'zh-Hant', 'zh-TW', 'zh-HK' and 'zh-MO' → 'zh-Hant'. * @returns {string|null} */ export function normalizeLocale(candidate) { @@ -33,7 +34,7 @@ export function normalizeLocale(candidate) { if (primary === 'zh') { if (rest.includes('hans')) return 'zh-CN'; return rest.some((part) => ['hant', 'tw', 'hk', 'mo'].includes(part)) - ? 'zh-TW' + ? 'zh-Hant' : 'zh-CN'; } return LOCALES.includes(primary) ? primary : null; diff --git a/src/i18n/locales/zh-TW.json b/src/i18n/locales/zh-Hant.json similarity index 100% rename from src/i18n/locales/zh-TW.json rename to src/i18n/locales/zh-Hant.json diff --git a/src/i18n/same-as-english.json b/src/i18n/same-as-english.json index 48688a0c7..d96319535 100644 --- a/src/i18n/same-as-english.json +++ b/src/i18n/same-as-english.json @@ -193,7 +193,7 @@ "ΔN", "▲ {frp} MW" ], - "zh-TW": [ + "zh-Hant": [ "1090 MHz", "978 MHz UAT", "AIS: --", diff --git a/src/i18n/zh-TW-display.test.mjs b/src/i18n/zh-Hant-display.test.mjs similarity index 72% rename from src/i18n/zh-TW-display.test.mjs rename to src/i18n/zh-Hant-display.test.mjs index 74b2f714a..187977cb3 100644 --- a/src/i18n/zh-TW-display.test.mjs +++ b/src/i18n/zh-Hant-display.test.mjs @@ -1,7 +1,12 @@ import test from 'node:test'; import assert from 'node:assert/strict'; import { setLocale, t, tn, getLocale } from './index.js'; -import { resolveLocale, LOCALE_STORAGE_KEY } from './locale.js'; +import { + resolveLocale, + LOCALE_STORAGE_KEY, + writeStoredLocale, + applyDocumentLanguage, +} from './locale.js'; import { hudQuantity, LOCALIZED_LOCALITY } from '../hudLocalityFormat.js'; import { formatCockpitDistance } from '../ui/cockpitPresentation.js'; import { READOUT_WORDS } from '../layers/recentImagery/display.js'; @@ -14,7 +19,7 @@ test('Traditional Chinese resolves from URL, saved preference and browser langua storage: { getItem: () => 'en' }, languages: ['en'], }), - 'zh-TW', + 'zh-Hant', ); assert.equal( resolveLocale({ @@ -24,7 +29,7 @@ test('Traditional Chinese resolves from URL, saved preference and browser langua }, languages: ['en'], }), - 'zh-TW', + 'zh-Hant', ); assert.equal( resolveLocale({ @@ -32,14 +37,29 @@ test('Traditional Chinese resolves from URL, saved preference and browser langua storage: { getItem: () => null }, languages: ['zh-Hant', 'en'], }), - 'zh-TW', + 'zh-Hant', ); }); +test('Traditional Chinese persists and exposes the script locale for legacy choices', () => { + const stored = new Map(); + assert.equal( + writeStoredLocale('zh-TW', { + setItem: (key, value) => stored.set(key, value), + }), + true, + ); + assert.equal(stored.get(LOCALE_STORAGE_KEY), 'zh-Hant'); + const doc = { documentElement: {} }; + assert.equal(applyDocumentLanguage(doc, 'zh-TW'), true); + assert.equal(doc.documentElement.lang, 'zh-Hant'); + assert.equal(doc.documentElement.dir, 'ltr'); +}); + test('Traditional Chinese readouts preserve unit case, coordinates and natural relative dates', () => { const previous = getLocale(); try { - setLocale('zh-TW'); + setLocale('zh-Hant'); assert.equal(hudQuantity(2069, 'km', 1), '2069.0 km'); assert.equal(formatCockpitDistance(14000), '14\u00a0km'); assert.equal( diff --git a/src/ui/localePicker.js b/src/ui/localePicker.js index d60b4e91a..41875042d 100644 --- a/src/ui/localePicker.js +++ b/src/ui/localePicker.js @@ -20,6 +20,11 @@ export const LOCALE_SEARCH_THRESHOLD = 8; /** Type-ahead keystrokes closer together than this extend one prefix. */ export const TYPEAHEAD_RESET_MS = 500; +const CHINESE_LABELS = { + 'zh-CN': 'Chinese (Simplified)', + 'zh-Hant': 'Chinese (Traditional)', +}; + /** * Text folded for search: no diacritics, lower case. 'Español' → 'espanol', * 'Ёжик' → 'ежик'. @@ -464,12 +469,13 @@ export function mountLocalePicker({ item.dataset.locale = option.code; const name = element(documentRef, 'span', 'locale-picker-native'); name.textContent = option.nativeName; - // Every row reads the same: the language named in itself, then its code. - // The interface-language name only helps the search find it. + // Chinese variants are distinguished by script rather than region. const meta = element(documentRef, 'span', 'locale-picker-meta'); const codeLabel = element(documentRef, 'span', 'locale-picker-option-code'); codeLabel.setAttribute('translate', 'no'); - codeLabel.textContent = option.code.toUpperCase(); + codeLabel.textContent = + CHINESE_LABELS[option.code] || option.code.toUpperCase(); + if (CHINESE_LABELS[option.code]) codeLabel.lang = 'en'; meta.append(codeLabel); const text = element(documentRef, 'span', 'locale-picker-text'); text.append(name, meta); diff --git a/src/ui/localePicker.test.mjs b/src/ui/localePicker.test.mjs index 5151ad4fc..057642827 100644 --- a/src/ui/localePicker.test.mjs +++ b/src/ui/localePicker.test.mjs @@ -40,7 +40,7 @@ test('the current language comes first, the rest by their own names', () => { nativeNames: LOCALE_NAMES, }), ), - ['ru', 'en', 'es', 'zh-CN', 'zh-TW'], + ['ru', 'en', 'es', 'zh-CN', 'zh-Hant'], ); assert.deepEqual( codes( @@ -50,7 +50,7 @@ test('the current language comes first, the rest by their own names', () => { nativeNames: LOCALE_NAMES, }), ), - ['es', 'en', 'ru', 'zh-CN', 'zh-TW'], + ['es', 'en', 'ru', 'zh-CN', 'zh-Hant'], ); assert.deepEqual( codes( @@ -60,7 +60,7 @@ test('the current language comes first, the rest by their own names', () => { nativeNames: LOCALE_NAMES, }), ), - ['en', 'es', 'ru', 'zh-CN', 'zh-TW'], + ['en', 'es', 'ru', 'zh-CN', 'zh-Hant'], ); const rows = buildLocaleOptions({ locales: MANY, @@ -263,7 +263,7 @@ test('keyboard model: open on the current language, move, choose, close', () => assert.deepEqual(model.keydown({ key: 'ArrowDown' }), { handled: true }); assert.equal(model.activeOption.code, 'en'); model.keydown({ key: 'End' }); - assert.equal(model.activeOption.code, 'zh-TW'); + assert.equal(model.activeOption.code, 'zh-Hant'); model.keydown({ key: 'Home' }); assert.equal(model.activeOption.code, 'ru'); model.keydown({ key: 'ArrowUp' }); From 6d6b2e8fe9f9ff4a2279148aa8461476ae5a07fb Mon Sep 17 00:00:00 2001 From: Aditya <205600203+Rohilalala@users.noreply.github.com> Date: Tue, 27 Oct 2026 15:52:27 +0530 Subject: [PATCH 04/11] =?UTF-8?q?fix(street-level):=20show=20a=20359.6?= =?UTF-8?q?=C2=B0=20bearing=20as=200=C2=B0,=20not=20360=C2=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The Street Level viewer caption rounded the photo's bearing without wrapping, so a view facing 359.5° or more read "360°". The rounded bearing now wraps to 0°. --- docs/CURRENT-STATE.md | 2 ++ src/ui/streetLevelPresentation.js | 3 ++- src/ui/streetLevelPresentation.test.mjs | 8 ++++++++ 3 files changed, 12 insertions(+), 1 deletion(-) diff --git a/docs/CURRENT-STATE.md b/docs/CURRENT-STATE.md index 0cb46940c..838911b0c 100644 --- a/docs/CURRENT-STATE.md +++ b/docs/CURRENT-STATE.md @@ -3906,6 +3906,8 @@ reports it (`keyAlternatives`), and the panel's KEY REQUIRED, its coverage line and the layer row's tooltip say to light it. The viewer sits under the header with EXPAND, FIT/FILL and close above the image. SINCE is a stepped slider whose readout names the cut-off date. +The viewer caption's bearing wraps after rounding to whole degrees, so a view +facing 359.5° or more reads `0°` rather than `360°`. MapillaryJS loads on the first photo. Opening one frames it with a single camera flight through the application's deferred navigation (`begin` / diff --git a/src/ui/streetLevelPresentation.js b/src/ui/streetLevelPresentation.js index c491ed9bf..2366371f7 100644 --- a/src/ui/streetLevelPresentation.js +++ b/src/ui/streetLevelPresentation.js @@ -168,8 +168,9 @@ function presentViewer(state) { const { street } = state; const right = []; if (street.isPano) right.push('360°'); + // 359.5° and above rounds to north; modulo keeps it from printing 360°. if (Number.isFinite(street.bearing)) - right.push(`${Math.round(street.bearing)}°`); + right.push(`${Math.round(street.bearing) % 360}°`); if (street.capturedAt) right.push(formatDate(street.capturedAt, street.capturedAtPrecision)); const left = []; diff --git a/src/ui/streetLevelPresentation.test.mjs b/src/ui/streetLevelPresentation.test.mjs index b81e203cb..b72e1a5d3 100644 --- a/src/ui/streetLevelPresentation.test.mjs +++ b/src/ui/streetLevelPresentation.test.mjs @@ -273,6 +273,14 @@ test('viewer caption reads "Image by" left, date right, and links to Mapillary', assert.equal(view.viewer.open, true); }); +test('a bearing that rounds to north reads 0°, not 360°', () => { + const caption = (bearing) => + presentStreetLevelPanel(snapshot({ street: { open: true, bearing } })) + .viewer.captionRight; + assert.equal(caption(359.4), '359°'); + assert.equal(caption(359.6), '0°'); +}); + test('an image without a creator name leaves the left caption empty', () => { const view = presentStreetLevelPanel( snapshot({ From 5654be5074a60f82f4de7177284fa4a82d0f7635 Mon Sep 17 00:00:00 2001 From: German Khokhlov Date: Tue, 27 Oct 2026 19:36:35 +0400 Subject: [PATCH 05/11] docs: point Traditional Chinese changelog to replacement PR --- ...{1336-traditional-chinese.md => 1430-traditional-chinese.md} | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) rename changelog.d/{1336-traditional-chinese.md => 1430-traditional-chinese.md} (88%) diff --git a/changelog.d/1336-traditional-chinese.md b/changelog.d/1430-traditional-chinese.md similarity index 88% rename from changelog.d/1336-traditional-chinese.md rename to changelog.d/1430-traditional-chinese.md index c3969d44e..3d34d6536 100644 --- a/changelog.d/1336-traditional-chinese.md +++ b/changelog.d/1430-traditional-chinese.md @@ -1,4 +1,4 @@ - Add Traditional Chinese (zh-Hant) with language selection, and localized Chinese readouts. Based on translations by @caxer (#724), @tbdavid2019 (#652), @abiyeenzo (#914), and @EDIT-Aeterna (#979) - (German, @gekh, #1336). + (German, @gekh, #1430). From 8269facb5af8db92ecf0a875d8894c5438e35eb7 Mon Sep 17 00:00:00 2001 From: German Khokhlov Date: Tue, 27 Oct 2026 19:41:07 +0400 Subject: [PATCH 06/11] i18n: address Traditional Chinese translation review --- docs/translations/zh-Hant.md | 11 ++ src/i18n/locales/zh-Hant.json | 314 +++++++++++++++++----------------- 2 files changed, 168 insertions(+), 157 deletions(-) diff --git a/docs/translations/zh-Hant.md b/docs/translations/zh-Hant.md index 9e3bbfeba..f53a8cd97 100644 --- a/docs/translations/zh-Hant.md +++ b/docs/translations/zh-Hant.md @@ -9,6 +9,7 @@ Sources: caxer (#724), tbdavid2019 (#652), and the zh-CN catalog credited to abi - Use Traditional characters and consistent terminology from the glossary below. Prefer short, neutral instructions: 「點選地圖」、「儲存金鑰」. - Use full-width Chinese punctuation and 「」 for quotations. Keep `·`, `…`, provider names, codes and placeholders unchanged. - Separate Chinese from Latin letters and numbers with a space: 「AIS 船舶」、「24 小時」. Keep unit symbols unchanged: km, m, km/h, m/s, kn, ft, MW, °, %. +- Relative-time placeholders may already include 前. In `LIVE · updated {age}`, the caller supplies the complete relative age; do not append another 前. - Chinese labels have no uppercase variant. Keep button labels short and avoid splitting short words across lines. - The picker displays 中文(繁體) / Chinese (Traditional). Browser tags with Hant or TW/HK/MO select the shared `zh-Hant` catalog. Existing `zh-TW` links and saved choices remain supported. Explicit Hans selects Simplified Chinese, including Hans-TW. @@ -34,3 +35,13 @@ Sources: caxer (#724), tbdavid2019 (#652), and the zh-CN catalog credited to abi | cockpit / context | 駕駛艙 / 態勢 | | air quality | 空氣品質 | | transit / bikeshare | 大眾運輸 / 公共自行車 | + +## Context-sensitive terms + +- Weather `CLEAR` is 晴; `action|CLEAR` is 清除. +- `LOCAL INFO` describes 在地資訊; 本機 refers to the local device. +- Observation windows describe 範圍, not a UI 視窗. The scope control is 視域 and its feather slider is 視域邊緣羽化. +- Roundabouts are 圓環; telemetry is 回報; weather advisories are 發布. +- Intercardinal compass points: NNE 北北東, ENE 東北東, ESE 東南東, SSE 南南東, SSW 南南西, WSW 西南西, WNW 西北西, NNW 北北西. +- The Celestial control and its help text use 天球環. An uncalibrated camera's `RAW PRIOR` is 原始推估. +- `Wind unavailable` is shared by cyclone wind-speed cards and the wind-field layer; keep the wording broad enough for both (風況資料不可用). diff --git a/src/i18n/locales/zh-Hant.json b/src/i18n/locales/zh-Hant.json index 6ef369fae..e86b7d9ab 100644 --- a/src/i18n/locales/zh-Hant.json +++ b/src/i18n/locales/zh-Hant.json @@ -53,7 +53,7 @@ "REFERENCE ONLY · CLAIMS UNVERIFIED": "僅供參考 · 說法未核實", "SOURCE GEOCONFIRMED": "來源位置已核實", "2021 historical reference versus 2026 post-event imagery; changes are cumulative and include the July 2025 Rasuwagadhi flood. Schematic downstream progression, not modeled arrival time; not an official hazard model.": "2021 年歷史參考影像與 2026 年災後影像對比;變化為累計結果,包含 2025 年 7 月的 Rasuwagadhi 洪水。下游演進為示意,並非模擬的到達時間;也不是官方災害模型。", - "Immediate collapse viewpoint": "近距離崩塌觀察點", + "Immediate collapse viewpoint": "初始崩塌觀察點", "Collapse viewpoint": "崩塌觀察點", "Debris-dammed lake": "碎屑堰塞湖", "Dammed lake": "堰塞湖", @@ -140,7 +140,7 @@ "FIELD REPORTS · {count}": "現場報道 · {count}", "GEOLOCATIONS · {credit}": "地理定位 · {credit}", "↗ OPEN PUBLIC MAP": "↗ 開啟公共地圖", - " Clouds are preserved from the source imagery.": "雲層按源影像原樣保留。", + " Clouds are preserved from the source imagery.": "雲層按原始影像原樣保留。", "Rasuwagadhi witness": "Rasuwagadhi 目擊者", "Open original source for {source}; capture time unverified": "開啟 {source} 的原始來源;拍攝時間未核實", "Historical reference and post-event image divider": "歷史參考與災後影像的分割線", @@ -263,11 +263,11 @@ "STATION": "太空站", "Crewed stations and their visiting vehicles": "載人太空站與來訪載具", "NAV": "導航", - "GNSS navigation — GPS, GLONASS, Galileo": "GNSS 導航衛星 — GPS、GLONASS、Galileo", + "GNSS navigation — GPS, GLONASS, Galileo": "GNSS 導航衛星——GPS、GLONASS、Galileo", "GEO": "GEO", - "Geostationary belt — comms and weather, fixed over the equator": "地球同步軌道帶 — 通訊與氣象衛星,固定於赤道上空", + "Geostationary belt — comms and weather, fixed over the equator": "地球同步軌道帶——通訊與氣象衛星,固定於赤道上空", "VISUAL": "目視可見", - "Brightest naked-eye objects — CelesTrak visual group": "肉眼最亮天體 — CelesTrak 目視群組", + "Brightest naked-eye objects — CelesTrak visual group": "肉眼最亮天體——CelesTrak 目視群組", "COMMS": "通訊", "Broadband constellation shell — shown only in DENSE mode": "寬頻星座殼層——僅在「密集」模式下顯示", "FISHING": "漁船", @@ -322,7 +322,7 @@ "NORTHERN OCEANIC GRID": "北方海洋網格", "SOUTHERN OCEANIC GRID": "南方海洋網格", "LOADING": "載入中", - "DEGRADED": "效能受限", + "DEGRADED": "資料品質下降", "STALE": "資料過期", "PARTIAL": "部分可用", "FALLBACK": "備用模式", @@ -369,9 +369,9 @@ "{name} may only contain printable characters with no spaces": "{name} 只能包含可列印字元,且不能有空格", "{name} contains a character that is not valid in a key (#, quotes, $, \\, or backtick)": "{name} 包含金鑰中不允許的字元(#、引號、$、\\ 或反引號)", "{name} is configured outside Provider Settings and can only be changed where it was set": "{name} 是在服務供應商設定之外配置的,只能在原設定處修改", - "The key was not saved: could not restrict the credential file to your account; nothing was saved": "金鑰未儲存:無法將憑據檔案限制為僅你的賬戶可訪問;未儲存任何內容", + "The key was not saved: could not restrict the credential file to your account; nothing was saved": "金鑰未儲存:無法將憑據檔案限制為僅你的帳戶可訪問;未儲存任何內容", "The key was not saved: the existing configuration could not be read, so nothing was changed": "金鑰未儲存:無法讀取現有配置,因此未做任何更改", - "Could not write the {store} store": "無法寫入 {store} 儲存", + "Could not write the {store} store": "無法寫入 {store}", "Save failed ({status}).": "儲存失敗({status})。", "OAuth check failed: {detail}": "OAuth 檢查失敗:{detail}", "Could not check ChatGPT sign-in. Try again.": "無法檢查 ChatGPT 登入狀態,請重試。", @@ -381,13 +381,13 @@ "USE CHATGPT OAUTH": "使用 CHATGPT OAUTH", "Use OPENAI_API_KEY for the next cloud voice session": "下次雲語音工作階段使用 OPENAI_API_KEY", "Use the signed-in local ChatGPT/Codex OAuth session for the next cloud voice session": "下次雲語音工作階段使用本機已登入的 ChatGPT/Codex OAuth 工作階段", - "Metered — a billing-enabled account": "計費 — 需啟用帳單的帳戶", + "Metered — a billing-enabled account": "計費——需啟用帳單的帳戶", "Optional paid token — public access works without one": "可選的付費權杖——無需權杖也可公開訪問", - "Free key — register, paste, done": "免費金鑰 — 註冊、貼上、完成", + "Free key — register, paste, done": "免費金鑰——註冊、貼上、完成", "browser-side": "瀏覽器端", - "This key runs in the browser by design — restrict it at the provider (see SECURITY.md)": "此金鑰設計上在瀏覽器執行 — 請在供應商端設定限制(見 SECURITY.md)", + "This key runs in the browser by design — restrict it at the provider (see SECURITY.md)": "此金鑰設計上在瀏覽器執行——請在供應商端設定限制(見 SECURITY.md)", "configured externally": "已在外部設定", - "Supplied by your environment, Keychain, or launcher — change it where it was set": "由你的環境、鑰匙串或啟動器提供——請在原設定處修改", + "Supplied by your environment, Keychain, or launcher — change it where it was set": "由你的環境、鑰匙圈或啟動器提供——請在原設定處修改", "MANAGE ↗": "管理 ↗", "GET KEY ↗": "取得金鑰 ↗", "{envVar} saved — paste to replace": "{envVar} 已儲存——貼上可替換", @@ -415,20 +415,20 @@ "Remove this key from your saved configuration?": "要從已儲存的配置中移除此金鑰嗎?", "Removed from {store}. Restarting — this page reloads itself.": "已從 {store} 中移除。正在重啟——本頁面將自動重新載入。", "The photorealistic 3D planet, place search + Street View": "照片級逼真 3D 地球、地點搜尋 + 街景", - "Places context + Street View fallback; optional separate key": "地點資訊 + 街景備援;可選用獨立金鑰", + "Places context + Street View fallback; optional separate key": "地點資訊 + 街景備援;可選用獨立金鑰", "Voice control — API key or ChatGPT OAuth": "語音控制——API 金鑰或 ChatGPT OAuth", "Live ships, worldwide": "全球即時船舶", "Live active-fire detections": "即時野火偵測", - "Real live traffic (keyless runs a simulation)": "真實即時路況(無金鑰時為模擬)", + "Real live traffic (keyless runs a simulation)": "真實即時路況(無金鑰時為模擬)", "Bing imagery map stacks + world terrain": "Bing 影像圖層 + 全球地形", - "More flight-polling credits (anonymous works without)": "更多航班查詢額度(匿名也可使用)", - "Street-level imagery and coverage in the Street Level layer. Free: register an app in the Mapillary developer dashboard and paste its Client Token": "街景影像與街景圖層中的覆蓋範圍。免費:在 Mapillary 開發者控制檯註冊一個應用,並貼上其 Client Token", + "More flight-polling credits (anonymous works without)": "更多航班查詢額度(匿名也可使用)", + "Street-level imagery and coverage in the Street Level layer. Free: register an app in the Mapillary developer dashboard and paste its Client Token": "街景影像與街景圖層中的覆蓋範圍。免費:在 Mapillary 開發者控制台註冊一個應用,並貼上其 Client Token", "Public space-missions access needs no key. Leave blank for standard use; paid tokens only raise request limits.": "公開的太空任務資料無需金鑰。常規使用請留空;付費權杖只會提高請求上限。", "Air quality request failed": "空氣品質請求失敗", "No readings available": "暫無讀數", "No current readings": "暫無最新讀數", "{count} stations reporting": { - "other": "{count} 個站點上報資料" + "other": "{count} 個站點回報資料" }, "Highest air-quality readings in view": "視野內空氣品質讀數最高的站點", "Low": "低", @@ -440,7 +440,7 @@ "Very High": "極高", "Very High health risk": "極高健康風險", "Air quality": "空氣品質", - "Canada only · ECCC AQHI network": "僅限加拿大 · ECCC AQHI 站網", + "Canada only · ECCC AQHI network": "僅限加拿大 · ECCC AQHI 監測網", "ECCC request timed out": "ECCC 請求逾時", "Malformed AQHI station response": "AQHI 站點回應格式錯誤", "No AQHI stations available": "沒有可用的 AQHI 站點", @@ -450,7 +450,7 @@ "SHOW NEAREST": "顯示最近", "Stop following the current object before navigating to a camera": "請先停止追蹤目前目標,再前往攝影機", "Move to the nearest loaded camera and show its details": "前往最近已載入的攝影機並顯示詳情", - "Camera badges": "攝影機標章", + "Camera badges": "攝影機標記", "Cyan cameras turn coral when selected. Wedges illustrate mapped direction, not measured coverage. Nearby cameras may be outside the screen.": "選中後青色攝影機變為珊瑚色。扇形僅示意已標繪方向,並非實測覆蓋範圍。附近的攝影機可能不在螢幕內。", "{count} nearby · {onScreen} on screen": { "other": "附近 {count} 個 · 螢幕上 {onScreen} 個" @@ -478,13 +478,13 @@ "Unavailable": "不可用", "Focus {label}": "聚焦 {label}", "Global Context navigation": "全域態勢導航", - "Previous — prior visited contact in the 250 km window": "上一個 — 250 公里範圍內先前造訪的目標", + "Previous — prior visited contact in the 250 km window": "上一個——250 公里範圍內先前造訪的目標", "PREVIOUS": "上一個", "FOCUS": "聚焦", - "Next — nearest unvisited contact in the 250 km window": "下一個 — 250 公里範圍內最近的未造訪目標", + "Next — nearest unvisited contact in the 250 km window": "下一個——250 公里範圍內最近的未造訪目標", "NEXT": "下一個", "Named areas ({n})": "已命名區域({n})", - "{distance} FLIGHT / VESSEL WINDOW": "{distance} 航班 / 船舶監視視窗", + "{distance} FLIGHT / VESSEL WINDOW": "{distance} 航班 / 船舶監視範圍", "Open-source mapped/observed context. Missing broadcasts, unloaded map areas, or unmapped sites are not evidence of absence.": "開源的地圖標註/觀測態勢資訊。缺失的廣播、未載入的地圖區域或未標註的設施不能作為不存在的證據。", "mapped matches within {km} km of the subject": "所選物件 {km} km 內的地圖標註匹配", "none mapped within {km} km; not a complete 250 km survey": "{km} km 內無地圖標註;並非完整的 250 km 普查", @@ -499,7 +499,7 @@ "Flights": "航班", "Military flights": "軍機", "AIS vessels": "AIS 船舶", - "Mapped installations": "已標記軍事設施", + "Mapped installations": "地圖標註設施", "syncing {count} city feeds...": "正在同步 {count} 個城市資料來源…", "scanning nearby systems...": "正在掃描附近系統…", "GBFS fetch error": "GBFS 取得錯誤", @@ -545,7 +545,7 @@ }, "Position as of {time}": "位置(截至 {time})", "Maximum sustained wind: {wind} · Pressure: {pressure}": "最大持續風速:{wind} · 氣壓:{pressure}", - "{name} · {classification} · Advisory {number} · issued {time}": "{name} · {classification} · 第 {number} 號公告 · 釋出於 {time}", + "{name} · {classification} · Advisory {number} · issued {time}": "{name} · {classification} · 第 {number} 號公告 · 發布於 {time}", "No active NHC/CPHC systems": "目前沒有活躍的 NHC/CPHC 氣旋", "Advisories unavailable": "公告不可用", "Cyclones · NHC / CPHC": "氣旋 · NHC / CPHC", @@ -553,7 +553,7 @@ "{storms} · {name} selected": "{storms} · 已選擇 {name}", "Official advisory ↗": "官方公告 ↗", "Active NHC and CPHC cyclone advisories": "活躍的 NHC 與 CPHC 氣旋公告", - "Wind unavailable": "風場資料不可用", + "Wind unavailable": "風況資料不可用", "Advisory center / forecast track": "公告中的氣旋中心 / 預報路徑", "Center-track uncertainty cone": "中心路徑預報不確定範圍", "Select a storm on the map, or choose a storm in the list to select it and move the camera. Click empty map space to clear the selection. NOAA NHC/CPHC advisory context. The cone describes forecast center-track uncertainty, not storm size or the full hazard area. Forecast point labels are source lead hours, not times computed from advisory issuance. Geometry follows the surface; height is not weather altitude. Consult the official advisory.": "在地圖上點選氣旋,或在清單中點選氣旋,即可選中並移動相機。點選空白地圖區域可清除選擇。內容來自 NOAA NHC/CPHC 公告。該區域表示氣旋中心路徑預報的不確定範圍,不代表氣旋大小或全部災害影響範圍。預報點標註的是資料來源的預報時效(小時),不是按公告發布時刻推算的時間。幾何圖形貼地顯示;顯示高度並非氣象高度。請以官方公告為準。", @@ -632,16 +632,16 @@ "Take the exit on the {direction}": "從出口{direction}駛出", "Take the exit onto {road}": "從出口駛出,進入 {road}", "Take the exit": "從出口駛出", - "At the roundabout, take the {exit} exit onto {road}": "在環島從{exit}出口駛出,進入 {road}", - "At the roundabout, take the {exit} exit": "在環島從{exit}出口駛出", - "Enter the roundabout onto {road}": "駛入環島,進入 {road}", - "Enter the roundabout": "駛入環島", - "At the roundabout, turn {direction} onto {road}": "在環島{direction}轉,進入 {road}", - "At the roundabout, turn {direction}": "在環島{direction}轉", - "At the roundabout, continue onto {road}": "在環島繼續行駛,進入 {road}", - "At the roundabout, continue": "在環島繼續行駛", - "Exit the roundabout onto {road}": "駛出環島,進入 {road}", - "Exit the roundabout": "駛出環島", + "At the roundabout, take the {exit} exit onto {road}": "在圓環從{exit}出口駛出,進入 {road}", + "At the roundabout, take the {exit} exit": "在圓環從{exit}出口駛出", + "Enter the roundabout onto {road}": "駛入圓環,進入 {road}", + "Enter the roundabout": "駛入圓環", + "At the roundabout, turn {direction} onto {road}": "在圓環{direction}轉,進入 {road}", + "At the roundabout, turn {direction}": "在圓環{direction}轉", + "At the roundabout, continue onto {road}": "在圓環繼續行駛,進入 {road}", + "At the roundabout, continue": "在圓環繼續行駛", + "Exit the roundabout onto {road}": "駛出圓環,進入 {road}", + "Exit the roundabout": "駛出圓環", "Use the {direction} lane onto {road}": "使用{direction}車道,進入 {road}", "Use the {direction} lane": "使用{direction}車道", "Continue onto {road}": "繼續行駛,進入 {road}", @@ -683,7 +683,7 @@ "Routing timed out": "路線規劃逾時", "Routing unavailable — no response from the routing service": "路線規劃不可用——路線服務無回應", "Earthquake source unavailable": "地震資料來源不可用", - "Focus fire detection {title}, {details}": "聚焦火點探測 {title},{details}", + "Focus fire detection {title}, {details}": "聚焦火點偵測 {title},{details}", "live feed unavailable": "即時資料來源不可用", "{value} conf": "置信度 {value}", "{value} ago": "{value}前", @@ -721,12 +721,12 @@ "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 30 min": "區域取樣 · 半徑 250 海里 · 30 分鐘內已瀏覽視野中的網格", "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 海里的範圍;縮小地圖並不會使其成為全球快照。空白網格位於取樣覆蓋範圍之外,或觀測資料不足。", "Low-accuracy score = 100 × max(0, bad − 1) / total: one aircraft is discounted, so this is not the raw share. Cells need {aircraft} aircraft over {minutes} minutes. Navigation-integrity anomalies are not a detection of jamming or spoofing.": "低精度評分 = 100 × max(0, bad − 1) / total:扣除一架飛機,因此並非原始佔比。每個網格需在 {minutes} 分鐘內有 {aircraft} 架飛機。導航完好性異常不等於檢測到干擾或欺騙。", - "GNSS snapshot needs a view anchor": "GNSS 快照需要檢視錨點", + "GNSS snapshot needs a view anchor": "GNSS 快照需要視野錨點", "GNSS feed rate limited (HTTP 429)": "GNSS 資料來源已被限流(HTTP 429)", "Malformed GNSS integrity snapshot": "GNSS 完好性快照格式錯誤", "GNSS integrity snapshot has no observation time": "GNSS 完好性快照缺少觀測時間", @@ -799,7 +799,7 @@ "FINAL POSITION": "最終位置", "REPLAY SPEED": "回放速度", "Replay speed multiplier": "回放速度倍率", - "REPLAY ASCENT": "重播升空", + "REPLAY ASCENT": "回放升空", "Previous mission": "上一個任務", "PREV": "上一個", "Next mission": "下一個任務", @@ -810,7 +810,7 @@ "PLANNED · ": "計畫 · ", "SUPPLIED TRAJECTORY POINTS": "提供的軌跡點", "RECONSTRUCTED ESTIMATE": "重建估算", - "Replay the estimated ascent with a following camera": "以跟隨鏡頭重播推估的升空過程", + "Replay the estimated ascent with a following camera": "以跟隨鏡頭回放推估的升空過程", "Resume replay": "繼續回放", "T minus {seconds}": "T−{seconds}", "Preparing launch site": "正在準備發射場", @@ -878,7 +878,7 @@ "part of {complex}": "屬於 {complex} 複合火場", "InciWeb ↗ · click card to open": "InciWeb ↗ · 點選卡片開啟", "FIRE · {name}": "火場 · {name}", - "Unnamed incident": "未命名火情", + "Unnamed incident": "未命名事件", "Open {title} on InciWeb": "在 InciWeb 上開啟 {title}", "Perimeter source unavailable": "周界資料來源不可用", "Not contained or unknown": "未控制或未知", @@ -890,7 +890,7 @@ "radio tag|All": "全部", "News": "新聞", "Talk": "談話", - "Weather / Emergency": "氣象/緊急", + "Weather / Emergency": "氣象 / 緊急", "Public Safety": "公共安全", "Aviation / Marine": "航空/海事", "Traffic / Transit": "交通/運輸", @@ -950,19 +950,19 @@ "Daily overview for today may still be empty until the pass": "衛星過境前,今天的每日概覽可能仍為空", "Box and images cleared": "框選及影像已清除", "MORE DETAIL · 30 m": "更多細節 · 30 m", - "Sentinel-2 and Landsat via HLS, 30 m, every 2–6 days": "Sentinel-2 與 Landsat,經 HLS,30 m,每 2–6 天", + "Sentinel-2 and Landsat via HLS, 30 m, every 2–6 days": "Sentinel-2 與 Landsat,透過 HLS,30 m,每 2–6 天", "DAILY OVERVIEW · 250 m": "每日概覽 · 250 m", "VIIRS daily mosaic, 250 m, follows broad changes; little detail under 25 km": "VIIRS 每日鑲嵌圖,250 m,反映大範圍變化;25 km 以下幾乎沒有細節", "Sentinel-2": "Sentinel-2", - "Sentinel-2 via HLS": "Sentinel-2(經 HLS)", + "Sentinel-2 via HLS": "Sentinel-2(透過 HLS)", "Landsat 8/9": "Landsat 8/9", - "Landsat 8/9 via HLS": "Landsat 8/9(經 HLS)", + "Landsat 8/9 via HLS": "Landsat 8/9(透過 HLS)", "Daily overview": "每日概覽", "Box edges must be finite": "框選邊界必須是有限值", "Longitudes must be within ±180°": "經度必須在 ±180° 以內", "Select one side of the dateline": "請只選擇日界線的一側", "Box must enclose an area": "框選必須包含一定面積", - "Add the full Starlink broadband shell (thousands of extra points)": "加入完整 Starlink 寬頻星座(額外數千個點)", + "Add the full Starlink broadband shell (thousands of extra points)": "加入完整 Starlink 寬頻星座(額外數千個點)", "Loading the Starlink shell…": "正在載入 Starlink 星座…", "Starlink {detail} — click to retry": "Starlink {detail}——點選重試", "load failed": "載入失敗", @@ -973,7 +973,7 @@ "CelesTrak unreachable": "CelesTrak 無法連線", "DOCKED · {name} · +{extra}": "對接 · {name} · +{extra}", "DOCKED · {name}": "對接 · {name}", - "{name} needs the Google 3D map: choose it under MAP SOURCE": "{name} 需要 Google 3D 地圖:請在地圖源(MAP SOURCE)中選擇", + "{name} needs the Google 3D map: choose it under MAP SOURCE": "{name} 需要 Google 3D 地圖:請在地圖來源(MAP SOURCE)中選擇", "zoom in to a street to open {name}": "放大到街道以開啟 {name}", "KEY REJECTED": "金鑰被拒絕", "loading coverage...": "正在載入覆蓋範圍…", @@ -1001,7 +1001,7 @@ "KartaView is rate-limiting requests — they resume on their own": "KartaView 已被限流——稍後會自動恢復", "KartaView’s photos here are archived and cannot be shown": "KartaView 在此處的照片已歸檔,無法顯示", "KartaView did not filter this area in time — move the map to ask again": "KartaView 未能及時篩選此區域——移動地圖以重新請求", - "None of KartaView’s photos here pass the imagery filter": "此處沒有 KartaView 照片透過影像篩選", + "None of KartaView’s photos here pass the imagery filter": "此處沒有 KartaView 照片通過影像篩選", "KartaView did not answer in time — try again": "KartaView 未及時回應——請重試", "KartaView could not be reached — check the network": "無法連線 KartaView——請檢查網路", "KartaView sent an answer that could not be read": "KartaView 返回的回應無法讀取", @@ -1009,7 +1009,7 @@ "KartaView sent too much data": "KartaView 返回的資料過多", "KartaView is rate-limiting requests — try again in a moment": "KartaView 已被限流——請稍後重試", "KartaView has no such photo": "KartaView 沒有這張照片", - "Mapillary rejected MAPILLARY_CLIENT_TOKEN — replace it in Provider Settings": "Mapillary 拒絕了 MAPILLARY_CLIENT_TOKEN——請在服務供應商設定中更換", + "Mapillary rejected MAPILLARY_CLIENT_TOKEN — replace it in Provider Settings": "Mapillary 拒絕了 MAPILLARY_CLIENT_TOKEN——請在服務供應商設定中更換該權杖", "Coverage requests are being rate-limited — they resume on their own": "覆蓋範圍請求已被限流——稍後會自動恢復", "The Panoramax photo could not be loaded": "Panoramax 照片無法載入", "Panoramax is busy — coverage resumes on its own": "Panoramax 繁忙——覆蓋範圍稍後會自動恢復", @@ -1059,7 +1059,7 @@ "LIVE · Roads: OpenStreetMap · Flow: TomTom · {percent}% cov": "即時 · 道路:OpenStreetMap · 路況:TomTom · 覆蓋 {percent}%", "SIMULATED · Roads: OpenStreetMap · Flow: TomTom (no matches)": "模擬 · 道路:OpenStreetMap · 路況:TomTom(無匹配)", "SIMULATED — traffic service unreachable": "模擬——交通服務無法連線", - "SIMULATED — add TomTom key for live": "模擬中 — 加入 TomTom 金鑰以取得即時路況", + "SIMULATED — add TomTom key for live": "模擬——加入 TomTom 金鑰以取得即時路況", "OpenFreeMap tiles rate-limited": "OpenFreeMap 瓦片已被限流", "OpenFreeMap tiles timed out": "OpenFreeMap 瓦片逾時", "OpenFreeMap tiles unavailable": "OpenFreeMap 瓦片不可用", @@ -1077,14 +1077,14 @@ "No recent fix": "無近期定位", "Waiting for update": "等待更新", "Moving": "行駛中", - "reported {speed} km/h": "上報 {speed} km/h", - "reported hdg {heading}°": "上報航向 {heading}°", - "Last report: stopped at stop {stop}": "最近上報:停靠站點 {stop}", - "Last report: arriving at stop {stop}": "最近上報:即將到達站點 {stop}", - "Last report: next stop {stop}": "最近上報:下一站 {stop}", + "reported {speed} km/h": "回報 {speed} km/h", + "reported hdg {heading}°": "回報航向 {heading}°", + "Last report: stopped at stop {stop}": "最近回報:已停靠於站點 {stop}", + "Last report: arriving at stop {stop}": "最近回報:即將到達站點 {stop}", + "Last report: next stop {stop}": "最近回報:下一站 {stop}", "Shown at street level · depth not in the feed": "按地面高度顯示 · 資料來源未提供深度", - "Reported {seconds} s ago": "{seconds} 秒前上報", - "Reported {minutes} min ago": "{minutes} 分鐘前上報", + "Reported {seconds} s ago": "{seconds} 秒前回報", + "Reported {minutes} min ago": "{minutes} 分鐘前回報", "shown {seconds} s behind": "顯示滯後 {seconds} 秒", "{reported} (feed time)": "{reported}(資料來源時間)", "Available trail: {minutes} min (limited)": "可用軌跡:{minutes} 分鐘(受限)", @@ -1120,7 +1120,7 @@ "feed down — retrying slowly": "資料來源中斷——正在低頻重試", "reconnecting to feed…": "正在重新連線資料來源…", "Focus vessel {name}, MMSI {mmsi}": "聚焦船舶 {name},MMSI {mmsi}", - "Hidden by this map source · choose a globe map": "已被目前地圖源隱藏 · 請選擇地球地圖", + "Hidden by this map source · choose a globe map": "已被目前地圖來源隱藏 · 請選擇地球地圖", "Weather image HTTP {status}": "天氣圖像 HTTP {status}", "Weather HTTP {status}": "天氣 HTTP {status}", "Frame unavailable; previous observation retained": "幀不可用;保留上一幀觀測", @@ -1219,7 +1219,7 @@ "Reduced motion": "減弱動效", "Resume": "繼續", "Pause": "暫停", - "Pause visual flow; forecast time does not advance with animation": "暫停流動動畫;預報時次不會隨動畫推進", + "Pause visual flow; forecast time does not advance with animation": "暫停流動動畫;預報時間不會隨動畫推進", "None": "無", "Speed": "風速", "Pressure": "氣壓", @@ -1227,14 +1227,14 @@ "Wind trails with no field shading": "僅顯示風場流線,不疊加氣象場填色", "How hard the surface wind is blowing": "地面風有多大", "Sea-level air pressure: broad highs and lows": "海平面氣壓:大範圍的高壓與低壓", - "Air temperature two meters above the surface": "地面以上兩米的氣溫", + "Air temperature two meters above the surface": "地面以上 2 公尺的氣溫", "Wind speed units": "風速單位", "Read wind at map center": "讀取地圖中心風況", "Read the forecast at the center of the map without changing selection": "讀取地圖中心的預報值,不改變目前選擇", "{model} forecast · {field} ({unit})": "{model} 預報 · {field}({unit})", "Valid: {time}": "有效時間:{time}", "preparing": "準備中", - "Issued: {time}": "釋出時間:{time}", + "Issued: {time}": "發布時間:{time}", "Selected field unavailable · wind remains visible": "所選氣象場不可用 · 風場仍可見", "{error} · wind remains visible": "{error} · 風場仍可見", "Surface wind at 10 m. Approximately 1° global grid. Curves follow the 10 m wind field, lifted 12 km for visibility; display height is not weather altitude. View lighting is for readability. Animation shows flow through one fixed forecast; it does not advance time. Color fields drape the globe basemap or the active photorealistic 3D Tiles.": "10 m 高度的地面風。約 1° 全球網格。流線沿 10 m 風場繪製,為便於觀看抬升至 12 km;顯示高度並非氣象高度。檢視光照僅為提高可讀性。動畫展示的是單一固定預報內的流場,不推進時間。氣象場填色疊加於地球底圖或目前的照片級逼真 3D Tiles。", @@ -1243,18 +1243,18 @@ "UNITS": "單位", "MOTION": "運動", "Forecast": "預報", - "NNE": "北東北", + "NNE": "北北東", "NE": "東北", - "ENE": "東東北", - "ESE": "東東南", + "ENE": "東北東", + "ESE": "東南東", "SE": "東南", - "SSE": "南東南", - "SSW": "南西南", + "SSE": "南南東", + "SSW": "南南西", "SW": "西南", - "WSW": "西西南", - "WNW": "西西北", + "WSW": "西南西", + "WNW": "西北西", "NW": "西北", - "NNW": "北西北", + "NNW": "北北西", "No surface reading": "暫無地表讀數", "Aim the map center at Earth": "請將地圖中心對準地球", "A location reading needs a loaded forecast and the Earth at the center of the view.": "位置讀數需要已載入的預報,且地圖中心對準地球。", @@ -1382,14 +1382,14 @@ }, "{scene} / {pack}: {status}. File: {path}. {attribution} · {license}": "{scene} / {pack}:{status}。檔案:{path}。{attribution} · {license}", "Unavailable layers: {layers}": "不可用圖層:{layers}", - "Uses registered content or linked media. Those external files are not included in a scene bundle. Their original notices still apply.": "使用了已註冊內容或連結媒體。這些外部檔案不包含在場景資源包中。其原始宣告仍然適用。", + "Uses registered content or linked media. Those external files are not included in a scene bundle. Their original notices still apply.": "使用了已註冊內容或連結媒體。這些外部檔案不包含在場景資源包中。其原始聲明仍然適用。", "{bytes} bundled bytes verified. Files stay in memory for this session. Reimport the bundle after reloading the app.": "已校驗打包內容 {bytes} 位元組。檔案僅保留在本次工作階段的記憶體中。重新載入應用後請再次匯入資源包。", "Review scene import": "場景匯入預覽", "Nothing is loaded or changed until you apply this file.": "確認匯入此檔案前,不會載入或更改任何內容。", "Ready to import": "可以匯入", "Apply replaces the current project. Export your current project first if you want to keep both.": "應用後將替換目前專案。如需同時保留兩者,請先匯出目前專案。", "Apply import": "確認匯入", - "Import was not applied. The current project may have changed.": "未執行匯入。目前專案可能已發生變化。", + "Import was not applied. The current project may have changed.": "匯入未套用。目前專案可能已發生變化。", "Select a scene and shot first": "請先選擇場景和鏡頭", "Edit scene details": "編輯場景詳情", "Camera positions use degrees and meters above the ellipsoid. Drafts are validated before they replace your saved scene.": "相機經緯度以度為單位,高度以米為單位(相對橢球面)。草稿透過校驗後才會替換已儲存的場景。", @@ -1402,7 +1402,7 @@ "Move added to draft; destination remains the shot camera": "運鏡已加入草稿;終點仍為該鏡頭的相機位置", "Use ordinary flight": "使用普通飛行", "Invalid shot JSON": "鏡頭 JSON 無效", - "Apply details": "應用詳情", + "Apply details": "套用詳細資料", "Select a scene first": "請先選擇一個場景", "Share selected scene": "分享所選場景", "Scene JSON preserves authored settings and attribution. It does not include asset files. Bundles include only pack files you choose here or previously imported bundle files.": "場景 JSON 保留創作設定與署名資訊。它不包含資源檔案。資源包僅包含你在此選擇的包檔案或先前匯入的資源包檔案。", @@ -1432,9 +1432,9 @@ "Browser audio is suspended; select FM again to resume it": "瀏覽器音訊已掛起;再次選擇 FM 以恢復", "RTL-SDR gain change failed": "RTL-SDR 增益調整失敗", "Tuned to {mhz} MHz FM": "已調諧到 FM {mhz} MHz", - "Seeking up…": "正在向上搜臺…", - "Seeking down…": "正在向下搜臺…", - "Seek stopped": "搜臺已停止", + "Seeking up…": "正在向上搜台…", + "Seeking down…": "正在向下搜台…", + "Seek stopped": "搜台已停止", "Scanning {mhz} MHz…": "正在掃描 {mhz} MHz…", "Found {mhz} MHz · {snr} dB": "找到 {mhz} MHz · {snr} dB", "FM signal found at {mhz} MHz": "在 {mhz} MHz 找到 FM 訊號", @@ -1467,8 +1467,8 @@ "Switching language reloads the page. This will be lost: {items}. Switch anyway?": "切換語言會重新載入頁面。以下內容將會丟失:{items}。仍要切換嗎?", "VISUAL PRESETS": "視覺預設", "LOCATION": "位置", - "CONTACTS — nearest planes · vessels · sites": "目標 — 最近的飛機 · 船舶 · 設施", - "SPACE MISSIONS — launches & orbital assets": "太空任務 — 發射與軌道資產", + "CONTACTS — nearest planes · vessels · sites": "目標——最近的飛機 · 船舶 · 設施", + "SPACE MISSIONS — launches & orbital assets": "太空任務——發射與軌道資產", "LIVE SIGNALS": "即時訊號", "CCTV layer unavailable": "CCTV 圖層不可用", "Link copied!": "連結已複製!", @@ -1489,7 +1489,7 @@ "ΔE": "ΔE", "{value}m": "{value} m", "CCTV calibration reset": "CCTV 校準已重置", - "ADJUST ON": "調整開", + "ADJUST ON": "調整 開", "ADJUST": "調整", "SNAPSHOT": "快照", "LIVE": "即時", @@ -1511,7 +1511,7 @@ "No source configured": "未設定來源", "Configured source": "已配置來源", "Configured Source": "已配置資料來源", - "Synthetic fallback": "合成備用", + "Synthetic fallback": "合成備援", "Upstream HTTP {status}": "上游 HTTP {status}", "Unexpected media type {type}": "意外的媒體型別 {type}", "SOURCE · UNKNOWN": "來源 · 未知", @@ -1519,10 +1519,10 @@ "FRAME · UNAVAILABLE": "畫面 · 無法使用", "CALIBRATED": "已校準", "CURATED": "精選", - "RAW PRIOR": "原始預設", - "CCTV ON": "監視器 開", - "CCTV OFF": "監視器 關", - "VIEWSHED ON": "可視域開", + "RAW PRIOR": "原始推估", + "CCTV ON": "CCTV 開", + "CCTV OFF": "CCTV 關", + "VIEWSHED ON": "可視域 開", "COVERAGE ON": "覆蓋範圍 開", "COVERAGE OFF": "覆蓋範圍 關", "AUTO HOP ON": "自動輪播 開", @@ -1533,22 +1533,22 @@ "CAL · {badge}": "CAL · {badge}", "MONITOR": "螢幕", "OFF": "關", - "{city} · HDG {heading} · FOV {fov} · RANGE {range}m · {projection}{calBadge} · {provider}{status}": "{city} · HDG {heading} · FOV {fov} · 範圍 {range} m · {projection}{calBadge} · {provider}{status}", + "{city} · HDG {heading} · FOV {fov} · RANGE {range}m · {projection}{calBadge} · {provider}{status}": "{city} · HDG {heading} · FOV {fov} · 距離 {range} m · {projection}{calBadge} · {provider}{status}", "{count} cameras loaded · click a camera to activate": { "other": "已載入 {count} 個攝影機 · 點選攝影機以啟用" }, "{count} cameras loaded · enable CCTV to activate": { - "other": "已載入 {count} 個攝影機 · 啟用 CCTV 以啟用" + "other": "已載入 {count} 個攝影機 · 開啟 CCTV 即可使用" }, "Enable CCTV to load camera intersections": "啟用監視器以載入路口攝影機", "Enable CCTV to start camera-linked intelligence summaries.": "啟用監視器以開始產生攝影機情資摘要。", "No summary available.": "尚無摘要。", - "loading frames": "載入畫面", + "loading frames": "畫面載入中", "camera grid ready": "攝影機網格就緒", "Clearing selected data layers": "正在清除已選資料圖層", "Clear selected data layers": "清除已選資料圖層", "CONDITIONS UNKNOWN": "天氣狀況未知", - "CLEAR": "清除", + "CLEAR": "晴", "PARTLY CLOUDY": "晴間多雲", "OVERCAST": "陰", "FOG": "霧", @@ -1560,10 +1560,10 @@ "MIXED CONDITIONS": "混合天氣", "CYCLE ON": "輪播 開", "CYCLE OFF": "輪播 關", - "Stop automatic page cycling. Previous, Next, and the SIG/NEWS/LOCAL tabs stay available.": "停止自動翻頁。上一頁、下一頁以及「訊號」「新聞」「本機」標籤頁仍可使用。", - "Cycle briefing pages automatically every 9 seconds (Signals → News → Local). Pauses while you hover or focus the panel. Live signal data refreshes continuously either way.": "每 9 秒自動輪播簡報頁(訊號 → 新聞 → 在地)。滑鼠停留或聚焦面板時暫停;即時訊號資料會持續更新。", - "ACQUIRING REGIONAL NEWS": "取得區域新聞中", - "REGIONAL NEWS UNAVAILABLE": "地區新聞不可用", + "Stop automatic page cycling. Previous, Next, and the SIG/NEWS/LOCAL tabs stay available.": "停止自動翻頁。上一頁、下一頁以及「訊號」「新聞」「在地」標籤頁仍可使用。", + "Cycle briefing pages automatically every 9 seconds (Signals → News → Local). Pauses while you hover or focus the panel. Live signal data refreshes continuously either way.": "每 9 秒自動輪播簡報頁(訊號 → 新聞 → 在地)。滑鼠停留或聚焦面板時暫停;即時訊號資料會持續更新。", + "ACQUIRING REGIONAL NEWS": "正在取得區域新聞", + "REGIONAL NEWS UNAVAILABLE": "區域新聞不可用", "RESOLVING REGION": "解析區域中", "REGION UNAVAILABLE": "無法取得區域", "NO RECENT LOCATION MATCHES": "暫無近期位置匹配結果", @@ -1572,8 +1572,8 @@ "CLOUD {pct}%": "雲量 {pct}%", "CLOUD UNKNOWN": "雲量未知", "{source} · LOCATION QUERY": "{source} · 位置查詢", - "REGIONAL NEWS": "地區新聞", - "{label} · {radius} AIR/SEA WINDOW": "{label} · {radius} 空/海監視視窗", + "REGIONAL NEWS": "區域新聞", + "{label} · {radius} AIR/SEA WINDOW": "{label} · {radius} 空 / 海監視範圍", "{scope} · INSTALLATIONS {coverage}": "{scope} · 設施 {coverage}", "CONTEXT STANDBY": "態勢待機", "ENABLE GLOBAL CONTEXT FOR PROXIMITY PINGS": "啟用全域態勢以接收鄰近目標提醒", @@ -1596,7 +1596,7 @@ "ADS-B EMERGENCY · {status}": "ADS-B 緊急 · {status}", "AIRCRAFT": "飛機", "ACQUIRING SURFACE": "正在取得地面資料", - "SURFACE FALLBACK": "地面資料備用", + "SURFACE FALLBACK": "地面資料備援", "STALE FEED": "資料來源過期", "LIVE TRACK": "即時航跡", "COMMERCIAL": "商用", @@ -1628,7 +1628,7 @@ "SOURCE-BACKED EVENTS · NO SYNTHETIC NEWS": "有來源佐證的事件 · 無合成新聞", "LATEST LOCATION-MATCHED REPORTING": "最新在地相關報導", "{source} · LOCATION QUERY · RECENT": "{source} · 位置查詢 · 近期", - "LOCAL INFO": "本機資訊", + "LOCAL INFO": "在地資訊", "PLACE / CONDITIONS / POSITION": "地點/天候/位置", "TIME UNKNOWN": "時間未知", "{count}M AGO": "{count} 分鐘前", @@ -1699,9 +1699,9 @@ "{requirement}, or {offer}": "{requirement},或{offer}", "Live Flights": "即時航班", "Military Flights": "軍機", - "Earthquakes (24h)": "全球地震 (24小時)", + "Earthquakes (24h)": "全球地震(24 小時)", "Satellites": "衛星", - "Space Missions (30d)": "太空發射任務 (30天)", + "Space Missions (30d)": "太空發射任務(30 天)", "Street Traffic": "道路交通", "CCTV": "CCTV", "Radio": "廣播電台", @@ -1731,7 +1731,7 @@ "Active Fires": "野火熱點", "Military aircraft": "軍用飛機", "Vessels": "船舶", - "CCTV + Street View fallback": "CCTV + 街景備用", + "CCTV + Street View fallback": "CCTV + 街景備援", "OpenStreetMap + optional Google Maps Places": "OpenStreetMap + 可選 Google Maps Places", "GFS / ECMWF IFS · FORECAST": "GFS / ECMWF IFS · 預報", "NOAA nowCOAST · OBSERVED": "NOAA nowCOAST · 觀測", @@ -1811,10 +1811,10 @@ "Search failed": "搜尋失敗", "Detailed outline unavailable": "無法取得詳細輪廓", "Fly to a POI first": "請先飛往一個 POI", - "Reset to full globe view": "重設為完整地球視角", - "Reset cockpit to full globe view": "駕駛艙重設為完整地球視角", - "Resetting to full globe view": "正在重置為完整地球檢視", - "Resetting cockpit to full globe view": "正在將駕駛艙重置為完整地球檢視", + "Reset to full globe view": "重設為完整地球視野", + "Reset cockpit to full globe view": "駕駛艙重設為完整地球視野", + "Resetting to full globe view": "正在重設為完整地球視野", + "Resetting cockpit to full globe view": "正在將駕駛艙重設為完整地球視野", "MAP": "地圖", "panel": "面板", "Expand {name}": "展開 {name}", @@ -1823,7 +1823,7 @@ "Collapse Radio": "收起電台", "Expand Radio section": "展開電台區域", "Collapse Radio section": "收起電台區域", - "Panel layout updated — positions reset to new defaults": "面板佈局已更新——位置已重置為新的預設值", + "Panel layout updated — positions reset to new defaults": "面板版面已更新——位置已重設為新的預設值", "Austin": "奧斯汀", "San Francisco": "舊金山", "New York": "紐約", @@ -1836,7 +1836,7 @@ "Los Angeles": "洛杉磯", "Collapse Cockpit display options": "收起駕駛艙顯示選項", "Expand Cockpit display options": "展開駕駛艙顯示選項", - "Collapse Cockpit Radio controls": "收起駕駛艙電台控制元件", + "Collapse Cockpit Radio controls": "收起駕駛艙廣播控制", "Expand Cockpit Radio controls": "展開駕駛艙廣播控制", "CH {index} / {total}": "頻道 {index} / {total}", "NO STATIONS": "無電台", @@ -1956,7 +1956,7 @@ "USE VIEW": "使用視野", "Use the current view as the box": "以目前視野作為框選", "Forget the box and its images": "清除框選及其影像", - "START HERE": "從此開始", + "START HERE": "從這裡開始", "Checking": "檢查中", "PREVIEW": "預覽", "Newest day with imagery for this box": "此框選有影像的最新一天", @@ -1984,7 +1984,7 @@ "Box {width} × {height} km": "框選 {width} × {height} km", "Acquired {time}": "取得於 {time}", "Coverage {coverage}": "覆蓋 {coverage}", - "START HERE · {reason}": "從此開始 · {reason}", + "START HERE · {reason}": "從這裡開始 · {reason}", "Daily overview shows little detail in a box this small": "在這麼小的框選內,每日概覽幾乎看不出細節", "Imagery: NASA GIBS and Worldview · HLS (Sentinel-2, Landsat 8/9) and VIIRS": "影像:NASA GIBS 與 Worldview · HLS(Sentinel-2、Landsat 8/9)與 VIIRS", "Details": "詳情", @@ -2052,9 +2052,9 @@ "OVERPASS TIMED OUT": "Overpass 逾時", "OVERPASS COULD NOT COMPLETE THE QUERY": "Overpass 無法完成查詢", "MAP TILES TEMPORARILY UNAVAILABLE": "地圖瓦片暫時不可用", - "MAPPED NAMES TEMPORARILY UNAVAILABLE": "地點名稱暫時不可用", + "MAPPED NAMES TEMPORARILY UNAVAILABLE": "地圖標註名稱暫時不可用", "TURNING OFF LIVE DATA": "正在關閉即時資料", - "REFRESHING LIVE DATA": "更新即時資料", + "REFRESHING LIVE DATA": "正在重新整理即時資料", "syncing road network": "同步道路網路", "retry pending": "等待重試", "retrying in {seconds}s": "{seconds} 秒後重試", @@ -2131,7 +2131,7 @@ "Zoom in to a street to open {names} here": "放大到街道以在此處開啟 {names}", "Loading this sequence…": "正在載入此序列…", "{n} images in this sequence · Esc clears": { - "other": "此序列共 {n} 張圖像 · Esc 清除" + "other": "此序列共 {n} 張圖像 · 按 Esc 清除" }, "{n} streets in view · click a line for its nearest photo": { "other": "視野內共 {n} 條街道 · 點選線段檢視距其最近的照片" @@ -2155,15 +2155,15 @@ "min": "分鐘", "s": "秒", "dB": "dB", - "Celestial ring — reveal the full globe": "天體環 — 顯示完整地球", - "Celestial ring — available in Normal style": "天球環——僅在常規樣式下可用", - "Detection overlay: {mode}": "探測疊加層:{mode}", - "Detection overlay: off": "探測疊加層:關閉", + "Celestial ring — reveal the full globe": "天球環——顯示完整地球", + "Celestial ring — available in Normal style": "天球環——僅在一般樣式下可用", + "Detection overlay: {mode}": "偵測疊加層:{mode}", + "Detection overlay: off": "偵測疊加層:關閉", "DETECT": "偵測", "{time} · {minutes} min ago": "{time} · {minutes} 分鐘前", "Active weather": "已啟用的天氣圖層", "LATEST · newest per product": "最新 · 每個產品的最新一幀", - "Forecast · valid {valid} · issued {issued}": "預報 · 有效時間 {valid} · 釋出時間 {issued}", + "Forecast · valid {valid} · issued {issued}": "預報 · 有效時間 {valid} · 發布時間 {issued}", "{detail} · Does not follow history": "{detail} · 不隨觀測歷史變化", "Forecast · valid {valid}": "預報 · 有效時間 {valid}", "voice|OFF": "關", @@ -2172,15 +2172,15 @@ "voice|EXECUTING": "執行中", "voice|ERROR": "錯誤", "AI AGENT": "AI 助理", - "Voice model tier — applies next session": "語音模型等級 — 於下次工作階段生效", + "Voice model tier — applies next session": "語音模型等級——於下次工作階段生效", "STD": "標準", "Estimated session cost": "預估工作階段費用", - "Voice control — activate to toggle voice; hold Space to speak": "語音控制 — 啟用以切換語音;按住空白鍵說話", + "Voice control — activate to toggle voice; hold Space to speak": "語音控制——啟用以切換語音;按住空白鍵說話", "ON/OFF": "開/關", "VOICE STANDBY": "語音待命", "VOICE CONTROL": "語音控制", "Hold Space to speak · tap Space to activate focused controls": "按住空白鍵說話 · 輕按空白鍵啟用聚焦的控制項", - "Voice assistant": "語音助手", + "Voice assistant": "語音助理", "VOICE": "語音", "Dismiss voice card": "關閉語音卡片", "YOU": "你", @@ -2211,7 +2211,7 @@ "USD cost and the API spend cap are unavailable for this auth mode.": "此認證模式下無法提供美元費用與 API 消費上限。", "Usage is incomplete because a response was still in flight when the session ended.": "用量不完整,因為工作階段結束時仍有回應在處理中。", "Estimated session cost on {modelId} — {responses} response(s). Warns at {warn}, ends the session at {cap}.": "{modelId} 的預估工作階段費用——{responses} 次回應。達到 {warn} 時警告,達到 {cap} 時結束工作階段。", - "Estimate is incomplete — a response was still in flight when the session ended, so its usage was never reported.": "估算不完整——工作階段結束時仍有回應在處理中,因此其用量從未上報。", + "Estimate is incomplete — a response was still in flight when the session ended, so its usage was never reported.": "估算不完整——工作階段結束時仍有回應在處理中,因此其用量從未回報。", "STANDARD": "標準", "{tier} applies next session": "{tier} 將在下次工作階段生效", "Session ended — cost cap {cost}": "工作階段已結束——已達費用上限 {cost}", @@ -2272,7 +2272,7 @@ "anywhere in the loaded data": "已載入資料中的任意位置", "in view": "視野內", "within {radius} of the view centre": "視野中心 {radius} 範圍內", - "within {radius} of {place} (Contacts window)": "{place} {radius} 範圍內(目標視窗)", + "within {radius} of {place} (Contacts window)": "{place} {radius} 範圍內(目標範圍)", "within {radius} of {place}": "{place} {radius} 範圍內", "within {radius}": "{radius} 範圍內", "over {region}": "{region} 範圍內", @@ -2302,7 +2302,7 @@ "unavailable": "不可用", "Not answered: {layers}": "未回應:{layers}", "Toggle voice control": "切換語音控制", - "Activate to toggle voice": "點選切換語音", + "Activate to toggle voice": "啟用以切換語音", "Voice active": "語音已啟用", "Voice could not be started.": "無法啟動語音。", "the active voice session": "目前語音工作階段", @@ -2390,7 +2390,7 @@ "Change visual style": "切換視覺樣式", "Adjust HUD": "調整 HUD", "Adjust cyber sonar": "調整賽博聲納", - "Adjust detection overlay": "調整探測疊加層", + "Adjust detection overlay": "調整偵測疊加層", "Change map stack": "切換地圖組合", "Adjust post-processing": "調整後期處理", "Control scene": "控制場景", @@ -2449,8 +2449,8 @@ "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 cockpit vision style: NORMAL. Activate for next style.": "目前駕駛艙視覺樣式:一般。啟用以切換下一個樣式。", + "Current style: NORMAL — click for next": "目前風格:一般——點選切換", "CURRENT": "目前", "Next cockpit vision style": "下一個駕駛艙視覺風格", "Next vision style": "下一個視覺風格", @@ -2475,10 +2475,10 @@ "Estimated flight plan": "推估飛行計畫", "ESTIMATED FLIGHT PLAN": "推估飛行計畫", "FROM": "出發", - "TO": "目的", + "TO": "目的地", "Cockpit briefing controls": "駕駛艙簡報控制", - "Previous briefing page": "上一頁簡報", - "Next briefing page": "下一頁簡報", + "Previous briefing page": "簡報上一頁", + "Next briefing page": "簡報下一頁", "Live signals": "即時訊號", "Latest regional news": "最新區域新聞", "Location-based information": "在地資訊", @@ -2508,7 +2508,7 @@ "ESC EXIT": "ESC 離開", "C TOGGLE": "C 切換", "View switcher": "視角切換", - "Exit cockpit and return to full globe view": "離開駕駛艙並回到完整地球視角", + "Exit cockpit and return to full globe view": "離開駕駛艙並回到完整地球視野", "RESET": "重設", "Exit cockpit view": "離開駕駛艙視角", "EXIT COCKPIT": "離開駕駛艙", @@ -2521,7 +2521,7 @@ "Simulate night-vision goggles with green intensification and a tube vignette.": "模擬綠色增光與鏡筒暗角的夜視鏡。", "Simulate FLIR-style thermal contrast. Turn up Ironbow for color.": "模擬 FLIR 熱成像對比。調高 Ironbow 可顯示色彩。", "Apply bright cel-shaded color and illustrated outlines.": "套用明亮的賽璐璐上色與插畫描邊。", - "Apply high-contrast monochrome film-noir grading.": "套用高對比黑白黑色電影調色。", + "Apply high-contrast monochrome film-noir grading.": "套用高對比黑色電影風格的黑白調色。", "Add a cold, snowy whiteout treatment to the scene.": "為場景加上冰冷的白茫雪景效果。", "MAP SOURCE": "地圖來源", "Map source": "地圖來源", @@ -2546,7 +2546,7 @@ "Expand panel": "展開面板", "Context mode": "態勢模式", "CONTACTS": "目標", - "Cycles the nearest contacts of whatever type you select — planes, vessels, installations. Satellites track independently.": "輪流切換所選類型的最近目標 — 飛機、船舶、設施。衛星獨立追蹤。", + "Cycles the nearest contacts of whatever type you select — planes, vessels, installations. Satellites track independently.": "輪流切換所選類型的最近目標——飛機、船舶、設施。衛星獨立追蹤。", "SPACE MISSIONS": "太空任務", "SELECT CONTEXT": "選擇態勢", "Contact Context actions": "目標情境操作", @@ -2566,7 +2566,7 @@ "All": "全部", "Enable Radio, then choose a globe marker or use next.": "啟用廣播,再選擇地球上的標記或按「下一個」。", "DRAG TO TUNE": "拖曳調頻", - "Tune available internet radio stations": "調整可用網路電台", + "Tune available internet radio stations": "調諧可用網路電台", "ALL · DRAG THE NEEDLE": "全部 · 拖曳指針", "SNAPS TO AVAILABLE STATIONS": "自動對齊可用電台", "Radio playback": "廣播播放", @@ -2595,11 +2595,11 @@ "FM MHZ": "FM MHz", "TUNE": "調諧", "Seek broadcast FM stations": "搜尋廣播 FM 電台", - "◀ SEEK": "◀ 搜臺", - "SEEK ▶": "搜臺 ▶", + "◀ SEEK": "◀ 搜台", + "SEEK ▶": "搜台 ▶", "SDR VOL": "SDR 音量", "Local SDR volume": "本機 SDR 音量", - "Intelligence HUD (H)": "情報抬頭顯示 (H)", + "Intelligence HUD (H)": "情報抬頭顯示(H)", "Layout": "版面", "HUD layout": "HUD 版面", "Tactical": "戰術", @@ -2619,7 +2619,7 @@ "Minimum opacity for map dots, icons, models, brackets, and labels between sonar passes": "兩次聲納掃描之間地圖點、圖示、模型、括號標記與標籤的最低不透明度", "Sector": "扇區", "Sonar sector width": "聲納扇區寬度", - "Detection Overlay (D)": "偵測疊加 (D)", + "Detection Overlay (D)": "偵測疊加(D)", "Detection overlay": "偵測疊加", "Detection label density": "偵測標籤密度", "Allocation": "分配", @@ -2628,27 +2628,27 @@ "Weighted": "加權", "Fade": "淡出", "Detection fade distance": "偵測淡出距離", - "World-overlay fade distance outside the keyhole as a percentage of its radius": "瞄準孔外世界疊加層的淡出距離(半徑百分比)", + "World-overlay fade distance outside the keyhole as a percentage of its radius": "瞄準孔外世界疊加層的淡出距離(半徑百分比)", "Outside": "外圍", "Detection opacity outside the keyhole": "瞄準孔外的偵測不透明度", "World-overlay label and card opacity beyond the fade distance": "超過淡出距離後世界疊加標籤與卡片的不透明度", "PARAMETERS": "參數", - "3D aircraft — flat icons zoomed out, 3D models up close": "3D 飛機 — 拉遠為平面圖示,拉近為 3D 模型", + "3D aircraft — flat icons zoomed out, 3D models up close": "3D 飛機——拉遠為平面圖示,拉近為 3D 模型", "Models": "模型", "3D model coverage": "3D 模型範圍", "Proximity": "鄰近", - "Scope — the circular viewport mask": "視域 — 圓形檢視範圍遮罩", + "Scope — the circular viewport mask": "視域——圓形檢視範圍遮罩", "Scope": "視域", "Feather": "羽化", "Scope edge feather": "視域邊緣羽化", - "Scope edge feather as a percentage of the keyhole radius": "瞄準鏡邊緣羽化(瞄準孔半徑百分比)", - "Draw on the world — click vertices, double-click or Enter to finish, Esc to cancel": "在世界上繪圖 — 點選頂點,按兩下或 Enter 完成,Esc 取消", + "Scope edge feather as a percentage of the keyhole radius": "視域邊緣羽化(瞄準孔半徑百分比)", + "Draw on the world — click vertices, double-click or Enter to finish, Esc to cancel": "在世界上繪圖——點選頂點,按兩下或 Enter 完成,Esc 取消", "Shape": "形狀", "Shape to draw": "要繪製的形狀", "Area": "區域", "Line": "線", "Pin": "圖釘", - "Label (optional)": "標籤(選填)", + "Label (optional)": "標籤(選填)", "Label for the drawn shape": "繪製形狀的標籤", "Colour of the drawn shape": "繪製形狀的顏色", "Primary": "主色", @@ -2662,7 +2662,7 @@ "Import": "匯入", "Choose GeoJSON, KML, KMZ or GPX files": "選擇 GeoJSON、KML、KMZ 或 GPX 檔案", "Imported files": "已匯入的檔案", - "Celestial": "天體環", + "Celestial": "天球環", "Hide UI chrome": "隱藏介面框架", "Clean UI": "簡潔介面", "Bloom / Glow": "光暈/輝光", @@ -2679,14 +2679,14 @@ "CCTV camera": "監視器攝影機", "CALIBRATION": "校正", "Drag the camera in the world: rings rotate, arrows move, handles set range/FOV": "在世界中拖曳攝影機:圓環旋轉、箭頭移動、把手調整距離/視角", - "Camera pose — click a value to type": "攝影機姿態 — 點選數值即可輸入", - "Heading (compass °) — click to type": "方位角(羅盤 °)— 點選輸入", - "Pitch (° up/down) — click to type": "俯仰角(° 上/下)— 點選輸入", - "Horizontal FOV (°) — click to type": "水平視角(°)— 點選輸入", - "Range / monitor-plane distance (m) — click to type": "距離/投影平面距離(公尺)— 點選輸入", - "Mount height above ground (m) — click to type": "架設離地高度(公尺)— 點選輸入", - "North offset from catalog position (m) — click to type": "相對目錄位置的北向偏移(公尺)— 點選輸入", - "East offset from catalog position (m) — click to type": "相對目錄位置的東向偏移(公尺)— 點選輸入", + "Camera pose — click a value to type": "攝影機姿態——點選數值即可輸入", + "Heading (compass °) — click to type": "方位角(羅盤 °)——點選輸入", + "Pitch (° up/down) — click to type": "俯仰角(° 上/下)——點選輸入", + "Horizontal FOV (°) — click to type": "水平視角(°)——點選輸入", + "Range / monitor-plane distance (m) — click to type": "距離 / 螢幕平面距離(公尺)——點選輸入", + "Mount height above ground (m) — click to type": "架設離地高度(公尺)——點選輸入", + "North offset from catalog position (m) — click to type": "相對目錄位置的北向偏移(公尺)——點選輸入", + "East offset from catalog position (m) — click to type": "相對目錄位置的東向偏移(公尺)——點選輸入", "SAVE CAL": "儲存校正", "RESET CAL": "重設校正", "SCENE SUMMARY": "場景摘要", @@ -2694,9 +2694,9 @@ "Turn Street Level on or off": "開啟或關閉街景", "Image fit": "圖像縮放方式", "FIT": "完整顯示", - "Fit: show the whole photo, with dark bars where its shape differs from the frame": "適應:顯示整張照片,在比例與畫框不符處留黑邊", + "Fit: show the whole photo, with dark bars where its shape differs from the frame": "完整顯示:顯示整張照片,在比例與畫框不符處留黑邊", "FILL": "填滿", - "Fill: fill the frame edge to edge, cropping the photo": "填充:圖像鋪滿畫框並裁剪照片", + "Fill: fill the frame edge to edge, cropping the photo": "填滿:圖像鋪滿畫框並裁剪照片", "Close the image and deselect it on the map": "關閉圖像並取消其在地圖上的選中狀態", "Close the street-level image": "關閉街景圖像", "Street-level viewer": "街景檢視器", @@ -2722,10 +2722,10 @@ "GROUND STATION · PROVIDER SETTINGS": "地面站 · 服務供應商設定", "Close key setup": "關閉金鑰設定", "Power up the globe": "強化你的地球", - "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.": "不需任何金鑰地球就能運作。下方每一組金鑰都會開啟另一個真實資料來源 — 貼上後會存入本機設定,伺服器隨即自動重新啟動。伺服器端金鑰只留在本機;Google Maps 與 Cesium ion 在瀏覽器中執行,務必在供應商端設定使用限制。在其他地方設定的金鑰只會顯示,不會被修改。", + "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.": "不需任何金鑰,地球就能運作。下方每一組金鑰都會開啟另一個真實資料來源——貼上後會存入本機設定,伺服器隨即自動重新啟動。伺服器端金鑰只留在本機;Google Maps 與 Cesium ion 在瀏覽器中執行,務必在供應商端設定使用限制。在其他地方設定的金鑰只會顯示,不會被修改。", "SAVE KEYS": "儲存金鑰", "ESC to close": "ESC 關閉", - "The Google Maps key buys the photorealistic planet — everything else stacks on top.": "Google Maps 金鑰帶來擬真地球 — 其他功能都疊加在它之上。", + "The Google Maps key buys the photorealistic planet — everything else stacks on top.": "Google Maps 金鑰帶來擬真地球——其他功能都疊加在它之上。", "NO PLACE LEFT BEHIND": "無處遁形", "ACTIVE STYLE": "目前風格", "Globe actions": "地球操作", @@ -2734,7 +2734,7 @@ "Toggle straight-down and tilted map views": "切換俯視/傾斜地圖視角", "Reset map to north up": "地圖重設為北方朝上", "Reset map bearing to north": "重設地圖方位為正北", - "Reset camera and return to full globe view": "重設鏡頭並回到完整地球視角", + "Reset camera and return to full globe view": "重設鏡頭並回到完整地球視野", "MISSION CONTROL · FIRST LAUNCH": "任務控制 · 首次啟動", "Choose your first view": "選擇你的第一個視角", "LIVE CONTACTS": "即時目標", @@ -2759,7 +2759,7 @@ "No coverage in view": "視野內無覆蓋範圍", "Voice provider": "語音服務供應商", "Changing provider reconnects voice if it is on.": "如語音已開啟,切換服務供應商會重新連線語音。", - "Gemini returned an oversized audio chunk": "Gemini 返回的音訊塊過大", + "Gemini returned an oversized audio chunk": "Gemini 傳回的音訊區塊過大", "Gemini returned an unsupported audio format": "Gemini 返回了不支援的音訊格式", "Gemini returned an invalid audio sample rate": "Gemini 返回了無效的音訊取樣率", "Gemini returned incomplete PCM audio": "Gemini 返回的 PCM 音訊不完整", @@ -2769,7 +2769,7 @@ "Gemini token response did not include an ephemeral credential": "Gemini 權杖回應中沒有臨時憑據", "Invalid Gemini connection endpoint": "Gemini 連線端點無效", "Gemini voice could not connect. Try again.": "Gemini 語音無法連線。請重試。", - "Gemini voice requires a same-origin app request": "Gemini 語音需要與本應用同源的請求", + "Gemini voice requires a same-origin app request": "Gemini 語音需要與本應用程式同源的請求", "Add a Gemini API key in Provider Settings": "請在服務供應商設定中新增 Gemini API 金鑰", "The Gemini Live model configuration is invalid": "Gemini Live 模型配置無效", "Gemini voice is starting too often. Try again shortly.": "Gemini 語音啟動過於頻繁。請稍後重試。", @@ -2852,7 +2852,7 @@ "GhostMaps catalog unavailable": "無法取得 GhostMaps 目錄", "Malformed GhostMaps catalog": "GhostMaps 目錄格式無效", "{count} source links ↗ · click card to open the first": { - "other": "{count} 個來源連結 ↗ · 點選卡片開啟第一個" + "other": "{count} 個來源連結 ↗ · 點選卡片開啟第一個連結" }, "S2 · {name}": "S2 · {name}", "Report": "報告", From 09cef198292ac5701d7ec07ce40f11dc8343b2d9 Mon Sep 17 00:00:00 2001 From: Aditya <205600203+Rohilalala@users.noreply.github.com> Date: Tue, 27 Oct 2026 21:56:52 +0530 Subject: [PATCH 07/11] docs(changelog): add #1431 fragment --- changelog.d/1431-street-level-bearing-north.md | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 changelog.d/1431-street-level-bearing-north.md diff --git a/changelog.d/1431-street-level-bearing-north.md b/changelog.d/1431-street-level-bearing-north.md new file mode 100644 index 000000000..f30084b71 --- /dev/null +++ b/changelog.d/1431-street-level-bearing-north.md @@ -0,0 +1,3 @@ +- Show a Street Level view facing 359.5° or more as 0°. The viewer caption + rounded the bearing without wrapping, so a view facing 359.6° read "360°" + (Aditya, @Rohilalala, #1431). From 51ee9ae9142f8b53a828b6e2645b6354811f9aa9 Mon Sep 17 00:00:00 2001 From: German Khokhlov Date: Tue, 27 Oct 2026 23:57:25 +0400 Subject: [PATCH 08/11] i18n: write zh-Hant as zh-CN in Traditional characters Rebuild the zh-Hant catalog from zh-CN with OpenCC s2tw glyph conversion, so wording and terminology match zh-CN and only the script differs. Drop Taiwan-specific vocabulary and wording notes; zh-TW/HK/MO browser tags still select zh-Hant. Co-Authored-By: Claude Opus 5.5 --- changelog.d/1430-traditional-chinese.md | 8 +- docs/CURRENT-STATE.md | 2 +- docs/translations/zh-Hant.md | 40 +- src/i18n/firms-live-zh.test.mjs | 4 +- src/i18n/i18n.test.mjs | 2 +- src/i18n/locales/zh-Hant.json | 2344 +++++++++++------------ src/i18n/same-as-english.json | 2 +- src/i18n/zh-Hant-display.test.mjs | 4 +- 8 files changed, 1187 insertions(+), 1219 deletions(-) diff --git a/changelog.d/1430-traditional-chinese.md b/changelog.d/1430-traditional-chinese.md index 3d34d6536..e644829fc 100644 --- a/changelog.d/1430-traditional-chinese.md +++ b/changelog.d/1430-traditional-chinese.md @@ -1,4 +1,4 @@ -- Add Traditional Chinese (zh-Hant) with language selection, - and localized Chinese readouts. Based on translations by @caxer (#724), - @tbdavid2019 (#652), @abiyeenzo (#914), and @EDIT-Aeterna (#979) - (German, @gekh, #1430). +- Add Traditional Chinese (zh-Hant) with language selection and localized + Chinese readouts: the Simplified Chinese catalog written in Traditional + characters, based on translations by @abiyeenzo (#914) and @EDIT-Aeterna + (#979) (German, @gekh, #1430). diff --git a/docs/CURRENT-STATE.md b/docs/CURRENT-STATE.md index 570b50371..829fb1ceb 100644 --- a/docs/CURRENT-STATE.md +++ b/docs/CURRENT-STATE.md @@ -3744,7 +3744,7 @@ Shipped locales: **en** (source and fallback), **es**, **ru**, **zh-CN** and **z value). English has no catalog; every other locale is `src/i18n/locales/.json`, and a missing entry falls back to English. - **Locale choice.** `?lang=` → stored choice (`gev:locale:v1`) → - `navigator.languages` → English. Chinese tags default to `zh-CN`; `Hant`, `TW`, `HK` and `MO` + `navigator.languages` → English. Chinese tags default to `zh-CN`; Traditional Chinese tags select `zh-Hant`. Explicit `Hans` selects `zh-CN` regardless of region. `?lang=` is not stored, and share links drop it, so a recipient keeps their own language. The globe picker in the bottom-right corner (`src/ui/localePicker.js`) stores the choice, drops diff --git a/docs/translations/zh-Hant.md b/docs/translations/zh-Hant.md index f53a8cd97..7354e6b1b 100644 --- a/docs/translations/zh-Hant.md +++ b/docs/translations/zh-Hant.md @@ -2,46 +2,14 @@ Catalog: `src/i18n/locales/zh-Hant.json`. General rules: [TRANSLATORS.md](../TRANSLATORS.md). -Sources: caxer (#724), tbdavid2019 (#652), and the zh-CN catalog credited to abiyeenzo (#914) and EDIT-Aeterna (#979). The remaining entries were seeded with OpenCC s2twp and edited for consistency. The catalog retains terminology from these Taiwan-oriented sources; `zh-Hant` identifies the writing system and does not promise separate regional vocabulary. +`zh-Hant` is the Simplified Chinese catalog (`zh-CN`, credited to abiyeenzo, #914, and EDIT-Aeterna, #979) written in Traditional characters with OpenCC character conversion. Wording and terminology are the same as in `zh-CN`: change a term in [zh-CN.md](./zh-CN.md) and the `zh-CN` catalog first, then convert. Only the script differs. ## Style -- Use Traditional characters and consistent terminology from the glossary below. Prefer short, neutral instructions: 「點選地圖」、「儲存金鑰」. -- Use full-width Chinese punctuation and 「」 for quotations. Keep `·`, `…`, provider names, codes and placeholders unchanged. -- Separate Chinese from Latin letters and numbers with a space: 「AIS 船舶」、「24 小時」. Keep unit symbols unchanged: km, m, km/h, m/s, kn, ft, MW, °, %. +- Follow [zh-CN.md](./zh-CN.md) for wording, punctuation, spacing, units and the glossary, written in Traditional characters. - Relative-time placeholders may already include 前. In `LIVE · updated {age}`, the caller supplies the complete relative age; do not append another 前. -- Chinese labels have no uppercase variant. Keep button labels short and avoid splitting short words across lines. -- The picker displays 中文(繁體) / Chinese (Traditional). Browser tags with Hant or TW/HK/MO select the shared `zh-Hant` catalog. Existing `zh-TW` links and saved choices remain supported. Explicit Hans selects Simplified Chinese, including Hans-TW. +- The picker displays 中文(繁體) / Chinese (Traditional); explicit Hans tags select Simplified Chinese. ## Plurals -`Intl.PluralRules('zh-Hant')` uses only `other`. Keep suitable measure words: 「{count} 架飛機」、「{count} 艘船」、「{count} 個金鑰」. - -## Catalog terminology - -| English | Traditional Chinese | -| --- | --- | -| data / information | 資料 / 資訊 | -| file / folder | 檔案 / 資料夾 | -| settings / save | 設定 / 儲存 | -| API key / token | API 金鑰 / 權杖 | -| live / load | 即時 / 載入 | -| camera / video | 攝影機 / 影片 | -| network / link | 網路 / 連結 | -| image / imagery | 圖像 / 影像 | -| click / double-click | 點選 / 按兩下 | -| response / timeout | 回應 / 逾時 | -| layer / data layer | 圖層 / 資料圖層 | -| cockpit / context | 駕駛艙 / 態勢 | -| air quality | 空氣品質 | -| transit / bikeshare | 大眾運輸 / 公共自行車 | - -## Context-sensitive terms - -- Weather `CLEAR` is 晴; `action|CLEAR` is 清除. -- `LOCAL INFO` describes 在地資訊; 本機 refers to the local device. -- Observation windows describe 範圍, not a UI 視窗. The scope control is 視域 and its feather slider is 視域邊緣羽化. -- Roundabouts are 圓環; telemetry is 回報; weather advisories are 發布. -- Intercardinal compass points: NNE 北北東, ENE 東北東, ESE 東南東, SSE 南南東, SSW 南南西, WSW 西南西, WNW 西北西, NNW 北北西. -- The Celestial control and its help text use 天球環. An uncalibrated camera's `RAW PRIOR` is 原始推估. -- `Wind unavailable` is shared by cyclone wind-speed cards and the wind-field layer; keep the wording broad enough for both (風況資料不可用). +`Intl.PluralRules('zh-Hant')` uses only `other`. Keep the measure words of the `zh-CN` entry: 「{count} 架飛機」、「{count} 艘船」. diff --git a/src/i18n/firms-live-zh.test.mjs b/src/i18n/firms-live-zh.test.mjs index 11878e790..03b3af6c8 100644 --- a/src/i18n/firms-live-zh.test.mjs +++ b/src/i18n/firms-live-zh.test.mjs @@ -10,7 +10,7 @@ const cases = [ [7200000, '2 小时前', '2h ago', '2 小時前'], ]; -for (const [age, zh, en, tw] of cases) { +for (const [age, zh, en, hant] of cases) { test(`FIRMS live age ${age} ms has one relative-time suffix`, (context) => { const now = 1800000000000; context.mock.method(Date, 'now', () => now); @@ -37,7 +37,7 @@ for (const [age, zh, en, tw] of cases) { setLocale('zh-CN'); assert.equal(methods.getStats().loadingLabel, `实时 · 更新于 ${zh}`); setLocale('zh-Hant'); - assert.equal(methods.getStats().loadingLabel, `即時 · 更新於 ${tw}`); + assert.equal(methods.getStats().loadingLabel, `實時 · 更新於 ${hant}`); } finally { setLocale(previousLocale); } diff --git a/src/i18n/i18n.test.mjs b/src/i18n/i18n.test.mjs index 031d4f85e..1b421f2ff 100644 --- a/src/i18n/i18n.test.mjs +++ b/src/i18n/i18n.test.mjs @@ -43,7 +43,7 @@ test('normalizeLocale folds regional variants and rejects unshipped tags', () => assert.equal(normalizeLocale(' ZH_hant '), 'zh-Hant'); assert.equal(normalizeLocale('zh-TW'), 'zh-Hant'); assert.equal(normalizeLocale('zh-Hant-HK'), 'zh-Hant'); - assert.equal(normalizeLocale('zh-Hans-TW'), 'zh-CN'); + assert.equal(normalizeLocale('zh-Hans-HK'), 'zh-CN'); assert.equal(normalizeLocale('zh-Hant-CN'), 'zh-Hant'); assert.equal(normalizeLocale('zh_HK'), 'zh-Hant'); assert.equal(normalizeLocale('zh-MO'), 'zh-Hant'); diff --git a/src/i18n/locales/zh-Hant.json b/src/i18n/locales/zh-Hant.json index e86b7d9ab..414624f2d 100644 --- a/src/i18n/locales/zh-Hant.json +++ b/src/i18n/locales/zh-Hant.json @@ -1,41 +1,41 @@ { - "Pick a shape, then click the map.": "選擇形狀,然後點選地圖。", + "Pick a shape, then click the map.": "先選擇形狀,再在地圖上點擊。", "Enter to place the pin, Esc to cancel.": "按 Enter 放置圖釘,按 Esc 取消。", - "Click where the pin goes.": "點選圖釘的放置位置。", + "Click where the pin goes.": "點擊圖釘的放置位置。", "Click {count} more points.": { - "other": "再點選 {count} 個點。" + "other": "再點擊 {count} 個點。" }, "Those points are in a line — move one off it to enclose an area.": "這些點都在同一條直線上——請移開其中一個點才能圍出區域。", - "That line has no length — click somewhere further away.": "這條線沒有長度——請在更遠處點選。", + "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}", + "{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 point is off the globe — click on the world.": "該點在地球之外——請點擊地球上的位置。", "That shape could not be placed.": "該形狀無法放置。", "Could not place the shape: {error}": "無法放置形狀:{error}", "Board cleared.": "畫板已清除。", - "{owner} is using the pointer — close it first.": "{owner} 正在使用指標——請先關閉它。", - "{label} · Detailed outline unavailable": "{label} · 無法取得詳細輪廓", - "Flying to Austin, TX...": "正在飛往德州奧斯汀…", - "Restoring shared view...": "正在還原分享的視角…", - "Configuring viewer...": "正在設定檢視器…", - "Loading Google 3D Tiles...": "正在載入 Google 3D Tiles…", - "Loading the keyless globe...": "正在載入免金鑰地球…", - "Google 3D Tiles unavailable ({detail}). Loading the keyless globe...": "Google 3D Tiles 不可用({detail})。正在載入免金鑰地球…", - "Initializing systems...": "系統初始化中…", - "Space Missions isolates replay data. Exit the mode to enable {layer}.": "太空任務模式會隔離回放資料。退出該模式後才能啟用「{layer}」。", - "Data attribution": "資料來源", - "Data provided by:": "資料提供:", - "Close data attribution": "關閉資料來源", + "{owner} is using the pointer — close it first.": "{owner} 正在使用指針——請先關閉它。", + "{label} · Detailed outline unavailable": "{label} · 無法獲取詳細輪廓", + "Flying to Austin, TX...": "正在飛往德克薩斯州奧斯汀…", + "Restoring shared view...": "正在恢復分享視圖…", + "Configuring viewer...": "正在配置視圖…", + "Loading Google 3D Tiles...": "正在加載 Google 3D Tiles…", + "Loading the keyless globe...": "正在加載免密鑰地球…", + "Google 3D Tiles unavailable ({detail}). Loading the keyless globe...": "Google 3D Tiles 不可用({detail})。正在加載免密鑰地球…", + "Initializing systems...": "正在初始化系統…", + "Space Missions isolates replay data. Exit the mode to enable {layer}.": "太空任務模式會隔離回放數據。退出該模式後才能啟用“{layer}”。", + "Data attribution": "數據來源說明", + "Data provided by:": "數據提供方:", + "Close data attribution": "關閉數據來源說明", "Light aircraft": "輕型飛機", "Glider": "滑翔機", "Turboprop": "渦槳飛機", "Airliner": "民航客機", "Widebody": "寬體機", - "Four-engine jet": "四發噴射機", + "Four-engine jet": "四發噴氣機", "Helicopter": "直升機", - "Fast jet": "噴射戰機", + "Fast jet": "噴氣戰機", "Business jet": "公務機", "Drone": "無人機", "General emergency": "一般緊急情況", @@ -44,16 +44,16 @@ "Downed aircraft": "飛機墜毀", "Minimum fuel": "最低油量", "Lifeguard (medical priority)": "救護飛行(醫療優先)", - "Rasuwagadhi witness video": "Rasuwagadhi 目擊影片", + "Rasuwagadhi witness video": "Rasuwagadhi 目擊視頻", "Bhote Koshi valley footage": "Bhote Koshi 河谷畫面", "Flood footage": "洪水畫面", - "Compilation and casualty claims": "影片合集與傷亡說法", + "Compilation and casualty claims": "視頻合集與傷亡說法", "SOURCE GEOCONFIRMED · WORLD-PINNED": "來源位置已核實 · 已在地圖上標註", "SOURCE CREDITED · LOCATION UNRESOLVED": "來源已署名 · 位置未確定", "REFERENCE ONLY · CLAIMS UNVERIFIED": "僅供參考 · 說法未核實", "SOURCE GEOCONFIRMED": "來源位置已核實", - "2021 historical reference versus 2026 post-event imagery; changes are cumulative and include the July 2025 Rasuwagadhi flood. Schematic downstream progression, not modeled arrival time; not an official hazard model.": "2021 年歷史參考影像與 2026 年災後影像對比;變化為累計結果,包含 2025 年 7 月的 Rasuwagadhi 洪水。下游演進為示意,並非模擬的到達時間;也不是官方災害模型。", - "Immediate collapse viewpoint": "初始崩塌觀察點", + "2021 historical reference versus 2026 post-event imagery; changes are cumulative and include the July 2025 Rasuwagadhi flood. Schematic downstream progression, not modeled arrival time; not an official hazard model.": "2021 年曆史參考影像與 2026 年災後影像對比;變化為累計結果,包含 2025 年 7 月的 Rasuwagadhi 洪水。下游演進為示意,並非模擬的到達時間;也不是官方災害模型。", + "Immediate collapse viewpoint": "近距離崩塌觀察點", "Collapse viewpoint": "崩塌觀察點", "Debris-dammed lake": "碎屑堰塞湖", "Dammed lake": "堰塞湖", @@ -69,43 +69,43 @@ "Devighat / Taadi Khola Bridge": "Devighat / Taadi Khola 橋", "Devighat bridge": "Devighat 橋", "Facebook player API did not initialize.": "Facebook 播放器 API 未能初始化。", - "Facebook player API could not load.": "無法載入 Facebook 播放器 API。", - "Facebook player API timed out.": "Facebook 播放器 API 逾時。", + "Facebook player API could not load.": "無法加載 Facebook 播放器 API。", + "Facebook player API timed out.": "Facebook 播放器 API 超時。", "X embed API did not initialize.": "X 嵌入 API 未能初始化。", - "X embed could not load.": "無法載入 X 嵌入內容。", - "X embed timed out.": "X 嵌入內容逾時。", - "UNAVAILABLE": "無法使用", - "TIMEOUT": "逾時", + "X embed could not load.": "無法加載 X 嵌入內容。", + "X embed timed out.": "X 嵌入內容超時。", + "UNAVAILABLE": "不可用", + "TIMEOUT": "超時", "BLOCKED": "被攔截", "SOURCE": "來源", - "Facebook embed unavailable. The post may be private, removed, region-restricted, or blocked.": "Facebook 嵌入內容不可用。該貼文可能為私密、已刪除、受地區限制或被攔截。", - "Preloading {provider} media": "正在預載入 {provider} 媒體", - "LOADING X POST…": "正在載入 X 貼文…", - "The X post is unavailable or cannot be embedded.": "該 X 貼文不可用或無法嵌入。", - "X POST · PROVIDER CONTROLS": "X 貼文 · 平台控制元件", - "{reason} OPEN ORIGINAL.": "{reason} 請開啟原始來源。", + "Facebook embed unavailable. The post may be private, removed, region-restricted, or blocked.": "Facebook 嵌入內容不可用。該帖子可能為私密、已刪除、受地區限制或被攔截。", + "Preloading {provider} media": "正在預加載 {provider} 媒體", + "LOADING X POST…": "正在加載 X 帖子…", + "The X post is unavailable or cannot be embedded.": "該 X 帖子不可用或無法嵌入。", + "X POST · PROVIDER CONTROLS": "X 帖子 · 平臺控件", + "{reason} OPEN ORIGINAL.": "{reason} 請打開原始來源。", "X embed unavailable": "X 嵌入內容不可用。", - "FACEBOOK · PROVIDER CONTROLS": "FACEBOOK · 平台控制元件", + "FACEBOOK · PROVIDER CONTROLS": "FACEBOOK · 平臺控件", "Facebook embed unavailable": "Facebook 嵌入內容不可用。", - "AUTOPLAY BLOCKED · USE PROVIDER CONTROLS": "自動播放被攔截 · 請使用平台控制元件", + "AUTOPLAY BLOCKED · USE PROVIDER CONTROLS": "自動播放被攔截 · 請使用平臺控件", "Embedded {provider} media for {source}": "{source} 的嵌入 {provider} 媒體", "witness source": "目擊來源", "Witness source": "目擊來源", "{provider} · EMBEDDED SOURCE": "{provider} · 嵌入來源", - "OPEN ORIGINAL ↗": "開啟原始來源 ↗", + "OPEN ORIGINAL ↗": "打開原始來源 ↗", "{provider} media: {source}": "{provider} 媒體:{source}", - "{provider} · PROVIDER CONTROLS": "{provider} · 平台控制元件", - "YOUTUBE {state} · OPEN ORIGINAL": "YOUTUBE {state} · 開啟原始來源", + "{provider} · PROVIDER CONTROLS": "{provider} · 平臺控件", + "YOUTUBE {state} · OPEN ORIGINAL": "YOUTUBE {state} · 打開原始來源", "INITIATION": "起始", "DAMMING": "堰塞", "SECONDARY FAILURE": "第二次滑坡", "BORDER ARRIVAL": "抵達邊境", "PROPAGATION": "演進", - "DOWNSTREAM PASSAGE": "向下游推進", + "DOWNSTREAM PASSAGE": "向下遊推進", "CONSEQUENCE": "後果", "DOWNSTREAM CONSEQUENCE": "下游後果", "EVIDENCE": "證據", - "{year} HISTORICAL REFERENCE": "{year} 年歷史參考", + "{year} HISTORICAL REFERENCE": "{year} 年曆史參考", "{year} POST-EVENT": "{year} 年災後", "{count} GEOLOCATED SOURCE-MAP PLACEMENTS": { "other": "{count} 個地理定位來源點位" @@ -113,15 +113,15 @@ "NO PREVIEW": "無預覽", "YouTube source": "YouTube 來源", "Facebook source": "Facebook 來源", - "SOURCE LINK": "來源連結", - "{publisher} / OPEN": "{publisher} / 開啟", + "SOURCE LINK": "來源鏈接", + "{publisher} / OPEN": "{publisher} / 打開", "Bhote Koshi flood reconstruction controls": "Bhote Koshi 洪水重構控制", "EVENT RECONSTRUCTION · 26 AUG 2026": "事件重構 · 2026-08-26", "BHOTE KOSHI OUTBURST FLOOD": "BHOTE KOSHI 潰決洪水", "Close event layer": "關閉事件圖層", "OBSERVED IMAGERY": "觀測影像", "SCHEMATIC CORRIDOR": "示意走廊", - "2021 HISTORICAL REFERENCE / 2026 POST-EVENT": "2021 年歷史參考 / 2026 年災後", + "2021 HISTORICAL REFERENCE / 2026 POST-EVENT": "2021 年曆史參考 / 2026 年災後", "Historical reference and post-event image split": "歷史參考與災後影像的分割", "RECONSTRUCTION CLOCK": "重構時鐘", "Schematic downstream progression": "下游演進示意", @@ -135,14 +135,14 @@ "▶ PLAY SCENE": "▶ 播放場景", "◉ CINEMATIC": "◉ 運鏡", "↺ FULL STORY": "↺ 完整故事", - "↗ OPEN ORIGINAL": "↗ 開啟原始來源", + "↗ OPEN ORIGINAL": "↗ 打開原始來源", "⌖ LOWER GORGE": "⌖ 下游峽谷", "FIELD REPORTS · {count}": "現場報道 · {count}", "GEOLOCATIONS · {credit}": "地理定位 · {credit}", - "↗ OPEN PUBLIC MAP": "↗ 開啟公共地圖", - " Clouds are preserved from the source imagery.": "雲層按原始影像原樣保留。", + "↗ OPEN PUBLIC MAP": "↗ 打開公共地圖", + " Clouds are preserved from the source imagery.": "雲層按源影像原樣保留。", "Rasuwagadhi witness": "Rasuwagadhi 目擊者", - "Open original source for {source}; capture time unverified": "開啟 {source} 的原始來源;拍攝時間未核實", + "Open original source for {source}; capture time unverified": "打開 {source} 的原始來源;拍攝時間未核實", "Historical reference and post-event image divider": "歷史參考與災後影像的分割線", "A historical reference {before} percent, B post-event {after} percent": "A 歷史參考 {before}%,B 災後 {after}%", "■ RELEASE CAMERA": "■ 釋放相機", @@ -155,7 +155,7 @@ "↺ REPLAY": "↺ 重播", "… PLAYING SCENE": "… 場景播放中", "Continue {scene} from next shot": "從下一鏡頭繼續播放 {scene}", - "current scene": "目前場景", + "current scene": "當前場景", "Replay the full reconstruction": "重播完整重構", "SCENE SHOT": "場景鏡頭", "TIME UNVERIFIED": "拍攝時間未核實", @@ -166,10 +166,10 @@ "{scene} / AUTHORED SHOT": "{scene} / 編排鏡頭", "NEPAL FLOOD INCIDENT": "尼泊爾洪水事件", "Play {shot}": "播放 {shot}", - "current scene shot": "目前場景鏡頭", + "current scene shot": "當前場景鏡頭", "Play reconstruction": "播放重構", - "Load previous scene shot": "載入上一個場景鏡頭", - "Load next scene shot": "載入下一個場景鏡頭", + "Load previous scene shot": "加載上一個場景鏡頭", + "Load next scene shot": "加載下一個場景鏡頭", "SCHEMATIC CORRIDOR, NOT MODELED ARRIVAL TIME.": "示意走廊,並非模擬的到達時間。", "Rasuwa · 26 Aug 2026": "Rasuwa · 2026-08-26", "Event reconstruction": "事件重構", @@ -179,8 +179,8 @@ "26 AUG 2026 · 08:37 NPT": "2026-08-26 · 08:37 NPT", "28.2710° N · 85.5150° E": "北緯 28.2710° · 東經 85.5150°", "INITIAL M4.4 · RECLASSIFIED M5.2 LANDSLIDE": "初報 M4.4 · 重新歸類為 M5.2 滑坡", - "USGS EVENT us7000tbwb · OPEN SOURCE": "USGS 事件 us7000tbwb · 開啟來源", - "Open the USGS initial report for the 26 August 2026 Nepal landslide": "開啟 USGS 關於 2026 年 8 月 26 日尼泊爾滑坡的初始報告", + "USGS EVENT us7000tbwb · OPEN SOURCE": "USGS 事件 us7000tbwb · 打開來源", + "Open the USGS initial report for the 26 August 2026 Nepal landslide": "打開 USGS 關於 2026 年 8 月 26 日尼泊爾滑坡的初始報告", "Show the Nepal context callout without a border or country fill": "顯示尼泊爾背景標註,不繪製邊界和國家填充", "Introduce Nepal, draw its border, then reveal the Bhote Koshi incident": "介紹尼泊爾,繪製其邊界,再展示 Bhote Koshi 事件", "CITIES": "城市", @@ -194,56 +194,56 @@ "RECORD": "記錄", "Reveal the trigger record while making a slow camera approach": "鏡頭緩慢推近,同時展示觸發事件記錄", "{speed} kn": "{speed} kn", - "That file is not valid JSON.": "該檔案不是有效的 JSON。", - "That JSON file is not GeoJSON.": "該 JSON 檔案不是 GeoJSON。", - "That FeatureCollection has no features list.": "該 FeatureCollection 沒有 features 清單。", - "Every GeoJSON feature must have type Feature.": "每個 GeoJSON 要素的型別都必須是 Feature。", + "That file is not valid JSON.": "該文件不是有效的 JSON。", + "That JSON file is not GeoJSON.": "該 JSON 文件不是 GeoJSON。", + "That FeatureCollection has no features list.": "該 FeatureCollection 沒有 features 列表。", + "Every GeoJSON feature must have type Feature.": "每個 GeoJSON 要素的類型都必須是 Feature。", "That GeoJSON has invalid geometries.": "該 GeoJSON 包含無效的幾何圖形。", - "That GeoJSON contains an unsupported geometry.": "該 GeoJSON 包含不受支援的幾何圖形。", + "That GeoJSON contains an unsupported geometry.": "該 GeoJSON 包含不受支持的幾何圖形。", "That GeoJSON has invalid coordinates.": "該 GeoJSON 包含無效座標。", - "That file creates more than {limit} map objects (the limit).": "該檔案生成的地圖物件超過上限 {limit} 個。", - "That file has more than {limit} style definitions and image links after cleanup (the limit).": "清理後,該檔案的樣式定義和圖像連結仍超過上限 {limit} 個。", - "That file has more than {limit} features (the limit).": "該檔案的要素超過上限 {limit} 個。", - "That file has more than {limit} points (the limit) across {features} features.": "該檔案的點數超過上限 {limit} 個(共 {features} 個要素)。", - "That file has more than {limit} points (the limit).": "該檔案的點數超過上限 {limit} 個。", - "That KMZ unpacks to more than the import limit.": "該 KMZ 解壓後超過匯入上限。", + "That file creates more than {limit} map objects (the limit).": "該文件生成的地圖對象超過上限 {limit} 個。", + "That file has more than {limit} style definitions and image links after cleanup (the limit).": "清理後,該文件的樣式定義和圖像鏈接仍超過上限 {limit} 個。", + "That file has more than {limit} features (the limit).": "該文件的要素超過上限 {limit} 個。", + "That file has more than {limit} points (the limit) across {features} features.": "該文件的點數超過上限 {limit} 個(共 {features} 個要素)。", + "That file has more than {limit} points (the limit).": "該文件的點數超過上限 {limit} 個。", + "That KMZ unpacks to more than the import limit.": "該 KMZ 解壓後超過導入上限。", "That KMZ is damaged and could not be unpacked.": "該 KMZ 已損壞,無法解壓。", "That KMZ is not a readable zip archive.": "該 KMZ 不是可讀取的 zip 壓縮包。", - "That KMZ uses a zip format this import does not read.": "該 KMZ 使用的 zip 格式無法匯入。", + "That KMZ uses a zip format this import does not read.": "該 KMZ 使用的 zip 格式無法導入。", "That KMZ is encrypted.": "該 KMZ 已加密。", - "That KMZ uses a compression method this import does not read.": "該 KMZ 使用的壓縮方式無法匯入。", + "That KMZ uses a compression method this import does not read.": "該 KMZ 使用的壓縮方式無法導入。", "That KML has invalid geometry bounds.": "該 KML 的幾何範圍無效。", "That KML has invalid coordinates.": "該 KML 包含無效座標。", - "That GPX file has no document.": "該 GPX 檔案沒有 文件。", - "That {format} file is not valid XML.": "該 {format} 檔案不是有效的 XML。", - "That file has an unreadable image or exceeds the 16-megapixel image limit.": "該檔案包含無法讀取的圖像,或圖像超過 1600 萬像素上限。", + "That GPX file has no document.": "該 GPX 文件沒有 文檔。", + "That {format} file is not valid XML.": "該 {format} 文件不是有效的 XML。", + "That file has an unreadable image or exceeds the 16-megapixel image limit.": "該文件包含無法讀取的圖像,或圖像超過 1600 萬像素上限。", "That KML could not be read.": "無法讀取該 KML。", - "That file has invalid point coordinates.": "該檔案的點座標無效。", - "Ground heights are not available for that file. Try again when the map has loaded.": "無法取得該檔案的地面高度。請在地圖載入完成後重試。", - "That file took too long to read.": "讀取該檔案耗時過長。", - "Nothing to import.": "沒有可匯入的內容。", - "That file is larger than {size} MiB.": "該檔案大於 {size} MiB。", - "Only GeoJSON, KML, KMZ and GPX files can be imported.": "只能匯入 GeoJSON、KML、KMZ 和 GPX 檔案。", - "That file has nothing to draw.": "該檔案沒有可在地圖上繪製的內容。", - "That KMZ holds no KML document.": "該 KMZ 中沒有 KML 文件。", - "That {format} file could not be read.": "無法讀取該 {format} 檔案。", - "That file has {count} map objects; the limit is {limit}.": "該檔案有 {count} 個地圖物件,上限為 {limit} 個。", - "Ground heights could not be read. Try that file again.": "無法讀取地面高度。請重新匯入該檔案。", - "That file has invalid point graphics.": "該檔案的點樣式無效。", + "That file has invalid point coordinates.": "該文件的點座標無效。", + "Ground heights are not available for that file. Try again when the map has loaded.": "無法獲取該文件的地面高度。請在地圖加載完成後重試。", + "That file took too long to read.": "讀取該文件耗時過長。", + "Nothing to import.": "沒有可導入的內容。", + "That file is larger than {size} MiB.": "該文件大於 {size} MiB。", + "Only GeoJSON, KML, KMZ and GPX files can be imported.": "只能導入 GeoJSON、KML、KMZ 和 GPX 文件。", + "That file has nothing to draw.": "該文件沒有可在地圖上繪製的內容。", + "That KMZ holds no KML document.": "該 KMZ 中沒有 KML 文檔。", + "That {format} file could not be read.": "無法讀取該 {format} 文件。", + "That file has {count} map objects; the limit is {limit}.": "該文件有 {count} 個地圖對象,上限為 {limit} 個。", + "Ground heights could not be read. Try that file again.": "無法讀取地面高度。請重新導入該文件。", + "That file has invalid point graphics.": "該文件的點樣式無效。", "Overpass rate-limited": "Overpass 已被限流", - "Overpass timed out": "Overpass 逾時", + "Overpass timed out": "Overpass 超時", "Overpass could not complete the query": "Overpass 無法完成查詢", "Map tiles temporarily unavailable": "地圖瓦片暫時不可用", "Mapped names temporarily unavailable": "地點名稱暫時不可用", "Overpass temporarily unavailable": "Overpass 暫時不可用", - "Retrying mapped sites…": "正在重試載入地圖標註設施…", - "Fetching mapped sites…": "正在取得地圖標註設施…", + "Retrying mapped sites…": "正在重試加載地圖標註設施…", + "Fetching mapped sites…": "正在獲取地圖標註設施…", "{reason} — retrying in {seconds}s": "{reason}——{seconds} 秒後重試", "{reason} — retry pending": "{reason}——等待重試", - "Zoom in to search mapped installations": "請放大地圖以搜尋地圖標註的設施", - "Showing cached mapped sites": "正在顯示快取的地圖標註設施", - "Mapped sites not loaded": "地圖標註設施未載入", - "Mapped sites loaded": "已載入地圖標註設施", + "Zoom in to search mapped installations": "請放大地圖以搜索地圖標註的設施", + "Showing cached mapped sites": "正在顯示緩存的地圖標註設施", + "Mapped sites not loaded": "地圖標註設施未加載", + "Mapped sites loaded": "已加載地圖標註設施", "Military airfield": "軍用機場", "Naval base": "海軍基地", "Firing range": "靶場", @@ -253,23 +253,23 @@ "flight": "航班", "military flight": "軍用航班", "satellite": "衛星", - "feed unavailable": "資料來源不可用", - "feed stale": "資料來源過期", + "feed unavailable": "數據源不可用", + "feed stale": "數據源過期", "observed or mapped nearby context": "附近的觀測或地圖標註態勢", - "no observed or mapped objects in current feeds": "目前資料來源中沒有觀測或地圖標註的物件", + "no observed or mapped objects in current feeds": "當前數據源中沒有觀測或地圖標註的對象", "Draw": "繪製", - "Directions": "路線規劃", + "Directions": "路線導航", "Recent imagery": "近期影像", - "STATION": "太空站", - "Crewed stations and their visiting vehicles": "載人太空站與來訪載具", + "STATION": "空間站", + "Crewed stations and their visiting vehicles": "載人空間站及其來訪航天器", "NAV": "導航", - "GNSS navigation — GPS, GLONASS, Galileo": "GNSS 導航衛星——GPS、GLONASS、Galileo", + "GNSS navigation — GPS, GLONASS, Galileo": "GNSS 導航:GPS、GLONASS、Galileo", "GEO": "GEO", - "Geostationary belt — comms and weather, fixed over the equator": "地球同步軌道帶——通訊與氣象衛星,固定於赤道上空", + "Geostationary belt — comms and weather, fixed over the equator": "地球靜止軌道帶:通信和氣象,固定在赤道上空", "VISUAL": "目視可見", - "Brightest naked-eye objects — CelesTrak visual group": "肉眼最亮天體——CelesTrak 目視群組", - "COMMS": "通訊", - "Broadband constellation shell — shown only in DENSE mode": "寬頻星座殼層——僅在「密集」模式下顯示", + "Brightest naked-eye objects — CelesTrak visual group": "最亮的肉眼可見天體:CelesTrak visual 組", + "COMMS": "通信", + "Broadband constellation shell — shown only in DENSE mode": "寬帶星座殼層——僅在“密集”模式下顯示", "FISHING": "漁船", "TOWING": "拖帶", "DREDGER": "挖泥船", @@ -290,21 +290,21 @@ "TANKER": "油輪", "OTHER": "其他", "Included in bundle": "已包含在資源包中", - "Missing bundle file — reimport its bundle": "缺少資源包檔案——請重新匯入其資源包", - "Source configured; file checked when loaded": "資料來源已配置;檔案在載入時校驗", - "Source unavailable": "資料來源不可用", + "Missing bundle file — reimport its bundle": "缺少資源包文件——請重新導入其資源包", + "Source configured; file checked when loaded": "數據源已配置;文件在加載時校驗", + "Source unavailable": "數據源不可用", "ENVIRONMENTAL": "環境", "EARTH WATCH": "地球監測", - "ACTIVE EVENTS": "進行中事件", - "Starting live contacts…": "正在接入即時目標…", - "Opening space missions…": "正在開啟太空任務…", + "ACTIVE EVENTS": "活躍事件", + "Starting live contacts…": "正在接入實時目標…", + "Opening space missions…": "正在打開太空任務…", "Scanning active events…": "正在掃描活躍事件…", - "Live earthquakes and active fires, from USGS and NASA": "來自 USGS 與 NASA 的即時地震與野火", - "It feels like a forbidden cockpit—then you realize the sources are public and the data is real.": "像是闖進了禁區駕駛艙——接著你才發現,所有來源都是公開的,資料也都是真的。", + "Live earthquakes and active fires, from USGS and NASA": "來自 USGS 和 NASA 的實時地震與活躍火點", + "It feels like a forbidden cockpit—then you realize the sources are public and the data is real.": "彷彿闖進了一個機密座艙——隨後你會發現,數據來源全部公開,數據全部真實。", "Working…": "處理中…", - "Could not open that mission{detail}. Retry or explore manually.": "無法開啟該任務{detail}。請重試或手動探索。", - "This browser is blocking storage, so that could not be saved.": "此瀏覽器阻止了儲存,因此無法儲存。", - "NORMAL": "一般", + "Could not open that mission{detail}. Retry or explore manually.": "無法打開該任務{detail}。請重試或手動探索。", + "This browser is blocking storage, so that could not be saved.": "此瀏覽器阻止了存儲,因此無法保存。", + "NORMAL": "常規", "CRT": "CRT", "NVG": "NVG", "FLIR": "FLIR", @@ -321,11 +321,11 @@ "OCEANIA": "大洋洲", "NORTHERN OCEANIC GRID": "北方海洋網格", "SOUTHERN OCEANIC GRID": "南方海洋網格", - "LOADING": "載入中", - "DEGRADED": "資料品質下降", - "STALE": "資料過期", - "PARTIAL": "部分可用", - "FALLBACK": "備用模式", + "LOADING": "加載中", + "DEGRADED": "降級", + "STALE": "過期", + "PARTIAL": "部分", + "FALLBACK": "備用", "{state} {layers}": "{state} {layers}", "view band|STREET": "街道", "view band|CITY": "城市", @@ -333,11 +333,11 @@ "view band|REGIONAL": "區域", "view band|GLOBAL": "全球", "SUMMARY": "摘要", - "Awaiting telemetry...": "等待遙測資料…", + "Awaiting telemetry...": "等待遙測數據…", "REC": "REC", "AIS: --": "AIS: --", "N/A": "無", - "{mode} {band} {locality} | {region} | ALT {alt} | WINDOW {window} | SUN {sun}° | ONA {ona}° | {zone}": "{mode} {band} {locality} | {region} | ALT {alt} | 視窗 {window} | SUN {sun}° | ONA {ona}° | {zone}", + "{mode} {band} {locality} | {region} | ALT {alt} | WINDOW {window} | SUN {sun}° | ONA {ona}° | {zone}": "{mode} {band} {locality} | {region} | ALT {alt} | 窗口 {window} | SUN {sun}° | ONA {ona}° | {zone}", "NEAR {poi} ({city}) {distance}": "{poi}({city})附近 {distance}", "SECTOR {lat} {lon}": "扇區 {lat} {lon}", "N": "北", @@ -345,92 +345,92 @@ "E": "東", "W": "西", "POWER UP · {count} KEYS WAITING": { - "other": "增強 · {count} 個金鑰待配置" + "other": "增強 · {count} 個密鑰待配置" }, - "POWERED UP": "已全面強化", - "Provider Settings does not answer proxied requests": "服務供應商設定不回應經代理的請求", - "Provider Settings is disabled while sharing is enabled": "啟用分享時,服務供應商設定不可用", - "Provider Settings answers only the machine running the server": "服務供應商設定僅回應執行伺服器的那臺機器", - "Provider Settings answers only local hostnames": "服務供應商設定只回應本機主機名", - "Provider Settings requires an exact local Origin": "服務供應商設定要求完全匹配的本機 Origin", + "POWERED UP": "已增強", + "Provider Settings does not answer proxied requests": "服務商設置不響應經代理的請求", + "Provider Settings is disabled while sharing is enabled": "啟用分享時,服務商設置不可用", + "Provider Settings answers only the machine running the server": "服務商設置僅響應運行服務器的那臺機器", + "Provider Settings answers only local hostnames": "服務商設置只響應本地主機名", + "Provider Settings requires an exact local Origin": "服務商設置要求完全匹配的本地 Origin", "Unrecognized Origin refused": "已拒絕無法識別的 Origin", "Cross-origin requests are refused": "拒絕跨源請求", "Content-Type must be application/json": "Content-Type 必須為 application/json", "Method not allowed": "不允許的方法", "Request too large": "請求過大", "Invalid JSON": "無效的 JSON", - "Body must be a JSON object of {ENV_VAR: value}": "請求體必須是 {ENV_VAR: value} 形式的 JSON 物件", - "No keys provided": "未提供金鑰", - "At most {limit} keys per save": "每次最多儲存 {limit} 個金鑰", - "Unknown key: {name}": "未知金鑰:{name}", - "{name} must be a string": "{name} 必須是字串", + "Body must be a JSON object of {ENV_VAR: value}": "請求體必須是 {ENV_VAR: value} 形式的 JSON 對象", + "No keys provided": "未提供密鑰", + "At most {limit} keys per save": "每次最多保存 {limit} 個密鑰", + "Unknown key: {name}": "未知密鑰:{name}", + "{name} must be a string": "{name} 必須是字符串", "{name} is empty": "{name} 為空", - "{name} is longer than any real key ({limit} max)": "{name} 比任何真實金鑰都長(最多 {limit} 個字元)", - "{name} may only contain printable characters with no spaces": "{name} 只能包含可列印字元,且不能有空格", - "{name} contains a character that is not valid in a key (#, quotes, $, \\, or backtick)": "{name} 包含金鑰中不允許的字元(#、引號、$、\\ 或反引號)", - "{name} is configured outside Provider Settings and can only be changed where it was set": "{name} 是在服務供應商設定之外配置的,只能在原設定處修改", - "The key was not saved: could not restrict the credential file to your account; nothing was saved": "金鑰未儲存:無法將憑據檔案限制為僅你的帳戶可訪問;未儲存任何內容", - "The key was not saved: the existing configuration could not be read, so nothing was changed": "金鑰未儲存:無法讀取現有配置,因此未做任何更改", - "Could not write the {store} store": "無法寫入 {store}", - "Save failed ({status}).": "儲存失敗({status})。", + "{name} is longer than any real key ({limit} max)": "{name} 比任何真實密鑰都長(最多 {limit} 個字符)", + "{name} may only contain printable characters with no spaces": "{name} 只能包含可打印字符,且不能有空格", + "{name} contains a character that is not valid in a key (#, quotes, $, \\, or backtick)": "{name} 包含密鑰中不允許的字符(#、引號、$、\\ 或反引號)", + "{name} is configured outside Provider Settings and can only be changed where it was set": "{name} 是在服務商設置之外配置的,只能在原設置處修改", + "The key was not saved: could not restrict the credential file to your account; nothing was saved": "密鑰未保存:無法將憑據文件限制為僅你的賬戶可訪問;未保存任何內容", + "The key was not saved: the existing configuration could not be read, so nothing was changed": "密鑰未保存:無法讀取現有配置,因此未做任何更改", + "Could not write the {store} store": "無法寫入 {store} 存儲", + "Save failed ({status}).": "保存失敗({status})。", "OAuth check failed: {detail}": "OAuth 檢查失敗:{detail}", - "Could not check ChatGPT sign-in. Try again.": "無法檢查 ChatGPT 登入狀態,請重試。", + "Could not check ChatGPT sign-in. Try again.": "無法檢查 ChatGPT 登錄狀態,請重試。", "VOICE AUTH · CHATGPT OAUTH": "語音認證 · CHATGPT OAUTH", - "VOICE AUTH · API KEY": "語音認證 · API 金鑰", - "USE API KEY": "使用 API 金鑰", + "VOICE AUTH · API KEY": "語音認證 · API 密鑰", + "USE API KEY": "使用 API 密鑰", "USE CHATGPT OAUTH": "使用 CHATGPT OAUTH", - "Use OPENAI_API_KEY for the next cloud voice session": "下次雲語音工作階段使用 OPENAI_API_KEY", - "Use the signed-in local ChatGPT/Codex OAuth session for the next cloud voice session": "下次雲語音工作階段使用本機已登入的 ChatGPT/Codex OAuth 工作階段", - "Metered — a billing-enabled account": "計費——需啟用帳單的帳戶", - "Optional paid token — public access works without one": "可選的付費權杖——無需權杖也可公開訪問", - "Free key — register, paste, done": "免費金鑰——註冊、貼上、完成", + "Use OPENAI_API_KEY for the next cloud voice session": "下次雲語音會話使用 OPENAI_API_KEY", + "Use the signed-in local ChatGPT/Codex OAuth session for the next cloud voice session": "下次雲語音會話使用本機已登錄的 ChatGPT/Codex OAuth 會話", + "Metered — a billing-enabled account": "按量計費——需要啟用結算的賬號", + "Optional paid token — public access works without one": "可選的付費令牌——無需令牌也可公開訪問", + "Free key — register, paste, done": "免費密鑰——註冊、粘貼,即可使用", "browser-side": "瀏覽器端", - "This key runs in the browser by design — restrict it at the provider (see SECURITY.md)": "此金鑰設計上在瀏覽器執行——請在供應商端設定限制(見 SECURITY.md)", - "configured externally": "已在外部設定", - "Supplied by your environment, Keychain, or launcher — change it where it was set": "由你的環境、鑰匙圈或啟動器提供——請在原設定處修改", + "This key runs in the browser by design — restrict it at the provider (see SECURITY.md)": "此密鑰設計上就在瀏覽器中運行——請在服務商處設置限制(見 SECURITY.md)", + "configured externally": "由外部配置", + "Supplied by your environment, Keychain, or launcher — change it where it was set": "由你的環境、鑰匙串或啟動器提供——請在原設置處修改", "MANAGE ↗": "管理 ↗", - "GET KEY ↗": "取得金鑰 ↗", - "{envVar} saved — paste to replace": "{envVar} 已儲存——貼上可替換", - "paste {envVar}": "貼上 {envVar}", + "GET KEY ↗": "獲取密鑰 ↗", + "{envVar} saved — paste to replace": "{envVar} 已保存——粘貼可替換", + "paste {envVar}": "粘貼 {envVar}", "REMOVE": "移除", - "Remove {title} from this app's saved keys": "從本應用已儲存的金鑰中移除 {title}", - "unsaved provider keys": "未儲存的服務供應商金鑰", - "Project keys: {status}": "專案金鑰:{status}", + "Remove {title} from this app's saved keys": "從本應用已保存的密鑰中移除 {title}", + "unsaved provider keys": "未保存的服務商密鑰", + "Project keys: {status}": "項目密鑰:{status}", "your app configuration": "你的應用配置", - "your local .env": "你的本機 .env", - "Saving…": "正在儲存…", - "Save failed: {detail}": "儲存失敗:{detail}", - "Paste at least one key first.": "請先貼上至少一個金鑰。", - "Saved to {store}. Restarting — this page reloads itself.": "已儲存到 {store}。正在重啟——本頁面將自動重新載入。", - "Cloud voice will use OPENAI_API_KEY on the next session.": "雲語音將在下次工作階段使用 OPENAI_API_KEY。", - "Checking local ChatGPT OAuth sign-in…": "正在檢查本機 ChatGPT OAuth 登入…", - "Could not check ChatGPT sign-in.": "無法檢查 ChatGPT 登入狀態。", - "ChatGPT OAuth selected for cloud voice. Your API key stays saved and available.": "已為雲語音選擇 ChatGPT OAuth。你的 API 金鑰仍會保留並可用。", - "ChatGPT sign-in expired. Opening sign-in again…": "ChatGPT 登入已過期。正在重新開啟登入…", - "Opening ChatGPT sign-in in your browser…": "正在瀏覽器中開啟 ChatGPT 登入…", - "Could not start ChatGPT sign-in on this machine.": "無法在本機啟動 ChatGPT 登入。", - "Finish ChatGPT sign-in in the browser. Waiting for it to complete…": "請在瀏覽器中完成 ChatGPT 登入,正在等待其完成…", - "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。", - "Remove this key from your saved configuration?": "要從已儲存的配置中移除此金鑰嗎?", - "Removed from {store}. Restarting — this page reloads itself.": "已從 {store} 中移除。正在重啟——本頁面將自動重新載入。", - "The photorealistic 3D planet, place search + Street View": "照片級逼真 3D 地球、地點搜尋 + 街景", - "Places context + Street View fallback; optional separate key": "地點資訊 + 街景備援;可選用獨立金鑰", - "Voice control — API key or ChatGPT OAuth": "語音控制——API 金鑰或 ChatGPT OAuth", - "Live ships, worldwide": "全球即時船舶", - "Live active-fire detections": "即時野火偵測", - "Real live traffic (keyless runs a simulation)": "真實即時路況(無金鑰時為模擬)", - "Bing imagery map stacks + world terrain": "Bing 影像圖層 + 全球地形", - "More flight-polling credits (anonymous works without)": "更多航班查詢額度(匿名也可使用)", - "Street-level imagery and coverage in the Street Level layer. Free: register an app in the Mapillary developer dashboard and paste its Client Token": "街景影像與街景圖層中的覆蓋範圍。免費:在 Mapillary 開發者控制台註冊一個應用,並貼上其 Client Token", - "Public space-missions access needs no key. Leave blank for standard use; paid tokens only raise request limits.": "公開的太空任務資料無需金鑰。常規使用請留空;付費權杖只會提高請求上限。", - "Air quality request failed": "空氣品質請求失敗", + "your local .env": "你的本地 .env", + "Saving…": "正在保存…", + "Save failed: {detail}": "保存失敗:{detail}", + "Paste at least one key first.": "請先粘貼至少一個密鑰。", + "Saved to {store}. Restarting — this page reloads itself.": "已保存到 {store}。正在重啟——本頁面將自動重新加載。", + "Cloud voice will use OPENAI_API_KEY on the next session.": "雲語音將在下次會話使用 OPENAI_API_KEY。", + "Checking local ChatGPT OAuth sign-in…": "正在檢查本機 ChatGPT OAuth 登錄…", + "Could not check ChatGPT sign-in.": "無法檢查 ChatGPT 登錄狀態。", + "ChatGPT OAuth selected for cloud voice. Your API key stays saved and available.": "已為雲語音選擇 ChatGPT OAuth。你的 API 密鑰仍會保留並可用。", + "ChatGPT sign-in expired. Opening sign-in again…": "ChatGPT 登錄已過期。正在重新打開登錄…", + "Opening ChatGPT sign-in in your browser…": "正在瀏覽器中打開 ChatGPT 登錄…", + "Could not start ChatGPT sign-in on this machine.": "無法在本機啟動 ChatGPT 登錄。", + "Finish ChatGPT sign-in in the browser. Waiting for it to complete…": "請在瀏覽器中完成 ChatGPT 登錄,正在等待其完成…", + "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。", + "Remove this key from your saved configuration?": "要從已保存的配置中移除此密鑰嗎?", + "Removed from {store}. Restarting — this page reloads itself.": "已從 {store} 中移除。正在重啟——本頁面將自動重新加載。", + "The photorealistic 3D planet, place search + Street View": "照片級逼真 3D 地球、地點搜索 + 街景", + "Places context + Street View fallback; optional separate key": "地點信息 + 街景備用;可選的獨立密鑰", + "Voice control — API key or ChatGPT OAuth": "語音控制——API 密鑰或 ChatGPT OAuth", + "Live ships, worldwide": "全球實時船舶", + "Live active-fire detections": "實時活躍火點探測", + "Real live traffic (keyless runs a simulation)": "真實實時路況(無密鑰時為模擬)", + "Bing imagery map stacks + world terrain": "Bing 影像地圖組合 + 全球地形", + "More flight-polling credits (anonymous works without)": "更多航班輪詢額度(無密鑰也可匿名使用)", + "Street-level imagery and coverage in the Street Level layer. Free: register an app in the Mapillary developer dashboard and paste its Client Token": "街景影像與街景圖層中的覆蓋範圍。免費:在 Mapillary 開發者控制檯註冊一個應用,並粘貼其 Client Token", + "Public space-missions access needs no key. Leave blank for standard use; paid tokens only raise request limits.": "公開的太空任務數據無需密鑰。常規使用請留空;付費令牌只會提高請求上限。", + "Air quality request failed": "空氣質量請求失敗", "No readings available": "暫無讀數", "No current readings": "暫無最新讀數", "{count} stations reporting": { - "other": "{count} 個站點回報資料" + "other": "{count} 個站點上報數據" }, - "Highest air-quality readings in view": "視野內空氣品質讀數最高的站點", + "Highest air-quality readings in view": "視野內空氣質量讀數最高的站點", "Low": "低", "Low health risk": "低健康風險", "Moderate": "中等", @@ -439,70 +439,70 @@ "High health risk": "高健康風險", "Very High": "極高", "Very High health risk": "極高健康風險", - "Air quality": "空氣品質", - "Canada only · ECCC AQHI network": "僅限加拿大 · ECCC AQHI 監測網", - "ECCC request timed out": "ECCC 請求逾時", - "Malformed AQHI station response": "AQHI 站點回應格式錯誤", + "Air quality": "空氣質量", + "Canada only · ECCC AQHI network": "僅限加拿大 · ECCC AQHI 站網", + "ECCC request timed out": "ECCC 請求超時", + "Malformed AQHI station response": "AQHI 站點響應格式錯誤", "No AQHI stations available": "沒有可用的 AQHI 站點", - "Malformed AQHI observation response": "AQHI 觀測回應格式錯誤", - "Camera source temporarily unavailable": "攝影機資料來源暫時不可用", - "Mapped camera locations": "地圖標註的攝影機位置", + "Malformed AQHI observation response": "AQHI 觀測響應格式錯誤", + "Camera source temporarily unavailable": "攝像頭數據源暫時不可用", + "Mapped camera locations": "地圖標註的攝像頭位置", "SHOW NEAREST": "顯示最近", - "Stop following the current object before navigating to a camera": "請先停止追蹤目前目標,再前往攝影機", - "Move to the nearest loaded camera and show its details": "前往最近已載入的攝影機並顯示詳情", - "Camera badges": "攝影機標記", - "Cyan cameras turn coral when selected. Wedges illustrate mapped direction, not measured coverage. Nearby cameras may be outside the screen.": "選中後青色攝影機變為珊瑚色。扇形僅示意已標繪方向,並非實測覆蓋範圍。附近的攝影機可能不在螢幕內。", + "Stop following the current object before navigating to a camera": "請先停止跟蹤當前目標,再前往攝像頭", + "Move to the nearest loaded camera and show its details": "前往最近已加載的攝像頭並顯示詳情", + "Camera badges": "攝像頭標記", + "Cyan cameras turn coral when selected. Wedges illustrate mapped direction, not measured coverage. Nearby cameras may be outside the screen.": "選中後青色攝像頭變為珊瑚色。扇形僅示意已標繪方向,並非實測覆蓋範圍。附近的攝像頭可能不在屏幕內。", "{count} nearby · {onScreen} on screen": { - "other": "附近 {count} 個 · 螢幕上 {onScreen} 個" + "other": "附近 {count} 個 · 屏幕上 {onScreen} 個" }, "{count} nearby": { "other": "附近 {count} 個" }, - "retrying mapped ALPR cameras": "正在重試載入地圖標註的 ALPR 攝影機", - "loading mapped ALPR cameras": "正在載入地圖標註的 ALPR 攝影機", - "No ALPR data for this area — US and Canada only": "此區域沒有 ALPR 資料——僅覆蓋美國和加拿大", - "Zoom in to load mapped cameras": "放大以載入地圖標註的攝影機", - "Showing cached locations": "目前顯示的是快取位置", + "retrying mapped ALPR cameras": "正在重試加載地圖標註的 ALPR 攝像頭", + "loading mapped ALPR cameras": "正在加載地圖標註的 ALPR 攝像頭", + "No ALPR data for this area — US and Canada only": "此區域沒有 ALPR 數據——僅覆蓋美國和加拿大", + "Zoom in to load mapped cameras": "放大以加載地圖標註的攝像頭", + "Showing cached locations": "當前顯示的是緩存位置", "Coverage limited — zoom in": "覆蓋受限——請放大", - "No ALPR data for this area": "此區域沒有 ALPR 資料", - "None on screen — nearby cameras are outside the view": "螢幕上沒有攝影機——附近的攝影機在視野之外", - "ALPR camera": "車牌辨識攝影機", - "Camera coverage unavailable": "攝影機覆蓋範圍不可用", - "OpenStreetMap · community mapped": "OpenStreetMap · 社群標註", - "Overpass returned an incomplete camera response": "Overpass 返回的攝影機資料不完整", + "No ALPR data for this area": "此區域沒有 ALPR 數據", + "None on screen — nearby cameras are outside the view": "屏幕上沒有攝像頭——附近的攝像頭在視野之外", + "ALPR camera": "ALPR 攝像頭", + "Camera coverage unavailable": "攝像頭覆蓋範圍不可用", + "OpenStreetMap · community mapped": "OpenStreetMap · 社區標註", + "Overpass returned an incomplete camera response": "Overpass 返回的攝像頭數據不完整", "At least {count}": "至少 {count}", "CONTEXT READY": "態勢就緒", - "GLOBAL CONTEXT OFF": "全域態勢已關閉", + "GLOBAL CONTEXT OFF": "全局態勢已關閉", "SELECT A FLIGHT, VESSEL, OR MAPPED INSTALLATION": "選擇航班、船舶或地圖標註設施", - "ENABLE TO LOAD OBSERVED / MAPPED PROXIMITY": "啟用以載入觀測 / 地圖標註的鄰近資訊", + "ENABLE TO LOAD OBSERVED / MAPPED PROXIMITY": "啟用以加載觀測 / 地圖標註的鄰近信息", "Unavailable": "不可用", "Focus {label}": "聚焦 {label}", - "Global Context navigation": "全域態勢導航", - "Previous — prior visited contact in the 250 km window": "上一個——250 公里範圍內先前造訪的目標", + "Global Context navigation": "全局態勢導航", + "Previous — prior visited contact in the 250 km window": "上一個:250 km 範圍內先前訪問過的目標", "PREVIOUS": "上一個", "FOCUS": "聚焦", - "Next — nearest unvisited contact in the 250 km window": "下一個——250 公里範圍內最近的未造訪目標", + "Next — nearest unvisited contact in the 250 km window": "下一個:250 km 範圍內最近的未訪問目標", "NEXT": "下一個", "Named areas ({n})": "已命名區域({n})", - "{distance} FLIGHT / VESSEL WINDOW": "{distance} 航班 / 船舶監視範圍", - "Open-source mapped/observed context. Missing broadcasts, unloaded map areas, or unmapped sites are not evidence of absence.": "開源的地圖標註/觀測態勢資訊。缺失的廣播、未載入的地圖區域或未標註的設施不能作為不存在的證據。", - "mapped matches within {km} km of the subject": "所選物件 {km} km 內的地圖標註匹配", + "{distance} FLIGHT / VESSEL WINDOW": "{distance} 航班 / 船舶監視窗口", + "Open-source mapped/observed context. Missing broadcasts, unloaded map areas, or unmapped sites are not evidence of absence.": "開源的地圖標註/觀測態勢信息。缺失的廣播、未加載的地圖區域或未標註的設施不能作為不存在的證據。", + "mapped matches within {km} km of the subject": "所選對象 {km} km 內的地圖標註匹配", "none mapped within {km} km; not a complete 250 km survey": "{km} km 內無地圖標註;並非完整的 250 km 普查", - "mapped matches from the loaded viewport": "來自已載入視口的地圖標註匹配", - "viewport feed is not a complete 250 km survey": "視口資料來源並非完整的 250 km 普查", + "mapped matches from the loaded viewport": "來自已加載視口的地圖標註匹配", + "viewport feed is not a complete 250 km survey": "視口數據源並非完整的 250 km 普查", "HDG {value}°": "HDG {value}°", "BRG {value}°": "BRG {value}°", "BRG —": "BRG —", "CRS {value}°": "CRS {value}°", - "CURRENT VIEWPORT ONLY": "僅限目前視口", + "CURRENT VIEWPORT ONLY": "僅限當前視口", "WITHIN {km} KM": "{km} km 以內", "Flights": "航班", - "Military flights": "軍機", + "Military flights": "軍用航班", "AIS vessels": "AIS 船舶", "Mapped installations": "地圖標註設施", - "syncing {count} city feeds...": "正在同步 {count} 個城市資料來源…", + "syncing {count} city feeds...": "正在同步 {count} 個城市數據源…", "scanning nearby systems...": "正在掃描附近系統…", - "GBFS fetch error": "GBFS 取得錯誤", + "GBFS fetch error": "GBFS 獲取錯誤", "Station {id}": "站點 {id}", "Station": "站點", "🚲 {bikes} avail · {docks} docks · {capacity} cap": "🚲 可用 {bikes} · 車樁 {docks} · 容量 {capacity}", @@ -510,14 +510,14 @@ "⚠️ Not renting": "⚠️ 暫停租車", "⚠️ Not returning": "⚠️ 暫停還車", "HDG {value}° (ESTIMATED)": "HDG {value}°(估算)", - "{count} CAMERAS STANDING BY · NO CAMERA SELECTED · CLICK A CAMERA TO ACTIVATE": "{count} 個攝影機待命 · 未選擇攝影機 · 點選攝影機以啟用", - "No cameras available in catalog.": "目錄中沒有可用的攝影機。", + "{count} CAMERAS STANDING BY · NO CAMERA SELECTED · CLICK A CAMERA TO ACTIVATE": "{count} 個攝像頭待命 · 未選擇攝像頭 · 點擊攝像頭以激活", + "No cameras available in catalog.": "目錄中沒有可用攝像頭。", "{city} CCTV": "{city} CCTV", "FOV {value}° (DATASHEET)": "FOV {value}°(規格書)", "FOV {value}°": "FOV {value}°", "SPEC FOV {span}° (CAPABILITY)": "規格 FOV {span}°(可調範圍)", "COVERAGE {value}km²": "覆蓋 {value}km²", - "OVERLAP {count} cams": "重疊 {count} 個攝影機", + "OVERLAP {count} cams": "重疊 {count} 個攝像頭", "ISOLATED VIEW": "獨立視角", "PROJ MONITOR": "投影:監視器", "PROJ OFF": "投影:關", @@ -528,7 +528,7 @@ "{spec} · SPECS: CCTV-DATABASE.COM": "{spec} · 規格:CCTV-DATABASE.COM", "Atlantic and eastern/central North Pacific; not worldwide cyclone coverage.": "僅覆蓋大西洋及北太平洋東部和中部,並非全球氣旋覆蓋。", "Cyclone advisories unavailable": "氣旋公告不可用", - "Cyclone data unavailable": "氣旋資料不可用", + "Cyclone data unavailable": "氣旋數據不可用", "Potential tropical cyclone": "潛在熱帶氣旋", "Hurricane": "颶風", "Tropical storm": "熱帶風暴", @@ -538,25 +538,25 @@ "Track and cone match this advisory": "路徑和預報不確定範圍與本期公告一致", "Track/cone awaiting advisory {number}": "路徑/預報不確定範圍等待第 {number} 號公告", "Track/cone unavailable": "路徑/預報不確定範圍不可用", - "Cached advisory · stale source": "快取公告 · 資料來源已過期", - "Loading advisories…": "正在載入公告…", + "Cached advisory · stale source": "緩存公告 · 數據源已過期", + "Loading advisories…": "正在加載公告…", "{count} active storms": { "other": "{count} 個活躍氣旋" }, "Position as of {time}": "位置(截至 {time})", "Maximum sustained wind: {wind} · Pressure: {pressure}": "最大持續風速:{wind} · 氣壓:{pressure}", - "{name} · {classification} · Advisory {number} · issued {time}": "{name} · {classification} · 第 {number} 號公告 · 發布於 {time}", - "No active NHC/CPHC systems": "目前沒有活躍的 NHC/CPHC 氣旋", + "{name} · {classification} · Advisory {number} · issued {time}": "{name} · {classification} · 第 {number} 號公告 · 發佈於 {time}", + "No active NHC/CPHC systems": "當前沒有活躍的 NHC/CPHC 氣旋", "Advisories unavailable": "公告不可用", "Cyclones · NHC / CPHC": "氣旋 · NHC / CPHC", "Atlantic · E/C Pacific": "大西洋 · 東/中太平洋", "{storms} · {name} selected": "{storms} · 已選擇 {name}", "Official advisory ↗": "官方公告 ↗", "Active NHC and CPHC cyclone advisories": "活躍的 NHC 與 CPHC 氣旋公告", - "Wind unavailable": "風況資料不可用", + "Wind unavailable": "風場數據不可用", "Advisory center / forecast track": "公告中的氣旋中心 / 預報路徑", "Center-track uncertainty cone": "中心路徑預報不確定範圍", - "Select a storm on the map, or choose a storm in the list to select it and move the camera. Click empty map space to clear the selection. NOAA NHC/CPHC advisory context. The cone describes forecast center-track uncertainty, not storm size or the full hazard area. Forecast point labels are source lead hours, not times computed from advisory issuance. Geometry follows the surface; height is not weather altitude. Consult the official advisory.": "在地圖上點選氣旋,或在清單中點選氣旋,即可選中並移動相機。點選空白地圖區域可清除選擇。內容來自 NOAA NHC/CPHC 公告。該區域表示氣旋中心路徑預報的不確定範圍,不代表氣旋大小或全部災害影響範圍。預報點標註的是資料來源的預報時效(小時),不是按公告發布時刻推算的時間。幾何圖形貼地顯示;顯示高度並非氣象高度。請以官方公告為準。", + "Select a storm on the map, or choose a storm in the list to select it and move the camera. Click empty map space to clear the selection. NOAA NHC/CPHC advisory context. The cone describes forecast center-track uncertainty, not storm size or the full hazard area. Forecast point labels are source lead hours, not times computed from advisory issuance. Geometry follows the surface; height is not weather altitude. Consult the official advisory.": "在地圖上點選氣旋,或在列表中點選氣旋,即可選中並移動相機。點擊空白地圖區域可清除選擇。內容來自 NOAA NHC/CPHC 公告。該區域表示氣旋中心路徑預報的不確定範圍,不代表氣旋大小或全部災害影響範圍。預報點標註的是數據源的預報時效(小時),不是按公告發布時刻推算的時間。幾何圖形貼地顯示;顯示高度並非氣象高度。請以官方公告為準。", "DRIVE": "駕車", "Drive": "駕車", "WALK": "步行", @@ -632,62 +632,62 @@ "Take the exit on the {direction}": "從出口{direction}駛出", "Take the exit onto {road}": "從出口駛出,進入 {road}", "Take the exit": "從出口駛出", - "At the roundabout, take the {exit} exit onto {road}": "在圓環從{exit}出口駛出,進入 {road}", - "At the roundabout, take the {exit} exit": "在圓環從{exit}出口駛出", - "Enter the roundabout onto {road}": "駛入圓環,進入 {road}", - "Enter the roundabout": "駛入圓環", - "At the roundabout, turn {direction} onto {road}": "在圓環{direction}轉,進入 {road}", - "At the roundabout, turn {direction}": "在圓環{direction}轉", - "At the roundabout, continue onto {road}": "在圓環繼續行駛,進入 {road}", - "At the roundabout, continue": "在圓環繼續行駛", - "Exit the roundabout onto {road}": "駛出圓環,進入 {road}", - "Exit the roundabout": "駛出圓環", + "At the roundabout, take the {exit} exit onto {road}": "在環島從{exit}出口駛出,進入 {road}", + "At the roundabout, take the {exit} exit": "在環島從{exit}出口駛出", + "Enter the roundabout onto {road}": "駛入環島,進入 {road}", + "Enter the roundabout": "駛入環島", + "At the roundabout, turn {direction} onto {road}": "在環島{direction}轉,進入 {road}", + "At the roundabout, turn {direction}": "在環島{direction}轉", + "At the roundabout, continue onto {road}": "在環島繼續行駛,進入 {road}", + "At the roundabout, continue": "在環島繼續行駛", + "Exit the roundabout onto {road}": "駛出環島,進入 {road}", + "Exit the roundabout": "駛出環島", "Use the {direction} lane onto {road}": "使用{direction}車道,進入 {road}", "Use the {direction} lane": "使用{direction}車道", "Continue onto {road}": "繼續行駛,進入 {road}", "maneuver|Continue": "繼續行駛", "{mode} — reroute for {modeLower}": "{mode}——按{modeLower}重新規劃路線", - "CLICK MAP": "點選地圖", - "SET A": "設定 A", - "Click a spot on the globe to place A (click again to cancel)": "點選地球上的位置放置 A(再次點選取消)", - "Then click the globe to place the start": "然後點選地球放置起點", - "SET B": "設定 B", - "Click a spot on the globe to place B (click again to cancel)": "點選地球上的位置放置 B(再次點選取消)", - "Then click the globe to place the destination": "然後點選地球放置終點", - "Swap A and B": "交換 A 與 B", + "CLICK MAP": "點擊地圖", + "SET A": "設置 A", + "Click a spot on the globe to place A (click again to cancel)": "點擊地球上的位置放置 A(再次點擊取消)", + "Then click the globe to place the start": "然後點擊地球放置起點", + "SET B": "設置 B", + "Click a spot on the globe to place B (click again to cancel)": "點擊地球上的位置放置 B(再次點擊取消)", + "Then click the globe to place the destination": "然後點擊地球放置終點", + "Swap A and B": "交換 A 和 B", "FLY ···": "飛行 ···", "FLYING": "飛行中", "FLY": "飛行", "Fly the camera along the route": "讓相機沿路線飛行", "Place A and B first": "請先放置 A 和 B", "action|CLEAR": "清除", - "Remove the route and both markers": "移除路線與兩端標記", - "press Escape twice to leave Draw": "按兩次 Escape 退出「繪製」", - "{name} is active — turn {name} off, then set {endpoint}": "{name} 正在使用——請先關閉 {name},再設定 {endpoint}", - "{name} is active — {leave}, then set {endpoint}": "{name} 正在使用——請先{leave},再設定 {endpoint}", + "Remove the route and both markers": "移除路線和兩個標註點", + "press Escape twice to leave Draw": "按兩次 Escape 退出“繪製”", + "{name} is active — turn {name} off, then set {endpoint}": "{name} 正在使用——請先關閉 {name},再設置 {endpoint}", + "{name} is active — {leave}, then set {endpoint}": "{name} 正在使用——請先{leave},再設置 {endpoint}", "Only the first {count} turns of this route are shown": "此路線僅顯示前 {count} 個轉向", - "Turn-by-turn directions": "逐步導航", - "Another map tool is using clicks — close it, then SET A again": "另一個地圖工具正在攔截點選——請先關閉它,再重新設定 A", + "Turn-by-turn directions": "分步導航", + "Another map tool is using clicks — close it, then SET A again": "另一個地圖工具正在攔截點擊——請先關閉它,再重新設置 A", "Routing…": "正在規劃路線…", "No route found": "未找到路線", "{distance} · {duration} · {mode} · first {count} turns": "{distance} · {duration} · {mode} · 前 {count} 個轉向", "{distance} · {duration} · {mode}": "{distance} · {duration} · {mode}", - "Click the globe to place {endpoint}": "點選地球放置 {endpoint}", - "SET B, then click the globe": "設定 B,然後點選地球", - "SET A, then click the globe": "設定 A,然後點選地球", + "Click the globe to place {endpoint}": "點擊地球放置 {endpoint}", + "SET B, then click the globe": "設置 B,然後點擊地球", + "SET A, then click the globe": "設置 A,然後點擊地球", "Step {step} of {total} · then {leg}": "第 {step}/{total} 步 · 隨後 {leg}", "Step {step} of {total}": "第 {step} 步,共 {total} 步", "Then: {instruction}": "接下來:{instruction}", "No route found between A and B": "在 A 和 B 之間未找到路線", "Routing failed: {error}": "路線規劃失敗:{error}", - "Routing timed out": "路線規劃逾時", - "Routing unavailable — no response from the routing service": "路線規劃不可用——路線服務無回應", - "Earthquake source unavailable": "地震資料來源不可用", - "Focus fire detection {title}, {details}": "聚焦火點偵測 {title},{details}", - "live feed unavailable": "即時資料來源不可用", + "Routing timed out": "路線規劃超時", + "Routing unavailable — no response from the routing service": "路線規劃不可用——路線服務無響應", + "Earthquake source unavailable": "地震數據源不可用", + "Focus fire detection {title}, {details}": "聚焦火點探測 {title},{details}", + "live feed unavailable": "實時數據源不可用", "{value} conf": "置信度 {value}", "{value} ago": "{value}前", - "sensor n/a": "感測器 n/a", + "sensor n/a": "傳感器 n/a", "FIRE · {frp} MW": "火點 · {frp} MW", "NIGHT": "夜間", "▲ {frp} MW": "▲ {frp} MW", @@ -710,24 +710,24 @@ "age|{count}h": "{count} 小時", "age|{count}d": "{count} 天", "Fire · FRP {frp} MW": "火點 · FRP {frp} MW", - "STALE · cached {age}": "過期 · {age}前快取", - "refreshing...": "重新整理中…", - "loading...": "載入中…", - "KEY REQUIRED": "需要金鑰", - "LIVE · updated {age}": "即時 · 更新於 {age}", + "STALE · cached {age}": "過期 · {age}前緩存", + "refreshing...": "刷新中…", + "loading...": "加載中…", + "KEY REQUIRED": "需要密鑰", + "LIVE · updated {age}": "實時 · 更新於 {age}", "Source snapshot time unavailable": "來源快照時間不可用", - "Live data unavailable": "即時資料不可用", + "Live data unavailable": "實時數據不可用", "Low-accuracy score < 2%": "低精度評分 < 2%", "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 分鐘內已瀏覽視野中的網格", + "GNSS integrity source unavailable": "GNSS 完好性數據源不可用", + "Regional sample · 250 nm radius · cells from visited views over 30 min": "區域採樣 · 半徑 250 海里 · 30 分鐘內已訪問視圖中的網格", "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 海里的範圍;縮小地圖並不會使其成為全球快照。空白網格位於取樣覆蓋範圍之外,或觀測資料不足。", + "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 海里的範圍;縮小地圖並不會使其成為全球快照。空白網格位於採樣覆蓋範圍之外,或觀測數據不足。", "Low-accuracy score = 100 × max(0, bad − 1) / total: one aircraft is discounted, so this is not the raw share. Cells need {aircraft} aircraft over {minutes} minutes. Navigation-integrity anomalies are not a detection of jamming or spoofing.": "低精度評分 = 100 × max(0, bad − 1) / total:扣除一架飛機,因此並非原始佔比。每個網格需在 {minutes} 分鐘內有 {aircraft} 架飛機。導航完好性異常不等於檢測到干擾或欺騙。", - "GNSS snapshot needs a view anchor": "GNSS 快照需要視野錨點", - "GNSS feed rate limited (HTTP 429)": "GNSS 資料來源已被限流(HTTP 429)", + "GNSS snapshot needs a view anchor": "GNSS 快照需要視圖錨點", + "GNSS feed rate limited (HTTP 429)": "GNSS 數據源已被限流(HTTP 429)", "Malformed GNSS integrity snapshot": "GNSS 完好性快照格式錯誤", "GNSS integrity snapshot has no observation time": "GNSS 完好性快照缺少觀測時間", "installation class|AIRFIELD": "機場", @@ -747,9 +747,9 @@ "{count} mapped sites in view": { "other": "視野內有 {count} 個地圖標註設施" }, - "loading mapped installation context": "正在載入地圖標註設施資訊", + "loading mapped installation context": "正在加載地圖標註設施信息", "Too many mapped sites in view to list them all": "視野內地圖標註設施過多,無法全部列出", - "Installation context unavailable": "設施資訊不可用", + "Installation context unavailable": "設施信息不可用", "MAPPED INSTALLATION": "地圖標註設施", "Unknown": "未知", "LAUNCH SITE · {site}": "發射場 · {site}", @@ -764,16 +764,16 @@ "PAUSED · {title}": "已暫停 · {title}", "UNSPECIFIED": "未指明", "+{count} additional payload records": "另有 {count} 條有效載荷記錄", - "PAYLOAD DATA UNAVAILABLE": "有效載荷資料不可用", + "PAYLOAD DATA UNAVAILABLE": "有效載荷數據不可用", "{value} KM DOWNRANGE": "落點距離 {value} km", - "POSITION UNAVAILABLE": "無法取得位置", + "POSITION UNAVAILABLE": "位置不可用", "FLIGHT {count}": "第 {count} 次飛行", "REUSED": "複用", - "NO STAGE RE-ENTRY / RECOVERY DATA": "無子級再入 / 回收資料", + "NO STAGE RE-ENTRY / RECOVERY DATA": "無子級再入 / 回收數據", "{count} / 30D": "{count} / 30 天", - "NO MISSIONS AVAILABLE IN THE CURRENT 30-DAY WINDOW": "目前 30 天視窗內沒有可用任務", + "NO MISSIONS AVAILABLE IN THE CURRENT 30-DAY WINDOW": "當前 30 天窗口內沒有可用任務", "DATE UNAVAILABLE": "日期不可用", - "UNSPECIFIED OPERATOR": "營運方未指明", + "UNSPECIFIED OPERATOR": "運營方未指明", "Select {mission}": "選擇 {mission}", "{value} KM": "{value} km", "{value} KM/S": "{value} km/s", @@ -787,11 +787,11 @@ "LAUNCH TIME · ": "發射時間 · ", "ORBIT · ": "軌道 · ", "ASCENT PATH · ": "上升軌跡 · ", - "CURRENT DISTANCE FROM EARTH · ": "目前與地球的距離 · ", + "CURRENT DISTANCE FROM EARTH · ": "當前與地球的距離 · ", "SATELLITE SPEED · ": "衛星速度 · ", "PAYLOAD": "有效載荷", "NAME": "名稱", - "TYPE": "型別", + "TYPE": "類型", "DESTINATION": "目的地", "STAGE / RE-ENTRY / RECOVERY": "子級 / 再入 / 回收", "STAGE": "子級", @@ -799,7 +799,7 @@ "FINAL POSITION": "最終位置", "REPLAY SPEED": "回放速度", "Replay speed multiplier": "回放速度倍率", - "REPLAY ASCENT": "回放升空", + "REPLAY ASCENT": "回放上升過程", "Previous mission": "上一個任務", "PREV": "上一個", "Next mission": "下一個任務", @@ -807,10 +807,10 @@ "Pause replay": "暫停回放", "Cancel replay": "取消回放", "EST. DOWNRANGE": "預估落點距離", - "PLANNED · ": "計畫 · ", + "PLANNED · ": "計劃 · ", "SUPPLIED TRAJECTORY POINTS": "提供的軌跡點", "RECONSTRUCTED ESTIMATE": "重建估算", - "Replay the estimated ascent with a following camera": "以跟隨鏡頭回放推估的升空過程", + "Replay the estimated ascent with a following camera": "以跟隨相機回放估算的上升過程", "Resume replay": "繼續回放", "T minus {seconds}": "T−{seconds}", "Preparing launch site": "正在準備發射場", @@ -823,9 +823,9 @@ "1090 MHz": "1090 MHz", "978 MHz UAT": "978 MHz UAT", "browser SDR": "瀏覽器 SDR", - "decoder feed": "解碼器資料來源", - "Your RTL-SDR receiver and decoder feed": "你的 RTL-SDR 接收機和解碼器資料來源", - "Your decoder feed": "你的解碼器資料來源", + "decoder feed": "解碼器數據源", + "Your RTL-SDR receiver and decoder feed": "你的 RTL-SDR 接收機和解碼器數據源", + "Your decoder feed": "你的解碼器數據源", "Your RTL-SDR receiver": "你的 RTL-SDR 接收機", "NO CALLSIGN": "無呼號", "ALT {altitude} FT · GS {speed} KT · TRK {track}": "高度 {altitude} ft · 地速 {speed} kn · 航跡角 {track}", @@ -834,21 +834,21 @@ "POSITION {age}": "位置 {age}前", "POSITION {seconds} S AGO": "位置 {seconds} 秒前", "{count} MSGS": { - "other": "{count} 條訊息" + "other": "{count} 條消息" }, - "Decoder feeds": "解碼器資料來源", - "WebUSB + decoder feeds": "WebUSB + 解碼器資料來源", - "opening receiver": "正在開啟接收機", - "checking decoder feeds": "正在檢查解碼器資料來源", + "Decoder feeds": "解碼器數據源", + "WebUSB + decoder feeds": "WebUSB + 解碼器數據源", + "opening receiver": "正在打開接收機", + "checking decoder feeds": "正在檢查解碼器數據源", "WebUSB needs desktop Chrome or Edge": "WebUSB 需要桌面版 Chrome 或 Edge", - "connect a receiver in Radio": "在電台面板連線接收機", + "connect a receiver in Radio": "在電臺面板連接接收機", "receiver is in FM mode": "接收機處於 FM 模式", "listening": "監聽中", "USB error": "USB 錯誤", "Alt unknown": "高度未知", - "Type unknown": "型別未知", + "Type unknown": "類型未知", "Reg unknown": "註冊號未知", - "Operator unknown": "營運方未知", + "Operator unknown": "運營方未知", "${amount}K": "{amount}K 美元", "${amount}M": "{amount}M 美元", "${amount}B": "{amount}B 美元", @@ -876,11 +876,11 @@ "discovered {age} ago": "發現於 {age}前", "updated {age} ago": "更新於 {age}前", "part of {complex}": "屬於 {complex} 複合火場", - "InciWeb ↗ · click card to open": "InciWeb ↗ · 點選卡片開啟", + "InciWeb ↗ · click card to open": "InciWeb ↗ · 點擊卡片打開", "FIRE · {name}": "火場 · {name}", - "Unnamed incident": "未命名事件", - "Open {title} on InciWeb": "在 InciWeb 上開啟 {title}", - "Perimeter source unavailable": "周界資料來源不可用", + "Unnamed incident": "未命名火情", + "Open {title} on InciWeb": "在 InciWeb 上打開 {title}", + "Perimeter source unavailable": "周界數據源不可用", "Not contained or unknown": "未控制或未知", "Under 50% contained": "控制低於 50%", "50–99% contained": "控制 50–99%", @@ -889,28 +889,28 @@ "Malformed perimeter snapshot": "周界快照格式錯誤", "radio tag|All": "全部", "News": "新聞", - "Talk": "談話", - "Weather / Emergency": "氣象 / 緊急", + "Talk": "脫口秀", + "Weather / Emergency": "天氣 / 應急", "Public Safety": "公共安全", - "Aviation / Marine": "航空/海事", - "Traffic / Transit": "交通/運輸", + "Aviation / Marine": "航空 / 海事", + "Traffic / Transit": "交通 / 公共交通", "Music": "音樂", "Other": "其他", - "Directory refresh degraded; showing the previous station catalog.": "目錄重新整理降級;正在顯示上一次的電台目錄。", - "Radio directory coverage is degraded.": "電台目錄覆蓋已降級。", - "Directory refresh failed; showing the previous station catalog.": "目錄重新整理失敗;正在顯示上一次的電台目錄。", - "Radio directory is temporarily unavailable.": "電台目錄暫時無法使用。", + "Directory refresh degraded; showing the previous station catalog.": "目錄刷新降級;正在顯示上一次的電臺目錄。", + "Radio directory coverage is degraded.": "電臺目錄覆蓋已降級。", + "Directory refresh failed; showing the previous station catalog.": "目錄刷新失敗;正在顯示上一次的電臺目錄。", + "Radio directory is temporarily unavailable.": "電臺目錄暫時不可用。", "radio|NEWS": "新聞", - "radio|TALK": "談話", + "radio|TALK": "脫口秀", "radio|WEATHER": "天氣", "radio|SAFETY": "安全", "radio|AIR / SEA": "航空 / 海事", - "radio|TRANSIT": "大眾運輸", + "radio|TRANSIT": "公共交通", "radio|MUSIC": "音樂", "radio|OTHER": "其他", - "Broadcaster stream is unavailable or blocked by the browser.": "廣播串流不可用,或被瀏覽器阻止。", - "Playback requires a direct click or tap.": "需直接點選或輕觸才能播放。", - "Broadcaster stream could not be started.": "無法啟動廣播串流。", + "Broadcaster stream is unavailable or blocked by the browser.": "廣播流不可用,或被瀏覽器阻止。", + "Playback requires a direct click or tap.": "需直接點擊或輕觸才能播放。", + "Broadcaster stream could not be started.": "無法啟動廣播流。", "Alternative": "另類", "Ambient": "氛圍", "Blues": "藍調", @@ -928,7 +928,7 @@ "Metal": "金屬樂", "Oldies": "懷舊金曲", "Pop": "流行", - "Punk": "龐克", + "Punk": "朋克", "R&B": "R&B", "Reggae": "雷鬼", "Rock": "搖滾", @@ -950,118 +950,118 @@ "Daily overview for today may still be empty until the pass": "衛星過境前,今天的每日概覽可能仍為空", "Box and images cleared": "框選及影像已清除", "MORE DETAIL · 30 m": "更多細節 · 30 m", - "Sentinel-2 and Landsat via HLS, 30 m, every 2–6 days": "Sentinel-2 與 Landsat,透過 HLS,30 m,每 2–6 天", + "Sentinel-2 and Landsat via HLS, 30 m, every 2–6 days": "Sentinel-2 與 Landsat,經 HLS,30 m,每 2–6 天", "DAILY OVERVIEW · 250 m": "每日概覽 · 250 m", "VIIRS daily mosaic, 250 m, follows broad changes; little detail under 25 km": "VIIRS 每日鑲嵌圖,250 m,反映大範圍變化;25 km 以下幾乎沒有細節", "Sentinel-2": "Sentinel-2", - "Sentinel-2 via HLS": "Sentinel-2(透過 HLS)", + "Sentinel-2 via HLS": "Sentinel-2(經 HLS)", "Landsat 8/9": "Landsat 8/9", - "Landsat 8/9 via HLS": "Landsat 8/9(透過 HLS)", + "Landsat 8/9 via HLS": "Landsat 8/9(經 HLS)", "Daily overview": "每日概覽", "Box edges must be finite": "框選邊界必須是有限值", "Longitudes must be within ±180°": "經度必須在 ±180° 以內", "Select one side of the dateline": "請只選擇日界線的一側", "Box must enclose an area": "框選必須包含一定面積", - "Add the full Starlink broadband shell (thousands of extra points)": "加入完整 Starlink 寬頻星座(額外數千個點)", - "Loading the Starlink shell…": "正在載入 Starlink 星座…", - "Starlink {detail} — click to retry": "Starlink {detail}——點選重試", - "load failed": "載入失敗", - "Showing the full Starlink shell — click for the core catalog only": "正在顯示完整的 Starlink 星座——點選僅顯示核心目錄", + "Add the full Starlink broadband shell (thousands of extra points)": "添加完整的 Starlink 寬帶星座(數千個額外點位)", + "Loading the Starlink shell…": "正在加載 Starlink 星座…", + "Starlink {detail} — click to retry": "Starlink {detail}——點擊重試", + "load failed": "加載失敗", + "Showing the full Starlink shell — click for the core catalog only": "正在顯示完整的 Starlink 星座——點擊僅顯示核心目錄", "DENSE ···": "密集 ···", "DENSE ✕": "密集 ✕", "DENSE": "密集", - "CelesTrak unreachable": "CelesTrak 無法連線", + "CelesTrak unreachable": "CelesTrak 無法連接", "DOCKED · {name} · +{extra}": "對接 · {name} · +{extra}", "DOCKED · {name}": "對接 · {name}", - "{name} needs the Google 3D map: choose it under MAP SOURCE": "{name} 需要 Google 3D 地圖:請在地圖來源(MAP SOURCE)中選擇", - "zoom in to a street to open {name}": "放大到街道以開啟 {name}", - "KEY REJECTED": "金鑰被拒絕", - "loading coverage...": "正在載入覆蓋範圍…", + "{name} needs the Google 3D map: choose it under MAP SOURCE": "{name} 需要 Google 3D 地圖:請在地圖源(MAP SOURCE)中選擇", + "zoom in to a street to open {name}": "放大到街道以打開 {name}", + "KEY REJECTED": "密鑰被拒絕", + "loading coverage...": "正在加載覆蓋範圍…", "No street-level imagery within {radius} m of that point": "該點 {radius} m 範圍內沒有街景影像", "No street-level imagery within {radius} m of the view centre": "視野中心 {radius} m 範圍內沒有街景影像", - "Coverage tile failed": "覆蓋瓦片載入失敗", - "The photo could not be loaded": "照片無法載入", + "Coverage tile failed": "覆蓋瓦片加載失敗", + "The photo could not be loaded": "照片無法加載", "{name} photo. ← and → step along the sequence. On a 360° photo, drag or use Shift+← →, ↑ ↓ to look around, and + − to zoom": "{name} 照片。← 和 → 沿序列切換。在 360° 照片上,拖動或使用 Shift+← →、↑ ↓ 環視,+ − 縮放", "{name} street-level photo": "{name} 街景照片", "Previous photo in this sequence (←)": "此序列中的上一張照片(←)", "Next photo in this sequence (→)": "此序列中的下一張照片(→)", - "Aim the middle of the view at a street to look for imagery there": "將視野中心對準街道以查詢該處影像", - "GOOGLE_MAPS_API_KEY is not set": "未設定 GOOGLE_MAPS_API_KEY", - "The Google Maps JavaScript API could not load": "Google Maps JavaScript API 無法載入", + "Aim the middle of the view at a street to look for imagery there": "將視野中心對準街道以查找該處影像", + "GOOGLE_MAPS_API_KEY is not set": "未設置 GOOGLE_MAPS_API_KEY", + "The Google Maps JavaScript API could not load": "Google Maps JavaScript API 無法加載", "Google Street View": "Google 街景", "GOOGLE STREET VIEW": "Google 街景", - "Google refused GOOGLE_MAPS_API_KEY for Street View — check that the Maps JavaScript API is enabled for it and this site is an allowed referrer": "Google 拒絕了用於街景的 GOOGLE_MAPS_API_KEY——請確認已為該金鑰啟用 Maps JavaScript API,且本站點在允許的引薦來源(referrer)中", - "Street View did not answer — check the network, and that the Maps JavaScript API is enabled for GOOGLE_MAPS_API_KEY": "街景無回應——請檢查網路,並確認 GOOGLE_MAPS_API_KEY 已啟用 Maps JavaScript API", - "click a street to open Street View": "點選街道以開啟街景", + "Google refused GOOGLE_MAPS_API_KEY for Street View — check that the Maps JavaScript API is enabled for it and this site is an allowed referrer": "Google 拒絕了用於街景的 GOOGLE_MAPS_API_KEY——請確認已為該密鑰啟用 Maps JavaScript API,且本站點在允許的引薦來源(referrer)中", + "Street View did not answer — check the network, and that the Maps JavaScript API is enabled for GOOGLE_MAPS_API_KEY": "街景無響應——請檢查網絡,並確認 GOOGLE_MAPS_API_KEY 已啟用 Maps JavaScript API", + "click a street to open Street View": "點擊街道以打開街景", "Street View has no imagery for this place": "街景沒有此地的影像", "KartaView has no position for this photo": "KartaView 沒有此照片的位置", - "The KartaView photo could not be loaded": "KartaView 照片無法載入", - "zoom in to see KartaView coverage": "放大以檢視 KartaView 覆蓋範圍", + "The KartaView photo could not be loaded": "KartaView 照片無法加載", + "zoom in to see KartaView coverage": "放大以查看 KartaView 覆蓋範圍", "no KartaView photos in view": "視野內沒有 KartaView 照片", "KartaView is rate-limiting requests — they resume on their own": "KartaView 已被限流——稍後會自動恢復", "KartaView’s photos here are archived and cannot be shown": "KartaView 在此處的照片已歸檔,無法顯示", "KartaView did not filter this area in time — move the map to ask again": "KartaView 未能及時篩選此區域——移動地圖以重新請求", "None of KartaView’s photos here pass the imagery filter": "此處沒有 KartaView 照片通過影像篩選", - "KartaView did not answer in time — try again": "KartaView 未及時回應——請重試", - "KartaView could not be reached — check the network": "無法連線 KartaView——請檢查網路", - "KartaView sent an answer that could not be read": "KartaView 返回的回應無法讀取", + "KartaView did not answer in time — try again": "KartaView 未及時響應——請重試", + "KartaView could not be reached — check the network": "無法連接 KartaView——請檢查網絡", + "KartaView sent an answer that could not be read": "KartaView 返回的響應無法讀取", "KartaView is rate-limiting requests": "KartaView 已被限流", - "KartaView sent too much data": "KartaView 返回的資料過多", + "KartaView sent too much data": "KartaView 返回的數據過多", "KartaView is rate-limiting requests — try again in a moment": "KartaView 已被限流——請稍後重試", "KartaView has no such photo": "KartaView 沒有這張照片", - "Mapillary rejected MAPILLARY_CLIENT_TOKEN — replace it in Provider Settings": "Mapillary 拒絕了 MAPILLARY_CLIENT_TOKEN——請在服務供應商設定中更換該權杖", + "Mapillary rejected MAPILLARY_CLIENT_TOKEN — replace it in Provider Settings": "Mapillary 拒絕了 MAPILLARY_CLIENT_TOKEN——請在服務商設置中更換", "Coverage requests are being rate-limited — they resume on their own": "覆蓋範圍請求已被限流——稍後會自動恢復", - "The Panoramax photo could not be loaded": "Panoramax 照片無法載入", + "The Panoramax photo could not be loaded": "Panoramax 照片無法加載", "Panoramax is busy — coverage resumes on its own": "Panoramax 繁忙——覆蓋範圍稍後會自動恢復", "no Panoramax photos in view": "視野內沒有 Panoramax 照片", "no Panoramax photos here match the filters": "此處沒有符合篩選條件的 Panoramax 照片", "Panoramax sent a map tile that could not be read": "Panoramax 返回的地圖瓦片無法讀取", "This Panoramax photo is no longer available": "這張 Panoramax 照片已不可用", - "zoom in to see Panoramax coverage": "放大以檢視 Panoramax 覆蓋範圍", - "Panoramax did not answer in time — try again": "Panoramax 未及時回應——請重試", - "Panoramax could not be reached — check the connection": "無法連線 Panoramax——請檢查網路連線", - "Panoramax sent too much data": "Panoramax 返回的資料過多", + "zoom in to see Panoramax coverage": "放大以查看 Panoramax 覆蓋範圍", + "Panoramax did not answer in time — try again": "Panoramax 未及時響應——請重試", + "Panoramax could not be reached — check the connection": "無法連接 Panoramax——請檢查網絡連接", + "Panoramax sent too much data": "Panoramax 返回的數據過多", "Panoramax is busy": "Panoramax 繁忙", - "Panoramax sent an unreadable answer": "Panoramax 返回的回應無法讀取", - "No street-level imagery providers configured": "未配置街景影像服務供應商", + "Panoramax sent an unreadable answer": "Panoramax 返回的響應無法讀取", + "No street-level imagery providers configured": "未配置街景影像服務商", "(by upload date)": "(按上傳日期)", - "Open the Street Level panel to view imagery": "開啟街景面板以檢視影像", - "Image could not be opened": "圖像無法開啟", - "TeleGeography load failed": "TeleGeography 載入失敗", + "Open the Street Level panel to view imagery": "打開街景面板以查看影像", + "Image could not be opened": "圖像無法打開", + "TeleGeography load failed": "TeleGeography 加載失敗", "UNAVAILABLE · {source} · Roads unavailable": "不可用 · {source} · 道路不可用", "Roads: {source}": "道路:{source}", - "TomTom roads unavailable while the traffic service is unreachable": "交通服務無法連線期間,TomTom 道路不可用", - "Hybrid unavailable while the traffic service is unreachable": "交通服務無法連線期間,混合模式不可用", - "TomTom roads need a TomTom key": "TomTom 道路需要 TomTom 金鑰", - "Hybrid needs a TomTom key": "混合模式需要 TomTom 金鑰", - "Local surface still loading": "本機路面仍在載入", + "TomTom roads unavailable while the traffic service is unreachable": "交通服務無法連接期間,TomTom 道路不可用", + "Hybrid unavailable while the traffic service is unreachable": "交通服務無法連接期間,混合模式不可用", + "TomTom roads need a TomTom key": "TomTom 道路需要 TomTom 密鑰", + "Hybrid needs a TomTom key": "混合模式需要 TomTom 密鑰", + "Local surface still loading": "本地路面仍在加載", "Partial coverage": "部分覆蓋", "Detailed roads unavailable": "詳細道路不可用", "Reduced detail coverage": "詳細覆蓋範圍受限", - "TomTom roads only, each with its live flow": "僅 TomTom 道路,各自帶即時路況", - "TomTom roads only, each with its live flow (needs a TomTom key)": "僅 TomTom 道路,各自帶即時路況(需要 TomTom 金鑰)", + "TomTom roads only, each with its live flow": "僅 TomTom 道路,各自帶實時路況", + "TomTom roads only, each with its live flow (needs a TomTom key)": "僅 TomTom 道路,各自帶實時路況(需要 TomTom 密鑰)", "OpenStreetMap roads, with TomTom flow matched when available": "OpenStreetMap 道路,可用時匹配 TomTom 路況", - "TomTom roads first; OpenStreetMap fills the rest, simulated": "優先使用 TomTom 道路及即時路況;缺失路段由 OpenStreetMap 補充,並模擬其路況", - "TomTom roads first; OpenStreetMap fills the rest, simulated (needs a TomTom key)": "優先使用 TomTom 道路及即時路況;缺失路段由 OpenStreetMap 補充,並模擬其路況(需要 TomTom 金鑰)", + "TomTom roads first; OpenStreetMap fills the rest, simulated": "優先使用 TomTom 道路及實時路況;缺失路段由 OpenStreetMap 補充,並模擬其路況", + "TomTom roads first; OpenStreetMap fills the rest, simulated (needs a TomTom key)": "優先使用 TomTom 道路及實時路況;缺失路段由 OpenStreetMap 補充,並模擬其路況(需要 TomTom 密鑰)", "Hybrid": "混合", - "TomTom key unavailable": "TomTom 金鑰不可用", + "TomTom key unavailable": "TomTom 密鑰不可用", "TomTom daily budget reached": "已達 TomTom 每日配額", - "TomTom upstream unreachable": "TomTom 上游服務無法連線", + "TomTom upstream unreachable": "TomTom 上游服務無法連接", "TomTom flow unavailable": "TomTom 路況不可用", "SIMULATED — {reason}": "模擬——{reason}", "Syncing flow · Roads: {source}": "正在同步路況 · 道路:{source}", - "LIVE · Roads: {source} · Roads without flow hidden": "即時 · 道路:{source} · 已隱藏無路況道路", - "LIVE · Roads: {source} · No flow roads in view": "即時 · 道路:{source} · 視野內沒有帶路況資料的道路", - "LIVE · Roads: {source} · Flow {percent}%": "即時 · 道路:{source} · 路況 {percent}%", + "LIVE · Roads: {source} · Roads without flow hidden": "實時 · 道路:{source} · 已隱藏無路況道路", + "LIVE · Roads: {source} · No flow roads in view": "實時 · 道路:{source} · 視野內沒有帶路況數據的道路", + "LIVE · Roads: {source} · Flow {percent}%": "實時 · 道路:{source} · 路況 {percent}%", "SIMULATED · Roads: {source} · Flow {percent}%": "模擬 · 道路:{source} · 路況 {percent}%", "Syncing flow · Roads: OpenStreetMap · Flow: TomTom · Unmatched: simulated": "正在同步路況 · 道路:OpenStreetMap · 路況:TomTom · 未匹配:模擬", - "LIVE · Roads: OpenStreetMap · Flow: TomTom · {percent}% cov · Unmatched: simulated": "即時 · 道路:OpenStreetMap · 路況:TomTom · 覆蓋 {percent}% · 未匹配:模擬", - "LIVE · Roads: OpenStreetMap · Flow: TomTom · {percent}% cov": "即時 · 道路:OpenStreetMap · 路況:TomTom · 覆蓋 {percent}%", + "LIVE · Roads: OpenStreetMap · Flow: TomTom · {percent}% cov · Unmatched: simulated": "實時 · 道路:OpenStreetMap · 路況:TomTom · 覆蓋 {percent}% · 未匹配:模擬", + "LIVE · Roads: OpenStreetMap · Flow: TomTom · {percent}% cov": "實時 · 道路:OpenStreetMap · 路況:TomTom · 覆蓋 {percent}%", "SIMULATED · Roads: OpenStreetMap · Flow: TomTom (no matches)": "模擬 · 道路:OpenStreetMap · 路況:TomTom(無匹配)", - "SIMULATED — traffic service unreachable": "模擬——交通服務無法連線", - "SIMULATED — add TomTom key for live": "模擬——加入 TomTom 金鑰以取得即時路況", + "SIMULATED — traffic service unreachable": "模擬——交通服務無法連接", + "SIMULATED — add TomTom key for live": "模擬——添加 TomTom 密鑰以獲取實時數據", "OpenFreeMap tiles rate-limited": "OpenFreeMap 瓦片已被限流", - "OpenFreeMap tiles timed out": "OpenFreeMap 瓦片逾時", + "OpenFreeMap tiles timed out": "OpenFreeMap 瓦片超時", "OpenFreeMap tiles unavailable": "OpenFreeMap 瓦片不可用", "occupancy|empty": "空載", "occupancy|many seats available": "空座較多", @@ -1077,56 +1077,56 @@ "No recent fix": "無近期定位", "Waiting for update": "等待更新", "Moving": "行駛中", - "reported {speed} km/h": "回報 {speed} km/h", - "reported hdg {heading}°": "回報航向 {heading}°", - "Last report: stopped at stop {stop}": "最近回報:已停靠於站點 {stop}", - "Last report: arriving at stop {stop}": "最近回報:即將到達站點 {stop}", - "Last report: next stop {stop}": "最近回報:下一站 {stop}", - "Shown at street level · depth not in the feed": "按地面高度顯示 · 資料來源未提供深度", - "Reported {seconds} s ago": "{seconds} 秒前回報", - "Reported {minutes} min ago": "{minutes} 分鐘前回報", + "reported {speed} km/h": "上報 {speed} km/h", + "reported hdg {heading}°": "上報航向 {heading}°", + "Last report: stopped at stop {stop}": "最近上報:停靠站點 {stop}", + "Last report: arriving at stop {stop}": "最近上報:即將到達站點 {stop}", + "Last report: next stop {stop}": "最近上報:下一站 {stop}", + "Shown at street level · depth not in the feed": "按地面高度顯示 · 數據源未提供深度", + "Reported {seconds} s ago": "{seconds} 秒前上報", + "Reported {minutes} min ago": "{minutes} 分鐘前上報", "shown {seconds} s behind": "顯示滯後 {seconds} 秒", - "{reported} (feed time)": "{reported}(資料來源時間)", + "{reported} (feed time)": "{reported}(數據源時間)", "Available trail: {minutes} min (limited)": "可用軌跡:{minutes} 分鐘(受限)", "Available trail: {minutes} min": "可用軌跡:{minutes} 分鐘", - "Bus": "公車", - "Tram": "路面電車", + "Bus": "公交車", + "Tram": "有軌電車", "Subway": "地鐵", "Train": "火車", "Ferry": "渡輪", - "Transit vehicle": "大眾運輸車輛", + "Transit vehicle": "公共交通車輛", "AIS: {name}": "AIS: {name}", "{type} SPD: {speed} HDG: {heading}": "{type} SPD: {speed} HDG: {heading}", "VESSEL": "船舶", "{speed}KT": "{speed} kn", "{heading}DEG": "{heading}°", - "POS: LIVE": "POS:即時", + "POS: LIVE": "POS:實時", "POS: {time}Z": "POS:{time}Z", - "AIS live load failed": "AIS 即時資料載入失敗", + "AIS live load failed": "AIS 實時數據加載失敗", "awaiting first AIS position…": "等待首個 AIS 位置…", "awaiting usable AIS positions…": "等待可用的 AIS 位置…", - "awaiting first AIS message…": "等待首條 AIS 訊息…", - "AISSTREAM_API_KEY not set": "未設定 AISSTREAM_API_KEY", - "live feed unsupported": "不支援即時資料來源", - "connecting to feed…": "正在連線資料來源…", - "feed disconnected": "資料來源已斷開", - "feed down": "資料來源中斷", - "feed idle": "資料來源空閒", - "API key rejected — check AISSTREAM_API_KEY": "API 金鑰被拒絕——請檢查 AISSTREAM_API_KEY", - "feed silent {seconds}s — no AIS data": "資料來源已靜默 {seconds} 秒——無 AIS 資料", - "feed silent — no AIS data": "資料來源已靜默——無 AIS 資料", - "feed down — retrying slowly (attempt {attempt})": "資料來源中斷——正在低頻重試(第 {attempt} 次)", - "reconnecting to feed… (attempt {attempt})": "正在重新連線資料來源…(第 {attempt} 次)", - "feed down — retrying slowly": "資料來源中斷——正在低頻重試", - "reconnecting to feed…": "正在重新連線資料來源…", + "awaiting first AIS message…": "等待首條 AIS 消息…", + "AISSTREAM_API_KEY not set": "未設置 AISSTREAM_API_KEY", + "live feed unsupported": "不支持實時數據源", + "connecting to feed…": "正在連接數據源…", + "feed disconnected": "數據源已斷開", + "feed down": "數據源中斷", + "feed idle": "數據源空閒", + "API key rejected — check AISSTREAM_API_KEY": "API 密鑰被拒絕——請檢查 AISSTREAM_API_KEY", + "feed silent {seconds}s — no AIS data": "數據源已靜默 {seconds} 秒——無 AIS 數據", + "feed silent — no AIS data": "數據源已靜默——無 AIS 數據", + "feed down — retrying slowly (attempt {attempt})": "數據源中斷——正在低頻重試(第 {attempt} 次)", + "reconnecting to feed… (attempt {attempt})": "正在重新連接數據源…(第 {attempt} 次)", + "feed down — retrying slowly": "數據源中斷——正在低頻重試", + "reconnecting to feed…": "正在重新連接數據源…", "Focus vessel {name}, MMSI {mmsi}": "聚焦船舶 {name},MMSI {mmsi}", - "Hidden by this map source · choose a globe map": "已被目前地圖來源隱藏 · 請選擇地球地圖", + "Hidden by this map source · choose a globe map": "已被當前地圖源隱藏 · 請選擇地球地圖", "Weather image HTTP {status}": "天氣圖像 HTTP {status}", "Weather HTTP {status}": "天氣 HTTP {status}", "Frame unavailable; previous observation retained": "幀不可用;保留上一幀觀測", "Weather imagery unavailable": "天氣影像不可用", - "Weather source unavailable; previous observation retained": "天氣資料來源不可用;保留上一幀觀測", - "Weather unavailable": "天氣資料不可用", + "Weather source unavailable; previous observation retained": "天氣數據源不可用;保留上一幀觀測", + "Weather unavailable": "天氣數據不可用", "No frame within {gap} min of {time}": "{time} 前後 {gap} 分鐘內沒有幀", "No frame within {gap} h of {time}": "{time} 前後 {gap} 小時內沒有幀", "{hours}h {minutes}m ago": "{hours} 小時 {minutes} 分鐘前", @@ -1135,7 +1135,7 @@ "Observed": "觀測", "History": "歷史", "Observation unavailable": "觀測不可用", - "Waiting for observation": "等待觀測資料", + "Waiting for observation": "等待觀測數據", "{detail} · synced": "{detail} · 已同步", "{detail} · nearest": "{detail} · 最接近", "RADAR REFLECTIVITY · dBZ": "雷達反射率 · dBZ", @@ -1145,9 +1145,9 @@ "{state}: {time}": "{state}:{time}", "Latest observation": "最新觀測", "frame {index}/{total}": "第 {index}/{total} 幀", - "loading": "載入中", + "loading": "加載中", "Observation: unavailable": "觀測:不可用", - "Contiguous US · gaps ≠ no rain": "美國本土 · 資料缺失 ≠ 無降雨", + "Contiguous US · gaps ≠ no rain": "美國本土 · 數據缺失 ≠ 無降雨", "Americas + Pacific · not individual strikes": "美洲與太平洋 · 非單次閃擊", "Color: strikes/km²/min ×10³": "顏色:閃擊次數/km²/分鐘 ×10³", "60°S–60°N · typically 2–3 h delayed": "60°S–60°N · 通常延遲 2–3 小時", @@ -1160,9 +1160,9 @@ "Americas + Pacific": "美洲與太平洋", "Global · 60°S–60°N": "全球 · 60°S–60°N", "North America": "北美洲", - "Source observations delayed": "資料來源觀測延遲", - "Stale source": "資料來源已過期", - "Loading next frame…": "正在載入下一幀…", + "Source observations delayed": "數據源觀測延遲", + "Stale source": "數據源已過期", + "Loading next frame…": "正在加載下一幀…", "Map center outside coverage": "地圖中心在覆蓋範圍之外", "strikes/km²/min ×10³": "閃擊次數/km²/分鐘 ×10³", "N. America": "北美", @@ -1170,22 +1170,22 @@ "Hourly global mosaic; usually 2–3 hours delayed": "每小時全球鑲嵌圖;通常延遲 2–3 小時", "GOES regional clouds; approximately 5-minute updates": "GOES 區域雲圖;約 5 分鐘更新", "Clouds only": "僅雲區", - "Apply the full cloud brightness key; 100% filter strength": "應用完整的雲層亮度對映;濾鏡強度 100%", + "Apply the full cloud brightness key; 100% filter strength": "應用完整的雲層亮度映射;濾鏡強度 100%", "Full": "完整", "Show the complete infrared image; 0% filter strength": "顯示完整紅外圖像;濾鏡強度 0%", "Soft": "柔和", "Vivid": "鮮明", "Image opacity; does not alter the observed values": "圖像不透明度;不改變觀測值", - "View US radar": "檢視美國雷達", - "View Americas & Pacific": "檢視美洲與太平洋", - "View coverage": "檢視覆蓋範圍", + "View US radar": "查看美國雷達", + "View Americas & Pacific": "查看美洲與太平洋", + "View coverage": "查看覆蓋範圍", "{value} strikes/km²/min ×10³ (15-minute density)": "{value} 次閃擊/km²/分鐘 ×10³(15 分鐘密度)", "{value} dBZ radar reflectivity": "{value} dBZ 雷達反射率", - "STALE · cached source metadata": "已過期 · 資料來源後設資料來自快取", - "Map center is outside source coverage": "地圖中心在資料來源覆蓋範圍之外", - "NOAA/NWS 15-minute lightning density derived from Vaisala NLDN/GLD360. Coverage 110°E across the Pacific/Americas to 0°, 25°S–80°N. Not a live strike count, global coverage or a safety warning.": "NOAA/NWS 15 分鐘閃電密度,來源為 Vaisala NLDN/GLD360。覆蓋自 110°E 經太平洋/美洲至 0°,25°S–80°N。不是即時閃擊計數、不是全球覆蓋,也不構成安全警示。", - "NOAA MRMS radar echoes indicate precipitation patterns, not rain rate, a storm warning or a future forecast. Native source approximately 1 km; display is limited to level 6. Frames use exact advertised observation times.": "NOAA MRMS 雷達回波反映降水形態,不代表降雨強度、風暴警報或未來預報。原始資料解析度約 1 km;顯示僅限縮放級別 6。各幀使用資料來源公佈的精確觀測時間。", - "GOES-19/18 longwave infrared Band 14 regional; NESDIS global longwave mosaic. Clouds only dims everything but bright, cold cloud tops; a brightness filter, not a cloud mask. Coverage and freshness differ by region.": "GOES-19/18 第 14 波段長波紅外區域圖;NESDIS 全球長波鑲嵌圖。「僅雲區」會調暗除明亮冷雲頂之外的一切;這是亮度濾鏡,不是雲掩膜。覆蓋範圍與新鮮度因區域而異。", + "STALE · cached source metadata": "已過期 · 數據源元數據來自緩存", + "Map center is outside source coverage": "地圖中心在數據源覆蓋範圍之外", + "NOAA/NWS 15-minute lightning density derived from Vaisala NLDN/GLD360. Coverage 110°E across the Pacific/Americas to 0°, 25°S–80°N. Not a live strike count, global coverage or a safety warning.": "NOAA/NWS 15 分鐘閃電密度,來源為 Vaisala NLDN/GLD360。覆蓋自 110°E 經太平洋/美洲至 0°,25°S–80°N。不是實時閃擊計數、不是全球覆蓋,也不構成安全警示。", + "NOAA MRMS radar echoes indicate precipitation patterns, not rain rate, a storm warning or a future forecast. Native source approximately 1 km; display is limited to level 6. Frames use exact advertised observation times.": "NOAA MRMS 雷達回波反映降水形態,不代表降雨強度、風暴警報或未來預報。原始數據分辨率約 1 km;顯示僅限縮放級別 6。各幀使用數據源公佈的精確觀測時間。", + "GOES-19/18 longwave infrared Band 14 regional; NESDIS global longwave mosaic. Clouds only dims everything but bright, cold cloud tops; a brightness filter, not a cloud mask. Coverage and freshness differ by region.": "GOES-19/18 第 14 波段長波紅外區域圖;NESDIS 全球長波鑲嵌圖。“僅雲區”會調暗除明亮冷雲頂之外的一切;這是亮度濾鏡,不是雲掩膜。覆蓋範圍與新鮮度因區域而異。", "REGION": "區域", "IMAGE": "圖像", "FILTER": "濾鏡", @@ -1196,13 +1196,13 @@ "Weather tiles unavailable · previous frame retained": "天氣瓦片不可用 · 保留上一幀", "Some weather tiles unavailable": "部分天氣瓦片不可用", "Malformed weather manifest": "天氣清單格式錯誤", - "Weather request timed out": "天氣請求逾時", + "Weather request timed out": "天氣請求超時", "Temperature field unavailable": "溫度場不可用", "Mean sea level pressure field unavailable": "平均海平面氣壓場不可用", - "Wind upstream unavailable": "風場上游資料來源不可用", + "Wind upstream unavailable": "風場上游數據源不可用", "{source} HTTP {status}": "{source} HTTP {status}", "Wind": "風", - "Wind source unavailable": "風場資料來源不可用", + "Wind source unavailable": "風場數據源不可用", "Forecast · does not follow history": "預報 · 不隨觀測歷史變化", "Wind motion": "風場運動", "Wind speed": "風速", @@ -1210,16 +1210,16 @@ "Air temperature · 2 m": "氣溫 · 2 m", "Global · 1° grid": "全球 · 1° 網格", "{model} forecast · {time}": "{model} 預報 · {time}", - "Loading forecast": "正在載入預報", + "Loading forecast": "正在加載預報", "Preparing flow": "正在準備流場", "Selected field unavailable": "所選氣象場不可用", - "Cached forecast · stale": "快取預報 · 已過期", + "Cached forecast · stale": "緩存預報 · 已過期", "ECMWF IFS surface forecast": "ECMWF IFS 地面預報", "NOAA GFS surface forecast": "NOAA GFS 地面預報", "Reduced motion": "減弱動效", "Resume": "繼續", "Pause": "暫停", - "Pause visual flow; forecast time does not advance with animation": "暫停流動動畫;預報時間不會隨動畫推進", + "Pause visual flow; forecast time does not advance with animation": "暫停流動動畫;預報時次不會隨動畫推進", "None": "無", "Speed": "風速", "Pressure": "氣壓", @@ -1227,37 +1227,37 @@ "Wind trails with no field shading": "僅顯示風場流線,不疊加氣象場填色", "How hard the surface wind is blowing": "地面風有多大", "Sea-level air pressure: broad highs and lows": "海平面氣壓:大範圍的高壓與低壓", - "Air temperature two meters above the surface": "地面以上 2 公尺的氣溫", + "Air temperature two meters above the surface": "地面以上兩米的氣溫", "Wind speed units": "風速單位", "Read wind at map center": "讀取地圖中心風況", - "Read the forecast at the center of the map without changing selection": "讀取地圖中心的預報值,不改變目前選擇", + "Read the forecast at the center of the map without changing selection": "讀取地圖中心的預報值,不改變當前選擇", "{model} forecast · {field} ({unit})": "{model} 預報 · {field}({unit})", "Valid: {time}": "有效時間:{time}", "preparing": "準備中", - "Issued: {time}": "發布時間:{time}", + "Issued: {time}": "發佈時間:{time}", "Selected field unavailable · wind remains visible": "所選氣象場不可用 · 風場仍可見", "{error} · wind remains visible": "{error} · 風場仍可見", - "Surface wind at 10 m. Approximately 1° global grid. Curves follow the 10 m wind field, lifted 12 km for visibility; display height is not weather altitude. View lighting is for readability. Animation shows flow through one fixed forecast; it does not advance time. Color fields drape the globe basemap or the active photorealistic 3D Tiles.": "10 m 高度的地面風。約 1° 全球網格。流線沿 10 m 風場繪製,為便於觀看抬升至 12 km;顯示高度並非氣象高度。檢視光照僅為提高可讀性。動畫展示的是單一固定預報內的流場,不推進時間。氣象場填色疊加於地球底圖或目前的照片級逼真 3D Tiles。", + "Surface wind at 10 m. Approximately 1° global grid. Curves follow the 10 m wind field, lifted 12 km for visibility; display height is not weather altitude. View lighting is for readability. Animation shows flow through one fixed forecast; it does not advance time. Color fields drape the globe basemap or the active photorealistic 3D Tiles.": "10 m 高度的地面風。約 1° 全球網格。流線沿 10 m 風場繪製,為便於觀看抬升至 12 km;顯示高度並非氣象高度。視圖光照僅為提高可讀性。動畫展示的是單一固定預報內的流場,不推進時間。氣象場填色疊加於地球底圖或當前的照片級逼真 3D Tiles。", "MODEL": "模式", "FIELD": "要素", "UNITS": "單位", "MOTION": "運動", "Forecast": "預報", - "NNE": "北北東", + "NNE": "北東北", "NE": "東北", - "ENE": "東北東", - "ESE": "東南東", + "ENE": "東東北", + "ESE": "東東南", "SE": "東南", - "SSE": "南南東", - "SSW": "南南西", + "SSE": "南東南", + "SSW": "南西南", "SW": "西南", - "WSW": "西南西", - "WNW": "西北西", + "WSW": "西西南", + "WNW": "西西北", "NW": "西北", - "NNW": "北北西", + "NNW": "北西北", "No surface reading": "暫無地表讀數", "Aim the map center at Earth": "請將地圖中心對準地球", - "A location reading needs a loaded forecast and the Earth at the center of the view.": "位置讀數需要已載入的預報,且地圖中心對準地球。", + "A location reading needs a loaded forecast and the Earth at the center of the view.": "位置讀數需要已加載的預報,且地圖中心對準地球。", "Interpolated model forecast on an approximately 1° grid. Broad weather patterns, not a street-level measurement.": "按約 1° 網格插值的模式預報。反映大範圍天氣形勢,不是街道級實測。", " · calm": " · 靜風", " from {direction}": ",{direction}風", @@ -1268,87 +1268,87 @@ "Globe field image unavailable": "地球氣象場圖像不可用", "Unknown wind model": "未知風場模式", "Unknown weather overlay": "未知天氣疊加層", - "Wind request timed out": "風場請求逾時", + "Wind request timed out": "風場請求超時", "Malformed wind manifest": "風場清單格式錯誤", "Malformed wind grid": "風場網格格式錯誤", "Error: {message}": "錯誤:{message}", - "Needs {envVars} — add it in Provider Settings": "需要 {envVars},請在服務供應商設定中新增", + "Needs {envVars} — add it in Provider Settings": "需要 {envVars},請在服務商設置中添加", "{label} is unavailable": "{label} 不可用", "This map stack": "此地圖組合", "{label} unavailable: {hint}": "{label} 不可用:{hint}", - "Google 3D tiles unavailable — check the key's API restrictions, quota, or network": "Google 3D 瓦片不可用——請檢查金鑰的 API 限制、配額或網路", - "Needs {envVars} — add it in Provider Settings — or a Cesium ion token for the ion-hosted route": "需要 {envVars}(請在服務供應商設定中新增),或使用 Cesium ion 權杖走 ion 託管通道", - "Exit cockpit to fly to a camera": "請先退出駕駛艙,再飛往攝影機", - "Exit cockpit to fly to a location": "請先退出駕駛艙,再飛往該地點", - "Exit cockpit to fly to a photo": "請先退出駕駛艙,再飛往照片", - "Exit cockpit to fly to a shared view": "請先退出駕駛艙,再飛往分享的檢視", - "Exit cockpit to fly to a target": "請先退出駕駛艙,再飛往目標", - "Exit cockpit to fly to a vessel": "請先退出駕駛艙,再飛往船舶", - "Exit cockpit to fly to a fire": "請先退出駕駛艙,再飛往火點", - "Exit cockpit to fly to a route": "請先退出駕駛艙,再飛往路線", - "Exit cockpit to fly to a file": "請先退出駕駛艙,再飛往檔案位置", - "Exit cockpit to fly to a scene": "請先退出駕駛艙,再飛往場景", - "Exit cockpit to view weather coverage": "請先退出駕駛艙,再檢視天氣覆蓋範圍", - "Exit cockpit to fly to a cyclone": "請先退出駕駛艙,再飛往氣旋", - "Exit cockpit to fly to an aircraft": "請先退出駕駛艙,再飛往飛機", - "Exit cockpit to fly to a satellite": "請先退出駕駛艙,再飛往衛星", - "Exit cockpit to frame contacts": "請先退出駕駛艙,再將目標納入視野", - "Visible map targets": "可見地圖目標", + "Google 3D tiles unavailable — check the key's API restrictions, quota, or network": "Google 3D 瓦片不可用——請檢查密鑰的 API 限制、配額或網絡", + "Needs {envVars} — add it in Provider Settings — or a Cesium ion token for the ion-hosted route": "需要 {envVars}(請在服務商設置中添加),或使用 Cesium ion 令牌走 ion 託管通道", + "Exit cockpit to fly to a camera": "請先退出座艙,再飛往攝像頭", + "Exit cockpit to fly to a location": "請先退出座艙,再飛往該地點", + "Exit cockpit to fly to a photo": "請先退出座艙,再飛往照片", + "Exit cockpit to fly to a shared view": "請先退出座艙,再飛往分享的視圖", + "Exit cockpit to fly to a target": "請先退出座艙,再飛往目標", + "Exit cockpit to fly to a vessel": "請先退出座艙,再飛往船舶", + "Exit cockpit to fly to a fire": "請先退出座艙,再飛往火點", + "Exit cockpit to fly to a route": "請先退出座艙,再飛往路線", + "Exit cockpit to fly to a file": "請先退出座艙,再飛往文件位置", + "Exit cockpit to fly to a scene": "請先退出座艙,再飛往場景", + "Exit cockpit to view weather coverage": "請先退出座艙,再查看天氣覆蓋範圍", + "Exit cockpit to fly to a cyclone": "請先退出座艙,再飛往氣旋", + "Exit cockpit to fly to an aircraft": "請先退出座艙,再飛往飛機", + "Exit cockpit to fly to a satellite": "請先退出座艙,再飛往衛星", + "Exit cockpit to frame contacts": "請先退出座艙,再將目標納入視野", + "Visible map targets": "可見的地圖目標", "Focusing {label}": "正在聚焦 {label}", "Source": "來源", "Camera ownership changed": "相機控制權已變更", - "Saved project could not be read; storage preserved. Import a valid file to resume saving.": "已儲存的專案無法讀取;儲存已保留。請匯入有效檔案以恢復儲存。", + "Saved project could not be read; storage preserved. Import a valid file to resume saving.": "已保存的項目無法讀取;存儲已保留。請導入有效文件以恢復保存。", "Ready": "就緒", "Scene layer turned off": "場景圖層已關閉", "Stopped": "已停止", - "Scene not saved — existing saved project could not be read. Export edits or import a valid file.": "場景未儲存——已儲存的專案無法讀取。請先匯出修改或匯入有效檔案。", - "Scene not saved — {reason}": "場景未儲存——{reason}", - "Scene not saved — browser storage unavailable": "場景未儲存——瀏覽器儲存不可用", - "Loaded: {scene} / {shot}": "已載入:{scene} / {shot}", + "Scene not saved — existing saved project could not be read. Export edits or import a valid file.": "場景未保存——已保存的項目無法讀取。請先導出修改或導入有效文件。", + "Scene not saved — {reason}": "場景未保存——{reason}", + "Scene not saved — browser storage unavailable": "場景未保存——瀏覽器存儲不可用", + "Loaded: {scene} / {shot}": "已加載:{scene} / {shot}", "Cannot update {scene}: shot inventory changed": "無法更新 {scene}:鏡頭清單已變化", "Cannot update {scene}: evidence beats changed": "無法更新 {scene}:證據節點已變化", - "Cannot update {scene}: shot bindings are incomplete": "無法更新 {scene}:鏡頭繫結不完整", + "Cannot update {scene}: shot bindings are incomplete": "無法更新 {scene}:鏡頭綁定不完整", "Updated {count} shots: {scene}": { "other": "已更新 {count} 個鏡頭:{scene}" }, "Appended {count} shots: {scene}": { "other": "已追加 {count} 個鏡頭:{scene}" }, - "Cannot capture shot: camera not ready": "無法儲存鏡頭:相機未就緒", - "Captured: {scene} / {shot}": "已儲存:{scene} / {shot}", + "Cannot capture shot: camera not ready": "無法保存鏡頭:相機未就緒", + "Captured: {scene} / {shot}": "已保存:{scene} / {shot}", "Select a shot first": "請先選擇一個鏡頭", "Updated: {scene} / {shot}": "已更新:{scene} / {shot}", "Could not leave scene: {scene}": "無法離開場景:{scene}", "Seeked: {scene} / {shot}": "已定位:{scene} / {shot}", "Seeking scene clock": "正在定位場景時鐘", - "Camera unavailable — exit cockpit first": "相機不可用——請先退出駕駛艙", - "No shots to run": "沒有可執行的鏡頭", - "Scene transition limit reached — load a shot to reset": "已達到場景切換上限——請載入一個鏡頭以重置", - "Export failed: {error}": "匯出失敗:{error}", - "Project exported": "專案已匯出", - "Importing project": "正在匯入專案", - "Imported {file}": "已匯入 {file}", - "Import failed: {error}": "匯入失敗:{error}", - "Import failed (could not read JSON file)": "匯入失敗(無法讀取 JSON 檔案)", + "Camera unavailable — exit cockpit first": "相機不可用——請先退出座艙", + "No shots to run": "沒有可運行的鏡頭", + "Scene transition limit reached — load a shot to reset": "已達到場景切換上限——請加載一個鏡頭以重置", + "Export failed: {error}": "導出失敗:{error}", + "Project exported": "項目已導出", + "Importing project": "正在導入項目", + "Imported {file}": "已導入 {file}", + "Import failed: {error}": "導入失敗:{error}", + "Import failed (could not read JSON file)": "導入失敗(無法讀取 JSON 文件)", "Layers refused: {layers}": "被拒絕的圖層:{layers}", "Could not exit {mode} — scene layers may be refused": "無法退出 {mode}——場景圖層可能被拒絕", "Camera move interrupted": "相機移動被中斷", - "Scene media timed out": "場景媒體播放逾時", + "Scene media timed out": "場景媒體播放超時", "Action complete": "動作已完成", "Action unavailable or cancelled": "動作不可用或已取消", "Scene actions": "場景動作", "Select a feature or use Tab and Enter to choose an action.": "選擇一個要素,或使用 Tab 和 Enter 選擇動作。", "Selected feature: {feature}. Choose an action.": "已選要素:{feature}。請選擇動作。", - "Running {index}/{total}: {scene} / {shot}": "正在執行 {index}/{total}:{scene} / {shot}", - "Scene run complete": "場景執行完成", + "Running {index}/{total}: {scene} / {shot}": "正在運行 {index}/{total}:{scene} / {shot}", + "Scene run complete": "場景運行完成", "Bhote Koshi Evidence Sequence": "Bhote Koshi 證據序列", "Nepal Flood Incident": "尼泊爾洪水事件", "Global Flights Radar": "全球航班雷達", - "Orbital Watch": "軌道監看", + "Orbital Watch": "軌道監視", "Thermal Threat Board": "熱源威脅看板", "City Overload": "城市過載", "Omniscience Pullback": "全知拉遠", - "Global Incident Context": "全球事件情境", + "Global Incident Context": "全球事件背景", "Nepal-Focused Globe Rotation": "聚焦尼泊爾的地球旋轉", "Bhote Koshi Regional Approach": "Bhote Koshi 區域推近", "Bhote Koshi Nearby Cities": "Bhote Koshi 周邊城市", @@ -1362,15 +1362,15 @@ "Timure Evidence Cluster": "Timure 證據群", "Syabru Besi Passage": "Syabru Besi 通道", "Bidur / Trishuli Consequence": "Bidur / Trishuli 後果", - "Final view": "最終視角", + "Final view": "最終視圖", "Scene {n}": "場景 {n}", "Shot {n}": "鏡頭 {n}", - "the title of scene {scene} is empty or longer than {max} characters": "場景 {scene} 的標題為空或超過 {max} 個字元", - "the title of shot {shot} in scene {scene} is empty or longer than {max} characters": "場景 {scene} 中鏡頭 {shot} 的標題為空或超過 {max} 個字元", - "the project is larger than 5 MiB": "專案大於 5 MiB", - "the project has too many shots": "專案中的鏡頭過多", - "the scene data failed validation": "場景資料未透過校驗", - "Could not complete this action. Check the file, references and selected assets.": "無法完成此操作。請檢查檔案、引用和所選資源。", + "the title of scene {scene} is empty or longer than {max} characters": "場景 {scene} 的標題為空或超過 {max} 個字符", + "the title of shot {shot} in scene {scene} is empty or longer than {max} characters": "場景 {scene} 中鏡頭 {shot} 的標題為空或超過 {max} 個字符", + "the project is larger than 5 MiB": "項目大於 5 MiB", + "the project has too many shots": "項目中的鏡頭過多", + "the scene data failed validation": "場景數據未通過校驗", + "Could not complete this action. Check the file, references and selected assets.": "無法完成此操作。請檢查文件、引用和所選資源。", "{count} scenes": { "other": "{count} 個場景" }, @@ -1378,75 +1378,75 @@ "other": "{count} 個鏡頭" }, "{count} data packs": { - "other": "{count} 個資料包" + "other": "{count} 個數據包" }, - "{scene} / {pack}: {status}. File: {path}. {attribution} · {license}": "{scene} / {pack}:{status}。檔案:{path}。{attribution} · {license}", + "{scene} / {pack}: {status}. File: {path}. {attribution} · {license}": "{scene} / {pack}:{status}。文件:{path}。{attribution} · {license}", "Unavailable layers: {layers}": "不可用圖層:{layers}", - "Uses registered content or linked media. Those external files are not included in a scene bundle. Their original notices still apply.": "使用了已註冊內容或連結媒體。這些外部檔案不包含在場景資源包中。其原始聲明仍然適用。", - "{bytes} bundled bytes verified. Files stay in memory for this session. Reimport the bundle after reloading the app.": "已校驗打包內容 {bytes} 位元組。檔案僅保留在本次工作階段的記憶體中。重新載入應用後請再次匯入資源包。", - "Review scene import": "場景匯入預覽", - "Nothing is loaded or changed until you apply this file.": "確認匯入此檔案前,不會載入或更改任何內容。", - "Ready to import": "可以匯入", - "Apply replaces the current project. Export your current project first if you want to keep both.": "應用後將替換目前專案。如需同時保留兩者,請先匯出目前專案。", - "Apply import": "確認匯入", - "Import was not applied. The current project may have changed.": "匯入未套用。目前專案可能已發生變化。", + "Uses registered content or linked media. Those external files are not included in a scene bundle. Their original notices still apply.": "使用了已註冊內容或鏈接媒體。這些外部文件不包含在場景資源包中。其原始聲明仍然適用。", + "{bytes} bundled bytes verified. Files stay in memory for this session. Reimport the bundle after reloading the app.": "已校驗打包內容 {bytes} 字節。文件僅保留在本次會話的內存中。重新加載應用後請再次導入資源包。", + "Review scene import": "場景導入預覽", + "Nothing is loaded or changed until you apply this file.": "確認導入此文件前,不會加載或更改任何內容。", + "Ready to import": "可以導入", + "Apply replaces the current project. Export your current project first if you want to keep both.": "應用後將替換當前項目。如需同時保留兩者,請先導出當前項目。", + "Apply import": "確認導入", + "Import was not applied. The current project may have changed.": "未執行導入。當前項目可能已發生變化。", "Select a scene and shot first": "請先選擇場景和鏡頭", "Edit scene details": "編輯場景詳情", - "Camera positions use degrees and meters above the ellipsoid. Drafts are validated before they replace your saved scene.": "相機經緯度以度為單位,高度以米為單位(相對橢球面)。草稿透過校驗後才會替換已儲存的場景。", - "Anchors and data packs": "錨點與資料包", - "Shot camera, timing, packs and actions": "鏡頭相機、時序、資料包與動作", + "Camera positions use degrees and meters above the ellipsoid. Drafts are validated before they replace your saved scene.": "相機經緯度以度為單位,高度以米為單位(相對橢球面)。草稿通過校驗後才會替換已保存的場景。", + "Anchors and data packs": "錨點與數據包", + "Shot camera, timing, packs and actions": "鏡頭相機、時序、數據包與動作", "New anchor ID": "新錨點 ID", - "Capture camera as anchor": "將目前相機位置設為錨點", + "Capture camera as anchor": "將當前相機位置設為錨點", "Anchor added to draft": "錨點已加入草稿", - "Set move start to current camera": "將運鏡起點設為目前相機位置", + "Set move start to current camera": "將運鏡起點設為當前相機位置", "Move added to draft; destination remains the shot camera": "運鏡已加入草稿;終點仍為該鏡頭的相機位置", "Use ordinary flight": "使用普通飛行", "Invalid shot JSON": "鏡頭 JSON 無效", - "Apply details": "套用詳細資料", + "Apply details": "應用詳情", "Select a scene first": "請先選擇一個場景", "Share selected scene": "分享所選場景", - "Scene JSON preserves authored settings and attribution. It does not include asset files. Bundles include only pack files you choose here or previously imported bundle files.": "場景 JSON 保留創作設定與署名資訊。它不包含資源檔案。資源包僅包含你在此選擇的包檔案或先前匯入的資源包檔案。", + "Scene JSON preserves authored settings and attribution. It does not include asset files. Bundles include only pack files you choose here or previously imported bundle files.": "場景 JSON 保留創作設置與署名信息。它不包含資源文件。資源包僅包含你在此選擇的包文件或先前導入的資源包文件。", "Download scene JSON": "下載場景 JSON", - "Choose data-pack files": "選擇資料包檔案", - "Or choose a data-pack folder": "或選擇資料包資料夾", + "Choose data-pack files": "選擇數據包文件", + "Or choose a data-pack folder": "或選擇數據包文件夾", "Download asset bundle": "下載資源包", "Asset bundle downloaded": "資源包已下載", - "No RTL-SDR device selected": "未選擇 RTL-SDR 裝置", + "No RTL-SDR device selected": "未選擇 RTL-SDR 設備", "WebUSB requires desktop Chrome or Edge on localhost/HTTPS": "WebUSB 需要在 localhost/HTTPS 上使用桌面版 Chrome 或 Edge", "RTL-SDR access failed; close other SDR apps and check USB permissions": "RTL-SDR 訪問失敗;請關閉其他 SDR 應用並檢查 USB 權限", - "RTL-SDR connection failed": "RTL-SDR 連線失敗", + "RTL-SDR connection failed": "RTL-SDR 連接失敗", "Receiving 1090 MHz ADS-B": "正在接收 1090 MHz ADS-B", "Receiving broadcast FM": "正在接收廣播 FM", - "Connect an RTL-SDR to begin.": "連線 RTL-SDR 即可開始。", - "WebUSB is unavailable in this browser": "此瀏覽器不支援 WebUSB", + "Connect an RTL-SDR to begin.": "連接 RTL-SDR 即可開始。", + "WebUSB is unavailable in this browser": "此瀏覽器不支持 WebUSB", "USB work abandoned after a stalled transfer": "USB 傳輸停滯,已放棄操作", - "SDR decoder worker failed": "SDR 解碼器工作執行緒失敗", + "SDR decoder worker failed": "SDR 解碼器工作線程失敗", "SDR decoder did not start; receiver stopped": "SDR 解碼器未能啟動;接收機已停止", - "SDR decoder stopped responding; receiver stopped": "SDR 解碼器停止回應;接收機已停止", + "SDR decoder stopped responding; receiver stopped": "SDR 解碼器停止響應;接收機已停止", "SDR decoder fell behind; receiver stopped": "SDR 解碼器處理滯後;接收機已停止", "WebUSB requires desktop Chrome or Edge": "WebUSB 需要桌面版 Chrome 或 Edge", - "Waiting for an RTL-SDR device…": "正在等待 RTL-SDR 裝置…", - "Browser audio is suspended; press Connect again to resume it": "瀏覽器音訊已掛起;再次按「連線」以恢復", - "RTL-SDR sample stream stopped": "RTL-SDR 取樣流已停止", + "Waiting for an RTL-SDR device…": "正在等待 RTL-SDR 設備…", + "Browser audio is suspended; press Connect again to resume it": "瀏覽器音頻已掛起;再次按“連接”以恢復", + "RTL-SDR sample stream stopped": "RTL-SDR 採樣流已停止", "Switching to {mode}…": "正在切換到 {mode}…", - "Browser audio is suspended; select FM again to resume it": "瀏覽器音訊已掛起;再次選擇 FM 以恢復", + "Browser audio is suspended; select FM again to resume it": "瀏覽器音頻已掛起;再次選擇 FM 以恢復", "RTL-SDR gain change failed": "RTL-SDR 增益調整失敗", "Tuned to {mhz} MHz FM": "已調諧到 FM {mhz} MHz", - "Seeking up…": "正在向上搜台…", - "Seeking down…": "正在向下搜台…", - "Seek stopped": "搜台已停止", + "Seeking up…": "正在向上搜臺…", + "Seeking down…": "正在向下搜臺…", + "Seek stopped": "搜臺已停止", "Scanning {mhz} MHz…": "正在掃描 {mhz} MHz…", "Found {mhz} MHz · {snr} dB": "找到 {mhz} MHz · {snr} dB", - "FM signal found at {mhz} MHz": "在 {mhz} MHz 找到 FM 訊號", - "No FM signal found": "未找到 FM 訊號", + "FM signal found at {mhz} MHz": "在 {mhz} MHz 找到 FM 信號", + "No FM signal found": "未找到 FM 信號", "Browser location is unavailable": "瀏覽器位置不可用", "Receiver location was not granted": "未授予接收機位置權限", "RTL-SDR disconnected": "RTL-SDR 已斷開", - "Upstream response too large": "上游回應過大", - "Vector tile request timed out": "向量瓦片請求逾時", - "Vector tiles unavailable": "向量瓦片不可用", - "Vector tile metadata unavailable": "向量瓦片後設資料不可用", - "Zoom in for vector tile coverage": "放大以檢視向量瓦片覆蓋", + "Upstream response too large": "上游響應過大", + "Vector tile request timed out": "矢量瓦片請求超時", + "Vector tiles unavailable": "矢量瓦片不可用", + "Vector tile metadata unavailable": "矢量瓦片元數據不可用", + "Zoom in for vector tile coverage": "放大以查看矢量瓦片覆蓋", "Saturation": "飽和度", "Edge Thickness": "描邊粗細", "Contrast": "對比度", @@ -1457,96 +1457,96 @@ "Instability": "抖動", "Density": "密度", "Gain": "增益", - "Bloom": "光暈", + "Bloom": "泛光", "Scanlines": "掃描線", "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}。仍要切換嗎?", + "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": "目標——最近的飛機 · 船舶 · 設施", - "SPACE MISSIONS — launches & orbital assets": "太空任務——發射與軌道資產", - "LIVE SIGNALS": "即時訊號", + "CONTACTS — nearest planes · vessels · sites": "目標:最近的飛機 · 船舶 · 設施", + "SPACE MISSIONS — launches & orbital assets": "太空任務:發射與在軌資產", + "LIVE SIGNALS": "實時信號", "CCTV layer unavailable": "CCTV 圖層不可用", - "Link copied!": "連結已複製!", + "Link copied!": "鏈接已複製!", "Copy failed": "複製失敗", - "Return map to straight-down view": "地圖回到正俯視", - "Tilt map to oblique view": "將地圖傾斜為斜視角", - "Reset map to north up. Current heading {heading} degrees": "將地圖重置為正北朝上。目前方位 {heading} 度", + "Return map to straight-down view": "將地圖恢復為垂直俯視", + "Tilt map to oblique view": "將地圖傾斜至斜視角", + "Reset map to north up. Current heading {heading} degrees": "將地圖重置為正北朝上。當前方位 {heading} 度", "Tilted view": "傾斜視角", "Straight-down view": "垂直俯視", "North up": "正北朝上", - "CCTV calibration saved": "CCTV 校準已儲存", + "CCTV calibration saved": "CCTV 校準已保存", "HDG": "HDG", "PITCH": "俯仰", "FOV": "FOV", - "RANGE": "距離", + "RANGE": "範圍", "HGT": "高度", "ΔN": "ΔN", "ΔE": "ΔE", "{value}m": "{value} m", "CCTV calibration reset": "CCTV 校準已重置", - "ADJUST ON": "調整 開", + "ADJUST ON": "調整開", "ADJUST": "調整", "SNAPSHOT": "快照", - "LIVE": "即時", + "LIVE": "實時", "UPSTREAM": "上游", "SYNTHETIC": "合成", "CONFIGURED": "已配置", "SEED": "預置", "UNKNOWN": "未知", "ERROR": "錯誤", - "Live HLS connected": "即時 HLS 已連線", - "Live HLS unavailable": "即時 HLS 不可用", - "No stream URL configured": "未設定串流網址", - "Live stream connected": "即時串流已連線", - "Snapshot feed connected": "快照來源已連線", - "Media fetch failed": "媒體取得失敗", - "Upstream snapshot active": "上游快照運作中", - "Fallback Street View frame": "備援街景畫面", - "Upstream unavailable": "上游無法使用", - "No source configured": "未設定來源", + "Live HLS connected": "實時 HLS 已連接", + "Live HLS unavailable": "實時 HLS 不可用", + "No stream URL configured": "未配置流 URL", + "Live stream connected": "實時流已連接", + "Snapshot feed connected": "快照數據源已連接", + "Media fetch failed": "媒體獲取失敗", + "Upstream snapshot active": "上游快照已啟用", + "Fallback Street View frame": "備用街景畫面", + "Upstream unavailable": "上游不可用", + "No source configured": "未配置來源", "Configured source": "已配置來源", - "Configured Source": "已配置資料來源", - "Synthetic fallback": "合成備援", + "Configured Source": "已配置數據源", + "Synthetic fallback": "合成備用", "Upstream HTTP {status}": "上游 HTTP {status}", - "Unexpected media type {type}": "意外的媒體型別 {type}", + "Unexpected media type {type}": "意外的媒體類型 {type}", "SOURCE · UNKNOWN": "來源 · 未知", - "FRAME · LOADING": "畫面 · 載入中", - "FRAME · UNAVAILABLE": "畫面 · 無法使用", + "FRAME · LOADING": "畫面 · 加載中", + "FRAME · UNAVAILABLE": "畫面 · 不可用", "CALIBRATED": "已校準", "CURATED": "精選", - "RAW PRIOR": "原始推估", + "RAW PRIOR": "初始估計", "CCTV ON": "CCTV 開", "CCTV OFF": "CCTV 關", - "VIEWSHED ON": "可視域 開", - "COVERAGE ON": "覆蓋範圍 開", - "COVERAGE OFF": "覆蓋範圍 關", - "AUTO HOP ON": "自動輪播 開", - "AUTO HOP OFF": "自動輪播 關", - "PROJECTION ON": "投影 開", - "PROJECTION OFF": "投影 關", - "CAL · EDITED (UNSAVED)": "CAL · 已編輯(未儲存)", + "VIEWSHED ON": "可視域開", + "COVERAGE ON": "覆蓋範圍開", + "COVERAGE OFF": "覆蓋範圍關", + "AUTO HOP ON": "自動跳轉開", + "AUTO HOP OFF": "自動跳轉關", + "PROJECTION ON": "投影開", + "PROJECTION OFF": "投影關", + "CAL · EDITED (UNSAVED)": "CAL · 已編輯(未保存)", "CAL · {badge}": "CAL · {badge}", - "MONITOR": "螢幕", + "MONITOR": "監視器", "OFF": "關", - "{city} · HDG {heading} · FOV {fov} · RANGE {range}m · {projection}{calBadge} · {provider}{status}": "{city} · HDG {heading} · FOV {fov} · 距離 {range} m · {projection}{calBadge} · {provider}{status}", + "{city} · HDG {heading} · FOV {fov} · RANGE {range}m · {projection}{calBadge} · {provider}{status}": "{city} · HDG {heading} · FOV {fov} · 範圍 {range} m · {projection}{calBadge} · {provider}{status}", "{count} cameras loaded · click a camera to activate": { - "other": "已載入 {count} 個攝影機 · 點選攝影機以啟用" + "other": "已加載 {count} 個攝像頭 · 點擊攝像頭以激活" }, "{count} cameras loaded · enable CCTV to activate": { - "other": "已載入 {count} 個攝影機 · 開啟 CCTV 即可使用" + "other": "已加載 {count} 個攝像頭 · 啟用 CCTV 以激活" }, - "Enable CCTV to load camera intersections": "啟用監視器以載入路口攝影機", - "Enable CCTV to start camera-linked intelligence summaries.": "啟用監視器以開始產生攝影機情資摘要。", - "No summary available.": "尚無摘要。", - "loading frames": "畫面載入中", - "camera grid ready": "攝影機網格就緒", - "Clearing selected data layers": "正在清除已選資料圖層", - "Clear selected data layers": "清除已選資料圖層", + "Enable CCTV to load camera intersections": "啟用 CCTV 以加載路口攝像頭", + "Enable CCTV to start camera-linked intelligence summaries.": "啟用 CCTV 以開始生成與攝像頭關聯的情報摘要。", + "No summary available.": "暫無摘要。", + "loading frames": "正在加載畫面", + "camera grid ready": "攝像頭網格就緒", + "Clearing selected data layers": "正在清除已選數據圖層", + "Clear selected data layers": "清除已選數據圖層", "CONDITIONS UNKNOWN": "天氣狀況未知", "CLEAR": "晴", "PARTLY CLOUDY": "晴間多雲", @@ -1558,32 +1558,32 @@ "SNOW SHOWERS": "陣雪", "THUNDERSTORM": "雷暴", "MIXED CONDITIONS": "混合天氣", - "CYCLE ON": "輪播 開", - "CYCLE OFF": "輪播 關", - "Stop automatic page cycling. Previous, Next, and the SIG/NEWS/LOCAL tabs stay available.": "停止自動翻頁。上一頁、下一頁以及「訊號」「新聞」「在地」標籤頁仍可使用。", - "Cycle briefing pages automatically every 9 seconds (Signals → News → Local). Pauses while you hover or focus the panel. Live signal data refreshes continuously either way.": "每 9 秒自動輪播簡報頁(訊號 → 新聞 → 在地)。滑鼠停留或聚焦面板時暫停;即時訊號資料會持續更新。", - "ACQUIRING REGIONAL NEWS": "正在取得區域新聞", - "REGIONAL NEWS UNAVAILABLE": "區域新聞不可用", - "RESOLVING REGION": "解析區域中", - "REGION UNAVAILABLE": "無法取得區域", + "CYCLE ON": "輪換開", + "CYCLE OFF": "輪換關", + "Stop automatic page cycling. Previous, Next, and the SIG/NEWS/LOCAL tabs stay available.": "停止自動翻頁。上一頁、下一頁以及“信號”“新聞”“本地”標籤頁仍可使用。", + "Cycle briefing pages automatically every 9 seconds (Signals → News → Local). Pauses while you hover or focus the panel. Live signal data refreshes continuously either way.": "每 9 秒自動輪換簡報頁面(信號 → 新聞 → 本地)。懸停或聚焦面板時暫停。無論是否輪換,實時信號數據都會持續刷新。", + "ACQUIRING REGIONAL NEWS": "正在獲取地區新聞", + "REGIONAL NEWS UNAVAILABLE": "地區新聞不可用", + "RESOLVING REGION": "正在解析區域", + "REGION UNAVAILABLE": "區域不可用", "NO RECENT LOCATION MATCHES": "暫無近期位置匹配結果", "{domain} · {age}": "{domain} · {age}", "{value} KM/H": "{value} km/h", "CLOUD {pct}%": "雲量 {pct}%", "CLOUD UNKNOWN": "雲量未知", "{source} · LOCATION QUERY": "{source} · 位置查詢", - "REGIONAL NEWS": "區域新聞", - "{label} · {radius} AIR/SEA WINDOW": "{label} · {radius} 空 / 海監視範圍", + "REGIONAL NEWS": "地區新聞", + "{label} · {radius} AIR/SEA WINDOW": "{label} · {radius} 空/海監視窗口", "{scope} · INSTALLATIONS {coverage}": "{scope} · 設施 {coverage}", "CONTEXT STANDBY": "態勢待機", - "ENABLE GLOBAL CONTEXT FOR PROXIMITY PINGS": "啟用全域態勢以接收鄰近目標提醒", + "ENABLE GLOBAL CONTEXT FOR PROXIMITY PINGS": "啟用全局態勢以接收鄰近目標提醒", "CONTACT LOST · LAST KNOWN READOUT · NOT AN ALL-CLEAR": "目標丟失 · 最後已知讀數 · 不代表安全無虞", "CONTACT LOST · {subject}": "目標丟失 · {subject}", - "SUBJECT LEFT ITS FEED · READOUT HOLDING LAST KNOWN": "目標已脫離其資料來源 · 讀數保持最後已知值", + "SUBJECT LEFT ITS FEED · READOUT HOLDING LAST KNOWN": "目標已脫離其數據源 · 讀數保持最後已知值", "{cohort} · {contact}": "{cohort} · {contact}", - "NO AVAILABLE EXAMPLE": "沒有可用範例", + "NO AVAILABLE EXAMPLE": "無可用示例", "{cohort}, Unavailable": "{cohort},不可用", - "AHEAD": "前方", + "AHEAD": "正前方", "{side} {angle}": "{side} {angle}", "L": "左", "R": "右", @@ -1592,51 +1592,51 @@ }, "AVAILABLE INPUTS CURRENT · NOT AN ALL-CLEAR": "可用輸入均為最新 · 不代表安全無虞", "SQUAWK {code} · {status}": "應答碼 {code} · {status}", - "ADS-B PRIORITY · {status}": "ADS-B 優先順序 · {status}", + "ADS-B PRIORITY · {status}": "ADS-B 優先級 · {status}", "ADS-B EMERGENCY · {status}": "ADS-B 緊急 · {status}", "AIRCRAFT": "飛機", - "ACQUIRING SURFACE": "正在取得地面資料", - "SURFACE FALLBACK": "地面資料備援", - "STALE FEED": "資料來源過期", - "LIVE TRACK": "即時航跡", + "ACQUIRING SURFACE": "正在獲取地面數據", + "SURFACE FALLBACK": "地面數據備用", + "STALE FEED": "數據源過期", + "LIVE TRACK": "實時航跡", "COMMERCIAL": "商用", "{aircraftClass} · {emergency} · {feedState}": "{aircraftClass} · {emergency} · {feedState}", "{aircraftClass} · {feedState} · COURSE ALIGNED": "{aircraftClass} · {feedState} · 航向對準", "ARROW · ESTIMATED DIRECTION": "箭頭 · 預估方向", - "ROUTE DATA UNAVAILABLE": "無航線資料", + "ROUTE DATA UNAVAILABLE": "航線數據不可用", "DEST {bearing}": "目的地 {bearing}", - "Disable cockpit weather effects": "停用駕駛艙天氣效果", - "Enable cockpit weather effects": "啟用駕駛艙天氣效果", + "Disable cockpit weather effects": "停用座艙天氣效果", + "Enable cockpit weather effects": "啟用座艙天氣效果", "ON": "開", - "Normal": "一般", + "Normal": "常規", "Night vision": "夜視", "Thermal": "熱成像", - "Anime": "動畫", - "Noir": "黑色電影", + "Anime": "動漫", + "Noir": "黑白", "Snow": "雪景", - "Current cockpit vision style: {style}. Activate for next style.": "目前駕駛艙視覺樣式:{style}。點選可切換到下一個樣式。", - "Current style: {style} — click for next": "目前樣式:{style}——點選切換到下一個", - "Collapse Contact panel": "收合目標面板", + "Current cockpit vision style: {style}. Activate for next style.": "當前座艙視覺樣式:{style}。點擊可切換到下一個樣式。", + "Current style: {style} — click for next": "當前樣式:{style}——點擊切換到下一個", + "Collapse Contact panel": "收起目標面板", "Expand Contact panel": "展開目標面板", - "Collapse contact panel": "收合目標面板", + "Collapse contact panel": "收起目標面板", "Expand contact panel": "展開目標面板", - "Collapse cockpit briefing panel": "收合駕駛艙簡報面板", - "Expand cockpit briefing panel": "展開駕駛艙簡報面板", - "Collapse briefing panel": "收合簡報面板", + "Collapse cockpit briefing panel": "收起座艙簡報面板", + "Expand cockpit briefing panel": "展開座艙簡報面板", + "Collapse briefing panel": "收起簡報面板", "Expand briefing panel": "展開簡報面板", - "OBSERVED / MAPPED PINGS": "觀測/標記訊號", - "SOURCE-BACKED EVENTS · NO SYNTHETIC NEWS": "有來源佐證的事件 · 無合成新聞", - "LATEST LOCATION-MATCHED REPORTING": "最新在地相關報導", + "OBSERVED / MAPPED PINGS": "觀測 / 地圖標註目標", + "SOURCE-BACKED EVENTS · NO SYNTHETIC NEWS": "來源可查的事件 · 無合成新聞", + "LATEST LOCATION-MATCHED REPORTING": "當前地區最新報道", "{source} · LOCATION QUERY · RECENT": "{source} · 位置查詢 · 近期", - "LOCAL INFO": "在地資訊", - "PLACE / CONDITIONS / POSITION": "地點/天候/位置", + "LOCAL INFO": "本地信息", + "PLACE / CONDITIONS / POSITION": "地點 / 狀況 / 位置", "TIME UNKNOWN": "時間未知", "{count}M AGO": "{count} 分鐘前", "{count}H AGO": "{count} 小時前", "{count}D AGO": "{count} 天前", "DIR UNKNOWN": "風向未知", "Select flight {title}": "選擇航班 {title}", - "{aircraftClass} · CURRENT": "{aircraftClass} · 目前", + "{aircraftClass} · CURRENT": "{aircraftClass} · 當前", "MILITARY FLIGHT": "軍用航班", "COMMERCIAL FLIGHT": "商用航班", "{aircraftClass} · {distance}": "{aircraftClass} · {distance}", @@ -1644,113 +1644,113 @@ "{count} INPUTS UNKNOWN": { "other": "{count} 項輸入未知" }, - "SOURCE STATUS UNAVAILABLE": "資料來源狀態不可用", + "SOURCE STATUS UNAVAILABLE": "數據源狀態不可用", "Restore real aircraft": "恢復真實飛機", - "Reclassify as TR-3B": "重新分類為 TR-3B", - "TRACK ACQUIRED": "已取得航跡", + "Reclassify as TR-3B": "重新歸類為 TR-3B", + "TRACK ACQUIRED": "已獲取航跡", "{label} · COURSE {heading}°": "{label} · 航向 {heading}°", "Context could not restore every layer; try again": "態勢未能恢復所有圖層,請重試", - "No selected data layers": "沒有已選資料圖層", + "No selected data layers": "沒有已選數據圖層", "{count} data layers could not be cleared": { - "other": "{count} 個資料圖層無法清除" + "other": "{count} 個數據圖層無法清除" }, "Cleared {count} data layers": { - "other": "已清除 {count} 個資料圖層" + "other": "已清除 {count} 個數據圖層" }, - "Selected data layers could not be cleared": "無法清除已選資料圖層", + "Selected data layers could not be cleared": "無法清除已選數據圖層", "Contacts could not complete the requested transition; try again": "目標未能完成所請求的切換,請重試", "Space Missions could not complete the requested transition; try again": "太空任務未能完成所請求的切換,請重試", - "Nearby installations refreshed": "附近設施已重新整理", - "Nearby installations could not be refreshed; try again": "無法重新整理附近設施,請重試", + "Nearby installations refreshed": "附近設施已刷新", + "Nearby installations could not be refreshed; try again": "無法刷新附近設施,請重試", "Space Missions cancellation could not restore the previous layer state": "取消太空任務後無法恢復先前的圖層狀態", - "That layer is unavailable in the current Context mode": "該圖層在目前態勢模式下不可用", + "That layer is unavailable in the current Context mode": "該圖層在當前態勢模式下不可用", "{layerId} could not {action} cleanly": "{layerId} 未能正常{action}", "start": "啟動", "stop": "停止", "{mode} could not start because another layer did not stop cleanly": "{mode} 無法啟動,因為另一個圖層未能正常停止", "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.": "無法重新整理地面高度。請在地圖載入完成後重新嘗試該檔案。", + "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} 個地圖物件" + "other": "{count} 個地圖對象" }, ", drawn with its own styles": ",使用其自帶樣式繪製", "Hide {name}": "隱藏 {name}", "Show {name}": "顯示 {name}", "Fly to {name}": "飛往 {name}", "Remove {name}": "移除 {name}", - "At most {count} files at once — remove one first.": "一次最多 {count} 個檔案——請先移除一個。", + "At most {count} files at once — remove one first.": "一次最多 {count} 個文件——請先移除一個。", "Reading {name}…": "正在讀取 {name}…", - "That file could not be read.": "無法讀取該檔案。", + "That file could not be read.": "無法讀取該文件。", "Added {count} files.": { - "other": "已新增 {count} 個檔案。" + "other": "已添加 {count} 個文件。" }, "{count} files could not be added ({name}: {error})": { - "other": "{count} 個檔案無法新增({name}:{error})" + "other": "{count} 個文件無法添加({name}:{error})" }, - "Some KML content was left out.": "部分 KML 內容未被匯入。", + "Some KML content was left out.": "部分 KML 內容未被導入。", "Press on the ground, not the sky": "請按在地面,而不是天空", "Drag to size the box": "拖動以調整框選大小", - "light {source} to use your {name} key": "開啟 {source} 以使用你的 {name} 金鑰", + "light {source} to use your {name} key": "開啟 {source} 以使用你的 {name} 密鑰", "light {source}": "開啟 {source}", ", or ": ",或", "{requirement}, or {offer}": "{requirement},或{offer}", - "Live Flights": "即時航班", - "Military Flights": "軍機", - "Earthquakes (24h)": "全球地震(24 小時)", + "Live Flights": "實時航班", + "Military Flights": "軍用航班", + "Earthquakes (24h)": "地震(24 小時)", "Satellites": "衛星", - "Space Missions (30d)": "太空發射任務(30 天)", - "Street Traffic": "道路交通", + "Space Missions (30d)": "太空任務(30 天)", + "Street Traffic": "街道交通", "CCTV": "CCTV", - "Radio": "廣播電台", - "Bikeshare": "公共自行車", - "Live AIS Vessels": "即時 AIS 船舶", - "Mapped Installations": "已標記軍事設施", - "Global Context": "全域態勢", - "Datacenters": "資料中心", + "Radio": "電臺", + "Bikeshare": "共享單車", + "Live AIS Vessels": "實時 AIS 船舶", + "Mapped Installations": "地圖標註設施", + "Global Context": "全局態勢", + "Datacenters": "數據中心", "Dams": "水壩", "Submarine Cables": "海底電纜", - "FIRMS Active Fires": "FIRMS 野火熱點", - "Local ADS-B": "本機 ADS-B", - "Transit": "大眾運輸", + "FIRMS Active Fires": "FIRMS 活躍火點", + "Local ADS-B": "本地 ADS-B", + "Transit": "公共交通", "Recent Imagery": "近期影像", "Fire Perimeters": "火場周界", "GNSS Integrity": "GNSS 完好性", "Rain radar": "降雨雷達", "Lightning density": "閃電密度", "Cyclone advisories": "氣旋預警", - "ALPR Cameras": "ALPR 攝影機", - "Live Vessels": "即時船舶", - "Bike Share": "公共自行車", - "Cameras": "攝影機", + "ALPR Cameras": "ALPR 攝像頭", + "Live Vessels": "實時船舶", + "Bike Share": "共享單車", + "Cameras": "攝像頭", "Street Level": "街景", - "Mapped ALPR Cameras": "已標記車牌辨識攝影機", - "Data Centers": "資料中心", - "Active Fires": "野火熱點", + "Mapped ALPR Cameras": "地圖標註 ALPR 攝像頭", + "Data Centers": "數據中心", + "Active Fires": "活躍火點", "Military aircraft": "軍用飛機", "Vessels": "船舶", - "CCTV + Street View fallback": "CCTV + 街景備援", + "CCTV + Street View fallback": "CCTV + 街景備用", "OpenStreetMap + optional Google Maps Places": "OpenStreetMap + 可選 Google Maps Places", "GFS / ECMWF IFS · FORECAST": "GFS / ECMWF IFS · 預報", "NOAA nowCOAST · OBSERVED": "NOAA nowCOAST · 觀測", - "NASA FIRMS · LIVE": "NASA FIRMS · 即時", + "NASA FIRMS · LIVE": "NASA FIRMS · 實時", "OSM routing": "OSM 路線規劃", - "data source|Local": "本機", - "ENABLING": "啟動中", - "DISABLING": "關閉中", - "Movement": "移動目標", + "data source|Local": "本地", + "ENABLING": "啟用中", + "DISABLING": "停用中", + "Movement": "動態目標", "Infrastructure": "基礎設施", "Events": "事件", "Weather": "天氣", - "Utilities": "公用設施", + "Utilities": "工具", "Other layers": "其他圖層", "{state} · {source}": "{state} · {source}", "UNCERTAIN · {source} · lifecycle state requires reconciliation": "不確定 · {source} · 生命週期狀態需要核對", "{state} · {source} · {detail} · retry {seconds}s": "{state} · {source} · {detail} · {seconds} 秒後重試", "{state} · {source} · {detail}": "{state} · {source} · {detail}", - "never": "從未", + "never": "未更新", "{source} · {loadingLabel}": "{source} · {loadingLabel}", "{accepted} of {raw} records accepted": "已接受 {accepted} / {raw} 條記錄", "incomplete snapshot": "快照不完整", @@ -1758,112 +1758,112 @@ "{state} · {source} · {ago} · retrying in {seconds}s": "{state} · {source} · {ago} · {seconds} 秒後重試", "{state} · {source} · {ago}": "{state} · {source} · {ago}", "{source} · {ago}": "{source} · {ago}", - "UNCERTAIN": "狀態未知", + "UNCERTAIN": "不確定", "status chip|UNAVAILABLE": "不可用", - "Data source unavailable": "資料來源不可用", + "Data source unavailable": "數據源不可用", "{name}: {state}": "{name}:{state}", "{count}s ago": "{count} 秒前", - "Local FM stopped: internet radio started": "本機 FM 已停止:網路電台已開始播放", + "Local FM stopped: internet radio started": "本地 FM 已停止:網絡電臺已開始播放", "IDLE": "空閒", - "CONNECTING": "連線中", + "CONNECTING": "連接中", "TUNING": "調諧中", "STREAMING": "接收中", - "UNSUPPORTED": "不支援", + "UNSUPPORTED": "不支持", "idle": "空閒", - "running": "執行中", + "running": "運行中", "suspended": "已掛起", "closed": "已關閉", - "feed status|live": "即時", + "feed status|live": "實時", "feed status|stale": "過期", - "feed status|unreachable": "無法連線", + "feed status|unreachable": "無法連接", "feed status|invalid": "無效", - "waiting for IQ": "等待 IQ 資料", + "waiting for IQ": "等待 IQ 數據", "{count} messages": { - "other": "{count} 條訊息" + "other": "{count} 條消息" }, "DSP {count} blocks": { - "other": "DSP {count} 個資料塊" + "other": "DSP {count} 個數據塊" }, "DSP waiting": "DSP 等待中", - "{level} dBFS audio": "音訊 {level} dBFS", - "audio signal --": "音訊訊號 --", - "audio {state}": "音訊 {state}", + "{level} dBFS audio": "音頻 {level} dBFS", + "audio signal --": "音頻信號 --", + "audio {state}": "音頻 {state}", "{count} HEARD": { - "other": "已接收 {count} 架飛機的訊號" + "other": "已接收 {count} 架飛機的信號" }, - "DISCONNECT": "斷開連線", - "CONNECT": "連線", + "DISCONNECT": "斷開連接", + "CONNECT": "連接", "LOCATING…": "定位中…", "LOCATED": "已定位", "LOCATE": "定位", - " · read while Local ADS-B is on": " · 僅在本機 ADS-B 開啟時讀取", - "Decoder feeds: {feeds}": "解碼器資料來源:{feeds}", + " · read while Local ADS-B is on": " · 僅在本地 ADS-B 開啟時讀取", + "Decoder feeds: {feeds}": "解碼器數據源:{feeds}", "Language: {language}": "語言:{language}", - "Change the interface language": "更改介面語言", - "Interface language": "介面語言", - "Search languages": "搜尋語言", + "Change the interface language": "更改界面語言", + "Interface language": "界面語言", + "Search languages": "搜索語言", "No matching languages": "沒有匹配的語言", "📍 Location: --": "📍 位置:--", "Landmark: --": "地標:--", - "Searched location": "已搜尋的位置", - "ORBIT": "軌道", + "Searched location": "已搜索的位置", + "ORBIT": "環繞", "Location not found": "未找到位置", - "Search failed": "搜尋失敗", - "Detailed outline unavailable": "無法取得詳細輪廓", + "Search failed": "搜索失敗", + "Detailed outline unavailable": "無法獲取詳細輪廓", "Fly to a POI first": "請先飛往一個 POI", - "Reset to full globe view": "重設為完整地球視野", - "Reset cockpit to full globe view": "駕駛艙重設為完整地球視野", - "Resetting to full globe view": "正在重設為完整地球視野", - "Resetting cockpit to full globe view": "正在將駕駛艙重設為完整地球視野", + "Reset to full globe view": "重置為完整地球視圖", + "Reset cockpit to full globe view": "將座艙重置為完整地球視圖", + "Resetting to full globe view": "正在重置為完整地球視圖", + "Resetting cockpit to full globe view": "正在將座艙重置為完整地球視圖", "MAP": "地圖", "panel": "面板", "Expand {name}": "展開 {name}", "Collapse {name}": "收起 {name}", - "Expand Radio": "展開電台", - "Collapse Radio": "收起電台", - "Expand Radio section": "展開電台區域", - "Collapse Radio section": "收起電台區域", - "Panel layout updated — positions reset to new defaults": "面板版面已更新——位置已重設為新的預設值", + "Expand Radio": "展開電臺", + "Collapse Radio": "收起電臺", + "Expand Radio section": "展開電臺區域", + "Collapse Radio section": "收起電臺區域", + "Panel layout updated — positions reset to new defaults": "面板佈局已更新——位置已重置為新的默認值", "Austin": "奧斯汀", "San Francisco": "舊金山", "New York": "紐約", "Tokyo": "東京", "London": "倫敦", "Paris": "巴黎", - "Dubai": "杜拜", + "Dubai": "迪拜", "Washington DC": "華盛頓特區", "Tallinn": "塔林", "Los Angeles": "洛杉磯", - "Collapse Cockpit display options": "收起駕駛艙顯示選項", - "Expand Cockpit display options": "展開駕駛艙顯示選項", - "Collapse Cockpit Radio controls": "收起駕駛艙廣播控制", - "Expand Cockpit Radio controls": "展開駕駛艙廣播控制", + "Collapse Cockpit display options": "收起座艙顯示選項", + "Expand Cockpit display options": "展開座艙顯示選項", + "Collapse Cockpit Radio controls": "收起座艙電臺控件", + "Expand Cockpit Radio controls": "展開座艙電臺控件", "CH {index} / {total}": "頻道 {index} / {total}", - "NO STATIONS": "無電台", - "NO STATION AVAILABLE": "無可用電台", - "{name}, station {index} of {total}": "{name},第 {index} 個電台,共 {total} 個", - "No station available": "沒有可用電台", - "OFF AIR": "未播出", - "STATION UNAVAILABLE": "電台無法使用", - "Station unavailable after directory refresh": "目錄重新整理後該電台不可用", - "Radio could not {action} cleanly": "電台未能正常{action}", - "Go to expanded Radio section": "前往展開的電台區域", - "Expand Radio section in Context": "在態勢面板中展開電台區域", - "Close compact Radio controls": "關閉精簡廣播控制", - "Open compact Radio controls": "開啟精簡廣播控制", + "NO STATIONS": "無電臺", + "NO STATION AVAILABLE": "無可用電臺", + "{name}, station {index} of {total}": "{name},第 {index} 個電臺,共 {total} 個", + "No station available": "沒有可用電臺", + "OFF AIR": "停播", + "STATION UNAVAILABLE": "電臺不可用", + "Station unavailable after directory refresh": "目錄刷新後該電臺不可用", + "Radio could not {action} cleanly": "電臺未能正常{action}", + "Go to expanded Radio section": "前往展開的電臺區域", + "Expand Radio section in Context": "在態勢面板中展開電臺區域", + "Close compact Radio controls": "關閉精簡電臺控件", + "Open compact Radio controls": "打開精簡電臺控件", "SYNC": "同步", "RECONCILE": "核對", "DISABLE": "停用", "ENABLE": "啟用", - "Reconcile Radio — lifecycle uncertain": "核對電台——生命週期狀態不確定", - "Disable Radio": "停用廣播", - "Enable Radio": "啟用廣播", + "Reconcile Radio — lifecycle uncertain": "核對電臺——生命週期狀態不確定", + "Disable Radio": "停用電臺", + "Enable Radio": "啟用電臺", "DIRECTORY BAND": "目錄頻段", "{category} BAND": "{category} 頻段", - "NO STATION SELECTED": "未選擇電台", - "Directory metadata only": "僅目錄後設資料", - "Loading station directory…": "正在載入電台目錄…", - "Choose a globe marker or use next.": "選擇地球上的標記或按「下一個」。", + "NO STATION SELECTED": "未選擇電臺", + "Directory metadata only": "僅目錄元數據", + "Loading station directory…": "正在加載電臺目錄…", + "Choose a globe marker or use next.": "請選擇地球上的標註或使用“下一個”。", "TAGS · {tags}": "標籤 · {tags}", "Play": "播放", "PAUSE": "暫停", @@ -1871,32 +1871,32 @@ "PLAY": "播放", "selected": "所選", "nearest": "最近", - "{action} {target} radio station": "{action}{target}電台", - "RADIO STATE UNCERTAIN": "電台狀態不確定", + "{action} {target} radio station": "{action}{target}電臺", + "RADIO STATE UNCERTAIN": "電臺狀態不確定", "SYNCING DIRECTORY": "正在同步目錄", - "RADIO READY": "廣播就緒", + "RADIO READY": "電臺就緒", "SYNCING": "同步中", "READY": "就緒", - "station": "電台", + "station": "電臺", " · stale/degraded directory": " · 目錄過期/降級", " · degraded directory": " · 目錄降級", " · stale directory": " · 目錄過期", - " · outside current filter": " · 不在目前篩選範圍內", + " · outside current filter": " · 不在當前篩選範圍內", "Ready — playback starts only from your action": "就緒——手動操作後開始播放", - "Radio off": "廣播關閉", - "Connecting directly to broadcaster…": "正在直接連線廣播方…", - "Buffering broadcaster stream…": "正在緩衝廣播串流…", + "Radio off": "電臺已關閉", + "Connecting directly to broadcaster…": "正在直接連接廣播方…", + "Buffering broadcaster stream…": "正在緩衝廣播流…", "Playing {station}": "正在播放 {station}", "Paused {station}": "已暫停 {station}", - "Broadcaster stream unavailable": "廣播串流不可用", - " · muted during voice interaction": " · 語音互動期間已靜音", + "Broadcaster stream unavailable": "廣播流不可用", + " · muted during voice interaction": " · 語音交互期間已靜音", " · restoring volume after voice": " · 語音結束後正在恢復音量", - " · static indicates no broadcaster audio": " · 雜音表示廣播方沒有音訊", + " · static indicates no broadcaster audio": " · 雜音表示廣播方沒有音頻", " · tuning static until broadcaster starts": " · 廣播方啟動前為調諧雜音", - "Station unavailable after directory refresh — choose another channel": "目錄重新整理後電台不可用——請選擇其他頻道", - "Radio is enabling…": "電台正在啟用…", - "Radio is disabling…": "電台正在停用…", - "Radio lifecycle is uncertain — use Enable or Disable to reconcile": "電台生命週期狀態不確定——請使用「啟用」或「停用」進行核對", + "Station unavailable after directory refresh — choose another channel": "目錄刷新後電臺不可用——請選擇其他頻道", + "Radio is enabling…": "電臺正在啟用…", + "Radio is disabling…": "電臺正在停用…", + "Radio lifecycle is uncertain — use Enable or Disable to reconcile": "電臺生命週期狀態不確定——請使用“啟用”或“停用”進行核對", "Clear reading": "清除讀數", "Earlier observation": "較早觀測", "Observed history": "觀測歷史", @@ -1905,10 +1905,10 @@ "Newest frame per product": "每個產品的最新一幀", "Replay observed history": "回放觀測歷史", "Imagery on Esri · Google 3D returns when cleared": "影像顯示在 Esri 底圖上 · 清除後恢復 Google 3D", - "Point the camera at the ground to use the view": "將相機對準地面才能使用目前視野", + "Point the camera at the ground to use the view": "將相機對準地面才能使用當前視野", "That point cannot anchor a box": "該點無法作為框選錨點", "Imagery stops at ±{limit}° latitude": "影像僅覆蓋到緯度 ±{limit}°", - "{owner} is using the pointer — close it first": "{owner} 正在使用指標——請先將其關閉", + "{owner} is using the pointer — close it first": "{owner} 正在使用指針——請先將其關閉", "Box is {size} wide · limit {limit}": "框選寬 {size} · 上限 {limit}", "View is {size} wide · limit {limit}": "視野寬 {size} · 上限 {limit}", "VS BASEMAP": "對比底圖", @@ -1922,7 +1922,7 @@ "newest day (partial coverage)": "最新一天(部分覆蓋)", "newest overview": "最新概覽", "No imagery": "無影像", - "Loading": "載入中", + "Loading": "加載中", "coverage|full": "完整", "coverage|partial": "部分", "unknown": "未知", @@ -1930,19 +1930,19 @@ "{percent}% cloud": "{percent}% 雲量", "{min}–{max}% cloud": "{min}–{max}% 雲量", "NO BOX": "無框選", - "SEARCHING": "搜尋中", + "SEARCHING": "搜索中", "{count} DAYS": { "other": "{count} 天" }, "Zoom in or draw a smaller box": "放大或繪製更小的框選", - "Select a box or use the view": "框選區域,或使用目前視野", - "Searching the last 30 days": "正在搜尋最近 30 天", + "Select a box or use the view": "框選區域,或使用當前視野", + "Searching the last 30 days": "正在搜索最近 30 天", "No days to show for this box": "此框選沒有可顯示的日期", - "Drag the divider · SWAP trades sides": "拖動分割線 · 「交換」可互換兩側", - "← → preview · A or B pins the focused day": "← → 預覽 · A 或 B 固定目前所選日期", + "Drag the divider · SWAP trades sides": "拖動分割線 · “交換”可互換兩側", + "← → preview · A or B pins the focused day": "← → 預覽 · A 或 B 固定當前所選日期", "← → preview the other side · A or B pins it": "← → 預覽另一側 · A 或 B 將其固定", "S on another day replaces it · × unpins": "在其他日期按 S 替換 · × 取消固定", - "← → preview · S shows the focused day": "← → 預覽 · S 顯示目前所選日期", + "← → preview · S shows the focused day": "← → 預覽 · S 顯示當前所選日期", "ZOOM IN": "放大", "Fly in until the view fits the 1,000 km limit": "拉近直到視野不超過 1,000 km 上限", "Imagery days, newest first · arrows move, S or A and B pin": "影像日期(最新在前)· 方向鍵移動,S、A、B 固定", @@ -1954,9 +1954,9 @@ "SELECT BOX": "框選區域", "Drag a box on the map (Esc cancels)": "在地圖上拖出框選(Esc 取消)", "USE VIEW": "使用視野", - "Use the current view as the box": "以目前視野作為框選", + "Use the current view as the box": "以當前視野作為框選", "Forget the box and its images": "清除框選及其影像", - "START HERE": "從這裡開始", + "START HERE": "從此開始", "Checking": "檢查中", "PREVIEW": "預覽", "Newest day with imagery for this box": "此框選有影像的最新一天", @@ -1968,27 +1968,27 @@ "preview": "預覽", "start here": "從此開始", "No box": "無框選", - "Searching": "搜尋中", + "Searching": "搜索中", "Every day is empty here": "此處每天都為空", - "Sources off": "資料來源已關閉", + "Sources off": "數據源已關閉", "VS": "對比", - "Not set": "未設定", + "Not set": "未設置", "Basemap": "底圖", - "Source off": "資料來源已關閉", + "Source off": "數據源已關閉", "Unpin {slot}": "取消固定 {slot}", "Unpin the image": "取消固定圖像", - "EXPORT {slot}": "匯出 {slot}", - "EXPORT": "匯出", + "EXPORT {slot}": "導出 {slot}", + "EXPORT": "導出", "Download {slot} as a PNG": "將 {slot} 下載為 PNG", "Download the image as a PNG": "將圖像下載為 PNG", "Box {width} × {height} km": "框選 {width} × {height} km", - "Acquired {time}": "取得於 {time}", + "Acquired {time}": "獲取於 {time}", "Coverage {coverage}": "覆蓋 {coverage}", - "START HERE · {reason}": "從這裡開始 · {reason}", + "START HERE · {reason}": "從此開始 · {reason}", "Daily overview shows little detail in a box this small": "在這麼小的框選內,每日概覽幾乎看不出細節", "Imagery: NASA GIBS and Worldview · HLS (Sentinel-2, Landsat 8/9) and VIIRS": "影像:NASA GIBS 與 Worldview · HLS(Sentinel-2、Landsat 8/9)與 VIIRS", "Details": "詳情", - "Times, coverage, sources": "時間、覆蓋與資料來源", + "Times, coverage, sources": "時間、覆蓋與數據源", "HIDE EMPTY DAYS": "隱藏空白日", "SHOW EMPTY DAYS · {count}": "顯示空白日 · {count}", "Days the probe found empty in this box": "探測發現此框選內為空的日期", @@ -1999,69 +1999,69 @@ "Recent imagery against the basemap divider": "近期影像與底圖對比分割線", "Recent imagery A and B divider": "近期影像 A / B 分割線", "{before} {left} percent, {after} {right} percent": "{before} {left}%,{after} {right}%", - "Export failed · {error}": "匯出失敗 · {error}", + "Export failed · {error}": "導出失敗 · {error}", "Scene action failed": "場景操作失敗", "New scene name": "新場景名稱", - "Delete scene \"{scene}\" and all shots?": "刪除場景「{scene}」及其全部鏡頭?", - "Delete shot \"{shot}\"?": "刪除鏡頭「{shot}」?", + "Delete scene \"{scene}\" and all shots?": "刪除場景“{scene}”及其全部鏡頭?", + "Delete shot \"{shot}\"?": "刪除鏡頭“{shot}”?", "Stopped (Esc)": "已停止(Esc)", "SPARSE": "稀疏", - "BALANCED": "平衡", - "No shots yet. Use CAPTURE SHOT to save current look.": "尚無鏡頭。使用「擷取鏡頭」儲存目前畫面。", - "Double-click to rename": "按兩下以重新命名", + "BALANCED": "均衡", + "No shots yet. Use CAPTURE SHOT to save current look.": "暫無鏡頭。使用“保存鏡頭”保存當前視角及設置。", + "Double-click to rename": "雙擊重命名", "Shot name": "鏡頭名稱", - "LOAD": "載入", + "LOAD": "加載", "DEL": "刪除", "{duration}s + {hold}s": "{duration} 秒 + {hold} 秒", - "Choose files": "選擇檔案", + "Choose files": "選擇文件", "{count} files selected": { - "other": "已選擇 {count} 個檔案" + "other": "已選擇 {count} 個文件" }, - "No file chosen": "未選擇檔案", + "No file chosen": "未選擇文件", "Cancel": "取消", - "EDIT DETAILS": "編輯詳細資料", + "EDIT DETAILS": "編輯詳情", "SHARE SCENE": "分享場景", "Shared flight follow expired": "分享的航班跟隨已過期", "Shared military flight follow expired": "分享的軍用航班跟隨已過期", "Shared satellite follow expired": "分享的衛星跟隨已過期", - "Shared flight could not be restored — feed unavailable": "無法恢復分享的航班——資料來源不可用", - "Shared military flight could not be restored — feed unavailable": "無法恢復分享的軍用航班——資料來源不可用", - "Shared satellite could not be restored — feed unavailable": "無法恢復分享的衛星——資料來源不可用", + "Shared flight could not be restored — feed unavailable": "無法恢復分享的航班——數據源不可用", + "Shared military flight could not be restored — feed unavailable": "無法恢復分享的軍用航班——數據源不可用", + "Shared satellite could not be restored — feed unavailable": "無法恢復分享的衛星——數據源不可用", "Shared flight is unavailable": "分享的航班不可用", "Shared military flight is unavailable": "分享的軍用航班不可用", "Shared satellite is unavailable": "分享的衛星不可用", "entity": "實體", "Shared {subject} follow expired": "分享的 {subject} 跟隨已過期", - "Shared {subject} could not be restored — feed unavailable": "無法恢復分享的 {subject}——資料來源不可用", + "Shared {subject} could not be restored — feed unavailable": "無法恢復分享的 {subject}——數據源不可用", "Shared {subject} is unavailable": "分享的 {subject} 不可用", - "ACQUIRING": "取得中", + "ACQUIRING": "獲取中", "SHARED {subject}": "分享的 {subject}", "subject": "目標", - "LOADING LIVE DATA": "載入即時資料", - "LOAD COMPLETE": "載入完成", - "LOAD CANCELLED": "載入已取消", - "LOAD FAILED": "載入失敗", - "LIVE DATA OFF": "即時資料已關閉", - "MAPPED SITES LOADED": "已載入地圖標註設施", + "LOADING LIVE DATA": "正在加載實時數據", + "LOAD COMPLETE": "加載完成", + "LOAD CANCELLED": "加載已取消", + "LOAD FAILED": "加載失敗", + "LIVE DATA OFF": "實時數據已關閉", + "MAPPED SITES LOADED": "已加載地圖標註設施", "RETRYING MAPPED SITES": "正在重試地圖標註設施", - "FETCHING MAPPED SITES": "正在取得地圖標註設施", - "RETRYING ALPR CAMERAS": "正在重試 ALPR 攝影機", - "FETCHING ALPR CAMERAS": "正在取得 ALPR 攝影機", + "FETCHING MAPPED SITES": "正在獲取地圖標註設施", + "RETRYING ALPR CAMERAS": "正在重試 ALPR 攝像頭", + "FETCHING ALPR CAMERAS": "正在獲取 ALPR 攝像頭", "OVERPASS TEMPORARILY UNAVAILABLE": "Overpass 暫時不可用", "OVERPASS RATE-LIMITED": "Overpass 已被限流", - "OVERPASS TIMED OUT": "Overpass 逾時", + "OVERPASS TIMED OUT": "Overpass 超時", "OVERPASS COULD NOT COMPLETE THE QUERY": "Overpass 無法完成查詢", "MAP TILES TEMPORARILY UNAVAILABLE": "地圖瓦片暫時不可用", - "MAPPED NAMES TEMPORARILY UNAVAILABLE": "地圖標註名稱暫時不可用", - "TURNING OFF LIVE DATA": "正在關閉即時資料", - "REFRESHING LIVE DATA": "正在重新整理即時資料", - "syncing road network": "同步道路網路", + "MAPPED NAMES TEMPORARILY UNAVAILABLE": "地點名稱暫時不可用", + "TURNING OFF LIVE DATA": "正在關閉實時數據", + "REFRESHING LIVE DATA": "正在刷新實時數據", + "syncing road network": "正在同步路網", "retry pending": "等待重試", "retrying in {seconds}s": "{seconds} 秒後重試", - "ALPR cameras": "ALPR 攝影機", + "ALPR cameras": "ALPR 攝像頭", "OpenSky OAuth client missing/invalid": "OpenSky OAuth 客戶端缺失/無效", "OpenSky OAuth rejected credentials": "OpenSky OAuth 拒絕了憑據", - "OpenSky username/password rejected": "OpenSky 使用者名稱/密碼被拒絕", + "OpenSky username/password rejected": "OpenSky 用戶名/密碼被拒絕", "OpenSky auth missing": "OpenSky 缺少認證", "OpenSky auth required": "OpenSky 需要認證", "OpenSky auth invalid": "OpenSky 認證無效", @@ -2069,36 +2069,36 @@ "KartaView answered HTTP {status}": "KartaView 返回 HTTP {status}", "Panoramax answered HTTP {status}": "Panoramax 返回 HTTP {status}", "KartaView refused the request (code {code})": "KartaView 拒絕了請求(代碼 {code})", - "Vector tiles unavailable (HTTP {status})": "向量瓦片不可用(HTTP {status})", - "GNSS feed unavailable (HTTP {status})": "GNSS 資料來源不可用(HTTP {status})", + "Vector tiles unavailable (HTTP {status})": "矢量瓦片不可用(HTTP {status})", + "GNSS feed unavailable (HTTP {status})": "GNSS 數據源不可用(HTTP {status})", "{count} CelesTrak groups unavailable": { "other": "{count} 個 CelesTrak 分組不可用" }, - "{feed} feed unavailable": "{feed} 資料來源不可用", - "Source snapshot {minutes} min old": "資料來源快照:{minutes} 分鐘前", + "{feed} feed unavailable": "{feed} 數據源不可用", + "Source snapshot {minutes} min old": "數據源快照:{minutes} 分鐘前", "{source} rate limited (anonymous)": "{source} 已被限流(匿名)", "{source} rate limited": "{source} 已被限流", - "{source} network error": "{source} 網路錯誤", - "Malformed {source} aircraft rows": "{source} 飛機資料行格式錯誤", - "Malformed {source} response": "{source} 回應格式錯誤", + "{source} network error": "{source} 網絡錯誤", + "Malformed {source} aircraft rows": "{source} 飛機數據行格式錯誤", + "Malformed {source} response": "{source} 響應格式錯誤", "entry {n}": "條目 {n}", "feeds {names} stale": { - "other": "資料來源 {names} 過期" + "other": "數據源 {names} 過期" }, "feeds {names} unreachable": { - "other": "資料來源 {names} 無法連線" + "other": "數據源 {names} 無法連接" }, "feeds {names} invalid": { - "other": "資料來源 {names} 無效" + "other": "數據源 {names} 無效" }, - "Loading {feeds}": "正在載入 {feeds}", + "Loading {feeds}": "正在加載 {feeds}", "{count} heard": { - "other": "已接收 {count} 架飛機的訊號" + "other": "已接收 {count} 架飛機的信號" }, "USB {rate} msg/s": "USB {rate} msg/s", "{rate} msg/s": "{rate} msg/s", "{count} feeds live": { - "other": "即時資料來源 {count} 個" + "other": "實時數據源 {count} 個" }, "{feed} {count} ({seconds}s old)": "{feed} {count}({seconds} 秒前)", "Street Level could not start": "街景未能啟動", @@ -2126,21 +2126,21 @@ "{name} imagery off": "{name} 影像已關閉", "Image by {creator}": "圖像作者:{creator}", " or ": " 或 ", - "OPEN {labels}": "開啟 {labels}", - "Open {names} at the centre of the view": "在視野中心開啟 {names}", - "Zoom in to a street to open {names} here": "放大到街道以在此處開啟 {names}", - "Loading this sequence…": "正在載入此序列…", + "OPEN {labels}": "打開 {labels}", + "Open {names} at the centre of the view": "在視野中心打開 {names}", + "Zoom in to a street to open {names} here": "放大到街道以在此處打開 {names}", + "Loading this sequence…": "正在加載此序列…", "{n} images in this sequence · Esc clears": { - "other": "此序列共 {n} 張圖像 · 按 Esc 清除" + "other": "此序列共 {n} 張圖像 · Esc 清除" }, "{n} streets in view · click a line for its nearest photo": { - "other": "視野內共 {n} 條街道 · 點選線段檢視距其最近的照片" + "other": "視野內共 {n} 條街道 · 點擊線段查看距其最近的照片" }, "{n} sequences in view · click a line for its nearest photo": { - "other": "視野內共 {n} 條序列 · 點選線段檢視距其最近的照片" + "other": "視野內共 {n} 條序列 · 點擊線段查看距其最近的照片" }, "{n} sequences in view · click a line for its photos": { - "other": "視野內共 {n} 條序列 · 點選線段檢視其照片" + "other": "視野內共 {n} 條序列 · 點擊線段查看其照片" }, "km/h": "km/h", "m/s": "m/s", @@ -2156,67 +2156,67 @@ "s": "秒", "dB": "dB", "Celestial ring — reveal the full globe": "天球環——顯示完整地球", - "Celestial ring — available in Normal style": "天球環——僅在一般樣式下可用", - "Detection overlay: {mode}": "偵測疊加層:{mode}", - "Detection overlay: off": "偵測疊加層:關閉", - "DETECT": "偵測", + "Celestial ring — available in Normal style": "天球環——僅在常規樣式下可用", + "Detection overlay: {mode}": "探測疊加層:{mode}", + "Detection overlay: off": "探測疊加層:關閉", + "DETECT": "探測", "{time} · {minutes} min ago": "{time} · {minutes} 分鐘前", "Active weather": "已啟用的天氣圖層", "LATEST · newest per product": "最新 · 每個產品的最新一幀", - "Forecast · valid {valid} · issued {issued}": "預報 · 有效時間 {valid} · 發布時間 {issued}", + "Forecast · valid {valid} · issued {issued}": "預報 · 有效時間 {valid} · 發佈時間 {issued}", "{detail} · Does not follow history": "{detail} · 不隨觀測歷史變化", "Forecast · valid {valid}": "預報 · 有效時間 {valid}", "voice|OFF": "關", - "voice|CONNECTING": "連線中", + "voice|CONNECTING": "連接中", "voice|LISTENING": "聆聽中", "voice|EXECUTING": "執行中", "voice|ERROR": "錯誤", - "AI AGENT": "AI 助理", - "Voice model tier — applies next session": "語音模型等級——於下次工作階段生效", + "AI AGENT": "AI 智能體", + "Voice model tier — applies next session": "語音模型檔位——下次會話生效", "STD": "標準", - "Estimated session cost": "預估工作階段費用", - "Voice control — activate to toggle voice; hold Space to speak": "語音控制——啟用以切換語音;按住空白鍵說話", + "Estimated session cost": "預估會話費用", + "Voice control — activate to toggle voice; hold Space to speak": "語音控制——點擊可切換語音;按住空格鍵說話", "ON/OFF": "開/關", - "VOICE STANDBY": "語音待命", + "VOICE STANDBY": "語音待機", "VOICE CONTROL": "語音控制", - "Hold Space to speak · tap Space to activate focused controls": "按住空白鍵說話 · 輕按空白鍵啟用聚焦的控制項", - "Voice assistant": "語音助理", + "Hold Space to speak · tap Space to activate focused controls": "按住空格鍵說話 · 輕按空格鍵激活當前聚焦的控件", + "Voice assistant": "語音助手", "VOICE": "語音", "Dismiss voice card": "關閉語音卡片", "YOU": "你", "THIS": "所指", - "Plan": "計畫", + "Plan": "計劃", "Referenced items": "引用條目", "NOTES & SOURCES": "說明與來源", "VOICE SYSTEM ERROR": "語音系統錯誤", "DISMISS": "關閉", - "Check microphone permission and network access, then try again.": "請檢查麥克風權限與網路連線後再試一次。", - "Stopped by voice": "已透過語音停止", - "WebRTC microphone support unavailable": "目前瀏覽器不支援透過 WebRTC 使用麥克風", + "Check microphone permission and network access, then try again.": "請檢查麥克風權限和網絡連接,然後重試。", + "Stopped by voice": "已通過語音停止", + "WebRTC microphone support unavailable": "當前瀏覽器不支持通過 WebRTC 使用麥克風", "Requesting microphone": "正在請求麥克風", - "Release Space to send": "鬆開空白鍵傳送", - "Hold Space to talk": "按住空白鍵說話", + "Release Space to send": "鬆開空格鍵發送", + "Hold Space to talk": "按住空格鍵說話", "Ask or command": "提問或下達指令", "Voice off": "語音已關閉", "VOICE UNAVAILABLE": "語音不可用", "VOICE ACTIVE": "語音已啟用", - "Voice session could not be started.": "無法啟動語音工作階段。", + "Voice session could not be started.": "無法啟動語音會話。", "MINI": "輕量", - "Next session: {pendingId} — this session stays on {modelId}": "下次工作階段:{pendingId}——本次工作階段仍使用 {modelId}", - "Voice model: {pendingId} — click to switch to {target}; applies next session": "語音模型:{pendingId}——點選切換到 {target};下次工作階段生效", + "Next session: {pendingId} — this session stays on {modelId}": "下次會話:{pendingId}——本次會話仍使用 {modelId}", + "Voice model: {pendingId} — click to switch to {target}; applies next session": "語音模型:{pendingId}——點擊切換到 {target};下次會話生效", "standard": "標準", "mini": "輕量", "COST UNKNOWN": "費用未知", - "ChatGPT OAuth session: {responses} response(s), {input} input and {output} output tokens, {captions} caption transcription(s) reported.": "ChatGPT OAuth 工作階段:已報告 {responses} 個回應、{input} 個輸入 token、{output} 個輸出 token、{captions} 次字幕轉寫。", + "ChatGPT OAuth session: {responses} response(s), {input} input and {output} output tokens, {captions} caption transcription(s) reported.": "ChatGPT OAuth 會話:已報告 {responses} 個響應、{input} 個輸入 token、{output} 個輸出 token、{captions} 次字幕轉寫。", "USD cost and the API spend cap are unavailable for this auth mode.": "此認證模式下無法提供美元費用與 API 消費上限。", - "Usage is incomplete because a response was still in flight when the session ended.": "用量不完整,因為工作階段結束時仍有回應在處理中。", - "Estimated session cost on {modelId} — {responses} response(s). Warns at {warn}, ends the session at {cap}.": "{modelId} 的預估工作階段費用——{responses} 次回應。達到 {warn} 時警告,達到 {cap} 時結束工作階段。", - "Estimate is incomplete — a response was still in flight when the session ended, so its usage was never reported.": "估算不完整——工作階段結束時仍有回應在處理中,因此其用量從未回報。", + "Usage is incomplete because a response was still in flight when the session ended.": "用量不完整,因為會話結束時仍有響應在處理中。", + "Estimated session cost on {modelId} — {responses} response(s). Warns at {warn}, ends the session at {cap}.": "{modelId} 的預估會話費用——{responses} 次響應。達到 {warn} 時警告,達到 {cap} 時結束會話。", + "Estimate is incomplete — a response was still in flight when the session ended, so its usage was never reported.": "估算不完整——會話結束時仍有響應在處理中,因此其用量從未上報。", "STANDARD": "標準", - "{tier} applies next session": "{tier} 將在下次工作階段生效", - "Session ended — cost cap {cost}": "工作階段已結束——已達費用上限 {cost}", + "{tier} applies next session": "{tier} 將在下次會話生效", + "Session ended — cost cap {cost}": "會話已結束——已達費用上限 {cost}", "MIC": "麥克風", - "Radio did not start": "電台未能啟動", + "Radio did not start": "電臺未能啟動", "Running command": "正在執行指令", "{n} aircraft": { "other": "{n} 架飛機" @@ -2246,33 +2246,33 @@ "other": "{n} 個氣旋" }, "{n} buses": { - "other": "{n} 輛公車" + "other": "{n} 輛公交車" }, "{n} bike share": { - "other": "{n} 個公共自行車站點" + "other": "{n} 個共享單車站點" }, "{n} flock cameras": { - "other": "{n} 個 Flock 攝影機" + "other": "{n} 個 Flock 攝像頭" }, "{n} military bases": { "other": "{n} 處軍事基地" }, "{n} datacenters": { - "other": "{n} 個資料中心" + "other": "{n} 個數據中心" }, "{n} dams": { "other": "{n} 座水壩" }, "{n} air quality": { - "other": "{n} 個空氣品質站點" + "other": "{n} 個空氣質量站點" }, "{n} results": { "other": "{n} 條結果" }, - "anywhere in the loaded data": "已載入資料中的任意位置", + "anywhere in the loaded data": "已加載數據中的任意位置", "in view": "視野內", "within {radius} of the view centre": "視野中心 {radius} 範圍內", - "within {radius} of {place} (Contacts window)": "{place} {radius} 範圍內(目標範圍)", + "within {radius} of {place} (Contacts window)": "{place} {radius} 範圍內(目標窗口)", "within {radius} of {place}": "{place} {radius} 範圍內", "within {radius}": "{radius} 範圍內", "over {region}": "{region} 範圍內", @@ -2280,57 +2280,57 @@ "{items} {scope}": "{items} {scope}", "last 24 h": "過去 24 小時", "past 30 d and upcoming": "過去 30 天及未來", - "the flights layer loads by viewport": "航班圖層按視口載入", + "the flights layer loads by viewport": "航班圖層按視口加載", "distance is ground distance, not overhead": "距離為地面距離,而非空中直線距離", "the count is a lower bound because at least one layer reached its retained limit.": "該計數為下限,因為至少一個圖層已達到其保留上限。", "{label} off": "{label} 已關閉", - "{label} loading": "{label} 載入中", + "{label} loading": "{label} 加載中", "{label} error": "{label} 出錯", - "counted the first {returned} loaded records": "已統計最先載入的 {returned} 條記錄", - "counted {returned} of {total} loaded records": "已統計 {total} 條已載入記錄中的 {returned} 條", - "{layers} just turned on — still loading, counts will rise": "{layers} 剛開啟——仍在載入,計數還會增加", + "counted the first {returned} loaded records": "已統計最先加載的 {returned} 條記錄", + "counted {returned} of {total} loaded records": "已統計 {total} 條已加載記錄中的 {returned} 條", + "{layers} just turned on — still loading, counts will rise": "{layers} 剛開啟——仍在加載,計數還會增加", "Contacts panel snapshot at {time} — the same retained cohort supplies the card, speech, and follow-up memory": "目標面板快照({time})——卡片、語音播報和後續追問記憶均來自同一組保留目標", "Contacts panel snapshot — the same retained cohort supplies the card, speech, and follow-up memory": "目標面板快照——卡片、語音播報和後續追問記憶均來自同一組保留目標", "Fly below {km} km to a covered region": "請降至 {km} km 以下並飛往有覆蓋的區域", "No feed here yet · {n} regions available": { - "other": "此處暫無資料來源 · 有 {n} 個覆蓋區域" + "other": "此處暫無數據源 · 有 {n} 個覆蓋區域" }, "degraded": "降級", "stale": "過期", "partial": "部分可用", "fallback": "備用", "unavailable": "不可用", - "Not answered: {layers}": "未回應:{layers}", + "Not answered: {layers}": "未響應:{layers}", "Toggle voice control": "切換語音控制", - "Activate to toggle voice": "啟用以切換語音", + "Activate to toggle voice": "點擊切換語音", "Voice active": "語音已啟用", "Voice could not be started.": "無法啟動語音。", - "the active voice session": "目前語音工作階段", + "the active voice session": "當前語音會話", "{value} feet": "{value} 英尺", "The flights layer is not enabled": "航班圖層未開啟", "The military layer is not enabled": "軍用航班圖層未開啟", "The satellites layer is not enabled": "衛星圖層未開啟", - "The ais-live-vessels layer is not enabled": "即時 AIS 船舶圖層未開啟", + "The ais-live-vessels layer is not enabled": "實時 AIS 船舶圖層未開啟", "Could not enable the requested layer": "無法開啟所請求的圖層", "Could not disable the requested layer": "無法關閉所請求的圖層", - "Radio layer unavailable": "電台圖層不可用", - "Camera navigation is unavailable in the current view": "目前檢視下無法進行相機導航", + "Radio layer unavailable": "電臺圖層不可用", + "Camera navigation is unavailable in the current view": "當前視圖下無法進行相機導航", "Camera navigation policy unavailable": "相機導航策略不可用", - "Nearest-aircraft selection supports Flights or Military Flights only": "最近飛機選擇僅支援航班或軍用航班", + "Nearest-aircraft selection supports Flights or Military Flights only": "最近飛機選擇僅支持航班或軍用航班", "Nearest-aircraft selection needs a preset, place name, or latitude and longitude": "最近飛機選擇需要預設、地名或經緯度", "Could not arrive at the requested place": "無法抵達所請求的地點", "The nearest airborne aircraft could not be selected": "無法選中最近的空中飛機", - "No flights within {radius} of the current view": "目前視野 {radius} 範圍內沒有航班", - "No military within {radius} of the current view": "目前視野 {radius} 範圍內沒有軍用航班", - "No satellites within {radius} of the current view": "目前視野 {radius} 範圍內沒有衛星", - "No vessels within {radius} of the current view": "目前視野 {radius} 範圍內沒有船舶", - "{layer} is enabled on the {source} feed, but no airborne aircraft is loaded in the {place} view yet": "{layer} 已在 {source} 資料來源上開啟,但 {place} 視野中尚未載入空中飛機", - "{layer} is enabled, but no airborne aircraft is loaded in the {place} view yet": "{layer} 已開啟,但 {place} 視野中尚未載入空中飛機", - "{layer} is enabled, but its aircraft feed is unavailable": "{layer} 已開啟,但其飛機資料來源不可用", - "{layer} is enabled, but its destination refresh did not complete": "{layer} 已開啟,但目的地重新整理未完成", + "No flights within {radius} of the current view": "當前視野 {radius} 範圍內沒有航班", + "No military within {radius} of the current view": "當前視野 {radius} 範圍內沒有軍用航班", + "No satellites within {radius} of the current view": "當前視野 {radius} 範圍內沒有衛星", + "No vessels within {radius} of the current view": "當前視野 {radius} 範圍內沒有船舶", + "{layer} is enabled on the {source} feed, but no airborne aircraft is loaded in the {place} view yet": "{layer} 已在 {source} 數據源上開啟,但 {place} 視野中尚未加載空中飛機", + "{layer} is enabled, but no airborne aircraft is loaded in the {place} view yet": "{layer} 已開啟,但 {place} 視野中尚未加載空中飛機", + "{layer} is enabled, but its aircraft feed is unavailable": "{layer} 已開啟,但其飛機數據源不可用", + "{layer} is enabled, but its destination refresh did not complete": "{layer} 已開啟,但目的地刷新未完成", "{layer} is enabled, but {source} is unavailable": "{layer} 已開啟,但 {source} 不可用", "Could not arrive at {place}": "無法抵達 {place}", - "{name} is no longer loaded": "{name} 已不在載入資料中", + "{name} is no longer loaded": "{name} 已不在加載數據中", "Unknown target layer: {target}": "未知的目標圖層:{target}", "nominal": "正常", "{label} on": "{label} 已開啟", @@ -2362,9 +2362,9 @@ "Layer": "圖層", "there": "那裡", "Camera range {range}": "相機距離 {range}", - "Within {radius} of the view": "目前視野 {radius} 範圍內", + "Within {radius} of the view": "當前視野 {radius} 範圍內", "Labels on": "標籤已開啟", - "Framing uses the nearest 80 loaded contacts": "調整視野時僅包含已載入的最近 80 個目標", + "Framing uses the nearest 80 loaded contacts": "調整視野時僅包含已加載的最近 80 個目標", "{distance} from {location}": "距 {location} {distance}", "Altitude {altitude}": "高度 {altitude}", "{origin} to {destination}": "{origin} 至 {destination}", @@ -2382,22 +2382,22 @@ "Frame military": "將軍用航班納入視野", "Frame vessels": "將船舶納入視野", "Frame {target}": "將 {target} 納入視野", - "Zoom out to globe": "縮小至地球檢視", - "Open data layers": "開啟資料圖層", - "Open or close a panel": "開啟或關閉面板", + "Zoom out to globe": "縮小至地球視圖", + "Open data layers": "打開數據圖層", + "Open or close a panel": "打開或關閉面板", "Change context mode": "切換態勢模式", - "Control cockpit": "控制駕駛艙", + "Control cockpit": "控制座艙", "Change visual style": "切換視覺樣式", "Adjust HUD": "調整 HUD", - "Adjust cyber sonar": "調整賽博聲納", - "Adjust detection overlay": "調整偵測疊加層", + "Adjust cyber sonar": "調整賽博聲吶", + "Adjust detection overlay": "調整探測疊加層", "Change map stack": "切換地圖組合", "Adjust post-processing": "調整後期處理", "Control scene": "控制場景", "Control CCTV": "控制 CCTV", - "Control radio": "控制電台", - "Track contact": "追蹤目標", - "Stop tracking": "停止追蹤", + "Control radio": "控制電臺", + "Track contact": "跟蹤目標", + "Stop tracking": "停止跟蹤", "Clear marks": "清除標註", "Move camera": "移動相機", "Fly route": "沿路線飛行", @@ -2415,15 +2415,15 @@ "Layer off": "圖層已關閉", "Zoom out": "縮小", "Zoom in": "放大", - "Read the view": "播報目前視野", + "Read the view": "播報當前視野", "Check view state": "檢查視野狀態", "Action": "操作", - "Finding places": "正在查詢地點", + "Finding places": "正在查找地點", "Tracing outline": "正在繪製輪廓", "Looking up place": "正在查詢地點", "Flying": "飛行中", "Turning on layer": "正在開啟圖層", - "Loading aircraft": "正在載入飛機", + "Loading aircraft": "正在加載飛機", "Picking nearest": "正在選取最近目標", "Working": "處理中", "in progress": "進行中", @@ -2436,273 +2436,273 @@ "WORKING": "處理中", "DONE": "完成", "HERE": "此處", - "Aircraft cockpit view": "飛機駕駛艙視角", + "Aircraft cockpit view": "飛機座艙視圖", "LEVEL": "水平", - "Estimated destination direction": "推估目的地方向", + "Estimated destination direction": "預估目的地方向", "DEST ---°": "目的地 ---°", "OPTICAL PLANE · 01": "光學平面 · 01", - "VISOR LOCK · ACTIVE": "護目鏡鎖定 · 啟用", - "GROUND SPEED · KTS": "地速 · 節", - "ALTITUDE · FT": "高度 · 英尺", + "VISOR LOCK · ACTIVE": "面罩鎖定 · 激活", + "GROUND SPEED · KTS": "地速 · kn", + "ALTITUDE · FT": "高度 · ft", "FIRST PERSON": "第一人稱", - "LIVE TRACK · COURSE ALIGNED": "即時追蹤 · 航向對齊", - "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": "下一個視覺風格", - "Current aircraft heading": "目前飛機航向", + "LIVE TRACK · COURSE ALIGNED": "實時航跡 · 航向對準", + "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": "下一個視覺樣式", + "Current aircraft heading": "飛機當前航向", "GROUND SPEED": "地速", "KTS": "kn", "ALTITUDE": "高度", "FT": "ft", - "Contact cockpit summary": "目標駕駛艙摘要", + "Contact cockpit summary": "目標座艙摘要", "CONTACT": "目標", - "CONTACTS · 250 KM": "目標 · 250 公里", - "Contact navigation": "目標導覽", - "CONTEXT ONLY": "僅供態勢參考", - "Nearby cohort counts": "周邊目標數量", + "CONTACTS · 250 KM": "目標 · 250 km", + "Contact navigation": "目標導航", + "CONTEXT ONLY": "僅供參考", + "Nearby cohort counts": "附近各類目標數量", "FLT": "航班", "MIL": "軍用", "SITE": "設施", - "NEAREST OBSERVED / MAPPED": "最近的觀測/標記目標", - "AVAILABLE INPUTS ONLY · NOT AN ALL-CLEAR": "僅依現有資料 · 不代表安全無虞", + "NEAREST OBSERVED / MAPPED": "最近的觀測 / 地圖標註目標", + "AVAILABLE INPUTS ONLY · NOT AN ALL-CLEAR": "僅限可用輸入 · 不代表安全無虞", "WX": "天氣", - "Cockpit briefing carousel": "駕駛艙簡報輪播", - "Estimated flight plan": "推估飛行計畫", - "ESTIMATED FLIGHT PLAN": "推估飛行計畫", + "Cockpit briefing carousel": "座艙簡報輪播", + "Estimated flight plan": "預估飛行計劃", + "ESTIMATED FLIGHT PLAN": "預估飛行計劃", "FROM": "出發", - "TO": "目的地", - "Cockpit briefing controls": "駕駛艙簡報控制", + "TO": "到達", + "Cockpit briefing controls": "座艙簡報控件", "Previous briefing page": "簡報上一頁", "Next briefing page": "簡報下一頁", - "Live signals": "即時訊號", - "Latest regional news": "最新區域新聞", - "Location-based information": "在地資訊", - "TEMP": "溫度", + "Live signals": "實時信號", + "Latest regional news": "最新地區新聞", + "Location-based information": "基於位置的信息", + "TEMP": "氣溫", "WIND": "風", "SKY": "天空", "PRECIP": "降水", "MM": "mm", - "Weather data by Open-Meteo.com": "天氣資料來自 Open-Meteo.com", - "Cockpit briefing pages": "駕駛艙簡報頁", - "SIG": "訊號", - "Show Live Signals": "顯示即時訊號", + "Weather data by Open-Meteo.com": "天氣數據由 Open-Meteo.com 提供", + "Cockpit briefing pages": "座艙簡報頁面", + "SIG": "信號", + "Show Live Signals": "顯示實時信號", "NEWS": "新聞", - "Show Regional News": "顯示區域新聞", - "LOCAL": "在地", - "Show Local Info": "顯示在地資訊", - "Cockpit display and Radio controls": "駕駛艙顯示與廣播控制", + "Show Regional News": "顯示地區新聞", + "LOCAL": "本地", + "Show Local Info": "顯示本地信息", + "Cockpit display and Radio controls": "座艙顯示與電臺控件", "DISPLAY": "顯示", - "Cockpit display options": "駕駛艙顯示選項", - "RADIO": "廣播", - "Cockpit compact Radio controls": "駕駛艙精簡廣播控制", - "Previous filtered radio station": "上一個篩選電台", - "Play selected radio station": "播放所選電台", - "Next filtered radio station": "下一個篩選電台", + "Cockpit display options": "座艙顯示選項", + "RADIO": "電臺", + "Cockpit compact Radio controls": "座艙精簡電臺控件", + "Previous filtered radio station": "上一個已篩選電臺", + "Play selected radio station": "播放所選電臺", + "Next filtered radio station": "下一個已篩選電臺", "VOLUME": "音量", - "Cockpit Radio volume": "駕駛艙廣播音量", - "ESC EXIT": "ESC 離開", + "Cockpit Radio volume": "座艙電臺音量", + "ESC EXIT": "ESC 退出", "C TOGGLE": "C 切換", - "View switcher": "視角切換", - "Exit cockpit and return to full globe view": "離開駕駛艙並回到完整地球視野", - "RESET": "重設", - "Exit cockpit view": "離開駕駛艙視角", - "EXIT COCKPIT": "離開駕駛艙", - "Navigation, voice, and visual preset controls": "導航、語音與視覺預設控制", + "View switcher": "視圖切換", + "Exit cockpit and return to full globe view": "退出座艙並返回完整地球視圖", + "RESET": "重置", + "Exit cockpit view": "退出座艙視圖", + "EXIT COCKPIT": "退出座艙", + "Navigation, voice, and visual preset controls": "導航、語音和視覺預設控件", "Expand Visual Presets": "展開視覺預設", - "Pin visual presets": "釘選視覺預設", - "Keep visual presets open": "保持視覺預設開啟", - "Show the globe without a visual filter.": "不套用任何視覺濾鏡顯示地球。", - "Emulate a green phosphor CRT with scanlines and screen curvature.": "模擬帶有掃描線與螢幕弧度的綠色磷光 CRT。", - "Simulate night-vision goggles with green intensification and a tube vignette.": "模擬綠色增光與鏡筒暗角的夜視鏡。", - "Simulate FLIR-style thermal contrast. Turn up Ironbow for color.": "模擬 FLIR 熱成像對比。調高 Ironbow 可顯示色彩。", - "Apply bright cel-shaded color and illustrated outlines.": "套用明亮的賽璐璐上色與插畫描邊。", - "Apply high-contrast monochrome film-noir grading.": "套用高對比黑色電影風格的黑白調色。", - "Add a cold, snowy whiteout treatment to the scene.": "為場景加上冰冷的白茫雪景效果。", - "MAP SOURCE": "地圖來源", - "Map source": "地圖來源", + "Pin visual presets": "固定視覺預設", + "Keep visual presets open": "保持視覺預設展開", + "Show the globe without a visual filter.": "顯示不帶視覺濾鏡的地球。", + "Emulate a green phosphor CRT with scanlines and screen curvature.": "模擬帶掃描線和屏幕弧度的綠色熒光 CRT。", + "Simulate night-vision goggles with green intensification and a tube vignette.": "模擬夜視儀,帶綠色增強和鏡筒暗角。", + "Simulate FLIR-style thermal contrast. Turn up Ironbow for color.": "模擬 FLIR 風格的熱成像對比。調高 Ironbow 可顯示色彩。", + "Apply bright cel-shaded color and illustrated outlines.": "應用明亮的賽璐珞色彩和插畫輪廓線。", + "Apply high-contrast monochrome film-noir grading.": "應用高對比度的黑白電影風格調色。", + "Add a cold, snowy whiteout treatment to the scene.": "為場景添加寒冷的暴雪白化效果。", + "MAP SOURCE": "地圖源", + "Map source": "地圖源", "Style": "樣式", - "Expand LOCATION": "展開地理位置面板", - "Collapse panel": "收合面板", - "Pin location tray": "釘選位置面板", - "Keep location tray open": "保持位置面板開啟", - "Search any location": "搜尋任何地點", - "Search location by name or coordinates": "依名稱或座標搜尋地點", - "Search any location...": "搜尋任何地點…", + "Expand LOCATION": "展開位置", + "Collapse panel": "收起面板", + "Pin location tray": "固定位置托盤", + "Keep location tray open": "保持位置托盤展開", + "Search any location": "搜索任意位置", + "Search location by name or coordinates": "按名稱或座標搜索位置", + "Search any location...": "搜索任意位置…", "WEATHER": "天氣", "Active weather products": "已啟用的天氣產品", "RECENT IMAGERY": "近期影像", "Imagery days in the box": "視野內的影像天數", "CONTEXT": "態勢", - "Compact Radio controls": "精簡廣播控制", - "Open detailed Radio controls": "開啟詳細廣播控制", - "Previous station": "上一個電台", - "Next station": "下一個電台", - "Compact Radio volume": "精簡廣播音量", + "Compact Radio controls": "精簡電臺控件", + "Open detailed Radio controls": "打開詳細電臺控件", + "Previous station": "上一個電臺", + "Next station": "下一個電臺", + "Compact Radio volume": "精簡電臺音量", "Expand panel": "展開面板", "Context mode": "態勢模式", "CONTACTS": "目標", - "Cycles the nearest contacts of whatever type you select — planes, vessels, installations. Satellites track independently.": "輪流切換所選類型的最近目標——飛機、船舶、設施。衛星獨立追蹤。", + "Cycles the nearest contacts of whatever type you select — planes, vessels, installations. Satellites track independently.": "循環切換你所選類型中最近的目標,包括飛機、船舶、設施。衛星獨立跟蹤。", "SPACE MISSIONS": "太空任務", "SELECT CONTEXT": "選擇態勢", - "Contact Context actions": "目標情境操作", - "COCKPIT": "駕駛艙", - "SEARCH NEARBY SITES": "搜尋附近設施", - "Reclassify tracked contact as TR-3B": "將追蹤目標重新分類為 TR-3B", + "Contact Context actions": "目標態勢操作", + "COCKPIT": "座艙", + "SEARCH NEARBY SITES": "搜索附近設施", + "Reclassify tracked contact as TR-3B": "將跟蹤目標重新歸類為 TR-3B", "CONTACTS CONTEXT OFF": "目標態勢已關閉", - "SELECT CONTACTS TO LOAD OBSERVED / MAPPED PROXIMITY": "選擇「目標」以載入觀測/標記的鄰近資訊", + "SELECT CONTACTS TO LOAD OBSERVED / MAPPED PROXIMITY": "選擇目標以加載觀測 / 地圖標註的鄰近信息", "Available Space Missions": "可用太空任務", "AVAILABLE MISSIONS": "可用任務", - "SELECT A MISSION TO INSPECT": "選擇要檢視的任務", - "LOADING 30-DAY MISSION INDEX": "載入 30 天任務索引", - "TAB PREVIEWS · ENTER / SPACE SELECTS": "TAB 預覽 · ENTER/空白鍵 選取", - "Internet radio and local SDR": "網路電台與本機 SDR", - "STATION TAG": "電台標籤", - "Filter stations by station tag": "依電台標籤篩選", + "SELECT A MISSION TO INSPECT": "選擇一項任務以查看", + "LOADING 30-DAY MISSION INDEX": "正在加載 30 天任務索引", + "TAB PREVIEWS · ENTER / SPACE SELECTS": "TAB 預覽 · ENTER / 空格鍵選擇", + "Internet radio and local SDR": "網絡電臺與本地 SDR", + "STATION TAG": "電臺標籤", + "Filter stations by station tag": "按電臺標籤篩選電臺", "All": "全部", - "Enable Radio, then choose a globe marker or use next.": "啟用廣播,再選擇地球上的標記或按「下一個」。", - "DRAG TO TUNE": "拖曳調頻", - "Tune available internet radio stations": "調諧可用網路電台", - "ALL · DRAG THE NEEDLE": "全部 · 拖曳指針", - "SNAPS TO AVAILABLE STATIONS": "自動對齊可用電台", - "Radio playback": "廣播播放", - "Previous filtered station": "上一個篩選電台", - "Play selected station": "播放所選電台", - "Next filtered station": "下一個篩選電台", + "Enable Radio, then choose a globe marker or use next.": "請先啟用電臺,然後選擇地球上的標註或使用“下一個”。", + "DRAG TO TUNE": "拖動調諧", + "Tune available internet radio stations": "調諧可用的網絡電臺", + "ALL · DRAG THE NEEDLE": "全部 · 拖動指針", + "SNAPS TO AVAILABLE STATIONS": "自動吸附到可用電臺", + "Radio playback": "電臺播放", + "Previous filtered station": "上一個已篩選電臺", + "Play selected station": "播放所選電臺", + "Next filtered station": "下一個已篩選電臺", "STOP": "停止", - "Stop radio playback": "停止廣播播放", - "Radio volume": "廣播音量", - "STATION SITE": "電台位置", + "Stop radio playback": "停止電臺播放", + "Radio volume": "電臺音量", + "STATION SITE": "電臺網站", "DIRECTORY: RADIO BROWSER": "目錄:RADIO BROWSER", - "Audio connects directly to the broadcaster after you press play. Your IP is visible to that broadcaster.": "按下播放後會直接連線到廣播電台,你的 IP 位址會被該電台看到。", - "Local RTL-SDR receiver": "本機 RTL-SDR 接收機", - "LOCAL RTL-SDR": "本機 RTL-SDR", - "Chrome/Edge · WebUSB · one local tuner shared by FM and the Local ADS-B layer.": "Chrome/Edge · WebUSB · 一個本機調諧器由 FM 與本機 ADS-B 圖層共享。", + "Audio connects directly to the broadcaster after you press play. Your IP is visible to that broadcaster.": "點擊播放後,音頻將直接連接到廣播方。廣播方可以看到你的 IP。", + "Local RTL-SDR receiver": "本地 RTL-SDR 接收機", + "LOCAL RTL-SDR": "本地 RTL-SDR", + "Chrome/Edge · WebUSB · one local tuner shared by FM and the Local ADS-B layer.": "Chrome/Edge · WebUSB · 一個本地調諧器由 FM 與本地 ADS-B 圖層共享。", "Use your location for faster ADS-B position decoding": "使用你的位置,加快 ADS-B 位置解碼", - "CHANGE DEVICE": "更換裝置", + "CHANGE DEVICE": "更換設備", "Choose a different RTL-SDR or receiver channel": "選擇其他 RTL-SDR 或接收通道", "RTL-SDR receiver mode": "RTL-SDR 接收模式", "GAIN": "增益", - "RTL-SDR tuner gain for the current mode": "目前模式下的 RTL-SDR 調諧器增益", + "RTL-SDR tuner gain for the current mode": "當前模式下的 RTL-SDR 調諧器增益", "AUTO": "自動", "MSG/S": "msg/s", - "HEARD": "已接收訊號", + "HEARD": "已接收信號", "POSITIONED": "已定位", "FM MHZ": "FM MHz", "TUNE": "調諧", - "Seek broadcast FM stations": "搜尋廣播 FM 電台", - "◀ SEEK": "◀ 搜台", - "SEEK ▶": "搜台 ▶", + "Seek broadcast FM stations": "搜索廣播 FM 電臺", + "◀ SEEK": "◀ 搜臺", + "SEEK ▶": "搜臺 ▶", "SDR VOL": "SDR 音量", - "Local SDR volume": "本機 SDR 音量", - "Intelligence HUD (H)": "情報抬頭顯示(H)", - "Layout": "版面", - "HUD layout": "HUD 版面", + "Local SDR volume": "本地 SDR 音量", + "Intelligence HUD (H)": "情報 HUD(H)", + "Layout": "佈局", + "HUD layout": "HUD 佈局", "Tactical": "戰術", "Operator": "操作員", - "Minimal": "極簡", + "Minimal": "精簡", "Cyber": "賽博", - "Sonar": "聲納", - "Cyber sonar contact scanner": "賽博聲納目標掃描器", + "Sonar": "聲吶", + "Cyber sonar contact scanner": "賽博聲吶目標掃描器", "Rings": "圈數", - "Sonar ring count": "聲納圈數", + "Sonar ring count": "聲吶圈數", "Range": "範圍", - "Sonar ring range": "聲納圈範圍", + "Sonar ring range": "聲吶圈範圍", "Power": "強度", - "Sonar intensity": "聲納強度", + "Sonar intensity": "聲吶強度", "Opacity": "不透明度", "Cyber contact and label opacity": "賽博目標與標籤不透明度", - "Minimum opacity for map dots, icons, models, brackets, and labels between sonar passes": "兩次聲納掃描之間地圖點、圖示、模型、括號標記與標籤的最低不透明度", + "Minimum opacity for map dots, icons, models, brackets, and labels between sonar passes": "兩次聲吶掃描之間地圖點、圖標、模型、括號標記與標籤的最低不透明度", "Sector": "扇區", - "Sonar sector width": "聲納扇區寬度", - "Detection Overlay (D)": "偵測疊加(D)", - "Detection overlay": "偵測疊加", - "Detection label density": "偵測標籤密度", + "Sonar sector width": "聲吶扇區寬度", + "Detection Overlay (D)": "探測疊加層(D)", + "Detection overlay": "探測疊加層", + "Detection label density": "探測標籤密度", "Allocation": "分配", - "Detection label allocation": "偵測標籤分配", + "Detection label allocation": "探測標籤分配方式", "Elastic": "彈性", "Weighted": "加權", - "Fade": "淡出", - "Detection fade distance": "偵測淡出距離", - "World-overlay fade distance outside the keyhole as a percentage of its radius": "瞄準孔外世界疊加層的淡出距離(半徑百分比)", - "Outside": "外圍", - "Detection opacity outside the keyhole": "瞄準孔外的偵測不透明度", - "World-overlay label and card opacity beyond the fade distance": "超過淡出距離後世界疊加標籤與卡片的不透明度", + "Fade": "漸隱", + "Detection fade distance": "探測漸隱距離", + "World-overlay fade distance outside the keyhole as a percentage of its radius": "視域之外的世界疊加層漸隱距離,以其半徑的百分比表示", + "Outside": "外部", + "Detection opacity outside the keyhole": "視域之外的探測不透明度", + "World-overlay label and card opacity beyond the fade distance": "超出漸隱距離後世界疊加層標籤和卡片的不透明度", "PARAMETERS": "參數", - "3D aircraft — flat icons zoomed out, 3D models up close": "3D 飛機——拉遠為平面圖示,拉近為 3D 模型", + "3D aircraft — flat icons zoomed out, 3D models up close": "3D 飛機——拉遠顯示平面圖標,拉近顯示 3D 模型", "Models": "模型", - "3D model coverage": "3D 模型範圍", - "Proximity": "鄰近", - "Scope — the circular viewport mask": "視域——圓形檢視範圍遮罩", + "3D model coverage": "3D 模型覆蓋範圍", + "Proximity": "近處", + "Scope — the circular viewport mask": "視域——圓形視口遮罩", "Scope": "視域", "Feather": "羽化", "Scope edge feather": "視域邊緣羽化", - "Scope edge feather as a percentage of the keyhole radius": "視域邊緣羽化(瞄準孔半徑百分比)", - "Draw on the world — click vertices, double-click or Enter to finish, Esc to cancel": "在世界上繪圖——點選頂點,按兩下或 Enter 完成,Esc 取消", + "Scope edge feather as a percentage of the keyhole radius": "視域邊緣羽化,以視域半徑的百分比表示", + "Draw on the world — click vertices, double-click or Enter to finish, Esc to cancel": "在地球上繪製——單擊放置頂點,雙擊或按 Enter 完成,按 Esc 取消", "Shape": "形狀", "Shape to draw": "要繪製的形狀", - "Area": "區域", + "Area": "面", "Line": "線", "Pin": "圖釘", - "Label (optional)": "標籤(選填)", + "Label (optional)": "標籤(可選)", "Label for the drawn shape": "繪製形狀的標籤", "Colour of the drawn shape": "繪製形狀的顏色", - "Primary": "主色", - "Amber": "琥珀", - "Cyan": "青", - "Green": "綠", - "Red": "紅", + "Primary": "主題色", + "Amber": "琥珀色", + "Cyan": "青色", + "Green": "綠色", + "Red": "紅色", "Clear": "清除", - "Remove every mark from the board": "清除畫板上所有標記", - "Show your own GeoJSON, KML, KMZ or GPX files on the globe (or drop them onto it). File bytes stay on this device; overlays can appear in map screenshots shared with voice.": "在地球上顯示自己的 GeoJSON、KML、KMZ 或 GPX 檔案(也可直接拖放到地球上)。檔案內容僅保留在本裝置上;疊加層可能出現在隨語音分享的地圖截圖中。", - "Import": "匯入", - "Choose GeoJSON, KML, KMZ or GPX files": "選擇 GeoJSON、KML、KMZ 或 GPX 檔案", - "Imported files": "已匯入的檔案", - "Celestial": "天球環", - "Hide UI chrome": "隱藏介面框架", - "Clean UI": "簡潔介面", - "Bloom / Glow": "光暈/輝光", - "Bloom intensity": "光暈強度", - "Sharpening": "銳利化", - "Sharpen": "銳利化", - "Sharpen intensity": "銳利化強度", - "EXIT CLEAN VIEW": "離開簡潔檢視", - "Return UI controls": "恢復介面控制項", - "Initializing photorealistic world...": "正在初始化擬真世界…", - "DATA LAYERS": "資料圖層", - "ACQUIRING FRAME": "擷取畫面中", + "Remove every mark from the board": "清除畫板上的所有標註", + "Show your own GeoJSON, KML, KMZ or GPX files on the globe (or drop them onto it). File bytes stay on this device; overlays can appear in map screenshots shared with voice.": "在地球上顯示自己的 GeoJSON、KML、KMZ 或 GPX 文件(也可直接拖放到地球上)。文件內容僅保留在本設備上;疊加層可能出現在隨語音分享的地圖截圖中。", + "Import": "導入", + "Choose GeoJSON, KML, KMZ or GPX files": "選擇 GeoJSON、KML、KMZ 或 GPX 文件", + "Imported files": "已導入的文件", + "Celestial": "天球", + "Hide UI chrome": "隱藏界面控件", + "Clean UI": "純淨界面", + "Bloom / Glow": "泛光 / 輝光", + "Bloom intensity": "泛光強度", + "Sharpening": "銳化", + "Sharpen": "銳化", + "Sharpen intensity": "銳化強度", + "EXIT CLEAN VIEW": "退出純淨界面", + "Return UI controls": "恢復界面控件", + "Initializing photorealistic world...": "正在初始化照片級逼真世界…", + "DATA LAYERS": "數據圖層", + "ACQUIRING FRAME": "正在獲取畫面", "NEAREST": "最近", - "CCTV camera": "監視器攝影機", - "CALIBRATION": "校正", - "Drag the camera in the world: rings rotate, arrows move, handles set range/FOV": "在世界中拖曳攝影機:圓環旋轉、箭頭移動、把手調整距離/視角", - "Camera pose — click a value to type": "攝影機姿態——點選數值即可輸入", - "Heading (compass °) — click to type": "方位角(羅盤 °)——點選輸入", - "Pitch (° up/down) — click to type": "俯仰角(° 上/下)——點選輸入", - "Horizontal FOV (°) — click to type": "水平視角(°)——點選輸入", - "Range / monitor-plane distance (m) — click to type": "距離 / 螢幕平面距離(公尺)——點選輸入", - "Mount height above ground (m) — click to type": "架設離地高度(公尺)——點選輸入", - "North offset from catalog position (m) — click to type": "相對目錄位置的北向偏移(公尺)——點選輸入", - "East offset from catalog position (m) — click to type": "相對目錄位置的東向偏移(公尺)——點選輸入", - "SAVE CAL": "儲存校正", - "RESET CAL": "重設校正", + "CCTV camera": "CCTV 攝像頭", + "CALIBRATION": "校準", + "Drag the camera in the world: rings rotate, arrows move, handles set range/FOV": "在世界中拖動攝像頭:圓環旋轉,箭頭平移,控制點設置範圍/FOV", + "Camera pose — click a value to type": "攝像頭位姿——點擊數值可輸入", + "Heading (compass °) — click to type": "航向(羅盤 °)——點擊輸入", + "Pitch (° up/down) — click to type": "俯仰(° 上/下)——點擊輸入", + "Horizontal FOV (°) — click to type": "水平 FOV(°)——點擊輸入", + "Range / monitor-plane distance (m) — click to type": "範圍 / 監視器平面距離(m)——點擊輸入", + "Mount height above ground (m) — click to type": "安裝高度(距地面,m)——點擊輸入", + "North offset from catalog position (m) — click to type": "相對目錄位置的北向偏移(m)——點擊輸入", + "East offset from catalog position (m) — click to type": "相對目錄位置的東向偏移(m)——點擊輸入", + "SAVE CAL": "保存校準", + "RESET CAL": "重置校準", "SCENE SUMMARY": "場景摘要", "STREET LEVEL": "街景", "Turn Street Level on or off": "開啟或關閉街景", - "Image fit": "圖像縮放方式", - "FIT": "完整顯示", - "Fit: show the whole photo, with dark bars where its shape differs from the frame": "完整顯示:顯示整張照片,在比例與畫框不符處留黑邊", - "FILL": "填滿", - "Fill: fill the frame edge to edge, cropping the photo": "填滿:圖像鋪滿畫框並裁剪照片", + "Image fit": "圖像適配", + "FIT": "適應", + "Fit: show the whole photo, with dark bars where its shape differs from the frame": "適應:顯示整張照片,在比例與畫框不符處留黑邊", + "FILL": "填充", + "Fill: fill the frame edge to edge, cropping the photo": "填充:圖像鋪滿畫框並裁剪照片", "Close the image and deselect it on the map": "關閉圖像並取消其在地圖上的選中狀態", "Close the street-level image": "關閉街景圖像", - "Street-level viewer": "街景檢視器", - "Open this image on the provider's site": "在服務供應商網站上開啟此圖像", - "Imagery providers": "影像服務供應商", - "PROVIDERS": "服務供應商", + "Street-level viewer": "街景查看器", + "Open this image on the provider's site": "在服務商網站上打開此圖像", + "Imagery providers": "影像服務商", + "PROVIDERS": "服務商", "Imagery filters": "影像篩選", "IMAGERY": "影像", "Panorama filter": "全景篩選", @@ -2710,108 +2710,108 @@ "FLAT": "平面", "SINCE": "起始時間", "SCENES": "場景", - "Scene recipe": "場景配方", - "NEW": "新增", - "CAPTURE SHOT": "擷取鏡頭", + "Scene recipe": "場景方案", + "NEW": "新建", + "CAPTURE SHOT": "保存鏡頭", "UPDATE SHOT": "更新鏡頭", - "START": "開始", - "EXPORT PRESETS": "匯出預設", - "IMPORT": "匯入", - "RUN LOG": "執行紀錄", - "POWER UP": "強化功能", - "GROUND STATION · PROVIDER SETTINGS": "地面站 · 服務供應商設定", - "Close key setup": "關閉金鑰設定", - "Power up the globe": "強化你的地球", - "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.": "不需任何金鑰,地球就能運作。下方每一組金鑰都會開啟另一個真實資料來源——貼上後會存入本機設定,伺服器隨即自動重新啟動。伺服器端金鑰只留在本機;Google Maps 與 Cesium ion 在瀏覽器中執行,務必在供應商端設定使用限制。在其他地方設定的金鑰只會顯示,不會被修改。", - "SAVE KEYS": "儲存金鑰", - "ESC to close": "ESC 關閉", - "The Google Maps key buys the photorealistic planet — everything else stacks on top.": "Google Maps 金鑰帶來擬真地球——其他功能都疊加在它之上。", - "NO PLACE LEFT BEHIND": "無處遁形", - "ACTIVE STYLE": "目前風格", + "START": "啟動", + "EXPORT PRESETS": "導出預設", + "IMPORT": "導入", + "RUN LOG": "運行日誌", + "POWER UP": "增強", + "GROUND STATION · PROVIDER SETTINGS": "地面站 · 服務商設置", + "Close key setup": "關閉密鑰設置", + "Power up the globe": "增強地球", + "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.": "地球無需密鑰即可運行。下面的每個密鑰都會啟用一個新的真實數據源:粘貼後會保存到本應用的本地配置,隨後服務器自動重啟。服務端密鑰只保存在本機;Google Maps 和 Cesium ion 在瀏覽器中運行,必須設置服務商限制。你在其他位置配置的密鑰會顯示,但不會被改動。", + "SAVE KEYS": "保存密鑰", + "ESC to close": "按 ESC 關閉", + "The Google Maps key buys the photorealistic planet — everything else stacks on top.": "Google Maps 密鑰提供照片級逼真 3D 地球,其餘數據源都疊加在其上。", + "NO PLACE LEFT BEHIND": "不遺漏任何地方", + "ACTIVE STYLE": "當前樣式", "Globe actions": "地球操作", - "Turn off all selected data layers": "關閉所有已選資料圖層", - "Copy share link": "複製分享連結", - "Toggle straight-down and tilted map views": "切換俯視/傾斜地圖視角", - "Reset map to north up": "地圖重設為北方朝上", - "Reset map bearing to north": "重設地圖方位為正北", - "Reset camera and return to full globe view": "重設鏡頭並回到完整地球視野", + "Turn off all selected data layers": "關閉所有已選數據圖層", + "Copy share link": "複製分享鏈接", + "Toggle straight-down and tilted map views": "在垂直俯視與傾斜視角之間切換", + "Reset map to north up": "將地圖重置為正北朝上", + "Reset map bearing to north": "重置地圖方位為正北", + "Reset camera and return to full globe view": "重置相機並返回完整地球視圖", "MISSION CONTROL · FIRST LAUNCH": "任務控制 · 首次啟動", - "Choose your first view": "選擇你的第一個視角", - "LIVE CONTACTS": "即時目標", - "Aircraft, vessels and nearby intelligence": "飛機、船舶與周邊情資", - "Launches, spacecraft and orbital context": "發射、太空載具與軌道資訊", - "EXPLORE MANUALLY": "自由探索", - "Begin with a clean globe": "從乾淨的地球開始", + "Choose your first view": "選擇初始視圖", + "LIVE CONTACTS": "實時目標", + "Aircraft, vessels and nearby intelligence": "飛機、船舶及周邊情報", + "Launches, spacecraft and orbital context": "發射、航天器與軌道態勢", + "EXPLORE MANUALLY": "手動探索", + "Begin with a clean globe": "從空白地球開始", "Don't show this again": "不再顯示", - "ESC to dismiss": "ESC 關閉", - "Tip: the GEV MIC button in the dock lets you talk to the map.": "提示:按下底部的 GEV 麥克風按鈕,就能用語音操控地圖。", + "ESC to dismiss": "按 ESC 關閉", + "Tip: the GEV MIC button in the dock lets you talk to the map.": "提示:可通過停靠欄中的 GEV 麥克風按鈕用語音操控地圖。", "hemisphere|N": "N", "hemisphere|S": "S", "hemisphere|E": "E", "hemisphere|W": "W", "Gemini Live voice control": "Gemini Live 語音控制", - "Zoom in to see street-level coverage": "放大地圖以檢視街景覆蓋範圍", - "Point the camera at the ground for street-level coverage": "將相機朝向地面以檢視街景覆蓋範圍", + "Zoom in to see street-level coverage": "放大地圖以查看街景覆蓋範圍", + "Point the camera at the ground for street-level coverage": "將相機朝向地面以查看街景覆蓋範圍", "Sequence images unavailable": "序列影像不可用", - "Switch Street Level on to draw its coverage.": "開啟「街景」以繪製其覆蓋範圍。", - "Every provider is switched off: light a chip to draw its coverage.": "所有服務供應商均已關閉:點亮一個標籤即可繪製其覆蓋範圍。", + "Switch Street Level on to draw its coverage.": "開啟“街景”以繪製其覆蓋範圍。", + "Every provider is switched off: light a chip to draw its coverage.": "所有服務商均已關閉:點亮一個標籤即可繪製其覆蓋範圍。", "No sequences in view match the filter": "視野內沒有符合篩選條件的序列", "No coverage in view": "視野內無覆蓋範圍", - "Voice provider": "語音服務供應商", - "Changing provider reconnects voice if it is on.": "如語音已開啟,切換服務供應商會重新連線語音。", - "Gemini returned an oversized audio chunk": "Gemini 傳回的音訊區塊過大", - "Gemini returned an unsupported audio format": "Gemini 返回了不支援的音訊格式", - "Gemini returned an invalid audio sample rate": "Gemini 返回了無效的音訊取樣率", - "Gemini returned incomplete PCM audio": "Gemini 返回的 PCM 音訊不完整", - "This browser does not support Gemini microphone audio": "目前瀏覽器不支援 Gemini 麥克風音訊", - "Microphone audio processing failed": "麥克風音訊處理失敗", - "Gemini audio playback fell behind. Reconnect to continue.": "Gemini 音訊播放滯後。請重新連線以繼續。", - "Gemini token response did not include an ephemeral credential": "Gemini 權杖回應中沒有臨時憑據", - "Invalid Gemini connection endpoint": "Gemini 連線端點無效", - "Gemini voice could not connect. Try again.": "Gemini 語音無法連線。請重試。", - "Gemini voice requires a same-origin app request": "Gemini 語音需要與本應用程式同源的請求", - "Add a Gemini API key in Provider Settings": "請在服務供應商設定中新增 Gemini API 金鑰", + "Voice provider": "語音服務商", + "Changing provider reconnects voice if it is on.": "如語音已開啟,切換服務商會重新連接語音。", + "Gemini returned an oversized audio chunk": "Gemini 返回的音頻塊過大", + "Gemini returned an unsupported audio format": "Gemini 返回了不支持的音頻格式", + "Gemini returned an invalid audio sample rate": "Gemini 返回了無效的音頻採樣率", + "Gemini returned incomplete PCM audio": "Gemini 返回的 PCM 音頻不完整", + "This browser does not support Gemini microphone audio": "當前瀏覽器不支持 Gemini 麥克風音頻", + "Microphone audio processing failed": "麥克風音頻處理失敗", + "Gemini audio playback fell behind. Reconnect to continue.": "Gemini 音頻播放滯後。請重新連接以繼續。", + "Gemini token response did not include an ephemeral credential": "Gemini 令牌響應中沒有臨時憑據", + "Invalid Gemini connection endpoint": "Gemini 連接端點無效", + "Gemini voice could not connect. Try again.": "Gemini 語音無法連接。請重試。", + "Gemini voice requires a same-origin app request": "Gemini 語音需要與本應用同源的請求", + "Add a Gemini API key in Provider Settings": "請在服務商設置中添加 Gemini API 密鑰", "The Gemini Live model configuration is invalid": "Gemini Live 模型配置無效", "Gemini voice is starting too often. Try again shortly.": "Gemini 語音啟動過於頻繁。請稍後重試。", "Gemini quota is unavailable. Try again later.": "Gemini 配額不可用。請稍後重試。", - "Gemini access was refused. Check the API key and model access.": "Gemini 拒絕了訪問。請檢查 API 金鑰和模型訪問權限。", + "Gemini access was refused. Check the API key and model access.": "Gemini 拒絕了訪問。請檢查 API 密鑰和模型訪問權限。", "Gemini Live is unavailable for the configured model.": "所配置的模型無法使用 Gemini Live。", - "Token request is too large": "權杖請求過大", - "Use an empty JSON token request": "請使用空的 JSON 權杖請求", + "Token request is too large": "令牌請求過大", + "Use an empty JSON token request": "請使用空的 JSON 令牌請求", "Voice command context is too large": "語音命令上下文過大", - "Gemini reliable transport exceeded its queue limit. Start voice again.": "Gemini 可靠傳輸超出了佇列上限。請重新啟動語音。", - "Gemini reliable transport did not drain. Start voice again.": "Gemini 可靠傳輸的佇列未能清空。請重新啟動語音。", - "Gemini token request failed (HTTP {status})": "Gemini 權杖請求失敗(HTTP {status})", - "Gemini token response did not include a valid model": "Gemini 權杖回應中沒有有效的模型", - "Gemini token response did not include session settings": "Gemini 權杖回應中沒有工作階段設定", - "Gemini session settings do not match the input mode": "Gemini 工作階段設定與輸入模式不匹配", + "Gemini reliable transport exceeded its queue limit. Start voice again.": "Gemini 可靠傳輸超出了隊列上限。請重新啟動語音。", + "Gemini reliable transport did not drain. Start voice again.": "Gemini 可靠傳輸的隊列未能清空。請重新啟動語音。", + "Gemini token request failed (HTTP {status})": "Gemini 令牌請求失敗(HTTP {status})", + "Gemini token response did not include a valid model": "Gemini 令牌響應中沒有有效的模型", + "Gemini token response did not include session settings": "Gemini 令牌響應中沒有會話設置", + "Gemini session settings do not match the input mode": "Gemini 會話設置與輸入模式不匹配", "Gemini could not submit this input. Start voice again.": "Gemini 無法提交此輸入。請重新啟動語音。", - "Connecting to Gemini": "正在連線 Gemini", - "Gemini returned an oversized message": "Gemini 返回的訊息過大", - "Gemini Live connection failed. Check network access, then start voice again.": "Gemini Live 連線失敗。請檢查網路連線,然後重新啟動語音。", - "Gemini Live connection ended. Start voice again for a new conversation.": "Gemini Live 連線已結束。請重新啟動語音以開始新對話。", - "Gemini Live could not start. Start voice again to request a fresh session.": "Gemini Live 無法啟動。請重新啟動語音以申請新的工作階段。", - "Start voice again for a fresh token and a new conversation.": "請重新啟動語音,以取得新權杖並開始新對話。", - "Start voice again to request a fresh session credential.": "請重新啟動語音以申請新的工作階段憑據。", + "Connecting to Gemini": "正在連接 Gemini", + "Gemini returned an oversized message": "Gemini 返回的消息過大", + "Gemini Live connection failed. Check network access, then start voice again.": "Gemini Live 連接失敗。請檢查網絡連接,然後重新啟動語音。", + "Gemini Live connection ended. Start voice again for a new conversation.": "Gemini Live 連接已結束。請重新啟動語音以開始新對話。", + "Gemini Live could not start. Start voice again to request a fresh session.": "Gemini Live 無法啟動。請重新啟動語音以申請新的會話。", + "Start voice again for a fresh token and a new conversation.": "請重新啟動語音,以獲取新令牌並開始新對話。", + "Start voice again to request a fresh session credential.": "請重新啟動語音以申請新的會話憑據。", "Microphone permission was denied. Allow microphone access and try again.": "麥克風權限被拒絕。請允許訪問麥克風後重試。", - "Gemini connection timed out. Try again.": "Gemini 連線逾時。請重試。", + "Gemini connection timed out. Try again.": "Gemini 連接超時。請重試。", "Gemini voice could not start": "Gemini 語音無法啟動", "Gemini did not finish the interrupted reply. Start voice again.": "Gemini 未能完成被打斷的回覆。請重新啟動語音。", - "Gemini session expiring; finishing the current reply": "Gemini 工作階段即將到期,正在完成目前回覆", - "Gemini rejected the voice session. Start voice again to request a fresh session.": "Gemini 拒絕了語音工作階段。請重新啟動語音以申請新的工作階段。", - "Start voice again for a fresh session credential. If it repeats, check Gemini model and API access.": "請重新啟動語音以取得新的工作階段憑據。如問題重複出現,請檢查 Gemini 模型和 API 訪問權限。", - "Gemini action history is full. Start voice again for a fresh session.": "Gemini 操作歷史已滿。請重新啟動語音以開始新的工作階段。", + "Gemini session expiring; finishing the current reply": "Gemini 會話即將到期,正在完成當前回覆", + "Gemini rejected the voice session. Start voice again to request a fresh session.": "Gemini 拒絕了語音會話。請重新啟動語音以申請新的會話。", + "Start voice again for a fresh session credential. If it repeats, check Gemini model and API access.": "請重新啟動語音以獲取新的會話憑據。如問題重複出現,請檢查 Gemini 模型和 API 訪問權限。", + "Gemini action history is full. Start voice again for a fresh session.": "Gemini 操作歷史已滿。請重新啟動語音以開始新的會話。", "Gemini requested too many simultaneous actions": "Gemini 請求的同時操作過多", - "Voice text command is too long": "語音文字命令過長", - "Gemini voice is not connected": "Gemini 語音未連線", + "Voice text command is too long": "語音文本命令過長", + "Gemini voice is not connected": "Gemini 語音未連接", "Gemini interrupted input exceeded its buffer or wait limit. Start voice again.": "Gemini 被打斷的輸入超出了緩衝區或等待上限。請重新啟動語音。", - "Gemini Live connection is expiring. Start voice again for a new conversation.": "Gemini Live 連線即將到期。請重新啟動語音以開始新對話。", - "Gemini voice sessions have a time limit. When a session expires, start voice again for a new conversation.": "Gemini 語音工作階段有時長限制。工作階段到期後,請重新啟動語音以開始新對話。", - "Show the street-level view full screen (Esc shrinks it)": "全屏顯示街景檢視(按 Esc 縮小)", + "Gemini Live connection is expiring. Start voice again for a new conversation.": "Gemini Live 連接即將到期。請重新啟動語音以開始新對話。", + "Gemini voice sessions have a time limit. When a session expires, start voice again for a new conversation.": "Gemini 語音會話有時長限制。會話到期後,請重新啟動語音以開始新對話。", + "Show the street-level view full screen (Esc shrinks it)": "全屏顯示街景視圖(按 Esc 縮小)", "OK": "正常", "{category} ({count})": "{category}({count})", "Layers": "圖層", - "Search": "搜尋", + "Search": "搜索", "More": "更多", "Panels": "面板", "Post-tropical cyclone": "後熱帶氣旋", @@ -2819,49 +2819,49 @@ "Take the ramp {direction}": "{direction}駛入匝道", "Take the exit {direction} onto {road}": "從出口{direction}駛出,進入 {road}", "Take the exit {direction}": "從出口{direction}駛出", - "Link shared": "連結已分享", - "This share link can't be opened": "無法開啟此分享連結", - "{id} isn't reporting now — showing where it was at {time}": "{id} 目前未傳送訊號——顯示其在 {time} 的位置", - "{id} isn't reporting now — showing where it was last seen": "{id} 目前未傳送訊號——顯示其最後出現的位置", - "Shared vessel is unavailable": "無法取得分享的船舶", - "Check the spelling and press Enter to search again.": "請檢查拼字,然後按 Enter 重新搜尋。", - "Press Enter to try again.": "按 Enter 再試一次。", + "Link shared": "鏈接已分享", + "This share link can't be opened": "無法打開此分享鏈接", + "{id} isn't reporting now — showing where it was at {time}": "{id} 目前沒有發送信號——顯示其在 {time} 的位置", + "{id} isn't reporting now — showing where it was last seen": "{id} 目前沒有發送信號——顯示其最後出現的位置", + "Shared vessel is unavailable": "分享的船隻不可用", + "Check the spelling and press Enter to search again.": "請檢查拼寫,然後按 Enter 重新搜索。", + "Press Enter to try again.": "按 Enter 重試。", "Recent speech": "最近語音", - "Voice Settings": "語音設定", + "Voice Settings": "語音設置", "Preview": "預覽", - "Settings": "設定", + "Settings": "設置", "Close voice panel": "關閉語音面板", "Show Voice Preview": "顯示語音預覽", - "Voice inactivity timeout": "語音閒置逾時", - "Custom": "自訂", + "Voice inactivity timeout": "語音空閒超時", + "Custom": "自定義", "Minutes": "分鐘", - "These preferences stay in this browser.": "這些偏好設定僅儲存在此瀏覽器中。", - "Your choice applies now, but could not be saved.": "選擇已生效,但無法儲存。", - "Voice replies appear here.": "語音回覆會顯示在此處。", + "These preferences stay in this browser.": "這些偏好設置僅保存在此瀏覽器中。", + "Your choice applies now, but could not be saved.": "選擇已生效,但無法保存。", + "Voice replies appear here.": "語音回覆顯示在此處。", "Preview is off.": "預覽已關閉。", - "Automatic stop is unavailable for this voice connection.": "此語音連線不支援自動停止。", + "Automatic stop is unavailable for this voice connection.": "此語音連接不支持自動停止。", "S2 GhostMaps": "S2 GhostMaps", "Intel Picture": "情報態勢圖", "Kinetic 30d": "近 30 天軍事行動", "Border Crisis": "邊境危機", "Iran Picture": "伊朗態勢圖", "Iran Kinetic": "伊朗軍事行動", - "Yemen FLOT": "葉門前線", + "Yemen FLOT": "也門前線", "Latest Drop": "最新發布", - "GhostMaps file could not be read": "無法讀取 GhostMaps 檔案", - "GhostMaps catalog unavailable": "無法取得 GhostMaps 目錄", + "GhostMaps file could not be read": "無法讀取 GhostMaps 文件", + "GhostMaps catalog unavailable": "GhostMaps 目錄不可用", "Malformed GhostMaps catalog": "GhostMaps 目錄格式無效", "{count} source links ↗ · click card to open the first": { - "other": "{count} 個來源連結 ↗ · 點選卡片開啟第一個連結" + "other": "{count} 個來源鏈接 ↗ · 點擊卡片打開第一個" }, "S2 · {name}": "S2 · {name}", "Report": "報告", - "Open the source for {title}": "開啟 {title} 的來源", - "LIVE · GitHub {commit} · {message} · checked every {seconds}s": "即時 · GitHub {commit} · {message} · 每 {seconds} 秒檢查一次", - "GitHub {commit} · {message} · reconnecting for live updates": "GitHub {commit} · {message} · 正在重新連線以取得即時更新", - "Connecting to the S2 GhostMaps repository…": "正在連線至 S2 GhostMaps 儲存庫…", + "Open the source for {title}": "打開 {title} 的來源", + "LIVE · GitHub {commit} · {message} · checked every {seconds}s": "實時 · GitHub {commit} · {message} · 每 {seconds} 秒檢查一次", + "GitHub {commit} · {message} · reconnecting for live updates": "GitHub {commit} · {message} · 正在重新連接以獲取實時更新", + "Connecting to the S2 GhostMaps repository…": "正在連接 S2 GhostMaps 倉庫…", "{count} placemarks": { "other": "{count} 個地標" }, - "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 產品。新上傳的內容會在數秒內被偵測到,並自動取代舊版本。點選標記查看報告。" + "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 產品。新上傳的內容會在數秒內被檢測到,並自動替換舊版本。點擊標記查看報告。" } diff --git a/src/i18n/same-as-english.json b/src/i18n/same-as-english.json index 37e26399f..83c8897d8 100644 --- a/src/i18n/same-as-english.json +++ b/src/i18n/same-as-english.json @@ -225,9 +225,9 @@ "MM", "NVG", "REC", + "SRC {value}", "S2 GhostMaps", "S2 · {name}", - "SRC {value}", "Sentinel-2", "Techno", "Trance", diff --git a/src/i18n/zh-Hant-display.test.mjs b/src/i18n/zh-Hant-display.test.mjs index 187977cb3..c802c61c0 100644 --- a/src/i18n/zh-Hant-display.test.mjs +++ b/src/i18n/zh-Hant-display.test.mjs @@ -69,10 +69,10 @@ test('Traditional Chinese readouts preserve unit case, coordinates and natural r assert.equal(READOUT_WORDS.daysAgo(9), '9 天前'); assert.equal(READOUT_WORDS.daysAgo(0), '今天'); assert.equal(cctvSourceStatusLabel('ok'), '正常'); - assert.equal(t('SAVE KEYS'), '儲存金鑰'); + assert.equal(t('SAVE KEYS'), '保存密鑰'); assert.equal( tn(2, 'Click {count} more point.', 'Click {count} more points.'), - '再點選 2 個點。', + '再點擊 2 個點。', ); } finally { setLocale(previous); From 237684ba8636151d8148f72495fe30e7339ab6e0 Mon Sep 17 00:00:00 2001 From: Sameh Khamis Date: Tue, 27 Oct 2026 22:08:29 -0700 Subject: [PATCH 09/11] chore(release): prepare v0.3.0 --- CHANGELOG.md | 740 +++++++++++++++++- changelog.d/1056-area-tool-breakdowns.md | 12 - changelog.d/1057-windows-npm-dep0190.md | 4 - changelog.d/1066-keyless-google-token.md | 3 - changelog.d/1071-geo-uri-search.md | 3 - .../1094-dependency-security-patches.md | 4 - changelog.d/1096-military-hold-track-speed.md | 3 - .../1097-overpass-remark-failure-phrases.md | 5 - changelog.d/1101-tle-catalog-number-match.md | 3 - changelog.d/1111-map-fallback-retry.md | 5 - .../1115-aircraft-altitude-band-unknown.md | 2 - changelog.d/1117-google-viewer-lifecycle.md | 3 - .../1118-cctv-snapshot-fallback-provenance.md | 3 - .../1135-director-save-status-run-results.md | 5 - .../1142-antimeridian-fire-perimeters.md | 6 - changelog.d/1171-director-goto-shot.md | 3 - changelog.d/1172-cctv-missing-numbers.md | 13 - changelog.d/1173-antimeridian-ground-floor.md | 10 - .../1186-launch-unknown-coordinates.md | 4 - changelog.d/1190-bikeshare-spain-cities.md | 6 - .../1197-launch-library-provider-guidance.md | 5 - changelog.d/1199-launch-cache-provenance.md | 3 - changelog.d/1200-cctv-live-icon-color.md | 5 - changelog.d/1201-cctv-stills-aspect.md | 4 - changelog.d/1205-cctv-tool-routing.md | 3 - .../1207-voice-entity-labels-english.md | 3 - changelog.d/1220-openai-typed-send.md | 3 - changelog.d/1222-pinokio-open-in-browser.md | 3 - changelog.d/1225-globe-rotation.md | 2 - changelog.d/1226-first-run-touch-dismiss.md | 4 - changelog.d/1228-cctv-ontario-511-key.md | 4 - changelog.d/1229-opensky-oauth-only.md | 8 - changelog.d/1232-gbfs-invalid-coordinates.md | 3 - .../1233-tarktee-datex-catalog-hardening.md | 4 - .../1234-cctv-catalog-background-refresh.md | 5 - changelog.d/1235-location-resolution.md | 3 - changelog.d/1237-taiwan-freeway-cctv.md | 4 - changelog.d/1239-traffic-stale-flow.md | 3 - changelog.d/1243-starfield-sky.md | 5 - .../1244-terrain-test-cache-isolation.md | 4 - .../1264-overpass-request-admission.md | 9 - changelog.d/1265-docker-trusted-peers.md | 3 - changelog.d/1268-radio-issue-fix.md | 2 - changelog.d/1269-aircraft-issue-fix.md | 1 - changelog.d/1270-space-issue-fix.md | 1 - changelog.d/1271-share-issue-fix.md | 1 - changelog.d/1272-search-issue-fix.md | 1 - changelog.d/1273-history-issue-fix.md | 1 - changelog.d/1274-import-issue-fix.md | 1 - changelog.d/1275-forecast-issue-fix.md | 3 - changelog.d/1276-terrain-issue-fix.md | 1 - changelog.d/1278-overpass-issue-fix.md | 1 - changelog.d/1279-launch-issue-fix.md | 1 - changelog.d/1281-traffic-issue-fix.md | 8 - changelog.d/1282-polling-issue-fix.md | 7 - .../1283-satellite-cache-provenance.md | 3 - .../1284-route-plausibility-segment.md | 3 - changelog.d/1286-since-note-inline.md | 4 - changelog.d/1287-shared-sliders.md | 3 - changelog.d/1288-zoomfor-legacy-shape.md | 4 - changelog.d/1297-s2-ghostmaps-layer.md | 14 - changelog.d/1298-simplified-chinese.md | 4 - changelog.d/1299-voice-panel-settings.md | 5 - .../1301-shared-segmented-selectors.md | 5 - changelog.d/1302-shared-action-buttons.md | 3 - changelog.d/1303-wind-stale.md | 2 - changelog.d/1304-antimeridian-distances.md | 2 - changelog.d/1305-shared-native-form-fields.md | 3 - changelog.d/1306-shared-status-badges.md | 4 - .../1309-shared-field-css-ownership.md | 3 - .../1317-provider-response-hardening.md | 1 - changelog.d/1321-dead-code-cleanup.md | 6 - .../1324-street-level-provider-exports.md | 8 - changelog.d/1325-phone-layout.md | 4 - changelog.d/1326-terrain-cache-eviction.md | 3 - changelog.d/1338-mobile-contact-context.md | 4 - changelog.d/1339-hud-dms-carry.md | 3 - .../1340-search-separated-hemisphere.md | 3 - .../1341-kartaview-impossible-timestamps.md | 3 - .../1342-firms-acquisition-calendar.md | 3 - changelog.d/1343-route-ramp-lane-wording.md | 4 - changelog.d/1345-weather-staging-wake.md | 3 - .../1349-cyclone-classification-codes.md | 3 - changelog.d/1350-cyclone-movement-knots.md | 3 - changelog.d/1351-ais-static-keeps-motion.md | 6 - .../1352-cockpit-destination-heading.md | 3 - changelog.d/1353-transit-ninety-second-age.md | 3 - changelog.d/1354-firms-frp-ten-megawatts.md | 3 - ...1366-aircraft-models-no-environment-map.md | 5 - changelog.d/1367-turned-off-layer-memory.md | 4 - .../1378-touch-zoom-aircraft-updates.md | 5 - changelog.d/1379-aircraft-label-candidates.md | 4 - changelog.d/1384-hud-summary-moving.md | 4 - changelog.d/1385-route-duration-minute.md | 3 - changelog.d/1386-route-distance-kilometre.md | 3 - .../1387-awareness-distance-kilometre.md | 3 - changelog.d/1388-draw-line-kilometre.md | 3 - changelog.d/1389-cockpit-wind-north.md | 3 - changelog.d/1390-awareness-bearing-north.md | 2 - changelog.d/1391-docker-selinux.md | 4 - changelog.d/1394-docker-healthcheck.md | 2 - changelog.d/1395-fires-tool-acquired-time.md | 6 - changelog.d/1396-local-adsb-track-north.md | 3 - changelog.d/1398-sharpen-zero-off.md | 2 - changelog.d/1399-ground-snap-clock-step.md | 3 - changelog.d/1403-remove-unused-modules.md | 5 - .../1410-scope-controls-hud-readability.md | 8 - changelog.d/1416-share-hash-navigation.md | 4 - changelog.d/1417-clear-all-saved-layers.md | 3 - changelog.d/1418-short-share-links.md | 5 - changelog.d/1419-share-view-codec-export.md | 4 - .../1420-keep-missed-location-query.md | 4 - .../1421-style-modules-skip-catalogs.md | 3 - .../1431-street-level-bearing-north.md | 3 - .../287-shared-great-circle-distance.md | 5 - changelog.d/605-fl511-florida-cameras.md | 9 - changelog.d/686-terrain-heights-bounds.md | 9 - changelog.d/761-dev-unwatched-runtime-dirs.md | 5 - changelog.d/767-alpha5-catalog-numbers.md | 11 - changelog.d/787-changelog-fragments.md | 7 - changelog.d/816-radio-owner-restoration.md | 7 - changelog.d/872-gemini-live-voice.md | 4 - changelog.d/880-world-packet-boundary.md | 6 - .../945-cctv-vegvesen-kartverket-heights.md | 17 - changelog.d/948-vite-fs-deny.md | 4 - .../970-recent-imagery-details-scroll.md | 3 - changelog.d/973-tomtom-cross-site-gate.md | 4 - changelog.d/974-street-level-slim.md | 6 - changelog.d/975-terrain-cross-site-gate.md | 8 - changelog.d/990-hong-kong-cctv.md | 7 - package-lock.json | 4 +- package.json | 2 +- 132 files changed, 714 insertions(+), 586 deletions(-) delete mode 100644 changelog.d/1056-area-tool-breakdowns.md delete mode 100644 changelog.d/1057-windows-npm-dep0190.md delete mode 100644 changelog.d/1066-keyless-google-token.md delete mode 100644 changelog.d/1071-geo-uri-search.md delete mode 100644 changelog.d/1094-dependency-security-patches.md delete mode 100644 changelog.d/1096-military-hold-track-speed.md delete mode 100644 changelog.d/1097-overpass-remark-failure-phrases.md delete mode 100644 changelog.d/1101-tle-catalog-number-match.md delete mode 100644 changelog.d/1111-map-fallback-retry.md delete mode 100644 changelog.d/1115-aircraft-altitude-band-unknown.md delete mode 100644 changelog.d/1117-google-viewer-lifecycle.md delete mode 100644 changelog.d/1118-cctv-snapshot-fallback-provenance.md delete mode 100644 changelog.d/1135-director-save-status-run-results.md delete mode 100644 changelog.d/1142-antimeridian-fire-perimeters.md delete mode 100644 changelog.d/1171-director-goto-shot.md delete mode 100644 changelog.d/1172-cctv-missing-numbers.md delete mode 100644 changelog.d/1173-antimeridian-ground-floor.md delete mode 100644 changelog.d/1186-launch-unknown-coordinates.md delete mode 100644 changelog.d/1190-bikeshare-spain-cities.md delete mode 100644 changelog.d/1197-launch-library-provider-guidance.md delete mode 100644 changelog.d/1199-launch-cache-provenance.md delete mode 100644 changelog.d/1200-cctv-live-icon-color.md delete mode 100644 changelog.d/1201-cctv-stills-aspect.md delete mode 100644 changelog.d/1205-cctv-tool-routing.md delete mode 100644 changelog.d/1207-voice-entity-labels-english.md delete mode 100644 changelog.d/1220-openai-typed-send.md delete mode 100644 changelog.d/1222-pinokio-open-in-browser.md delete mode 100644 changelog.d/1225-globe-rotation.md delete mode 100644 changelog.d/1226-first-run-touch-dismiss.md delete mode 100644 changelog.d/1228-cctv-ontario-511-key.md delete mode 100644 changelog.d/1229-opensky-oauth-only.md delete mode 100644 changelog.d/1232-gbfs-invalid-coordinates.md delete mode 100644 changelog.d/1233-tarktee-datex-catalog-hardening.md delete mode 100644 changelog.d/1234-cctv-catalog-background-refresh.md delete mode 100644 changelog.d/1235-location-resolution.md delete mode 100644 changelog.d/1237-taiwan-freeway-cctv.md delete mode 100644 changelog.d/1239-traffic-stale-flow.md delete mode 100644 changelog.d/1243-starfield-sky.md delete mode 100644 changelog.d/1244-terrain-test-cache-isolation.md delete mode 100644 changelog.d/1264-overpass-request-admission.md delete mode 100644 changelog.d/1265-docker-trusted-peers.md delete mode 100644 changelog.d/1268-radio-issue-fix.md delete mode 100644 changelog.d/1269-aircraft-issue-fix.md delete mode 100644 changelog.d/1270-space-issue-fix.md delete mode 100644 changelog.d/1271-share-issue-fix.md delete mode 100644 changelog.d/1272-search-issue-fix.md delete mode 100644 changelog.d/1273-history-issue-fix.md delete mode 100644 changelog.d/1274-import-issue-fix.md delete mode 100644 changelog.d/1275-forecast-issue-fix.md delete mode 100644 changelog.d/1276-terrain-issue-fix.md delete mode 100644 changelog.d/1278-overpass-issue-fix.md delete mode 100644 changelog.d/1279-launch-issue-fix.md delete mode 100644 changelog.d/1281-traffic-issue-fix.md delete mode 100644 changelog.d/1282-polling-issue-fix.md delete mode 100644 changelog.d/1283-satellite-cache-provenance.md delete mode 100644 changelog.d/1284-route-plausibility-segment.md delete mode 100644 changelog.d/1286-since-note-inline.md delete mode 100644 changelog.d/1287-shared-sliders.md delete mode 100644 changelog.d/1288-zoomfor-legacy-shape.md delete mode 100644 changelog.d/1297-s2-ghostmaps-layer.md delete mode 100644 changelog.d/1298-simplified-chinese.md delete mode 100644 changelog.d/1299-voice-panel-settings.md delete mode 100644 changelog.d/1301-shared-segmented-selectors.md delete mode 100644 changelog.d/1302-shared-action-buttons.md delete mode 100644 changelog.d/1303-wind-stale.md delete mode 100644 changelog.d/1304-antimeridian-distances.md delete mode 100644 changelog.d/1305-shared-native-form-fields.md delete mode 100644 changelog.d/1306-shared-status-badges.md delete mode 100644 changelog.d/1309-shared-field-css-ownership.md delete mode 100644 changelog.d/1317-provider-response-hardening.md delete mode 100644 changelog.d/1321-dead-code-cleanup.md delete mode 100644 changelog.d/1324-street-level-provider-exports.md delete mode 100644 changelog.d/1325-phone-layout.md delete mode 100644 changelog.d/1326-terrain-cache-eviction.md delete mode 100644 changelog.d/1338-mobile-contact-context.md delete mode 100644 changelog.d/1339-hud-dms-carry.md delete mode 100644 changelog.d/1340-search-separated-hemisphere.md delete mode 100644 changelog.d/1341-kartaview-impossible-timestamps.md delete mode 100644 changelog.d/1342-firms-acquisition-calendar.md delete mode 100644 changelog.d/1343-route-ramp-lane-wording.md delete mode 100644 changelog.d/1345-weather-staging-wake.md delete mode 100644 changelog.d/1349-cyclone-classification-codes.md delete mode 100644 changelog.d/1350-cyclone-movement-knots.md delete mode 100644 changelog.d/1351-ais-static-keeps-motion.md delete mode 100644 changelog.d/1352-cockpit-destination-heading.md delete mode 100644 changelog.d/1353-transit-ninety-second-age.md delete mode 100644 changelog.d/1354-firms-frp-ten-megawatts.md delete mode 100644 changelog.d/1366-aircraft-models-no-environment-map.md delete mode 100644 changelog.d/1367-turned-off-layer-memory.md delete mode 100644 changelog.d/1378-touch-zoom-aircraft-updates.md delete mode 100644 changelog.d/1379-aircraft-label-candidates.md delete mode 100644 changelog.d/1384-hud-summary-moving.md delete mode 100644 changelog.d/1385-route-duration-minute.md delete mode 100644 changelog.d/1386-route-distance-kilometre.md delete mode 100644 changelog.d/1387-awareness-distance-kilometre.md delete mode 100644 changelog.d/1388-draw-line-kilometre.md delete mode 100644 changelog.d/1389-cockpit-wind-north.md delete mode 100644 changelog.d/1390-awareness-bearing-north.md delete mode 100644 changelog.d/1391-docker-selinux.md delete mode 100644 changelog.d/1394-docker-healthcheck.md delete mode 100644 changelog.d/1395-fires-tool-acquired-time.md delete mode 100644 changelog.d/1396-local-adsb-track-north.md delete mode 100644 changelog.d/1398-sharpen-zero-off.md delete mode 100644 changelog.d/1399-ground-snap-clock-step.md delete mode 100644 changelog.d/1403-remove-unused-modules.md delete mode 100644 changelog.d/1410-scope-controls-hud-readability.md delete mode 100644 changelog.d/1416-share-hash-navigation.md delete mode 100644 changelog.d/1417-clear-all-saved-layers.md delete mode 100644 changelog.d/1418-short-share-links.md delete mode 100644 changelog.d/1419-share-view-codec-export.md delete mode 100644 changelog.d/1420-keep-missed-location-query.md delete mode 100644 changelog.d/1421-style-modules-skip-catalogs.md delete mode 100644 changelog.d/1431-street-level-bearing-north.md delete mode 100644 changelog.d/287-shared-great-circle-distance.md delete mode 100644 changelog.d/605-fl511-florida-cameras.md delete mode 100644 changelog.d/686-terrain-heights-bounds.md delete mode 100644 changelog.d/761-dev-unwatched-runtime-dirs.md delete mode 100644 changelog.d/767-alpha5-catalog-numbers.md delete mode 100644 changelog.d/787-changelog-fragments.md delete mode 100644 changelog.d/816-radio-owner-restoration.md delete mode 100644 changelog.d/872-gemini-live-voice.md delete mode 100644 changelog.d/880-world-packet-boundary.md delete mode 100644 changelog.d/945-cctv-vegvesen-kartverket-heights.md delete mode 100644 changelog.d/948-vite-fs-deny.md delete mode 100644 changelog.d/970-recent-imagery-details-scroll.md delete mode 100644 changelog.d/973-tomtom-cross-site-gate.md delete mode 100644 changelog.d/974-street-level-slim.md delete mode 100644 changelog.d/975-terrain-cross-site-gate.md delete mode 100644 changelog.d/990-hong-kong-cctv.md diff --git a/CHANGELOG.md b/CHANGELOG.md index f5d3a4842..356289841 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,692 @@ # Changelog +## [Unreleased] + +## [0.3.0] — 2026-10-27 — Street Level, On Your Phone, in Your Language + +- Show a Street Level view facing 359.5° or more as 0°. The viewer caption + rounded the bearing without wrapping, so a view facing 359.6° read "360°" + (Aditya, @Rohilalala, #1431). + +- The visual styles and their presets mark their labels with the catalog-free + `msg()`, so the share-link codec, and any server that loads it, no longer + bundles every translation catalog (about 0.9 MB) (samehkhamis, #1421). + +- Keep a location search that found nothing, or failed, in the field so it can + be corrected: the query stays, focused and selected, and a persistent + announced message under the search row says what to do next, instead of a + toast followed by a cleared and closed field (samehkhamis, #1420). + +- Hosts can read share links on their server: the share-link codec and the + `/share/` address helpers are now package exports, + `@gods-eye-view/core/share/view-codec` and `@gods-eye-view/core/share/link-path` + (samehkhamis, #1419). + +- Share links are now short: the share button makes `/share/` links + that open on any copy of the app, follow the aircraft, military aircraft or + satellite you were following, and fall back to its last-known position with + a notice if it isn't reporting. A mistyped link is refused instead of + opening a different view. Long `#v=2` links keep working (samehkhamis, #1418). + +- Make Clear All clear the saved and shared layer selection. Layers that a + context mode had already switched off no longer stay in the share link and + come back on reload (samehkhamis, #1417). + +- Restore a share link opened in an already-open tab. Pasting a link into the + address bar, following one, or using Back/Forward now moves the camera and + restores the style, map, panels and layers instead of changing only the URL + (samehkhamis, #1416). + +- Add a Scope checkbox and extend feathering to 200%, retaining scope settings + across HUD layouts, share links and scenes. First run opens with Scope ON at + 100% feather; explicit settings and historical links retain their values. Give + Tactical, Operator and Minimal text black backplates only when Scope is OFF, + including vertical metadata, without changing the original HUD text color, glow or + opacity. Scope ON retains its original HUD presentation (bilawalsidhu, #1410). + Keep title and tagline positions stable when toggling Scope, include the eye + in the title backing, and brighten the two secondary labels only with Scope OFF. + +- Remove four modules nothing in the app imports: `src/app/sourceSlot.js`, + `src/data/flowTiles.js`, `src/data/issPass.js` and `src/data/localGeojson.js`. + The local GeoJSON layer tests now build layers the way the catalog does, so + they keep covering `localGeojsonCore.js`. Package exports are unchanged + (samehkhamis, #1403). + +- Aircraft on the ground keep getting ground-height samples after the + computer's clock steps back, instead of waiting for it to catch up + (quanticsoul4772, #1399). + +- The Sharpen slider at 0 now turns the sharpen pass off instead of still + sharpening at a low amount (quanticsoul4772, #1398). + +- Show a locally heard aircraft tracking 359.5° or more as TRK 0°. The Local + ADS-B card rounded the track without wrapping, so 359.7° read "TRK 360°" + (Rudy Celekli, @rudycelekli, #1396). + +- Report a fire detection's acquisition time as a UTC timestamp in + `get_active_fires`. The tool joined FIRMS's unpadded date and time, so a + 00:45 UTC detection read "2026-01-01 45"; it now reads + `2026-01-01T00:45:00.000Z`. Missing or invalid dates and times remain + unknown rather than rolling into another calendar day + (Rudy Celekli, @rudycelekli, #1395). + +- Report Docker container health with a local HTTP check using Node, with the + same port parsing as the launcher (John Rogers, @14traits, #1394). + +- Start the Docker install on SELinux hosts such as Fedora and RHEL. Compose now + mounts the checkout with `:z`; without it the container could not read `/app` + and stopped with "Cannot find module '/app/scripts/docker-start.mjs'" + (Anıl Güvenç, @anilguvenc, #1391). + +- Render awareness-overlay bearings and courses that round through north as + `000°`, rather than `360°` (Rudy Celekli, #1390). + +- Show cockpit wind from 359.5° or more as 0°, not 360°. Rounding 359.6° + printed "N · 360°" on the local wind direction + (Rudy Celekli, @rudycelekli, #1389). + +- Show a drawn line of 999.5 m or more as 1.0 km. The draw hint kept metres + below 1000, then rounded 999.6 m up to "1000 m" + (Rudy Celekli, @rudycelekli, #1388). + +- Show a Contacts entry 999.5 m or more away as 1.0 km. The panel kept meters + below 1000, then rounded 999.6 m up to "1000 m" + (Rudy Celekli, @rudycelekli, #1387). + +- Show a route leg of 995 m or more as 1.0 km. The route summary and step + cards kept meters below 1000, then rounded 996 m up to "1000 m" + (Rudy Celekli, @rudycelekli, #1386). + +- Show a route leg of 59.5 seconds or more as 1 min. The route summary and step + cards kept seconds below 60, then rounded 59.6 s up to "60 s" + (Rudy Celekli, @rudycelekli, #1385). + +- The HUD's AI place summary drops a reply that arrives after the camera has + started moving, so a summary asked for before a flight no longer names the + old place mid-flight. Cancelled or partially typed summaries retry even if the place + context stays the same (quanticsoul4772, #1384). + +- Reduce repeated work in aircraft detection candidates by caching unchanged + callsign/registration text and reusing resolved fleet models. Metadata updates, + live positions and tracked-aircraft/model handoffs remain immediate + (samehkhamis, #1379). + +- Increase touch-first globe zoom sensitivity to three times the default while + retaining Cesium collision and distance limits. +- Reuse one delayed display timestamp per civil-aircraft fleet update and cache + extrapolation coordinate frames until their fix coordinates change. Preserve + contact counts, movement cadence, tracked motion and ground corrections. + +- Turning a layer off frees the memory its entities held. Cesium kept + removed layers' draw commands in reused per-pass arrays, so Data Centers + kept 116 MiB after it was switched off, submarine cables 74 MiB and dams + 30 MiB; they now keep 13, 9 and 9 MiB (quanticsoul4772, #1367). + +- Aircraft 3D models (Flights, Military Flights, Local ADS-B) skip Cesium's + dynamic environment map, a sky render and GPU readback per model. With + ~150 models in the scene at Atlanta on Google 3D, GPU time per frame at + rest falls from 14.3-14.8 ms to 12.1-12.5 ms; a same-model comparison + showed no visible change (quanticsoul4772, #1366). + +- Drop the decimal when fire radiative power rounds to 10 MW. A 9.96 MW + detection was labeled 10.0 MW because the one-decimal cutoff ran before + rounding (Rudy Celekli, @rudycelekli, #1354). + +- Count a transit report that is 90 seconds old as one minute. The card kept + seconds through 89s, then rounded 90s up to "Reported 2 min ago" + (Rudy Celekli, @rudycelekli, #1353). + +- Read a destination heading that rounds to north as 000. 359.6° was shown as + 360° on the destination bearing while the compass tape already uses 000 + (Rudy Celekli, @rudycelekli, #1352). + +- Keep a tracked vessel's speed, course, heading and fix time when AISStream + static data arrives; the static message only merges name, type, destination + and IMO (rudycelekli, #1351). +- Apply changed static metadata immediately, retaining known fields when a + later static report omits them, without refreshing the vessel's position + (samehkhamis, #1351). + +- Convert NHC cyclone movement speed from miles per hour to knots, so + `movement.speedKt` in cyclone query results is no longer about 15% high + (rudycelekli, #1350). + +- Label NHC cyclone classifications by their published meanings: `PTC` is a + post-tropical cyclone, `PC` a potential tropical cyclone, and subtropical + systems arrive as `STS` and `STD` (rudycelekli, #1349). + +- Wake staged weather imagery on a 150 ms timer while waiting for readiness, + avoiding a continuous render loop and cancelling the wake when work ends + (@nu-stats, #1345). + +- Phrase slight and sharp ramps as directions, so a ramp reads "slightly left" + instead of "on the slightly left", and a lane names its side in both + the proxy response and localized browser instructions + (Rudy Celekli, @rudycelekli, #1343). + +- Keep an impossible wildfire acquisition date off the detection clock, so a + fire is not labeled with a later day it did not happen + (Rudy Celekli, @rudycelekli, #1342). + +- Reject impossible KartaView photo timestamps, so 31 February is unknown + instead of rolling forward into March and passing the imagery date filter + (Rudy Celekli, @rudycelekli, #1341). + +- Read a hemisphere letter that is separated from its number, so a search for + `40.7128 N 74.0060 W` flies there instead of falling through to the geocoders + (Rudy Celekli, @rudycelekli, #1340). + +- Carry HUD LAT/LON seconds that round up to 60.00" into the minutes and + degrees, so longitude -122.35 reads `122°21'00.00"W` instead of + `122°20'60.00"W` (rudycelekli, #1339). + +- Improve touch selection of aircraft and vessels through the shared contact + picker, reveal tracked aircraft details when opening Context, support downward + swipe dismissal of phone drawers while preserving scrolling and controls, and + enlarge the phone logo (samehkhamis, #1338). + +- Evict terrain-height cache entries in fetch-time order without repeatedly + sorting the full cache, while keeping refreshed points newest and ordering + restored entries by their fetch time (daikaginza, #1326). + +- Add a phone layout for viewports 720px and narrower: the globe stays full + screen and a bottom tab bar (Layers, Cameras, Context, Search, More) opens one + panel sheet at a time, keeping attribution visible and scene STOP reachable. + Adapted from the phone tab-shell in #203 by blearymoth (samehkhamis, #1325). + +- Export the KartaView and Panoramax Street Level providers, so a host composing + its own provider list can offer the keyless providers without Mapillary + (samehkhamis, #1324). +- A Mapillary source can take a `graphEndpoint`, a Graph API base that adds the + token itself (such as a same-origin proxy). Its sequence lookups go there + through the source's transport, and the photo viewer uses MapillaryJS's + Graph provider at that endpoint, so no client token is needed in the page + (samehkhamis, #1324). + +- Remove dead code across the repository: three modules nothing imports + (`src/ui.js`, `src/standalone/ui.js`, `src/data/localLayers.js`), exports + and locals nothing reads, a duplicate copy of the bundled dams data and an + unused ship model. The app no longer builds an unused default wind layer + and Bhote Koshi locator layer when it loads. Package exports are unchanged + (samehkhamis, #1321). + +- Validate provider response formats, strengthen camera source checks, and apply consistent API response protections (samehkhamis, #1317). + +- Clarify shared field CSS ownership: CCTV owns calibration editor sizing, + while Radio and Cyber supply explicit field palettes without changing the + current appearance or native control behavior (mazy1998, #1309). + +- Share read-only status badge presentation across CCTV source/frame labels, + calibration provenance and Weather coverage, preserving status meanings, + palettes, translations and announcements while preparing the view contract + for a future Vue migration (mazy1998, #1306). + +- Share native dropdown and numeric-field styling across Scene, CCTV, Display + and Radio controls, with a shared CCTV number-input builder that preserves + existing precision, validation and commit behavior (mazy1998, #1305). + +- Point distances wrap longitude differences across the antimeridian, in voice + proximity checks and `places_nearby` (quanticsoul4772, #1304). + +- `get_wind` flags stale forecasts (`stale`) when the wind proxy serves a + cached model run (quanticsoul4772, #1303). + +- Give ordinary Scene and CCTV actions shared native buttons with consistent + default, destructive and compact styling while preserving their existing + behavior and specialized controls (mazy1998, #1302). + +- Unify segmented selectors for model coverage, detection allocation, drawing + shape, Street View and imagery comparison while preserving their existing + behavior. Keep compact labels such as FILL and FLAT on one line, and let + collapsed Weather release space to the open rail panel. Reserve the full mode + button height in Recent Imagery so keyboard focus is not clipped (mazy1998, #1301). + +- Add a shared Voice Preview and Settings panel with browser-local preferences, + inactivity controls and accessible floating provider controls on compact layouts; + recover inactivity after confirmed audio-less replies, release retired audio + observers and keep cost warnings visible outside Settings + (manjunath22466, #1299). + +- Add Simplified Chinese (zh-CN) to the language picker, with localized dates + and readable Chinese labels. Based on translations by @abiyeenzo (#914) + and @EDIT-Aeterna (#979). + (German, @gekh, #1298). + +- Add the S2 GhostMaps layer: S2 Underground's public KMZ intel products + (Common Intelligence Picture, 30-day kinetic pull, Border Crisis Map, Iran + and Yemen products and the newest incident drop) from + github.com/s2underground/GhostMaps, with one chip per product and report + cards on click. `/api/ghostmaps` watches the repository's branch head every + 15 s and pushes each new commit to open pages, which reload only the + products that changed (Black Pine Defense). +- Clear a temporary GhostMaps upstream error and notify open pages when the + repository becomes reachable again, including when no new edition was published. +- Release packed-image resources when a load is cancelled or fails, respect + injected or omitted GhostMaps sources, and wait for background cache warm-up + before removing provider test fixtures. +- Include Simplified Chinese translations and keep the combined voice prompt + within its existing size limit while retaining all spoken aliases. + +- A Street Level provider whose `zoomFor` still answers `{zoom, kind}`, the + shape before the core went slim, draws its lines again instead of a silent + blank; an overview level or any answer that is not a whole zoom shows the + zoom-in hint (asturksever, #1288). + +- Give ordinary sliders a shared native control and consistent track, thumb, + value, focus and disabled styling while preserving feature behavior and + specialized controls (mazy1998, #1287). + +- The Street Level SINCE note sits on the value's line, in its type and a + size smaller: with KartaView lit it reads ANY DATE (by upload date). It + had lost its size variable in the Street Level slim-down and rendered + larger than the value, on a line of its own (asturksever, #1286). + +- Keep aircraft route labels on the scheduled airport leg instead of accepting + its distant great-circle extensions, preserving generous endpoint tolerance + across the signed-angle branch cut (rudycelekli, #1284). + +- Report cached CelesTrak satellite records as stale in the Data Layers row, + preserving separate core and dense catalog provenance through refresh, + removal and lifecycle cleanup (rudycelekli, #1283). + +- Pause periodic network updates in hidden tabs; the overdue update on return restarts the polling schedule, so the next poll follows one interval later even when that update fails (asturksever, #1282). +- Report and guard browser visibility during Transit QA so hidden-page polling pauses cannot masquerade as playback regressions (asturksever, #1282). +- Require each live city to supply its own feed vehicles in Transit QA; retained vehicles cannot qualify another city (asturksever, #1282). +- Bound the Transit card-anchor probe by observed poll coverage instead of a fixed 20-second window (asturksever, #1282). +- Keep visible-page Transit probes focused through the browser testing API (asturksever, #1282). +- Add a real-browser regression gate for hidden-tab periodic work, explicit refresh, resume and teardown (asturksever, #1282). +- Restore minimized test windows before screenshots so native compositor pauses cannot stall browser acceptance (asturksever, #1282). + +- Hold rendering only for animated content (asturksever, #1281). +- Exercise current vector road sources and published camera bounds in Traffic fixture QA (asturksever, #1281). +- Establish browser-level foreground visibility for Traffic QA and reject hidden-page samples (asturksever, #1281). +- Supply CORS headers on cross-origin traffic fixtures and report browser exceptions without disabling browser security (asturksever, #1281). +- Isolate the Traffic keyless browser scenario from the keyed page’s workers and intercepted cache (asturksever, #1281). +- Restore minimized test windows before screenshots so native compositor pauses cannot stall browser acceptance (asturksever, #1281). +- Intercept only Traffic provider URLs, leaving Cesium worker and module loading untouched (asturksever, #1281). +- Settle an unfinished Traffic height correction when the last animated point leaves, so the layer stops reporting loading once its render hold is released (asturksever, #1281). + +- Throttle mission hover picks with a trailing check for the last pointer position, and clear stale cursors (asturksever, #1279). + +- Reserve singleflight before disk cache reads (asturksever, #1278). + +- Bound each height request to one upstream chunk (asturksever, #1276). + +- Preserve enable during first-load replacement (asturksever, #1275). +- Release disabled weather camera listeners and make teardown resource leaks fail the browser probe (asturksever, #1275). +- Keep visible-page weather teardown probes focused through the browser testing API (asturksever, #1275). + +- Scan the kml root delimiter in bounded time (asturksever, #1274). + +- Retire unavailable history and keep local trails (asturksever, #1273). + +- Normalize geocoder bias across the antimeridian (asturksever, #1272). + +- Reject inherited style keys during restore (asturksever, #1271). + +- Respect provider cooldowns and bound tle groups (asturksever, #1270). + +- Coalesce refreshes and cool down opensky failures (asturksever, #1269). + +- Normalize station tags and retain valid mixed rows; skipped malformed rows still report degraded coverage (asturksever, #1268). +- Correct Radio QA push-to-talk setup to target the mounted voice controller (asturksever, #1268). + +- Honor Docker Compose trusted-peer and allowed-host settings from the shell + or project `.env`, and let `GEV_KEY_SETUP_TRUSTED_PEERS=none` disable gateway + access to Provider Settings before Vite starts (asturksever, #1265). + +- Prevent malformed Overpass filters from blocking the local server, and reject + cross-site or excessive query requests before reading their bodies + (asturksever, #1264; fixes #1248). +- Release unread responses from the optional Google-token probe so keyless + browser validation can settle; the Overpass gate recognizes only that probe's + expected 404 as an unavailable capability (asturksever, #1264). +- Make tracking arrival checks respect the aircraft update cadence while checking + orientation on the first reveal, avoiding false failures at faster render + rates (asturksever, #1264). + +- The terrain-heights bounds tests no longer read the checkout's + `.gev-cache/terrain-heights.json`. Each test gets a cache file of its own, so + `npm test` no longer fails after the dev server has cached terrain near + Austin (KnottyDyes, #1244). + +- Replace the blocky JPEG sky around the globe with the 9,096 stars of the + Yale Bright Star Catalogue, drawn as sharp points where they are at the + scene time, over a soft Milky Way from ESO/S. Brunier (CC BY 4.0). The Sun + and Moon stay; the anime style hides the Milky Way. Assets: 296 kB (gekh, + #1243). + +- `get_traffic_flow` flags stale cached TomTom tiles and reports the oldest + tile fetch time (`stale`, `oldest_tile_at`), with pending freshness metadata + released on failed or cancelled tile reads (quanticsoul4772, #1239). + +- Add Taiwan's national freeway cameras from the Freeway Bureau, MOTC to CCTV: + ~1,800 cameras read at runtime from the official MOTC 2.0 open-data table, + with on-demand snapshots and attribution. No API key is required; set + `CCTV_TAIWAN_ENABLED=0` to skip it (419vive, #1237). + +- Require a geocoded containment anchor for ambiguous analyst region names, + preserve boundary provenance and cancellation safety, and retain exact-name + precedence for natural outlines (manjunath22466, #1235). + +- Serve the camera catalog while it refreshes. An expired catalog made every + camera request wait for the slowest pack to reload; it is now answered at + once while one background refresh runs, so only the first load waits. Estonia's + slow Tarktee feeds get 30 s instead of 15 s, so the pack no longer drops out + on about a third of loads (quanticsoul4772, #1234). + +- Harden the Tarktee (Estonia) DATEX2 camera catalog fetches: refuse redirects, + cancel both response streams when either response fails or overflows the 4 MB + byte cap, and deduplicate camera IDs before per-pack prioritization + (yaka0007, #1233). + +- Skip bike-share stations with missing, blank or invalid coordinates instead + of placing them at coerced zero coordinates or accepting out-of-range values. + Explicit zero coordinates and numeric strings remain supported (Bortlesboat, #1232). + +- OpenSky sign-in matches what OpenSky accepts since 2026-03-18. The server + now reads `OPENSKY_CREDENTIALS_FILE` (the `credentials.json` OpenSky's + account page downloads) on every platform, not only through the macOS + launcher, and no longer sends retired username/password Basic auth: + `OPENSKY_AUTH_MODE=basic` loads anonymously with one warning saying what to + set instead (quanticsoul4772, #1229). +- Credential-file warnings omit parser excerpts and filesystem error details; + the path example also works with the macOS launchers. + +- Load Ontario 511 cameras again. 511on.ca's camera endpoint now requires a + free developer key; set `ONTARIO_511_API_KEY` to enable the pack, which is + otherwise skipped with one log line saying where to get a key + (quanticsoul4772, #1228). + +- The first-run card can be closed on a phone or tablet. "ESC to dismiss" is + now a button that closes the card the same way ESC does; touch screens read + DISMISS, and phones no longer hide it, so choosing a mission is not the only + way out (KnottyDyes, #1226). + +- Add continuous globe rotation with direction and speed controls and a globe-fit + check before starting (manjunath22466, #1225). + +- Open God's Eye View from Pinokio in the system browser using the supported + `popout` menu option. The application's framing policy is unchanged + (NukeThemAII, #1222). + +- Avoid starting or queuing a reply when the local channel rejects a typed OpenAI + command, while preserving an earlier accepted deferred input + (Manjunath, #1220). + +- Keep NASA FIRMS fire and ALPR camera labels English in voice tool results + (`track_entity`, `get_entity_context`, pointer context); the voice card still + shows them in the interface language (daikaginza, #1207). + +- Report actual outcomes when voice enables or disables CCTV through the shared + layer lifecycle, including failed and cancelled changes (manjunath22466, + #1205). + +- Draw CCTV stills at their source aspect on the monitor plane instead of + stretching them to the 16:9 canvas. Most DOT cameras publish 4:3 frames, so + every still was widened; they are now centered and pillarboxed on the dark + the placeholder already ends on (Danielslay86, #1201). + +- Color CCTV cameras with a video feed violet. Cameras with an HLS, MP4 or + WebM feed were the same cyan as stills, so a DelDOT or Statens vegvesen + video camera could only be found by opening it. Stills stay cyan and the + active camera stays amber, and focus de-emphasis fades the violet the same + way (Danielslay86, #1200). + +- Keep Space Missions marked STALE when Launch Library 2 falls back to cached + launch data, and return to NOMINAL after a fresh response without discarding + retained missions (rudycelekli, #1199). + +- Share Launch Library request cache keys across installations refreshing in the + same UTC minute, identify the app to the provider, and explain that standard + space-missions access needs no key. Optional higher-rate LL2 tokens are paid + upgrades; existing local cache and server-only token handling are unchanged + (rudycelekli, #1197). + +- Add nine Spanish city bike systems to Bike Share and `get_bike_share`: BiciMAD + (Madrid), Valenbisi (Valencia), Bizi Zaragoza, Sevici (Seville), BIKI + (Valladolid), BiciCoruña, Dbizi (Donostia-San Sebastián), Bilbao Bizi and + BicinRivas, about 1,840 stations. Station names read underscores as word + breaks, and station capacity counts docks rather than PBSC's geofenced area + (ulihhhh, #1190). + +- Keep missing launch-pad coordinates unknown so launches use the location + fallback or stay off the map instead of appearing at 0°N 0°E. Missing stage + flight numbers no longer show "FLIGHT 0" + (Rudy Celekli, @rudycelekli, #1186). + +- Flights' ground floor works across the antimeridian. The viewer-distance + check behind the 150 km floor radius and its copy in the photoreal mesh-floor + sampler subtracted longitudes without wrapping, so two points 21 km apart + across 180° measured about 38,000 km and low or grounded aircraft just across + the line from the viewer were never floored. A contact's display corridor + walked a segment across 180° the long way round, spending its cell budget on + ground behind the contact, and a contact on the seam lost its cell hysteresis. + SEARCH NEARBY SITES on a view across 180° searched Google Places around + longitude 0, on the far side of the globe, with a radius sized from the view's + height alone; it now searches the view (Aditya, @Rohilalala, #1173). + +- Keep missing CCTV numbers unknown instead of reading them as zero. `Number` + turns null, blank strings and booleans into 0 or 1, and the camera source + list sends an unknown number as JSON null, so a source-pack camera that left + out its pose reached the browser as zeros clamped to each field's floor — + facing north, pitch −2°, FOV 20°, range 120 m, mount 6 m and ground 0 m — + instead of the defaults (id-hash heading, −17°, 74°, 700 m, 24 m and the + city's ground); a null or blank position placed the camera at 0,0. The + server's `toFiniteNumber` and the browser's `safeNumber` now treat absent, + blank and boolean values as missing. The same conversion also stops a + Tallinn row with a null heading reading as a confident north-facing camera, + a Caltrans camera with a blank elevation losing its 150 m ground prior, and + a TfL or Catalonia camera with a null or blank coordinate being kept at 0,0 + or on the zero meridian (omerbberk, #1172). + +- Director shot actions land on the requested shot. A seek to a shot's start + could round a hair below it and select the end of the previous shot for some + shot counts and durations (Aditya, @Rohilalala, #1171). + +- Fire-perimeter queries handle outlines and holes crossing the antimeridian: + areas enclosed near ±180° are included, areas at the opposite meridian are + excluded, and returned perimeter coordinates stay near the dateline. Incident + cards use the same circular longitude mean and compare multipart outline + areas along short longitude edges, keeping the card on the largest polygon + (Arianna Method, @ariannamethod, #1142). + +- Scenes keep the "Scene not saved" status when a capture, update, append or + import cannot be saved, and an unreadable saved project no longer overwrites + the recovery checkpoint. `startScene()` resolves to its documented result, + `afterShotId` works without an explicit scene, and `scenesRun` counts the + distinct scenes queued (djabhi31, #1135). + +- Label camera-tool Street View fallbacks as historical Google imagery rather + than the current camera view; keep unknown frame provenance explicit + (rudycelekli, #1118). + +- Release superseded Google Street View open waits and suppress metadata + requests whose viewer was unmounted while the service loaded (rudycelekli, + #1117). + +- Exclude aircraft without a reported altitude from requested altitude bands; + unfiltered aircraft queries still retain them (rudycelekli, #1115). + +- A failed Esri Satellite or keyless terrain load still shows OSM or flat terrain + at once, but no longer lasts the whole session: while the fallback is on + screen, the real provider is retried in the background (30 seconds, doubling + to a 10-minute cap) and replaces it live once it loads. Map switches never + wait for a retry (Aditya, @Rohilalala, #1111). + +- Skip TLE sets whose line 1 and line 2 carry different catalog numbers, so a + spliced catalog cannot pair one satellite's elements with another's; the next + valid set still parses (VG31OP, #1101). + +- Overpass data whose element tags contain a failure phrase ("timed out", + "runtime error", "too many requests" and similar, e.g. a place named "Timed + Out Escape Rooms") is returned as data instead of being refused and putting + the endpoint on cooldown; upstream failures are read from the remark (Aditya, + @Rohilalala, #1097). + +- Military aircraft keep their last heading and speed when an adsb.lol row omits + `track` or `gs`, instead of turning north and stopping; a grounded row without + a speed still reads 0 (Aditya, @Rohilalala, #1096). + +- Update DOMPurify to 3.4.17, Sharp to 0.35.5 and source-map-js to 1.2.2 for + GHSA-p98j-92pf-mc4p, GHSA-6688-9rhm-gjv2, GHSA-wq5f-xc86-pv6w and + GHSA-68fv-2mgg-jv7q; `npm audit` now reports no vulnerabilities (NurstarK, + #1094). + +- Location search accepts two-dimensional WGS84 `geo:` URIs offline, with + the existing coordinate framing and label. Unsupported URI fields are passed + to the remaining search providers unchanged (cj-vana, #1071). + +- Keyless standalone startup answers an unavailable Google tile-token endpoint + with uncached 204 instead of a browser-visible 404. Existing providers take + precedence, and unrelated API routes behave as before. (dvilrgamerz, #1066) + +- On Windows, `npm run doctor` and the Pinokio install no longer print Node's + DEP0190 warning ("Passing args to a child process with shell option true can + lead to security vulnerabilities"): npm.cmd's fixed subcommand is now part of + the shell command string instead of an argument array (quanticsoul4772, #1057). + +- `aircraft_in_area` and `vessels_in_area` take `group_by` and `stats`, so an + MCP client can ask which airlines, countries, aircraft types or ship types + dominate an area, or the average altitude or speed, over every match instead + of estimating from the returned rows. Airlines come from the ICAO designator + in each callsign (SWA1234 counts as SWA), so the breakdown works on feeds + that report no operator; operator and type are counted only where the feed + reports them. Ship types count by family, so AIS codes 70 to 79 are all + cargo; type 0 ("not available") and the reserved codes 100 to 255 count as + unknown. Altitude and speed stats cover airborne aircraft only, so parked + aircraft do not pull the means down. Every vessel answer, `find_vessel` + included, now reads AIS ship-type codes as their family and a destination + with no letters as unknown (quanticsoul4772, #1056). + +- Add Hong Kong Transport Department traffic snapshot cameras as a keyless CCTV + source pack: the public DATA.GOV.HK English locations XML, frames pinned to + `tdcctv.data.one.gov.hk`, with DATA.GOV.HK Terms of Use attribution. By + default nearly the full TD catalog (~1,013 cameras; cap 1,100) loads, + prioritized across Hong Kong Island, Kowloon and the New Territories. Headings + use the shared id-hash fallback at low confidence. `CCTV_HK_MAX_SOURCES` sets + the cap (8–1,200) and `CCTV_HK_ENABLED=0` turns the pack off (JCY2515, #990). + +- Cross-site pages can no longer fill the terrain-height cache or spend the + visitor's own `/api/terrain/heights` rate-limit quota through the visitor's + browser. The route refuses a cross-site `Sec-Fetch-Site` or a foreign or + opaque `Origin` before rate limiting, cache access or upstream work. Unlike + the cost-bearing routes it still answers same-origin requests that arrive + through a reverse proxy, so terrain keeps rendering behind nginx, Caddy or + Cloudflare instead of falling back to the geoid (Sunil56224972, daikaginza, + #975). + +- Street Level is rebuilt around one small provider registry: Mapillary, + KartaView, Panoramax and Google Street View share one coverage drawer and + one photo viewer, one source lit at a time. Floating and docked panels, + FOLLOW, surface modes, the legend and the Mapillary proxy's disk cache are + gone; `.gev-cache/mapillary/` from earlier runs is no longer read and can be + deleted (gekh, #974). + +- Cross-site browser requests can no longer spend the TomTom traffic-tile + budget through `/api/tomtom/*`. The shared same-site gate runs before status, + cache, and upstream work; same-origin app requests and non-browser local + callers remain supported (Sunil56224972, #973). + +- Recent Imagery: opening DETAILS scrolls its card into view when it opens below + the fold. The panel used to restore the previous scroll position right after + the reveal, so the card stayed out of sight (Ian Blenke, #970). + +- Harden Vite's filesystem deny list for local-only artifacts: repo `dist/`, + `.gev-logs/`, and `.gev-cache/` are denied without blocking dependency + `dist/` directories, and checkout paths containing glob metacharacters are + escaped before building the root-anchored pattern (blowing-a-raspberry, #948). + +- Give each Statens vegvesen camera its own ground height from Kartverket's + keyless point-height API (CC BY 4.0) instead of one flat 150 m prior, so + mountain-pass cameras no longer sit hundreds of metres below the terrain + where neither the point-height prior nor the ground snap resolves. About 850 + of ~855 cameras get a height; the rest keep the old prior. Requests carry 20 + points, the most the API answers from its 1 m terrain model, eight at a + time; a cold lookup takes about 6–13 s. Cameras over water use the water + surface rather than the sea-floor depth the API returns there; for bridge + cameras that is still below the deck. Heights are cached for good and misses + for 6 h, so a refresh only asks about new or moved cameras. After a + failing request (a 408, 429 or 5xx, a network error, a request over 10 s or + an unreadable body) the lookup stops and backs off (Retry-After, else + 30 min, longer than the refresh). The lane waits at most 12 s from its + start, and only on a cold cache; a slower first lookup leaves the cameras it + had not reached on the flat prior until the next 15-minute refresh, and + keeps filling the cache meanwhile. + `CCTV_VEGVESEN_HEIGHTS=0` turns it off. Follow-up to #929 (trygvehhh, #945). + +- Extract a reusable model-free World Packet from the existing voice + `get_current_view_state` owner without restoring disabled layers to the + model context. Keep the enabled-only payload, disabled-layer count, source + provenance, action result and view-state contract; read the layer roster once + per packet; voice retains the speech/card envelope at its own boundary. + Credits: original GEV voice/layer contributors and #880 implementation. + +- Add optional Gemini Live voice to the standalone app, with a provider chooser, + server-held API key, microphone streaming, shared map actions and captions. + Switching providers ends the old conversation and preserves the input mode + (Manjunath, #872). + +- Close the compact Radio disclosure when an adaptive tactical right-rail + restore directly expands Context, before Space Missions can be covered. + A repeated Context-open request also clears stale disclosure state. + Real PanelChrome constructor wiring and the rail reflow path are covered + by focused regressions. Credits: kvnloo (#816), raysung-2026's original + #804 report, asturksever's review, and quanticsoul4772's independent + Windows diagnosis. + +- Changelog entries are now one file per pull request. A change adds + `changelog.d/-.md` instead of editing the top of + `CHANGELOG.md`, which two pull requests in flight could not share — it was the + most frequent merge conflict in the open queue, and for six of them the only + one. `npm run changelog` splices the directory into `CHANGELOG.md` at release + time and empties it; `npm run changelog:check` reports the batch and changes + nothing. Fragment text is copied through unchanged (daikaginza, #787). + +- Read satellite catalog numbers written in Alpha-5, the TLE spelling of + numbers above 99999: a letter for the first two digits, skipping I and O + (`A0000` is 100000, `Z9999` is 339999). The satellites layer converted such a + field to `NaN`, so every Alpha-5 satellite shared one catalog entry and all + but the first were dropped as duplicates; the satellite tools read the same + field as no number, so such a satellite could not be found by it. The layer + and the tools now decode the field in `src/sources/tle.js`, and reject a + malformed one (a sign, decimal point, hex, embedded space or stray letter) + instead of reading part of it as a number. This is Alpha-5 TLE + compatibility: CelesTrak's TLE feed carries no satellite above 99999, which + needs the OMM feed (#1191) (Honorius Neogy, #767, fixes #751). + +- The dev server no longer watches `.gev-cache` and `.gev-logs`. Providers write + cache files and logs there while the app runs, and none of it is source, so + the watcher now skips it; this guards against the DNS-lookup delays heavy + cache writes have caused, though no difference was measured on current main + (monwiss, #761). + +- Bound what a caller can grow through `/api/terrain/heights`. Every distinct + 5-decimal point was a permanent in-memory entry, a permanent line in an + uncapped `.gev-cache/terrain-heights.json`, and a live upstream call, with + nothing limiting the rate. The point cache now holds at most 50,000 entries + and evicts oldest-first, a cache file above + 24 MB is not read back, and the route is limited to 90 requests/minute per + client (270 global). Evicting a point costs one refetch, never a wrong + answer, since terrain does not move. Ordinary use is unaffected: a full + `test:track` run drives 10 requests, peaking at 8/min (daikaginza, #686). + +- Add FL511 (Florida DOT) traffic cameras as an opt-in CCTV source pack: + the statewide ArcGIS catalog, read a page at a time under a byte cap with + redirects refused, and frames pinned to FL511's two image hosts over HTTPS. + FL511's terms limit its content to individual, personal use, and any other + use (a public deployment included) needs FDOT's express written consent, so + the pack stays off unless `CCTV_FLORIDA_ENABLED=1`. Headings come from the + catalog's direction codes, and camera ids come from the image channel, since + the catalog's ID column repeats across regions. `CCTV_FLORIDA_MAX_SOURCES` + sets the cap (Danielslay86, #605). + +- The client's great-circle distances now come from one shared + `src/geoDistance.js` (`greatCircleKm`/`greatCircleMeters`, `{lat, lon}` + points). The Earth radius is standardized on 6371.0088 km, so distances shift + by about 1.4 ppm and region areas by about 2.8 ppm, and missing or + out-of-range points return `Infinity` (onionviolet, #287; Rajojha-1, #749). + - The tracked-aircraft descriptor now publishes `verticalRateMps`, on both the civil and military layers, so a consumer reading `getTrackedInfo()` no longer has to reach past it into the raw poll record for climb/descent. Reported, @@ -291,8 +978,6 @@ point. A slow render gets one bounded second frame request, while hidden, stale, moved-camera, invalid and oversized captures still fail closed. -## [Unreleased] - - Add a keyless Air quality layer to the Weather group, with Environment and Climate Change Canada's AQHI as the first registered provider. Readings carry `{ provider, scale, value, band }` so another network can be added without @@ -507,6 +1192,28 @@ needs only the Map Tiles API and the Maps JavaScript API (Street View). Keyless sessions and the Photon/Nominatim fallback order are unchanged. +- Voice can switch on every shipped data layer (the two scene-driven + Bhote Koshi layers stay scene-only), including transit, Recent + Imagery, wind, the weather layers, cyclones and mapped installations, and + understands their spoken names ("buses", "hurricanes", "military bases"). + One voice manifest (`src/voice/layerManifest.js`) generates the tool enums + and aliases, and a unit test fails when a new layer has no entry. +- `analyst_query` counts up to 250,000 loaded records per layer instead of the + first 2,000, and says when a layer went past that (`complete: false`). It + also answers over bikeshare stations, transit vehicles, rocket launches, + cyclones, ALPR cameras, mapped installations, local ADS-B aircraft and fire perimeters; fire + records carry their sensor (VIIRS or MODIS). +- Unknown fields, operators, units, value types, scope kinds and invalid + centres are refused with the allowed values instead of answering zero or widening to anywhere. A + layer that is off, still loading or unavailable is reported as such, not + as a count of zero; a partly answerable query is marked `partial`. + Distance sorts honour `sortDir`, a written unit such as `altitudeM(ft)` + converts, and large rankings no longer sort the whole set. +- Results carry `lat`/`lon` for each item and a `display` object with the + scope, the feed window (earthquakes and fires cover the last 24 h) and any + caveat for the screen. The model is asked to answer in one short phrase. +- The weather and Recent Imagery panels can be opened by voice. + ## [0.2.1] — 2026-10-02 — God's Eye View through Your Agent (with security fixes and other features) - Ship each bundled data pack once. The region, marine, admin-boundary, @@ -789,32 +1496,6 @@ (`src/ui/imagerySplit.js`, `src/maps/imageryComparison.js`), and `MapSourceController.subscribe()` reports every settled map switch. -## Unreleased — voice reaches every layer; honest analyst answers - -- Voice can switch on every shipped data layer (the two scene-driven - Bhote Koshi layers stay scene-only), including transit, Recent - Imagery, wind, the weather layers, cyclones and mapped installations, and - understands their spoken names ("buses", "hurricanes", "military bases"). - One voice manifest (`src/voice/layerManifest.js`) generates the tool enums - and aliases, and a unit test fails when a new layer has no entry. -- `analyst_query` counts up to 250,000 loaded records per layer instead of the - first 2,000, and says when a layer went past that (`complete: false`). It - also answers over bikeshare stations, transit vehicles, rocket launches, - cyclones, ALPR cameras, mapped installations, local ADS-B aircraft and fire perimeters; fire - records carry their sensor (VIIRS or MODIS). -- Unknown fields, operators, units, value types, scope kinds and invalid - centres are refused with the allowed values instead of answering zero or widening to anywhere. A - layer that is off, still loading or unavailable is reported as such, not - as a count of zero; a partly answerable query is marked `partial`. - Distance sorts honour `sortDir`, a written unit such as `altitudeM(ft)` - converts, and large rankings no longer sort the whole set. -- Results carry `lat`/`lon` for each item and a `display` object with the - scope, the feed window (earthquakes and fires cover the last 24 h) and any - caveat for the screen. The model is asked to answer in one short phrase. -- The weather and Recent Imagery panels can be opened by voice. - -## Unreleased — local receiver feeds - ### Local receiver feeds - The Local ADS-B layer also reads local 1090 MHz and 978 MHz UAT decoder @@ -957,7 +1638,6 @@ Add feed provenance to analyst/view answers and HUD context while retaining existing response fields and runner ownership (Matt Van Horn, #347). Analyst records for loaded satellites, datacenters and dams, with explicit bounded count/rank coverage (Matt Van Horn, #351). - - New Fire Perimeters layer (Events group): live NIFC WFIGS interagency wildfire incident perimeters as ground-clamped polygons with a containment-colored fire line, refreshed every 5 minutes from the public @@ -1234,6 +1914,7 @@ of current runtime behavior, see [`docs/CURRENT-STATE.md`](docs/CURRENT-STATE.md ### Other changes + - Add ECMWF IFS model selection to Wind (#464, thanks @beneduzi), with model-scoped forecast-step caches, cancellation of replaced requests, and separate issue/valid timestamps. - Add bounded Director feature actions with accessible controls, explicit camera/layer admission and cancellation; restore pack geometry on same-shot seek. Preserve existing scenes and content attribution. @@ -2042,3 +2723,4 @@ represent previously published GitHub Releases. ## [0.1.0] — 2026-02-09 - Initial project version. + diff --git a/changelog.d/1056-area-tool-breakdowns.md b/changelog.d/1056-area-tool-breakdowns.md deleted file mode 100644 index 3ca857a45..000000000 --- a/changelog.d/1056-area-tool-breakdowns.md +++ /dev/null @@ -1,12 +0,0 @@ -- `aircraft_in_area` and `vessels_in_area` take `group_by` and `stats`, so an - MCP client can ask which airlines, countries, aircraft types or ship types - dominate an area, or the average altitude or speed, over every match instead - of estimating from the returned rows. Airlines come from the ICAO designator - in each callsign (SWA1234 counts as SWA), so the breakdown works on feeds - that report no operator; operator and type are counted only where the feed - reports them. Ship types count by family, so AIS codes 70 to 79 are all - cargo; type 0 ("not available") and the reserved codes 100 to 255 count as - unknown. Altitude and speed stats cover airborne aircraft only, so parked - aircraft do not pull the means down. Every vessel answer, `find_vessel` - included, now reads AIS ship-type codes as their family and a destination - with no letters as unknown (quanticsoul4772, #1056). diff --git a/changelog.d/1057-windows-npm-dep0190.md b/changelog.d/1057-windows-npm-dep0190.md deleted file mode 100644 index 1e8e1da55..000000000 --- a/changelog.d/1057-windows-npm-dep0190.md +++ /dev/null @@ -1,4 +0,0 @@ -- On Windows, `npm run doctor` and the Pinokio install no longer print Node's - DEP0190 warning ("Passing args to a child process with shell option true can - lead to security vulnerabilities"): npm.cmd's fixed subcommand is now part of - the shell command string instead of an argument array (quanticsoul4772, #1057). diff --git a/changelog.d/1066-keyless-google-token.md b/changelog.d/1066-keyless-google-token.md deleted file mode 100644 index c07cbade8..000000000 --- a/changelog.d/1066-keyless-google-token.md +++ /dev/null @@ -1,3 +0,0 @@ -- Keyless standalone startup answers an unavailable Google tile-token endpoint - with uncached 204 instead of a browser-visible 404. Existing providers take - precedence, and unrelated API routes behave as before. (dvilrgamerz, #1066) diff --git a/changelog.d/1071-geo-uri-search.md b/changelog.d/1071-geo-uri-search.md deleted file mode 100644 index eba251948..000000000 --- a/changelog.d/1071-geo-uri-search.md +++ /dev/null @@ -1,3 +0,0 @@ -- Location search accepts two-dimensional WGS84 `geo:` URIs offline, with - the existing coordinate framing and label. Unsupported URI fields are passed - to the remaining search providers unchanged (cj-vana, #1071). diff --git a/changelog.d/1094-dependency-security-patches.md b/changelog.d/1094-dependency-security-patches.md deleted file mode 100644 index 058359efc..000000000 --- a/changelog.d/1094-dependency-security-patches.md +++ /dev/null @@ -1,4 +0,0 @@ -- Update DOMPurify to 3.4.17, Sharp to 0.35.5 and source-map-js to 1.2.2 for - GHSA-p98j-92pf-mc4p, GHSA-6688-9rhm-gjv2, GHSA-wq5f-xc86-pv6w and - GHSA-68fv-2mgg-jv7q; `npm audit` now reports no vulnerabilities (NurstarK, - #1094). diff --git a/changelog.d/1096-military-hold-track-speed.md b/changelog.d/1096-military-hold-track-speed.md deleted file mode 100644 index adc1793c4..000000000 --- a/changelog.d/1096-military-hold-track-speed.md +++ /dev/null @@ -1,3 +0,0 @@ -- Military aircraft keep their last heading and speed when an adsb.lol row omits - `track` or `gs`, instead of turning north and stopping; a grounded row without - a speed still reads 0 (Aditya, @Rohilalala, #1096). diff --git a/changelog.d/1097-overpass-remark-failure-phrases.md b/changelog.d/1097-overpass-remark-failure-phrases.md deleted file mode 100644 index 4543710da..000000000 --- a/changelog.d/1097-overpass-remark-failure-phrases.md +++ /dev/null @@ -1,5 +0,0 @@ -- Overpass data whose element tags contain a failure phrase ("timed out", - "runtime error", "too many requests" and similar, e.g. a place named "Timed - Out Escape Rooms") is returned as data instead of being refused and putting - the endpoint on cooldown; upstream failures are read from the remark (Aditya, - @Rohilalala, #1097). diff --git a/changelog.d/1101-tle-catalog-number-match.md b/changelog.d/1101-tle-catalog-number-match.md deleted file mode 100644 index d1e2aa407..000000000 --- a/changelog.d/1101-tle-catalog-number-match.md +++ /dev/null @@ -1,3 +0,0 @@ -- Skip TLE sets whose line 1 and line 2 carry different catalog numbers, so a - spliced catalog cannot pair one satellite's elements with another's; the next - valid set still parses (VG31OP, #1101). diff --git a/changelog.d/1111-map-fallback-retry.md b/changelog.d/1111-map-fallback-retry.md deleted file mode 100644 index 45086eab1..000000000 --- a/changelog.d/1111-map-fallback-retry.md +++ /dev/null @@ -1,5 +0,0 @@ -- A failed Esri Satellite or keyless terrain load still shows OSM or flat terrain - at once, but no longer lasts the whole session: while the fallback is on - screen, the real provider is retried in the background (30 seconds, doubling - to a 10-minute cap) and replaces it live once it loads. Map switches never - wait for a retry (Aditya, @Rohilalala, #1111). diff --git a/changelog.d/1115-aircraft-altitude-band-unknown.md b/changelog.d/1115-aircraft-altitude-band-unknown.md deleted file mode 100644 index a6b69472d..000000000 --- a/changelog.d/1115-aircraft-altitude-band-unknown.md +++ /dev/null @@ -1,2 +0,0 @@ -- Exclude aircraft without a reported altitude from requested altitude bands; - unfiltered aircraft queries still retain them (rudycelekli, #1115). diff --git a/changelog.d/1117-google-viewer-lifecycle.md b/changelog.d/1117-google-viewer-lifecycle.md deleted file mode 100644 index 66d73d4a2..000000000 --- a/changelog.d/1117-google-viewer-lifecycle.md +++ /dev/null @@ -1,3 +0,0 @@ -- Release superseded Google Street View open waits and suppress metadata - requests whose viewer was unmounted while the service loaded (rudycelekli, - #1117). diff --git a/changelog.d/1118-cctv-snapshot-fallback-provenance.md b/changelog.d/1118-cctv-snapshot-fallback-provenance.md deleted file mode 100644 index 648891785..000000000 --- a/changelog.d/1118-cctv-snapshot-fallback-provenance.md +++ /dev/null @@ -1,3 +0,0 @@ -- Label camera-tool Street View fallbacks as historical Google imagery rather - than the current camera view; keep unknown frame provenance explicit - (rudycelekli, #1118). diff --git a/changelog.d/1135-director-save-status-run-results.md b/changelog.d/1135-director-save-status-run-results.md deleted file mode 100644 index aa3c6f0e6..000000000 --- a/changelog.d/1135-director-save-status-run-results.md +++ /dev/null @@ -1,5 +0,0 @@ -- Scenes keep the "Scene not saved" status when a capture, update, append or - import cannot be saved, and an unreadable saved project no longer overwrites - the recovery checkpoint. `startScene()` resolves to its documented result, - `afterShotId` works without an explicit scene, and `scenesRun` counts the - distinct scenes queued (djabhi31, #1135). diff --git a/changelog.d/1142-antimeridian-fire-perimeters.md b/changelog.d/1142-antimeridian-fire-perimeters.md deleted file mode 100644 index 8b847163e..000000000 --- a/changelog.d/1142-antimeridian-fire-perimeters.md +++ /dev/null @@ -1,6 +0,0 @@ -- Fire-perimeter queries handle outlines and holes crossing the antimeridian: - areas enclosed near ±180° are included, areas at the opposite meridian are - excluded, and returned perimeter coordinates stay near the dateline. Incident - cards use the same circular longitude mean and compare multipart outline - areas along short longitude edges, keeping the card on the largest polygon - (Arianna Method, @ariannamethod, #1142). diff --git a/changelog.d/1171-director-goto-shot.md b/changelog.d/1171-director-goto-shot.md deleted file mode 100644 index 4c08351ef..000000000 --- a/changelog.d/1171-director-goto-shot.md +++ /dev/null @@ -1,3 +0,0 @@ -- Director shot actions land on the requested shot. A seek to a shot's start - could round a hair below it and select the end of the previous shot for some - shot counts and durations (Aditya, @Rohilalala, #1171). diff --git a/changelog.d/1172-cctv-missing-numbers.md b/changelog.d/1172-cctv-missing-numbers.md deleted file mode 100644 index d401021e9..000000000 --- a/changelog.d/1172-cctv-missing-numbers.md +++ /dev/null @@ -1,13 +0,0 @@ -- Keep missing CCTV numbers unknown instead of reading them as zero. `Number` - turns null, blank strings and booleans into 0 or 1, and the camera source - list sends an unknown number as JSON null, so a source-pack camera that left - out its pose reached the browser as zeros clamped to each field's floor — - facing north, pitch −2°, FOV 20°, range 120 m, mount 6 m and ground 0 m — - instead of the defaults (id-hash heading, −17°, 74°, 700 m, 24 m and the - city's ground); a null or blank position placed the camera at 0,0. The - server's `toFiniteNumber` and the browser's `safeNumber` now treat absent, - blank and boolean values as missing. The same conversion also stops a - Tallinn row with a null heading reading as a confident north-facing camera, - a Caltrans camera with a blank elevation losing its 150 m ground prior, and - a TfL or Catalonia camera with a null or blank coordinate being kept at 0,0 - or on the zero meridian (omerbberk, #1172). diff --git a/changelog.d/1173-antimeridian-ground-floor.md b/changelog.d/1173-antimeridian-ground-floor.md deleted file mode 100644 index 939559bb5..000000000 --- a/changelog.d/1173-antimeridian-ground-floor.md +++ /dev/null @@ -1,10 +0,0 @@ -- Flights' ground floor works across the antimeridian. The viewer-distance - check behind the 150 km floor radius and its copy in the photoreal mesh-floor - sampler subtracted longitudes without wrapping, so two points 21 km apart - across 180° measured about 38,000 km and low or grounded aircraft just across - the line from the viewer were never floored. A contact's display corridor - walked a segment across 180° the long way round, spending its cell budget on - ground behind the contact, and a contact on the seam lost its cell hysteresis. - SEARCH NEARBY SITES on a view across 180° searched Google Places around - longitude 0, on the far side of the globe, with a radius sized from the view's - height alone; it now searches the view (Aditya, @Rohilalala, #1173). diff --git a/changelog.d/1186-launch-unknown-coordinates.md b/changelog.d/1186-launch-unknown-coordinates.md deleted file mode 100644 index d03c2d902..000000000 --- a/changelog.d/1186-launch-unknown-coordinates.md +++ /dev/null @@ -1,4 +0,0 @@ -- Keep missing launch-pad coordinates unknown so launches use the location - fallback or stay off the map instead of appearing at 0°N 0°E. Missing stage - flight numbers no longer show "FLIGHT 0" - (Rudy Celekli, @rudycelekli, #1186). diff --git a/changelog.d/1190-bikeshare-spain-cities.md b/changelog.d/1190-bikeshare-spain-cities.md deleted file mode 100644 index f07faa813..000000000 --- a/changelog.d/1190-bikeshare-spain-cities.md +++ /dev/null @@ -1,6 +0,0 @@ -- Add nine Spanish city bike systems to Bike Share and `get_bike_share`: BiciMAD - (Madrid), Valenbisi (Valencia), Bizi Zaragoza, Sevici (Seville), BIKI - (Valladolid), BiciCoruña, Dbizi (Donostia-San Sebastián), Bilbao Bizi and - BicinRivas, about 1,840 stations. Station names read underscores as word - breaks, and station capacity counts docks rather than PBSC's geofenced area - (ulihhhh, #1190). diff --git a/changelog.d/1197-launch-library-provider-guidance.md b/changelog.d/1197-launch-library-provider-guidance.md deleted file mode 100644 index 34cbe299e..000000000 --- a/changelog.d/1197-launch-library-provider-guidance.md +++ /dev/null @@ -1,5 +0,0 @@ -- Share Launch Library request cache keys across installations refreshing in the - same UTC minute, identify the app to the provider, and explain that standard - space-missions access needs no key. Optional higher-rate LL2 tokens are paid - upgrades; existing local cache and server-only token handling are unchanged - (rudycelekli, #1197). diff --git a/changelog.d/1199-launch-cache-provenance.md b/changelog.d/1199-launch-cache-provenance.md deleted file mode 100644 index 04f33cb7f..000000000 --- a/changelog.d/1199-launch-cache-provenance.md +++ /dev/null @@ -1,3 +0,0 @@ -- Keep Space Missions marked STALE when Launch Library 2 falls back to cached - launch data, and return to NOMINAL after a fresh response without discarding - retained missions (rudycelekli, #1199). diff --git a/changelog.d/1200-cctv-live-icon-color.md b/changelog.d/1200-cctv-live-icon-color.md deleted file mode 100644 index 30d67e1d4..000000000 --- a/changelog.d/1200-cctv-live-icon-color.md +++ /dev/null @@ -1,5 +0,0 @@ -- Color CCTV cameras with a video feed violet. Cameras with an HLS, MP4 or - WebM feed were the same cyan as stills, so a DelDOT or Statens vegvesen - video camera could only be found by opening it. Stills stay cyan and the - active camera stays amber, and focus de-emphasis fades the violet the same - way (Danielslay86, #1200). diff --git a/changelog.d/1201-cctv-stills-aspect.md b/changelog.d/1201-cctv-stills-aspect.md deleted file mode 100644 index fdb560064..000000000 --- a/changelog.d/1201-cctv-stills-aspect.md +++ /dev/null @@ -1,4 +0,0 @@ -- Draw CCTV stills at their source aspect on the monitor plane instead of - stretching them to the 16:9 canvas. Most DOT cameras publish 4:3 frames, so - every still was widened; they are now centered and pillarboxed on the dark - the placeholder already ends on (Danielslay86, #1201). diff --git a/changelog.d/1205-cctv-tool-routing.md b/changelog.d/1205-cctv-tool-routing.md deleted file mode 100644 index ed7552591..000000000 --- a/changelog.d/1205-cctv-tool-routing.md +++ /dev/null @@ -1,3 +0,0 @@ -- Report actual outcomes when voice enables or disables CCTV through the shared - layer lifecycle, including failed and cancelled changes (manjunath22466, - #1205). diff --git a/changelog.d/1207-voice-entity-labels-english.md b/changelog.d/1207-voice-entity-labels-english.md deleted file mode 100644 index b69cdc7ed..000000000 --- a/changelog.d/1207-voice-entity-labels-english.md +++ /dev/null @@ -1,3 +0,0 @@ -- Keep NASA FIRMS fire and ALPR camera labels English in voice tool results - (`track_entity`, `get_entity_context`, pointer context); the voice card still - shows them in the interface language (daikaginza, #1207). diff --git a/changelog.d/1220-openai-typed-send.md b/changelog.d/1220-openai-typed-send.md deleted file mode 100644 index cd1b5b470..000000000 --- a/changelog.d/1220-openai-typed-send.md +++ /dev/null @@ -1,3 +0,0 @@ -- Avoid starting or queuing a reply when the local channel rejects a typed OpenAI - command, while preserving an earlier accepted deferred input - (Manjunath, #1220). diff --git a/changelog.d/1222-pinokio-open-in-browser.md b/changelog.d/1222-pinokio-open-in-browser.md deleted file mode 100644 index bc6b62402..000000000 --- a/changelog.d/1222-pinokio-open-in-browser.md +++ /dev/null @@ -1,3 +0,0 @@ -- Open God's Eye View from Pinokio in the system browser using the supported - `popout` menu option. The application's framing policy is unchanged - (NukeThemAII, #1222). diff --git a/changelog.d/1225-globe-rotation.md b/changelog.d/1225-globe-rotation.md deleted file mode 100644 index 844966030..000000000 --- a/changelog.d/1225-globe-rotation.md +++ /dev/null @@ -1,2 +0,0 @@ -- Add continuous globe rotation with direction and speed controls and a globe-fit - check before starting (manjunath22466, #1225). diff --git a/changelog.d/1226-first-run-touch-dismiss.md b/changelog.d/1226-first-run-touch-dismiss.md deleted file mode 100644 index 3eb802dac..000000000 --- a/changelog.d/1226-first-run-touch-dismiss.md +++ /dev/null @@ -1,4 +0,0 @@ -- The first-run card can be closed on a phone or tablet. "ESC to dismiss" is - now a button that closes the card the same way ESC does; touch screens read - DISMISS, and phones no longer hide it, so choosing a mission is not the only - way out (KnottyDyes, #1226). diff --git a/changelog.d/1228-cctv-ontario-511-key.md b/changelog.d/1228-cctv-ontario-511-key.md deleted file mode 100644 index d9dc7986f..000000000 --- a/changelog.d/1228-cctv-ontario-511-key.md +++ /dev/null @@ -1,4 +0,0 @@ -- Load Ontario 511 cameras again. 511on.ca's camera endpoint now requires a - free developer key; set `ONTARIO_511_API_KEY` to enable the pack, which is - otherwise skipped with one log line saying where to get a key - (quanticsoul4772, #1228). diff --git a/changelog.d/1229-opensky-oauth-only.md b/changelog.d/1229-opensky-oauth-only.md deleted file mode 100644 index 25159830b..000000000 --- a/changelog.d/1229-opensky-oauth-only.md +++ /dev/null @@ -1,8 +0,0 @@ -- OpenSky sign-in matches what OpenSky accepts since 2026-03-18. The server - now reads `OPENSKY_CREDENTIALS_FILE` (the `credentials.json` OpenSky's - account page downloads) on every platform, not only through the macOS - launcher, and no longer sends retired username/password Basic auth: - `OPENSKY_AUTH_MODE=basic` loads anonymously with one warning saying what to - set instead (quanticsoul4772, #1229). -- Credential-file warnings omit parser excerpts and filesystem error details; - the path example also works with the macOS launchers. diff --git a/changelog.d/1232-gbfs-invalid-coordinates.md b/changelog.d/1232-gbfs-invalid-coordinates.md deleted file mode 100644 index 4f3da2a97..000000000 --- a/changelog.d/1232-gbfs-invalid-coordinates.md +++ /dev/null @@ -1,3 +0,0 @@ -- Skip bike-share stations with missing, blank or invalid coordinates instead - of placing them at coerced zero coordinates or accepting out-of-range values. - Explicit zero coordinates and numeric strings remain supported (Bortlesboat, #1232). diff --git a/changelog.d/1233-tarktee-datex-catalog-hardening.md b/changelog.d/1233-tarktee-datex-catalog-hardening.md deleted file mode 100644 index 39f184526..000000000 --- a/changelog.d/1233-tarktee-datex-catalog-hardening.md +++ /dev/null @@ -1,4 +0,0 @@ -- Harden the Tarktee (Estonia) DATEX2 camera catalog fetches: refuse redirects, - cancel both response streams when either response fails or overflows the 4 MB - byte cap, and deduplicate camera IDs before per-pack prioritization - (yaka0007, #1233). diff --git a/changelog.d/1234-cctv-catalog-background-refresh.md b/changelog.d/1234-cctv-catalog-background-refresh.md deleted file mode 100644 index 2d3706b14..000000000 --- a/changelog.d/1234-cctv-catalog-background-refresh.md +++ /dev/null @@ -1,5 +0,0 @@ -- Serve the camera catalog while it refreshes. An expired catalog made every - camera request wait for the slowest pack to reload; it is now answered at - once while one background refresh runs, so only the first load waits. Estonia's - slow Tarktee feeds get 30 s instead of 15 s, so the pack no longer drops out - on about a third of loads (quanticsoul4772, #1234). diff --git a/changelog.d/1235-location-resolution.md b/changelog.d/1235-location-resolution.md deleted file mode 100644 index 160688005..000000000 --- a/changelog.d/1235-location-resolution.md +++ /dev/null @@ -1,3 +0,0 @@ -- Require a geocoded containment anchor for ambiguous analyst region names, - preserve boundary provenance and cancellation safety, and retain exact-name - precedence for natural outlines (manjunath22466, #1235). diff --git a/changelog.d/1237-taiwan-freeway-cctv.md b/changelog.d/1237-taiwan-freeway-cctv.md deleted file mode 100644 index 1578971d4..000000000 --- a/changelog.d/1237-taiwan-freeway-cctv.md +++ /dev/null @@ -1,4 +0,0 @@ -- Add Taiwan's national freeway cameras from the Freeway Bureau, MOTC to CCTV: - ~1,800 cameras read at runtime from the official MOTC 2.0 open-data table, - with on-demand snapshots and attribution. No API key is required; set - `CCTV_TAIWAN_ENABLED=0` to skip it (419vive, #1237). diff --git a/changelog.d/1239-traffic-stale-flow.md b/changelog.d/1239-traffic-stale-flow.md deleted file mode 100644 index 5338e8e60..000000000 --- a/changelog.d/1239-traffic-stale-flow.md +++ /dev/null @@ -1,3 +0,0 @@ -- `get_traffic_flow` flags stale cached TomTom tiles and reports the oldest - tile fetch time (`stale`, `oldest_tile_at`), with pending freshness metadata - released on failed or cancelled tile reads (quanticsoul4772, #1239). diff --git a/changelog.d/1243-starfield-sky.md b/changelog.d/1243-starfield-sky.md deleted file mode 100644 index 04d0cfbf8..000000000 --- a/changelog.d/1243-starfield-sky.md +++ /dev/null @@ -1,5 +0,0 @@ -- Replace the blocky JPEG sky around the globe with the 9,096 stars of the - Yale Bright Star Catalogue, drawn as sharp points where they are at the - scene time, over a soft Milky Way from ESO/S. Brunier (CC BY 4.0). The Sun - and Moon stay; the anime style hides the Milky Way. Assets: 296 kB (gekh, - #1243). diff --git a/changelog.d/1244-terrain-test-cache-isolation.md b/changelog.d/1244-terrain-test-cache-isolation.md deleted file mode 100644 index 5efacd3bb..000000000 --- a/changelog.d/1244-terrain-test-cache-isolation.md +++ /dev/null @@ -1,4 +0,0 @@ -- The terrain-heights bounds tests no longer read the checkout's - `.gev-cache/terrain-heights.json`. Each test gets a cache file of its own, so - `npm test` no longer fails after the dev server has cached terrain near - Austin (KnottyDyes, #1244). diff --git a/changelog.d/1264-overpass-request-admission.md b/changelog.d/1264-overpass-request-admission.md deleted file mode 100644 index c5e763e30..000000000 --- a/changelog.d/1264-overpass-request-admission.md +++ /dev/null @@ -1,9 +0,0 @@ -- Prevent malformed Overpass filters from blocking the local server, and reject - cross-site or excessive query requests before reading their bodies - (asturksever, #1264; fixes #1248). -- Release unread responses from the optional Google-token probe so keyless - browser validation can settle; the Overpass gate recognizes only that probe's - expected 404 as an unavailable capability (asturksever, #1264). -- Make tracking arrival checks respect the aircraft update cadence while checking - orientation on the first reveal, avoiding false failures at faster render - rates (asturksever, #1264). diff --git a/changelog.d/1265-docker-trusted-peers.md b/changelog.d/1265-docker-trusted-peers.md deleted file mode 100644 index f86fe3732..000000000 --- a/changelog.d/1265-docker-trusted-peers.md +++ /dev/null @@ -1,3 +0,0 @@ -- Honor Docker Compose trusted-peer and allowed-host settings from the shell - or project `.env`, and let `GEV_KEY_SETUP_TRUSTED_PEERS=none` disable gateway - access to Provider Settings before Vite starts (asturksever, #1265). diff --git a/changelog.d/1268-radio-issue-fix.md b/changelog.d/1268-radio-issue-fix.md deleted file mode 100644 index ab68243d6..000000000 --- a/changelog.d/1268-radio-issue-fix.md +++ /dev/null @@ -1,2 +0,0 @@ -- Normalize station tags and retain valid mixed rows; skipped malformed rows still report degraded coverage (asturksever, #1268). -- Correct Radio QA push-to-talk setup to target the mounted voice controller (asturksever, #1268). diff --git a/changelog.d/1269-aircraft-issue-fix.md b/changelog.d/1269-aircraft-issue-fix.md deleted file mode 100644 index 8984a9141..000000000 --- a/changelog.d/1269-aircraft-issue-fix.md +++ /dev/null @@ -1 +0,0 @@ -- Coalesce refreshes and cool down opensky failures (asturksever, #1269). diff --git a/changelog.d/1270-space-issue-fix.md b/changelog.d/1270-space-issue-fix.md deleted file mode 100644 index b483c4c01..000000000 --- a/changelog.d/1270-space-issue-fix.md +++ /dev/null @@ -1 +0,0 @@ -- Respect provider cooldowns and bound tle groups (asturksever, #1270). diff --git a/changelog.d/1271-share-issue-fix.md b/changelog.d/1271-share-issue-fix.md deleted file mode 100644 index 7a01330ba..000000000 --- a/changelog.d/1271-share-issue-fix.md +++ /dev/null @@ -1 +0,0 @@ -- Reject inherited style keys during restore (asturksever, #1271). diff --git a/changelog.d/1272-search-issue-fix.md b/changelog.d/1272-search-issue-fix.md deleted file mode 100644 index 48b803534..000000000 --- a/changelog.d/1272-search-issue-fix.md +++ /dev/null @@ -1 +0,0 @@ -- Normalize geocoder bias across the antimeridian (asturksever, #1272). diff --git a/changelog.d/1273-history-issue-fix.md b/changelog.d/1273-history-issue-fix.md deleted file mode 100644 index f672a5c22..000000000 --- a/changelog.d/1273-history-issue-fix.md +++ /dev/null @@ -1 +0,0 @@ -- Retire unavailable history and keep local trails (asturksever, #1273). diff --git a/changelog.d/1274-import-issue-fix.md b/changelog.d/1274-import-issue-fix.md deleted file mode 100644 index 99bbc1429..000000000 --- a/changelog.d/1274-import-issue-fix.md +++ /dev/null @@ -1 +0,0 @@ -- Scan the kml root delimiter in bounded time (asturksever, #1274). diff --git a/changelog.d/1275-forecast-issue-fix.md b/changelog.d/1275-forecast-issue-fix.md deleted file mode 100644 index 2013bc4f2..000000000 --- a/changelog.d/1275-forecast-issue-fix.md +++ /dev/null @@ -1,3 +0,0 @@ -- Preserve enable during first-load replacement (asturksever, #1275). -- Release disabled weather camera listeners and make teardown resource leaks fail the browser probe (asturksever, #1275). -- Keep visible-page weather teardown probes focused through the browser testing API (asturksever, #1275). diff --git a/changelog.d/1276-terrain-issue-fix.md b/changelog.d/1276-terrain-issue-fix.md deleted file mode 100644 index 17e8f4b50..000000000 --- a/changelog.d/1276-terrain-issue-fix.md +++ /dev/null @@ -1 +0,0 @@ -- Bound each height request to one upstream chunk (asturksever, #1276). diff --git a/changelog.d/1278-overpass-issue-fix.md b/changelog.d/1278-overpass-issue-fix.md deleted file mode 100644 index 4b028f046..000000000 --- a/changelog.d/1278-overpass-issue-fix.md +++ /dev/null @@ -1 +0,0 @@ -- Reserve singleflight before disk cache reads (asturksever, #1278). diff --git a/changelog.d/1279-launch-issue-fix.md b/changelog.d/1279-launch-issue-fix.md deleted file mode 100644 index ec451e7ae..000000000 --- a/changelog.d/1279-launch-issue-fix.md +++ /dev/null @@ -1 +0,0 @@ -- Throttle mission hover picks with a trailing check for the last pointer position, and clear stale cursors (asturksever, #1279). diff --git a/changelog.d/1281-traffic-issue-fix.md b/changelog.d/1281-traffic-issue-fix.md deleted file mode 100644 index 3ce673038..000000000 --- a/changelog.d/1281-traffic-issue-fix.md +++ /dev/null @@ -1,8 +0,0 @@ -- Hold rendering only for animated content (asturksever, #1281). -- Exercise current vector road sources and published camera bounds in Traffic fixture QA (asturksever, #1281). -- Establish browser-level foreground visibility for Traffic QA and reject hidden-page samples (asturksever, #1281). -- Supply CORS headers on cross-origin traffic fixtures and report browser exceptions without disabling browser security (asturksever, #1281). -- Isolate the Traffic keyless browser scenario from the keyed page’s workers and intercepted cache (asturksever, #1281). -- Restore minimized test windows before screenshots so native compositor pauses cannot stall browser acceptance (asturksever, #1281). -- Intercept only Traffic provider URLs, leaving Cesium worker and module loading untouched (asturksever, #1281). -- Settle an unfinished Traffic height correction when the last animated point leaves, so the layer stops reporting loading once its render hold is released (asturksever, #1281). diff --git a/changelog.d/1282-polling-issue-fix.md b/changelog.d/1282-polling-issue-fix.md deleted file mode 100644 index 98885fc20..000000000 --- a/changelog.d/1282-polling-issue-fix.md +++ /dev/null @@ -1,7 +0,0 @@ -- Pause periodic network updates in hidden tabs; the overdue update on return restarts the polling schedule, so the next poll follows one interval later even when that update fails (asturksever, #1282). -- Report and guard browser visibility during Transit QA so hidden-page polling pauses cannot masquerade as playback regressions (asturksever, #1282). -- Require each live city to supply its own feed vehicles in Transit QA; retained vehicles cannot qualify another city (asturksever, #1282). -- Bound the Transit card-anchor probe by observed poll coverage instead of a fixed 20-second window (asturksever, #1282). -- Keep visible-page Transit probes focused through the browser testing API (asturksever, #1282). -- Add a real-browser regression gate for hidden-tab periodic work, explicit refresh, resume and teardown (asturksever, #1282). -- Restore minimized test windows before screenshots so native compositor pauses cannot stall browser acceptance (asturksever, #1282). diff --git a/changelog.d/1283-satellite-cache-provenance.md b/changelog.d/1283-satellite-cache-provenance.md deleted file mode 100644 index c9b0dd7dc..000000000 --- a/changelog.d/1283-satellite-cache-provenance.md +++ /dev/null @@ -1,3 +0,0 @@ -- Report cached CelesTrak satellite records as stale in the Data Layers row, - preserving separate core and dense catalog provenance through refresh, - removal and lifecycle cleanup (rudycelekli, #1283). diff --git a/changelog.d/1284-route-plausibility-segment.md b/changelog.d/1284-route-plausibility-segment.md deleted file mode 100644 index 4ab211957..000000000 --- a/changelog.d/1284-route-plausibility-segment.md +++ /dev/null @@ -1,3 +0,0 @@ -- Keep aircraft route labels on the scheduled airport leg instead of accepting - its distant great-circle extensions, preserving generous endpoint tolerance - across the signed-angle branch cut (rudycelekli, #1284). diff --git a/changelog.d/1286-since-note-inline.md b/changelog.d/1286-since-note-inline.md deleted file mode 100644 index f66467d67..000000000 --- a/changelog.d/1286-since-note-inline.md +++ /dev/null @@ -1,4 +0,0 @@ -- The Street Level SINCE note sits on the value's line, in its type and a - size smaller: with KartaView lit it reads ANY DATE (by upload date). It - had lost its size variable in the Street Level slim-down and rendered - larger than the value, on a line of its own (asturksever, #1286). diff --git a/changelog.d/1287-shared-sliders.md b/changelog.d/1287-shared-sliders.md deleted file mode 100644 index b5e5fb215..000000000 --- a/changelog.d/1287-shared-sliders.md +++ /dev/null @@ -1,3 +0,0 @@ -- Give ordinary sliders a shared native control and consistent track, thumb, - value, focus and disabled styling while preserving feature behavior and - specialized controls (mazy1998, #1287). diff --git a/changelog.d/1288-zoomfor-legacy-shape.md b/changelog.d/1288-zoomfor-legacy-shape.md deleted file mode 100644 index e23b524e8..000000000 --- a/changelog.d/1288-zoomfor-legacy-shape.md +++ /dev/null @@ -1,4 +0,0 @@ -- A Street Level provider whose `zoomFor` still answers `{zoom, kind}`, the - shape before the core went slim, draws its lines again instead of a silent - blank; an overview level or any answer that is not a whole zoom shows the - zoom-in hint (asturksever, #1288). diff --git a/changelog.d/1297-s2-ghostmaps-layer.md b/changelog.d/1297-s2-ghostmaps-layer.md deleted file mode 100644 index 7dd52862d..000000000 --- a/changelog.d/1297-s2-ghostmaps-layer.md +++ /dev/null @@ -1,14 +0,0 @@ -- Add the S2 GhostMaps layer: S2 Underground's public KMZ intel products - (Common Intelligence Picture, 30-day kinetic pull, Border Crisis Map, Iran - and Yemen products and the newest incident drop) from - github.com/s2underground/GhostMaps, with one chip per product and report - cards on click. `/api/ghostmaps` watches the repository's branch head every - 15 s and pushes each new commit to open pages, which reload only the - products that changed (Black Pine Defense). -- Clear a temporary GhostMaps upstream error and notify open pages when the - repository becomes reachable again, including when no new edition was published. -- Release packed-image resources when a load is cancelled or fails, respect - injected or omitted GhostMaps sources, and wait for background cache warm-up - before removing provider test fixtures. -- Include Simplified Chinese translations and keep the combined voice prompt - within its existing size limit while retaining all spoken aliases. diff --git a/changelog.d/1298-simplified-chinese.md b/changelog.d/1298-simplified-chinese.md deleted file mode 100644 index d35d08cf1..000000000 --- a/changelog.d/1298-simplified-chinese.md +++ /dev/null @@ -1,4 +0,0 @@ -- Add Simplified Chinese (zh-CN) to the language picker, with localized dates - and readable Chinese labels. Based on translations by @abiyeenzo (#914) - and @EDIT-Aeterna (#979). - (German, @gekh, #1298). diff --git a/changelog.d/1299-voice-panel-settings.md b/changelog.d/1299-voice-panel-settings.md deleted file mode 100644 index 1a95a6ed4..000000000 --- a/changelog.d/1299-voice-panel-settings.md +++ /dev/null @@ -1,5 +0,0 @@ -- Add a shared Voice Preview and Settings panel with browser-local preferences, - inactivity controls and accessible floating provider controls on compact layouts; - recover inactivity after confirmed audio-less replies, release retired audio - observers and keep cost warnings visible outside Settings - (manjunath22466, #1299). diff --git a/changelog.d/1301-shared-segmented-selectors.md b/changelog.d/1301-shared-segmented-selectors.md deleted file mode 100644 index 379b8c716..000000000 --- a/changelog.d/1301-shared-segmented-selectors.md +++ /dev/null @@ -1,5 +0,0 @@ -- Unify segmented selectors for model coverage, detection allocation, drawing - shape, Street View and imagery comparison while preserving their existing - behavior. Keep compact labels such as FILL and FLAT on one line, and let - collapsed Weather release space to the open rail panel. Reserve the full mode - button height in Recent Imagery so keyboard focus is not clipped (mazy1998, #1301). diff --git a/changelog.d/1302-shared-action-buttons.md b/changelog.d/1302-shared-action-buttons.md deleted file mode 100644 index 3c8318488..000000000 --- a/changelog.d/1302-shared-action-buttons.md +++ /dev/null @@ -1,3 +0,0 @@ -- Give ordinary Scene and CCTV actions shared native buttons with consistent - default, destructive and compact styling while preserving their existing - behavior and specialized controls (mazy1998, #1302). diff --git a/changelog.d/1303-wind-stale.md b/changelog.d/1303-wind-stale.md deleted file mode 100644 index cb54224a5..000000000 --- a/changelog.d/1303-wind-stale.md +++ /dev/null @@ -1,2 +0,0 @@ -- `get_wind` flags stale forecasts (`stale`) when the wind proxy serves a - cached model run (quanticsoul4772, #1303). diff --git a/changelog.d/1304-antimeridian-distances.md b/changelog.d/1304-antimeridian-distances.md deleted file mode 100644 index fc7744f86..000000000 --- a/changelog.d/1304-antimeridian-distances.md +++ /dev/null @@ -1,2 +0,0 @@ -- Point distances wrap longitude differences across the antimeridian, in voice - proximity checks and `places_nearby` (quanticsoul4772, #1304). diff --git a/changelog.d/1305-shared-native-form-fields.md b/changelog.d/1305-shared-native-form-fields.md deleted file mode 100644 index 129d81bcf..000000000 --- a/changelog.d/1305-shared-native-form-fields.md +++ /dev/null @@ -1,3 +0,0 @@ -- Share native dropdown and numeric-field styling across Scene, CCTV, Display - and Radio controls, with a shared CCTV number-input builder that preserves - existing precision, validation and commit behavior (mazy1998, #1305). diff --git a/changelog.d/1306-shared-status-badges.md b/changelog.d/1306-shared-status-badges.md deleted file mode 100644 index 007a028d1..000000000 --- a/changelog.d/1306-shared-status-badges.md +++ /dev/null @@ -1,4 +0,0 @@ -- Share read-only status badge presentation across CCTV source/frame labels, - calibration provenance and Weather coverage, preserving status meanings, - palettes, translations and announcements while preparing the view contract - for a future Vue migration (mazy1998, #1306). diff --git a/changelog.d/1309-shared-field-css-ownership.md b/changelog.d/1309-shared-field-css-ownership.md deleted file mode 100644 index 1b8817bac..000000000 --- a/changelog.d/1309-shared-field-css-ownership.md +++ /dev/null @@ -1,3 +0,0 @@ -- Clarify shared field CSS ownership: CCTV owns calibration editor sizing, - while Radio and Cyber supply explicit field palettes without changing the - current appearance or native control behavior (mazy1998, #1309). diff --git a/changelog.d/1317-provider-response-hardening.md b/changelog.d/1317-provider-response-hardening.md deleted file mode 100644 index 398688fc0..000000000 --- a/changelog.d/1317-provider-response-hardening.md +++ /dev/null @@ -1 +0,0 @@ -- Validate provider response formats, strengthen camera source checks, and apply consistent API response protections (samehkhamis, #1317). diff --git a/changelog.d/1321-dead-code-cleanup.md b/changelog.d/1321-dead-code-cleanup.md deleted file mode 100644 index e8cad2a23..000000000 --- a/changelog.d/1321-dead-code-cleanup.md +++ /dev/null @@ -1,6 +0,0 @@ -- Remove dead code across the repository: three modules nothing imports - (`src/ui.js`, `src/standalone/ui.js`, `src/data/localLayers.js`), exports - and locals nothing reads, a duplicate copy of the bundled dams data and an - unused ship model. The app no longer builds an unused default wind layer - and Bhote Koshi locator layer when it loads. Package exports are unchanged - (samehkhamis, #1321). diff --git a/changelog.d/1324-street-level-provider-exports.md b/changelog.d/1324-street-level-provider-exports.md deleted file mode 100644 index a3dc4cb6b..000000000 --- a/changelog.d/1324-street-level-provider-exports.md +++ /dev/null @@ -1,8 +0,0 @@ -- Export the KartaView and Panoramax Street Level providers, so a host composing - its own provider list can offer the keyless providers without Mapillary - (samehkhamis, #1324). -- A Mapillary source can take a `graphEndpoint`, a Graph API base that adds the - token itself (such as a same-origin proxy). Its sequence lookups go there - through the source's transport, and the photo viewer uses MapillaryJS's - Graph provider at that endpoint, so no client token is needed in the page - (samehkhamis, #1324). diff --git a/changelog.d/1325-phone-layout.md b/changelog.d/1325-phone-layout.md deleted file mode 100644 index c1653df62..000000000 --- a/changelog.d/1325-phone-layout.md +++ /dev/null @@ -1,4 +0,0 @@ -- Add a phone layout for viewports 720px and narrower: the globe stays full - screen and a bottom tab bar (Layers, Cameras, Context, Search, More) opens one - panel sheet at a time, keeping attribution visible and scene STOP reachable. - Adapted from the phone tab-shell in #203 by blearymoth (samehkhamis, #1325). diff --git a/changelog.d/1326-terrain-cache-eviction.md b/changelog.d/1326-terrain-cache-eviction.md deleted file mode 100644 index ccb374ccd..000000000 --- a/changelog.d/1326-terrain-cache-eviction.md +++ /dev/null @@ -1,3 +0,0 @@ -- Evict terrain-height cache entries in fetch-time order without repeatedly - sorting the full cache, while keeping refreshed points newest and ordering - restored entries by their fetch time (daikaginza, #1326). diff --git a/changelog.d/1338-mobile-contact-context.md b/changelog.d/1338-mobile-contact-context.md deleted file mode 100644 index e240dc82a..000000000 --- a/changelog.d/1338-mobile-contact-context.md +++ /dev/null @@ -1,4 +0,0 @@ -- Improve touch selection of aircraft and vessels through the shared contact - picker, reveal tracked aircraft details when opening Context, support downward - swipe dismissal of phone drawers while preserving scrolling and controls, and - enlarge the phone logo (samehkhamis, #1338). diff --git a/changelog.d/1339-hud-dms-carry.md b/changelog.d/1339-hud-dms-carry.md deleted file mode 100644 index 588668afe..000000000 --- a/changelog.d/1339-hud-dms-carry.md +++ /dev/null @@ -1,3 +0,0 @@ -- Carry HUD LAT/LON seconds that round up to 60.00" into the minutes and - degrees, so longitude -122.35 reads `122°21'00.00"W` instead of - `122°20'60.00"W` (rudycelekli, #1339). diff --git a/changelog.d/1340-search-separated-hemisphere.md b/changelog.d/1340-search-separated-hemisphere.md deleted file mode 100644 index 5b89020e4..000000000 --- a/changelog.d/1340-search-separated-hemisphere.md +++ /dev/null @@ -1,3 +0,0 @@ -- Read a hemisphere letter that is separated from its number, so a search for - `40.7128 N 74.0060 W` flies there instead of falling through to the geocoders - (Rudy Celekli, @rudycelekli, #1340). diff --git a/changelog.d/1341-kartaview-impossible-timestamps.md b/changelog.d/1341-kartaview-impossible-timestamps.md deleted file mode 100644 index 302ff38f4..000000000 --- a/changelog.d/1341-kartaview-impossible-timestamps.md +++ /dev/null @@ -1,3 +0,0 @@ -- Reject impossible KartaView photo timestamps, so 31 February is unknown - instead of rolling forward into March and passing the imagery date filter - (Rudy Celekli, @rudycelekli, #1341). diff --git a/changelog.d/1342-firms-acquisition-calendar.md b/changelog.d/1342-firms-acquisition-calendar.md deleted file mode 100644 index e0003636d..000000000 --- a/changelog.d/1342-firms-acquisition-calendar.md +++ /dev/null @@ -1,3 +0,0 @@ -- Keep an impossible wildfire acquisition date off the detection clock, so a - fire is not labeled with a later day it did not happen - (Rudy Celekli, @rudycelekli, #1342). diff --git a/changelog.d/1343-route-ramp-lane-wording.md b/changelog.d/1343-route-ramp-lane-wording.md deleted file mode 100644 index 4f6817e9c..000000000 --- a/changelog.d/1343-route-ramp-lane-wording.md +++ /dev/null @@ -1,4 +0,0 @@ -- Phrase slight and sharp ramps as directions, so a ramp reads "slightly left" - instead of "on the slightly left", and a lane names its side in both - the proxy response and localized browser instructions - (Rudy Celekli, @rudycelekli, #1343). diff --git a/changelog.d/1345-weather-staging-wake.md b/changelog.d/1345-weather-staging-wake.md deleted file mode 100644 index fec4d54ec..000000000 --- a/changelog.d/1345-weather-staging-wake.md +++ /dev/null @@ -1,3 +0,0 @@ -- Wake staged weather imagery on a 150 ms timer while waiting for readiness, - avoiding a continuous render loop and cancelling the wake when work ends - (@nu-stats, #1345). diff --git a/changelog.d/1349-cyclone-classification-codes.md b/changelog.d/1349-cyclone-classification-codes.md deleted file mode 100644 index c22debfa1..000000000 --- a/changelog.d/1349-cyclone-classification-codes.md +++ /dev/null @@ -1,3 +0,0 @@ -- Label NHC cyclone classifications by their published meanings: `PTC` is a - post-tropical cyclone, `PC` a potential tropical cyclone, and subtropical - systems arrive as `STS` and `STD` (rudycelekli, #1349). diff --git a/changelog.d/1350-cyclone-movement-knots.md b/changelog.d/1350-cyclone-movement-knots.md deleted file mode 100644 index 3fc8c8f9f..000000000 --- a/changelog.d/1350-cyclone-movement-knots.md +++ /dev/null @@ -1,3 +0,0 @@ -- Convert NHC cyclone movement speed from miles per hour to knots, so - `movement.speedKt` in cyclone query results is no longer about 15% high - (rudycelekli, #1350). diff --git a/changelog.d/1351-ais-static-keeps-motion.md b/changelog.d/1351-ais-static-keeps-motion.md deleted file mode 100644 index 52dd9bede..000000000 --- a/changelog.d/1351-ais-static-keeps-motion.md +++ /dev/null @@ -1,6 +0,0 @@ -- Keep a tracked vessel's speed, course, heading and fix time when AISStream - static data arrives; the static message only merges name, type, destination - and IMO (rudycelekli, #1351). -- Apply changed static metadata immediately, retaining known fields when a - later static report omits them, without refreshing the vessel's position - (samehkhamis, #1351). diff --git a/changelog.d/1352-cockpit-destination-heading.md b/changelog.d/1352-cockpit-destination-heading.md deleted file mode 100644 index c7a5ea9b5..000000000 --- a/changelog.d/1352-cockpit-destination-heading.md +++ /dev/null @@ -1,3 +0,0 @@ -- Read a destination heading that rounds to north as 000. 359.6° was shown as - 360° on the destination bearing while the compass tape already uses 000 - (Rudy Celekli, @rudycelekli, #1352). diff --git a/changelog.d/1353-transit-ninety-second-age.md b/changelog.d/1353-transit-ninety-second-age.md deleted file mode 100644 index 50611060d..000000000 --- a/changelog.d/1353-transit-ninety-second-age.md +++ /dev/null @@ -1,3 +0,0 @@ -- Count a transit report that is 90 seconds old as one minute. The card kept - seconds through 89s, then rounded 90s up to "Reported 2 min ago" - (Rudy Celekli, @rudycelekli, #1353). diff --git a/changelog.d/1354-firms-frp-ten-megawatts.md b/changelog.d/1354-firms-frp-ten-megawatts.md deleted file mode 100644 index 394eba1df..000000000 --- a/changelog.d/1354-firms-frp-ten-megawatts.md +++ /dev/null @@ -1,3 +0,0 @@ -- Drop the decimal when fire radiative power rounds to 10 MW. A 9.96 MW - detection was labeled 10.0 MW because the one-decimal cutoff ran before - rounding (Rudy Celekli, @rudycelekli, #1354). diff --git a/changelog.d/1366-aircraft-models-no-environment-map.md b/changelog.d/1366-aircraft-models-no-environment-map.md deleted file mode 100644 index 8c5ad49c3..000000000 --- a/changelog.d/1366-aircraft-models-no-environment-map.md +++ /dev/null @@ -1,5 +0,0 @@ -- Aircraft 3D models (Flights, Military Flights, Local ADS-B) skip Cesium's - dynamic environment map, a sky render and GPU readback per model. With - ~150 models in the scene at Atlanta on Google 3D, GPU time per frame at - rest falls from 14.3-14.8 ms to 12.1-12.5 ms; a same-model comparison - showed no visible change (quanticsoul4772, #1366). diff --git a/changelog.d/1367-turned-off-layer-memory.md b/changelog.d/1367-turned-off-layer-memory.md deleted file mode 100644 index 08bbbad81..000000000 --- a/changelog.d/1367-turned-off-layer-memory.md +++ /dev/null @@ -1,4 +0,0 @@ -- Turning a layer off frees the memory its entities held. Cesium kept - removed layers' draw commands in reused per-pass arrays, so Data Centers - kept 116 MiB after it was switched off, submarine cables 74 MiB and dams - 30 MiB; they now keep 13, 9 and 9 MiB (quanticsoul4772, #1367). diff --git a/changelog.d/1378-touch-zoom-aircraft-updates.md b/changelog.d/1378-touch-zoom-aircraft-updates.md deleted file mode 100644 index 81acefb00..000000000 --- a/changelog.d/1378-touch-zoom-aircraft-updates.md +++ /dev/null @@ -1,5 +0,0 @@ -- Increase touch-first globe zoom sensitivity to three times the default while - retaining Cesium collision and distance limits. -- Reuse one delayed display timestamp per civil-aircraft fleet update and cache - extrapolation coordinate frames until their fix coordinates change. Preserve - contact counts, movement cadence, tracked motion and ground corrections. diff --git a/changelog.d/1379-aircraft-label-candidates.md b/changelog.d/1379-aircraft-label-candidates.md deleted file mode 100644 index f51ff101d..000000000 --- a/changelog.d/1379-aircraft-label-candidates.md +++ /dev/null @@ -1,4 +0,0 @@ -- Reduce repeated work in aircraft detection candidates by caching unchanged - callsign/registration text and reusing resolved fleet models. Metadata updates, - live positions and tracked-aircraft/model handoffs remain immediate - (samehkhamis, #1379). diff --git a/changelog.d/1384-hud-summary-moving.md b/changelog.d/1384-hud-summary-moving.md deleted file mode 100644 index 21965af96..000000000 --- a/changelog.d/1384-hud-summary-moving.md +++ /dev/null @@ -1,4 +0,0 @@ -- The HUD's AI place summary drops a reply that arrives after the camera has - started moving, so a summary asked for before a flight no longer names the - old place mid-flight. Cancelled or partially typed summaries retry even if the place - context stays the same (quanticsoul4772, #1384). diff --git a/changelog.d/1385-route-duration-minute.md b/changelog.d/1385-route-duration-minute.md deleted file mode 100644 index fa354766b..000000000 --- a/changelog.d/1385-route-duration-minute.md +++ /dev/null @@ -1,3 +0,0 @@ -- Show a route leg of 59.5 seconds or more as 1 min. The route summary and step - cards kept seconds below 60, then rounded 59.6 s up to "60 s" - (Rudy Celekli, @rudycelekli, #1385). diff --git a/changelog.d/1386-route-distance-kilometre.md b/changelog.d/1386-route-distance-kilometre.md deleted file mode 100644 index 0a60fcc62..000000000 --- a/changelog.d/1386-route-distance-kilometre.md +++ /dev/null @@ -1,3 +0,0 @@ -- Show a route leg of 995 m or more as 1.0 km. The route summary and step - cards kept meters below 1000, then rounded 996 m up to "1000 m" - (Rudy Celekli, @rudycelekli, #1386). diff --git a/changelog.d/1387-awareness-distance-kilometre.md b/changelog.d/1387-awareness-distance-kilometre.md deleted file mode 100644 index 4414b7c5f..000000000 --- a/changelog.d/1387-awareness-distance-kilometre.md +++ /dev/null @@ -1,3 +0,0 @@ -- Show a Contacts entry 999.5 m or more away as 1.0 km. The panel kept meters - below 1000, then rounded 999.6 m up to "1000 m" - (Rudy Celekli, @rudycelekli, #1387). diff --git a/changelog.d/1388-draw-line-kilometre.md b/changelog.d/1388-draw-line-kilometre.md deleted file mode 100644 index 137075707..000000000 --- a/changelog.d/1388-draw-line-kilometre.md +++ /dev/null @@ -1,3 +0,0 @@ -- Show a drawn line of 999.5 m or more as 1.0 km. The draw hint kept metres - below 1000, then rounded 999.6 m up to "1000 m" - (Rudy Celekli, @rudycelekli, #1388). diff --git a/changelog.d/1389-cockpit-wind-north.md b/changelog.d/1389-cockpit-wind-north.md deleted file mode 100644 index cc81c362e..000000000 --- a/changelog.d/1389-cockpit-wind-north.md +++ /dev/null @@ -1,3 +0,0 @@ -- Show cockpit wind from 359.5° or more as 0°, not 360°. Rounding 359.6° - printed "N · 360°" on the local wind direction - (Rudy Celekli, @rudycelekli, #1389). diff --git a/changelog.d/1390-awareness-bearing-north.md b/changelog.d/1390-awareness-bearing-north.md deleted file mode 100644 index af7fb4da3..000000000 --- a/changelog.d/1390-awareness-bearing-north.md +++ /dev/null @@ -1,2 +0,0 @@ -- Render awareness-overlay bearings and courses that round through north as - `000°`, rather than `360°` (Rudy Celekli, #1390). diff --git a/changelog.d/1391-docker-selinux.md b/changelog.d/1391-docker-selinux.md deleted file mode 100644 index 186147a2e..000000000 --- a/changelog.d/1391-docker-selinux.md +++ /dev/null @@ -1,4 +0,0 @@ -- Start the Docker install on SELinux hosts such as Fedora and RHEL. Compose now - mounts the checkout with `:z`; without it the container could not read `/app` - and stopped with "Cannot find module '/app/scripts/docker-start.mjs'" - (Anıl Güvenç, @anilguvenc, #1391). diff --git a/changelog.d/1394-docker-healthcheck.md b/changelog.d/1394-docker-healthcheck.md deleted file mode 100644 index 75ead9667..000000000 --- a/changelog.d/1394-docker-healthcheck.md +++ /dev/null @@ -1,2 +0,0 @@ -- Report Docker container health with a local HTTP check using Node, with the - same port parsing as the launcher (John Rogers, @14traits, #1394). diff --git a/changelog.d/1395-fires-tool-acquired-time.md b/changelog.d/1395-fires-tool-acquired-time.md deleted file mode 100644 index 17d74e481..000000000 --- a/changelog.d/1395-fires-tool-acquired-time.md +++ /dev/null @@ -1,6 +0,0 @@ -- Report a fire detection's acquisition time as a UTC timestamp in - `get_active_fires`. The tool joined FIRMS's unpadded date and time, so a - 00:45 UTC detection read "2026-01-01 45"; it now reads - `2026-01-01T00:45:00.000Z`. Missing or invalid dates and times remain - unknown rather than rolling into another calendar day - (Rudy Celekli, @rudycelekli, #1395). diff --git a/changelog.d/1396-local-adsb-track-north.md b/changelog.d/1396-local-adsb-track-north.md deleted file mode 100644 index 9235a19a3..000000000 --- a/changelog.d/1396-local-adsb-track-north.md +++ /dev/null @@ -1,3 +0,0 @@ -- Show a locally heard aircraft tracking 359.5° or more as TRK 0°. The Local - ADS-B card rounded the track without wrapping, so 359.7° read "TRK 360°" - (Rudy Celekli, @rudycelekli, #1396). diff --git a/changelog.d/1398-sharpen-zero-off.md b/changelog.d/1398-sharpen-zero-off.md deleted file mode 100644 index ab05aa6f2..000000000 --- a/changelog.d/1398-sharpen-zero-off.md +++ /dev/null @@ -1,2 +0,0 @@ -- The Sharpen slider at 0 now turns the sharpen pass off instead of still - sharpening at a low amount (quanticsoul4772, #1398). diff --git a/changelog.d/1399-ground-snap-clock-step.md b/changelog.d/1399-ground-snap-clock-step.md deleted file mode 100644 index 73196986a..000000000 --- a/changelog.d/1399-ground-snap-clock-step.md +++ /dev/null @@ -1,3 +0,0 @@ -- Aircraft on the ground keep getting ground-height samples after the - computer's clock steps back, instead of waiting for it to catch up - (quanticsoul4772, #1399). diff --git a/changelog.d/1403-remove-unused-modules.md b/changelog.d/1403-remove-unused-modules.md deleted file mode 100644 index da95c7dcd..000000000 --- a/changelog.d/1403-remove-unused-modules.md +++ /dev/null @@ -1,5 +0,0 @@ -- Remove four modules nothing in the app imports: `src/app/sourceSlot.js`, - `src/data/flowTiles.js`, `src/data/issPass.js` and `src/data/localGeojson.js`. - The local GeoJSON layer tests now build layers the way the catalog does, so - they keep covering `localGeojsonCore.js`. Package exports are unchanged - (samehkhamis, #1403). diff --git a/changelog.d/1410-scope-controls-hud-readability.md b/changelog.d/1410-scope-controls-hud-readability.md deleted file mode 100644 index 38cfdf48e..000000000 --- a/changelog.d/1410-scope-controls-hud-readability.md +++ /dev/null @@ -1,8 +0,0 @@ -- Add a Scope checkbox and extend feathering to 200%, retaining scope settings - across HUD layouts, share links and scenes. First run opens with Scope ON at - 100% feather; explicit settings and historical links retain their values. Give - Tactical, Operator and Minimal text black backplates only when Scope is OFF, - including vertical metadata, without changing the original HUD text color, glow or - opacity. Scope ON retains its original HUD presentation (bilawalsidhu, #1410). - Keep title and tagline positions stable when toggling Scope, include the eye - in the title backing, and brighten the two secondary labels only with Scope OFF. diff --git a/changelog.d/1416-share-hash-navigation.md b/changelog.d/1416-share-hash-navigation.md deleted file mode 100644 index 0effac1cb..000000000 --- a/changelog.d/1416-share-hash-navigation.md +++ /dev/null @@ -1,4 +0,0 @@ -- Restore a share link opened in an already-open tab. Pasting a link into the - address bar, following one, or using Back/Forward now moves the camera and - restores the style, map, panels and layers instead of changing only the URL - (samehkhamis, #1416). diff --git a/changelog.d/1417-clear-all-saved-layers.md b/changelog.d/1417-clear-all-saved-layers.md deleted file mode 100644 index 8cffbd366..000000000 --- a/changelog.d/1417-clear-all-saved-layers.md +++ /dev/null @@ -1,3 +0,0 @@ -- Make Clear All clear the saved and shared layer selection. Layers that a - context mode had already switched off no longer stay in the share link and - come back on reload (samehkhamis, #1417). diff --git a/changelog.d/1418-short-share-links.md b/changelog.d/1418-short-share-links.md deleted file mode 100644 index 8dce5761f..000000000 --- a/changelog.d/1418-short-share-links.md +++ /dev/null @@ -1,5 +0,0 @@ -- Share links are now short: the share button makes `/share/` links - that open on any copy of the app, follow the aircraft, military aircraft or - satellite you were following, and fall back to its last-known position with - a notice if it isn't reporting. A mistyped link is refused instead of - opening a different view. Long `#v=2` links keep working (samehkhamis, #1418). diff --git a/changelog.d/1419-share-view-codec-export.md b/changelog.d/1419-share-view-codec-export.md deleted file mode 100644 index e3ce1b105..000000000 --- a/changelog.d/1419-share-view-codec-export.md +++ /dev/null @@ -1,4 +0,0 @@ -- Hosts can read share links on their server: the share-link codec and the - `/share/` address helpers are now package exports, - `@gods-eye-view/core/share/view-codec` and `@gods-eye-view/core/share/link-path` - (samehkhamis, #1419). diff --git a/changelog.d/1420-keep-missed-location-query.md b/changelog.d/1420-keep-missed-location-query.md deleted file mode 100644 index 233abf495..000000000 --- a/changelog.d/1420-keep-missed-location-query.md +++ /dev/null @@ -1,4 +0,0 @@ -- Keep a location search that found nothing, or failed, in the field so it can - be corrected: the query stays, focused and selected, and a persistent - announced message under the search row says what to do next, instead of a - toast followed by a cleared and closed field (samehkhamis, #1420). diff --git a/changelog.d/1421-style-modules-skip-catalogs.md b/changelog.d/1421-style-modules-skip-catalogs.md deleted file mode 100644 index bc79c5cd6..000000000 --- a/changelog.d/1421-style-modules-skip-catalogs.md +++ /dev/null @@ -1,3 +0,0 @@ -- The visual styles and their presets mark their labels with the catalog-free - `msg()`, so the share-link codec, and any server that loads it, no longer - bundles every translation catalog (about 0.9 MB) (samehkhamis, #1421). diff --git a/changelog.d/1431-street-level-bearing-north.md b/changelog.d/1431-street-level-bearing-north.md deleted file mode 100644 index f30084b71..000000000 --- a/changelog.d/1431-street-level-bearing-north.md +++ /dev/null @@ -1,3 +0,0 @@ -- Show a Street Level view facing 359.5° or more as 0°. The viewer caption - rounded the bearing without wrapping, so a view facing 359.6° read "360°" - (Aditya, @Rohilalala, #1431). diff --git a/changelog.d/287-shared-great-circle-distance.md b/changelog.d/287-shared-great-circle-distance.md deleted file mode 100644 index c2db9d54d..000000000 --- a/changelog.d/287-shared-great-circle-distance.md +++ /dev/null @@ -1,5 +0,0 @@ -- The client's great-circle distances now come from one shared - `src/geoDistance.js` (`greatCircleKm`/`greatCircleMeters`, `{lat, lon}` - points). The Earth radius is standardized on 6371.0088 km, so distances shift - by about 1.4 ppm and region areas by about 2.8 ppm, and missing or - out-of-range points return `Infinity` (onionviolet, #287; Rajojha-1, #749). diff --git a/changelog.d/605-fl511-florida-cameras.md b/changelog.d/605-fl511-florida-cameras.md deleted file mode 100644 index 76f840198..000000000 --- a/changelog.d/605-fl511-florida-cameras.md +++ /dev/null @@ -1,9 +0,0 @@ -- Add FL511 (Florida DOT) traffic cameras as an opt-in CCTV source pack: - the statewide ArcGIS catalog, read a page at a time under a byte cap with - redirects refused, and frames pinned to FL511's two image hosts over HTTPS. - FL511's terms limit its content to individual, personal use, and any other - use (a public deployment included) needs FDOT's express written consent, so - the pack stays off unless `CCTV_FLORIDA_ENABLED=1`. Headings come from the - catalog's direction codes, and camera ids come from the image channel, since - the catalog's ID column repeats across regions. `CCTV_FLORIDA_MAX_SOURCES` - sets the cap (Danielslay86, #605). diff --git a/changelog.d/686-terrain-heights-bounds.md b/changelog.d/686-terrain-heights-bounds.md deleted file mode 100644 index 7e0004069..000000000 --- a/changelog.d/686-terrain-heights-bounds.md +++ /dev/null @@ -1,9 +0,0 @@ -- Bound what a caller can grow through `/api/terrain/heights`. Every distinct - 5-decimal point was a permanent in-memory entry, a permanent line in an - uncapped `.gev-cache/terrain-heights.json`, and a live upstream call, with - nothing limiting the rate. The point cache now holds at most 50,000 entries - and evicts oldest-first, a cache file above - 24 MB is not read back, and the route is limited to 90 requests/minute per - client (270 global). Evicting a point costs one refetch, never a wrong - answer, since terrain does not move. Ordinary use is unaffected: a full - `test:track` run drives 10 requests, peaking at 8/min (daikaginza, #686). diff --git a/changelog.d/761-dev-unwatched-runtime-dirs.md b/changelog.d/761-dev-unwatched-runtime-dirs.md deleted file mode 100644 index d3aaf0a91..000000000 --- a/changelog.d/761-dev-unwatched-runtime-dirs.md +++ /dev/null @@ -1,5 +0,0 @@ -- The dev server no longer watches `.gev-cache` and `.gev-logs`. Providers write - cache files and logs there while the app runs, and none of it is source, so - the watcher now skips it; this guards against the DNS-lookup delays heavy - cache writes have caused, though no difference was measured on current main - (monwiss, #761). diff --git a/changelog.d/767-alpha5-catalog-numbers.md b/changelog.d/767-alpha5-catalog-numbers.md deleted file mode 100644 index 8a96698a1..000000000 --- a/changelog.d/767-alpha5-catalog-numbers.md +++ /dev/null @@ -1,11 +0,0 @@ -- Read satellite catalog numbers written in Alpha-5, the TLE spelling of - numbers above 99999: a letter for the first two digits, skipping I and O - (`A0000` is 100000, `Z9999` is 339999). The satellites layer converted such a - field to `NaN`, so every Alpha-5 satellite shared one catalog entry and all - but the first were dropped as duplicates; the satellite tools read the same - field as no number, so such a satellite could not be found by it. The layer - and the tools now decode the field in `src/sources/tle.js`, and reject a - malformed one (a sign, decimal point, hex, embedded space or stray letter) - instead of reading part of it as a number. This is Alpha-5 TLE - compatibility: CelesTrak's TLE feed carries no satellite above 99999, which - needs the OMM feed (#1191) (Honorius Neogy, #767, fixes #751). diff --git a/changelog.d/787-changelog-fragments.md b/changelog.d/787-changelog-fragments.md deleted file mode 100644 index 41509c046..000000000 --- a/changelog.d/787-changelog-fragments.md +++ /dev/null @@ -1,7 +0,0 @@ -- Changelog entries are now one file per pull request. A change adds - `changelog.d/-.md` instead of editing the top of - `CHANGELOG.md`, which two pull requests in flight could not share — it was the - most frequent merge conflict in the open queue, and for six of them the only - one. `npm run changelog` splices the directory into `CHANGELOG.md` at release - time and empties it; `npm run changelog:check` reports the batch and changes - nothing. Fragment text is copied through unchanged (daikaginza, #787). diff --git a/changelog.d/816-radio-owner-restoration.md b/changelog.d/816-radio-owner-restoration.md deleted file mode 100644 index df38617ee..000000000 --- a/changelog.d/816-radio-owner-restoration.md +++ /dev/null @@ -1,7 +0,0 @@ -- Close the compact Radio disclosure when an adaptive tactical right-rail - restore directly expands Context, before Space Missions can be covered. - A repeated Context-open request also clears stale disclosure state. - Real PanelChrome constructor wiring and the rail reflow path are covered - by focused regressions. Credits: kvnloo (#816), raysung-2026's original - #804 report, asturksever's review, and quanticsoul4772's independent - Windows diagnosis. diff --git a/changelog.d/872-gemini-live-voice.md b/changelog.d/872-gemini-live-voice.md deleted file mode 100644 index 519e4d37b..000000000 --- a/changelog.d/872-gemini-live-voice.md +++ /dev/null @@ -1,4 +0,0 @@ -- Add optional Gemini Live voice to the standalone app, with a provider chooser, - server-held API key, microphone streaming, shared map actions and captions. - Switching providers ends the old conversation and preserves the input mode - (Manjunath, #872). diff --git a/changelog.d/880-world-packet-boundary.md b/changelog.d/880-world-packet-boundary.md deleted file mode 100644 index 7ee574e35..000000000 --- a/changelog.d/880-world-packet-boundary.md +++ /dev/null @@ -1,6 +0,0 @@ -- Extract a reusable model-free World Packet from the existing voice - `get_current_view_state` owner without restoring disabled layers to the - model context. Keep the enabled-only payload, disabled-layer count, source - provenance, action result and view-state contract; read the layer roster once - per packet; voice retains the speech/card envelope at its own boundary. - Credits: original GEV voice/layer contributors and #880 implementation. diff --git a/changelog.d/945-cctv-vegvesen-kartverket-heights.md b/changelog.d/945-cctv-vegvesen-kartverket-heights.md deleted file mode 100644 index 1572c0316..000000000 --- a/changelog.d/945-cctv-vegvesen-kartverket-heights.md +++ /dev/null @@ -1,17 +0,0 @@ -- Give each Statens vegvesen camera its own ground height from Kartverket's - keyless point-height API (CC BY 4.0) instead of one flat 150 m prior, so - mountain-pass cameras no longer sit hundreds of metres below the terrain - where neither the point-height prior nor the ground snap resolves. About 850 - of ~855 cameras get a height; the rest keep the old prior. Requests carry 20 - points, the most the API answers from its 1 m terrain model, eight at a - time; a cold lookup takes about 6–13 s. Cameras over water use the water - surface rather than the sea-floor depth the API returns there; for bridge - cameras that is still below the deck. Heights are cached for good and misses - for 6 h, so a refresh only asks about new or moved cameras. After a - failing request (a 408, 429 or 5xx, a network error, a request over 10 s or - an unreadable body) the lookup stops and backs off (Retry-After, else - 30 min, longer than the refresh). The lane waits at most 12 s from its - start, and only on a cold cache; a slower first lookup leaves the cameras it - had not reached on the flat prior until the next 15-minute refresh, and - keeps filling the cache meanwhile. - `CCTV_VEGVESEN_HEIGHTS=0` turns it off. Follow-up to #929 (trygvehhh, #945). diff --git a/changelog.d/948-vite-fs-deny.md b/changelog.d/948-vite-fs-deny.md deleted file mode 100644 index 642bafb1f..000000000 --- a/changelog.d/948-vite-fs-deny.md +++ /dev/null @@ -1,4 +0,0 @@ -- Harden Vite's filesystem deny list for local-only artifacts: repo `dist/`, - `.gev-logs/`, and `.gev-cache/` are denied without blocking dependency - `dist/` directories, and checkout paths containing glob metacharacters are - escaped before building the root-anchored pattern (blowing-a-raspberry, #948). diff --git a/changelog.d/970-recent-imagery-details-scroll.md b/changelog.d/970-recent-imagery-details-scroll.md deleted file mode 100644 index 761e265c0..000000000 --- a/changelog.d/970-recent-imagery-details-scroll.md +++ /dev/null @@ -1,3 +0,0 @@ -- Recent Imagery: opening DETAILS scrolls its card into view when it opens below - the fold. The panel used to restore the previous scroll position right after - the reveal, so the card stayed out of sight (Ian Blenke, #970). diff --git a/changelog.d/973-tomtom-cross-site-gate.md b/changelog.d/973-tomtom-cross-site-gate.md deleted file mode 100644 index e4a029406..000000000 --- a/changelog.d/973-tomtom-cross-site-gate.md +++ /dev/null @@ -1,4 +0,0 @@ -- Cross-site browser requests can no longer spend the TomTom traffic-tile - budget through `/api/tomtom/*`. The shared same-site gate runs before status, - cache, and upstream work; same-origin app requests and non-browser local - callers remain supported (Sunil56224972, #973). diff --git a/changelog.d/974-street-level-slim.md b/changelog.d/974-street-level-slim.md deleted file mode 100644 index 8bc2b5346..000000000 --- a/changelog.d/974-street-level-slim.md +++ /dev/null @@ -1,6 +0,0 @@ -- Street Level is rebuilt around one small provider registry: Mapillary, - KartaView, Panoramax and Google Street View share one coverage drawer and - one photo viewer, one source lit at a time. Floating and docked panels, - FOLLOW, surface modes, the legend and the Mapillary proxy's disk cache are - gone; `.gev-cache/mapillary/` from earlier runs is no longer read and can be - deleted (gekh, #974). diff --git a/changelog.d/975-terrain-cross-site-gate.md b/changelog.d/975-terrain-cross-site-gate.md deleted file mode 100644 index 6c0e42156..000000000 --- a/changelog.d/975-terrain-cross-site-gate.md +++ /dev/null @@ -1,8 +0,0 @@ -- Cross-site pages can no longer fill the terrain-height cache or spend the - visitor's own `/api/terrain/heights` rate-limit quota through the visitor's - browser. The route refuses a cross-site `Sec-Fetch-Site` or a foreign or - opaque `Origin` before rate limiting, cache access or upstream work. Unlike - the cost-bearing routes it still answers same-origin requests that arrive - through a reverse proxy, so terrain keeps rendering behind nginx, Caddy or - Cloudflare instead of falling back to the geoid (Sunil56224972, daikaginza, - #975). diff --git a/changelog.d/990-hong-kong-cctv.md b/changelog.d/990-hong-kong-cctv.md deleted file mode 100644 index a150b66ae..000000000 --- a/changelog.d/990-hong-kong-cctv.md +++ /dev/null @@ -1,7 +0,0 @@ -- Add Hong Kong Transport Department traffic snapshot cameras as a keyless CCTV - source pack: the public DATA.GOV.HK English locations XML, frames pinned to - `tdcctv.data.one.gov.hk`, with DATA.GOV.HK Terms of Use attribution. By - default nearly the full TD catalog (~1,013 cameras; cap 1,100) loads, - prioritized across Hong Kong Island, Kowloon and the New Territories. Headings - use the shared id-hash fallback at low confidence. `CCTV_HK_MAX_SOURCES` sets - the cap (8–1,200) and `CCTV_HK_ENABLED=0` turns the pack off (JCY2515, #990). diff --git a/package-lock.json b/package-lock.json index 7b6d3476f..9d4714ce2 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "gods-eye-view", - "version": "0.2.1", + "version": "0.3.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "gods-eye-view", - "version": "0.2.1", + "version": "0.3.0", "license": "MIT", "dependencies": { "@jtarrio/signals": "^0.10.0", diff --git a/package.json b/package.json index 75a1f994c..aa42dffe1 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "gods-eye-view", "private": true, - "version": "0.2.1", + "version": "0.3.0", "description": "A real-time intelligence console for planet Earth — photorealistic 3D globe, live aircraft/ships/satellites/earthquakes/CCTV, and hands-free voice control. Runs in a browser.", "type": "module", "license": "MIT", From 018b6d3f1bd5f4e8a2a3f9dcfb45a9b6eb7b0dbe Mon Sep 17 00:00:00 2001 From: German Khokhlov Date: Wed, 28 Oct 2026 10:37:21 +0400 Subject: [PATCH 10/11] i18n: fix zh-Hant characters OpenCC converts wrongly MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Correct 年曆史 → 年歷史, 下遊 → 下游, 並道 → 併道 and 發佈 → 發布, and list these fixes for future reconversions from zh-CN. Co-Authored-By: Claude Opus 5.5 --- docs/translations/zh-Hant.md | 2 ++ src/i18n/locales/zh-Hant.json | 22 +++++++++++----------- 2 files changed, 13 insertions(+), 11 deletions(-) diff --git a/docs/translations/zh-Hant.md b/docs/translations/zh-Hant.md index 7354e6b1b..9a36f877c 100644 --- a/docs/translations/zh-Hant.md +++ b/docs/translations/zh-Hant.md @@ -4,6 +4,8 @@ Catalog: `src/i18n/locales/zh-Hant.json`. General rules: [TRANSLATORS.md](../TRA `zh-Hant` is the Simplified Chinese catalog (`zh-CN`, credited to abiyeenzo, #914, and EDIT-Aeterna, #979) written in Traditional characters with OpenCC character conversion. Wording and terminology are the same as in `zh-CN`: change a term in [zh-CN.md](./zh-CN.md) and the `zh-CN` catalog first, then convert. Only the script differs. +After `s2tw` conversion, fix the characters OpenCC picks wrongly: 年曆史 → 年歷史, 下遊 → 下游, 並道 → 併道, 發佈 → 發布. + ## Style - Follow [zh-CN.md](./zh-CN.md) for wording, punctuation, spacing, units and the glossary, written in Traditional characters. diff --git a/src/i18n/locales/zh-Hant.json b/src/i18n/locales/zh-Hant.json index 414624f2d..ec908665f 100644 --- a/src/i18n/locales/zh-Hant.json +++ b/src/i18n/locales/zh-Hant.json @@ -52,7 +52,7 @@ "SOURCE CREDITED · LOCATION UNRESOLVED": "來源已署名 · 位置未確定", "REFERENCE ONLY · CLAIMS UNVERIFIED": "僅供參考 · 說法未核實", "SOURCE GEOCONFIRMED": "來源位置已核實", - "2021 historical reference versus 2026 post-event imagery; changes are cumulative and include the July 2025 Rasuwagadhi flood. Schematic downstream progression, not modeled arrival time; not an official hazard model.": "2021 年曆史參考影像與 2026 年災後影像對比;變化為累計結果,包含 2025 年 7 月的 Rasuwagadhi 洪水。下游演進為示意,並非模擬的到達時間;也不是官方災害模型。", + "2021 historical reference versus 2026 post-event imagery; changes are cumulative and include the July 2025 Rasuwagadhi flood. Schematic downstream progression, not modeled arrival time; not an official hazard model.": "2021 年歷史參考影像與 2026 年災後影像對比;變化為累計結果,包含 2025 年 7 月的 Rasuwagadhi 洪水。下游演進為示意,並非模擬的到達時間;也不是官方災害模型。", "Immediate collapse viewpoint": "近距離崩塌觀察點", "Collapse viewpoint": "崩塌觀察點", "Debris-dammed lake": "碎屑堰塞湖", @@ -101,11 +101,11 @@ "SECONDARY FAILURE": "第二次滑坡", "BORDER ARRIVAL": "抵達邊境", "PROPAGATION": "演進", - "DOWNSTREAM PASSAGE": "向下遊推進", + "DOWNSTREAM PASSAGE": "向下游推進", "CONSEQUENCE": "後果", "DOWNSTREAM CONSEQUENCE": "下游後果", "EVIDENCE": "證據", - "{year} HISTORICAL REFERENCE": "{year} 年曆史參考", + "{year} HISTORICAL REFERENCE": "{year} 年歷史參考", "{year} POST-EVENT": "{year} 年災後", "{count} GEOLOCATED SOURCE-MAP PLACEMENTS": { "other": "{count} 個地理定位來源點位" @@ -121,7 +121,7 @@ "Close event layer": "關閉事件圖層", "OBSERVED IMAGERY": "觀測影像", "SCHEMATIC CORRIDOR": "示意走廊", - "2021 HISTORICAL REFERENCE / 2026 POST-EVENT": "2021 年曆史參考 / 2026 年災後", + "2021 HISTORICAL REFERENCE / 2026 POST-EVENT": "2021 年歷史參考 / 2026 年災後", "Historical reference and post-event image split": "歷史參考與災後影像的分割", "RECONSTRUCTION CLOCK": "重構時鐘", "Schematic downstream progression": "下游演進示意", @@ -545,7 +545,7 @@ }, "Position as of {time}": "位置(截至 {time})", "Maximum sustained wind: {wind} · Pressure: {pressure}": "最大持續風速:{wind} · 氣壓:{pressure}", - "{name} · {classification} · Advisory {number} · issued {time}": "{name} · {classification} · 第 {number} 號公告 · 發佈於 {time}", + "{name} · {classification} · Advisory {number} · issued {time}": "{name} · {classification} · 第 {number} 號公告 · 發布於 {time}", "No active NHC/CPHC systems": "當前沒有活躍的 NHC/CPHC 氣旋", "Advisories unavailable": "公告不可用", "Cyclones · NHC / CPHC": "氣旋 · NHC / CPHC", @@ -620,10 +620,10 @@ "Keep {direction} at the fork": "在岔路口{direction}", "Continue at the fork onto {road}": "在岔路口繼續行駛,進入 {road}", "Continue at the fork": "在岔路口繼續行駛", - "Merge {direction} onto {road}": "{direction}並道,進入 {road}", - "Merge {direction}": "{direction}並道", + "Merge {direction} onto {road}": "{direction}併道,進入 {road}", + "Merge {direction}": "{direction}併道", "Merge onto {road}": "併入 {road}", - "maneuver|Merge": "並道", + "maneuver|Merge": "併道", "Take the ramp on the {direction} onto {road}": "{direction}駛入匝道,進入 {road}", "Take the ramp on the {direction}": "{direction}駛入匝道", "Take the ramp onto {road}": "駛入匝道,進入 {road}", @@ -1234,7 +1234,7 @@ "{model} forecast · {field} ({unit})": "{model} 預報 · {field}({unit})", "Valid: {time}": "有效時間:{time}", "preparing": "準備中", - "Issued: {time}": "發佈時間:{time}", + "Issued: {time}": "發布時間:{time}", "Selected field unavailable · wind remains visible": "所選氣象場不可用 · 風場仍可見", "{error} · wind remains visible": "{error} · 風場仍可見", "Surface wind at 10 m. Approximately 1° global grid. Curves follow the 10 m wind field, lifted 12 km for visibility; display height is not weather altitude. View lighting is for readability. Animation shows flow through one fixed forecast; it does not advance time. Color fields drape the globe basemap or the active photorealistic 3D Tiles.": "10 m 高度的地面風。約 1° 全球網格。流線沿 10 m 風場繪製,為便於觀看抬升至 12 km;顯示高度並非氣象高度。視圖光照僅為提高可讀性。動畫展示的是單一固定預報內的流場,不推進時間。氣象場填色疊加於地球底圖或當前的照片級逼真 3D Tiles。", @@ -2163,7 +2163,7 @@ "{time} · {minutes} min ago": "{time} · {minutes} 分鐘前", "Active weather": "已啟用的天氣圖層", "LATEST · newest per product": "最新 · 每個產品的最新一幀", - "Forecast · valid {valid} · issued {issued}": "預報 · 有效時間 {valid} · 發佈時間 {issued}", + "Forecast · valid {valid} · issued {issued}": "預報 · 有效時間 {valid} · 發布時間 {issued}", "{detail} · Does not follow history": "{detail} · 不隨觀測歷史變化", "Forecast · valid {valid}": "預報 · 有效時間 {valid}", "voice|OFF": "關", @@ -2863,5 +2863,5 @@ "{count} placemarks": { "other": "{count} 個地標" }, - "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 產品。新上傳的內容會在數秒內被檢測到,並自動替換舊版本。點擊標記查看報告。" + "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 產品。新上傳的內容會在數秒內被檢測到,並自動替換舊版本。點擊標記查看報告。" } From 982edfd56d4d7477a95648343d69dc6eabb5d95c Mon Sep 17 00:00:00 2001 From: German Khokhlov Date: Wed, 28 Oct 2026 11:26:52 +0400 Subject: [PATCH 11/11] =?UTF-8?q?i18n:=20use=20=E5=85=AC=E5=B8=83=20in=20z?= =?UTF-8?q?h-Hant=20to=20match=20=E7=99=BC=E5=B8=83?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Opus 5.5 --- docs/translations/zh-Hant.md | 2 +- src/i18n/locales/zh-Hant.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/translations/zh-Hant.md b/docs/translations/zh-Hant.md index 9a36f877c..ac355516b 100644 --- a/docs/translations/zh-Hant.md +++ b/docs/translations/zh-Hant.md @@ -4,7 +4,7 @@ Catalog: `src/i18n/locales/zh-Hant.json`. General rules: [TRANSLATORS.md](../TRA `zh-Hant` is the Simplified Chinese catalog (`zh-CN`, credited to abiyeenzo, #914, and EDIT-Aeterna, #979) written in Traditional characters with OpenCC character conversion. Wording and terminology are the same as in `zh-CN`: change a term in [zh-CN.md](./zh-CN.md) and the `zh-CN` catalog first, then convert. Only the script differs. -After `s2tw` conversion, fix the characters OpenCC picks wrongly: 年曆史 → 年歷史, 下遊 → 下游, 並道 → 併道, 發佈 → 發布. +After `s2tw` conversion, fix the characters OpenCC picks wrongly: 年曆史 → 年歷史, 下遊 → 下游, 並道 → 併道, 發佈 → 發布, 公佈 → 公布. ## Style diff --git a/src/i18n/locales/zh-Hant.json b/src/i18n/locales/zh-Hant.json index ec908665f..d95a18e39 100644 --- a/src/i18n/locales/zh-Hant.json +++ b/src/i18n/locales/zh-Hant.json @@ -1184,7 +1184,7 @@ "STALE · cached source metadata": "已過期 · 數據源元數據來自緩存", "Map center is outside source coverage": "地圖中心在數據源覆蓋範圍之外", "NOAA/NWS 15-minute lightning density derived from Vaisala NLDN/GLD360. Coverage 110°E across the Pacific/Americas to 0°, 25°S–80°N. Not a live strike count, global coverage or a safety warning.": "NOAA/NWS 15 分鐘閃電密度,來源為 Vaisala NLDN/GLD360。覆蓋自 110°E 經太平洋/美洲至 0°,25°S–80°N。不是實時閃擊計數、不是全球覆蓋,也不構成安全警示。", - "NOAA MRMS radar echoes indicate precipitation patterns, not rain rate, a storm warning or a future forecast. Native source approximately 1 km; display is limited to level 6. Frames use exact advertised observation times.": "NOAA MRMS 雷達回波反映降水形態,不代表降雨強度、風暴警報或未來預報。原始數據分辨率約 1 km;顯示僅限縮放級別 6。各幀使用數據源公佈的精確觀測時間。", + "NOAA MRMS radar echoes indicate precipitation patterns, not rain rate, a storm warning or a future forecast. Native source approximately 1 km; display is limited to level 6. Frames use exact advertised observation times.": "NOAA MRMS 雷達回波反映降水形態,不代表降雨強度、風暴警報或未來預報。原始數據分辨率約 1 km;顯示僅限縮放級別 6。各幀使用數據源公布的精確觀測時間。", "GOES-19/18 longwave infrared Band 14 regional; NESDIS global longwave mosaic. Clouds only dims everything but bright, cold cloud tops; a brightness filter, not a cloud mask. Coverage and freshness differ by region.": "GOES-19/18 第 14 波段長波紅外區域圖;NESDIS 全球長波鑲嵌圖。“僅雲區”會調暗除明亮冷雲頂之外的一切;這是亮度濾鏡,不是雲掩膜。覆蓋範圍與新鮮度因區域而異。", "REGION": "區域", "IMAGE": "圖像",