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

@@ -13,5 +13,8 @@
"data_since": "Daten seit", "data_since": "Daten seit",
"loading": "Analysen werden geladen...", "loading": "Analysen werden geladen...",
"error_loading": "Analysedaten konnten nicht geladen werden" "error_loading": "Analysedaten konnten nicht geladen werden"
},
"menu": {
"analytics": "Analytik"
} }
} }

View File

@@ -13,5 +13,8 @@
"data_since": "Data since", "data_since": "Data since",
"loading": "Loading analytics...", "loading": "Loading analytics...",
"error_loading": "Failed to load analytics data" "error_loading": "Failed to load analytics data"
},
"menu": {
"analytics": "Analytics"
} }
} }

View File

@@ -13,5 +13,8 @@
"data_since": "Données depuis", "data_since": "Données depuis",
"loading": "Chargement des analyses...", "loading": "Chargement des analyses...",
"error_loading": "Impossible de charger les données analytiques" "error_loading": "Impossible de charger les données analytiques"
},
"menu": {
"analytics": "Analytique"
} }
} }

View File

@@ -13,5 +13,8 @@
"data_since": "Daten zënter", "data_since": "Daten zënter",
"loading": "Analysen lueden...", "loading": "Analysen lueden...",
"error_loading": "Feeler beim Lueden vun den Analysedaten" "error_loading": "Feeler beim Lueden vun den Analysedaten"
},
"menu": {
"analytics": "Analytik"
} }
} }

View File

@@ -123,5 +123,15 @@
"name": "Nutzungsverfolgung", "name": "Nutzungsverfolgung",
"description": "Funktionsnutzung gegen Stufenlimits verfolgen" "description": "Funktionsnutzung gegen Stufenlimits verfolgen"
} }
},
"menu": {
"billing_subscriptions": "Abrechnung & Abonnements",
"subscription_tiers": "Abo-Stufen",
"store_subscriptions": "Shop-Abonnements",
"billing_history": "Abrechnungsverlauf",
"sales_orders": "Verkäufe & Bestellungen",
"invoices": "Rechnungen",
"account_settings": "Kontoeinstellungen",
"billing": "Abrechnung"
} }
} }

View File

@@ -123,5 +123,15 @@
"name": "Usage Tracking", "name": "Usage Tracking",
"description": "Track feature usage against tier limits" "description": "Track feature usage against tier limits"
} }
},
"menu": {
"billing_subscriptions": "Billing & Subscriptions",
"subscription_tiers": "Subscription Tiers",
"store_subscriptions": "Store Subscriptions",
"billing_history": "Billing History",
"sales_orders": "Sales & Orders",
"invoices": "Invoices",
"account_settings": "Account Settings",
"billing": "Billing"
} }
} }

View File

@@ -123,5 +123,15 @@
"name": "Suivi d'utilisation", "name": "Suivi d'utilisation",
"description": "Suivre l'utilisation des fonctionnalités par rapport aux limites du niveau" "description": "Suivre l'utilisation des fonctionnalités par rapport aux limites du niveau"
} }
},
"menu": {
"billing_subscriptions": "Facturation et Abonnements",
"subscription_tiers": "Niveaux d'abonnement",
"store_subscriptions": "Abonnements des magasins",
"billing_history": "Historique de facturation",
"sales_orders": "Ventes et Commandes",
"invoices": "Factures",
"account_settings": "Paramètres du compte",
"billing": "Facturation"
} }
} }

View File

@@ -123,5 +123,15 @@
"name": "Notzungsverfolgung", "name": "Notzungsverfolgung",
"description": "Funktiounsnotzung géint Stuflimiten verfolgen" "description": "Funktiounsnotzung géint Stuflimiten verfolgen"
} }
},
"menu": {
"billing_subscriptions": "Ofrechnung & Abonnementer",
"subscription_tiers": "Abo-Stufen",
"store_subscriptions": "Buttek-Abonnementer",
"billing_history": "Ofrechnungsverlaf",
"sales_orders": "Verkaf & Bestellungen",
"invoices": "Rechnungen",
"account_settings": "Kont-Astellungen",
"billing": "Ofrechnung"
} }
} }

