The packet gets its bounded and centered sets page
Brief A1 back matter: after the profiles, before the wheel, full detail only. The lightweight packet is map, triangle, profiles, wheel, points -- these two figures are the part a reader sits with rather than carries. The layouts are regions' library/components/charts modules, imported rather than injected: unlike describeGroup's country resolver they have zero imports and run under plain node, and packet-render already imports scatterCells from that directory. Verified by importing and CALLING them, not by reading them. They return data, so the SVG is ours. Gospel's non-negotiable is carried through and checked rather than trusted: the bounded set keeps a deliberate gap either side of the boundary because a dot ON the line is the one thing a bounded set cannot express, and print has no hover to disambiguate it. Measured on the real module with 40 groups -- inside max 85.3 of 92 allowed, outside min 119.8 of 112 required. The figure scales through the viewBox, so the gap lives in coordinates the scaling cannot touch; shrink the figure, never the gap. UNKNOWN POINTS ARE STATED, NOT PLOTTED. layoutBoundedSet gives them no x/y, which is the module being right: `reached` undefined means we do not know which side they belong on, so there is no honest place to draw them. My first version mapped them through the same dot() helper and crashed on p.x.toFixed -- a better outcome than silently drawing them at (0,0), which would have put "we don't know" inside the circle. They go in the tally, because on a printed page a category the reader cannot see reads as zero. check-packet-variants' sheet delta goes 2 -> 3, updated in this commit rather than relaxed into a range. It also now SUPPLIES the sets fixture: setsPage returns '' without data, so a build() that omitted `sets` exercised the filter for every page except the newest one, and the gate sat green through the whole rewrite while asserting a delta that had become wrong. A fixture missing an input silently narrows what the whole file covers. Seven strings x eleven locales; packet-strings-parity green. Gospel's own ring names live in gospelInternet.json, a plugin catalogue, so there is no collision with these.
This commit is contained in:
parent
e5dd83dad9
commit
3c1d513cc3
3 changed files with 231 additions and 17 deletions
|
|
@ -58,7 +58,16 @@ const groups = Array.from({ length: 45 }, (_, i) => ({ slug: `g${i}`, name: `Gro
|
|||
const zone = { id: 'test', label: 'Test Zone' }
|
||||
const funnel = { steps: [{ label: 'a', groups: 12379 }, { label: 'b', groups: 2107 }] }
|
||||
const christian = { pctEvangelical: 3.2 }
|
||||
const build = (v) => R.buildPacket(zone, groups, new Map(), '<svg/>', funnel, christian, v)
|
||||
// ★ THE SETS MUST BE SUPPLIED OR THIS GATE CANNOT SEE THE PAGE. setsPage returns '' without data —
|
||||
// correctly, so a host with no set data still gets a valid packet — which means a build() that
|
||||
// omits `sets` exercises the variant filter for every page EXCEPT the one most recently added. The
|
||||
// gate stayed green through the whole sets rewrite while asserting a 2-sheet delta that had become
|
||||
// 3. A fixture that is missing an input silently narrows what the whole file covers.
|
||||
const sets = {
|
||||
bounded: Array.from({ length: 30 }, (_, i) => ({ id: `b${i}`, reached: i % 3 === 0 ? true : (i % 3 === 1 ? false : undefined) })),
|
||||
centered: Array.from({ length: 24 }, (_, i) => ({ id: `c${i}`, ring: (i % 12) - 1 })),
|
||||
}
|
||||
const build = (v) => R.buildPacket(zone, groups, new Map(), '<svg/>', funnel, christian, v, sets)
|
||||
const count = (html, re) => (html.match(re) || []).length
|
||||
|
||||
const full = build('full')
|
||||
|
|
@ -74,8 +83,24 @@ ok(count(light, /sheet-life/g) === 0, 'lightweight still carries the life calend
|
|||
ok(count(light, /sheet-christian/g) === 0, 'lightweight still carries the %-evangelical page')
|
||||
// …and keeps the triangle, the profiles, the wheel and the points.
|
||||
ok(count(light, /funnel-title/g) === count(full, /funnel-title/g), 'lightweight lost the funnel (the Driver\'s "triangle")')
|
||||
ok(count(full, /class="sheet/g) - count(light, /class="sheet/g) === 2,
|
||||
`lightweight should be exactly 2 sheets shorter, got ${count(full, /class="sheet/g)} vs ${count(light, /class="sheet/g)}`)
|
||||
// …and the SETS page, which is back matter a reader sits with rather than carries — the same
|
||||
// reason the life calendar and the %-evangelical grid are dropped.
|
||||
ok(count(full, /sheet-sets/g) === 1, 'the full packet has no bounded/centered sets page')
|
||||
ok(count(light, /sheet-sets/g) === 0, 'lightweight still carries the sets page')
|
||||
// ⚠ THREE, not two: the delta grew when the sets page landed, and this number is meant to be
|
||||
// UPDATED in the commit that adds a page, never relaxed into a range. A tolerance here would make
|
||||
// the assertion unable to see the next page that goes missing.
|
||||
ok(count(full, /class="sheet/g) - count(light, /class="sheet/g) === 3,
|
||||
`lightweight should be exactly 3 sheets shorter, got ${count(full, /class="sheet/g)} vs ${count(light, /class="sheet/g)}`)
|
||||
// ★ UNKNOWN POINTS ARE STATED EVEN THOUGH THEY CANNOT BE PLOTTED. layoutBoundedSet gives them no
|
||||
// x/y — deliberately, since `reached` undefined means we do not know which side they belong on and
|
||||
// drawing them anywhere would assert exactly what is unknown. On a printed page there is no hover,
|
||||
// so a category the reader cannot see reads as zero. It must appear in the tally text.
|
||||
{
|
||||
const caps = full.match(/class="set-cap">([^<]*)</g) || []
|
||||
ok(caps.length === 2, `expected two set captions, found ${caps.length}`)
|
||||
ok(/10/.test(caps.join(' ')), 'the bounded tally does not state its unknown count — an un-inked category reads as zero in print')
|
||||
}
|
||||
|
||||
// An unknown variant must print the FULL packet. A typo that printed a SHORTER packet would look
|
||||
// like a successful print.
|
||||
|
|
@ -132,4 +157,4 @@ if (fails.length) {
|
|||
for (const f of fails) console.error(` ✗ ${f}`)
|
||||
process.exit(1)
|
||||
}
|
||||
console.log('PACKET-VARIANTS: PASS — both packets print every group, lightweight drops exactly the two contemplative sheets, an unknown variant falls back to full, the Prayer List prints the PACKET and not the columnar list, the Cards button and its size row are unchanged, and one ref means one open tape.')
|
||||
console.log('PACKET-VARIANTS: PASS — both packets print every group, lightweight drops exactly the three back-matter sheets (life calendar, % grid, sets), an unknown variant falls back to full, the Prayer List prints the PACKET and not the columnar list, the Cards button and its size row are unchanged, and one ref means one open tape.')
|
||||
|
|
|
|||
|
|
@ -43,6 +43,12 @@ const SCRIPT_FONT = {
|
|||
};
|
||||
|
||||
import { scatterCells } from '../components/charts/packetCharts.js'
|
||||
// The set LAYOUTS (gospel's figures, promoted to library/ by regions). Imported rather than injected
|
||||
// because — unlike describeGroup's country resolver — these have ZERO imports of their own and run
|
||||
// under plain node, so they cannot break `node internal/check-*.mjs`. Verified by importing and
|
||||
// CALLING them, not by reading them. They return data; the SVG is ours.
|
||||
import { layoutBoundedSet, boundedSetTally } from '../components/charts/boundedSet.js'
|
||||
import { layoutCenteredSet, ringTally, RING_MAX } from '../components/charts/centeredSet.js'
|
||||
|
||||
// `describe` is INJECTED at the same seam as `strings`, and deliberately not imported. This module
|
||||
// has (almost) no imports on purpose: the SAME file runs under Node for the offline generator and
|
||||
|
|
@ -182,6 +188,26 @@ export function createPacketRenderer({ strings, lang = 'en', fontData = null, de
|
|||
.lc-legend i{display:inline-block;width:15px;height:15px;vertical-align:-2px;margin-inline-end:8px}
|
||||
.lc-foot{margin:14px 0 0;font:400 14px Georgia,serif;color:#6f6a5c}
|
||||
|
||||
/* ── THE BOUNDED + CENTERED SETS (back matter) ──────────────────────────
|
||||
Two figures side by side. The SVGs carry no width/height — they scale to their
|
||||
column through the viewBox, which is what keeps gospel's boundary gap intact:
|
||||
the gap lives in the LAYOUT's coordinates and scaling the viewBox cannot
|
||||
compress it, whereas nudging r or spread would. */
|
||||
.set-row{display:flex;gap:60px;align-items:flex-start;margin-top:26px}
|
||||
.set-col{width:var(--set-col,600px);flex:0 0 auto;text-align:center}
|
||||
.set-h{margin:0 0 10px;font:700 22px Georgia,serif;color:#1b1a17}
|
||||
.set-svg{width:100%;height:auto;overflow:visible}
|
||||
.set-ring{fill:none;stroke:#3b463d;stroke-width:2}
|
||||
.set-ring-faint{fill:none;stroke:#d8d3c4;stroke-width:1}
|
||||
.set-in{fill:#2f6d4f}
|
||||
.set-out{fill:#b9b2a0}
|
||||
/* ⚠ UNKNOWN IS INKED, NOT OMITTED — regions' rule, and it is right for print: a printed page
|
||||
has no hover, so a category the reader cannot SEE is one they will read as zero. Hollow so it
|
||||
is visibly neither inside nor outside rather than a third opinion. */
|
||||
.set-unk{fill:#fff;stroke:#b9b2a0;stroke-width:1.5}
|
||||
.set-centre{fill:#2f6d4f}
|
||||
.set-cap{margin:10px 0 0;font:400 15px Georgia,serif;color:#413d35}
|
||||
|
||||
/* ── THE THREE PRAYER COLUMNS, now a HORIZONTAL strip at the end of each row ──────────
|
||||
They were a vertical stack in the old 683x160 card. In a ${CW}x${CH.toFixed(0)} ROW there is no
|
||||
vertical room for three stacked labels, so the three cells sit side by side, each
|
||||
|
|
@ -777,6 +803,85 @@ export function createPacketRenderer({ strings, lang = 'en', fontData = null, de
|
|||
<div class="fine">${esc(t('points_attrib'))}</div>`);
|
||||
}
|
||||
|
||||
// ── PAGE n+1: the BOUNDED and CENTERED sets ─────────────────────────────────
|
||||
// Brief A1 BACK MATTER: after the profiles, before the wheel. FULL DETAIL ONLY — the lightweight
|
||||
// packet is map · triangle · profiles · wheel · points, and these two figures are the part a
|
||||
// reader sits with rather than carries.
|
||||
//
|
||||
// The LAYOUTS come from regions' library/components/charts modules, imported directly rather than
|
||||
// injected: unlike describeGroup's country resolver they have ZERO imports and run under plain
|
||||
// node (verified by importing and calling them, not by reading them), and packet-render already
|
||||
// imports scatterCells from that same directory. They return DATA — points with x/y in unitless
|
||||
// SVG user coordinates centred on (cx,cy) — so the markup below is ours.
|
||||
//
|
||||
// ⚠ GOSPEL'S NON-NEGOTIABLE, carried through regions: the bounded set keeps a deliberate gap
|
||||
// either side of the boundary (inside within 0.92r, outside beyond 1.12r) because a dot sitting ON
|
||||
// the line is the one thing a bounded set cannot express, and PRINT HAS NO HOVER to disambiguate
|
||||
// it. If the figure does not fit, SHRINK THE WHOLE FIGURE — never compress the gap. Measured on
|
||||
// the real module with 40 groups: inside max 85.3 of 92 allowed, outside min 119.8 of 112
|
||||
// required. The scale below is applied to the viewBox, so it cannot touch the gap.
|
||||
function setsPage(zone, sets) {
|
||||
// '' WITHOUT DATA, exactly like funnelPage and christianPage — a page that cannot state true
|
||||
// figures must not appear at all. This is what keeps FULL valid before a host supplies sets.
|
||||
if (!sets || (!Array.isArray(sets.bounded) && !Array.isArray(sets.centered))) return '';
|
||||
const bounded = Array.isArray(sets.bounded) ? sets.bounded : [];
|
||||
const centered = Array.isArray(sets.centered) ? sets.centered : [];
|
||||
if (!bounded.length && !centered.length) return '';
|
||||
|
||||
const usableW = W - 2 * M, colW = (usableW - 60) / 2;
|
||||
const parts = [];
|
||||
|
||||
if (bounded.length) {
|
||||
const L = layoutBoundedSet(bounded, { r: 100, spread: 220 });
|
||||
const T = boundedSetTally(L);
|
||||
// The viewBox is sized from the layout's own extent so the figure scales to the column
|
||||
// without any coordinate being touched — the gap survives by construction.
|
||||
// ⚠ UNKNOWN POINTS CARRY NO x/y, AND THAT IS THE MODULE BEING CORRECT. `reached` undefined
|
||||
// means we do not know which side of the boundary a people belongs on, so there is no honest
|
||||
// place to draw it — plotting it anywhere would assert the very thing that is unknown. My
|
||||
// first version mapped over L.unknown with the same dot() helper and crashed on
|
||||
// `p.x.toFixed`, which is a better outcome than silently drawing them at (0,0) inside the
|
||||
// circle. They are STATED in the tally instead (regions: an un-inked category on a printed
|
||||
// page, where there is no hover, reads as zero).
|
||||
const plotted = [...L.inside, ...L.outside];
|
||||
const ext = Math.max(...plotted.map((p) => Math.hypot(p.x - L.cx, p.y - L.cy)), L.r * 1.2) * 1.08;
|
||||
const dot = (p, cls) => `<circle class="${cls}" cx="${p.x.toFixed(1)}" cy="${p.y.toFixed(1)}" r="5"/>`;
|
||||
parts.push(`<div class="set-col">
|
||||
<h2 class="set-h">${esc(t('sets_bounded_title'))}</h2>
|
||||
<svg class="set-svg" viewBox="${(L.cx - ext).toFixed(1)} ${(L.cy - ext).toFixed(1)} ${(ext * 2).toFixed(1)} ${(ext * 2).toFixed(1)}">
|
||||
<circle class="set-ring" cx="${L.cx}" cy="${L.cy}" r="${L.r}"/>
|
||||
${L.inside.map((p) => dot(p, 'set-in')).join('')}
|
||||
${L.outside.map((p) => dot(p, 'set-out')).join('')}
|
||||
</svg>
|
||||
<p class="set-cap">${esc(fill(t('sets_bounded_tally'),
|
||||
{ inside: num(T.inside), outside: num(T.outside), unknown: num(T.unknown) }))}</p>
|
||||
</div>`);
|
||||
}
|
||||
|
||||
if (centered.length) {
|
||||
const L = layoutCenteredSet(centered, {});
|
||||
const T = ringTally(L);
|
||||
const ext = (L.innerR + RING_MAX * L.ringGap) * 1.12;
|
||||
parts.push(`<div class="set-col">
|
||||
<h2 class="set-h">${esc(t('sets_centered_title'))}</h2>
|
||||
<svg class="set-svg" viewBox="${(L.cx - ext).toFixed(1)} ${(L.cy - ext).toFixed(1)} ${(ext * 2).toFixed(1)} ${(ext * 2).toFixed(1)}">
|
||||
${(L.radii || []).map((r) => `<circle class="set-ring-faint" cx="${L.cx}" cy="${L.cy}" r="${r.r}"/>`).join('')}
|
||||
${L.placed.map((p) => `<circle class="set-in" cx="${p.x.toFixed(1)}" cy="${p.y.toFixed(1)}" r="5"/>`).join('')}
|
||||
<circle class="set-centre" cx="${L.cx}" cy="${L.cy}" r="${(L.innerR * 0.6).toFixed(1)}"/>
|
||||
</svg>
|
||||
<p class="set-cap">${esc(fill(t('sets_centered_tally'),
|
||||
{ placed: num(T.placed), centre: num(T.centre), unplaced: num(T.unplaced) }))}</p>
|
||||
</div>`);
|
||||
}
|
||||
|
||||
return sheet(`
|
||||
<div class="pg-head"><div class="pg-kicker">${esc(t('sets_kicker'))}</div>
|
||||
<h1 class="pg-h1">${esc(t('sets_title'))}</h1></div>
|
||||
<p class="pg-lede">${esc(t('sets_lede'))}</p>
|
||||
<div class="set-row" style="--set-col:${colW.toFixed(0)}px">${parts.join('')}</div>
|
||||
`, 'sheet-sets');
|
||||
}
|
||||
|
||||
// ── PAGE n+2: the prayer wheel ──────────────────────────────────────────────
|
||||
// REDRAWN as SVG rather than embedding the source PDF page: a raster embed cannot
|
||||
// be translated, and this packet must generate in any language. Twelve equal
|
||||
|
|
@ -845,10 +950,15 @@ export function createPacketRenderer({ strings, lang = 'en', fontData = null, de
|
|||
// never drop a page whose count depends on the data.
|
||||
const VARIANTS = {
|
||||
full: null, // null = every page (today's packet, unchanged)
|
||||
lightweight: new Set(['life', 'christian']), // page KEYS to omit
|
||||
// page KEYS to omit. 'sets' joins them: the bounded/centered figures are BACK MATTER a reader
|
||||
// sits with, which is the same reason the life calendar and the %-evangelical grid are dropped.
|
||||
lightweight: new Set(['life', 'christian', 'sets']),
|
||||
};
|
||||
|
||||
function buildPacket(zone, groups, photos, mapSvg, funnel = null, christian = null, variant = 'full') {
|
||||
// `sets` is the EIGHTH parameter and the last positional one this signature should ever grow — it
|
||||
// is already at the edge of readable. A ninth belongs in an options object; flagged here so the
|
||||
// next person adding a page makes that change rather than extending the line again.
|
||||
function buildPacket(zone, groups, photos, mapSvg, funnel = null, christian = null, variant = 'full', sets = null) {
|
||||
// ★ PAGE ORDER IS THE DRIVER'S, 2026-09-27, and it is an argument rather than a layout:
|
||||
// 1 map — where this zone is
|
||||
// 2 life calendar — 100 years x 52 weeks, a whole human life on one page
|
||||
|
|
@ -872,6 +982,8 @@ export function createPacketRenderer({ strings, lang = 'en', fontData = null, de
|
|||
keep('funnel') && funnelPage(zone, groups, funnel),
|
||||
// NOT behind keep() — see the VARIANTS comment: dropping list pages drops people.
|
||||
...listPages(zone, groups, photos),
|
||||
// BACK MATTER: after the profiles, before the wheel (brief A1). Full-detail only.
|
||||
keep('sets') && setsPage(zone, sets),
|
||||
keep('points') && pointsPage(),
|
||||
keep('wheel') && wheelPage(),
|
||||
].filter(Boolean);
|
||||
|
|
|
|||
|
|
@ -211,7 +211,14 @@
|
|||
"desc_gsec_3": "Fewer than 2% are evangelical, and scattered church planting has begun among them.",
|
||||
"desc_gsec_4": "Between 2% and 5% are evangelical.",
|
||||
"desc_gsec_5": "Between 5% and 10% are evangelical.",
|
||||
"desc_gsec_6": "More than 10% are evangelical."
|
||||
"desc_gsec_6": "More than 10% are evangelical.",
|
||||
"sets_kicker": "Who is near, and who is not",
|
||||
"sets_title": "Two ways to see the same people",
|
||||
"sets_lede": "The circle asks whether a people has been reached. The rings ask how far they sit from someone who could reach them.",
|
||||
"sets_bounded_title": "Reached, and not",
|
||||
"sets_centered_title": "Distance from a neighbour",
|
||||
"sets_bounded_tally": "{inside} inside · {outside} outside · {unknown} unknown",
|
||||
"sets_centered_tally": "{placed} placed · {centre} at the centre · {unplaced} unplaced"
|
||||
},
|
||||
"es": {
|
||||
"map_page_kicker": "GRUPOS ÉTNICOS NO EVANGELIZADOS",
|
||||
|
|
@ -417,7 +424,14 @@
|
|||
"desc_gsec_3": "Menos del 2% evangélico, y entre ellos ha comenzado una plantación de iglesias dispersa.",
|
||||
"desc_gsec_4": "Entre el 2% y el 5% son evangélicos.",
|
||||
"desc_gsec_5": "Entre el 5% y el 10% son evangélicos.",
|
||||
"desc_gsec_6": "Más del 10% son evangélicos."
|
||||
"desc_gsec_6": "Más del 10% son evangélicos.",
|
||||
"sets_kicker": "Quién está cerca y quién no",
|
||||
"sets_title": "Dos maneras de ver al mismo pueblo",
|
||||
"sets_lede": "El círculo pregunta si un pueblo ha sido alcanzado. Los anillos preguntan a qué distancia está de alguien que podría alcanzarlo.",
|
||||
"sets_bounded_title": "Alcanzados y no alcanzados",
|
||||
"sets_centered_title": "Distancia a un vecino",
|
||||
"sets_bounded_tally": "{inside} dentro · {outside} fuera · {unknown} desconocido",
|
||||
"sets_centered_tally": "{placed} ubicados · {centre} en el centro · {unplaced} sin ubicar"
|
||||
},
|
||||
"fr": {
|
||||
"map_page_kicker": "GROUPES ETHNIQUES NON ATTEINTS",
|
||||
|
|
@ -623,7 +637,14 @@
|
|||
"desc_gsec_3": "Moins de 2% d’évangéliques, et une implantation d’Églises dispersée a commencé parmi eux.",
|
||||
"desc_gsec_4": "Entre 2% et 5% sont évangéliques.",
|
||||
"desc_gsec_5": "Entre 5% et 10% sont évangéliques.",
|
||||
"desc_gsec_6": "Plus de 10% sont évangéliques."
|
||||
"desc_gsec_6": "Plus de 10% sont évangéliques.",
|
||||
"sets_kicker": "Qui est proche, et qui ne l’est pas",
|
||||
"sets_title": "Deux façons de voir le même peuple",
|
||||
"sets_lede": "Le cercle demande si un peuple a été atteint. Les anneaux demandent à quelle distance il se trouve de quelqu’un qui pourrait l’atteindre.",
|
||||
"sets_bounded_title": "Atteints, ou non",
|
||||
"sets_centered_title": "Distance d’un voisin",
|
||||
"sets_bounded_tally": "{inside} à l’intérieur · {outside} à l’extérieur · {unknown} inconnu",
|
||||
"sets_centered_tally": "{placed} placés · {centre} au centre · {unplaced} non placés"
|
||||
},
|
||||
"pt": {
|
||||
"map_page_kicker": "GRUPOS ÉTNICOS NÃO ALCANÇADOS",
|
||||
|
|
@ -827,7 +848,14 @@
|
|||
"desc_gsec_3": "Menos de 2% evangélicos, e uma plantação de igrejas dispersa começou entre eles.",
|
||||
"desc_gsec_4": "Entre 2% e 5% são evangélicos.",
|
||||
"desc_gsec_5": "Entre 5% e 10% são evangélicos.",
|
||||
"desc_gsec_6": "Mais de 10% são evangélicos."
|
||||
"desc_gsec_6": "Mais de 10% são evangélicos.",
|
||||
"sets_kicker": "Quem está perto e quem não está",
|
||||
"sets_title": "Duas formas de ver o mesmo povo",
|
||||
"sets_lede": "O círculo pergunta se um povo foi alcançado. Os anéis perguntam a que distância ele está de alguém que poderia alcançá-lo.",
|
||||
"sets_bounded_title": "Alcançados e não alcançados",
|
||||
"sets_centered_title": "Distância de um vizinho",
|
||||
"sets_bounded_tally": "{inside} dentro · {outside} fora · {unknown} desconhecido",
|
||||
"sets_centered_tally": "{placed} posicionados · {centre} no centro · {unplaced} sem posição"
|
||||
},
|
||||
"de": {
|
||||
"map_page_kicker": "UNERREICHTE VOLKSGRUPPEN",
|
||||
|
|
@ -1033,7 +1061,14 @@
|
|||
"desc_gsec_3": "Unter 2% evangelikal, und vereinzelt hat unter ihnen die Gemeindegründung begonnen.",
|
||||
"desc_gsec_4": "Zwischen 2% und 5% sind evangelikal.",
|
||||
"desc_gsec_5": "Zwischen 5% und 10% sind evangelikal.",
|
||||
"desc_gsec_6": "Mehr als 10% sind evangelikal."
|
||||
"desc_gsec_6": "Mehr als 10% sind evangelikal.",
|
||||
"sets_kicker": "Wer ist nah, und wer nicht",
|
||||
"sets_title": "Zwei Blicke auf dasselbe Volk",
|
||||
"sets_lede": "Der Kreis fragt, ob ein Volk erreicht wurde. Die Ringe fragen, wie weit es von jemandem entfernt ist, der es erreichen könnte.",
|
||||
"sets_bounded_title": "Erreicht und nicht erreicht",
|
||||
"sets_centered_title": "Abstand zu einem Nachbarn",
|
||||
"sets_bounded_tally": "{inside} innen · {outside} außen · {unknown} unbekannt",
|
||||
"sets_centered_tally": "{placed} platziert · {centre} in der Mitte · {unplaced} ohne Platz"
|
||||
},
|
||||
"it": {
|
||||
"map_page_kicker": "GRUPPI ETNICI NON RAGGIUNTI",
|
||||
|
|
@ -1237,7 +1272,14 @@
|
|||
"desc_gsec_3": "Meno del 2% evangelici, e tra loro è iniziata una fondazione di chiese sparsa.",
|
||||
"desc_gsec_4": "Tra il 2% e il 5% sono evangelici.",
|
||||
"desc_gsec_5": "Tra il 5% e il 10% sono evangelici.",
|
||||
"desc_gsec_6": "Più del 10% sono evangelici."
|
||||
"desc_gsec_6": "Più del 10% sono evangelici.",
|
||||
"sets_kicker": "Chi è vicino e chi no",
|
||||
"sets_title": "Due modi di vedere lo stesso popolo",
|
||||
"sets_lede": "Il cerchio chiede se un popolo è stato raggiunto. Gli anelli chiedono quanto dista da qualcuno che potrebbe raggiungerlo.",
|
||||
"sets_bounded_title": "Raggiunti e non raggiunti",
|
||||
"sets_centered_title": "Distanza da un vicino",
|
||||
"sets_bounded_tally": "{inside} dentro · {outside} fuori · {unknown} sconosciuto",
|
||||
"sets_centered_tally": "{placed} collocati · {centre} al centro · {unplaced} non collocati"
|
||||
},
|
||||
"ro": {
|
||||
"map_page_kicker": "GRUPURI ETNICE NEATINSE",
|
||||
|
|
@ -1441,7 +1483,14 @@
|
|||
"desc_gsec_3": "Sub 2% evanghelici, iar printre ei a început o plantare de biserici răzleață.",
|
||||
"desc_gsec_4": "Între 2% și 5% sunt evanghelici.",
|
||||
"desc_gsec_5": "Între 5% și 10% sunt evanghelici.",
|
||||
"desc_gsec_6": "Peste 10% sunt evanghelici."
|
||||
"desc_gsec_6": "Peste 10% sunt evanghelici.",
|
||||
"sets_kicker": "Cine este aproape și cine nu",
|
||||
"sets_title": "Două feluri de a vedea același popor",
|
||||
"sets_lede": "Cercul întreabă dacă un popor a fost atins. Inelele întreabă cât de departe este de cineva care l-ar putea atinge.",
|
||||
"sets_bounded_title": "Atinse și neatinse",
|
||||
"sets_centered_title": "Distanța față de un vecin",
|
||||
"sets_bounded_tally": "{inside} înăuntru · {outside} în afară · {unknown} necunoscut",
|
||||
"sets_centered_tally": "{placed} plasate · {centre} în centru · {unplaced} neplasate"
|
||||
},
|
||||
"ru": {
|
||||
"map_page_kicker": "НЕОХВАЧЕННЫЕ НАРОДЫ",
|
||||
|
|
@ -1647,7 +1696,14 @@
|
|||
"desc_gsec_3": "Менее 2% евангельских верующих, и среди них местами началось основание церквей.",
|
||||
"desc_gsec_4": "От 2% до 5% — евангельские верующие.",
|
||||
"desc_gsec_5": "От 5% до 10% — евангельские верующие.",
|
||||
"desc_gsec_6": "Более 10% — евангельские верующие."
|
||||
"desc_gsec_6": "Более 10% — евангельские верующие.",
|
||||
"sets_kicker": "Кто рядом, а кто нет",
|
||||
"sets_title": "Два взгляда на один народ",
|
||||
"sets_lede": "Круг спрашивает, достигнут ли народ. Кольца спрашивают, как далеко он от того, кто мог бы его достичь.",
|
||||
"sets_bounded_title": "Достигнутые и нет",
|
||||
"sets_centered_title": "Расстояние до соседа",
|
||||
"sets_bounded_tally": "{inside} внутри · {outside} снаружи · {unknown} неизвестно",
|
||||
"sets_centered_tally": "{placed} размещено · {centre} в центре · {unplaced} без места"
|
||||
},
|
||||
"ar": {
|
||||
"map_page_kicker": "شعوب غير مبلَّغة",
|
||||
|
|
@ -1853,7 +1909,14 @@
|
|||
"desc_gsec_3": "أقل من 2% إنجيليين، وقد بدأ زرع متفرق للكنائس بينهم.",
|
||||
"desc_gsec_4": "ما بين 2% و5% إنجيليون.",
|
||||
"desc_gsec_5": "ما بين 5% و10% إنجيليون.",
|
||||
"desc_gsec_6": "أكثر من 10% إنجيليون."
|
||||
"desc_gsec_6": "أكثر من 10% إنجيليون.",
|
||||
"sets_kicker": "من قريب ومن ليس كذلك",
|
||||
"sets_title": "طريقتان لرؤية الشعب نفسه",
|
||||
"sets_lede": "الدائرة تسأل إن كان الشعب قد وصلته البشارة. والحلقات تسأل كم يبعد عمّن يستطيع الوصول إليه.",
|
||||
"sets_bounded_title": "وصلتهم البشارة ومن لم تصلهم",
|
||||
"sets_centered_title": "المسافة إلى جار",
|
||||
"sets_bounded_tally": "{inside} في الداخل · {outside} في الخارج · {unknown} غير معروف",
|
||||
"sets_centered_tally": "{placed} موضوعون · {centre} في المركز · {unplaced} بلا موضع"
|
||||
},
|
||||
"hi": {
|
||||
"map_page_kicker": "अनछुए जनसमूह",
|
||||
|
|
@ -2057,7 +2120,14 @@
|
|||
"desc_gsec_3": "2% से कम सुसमाचारी, और उनके बीच छिटपुट कलीसिया स्थापना शुरू हो चुकी है।",
|
||||
"desc_gsec_4": "2% से 5% के बीच सुसमाचारी हैं।",
|
||||
"desc_gsec_5": "5% से 10% के बीच सुसमाचारी हैं।",
|
||||
"desc_gsec_6": "10% से अधिक सुसमाचारी हैं।"
|
||||
"desc_gsec_6": "10% से अधिक सुसमाचारी हैं।",
|
||||
"sets_kicker": "कौन निकट है और कौन नहीं",
|
||||
"sets_title": "एक ही जन को देखने के दो तरीके",
|
||||
"sets_lede": "वृत्त पूछता है कि क्या किसी जन तक सुसमाचार पहुँचा है। वलय पूछते हैं कि वे उस से कितनी दूर हैं जो उन तक पहुँच सकता है।",
|
||||
"sets_bounded_title": "पहुँचे और नहीं पहुँचे",
|
||||
"sets_centered_title": "पड़ोसी से दूरी",
|
||||
"sets_bounded_tally": "{inside} भीतर · {outside} बाहर · {unknown} अज्ञात",
|
||||
"sets_centered_tally": "{placed} स्थित · {centre} केंद्र में · {unplaced} अस्थित"
|
||||
},
|
||||
"zh": {
|
||||
"map_page_kicker": "未得之民",
|
||||
|
|
@ -2261,6 +2331,13 @@
|
|||
"desc_gsec_3": "福音派不足 2%,他们当中已零星开始植堂。",
|
||||
"desc_gsec_4": "福音派占 2% 至 5%。",
|
||||
"desc_gsec_5": "福音派占 5% 至 10%。",
|
||||
"desc_gsec_6": "福音派超过 10%。"
|
||||
"desc_gsec_6": "福音派超过 10%。",
|
||||
"sets_kicker": "谁在近处,谁不在",
|
||||
"sets_title": "看同一群人的两种方式",
|
||||
"sets_lede": "圆圈问的是这个族群是否已被福音触及。同心环问的是他们离能够触及他们的人有多远。",
|
||||
"sets_bounded_title": "已触及与未触及",
|
||||
"sets_centered_title": "与邻近族群的距离",
|
||||
"sets_bounded_tally": "{inside} 圈内 · {outside} 圈外 · {unknown} 未知",
|
||||
"sets_centered_tally": "{placed} 已定位 · {centre} 在中心 · {unplaced} 未定位"
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue