The dashboard's five resize handles are role="separator" widgets with arrow-key operation and live aria-valuenow — properly built, and four of them already read their names through T(). None of the six keys they asked for existed. aria.json held eleven keys and not one of them was a resize key, so every handle fell back to its English default in all eleven locales: a screen reader in Arabic announced "Resize filters rail" over an otherwise Arabic board. The T() call sites were right the whole time; the catalogue simply never caught up, which is the quiet half of this defect class and the half no gate was watching. Ten resize keys (each handle's accessible name plus its tooltip hint) and aria.removeFilter for the kit's chip strip, all eleven locales. Three dashboard keys for the shell's new polite live region: results_live, filters_live, search_live. They are the sentence a screen-reader user gets when a brush changes the row count — "693 of 2,107 groups shown · Filters: Religion". The counts arrive already formatted by the shell, so numerals are untouched here and the placeholders pass straight through. Keys are appended, never reordered: a catalogue diff that reshuffles is a diff nobody can review. check:i18n-parity and check:english-leaks pass, and check:i18n-never-translated finds none of these fourteen identical across locales. (It still reports poster.json:dpi, tables.json:csv and tables.json:json from before this branch.) |
||
|---|---|---|
| .. | ||
| api | ||
| colors | ||
| components | ||
| composables | ||
| constants | ||
| data | ||
| i18n | ||
| layouts | ||
| lists | ||
| maps | ||
| packet | ||
| scripts | ||
| stores | ||
| styles | ||
| utils | ||
| index.js | ||
| ProfileLoader.vue | ||
| README.md | ||
library/ (@map) — the shared map template
The other half of the architecture (see ../plugin-designs/README.md):
every map in plugin-designs/<your-map>/ composes the reusable, parameterized pieces that live here.
Fix something here and every map benefits on the next build; break something here and every map
breaks — read components/WARNING.md before touching shared pieces.
| Folder | What lives there |
|---|---|
ProfileLoader.vue |
The root of every bundle: parses profile-config, loads the profile, provides the stores + config |
components/ |
Shared UI — map, legends, controls, popup (PeopleGroupDetail), tables, charts, hints (README) |
composables/ |
Shared logic — map engine (useMapInstance), provider switch, shadow-DOM styles, theming |
stores/ |
Per-instance Pinia stores (ui / map / data) — provided by ProfileLoader, injected by children |
api/ |
Data-source registry (sources.json) + fetch layer — the JAMstack runtime wiring |
colors/ |
Color sets maps opt into via profile-config.colorSet |
i18n/ |
The shared string catalogs (all maps speak the same languages) |
data/ |
Small shared datasets baked at build time (big served data lives in ../data/) |
constants/ |
Shared constants |
scripts/ |
Maintainer pipelines (posters, research) — not part of any bundle |
The rule of thumb (same as WARNING.md): custom code in your app-profile, reusable code here — and things only move from the first to the second once they've earned it.