View File

@@ -71,5 +71,9 @@
"name": "Import/Export", "name": "Import/Export",
"description": "Massenimport und -export von Produkten" "description": "Massenimport und -export von Produkten"
} }
},
"menu": {
"products_inventory": "Produkte & Inventar",
"all_products": "Alle Produkte"
} }
} }

View File

@@ -89,5 +89,9 @@
"name": "Import/Export", "name": "Import/Export",
"description": "Bulk product import and export functionality" "description": "Bulk product import and export functionality"
} }
},
"menu": {
"products_inventory": "Products & Inventory",
"all_products": "All Products"
} }
} }

View File

@@ -71,5 +71,9 @@
"name": "Import/Export", "name": "Import/Export",
"description": "Import et export en masse de produits" "description": "Import et export en masse de produits"
} }
},
"menu": {
"products_inventory": "Produits et Inventaire",
"all_products": "Tous les produits"
} }
} }

View File

@@ -71,5 +71,9 @@
"name": "Import/Export", "name": "Import/Export",
"description": "Mass-Import an -Export vu Produkter" "description": "Mass-Import an -Export vu Produkter"
} }
},
"menu": {
"products_inventory": "Produkter & Inventar",
"all_products": "All Produkter"
} }
} }

View File

@@ -227,5 +227,12 @@
"name": "Seitenvorlagen", "name": "Seitenvorlagen",
"description": "Zugang zu Premium-Seitenvorlagen" "description": "Zugang zu Premium-Seitenvorlagen"
} }
},
"menu": {
"content_management": "Inhaltsverwaltung",
"shop_content": "Shop-Inhalte",
"content_pages": "Inhaltsseiten",
"store_themes": "Shop-Themes",
"media_library": "Mediathek"
} }
} }

View File

@@ -237,5 +237,12 @@
"name": "Page Templates", "name": "Page Templates",
"description": "Access to premium page templates" "description": "Access to premium page templates"
} }
},
"menu": {
"content_management": "Content Management",
"shop_content": "Shop Content",
"content_pages": "Content Pages",
"store_themes": "Store Themes",
"media_library": "Media Library"
} }
} }

View File

@@ -227,5 +227,12 @@
"name": "Modèles de pages", "name": "Modèles de pages",
"description": "Accès aux modèles de pages premium" "description": "Accès aux modèles de pages premium"
} }
},
"menu": {
"content_management": "Gestion du contenu",
"shop_content": "Contenu du magasin",
"content_pages": "Pages de contenu",
"store_themes": "Thèmes du magasin",
"media_library": "Médiathèque"
} }
} }

View File

@@ -227,5 +227,12 @@
"name": "Säitevirlagen", "name": "Säitevirlagen",
"description": "Zougang zu Premium-Säitevirlagen" "description": "Zougang zu Premium-Säitevirlagen"
} }
},
"menu": {
"content_management": "Inhaltsverwaltung",
"shop_content": "Buttek-Inhalter",
"content_pages": "Inhaltsäiten",
"store_themes": "Buttek-Themen",
"media_library": "Mediathéik"
} }
} }

View File

