Skip to content

Development.de

Doug Blank edited this page Sep 20, 2026 · 1 revision

🌐 English

Entwicklung

Diese Seite behandelt das Einrichten einer lokalen Entwicklungsumgebung für app/ selbst — im Gegensatz zu Installation (die verpackte Desktop-Version ausführen) oder Bereitstellung (die containerisierte Produktionsform ausführen). Zuerst Architektur lesen, wie die Teile zusammenpassen.

Erste Schritte

npm install                 # installiert den Workspace (app/ + packages/gramps-date)
cp app/.env.example app/.env.local   # zeigt auf eine laufende gramps-web-api-Instanz
npm run dev -w app          # startet den Vite-Entwicklungsserver

app/ braucht ein echtes gramps-web-api-Backend, mit dem es sprechen kann — es ist ein reiner Client, es gibt keinen Mock-Daten-Modus. Die leichteste Option ist dev-fixtures/layer2-local-cache/api-fixture-example/setup.sh (siehe Dev-Fixtures unten).

Jede Fixture führt gramps-web-api aus einem Quellcode-Checkout in derselben Python-Umgebung wie das Fixture-Skript aus, diese Umgebung braucht also:

pip install -e ~/gramps/gramps --no-deps          # Gramps selbst
pip install -e ~/gramps/gramps-web-api --no-deps  # + dessen Abhängigkeiten, siehe unten
python3 deploy/webapi-requirements.py ~/gramps/gramps-web-api/pyproject.toml \
  | pip install -r /dev/stdin

Die const.py von gramps-web-api macht beim Import gi.require_version("Gtk", "3.0"), echtes PyGObject und die GTK3-Typelibs müssen also vorhanden sein (apt install python3-gi gir1.2-gtk-3.0, oder conda install -c conda-forge pygobject gtk3); PyICU ist optional, unterdrückt aber eine Lokalisierungswarnung und behebt die Namenssortierung.

Zu beachten: die /api/<type>/query/-Endpunkte, auf denen app/ aufbaut, landeten im master von gramps-project/gramps-web-api — ein älterer Fork oder Branch liefert bei jedem davon einen 404.

Dev-Fixtures

dev-fixtures/ enthält echte gramps-web-api-Backends, um app/ lokal dagegen laufen zu lassen. Sie sind nicht Teil des ausgelieferten Produkts — nur das, was lokale Entwicklung ohne von Hand konfigurierten eigenen Server erst möglich macht. Ein Skript lesen, bevor es ausgeführt wird — keines von ihnen ist idempotent gegenüber einem bereits befüllten Stammbaum. Jede Fixture meldet sich als gramps/gramps an.

  • layer2-local-cache/api-fixture-example/ — die leichteste Option: eine reine SQLite-Instanz auf :5002, geladen mit Gramps' eigener offizieller Beispieldatenbank example.gramps, nützlich für echte Datumsvielfalt (Modifikatoren, Qualität, Bereiche/Zeitspannen). VITE_API_BASE=http://localhost:5002 in app/.env.local setzen, um darauf zu zeigen. Live-Synchronisierung funktioniert auch dagegen, da es nur eine Abfrage gegen /api/transactions/history/ ist, nicht an Postgres gebunden.
  • layer2-local-cache/api-fixture/ — eine weitere reine SQLite-Instanz, stattdessen mit von gramps-bench erzeugten synthetischen Daten geladen, für Skalierungstests gegen einen großen Stammbaum.
  • layer3-sync/api-fixture/ — eine Instanz mit echtem Postgres dahinter (SharedPostgreSQL), nützlich, um echte gleichzeitige Bearbeitungen mehrerer Schreiber gegen denselben Stammbaum auszuüben. Darauf zeigt das Standard-VITE_API_BASE von app/.env.example, und es braucht ein laufendes Postgres plus das Add-on SharedPostgreSQL zusätzlich zu allem, was die SQLite-Fixtures brauchen.

Gramplet-Wheels bauen

Gramplets führen Python im Browser unter Pyodide aus, gegen lokal gebaute Wheels, die der postinstall-Schritt von npm install überspringt (mit einer Log-Zeile), wenn sie noch nicht da sind — dann schlagen Gramplets zur Laufzeit mit No known package with name 'gramps-gen-lib' fehl. Sie einmalig bauen:

python3 scripts/build-stub-wheels.py    # gi + orjson Platzhalter für Pyodide
python3 scripts/build-gramps-wheel.py   # gramps.gen.lib als Pyodide-Wheel
node app/scripts/copy-wasm.mjs          # registriert sie in public/pyodide/

Testen

