diff --git a/library/i18n/locales/ar/upgMap.json b/library/i18n/locales/ar/upgMap.json index bd77e9a42..53d106ba5 100644 --- a/library/i18n/locales/ar/upgMap.json +++ b/library/i18n/locales/ar/upgMap.json @@ -20,5 +20,5 @@ "wallHeading": "ملصقات UPG100", "wallIntroA": "كيف تُطعم جمعًا من خمسة آلاف؟ أجلسهم يسوع جماعاتٍ من خمسين ومن مئة، فصار المستحيل قابلًا للمشاركة (لوقا ٩:١٤). فعلنا المثل مع {n} شعوب غير مبلَّغة: ٢٧ قائمة من نحو خمسين إلى مئة. تُطبع كل قائمة حزمةَ صلاة وملصقًا، ليحمل ٢٧ تلميذًا أو كنيسة أو قائدًا محليًا كلٌّ واحدة — مصلّين لأجلهم ", "peopleStillLoading": "لا تزال الشعوب قيد التحميل، حاول مرة أخرى بعد لحظة", - "posterDesignTerritory": "ملصق منطقة UPG-100" + "posterDesignTerritory": "ملصق منطقة UPG100" } diff --git a/library/i18n/locales/de/upgMap.json b/library/i18n/locales/de/upgMap.json index c247491fe..4240cd3d1 100644 --- a/library/i18n/locales/de/upgMap.json +++ b/library/i18n/locales/de/upgMap.json @@ -20,5 +20,5 @@ "wallHeading": "UPG100-Poster", "wallIntroA": "Wie würden Sie eine Menge von fünftausend speisen? Jesus ließ sie in Gruppen zu fünfzig und hundert lagern, und das Unmögliche wurde teilbar (Lukas 9,14). Dasselbe haben wir mit den {n} unerreichten Volksgruppen getan: 27 Listen von etwa fünfzig bis hundert. Jede Liste druckt als Gebetspaket und als Poster, damit 27 Jünger, Gemeinden oder einheimische Leiter je eine tragen können — und für sie beten ", "peopleStillLoading": "die Volksgruppen werden noch geladen; versuchen Sie es gleich noch einmal", - "posterDesignTerritory": "UPG-100-Gebietsplakat" + "posterDesignTerritory": "UPG100-Gebietsplakat" } diff --git a/library/i18n/locales/en/upgMap.json b/library/i18n/locales/en/upgMap.json index 916e5e21e..7364a6190 100644 --- a/library/i18n/locales/en/upgMap.json +++ b/library/i18n/locales/en/upgMap.json @@ -20,5 +20,5 @@ "wallHeading": "UPG100 Posters", "wallIntroA": "How would you feed a crowd of five thousand? Jesus sat them down in groups of fifty and a hundred, and the impossible became shareable (Luke 9:14). We did the same with the {n} unreached people groups: 27 lists of about fifty to a hundred. Each list prints as a prayer packet and a poster, so 27 disciples, churches or local leaders can each carry one — praying for them ", "peopleStillLoading": "the people groups are still loading, try again in a moment", - "posterDesignTerritory": "UPG-100 territory poster" + "posterDesignTerritory": "UPG100 zone poster" } diff --git a/library/i18n/locales/es/upgMap.json b/library/i18n/locales/es/upgMap.json index da700b62f..794d3f36f 100644 --- a/library/i18n/locales/es/upgMap.json +++ b/library/i18n/locales/es/upgMap.json @@ -20,5 +20,5 @@ "wallHeading": "Carteles UPG100", "wallIntroA": "¿Cómo alimentarías a una multitud de cinco mil? Jesús los sentó en grupos de cincuenta y de cien, y lo imposible se volvió compartible (Lucas 9:14). Hicimos lo mismo con los {n} pueblos no alcanzados: 27 listas de unos cincuenta a cien. Cada lista se imprime como paquete de oración y cartel, para que 27 discípulos, iglesias o líderes locales lleven una cada uno — orando por ellos ", "peopleStillLoading": "los pueblos aún se están cargando; inténtalo de nuevo en un momento", - "posterDesignTerritory": "Cartel de territorio UPG-100" + "posterDesignTerritory": "Cartel de zona UPG100" } diff --git a/library/i18n/locales/fr/upgMap.json b/library/i18n/locales/fr/upgMap.json index 06bd814ca..937900fa5 100644 --- a/library/i18n/locales/fr/upgMap.json +++ b/library/i18n/locales/fr/upgMap.json @@ -20,5 +20,5 @@ "wallHeading": "Affiches UPG100", "wallIntroA": "Comment nourririez-vous une foule de cinq mille personnes ? Jésus les a fait asseoir par groupes de cinquante et de cent, et l’impossible est devenu partageable (Luc 9.14). Nous avons fait de même avec les {n} peuples non atteints : 27 listes d’environ cinquante à cent. Chaque liste s’imprime en dossier de prière et en affiche, pour que 27 disciples, Églises ou responsables locaux en portent chacun une — en priant pour eux ", "peopleStillLoading": "les peuples sont encore en cours de chargement ; réessayez dans un instant", - "posterDesignTerritory": "Affiche de territoire UPG-100" + "posterDesignTerritory": "Affiche de zone UPG100" } diff --git a/library/i18n/locales/hi/upgMap.json b/library/i18n/locales/hi/upgMap.json index d96462b7c..4eb1cfafd 100644 --- a/library/i18n/locales/hi/upgMap.json +++ b/library/i18n/locales/hi/upgMap.json @@ -20,5 +20,5 @@ "wallHeading": "UPG100 पोस्टर", "wallIntroA": "पाँच हज़ार की भीड़ को आप कैसे खिलाते? यीशु ने उन्हें पचास-पचास और सौ-सौ के समूहों में बिठाया, और असंभव बाँटने योग्य हो गया (लूका 9:14). हमने {n} अनपहुँचे जनसमूहों के साथ वही किया: लगभग पचास से सौ तक की 27 सूचियाँ. हर सूची प्रार्थना पैकेट और पोस्टर के रूप में छपती है, ताकि 27 शिष्य, कलीसियाएँ या स्थानीय अगुवे एक-एक ले सकें — उनके लिए प्रार्थना करते हुए ", "peopleStillLoading": "जनसमूह अभी लोड हो रहे हैं, थोड़ी देर में फिर कोशिश करें", - "posterDesignTerritory": "UPG-100 क्षेत्र पोस्टर" + "posterDesignTerritory": "UPG100 क्षेत्र का पोस्टर" } diff --git a/library/i18n/locales/it/upgMap.json b/library/i18n/locales/it/upgMap.json index c9f8d025e..6c9a47d53 100644 --- a/library/i18n/locales/it/upgMap.json +++ b/library/i18n/locales/it/upgMap.json @@ -20,5 +20,5 @@ "wallHeading": "Poster UPG100", "wallIntroA": "Come sfameresti una folla di cinquemila? Gesù li fece sedere a gruppi di cinquanta e di cento, e l’impossibile divenne condivisibile (Luca 9:14). Abbiamo fatto lo stesso con i {n} popoli non raggiunti: 27 liste di circa cinquanta-cento. Ogni lista si stampa come pacchetto di preghiera e manifesto, così 27 discepoli, chiese o responsabili locali ne portano una ciascuno — pregando per loro ", "peopleStillLoading": "i popoli si stanno ancora caricando; riprova tra un momento", - "posterDesignTerritory": "Manifesto di territorio UPG-100" + "posterDesignTerritory": "Poster di zona UPG100" } diff --git a/library/i18n/locales/pt/upgMap.json b/library/i18n/locales/pt/upgMap.json index 9cffd9585..7a1a7b2cf 100644 --- a/library/i18n/locales/pt/upgMap.json +++ b/library/i18n/locales/pt/upgMap.json @@ -20,5 +20,5 @@ "wallHeading": "Cartazes UPG100", "wallIntroA": "Como você alimentaria uma multidão de cinco mil? Jesus os sentou em grupos de cinquenta e de cem, e o impossível tornou-se compartilhável (Lucas 9.14). Fizemos o mesmo com os {n} povos não alcançados: 27 listas de cerca de cinquenta a cem. Cada lista imprime como pacote de oração e cartaz, para que 27 discípulos, igrejas ou líderes locais levem uma cada um — orando por eles ", "peopleStillLoading": "os povos ainda estão carregando; tente de novo em um instante", - "posterDesignTerritory": "Cartaz de território UPG-100" + "posterDesignTerritory": "Cartaz de zona UPG100" } diff --git a/library/i18n/locales/ro/upgMap.json b/library/i18n/locales/ro/upgMap.json index 331a40a1e..056cdb3ad 100644 --- a/library/i18n/locales/ro/upgMap.json +++ b/library/i18n/locales/ro/upgMap.json @@ -20,5 +20,5 @@ "wallHeading": "Afișe UPG100", "wallIntroA": "Cum ai hrăni o mulțime de cinci mii? Isus i-a așezat în grupuri de cincizeci și de o sută, iar imposibilul a devenit împărțibil (Luca 9:14). Am făcut la fel cu cele {n} popoare neatinse: 27 de liste de aproximativ cincizeci până la o sută. Fiecare listă se tipărește ca pachet de rugăciune și afiș, ca 27 de ucenici, biserici sau lideri locali să poarte fiecare câte una — rugându-se pentru ei ", "peopleStillLoading": "popoarele încă se încarcă; încearcă din nou peste o clipă", - "posterDesignTerritory": "Afiș de teritoriu UPG-100" + "posterDesignTerritory": "Poster de zonă UPG100" } diff --git a/library/i18n/locales/ru/upgMap.json b/library/i18n/locales/ru/upgMap.json index 3e91bde32..ffaa2788c 100644 --- a/library/i18n/locales/ru/upgMap.json +++ b/library/i18n/locales/ru/upgMap.json @@ -20,5 +20,5 @@ "wallHeading": "Плакаты UPG100", "wallIntroA": "Как накормить толпу в пять тысяч человек? Иисус рассадил их группами по пятьдесят и по сто, и невозможное стало посильным (Лк. 9:14). Мы поступили так же с {n} неохваченными народами: 27 списков примерно по пятьдесят-сто. Каждый список печатается как молитвенный пакет и плакат, чтобы 27 учеников, церквей или местных служителей взяли по одному — молясь о них ", "peopleStillLoading": "народы ещё загружаются; попробуйте ещё раз через мгновение", - "posterDesignTerritory": "Плакат территории UPG-100" + "posterDesignTerritory": "Плакат зоны UPG100" } diff --git a/library/i18n/locales/zh/upgMap.json b/library/i18n/locales/zh/upgMap.json index 326f50cdb..ce9f431d5 100644 --- a/library/i18n/locales/zh/upgMap.json +++ b/library/i18n/locales/zh/upgMap.json @@ -20,5 +20,5 @@ "wallHeading": "UPG100 海报", "wallIntroA": "你会怎样喂饱五千人的群众?耶稣让他们一排五十、一排一百地坐下,不可能的事就变得可以分担了(路加福音 9:14)。我们对 {n} 个未得之民做了同样的事:27 份名单,每份约五十到一百。每份名单都能印成祷告手册和海报,让 27 位门徒、教会或当地领袖各领一份 — 为他们祷告 ", "peopleStillLoading": "族群仍在加载中,请稍后再试", - "posterDesignTerritory": "UPG-100 区域海报" + "posterDesignTerritory": "UPG100 区域海报(单张)" } diff --git a/library/packet/poster-render.js b/library/packet/poster-render.js index 7b0871815..25b7a95a7 100644 --- a/library/packet/poster-render.js +++ b/library/packet/poster-render.js @@ -290,6 +290,7 @@ const HEAD_COLUMNS_CSS = ` const HEAD_COLUMNS_FULL_CSS = ` .hcolk{font-size:19px;fill:#2f2a22;font-weight:800;letter-spacing:.1em} .hcolt{font-size:22px;fill:#3a362c} + .hcolb{font-weight:700;fill:#2f2a22} .hcolh{font-family:Georgia,'Times New Roman',serif;font-size:23px;font-weight:700;fill:#2f2a22;letter-spacing:.04em;font-variant:small-caps} .hvref{font-size:19px} .hverse{font-size:19.5px} @@ -851,6 +852,27 @@ const strategyParas = () => (POSTER_TEXT.strategyBody ? [].concat(POSTER_TEXT.st // series.json (poster.sideBoxMore: one paragraph, or a list; [] prints none), as UPG100 does to keep its band even. const whatIsMore = () => (POSTER_TEXT.sideBoxMore !== undefined ? [].concat(POSTER_TEXT.sideBoxMore) : [WHAT_IS_MORE]); const WHAT_IS_MORE = 'Each map comes with a prayer list of its fifty to a hundred people groups — their names, a representative photo, and more detail — to mobilise informed intercession.'; +// A paragraph's lines as SVG text content, its **...** runs set bold (.hcolb); the markers are not printed. +// The wrap measures the plain text: a short bold run is a few px wider, inside the measure's room. +function boldLines(text, width) { + let plain = '', bold = [], on = false; + for (const part of String(text).replace(/\s+/g, ' ').trim().split('**')) { + for (let i = 0; i < part.length; i++) { plain += part[i]; bold.push(on); } // per UTF-16 unit, as plain[p] reads + on = !on; + } + let p = 0; + return wrapPx(plain, HC.fs, width).map((ln) => { + while (plain[p] === ' ') p++; + let out = '', run = '', runBold = null; + const flush = () => { if (run) out += runBold ? `${esc(run)}` : esc(run); run = ''; }; + for (let k = 0; k < ln.length; k++, p++) { + if (bold[p] !== runBold) { flush(); runBold = bold[p]; } + run += plain[p]; + } + flush(); + return out; + }); +} function headColumnsBand(top, facts, approxLists) { const GRID_L = BAND_MARGIN_G, GRID_W = PW - 2 * BAND_MARGIN_G; const CW = (GRID_W - 2 * HC.gut) / 3; @@ -885,14 +907,16 @@ function headColumnsBand(top, facts, approxLists) { bottom = Math.max(bottom, y); } else { const { head, paras } = col[0]; - const wrapped = paras.map((t) => wrapPx(t, HC.fs, TW)); - const blockW = Math.min(TW, Math.max(textW(head, HC.headFs), ...wrapped.flat().map((ln) => textW(ln, HC.fs)))); + // ★ MIRRORED (2026-10-03): both prose columns take the full measure, so each sits the same distance from + // its rule and the two outer columns mirror each other round the centred facts column. (Each used to be + // centred on its own widest line, so the two could sit at different distances from their rules.) + const blockW = TW; const x = (centre - blockW * HC_FALLBACK / 2).toFixed(1); frags += `${esc(head)}`; let y = top + HC.headLh; - wrapped.forEach((lines, k) => { + paras.forEach((text, k) => { if (k) y += HC.gap; - for (const ln of lines) { frags += `${esc(ln)}`; y += HC.lh; } + for (const ln of boldLines(text, TW)) { frags += `${ln}`; y += HC.lh; } }); bottom = Math.max(bottom, y); } diff --git a/library/scripts/posters/series.json b/library/scripts/posters/series.json index 21c598936..cbdb05c85 100644 --- a/library/scripts/posters/series.json +++ b/library/scripts/posters/series.json @@ -29,7 +29,7 @@ "titleQualifier": "the coloured words before the region name, e.g. 'Unengaged of' (:2427)", "seriesName": "the name in quotes on the Series line and in the side box (:1877, :1907, :2115)", "sideBoxHeading": "the right-hand explainer's heading (:2097)", - "sideBoxBody": "that explainer's first paragraph (:2115)", + "sideBoxBody": "that explainer's first paragraph (:2115); in the head-columns band **...** prints a bold run", "strategyBody": "the Jesus column's text: one paragraph, or a list of them; absent = poster-render's STRATEGY_DEFAULT", "sideBoxMore": "the explainer's further paragraphs: one, or a list; [] prints none; absent = poster-render's WHAT_IS_MORE" }, @@ -68,8 +68,8 @@ "titleQualifier": "Unengaged of", "seriesName": "UPG100 List", "sideBoxHeading": "What is a UPG100 List?", - "sideBoxBody": "This map is one of a {approxLists}-map set called the {seriesName} — a large, overwhelming target in the thousands, organised into clear groupings and displayed on maps and prayer lists.", - "strategyBody": "Jesus fed the 5,000 by multiplying a small offering. He had the crowd sit in groups of hundreds and fifties (Mark 6:40). So we pray by name, a few groups at a time.", + "sideBoxBody": "This map is one of a {approxLists}-map set called the {seriesName} — a large, overwhelming target in the thousands, organised into clear groupings and displayed on maps and prayer lists. Each map comes with a prayer list of its fifty to a hundred people groups — their names, a representative photo, and more detail — to mobilise **informed intercession.**", + "strategyBody": "2000 People Groups? Jesus’ disciples were faced with a similar problem, “How can we feed so many with only five loaves and two fish?” Through radical faith and miracle-expectant prayer, He focused on the few in front of Him — dividing the crowd and entrusting faithful men and women to serve the most strategic groups of fifties and hundreds (Mark 6:40).", "sideBoxMore": [], "headColumns": true },