mirror of
https://github.com/Memo-2023/mana-monorepo.git
synced 2026-05-20 04:01:24 +02:00
feat(i18n): add language picker and 5-language support to all auth screens
- 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 <noreply@anthropic.com>
This commit is contained in:
parent
e85ef8babe
commit
eab69c512c
41 changed files with 626 additions and 142 deletions
|
|
@ -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"
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,20 @@
|
|||
<script lang="ts">
|
||||
import { locale } from 'svelte-i18n';
|
||||
import { LanguageSelector } from '@manacore/shared-i18n';
|
||||
import { setLocale, supportedLocales } from '$lib/i18n';
|
||||
import { theme } from '$lib/stores/theme';
|
||||
|
||||
let currentLocale = $derived($locale || 'de');
|
||||
|
||||
function handleLocaleChange(newLocale: string) {
|
||||
setLocale(newLocale as any);
|
||||
}
|
||||
</script>
|
||||
|
||||
<LanguageSelector
|
||||
{currentLocale}
|
||||
{supportedLocales}
|
||||
onLocaleChange={handleLocaleChange}
|
||||
isDark={theme.isDark}
|
||||
primaryColor="#0ea5e9"
|
||||
/>
|
||||
52
apps/chat/apps/web/src/lib/i18n/index.ts
Normal file
52
apps/chat/apps/web/src/lib/i18n/index.ts
Normal file
|
|
@ -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 };
|
||||
13
apps/chat/apps/web/src/lib/i18n/locales/de.json
Normal file
13
apps/chat/apps/web/src/lib/i18n/locales/de.json
Normal file
|
|
@ -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"
|
||||
}
|
||||
}
|
||||
13
apps/chat/apps/web/src/lib/i18n/locales/en.json
Normal file
13
apps/chat/apps/web/src/lib/i18n/locales/en.json
Normal file
|
|
@ -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"
|
||||
}
|
||||
}
|
||||
13
apps/chat/apps/web/src/lib/i18n/locales/es.json
Normal file
13
apps/chat/apps/web/src/lib/i18n/locales/es.json
Normal file
|
|
@ -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"
|
||||
}
|
||||
}
|
||||
13
apps/chat/apps/web/src/lib/i18n/locales/fr.json
Normal file
13
apps/chat/apps/web/src/lib/i18n/locales/fr.json
Normal file
|
|
@ -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"
|
||||
}
|
||||
}
|
||||
13
apps/chat/apps/web/src/lib/i18n/locales/it.json
Normal file
13
apps/chat/apps/web/src/lib/i18n/locales/it.json
Normal file
|
|
@ -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"
|
||||
}
|
||||
}
|
||||
|
|
@ -1,26 +1,16 @@
|
|||
<script lang="ts">
|
||||
import { goto } from '$app/navigation';
|
||||
import { locale } from 'svelte-i18n';
|
||||
import { ForgotPasswordPage } from '@manacore/shared-auth-ui';
|
||||
import { getForgotPasswordTranslations } from '@manacore/shared-i18n';
|
||||
import { ChatLogo } from '@manacore/shared-branding';
|
||||
import { authStore } from '$lib/stores/auth.svelte';
|
||||
import AppSlider from '$lib/components/AppSlider.svelte';
|
||||
import LanguageSelector from '$lib/components/LanguageSelector.svelte';
|
||||
import '$lib/i18n';
|
||||
|
||||
// German translations
|
||||
const translations = {
|
||||
titleForm: 'Passwort zurücksetzen',
|
||||
titleSuccess: 'E-Mail gesendet',
|
||||
description:
|
||||
'Gib deine E-Mail-Adresse ein und wir senden dir einen Link zum Zurücksetzen deines Passworts.',
|
||||
emailPlaceholder: 'E-Mail',
|
||||
sendResetLinkButton: 'Link senden',
|
||||
sending: 'Wird gesendet...',
|
||||
backToLogin: 'Zurück zur Anmeldung',
|
||||
resendEmail: 'E-Mail erneut senden',
|
||||
successMessage:
|
||||
'Wir haben einen Link zum Zurücksetzen deines Passworts an {email} gesendet. Bitte überprüfe deinen Posteingang.',
|
||||
emailRequired: 'E-Mail ist erforderlich',
|
||||
sendFailed: 'Fehler beim Senden der E-Mail',
|
||||
};
|
||||
// Get translations based on current locale
|
||||
const translations = $derived(getForgotPasswordTranslations($locale || 'de'));
|
||||
|
||||
async function handleForgotPassword(email: string) {
|
||||
return authStore.resetPassword(email);
|
||||
|
|
@ -28,7 +18,7 @@
|
|||
</script>
|
||||
|
||||
<svelte:head>
|
||||
<title>Passwort zurücksetzen | ManaChat</title>
|
||||
<title>{translations.titleForm} | ManaChat</title>
|
||||
</svelte:head>
|
||||
|
||||
<ForgotPasswordPage
|
||||
|
|
@ -42,6 +32,9 @@
|
|||
darkBackground="#0c1929"
|
||||
{translations}
|
||||
>
|
||||
{#snippet headerControls()}
|
||||
<LanguageSelector />
|
||||
{/snippet}
|
||||
{#snippet appSlider()}
|
||||
<AppSlider />
|
||||
{/snippet}
|
||||
|
|
|
|||
|
|
@ -1,39 +1,20 @@
|
|||
<script lang="ts">
|
||||
import { goto } from '$app/navigation';
|
||||
import { page } from '$app/stores';
|
||||
import { locale } from 'svelte-i18n';
|
||||
import { LoginPage } from '@manacore/shared-auth-ui';
|
||||
import { getLoginTranslations } from '@manacore/shared-i18n';
|
||||
import { ChatLogo } from '@manacore/shared-branding';
|
||||
import { authStore } from '$lib/stores/auth.svelte';
|
||||
import AppSlider from '$lib/components/AppSlider.svelte';
|
||||
import LanguageSelector from '$lib/components/LanguageSelector.svelte';
|
||||
import '$lib/i18n';
|
||||
|
||||
// Get redirect URL from query params
|
||||
const redirectTo = $derived($page.url.searchParams.get('redirectTo') || '/chat');
|
||||
|
||||
// German translations
|
||||
const translations = {
|
||||
title: 'Anmelden',
|
||||
subtitle: 'Melde dich mit deinem Konto an',
|
||||
emailPlaceholder: 'E-Mail',
|
||||
passwordPlaceholder: 'Passwort',
|
||||
rememberMe: 'Angemeldet bleiben',
|
||||
forgotPassword: 'Passwort vergessen?',
|
||||
signInButton: 'Anmelden',
|
||||
signingIn: 'Wird angemeldet...',
|
||||
success: 'Erfolgreich!',
|
||||
orDivider: 'oder',
|
||||
noAccount: 'Noch kein Konto?',
|
||||
createAccount: 'Jetzt registrieren',
|
||||
skipToForm: 'Zum Login-Formular springen',
|
||||
showPassword: 'Passwort anzeigen',
|
||||
hidePassword: 'Passwort verbergen',
|
||||
emailRequired: 'E-Mail ist erforderlich',
|
||||
emailInvalid: 'Bitte gib eine gültige E-Mail-Adresse ein',
|
||||
passwordRequired: 'Passwort ist erforderlich',
|
||||
signInFailed: 'Anmeldung fehlgeschlagen',
|
||||
googleSignInFailed: 'Google-Anmeldung fehlgeschlagen',
|
||||
signInSuccess: 'Erfolgreich angemeldet. Weiterleitung...',
|
||||
googleSignInSuccess: 'Erfolgreich mit Google angemeldet. Weiterleitung...',
|
||||
};
|
||||
// Get translations based on current locale
|
||||
const translations = $derived(getLoginTranslations($locale || 'de'));
|
||||
|
||||
async function handleSignIn(email: string, password: string) {
|
||||
return authStore.signIn(email, password);
|
||||
|
|
@ -41,7 +22,7 @@
|
|||
</script>
|
||||
|
||||
<svelte:head>
|
||||
<title>Anmelden | ManaChat</title>
|
||||
<title>{translations.title} | ManaChat</title>
|
||||
</svelte:head>
|
||||
|
||||
<LoginPage
|
||||
|
|
@ -59,6 +40,9 @@
|
|||
darkBackground="#0c1929"
|
||||
{translations}
|
||||
>
|
||||
{#snippet headerControls()}
|
||||
<LanguageSelector />
|
||||
{/snippet}
|
||||
{#snippet appSlider()}
|
||||
<AppSlider />
|
||||
{/snippet}
|
||||
|
|
|
|||
|
|
@ -1,33 +1,16 @@
|
|||
<script lang="ts">
|
||||
import { goto } from '$app/navigation';
|
||||
import { locale } from 'svelte-i18n';
|
||||
import { RegisterPage } from '@manacore/shared-auth-ui';
|
||||
import { getRegisterTranslations } from '@manacore/shared-i18n';
|
||||
import { ChatLogo } from '@manacore/shared-branding';
|
||||
import { authStore } from '$lib/stores/auth.svelte';
|
||||
import AppSlider from '$lib/components/AppSlider.svelte';
|
||||
import LanguageSelector from '$lib/components/LanguageSelector.svelte';
|
||||
import '$lib/i18n';
|
||||
|
||||
// German translations
|
||||
const translations = {
|
||||
title: 'Konto erstellen',
|
||||
emailPlaceholder: 'E-Mail',
|
||||
passwordPlaceholder: 'Passwort',
|
||||
confirmPasswordPlaceholder: 'Passwort bestätigen',
|
||||
passwordRequirements:
|
||||
'Passwort muss mindestens 8 Zeichen mit Kleinbuchstaben, Großbuchstaben, Zahl und Sonderzeichen enthalten.',
|
||||
createAccountButton: 'Konto erstellen',
|
||||
creatingAccount: 'Wird erstellt...',
|
||||
backToLogin: 'Zurück zur Anmeldung',
|
||||
showPassword: 'Passwort anzeigen',
|
||||
hidePassword: 'Passwort verbergen',
|
||||
emailRequired: 'E-Mail ist erforderlich',
|
||||
passwordRequired: 'Passwort ist erforderlich',
|
||||
confirmPasswordRequired: 'Bitte bestätige dein Passwort',
|
||||
passwordsDoNotMatch: 'Passwörter stimmen nicht überein',
|
||||
passwordTooShort: 'Passwort muss mindestens 8 Zeichen lang sein',
|
||||
passwordStrengthError:
|
||||
'Passwort muss Kleinbuchstaben, Großbuchstaben, Zahl und Sonderzeichen enthalten',
|
||||
registrationFailed: 'Registrierung fehlgeschlagen',
|
||||
accountCreated: 'Konto erstellt! Bitte überprüfe deine E-Mails zur Bestätigung.',
|
||||
};
|
||||
// Get translations based on current locale
|
||||
const translations = $derived(getRegisterTranslations($locale || 'de'));
|
||||
|
||||
async function handleSignUp(email: string, password: string) {
|
||||
return authStore.signUp(email, password);
|
||||
|
|
@ -35,7 +18,7 @@
|
|||
</script>
|
||||
|
||||
<svelte:head>
|
||||
<title>Registrieren | ManaChat</title>
|
||||
<title>{translations.title} | ManaChat</title>
|
||||
</svelte:head>
|
||||
|
||||
<RegisterPage
|
||||
|
|
@ -50,6 +33,9 @@
|
|||
darkBackground="#0c1929"
|
||||
{translations}
|
||||
>
|
||||
{#snippet headerControls()}
|
||||
<LanguageSelector />
|
||||
{/snippet}
|
||||
{#snippet appSlider()}
|
||||
<AppSlider />
|
||||
{/snippet}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue