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 <[email protected]>
This commit is contained in:
German KhokhlovandClaude Opus 5.5 committed 2026-10-27 23:57:25 +04:00
1 parent 8269facb5a
commit 51ee9ae914
8 files changed
+1187 -1219

No files matched your search

+4 -4
View File
@@ -1,4 +1,4 @@
- Add Traditional Chinese (zh-Hant) with language selection, - Add Traditional Chinese (zh-Hant) with language selection and localized
and localized Chinese readouts. Based on translations by @caxer (#724), Chinese readouts: the Simplified Chinese catalog written in Traditional
@tbdavid2019 (#652), @abiyeenzo (#914), and @EDIT-Aeterna (#979) characters, based on translations by @abiyeenzo (#914) and @EDIT-Aeterna
(German, @gekh, #1430). (#979) (German, @gekh, #1430).
+1 -1
View File
@@ -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 value). English has no catalog; every other locale is
`src/i18n/locales/<code>.json`, and a missing entry falls back to English. `src/i18n/locales/<code>.json`, and a missing entry falls back to English.
- **Locale choice.** `?lang=` → stored choice (`gev:locale:v1`) → - **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 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 it, so a recipient keeps their own language. The globe picker in the
bottom-right corner (`src/ui/localePicker.js`) stores the choice, drops bottom-right corner (`src/ui/localePicker.js`) stores the choice, drops
+4 -36
View File
@@ -2,46 +2,14 @@
Catalog: `src/i18n/locales/zh-Hant.json`. General rules: [TRANSLATORS.md](../TRANSLATORS.md). 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 ## Style
- Use Traditional characters and consistent terminology from the glossary below. Prefer short, neutral instructions: 「點選地圖」、「儲存金鑰」. - Follow [zh-CN.md](./zh-CN.md) for wording, punctuation, spacing, units and the glossary, written in Traditional characters.
- 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 前. - 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); explicit Hans tags select Simplified Chinese.
- 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 ## Plurals
`Intl.PluralRules('zh-Hant')` uses only `other`. Keep suitable measure words: 「{count} 架飛機」、「{count} 艘船」、「{count} 個金鑰」. `Intl.PluralRules('zh-Hant')` uses only `other`. Keep the measure words of the `zh-CN` entry: 「{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 (風況資料不可用).
+2 -2
View File
@@ -10,7 +10,7 @@ const cases = [
[7200000, '2 小时前', '2h ago', '2 小時前'], [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) => { test(`FIRMS live age ${age} ms has one relative-time suffix`, (context) => {
const now = 1800000000000; const now = 1800000000000;
context.mock.method(Date, 'now', () => now); context.mock.method(Date, 'now', () => now);
@@ -37,7 +37,7 @@ for (const [age, zh, en, tw] of cases) {
setLocale('zh-CN'); setLocale('zh-CN');
assert.equal(methods.getStats().loadingLabel, `实时 · 更新于 ${zh}`); assert.equal(methods.getStats().loadingLabel, `实时 · 更新于 ${zh}`);
setLocale('zh-Hant'); setLocale('zh-Hant');
assert.equal(methods.getStats().loadingLabel, `即時 · 更新於 ${tw}`); assert.equal(methods.getStats().loadingLabel, `實時 · 更新於 ${hant}`);
} finally { } finally {
setLocale(previousLocale); setLocale(previousLocale);
} }
+1 -1
View File
@@ -43,7 +43,7 @@ test('normalizeLocale folds regional variants and rejects unshipped tags', () =>
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-TW'), 'zh-Hant');
assert.equal(normalizeLocale('zh-Hant-HK'), '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-Hant-CN'), 'zh-Hant');
assert.equal(normalizeLocale('zh_HK'), 'zh-Hant'); assert.equal(normalizeLocale('zh_HK'), 'zh-Hant');
assert.equal(normalizeLocale('zh-MO'), 'zh-Hant'); assert.equal(normalizeLocale('zh-MO'), 'zh-Hant');
+1172 -1172
View File
File diff suppressed because it is too large. Load diff
+1 -1
View File
@@ -225,9 +225,9 @@
"MM", "MM",
"NVG", "NVG",
"REC", "REC",
"SRC {value}",
"S2 GhostMaps", "S2 GhostMaps",
"S2 · {name}", "S2 · {name}",
"SRC {value}",
"Sentinel-2", "Sentinel-2",
"Techno", "Techno",
"Trance", "Trance",
+2 -2
View File
@@ -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(9), '9 天前');
assert.equal(READOUT_WORDS.daysAgo(0), '今天'); assert.equal(READOUT_WORDS.daysAgo(0), '今天');
assert.equal(cctvSourceStatusLabel('ok'), '正常'); assert.equal(cctvSourceStatusLabel('ok'), '正常');
assert.equal(t('SAVE KEYS'), '儲存金鑰'); assert.equal(t('SAVE KEYS'), '保存密鑰');
assert.equal( assert.equal(
tn(2, 'Click {count} more point.', 'Click {count} more points.'), tn(2, 'Click {count} more point.', 'Click {count} more points.'),
'再點選 2 個點。', '再點擊 2 個點。',
); );
} finally { } finally {
setLocale(previous); setLocale(previous);