l18n fixes
This commit is contained in:
parent
d16e1029a7
commit
1cb99f8639
2 changed files with 192 additions and 18 deletions
|
|
@ -1,5 +1,5 @@
|
|||
<!-- status: canonical -->
|
||||
<!-- lastReviewed: 2026-04-11 -->
|
||||
<!-- lastReviewed: 2026-04-12 -->
|
||||
|
||||
# Coding-Konventionen
|
||||
|
||||
|
|
@ -10,6 +10,23 @@
|
|||
- **PascalCase** fuer Klassen und Pydantic-Models
|
||||
- Dateien: `camelCase` fuer Module (z.B. `mainServiceAi.py`, `routeBilling.py`)
|
||||
|
||||
## i18n Grundprinzip: Uebersetzen an der Quelle
|
||||
|
||||
Jeder Text wird **an der Quelle** uebersetzt. Backend-Strings werden im Backend uebersetzt, Frontend-Strings im Frontend. Der Empfaenger rendert direkt — keine doppelte Uebersetzung, keine Checks.
|
||||
|
||||
**Backend liefert IMMER in der korrekten Sprache.** Das Frontend muss nichts pruefen oder nochmals uebersetzen.
|
||||
|
||||
| Text-Quelle | Wer uebersetzt | Empfaenger |
|
||||
|---|---|---|
|
||||
| Frontend-Komponente (Button, Label, h1) | Frontend: `t('Speichern')` | rendert direkt |
|
||||
| Backend statische Struktur (Navigation, Katalog) | Backend: `t()` registriert Key, `resolveText()` liefert zur Request-Zeit | Frontend: `item.uiLabel` direkt rendern |
|
||||
| Backend API-Response (Fehlermeldung, Erfolg) | Backend: `t("Zugriff verweigert")` | Frontend: `error.detail` direkt rendern |
|
||||
| Backend DB-Wert (TextMultilingual) | Backend: `resolveText(role.description)` | Frontend: `role.description` direkt rendern |
|
||||
|
||||
**Kernregel:** Strings vom Backend sind **immer bereits uebersetzt**. Das Frontend darf `t()` **nie** auf Backend-Werte anwenden — weder `t(item.label)` noch `t(variable)`. Keine `typeof === 'object'` Checks, keine Fallback-Ketten. Nur eigene Frontend-Literale wie `t('Speichern')`.
|
||||
|
||||
**Redundanz vermeiden:** Derselbe Text darf nicht an zwei Stellen mit `t()` getaggt werden.
|
||||
|
||||
## Frontend (React/TypeScript)
|
||||
|
||||
- Keine Browser-Dialoge (`alert`, `confirm`, `prompt`) -- stattdessen `useConfirm()` / `usePrompt()` Hooks
|
||||
|
|
@ -37,7 +54,18 @@ t('Offen (Status)') // vs. t('Offen (Zustand)')
|
|||
```
|
||||
|
||||
- **Key = deutscher Klartext** (kein Dot-Notation-Schema)
|
||||
- **`t()` NUR mit String-Literalen** — `t(variable)` ist verboten. Backend-Werte (feature.label, role.description etc.) sind bereits uebersetzt und werden direkt gerendert.
|
||||
- **`t()` NUR mit String-Literalen** — `t(variable)` ist verboten. Backend-Werte (Navigation-Labels, Feature-Labels, Role-Descriptions etc.) sind bereits uebersetzt und werden direkt gerendert:
|
||||
|
||||
```tsx
|
||||
// FALSCH - Backend-Wert nochmal durch t()
|
||||
label: t(item.uiLabel) // Backend hat schon uebersetzt!
|
||||
<h1>{t(plan.title)}</h1> // Backend hat schon uebersetzt!
|
||||
|
||||
// RICHTIG - Backend-Wert direkt rendern
|
||||
label: item.uiLabel
|
||||
<h1>{plan.title}</h1>
|
||||
```
|
||||
|
||||
- Fuer statische Frontend-Maps (Wochentage, Monatsnamen, Status-Labels) wird `t()` per `switch`-Funktion mit Literalen aufgerufen, nicht ueber Map-Lookup:
|
||||
|
||||
```tsx
|
||||
|
|
@ -86,29 +114,35 @@ return {"message": t("Datei erfolgreich hochgeladen", "api.routeFiles",
|
|||
|
||||
**Nicht** mit `t()` taggen: Log-Eintraege, AI-Prompts, interne technische Fehlermeldungen.
|
||||
|
||||
### Statische Dicts mit i18n-Keys: t() auf Modul-Ebene registrieren
|
||||
### Statische Dicts mit i18n-Keys: t() registriert, resolveText() liefert
|
||||
|
||||
Wenn ein Modul statische Dicts/Listen mit UI-sichtbaren Texten definiert (z.B. `BADGE_DEFINITIONS`, Level-Labels), muessen die Keys **auf Modul-Ebene** via `t()` registriert werden. Nur so erscheinen sie im `xx`-Basisset und koennen uebersetzt werden.
|
||||
Statische Dicts (Navigation, Kataloge) haben **zwei Schritte**:
|
||||
|
||||
1. **Import-Zeit:** `t()` im Dict **registriert** den Key (und gibt den deutschen String zurueck, der im Dict gespeichert wird)
|
||||
2. **Request-Zeit:** `resolveText()` in der Route nimmt den deutschen String und liefert die Uebersetzung fuer die aktuelle Sprache
|
||||
|
||||
```python
|
||||
# mainSystem.py — t() registriert Keys bei Import-Zeit
|
||||
from modules.shared.i18nRegistry import t
|
||||
|
||||
# Alle Keys auf Modul-Ebene mit t("...") registrieren (Import-Zeit), siehe z.B. CommCoach BADGE_DEFINITIONS
|
||||
|
||||
# Dict mit deutschen Quelltexten als Strings (NICHT t() im Dict!)
|
||||
BADGE_DEFINITIONS = {
|
||||
"first_session": {"label": "Erste Session", "icon": "star"},
|
||||
"streak_3": {"label": "3-Tage-Serie", "icon": "fire"},
|
||||
}
|
||||
|
||||
# Runtime: resolveText (nicht t(variable))
|
||||
from modules.shared.i18nRegistry import resolveText
|
||||
|
||||
def getBadgeDefinitions():
|
||||
return {k: {**v, "label": resolveText(v["label"])} for k, v in BADGE_DEFINITIONS.items()}
|
||||
NAVIGATION_SECTIONS = [
|
||||
{"title": t("Meine Sicht"), "items": [
|
||||
{"label": t("Uebersicht"), "objectKey": "ui.system.home", ...},
|
||||
]},
|
||||
]
|
||||
```
|
||||
|
||||
**Warum?** `t()` registriert Keys nur beim ersten Aufruf. Wenn `t()` nur in einer Funktion steht, wird der Key erst beim ersten Request registriert -- **nach** dem Boot-Sync. Der Key fehlt dann im `xx`-Set und kann nicht uebersetzt werden.
|
||||
```python
|
||||
# routeSystem.py — resolveText() uebersetzt zur Request-Zeit
|
||||
from modules.shared.i18nRegistry import resolveText
|
||||
|
||||
def _formatBlockItem(item):
|
||||
return {"uiLabel": resolveText(item["label"]), ...}
|
||||
```
|
||||
|
||||
**Warum zwei Schritte?** `t()` wird bei Import-Zeit ausgewertet — der Rueckgabewert ist immer deutsch (Default-Sprache). Der Wert im Dict ist daher ein fester deutscher String. `resolveText()` nimmt diesen deutschen String zur Request-Zeit und liefert die korrekte Uebersetzung.
|
||||
|
||||
**Warum Modul-Ebene?** `t()` registriert Keys nur beim ersten Aufruf. Wenn `t()` nur in einer Funktion steht, wird der Key erst beim ersten Request registriert — **nach** dem Boot-Sync. Der Key fehlt dann im `xx`-Set und kann nicht uebersetzt werden.
|
||||
|
||||
### TextMultilingual-Felder: Backend loest auf via resolveText()
|
||||
|
||||
|
|
|
|||
140
d-guides/unused-api-endpoints.md
Normal file
140
d-guides/unused-api-endpoints.md
Normal file
|
|
@ -0,0 +1,140 @@
|
|||
<!-- status: canonical -->
|
||||
<!-- lastReviewed: 2026-04-12 -->
|
||||
|
||||
# Ungenutzte API-Endpunkte — Kandidaten zum Loeschen
|
||||
|
||||
Analyse vom 2026-04-12. Geprueft gegen:
|
||||
- `frontend_nyla/src/` (UI)
|
||||
- `service-teams-browser-bot/` (Teams Bot)
|
||||
- `private-llm/` (Private LLM)
|
||||
|
||||
Keiner dieser Endpunkte wird in irgendeinem der drei Repos referenziert.
|
||||
|
||||
---
|
||||
|
||||
## Komplett ungenutzte Route-Module
|
||||
|
||||
### `routeMessaging.py` — 14 Endpunkte (alle loeschen)
|
||||
|
||||
| Method | Path | Funktion |
|
||||
|--------|------|----------|
|
||||
| GET | `/api/messaging/subscriptions` | Subscriptions auflisten |
|
||||
| POST | `/api/messaging/subscriptions` | Subscription erstellen |
|
||||
| GET | `/api/messaging/subscriptions/{id}` | Subscription abrufen |
|
||||
| PUT | `/api/messaging/subscriptions/{id}` | Subscription aktualisieren |
|
||||
| DELETE | `/api/messaging/subscriptions/{id}` | Subscription loeschen |
|
||||
| GET | `/api/messaging/subscriptions/{id}/registrations` | Registrierungen auflisten |
|
||||
| POST | `/api/messaging/subscriptions/{id}/subscribe` | Registrierung erstellen |
|
||||
| DELETE | `/api/messaging/subscriptions/{id}/unsubscribe` | Abmelden |
|
||||
| GET | `/api/messaging/registrations` | Alle Registrierungen |
|
||||
| PUT | `/api/messaging/registrations/{id}` | Registrierung aktualisieren |
|
||||
| DELETE | `/api/messaging/registrations/{id}` | Registrierung loeschen |
|
||||
| POST | `/api/messaging/trigger/{id}` | Subscription ausloesen |
|
||||
| GET | `/api/messaging/deliveries` | Zustellungen auflisten |
|
||||
| GET | `/api/messaging/deliveries/{id}` | Zustellung abrufen |
|
||||
|
||||
### `routeSecurityAdmin.py` — 9 Endpunkte (alle loeschen)
|
||||
|
||||
| Method | Path | Funktion |
|
||||
|--------|------|----------|
|
||||
| GET | `/api/admin/tokens` | Token/Sessions auflisten |
|
||||
| POST | `/api/admin/tokens/revoke/user` | Tokens per User widerrufen |
|
||||
| POST | `/api/admin/tokens/revoke/session` | Session widerrufen |
|
||||
| POST | `/api/admin/tokens/revoke/id` | Token per ID widerrufen |
|
||||
| POST | `/api/admin/tokens/revoke/mandate` | Tokens per Mandate widerrufen |
|
||||
| GET | `/api/admin/databases` | Datenbanken auflisten |
|
||||
| GET | `/api/admin/databases/{name}/tables` | Tabellen auflisten |
|
||||
| POST | `/api/admin/databases/{name}/tables/{table}/drop` | Tabelle loeschen |
|
||||
| POST | `/api/admin/databases/drop` | Datenbank loeschen |
|
||||
|
||||
### `routeAdminRbacExport.py` — 4 Endpunkte (alle loeschen)
|
||||
|
||||
| Method | Path | Funktion |
|
||||
|--------|------|----------|
|
||||
| GET | `/api/rbac/export/global` | Globale RBAC exportieren |
|
||||
| POST | `/api/rbac/import/global` | Globale RBAC importieren |
|
||||
| GET | `/api/rbac/export/mandate` | Mandate RBAC exportieren |
|
||||
| POST | `/api/rbac/import/mandate` | Mandate RBAC importieren |
|
||||
|
||||
---
|
||||
|
||||
## Teilweise ungenutzte Route-Module
|
||||
|
||||
### `routeVoiceGoogle.py` — 8 Endpunkte loeschen
|
||||
|
||||
Genutzt werden: `GET /languages`, `GET /voices`, `POST /stt/token`.
|
||||
|
||||
| Method | Path | Funktion |
|
||||
|--------|------|----------|
|
||||
| POST | `/voice-google/speech-to-text` | Audio STT |
|
||||
| POST | `/voice-google/detect-language` | Sprache erkennen |
|
||||
| POST | `/voice-google/translate` | Text uebersetzen |
|
||||
| POST | `/voice-google/realtime-interpreter` | Interpreter-Pipeline |
|
||||
| POST | `/voice-google/text-to-speech` | TTS |
|
||||
| GET | `/voice-google/health` | Health Check |
|
||||
| GET | `/voice-google/settings` | Voice-Einstellungen lesen |
|
||||
| POST | `/voice-google/settings` | Voice-Einstellungen speichern |
|
||||
|
||||
### `routeClickup.py` — 10 Endpunkte loeschen
|
||||
|
||||
Genutzt werden: `GET /{id}/tasks/{taskId}`, `GET /{id}/lists/{listId}`, `GET /{id}/teams/{teamId}`, `GET /{id}/lists/{listId}/fields`, `GET /{id}/lists/{listId}/tasks`.
|
||||
|
||||
| Method | Path | Funktion |
|
||||
|--------|------|----------|
|
||||
| GET | `/api/clickup/{id}/teams` | Teams auflisten |
|
||||
| GET | `/api/clickup/{id}/teams/{teamId}/spaces` | Spaces auflisten |
|
||||
| GET | `/api/clickup/{id}/spaces/{spaceId}/folders` | Folders auflisten |
|
||||
| GET | `/api/clickup/{id}/spaces/{spaceId}/lists` | Listen in Space |
|
||||
| GET | `/api/clickup/{id}/folders/{folderId}/lists` | Listen in Folder |
|
||||
| GET | `/api/clickup/{id}/teams/{teamId}/tasks/search` | Tasks suchen |
|
||||
| GET | `/api/clickup/{id}/user` | ClickUp User |
|
||||
| POST | `/api/clickup/{id}/lists/{listId}/tasks` | Task erstellen |
|
||||
| PUT | `/api/clickup/{id}/tasks/{taskId}` | Task aktualisieren |
|
||||
| DELETE | `/api/clickup/{id}/tasks/{taskId}` | Task loeschen |
|
||||
|
||||
### `routeSharepoint.py` — 3 Endpunkte loeschen
|
||||
|
||||
Genutzt wird: `GET /api/sharepoint/folder-options` (ohne connectionId).
|
||||
|
||||
| Method | Path | Funktion |
|
||||
|--------|------|----------|
|
||||
| GET | `/api/sharepoint/{id}/sites` | SharePoint Sites |
|
||||
| GET | `/api/sharepoint/{id}/sites/{siteId}/folders` | Folders unter Site |
|
||||
| GET | `/api/sharepoint/{id}/folder-options` | Folder-Optionen (mit connectionId) |
|
||||
|
||||
### `routeFeatureGraphicalEditor.py` — 5 Endpunkte loeschen
|
||||
|
||||
| Method | Path | Funktion |
|
||||
|--------|------|----------|
|
||||
| GET | `/api/workflows/{id}/info` | Workflow-Engine Info |
|
||||
| POST | `/api/workflows/{id}/schedule-sync` | Schedule-Trigger sync |
|
||||
| POST | `/api/workflows/{id}/workflows/{wfId}/webhooks/{epId}` | Webhook registrieren |
|
||||
| POST | `/api/workflows/{id}/workflows/{wfId}/forms/{epId}/submit` | Formular-Submit |
|
||||
| POST | `/api/workflows/{id}/runs/{runId}/resume` | Pausierten Run fortsetzen |
|
||||
|
||||
---
|
||||
|
||||
## Einzelne ungenutzte Endpunkte
|
||||
|
||||
| Route-Datei | Method | Path | Funktion |
|
||||
|-------------|--------|------|----------|
|
||||
| `routeAdminRbacRules.py` | GET | `/api/rbac/catalog/stats` | RBAC Katalog-Statistiken |
|
||||
| `routeI18n.py` | GET | `/api/i18n/user-language-options` | Sprach-Optionen fuer User |
|
||||
| `routeI18n.py` | PUT | `/api/i18n/sets/update-all` | Alle Sprachsets aktualisieren |
|
||||
| `routeSecurityGoogle.py` | GET | `/api/google/config` | Google OAuth Config |
|
||||
| `routeSecurityGoogle.py` | POST | `/api/google/verify` | Token-Verifikation |
|
||||
| `routeSecurityMsft.py` | POST | `/api/msft/cleanup` | MSFT Auth Cleanup |
|
||||
| `routeAdminUserAccessOverview.py` | GET | `/api/admin/user-access-overview/{userId}/effective-permissions` | Effektive Berechtigungen |
|
||||
| `routeDataFiles.py` | GET | `/api/files/stats` | Datei-Statistiken |
|
||||
| `routeBilling.py` | GET | `/api/billing/admin/transactions/{id}/filter-values` | Filter-Werte Admin-Transaktionen |
|
||||
|
||||
---
|
||||
|
||||
## Zusammenfassung
|
||||
|
||||
| Kategorie | Endpunkte |
|
||||
|-----------|-----------|
|
||||
| Komplett ungenutzte Module | 27 |
|
||||
| Teilweise ungenutzte Module | 26 |
|
||||
| Einzelne Endpunkte | 9 |
|
||||
| **Total** | **62** |
|
||||
Loading…
Reference in a new issue