mirror of
https://github.com/bilawalsidhu/gods-eye-view.git
synced 2026-11-10 21:32:23 +00:00
i18n(he): apply review (#1594)
Before merging: singular 'one' forms from the review table (44 entries),
counters keep their order across the slash (מתוך, as Arabic المن), the
lightning layer says ברקים (the legend now counts ברק strikes, the help
text keeps 110°E Latin), configured-elsewhere keys are promised
untouched, Punk is פאנק רוק, dock/panel side labels follow the mirrored
layout, and the HUD-summary English guard covers he (NON_LATIN_LOCALES,
tested) — documented in Adding a language along with format-scope.
Suggestions and nits: restricted is מוגבל, stage recovery is החבה not
שחזור, voice-inactivity names the behavior, lane directions use
attributes (השמאלי) and around is לאחור, Ironbow and KM/S stay Latin in
same-as-english, {age} no longer doubles לפני, typos and garbled words
fixed (תנאים, ידנית, ודאות, מקלט, זמניים, ערוץ 14, מעונן חלקית, אין אות
קריאה, Tab לתצוגה מקדימה, השאר ריק, היוועץ), counted units shortened
(שנ' דק' שע' ימ'), terminology unified (briefing תדריך, forecast תחזית,
course מהלך, אונייה, שריפה), rtl.css shares the mono redirect under
:is(:lang(ar), :lang(he)) and its comments match the rules,
worldOverlayTokens adds Noto Sans Hebrew to the canvas card fonts, he.md
gets the fraction-aware plural table, iw/iw-IL map to he (tested).
This commit is contained in:
1 parent
23609b94b6
commit
f79ceb690f
11 files changed
+240
-212
No files matched your search
+3
-2
@@ -45,9 +45,10 @@ Edit `src/i18n/locales/<code>.json` and run `npm run i18n`. To see your change,
|
||||
1. Create `src/i18n/locales/<code>.json`, fill it from `npm run i18n -- --missing <code>` (start from `{}`), and translate every entry.
|
||||
2. Import it in `src/i18n/index.js` and add it to `CATALOGS`.
|
||||
3. Add the code to `LOCALES` and its own-language name to `LOCALE_NAMES` in `src/i18n/locale.js`. Right-to-left languages also go in `RTL_LOCALES`; the chrome mirrors through logical CSS properties (`inset-inline-*`, `margin-inline-*`), and `src/ui/styles/rtl.css` holds what those cannot express (see the Arabic notes). If the language should keep Western digits, map it in `INTL_TAGS` in `locale.js`.
|
||||
4. Add `src/i18n/locales/<code>.json` next to `ru.json` in `scripts/package-boundaries.json`.
|
||||
4. Add `src/i18n/locales/<code>.json` next to `ru.json` in `scripts/package-boundaries.json` and in `scripts/format-scope.json`.
|
||||
5. Write `docs/translations/<code>.md`: glossary, plural forms, units and style (copy the structure of `ru.md`).
|
||||
6. Run `npm run i18n` and `npm test`, then check the panels in the app at narrow widths.
|
||||
6. If the language is not written in Latin letters, also add it to `NON_LATIN_LOCALES` in `src/hudSummaryResponse.js` — that guard falls back to the translated text when a summary provider answers in English.
|
||||
7. Run `npm run i18n` and `npm test`, then check the panels in the app at narrow widths.
|
||||
|
||||
## Rules
|
||||
|
||||
|
||||
+10
-10
@@ -7,7 +7,7 @@ Catalog: `src/i18n/locales/he.json`. General rules: [TRANSLATORS.md](../TRANSLAT
|
||||
- Address the user with a masculine imperative, Google style: הסתר, הצג, נסה שוב, התקרב. Menu items and tooltips take the noun form: הסרת {name}, הרחבת {name}, שינוי הצבע של {name}.
|
||||
- Sentence case: Hebrew has no case forms, so UPPERCASE English is normal sentence style here; short HUD labels stay short, favor an abbreviation over a wrapped line.
|
||||
- Keep the `·`, `—`, `→`, `↗`, `…` separators. Latin codes read inside RTL text because the app isolates interpolated values; leave them alone.
|
||||
- Units follow the catalog: ק"מ, מ׳, קמ"ש, שנ', דק', שע'; instrument chips keep the Latin unit (MW, KM, FT, KTS, kn) and codes (HDG, FOV, CAL, SRC, REC) exactly as in English — see `same-as-english.json`.
|
||||
- Units follow the catalog: ק"מ, מ׳, קמ"ש, שנ', דק', שע'. Instrument readouts and formatted shared-unit labels keep the Latin units (km, NM, FT, KTS, MW, KM/S); catalog prose outside those readouts keeps ק"מ/מ׳. Codes like HDG, FOV, CAL, SRC, REC stay exactly as in English — see `same-as-english.json`.
|
||||
|
||||
## Digits and direction
|
||||
|
||||
@@ -19,11 +19,11 @@ Catalog: `src/i18n/locales/he.json`. General rules: [TRANSLATORS.md](../TRANSLAT
|
||||
|
||||
A `tn()` entry needs three forms under `Intl.PluralRules('he')`:
|
||||
|
||||
| Form | Counts | Example |
|
||||
| ------- | ------------------------- | -------------- |
|
||||
| `one` | 1 | 1 מצלמה |
|
||||
| `two` | 2 | 2 מצלמות |
|
||||
| `other` | 0, 3, 10, 100, fractions… | 5 מצלמות |
|
||||
| Form | Counts | Example |
|
||||
| ------- | ---------------------------- | -------------- |
|
||||
| `one` | 1 and fractions below 1 | 1 מצלמה · 0.5 |
|
||||
| `two` | 2 | 2 מצלמות |
|
||||
| `other` | 0, 3, 10, 100, integers… | 5 מצלמות |
|
||||
|
||||
With {count} shown as a digit, `two` and `other` share the plural noun (2 מצלמות, 5 מצלמות); `one` takes the singular (1 מצלמה). For constructs that resist agreement with a noun (אין, הכול, זמין), phrase around the number: "{count} תחנות מדווחות" is fine, but prefer "ממתין: {count}" over a mismatched genitive chain.
|
||||
|
||||
@@ -37,7 +37,7 @@ With {count} shown as a digit, `two` and `other` share the plural noun (2 מצל
|
||||
| LIVE / live data / LIVE TRACK | חי / נתונים חיים / מעקב חי |
|
||||
| SIMULATED | מדומה |
|
||||
| stale / degraded / unavailable | מיושן / מופחת / לא זמין |
|
||||
| key (API key) / POWER UP | מפתח / אתחול |
|
||||
| key (API key) / POWER UP | מפתח / שדרוג |
|
||||
| globe / map / map source / basemap | גלובוס / מפה / מקור מפה / מפת בסיס |
|
||||
| aircraft / flight / military flight | מטוס (כלי טיס in class lists) / טיסה / טיסה צבאית |
|
||||
| vessel / ship / ships | אונייה / אוניות |
|
||||
@@ -48,10 +48,10 @@ With {count} shown as a digit, `two` and `other` share the plural noun (2 מצל
|
||||
| camera / CCTV camera / ALPR camera | מצלמה / מצלמת CCTV / מצלמת ALPR |
|
||||
| earthquake / active fire / cyclone | רעידת אדמה / שרפה פעילה / ציקלון |
|
||||
| scene / shot | סצנה / שוט |
|
||||
| briefing / panel / dock | דיווח / פאנל / עגינה |
|
||||
| briefing / panel / dock | תדריך / פאנל / עגינה |
|
||||
| visual preset / style | ערכת ראייה / סגנון |
|
||||
| Scope (circular viewport mask) / keyhole | סקופ / חור המנעול |
|
||||
| heading (compass °) / course | כיוון / מסלול |
|
||||
| heading (compass °) / course | כיוון / מהלך |
|
||||
| HDG / BRG / CRS / FOV / DEST / SPD / RANGE | בלי שינוי — קודי מכשיר |
|
||||
| advisory (NHC/CPHC cyclone) | ייעוץ; Advisory center — מרכז הייעוץ |
|
||||
| Street View (Google) | Street View, בלי תרגום |
|
||||
@@ -59,7 +59,7 @@ With {count} shown as a digit, `two` and `other` share the plural noun (2 מצל
|
||||
| WHOT/BHOT, Ironbow, CRT, NVG, FLIR | בלי שינוי — קודים ושמות מצבים |
|
||||
| PREV / NEXT | הקודם / הבא |
|
||||
| anchor / data pack / asset bundle (scene) | עוגן / חבילת נתונים / חבילת נכסים |
|
||||
| forecast (weather) | תחזית |
|
||||
| witness / geolocated source | עד ראייה / מקור נתון גיאוגרפית |
|
||||
| contained (wildland fire) / FRP | הכלה / FRP, בלי שינוי |
|
||||
|
||||
Latin product, provider and dataset names stay as printed: Google Maps, Cesium ion, OpenSky, ADS-B, AIS, KartaView, Mapillary, Panoramax, Overpass, InciWeb, iNaturalist, Acartia, NASA FIRMS, NOAA, USGS, CelesTrak, TomTom, Sentinel-2, Landsat, VIIRS, HLS, S2 GhostMaps, TeleGeography.
|
||||
@@ -1293,6 +1293,7 @@
|
||||
"src/i18n/locales/de.json",
|
||||
"src/i18n/locales/es.json",
|
||||
"src/i18n/locales/fr.json",
|
||||
"src/i18n/locales/he.json",
|
||||
"src/i18n/locales/it.json",
|
||||
"src/i18n/locales/ja.json",
|
||||
"src/i18n/locales/pt.json",
|
||||
|
||||
@@ -143,6 +143,7 @@ for (const [locale, summary] of [
|
||||
['ja', '東京上空のLive Flights'],
|
||||
['zh-CN', '北京航班stale数据'],
|
||||
['ru', 'Остин Live-Flights частично'],
|
||||
['he', 'תל אביב stale טיסות'],
|
||||
]) {
|
||||
test(`English flush against other text is an echo: ${summary}`, () => {
|
||||
assert.ok(hudSummaryHasEnglish(summary, locale, ['stale', 'Live Flights']));
|
||||
|
||||
@@ -110,7 +110,7 @@ const SUMMARY_LANGUAGES = Object.freeze({
|
||||
const UNSPACED_LOCALES = /^(?:ja|zh)(?:-|$)/;
|
||||
|
||||
/** Shipped locales not written in Latin letters. */
|
||||
const NON_LATIN_LOCALES = /^(?:ar|ja|ru|uk|zh)(?:-|$)/;
|
||||
const NON_LATIN_LOCALES = /^(?:ar|ja|ru|uk|zh|he)(?:-|$)/;
|
||||
|
||||
/** Scripts whose letters extend a word; any other neighbour ends it. */
|
||||
const WORD_SCRIPTS = [
|
||||
|
||||
@@ -41,9 +41,12 @@ test('normalizeLocale folds regional variants and rejects unshipped tags', () =>
|
||||
assert.equal(normalizeLocale('de'), 'de');
|
||||
assert.equal(normalizeLocale('de-AT'), 'de');
|
||||
assert.equal(normalizeLocale('de_CH'), 'de');
|
||||
// Hebrew keeps Western digits like its catalog; regional tags fold to he.
|
||||
// Hebrew keeps Western digits like its catalog; regional tags fold to he,
|
||||
// and the legacy tag iw is still what some browsers and OSes label Hebrew.
|
||||
assert.equal(normalizeLocale('he'), 'he');
|
||||
assert.equal(normalizeLocale('he-IL'), 'he');
|
||||
assert.equal(normalizeLocale('iw'), 'he');
|
||||
assert.equal(normalizeLocale('iw-IL'), 'he');
|
||||
assert.equal(normalizeLocale('fr'), 'fr');
|
||||
assert.equal(normalizeLocale('fr-CA'), 'fr');
|
||||
assert.equal(normalizeLocale('FR_be'), 'fr');
|
||||
|
||||
+3
-1
@@ -64,7 +64,8 @@ export function intlLocale(locale) {
|
||||
|
||||
/**
|
||||
* Map any language tag to a shipped locale: 'ru-RU' and 'RU' → 'ru',
|
||||
* 'ar-EG' and 'ar-SA' → 'ar', 'he-IL' and 'he' → 'he',
|
||||
* 'ar-EG' and 'ar-SA' → 'ar', 'he-IL' and 'he' → 'he', and the
|
||||
* legacy tag 'iw'/'iw-IL' → 'he',
|
||||
* 'de-AT' and 'de_CH' → 'de', 'ja-JP' → 'ja',
|
||||
* 'pt-BR' and 'pt-PT' → 'pt' (Brazilian Portuguese),
|
||||
* 'zh', 'zh-CN' and 'zh-Hans-SG' → 'zh-CN';
|
||||
@@ -80,6 +81,7 @@ export function normalizeLocale(candidate) {
|
||||
? 'zh-Hant'
|
||||
: 'zh-CN';
|
||||
}
|
||||
if (primary === 'iw') return 'he';
|
||||
return LOCALES.includes(primary) ? primary : null;
|
||||
}
|
||||
|
||||
|
||||
+178
-172
File diff suppressed because it is too large.
Load diff
@@ -1250,7 +1250,6 @@
|
||||
"DEST ---°",
|
||||
"SQUAWK {code} · {status}",
|
||||
"DEST {bearing}",
|
||||
"Space Missions",
|
||||
"CCTV",
|
||||
"S2 GhostMaps",
|
||||
"Street Level",
|
||||
@@ -1264,7 +1263,6 @@
|
||||
"km",
|
||||
"min",
|
||||
"dB",
|
||||
"LEVEL",
|
||||
"KTS",
|
||||
"FT",
|
||||
"FLT",
|
||||
@@ -1281,16 +1279,14 @@
|
||||
"STARLINK",
|
||||
"STARLINK ···",
|
||||
"STARLINK ✕",
|
||||
"LOOK STBD {bearing}°",
|
||||
"LOOK PORT {bearing}°",
|
||||
"LOOK ASTERN",
|
||||
"LOOK {elevation}",
|
||||
"{vesselType} · {feedState} · EYE {height}",
|
||||
"{range} NM",
|
||||
"OFF-NADIR {angle}° · {offset}",
|
||||
"NORAD {id}",
|
||||
"EPOCH {time}",
|
||||
"TLE",
|
||||
"OFF-NADIR {angle}°"
|
||||
"OFF-NADIR {angle}°",
|
||||
"{value} KM/S",
|
||||
"Ironbow"
|
||||
]
|
||||
}
|
||||
@@ -7,9 +7,10 @@
|
||||
*/
|
||||
|
||||
/** Shared visual tokens used by every world-overlay source. */
|
||||
// Map-card fonts: JetBrains Mono has no Arabic glyphs and the generic
|
||||
// monospace fallback is a fixed-pitch Arabic face that stretches every word;
|
||||
// Arabic text falls through to Noto Sans Arabic (loaded with the page fonts).
|
||||
// Map-card fonts: JetBrains Mono has no Arabic or Hebrew glyphs and the
|
||||
// generic monospace fallback is a fixed-pitch Arabic face that stretches every
|
||||
// word; Arabic falls through to Noto Sans Arabic, Hebrew to Noto Sans Hebrew
|
||||
// (both loaded with the page fonts).
|
||||
export const WORLD_OVERLAY_STYLE = Object.freeze({
|
||||
background: 'rgba(4, 12, 16, 0.82)',
|
||||
selectedBackground: 'rgba(5, 18, 24, 0.94)',
|
||||
@@ -19,13 +20,20 @@ export const WORLD_OVERLAY_STYLE = Object.freeze({
|
||||
detail: 'rgba(147, 161, 173, 0.92)',
|
||||
leader: 'rgba(147, 213, 228, 0.58)',
|
||||
accent: '#6be8ff',
|
||||
fontLabel: '500 10px "JetBrains Mono", "Noto Sans Arabic", monospace',
|
||||
fontTrack: '600 10px "JetBrains Mono", "Noto Sans Arabic", monospace',
|
||||
fontTitle: '600 12px "JetBrains Mono", "Noto Sans Arabic", monospace',
|
||||
fontDetail: '500 10.5px "JetBrains Mono", "Noto Sans Arabic", monospace',
|
||||
fontSelected: '600 13px "JetBrains Mono", "Noto Sans Arabic", monospace',
|
||||
fontTrackedTitle: '600 13px "JetBrains Mono", "Noto Sans Arabic", monospace',
|
||||
fontTrackedDetail: '500 11px "JetBrains Mono", "Noto Sans Arabic", monospace',
|
||||
fontLabel:
|
||||
'500 10px "JetBrains Mono", "Noto Sans Arabic", "Noto Sans Hebrew", monospace',
|
||||
fontTrack:
|
||||
'600 10px "JetBrains Mono", "Noto Sans Arabic", "Noto Sans Hebrew", monospace',
|
||||
fontTitle:
|
||||
'600 12px "JetBrains Mono", "Noto Sans Arabic", "Noto Sans Hebrew", monospace',
|
||||
fontDetail:
|
||||
'500 10.5px "JetBrains Mono", "Noto Sans Arabic", "Noto Sans Hebrew", monospace',
|
||||
fontSelected:
|
||||
'600 13px "JetBrains Mono", "Noto Sans Arabic", "Noto Sans Hebrew", monospace',
|
||||
fontTrackedTitle:
|
||||
'600 13px "JetBrains Mono", "Noto Sans Arabic", "Noto Sans Hebrew", monospace',
|
||||
fontTrackedDetail:
|
||||
'500 11px "JetBrains Mono", "Noto Sans Arabic", "Noto Sans Hebrew", monospace',
|
||||
radius: 4,
|
||||
anchorDotRadius: 3.2,
|
||||
anchorDotStrokeWidth: 1,
|
||||
|
||||
+18
-8
@@ -1,6 +1,7 @@
|
||||
/* Right-to-left languages (Arabic). The chrome mirrors through logical
|
||||
properties in the component sheets (inset-inline-*, margin-inline-*); this
|
||||
sheet holds only what logical properties cannot express. */
|
||||
/* Right-to-left languages (Arabic, Hebrew). The chrome mirrors through
|
||||
logical properties in the component sheets (inset-inline-*,
|
||||
margin-inline-*); this sheet holds only what logical properties cannot
|
||||
express. */
|
||||
|
||||
/* Arabic letters join: letter-spacing tears every word into separate glyphs.
|
||||
Latin marked translate="no" and the intel HUD's Latin telemetry keep their
|
||||
@@ -63,10 +64,9 @@ html:lang(ar) :is(#intel-hud, #cockpit-hud) {
|
||||
/* Hebrew: JetBrains Mono and Inter also lack Hebrew glyphs. Noto Sans Hebrew
|
||||
(loaded with the other Google fonts; its files download only when the page
|
||||
shows Hebrew) leads the stack so the body text keeps one proportional
|
||||
Hebrew face across platforms. Hebrew letters do not join like Arabic, but
|
||||
tracking still reads as gaps inside a word, so the body is released from it
|
||||
the same way; Latin marked translate="no" keeps its tracking. The intel and
|
||||
cockpit HUDs keep JetBrains Mono for their Latin telemetry. */
|
||||
Hebrew face across platforms. Hebrew letters do not join, so tracking on
|
||||
them only spaces a word out; the body is released the same way, and the
|
||||
HUDs keep their instrument tracking inside. */
|
||||
html:lang(he) {
|
||||
--font-mono:
|
||||
'Noto Sans Hebrew', 'JetBrains Mono', 'SF Mono', 'Fira Code', Tahoma,
|
||||
@@ -75,7 +75,10 @@ html:lang(he) {
|
||||
'Inter', 'Noto Sans Hebrew', -apple-system, BlinkMacSystemFont, Tahoma,
|
||||
sans-serif;
|
||||
}
|
||||
html:lang(he)
|
||||
/* The Global Context lines and their buttons set ui-monospace through the
|
||||
`font` shorthand; in both RTL languages the words come from the page's
|
||||
own font stack. */
|
||||
html:is(:lang(ar), :lang(he))
|
||||
:is(
|
||||
#military-awareness-panel,
|
||||
.military-awareness-controls button,
|
||||
@@ -87,6 +90,13 @@ html:lang(he)
|
||||
) {
|
||||
font-family: var(--font-mono);
|
||||
}
|
||||
/* The intel and cockpit HUDs keep JetBrains Mono leading for their Latin
|
||||
telemetry and column-aligned digits, with the language's face behind it. */
|
||||
html:lang(ar) :is(#intel-hud, #cockpit-hud) {
|
||||
--font-mono:
|
||||
'JetBrains Mono', 'SF Mono', 'Fira Code', 'Noto Sans Arabic', 'Geeza Pro',
|
||||
Tahoma, monospace;
|
||||
}
|
||||
html:lang(he) :is(#intel-hud, #cockpit-hud) {
|
||||
--font-mono:
|
||||
'JetBrains Mono', 'SF Mono', 'Fira Code', 'Noto Sans Hebrew', Tahoma,
|
||||
|
||||
Reference in new issue
Block a user