mirror of
https://github.com/bilawalsidhu/gods-eye-view.git
synced 2026-11-05 10:53:59 +00:00
fix(zh-CN): localize readouts and keep short labels intact
Preserve Chinese unit casing and spacing in the HUD and cockpit, localize FIRMS cache ages, CCTV health and radio counts, and keep imagery resolution and route modes readable. Add regression coverage for localized output and unchanged English. Co-Authored-By: Codex (GPT-6) <[email protected]>
This commit is contained in:
1 parent
d6c4d58a2d
commit
fd78bc3884
14 files changed
+171
-18
No files matched your search
@@ -2941,5 +2941,7 @@
|
||||
"hemisphere|N": "N",
|
||||
"hemisphere|S": "S",
|
||||
"hemisphere|E": "E",
|
||||
"hemisphere|W": "O"
|
||||
"hemisphere|W": "O",
|
||||
"OK": "OK",
|
||||
"{category} ({count})": "{category} ({count})"
|
||||
}
|
||||
@@ -3008,5 +3008,7 @@
|
||||
"hemisphere|N": "С",
|
||||
"hemisphere|S": "Ю",
|
||||
"hemisphere|E": "В",
|
||||
"hemisphere|W": "З"
|
||||
"hemisphere|W": "З",
|
||||
"OK": "НОРМА",
|
||||
"{category} ({count})": "{category} ({count})"
|
||||
}
|
||||
@@ -2807,5 +2807,7 @@
|
||||
"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 缩小)"
|
||||
"Show the street-level view full screen (Esc shrinks it)": "全屏显示街景视图(按 Esc 缩小)",
|
||||
"OK": "正常",
|
||||
"{category} ({count})": "{category}({count})"
|
||||
}
|
||||
@@ -63,6 +63,7 @@
|
||||
"NVG",
|
||||
"Noir",
|
||||
"Normal",
|
||||
"OK",
|
||||
"POS: {time}Z",
|
||||
"Plan",
|
||||
"Pop",
|
||||
|
||||
@@ -0,0 +1,106 @@
|
||||
import test from 'node:test';
|
||||
import assert from 'node:assert/strict';
|
||||
import { setLocale, t } from './index.js';
|
||||
import { hudQuantity, LOCALIZED_LOCALITY } from '../hudLocalityFormat.js';
|
||||
import { formatCockpitDistance } from '../ui/cockpitPresentation.js';
|
||||
import { cctvSourceStatusLabel } from '../ui/cctvFrames.js';
|
||||
import { READOUT_WORDS } from '../layers/recentImagery/display.js';
|
||||
import { createModel } from '../layers/firms/model.js';
|
||||
import { createQueries } from '../layers/firms/queries.js';
|
||||
import { renderRadioState } from '../ui/radioPresentation.js';
|
||||
|
||||
test('Chinese HUD and cockpit units keep their case without spacing coordinates', () => {
|
||||
try {
|
||||
setLocale('zh-CN');
|
||||
assert.equal(hudQuantity(0, 'km'), '0 km');
|
||||
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');
|
||||
setLocale('en');
|
||||
assert.equal(hudQuantity(0, 'km'), '0KM');
|
||||
assert.equal(hudQuantity(2069, 'km', 1), '2069.0KM');
|
||||
assert.equal(formatCockpitDistance(14000), '14\u00a0KM');
|
||||
} finally {
|
||||
setLocale('en');
|
||||
}
|
||||
});
|
||||
|
||||
test('FIRMS stale cache age uses localized durations while English stays compact', () => {
|
||||
const now = Date.now();
|
||||
const layerState = { _stale: true };
|
||||
const components = {
|
||||
model: createModel({ services: { anchors: {} } }),
|
||||
};
|
||||
const { methods } = createQueries({ layerState, components, config: {} });
|
||||
try {
|
||||
for (const [hours, zh, en] of [[0.5, '不到 1 小时', '<1h'], [2, '2 小时', '2h'], [72, '3 天', '3d']]) {
|
||||
layerState._lastUpdate = now - hours * 3600000;
|
||||
setLocale('zh-CN');
|
||||
const expected = t('STALE · cached {age}', { age: zh });
|
||||
assert.equal(methods.getStats().loadingLabel, expected);
|
||||
assert.equal(methods.getStats().error, expected);
|
||||
setLocale('en');
|
||||
assert.equal(methods.getStats().loadingLabel, `STALE · cached ${en}`);
|
||||
}
|
||||
} finally {
|
||||
setLocale('en');
|
||||
}
|
||||
});
|
||||
|
||||
test('Recent Imagery spaces numeric Chinese ages and retains natural relative dates', () => {
|
||||
try {
|
||||
setLocale('zh-CN');
|
||||
assert.equal(READOUT_WORDS.daysAgo(9), '9 天前');
|
||||
assert.equal(READOUT_WORDS.daysAgo(0), '今天');
|
||||
assert.equal(READOUT_WORDS.daysAgo(1), '昨天');
|
||||
setLocale('en');
|
||||
assert.equal(READOUT_WORDS.daysAgo(9), '9 days ago');
|
||||
assert.equal(READOUT_WORDS.daysAgo(0), 'today');
|
||||
} finally {
|
||||
setLocale('en');
|
||||
}
|
||||
});
|
||||
|
||||
test('CCTV translates the healthy status and preserves unknown provider codes', () => {
|
||||
try {
|
||||
for (const [locale, expected] of [['zh-CN', '正常'], ['ru', 'НОРМА'], ['es', 'OK'], ['en', 'OK']]) {
|
||||
setLocale(locale);
|
||||
assert.equal(cctvSourceStatusLabel('ok'), expected);
|
||||
assert.equal(cctvSourceStatusLabel('CUSTOM'), 'CUSTOM');
|
||||
}
|
||||
} finally {
|
||||
setLocale('en');
|
||||
}
|
||||
});
|
||||
|
||||
test('radio option text and accessible name use the same localized parentheses', () => {
|
||||
const originalDocument = globalThis.document;
|
||||
const element = () => ({
|
||||
style: {}, dataset: {}, attributes: {},
|
||||
classList: { contains: () => true, toggle() {} },
|
||||
setAttribute(name, value) { this.attributes[name] = value; },
|
||||
replaceChildren(...children) { this.children = children; },
|
||||
});
|
||||
globalThis.document = { createElement: element, getElementById: () => null };
|
||||
try {
|
||||
for (const [locale, label, expected] of [['zh-CN', '全部', '全部(750)'], ['en', 'All', 'All (750)']]) {
|
||||
setLocale(locale);
|
||||
const host = {
|
||||
_radioPanel: element(), _radioFilter: element(),
|
||||
_syncContextRadioLauncherState() {},
|
||||
actions: { getLifecycle: () => null, scheduleLayout() {} },
|
||||
};
|
||||
renderRadioState.call(host, {
|
||||
enabled: true, categories: [{ id: 'all', label, count: 750, color: '' }],
|
||||
filter: 'all', filteredCount: 750, stationCount: 750, volume: 1,
|
||||
});
|
||||
const option = host._radioFilter.children[0];
|
||||
assert.equal(option.textContent, `● ${expected}`);
|
||||
assert.equal(option.attributes['aria-label'], expected);
|
||||
}
|
||||
} finally {
|
||||
globalThis.document = originalDocument;
|
||||
setLocale('en');
|
||||
}
|
||||
});
|
||||
Reference in new issue
Block a user