Seed-Daten per Fetch von externem Server laden, UI-Sprachumschalter (DE/EN) und KI-Übersetzungs-Prompt-Generator ergänzen

- Beispieldaten werden nicht mehr eingebettet (data/seed.js entfernt),
  sondern beim ersten Start per fetch(EventMap.config.SEED_DATA_URL) von
  einem externen, selbst gehosteten Server geladen (siehe ADR 0001,
  Revision 2026-07-28).
- Neuer UI-Sprachumschalter (Deutsch/Englisch) für die Bedienoberfläche:
  js/i18n/strings.js + js/i18n/i18n.js, Sprachwahl im Menü, Persistenz über
  settings.language, Retranslation ohne Reload.
- Neuer Menüpunkt "Ausflugsziel übersetzen (KI)": erzeugt einen Prompt, der
  eine externe KI bittet, Name/Beschreibungen eines bestehenden Ortes ins
  Englische, Spanische oder Französische zu übersetzen (js/ai/translatePromptBuilder.js,
  js/ui/translatePromptGenerator.js).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
2026-07-28 15:16:31 +02:00
co-authored by Claude Sonnet 5
parent 4eb595aa81
commit 2aaff8f680
17 changed files with 1027 additions and 2007 deletions
+15 -12
View File
@@ -33,7 +33,6 @@ js/models/ place.js (Normalisierung), schema.js (Feldstruktur/Defaults)
js/map/ mapController.js, markers.js, geolocation.js
js/ui/ list.js (Ergebnisliste; weitere UI-Module folgen in späteren Phasen)
js/utils/ dom.js, geo.js, id.js
data/seed.js Beispieldaten (10 Ausflugsziele, wird nur beim allerersten Start geladen)
vendor/ lokal vendorte Leaflet-Bibliotheken (JS/CSS/Bildassets)
docs/ dieser Plan, ADRs
```
@@ -53,8 +52,9 @@ aus `anforderung.md` (siehe dortiger Abschnitt "Vorgabe für das KI-JSON"):
- `website`, `image`, `rating`, `tags[]`, `source`, `sourceVerified`
- Intern generiert: `id` (UUID), `createdAt`, `updatedAt` (ISO-Strings)
`js/models/place.js` normalisiert rohe Objekte (aus `data/seed.js` oder späteren
Importen) zu diesem vollständigen internen Format; die Kategorie wird dabei
`js/models/place.js` normalisiert rohe Objekte (aus den per `EventMap.config.SEED_DATA_URL`
nachgeladenen Beispieldaten oder späteren Importen) zu diesem vollständigen internen
Format; die Kategorie wird dabei
immer auf eine gültige Kategorie-`id` (Slug, siehe `js/config/categories.js`)
aufgelöst entweder direkt (falls schon ein Slug vorliegt) oder über das
Label (z.B. `"Spielplatz"``spielplatz`), wie es die KI liefern würde.
@@ -75,9 +75,12 @@ state = { places, filters: null, userLocation: null, selectedPlaceId: null }
- `subscribe(fn)` registriert Listener, `setState(patch)` merged den State und
benachrichtigt alle Subscriber.
- `initStore()` lädt beim Start persistierte Daten aus LocalStorage
(`js/store/storage.js`). Ist noch nichts gespeichert, wird `data/seed.js`
geladen, normalisiert und einmalig persistiert.
- `initStore()` (async) lädt beim Start persistierte Daten aus LocalStorage
(`js/store/storage.js`). Ist noch nichts gespeichert, werden die Beispieldaten
per `fetch(EventMap.config.SEED_DATA_URL)` nachgeladen, normalisiert und
einmalig persistiert. Schlägt der Download fehl (offline, CORS, Server nicht
erreichbar), startet die App mit einer leeren Places-Liste und zeigt einen
Hinweis im Status-Banner an, statt die Initialisierung abzubrechen.
- Einstellungen (`lastFilters`, `lastMapView`, `userConsentGeo`, `defaultCenter`)
werden getrennt über `getSettings()`/`updateSettings()` verwaltet und im
Key `eventmap.settings.v1` persistiert.
@@ -143,12 +146,12 @@ Die App verwendet klassische `<script>`-Tags statt ES-Module (siehe
`index.html`** direkt aus dem lokal synchronisierten Ordner öffnen
(`file://...`) ein lokaler HTTP-Server ist dafür nicht mehr nötig.
Die Beispieldaten liegen in `data/seed.js` als eingebettetes
`<script>`-Objekt (`EventMap.data.SEED_PLACES`) statt als `.json`-Datei,
da `fetch()` auf lokale Dateien über `file://` in manchen Browsern
(insbesondere Chrome/Chromium) blockiert wird. `initStore()` liest die
Seed-Daten dadurch synchron direkt aus dem globalen Namespace, ganz ohne
`fetch()`.
Die Beispieldaten liegen nicht im Repo, sondern werden beim allerersten Start
(leerer LocalStorage) per `fetch(EventMap.config.SEED_DATA_URL)` von einem
externen Server geladen (siehe `docs/adr/0001-vanilla-esm.md`). Das
funktioniert auch unter `file://`, da die Same-Origin-Blockade in Chrome/Chromium
nur `fetch()` auf *lokale* Dateien betrifft, nicht auf entfernte `https://`-URLs
(vorausgesetzt der Server sendet passende CORS-Header).
## Phasenübersicht