From ed8ec98572ff7fbf86953dc8e846871840faebe6 Mon Sep 17 00:00:00 2001 From: Till JS Date: Fri, 24 Apr 2026 16:00:27 +0200 Subject: [PATCH] feat(workbench): app picker searches English aliases + IT/FR/ES i18n MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Die Suche im AppPagePicker matcht jetzt gegen DE + EN + Fallback-Name + id-Slug, damit englische Begriffe immer greifen — auch wenn die UI in Deutsch läuft ("cal" → Kalender, "weather" → Wetter). - AppPagePicker: statische Imports von apps/de.json + apps/en.json, neue searchHaystack-Funktion, Filter über Haystack statt nur displayName. - apps/{it,fr,es}.json: +42 Einträge pro Sprache, alle 78 registrierten Module sind jetzt nativ übersetzt. Vorher fiel IT/FR/ES für neuere Module via fallbackLocale auf Deutsch zurück (z.B. "Wetter" im italienischen Menü). Co-Authored-By: Claude Opus 4.7 (1M context) --- .../components/workbench/AppPagePicker.svelte | 25 ++++++++--- .../web/src/lib/i18n/locales/apps/es.json | 44 ++++++++++++++++++- .../web/src/lib/i18n/locales/apps/fr.json | 44 ++++++++++++++++++- .../web/src/lib/i18n/locales/apps/it.json | 44 ++++++++++++++++++- 4 files changed, 149 insertions(+), 8 deletions(-) diff --git a/apps/mana/apps/web/src/lib/components/workbench/AppPagePicker.svelte b/apps/mana/apps/web/src/lib/components/workbench/AppPagePicker.svelte index 012fcbda5..4b3bce452 100644 --- a/apps/mana/apps/web/src/lib/components/workbench/AppPagePicker.svelte +++ b/apps/mana/apps/web/src/lib/components/workbench/AppPagePicker.svelte @@ -12,6 +12,11 @@ import { getAccessibleApps } from '$lib/app-registry'; import type { AppDescriptor } from '$lib/app-registry/types'; import { APP_CATEGORIES, getAppCategory, type AppCategory } from '$lib/app-registry/categories'; + import appsDeRaw from '$lib/i18n/locales/apps/de.json'; + import appsEnRaw from '$lib/i18n/locales/apps/en.json'; + + const appsDe = appsDeRaw as Record; + const appsEn = appsEnRaw as Record; function appName(id: string, fallback: string): string { const key = `apps.${id}`; @@ -19,6 +24,15 @@ return translated !== key ? translated : fallback; } + // Match against DE + EN names, fallback, and id together so English + // aliases stay searchable while the UI is in German ("cal" → Kalender). + function searchHaystack(id: string, fallback: string, displayName: string): string { + return [displayName, fallback, appsDe[id], appsEn[id], id.replace(/-/g, ' ')] + .filter(Boolean) + .join(' ') + .toLowerCase(); + } + interface Props { onSelect: (appId: string) => void; onClose: () => void; @@ -43,11 +57,14 @@ system: true, // System is collapsed by default — noisy and rarely toggled }); - // Tier-gate first, then drop open apps, then attach display name. + // Tier-gate first, then drop open apps, then attach display name + search haystack. let available = $derived( getAccessibleApps(userTier) .filter((app) => !activeAppIds.includes(app.id)) - .map((app) => ({ app, displayName: appName(app.id, app.name) })) + .map((app) => { + const displayName = appName(app.id, app.name); + return { app, displayName, haystack: searchHaystack(app.id, app.name, displayName) }; + }) .sort((a, b) => a.displayName.localeCompare(b.displayName, 'de')) ); @@ -56,9 +73,7 @@ let searchResults = $derived( searchMode - ? available.filter(({ displayName }) => - displayName.toLowerCase().includes(query.trim().toLowerCase()) - ) + ? available.filter(({ haystack }) => haystack.includes(query.trim().toLowerCase())) : [] ); diff --git a/apps/mana/apps/web/src/lib/i18n/locales/apps/es.json b/apps/mana/apps/web/src/lib/i18n/locales/apps/es.json index b65d94eed..c7c8d3001 100644 --- a/apps/mana/apps/web/src/lib/i18n/locales/apps/es.json +++ b/apps/mana/apps/web/src/lib/i18n/locales/apps/es.json @@ -34,5 +34,47 @@ "who": "Who", "events": "Eventos", "automations": "Automatizaciones", - "playground": "Playground" + "playground": "Playground", + "kontext": "Contexto web", + "news": "Noticias", + "news-research": "Investigación de noticias", + "articles": "Artículos", + "research-lab": "Laboratorio de investigación", + "drink": "Bebidas", + "recipes": "Recetas", + "stretch": "Estiramientos", + "mail": "Correo", + "meditate": "Meditación", + "mood": "Estado de ánimo", + "sleep": "Sueño", + "myday": "Mi día", + "activity": "Actividad", + "companion": "Compañero", + "ai-missions": "Misiones IA", + "ai-agents": "Agentes IA", + "ai-workbench": "Workbench IA", + "rituals": "Rituales", + "ai-policy": "Políticas IA", + "ai-insights": "Información IA", + "ai-health": "Salud IA", + "goals": "Metas", + "credits": "Créditos y suscripción", + "spiral": "Mana Spiral", + "settings": "Ajustes", + "themes": "Temas", + "profile": "Perfil", + "admin": "Admin", + "complexity": "Complejidad", + "api-keys": "Claves API", + "wishes": "Deseos", + "help": "Ayuda", + "wetter": "Tiempo", + "feedback": "Comentarios", + "wardrobe": "Armario", + "library": "Biblioteca", + "spaces": "Espacios", + "website": "Sitio web", + "quiz": "Quiz", + "guides": "Guías", + "comic": "Cómic" } diff --git a/apps/mana/apps/web/src/lib/i18n/locales/apps/fr.json b/apps/mana/apps/web/src/lib/i18n/locales/apps/fr.json index 0186dc656..1b2e67e66 100644 --- a/apps/mana/apps/web/src/lib/i18n/locales/apps/fr.json +++ b/apps/mana/apps/web/src/lib/i18n/locales/apps/fr.json @@ -34,5 +34,47 @@ "who": "Who", "events": "Événements", "automations": "Automations", - "playground": "Playground" + "playground": "Playground", + "kontext": "Contexte web", + "news": "Actualités", + "news-research": "Recherche d'actus", + "articles": "Articles", + "research-lab": "Laboratoire de recherche", + "drink": "Boissons", + "recipes": "Recettes", + "stretch": "Étirements", + "mail": "Courrier", + "meditate": "Méditation", + "mood": "Humeur", + "sleep": "Sommeil", + "myday": "Ma journée", + "activity": "Activité", + "companion": "Compagnon", + "ai-missions": "Missions IA", + "ai-agents": "Agents IA", + "ai-workbench": "Workbench IA", + "rituals": "Rituels", + "ai-policy": "Règles IA", + "ai-insights": "Analyses IA", + "ai-health": "Santé IA", + "goals": "Objectifs", + "credits": "Crédits et abonnement", + "spiral": "Mana Spirale", + "settings": "Paramètres", + "themes": "Thèmes", + "profile": "Profil", + "admin": "Admin", + "complexity": "Complexité", + "api-keys": "Clés API", + "wishes": "Souhaits", + "help": "Aide", + "wetter": "Météo", + "feedback": "Retours", + "wardrobe": "Garde-robe", + "library": "Bibliothèque", + "spaces": "Espaces", + "website": "Site web", + "quiz": "Quiz", + "guides": "Guides", + "comic": "Bande dessinée" } diff --git a/apps/mana/apps/web/src/lib/i18n/locales/apps/it.json b/apps/mana/apps/web/src/lib/i18n/locales/apps/it.json index 6ab7de6a7..110bf5689 100644 --- a/apps/mana/apps/web/src/lib/i18n/locales/apps/it.json +++ b/apps/mana/apps/web/src/lib/i18n/locales/apps/it.json @@ -34,5 +34,47 @@ "who": "Who", "events": "Eventi", "automations": "Automazioni", - "playground": "Playground" + "playground": "Playground", + "kontext": "Contesto Web", + "news": "News", + "news-research": "Ricerca News", + "articles": "Articoli", + "research-lab": "Laboratorio di ricerca", + "drink": "Bevande", + "recipes": "Ricette", + "stretch": "Stretching", + "mail": "Posta", + "meditate": "Meditazione", + "mood": "Umore", + "sleep": "Sonno", + "myday": "La mia giornata", + "activity": "Attività", + "companion": "Compagno", + "ai-missions": "Missioni IA", + "ai-agents": "Agenti IA", + "ai-workbench": "Workbench IA", + "rituals": "Rituali", + "ai-policy": "Regole IA", + "ai-insights": "Insight IA", + "ai-health": "Salute IA", + "goals": "Obiettivi", + "credits": "Crediti & Abbonamento", + "spiral": "Mana Spiral", + "settings": "Impostazioni", + "themes": "Temi", + "profile": "Profilo", + "admin": "Admin", + "complexity": "Complessità", + "api-keys": "Chiavi API", + "wishes": "Desideri", + "help": "Aiuto", + "wetter": "Meteo", + "feedback": "Feedback", + "wardrobe": "Guardaroba", + "library": "Biblioteca", + "spaces": "Spazi", + "website": "Sito web", + "quiz": "Quiz", + "guides": "Guide", + "comic": "Fumetto" }