mirror of
https://github.com/bilawalsidhu/gods-eye-view.git
synced 2026-11-05 02:44:02 +00:00
Merge origin/main into claude/hal-676-gev-fire-intensity-742bd1
Locale conflicts (es, ru, zh-CN): keep both sides' new keys. The new uk
and zh-Hant catalogs get the fire filter strings; zh-Hant keeps
"≥ {value} MW" as in English, like zh-CN.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
This commit is contained in:
commit
520cf4cb4f
237 files changed
+10805
-944
No files matched your search
+73
-7
@@ -4,6 +4,24 @@ Docker Compose mounts the checkout with the shared SELinux `:z` label so
|
||||
containers can read it on enforcing SELinux hosts. The separate image-owned
|
||||
`node_modules` volume and loopback-only port publishing remain unchanged.
|
||||
|
||||
The HUD's AI summary line looks up place names for the view only when the
|
||||
summary can use them. The page asks `GET /api/openai/hud-summary/status` once;
|
||||
a server without an OpenAI key answers `{ configured: false }`, and the HUD then
|
||||
makes no reverse-geocode or Nearby Places request until the page reloads. A
|
||||
server without the route is asked once, and an unconfigured summary reply
|
||||
stops the lookups the same way. Each lookup reverse-geocodes at most two
|
||||
points: the view center alone below 10 km, the center and one viewport point
|
||||
up to 750 km, and two viewport points up to 3000 km; Nearby Places is still
|
||||
added below 25 km. A lookup is reused until the view center moves a quarter of
|
||||
the visible width, the camera's distance to the center doubles or halves, or
|
||||
the camera crosses one of those heights. The width is measured from the
|
||||
camera's distance to the view center, so terrain and tilt scale it. A reused
|
||||
lookup asks again only for what it did not get (a timeout, a failure, an empty
|
||||
answer); everything else is a cache hit. A small pan over a reused lookup
|
||||
repaints the last AI reply instead of asking for a new one. A host passing
|
||||
`cachedOnly` keeps reading every cached sample. Voice context lookups are
|
||||
unchanged.
|
||||
|
||||
The HUD's LAT/LON degrees-minutes-seconds readout rounds the coordinate once, to
|
||||
hundredths of a second, and then splits it. A value within 0.005" of the next
|
||||
whole minute carries into the minutes and degrees, so `-122.35` reads
|
||||
@@ -560,6 +578,11 @@ dateline while preserving both authored endpoint longitudes, and turns heading
|
||||
and roll the short way for any authored angles.
|
||||
A seek to a shot's start, as a shot action makes, selects that shot rather than
|
||||
the end of the previous one.
|
||||
Same-shot seeking restores declared layer visibility after a manual toggle,
|
||||
including one still in flight, by reconciling only the changed layers through
|
||||
the cancellable layer admission path. Refused restoration reports a failed
|
||||
seek and keeps the last settled position. Undeclared operator layers remain
|
||||
untouched, and the shot is not rebuilt.
|
||||
See [camera directions](DIRECTOR-CAMERA.md).
|
||||
|
||||
Realtime voice composes separate connection, response/tool, Radio handoff, input
|
||||
@@ -793,6 +816,11 @@ rendered detection set. The legacy manager retains panel helper compatibility;
|
||||
registration sealing, restoration order and failed-transition rollback remain
|
||||
unchanged.
|
||||
|
||||
Polled layer refreshes and the HUD's camera readout pause while the page is
|
||||
hidden. An app embedded inline in a panel keeps both running, because the
|
||||
panel's host can report the page as hidden while it is on screen. This is the
|
||||
same rule the render loop follows (`keepPanelRendering` in `app/embed.js`).
|
||||
|
||||
Application scene setup owns request services, terrain/floor caches and annotation
|
||||
lookup state. Controls, layers and voice share those owners, and cancellation
|
||||
clears caches and removes map-stack listeners. Standalone setup supplies the
|
||||
@@ -1144,6 +1172,10 @@ Shot selection updates the highlight without replacing the row, preserving
|
||||
native double-click rename. Replacing rows revokes their old listeners. Disposal stops controls immediately;
|
||||
late file and failed-action completions cannot update removed presentation.
|
||||
|
||||
Director clock listeners, interaction observers and scene release failures no
|
||||
longer leave the director inconsistent, and a phase error is kept when cleanup
|
||||
also fails.
|
||||
|
||||
## Cockpit component ownership
|
||||
|
||||
Cockpit presentation is separated from its camera/controller behavior. Existing
|
||||
@@ -2291,6 +2323,16 @@ fetching, trailing-24-hour filtering and partial-success caching are unchanged.
|
||||
> SCOPE toggle + FEATHER slider, hash keys `sc`/`scf`) — it is NOT the
|
||||
> six zero-intensity style stages anymore (those are disabled; see the
|
||||
> history note in `_initStages`). Hidden tabs stop the render loop.
|
||||
> AIS vessels no longer hold the loop while enabled (2026-09-30): vessels move
|
||||
> only when a poll lands, so the layer requests a frame for every forced pass
|
||||
> (new data, selection), leaves one trailing frame when the camera moved inside
|
||||
> the 800 ms visibility cadence, and holds `ais-vessels` only while focus
|
||||
> emphasis animates or any vessel stays dimmed under a live focus target. The
|
||||
> trailing frame goes through the layer's injectable runtime clock and is
|
||||
> cancelled on disable, destroy and reset (`renderGovernor.test.mjs` pins the
|
||||
> no-self-wake invariant). The 80 ms focus pass also skips hidden sprites whose
|
||||
> focus state is at rest (`spriteFocusAtRest`), since advancing them changes
|
||||
> nothing; with a 12k worldwide feed that is most of the fleet.
|
||||
> The scope's OUTSIDE terminus is **altitude-adaptive** (2026-08-17): 0.94
|
||||
> at/above **10 Mm**, so
|
||||
> faint stars survive in the corners of a TRUE full-globe view, fading quickly
|
||||
@@ -3115,7 +3157,14 @@ down | auth-failed` (plus the unchanged `missing-key`/`unsupported`) with
|
||||
> usable per point, while an uncached absent height still returns 502 rather
|
||||
> than becoming a fabricated ground value. A position the upstream answers
|
||||
> with a null ellipsoid is reported as an absent height rather than a refresh
|
||||
> failure, and is left uncached so a later poll re-asks it. Client geoid
|
||||
> failure, and is left uncached so a later poll re-asks it. A `Retry-After`
|
||||
> longer than the 10 s retry budget ends the retries at once. After a 429 that
|
||||
> outlasts its retries, the proxy pauses upstream calls for the `Retry-After`
|
||||
> (60 seconds when none, at most 10 minutes). A request whose points are all
|
||||
> cached, fresh or stale, is still served; a request with any uncached point
|
||||
> gets 502 and the page uses its geoid fallback for that chunk. Each request
|
||||
> that was waiting on the upstream when the 429 came back logs one warning;
|
||||
> requests refused during the pause do not log. Client geoid
|
||||
> fallbacks wait 60 seconds before retrying and self-heal to Re:Earth on the
|
||||
> first later successful fetch. Smaller chunks reduce timeout risk; complete
|
||||
> camera batches still wait for their sequential requests, and unresolved
|
||||
@@ -3770,7 +3819,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**, **uk**, **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).
|
||||
|
||||
@@ -3781,8 +3830,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/<code>.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`; 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
|
||||
`?lang=` (keeps it only when storage is blocked) and reloads. It asks first
|
||||
@@ -3888,7 +3937,7 @@ anchors, recovery, keyboard and mobile states; emergency repainting is covered
|
||||
by `scripts/qa-emergency-squawk.mjs`. Both accept `--timeout-ms` for slow boot.
|
||||
|
||||
|
||||
Fire Perimeters uses capped, timed server reads with stale-on-error caching and a per-client limit. Unchanged snapshots retain geometry; link checks cancel on disable or selection change, and the row legend shows reported containment.
|
||||
Fire Perimeters uses capped, timed server reads with stale-on-error caching and a per-client limit. A stale snapshot is served for at most 24 hours; the layer row then reads STALE, dated by that snapshot's fetch, and `get_fire_perimeters` returns `stale` and `retrieved_at` with "(data may be stale)" in its summary. Unchanged snapshots retain geometry; link checks cancel on disable or selection change, and the row legend shows reported containment.
|
||||
|
||||
Street Level is a docked, collapsible right-rail panel (`#street-level-panel`,
|
||||
layer token `0`, option owner `street-level`, panel `ui` token `t`) that starts
|
||||
@@ -3943,6 +3992,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` /
|
||||
@@ -5302,7 +5353,13 @@ HTTP refusals and outages remain retryable. Searches share a 12-second total
|
||||
deadline, with Photon requests capped at six seconds each. Caller/application
|
||||
cancellation stops retries and late cache writes. Replacing a location search
|
||||
cancels the previous lookup; disposing its controls cancels the active lookup. Photon uses a soft proximity bias, up to five
|
||||
candidates, and an unbiased retry for name mismatches. Invalid or wrapped bounds returned by providers
|
||||
candidates, and an unbiased retry for name mismatches. A "place, region" query
|
||||
prefers a candidate named exactly for the place whose city, county, state,
|
||||
country or country code (or USA/UK) contains every word of the region, and a
|
||||
settlement or administrative area over a POI when both fit. Nearby results that
|
||||
fail that check are retried unbiased. After the region checks of both passes, a
|
||||
nearby place whose whole name is the query (one with a comma in it) comes next,
|
||||
then the unbiased name match. Invalid or wrapped bounds returned by providers
|
||||
are omitted rather than framing the wrong part of the globe.
|
||||
|
||||
A location search that finds nothing, or fails, leaves the field open with the
|
||||
@@ -5793,7 +5850,11 @@ easier to meet (detection is now on more often), but does not create it.
|
||||
coverage number. `stats.loading` covers outstanding flow work as well as the
|
||||
road fetch, so a flow failure landing after the first paint still ends the
|
||||
shared loading batch as LOAD FAILED. Harnesses must gate on `!stats.error`,
|
||||
never on `mode === 'live'` alone.
|
||||
never on `mode === 'live'` alone. When the drawn flow came from the proxy's
|
||||
cached STALE-BUDGET / STALE-ERROR tiles, `getStats()` reports `stale: true`
|
||||
and `oldestTileAt`, the row reads STALE with the oldest tile's age, and the
|
||||
sync chip reads
|
||||
`STALE · Roads: <source> · Flow: cached TomTom tiles` instead of LIVE.
|
||||
- Traffic runs in `sim` mode (white dots, hardcoded speeds) unless `TOMTOM_API_KEY`
|
||||
is configured (env or Keychain `tomtom-api`/`api-key`), which enables `live` mode:
|
||||
TomTom flow vector tiles via the budget-governed `/api/tomtom` proxy
|
||||
@@ -6096,6 +6157,11 @@ reception does not interrupt internet radio.
|
||||
Changes apply to the open receiver without reconnecting.
|
||||
- **Receiver stats (ADS-B).** CRC-valid messages per second, aircraft heard,
|
||||
aircraft with a fresh position and the IQ level.
|
||||
- **Error text.** A receiver error sets two fields (`errorState()` in
|
||||
`src/sdr/controller.js`): `message` is the UI language for the Radio card,
|
||||
`errorText` is the English text the Local ADS-B layer reports as its stats
|
||||
`error` (`localAdsbStatus()`, falling back to `message` when a receiver sets
|
||||
none); the Layers panel translates it where it shows it.
|
||||
- **Devices.** An already-authorized receiver opens without the WebUSB
|
||||
picker. ADS-B prefers a device whose product name matches ADS-B or 1090 (the
|
||||
1090 MHz channel of a dual-channel board); FM avoids ADS-B/UAT channels.
|
||||
|
||||
+2
-2
@@ -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`), **Ukrainian** (`uk`), **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/<code>.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/<code>.md`: [Spanish](./translations/es.md), [Russian](./translations/ru.md), [Ukrainian](./translations/uk.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.
|
||||
@@ -0,0 +1,106 @@
|
||||
# Ukrainian (`uk`)
|
||||
|
||||
Catalog: `src/i18n/locales/uk.json`. General rules: [TRANSLATORS.md](../TRANSLATORS.md).
|
||||
|
||||
Translation source: meirm (#312).
|
||||
|
||||
## Style
|
||||
|
||||
- Address the user with polite imperatives: «Натисніть», «Увімкніть», «Спробуйте ще раз».
|
||||
- Sentence case, not Title Case: "Live Flights" → «Рейси онлайн».
|
||||
- Ukrainian norms, not Russian calques: «у радіусі», «за посиланням», «надто довгий», «потім», «вигляд» (a camera view: «вигляд згори»), «стеження» (tracking); prepositions alternate у/в and і/й by euphony.
|
||||
- The apostrophe is always ʼ (U+02BC): обʼєкт, звʼязок, памʼять. Not ' or ’.
|
||||
- Quotes inside Ukrainian text are «ялинки»; a button or layer name inside a sentence goes in them: Увімкніть «Вуличні знімки».
|
||||
- In short labels, a standard abbreviation with a period beats a wrapped line: ПОПЕР., ДАЛЬН., КАЛІБР.
|
||||
- Units: км, м, км/год, м/с, вуз (knots), фт (feet), год, хв, с, МГц, дБ, гПа; in UPPERCASE text КМ, М, КМ/С, ВУЗ, ФТ. MW is МВт in any case. `°` and `%` stay. Decimal comma in coordinates written as text: 28,2710° пн. ш.
|
||||
- Coordinates: пн. ш. / пд. ш. / сх. д. / зх. д.; the HUD hemisphere letters are Пн, Пд, Сх, Зх.
|
||||
|
||||
## Plurals
|
||||
|
||||
A `tn()` entry needs four forms. `Intl.PluralRules('uk')` picks:
|
||||
|
||||
| Form | Counts | Example |
|
||||
| ------- | ------------------------ | ---------- |
|
||||
| `one` | 1, 21, 31, 101… | 1 камера |
|
||||
| `few` | 2–4, 22–24, 32–34… | 3 камери |
|
||||
| `many` | 0, 5–20, 25–30, 111–114… | 5 камер |
|
||||
| `other` | fractions: 1.5, 2.25… | 1,5 камери |
|
||||
|
||||
`other` takes the genitive singular: 1,5 кадру, 1,5 літака, 1,5 ключа. When a word next to a number cannot agree in every form, move the number after a colon instead: «поруч: {count}», «відповідей: {responses}». The same trick keeps place names and tool names out of a preposition's case: «звідки: {origin}», «Активно: {name}».
|
||||
|
||||
## Glossary
|
||||
|
||||
| English | Українська |
|
||||
| ----------------------------------------------- | ---------------------------------------------------------------- |
|
||||
| layer / data layer | шар / шар даних |
|
||||
| feed | потік даних (short: потік) |
|
||||
| source / data source | джерело / джерело даних |
|
||||
| LIVE (status) / live data | ОНЛАЙН / у реальному часі (status chip: ДАНІ ОНЛАЙН) |
|
||||
| SIMULATED / SYNTHETIC | ІМІТАЦІЯ |
|
||||
| stale / degraded / unavailable | застарів / з перебоями (chip: ПЕРЕБОЇ) / недоступний |
|
||||
| retry | повтор |
|
||||
| key (API key) / POWER UP | ключ / ЗАПУСК |
|
||||
| Provider Settings / provider | Налаштування постачальників / постачальник |
|
||||
| globe / map / map source / basemap | глобус / карта / джерело карти / підкладка |
|
||||
| aircraft / flight / military flights | літак (short HUD: борт) / рейс / військові рейси |
|
||||
| vessel, ship / vessels | судно / судна (gen. pl. суден) |
|
||||
| satellite | супутник |
|
||||
| launch (rocket) / space mission | запуск / космічна місія |
|
||||
| ascent (rocket) / booster FLIGHT {n} | виведення / ПОЛІТ {n} (not рейс) |
|
||||
| contact / tracking | контакт / стеження |
|
||||
| installation, site / mapped | обʼєкт / нанесений (обʼєкт, контакт) |
|
||||
| camera / CCTV camera | камера / камера CCTV |
|
||||
| earthquake / active fire / fire perimeter | землетрус / активна пожежа / контур пожежі |
|
||||
| advisory (NHC/CPHC cyclone) | зведення |
|
||||
| scene / shot / scene recipe | сцена / кадр / рецепт сцени |
|
||||
| briefing / panel / dock | брифінг / панель / док |
|
||||
| preset / visual preset | пресет / візуальний пресет |
|
||||
| Scope, keyhole (circular viewport mask) | приціл |
|
||||
| overlay (detection overlay) / world overlay | накладка / накладка на глобусі |
|
||||
| heading / altitude / ground speed | курс / висота / шляхова швидкість |
|
||||
| map bearing, map heading | азимут карти |
|
||||
| HDG / BRG / CRS, TRK / FOV / DEST / SPD / RANGE | КУРС / ПЕЛ. / ШК (шляховий кут) / ОГЛЯД / ПРИЗН. / ШВИД / ДАЛЬН. |
|
||||
| Street View (Google) | Перегляд вулиць (as in Ukrainian Google Maps) |
|
||||
| Street Level (layer) | Вуличні знімки |
|
||||
| imagery / recent imagery | знімки / свіжі знімки |
|
||||
| radar reflectivity / lightning density | радіолокаційна відбивність / щільність блискавок |
|
||||
| infrared | інфрачервоний (short: ІЧ) |
|
||||
| receiver / gain / decoder | приймач / підсилення / декодер |
|
||||
| broadcaster | мовник |
|
||||
| CONUS, WHOT/BHOT, Ironbow, CRT, NVG, FLIR | без перекладу |
|
||||
| PREV / NEXT (HUD) / Previous / Next | ПОПЕР. / ДАЛІ / Попередній / Наступний |
|
||||
| anchor / data pack / bundle (scene) | якір / пакет даних / архів |
|
||||
| box (Recent Imagery area) | область |
|
||||
| camera move | переліт |
|
||||
| SIG / NEWS / LOCAL (briefing tabs) | СИГН. / НОВИНИ / МІСЦ. |
|
||||
| compass points (N, NNE, NE, …) | Пн, ПнПнСх, ПнСх, … |
|
||||
| L / R (relative bearing) | Л / П |
|
||||
| click / tap | клацнути / натиснути |
|
||||
| session (voice, OAuth) | сеанс |
|
||||
| sequence (street-level photos) | послідовність |
|
||||
| search (place search) | пошук місця |
|
||||
| pitch (CCTV camera pose) | нахил |
|
||||
| traffic (road traffic layer) | дорожній рух |
|
||||
| phosphor (CRT) | люмінофор |
|
||||
| view (map extent) / view centre / in view | видима область (карти) / центр карти / у кадрі |
|
||||
| select (verb) / selected | вибрати / вибраний (not обрати) |
|
||||
| ping (cockpit proximity contacts) | контакт |
|
||||
| merge (turn-by-turn) / on ramp | влитися в потік / вʼїзд (off ramp: зʼїзд) |
|
||||
| watch (Earth/Orbital Watch) | спостереження |
|
||||
| timeout | тайм-аут |
|
||||
| icon | значок (not іконка) |
|
||||
| run (scene playback) / RUN LOG | відтворення / ЖУРНАЛ ВІДТВОРЕННЯ (запуск is a rocket launch) |
|
||||
| Preview (voice panel replies) | відповіді |
|
||||
| Marine (radio tag) / pleasure craft | море (not флот) / прогулянкове судно |
|
||||
| emergency (ADS-B) / Emergency (radio tag) | аварійний стан / надзвичайні ситуації |
|
||||
| confidence (FIRMS fire detection) | достовірність (short: достов.) |
|
||||
| thermal (FLIR-style imaging) | тепловий (not термальний) |
|
||||
| map stack | набір карт |
|
||||
| stage (rocket) re-entry / recovery | вхід ступеня в атмосферу / повернення |
|
||||
| ON / OFF (toggle chips) | УВІМК. / ВИМК. |
|
||||
| Clean UI / EXIT CLEAN VIEW | чистий інтерфейс / ПОВЕРНУТИ ІНТЕРФЕЙС |
|
||||
| full globe view | вигляд всього глобуса |
|
||||
| inputs (cockpit context chip) | потоки (not вхідні дані) |
|
||||
| downrange (rocket stage) | дальність |
|
||||
| resolution (spatial) | роздільна здатність (not роздільність) |
|
||||
| shared follow expired | посилання на стеження застаріло |
|
||||
@@ -0,0 +1,17 @@
|
||||
# Traditional Chinese (`zh-Hant`)
|
||||
|
||||
Catalog: `src/i18n/locales/zh-Hant.json`. General rules: [TRANSLATORS.md](../TRANSLATORS.md).
|
||||
|
||||
`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.
|
||||
- Relative-time placeholders may already include 前. In `LIVE · updated {age}`, the caller supplies the complete relative age; do not append another 前.
|
||||
- The picker displays 中文(繁體) / Chinese (Traditional); explicit Hans tags select Simplified Chinese.
|
||||
|
||||
## Plurals
|
||||
|
||||
`Intl.PluralRules('zh-Hant')` uses only `other`. Keep the measure words of the `zh-CN` entry: 「{count} 架飛機」、「{count} 艘船」.
|
||||
Reference in new issue
Block a user