Research Gallery: a "Back to homepage" link above Collapse, and the poster rows in Prayer Mobilization

The tab layout takes an optional homeHref and homeLabel from its host. When a URL is given it draws a
link directly above the rail's Collapse button, in the same box, and a phone shows it at the top of the
drawer. It mirrors in Arabic and slims with the rail. With no URL nothing changes, so the Plugin Studio
and every other host look exactly as before. A javascript:, data: or vbscript: URL is ignored.

The gallery accepts home-href and home-label (or profile-config homeHref and homeLabel) and passes them
on; its own "Back to homepage" is the fallback label in all 11 languages.

Prayer Mobilization now reads Prayer Progress, UPG 100 List Posters (renamed in all 11 languages), then
Country Posters, which mounts its composite view and leaves the Experimental shelf. Posterverse, the
second shell, is kept off this shelf so a shell never opens inside a shell.
This commit is contained in:
Doxa Maps 2026-09-30 20:16:15 +00:00
parent eca1ecb4af
commit f18aff662b
6 changed files with 127 additions and 66 deletions

View file

@ -144,6 +144,16 @@
to desktop (the old cross-breakpoint bug). `aria-hidden` mirrors real visibility for a11y. -->
<nav class="vtl-nav" :aria-label="navLabel" :aria-hidden="String(!railShown)"
:role="$slots.rail ? null : 'tablist'" :aria-orientation="$slots.rail ? null : 'vertical'">
<!-- THE HOST'S WAY HOME (optional). A host page that embeds this layout full-page (DX Life's
/deep-research) has no header of its own there, so it hands in its homepage URL and label
(homeHref / homeLabel) and the link sits here: directly above Collapse, the same box, in the
rail on a desktop and at the top of the drawer on a phone. The URL is the HOST's, never a
default, so an embed that passes none shows nothing and the layout stays embeddable anywhere. -->
<a v-if="homeLink" class="vtl-home" :href="homeLink" target="_top" :aria-label="homeText"
:title="railCollapsed && !narrow ? homeText : null">
<span class="vtl-home-ic" aria-hidden="true" v-html="iconSvg('home')"></span>
<span class="vtl-home-tx">{{ homeText }}</span>
</a>
<!-- Rail toggle: always visible, collapses the rail (slim icon rail on desktop; off-canvas
drawer on mobile). The chevron points the way the click will move the rail. -->
<button
@ -359,12 +369,18 @@ const VTL_SHADOW_CSS = `
.vtl-nav::-webkit-scrollbar-track { background:transparent; }
.vtl-nav::-webkit-scrollbar-thumb { background:#c4c8c0; border-radius:8px; }
.vtl-nav::-webkit-scrollbar-thumb:hover { background:#9aa197; }
.vtl-collapse { display:flex; align-items:center; gap:8px; width:100%; box-sizing:border-box; margin:0 0 8px; padding:7px 10px; border:1px solid var(--vtl-border); border-radius:8px; background:#d1d4cd; color:var(--vtl-muted); font:inherit; font-size:12px; cursor:pointer; }
.vtl-collapse:hover { background:var(--vtl-accented); color:#3b463d; }
.vtl-collapse:focus-visible { outline:2px solid var(--vtl-accent); outline-offset:-2px; }
.vtl-collapse, .vtl-home { display:flex; align-items:center; gap:8px; width:100%; box-sizing:border-box; margin:0 0 8px; padding:7px 10px; border:1px solid var(--vtl-border); border-radius:8px; background:#d1d4cd; color:var(--vtl-muted); font:inherit; font-size:12px; cursor:pointer; }
.vtl-collapse:hover, .vtl-home:hover { background:var(--vtl-accented); color:#3b463d; }
.vtl-collapse:focus-visible, .vtl-home:focus-visible { outline:2px solid var(--vtl-accent); outline-offset:-2px; }
.vtl-collapse-ic { flex:0 0 auto; display:inline-flex; transition:transform .16s ease; transform:rotate(180deg); }
.vtl-collapse-ic svg { width:16px; height:16px; }
.vtl-collapse-tx { white-space:nowrap; }
/* The host’s home link (homeHref) shares Collapse’s box through the selector lists above and below, so the
two are the same size by construction and cannot drift apart. The house does not rotate or mirror. */
.vtl-home { text-decoration:none; }
.vtl-home-ic { flex:0 0 auto; display:inline-flex; }
.vtl-home-ic svg { width:16px; height:16px; }
.vtl-home-tx { white-space:nowrap; overflow:hidden; text-overflow:ellipsis; }
.vtl-grp { margin-bottom:2px; }
.vtl-grp + .vtl-grp { margin-top:8px; padding-top:8px; border-top:1px solid var(--vtl-border); }
.vtl-tier { width:100%; padding:8px 8px 6px; display:flex; align-items:center; gap:8px; box-sizing:border-box; }
@ -496,9 +512,9 @@ const VTL_SHADOW_CSS = `
THIS BLOCK EXISTS TWICE (VTL_SHADOW_CSS and the scoped style block); keep them byte-identical. */
.vtl.rail-collapsed .vtl-nav { transform:translateX(-184px); }
.vtl.rail-collapsed .vtl-main { left:72px; }
.vtl.rail-collapsed .vtl-collapse { padding-left:184px; justify-content:flex-start; }
.vtl.rail-collapsed .vtl-collapse, .vtl.rail-collapsed .vtl-home { padding-left:184px; justify-content:flex-start; }
.vtl.rail-collapsed .vtl-collapse-ic { transform:rotate(0deg); }
.vtl.rail-collapsed .vtl-collapse-tx { display:none; }
.vtl.rail-collapsed .vtl-collapse-tx, .vtl.rail-collapsed .vtl-home-tx { display:none; }
.vtl.rail-collapsed .vtl-tab { padding-left:188px; gap:0; }
.vtl.rail-collapsed .vtl-tab-text { display:none; }
.vtl.rail-collapsed .vtl-tab-emoji { font-size:19px; }
@ -533,9 +549,9 @@ const VTL_SHADOW_CSS = `
.vtl.rail-collapsed .vtl-nav { transform:translateX(-100%); }
.vtl.rail-collapsed.nav-open .vtl-nav { transform:translateX(0); }
.vtl.rail-collapsed .vtl-main { left:0; }
.vtl.rail-collapsed .vtl-collapse { padding-left:10px; justify-content:flex-start; }
.vtl.rail-collapsed .vtl-collapse, .vtl.rail-collapsed .vtl-home { padding-left:10px; justify-content:flex-start; }
.vtl.rail-collapsed .vtl-collapse-ic { transform:rotate(180deg); }
.vtl.rail-collapsed .vtl-collapse-tx { display:inline; }
.vtl.rail-collapsed .vtl-collapse-tx, .vtl.rail-collapsed .vtl-home-tx { display:inline; }
.vtl.rail-collapsed .vtl-tab { padding-left:10px; gap:11px; }
.vtl.rail-collapsed .vtl-tab-text { display:flex; }
.vtl.rail-collapsed .vtl-tab-fallback { display:none; }
@ -559,7 +575,7 @@ const VTL_SHADOW_CSS = `
.vtl:dir(rtl) .vtl-fab { left:auto; right:calc(8px + env(safe-area-inset-right)); }
.vtl.rail-collapsed:dir(rtl) .vtl-nav { transform:translateX(184px); }
.vtl.rail-collapsed:dir(rtl) .vtl-main { left:0; right:72px; }
.vtl.rail-collapsed:dir(rtl) .vtl-collapse { padding-left:10px; padding-right:184px; }
.vtl.rail-collapsed:dir(rtl) .vtl-collapse, .vtl.rail-collapsed:dir(rtl) .vtl-home { padding-left:10px; padding-right:184px; }
.vtl.rail-collapsed:dir(rtl) .vtl-tab { padding-left:12px; padding-right:188px; }
.vtl.rail-collapsed:dir(rtl) .vtl-tier { padding-left:8px; padding-right:196px; }
@media (max-width: 760px) {
@ -568,7 +584,7 @@ const VTL_SHADOW_CSS = `
.vtl:dir(rtl) .vtl-main, .vtl.rail-collapsed:dir(rtl) .vtl-main { left:0; right:0; }
.vtl.rail-collapsed:dir(rtl) .vtl-nav { transform:translateX(100%); }
.vtl.rail-collapsed.nav-open:dir(rtl) .vtl-nav { transform:translateX(0); }
.vtl.rail-collapsed:dir(rtl) .vtl-collapse { padding-left:10px; padding-right:10px; }
.vtl.rail-collapsed:dir(rtl) .vtl-collapse, .vtl.rail-collapsed:dir(rtl) .vtl-home { padding-left:10px; padding-right:10px; }
.vtl.rail-collapsed:dir(rtl) .vtl-tab { padding-left:12px; padding-right:10px; }
.vtl.rail-collapsed:dir(rtl) .vtl-tier { padding-left:8px; padding-right:8px; }
}
@ -593,7 +609,7 @@ export default defineComponent({
groups: { type: Array, default: () => [] },
navLabel: { type: String, default: 'Sections' },
// The shell's own words, for a localised host: { toggleList, openViews, expandList, collapseList,
// collapse }. Any key left out keeps its English default, so existing hosts are unchanged.
// collapse, home }. Any key left out keeps its English default, so existing hosts are unchanged.
labels: { type: Object, default: () => ({}) },
// Start with the rail open (desktop). Auto-collapses on narrow screens after mount.
initialNavOpen: { type: Boolean, default: true },
@ -601,7 +617,11 @@ export default defineComponent({
// (embedded where a host header already exists — stacked headers look bad). #toolbar is unaffected.
header: { type: Boolean, default: true },
// Start the desktop rail collapsed (slim icon rail). Off by default so the rail opens expanded.
initialRailCollapsed: { type: Boolean, default: false }
initialRailCollapsed: { type: Boolean, default: false },
// The HOST's homepage, shown as a link above Collapse (see the template). Empty = no link, which is
// every existing consumer. homeLabel is the host's own words; unset, labels.home, then English.
homeHref: { type: String, default: '' },
homeLabel: { type: String, default: '' }
},
emits: ['update:active'],
setup() {
@ -656,6 +676,13 @@ export default defineComponent({
// only when the off-canvas drawer is open (navOpen). Binding the rail's v-show to THIS (not raw
// navOpen) prevents a mobile-closed drawer from hiding the rail after a resize back to desktop.
railShown() { return this.narrow ? this.navOpen : true },
// The home link's URL, or '' for none. A script URL is refused: the value can arrive through an
// attribute or a JSON config, and a link that runs code is never a way home.
homeLink() {
const h = String(this.homeHref || '').trim()
return (!h || /^(javascript|data|vbscript):/i.test(h.replace(/[\u0000- ]/g, ''))) ? '' : h
},
homeText() { return this.homeLabel || this.label('home') },
// Every row/item flattened across whichever shape is in use (groups take precedence over items).
allRows() {
if (this.groups && this.groups.length) {
@ -730,7 +757,7 @@ export default defineComponent({
}
},
label(key) {
const EN = { toggleList: 'Toggle list', openViews: 'Open the list of views', expandList: 'Expand list', collapseList: 'Collapse list', collapse: 'Collapse' }
const EN = { toggleList: 'Toggle list', openViews: 'Open the list of views', expandList: 'Expand list', collapseList: 'Collapse list', collapse: 'Collapse', home: 'Back to homepage' }
return (this.labels && this.labels[key]) || EN[key]
},
// Open the desktop rail if it is in its slim state (a #rail host calls this when its slim-strip
@ -937,12 +964,18 @@ export default defineComponent({
.vtl-nav::-webkit-scrollbar-track { background:transparent; }
.vtl-nav::-webkit-scrollbar-thumb { background:#c4c8c0; border-radius:8px; }
.vtl-nav::-webkit-scrollbar-thumb:hover { background:#9aa197; }
.vtl-collapse { display:flex; align-items:center; gap:8px; width:100%; box-sizing:border-box; margin:0 0 8px; padding:7px 10px; border:1px solid var(--vtl-border); border-radius:8px; background:#d1d4cd; color:var(--vtl-muted); font:inherit; font-size:12px; cursor:pointer; }
.vtl-collapse:hover { background:var(--vtl-accented); color:#3b463d; }
.vtl-collapse:focus-visible { outline:2px solid var(--vtl-accent); outline-offset:-2px; }
.vtl-collapse, .vtl-home { display:flex; align-items:center; gap:8px; width:100%; box-sizing:border-box; margin:0 0 8px; padding:7px 10px; border:1px solid var(--vtl-border); border-radius:8px; background:#d1d4cd; color:var(--vtl-muted); font:inherit; font-size:12px; cursor:pointer; }
.vtl-collapse:hover, .vtl-home:hover { background:var(--vtl-accented); color:#3b463d; }
.vtl-collapse:focus-visible, .vtl-home:focus-visible { outline:2px solid var(--vtl-accent); outline-offset:-2px; }
.vtl-collapse-ic { flex:0 0 auto; display:inline-flex; transition:transform .16s ease; transform:rotate(180deg); }
.vtl-collapse-ic svg { width:16px; height:16px; }
.vtl-collapse-tx { white-space:nowrap; }
/* The host’s home link (homeHref) shares Collapse’s box through the selector lists above and below, so the
two are the same size by construction and cannot drift apart. The house does not rotate or mirror. */
.vtl-home { text-decoration:none; }
.vtl-home-ic { flex:0 0 auto; display:inline-flex; }
.vtl-home-ic svg { width:16px; height:16px; }
.vtl-home-tx { white-space:nowrap; overflow:hidden; text-overflow:ellipsis; }
.vtl-grp { margin-bottom:2px; }
.vtl-grp + .vtl-grp { margin-top:8px; padding-top:8px; border-top:1px solid var(--vtl-border); }
.vtl-tier { width:100%; padding:8px 8px 6px; display:flex; align-items:center; gap:8px; box-sizing:border-box; }
@ -1074,9 +1107,9 @@ export default defineComponent({
THIS BLOCK EXISTS TWICE (VTL_SHADOW_CSS and the scoped style block); keep them byte-identical. */
.vtl.rail-collapsed .vtl-nav { transform:translateX(-184px); }
.vtl.rail-collapsed .vtl-main { left:72px; }
.vtl.rail-collapsed .vtl-collapse { padding-left:184px; justify-content:flex-start; }
.vtl.rail-collapsed .vtl-collapse, .vtl.rail-collapsed .vtl-home { padding-left:184px; justify-content:flex-start; }
.vtl.rail-collapsed .vtl-collapse-ic { transform:rotate(0deg); }
.vtl.rail-collapsed .vtl-collapse-tx { display:none; }
.vtl.rail-collapsed .vtl-collapse-tx, .vtl.rail-collapsed .vtl-home-tx { display:none; }
.vtl.rail-collapsed .vtl-tab { padding-left:188px; gap:0; }
.vtl.rail-collapsed .vtl-tab-text { display:none; }
.vtl.rail-collapsed .vtl-tab-emoji { font-size:19px; }
@ -1111,9 +1144,9 @@ export default defineComponent({
.vtl.rail-collapsed .vtl-nav { transform:translateX(-100%); }
.vtl.rail-collapsed.nav-open .vtl-nav { transform:translateX(0); }
.vtl.rail-collapsed .vtl-main { left:0; }
.vtl.rail-collapsed .vtl-collapse { padding-left:10px; justify-content:flex-start; }
.vtl.rail-collapsed .vtl-collapse, .vtl.rail-collapsed .vtl-home { padding-left:10px; justify-content:flex-start; }
.vtl.rail-collapsed .vtl-collapse-ic { transform:rotate(180deg); }
.vtl.rail-collapsed .vtl-collapse-tx { display:inline; }
.vtl.rail-collapsed .vtl-collapse-tx, .vtl.rail-collapsed .vtl-home-tx { display:inline; }
.vtl.rail-collapsed .vtl-tab { padding-left:10px; gap:11px; }
.vtl.rail-collapsed .vtl-tab-text { display:flex; }
.vtl.rail-collapsed .vtl-tab-fallback { display:none; }
@ -1137,7 +1170,7 @@ export default defineComponent({
.vtl:dir(rtl) .vtl-fab { left:auto; right:calc(8px + env(safe-area-inset-right)); }
.vtl.rail-collapsed:dir(rtl) .vtl-nav { transform:translateX(184px); }
.vtl.rail-collapsed:dir(rtl) .vtl-main { left:0; right:72px; }
.vtl.rail-collapsed:dir(rtl) .vtl-collapse { padding-left:10px; padding-right:184px; }
.vtl.rail-collapsed:dir(rtl) .vtl-collapse, .vtl.rail-collapsed:dir(rtl) .vtl-home { padding-left:10px; padding-right:184px; }
.vtl.rail-collapsed:dir(rtl) .vtl-tab { padding-left:12px; padding-right:188px; }
.vtl.rail-collapsed:dir(rtl) .vtl-tier { padding-left:8px; padding-right:196px; }
@media (max-width: 760px) {
@ -1146,7 +1179,7 @@ export default defineComponent({
.vtl:dir(rtl) .vtl-main, .vtl.rail-collapsed:dir(rtl) .vtl-main { left:0; right:0; }
.vtl.rail-collapsed:dir(rtl) .vtl-nav { transform:translateX(100%); }
.vtl.rail-collapsed.nav-open:dir(rtl) .vtl-nav { transform:translateX(0); }
.vtl.rail-collapsed:dir(rtl) .vtl-collapse { padding-left:10px; padding-right:10px; }
.vtl.rail-collapsed:dir(rtl) .vtl-collapse, .vtl.rail-collapsed:dir(rtl) .vtl-home { padding-left:10px; padding-right:10px; }
.vtl.rail-collapsed:dir(rtl) .vtl-tab { padding-left:12px; padding-right:10px; }
.vtl.rail-collapsed:dir(rtl) .vtl-tier { padding-left:8px; padding-right:8px; }
}

View file

@ -52,6 +52,8 @@ const P = {
search: '<circle cx="10.5" cy="10.5" r="7.5"/><line x1="15.8" y1="15.8" x2="20.5" y2="20.5"/>',
// `book` = Gospel Access (an open book / the Word reaching a place).
book: '<path d="M12 6.5C12 6.5 9.5 4.5 4 4.5v13C9.5 17.5 12 19.5 12 19.5"/><path d="M12 6.5C12 6.5 14.5 4.5 20 4.5v13C14.5 17.5 12 19.5 12 19.5"/>',
// `home` = the host site's homepage (VerticalTabsLayout's optional "Back to homepage" link): a house.
home: '<path d="M3 11 12 3l9 8"/><path d="M5 9.5V20a1 1 0 0 0 1 1h4v-6h4v6h4a1 1 0 0 0 1-1V9.5"/>',
// `wifi` = Cities with Internet (connectivity arcs + node). Local, no CDN.
wifi: '<path d="M3.5 9a13 13 0 0 1 17 0"/><path d="M6.8 12.4a8.5 8.5 0 0 1 10.4 0"/><path d="M10 15.7a4 4 0 0 1 4 0"/><circle cx="12" cy="19" r="1"/>',
}

View file

@ -61,9 +61,11 @@ Add `?tab=<id>` to the `src` to open a specific map.
| `token-url` | none | Token endpoint forwarded to each map. |
| `tree-base` | derived from the script URL | Pin the tree root explicitly (needed only when the script is re-hosted apart from its tree). |
| `heading` | `DX-Maps` | Shell title (shown only when the shell header is enabled). |
| `home-href` | none | Your homepage. Shows a "Back to homepage" link directly above the rail’s Collapse button (at the top of the drawer on a phone). Without it there is no link. `javascript:` and `data:` URLs are ignored. |
| `home-label` | "Back to homepage" in the gallery’s language | The link’s text, in your own words. |
Tab ids: `dashboard-plus-grid` (Big Picture), `research-map-plus-grid` (Simple Research),
`regions-dashboard`, `upg-100`, `prayer-map` (Prayer Progress), `cities-internet`,
`regions-dashboard`, `upg-100` (UPG 100 List Posters), `prayer-map` (Prayer Progress), `country-posters`, `cities-internet`,
`gospel-resources`, and every Experimental bundle by its bundle name.
## Events

View file

@ -1,14 +1,15 @@
{
"_comment": "Declares the composability tier. 'nested-mfe-spa' (display alias 'app-shell') = Capability-5: this plugin is the OUTER app shell of the dx-maps app, the Research Gallery. Its single element <doxa-maps-spa> renders a vertical-tab rail whose tabs each mount a REAL, independently embeddable plugin: the shell loads that bundle's script (URL from manifest.json) and creates its registered custom element in the pane. There is no iframe mode. Tab order and grouping live in NAV_MODEL/TAB_DEFS in doxa-maps-spa.vue; `composes` below lists the seven curated tabs as bundle/profile and must be kept in step with TAB_DEFS (check:composite reads it; the studio's \"Inside doxa-maps-spa\" tree shows it). Bundles not placed in a section appear under Experimental automatically. The tier is now DERIVED from the `composes` edges below at tree generation (a profile that composes anything is cap-4; one that composes a cap-4 is cap-5), and this explicit `type` is CHECKED against that derivation rather than being the only source: if the two disagree the build fails, because one of them is stale. discover.mjs still never infers tiers 3-5 on its own.",
"_comment": "Declares the composability tier. 'nested-mfe-spa' (display alias 'app-shell') = Capability-5: this plugin is the OUTER app shell of the dx-maps app, the Research Gallery. Its single element <doxa-maps-spa> renders a vertical-tab rail whose tabs each mount a REAL, independently embeddable plugin: the shell loads that bundle's script (URL from manifest.json) and creates its registered custom element in the pane. There is no iframe mode. Tab order and grouping live in NAV_MODEL/TAB_DEFS in doxa-maps-spa.vue; `composes` below lists the eight curated tabs as bundle/profile and must be kept in step with TAB_DEFS (check:composite reads it; the studio's \"Inside doxa-maps-spa\" tree shows it). Bundles not placed in a section appear under Experimental automatically. The tier is now DERIVED from the `composes` edges below at tree generation (a profile that composes anything is cap-4; one that composes a cap-4 is cap-5), and this explicit `type` is CHECKED against that derivation rather than being the only source: if the two disagree the build fails, because one of them is stale. discover.mjs still never infers tiers 3-5 on its own.",
"type": "nested-mfe-spa",
"composes": [
"dashboard-plus-grid/dashboard-plus-grid",
"research-map-plus-grid/research-map-plus-grid",
"regions-dashboard/regions-mfe",
"my-upg-100-list/upg-100-mfe",
"country-posters/country-posters-mfe",
"doxa-simple-map/doxa-simple-map",
"cities-internet/connectivity-map",
"gospel-resources/resources-map"
],
"label": "Deep Research (vertical-tab app shell: the seven production maps)"
"label": "Deep Research (vertical-tab app shell: the eight production maps)"
}

View file

@ -60,6 +60,8 @@
:dir="uiDir"
:lang="uiLocale"
:labels="layoutLabels"
:home-href="homeHref || cfg.homeHref || ''"
:home-label="homeLabel || cfg.homeLabel || ''"
:title="headingText"
:nav-label="t('navLabel')"
:header="showHeader"
@ -276,11 +278,17 @@ const NAV_MODEL = [
// per the spec's table. UPG-100 BEFORE Prayer Progress is a deliberate product order: to someone
// being mobilized to pray, the UPG-100 list is the NEW thing, so they meet it first — hand the
// newcomer the concrete new artifact, THEN ask them to pray it.
//
// THE POSTER ROWS (2026-09-30): the section now runs Prayer Progress, UPG 100 List Posters, Country Posters,
// then Poster Design. The same poster plugins also live in the Posterverse shell; each is ONE bundle, mounted
// by whichever shell opens it. Poster Design joins this list when its bundle exists: a row whose bundle is
// not in the manifest is dropped without a word (resolveTabsFromManifest), so listing it early shows nothing.
{ key: 'prayer-mobilization', label: 'Prayer Mobilization', i18n: 'sec.prayer', icon: 'heart',
tabs: [
// Prayer Progress, then the UPG-100 List: the published order of this section, fixed.
{ id: 'prayer-map', icon: 'embed' },
{ id: 'upg-100', icon: 'list' },
// Prayer Progress, then UPG 100 List Posters, then Country Posters: the published order, fixed.
{ id: 'prayer-map', icon: 'embed' },
{ id: 'upg-100', icon: 'list' },
{ id: 'country-posters', icon: 'poster' },
] },
// Gospel Research — RENAMED section (was "Research"). Cities with Internet then Gospel Resources,
// per the spec's table (rows 5-6). The plain, uncomposited "Research Map" tab (doxa-research-map)
@ -352,7 +360,11 @@ const NOT_EXPERIMENTAL = new Set([
'doxa-research-map',
// stack-demo is broken and DEFERRED; a broken tab in the giveaway shelf reads as
// product damage. It returns when someone fixes it (a tracked issue).
'stack-demo'
'stack-demo',
// posterverse is the OTHER capability-5 shell (the poster plugins). Shown here it would be a
// whole second rail inside this pane: a shell does not nest a shell, for the same reason this
// shell excludes itself above.
'posterverse'
])
// ── EXPERIMENTAL ORDER = KINGDOM IMPACT, not the alphabet ────────────────────────────────
@ -371,8 +383,7 @@ const EXPERIMENTAL_RANK = {
'upg-neighbor': 3, // near reached neighbors, both directions ("who goes, to whom")
'key-cities': 4, // where the unreached physically live
'all-people-groups': 5, // the census view that feeds everything else
'country-posters': 6, // mobilization print artifacts
'doxa-vision-card': 7, // vision framing
'doxa-vision-card': 7, // vision framing (6 was country-posters, now a Prayer Mobilization row)
}
// The tab manifest. Each entry CURATES one tab: which bundle+profile it shows, in what order, under
@ -476,9 +487,16 @@ const TAB_DEFS = [
bundle: 'regions-dashboard', profile: 'regions-mfe'
},
{
id: 'upg-100', label: 'UPG-100 List', sub: 'my unreached list + posters', emoji: '📋',
id: 'upg-100', label: 'UPG 100 List Posters', sub: 'my unreached list + posters', emoji: '📋',
bundle: 'my-upg-100-list', profile: 'upg-100-mfe'
},
{
// The capability-4 composite, as with Regions and UPG-100 above: country-posters also ships the
// single views countries-map and country-poster-wall, and naming one of those would mount a
// part without the view strip that joins them.
id: 'country-posters', label: 'Country Posters', sub: 'a poster for every country', emoji: '🗺️',
bundle: 'country-posters', profile: 'country-posters-mfe'
},
// ── NOTE: there are deliberately NO hardcoded Experimental entries here. Every built bundle not
// named above is discovered from manifest.json at runtime and appended as an Experimental tab
// (see discoverExperimental + NOT_EXPERIMENTAL). That is what keeps a NEW plugin visible with
@ -794,7 +812,12 @@ export default defineComponent({
provider: { type: String, default: '' },
// Which tab opens first, by tab id (e.g. "upg-100", "gospel-resources"). Lets a host page deep-
// link into one map of the gallery. Falls back to ?tab= on the page URL, then the device default.
tab: { type: String, default: '' }
tab: { type: String, default: '' },
// The HOST's homepage: a "Back to homepage" link directly above the rail's Collapse button (a phone
// shows it at the top of the drawer). Also accepted as profile-config.homeHref / homeLabel. No URL,
// no link: the gallery never invents one, because it cannot know whose page it is on.
homeHref: { type: String, default: '' },
homeLabel: { type: String, default: '' }
},
emits: ['tab-change'],
setup() {
@ -1021,7 +1044,7 @@ export default defineComponent({
// defaults inside VerticalTabsLayout, translated here through its `labels` contract.
layoutLabels() {
const out = {}
for (const k of ['toggleList', 'openViews', 'expandList', 'collapseList', 'collapse']) out[k] = this.tr(k)
for (const k of ['toggleList', 'openViews', 'expandList', 'collapseList', 'collapse', 'home']) out[k] = this.tr(k)
return out
},
// The engine a HOST asked for ('' = none; each map keeps its own ladder).

View file

@ -25,16 +25,16 @@ export const STRINGS = {
'tab.cities-internet': 'Cities with Internet', 'sub.cities-internet': 'connectivity of key cities',
'tab.gospel-resources': 'Gospel Resources', 'sub.gospel-resources': 'resources by place',
'tab.regions-dashboard': 'Regions', 'sub.regions-dashboard': 'regions and their countries',
'tab.upg-100': 'UPG-100 List', 'sub.upg-100': 'my unreached list + posters',
'tab.upg-100': "UPG 100 List Posters", 'sub.upg-100': 'my unreached list + posters',
navLabel: 'Research maps', meta: '{n} maps', loading: 'Loading {label}…', loadFailed: 'Could not load {label}.',
manifestHint: 'This tab is composed from manifest.json — build the tree, or serve the built tree, to load it.',
close: 'Close', help: 'About this map', desktopOnly: 'desktop only', lab: 'lab', experimentalSub: 'experimental bundle',
mobileNotBuilt: 'not built for mobile', dismiss: 'Dismiss', desktopOnly: 'desktop only', lab: 'lab', experimentalSub: 'experimental bundle',
// The shared VerticalTabsLayout's own controls, VERBATIM from library/i18n/locales/en/studio.json
// (plugin studio's catalog) so both shells name the same buttons the same way.
toggleList: "Toggle list", openViews: "Open the list of views", expandList: "Expand list", collapseList: "Collapse list", collapse: "Collapse",
toggleList: "Toggle list", openViews: "Open the list of views", expandList: "Expand list", collapseList: "Collapse list", collapse: "Collapse", home: "Back to homepage",
// Experimental bundles known today (rail-length names; a bundle not listed keeps its manifest title).
'tab.prayer-walk-planner': "Prayer Walk Planner", 'tab.upg-neighbor': "UPG Neighbor", 'tab.key-cities': "Key Cities", 'tab.all-people-groups': "All People Groups", 'tab.pplr-data-maps': "PPLR Data Maps", 'tab.wall-of-people-groups': "Wall of People Groups", 'tab.country-posters': "Country Posters", 'tab.doxa-vision-card': "Doxa Vision Card",
'tab.prayer-walk-planner': "Prayer Walk Planner", 'tab.upg-neighbor': "UPG Neighbor", 'tab.key-cities': "Key Cities", 'tab.all-people-groups': "All People Groups", 'tab.pplr-data-maps': "PPLR Data Maps", 'tab.wall-of-people-groups': "Wall of People Groups", 'tab.country-posters': "Country Posters", 'sub.country-posters': "a poster for every country", 'tab.doxa-vision-card': "Doxa Vision Card",
},
es: {
backToTop: 'Volver arriba',
@ -46,16 +46,16 @@ export const STRINGS = {
'tab.cities-internet': 'Ciudades con Internet', 'sub.cities-internet': 'conectividad de ciudades clave',
'tab.gospel-resources': 'Recursos del Evangelio', 'sub.gospel-resources': 'recursos por lugar',
'tab.regions-dashboard': 'Regiones', 'sub.regions-dashboard': 'regiones y sus países',
'tab.upg-100': 'Lista UPG-100', 'sub.upg-100': 'mi lista de no alcanzados + carteles',
'tab.upg-100': "Carteles de la lista UPG 100", 'sub.upg-100': 'mi lista de no alcanzados + carteles',
navLabel: 'Mapas de investigación', meta: '{n} mapas', 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.',
close: 'Cerrar', help: 'Acerca de este mapa', desktopOnly: 'solo escritorio', lab: 'beta', experimentalSub: 'mapa experimental',
mobileNotBuilt: 'no diseñado para móvil', dismiss: 'Cerrar', desktopOnly: 'solo escritorio', lab: 'beta', experimentalSub: 'mapa experimental',
// The shared VerticalTabsLayout's own controls, VERBATIM from library/i18n/locales/es/studio.json
// (plugin studio's catalog) so both shells name the same buttons the same way.
toggleList: "Mostrar u ocultar la lista", openViews: "Abrir la lista de vistas", expandList: "Expandir la lista", collapseList: "Contraer la lista", collapse: "Contraer",
toggleList: "Mostrar u ocultar la lista", openViews: "Abrir la lista de vistas", expandList: "Expandir la lista", collapseList: "Contraer la lista", collapse: "Contraer", home: "Volver a la página de inicio",
// Experimental bundles known today (rail-length names; a bundle not listed keeps its manifest title).
'tab.prayer-walk-planner': "Caminatas de oración", 'tab.upg-neighbor': "Vecino UPG", 'tab.key-cities': "Ciudades clave", 'tab.all-people-groups': "Todos los pueblos", 'tab.pplr-data-maps': "Mapas de datos PPLR", 'tab.wall-of-people-groups': "Muro de los pueblos", 'tab.country-posters': "Carteles por país", 'tab.doxa-vision-card': "Tarjeta de visión Doxa",
'tab.prayer-walk-planner': "Caminatas de oración", 'tab.upg-neighbor': "Vecino UPG", 'tab.key-cities': "Ciudades clave", 'tab.all-people-groups': "Todos los pueblos", 'tab.pplr-data-maps': "Mapas de datos PPLR", 'tab.wall-of-people-groups': "Muro de los pueblos", 'tab.country-posters': "Carteles por país", 'sub.country-posters': "un cartel para cada país", 'tab.doxa-vision-card': "Tarjeta de visión Doxa",
},
fr: {
backToTop: 'Retour en haut',
@ -67,16 +67,16 @@ export const STRINGS = {
'tab.cities-internet': 'Villes avec Internet', 'sub.cities-internet': 'connectivité des villes clés',
'tab.gospel-resources': "Ressources de l'Évangile", 'sub.gospel-resources': 'ressources par lieu',
'tab.regions-dashboard': 'Régions', 'sub.regions-dashboard': 'régions et leurs pays',
'tab.upg-100': 'Liste UPG-100', 'sub.upg-100': 'ma liste des non atteints + affiches',
'tab.upg-100': "Affiches de la liste UPG 100", 'sub.upg-100': 'ma liste des non atteints + affiches',
navLabel: 'Cartes de recherche', meta: '{n} cartes', 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.",
close: 'Fermer', help: 'À propos de cette carte', desktopOnly: 'ordinateur uniquement', lab: 'bêta', experimentalSub: 'carte expérimentale',
mobileNotBuilt: 'pas conçu pour mobile', dismiss: 'Fermer', desktopOnly: 'ordinateur uniquement', lab: 'bêta', experimentalSub: 'carte expérimentale',
// The shared VerticalTabsLayout's own controls, VERBATIM from library/i18n/locales/fr/studio.json
// (plugin studio's catalog) so both shells name the same buttons the same way.
toggleList: "Afficher ou masquer la liste", openViews: "Ouvrir la liste des vues", expandList: "Déplier la liste", collapseList: "Replier la liste", collapse: "Replier",
toggleList: "Afficher ou masquer la liste", openViews: "Ouvrir la liste des vues", expandList: "Déplier la liste", collapseList: "Replier la liste", collapse: "Replier", home: "Retour à l’accueil",
// Experimental bundles known today (rail-length names; a bundle not listed keeps its manifest title).
'tab.prayer-walk-planner': "Marches de prière", 'tab.upg-neighbor': "Voisin UPG", 'tab.key-cities': "Villes clés", 'tab.all-people-groups': "Tous les peuples", 'tab.pplr-data-maps': "Cartes de données PPLR", 'tab.wall-of-people-groups': "Mur des peuples", 'tab.country-posters': "Affiches par pays", 'tab.doxa-vision-card': "Carte de vision Doxa",
'tab.prayer-walk-planner': "Marches de prière", 'tab.upg-neighbor': "Voisin UPG", 'tab.key-cities': "Villes clés", 'tab.all-people-groups': "Tous les peuples", 'tab.pplr-data-maps': "Cartes de données PPLR", 'tab.wall-of-people-groups': "Mur des peuples", 'tab.country-posters': "Affiches par pays", 'sub.country-posters': "une affiche pour chaque pays", 'tab.doxa-vision-card': "Carte de vision Doxa",
},
de: {
backToTop: 'Nach oben',
@ -88,16 +88,16 @@ export const STRINGS = {
'tab.cities-internet': 'Städte mit Internet', 'sub.cities-internet': 'Konnektivität wichtiger Städte',
'tab.gospel-resources': 'Evangeliumsressourcen', 'sub.gospel-resources': 'Ressourcen nach Ort',
'tab.regions-dashboard': 'Regionen', 'sub.regions-dashboard': 'Regionen und ihre Länder',
'tab.upg-100': 'UPG-100-Liste', 'sub.upg-100': 'meine Liste der Unerreichten + Poster',
'tab.upg-100': "Poster der UPG 100 Liste", 'sub.upg-100': 'meine Liste der Unerreichten + Poster',
navLabel: 'Forschungskarten', meta: '{n} Karten', 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.',
close: 'Schließen', help: 'Über diese Karte', desktopOnly: 'nur Desktop', lab: 'Beta', experimentalSub: 'experimentelle Karte',
mobileNotBuilt: 'nicht für Mobilgeräte', dismiss: 'Schließen', desktopOnly: 'nur Desktop', lab: 'Beta', experimentalSub: 'experimentelle Karte',
// The shared VerticalTabsLayout's own controls, VERBATIM from library/i18n/locales/de/studio.json
// (plugin studio's catalog) so both shells name the same buttons the same way.
toggleList: "Liste ein-/ausblenden", openViews: "Ansichtsliste öffnen", expandList: "Liste ausklappen", collapseList: "Liste einklappen", collapse: "Einklappen",
toggleList: "Liste ein-/ausblenden", openViews: "Ansichtsliste öffnen", expandList: "Liste ausklappen", collapseList: "Liste einklappen", collapse: "Einklappen", home: "Zurück zur Startseite",
// Experimental bundles known today (rail-length names; a bundle not listed keeps its manifest title).
'tab.prayer-walk-planner': "Gebetsspaziergänge", 'tab.upg-neighbor': "UPG-Nachbar", 'tab.key-cities': "Schlüsselstädte", 'tab.all-people-groups': "Alle Volksgruppen", 'tab.pplr-data-maps': "PPLR-Datenkarten", 'tab.wall-of-people-groups': "Wand der Volksgruppen", 'tab.country-posters': "Länderposter", 'tab.doxa-vision-card': "Doxa-Visionskarte",
'tab.prayer-walk-planner': "Gebetsspaziergänge", 'tab.upg-neighbor': "UPG-Nachbar", 'tab.key-cities': "Schlüsselstädte", 'tab.all-people-groups': "Alle Volksgruppen", 'tab.pplr-data-maps': "PPLR-Datenkarten", 'tab.wall-of-people-groups': "Wand der Volksgruppen", 'tab.country-posters': "Länderposter", 'sub.country-posters': "ein Poster für jedes Land", 'tab.doxa-vision-card': "Doxa-Visionskarte",
},
pt: {
backToTop: 'Voltar ao topo',
@ -109,16 +109,16 @@ export const STRINGS = {
'tab.cities-internet': 'Cidades com Internet', 'sub.cities-internet': 'conectividade das principais cidades',
'tab.gospel-resources': 'Recursos do Evangelho', 'sub.gospel-resources': 'recursos por lugar',
'tab.regions-dashboard': 'Regiões', 'sub.regions-dashboard': 'regiões e seus países',
'tab.upg-100': 'Lista UPG-100', 'sub.upg-100': 'minha lista de não alcançados + cartazes',
'tab.upg-100': "Cartazes da lista UPG 100", 'sub.upg-100': 'minha lista de não alcançados + cartazes',
navLabel: 'Mapas de pesquisa', meta: '{n} mapas', 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.',
close: 'Fechar', help: 'Sobre este mapa', desktopOnly: 'só no computador', lab: 'beta', experimentalSub: 'mapa experimental',
mobileNotBuilt: 'não feito para celular', dismiss: 'Fechar', desktopOnly: 'só no computador', lab: 'beta', experimentalSub: 'mapa experimental',
// The shared VerticalTabsLayout's own controls, VERBATIM from library/i18n/locales/pt/studio.json
// (plugin studio's catalog) so both shells name the same buttons the same way.
toggleList: "Mostrar ou ocultar a lista", openViews: "Abrir a lista de visualizações", expandList: "Expandir a lista", collapseList: "Recolher a lista", collapse: "Recolher",
toggleList: "Mostrar ou ocultar a lista", openViews: "Abrir a lista de visualizações", expandList: "Expandir a lista", collapseList: "Recolher a lista", collapse: "Recolher", home: "Voltar à página inicial",
// Experimental bundles known today (rail-length names; a bundle not listed keeps its manifest title).
'tab.prayer-walk-planner': "Caminhadas de oração", 'tab.upg-neighbor': "Vizinho UPG", 'tab.key-cities': "Cidades-chave", 'tab.all-people-groups': "Todos os povos", 'tab.pplr-data-maps': "Mapas de dados PPLR", 'tab.wall-of-people-groups': "Mural dos povos", 'tab.country-posters': "Cartazes por país", 'tab.doxa-vision-card': "Cartão de visão Doxa",
'tab.prayer-walk-planner': "Caminhadas de oração", 'tab.upg-neighbor': "Vizinho UPG", 'tab.key-cities': "Cidades-chave", 'tab.all-people-groups': "Todos os povos", 'tab.pplr-data-maps': "Mapas de dados PPLR", 'tab.wall-of-people-groups': "Mural dos povos", 'tab.country-posters': "Cartazes por país", 'sub.country-posters': "um cartaz para cada país", 'tab.doxa-vision-card': "Cartão de visão Doxa",
},
it: {
backToTop: 'Torna su',
@ -132,16 +132,16 @@ export const STRINGS = {
'tab.cities-internet': 'Città con Internet', 'sub.cities-internet': 'connettività delle città chiave',
'tab.gospel-resources': 'Risorse del Vangelo', 'sub.gospel-resources': 'risorse per luogo',
'tab.regions-dashboard': 'Regioni', 'sub.regions-dashboard': 'regioni e i loro paesi',
'tab.upg-100': 'Lista UPG-100', 'sub.upg-100': 'la mia lista dei non raggiunti + poster',
'tab.upg-100': "Poster della lista UPG 100", 'sub.upg-100': 'la mia lista dei non raggiunti + poster',
navLabel: 'Mappe di ricerca', meta: '{n} mappe', 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.",
close: 'Chiudi', help: 'Informazioni su questa mappa', desktopOnly: 'solo desktop', lab: 'beta', experimentalSub: 'mappa sperimentale',
mobileNotBuilt: 'non pensato per mobile', dismiss: 'Chiudi', desktopOnly: 'solo desktop', lab: 'beta', experimentalSub: 'mappa sperimentale',
// The shared VerticalTabsLayout's own controls, VERBATIM from library/i18n/locales/it/studio.json
// (plugin studio's catalog) so both shells name the same buttons the same way.
toggleList: "Mostra o nascondi l’elenco", openViews: "Apri l’elenco delle viste", expandList: "Espandi l’elenco", collapseList: "Comprimi l’elenco", collapse: "Comprimi",
toggleList: "Mostra o nascondi l’elenco", openViews: "Apri l’elenco delle viste", expandList: "Espandi l’elenco", collapseList: "Comprimi l’elenco", collapse: "Comprimi", home: "Torna alla home page",
// Experimental bundles known today (rail-length names; a bundle not listed keeps its manifest title).
'tab.prayer-walk-planner': "Passeggiate di preghiera", 'tab.upg-neighbor': "Vicino UPG", 'tab.key-cities': "Città chiave", 'tab.all-people-groups': "Tutti i popoli", 'tab.pplr-data-maps': "Mappe dati PPLR", 'tab.wall-of-people-groups': "Muro dei popoli", 'tab.country-posters': "Poster per paese", 'tab.doxa-vision-card': "Scheda visione Doxa",
'tab.prayer-walk-planner': "Passeggiate di preghiera", 'tab.upg-neighbor': "Vicino UPG", 'tab.key-cities': "Città chiave", 'tab.all-people-groups': "Tutti i popoli", 'tab.pplr-data-maps': "Mappe dati PPLR", 'tab.wall-of-people-groups': "Muro dei popoli", 'tab.country-posters': "Poster per paese", 'sub.country-posters': "un poster per ogni paese", 'tab.doxa-vision-card': "Scheda visione Doxa",
},
ro: {
backToTop: 'Sus',
@ -153,16 +153,16 @@ export const STRINGS = {
'tab.cities-internet': 'Orașe cu internet', 'sub.cities-internet': 'conectivitatea orașelor-cheie',
'tab.gospel-resources': 'Resurse ale Evangheliei', 'sub.gospel-resources': 'resurse după loc',
'tab.regions-dashboard': 'Regiuni', 'sub.regions-dashboard': 'regiunile și țările lor',
'tab.upg-100': 'Lista UPG-100', 'sub.upg-100': 'lista mea de neatinși + afișe',
'tab.upg-100': "Afișe din lista UPG 100", 'sub.upg-100': 'lista mea de neatinși + afișe',
navLabel: 'Hărți de cercetare', meta: '{n} hărți', 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.',
close: 'Închide', help: 'Despre această hartă', desktopOnly: 'doar pe desktop', lab: 'beta', experimentalSub: 'hartă experimentală',
mobileNotBuilt: 'nu e făcut pentru mobil', dismiss: 'Închide', desktopOnly: 'doar pe desktop', lab: 'beta', experimentalSub: 'hartă experimentală',
// The shared VerticalTabsLayout's own controls, VERBATIM from library/i18n/locales/ro/studio.json
// (plugin studio's catalog) so both shells name the same buttons the same way.
toggleList: "Afișează sau ascunde lista", openViews: "Deschide lista de vizualizări", expandList: "Extinde lista", collapseList: "Restrânge lista", collapse: "Restrânge",
toggleList: "Afișează sau ascunde lista", openViews: "Deschide lista de vizualizări", expandList: "Extinde lista", collapseList: "Restrânge lista", collapse: "Restrânge", home: "Înapoi la pagina principală",
// Experimental bundles known today (rail-length names; a bundle not listed keeps its manifest title).
'tab.prayer-walk-planner': "Plimbări de rugăciune", 'tab.upg-neighbor': "Vecin UPG", 'tab.key-cities': "Orașe-cheie", 'tab.all-people-groups': "Toate popoarele", 'tab.pplr-data-maps': "Hărți de date PPLR", 'tab.wall-of-people-groups': "Zidul popoarelor", 'tab.country-posters': "Afișe pe țări", 'tab.doxa-vision-card': "Card de viziune Doxa",
'tab.prayer-walk-planner': "Plimbări de rugăciune", 'tab.upg-neighbor': "Vecin UPG", 'tab.key-cities': "Orașe-cheie", 'tab.all-people-groups': "Toate popoarele", 'tab.pplr-data-maps': "Hărți de date PPLR", 'tab.wall-of-people-groups': "Zidul popoarelor", 'tab.country-posters': "Afișe pe țări", 'sub.country-posters': "un afiș pentru fiecare țară", 'tab.doxa-vision-card': "Card de viziune Doxa",
},
ru: {
backToTop: 'Наверх',
@ -174,16 +174,16 @@ export const STRINGS = {
'tab.cities-internet': 'Города с интернетом', 'sub.cities-internet': 'подключённость ключевых городов',
'tab.gospel-resources': 'Евангельские ресурсы', 'sub.gospel-resources': 'ресурсы по местам',
'tab.regions-dashboard': 'Регионы', 'sub.regions-dashboard': 'регионы и их страны',
'tab.upg-100': 'Список UPG-100', 'sub.upg-100': 'мой список недостигнутых + плакаты',
'tab.upg-100': "Плакаты списка UPG 100", 'sub.upg-100': 'мой список недостигнутых + плакаты',
navLabel: 'Исследовательские карты', meta: 'Карт: {n}', loading: 'Загрузка: {label}…', loadFailed: 'Не удалось загрузить: {label}.',
manifestHint: 'Эта вкладка собирается из manifest.json — соберите дерево или разместите собранное дерево, чтобы загрузить её.',
close: 'Закрыть', help: 'Об этой карте', desktopOnly: 'только на компьютере', lab: 'бета', experimentalSub: 'экспериментальная карта',
mobileNotBuilt: 'не для телефона', dismiss: 'Закрыть', desktopOnly: 'только на компьютере', lab: 'бета', experimentalSub: 'экспериментальная карта',
// The shared VerticalTabsLayout's own controls, VERBATIM from library/i18n/locales/ru/studio.json
// (plugin studio's catalog) so both shells name the same buttons the same way.
toggleList: "Показать или скрыть список", openViews: "Открыть список представлений", expandList: "Развернуть список", collapseList: "Свернуть список", collapse: "Свернуть",
toggleList: "Показать или скрыть список", openViews: "Открыть список представлений", expandList: "Развернуть список", collapseList: "Свернуть список", collapse: "Свернуть", home: "На главную страницу",
// Experimental bundles known today (rail-length names; a bundle not listed keeps its manifest title).
'tab.prayer-walk-planner': "Молитвенные прогулки", 'tab.upg-neighbor': "Сосед UPG", 'tab.key-cities': "Ключевые города", 'tab.all-people-groups': "Все народы", 'tab.pplr-data-maps': "Карты данных PPLR", 'tab.wall-of-people-groups': "Стена народов", 'tab.country-posters': "Плакаты по странам", 'tab.doxa-vision-card': "Карточка видения Doxa",
'tab.prayer-walk-planner': "Молитвенные прогулки", 'tab.upg-neighbor': "Сосед UPG", 'tab.key-cities': "Ключевые города", 'tab.all-people-groups': "Все народы", 'tab.pplr-data-maps': "Карты данных PPLR", 'tab.wall-of-people-groups': "Стена народов", 'tab.country-posters': "Плакаты по странам", 'sub.country-posters': "плакат для каждой страны", 'tab.doxa-vision-card': "Карточка видения Doxa",
},
ar: {
backToTop: 'إلى الأعلى',
@ -195,16 +195,16 @@ export const STRINGS = {
'tab.cities-internet': 'مدن متصلة بالإنترنت', 'sub.cities-internet': 'اتصال المدن الرئيسية',
'tab.gospel-resources': 'موارد الإنجيل', 'sub.gospel-resources': 'الموارد حسب المكان',
'tab.regions-dashboard': 'المناطق', 'sub.regions-dashboard': 'المناطق ودولها',
'tab.upg-100': 'قائمة UPG-100', 'sub.upg-100': 'قائمتي لغير المُبشَّرين + ملصقات',
'tab.upg-100': "ملصقات قائمة UPG 100", 'sub.upg-100': 'قائمتي لغير المُبشَّرين + ملصقات',
navLabel: 'خرائط البحث', meta: 'عدد الخرائط: {n}', loading: 'جارٍ تحميل {label}…', loadFailed: 'تعذّر تحميل {label}.',
manifestHint: 'تُبنى علامة التبويب هذه من manifest.json — ابنِ الشجرة أو قدّم الشجرة المبنية لتحميلها.',
close: 'إغلاق', help: 'عن هذه الخريطة', desktopOnly: 'على الحاسوب فقط', lab: 'تجريبي', experimentalSub: 'خريطة تجريبية',
mobileNotBuilt: 'غير مُعدّ للهاتف', dismiss: 'إغلاق', desktopOnly: 'على الحاسوب فقط', lab: 'تجريبي', experimentalSub: 'خريطة تجريبية',
// The shared VerticalTabsLayout's own controls, VERBATIM from library/i18n/locales/ar/studio.json
// (plugin studio's catalog) so both shells name the same buttons the same way.
toggleList: "إظهار القائمة أو إخفاؤها", openViews: "فتح قائمة العروض", expandList: "توسيع القائمة", collapseList: "طي القائمة", collapse: "طي",
toggleList: "إظهار القائمة أو إخفاؤها", openViews: "فتح قائمة العروض", expandList: "توسيع القائمة", collapseList: "طي القائمة", collapse: "طي", home: "العودة إلى الصفحة الرئيسية",
// Experimental bundles known today (rail-length names; a bundle not listed keeps its manifest title).
'tab.prayer-walk-planner': "جولات الصلاة", 'tab.upg-neighbor': "جار UPG", 'tab.key-cities': "المدن الرئيسية", 'tab.all-people-groups': "جميع الشعوب", 'tab.pplr-data-maps': "خرائط بيانات PPLR", 'tab.wall-of-people-groups': "جدار الشعوب", 'tab.country-posters': "ملصقات الدول", 'tab.doxa-vision-card': "بطاقة رؤية Doxa",
'tab.prayer-walk-planner': "جولات الصلاة", 'tab.upg-neighbor': "جار UPG", 'tab.key-cities': "المدن الرئيسية", 'tab.all-people-groups': "جميع الشعوب", 'tab.pplr-data-maps': "خرائط بيانات PPLR", 'tab.wall-of-people-groups': "جدار الشعوب", 'tab.country-posters': "ملصقات الدول", 'sub.country-posters': "ملصق لكل دولة", 'tab.doxa-vision-card': "بطاقة رؤية Doxa",
},
hi: {
backToTop: 'ऊपर जाएँ',
@ -216,16 +216,16 @@ export const STRINGS = {
'tab.cities-internet': 'इंटरनेट वाले शहर', 'sub.cities-internet': 'प्रमुख शहरों की कनेक्टिविटी',
'tab.gospel-resources': 'सुसमाचार संसाधन', 'sub.gospel-resources': 'स्थान के अनुसार संसाधन',
'tab.regions-dashboard': 'क्षेत्र', 'sub.regions-dashboard': 'क्षेत्र और उनके देश',
'tab.upg-100': 'UPG-100 सूची', 'sub.upg-100': 'मेरी अप्राप्त सूची + पोस्टर',
'tab.upg-100': "UPG 100 सूची पोस्टर", 'sub.upg-100': 'मेरी अप्राप्त सूची + पोस्टर',
navLabel: 'शोध मानचित्र', meta: '{n} मानचित्र', loading: '{label} लोड हो रहा है…', loadFailed: '{label} लोड नहीं हो सका।',
manifestHint: 'यह टैब manifest.json से बनता है — इसे लोड करने के लिए ट्री बनाएँ या बना हुआ ट्री सर्व करें।',
close: 'बंद करें', help: 'इस नक्शे के बारे में', desktopOnly: 'केवल डेस्कटॉप', lab: 'बीटा', experimentalSub: 'प्रायोगिक मानचित्र',
mobileNotBuilt: 'मोबाइल के लिए नहीं बना', dismiss: 'बंद करें', desktopOnly: 'केवल डेस्कटॉप', lab: 'बीटा', experimentalSub: 'प्रायोगिक मानचित्र',
// The shared VerticalTabsLayout's own controls, VERBATIM from library/i18n/locales/hi/studio.json
// (plugin studio's catalog) so both shells name the same buttons the same way.
toggleList: "सूची दिखाएँ या छिपाएँ", openViews: "दृश्यों की सूची खोलें", expandList: "सूची फैलाएँ", collapseList: "सूची संक्षिप्त करें", collapse: "संक्षिप्त करें",
toggleList: "सूची दिखाएँ या छिपाएँ", openViews: "दृश्यों की सूची खोलें", expandList: "सूची फैलाएँ", collapseList: "सूची संक्षिप्त करें", collapse: "संक्षिप्त करें", home: "होमपेज पर वापस जाएँ",
// Experimental bundles known today (rail-length names; a bundle not listed keeps its manifest title).
'tab.prayer-walk-planner': "प्रार्थना पदयात्रा", 'tab.upg-neighbor': "UPG पड़ोसी", 'tab.key-cities': "प्रमुख शहर", 'tab.all-people-groups': "सभी जनसमूह", 'tab.pplr-data-maps': "PPLR डेटा मानचित्र", 'tab.wall-of-people-groups': "जनसमूहों की दीवार", 'tab.country-posters': "देश पोस्टर", 'tab.doxa-vision-card': "Doxa दर्शन कार्ड",
'tab.prayer-walk-planner': "प्रार्थना पदयात्रा", 'tab.upg-neighbor': "UPG पड़ोसी", 'tab.key-cities': "प्रमुख शहर", 'tab.all-people-groups': "सभी जनसमूह", 'tab.pplr-data-maps': "PPLR डेटा मानचित्र", 'tab.wall-of-people-groups': "जनसमूहों की दीवार", 'tab.country-posters': "देश पोस्टर", 'sub.country-posters': "हर देश के लिए एक पोस्टर", 'tab.doxa-vision-card': "Doxa दर्शन कार्ड",
},
zh: {
backToTop: '回到顶部',
@ -237,16 +237,16 @@ export const STRINGS = {
'tab.cities-internet': '有互联网的城市', 'sub.cities-internet': '主要城市的网络连接',
'tab.gospel-resources': '福音资源', 'sub.gospel-resources': '按地点划分的资源',
'tab.regions-dashboard': '区域', 'sub.regions-dashboard': '区域及其国家',
'tab.upg-100': 'UPG-100 名单', 'sub.upg-100': '我的未得之民名单 + 海报',
'tab.upg-100': "UPG 100 名单海报", 'sub.upg-100': '我的未得之民名单 + 海报',
navLabel: '研究地图', meta: '{n} 张地图', loading: '正在加载{label}…', loadFailed: '无法加载{label}。',
manifestHint: '此标签页由 manifest.json 组成——请构建目录树或提供已构建的目录树以加载它。',
close: '关闭', help: '关于此地图', desktopOnly: '仅限桌面', lab: '测试版', experimentalSub: '实验性地图',
mobileNotBuilt: '未针对手机设计', dismiss: '关闭', desktopOnly: '仅限桌面', lab: '测试版', experimentalSub: '实验性地图',
// The shared VerticalTabsLayout's own controls, VERBATIM from library/i18n/locales/zh/studio.json
// (plugin studio's catalog) so both shells name the same buttons the same way.
toggleList: "显示或隐藏列表", openViews: "打开视图列表", expandList: "展开列表", collapseList: "折叠列表", collapse: "折叠",
toggleList: "显示或隐藏列表", openViews: "打开视图列表", expandList: "展开列表", collapseList: "折叠列表", collapse: "折叠", home: "返回首页",
// Experimental bundles known today (rail-length names; a bundle not listed keeps its manifest title).
'tab.prayer-walk-planner': "祷告行走", 'tab.upg-neighbor': "UPG 邻居", 'tab.key-cities': "重点城市", 'tab.all-people-groups': "所有民族", 'tab.pplr-data-maps': "PPLR 数据地图", 'tab.wall-of-people-groups': "民族之墙", 'tab.country-posters': "国家海报", 'tab.doxa-vision-card': "Doxa 异象卡",
'tab.prayer-walk-planner': "祷告行走", 'tab.upg-neighbor': "UPG 邻居", 'tab.key-cities': "重点城市", 'tab.all-people-groups': "所有民族", 'tab.pplr-data-maps': "PPLR 数据地图", 'tab.wall-of-people-groups': "民族之墙", 'tab.country-posters': "国家海报", 'sub.country-posters': "每个国家一张海报", 'tab.doxa-vision-card': "Doxa 异象卡",
}
}