Merge branch 'main' into sameh/firms-window-label

This commit is contained in:
Sameh Khamis authored and GitHub committed 2026-11-10 10:27:01 -08:00
commit bb45aacb24
18 files changed
+3735 -37

No files matched your search

+1
View File
@@ -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']));
+1 -1
View File
@@ -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 = [
+6
View File
@@ -41,6 +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,
// 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');
+2
View File
@@ -22,6 +22,7 @@ import ar from './locales/ar.json' with { type: 'json' };
import de from './locales/de.json' with { type: 'json' };
import es from './locales/es.json' with { type: 'json' };
import fr from './locales/fr.json' with { type: 'json' };
import he from './locales/he.json' with { type: 'json' };
import it from './locales/it.json' with { type: 'json' };
import ja from './locales/ja.json' with { type: 'json' };
import pt from './locales/pt.json' with { type: 'json' };
@@ -35,6 +36,7 @@ const CATALOGS = Object.freeze({
de,
es,
fr,
he,
it,
ja,
pt,
+6 -2
View File
@@ -14,6 +14,7 @@ export const LOCALES = Object.freeze([
'de',
'es',
'fr',
'he',
'it',
'ja',
'pt',
@@ -30,6 +31,7 @@ export const LOCALE_NAMES = Object.freeze({
de: 'Deutsch',
es: 'Español',
fr: 'Français',
he: 'עברית',
it: 'Italiano',
ja: '日本語',
pt: 'Português (Brasil)',
@@ -40,7 +42,7 @@ export const LOCALE_NAMES = Object.freeze({
});
/** Right-to-left locales. */
const RTL_LOCALES = Object.freeze(['ar']);
const RTL_LOCALES = Object.freeze(['ar', 'he']);
/** Whether a shipped locale reads right to left. */
export function isRtlLocale(locale) {
@@ -62,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',
* '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';
@@ -78,6 +81,7 @@ export function normalizeLocale(candidate) {
? 'zh-Hant'
: 'zh-CN';
}
if (primary === 'iw') return 'he';
return LOCALES.includes(primary) ? primary : null;
}
File diff suppressed because it is too large. Load diff
+97
View File
@@ -1190,5 +1190,102 @@
"acartia.io ↗",
"iNaturalist ↗",
"iNaturalist"
],
"he": [
"{speed} kn",
"GEO",
"SAR",
"EARTH WATCH",
"CRT",
"NVG",
"FLIR",
"AIS: --",
"REC",
"HDG {value}°",
"BRG {value}°",
"BRG —",
"CRS {value}°",
"FOV {value}°",
"CAL {value}",
"SRC {value}",
"▲ {frp} MW",
"≥ {value} MW",
"Intel Picture",
"Kinetic 30d",
"Border Crisis",
"Iran Picture",
"Iran Kinetic",
"Yemen FLOT",
"Latest Drop",
"1090 MHz",
"978 MHz UAT",
"ALT {altitude} FT · GS {speed} KT · TRK {track}",
"V/S {rate} FPM",
"Sentinel-2",
"Landsat 8/9",
"Google Street View",
"GOOGLE STREET VIEW",
"AIS: {name}",
"{type} SPD: {speed} HDG: {heading}",
"POS: {time}Z",
"{source} HTTP {status}",
"NNE",
"NE",
"ENE",
"ESE",
"SE",
"SSE",
"SSW",
"SW",
"WSW",
"WNW",
"NW",
"NNW",
"WHOT/BHOT",
"HDG",
"FOV",
"HGT",
"ΔN",
"ΔE",
"CAL · {badge}",
"DEST ---°",
"SQUAWK {code} · {status}",
"DEST {bearing}",
"CCTV",
"S2 GhostMaps",
"Street Level",
"STREET LEVEL",
"km/h",
"mph",
"hPa",
"kt",
"kts",
"ft",
"km",
"min",
"dB",
"KTS",
"FT",
"FLT",
"MIL",
"WX",
"MSG/S",
"FM MHZ",
"Acartia",
"CC BY 4.0",
"Salish Sea",
"iNaturalist",
"Be Whale Wise",
"MIC",
"STARLINK",
"STARLINK ···",
"STARLINK ✕",
"{range} NM",
"NORAD {id}",
"EPOCH {time}",
"TLE",
"{value} KM",
"{value} KM/S",
"Ironbow"
]
}
+18 -10
View File
@@ -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,
+4
View File
@@ -52,6 +52,7 @@ test('the current language comes first, the rest by their own names', () => {
'fr',
'it',
'pt',
'he',
'ar',
'zh-CN',
'zh-Hant',
@@ -75,6 +76,7 @@ test('the current language comes first, the rest by their own names', () => {
'pt',
'ru',
'uk',
'he',
'ar',
'zh-CN',
'zh-Hant',
@@ -98,6 +100,7 @@ test('the current language comes first, the rest by their own names', () => {
'pt',
'ru',
'uk',
'he',
'ar',
'zh-CN',
'zh-Hant',
@@ -122,6 +125,7 @@ test('the current language comes first, the rest by their own names', () => {
'pt',
'ru',
'uk',
'he',
'zh-CN',
'zh-Hant',
'ja',
+31 -9
View File
@@ -1,13 +1,15 @@
/* 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.
Hebrew letters do not join, but tracking only spaces their words out.
Latin marked translate="no" and the intel HUD's Latin telemetry keep their
tracking; the HUD's translated lines are released below. Unlike cjk.css, a
container that merely holds a translate="no" span is not spared: its own
Arabic text would come apart. */
html:lang(ar)
text would come apart. */
html:is(:lang(ar), :lang(he))
body
:not(#intel-hud, #intel-hud *, [translate='no'], [translate='no'] *) {
letter-spacing: 0 !important;
@@ -30,8 +32,7 @@ html[dir='rtl'] #intel-hud :is(.hud-mode, .hud-summary-label, .hud-summary) {
letter apart. Noto Sans Arabic (loaded with the other Google fonts; its
files download only when the page shows Arabic) leads the mono stack, so
the spaces between Arabic words come from it too and not from the
fixed-pitch Latin face. The intel and cockpit HUDs keep JetBrains Mono for
their Latin telemetry and column-aligned digits. */
fixed-pitch Latin face. */
html:lang(ar) {
--font-mono:
'Noto Sans Arabic', 'JetBrains Mono', 'SF Mono', 'Fira Code', 'Geeza Pro',
@@ -40,9 +41,23 @@ html:lang(ar) {
'Inter', 'Noto Sans Arabic', -apple-system, BlinkMacSystemFont, 'Geeza Pro',
Tahoma, sans-serif;
}
/* 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. */
html:lang(he) {
--font-mono:
'Noto Sans Hebrew', 'JetBrains Mono', 'SF Mono', 'Fira Code', Tahoma,
monospace;
--font-sans:
'Inter', 'Noto Sans Hebrew', -apple-system, BlinkMacSystemFont, Tahoma,
sans-serif;
}
/* The Global Context lines and their buttons set ui-monospace through the
`font` shorthand; route them through the Arabic-aware stack too. */
html:lang(ar)
`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,
@@ -54,11 +69,18 @@ html:lang(ar)
) {
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,
monospace;
}
/* The Display/Context rail moves to the left edge. It keeps a physical
`right` in layers.css because the attribution-clearance model