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,40 +1,46 @@
{
"inventory": {
"title": "Inventar",
"stock_level": "Lagerbestand",
"quantity": "Menge",
"reorder_point": "Nachbestellpunkt",
"adjust_stock": "Bestand anpassen",
"stock_in": "Wareneingang",
"stock_out": "Warenausgang",
"transfer": "Transfer",
"history": "Verlauf",
"low_stock_alert": "Warnung bei geringem Bestand",
"out_of_stock_alert": "Warnung bei Ausverkauf"
},
"messages": {
"stock_adjusted_successfully": "Stock adjusted successfully",
"quantity_set_successfully": "Quantity set successfully",
"inventory_entry_deleted": "Inventory entry deleted.",
"please_select_a_store_and_file": "Please select a store and file",
"import_completed_with_errors": "Import completed with errors"
},
"features": {
"inventory_basic": {
"name": "Basis-Inventar",
"description": "Grundlegende Lagerverwaltung"
"inventory": {
"title": "Inventar",
"stock_level": "Lagerbestand",
"quantity": "Menge",
"reorder_point": "Nachbestellpunkt",
"adjust_stock": "Bestand anpassen",
"stock_in": "Wareneingang",
"stock_out": "Warenausgang",
"transfer": "Transfer",
"history": "Verlauf",
"low_stock_alert": "Warnung bei geringem Bestand",
"out_of_stock_alert": "Warnung bei Ausverkauf"
},
"inventory_locations": {
"name": "Mehrere Standorte",
"description": "Inventar an mehreren Standorten verwalten"
"messages": {
"stock_adjusted_successfully": "Stock adjusted successfully",
"quantity_set_successfully": "Quantity set successfully",
"inventory_entry_deleted": "Inventory entry deleted.",
"please_select_a_store_and_file": "Please select a store and file",
"import_completed_with_errors": "Import completed with errors"
},
"inventory_purchase_orders": {
"name": "Bestellungen",
"description": "Bestellungen erstellen und verwalten"
"features": {
"inventory_basic": {
"name": "Basis-Inventar",
"description": "Grundlegende Lagerverwaltung"
},
"inventory_locations": {
"name": "Mehrere Standorte",
"description": "Inventar an mehreren Standorten verwalten"
},
"inventory_purchase_orders": {
"name": "Bestellungen",
"description": "Bestellungen erstellen und verwalten"
},
"low_stock_alerts": {
"name": "Niedrigbestandswarnungen",
"description": "Automatische Benachrichtigungen bei niedrigem Lagerbestand"
}
},
"low_stock_alerts": {
"name": "Niedrigbestandswarnungen",
"description": "Automatische Benachrichtigungen bei niedrigem Lagerbestand"
"menu": {
"store_operations": "Shop-Betrieb",
"products_inventory": "Produkte & Inventar",
"products": "Produkte",
"inventory": "Inventar"
}
}
}

View File

@@ -1,49 +1,55 @@
{
"inventory": {
"title": "Inventory",
"stock_level": "Stock Level",
"quantity": "Quantity",
"reorder_point": "Reorder Point",
"adjust_stock": "Adjust Stock",
"stock_in": "Stock In",
"stock_out": "Stock Out",
"transfer": "Transfer",
"history": "History",
"low_stock_alert": "Low Stock Alert",
"out_of_stock_alert": "Out of Stock Alert"
},
"messages": {
"stock_adjusted_successfully": "Stock adjusted successfully",
"quantity_set_successfully": "Quantity set successfully",
"inventory_entry_deleted": "Inventory entry deleted.",
"please_select_a_store_and_file": "Please select a store and file",
"import_completed_with_errors": "Import completed with errors",
"failed_to_adjust_stock": "Failed to adjust stock.",
"failed_to_set_quantity": "Failed to set quantity.",
"failed_to_delete_entry": "Failed to delete entry.",
"import_success": "Imported {quantity} units ({created} new, {updated} updated)",
"import_completed": "Import completed: {created} created, {updated} updated, {errors} errors",
"import_failed": "Import failed",
"bulk_adjust_success": "{count} item(s) adjusted by {amount}",
"failed_to_adjust_inventory": "Failed to adjust inventory",
"exported_items": "Exported {count} item(s)"
},
"features": {
"inventory_basic": {
"name": "Basic Inventory",
"description": "Basic stock management"
"inventory": {
"title": "Inventory",
"stock_level": "Stock Level",
"quantity": "Quantity",
"reorder_point": "Reorder Point",
"adjust_stock": "Adjust Stock",
"stock_in": "Stock In",
"stock_out": "Stock Out",
"transfer": "Transfer",
"history": "History",
"low_stock_alert": "Low Stock Alert",
"out_of_stock_alert": "Out of Stock Alert"
},
"inventory_locations": {
"name": "Multiple Locations",
"description": "Manage inventory across multiple locations"
"messages": {
"stock_adjusted_successfully": "Stock adjusted successfully",
"quantity_set_successfully": "Quantity set successfully",
"inventory_entry_deleted": "Inventory entry deleted.",
"please_select_a_store_and_file": "Please select a store and file",
"import_completed_with_errors": "Import completed with errors",
"failed_to_adjust_stock": "Failed to adjust stock.",
"failed_to_set_quantity": "Failed to set quantity.",
"failed_to_delete_entry": "Failed to delete entry.",
"import_success": "Imported {quantity} units ({created} new, {updated} updated)",
"import_completed": "Import completed: {created} created, {updated} updated, {errors} errors",
"import_failed": "Import failed",
"bulk_adjust_success": "{count} item(s) adjusted by {amount}",
"failed_to_adjust_inventory": "Failed to adjust inventory",
"exported_items": "Exported {count} item(s)"
},
"inventory_purchase_orders": {
"name": "Purchase Orders",
"description": "Create and manage purchase orders"
"features": {
"inventory_basic": {
"name": "Basic Inventory",
"description": "Basic stock management"
},
"inventory_locations": {
"name": "Multiple Locations",
"description": "Manage inventory across multiple locations"
},
"inventory_purchase_orders": {
"name": "Purchase Orders",
"description": "Create and manage purchase orders"
},
"low_stock_alerts": {
"name": "Low Stock Alerts",
"description": "Automatic notifications for low stock levels"
}
},
"low_stock_alerts": {
"name": "Low Stock Alerts",
"description": "Automatic notifications for low stock levels"
"menu": {
"store_operations": "Store Operations",
"products_inventory": "Products & Inventory",
"products": "Products",
"inventory": "Inventory"
}
}
}

View File

@@ -1,40 +1,46 @@
{
"inventory": {
"title": "Inventaire",
"stock_level": "Niveau de stock",
"quantity": "Quantité",
"reorder_point": "Seuil de réapprovisionnement",
"adjust_stock": "Ajuster le stock",
"stock_in": "Entrée de stock",
"stock_out": "Sortie de stock",
"transfer": "Transfert",
"history": "Historique",
"low_stock_alert": "Alerte stock faible",
"out_of_stock_alert": "Alerte rupture de stock"
},
"messages": {
"stock_adjusted_successfully": "Stock adjusted successfully",
"quantity_set_successfully": "Quantity set successfully",
"inventory_entry_deleted": "Inventory entry deleted.",
"please_select_a_store_and_file": "Please select a store and file",
"import_completed_with_errors": "Import completed with errors"
},
"features": {
"inventory_basic": {
"name": "Inventaire de base",
"description": "Gestion de stock de base"
"inventory": {
"title": "Inventaire",
"stock_level": "Niveau de stock",
"quantity": "Quantité",
"reorder_point": "Seuil de réapprovisionnement",
"adjust_stock": "Ajuster le stock",
"stock_in": "Entrée de stock",
"stock_out": "Sortie de stock",
"transfer": "Transfert",
"history": "Historique",
"low_stock_alert": "Alerte stock faible",
"out_of_stock_alert": "Alerte rupture de stock"
},
"inventory_locations": {
"name": "Emplacements multiples",
"description": "Gérer l'inventaire sur plusieurs emplacements"
"messages": {
"stock_adjusted_successfully": "Stock adjusted successfully",
"quantity_set_successfully": "Quantity set successfully",
"inventory_entry_deleted": "Inventory entry deleted.",
"please_select_a_store_and_file": "Please select a store and file",
"import_completed_with_errors": "Import completed with errors"
},
"inventory_purchase_orders": {
"name": "Bons de commande",
"description": "Créer et gérer les bons de commande"
"features": {
"inventory_basic": {
"name": "Inventaire de base",
"description": "Gestion de stock de base"
},
"inventory_locations": {
"name": "Emplacements multiples",
"description": "Gérer l'inventaire sur plusieurs emplacements"
},
"inventory_purchase_orders": {
"name": "Bons de commande",
"description": "Créer et gérer les bons de commande"
},
"low_stock_alerts": {
"name": "Alertes stock bas",
"description": "Notifications automatiques pour les niveaux de stock bas"
}
},
"low_stock_alerts": {
"name": "Alertes 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

@@ -1,40 +1,46 @@
{
"inventory": {
"title": "Inventar",
"stock_level": "Lagerniveau",
"quantity": "Quantitéit",
"reorder_point": "Nobestellungspunkt",
"adjust_stock": "Lager upaassen",
"stock_in": "Lager eran",
"stock_out": "Lager eraus",
"transfer": "Transfer",
"history": "Geschicht",
"low_stock_alert": "Niddreg Lager Alarm",
"out_of_stock_alert": "Net op Lager Alarm"
},
"messages": {
"stock_adjusted_successfully": "Stock adjusted successfully",
"quantity_set_successfully": "Quantity set successfully",
"inventory_entry_deleted": "Inventory entry deleted.",
"please_select_a_store_and_file": "Please select a store and file",
"import_completed_with_errors": "Import completed with errors"
},
"features": {
"inventory_basic": {
"name": "Basis-Inventar",
"description": "Grondleeënd Lagerverwaltung"
"inventory": {
"title": "Inventar",
"stock_level": "Lagerniveau",
"quantity": "Quantitéit",
"reorder_point": "Nobestellungspunkt",
"adjust_stock": "Lager upaassen",
"stock_in": "Lager eran",
"stock_out": "Lager eraus",
"transfer": "Transfer",
"history": "Geschicht",
"low_stock_alert": "Niddreg Lager Alarm",
"out_of_stock_alert": "Net op Lager Alarm"
},
"inventory_locations": {
"name": "Méi Standuerter",
"description": "Inventar u méi Standuerter verwalten"
"messages": {
"stock_adjusted_successfully": "Stock adjusted successfully",
"quantity_set_successfully": "Quantity set successfully",
"inventory_entry_deleted": "Inventory entry deleted.",
"please_select_a_store_and_file": "Please select a store and file",
"import_completed_with_errors": "Import completed with errors"
},
"inventory_purchase_orders": {
"name": "Bestellungen",
"description": "Bestellungen erstellen an verwalten"
"features": {
"inventory_basic": {
"name": "Basis-Inventar",
"description": "Grondleeënd Lagerverwaltung"
},
"inventory_locations": {
"name": "Méi Standuerter",
"description": "Inventar u méi Standuerter verwalten"
},
"inventory_purchase_orders": {
"name": "Bestellungen",
"description": "Bestellungen erstellen an verwalten"
},
"low_stock_alerts": {
"name": "Niddreg-Lagerbestandswarnungen",
"description": "Automatesch Benoriichtegungen bei niddregem Lagerbestand"
}
},
"low_stock_alerts": {
"name": "Niddreg-Lagerbestandswarnungen",
"description": "Automatesch Benoriichtegungen bei niddregem Lagerbestand"
"menu": {
"store_operations": "Buttek-Operatiounen",
"products_inventory": "Produkter & Inventar",
"products": "Produkter",
"inventory": "Inventar"
}
}
}