# WTHB TOC Language Pipeline

> How the German webtrees manual TOC is produced (GenWiki → pywikibot → generation → external repo / Pages / Weblate → module)

---

## Overview

The **`linkenhancer-wthb-toc-lang`** package delivers the table of contents (TOC) of the German webtrees manual — and its translations — to the [WTHB help feature](../features/wthb). Its production is a **round trip** that lives entirely outside the webtrees install: it reads the manual from **GenWiki**, regenerates the TOC, writes the result back to GenWiki as a **MediaWiki template**, and — in parallel — ships the structured data to an **external Codeberg repo** that feeds **Codeberg Pages**, **Weblate** (translations) and, finally, the **module**. This page documents the *production* side; the *consumer* side (cache, CLI, rendering) is covered on the [WTHB feature page](../features/wthb) and the [CLI scripts](cli-scripts) page.

### Ressources

- GenWiki German Webtrees Manual: <https://wiki.genealogy.net/Webtrees_Handbuch>
- Code Repositories:
  - Module: <https://codeberg.org/bschwede/linkenhancer>
  - TOC-Translation: <https://codeberg.org/bschwede/linkenhancer-wthb-toc-lang>
- Weblate translation component: <https://translate.codeberg.org/projects/wt-modules/linkenhancer-wthb-toc>
- GenWiki Bot project: <https://gitlab.genealogy.net/genwiki/wikibots> (gw-skripte / [pywikibot documentation](https://doc.wikimedia.org/pywikibot/stable/introduction.html))

## Pipeline

The round trip has two halves: the **GenWiki round trip** (read the manual → generate → write the TOC template back) and the **delivery pipeline** (structured data → external repo → Pages / Weblate → module).

The GenWiki round trip:




