feat: add page shell, preferences and translations

Base layout with top bar, role-based menu, profile menu and phone layout; theme, language and German form of address kept in cookies; German formal, German informal and English text; Fluent avatar bundled in the image by a Node build stage; placeholder pages for the Publisher and Admin groups.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01N3t4WL7bd9bdHHNjEsxzqC
This commit is contained in:
2026-10-17 21:05:40 +02:00
co-authored by Claude Sonnet 5.5
parent 3c69c2a156
commit 0dc079a8ac
34 changed files with 2132 additions and 24 deletions
+8
View File
@@ -53,6 +53,14 @@ uv run ruff check .
`pytest` sets its own test environment (see `pyproject.toml`).
### Page shell, front end and translations
The Fluent web components are bundled by a Node build stage in the `Dockerfile` (`portal/frontend`, pinned by `package-lock.json`) and served from the portal's own origin; the runtime image has no Node.js. To rebuild the bundle locally: `cd portal/frontend && npm ci && npm run build`, then copy `dist/fluent.js` to `portal/static/vendor/`. Pages work without it (the avatar falls back to initials).
Text is German (formal and informal) and English. The English text is the message id. Add the German text to `portal/locale/de/LC_MESSAGES/django.po`, and an informal variant to `portal/locale/de_DU/...` only where it differs. `test_translations.py` fails if a string has no German text. The Docker build compiles the catalogues with `gettext`; the tests compile their own copy.
Theme, language and form of address are stored per device in the cookies `pm_theme`, `pm_lang` and `pm_form`; nothing is stored on the server.
### Directory adapter against the test OU
`uv sync` builds `python-ldap`, which needs the OpenLDAP and SASL development libraries (the Docker image installs them). The automated tests use an in-memory fake and a stand-in for the `ldap` module, so they run anywhere.