fix(i18n): add missing menu translations and fix admin language resolution

Two issues caused the admin sidebar to show a mix of French and English:

1. Only 3 of 14 modules had "menu" translations in their locale files.
   When a key was missing, _translate_label() fell back to English Title
   Case from the key name — mixing with French from modules that had
   translations. Added menu sections to all 4 languages (en, fr, de, lb)
   across 13 modules.

2. The language middleware hardcoded admin to "en" ignoring user preference,
   while the menu API fell back to DEFAULT_LANGUAGE ("fr") when
   preferred_language was NULL. Fixed middleware to respect user's
   preferred_language and menu API to use middleware-resolved language
   as fallback.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-02-07 23:37:13 +01:00
parent faf7047979
commit dad02695f6
54 changed files with 3924 additions and 3549 deletions

View File

@@ -1,71 +1,80 @@
{
"dashboard": {
"title": "Dashboard",
"welcome": "Willkommen zurück",
"overview": "Übersicht",
"quick_stats": "Schnellstatistiken",
"recent_activity": "Letzte Aktivitäten",
"total_products": "Produkte gesamt",
"total_orders": "Bestellungen gesamt",
"total_customers": "Kunden gesamt",
"total_revenue": "Gesamtumsatz",
"active_products": "Aktive Produkte",
"pending_orders": "Ausstehende Bestellungen",
"new_customers": "Neue Kunden",
"today": "Heute",
"this_week": "Diese Woche",
"this_month": "Dieser Monat",
"this_year": "Dieses Jahr",
"error_loading": "Fehler beim Laden des Dashboards",
"no_data": "Keine Daten verfügbar"
},
"settings": {
"title": "Einstellungen",
"general": "Allgemein",
"store": "Shop",
"store_name": "Shop-Name",
"store_description": "Shop-Beschreibung",
"contact_email": "Kontakt-E-Mail",
"contact_phone": "Kontakttelefon",
"business_address": "Geschäftsadresse",
"tax_number": "Steuernummer",
"currency": "Währung",
"timezone": "Zeitzone",
"language": "Sprache",
"language_settings": "Spracheinstellungen",
"default_language": "Standardsprache",
"dashboard_language": "Dashboard-Sprache",
"storefront_language": "Shop-Sprache",
"enabled_languages": "Aktivierte Sprachen",
"notifications": "Benachrichtigungen",
"email_notifications": "E-Mail-Benachrichtigungen",
"integrations": "Integrationen",
"api_keys": "API-Schlüssel",
"webhooks": "Webhooks",
"save_settings": "Einstellungen speichern",
"settings_saved": "Einstellungen erfolgreich gespeichert"
},
"profile": {
"title": "Profil",
"my_profile": "Mein Profil",
"edit_profile": "Profil bearbeiten",
"personal_info": "Persönliche Informationen",
"first_name": "Vorname",
"last_name": "Nachname",
"email": "E-Mail",
"phone": "Telefon",
"avatar": "Profilbild",
"change_avatar": "Profilbild ändern",
"security": "Sicherheit",
"two_factor": "Zwei-Faktor-Authentifizierung",
"sessions": "Aktive Sitzungen",
"preferences": "Präferenzen",
"language_preference": "Sprachpräferenz",
"save_profile": "Profil speichern",
"profile_updated": "Profil erfolgreich aktualisiert"
},
"messages": {
"failed_to_load_dashboard_data": "Failed to load dashboard data",
"dashboard_refreshed": "Dashboard refreshed"
}
"dashboard": {
"title": "Dashboard",
"welcome": "Willkommen zurück",
"overview": "Übersicht",
"quick_stats": "Schnellstatistiken",
"recent_activity": "Letzte Aktivitäten",
"total_products": "Produkte gesamt",
"total_orders": "Bestellungen gesamt",
"total_customers": "Kunden gesamt",
"total_revenue": "Gesamtumsatz",
"active_products": "Aktive Produkte",
"pending_orders": "Ausstehende Bestellungen",
"new_customers": "Neue Kunden",
"today": "Heute",
"this_week": "Diese Woche",
"this_month": "Dieser Monat",
"this_year": "Dieses Jahr",
"error_loading": "Fehler beim Laden des Dashboards",
"no_data": "Keine Daten verfügbar"
},
"settings": {
"title": "Einstellungen",
"general": "Allgemein",
"store": "Shop",
"store_name": "Shop-Name",
"store_description": "Shop-Beschreibung",
"contact_email": "Kontakt-E-Mail",
"contact_phone": "Kontakttelefon",
"business_address": "Geschäftsadresse",
"tax_number": "Steuernummer",
"currency": "Währung",
"timezone": "Zeitzone",
"language": "Sprache",
"language_settings": "Spracheinstellungen",
"default_language": "Standardsprache",
"dashboard_language": "Dashboard-Sprache",
"storefront_language": "Shop-Sprache",
"enabled_languages": "Aktivierte Sprachen",
"notifications": "Benachrichtigungen",
"email_notifications": "E-Mail-Benachrichtigungen",
"integrations": "Integrationen",
"api_keys": "API-Schlüssel",
"webhooks": "Webhooks",
"save_settings": "Einstellungen speichern",
"settings_saved": "Einstellungen erfolgreich gespeichert"
},
"profile": {
"title": "Profil",
"my_profile": "Mein Profil",
"edit_profile": "Profil bearbeiten",
"personal_info": "Persönliche Informationen",
"first_name": "Vorname",
"last_name": "Nachname",
"email": "E-Mail",
"phone": "Telefon",
"avatar": "Profilbild",
"change_avatar": "Profilbild ändern",
"security": "Sicherheit",
"two_factor": "Zwei-Faktor-Authentifizierung",
"sessions": "Aktive Sitzungen",
"preferences": "Präferenzen",
"language_preference": "Sprachpräferenz",
"save_profile": "Profil speichern",
"profile_updated": "Profil erfolgreich aktualisiert"
},
"messages": {
"failed_to_load_dashboard_data": "Failed to load dashboard data",
"dashboard_refreshed": "Dashboard refreshed"
},
"menu": {
"dashboard": "Dashboard",
"platform_settings": "Plattform-Einstellungen",
"general": "Allgemein",
"my_menu": "Mein Menü",
"account_settings": "Kontoeinstellungen",
"profile": "Profil",
"settings": "Einstellungen"
}
}

View File

@@ -1,79 +1,88 @@
{
"dashboard": {
"title": "Dashboard",
"welcome": "Welcome back",
"overview": "Overview",
"quick_stats": "Quick Stats",
"recent_activity": "Recent Activity",
"total_products": "Total Products",
"total_orders": "Total Orders",
"total_customers": "Total Customers",
"total_revenue": "Total Revenue",
"active_products": "Active Products",
"pending_orders": "Pending Orders",
"new_customers": "New Customers",
"today": "Today",
"this_week": "This Week",
"this_month": "This Month",
"this_year": "This Year",
"error_loading": "Error loading dashboard",
"no_data": "No data available"
},
"settings": {
"title": "Settings",
"general": "General",
"store": "Store",
"store_name": "Store Name",
"store_description": "Store Description",
"contact_email": "Contact Email",
"contact_phone": "Contact Phone",
"business_address": "Business Address",
"tax_number": "Tax Number",
"currency": "Currency",
"timezone": "Timezone",
"language": "Language",
"language_settings": "Language Settings",
"default_language": "Default Language",
"dashboard_language": "Dashboard Language",
"storefront_language": "Storefront Language",
"enabled_languages": "Enabled Languages",
"notifications": "Notifications",
"email_notifications": "Email Notifications",
"integrations": "Integrations",
"api_keys": "API Keys",
"webhooks": "Webhooks",
"save_settings": "Save Settings",
"settings_saved": "Settings saved successfully"
},
"profile": {
"title": "Profile",
"my_profile": "My Profile",
"edit_profile": "Edit Profile",
"personal_info": "Personal Information",
"first_name": "First Name",
"last_name": "Last Name",
"email": "Email",
"phone": "Phone",
"avatar": "Avatar",
"change_avatar": "Change Avatar",
"security": "Security",
"two_factor": "Two-Factor Authentication",
"sessions": "Active Sessions",
"preferences": "Preferences",
"language_preference": "Language Preference",
"save_profile": "Save Profile",
"profile_updated": "Profile updated successfully"
},
"messages": {
"failed_to_load_dashboard_data": "Failed to load dashboard data",
"dashboard_refreshed": "Dashboard refreshed",
"item_removed_from_cart": "Item removed from cart",
"cart_cleared": "Cart cleared"
},
"confirmations": {
"show_all_menu_items": "This will show all menu items. Continue?",
"hide_all_menu_items": "This will hide all menu items (except mandatory ones). You can then enable the ones you want. Continue?",
"reset_email_settings": "This will reset all email settings to use .env defaults. Continue?",
"cleanup_logs": "This will delete all logs older than {days} days. Continue?"
}
"dashboard": {
"title": "Dashboard",
"welcome": "Welcome back",
"overview": "Overview",
"quick_stats": "Quick Stats",
"recent_activity": "Recent Activity",
"total_products": "Total Products",
"total_orders": "Total Orders",
"total_customers": "Total Customers",
"total_revenue": "Total Revenue",
"active_products": "Active Products",
"pending_orders": "Pending Orders",
"new_customers": "New Customers",
"today": "Today",
"this_week": "This Week",
"this_month": "This Month",
"this_year": "This Year",
"error_loading": "Error loading dashboard",
"no_data": "No data available"
},
"settings": {
"title": "Settings",
"general": "General",
"store": "Store",
"store_name": "Store Name",
"store_description": "Store Description",
"contact_email": "Contact Email",
"contact_phone": "Contact Phone",
"business_address": "Business Address",
"tax_number": "Tax Number",
"currency": "Currency",
"timezone": "Timezone",
"language": "Language",
"language_settings": "Language Settings",
"default_language": "Default Language",
"dashboard_language": "Dashboard Language",
"storefront_language": "Storefront Language",
"enabled_languages": "Enabled Languages",
"notifications": "Notifications",
"email_notifications": "Email Notifications",
"integrations": "Integrations",
"api_keys": "API Keys",
"webhooks": "Webhooks",
"save_settings": "Save Settings",
"settings_saved": "Settings saved successfully"
},
"profile": {
"title": "Profile",
"my_profile": "My Profile",
"edit_profile": "Edit Profile",
"personal_info": "Personal Information",
"first_name": "First Name",
"last_name": "Last Name",
"email": "Email",
"phone": "Phone",
"avatar": "Avatar",
"change_avatar": "Change Avatar",
"security": "Security",
"two_factor": "Two-Factor Authentication",
"sessions": "Active Sessions",
"preferences": "Preferences",
"language_preference": "Language Preference",
"save_profile": "Save Profile",
"profile_updated": "Profile updated successfully"
},
"messages": {
"failed_to_load_dashboard_data": "Failed to load dashboard data",
"dashboard_refreshed": "Dashboard refreshed",
"item_removed_from_cart": "Item removed from cart",
"cart_cleared": "Cart cleared"
},
"confirmations": {
"show_all_menu_items": "This will show all menu items. Continue?",
"hide_all_menu_items": "This will hide all menu items (except mandatory ones). You can then enable the ones you want. Continue?",
"reset_email_settings": "This will reset all email settings to use .env defaults. Continue?",
"cleanup_logs": "This will delete all logs older than {days} days. Continue?"
},
"menu": {
"dashboard": "Dashboard",
"platform_settings": "Platform Settings",
"general": "General",
"my_menu": "My Menu",
"account_settings": "Account Settings",
"profile": "Profile",
"settings": "Settings"
}
}

View File

@@ -1,71 +1,80 @@
{
"dashboard": {
"title": "Tableau de bord",
"welcome": "Bienvenue",
"overview": "Vue d'ensemble",
"quick_stats": "Statistiques rapides",
"recent_activity": "Activité récente",
"total_products": "Total des produits",
"total_orders": "Total des commandes",
"total_customers": "Total des clients",
"total_revenue": "Chiffre d'affaires total",
"active_products": "Produits actifs",
"pending_orders": "Commandes en attente",
"new_customers": "Nouveaux clients",
"today": "Aujourd'hui",
"this_week": "Cette semaine",
"this_month": "Ce mois",
"this_year": "Cette année",
"error_loading": "Erreur lors du chargement du tableau de bord",
"no_data": "Aucune donnée disponible"
},
"settings": {
"title": "Paramètres",
"general": "Général",
"store": "Boutique",
"store_name": "Nom de la boutique",
"store_description": "Description de la boutique",
"contact_email": "E-mail de contact",
"contact_phone": "Téléphone de contact",
"business_address": "Adresse professionnelle",
"tax_number": "Numéro de TVA",
"currency": "Devise",
"timezone": "Fuseau horaire",
"language": "Langue",
"language_settings": "Paramètres de langue",
"default_language": "Langue par défaut",
"dashboard_language": "Langue du tableau de bord",
"storefront_language": "Langue de la boutique",
"enabled_languages": "Langues activées",
"notifications": "Notifications",
"email_notifications": "Notifications par e-mail",
"integrations": "Intégrations",
"api_keys": "Clés API",
"webhooks": "Webhooks",
"save_settings": "Enregistrer les paramètres",
"settings_saved": "Paramètres enregistrés avec succès"
},
"profile": {
"title": "Profil",
"my_profile": "Mon profil",
"edit_profile": "Modifier le profil",
"personal_info": "Informations personnelles",
"first_name": "Prénom",
"last_name": "Nom",
"email": "E-mail",
"phone": "Téléphone",
"avatar": "Avatar",
"change_avatar": "Changer l'avatar",
"security": "Sécurité",
"two_factor": "Authentification à deux facteurs",
"sessions": "Sessions actives",
"preferences": "Préférences",
"language_preference": "Préférence de langue",
"save_profile": "Enregistrer le profil",
"profile_updated": "Profil mis à jour avec succès"
},
"messages": {
"failed_to_load_dashboard_data": "Failed to load dashboard data",
"dashboard_refreshed": "Dashboard refreshed"
}
"dashboard": {
"title": "Tableau de bord",
"welcome": "Bienvenue",
"overview": "Vue d'ensemble",
"quick_stats": "Statistiques rapides",
"recent_activity": "Activité récente",
"total_products": "Total des produits",
"total_orders": "Total des commandes",
"total_customers": "Total des clients",
"total_revenue": "Chiffre d'affaires total",
"active_products": "Produits actifs",
"pending_orders": "Commandes en attente",
"new_customers": "Nouveaux clients",
"today": "Aujourd'hui",
"this_week": "Cette semaine",
"this_month": "Ce mois",
"this_year": "Cette année",
"error_loading": "Erreur lors du chargement du tableau de bord",
"no_data": "Aucune donnée disponible"
},
"settings": {
"title": "Paramètres",
"general": "Général",
"store": "Boutique",
"store_name": "Nom de la boutique",
"store_description": "Description de la boutique",
"contact_email": "E-mail de contact",
"contact_phone": "Téléphone de contact",
"business_address": "Adresse professionnelle",
"tax_number": "Numéro de TVA",
"currency": "Devise",
"timezone": "Fuseau horaire",
"language": "Langue",
"language_settings": "Paramètres de langue",
"default_language": "Langue par défaut",
"dashboard_language": "Langue du tableau de bord",
"storefront_language": "Langue de la boutique",
"enabled_languages": "Langues activées",
"notifications": "Notifications",
"email_notifications": "Notifications par e-mail",
"integrations": "Intégrations",
"api_keys": "Clés API",
"webhooks": "Webhooks",
"save_settings": "Enregistrer les paramètres",
"settings_saved": "Paramètres enregistrés avec succès"
},
"profile": {
"title": "Profil",
"my_profile": "Mon profil",
"edit_profile": "Modifier le profil",
"personal_info": "Informations personnelles",
"first_name": "Prénom",
"last_name": "Nom",
"email": "E-mail",
"phone": "Téléphone",
"avatar": "Avatar",
"change_avatar": "Changer l'avatar",
"security": "Sécurité",
"two_factor": "Authentification à deux facteurs",
"sessions": "Sessions actives",
"preferences": "Préférences",
"language_preference": "Préférence de langue",
"save_profile": "Enregistrer le profil",
"profile_updated": "Profil mis à jour avec succès"
},
"messages": {
"failed_to_load_dashboard_data": "Failed to load dashboard data",
"dashboard_refreshed": "Dashboard refreshed"
},
"menu": {
"dashboard": "Tableau de bord",
"platform_settings": "Paramètres de la plateforme",
"general": "Général",
"my_menu": "Mon menu",
"account_settings": "Paramètres du compte",
"profile": "Profil",
"settings": "Paramètres"
}
}