@@ -67,5 +67,14 @@
"messages": { "messages": {
"failed_to_load_dashboard_data": "Failed to load dashboard data", "failed_to_load_dashboard_data": "Failed to load dashboard data",
"dashboard_refreshed": "Dashboard refreshed" "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

@@ -75,5 +75,14 @@
"hide_all_menu_items": "This will hide all menu items (except mandatory ones). You can then enable the ones you want. 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?", "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?" "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

@@ -67,5 +67,14 @@
"messages": { "messages": {
"failed_to_load_dashboard_data": "Failed to load dashboard data", "failed_to_load_dashboard_data": "Failed to load dashboard data",
"dashboard_refreshed": "Dashboard refreshed" "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

@@ -67,5 +67,14 @@
"messages": { "messages": {
"failed_to_load_dashboard_data": "Failed to load dashboard data", "failed_to_load_dashboard_data": "Failed to load dashboard data",
"dashboard_refreshed": "Dashboard refreshed" "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 import logging
from typing import Any 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 pydantic import BaseModel, Field
from sqlalchemy.orm import Session from sqlalchemy.orm import Session
@@ -180,6 +180,7 @@ def _build_menu_config_response(
@router.get("/platforms/{platform_id}", response_model=MenuConfigResponse) @router.get("/platforms/{platform_id}", response_model=MenuConfigResponse)
async def get_platform_menu_config( async def get_platform_menu_config(
request: Request,
platform_id: int = Path(..., description="Platform ID"), platform_id: int = Path(..., description="Platform ID"),
frontend_type: FrontendType = Query( frontend_type: FrontendType = Query(
FrontendType.ADMIN, description="Frontend type (admin or store)" 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})" f"for platform {platform.code} ({frontend_type.value})"
) )
# Use user's preferred language, falling back to default # Use user's preferred language, falling back to middleware-resolved language
language = current_user.preferred_language or DEFAULT_LANGUAGE language = current_user.preferred_language or getattr(request.state, "language", "en")
return _build_menu_config_response( return _build_menu_config_response(
items, frontend_type, language=language, platform_id=platform_id 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) @router.get("/user", response_model=MenuConfigResponse)
async def get_user_menu_config( async def get_user_menu_config(
request: Request,
db: Session = Depends(get_db), db: Session = Depends(get_db),
current_user: UserContext = Depends(get_current_super_admin), 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" f"[MENU_CONFIG] Super admin {current_user.email} fetched their personal menu config"
) )
# Use user's preferred language, falling back to default # Use user's preferred language, falling back to middleware-resolved language
language = current_user.preferred_language or DEFAULT_LANGUAGE language = current_user.preferred_language or getattr(request.state, "language", "en")
return _build_menu_config_response( return _build_menu_config_response(
items, FrontendType.ADMIN, language=language, user_id=current_user.id 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) @router.get("/render/admin", response_model=RenderedMenuResponse)
async def get_rendered_admin_menu( async def get_rendered_admin_menu(
request: Request,
db: Session = Depends(get_db), db: Session = Depends(get_db),
current_user: UserContext = Depends(get_current_admin_from_cookie_or_header), 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, is_super_admin=False,
) )
# Use user's preferred language, falling back to default # Use user's preferred language, falling back to middleware-resolved language
language = current_user.preferred_language or DEFAULT_LANGUAGE language = current_user.preferred_language or getattr(request.state, "language", "en")
# Translate section and item labels # Translate section and item labels
sections = [] sections = []

View File

@@ -31,5 +31,11 @@
"name": "Kundennachrichten", "name": "Kundennachrichten",
"description": "Nachrichten an Kunden senden" "description": "Nachrichten an Kunden senden"
} }
},
"menu": {
"store_operations": "Shop-Betrieb",
"customers_section": "Kunden",
"customers": "Kunden",
"all_customers": "Alle Kunden"
} }
} }

View File

@@ -36,5 +36,11 @@
"name": "Customer Messaging", "name": "Customer Messaging",
"description": "Send messages to customers" "description": "Send messages to customers"
} }
},
"menu": {
"store_operations": "Store Operations",
"customers_section": "Customers",
"customers": "Customers",
"all_customers": "All Customers"
} }
} }

View File

@@ -31,5 +31,11 @@
"name": "Messagerie clients", "name": "Messagerie clients",
"description": "Envoyer des messages aux clients" "description": "Envoyer des messages aux clients"
} }
},
"menu": {
"store_operations": "Opérations du magasin",
"customers_section": "Clients",
"customers": "Clients",
"all_customers": "Tous les clients"
} }
} }

