read the glossary from pray.doxa.life instead of a vendored file

config/glossaries.ts was generated from the retired translation repo's DeepL
TSVs, so it had no source left and only the German, Spanish and Portuguese
rows had been hand-patched. Both it and its build script are gone.

- fetch GET /api/glossary/{lang} at runtime, cached ten minutes, serving the
  last good answer when the request fails and an empty one when it never
  succeeded. A reviewer's correction now reaches auto-translate without a
  deploy here
- carry the glossary's notes as well as its terms: register, acronym policy
  and number format, placed after the term list so a rule about inflection
  governs the pairs above it
- glossary_used on the MCP translate tool now means the locale's terminology
  was available, and reads false for a language whose glossary has not been
  started
- add /add-language and /sync-language skills for the site strings, the map
  widget locales and bundles, the /terms edition, and the CMS pages
This commit is contained in:
corsacca 2026-09-18 10:06:13 +01:00
parent 10f63df2eb
commit a994baec4f
10 changed files with 365 additions and 957 deletions

View 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 /terms 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 `/terms` edition
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/terms.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}/terms` 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.

View file

@ -0,0 +1,105 @@
---
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 /terms 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.
## 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 `/terms` edition
`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.

2
.gitignore vendored
View file

@ -49,5 +49,5 @@ embeddables/micro-frontends/_template/
package-lock.json
plans
.claude
.claude/settings.local.json
.vscode

View file

@ -2,8 +2,10 @@
// 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'

View file

