Bilingual UI - msupino/NavigationApp GitHub Wiki

๐Ÿ‡ฎ๐Ÿ‡ฑ ืขื‘ืจื™ืช

Bilingual UI

NavAid ships a fully translated Hebrew (RTL) and English UI. Switch via the language picker in the toolbar (๐ŸŒ).

NavAid in English

The same app in Hebrew (RTL):

NavAid Hebrew UI

How language is chosen

The choice (on every page load) is short:

  1. ?lang=he or ?lang=en in the address, else
  2. Hebrew โ€” NavAid is flown in Israeli airspace and read in Hebrew by most of the people who open it.

That is the whole rule. A language is not remembered. A plain navaid.supino.org is Hebrew every time, not only the first, and English is a choice the address carries โ€” which the toolbar picker, the safety notice's selector and every link shared from inside the app all set.

What this replaced was a stored navaid.lang: it made a plain address mean different things on different devices, so "open navaid.supino.org" became an unanswerable question about what a pilot would actually see โ€” including for whoever was talking them through it over the radio. A key left behind by an older version is ignored, not honoured.

The bootstrap sets <html lang> and <html dir> before the stylesheet, and writes ?lang=โ€ฆ into the address so the language on screen is the language in the link you copy.

Two other places carry the same decision:

  • The safety notice has its own language control, because it is the first thing on screen and the toolbar's picker is behind it. What it picks is the app's language, not the notice's. See Safety notice.
  • About, Privacy and Terms resolve language exactly the same way โ€” ?lang, else Hebrew โ€” and store nothing either. They used to default to English and write that fallback, so opening Terms before the planner flipped the whole app to English.

Where strings live

  • docs/i18n/he/strings.js โ€” Hebrew overrides.
  • docs/i18n/en/strings.js โ€” empty (window.S = {}); English is the default locale defined inline in docs/app/core.js.

The locale file loads first; core.js then merges the English defaults beneath it (window.S = Object.assign({ โ€ฆdefaultsโ€ฆ }, window.S || {})), so a key like tbAddWp resolves to the locale value when present, else English. The HTML uses data-i18n="key" / data-i18n-title="key" / data-i18n-placeholder="key" attributes. A small init pass walks the DOM and fills text / title / placeholder from S.

Adding a new translated string requires:

  1. A new entry in docs/app/core.js (the English default) and, if translated, an override in docs/i18n/he/strings.js.
  2. A data-i18n="newKey" on the element.
  3. Do not bump cache values merely for deployment invalidation. docs/index.html keeps literal ?v=src; app/i18n data URLs retain their existing source values. Deploy rewrites both forms to the branch short SHA.

RTL handling

  • <html dir="rtl"> is set when Hebrew is active.
  • The toolbar swaps its handle / collapse icons via CSS logical properties (inline-start / inline-end).
  • The Hebrew page uses an entry-point HTML at docs/he/index.html that redirects to /?lang=he to preserve a stable, indexable Hebrew URL.

Dataset names

The CVFR graph has 172 layer members; the 170 active reporting points carry name, English en, and Hebrew he fields and appear in the overlay. The map label uses the locale's language; search matches both languages and renders primary / alt.

Airfields carry ICAO name, Hebrew he, and English en fields. Search matches all three, and the marker label shows ICAO plus the localized name.

Airfield charts strings

The charts viewer adds the following i18n keys (English defaults in docs/app/core.js, Hebrew overrides in docs/i18n/he/strings.js):

Key EN HE
plates Charts ื“ืคื™ื•ืช
plateCategoryApproach Approach ื’ื™ืฉื”
plateCategorySid SID SID
plateCategoryStar STAR STAR
plateCategoryGround Ground ืงืจืงืข
plateCategoryVfr VFR / Airport VFR / ืฉื“ื” ืชืขื•ืคื”
plateCategoryOther Other ืื—ืจ
plateOpen Open ืคืชื—
plateDownload Download ื”ื•ืจื“
plateOpenTab Open in new tab ืคืชื— ื‘ืœืฉื•ื ื™ืช ื—ื“ืฉื”
plateClose Close ืกื’ื•ืจ
platesNone No charts available โ€” see official AIP ืื™ืŸ ื“ืคื™ื•ืช โ€” ืจืื” AIP ื”ืจืฉืžื™
plateLoadError Failed to load chart. ื˜ืขื™ื ืช ื”ื“ืคื™ืช ื ื›ืฉืœื”.
plateAttribution Charts ยฉ Israel CAAI / Ministry of Transport โ€” published in the AIP. ืžืคื•ืช ยฉ ืจืฉื•ืช ื”ืชืขื•ืคื” ื”ืื–ืจื—ื™ืช / ืžืฉืจื“ ื”ืชื—ื‘ื•ืจื” โ€” ืžืคื•ืจืกื ื‘-AIP.

Notes for translators

  • The toolbar buttons and titles are user-visible and reviewed; pick the shortest natural phrasing โ€” the toolbar is narrow.
  • The inspector strings are also visible and frequently used.
  • "Mag var" is a pilot term โ€” in Hebrew use "ื ื˜ื™ื™ื” ืžื’ื ื˜ื™ืช"; do not invent.
  • "CVFR" stays as is in both languages (it's an internationally-recognised acronym).
  • Brand labels GitHub and Wiki stay in English in the Hebrew UI.

SEO

  • The page exposes hreflang he, en, and x-default alternates so search engines route users to the right language.
  • The page title is rewritten to a localized version on language switch; meta description / OG tags follow shortly (see SEO roadmap).
โš ๏ธ **GitHub.com Fallback** โš ๏ธ