From e25a604c0aece7695a1dd690e5494b933e024223 Mon Sep 17 00:00:00 2001 From: RMA1313 <75065599+RMA1313@users.noreply.github.com> Date: Sat, 8 Aug 2026 20:20:23 +0330 Subject: [PATCH 1/3] feat(i18n): use Vazirmatn font for Persian locale --- apps/geolibre-desktop/package.json | 1 + apps/geolibre-desktop/src/index.css | 7 +++++++ apps/geolibre-desktop/src/main.tsx | 1 + package-lock.json | 10 ++++++++++ 4 files changed, 19 insertions(+) diff --git a/apps/geolibre-desktop/package.json b/apps/geolibre-desktop/package.json index 85ddf15af7..15a9d651a9 100644 --- a/apps/geolibre-desktop/package.json +++ b/apps/geolibre-desktop/package.json @@ -32,6 +32,7 @@ "@electric-sql/pglite": "^0.5.4", "@electric-sql/pglite-postgis": "^0.2.4", "@fontsource-variable/ibm-plex-sans": "^5.3.0", + "@fontsource-variable/vazirmatn": "^5.3.0", "@fontsource/ibm-plex-mono": "^5.3.0", "@geolibre/core": "*", "@geolibre/embed": "*", diff --git a/apps/geolibre-desktop/src/index.css b/apps/geolibre-desktop/src/index.css index 79daae6f8d..d3956fcdbc 100644 --- a/apps/geolibre-desktop/src/index.css +++ b/apps/geolibre-desktop/src/index.css @@ -27,6 +27,13 @@ "IBM Plex Mono", ui-monospace, SFMono-Regular, Menlo, Consolas, "Liberation Mono", monospace; } +html:lang(fa) { + --font-sans: + "Vazirmatn Variable", ui-sans-serif, system-ui, -apple-system, "Segoe UI", Roboto, + "Noto Sans Arabic", "Noto Sans", "Helvetica Neue", Arial, sans-serif, + "Apple Color Emoji", "Segoe UI Emoji"; +} + /* Map-floating chrome, a.k.a. "instrument glass". The distinction this encodes: chrome docked BESIDE the map (top toolbar, diff --git a/apps/geolibre-desktop/src/main.tsx b/apps/geolibre-desktop/src/main.tsx index e557c2dc7b..904313b287 100644 --- a/apps/geolibre-desktop/src/main.tsx +++ b/apps/geolibre-desktop/src/main.tsx @@ -9,6 +9,7 @@ import ReactDOM from "react-dom/client"; clean and 404s at runtime, silently falling back to system fonts. Importing from JS routes the CSS through Vite's asset pipeline instead. */ import "@fontsource-variable/ibm-plex-sans/wght.css"; +import "@fontsource-variable/vazirmatn/wght.css"; import "@fontsource/ibm-plex-mono/400.css"; import "@fontsource/ibm-plex-mono/700.css"; import "@geoman-io/maplibre-geoman-free/dist/maplibre-geoman.css"; diff --git a/package-lock.json b/package-lock.json index b9df927402..11732a9f2b 100644 --- a/package-lock.json +++ b/package-lock.json @@ -45,6 +45,7 @@ "@electric-sql/pglite": "^0.5.4", "@electric-sql/pglite-postgis": "^0.2.4", "@fontsource-variable/ibm-plex-sans": "^5.3.0", + "@fontsource-variable/vazirmatn": "^5.3.0", "@fontsource/ibm-plex-mono": "^5.3.0", "@geolibre/core": "*", "@geolibre/embed": "*", @@ -3887,6 +3888,15 @@ "url": "https://github.com/sponsors/ayuhito" } }, + "node_modules/@fontsource-variable/vazirmatn": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/@fontsource-variable/vazirmatn/-/vazirmatn-5.3.0.tgz", + "integrity": "sha512-ZA68W8JHbMdNzzwjYHUWKB2PH22QpxNEnk0ukcXM+XiqYMV6ZWJZAKuNXcrMR2JjuIAwsfAU3KknCXPI6wXUvw==", + "license": "OFL-1.1", + "funding": { + "url": "https://github.com/sponsors/ayuhito" + } + }, "node_modules/@fontsource/ibm-plex-mono": { "version": "5.3.0", "resolved": "https://registry.npmjs.org/@fontsource/ibm-plex-mono/-/ibm-plex-mono-5.3.0.tgz", From f98343c8d56459773d59b875175cb6db4a0735e2 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Sat, 8 Aug 2026 16:51:48 +0000 Subject: [PATCH 2/3] style: auto-format (ruff + oxfmt) [pre-commit.ci] --- apps/geolibre-desktop/src/index.css | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/geolibre-desktop/src/index.css b/apps/geolibre-desktop/src/index.css index d3956fcdbc..6f8068e2ee 100644 --- a/apps/geolibre-desktop/src/index.css +++ b/apps/geolibre-desktop/src/index.css @@ -30,8 +30,8 @@ html:lang(fa) { --font-sans: "Vazirmatn Variable", ui-sans-serif, system-ui, -apple-system, "Segoe UI", Roboto, - "Noto Sans Arabic", "Noto Sans", "Helvetica Neue", Arial, sans-serif, - "Apple Color Emoji", "Segoe UI Emoji"; + "Noto Sans Arabic", "Noto Sans", "Helvetica Neue", Arial, sans-serif, "Apple Color Emoji", + "Segoe UI Emoji"; } /* Map-floating chrome, a.k.a. "instrument glass". From 67bbb91e09c2d15f76f58571149d5d9f107937a9 Mon Sep 17 00:00:00 2001 From: giswqs Date: Sat, 8 Aug 2026 13:14:25 -0400 Subject: [PATCH 3/3] perf(i18n): load only Vazirmatn's arabic subset for Persian MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Importing @fontsource-variable/vazirmatn/wght.css pulled in all three of the font's subsets — arabic (46,308 B), latin (34,524 B) and latin-ext (21,860 B). The two Latin subsets duplicate coverage IBM Plex Sans already provides, and because every emitted asset lands in the Workbox precache manifest, they were not lazily fetched per unicode-range: the service worker downloaded all three on install for every user, whatever their locale. Fontsource publishes no subset-scoped entry point (index.css and wght.css both declare all three), so declare the @font-face by hand against the package's exported ./files/*.woff2. The Tailwind-inlining hazard documented in main.tsx does not apply — that one is specific to @importing fontsource's own CSS, whose relative url(./files/*.woff2) never reaches Vite's asset pipeline. Also add IBM Plex Sans to the fa stack, after Vazirmatn. Without the Latin subsets the Latin text that remains in a Persian UI (layer names, coordinates, product names) would drop to system-ui; this keeps it on the same typeface as every other locale, at no extra bytes since Plex is already loaded. dist delta vs main: +105,462 B -> +48,007 B. Precache: +101.92 KiB (3 entries) -> +45.95 KiB (1 entry). --- apps/geolibre-desktop/src/index.css | 50 +++++++++++++++++++++++++---- apps/geolibre-desktop/src/main.tsx | 1 - 2 files changed, 43 insertions(+), 8 deletions(-) diff --git a/apps/geolibre-desktop/src/index.css b/apps/geolibre-desktop/src/index.css index 6f8068e2ee..57efe968a0 100644 --- a/apps/geolibre-desktop/src/index.css +++ b/apps/geolibre-desktop/src/index.css @@ -7,10 +7,10 @@ /* App typeface: IBM Plex Sans for UI, IBM Plex Mono for the numeric/coordinate readouts (StatusBar, code, feature IDs). One matched superfamily, so the mono - readouts and the surrounding UI share a voice. The @font-face rules are - loaded from main.tsx — see the note there for why they cannot be @imported - here. Self-hosted rather than CDN-loaded: the desktop build must render - offline, and the Tauri CSP is `default-src 'self'`. + readouts and the surrounding UI share a voice. Fontsource's own @font-face + stylesheets are loaded from main.tsx — see the note there for why they cannot + be @imported here. Self-hosted rather than CDN-loaded: the desktop build must + render offline, and the Tauri CSP is `default-src 'self'`. This block drives both the `font-sans`/`font-mono` utilities and Tailwind's preflight default, so no `font-family` on is needed. @@ -27,11 +27,47 @@ "IBM Plex Mono", ui-monospace, SFMono-Regular, Menlo, Consolas, "Liberation Mono", monospace; } +/* Persian (fa) is the one locale that needs a second webfont: Plex has no + Arabic-script coverage, so without this the UI falls back to whatever the + system happens to ship. Only the *arabic* subset is loaded — Vazirmatn also + publishes latin and latin-ext, but those duplicate Plex for 56 KB, and the + service worker precaches every emitted asset, so an unused subset is weight + every user downloads on SW install rather than a lazy per-glyph fetch. + + Written out by hand rather than imported from main.tsx because fontsource + ships no subset-scoped entry point: both index.css and wght.css declare all + three subsets. The Tailwind-inlining hazard described in main.tsx does not + apply here — it is specific to @importing fontsource's CSS, whose relative + url(./files/*.woff2) never reaches Vite's asset pipeline. A bare package + specifier in a url() that Tailwind passes through is rewritten normally. + + unicode-range is copied verbatim from the package's wght.css; keep it in sync + if @fontsource-variable/vazirmatn is bumped and the subset boundaries move. */ +@font-face { + font-family: "Vazirmatn Variable"; + font-style: normal; + font-display: swap; + font-weight: 100 900; + src: url("@fontsource-variable/vazirmatn/files/vazirmatn-arabic-wght-normal.woff2") + format("woff2-variations"); + unicode-range: + U+0600-06FF, U+0750-077F, U+0870-088E, U+0890-0891, U+0897-08E1, U+08E3-08FF, U+200C-200E, + U+2010-2011, U+204F, U+2E41, U+FB50-FDFF, U+FE70-FE74, U+FE76-FEFC, U+102E0-102FB, + U+10E60-10E7E, U+10EC2-10EC4, U+10EFC-10EFF, U+1EE00-1EE03, U+1EE05-1EE1F, U+1EE21-1EE22, + U+1EE24, U+1EE27, U+1EE29-1EE32, U+1EE34-1EE37, U+1EE39, U+1EE3B, U+1EE42, U+1EE47, U+1EE49, + U+1EE4B, U+1EE4D-1EE4F, U+1EE51-1EE52, U+1EE54, U+1EE57, U+1EE59, U+1EE5B, U+1EE5D, U+1EE5F, + U+1EE61-1EE62, U+1EE64, U+1EE67-1EE6A, U+1EE6C-1EE72, U+1EE74-1EE77, U+1EE79-1EE7C, U+1EE7E, + U+1EE80-1EE89, U+1EE8B-1EE9B, U+1EEA1-1EEA3, U+1EEA5-1EEA9, U+1EEAB-1EEBB, U+1EEF0-1EEF1; +} + +/* Vazirmatn covers the Arabic script; Plex stays second so the Latin text that + remains in a Persian UI (layer names, coordinates, product names) keeps the + same voice as every other locale instead of dropping to system-ui. */ html:lang(fa) { --font-sans: - "Vazirmatn Variable", ui-sans-serif, system-ui, -apple-system, "Segoe UI", Roboto, - "Noto Sans Arabic", "Noto Sans", "Helvetica Neue", Arial, sans-serif, "Apple Color Emoji", - "Segoe UI Emoji"; + "Vazirmatn Variable", "IBM Plex Sans Variable", ui-sans-serif, system-ui, -apple-system, + "Segoe UI", Roboto, "Noto Sans Arabic", "Noto Sans", "Helvetica Neue", Arial, sans-serif, + "Apple Color Emoji", "Segoe UI Emoji"; } /* Map-floating chrome, a.k.a. "instrument glass". diff --git a/apps/geolibre-desktop/src/main.tsx b/apps/geolibre-desktop/src/main.tsx index 904313b287..e557c2dc7b 100644 --- a/apps/geolibre-desktop/src/main.tsx +++ b/apps/geolibre-desktop/src/main.tsx @@ -9,7 +9,6 @@ import ReactDOM from "react-dom/client"; clean and 404s at runtime, silently falling back to system fonts. Importing from JS routes the CSS through Vite's asset pipeline instead. */ import "@fontsource-variable/ibm-plex-sans/wght.css"; -import "@fontsource-variable/vazirmatn/wght.css"; import "@fontsource/ibm-plex-mono/400.css"; import "@fontsource/ibm-plex-mono/700.css"; import "@geoman-io/maplibre-geoman-free/dist/maplibre-geoman.css";