@ -1,888 +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", "unberührte Volksgruppe"],
["unengaged people groups", "unberührte Volksgruppen"],
["unengaged unreached people group", "völlig unerreichte Volksgruppe (VUVG)"],
["under-engaged", "am wenigsten erreicht"],
["frontier people group", "Frontier-Volksgruppe"],
["frontier people groups", "Frontier-Volksgruppen"],
["ethnolinguistic group", "ethno-linguistische Gruppe"],
["unreached", "unerreicht"],
["unengaged", "unberührt"],
["engaged", "engagiert"],
["engagement", "missionarische Arbeit vor Ort"],
["fruitful engagement", "fruchtbare Arbeit vor Ort"],
["gospel access", "Zugang zum Evangelium"],
["gospel engagement", "Evangelisationsarbeit"],
["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", "vor Ort ansässige Mitarbeiter/innen"],
["cross-cultural workers", "kulturübergreifende Mitarbeiter/innen"],
["apostolic effort", "apostolischer Einsatz"],
["pioneer work", "Pionierarbeit"],
["heart language", "Herzenssprache"],
["movement to Jesus", "Bewegung zu Jesus hin"],
["nonresident partners", "Projektpartner"],
["broader engagement", "weiteres Engagement"],
["diaspora", "Diaspora"],
["daily prayer", "tägliches Gebet"],
["24-hour prayer coverage", "24-Stunden-Gebetsabdeckung"],
["intercessor", "Fürbitter/in"],
["intercessors", "Fürbitter/innen"],
["intercessory prayer", "Fürbittegebet"],
["prayer points", "Gebetsanliegen"],
["daily prayer guide", "täglicher Gebetsleitfaden"],
["prayer prepares the way", "Gebet bahnt 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", "Sendeorganisation"],
["sending agencies", "Sendeorganisationen"],
["our gift to Jesus", "unser Geschenk an Jesus"],
["DOXA partnership missionaries", "DOXA-Partnermissionare"],
["every tribe, tongue, people, and nation", "jeder Stamm, jede Zunge, 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", "eine missionarische Arbeit vor Ort beginnen"],
["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 no comprometido (GENANC)"],
["under-engaged", "poco comprometido"],
["frontier people group", "grupo fronterizo"],
["frontier people groups", "grupos fronterizos"],
["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 (MPI)"],
["church planting", "plantación de iglesias"],
["indigenous church", "iglesia autóctona"],
["indigenous churches", "iglesias autóctonas"],
["self-propagating", "autopropagador"],
["self-governing", "autogobernado"],
["self-supporting", "autosustentado"],
["self-theologizing", "autoteologizante"],
["self-missionizing", "automisionero"],
["residential engagement", "compromiso residencial"],
["workers in residence", "trabajadores residentes"],
["cross-cultural workers", "obreros transculturales"],
["apostolic effort", "esfuerzo apostólico"],
["pioneer work", "trabajo pionero"],
["heart language", "lengua del corazón"],
["movement to Jesus", "movimiento hacia Jesús"],
["nonresident partners", "asociados no residentes"],
["broader engagement", "compromiso más amplio"],
["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 intercesora"],
["prayer points", "motivos de oración"],
["daily prayer guide", "guía diaria de oración"],
["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 enviadora"],
["sending agencies", "agencias enviadoras"],
["our gift to Jesus", "nuestro regalo para Jesús"],
["DOXA partnership missionaries", "misioneros asociados a DOXA"],
["every tribe, tongue, people, and nation", "cada tribu, lengua, pueblo y nación"],
["make disciples of all the nations", "hacer discípulos a todas las naciones"],
["disciple", "discípulo"],
["disciples", "discípulos"],
["baptized disciples", "discípulos bautizados"],
["culturally appropriate", "culturalmente apropiado"],
["self-sustaining churches", "iglesias autosustentables"],
["spiritual generations", "generaciones espirituales"],
["abide in Jesus", "permanecer en Jesús"],
["pray without ceasing", "orar sin cesar"],
["deny yourself", "niégate a ti mismo"],
["engage the regions beyond", "involucrarse en las regiones 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", "Cena del Señor"],
["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", "GENANC"],
["World Assemblies of God Fellowship", "Fraternidad Mundial de las Asambleas de Dios"],
["champion", "defensor"],
["champions", "defensores"],
["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", "Fraternité 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 (PNANE)"],
["under-engaged", "sub-engajado"],
["frontier people group", "povo de fronteira"],
["frontier people groups", "povos 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 do evangelho"],
["the gospel", "o evangelho"],
["church-planting movement", "movimento de plantação de igrejas (MPI)"],
["church planting", "plantação de igrejas"],
["indigenous church", "igreja autóctone"],
["indigenous churches", "igrejas autóctones"],
["self-propagating", "autopropagador"],
["self-governing", "autogovernado"],
["self-supporting", "autossustentado"],
["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 do coração"],
["movement to Jesus", "movimento em direção a Jesus"],
["nonresident partners", "parceiros não residentes"],
["broader engagement", "engajamento mais amplo"],
["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", "pontos 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, doar e enviar"],
["mobilize", "mobilizar"],
["mobilization", "mobilização"],
["sending agency", "secretaria de missões"],
["sending agencies", "secretarias de missões"],
["our gift to Jesus", "nossa oferta a Jesus"],
["DOXA partnership missionaries", "missionários parceiros de DOXA"],
["every tribe, tongue, people, and nation", "todas as tribos, línguas, povos e nações"],
["make disciples of all the nations", "fazer 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", "permanecer em Jesus"],
["pray without ceasing", "orar sem cessar"],
["deny yourself", "renunciar a si mesmo"],
["engage the regions beyond", "engajar as regiões 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"],
["UUPG", "PNANE"],
["UPG", "PNA"],
["World Assemblies of God Fellowship", "Comunhão das Assembléias de Deus Mundial"],
["champion", "defensor"],
["champions", "defensores"],
["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", "注册"]
]
}

View file

@ -1,47 +0,0 @@
/**
* Generates config/glossaries.ts from the translation repo's glossary TSVs
* (../translation/deepl-glossaries/*.tsv). The generated module is committed
* so production builds don't need the translation repo checked out.
*
* Run after updating the TSVs: bun scripts/build-glossaries.ts
*/
import { readdirSync, readFileSync, writeFileSync } from 'node:fs'
import { join } from 'node:path'
const sourceDir = join(import.meta.dir, '../../translation/deepl-glossaries')
const outFile = join(import.meta.dir, '../config/glossaries.ts')
const glossaries: Record<string, Array<[string, string]>> = {}
for (const file of readdirSync(sourceDir).sort()) {
if (!file.endsWith('.tsv')) continue
const code = file.replace(/\.tsv$/, '')
const pairs: Array<[string, string]> = []
for (const line of readFileSync(join(sourceDir, file), 'utf8').split('\n')) {
const trimmed = line.trim()
if (!trimmed) continue
const [source, target] = trimmed.split('\t')
if (source && target) pairs.push([source.trim(), target.trim()])
}
glossaries[code] = pairs
}
const entries = Object.entries(glossaries)
.map(([code, pairs]) => {
const rows = pairs.map(([s, t]) => ` [${JSON.stringify(s)}, ${JSON.stringify(t)}]`).join(',\n')
return ` ${code}: [\n${rows}\n ]`
})
.join(',\n')
const output = `// 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]>> = {
${entries}
}
`
writeFileSync(outFile, output)
console.log(`Wrote ${Object.keys(glossaries).length} glossaries (${Object.values(glossaries).reduce((n, p) => n + p.length, 0)} terms) to config/glossaries.ts`)