View File

@@ -31,5 +31,11 @@
"name": "Kundennoriichten", "name": "Kundennoriichten",
"description": "Noriichten u Clienten schécken" "description": "Noriichten u Clienten schécken"
} }
},
"menu": {
"store_operations": "Buttek-Operatiounen",
"customers_section": "Clienten",
"customers": "Clienten",
"all_customers": "All Clienten"
} }
} }

View File

@@ -8,5 +8,10 @@
"review_submitted_successfully": "Review submitted successfully!", "review_submitted_successfully": "Review submitted successfully!",
"thanks_for_your_feedback": "Thanks for your feedback!", "thanks_for_your_feedback": "Thanks for your feedback!",
"code_copied_to_clipboard": "Code copied to clipboard!" "code_copied_to_clipboard": "Code copied to clipboard!"
},
"menu": {
"developer_tools": "Entwicklerwerkzeuge",
"components": "Komponenten",
"icons": "Icons"
} }
} }

View File

@@ -8,5 +8,10 @@
"review_submitted_successfully": "Review submitted successfully!", "review_submitted_successfully": "Review submitted successfully!",
"thanks_for_your_feedback": "Thanks for your feedback!", "thanks_for_your_feedback": "Thanks for your feedback!",
"code_copied_to_clipboard": "Code copied to clipboard!" "code_copied_to_clipboard": "Code copied to clipboard!"
},
"menu": {
"developer_tools": "Developer Tools",
"components": "Components",
"icons": "Icons"
} }
} }

View File

@@ -8,5 +8,10 @@
"review_submitted_successfully": "Review submitted successfully!", "review_submitted_successfully": "Review submitted successfully!",
"thanks_for_your_feedback": "Thanks for your feedback!", "thanks_for_your_feedback": "Thanks for your feedback!",
"code_copied_to_clipboard": "Code copied to clipboard!" "code_copied_to_clipboard": "Code copied to clipboard!"
},
"menu": {
"developer_tools": "Outils de développement",
"components": "Composants",
"icons": "Icônes"
} }
} }

View File

@@ -8,5 +8,10 @@
"review_submitted_successfully": "Review submitted successfully!", "review_submitted_successfully": "Review submitted successfully!",
"thanks_for_your_feedback": "Thanks for your feedback!", "thanks_for_your_feedback": "Thanks for your feedback!",
"code_copied_to_clipboard": "Code copied to clipboard!" "code_copied_to_clipboard": "Code copied to clipboard!"
},
"menu": {
"developer_tools": "Entwécklerwerkzäicher",
"components": "Komponenten",
"icons": "Icons"
} }
} }

View File

@@ -36,5 +36,11 @@
"name": "Niedrigbestandswarnungen", "name": "Niedrigbestandswarnungen",
"description": "Automatische Benachrichtigungen bei niedrigem Lagerbestand" "description": "Automatische Benachrichtigungen bei niedrigem Lagerbestand"
} }
},
"menu": {
"store_operations": "Shop-Betrieb",
"products_inventory": "Produkte & Inventar",
"products": "Produkte",
"inventory": "Inventar"
} }
} }

View File

@@ -45,5 +45,11 @@
"name": "Low Stock Alerts", "name": "Low Stock Alerts",
"description": "Automatic notifications for low stock levels" "description": "Automatic notifications for low stock levels"
} }
},
"menu": {
"store_operations": "Store Operations",
"products_inventory": "Products & Inventory",
"products": "Products",
"inventory": "Inventory"
} }
} }

View File

@@ -36,5 +36,11 @@
"name": "Alertes stock bas", "name": "Alertes stock bas",
"description": "Notifications automatiques pour les niveaux de stock bas" "description": "Notifications automatiques pour les niveaux de stock bas"
} }
},
"menu": {
"store_operations": "Opérations du magasin",
"products_inventory": "Produits et Inventaire",
"products": "Produits",
"inventory": "Inventaire"
} }
} }

