join(', ') builds "A, B, C" for every reader. Arabic joins with و and no comma, Chinese with 、,
German and Russian with their own final conjunction, and no catalogue key can fix it, because the
separator and conjunction ARE the grammar. gospel measured it inside a fully keyed sentence
(pins.sharedPoint in Arabic still carried English commas) and counted 31 such joins across library
and plugins, with no Intl.ListFormat and no helper anywhere in the tree.
library/i18n now exports formatList(items, { type, style, locale }), backed by Intl.ListFormat.
It resolves the locale the way tStatic does (explicit argument, then the host's runtime locale,
then the page's), caches one formatter per locale and options, and falls back to ', ' only where
Intl.ListFormat does not exist. Proven from the shipped source, not a copy: en "A, B, and C",
ar "A وB وC", zh "A、B和C", de "A, B und C", disjunction "A or B", one item, none, and the runtime
locale when no argument is given. The call sites stay with their owners to migrate.
|
||
|---|---|---|
| .. | ||
| api | ||
| charts/whiteboard | ||
| colors | ||
| components | ||
| composables | ||
| constants | ||
| dashboards | ||
| data | ||
| elements | ||
| i18n | ||
| layouts | ||
| lists | ||
| maps | ||
| packet | ||
| packets | ||
| scripts | ||
| stores | ||
| styles | ||
| utils | ||
| vendor/cldr | ||
| 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.