From 1c7104e90b630bec6f5df7351d9f3fb1fe3b6bcc Mon Sep 17 00:00:00 2001 From: Doxa Maps Date: Sat, 26 Sep 2026 07:42:47 +0000 Subject: [PATCH] List names speak the reader's language: listLabel and listDefinition library/lists/lists.json carried one English label per list, so every surface that showed a list's name printed English in every locale (reported by upg100, which worked around it inside the packet's own strings). - A `lists` catalogue area, library/i18n/locales//lists.json: a label and a definition for each of the five lists, in all 11 locales. - listLabel(id, t) / listDefinition(id, t) in peopleGroupList.js resolve lists..label through the caller's translator (useI18n's t, tStatic, or any key -> string), accept ids and aliases ('700'), and fall back to the registry's English. The module still imports no i18n runtime, so it stays pure and testable in Node. - The registry's labels are now documented as the English fallback only, and the doxa list gains the definition its catalogue entry has. - check:list-prop-unit (24 cases, was 17): the Arabic and German catalogues come through, a missing translator or a raw key falls back to English, the English catalogue must equal the registry word for word (a drifted registry label fails it, naming the list), and every locale must carry both fields for every list. - documentation/reference-universal-props.md: read names through listLabel. Headless: list-prop-unit, i18n-parity, i18n-never-translated, no-free-identifiers and universal-props pass. No consumer calls listLabel yet (the packet has its own strings), so nothing renders differently until one does. --- documentation/reference-universal-props.md | 3 +++ internal/check-list-prop-unit.mjs | 30 +++++++++++++++++++--- library/i18n/locales/ar/lists.json | 22 ++++++++++++++++ library/i18n/locales/de/lists.json | 22 ++++++++++++++++ library/i18n/locales/en/lists.json | 22 ++++++++++++++++ library/i18n/locales/es/lists.json | 22 ++++++++++++++++ library/i18n/locales/fr/lists.json | 22 ++++++++++++++++ library/i18n/locales/hi/lists.json | 22 ++++++++++++++++ library/i18n/locales/it/lists.json | 22 ++++++++++++++++ library/i18n/locales/pt/lists.json | 22 ++++++++++++++++ library/i18n/locales/ro/lists.json | 22 ++++++++++++++++ library/i18n/locales/ru/lists.json | 22 ++++++++++++++++ library/i18n/locales/zh/lists.json | 22 ++++++++++++++++ library/lists/lists.json | 3 ++- library/lists/peopleGroupList.js | 18 +++++++++++++ 15 files changed, 292 insertions(+), 4 deletions(-) create mode 100644 library/i18n/locales/ar/lists.json create mode 100644 library/i18n/locales/de/lists.json create mode 100644 library/i18n/locales/en/lists.json create mode 100644 library/i18n/locales/es/lists.json create mode 100644 library/i18n/locales/fr/lists.json create mode 100644 library/i18n/locales/hi/lists.json create mode 100644 library/i18n/locales/it/lists.json create mode 100644 library/i18n/locales/pt/lists.json create mode 100644 library/i18n/locales/ro/lists.json create mode 100644 library/i18n/locales/ru/lists.json create mode 100644 library/i18n/locales/zh/lists.json diff --git a/documentation/reference-universal-props.md b/documentation/reference-universal-props.md index 4d0aa4350..b027adc0d 100644 --- a/documentation/reference-universal-props.md +++ b/documentation/reference-universal-props.md @@ -148,6 +148,9 @@ the IMB / peoplegroups.org dataset (never a hand-kept roster). Aliases name them from the IMB CSV and the DOXA snapshot that `build-vision-funnel.mjs` saves). - **An unknown list** falls back to `'doxa'` with a console warning. **A list whose membership cannot load** shows no groups (fails closed), never DOXA's whole list under another list's name. +- **Showing a list's name:** `listLabel(id, t)` and `listDefinition(id, t)` read the reader's catalogue + (`i18n/locales//lists.json`, area `lists`) through the caller's translator, and fall back to the + registry's English. Never print `lists.json`'s `label` directly: it is the English fallback only. - **Guarded by** `check:universal-props` (LIST-FETCH, LIST-DSM, LIST-KEYS) and `check:list-prop-unit`. diff --git a/internal/check-list-prop-unit.mjs b/internal/check-list-prop-unit.mjs index 936671d23..d094f8716 100644 --- a/internal/check-list-prop-unit.mjs +++ b/internal/check-list-prop-unit.mjs @@ -8,11 +8,14 @@ * - the default list returns the SAME array, untouched, with no fetch at all; * - a list keeps exactly the rows whose slug is in its membership file, fetched from the asset pool; * - a membership that cannot load FAILS CLOSED: no rows, never the whole DOXA list; - * - every registry list with an imb filter has a membership file, and its counts match the slugs. + * - every registry list with an imb filter has a membership file, and its counts match the slugs; + * - listLabel / listDefinition read the reader's catalogue (library/i18n/locales//lists.json), + * fall back to the registry's English, the English catalogue equals the registry, and every + * locale carries a label and a definition for every list. * USAGE node internal/check-list-prop-unit.mjs EXIT 0 pass · 1 fail */ import { register } from 'node:module' -import { readFileSync, existsSync } from 'node:fs' +import { readFileSync, existsSync, readdirSync } from 'node:fs' import { resolve, dirname, join } from 'node:path' import { fileURLToPath } from 'node:url' @@ -65,6 +68,27 @@ for (const l of L.peopleGroupLists().filter((x) => x.source === 'imb')) { check(`${l.id}: file matches its registry filter, counts match its slugs`, [JSON.stringify(d.filter) === JSON.stringify(l.filter), d.counts.doxa === d.slugs.length, d.counts.imb >= d.counts.doxa], [true, true, true]) } +console.log('labels in the reader\'s language') +const cat = (lc) => JSON.parse(readFileSync(join(ROOT, 'library/i18n/locales', lc, 'lists.json'), 'utf8')) +const tFrom = (lc) => (key) => key.split('.').slice(1).reduce((o, k) => (o == null ? o : o[k]), cat(lc)) ?? key +check('no translator -> the registry English', L.listLabel('700'), 'Project 700: frontier people groups of 500,000 or more') +check('a translator that returns the key -> English', L.listLabel('frontier', (k) => k), 'Project 4700: frontier people groups') +check('Arabic catalogue, by alias', L.listLabel('4700', tFrom('ar')), cat('ar').frontier.label) +check('definition, German catalogue', L.listDefinition('unreached', tFrom('de')), cat('de').unreached.definition) +check('an unknown list -> empty, not a crash', L.listLabel('project-9999', tFrom('en')), '') +{ const en = cat('en'), bad = [] + for (const l of L.peopleGroupLists()) { + if (en[l.id]?.label !== l.label) bad.push(`${l.id}.label`) + if ((en[l.id]?.definition || '') !== (l.definition || '')) bad.push(`${l.id}.definition`) + } + check('the English catalogue matches the registry, word for word', bad, []) } +{ const missing = [] + for (const lc of readdirSync(join(ROOT, 'library/i18n/locales'))) { + const c = cat(lc) + for (const l of L.peopleGroupLists()) for (const f of ['label', 'definition']) if (!c[l.id]?.[f]) missing.push(`${lc}:${l.id}.${f}`) + } + check('every locale has a label and a definition for every list', missing, []) } + const failed = results.filter((x) => !x).length -console.log(failed ? `LIST-PROP: FAIL — ${failed} case(s)` : `LIST-PROP: PASS — ${results.length} cases: the ladder, aliases, the untouched default, membership filtering, fail-closed, and the membership files`) +console.log(failed ? `LIST-PROP: FAIL — ${failed} case(s)` : `LIST-PROP: PASS — ${results.length} cases: the ladder, aliases, the untouched default, membership filtering, fail-closed, the membership files, and labels in every locale`) process.exit(failed ? 1 : 0) diff --git a/library/i18n/locales/ar/lists.json b/library/i18n/locales/ar/lists.json new file mode 100644 index 000000000..da613c379 --- /dev/null +++ b/library/i18n/locales/ar/lists.json @@ -0,0 +1,22 @@ +{ + "doxa": { + "label": "المشروع 2000: الشعوب التي تخدمها DOXA", + "definition": "الشعوب التي تخدمها DOXA كما تقدّمها قائمتها الحيّة" + }, + "unreached": { + "label": "المشروع 7000: الشعوب غير المُبشَّرة", + "definition": "أولوية الضياع لدى IMB من 0 إلى 2 (حدودية أو رائدة أو متوسّعة غير مُبشَّرة: أقل من 2% إنجيليون)" + }, + "frontier": { + "label": "المشروع 4700: الشعوب الحدودية", + "definition": "أولوية الضياع لدى IMB بقيمة 0 (حدودية غير مُبشَّرة: 0.1% إنجيليون أو أقل)" + }, + "frontier-500k": { + "label": "المشروع 700: الشعوب الحدودية التي يبلغ عددها 500,000 أو أكثر", + "definition": "أولوية الضياع لدى IMB بقيمة 0 وعدد سكان لا يقل عن 500,000" + }, + "unengaged": { + "label": "الشعوب غير المُبشَّرة التي لم يُعمَل بينها", + "definition": "أولوية الضياع لدى IMB من 0 إلى 2 وحالة العمل: لم يُعمَل بينها" + } +} diff --git a/library/i18n/locales/de/lists.json b/library/i18n/locales/de/lists.json new file mode 100644 index 000000000..b2eeebdfa --- /dev/null +++ b/library/i18n/locales/de/lists.json @@ -0,0 +1,22 @@ +{ + "doxa": { + "label": "Projekt 2000: die Volksgruppen von DOXA", + "definition": "Die Volksgruppen, denen DOXA dient, wie seine Live-Liste sie angibt" + }, + "unreached": { + "label": "Projekt 7000: unerreichte Volksgruppen", + "definition": "IMB Lostness Priority 0–2 (Frontier, Pioneer oder Expanding Unreached: unter 2 % Evangelikale)" + }, + "frontier": { + "label": "Projekt 4700: Frontier-Volksgruppen", + "definition": "IMB Lostness Priority 0 (Frontier Unreached: 0,1 % Evangelikale oder weniger)" + }, + "frontier-500k": { + "label": "Projekt 700: Frontier-Volksgruppen mit 500.000 oder mehr Menschen", + "definition": "IMB Lostness Priority 0 und eine Bevölkerung von mindestens 500.000" + }, + "unengaged": { + "label": "Unerreichte Volksgruppen ohne Engagement", + "definition": "IMB Lostness Priority 0–2 und Engagement-Status: ohne Engagement" + } +} diff --git a/library/i18n/locales/en/lists.json b/library/i18n/locales/en/lists.json new file mode 100644 index 000000000..06c446a67 --- /dev/null +++ b/library/i18n/locales/en/lists.json @@ -0,0 +1,22 @@ +{ + "doxa": { + "label": "Project 2000: DOXA's people groups", + "definition": "The people groups DOXA serves, as its live list gives them" + }, + "unreached": { + "label": "Project 7000: unreached people groups", + "definition": "IMB Lostness Priority 0-2 (Frontier, Pioneer or Expanding Unreached: under 2% evangelical)" + }, + "frontier": { + "label": "Project 4700: frontier people groups", + "definition": "IMB Lostness Priority 0 (Frontier Unreached: 0.1% evangelical or less)" + }, + "frontier-500k": { + "label": "Project 700: frontier people groups of 500,000 or more", + "definition": "IMB Lostness Priority 0 and Population of at least 500,000" + }, + "unengaged": { + "label": "Unengaged unreached people groups", + "definition": "IMB Lostness Priority 0-2 and Engagement Status Unengaged" + } +} diff --git a/library/i18n/locales/es/lists.json b/library/i18n/locales/es/lists.json new file mode 100644 index 000000000..f72d88035 --- /dev/null +++ b/library/i18n/locales/es/lists.json @@ -0,0 +1,22 @@ +{ + "doxa": { + "label": "Proyecto 2000: los pueblos de DOXA", + "definition": "Los pueblos a los que sirve DOXA, tal como los da su lista en vivo" + }, + "unreached": { + "label": "Proyecto 7000: pueblos no alcanzados", + "definition": "Prioridad de perdición de IMB 0–2 (no alcanzados de frontera, pioneros o en expansión: menos del 2 % evangélicos)" + }, + "frontier": { + "label": "Proyecto 4700: pueblos de frontera", + "definition": "Prioridad de perdición de IMB 0 (no alcanzados de frontera: 0,1 % evangélicos o menos)" + }, + "frontier-500k": { + "label": "Proyecto 700: pueblos de frontera de 500.000 o más", + "definition": "Prioridad de perdición de IMB 0 y una población de al menos 500.000" + }, + "unengaged": { + "label": "Pueblos no alcanzados y no atendidos", + "definition": "Prioridad de perdición de IMB 0–2 y estado de compromiso: no atendido" + } +} diff --git a/library/i18n/locales/fr/lists.json b/library/i18n/locales/fr/lists.json new file mode 100644 index 000000000..c05ff373f --- /dev/null +++ b/library/i18n/locales/fr/lists.json @@ -0,0 +1,22 @@ +{ + "doxa": { + "label": "Projet 2000 : les peuples de DOXA", + "definition": "Les peuples que DOXA sert, tels que sa liste en direct les donne" + }, + "unreached": { + "label": "Projet 7000 : peuples non atteints", + "definition": "Priorité de perdition IMB 0–2 (non atteints frontières, pionniers ou en expansion : moins de 2 % d’évangéliques)" + }, + "frontier": { + "label": "Projet 4700 : peuples frontières", + "definition": "Priorité de perdition IMB 0 (non atteints frontières : 0,1 % d’évangéliques ou moins)" + }, + "frontier-500k": { + "label": "Projet 700 : peuples frontières de 500 000 personnes ou plus", + "definition": "Priorité de perdition IMB 0 et une population d’au moins 500 000" + }, + "unengaged": { + "label": "Peuples non atteints et non engagés", + "definition": "Priorité de perdition IMB 0–2 et statut d’engagement : non engagé" + } +} diff --git a/library/i18n/locales/hi/lists.json b/library/i18n/locales/hi/lists.json new file mode 100644 index 000000000..80b40b85e --- /dev/null +++ b/library/i18n/locales/hi/lists.json @@ -0,0 +1,22 @@ +{ + "doxa": { + "label": "प्रोजेक्ट 2000: DOXA के जनसमूह", + "definition": "वे जनसमूह जिनकी DOXA सेवा करता है, जैसे उसकी लाइव सूची उन्हें देती है" + }, + "unreached": { + "label": "प्रोजेक्ट 7000: अपहुँचे जनसमूह", + "definition": "IMB लॉस्टनेस प्राथमिकता 0–2 (फ़्रंटियर, पायनियर या एक्सपैंडिंग अपहुँचे: 2% से कम इवेंजेलिकल)" + }, + "frontier": { + "label": "प्रोजेक्ट 4700: फ़्रंटियर जनसमूह", + "definition": "IMB लॉस्टनेस प्राथमिकता 0 (फ़्रंटियर अपहुँचे: 0.1% या उससे कम इवेंजेलिकल)" + }, + "frontier-500k": { + "label": "प्रोजेक्ट 700: 5,00,000 या उससे अधिक के फ़्रंटियर जनसमूह", + "definition": "IMB लॉस्टनेस प्राथमिकता 0 और कम से कम 5,00,000 की जनसंख्या" + }, + "unengaged": { + "label": "अपहुँचे और असंलग्न जनसमूह", + "definition": "IMB लॉस्टनेस प्राथमिकता 0–2 और संलग्नता स्थिति: असंलग्न" + } +} diff --git a/library/i18n/locales/it/lists.json b/library/i18n/locales/it/lists.json new file mode 100644 index 000000000..1863390c8 --- /dev/null +++ b/library/i18n/locales/it/lists.json @@ -0,0 +1,22 @@ +{ + "doxa": { + "label": "Progetto 2000: i popoli di DOXA", + "definition": "I popoli che DOXA serve, come li fornisce la sua lista in tempo reale" + }, + "unreached": { + "label": "Progetto 7000: popoli non raggiunti", + "definition": "Priorità di perdizione IMB 0–2 (non raggiunti di frontiera, pionieri o in espansione: meno del 2% evangelici)" + }, + "frontier": { + "label": "Progetto 4700: popoli di frontiera", + "definition": "Priorità di perdizione IMB 0 (non raggiunti di frontiera: 0,1% evangelici o meno)" + }, + "frontier-500k": { + "label": "Progetto 700: popoli di frontiera di 500.000 o più", + "definition": "Priorità di perdizione IMB 0 e una popolazione di almeno 500.000" + }, + "unengaged": { + "label": "Popoli non raggiunti e non coinvolti", + "definition": "Priorità di perdizione IMB 0–2 e stato di coinvolgimento: non coinvolto" + } +} diff --git a/library/i18n/locales/pt/lists.json b/library/i18n/locales/pt/lists.json new file mode 100644 index 000000000..025be7ed5 --- /dev/null +++ b/library/i18n/locales/pt/lists.json @@ -0,0 +1,22 @@ +{ + "doxa": { + "label": "Projeto 2000: os povos da DOXA", + "definition": "Os povos que a DOXA serve, como a sua lista ao vivo os apresenta" + }, + "unreached": { + "label": "Projeto 7000: povos não alcançados", + "definition": "Prioridade de perdição do IMB 0–2 (não alcançados de fronteira, pioneiros ou em expansão: menos de 2% evangélicos)" + }, + "frontier": { + "label": "Projeto 4700: povos de fronteira", + "definition": "Prioridade de perdição do IMB 0 (não alcançados de fronteira: 0,1% evangélicos ou menos)" + }, + "frontier-500k": { + "label": "Projeto 700: povos de fronteira de 500.000 ou mais", + "definition": "Prioridade de perdição do IMB 0 e uma população de pelo menos 500.000" + }, + "unengaged": { + "label": "Povos não alcançados e não engajados", + "definition": "Prioridade de perdição do IMB 0–2 e estado de engajamento: não engajado" + } +} diff --git a/library/i18n/locales/ro/lists.json b/library/i18n/locales/ro/lists.json new file mode 100644 index 000000000..8cd853025 --- /dev/null +++ b/library/i18n/locales/ro/lists.json @@ -0,0 +1,22 @@ +{ + "doxa": { + "label": "Proiectul 2000: popoarele DOXA", + "definition": "Popoarele pe care DOXA le slujește, așa cum le dă lista sa live" + }, + "unreached": { + "label": "Proiectul 7000: popoare neatinse", + "definition": "Prioritatea de pierzare IMB 0–2 (neatinse de frontieră, pionier sau în expansiune: sub 2% evanghelici)" + }, + "frontier": { + "label": "Proiectul 4700: popoare de frontieră", + "definition": "Prioritatea de pierzare IMB 0 (neatinse de frontieră: 0,1% evanghelici sau mai puțin)" + }, + "frontier-500k": { + "label": "Proiectul 700: popoare de frontieră de 500.000 sau mai mult", + "definition": "Prioritatea de pierzare IMB 0 și o populație de cel puțin 500.000" + }, + "unengaged": { + "label": "Popoare neatinse și neangajate", + "definition": "Prioritatea de pierzare IMB 0–2 și starea de angajare: neangajat" + } +} diff --git a/library/i18n/locales/ru/lists.json b/library/i18n/locales/ru/lists.json new file mode 100644 index 000000000..46d35dc88 --- /dev/null +++ b/library/i18n/locales/ru/lists.json @@ -0,0 +1,22 @@ +{ + "doxa": { + "label": "Проект 2000: народы DOXA", + "definition": "Народы, которым служит DOXA, как их даёт её живой список" + }, + "unreached": { + "label": "Проект 7000: недостигнутые народы", + "definition": "Приоритет потерянности IMB 0–2 (пограничные, первопроходческие или расширяющиеся недостигнутые: менее 2% евангельских христиан)" + }, + "frontier": { + "label": "Проект 4700: пограничные народы", + "definition": "Приоритет потерянности IMB 0 (пограничные недостигнутые: 0,1% евангельских христиан или меньше)" + }, + "frontier-500k": { + "label": "Проект 700: пограничные народы численностью от 500 000", + "definition": "Приоритет потерянности IMB 0 и численность не менее 500 000" + }, + "unengaged": { + "label": "Недостигнутые народы без служения", + "definition": "Приоритет потерянности IMB 0–2 и статус служения: без служения" + } +} diff --git a/library/i18n/locales/zh/lists.json b/library/i18n/locales/zh/lists.json new file mode 100644 index 000000000..2f5226bf1 --- /dev/null +++ b/library/i18n/locales/zh/lists.json @@ -0,0 +1,22 @@ +{ + "doxa": { + "label": "2000 计划:DOXA 服侍的族群", + "definition": "DOXA 服侍的族群,以其实时名单为准" + }, + "unreached": { + "label": "7000 计划:未得之民族群", + "definition": "IMB 失丧优先级 0–2(前沿、先锋或扩展中的未得之民:福音派少于 2%)" + }, + "frontier": { + "label": "4700 计划:前沿族群", + "definition": "IMB 失丧优先级 0(前沿未得之民:福音派 0.1% 或更少)" + }, + "frontier-500k": { + "label": "700 计划:人口 50 万或以上的前沿族群", + "definition": "IMB 失丧优先级 0,且人口至少 50 万" + }, + "unengaged": { + "label": "尚无人参与的未得之民族群", + "definition": "IMB 失丧优先级 0–2,且参与状态为:无人参与" + } +} diff --git a/library/lists/lists.json b/library/lists/lists.json index e641fe56a..34b4e2c55 100644 --- a/library/lists/lists.json +++ b/library/lists/lists.json @@ -1,11 +1,12 @@ { - "_about": "The people-group LISTS a map can be asked to show (profile-config `list`, ?list=, window.MAP_LIST; see peopleGroupList.js). Each list is a FILTER, never a hand-kept roster: `source: doxa` is DOXA's live list as the API serves it; `source: imb` is a filter over the IMB / peoplegroups.org dataset in data/people-groups/people_groups.csv, using its own columns (LostnessPriority, Population, EngagementStatus). library/scripts/people-groups/build-lists.mjs turns each imb filter into data/people-groups/lists/.json. TIER A (today): a map shows the DOXA groups that belong to the list, because the DOXA API is where every map's rows and prayer fields come from. TIER B (later, per map): the list's groups that DOXA does not carry. Definitions and counts: _qa-cycle/03-deployment-cycle/SPEC-PEOPLE-GROUP-LIST-PROP.md.", + "_about": "The people-group LISTS a map can be asked to show (profile-config `list`, ?list=, window.MAP_LIST; see peopleGroupList.js). Each list is a FILTER, never a hand-kept roster: `source: doxa` is DOXA's live list as the API serves it; `source: imb` is a filter over the IMB / peoplegroups.org dataset in data/people-groups/people_groups.csv, using its own columns (LostnessPriority, Population, EngagementStatus). library/scripts/people-groups/build-lists.mjs turns each imb filter into data/people-groups/lists/.json. TIER A (today): a map shows the DOXA groups that belong to the list, because the DOXA API is where every map's rows and prayer fields come from. TIER B (later, per map): the list's groups that DOXA does not carry. Definitions and counts: _qa-cycle/03-deployment-cycle/SPEC-PEOPLE-GROUP-LIST-PROP.md. LABELS HERE ARE THE ENGLISH FALLBACK ONLY: every locale's label and definition live in library/i18n/locales//lists.json (read them with listLabel / listDefinition), and check:list-prop-unit fails if the English catalogue and this file disagree.", "default": "doxa", "lists": [ { "id": "doxa", "aliases": ["2000", "project-2000"], "label": "Project 2000: DOXA's people groups", + "definition": "The people groups DOXA serves, as its live list gives them", "source": "doxa", "filter": null }, diff --git a/library/lists/peopleGroupList.js b/library/lists/peopleGroupList.js index 80c114451..2f60b093f 100644 --- a/library/lists/peopleGroupList.js +++ b/library/lists/peopleGroupList.js @@ -42,6 +42,24 @@ export function listInfo(idOrAlias) { return byKey.get(String(idOrAlias ?? '').toLowerCase().trim()) || null } +// A list's name and definition in the READER'S language. They live in the i18n catalogues +// (library/i18n/locales//lists.json, area `lists`), not here, so every surface that shows a list +// speaks the page's locale. `t` is the caller's translator (useI18n's t, tStatic, or any (key) => +// string); this module takes it as an argument instead of importing the i18n runtime, so it stays +// pure. With no translator, or a key the catalogue lacks, the registry's English answers. +function listText(idOrAlias, field, t) { + const l = listInfo(idOrAlias) + if (!l) return '' + const key = `lists.${l.id}.${field}` + let v = '' + if (typeof t === 'function') { try { v = t(key) } catch { v = '' } } + return v && v !== key ? v : (l[field] || '') +} +/** The list's label ("Project 700: …") in the reader's language, English as the fallback. */ +export function listLabel(idOrAlias, t) { return listText(idOrAlias, 'label', t) } +/** The list's one-line definition in the reader's language, English as the fallback. */ +export function listDefinition(idOrAlias, t) { return listText(idOrAlias, 'definition', t) } + /** Unwrap a ref/computed to its config object; parse a JSON string; pass plain objects through. */ function unwrapConfig(profileConfig) { let cfg = profileConfig