diff --git a/docs/CURRENT-STATE.md b/docs/CURRENT-STATE.md index c55031a6a..7e717a6ea 100644 --- a/docs/CURRENT-STATE.md +++ b/docs/CURRENT-STATE.md @@ -3733,7 +3733,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-Hant**. The code lives in +Shipped locales: **en** (source and fallback), **ar**, **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). @@ -3747,11 +3747,19 @@ Shipped locales: **en** (source and fallback), **es**, **ru**, **zh-CN** and **z `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 + bottom-right corner (bottom-left in Arabic) (`src/ui/localePicker.js`) stores the choice, drops `?lang=` (keeps it only when storage is blocked) and reloads. It asks first when the reload would lose work registered with `registerUnsavedWork`: unsaved keys or CCTV calibration, Draw marks, imported map files, the open cockpit, a voice session. +- **Right to left.** Arabic (`ar`) is in `RTL_LOCALES`, so ``: + the title, style indicator and both rails swap sides through logical + properties (`inset-inline-*`, `margin-inline-*`), the dock and corner row + reverse their order, and `src/ui/styles/rtl.css` holds the rest: no + letter-spacing on Arabic text, Noto Sans Arabic in the font stacks, the intel + HUD kept as a left-to-right instrument overlay, media transport and the radio + dial kept left to right. Intl formatters get `ar-u-nu-latn`, so numbers and + dates keep Western digits. - **Gate.** `npm run i18n` (and `src/i18n/catalog.test.mjs` under `npm test`) extracts every message and fails on missing, empty, unused, placeholder-mismatched, still-English (plural forms included) or diff --git a/docs/TRANSLATORS.md b/docs/TRANSLATORS.md index 830ca155e..9454b1719 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-Hant`). +Shipped languages: **English** (source and fallback), **Arabic** (`ar`), **Spanish** (`es`), **Russian** (`ru`), **Simplified Chinese** (`zh-CN`) and **Traditional Chinese** (`zh-Hant`). ## How it works @@ -44,7 +44,7 @@ Edit `src/i18n/locales/.json` and run `npm run i18n`. To see your change, 1. Create `src/i18n/locales/.json`, fill it from `npm run i18n -- --missing ` (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`. +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/.json` next to `ru.json` in `scripts/package-boundaries.json`. 5. Write `docs/translations/.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. @@ -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-Hant.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`: [Arabic](./translations/ar.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/ar.md b/docs/translations/ar.md new file mode 100644 index 000000000..e97e31ac2 --- /dev/null +++ b/docs/translations/ar.md @@ -0,0 +1,92 @@ +# Arabic (`ar`) + +Catalog: `src/i18n/locales/ar.json`. General rules: [TRANSLATORS.md](../TRANSLATORS.md). + +Translation sources: abiyeenzo (#915). + +## Style + +- Modern Standard Arabic, neutral across regions. Address the user with plain imperatives: «انقر»، «فعّل»، «أعد المحاولة». +- Arabic has no letter case: an UPPERCASE English HUD label becomes the same short Arabic label. Keep labels as short as the English: «مباشر»، «متقادم»، «متوقف». +- Status words in progress use «جارٍ …» («جارٍ التحميل»); finished actions use the passive («تم الحفظ»، «أُلغي التحميل»). +- Arabic punctuation in Arabic text: ، ؛ ؟ and «» for quotes. Keep `·` as the HUD separator, `—` with spaces, and `…`. +- Arrows that show a sequence point the way Arabic reads: «الإشارات ← الأخبار ← المحلي», «{origin} ← {destination}». +- Product names, provider names and codes stay in Latin letters: Google, Cesium ion, CelesTrak, NOAA, FIRMS, AIS, ADS-B, GNSS, CCTV, HUD, CRT, NVG, FLIR, WHOT/BHOT, Ironbow, Street View, Mapillary. Aviation and camera abbreviations stay Latin too: HDG, FOV, BRG, CRS, GS, TRK, V/S, SQUAWK. Local place names from the Bhote Koshi scene (Rasuwagadhi, Bidur, Timure…) stay Latin; well-known cities and countries are written in Arabic (أوستن، طوكيو، نيبال). +- Months are the international names used across the Arab world: يناير، فبراير … أغسطس. + +## Digits and direction + +- **Western digits (0–9)**, as in the catalog. The HUD reads like an instrument panel, and mixing ٠–٩ with Latin codes and coordinates misreads. `intlLocale('ar')` in `src/i18n/locale.js` passes `ar-u-nu-latn` to every Intl formatter, so browsers that default to Arabic-Indic digits for an Arabic region still show 0–9. +- **Right to left.** `ar` is in `RTL_LOCALES`, so the page gets ``. The title, style indicator and both rails swap sides; the dock and the corner row reverse. The intel HUD (classification block, MGRS, coordinates, GSD) stays a left-to-right instrument overlay; its translated lines read right to left inside it. Media transport (previous / play / next) and the radio dial stay left to right, as on any player. Layout rules: `src/ui/styles/rtl.css`. +- Latin runs inside Arabic sentences (product names, codes, `{placeholders}` filled with English data) are isolated by the bidi algorithm; write them as plain text, without manual direction marks. + +## Units + +Distances and speeds take Arabic abbreviations after the number, with a space: كم، م، كم/س، كم/ث، م/ث، ميل/س، عقدة (knots)، قدم (feet)، مم. Time: ث (seconds)، د (minutes)، س (hours)، يوم. Scientific and radio units stay Latin: MHz، dB، dBFS، dBZ، hPa، MW، MiB. `°` and `%` stay. Hemisphere letters in coordinates: ش (N)، ج (S)، ق (E)، غ (W), as in `21.33ش`. + +## Plurals + +`Intl.PluralRules('ar')` uses all six CLDR categories, and a `tn()` entry needs every one: + +| Form | Counts | Example | +| ------- | --------------------------- | ------------- | +| `zero` | 0 | 0 مصدر | +| `one` | 1 | مصدر واحد (1) | +| `two` | 2 | مصدران (2) | +| `few` | 3–10, 103–110… | 3 مصادر | +| `many` | 11–99, 111–199… | 11 مصدرًا | +| `other` | 100–102, 200–202, fractions | 100 مصدر | + +Every form must keep `{count}`. For one and two, Arabic names the quantity with the noun itself (مصدر واحد، مصدران), so the number follows in parentheses. `few` takes the plural noun; `many` the accusative singular (مصدرًا، مفتاحًا); `zero` and `other` the genitive singular. When a word next to the number cannot agree in every form, or a short chip has no room, put the number after a colon instead: «القريبة: {count}»، «الملفات المحددة: {count}». + +## Glossary + +| English | العربية | +| ----------------------------------------- | --------------------------------------------------------- | +| layer / data layer | طبقة / طبقة بيانات | +| feed / source | مصدر بيانات (short: مصدر) / مصدر | +| LIVE (status) / live data | مباشر / البيانات المباشرة (not حي) | +| SIMULATED | محاكى (status) / محاكاة | +| stale / degraded / unavailable | متقادم / متدهور / غير متاح | +| ON / OFF (state) | مفعّل / متوقف | +| retry | إعادة المحاولة | +| key (API key) / POWER UP | مفتاح (مفتاح API) / تشغيل | +| Provider Settings | إعدادات المزوّدين | +| globe / map / map source / basemap | الكرة الأرضية / الخريطة / مصدر الخريطة / الخريطة الأساسية | +| tiles | بلاطات | +| aircraft / flight / military flights | طائرة / رحلة / الرحلات العسكرية | +| vessel, ship | سفينة | +| satellite | قمر صناعي | +| launch (rocket) / space mission | إطلاق / مهمة فضائية | +| contact (tracked object) | هدف | +| installation, site / mapped | منشأة، موقع / مرسوم | +| camera / CCTV camera | كاميرا / كاميرا CCTV | +| earthquake / active fire / fire perimeter | زلزال / حريق نشط / محيط حريق | +| cyclone advisory | نشرة إعصار | +| scene / shot / scene recipe | مشهد / لقطة / قالب المشهد | +| briefing / panel / dock | إحاطة / لوحة / الشريط السفلي | +| preset / visual preset | إعداد مسبق / نمط بصري | +| Scope (circular viewport mask) / keyhole | المنظار / الفتحة | +| Clean UI | واجهة نظيفة | +| cockpit | القمرة (قمرة القيادة) | +| heading / altitude / ground speed | الاتجاه (HDG) / الارتفاع / السرعة الأرضية | +| Street Level / Street View | مستوى الشارع / Street View | +| Recent Imagery | الصور الحديثة | +| Global Context / Context | السياق العالمي / السياق | +| radio station / tuner / gain | محطة / موالف / الكسب | +| decoder (SDR) | مفكّك | +| transit / bike share | النقل العام / الدراجات المشتركة | +| Previous / Next | السابق / التالي | +| compass points (N, NNE, …) | شمال، شمال شمال شرق، … | +| forecast / valid / issued | توقع / صالح حتى / صدر | +| observation / observed | رصد / مرصود | +| field (weather) / model | حقل / نموذج | +| scene cloud | غيوم المشهد | +| box (Recent Imagery area) / pin | منطقة / تثبيت | +| THIS (voice pointer) | المُشار إليه | +| outline / mark (map annotation) | مخطط / علامة، تعليم | +| share (a view or link) | مشاركة | +| AI agent | وكيل ذكاء اصطناعي | +| stage (rocket) / downrange | مرحلة / على امتداد المسار | +| frame (bring into view) | إظهار في الإطار | +| story beat | مرحلة القصة |