View File

@@ -36,5 +36,11 @@
"name": "Niddreg-Lagerbestandswarnungen", "name": "Niddreg-Lagerbestandswarnungen",
"description": "Automatesch Benoriichtegungen bei niddregem Lagerbestand" "description": "Automatesch Benoriichtegungen bei niddregem Lagerbestand"
} }
},
"menu": {
"store_operations": "Buttek-Operatiounen",
"products_inventory": "Produkter & Inventar",
"products": "Produkter",
"inventory": "Inventar"
} }
} }

View File

@@ -68,5 +68,14 @@
"pin_invalid": "Ungültiger PIN", "pin_invalid": "Ungültiger PIN",
"pin_locked": "PIN wegen zu vieler Fehlversuche gesperrt" "pin_locked": "PIN wegen zu vieler Fehlversuche gesperrt"
} }
},
"menu": {
"loyalty": "Treueprogramm",
"loyalty_programs": "Treueprogramme",
"programs": "Programme",
"analytics": "Analytik",
"dashboard": "Dashboard",
"customer_cards": "Kundenkarten",
"statistics": "Statistiken"
} }
} }

View File

@@ -68,5 +68,14 @@
"pin_invalid": "Invalid staff PIN", "pin_invalid": "Invalid staff PIN",
"pin_locked": "PIN locked due to too many failed attempts" "pin_locked": "PIN locked due to too many failed attempts"
} }
},
"menu": {
"loyalty": "Loyalty",
"loyalty_programs": "Loyalty Programs",
"programs": "Programs",
"analytics": "Analytics",
"dashboard": "Dashboard",
"customer_cards": "Customer Cards",
"statistics": "Statistics"
} }
} }

View File

@@ -68,5 +68,14 @@
"pin_invalid": "Code PIN invalide", "pin_invalid": "Code PIN invalide",
"pin_locked": "PIN bloqué suite à trop de tentatives échouées" "pin_locked": "PIN bloqué suite à trop de tentatives échouées"
} }
},
"menu": {
"loyalty": "Fidélité",
"loyalty_programs": "Programmes de fidélité",
"programs": "Programmes",
"analytics": "Analytique",
"dashboard": "Tableau de bord",
"customer_cards": "Cartes clients",
"statistics": "Statistiques"
} }
} }

View File

@@ -68,5 +68,14 @@
"pin_invalid": "Ongëlteg Personal-PIN", "pin_invalid": "Ongëlteg Personal-PIN",
"pin_locked": "PIN gespaart wéinst ze vill Fehlversich" "pin_locked": "PIN gespaart wéinst ze vill Fehlversich"
} }
},
"menu": {
"loyalty": "Treiprogramm",
"loyalty_programs": "Treiprogrammer",
"programs": "Programmer",
"analytics": "Analytik",
"dashboard": "Dashboard",
"customer_cards": "Clientekaarten",
"statistics": "Statistiken"
} }
} }

View File

@@ -50,5 +50,15 @@
"name": "Massennachrichten", "name": "Massennachrichten",
"description": "Massennachrichten an Kunden senden" "description": "Massennachrichten an Kunden senden"
} }
},
"menu": {
"platform_admin": "Plattform-Administration",
"platform_monitoring": "Plattform-Überwachung",
"platform_settings": "Plattform-Einstellungen",
"customers": "Kunden",
"account_settings": "Kontoeinstellungen",
"messages": "Nachrichten",
"notifications": "Benachrichtigungen",
"email_templates": "E-Mail-Vorlagen"
} }
} }

View File

@@ -59,5 +59,15 @@
"name": "Bulk Messaging", "name": "Bulk Messaging",
"description": "Send bulk messages to customers" "description": "Send bulk messages to customers"
} }
},
"menu": {
"platform_admin": "Platform Admin",
"platform_monitoring": "Platform Monitoring",
"platform_settings": "Platform Settings",
"customers": "Customers",
"account_settings": "Account Settings",
"messages": "Messages",
"notifications": "Notifications",
"email_templates": "Email Templates"
} }
} }

