Posterverse: the Bless India Posters rail label is the plugin's own title

The rail row now uses the plugin's own title in all 11 locales, copied from its
catalogue (blessIndiaPosters.title), so the rail and the plugin name it the same
way. Copied rather than read at runtime: naming that catalogue area from the
shell would ship the plugin's whole catalogue inside posterverse.js.
check:posterverse-shelf arm F asserts the two stay equal in every locale; its
self-test plants a drifted label.
This commit is contained in:
Doxa Maps 2026-10-02 18:35:12 +00:00
parent 988bc0cf51
commit d329a3a612
2 changed files with 36 additions and 12 deletions

View file

@ -20,6 +20,7 @@
* D. posterverse.meta.json `composes` == the bundle/profile of every row whose bundle exists in
* plugin-designs/ (two-sided: nothing declared that the rail cannot show, nothing shown undeclared).
* E. strings: every locale carries every English key, and every key the shell reads exists in English.
* F. a rail label named in LABEL_FOLLOWS equals that plugin's own catalogue title, in every locale.
*
* Headless, no browser. Exit 0 pass · 1 fail · 75 not measured (no built manifest).
*/
@ -40,10 +41,14 @@ const GATED = 'key-cities'
// Rows whose plugin is a natural-height page: mounted unpinned so the pane scrolls them. Named, because a
// pinned scroll page traps its own content and nothing else would notice.
const EXPECT_SCROLL = ['bless-india-posters']
// Rail labels that must EQUAL the plugin's own title (vocabulary follows the plugin), per locale:
// row id -> [catalogue area file under library/i18n/locales/<locale>/, key inside it]. Copied, not read at
// runtime: naming the area from the shell would ship the plugin's whole catalogue inside posterverse.js.
const LABEL_FOLLOWS = { 'bless-india-posters': ['blessIndiaPosters.json', 'title'] }
const sameList = (a, b) => a.length === b.length && a.every((x, i) => x === b[i])
export function checkShelf({ SECTIONS, TABS, NEVER, resolveTabs, manifest, meta, bundleExists, STRINGS }) {
export function checkShelf({ SECTIONS, TABS, NEVER, resolveTabs, manifest, meta, bundleExists, STRINGS, pluginTitles = {} }) {
const errs = []
const notes = []
// A. exact membership, per section, in order
@ -104,6 +109,14 @@ export function checkShelf({ SECTIONS, TABS, NEVER, resolveTabs, manifest, meta,
const v = STRINGS[l][k]
if (typeof v !== 'string' || !v.trim()) errs.push(`E: ${l} is missing "${k}"`)
}
// F. labels that follow a plugin's own title, per locale
for (const [id, byLocale] of Object.entries(pluginTitles)) {
for (const [l, want] of Object.entries(byLocale)) {
const got = (STRINGS[l] || {})['tab.' + id]
if (want === undefined) errs.push(`F: ${l}: the plugin's own title for ${id} is missing from its catalogue`)
else if (got !== want) errs.push(`F: ${l}: tab.${id} is ${JSON.stringify(got)}, the plugin's own title is ${JSON.stringify(want)}`)
}
}
return { errs, notes, counts: { rows: TABS.length, resolved: resolved.length, composes: composes.length, locales: locales.length, keys: Object.keys(en).length } }
}
@ -115,7 +128,17 @@ async function load() {
const mf = join(ROOT, 'public', TREE_NAME, 'manifest.json')
const manifest = existsSync(mf) ? JSON.parse(readFileSync(mf, 'utf8')) : null
const bundleExists = (b, p) => existsSync(join(ROOT, 'plugin-designs', b, `${p}.vue`))
return { ...tabs, STRINGS, meta, manifest, bundleExists }
const pluginTitles = {}
for (const [id, [file, key]] of Object.entries(LABEL_FOLLOWS)) {
pluginTitles[id] = {}
for (const l of Object.keys(STRINGS)) {
const f = join(ROOT, 'library/i18n/locales', l, file)
let v
try { const j = JSON.parse(readFileSync(f, 'utf8')); v = key.split('.').reduce((o, k) => (o == null ? o : o[k]), j) } catch { v = undefined }
pluginTitles[id][l] = v
}
}
return { ...tabs, STRINGS, meta, manifest, bundleExists, pluginTitles }
}
function selfTest(base) {
@ -130,6 +153,7 @@ function selfTest(base) {
['C: a composite row falls back to a leaf', (c) => { c.manifest = clone(c.manifest); const b = c.manifest.bundles.find((x) => x.bundle === 'my-upg-100-list'); b.profiles = b.profiles.filter((p) => p.profile !== 'upg-100-mfe') }, /^C: row upg-100 opens/],
['D: composes drift', (c) => { c.meta = { ...c.meta, composes: c.meta.composes.slice(1) } }, /^D: the rail shows/],
['D: composes a ref the rail cannot show', (c) => { c.meta = { ...c.meta, composes: [...c.meta.composes, 'key-cities/key-cities'] } }, /^D: meta composes/],
['F: a rail label drifts from the plugin title', (c) => { c.STRINGS = clone(c.STRINGS); c.STRINGS.ar['tab.bless-india-posters'] = 'باركوا الهند: ملصقات' }, /^F: ar: tab\.bless-india-posters is/],
['E: a locale loses a key', (c) => { c.STRINGS = clone(c.STRINGS); delete c.STRINGS.ar['tab.upg-100'] }, /^E: ar is missing "tab.upg-100"/],
['E: a row without an English label', (c) => { c.STRINGS = clone(c.STRINGS); delete c.STRINGS.en['tab.bible-posters'] }, /^E: the shell reads "tab.bible-posters"/],
]

View file

@ -35,7 +35,7 @@ export const STRINGS = {
'tab.poster-design': 'Diseño de carteles', 'sub.poster-design': 'todos los estilos y tamaños de cartel',
'tab.wall-of-people-groups': 'Muro de los pueblos',
'tab.bible-posters': 'Carteles bíblicos',
'tab.bless-india-posters': 'Bendigan a la India: carteles',
'tab.bless-india-posters': 'Pósteres «Bendice a la India»',
experimentalSub: 'mapa experimental', lab: 'beta',
loading: 'Cargando {label}…', loadFailed: 'No se pudo cargar {label}.',
manifestHint: 'Esta pestaña se compone a partir de manifest.json: compila el árbol o sirve el árbol compilado para cargarla.',
@ -50,7 +50,7 @@ export const STRINGS = {
'tab.poster-design': 'Conception d’affiches', 'sub.poster-design': 'tous les styles et formats d’affiche',
'tab.wall-of-people-groups': 'Mur des peuples',
'tab.bible-posters': 'Affiches bibliques',
'tab.bless-india-posters': 'Bénissez l’Inde : affiches',
'tab.bless-india-posters': 'Affiches « Bénis l’Inde »',
experimentalSub: 'carte expérimentale', lab: 'bêta',
loading: 'Chargement de {label}…', loadFailed: 'Impossible de charger {label}.',
manifestHint: "Cet onglet est composé à partir de manifest.json : construisez l'arborescence ou servez l'arborescence construite pour le charger.",
@ -65,7 +65,7 @@ export const STRINGS = {
'tab.poster-design': 'Postergestaltung', 'sub.poster-design': 'alle Posterstile und -größen',
'tab.wall-of-people-groups': 'Wand der Volksgruppen',
'tab.bible-posters': 'Bibelposter',
'tab.bless-india-posters': 'Segnet Indien: Poster',
'tab.bless-india-posters': '„Segne Indien“-Poster',
experimentalSub: 'experimentelle Karte', lab: 'Beta',
loading: '{label} wird geladen…', loadFailed: '{label} konnte nicht geladen werden.',
manifestHint: 'Dieser Tab wird aus manifest.json zusammengesetzt – bauen Sie den Baum oder stellen Sie den gebauten Baum bereit, um ihn zu laden.',
@ -80,7 +80,7 @@ export const STRINGS = {
'tab.poster-design': 'Design de cartazes', 'sub.poster-design': 'todos os estilos e tamanhos de cartaz',
'tab.wall-of-people-groups': 'Mural dos povos',
'tab.bible-posters': 'Cartazes bíblicos',
'tab.bless-india-posters': 'Abençoem a Índia: cartazes',
'tab.bless-india-posters': 'Pôsteres «Abençoe a Índia»',
experimentalSub: 'mapa experimental', lab: 'beta',
loading: 'Carregando {label}…', loadFailed: 'Não foi possível carregar {label}.',
manifestHint: 'Esta aba é composta a partir do manifest.json — compile a árvore ou sirva a árvore compilada para carregá-la.',
@ -95,7 +95,7 @@ export const STRINGS = {
'tab.poster-design': 'Design dei poster', 'sub.poster-design': 'tutti gli stili e i formati dei poster',
'tab.wall-of-people-groups': 'Muro dei popoli',
'tab.bible-posters': 'Poster biblici',
'tab.bless-india-posters': 'Benedite l’India: poster',
'tab.bless-india-posters': 'Poster «Benedici l’India»',
experimentalSub: 'mappa sperimentale', lab: 'beta',
loading: 'Caricamento di {label}…', loadFailed: 'Impossibile caricare {label}.',
manifestHint: "Questa scheda è composta da manifest.json: compila l'albero o pubblica l'albero compilato per caricarla.",
@ -110,7 +110,7 @@ export const STRINGS = {
'tab.poster-design': 'Design de afișe', 'sub.poster-design': 'toate stilurile și dimensiunile de afiș',
'tab.wall-of-people-groups': 'Zidul popoarelor',
'tab.bible-posters': 'Afișe biblice',
'tab.bless-india-posters': 'Binecuvântați India: afișe',
'tab.bless-india-posters': 'Postere „Binecuvântează India”',
experimentalSub: 'hartă experimentală', lab: 'beta',
loading: 'Se încarcă {label}…', loadFailed: '{label} nu a putut fi încărcat.',
manifestHint: 'Această filă este compusă din manifest.json — construiți arborele sau serviți arborele construit pentru a o încărca.',
@ -125,7 +125,7 @@ export const STRINGS = {
'tab.poster-design': 'Дизайн плакатов', 'sub.poster-design': 'все стили и размеры плакатов',
'tab.wall-of-people-groups': 'Стена народов',
'tab.bible-posters': 'Библейские плакаты',
'tab.bless-india-posters': 'Благословляйте Индию: плакаты',
'tab.bless-india-posters': 'Плакаты «Благослови Индию»',
experimentalSub: 'экспериментальная карта', lab: 'бета',
loading: 'Загрузка: {label}…', loadFailed: 'Не удалось загрузить: {label}.',
manifestHint: 'Эта вкладка собирается из manifest.json — соберите дерево или разместите собранное дерево, чтобы загрузить её.',
@ -140,7 +140,7 @@ export const STRINGS = {
'tab.poster-design': 'تصميم الملصقات', 'sub.poster-design': 'كل أنماط الملصقات وأحجامها',
'tab.wall-of-people-groups': 'جدار الشعوب',
'tab.bible-posters': 'ملصقات الكتاب المقدس',
'tab.bless-india-posters': 'باركوا الهند: ملصقات',
'tab.bless-india-posters': 'ملصقات باركوا الهند',
experimentalSub: 'خريطة تجريبية', lab: 'تجريبي',
loading: 'جارٍ تحميل {label}…', loadFailed: 'تعذّر تحميل {label}.',
manifestHint: 'تُبنى علامة التبويب هذه من manifest.json — ابنِ الشجرة أو قدّم الشجرة المبنية لتحميلها.',
@ -155,7 +155,7 @@ export const STRINGS = {
'tab.poster-design': 'पोस्टर डिज़ाइन', 'sub.poster-design': 'हर पोस्टर शैली और आकार',
'tab.wall-of-people-groups': 'जनसमूहों की दीवार',
'tab.bible-posters': 'बाइबल पोस्टर',
'tab.bless-india-posters': 'भारत को आशीष दो: पोस्टर',
'tab.bless-india-posters': 'भारत को आशीष दें — पोस्टर',
experimentalSub: 'प्रायोगिक मानचित्र', lab: 'बीटा',
loading: '{label} लोड हो रहा है…', loadFailed: '{label} लोड नहीं हो सका।',
manifestHint: 'यह टैब manifest.json से बनता है — इसे लोड करने के लिए ट्री बनाएँ या बना हुआ ट्री सर्व करें।',
@ -170,7 +170,7 @@ export const STRINGS = {
'tab.poster-design': '海报设计', 'sub.poster-design': '所有海报样式与尺寸',
'tab.wall-of-people-groups': '民族之墙',
'tab.bible-posters': '圣经海报',
'tab.bless-india-posters': '祝福印度:海报',
'tab.bless-india-posters': '祝福印度海报',
experimentalSub: '实验性地图', lab: '测试版',
loading: '正在加载{label}…', loadFailed: '无法加载{label}。',
manifestHint: '此标签页由 manifest.json 组成——请构建目录树或提供已构建的目录树以加载它。',