View file

@ -1,7 +1,7 @@
// LLM text-translation tool. Generic primitive — Claude composes
// with upsert_page_translation when applying translations to pages.
//
// The vendored glossary for each target locale is always injected into
// The approved terminology for each target locale is always injected into
// the translation prompt, keeping MCP-driven translations terminologically
// consistent with admin auto-translates.
@ -18,7 +18,7 @@ Inputs:
- \`source_locale\`: defaults to "en"; must be one of the site's enabled locales.
- \`target_locales\`: array of locale codes to translate into; each must be enabled and different from the source.
Output: \`translations: [{locale, text, glossary_used}]\`. \`glossary_used\` is true when a per-locale terminology glossary was applied (consistent with admin auto-translate behavior). After this returns, embed each translated text into the corresponding locale's page via upsert_page_translation.
Output: \`translations: [{locale, text, glossary_used}]\`. \`glossary_used\` is true when the locale's approved DOXA terminology was applied (consistent with admin auto-translate behavior); it is false for a locale whose glossary has not been started yet. After this returns, embed each translated text into the corresponding locale's page via upsert_page_translation.
Limits: 100 KB per call. For longer content, split into sections and translate each separately.`

View file

@ -1,13 +1,14 @@
// LLM text-translation service — the canonical primitive both the
// MCP translate_text tool and the admin batch-translate flow share.
//
// The per-locale glossary vendored in config/glossaries.ts is injected
// into every translation prompt, so the terminology stays consistent
// with admin auto-translates and with the translation/ glossaries repo.
// Every translation prompt carries the target locale's approved terminology,
// read at runtime from the glossary published by pray.doxa.life, so the
// wording here matches the prayer site and the mobile app.
import type { H3Error } from 'h3'
import { translateTexts, translateTiptapContent, isTranslationConfigured } from '../utils/translate'
import { OpenRouterError, hasGlossary } from '../utils/openrouter'
import { OpenRouterError } from '../utils/openrouter'
import { hasGlossary } from '../utils/glossary'
import { ENABLED_LANGUAGE_CODES } from '~~/config/languages'
import { db } from '../utils/database'
import {
@ -84,7 +85,7 @@ export async function translateText(input: TranslateTextInput): Promise<Translat
return {
locale,
text: out[0] ?? '',
glossary_used: hasGlossary(locale)
glossary_used: await hasGlossary(locale)
}
})
)

115
server/utils/glossary.ts Normal file
View file