View File

@@ -50,5 +50,15 @@
"name": "Messagerie en masse", "name": "Messagerie en masse",
"description": "Envoyer des messages en masse aux clients" "description": "Envoyer des messages en masse aux clients"
} }
},
"menu": {
"platform_admin": "Administration de la plateforme",
"platform_monitoring": "Surveillance de la plateforme",
"platform_settings": "Paramètres de la plateforme",
"customers": "Clients",
"account_settings": "Paramètres du compte",
"messages": "Messages",
"notifications": "Notifications",
"email_templates": "Modèles d'e-mail"
} }
} }

View File

@@ -50,5 +50,15 @@
"name": "Massennoriichten", "name": "Massennoriichten",
"description": "Massennoriichten u Clienten schécken" "description": "Massennoriichten u Clienten schécken"
} }
},
"menu": {
"platform_admin": "Plattform-Administratioun",
"platform_monitoring": "Plattform-Iwwerwaachung",
"platform_settings": "Plattform-Astellungen",
"customers": "Clienten",
"account_settings": "Kont-Astellungen",
"messages": "Messagen",
"notifications": "Notifikatiounen",
"email_templates": "E-Mail-Virlagen"
} }
} }

View File

@@ -1 +1,12 @@
{} {
"menu": {
"platform_health": "Plattform-Gesundheit",
"platform_monitoring": "Plattform-Überwachung",
"capacity_monitor": "Kapazitätsmonitor",
"testing_hub": "Test-Center",
"code_quality": "Code-Qualität",
"import_jobs": "Import-Aufträge",
"background_tasks": "Hintergrundaufgaben",
"application_logs": "Anwendungsprotokolle"
}
}

View File

@@ -1 +1,12 @@
{} {
"menu": {
"platform_health": "Platform Health",
"platform_monitoring": "Platform Monitoring",
"capacity_monitor": "Capacity Monitor",
"testing_hub": "Testing Hub",
"code_quality": "Code Quality",
"import_jobs": "Import Jobs",
"background_tasks": "Background Tasks",
"application_logs": "Application Logs"
}
}

View File

@@ -1 +1,12 @@
{} {
"menu": {
"platform_health": "Santé de la plateforme",
"platform_monitoring": "Surveillance de la plateforme",
"capacity_monitor": "Moniteur de capacité",
"testing_hub": "Centre de tests",
"code_quality": "Qualité du code",
"import_jobs": "Tâches d'import",
"background_tasks": "Tâches de fond",
"application_logs": "Journaux applicatifs"
}
}

View File

@@ -1 +1,12 @@
{} {
"menu": {
"platform_health": "Plattform-Gesondheet",
"platform_monitoring": "Plattform-Iwwerwaachung",
"capacity_monitor": "Kapazitéitsmonitor",
"testing_hub": "Test-Center",
"code_quality": "Code-Qualitéit",
"import_jobs": "Import-Aufträg",
"background_tasks": "Hannergrondaufgaben",
"application_logs": "Applikatiounsprotokoller"
}
}

View File

@@ -74,5 +74,10 @@
"name": "Automatisierungsregeln", "name": "Automatisierungsregeln",
"description": "Automatisierte Bestellverarbeitungsregeln" "description": "Automatisierte Bestellverarbeitungsregeln"
} }
},
"menu": {
"store_operations": "Shop-Betrieb",
"sales_orders": "Verkäufe & Bestellungen",
"orders": "Bestellungen"
} }
} }

View File

@@ -74,5 +74,10 @@
"name": "Automation Rules", "name": "Automation Rules",
"description": "Automated order processing rules" "description": "Automated order processing rules"
} }
},
"menu": {
"store_operations": "Store Operations",
"sales_orders": "Sales & Orders",
"orders": "Orders"
} }
} }

