Merge remote-tracking branch 'origin/development' into reg-post/bless-india-posters
# Conflicts: # public/dx-maps/bless-india-posters/bless-india-posters.js # public/dx-maps/bless-india-posters/bless-india-posters/index.html # public/dx-maps/doxa-maps-spa/manifest.json # public/dx-maps/manifest.json
42
README.md
|
|
@ -26,7 +26,7 @@ Made by Vibe Coders for Vibe Coders to prepare the way of the Lord and make His
|
|||
relational-stewardship training (bounded and centered sets).
|
||||
- **What each map is for:**
|
||||
- **Big Picture:** the library's own interface, the one agents use to build maps.
|
||||
- **UPG-100:** the most strategic. It divides the task into prayer packets.
|
||||
- **UPG100 List:** the most strategic. It divides the task into prayer packets.
|
||||
- **Gospel maps:** the resources that exist in each language.
|
||||
- **UPG Neighbor:** the reached neighbors near each unreached group.
|
||||
- **Gospel × Internet:** all of it, together. Built for linguists, catalysts, translators (human
|
||||
|
|
@ -37,7 +37,7 @@ Built with love, with the prayer that these maps bless the nations.
|
|||
**A blessing for you.** These maps and posters are given to bless the people who bless the nations.
|
||||
We love you, and we are thankful for your work. We bless you in Jesus' name.
|
||||
|
||||
Every poster is in Posterverse (`plugin-designs/posterverse/`): the UPG 100 List, Country Posters,
|
||||
Every poster is in Posterverse (`plugin-designs/posterverse/`): UPG100 Posters, Country Posters,
|
||||
Poster Design and Wall of People Groups. They are all in the Plugin Studio (`bun run dev`) too.
|
||||
|
||||
# dx-maps — one build, maps that embed everywhere
|
||||
|
|
@ -119,7 +119,7 @@ people groups of the world. When you work here, the goal is one of these:
|
|||
| **Reach a city** | Regions (`regions-dashboard`) and the country map (`country-map`): the people groups of each country. The production maps work by country and region; city-level planning (Prayer Walk Planner) is still experimental |
|
||||
| **Mobilize for people groups** | Big Picture (`dashboard-plus-grid`); Simple Research (`research-map-plus-grid`) |
|
||||
| **Plan outreach** | Gospel Resources (`gospel-resources`): what exists in each language; Cities with Internet (`cities-internet`): whether a group can be reached online |
|
||||
| **Pray: packets and prayer resources** | UPG 100 List (`my-upg-100-list`), Regions and Simple Research: posters and prayer packets; Prayer Progress (`doxa-simple-map`) |
|
||||
| **Pray: packets and prayer resources** | UPG100 Posters (`my-upg-100-list`), Regions and Simple Research: posters and prayer packets; Prayer Progress (`doxa-simple-map`) |
|
||||
|
||||
- **Start with the skill:** [`skills/plugin-designer`](./skills/plugin-designer) teaches the patterns, the shared
|
||||
library and the checks.
|
||||
|
|
@ -149,7 +149,7 @@ the Research Gallery, which DX Life publishes as **Deep Research**. An eighth pr
|
|||
<td width="25%" valign="top"><img src="documentation/readme-images/cap2-prayer.png" alt="Prayer Progress"><br><b>Prayer Progress</b><br><sub>where prayer is happening, and where it is still needed</sub></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td width="25%" valign="top"><img src="documentation/readme-images/cap4-upg100-mfe.png" alt="UPG-100 List"><br><b>UPG-100 List</b><br><sub>prayer lists of 100 people groups, with posters to print</sub></td>
|
||||
<td width="25%" valign="top"><img src="documentation/readme-images/cap4-upg100-mfe.png" alt="UPG100 Posters"><br><b>UPG100 Posters</b><br><sub>prayer lists of 100 people groups, with posters to print</sub></td>
|
||||
<td width="25%" valign="top"><img src="documentation/readme-images/prod-cities-internet.png" alt="Cities with Internet"><br><b>Cities with Internet</b><br><sub>internet access where unreached people groups live</sub></td>
|
||||
<td width="25%" valign="top"><img src="documentation/readme-images/prod-gospel-resources.png" alt="Gospel Resources"><br><b>Gospel Resources</b><br><sub>which people groups have scripture, film or audio — and which have nothing</sub></td>
|
||||
<td width="25%" valign="top"><img src="documentation/readme-images/cap5-doxa-maps-spa.png" alt="Research Gallery"><br><b>Research Gallery</b><br><sub>all seven in one app — capability 5</sub></td>
|
||||
|
|
@ -163,7 +163,7 @@ the Research Gallery, which DX Life publishes as **Deep Research**. An eighth pr
|
|||
<td width="25%" valign="top"><img src="documentation/readme-images/prod-simple-research-phone.png" alt="Simple Research on a phone"><br><b>Simple Research</b></td>
|
||||
<td width="25%" valign="top"><img src="documentation/readme-images/prod-regions-phone.png" alt="Regions on a phone"><br><b>Regions</b></td>
|
||||
<td width="25%" valign="top"><img src="documentation/readme-images/prod-prayer-phone.png" alt="Prayer Progress on a phone"><br><b>Prayer Progress</b></td>
|
||||
<td width="25%" valign="top"><img src="documentation/readme-images/deploy2-mobile-upg100.png" alt="UPG-100 List on a phone"><br><b>UPG-100 List</b></td>
|
||||
<td width="25%" valign="top"><img src="documentation/readme-images/deploy2-mobile-upg100.png" alt="UPG100 Posters on a phone"><br><b>UPG100 Posters</b></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td width="25%" valign="top"><img src="documentation/readme-images/prod-cities-internet-phone.png" alt="Cities with Internet on a phone"><br><b>Cities with Internet</b></td>
|
||||
|
|
@ -175,11 +175,11 @@ the Research Gallery, which DX Life publishes as **Deep Research**. An eighth pr
|
|||
|
||||
### Print your first poster
|
||||
|
||||
1. **Open a poster wall:** *UPG-100 List*, *Country Posters*, or *Regions* (its **View country posters**
|
||||
1. **Open a poster wall:** *UPG100 Posters*, *Country Posters*, or *Regions* (its **View country posters**
|
||||
button). Every card on the wall has a **Print Options** strip. India's whole-country poster isn't
|
||||
available yet; its state posters are.
|
||||
2. **Pick what to print:** **Poster Map** (the poster), **Prayer List** (choose **Full detail** or
|
||||
**Lightweight**) or **Card Deck** (choose a card size). On *UPG-100 List*, clicking the poster
|
||||
**Lightweight**) or **Card Deck** (choose a card size). On *UPG100 Posters*, clicking the poster
|
||||
picture prints it too.
|
||||
3. **Your browser's print window opens, and it is the preview.** Choose the printer and print. Nothing
|
||||
is downloaded; to keep a file, choose **Save as PDF** instead of a printer.
|
||||
|
|
@ -195,14 +195,14 @@ numbered (1 / 3, 2 / 3 …) and marked **glue here** where the next one goes.
|
|||
**On a phone.** The same print window rises over the page; choose **Save as PDF** to keep the file or
|
||||
send it on. A phone prints page sizes only (Letter or A4 paper), and the largest poster sizes are
|
||||
switched off there. A few prints say they need a computer: *Bless India Posters*, the *Wall of People
|
||||
Groups* and a UPG-100 selection of more than 1,000 groups.
|
||||
Groups* and a selection of more than 1,000 groups on *UPG100 Posters*.
|
||||
|
||||
### Every capability ships every way
|
||||
|
||||
| Capability | Example | iframe | Mobile app | JavaScript embed | WordPress / Disciple Tools | Desktop |
|
||||
|---|---|:-:|:-:|:-:|:-:|:-:|
|
||||
| **5 — app shell** | Research Gallery | ✅ | ✅ | ✅ | 🧪 | ✅ |
|
||||
| **4 — composite** | UPG-100 List | ✅ | ✅ | ✅ | 🧪 | ✅ |
|
||||
| **4 — composite** | UPG100 Posters | ✅ | ✅ | ✅ | 🧪 | ✅ |
|
||||
| **3 — multi-view** | research map | ✅ | ✅ | ✅ | 🧪 | ✅ |
|
||||
| **2 — presets** | Prayer Progress | ✅ | ✅ | ✅ | 🧪 | ✅ |
|
||||
| **1 — single element** | all people groups | ✅ | ✅ | ✅ | 🧪 | ✅ |
|
||||
|
|
@ -275,8 +275,8 @@ embed just the one you need.
|
|||
|---|---|---|
|
||||
| a **translator** (or an AI translation pipeline) | Gospel Resources (map, list, data tables) | which people groups have no Scripture, film or audio in their language, and which bridge language already reaches them |
|
||||
| **media to movements** | Cities with Internet · Gospel × Internet | where unreached people groups live with internet access, country by country and down to province where data exists |
|
||||
| a **catalyst** or mobilizer | Big Picture · Prayer Walk Planner · UPG 100 List · Gospel × Internet | find **gospel resources** for the people you are reaching real time, build prayer walking maps for real outreach, as you prayer walk each key zone in your cities of choice, find indigenous disciples, groups, and leaders mobilize them each to have prayer packets, cards and posters to blanket all the people groups in prayer as a prayer mobilizer catalyst |
|
||||
| **praying** | Prayer Progress · UPG-100 List | where prayer is covered and where it is still needed; print a **Prayer List**, **Poster Map** or **Card Deck** for a list of 100 |
|
||||
| a **catalyst** or mobilizer | Big Picture · Prayer Walk Planner · UPG100 Posters · Gospel × Internet | find **gospel resources** for the people you are reaching real time, build prayer walking maps for real outreach, as you prayer walk each key zone in your cities of choice, find indigenous disciples, groups, and leaders mobilize them each to have prayer packets, cards and posters to blanket all the people groups in prayer as a prayer mobilizer catalyst |
|
||||
| **praying** | Prayer Progress · UPG100 Posters | where prayer is covered and where it is still needed; print a **Prayer List**, **Poster Map** or **Card Deck** for a list of 100 |
|
||||
| a **teacher** or presenter | the Research Gallery | every map in one app, multiple languages support |
|
||||
|
||||
<details>
|
||||
|
|
@ -341,8 +341,8 @@ Research Gallery <doxa-maps-spa> capability 5
|
|||
│ ├─ regions list regions-list capability 1
|
||||
│ └─ region dashboards region-dashboards capability 1
|
||||
├─ Prayer Mobilization
|
||||
│ ├─ UPG-100 List upg-100-mfe capability 4
|
||||
│ │ ├─ list upg-100-list capability 1
|
||||
│ ├─ UPG100 Posters upg-100-mfe capability 4
|
||||
│ │ ├─ zoned map upg-100-list capability 1
|
||||
│ │ └─ poster wall poster-wall capability 1
|
||||
│ └─ Prayer Progress doxa-simple-map capability 2
|
||||
├─ Gospel Research
|
||||
|
|
@ -364,11 +364,11 @@ Research Gallery <doxa-maps-spa> capability 5
|
|||
|
||||
**Several plugins glued into one**, talking to each other — and each piece still embeddable alone.
|
||||
|
||||

|
||||

|
||||
|
||||
| List (capability 1, embeddable alone) | Poster wall (capability 1, embeddable alone) |
|
||||
|---|---|
|
||||
|  |  |
|
||||
|  |  |
|
||||
|
||||
<details>
|
||||
<summary><b>More about capability 4 — composites</b></summary>
|
||||
|
|
@ -378,7 +378,7 @@ as views you switch between — and ships the set as **one new element**. The pi
|
|||
**props** (settings passed in) and **events** (messages sent out): click a region in one piece and
|
||||
another piece updates. Nothing is copied, so each piece can still be embedded on its own.
|
||||
|
||||
- **Example:** `plugin-designs/my-upg-100-list/` — the UPG-100 list and its poster wall, joined into
|
||||
- **Example:** `plugin-designs/my-upg-100-list/` — the UPG100 Posters zoned map and its poster wall, joined into
|
||||
`upg-100-mfe`. Big Picture, Simple Research and Regions are composites too.
|
||||
- **How to declare one:** a `<name>.meta.json` beside it with `"type": "nested-elements-mfe"` and a
|
||||
`"composes"` list of the plugins inside.
|
||||
|
|
@ -596,13 +596,13 @@ installed.
|
|||
**The same maps, wrapped as a phone app.** No new code — the maps are JAMstack: they fetch their data
|
||||
from a remote API, which is exactly what a mobile app needs.
|
||||
|
||||
<p align="center"><img src="documentation/readme-images/deploy2-mobile-upg100.png" alt="Mobile app — the UPG-100 list at phone size" width="320"></p>
|
||||
<p align="center"><img src="documentation/readme-images/deploy2-mobile-upg100.png" alt="Mobile app — UPG100 Posters at phone size" width="320"></p>
|
||||
|
||||
<details>
|
||||
<summary><b>More about the mobile app</b></summary>
|
||||
|
||||
[Capacitor](https://capacitorjs.com) wraps the built folder into an Android app. Shown here: the
|
||||
UPG-100 prayer lists and posters at phone size, each poster with its own print options.
|
||||
UPG100 prayer lists and posters at phone size, each poster with its own print options.
|
||||
|
||||
```bash
|
||||
bun run check:mobile # checks the app is wired up correctly — needs no Android tools
|
||||
|
|
@ -679,9 +679,9 @@ with the bundle. `bun run check:sri` keeps the manifest and the built pages in s
|
|||
**Every map speaks 11 languages** — add `?lang=<code>` to a map's page address, or, when a map is embedded in
|
||||
your own page, set `"locale"` in its `profile-config`. Arabic reads right to left.
|
||||
|
||||

|
||||

|
||||
|
||||
<sub>UPG-100 List with `?lang=ar`: the interface is in Arabic; people-group and place names come from the data.</sub>
|
||||
<sub>UPG100 Posters with `?lang=ar`: the interface is in Arabic; people-group and place names come from the data.</sub>
|
||||
|
||||
| Code | Language | | Code | Language |
|
||||
|---|---|---|---|---|
|
||||
|
|
@ -966,7 +966,7 @@ doxa-maps/
|
|||
├── plugin-designs/ YOUR maps — one folder per plugin (the free zone)
|
||||
│ ├── doxa-maps-spa/ the Research Gallery (capability 5)
|
||||
│ ├── plugin-studio/ the Plugin Studio (capability 5)
|
||||
│ ├── my-upg-100-list/ UPG-100 List (capability 4)
|
||||
│ ├── my-upg-100-list/ UPG100 Posters (capability 4)
|
||||
│ ├── doxa-simple-map/ Prayer Progress and its presets (capability 2)
|
||||
│ ├── all-people-groups/ a single map (capability 1)
|
||||
│ └── template-bundle/ copy this to start a new plugin
|
||||
|
|
|
|||
|
Before Width: | Height: | Size: 217 KiB After Width: | Height: | Size: 222 KiB |
|
Before Width: | Height: | Size: 184 KiB After Width: | Height: | Size: 187 KiB |
|
Before Width: | Height: | Size: 235 KiB After Width: | Height: | Size: 249 KiB |
|
Before Width: | Height: | Size: 230 KiB After Width: | Height: | Size: 244 KiB |
|
Before Width: | Height: | Size: 216 KiB After Width: | Height: | Size: 224 KiB |
|
Before Width: | Height: | Size: 220 KiB After Width: | Height: | Size: 230 KiB |
|
Before Width: | Height: | Size: 232 KiB After Width: | Height: | Size: 231 KiB |
|
Before Width: | Height: | Size: 219 KiB After Width: | Height: | Size: 236 KiB |
|
Before Width: | Height: | Size: 219 KiB After Width: | Height: | Size: 235 KiB |
|
Before Width: | Height: | Size: 240 KiB After Width: | Height: | Size: 257 KiB |
|
Before Width: | Height: | Size: 219 KiB After Width: | Height: | Size: 230 KiB |
|
Before Width: | Height: | Size: 223 KiB After Width: | Height: | Size: 240 KiB |
|
Before Width: | Height: | Size: 224 KiB After Width: | Height: | Size: 238 KiB |
|
Before Width: | Height: | Size: 238 KiB After Width: | Height: | Size: 242 KiB |
|
Before Width: | Height: | Size: 197 KiB After Width: | Height: | Size: 211 KiB |
|
Before Width: | Height: | Size: 174 KiB After Width: | Height: | Size: 264 KiB |
|
Before Width: | Height: | Size: 220 KiB After Width: | Height: | Size: 238 KiB |
|
Before Width: | Height: | Size: 213 KiB After Width: | Height: | Size: 172 KiB |
|
Before Width: | Height: | Size: 213 KiB After Width: | Height: | Size: 231 KiB |
|
Before Width: | Height: | Size: 192 KiB After Width: | Height: | Size: 191 KiB |
|
Before Width: | Height: | Size: 189 KiB After Width: | Height: | Size: 200 KiB |
|
Before Width: | Height: | Size: 162 KiB After Width: | Height: | Size: 220 KiB |
|
Before Width: | Height: | Size: 184 KiB After Width: | Height: | Size: 207 KiB |
|
Before Width: | Height: | Size: 166 KiB After Width: | Height: | Size: 174 KiB |
|
Before Width: | Height: | Size: 226 KiB After Width: | Height: | Size: 233 KiB |
|
Before Width: | Height: | Size: 197 KiB After Width: | Height: | Size: 207 KiB |
|
Before Width: | Height: | Size: 106 KiB After Width: | Height: | Size: 100 KiB |
|
Before Width: | Height: | Size: 236 KiB After Width: | Height: | Size: 246 KiB |
|
|
@ -1,4 +1,4 @@
|
|||
# Architecture — UPG-100 poster generation
|
||||
# Architecture — UPG100 List poster generation
|
||||
|
||||
> The simple overview is in `library/scripts/posters/README.md`. This is the full reference for the
|
||||
> generator: files, environment, pipeline, and the gotchas that have bitten before.
|
||||
|
|
@ -53,7 +53,7 @@ the app is rebuilt.**
|
|||
| `VITE_API_BASE_URL` | — | Satisfies the fail-closed config gate. No request is made under `OFFLINE=1`. |
|
||||
| `ONLY` | — | Build a single zone by `zoneKey`. |
|
||||
| `UPG100_DATA_PATH` | the profile in this repo | Only override to test against other data. |
|
||||
| `SERIES_INDEX` / `SERIES_NAME` | derived / `List of 100 UPG's` | Series line on the sheet. |
|
||||
| `SERIES_INDEX` / `SERIES_NAME` | derived / `UPG100 List` | Series line on the sheet. |
|
||||
|
||||
## Two things that will bite you
|
||||
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ Deep Research is the plugin that is already a whole app. It is the app shell in
|
|||
- Simple Research;
|
||||
- Regions;
|
||||
- Prayer Progress;
|
||||
- UPG-100 List;
|
||||
- UPG100 Posters;
|
||||
- Cities with Internet;
|
||||
- Gospel Resources.
|
||||
|
||||
|
|
@ -95,7 +95,7 @@ It is the same command with another start page. Name the page's folder inside `p
|
|||
|
||||
```bash
|
||||
APP_START=doxa-simple-map/doxa-simple-map bun run phone:from-tree # Prayer Progress
|
||||
bun run phone:from-tree # unset: the UPG-100 list
|
||||
bun run phone:from-tree # unset: UPG100 Posters
|
||||
```
|
||||
|
||||
Pick a page that works on a phone; Big Picture, for one, is desktop only. The start-page step
|
||||
|
|
|
|||
|
|
@ -237,7 +237,7 @@ snippets (leave it empty for relative URLs that work wherever the folder is drop
|
|||
## Hosting the dx-maps folder: caching, compression, CORS
|
||||
|
||||
**Why it matters.** On a cold load a map's layers draw about 10–17 s after the page opens (measured
|
||||
on the UPG-100 list page). The bundle and the map engine take under 2 s of that; the rest is basemap
|
||||
on the UPG100 Posters page). The bundle and the map engine take under 2 s of that; the rest is basemap
|
||||
tiles and data files such as the country-boundary file (1,866 KB raw, 597 KB gzipped). Compression
|
||||
cuts every visit; caching means a returning reader doesn't download the same files again.
|
||||
|
||||
|
|
|
|||
|
Before Width: | Height: | Size: 926 KiB After Width: | Height: | Size: 926 KiB |
|
|
@ -72,8 +72,8 @@
|
|||
<line x1="862.1" y1="1120.7" x2="822.7" y2="1025.5" stroke="#15803d" stroke-width="1.4" opacity=".45"/>
|
||||
<line x1="940.6" y1="1310.1" x2="912.3" y2="1241.7" stroke="#2563eb" stroke-width="2.4" marker-end="url(#aA)"/>
|
||||
<circle cx="885.9" cy="1178.0" r="62" fill="#f0fdf4" stroke="#15803d" stroke-width="2.6"/>
|
||||
<text x="885.9" y="1168.0" text-anchor="middle" font-size="14" font-weight="800" fill="#14532d">UPG-100</text>
|
||||
<text x="885.9" y="1185.0" text-anchor="middle" font-size="14" font-weight="800" fill="#14532d">List</text>
|
||||
<text x="885.9" y="1168.0" text-anchor="middle" font-size="14" font-weight="800" fill="#14532d">UPG100</text>
|
||||
<text x="885.9" y="1185.0" text-anchor="middle" font-size="14" font-weight="800" fill="#14532d">Posters</text>
|
||||
<rect x="859.9" y="1193.0" width="52" height="20" rx="10" fill="#15803d"/>
|
||||
<text x="885.9" y="1208.0" text-anchor="middle" font-size="11.5" font-weight="800" fill="#fff">cap 4</text>
|
||||
<circle cx="956.6" cy="1348.9" r="40" fill="#eff6ff" stroke="#2563eb" stroke-width="2.5"/>
|
||||
|
|
|
|||
|
Before Width: | Height: | Size: 20 KiB After Width: | Height: | Size: 20 KiB |
|
|
@ -57,7 +57,6 @@ Generated from 30 bundle(s).
|
|||
| `poster-design` | `poster-sizes` | `single` |
|
||||
| `poster-design` | `poster-styles` | `single` |
|
||||
| `prayer-walk-planner` | `prayer-walk-planner` | `single` |
|
||||
| `regions-dashboard` | `country-poster-sections` | `single` |
|
||||
| `regions-dashboard` | `region-dashboards` | `single` |
|
||||
| `regions-dashboard` | `regions-list` | `single` |
|
||||
|
||||
|
|
|
|||
|
|
@ -347,7 +347,7 @@ The measurements behind the rules above, kept for whoever needs the reasoning.
|
|||
one. `verify:map-paint` passes under both tokens (it checks GL + attribution, not tiles), so judge tile
|
||||
loading by the tile response count, not a screenshot — the basemap is Mapbox Light, which looks bare.
|
||||
- **Share round-trip (2026-09-22).** 8/8 passed with six distinct reopened tags, each matching its plugin
|
||||
(the two UPG-100 profiles share one tag). A pass count alone cannot catch an SPA fallback that renders
|
||||
(the two UPG100 Posters profiles share one tag). A pass count alone cannot catch an SPA fallback that renders
|
||||
*a* map for every URL.
|
||||
- **Why SRI identity, not HTTP status.** A platform's app URL can return 200 with a sign-in page; comparing
|
||||
each live bundle's bytes against the manifest's `integrity` hash is a cryptographic identity proof that
|
||||
|
|
|
|||
|
|
@ -90,15 +90,28 @@ const notes = []
|
|||
if (!partial.includes(`5 ${ppl}`) || !partial.includes(`995 ${ppl}`)) {
|
||||
fails.push(`a 0.5% list of 1,000 people does not state both totals ("5 ${ppl}" who follow Jesus, "995 ${ppl}" who do not yet)`)
|
||||
} else notes.push(' ok both totals are stated in people: 5 who follow Jesus, 995 who do not yet')
|
||||
if (/week/i.test(partial) || /class="lc-(wk|y)"/.test(partial)) fails.push('the page still counts in weeks or draws a week/year axis')
|
||||
// The grid is one SVG now (lifeGrid): its week numbers are <text class="lc-t lc-tw">, its year numbers
|
||||
// "lc-t lc-ty", and its markup names `data-weeks` as geometry, so the WORDS a reader sees are read with the
|
||||
// tags stripped.
|
||||
const axis = /class="lc-t lc-t[wy]\b/
|
||||
if (/week/i.test(partial.replace(/<[^>]+>/g, ' ')) || axis.test(partial)) fails.push('the page still counts in weeks or draws a week/year axis')
|
||||
else notes.push(' ok no weeks and no week/year axis on the page')
|
||||
// ★ ITS SIDE LABELS ARE SHARES (2026-10-02): each 10-row block is 520 boxes, a tenth of the list's people,
|
||||
// labelled 10% ... 100% in the page's own numerals; exactly those ten, in order.
|
||||
const shares = [...partial.matchAll(/class="lc-t lc-tp[^"]*"[^>]*>([^<]*)</g)].map((m) => m[1])
|
||||
const want = Array.from({ length: 10 }, (_, i) => `${((i + 1) * 10).toLocaleString('en')}%`)
|
||||
if (shares.join('|') !== want.join('|')) fails.push(`the people grid's side labels should read ${want.join(' ')}, got ${shares.join(' ') || 'none'}`)
|
||||
else notes.push(' ok the people grid labels each 10-row block with its share: 10% ... 100%')
|
||||
// A TINY SHARE: the totals come from the unrounded figure. 0.004% of 1,000,000,000 is 40,000 people,
|
||||
// which must not print as 0 because the percentage rounds to 0.00.
|
||||
const tiny = page({ groupsInList: 5, groupsMatched: 5, population: 1e9, evangelicalPopulation: 40000, pctEvangelical: 0.004 })
|
||||
if (!tiny.includes(`40,000 ${ppl}`) || !/ev-pct"><0\.01%</.test(tiny)) fails.push('a 0.004% share of a billion does not print 40,000 people and "<0.01%"')
|
||||
else notes.push(' ok a share below the printed digits keeps its real total (40,000 people) and reads "<0.01%"')
|
||||
// NEG CONTROL: the life page itself keeps its axes, so the axis test above can see one when it is there.
|
||||
if (!/class="lc-wk"/.test(R.lifePage(zone))) fails.push('the life page lost its week axis (the axis check above cannot fail)')
|
||||
// NEG CONTROL: the life page itself keeps both axes, so the axis test above can see one when it is there,
|
||||
// and it carries no share labels, so the share test above is not satisfied by any grid.
|
||||
const life = R.lifePage(zone)
|
||||
if (!/class="lc-t lc-tw"/.test(life) || !/class="lc-t lc-ty/.test(life)) fails.push('the life page lost its week or year axis (the axis check above cannot fail)')
|
||||
if (/class="lc-t lc-tp/.test(life)) fails.push('the life page carries share labels: a week of a life is not a share of people')
|
||||
}
|
||||
|
||||
for (const n of notes) console.log(n)
|
||||
|
|
|
|||
|
|
@ -78,7 +78,7 @@ function sequence(html) {
|
|||
: /word-title/.test(seg) ? 'word' // point 4's passage in full + the Father's-heart list (2026-09-30)
|
||||
: /points-title|points_title|Prayer Points/.test(seg) ? 'points'
|
||||
: `?${cls.trim()}`
|
||||
if ((kind === 'profiles' || kind === 'worksheet') && out[out.length - 1] === kind) return // one entry per run
|
||||
if ((kind === 'profiles' || kind === 'worksheet' || kind === 'points') && out[out.length - 1] === kind) return // one entry per run
|
||||
out.push(kind)
|
||||
})
|
||||
return out.join(' · ')
|
||||
|
|
@ -119,9 +119,9 @@ const box = (html) => {
|
|||
ok(p1.indexOf('class="map-sheet"') >= 0 && p1.indexOf('class="map-sheet"') < p1.indexOf('map-series'),
|
||||
'page 1 draws its title BEFORE the map, so the map-only sheet\'s background paints over it', 'on a map-only sheet the map is drawn first, the title over it')
|
||||
// two-sided: the series line WITH a packet count, and NOT without one
|
||||
ok(/class="map-series"[\s\S]{0,200}One of 28 UPG 100 prayer lists/.test(p1), 'page 1 (map-only) does not say it is one of the 28 UPG 100 prayer lists')
|
||||
ok(/class="map-series"[\s\S]{0,200}One of 28 UPG100 prayer lists/.test(p1), 'page 1 (map-only) does not say it is one of the 28 UPG100 prayer lists')
|
||||
const noKp1 = R.mapPage(zone, groups, liftedMap, noK)
|
||||
ok(!/map-series/.test(noKp1), 'page 1 prints a series line with NO packet count to state', 'a map-only page 1 says "One of 28 UPG 100 prayer lists" — and stays silent without a count')
|
||||
ok(!/map-series/.test(noKp1), 'page 1 prints a series line with NO packet count to state', 'a map-only page 1 says "One of 28 UPG100 prayer lists" — and stays silent without a count')
|
||||
// ★ A POSTER PAGE 1 HAS ONE HEADER, THE POSTER'S — two-sided against the map-only page above, which has the packet's.
|
||||
const posterP1 = R.mapPage(zone, groups, R.liftMap(POSTER_SHEET), withK)
|
||||
ok(/sheet-map-poster/.test(posterP1) && !/map-series/.test(posterP1) && !posterP1.includes(strings.en.map_page_sub.split('{count}')[0]),
|
||||
|
|
@ -143,10 +143,10 @@ const box = (html) => {
|
|||
ok(tiers === funnelRaw.steps.length + 2 && nums === tiers,
|
||||
`with a packet count the triangle should have ${funnelRaw.steps.length + 2} tiers each with its number; got ${tiers} tiers, ${nums} numbers`,
|
||||
`${tiers} tiers, every one with its number: ${funnelRaw.steps.length} global steps, the packets, this packet`)
|
||||
ok(/UPG 100 prayer packets divide/.test(page), 'the packets tier is missing although a packet count was supplied')
|
||||
ok(/UPG100 prayer packets divide/.test(page), 'the packets tier is missing although a packet count was supplied')
|
||||
const pageNoK = tri(R.buildPacket(zone, groups, new Map(), liftedMap, noK, christian, 'full', sets))
|
||||
const tiersNoK = (pageNoK.match(/class="funnel-tier/g) || []).length
|
||||
ok(tiersNoK === funnelRaw.steps.length + 1 && !/UPG 100 prayer packets divide/.test(pageNoK),
|
||||
ok(tiersNoK === funnelRaw.steps.length + 1 && !/UPG100 prayer packets divide/.test(pageNoK),
|
||||
`without a packet count the packets tier must be absent (${tiersNoK} tiers)`, 'no packet count, no packets tier')
|
||||
ok(/class="[^"]*funnel-mine/.test(page), 'the reader\'s own count (.funnel-mine) is missing from the triangle')
|
||||
// two-sided: a step is subtracted where the sets nest, and only there
|
||||
|
|
|
|||
|
|
@ -117,8 +117,11 @@ const layout = await page.evaluate(() => {
|
|||
const tb = rng.getBoundingClientRect()
|
||||
if (tb.width < 20 || box.width < 50 || box.width - tb.width < 12) continue
|
||||
if (cs.direction === 'rtl') out.rtlComputed += 1
|
||||
if (Math.round(box.right - tb.right) <= 1) out.pinnedRight += 1
|
||||
else if (Math.round(tb.left - box.left) <= 1) out.pinnedLeft += 1
|
||||
// Against the CONTENT box: a padded table cell (the pace table's) starts its run at its padding, which is
|
||||
// still the left (or right) edge the direction pins it to.
|
||||
const pl = parseFloat(cs.paddingLeft) || 0, pr = parseFloat(cs.paddingRight) || 0
|
||||
if (Math.round(box.right - pr - tb.right) <= 1) out.pinnedRight += 1
|
||||
else if (Math.round(tb.left - box.left - pl) <= 1) out.pinnedLeft += 1
|
||||
out.sampled += 1
|
||||
if (out.sampled >= 25) break
|
||||
}
|
||||
|
|
@ -181,6 +184,24 @@ const scriptureIsEnglish = lang !== 'en'
|
|||
&& !(catalog[lang] || {}).point4_passage
|
||||
await page.evaluate((words) => { window.__EXPECTED_RHYTHMS = words }, expected)
|
||||
|
||||
// The life grid's decoder: every square subpath (M x y …) of an .lc-svg back to its box index, from the geometry
|
||||
// the SVG declares. Used by the life-calendar checks below.
|
||||
await page.evaluate(() => {
|
||||
window.__lcBoxes = (svg) => {
|
||||
// data-geom x0,y0,px,dec[,py]: the box pitch across and down (one pitch when py is absent).
|
||||
const [x0, y0, px, dec, py = px] = String(svg.dataset.geom || '').split(',').map(Number)
|
||||
const weeks = Number(svg.dataset.weeks)
|
||||
const idx = (d) => [...String(d || '').matchAll(/M([\d.]+) ([\d.]+)/g)].map((m) => {
|
||||
const x = Number(m[1]) - 0.5 - x0, y = Number(m[2]) - 0.5 - y0
|
||||
const b = Math.floor(y / (10 * py + dec))
|
||||
return (b * 10 + Math.round((y - b * (10 * py + dec)) / py)) * weeks + Math.round(x / px)
|
||||
})
|
||||
const off = idx((svg.querySelector('path.lc-off') || {}).getAttribute?.('d'))
|
||||
const sh = svg.querySelector('path.lc-on, path.lc-reached')
|
||||
const shaded = sh ? idx(sh.getAttribute('d')).sort((a, b) => a - b) : []
|
||||
return { total: off.length + shaded.length, shaded, distinct: new Set([...off, ...shaded]).size }
|
||||
}
|
||||
})
|
||||
const r = await page.evaluate(() => {
|
||||
const body = document.body.innerText
|
||||
const imgs = [...document.querySelectorAll('.card img, img.ws-ph')] // profile cards, or lightweight rows (2026-09-30)
|
||||
|
|
@ -250,27 +271,43 @@ const r = await page.evaluate(() => {
|
|||
// stays exact whether or not the caller supplied set data.
|
||||
setsSheets: document.querySelectorAll('.sheet-sets').length,
|
||||
christianSheets: document.querySelectorAll('.sheet-christian').length,
|
||||
lifeCells: document.querySelectorAll('.lc-frame .lc-c').length,
|
||||
// ★ THE LIFE GRIDS ARE ONE SVG EACH (2026-10-02): two paths of square subpaths (empty and shaded) placed by
|
||||
// the geometry the SVG states (data-geom x0,y0,px,decadeGap,py). Each subpath is decoded back to its box index
|
||||
// in reading order, so the checks below still see box by box what is drawn, not a count the renderer asserts.
|
||||
lifeCells: [...document.querySelectorAll('.lc-frame .lc-svg')].reduce((a, g) => a + window.__lcBoxes(g).total, 0),
|
||||
prayBoxes: document.querySelectorAll('.pray-box').length,
|
||||
fdTopOver: (() => { const b = document.querySelector('.fd-top'); if (!b) return 0; const top = b.getBoundingClientRect().top
|
||||
return Math.round(Math.max(0, ...[...b.children].map((k) => k.getBoundingClientRect().bottom + parseFloat(getComputedStyle(k).marginBottom))) - top - b.clientHeight) })(),
|
||||
// The points page is ONE sheet by design and fits only because its sizes were tuned to the longest locale;
|
||||
// measure its content against its box (studio's ask), as fdTopOver does for the list's first page.
|
||||
// Each points sheet's body is measured, the worst one reported (one sheet today).
|
||||
pointsOver: (() => { const bs = [...document.querySelectorAll('.points-body')]; if (!bs.length) return null
|
||||
return Math.max(...bs.map((b) => { const top = b.getBoundingClientRect().top
|
||||
return Math.round(Math.max(b.scrollHeight - b.clientHeight, ...[...b.children].map((k) => k.getBoundingClientRect().bottom - top - b.clientHeight))) })) })(),
|
||||
pointsSheets: document.querySelectorAll('.sheet-points').length,
|
||||
// ★ THE POINTS PAGE SIZES ITSELF FROM AN ESTIMATE (2026-10-03, data-pt-est): the page must never be taller
|
||||
// than the estimate it was sized by, or the estimate is drifting and only its 3% margin still saves the page.
|
||||
pointsUnder: (() => { const b = document.querySelector('.points-body[data-pt-est]'); if (!b) return null
|
||||
const top = b.getBoundingClientRect().top, kids = [...b.children]
|
||||
const real = Math.max(...kids.map((k) => k.getBoundingClientRect().bottom - top)) + parseFloat(getComputedStyle(kids[kids.length - 1]).marginBottom)
|
||||
return { real: Math.round(real), est: Number(b.dataset.ptEst), tier: Number(b.dataset.ptTier) } })(),
|
||||
funnelTip: document.querySelectorAll('.funnel-tip').length,
|
||||
lifeShaded: document.querySelectorAll('.lc-frame .lc-reached').length,
|
||||
lifeShaded: (() => { const g = document.querySelector('.sheet-christian .lc-svg'); return g ? window.__lcBoxes(g).shaded.length : null })(),
|
||||
// ★ FILLED FROM THE TOP, in reading order (the packet's design), measured on the DOM order of the cells:
|
||||
// the shaded boxes must be EXACTLY the first N. This used to require a SCATTER, the opposite design;
|
||||
// a count alone still cannot tell a top fill from a scatter or a fill from the bottom.
|
||||
lifeTopFill: (() => {
|
||||
const grid = document.querySelector('.sheet-christian .lc-frame')
|
||||
if (!grid) return null
|
||||
const cells = [...grid.querySelectorAll('.lc-c')]
|
||||
const n = cells.filter((c) => c.classList.contains('lc-reached')).length
|
||||
return cells.slice(0, n).every((c) => c.classList.contains('lc-reached'))
|
||||
const g = document.querySelector('.sheet-christian .lc-svg')
|
||||
if (!g) return null
|
||||
const s = window.__lcBoxes(g).shaded
|
||||
return s.every((v, i) => v === i)
|
||||
})(),
|
||||
// The life page: Jesus' 33 years, the first 33 x 52 = 1,716 boxes and no others.
|
||||
jesusTopFill: (() => {
|
||||
const grid = document.querySelector('.sheet-life .lc-frame')
|
||||
if (!grid) return null
|
||||
const cells = [...grid.querySelectorAll('.lc-c')]
|
||||
const on = cells.filter((c) => c.classList.contains('lc-on')).length
|
||||
return { on, top: cells.slice(0, on).every((c) => c.classList.contains('lc-on')) }
|
||||
const g = document.querySelector('.sheet-life .lc-svg')
|
||||
if (!g) return null
|
||||
const s = window.__lcBoxes(g).shaded
|
||||
return { on: s.length, top: s.every((v, i) => v === i) }
|
||||
})(),
|
||||
funnelEq: document.querySelectorAll('.funnel-eq').length,
|
||||
funnelSteps: document.querySelectorAll('.funnel-mine').length,
|
||||
|
|
@ -427,6 +464,10 @@ const r = await page.evaluate(() => {
|
|||
if (!title) return -1
|
||||
const host = title.parentElement?.parentElement
|
||||
if (!host) return -1
|
||||
// Each point's heading carries class="pt-h": a numbered LINE is not a point. German cites "1. Petrus 5:6–11"
|
||||
// (its own name for 1 Peter), and that reference line was counted as a thirteenth point.
|
||||
const heads = document.querySelectorAll('.pt-h')
|
||||
if (heads.length) return heads.length
|
||||
return (host.innerText || '').split('\n').filter((l) => /^\s*\d{1,2}\.\s/.test(l)).length
|
||||
})(),
|
||||
metacamp: (body.match(/metacamp\.org/g) || []).length,
|
||||
|
|
@ -730,20 +771,31 @@ if (!boxes.length) {
|
|||
// sheets — a 100-year life in weeks, then the SAME grid shaded by the evangelical share of these
|
||||
// groups' population — so they are DETECTED and added as known terms for exactly the reason the
|
||||
// funnel was, and for the reason stated above: a tolerance here would hide a dropped list page.
|
||||
const PER_PAGE = 20
|
||||
// THE PAGE SIZES ARE THE RENDERER'S, read from it rather than retyped: the first list page of each packet
|
||||
// gives rows to the explanation band (2026-10-02), so a typed number drifted the moment the band changed.
|
||||
const { createPacketRenderer: makeR } = await import(resolve(dirname(fileURLToPath(import.meta.url)), '../library/packet/packet-render.js'))
|
||||
const RR = makeR({ strings: catalog, lang: 'en' })
|
||||
const PER_PAGE = RR.PER_PAGE
|
||||
const funnelSheets = r.funnel ? 1 : 0
|
||||
const lifeSheets = (r.lifeSheets || 0) + (r.christianSheets || 0)
|
||||
// ⚠ AND THE SETS PAGES (bounded, centered): back matter, DETECTED for the same reason as the rest.
|
||||
// Before they were counted the arithmetic only held when a fixture omitted set data.
|
||||
const setsSheets = r.setsSheets || 0
|
||||
// The worksheet paginates 11 rows on its first page and 18 after (packet-render WS_FIRST / WS_REST; the first page
|
||||
// gave five rows to its description and pace table on 2026-10-02; 20 and 24
|
||||
// before its rows gained a photo and a description, 2026-09-30).
|
||||
const wsPages = (n) => (n <= 0 ? 0 : 1 + Math.ceil(Math.max(0, n - 11) / 18))
|
||||
const listSheets = r.cards ? Math.ceil(r.cards / PER_PAGE) : wsPages(r.wsRows)
|
||||
// Both lists give their first page to the explanation band: the worksheet holds WS_FIRST rows there and
|
||||
// WS_REST after; the profile pages FD_FIRST, then PER_PAGE.
|
||||
const wsPages = (n) => (n <= 0 ? 0 : 1 + Math.ceil(Math.max(0, n - RR.WS_FIRST) / RR.WS_REST))
|
||||
const fdPages = (n) => (n <= 0 ? 0 : 1 + Math.ceil(Math.max(0, n - RR.FD_FIRST) / PER_PAGE))
|
||||
const listSheets = r.cards ? fdPages(r.cards) : wsPages(r.wsRows)
|
||||
// The Full detail's first page reserves a block for the explanation and CLIPS what outgrows it (rather than
|
||||
// let it overlap the rows): only a measurement sees a clipped line, so measure it.
|
||||
if (r.pointsOver !== null && r.pointsOver > 0) fails.push(`the prayer-points page outgrows its sheet by ${r.pointsOver}px — the twelve points and the themes must fit ONE page in every language`)
|
||||
if (r.pointsUnder && r.pointsUnder.real > r.pointsUnder.est) fails.push(`the prayer-points page is ${r.pointsUnder.real}px tall, over the ${r.pointsUnder.est}px its size tier ${r.pointsUnder.tier} was chosen by — the estimate (packet-render pointsHeight) under-measures this language`)
|
||||
if (r.fdTopOver > 0) fails.push(`the Full detail's explanation block outgrows its reserved height by ${r.fdTopOver}px — text is clipped (raise FD_TOP_H)`)
|
||||
if (r.wsRows && r.wsSheets !== wsPages(r.wsRows)) fails.push(`${r.wsRows} worksheet rows should take ${wsPages(r.wsRows)} page(s) but the packet has ${r.wsSheets}`)
|
||||
// + 2 again (2026-09-30, the second revision): point 4's Mark 5:18-20 and the Father's-heart list are back ON the
|
||||
// points page, so the back matter is the wheel and the points.
|
||||
// + 2: the wheel and the points, the twelve points and the themes on ONE sheet (2026-10-02, at the demo).
|
||||
if (r.pointsSheets !== 1) fails.push(`the twelve prayer points and the themes should fit ONE sheet, found ${r.pointsSheets}`)
|
||||
const expectedSheets = 1 + lifeSheets + funnelSheets + listSheets + setsSheets + 2
|
||||
// ── THE LIFE-CALENDAR PAGES, asserted rather than merely counted ──────────────────────────────────
|
||||
// A page that EXISTS is not a page that is RIGHT: an empty grid, a grid of the wrong size, or a
|
||||
|
|
@ -833,6 +885,8 @@ if (r.funnel && r.funnelRows !== r.funnelBars) {
|
|||
// an allowlist entry added BEFORE translating would have hidden fifteen untranslated strings.
|
||||
// 'UPG' is the same product name as renamed, "UPG 100" with a space: the digits break the run, so it
|
||||
// surfaces as 'UPG' (page 2's kicker and packets tier). Settled, like 'UPG-' — a name, not prose.
|
||||
// The series is now written as ONE term, "UPG100" (2026-10-02): the digits still break the run, so it too
|
||||
// surfaces as 'UPG'.
|
||||
const LATIN_OK = new Set(['IMB', 'peoplegroups.org', 'Project', 'UPG-', 'UPG'])
|
||||
const NON_LATIN_LOCALES = new Set(['hi', 'ar', 'ru', 'zh', 'he', 'fa', 'ur', 'bn', 'ta', 'th', 'ko', 'ja'])
|
||||
if (r.funnel && NON_LATIN_LOCALES.has(String(lang).split('-')[0])) {
|
||||
|
|
@ -916,6 +970,7 @@ console.log(` funnel (page 2) : ${r.funnel
|
|||
? `${r.funnelRows} row(s), ${r.funnelBars} bar(s)${r.funnelShare ? ` — "${r.funnelShare}"` : ' — no share line'}`
|
||||
: 'absent' + (EXPECT_FUNNEL ? ' (REQUIRED — see FAIL above)' : ' (not required)')}`)
|
||||
console.log(` prayer points : ${r.points} / ${POINTS_EXPECT}`)
|
||||
if (r.pointsUnder) console.log(` points size tier : ${r.pointsUnder.tier} (estimated ${r.pointsUnder.est}px, measured ${r.pointsUnder.real}px)`)
|
||||
console.log(` wheel segments : ${r.wheelSegs} (${r.wheelLabels}/${WHEEL_LABELS} labelled)`)
|
||||
console.log(` point 4 : Mark 5:18-20 ${r.mark5Len} chars, verse 19 bold ${r.v19Len} chars, ${r.heartItems} readings`)
|
||||
console.log(` metacamp.org : ${r.metacamp}`)
|
||||
|
|
|
|||
|
|
@ -125,6 +125,22 @@ for (const loc of locales) {
|
|||
}
|
||||
}
|
||||
|
||||
// ── SCRIPTURE ADDRESSES ARE ENGLISH'S, AND THE THEMES ARE WHOLE ───────────────────
|
||||
// A point's refs are canonical addresses: a language may not keep an older set (point 12 kept Acts 2 / Matthew 28
|
||||
// in ten languages after English moved to John 17). The prayer themes are seven and the scenes three in every
|
||||
// language, or the page falls back to English for the whole list.
|
||||
for (const loc of locales) {
|
||||
const b = cat[loc]
|
||||
;(b.points || []).forEach((pt, i) => {
|
||||
if (pt && pt.refs !== undefined && JSON.stringify(pt.refs) !== JSON.stringify((en.points[i] || {}).refs)) {
|
||||
fails.push(`${loc} point ${i + 1} carries references ${JSON.stringify(pt.refs)}, not English's ${JSON.stringify((en.points[i] || {}).refs)}`)
|
||||
}
|
||||
})
|
||||
if (!Array.isArray(b.themes) || b.themes.length !== 7 || b.themes.some((x) => typeof x !== 'string' || !x.trim())) fails.push(`${loc} needs 7 prayer themes`)
|
||||
if (!Array.isArray(b.scenes) || b.scenes.length !== 3 || b.scenes.some((x) => typeof x !== 'string' || !x.trim())) fails.push(`${loc} needs 3 prayer scenes`)
|
||||
}
|
||||
if (!Array.isArray(en.scene_refs) || en.scene_refs.length !== 3 || en.scene_refs.some((r) => !Array.isArray(r) || r.length !== 2)) fails.push('en scene_refs must give each of the 3 scenes two references')
|
||||
|
||||
// ── ARABIC: NO ALEF WASLA (U+0671) ─────────────────────────────────────────────
|
||||
// The Van Dyck texts write the article with alef wasla (ٱ). A device whose fonts lack U+0671 printed it as a
|
||||
// BOX, three times in the blessing and eight in Mark 5. The stored ar text uses plain alef (U+0627), the
|
||||
|
|
|
|||
|
|
@ -97,7 +97,7 @@ ok(count(light, /sheet-sets-(bounded|centered)/g) === 0, 'lightweight still carr
|
|||
// ⚠ THE DELTA IS DERIVED, never relaxed into a range: lightweight drops four back pages (life, % grid,
|
||||
// bounded, centered) AND lists the same people as a worksheet, whose pages hold more rows than profiles.
|
||||
{
|
||||
const profilePages = Math.ceil(45 / R.PER_PAGE)
|
||||
const profilePages = 1 + Math.ceil(Math.max(0, 45 - R.FD_FIRST) / R.PER_PAGE)
|
||||
const worksheetPages = count(light, /<div class="sheet sheet-worksheet/g)
|
||||
const want = 4 + profilePages - worksheetPages
|
||||
ok(worksheetPages >= 1 && count(light, /class="ws-row"/g) === 45, `the lightweight worksheet should list all 45 groups, got ${count(light, /class="ws-row"/g)}`)
|
||||
|
|
@ -116,47 +116,95 @@ ok(count(light, /sheet-sets-(bounded|centered)/g) === 0, 'lightweight still carr
|
|||
`each lightweight row should carry ONE photo cell (${pics.size} photos + ${45 - pics.size} "no photo"), got ${imgs} + ${none} in ${rows} rows`)
|
||||
ok(count(lw, /class="ws-desc"/g) === 45, `each lightweight row should carry its group's description, got ${count(lw, /class="ws-desc"/g)} of 45`)
|
||||
}
|
||||
// ★ THE LIGHTWEIGHT LIST EXPLAINS ITSELF FIRST (2026-10-02): its first page carries, before any row, what the three
|
||||
// columns ask, the blessing in full with its credit, ONE line of further references, the wheel pointer, and a
|
||||
// five-pace table whose daily load is COMPUTED from the list (45 groups: all 45 a day, 6 at a weekly pace).
|
||||
// Once, on the first worksheet page only, and never in the full packet. The rows keep their tally cells.
|
||||
{
|
||||
const first = light.slice(light.indexOf('<div class="sheet sheet-worksheet'))
|
||||
const page1 = first.slice(0, first.indexOf('<div class="sheet', 10))
|
||||
// ★ BOTH LISTS EXPLAIN THEMSELVES FIRST (2026-10-02, v2): the first list page of EACH packet carries, before any
|
||||
// row, the blessing in full with its credit, ONE line of further references, the wheel pointer, and ONE band
|
||||
// (class="xb"): a five-pace table whose loads are COMPUTED from the list (45 groups: all 45 a day, 6 at a
|
||||
// weekly pace), what the three columns ask, and an example row of three tally cells under the table's own
|
||||
// question heads. The question heads stand ONCE per page over the tally cells, never per group.
|
||||
for (const [name, html, rowRe, cellRe, headRe, pageRe] of [
|
||||
['lightweight', light, /class="ws-row"/g, /class="ws-box"/g, /class="ws-head"/g, /<div class="sheet sheet-worksheet/g],
|
||||
['full', full, /class="card"/g, /class="pray-box"/g, /class="pray-head"/g, /<div class="hd">/g],
|
||||
]) {
|
||||
const E = strings.en
|
||||
const before = page1.indexOf('class="ws-howto"') >= 0 && page1.indexOf('class="ws-howto"') < page1.indexOf('class="ws-row"')
|
||||
ok(count(light, /class="ws-howto"/g) === 1 && before, 'the lightweight list should explain its three columns ONCE, on its first page, before the first row')
|
||||
ok(count(full, /class="ws-howto"|class="ws-pace"/g) === 0, 'the full packet should not carry the worksheet description')
|
||||
ok(page1.includes(E.blessing_text.replace(/&/g, '&')) && page1.includes(E.blessing_credit), 'the first page should print the blessing (Numbers 6:24-26) with its credit')
|
||||
ok(count(page1, /class="ws-refs"/g) === 1 && count(page1, /Psalm 134:3/g) === 1, 'the first page should carry ONE line of blessing references')
|
||||
ok(page1.includes(E.howto_wheel), 'the first page should point to the prayer wheel at the end of the packet')
|
||||
const paceRows = (page1.match(/<table class="ws-pace-t">([\s\S]*?)<\/table>/) || [])[1] || ''
|
||||
ok(count(paceRows, /<th/g) === 5 && paceRows.includes('all 45, every day') && paceRows.includes('about 6 a day') && count(paceRows, /ws-pace-best/g) === 3,
|
||||
`the pace table should show five paces, daily = all 45 and weekly = about 6 a day (from the list size), weekly marked: ${paceRows.replace(/<[^>]+>/g, ' ').replace(/\s+/g, ' ').trim().slice(0, 200)}`)
|
||||
ok(!/no pace to keep/.test(light), 'the lightweight list should no longer say there is no pace to keep')
|
||||
ok(count(light, /class="ws-box"/g) === 45 * 3, `every worksheet row should carry three tally cells, got ${count(light, /class="ws-box"/g)}`)
|
||||
const band = html.indexOf('<section class="xb"')
|
||||
ok(count(html, /<section class="xb"/g) === 1 && band > 0 && band < html.search(rowRe),
|
||||
`the ${name} list should explain itself ONCE, on its first list page, before the first row`)
|
||||
ok(html.includes(E.blessing_text.replace(/&/g, '&')) && html.includes(E.blessing_credit), `the ${name} list should print the blessing (Numbers 6:24-26) with its credit`)
|
||||
ok(count(html, /class="ws-refs"/g) === 1 && count(html, /Psalm 134:3/g) === 1, `the ${name} list should carry ONE line of blessing references`)
|
||||
ok(html.includes(E.howto_wheel), `the ${name} list should point to the prayer wheel at the end of the packet`)
|
||||
const pace = (html.match(/<table class="ws-pace-t">([\s\S]*?)<\/table>/) || [])[1] || ''
|
||||
ok(count(pace, /<tr/g) === 5 && pace.includes('all 45, every day') && pace.includes('about 6 a day') && count(pace, /ws-pace-best/g) === 1,
|
||||
`the ${name} pace table should show five paces, daily = all 45 and weekly = about 6 a day (from the list size), weekly marked: ${pace.replace(/<[^>]+>/g, ' ').replace(/\s+/g, ' ').trim().slice(0, 160)}`)
|
||||
ok(count(html, /class="xb-cell /g) === 3 && count(html, /class="xb-marks"/g) === 3, `the ${name} band's example should be ONE row of three tally cells with marks`)
|
||||
ok(count(html, rowRe) === 45 && count(html, cellRe) === 45 * 3, `every ${name} row should carry three tally cells, got ${count(html, cellRe)} for ${count(html, rowRe)} rows`)
|
||||
ok(count(html, headRe) === count(html, pageRe), `the ${name} question heads should stand once per list page: ${count(html, headRe)} heads on ${count(html, pageRe)} pages`)
|
||||
}
|
||||
ok(!/no pace to keep/.test(light), 'the lightweight list should no longer say there is no pace to keep')
|
||||
// ★ THE PRAYER THEMES HEAD THE POINTS PAGE (2026-10-02): seven themes, then three scenes with two references
|
||||
// each, in both packets; point 12 is John 17 (its references are John 17:3, John 17:11–23, Ephesians 3:20).
|
||||
for (const [name, html] of [['lightweight', light], ['full', full]]) {
|
||||
const th = (html.match(/<div class="pt-themes">([\s\S]*?)<\/div>\s*<div style="margin-bottom/) || [])[1] || ''
|
||||
const themes = count(th.split('pt-sc-list')[0] || '', /<li>/g), scenes = count(th.split('pt-sc-list')[1] || '', /<li>/g)
|
||||
ok(themes === 7 && scenes === 3 && count(th, /class="pt-sc-r"/g) === 3 && /Haggai 2:7/.test(th) && /Matthew 8:26/.test(th),
|
||||
`the ${name} points page should open with 7 themes and 3 scenes (2 references each): ${themes} themes, ${scenes} scenes`)
|
||||
ok(/John 17:3/.test(html) && /Ephesians 3:20/.test(html) && !/Acts 2:42/.test(html), `the ${name} point 12 should be John 17 (John 17:3 · John 17:11–23 · Ephesians 3:20)`)
|
||||
}
|
||||
ok(!/<em>[^<]*<\/em><\/span>/.test(full.slice(full.indexOf('class="card"'))), 'the full packet repeats a question under each tally cell; the heads stand once per page')
|
||||
// ★ THE LIFE CALENDAR, HEADLESS — the grid's CONTENT, not just its page. An adversarial review mutated the
|
||||
// renderer to shade the LAST 33 years, to shade nothing, and to draw 90 rows; every packet gate stayed green
|
||||
// because none looked inside the grid. Read the cells of each frame, in order (the legend's sample boxes
|
||||
// sit outside the frame and are excluded):
|
||||
{
|
||||
const frame = (html, cls) => {
|
||||
// The grid is ONE SVG per page (packet-render lifeGrid): decode each square subpath back to its box index
|
||||
// from the geometry the SVG declares, so the check reads the boxes as drawn, in reading order.
|
||||
const grid = (html, cls) => {
|
||||
const i = html.indexOf(`<div class="sheet ${cls}`)
|
||||
// By class PREFIX: the knows-Christ grid is `lc-frame lc-plain` (drawn without week/year axes).
|
||||
const a = html.indexOf('<div class="lc-frame', i)
|
||||
return a < 0 ? '' : html.slice(a, html.indexOf('<div class="lc-legend">', a))
|
||||
const a = html.indexOf('<svg class="lc-svg"', i)
|
||||
return a < 0 || i < 0 ? '' : html.slice(a, html.indexOf('</svg>', a))
|
||||
}
|
||||
const cells = (h) => [...h.matchAll(/<i class="lc-c( lc-on| lc-reached)?"><\/i>/g)].map((m) => (m[1] || '').trim())
|
||||
const life = cells(frame(full, 'sheet-life'))
|
||||
ok(life.length === 5200, `the life calendar should hold 100 x 52 = 5,200 boxes, got ${life.length}`)
|
||||
const gold = life.filter((c) => c === 'lc-on').length
|
||||
ok(gold === 33 * 52 && life.slice(0, gold).every((c) => c === 'lc-on'),
|
||||
`the life calendar should shade Jesus' 33 years as its FIRST 1,716 boxes — got ${gold}, from the top: ${life.slice(0, gold).every((c) => c === 'lc-on')}`)
|
||||
const ev = cells(frame(full, 'sheet-christian'))
|
||||
const shaded = ev.filter((c) => c === 'lc-reached').length
|
||||
ok(ev.length === 5200 && shaded === Math.round(0.032 * 5200) && ev.slice(0, shaded).every((c) => c === 'lc-reached'),
|
||||
`the %-evangelical grid should shade 3.2% = ${Math.round(0.032 * 5200)} boxes FROM THE TOP, got ${shaded} of ${ev.length}`)
|
||||
const boxes = (svg) => {
|
||||
// data-geom x0,y0,px,dec[,py]: the box pitch across and down (one pitch when py is absent).
|
||||
const [x0, y0, px, dec, py = px] = ((svg.match(/data-geom="([^"]+)"/) || [])[1] || '').split(',').map(Number)
|
||||
const weeks = Number((svg.match(/data-weeks="(\d+)"/) || [])[1])
|
||||
const idx = (d) => [...String(d || '').matchAll(/M([\d.]+) ([\d.]+)/g)].map((m) => {
|
||||
const x = Number(m[1]) - 0.5 - x0, y = Number(m[2]) - 0.5 - y0, b = Math.floor(y / (10 * py + dec))
|
||||
return (b * 10 + Math.round((y - b * (10 * py + dec)) / py)) * weeks + Math.round(x / px)
|
||||
})
|
||||
const off = idx((svg.match(/<path class="lc-off" d="([^"]*)"/) || [])[1])
|
||||
const on = idx((svg.match(/<path class="lc-(?:on|reached)" d="([^"]*)"/) || [])[1]).sort((a, b) => a - b)
|
||||
return { total: off.length + on.length, distinct: new Set([...off, ...on]).size, on }
|
||||
}
|
||||
const life = boxes(grid(full, 'sheet-life'))
|
||||
ok(life.total === 5200 && life.distinct === 5200, `the life calendar should hold 100 x 52 = 5,200 distinct boxes, got ${life.total} (${life.distinct} distinct)`)
|
||||
ok(life.on.length === 33 * 52 && life.on.every((v, i) => v === i),
|
||||
`the life calendar should shade Jesus' 33 years as its FIRST 1,716 boxes — got ${life.on.length}, from the top: ${life.on.every((v, i) => v === i)}`)
|
||||
const ev = boxes(grid(full, 'sheet-christian'))
|
||||
ok(ev.total === 5200 && ev.on.length === Math.round(0.032 * 5200) && ev.on.every((v, i) => v === i),
|
||||
`the %-evangelical grid should shade 3.2% = ${Math.round(0.032 * 5200)} boxes FROM THE TOP, got ${ev.on.length} of ${ev.total}`)
|
||||
// THE SAME TABLE: the people grid has the life grid's exact shape (one aspect ratio for both pages).
|
||||
const vb = (svg) => (svg.match(/viewBox="([^"]+)"/) || [])[1]
|
||||
ok(vb(grid(full, 'sheet-life')) && vb(grid(full, 'sheet-life')) === vb(grid(full, 'sheet-christian')), 'the people grid should have the life grid\'s exact shape')
|
||||
}
|
||||
|
||||
// ★ THE POINTS PAGE FITS ITSELF (2026-10-03): per language it takes the LARGEST size tier whose estimate fits
|
||||
// one sheet, from the one-sheet sizes up to the two-sheet sizes before them (the cap). Asserted both ways: the
|
||||
// tier chosen is the largest that fits, and SHORTER words print LARGER (halving the English points raises
|
||||
// the English tier) while the real words keep theirs. check:packet-render holds the estimate to the real page.
|
||||
{
|
||||
for (const lang of ['en', 'ar', 'zh', 'fr']) {
|
||||
const R = createPacketRenderer({ strings, lang })
|
||||
const f = R.pointsFit, k = f.chosen(), budget = f.bodyH * f.safe
|
||||
ok(k === f.tiers || f.height(k + 1) > budget, `${lang}: points tier ${k} is not the largest that fits (tier ${k + 1} estimates ${Math.round(f.height(k + 1))}px of ${Math.round(budget)})`)
|
||||
ok(k === 0 || f.height(k) <= budget, `${lang}: points tier ${k} estimates ${Math.round(f.height(k))}px, over the ${Math.round(budget)}px budget`)
|
||||
ok(R.pointsPage().includes(`data-pt-tier="${k}"`), `${lang}: the points page does not print at the tier it chose (${k})`)
|
||||
}
|
||||
const top = (lang, s) => createPacketRenderer({ strings: s, lang }).pointsFit
|
||||
const short = JSON.parse(JSON.stringify(strings))
|
||||
short.en.points = short.en.points.map((p) => ({ ...p, text: p.text.slice(0, Math.ceil(p.text.length / 2)) }))
|
||||
const k0 = top('en', strings).chosen(), k1 = top('en', short).chosen()
|
||||
ok(k1 > k0, `halving the English points' text should raise the English points tier, got ${k0} -> ${k1}`)
|
||||
// the cap is the two-sheet sizes: the largest tier prints the point text at 22.5px
|
||||
ok(/font:400 22\.5px Georgia/.test(createPacketRenderer({ strings, lang: 'en' }).pointsPage(top('en', strings).tiers)), 'the largest points tier should print the text at 22.5px (the two-sheet size, the cap)')
|
||||
}
|
||||
|
||||
// ★ UNKNOWN POINTS ARE STATED EVEN THOUGH THEY CANNOT BE PLOTTED. layoutBoundedSet gives them no
|
||||
|
|
|
|||
|
|
@ -40,7 +40,7 @@ const G = (i) => ({ slug: `g${i}`, name: `Group ${i}`, country_code: 'MYS', prim
|
|||
// which meant the assertion checked MY arithmetic against MY arithmetic and stayed green when the
|
||||
// source's ROWS changed — it was the pagination check that caught that mutant, by luck. PER_PAGE is
|
||||
// exported; the rest come out of the rendered geometry, so this compares the SOURCE to the sheet.
|
||||
const { PER_PAGE, W, H } = mk(describe)
|
||||
const { PER_PAGE, FD_FIRST, W, H } = mk(describe)
|
||||
const SRC = read('library/packet/packet-render.js')
|
||||
const numOf = (re, what) => {
|
||||
const m = SRC.match(re)
|
||||
|
|
@ -91,7 +91,10 @@ for (const n of [1, 19, 20, 21, 45, 100]) {
|
|||
const rows = (html.match(/class="card"/g) || []).length
|
||||
ok(rows === n, `${n} groups rendered ${rows} rows — a layout rewrite dropped people`)
|
||||
const pages = R.listPages({ id: 'z', label: 'Z' }, Array.from({ length: n }, (_, i) => G(i)), new Map()).length
|
||||
ok(pages === Math.ceil(n / 20), `${n} groups made ${pages} pages, expected ${Math.ceil(n / 20)}`)
|
||||
// The first page gives its top to the explanation band (2026-10-02) and holds FD_FIRST rows; the rest PER_PAGE.
|
||||
const want = 1 + Math.ceil(Math.max(0, n - FD_FIRST) / PER_PAGE)
|
||||
ok(Number.isInteger(FD_FIRST) && FD_FIRST > 0 && FD_FIRST < PER_PAGE, `FD_FIRST should be a row count below PER_PAGE, got ${FD_FIRST}`)
|
||||
ok(pages === want, `${n} groups made ${pages} pages, expected ${want} (${FD_FIRST} on the first, ${PER_PAGE} after)`)
|
||||
}
|
||||
|
||||
// Each row must carry its three prayer boxes — the packet is a WORKING sheet, and a row without
|
||||
|
|
@ -104,7 +107,11 @@ for (const n of [1, 19, 20, 21, 45, 100]) {
|
|||
// ── 3. THE FIT LADDER PICKS THE SIZE IT CLAIMS, AND EVERY TIER FIRES ───────────────────────────
|
||||
// Budgets are recomputed here from the same inputs rather than hardcoded, so this tests the LADDER
|
||||
// and not my arithmetic twice.
|
||||
const DESC_W = 1036, ADV = 0.52, LINES = 2
|
||||
// DESC_W READ FROM THE SOURCE'S OWN INPUTS, not restated: it was a typed 1036 and went stale the moment the tally
|
||||
// cells widened (PRAY_CELL 84 → 96). The row is the sheet less its margins, the photo, the three tally cells and
|
||||
// two gutters.
|
||||
const PRAY_CELL = numOf(/const PRAY_CELL = (\d+)/, 'PRAY_CELL')
|
||||
const DESC_W = (W - 2 * M) - Math.min(CH - 8, 64) - 3 * PRAY_CELL - GUT * 2, ADV = 0.52, LINES = 2
|
||||
const budget = (px) => Math.floor(DESC_W / (px * ADV)) * LINES
|
||||
const probe = (txt) => {
|
||||
const html = mk(() => txt).listPages({ id: 'z' }, [G(0)], new Map()).join('')
|
||||
|
|
@ -114,7 +121,9 @@ const probe = (txt) => {
|
|||
const words = (n) => 'word '.repeat(n).trim()
|
||||
ok(probe(words(10)).px === 17, 'a short description did not render at the full 17px')
|
||||
ok(probe(words(Math.floor(budget(17) / 5))).px === 17, 'a description just inside the 17px budget stepped down anyway')
|
||||
ok(probe(words(Math.floor(budget(17) / 5) + 6)).px === 15,
|
||||
// Between the 17px and the 15px budgets, wherever they fall for this row width: '+6 words' was 30 characters, and
|
||||
// when the tally cells widened the gap between the two budgets shrank to 24, so the probe skipped 15 for 14.
|
||||
ok(probe(words(Math.floor((budget(17) + budget(15)) / 2 / 5))).px === 15,
|
||||
'a description over the 17px budget did not step to 15px')
|
||||
const long = probe(words(Math.floor(budget(14) / 5) + 40))
|
||||
ok(long.px === 14, `a very long description did not clamp at the smallest size (got ${long.px}px)`)
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@
|
|||
"neg": { "leaf": "regions-dashboard/regions-list/index.html", "text": "View country posters" },
|
||||
"sanctioned": [
|
||||
{
|
||||
"match": "^(Select view|Regions List|Dashboard|Country Posters)$", "flags": "i",
|
||||
"match": "^(Select view|Regions List|Dashboard)$", "flags": "i",
|
||||
"what": "the SELECT VIEW tab strip — sanctioned addition #1",
|
||||
"ruling": "the tabs added, and what the dashboard tab shows before a region or country is selected",
|
||||
"date": "2026-09-24", "card": "SPEC-REGIONS-IS-A-CLONE-PLUS-EXACTLY-TWO-ADDITIONS"
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@
|
|||
"gospelResources": "موارد الإنجيل",
|
||||
"languageFamilies": "العائلات اللغوية",
|
||||
"prayer": "تقدم الصلاة",
|
||||
"upg100List": "قائمة UPG 100 الخاصة بي",
|
||||
"upg100List": "قائمة UPG100 الخاصة بي",
|
||||
"batchSelect": "تحديد متعدد"
|
||||
},
|
||||
"header": {
|
||||
|
|
@ -58,8 +58,8 @@
|
|||
"languages": "اللغات"
|
||||
},
|
||||
"tabInfo": {
|
||||
"upg100Region": "المنطقة — ترتّب قوائم UPG-100 حسب منطقة العالم (أفريقيا، الهند، الشرق الأوسط، الصمّ، …). الأعداد هي مجموع UUPG والسكان لكل قائمة تحتها.",
|
||||
"upg100Zone": "قوائم UPG-100 — كل واحدة هي قائمة صلاة للشعوب غير الموصول إليها في منطقة ما، وهي ما ترسمه الخريطة وتلوّنه. تُطبع كل قائمة ككُتيّب خاص بها.",
|
||||
"upg100Region": "المنطقة — ترتّب قوائم UPG100 حسب منطقة العالم (أفريقيا، الهند، الشرق الأوسط، الصمّ، …). الأعداد هي مجموع UUPG والسكان لكل قائمة تحتها.",
|
||||
"upg100Zone": "قوائم UPG100 — كل واحدة هي قائمة صلاة للشعوب غير الموصول إليها في منطقة ما، وهي ما ترسمه الخريطة وتلوّنه. تُطبع كل قائمة ككُتيّب خاص بها.",
|
||||
"upg100Group": "مجموعة شعبية — المجموعات غير الموصول إليها داخل القائمة، الأكثر حاجة للصلاة أولاً. كل نقطة على الخريطة هي واحدة منها.",
|
||||
"family": "عائلة اللغة — مجموعة لغات منحدرة من أصل مشترك (مثل الهندية الأوروبية، الأفروآسيوية).",
|
||||
"language": "اللغة — نظام تواصل يستخدمه شعب ما (مثل العربية، البنغالية، الهندية).",
|
||||
|
|
@ -80,7 +80,7 @@
|
|||
},
|
||||
"export": {
|
||||
"poster": "ملصق",
|
||||
"packet": "UPG 100",
|
||||
"packet": "UPG100",
|
||||
"packetExplain": "قائمة صلاة من نحو ٥٠ إلى ١٠٠ شعب غير مبلَّغ — يستطيع شخص واحد أن يحمل واحدة.",
|
||||
"packetAria": "تفاصيل حزمة الصلاة",
|
||||
"packetFull": "تفاصيل كاملة",
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@
|
|||
"p2": "اعثر على الفجوات. انتقل إلى «المشاركة» لترى أين بدأ العمل وأين لم يُخدَم أحد بعد. تلك الفجوات هي المناطق ذات الأولوية للتحشيد.",
|
||||
"p3": "ابحث في جزء واحد من العالم في كل مرة. ضيِّق حسب المنطقة أو اللغة أو الديانة، أو ابحث في القائمة بالاسم. تتبع القائمة الخريطة، فتقرأ الأسماء التي وراء النقاط.",
|
||||
"p4": "تعرّف على شعب. اضغط على نقطة لترى بلده وعدد سكانه ولغته وديانته، ثم استخدم «صلِّ من أجلهم» لتبدأ الصلاة من أجل ذلك الشعب باسمه.",
|
||||
"p5": "اجعله بسيطًا. تتابع هذه الخريطة التقدّم على مستوى بسيط وبلمحة. وحين تحتاج إلى البيانات الكاملة، انتقل إلى «الصورة الكاملة»؛ ولموارد الصلاة القابلة للطباعة، انتقل إلى «المناطق» أو «قائمة UPG-100»."
|
||||
"p5": "اجعله بسيطًا. تتابع هذه الخريطة التقدّم على مستوى بسيط وبلمحة. وحين تحتاج إلى البيانات الكاملة، انتقل إلى «الصورة الكاملة»؛ ولموارد الصلاة القابلة للطباعة، انتقل إلى «المناطق» أو «قائمة UPG100»."
|
||||
},
|
||||
"regions-dashboard": {
|
||||
"bottom": "لنحو 170 دولة ملصقها وحزمتها ومجموعة بطاقاتها. حشِّد مجموعة واحدة لتصلّي من أجل كل دولة، فتُغطّى كل دولة بالصلاة.",
|
||||
|
|
@ -22,7 +22,7 @@
|
|||
"p2": "ابدأ قريبًا من بيتك، بالتلاميذ والكنائس المحلية. ثم انتقل إلى القادة والعاملين المحليين على الأرض في تلك الدول، وأرسل إليهم ملصق الدولة وحزمتها وبطاقاتها ليطبعوها حيث هم.",
|
||||
"p3": "حزمة الصلاة هي الأكثر استراتيجية بين الثلاثة: كل ما تحتاجه للصلاة من أجل دولة، في حزمة واحدة قابلة للطباعة.",
|
||||
"p4": "تفيد البطاقات أكثر حين تكون لديك مجموعة توزّعها عليها: شعب واحد في كل بطاقة.",
|
||||
"p5": "تناسب حزم الدول قاعدة تحشيد أكبر، أو دولة واحدة تريد أن تراها مُبلَّغة. وإن كان التحشيد بطيئًا، فقوائم UPG-100 هي المكان الأبسط للبدء."
|
||||
"p5": "تناسب حزم الدول قاعدة تحشيد أكبر، أو دولة واحدة تريد أن تراها مُبلَّغة. وإن كان التحشيد بطيئًا، فقوائم UPG100 هي المكان الأبسط للبدء."
|
||||
},
|
||||
"prayer-map": {
|
||||
"bottom": "تنمو حركة الصلاة حين يعرض كل شريك الخريطة نفسها، فضع هذه الخريطة على كل موقع في شبكتك.",
|
||||
|
|
@ -36,7 +36,7 @@
|
|||
"bottom": "أجلس يسوع الخمسة آلاف في مجموعات من خمسين ومئة قبل أن يطعمهم (لوقا 9:14). وهذه القوائم تفعل الشيء نفسه لنحو 2,100 شعب غير مُبلَّغ: حين تُقسَّم إلى قوائم بهذا الحجم، تصير المهمة كلها حملًا يستطيع شخص واحد أن يحمله.",
|
||||
"p1": "27 قائمة تعني 27 ملصقًا و27 حزمة صلاة و27 مجموعة بطاقات. ضع واحدة في يد كل واحد من 27 تلميذًا أو كنيسة أو قائدًا محليًا، فيُصلّى من أجل كل شعب بالاسم.",
|
||||
"p2": "أعطِ كل قائمة لمن سيواظب على الصلاة من أجلها. ويستطيع القادة المحليون أن يصلّوا بلغات الشعوب نفسها.",
|
||||
"p3": "هذا يتبع ممارسة مُثبتة في الحركات: يصلّي التلاميذ بانتظام من أجل خمسين إلى مئة شخص يعرفونهم (العائلة والأصدقاء والجيران وزملاء العمل والدراسة). وقائمة UPG-100 هي الحمل نفسه، لأناس لم يلتقوهم قط.",
|
||||
"p3": "هذا يتبع ممارسة مُثبتة في الحركات: يصلّي التلاميذ بانتظام من أجل خمسين إلى مئة شخص يعرفونهم (العائلة والأصدقاء والجيران وزملاء العمل والدراسة). وقائمة UPG100 هي الحمل نفسه، لأناس لم يلتقوهم قط.",
|
||||
"p4": "ابدأ بقائمة واحدة وشخص واحد. تحمل الحزمة كل ما تحتاجه تلك القائمة في مطبوعة واحدة، وتساعد البطاقات حين تتقاسم مجموعة القائمة."
|
||||
},
|
||||
"cities-internet": {
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@
|
|||
"pinHint": {
|
||||
"tapDot": "اضغط على نقطة ملوّنة — لا يزال هناك من يحتاج إلى الصلاة"
|
||||
},
|
||||
"upg100WallHeading": "قائمتي UPG 100 — قوائم صلاة وملصقات",
|
||||
"upg100WallHeading": "قائمتي UPG100 — قوائم صلاة وملصقات",
|
||||
"upg100WallTag": "تعبئة للصلاة",
|
||||
"upg100WallIntroA": "كيف تُطعم جمعًا من خمسة آلاف؟ أجلسهم يسوع جماعاتٍ من خمسين ومن مئة، فصار المستحيل قابلًا للمشاركة (لوقا ٩:١٤). فعلنا المثل مع ٢١٠٦ شعوب غير مبلَّغة: ٢٧ قائمة من نحو خمسين إلى مئة. تُطبع كل قائمة حزمةَ صلاة وملصقًا، ليحمل ٢٧ تلميذًا أو كنيسة أو قائدًا محليًا كلٌّ واحدة — مصلّين لأجلهم ",
|
||||
"upg100WallIntroEmph": "باسم شعبهم",
|
||||
|
|
|
|||
|
|
@ -23,7 +23,7 @@
|
|||
"within": "ضمن {selection}",
|
||||
"allData": "كل بيانات DOXA"
|
||||
},
|
||||
"upg100Placeholder": "ابحث عن شعب أو قائمة UPG-100 أو منطقة…",
|
||||
"upg100Placeholder": "ابحث عن شعب أو قائمة UPG100 أو منطقة…",
|
||||
"tabPlaceholder": {
|
||||
"languageFamilies": "ابحث في عائلة اللغة أو اللغة أو اللهجة/التنوع",
|
||||
"affinityBlocks": "ابحث في كتلة التقارب أو المجموعة أو الشعب",
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@
|
|||
"block": "كتلة WAGF",
|
||||
"country": "الدولة",
|
||||
"upg100Region": "المنطقة",
|
||||
"upg100Zone": "قوائم UPG-100",
|
||||
"upg100Zone": "قوائم UPG100",
|
||||
"upg100Group": "مجموعة شعبية",
|
||||
"selectView": "اختر العرض",
|
||||
"views": "العروض",
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@
|
|||
"selectionCardsFailed": "فشل إنشاء بطاقات التحديد: {reason}",
|
||||
"selectionPosterNeedsZone": "الملصقات متاحة لكل منطقة في مفتاح الخريطة — استخدم «قائمة الصلاة» لتحديد على الخريطة",
|
||||
"mapDataFailed": "تعذّر تحميل بيانات الخريطة",
|
||||
"infoLead": "قائمة UPG-100 على خريطة واحدة: الشعوب غير المُبشَّرة، مجمّعة في مناطق يمكنك أن تتبنّاها بالصلاة.",
|
||||
"infoLead": "قائمة UPG100 على خريطة واحدة: الشعوب غير المُبشَّرة، مجمّعة في مناطق يمكنك أن تتبنّاها بالصلاة.",
|
||||
"infoTakeaway": "لكل منطقة: ملصق للحائط، وحزمة صلاة للتوزيع، ومجموعة من بطاقات الصلاة. المثال أدناه هو المنطقة التي تضم أكبر عدد من الناس في شعوب لا يعمل أحد بعد على غرس كنائس بينها.",
|
||||
"selectionColourGroup": "لون التحديد",
|
||||
"selectionColour": "تلوين التحديد {hex}",
|
||||
|
|
@ -16,8 +16,8 @@
|
|||
"copySelection": "نسخ",
|
||||
"exportCsv": "تصدير CSV",
|
||||
"copyNotRegroupable": "لا يمكن إعادة تجميعها معًا: انسخ ولايات أو مقاطعات بلد واحد، أو البلدان، كلًّا على حدة",
|
||||
"displayName": "ملصقات قائمة UPG 100",
|
||||
"wallHeading": "ملصقات قائمة UPG 100",
|
||||
"displayName": "ملصقات UPG100",
|
||||
"wallHeading": "ملصقات UPG100",
|
||||
"wallIntroA": "كيف تُطعم جمعًا من خمسة آلاف؟ أجلسهم يسوع جماعاتٍ من خمسين ومن مئة، فصار المستحيل قابلًا للمشاركة (لوقا ٩:١٤). فعلنا المثل مع {n} شعوب غير مبلَّغة: ٢٧ قائمة من نحو خمسين إلى مئة. تُطبع كل قائمة حزمةَ صلاة وملصقًا، ليحمل ٢٧ تلميذًا أو كنيسة أو قائدًا محليًا كلٌّ واحدة — مصلّين لأجلهم ",
|
||||
"peopleStillLoading": "لا تزال الشعوب قيد التحميل، حاول مرة أخرى بعد لحظة"
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@
|
|||
"gospelResources": "Evangeliumsressourcen",
|
||||
"languageFamilies": "Sprachfamilien",
|
||||
"prayer": "Gebetsfortschritt",
|
||||
"upg100List": "Meine UPG-100-Liste",
|
||||
"upg100List": "Meine UPG100-Liste",
|
||||
"batchSelect": "Mehrfachauswahl"
|
||||
},
|
||||
"header": {
|
||||
|
|
@ -58,8 +58,8 @@
|
|||
"languages": "Sprachen"
|
||||
},
|
||||
"tabInfo": {
|
||||
"upg100Region": "Region — sortiert die UPG-100-Listen nach Weltgegend (Afrika, Indien, Naher Osten, Gehörlose, …). Die Zahlen sind die UUPGs und die Bevölkerung aller darunterliegenden Listen zusammen.",
|
||||
"upg100Zone": "UPG-100-Listen — jede ist eine Gebetsliste der unerreichten Volksgruppen eines Gebiets und das, was die Karte zeichnet und einfärbt. Jede Liste wird als eigenes Heft gedruckt.",
|
||||
"upg100Region": "Region — sortiert die UPG100-Listen nach Weltgegend (Afrika, Indien, Naher Osten, Gehörlose, …). Die Zahlen sind die UUPGs und die Bevölkerung aller darunterliegenden Listen zusammen.",
|
||||
"upg100Zone": "UPG100-Listen — jede ist eine Gebetsliste der unerreichten Volksgruppen eines Gebiets und das, was die Karte zeichnet und einfärbt. Jede Liste wird als eigenes Heft gedruckt.",
|
||||
"upg100Group": "Volksgruppe — die einzelnen unerreichten Gruppen innerhalb einer Liste, größter Gebetsbedarf zuerst. Jeder Kartenpunkt ist eine davon.",
|
||||
"family": "Sprachfamilie — eine Gruppe von Sprachen gemeinsamen Ursprungs (z. B. indogermanisch, afroasiatisch).",
|
||||
"language": "Sprache — ein Verständigungssystem, das eine Volksgruppe verwendet (z. B. Arabisch, Bengalisch, Hindi).",
|
||||
|
|
@ -80,7 +80,7 @@
|
|||
},
|
||||
"export": {
|
||||
"poster": "Plakat",
|
||||
"packet": "UPG 100",
|
||||
"packet": "UPG100",
|
||||
"packetExplain": "Eine Gebetsliste von etwa 50 bis 100 unerreichten Volksgruppen — eine Person kann eine tragen.",
|
||||
"packetAria": "Detailgrad des Gebetspakets",
|
||||
"packetFull": "Vollständig",
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@
|
|||
"p2": "Finden Sie die Lücken. Wechseln Sie zu „Engagement“, um zu sehen, wo die Arbeit begonnen hat und wo noch niemand tätig ist. Diese Lücken sind die vorrangigen Zonen für die Mobilisierung.",
|
||||
"p3": "Erforschen Sie einen Teil der Welt nach dem anderen. Grenzen Sie nach Region, Sprache oder Religion ein, oder durchsuchen Sie die Liste nach Namen. Die Liste folgt der Karte, sodass Sie die Namen hinter den Punkten lesen können.",
|
||||
"p4": "Lernen Sie eine Volksgruppe kennen. Tippen Sie auf einen Punkt, um Land, Bevölkerung, Sprache und Religion zu sehen, und beginnen Sie dann mit „Für sie beten“, für dieses Volk namentlich zu beten.",
|
||||
"p5": "Halten Sie es einfach. Diese Karte verfolgt den Fortschritt auf einfache Weise, auf einen Blick. Für die vollständigen Daten gehen Sie zu „Gesamtbild“; für druckbare Gebetsmaterialien zu „Regionen“ oder „UPG-100-Liste“."
|
||||
"p5": "Halten Sie es einfach. Diese Karte verfolgt den Fortschritt auf einfache Weise, auf einen Blick. Für die vollständigen Daten gehen Sie zu „Gesamtbild“; für druckbare Gebetsmaterialien zu „Regionen“ oder „UPG100-Liste“."
|
||||
},
|
||||
"regions-dashboard": {
|
||||
"bottom": "Rund 170 Länder haben ihr eigenes Poster, Paket und Kartenset. Mobilisieren Sie für jedes Land eine Gruppe zum Gebet, und jedes Land ist im Gebet abgedeckt.",
|
||||
|
|
@ -22,7 +22,7 @@
|
|||
"p2": "Beginnen Sie in Ihrer Nähe, mit Jüngern und Gemeinden vor Ort. Gehen Sie dann zu den einheimischen Leitern und Mitarbeitern vor Ort in diesen Ländern, und schicken Sie ihnen Poster, Paket und Karten des Landes, damit sie dort gedruckt werden.",
|
||||
"p3": "Das Gebetspaket ist das strategischste der drei: alles, was man braucht, um für ein Land zu beten, in einem druckbaren Paket.",
|
||||
"p4": "Die Karten helfen am meisten, wenn Sie eine Gruppe haben, an die Sie sie verteilen: eine Volksgruppe pro Karte.",
|
||||
"p5": "Länderpakete passen zu einer größeren Mobilisierungsbasis oder zu einem Land, das Sie erreicht sehen wollen. Wenn die Mobilisierung schwer anläuft, sind die UPG-100-Listen der einfachere Anfang."
|
||||
"p5": "Länderpakete passen zu einer größeren Mobilisierungsbasis oder zu einem Land, das Sie erreicht sehen wollen. Wenn die Mobilisierung schwer anläuft, sind die UPG100-Listen der einfachere Anfang."
|
||||
},
|
||||
"prayer-map": {
|
||||
"bottom": "Eine Gebetsbewegung wächst, wenn jeder Partner dieselbe Karte zeigt. Stellen Sie diese Karte deshalb auf jede Website in Ihrem Netzwerk.",
|
||||
|
|
@ -36,7 +36,7 @@
|
|||
"bottom": "Jesus ließ die Fünftausend sich in Gruppen zu fünfzig und hundert setzen, bevor er sie speiste (Lukas 9,14). Diese Listen tun dasselbe für rund 2.100 unerreichte Volksgruppen: in Listen dieser Größe geteilt, wird die ganze Aufgabe zu einer Last, die ein Mensch tragen kann.",
|
||||
"p1": "27 Listen bedeuten 27 Poster, 27 Gebetspakete und 27 Kartensets. Geben Sie je eines 27 Jüngern, Gemeinden oder einheimischen Leitern, und für jede der Gruppen wird namentlich gebetet.",
|
||||
"p2": "Geben Sie jede Liste jemandem, der dranbleibt und für sie betet. Einheimische Leiter können in den Sprachen der Völker selbst beten.",
|
||||
"p3": "Das folgt einer in Bewegungen bewährten Praxis: Jünger beten regelmäßig für fünfzig bis hundert Menschen, die sie kennen (Familie, Freunde, Nachbarn, Kollegen, Mitschüler). Eine UPG-100-Liste ist dieselbe Last, für Menschen, denen sie nie begegnet sind.",
|
||||
"p3": "Das folgt einer in Bewegungen bewährten Praxis: Jünger beten regelmäßig für fünfzig bis hundert Menschen, die sie kennen (Familie, Freunde, Nachbarn, Kollegen, Mitschüler). Eine UPG100-Liste ist dieselbe Last, für Menschen, denen sie nie begegnet sind.",
|
||||
"p4": "Beginnen Sie mit einer Liste und einem Menschen. Das Paket enthält alles für diese Liste in einem Ausdruck, und die Karten helfen, wenn eine Gruppe sich die Liste teilt."
|
||||
},
|
||||
"cities-internet": {
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@
|
|||
"pinHint": {
|
||||
"tapDot": "Tippe auf einen farbigen Punkt — jemand braucht noch Gebet"
|
||||
},
|
||||
"upg100WallHeading": "Meine UPG-100-Liste — Gebetslisten und Poster",
|
||||
"upg100WallHeading": "Meine UPG100-Liste — Gebetslisten und Poster",
|
||||
"upg100WallTag": "Gebetsmobilisierung",
|
||||
"upg100WallIntroA": "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 2.106 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 ",
|
||||
"upg100WallIntroEmph": "mit dem Namen ihrer Volksgruppe",
|
||||
|
|
|
|||
|
|
@ -23,7 +23,7 @@
|
|||
"dialect": "Dialekt",
|
||||
"religionKind": "Religion"
|
||||
},
|
||||
"upg100Placeholder": "Volksgruppe, UPG-100-Liste oder Region suchen…",
|
||||
"upg100Placeholder": "Volksgruppe, UPG100-Liste oder Region suchen…",
|
||||
"tabPlaceholder": {
|
||||
"languageFamilies": "Sprachfamilie, Sprache, Dialekt/Varietät suchen",
|
||||
"affinityBlocks": "Affinitätsblock, Cluster, Volksgruppe suchen",
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@
|
|||
"block": "WAGF-Block",
|
||||
"country": "Land",
|
||||
"upg100Region": "Region",
|
||||
"upg100Zone": "UPG-100-Listen",
|
||||
"upg100Zone": "UPG100-Listen",
|
||||
"upg100Group": "Volksgruppe",
|
||||
"selectView": "Ansicht wählen",
|
||||
"views": "Ansichten",
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@
|
|||
"selectionCardsFailed": "Karten der Auswahl fehlgeschlagen: {reason}",
|
||||
"selectionPosterNeedsZone": "Plakate gibt es pro Gebiet in der Legende – nutzen Sie Gebetsliste für eine Auswahl auf der Karte",
|
||||
"mapDataFailed": "Die Kartendaten konnten nicht geladen werden",
|
||||
"infoLead": "Die UPG-100-Liste auf einer Karte: unerreichte Volksgruppen, zusammengefasst in Zonen, die Sie im Gebet übernehmen können.",
|
||||
"infoLead": "Die UPG100-Liste auf einer Karte: unerreichte Volksgruppen, zusammengefasst in Zonen, die Sie im Gebet übernehmen können.",
|
||||
"infoTakeaway": "für jede Zone ein Wandposter, ein Gebetsheft zum Weitergeben und ein Satz Gebetskarten. Das Beispiel unten ist die Zone mit den meisten Menschen in Volksgruppen, unter denen noch niemand Gemeinden gründet.",
|
||||
"selectionColourGroup": "Farbe der Auswahl",
|
||||
"selectionColour": "Auswahl einfärben: {hex}",
|
||||
|
|
@ -16,8 +16,8 @@
|
|||
"copySelection": "Kopieren",
|
||||
"exportCsv": "CSV exportieren",
|
||||
"copyNotRegroupable": "Nicht gemeinsam umgruppierbar: Bundesstaaten oder Provinzen eines Landes oder die Länder getrennt kopieren",
|
||||
"displayName": "Poster der UPG 100 Liste",
|
||||
"wallHeading": "Poster der UPG 100 Liste",
|
||||
"displayName": "UPG100-Poster",
|
||||
"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"
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@
|
|||
"gospelResources": "Gospel Resources",
|
||||
"languageFamilies": "Language Families",
|
||||
"prayer": "Prayer Progress",
|
||||
"upg100List": "My UPG 100 List",
|
||||
"upg100List": "My UPG100 List",
|
||||
"batchSelect": "Batch Select"
|
||||
},
|
||||
"header": {
|
||||
|
|
@ -58,8 +58,8 @@
|
|||
"languages": "Languages"
|
||||
},
|
||||
"tabInfo": {
|
||||
"upg100Region": "Region — sort the UPG-100 lists by world area (Africa, India, Middle East, Deaf, …). Counts are the UUPGs and population summed across every list beneath it.",
|
||||
"upg100Zone": "UPG-100 Lists — each one is a prayer list of the unreached people groups in an area, and is what the map paints and colours. Every list prints as its own packet.",
|
||||
"upg100Region": "Region — sort the UPG100 lists by world area (Africa, India, Middle East, Deaf, …). Counts are the UUPGs and population summed across every list beneath it.",
|
||||
"upg100Zone": "UPG100 Lists — each one is a prayer list of the unreached people groups in an area, and is what the map paints and colours. Every list prints as its own packet.",
|
||||
"upg100Group": "People Group — the individual unreached groups inside a list, largest prayer need first. Each map dot is one of these.",
|
||||
"family": "Lang Family — a group of languages descended from a common ancestor (e.g. Indo-European, Afro-Asiatic).",
|
||||
"language": "Language — a system of communication used by a people (e.g. Arabic, Bengali, Hindi).",
|
||||
|
|
@ -80,7 +80,7 @@
|
|||
},
|
||||
"export": {
|
||||
"poster": "Poster",
|
||||
"packet": "UPG 100",
|
||||
"packet": "UPG100",
|
||||
"packetExplain": "A prayer list of about 50 to 100 unreached people groups — one person can carry one.",
|
||||
"packetAria": "Prayer packet detail",
|
||||
"packetFull": "Full detail",
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@
|
|||
"p2": "Find the gaps. Switch to Engagement to see where work has begun and where no one is engaged yet. Those gaps are the priority zones to mobilize for.",
|
||||
"p3": "Research one part of the world at a time. Narrow by region, language or religion, or search the list by name. The list follows the map, so you can read the names behind the dots.",
|
||||
"p4": "Meet a people group. Tap a dot to see its country, population, language and religion, then use “Pray for them” to start praying for that people by name.",
|
||||
"p5": "Keep it simple. This map tracks progress at a simple level, at a glance. When you need the full data, go to Big Picture; for printable prayer resources, go to Regions or UPG-100."
|
||||
"p5": "Keep it simple. This map tracks progress at a simple level, at a glance. When you need the full data, go to Big Picture; for printable prayer resources, go to Regions or UPG100."
|
||||
},
|
||||
"regions-dashboard": {
|
||||
"bottom": "About 170 countries have their own poster, packet and card deck. Mobilize one group to pray for each country, and every country is covered in prayer.",
|
||||
|
|
@ -22,7 +22,7 @@
|
|||
"p2": "Start close to home, with local disciples and churches. Then go to the indigenous leaders and workers on the ground in those countries, and send them the country's poster, packet and cards to print where they are.",
|
||||
"p3": "The prayer packet is the most strategic of the three: everything needed to pray for a country, in one printable packet.",
|
||||
"p4": "The cards work best when you have a group to hand them to: one people group per card.",
|
||||
"p5": "Country packets suit a larger mobilization base, or one country you want to see reached. If mobilizing is slow going, the UPG-100 lists are the simpler place to begin."
|
||||
"p5": "Country packets suit a larger mobilization base, or one country you want to see reached. If mobilizing is slow going, the UPG100 lists are the simpler place to begin."
|
||||
},
|
||||
"prayer-map": {
|
||||
"bottom": "A prayer movement grows when every partner shows the same map, so place this map on every website in your network.",
|
||||
|
|
@ -36,7 +36,7 @@
|
|||
"bottom": "Jesus had the five thousand sit down in groups of fifty and a hundred before He fed them (Luke 9:14). These lists do the same for about 2,100 unreached people groups: split into lists that size, the whole task becomes a load one person can carry.",
|
||||
"p1": "27 lists means 27 posters, 27 prayer packets and 27 card decks. Put one in the hands of each of 27 disciples, churches or indigenous leaders, and every one of the groups is prayed for by name.",
|
||||
"p2": "Give each list to someone who will keep praying it. Indigenous leaders can pray in the people's own languages.",
|
||||
"p3": "This follows a practice proven in movements: disciples pray regularly for fifty to a hundred people they know (family, friends, neighbours, co-workers, classmates). A UPG-100 list is the same load, for people they have never met.",
|
||||
"p3": "This follows a practice proven in movements: disciples pray regularly for fifty to a hundred people they know (family, friends, neighbours, co-workers, classmates). A UPG100 list is the same load, for people they have never met.",
|
||||
"p4": "Start with one list and one person. The packet holds everything for that list in one printout, and the cards help when a group shares the list."
|
||||
},
|
||||
"cities-internet": {
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@
|
|||
"pinHint": {
|
||||
"tapDot": "Tap a coloured dot — someone still needs prayer"
|
||||
},
|
||||
"upg100WallHeading": "My UPG 100 List — Prayer Lists & Posters",
|
||||
"upg100WallHeading": "My UPG100 List — Prayer Lists & Posters",
|
||||
"upg100WallTag": "Prayer Mobilization",
|
||||
"upg100WallIntroA": "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 2,106 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 ",
|
||||
"upg100WallIntroEmph": "by their people group name",
|
||||
|
|
|
|||
|
|
@ -23,7 +23,7 @@
|
|||
"within": "Within {selection}",
|
||||
"allData": "All DOXA Data"
|
||||
},
|
||||
"upg100Placeholder": "Search people group, UPG-100 list, or region…",
|
||||
"upg100Placeholder": "Search people group, UPG100 list, or region…",
|
||||
"tabPlaceholder": {
|
||||
"languageFamilies": "Search language family, language, dialect/variety",
|
||||
"affinityBlocks": "Search affinity bloc, cluster, people group",
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@
|
|||
"block": "WAGF Bloc",
|
||||
"country": "Country",
|
||||
"upg100Region": "Region",
|
||||
"upg100Zone": "UPG-100 Lists",
|
||||
"upg100Zone": "UPG100 Lists",
|
||||
"upg100Group": "People Group",
|
||||
"selectView": "Select View",
|
||||
"views": "Views",
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@
|
|||
"selectionCardsFailed": "Selection card deck failed: {reason}",
|
||||
"selectionPosterNeedsZone": "Posters exist per territory on the legend — use Prayer List for a map selection",
|
||||
"mapDataFailed": "The map data could not be loaded",
|
||||
"infoLead": "The UPG-100 list on one map: unreached people groups, gathered into zones you can adopt in prayer.",
|
||||
"infoLead": "The UPG100 list on one map: unreached people groups, gathered into zones you can adopt in prayer.",
|
||||
"infoTakeaway": "for any zone, a wall poster, a prayer packet to hand out and a deck of prayer cards. The example below is the zone with the most people in groups where no one is planting churches yet.",
|
||||
"selectionColourGroup": "Selection colour",
|
||||
"selectionColour": "Colour the selection {hex}",
|
||||
|
|
@ -16,8 +16,8 @@
|
|||
"copySelection": "Copy",
|
||||
"exportCsv": "Export CSV",
|
||||
"copyNotRegroupable": "Can't be regrouped together: copy one country's states or provinces, or the countries, separately",
|
||||
"displayName": "UPG 100 List Posters",
|
||||
"wallHeading": "UPG 100 List Posters",
|
||||
"displayName": "UPG100 Posters",
|
||||
"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"
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@
|
|||
"gospelResources": "Recursos del Evangelio",
|
||||
"languageFamilies": "Familias lingüísticas",
|
||||
"prayer": "Progreso de oración",
|
||||
"upg100List": "Mi lista UPG 100",
|
||||
"upg100List": "Mi lista UPG100",
|
||||
"batchSelect": "Selección múltiple"
|
||||
},
|
||||
"header": {
|
||||
|
|
@ -58,8 +58,8 @@
|
|||
"languages": "Idiomas"
|
||||
},
|
||||
"tabInfo": {
|
||||
"upg100Region": "Región — ordena las listas UPG-100 por área mundial (África, India, Oriente Medio, Sordos, …). Los totales son los UUPG y la población sumados de todas las listas que contiene.",
|
||||
"upg100Zone": "Listas UPG-100 — cada una es una lista de oración de los grupos étnicos no alcanzados de un área, y es lo que el mapa pinta y colorea. Cada lista se imprime como su propio paquete.",
|
||||
"upg100Region": "Región — ordena las listas UPG100 por área mundial (África, India, Oriente Medio, Sordos, …). Los totales son los UUPG y la población sumados de todas las listas que contiene.",
|
||||
"upg100Zone": "Listas UPG100 — cada una es una lista de oración de los grupos étnicos no alcanzados de un área, y es lo que el mapa pinta y colorea. Cada lista se imprime como su propio paquete.",
|
||||
"upg100Group": "Grupo étnico — los grupos no alcanzados dentro de una lista, primero los de mayor necesidad de oración. Cada punto del mapa es uno de ellos.",
|
||||
"family": "Familia lingüística — un conjunto de lenguas procedentes de un antepasado común (p. ej. indoeuropea, afroasiática).",
|
||||
"language": "Idioma — un sistema de comunicación que usa un pueblo (p. ej. árabe, bengalí, hindi).",
|
||||
|
|
@ -80,7 +80,7 @@
|
|||
},
|
||||
"export": {
|
||||
"poster": "Cartel",
|
||||
"packet": "UPG 100",
|
||||
"packet": "UPG100",
|
||||
"packetExplain": "Una lista de oración de unos 50 a 100 pueblos no alcanzados: una persona puede llevar una.",
|
||||
"packetAria": "Detalle del paquete de oración",
|
||||
"packetFull": "Detalle completo",
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@
|
|||
"p2": "Encuentre los vacíos. Cambie a «Compromiso» para ver dónde ha comenzado el trabajo y dónde aún nadie está comprometido. Esos vacíos son las zonas prioritarias para movilizar.",
|
||||
"p3": "Investigue una parte del mundo a la vez. Reduzca por región, idioma o religión, o busque en la lista por nombre. La lista sigue al mapa, así que puede leer los nombres detrás de los puntos.",
|
||||
"p4": "Conozca a un grupo étnico. Toque un punto para ver su país, población, idioma y religión, y luego use «Ora por ellos» para empezar a orar por ese pueblo por su nombre.",
|
||||
"p5": "Manténgalo simple. Este mapa sigue el progreso a un nivel sencillo, de un vistazo. Si necesita los datos completos, vaya a «Panorama general»; para recursos de oración imprimibles, vaya a «Regiones» o a «Lista UPG-100»."
|
||||
"p5": "Manténgalo simple. Este mapa sigue el progreso a un nivel sencillo, de un vistazo. Si necesita los datos completos, vaya a «Panorama general»; para recursos de oración imprimibles, vaya a «Regiones» o a «Lista UPG100»."
|
||||
},
|
||||
"regions-dashboard": {
|
||||
"bottom": "Unos 170 países tienen su propio póster, paquete y baraja de tarjetas. Movilice un grupo para orar por cada país, y todos los países quedan cubiertos en oración.",
|
||||
|
|
@ -22,7 +22,7 @@
|
|||
"p2": "Empiece cerca de casa, con discípulos e iglesias locales. Luego vaya a los líderes y obreros autóctonos sobre el terreno en esos países, y envíeles el póster, el paquete y las tarjetas del país para imprimirlos allí donde están.",
|
||||
"p3": "El paquete de oración es el más estratégico de los tres: todo lo necesario para orar por un país, en un solo paquete imprimible.",
|
||||
"p4": "Las tarjetas sirven mejor cuando tiene un grupo al que repartirlas: un grupo étnico por tarjeta.",
|
||||
"p5": "Los paquetes por país convienen a una base de movilización más grande, o a un país que quiere ver alcanzado. Si movilizar cuesta, las listas UPG-100 son un comienzo más sencillo."
|
||||
"p5": "Los paquetes por país convienen a una base de movilización más grande, o a un país que quiere ver alcanzado. Si movilizar cuesta, las listas UPG100 son un comienzo más sencillo."
|
||||
},
|
||||
"prayer-map": {
|
||||
"bottom": "Un movimiento de oración crece cuando cada socio muestra el mismo mapa, así que ponga este mapa en cada sitio web de su red.",
|
||||
|
|
@ -36,7 +36,7 @@
|
|||
"bottom": "Jesús hizo sentar a los cinco mil en grupos de cincuenta y de cien antes de alimentarlos (Lucas 9:14). Estas listas hacen lo mismo con unos 2.100 grupos étnicos no alcanzados: divididos en listas de ese tamaño, toda la tarea se vuelve una carga que una persona puede llevar.",
|
||||
"p1": "27 listas son 27 pósteres, 27 paquetes de oración y 27 barajas de tarjetas. Ponga una en manos de cada uno de 27 discípulos, iglesias o líderes autóctonos, y se ora por cada uno de los grupos por su nombre.",
|
||||
"p2": "Entregue cada lista a alguien que siga orando por ella. Los líderes autóctonos pueden orar en los propios idiomas de los pueblos.",
|
||||
"p3": "Esto sigue una práctica probada en los movimientos: los discípulos oran con regularidad por cincuenta a cien personas que conocen (familia, amigos, vecinos, compañeros de trabajo y de estudios). Una lista UPG-100 es la misma carga, por personas que nunca han conocido.",
|
||||
"p3": "Esto sigue una práctica probada en los movimientos: los discípulos oran con regularidad por cincuenta a cien personas que conocen (familia, amigos, vecinos, compañeros de trabajo y de estudios). Una lista UPG100 es la misma carga, por personas que nunca han conocido.",
|
||||
"p4": "Empiece con una lista y una persona. El paquete contiene todo lo de esa lista en una sola impresión, y las tarjetas ayudan cuando un grupo se reparte la lista."
|
||||
},
|
||||
"cities-internet": {
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@
|
|||
"pinHint": {
|
||||
"tapDot": "Toca un punto de color: alguien todavía necesita oración"
|
||||
},
|
||||
"upg100WallHeading": "Mi lista UPG 100 — Listas de oración y carteles",
|
||||
"upg100WallHeading": "Mi lista UPG100 — Listas de oración y carteles",
|
||||
"upg100WallTag": "Movilización de oración",
|
||||
"upg100WallIntroA": "¿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 2.106 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 ",
|
||||
"upg100WallIntroEmph": "por el nombre de su pueblo",
|
||||
|
|
|
|||
|
|
@ -23,7 +23,7 @@
|
|||
"within": "Dentro de {selection}",
|
||||
"allData": "Todos los datos DOXA"
|
||||
},
|
||||
"upg100Placeholder": "Buscar pueblo, lista UPG-100 o región…",
|
||||
"upg100Placeholder": "Buscar pueblo, lista UPG100 o región…",
|
||||
"tabPlaceholder": {
|
||||
"languageFamilies": "Buscar familia lingüística, idioma, dialecto/variedad",
|
||||
"affinityBlocks": "Buscar bloque de afinidad, clúster, pueblo",
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@
|
|||
"block": "Bloque WAGF",
|
||||
"country": "País",
|
||||
"upg100Region": "Región",
|
||||
"upg100Zone": "Listas UPG-100",
|
||||
"upg100Zone": "Listas UPG100",
|
||||
"upg100Group": "Grupo étnico",
|
||||
"selectView": "Seleccionar vista",
|
||||
"views": "Vistas",
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@
|
|||
"selectionCardsFailed": "Error al generar las tarjetas de la selección: {reason}",
|
||||
"selectionPosterNeedsZone": "Hay carteles por territorio en la leyenda; usa Lista de oración para una selección en el mapa",
|
||||
"mapDataFailed": "No se pudieron cargar los datos del mapa",
|
||||
"infoLead": "La lista UPG-100 en un solo mapa: pueblos no alcanzados, agrupados en zonas que usted puede adoptar en oración.",
|
||||
"infoLead": "La lista UPG100 en un solo mapa: pueblos no alcanzados, agrupados en zonas que usted puede adoptar en oración.",
|
||||
"infoTakeaway": "para cada zona, un póster para la pared, un paquete de oración para repartir y un mazo de tarjetas de oración. El ejemplo de abajo es la zona con más personas en pueblos donde todavía nadie está plantando iglesias.",
|
||||
"selectionColourGroup": "Color de la selección",
|
||||
"selectionColour": "Colorear la selección {hex}",
|
||||
|
|
@ -16,8 +16,8 @@
|
|||
"copySelection": "Copiar",
|
||||
"exportCsv": "Exportar CSV",
|
||||
"copyNotRegroupable": "No se pueden reagrupar juntos: copia por separado los estados o provincias de un solo país, o los países",
|
||||
"displayName": "Carteles de la lista UPG 100",
|
||||
"wallHeading": "Carteles de la lista UPG 100",
|
||||
"displayName": "Carteles UPG100",
|
||||
"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"
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@
|
|||
"gospelResources": "Ressources de l'Évangile",
|
||||
"languageFamilies": "Familles de langues",
|
||||
"prayer": "Progression de la prière",
|
||||
"upg100List": "Ma liste UPG 100",
|
||||
"upg100List": "Ma liste UPG100",
|
||||
"batchSelect": "Sélection multiple"
|
||||
},
|
||||
"header": {
|
||||
|
|
@ -58,8 +58,8 @@
|
|||
"languages": "Langues"
|
||||
},
|
||||
"tabInfo": {
|
||||
"upg100Region": "Région — trie les listes UPG-100 par zone du monde (Afrique, Inde, Moyen-Orient, Sourds, …). Les totaux sont les UUPG et la population additionnés sur toutes les listes qu’elle contient.",
|
||||
"upg100Zone": "Listes UPG-100 — chacune est une liste de prière des groupes de peuples non atteints d’une zone, et c’est ce que la carte dessine et colore. Chaque liste s’imprime comme son propre livret.",
|
||||
"upg100Region": "Région — trie les listes UPG100 par zone du monde (Afrique, Inde, Moyen-Orient, Sourds, …). Les totaux sont les UUPG et la population additionnés sur toutes les listes qu’elle contient.",
|
||||
"upg100Zone": "Listes UPG100 — chacune est une liste de prière des groupes de peuples non atteints d’une zone, et c’est ce que la carte dessine et colore. Chaque liste s’imprime comme son propre livret.",
|
||||
"upg100Group": "Groupe de peuples — les groupes non atteints au sein d’une liste, les plus grands besoins de prière en premier. Chaque point de la carte en est un.",
|
||||
"family": "Famille linguistique — un ensemble de langues issues d’un ancêtre commun (p. ex. indo-européen, afro-asiatique).",
|
||||
"language": "Langue — un système de communication employé par un peuple (p. ex. arabe, bengali, hindi).",
|
||||
|
|
@ -80,7 +80,7 @@
|
|||
},
|
||||
"export": {
|
||||
"poster": "Affiche",
|
||||
"packet": "UPG 100",
|
||||
"packet": "UPG100",
|
||||
"packetExplain": "Une liste de prière d’environ 50 à 100 peuples non atteints : une personne peut en porter une.",
|
||||
"packetAria": "Niveau de détail du dossier de prière",
|
||||
"packetFull": "Détail complet",
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@
|
|||
"p2": "Trouvez les manques. Passez à « Engagement » pour voir où le travail a commencé et où personne n'est encore engagé. Ces manques sont les zones prioritaires à mobiliser.",
|
||||
"p3": "Étudiez une partie du monde à la fois. Resserrez par région, langue ou religion, ou cherchez dans la liste par nom. La liste suit la carte, et vous lisez les noms derrière les points.",
|
||||
"p4": "Rencontrez un peuple. Touchez un point pour voir son pays, sa population, sa langue et sa religion, puis utilisez « Priez pour eux » pour commencer à prier pour ce peuple par son nom.",
|
||||
"p5": "Restez simple. Cette carte suit les progrès à un niveau simple, d'un coup d'œil. Pour les données complètes, allez à « Vue d'ensemble » ; pour des ressources de prière à imprimer, allez à « Régions » ou à « Liste UPG-100 »."
|
||||
"p5": "Restez simple. Cette carte suit les progrès à un niveau simple, d'un coup d'œil. Pour les données complètes, allez à « Vue d'ensemble » ; pour des ressources de prière à imprimer, allez à « Régions » ou à « Liste UPG100 »."
|
||||
},
|
||||
"regions-dashboard": {
|
||||
"bottom": "Environ 170 pays ont leur propre affiche, leur dossier et leur jeu de cartes. Mobilisez un groupe pour prier pour chaque pays, et chaque pays est couvert par la prière.",
|
||||
|
|
@ -22,7 +22,7 @@
|
|||
"p2": "Commencez près de chez vous, avec les disciples et les Églises locales. Allez ensuite vers les responsables et les ouvriers autochtones sur le terrain dans ces pays, et envoyez-leur l'affiche, le dossier et les cartes du pays à imprimer là où ils sont.",
|
||||
"p3": "Le dossier de prière est le plus stratégique des trois : tout ce qu'il faut pour prier pour un pays, dans un seul dossier imprimable.",
|
||||
"p4": "Les cartes servent surtout quand vous avez un groupe à qui les distribuer : un peuple par carte.",
|
||||
"p5": "Les dossiers par pays conviennent à une base de mobilisation plus large, ou à un pays que vous voulez voir atteint. Si la mobilisation est lente, les listes UPG-100 sont un point de départ plus simple."
|
||||
"p5": "Les dossiers par pays conviennent à une base de mobilisation plus large, ou à un pays que vous voulez voir atteint. Si la mobilisation est lente, les listes UPG100 sont un point de départ plus simple."
|
||||
},
|
||||
"prayer-map": {
|
||||
"bottom": "Un mouvement de prière grandit quand chaque partenaire montre la même carte : placez donc cette carte sur chaque site de votre réseau.",
|
||||
|
|
@ -36,7 +36,7 @@
|
|||
"bottom": "Jésus a fait asseoir les cinq mille par groupes de cinquante et de cent avant de les nourrir (Luc 9.14). Ces listes font de même pour environ 2 100 peuples non atteints : découpée en listes de cette taille, toute la tâche devient une charge qu'une seule personne peut porter.",
|
||||
"p1": "27 listes, ce sont 27 affiches, 27 dossiers de prière et 27 jeux de cartes. Mettez-en un entre les mains de chacun de 27 disciples, Églises ou responsables autochtones, et chacun des groupes est porté dans la prière par son nom.",
|
||||
"p2": "Confiez chaque liste à quelqu'un qui continuera de prier pour elle. Les responsables autochtones peuvent prier dans les langues mêmes des peuples.",
|
||||
"p3": "Cela suit une pratique éprouvée dans les mouvements : les disciples prient régulièrement pour cinquante à cent personnes qu'ils connaissent (famille, amis, voisins, collègues, camarades). Une liste UPG-100 est la même charge, pour des gens qu'ils n'ont jamais rencontrés.",
|
||||
"p3": "Cela suit une pratique éprouvée dans les mouvements : les disciples prient régulièrement pour cinquante à cent personnes qu'ils connaissent (famille, amis, voisins, collègues, camarades). Une liste UPG100 est la même charge, pour des gens qu'ils n'ont jamais rencontrés.",
|
||||
"p4": "Commencez avec une liste et une personne. Le dossier contient tout ce qu'il faut pour cette liste en une impression, et les cartes aident quand un groupe se partage la liste."
|
||||
},
|
||||
"cities-internet": {
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@
|
|||
"pinHint": {
|
||||
"tapDot": "Touchez un point coloré — quelqu’un a encore besoin de prière"
|
||||
},
|
||||
"upg100WallHeading": "Ma liste UPG 100 — Listes de prière et affiches",
|
||||
"upg100WallHeading": "Ma liste UPG100 — Listes de prière et affiches",
|
||||
"upg100WallTag": "Mobilisation pour la prière",
|
||||
"upg100WallIntroA": "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 2 106 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 ",
|
||||
"upg100WallIntroEmph": "par le nom de leur peuple",
|
||||
|
|
|
|||
|
|
@ -23,7 +23,7 @@
|
|||
"within": "Dans {selection}",
|
||||
"allData": "Toutes les données DOXA"
|
||||
},
|
||||
"upg100Placeholder": "Rechercher un peuple, une liste UPG-100 ou une région…",
|
||||
"upg100Placeholder": "Rechercher un peuple, une liste UPG100 ou une région…",
|
||||
"tabPlaceholder": {
|
||||
"languageFamilies": "Rechercher une famille linguistique, une langue, un dialecte/une variété",
|
||||
"affinityBlocks": "Rechercher un bloc d’affinité, une grappe, un peuple",
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@
|
|||
"block": "Bloc WAGF",
|
||||
"country": "Pays",
|
||||
"upg100Region": "Région",
|
||||
"upg100Zone": "Listes UPG-100",
|
||||
"upg100Zone": "Listes UPG100",
|
||||
"upg100Group": "Groupe de peuples",
|
||||
"selectView": "Choisir la vue",
|
||||
"views": "Vues",
|
||||
|
|
|
|||