From 0ea7dd48e721e01c3db48efa34d652cae7d66e8d Mon Sep 17 00:00:00 2001 From: Doxa Maps Date: Sat, 26 Sep 2026 17:22:44 +0000 Subject: [PATCH] ApproxPinNote renders on a host without vue-i18n It called useI18n() unguarded at setup. On an embeddable leaf whose host never installed vue-i18n that throws inside the custom-element boundary and leaves an empty shadow root: the FilterDropdown failure that blanked people-groups-grid. It now guards the call the way PinHint does, and falls back to the English pins.* wording with the same {names}/{n} placeholders filled. Reported by gospel-plugin. --- library/components/legends/ApproxPinNote.vue | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/library/components/legends/ApproxPinNote.vue b/library/components/legends/ApproxPinNote.vue index 4d6b0ab58..5610bb9dc 100644 --- a/library/components/legends/ApproxPinNote.vue +++ b/library/components/legends/ApproxPinNote.vue @@ -16,7 +16,15 @@ const props = defineProps({ shared: { type: Array, default: () => [] }, dark: { type: Boolean, default: false }, }) -const { t } = useI18n() +// i18n is OPTIONAL here, as in PinHint: an unguarded useI18n() throws on a host that never installed +// vue-i18n, inside the custom-element boundary, and the reader gets an empty shadow root. Without it +// the English below renders, with the same placeholders filled. +const APPROX_FALLBACK = { + 'pins.approximate': 'The dot marks where this people is found, not a town or a boundary.', + 'pins.sharedPoint': 'It sits on the same point as {names} — {n} groups share this coordinate, so the position tells you the locality and not which group is where.', +} +let t = (key, vars = {}) => (APPROX_FALLBACK[key] || key).replace(/\{(\w+)\}/g, (m, k) => (k in vars ? String(vars[k]) : m)) +try { t = useI18n().t } catch (_) { /* no i18n on this host */ } const second = computed(() => props.shared.length ? t('pins.sharedPoint', { names: props.shared.join(', '), n: props.shared.length + 1 }) : '')