View File

@@ -74,5 +74,10 @@
"name": "Règles d'automatisation", "name": "Règles d'automatisation",
"description": "Règles de traitement automatique des commandes" "description": "Règles de traitement automatique des commandes"
} }
},
"menu": {
"store_operations": "Opérations du magasin",
"sales_orders": "Ventes et Commandes",
"orders": "Commandes"
} }
} }

View File

@@ -74,5 +74,10 @@
"name": "Automatiséierungsreegelen", "name": "Automatiséierungsreegelen",
"description": "Automatiséiert Bestellveraarbechtungsreegelen" "description": "Automatiséiert Bestellveraarbechtungsreegelen"
} }
},
"menu": {
"store_operations": "Buttek-Operatiounen",
"sales_orders": "Verkaf & Bestellungen",
"orders": "Bestellungen"
} }
} }

View File

@@ -1,7 +1,15 @@
{ {
"menu": { "menu": {
"user_management": "Benutzerverwaltung", "user_management": "Benutzerverwaltung",
"merchant_users": "Händler-Benutzer" "merchant_users": "Händler-Benutzer",
"platform_admin": "Plattform-Administration",
"content_management": "Inhaltsverwaltung",
"account_settings": "Kontoeinstellungen",
"admin_users": "Admin-Benutzer",
"merchants": "Händler",
"stores": "Shops",
"platforms": "Plattformen",
"team": "Team"
}, },
"team": { "team": {
"title": "Team", "title": "Team",

View File

@@ -1,7 +1,15 @@
{ {
"menu": { "menu": {
"user_management": "User Management", "user_management": "User Management",
"merchant_users": "Merchant Users" "merchant_users": "Merchant Users",
"platform_admin": "Platform Admin",
"content_management": "Content Management",
"account_settings": "Account Settings",
"admin_users": "Admin Users",
"merchants": "Merchants",
"stores": "Stores",
"platforms": "Platforms",
"team": "Team"
}, },
"team": { "team": {
"title": "Team", "title": "Team",

View File

@@ -1,7 +1,15 @@
{ {
"menu": { "menu": {
"user_management": "Gestion des utilisateurs", "user_management": "Gestion des utilisateurs",
"merchant_users": "Utilisateurs marchands" "merchant_users": "Utilisateurs marchands",
"platform_admin": "Administration de la plateforme",
"content_management": "Gestion du contenu",
"account_settings": "Paramètres du compte",
"admin_users": "Utilisateurs administrateurs",
"merchants": "Marchands",
"stores": "Magasins",
"platforms": "Plateformes",
"team": "Équipe"
}, },
"team": { "team": {
"title": "Équipe", "title": "Équipe",

View File

@@ -1,7 +1,15 @@
{ {
"menu": { "menu": {
"user_management": "Benotzerverwaltung", "user_management": "Benotzerverwaltung",
"merchant_users": "Händler-Benotzer" "merchant_users": "Händler-Benotzer",
"platform_admin": "Plattform-Administratioun",
"content_management": "Inhaltsverwaltung",
"account_settings": "Kont-Astellungen",
"admin_users": "Admin-Benotzer",
"merchants": "Händler",
"stores": "Butteker",
"platforms": "Plattformen",
"team": "Team"
}, },
"team": { "team": {
"title": "Team", "title": "Team",

View File

@@ -61,9 +61,9 @@ class LanguageMiddleware(BaseHTTPMiddleware):
# Resolve language based on frontend type # Resolve language based on frontend type
if frontend_type == FrontendType.ADMIN: if frontend_type == FrontendType.ADMIN:
# Admin dashboard: English only (for now) # Admin dashboard: respect user's preferred language
# TODO: Implement admin language support later user_preferred = self._get_user_language_from_token(request)
language = "en" language = user_preferred or "en"
elif frontend_type == FrontendType.STORE: elif frontend_type == FrontendType.STORE:
# Store dashboard # Store dashboard