View File

@@ -1,71 +1,80 @@
{
"dashboard": {
"title": "Dashboard",
"welcome": "Wëllkomm zréck",
"overview": "Iwwersiicht",
"quick_stats": "Séier Statistiken",
"recent_activity": "Rezent Aktivitéit",
"total_products": "Produkter insgesamt",
"total_orders": "Bestellungen insgesamt",
"total_customers": "Clienten insgesamt",
"total_revenue": "Ëmsaz insgesamt",
"active_products": "Aktiv Produkter",
"pending_orders": "Aussteesend Bestellungen",
"new_customers": "Nei Clienten",
"today": "Haut",
"this_week": "Dës Woch",
"this_month": "Dëse Mount",
"this_year": "Dëst Joer",
"error_loading": "Feeler beim Lueden vum Dashboard",
"no_data": "Keng Donnéeën disponibel"
},
"settings": {
"title": "Astellungen",
"general": "Allgemeng",
"store": "Buttek",
"store_name": "Butteknumm",
"store_description": "Buttekbeschreiwung",
"contact_email": "Kontakt E-Mail",
"contact_phone": "Kontakt Telefon",
"business_address": "Geschäftsadress",
"tax_number": "Steiernummer",
"currency": "Wärung",
"timezone": "Zäitzon",
"language": "Sprooch",
"language_settings": "Sproochastellungen",
"default_language": "Standard Sprooch",
"dashboard_language": "Dashboard Sprooch",
"storefront_language": "Buttek Sprooch",
"enabled_languages": "Aktivéiert Sproochen",
"notifications": "Notifikatiounen",
"email_notifications": "E-Mail Notifikatiounen",
"integrations": "Integratiounen",
"api_keys": "API Schlësselen",
"webhooks": "Webhooks",
"save_settings": "Astellunge späicheren",
"settings_saved": "Astellungen erfollegräich gespäichert"
},
"profile": {
"title": "Profil",
"my_profile": "Mäi Profil",
"edit_profile": "Profil änneren",
"personal_info": "Perséinlech Informatiounen",
"first_name": "Virnumm",
"last_name": "Nonumm",
"email": "E-Mail",
"phone": "Telefon",
"avatar": "Avatar",
"change_avatar": "Avatar änneren",
"security": "Sécherheet",
"two_factor": "Zwee-Faktor Authentifikatioun",
"sessions": "Aktiv Sessiounen",
"preferences": "Astellungen",
"language_preference": "Sproochpräferenz",
"save_profile": "Profil späicheren",
"profile_updated": "Profil erfollegräich aktualiséiert"
},
"messages": {
"failed_to_load_dashboard_data": "Failed to load dashboard data",
"dashboard_refreshed": "Dashboard refreshed"
}
"dashboard": {
"title": "Dashboard",
"welcome": "Wëllkomm zréck",
"overview": "Iwwersiicht",
"quick_stats": "Séier Statistiken",
"recent_activity": "Rezent Aktivitéit",
"total_products": "Produkter insgesamt",
"total_orders": "Bestellungen insgesamt",
"total_customers": "Clienten insgesamt",
"total_revenue": "Ëmsaz insgesamt",
"active_products": "Aktiv Produkter",
"pending_orders": "Aussteesend Bestellungen",
"new_customers": "Nei Clienten",
"today": "Haut",
"this_week": "Dës Woch",
"this_month": "Dëse Mount",
"this_year": "Dëst Joer",
"error_loading": "Feeler beim Lueden vum Dashboard",
"no_data": "Keng Donnéeën disponibel"
},
"settings": {
"title": "Astellungen",
"general": "Allgemeng",
"store": "Buttek",
"store_name": "Butteknumm",
"store_description": "Buttekbeschreiwung",
"contact_email": "Kontakt E-Mail",
"contact_phone": "Kontakt Telefon",
"business_address": "Geschäftsadress",
"tax_number": "Steiernummer",
"currency": "Wärung",
"timezone": "Zäitzon",
"language": "Sprooch",
"language_settings": "Sproochastellungen",
"default_language": "Standard Sprooch",
"dashboard_language": "Dashboard Sprooch",
"storefront_language": "Buttek Sprooch",
"enabled_languages": "Aktivéiert Sproochen",
"notifications": "Notifikatiounen",
"email_notifications": "E-Mail Notifikatiounen",
"integrations": "Integratiounen",
"api_keys": "API Schlësselen",
"webhooks": "Webhooks",
"save_settings": "Astellunge späicheren",
"settings_saved": "Astellungen erfollegräich gespäichert"
},
"profile": {
"title": "Profil",
"my_profile": "Mäi Profil",
"edit_profile": "Profil änneren",
"personal_info": "Perséinlech Informatiounen",
"first_name": "Virnumm",
"last_name": "Nonumm",
"email": "E-Mail",
"phone": "Telefon",
"avatar": "Avatar",
"change_avatar": "Avatar änneren",
"security": "Sécherheet",
"two_factor": "Zwee-Faktor Authentifikatioun",
"sessions": "Aktiv Sessiounen",
"preferences": "Astellungen",
"language_preference": "Sproochpräferenz",
"save_profile": "Profil späicheren",
"profile_updated": "Profil erfollegräich aktualiséiert"
},
"messages": {
"failed_to_load_dashboard_data": "Failed to load dashboard data",
"dashboard_refreshed": "Dashboard refreshed"
},
"menu": {
"dashboard": "Dashboard",
"platform_settings": "Plattform-Astellungen",
"general": "Allgemeng",
"my_menu": "Mäi Menü",
"account_settings": "Kont-Astellungen",
"profile": "Profil",
"settings": "Astellungen"
}
}

