- 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>
58 lines
2.0 KiB
JavaScript
58 lines
2.0 KiB
JavaScript
// Internes Place-Objekt: bleibt nah am KI-Import-JSON-Format aus
|
|
// anforderung.md, ergänzt um intern generierte Felder (id, createdAt,
|
|
// updatedAt). Die Kategorie wird beim Normalisieren immer auf eine
|
|
// gültige Kategorie-id (Slug) aufgelöst, damit Styling (Farbe/Icon)
|
|
// überall per getCategoryById() funktioniert.
|
|
|
|
(function () {
|
|
const { generateId } = EventMap.utils;
|
|
const { CATEGORIES, getCategoryById, getCategoryByLabel } = EventMap.config;
|
|
const { createDefaultPlaceFields } = EventMap.models;
|
|
|
|
const CATEGORY_IDS = new Set(CATEGORIES.map((c) => c.id));
|
|
|
|
function resolveCategory(rawCategory) {
|
|
if (typeof rawCategory === 'string' && CATEGORY_IDS.has(rawCategory)) {
|
|
return rawCategory;
|
|
}
|
|
return getCategoryByLabel(rawCategory).id;
|
|
}
|
|
|
|
/**
|
|
* Normalisiert ein rohes Place-Objekt (z.B. aus den per SEED_DATA_URL
|
|
* geladenen Beispieldaten oder einem späteren KI-Import) zu einem
|
|
* vollständigen internen Place-Objekt.
|
|
* Fehlende Felder werden mit Defaults aufgefüllt, id/createdAt/updatedAt
|
|
* werden übernommen falls vorhanden, sonst neu generiert.
|
|
*/
|
|
function normalizePlace(raw = {}) {
|
|
const defaults = createDefaultPlaceFields();
|
|
const now = new Date().toISOString();
|
|
|
|
return {
|
|
id: raw.id || generateId(),
|
|
...defaults,
|
|
...raw,
|
|
category: resolveCategory(raw.category),
|
|
ageRecommendation: { ...defaults.ageRecommendation, ...(raw.ageRecommendation || {}) },
|
|
cost: { ...defaults.cost, ...(raw.cost || {}) },
|
|
facilities: { ...defaults.facilities, ...(raw.facilities || {}) },
|
|
tags: Array.isArray(raw.tags) ? [...raw.tags] : [],
|
|
createdAt: raw.createdAt || now,
|
|
updatedAt: raw.updatedAt || now,
|
|
};
|
|
}
|
|
|
|
function getPlaceCategory(place) {
|
|
return getCategoryById(place.category);
|
|
}
|
|
|
|
function getPlaceLatLng(place) {
|
|
return { lat: place.latitude, lng: place.longitude };
|
|
}
|
|
|
|
EventMap.models.normalizePlace = normalizePlace;
|
|
EventMap.models.getPlaceCategory = getPlaceCategory;
|
|
EventMap.models.getPlaceLatLng = getPlaceLatLng;
|
|
})();
|