npm run test -w app         # Vitest: reine Store-/Sync-Logik, kein vollständiges App-Rendering
npm run typecheck -w app    # tsc --noEmit
npm run test -w packages/gramps-date
pytest tests/               # eingebaute GOQL-Filter-Voreinstellungen gegen echte gramps-core-Regeln

Die pytest-Suite (tests/gql_presets/, siehe ihre eigene README) prüft jede eingebaute Filter-Voreinstellung (app/src/data/gqlFilterPresets.ts) gegen die echte Rule-Klasse von gramps-core, die sie portieren soll, ausgeführt gegen den eigenen mitgelieferten Beispielstammbaum von gramps-core — das prüft nicht nur „kompiliert das“, sondern „wählt es dieselben Zeilen wie die Desktop-Regel“. Braucht importierbares gramps/gramps-object-query-language (schon überall gegeben, wo gramps-web-api selbst läuft); kein separater Schritt nötig, um die eigene JSON-Momentaufnahme der Voreinstellungen synchron zu halten, das passiert automatisch.

Übersetzungen

Die UI-Zeichenketten von app/ laufen über t() (app/src/i18n/i18n.ts), was den eigenen Ansatz von gramps-web spiegelt — ein schlichtes {englisch: übersetzt}-Nachschlagen, keine i18n-Bibliothek — zusammengeführt aus zwei Quellen pro Sprache, bei setLanguage() ausgewählt und bis zum nächsten Sprachwechsel im Speicher zwischengespeichert:

  • Das Vokabular der Gramps-Desktop-Applive übersetzt, pro Anfrage, indem die tatsächlich verwendeten Zeichenketten an den bereits bestehenden Endpunkt GET/POST /api/translations/<lang> von gramps-web-api gesendet werden, der sie durch den eigenen gettext-Katalog des installierten gramps-Pakets laufen lässt. Keine statische Kopie, die synchron gehalten werden muss; immer so aktuell wie die auf dem Server installierte gramps-Version. Die feste Liste, welche Zeichenketten des Desktop-Vokabulars angefragt werden, lebt im Array desktopStrings von i18n.ts — von Hand gewachsen, ein Eintrag pro Zeichenkette, immer wenn sich ein neu eingepackter t()-Aufruf als echtes Gramps-Vokabular statt etwas gramps-connect-Spezifisches herausstellt.
  • Die eigenen UI-Zeichenketten von gramps-web, und die Zeichenketten der Gramps-Add-ons — als statische Dateien app/public/lang/ {locale}.json bootstrapped (in git verfolgt, die App funktioniert also, ohne dass jemand eine Weblate-Verbindung braucht) von scripts/bootstrap-translations.py, das ../gramps-web/lang/ und ../addons-source/*/po/*-local.po liest — Geschwister-Checkouts dieses Repositorys, kein Netzwerkaufruf. Es ausführen (python3 scripts/bootstrap-translations.py, braucht pip install polib), wann immer diese Geschwister-Checkouts aktualisiert werden und der statische Korpus aufgefrischt werden soll; es ist in keinen Build-Schritt eingebunden, nichts führt es also automatisch aus. Gefahrlos erneut auszuführen: ohne --force überspringt es jedes bereits vorhandene Locale-.json, und selbst mit --force überschreibt es nur Dateien unter app/public/lang/ — keine Netzwerkaufrufe, keine Git-Operationen, und jedes schlechte Ergebnis ist nur ein git checkout von rückgängig entfernt.

Mehr der eigenen Zeichenketten der App in t() einzupacken ist laufende, schrittweise Arbeit — app/scripts/wrap-translations.mjs ist ein einmaliges Codemod (als wiederverwendbares Werkzeug aufbewahrt), das schlichten JSX-Text und eine sichere Attribut-Positivliste (label/title/placeholder) mechanisch einpackt; alles, was aus einer Variable oder einer Objekt-Literal-Eigenschaft stammt (Ansichts-/Spalten-Konfigurationen in app/src/store/views.ts, dynamische API-Daten, notifications.show()-Aufrufe), braucht stattdessen ein manuelles t(...) an der Stelle, an der die jeweilige Komponente es rendert.

Mitwirken

Diskussionen finden im Gramps-Discourse-Forum statt; Issues und Pull Requests gegen das gramps-connect-Repository sind willkommen.

Lizenz

AGPL-3.0-or-later, passend zu gramps-web-api und gramps-web. packages/gramps-date übersetzt GPL-2.0-or-later-Code von Gramps core in die AGPL-3.0-or-later-Codebasis dieses Projekts — siehe seine eigene README (und Architektur) dafür, wie diese beiden Lizenzen zusammenpassen.

Clone this wiki locally