Two gates:post reds from this landing's own commits, fixed at the source

check:optional-t-equivalence evaluates useOptionalT.js on its own, with its
imports stripped and tStatic and useI18n handed in. The composable now also
imports getRuntimeLocale and cldrChoiceIndex, so every section died with a
ReferenceError. The gate now hands in a bare host's getRuntimeLocale and the
shipped cldrChoiceIndex, lifted from library/i18n/index.js's own text; its
import control accepts tStatic among several names, but still only from
'@map/i18n/index.js' (a catalogue import of the module's own still fails).

check:frozen-labels caught the research filters' new search placeholder:
tStatic inside a computed that reads no locale never re-runs, so the
placeholder stayed in the boot language. It now reads and passes
locale.value, like the search chip in the same file.
This commit is contained in:
Doxa Maps 2026-09-29 04:49:03 +00:00
parent 1a0db171dc
commit 50b9f9a8a2
2 changed files with 16 additions and 4 deletions

View file

@ -28,8 +28,18 @@ const body = src
.replace(/^import .*$/gm, '') // drop the two un-runnable imports
.replace(/^export default .*$/gm, '') // and the default re-export (it is not a declaration)
.replace(/^export /gm, '')
const make = (tStatic, useI18n) => new Function('tStatic', 'useI18n',
body + '\nreturn { useOptionalT, useOptionalI18n, fillParams, qualify };')(tStatic, useI18n)
// The composable also imports getRuntimeLocale and cldrChoiceIndex from library/i18n/index.js, which
// cannot be imported here (vue-i18n and the @map alias). cldrChoiceIndex is lifted from that file's
// own text, so the plural rule under test is the shipped one; getRuntimeLocale is a bare host's: no
// locale set, which is the English path every section below exercises.
const i18nSrc = readFileSync(new URL('../library/i18n/index.js', import.meta.url), 'utf8')
const lift = (re, what) => { const m = i18nSrc.match(re); if (!m) throw new Error(`library/i18n/index.js no longer defines ${what}`); return m[0] }
const cldrChoiceIndex = new Function(
lift(/^const CLDR_CATEGORY_ORDER = .*$/m, 'CLDR_CATEGORY_ORDER') + '\n'
+ lift(/^export function cldrChoiceIndex\([\s\S]*?\n\}$/m, 'cldrChoiceIndex').replace(/^export /, '')
+ '\nreturn cldrChoiceIndex;')()
const make = (tStatic, useI18n, getRuntimeLocale = () => '') => new Function('tStatic', 'useI18n', 'getRuntimeLocale', 'cldrChoiceIndex',
body + '\nreturn { useOptionalT, useOptionalI18n, fillParams, qualify };')(tStatic, useI18n, getRuntimeLocale, cldrChoiceIndex)
// The English catalogue the old code imported, as a stub tree: messages.en.pplr equivalent.
const EN = { greeting: 'Hello {name}', nested: { deep: 'Deep value' } }
@ -89,7 +99,7 @@ const hostI18n = (table) => () => ({ t: (k) => (k in table ? table[k] : k) })
const { useOptionalT: u2 } = make(tStatic, hostI18n({ 'pplr.greeting': 'Bonjour' }))
ok(u2('pplr')('greeting') !== 'Hello Ada', 'NEG CONTROL: the host path and the catalogue path are distinguishable')
}
ok(/import \{ tStatic \}/.test(src), 'CONTROL: the shipped module really does route through tStatic (not a catalogue import of its own)')
ok(/import \{[^}]*\btStatic\b[^}]*\} from '@map\/i18n\/index\.js'/.test(src), 'CONTROL: the shipped module really does route through tStatic (not a catalogue import of its own)')
// ★ codeOnly, because this assertion failed on its OWN DOCUMENTATION: useOptionalT.js's header QUOTES
// '@map/i18n/locales/en/pplr.json' as the import it removed, and a whole-file grep counted the prose as
// the thing it forbids. Fifth time this session that a detector has read a comment as code.

View file

@ -111,7 +111,9 @@ const dropdownKeys = computed(() => {
const configured = rf.value.dropdowns || ['wagf_region', 'wagf_block', 'country_code', 'people_group', 'religion']
return [PRAYER_KEY, ...configured.filter((k) => k !== PRAYER_KEY)]
})
const searchPlaceholder = computed(() => rf.value.searchPlaceholder || tStatic('dashboard.search_placeholder') || 'Search people groups, place, language, religion…')
// locale.value is read and passed for the same reason as the search chip below: without it this
// computed never re-runs, and the placeholder stays in the boot language after a switch.
const searchPlaceholder = computed(() => rf.value.searchPlaceholder || tStatic('dashboard.search_placeholder', locale.value) || 'Search people groups, place, language, religion…')
// Apply a filter-set (facetKey -> label) to a row list — reused for cross-filtered counts.
function applyWith(fset, list) {