The wall and the tab strip translate on a host with no vue-i18n
Both files hand-rolled the same guard — useI18n() in a try/catch, falling back to humanizeKey() — and both now route through library's useOptionalT (host i18n -> tStatic -> the key). The consolidation is incidental; deleting the FALLBACK is the product change, and dx-shepherd took it (UPGHK) under the Driver's standing goal that the production maps be localized. WHAT humanizeKey ACTUALLY DID, measured against the catalogues rather than reasoned about: messages.upg100WallIntro "Upg100 Wall Intro" -> "Hand away the prayer task in clusters of …" messages.upg100WallHeading "Upg100 Wall Heading" -> "My UPG 100 List — Prayer Lists & Posters" tabs.selectView "Select View" -> "Select View" (en) / "दृश्य चुनें" (hi) tabs.prayerResources "Prayer Resources" -> "Prayer Resources" (en) / "प्रार्थना संसाधन" (hi) Two different defects, and the second is why this survived so long. On the messages keys it printed GARBAGE — a title-cased identifier where a whole sentence exists, wrong even in English. On the tabs keys it printed the RIGHT English by coincidence, because the key was named after the word, so it looked correct forever while every non-English reader silently got English. A fallback that happens to agree with en is indistinguishable from a working translation until someone changes locale. ★ AND I HAD THE GUARD'S PURPOSE WRONG, which is the part worth recording. I told regions-plugin to keep humanizeKey because "my wall/poster keys are not fully catalogued". Enumerated: this is SEVEN keys total across both files, all string literals, no computed keys, and every one present in all ELEVEN locales — 0 gaps. The premise was false; I asserted a catalogue state from memory and presented it as a measurement. humanizeKey never guarded a MISSING KEY at all, it guarded a host that never installed vue-i18n (useI18n() throws; seven bundles here install none). Those are different failures, and useOptionalT's own header says so. Correction sent to regions, who has unwound the register row. Verified: check:sfc-parse PASS, check:no-free-identifiers PASS across 128 SFCs (which is what proves useOptionalT resolves and no orphaned useI18n reference is left behind), check:i18n-keys-exist PASS.
This commit is contained in:
parent
ff0c19e79a
commit
b97897b7bd
2 changed files with 31 additions and 13 deletions
|
|
@ -39,7 +39,7 @@
|
|||
* IDEA-POSTER-EXPORT-404-ON-DROPPED-FOLDER-TRADEOFF.
|
||||
*/
|
||||
import { computed, inject, ref } from 'vue'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
import { useOptionalT } from '@map/composables/useOptionalT.js'
|
||||
// The page's people-group LIST (library/lists/): every people-group fetch below keeps only its groups.
|
||||
import { applyPeopleGroupList } from '@map/lists/peopleGroupList.js'
|
||||
import PosterWall from '@map/components/poster/PosterWall.vue'
|
||||
|
|
@ -160,11 +160,22 @@ async function fetchListRecords(list) {
|
|||
// copy a reader reads FIRST was the untranslated part. The <strong> travels inside the
|
||||
// translated string so each language can emphasise its own words, which is not something a
|
||||
// wrapper around an English sentence could do.
|
||||
// Guarded like every other useI18n() here: it throws on a host without vue-i18n.
|
||||
const humanizeKey = (k) => String(k).split('.').pop()
|
||||
.replace(/([a-z0-9])([A-Z])/g, '$1 $2').replace(/^./, (c) => c.toUpperCase())
|
||||
let t = (k) => humanizeKey(k)
|
||||
try { t = useI18n().t } catch (_) { /* no i18n on this host */ }
|
||||
// Guarded like every other useI18n() here: it throws on a host without vue-i18n. useOptionalT stores
|
||||
// that guard once (host i18n -> tStatic -> the key itself) instead of a fourth hand-rolled copy.
|
||||
//
|
||||
// ★ NO humanizeKey FALLBACK, and the reason is a MEASUREMENT, not a preference. That fallback rendered
|
||||
// a key's last segment title-cased, so a bare host showed "Upg100 Wall Intro" where a real sentence
|
||||
// exists. It was kept on the theory that these keys were not fully catalogued — I said so to
|
||||
// regions-plugin, and it was FALSE: this file's three keys are present in all ELEVEN locales, 0 gaps
|
||||
// (enumerated 2026-09-27; they are the only three, all string literals, no computed keys).
|
||||
// So the fallback was shielding nothing and costing the translation. tStatic honours the READER'S
|
||||
// locale with English as the last resort, which is strictly better than an English-ish word derived
|
||||
// from an identifier.
|
||||
// ⚠ IT GUARDS A BARE HOST, NOT A MISSING KEY — those are different failures and I had them confused.
|
||||
// Switching changes what seven vue-i18n-less bundles render, so it is a product decision: taken by
|
||||
// dx-shepherd (UPGHK, 2026-09-27) as carrying out the Driver's standing goal that the production maps
|
||||
// be localized. Not a consolidation I was entitled to make on my own.
|
||||
const t = useOptionalT('messages')
|
||||
const intro = computed(() => t('messages.upg100WallIntro'))
|
||||
const heading = computed(() => t('messages.upg100WallHeading'))
|
||||
const wallTag = computed(() => t('messages.upg100WallTag'))
|
||||
|
|
|
|||
|
|
@ -34,7 +34,7 @@
|
|||
* whole MFE (both panes) is what gets shared/embedded.
|
||||
*/
|
||||
import { ref, computed, inject, onMounted, onBeforeUnmount } from 'vue'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
import { useOptionalT } from '@map/composables/useOptionalT.js'
|
||||
import { buildPaneColumn, PANE_GRID_STYLES } from '@map/layouts/pane-wrapper/pane-wrapper.js'
|
||||
import { useShadowStyles } from '@map/composables/useShadowStyles.js'
|
||||
import ViewSelect from '@map/components/ViewSelect.vue'
|
||||
|
|
@ -46,12 +46,19 @@ import ShareButton from '@map/components/map-controls/ShareButton.vue'
|
|||
// wrapper never did. The chrome a reader sees FIRST was the untranslated part.
|
||||
//
|
||||
// ⚠ GUARDED, like every other useI18n() call in this codebase: it THROWS on a host that has not
|
||||
// installed vue-i18n, and this component is mounted by hosts we do not control. The fallback
|
||||
// humanises the key so a bare host shows "Select View", never a blank or a raw dotted key.
|
||||
const humanizeKey = (k) => String(k).split('.').pop()
|
||||
.replace(/([a-z0-9])([A-Z])/g, '$1 $2').replace(/^./, (c) => c.toUpperCase())
|
||||
let t = (k) => humanizeKey(k)
|
||||
try { t = useI18n().t } catch (_) { /* no i18n on this host */ }
|
||||
// installed vue-i18n, and this component is mounted by hosts we do not control. useOptionalT holds
|
||||
// that guard once — host i18n first, then tStatic, then the key — instead of a hand-rolled copy here.
|
||||
//
|
||||
// ★ THE humanizeKey FALLBACK IS GONE ON PURPOSE. It rendered a key's last segment title-cased, so a
|
||||
// bare host showed "Select View" — which reads fine in English and is simply WRONG for every other
|
||||
// reader, because it cannot be translated: it is derived from the identifier, not from a catalogue.
|
||||
// tStatic honours the reader's locale and still ends at English. The four keys this file uses
|
||||
// (tabs.map / prayerResources / selectView / views) are present in all ELEVEN locales, 0 gaps,
|
||||
// enumerated 2026-09-27 — so nothing here was relying on the fallback.
|
||||
// Product decision, taken by dx-shepherd (UPGHK) under the Driver's standing goal that the production
|
||||
// maps be localized: switching changes what seven vue-i18n-less bundles render, which is not a call a
|
||||
// consolidation gets to make for itself.
|
||||
const t = useOptionalT('tabs')
|
||||
|
||||
const cfg = inject('profileConfig', ref(null))
|
||||
const tk = inject('mapboxToken', ref(''))
|
||||
|
|
|
|||
Loading…
Reference in a new issue