mirror of
https://github.com/Memo-2023/mana-monorepo.git
synced 2026-05-14 20:01:09 +02:00
feat(i18n): wire user settings locale, add nav translations
- Sync svelte-i18n locale from userSettings.locale (backend) via $effect - Persist language changes to backend via userSettings.updateGlobal - Add nav/ locale module with navigation labels in 5 languages - Replace 6 hardcoded German strings in app layout with $_() calls: "Alle Themes", "Menü", "Geschenke", "Profil", "Einstellungen", etc. - Make baseNavItems reactive ($derived) so labels update on language change Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
e152098829
commit
bfe11d91ed
7 changed files with 114 additions and 20 deletions
|
|
@ -15,20 +15,21 @@ const defaultLocale = 'de';
|
|||
|
||||
function registerLocale(lang: SupportedLocale) {
|
||||
register(lang, async () => {
|
||||
const [common, dashboard, credits, profile, subscription, todo, app_slider] = await Promise.all(
|
||||
[
|
||||
const [common, nav, dashboard, credits, profile, subscription, todo, app_slider] =
|
||||
await Promise.all([
|
||||
import(`./locales/common/${lang}.json`),
|
||||
import(`./locales/nav/${lang}.json`),
|
||||
import(`./locales/dashboard/${lang}.json`),
|
||||
import(`./locales/credits/${lang}.json`),
|
||||
import(`./locales/profile/${lang}.json`),
|
||||
import(`./locales/subscription/${lang}.json`),
|
||||
import(`./locales/todo/${lang}.json`),
|
||||
import(`./locales/app_slider/${lang}.json`),
|
||||
]
|
||||
);
|
||||
]);
|
||||
|
||||
return {
|
||||
common: common.default,
|
||||
nav: nav.default,
|
||||
dashboard: dashboard.default,
|
||||
credits: credits.default,
|
||||
profile: profile.default,
|
||||
|
|
|
|||
16
apps/manacore/apps/web/src/lib/i18n/locales/nav/de.json
Normal file
16
apps/manacore/apps/web/src/lib/i18n/locales/nav/de.json
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
{
|
||||
"home": "Home",
|
||||
"dashboard": "Dashboard",
|
||||
"spiral": "Spiral",
|
||||
"observatory": "Observatory",
|
||||
"credits": "Credits",
|
||||
"gifts": "Geschenke",
|
||||
"api_keys": "API Keys",
|
||||
"profile": "Profil",
|
||||
"settings": "Einstellungen",
|
||||
"tags": "Tags",
|
||||
"admin": "Admin",
|
||||
"all_themes": "Alle Themes",
|
||||
"menu": "Menü",
|
||||
"sign_out": "Abmelden"
|
||||
}
|
||||
16
apps/manacore/apps/web/src/lib/i18n/locales/nav/en.json
Normal file
16
apps/manacore/apps/web/src/lib/i18n/locales/nav/en.json
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
{
|
||||
"home": "Home",
|
||||
"dashboard": "Dashboard",
|
||||
"spiral": "Spiral",
|
||||
"observatory": "Observatory",
|
||||
"credits": "Credits",
|
||||
"gifts": "Gifts",
|
||||
"api_keys": "API Keys",
|
||||
"profile": "Profile",
|
||||
"settings": "Settings",
|
||||
"tags": "Tags",
|
||||
"admin": "Admin",
|
||||
"all_themes": "All Themes",
|
||||
"menu": "Menu",
|
||||
"sign_out": "Sign out"
|
||||
}
|
||||
16
apps/manacore/apps/web/src/lib/i18n/locales/nav/es.json
Normal file
16
apps/manacore/apps/web/src/lib/i18n/locales/nav/es.json
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
{
|
||||
"home": "Inicio",
|
||||
"dashboard": "Panel",
|
||||
"spiral": "Spiral",
|
||||
"observatory": "Observatorio",
|
||||
"credits": "Créditos",
|
||||
"gifts": "Regalos",
|
||||
"api_keys": "API Keys",
|
||||
"profile": "Perfil",
|
||||
"settings": "Ajustes",
|
||||
"tags": "Tags",
|
||||
"admin": "Admin",
|
||||
"all_themes": "Todos los temas",
|
||||
"menu": "Menú",
|
||||
"sign_out": "Cerrar sesión"
|
||||
}
|
||||
16
apps/manacore/apps/web/src/lib/i18n/locales/nav/fr.json
Normal file
16
apps/manacore/apps/web/src/lib/i18n/locales/nav/fr.json
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
{
|
||||
"home": "Accueil",
|
||||
"dashboard": "Tableau de bord",
|
||||
"spiral": "Spiral",
|
||||
"observatory": "Observatoire",
|
||||
"credits": "Crédits",
|
||||
"gifts": "Cadeaux",
|
||||
"api_keys": "Clés API",
|
||||
"profile": "Profil",
|
||||
"settings": "Paramètres",
|
||||
"tags": "Tags",
|
||||
"admin": "Admin",
|
||||
"all_themes": "Tous les thèmes",
|
||||
"menu": "Menu",
|
||||
"sign_out": "Déconnexion"
|
||||
}
|
||||
16
apps/manacore/apps/web/src/lib/i18n/locales/nav/it.json
Normal file
16
apps/manacore/apps/web/src/lib/i18n/locales/nav/it.json
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
{
|
||||
"home": "Home",
|
||||
"dashboard": "Dashboard",
|
||||
"spiral": "Spiral",
|
||||
"observatory": "Osservatorio",
|
||||
"credits": "Crediti",
|
||||
"gifts": "Regali",
|
||||
"api_keys": "Chiavi API",
|
||||
"profile": "Profilo",
|
||||
"settings": "Impostazioni",
|
||||
"tags": "Tag",
|
||||
"admin": "Admin",
|
||||
"all_themes": "Tutti i temi",
|
||||
"menu": "Menu",
|
||||
"sign_out": "Esci"
|
||||
}
|
||||
|
|
@ -5,7 +5,7 @@
|
|||
import { onDestroy, setContext } from 'svelte';
|
||||
import KeyboardShortcutsModal from '$lib/components/KeyboardShortcutsModal.svelte';
|
||||
import SessionWarning from '$lib/components/SessionWarning.svelte';
|
||||
import { locale } from 'svelte-i18n';
|
||||
import { locale, _ } from 'svelte-i18n';
|
||||
import {
|
||||
PillNavigation,
|
||||
TagStrip,
|
||||
|
|
@ -83,7 +83,7 @@
|
|||
})),
|
||||
{
|
||||
id: 'all-themes',
|
||||
label: 'Alle Themes',
|
||||
label: $_('nav.all_themes'),
|
||||
icon: 'palette',
|
||||
onClick: () => goto('/themes'),
|
||||
active: false,
|
||||
|
|
@ -95,15 +95,28 @@
|
|||
let currentLocale = $derived($locale || 'de');
|
||||
function handleLocaleChange(newLocale: string) {
|
||||
setLocale(newLocale as any);
|
||||
userSettings.updateGlobal({ locale: newLocale });
|
||||
AppEvents.languageChanged(newLocale);
|
||||
}
|
||||
|
||||
// Sync locale from user settings (backend) after login
|
||||
$effect(() => {
|
||||
if (userSettings.loaded && userSettings.locale) {
|
||||
const settingsLocale = userSettings.locale;
|
||||
if (supportedLocales.includes(settingsLocale as any) && settingsLocale !== $locale) {
|
||||
setLocale(settingsLocale as any);
|
||||
}
|
||||
}
|
||||
});
|
||||
let languageItems = $derived(
|
||||
getLanguageDropdownItems(supportedLocales, currentLocale, handleLocaleChange)
|
||||
);
|
||||
let currentLanguageLabel = $derived(getCurrentLanguageLabel(currentLocale));
|
||||
|
||||
// ── User / Guest awareness ──────────────────────────────
|
||||
let userEmail = $derived(authStore.isAuthenticated ? authStore.user?.email || 'Menü' : '');
|
||||
let userEmail = $derived(
|
||||
authStore.isAuthenticated ? authStore.user?.email || $_('nav.menu') : ''
|
||||
);
|
||||
|
||||
// ── Tags ────────────────────────────────────────────────
|
||||
const allTags = useAllTags();
|
||||
|
|
@ -124,30 +137,30 @@
|
|||
});
|
||||
|
||||
// ── Navigation ──────────────────────────────────────────
|
||||
const baseNavItems: PillNavItem[] = [
|
||||
{ href: '/home', label: 'Home', icon: 'home' },
|
||||
{ href: '/dashboard', label: 'Dashboard', icon: 'grid' },
|
||||
{ href: '/spiral', label: 'Spiral', icon: 'spiral' },
|
||||
{ href: '/observatory', label: 'Observatory', icon: 'eye' },
|
||||
{ href: '/credits', label: 'Credits', icon: 'creditCard' },
|
||||
{ href: '/gifts', label: 'Geschenke', icon: 'gift' },
|
||||
{ href: '/api-keys', label: 'API Keys', icon: 'key' },
|
||||
{ href: '/profile', label: 'Profil', icon: 'user' },
|
||||
{ href: '/settings', label: 'Settings', icon: 'settings' },
|
||||
let baseNavItems = $derived<PillNavItem[]>([
|
||||
{ href: '/home', label: $_('nav.home'), icon: 'home' },
|
||||
{ href: '/dashboard', label: $_('nav.dashboard'), icon: 'grid' },
|
||||
{ href: '/spiral', label: $_('nav.spiral'), icon: 'spiral' },
|
||||
{ href: '/observatory', label: $_('nav.observatory'), icon: 'eye' },
|
||||
{ href: '/credits', label: $_('nav.credits'), icon: 'creditCard' },
|
||||
{ href: '/gifts', label: $_('nav.gifts'), icon: 'gift' },
|
||||
{ href: '/api-keys', label: $_('nav.api_keys'), icon: 'key' },
|
||||
{ href: '/profile', label: $_('nav.profile'), icon: 'user' },
|
||||
{ href: '/settings', label: $_('nav.settings'), icon: 'settings' },
|
||||
{
|
||||
href: '/',
|
||||
label: 'Tags',
|
||||
label: $_('nav.tags'),
|
||||
icon: 'tag',
|
||||
onClick: handleTagStripToggle,
|
||||
active: isTagStripVisible,
|
||||
},
|
||||
];
|
||||
]);
|
||||
|
||||
let isAdmin = $derived(authStore.user?.role === 'admin');
|
||||
let navItems = $derived<PillNavItem[]>(
|
||||
isAdmin ? [...baseNavItems, { href: '/admin', label: 'Admin', icon: 'shield' }] : baseNavItems
|
||||
);
|
||||
const navRoutes = navItems.map((item) => item.href);
|
||||
let navRoutes = $derived(navItems.map((item) => item.href));
|
||||
|
||||
function handleKeydown(event: KeyboardEvent) {
|
||||
const target = event.target as HTMLElement;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue