From eab69c512cc4a42d522273ca5f26ba963fd5d2d5 Mon Sep 17 00:00:00 2001 From: Till-JS <101404291+Till-JS@users.noreply.github.com> Date: Sun, 30 Nov 2025 00:28:14 +0100 Subject: [PATCH] feat(i18n): add language picker and 5-language support to all auth screens MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Add svelte-i18n and @manacore/shared-i18n to Chat, Presi, Zitare - Create LanguageSelector component for each app - Add locale files for DE, EN, IT, FR, ES in all apps - Update auth pages (login, register, forgot-password) to use shared translations - Add headerControls snippet to RegisterPage and ForgotPasswordPage - Export ZitareLogo and NutriPhiLogo from shared-branding 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude --- apps/chat/apps/web/package.json | 3 +- .../lib/components/LanguageSelector.svelte | 20 +++++++ apps/chat/apps/web/src/lib/i18n/index.ts | 52 +++++++++++++++++++ .../apps/web/src/lib/i18n/locales/de.json | 13 +++++ .../apps/web/src/lib/i18n/locales/en.json | 13 +++++ .../apps/web/src/lib/i18n/locales/es.json | 13 +++++ .../apps/web/src/lib/i18n/locales/fr.json | 13 +++++ .../apps/web/src/lib/i18n/locales/it.json | 13 +++++ .../(auth)/forgot-password/+page.svelte | 27 ++++------ .../web/src/routes/(auth)/login/+page.svelte | 36 ++++--------- .../src/routes/(auth)/register/+page.svelte | 34 ++++-------- apps/picture/apps/web/src/lib/i18n/index.ts | 5 +- .../apps/web/src/lib/i18n/locales/es.json | 23 ++++++++ .../apps/web/src/lib/i18n/locales/fr.json | 23 ++++++++ .../apps/web/src/lib/i18n/locales/it.json | 23 ++++++++ apps/presi/apps/web/package.json | 4 +- .../lib/components/LanguageSelector.svelte | 20 +++++++ apps/presi/apps/web/src/lib/i18n/index.ts | 52 +++++++++++++++++++ .../apps/web/src/lib/i18n/locales/de.json | 13 +++++ .../apps/web/src/lib/i18n/locales/en.json | 13 +++++ .../apps/web/src/lib/i18n/locales/es.json | 13 +++++ .../apps/web/src/lib/i18n/locales/fr.json | 13 +++++ .../apps/web/src/lib/i18n/locales/it.json | 13 +++++ .../src/routes/forgot-password/+page.svelte | 25 ++++----- .../apps/web/src/routes/login/+page.svelte | 36 ++++--------- .../apps/web/src/routes/register/+page.svelte | 34 ++++-------- apps/zitare/apps/web/package.json | 4 +- .../lib/components/LanguageSelector.svelte | 20 +++++++ apps/zitare/apps/web/src/lib/i18n/index.ts | 52 +++++++++++++++++++ .../apps/web/src/lib/i18n/locales/de.json | 13 +++++ .../apps/web/src/lib/i18n/locales/en.json | 13 +++++ .../apps/web/src/lib/i18n/locales/es.json | 13 +++++ .../apps/web/src/lib/i18n/locales/fr.json | 13 +++++ .../apps/web/src/lib/i18n/locales/it.json | 13 +++++ .../(auth)/forgot-password/+page.svelte | 15 +++++- .../web/src/routes/(auth)/login/+page.svelte | 15 +++++- .../src/routes/(auth)/register/+page.svelte | 15 +++++- .../src/pages/ForgotPasswordPage.svelte | 9 ++++ .../src/pages/RegisterPage.svelte | 9 ++++ packages/shared-branding/src/index.ts | 2 + pnpm-lock.yaml | 15 ++++++ 41 files changed, 626 insertions(+), 142 deletions(-) create mode 100644 apps/chat/apps/web/src/lib/components/LanguageSelector.svelte create mode 100644 apps/chat/apps/web/src/lib/i18n/index.ts create mode 100644 apps/chat/apps/web/src/lib/i18n/locales/de.json create mode 100644 apps/chat/apps/web/src/lib/i18n/locales/en.json create mode 100644 apps/chat/apps/web/src/lib/i18n/locales/es.json create mode 100644 apps/chat/apps/web/src/lib/i18n/locales/fr.json create mode 100644 apps/chat/apps/web/src/lib/i18n/locales/it.json create mode 100644 apps/picture/apps/web/src/lib/i18n/locales/es.json create mode 100644 apps/picture/apps/web/src/lib/i18n/locales/fr.json create mode 100644 apps/picture/apps/web/src/lib/i18n/locales/it.json create mode 100644 apps/presi/apps/web/src/lib/components/LanguageSelector.svelte create mode 100644 apps/presi/apps/web/src/lib/i18n/index.ts create mode 100644 apps/presi/apps/web/src/lib/i18n/locales/de.json create mode 100644 apps/presi/apps/web/src/lib/i18n/locales/en.json create mode 100644 apps/presi/apps/web/src/lib/i18n/locales/es.json create mode 100644 apps/presi/apps/web/src/lib/i18n/locales/fr.json create mode 100644 apps/presi/apps/web/src/lib/i18n/locales/it.json create mode 100644 apps/zitare/apps/web/src/lib/components/LanguageSelector.svelte create mode 100644 apps/zitare/apps/web/src/lib/i18n/index.ts create mode 100644 apps/zitare/apps/web/src/lib/i18n/locales/de.json create mode 100644 apps/zitare/apps/web/src/lib/i18n/locales/en.json create mode 100644 apps/zitare/apps/web/src/lib/i18n/locales/es.json create mode 100644 apps/zitare/apps/web/src/lib/i18n/locales/fr.json create mode 100644 apps/zitare/apps/web/src/lib/i18n/locales/it.json diff --git a/apps/chat/apps/web/package.json b/apps/chat/apps/web/package.json index f02d0eec0..66f3ded4e 100644 --- a/apps/chat/apps/web/package.json +++ b/apps/chat/apps/web/package.json @@ -42,6 +42,7 @@ "@manacore/shared-profile-ui": "workspace:*", "@manacore/shared-ui": "workspace:*", "@manacore/shared-utils": "workspace:*", - "marked": "^17.0.0" + "marked": "^17.0.0", + "svelte-i18n": "^4.0.1" } } diff --git a/apps/chat/apps/web/src/lib/components/LanguageSelector.svelte b/apps/chat/apps/web/src/lib/components/LanguageSelector.svelte new file mode 100644 index 000000000..8b7cd2b55 --- /dev/null +++ b/apps/chat/apps/web/src/lib/components/LanguageSelector.svelte @@ -0,0 +1,20 @@ + + + diff --git a/apps/chat/apps/web/src/lib/i18n/index.ts b/apps/chat/apps/web/src/lib/i18n/index.ts new file mode 100644 index 000000000..7634ae4ad --- /dev/null +++ b/apps/chat/apps/web/src/lib/i18n/index.ts @@ -0,0 +1,52 @@ +import { browser } from '$app/environment'; +import { init, register, locale, waitLocale } from 'svelte-i18n'; + +// List of supported locales +export const supportedLocales = ['de', 'en', 'it', 'fr', 'es'] as const; +export type SupportedLocale = (typeof supportedLocales)[number]; + +// Default locale +const defaultLocale = 'de'; + +// Register all available locales +register('de', () => import('./locales/de.json')); +register('en', () => import('./locales/en.json')); +register('it', () => import('./locales/it.json')); +register('fr', () => import('./locales/fr.json')); +register('es', () => import('./locales/es.json')); + +// Get initial locale from browser or localStorage +function getInitialLocale(): SupportedLocale { + if (browser) { + // Check localStorage first + const stored = localStorage.getItem('chat_locale'); + if (stored && supportedLocales.includes(stored as SupportedLocale)) { + return stored as SupportedLocale; + } + + // Fall back to browser language + const browserLang = navigator.language.split('-')[0]; + if (supportedLocales.includes(browserLang as SupportedLocale)) { + return browserLang as SupportedLocale; + } + } + + return defaultLocale; +} + +// Initialize i18n at module scope (required for SSR) +init({ + fallbackLocale: defaultLocale, + initialLocale: getInitialLocale(), +}); + +// Set locale and persist to localStorage +export function setLocale(newLocale: SupportedLocale) { + locale.set(newLocale); + if (browser) { + localStorage.setItem('chat_locale', newLocale); + } +} + +// Wait for locale to be loaded (useful for SSR) +export { waitLocale }; diff --git a/apps/chat/apps/web/src/lib/i18n/locales/de.json b/apps/chat/apps/web/src/lib/i18n/locales/de.json new file mode 100644 index 000000000..a34ffac83 --- /dev/null +++ b/apps/chat/apps/web/src/lib/i18n/locales/de.json @@ -0,0 +1,13 @@ +{ + "app_slider": { + "title": "Weitere Manacore Apps", + "memoro_desc": "KI-gestützte Sprachmemos", + "maerchenzauber_desc": "Magische Gute-Nacht-Geschichten", + "manadeck_desc": "KI Lernkarten", + "picture_desc": "KI Bildgenerierung", + "moodlit_desc": "Dein Stimmungsbegleiter", + "manacore_desc": "KI-Produktivitätssuite", + "coming_soon": "Demnächst", + "download": "Download" + } +} diff --git a/apps/chat/apps/web/src/lib/i18n/locales/en.json b/apps/chat/apps/web/src/lib/i18n/locales/en.json new file mode 100644 index 000000000..de8951cf7 --- /dev/null +++ b/apps/chat/apps/web/src/lib/i18n/locales/en.json @@ -0,0 +1,13 @@ +{ + "app_slider": { + "title": "More Manacore Apps", + "memoro_desc": "AI-powered voice memos", + "maerchenzauber_desc": "Magical bedtime stories", + "manadeck_desc": "AI flashcards", + "picture_desc": "AI image generation", + "moodlit_desc": "Your mood companion", + "manacore_desc": "AI productivity suite", + "coming_soon": "Coming soon", + "download": "Download" + } +} diff --git a/apps/chat/apps/web/src/lib/i18n/locales/es.json b/apps/chat/apps/web/src/lib/i18n/locales/es.json new file mode 100644 index 000000000..381a82335 --- /dev/null +++ b/apps/chat/apps/web/src/lib/i18n/locales/es.json @@ -0,0 +1,13 @@ +{ + "app_slider": { + "title": "Más Apps de Manacore", + "memoro_desc": "Notas de voz con IA", + "maerchenzauber_desc": "Cuentos mágicos para dormir", + "manadeck_desc": "Flashcards con IA", + "picture_desc": "Generación de imágenes con IA", + "moodlit_desc": "Tu compañero de ánimo", + "manacore_desc": "Suite de productividad IA", + "coming_soon": "Próximamente", + "download": "Descargar" + } +} diff --git a/apps/chat/apps/web/src/lib/i18n/locales/fr.json b/apps/chat/apps/web/src/lib/i18n/locales/fr.json new file mode 100644 index 000000000..756dd891c --- /dev/null +++ b/apps/chat/apps/web/src/lib/i18n/locales/fr.json @@ -0,0 +1,13 @@ +{ + "app_slider": { + "title": "Autres Apps Manacore", + "memoro_desc": "Mémos vocaux avec IA", + "maerchenzauber_desc": "Histoires magiques du soir", + "manadeck_desc": "Flashcards avec IA", + "picture_desc": "Génération d'images avec IA", + "moodlit_desc": "Ton compagnon d'humeur", + "manacore_desc": "Suite de productivité IA", + "coming_soon": "Bientôt disponible", + "download": "Télécharger" + } +} diff --git a/apps/chat/apps/web/src/lib/i18n/locales/it.json b/apps/chat/apps/web/src/lib/i18n/locales/it.json new file mode 100644 index 000000000..223bf728e --- /dev/null +++ b/apps/chat/apps/web/src/lib/i18n/locales/it.json @@ -0,0 +1,13 @@ +{ + "app_slider": { + "title": "Altre App Manacore", + "memoro_desc": "Memo vocali con IA", + "maerchenzauber_desc": "Storie magiche della buonanotte", + "manadeck_desc": "Flashcard con IA", + "picture_desc": "Generazione immagini con IA", + "moodlit_desc": "Il tuo compagno d'umore", + "manacore_desc": "Suite di produttività IA", + "coming_soon": "Prossimamente", + "download": "Scarica" + } +} diff --git a/apps/chat/apps/web/src/routes/(auth)/forgot-password/+page.svelte b/apps/chat/apps/web/src/routes/(auth)/forgot-password/+page.svelte index 3283aa3a8..7d651cdc1 100644 --- a/apps/chat/apps/web/src/routes/(auth)/forgot-password/+page.svelte +++ b/apps/chat/apps/web/src/routes/(auth)/forgot-password/+page.svelte @@ -1,26 +1,16 @@ - Passwort zurücksetzen | ManaChat + {translations.titleForm} | ManaChat + {#snippet headerControls()} + + {/snippet} {#snippet appSlider()} {/snippet} diff --git a/apps/chat/apps/web/src/routes/(auth)/login/+page.svelte b/apps/chat/apps/web/src/routes/(auth)/login/+page.svelte index e8c5718c0..74e946977 100644 --- a/apps/chat/apps/web/src/routes/(auth)/login/+page.svelte +++ b/apps/chat/apps/web/src/routes/(auth)/login/+page.svelte @@ -1,39 +1,20 @@ - Anmelden | ManaChat + {translations.title} | ManaChat + {#snippet headerControls()} + + {/snippet} {#snippet appSlider()} {/snippet} diff --git a/apps/chat/apps/web/src/routes/(auth)/register/+page.svelte b/apps/chat/apps/web/src/routes/(auth)/register/+page.svelte index 4761a09bd..35dc40839 100644 --- a/apps/chat/apps/web/src/routes/(auth)/register/+page.svelte +++ b/apps/chat/apps/web/src/routes/(auth)/register/+page.svelte @@ -1,33 +1,16 @@ - Registrieren | ManaChat + {translations.title} | ManaChat + {#snippet headerControls()} + + {/snippet} {#snippet appSlider()} {/snippet} diff --git a/apps/picture/apps/web/src/lib/i18n/index.ts b/apps/picture/apps/web/src/lib/i18n/index.ts index 7a6cba119..2706251dd 100644 --- a/apps/picture/apps/web/src/lib/i18n/index.ts +++ b/apps/picture/apps/web/src/lib/i18n/index.ts @@ -2,7 +2,7 @@ import { browser } from '$app/environment'; import { init, register, locale, waitLocale } from 'svelte-i18n'; // List of supported locales -export const supportedLocales = ['de', 'en'] as const; +export const supportedLocales = ['de', 'en', 'it', 'fr', 'es'] as const; export type SupportedLocale = (typeof supportedLocales)[number]; // Default locale @@ -11,6 +11,9 @@ const defaultLocale = 'de'; // Register all available locales register('de', () => import('./locales/de.json')); register('en', () => import('./locales/en.json')); +register('it', () => import('./locales/it.json')); +register('fr', () => import('./locales/fr.json')); +register('es', () => import('./locales/es.json')); // Get initial locale from browser or localStorage function getInitialLocale(): SupportedLocale { diff --git a/apps/picture/apps/web/src/lib/i18n/locales/es.json b/apps/picture/apps/web/src/lib/i18n/locales/es.json new file mode 100644 index 000000000..0808e6891 --- /dev/null +++ b/apps/picture/apps/web/src/lib/i18n/locales/es.json @@ -0,0 +1,23 @@ +{ + "app_slider": { + "title": "Más Apps de Manacore", + "memoro_desc": "Notas de voz con IA", + "memoro_long_desc": "Transforma tu voz en notas organizadas y accionables con transcripción y análisis impulsados por IA. Perfecto para capturar ideas en movimiento.", + "maerchenzauber_desc": "Cuentos mágicos para dormir", + "maerchenzauber_long_desc": "Crea cuentos personalizados para dormir para tus hijos con IA. Enciende la imaginación y haz cada noche mágica con narrativas únicas.", + "manadeck_desc": "Flashcards con IA", + "manadeck_long_desc": "Crea y estudia con flashcards inteligentes y repetición espaciada impulsada por IA.", + "picture_desc": "Generación de imágenes con IA", + "picture_long_desc": "Crea imágenes impresionantes con IA. Transforma tus ideas en obras de arte visuales en segundos.", + "moodlit_desc": "Tu compañero de ánimo", + "moodlit_long_desc": "Rastrea y comprende tus emociones con análisis impulsados por IA. Desarrolla conciencia emocional y mejora tu bienestar mental.", + "manacore_desc": "Suite de productividad IA", + "manacore_long_desc": "El centro para todas las apps de Manacore. Gestiona tus suscripciones, sincroniza datos y accede a potentes herramientas de IA desde un solo lugar.", + "coming_soon": "Próximamente", + "download": "Descargar", + "status_published": "Publicado", + "status_beta": "Beta", + "status_development": "En desarrollo", + "status_planning": "Planificado" + } +} diff --git a/apps/picture/apps/web/src/lib/i18n/locales/fr.json b/apps/picture/apps/web/src/lib/i18n/locales/fr.json new file mode 100644 index 000000000..5dbee58e3 --- /dev/null +++ b/apps/picture/apps/web/src/lib/i18n/locales/fr.json @@ -0,0 +1,23 @@ +{ + "app_slider": { + "title": "Autres Apps Manacore", + "memoro_desc": "Mémos vocaux avec IA", + "memoro_long_desc": "Transformez votre voix en notes organisées et exploitables grâce à la transcription et l'analyse alimentées par l'IA. Parfait pour capturer des idées en déplacement.", + "maerchenzauber_desc": "Histoires magiques du soir", + "maerchenzauber_long_desc": "Créez des histoires du soir personnalisées pour vos enfants avec l'IA. Éveillez l'imagination et rendez chaque nuit magique avec des récits uniques.", + "manadeck_desc": "Flashcards avec IA", + "manadeck_long_desc": "Créez et apprenez avec des flashcards intelligentes et une répétition espacée alimentée par l'IA.", + "picture_desc": "Génération d'images avec IA", + "picture_long_desc": "Créez des images époustouflantes avec l'IA. Transformez vos idées en œuvres d'art visuelles en quelques secondes.", + "moodlit_desc": "Ton compagnon d'humeur", + "moodlit_long_desc": "Suivez et comprenez vos émotions grâce aux analyses alimentées par l'IA. Développez votre conscience émotionnelle et améliorez votre bien-être mental.", + "manacore_desc": "Suite de productivité IA", + "manacore_long_desc": "Le hub central pour toutes les apps Manacore. Gérez vos abonnements, synchronisez vos données et accédez à de puissants outils IA depuis un seul endroit.", + "coming_soon": "Bientôt disponible", + "download": "Télécharger", + "status_published": "Publié", + "status_beta": "Bêta", + "status_development": "En développement", + "status_planning": "Planifié" + } +} diff --git a/apps/picture/apps/web/src/lib/i18n/locales/it.json b/apps/picture/apps/web/src/lib/i18n/locales/it.json new file mode 100644 index 000000000..ab5d948fa --- /dev/null +++ b/apps/picture/apps/web/src/lib/i18n/locales/it.json @@ -0,0 +1,23 @@ +{ + "app_slider": { + "title": "Altre App Manacore", + "memoro_desc": "Memo vocali con IA", + "memoro_long_desc": "Trasforma la tua voce in appunti organizzati e azionabili con trascrizione e analisi basate su IA. Perfetto per catturare idee in movimento.", + "maerchenzauber_desc": "Storie magiche della buonanotte", + "maerchenzauber_long_desc": "Crea storie della buonanotte personalizzate per i tuoi bambini con l'IA. Accendi l'immaginazione e rendi ogni notte magica con racconti unici.", + "manadeck_desc": "Flashcard con IA", + "manadeck_long_desc": "Crea e studia con flashcard intelligenti e ripetizione spaziata basata su IA.", + "picture_desc": "Generazione immagini con IA", + "picture_long_desc": "Crea immagini straordinarie con l'IA. Trasforma le tue idee in opere d'arte visive in pochi secondi.", + "moodlit_desc": "Il tuo compagno d'umore", + "moodlit_long_desc": "Monitora e comprendi le tue emozioni con approfondimenti basati su IA. Sviluppa la consapevolezza emotiva e migliora il tuo benessere mentale.", + "manacore_desc": "Suite di produttività IA", + "manacore_long_desc": "L'hub centrale per tutte le app Manacore. Gestisci i tuoi abbonamenti, sincronizza i dati e accedi a potenti strumenti IA da un unico posto.", + "coming_soon": "Prossimamente", + "download": "Scarica", + "status_published": "Pubblicato", + "status_beta": "Beta", + "status_development": "In sviluppo", + "status_planning": "Pianificato" + } +} diff --git a/apps/presi/apps/web/package.json b/apps/presi/apps/web/package.json index 0bee5d4f1..b20d47da3 100644 --- a/apps/presi/apps/web/package.json +++ b/apps/presi/apps/web/package.json @@ -35,6 +35,7 @@ "@manacore/shared-branding": "workspace:*", "@manacore/shared-feedback-service": "workspace:*", "@manacore/shared-feedback-ui": "workspace:*", + "@manacore/shared-i18n": "workspace:*", "@manacore/shared-icons": "workspace:*", "@manacore/shared-profile-ui": "workspace:*", "@manacore/shared-subscription-ui": "workspace:*", @@ -42,7 +43,8 @@ "@manacore/shared-theme": "workspace:*", "@manacore/shared-theme-ui": "workspace:*", "@manacore/shared-ui": "workspace:*", - "lucide-svelte": "^0.460.0" + "lucide-svelte": "^0.460.0", + "svelte-i18n": "^4.0.1" }, "type": "module" } diff --git a/apps/presi/apps/web/src/lib/components/LanguageSelector.svelte b/apps/presi/apps/web/src/lib/components/LanguageSelector.svelte new file mode 100644 index 000000000..072a68eac --- /dev/null +++ b/apps/presi/apps/web/src/lib/components/LanguageSelector.svelte @@ -0,0 +1,20 @@ + + + diff --git a/apps/presi/apps/web/src/lib/i18n/index.ts b/apps/presi/apps/web/src/lib/i18n/index.ts new file mode 100644 index 000000000..acf6fc325 --- /dev/null +++ b/apps/presi/apps/web/src/lib/i18n/index.ts @@ -0,0 +1,52 @@ +import { browser } from '$app/environment'; +import { init, register, locale, waitLocale } from 'svelte-i18n'; + +// List of supported locales +export const supportedLocales = ['de', 'en', 'it', 'fr', 'es'] as const; +export type SupportedLocale = (typeof supportedLocales)[number]; + +// Default locale +const defaultLocale = 'de'; + +// Register all available locales +register('de', () => import('./locales/de.json')); +register('en', () => import('./locales/en.json')); +register('it', () => import('./locales/it.json')); +register('fr', () => import('./locales/fr.json')); +register('es', () => import('./locales/es.json')); + +// Get initial locale from browser or localStorage +function getInitialLocale(): SupportedLocale { + if (browser) { + // Check localStorage first + const stored = localStorage.getItem('presi_locale'); + if (stored && supportedLocales.includes(stored as SupportedLocale)) { + return stored as SupportedLocale; + } + + // Fall back to browser language + const browserLang = navigator.language.split('-')[0]; + if (supportedLocales.includes(browserLang as SupportedLocale)) { + return browserLang as SupportedLocale; + } + } + + return defaultLocale; +} + +// Initialize i18n at module scope (required for SSR) +init({ + fallbackLocale: defaultLocale, + initialLocale: getInitialLocale(), +}); + +// Set locale and persist to localStorage +export function setLocale(newLocale: SupportedLocale) { + locale.set(newLocale); + if (browser) { + localStorage.setItem('presi_locale', newLocale); + } +} + +// Wait for locale to be loaded (useful for SSR) +export { waitLocale }; diff --git a/apps/presi/apps/web/src/lib/i18n/locales/de.json b/apps/presi/apps/web/src/lib/i18n/locales/de.json new file mode 100644 index 000000000..a34ffac83 --- /dev/null +++ b/apps/presi/apps/web/src/lib/i18n/locales/de.json @@ -0,0 +1,13 @@ +{ + "app_slider": { + "title": "Weitere Manacore Apps", + "memoro_desc": "KI-gestützte Sprachmemos", + "maerchenzauber_desc": "Magische Gute-Nacht-Geschichten", + "manadeck_desc": "KI Lernkarten", + "picture_desc": "KI Bildgenerierung", + "moodlit_desc": "Dein Stimmungsbegleiter", + "manacore_desc": "KI-Produktivitätssuite", + "coming_soon": "Demnächst", + "download": "Download" + } +} diff --git a/apps/presi/apps/web/src/lib/i18n/locales/en.json b/apps/presi/apps/web/src/lib/i18n/locales/en.json new file mode 100644 index 000000000..de8951cf7 --- /dev/null +++ b/apps/presi/apps/web/src/lib/i18n/locales/en.json @@ -0,0 +1,13 @@ +{ + "app_slider": { + "title": "More Manacore Apps", + "memoro_desc": "AI-powered voice memos", + "maerchenzauber_desc": "Magical bedtime stories", + "manadeck_desc": "AI flashcards", + "picture_desc": "AI image generation", + "moodlit_desc": "Your mood companion", + "manacore_desc": "AI productivity suite", + "coming_soon": "Coming soon", + "download": "Download" + } +} diff --git a/apps/presi/apps/web/src/lib/i18n/locales/es.json b/apps/presi/apps/web/src/lib/i18n/locales/es.json new file mode 100644 index 000000000..381a82335 --- /dev/null +++ b/apps/presi/apps/web/src/lib/i18n/locales/es.json @@ -0,0 +1,13 @@ +{ + "app_slider": { + "title": "Más Apps de Manacore", + "memoro_desc": "Notas de voz con IA", + "maerchenzauber_desc": "Cuentos mágicos para dormir", + "manadeck_desc": "Flashcards con IA", + "picture_desc": "Generación de imágenes con IA", + "moodlit_desc": "Tu compañero de ánimo", + "manacore_desc": "Suite de productividad IA", + "coming_soon": "Próximamente", + "download": "Descargar" + } +} diff --git a/apps/presi/apps/web/src/lib/i18n/locales/fr.json b/apps/presi/apps/web/src/lib/i18n/locales/fr.json new file mode 100644 index 000000000..756dd891c --- /dev/null +++ b/apps/presi/apps/web/src/lib/i18n/locales/fr.json @@ -0,0 +1,13 @@ +{ + "app_slider": { + "title": "Autres Apps Manacore", + "memoro_desc": "Mémos vocaux avec IA", + "maerchenzauber_desc": "Histoires magiques du soir", + "manadeck_desc": "Flashcards avec IA", + "picture_desc": "Génération d'images avec IA", + "moodlit_desc": "Ton compagnon d'humeur", + "manacore_desc": "Suite de productivité IA", + "coming_soon": "Bientôt disponible", + "download": "Télécharger" + } +} diff --git a/apps/presi/apps/web/src/lib/i18n/locales/it.json b/apps/presi/apps/web/src/lib/i18n/locales/it.json new file mode 100644 index 000000000..223bf728e --- /dev/null +++ b/apps/presi/apps/web/src/lib/i18n/locales/it.json @@ -0,0 +1,13 @@ +{ + "app_slider": { + "title": "Altre App Manacore", + "memoro_desc": "Memo vocali con IA", + "maerchenzauber_desc": "Storie magiche della buonanotte", + "manadeck_desc": "Flashcard con IA", + "picture_desc": "Generazione immagini con IA", + "moodlit_desc": "Il tuo compagno d'umore", + "manacore_desc": "Suite di produttività IA", + "coming_soon": "Prossimamente", + "download": "Scarica" + } +} diff --git a/apps/presi/apps/web/src/routes/forgot-password/+page.svelte b/apps/presi/apps/web/src/routes/forgot-password/+page.svelte index e6cd36efd..6d64ad0a3 100644 --- a/apps/presi/apps/web/src/routes/forgot-password/+page.svelte +++ b/apps/presi/apps/web/src/routes/forgot-password/+page.svelte @@ -1,24 +1,16 @@ - Forgot Password | Presi + {translations.titleForm} | Presi + {#snippet headerControls()} + + {/snippet} {#snippet appSlider()} {/snippet} diff --git a/apps/presi/apps/web/src/routes/login/+page.svelte b/apps/presi/apps/web/src/routes/login/+page.svelte index ee687e9e5..1de53fb3b 100644 --- a/apps/presi/apps/web/src/routes/login/+page.svelte +++ b/apps/presi/apps/web/src/routes/login/+page.svelte @@ -1,39 +1,20 @@ - Login | Presi + {translations.title} | Presi + {#snippet headerControls()} + + {/snippet} {#snippet appSlider()} {/snippet} diff --git a/apps/presi/apps/web/src/routes/register/+page.svelte b/apps/presi/apps/web/src/routes/register/+page.svelte index 18056ed1f..6c76ec2ae 100644 --- a/apps/presi/apps/web/src/routes/register/+page.svelte +++ b/apps/presi/apps/web/src/routes/register/+page.svelte @@ -1,33 +1,16 @@ - Register | Presi + {translations.title} | Presi + {#snippet headerControls()} + + {/snippet} {#snippet appSlider()} {/snippet} diff --git a/apps/zitare/apps/web/package.json b/apps/zitare/apps/web/package.json index 43a97cbbd..0e17ae941 100644 --- a/apps/zitare/apps/web/package.json +++ b/apps/zitare/apps/web/package.json @@ -32,6 +32,7 @@ "@manacore/shared-branding": "workspace:*", "@manacore/shared-feedback-service": "workspace:*", "@manacore/shared-feedback-ui": "workspace:*", + "@manacore/shared-i18n": "workspace:*", "@manacore/shared-icons": "workspace:*", "@manacore/shared-profile-ui": "workspace:*", "@manacore/shared-subscription-ui": "workspace:*", @@ -40,7 +41,8 @@ "@manacore/shared-theme-ui": "workspace:*", "@manacore/shared-ui": "workspace:*", "@zitare/shared": "workspace:*", - "@zitare/web-ui": "workspace:*" + "@zitare/web-ui": "workspace:*", + "svelte-i18n": "^4.0.1" }, "type": "module" } diff --git a/apps/zitare/apps/web/src/lib/components/LanguageSelector.svelte b/apps/zitare/apps/web/src/lib/components/LanguageSelector.svelte new file mode 100644 index 000000000..97183be0b --- /dev/null +++ b/apps/zitare/apps/web/src/lib/components/LanguageSelector.svelte @@ -0,0 +1,20 @@ + + + diff --git a/apps/zitare/apps/web/src/lib/i18n/index.ts b/apps/zitare/apps/web/src/lib/i18n/index.ts new file mode 100644 index 000000000..bbd3a9e1d --- /dev/null +++ b/apps/zitare/apps/web/src/lib/i18n/index.ts @@ -0,0 +1,52 @@ +import { browser } from '$app/environment'; +import { init, register, locale, waitLocale } from 'svelte-i18n'; + +// List of supported locales +export const supportedLocales = ['de', 'en', 'it', 'fr', 'es'] as const; +export type SupportedLocale = (typeof supportedLocales)[number]; + +// Default locale +const defaultLocale = 'de'; + +// Register all available locales +register('de', () => import('./locales/de.json')); +register('en', () => import('./locales/en.json')); +register('it', () => import('./locales/it.json')); +register('fr', () => import('./locales/fr.json')); +register('es', () => import('./locales/es.json')); + +// Get initial locale from browser or localStorage +function getInitialLocale(): SupportedLocale { + if (browser) { + // Check localStorage first + const stored = localStorage.getItem('zitare_locale'); + if (stored && supportedLocales.includes(stored as SupportedLocale)) { + return stored as SupportedLocale; + } + + // Fall back to browser language + const browserLang = navigator.language.split('-')[0]; + if (supportedLocales.includes(browserLang as SupportedLocale)) { + return browserLang as SupportedLocale; + } + } + + return defaultLocale; +} + +// Initialize i18n at module scope (required for SSR) +init({ + fallbackLocale: defaultLocale, + initialLocale: getInitialLocale(), +}); + +// Set locale and persist to localStorage +export function setLocale(newLocale: SupportedLocale) { + locale.set(newLocale); + if (browser) { + localStorage.setItem('zitare_locale', newLocale); + } +} + +// Wait for locale to be loaded (useful for SSR) +export { waitLocale }; diff --git a/apps/zitare/apps/web/src/lib/i18n/locales/de.json b/apps/zitare/apps/web/src/lib/i18n/locales/de.json new file mode 100644 index 000000000..a34ffac83 --- /dev/null +++ b/apps/zitare/apps/web/src/lib/i18n/locales/de.json @@ -0,0 +1,13 @@ +{ + "app_slider": { + "title": "Weitere Manacore Apps", + "memoro_desc": "KI-gestützte Sprachmemos", + "maerchenzauber_desc": "Magische Gute-Nacht-Geschichten", + "manadeck_desc": "KI Lernkarten", + "picture_desc": "KI Bildgenerierung", + "moodlit_desc": "Dein Stimmungsbegleiter", + "manacore_desc": "KI-Produktivitätssuite", + "coming_soon": "Demnächst", + "download": "Download" + } +} diff --git a/apps/zitare/apps/web/src/lib/i18n/locales/en.json b/apps/zitare/apps/web/src/lib/i18n/locales/en.json new file mode 100644 index 000000000..de8951cf7 --- /dev/null +++ b/apps/zitare/apps/web/src/lib/i18n/locales/en.json @@ -0,0 +1,13 @@ +{ + "app_slider": { + "title": "More Manacore Apps", + "memoro_desc": "AI-powered voice memos", + "maerchenzauber_desc": "Magical bedtime stories", + "manadeck_desc": "AI flashcards", + "picture_desc": "AI image generation", + "moodlit_desc": "Your mood companion", + "manacore_desc": "AI productivity suite", + "coming_soon": "Coming soon", + "download": "Download" + } +} diff --git a/apps/zitare/apps/web/src/lib/i18n/locales/es.json b/apps/zitare/apps/web/src/lib/i18n/locales/es.json new file mode 100644 index 000000000..381a82335 --- /dev/null +++ b/apps/zitare/apps/web/src/lib/i18n/locales/es.json @@ -0,0 +1,13 @@ +{ + "app_slider": { + "title": "Más Apps de Manacore", + "memoro_desc": "Notas de voz con IA", + "maerchenzauber_desc": "Cuentos mágicos para dormir", + "manadeck_desc": "Flashcards con IA", + "picture_desc": "Generación de imágenes con IA", + "moodlit_desc": "Tu compañero de ánimo", + "manacore_desc": "Suite de productividad IA", + "coming_soon": "Próximamente", + "download": "Descargar" + } +} diff --git a/apps/zitare/apps/web/src/lib/i18n/locales/fr.json b/apps/zitare/apps/web/src/lib/i18n/locales/fr.json new file mode 100644 index 000000000..756dd891c --- /dev/null +++ b/apps/zitare/apps/web/src/lib/i18n/locales/fr.json @@ -0,0 +1,13 @@ +{ + "app_slider": { + "title": "Autres Apps Manacore", + "memoro_desc": "Mémos vocaux avec IA", + "maerchenzauber_desc": "Histoires magiques du soir", + "manadeck_desc": "Flashcards avec IA", + "picture_desc": "Génération d'images avec IA", + "moodlit_desc": "Ton compagnon d'humeur", + "manacore_desc": "Suite de productivité IA", + "coming_soon": "Bientôt disponible", + "download": "Télécharger" + } +} diff --git a/apps/zitare/apps/web/src/lib/i18n/locales/it.json b/apps/zitare/apps/web/src/lib/i18n/locales/it.json new file mode 100644 index 000000000..223bf728e --- /dev/null +++ b/apps/zitare/apps/web/src/lib/i18n/locales/it.json @@ -0,0 +1,13 @@ +{ + "app_slider": { + "title": "Altre App Manacore", + "memoro_desc": "Memo vocali con IA", + "maerchenzauber_desc": "Storie magiche della buonanotte", + "manadeck_desc": "Flashcard con IA", + "picture_desc": "Generazione immagini con IA", + "moodlit_desc": "Il tuo compagno d'umore", + "manacore_desc": "Suite di produttività IA", + "coming_soon": "Prossimamente", + "download": "Scarica" + } +} diff --git a/apps/zitare/apps/web/src/routes/(auth)/forgot-password/+page.svelte b/apps/zitare/apps/web/src/routes/(auth)/forgot-password/+page.svelte index 77bdcfa45..3bc7595db 100644 --- a/apps/zitare/apps/web/src/routes/(auth)/forgot-password/+page.svelte +++ b/apps/zitare/apps/web/src/routes/(auth)/forgot-password/+page.svelte @@ -1,8 +1,14 @@ - Passwort vergessen - Zitare + {translations.titleForm} - Zitare + {translations} +> + {#snippet headerControls()} + + {/snippet} + diff --git a/apps/zitare/apps/web/src/routes/(auth)/login/+page.svelte b/apps/zitare/apps/web/src/routes/(auth)/login/+page.svelte index b0d63703e..26372c9d6 100644 --- a/apps/zitare/apps/web/src/routes/(auth)/login/+page.svelte +++ b/apps/zitare/apps/web/src/routes/(auth)/login/+page.svelte @@ -1,8 +1,14 @@ - Anmelden - Zitare + {translations.title} - Zitare + {translations} +> + {#snippet headerControls()} + + {/snippet} + diff --git a/apps/zitare/apps/web/src/routes/(auth)/register/+page.svelte b/apps/zitare/apps/web/src/routes/(auth)/register/+page.svelte index 4d35fda6a..6e46f40a0 100644 --- a/apps/zitare/apps/web/src/routes/(auth)/register/+page.svelte +++ b/apps/zitare/apps/web/src/routes/(auth)/register/+page.svelte @@ -1,8 +1,14 @@ - Registrieren - Zitare + {translations.title} - Zitare + {translations} +> + {#snippet headerControls()} + + {/snippet} + diff --git a/packages/shared-auth-ui/src/pages/ForgotPasswordPage.svelte b/packages/shared-auth-ui/src/pages/ForgotPasswordPage.svelte index 30c293430..fb3ace7f2 100644 --- a/packages/shared-auth-ui/src/pages/ForgotPasswordPage.svelte +++ b/packages/shared-auth-ui/src/pages/ForgotPasswordPage.svelte @@ -56,6 +56,8 @@ darkBackground?: string; /** App slider snippet */ appSlider?: Snippet; + /** Header controls snippet (e.g., language selector) */ + headerControls?: Snippet; /** Translations for i18n support */ translations?: Partial; } @@ -70,6 +72,7 @@ lightBackground = '#f5f5f5', darkBackground = '#121212', appSlider, + headerControls, translations = {}, }: Props = $props(); @@ -138,6 +141,12 @@ class="flex min-h-screen flex-col justify-between" style="background-color: {getPageBackground()}; max-width: 100vw; overflow-x: hidden;" > + {#if headerControls} +
+ {@render headerControls()} +
+ {/if} +
; } @@ -89,6 +91,7 @@ lightBackground = '#f5f5f5', darkBackground = '#121212', appSlider, + headerControls, translations = {}, }: Props = $props(); @@ -220,6 +223,12 @@ class="flex min-h-screen flex-col justify-between" style="background-color: {getPageBackground()}; max-width: 100vw; overflow-x: hidden;" > + {#if headerControls} +
+ {@render headerControls()} +
+ {/if} +