@ -0,0 +1,115 @@
/**
* The approved DOXA terminology, read from pray.doxa.life.
*
* The glossary is maintained in the campaigns server's admin, where reviewers
* confirm each term through a magic link, and published at
* `GET /api/glossary/{lang}`. This site reads it at runtime rather than
* vendoring a copy, so a reviewer's correction reaches the next translation
* without a deploy here.
*
* Nothing in this module throws: a translation with no glossary is worse than
* one with it, but far better than a failed request, so a fetch that fails
* serves the last good answer and otherwise an empty one.
*/
export interface GlossaryPair {
term: string
value: string
}
export interface Glossary {
pairs: GlossaryPair[]
/** The language's rules: register, acronym policy, numerals, script and names. */
notes: string
}
const EMPTY: Glossary = { pairs: [], notes: '' }
/** How long a language's glossary is reused before it is fetched again. */
const CACHE_MS = 10 * 60 * 1000
/**
* How long a failure or a language with no glossary is remembered. Short
* enough that starting a language upstream shows up here the same morning,
* long enough that a locale nobody has a glossary for is not refetched on
* every fragment of a page translation.
*/
const MISS_CACHE_MS = 60 * 1000
interface CacheEntry {
glossary: Glossary
expires: number
}
const cache = new Map<string, CacheEntry>()
interface PublishedGlossary {
notes?: string
terms?: Array<{ term?: string, translation?: string }>
}
/**
* The terminology for one language. Cached in the instance; call it per request
* rather than holding the result.
*/
export async function getGlossary(code: string): Promise<Glossary> {
const cached = cache.get(code)
if (cached && cached.expires > Date.now()) return cached.glossary
const base = String(useRuntimeConfig().prayBaseUrl || '').replace(/\/$/, '')
if (!base) return cached?.glossary ?? EMPTY
try {
const data = await $fetch<PublishedGlossary>(`${base}/api/glossary/${encodeURIComponent(code)}`, {
timeout: 5000,
retry: 1
})
const pairs = (data?.terms || [])
.filter(entry => entry?.term && entry?.translation)
.map(entry => ({ term: String(entry.term), value: String(entry.translation) }))
const glossary: Glossary = { pairs, notes: String(data?.notes || '') }
cache.set(code, { glossary, expires: Date.now() + CACHE_MS })
return glossary
} catch (error) {
// A 404 is the ordinary answer for a language whose glossary has not been
// started yet, so it is cached briefly rather than logged as a fault.
const failure = error as { statusCode?: number, response?: { status?: number }, message?: string }
const status = failure?.statusCode ?? failure?.response?.status
if (status !== 404) {
console.warn(`[Glossary] could not read the ${code} glossary from ${base}: ${failure?.message}`)
}
const glossary = cached?.glossary ?? EMPTY
cache.set(code, { glossary, expires: Date.now() + MISS_CACHE_MS })
return glossary
}
}
/** Whether approved terminology was available to steer a translation. */
export async function hasGlossary(code: string): Promise<boolean> {
const glossary = await getGlossary(code)
return glossary.pairs.length > 0
}
/** Drop the cached copies so the next translation refetches. */
export function clearGlossaryCache(code?: string): void {
if (code) cache.delete(code)
else cache.clear()
}
/** The glossary as the two blocks a translation prompt carries. */
export function renderGlossaryPrompt(glossary: Glossary, targetLanguage: string): string {
const pairs = glossary.pairs.map(({ term, value }) => `${term} → ${value}`).join('\n')
const terms = glossary.pairs.length
? `\nGlossary — always use these translations, inflected correctly for the surrounding grammar:\n${pairs}\n`
: ''
// After the terms, so a rule about register or inflection governs the bare
// pairs above it.
const notes = glossary.notes.trim()
? `\nRules for ${targetLanguage}, from the reviewer who approved the glossary. Follow them everywhere they apply:\n${glossary.notes.trim()}\n`
: ''
return `${terms}${notes}`
}

View file

@ -8,7 +8,7 @@
*/
import { getLanguage } from '~~/config/languages'
import { GLOSSARIES } from '~~/config/glossaries'
import { getGlossary, renderGlossaryPrompt, type Glossary } from './glossary'
import { getSetting } from './site-settings'
const DEFAULT_TRANSLATION_MODEL = 'anthropic/claude-opus-5'
@ -41,19 +41,16 @@ function promptLanguageName(code: string): string {
return lang?.translationName || lang?.name || code
}
/** Whether a curated terminology glossary is injected for this language. */
export function hasGlossary(code: string): boolean {
return Boolean(GLOSSARIES[code]?.length)
}
function buildSystemPrompt(targetLanguage: string, sourceLanguage: string, fragmentCount: number): string {
function buildSystemPrompt(
targetLanguage: string,
sourceLanguage: string,
fragmentCount: number,
glossary: Glossary
): string {
const source = promptLanguageName(sourceLanguage)
const target = promptLanguageName(targetLanguage)
const glossary = GLOSSARIES[targetLanguage]
const glossaryBlock = glossary?.length
? `\nGlossary — always use these translations, inflected correctly for the surrounding grammar:\n${glossary.map(([s, t]) => `${s} → ${t}`).join('\n')}\n`
: ''
const glossaryBlock = renderGlossaryPrompt(glossary, target)
return `You are a professional translator for DOXA, a Christian mission organization mobilizing prayer for unreached people groups. Translate marketing and informational website copy from ${source} into ${target}.
@ -140,11 +137,12 @@ export async function openrouterTranslateTexts(
}
const model = await getTranslationModel(targetLanguage)
const glossary = await getGlossary(targetLanguage)
const body = JSON.stringify({
model,
messages: [
{ role: 'system', content: buildSystemPrompt(targetLanguage, sourceLanguage, texts.length) },
{ role: 'system', content: buildSystemPrompt(targetLanguage, sourceLanguage, texts.length, glossary) },
{ role: 'user', content: JSON.stringify({ fragments: texts }) }
],
response_format: { type: 'json_object' },