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:
@@ -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"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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 = []
|
||||||
|
|||||||
@@ -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"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -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"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -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"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -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"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -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"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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",
|
||||||
|
|||||||
@@ -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",
|
||||||
|
|||||||
@@ -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",
|
||||||
|
|||||||
@@ -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",
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
Reference in New Issue
Block a user