Compare commits
64 commits
doxa-maps-
...
wip/subdom
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
12d9db806c | ||
|
|
f8d788a07e | ||
|
|
ed957a2688 | ||
|
|
18e0c39ed9 | ||
|
|
fa3591ca9b | ||
|
|
bdac891e90 | ||
|
|
80b6cd5775 | ||
|
|
5dea900183 | ||
|
|
8770903270 | ||
|
|
226992541f | ||
|
|
d691b5401a | ||
|
|
ee1ad40926 | ||
|
|
a3ee6ae224 | ||
|
|
f837b43609 | ||
|
|
f3e4623216 | ||
|
|
7114d0a6fd | ||
|
|
fce82c17f8 | ||
|
|
ff1e2dcbe4 | ||
|
|
c1054993c6 | ||
|
|
afb13a151b | ||
|
|
6444a05203 | ||
|
|
89ce341c82 | ||
|
|
50dcf627ad | ||
|
|
0a0bfdf8b3 | ||
|
|
d5d72e8e76 | ||
|
|
6be3662b8a | ||
|
|
087ae5d8a0 | ||
|
|
d4daff02b9 | ||
|
|
bdf1061a28 | ||
|
|
a61b1e810a | ||
|
|
aeb61e64f7 | ||
|
|
3f5cf457b3 | ||
|
|
fc4d6228f8 | ||
|
|
c65b41633c | ||
|
|
d58700ddff | ||
|
|
18e61e92c2 | ||
|
|
766ab697c5 | ||
|
|
8e4c9285ab | ||
|
|
80cbfadb85 | ||
|
|
1128823172 | ||
|
|
0098a69d7e | ||
|
|
b30f3c39f4 | ||
|
|
87b835e312 | ||
|
|
0262bb4219 | ||
|
|
fb51cf738a | ||
|
|
2149a3874a | ||
|
|
516620bfa9 | ||
|
|
86abef3420 | ||
|
|
57f35d12b4 | ||
|
|
aa2f7dee92 | ||
|
|
55b21dcd80 | ||
|
|
ce33af390f | ||
|
|
9d05a039f8 | ||
|
|
a994baec4f | ||
|
|
10f63df2eb | ||
|
|
743714b21a | ||
|
|
0418c1e8b7 | ||
|
|
873c0c9cea | ||
|
|
5651aac6fd | ||
|
|
ab1244a230 | ||
|
|
2994ccd541 | ||
|
|
ca2addcfac | ||
|
|
cea9583792 | ||
|
|
4dfee08d13 |
228 changed files with 7276 additions and 41574 deletions
122
.claude/skills/add-language/SKILL.md
Normal file
122
.claude/skills/add-language/SKILL.md
Normal file
|
|
@ -0,0 +1,122 @@
|
|||
---
|
||||
name: add-language
|
||||
description: Bring a new language onto the marketing site — the config/languages.ts entry from its glossary record, the site strings, the map widget locales and bundles, the /about/definitions terminology edition, and the CMS pages. Use after the language has a glossary with reviewed terms. Invoke with /add-language <code>.
|
||||
user-invocable: true
|
||||
---
|
||||
|
||||
# Add a language to doxa.life
|
||||
|
||||
Argument: the language code. The language must already exist in the DOXA
|
||||
glossary, which is maintained in the campaigns server's admin and published at
|
||||
`https://pray.doxa.life/api/glossary/{code}`. That is where a language is born;
|
||||
this site follows it.
|
||||
|
||||
## 1. Refuse to start without a glossary
|
||||
|
||||
```bash
|
||||
curl -s -o /dev/null -w '%{http_code}\n' https://pray.doxa.life/api/glossary/{code}
|
||||
```
|
||||
|
||||
A 404 means the language has no terminology yet. Stop, and say what has to
|
||||
happen first: an admin adds it at `/admin/glossary` on pray.doxa.life, drafts
|
||||
its terms, and a reviewer confirms them. Copy written before that has to be
|
||||
rewritten after.
|
||||
|
||||
Read the whole glossary before writing anything, `notes` included.
|
||||
|
||||
## 2. Create the `config/languages.ts` entry
|
||||
|
||||
From the glossary record:
|
||||
|
||||
| Glossary field | Entry field |
|
||||
|---|---|
|
||||
| `language.name_en` | `name` |
|
||||
| `language.name_local` | `nativeName` |
|
||||
| `language.text_direction` | `dir: 'rtl'`, omitted when `ltr` |
|
||||
| `language.bible_id` | `bibleId` |
|
||||
|
||||
Ask the person for `flag`, and for `translationName` when the plain English name
|
||||
is ambiguous in a translation prompt. Set `latinHeadings: false` for any
|
||||
non-Latin script, so the site does not try to set headings in a display face
|
||||
that has no glyphs for it.
|
||||
|
||||
Add it with `enabled: false`. The language then has routes and can be worked on
|
||||
while the public switcher stays unchanged.
|
||||
|
||||
`hideFromSwitcher: true` is the middle state: routable and translated, but not
|
||||
offered until someone decides it is ready.
|
||||
|
||||
## 3. Site strings
|
||||
|
||||
`i18n/locales/{code}/common.json`, with exactly the key structure of
|
||||
`i18n/locales/en/common.json`.
|
||||
|
||||
Translate from English with the glossary and its notes in front of you. Never
|
||||
add or drop a key. Validate the JSON and compare the key set against English
|
||||
before moving on.
|
||||
|
||||
Missing keys fall back to English rather than showing a key, so a half-finished
|
||||
file is not obviously broken. Check the count, not the appearance.
|
||||
|
||||
## 4. The map widget
|
||||
|
||||
1. Copy `embeddables/micro-frontends/1040-maps/src/i18n/locales/en/` to
|
||||
`{code}/` and translate every file. `legend.json`, `search.json` and
|
||||
`prayerLaps.json` carry terminology; the rest is interface wording.
|
||||
2. Rebuild: `npm run build` inside `embeddables/micro-frontends/1040-maps/`,
|
||||
which writes `public/js/`.
|
||||
3. `public/js/pplr-data-maps.iife.js` has no build profile. If it carries
|
||||
per-language strings for the languages it supports, add this one by patching
|
||||
its literals in place; otherwise leave it and say so.
|
||||
|
||||
## 5. The terminology edition (`/about/definitions`)
|
||||
|
||||
Create `app/utils/terms/{code}.ts` from `en.ts` and register it in
|
||||
`app/utils/terms/index.ts`. A locale with no edition falls back to English.
|
||||
|
||||
**Entry parity is the rule:** the same 20 entries in the same order as `en.ts`.
|
||||
Per entry, fill what applies — the chosen term, the English original, the
|
||||
definition, the alternatives considered, what Joshua Project and
|
||||
PeopleGroups.org use, and a rationale that cites this language's reference Bible
|
||||
wherever the choice is Scripture-driven. An entry that needed no real decision
|
||||
in this language still appears, with its definition and a one-line rationale.
|
||||
|
||||
Two rendering rules already encoded in `app/pages/about/definitions.vue` that a new edition
|
||||
must not break: entries stay flat children of `.page-body`, because the site's
|
||||
typography uses direct-child selectors and a global rule gives every `<section>`
|
||||
landing-page padding; and a space at the edge of a `<template>` fragment has to
|
||||
be interpolated as `{{ ' ' }}` or Vue's whitespace handling strips it.
|
||||
|
||||
## 6. CMS pages
|
||||
|
||||
Pages live in this site's database. Create the translations through the
|
||||
`doxa-cms` MCP server at `https://doxa.life/mcp`.
|
||||
|
||||
- `list_pages(locale: "en", status: "any", limit: 100)` for the set to
|
||||
translate. Match the set an established language already has rather than
|
||||
translating everything: signed letters and one-off event pages are
|
||||
deliberately left in English.
|
||||
- `upsert_page_translation` creates a draft. `publish_translation` is a separate
|
||||
call, and publishing is the person's decision, not yours. Draft everything,
|
||||
then ask.
|
||||
- Edit `body_json` on any page reported lossy, any page with links, and any page
|
||||
whose heading begins with a line break.
|
||||
- One subagent per page works well, each given the glossary, the language's
|
||||
notes, and the register. Follow it with a pass across all the pages together,
|
||||
because per-page agents diverge on wording the glossary does not fix.
|
||||
|
||||
## 7. Switch it on
|
||||
|
||||
Set `enabled: true` once the site strings and the map locales are done. Then run
|
||||
`npx nuxi typecheck`, start the dev server, and read the home page, a people
|
||||
group page, the adopt flow and `/{code}/about/definitions` end to end. For a right-to-left
|
||||
language, confirm the layout mirrors.
|
||||
|
||||
The typecheck baseline is 122 pre-existing errors in the external layers and
|
||||
`server/api/maps/token.get.ts`. None of them are yours.
|
||||
|
||||
## 8. Report
|
||||
|
||||
What was added, what is still English, which CMS pages are drafted and awaiting
|
||||
a decision to publish, and anything a reviewer must answer. Repository changes
|
||||
stay uncommitted.
|
||||
112
.claude/skills/sync-language/SKILL.md
Normal file
112
.claude/skills/sync-language/SKILL.md
Normal file
|
|
@ -0,0 +1,112 @@
|
|||
---
|
||||
name: sync-language
|
||||
description: Bring the marketing site's existing text for one language into line with the current DOXA glossary — site strings, the map widget locales and their bundles, the /about/definitions terminology edition, and the published CMS pages. Use after a reviewer confirms or changes terminology. Invoke with /sync-language <code>.
|
||||
user-invocable: true
|
||||
---
|
||||
|
||||
# Align doxa.life with the glossary
|
||||
|
||||
Argument: a language code this site already carries. For a new one, use
|
||||
`/add-language`.
|
||||
|
||||
## 1. Read the glossary
|
||||
|
||||
```bash
|
||||
curl -s https://pray.doxa.life/api/glossary/{code}?format=markdown
|
||||
```
|
||||
|
||||
The glossary lives in the campaigns server's admin, where reviewers confirm each
|
||||
term through a magic link, and it is authoritative for every DOXA property. The
|
||||
response also carries `notes`: this language's register, its acronym policy, its
|
||||
number format and its script rules. Read those first; they decide how the terms
|
||||
are used.
|
||||
|
||||
A `draft` term is still authoritative — it is wording nobody has ruled on yet,
|
||||
not wording to ignore.
|
||||
|
||||
An acronym is a field of its own. The wording never carries it, so a term
|
||||
published as `Unreached people group (UPG) → grupo étnico não alcançado (PNA)`
|
||||
gives the phrase `grupo étnico não alcançado` and, separately, the acronym
|
||||
`PNA`. A bare acronym in a string — `Find a UUPG`, the map legend's `UUPGs` —
|
||||
takes this language's acronym, which is the English one unless a reviewer chose
|
||||
another.
|
||||
|
||||
## 2. Establish what here was written by a human
|
||||
|
||||
This matters more on this site than anywhere else. Several languages' copy was
|
||||
reviewed by a native-speaking volunteer, and their review documents are not in
|
||||
the repository. `git log` on the locale file and a look at whether the prose
|
||||
reads like a person wrote it are the available evidence. **Ask.**
|
||||
|
||||
**Precedence, highest first:** the reviewer's later notes, then the glossary,
|
||||
then wording a human reviewer approved, then anything AI-generated.
|
||||
|
||||
On reviewed copy, change only a glossary term or an outright defect. Keep their
|
||||
register, their phrasing, their headings. Where the glossary contradicts a
|
||||
reviewed sentence, change the term inside that sentence and leave the rest.
|
||||
|
||||
On machine-translated copy, fix the defects too. Past sweeps have found
|
||||
mistranslations that no reviewer ever saw, not just terminology.
|
||||
|
||||
## 3. Site strings
|
||||
|
||||
`i18n/locales/{code}/common.json`.
|
||||
|
||||
Script the replacements with explicit old-to-new pairs, assert each matches,
|
||||
never change a key, and validate the JSON afterwards. Then grep `app/` and
|
||||
`server/` for the old wording in case a term is hardcoded.
|
||||
|
||||
## 4. The map widget
|
||||
|
||||
Three layers, and all three have to move together or the site shows two
|
||||
vocabularies on one page.
|
||||
|
||||
1. **Source locales** — `embeddables/micro-frontends/1040-maps/src/i18n/locales/{code}/`.
|
||||
`legend.json`, `search.json` and `prayerLaps.json` carry the terminology.
|
||||
These were never human-reviewed, so they follow the glossary outright.
|
||||
2. **Built bundles** — rebuild with `npm run build` inside
|
||||
`embeddables/micro-frontends/1040-maps/`, which writes `public/js/`.
|
||||
3. **`public/js/pplr-data-maps.iife.js`** — has no build profile and carries an
|
||||
older snapshot of the strings. Patch its literals in place with a regex
|
||||
against the minified file. Do not copy source strings in blind: its wording
|
||||
can differ from the current source. Anchor on a nearby unique literal,
|
||||
because several locales' blocks sit within a few kilobytes of each other.
|
||||
|
||||
## 5. The terminology edition (`/about/definitions`)
|
||||
|
||||
`app/utils/terms/{code}.ts`, registered in `app/utils/terms/index.ts`. It
|
||||
documents this language's terminology decisions: the chosen term, the
|
||||
alternatives considered, what Joshua Project and PeopleGroups.org use, and why.
|
||||
|
||||
Every edition carries the same 20 entries in the same order as `en.ts`. Keep
|
||||
that parity. Update any entry the glossary has moved, and state plainly in the
|
||||
rationale where the glossary and the language's reference Bible disagree rather
|
||||
than quietly picking one.
|
||||
|
||||
## 6. CMS pages
|
||||
|
||||
Pages on doxa.life live in this site's database, not in the repository. Edit
|
||||
them through the `doxa-cms` MCP server at `https://doxa.life/mcp`, which needs
|
||||
an OAuth login with `pages.view` and `pages.write`.
|
||||
|
||||
- `list_pages(locale: "{code}", status: "any", limit: 100)` to find them.
|
||||
- `get_page_translation(page_id, "{code}")`, fix, `upsert_page_translation`.
|
||||
- **Never pass `status` on a published page.** One row holds each page and
|
||||
locale, and the site serves only `published`; passing `draft` takes the page
|
||||
off the live site. Omitting it keeps the page published, which also means
|
||||
**every edit is live the moment it saves**. Say this to the person before the
|
||||
first write.
|
||||
- Edit `body_json`, not markdown, on any page reported lossy, on any page with
|
||||
links, and on any page whose heading starts with a line break. A markdown
|
||||
save rewrites link attributes and drops trailing breaks even on a page
|
||||
reported clean.
|
||||
- Run replacements against the fetched body with an assertion that each matches
|
||||
exactly once, so untouched prose cannot drift.
|
||||
- Responses are cached for an hour at the origin. Verify an edit with a
|
||||
cache-busting query parameter.
|
||||
|
||||
## 7. Report
|
||||
|
||||
Per surface: terms changed, defects fixed, what was deliberately left, what a
|
||||
reviewer still owes an answer on. Repository changes stay uncommitted; CMS
|
||||
pages are already live and must be reported as such.
|
||||
42
.env.example
42
.env.example
|
|
@ -5,10 +5,12 @@ NUXT_PUBLIC_SITE_URL=http://localhost:3000
|
|||
|
||||
JWT_SECRET=your-super-secret-jwt-key-change-this
|
||||
|
||||
MAILGUN_API_KEY=your-mailgun-api-key
|
||||
MAILGUN_DOMAIN=mg.yourdomain.com
|
||||
# Optional: Use 'api.eu.mailgun.net' for EU region
|
||||
MAILGUN_HOST=
|
||||
# SendGrid (transactional email: invites, password resets, verification).
|
||||
# Sends through the v3 JSON API. The From address in SMTP_FROM must be on a
|
||||
# domain authenticated in the SendGrid account.
|
||||
SENDGRID_API_KEY=your-sendgrid-api-key
|
||||
# Optional API host override; defaults to api.sendgrid.com (use api.eu.sendgrid.com for EU)
|
||||
SENDGRID_HOST=
|
||||
SMTP_FROM=noreply@yourdomain.com
|
||||
SMTP_FROM_NAME=My App
|
||||
|
||||
|
|
@ -26,17 +28,38 @@ NUXT_PRAY_BASE_URL=https://pray.doxa.life
|
|||
NUXT_PUBLIC_PRAY_BASE_URL=https://pray.doxa.life
|
||||
FORM_API_KEY=your-form-api-key
|
||||
|
||||
# DOXA Prayer App store listings (app promo section on /pray and the research
|
||||
# people group pages). Leave MOBILE_APP_APPLE_ID empty to hide the App Store
|
||||
# badge until the iOS app is live.
|
||||
MOBILE_APP_APPLE_ID=
|
||||
MOBILE_APP_ANDROID_PACKAGE=life.doxa.pray
|
||||
|
||||
# Mapbox (used by the prayer map on /pray)
|
||||
NUXT_PUBLIC_MAPBOX_TOKEN=your-mapbox-public-token
|
||||
|
||||
# The subdomain branch's two addresses, per deployment. Both are REQUIRED, and both are read by the
|
||||
# server at REQUEST time (server/utils/dx-runtime.ts). They are never baked into a build, so one build
|
||||
# serves any deployment. Changing them needs a restart, not a rebuild. There is no default host: when
|
||||
# one is unset, the pages that need it say which setting is missing.
|
||||
#
|
||||
# The Research Gallery: the research site on its own subdomain, served by the team's dx-maps container.
|
||||
# The menu's Research item, every in-page gallery link and the /regions index go here (through this
|
||||
# site's /research-gallery).
|
||||
# VPS: NUXT_PUBLIC_RESEARCH_GALLERY_URL=https://research.<host>/
|
||||
# laptop: NUXT_PUBLIC_RESEARCH_GALLERY_URL=http://research.localhost:4615/
|
||||
NUXT_PUBLIC_RESEARCH_GALLERY_URL=
|
||||
#
|
||||
# The dx-maps tree this site's maps load from: the container's published tree, which the research
|
||||
# subdomain serves at /dx-maps. It must send Access-Control-Allow-Origin for the tree (the container
|
||||
# does). The Studio's own host serves the same tree at /cdn/dx-maps.
|
||||
# VPS: NUXT_PUBLIC_DX_MAPS_BASE=https://research.<host>/dx-maps
|
||||
# laptop: NUXT_PUBLIC_DX_MAPS_BASE=http://research.localhost:4615/dx-maps
|
||||
NUXT_PUBLIC_DX_MAPS_BASE=
|
||||
|
||||
# Cloudflare Turnstile
|
||||
NUXT_TURNSTILE_SITE_KEY=your-turnstile-site-key
|
||||
NUXT_TURNSTILE_SECRET_KEY=your-turnstile-secret-key
|
||||
|
||||
# Feedback widget (site-wide chat bubble). No PROJECT_ID = widget not rendered.
|
||||
NUXT_PUBLIC_FEEDBACK_API_BASE=https://support.example.org
|
||||
NUXT_PUBLIC_FEEDBACK_PROJECT_ID=your-feedback-project-id
|
||||
|
||||
# Statinator analytics (self-hosted tracking-server)
|
||||
# Project must exist on the tracking-server with this site's hostname in allowed_domains.
|
||||
# Set NUXT_PUBLIC_STATINATOR_ENABLED=false (or unset) to disable tracking entirely.
|
||||
|
|
@ -78,3 +101,6 @@ MCP_LAYER_PATH=
|
|||
# MCP server identity advertised in the `initialize` response.
|
||||
MCP_SERVER_NAME=marketing-rebuild
|
||||
MCP_SERVER_VERSION=1.0.0
|
||||
|
||||
# The map engine for every map: maplibre (keyless, the default) or mapbox (needs NUXT_PUBLIC_MAPBOX_TOKEN).
|
||||
# NUXT_PUBLIC_MAP_PROVIDER=maplibre
|
||||
|
|
|
|||
2
.gitignore
vendored
2
.gitignore
vendored
|
|
@ -49,5 +49,5 @@ embeddables/micro-frontends/_template/
|
|||
|
||||
package-lock.json
|
||||
plans
|
||||
.claude
|
||||
.claude/settings.local.json
|
||||
.vscode
|
||||
|
|
|
|||
105
DX-MAPS-GALLERY.md
Normal file
105
DX-MAPS-GALLERY.md
Normal file
|
|
@ -0,0 +1,105 @@
|
|||
# Research Gallery on /research, and every map served from /dx-maps/
|
||||
|
||||
This branch replaces the Research page with the **Research Gallery**: the research maps, dashboards
|
||||
and lists in one app, filling the page below the site header, on desktop and phone. Every other map
|
||||
on the site now loads from the same build tree.
|
||||
|
||||
## What changed
|
||||
|
||||
| | |
|
||||
|---|---|
|
||||
| `public/dx-maps/` | **Removed on this branch** (see *Deployment method* below): every map loads from the maps CDN. The drop-in branch keeps this folder and serves the tree same-origin. |
|
||||
| `app/pages/research/index.vue` | **The Research Gallery.** The page loads one script (`/dx-maps/doxa-maps-spa/doxa-maps-spa.js`) and adds one element (`<doxa-maps-spa>`), sized to the viewport below the header; its `tree-base` is built at runtime from the page's own origin. The previous content (the "By Region" link, the single research map and the UUPG list) is **kept but switched off**: set `SHOW_LEGACY_RESEARCH = true` in the page to bring it back. |
|
||||
| `app/composables/useDoxaMap.ts` | The home (engagement), pray (prayer) and adopt (adoption) maps now load `/dx-maps/doxa-simple-map/doxa-simple-map.js`; the research-map key loads `/dx-maps/doxa-research-map/doxa-research-map.js`. Mapbox GL moves from v3.3.0 to v3.24.0, the version the dx-maps bundles are built and tested with. |
|
||||
| `app/components/DoxaMapSlot.vue` | With no Mapbox token configured, it asks the map for the keyless MapLibre engine (see **Map engine**). With a token, the config passes through unchanged. |
|
||||
| `public/embed/map/index.html`, `public/research/doxa-research-map.html` | The same: bundles from `/dx-maps/`, Mapbox GL v3.24.0. |
|
||||
| `public/js/doxa-simple-map.js`, `public/js/doxa-research-map.js` | **Kept, unused.** No page loads them any more (every map loads from `/dx-maps/`), but they stay in place so nothing DX-life relied on is deleted. |
|
||||
|
||||
Unchanged on purpose: the element names (`<doxa-map>`, `<doxa-research-map>`, `<doxa-maps-spa>`)
|
||||
and `nuxt.config.ts` (its `isCustomElement` lists only those names). `public/js/pplr-data-maps.iife.js`
|
||||
and `/research/pplr-data-maps.html` are a separate showcase with no dx-maps equivalent, so they are
|
||||
also unchanged.
|
||||
|
||||
**Language.** The gallery follows the site's language and the language switcher (all 11 locales;
|
||||
Arabic lays out right-to-left).
|
||||
|
||||
**Map engine.** If `NUXT_PUBLIC_MAPBOX_TOKEN` is set, every map uses Mapbox with that token, as
|
||||
before. If it is not set (for example, a fresh laptop with no `.env`), every map (the Research
|
||||
gallery and the home, pray and adopt maps) uses the keyless MapLibre engine (OpenFreeMap tiles)
|
||||
instead of refusing to start. So the whole site's maps work with no secrets at all.
|
||||
|
||||
**Footer.** The gallery is a full-page app: it fills exactly the space between the header and the
|
||||
bottom of the screen. The site footer is kept, directly below it, where a scroll reaches it. So the
|
||||
app is never squeezed, and the footer's links stay on the page.
|
||||
|
||||
**Phone.** The gallery opens straight on a map (Simple Research). Its list of views sits behind the
|
||||
☰ button. Big Picture is marked **Desktop only** there (it needs a wide screen); every other view
|
||||
works on a phone.
|
||||
|
||||
## Run it
|
||||
|
||||
```bash
|
||||
bun install
|
||||
bun run dev
|
||||
```
|
||||
|
||||
Then open <http://localhost:3000/research/> (Nuxt prints the port if 3000 is taken). The maps need
|
||||
one setting, the published tree they load from: `NUXT_PUBLIC_DX_MAPS_BASE` (see *Deployment method*
|
||||
below; any published tree works, for example `https://research.<host>/dx-maps`). Without it, each map
|
||||
says which setting is missing. No database is needed for this page: without `DATABASE_URL`, the dev
|
||||
server only logs "skipping migrations".
|
||||
|
||||
- Arabic: <http://localhost:3000/ar/research/>
|
||||
- Open a specific view: `/research/?tab=prayer-map` (also `research-map-plus-grid`,
|
||||
`regions-dashboard`, `upg-100`, and so on).
|
||||
- Share and embed links in the maps point at this site's own `/dx-maps/` pages.
|
||||
- To run it against a **local** dx-maps, and to try the three routes a site can take the gallery (drop-in,
|
||||
subdomain and Plugin Studio) with the exact ports and settings: [documentation/LAPTOP-6WAY.md](documentation/LAPTOP-6WAY.md).
|
||||
|
||||
## Deployment method: the Research Gallery on its own subdomain (this branch, research-gallery-subdomain)
|
||||
|
||||
The research subdomain is the **research site**, served by the team's dx-maps container (the same
|
||||
container runs the signed-in Plugin Studio and PocketBase, and publishes the maps). It carries every
|
||||
research map, dashboard and list. This site sends readers there and loads its own maps from the
|
||||
container's published tree. Each deployment sets two addresses, read by the server at **request
|
||||
time** and never baked into a build:
|
||||
|
||||
| Setting | What it is | VPS | Laptop |
|
||||
|---|---|---|---|
|
||||
| `NUXT_PUBLIC_RESEARCH_GALLERY_URL` | the research site | `https://research.<host>/` | `http://research.localhost:4615/` |
|
||||
| `NUXT_PUBLIC_DX_MAPS_BASE` | the container's published tree, where this site's maps load from | `https://research.<host>/dx-maps` | `http://research.localhost:4615/dx-maps` |
|
||||
|
||||
The research subdomain serves the published tree at `/dx-maps`, and the Studio's own host serves the
|
||||
same tree at `/cdn/dx-maps`. Either works; both send CORS for it.
|
||||
|
||||
**Why request time.** About 4,000 pages are prerendered, and a prerendered page carries the build's
|
||||
runtime config. An address read there would be baked into the build, which is how the CDN branch
|
||||
failed. So neither setting is in `nuxt.config.ts`:
|
||||
- **Links:** the menu's **Research** item, every in-page gallery link and the `/regions` and
|
||||
`/countries` index pages go to this site's own `/research-gallery?tab=…&lang=…`. The server
|
||||
redirects that (302) to the deployment's gallery (`server/routes/research-gallery.get.ts`).
|
||||
- **Maps:** every map (the home, pray and adopt maps, `/embed-test`, `/research`, and the static pages
|
||||
under `public/`) first asks this site's server for the tree (`GET /api/dx-runtime`), then loads its
|
||||
bundle from there.
|
||||
- **Old links:** old `/js/doxa-maps/…` links are redirected per request to the same path in the tree
|
||||
(`server/middleware/legacy-map-links.ts`).
|
||||
|
||||
When a setting is unset there is no fallback host. `/research-gallery` answers 503 and the maps say
|
||||
which setting to set. Changing an address needs a restart, not a rebuild.
|
||||
|
||||
The menu no longer lists this site's Research page or its **Regions** page. The Regions item is
|
||||
switched off with `off: true` in `app/utils/nav.ts`, not deleted. `/research` is kept, unlinked, and
|
||||
the region and country detail pages stay. No iframe is used.
|
||||
|
||||
## /embed-test
|
||||
|
||||
`/embed-test` embeds **every web plugin** in the dx-maps tree, as JavaScript (no iframe). The list is read
|
||||
at runtime from the tree's `manifest.json`, never typed: section 1 is every profile with `stage: production`,
|
||||
section 2 every other profile. A profile whose `targets` leave out `web` (a desktop-only plugin, such as
|
||||
Rudder) is skipped. Each card loads its bundle's script and adds the element that bundle defines. A card
|
||||
mounts its plugin when it scrolls into view and removes it when it leaves (browsers allow only a few WebGL
|
||||
maps at once). `?only=<bundle>/<profile>` (or a bundle name, comma-separated) shows just those.
|
||||
|
||||
## Updating the maps
|
||||
|
||||
Nothing to do on this site: the CDN serves the current tree.
|
||||
40
app/app.vue
40
app/app.vue
|
|
@ -1,45 +1,5 @@
|
|||
<script setup lang="ts">
|
||||
// Site-wide feedback widget. It lives here (outside NuxtLayout) so it renders
|
||||
// on every layout — public, admin and auth. It stays opted out by default and
|
||||
// surfaces only when the visitor opts in: via ?feedback=true or by logging in.
|
||||
// Both set the component's `show-feedback-widget` localStorage flag (login is
|
||||
// wired in useAuth). This is the only feedback widget on the site.
|
||||
// Destination comes from NUXT_PUBLIC_FEEDBACK_API_BASE / _PROJECT_ID. With no
|
||||
// project id there is nowhere to post, so the widget and its bundle are skipped.
|
||||
const { public: pub } = useRuntimeConfig()
|
||||
const feedbackEnabled = Boolean(pub.feedbackProjectId)
|
||||
|
||||
if (feedbackEnabled) useFeedbackScript()
|
||||
|
||||
const siteFeedbackConfig = JSON.stringify({
|
||||
profile: 'chat-bubble',
|
||||
apiBase: pub.feedbackApiBase,
|
||||
enabled: true,
|
||||
showByDefault: false,
|
||||
instanceId: 'fb-site',
|
||||
projectId: pub.feedbackProjectId
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<NuxtLayout>
|
||||
<NuxtPage />
|
||||
</NuxtLayout>
|
||||
<ClientOnly>
|
||||
<div
|
||||
v-if="feedbackEnabled"
|
||||
class="site-feedback-widget"
|
||||
>
|
||||
<feedback-web-component :profile-config="siteFeedbackConfig" />
|
||||
</div>
|
||||
</ClientOnly>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
.site-feedback-widget {
|
||||
position: fixed;
|
||||
right: 16px;
|
||||
bottom: 16px;
|
||||
z-index: 2147483647;
|
||||
}
|
||||
</style>
|
||||
|
|
|
|||
|
|
@ -56,10 +56,19 @@
|
|||
position: relative;
|
||||
overflow: hidden;
|
||||
border-radius: var(--border-radius-lg);
|
||||
// An <iframe> is composited in its own layer: `overflow: hidden` + `border-radius` on the
|
||||
// parent does not clip it in Chrome until the layer tree settles after the frame paints,
|
||||
// so the map showed square corners until it loaded and rounded ones after. clip-path is
|
||||
// applied at paint time regardless of compositing, and the iframe carries the radius too.
|
||||
clip-path: inset(0 round var(--border-radius-lg));
|
||||
isolation: isolate;
|
||||
|
||||
iframe {
|
||||
display: block;
|
||||
width: 100%;
|
||||
height: 20rem;
|
||||
border: 0;
|
||||
border-radius: inherit;
|
||||
}
|
||||
|
||||
.overlay {
|
||||
|
|
@ -199,11 +208,6 @@
|
|||
}
|
||||
}
|
||||
|
||||
.uupg__content {
|
||||
display: none;
|
||||
grid-area: content;
|
||||
}
|
||||
|
||||
.uupg__more-button {
|
||||
grid-area: footer;
|
||||
align-self: flex-end;
|
||||
|
|
|
|||
|
|
@ -52,3 +52,16 @@
|
|||
padding: 0.25rem 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* Language dropdown in the desktop nav: the shared .main-navigation .sub-menu
|
||||
padding is sized for wide content menus and leaves the short language rows
|
||||
floating in whitespace, so tighten it to list proportions. */
|
||||
.main-navigation {
|
||||
.pll-parent-menu-item > .sub-menu {
|
||||
padding: var(--spacing-2xs) 0;
|
||||
}
|
||||
|
||||
.pll-parent-menu-item > .sub-menu > li > a {
|
||||
padding: var(--spacing-2xs) var(--spacing-xs);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ textarea,
|
|||
select,
|
||||
input,
|
||||
.input {
|
||||
border: 1px solid var(--input-border-color);
|
||||
border: 1px solid gray;
|
||||
border-radius: 8px;
|
||||
background-color: var(--color-surface-white);
|
||||
width: 100%;
|
||||
|
|
@ -127,6 +127,43 @@ input[type=radio] {
|
|||
fill: var(--color-brand-secondary-light);
|
||||
}
|
||||
|
||||
/* Required-field marker: the red asterisk that follows a label's text. */
|
||||
.required-marker {
|
||||
color: var(--color-status-error);
|
||||
margin-inline-start: 0.15em;
|
||||
}
|
||||
|
||||
/* Per-field validation message, rendered directly under the field it belongs to. */
|
||||
.field-error {
|
||||
color: var(--color-status-error);
|
||||
font-size: var(--font-size-xs);
|
||||
}
|
||||
|
||||
/* Quieter form chrome: field outlines drop to the weight of placeholder text so
|
||||
the labels lead instead of the boxes. Opt in per form, not site-wide. */
|
||||
.form--quiet {
|
||||
textarea,
|
||||
select,
|
||||
input,
|
||||
.input {
|
||||
border-color: var(--input-border-color-muted);
|
||||
}
|
||||
}
|
||||
|
||||
/* Opt-in row: a switch beside small print, rather than a checkbox beside a label. */
|
||||
.form-consent {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: var(--spacing-sm);
|
||||
|
||||
& .form-consent__label {
|
||||
font-size: var(--font-size-sm);
|
||||
color: var(--color-text-muted);
|
||||
max-width: 60ch;
|
||||
cursor: pointer;
|
||||
}
|
||||
}
|
||||
|
||||
.contact-message {
|
||||
&.error {
|
||||
color: var(--color-error, #c00);
|
||||
|
|
|
|||
|
|
@ -25,49 +25,9 @@
|
|||
}
|
||||
|
||||
|
||||
.stack-spacing-3xs,
|
||||
.stack--3xs > * + * {
|
||||
--stack-spacing: var(--spacing-3xs, 0.25rem);
|
||||
}
|
||||
|
||||
.stack-spacing-2xs,
|
||||
.stack--2xs > * + * {
|
||||
--stack-spacing: var(--spacing-2xs, 0.25rem);
|
||||
}
|
||||
|
||||
.stack-spacing-xs,
|
||||
.stack--xs > * + * {
|
||||
--stack-spacing: var(--spacing-xs, 0.5rem);
|
||||
}
|
||||
|
||||
.stack-spacing-sm,
|
||||
.stack--sm > * + * {
|
||||
--stack-spacing: var(--spacing-sm, 0.5rem);
|
||||
}
|
||||
|
||||
.stack-spacing-lg,
|
||||
.stack--lg > * + * {
|
||||
--stack-spacing: var(--spacing-lg, 2rem);
|
||||
}
|
||||
|
||||
.stack-spacing-xl,
|
||||
.stack--xl > * + * {
|
||||
--stack-spacing: var(--spacing-xl, 2rem);
|
||||
}
|
||||
|
||||
.stack-spacing-2xl,
|
||||
.stack--2xl > * + * {
|
||||
--stack-spacing: var(--spacing-2xl, 2rem);
|
||||
}
|
||||
|
||||
.stack-spacing-3xl,
|
||||
.stack--3xl > * + * {
|
||||
--stack-spacing: var(--spacing-3xl, 2rem);
|
||||
}
|
||||
|
||||
.stack-spacing-4xl,
|
||||
.stack--4xl > * + * {
|
||||
--stack-spacing: var(--spacing-4xl, 2rem);
|
||||
.stack-spacing-0,
|
||||
.stack--0 > * + * {
|
||||
--stack-spacing: 0;
|
||||
}
|
||||
|
||||
.stack-spacing-5xl,
|
||||
|
|
@ -75,7 +35,47 @@
|
|||
--stack-spacing: var(--spacing-5xl, 2rem);
|
||||
}
|
||||
|
||||
.stack-spacing-0,
|
||||
.stack--0 > * + * {
|
||||
--stack-spacing: 0;
|
||||
.stack-spacing-4xl,
|
||||
.stack--4xl > * + * {
|
||||
--stack-spacing: var(--spacing-4xl, 2rem);
|
||||
}
|
||||
|
||||
.stack-spacing-3xl,
|
||||
.stack--3xl > * + * {
|
||||
--stack-spacing: var(--spacing-3xl, 2rem);
|
||||
}
|
||||
|
||||
.stack-spacing-2xl,
|
||||
.stack--2xl > * + * {
|
||||
--stack-spacing: var(--spacing-2xl, 2rem);
|
||||
}
|
||||
|
||||
.stack-spacing-xl,
|
||||
.stack--xl > * + * {
|
||||
--stack-spacing: var(--spacing-xl, 2rem);
|
||||
}
|
||||
|
||||
.stack-spacing-lg,
|
||||
.stack--lg > * + * {
|
||||
--stack-spacing: var(--spacing-lg, 2rem);
|
||||
}
|
||||
|
||||
.stack-spacing-sm,
|
||||
.stack--sm > * + * {
|
||||
--stack-spacing: var(--spacing-sm, 0.5rem);
|
||||
}
|
||||
|
||||
.stack-spacing-xs,
|
||||
.stack--xs > * + * {
|
||||
--stack-spacing: var(--spacing-xs, 0.5rem);
|
||||
}
|
||||
|
||||
.stack-spacing-2xs,
|
||||
.stack--2xs > * + * {
|
||||
--stack-spacing: var(--spacing-2xs, 0.25rem);
|
||||
}
|
||||
|
||||
.stack-spacing-3xs,
|
||||
.stack--3xs > * + * {
|
||||
--stack-spacing: var(--spacing-3xs, 0.25rem);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -75,6 +75,7 @@ $color-red-600: #bd1218;
|
|||
--color-text-on-brand-lightest: #{$color-beige-50};
|
||||
--color-text-on-secondary-light: #{$color-green-600};
|
||||
--color-text-on-white: #{$color-green-600};
|
||||
--color-text-muted: #{$color-gray-500};
|
||||
--color-white: #{$color-white};
|
||||
|
||||
// Status
|
||||
|
|
@ -87,5 +88,8 @@ $color-red-600: #bd1218;
|
|||
|
||||
// forms
|
||||
--input-border-color: #{$color-gray-500};
|
||||
// Quieter field outline, the same weight as placeholder text — for forms that
|
||||
// should let their labels lead rather than their boxes (see `.form--quiet`).
|
||||
--input-border-color-muted: #{$color-gray-400};
|
||||
--table-border-color: #{$color-gray-500};
|
||||
}
|
||||
|
|
@ -1,4 +1,5 @@
|
|||
<script setup lang="ts">
|
||||
import { mapboxTokenIfChosen } from '~/utils/mapProvider'
|
||||
interface Props {
|
||||
mapId: string
|
||||
profileConfig: string
|
||||
|
|
@ -10,7 +11,8 @@ interface Props {
|
|||
|
||||
const props = withDefaults(defineProps<Props>(), { bundle: 'simple-map' })
|
||||
|
||||
useDoxaMap(props.bundle)
|
||||
// base: the deployment's dx-maps tree, known once this site's server answers (''); error: why not, in words.
|
||||
const { base, error } = useDoxaMap(props.bundle)
|
||||
|
||||
/* Each bundle registers a DIFFERENT custom element name so both IIFEs can
|
||||
* coexist on the same SPA. customElements.define() is one-shot per tag,
|
||||
|
|
@ -20,30 +22,151 @@ useDoxaMap(props.bundle)
|
|||
* its IIFE first and then the user navigated to /, /pray, or /adopt. */
|
||||
const tagName = props.bundle === 'research-map' ? 'doxa-research-map' : 'doxa-map'
|
||||
const isSimple = props.bundle === 'simple-map'
|
||||
|
||||
/* Until the map's element is defined (its scripts are still downloading on a cold first visit),
|
||||
* the slot would be an empty box. Show a quiet spinner instead, so the wait reads as loading. */
|
||||
const ready = ref(false)
|
||||
onMounted(() => {
|
||||
if (typeof customElements === 'undefined') return
|
||||
customElements.whenDefined(tagName).then(() => { ready.value = true })
|
||||
})
|
||||
|
||||
/* With no Mapbox token configured (e.g. a fresh checkout with no .env), the
|
||||
* map would refuse to start ("No Mapbox access token provided"). Ask the
|
||||
* dx-maps bundle for its keyless MapLibre engine instead, as the Research
|
||||
* page does. With a token, the config passes through unchanged. */
|
||||
/* The map's own files (styles, boundaries) live in the dx-maps tree it was loaded from, not on this
|
||||
* site: without assetsBase the bundle would look for them under this page's ./assets. The tree's
|
||||
* address comes from the server at runtime (useDoxaMap), so the element is added only once it is known. */
|
||||
const runtimeConfig = useRuntimeConfig()
|
||||
/* The site's language (it lives in the URL path, /ar/pray, which the map cannot read) goes to the map as
|
||||
* its locale, so its text, direction and data follow DX-life's language and its switcher. */
|
||||
const { locale } = useI18n()
|
||||
const effectiveConfig = computed(() => {
|
||||
try {
|
||||
// The page's own tk is ignored: the site's provider setting decides (MapLibre by default).
|
||||
const { tk: _pageToken, ...cfg } = { assetsBase: `${base.value}/assets`, locale: locale.value, ...JSON.parse(props.profileConfig) }
|
||||
const tk = mapboxTokenIfChosen(runtimeConfig.public)
|
||||
return JSON.stringify(tk ? { ...cfg, tk } : { ...cfg, provider: 'maplibre' })
|
||||
} catch {
|
||||
return props.profileConfig
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="doxa-map-slot">
|
||||
<component :is="tagName" :id="mapId" :profile-config="profileConfig" />
|
||||
<div class="doxa-map-slot" :aria-busy="ready ? undefined : 'true'">
|
||||
<div
|
||||
v-if="!ready"
|
||||
class="doxa-map-loading"
|
||||
:aria-hidden="error ? undefined : 'true'"
|
||||
>
|
||||
<p
|
||||
v-if="error"
|
||||
class="doxa-map-error"
|
||||
role="status"
|
||||
>
|
||||
{{ error }}
|
||||
</p>
|
||||
<span
|
||||
v-else
|
||||
class="doxa-map-spinner"
|
||||
/>
|
||||
</div>
|
||||
<component
|
||||
:is="tagName"
|
||||
v-if="base"
|
||||
:id="mapId"
|
||||
:profile-config="effectiveConfig"
|
||||
/>
|
||||
<div v-if="isSimple" class="doxa-map-scroll-pad doxa-map-scroll-pad--top" />
|
||||
<slot />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
.doxa-map-error {
|
||||
max-width: 32rem;
|
||||
margin: 0;
|
||||
padding: 1rem;
|
||||
text-align: center;
|
||||
color: rgba(59, 70, 61, 0.9);
|
||||
}
|
||||
.doxa-map-loading {
|
||||
position: absolute;
|
||||
inset: 0;
|
||||
display: grid;
|
||||
place-items: center;
|
||||
background: #f2f2f0;
|
||||
z-index: 1;
|
||||
}
|
||||
.doxa-map-spinner {
|
||||
width: 36px;
|
||||
height: 36px;
|
||||
border-radius: 50%;
|
||||
border: 3px solid rgba(59, 70, 61, 0.2);
|
||||
border-top-color: rgba(59, 70, 61, 0.8);
|
||||
animation: doxa-map-spin 0.9s linear infinite;
|
||||
}
|
||||
@keyframes doxa-map-spin { to { transform: rotate(360deg); } }
|
||||
@media (prefers-reduced-motion: reduce) { .doxa-map-spinner { animation: none; } }
|
||||
/* ROUNDED MAP CARDS (carried from doxa-maps-build). The slot is a LAYOUT, not a mask: the map sits
|
||||
inside an opaque rounded frame, inset by enough (0.32r, just over the r(1-1/sqrt 2) corner bite) that its
|
||||
own square corner never reaches the rounded edge, and the four corner wedges are PAINTED over it on
|
||||
their own layer. A WebGL canvas is a composited layer that an ancestor's radius does not reliably clip
|
||||
(the corners went square once a map loaded), so clipping alone is not enough. */
|
||||
.doxa-map-slot {
|
||||
/* read by the maps inside their shadow DOM, to round the canvas itself */
|
||||
--map-radius: var(--slot-radius, 0px);
|
||||
--map-radius-corners: var(--slot-radius, 0px);
|
||||
--slot-inset: calc(var(--slot-radius, 0px) * 0.32);
|
||||
--slot-radius: 0px;
|
||||
background: var(--slot-corner-bg, var(--color-surface-default, #F3F3F1));
|
||||
display: block;
|
||||
position: relative;
|
||||
width: 100%;
|
||||
min-height: 780px;
|
||||
aspect-ratio: 16 / 9;
|
||||
overflow: hidden;
|
||||
/* clip-path is applied at paint time, so the corners are round from the first frame, before the
|
||||
compositor has a mask layer for the canvas */
|
||||
clip-path: inset(0 round var(--slot-radius));
|
||||
isolation: isolate;
|
||||
will-change: transform;
|
||||
transform: translateZ(0);
|
||||
}
|
||||
.doxa-map-slot::after {
|
||||
content: '';
|
||||
position: absolute;
|
||||
inset: 0;
|
||||
pointer-events: none;
|
||||
z-index: 4;
|
||||
/* own compositing layer, so the map's GPU layer cannot paint over the wedges */
|
||||
transform: translateZ(0);
|
||||
will-change: transform;
|
||||
backface-visibility: hidden;
|
||||
--corner-tl: var(--slot-radius, 0px);
|
||||
--corner-tr: var(--slot-radius, 0px);
|
||||
--corner-br: var(--slot-radius, 0px);
|
||||
--corner-bl: var(--slot-radius, 0px);
|
||||
--corner-bg: var(--slot-corner-bg, var(--color-surface-default, #F3F3F1));
|
||||
background:
|
||||
radial-gradient(circle at 100% 100%, #0000 calc(var(--corner-tl) - 0.5px), var(--corner-bg) var(--corner-tl)) left top / var(--corner-tl) var(--corner-tl) no-repeat,
|
||||
radial-gradient(circle at 0 100%, #0000 calc(var(--corner-tr) - 0.5px), var(--corner-bg) var(--corner-tr)) right top / var(--corner-tr) var(--corner-tr) no-repeat,
|
||||
radial-gradient(circle at 0 0, #0000 calc(var(--corner-br) - 0.5px), var(--corner-bg) var(--corner-br)) right bottom / var(--corner-br) var(--corner-br) no-repeat,
|
||||
radial-gradient(circle at 100% 0, #0000 calc(var(--corner-bl) - 0.5px), var(--corner-bg) var(--corner-bl)) left bottom / var(--corner-bl) var(--corner-bl) no-repeat;
|
||||
}
|
||||
/* one corner size for every map card; the element's own radius is pinned to the same token */
|
||||
.doxa-map-slot.rounded-md,
|
||||
.doxa-map-slot.rounded-xlg { --slot-radius: var(--border-radius-lg); border-radius: var(--slot-radius); }
|
||||
|
||||
@media (max-width: 768px) {
|
||||
.doxa-map-slot {
|
||||
min-height: 0;
|
||||
/* twice as tall as wide (80px more map than the 9/16 before it), capped at one screen so the page
|
||||
below stays reachable */
|
||||
aspect-ratio: 1 / 2;
|
||||
max-height: 90svh;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -51,9 +174,13 @@ const isSimple = props.bundle === 'simple-map'
|
|||
.doxa-map-slot :deep(doxa-research-map) {
|
||||
display: block;
|
||||
position: absolute;
|
||||
inset: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
/* inset inside the rounded frame; the map keeps its stacking to itself so its legend and search
|
||||
(z-index 1000+) cannot paint over the corner wedges */
|
||||
inset: var(--slot-inset, 0px);
|
||||
isolation: isolate;
|
||||
z-index: 0;
|
||||
width: auto;
|
||||
height: auto;
|
||||
/* Inherit any border-radius the host page gave the slot (e.g. .rounded-md /
|
||||
.rounded-xlg on the research page). Without this, the bare custom element
|
||||
paints a rectangular background during the brief window between page
|
||||
|
|
|
|||
|
|
@ -1,22 +0,0 @@
|
|||
<script setup lang="ts">
|
||||
interface Props {
|
||||
profileConfig: string
|
||||
}
|
||||
|
||||
defineProps<Props>()
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="feedback-widget-slot">
|
||||
<feedback-web-component :profile-config="profileConfig" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
.feedback-widget-slot {
|
||||
position: absolute;
|
||||
right: 16px;
|
||||
bottom: 16px;
|
||||
z-index: 2147483647;
|
||||
}
|
||||
</style>
|
||||
85
app/components/public/AppStoreBadges.vue
Normal file
85
app/components/public/AppStoreBadges.vue
Normal file
|
|
@ -0,0 +1,85 @@
|
|||
<script setup lang="ts">
|
||||
// The two official store badges. Apple and Google each require their own
|
||||
// artwork, unaltered, so the files in public/assets/images/badges are the
|
||||
// ones their badge tools hand out (same set the campaigns server uses).
|
||||
//
|
||||
// The Apple badge is hidden when no App Store link is available — the iOS
|
||||
// app only shows up once MOBILE_APP_APPLE_ID is configured.
|
||||
|
||||
defineProps<{
|
||||
appStoreUrl?: string | null
|
||||
googlePlayUrl: string
|
||||
}>()
|
||||
|
||||
const { t, locale } = useI18n()
|
||||
|
||||
// Apple publishes no Arabic or Hindi badge — their tool returns the English
|
||||
// artwork for those locales, so those locales fall back to it here.
|
||||
const APP_STORE_BADGE_LOCALES = ['de', 'en', 'es', 'fr', 'it', 'pt', 'ro', 'ru', 'zh']
|
||||
const GOOGLE_PLAY_BADGE_LOCALES = ['ar', 'de', 'en', 'es', 'fr', 'hi', 'it', 'pt', 'ro', 'ru', 'zh']
|
||||
|
||||
function badgeLocale(available: string[]) {
|
||||
return available.includes(locale.value) ? locale.value : 'en'
|
||||
}
|
||||
|
||||
const appStoreBadge = computed(() => `/assets/images/badges/app-store-${badgeLocale(APP_STORE_BADGE_LOCALES)}.svg`)
|
||||
const googlePlayBadge = computed(() => `/assets/images/badges/google-play-${badgeLocale(GOOGLE_PLAY_BADGE_LOCALES)}.png`)
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="app-store-badges">
|
||||
<a
|
||||
v-if="appStoreUrl"
|
||||
:href="appStoreUrl"
|
||||
class="app-store-badges__link"
|
||||
target="_blank"
|
||||
>
|
||||
<img
|
||||
class="app-store-badges__apple"
|
||||
:src="appStoreBadge"
|
||||
:alt="t('Download on the App Store')"
|
||||
width="120"
|
||||
height="40"
|
||||
loading="lazy"
|
||||
>
|
||||
</a>
|
||||
<a :href="googlePlayUrl" class="app-store-badges__link" target="_blank" rel="noopener noreferrer">
|
||||
<img
|
||||
class="app-store-badges__google"
|
||||
:src="googlePlayBadge"
|
||||
:alt="t('Get it on Google Play')"
|
||||
width="155"
|
||||
height="60"
|
||||
loading="lazy"
|
||||
>
|
||||
</a>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
.app-store-badges {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
align-items: center;
|
||||
gap: 0.5rem;
|
||||
}
|
||||
|
||||
.app-store-badges__link {
|
||||
flex: 0 0 auto;
|
||||
}
|
||||
|
||||
/* Google's badge carries its mandatory clear space inside the image, so it
|
||||
is rendered taller than Apple's to make the two read at the same size. */
|
||||
.app-store-badges__apple {
|
||||
height: 44px;
|
||||
width: auto;
|
||||
border-radius: 0;
|
||||
margin-left: 11px;
|
||||
margin-right: 11px;
|
||||
}
|
||||
|
||||
.app-store-badges__google {
|
||||
height: 66px;
|
||||
width: auto;
|
||||
}
|
||||
</style>
|
||||
|
|
@ -1,4 +1,5 @@
|
|||
<script setup lang="ts">
|
||||
const researchGallery = useResearchGalleryUrl() // /research and /regions moved to the gallery's subdomain
|
||||
// Per-country page body: a map that highlights the country and plots its
|
||||
// people groups (plus surrounding ones, muted), alongside the people-group list
|
||||
// locked to this country. The summary (name, code, count, region, map
|
||||
|
|
@ -34,7 +35,7 @@ const mapNote = computed(() =>
|
|||
<template>
|
||||
<div class="container page-content uupgs-page stack stack--3xl">
|
||||
<div class="stack stack--xs text-center">
|
||||
<NuxtLink class="light-link" :to="localePath('/regions')">← {{ t('All Regions') }}</NuxtLink>
|
||||
<NuxtLink class="light-link" :to="researchGallery('regions-dashboard')" external>← {{ t('All Regions') }}</NuxtLink>
|
||||
<h1 class="highlight" data-highlight-last>{{ country.name }}</h1>
|
||||
<p class="color-brand-lighter">
|
||||
{{ country.count }} {{ t('People Groups') }} ·
|
||||
|
|
|
|||
|
|
@ -86,7 +86,7 @@ function mapColors() {
|
|||
}
|
||||
}
|
||||
|
||||
const PIN_FIELDS = 'name,slug,country_code,rop1,religion,population,location_description,image_url,has_photo,latitude,longitude,people_committed'
|
||||
const PIN_FIELDS = 'name,slug,country_code,rop1,religion,population,imb_people_description,image_url,has_photo,latitude,longitude,people_committed'
|
||||
|
||||
async function loadPins() {
|
||||
const url = `${prayBaseUrl}/api/people-groups/list?fields=${PIN_FIELDS}&lang=${props.languageCode}`
|
||||
|
|
@ -111,7 +111,7 @@ async function loadPins() {
|
|||
rop1: p.rop1?.label ?? '',
|
||||
religion: p.religion?.label ?? '',
|
||||
population: p.population ?? 0,
|
||||
description: p.location_description ?? '',
|
||||
description: p.imb_people_description ?? '',
|
||||
imageUrl: (p.has_photo && p.image_url) ? p.image_url : ''
|
||||
}
|
||||
}))
|
||||
|
|
@ -131,7 +131,7 @@ function formatPopulation(pop: number): string {
|
|||
// Build the pin popup's inner HTML from a feature's properties. Mirrors the
|
||||
// research map's detail panel: photo, name, country · people-group, the
|
||||
// population/religion stats and intercessor count (out of the full-coverage
|
||||
// goal, as on the people-group cards), a short description, and Pray / Full
|
||||
// goal, as on the people-group cards), the people group description, and Pray / Full
|
||||
// Profile links.
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
function popupHtml(p: any): string {
|
||||
|
|
@ -154,8 +154,8 @@ function popupHtml(p: any): string {
|
|||
${rows.length ? `<dl class="cm-popup__stats">${rows.join('')}</dl>` : ''}
|
||||
${p.description ? `<p class="cm-popup__desc">${escapeHtml(p.description)}</p>` : ''}
|
||||
<div class="cm-popup__actions">
|
||||
<a class="cm-popup__btn cm-popup__btn--primary" href="${prayUrl}">${escapeHtml(t('Pray'))}</a>
|
||||
<a class="cm-popup__btn" href="${profileUrl}">${escapeHtml(t('Full Profile'))}</a>
|
||||
<a class="cm-popup__btn cm-popup__btn--primary" href="${escapeHtml(prayUrl)}">${escapeHtml(t('Pray'))}</a>
|
||||
<a class="cm-popup__btn" href="${escapeHtml(profileUrl)}">${escapeHtml(t('Full Profile'))}</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>`
|
||||
|
|
|
|||
|
|
@ -11,9 +11,11 @@ const props = withDefaults(defineProps<{
|
|||
options: FilterOption[]
|
||||
value?: string
|
||||
placeholder?: string
|
||||
noOptionsText?: string
|
||||
}>(), {
|
||||
value: '',
|
||||
placeholder: 'Type to search...'
|
||||
placeholder: 'Type to search...',
|
||||
noOptionsText: 'No options found'
|
||||
})
|
||||
|
||||
const emit = defineEmits<{
|
||||
|
|
@ -154,7 +156,7 @@ onBeforeUnmount(() => document.removeEventListener('click', onClickOutside))
|
|||
>Clear selection</button>
|
||||
<div class="filter-dropdown__options">
|
||||
<template v-if="filteredOptions.length === 0">
|
||||
<div class="filter-dropdown__no-options">No options found</div>
|
||||
<div class="filter-dropdown__no-options">{{ noOptionsText }}</div>
|
||||
</template>
|
||||
<template v-else>
|
||||
<div
|
||||
|
|
|
|||
|
|
@ -11,7 +11,12 @@ const switchLocalePath = useSwitchLocalePath()
|
|||
const route = useRoute()
|
||||
|
||||
const current = computed(() => LANGUAGES.find(l => l.code === locale.value) ?? LANGUAGES[0])
|
||||
const others = computed(() => ENABLED_LANGUAGES.filter(l => l.code !== locale.value && !l.hideFromSwitcher))
|
||||
const others = computed(() => {
|
||||
ENABLED_LANGUAGES.filter(l => l.code !== locale.value && !l.hideFromSwitcher)
|
||||
ENABLED_LANGUAGES.sort((a, b) => a.nativeName.localeCompare(b.nativeName))
|
||||
|
||||
return ENABLED_LANGUAGES
|
||||
})
|
||||
|
||||
const isOpen = ref(false)
|
||||
const isPinned = ref(false)
|
||||
|
|
|
|||
99
app/components/public/MessageTypeSelect.vue
Normal file
99
app/components/public/MessageTypeSelect.vue
Normal file
|
|
@ -0,0 +1,99 @@
|
|||
<script setup lang="ts">
|
||||
// Message-category picker for the contact form, mirroring the campaigns-server
|
||||
// feedback form's three options. The values are the feedback types the
|
||||
// campaigns-server understands (`compliment` / `suggestion` / `problem`); only
|
||||
// the labels are worded for a contact-us page.
|
||||
|
||||
import type { MessageType } from '~/types/contact'
|
||||
|
||||
const model = defineModel<MessageType | null>({ default: null })
|
||||
|
||||
defineProps<{
|
||||
/** id of the field label, so the group is announced with it. */
|
||||
labelId?: string
|
||||
}>()
|
||||
|
||||
const { t } = useI18n()
|
||||
|
||||
const options = computed<{ value: MessageType, label: string }[]>(() => [
|
||||
{ value: 'compliment', label: t('Compliment') },
|
||||
{ value: 'suggestion', label: t('Suggestion') },
|
||||
{ value: 'problem', label: t('Problem') }
|
||||
])
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div
|
||||
class="cluster message-type-select"
|
||||
role="group"
|
||||
:aria-labelledby="labelId"
|
||||
>
|
||||
<button
|
||||
v-for="option in options"
|
||||
:key="option.value"
|
||||
type="button"
|
||||
class="button compact with-icon"
|
||||
:class="{ outline: model !== option.value }"
|
||||
:aria-pressed="model === option.value"
|
||||
@click="model = option.value"
|
||||
>
|
||||
<!-- Heart / lightbulb / warning-triangle, matching the feedback form's
|
||||
icon set. Stroked rather than filled, so `fill` is overridden here. -->
|
||||
<svg
|
||||
v-if="option.value === 'compliment'"
|
||||
class="icon width-md"
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
stroke-width="2"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
aria-hidden="true"
|
||||
>
|
||||
<path d="M19 14c1.49-1.46 3-3.21 3-5.5A5.5 5.5 0 0 0 16.5 3c-1.76 0-3 .5-4.5 2-1.5-1.5-2.74-2-4.5-2A5.5 5.5 0 0 0 2 8.5c0 2.3 1.5 4.05 3 5.5l7 7Z" />
|
||||
</svg>
|
||||
<svg
|
||||
v-else-if="option.value === 'suggestion'"
|
||||
class="icon width-md"
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
stroke-width="2"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
aria-hidden="true"
|
||||
>
|
||||
<path d="M15 14c.2-1 .7-1.7 1.5-2.5 1-.9 1.5-2.2 1.5-3.5A6 6 0 0 0 6 8c0 1 .2 2.2 1.5 3.5.7.7 1.3 1.5 1.5 2.5" />
|
||||
<path d="M9 18h6" />
|
||||
<path d="M10 22h4" />
|
||||
</svg>
|
||||
<svg
|
||||
v-else
|
||||
class="icon width-md"
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
stroke-width="2"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
aria-hidden="true"
|
||||
>
|
||||
<path d="m21.73 18-8-14a2 2 0 0 0-3.48 0l-8 14A2 2 0 0 0 4 21h16a2 2 0 0 0 1.73-3" />
|
||||
<path d="M12 9v4" />
|
||||
<path d="M12 17h.01" />
|
||||
</svg>
|
||||
{{ option.label }}
|
||||
</button>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
/* The shared `.icon` rule fills with currentColor; these are stroked outlines. */
|
||||
.message-type-select .icon {
|
||||
fill: none;
|
||||
}
|
||||
|
||||
.message-type-select .with-icon .icon {
|
||||
margin-inline-end: var(--spacing-2xs);
|
||||
}
|
||||
</style>
|
||||
102
app/components/public/MobileAppSection.vue
Normal file
102
app/components/public/MobileAppSection.vue
Normal file
|
|
@ -0,0 +1,102 @@
|
|||
<script setup lang="ts">
|
||||
// "Take the unreached with you" — the DOXA Prayer App promo section, used at
|
||||
// the bottom of /pray and of each research people group page.
|
||||
//
|
||||
// Where a people group is in hand (the research detail page) both badges point
|
||||
// at the campaigns-server smart link, `{prayBaseUrl}/app/<slug>`: it opens an
|
||||
// installed app straight on that people group and, on Android, carries the slug
|
||||
// through the Play install referrer so a fresh install lands there too
|
||||
// (deferred deep linking — see doxa-campaigns-server server/routes/app/[slug]).
|
||||
// With no people group there is nothing to defer, so the badges go straight to
|
||||
// the stores, built from the MOBILE_APP_* ids in runtime config.
|
||||
|
||||
const props = defineProps<{
|
||||
peopleGroupName?: string | null
|
||||
peopleGroupSlug?: string | null
|
||||
}>()
|
||||
|
||||
const { t } = useI18n()
|
||||
const config = useRuntimeConfig()
|
||||
|
||||
const prayBaseUrl = config.public.prayBaseUrl as string
|
||||
const appleId = config.public.mobileAppAppleId as string
|
||||
const androidPackage = config.public.mobileAppAndroidPackage as string
|
||||
|
||||
const appStoreUrl = computed(() => {
|
||||
if (!appleId) return null
|
||||
return props.peopleGroupSlug
|
||||
? `${prayBaseUrl}/app/${props.peopleGroupSlug}?store=ios`
|
||||
: `https://apps.apple.com/app/id${appleId}`
|
||||
})
|
||||
|
||||
const googlePlayUrl = computed(() => {
|
||||
if (props.peopleGroupSlug) return `${prayBaseUrl}/app/${props.peopleGroupSlug}?store=android`
|
||||
const referrer = encodeURIComponent('utm_source=doxa_life&utm_medium=referral')
|
||||
return `https://play.google.com/store/apps/details?id=${androidPackage}&referrer=${referrer}`
|
||||
})
|
||||
|
||||
// A locale that hasn't translated a string gets the English key back, and that
|
||||
// fallback is *not* interpolated (see i18n.config.ts) — so pass the placeholder
|
||||
// through as the argument and split on it here. Either way we end up with the
|
||||
// text either side of the people group's name, which lets the name carry the
|
||||
// accent colour the way "unreached" does in the generic heading.
|
||||
const titleParts = computed(() => {
|
||||
const [before = '', after = ''] = t('Take the {0} with you', ['{0}']).split('{0}')
|
||||
return { before, after }
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<section class="surface-white">
|
||||
<div class="container">
|
||||
<div class="switcher | align-center" data-width="xl">
|
||||
<div class="stack | grow-2 align-center">
|
||||
<div class="stack stack--2xl">
|
||||
<p class="color-brand-lighter font-weight-medium uppercase">
|
||||
{{ t('The DOXA Prayer App') }}
|
||||
</p>
|
||||
<h2 v-if="peopleGroupName" class="stack-spacing-sm">
|
||||
{{ titleParts.before }}<span class="color-primary">{{ peopleGroupName }}</span>{{ titleParts.after }}
|
||||
</h2>
|
||||
<h2 v-else class="highlight stack-spacing-sm" data-highlight-index="3">
|
||||
{{ t('Take the unreached with you') }}
|
||||
</h2>
|
||||
<ul class="stack stack--sm" data-list-color="primary">
|
||||
<li>{{ t('Daily reminders at the time you choose') }}</li>
|
||||
<li>{{ t('Today\'s prayer ready to open') }}</li>
|
||||
<li>{{ t('See how many people are praying with you now') }}</li>
|
||||
</ul>
|
||||
<AppStoreBadges
|
||||
id="app-store-links"
|
||||
:app-store-url="appStoreUrl"
|
||||
:google-play-url="googlePlayUrl"
|
||||
/>
|
||||
<p class="font-size-sm color-brand-light stack-spacing-sm">
|
||||
{{t('Download and choose your people group in the app.')}}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<picture>
|
||||
<source
|
||||
srcset="/assets/images/pray-02-PrayerFUEL-Phone-graphic-2.avif"
|
||||
type="image/avif"
|
||||
>
|
||||
<source
|
||||
srcset="/assets/images/pray-02-PrayerFUEL-Phone-graphic-2.webp"
|
||||
type="image/webp"
|
||||
>
|
||||
<img
|
||||
class="center"
|
||||
src="/assets/images/pray-02-PrayerFUEL-Phone-graphic-2.png"
|
||||
:alt="t('Your daily prayer guide')"
|
||||
width="500"
|
||||
height="872"
|
||||
loading="lazy"
|
||||
>
|
||||
</picture>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</template>
|
||||
|
|
@ -1,4 +1,5 @@
|
|||
<script setup lang="ts">
|
||||
const researchGallery = useResearchGalleryUrl() // /research and /regions moved to the gallery's subdomain
|
||||
// Region dashboard body: headline figures, a map of the region's countries
|
||||
// with its people groups coloured by prayer coverage, progress toward the DOXA
|
||||
// goals — prayer coverage, adoption, engagement — and a per-country breakdown
|
||||
|
|
@ -45,7 +46,7 @@ const mapNote = computed(() =>
|
|||
<template>
|
||||
<div class="container page-content uupgs-page stack stack--3xl">
|
||||
<div class="stack stack--xs text-center">
|
||||
<NuxtLink class="light-link" :to="localePath('/regions')">← {{ t('All Regions') }}</NuxtLink>
|
||||
<NuxtLink class="light-link" :to="researchGallery('regions-dashboard')" external>← {{ t('All Regions') }}</NuxtLink>
|
||||
<h1 class="highlight" data-highlight-last>{{ label }}</h1>
|
||||
<p class="color-brand-lighter">{{ summaryLine }}</p>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -3,7 +3,12 @@
|
|||
// Layout: logo + WAGF tagline on the left, primary nav + hamburger toggle
|
||||
// on the right, plus a slide-down hamburger overlay for mobile.
|
||||
|
||||
import { PRIMARY_NAV, SECONDARY_NAV } from '~/utils/nav'
|
||||
import { PRIMARY_NAV, SECONDARY_NAV, type NavItem } from '~/utils/nav'
|
||||
const researchGallery = useResearchGalleryUrl()
|
||||
// Items switched off are not shown; the Research item gets the gallery's URL (in the reader's language).
|
||||
const secondaryNav = computed(() => SECONDARY_NAV.filter((i) => !i.off).map((i): NavItem =>
|
||||
i.hrefConfig === 'researchGalleryUrl' ? { ...i, href: researchGallery() } : i)
|
||||
.filter((i) => i.href || i.to))
|
||||
|
||||
const { t } = useI18n()
|
||||
const localePath = useLocalePath()
|
||||
|
|
@ -29,9 +34,17 @@ watch(() => route.fullPath, close)
|
|||
:data-state="isOpen ? 'open' : 'closed'"
|
||||
>
|
||||
<ul id="secondary-menu" class="role-list stack">
|
||||
<li v-for="item in SECONDARY_NAV" :key="item.key" class="menu-item">
|
||||
<li v-for="item in secondaryNav" :key="item.key" class="menu-item">
|
||||
<!-- The Research Gallery is this site's own gallery, on its subdomain: it opens in the same tab like
|
||||
every other page. Only the external links (Give) open a new tab. -->
|
||||
<a
|
||||
v-if="item.href"
|
||||
v-if="item.hrefConfig"
|
||||
:href="item.href"
|
||||
>
|
||||
{{ t(item.key) }}
|
||||
</a>
|
||||
<a
|
||||
v-else-if="item.href"
|
||||
:href="item.href"
|
||||
target="_blank"
|
||||
rel="noopener"
|
||||
|
|
|
|||
72
app/components/public/ToggleSwitch.vue
Normal file
72
app/components/public/ToggleSwitch.vue
Normal file
|
|
@ -0,0 +1,72 @@
|
|||
<script setup lang="ts">
|
||||
// Accessible on/off switch styled to match the campaigns-server feedback form.
|
||||
// Used instead of a checkbox for opt-ins where the control should read as a
|
||||
// preference rather than a form field. The label is rendered by the caller and
|
||||
// wired up through `label-id` so it stays part of the surrounding copy flow.
|
||||
|
||||
const model = defineModel<boolean>({ default: false })
|
||||
|
||||
defineProps<{
|
||||
/** id of the element labelling this switch, for `aria-labelledby`. */
|
||||
labelId?: string
|
||||
}>()
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<button
|
||||
type="button"
|
||||
role="switch"
|
||||
class="toggle-switch"
|
||||
:class="{ 'is-on': model }"
|
||||
:aria-checked="model"
|
||||
:aria-labelledby="labelId"
|
||||
@click="model = !model"
|
||||
>
|
||||
<span class="toggle-switch__thumb" />
|
||||
</button>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
.toggle-switch {
|
||||
--toggle-width: 2.75rem;
|
||||
--toggle-height: 1.5rem;
|
||||
--toggle-padding: 0.2rem;
|
||||
flex: none;
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
width: var(--toggle-width);
|
||||
height: var(--toggle-height);
|
||||
padding: var(--toggle-padding);
|
||||
border: none;
|
||||
border-radius: 100px;
|
||||
background-color: var(--color-brand-secondary);
|
||||
cursor: pointer;
|
||||
transition: background-color 0.2s ease;
|
||||
}
|
||||
|
||||
.toggle-switch.is-on {
|
||||
background-color: var(--color-brand-primary);
|
||||
}
|
||||
|
||||
.toggle-switch:focus-visible {
|
||||
outline: max(1px, 0.1em) solid var(--color-brand-dark);
|
||||
outline-offset: 2px;
|
||||
}
|
||||
|
||||
.toggle-switch__thumb {
|
||||
width: calc(var(--toggle-height) - (2 * var(--toggle-padding)));
|
||||
height: calc(var(--toggle-height) - (2 * var(--toggle-padding)));
|
||||
border-radius: 50%;
|
||||
background-color: var(--color-surface-white);
|
||||
transition: transform 0.2s ease;
|
||||
}
|
||||
|
||||
.toggle-switch.is-on .toggle-switch__thumb {
|
||||
transform: translateX(calc(var(--toggle-width) - var(--toggle-height)));
|
||||
}
|
||||
|
||||
/* The thumb travels the other way in RTL, where the track is mirrored. */
|
||||
[dir="rtl"] .toggle-switch.is-on .toggle-switch__thumb {
|
||||
transform: translateX(calc((var(--toggle-width) - var(--toggle-height)) * -1));
|
||||
}
|
||||
</style>
|
||||
|
|
@ -497,6 +497,7 @@ const showMore = computed(() => hasMore())
|
|||
:options="filterOptions.wagf_region || []"
|
||||
:value="activeFilters.wagf_region?.value ?? ''"
|
||||
:placeholder="t.type_to_search || 'Type to search...'"
|
||||
:no-options-text="t.no_options || 'No options found'"
|
||||
@filter-change="onFilterChange"
|
||||
@filter-clear="onFilterClear"
|
||||
/>
|
||||
|
|
@ -506,6 +507,7 @@ const showMore = computed(() => hasMore())
|
|||
:options="filterOptions.wagf_block || []"
|
||||
:value="activeFilters.wagf_block?.value ?? ''"
|
||||
:placeholder="t.type_to_search || 'Type to search...'"
|
||||
:no-options-text="t.no_options || 'No options found'"
|
||||
@filter-change="onFilterChange"
|
||||
@filter-clear="onFilterClear"
|
||||
/>
|
||||
|
|
@ -516,6 +518,7 @@ const showMore = computed(() => hasMore())
|
|||
:options="filterOptions.country_code || []"
|
||||
:value="activeFilters.country_code?.value ?? ''"
|
||||
:placeholder="t.type_to_search || 'Type to search...'"
|
||||
:no-options-text="t.no_options || 'No options found'"
|
||||
@filter-change="onFilterChange"
|
||||
@filter-clear="onFilterClear"
|
||||
/>
|
||||
|
|
@ -525,6 +528,7 @@ const showMore = computed(() => hasMore())
|
|||
:options="filterOptions.rop1 || []"
|
||||
:value="activeFilters.rop1?.value ?? ''"
|
||||
:placeholder="t.type_to_search || 'Type to search...'"
|
||||
:no-options-text="t.no_options || 'No options found'"
|
||||
@filter-change="onFilterChange"
|
||||
@filter-clear="onFilterClear"
|
||||
/>
|
||||
|
|
@ -534,6 +538,7 @@ const showMore = computed(() => hasMore())
|
|||
:options="filterOptions.religion || []"
|
||||
:value="activeFilters.religion?.value ?? ''"
|
||||
:placeholder="t.type_to_search || 'Type to search...'"
|
||||
:no-options-text="t.no_options || 'No options found'"
|
||||
@filter-change="onFilterChange"
|
||||
@filter-clear="onFilterClear"
|
||||
/>
|
||||
|
|
@ -600,7 +605,7 @@ const showMore = computed(() => hasMore())
|
|||
<div v-if="useSelectCard" class="stack stack--sm | card | highlighted-uupg__card">
|
||||
<div class="repel align-start">
|
||||
<img :src="uupg.image_url" :alt="uupg.name">
|
||||
<p class="color-brand-lighter uppercase text-end overflow-wrap-anywhere" v-html="uupg.wagf_region_label ? uupg.wagf_region_label : uupg.wagf_region.label" />
|
||||
<p class="color-brand-lighter uppercase text-end overflow-wrap-anywhere" v-html="uupg.wagf_region_label ? uupg.wagf_region_label : uupg.wagf_region?.label" />
|
||||
</div>
|
||||
<div>
|
||||
<p class="line-height-tight" v-html="uupg.name" />
|
||||
|
|
@ -633,9 +638,10 @@ const showMore = computed(() => hasMore())
|
|||
<h3 class="uupg__name line-height-tight" v-html="uupg.name" />
|
||||
<p class="uupg__country">
|
||||
<a
|
||||
v-if="uupg.country_code"
|
||||
class="uupg__country-link light-link"
|
||||
:href="localePath(`/regions/${countrySlug(uupg.country_code.value, uupg.country_code.label)}`)"
|
||||
><span v-html="uupg.country_label ? uupg.country_label : uupg.country_code.label" /></a> (<span v-html="uupg.rop1_label ? uupg.rop1_label : uupg.rop1.label" />)
|
||||
><span v-html="uupg.country_label ? uupg.country_label : uupg.country_code.label" /></a> (<span v-html="uupg.rop1_label ? uupg.rop1_label : uupg.rop1?.label" />)
|
||||
</p>
|
||||
<template v-if="uupg.matches">
|
||||
<p v-for="(match, mi) in uupg.matches" :key="mi" class="font-size-sm color-brand-lighter">
|
||||
|
|
@ -643,7 +649,6 @@ const showMore = computed(() => hasMore())
|
|||
</p>
|
||||
</template>
|
||||
</div>
|
||||
<p v-if="uupg.location_description" class="uupg__content">{{ uupg.location_description }}</p>
|
||||
<a class="uupg__more-button button compact" :href="`${researchUrl}${uupg.slug}`">{{ t.full_profile }}</a>
|
||||
</div>
|
||||
</template>
|
||||
|
|
|
|||
|
|
@ -26,17 +26,6 @@ const clearCache = () => {
|
|||
}
|
||||
}
|
||||
|
||||
// Opt this browser into the feedback widget — the same `show-feedback-widget`
|
||||
// flag that ?feedback=true sets. Lets logged-in users see the widget on public,
|
||||
// edge-cached pages without a /api/auth/me check (we don't run one there).
|
||||
const enableFeedbackWidget = () => {
|
||||
if (import.meta.client) {
|
||||
try {
|
||||
localStorage.setItem('show-feedback-widget', 'true')
|
||||
} catch {}
|
||||
}
|
||||
}
|
||||
|
||||
export const useAuth = () => {
|
||||
const user = useState('auth.user', () => null as any)
|
||||
const authReady = useState('auth.ready', () => false)
|
||||
|
|
@ -58,7 +47,6 @@ export const useAuth = () => {
|
|||
if (response.success) {
|
||||
user.value = response.user
|
||||
saveToCache(response.user)
|
||||
enableFeedbackWidget()
|
||||
|
||||
const route = useRoute()
|
||||
const redirectTo = route.query.redirect as string
|
||||
|
|
@ -124,7 +112,6 @@ export const useAuth = () => {
|
|||
const response = await $fetch('/api/auth/me') as { user: any }
|
||||
user.value = response.user
|
||||
saveToCache(response.user)
|
||||
enableFeedbackWidget()
|
||||
return response.user
|
||||
} catch {
|
||||
user.value = null
|
||||
|
|
|
|||
|
|
@ -4,16 +4,17 @@
|
|||
// window.mapboxgl / window.MapboxGeocoder BEFORE map-app.iife.js runs
|
||||
// customElements.define('doxa-map', …) — otherwise the custom-element upgrade's
|
||||
// connectedCallback calls `new mapboxgl.Map(…)` before the global exists.
|
||||
// The <feedback-widget> bundle is loaded globally via nuxt.config.ts.
|
||||
|
||||
const MAPBOX_JS = 'https://api.mapbox.com/mapbox-gl-js/v3.3.0/mapbox-gl.js'
|
||||
const MAPBOX_JS = 'https://api.mapbox.com/mapbox-gl-js/v3.24.0/mapbox-gl.js'
|
||||
const MAPBOX_GEOCODER_JS = 'https://api.mapbox.com/mapbox-gl-js/plugins/mapbox-gl-geocoder/v5.0.0/mapbox-gl-geocoder.min.js'
|
||||
|
||||
// Map of bundle keys → /public/js URLs. The IIFE bundles all register the
|
||||
// same `<doxa-map>` custom element, so only one bundle should load per page.
|
||||
// Map of bundle keys → bundles in the dx-maps build tree: the deployment's NUXT_PUBLIC_DX_MAPS_BASE (the
|
||||
// team container's published tree), asked from this site's server at runtime (loadDxRuntime) because a
|
||||
// prerendered page cannot carry it. Each bundle registers its own custom element (<doxa-map>,
|
||||
// <doxa-research-map>).
|
||||
const BUNDLES = {
|
||||
'simple-map': '/js/doxa-simple-map.js',
|
||||
'research-map': '/js/doxa-research-map.js'
|
||||
'simple-map': 'doxa-simple-map/doxa-simple-map.js',
|
||||
'research-map': 'doxa-research-map/doxa-research-map.js'
|
||||
} as const
|
||||
type BundleKey = keyof typeof BUNDLES
|
||||
|
||||
|
|
@ -26,6 +27,16 @@ declare global {
|
|||
}
|
||||
}
|
||||
|
||||
// Start downloading a script now, to run later (loadScript), without blocking anything.
|
||||
function preloadScript(href: string) {
|
||||
if (document.querySelector(`link[rel="preload"][href="${href}"]`)) return
|
||||
const l = document.createElement('link')
|
||||
l.rel = 'preload'
|
||||
l.as = 'script'
|
||||
l.href = href
|
||||
document.head.appendChild(l)
|
||||
}
|
||||
|
||||
function loadScript(src: string): Promise<void> {
|
||||
return new Promise((resolve, reject) => {
|
||||
const existing = document.querySelector<HTMLScriptElement>(`script[data-doxa-map="${src}"]`)
|
||||
|
|
@ -51,19 +62,31 @@ function loadScript(src: string): Promise<void> {
|
|||
* callers (home, pray, adopt, contact-us) don't break. The
|
||||
* research/index.vue page passes 'research-map' to load the
|
||||
* 5-tab research bundle.
|
||||
* @returns base - the dx-maps tree's address once known ('' until then): the
|
||||
* map's element is added only when it is set, since the
|
||||
* element needs it for its styles and boundaries.
|
||||
* error - why the map cannot load, in words (a missing setting names
|
||||
* itself), or ''.
|
||||
*/
|
||||
export function useDoxaMap(bundle: BundleKey = 'simple-map') {
|
||||
const config = useRuntimeConfig()
|
||||
const base = ref('')
|
||||
const error = ref('')
|
||||
|
||||
useHead({
|
||||
link: [
|
||||
{ rel: 'stylesheet', href: 'https://api.mapbox.com/mapbox-gl-js/v3.3.0/mapbox-gl.css' },
|
||||
{ rel: 'stylesheet', href: 'https://api.mapbox.com/mapbox-gl-js/plugins/mapbox-gl-geocoder/v5.0.0/mapbox-gl-geocoder.css' }
|
||||
{ rel: 'stylesheet', href: 'https://api.mapbox.com/mapbox-gl-js/v3.24.0/mapbox-gl.css' },
|
||||
{ rel: 'stylesheet', href: 'https://api.mapbox.com/mapbox-gl-js/plugins/mapbox-gl-geocoder/v5.0.0/mapbox-gl-geocoder.css' },
|
||||
// The three scripts below still RUN one after another (the map bundle must find
|
||||
// window.mapboxgl), but nothing stops them DOWNLOADING together: without these hints a cold
|
||||
// first visit fetched ~1.8 MB of Mapbox GL, then the geocoder, then the map bundle, in series.
|
||||
// The map bundle's address is known only once /api/dx-runtime answers, so its preload is added
|
||||
// then (onMounted), still while Mapbox downloads.
|
||||
{ rel: 'preload', as: 'script', href: MAPBOX_JS },
|
||||
{ rel: 'preload', as: 'script', href: MAPBOX_GEOCODER_JS }
|
||||
]
|
||||
})
|
||||
|
||||
const MAP_APP_JS = BUNDLES[bundle]
|
||||
|
||||
onMounted(async () => {
|
||||
try {
|
||||
// Tell the map bundle which prayer API to fetch from. Must be set before
|
||||
|
|
@ -72,11 +95,24 @@ export function useDoxaMap(bundle: BundleKey = 'simple-map') {
|
|||
if (config.public.prayBaseUrl) {
|
||||
window.MAP_APP_API_URL = config.public.prayBaseUrl as string
|
||||
}
|
||||
const mapAppJs = dxMapsBaseOrThrow().then((tree) => {
|
||||
base.value = tree
|
||||
const src = `${tree}/${BUNDLES[bundle]}`
|
||||
preloadScript(src)
|
||||
return src
|
||||
})
|
||||
// A missing address is shown at once, not after Mapbox has downloaded (the await below throws too).
|
||||
mapAppJs.catch((err) => {
|
||||
error.value = String((err as Error)?.message || err)
|
||||
})
|
||||
await loadScript(MAPBOX_JS)
|
||||
await loadScript(MAPBOX_GEOCODER_JS)
|
||||
await loadScript(MAP_APP_JS)
|
||||
await loadScript(await mapAppJs)
|
||||
} catch (err) {
|
||||
error.value = String((err as Error)?.message || err)
|
||||
console.error('[useDoxaMap] script load failed', err)
|
||||
}
|
||||
})
|
||||
|
||||
return { base, error }
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,24 +0,0 @@
|
|||
// Idle-loads the third-party feedback web-component bundle. It's a ~95 KB
|
||||
// script not needed for first paint, so we defer it until the browser is idle
|
||||
// to keep it off the initial load critical path. Call this from any layout
|
||||
// that renders a <feedback-web-component>; the in-DOM guard means multiple
|
||||
// callers still load the bundle only once.
|
||||
const FEEDBACK_SCRIPT = 'https://support.gospelambition.org/js/feedback-web-component.iife.js'
|
||||
|
||||
function loadFeedbackScript() {
|
||||
if (document.querySelector(`script[src="${FEEDBACK_SCRIPT}"]`)) return
|
||||
const script = document.createElement('script')
|
||||
script.src = FEEDBACK_SCRIPT
|
||||
script.async = true
|
||||
document.head.appendChild(script)
|
||||
}
|
||||
|
||||
export function useFeedbackScript() {
|
||||
onMounted(() => {
|
||||
if ('requestIdleCallback' in window) {
|
||||
requestIdleCallback(loadFeedbackScript, { timeout: 3000 })
|
||||
} else {
|
||||
setTimeout(loadFeedbackScript, 2000)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
|
@ -24,7 +24,7 @@ export interface PrayerStatistics {
|
|||
const FALLBACK_TOTAL = 2085
|
||||
|
||||
// Fallback unengaged population (≈200M) shown only when the upstream API
|
||||
// hasn't responded yet or failed — avoids rendering "0 Million" in the
|
||||
// hasn't responded yet or failed — avoids rendering a zero population in the
|
||||
// bullseye on a cold cache. Replaced by the live SUM(population) as soon as
|
||||
// the stats load.
|
||||
const FALLBACK_UNENGAGED_POPULATION = 200_000_000
|
||||
|
|
@ -105,13 +105,8 @@ export function usePrayerStatistics() {
|
|||
)
|
||||
|
||||
// Total population living in the unengaged people groups. Drives the
|
||||
// bullseye's "{0} Million" figure, which shrinks as groups become engaged.
|
||||
// bullseye's population figure, which shrinks as groups become engaged.
|
||||
const unengagedPopulation = computed(() => stats.value.unengaged_population || FALLBACK_UNENGAGED_POPULATION)
|
||||
// Rounded to whole millions to match the "{0} Million" copy (e.g. 202).
|
||||
// Latin digits forced like the other counters so it matches the page.
|
||||
const unengagedPopulationMillionsFormatted = computed(() =>
|
||||
Math.round(unengagedPopulation.value / 1_000_000).toLocaleString(`${locale.value}-u-nu-latn`)
|
||||
)
|
||||
|
||||
const prayerCoveragePercent = computed(
|
||||
() => Math.min(100, (stats.value.total_with_full_prayer / totalPeopleGroups.value) * 100)
|
||||
|
|
@ -129,7 +124,6 @@ export function usePrayerStatistics() {
|
|||
unengagedPeopleGroups,
|
||||
unengagedPeopleGroupsFormatted,
|
||||
unengagedPopulation,
|
||||
unengagedPopulationMillionsFormatted,
|
||||
prayerCoveragePercent,
|
||||
adoptedPercent,
|
||||
reload,
|
||||
|
|
|
|||
18
app/composables/useResearchGalleryUrl.ts
Normal file
18
app/composables/useResearchGalleryUrl.ts
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
// The Research Gallery lives on its own subdomain (the research site, served by the team's dx-maps
|
||||
// container), so every link that went to this site's /research or /regions page goes there instead.
|
||||
// The link is this site's own /research-gallery, which the server redirects to the deployment's
|
||||
// gallery (NUXT_PUBLIC_RESEARCH_GALLERY_URL, server/routes/research-gallery.get.ts). A prerendered
|
||||
// page therefore names no deployment's host. A view opens with ?tab=<view id> (for example
|
||||
// 'regions-dashboard'). The reader's language travels as ?lang=<locale>, since the gallery lays
|
||||
// Arabic out right-to-left and an Arabic reader should not land on the English gallery. The
|
||||
// /research and /regions detail pages are kept; nothing links to them any more.
|
||||
export function useResearchGalleryUrl() {
|
||||
const { locale } = useI18n()
|
||||
return (tab?: string): string => {
|
||||
const q = new URLSearchParams()
|
||||
if (tab) q.set('tab', tab)
|
||||
if (locale.value && locale.value !== 'en') q.set('lang', locale.value)
|
||||
const s = q.toString()
|
||||
return `/research-gallery${s ? `?${s}` : ''}`
|
||||
}
|
||||
}
|
||||
|
|
@ -1,4 +1,5 @@
|
|||
<script setup lang="ts">
|
||||
const researchGallery = useResearchGalleryUrl() // /research and /regions moved to the gallery's subdomain
|
||||
// Port of marketing-theme/404.php. Nuxt's `error.vue` replaces the root
|
||||
// app when an error is thrown (including nuxt's built-in 404). Wraps the
|
||||
// message in the public default layout so header/footer still render.
|
||||
|
|
@ -24,7 +25,7 @@ const localePath = useLocalePath()
|
|||
<li><NuxtLink :to="localePath('/')">{{ t('Home') }}</NuxtLink></li>
|
||||
<li><NuxtLink :to="localePath('/pray')">{{ t('Pray') }}</NuxtLink></li>
|
||||
<li><NuxtLink :to="localePath('/adopt')">{{ t('Adopt') }}</NuxtLink></li>
|
||||
<li><NuxtLink :to="localePath('/research')">{{ t('Research') }}</NuxtLink></li>
|
||||
<li><NuxtLink :to="researchGallery()" external>{{ t('Research') }}</NuxtLink></li>
|
||||
<li><NuxtLink :to="localePath('/about')">{{ t('About') }}</NuxtLink></li>
|
||||
<li><NuxtLink :to="localePath('/contact')">{{ t('Contact') }}</NuxtLink></li>
|
||||
</ul>
|
||||
|
|
|
|||
|
|
@ -5,14 +5,17 @@
|
|||
// routes — admin pages declare their own typography in admin.css.
|
||||
|
||||
const { locale, locales } = useI18n()
|
||||
// A page can drop the footer with definePageMeta({ hideFooter: true }): the Research Gallery fills the
|
||||
// viewport below the header, so a footer under it would only add a second, page-level scrollbar.
|
||||
const layoutRoute = useRoute()
|
||||
const { public: pub } = useRuntimeConfig()
|
||||
|
||||
// Warm DNS+TCP+TLS for the cross-origin services these pages hit: the prayer
|
||||
// data API (people-group components) and the idle-loaded analytics + feedback
|
||||
// widget scripts. Deriving from runtime config keeps these correct per env.
|
||||
// data API (people-group components) and the idle-loaded analytics script.
|
||||
// Deriving from runtime config keeps these correct per env.
|
||||
const preconnectOrigins = computed(() => {
|
||||
const origins = new Set<string>()
|
||||
for (const url of [pub.prayBaseUrl, pub.statinatorUrl, pub.feedbackApiBase]) {
|
||||
for (const url of [pub.prayBaseUrl, pub.statinatorUrl]) {
|
||||
if (!url) continue
|
||||
try {
|
||||
origins.add(new URL(String(url)).origin)
|
||||
|
|
@ -69,7 +72,7 @@ const { isLoading } = useLoadingIndicator()
|
|||
<main class="site-main" :class="{ 'site-main--loading': isLoading }">
|
||||
<slot />
|
||||
</main>
|
||||
<TheFooter />
|
||||
<TheFooter v-if="!layoutRoute.meta.hideFooter" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
|
|
|
|||
97
app/pages/about/definitions.vue
Normal file
97
app/pages/about/definitions.vue
Normal file
|
|
@ -0,0 +1,97 @@
|
|||
<script setup lang="ts">
|
||||
// Terminology page (/about/definitions). Hardcoded rather than CMS:
|
||||
// each locale ships its own edition in app/utils/terms/ documenting that
|
||||
// language's terminology decisions; locales without an edition fall back
|
||||
// to the English one. The CMS keeps a "definitions" page under About only
|
||||
// so the sidebar lists it; this route takes priority over the catch-all.
|
||||
|
||||
import { getTermsContent } from '~/utils/terms'
|
||||
|
||||
interface PageResponse {
|
||||
title: string
|
||||
menu_parent: { slug: string; title: string }
|
||||
children: Array<{ slug: string; url: string; title: string }>
|
||||
}
|
||||
|
||||
const { locale } = useI18n()
|
||||
const localePath = useLocalePath()
|
||||
|
||||
const content = computed(() => getTermsContent(locale.value))
|
||||
|
||||
const { data: about } = await useAsyncData<PageResponse | null>(
|
||||
() => `about-sidebar-${locale.value}`,
|
||||
async () => {
|
||||
try {
|
||||
return await $fetch<PageResponse>('/api/pages/about', {
|
||||
query: { locale: locale.value }
|
||||
})
|
||||
} catch {
|
||||
return null
|
||||
}
|
||||
},
|
||||
{ watch: [() => locale.value] }
|
||||
)
|
||||
|
||||
useHead(() => ({ title: content.value.title }))
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="container page-content">
|
||||
<div class="with-sidebar">
|
||||
<aside class="sidebar">
|
||||
<nav class="stack" aria-label="Child pages navigation">
|
||||
<div>
|
||||
<ul class="stack | max-width-xs" role="list">
|
||||
<li v-if="about">
|
||||
<span class="font-size-lg category-heading">
|
||||
{{ about.menu_parent.title }}
|
||||
</span>
|
||||
</li>
|
||||
<li v-for="child in about?.children ?? []" :key="child.url">
|
||||
<NuxtLink
|
||||
:class="{ 'current-link': child.url === 'about/definitions' }"
|
||||
:to="localePath(`/${child.url}`)"
|
||||
>{{ child.title }}</NuxtLink>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</nav>
|
||||
</aside>
|
||||
|
||||
<article class="page">
|
||||
<h1 class="page-title">{{ content.title }}</h1>
|
||||
<div class="page-body">
|
||||
<p v-for="(paragraph, i) in content.intro" :key="i">{{ paragraph }}</p>
|
||||
|
||||
<!-- Entries render as flat children of .page-body — the same shape the
|
||||
CMS catch-all produces — so the site's direct-child typography
|
||||
rules (heading and paragraph rhythm) apply as on CMS pages.
|
||||
Wrapping each entry in an element would defeat those selectors
|
||||
(and <section> carries landing-page band padding globally). -->
|
||||
<template v-for="entry in content.entries" :key="entry.term">
|
||||
<h2>{{ entry.term }}</h2>
|
||||
<p v-if="entry.english">
|
||||
<em>{{ content.labels.english }} {{ entry.english }}</em>
|
||||
</p>
|
||||
<p v-if="entry.definition">
|
||||
<!-- Spaces are interpolated: literal whitespace at template-fragment
|
||||
edges is stripped by Vue's whitespace condensing. -->
|
||||
<template v-if="entry.english"><strong>{{ content.labels.definition }}</strong>{{ ' ' }}</template>{{ entry.definition }}
|
||||
</p>
|
||||
<p v-if="entry.alternatives">
|
||||
<strong>{{ content.labels.alternatives }}</strong> {{ entry.alternatives }}
|
||||
</p>
|
||||
<p v-if="entry.jp || entry.pg">
|
||||
<template v-if="entry.jp"><strong>{{ content.labels.jp }}</strong>{{ ' ' + entry.jp }}</template>
|
||||
<template v-if="entry.jp && entry.pg">{{ ' ' }}</template>
|
||||
<template v-if="entry.pg"><strong>{{ content.labels.pg }}</strong>{{ ' ' + entry.pg }}</template>
|
||||
</p>
|
||||
<p v-if="entry.rationale">
|
||||
<strong>{{ content.labels.rationale }}</strong> {{ entry.rationale }}
|
||||
</p>
|
||||
</template>
|
||||
</div>
|
||||
</article>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
|
@ -1,4 +1,5 @@
|
|||
<script setup lang="ts">
|
||||
const researchGallery = useResearchGalleryUrl() // /research and /regions moved to the gallery's subdomain
|
||||
// Port of marketing-theme/page-adopt.php.
|
||||
|
||||
import { buildUupgListTranslations } from '~/utils/uupgListTranslations'
|
||||
|
|
@ -89,7 +90,7 @@ useTextHighlight()
|
|||
</div>
|
||||
<DoxaMapSlot map-id="adopt-map" :profile-config="adoptMapConfig" class="rounded-md" />
|
||||
<NuxtLink
|
||||
:to="localePath('/research')"
|
||||
:to="researchGallery()" external
|
||||
class="research-map-link"
|
||||
>
|
||||
Explore our research maps →
|
||||
|
|
|
|||
|
|
@ -1,51 +1,87 @@
|
|||
<script setup lang="ts">
|
||||
// Port of marketing-theme/page-contact.php.
|
||||
// Markup, classes, field names, labels, placeholders, and submit flow
|
||||
// mirror the source exactly. The Turnstile widget is rendered via the
|
||||
// @nuxtjs/turnstile module; the form submits to our server proxy at
|
||||
// /api/contact which verifies the token and forwards to pray.doxa.life.
|
||||
// Contact form. Shares its shape and copy with the campaigns-server feedback
|
||||
// form (app/pages/feedback.vue there) — a required message category, the same
|
||||
// field labels and placeholders, a consent switch and a full-width submit —
|
||||
// because both open the same kind of inbox conversation. The category is sent
|
||||
// on as the campaigns-server `feedback_type`, while `source: doxa_life` (added
|
||||
// by the server proxy) keeps these messages identifiable in the inbox.
|
||||
//
|
||||
// The form posts to our server proxy at /api/contact which verifies the
|
||||
// Turnstile token and forwards to pray.doxa.life. Turnstile runs in
|
||||
// interaction-only mode, so it stays invisible unless Cloudflare decides the
|
||||
// visitor actually needs to be challenged.
|
||||
|
||||
import { COUNTRIES } from '~/utils/countries'
|
||||
import type { MessageType } from '~/types/contact'
|
||||
|
||||
const { t, locale } = useI18n()
|
||||
|
||||
const messageType = ref<MessageType | null>(null)
|
||||
const name = ref('')
|
||||
const email = ref('')
|
||||
const honeypot = ref('') // matches the `name="email"` trap in the PHP template
|
||||
const country = ref('')
|
||||
const message = ref('')
|
||||
const consent = ref(false)
|
||||
const turnstileToken = ref('')
|
||||
|
||||
const submitting = ref(false)
|
||||
const submitDisabled = computed(() => submitting.value || !turnstileToken.value)
|
||||
|
||||
const messageEl = ref<HTMLDivElement | null>(null)
|
||||
const typeError = ref('')
|
||||
const emailError = ref('')
|
||||
const messageError = ref('')
|
||||
|
||||
const messageText = ref('')
|
||||
const messageClass = ref<'success' | 'error' | ''>('')
|
||||
const formRef = ref<HTMLFormElement | null>(null)
|
||||
const turnstileRef = ref<{ reset: () => void } | null>(null)
|
||||
|
||||
const EMAIL_REGEX = /^[^\s@]+@[^\s@]+\.[^\s@]+$/
|
||||
|
||||
async function onSubmit(e: Event) {
|
||||
e.preventDefault()
|
||||
if (honeypot.value) return
|
||||
if (formRef.value && !formRef.value.checkValidity()) {
|
||||
formRef.value.reportValidity()
|
||||
|
||||
typeError.value = ''
|
||||
emailError.value = ''
|
||||
messageError.value = ''
|
||||
messageText.value = ''
|
||||
messageClass.value = ''
|
||||
|
||||
const trimmedEmail = email.value.trim()
|
||||
const trimmedMessage = message.value.trim()
|
||||
let valid = true
|
||||
if (!messageType.value) {
|
||||
typeError.value = t('Please choose what your message is about.')
|
||||
valid = false
|
||||
}
|
||||
if (!EMAIL_REGEX.test(trimmedEmail)) {
|
||||
emailError.value = t('Please enter a valid email address.')
|
||||
valid = false
|
||||
}
|
||||
if (!trimmedMessage) {
|
||||
messageError.value = t('Please enter a message.')
|
||||
valid = false
|
||||
}
|
||||
if (!valid) return
|
||||
|
||||
// The widget is invisible and re-arms itself periodically, so a missing token
|
||||
// means "not ready yet" rather than "failed" — say so instead of letting the
|
||||
// proxy reject the submission with a generic error.
|
||||
if (!turnstileToken.value) {
|
||||
messageClass.value = 'error'
|
||||
messageText.value = t('Verification is still loading. Please try again in a moment.')
|
||||
return
|
||||
}
|
||||
|
||||
submitting.value = true
|
||||
messageText.value = ''
|
||||
messageClass.value = ''
|
||||
|
||||
try {
|
||||
const response = await $fetch<{ status: string; message?: string }>('/api/contact', {
|
||||
const response = await $fetch<{ status: string, message?: string }>('/api/contact', {
|
||||
method: 'POST',
|
||||
body: {
|
||||
name: name.value,
|
||||
email: email.value,
|
||||
country: country.value,
|
||||
message: message.value,
|
||||
email: trimmedEmail,
|
||||
message: trimmedMessage,
|
||||
message_type: messageType.value,
|
||||
consent_doxa_general: consent.value,
|
||||
language: locale.value,
|
||||
cf_turnstile: turnstileToken.value
|
||||
|
|
@ -55,10 +91,10 @@ async function onSubmit(e: Event) {
|
|||
if (response?.status === 'success') {
|
||||
messageClass.value = 'success'
|
||||
messageText.value = t('Thank you for your message. We will get back to you soon!')
|
||||
window.goStats?.track('contact_submit', { metadata: { language: locale.value, country: country.value || null } })
|
||||
window.goStats?.track('contact_submit', { metadata: { language: locale.value, message_type: messageType.value } })
|
||||
messageType.value = null
|
||||
name.value = ''
|
||||
email.value = ''
|
||||
country.value = ''
|
||||
message.value = ''
|
||||
consent.value = false
|
||||
formRef.value?.reset()
|
||||
|
|
@ -78,16 +114,26 @@ async function onSubmit(e: Event) {
|
|||
</script>
|
||||
|
||||
<template>
|
||||
<div class="container page-content">
|
||||
<h1 class="page-title">{{ t('Contact Us') }}</h1>
|
||||
<div class="container page-content max-width-lg">
|
||||
<h1 class="page-title">
|
||||
{{ t('Contact Us') }}
|
||||
</h1>
|
||||
<p class="center contact-intro">
|
||||
{{ t("We'd love to hear from you — tell us what you love, share a suggestion, or report a problem.") }}
|
||||
</p>
|
||||
|
||||
<form
|
||||
id="contact-form"
|
||||
ref="formRef"
|
||||
class="stack stack--md max-width-lg center"
|
||||
class="stack stack--md center form--quiet"
|
||||
novalidate
|
||||
@submit="onSubmit"
|
||||
>
|
||||
<input type="hidden" name="action" value="contact_us">
|
||||
<input
|
||||
type="hidden"
|
||||
name="action"
|
||||
value="contact_us"
|
||||
>
|
||||
<input
|
||||
v-model="honeypot"
|
||||
type="email"
|
||||
|
|
@ -97,6 +143,28 @@ async function onSubmit(e: Event) {
|
|||
tabindex="-1"
|
||||
>
|
||||
|
||||
<div class="">
|
||||
<span
|
||||
id="message-type-label"
|
||||
class="field-label"
|
||||
>
|
||||
{{ t('What is your message about?') }}<span
|
||||
class="required-marker"
|
||||
aria-hidden="true"
|
||||
>*</span>
|
||||
</span>
|
||||
<MessageTypeSelect
|
||||
v-model="messageType"
|
||||
label-id="message-type-label"
|
||||
/>
|
||||
<p
|
||||
v-if="typeError"
|
||||
class="field-error"
|
||||
>
|
||||
{{ typeError }}
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="">
|
||||
<label for="name">{{ t('Name') }}</label>
|
||||
<input
|
||||
|
|
@ -104,13 +172,17 @@ async function onSubmit(e: Event) {
|
|||
v-model="name"
|
||||
type="text"
|
||||
name="name"
|
||||
required
|
||||
:placeholder="t('Enter your name')"
|
||||
:placeholder="t('Your name (optional)')"
|
||||
>
|
||||
</div>
|
||||
|
||||
<div class="">
|
||||
<label for="contact_email">{{ t('Email') }}</label>
|
||||
<label for="contact_email">
|
||||
{{ t('Email') }}<span
|
||||
class="required-marker"
|
||||
aria-hidden="true"
|
||||
>*</span>
|
||||
</label>
|
||||
<input
|
||||
id="contact_email"
|
||||
v-model="email"
|
||||
|
|
@ -119,60 +191,93 @@ async function onSubmit(e: Event) {
|
|||
required
|
||||
:placeholder="t('Enter your email')"
|
||||
>
|
||||
<p
|
||||
v-if="emailError"
|
||||
class="field-error"
|
||||
>
|
||||
{{ emailError }}
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="">
|
||||
<label for="country">{{ t('Your Country (optional)') }}</label>
|
||||
<select id="country" v-model="country" name="country">
|
||||
<option value="">{{ t('Select Country') }}</option>
|
||||
<option v-for="c in COUNTRIES" :key="c.value" :value="c.value">{{ c.label }}</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div class="">
|
||||
<label for="message">{{ t('Message') }}</label>
|
||||
<label for="message">
|
||||
{{ t('Message') }}<span
|
||||
class="required-marker"
|
||||
aria-hidden="true"
|
||||
>*</span>
|
||||
</label>
|
||||
<textarea
|
||||
id="message"
|
||||
v-model="message"
|
||||
name="message"
|
||||
rows="5"
|
||||
required
|
||||
:placeholder="t('Enter your message')"
|
||||
:placeholder="t('Tell us more…')"
|
||||
/>
|
||||
<p
|
||||
v-if="messageError"
|
||||
class="field-error"
|
||||
>
|
||||
{{ messageError }}
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="form-control color-primary-darker">
|
||||
<input
|
||||
id="consent-doxa-general"
|
||||
<div class="form-consent">
|
||||
<ToggleSwitch
|
||||
v-model="consent"
|
||||
type="checkbox"
|
||||
name="consent_doxa_general"
|
||||
label-id="consent-doxa-general"
|
||||
/>
|
||||
<span
|
||||
id="consent-doxa-general"
|
||||
class="form-consent__label"
|
||||
@click="consent = !consent"
|
||||
>
|
||||
<label for="consent-doxa-general">{{ t('I would like to receive email updates from the DOXA partnership.') }}</label>
|
||||
{{ t("I'd like to receive email updates from the DOXA partnership.") }}
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<NuxtTurnstile
|
||||
ref="turnstileRef"
|
||||
v-model="turnstileToken"
|
||||
:options="{ theme: 'light' }"
|
||||
:options="{ theme: 'light', appearance: 'interaction-only' }"
|
||||
/>
|
||||
|
||||
<div
|
||||
id="contact-message"
|
||||
ref="messageEl"
|
||||
class="contact-message"
|
||||
:class="messageClass"
|
||||
:style="{ display: messageText ? 'block' : 'none' }"
|
||||
>{{ messageText }}</div>
|
||||
>
|
||||
{{ messageText }}
|
||||
</div>
|
||||
|
||||
<button
|
||||
id="contact-submit"
|
||||
type="submit"
|
||||
class="button"
|
||||
:disabled="submitDisabled"
|
||||
class="button width-100"
|
||||
:disabled="submitting"
|
||||
>
|
||||
{{ submitting ? t('Submitting...') : t('Submit') }}
|
||||
{{ submitting ? t('Sending…') : t('Send message') }}
|
||||
</button>
|
||||
</form>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
.contact-intro {
|
||||
color: var(--color-text-muted);
|
||||
margin-bottom: var(--spacing-lg);
|
||||
}
|
||||
|
||||
/* Matches the weight and spacing of the <label>s the other fields use, for the
|
||||
one field whose control is a button group rather than a labelable input. */
|
||||
.field-label {
|
||||
display: block;
|
||||
}
|
||||
|
||||
/* `.button` centres nothing by default because it is sized to its content; as a
|
||||
full-width submit it needs its own text centring. */
|
||||
#contact-submit {
|
||||
text-align: center;
|
||||
}
|
||||
</style>
|
||||
|
|
|
|||
198
app/pages/embed-test.vue
Normal file
198
app/pages/embed-test.vue
Normal file
|
|
@ -0,0 +1,198 @@
|
|||
<script setup lang="ts">
|
||||
// /embed-test — proves that EVERY dx-maps plugin built for the web embeds on this site as JavaScript
|
||||
// (no iframe). The list is read at runtime from the dx-maps tree's manifest.json, never typed here:
|
||||
// section 1 is every profile whose stage is "production", section 2 every other profile. A profile whose
|
||||
// manifest `targets` leaves out "web" (a desktop-only plugin) is skipped. So a plugin promoted, added or
|
||||
// retired changes this page by itself. Each card loads its bundle's script from the same tree the rest of the site uses and adds
|
||||
// the element the bundle defines, the way the manifest's embed.script snippet does.
|
||||
//
|
||||
// A map owns a WebGL context and a browser allows only a handful at once, so a card MOUNTS its
|
||||
// element when it scrolls into view and REMOVES it when it scrolls far away. ?only=<bundle>/<profile>
|
||||
// (comma-separated, or a bundle name) shows just those cards, for a single-plugin check.
|
||||
|
||||
import { mapboxTokenIfChosen } from '~/utils/mapProvider'
|
||||
useHead({ title: 'Embed test', meta: [{ name: 'robots', content: 'noindex' }] })
|
||||
|
||||
interface Card {
|
||||
key: string
|
||||
bundle: string
|
||||
profile: string
|
||||
tag: string
|
||||
script: string
|
||||
integrity: string
|
||||
description: string
|
||||
production: boolean
|
||||
locale: string // the language handed to the element (data-locale, for a probe)
|
||||
state: 'idle' | 'loading' | 'mounted' | 'error'
|
||||
error: string
|
||||
}
|
||||
|
||||
const runtimeConfig = useRuntimeConfig()
|
||||
const route = useRoute()
|
||||
const { locale } = useI18n() // the site's language, handed to every plugin (it is in the path, not ?lang)
|
||||
const cards = ref<Card[]>([])
|
||||
const status = ref('Reading the manifest…')
|
||||
const hosts = new Map<string, HTMLElement>()
|
||||
let observer: IntersectionObserver | null = null
|
||||
|
||||
// The dx-maps tree: the deployment's NUXT_PUBLIC_DX_MAPS_BASE, asked from this site's server when the page
|
||||
// mounts (loadDxRuntime), never read from the page's own config.
|
||||
let tree = ''
|
||||
function treeBase(): string {
|
||||
return tree
|
||||
}
|
||||
const resolveUrl = (base: string, ref: string) =>
|
||||
/^(https?:)?\/\//.test(ref) ? ref : ref.startsWith('/') ? new URL(ref, base).href : `${base}/${ref.replace(/^\.\//, '')}`
|
||||
|
||||
const scripts = new Map<string, Promise<void>>()
|
||||
function loadScript(src: string, integrity: string): Promise<void> {
|
||||
if (!scripts.has(src)) {
|
||||
scripts.set(src, new Promise((resolve, reject) => {
|
||||
const s = document.createElement('script')
|
||||
s.src = src
|
||||
if (integrity) { s.integrity = integrity; s.crossOrigin = 'anonymous' }
|
||||
s.onload = () => resolve()
|
||||
s.onerror = () => reject(new Error(`the script did not load: ${src}`))
|
||||
document.head.appendChild(s)
|
||||
}))
|
||||
}
|
||||
return scripts.get(src)!
|
||||
}
|
||||
|
||||
// The element's config, in the site's CURRENT language: set on mount and again on every language switch,
|
||||
// so a mounted plugin follows the switcher (profile-config.locale for the maps, the language attribute for
|
||||
// the shells).
|
||||
function applyLocale(el: Element, card: Card) {
|
||||
const token = mapboxTokenIfChosen(runtimeConfig.public)
|
||||
el.setAttribute('profile-config', JSON.stringify({
|
||||
profile: card.profile,
|
||||
assetsBase: `${treeBase()}/assets`,
|
||||
locale: locale.value,
|
||||
// MapLibre by default; Mapbox only when NUXT_PUBLIC_MAP_PROVIDER=mapbox and a token is set
|
||||
...(token ? { tk: token } : { provider: 'maplibre' })
|
||||
}))
|
||||
el.setAttribute('language', locale.value)
|
||||
card.locale = locale.value
|
||||
}
|
||||
watch(locale, () => {
|
||||
for (const c of cards.value) {
|
||||
const el = c.state === 'mounted' ? hosts.get(c.key)?.firstElementChild : null
|
||||
if (el) applyLocale(el, c)
|
||||
}
|
||||
})
|
||||
|
||||
async function mount(card: Card) {
|
||||
const host = hosts.get(card.key)
|
||||
if (!host || card.state === 'mounted' || card.state === 'loading') return
|
||||
card.state = 'loading'
|
||||
try {
|
||||
await loadScript(card.script, card.integrity)
|
||||
if (!customElements.get(card.tag)) throw new Error(`<${card.tag}> was not defined by its bundle`)
|
||||
const el = document.createElement(card.tag)
|
||||
// shells (the Research Gallery, Plugin Studio) find their child maps through the tree's manifest
|
||||
el.setAttribute('tree-base', treeBase())
|
||||
applyLocale(el, card)
|
||||
host.replaceChildren(el)
|
||||
card.state = 'mounted'
|
||||
} catch (e) {
|
||||
card.state = 'error'
|
||||
card.error = String((e as Error)?.message || e)
|
||||
}
|
||||
}
|
||||
function unmount(card: Card) {
|
||||
if (card.state !== 'mounted') return
|
||||
hosts.get(card.key)?.replaceChildren()
|
||||
card.state = 'idle'
|
||||
}
|
||||
|
||||
onMounted(async () => {
|
||||
try {
|
||||
tree = await dxMapsBaseOrThrow()
|
||||
} catch (e) {
|
||||
status.value = String((e as Error)?.message || e)
|
||||
return
|
||||
}
|
||||
const base = treeBase()
|
||||
// Must be set before any bundle runs so the maps fetch from the configured prayer API.
|
||||
const pray = (runtimeConfig.public as { prayBaseUrl?: string }).prayBaseUrl
|
||||
if (pray) (window as unknown as { MAP_APP_API_URL?: string }).MAP_APP_API_URL = pray
|
||||
let manifest: { bundles?: Array<Record<string, any>> }
|
||||
try {
|
||||
const r = await fetch(`${base}/manifest.json`, { cache: 'no-cache' })
|
||||
if (!r.ok) throw new Error(`HTTP ${r.status}`)
|
||||
manifest = await r.json()
|
||||
} catch (e) {
|
||||
status.value = `The manifest did not load from ${base}/manifest.json (${(e as Error).message}).`
|
||||
return
|
||||
}
|
||||
const only = String(route.query.only || '').split(',').map((s) => s.trim()).filter(Boolean)
|
||||
const out: Card[] = []
|
||||
for (const b of manifest.bundles || []) {
|
||||
const defined: string[] = b.elements || []
|
||||
for (const p of b.profiles || []) {
|
||||
// desktop-only (or any non-web) plugins are not embeddable in a web page
|
||||
const targets: string[] | undefined = p.targets || b.targets
|
||||
if (Array.isArray(targets) && !targets.includes('web')) continue
|
||||
const key = `${b.bundle}/${p.profile}`
|
||||
if (only.length && !only.includes(key) && !only.includes(b.bundle)) continue
|
||||
// the tag the bundle actually defines (a profile's own element name can name one it does not)
|
||||
const tag = p.element && (!defined.length || defined.includes(p.element)) ? p.element : defined[0] || p.element
|
||||
out.push({ key, bundle: b.bundle, profile: p.profile, tag, script: resolveUrl(base, b.scriptUrl || `${b.bundle}/${b.bundle}.js`),
|
||||
integrity: b.integrity || '', description: p.description || '', production: (p.stage || b.stage) === 'production', locale: '',
|
||||
state: 'idle', error: '' })
|
||||
}
|
||||
}
|
||||
cards.value = [...out.filter((c) => c.production), ...out.filter((c) => !c.production)]
|
||||
const prod = out.filter((c) => c.production).length
|
||||
status.value = `${out.length} web plugins from ${base}/manifest.json (${prod} production, ${out.length - prod} other), each embedded as JavaScript.`
|
||||
await nextTick()
|
||||
observer = new IntersectionObserver((entries) => {
|
||||
for (const en of entries) {
|
||||
const card = cards.value.find((c) => c.key === (en.target as HTMLElement).dataset.card)
|
||||
if (!card) continue
|
||||
if (en.isIntersecting) mount(card)
|
||||
else unmount(card)
|
||||
}
|
||||
}, { rootMargin: '600px 0px' })
|
||||
document.querySelectorAll<HTMLElement>('[data-card]').forEach((n) => observer!.observe(n))
|
||||
})
|
||||
|
||||
onBeforeUnmount(() => {
|
||||
observer?.disconnect()
|
||||
hosts.forEach((h) => h.replaceChildren())
|
||||
})
|
||||
|
||||
const setHost = (key: string) => (el: unknown) => { if (el) hosts.set(key, el as HTMLElement); else hosts.delete(key) }
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="container page-content embed-test stack stack--lg">
|
||||
<h1>Embed test</h1>
|
||||
<p data-embed-status>{{ status }}</p>
|
||||
<template v-for="(c, i) in cards" :key="c.key">
|
||||
<h2 v-if="i === 0 && c.production" data-embed-section="production">1. Production</h2>
|
||||
<h2 v-if="!c.production && (i === 0 || cards[i - 1].production)" data-embed-section="other">2. Every other web plugin</h2>
|
||||
<section class="embed-card" :data-card="c.key" :data-state="c.state" :data-production="c.production" :data-locale="c.locale">
|
||||
<header class="embed-card__head">
|
||||
<strong>{{ c.bundle }} / {{ c.profile }}</strong>
|
||||
<code><{{ c.tag }}></code>
|
||||
<span class="embed-card__state">{{ c.state }}</span>
|
||||
</header>
|
||||
<p v-if="c.description" class="embed-card__desc">{{ c.description }}</p>
|
||||
<p v-if="c.error" class="embed-card__error" role="alert">{{ c.error }}</p>
|
||||
<div :ref="setHost(c.key)" class="embed-card__host" />
|
||||
</section>
|
||||
</template>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
.embed-card { border: 1px solid #d1d4cd; border-radius: 10px; overflow: hidden; }
|
||||
.embed-card__head { display: flex; flex-wrap: wrap; gap: 8px 12px; align-items: baseline; padding: 10px 12px; background: #f3f3f1; }
|
||||
.embed-card__state { margin-inline-start: auto; font-size: 12px; color: #6d766e; }
|
||||
.embed-card__desc { margin: 0; padding: 6px 12px; font-size: 13px; color: #3b463d; }
|
||||
.embed-card__error { margin: 0; padding: 6px 12px; color: #a0302a; }
|
||||
.embed-card__host { position: relative; height: 560px; }
|
||||
.embed-card__host :deep(> *) { display: block; width: 100%; height: 100%; }
|
||||
@media (max-width: 600px) { .embed-card__host { height: 480px; } }
|
||||
</style>
|
||||
|
|
@ -1,4 +1,5 @@
|
|||
<script setup lang="ts">
|
||||
const researchGallery = useResearchGalleryUrl() // /research and /regions moved to the gallery's subdomain
|
||||
// Port of marketing-theme/front-page.php.
|
||||
// Each <section> mirrors the PHP source in the same order with the same
|
||||
// CUBE classes, data attributes, asset paths, and strings. Dynamic bits
|
||||
|
|
@ -19,7 +20,7 @@ function openVideo() {
|
|||
videoModalRef.value?.open()
|
||||
}
|
||||
|
||||
const { unengagedPeopleGroupsFormatted, totalPeopleGroupsFormatted, unengagedPopulationMillionsFormatted, ensureLoaded, reload } = usePrayerStatistics()
|
||||
const { unengagedPeopleGroupsFormatted, totalPeopleGroupsFormatted, unengagedPopulation, ensureLoaded, reload } = usePrayerStatistics()
|
||||
await ensureLoaded()
|
||||
// This page is prerendered, so its payload carries build-time counts; refetch
|
||||
// on the client so the figures track the live API between deploys.
|
||||
|
|
@ -28,6 +29,13 @@ onMounted(() => reload())
|
|||
// Locale separators with Latin digits, matching usePrayerStatistics — for the
|
||||
// bullseye's static figures (e.g. 3.9 → "3,9" and 6602 → "6.602" in pt).
|
||||
const formatNumber = (n: number) => n.toLocaleString(`${locale.value}-u-nu-latn`)
|
||||
// Population magnitudes in the locale's own grouping (3.9 billion, 39亿, 20.2 करोड़).
|
||||
// Three significant digits so 201.6M stays 2.02亿 rather than collapsing to 2亿.
|
||||
const formatPopulation = (n: number) => new Intl.NumberFormat(`${locale.value}-u-nu-latn`, {
|
||||
notation: 'compact',
|
||||
compactDisplay: 'long',
|
||||
maximumSignificantDigits: 3
|
||||
}).format(n)
|
||||
|
||||
const mapboxToken = config.public.mapboxToken as string
|
||||
|
||||
|
|
@ -109,7 +117,7 @@ useTextHighlight()
|
|||
</div>
|
||||
<DoxaMapSlot map-id="home-map" :profile-config="homeMapConfig" class="rounded-xlg" />
|
||||
<NuxtLink
|
||||
:to="localePath('/research')"
|
||||
:to="researchGallery()" external
|
||||
class="research-map-link"
|
||||
>
|
||||
Explore our research maps →
|
||||
|
|
@ -130,18 +138,7 @@ useTextHighlight()
|
|||
:research-url="localePath('/research') + '/'"
|
||||
:language-code="locale"
|
||||
/>
|
||||
<div class="stack stack--2xl">
|
||||
<h2 class="highlight" data-highlight-last>{{ t('A simple path to faithful obedience') }}</h2>
|
||||
<div class="switcher | gap-md">
|
||||
<div class="step-card">
|
||||
<div class="step-card__content">
|
||||
<h2 class="step-card__title">{{ t('Pray') }}</h2>
|
||||
<p>{{ t('Receive daily prayer points and join believers worldwide in prayer for the unengaged peoples.') }}</p>
|
||||
</div>
|
||||
<NuxtLink :to="localePath('/pray')" class="button | compact">{{ t('Join') }}</NuxtLink>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<NuxtLink :to="localePath('/pray')" class="center | button | compact">{{ t('Join') }}</NuxtLink>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
|
|
@ -160,7 +157,7 @@ useTextHighlight()
|
|||
<div class="info-card color-brand-dark justify-center">
|
||||
<div class="stack stack--lg | info-card__content">
|
||||
<h3 class="color-brand-lighter">{{ t('Unreached') }}</h3>
|
||||
<span>{{ t('{0} Billion', [formatNumber(3.9)]) }}</span>
|
||||
<span>{{ formatPopulation(3_900_000_000) }}</span>
|
||||
<span class="color-brand-lighter">{{ t('{0} People Groups', [formatNumber(6602)]) }}</span>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -169,7 +166,7 @@ useTextHighlight()
|
|||
<div class="info-card color-secondary-very-light justify-center">
|
||||
<div class="stack stack--lg | info-card__content">
|
||||
<h3>{{ t('Under-Engaged') }}</h3>
|
||||
<span class="color-secondary-light">{{ t('{0} Billion', [formatNumber(3.3)]) }}</span>
|
||||
<span class="color-secondary-light">{{ formatPopulation(3_300_000_000) }}</span>
|
||||
<span>{{ t('{0} People Groups', [formatNumber(5119)]) }}</span>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -178,7 +175,7 @@ useTextHighlight()
|
|||
<div class="info-card color-secondary-very-light justify-center">
|
||||
<div class="stack stack--lg | info-card__content">
|
||||
<h3>{{ t('Frontier People') }}</h3>
|
||||
<span class="color-secondary-light">{{ t('{0} Billion', [formatNumber(2)]) }}</span>
|
||||
<span class="color-secondary-light">{{ formatPopulation(2_000_000_000) }}</span>
|
||||
<span>{{ t('{0} People Groups', [formatNumber(4788)]) }}</span>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -187,7 +184,7 @@ useTextHighlight()
|
|||
<div class="info-card surface-brand-dark justify-center">
|
||||
<div class="stack stack--lg | info-card__content">
|
||||
<h3>{{ t('Unengaged') }}</h3>
|
||||
<span>{{ t('{0} Million', [unengagedPopulationMillionsFormatted]) }}</span>
|
||||
<span>{{ formatPopulation(unengagedPopulation) }}</span>
|
||||
<span>{{ t('{0} People Groups', [unengagedPeopleGroupsFormatted]) }}</span>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
<script setup lang="ts">
|
||||
const researchGallery = useResearchGalleryUrl() // /research and /regions moved to the gallery's subdomain
|
||||
// Port of marketing-theme/page-pray.php.
|
||||
|
||||
import { buildUupgListTranslations } from '~/utils/uupgListTranslations'
|
||||
|
|
@ -121,7 +122,7 @@ useTextHighlight()
|
|||
<h2>{{ t('Prayer Progress') }}</h2>
|
||||
<DoxaMapSlot map-id="pray-map" :profile-config="prayMapConfig" class="rounded-md" />
|
||||
<NuxtLink
|
||||
:to="localePath('/research')"
|
||||
:to="researchGallery()" external
|
||||
class="research-map-link"
|
||||
>
|
||||
Explore our research maps →
|
||||
|
|
@ -301,6 +302,8 @@ useTextHighlight()
|
|||
</div>
|
||||
</section>
|
||||
|
||||
<MobileAppSection />
|
||||
|
||||
<section>
|
||||
<div class="container stack stack--5xl">
|
||||
<figure class="text-center font-size-5xl font-heading">
|
||||
|
|
|
|||
|
|
@ -6,6 +6,23 @@
|
|||
|
||||
import type { RegionSummary } from '~~/config/countries-meta'
|
||||
|
||||
// Regions is a view of the Research Gallery now, so /regions (in every language) REDIRECTS there with
|
||||
// ?tab=regions-dashboard and old links keep working. The region and country detail pages (/regions/<slug>)
|
||||
// stay. Set USE_LEGACY_REGIONS_PAGE to true (inside the middleware) to bring this index page back.
|
||||
// The redirect goes through this site's /research-gallery, which resolves the deployment's gallery
|
||||
// address on the server (server/routes/research-gallery.get.ts), so no address is read here.
|
||||
definePageMeta({
|
||||
middleware: [() => {
|
||||
const USE_LEGACY_REGIONS_PAGE = false
|
||||
if (!USE_LEGACY_REGIONS_PAGE) {
|
||||
const lang = (useNuxtApp().$i18n as { locale: { value: string } })?.locale?.value
|
||||
const q = new URLSearchParams({ tab: 'regions-dashboard' })
|
||||
if (lang && lang !== 'en') q.set('lang', lang)
|
||||
return navigateTo(`/research-gallery?${q}`, { external: true, redirectCode: 301 })
|
||||
}
|
||||
}]
|
||||
})
|
||||
|
||||
const { t, locale } = useI18n()
|
||||
const localePath = useLocalePath()
|
||||
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
<script setup lang="ts">
|
||||
const researchGallery = useResearchGalleryUrl() // /research and /regions moved to the gallery's subdomain
|
||||
// Port of marketing-theme/template-uupg-detail.php.
|
||||
// Fetches the people group by slug from
|
||||
// `{prayBaseUrl}/api/people-groups/detail/{slug}?lang={locale}` and renders
|
||||
|
|
@ -150,11 +151,12 @@ const mapSrc = computed(() => {
|
|||
</script>
|
||||
|
||||
<template>
|
||||
<div>
|
||||
<div v-if="notFound || uupgError" class="container page-content uupg-detail-page">
|
||||
<div class="stack stack--lg">
|
||||
<h1>{{ t('People Group Not Found') }}</h1>
|
||||
<p>{{ t('The people group you are looking for could not be found. Please try again.') }}</p>
|
||||
<NuxtLink :to="localePath('/research')" class="button font-size-lg">
|
||||
<NuxtLink :to="researchGallery()" external class="button font-size-lg">
|
||||
<span class="sr-only">{{ t('Back') }}</span>
|
||||
<svg class="icon | rotate-270" viewBox="0 0 489.67 289.877">
|
||||
<path d="M439.017,211.678L263.258,35.919c-3.9-3.9-8.635-6.454-13.63-7.665-9.539-2.376-20.051.161-27.509,7.619L46.361,211.632c-11.311,11.311-11.311,29.65,0,40.961h0c11.311,11.311,29.65,11.311,40.961,0L242.667,97.248l155.39,155.39c11.311,11.311,29.65,11.311,40.961,0h0c11.311-11.311,11.311-29.65,0-40.961Z" />
|
||||
|
|
@ -211,7 +213,7 @@ const mapSrc = computed(() => {
|
|||
<p class="font-weight-medium font-size-lg">
|
||||
{{ uupg.country_code?.label }} ({{ uupg.rop1?.label }})
|
||||
</p>
|
||||
<p>{{ uupg.imb_people_description ?? uupg.location_description }}</p>
|
||||
<p>{{ uupg.imb_people_description }}</p>
|
||||
|
||||
<a
|
||||
v-if="locale === 'en'"
|
||||
|
|
@ -327,4 +329,12 @@ const mapSrc = computed(() => {
|
|||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Full-bleed, so it sits outside the page container above. -->
|
||||
<MobileAppSection
|
||||
v-if="!notFound && !uupgError"
|
||||
:people-group-name="uupg?.name"
|
||||
:people-group-slug="slug"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
<script setup lang="ts">
|
||||
const researchGallery = useResearchGalleryUrl() // /research and /regions moved to the gallery's subdomain
|
||||
// Port of marketing-theme/template-uupg-resources.php (WP rewrite
|
||||
// /research/{slug}/resources/ → template-uupg-resources.php). Fetches
|
||||
// the people group by slug from
|
||||
|
|
@ -127,7 +128,7 @@ async function handleDownloadClick(e: MouseEvent) {
|
|||
<div class="stack stack--lg">
|
||||
<h1>{{ t('People Group Not Found') }}</h1>
|
||||
<p>{{ t('The people group you are looking for could not be found. Please try again.') }}</p>
|
||||
<NuxtLink :to="localePath('/research')" class="button font-size-lg">
|
||||
<NuxtLink :to="researchGallery()" external class="button font-size-lg">
|
||||
<span class="sr-only">{{ t('Back') }}</span>
|
||||
<svg class="icon | rotate-270" viewBox="0 0 489.67 289.877">
|
||||
<path d="M439.017,211.678L263.258,35.919c-3.9-3.9-8.635-6.454-13.63-7.665-9.539-2.376-20.051.161-27.509,7.619L46.361,211.632c-11.311,11.311-11.311,29.65,0,40.961h0c11.311,11.311,29.65,11.311,40.961,0L242.667,97.248l155.39,155.39c11.311,11.311,29.65,11.311,40.961,0h0c11.311-11.311,11.311-29.65,0-40.961Z" />
|
||||
|
|
|
|||
|
|
@ -1,56 +1,127 @@
|
|||
<script setup lang="ts">
|
||||
// Port of marketing-theme/page-uupgs.php.
|
||||
// Matches the PHP markup verbatim: container page-content uupgs-page stack
|
||||
// stack--3xl + a highlighted h1 + the <UupgsList> component. The
|
||||
// `initialSearchTerm` is taken from the `uupg_search` query parameter
|
||||
// (PHP equivalent: `get_query_var('uupg_search')`).
|
||||
// The Research page IS the Research Gallery: every research map, dashboard and list in one app,
|
||||
// filling the page below the header. It replaces the single research map, the UUPG list and the
|
||||
// "By Region" link that were here. Those three are NOT deleted: they are kept below, switched off by
|
||||
// SHOW_LEGACY_RESEARCH, so the previous page returns by flipping one constant.
|
||||
//
|
||||
// Below the UupgsList we embed the 5-tab `research-map` IIFE built from
|
||||
// the upstream DOXA-MAPS module — exposes Engagement / Prayer
|
||||
// / Adoption (clones of doxa-simple-map) plus Language Families. The
|
||||
// 1040-maps build now publishes /js/doxa-research-map.js (canonical name).
|
||||
// via the publishToDoxaLife() plugin.
|
||||
// The gallery is a web component served from the deployment's dx-maps tree (NUXT_PUBLIC_DX_MAPS_BASE,
|
||||
// the team container's published tree), asked from this site's server at runtime: this page is prerendered,
|
||||
// and a prerendered page cannot carry a deployment's address. It reads its manifest and every child map
|
||||
// from the same tree. The menu's Research item goes to the gallery's own subdomain instead; this page
|
||||
// is kept, unlinked. See DX-MAPS-GALLERY.md at the repo root.
|
||||
//
|
||||
// The element is created in onMounted rather than written in the template: it is a custom element
|
||||
// that only exists in the browser, so this keeps it out of SSR and out of Vue's component resolver
|
||||
// without any nuxt.config change.
|
||||
|
||||
import { mapboxTokenIfChosen } from '~/utils/mapProvider'
|
||||
import { buildUupgListTranslations } from '~/utils/uupgListTranslations'
|
||||
|
||||
// ONE scrollbar: no footer here, and the page itself never scrolls; the gallery's own content does.
|
||||
definePageMeta({ hideFooter: true })
|
||||
|
||||
const { t, locale } = useI18n()
|
||||
const runtimeConfig = useRuntimeConfig()
|
||||
|
||||
// The previous Research page (the "By Region" link, the single research map and the UUPG list).
|
||||
// Off on this branch: the Research Gallery replaces all three. Set true to bring them back.
|
||||
const SHOW_LEGACY_RESEARCH = false
|
||||
const localePath = useLocalePath()
|
||||
const route = useRoute()
|
||||
|
||||
const initialSearchTerm = computed(() =>
|
||||
(Array.isArray(route.query.uupg_search) ? route.query.uupg_search[0] : route.query.uupg_search) ?? ''
|
||||
)
|
||||
|
||||
const translations = computed(() => buildUupgListTranslations(t))
|
||||
|
||||
const runtimeConfig = useRuntimeConfig()
|
||||
const researchProfileConfig = computed(() => JSON.stringify({
|
||||
profile: 'research-map',
|
||||
tk: (runtimeConfig.public as { mapboxToken?: string }).mapboxToken || '',
|
||||
dataSource: 'pray-tools',
|
||||
instanceId: 'research-page'
|
||||
}))
|
||||
if (SHOW_LEGACY_RESEARCH) useTextHighlight()
|
||||
|
||||
useTextHighlight()
|
||||
useHead({ title: () => t('Research') })
|
||||
|
||||
const host = ref<HTMLElement | null>(null)
|
||||
let gallery: HTMLElement | null = null
|
||||
let resizeObs: ResizeObserver | null = null
|
||||
|
||||
// The gallery fills the viewport below the header. The header's height differs between desktop
|
||||
// and phone (and with the language), so it is measured, not assumed.
|
||||
function fitBelowHeader() {
|
||||
const header = document.getElementById('masthead')
|
||||
const h = header ? Math.round(header.getBoundingClientRect().height) : 0
|
||||
document.documentElement.style.setProperty('--rg-header-h', h + 'px')
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
fitBelowHeader()
|
||||
// The gallery is sized to the viewport below the header; a sub-pixel header height must not add a
|
||||
// page scrollbar, so the page does not scroll while the gallery is shown.
|
||||
document.documentElement.classList.add('rg-no-page-scroll')
|
||||
const header = document.getElementById('masthead')
|
||||
if (header && 'ResizeObserver' in window) {
|
||||
resizeObs = new ResizeObserver(fitBelowHeader)
|
||||
resizeObs.observe(header)
|
||||
}
|
||||
|
||||
gallery = document.createElement('doxa-maps-spa')
|
||||
// The site's language drives the gallery's (and every map's); it follows the language switcher.
|
||||
gallery.setAttribute('language', locale.value)
|
||||
// MapLibre (keyless) by default; Mapbox only when NUXT_PUBLIC_MAP_PROVIDER=mapbox and a token is set.
|
||||
const token = mapboxTokenIfChosen(runtimeConfig.public)
|
||||
if (token) gallery.setAttribute('profile-config', JSON.stringify({ tk: token }))
|
||||
else gallery.setAttribute('provider', 'maplibre')
|
||||
// The tree, its script and every embed URL come from the deployment's address, asked at RUNTIME, so
|
||||
// the same build works on any host (laptop, staging, production) with nothing hardcoded.
|
||||
dxMapsBaseOrThrow().then((tree) => {
|
||||
if (!gallery) return
|
||||
gallery.setAttribute('tree-base', tree)
|
||||
host.value?.appendChild(gallery)
|
||||
if (!document.querySelector('script[data-research-gallery]')) {
|
||||
const s = document.createElement('script')
|
||||
s.src = `${tree}/doxa-maps-spa/doxa-maps-spa.js`
|
||||
s.dataset.researchGallery = '1'
|
||||
document.head.appendChild(s)
|
||||
}
|
||||
}).catch((err) => {
|
||||
const p = document.createElement('p')
|
||||
p.className = 'research-gallery-error'
|
||||
p.setAttribute('role', 'status')
|
||||
p.textContent = String((err as Error)?.message || err)
|
||||
host.value?.replaceChildren(p)
|
||||
})
|
||||
})
|
||||
|
||||
watch(locale, (lang) => { gallery?.setAttribute('language', lang) })
|
||||
|
||||
onBeforeUnmount(() => {
|
||||
document.documentElement.classList.remove('rg-no-page-scroll')
|
||||
resizeObs?.disconnect()
|
||||
gallery?.remove()
|
||||
gallery = null
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="container page-content uupgs-page stack stack--3xl">
|
||||
<div>
|
||||
<div class="research-gallery-page">
|
||||
<h1 class="visually-hidden">{{ t('Research') }}</h1>
|
||||
<div ref="host" class="research-gallery-host" />
|
||||
</div>
|
||||
|
||||
<!-- The previous Research page, switched off (SHOW_LEGACY_RESEARCH): kept, not deleted. -->
|
||||
<div v-if="SHOW_LEGACY_RESEARCH" class="container page-content uupgs-page stack stack--3xl">
|
||||
<div class="stack stack--xs text-center">
|
||||
<h1 class="highlight" data-highlight-last>{{ t('Find a UUPG') }}</h1>
|
||||
<p><NuxtLink class="light-link" :to="localePath('/regions')">{{ t('By Region') }} →</NuxtLink></p>
|
||||
</div>
|
||||
|
||||
<!-- Research map embed — sits directly under the H1, above the UUPG
|
||||
search bar. Loads /js/doxa-research-map.js (auto-published from
|
||||
the upstream module on every research-mfe build). -->
|
||||
<DoxaMapSlot
|
||||
map-id="research-page-map"
|
||||
bundle="research-map"
|
||||
:profile-config="researchProfileConfig"
|
||||
class="rounded-xlg"
|
||||
/>
|
||||
|
||||
<UupgsList
|
||||
:language-code="locale"
|
||||
:research-url="localePath('/research') + '/'"
|
||||
|
|
@ -59,4 +130,40 @@ useTextHighlight()
|
|||
hide-see-all-link
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
.research-gallery-page {
|
||||
/* 100svh: the phone's SMALL viewport, so the browser's own toolbars never cover the gallery. */
|
||||
height: calc(100svh - var(--rg-header-h, 0px));
|
||||
}
|
||||
.research-gallery-host,
|
||||
.research-gallery-host :deep(doxa-maps-spa) {
|
||||
display: block;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
.research-gallery-host :deep(.research-gallery-error) {
|
||||
max-width: 32rem;
|
||||
margin: 2rem auto;
|
||||
padding: 0 1rem;
|
||||
text-align: center;
|
||||
}
|
||||
.visually-hidden {
|
||||
position: absolute;
|
||||
width: 1px;
|
||||
height: 1px;
|
||||
overflow: hidden;
|
||||
clip: rect(0 0 0 0);
|
||||
white-space: nowrap;
|
||||
}
|
||||
</style>
|
||||
|
||||
<style>
|
||||
/* Not scoped: set on <html> by this page only while the gallery is mounted. */
|
||||
html.rg-no-page-scroll,
|
||||
html.rg-no-page-scroll body {
|
||||
overflow: hidden;
|
||||
}
|
||||
</style>
|
||||
|
|
|
|||
|
|
@ -1,56 +0,0 @@
|
|||
<script setup lang="ts">
|
||||
// Terminology page (/terms, /{locale}/terms). Hardcoded rather than CMS:
|
||||
// each locale ships its own edition in app/utils/terms/ documenting that
|
||||
// language's terminology decisions; locales without an edition fall back
|
||||
// to the English one. Mounted ahead of the CMS catch-all by route priority.
|
||||
|
||||
import { getTermsContent } from '~/utils/terms'
|
||||
|
||||
const { locale } = useI18n()
|
||||
const localePath = useLocalePath()
|
||||
|
||||
const content = computed(() => getTermsContent(locale.value))
|
||||
|
||||
useHead(() => ({ title: content.value.title }))
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="container page-content">
|
||||
<h1 class="page-title">{{ content.title }}</h1>
|
||||
<div class="page-body">
|
||||
<p v-for="(paragraph, i) in content.intro" :key="i">{{ paragraph }}</p>
|
||||
<p>
|
||||
{{ content.seeDefinitionsBefore }}
|
||||
<NuxtLink :to="localePath('/about/definitions')">{{ content.definitionsLinkLabel }}</NuxtLink>{{ content.seeDefinitionsAfter }}
|
||||
</p>
|
||||
|
||||
<!-- Entries render as flat children of .page-body — the same shape the
|
||||
CMS catch-all produces — so the site's direct-child typography
|
||||
rules (heading and paragraph rhythm) apply as on CMS pages.
|
||||
Wrapping each entry in an element would defeat those selectors
|
||||
(and <section> carries landing-page band padding globally). -->
|
||||
<template v-for="entry in content.entries" :key="entry.term">
|
||||
<h2>{{ entry.term }}</h2>
|
||||
<p v-if="entry.english">
|
||||
<em>{{ content.labels.english }} {{ entry.english }}</em>
|
||||
</p>
|
||||
<p v-if="entry.definition">
|
||||
<!-- Spaces are interpolated: literal whitespace at template-fragment
|
||||
edges is stripped by Vue's whitespace condensing. -->
|
||||
<template v-if="entry.english"><strong>{{ content.labels.definition }}</strong>{{ ' ' }}</template>{{ entry.definition }}
|
||||
</p>
|
||||
<p v-if="entry.alternatives">
|
||||
<strong>{{ content.labels.alternatives }}</strong> {{ entry.alternatives }}
|
||||
</p>
|
||||
<p v-if="entry.jp || entry.pg">
|
||||
<template v-if="entry.jp"><strong>{{ content.labels.jp }}</strong>{{ ' ' + entry.jp }}</template>
|
||||
<template v-if="entry.jp && entry.pg">{{ ' ' }}</template>
|
||||
<template v-if="entry.pg"><strong>{{ content.labels.pg }}</strong>{{ ' ' + entry.pg }}</template>
|
||||
</p>
|
||||
<p v-if="entry.rationale">
|
||||
<strong>{{ content.labels.rationale }}</strong> {{ entry.rationale }}
|
||||
</p>
|
||||
</template>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
4
app/types/contact.ts
Normal file
4
app/types/contact.ts
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
// Message categories the contact form offers. The values are the feedback types
|
||||
// the campaigns-server understands (`/api/contact` -> `feedback_type`); only the
|
||||
// labels are worded for a contact-us page.
|
||||
export type MessageType = 'compliment' | 'suggestion' | 'problem'
|
||||
|
|
@ -24,7 +24,6 @@ export interface Uupg {
|
|||
country_label?: any
|
||||
rop1: ValueLabel
|
||||
rop1_label?: any
|
||||
location_description: string
|
||||
has_photo: boolean
|
||||
image_url: string
|
||||
picture_credit: any
|
||||
|
|
|
|||
32
app/utils/dxRuntime.ts
Normal file
32
app/utils/dxRuntime.ts
Normal file
|
|
@ -0,0 +1,32 @@
|
|||
// This deployment's Research Gallery and dx-maps tree, asked from this site's own server at RUNTIME
|
||||
// (/api/dx-runtime). Never read from useRuntimeConfig(): about 4,000 pages are prerendered, and a
|
||||
// prerendered page carries the build's values, so one build could not serve two deployments. See
|
||||
// server/utils/dx-runtime.ts. Browser only: call it from onMounted or later. One request per page load.
|
||||
export interface DxRuntime {
|
||||
researchGalleryUrl: string
|
||||
dxMapsBase: string
|
||||
}
|
||||
|
||||
let pending: Promise<DxRuntime> | null = null
|
||||
|
||||
export function loadDxRuntime(): Promise<DxRuntime> {
|
||||
if (!pending) {
|
||||
pending = fetch('/api/dx-runtime', { cache: 'no-store' })
|
||||
.then((r) => {
|
||||
if (!r.ok) throw new Error(`/api/dx-runtime answered ${r.status}`)
|
||||
return r.json() as Promise<DxRuntime>
|
||||
})
|
||||
.catch((e) => {
|
||||
pending = null
|
||||
throw e
|
||||
})
|
||||
}
|
||||
return pending
|
||||
}
|
||||
|
||||
// The dx-maps tree's address, or an Error that names the missing setting.
|
||||
export async function dxMapsBaseOrThrow(): Promise<string> {
|
||||
const { dxMapsBase } = await loadDxRuntime()
|
||||
if (!dxMapsBase) throw new Error('This deployment has no maps address: set NUXT_PUBLIC_DX_MAPS_BASE.')
|
||||
return dxMapsBase
|
||||
}
|
||||
|
|
@ -4,7 +4,10 @@
|
|||
// `DOCUMENT_RESOURCES_NO_IMAGE` depending on the `useDocuments` flag,
|
||||
// and always renders `GENERAL_RESOURCES_WITH_IMAGE` above it.
|
||||
|
||||
import { hasVideoTranslation } from '~/utils/videoUrls'
|
||||
|
||||
const S3_URL = 'https://s3.doxa.life/'
|
||||
const GOOGLE_DRIVE_URL = 'https://drive.google.com/drive/folders/1TSfjWdu7p0GZ22xXjlppcX_vrgmVyzBV?usp=drive_link'
|
||||
|
||||
export interface ResourceWithImage {
|
||||
key: string
|
||||
|
|
@ -42,9 +45,6 @@ const DOCUMENT_LANGS: Record<string, string[]> = {
|
|||
'initial-proposal': ['en', 'es', 'fr']
|
||||
}
|
||||
|
||||
// Per-language Vimeo URLs for the promo video — same ids as videoUrls.ts.
|
||||
const VIDEO_LANGS = ['en', 'es', 'fr']
|
||||
|
||||
function s3LangCode(docId: string, lang: string): string {
|
||||
const langs = DOCUMENT_LANGS[docId] ?? ['en']
|
||||
return langs.includes(lang) ? lang : 'en'
|
||||
|
|
@ -55,10 +55,6 @@ function hasDocumentTranslation(docId: string, lang: string): boolean {
|
|||
return langs.includes(lang)
|
||||
}
|
||||
|
||||
function hasVideoTranslation(lang: string): boolean {
|
||||
return VIDEO_LANGS.includes(lang)
|
||||
}
|
||||
|
||||
export function resourcesWithImage(videoUrl: (lang: string) => string): ResourceWithImage[] {
|
||||
return [
|
||||
{
|
||||
|
|
@ -87,6 +83,15 @@ export function resourcesWithImage(videoUrl: (lang: string) => string): Resource
|
|||
downloadType: 'link',
|
||||
downloadLink: lang => videoUrl(lang),
|
||||
hasTranslation: lang => hasVideoTranslation(lang)
|
||||
},
|
||||
{
|
||||
key: 'doxa_prayer_card_bundles',
|
||||
title: 'DOXA Prayer Card Bundles per language',
|
||||
imageUrl: '/assets/images/card.png',
|
||||
style: 'width: 80%; padding-top: 10%; padding-bottom: 10%;',
|
||||
downloadType: 'link',
|
||||
downloadLink: () => GOOGLE_DRIVE_URL,
|
||||
hasTranslation: () => true
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
|
|||
8
app/utils/mapProvider.ts
Normal file
8
app/utils/mapProvider.ts
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
// The map engine for every dx-maps map on this site. MapLibre (keyless) is the DEFAULT. Set
|
||||
// NUXT_PUBLIC_MAP_PROVIDER=mapbox to use Mapbox, which also needs NUXT_PUBLIC_MAPBOX_TOKEN; without a token,
|
||||
// even "mapbox" falls back to MapLibre, so a map always starts.
|
||||
// Returns the Mapbox token to hand the maps, or '' for MapLibre.
|
||||
export function mapboxTokenIfChosen(pub: Record<string, unknown>): string {
|
||||
const provider = String(pub.mapProvider || 'maplibre').toLowerCase()
|
||||
return provider === 'mapbox' ? String(pub.mapboxToken || '') : ''
|
||||
}
|
||||
|
|
@ -7,6 +7,11 @@ export interface NavItem {
|
|||
to?: string // internal route (passed through localePath in components)
|
||||
href?: string // external URL (no locale prefix)
|
||||
rel?: string // e.g. 'noopener'
|
||||
// the Research Gallery: this site's /research-gallery, which the server sends to the deployment's gallery;
|
||||
// it opens in the same tab (components/public/TheHeader.vue)
|
||||
hrefConfig?: 'researchGalleryUrl'
|
||||
// kept in the list but not shown: switched off rather than deleted
|
||||
off?: boolean
|
||||
}
|
||||
|
||||
// Main header navigation (desktop). Minimal on purpose — the full list
|
||||
|
|
@ -27,10 +32,14 @@ export const FOOTER_NAV: NavItem[] = [
|
|||
// all viewports. Mirrors the live `#secondary-menu` list.
|
||||
export const SECONDARY_NAV: NavItem[] = [
|
||||
{ key: 'About', to: '/about' },
|
||||
{ key: 'Research', to: '/research' },
|
||||
// The Research Gallery lives on its own subdomain (the Plugin Studio container), so the Research
|
||||
// item links there (NUXT_PUBLIC_RESEARCH_GALLERY_URL). This site's own /research page is kept but no
|
||||
// longer in the menu.
|
||||
{ key: 'Research', hrefConfig: 'researchGalleryUrl' },
|
||||
{ key: 'Pray', to: '/pray' },
|
||||
{ key: 'Adopt', to: '/adopt' },
|
||||
{ key: 'Resources', to: '/resources' },
|
||||
{ key: 'Regions', to: '/regions' },
|
||||
// Off: the Regions view is part of the Research Gallery. The /regions pages are kept.
|
||||
{ key: 'Regions', to: '/regions', off: true },
|
||||
{ key: 'Give', href: 'https://giving.ag.org/donate/600001-6C2327?utm_source=direct_link' }
|
||||
]
|
||||
|
|
|
|||
182
app/utils/terms/ar.ts
Normal file
182
app/utils/terms/ar.ts
Normal file
|
|
@ -0,0 +1,182 @@
|
|||
import type { TermsContent } from './index'
|
||||
|
||||
export const ar: TermsContent = {
|
||||
title: 'تعريف المصطلحات',
|
||||
intro: [
|
||||
'توثّق هذه الصفحة الخيارات الاصطلاحية العربية لشراكة DOXA. لكل مصطلح: تعريفه، والبدائل التي دُرست، وسبب اختياره.',
|
||||
'مصادرنا: مسرد DOXA العربي الذي راجعه متحدثون أصليون، وقد أُكِّد فيه حتى الآن 22 مصطلحًا من أصل 39، ونشير في كل مدخل إلى المصطلحات التي ما زالت مسودة. ولأن الفروق بين اللهجات العربية واسعة، نختار الصياغة التي تُقرأ بطبيعية لدى أوسع شريحة من القرّاء العرب، ونتجنّب الكلمات التي تحمل في بعض البلدان إيحاءً عسكريًا أو سياسيًا. ونتبع ترجمة فاندايك (SVD) في كل تعبير كتابي. أما Joshua Project وPeopleGroups.org (IMB) فلا ينشران بالعربية، لذا لا تستشهد بهما هذه النسخة.'
|
||||
],
|
||||
labels: {
|
||||
english: 'بالإنجليزية:',
|
||||
definition: 'التعريف:',
|
||||
alternatives: 'بدائل دُرست:',
|
||||
jp: 'Joshua Project:',
|
||||
pg: 'PeopleGroups.org:',
|
||||
rationale: 'سبب الاختيار:'
|
||||
},
|
||||
entries: [
|
||||
{
|
||||
term: 'مجموعة شعبية',
|
||||
english: 'people group',
|
||||
definition:
|
||||
'مجموعة إثنولغوية (عِرقية-لغوية) يرى أفرادها أن بينهم انتماءً مشتركًا قائمًا على اللغة والثقافة والدين ونظرة العالم؛ وهي أكبر مجموعة يمكن أن ينتشر فيها الإنجيل دون أن يصطدم بحواجز في الفهم أو القبول. إنها الوحدة الأساسية لكل ما تحصيه DOXA.',
|
||||
rationale:
|
||||
'اتفق عليه ثلاثة مراجعين. المفهوم عِرقي ولغوي لا سياسي، فلا يصحّ أن يُترجَم بـ«دولة» أو «أمة» بمعناها السياسي، ولا بـ«قبيلة» لما تحمله من إيحاء بالبدائية، ولا بـ«فئة اجتماعية». وأي ترجمة غير دقيقة هنا تُفقد كل الإحصاءات معناها.'
|
||||
},
|
||||
{
|
||||
term: 'مجموعة شعبية غير مبلَّغة (UPG)',
|
||||
english: 'unreached people group (UPG)',
|
||||
definition:
|
||||
'حوالي تلميذين أو أقل من كل 100 شخص (≤ 2%)، مع افتقارها إلى القدرة على إنشاء كنائس محلية أصيلة دون مساعدة عبر الثقافات. تتبع DOXA تعريف IMB.',
|
||||
alternatives: 'غير مبلَّغة بالإنجيل',
|
||||
rationale:
|
||||
'اتفق عليه ثلاثة مراجعين، وحذفوا «بالإنجيل» من المصطلح لاختصاره؛ فالمعنى واضح من السياق. والصياغة لا توحي بأن المجموعة «غير مختارة» روحيًا أو مهمَّشة اجتماعيًا.'
|
||||
},
|
||||
{
|
||||
term: 'غير مَخْدُومَة',
|
||||
english: 'unengaged',
|
||||
definition:
|
||||
'لا يُعرَف فيها مؤمنون أو يوجد عدد ضئيل جدًا منهم، ولا يوجد جهد معروف لإنشاء كنائس قادرة على الاستمرار ذاتيًا — أي تغيب عنها المستويات الأربعة للانخراط الفعّال: جهد رسولي (ريادي تأسيسي) مُقيم بين الشعب، والتزام بالعمل داخل الثقافة المحلية وبلغة القلب، والتزام بخدمة طويلة الأمد، وزرع الإنجيل بهدف ظهور حركة لغرس الكنائس.',
|
||||
rationale:
|
||||
'مصطلح تقني يعني أنه لا أحد يخدم بينهم، لا أن الشعب نفسه غير مبالٍ. وتربط «مَخْدُومَة» المصطلح بالخدمة الروحية، فتصف غياب العاملين لا موقف الناس. أشار المراجع إلى أن هناك طرقًا كثيرة لقول ذلك بالعربية، واستقر على هذه لحالة المجموعة.'
|
||||
},
|
||||
{
|
||||
term: 'مجموعة شعبية غير مبلَّغة وغير مَخْدُومَة (UUPG)',
|
||||
english: 'unengaged unreached people group (UUPG)',
|
||||
definition:
|
||||
'الفئة المركّبة: غير مبلَّغة وغير مَخْدُومَة معًا. وهي المجموعات الشعبية الـ2,085 التي تحشد DOXA الصلاة من أجلها.',
|
||||
rationale:
|
||||
'نحتفظ بالاختصار الدولي UUPG ولا نصوغ اختصارًا عربيًا، تماشيًا مع أدوات الصلاة العالمية. أُكِّد المصطلح في المسرد، لكنه لم يحظَ بإجماع عام بين المراجعين.'
|
||||
},
|
||||
{
|
||||
term: 'مجموعة شعبية بها عمل روحي ضعيف',
|
||||
english: 'under-engaged',
|
||||
definition:
|
||||
'حوالي تلميذ واحد أو أقل من كل 100 شخص (≤ 1%): بدأ العمل، لكن الحاجة ما زالت قائمة إلى مزيد من فرق غرس الكنائس لكي يصبح الانخراط مثمرًا.',
|
||||
rationale:
|
||||
'لا تملك العربية مقابلًا موجزًا للبادئة الإنجليزية under-، فالعبارة الوصفية تنقل أن العمل قد بدأ لكنه غير كافٍ في حجمه، وتضع القصور على العمل لا على الشعب. أُكِّد المصطلح، لكنه لم يحظَ بإجماع عام بين المراجعين.'
|
||||
},
|
||||
{
|
||||
term: 'شعوب المناطق البعيدة',
|
||||
english: 'frontier people group',
|
||||
definition:
|
||||
'حوالي تلميذ واحد أو أقل من كل 1,000 شخص (≤ 0.1%)، ولا توجد فيها حركة توجُّه إلى يسوع مؤكَّدة ومستمرة — الأقل تبليغًا بين غير المبلَّغين. المصطلح مأخوذ من Joshua Project.',
|
||||
rationale:
|
||||
'اتفق عليه ثلاثة مراجعين. يتجنّب الإيحاء العسكري أو السياسي الذي قد تحمله الترجمة الحرفية لكلمة frontier، ويحفظ معنى أن العمل بينهم قد يكون أول اتصال لهم بالإنجيل على الإطلاق.'
|
||||
},
|
||||
{
|
||||
term: 'الانخراط · مجموعة مَخْدُومَة',
|
||||
english: 'engagement · engaged',
|
||||
definition:
|
||||
'نشاط مستمر ومُقيم وعبر الثقافات لمشاركة المسيح وتلمذة الناس، يهدف إلى كنائس قادرة على الاستمرار ذاتيًا، ويجري بطرق ملائمة ثقافيًا وذات صلة محلية.',
|
||||
alternatives: 'منخرطة إرساليًا · انخراط إرسالي',
|
||||
rationale:
|
||||
'مصطلح دقيق: مجرد «المشاركة» أو «التواصل» ليس انخراطًا. نستعمل «الانخراط» للاسم، و«مَخْدُومَة» لوصف المجموعة، فتقابل «غير مَخْدُومَة» مباشرة. لاحظ المراجع أن السياق قد يحتمل صيغًا أخرى، وهي المذكورة بين البدائل. يكتب المسرد «مُخْدُومَة» بضمّ الميم، ونكتبها «مَخْدُومَة» بفتحها لأنها اسم مفعول من «خَدَمَ»، كما في «غير مَخْدُومَة».'
|
||||
},
|
||||
{
|
||||
term: 'حركة غرس الكنائس (CPM)',
|
||||
english: 'church-planting movement (CPM)',
|
||||
definition:
|
||||
'تكاثر كنائس محلية أصيلة تغرس كنائس أخرى: أربعة مسارات على الأقل، في كل منها أربعة أجيال روحية، يبلغ مجموعها أكثر من 1,000 شخص.',
|
||||
rationale:
|
||||
'«الغرس» يحفظ صورة الزرع والنمو، و«حركة» تعني زخمًا يتكاثر ذاتيًا لا كنيسة واحدة ولا برنامجًا، على ألّا تُفهم حركةً اجتماعية أو سياسية. نحتفظ بالاختصار الإنجليزي CPM. المصطلح ما زال مسودة في المسرد ولم يؤكده مراجع بعد.'
|
||||
},
|
||||
{
|
||||
term: 'كنيسة محلية أصيلة',
|
||||
english: 'indigenous church',
|
||||
definition:
|
||||
'كنيسة تنشأ من داخل المجموعة الشعبية نفسها، وتنضج في «الذاتيات» الخمس: ذاتية الانتشار، وذاتية الحكم، وذاتية الإعالة، وذاتية التأصيل اللاهوتي، وذاتية الإرسال.',
|
||||
rationale:
|
||||
'«محلية» وحدها قد تعني مجرد كنيسة في الحيّ، فتضيف «أصيلة» معنى التجذّر في الشعب والاستقلال، دون أي إيحاء بـ«الديانة الأصلية» أو الوثنية. المصطلح ما زال مسودة في المسرد ولم يؤكده مراجع بعد.'
|
||||
},
|
||||
{
|
||||
term: 'عاملون عبر الثقافات',
|
||||
english: 'cross-cultural workers',
|
||||
definition:
|
||||
'عاملون في الإرسالية من ثقافة مختلفة يخدمون بين المجموعة الشعبية.',
|
||||
rationale:
|
||||
'صفة «عبر الثقافات» مقصودة: فهم ليسوا من داخل المجموعة. وهي تعبّر عن الاختلاف الثقافي دون أن تقتصر على معنى «الأجنبي».'
|
||||
},
|
||||
{
|
||||
term: 'رب الحصاد',
|
||||
english: 'Lord of the harvest',
|
||||
definition:
|
||||
'لقب كتابي ليسوع (متى 9: 38)، نستعمله في الدعوة إلى الصلاة لكي يرسل عاملين إلى المجموعات الشعبية غير المَخْدُومَة.',
|
||||
rationale:
|
||||
'متى 9: 38 في ترجمة فاندايك: «فَاطْلُبُوا مِنْ رَبِّ الْحَصَادِ أَنْ يُرْسِلَ فَعَلَةً إِلَى حَصَادِهِ». المصطلح يطابق الترجمة الكتابية، لكنه ما زال مسودة في المسرد ولم يؤكده مراجع بعد.'
|
||||
},
|
||||
{
|
||||
term: 'الصلاة تمهّد الطريق',
|
||||
english: 'prayer prepares the way',
|
||||
definition:
|
||||
'القناعة بأن الشفاعة تهيّئ الظروف الروحية لاختراقات الإنجيل قبل وصول العاملين.',
|
||||
rationale:
|
||||
'صدى لإشعياء 40: 3، وهو في ترجمة فاندايك «أَعِدُّوا طَرِيقَ الرَّبِّ». يحفظ المسرد كلمة «الطريق» من الآية لكنه يختار الفعل «تمهّد» بدل «أعِدّوا»، لأنه أوضح في معنى تهيئة الطريق أمام العمل.'
|
||||
},
|
||||
{
|
||||
term: 'لغة القلب',
|
||||
english: 'heart language',
|
||||
definition:
|
||||
'اللغة الأولى للإنسان، التي يفكّر ويشعر بها. عمل الإنجيل والتلمذة لا يكتمل تأثيره إلا بها، وهي تختلف عن اللغة الرسمية أو لغة التعامل التجاري.',
|
||||
rationale:
|
||||
'تعبير إرسالي راسخ يُترجَم حرفيًا ويُفهم بوضوح، ويميّز المفهوم عن «اللغة الرسمية»، وهو أدقّ من «اللغة الأم» التي لا تحمل البعد الوجداني.'
|
||||
},
|
||||
{
|
||||
term: 'نقاط الصلاة اليومية',
|
||||
english: 'prayer points',
|
||||
definition:
|
||||
'طلبات الصلاة اليومية الخاصة بكل مجموعة شعبية التي ترسلها DOXA إلى الشفعاء: متمحورة حول الكتاب المقدس ومرتبطة بالميدان، وتختلف عن المحتوى التعبّدي العام.',
|
||||
rationale:
|
||||
'مؤكَّد في المسرد، ومعه «دليل الصلاة اليومي» للمورد كاملًا، فيستعمل الموقع والرسائل الصيغة نفسها. «اليومية» جزء من المصطلح لأن الالتزام يومي.'
|
||||
},
|
||||
{
|
||||
term: 'تبنّي مجموعة شعبية',
|
||||
english: 'adopt (a people group)',
|
||||
definition:
|
||||
'التزام طويل الأمد تقوده الكنيسة بالصلاة والعطاء والإرسال لكي يبدأ الوصول للانجيل لدى مجموعة شعبية غير مَخْدُومَة بعينها — رعاية إرسالية لا تبنٍّ بالمعنى القانوني الأسري.',
|
||||
alternatives: 'انتماء',
|
||||
rationale:
|
||||
'رأى المراجع أن «انتماء» سلبية أكثر من اللازم، وأن «التبنّي» هو المصطلح الإرسالي المعتاد بالعربية، إذ ينقل تحمّل المسؤولية و«امتلاك» القضية. نستعمل فعل الأمر «تَبنَّ» للدعوة إلى الفعل، والمصدر «تبنّي» للمفهوم.'
|
||||
},
|
||||
{
|
||||
term: 'هديّتنا ليسوع',
|
||||
english: 'our gift to Jesus',
|
||||
definition:
|
||||
'الإطار الذي يجمع الجهد كله: الانخراط بين كل الشعوب بحلول عام 2033 تقدمةَ عبادة جماعية من الكنيسة.',
|
||||
rationale:
|
||||
'مؤكَّد في المسرد. ينبغي أن تُقرأ العبارة تقدمةً وبذلًا في العبادة، لا صفقة أو مقابلًا.'
|
||||
},
|
||||
{
|
||||
term: 'الرابطة العالمية لجماعات الله (WAGF)',
|
||||
english: 'World Assemblies of God Fellowship (WAGF)',
|
||||
definition:
|
||||
'الرابطة العالمية التي أسّست DOXA وترعاها.',
|
||||
rationale:
|
||||
'الاسم المستعمل في النسخة العربية من الموقع، و«جماعة الله» هو الاسم الذي تُعرف به كنائس جماعات الله في العالم العربي. نحتفظ بالاختصار WAGF في كل الموقع. هذا الاسم غير موجود في المسرد بعد.'
|
||||
},
|
||||
{
|
||||
term: 'هيئات إرسال',
|
||||
english: 'sending agencies',
|
||||
definition:
|
||||
'منظمات تجنّد المرسَلين وتدرّبهم وتدعمهم وترسلهم. تعمل DOXA مع هيئات الإرسال (129 هيئة تابعة للرابطة العالمية لجماعات الله حتى عام 2026) لكنها لا تحلّ محلّها.',
|
||||
rationale:
|
||||
'«الإرسال» يُبقي وظيفة الإرسال ظاهرة، وهي ضلع من ثلاثية الصلاة والعطاء والإرسال. المصطلح ما زال مسودة في المسرد ولم يؤكده مراجع بعد.'
|
||||
},
|
||||
{
|
||||
term: 'الصلاة اليومية (من أجل مجموعة شعبية)',
|
||||
english: 'daily prayer (for a people group)',
|
||||
definition:
|
||||
'الالتزام بالصلاة كل يوم من أجل مجموعة شعبية غير مَخْدُومَة بعينها، باستعمال دليل الصلاة اليومي. الهدف: أكثر من 100 شفيع يومي لكل مجموعة شعبية.',
|
||||
rationale:
|
||||
'مؤكَّد في المسرد. كلمة «اليومية» مقصودة: التزام كل يوم، لا صلاة منتظمة أو عرضية. ونسمّي المصلّين «شفعاء» (مفردها «شفيع»)، وهو المصطلح الكنسي المعروف.'
|
||||
},
|
||||
{
|
||||
term: 'كل قبيلة ولسان وشعب وأمة',
|
||||
english: 'every tribe, tongue, people, and nation',
|
||||
definition:
|
||||
'رؤية سفر الرؤيا 5: 9 و7: 9 التي تحرّك الإرسالية. كل واحد من الأسماء الأربعة يحمل بُعدًا مختلفًا من التنوّع البشري.',
|
||||
rationale:
|
||||
'رؤيا 5: 9 في ترجمة فاندايك: «مِنْ كُلِّ قَبِيلَةٍ وَلِسَانٍ وَشَعْبٍ وَأُمَّةٍ»، والمصطلح يطابقها حرفيًا. أما رؤيا 7: 9 فترتّب الأسماء ترتيبًا آخر: «مِنْ كُلِّ الأُمَمِ وَالْقَبَائِلِ وَالشُّعُوبِ وَالأَلْسِنَةِ».'
|
||||
}
|
||||
]
|
||||
}
|
||||
178
app/utils/terms/de.ts
Normal file
178
app/utils/terms/de.ts
Normal file
|
|
@ -0,0 +1,178 @@
|
|||
import type { TermsContent } from './index'
|
||||
|
||||
export const de: TermsContent = {
|
||||
title: 'Begriffsbestimmungen',
|
||||
intro: [
|
||||
'Diese Seite dokumentiert die deutschen Begriffsentscheidungen der DOXA-Partnerschaft. Zu jedem Begriff: die Definition, die erwogenen Alternativen, was Joshua Project und PeopleGroups.org (IMB) verwenden, und der Grund für unsere Wahl.',
|
||||
'Unsere Quellen: das von einem deutschsprachigen Prüfer durchgesehene DOXA-Glossar, der Sprachgebrauch deutschsprachiger Missionswerke und Gebetsnetzwerke (etwa Unerreichte-Volksgruppen.de) sowie Schlachter 2000 als Referenzübersetzung – zum Abgleich auch Luther 2017 – für jede Wendung biblischen Ursprungs.'
|
||||
],
|
||||
labels: {
|
||||
english: 'Englisch:',
|
||||
definition: 'Definition:',
|
||||
alternatives: 'Erwogene Alternativen:',
|
||||
jp: 'Joshua Project:',
|
||||
pg: 'PeopleGroups.org:',
|
||||
rationale: 'Warum diese Wahl:'
|
||||
},
|
||||
entries: [
|
||||
{
|
||||
term: 'Volksgruppe',
|
||||
english: 'people group',
|
||||
definition:
|
||||
'eine ethno-linguistische Gruppe, deren Mitglieder sich durch Sprache, Kultur, Religion und Weltanschauung verbunden wissen – die größte Gruppe, innerhalb derer sich das Evangelium ohne Verständnis- oder Akzeptanzbarrieren ausbreiten kann. Die Grundeinheit von allem, was DOXA zählt.',
|
||||
alternatives: 'Völker · Volk · ethnische Gruppe · Menschengruppe · Personengruppe',
|
||||
rationale:
|
||||
'der eingeführte Begriff der deutschsprachigen Missionsbewegung. Unser Prüfer: „Wir sagen nie Völker, sondern immer Volksgruppen.“ Der Plural „Völker“ klingt nach Nationen, „Personengruppe“ nach Statistik. In der Schweiz ist „Völker“ geläufiger; wir folgen dem deutschen Gebrauch und schreiben durchgehend „Volksgruppe“, auch in Zusammensetzungen (Volksgruppenprofil, DOXA-Volksgruppen).'
|
||||
},
|
||||
{
|
||||
term: 'Unerreichte Volksgruppe (UVG)',
|
||||
english: 'unreached people group (UPG)',
|
||||
definition:
|
||||
'etwa 2 Jünger oder weniger auf 100 Menschen (≤ 2 %), ohne die Fähigkeit, ohne kulturübergreifende Hilfe einheimische Gemeinden zu gründen. Joshua Project ergänzt ein Kriterium von ≤ 5 % Christen; DOXA folgt der IMB-Definition.',
|
||||
alternatives: 'nicht erreichte Volksgruppe · UPG (englisches Kürzel)',
|
||||
rationale:
|
||||
'Standardbegriff im deutschsprachigen evangelikalen Raum (Unerreichte-Volksgruppen.de). Kürzel werden eingedeutscht statt englisch übernommen: Aus UPG wird UVG. Für die allgemeine Gemeindearbeit genügt der Oberbegriff „unerreichte Volksgruppen“; die feineren Kategorien unten richten sich an strategisch Verantwortliche.'
|
||||
},
|
||||
{
|
||||
term: 'Unberührte Volksgruppe',
|
||||
english: 'unengaged people group',
|
||||
definition:
|
||||
'keine bekannten Bemühungen, sich selbst tragende Gemeinden zu gründen – die vier Ebenen wirksamer missionarischer Arbeit vor Ort fehlen (apostolischer Einsatz in der Pionierphase vor Ort; Arbeit in Kultur und Herzenssprache; langfristige Verbindlichkeit; Evangelisation mit dem Ziel einer Gemeindegründungsbewegung). Ein Fachbegriff aus dem Umfeld der IMB: Er sagt, dass niemand unter ihnen arbeitet – nicht, dass die Menschen gleichgültig wären.',
|
||||
alternatives: 'nicht-engagierte Volksgruppe · völlig unerreichte Volksgruppe · Volksgruppe ohne missionarische Arbeit vor Ort',
|
||||
rationale:
|
||||
'die abschließende Entscheidung unseres Prüfers: „Im Deutschen sprechen wir von unberührten Landstrichen.“ „Unberührt“ sagt, dass noch niemand begonnen hat, ohne Gleichgültigkeit zu unterstellen. „Nicht-engagiert“ klingt nach persönlichem Desinteresse; „völlig unerreicht“ bleibt der kombinierten Kategorie VUVG vorbehalten.'
|
||||
},
|
||||
{
|
||||
term: 'Völlig unerreichte Volksgruppe (VUVG)',
|
||||
english: 'unengaged unreached people group (UUPG)',
|
||||
definition:
|
||||
'die kombinierte Kategorie – unerreicht und unberührt. Die 2.085 Volksgruppen, für die DOXA Gebet mobilisiert.',
|
||||
alternatives: 'unerreichte und unberührte Volksgruppe · UUPG (englisches Kürzel)',
|
||||
pg: 'UUPG ist das international eingeführte Kürzel.',
|
||||
rationale:
|
||||
'„völlig unerreicht“ bringt auf den Punkt, was UUPG meint: keine Gläubigen und niemand, der unter ihnen arbeitet. Das Kürzel wird wie UVG eingedeutscht (VUVG). „Unberührt“ und „völlig unerreicht“ bleiben bewusst zwei getrennte Begriffe, damit die Kategorien unterscheidbar bleiben.'
|
||||
},
|
||||
{
|
||||
term: 'Am wenigsten erreichte Volksgruppe',
|
||||
english: 'under-engaged people group',
|
||||
definition:
|
||||
'etwa 1 Jünger oder weniger auf 100 (≤ 1 %): Die Arbeit hat begonnen, aber es braucht mehr Gemeindegründungsteams für eine fruchtbare Arbeit vor Ort.',
|
||||
alternatives: 'unterversorgte Volksgruppe · wenig erreichte Volksgruppe · unterengagierte Volksgruppe',
|
||||
rationale:
|
||||
'die Wendung, die Unerreichte-Volksgruppen.de verwendet, und die abschließende Wahl unseres Prüfers. Sie beschreibt den Grad der Erreichung, nicht eine Haltung der Menschen.'
|
||||
},
|
||||
{
|
||||
term: 'Frontier-Volksgruppe',
|
||||
english: 'frontier people group',
|
||||
definition:
|
||||
'etwa 1 Jünger oder weniger auf 1.000 (≤ 0,1 %), ohne bestätigte, anhaltende Bewegung zu Jesus hin – die unerreichtesten der Unerreichten. Der Begriff stammt von Joshua Project.',
|
||||
alternatives: 'Grenzvolksgruppe · Pioniervolksgruppe',
|
||||
jp: '„Grenzvolksgruppen“ in einem deutsch untertitelten Video.',
|
||||
rationale:
|
||||
'das englische Lehnwort wird beibehalten und bei der ersten Nennung erklärt. „Grenze“ liest sich im Deutschen als Landesgrenze; „Pionier“ beschreibt die Arbeit, nicht die Volksgruppe.'
|
||||
},
|
||||
{
|
||||
term: 'Missionarische Arbeit vor Ort · engagiert',
|
||||
english: 'engagement · engaged',
|
||||
definition:
|
||||
'eine dauerhafte, ansässige, kulturübergreifende Arbeit, die Christus bezeugt und Jünger macht, auf sich selbst tragende Gemeinden zielt und kulturell angemessen geschieht (siehe „Was ist Engagement?“ auf der Seite Vision).',
|
||||
alternatives: 'Engagement · Beteiligung · Kontakt · Einsatz',
|
||||
rationale:
|
||||
'„missionarische Arbeit vor Ort“ macht konkret, was gemeint ist: ansässig, dauerhaft, kulturübergreifend. „Beteiligung“ oder „Kontakt“ würden den Begriff entleeren, und „Engagement“ allein klingt im Deutschen nach ehrenamtlichem Einsatz. Das Adjektiv bleibt „engagiert“, damit Status und Definition denselben Wortstamm teilen; in Zusammensetzungen steht „Engagement vor Ort“ (Arbeit ansässiger Mitarbeiter/innen) und „weiteres Engagement“ (Beiträge von Projektpartnern von außen). In Oberflächenbeschriftungen steht die Kurzform „Arbeit vor Ort“ (Status der Arbeit vor Ort, Kriterien für Arbeit vor Ort).'
|
||||
},
|
||||
{
|
||||
term: 'Gemeindegründungsbewegung',
|
||||
english: 'church-planting movement (CPM)',
|
||||
definition:
|
||||
'eine Vervielfältigung einheimischer Gemeinden, die ihrerseits Gemeinden gründen – mindestens vier Stränge von je vier geistlichen Generationen mit insgesamt mehr als 1.000 Personen.',
|
||||
alternatives: 'Kirchengründungsbewegung · das englische Kürzel CPM',
|
||||
rationale:
|
||||
'„Gemeinde“ ist das Wort der deutschsprachigen Freikirchen für die örtliche Gemeinde; „Kirche“ klingt institutionell. Ein deutsches Kürzel hat sich nicht eingebürgert, deshalb steht in technischen Zusammenhängen weiterhin CPM daneben.'
|
||||
},
|
||||
{
|
||||
term: 'Einheimische Gemeinde',
|
||||
english: 'indigenous church',
|
||||
definition:
|
||||
'eine Gemeinde, die aus der Volksgruppe selbst hervorgeht und in den fünf „Selbst“ heranreift: sich selbst ausbreitend, sich selbst leitend, sich selbst finanzierend, selbst Theologie treibend, selbst missionierend.',
|
||||
alternatives: 'indigene Gemeinde · autochthone Gemeinde · Ortsgemeinde',
|
||||
rationale:
|
||||
'„einheimisch“ sagt lokal verwurzelt und selbstständig. „Indigen“ weckt im Deutschen die Assoziation an indigene Völker und Naturreligionen; „autochthon“ ist Fachsprache, die im Gemeindealltag kaum jemand benutzt.'
|
||||
},
|
||||
{
|
||||
term: 'Kulturübergreifende Mitarbeiter/innen',
|
||||
english: 'cross-cultural workers',
|
||||
alternatives: 'interkulturelle Mitarbeiter · transkulturelle Mitarbeiter · ausländische Missionare',
|
||||
rationale:
|
||||
'„kulturübergreifend“ benennt das Hinübergehen in eine andere Kultur – den missionarischen Sinn –, während „interkulturell“ eher den Austausch zwischen nebeneinander lebenden Kulturen meint (interkulturelle Kompetenz). Die Form mit „/innen“ ist die des geprüften Glossars.'
|
||||
},
|
||||
{
|
||||
term: 'Herr der Ernte',
|
||||
english: 'Lord of the harvest',
|
||||
rationale:
|
||||
'Matthäus 9,38 (Schlachter 2000, unsere Referenzübersetzung): „Darum bittet den Herrn der Ernte, dass er Arbeiter in seine Ernte aussende!“ Luther 2017 lautet bis auf die Wortstellung gleich. Glossar und Referenzübersetzung stimmen hier überein.'
|
||||
},
|
||||
{
|
||||
term: 'Gebet bahnt den Weg',
|
||||
english: 'prayer prepares the way',
|
||||
alternatives: 'Gebet bereitet den Weg · Gebet bereitet den Boden',
|
||||
rationale:
|
||||
'Anklang an Jesaja 40,3. Hier gehen Glossar und Referenzübersetzung auseinander: Schlachter 2000 liest „In der Wüste bereitet den Weg des Herrn, ebnet in der Steppe eine Straße unserem Gott!“ – also „bereiten“, während „Bahn“ nur bei Luther 2017 steht („macht in der Steppe eine ebene Bahn unserm Gott“). Das Glossar bleibt bei „bahnen“, weil es sagt, dass ein Weg entsteht, wo noch keiner war – genau das tut Fürbitte, lange bevor Mitarbeiter eintreffen. Wo die Wendung als Bibelzitat gesetzt wird, gilt der Schlachter-Wortlaut. „Den Boden bereiten“ bleibt richtig, wo der englische Text „prepares the soil“ sagt.'
|
||||
},
|
||||
{
|
||||
term: 'Herzenssprache',
|
||||
english: 'heart language',
|
||||
alternatives: 'Muttersprache',
|
||||
rationale:
|
||||
'der eingeführte Begriff der deutschsprachigen Missions- und Bibelübersetzungsarbeit für die Sprache, in der ein Mensch denkt und fühlt – im Unterschied zur Amts- oder Verkehrssprache, was „Muttersprache“ nicht ausdrückt.'
|
||||
},
|
||||
{
|
||||
term: 'Gebetsanliegen',
|
||||
english: 'prayer points',
|
||||
alternatives: 'Gebetspunkte · Gebetsimpulse · Gebetsaufforderungen',
|
||||
rationale:
|
||||
'„Gebetsanliegen“ ist das natürliche Wort deutschsprachiger Gemeinden; „Gebetspunkte“ ist eine Lehnübersetzung, „Gebetsaufforderung“ klingt nach Befehl. Das tägliche Ganze heißt „täglicher Gebetsleitfaden“.'
|
||||
},
|
||||
{
|
||||
term: 'Adoptieren (eine Volksgruppe)',
|
||||
english: 'adopt a people group',
|
||||
alternatives: 'eine Patenschaft übernehmen · auswählen · sich verpflichten',
|
||||
rationale:
|
||||
'unser Prüfer hat „Patenschaft übernehmen“ verworfen: Im deutschsprachigen Raum sagt man längst „eine Volksgruppe adoptieren“, und „adoptieren“ trägt nicht mehr familienrechtliches Gewicht als das englische Wort. „Auswählen“ bleibt dem Schritt der Auswahl vorbehalten („Wählen Sie eine Volksgruppe aus“).'
|
||||
},
|
||||
{
|
||||
term: 'Unser Geschenk an Jesus',
|
||||
english: 'our gift to Jesus',
|
||||
alternatives: 'unsere Gabe an Jesus · unser Opfer für Jesus',
|
||||
rationale: '„Geschenk“ behält die Wärme einer Gabe aus Anbetung; „Gabe“ klingt nach Kollekte, „Opfer“ nach Verlust.'
|
||||
},
|
||||
{
|
||||
term: 'World Assemblies of God Fellowship (WAGF)',
|
||||
english: 'World Assemblies of God Fellowship (WAGF)',
|
||||
alternatives: 'Weltweite Gemeinschaft der Assemblies of God',
|
||||
rationale:
|
||||
'ein etablierter deutscher Name existiert nicht, und Organisationsnamen bleiben nach unserer Glossarregel unübersetzt. Das Kürzel WAGF bleibt auf der ganzen Website gleich.'
|
||||
},
|
||||
{
|
||||
term: 'Sendeorganisationen',
|
||||
english: 'sending agencies',
|
||||
alternatives: 'Entsendeorganisationen · Missionswerke · Missionsgesellschaften',
|
||||
rationale:
|
||||
'Begriff des geprüften Glossars. „Missionswerk“ ist das gängige deutsche Wort, aber weiter gefasst; „Sendeorganisation“ hält die Aufgabe des Sendens sichtbar, die zum Dreiklang beten, geben und senden gehört.'
|
||||
},
|
||||
{
|
||||
term: 'Tägliches Gebet (für eine Volksgruppe)',
|
||||
english: 'daily prayer (for a people group)',
|
||||
definition:
|
||||
'die Verpflichtung, jeden Tag für eine bestimmte unberührte Volksgruppe zu beten – mit dem täglichen Gebetsleitfaden. Das Ziel: mehr als 100 tägliche Fürbitter/innen für jede Volksgruppe.',
|
||||
alternatives: 'regelmäßiges Gebet · 24-Stunden-Gebetsabdeckung (früheres Ziel: 144 Fürbitter × 10 Minuten)',
|
||||
rationale:
|
||||
'„täglich“ ist gewollt – eine Verpflichtung für jeden Tag, kein gelegentliches Gebet. Das frühere Bild von 144 Fürbittern, die zusammen 24 Stunden abdecken, wurde durch das Ziel von mehr als 100 täglichen Fürbitter/innen abgelöst.'
|
||||
},
|
||||
{
|
||||
term: 'Jeder Stamm, jede Zunge, jedes Volk und jede Nation',
|
||||
english: 'every tribe, tongue, people, and nation',
|
||||
rationale:
|
||||
'Offenbarung 5,9 und 7,9 – das Bild, das die ganze Arbeit motiviert. Auch hier gehen Glossar und Referenzübersetzung auseinander: Schlachter 2000 liest „aus allen Stämmen und Sprachen und Völkern und Nationen“ (5,9) und „aus allen Nationen und Stämmen und Völkern und Sprachen“ (7,9), Luther 2017 ebenso mit „Sprachen“. Die Glossarform behält „Zunge“ als wörtliche Wiedergabe des biblischen Begriffs bei, weil jedes der vier Wörter eine eigene Dimension menschlicher Vielfalt benennt und „Sprache“ sich sonst mit der Herzenssprache überschneidet. Wo der Satz als Bibelzitat gesetzt wird, gilt der Schlachter-Wortlaut.'
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
@ -1,14 +1,11 @@
|
|||
import type { TermsContent } from './index'
|
||||
|
||||
export const en: TermsContent = {
|
||||
title: 'Terminology',
|
||||
title: 'Definitions',
|
||||
intro: [
|
||||
'This page documents the terminology DOXA uses and why. Precise terms matter: our statistics, goals, and prayer tools all depend on definitions that must survive translation.',
|
||||
"Each language edition of this page documents that language's terminology decisions — the term we chose, the alternatives we considered, what Joshua Project and PeopleGroups.org (IMB) use, and the reasoning."
|
||||
],
|
||||
seeDefinitionsBefore: 'Full definitions live on the',
|
||||
definitionsLinkLabel: 'Definitions',
|
||||
seeDefinitionsAfter: ' page.',
|
||||
labels: {
|
||||
english: 'English:',
|
||||
definition: 'Definition:',
|
||||
|
|
@ -36,7 +33,7 @@ export const en: TermsContent = {
|
|||
{
|
||||
term: 'Unengaged, unreached people group (UUPG)',
|
||||
definition:
|
||||
'The combined category — unreached and unengaged. The 2,085 peoples DOXA mobilizes prayer for. UUPG is the established international acronym, kept as-is across all language editions.'
|
||||
'The combined category — unreached and unengaged. The 2,085 peoples DOXA mobilizes prayer for. UUPG is the established international acronym; most language editions keep it, while some carry a reviewer-chosen local acronym (Spanish GENANC, Portuguese PNANE, German VUVG).'
|
||||
},
|
||||
{
|
||||
term: 'Under-engaged',
|
||||
|
|
@ -101,7 +98,7 @@ export const en: TermsContent = {
|
|||
{
|
||||
term: 'World Assemblies of God Fellowship (WAGF)',
|
||||
definition:
|
||||
"The global fellowship that founded and stewards DOXA. Language editions use the fellowship's established national name where one exists; the WAGF acronym stays unchanged everywhere."
|
||||
"The global fellowship that founded and stewards DOXA. Language editions use the fellowship's established national name where one exists; the WAGF acronym is kept unless a reviewer has chosen a local one (Spanish FMAD)."
|
||||
},
|
||||
{
|
||||
term: 'Sending agencies',
|
||||
|
|
@ -109,9 +106,9 @@ export const en: TermsContent = {
|
|||
'Organizations that recruit, train, support, and send missionaries. DOXA works with sending agencies (129 WAGF-affiliated as of 2026) but does not replace them.'
|
||||
},
|
||||
{
|
||||
term: '24-hour prayer coverage',
|
||||
term: 'Daily prayer (for a people group)',
|
||||
definition:
|
||||
'At least 144 intercessors each praying 10 minutes a day for one people group — together, 24 hours of daily prayer.'
|
||||
'Committing to pray for a specific unengaged people group every day, using the daily prayer guide. The goal is 100+ daily intercessors for each people group. "Daily" is intentional — an every-day commitment, not regular or occasional prayer; it replaces the earlier framing of 144 intercessors covering 24 hours.'
|
||||
},
|
||||
{
|
||||
term: 'Every tribe, tongue, people, and nation',
|
||||
|
|
|
|||
177
app/utils/terms/es.ts
Normal file
177
app/utils/terms/es.ts
Normal file
|
|
@ -0,0 +1,177 @@
|
|||
import type { TermsContent } from './index'
|
||||
|
||||
export const es: TermsContent = {
|
||||
title: 'Definiciones',
|
||||
intro: [
|
||||
'Esta página documenta las decisiones terminológicas en español de la asociación DOXA. Para cada término: la definición, las alternativas consideradas, lo que usan Joshua Project y PeopleGroups.org (IMB) y la razón de nuestra elección.',
|
||||
'Nuestras fuentes: el glosario de DOXA revisado por un traductor hispanohablante, sus comentarios sobre el sitio web y, para toda expresión de origen bíblico, la Nueva Versión Internacional (NVI) y la Reina-Valera 1960 (RVR1960).'
|
||||
],
|
||||
labels: {
|
||||
english: 'Inglés:',
|
||||
definition: 'Definición:',
|
||||
alternatives: 'Alternativas consideradas:',
|
||||
jp: 'Joshua Project:',
|
||||
pg: 'PeopleGroups.org:',
|
||||
rationale: 'Por qué esta elección:'
|
||||
},
|
||||
entries: [
|
||||
{
|
||||
term: 'Grupo étnico',
|
||||
english: 'people group',
|
||||
definition:
|
||||
'un grupo etnolingüístico cuyos miembros perciben entre sí una afinidad común basada en el idioma, la cultura, la religión y la cosmovisión: el grupo más amplio dentro del cual el evangelio puede extenderse sin barreras de comprensión o aceptación. La unidad fundamental de todo lo que DOXA cuenta.',
|
||||
alternatives: 'grupo de personas · pueblo étnico · pueblo · tribu · grupo etnolingüístico',
|
||||
rationale:
|
||||
'preguntado si «grupo de personas» debía mantenerse, nuestro revisor respondió «grupo étnico»: recoge con más precisión el concepto etnolingüístico, mientras que «grupo de personas» suena a estadística y «pueblo» a nación. Es también la base de las siglas en español (GENANC). «Tribu» se evita por sus connotaciones primitivas.'
|
||||
},
|
||||
{
|
||||
term: 'Grupo étnico no alcanzado (UPG)',
|
||||
english: 'unreached people group (UPG)',
|
||||
definition:
|
||||
'aproximadamente 2 discípulos o menos de cada 100 personas (≤ 2 %), sin la capacidad de establecer iglesias autóctonas sin obreros transculturales. Joshua Project añade un criterio de ≤ 5 % de cristianos; DOXA sigue la definición de la IMB.',
|
||||
alternatives: 'pueblo étnico no alcanzado (PNA) · pueblo no alcanzado',
|
||||
rationale:
|
||||
'el glosario revisado no fija una sigla propia en español para este término, así que se conserva la inglesa, UPG, y en texto corrido se escribe completo. «PNA» se construyó sobre «pueblo» y se abandonó con él. Para la movilización general basta el término «grupos étnicos no alcanzados»; las categorías más finas de abajo se dirigen a los responsables estratégicos.'
|
||||
},
|
||||
{
|
||||
term: 'Grupo étnico no comprometido',
|
||||
english: 'unengaged people group',
|
||||
definition:
|
||||
'sin creyentes conocidos o con muy pocos, y sin los cuatro niveles primarios de compromiso efectivo (esfuerzo apostólico residente; compromiso con la cultura local y la lengua del corazón; compromiso ministerial a largo plazo; siembra del evangelio orientada a un movimiento de plantación de iglesias). Un término técnico del entorno de la IMB: dice que nadie trabaja entre ellos, no que el pueblo sea indiferente.',
|
||||
alternatives: 'sin compromiso · grupo desvinculado · no involucrado · sin participación misionera activa',
|
||||
rationale:
|
||||
'se le pidió al revisor que reconsiderara «no comprometido» porque podía sonar a que el grupo mismo carece de compromiso. Lo mantuvo: «comprometido es la palabra correcta para implicar a alguien con responsabilidad y compromiso; involucramiento significa implicar a alguien en un proyecto o una acción». «Sin compromiso» y «desvinculado», usados en borradores anteriores, quedan sustituidos. En texto corrido va en minúscula.'
|
||||
},
|
||||
{
|
||||
term: 'Grupo étnico no alcanzado no comprometido (GENANC)',
|
||||
english: 'unengaged unreached people group (UUPG)',
|
||||
definition:
|
||||
'la categoría combinada: no alcanzado y no comprometido. Los 2.085 grupos étnicos por los que DOXA moviliza oración.',
|
||||
alternatives: 'PNANC (pueblo no alcanzado no comprometido) · GNANC · UUPG (sigla inglesa)',
|
||||
pg: 'UUPG es la sigla internacional establecida.',
|
||||
rationale:
|
||||
'nuestro revisor usa siglas en español en lugar de las inglesas: «he usado una abreviatura en español en vez de la inglesa; por favor, añádanla donde aparece UUPG en la versión inglesa». Trabajó primero con PNANC y, al adoptarse «grupo étnico», propuso «GENANC o GNANC»; el glosario revisado usa GENANC en todo el texto. Como término técnico o al desplegar la sigla va sin «y»; en prosa descriptiva «grupo étnico no alcanzado y no comprometido» se lee con más naturalidad.'
|
||||
},
|
||||
{
|
||||
term: 'Grupo étnico poco comprometido',
|
||||
english: 'under-engaged people group',
|
||||
definition:
|
||||
'aproximadamente 1 discípulo o menos de cada 100 (≤ 1 %): el trabajo ha comenzado, pero se necesitan más equipos de plantación de iglesias para un compromiso fructífero.',
|
||||
alternatives: 'subcomprometido · menos alcanzado · pocos alcanzados',
|
||||
rationale:
|
||||
'transmite que el trabajo es insuficiente en escala, no que el pueblo sea indiferente, y mantiene la familia «comprometido». «Menos alcanzados» confunde esta categoría con el grado de alcance; «subcomprometido» es un calco poco natural.'
|
||||
},
|
||||
{
|
||||
term: 'Grupo fronterizo',
|
||||
english: 'frontier people group',
|
||||
definition:
|
||||
'aproximadamente 1 discípulo o menos de cada 1.000 (≤ 0,1 %) sin ningún movimiento confirmado y sostenido hacia Jesús: los más no alcanzados entre los no alcanzados. El término procede de Joshua Project.',
|
||||
alternatives: 'gente fronteriza · pueblo fronterizo · grupo étnico frontera · gente de la frontera',
|
||||
rationale:
|
||||
'«fronterizo» señala el extremo misionológico, el primer contacto con el evangelio, sin la connotación militar de «frontera». Para la cifra de la página de inicio el revisor corrigió «gente de la frontera» por «gente fronteriza», que se conserva en esa etiqueta.'
|
||||
},
|
||||
{
|
||||
term: 'Compromiso · comprometido',
|
||||
english: 'engagement · engaged',
|
||||
definition:
|
||||
'actividad sostenida, residente y transcultural para compartir a Cristo y hacer discípulos, orientada a iglesias autosustentables y realizada de maneras culturalmente apropiadas y localmente relevantes (véase «¿Qué es el compromiso?» en la página de Visión).',
|
||||
alternatives: 'involucramiento · participación · implicación · contacto',
|
||||
rationale:
|
||||
'se le pidió al revisor que considerara «compromiso» con cuidado, porque puede confundir el ministerio residente con una actitud. Lo confirmó por la misma razón que «comprometido»: implica responsabilidad y compromiso, mientras que «involucramiento» solo significa tomar parte en un proyecto. El verbo es «comprometer» («Comprometer a todos los grupos étnicos no comprometidos para 2033»); «involucrar» y «participación», de borradores anteriores, quedan sustituidos. En las etiquetas de interfaz: «Estado del compromiso», «Criterios de compromiso».'
|
||||
},
|
||||
{
|
||||
term: 'Movimiento de plantación de iglesias (MPI)',
|
||||
english: 'church-planting movement (CPM)',
|
||||
definition:
|
||||
'una multiplicación de iglesias autóctonas que plantan iglesias, con al menos cuatro corrientes de cuatro generaciones espirituales que juntas suman más de 1.000 personas.',
|
||||
alternatives: 'CPM (sigla inglesa) · movimiento de multiplicación de iglesias',
|
||||
rationale:
|
||||
'la expresión es la habitual en el ámbito misionológico hispano. La sigla se traduce, como GENANC, siguiendo la regla de nuestro revisor de sustituir las siglas inglesas; el glosario revisado usa MPI.'
|
||||
},
|
||||
{
|
||||
term: 'Iglesia autóctona',
|
||||
english: 'indigenous church',
|
||||
definition:
|
||||
'una iglesia que surge desde dentro del grupo étnico y madura en los cinco «auto»: autogobierno, autosustento, autopropagación, autoteologización y automisionología.',
|
||||
alternatives: 'iglesia indígena · iglesia nativa · iglesia local',
|
||||
rationale:
|
||||
'«autóctona» significa con raíces locales y autogobernada. «Indígena» evoca en español a los pueblos indígenas y sus religiones, lo que invita a asociaciones con el sincretismo; «local» no dice que la iglesia sea propia del grupo étnico.'
|
||||
},
|
||||
{
|
||||
term: 'Obreros transculturales',
|
||||
english: 'cross-cultural workers',
|
||||
alternatives: 'trabajadores interculturales · trabajadores transculturales · misioneros extranjeros',
|
||||
rationale:
|
||||
'«obrero» es la palabra del uso evangélico hispano para quien sirve en la mies (Mateo 9:38); «transcultural» nombra el paso a otra cultura, el sentido misionero, mientras que «intercultural» sugiere el intercambio entre culturas que conviven. «Extranjero» solo dice de dónde viene el obrero, no que cruza una cultura.'
|
||||
},
|
||||
{
|
||||
term: 'Señor de la cosecha',
|
||||
english: 'Lord of the harvest',
|
||||
rationale:
|
||||
'Mateo 9:38 (NVI): «Pídanle, por tanto, al Señor de la cosecha que envíe obreros a su campo». La RVR1960 dice «Señor de la mies»; el glosario revisado eligió «cosecha» y conserva «mies» como glosa (mies = personas listas para responder). Nuestras expresiones bíblicas siguen estas dos traducciones.'
|
||||
},
|
||||
{
|
||||
term: 'La oración prepara el camino',
|
||||
english: 'prayer prepares the way',
|
||||
alternatives: 'la oración abre el camino · la oración prepara el terreno',
|
||||
rationale:
|
||||
'eco de Isaías 40:3 («Preparen el camino del Señor», NVI; «Preparad camino a Jehová», RVR1960). Dice que la intercesión crea las condiciones para el evangelio mucho antes de que lleguen los obreros. «Prepara el terreno» sigue siendo correcto donde el texto inglés dice «prepares the soil».'
|
||||
},
|
||||
{
|
||||
term: 'Lengua del corazón',
|
||||
english: 'heart language',
|
||||
alternatives: 'idioma del corazón · lengua materna',
|
||||
rationale:
|
||||
'la expresión establecida en la obra misionera y de traducción bíblica para la lengua en la que una persona piensa y siente, a diferencia de la lengua oficial o franca, matiz que «lengua materna» no expresa. La cita de la página de Definiciones conserva «idioma del corazón».'
|
||||
},
|
||||
{
|
||||
term: 'Motivos de oración',
|
||||
english: 'prayer points',
|
||||
alternatives: 'puntos de oración · pedidos de oración · peticiones de oración · indicaciones de oración',
|
||||
rationale:
|
||||
'«motivos de oración» es la expresión natural de las iglesias hispanas; «puntos de oración» es un calco. El glosario revisado fija «motivos diarios de oración», que el sitio ya usa en lugar de los «pedidos de oración» que el revisor había escrito en el formulario. El conjunto diario se llama «guía diaria de oración»; el encabezado del sitio conserva el orden «Tu guía de oración diaria».'
|
||||
},
|
||||
{
|
||||
term: 'Adoptar (un grupo étnico)',
|
||||
english: 'adopt a people group',
|
||||
alternatives: 'apadrinar · acoger · elegir · comprometerse con',
|
||||
rationale:
|
||||
'el concepto es un patrocinio misional: una iglesia asume la responsabilidad estratégica de orar, dar y enviar por un grupo étnico. «Apadrinar» y «acoger» desplazan el sentido hacia el padrinazgo o la acogida familiar; «elegir» queda para el paso de selección («Elige un grupo étnico»). Se evita el lenguaje legal de la adopción de menores.'
|
||||
},
|
||||
{
|
||||
term: 'Nuestro regalo para Jesús',
|
||||
english: 'our gift to Jesus',
|
||||
alternatives: 'nuestra ofrenda a Jesús · nuestro don a Jesús',
|
||||
rationale: '«regalo» conserva la calidez de una entrega de adoración; «ofrenda» suena a colecta y «don» a lenguaje litúrgico.'
|
||||
},
|
||||
{
|
||||
term: 'Fraternidad Mundial de las Asambleas de Dios (FMAD)',
|
||||
english: 'World Assemblies of God Fellowship (WAGF)',
|
||||
alternatives: 'World Assemblies of God Fellowship (sin traducir) · Asambleas de Dios Mundial · Comunidad Mundial de las Asambleas de Dios',
|
||||
rationale:
|
||||
'a diferencia de otros idiomas, el español tiene un nombre establecido para la fraternidad, y nuestro revisor lo fijó: «WAGF, la traducción al español es FMAD». La sigla FMAD se mantiene igual en todo el sitio.'
|
||||
},
|
||||
{
|
||||
term: 'Agencias enviadoras',
|
||||
english: 'sending agencies',
|
||||
alternatives: 'agencias de envío · agencias misioneras · agencias misioneras de envío',
|
||||
rationale:
|
||||
'término del glosario revisado. «Agencia misionera» es la palabra corriente, pero más amplia; «enviadora» mantiene visible la función de enviar, que forma parte del tríptico orar, dar y enviar.'
|
||||
},
|
||||
{
|
||||
term: 'Oración diaria (por un grupo étnico)',
|
||||
english: 'daily prayer (for a people group)',
|
||||
definition:
|
||||
'el compromiso de orar todos los días por un grupo étnico no comprometido específico, con la guía diaria de oración. La meta: más de 100 intercesores diarios por cada grupo étnico.',
|
||||
alternatives: 'oración regular · cobertura de oración las 24 horas (meta anterior: 144 intercesores × 10 minutos)',
|
||||
rationale:
|
||||
'«diaria» es intencional: un compromiso para cada día, no una oración ocasional. La imagen anterior de 144 intercesores que juntos cubren 24 horas fue sustituida por la meta de más de 100 intercesores diarios; la métrica del sitio se llama «cobertura diaria de oración».'
|
||||
},
|
||||
{
|
||||
term: 'Cada tribu, lengua, pueblo y nación',
|
||||
english: 'every tribe, tongue, people, and nation',
|
||||
rationale:
|
||||
'Apocalipsis 5:9 y 7:9, el cuadro que motiva toda la obra. La NVI traduce 7:9 «de toda nación, tribu, pueblo y lengua» y la RVR1960 «de todas naciones y tribus y pueblos y lenguas»; la forma del glosario conserva el orden inglés de los cuatro sustantivos. Cada uno nombra una dimensión distinta de la diversidad humana: tribu (clan), lengua (idioma), pueblo (grupo étnico), nación (unidad política).'
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
@ -1,14 +1,11 @@
|
|||
import type { TermsContent } from './index'
|
||||
|
||||
export const fr: TermsContent = {
|
||||
title: 'Terminologie',
|
||||
title: 'Définitions',
|
||||
intro: [
|
||||
'Cette page documente les choix de terminologie française du partenariat DOXA. Pour chaque terme : sa définition, les autres options envisagées, ce qu’utilisent Joshua Project et PeopleGroups.org (IMB), et la raison de notre choix.',
|
||||
'Nos sources : les données officielles en français de PeopleGroups.org (IMB), les ressources françaises de Joshua Project, l’usage des ministères évangéliques francophones, et la Bible Louis Segond pour toute expression d’origine biblique.'
|
||||
],
|
||||
seeDefinitionsBefore: 'Les définitions complètes se trouvent sur la page',
|
||||
definitionsLinkLabel: 'Définitions',
|
||||
seeDefinitionsAfter: '.',
|
||||
labels: {
|
||||
english: 'Anglais :',
|
||||
definition: 'Définition :',
|
||||
|
|
@ -82,7 +79,7 @@ export const fr: TermsContent = {
|
|||
term: 'Engagement · s’engager auprès d’un peuple',
|
||||
english: 'engagement · to engage',
|
||||
definition:
|
||||
'une activité soutenue, en résidence, transculturelle, orientée vers un mouvement d’implantation d’églises (voir « Qu’est-ce que l’engagement ? » sur la page Vision).',
|
||||
'une activité soutenue, sur le terrain, transculturelle, orientée vers un mouvement d’implantation d’églises (voir « Qu’est-ce que l’engagement ? » sur la page Vision).',
|
||||
alternatives: 'implication · contact · cibler',
|
||||
rationale:
|
||||
'terme de précision — un rendu vague comme « implication » vide le sens. Au verbe, nous préférons « s’engager auprès d’un peuple » : « engager un peuple » évoquerait une embauche.'
|
||||
|
|
@ -135,11 +132,13 @@ export const fr: TermsContent = {
|
|||
'la notion missiologique — la langue dans laquelle une personne pense et ressent le plus profondément — distincte de la langue officielle ou véhiculaire, ce que « langue maternelle » ne dit pas.'
|
||||
},
|
||||
{
|
||||
term: 'Sujets de prière',
|
||||
term: 'Points de prière quotidiens',
|
||||
english: 'prayer points',
|
||||
alternatives: 'points de prière',
|
||||
definition:
|
||||
'les demandes de prière quotidiennes propres à un peuple que DOXA envoie aux intercesseurs : centrées sur les Écritures et reliées au terrain, distinctes d’un contenu de dévotion générale.',
|
||||
alternatives: 'sujets de prière · motifs de prière',
|
||||
rationale:
|
||||
'« sujets de prière » est l’expression naturelle des églises francophones ; « points de prière » est un calque de l’anglais.'
|
||||
'le glossaire DOXA fixe « points de prière quotidiens », en parallèle du « guide de prière quotidien » : le site et les e-mails emploient la même formule. « Sujets de prière » reste l’expression la plus naturelle des églises francophones et demeure l’alternative à retenir si une relecture francophone tranche en sa faveur.'
|
||||
},
|
||||
{
|
||||
term: 'Adopter un peuple',
|
||||
|
|
@ -155,11 +154,11 @@ export const fr: TermsContent = {
|
|||
rationale: '« offrande » porte le registre sacrificiel de l’adoration ; « cadeau » sonne transactionnel.'
|
||||
},
|
||||
{
|
||||
term: 'Association mondiale des Assemblées de Dieu (WAGF)',
|
||||
term: 'Fraternité Mondiale des Assemblées de Dieu (WAGF)',
|
||||
english: 'World Assemblies of God Fellowship (WAGF)',
|
||||
alternatives: 'conserver le nom anglais · « Fraternité mondiale des Assemblées de Dieu »',
|
||||
alternatives: 'conserver le nom anglais · « Association mondiale des Assemblées de Dieu »',
|
||||
rationale:
|
||||
'c’est le nom français établi de la communion mondiale des Assemblées de Dieu. L’acronyme WAGF reste inchangé sur tout le site.'
|
||||
'« fraternité » rend « fellowship » : la WAGF est une communion d’Églises, pas une association. C’est aussi le nom que portait la version française du site. L’acronyme WAGF reste inchangé sur tout le site.'
|
||||
},
|
||||
{
|
||||
term: 'Agences missionnaires',
|
||||
|
|
@ -168,12 +167,13 @@ export const fr: TermsContent = {
|
|||
rationale: 'terme usuel des structures missionnaires francophones ; « agence d’envoi » est un calque.'
|
||||
},
|
||||
{
|
||||
term: 'Couverture de prière 24h/24',
|
||||
english: '24-hour prayer coverage',
|
||||
term: 'Prière quotidienne (pour un peuple)',
|
||||
english: 'daily prayer (for a people group)',
|
||||
definition:
|
||||
'au moins 144 intercesseurs priant chacun 10 minutes par jour pour un même peuple — soit 24 heures de prière quotidienne.',
|
||||
alternatives: 'couverture de prière de 24 heures',
|
||||
rationale: '« 24h/24 » est la forme idiomatique française pour une couverture continue.'
|
||||
'l’engagement de prier chaque jour pour un peuple non engagé précis, à l’aide du guide de prière quotidien. L’objectif : 100 intercesseurs quotidiens ou plus pour chaque peuple.',
|
||||
alternatives: 'prière régulière · couverture de prière 24h/24 (ancien objectif : 144 intercesseurs × 10 minutes)',
|
||||
rationale:
|
||||
'« quotidienne » est voulu — un engagement de chaque jour, non une prière occasionnelle. L’ancien cadre des 144 intercesseurs couvrant 24 heures a été remplacé par l’objectif de 100 intercesseurs quotidiens ou plus.'
|
||||
},
|
||||
{
|
||||
term: 'Toute tribu, toute langue, tout peuple et toute nation',
|
||||
|
|
|
|||
199
app/utils/terms/hi.ts
Normal file
199
app/utils/terms/hi.ts
Normal file
|
|
@ -0,0 +1,199 @@
|
|||
import type { TermsContent } from './index'
|
||||
|
||||
export const hi: TermsContent = {
|
||||
title: 'परिभाषाएँ',
|
||||
intro: [
|
||||
'यह पृष्ठ DOXA साझेदारी के हिंदी शब्दों का लेखा-जोखा है। हर शब्द के लिए: उसकी परिभाषा, जिन विकल्पों पर विचार हुआ, और वह शब्द क्यों चुना गया।',
|
||||
'हमारे स्रोत: DOXA शब्दावली, DOXA Access and Alignment प्लेबुक का हिंदी अनुवाद, गोद लेने के प्रमाणपत्र की छपी हुई हिंदी, हिंदी सुसमाचारी और मिशन-विज्ञान का प्रचलित शब्द-भंडार, और बाइबिलीय वाक्यांशों के लिए पवित्र बाइबिल का पुराना संस्करण (OV)। Joshua Project और PeopleGroups.org (IMB) हिंदी में कुछ प्रकाशित नहीं करते, इसलिए इस संस्करण में उनका उल्लेख नहीं है।'
|
||||
],
|
||||
labels: {
|
||||
english: 'अंग्रेज़ी:',
|
||||
definition: 'परिभाषा:',
|
||||
alternatives: 'जिन विकल्पों पर विचार हुआ:',
|
||||
jp: 'Joshua Project:',
|
||||
pg: 'PeopleGroups.org:',
|
||||
rationale: 'यही क्यों चुना गया:'
|
||||
},
|
||||
entries: [
|
||||
{
|
||||
term: 'जनसमूह',
|
||||
english: 'people group',
|
||||
definition:
|
||||
'एक जातीय-भाषाई समूह जिसके सदस्य भाषा, संस्कृति, धर्म और विश्वदृष्टि के आधार पर स्वयं को एक-दूसरे से जुड़ा हुआ मानते हैं — वह सबसे बड़ा समूह जिसके भीतर सुसमाचार समझ या स्वीकार्यता की बाधाओं के बिना फैल सकता है। DOXA जो कुछ भी गिनता है, उसकी बुनियादी इकाई यही है।',
|
||||
alternatives: 'जातीय समूह · लोगों का समूह · जनजाति · जन-समूह',
|
||||
rationale:
|
||||
'DOXA प्लेबुक का हिंदी अनुवाद और गोद लेने का छपा हुआ प्रमाणपत्र, दोनों जनसमूह कहते हैं। «जातीय समूह» भारत में जाति-व्यवस्था की ओर संकेत करता है, और «जनजाति» का अर्थ आदिवासी समुदाय होता है — दोनों ही ग़लत अर्थ देते हैं। «लोगों का समूह» मशीनी अनुवाद है।'
|
||||
},
|
||||
{
|
||||
term: 'अप्राप्य जनसमूह (UPG)',
|
||||
english: 'unreached people group (UPG)',
|
||||
definition:
|
||||
'ऐसा जनसमूह जिसमें लगभग 100 में से 2 या उससे कम शिष्य (≤ 2%) हों, और जो अंतर-सांस्कृतिक सहायता के बिना स्वदेशी कलीसियाएँ स्थापित करने में सक्षम न हो। Joshua Project इसमें ≤ 5% घोषित मसीहियों की शर्त भी जोड़ता है; DOXA IMB की परिभाषा का पालन करता है।',
|
||||
alternatives: 'अनपहुँचा जनसमूह · अपहुँचा जनसमूह · अगम्य जनसमूह',
|
||||
rationale:
|
||||
'प्लेबुक का हिंदी अनुवाद और छपा हुआ प्रमाणपत्र, दोनों «अप्राप्य» कहते हैं। «अनपहुँचा» भी हिंदी में प्रचलित है और doxa.life के समीक्षक ने उसी का सुझाव दिया था। आपत्ति शब्दार्थ की है: «अप्राप्य» का अर्थ है «जो प्राप्त ही न हो सके», जबकि अंग्रेज़ी शब्द का अर्थ है «जिन तक सुसमाचार अब तक पहुँचा नहीं»। यह अंतर अभी किसी हिंदी समीक्षक के निर्णय की प्रतीक्षा में है। अंग्रेज़ी संक्षेप UPG ज्यों का त्यों रखा गया है, क्योंकि हिंदी में इसका कोई स्थिर संक्षेप नहीं है।'
|
||||
},
|
||||
{
|
||||
term: 'अनसंपर्कित',
|
||||
english: 'unengaged people group',
|
||||
definition:
|
||||
'ऐसा जनसमूह जिसके बीच आत्मनिर्भर कलीसियाएँ स्थापित करने का कोई ज्ञात प्रयास नहीं हो रहा — प्रभावी संलग्नता के चारों स्तर अनुपस्थित हैं (निवास में रहकर प्रेरितिक प्रयास; स्थानीय संस्कृति और हृदय की भाषा में कार्य; दीर्घकालिक प्रतिबद्धता; कलीसिया स्थापना आंदोलन की ओर लक्षित सुसमाचार की बुवाई)। यह IMB का तकनीकी शब्द है: इसका अर्थ है कि उनके बीच कोई काम नहीं कर रहा, न कि वे जनसमूह उदासीन हैं।',
|
||||
alternatives: 'असंलग्न · अप्रवेशित · अप्रविष्ट · अनपहुँचा',
|
||||
rationale:
|
||||
'प्लेबुक का हिंदी अनुवाद अपनी परिभाषा-सूची में और अपने हर आँकड़े में «अनसंपर्कित» कहता है। «अनपहुँचा» अप्राप्य और अनसंपर्कित का भेद मिटा देता है, और DOXA के सारे आँकड़े इसी भेद पर टिके हैं।'
|
||||
},
|
||||
{
|
||||
term: 'अनसंपर्कित-अप्राप्य जनसमूह (UUPG)',
|
||||
english: 'unengaged, unreached people group (UUPG)',
|
||||
definition:
|
||||
'दोनों श्रेणियों का मेल — अनसंपर्कित और अप्राप्य। ये वही 2,085 जनसमूह हैं जिनके लिए DOXA प्रार्थना को मोबिलाइज़ करता है।',
|
||||
alternatives: 'अप्राप्य और अनसंपर्कित जनसमूह · कोई नया हिंदी संक्षेप',
|
||||
rationale:
|
||||
'यह प्लेबुक के चार्ट की भाषा है, जिसमें अनसंपर्कित पहले आता है, ठीक अंग्रेज़ी की तरह। UUPG अंतरराष्ट्रीय स्तर पर स्थापित संक्षेप है; कुछ भाषाओं ने अपना संक्षेप गढ़ा है, पर हिंदी के किसी स्रोत में कोई हिंदी संक्षेप नहीं मिलता, इसलिए यहाँ यह ज्यों का त्यों रहता है।'
|
||||
},
|
||||
{
|
||||
term: 'कम-संपर्कित',
|
||||
english: 'under-engaged people group',
|
||||
definition:
|
||||
'ऐसा जनसमूह जिसमें लगभग 100 में से 1 या उससे कम शिष्य (≤ 1%) हों: कार्य आरंभ हो चुका है, परंतु फलदायी सहभागिता के लिए और कलीसिया-स्थापना टीमों की आवश्यकता है।',
|
||||
alternatives: 'कम संलग्न · अल्प-संपर्कित · आंशिक रूप से संपर्कित',
|
||||
rationale:
|
||||
'यह प्लेबुक की परिभाषा-सूची का रूप है, और यह «संपर्कित» तथा «अनसंपर्कित» के साथ एक ही परिवार में रहता है। यह बताता है कि कार्य कितना हुआ है, न कि जनसमूह का रवैया कैसा है।'
|
||||
},
|
||||
{
|
||||
term: 'फ्रंटियर जनसमूह',
|
||||
english: 'frontier people group',
|
||||
definition:
|
||||
'ऐसा जनसमूह जिसमें लगभग 1,000 में से 1 या उससे कम शिष्य (≤ 0.1%) हों और यीशु की ओर कोई पुष्ट, स्थायी आंदोलन न हो — अप्राप्य जनसमूहों में भी सबसे दूर। यह शब्द Joshua Project से आया है।',
|
||||
alternatives: 'सीमांत जनसमूह · सरहदी जनसमूह',
|
||||
rationale:
|
||||
'प्लेबुक का हिंदी अनुवाद अपनी परिभाषा-सूची, अपने चार्ट और अपने दर्शन-पृष्ठ पर यही लिप्यंतरण रखता है। «सीमांत» हिंदी में केवल सरहद या हाशिये का अर्थ देता है और मिशन-विज्ञान वाला भाव खो देता है।'
|
||||
},
|
||||
{
|
||||
term: 'संलग्नता',
|
||||
english: 'engagement',
|
||||
definition:
|
||||
'मसीह को बाँटने और चेले बनाने के लिए निरंतर, निवास-आधारित, अंतर-सांस्कृतिक कार्य, जो आत्मनिर्भर कलीसियाओं की ओर लक्षित हो और सांस्कृतिक रूप से उपयुक्त तथा स्थानीय रूप से प्रासंगिक ढंग से किया जाए। यह एक सटीक शब्द है — «संपर्क» या «रुचि» संलग्नता नहीं है।',
|
||||
alternatives: 'सहभागिता · संपर्क · सगाई · जुड़ाव',
|
||||
rationale:
|
||||
'प्लेबुक का हिंदी अनुवाद दो बार अंग्रेज़ी शब्द के साथ «संलग्नता (engagement)» लिखता है और अपने संबंधित अध्याय को «संलग्नता के मापदंड» शीर्षक देता है। जनसमूहों की श्रेणियाँ «संपर्कित» मूल से बनी हैं और 2033 के लक्ष्य में क्रिया «सहभागिता स्थापित करना» है, इसलिए हिंदी में यह परिवार अभी तीन मूलों में बँटा है और किसी समीक्षक के निर्णय की प्रतीक्षा में है। «सगाई» का अर्थ विवाह की मँगनी है और वह कभी प्रयोग नहीं होना चाहिए।'
|
||||
},
|
||||
{
|
||||
term: 'कलीसिया स्थापना आंदोलन (CPM)',
|
||||
english: 'church-planting movement (CPM)',
|
||||
definition:
|
||||
'स्वदेशी कलीसियाओं का ऐसा गुणन जिसमें कलीसियाएँ और कलीसियाएँ स्थापित करती हैं: कम से कम चार धाराएँ, हर एक में चार आत्मिक पीढ़ियाँ, और कुल मिलाकर 1,000 से अधिक लोग।',
|
||||
alternatives: 'चर्च प्लांटिंग मूवमेंट · कलीसिया रोपण आंदोलन · कलीसिया स्थापना अभियान',
|
||||
rationale:
|
||||
'प्लेबुक की परिभाषा-सूची इसे इसी तरह खोलकर लिखती है। «रोपण» पौधों की भाषा है; «अभियान», जो doxa.life के समीक्षक ने सुझाया था, एक सीमित मुहिम का अर्थ देता है, जबकि यह परमेश्वर का कार्य है जो फैलता जाता है। संक्षेप CPM अंग्रेज़ी में ही रहता है।'
|
||||
},
|
||||
{
|
||||
term: 'स्वदेशी कलीसिया',
|
||||
english: 'indigenous church',
|
||||
definition:
|
||||
'ऐसी कलीसिया जो जनसमूह के भीतर से उठती है और पाँच «स्व-क्षमताओं» में परिपक्व होती है: स्वयं फैलने वाली, स्वयं शासित, स्वयं का भरण-पोषण करने वाली, अपनी धर्मविद्या गढ़ने वाली और स्वयं मिशनरी भेजने वाली।',
|
||||
alternatives: 'स्थानीय कलीसिया · देशी कलीसिया · आदिवासी कलीसिया',
|
||||
rationale:
|
||||
'यह प्लेबुक का शब्द है। «स्थानीय कलीसिया» का अर्थ केवल आस-पास की कलीसिया है, और «आदिवासी» भारत के जनजातीय समुदायों की ओर संकेत करता है।'
|
||||
},
|
||||
{
|
||||
term: 'अंतर-सांस्कृतिक कार्यकर्ता',
|
||||
english: 'cross-cultural workers',
|
||||
definition:
|
||||
'किसी दूसरी संस्कृति से आकर किसी जनसमूह के बीच सेवा करने वाले मिशन कार्यकर्ता। «अंतर-सांस्कृतिक» जानबूझकर जोड़ा गया है — ये उसी जनसमूह के भीतर से नहीं आते — और कई संदर्भों में यह केवल «मिशनरी» कहने से बेहतर है।',
|
||||
alternatives: 'क्रॉस-सांस्कृतिक मिशनरी · विदेशी मिशनरी · अंतर-सांस्कृतिक मिशनरी',
|
||||
rationale:
|
||||
'प्लेबुक «अंतर-सांस्कृतिक मिशनरी» को विस्तार से परिभाषित करता है; यहाँ «कार्यकर्ता» रखा गया है ताकि «मिशनरी» शब्द DOXA साझेदारी मिशनरी के लिए बचा रहे। गोद लेने का प्रमाणपत्र भी «राज्य के कार्यकर्ता» कहता है।'
|
||||
},
|
||||
{
|
||||
term: 'खेत का स्वामी',
|
||||
english: 'Lord of the harvest',
|
||||
definition:
|
||||
'यीशु के लिए एक बाइबिलीय पद (मत्ती 9:38), जिसका प्रयोग इस पुकार में होता है कि वे अनसंपर्कित जनसमूहों के बीच मजदूर भेजें।',
|
||||
alternatives: 'फसल का प्रभु · फसल का स्वामी · खेत के प्रभु',
|
||||
rationale:
|
||||
'यह पवित्र बाइबिल के पुराने संस्करण (OV) में मत्ती 9:38 की भाषा है — «इसलिये खेत के स्वामी से विनती करो कि वह अपने खेत काटने के लिए मजदूर भेज दे।» «फसल का प्रभु» मशीनी अनुवाद है। किसी समीक्षक के दूसरा बाइबिल संस्करण बताने पर यह पद बदलेगा।'
|
||||
},
|
||||
{
|
||||
term: 'प्रार्थना मार्ग तैयार करती है',
|
||||
english: 'prayer prepares the way',
|
||||
definition:
|
||||
'यह विश्वास कि मध्यस्थ प्रार्थना कार्यकर्ताओं के पहुँचने से बहुत पहले ही सुसमाचार की सफलता के लिए आत्मिक परिस्थितियाँ तैयार कर देती है — «प्रभु का मार्ग तैयार करो» की गूँज के साथ।',
|
||||
alternatives: 'प्रार्थना द्वार खोलती है · प्रार्थना भूमि तैयार करती है',
|
||||
rationale:
|
||||
'सीधा और बाइबिलीय अनुवाद रखा गया है। doxa.life के पुराने मशीनी अनुवाद ने इससे मिलती-जुलती पंक्ति को «प्रार्थना संवाद का द्वार खोलती है» बना दिया था — यानी बातचीत का द्वार — और यही भटकाव यह प्रविष्टि रोकने के लिए है।'
|
||||
},
|
||||
{
|
||||
term: 'हृदय की भाषा',
|
||||
english: 'heart language',
|
||||
definition:
|
||||
'किसी व्यक्ति की पहली भाषा — वह भाषा जिसमें वह सोचता और महसूस करता है। सुसमाचार और चेला बनाने का कार्य पूरी तरह प्रभावी तभी होता है जब वह इसी भाषा में हो; यह राजभाषा या व्यापार की भाषा से अलग है।',
|
||||
alternatives: 'मातृभाषा · स्थानीय भाषा · अपनी भाषा',
|
||||
rationale:
|
||||
'«मातृभाषा» हमेशा हृदय की भाषा नहीं होती, और «स्थानीय भाषा», जो प्लेबुक में आया है, केवल क्षेत्र की भाषा बताता है। हिंदी प्रार्थना सामग्री पहले से «हृदय की भाषा» कहती है।'
|
||||
},
|
||||
{
|
||||
term: 'प्रार्थना विषय',
|
||||
english: 'prayer points',
|
||||
definition:
|
||||
'वे दैनिक, जनसमूह-विशेष प्रार्थना निवेदन जो DOXA मध्यस्थों को भेजता है — पवित्रशास्त्र पर केंद्रित और क्षेत्र से जुड़े हुए, सामान्य भक्ति-सामग्री से अलग।',
|
||||
alternatives: 'प्रार्थना बिंदु · प्रार्थना संकेत · प्रार्थना निवेदन',
|
||||
rationale:
|
||||
'भारतीय कलीसियाओं में प्रार्थना की सूची के लिए यही शब्द चलता है। «प्रार्थना बिंदु» अंग्रेज़ी का सीधा अनुवाद है और «प्रार्थना संकेत» का अर्थ इशारा होता है।'
|
||||
},
|
||||
{
|
||||
term: 'जनसमूह को अपनाना',
|
||||
english: 'adopt (a people group)',
|
||||
definition:
|
||||
'किसी एक अनसंपर्कित जनसमूह के लिए कलीसिया की अगुवाई में लिया गया दीर्घकालिक वचन — प्रार्थना करने, दान देने और भेजने का — ताकि उन तक सुसमाचार की पहुँच शुरू हो। यह मिशन का दायित्व उठाना है, कानूनी दत्तक ग्रहण नहीं।',
|
||||
alternatives: 'गोद लेना · दत्तक ग्रहण · अंगीकार',
|
||||
rationale:
|
||||
'गोद लेने का छपा हुआ हिंदी प्रमाणपत्र «विश्वासपूर्वक अपनाया है» कहता है, और doxa.life के समीक्षक ने भी क्रिया के रूप में «अपनाएँ» माँगा। संज्ञा के रूप में «गोद लेना» चलता है। «दत्तक ग्रहण» बच्चों को कानूनी रूप से गोद लेना है और उसे हटा दिया गया है।'
|
||||
},
|
||||
{
|
||||
term: 'यीशु को हमारा उपहार',
|
||||
english: 'our gift to Jesus',
|
||||
definition:
|
||||
'पूरे प्रयास को देखने का ढंग: 2033 तक हर जनसमूह के साथ सहभागिता स्थापित करना, कलीसिया की ओर से आराधना की सामूहिक भेंट के रूप में — बलिदान, कोई लेन-देन नहीं।',
|
||||
alternatives: 'यीशु को हमारा तोहफ़ा · यीशु के लिए हमारी भेंट',
|
||||
rationale:
|
||||
'प्लेबुक के आरंभिक पत्र की भाषा: «हम मिलकर यीशु को एक उपहार दे सकें।» «तोहफ़ा» व्यापारिक और हल्का लगता है।'
|
||||
},
|
||||
{
|
||||
term: 'वर्ल्ड असेंबलीज़ ऑफ़ गॉड फेलोशिप (WAGF)',
|
||||
english: 'World Assemblies of God Fellowship (WAGF)',
|
||||
definition:
|
||||
'वह वैश्विक संगति जिसने DOXA की शुरुआत की और जो उसकी देखरेख करती है।',
|
||||
alternatives: 'विश्व असेंबलीज़ ऑफ़ गॉड फेलोशिप · अनुवादित नाम',
|
||||
rationale:
|
||||
'प्लेबुक का हिंदी अनुवाद नाम का लिप्यंतरण करता है, अनुवाद नहीं, क्योंकि भारत में यह संगति इसी नाम से जानी जाती है। संक्षेप WAGF हिंदी में भी अपरिवर्तित रहता है।'
|
||||
},
|
||||
{
|
||||
term: 'भेजने वाली एजेंसियाँ',
|
||||
english: 'sending agencies',
|
||||
definition:
|
||||
'वे संस्थाएँ जो मिशनरियों को चुनती, प्रशिक्षित करती, सहारा देती और भेजती हैं। DOXA भेजने वाली एजेंसियों के साथ काम करता है (2026 तक WAGF से जुड़ी 129), उनकी जगह नहीं लेता।',
|
||||
alternatives: 'प्रेषण संस्थाएँ · मिशन संस्थाएँ · भेजने वाली संस्थाएँ',
|
||||
rationale:
|
||||
'यह प्लेबुक की साझेदारी-घोषणा की भाषा है, जो बार-बार «भेजने वाली एजेंसियाँ» कहती है।'
|
||||
},
|
||||
{
|
||||
term: 'दैनिक प्रार्थना',
|
||||
english: 'daily prayer (for a people group)',
|
||||
definition:
|
||||
'दैनिक प्रार्थना मार्गदर्शिका के साथ किसी एक अनसंपर्कित जनसमूह के लिए हर दिन प्रार्थना करने का वचन। लक्ष्य है हर जनसमूह के लिए 100 से अधिक दैनिक मध्यस्थ। «दैनिक» जानबूझकर कहा गया है — यह हर दिन का वचन है, नियमित या कभी-कभार की प्रार्थना नहीं।',
|
||||
alternatives: 'प्रतिदिन प्रार्थना · नियमित प्रार्थना · रोज़ाना प्रार्थना',
|
||||
rationale:
|
||||
'लेबल में «दैनिक» और वाक्य के भीतर «प्रतिदिन», जैसा प्लेबुक लिखता है। «नियमित» इसे कमज़ोर कर देता है और उस गिनती को तोड़ देता है जिस पर 100 मध्यस्थों का लक्ष्य टिका है।'
|
||||
},
|
||||
{
|
||||
term: 'हर कुल, हर भाषा, हर लोग और हर जाति',
|
||||
english: 'every tribe, tongue, people, and nation',
|
||||
definition:
|
||||
'प्रकाशितवाक्य 5:9 और 7:9 का वह दर्शन जो इस मिशन को प्रेरित करता है। चारों संज्ञाएँ मानव विविधता का अलग-अलग पहलू बताती हैं।',
|
||||
alternatives: 'हर जनजाति, हर भाषा, हर जाति और हर राष्ट्र · हर जाति, गोत्र, लोग और भाषा',
|
||||
rationale:
|
||||
'यह पवित्र बाइबिल के पुराने संस्करण (OV) में प्रकाशितवाक्य 5:9 का क्रम और शब्द हैं — «हर एक कुल और भाषा और लोग और जाति में से» — जो अंग्रेज़ी के चारों शब्दों से एक-एक करके मेल खाता है। यही बाइबिल प्रकाशितवाक्य 7:9 में इन्हीं शब्दों को उलटे क्रम में रखती है — «हर एक जाति और कुल और लोग और भाषा में से» — और गोद लेने का छपा हुआ प्रमाणपत्र अपना ही रूप छापता है («हर जाति, गोत्र, लोगों और भाषाओं में से»); यह प्रविष्टि 5:9 के क्रम पर टिकी है। उद्धरण के रूप में दिया गया पद बाइबिल की अपनी भाषा रखता है; यह प्रविष्टि वेबसाइट का सारांश-वाक्यांश है।'
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
@ -1,12 +1,23 @@
|
|||
// Terminology page content (/terms). Each locale has its own edition
|
||||
// Terminology page content (/about/definitions). Each locale has its own edition
|
||||
// documenting that language's terminology decisions — the chosen term,
|
||||
// alternatives considered, what Joshua Project and PeopleGroups.org use,
|
||||
// and the rationale. Locales without an edition fall back to English.
|
||||
// New language editions are added as part of the language-stabilization
|
||||
// process (see translation/LANGUAGE-STABILIZATION.md in the doxa monorepo).
|
||||
// A new edition is written when a language is added or its terminology
|
||||
// changes; the `add-language` and `sync-language` skills in .claude/skills
|
||||
// cover it. Terminology itself comes from the DOXA glossary, published at
|
||||
// https://pray.doxa.life/api/glossary/{lang}.
|
||||
|
||||
import { en } from './en'
|
||||
import { fr } from './fr'
|
||||
import { de } from './de'
|
||||
import { es } from './es'
|
||||
import { pt } from './pt'
|
||||
import { it } from './it'
|
||||
import { zh } from './zh'
|
||||
import { ru } from './ru'
|
||||
import { hi } from './hi'
|
||||
import { ro } from './ro'
|
||||
import { ar } from './ar'
|
||||
|
||||
export interface TermEntry {
|
||||
/** Canonical term in this edition's language. */
|
||||
|
|
@ -26,10 +37,6 @@ export interface TermEntry {
|
|||
export interface TermsContent {
|
||||
title: string
|
||||
intro: string[]
|
||||
/** "Full definitions live on the" / link label / " page." */
|
||||
seeDefinitionsBefore: string
|
||||
definitionsLinkLabel: string
|
||||
seeDefinitionsAfter: string
|
||||
labels: {
|
||||
english: string
|
||||
definition: string
|
||||
|
|
@ -41,7 +48,7 @@ export interface TermsContent {
|
|||
entries: TermEntry[]
|
||||
}
|
||||
|
||||
const editions: Record<string, TermsContent> = { en, fr }
|
||||
const editions: Record<string, TermsContent> = { en, fr, de, es, pt, it, zh, ru, hi, ro, ar }
|
||||
|
||||
export function getTermsContent(locale: string): TermsContent {
|
||||
return editions[locale] ?? en
|
||||
|
|
|
|||
199
app/utils/terms/it.ts
Normal file
199
app/utils/terms/it.ts
Normal file
|
|
@ -0,0 +1,199 @@
|
|||
import type { TermsContent } from './index'
|
||||
|
||||
export const it: TermsContent = {
|
||||
title: 'Definizioni',
|
||||
intro: [
|
||||
'Questa pagina documenta le scelte terminologiche italiane della partnership DOXA. Per ogni termine: la definizione, le alternative considerate e il motivo della scelta.',
|
||||
'Le nostre fonti: il glossario DOXA, l’uso già consolidato sull’app di preghiera e nei contenuti di preghiera quotidiani in italiano, il vocabolario missionario evangelico italiano e la Nuova Riveduta 2006 per ogni espressione di origine biblica. Joshua Project e PeopleGroups.org (IMB) non pubblicano dati in italiano, quindi questa edizione non li cita.'
|
||||
],
|
||||
labels: {
|
||||
english: 'Inglese:',
|
||||
definition: 'Definizione:',
|
||||
alternatives: 'Alternative considerate:',
|
||||
jp: 'Joshua Project:',
|
||||
pg: 'PeopleGroups.org:',
|
||||
rationale: 'Perché questa scelta:'
|
||||
},
|
||||
entries: [
|
||||
{
|
||||
term: 'Gruppo etnico',
|
||||
english: 'people group',
|
||||
definition:
|
||||
'un gruppo etnolinguistico i cui membri percepiscono tra loro un’affinità comune fondata su lingua, cultura, religione e visione del mondo — il gruppo più ampio all’interno del quale il Vangelo può diffondersi senza incontrare barriere di comprensione o di accettazione. È l’unità fondamentale di tutto ciò che DOXA conta.',
|
||||
alternatives: 'popolo · gruppo di persone · etnia · tribù',
|
||||
rationale:
|
||||
'è l’etichetta che l’app di preghiera e i contenuti di preghiera italiani usano già ovunque nei conteggi e nei pulsanti. «Popolo» resta naturale nella prosa corrente («i popoli non raggiunti», «un popolo di frontiera»), ma come etichetta è ambiguo perché in italiano indica anche una nazione. «Gruppo di persone» è traduzione automatica; «tribù» porta con sé connotazioni primitive; «etnia» perde la dimensione linguistica.'
|
||||
},
|
||||
{
|
||||
term: 'Gruppo etnico non raggiunto (UPG)',
|
||||
english: 'unreached people group (UPG)',
|
||||
definition:
|
||||
'circa 2 discepoli o meno ogni 100 persone (≤ 2%), senza la capacità di fondare chiese autoctone senza assistenza transculturale. Joshua Project aggiunge un criterio del ≤ 5% di cristiani dichiarati; DOXA segue la definizione dell’IMB.',
|
||||
alternatives: 'popolo non raggiunto · UPG scritto per esteso',
|
||||
rationale:
|
||||
'la sigla inglese resta invariata, come UUPG e CPM: l’italiano non ha una sigla missiologica stabile per questa categoria e inventarne una renderebbe illeggibili i dati internazionali. «Non raggiunto» è il termine consolidato della missiologia evangelica italiana.'
|
||||
},
|
||||
{
|
||||
term: 'Non coinvolto',
|
||||
english: 'unengaged people group',
|
||||
definition:
|
||||
'un gruppo etnico presso il quale non risulta alcuno sforzo mirato a fondare chiese capaci di sostenersi: mancano i quattro livelli del coinvolgimento efficace (sforzo apostolico pionieristico residente; lavoro nella cultura locale e nella lingua del cuore; impegno a lungo termine; semina del Vangelo orientata a un movimento di fondazione di chiese). È un termine tecnico dell’IMB: dice che nessuno lavora tra loro, non che quel popolo sia indifferente.',
|
||||
alternatives: 'non impegnato · non toccato · senza presenza missionaria · non evangelizzato',
|
||||
rationale:
|
||||
'«coinvolgimento» e «coinvolto» formano in italiano una famiglia completa e coerente con tutti i termini derivati — coinvolgere, coinvolto, non coinvolto, poco coinvolto, coinvolgimento fruttuoso — cosa che «impegno» non fa, perché in italiano descrive già la dedizione personale di chi prega. «Non evangelizzato» descrive un’altra cosa: l’assenza di annuncio, non l’assenza di operai residenti.'
|
||||
},
|
||||
{
|
||||
term: 'Gruppo etnico non coinvolto e non raggiunto (UUPG)',
|
||||
english: 'unengaged unreached people group (UUPG)',
|
||||
definition:
|
||||
'la categoria combinata — non coinvolto e non raggiunto. Sono i 2.085 gruppi etnici per cui DOXA mobilita la preghiera.',
|
||||
alternatives: 'popolo non raggiunto e non coinvolto · sigla italiana di nuovo conio',
|
||||
rationale:
|
||||
'UUPG è la sigla affermata a livello internazionale e viene mantenuta, come fa l’edizione francese. Nella forma estesa «non coinvolto» viene prima di «non raggiunto», seguendo l’ordine dell’inglese e quello già usato dall’app di preghiera.'
|
||||
},
|
||||
{
|
||||
term: 'Poco coinvolto',
|
||||
english: 'under-engaged people group',
|
||||
definition:
|
||||
'circa 1 discepolo o meno ogni 100 persone (≤ 1%): il lavoro è cominciato, ma servono altre squadre di fondazione di chiese perché il coinvolgimento sia fruttuoso.',
|
||||
alternatives: 'sotto-coinvolto · scarsamente coinvolto · parzialmente coinvolto',
|
||||
rationale:
|
||||
'«poco coinvolto» descrive l’ampiezza del lavoro svolto, non l’atteggiamento del popolo, e resta nella stessa famiglia di «coinvolto» e «non coinvolto». Il calco «sotto-coinvolto» non è italiano corrente.'
|
||||
},
|
||||
{
|
||||
term: 'Popolo di frontiera',
|
||||
english: 'frontier people group',
|
||||
definition:
|
||||
'circa 1 discepolo o meno ogni 1.000 persone (≤ 0,1%), senza alcun movimento verso Gesù confermato e duraturo — i più non raggiunti tra i non raggiunti. Il termine viene da Joshua Project.',
|
||||
alternatives: 'popolo di confine · gruppo etnico di frontiera',
|
||||
rationale:
|
||||
'«frontiera» conserva l’immagine del limite estremo da superare che l’inglese frontier porta con sé; «confine» in italiano indica soltanto una linea amministrativa. È la forma già usata nei contenuti di preghiera italiani.'
|
||||
},
|
||||
{
|
||||
term: 'Coinvolgimento',
|
||||
english: 'engagement',
|
||||
definition:
|
||||
'attività transculturale duratura e residente, volta ad annunciare Cristo e fare discepoli, orientata a chiese capaci di sostenersi e condotta in modo culturalmente appropriato e localmente pertinente. È un termine di precisione: «contatto» o «interessamento» non sono coinvolgimento.',
|
||||
alternatives: 'impegno · presenza missionaria · lavoro sul campo',
|
||||
rationale:
|
||||
'è il termine attorno al quale ruota tutta la terminologia DOXA, perché da esso derivano coinvolto, non coinvolto, poco coinvolto e coinvolgimento fruttuoso. «Impegno» è riservato alla dedizione di chi prega, dona o adotta, così che le due idee non si confondano in una sola parola.'
|
||||
},
|
||||
{
|
||||
term: 'Movimento di fondazione di chiese (CPM)',
|
||||
english: 'church-planting movement (CPM)',
|
||||
definition:
|
||||
'una moltiplicazione di chiese autoctone che fondano altre chiese: almeno quattro filoni di quattro generazioni spirituali, per un totale superiore a 1.000 persone.',
|
||||
alternatives: 'movimento di piantagione di chiese · movimento di moltiplicazione di chiese',
|
||||
rationale:
|
||||
'«fondazione di chiese» è italiano corrente e inequivocabile. Il verbo «piantare chiese» è diffuso negli ambienti evangelici italiani e resta utilizzabile nella prosa, ma il sostantivo «piantagione» indica anzitutto una coltivazione ed è un calco che non regge come etichetta. La sigla inglese CPM è mantenuta.'
|
||||
},
|
||||
{
|
||||
term: 'Chiesa autoctona',
|
||||
english: 'indigenous church',
|
||||
definition:
|
||||
'una chiesa nata all’interno del gruppo etnico stesso, che matura nelle cinque autonomie: si propaga, si governa, si sostiene, elabora la propria teologia e invia i propri missionari.',
|
||||
alternatives: 'chiesa indigena · chiesa locale · chiesa nazionale',
|
||||
rationale:
|
||||
'in italiano «indigeno» rimanda ai popoli indigeni ed è già usato da DOXA per distinguere un gruppo etnico autoctono da una popolazione della diaspora: riutilizzarlo qui creerebbe due sensi diversi nello stesso contesto. «Chiesa locale» in italiano indica semplicemente la singola congregazione e perde del tutto il senso tecnico.'
|
||||
},
|
||||
{
|
||||
term: 'Operatori transculturali',
|
||||
english: 'cross-cultural workers',
|
||||
definition:
|
||||
'operai missionari provenienti da una cultura diversa che servono tra un gruppo etnico. La precisazione «transculturale» è voluta — non provengono dall’interno del gruppo — ed è preferita al semplice «missionario» in alcuni contesti.',
|
||||
alternatives: 'operatori interculturali · operai transculturali · missionari',
|
||||
rationale:
|
||||
'in missiologia italiana l’aggettivo consolidato è «transculturale» («missione transculturale»), mentre «interculturale» appartiene al lessico della scuola e del lavoro sociale e indica il dialogo fra culture, non l’attraversarle. Le edizioni spagnola, portoghese e francese usano tutte la forma trans-.'
|
||||
},
|
||||
{
|
||||
term: 'Signore della messe',
|
||||
english: 'Lord of the harvest',
|
||||
definition:
|
||||
'un titolo biblico di Gesù (Matteo 9:38), usato nell’invito a pregare che egli mandi operai tra i non coinvolti.',
|
||||
alternatives: 'Signore della mietitura · padrone della messe',
|
||||
rationale:
|
||||
'è la formulazione della Nuova Riveduta 2006, la traduzione di riferimento italiana di DOXA: «Pregate dunque il Signore della mèsse che mandi degli operai nella sua mèsse». Manteniamo anche il verbo «mandare» della stessa versione nell’invito a pregare, donare e mandare.'
|
||||
},
|
||||
{
|
||||
term: 'La preghiera prepara la via',
|
||||
english: 'prayer prepares the way',
|
||||
definition:
|
||||
'la convinzione che l’intercessione crei le condizioni spirituali per le svolte del Vangelo ancora prima che gli operai arrivino.',
|
||||
alternatives: 'la preghiera prepara il terreno · la preghiera apre la strada',
|
||||
rationale:
|
||||
'riprende «Preparate la via del SIGNORE» (Isaia 40:3, Nuova Riveduta 2006) e conserva quindi l’eco biblica che l’inglese porta con sé. «Preparare il terreno» è un’immagine agricola corretta ma priva di quel riferimento.'
|
||||
},
|
||||
{
|
||||
term: 'Lingua del cuore',
|
||||
english: 'heart language',
|
||||
definition:
|
||||
'la prima lingua di una persona, quella in cui pensa e sente. Perché l’annuncio del Vangelo e il discepolato siano pienamente efficaci devono avvenire in questa lingua; è cosa diversa da una lingua ufficiale o veicolare.',
|
||||
alternatives: 'lingua materna · lingua madre · prima lingua',
|
||||
rationale:
|
||||
'è la formulazione già usata in tutti i contenuti di preghiera italiani. «Lingua materna» è il termine linguistico corretto, ma «lingua del cuore» conserva la dimensione affettiva e spirituale che rende il concetto significativo nel contesto missionario.'
|
||||
},
|
||||
{
|
||||
term: 'Spunti di preghiera',
|
||||
english: 'prayer points',
|
||||
definition:
|
||||
'le richieste di preghiera quotidiane e specifiche per ciascun gruppo etnico che DOXA invia agli intercessori: centrate sulla Scrittura e collegate al campo, distinte da un contenuto devozionale generico.',
|
||||
alternatives: 'punti di preghiera · motivi di preghiera · soggetti di preghiera',
|
||||
rationale:
|
||||
'«spunti» dice che si tratta di indicazioni da cui partire per pregare, che è esattamente ciò che il contenuto quotidiano offre. «Punti di preghiera» è un calco dall’inglese; «motivi di preghiera» in italiano indica le richieste portate dai membri di una comunità, cioè un’altra cosa.'
|
||||
},
|
||||
{
|
||||
term: 'Adottare (un gruppo etnico)',
|
||||
english: 'adopt (a people group)',
|
||||
definition:
|
||||
'l’impegno duraturo, guidato da una chiesa, a pregare, donare e mandare perché per uno specifico gruppo etnico non coinvolto cominci l’accesso al Vangelo. È un patrocinio missionario, non l’adozione del diritto di famiglia.',
|
||||
alternatives: 'sostenere · patrocinare · farsi carico di',
|
||||
rationale:
|
||||
'«adottare» conserva la forza del legame permanente e di responsabilità che il programma chiede, ed è la parola già usata nel certificato di adozione italiano e in tutta l’app. Le alternative descrivono un sostegno che si può interrompere.'
|
||||
},
|
||||
{
|
||||
term: 'Il nostro dono a Gesù',
|
||||
english: 'our gift to Jesus',
|
||||
definition:
|
||||
'la cornice di tutta l’iniziativa: coinvolgere ogni popolo entro il 2033 come offerta di adorazione della Chiesa intera — un dono sacrificale, non uno scambio.',
|
||||
alternatives: 'il nostro regalo a Gesù · la nostra offerta a Gesù',
|
||||
rationale:
|
||||
'«dono» ha in italiano il registro della gratuità e dell’offerta; «regalo» è quotidiano e domestico. «Offerta» è corretto ma nelle chiese italiane indica anzitutto la colletta.'
|
||||
},
|
||||
{
|
||||
term: 'Fratellanza Mondiale delle Assemblee di Dio (WAGF)',
|
||||
english: 'World Assemblies of God Fellowship (WAGF)',
|
||||
definition:
|
||||
'la comunione mondiale che ha fondato DOXA e la custodisce. La sigla WAGF resta invariata in ogni lingua.',
|
||||
alternatives: 'nome inglese non tradotto · Comunione Mondiale delle Assemblee di Dio',
|
||||
rationale:
|
||||
'le Assemblee di Dio in Italia (ADI) fanno parte di questa comunione e il nome proprio italiano corrente della denominazione è «Assemblee di Dio». La resa dell’organismo mondiale attende conferma da un revisore italiano; nel frattempo la sigla WAGF garantisce che il riferimento resti riconoscibile.'
|
||||
},
|
||||
{
|
||||
term: 'Agenzie missionarie',
|
||||
english: 'sending agencies',
|
||||
definition:
|
||||
'organizzazioni che reclutano, formano, sostengono e inviano missionari. DOXA collabora con le agenzie missionarie (129 affiliate alla WAGF nel 2026) ma non le sostituisce.',
|
||||
alternatives: 'agenzie di invio · enti invianti · società missionarie',
|
||||
rationale:
|
||||
'«agenzia missionaria» è la formula corrente in italiano e si regge da sola: la precisazione «di invio» è ridondante, perché inviare è ciò che un’agenzia missionaria fa.'
|
||||
},
|
||||
{
|
||||
term: 'Preghiera quotidiana (per un gruppo etnico)',
|
||||
english: 'daily prayer (for a people group)',
|
||||
definition:
|
||||
'l’impegno a pregare ogni giorno per uno specifico gruppo etnico non coinvolto, servendosi della guida di preghiera quotidiana. L’obiettivo è di oltre 100 intercessori quotidiani per ciascun gruppo etnico.',
|
||||
alternatives: 'preghiera giornaliera · preghiera regolare',
|
||||
rationale:
|
||||
'«quotidiana» è voluto: indica un impegno di ogni giorno, non una preghiera regolare od occasionale. Sostituisce l’impostazione precedente dei 144 intercessori che coprivano 24 ore.'
|
||||
},
|
||||
{
|
||||
term: 'Ogni tribù, lingua, popolo e nazione',
|
||||
english: 'every tribe, tongue, people, and nation',
|
||||
definition:
|
||||
'la visione di Apocalisse 5:9 e 7:9 che muove tutta la missione. Ciascuno dei quattro sostantivi porta una dimensione distinta della diversità umana.',
|
||||
alternatives: 'ogni tribù, lingua, popolo e nazione (altro ordine) · ogni stirpe, lingua, popolo e nazione',
|
||||
rationale:
|
||||
'è la formulazione esatta di Apocalisse 5:9 nella Nuova Riveduta 2006, già usata in tutti i contenuti di preghiera italiani. Per la folla di Apocalisse 7:9 la stessa versione dice «davanti al trono», non «intorno al trono».'
|
||||
}
|
||||
]
|
||||
}
|
||||
178
app/utils/terms/pt.ts
Normal file
178
app/utils/terms/pt.ts
Normal file
|
|
@ -0,0 +1,178 @@
|
|||
import type { TermsContent } from './index'
|
||||
|
||||
export const pt: TermsContent = {
|
||||
title: 'Definições',
|
||||
intro: [
|
||||
'Esta página documenta as decisões terminológicas da parceria DOXA em português. Para cada termo: a definição, as alternativas consideradas, o que o Joshua Project e o PeopleGroups.org (IMB) usam, e o motivo da nossa escolha.',
|
||||
'Nossas fontes: o glossário DOXA revisado por tradutores de língua portuguesa, o uso já estabelecido em doxa.life/pt e no aplicativo, o vocabulário das missões brasileiras e as traduções de Almeida para as expressões de origem bíblica.'
|
||||
],
|
||||
labels: {
|
||||
english: 'Inglês:',
|
||||
definition: 'Definição:',
|
||||
alternatives: 'Alternativas consideradas:',
|
||||
jp: 'Joshua Project:',
|
||||
pg: 'PeopleGroups.org:',
|
||||
rationale: 'Por que esta escolha:'
|
||||
},
|
||||
entries: [
|
||||
{
|
||||
term: 'Grupo étnico',
|
||||
english: 'people group',
|
||||
definition:
|
||||
'um grupo etnolinguístico cujos membros percebem entre si uma afinidade comum baseada na língua, na cultura, na religião e na cosmovisão — o maior grupo dentro do qual o evangelho pode difundir-se como um movimento de plantação de igrejas sem encontrar barreiras de compreensão ou de aceitação. A unidade fundamental de tudo o que a DOXA conta.',
|
||||
alternatives: 'povo · grupo de pessoas · grupo de povos · etnia · tribo',
|
||||
rationale:
|
||||
'o rótulo que doxa.life/pt já usa nas contagens e nos botões (“2.085 grupos étnicos não engajados”, “Escolha um grupo étnico”); o revisor corrigiu “grupos de pessoas” para “grupos étnicos”. “Povo” continua natural na prosa corrida (“povos não engajados”, “um povo de fronteira”) e é o termo do glossário revisado; a página de Definições trata os dois como sinônimos (“Povo (Grupo Étnico)”). “Grupo de pessoas” é tradução automática; “tribo” carrega conotações primitivas; “etnia” perde a dimensão linguística.'
|
||||
},
|
||||
{
|
||||
term: 'Grupo étnico não alcançado (PNA)',
|
||||
english: 'unreached people group (UPG)',
|
||||
definition:
|
||||
'aproximadamente 2 discípulos ou menos em cada 100 pessoas (≤ 2%) e sem capacidade para estabelecer igrejas autóctones sem assistência transcultural. O Joshua Project acrescenta um critério de ≤ 5% de cristãos; a DOXA segue a definição da IMB.',
|
||||
alternatives: 'povo não alcançado · UPG (sigla inglesa)',
|
||||
rationale:
|
||||
'a página de Definições já escreve “povo (grupo étnico) não alcançado (PNA)”. As siglas são aportuguesadas em vez de mantidas em inglês: UPG torna-se PNA, como UUPG torna-se PNANE e CPM torna-se MPI.'
|
||||
},
|
||||
{
|
||||
term: 'Não engajado',
|
||||
english: 'unengaged people group',
|
||||
definition:
|
||||
'um grupo étnico sem crentes conhecidos ou com muito poucos, e sem os quatro níveis primários de engajamento efetivo (esforço apostólico pioneiro residente; trabalho na cultura local e na língua do coração; compromisso ministerial de longo prazo; semeadura do evangelho visando um movimento de plantação de igrejas). Um termo técnico da IMB: diz que ninguém trabalha entre eles, não que as pessoas sejam indiferentes.',
|
||||
alternatives: 'não envolvido · desligado · sem compromisso · não evangelizado',
|
||||
rationale:
|
||||
'“engajar” e “engajamento” são o vocabulário estabelecido das missões brasileiras para esse sentido técnico, e o revisor substituiu “Desligado” e “não envolvidas” por “não engajados”. “Envolvimento” e “compromisso” descrevem uma atitude; “não evangelizado” descreve outra coisa — a ausência de proclamação, não a ausência de obreiros residentes.'
|
||||
},
|
||||
{
|
||||
term: 'Grupo étnico não alcançado e não engajado (PNANE)',
|
||||
english: 'unengaged unreached people group (UUPG)',
|
||||
definition:
|
||||
'a categoria combinada — não alcançado e não engajado. Os 2.085 grupos étnicos pelos quais a DOXA mobiliza oração.',
|
||||
alternatives: 'povo não alcançado não engajado · UUPG (sigla inglesa)',
|
||||
pg: 'UUPG é a sigla estabelecida internacionalmente.',
|
||||
rationale:
|
||||
'o site já usa a sigla portuguesa (“Encontre um PNANE”) e o glossário revisado pede que PNANE seja usada de forma consistente. Na expansão, o “e” torna a expressão legível; no plural escrevemos PNANEs, como no glossário revisado.'
|
||||
},
|
||||
{
|
||||
term: 'Sub-engajado',
|
||||
english: 'under-engaged people group',
|
||||
definition:
|
||||
'aproximadamente 1 discípulo ou menos em cada 100 (≤ 1%): o trabalho começou, mas são necessárias mais equipes de plantação de igrejas para um engajamento frutífero.',
|
||||
alternatives: 'subengajado · pouco engajado · menos envolvido',
|
||||
rationale:
|
||||
'o composto hifenizado é a forma do glossário revisado e a que o revisor escolheu na página inicial (“Sub-engajados”); descreve a escala do trabalho, não a atitude do povo. As variantes “subengajados” e “pouco engajados” são resíduos de tradução automática.'
|
||||
},
|
||||
{
|
||||
term: 'Povo de fronteira',
|
||||
english: 'frontier people group',
|
||||
definition:
|
||||
'aproximadamente 1 discípulo ou menos em cada 1.000 (≤ 0,1%), sem qualquer movimento confirmado e sustentado em direção a Jesus — os mais não alcançados entre os não alcançados. O termo vem do Joshua Project.',
|
||||
alternatives: 'povo fronteiriço · grupo étnico de fronteira · Povo da Fronteira',
|
||||
rationale:
|
||||
'o revisor trocou “povos fronteiriços” por “povos de fronteira”. “Fronteiriço” evoca a fronteira entre países; “de fronteira” preserva o sentido de vanguarda missiológica, o primeiro contato com o evangelho. Aqui fica “povo”, e não “grupo étnico”, porque é a forma fixada no glossário revisado e a mais curta para rótulos.'
|
||||
},
|
||||
{
|
||||
term: 'Engajamento · engajado',
|
||||
english: 'engagement · engaged',
|
||||
definition:
|
||||
'atividade sustentada, residente e transcultural para compartilhar Cristo e fazer discípulos, com esforços para estabelecer igrejas autossustentáveis, de formas culturalmente apropriadas e localmente relevantes (ver “O que é engajamento?” na página Visão).',
|
||||
alternatives: 'envolvimento · compromisso · participação · contato',
|
||||
rationale:
|
||||
'um termo de precisão: residente, sustentado, transcultural, orientado para um MPI. O revisor substituiu “compromisso” por “engajamento” (“O engajamento começa com a oração”) e “Envolver-se” por “Engaje-se”. “Envolvimento” ou “participação” esvaziam o sentido, e a família engajar / engajado / engajamento / não engajado / sub-engajado / engajamento frutífero deve manter-se unida — por isso a manchete “Envolvimento frutífero” da página inicial passa a “Engajamento frutífero”.'
|
||||
},
|
||||
{
|
||||
term: 'Movimento de plantação de igrejas (MPI)',
|
||||
english: 'church-planting movement (CPM)',
|
||||
definition:
|
||||
'uma multiplicação de igrejas autóctones que plantam igrejas, incluindo pelo menos quatro correntes de quatro gerações espirituais que juntas totalizam mais de 1.000 pessoas.',
|
||||
alternatives: 'movimento de implantação de igrejas · CPM (sigla inglesa)',
|
||||
rationale:
|
||||
'“plantação de igrejas” é a expressão corrente nas missões brasileiras. A sigla é aportuguesada (MPI), seguindo o padrão de PNA e PNANE que o site já usa; o glossário revisado usa MPI em todas as menções.'
|
||||
},
|
||||
{
|
||||
term: 'Igreja autóctone',
|
||||
english: 'indigenous church',
|
||||
definition:
|
||||
'uma igreja que emerge do interior do próprio grupo étnico e amadurece nos cinco “autos”: autopropagação, autogoverno, autossustento, autoteologização e automissionação.',
|
||||
alternatives: 'igreja indígena · igreja nativa · igreja local',
|
||||
rationale:
|
||||
'“autóctone” significa com raízes locais e autogoverno. No Brasil, “indígena” remete aos povos indígenas e às religiões tradicionais, o que tornaria “igreja indígena” ambíguo; o revisor reconheceu que “autóctone” é um pouco acadêmico, mas manteve-o (“If translators chose it, keep it”). As menções a “igreja indígena” no site foram alinhadas.'
|
||||
},
|
||||
{
|
||||
term: 'Obreiros transculturais',
|
||||
english: 'cross-cultural workers',
|
||||
alternatives: 'trabalhadores interculturais · obreiros interculturais · missionários estrangeiros',
|
||||
rationale:
|
||||
'“transcultural” é forte no vocabulário missionário brasileiro — o revisor pediu para manter “obreiros transculturais” e “assistência transcultural”. “Obreiro” é a palavra das igrejas para quem trabalha na obra; “trabalhador” soa laboral. “Intercultural” descreve o diálogo entre culturas vizinhas, não o atravessar de uma cultura para outra.'
|
||||
},
|
||||
{
|
||||
term: 'Senhor da seara',
|
||||
english: 'Lord of the harvest',
|
||||
rationale:
|
||||
'Mateus 9:38 nas traduções de Almeida: “Rogai, pois, ao Senhor da seara que mande ceifeiros para a sua seara” (Revista e Corrigida; a Revista e Atualizada diz “trabalhadores”) — a citação que a página Ore já traz. A edição de referência desta versão do site é a Nova Almeida Atualizada, que diz “peçam ao Senhor da seara que mande trabalhadores”: o termo “Senhor da seara” é o mesmo em todas as edições de Almeida, mas a citação da página Ore segue a Revista e Corrigida. A NVI diz “Senhor da colheita”; seguimos Almeida, corrente nas Assembleias de Deus. A metáfora agrícola (seara = pessoas prontas a responder) fica preservada.'
|
||||
},
|
||||
{
|
||||
term: 'A oração prepara o caminho',
|
||||
english: 'prayer prepares the way',
|
||||
alternatives: 'a oração abre o caminho · a oração prepara o terreno',
|
||||
rationale:
|
||||
'eco de Isaías 40:3 (Almeida): “Preparai no deserto o caminho do SENHOR”. A intercessão cria as condições espirituais para o evangelho muito antes de os obreiros chegarem. “Prepara o terreno” continua certo onde o inglês diz “prepares the soil”.'
|
||||
},
|
||||
{
|
||||
term: 'Língua do coração',
|
||||
english: 'heart language',
|
||||
alternatives: 'língua materna · idioma do coração',
|
||||
rationale:
|
||||
'a expressão estabelecida nas missões e na tradução da Bíblia para a língua em que a pessoa pensa e sente — distinta da língua oficial ou da língua franca, distinção que “língua materna” não faz. “Língua” em vez de “idioma” porque é a forma consagrada da expressão.'
|
||||
},
|
||||
{
|
||||
term: 'Pontos de oração',
|
||||
english: 'prayer points',
|
||||
alternatives: 'motivos de oração · pedidos de oração · tópicos de oração',
|
||||
rationale:
|
||||
'“motivos de oração” é a expressão mais comum nas igrejas brasileiras, e “pedidos de oração” a mais comum para pedidos pessoais; o glossário revisado e o site fixaram “pontos de oração diários” (“Receba pontos de oração diários”), e a consistência entre o site, o aplicativo e os e-mails pesa mais do que a preferência. O conjunto diário chama-se “guia de oração diário”.'
|
||||
},
|
||||
{
|
||||
term: 'Adotar (um grupo étnico)',
|
||||
english: 'adopt a people group',
|
||||
alternatives: 'acolher · apadrinhar · assumir · escolher',
|
||||
rationale:
|
||||
'um compromisso formal e de longo prazo, liderado pela igreja, de orar, doar e enviar para que o acesso ao evangelho comece. “Adotar” já é o que se diz em português (“adotar um povo”), e a página Adote deixa claro que não se trata da adoção familiar. “Igreja de acolhimento” e “adesão”, que a tradução automática produziu, foram corrigidos para “igreja adotante” e “adoção”. “Escolher” fica reservado ao passo de seleção (“Escolha um grupo étnico”).'
|
||||
},
|
||||
{
|
||||
term: 'Nossa oferta a Jesus',
|
||||
english: 'our gift to Jesus',
|
||||
alternatives: 'nossa dádiva a Jesus · nosso presente para Jesus',
|
||||
rationale:
|
||||
'o revisor pensou duas vezes: propôs “dádiva” e depois pediu “Nossa oferta a Jesus”, que está no ar. “Oferta” tem o calor de uma oferta de adoração — sacrificial, não transacional; “presente” soa a aniversário, “dádiva” é literário.'
|
||||
},
|
||||
{
|
||||
term: 'World Assemblies of God Fellowship (WAGF)',
|
||||
english: 'World Assemblies of God Fellowship (WAGF)',
|
||||
alternatives: 'Comunhão das Assembleias de Deus Mundial · Fraternidade Mundial das Assembleias de Deus',
|
||||
rationale:
|
||||
'nomes de organizações não se traduzem pela regra do glossário, mas o site usa a forma que o revisor escolheu, “Comunhão das Assembleias de Deus Mundial”, seguida do nome em inglês e da sigla WAGF, que se mantém igual em todo o site.'
|
||||
},
|
||||
{
|
||||
term: 'Secretarias de missões',
|
||||
english: 'sending agencies',
|
||||
alternatives: 'agências enviadoras · agências de envio · agências missionárias',
|
||||
rationale:
|
||||
'o glossário revisado dizia “agência enviadora”, mas a página Sobre já usa “secretaria de missões” (e “secretaria enviadora”) em toda a declaração — o nome que as Assembleias de Deus dão ao seu departamento de missões, e por isso o termo que os leitores reconhecem.'
|
||||
},
|
||||
{
|
||||
term: 'Oração diária (por um grupo étnico)',
|
||||
english: 'daily prayer (for a people group)',
|
||||
definition:
|
||||
'o compromisso de orar todos os dias por um grupo étnico não engajado específico, com o guia de oração diário. A meta: mais de 100 intercessores diários por grupo étnico.',
|
||||
alternatives: 'oração regular · cobertura de oração de 24 horas (meta anterior: 144 intercessores × 10 minutos)',
|
||||
rationale:
|
||||
'“diária” é intencional — um compromisso para cada dia, não uma oração ocasional. A imagem anterior de 144 intercessores que juntos cobrem 24 horas foi substituída pela meta de mais de 100 intercessores diários.'
|
||||
},
|
||||
{
|
||||
term: 'Todas as tribos, línguas, povos e nações',
|
||||
english: 'every tribe, tongue, people, and nation',
|
||||
rationale:
|
||||
'Apocalipse 5:9 e 7:9 — a visão que motiva todo o trabalho. Almeida traduz 7:9 por “de todas as nações, tribos, povos e línguas”, que a página Visão cita; a forma do glossário mantém a ordem do inglês e o plural, como na frase “Jesus é digno da glória de todas as tribos, línguas, povos e nações” que o revisor deixou na página inicial. Cada um dos quatro substantivos nomeia uma dimensão própria da diversidade humana.'
|
||||
}
|
||||
]
|
||||
}
|
||||
196
app/utils/terms/ro.ts
Normal file
196
app/utils/terms/ro.ts
Normal file
|
|
@ -0,0 +1,196 @@
|
|||
import type { TermsContent } from './index'
|
||||
|
||||
export const ro: TermsContent = {
|
||||
title: 'Definiții',
|
||||
intro: [
|
||||
'Această pagină documentează deciziile terminologice românești ale parteneriatului DOXA. Pentru fiecare termen: definiția, alternativele luate în calcul și motivul alegerii.',
|
||||
'Sursele noastre: glosarul DOXA, completat de un recenzent român în septembrie 2026 — niciunul dintre cei 39 de termeni nu este încă confirmat, iar cinci sunt marcați pentru discuție —, vocabularul misionar evanghelic românesc și traducerile românești ale Bibliei pentru fiecare expresie de origine biblică. Recenzentul a indicat Biblia Cornilescu 1924 (VDC) ca ediție a comunității sale, în timp ce site-ul citează deocamdată Noua Traducere Românească (NTR); acolo unde cele două diferă, sunt arătate amândouă. Joshua Project și PeopleGroups.org (IMB) publică doar în engleză, așa că această ediție nu le citează.'
|
||||
],
|
||||
labels: {
|
||||
english: 'În engleză:',
|
||||
definition: 'Definiție:',
|
||||
alternatives: 'Alternative luate în calcul:',
|
||||
jp: 'Joshua Project:',
|
||||
pg: 'PeopleGroups.org:',
|
||||
rationale: 'De ce am ales acest termen:'
|
||||
},
|
||||
entries: [
|
||||
{
|
||||
term: 'Grup etnolingvistic',
|
||||
english: 'people group',
|
||||
definition:
|
||||
'un grup de oameni care se percep pe ei înșiși ca având o afinitate comună, întemeiată pe limbă, cultură, religie și viziune despre lume — cel mai mare grup în interiorul căruia Evanghelia se poate răspândi fără bariere de înțelegere sau de acceptare. Este unitatea de măsură a tot ceea ce numără DOXA.',
|
||||
alternatives: 'grup etnic · popor · etnie · trib',
|
||||
rationale:
|
||||
'recenzentul a aprobat forma completă în locul lui „grup etnic”, care era termenul folosit până acum pe suprafețele românești ale DOXA. „Grup etnic” lasă pe dinafară limba, deși limba este criteriul care desparte două grupuri vecine de aceeași etnie; „popor” rămâne firesc în text curent, dar ca etichetă se confundă cu națiunea; „trib” aduce cu sine conotații primitive. În română, termenul tehnic și cel de zi cu zi sunt același, așa că „grup etnolingvistic” traduce și „ethnolinguistic group”.'
|
||||
},
|
||||
{
|
||||
term: 'Grup etnolingvistic neatins cu Evanghelia (UPG)',
|
||||
english: 'unreached people group (UPG)',
|
||||
definition:
|
||||
'aproximativ 2 ucenici sau mai puțin la 100 de oameni (≤ 2%), fără capacitatea de a întemeia biserici autohtone fără ajutor transcultural. Joshua Project adaugă un criteriu de ≤ 5% creștini declarați; DOXA urmează definiția IMB.',
|
||||
alternatives: 'grup etnolingvistic neatins · popor neatins · neevanghelizat',
|
||||
rationale:
|
||||
'recenzentul a adăugat „cu Evanghelia” la forma propusă: în română, „neatins” singur înseamnă neatins de orice, iar cititorul nu are de unde ști la ce se referă. „Neevanghelizat” descrie altceva — lipsa vestirii, nu lipsa capacității de a întemeia biserici. Sigla latină apare aici pentru că paginile fac trimitere la ea; recenzentul a scos-o din termen, iar întrebarea despre acronime este încă deschisă.'
|
||||
},
|
||||
{
|
||||
term: 'Neangajat misionar',
|
||||
english: 'unengaged people group',
|
||||
definition:
|
||||
'un grup etnolingvistic în mijlocul căruia nu se cunoaște niciun efort îndreptat spre întemeierea unor biserici care se susțin singure: lipsesc cele patru niveluri ale unei angajări misionare eficiente — lucrare apostolică de pionierat prin prezență activă, lucrare în cultura locală și în limba maternă, angajament pe termen lung și semănarea Evangheliei cu ținta unei mișcări de plantare de biserici. Este un termen tehnic al IMB: spune că nimeni nu lucrează în mijlocul lor, nu că oamenii ar fi nepăsători.',
|
||||
alternatives: 'fără angajare misionară activă · neangajat · neevanghelizat',
|
||||
rationale:
|
||||
'recenzentul a înlocuit formularea propusă, „fără angajare misionară activă”, cu adjectivul „neangajat misionar”, care se leagă direct de substantiv și formează o familie completă: angajare misionară, angajat misionar, neangajat misionar, puțin angajat misionar. Calificativul „misionar” este obligatoriu: „neangajat” singur înseamnă în română fără loc de muncă.'
|
||||
},
|
||||
{
|
||||
term: 'Grup etnolingvistic neatins și neangajat misionar (UUPG)',
|
||||
english: 'unengaged unreached people group (UUPG)',
|
||||
definition:
|
||||
'categoria combinată — neatins cu Evanghelia și neangajat misionar. Sunt cele 2.085 de grupuri etnolingvistice pentru care DOXA mobilizează rugăciunea.',
|
||||
alternatives:
|
||||
'grup etnolingvistic neatins și fără angajare misionară activă (UUPG) · un acronim românesc nou',
|
||||
rationale:
|
||||
'recenzentul a scurtat forma propusă și a renunțat la sigla latină, deși instrucțiunile cereau păstrarea ei. Sigla rămâne totuși pe site, pentru că „Găsește un UUPG” este o etichetă de interfață, iar expresia românească este prea lungă pentru un buton. Termenul este marcat pentru discuție în glosar: politica acronimelor ține de limbă, nu de un singur termen.'
|
||||
},
|
||||
{
|
||||
term: 'Puțin angajat misionar',
|
||||
english: 'under-engaged people group',
|
||||
definition:
|
||||
'aproximativ 1 ucenic sau mai puțin la 100 (≤ 1%): lucrarea a început, dar sunt necesare mai multe echipe de plantare de biserici pentru o angajare misionară roditoare.',
|
||||
alternatives: 'cu angajare misionară insuficientă · slab angajat misionar',
|
||||
rationale:
|
||||
'„puțin angajat” păstrează forma de adjectiv a familiei și spune că lucrarea este mică, nu că oamenii ar fi nepăsători. Forma propusă, „cu angajare misionară insuficientă”, era exactă, dar nu se putea folosi ca etichetă.'
|
||||
},
|
||||
{
|
||||
term: 'Grup etnolingvistic de frontieră',
|
||||
english: 'frontier people group',
|
||||
definition:
|
||||
'aproximativ 1 ucenic sau mai puțin la 1.000 (≤ 0,1%), fără o mișcare confirmată și susținută de oameni care se întorc în mod colectiv la Isus — cei mai neatinși dintre cei neatinși. Termenul vine de la Joshua Project.',
|
||||
alternatives: 'popor de frontieră · grup de pionierat',
|
||||
rationale:
|
||||
'aprobat ca atare. „De frontieră” păstrează sensul misiologic de margine a înaintării, fără conotația militară. Pentru „movement to Jesus” glosarul dă „oameni care se întorc în mod colectiv la Isus” și îl marchează pentru discuție tocmai aici: definiția se sprijină pe negație — „fără o mișcare confirmată și susținută” —, iar o expresie despre oameni nu poate fi negată în felul acesta, așa că substantivul „mișcare” rămâne în text.'
|
||||
},
|
||||
{
|
||||
term: 'Angajare misionară',
|
||||
english: 'engagement',
|
||||
definition:
|
||||
'lucrare susținută, cu prezență în mijlocul grupului și cu trecere dincolo de propria cultură, pentru a-L face cunoscut pe Hristos și a face ucenici, cu ținta unor biserici care se susțin singure, în forme potrivite culturii locale.',
|
||||
alternatives: 'implicare · angajament · lucrare misionară',
|
||||
rationale:
|
||||
'„implicare” și „angajament” descriu atitudinea celui care participă, nu prezența unei echipe în mijlocul unui popor. Recenzentul a păstrat „angajare misionară” tocmai pentru că, împreună cu „angajat misionar” și „neangajat misionar”, formează o familie unitară. Pentru „residential engagement” a ales „angajare misionară prin prezență activă”, păstrând „lucrători rezidenți” pentru oameni.'
|
||||
},
|
||||
{
|
||||
term: 'Mișcare de plantare de biserici (CPM)',
|
||||
english: 'church-planting movement (CPM)',
|
||||
definition:
|
||||
'înmulțirea bisericilor autohtone care plantează biserici: cel puțin patru fluxuri a câte patru generații spirituale, care însumează peste 1.000 de persoane.',
|
||||
alternatives: 'mișcare de întemeiere de biserici · CPM tradus integral',
|
||||
rationale:
|
||||
'este singura siglă latină pe care recenzentul a păstrat-o, pentru că datele internaționale o folosesc. „Plantare” este termenul consacrat în misiologia evanghelică românească.'
|
||||
},
|
||||
{
|
||||
term: 'Biserică autohtonă',
|
||||
english: 'indigenous church',
|
||||
definition:
|
||||
'o biserică ivită din interiorul grupului etnolingvistic, care se maturizează în cele cinci caracteristici de autonomie: se înmulțește singură, se conduce singură, se întreține singură, își dezvoltă singură teologia și trimite ea însăși misionari.',
|
||||
alternatives: 'biserică locală · biserică indigenă · biserică băștinașă',
|
||||
rationale:
|
||||
'„autohtonă” spune înrădăcinată local și de sine stătătoare, fără să alunece spre „religie tradițională”. „Biserică locală” înseamnă în română adunarea din localitatea ta, ceea ce este altceva. Româna nu are o formulă consacrată pentru cele cinci „selfs”, așa că lista este redată prin verbe.'
|
||||
},
|
||||
{
|
||||
term: 'Lucrători transculturali',
|
||||
english: 'cross-cultural workers',
|
||||
definition:
|
||||
'lucrători dintr-o altă cultură care slujesc în mijlocul unui grup etnolingvistic. Calificativul este intenționat: ei nu vin din interiorul grupului.',
|
||||
alternatives: 'lucrători interculturali · misionari străini',
|
||||
rationale:
|
||||
'recenzentul a schimbat „interculturali” în „transculturali”: „inter-” înseamnă între culturi, „trans-” înseamnă trecând dincolo de ele, ceea ce descrie exact ce face lucrătorul. „Misionari străini” mută accentul pe cetățenie, nu pe cultură.'
|
||||
},
|
||||
{
|
||||
term: 'Domnul secerișului',
|
||||
english: 'Lord of the harvest',
|
||||
definition:
|
||||
'titlu biblic al lui Isus (Matei 9:38), folosit în chemarea la rugăciune ca El să trimită lucrători la cei neangajați misionar.',
|
||||
rationale:
|
||||
'aprobat fără modificări. Este formularea din ambele ediții românești aflate în discuție — Cornilescu 1924, „Rugați dar pe Domnul secerișului”, și Noua Traducere Românească, „rugați-L fierbinte pe Domnul secerișului” — așa că alegerea nu depinde de ediție.'
|
||||
},
|
||||
{
|
||||
term: 'Rugăciunea pregătește calea',
|
||||
english: 'prayer prepares the way',
|
||||
definition:
|
||||
'convingerea că mijlocirea pregătește terenul spiritual pentru străpungerea Evangheliei cu mult înainte ca lucrătorii să ajungă acolo — cu ecoul chemării „Pregătiți calea Domnului”.',
|
||||
rationale:
|
||||
'aprobat ca atare; ecoul biblic se păstrează în ambele ediții românești.'
|
||||
},
|
||||
{
|
||||
term: 'Limba maternă',
|
||||
english: 'heart language',
|
||||
definition:
|
||||
'prima limbă a unui om — cea în care gândește și simte. Vestirea Evangheliei și ucenicia trebuie să se facă în această limbă ca să fie pe deplin lucrătoare; este altceva decât limba oficială sau limba de comerț.',
|
||||
alternatives: 'limba inimii · limba de acasă',
|
||||
rationale:
|
||||
'recenzentul a preferat expresia obișnuită din română în locul calcului „limba inimii”. „Limba maternă” desparte limba dintâi de limba oficială, dar pierde imaginea misiologică a originalului — o alegere asumată, nu o scăpare.'
|
||||
},
|
||||
{
|
||||
term: 'Motive de rugăciune',
|
||||
english: 'prayer points',
|
||||
definition:
|
||||
'cererile zilnice de rugăciune, specifice fiecărui grup etnolingvistic, pe care DOXA le trimite mijlocitorilor: centrate pe Scriptură și legate de realitatea de pe teren.',
|
||||
alternatives: 'subiecte de rugăciune · puncte de rugăciune',
|
||||
rationale:
|
||||
'recenzentul a înlocuit „subiecte” cu „motive”, cuvântul pe care bisericile românești îl folosesc pentru lucrurile pentru care se roagă o adunare. „Puncte de rugăciune” este traducere literală.'
|
||||
},
|
||||
{
|
||||
term: 'Adoptare',
|
||||
english: 'adopt (a people group)',
|
||||
definition:
|
||||
'angajamentul pe termen lung al unei biserici de a se ruga, de a dărui și de a trimite, pentru ca accesul la Evanghelie să înceapă pentru un anumit grup etnolingvistic neangajat misionar — o asumare misionară, nu o adopție în sensul dreptului familiei.',
|
||||
alternatives: 'adopție · adoptă un grup etnolingvistic neangajat misionar',
|
||||
rationale:
|
||||
'„adopție” este termenul juridic pentru copii și a fost evitat; „adoptare” păstrează sensul de asumare. În formular, recenzentul a scris chemarea întreagă — „adoptă un grup etnolingvistic neangajat misionar” — care merge în text curent, dar nu încape pe un buton, așa că termenul este marcat pentru discuție în glosar.'
|
||||
},
|
||||
{
|
||||
term: 'Darul nostru pentru Isus',
|
||||
english: 'our gift to Jesus',
|
||||
definition:
|
||||
'felul în care este așezat întregul efort: o lucrare misionară activă în fiecare grup etnolingvistic până în 2033, ca dar de închinare al Bisericii — jertfă, nu tranzacție.',
|
||||
rationale: 'aprobat ca atare.'
|
||||
},
|
||||
{
|
||||
term: 'World Assemblies of God Fellowship (WAGF)',
|
||||
english: 'World Assemblies of God Fellowship (WAGF)',
|
||||
definition: 'comuniunea mondială care a început DOXA și o poartă mai departe.',
|
||||
alternatives: 'Comuniunea Mondială a Adunărilor lui Dumnezeu',
|
||||
rationale:
|
||||
'numele rămâne în engleză, ca în celelalte ediții, iar sigla WAGF nu se schimbă nicăieri. Dacă Uniunea Penticostală din România folosește o denumire românească consacrată a comuniunii, un recenzent o poate adăuga aici.'
|
||||
},
|
||||
{
|
||||
term: 'Agenții misionare de trimitere',
|
||||
english: 'sending agencies',
|
||||
definition:
|
||||
'organizații care recrutează, pregătesc, sprijină și trimit misionari. DOXA lucrează împreună cu ele — 129 afiliate WAGF în 2026 — fără să le înlocuiască.',
|
||||
alternatives: 'agenții de trimitere · societăți misionare',
|
||||
rationale:
|
||||
'aprobat ca atare; „de trimitere” păstrează distincția față de partenerii care primesc lucrători pe câmp.'
|
||||
},
|
||||
{
|
||||
term: 'Rugăciune zilnică',
|
||||
english: 'daily prayer (for a people group)',
|
||||
definition:
|
||||
'angajamentul de a te ruga în fiecare zi pentru un anumit grup etnolingvistic neangajat misionar, folosind ghidul zilnic de rugăciune. Ținta este de peste 100 de mijlocitori zilnici pentru fiecare grup.',
|
||||
alternatives: 'rugăciune regulată · rugăciune constantă',
|
||||
rationale:
|
||||
'„zilnică” este intenționat: un angajament pentru fiecare zi, nu o rugăciune regulată sau ocazională.'
|
||||
},
|
||||
{
|
||||
term: 'Din orice neam, din orice seminție, din orice popor și de orice limbă',
|
||||
english: 'every tribe, tongue, people, and nation',
|
||||
definition:
|
||||
'viziunea din Apocalipsa 5:9 și 7:9 care pune în mișcare toată lucrarea. Fiecare dintre cele patru substantive poartă o altă dimensiune a diversității omenești.',
|
||||
alternatives:
|
||||
'din toate neamurile, semințiile, popoarele și limbile (Noua Traducere Românească) · din orice neam, din orice seminție, din orice norod și de orice limbă (Cornilescu 1924)',
|
||||
rationale:
|
||||
'formularea aprobată urmează construcția din Cornilescu 1924, cu „norod” modernizat în „popor”. Recenzentul a indicat Cornilescu 1924 ca ediția comunității sale, în timp ce site-ul citează Noua Traducere Românească; termenul este marcat pentru discuție până când se hotărăște ediția de referință.'
|
||||
}
|
||||
]
|
||||
}
|
||||
209
app/utils/terms/ru.ts
Normal file
209
app/utils/terms/ru.ts
Normal file
|
|
@ -0,0 +1,209 @@
|
|||
import type { TermsContent } from './index'
|
||||
|
||||
export const ru: TermsContent = {
|
||||
title: 'Определения',
|
||||
intro: [
|
||||
'Эта страница описывает русские терминологические решения партнёрства DOXA. Для каждого термина приводятся определение, рассмотренные варианты и причина выбора.',
|
||||
'Наши источники: глоссарий DOXA, русский перевод документа «DOXA — Доступ и согласованность», словоупотребление, уже принятое в молитвенном приложении и в ежедневных молитвенных материалах, русская евангельская миссиологическая лексика и Синодальный перевод — для всех выражений библейского происхождения. Joshua Project и PeopleGroups.org (IMB) не имеют подтверждённого русского издания, поэтому здесь они не цитируются.',
|
||||
'Русская терминология пока не подтверждена носителем-рецензентом: из 39 терминов глоссария не подтверждён ни один, а три помечены как спорные — латинская аббревиатура UUPG, глагол «взять ответственность» вместе с существительным к нему и триада «молиться, жертвовать и отправлять». Приведённые решения отражают то, что сейчас стоит в продуктах, и будут пересмотрены и обновлены рецензентом.'
|
||||
],
|
||||
labels: {
|
||||
english: 'Английский:',
|
||||
definition: 'Определение:',
|
||||
alternatives: 'Рассмотренные варианты:',
|
||||
jp: 'Joshua Project:',
|
||||
pg: 'PeopleGroups.org:',
|
||||
rationale: 'Почему так:'
|
||||
},
|
||||
entries: [
|
||||
{
|
||||
term: 'Народ',
|
||||
english: 'people group',
|
||||
definition:
|
||||
'этнолингвистическая общность, члены которой осознают взаимную близость на основании языка, культуры, религии и мировоззрения, — наибольшая общность, внутри которой Евангелие может распространяться, не встречая барьеров понимания или принятия. Это базовая единица всего, что считает DOXA.',
|
||||
alternatives: 'этническая группа · народность · группа людей · этнос · племя',
|
||||
rationale:
|
||||
'это слово стоит в глоссарии, в русском переводе «Доступа и согласованности» и в молитвенном приложении. «Этническая группа» и «народность» были машинным переводом и разошлись по продуктам сразу в четырёх вариантах; «племя» несёт уничижительный оттенок, «этнос» теряет самосознание общности. «Народ» к тому же перекликается с библейским языком Откр. 7:9, на котором держится всё видение DOXA.'
|
||||
},
|
||||
{
|
||||
term: 'Недостигнутый народ (UPG)',
|
||||
english: 'unreached people group (UPG)',
|
||||
definition:
|
||||
'примерно 2 ученика или менее на 100 человек (≤ 2 %) и отсутствие способности созидать поместные церкви без межкультурной помощи. Joshua Project добавляет критерий ≤ 5 % называющих себя христианами; DOXA следует определению IMB.',
|
||||
alternatives: 'неохваченный народ · неохваченная народность · народ, не достигнутый Евангелием',
|
||||
rationale:
|
||||
'«недостигнутый» — устоявшийся термин русской евангельской миссиологии, и он стоит во всех русских источниках DOXA. Латинская аббревиатура сохраняется, как UUPG и CPM: устойчивой русской аббревиатуры нет, а изобретённая сделала бы международные данные нечитаемыми.'
|
||||
},
|
||||
{
|
||||
term: 'Невовлечённый народ',
|
||||
english: 'unengaged people group',
|
||||
definition:
|
||||
'народ, среди которого нет известных верующих или их единицы и отсутствуют четыре основных уровня эффективного вовлечения: апостольское (первопроходческое) служение с проживанием на месте, труд в местной культуре и на родном языке, долгосрочное служение и сеяние Евангелия ради движения по открытию церквей.',
|
||||
alternatives: 'незадействованный · неохваченный · без активного миссионерского служения',
|
||||
rationale:
|
||||
'«незадействованный» — машинный перевод: он читается как «не занятый делом» и переносит бездействие на сам народ, тогда как речь об отсутствии работы среди него. Волонтёр, вычитывавший сайт, тоже писал «незадействованный», но в этом случае решает глоссарий.'
|
||||
},
|
||||
{
|
||||
term: 'Недостигнутый невовлечённый народ (UUPG)',
|
||||
english: 'unengaged unreached people group (UUPG)',
|
||||
definition:
|
||||
'народ, который одновременно недостигнут и невовлечён. Это и есть список, ради которого существует DOXA: 2 085 народов.',
|
||||
alternatives: 'ННН · недостигнутая и невовлечённая народность',
|
||||
rationale:
|
||||
'в заголовке глоссария стоит «Недостигнутый и Невовлечённый Народ», но его же примеры и русский перевод «Доступа и согласованности» обходятся без «и»; принята короткая форма. В глоссарии термин помечен как спорный, и спор идёт об аббревиатуре: рецензент называет ННН устоявшимся русским сокращением, тогда как все прочие русские источники DOXA пишут латинское UUPG. Пока сохраняется латинская форма; если ННН подтвердится, она заменит её и здесь, и в UPG, и в CPM.'
|
||||
},
|
||||
{
|
||||
term: 'Недостаточно вовлечённый народ',
|
||||
english: 'under-engaged people group',
|
||||
definition:
|
||||
'примерно 1 ученик или менее на 100 человек (≤ 1 %). Работа начата, но команд по открытию церквей не хватает, чтобы вовлечение стало плодотворным.',
|
||||
alternatives: 'малозадействованный · слабо вовлечённый · малоохваченный',
|
||||
rationale:
|
||||
'держит вместе семью «вовлечение — вовлечённый — невовлечённый — недостаточно вовлечённый». Речь о нехватке усилий извне, а не о безразличии самого народа.'
|
||||
},
|
||||
{
|
||||
term: 'Народ фронтира',
|
||||
english: 'frontier people group',
|
||||
definition:
|
||||
'примерно 1 ученик или менее на 1 000 человек (≤ 0,1 %), без подтверждённого устойчивого движения ко Христу. Такие народы часто изолированы, и труд первопроходца, как правило, приходится начинать с неверующих.',
|
||||
alternatives: 'приграничный народ · люди на границе · фронтирный народ',
|
||||
rationale:
|
||||
'«приграничный» и «люди на границе» читаются географически — о государственной границе, а не о миссиологическом переднем крае. Волонтёр, вычитывавший сайт, просил заменить «Люди на границе» именно на «Народ Фронтира», и глоссарий говорит то же.'
|
||||
},
|
||||
{
|
||||
term: 'Вовлечение',
|
||||
english: 'engagement',
|
||||
definition:
|
||||
'устойчивая работа по благовестию и ученичеству ради самостоятельных поместных церквей, которая ведётся культурно уместно и на месте. Для ВСАБ это означает межкультурных служителей, проживающих среди народа.',
|
||||
alternatives: 'взаимодействие · задействованность · вовлечённость · участие',
|
||||
rationale:
|
||||
'«взаимодействие» и «участие» размывают термин до любого контакта, а «вовлечённость» называет свойство там, где нужно действие. Выбранная форма даёт связную семью: вовлечение, вовлечённый, невовлечённый, недостаточно вовлечённый, плодотворное вовлечение.'
|
||||
},
|
||||
{
|
||||
term: 'Движение по открытию церквей (CPM)',
|
||||
english: 'church-planting movement (CPM)',
|
||||
definition:
|
||||
'умножение поместных церквей, открывающих новые церкви: не менее четырёх потоков в четырёх духовных поколениях, в общей сложности более 1 000 человек.',
|
||||
alternatives: 'движение насаждения церквей · движение по созданию церквей · движение по основанию церквей',
|
||||
rationale:
|
||||
'«открытие церквей» — выбор глоссария, и тот же волонтёр написал его в исправлениях к сайту. «Насаждение» ближе к английскому planting, но в русских продуктах DOXA сосуществовали сразу три варианта; оставлен один.'
|
||||
},
|
||||
{
|
||||
term: 'Поместная церковь',
|
||||
english: 'indigenous church',
|
||||
definition:
|
||||
'церковь, выросшая изнутри народа, самостоятельная и зрелая в пяти признаках: самораспространяющаяся, самоуправляемая, самофинансируемая, имеющая свои богословские ресурсы, самостоятельно участвующая в миссионерской работе.',
|
||||
alternatives: 'местная церковь · коренная церковь · туземная церковь',
|
||||
rationale:
|
||||
'«местная» говорит лишь о географии, а «коренная» и «туземная» тянут за собой ассоциации с местными религиями. «Поместная» — обычное слово русской церковной речи для самостоятельной церкви в своём месте.'
|
||||
},
|
||||
{
|
||||
term: 'Межкультурные служители',
|
||||
english: 'cross-cultural workers',
|
||||
definition:
|
||||
'служители из другой культуры, преодолевающие культурные и языковые барьеры, чтобы жить среди народа и взращивать учеников.',
|
||||
alternatives: 'межкультурные работники · межкультурные миссионеры · кросс-культурные работники',
|
||||
rationale:
|
||||
'определение «межкультурный» несёт здесь основную нагрузку: это служители не из того народа, к которому идут. «Работники» звучит как наёмный труд, «кросс-культурный» — калька.'
|
||||
},
|
||||
{
|
||||
term: 'Господь жатвы',
|
||||
english: 'Lord of the harvest',
|
||||
definition:
|
||||
'обращение к Иисусу из Мф. 9:38, которым DOXA призывает молиться о посылаемых делателях.',
|
||||
alternatives: 'Господин жатвы · Владыка жатвы',
|
||||
rationale:
|
||||
'выбор глоссария. В самом Синодальном переводе Мф. 9:38 стоит «молите Господина жатвы» — Господин, а не Господь; форма «Господь жатвы» используется там, где это термин, а в прямой цитате сохраняется синодальное чтение. Призыв на сайте звучит «Усердно молите Господа жатвы… чтобы Он выслал делателей»: само обращение взято из глоссария, а «выслал делателей» — из Синодального перевода.'
|
||||
},
|
||||
{
|
||||
term: 'Молитва прокладывает путь',
|
||||
english: 'prayer prepares the way',
|
||||
definition:
|
||||
'убеждение, что ходатайственная молитва создаёт духовные условия для прорыва Евангелия ещё до прихода служителей.',
|
||||
alternatives: 'молитва готовит путь · молитва подготавливает путь',
|
||||
rationale:
|
||||
'«прокладывает» — выбор глоссария; волонтёр, вычитывавший сайт, предлагал «готовит путь». Понятны оба, но в продуктах должно стоять одно.'
|
||||
},
|
||||
{
|
||||
term: 'Родной язык (язык сердца)',
|
||||
english: 'heart language',
|
||||
definition:
|
||||
'первый язык человека — тот, на котором он думает и чувствует глубже всего, а не государственный или официальный язык.',
|
||||
alternatives: 'язык сердца · сердечный язык · материнский язык',
|
||||
rationale:
|
||||
'глоссарий даёт обе формы, и русский перевод «Доступа и согласованности» сводит их так же: «на родном («сердечном») языке».'
|
||||
},
|
||||
{
|
||||
term: 'Молитвенные темы дня',
|
||||
english: 'prayer points',
|
||||
definition:
|
||||
'содержание ежедневного молитвенного руководства DOXA: библейские темы, нужды с поля, фотографии, истории и сведения о народе.',
|
||||
alternatives: 'темы молитв · молитвенные пункты · молитвенные нужды · молитвенник',
|
||||
rationale:
|
||||
'«пункты» звучат как повестка заседания, а «молитвенник» в русском — это книга молитв или сам молящийся. Волонтёр предлагал «темы молитв»; глоссарий даёт «молитвенные темы дня», и порядок слов взят оттуда. Рядом стоит «ежедневное молитвенное руководство» — само руководство, а не отдельная тема в нём.'
|
||||
},
|
||||
{
|
||||
term: 'Взять ответственность за народ',
|
||||
english: 'adopt (a people group)',
|
||||
definition:
|
||||
'долгосрочное обязательство церкви молиться, жертвовать и отправлять, чтобы у конкретного невовлечённого народа появился доступ к Евангелию.',
|
||||
alternatives: 'принять народ · усыновить · взять под опеку · взять на молитвенное попечение',
|
||||
rationale:
|
||||
'формулировка глоссария — «взять ответственность за невовлечённый народ»; он прямо предостерегает против «усыновления» с его семейно-правовым смыслом, а «опека» в русском несёт ту же правовую окраску. Термин помечен как спорный, и спор — о существительном: глагол решён, а названия самому обязательству нет. На уже напечатанных свидетельствах стоит «принял(а) на молитвенное попечение» и «усыновление в молитве», в молитвенном приложении — «ресурсы усыновления», на сайте сейчас — «принятие ответственности». Спорна и триада: заголовок глоссария даёт «молиться, жертвовать и отправлять», а его же примеры и печатное свидетельство — «посылать»; на сайте стоит заголовочная форма.'
|
||||
},
|
||||
{
|
||||
term: 'Наш дар Иисусу',
|
||||
english: 'our gift to Jesus',
|
||||
definition:
|
||||
'образ, которым DOXA называет свою цель: вовлечение каждого народа как общее приношение поклонения Иисусу.',
|
||||
alternatives: 'наш подарок Иисусу · наше приношение Иисусу',
|
||||
rationale:
|
||||
'«подарок» звучит бытово и коммерчески; «дар» удерживает смысл приношения.'
|
||||
},
|
||||
{
|
||||
term: 'Всемирное содружество Ассамблей Бога (ВСАБ)',
|
||||
english: 'World Assemblies of God Fellowship (WAGF)',
|
||||
definition:
|
||||
'объединение национальных церквей Ассамблей Бога, чья Миссионерская комиссия основала DOXA и несёт о ней попечение.',
|
||||
alternatives: 'Всемирное братство Ассамблей Бога · WAGF без перевода',
|
||||
rationale:
|
||||
'формулировка русского перевода «Доступа и согласованности», где при первом упоминании стоит «ВСАБ / WAGF», а дальше по тексту — только ВСАБ.'
|
||||
},
|
||||
{
|
||||
term: 'Посылающие миссионерские организации',
|
||||
english: 'sending agencies',
|
||||
definition:
|
||||
'организации, которые набирают, обучают, поддерживают и посылают миссионеров. DOXA работает с ними и не заменяет их.',
|
||||
alternatives: 'посылающие агентства · миссионерские агентства · направляющие организации',
|
||||
rationale:
|
||||
'«агентство» в русском ближе к коммерческой посреднической конторе. Глоссарий выбирает «организацию»; русский перевод «Доступа и согласованности» местами пишет «агентство», и здесь решает глоссарий.'
|
||||
},
|
||||
{
|
||||
term: 'Ежедневная молитва',
|
||||
english: 'daily prayer (for a people group)',
|
||||
definition:
|
||||
'обязательство молиться о конкретном невовлечённом народе каждый день — обычно 10 минут, по молитвенному руководству DOXA.',
|
||||
alternatives: 'регулярная молитва · постоянная молитва',
|
||||
rationale:
|
||||
'«ежедневно» здесь не приблизительность, а часть арифметики: 100+ ходатаев по 10 минут в день дают полный молитвенный охват. «Регулярная» эту арифметику разрушает.'
|
||||
},
|
||||
{
|
||||
term: 'Доступ к Евангелию',
|
||||
english: 'gospel access',
|
||||
definition:
|
||||
'наличие у народа возможности услышать и понять Евангелие — через служителей, церкви или само его содержание. Отсутствие такого доступа и есть та беда, ради которой существует DOXA.',
|
||||
alternatives: 'доступность Евангелия · знание Евангелия · слышание Евангелия',
|
||||
rationale:
|
||||
'речь именно о доступности, а не о том, что народ уже услышал. «Знание» и «слышание» описывают результат и потому смещают то, что измеряется.'
|
||||
},
|
||||
{
|
||||
term: 'Из всякого колена, языка, народа и племени',
|
||||
english: 'every tribe, tongue, people, and nation',
|
||||
definition:
|
||||
'библейское видение Откр. 7:9, которым живёт DOXA: все четыре слова названы намеренно и означают разные измерения человеческого разнообразия.',
|
||||
alternatives: 'из всякого племени, языка, народа и нации · из всех племён и колен, и народов и языков',
|
||||
rationale:
|
||||
'формулировка глоссария, совпадающая с русским переводом «Доступа и согласованности». Это обобщающая фраза сайта, а не цитата: Синодальный текст Откр. 7:9 читается «из всех племен и колен, и народов и языков», и именно он напечатан на свидетельствах.'
|
||||
}
|
||||
]
|
||||
}
|
||||
195
app/utils/terms/zh.ts
Normal file
195
app/utils/terms/zh.ts
Normal file
|
|
@ -0,0 +1,195 @@
|
|||
import type { TermsContent } from './index'
|
||||
|
||||
export const zh: TermsContent = {
|
||||
title: '定义',
|
||||
intro: [
|
||||
'本页记录 DOXA 伙伴关系的中文术语选择。每个术语都列出定义、曾考虑过的其他译法,以及选用的理由。',
|
||||
'我们的依据:DOXA 词汇表、祷告应用和中文每日祷告内容中已经在用的措辞、中文福音派与宣教学的既有词汇,以及和合本(简体,CUNPS)——凡出于圣经的表达都以它为准。Joshua Project 和 PeopleGroups.org(IMB)没有确认的中文版本,因此本版不引用它们。',
|
||||
'中文术语尚未经过母语审核者确认。以下选择反映各产品目前的实际用法,将来会由审核者复核并更新。'
|
||||
],
|
||||
labels: {
|
||||
english: '英语:',
|
||||
definition: '定义:',
|
||||
alternatives: '曾考虑的译法:',
|
||||
jp: 'Joshua Project:',
|
||||
pg: 'PeopleGroups.org:',
|
||||
rationale: '选用理由:'
|
||||
},
|
||||
entries: [
|
||||
{
|
||||
term: '族群',
|
||||
english: 'people group',
|
||||
definition:
|
||||
'一个民族语言群体,其成员因语言、文化、宗教和世界观而彼此认同——是福音能够在其中传开而不遇理解或接受障碍的最大群体。这是 DOXA 一切统计的基本单位。',
|
||||
alternatives: '民族群体 · 人群 · 民族 · 部落',
|
||||
rationale:
|
||||
'祷告应用、手机应用、认领证书和中文祷告内容都已经统一用“族群”。“民族”在中文里更多指向国族或法定民族身份,“部落”带有原始色彩,“人群”丢掉了民族语言的含义。1040 地图曾用“民族群体”,现已改齐。'
|
||||
},
|
||||
{
|
||||
term: '未得之民(UPG)',
|
||||
english: 'unreached people group (UPG)',
|
||||
definition:
|
||||
'每 100 人中约有 2 位或更少的门徒(≤ 2%),且没有跨文化协助就无力建立本土教会。Joshua Project 另加“基督徒人口 ≤ 5%”的标准;DOXA 采用 IMB 的定义。',
|
||||
alternatives: '未得之族 · 未触及族群 · 福音未及群体',
|
||||
rationale:
|
||||
'“未得之民”是中文宣教界长期沿用的说法,也是祷告应用里一整组标签的基础——前沿未得之民、开拓型未得之民、扩展型未得之民。英文缩写保持不变,因为中文没有稳定的对应缩写,另造一个会让国际数据无法对读。'
|
||||
},
|
||||
{
|
||||
term: '未接触',
|
||||
english: 'unengaged people group',
|
||||
definition:
|
||||
'没有已知的工作以建立能自立的教会为目标:有效接触的四个层面都不具备(驻地的开拓性事工;使用当地文化和心灵语言;长期委身;以植堂运动为目标撒下福音的种子)。这是 IMB 体系的专门用语:它说的是无人在他们中间做工,而不是这个族群冷淡。',
|
||||
alternatives: '未有宣教参与 · 尚无福音工作 · 无人问津',
|
||||
rationale:
|
||||
'“未接触/已接触”是祷告应用的状态标签,也是全部 2,085 个族群自动生成的描述所用的措辞,改动牵动的面最广。需要留意的是,其他五种语言的审核者都不肯用“接触”这一层意思的词——德语选了“在当地的宣教工作”而不是“接触”,葡萄牙语的文件明确说“参与”或“接触”会掏空这个术语。保留“未接触”是因为它已在使用,也因为中文宣教语境里它已经承载“无人在他们中间做工”的意思;中文审核者若不同意,这一整组词都要随之改动。'
|
||||
},
|
||||
{
|
||||
term: '未接触且未得之民(UUPG)',
|
||||
english: 'unengaged unreached people group (UUPG)',
|
||||
definition: '两项合起来的类别——既未接触又未得之民。这就是 DOXA 动员祷告的 2,085 个族群。',
|
||||
alternatives: '尚无福音工作的未得之族 · 另造中文缩写',
|
||||
rationale:
|
||||
'“未接触且未得之民”是祷告应用现成的复合标签,与它的姊妹标签“已接触但未得之民”成对。UUPG 是国际通行的缩写,予以保留——1040 地图的图例本来就直接写 UUPGs。'
|
||||
},
|
||||
{
|
||||
term: '接触不足',
|
||||
english: 'under-engaged people group',
|
||||
definition: '每 100 人中约有 1 位或更少的门徒(≤ 1%):工作已经开始,但要有果效的宣教参与还需要更多植堂团队。',
|
||||
alternatives: '福音工作投入不足 · 接触薄弱 · 参与不足',
|
||||
rationale:
|
||||
'与“未接触/已接触”同一组词,读起来也对称。它说的是规模不够,不是这个族群本身冷淡。目前还没有任何产品用到这个词。'
|
||||
},
|
||||
{
|
||||
term: '前沿族群',
|
||||
english: 'frontier people group',
|
||||
definition:
|
||||
'每 1,000 人中约有 1 位或更少的门徒(≤ 0.1%),且没有确认的、持续的归向耶稣的运动——未得之民中最未得的。这个说法出自 Joshua Project。',
|
||||
alternatives: '边疆族群 · 最前线族群',
|
||||
rationale:
|
||||
'“前沿”已经用在祷告应用的 IMB 标签“前沿未得之民”上。“边疆”会读成地理上的国境,正是德语审核者否掉 Grenzvolksgruppe 的同一个理由。'
|
||||
},
|
||||
{
|
||||
term: '接触',
|
||||
english: 'engagement',
|
||||
definition:
|
||||
'持续的、驻地的跨文化事工,以传扬基督、造就门徒为内容,以能自立的教会为目标,并以合乎当地文化、贴近当地处境的方式进行。这是一个精确的术语——“参与”或“有过往来”都不算接触。',
|
||||
alternatives: '宣教参与 · 参与 · 投入',
|
||||
rationale:
|
||||
'祷告应用用“接触”作名词(接触状态、接触标准、迈向接触的关键第一步)。但在英文把 engagement 当抽象名词用的地方——有果效的宣教参与、广义宣教参与、驻地宣教工作——本版改用“宣教参与”“宣教工作”,因为“有果效的接触”“广义接触”不是能用的中文。审核者确认这一条时,也请一并确认这个分工。'
|
||||
},
|
||||
{
|
||||
term: '植堂运动(CPM)',
|
||||
english: 'church-planting movement (CPM)',
|
||||
definition: '本土教会不断建立教会的倍增:至少四条支线、各达四代属灵世代,合计超过 1,000 人。',
|
||||
alternatives: '教会倍增运动 · 建立教会运动',
|
||||
rationale:
|
||||
'“植堂”是祷告应用一贯的用词——植堂状态、分散性植堂、集中性植堂、尚无植堂工作在他们中间开展。祷告内容里的“教会倍增运动”译的是 church multiplication movement,那是另一个英文术语,不是 CPM 的另一种译法。'
|
||||
},
|
||||
{
|
||||
term: '本土教会',
|
||||
english: 'indigenous church',
|
||||
definition:
|
||||
'从族群内部兴起的教会,在五项自立原则上渐趋成熟:自传、自治、自养、自立神学、自差宣教。',
|
||||
alternatives: '原住民教会 · 本地教会 · 土著教会',
|
||||
rationale:
|
||||
'“本土”指扎根本地、自行治理,“原住民”和“土著”在中文里指特定的族裔身份,会读成另一回事——葡萄牙语审核者对 indígena 的顾虑正是如此。祷告应用的接触标准已经写“本土教会”。'
|
||||
},
|
||||
{
|
||||
term: '跨文化工人',
|
||||
english: 'cross-cultural workers',
|
||||
definition:
|
||||
'来自另一种文化、在某个族群中服事的宣教工人。“跨文化”这个限定是有意的——他们不是这个族群里的人——在某些语境中比单说“宣教士”更合适。',
|
||||
alternatives: '宣教士 · 传教士 · 跨文化宣教士',
|
||||
rationale:
|
||||
'祷告应用的三条接触标准都写“驻地的跨文化工人”。“宣教士”保留给泛指的差派语境;“传教士”在中文里常带负面的历史联想,全线不用。'
|
||||
},
|
||||
{
|
||||
term: '庄稼的主',
|
||||
english: 'Lord of the harvest',
|
||||
definition:
|
||||
'耶稣的一个圣经称号(马太福音 9:38),用在呼吁祷告、求祂差派工人到未接触族群中去的地方。',
|
||||
alternatives: '收割的主 · 禾场的主',
|
||||
rationale:
|
||||
'和合本马太福音 9:38 作“你们当求庄稼的主打发工人出去收他的庄稼”,中文祷告内容已经照此引用。农事的比喻(庄稼=已经预备好回应的人)必须保留。'
|
||||
},
|
||||
{
|
||||
term: '祷告预备道路',
|
||||
english: 'prayer prepares the way',
|
||||
definition:
|
||||
'这一信念是:在工人到达之前,代祷就已经为福音的突破预备了属灵的条件——呼应“预备主的道”。',
|
||||
alternatives: '祷告开路 · 祷告铺平道路',
|
||||
rationale:
|
||||
'和合本马太福音 3:3 作“预备主的道”,以赛亚书 40:3 作“在旷野预备耶和华的路”。词条把两者合成“道路”,与和合本的任何一处都不字字相同;这样取舍是为了让短语独立成句时读得顺,圣经的回声中文读者仍一听就能听出。'
|
||||
},
|
||||
{
|
||||
term: '心灵语言',
|
||||
english: 'heart language',
|
||||
definition:
|
||||
'一个人的第一语言——他思考和感受时所用的那一种。福音和门训必须用这种语言进行才会真正有效;它不同于官方语言或通商语言。',
|
||||
alternatives: '母语 · 本族语言',
|
||||
rationale:
|
||||
'“母语”在中文里通常只指出生时所学的语言,而这个术语要说的是情感和属灵上的归属,所以保留“心灵语言”这个更贴近原意的说法。目前还没有任何产品用到这个词,是审核者最值得复核的一条。'
|
||||
},
|
||||
{
|
||||
term: '祷告事项',
|
||||
english: 'prayer points',
|
||||
definition:
|
||||
'DOXA 每天发给代祷者、针对具体族群的祷告内容——以圣经为中心,与工场实况相连,不同于一般的灵修材料。',
|
||||
alternatives: '祷告要点 · 祷告提示 · 祷告指引',
|
||||
rationale:
|
||||
'同一个中文文件里本来并存着四种说法,“祷告事项”出现得最多,现已统一。“每日祷告指南”保留给整份指南(daily prayer guide),与其中的单条祷告事项区分开。'
|
||||
},
|
||||
{
|
||||
term: '认领',
|
||||
english: 'adopt (a people group)',
|
||||
definition:
|
||||
'由教会带领的长期承诺——祷告、奉献并差派,使某一个未接触族群开始有福音可及性。这是宣教上的承担,不是家事法上的收养。',
|
||||
alternatives: '领养 · 收养 · 认养',
|
||||
rationale:
|
||||
'“认领”说的是主动承担责任,正是这个词要表达的意思。“领养”和“收养”在中文里专指收养儿女,会把整件事读成家庭关系。祷告应用、1040 地图和认领证书都已统一用“认领”。'
|
||||
},
|
||||
{
|
||||
term: '我们献给耶稣的礼物',
|
||||
english: 'our gift to Jesus',
|
||||
definition: '整件事的定位:到2033年接触每一个族群,作为教会共同献上的敬拜——是献祭式的,不是交易式的。',
|
||||
alternatives: '我们给耶稣的礼物 · 献给耶稣的供物',
|
||||
rationale:
|
||||
'“献给”带出献祭和敬拜的语气,单说“给”则显得像交易,这正是葡萄牙语审核者从 dádiva 改到 oferta 时所把握的分别。'
|
||||
},
|
||||
{
|
||||
term: '世界神召会团契(WAGF)',
|
||||
english: 'World Assemblies of God Fellowship (WAGF)',
|
||||
definition: '创立并托管 DOXA 的全球团契。',
|
||||
alternatives: '世界神召会联会 · 全球神召会团契',
|
||||
rationale:
|
||||
'“神召会”是 Assemblies of God 在中文里的既定名称。英文缩写 WAGF 在各语言版本中一律保持不变。'
|
||||
},
|
||||
{
|
||||
term: '差派机构',
|
||||
english: 'sending agencies',
|
||||
definition:
|
||||
'招募、培训、支持并差派宣教士的机构。DOXA 与差派机构合作(截至2026年有 129 个隶属 WAGF 的机构),但不取代它们。',
|
||||
alternatives: '宣教机构 · 差会',
|
||||
rationale:
|
||||
'“差派”与认领证书的第三根支柱(祷告、奉献、差派)用同一个词,使这一组词彼此呼应。“差会”是中文里的传统说法,但没有点出“差派”这个动作。'
|
||||
},
|
||||
{
|
||||
term: '每日祷告',
|
||||
english: 'daily prayer (for a people group)',
|
||||
definition:
|
||||
'承诺每天为某一个未接触族群祷告,使用每日祷告指南。目标是每个族群有 100 位以上的每日代祷者。',
|
||||
alternatives: '日常祷告 · 定期祷告',
|
||||
rationale:
|
||||
'“每日”是有意的——是每一天的承诺,不是经常或偶尔祷告。祷告应用的每日祷告内容、每日祷告提醒、每日祷告更新都用这个词。'
|
||||
},
|
||||
{
|
||||
term: '各族、各方、各民、各国',
|
||||
english: 'every tribe, tongue, people, and nation',
|
||||
definition:
|
||||
'启示录 5:9 和 7:9 的异象,是这项使命的动力。四个名词各自指向人类多样性的一个面向。',
|
||||
alternatives: '各支派、各方言、各民族、各邦国 · 万族万民',
|
||||
rationale:
|
||||
'和合本启示录 5:9 作“从各族、各方、各民、各国中买了人来”,这是应用为中文取用经文的版本。和合本在启示录 7:9 里四个名词的次序不同,作“从各国、各族、各民、各方来的”;本版一律采用 5:9 的次序,使全站只有一个固定说法,这一点与和合本的 7:9 并不一致,留待审核者定夺。此前草稿里的“各支派、各方言、各民族、各邦国”不属于任何一个中文译本。'
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
@ -4,9 +4,8 @@
|
|||
// .stack, etc.) get flattened into plain paragraphs when parsed. This
|
||||
// extension keeps the wrappers intact so the ported SCSS can style them.
|
||||
//
|
||||
// Shared by the editor (app/components/admin/RichTextEditor.vue), the
|
||||
// server renderer (server/utils/renderTiptap.ts), and the scrape-time
|
||||
// HTML→JSON converter (scripts/lib/htmlToTiptap.ts).
|
||||
// Shared by the editor (app/components/admin/RichTextEditor.vue) and the
|
||||
// server renderer (server/utils/renderTiptap.ts).
|
||||
|
||||
import { Node } from '@tiptap/core'
|
||||
|
||||
|
|
@ -36,7 +35,7 @@ export const Div = Node.create({
|
|||
const attrs: Record<string, { default: string | null }> = {
|
||||
class: { default: null },
|
||||
// Only preserved when the div is a `.wp-block-spacer` whose whole
|
||||
// purpose is an inline height; see scripts/lib/htmlToTiptap.ts.
|
||||
// purpose is an inline height.
|
||||
style: { default: null }
|
||||
}
|
||||
for (const name of PRESERVED_DATA_ATTRS) attrs[name] = { default: null }
|
||||
|
|
|
|||
|
|
@ -8,9 +8,8 @@
|
|||
// place (preserving the host app's i18n / runtime-config context via
|
||||
// h() + render()).
|
||||
//
|
||||
// Shared between editor (app/components/admin/RichTextEditor.vue),
|
||||
// server renderer (server/utils/renderTiptap.ts), and migration
|
||||
// converter (scripts/lib/htmlToTiptap.ts) via tiptapExtensions.ts.
|
||||
// Shared between editor (app/components/admin/RichTextEditor.vue) and
|
||||
// server renderer (server/utils/renderTiptap.ts) via tiptapExtensions.ts.
|
||||
|
||||
import { Node } from '@tiptap/core'
|
||||
|
||||
|
|
|
|||
|
|
@ -12,9 +12,8 @@
|
|||
// (preserving the host app's i18n / runtime-config context via `h()`
|
||||
// + `render()`).
|
||||
//
|
||||
// Keep this file shared between editor (app/components/admin/RichTextEditor.vue),
|
||||
// server renderer (server/utils/renderTiptap.ts), and scraper
|
||||
// (scripts/lib/htmlToTiptap.ts).
|
||||
// Keep this file shared between editor (app/components/admin/RichTextEditor.vue)
|
||||
// and server renderer (server/utils/renderTiptap.ts).
|
||||
|
||||
import { Node } from '@tiptap/core'
|
||||
|
||||
|
|
|
|||
|
|
@ -11,3 +11,10 @@ const VIDEO_URLS: Record<string, string> = {
|
|||
export function getVideoUrl(langCode: string): string {
|
||||
return VIDEO_URLS[langCode] ?? VIDEO_URLS.en!
|
||||
}
|
||||
|
||||
// The languages the video actually exists in, derived from VIDEO_URLS so that
|
||||
// adding a translation is one edit rather than two. Callers use this for the
|
||||
// "In English" hint, since getVideoUrl falls back silently.
|
||||
export function hasVideoTranslation(langCode: string): boolean {
|
||||
return Object.hasOwn(VIDEO_URLS, langCode)
|
||||
}
|
||||
|
|
|
|||
23
bun.lock
23
bun.lock
|
|
@ -31,6 +31,7 @@
|
|||
"bcrypt": "^6.0.0",
|
||||
"fuse.js": "^7.3.0",
|
||||
"intl-tel-input": "^26.7.5",
|
||||
"jiti": "^2.7.0",
|
||||
"jsdom": "^29.1.0",
|
||||
"jsonwebtoken": "^9.0.2",
|
||||
"kysely": "^0.28.0",
|
||||
|
|
@ -38,7 +39,6 @@
|
|||
"mapbox-gl": "^3.22.0",
|
||||
"markdown-it": "^14.1.1",
|
||||
"nodemailer": "^7.0.6",
|
||||
"nodemailer-mailgun-transport": "^2.1.5",
|
||||
"nuxt": "^4.4.2",
|
||||
"postgres": "^3.4.7",
|
||||
"tailwindcss": "^4.2.2",
|
||||
|
|
@ -54,7 +54,6 @@
|
|||
"@types/jsonwebtoken": "^9.0.10",
|
||||
"@types/markdown-it": "^14.1.2",
|
||||
"@types/nodemailer": "^7.0.1",
|
||||
"@types/nodemailer-mailgun-transport": "^1.4.6",
|
||||
"@types/turndown": "^5.0.6",
|
||||
"eslint": "^10.2.0",
|
||||
"sass": "^1.99.0",
|
||||
|
|
@ -892,8 +891,6 @@
|
|||
|
||||
"@types/nodemailer": ["@types/nodemailer@7.0.11", "", { "dependencies": { "@types/node": "*" } }, "sha512-E+U4RzR2dKrx+u3N4DlsmLaDC6mMZOM/TPROxA0UAPiTgI0y4CEFBmZE+coGWTjakDriRsXG368lNk1u9Q0a2g=="],
|
||||
|
||||
"@types/nodemailer-mailgun-transport": ["@types/nodemailer-mailgun-transport@1.4.6", "", { "dependencies": { "@types/nodemailer": "*" } }, "sha512-6qhtDo+1ZLtrmmpQN7O9e3NLK5ggnTS2Oca+22SvmhwChNKxDZErecTlF6qTOLnNW/CCcHmDaSmG2MXUeP1w9g=="],
|
||||
|
||||
"@types/pbf": ["@types/pbf@3.0.5", "", {}, "sha512-j3pOPiEcWZ34R6a6mN07mUkM4o4Lwf6hPNt8eilOeZhTFbxFXmKhvXl9Y28jotFPaI1bpPDJsbCprUoNke6OrA=="],
|
||||
|
||||
"@types/resolve": ["@types/resolve@1.20.2", "", {}, "sha512-60BCwRFOZCQhDncwQdxxeOEEkbc5dIMccYLwbxsS4TUNeVECQ/pBJ0j09mrHOl/JJvpRPGwO9SvE4nR2Nb/a4Q=="],
|
||||
|
|
@ -1004,7 +1001,7 @@
|
|||
|
||||
"@vue/compiler-ssr": ["@vue/compiler-ssr@3.5.34", "", { "dependencies": { "@vue/compiler-dom": "3.5.34", "@vue/shared": "3.5.34" } }, "sha512-cDtTHKibkThKGHH1SP+WdccquNRYQDFH6rRjQCqT9G2ltFAfoR5pUftpab/z+aM5mW9HLLVQW7hfKKQe/1GBeQ=="],
|
||||
|
||||
"@vue/devtools-api": ["@vue/devtools-api@6.6.4", "", {}, "sha512-sGhTPMuXqZ1rVOk32RylztWkfXTRhuS7vgAKv0zjqk8gbsHkJ7xfFf+jbySxt7tWObEJwyKaHMikV/WGDiQm8g=="],
|
||||
"@vue/devtools-api": ["@vue/devtools-api@8.1.2", "", { "dependencies": { "@vue/devtools-kit": "^8.1.2" } }, "sha512-vA0O112YqyDuNA1s7Yb2gCgToQ/OxOWiFDO5ThLCcDy0ldHnSd1dUTaSYhOldbqoNgumE4dxtGAoAaSUKUD1Zg=="],
|
||||
|
||||
"@vue/devtools-core": ["@vue/devtools-core@8.1.2", "", { "dependencies": { "@vue/devtools-kit": "^8.1.2", "@vue/devtools-shared": "^8.1.2" }, "peerDependencies": { "vue": "^3.0.0" } }, "sha512-ZGGyaSBP4/+bN2Nd9ZHNYAVDRIzMw1rv2RyXWtyZlo6mQal+IDmTvKY4V+DjAEBhaXt30mHmsgYp1yXJ/2tIWg=="],
|
||||
|
||||
|
|
@ -1100,8 +1097,6 @@
|
|||
|
||||
"bare-url": ["bare-url@2.4.3", "", { "dependencies": { "bare-path": "^3.0.0" } }, "sha512-Kccpc7ACfXaxfeInfqKcZtW4pT5YBn1mesc4sCsun6sRwtbJ4h+sNOaksUpYEJUKfN65YWC6Bw2OJEFiKxq8nQ=="],
|
||||
|
||||
"base-64": ["base-64@1.0.0", "", {}, "sha512-kwDPIFCGx0NZHog36dj+tHiwP4QMzsZ3AgMViUBKI0+V5n4U0ufTCUMhnQ04diaRI8EX/QcPfql7zlhZ7j4zgg=="],
|
||||
|
||||
"base64-js": ["base64-js@1.5.1", "", {}, "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA=="],
|
||||
|
||||
"baseline-browser-mapping": ["baseline-browser-mapping@2.10.31", "", { "bin": { "baseline-browser-mapping": "dist/cli.cjs" } }, "sha512-MujYO3eP72uvmSE0i4wltsodRfIpZATP3jvzRNRGGxgzId7aVocVJJV3nf01qnzzKFGxQVC9bpWxl5cjxTr/7Q=="],
|
||||
|
|
@ -1114,8 +1109,6 @@
|
|||
|
||||
"birpc": ["birpc@4.0.0", "", {}, "sha512-LShSxJP0KTmd101b6DRyGBj57LZxSDYWKitQNW/mi8GRMvZb078Uf9+pveax1DrVL89vm7mWe+TovdI/UDOuPw=="],
|
||||
|
||||
"bluebird": ["bluebird@3.7.2", "", {}, "sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg=="],
|
||||
|
||||
"body-parser": ["body-parser@2.2.2", "", { "dependencies": { "bytes": "^3.1.2", "content-type": "^1.0.5", "debug": "^4.4.3", "http-errors": "^2.0.0", "iconv-lite": "^0.7.0", "on-finished": "^2.4.1", "qs": "^6.14.1", "raw-body": "^3.0.1", "type-is": "^2.0.1" } }, "sha512-oP5VkATKlNwcgvxi0vM0p/D3n2C3EReYVX+DNYs5TjZFn/oQt2j+4sVJtSMr18pdRr8wjTcBl6LoV+FUwzPmNA=="],
|
||||
|
||||
"boolbase": ["boolbase@1.0.0", "", {}, "sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww=="],
|
||||
|
|
@ -1196,8 +1189,6 @@
|
|||
|
||||
"consola": ["consola@3.4.2", "", {}, "sha512-5IKcdX0nnYavi6G7TtOhwkYzyjfJlatbjMjuLSfE2kYT5pMDOilZ4OvMhi637CcDICTmz3wARPoyhqyX1Y+XvA=="],
|
||||
|
||||
"consolidate": ["consolidate@0.15.1", "", { "dependencies": { "bluebird": "^3.1.1" } }, "sha512-DW46nrsMJgy9kqAbPt5rKaCr7uFtpo4mSUvLHIUbJEjm0vo+aY5QLwBUq3FK4tRnJr/X0Psc0C4jf/h+HtXSMw=="],
|
||||
|
||||
"content-disposition": ["content-disposition@1.1.0", "", {}, "sha512-5jRCH9Z/+DRP7rkvY83B+yGIGX96OYdJmzngqnw2SBSxqCFPd0w2km3s5iawpGX8krnwSGmF0FW5Nhr0Hfai3g=="],
|
||||
|
||||
"content-type": ["content-type@1.0.5", "", {}, "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA=="],
|
||||
|
|
@ -1762,8 +1753,6 @@
|
|||
|
||||
"magicast": ["magicast@0.5.3", "", { "dependencies": { "@babel/parser": "^7.29.3", "@babel/types": "^7.29.0", "source-map-js": "^1.2.1" } }, "sha512-pVKE4UdSQ7DvHzivsCIFx2BJn1mHG6KsyrFcaxFx6tONdneEuThrDx0Cj3AMg58KyN4pzYT+LHOotxDQDjNvkw=="],
|
||||
|
||||
"mailgun.js": ["mailgun.js@8.2.2", "", { "dependencies": { "axios": "^1.3.3", "base-64": "^1.0.0", "url-join": "^4.0.1" } }, "sha512-po/KtofzrTuKhHLenbmliDsVVOFANwcfDFUGnggwnyZJmZz7JgBlV6nzK9o2Fk+OK2SiBmJTK25RbkAj57Hd+Q=="],
|
||||
|
||||
"mapbox-gl": ["mapbox-gl@3.24.0", "", { "dependencies": { "@mapbox/mapbox-gl-supported": "^3.0.0", "@mapbox/point-geometry": "^1.1.0", "@mapbox/tiny-sdf": "^2.0.6", "@mapbox/unitbezier": "^0.0.1", "@mapbox/vector-tile": "^2.0.4", "@types/geojson": "^7946.0.16", "@types/geojson-vt": "^3.2.5", "@types/pbf": "^3.0.5", "@types/supercluster": "^7.1.3", "cheap-ruler": "^4.0.0", "csscolorparser": "~1.0.3", "earcut": "^3.0.1", "geojson-vt": "^4.0.2", "gl-matrix": "^3.4.4", "kdbush": "^4.0.2", "martinez-polygon-clipping": "^0.8.1", "murmurhash-js": "^1.0.0", "pbf": "^4.0.1", "potpack": "^2.0.0", "quickselect": "^3.0.0", "supercluster": "^8.0.1", "tinyqueue": "^3.0.0" } }, "sha512-R+FdFUB3DnoE5FYASV7lGSiRyMkSblcZ2UEy7b2pt7s5ZbCxFIUPXd0E6iAFd8OdvdA2VtbvZZVylzAZNaurjA=="],
|
||||
|
||||
"markdown-it": ["markdown-it@14.1.1", "", { "dependencies": { "argparse": "^2.0.1", "entities": "^4.4.0", "linkify-it": "^5.0.0", "mdurl": "^2.0.0", "punycode.js": "^2.3.1", "uc.micro": "^2.1.0" }, "bin": { "markdown-it": "bin/markdown-it.mjs" } }, "sha512-BuU2qnTti9YKgK5N+IeMubp14ZUKUUw7yeJbkjtosvHiP0AZ5c8IAgEMk79D0eC8F23r4Ac/q8cAIFdm2FtyoA=="],
|
||||
|
|
@ -1848,8 +1837,6 @@
|
|||
|
||||
"nodemailer": ["nodemailer@7.0.13", "", {}, "sha512-PNDFSJdP+KFgdsG3ZzMXCgquO7I6McjY2vlqILjtJd0hy8wEvtugS9xKRF2NWlPNGxvLCXlTNIae4serI7dinw=="],
|
||||
|
||||
"nodemailer-mailgun-transport": ["nodemailer-mailgun-transport@2.1.5", "", { "dependencies": { "consolidate": "^0.15.1", "form-data": "^4.0.0", "mailgun.js": "^8.0.1" } }, "sha512-hF7POkaxFgMvYEd5aHLaQJI2511ld+aQlQi7JH6bGjhjlZ33cIbTB9PimlIrLu5XC3z76Kde6e65OIwL9lOdTA=="],
|
||||
|
||||
"nopt": ["nopt@8.1.0", "", { "dependencies": { "abbrev": "^3.0.0" }, "bin": { "nopt": "bin/nopt.js" } }, "sha512-ieGu42u/Qsa4TFktmaKEwM6MQH0pOWnaB3htzh0JRtx84+Mebc0cbZYN5bC+6WTZ4+77xrL9Pn5m7CV6VIkV7A=="],
|
||||
|
||||
"normalize-path": ["normalize-path@3.0.0", "", {}, "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA=="],
|
||||
|
|
@ -2354,8 +2341,6 @@
|
|||
|
||||
"uri-js": ["uri-js@4.4.1", "", { "dependencies": { "punycode": "^2.1.0" } }, "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg=="],
|
||||
|
||||
"url-join": ["url-join@4.0.1", "", {}, "sha512-jk1+QP6ZJqyOiuEI9AEWQfju/nB2Pw466kbA0LEZljHwKeMgd9WrAEgEGxjPDD2+TNbbb37rTyhEfrCXfuKXnA=="],
|
||||
|
||||
"util-deprecate": ["util-deprecate@1.0.2", "", {}, "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw=="],
|
||||
|
||||
"valibot": ["valibot@1.4.0", "", { "peerDependencies": { "typescript": ">=5" }, "optionalPeers": ["typescript"] }, "sha512-iC/x7fVcSyOwlm/VSt7RlHnzNGLGvR9GnxdifUeWoCJo0q4ZZvrVkIHC6faTlkxG47I2Y4UrFquPuVHCrOnrLg=="],
|
||||
|
|
@ -2696,7 +2681,7 @@
|
|||
|
||||
"vite-plugin-inspect/open": ["open@10.2.0", "", { "dependencies": { "default-browser": "^5.2.1", "define-lazy-prop": "^3.0.0", "is-inside-container": "^1.0.0", "wsl-utils": "^0.1.0" } }, "sha512-YgBpdJHPyQ2UE5x+hlSXcnejzAvD0b22U2OuAP+8OnlJT+PjWPxtgmGqKKc+RgTM63U9gN0YzrYc71R2WT/hTA=="],
|
||||
|
||||
"vue-router/@vue/devtools-api": ["@vue/devtools-api@8.1.2", "", { "dependencies": { "@vue/devtools-kit": "^8.1.2" } }, "sha512-vA0O112YqyDuNA1s7Yb2gCgToQ/OxOWiFDO5ThLCcDy0ldHnSd1dUTaSYhOldbqoNgumE4dxtGAoAaSUKUD1Zg=="],
|
||||
"vue-i18n/@vue/devtools-api": ["@vue/devtools-api@6.6.4", "", {}, "sha512-sGhTPMuXqZ1rVOk32RylztWkfXTRhuS7vgAKv0zjqk8gbsHkJ7xfFf+jbySxt7tWObEJwyKaHMikV/WGDiQm8g=="],
|
||||
|
||||
"wrap-ansi-cjs/ansi-styles": ["ansi-styles@4.3.0", "", { "dependencies": { "color-convert": "^2.0.1" } }, "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg=="],
|
||||
|
||||
|
|
@ -2766,6 +2751,8 @@
|
|||
|
||||
"@intlify/vue-i18n-extensions/vue-i18n/@intlify/core-base": ["@intlify/core-base@10.0.8", "", { "dependencies": { "@intlify/message-compiler": "10.0.8", "@intlify/shared": "10.0.8" } }, "sha512-FoHslNWSoHjdUBLy35bpm9PV/0LVI/DSv9L6Km6J2ad8r/mm0VaGg06C40FqlE8u2ADcGUM60lyoU7Myo4WNZQ=="],
|
||||
|
||||
"@intlify/vue-i18n-extensions/vue-i18n/@vue/devtools-api": ["@vue/devtools-api@6.6.4", "", {}, "sha512-sGhTPMuXqZ1rVOk32RylztWkfXTRhuS7vgAKv0zjqk8gbsHkJ7xfFf+jbySxt7tWObEJwyKaHMikV/WGDiQm8g=="],
|
||||
|
||||
"@isaacs/cliui/string-width/emoji-regex": ["emoji-regex@9.2.2", "", {}, "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg=="],
|
||||
|
||||
"@mapbox/node-pre-gyp/https-proxy-agent/agent-base": ["agent-base@7.1.4", "", {}, "sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ=="],
|
||||
|
|
|
|||
119
compose.laptop.yaml
Normal file
119
compose.laptop.yaml
Normal file
|
|
@ -0,0 +1,119 @@
|
|||
# The laptop's routes with the dx-maps container, one command each (documentation/LAPTOP-6WAY.md):
|
||||
# bun run laptop subdomain profile subdomain: the services below with the sign-in
|
||||
# bun run laptop plugin-studio profile plugin-studio: the PUBLIC Plugin Studio (ACCESS=public) + this site
|
||||
# Everything listens on this computer only (127.0.0.1):
|
||||
# dx-maps the team container the server runs: Plugin Studio, PocketBase, and the research site. Built from
|
||||
# dx-maps' root Dockerfile, the same image the VPS runs.
|
||||
# issuer a local sign-in provider with three users (admin, designer, and anyone else as a plain member).
|
||||
# It shares dx-maps' network, so http://localhost:4620 means the same thing to your browser and to
|
||||
# the container: sign-in works without any hosts-file entry.
|
||||
# dxlife this site on the subdomain branch, pointed at the research site.
|
||||
# Settings and secrets come from .env.laptop (made by `bun run laptop`, never committed).
|
||||
name: dxlife-laptop
|
||||
services:
|
||||
dx-maps:
|
||||
profiles: [subdomain]
|
||||
build: ${DXMAPS_DIR:-../doxa-maps}
|
||||
image: dxlife-laptop/dx-maps:local
|
||||
environment:
|
||||
REPO_URL: ${DXMAPS_REPO_URL:-https://git.nuxtbase.app/doxa-life/doxa-maps.git}
|
||||
BRANCH: ${DXMAPS_BRANCH:-development}
|
||||
PRODUCTION_BRANCH: ${DXMAPS_PRODUCTION_BRANCH:-main}
|
||||
GIT_TOKEN: ${GIT_TOKEN:-}
|
||||
OIDC_ISSUER: http://localhost:4620/team
|
||||
OIDC_CLIENT_ID: dx-maps
|
||||
OIDC_CLIENT_SECRET: ${OIDC_CLIENT_SECRET:?run bun run laptop}
|
||||
OIDC_COOKIE_SECRET: ${OIDC_COOKIE_SECRET:?run bun run laptop}
|
||||
OIDC_REDIRECT_URL: http://localhost:4616/oauth2/callback
|
||||
OIDC_ALLOWED_GROUPS: team:designer,team:admin
|
||||
OIDC_ADMIN_GROUPS: team:admin
|
||||
OIDC_DISPLAY_NAME: the laptop's test sign-in
|
||||
PB_OIDC_CLIENT_ID: dx-maps-pb
|
||||
PB_OIDC_CLIENT_SECRET: ${PB_OIDC_CLIENT_SECRET:?run bun run laptop}
|
||||
PB_SUPERUSER_EMAIL: ${PB_SUPERUSER_EMAIL:?run bun run laptop}
|
||||
PB_SUPERUSER_PASSWORD: ${PB_SUPERUSER_PASSWORD:?run bun run laptop}
|
||||
SUBDOMAIN_APPS: research.localhost=doxa-maps-spa/doxa-maps-spa
|
||||
SUBDOMAIN_PORT: "4615"
|
||||
EMBED_BASE_URL: http://research.localhost:4615
|
||||
PUBLIC_API_BASE: http://localhost:4616/api-prod
|
||||
HMR_CLIENT_PORT: "4616"
|
||||
HMR_PROTOCOL: ws
|
||||
CDN_AUTOBUILD_MINUTES: "1"
|
||||
ports:
|
||||
- 127.0.0.1:4616:5173 # Plugin Studio, PocketBase (/pb), /cdn, /admin: http://localhost:4616/
|
||||
- 127.0.0.1:4615:4615 # the research site: http://research.localhost:4615/
|
||||
- 127.0.0.1:4620:4620 # the sign-in provider, which runs in this container's network
|
||||
volumes:
|
||||
- dx-data:/data
|
||||
mem_limit: 2560m
|
||||
issuer:
|
||||
profiles: [subdomain]
|
||||
image: ghcr.io/navikt/mock-oauth2-server:6.0.3
|
||||
network_mode: service:dx-maps
|
||||
environment:
|
||||
SERVER_PORT: "4620"
|
||||
JSON_CONFIG: '{"interactiveLogin":true,"tokenCallbacks":[{"issuerId":"team","requestMappings":[{"requestParam":"subject","match":"admin","claims":{"groups":["team","team:admin"],"email":"admin@team.localhost","email_verified":true,"preferred_username":"admin"}},{"requestParam":"subject","match":"designer","claims":{"groups":["team","team:designer"],"email":"designer@team.localhost","email_verified":true,"preferred_username":"designer"}},{"requestParam":"subject","match":".*","claims":{"groups":["team"],"email":"$${subject}@team.localhost","email_verified":true,"preferred_username":"$${subject}"}}]}]}'
|
||||
mem_limit: 384m
|
||||
dxlife:
|
||||
profiles: [subdomain]
|
||||
build: ${DXMAPS_DIR:-../doxa-maps}
|
||||
image: dxlife-laptop/dx-maps:local
|
||||
entrypoint: ["bash", "/laptop-dxlife.sh"]
|
||||
environment:
|
||||
DXLIFE_REPO_URL: ${DXLIFE_REPO_URL:-https://git.nuxtbase.app/doxa-life/doxa-maps-cdn.git}
|
||||
DXLIFE_BRANCH: ${DXLIFE_BRANCH:-research-gallery-subdomain}
|
||||
GIT_TOKEN: ${GIT_TOKEN:-}
|
||||
NUXT_PUBLIC_DX_MAPS_BASE: http://research.localhost:4615/dx-maps
|
||||
NUXT_PUBLIC_RESEARCH_GALLERY_URL: http://research.localhost:4615/
|
||||
volumes:
|
||||
- ./scripts/laptop-dxlife.sh:/laptop-dxlife.sh:ro
|
||||
ports:
|
||||
- 127.0.0.1:4613:4613 # this site: http://localhost:4613/
|
||||
mem_limit: 2048m
|
||||
# The PLUGIN-STUDIO route: the research subdomain IS the public Plugin Studio. No sign-in provider: the Studio
|
||||
# and the maps are open, and /admin/ (publishing) and PocketBase's dashboard ask for ADMIN_USER/ADMIN_PASSWORD.
|
||||
# This site embeds production maps from the Studio's /cdn, built from main. Both addresses reach it at run time.
|
||||
dx-maps-studio:
|
||||
profiles: [plugin-studio]
|
||||
build: ${DXMAPS_DIR:-../doxa-maps}
|
||||
image: dxlife-laptop/dx-maps:local
|
||||
environment:
|
||||
REPO_URL: ${DXMAPS_REPO_URL:-https://git.nuxtbase.app/doxa-life/doxa-maps.git}
|
||||
BRANCH: ${DXMAPS_BRANCH:-development}
|
||||
PRODUCTION_BRANCH: ${DXMAPS_PRODUCTION_BRANCH:-main}
|
||||
GIT_TOKEN: ${GIT_TOKEN:-}
|
||||
ACCESS: public
|
||||
ADMIN_USER: admin
|
||||
ADMIN_PASSWORD: ${ADMIN_PASSWORD:?run bun run laptop}
|
||||
PB_SUPERUSER_EMAIL: ${PB_SUPERUSER_EMAIL:?run bun run laptop}
|
||||
PB_SUPERUSER_PASSWORD: ${PB_SUPERUSER_PASSWORD:?run bun run laptop}
|
||||
EMBED_BASE_URL: http://research.localhost:4616/cdn
|
||||
PUBLIC_API_BASE: http://research.localhost:4616/api-prod
|
||||
HMR_CLIENT_PORT: "4616"
|
||||
HMR_PROTOCOL: ws
|
||||
CDN_AUTOBUILD_MINUTES: "1"
|
||||
ports:
|
||||
- 127.0.0.1:4616:5173 # the public Plugin Studio and its /cdn: http://research.localhost:4616/
|
||||
volumes:
|
||||
- dx-data-studio:/data
|
||||
mem_limit: 2560m
|
||||
dxlife-studio:
|
||||
profiles: [plugin-studio]
|
||||
build: ${DXMAPS_DIR:-../doxa-maps}
|
||||
image: dxlife-laptop/dx-maps:local
|
||||
entrypoint: ["bash", "/laptop-dxlife.sh"]
|
||||
environment:
|
||||
DXLIFE_REPO_URL: ${DXLIFE_REPO_URL:-https://git.nuxtbase.app/doxa-life/doxa-maps-cdn.git}
|
||||
DXLIFE_BRANCH: ${DXLIFE_STUDIO_BRANCH:-research-gallery-plugin-studio}
|
||||
DXLIFE_PORT: "4614"
|
||||
GIT_TOKEN: ${GIT_TOKEN:-}
|
||||
NUXT_PUBLIC_RESEARCH_GALLERY_URL: http://research.localhost:4616/
|
||||
NUXT_PUBLIC_DX_MAPS_BASE: http://research.localhost:4616/cdn/dx-maps
|
||||
volumes:
|
||||
- ./scripts/laptop-dxlife.sh:/laptop-dxlife.sh:ro
|
||||
ports:
|
||||
- 127.0.0.1:4614:4614 # this site, plugin-studio branch: http://localhost:4614/
|
||||
mem_limit: 2048m
|
||||
volumes:
|
||||
dx-data:
|
||||
dx-data-studio:
|
||||
|
|
@ -1,882 +0,0 @@
|
|||
// Generated by scripts/build-glossaries.ts from ../translation/deepl-glossaries/*.tsv
|
||||
// Do not edit by hand — update the TSVs in the translation repo and re-run:
|
||||
// bun scripts/build-glossaries.ts
|
||||
|
||||
/** English → target-language term pairs, keyed by language code. */
|
||||
export const GLOSSARIES: Record<string, ReadonlyArray<readonly [string, string]>> = {
|
||||
ar: [
|
||||
["people group", "جماعة عرقية"],
|
||||
["people groups", "جماعات عرقية"],
|
||||
["unreached people group", "جماعة عرقية غير مُبلَّغة"],
|
||||
["unreached people groups", "جماعات عرقية غير مُبلَّغة"],
|
||||
["unengaged people group", "جماعة عرقية غير مُنخرَطة"],
|
||||
["unengaged people groups", "جماعات عرقية غير مُنخرَطة"],
|
||||
["unengaged unreached people group", "جماعة عرقية غير مُبلَّغة وغير مُنخرَطة"],
|
||||
["under-engaged", "ناقصة الانخراط"],
|
||||
["frontier people group", "جماعة عرقية حدودية"],
|
||||
["frontier people groups", "جماعات عرقية حدودية"],
|
||||
["ethnolinguistic group", "جماعة إثنولغوية"],
|
||||
["unreached", "غير مُبلَّغ"],
|
||||
["unengaged", "غير مُنخرَط"],
|
||||
["engaged", "مُنخرَط"],
|
||||
["engagement", "انخراط"],
|
||||
["fruitful engagement", "انخراط مثمر"],
|
||||
["gospel access", "الوصول إلى الإنجيل"],
|
||||
["gospel engagement", "الانخراط بالإنجيل"],
|
||||
["the gospel", "الإنجيل"],
|
||||
["church-planting movement", "حركة تأسيس كنائس"],
|
||||
["church planting", "تأسيس كنائس"],
|
||||
["indigenous church", "كنيسة محلّية"],
|
||||
["indigenous churches", "كنائس محلّية"],
|
||||
["self-propagating", "ذاتي الانتشار"],
|
||||
["self-governing", "ذاتي الحكم"],
|
||||
["self-supporting", "ذاتي التمويل"],
|
||||
["self-theologizing", "ذاتي اللاهوت"],
|
||||
["self-missionizing", "ذاتي الإرسال"],
|
||||
["residential engagement", "انخراط إقامي"],
|
||||
["workers in residence", "عاملون مقيمون"],
|
||||
["cross-cultural workers", "عاملون عابرون للثقافات"],
|
||||
["apostolic effort", "جهد رسولي"],
|
||||
["pioneer work", "عمل ريادي"],
|
||||
["heart language", "اللغة الأم"],
|
||||
["movement to Jesus", "حركة نحو يسوع"],
|
||||
["nonresident partners", "شركاء غير مقيمين"],
|
||||
["broader engagement", "انخراط أوسع"],
|
||||
["diaspora", "شتات"],
|
||||
["daily prayer", "صلاة يومية"],
|
||||
["24-hour prayer coverage", "تغطية صلاة على مدار 24 ساعة"],
|
||||
["intercessor", "شفيع"],
|
||||
["intercessors", "شفعاء"],
|
||||
["intercessory prayer", "صلاة شفاعية"],
|
||||
["prayer points", "نقاط صلاة"],
|
||||
["daily prayer guide", "دليل الصلاة اليومي"],
|
||||
["prayer prepares the way", "الصلاة تُمهِّد الطريق"],
|
||||
["Lord of the harvest", "ربّ الحصاد"],
|
||||
["adopt", "تبنّي"],
|
||||
["pray, give, and send", "صلّوا وقدِّموا وأرسِلوا"],
|
||||
["mobilize", "تعبئة"],
|
||||
["mobilization", "تعبئة"],
|
||||
["sending agency", "وكالة إرسال"],
|
||||
["sending agencies", "وكالات إرسال"],
|
||||
["our gift to Jesus", "تقدمتنا ليسوع"],
|
||||
["DOXA partnership missionaries", "مُرسَلون شركاء في DOXA"],
|
||||
["every tribe, tongue, people, and nation", "كلّ قبيلة ولسان وشعب وأمّة"],
|
||||
["make disciples of all the nations", "تلمِذوا جميع الأمم"],
|
||||
["disciple", "تلميذ"],
|
||||
["disciples", "تلاميذ"],
|
||||
["baptized disciples", "تلاميذ مُعمَّدون"],
|
||||
["culturally appropriate", "ملائم ثقافيًّا"],
|
||||
["self-sustaining churches", "كنائس مكتفية ذاتيًّا"],
|
||||
["spiritual generations", "أجيال روحية"],
|
||||
["abide in Jesus", "اثبُتوا في يسوع"],
|
||||
["pray without ceasing", "صلّوا بلا انقطاع"],
|
||||
["deny yourself", "أنكِروا أنفسكم"],
|
||||
["engage the regions beyond", "ابلُغوا المناطق الأبعد"],
|
||||
["Pentecostal", "خمسيني"],
|
||||
["Statement of Faith", "بيان الإيمان"],
|
||||
["new birth", "الولادة الجديدة"],
|
||||
["regeneration", "التجديد"],
|
||||
["justification", "التبرير"],
|
||||
["atonement", "الكفّارة"],
|
||||
["sanctification", "التقديس"],
|
||||
["baptism in water", "المعمودية بالماء"],
|
||||
["Lord's Supper", "العشاء الربّاني"],
|
||||
["baptism in the Holy Spirit", "المعمودية بالروح القدس"],
|
||||
["speaking in tongues", "التكلّم بألسنة"],
|
||||
["gifts of the Holy Spirit", "مواهب الروح القدس"],
|
||||
["pre-millennial return", "الرجوع قبل الألفية"],
|
||||
["bodily resurrection", "القيامة الجسدية"],
|
||||
["pray", "صلّوا"],
|
||||
["engage", "انخرِطوا"],
|
||||
["choose a people group", "اختاروا جماعة عرقية"],
|
||||
["sign up", "التسجيل"]
|
||||
],
|
||||
de: [
|
||||
["people group", "Volksgruppe"],
|
||||
["people groups", "Volksgruppen"],
|
||||
["unreached people group", "unerreichte Volksgruppe"],
|
||||
["unreached people groups", "unerreichte Volksgruppen"],
|
||||
["unengaged people group", "nicht-engagierte Volksgruppe"],
|
||||
["unengaged people groups", "nicht-engagierte Volksgruppen"],
|
||||
["unengaged unreached people group", "unerreichte und nicht-engagierte Volksgruppe"],
|
||||
["under-engaged", "unterengagiert"],
|
||||
["frontier people group", "Frontier-Volksgruppe"],
|
||||
["frontier people groups", "Frontier-Volksgruppen"],
|
||||
["ethnolinguistic group", "ethnolinguistische Gruppe"],
|
||||
["unreached", "unerreicht"],
|
||||
["unengaged", "nicht-engagiert"],
|
||||
["engaged", "engagiert"],
|
||||
["engagement", "Engagement"],
|
||||
["fruitful engagement", "fruchtbares Engagement"],
|
||||
["gospel access", "Zugang zum Evangelium"],
|
||||
["gospel engagement", "Engagement für das Evangelium"],
|
||||
["the gospel", "das Evangelium"],
|
||||
["church-planting movement", "Gemeindegründungsbewegung"],
|
||||
["church planting", "Gemeindegründung"],
|
||||
["indigenous church", "einheimische Gemeinde"],
|
||||
["indigenous churches", "einheimische Gemeinden"],
|
||||
["self-propagating", "sich selbst ausbreitend"],
|
||||
["self-governing", "selbstverwaltend"],
|
||||
["self-supporting", "sich selbst finanzierend"],
|
||||
["self-theologizing", "selbsttheologisierend"],
|
||||
["self-missionizing", "selbstmissionierend"],
|
||||
["residential engagement", "Engagement vor Ort"],
|
||||
["workers in residence", "Mitarbeiter vor Ort"],
|
||||
["cross-cultural workers", "interkulturelle Mitarbeiter"],
|
||||
["apostolic effort", "apostolischer Einsatz"],
|
||||
["pioneer work", "Pionierarbeit"],
|
||||
["heart language", "Muttersprache"],
|
||||
["movement to Jesus", "Bewegung zu Jesus"],
|
||||
["nonresident partners", "nicht-residente Partner"],
|
||||
["broader engagement", "erweitertes Engagement"],
|
||||
["diaspora", "Diaspora"],
|
||||
["daily prayer", "tägliches Gebet"],
|
||||
["24-hour prayer coverage", "24-Stunden-Gebetsabdeckung"],
|
||||
["intercessor", "Fürbitter"],
|
||||
["intercessors", "Fürbitter"],
|
||||
["intercessory prayer", "Fürbitte"],
|
||||
["prayer points", "Gebetsanliegen"],
|
||||
["daily prayer guide", "täglicher Gebetsleitfaden"],
|
||||
["prayer prepares the way", "Gebet bereitet den Weg"],
|
||||
["Lord of the harvest", "Herr der Ernte"],
|
||||
["adopt", "adoptieren"],
|
||||
["pray, give, and send", "beten, geben und senden"],
|
||||
["mobilize", "mobilisieren"],
|
||||
["mobilization", "Mobilisierung"],
|
||||
["sending agency", "Entsendeorganisation"],
|
||||
["sending agencies", "Entsendeorganisationen"],
|
||||
["our gift to Jesus", "unsere Gabe an Jesus"],
|
||||
["DOXA partnership missionaries", "DOXA-Partnerschaftsmissionare"],
|
||||
["every tribe, tongue, people, and nation", "jeder Stamm, jede Sprache, jedes Volk und jede Nation"],
|
||||
["make disciples of all the nations", "macht zu Jüngern alle Völker"],
|
||||
["disciple", "Jünger"],
|
||||
["disciples", "Jünger"],
|
||||
["baptized disciples", "getaufte Jünger"],
|
||||
["culturally appropriate", "kulturell angemessen"],
|
||||
["self-sustaining churches", "eigenständige Gemeinden"],
|
||||
["spiritual generations", "geistliche Generationen"],
|
||||
["abide in Jesus", "bleibt in Jesus"],
|
||||
["pray without ceasing", "betet ohne Unterlass"],
|
||||
["deny yourself", "verleugnet euch selbst"],
|
||||
["engage the regions beyond", "erreicht die Gebiete darüber hinaus"],
|
||||
["Pentecostal", "pfingstlich"],
|
||||
["Statement of Faith", "Glaubensbekenntnis"],
|
||||
["new birth", "Wiedergeburt"],
|
||||
["regeneration", "Erneuerung"],
|
||||
["justification", "Rechtfertigung"],
|
||||
["atonement", "Sühne"],
|
||||
["sanctification", "Heiligung"],
|
||||
["baptism in water", "Wassertaufe"],
|
||||
["Lord's Supper", "Abendmahl"],
|
||||
["baptism in the Holy Spirit", "Taufe im Heiligen Geist"],
|
||||
["speaking in tongues", "Zungenreden"],
|
||||
["gifts of the Holy Spirit", "Gaben des Heiligen Geistes"],
|
||||
["pre-millennial return", "prämillenniale Wiederkunft"],
|
||||
["bodily resurrection", "leibliche Auferstehung"],
|
||||
["pray", "beten"],
|
||||
["engage", "engagieren"],
|
||||
["choose a people group", "eine Volksgruppe wählen"],
|
||||
["sign up", "anmelden"]
|
||||
],
|
||||
es: [
|
||||
["people group", "grupo étnico"],
|
||||
["people groups", "grupos étnicos"],
|
||||
["unreached people group", "grupo étnico no alcanzado"],
|
||||
["unreached people groups", "grupos étnicos no alcanzados"],
|
||||
["unengaged people group", "grupo étnico no comprometido"],
|
||||
["unengaged people groups", "grupos étnicos no comprometidos"],
|
||||
["unengaged unreached people group", "grupo étnico no alcanzado y no comprometido"],
|
||||
["under-engaged", "subcomprometido"],
|
||||
["frontier people group", "grupo étnico frontera"],
|
||||
["frontier people groups", "grupos étnicos frontera"],
|
||||
["ethnolinguistic group", "grupo etnolingüístico"],
|
||||
["unreached", "no alcanzado"],
|
||||
["unengaged", "no comprometido"],
|
||||
["engaged", "comprometido"],
|
||||
["engagement", "compromiso"],
|
||||
["fruitful engagement", "compromiso fructífero"],
|
||||
["gospel access", "acceso al Evangelio"],
|
||||
["gospel engagement", "compromiso con el Evangelio"],
|
||||
["the gospel", "el Evangelio"],
|
||||
["church-planting movement", "movimiento de plantación de iglesias"],
|
||||
["church planting", "plantación de iglesias"],
|
||||
["indigenous church", "iglesia autóctona"],
|
||||
["indigenous churches", "iglesias autóctonas"],
|
||||
["self-propagating", "autopropagador"],
|
||||
["self-governing", "autogobernado"],
|
||||
["self-supporting", "autofinanciado"],
|
||||
["self-theologizing", "autoteologizante"],
|
||||
["self-missionizing", "automisionero"],
|
||||
["residential engagement", "compromiso residencial"],
|
||||
["workers in residence", "obreros residentes"],
|
||||
["cross-cultural workers", "obreros transculturales"],
|
||||
["apostolic effort", "esfuerzo apostólico"],
|
||||
["pioneer work", "trabajo pionero"],
|
||||
["heart language", "lengua materna"],
|
||||
["movement to Jesus", "movimiento hacia Jesús"],
|
||||
["nonresident partners", "socios no residentes"],
|
||||
["broader engagement", "compromiso ampliado"],
|
||||
["diaspora", "diáspora"],
|
||||
["daily prayer", "oración diaria"],
|
||||
["24-hour prayer coverage", "cobertura de oración de 24 horas"],
|
||||
["intercessor", "intercesor"],
|
||||
["intercessors", "intercesores"],
|
||||
["intercessory prayer", "oración de intercesión"],
|
||||
["prayer points", "motivos de oración"],
|
||||
["daily prayer guide", "guía de oración diaria"],
|
||||
["prayer prepares the way", "la oración prepara el camino"],
|
||||
["Lord of the harvest", "Señor de la cosecha"],
|
||||
["adopt", "adoptar"],
|
||||
["pray, give, and send", "orar, dar y enviar"],
|
||||
["mobilize", "movilizar"],
|
||||
["mobilization", "movilización"],
|
||||
["sending agency", "agencia de envío"],
|
||||
["sending agencies", "agencias de envío"],
|
||||
["our gift to Jesus", "nuestra ofrenda a Jesús"],
|
||||
["DOXA partnership missionaries", "misioneros asociados de DOXA"],
|
||||
["every tribe, tongue, people, and nation", "toda tribu, lengua, pueblo y nación"],
|
||||
["make disciples of all the nations", "hagan discípulos de todas las naciones"],
|
||||
["disciple", "discípulo"],
|
||||
["disciples", "discípulos"],
|
||||
["baptized disciples", "discípulos bautizados"],
|
||||
["culturally appropriate", "culturalmente apropiado"],
|
||||
["self-sustaining churches", "iglesias autosostenibles"],
|
||||
["spiritual generations", "generaciones espirituales"],
|
||||
["abide in Jesus", "permanezcan en Jesús"],
|
||||
["pray without ceasing", "oren sin cesar"],
|
||||
["deny yourself", "niéguense a sí mismos"],
|
||||
["engage the regions beyond", "alcanzar las regiones de más allá"],
|
||||
["Pentecostal", "pentecostal"],
|
||||
["Statement of Faith", "Declaración de fe"],
|
||||
["new birth", "nuevo nacimiento"],
|
||||
["regeneration", "regeneración"],
|
||||
["justification", "justificación"],
|
||||
["atonement", "expiación"],
|
||||
["sanctification", "santificación"],
|
||||
["baptism in water", "bautismo en agua"],
|
||||
["Lord's Supper", "Santa Cena"],
|
||||
["baptism in the Holy Spirit", "bautismo en el Espíritu Santo"],
|
||||
["speaking in tongues", "hablar en lenguas"],
|
||||
["gifts of the Holy Spirit", "dones del Espíritu Santo"],
|
||||
["pre-millennial return", "retorno premilenial"],
|
||||
["bodily resurrection", "resurrección corporal"],
|
||||
["pray", "orar"],
|
||||
["engage", "comprometer"],
|
||||
["UUPG", "PNANC"],
|
||||
["World Assemblies of God Fellowship", "Fraternidad Mundial de las Asambleas de Dios"],
|
||||
["choose a people group", "elegir un grupo étnico"],
|
||||
["sign up", "registrarse"]
|
||||
],
|
||||
fr: [
|
||||
["people group", "peuple"],
|
||||
["people groups", "peuples"],
|
||||
["unreached people group", "peuple non atteint"],
|
||||
["unreached people groups", "peuples non atteints"],
|
||||
["unengaged people group", "peuple non engagé"],
|
||||
["unengaged people groups", "peuples non engagés"],
|
||||
["unengaged unreached people group", "peuple non atteint et non engagé"],
|
||||
["under-engaged", "sous-engagé"],
|
||||
["frontier people group", "peuple frontière"],
|
||||
["frontier people groups", "peuples frontières"],
|
||||
["frontier peoples", "peuples frontières"],
|
||||
["ethnolinguistic group", "groupe ethnolinguistique"],
|
||||
["unreached", "non atteint"],
|
||||
["unengaged", "non engagé"],
|
||||
["engaged", "engagé"],
|
||||
["engagement", "engagement"],
|
||||
["fruitful engagement", "engagement fructueux"],
|
||||
["gospel access", "accès à l'Évangile"],
|
||||
["gospel engagement", "engagement pour l'Évangile"],
|
||||
["the gospel", "l'Évangile"],
|
||||
["church-planting movement", "mouvement d'implantation d'églises"],
|
||||
["church planting", "implantation d'églises"],
|
||||
["indigenous church", "église autochtone"],
|
||||
["indigenous churches", "églises autochtones"],
|
||||
["self-propagating", "auto-propagateur"],
|
||||
["self-governing", "auto-gouverné"],
|
||||
["self-supporting", "auto-financé"],
|
||||
["self-theologizing", "auto-théologisant"],
|
||||
["self-missionizing", "auto-missionnaire"],
|
||||
["residential engagement", "engagement sur le terrain"],
|
||||
["workers in residence", "ouvriers résidents"],
|
||||
["cross-cultural workers", "ouvriers transculturels"],
|
||||
["apostolic effort", "effort pionnier"],
|
||||
["pioneer work", "travail de pionnier"],
|
||||
["heart language", "langue du cœur"],
|
||||
["movement to Jesus", "mouvement vers Jésus"],
|
||||
["nonresident partners", "partenaires extérieurs"],
|
||||
["broader engagement", "engagement élargi"],
|
||||
["diaspora", "diaspora"],
|
||||
["daily prayer", "prière quotidienne"],
|
||||
["24-hour prayer coverage", "couverture de prière 24h/24"],
|
||||
["intercessor", "intercesseur"],
|
||||
["intercessors", "intercesseurs"],
|
||||
["intercessory prayer", "prière d'intercession"],
|
||||
["prayer points", "sujets de prière"],
|
||||
["daily prayer guide", "guide de prière quotidien"],
|
||||
["prayer prepares the way", "la prière prépare le chemin"],
|
||||
["Lord of the harvest", "Maître de la moisson"],
|
||||
["adopt", "adopter"],
|
||||
["pray, give, and send", "prier, donner et envoyer"],
|
||||
["mobilize", "mobiliser"],
|
||||
["mobilization", "mobilisation"],
|
||||
["sending agency", "agence missionnaire"],
|
||||
["sending agencies", "agences missionnaires"],
|
||||
["our gift to Jesus", "notre offrande à Jésus"],
|
||||
["DOXA partnership missionaries", "missionnaires en partenariat DOXA"],
|
||||
["every tribe, tongue, people, and nation", "toute tribu, toute langue, tout peuple et toute nation"],
|
||||
["make disciples of all the nations", "faites de toutes les nations des disciples"],
|
||||
["disciple", "disciple"],
|
||||
["disciples", "disciples"],
|
||||
["baptized disciples", "disciples baptisés"],
|
||||
["culturally appropriate", "culturellement approprié"],
|
||||
["self-sustaining churches", "églises autonomes"],
|
||||
["spiritual generations", "générations spirituelles"],
|
||||
["abide in Jesus", "demeurez en Jésus"],
|
||||
["pray without ceasing", "priez sans cesse"],
|
||||
["deny yourself", "renoncez à vous-même"],
|
||||
["engage the regions beyond", "portez l'Évangile au-delà"],
|
||||
["Pentecostal", "pentecôtiste"],
|
||||
["Statement of Faith", "Déclaration de foi"],
|
||||
["new birth", "nouvelle naissance"],
|
||||
["regeneration", "régénération"],
|
||||
["justification", "justification"],
|
||||
["atonement", "expiation"],
|
||||
["sanctification", "sanctification"],
|
||||
["baptism in water", "baptême d'eau"],
|
||||
["Lord's Supper", "Sainte Cène"],
|
||||
["baptism in the Holy Spirit", "baptême du Saint-Esprit"],
|
||||
["speaking in tongues", "parler en langues"],
|
||||
["gifts of the Holy Spirit", "dons du Saint-Esprit"],
|
||||
["pre-millennial return", "retour prémillénaire"],
|
||||
["bodily resurrection", "résurrection corporelle"],
|
||||
["pray", "prier"],
|
||||
["engage", "engager"],
|
||||
["World Assemblies of God Fellowship", "Association mondiale des Assemblées de Dieu"],
|
||||
["choose a people group", "choisir un peuple"],
|
||||
["sign up", "s'inscrire"]
|
||||
],
|
||||
hi: [
|
||||
["people group", "जातीय समूह"],
|
||||
["people groups", "जातीय समूह"],
|
||||
["unreached people group", "अगम्य जातीय समूह"],
|
||||
["unreached people groups", "अगम्य जातीय समूह"],
|
||||
["unengaged people group", "अप्रवेशित जातीय समूह"],
|
||||
["unengaged people groups", "अप्रवेशित जातीय समूह"],
|
||||
["unengaged unreached people group", "अगम्य और अप्रवेशित जातीय समूह"],
|
||||
["under-engaged", "अल्प-प्रवेशित"],
|
||||
["frontier people group", "सीमांत जातीय समूह"],
|
||||
["frontier people groups", "सीमांत जातीय समूह"],
|
||||
["ethnolinguistic group", "भाषाई-जातीय समूह"],
|
||||
["unreached", "अगम्य"],
|
||||
["unengaged", "अप्रवेशित"],
|
||||
["engaged", "प्रवेशित"],
|
||||
["engagement", "प्रवेश"],
|
||||
["fruitful engagement", "फलदायक प्रवेश"],
|
||||
["gospel access", "सुसमाचार तक पहुँच"],
|
||||
["gospel engagement", "सुसमाचार प्रवेश"],
|
||||
["the gospel", "सुसमाचार"],
|
||||
["church-planting movement", "कलीसिया रोपण आंदोलन"],
|
||||
["church planting", "कलीसिया रोपण"],
|
||||
["indigenous church", "देशज कलीसिया"],
|
||||
["indigenous churches", "देशज कलीसियाएँ"],
|
||||
["self-propagating", "स्व-प्रचारक"],
|
||||
["self-governing", "स्व-शासित"],
|
||||
["self-supporting", "स्व-पोषित"],
|
||||
["self-theologizing", "स्व-धर्मशास्त्रीय"],
|
||||
["self-missionizing", "स्व-मिशनकारी"],
|
||||
["residential engagement", "आवासीय प्रवेश"],
|
||||
["workers in residence", "निवासी कार्यकर्ता"],
|
||||
["cross-cultural workers", "अंतर-सांस्कृतिक कार्यकर्ता"],
|
||||
["apostolic effort", "प्रेरितिक प्रयास"],
|
||||
["pioneer work", "अग्रणी कार्य"],
|
||||
["heart language", "मातृभाषा"],
|
||||
["movement to Jesus", "यीशु की ओर आंदोलन"],
|
||||
["nonresident partners", "अनिवासी सहभागी"],
|
||||
["broader engagement", "व्यापक प्रवेश"],
|
||||
["diaspora", "प्रवासी समुदाय"],
|
||||
["daily prayer", "दैनिक प्रार्थना"],
|
||||
["24-hour prayer coverage", "24 घंटे की प्रार्थना कवरेज"],
|
||||
["intercessor", "मध्यस्थ प्रार्थनाकर्ता"],
|
||||
["intercessors", "मध्यस्थ प्रार्थनाकर्ता"],
|
||||
["intercessory prayer", "मध्यस्थ प्रार्थना"],
|
||||
["prayer points", "प्रार्थना विषय"],
|
||||
["daily prayer guide", "दैनिक प्रार्थना मार्गदर्शिका"],
|
||||
["prayer prepares the way", "प्रार्थना मार्ग तैयार करती है"],
|
||||
["Lord of the harvest", "कटनी का स्वामी"],
|
||||
["adopt", "अपनाना"],
|
||||
["pray, give, and send", "प्रार्थना करो, दो और भेजो"],
|
||||
["mobilize", "गतिशील करना"],
|
||||
["mobilization", "गतिशीलता"],
|
||||
["sending agency", "भेजने वाली संस्था"],
|
||||
["sending agencies", "भेजने वाली संस्थाएँ"],
|
||||
["our gift to Jesus", "यीशु को हमारी भेंट"],
|
||||
["DOXA partnership missionaries", "DOXA साझेदारी के मिशनरी"],
|
||||
["every tribe, tongue, people, and nation", "हर एक कुल, भाषा, लोग और जाति"],
|
||||
["make disciples of all the nations", "सब जातियों को चेला बनाओ"],
|
||||
["disciple", "चेला"],
|
||||
["disciples", "चेले"],
|
||||
["baptized disciples", "बपतिस्मा प्राप्त चेले"],
|
||||
["culturally appropriate", "सांस्कृतिक रूप से उपयुक्त"],
|
||||
["self-sustaining churches", "स्वावलंबी कलीसियाएँ"],
|
||||
["spiritual generations", "आत्मिक पीढ़ियाँ"],
|
||||
["abide in Jesus", "यीशु में बने रहो"],
|
||||
["pray without ceasing", "निरन्तर प्रार्थना करो"],
|
||||
["deny yourself", "अपने आप का इन्कार करो"],
|
||||
["engage the regions beyond", "परे के क्षेत्रों में सुसमाचार ले जाओ"],
|
||||
["Pentecostal", "पेन्तेकोस्तल"],
|
||||
["Statement of Faith", "विश्वास का वक्तव्य"],
|
||||
["new birth", "नया जन्म"],
|
||||
["regeneration", "नवीनीकरण"],
|
||||
["justification", "धर्मीकरण"],
|
||||
["atonement", "प्रायश्चित्त"],
|
||||
["sanctification", "पवित्रीकरण"],
|
||||
["baptism in water", "जल बपतिस्मा"],
|
||||
["Lord's Supper", "प्रभु भोज"],
|
||||
["baptism in the Holy Spirit", "पवित्र आत्मा का बपतिस्मा"],
|
||||
["speaking in tongues", "अन्य भाषाओं में बोलना"],
|
||||
["gifts of the Holy Spirit", "पवित्र आत्मा के वरदान"],
|
||||
["pre-millennial return", "सहस्राब्दी-पूर्व पुनरागमन"],
|
||||
["bodily resurrection", "शारीरिक पुनरुत्थान"],
|
||||
["pray", "प्रार्थना करना"],
|
||||
["engage", "प्रवेश करना"],
|
||||
["choose a people group", "एक जातीय समूह चुनना"],
|
||||
["sign up", "पंजीकरण करना"]
|
||||
],
|
||||
it: [
|
||||
["people group", "gruppo etnico"],
|
||||
["people groups", "gruppi etnici"],
|
||||
["unreached people group", "gruppo etnico non raggiunto"],
|
||||
["unreached people groups", "gruppi etnici non raggiunti"],
|
||||
["unengaged people group", "gruppo etnico non coinvolto"],
|
||||
["unengaged people groups", "gruppi etnici non coinvolti"],
|
||||
["unengaged unreached people group", "gruppo etnico non raggiunto e non coinvolto"],
|
||||
["under-engaged", "sottocoinvolto"],
|
||||
["frontier people group", "gruppo etnico di frontiera"],
|
||||
["frontier people groups", "gruppi etnici di frontiera"],
|
||||
["ethnolinguistic group", "gruppo etnolinguistico"],
|
||||
["unreached", "non raggiunto"],
|
||||
["unengaged", "non coinvolto"],
|
||||
["engaged", "coinvolto"],
|
||||
["engagement", "coinvolgimento"],
|
||||
["fruitful engagement", "coinvolgimento fruttuoso"],
|
||||
["gospel access", "accesso al Vangelo"],
|
||||
["gospel engagement", "coinvolgimento per il Vangelo"],
|
||||
["the gospel", "il Vangelo"],
|
||||
["church-planting movement", "movimento di fondazione di chiese"],
|
||||
["church planting", "fondazione di chiese"],
|
||||
["indigenous church", "chiesa autoctona"],
|
||||
["indigenous churches", "chiese autoctone"],
|
||||
["self-propagating", "autopropagatrice"],
|
||||
["self-governing", "autogovernata"],
|
||||
["self-supporting", "autofinanziata"],
|
||||
["self-theologizing", "autoteologizzante"],
|
||||
["self-missionizing", "automissionaria"],
|
||||
["residential engagement", "coinvolgimento residenziale"],
|
||||
["workers in residence", "operatori residenti"],
|
||||
["cross-cultural workers", "operatori interculturali"],
|
||||
["apostolic effort", "impegno apostolico"],
|
||||
["pioneer work", "lavoro pionieristico"],
|
||||
["heart language", "lingua madre"],
|
||||
["movement to Jesus", "movimento verso Gesù"],
|
||||
["nonresident partners", "partner non residenti"],
|
||||
["broader engagement", "coinvolgimento più ampio"],
|
||||
["diaspora", "diaspora"],
|
||||
["daily prayer", "preghiera quotidiana"],
|
||||
["24-hour prayer coverage", "copertura di preghiera di 24 ore"],
|
||||
["intercessor", "intercessore"],
|
||||
["intercessors", "intercessori"],
|
||||
["intercessory prayer", "preghiera di intercessione"],
|
||||
["prayer points", "spunti di preghiera"],
|
||||
["daily prayer guide", "guida di preghiera quotidiana"],
|
||||
["prayer prepares the way", "la preghiera prepara la via"],
|
||||
["Lord of the harvest", "Signore della messe"],
|
||||
["adopt", "adottare"],
|
||||
["pray, give, and send", "pregare, dare e inviare"],
|
||||
["mobilize", "mobilitare"],
|
||||
["mobilization", "mobilitazione"],
|
||||
["sending agency", "agenzia di invio"],
|
||||
["sending agencies", "agenzie di invio"],
|
||||
["our gift to Jesus", "la nostra offerta a Gesù"],
|
||||
["DOXA partnership missionaries", "missionari partner di DOXA"],
|
||||
["every tribe, tongue, people, and nation", "ogni tribù, lingua, popolo e nazione"],
|
||||
["make disciples of all the nations", "fate discepoli di tutti i popoli"],
|
||||
["disciple", "discepolo"],
|
||||
["disciples", "discepoli"],
|
||||
["baptized disciples", "discepoli battezzati"],
|
||||
["culturally appropriate", "culturalmente adeguato"],
|
||||
["self-sustaining churches", "chiese autonome"],
|
||||
["spiritual generations", "generazioni spirituali"],
|
||||
["abide in Jesus", "dimorate in Gesù"],
|
||||
["pray without ceasing", "pregate senza cessare"],
|
||||
["deny yourself", "rinnegate voi stessi"],
|
||||
["engage the regions beyond", "portate il Vangelo oltre"],
|
||||
["Pentecostal", "pentecostale"],
|
||||
["Statement of Faith", "Dichiarazione di fede"],
|
||||
["new birth", "nuova nascita"],
|
||||
["regeneration", "rigenerazione"],
|
||||
["justification", "giustificazione"],
|
||||
["atonement", "espiazione"],
|
||||
["sanctification", "santificazione"],
|
||||
["baptism in water", "battesimo in acqua"],
|
||||
["Lord's Supper", "Santa Cena"],
|
||||
["baptism in the Holy Spirit", "battesimo nello Spirito Santo"],
|
||||
["speaking in tongues", "parlare in lingue"],
|
||||
["gifts of the Holy Spirit", "doni dello Spirito Santo"],
|
||||
["pre-millennial return", "ritorno premillenario"],
|
||||
["bodily resurrection", "risurrezione corporea"],
|
||||
["pray", "pregare"],
|
||||
["engage", "coinvolgere"],
|
||||
["choose a people group", "scegliere un gruppo etnico"],
|
||||
["sign up", "iscriversi"]
|
||||
],
|
||||
pt: [
|
||||
["people group", "grupo étnico"],
|
||||
["people groups", "grupos étnicos"],
|
||||
["unreached people group", "grupo étnico não alcançado"],
|
||||
["unreached people groups", "grupos étnicos não alcançados"],
|
||||
["unengaged people group", "grupo étnico não engajado"],
|
||||
["unengaged people groups", "grupos étnicos não engajados"],
|
||||
["unengaged unreached people group", "grupo étnico não alcançado e não engajado"],
|
||||
["under-engaged", "subengajado"],
|
||||
["frontier people group", "grupo étnico de fronteira"],
|
||||
["frontier people groups", "grupos étnicos de fronteira"],
|
||||
["ethnolinguistic group", "grupo etnolinguístico"],
|
||||
["unreached", "não alcançado"],
|
||||
["unengaged", "não engajado"],
|
||||
["engaged", "engajado"],
|
||||
["engagement", "engajamento"],
|
||||
["fruitful engagement", "engajamento frutífero"],
|
||||
["gospel access", "acesso ao Evangelho"],
|
||||
["gospel engagement", "engajamento com o Evangelho"],
|
||||
["the gospel", "o Evangelho"],
|
||||
["church-planting movement", "movimento de plantação de igrejas"],
|
||||
["church planting", "plantação de igrejas"],
|
||||
["indigenous church", "igreja autóctona"],
|
||||
["indigenous churches", "igrejas autóctones"],
|
||||
["self-propagating", "autopropagador"],
|
||||
["self-governing", "autogovernado"],
|
||||
["self-supporting", "autofinanciado"],
|
||||
["self-theologizing", "autoteologizante"],
|
||||
["self-missionizing", "automissionário"],
|
||||
["residential engagement", "engajamento residencial"],
|
||||
["workers in residence", "obreiros residentes"],
|
||||
["cross-cultural workers", "obreiros transculturais"],
|
||||
["apostolic effort", "esforço apostólico"],
|
||||
["pioneer work", "trabalho pioneiro"],
|
||||
["heart language", "língua materna"],
|
||||
["movement to Jesus", "movimento em direção a Jesus"],
|
||||
["nonresident partners", "parceiros não residentes"],
|
||||
["broader engagement", "engajamento ampliado"],
|
||||
["diaspora", "diáspora"],
|
||||
["daily prayer", "oração diária"],
|
||||
["24-hour prayer coverage", "cobertura de oração de 24 horas"],
|
||||
["intercessor", "intercessor"],
|
||||
["intercessors", "intercessores"],
|
||||
["intercessory prayer", "oração intercessória"],
|
||||
["prayer points", "motivos de oração"],
|
||||
["daily prayer guide", "guia de oração diário"],
|
||||
["prayer prepares the way", "a oração prepara o caminho"],
|
||||
["Lord of the harvest", "Senhor da seara"],
|
||||
["adopt", "adotar"],
|
||||
["pray, give, and send", "orar, contribuir e enviar"],
|
||||
["mobilize", "mobilizar"],
|
||||
["mobilization", "mobilização"],
|
||||
["sending agency", "agência de envio"],
|
||||
["sending agencies", "agências de envio"],
|
||||
["our gift to Jesus", "nossa oferta a Jesus"],
|
||||
["DOXA partnership missionaries", "missionários parceiros da DOXA"],
|
||||
["every tribe, tongue, people, and nation", "toda tribo, língua, povo e nação"],
|
||||
["make disciples of all the nations", "façam discípulos de todas as nações"],
|
||||
["disciple", "discípulo"],
|
||||
["disciples", "discípulos"],
|
||||
["baptized disciples", "discípulos batizados"],
|
||||
["culturally appropriate", "culturalmente apropriado"],
|
||||
["self-sustaining churches", "igrejas autossustentáveis"],
|
||||
["spiritual generations", "gerações espirituais"],
|
||||
["abide in Jesus", "permaneçam em Jesus"],
|
||||
["pray without ceasing", "orem sem cessar"],
|
||||
["deny yourself", "neguem a si mesmos"],
|
||||
["engage the regions beyond", "alcancem as regiões mais além"],
|
||||
["Pentecostal", "pentecostal"],
|
||||
["Statement of Faith", "Declaração de fé"],
|
||||
["new birth", "novo nascimento"],
|
||||
["regeneration", "regeneração"],
|
||||
["justification", "justificação"],
|
||||
["atonement", "expiação"],
|
||||
["sanctification", "santificação"],
|
||||
["baptism in water", "batismo nas águas"],
|
||||
["Lord's Supper", "Santa Ceia"],
|
||||
["baptism in the Holy Spirit", "batismo no Espírito Santo"],
|
||||
["speaking in tongues", "falar em línguas"],
|
||||
["gifts of the Holy Spirit", "dons do Espírito Santo"],
|
||||
["pre-millennial return", "retorno pré-milenial"],
|
||||
["bodily resurrection", "ressurreição corporal"],
|
||||
["pray", "orar"],
|
||||
["engage", "engajar"],
|
||||
["World Assemblies of God Fellowship", "Comunhão das Assembléias de Deus Mundial"],
|
||||
["choose a people group", "escolher um grupo étnico"],
|
||||
["sign up", "inscrever-se"]
|
||||
],
|
||||
ro: [
|
||||
["people group", "grup etnic"],
|
||||
["people groups", "grupuri etnice"],
|
||||
["unreached people group", "grup etnic neatins"],
|
||||
["unreached people groups", "grupuri etnice neatinse"],
|
||||
["unengaged people group", "grup etnic neangajat"],
|
||||
["unengaged people groups", "grupuri etnice neangajate"],
|
||||
["unengaged unreached people group", "grup etnic neatins și neangajat"],
|
||||
["under-engaged", "insuficient angajat"],
|
||||
["frontier people group", "grup etnic de frontieră"],
|
||||
["frontier people groups", "grupuri etnice de frontieră"],
|
||||
["ethnolinguistic group", "grup etnolingvistic"],
|
||||
["unreached", "neatins"],
|
||||
["unengaged", "neangajat"],
|
||||
["engaged", "angajat"],
|
||||
["engagement", "angajare"],
|
||||
["fruitful engagement", "angajare rodnică"],
|
||||
["gospel access", "acces la Evanghelie"],
|
||||
["gospel engagement", "angajare pentru Evanghelie"],
|
||||
["the gospel", "Evanghelia"],
|
||||
["church-planting movement", "mișcare de plantare de biserici"],
|
||||
["church planting", "plantare de biserici"],
|
||||
["indigenous church", "biserică autohtonă"],
|
||||
["indigenous churches", "biserici autohtone"],
|
||||
["self-propagating", "autopropagator"],
|
||||
["self-governing", "autoguvernat"],
|
||||
["self-supporting", "autofinanțat"],
|
||||
["self-theologizing", "autoteologizant"],
|
||||
["self-missionizing", "automisionar"],
|
||||
["residential engagement", "angajare rezidențială"],
|
||||
["workers in residence", "lucrători rezidenți"],
|
||||
["cross-cultural workers", "lucrători interculturali"],
|
||||
["apostolic effort", "efort apostolic"],
|
||||
["pioneer work", "lucrare pionieră"],
|
||||
["heart language", "limba maternă"],
|
||||
["movement to Jesus", "mișcare spre Isus"],
|
||||
["nonresident partners", "parteneri nerezidenți"],
|
||||
["broader engagement", "angajare extinsă"],
|
||||
["diaspora", "diaspora"],
|
||||
["daily prayer", "rugăciune zilnică"],
|
||||
["24-hour prayer coverage", "acoperire de rugăciune de 24 de ore"],
|
||||
["intercessor", "mijlocitor"],
|
||||
["intercessors", "mijlocitori"],
|
||||
["intercessory prayer", "rugăciune de mijlocire"],
|
||||
["prayer points", "subiecte de rugăciune"],
|
||||
["daily prayer guide", "ghid zilnic de rugăciune"],
|
||||
["prayer prepares the way", "rugăciunea pregătește calea"],
|
||||
["Lord of the harvest", "Stăpânul secerișului"],
|
||||
["adopt", "a adopta"],
|
||||
["pray, give, and send", "rugați-vă, dăruiți și trimiteți"],
|
||||
["mobilize", "a mobiliza"],
|
||||
["mobilization", "mobilizare"],
|
||||
["sending agency", "agenție de trimitere"],
|
||||
["sending agencies", "agenții de trimitere"],
|
||||
["our gift to Jesus", "darul nostru pentru Isus"],
|
||||
["DOXA partnership missionaries", "misionari parteneri DOXA"],
|
||||
["every tribe, tongue, people, and nation", "orice seminție, orice limbă, orice popor și orice națiune"],
|
||||
["make disciples of all the nations", "faceți ucenici din toate neamurile"],
|
||||
["disciple", "ucenic"],
|
||||
["disciples", "ucenici"],
|
||||
["baptized disciples", "ucenici botezați"],
|
||||
["culturally appropriate", "adaptat cultural"],
|
||||
["self-sustaining churches", "biserici autonome"],
|
||||
["spiritual generations", "generații spirituale"],
|
||||
["abide in Jesus", "rămâneți în Isus"],
|
||||
["pray without ceasing", "rugați-vă neîncetat"],
|
||||
["deny yourself", "lepădați-vă de voi înșivă"],
|
||||
["engage the regions beyond", "duceți Evanghelia dincolo de hotare"],
|
||||
["Pentecostal", "penticostal"],
|
||||
["Statement of Faith", "Declarație de credință"],
|
||||
["new birth", "nașterea din nou"],
|
||||
["regeneration", "regenerare"],
|
||||
["justification", "justificare"],
|
||||
["atonement", "ispășire"],
|
||||
["sanctification", "sfințire"],
|
||||
["baptism in water", "botezul în apă"],
|
||||
["Lord's Supper", "Cina Domnului"],
|
||||
["baptism in the Holy Spirit", "botezul în Duhul Sfânt"],
|
||||
["speaking in tongues", "vorbirea în limbi"],
|
||||
["gifts of the Holy Spirit", "darurile Duhului Sfânt"],
|
||||
["pre-millennial return", "revenirea premilenială"],
|
||||
["bodily resurrection", "învierea trupească"],
|
||||
["pray", "a se ruga"],
|
||||
["engage", "a angaja"],
|
||||
["choose a people group", "a alege un grup etnic"],
|
||||
["sign up", "a se înregistra"]
|
||||
],
|
||||
ru: [
|
||||
["people group", "этническая группа"],
|
||||
["people groups", "этнические группы"],
|
||||
["unreached people group", "недостигнутая этническая группа"],
|
||||
["unreached people groups", "недостигнутые этнические группы"],
|
||||
["unengaged people group", "невовлечённая этническая группа"],
|
||||
["unengaged people groups", "невовлечённые этнические группы"],
|
||||
["unengaged unreached people group", "недостигнутая и невовлечённая этническая группа"],
|
||||
["under-engaged", "недостаточно вовлечённая"],
|
||||
["frontier people group", "этническая группа на передовой"],
|
||||
["frontier people groups", "этнические группы на передовой"],
|
||||
["ethnolinguistic group", "этнолингвистическая группа"],
|
||||
["unreached", "недостигнутый"],
|
||||
["unengaged", "невовлечённый"],
|
||||
["engaged", "вовлечённый"],
|
||||
["engagement", "вовлечение"],
|
||||
["fruitful engagement", "плодотворное вовлечение"],
|
||||
["gospel access", "доступ к Евангелию"],
|
||||
["gospel engagement", "евангельское вовлечение"],
|
||||
["the gospel", "Евангелие"],
|
||||
["church-planting movement", "движение насаждения церквей"],
|
||||
["church planting", "насаждение церквей"],
|
||||
["indigenous church", "местная церковь"],
|
||||
["indigenous churches", "местные церкви"],
|
||||
["self-propagating", "самовоспроизводящийся"],
|
||||
["self-governing", "самоуправляемый"],
|
||||
["self-supporting", "самофинансируемый"],
|
||||
["self-theologizing", "самобогословствующий"],
|
||||
["self-missionizing", "самомиссионерский"],
|
||||
["residential engagement", "вовлечение на месте"],
|
||||
["workers in residence", "резидентные работники"],
|
||||
["cross-cultural workers", "межкультурные работники"],
|
||||
["apostolic effort", "апостольское служение"],
|
||||
["pioneer work", "пионерское служение"],
|
||||
["heart language", "родной язык"],
|
||||
["movement to Jesus", "движение к Иисусу"],
|
||||
["nonresident partners", "нерезидентные партнёры"],
|
||||
["broader engagement", "расширенное вовлечение"],
|
||||
["diaspora", "диаспора"],
|
||||
["daily prayer", "ежедневная молитва"],
|
||||
["24-hour prayer coverage", "круглосуточное молитвенное покрытие"],
|
||||
["intercessor", "ходатай"],
|
||||
["intercessors", "ходатаи"],
|
||||
["intercessory prayer", "ходатайственная молитва"],
|
||||
["prayer points", "молитвенные нужды"],
|
||||
["daily prayer guide", "ежедневный молитвенный путеводитель"],
|
||||
["prayer prepares the way", "молитва готовит путь"],
|
||||
["Lord of the harvest", "Господин жатвы"],
|
||||
["adopt", "взять попечение"],
|
||||
["pray, give, and send", "молитесь, жертвуйте и посылайте"],
|
||||
["mobilize", "мобилизовать"],
|
||||
["mobilization", "мобилизация"],
|
||||
["sending agency", "посылающая организация"],
|
||||
["sending agencies", "посылающие организации"],
|
||||
["our gift to Jesus", "наш дар Иисусу"],
|
||||
["DOXA partnership missionaries", "миссионеры-партнёры DOXA"],
|
||||
["every tribe, tongue, people, and nation", "всякое колено, и язык, и народ, и племя"],
|
||||
["make disciples of all the nations", "научите все народы"],
|
||||
["disciple", "ученик"],
|
||||
["disciples", "ученики"],
|
||||
["baptized disciples", "крещёные ученики"],
|
||||
["culturally appropriate", "культурно адаптированный"],
|
||||
["self-sustaining churches", "самостоятельные церкви"],
|
||||
["spiritual generations", "духовные поколения"],
|
||||
["abide in Jesus", "пребывайте в Иисусе"],
|
||||
["pray without ceasing", "непрестанно молитесь"],
|
||||
["deny yourself", "отвергните себя"],
|
||||
["engage the regions beyond", "несите Евангелие за пределы"],
|
||||
["Pentecostal", "пятидесятнический"],
|
||||
["Statement of Faith", "Исповедание веры"],
|
||||
["new birth", "рождение свыше"],
|
||||
["regeneration", "возрождение"],
|
||||
["justification", "оправдание"],
|
||||
["atonement", "искупление"],
|
||||
["sanctification", "освящение"],
|
||||
["baptism in water", "водное крещение"],
|
||||
["Lord's Supper", "Вечеря Господня"],
|
||||
["baptism in the Holy Spirit", "крещение Духом Святым"],
|
||||
["speaking in tongues", "говорение на иных языках"],
|
||||
["gifts of the Holy Spirit", "дары Святого Духа"],
|
||||
["pre-millennial return", "домилленниальное возвращение"],
|
||||
["bodily resurrection", "телесное воскресение"],
|
||||
["pray", "молиться"],
|
||||
["engage", "вовлекать"],
|
||||
["choose a people group", "выбрать этническую группу"],
|
||||
["sign up", "зарегистрироваться"]
|
||||
],
|
||||
zh: [
|
||||
["people group", "族群"],
|
||||
["people groups", "族群"],
|
||||
["unreached people group", "未得之民"],
|
||||
["unreached people groups", "未得之民"],
|
||||
["unengaged people group", "未接触族群"],
|
||||
["unengaged people groups", "未接触族群"],
|
||||
["unengaged unreached people group", "未接触未得之民"],
|
||||
["under-engaged", "接触不足的"],
|
||||
["frontier people group", "前沿族群"],
|
||||
["frontier people groups", "前沿族群"],
|
||||
["ethnolinguistic group", "民族语言群体"],
|
||||
["unreached", "未得的"],
|
||||
["unengaged", "未接触的"],
|
||||
["engaged", "已接触的"],
|
||||
["engagement", "接触"],
|
||||
["fruitful engagement", "有果效的接触"],
|
||||
["gospel access", "福音可及性"],
|
||||
["gospel engagement", "福音接触"],
|
||||
["the gospel", "福音"],
|
||||
["church-planting movement", "植堂运动"],
|
||||
["church planting", "植堂"],
|
||||
["indigenous church", "本土教会"],
|
||||
["indigenous churches", "本土教会"],
|
||||
["self-propagating", "自传的"],
|
||||
["self-governing", "自治的"],
|
||||
["self-supporting", "自养的"],
|
||||
["self-theologizing", "自我神学建构的"],
|
||||
["self-missionizing", "自我差传的"],
|
||||
["residential engagement", "驻地接触"],
|
||||
["workers in residence", "驻地工人"],
|
||||
["cross-cultural workers", "跨文化工人"],
|
||||
["apostolic effort", "使徒性开拓"],
|
||||
["pioneer work", "先锋事工"],
|
||||
["heart language", "母语"],
|
||||
["movement to Jesus", "归主运动"],
|
||||
["nonresident partners", "非驻地伙伴"],
|
||||
["broader engagement", "广义接触"],
|
||||
["diaspora", "散居群体"],
|
||||
["daily prayer", "每日祷告"],
|
||||
["24-hour prayer coverage", "全天候祷告覆盖"],
|
||||
["intercessor", "代祷者"],
|
||||
["intercessors", "代祷者"],
|
||||
["intercessory prayer", "代祷"],
|
||||
["prayer points", "祷告事项"],
|
||||
["daily prayer guide", "每日祷告指南"],
|
||||
["prayer prepares the way", "祷告预备道路"],
|
||||
["Lord of the harvest", "庄稼的主"],
|
||||
["adopt", "认领"],
|
||||
["pray, give, and send", "祷告、奉献、差派"],
|
||||
["mobilize", "动员"],
|
||||
["mobilization", "动员"],
|
||||
["sending agency", "差传机构"],
|
||||
["sending agencies", "差传机构"],
|
||||
["our gift to Jesus", "我们献给耶稣的礼物"],
|
||||
["DOXA partnership missionaries", "DOXA伙伴宣教士"],
|
||||
["every tribe, tongue, people, and nation", "各族、各方、各民、各国"],
|
||||
["make disciples of all the nations", "使万民作主的门徒"],
|
||||
["disciple", "门徒"],
|
||||
["disciples", "门徒"],
|
||||
["baptized disciples", "受洗门徒"],
|
||||
["culturally appropriate", "合乎文化的"],
|
||||
["self-sustaining churches", "自立教会"],
|
||||
["spiritual generations", "属灵世代"],
|
||||
["abide in Jesus", "常在主里面"],
|
||||
["pray without ceasing", "不住地祷告"],
|
||||
["deny yourself", "舍己"],
|
||||
["engage the regions beyond", "进入未及之地"],
|
||||
["Pentecostal", "五旬节派"],
|
||||
["Statement of Faith", "信仰宣言"],
|
||||
["new birth", "重生"],
|
||||
["regeneration", "更新"],
|
||||
["justification", "称义"],
|
||||
["atonement", "赎罪"],
|
||||
["sanctification", "成圣"],
|
||||
["baptism in water", "水的洗礼"],
|
||||
["Lord's Supper", "圣餐"],
|
||||
["baptism in the Holy Spirit", "圣灵的洗"],
|
||||
["speaking in tongues", "说方言"],
|
||||
["gifts of the Holy Spirit", "圣灵的恩赐"],
|
||||
["pre-millennial return", "千禧年前再来"],
|
||||
["bodily resurrection", "身体复活"],
|
||||
["pray", "祷告"],
|
||||
["engage", "接触"],
|
||||
["choose a people group", "选择一个族群"],
|
||||
["sign up", "注册"]
|
||||
]
|
||||
}
|
||||
|
|
@ -24,13 +24,13 @@ export const LANGUAGES: Language[] = [
|
|||
{ code: 'es', name: 'Spanish', nativeName: 'Español', flag: '🇪🇸', bibleId: 'NVI' }, // RV1960
|
||||
{ code: 'fr', name: 'French', nativeName: 'Français', flag: '🇫🇷', bibleId: 'FRLSG', bibleLabel: 'LSG' }, // maybe BDS
|
||||
{ code: 'pt', name: 'Portuguese', nativeName: 'Português', flag: '🇵🇹', bibleId: 'NAA', translationName: 'Brazilian Portuguese' },
|
||||
{ code: 'de', name: 'German', nativeName: 'Deutsch', flag: '🇩🇪', bibleId: 'S00', bibleLabel: 'SCH2000', hideFromSwitcher: true },
|
||||
{ code: 'it', name: 'Italian', nativeName: 'Italiano', flag: '🇮🇹', bibleId: 'NR06', enabled: false },
|
||||
{ code: 'zh', name: 'Chinese', nativeName: '中文', flag: '🇨🇳', bibleId: 'CUNPS', translationName: 'Simplified Chinese', enabled: false, latinHeadings: false },
|
||||
{ code: 'de', name: 'German', nativeName: 'Deutsch', flag: '🇩🇪', bibleId: 'S00', bibleLabel: 'SCH2000' },
|
||||
{ code: 'it', name: 'Italian', nativeName: 'Italiano', flag: '🇮🇹', bibleId: 'NR06' },
|
||||
{ code: 'zh', name: 'Chinese', nativeName: '简体中文', flag: '🇨🇳', bibleId: 'CUNPS', translationName: 'Simplified Chinese', latinHeadings: false },
|
||||
{ code: 'ar', name: 'Arabic', nativeName: 'العربية', flag: '🇸🇦', dir: 'rtl', bibleId: 'SVD', translationName: 'Modern Standard Arabic', latinHeadings: false }, // NAV (New Arabic Version) would be better but not on Bolls
|
||||
{ code: 'ru', name: 'Russian', nativeName: 'Русский', flag: '🇷🇺', bibleId: 'SYNOD', latinHeadings: false }, // NRT (New Russian Translation) is a modern alternative
|
||||
{ code: 'hi', name: 'Hindi', nativeName: 'हिन्दी', flag: '🇮🇳', bibleId: 'HIOV', bibleLabel: 'OV', hideFromSwitcher: true, latinHeadings: false },
|
||||
{ code: 'ro', name: 'Romanian', nativeName: 'Română', flag: '🇷🇴', bibleId: 'NTR', enabled: false },
|
||||
{ code: 'hi', name: 'Hindi', nativeName: 'हिन्दी', flag: '🇮🇳', bibleId: 'HIOV', bibleLabel: 'OV', latinHeadings: false },
|
||||
{ code: 'ro', name: 'Romanian', nativeName: 'Română', flag: '🇷🇴', bibleId: 'NTR' }
|
||||
]
|
||||
|
||||
// All language codes
|
||||
|
|
|
|||
189
documentation/LAPTOP-6WAY.md
Normal file
189
documentation/LAPTOP-6WAY.md
Normal file
|
|
@ -0,0 +1,189 @@
|
|||
# The Research Gallery on your laptop: three routes
|
||||
|
||||
DX-life takes the dx-maps Research Gallery in **three routes**, one branch each. This page runs each of them on a
|
||||
laptop, so you can see and test them before any server is involved. The drop-in and subdomain routes also run on
|
||||
the team's servers (the embed test: each route on a laptop and on a server). The Plugin Studio route's own server
|
||||
is still to come.
|
||||
|
||||
| Route | DX-life branch | What runs | Docker | PocketBase |
|
||||
|---|---|---|---|---|
|
||||
| **Drop-in** (the default) | `research-gallery-drop-in` | this site alone; the maps are its own copy in `public/dx-maps` | no | no |
|
||||
| **Subdomain** | `research-gallery-subdomain` | the dx-maps **team container** (Plugin Studio, PocketBase, the research site) + a local sign-in + this site | yes, about 5 GB | yes, for plugins that have users, an API or a database |
|
||||
| **Plugin Studio** | `research-gallery-plugin-studio` | the dx-maps container in its **public** mode (the Plugin Studio open to everyone, and its `/cdn` of production maps) + this site | yes, about 5 GB | yes, the container's own; its dashboard asks for the admin password |
|
||||
|
||||
The **CDN** route (`research-gallery-cdn`) was retired on 2026-09-29. Its branch is kept for history.
|
||||
|
||||
## Before you start
|
||||
|
||||
- **Checkouts side by side:**
|
||||
```
|
||||
doxa-maps/ dx-maps, on development (the team's table) or main (production)
|
||||
doxa-life/ this repo
|
||||
```
|
||||
- **bun 1.3+** and **node 20+**. For the subdomain and Plugin Studio routes, **Docker** with Compose: each uses
|
||||
about 1.4 GB, 2.5 GB while publishing; give Docker 4-6 GB.
|
||||
- **Once:** `cd doxa-life && bun install`. The branches share one lockfile.
|
||||
|
||||
## 1. Drop-in (the default: one server, no Docker)
|
||||
|
||||
```bash
|
||||
cd doxa-life && git switch research-gallery-drop-in
|
||||
PORT=4611 bun run dev
|
||||
```
|
||||
|
||||
Open http://localhost:4611/research/ (the Research Gallery) and http://localhost:4611/embed-test (every web
|
||||
plugin, embedded). There is **no setting to change**: the branch loads every map from its own `/dx-maps/` (same
|
||||
origin), a copy committed with it. The first `bun run dev` compiles for about a minute; a page may answer 503
|
||||
until it's done.
|
||||
|
||||
**To try a newer dx-maps** than the committed copy:
|
||||
|
||||
```bash
|
||||
cd doxa-maps && EMBED_BASE_URL=http://localhost:4611 bun run tree # seconds; only the two manifests change
|
||||
bun run dropin # copies dx-maps/ into ../doxa-life/public
|
||||
git restore public # dx-maps back to its committed folder
|
||||
```
|
||||
|
||||
Afterwards, put the site's copy back: `git restore public/dx-maps && git clean -fdq public/dx-maps`.
|
||||
|
||||
## 2. Subdomain (the dx-maps team container, with PocketBase)
|
||||
|
||||
```bash
|
||||
cd doxa-life && git switch research-gallery-subdomain
|
||||
bun run laptop subdomain
|
||||
```
|
||||
|
||||
**The first time,** it makes `.env.laptop` (secrets, never committed) and stops if `GIT_TOKEN` is empty.
|
||||
- Put a read token for the team's git server there and run it again.
|
||||
- It builds dx-maps' container from `../doxa-maps/Dockerfile`, the image the team's server runs.
|
||||
- Pull dx-maps `development` first. The first start takes 5-10 minutes: the container clones, installs and
|
||||
publishes.
|
||||
|
||||
It starts three services, all on `127.0.0.1` only:
|
||||
|
||||
| Address | What |
|
||||
|---|---|
|
||||
| http://localhost:4613/ | this site, subdomain branch. The Research menu and `/regions` open the research site |
|
||||
| http://research.localhost:4615/ | the research site: the gallery at `/`, `/embed-test`, and the maps under `/dx-maps/`, which this site embeds |
|
||||
| http://localhost:4616/ | the Plugin Studio, PocketBase (`/pb`), `/cdn`, `/admin` |
|
||||
| http://localhost:4620/team | the local sign-in provider |
|
||||
|
||||
**Sign-in and roles**, the same as the team's server:
|
||||
- Sign in to the Studio as **`admin`** (everything, including publishing and the PocketBase dashboard) or
|
||||
**`designer`** (the Studio and PocketBase's API).
|
||||
- Any other name is a plain team member, and is refused, as on the server.
|
||||
- There's no password: the provider is a local stand-in.
|
||||
|
||||
**How it is wired:**
|
||||
- `research.localhost` is your laptop's `research.<host>`. Chrome and Firefox send every `*.localhost` name to
|
||||
this computer. Safari may not: add `127.0.0.1 research.localhost` to `/etc/hosts`.
|
||||
- The sign-in provider runs inside the dx-maps container's network, so `localhost:4620` means the same to your
|
||||
browser and to the container. No hosts-file entry is needed for sign-in.
|
||||
- Publishing is automatic: a minute after `main` holds a new commit, the container rebuilds `/cdn` and the
|
||||
research site. The snippets point at `http://research.localhost:4615`.
|
||||
|
||||
**If memory is short,** the command says so before starting anything, and names what to close, or the lighter
|
||||
drop-in route.
|
||||
|
||||
**Stop:** `bun run laptop down` keeps PocketBase's data and the published build; `bun run laptop down --wipe`
|
||||
deletes them. `bun run laptop status` shows what's running.
|
||||
|
||||
## 3. Plugin Studio (the public Studio, no sign-in)
|
||||
|
||||
```bash
|
||||
cd doxa-life && git switch research-gallery-plugin-studio
|
||||
bun run laptop plugin-studio
|
||||
```
|
||||
|
||||
- The first time is as for the subdomain route: `.env.laptop` needs `GIT_TOKEN`, and the first start takes 5-10
|
||||
minutes. `.env.laptop` also gets an `ADMIN_PASSWORD`.
|
||||
- It builds the same dx-maps image from `../doxa-maps/Dockerfile`, and runs dx-maps `development` in its public
|
||||
mode (`ACCESS=public`).
|
||||
- **Public mode is new.** If your dx-maps checkout's `deployment/cloud/README.md` has no "Public Studio" section,
|
||||
`development` doesn't have it yet: add `DXMAPS_BRANCH=repo/public-studio-mode` to `.env.laptop` until it lands.
|
||||
- It uses port 4616, as the subdomain route does, so run one of the two at a time (`bun run laptop down` first).
|
||||
|
||||
It starts two services, both on `127.0.0.1` only:
|
||||
|
||||
| Address | What |
|
||||
|---|---|
|
||||
| http://localhost:4614/ | this site, plugin-studio branch. The Research menu and `/regions` open the Studio; every map loads from the Studio's `/cdn` |
|
||||
| http://research.localhost:4616/ | the public Plugin Studio: every plugin, open to everyone, with no sign-in, as its public server will run it |
|
||||
| http://research.localhost:4616/admin/status and `/pb/_/` | publishing and PocketBase's dashboard: user `admin`, password `ADMIN_PASSWORD` from `.env.laptop` |
|
||||
|
||||
**How it is wired:**
|
||||
- This site reads both addresses per request, never at build time. The compose file sets them:
|
||||
`NUXT_PUBLIC_RESEARCH_GALLERY_URL=http://research.localhost:4616/` and
|
||||
`NUXT_PUBLIC_DX_MAPS_BASE=http://research.localhost:4616/cdn/dx-maps`.
|
||||
- Publishing is automatic. About a minute after the container starts, and whenever `main` moves, it publishes
|
||||
`main` to `/cdn`. The snippets point at `http://research.localhost:4616/cdn`.
|
||||
- `research.localhost` works as in the subdomain route (Safari may need the `/etc/hosts` line).
|
||||
|
||||
**Stop:** `bun run laptop down` (data kept; `--wipe` deletes it).
|
||||
|
||||
## What "working" looks like
|
||||
|
||||
- **`/embed-test`:** the production cards mount and draw their maps, with 0 page errors and 0 iframes.
|
||||
`/ar/embed-test` runs the same test right to left.
|
||||
- **`/research/?tab=regions-dashboard`** opens the gallery on its Regions tab, and `/regions` redirects there.
|
||||
On the subdomain route that means `http://research.localhost:4615/?tab=regions-dashboard`.
|
||||
- **Headless**, dx-base's `check-embed-6way.mjs` (in the fleet's QA folder) checks, for every production plugin:
|
||||
the script, its integrity hash, its element, its page, CORS, and the copy-paste snippet. The label reads
|
||||
`<name>=<site origin>@<manifest URL>`:
|
||||
- drop-in: `drop-in=http://localhost:4611@http://localhost:4611/dx-maps/manifest.json`;
|
||||
- subdomain: `subdomain=http://research.localhost:4615@http://research.localhost:4615/dx-maps/manifest.json`;
|
||||
- Plugin Studio: `plugin-studio=http://localhost:4614@http://research.localhost:4616/cdn/dx-maps/manifest.json`.
|
||||
- The **snippet** passes only when the manifests carry the address they're served from:
|
||||
- the subdomain and Plugin Studio routes bake it in by themselves;
|
||||
- for the drop-in, regenerate the manifests as shown in 1.
|
||||
|
||||
## Without Docker, the subdomain route by hand (no PocketBase)
|
||||
|
||||
Two terminals. dx-maps serves its built folder (loopback only), and this site points its research links at it.
|
||||
|
||||
```bash
|
||||
cd doxa-maps && EMBED_BASE_URL=http://localhost:4610 bun run tree && PORT=4610 bun run serve # Terminal A
|
||||
cd doxa-life && git switch research-gallery-subdomain # Terminal B
|
||||
NUXT_PUBLIC_DX_MAPS_BASE=http://localhost:4610/dx-maps \
|
||||
NUXT_PUBLIC_RESEARCH_GALLERY_URL=http://research.localhost:4610/dx-maps/doxa-maps-spa/doxa-maps-spa/index.html \
|
||||
PORT=4613 bun run dev
|
||||
```
|
||||
|
||||
The dx-maps server does not list directories, so the gallery address ends in `/index.html`. Afterwards:
|
||||
`cd doxa-maps && git restore public`.
|
||||
|
||||
## Checked
|
||||
|
||||
The subdomain route was run on 2026-09-29 with this branch's `compose.laptop.yaml`.
|
||||
- Docker ran on a server, because the checking box has no Docker. Its ports were tunnelled to a Linux box's
|
||||
`localhost`, standing in for the laptop's browser.
|
||||
- The dx-maps image was built from `development`'s root `Dockerfile`. The container cloned `development` and, 2.5
|
||||
minutes after it started, published `main` (93061d2) by itself.
|
||||
|
||||
Results:
|
||||
- **20 of 20 route checks passed:**
|
||||
- the sign-in provider answers on the same address inside and outside;
|
||||
- a plain member is refused;
|
||||
- `designer` gets the Studio, but not the PocketBase dashboard or publishing;
|
||||
- `admin` gets all three;
|
||||
- PocketBase's team API is open, with sign-in through the team provider;
|
||||
- the research site serves the gallery at `/` and a manifest whose snippets point at
|
||||
`http://research.localhost:4615`;
|
||||
- `/regions` on this site goes to `http://research.localhost:4615/?tab=regions-dashboard`.
|
||||
- **`check-embed-6way` on `subdomain=http://research.localhost:4615@…/dx-maps/manifest.json`:** 7 of 7 production
|
||||
maps pass all 6 checks, the snippet included.
|
||||
- **Memory once running:** dx-maps 0.3 GB, this site 0.9 GB, the sign-in provider 0.15 GB. The first publish added
|
||||
about 1 GB for a minute.
|
||||
|
||||
**The Plugin Studio route** was checked in two halves on 2026-09-29:
|
||||
- the public Studio container (dx-maps `repo/public-studio-mode`, `ACCESS=public`) ran on a server, tunnelled as
|
||||
above;
|
||||
- this site's plugin-studio branch ran as a dev server beside it, with the two addresses above.
|
||||
|
||||
Results:
|
||||
- **`check-embed-6way` on `plugin-studio=http://localhost:4614@…/cdn/dx-maps/manifest.json`:** 7 of 7 production
|
||||
maps pass all 6 checks, the snippet included (dx-base).
|
||||
- **The public Studio's review (dx-base): PASS.** A visitor with no password reaches the Studio and the plugins'
|
||||
data, and nothing else. Publishing and PocketBase's dashboard ask for the admin password.
|
||||
- **Not yet run:** the one command end to end (`bun run laptop plugin-studio` starting both services). It is run
|
||||
before the Driver's own laptop run.
|
||||
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"prayForThem": "صلِّ من أجلهم",
|
||||
"adoptThem": "تبنَّهم",
|
||||
"adoptThem": "تَبنَّهم",
|
||||
"moreInfo": "مزيد من المعلومات",
|
||||
"zoomIn": "تكبير",
|
||||
"zoomOut": "تصغير",
|
||||
|
|
|
|||
|
|
@ -1,16 +1,17 @@
|
|||
{
|
||||
"title": {
|
||||
"prayer": "تقدم الصلاة",
|
||||
"engagement": "تقدم الانخراط",
|
||||
"adoption": "تقدم التبني",
|
||||
"prayer": "تقدُّم الصلاة",
|
||||
"engagement": "تقدُّم الانخراط",
|
||||
"adoption": "تقدُّم التبنّي",
|
||||
"languageFamilies": "العائلات اللغوية",
|
||||
"doxaRegions": "مناطق Doxa",
|
||||
"affinityBlocs": "كتل القرابة",
|
||||
"gospelResources": "موارد الإنجيل"
|
||||
},
|
||||
"header": {
|
||||
"default": "وسيلة الإيضاح",
|
||||
"collapsed": "وسيلة الإيضاح",
|
||||
"peopleGroupFallback": "مجموعة الشعب"
|
||||
"peopleGroupFallback": "مجموعة شعبية"
|
||||
},
|
||||
"prayer": {
|
||||
"needsPrayer": "لا أحد يصلّي",
|
||||
|
|
@ -18,15 +19,15 @@
|
|||
"fullPrayerCoverage": "أكثر من 100 شخص يصلّون"
|
||||
},
|
||||
"engagement": {
|
||||
"needsEngagement": "يحتاج إلى انخراط",
|
||||
"hasEngagement": "لديه انخراط"
|
||||
"needsEngagement": "غير مَخْدُومَة",
|
||||
"hasEngagement": "مَخْدُومَة"
|
||||
},
|
||||
"adoption": {
|
||||
"needsAdoption": "يحتاج إلى تبني",
|
||||
"hasAdoption": "لديه تبني"
|
||||
"needsAdoption": "تحتاج إلى تبنٍّ",
|
||||
"hasAdoption": "لديها تبنٍّ"
|
||||
},
|
||||
"columns": {
|
||||
"upgs": "UUPGs",
|
||||
"upgs": "UUPG",
|
||||
"population": "السكان"
|
||||
},
|
||||
"footer": {
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"header": "دورة الصلاة الحالية",
|
||||
"lap": "الدورة",
|
||||
"upgs": "UUPGs",
|
||||
"upgs": "UUPG",
|
||||
"separator": " من "
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
{
|
||||
"placeholder": "شعب، مكان، لغة، ديانة",
|
||||
"placeholder": "مجموعة شعبية، مكان، لغة، ديانة",
|
||||
"labels": {
|
||||
"people": "الشعب:",
|
||||
"people": "المجموعة الشعبية:",
|
||||
"place": "المكان:",
|
||||
"language": "اللغة:",
|
||||
"religion": "الديانة:"
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"prayForThem": "Für sie beten",
|
||||
"adoptThem": "Sie adoptieren",
|
||||
"adoptThem": "Adoptieren",
|
||||
"moreInfo": "Mehr Infos",
|
||||
"zoomIn": "Vergrößern",
|
||||
"zoomOut": "Verkleinern",
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
{
|
||||
"title": {
|
||||
"prayer": "Gebetsfortschritt",
|
||||
"engagement": "Engagement-Fortschritt",
|
||||
"engagement": "Fortschritt der Arbeit vor Ort",
|
||||
"adoption": "Adoptionsfortschritt",
|
||||
"languageFamilies": "Sprachfamilien",
|
||||
"doxaRegions": "Doxa-Regionen",
|
||||
|
|
@ -9,6 +9,7 @@
|
|||
"gospelResources": "Evangeliumsressourcen"
|
||||
},
|
||||
"header": {
|
||||
"default": "Legende",
|
||||
"collapsed": "Legende",
|
||||
"peopleGroupFallback": "Volksgruppe"
|
||||
},
|
||||
|
|
@ -18,15 +19,15 @@
|
|||
"fullPrayerCoverage": "100+ Menschen beten"
|
||||
},
|
||||
"engagement": {
|
||||
"needsEngagement": "Braucht Engagement",
|
||||
"hasEngagement": "Hat Engagement"
|
||||
"needsEngagement": "Unberührt",
|
||||
"hasEngagement": "Engagiert"
|
||||
},
|
||||
"adoption": {
|
||||
"needsAdoption": "Braucht Adoption",
|
||||
"hasAdoption": "Hat Adoption"
|
||||
"needsAdoption": "Wartet auf Adoption",
|
||||
"hasAdoption": "Adoptiert"
|
||||
},
|
||||
"columns": {
|
||||
"upgs": "UUPGs",
|
||||
"upgs": "VUVGs",
|
||||
"population": "Bevölkerung"
|
||||
},
|
||||
"footer": {
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"header": "AKTUELLE GEBETSRUNDE",
|
||||
"lap": "Runde",
|
||||
"upgs": "UUPGs",
|
||||
"upgs": "VUVGs",
|
||||
"separator": " von "
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
{
|
||||
"placeholder": "Volk, Ort, Sprache, Religion",
|
||||
"placeholder": "Volksgruppe, Ort, Sprache, Religion",
|
||||
"labels": {
|
||||
"people": "Volk:",
|
||||
"people": "Volksgruppe:",
|
||||
"place": "Ort:",
|
||||
"language": "Sprache:",
|
||||
"religion": "Religion:"
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
{
|
||||
"title": {
|
||||
"prayer": "Progreso de oración",
|
||||
"engagement": "Progreso de implicación",
|
||||
"engagement": "Progreso del compromiso",
|
||||
"adoption": "Progreso de adopción",
|
||||
"languageFamilies": "Familias lingüísticas",
|
||||
"doxaRegions": "Regiones Doxa",
|
||||
|
|
@ -9,8 +9,9 @@
|
|||
"gospelResources": "Recursos del Evangelio"
|
||||
},
|
||||
"header": {
|
||||
"default": "Leyenda",
|
||||
"collapsed": "Leyenda",
|
||||
"peopleGroupFallback": "Grupo de personas"
|
||||
"peopleGroupFallback": "Grupo étnico"
|
||||
},
|
||||
"prayer": {
|
||||
"needsPrayer": "Nadie orando",
|
||||
|
|
@ -18,15 +19,15 @@
|
|||
"fullPrayerCoverage": "100+ personas orando"
|
||||
},
|
||||
"engagement": {
|
||||
"needsEngagement": "Necesita implicación",
|
||||
"hasEngagement": "Tiene implicación"
|
||||
"needsEngagement": "No comprometido",
|
||||
"hasEngagement": "Comprometido"
|
||||
},
|
||||
"adoption": {
|
||||
"needsAdoption": "Necesita adopción",
|
||||
"hasAdoption": "Tiene adopción"
|
||||
"needsAdoption": "No adoptado",
|
||||
"hasAdoption": "Adoptado"
|
||||
},
|
||||
"columns": {
|
||||
"upgs": "UUPGs",
|
||||
"upgs": "GENANC",
|
||||
"population": "Población"
|
||||
},
|
||||
"footer": {
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"header": "VUELTA DE ORACIÓN ACTUAL",
|
||||
"lap": "Vuelta",
|
||||
"upgs": "UUPGs",
|
||||
"upgs": "GENANC",
|
||||
"separator": " de "
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
{
|
||||
"placeholder": "Pueblo, lugar, idioma, religión",
|
||||
"placeholder": "Grupo étnico, lugar, idioma, religión",
|
||||
"labels": {
|
||||
"people": "Pueblo:",
|
||||
"people": "Grupo étnico:",
|
||||
"place": "Lugar:",
|
||||
"language": "Idioma:",
|
||||
"religion": "Religión:"
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@
|
|||
"gospelResources": "Ressources de l'Évangile"
|
||||
},
|
||||
"header": {
|
||||
"default": "Légende",
|
||||
"collapsed": "Légende",
|
||||
"peopleGroupFallback": "Peuple"
|
||||
},
|
||||
|
|
@ -18,12 +19,12 @@
|
|||
"fullPrayerCoverage": "100+ personnes en prière"
|
||||
},
|
||||
"engagement": {
|
||||
"needsEngagement": "Besoin d'engagement",
|
||||
"hasEngagement": "Engagement en cours"
|
||||
"needsEngagement": "Non engagé",
|
||||
"hasEngagement": "Engagé"
|
||||
},
|
||||
"adoption": {
|
||||
"needsAdoption": "Besoin d'adoption",
|
||||
"hasAdoption": "Adoption en cours"
|
||||
"hasAdoption": "Adopté"
|
||||
},
|
||||
"columns": {
|
||||
"upgs": "UUPG",
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
{
|
||||
"backToLegend": "लेजेंड पर वापस जाएं",
|
||||
"backToLegend": "लेजेंड पर वापस जाएँ",
|
||||
"closeDetailView": "विवरण दृश्य बंद करें"
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,17 +1,17 @@
|
|||
{
|
||||
"prayForThem": "उनके लिए प्रार्थना करें",
|
||||
"adoptThem": "उन्हें गोद लें",
|
||||
"adoptThem": "उन्हें अपनाएँ",
|
||||
"moreInfo": "अधिक जानकारी",
|
||||
"zoomIn": "ज़ूम इन",
|
||||
"zoomOut": "ज़ूम आउट",
|
||||
"switchToLightMode": "लाइट मोड पर जाएं",
|
||||
"switchToDarkMode": "डार्क मोड पर जाएं",
|
||||
"switchToLightMode": "लाइट मोड पर जाएँ",
|
||||
"switchToDarkMode": "डार्क मोड पर जाएँ",
|
||||
"resetView": "दृश्य रीसेट करें",
|
||||
"toggleFullscreen": "फ़ुलस्क्रीन टॉगल करें",
|
||||
"aboutThisMap": "इस मानचित्र के बारे में",
|
||||
"closeMenu": "मेनू बंद करें",
|
||||
"reloadMap": "मानचित्र पुनः लोड करें",
|
||||
"showClusters": "क्लस्टर दिखाएं",
|
||||
"showClusters": "क्लस्टर दिखाएँ",
|
||||
"clusterSettings": "क्लस्टर सेटिंग्स",
|
||||
"startAutoFly": "ऑटो फ्लाई शुरू करें",
|
||||
"stopFlight": "उड़ान रोकें",
|
||||
|
|
|
|||
|
|
@ -1,16 +1,17 @@
|
|||
{
|
||||
"title": {
|
||||
"prayer": "प्रार्थना प्रगति",
|
||||
"engagement": "सहभागिता प्रगति",
|
||||
"prayer": "प्रार्थना की प्रगति",
|
||||
"engagement": "संलग्नता की प्रगति",
|
||||
"adoption": "गोद लेने की प्रगति",
|
||||
"languageFamilies": "भाषा परिवार",
|
||||
"doxaRegions": "Doxa क्षेत्र",
|
||||
"affinityBlocs": "समानता समूह",
|
||||
"doxaRegions": "DOXA क्षेत्र",
|
||||
"affinityBlocs": "आत्मीयता ब्लॉक",
|
||||
"gospelResources": "सुसमाचार संसाधन"
|
||||
},
|
||||
"header": {
|
||||
"collapsed": "किंवदंती",
|
||||
"peopleGroupFallback": "जनजाति समूह"
|
||||
"default": "लेजेंड",
|
||||
"collapsed": "लेजेंड",
|
||||
"peopleGroupFallback": "जनसमूह"
|
||||
},
|
||||
"prayer": {
|
||||
"needsPrayer": "कोई प्रार्थना नहीं कर रहा",
|
||||
|
|
@ -18,15 +19,15 @@
|
|||
"fullPrayerCoverage": "100+ लोग प्रार्थना कर रहे हैं"
|
||||
},
|
||||
"engagement": {
|
||||
"needsEngagement": "सहभागिता चाहिए",
|
||||
"hasEngagement": "सहभागिता है"
|
||||
"needsEngagement": "अनसंपर्कित",
|
||||
"hasEngagement": "संपर्कित"
|
||||
},
|
||||
"adoption": {
|
||||
"needsAdoption": "गोद लेना चाहिए",
|
||||
"needsAdoption": "गोद लेने की ज़रूरत",
|
||||
"hasAdoption": "गोद लिया गया"
|
||||
},
|
||||
"columns": {
|
||||
"upgs": "UUPGs",
|
||||
"upgs": "UUPG",
|
||||
"population": "जनसंख्या"
|
||||
},
|
||||
"footer": {
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
{
|
||||
"clusterByRegion": "Doxa क्षेत्र के अनुसार",
|
||||
"clusterByRegion": "DOXA क्षेत्र के अनुसार",
|
||||
"clusterByLanguageFamily": "भाषा परिवार के अनुसार",
|
||||
"clusterByGospelResource": "सुसमाचार संसाधन के अनुसार"
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"header": "वर्तमान प्रार्थना चक्र",
|
||||
"lap": "चक्र",
|
||||
"upgs": "UUPGs",
|
||||
"separator": " में से "
|
||||
"upgs": "UUPG",
|
||||
"separator": " / "
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
{
|
||||
"placeholder": "लोग, स्थान, भाषा, धर्म",
|
||||
"placeholder": "जनसमूह, स्थान, भाषा, धर्म",
|
||||
"labels": {
|
||||
"people": "लोग:",
|
||||
"people": "जनसमूह:",
|
||||
"place": "स्थान:",
|
||||
"language": "भाषा:",
|
||||
"religion": "धर्म:"
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
{
|
||||
"prayForThem": "Prega per loro",
|
||||
"adoptThem": "Adottali",
|
||||
"moreInfo": "Più informazioni",
|
||||
"moreInfo": "Maggiori informazioni",
|
||||
"zoomIn": "Ingrandisci",
|
||||
"zoomOut": "Riduci",
|
||||
"switchToLightMode": "Passa alla modalità chiara",
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
{
|
||||
"title": {
|
||||
"prayer": "Avanzamento della preghiera",
|
||||
"engagement": "Avanzamento dell'impegno",
|
||||
"engagement": "Avanzamento del coinvolgimento",
|
||||
"adoption": "Avanzamento dell'adozione",
|
||||
"languageFamilies": "Famiglie linguistiche",
|
||||
"doxaRegions": "Regioni Doxa",
|
||||
|
|
@ -9,24 +9,25 @@
|
|||
"gospelResources": "Risorse del Vangelo"
|
||||
},
|
||||
"header": {
|
||||
"default": "Legenda",
|
||||
"collapsed": "Legenda",
|
||||
"peopleGroupFallback": "Gruppo di persone"
|
||||
"peopleGroupFallback": "Gruppo etnico"
|
||||
},
|
||||
"prayer": {
|
||||
"needsPrayer": "Nessuno prega",
|
||||
"needsPrayer": "Nessuno in preghiera",
|
||||
"hasPrayer": "1+ persone in preghiera",
|
||||
"fullPrayerCoverage": "100+ persone in preghiera"
|
||||
},
|
||||
"engagement": {
|
||||
"needsEngagement": "Necessita impegno",
|
||||
"hasEngagement": "Ha impegno"
|
||||
"needsEngagement": "Non coinvolto",
|
||||
"hasEngagement": "Coinvolto"
|
||||
},
|
||||
"adoption": {
|
||||
"needsAdoption": "Necessita adozione",
|
||||
"hasAdoption": "Ha adozione"
|
||||
"needsAdoption": "Da adottare",
|
||||
"hasAdoption": "Adottato"
|
||||
},
|
||||
"columns": {
|
||||
"upgs": "UUPGs",
|
||||
"upgs": "UUPG",
|
||||
"population": "Popolazione"
|
||||
},
|
||||
"footer": {
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"header": "GIRO DI PREGHIERA ATTUALE",
|
||||
"lap": "Giro",
|
||||
"upgs": "UUPGs",
|
||||
"upgs": "UUPG",
|
||||
"separator": " di "
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
{
|
||||
"placeholder": "Popolo, luogo, lingua, religione",
|
||||
"placeholder": "Gruppo etnico, luogo, lingua, religione",
|
||||
"labels": {
|
||||
"people": "Popolo:",
|
||||
"people": "Gruppo etnico:",
|
||||
"place": "Luogo:",
|
||||
"language": "Lingua:",
|
||||
"religion": "Religione:"
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
{
|
||||
"backToLegend": "Voltar à legenda",
|
||||
"closeDetailView": "Fechar vista de detalhe"
|
||||
"closeDetailView": "Fechar visualização de detalhes"
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,13 +6,13 @@
|
|||
"zoomOut": "Reduzir",
|
||||
"switchToLightMode": "Mudar para modo claro",
|
||||
"switchToDarkMode": "Mudar para modo escuro",
|
||||
"resetView": "Repor vista",
|
||||
"toggleFullscreen": "Alternar ecrã inteiro",
|
||||
"resetView": "Redefinir visualização",
|
||||
"toggleFullscreen": "Alternar tela cheia",
|
||||
"aboutThisMap": "Sobre este mapa",
|
||||
"closeMenu": "Fechar menu",
|
||||
"reloadMap": "Recarregar mapa",
|
||||
"showClusters": "Mostrar clusters",
|
||||
"clusterSettings": "Definições de clusters",
|
||||
"clusterSettings": "Configurações de clusters",
|
||||
"startAutoFly": "Iniciar voo automático",
|
||||
"stopFlight": "Parar voo",
|
||||
"speedLabel": "Velocidade:",
|
||||
|
|
@ -21,5 +21,5 @@
|
|||
"normal": "Normal",
|
||||
"fast": "Rápida"
|
||||
},
|
||||
"shareEmbed": "Partilhar e incorporar"
|
||||
"shareEmbed": "Compartilhar e incorporar"
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
{
|
||||
"title": {
|
||||
"prayer": "Progresso da oração",
|
||||
"engagement": "Progresso do envolvimento",
|
||||
"engagement": "Progresso do engajamento",
|
||||
"adoption": "Progresso da adoção",
|
||||
"languageFamilies": "Famílias linguísticas",
|
||||
"doxaRegions": "Regiões Doxa",
|
||||
|
|
@ -9,8 +9,9 @@
|
|||
"gospelResources": "Recursos do Evangelho"
|
||||
},
|
||||
"header": {
|
||||
"default": "Legenda",
|
||||
"collapsed": "Legenda",
|
||||
"peopleGroupFallback": "Grupo de pessoas"
|
||||
"peopleGroupFallback": "Grupo étnico"
|
||||
},
|
||||
"prayer": {
|
||||
"needsPrayer": "Ninguém orando",
|
||||
|
|
@ -18,15 +19,15 @@
|
|||
"fullPrayerCoverage": "100+ pessoas orando"
|
||||
},
|
||||
"engagement": {
|
||||
"needsEngagement": "Precisa de envolvimento",
|
||||
"hasEngagement": "Tem envolvimento"
|
||||
"needsEngagement": "Não engajado",
|
||||
"hasEngagement": "Engajado"
|
||||
},
|
||||
"adoption": {
|
||||
"needsAdoption": "Precisa de adoção",
|
||||
"hasAdoption": "Tem adoção"
|
||||
},
|
||||
"columns": {
|
||||
"upgs": "UUPGs",
|
||||
"upgs": "PNANEs",
|
||||
"population": "População"
|
||||
},
|
||||
"footer": {
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"header": "VOLTA DE ORAÇÃO ATUAL",
|
||||
"lap": "Volta",
|
||||
"upgs": "UUPGs",
|
||||
"upgs": "PNANEs",
|
||||
"separator": " de "
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
{
|
||||
"placeholder": "Povo, local, língua, religião",
|
||||
"placeholder": "Grupo étnico, local, língua, religião",
|
||||
"labels": {
|
||||
"people": "Povo:",
|
||||
"people": "Grupo étnico:",
|
||||
"place": "Local:",
|
||||
"language": "Língua:",
|
||||
"religion": "Religião:"
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@
|
|||
"switchToLightMode": "Comută la modul luminos",
|
||||
"switchToDarkMode": "Comută la modul întunecat",
|
||||
"resetView": "Resetează vizualizarea",
|
||||
"toggleFullscreen": "Comută ecran complet",
|
||||
"toggleFullscreen": "Comută pe ecran complet",
|
||||
"aboutThisMap": "Despre această hartă",
|
||||
"closeMenu": "Închide meniul",
|
||||
"reloadMap": "Reîncarcă harta",
|
||||
|
|
|
|||
|
|
@ -1,16 +1,17 @@
|
|||
{
|
||||
"title": {
|
||||
"prayer": "Progresul rugăciunii",
|
||||
"engagement": "Progresul implicării",
|
||||
"adoption": "Progresul adopției",
|
||||
"engagement": "Progresul angajării misionare",
|
||||
"adoption": "Progresul adoptării",
|
||||
"languageFamilies": "Familii de limbi",
|
||||
"doxaRegions": "Regiuni Doxa",
|
||||
"affinityBlocs": "Blocuri de afinitate",
|
||||
"gospelResources": "Resurse ale Evangheliei"
|
||||
},
|
||||
"header": {
|
||||
"default": "Legendă",
|
||||
"collapsed": "Legendă",
|
||||
"peopleGroupFallback": "Grup de popoare"
|
||||
"peopleGroupFallback": "Grup etnolingvistic"
|
||||
},
|
||||
"prayer": {
|
||||
"needsPrayer": "Nimeni nu se roagă",
|
||||
|
|
@ -18,15 +19,15 @@
|
|||
"fullPrayerCoverage": "100+ persoane se roagă"
|
||||
},
|
||||
"engagement": {
|
||||
"needsEngagement": "Necesită implicare",
|
||||
"hasEngagement": "Are implicare"
|
||||
"needsEngagement": "Neangajat misionar",
|
||||
"hasEngagement": "Angajat misionar"
|
||||
},
|
||||
"adoption": {
|
||||
"needsAdoption": "Necesită adopție",
|
||||
"hasAdoption": "Are adopție"
|
||||
"needsAdoption": "Necesită adoptare",
|
||||
"hasAdoption": "Adoptat"
|
||||
},
|
||||
"columns": {
|
||||
"upgs": "UUPGs",
|
||||
"upgs": "UUPG-uri",
|
||||
"population": "Populație"
|
||||
},
|
||||
"footer": {
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"header": "TURUL DE RUGĂCIUNE CURENT",
|
||||
"header": "TURUL ACTUAL DE RUGĂCIUNE",
|
||||
"lap": "Tur",
|
||||
"upgs": "UUPGs",
|
||||
"upgs": "UUPG-uri",
|
||||
"separator": " din "
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
{
|
||||
"placeholder": "Popor, loc, limbă, religie",
|
||||
"placeholder": "Grup etnolingvistic, loc, limbă, religie",
|
||||
"labels": {
|
||||
"people": "Popor:",
|
||||
"people": "Grup etnolingvistic:",
|
||||
"place": "Loc:",
|
||||
"language": "Limbă:",
|
||||
"religion": "Religie:"
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue