- The title, style indicator and both rails swap sides in RTL through logical
properties (inset-inline-*, margin-inline-*, border-inline-start); LTR
computes the same values. The Display/Context rail keeps its physical
`right` for the credit-clearance model and swaps in rtl.css above 720px.
- rtl.css: no letter-spacing on Arabic (it tears joined letters apart);
Noto Sans Arabic leads the Arabic font stacks so words are not set in a
fixed-pitch fallback; the intel HUD and cockpit instruments stay a
left-to-right instrument overlay; media transport and the radio dial stay
left to right; feed headlines and station names take their own direction;
the moved rail's arrows flip.
- isolate(): a quantity in RTL text (2.7 كم, -18.0°) is wrapped in
first-strong isolates so its digits do not join a neighbouring Latin run.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
- Register fr: catalog in CATALOGS, LOCALES and LOCALE_NAMES (Français);
any fr-* browser tag (fr-CA, fr-BE, fr-CH) maps to it.
- package-boundaries.json lists fr.json next to the other catalogs.
- Picker and locale tests cover the new row and its local names.
- docs/translations/fr.md: style, typography, plurals and glossary;
TRANSLATORS.md and CURRENT-STATE.md list French as shipped.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
- Translate the remaining 1,865 strings: aviation, maritime (AIS), weather
and remote-sensing terms, radio, routing, scenes, voice and setup.
- Review the 862 entries from #907: LIVE becomes DIRECT / en direct, stale
becomes obsolète, FIRMS detections are feux actifs, replay is rejeu, the
AIS ship types use the French terms (PILOTINE, SERVITUDE, POLICE), keys
stay Space / Esc / Enter as docs/TRANSLATORS.md asks, and NEXT/PREVIOUS
chips match PREV (SUIV. / PRÉC.).
- French typography: narrow no-break space before : ; ? ! and %, inside
« », and … for ellipsis; plural entries get the many form (exact
millions, "de").
- same-as-english.json: codes, units, genre and product names that French
spells the same as English.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
- Register ja: CATALOGS, LOCALES, LOCALE_NAMES (日本語) and the package
boundaries; ja and ja-JP tags select it.
- Japanese unit words follow the number directly, as in the catalog:
formatQuantity writes 5分 and 1時間5分 (km and kt keep the space), and
formatRelativeTime drops the space CLDR puts in 5 分前.
- Tests: locale tags, picker order, Intl output, durations and the
ramp/exit/lane wording in Japanese.
- docs/translations/ja.md: style, units, plurals and glossary; ja added to
TRANSLATORS.md and CURRENT-STATE.md.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
- Translate the 1,875 strings #913 did not cover (2,727 in all), for a
tactical HUD: aviation, maritime, weather and imagery terms, counters
next to numbers (機, 隻, 基, 件), year-first dates.
- Review the contributor entries: full-width punctuation ():? and …,
no space between Japanese and Latin, one katakana form per term
(ブラウザー, ビューアー), and fixes where the meaning was off:
NO PLACE LEFT BEHIND, LEVEL (horizon), CURATED / RAW PRIOR (CCTV
calibration), STALE (更新遅延, not 古い), rocket stage (段), SAR vessels,
T minus, POWER UP.
- List the codes, units and product names that stay as in English.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
- Translate the remaining 1,895 strings for the current UI (Bhote Koshi
event, weather, imagery, street level, directions, SDR, voice, scenes,
import) and review meirm's 832 entries from #312: 134 edited for
Ukrainian HUD terms (КУРС/ПЕЛ./ШЛЯХ/ПРИЗН., Л/П, ОНЛАЙН for LIVE,
Cyrillic units КМ, ВУЗ, ФТ, МВт), vessel types, number agreement and
the ʼ apostrophe throughout.
- Register uk: catalog, LOCALES, LOCALE_NAMES (Українська), package
boundaries, same-as-English codes; picker and plural tests cover the
four Ukrainian forms.
- docs/translations/uk.md: style, plurals, units and glossary.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
- Add ar to LOCALES (picker name العربية) and RTL_LOCALES, so <html dir>
turns rtl; any ar-* tag maps to it.
- Intl formatters get ar-u-nu-latn: numbers and dates keep Western digits
like the catalog, whatever the browser's ICU picks for Arabic regions.
- HUD quantities keep a space before an Arabic unit (2069.0 كم), as in
Chinese, instead of running digits into the word.
- Codes and product names that stay Latin go to same-as-english.json.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
- Translate the 1,875 strings #915 did not cover (2,727 in all), with all
six CLDR plural forms where tn() asks for them.
- Review pass on the #915 entries: LIVE reads مباشر (not حي, "alive"),
STALE reads متقادم, ON/OFF pair as مفعّل/متوقف; distances and speeds use
Arabic units (كم، م، قدم، عقدة) instead of Latin KM/FT/KTS; HUD stays HUD;
quotes are «» and a few clumsy count phrasings are rebuilt.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
- Translate the remaining 1,868 strings in a neutral infinitive style (no
Sie/du), with German compounds, decimal commas and CLDR one/other plurals.
- Review the #908 entries: knots are kn everywhere, the avionics codes BRG,
CRS and DEST stay English like HDG and SPD, expand/collapse is
ausklappen/einklappen, the radio toggle reads EIN/AUS, density SPARSE is
DÜNN, the Thermal style is Wärmebild, German quotes in the shot prompt.
- Register de: catalog, LOCALES, LOCALE_NAMES (Deutsch), package boundaries,
same-as-english (codes, product names, music genres, units).
- Tests: picker order and keyboard model with Deutsch, de/de-AT/de_CH
normalization, browser de-DE resolves to German.
- docs/translations/de.md: style, plurals, units and glossary; TRANSLATORS.md
and CURRENT-STATE.md list German.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
- Translate the remaining 1,868 strings (pt-BR, as in #909) and review the
contributor entries: HUD codes BRG/SPD/RANGE stay as in the other
languages, sentence-case layer and scene names, Space key named as on the
keyboard, short PREV/NEXT/ON/OFF chips, and the CLDR many form (exact
millions take «de») on every plural.
- Register pt: any pt tag (pt-BR, pt-PT) maps to it; the picker shows
«Português (Brasil)».
- Codes, units and product names identical to English go to
same-as-english.json.
- docs/translations/pt.md: style, plurals, units and glossary.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
- Register it: catalog in index.js, LOCALES and LOCALE_NAMES (Italiano);
it-IT, it-CH and other it tags select it.
- List it.json with the other catalogs in package-boundaries.json.
- docs/translations/it.md: style, plurals and glossary; Italian in the
shipped lists of TRANSLATORS.md and CURRENT-STATE.md.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
- Translate the 1,868 strings #912 does not cover: directions, weather and
wind, cyclones, Recent Imagery, Street Level, GNSS, the Bhote Koshi
reconstruction, scenes and sharing, local SDR, voice and key setup.
- Add the Italian `many` plural form (exact millions) to every plural entry.
- Review the #912 entries: fix RIMORCHIATORE, POWER UP (ACCENDI), DENSO,
minutes as "min", sentence case for layer and scene names, keyboard keys
kept in English (Space, Enter), and the SIG/NOTIZIE/LOCALE tab names.
- List codes, product names and words Italian spells as English in
same-as-english.json.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
The German locale by abiyeenzo (#908), converted from its namespaced JS
catalogs to the English-keyed de.json: 859 entries whose English still
matches the current UI.
The French locale by abiyeenzo (#907), converted from its namespaced JS
catalogs to the English-keyed fr.json: 862 entries whose English still
matches the current UI.
The Brazilian Portuguese locale by abiyeenzo (#909), converted from its
namespaced JS catalogs to the English-keyed pt.json: 859 entries whose
English still matches the current UI.
The Arabic locale by abiyeenzo (#915), converted from its namespaced JS
catalogs to the English-keyed ar.json: 852 entries whose English still
matches the current UI.
The Ukrainian locale by meirm (#312), converted from its namespaced JS
catalogs to the English-keyed uk.json: 832 entries whose English still
matches the current UI.
The Japanese locale by abiyeenzo (#913), converted from its namespaced JS
catalogs to the English-keyed ja.json: 852 entries whose English still
matches the current UI.
The Italian locale by abiyeenzo (#912), converted from its namespaced JS
catalogs to the English-keyed it.json: 859 entries whose English still
matches the current UI.
Correct 年曆史 → 年歷史, 下遊 → 下游, 並道 → 併道 and 發佈 → 發布,
and list these fixes for future reconversions from zh-CN.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
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]>
use bundled place boundaries and shared OpenFreeMap tiles before a guarded Nominatim fallback
preserve multipart shapes, holes and cancellation,
and keep pending annotations visible while ground sampling finishes across frames
keep non-Latin name distinctions when selecting provider results,
and retain an outline anchor only when it lies in filled geometry
The /api/military-installations endpoint was the last keyless proxy without
the admitSameSite gate that protects terrain, CCTV, traffic, places, and
Celestrak. A cross-site <img>, foreign Origin, opaque origin, or
reverse-proxy-forwarded request now receives 403 before any Overpass query.
Same-origin app requests and bare tool requests continue to work.
Adds 4 integration tests (cross-site refused, same-origin admitted,
bare tool admitted, proxied refused) following the terrainHeightsBounds
test pattern.
readsb reports an aircraft's vertical rate as geom_rate instead of baro_rate
when its source is GNSS. The military normaliser read only baro_rate, so about
one in six live /v2/mil contacts had a null vertical rate in analyst and
tracked-aircraft data. Fall back to geom_rate, as the adsb.lol flights
fallback already does; a sent baro_rate still wins.
The on-globe Contacts markers picked metres before rounding, so a contact
999.5 m or more away read "1000 m" while the Contacts panel read
"1.0 km". The marker label now rounds first, as the panel does.
select_nearest_aircraft passes altitudeM: null for an airborne contact
without a barometric altitude (military rows from adsb.lol can lack
alt_baro). The speech builder coerced it with Number(), and Number(null)
is 0, so the reply said "..., 0 feet." and the voice card showed
"Altitude 0 feet". Read the altitude only when it is a finite number,
so an unknown one is left out as the builder already intends.
Vessel cards and the AIS HUD rounded the direction without wrapping, so
a vessel reporting no heading and a course over ground of 359.5° or more
read "360°" on its cards and "HDG: 360DEG" in the HUD. The rounded
direction now wraps to 0°.
The Street Level viewer caption rounded the photo's bearing without
wrapping, so a view facing 359.5° or more read "360°". The rounded
bearing now wraps to 0°.
readsb omits lat/lon for a contact heard without a current position; about a
third of every /v2/mil response is such rows. They made every military
snapshot partial, so a contact that left the feed was retained at full
opacity for five minutes instead of fading and leaving on the missed-poll
limits. A row with a hex and no lat/lon now leaves the snapshot complete and
is listed in retainIds, as OpenSky's null-position rows already are.
Main now listens to camera.moveStart in IntelHUD's constructor (#1384), so
the fake camera in src/hudPageVisibility.test.mjs needs that event too, as
hudAltitudeDatum.test.mjs already has. No change to the fix itself.
Co-Authored-By: Claude Opus 5.5 <[email protected]>