View File

@@ -18,7 +18,7 @@ Menu rendering endpoints require authenticated admin/store access.
import logging
from typing import Any
from fastapi import APIRouter, Depends, Path, Query
from fastapi import APIRouter, Depends, Path, Query, Request
from pydantic import BaseModel, Field
from sqlalchemy.orm import Session
@@ -180,6 +180,7 @@ def _build_menu_config_response(
@router.get("/platforms/{platform_id}", response_model=MenuConfigResponse)
async def get_platform_menu_config(
request: Request,
platform_id: int = Path(..., description="Platform ID"),
frontend_type: FrontendType = Query(
FrontendType.ADMIN, description="Frontend type (admin or store)"
@@ -203,8 +204,8 @@ async def get_platform_menu_config(
f"for platform {platform.code} ({frontend_type.value})"
)
# Use user's preferred language, falling back to default
language = current_user.preferred_language or DEFAULT_LANGUAGE
# Use user's preferred language, falling back to middleware-resolved language
language = current_user.preferred_language or getattr(request.state, "language", "en")
return _build_menu_config_response(
items, frontend_type, language=language, platform_id=platform_id
@@ -317,6 +318,7 @@ async def reset_platform_menu_config(
@router.get("/user", response_model=MenuConfigResponse)
async def get_user_menu_config(
request: Request,
db: Session = Depends(get_db),
current_user: UserContext = Depends(get_current_super_admin),
):
@@ -331,8 +333,8 @@ async def get_user_menu_config(
f"[MENU_CONFIG] Super admin {current_user.email} fetched their personal menu config"
)
# Use user's preferred language, falling back to default
language = current_user.preferred_language or DEFAULT_LANGUAGE
# Use user's preferred language, falling back to middleware-resolved language
language = current_user.preferred_language or getattr(request.state, "language", "en")
return _build_menu_config_response(
items, FrontendType.ADMIN, language=language, user_id=current_user.id
@@ -442,6 +444,7 @@ async def show_all_platform_menu_config(
@router.get("/render/admin", response_model=RenderedMenuResponse)
async def get_rendered_admin_menu(
request: Request,
db: Session = Depends(get_db),
current_user: UserContext = Depends(get_current_admin_from_cookie_or_header),
):
@@ -482,8 +485,8 @@ async def get_rendered_admin_menu(
is_super_admin=False,
)
# Use user's preferred language, falling back to default
language = current_user.preferred_language or DEFAULT_LANGUAGE
# Use user's preferred language, falling back to middleware-resolved language
language = current_user.preferred_language or getattr(request.state, "language", "en")
# Translate section and item labels
sections = []