<pre class="mermaid">flowchart TB
    subgraph HOST[&#34;🖥️ Host · gw-skripte/&#34;]
        ORCH[&#34;`🚦 **wt-maintain.sh**&lt;br/&gt;*Orchestration*`&#34;]
        PREAD[&#34;`🤖 **pywikibot** · *wt-maintain.py*&lt;br/&gt;SectionsExportBot — *READ*`&#34;]
        GEN[&#34;`⚙️ **wt-gen-toc.py** *(pandas)*`&#34;]
        PREP[&#34;`📄 *pagefromfile file*&lt;br/&gt;vorlage_wt-verzeichnis-toc.txt`&#34;]
        PWRITE[&#34;`🤖 **pywikibot** · *pagefromfile*&lt;br/&gt;*WRITE* — Bot-Summary`&#34;]
    end

    GW[&#34;`📖 **GenWiki** · wiki.genealogy.net&lt;br/&gt;*webtrees handbook pages*`&#34;]
    CSV[&#34;`📄 *3 CSV*&lt;br/&gt;pageinfo · sections · images`&#34;]
    OUT[&#34;`📦 *Outputs*&lt;br/&gt;wthb-toc.wiki · .html · .json · de.json`&#34;]
    TPL[&#34;`📖 **Vorlage:WT-Verzeichnis-TOC**&lt;br/&gt;*noinclude &#43; includeonly TOC*`&#34;]
    API[&#34;`🔍 *API action=parse* → HTML&lt;br/&gt;(curl &#43; jq)`&#34;]

    GW --&gt;|&#34;allpages prefix &#39;Webtrees Handbuch&#39;&lt;br/&gt;API parse/sections &#43; imagelinks&#34;| PREAD
    ORCH -.-&gt;|&#34;drives&#34;| PREAD
    PREAD --&gt; CSV
    CSV --&gt;|&#34;&#43; wthb-pageinfo_ext.csv (target)&#34;| GEN
    GEN --&gt; OUT
    OUT --&gt; PREP
    PREP --&gt; PWRITE
    PWRITE --&gt;|&#34;pagefromfile -force&#34;| TPL
    TPL --&gt;|&#34;curl API parse&#34;| API

    classDef srcStyle fill:#e3f2fd,stroke:#1565c0,stroke-width:2px
    classDef coreStyle fill:#ede7f6,stroke:#5e35b1,stroke-width:2px
    classDef okStyle fill:#e8f5e9,stroke:#2e7d32,stroke-width:2px
    classDef pwbStyle fill:#fff8e1,stroke:#f57f17,stroke-width:2px
    classDef targetStyle fill:#fce4ec,stroke:#ad1457,stroke-width:2px

    class GW srcStyle
    class ORCH,GEN coreStyle
    class CSV,OUT,API okStyle
    class PREAD,PWRITE pwbStyle
    class TPL targetStyle
</pre>

## Orchestration — `wt-maintain.sh`

Everything runs from one host script (in `gw-skripte/`):

```bash
wt-maintain.sh <wthb-pageinfo_ext.csv> <DATADIR>
```

It depends on `setenv.sh` exporting `PWB_PY`, `PWB_CONF` and `SCRIPTDIR`, and drives these steps in order:

1. query the GenWiki data (pywikibot READ)
2. generate the TOC
3. build the [`pagefromfile`](https://doc.wikimedia.org/pywikibot/stable/scripts_ref/scripts.html#module-scripts.pagefromfile) wrapper file
4. write the template back to GenWiki (pywikibot WRITE)
5. parse-check the rendered template (curl + jq)
6. deploy the JSON to the external repo
7. downstream: repo CI, Weblate and the module pick the data up

## GenWiki data query (pywikibot READ)

Step 1 is `wt-maintain.py`, a pywikibot bot (`SectionsExportBot`, extending `ExistingPageBot`). It calls `site.login()`, iterates `allpages(prefix="Webtrees Handbuch")` and, per page, queries the [MediaWiki API](https://www.mediawiki.org/wiki/API:Action_API) (`action=parse&prop=sections`) plus `imagelinks()` (FilePage info). \
The result is **three CSV files**:
1. `wthb-pageinfo.csv`,
2. `wthb-sections.csv` and
3. `wthb-images.csv`.

Two manual follow-ups remain (per the script header): (b) maintaining the image directory and (c) adding the images to the `Kategorie:Webtrees` category — done by hand (helper: `wt-webtrees-cat-files.sh`).

## TOC generation — `wt-gen-toc.py`

Step 2 is a pandas script that combines the **IST** state (the three CSVs) with the **SOLL** target structure in `wthb-pageinfo_ext.csv`. `classify_prefix()` assigns chapter/section prefixes. It writes four outputs:

- `wthb-toc.wiki` — the MediaWiki TOC source
- `wthb-toc.json` — the structured data the module consumes
- `de.json` — the German language file for Weblate
- `wthb-toc.html` — a rendered HTML copy (legacy/parallel — the current consumer renders from **JSON**)

## GenWiki template (pywikibot WRITE)

Steps 3–4 wrap the generated TOC in the MediaWiki template [**`Vorlage:WT-Verzeichnis-TOC`**](https://wiki.genealogy.net/Vorlage:WT-Verzeichnis-TOC) and write it back:

- the `pagefromfile` file combines a `<noinclude>` part (`{{Dokumentation}}` + `[[Kategorie:Webtrees]]`) with an `<includeonly>` part (`Stand: <datum>` + `<div class="wthbtoc">…</div>`).
- `pywikibot pagefromfile -force -pt:1 -summary:"Bot: Webtrees Handbuch Inhaltsverzeichnis aktualisiert"` performs the write.

Step 5 verifies the result by parsing it back through the GenWiki API (`action=parse&format=json`) and extracting the HTML with `jq -r '.parse.text["*"]'`.

> **Note:** this is *automatic* writing to GenWiki via pywikibot — the opposite of the "produce review output, no bot" approach used for the GenWiki help-docs export. `Vorlage:WT-Verzeichnis-TOC` and `Kategorie:Webtrees` are GenWiki-specific German names and are kept verbatim.

## External repo, CI & Pages

The second half of the pipeline (step 6 onward) ships the structured data out of the host:




<pre class="mermaid">flowchart TB
    OUT[&#34;`📦 *Outputs*&lt;br/&gt;wthb-toc.json &#43; de.json`&#34;]
    DEP[&#34;`🚀 **wt-deploy-toc-lang.sh**`&#34;]

    subgraph EXTERNAL[&#34;🌐 External infrastructure&#34;]
        REPO[&#34;`📦 **linkenhancer-wthb-toc-lang**&lt;br/&gt;(Codeberg)`&#34;]
        META[&#34;`🔧 *tools/gen_meta.py*&lt;br/&gt;languages.json &#43; version.json`&#34;]
        CI[&#34;`⚙️ *CI regen-meta.yml*&lt;br/&gt;gen_toc_html.py`&#34;]
        PG[&#34;`🌐 **Codeberg Pages**`&#34;]
        WLB[&#34;`🌐 **Weblate** · linkenhancer/wthb-toc`&#34;]
        TNG[&#34;🗝 en.json · fr.json · …&#34;]
    end

    subgraph MODULE[&#34;📦 Module (linkenhancer)&#34;]
        SVC[&#34;`**WthbTocService**`&#34;]
        DS[&#34;`💾 *data/…/wthb-toc-lang/*&lt;br/&gt;2-Layer-Cache`&#34;]
        RDR[&#34;`📄 **help-wthb-toc.phtml**&lt;br/&gt;TOC-Modal`&#34;]
    end

    OUT --&gt;|&#34;cp wthb-toc.json &#43; de.json&#34;| DEP
    DEP --&gt;|&#34;git add / commit / push&#34;| REPO
    REPO --&gt;|&#34;regen meta&#34;| META
    REPO --&gt; CI --&gt; PG
    REPO --&gt;|&#34;de.json (Source)&#34;| WLB
    WLB --&gt; TNG
    TNG --&gt;|&#34;[lang].json&#34;| REPO
    PG --&gt;|&#34;fetch JSON&#34;| MODULE
    SVC --&gt; DS --&gt; RDR

    classDef coreStyle fill:#ede7f6,stroke:#5e35b1,stroke-width:2px
    classDef okStyle fill:#e8f5e9,stroke:#2e7d32,stroke-width:2px
    classDef queueStyle fill:#fff3e0,stroke:#e65100,stroke-width:2px

    class OUT okStyle
    class DEP,REPO,META,CI,SVC coreStyle
    class PG,TNG,DS,RDR okStyle
    class WLB queueStyle
</pre>

- **`wt-deploy-toc-lang.sh`** copies `wthb-toc.json` and `de.json` into the `linkenhancer-wthb-toc-lang` repo, runs `tools/gen_meta.py` (regenerates `languages.json` + `version.json`) and does `git add/commit/push`. It is standalone-callable and **soft-skips** (warning + `exit 0`) when the repo or JSON is missing, so it never aborts the `set -e` orchestrator.
- **Repo CI** (`regen-meta.yml`) runs `gen_toc_html.py` and publishes to **Codeberg Pages**.

## Weblate

The repo's `de.json` is the **source** of the Weblate component **`wt-modules/linkenhancer-wthb-toc`**; the other `[lang].json` files are its translation targets. Translations flow back into the repo and are served via Codeberg Pages.

## Consumer (module)

Briefly — see the [WTHB feature page](../features/wthb) and the [CLI scripts](cli-scripts) page for details:

- <a href="https://codeberg.org/bschwede/linkenhancer/src/branch/main/src/Services/WthbTocService.php" target="_blank" rel="noopener"><code>WthbTocService.php</code></a>
 pulls the language JSON from Codeberg Pages and serves it through a **two-layer cache**.
- <a href="https://codeberg.org/bschwede/linkenhancer/src/branch/main/cli/refresh-wthb-toc.php" target="_blank" rel="noopener"><code>refresh-wthb-toc.php</code></a>
 (and `cli/validate-wthb-toc.php`) refresh and verify that cache, typically on a cron schedule.
- <a href="https://codeberg.org/bschwede/linkenhancer/src/branch/main/resources/views/help-wthb-toc.phtml" target="_blank" rel="noopener"><code>help-wthb-toc.phtml</code></a>
 renders the TOC in the help dialog.

## Configuration & prerequisites

- `setenv.sh` — exports `PWB_PY`, `PWB_CONF`, `SCRIPTDIR`.
- pywikibot config — `user-config-test.py` / `user-config-prod.py`.
- `wthb-toc-lang.env` — `TOC_LANG_REPO=$HOME/dev/linkenhancer-wthb-toc-lang`, `TOC_LANG_DATADIR=$HOME/dev/wthb-toc-datadir`.
- Prerequisites: pywikibot, pandas, jq, python3.

## Ops & caveats

- **Manual image follow-up** — the image directory and `Kategorie:Webtrees` must be maintained by hand.
- **`pagefromfile` login** — the script comment notes that `site.login()` may need to be inserted into `pagefromfile.py`.
- **Soft-skip deploy** — a missing repo or JSON is a warning, not a failure (keeps `set -e` safe).
