Technische Dokumentation
Architektur, Datenmodell, API, Front-End-Lokalisierung und Tooling-Referenz für den i18n Manager.
Architektur-Überblick
Der i18n Manager ist eine klassische, serverseitig gerenderte PHP-Anwendung mit einer PostgreSQL-Datenbank und einem Front End im Stil einer Single-Page-Anwendung auf Basis von jQuery/Foundation. Es gibt keinen Build-Schritt und kein Framework — der Browser lädt index.php, das über AJAX mit einer Reihe kleiner PHP-Endpunkte unter /api/ kommuniziert. Jeder Endpunkt verbindet sich über einen schlanken prozeduralen Wrapper direkt mit PostgreSQL und gibt JSON zurück.
Browser (index.php + jQuery)
│ AJAX (GET/POST)
▼
/api/*.php ──► classes/class_pgsql_data.php ──► PostgreSQL
│
└─ JSON responses
Technologie-Stack
| Schicht | Technologie |
|---|---|
| Server | PHP (prozedural), pg_*-Erweiterung |
| Datenbank | PostgreSQL (gehostet auf Supabase) |
| Front-End-Bibliotheken | jQuery 3.6, Foundation Sites 6.7.5, Font Awesome 6.4 (über CDN) |
| Styling | includes/app.css |
| Tooling | Node.js (der Schlüssel-Scanner); keine npm-Abhängigkeiten zur Laufzeit |
| API-Dokumentation | OpenAPI 3.0, Swagger UI, ReDoc, Postman-Collection |
Verzeichnisstruktur
i18n_management/
├── index.php # Dashboard-SPA (Markup + jQuery-App)
├── pages/ # Eigenständige HTML-Seiten (Doku + API-UIs)
│ ├── swagger.html # Swagger UI (interaktive API-Doku)
│ ├── redoc.html # ReDoc (schreibgeschützte API-Doku)
│ ├── user-guide.html # Endbenutzer-Dokumentation (+ .de.html)
│ ├── technical.html # Diese Seite (+ .de.html)
│ └── integration.html # Integrationsleitfaden (+ .de.html)
├── api/
│ ├── languages_list.php
│ ├── language_toggle.php
│ ├── translations_list.php
│ ├── translations_i18n.php # flache { key: {lang: value} }-Map
│ ├── translations_export.php
│ ├── translation_key_save.php
│ ├── translations_import.php
│ ├── translation_key_delete.php
│ └── openapi.json # OpenAPI-3.0-Spezifikation
├── classes/
│ └── class_pgsql_data.php # PostgreSQL-Zugriffs-Wrapper
├── includes/
│ ├── app.css # Dashboard-Styles
│ └── docs.css # Dokumentations-Styles
├── tools/
│ └── scan_i18n_keys.js # Markup-Scanner + Seed-Generator
├── hold_files/ # Referenz-SQL/JSON (Schema, Seeds, i18n.json)
├── seeds/ # Generierte Seed-Ausgabe (optional)
└── postman/ # Postman-Collection
Datenbankschema
Definiert in hold_files/schema.sql. Vier Tabellen plus Trigger und Indizes.
languages
| Spalte | Typ | Anmerkungen |
|---|---|---|
| code | CHAR(2) | PK — ISO-639-1-Code (en, de…) |
| name | VARCHAR(64) | Anzeigename |
| is_active | BOOLEAN | Standard TRUE |
| created_at | TIMESTAMPTZ | Standard NOW() |
translation_keys
| Spalte | Typ | Anmerkungen |
|---|---|---|
| id | SERIAL | PK |
| key | VARCHAR(255) | UNIQUE — z. B. home.welcome |
| namespace | VARCHAR(64) | GENERATED ALWAYS AS split_part(key,'.',1) STORED |
| description | TEXT | Optionaler Hinweis für Übersetzer |
| contains_html | BOOLEAN | Standard FALSE |
| created_at / updated_at | TIMESTAMPTZ | updated_at wird per Trigger gepflegt |
translations
| Spalte | Typ | Anmerkungen |
|---|---|---|
| id | SERIAL | PK |
| key_id | INT | FK → translation_keys, ON DELETE CASCADE |
| language_code | CHAR(2) | FK → languages, ON DELETE RESTRICT |
| value | TEXT | Die übersetzte Zeichenkette |
| is_reviewed | BOOLEAN | Standard FALSE |
| created_at / updated_at | TIMESTAMPTZ | Per Trigger gepflegt |
UNIQUE (key_id, language_code) — eine Zeile pro Schlüssel × Sprache; ermöglicht Upserts über ON CONFLICT. | ||
translation_audit
Nur-anhängendes Protokoll, das von einem AFTER UPDATE-Trigger auf translations geschrieben wird, sobald sich ein Wert ändert: speichert key_id, language_code, old_value, new_value, changed_by, changed_at.
Trigger & Indizes
set_updated_at()— BEFORE UPDATE auf sowohltranslation_keysals auchtranslations, aktualisiertupdated_at.audit_translation_change()— AFTER UPDATE auftranslations, protokolliert Wertänderungen intranslation_audit.- Indizes auf
translations(key_id),translations(language_code)undtranslation_keys(namespace).
Datenzugriffsschicht
classes/class_pgsql_data.php ist ein prozeduraler Wrapper um die PHP-pg_*-Funktionen. Endpunkte binden ihn über $_SERVER['DOCUMENT_ROOT'] ein und nutzen diese Hilfsfunktionen:
| Funktion | Zweck |
|---|---|
DB_Connect_Direct($write) | Öffnet eine Verbindung (Lese-/Schreibzugriff oder schreibgeschützt). |
DB_Query($conn, $sql) | Führt eine literale Abfrage aus. |
DB_QueryParams($conn, $sql, $params) | Parametrisierte Abfrage ($1, $2…) — hiermit lässt sich SQL-Injection vermeiden. |
DB_FetchAssoc / DB_FetchAll | Eine Zeile / alle Zeilen als assoziative Arrays abrufen. |
DB_Begin / DB_Commit / DB_Rollback | Transaktionssteuerung (genutzt von Speichern & Import). |
DB_AffectedRows / DB_FreeResult / DB_Close | Zeilenanzahl / Aufräumen. |
't'/'f' zurück. Endpunkte normalisieren diese zu echten Booleans, bevor sie als JSON kodiert werden (z. B. $lang['is_active'] === 't').API-Endpunkte
Alle Endpunkte geben JSON zurück (außer dem Export-Download). Das vollständige Request-/Response-Schema befindet sich in openapi.json und ist über Swagger / ReDoc durchsuchbar.
| Methode | Endpunkt | Parameter | Zweck |
|---|---|---|---|
| GET | languages_list.php | — | Sprachen auflisten. |
| POST | language_toggle.php | code, is_active | Eine Sprache aktivieren/deaktivieren. |
| GET | translations_list.php | namespace, search, page, limit | Paginierte Schlüssel + Übersetzungen. |
| GET | translations_i18n.php | namespace, search, format | Flache {key:{lang:value}}-Map (json oder js). |
| GET | translations_export.php | language*, format, namespace, search | Herunterladbares JSON/CSV. |
| POST | translation_key_save.php | id, key, description, contains_html, mark_reviewed, translations | Einen Schlüssel anlegen/aktualisieren (transaktionaler Upsert). |
| POST | translations_import.php | data, overwrite, is_reviewed | Eine JSON-Map per Massenimport einlesen. |
| POST | translation_key_delete.php | id | Einen Schlüssel löschen (mit Kaskadierung). |
* erforderlich
API-Konventionen
- POST-Bodies sind
application/x-www-form-urlencoded(gelesen aus$_POST), keine JSON-Bodies. Felder, die strukturierte Daten enthalten (translations,data), sind JSON-Strings. - Erfolgsform:
{ "success": true, … }. Fehlerform: HTTP 4xx/5xx mit{ "success": false, "error": "…" }. - Unicode: JSON wird mit
JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHESausgegeben, damit die Werte für Menschen lesbar bleiben. - Upserts stützen sich auf die
UNIQUE(key_id, language_code)-Beschränkung mitINSERT … ON CONFLICT DO UPDATE. translations_i18n.phpberücksichtigt nur aktive Sprachen und serialisiert Schlüssel ohne Übersetzungen als{}.
Front-End-Lokalisierungs-Engine
Das Dashboard lokalisiert seine eigene Oberfläche aus denselben Daten, die es verwaltet. Beim Laden ruft es translations_i18n.php nach state.i18n ab (eine flache {key:{lang:value}}-Map), baut den Sprachumschalter aus den aktiven Sprachen auf und wendet die Übersetzungen an.
UI-Elemente nehmen über Datenattribute teil:
| Attribut | Effekt |
|---|---|
data-i18n="key" | Setzt den Text des Elements. |
data-i18n-html="key" | Setzt das innerHTML des Elements (für Werte, die Markup enthalten). |
data-i18n-placeholder="key" | Setzt den placeholder eines Eingabefelds. |
applyI18n(lang) durchläuft jedes markierte Element, schlägt state.i18n[key][lang] nach und aktualisiert es; fehlende Schlüssel/Sprachen fallen auf das vorhandene (englische) Markup zurück. Die ausgewählte Sprache wird in localStorage gespeichert und auf <html lang> widergespiegelt.
Die schlüsselweise automatische Übersetzung im Dialog Hinzufügen/Bearbeiten ruft für jede Zielsprache Googles Endpunkt translate.googleapis.com/translate_a/single?client=gtx auf.
Schlüssel-Scanner — tools/scan_i18n_keys.js
Ein abhängigkeitsfreies Node-Skript, das Quelldateien nach data-i18n*-Attributen durchsucht, ermittelt, welche Schlüssel neu sind, und einfügefertiges Massenimport-JSON sowie idempotentes Seed-SQL generiert — optional unter maschineller Übersetzung des Quelltexts in jede Sprache.
# New keys vs. the seed/reference files
node tools/scan_i18n_keys.js
# Diff against the LIVE database instead of seed files
node tools/scan_i18n_keys.js --endpoint http://localhost/api/translations_i18n.php
# Machine-translate the source text into all languages
node tools/scan_i18n_keys.js --translate
# Write seeds/new_keys.{json,sql} instead of printing
node tools/scan_i18n_keys.js --out seeds
# Other flags: --all (ignore existing), --root DIR, --langs de,fr,es
- Durchsucht
.php/.html/.htm/.js/.tpl; ignoriert.git/node_modules/vendor/tools. - Liest die englische Vorgabe aus dem Text / innerHTML / Placeholder jedes Elements.
- Als HTML markierte Schlüssel werden nicht automatisch übersetzt (das Übersetzen von Markup würde es beschädigen).
- Maschinelle Übersetzungen werden mit
is_reviewed = falsegeseedet. - Diagnoseausgaben gehen nach
stderr; die generierte Ausgabe nachstdout.
Seeds & Referenzdateien
| Datei | Zweck |
|---|---|
hold_files/schema.sql | Vollständiges Datenbankschema (Tabellen, Trigger, Indizes). |
hold_files/seed_translations.sql | Demo-Inhaltsschlüssel (nav.home, home.welcome…). |
hold_files/seed_ui_chrome.sql | Schlüssel der Oberflächen-Chrome (Tabs, Schaltflächen, Tabellenüberschriften) in allen Sprachen. |
hold_files/i18n.json | Referenz-Flachmap, die die Exportform veranschaulicht. |
Seed-Dateien verwenden einen CTE (WITH ins_keys AS (INSERT … RETURNING)) und ON CONFLICT … DO UPDATE, sodass sie idempotent und gefahrlos erneut ausführbar sind.
API-Dokumentations-Artefakte
api/openapi.json— einzige Quelle der Wahrheit (OpenAPI 3.0.3).swagger.html— Swagger UI mit Try it out (Live-Requests).redoc.html— ReDoc, schreibgeschützte Referenz.postman/i18n_management.postman_collection.json— Postman-Collection (v2.1.0) mit einerbase_url-Variablen.
Einrichtung & Deployment
- Stellen Sie das Projekt-Stammverzeichnis mit PHP bereit (die
pg_*-Erweiterung muss aktiviert sein). Die Anwendung geht davon aus, dass sie im Domain-Stammverzeichnis bereitgestellt wird — sie verweist auf/includes/,/classes/,/api/und$_SERVER['DOCUMENT_ROOT']. - Stellen Sie eine PostgreSQL-Datenbank bereit und wenden Sie
hold_files/schema.sqlan. - Seeden Sie die Referenzdaten:
seed_translations.sqlund/oderseed_ui_chrome.sql. - Konfigurieren Sie die Datenbank-Verbindungsdetails in
classes/class_pgsql_data.php(siehe Sicherheitshinweis unten). - Öffnen Sie
index.php. Die CDN-Assets (Foundation, jQuery, Font Awesome, Swagger/ReDoc) erfordern Internetzugang.
Sicherheitshinweise
classes/class_pgsql_data.php codiert. Verlagern Sie sie in Umgebungsvariablen und rotieren Sie das Passwort — alles, was in git committet wurde, sollte als kompromittiert betrachtet werden.- HTML-Schlüssel (
data-i18n-html/contains_html) rendern rohes HTML überinnerHTML. Markieren Sie nur vertrauenswürdige Inhalte als HTML; behandeln Sie Übersetzungswerte andernfalls als potenziellen XSS-Vektor. - Swagger „Try it out“ führt echte Schreibvorgänge (Speichern/Import/Löschen) gegen die vom Server verwendete Datenbank aus. Verwenden Sie ReDoc für schreibgeschütztes Teilen oder richten Sie Swagger auf einen Nicht-Produktions-Host.
- Maschinelle Übersetzung sendet Quelltext an Googles inoffiziellen
gtx-Endpunkt; vermeiden Sie sie für vertrauliche Zeichenketten und prüfen Sie die Ausgabe, bevor Sie ihr vertrauen. - SQL-Injection wird durchgängig durch die Verwendung von
DB_QueryParamsmit gebundenen Parametern entschärft — halten Sie neue Abfragen parametrisiert.