|
Some checks are pending
build-gate / build (push) Waiting to run
The legend's toggle button announced the literal string "aria.toggleLegend" to screen readers. Not in translated locales only — in English too. vue-i18n echoes the key when a lookup misses, and `toggleLegend` was absent from every catalog while its two siblings in the same file, backToLegend and closeDetailView, were present. Six call sites across LegendDesktop.vue and LegendMobile.vue, desktop and mobile alike. aria-label is the one string a sighted tester never sees. Every other untranslated string in this tree got caught because somebody looked at the screen; this one is only ever spoken aloud, so it survived every visual QA pass. A second instance turned up in the same sweep with the opposite shape: SemanticTreeLegend hardcoded 'Collapse legend' / 'Expand legend' into both title and aria-label with no t() at all — correct English, and untranslatable. One key missing FROM the catalog, one string never routed TO it. Adds toggleLegend, collapseLegend and expandLegend to all 11 aria.json catalogs and routes the hardcoded pair through t(). check:i18n-parity already guards them. New gate smoke:aria-labels asserts BOTH shapes, because either assertion alone is insufficient: "no raw keys" passes a hardcoded English label forever, and "labels differ across locales" passes a raw key, since a key is identical in every locale. It detects a raw key by SHAPE — dotted, camelCase, no spaces — which is locale-independent and works on the Arabic and Chinese pages where no English word list could. Mutation-tested twice. Removing the catalog key fails with the raw key named, on all four viewport/locale combinations. Hardcoding one label back to English initially PASSED: the differ count dropped 6 to 5 and nothing asserted on it — the same "a number printed but not asserted on is decoration" shape this tree keeps rediscovering — so the gate gained a LOCALIZED_FLOOR ratchet and now fails that too. Verified the fix generalizes beyond the profile it was found on: country-posters reports 182 of 190 accessible names localized, 0 raw keys. Rebuilds the six bundles that embed a legend; check:sri confirms every leaf matches. Wave 34/34. |
||
|---|---|---|
| .. | ||
| locales | ||
| index.js | ||
| README.md | ||
library/i18n/ — the map's translations
One of the three customization seams (colors/, api/, i18n/). This one owns every
user-facing string. Translations are one folder per locale, one JSON file per area, inlined at
build time into a Vue I18n instance (one per <doxa-map>, so embeds don't bleed state).
i18n/
┌───────────────────────────────┐
│ index.js ← engine, don't edit │
│ locales/ │
│ en/ buttons.json legend.json …│ ← en is the source of truth + fallback
│ es/ ar/ zh/ … (same keys) │ ← 11 shipped locales, drop in your own
└───────────────────────────────┘
filename → namespace: buttons.json → $t('buttons.prayForThem')
- 11 shipped locales;
arrenders right-to-left (RTL_LOCALES). - Add a language by copying
locales/en/tolocales/<code>/— never by editingindex.js(except adding the code toSUPPORTED_LOCALES). - Missing keys fall back to English silently.
Adding or overriding a locale? The full contract (locale matrix, checklist, integration) is in ../../documentation/architecture/i18n.md.