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,75 +1,79 @@
{
"products": {
"title": "Produkte",
"product": "Produkt",
"add_product": "Produkt hinzufügen",
"edit_product": "Produkt bearbeiten",
"delete_product": "Produkt löschen",
"product_name": "Produktname",
"product_code": "Produktcode",
"sku": "SKU",
"price": "Preis",
"sale_price": "Verkaufspreis",
"cost": "Kosten",
"stock": "Lagerbestand",
"in_stock": "Auf Lager",
"out_of_stock": "Nicht auf Lager",
"low_stock": "Geringer Bestand",
"availability": "Verfügbarkeit",
"available": "Verfügbar",
"unavailable": "Nicht verfügbar",
"brand": "Marke",
"category": "Kategorie",
"categories": "Kategorien",
"image": "Bild",
"images": "Bilder",
"main_image": "Hauptbild",
"gallery": "Galerie",
"weight": "Gewicht",
"dimensions": "Abmessungen",
"color": "Farbe",
"size": "Größe",
"material": "Material",
"condition": "Zustand",
"new": "Neu",
"used": "Gebraucht",
"refurbished": "Generalüberholt",
"no_products": "Keine Produkte gefunden",
"search_products": "Produkte suchen...",
"filter_by_category": "Nach Kategorie filtern",
"filter_by_status": "Nach Status filtern",
"sort_by": "Sortieren nach",
"sort_newest": "Neueste",
"sort_oldest": "Älteste",
"sort_price_low": "Preis: Niedrig bis Hoch",
"sort_price_high": "Preis: Hoch bis Niedrig",
"sort_name_az": "Name: A-Z",
"sort_name_za": "Name: Z-A"
},
"messages": {
"product_deleted_successfully": "Product deleted successfully",
"please_fill_in_all_required_fields": "Please fill in all required fields",
"product_updated_successfully": "Product updated successfully",
"failed_to_load_media_library": "Failed to load media library",
"no_store_associated_with_this_product": "No store associated with this product",
"please_select_an_image_file": "Please select an image file",
"image_must_be_less_than_10mb": "Image must be less than 10MB",
"image_uploaded_successfully": "Image uploaded successfully",
"product_removed_from_store_catalog": "Product removed from store catalog.",
"please_select_a_store": "Please select a store",
"please_enter_a_product_title_english": "Please enter a product title (English)",
"product_created_successfully": "Product created successfully",
"please_select_a_store_first": "Please select a store first"
},
"features": {
"products_limit": {
"name": "Produkte",
"description": "Maximale Anzahl an Produkten im Katalog",
"unit": "Produkte"
"products": {
"title": "Produkte",
"product": "Produkt",
"add_product": "Produkt hinzufügen",
"edit_product": "Produkt bearbeiten",
"delete_product": "Produkt löschen",
"product_name": "Produktname",
"product_code": "Produktcode",
"sku": "SKU",
"price": "Preis",
"sale_price": "Verkaufspreis",
"cost": "Kosten",
"stock": "Lagerbestand",
"in_stock": "Auf Lager",
"out_of_stock": "Nicht auf Lager",
"low_stock": "Geringer Bestand",
"availability": "Verfügbarkeit",
"available": "Verfügbar",
"unavailable": "Nicht verfügbar",
"brand": "Marke",
"category": "Kategorie",
"categories": "Kategorien",
"image": "Bild",
"images": "Bilder",
"main_image": "Hauptbild",
"gallery": "Galerie",
"weight": "Gewicht",
"dimensions": "Abmessungen",
"color": "Farbe",
"size": "Größe",
"material": "Material",
"condition": "Zustand",
"new": "Neu",
"used": "Gebraucht",
"refurbished": "Generalüberholt",
"no_products": "Keine Produkte gefunden",
"search_products": "Produkte suchen...",
"filter_by_category": "Nach Kategorie filtern",
"filter_by_status": "Nach Status filtern",
"sort_by": "Sortieren nach",
"sort_newest": "Neueste",
"sort_oldest": "Älteste",
"sort_price_low": "Preis: Niedrig bis Hoch",
"sort_price_high": "Preis: Hoch bis Niedrig",
"sort_name_az": "Name: A-Z",
"sort_name_za": "Name: Z-A"
},
"product_import_export": {
"name": "Import/Export",
"description": "Massenimport und -export von Produkten"
"messages": {
"product_deleted_successfully": "Product deleted successfully",
"please_fill_in_all_required_fields": "Please fill in all required fields",
"product_updated_successfully": "Product updated successfully",
"failed_to_load_media_library": "Failed to load media library",
"no_store_associated_with_this_product": "No store associated with this product",
"please_select_an_image_file": "Please select an image file",
"image_must_be_less_than_10mb": "Image must be less than 10MB",
"image_uploaded_successfully": "Image uploaded successfully",
"product_removed_from_store_catalog": "Product removed from store catalog.",
"please_select_a_store": "Please select a store",
"please_enter_a_product_title_english": "Please enter a product title (English)",
"product_created_successfully": "Product created successfully",
"please_select_a_store_first": "Please select a store first"
},
"features": {
"products_limit": {
"name": "Produkte",
"description": "Maximale Anzahl an Produkten im Katalog",
"unit": "Produkte"
},
"product_import_export": {
"name": "Import/Export",
"description": "Massenimport und -export von Produkten"
}
},
"menu": {
"products_inventory": "Produkte & Inventar",
"all_products": "Alle Produkte"
}
}
}

View File

@@ -1,93 +1,97 @@
{
"products": {
"title": "Products",
"product": "Product",
"add_product": "Add Product",
"edit_product": "Edit Product",
"delete_product": "Delete Product",
"product_name": "Product Name",
"product_code": "Product Code",
"sku": "SKU",
"price": "Price",
"sale_price": "Sale Price",
"cost": "Cost",
"stock": "Stock",
"in_stock": "In Stock",
"out_of_stock": "Out of Stock",
"low_stock": "Low Stock",
"availability": "Availability",
"available": "Available",
"unavailable": "Unavailable",
"brand": "Brand",
"category": "Category",
"categories": "Categories",
"image": "Image",
"images": "Images",
"main_image": "Main Image",
"gallery": "Gallery",
"weight": "Weight",
"dimensions": "Dimensions",
"color": "Color",
"size": "Size",
"material": "Material",
"condition": "Condition",
"new": "New",
"used": "Used",
"refurbished": "Refurbished",
"no_products": "No products found",
"search_products": "Search products...",
"filter_by_category": "Filter by category",
"filter_by_status": "Filter by status",
"sort_by": "Sort by",
"sort_newest": "Newest",
"sort_oldest": "Oldest",
"sort_price_low": "Price: Low to High",
"sort_price_high": "Price: High to Low",
"sort_name_az": "Name: A-Z",
"sort_name_za": "Name: Z-A"
},
"messages": {
"product_deleted_successfully": "Product deleted successfully",
"product_created_successfully": "Product created successfully",
"product_updated_successfully": "Product updated successfully",
"product_activated": "Product activated",
"product_deactivated": "Product deactivated",
"product_marked_as_featured": "Product marked as featured",
"product_unmarked_as_featured": "Product unmarked as featured",
"products_activated": "{count} product(s) activated",
"products_deactivated": "{count} product(s) deactivated",
"products_marked_as_featured": "{count} product(s) marked as featured",
"products_unmarked_as_featured": "{count} product(s) unmarked as featured",
"products_deleted": "{count} product(s) deleted",
"failed_to_save_product": "Failed to save product",
"failed_to_create_product": "Failed to create product",
"failed_to_update_product": "Failed to update product",
"failed_to_delete_product": "Failed to delete product",
"failed_to_load_products": "Failed to load products",
"failed_to_activate_products": "Failed to activate products",
"failed_to_deactivate_products": "Failed to deactivate products",
"failed_to_upload_image": "Failed to upload image",
"product_removed_from_store_catalog": "Product removed from store catalog.",
"please_fill_in_all_required_fields": "Please fill in all required fields",
"failed_to_load_media_library": "Failed to load media library",
"no_store_associated_with_this_product": "No store associated with this product",
"please_select_an_image_file": "Please select an image file",
"image_must_be_less_than_10mb": "Image must be less than 10MB",
"image_uploaded_successfully": "Image uploaded successfully",
"please_select_a_store": "Please select a store",
"please_enter_a_product_title_english": "Please enter a product title (English)",
"please_select_a_store_first": "Please select a store first",
"title_and_price_required": "Title and price are required"
},
"features": {
"products_limit": {
"name": "Products",
"description": "Maximum number of products in catalog",
"unit": "products"
"products": {
"title": "Products",
"product": "Product",
"add_product": "Add Product",
"edit_product": "Edit Product",
"delete_product": "Delete Product",
"product_name": "Product Name",
"product_code": "Product Code",
"sku": "SKU",
"price": "Price",
"sale_price": "Sale Price",
"cost": "Cost",
"stock": "Stock",
"in_stock": "In Stock",
"out_of_stock": "Out of Stock",
"low_stock": "Low Stock",
"availability": "Availability",
"available": "Available",
"unavailable": "Unavailable",
"brand": "Brand",
"category": "Category",
"categories": "Categories",
"image": "Image",
"images": "Images",
"main_image": "Main Image",
"gallery": "Gallery",
"weight": "Weight",
"dimensions": "Dimensions",
"color": "Color",
"size": "Size",
"material": "Material",
"condition": "Condition",
"new": "New",
"used": "Used",
"refurbished": "Refurbished",
"no_products": "No products found",
"search_products": "Search products...",
"filter_by_category": "Filter by category",
"filter_by_status": "Filter by status",
"sort_by": "Sort by",
"sort_newest": "Newest",
"sort_oldest": "Oldest",
"sort_price_low": "Price: Low to High",
"sort_price_high": "Price: High to Low",
"sort_name_az": "Name: A-Z",
"sort_name_za": "Name: Z-A"
},
"product_import_export": {
"name": "Import/Export",
"description": "Bulk product import and export functionality"
"messages": {
"product_deleted_successfully": "Product deleted successfully",
"product_created_successfully": "Product created successfully",
"product_updated_successfully": "Product updated successfully",
"product_activated": "Product activated",
"product_deactivated": "Product deactivated",
"product_marked_as_featured": "Product marked as featured",
"product_unmarked_as_featured": "Product unmarked as featured",
"products_activated": "{count} product(s) activated",
"products_deactivated": "{count} product(s) deactivated",
"products_marked_as_featured": "{count} product(s) marked as featured",
"products_unmarked_as_featured": "{count} product(s) unmarked as featured",
"products_deleted": "{count} product(s) deleted",
"failed_to_save_product": "Failed to save product",
"failed_to_create_product": "Failed to create product",
"failed_to_update_product": "Failed to update product",
"failed_to_delete_product": "Failed to delete product",
"failed_to_load_products": "Failed to load products",
"failed_to_activate_products": "Failed to activate products",
"failed_to_deactivate_products": "Failed to deactivate products",
"failed_to_upload_image": "Failed to upload image",
"product_removed_from_store_catalog": "Product removed from store catalog.",
"please_fill_in_all_required_fields": "Please fill in all required fields",
"failed_to_load_media_library": "Failed to load media library",
"no_store_associated_with_this_product": "No store associated with this product",
"please_select_an_image_file": "Please select an image file",
"image_must_be_less_than_10mb": "Image must be less than 10MB",
"image_uploaded_successfully": "Image uploaded successfully",
"please_select_a_store": "Please select a store",
"please_enter_a_product_title_english": "Please enter a product title (English)",
"please_select_a_store_first": "Please select a store first",
"title_and_price_required": "Title and price are required"
},
"features": {
"products_limit": {
"name": "Products",
"description": "Maximum number of products in catalog",
"unit": "products"
},
"product_import_export": {
"name": "Import/Export",
"description": "Bulk product import and export functionality"
}
},
"menu": {
"products_inventory": "Products & Inventory",
"all_products": "All Products"
}
}
}

View File

@@ -1,75 +1,79 @@
{
"products": {
"title": "Produits",
"product": "Produit",
"add_product": "Ajouter un produit",
"edit_product": "Modifier le produit",
"delete_product": "Supprimer le produit",
"product_name": "Nom du produit",
"product_code": "Code produit",
"sku": "SKU",
"price": "Prix",
"sale_price": "Prix de vente",
"cost": "Coût",
"stock": "Stock",
"in_stock": "En stock",
"out_of_stock": "Rupture de stock",
"low_stock": "Stock faible",
"availability": "Disponibilité",
"available": "Disponible",
"unavailable": "Indisponible",
"brand": "Marque",
"category": "Catégorie",
"categories": "Catégories",
"image": "Image",
"images": "Images",
"main_image": "Image principale",
"gallery": "Galerie",
"weight": "Poids",
"dimensions": "Dimensions",
"color": "Couleur",
"size": "Taille",
"material": "Matériau",
"condition": "État",
"new": "Neuf",
"used": "Occasion",
"refurbished": "Reconditionné",
"no_products": "Aucun produit trouvé",
"search_products": "Rechercher des produits...",
"filter_by_category": "Filtrer par catégorie",
"filter_by_status": "Filtrer par statut",
"sort_by": "Trier par",
"sort_newest": "Plus récent",
"sort_oldest": "Plus ancien",
"sort_price_low": "Prix : croissant",
"sort_price_high": "Prix : décroissant",
"sort_name_az": "Nom : A-Z",
"sort_name_za": "Nom : Z-A"
},
"messages": {
"product_deleted_successfully": "Product deleted successfully",
"please_fill_in_all_required_fields": "Please fill in all required fields",
"product_updated_successfully": "Product updated successfully",
"failed_to_load_media_library": "Failed to load media library",
"no_store_associated_with_this_product": "No store associated with this product",
"please_select_an_image_file": "Please select an image file",
"image_must_be_less_than_10mb": "Image must be less than 10MB",
"image_uploaded_successfully": "Image uploaded successfully",
"product_removed_from_store_catalog": "Product removed from store catalog.",
"please_select_a_store": "Please select a store",
"please_enter_a_product_title_english": "Please enter a product title (English)",
"product_created_successfully": "Product created successfully",
"please_select_a_store_first": "Please select a store first"
},
"features": {
"products_limit": {
"name": "Produits",
"description": "Nombre maximum de produits dans le catalogue",
"unit": "produits"
"products": {
"title": "Produits",
"product": "Produit",
"add_product": "Ajouter un produit",
"edit_product": "Modifier le produit",
"delete_product": "Supprimer le produit",
"product_name": "Nom du produit",
"product_code": "Code produit",
"sku": "SKU",
"price": "Prix",
"sale_price": "Prix de vente",
"cost": "Coût",
"stock": "Stock",
"in_stock": "En stock",
"out_of_stock": "Rupture de stock",
"low_stock": "Stock faible",
"availability": "Disponibilité",
"available": "Disponible",
"unavailable": "Indisponible",
"brand": "Marque",
"category": "Catégorie",
"categories": "Catégories",
"image": "Image",
"images": "Images",
"main_image": "Image principale",
"gallery": "Galerie",
"weight": "Poids",
"dimensions": "Dimensions",
"color": "Couleur",
"size": "Taille",
"material": "Matériau",
"condition": "État",
"new": "Neuf",
"used": "Occasion",
"refurbished": "Reconditionné",
"no_products": "Aucun produit trouvé",
"search_products": "Rechercher des produits...",
"filter_by_category": "Filtrer par catégorie",
"filter_by_status": "Filtrer par statut",
"sort_by": "Trier par",
"sort_newest": "Plus récent",
"sort_oldest": "Plus ancien",
"sort_price_low": "Prix : croissant",
"sort_price_high": "Prix : décroissant",
"sort_name_az": "Nom : A-Z",
"sort_name_za": "Nom : Z-A"
},
"product_import_export": {
"name": "Import/Export",
"description": "Import et export en masse de produits"
"messages": {
"product_deleted_successfully": "Product deleted successfully",
"please_fill_in_all_required_fields": "Please fill in all required fields",
"product_updated_successfully": "Product updated successfully",
"failed_to_load_media_library": "Failed to load media library",
"no_store_associated_with_this_product": "No store associated with this product",
"please_select_an_image_file": "Please select an image file",
"image_must_be_less_than_10mb": "Image must be less than 10MB",
"image_uploaded_successfully": "Image uploaded successfully",
"product_removed_from_store_catalog": "Product removed from store catalog.",
"please_select_a_store": "Please select a store",
"please_enter_a_product_title_english": "Please enter a product title (English)",
"product_created_successfully": "Product created successfully",
"please_select_a_store_first": "Please select a store first"
},
"features": {
"products_limit": {
"name": "Produits",
"description": "Nombre maximum de produits dans le catalogue",
"unit": "produits"
},
"product_import_export": {
"name": "Import/Export",
"description": "Import et export en masse de produits"
}
},
"menu": {
"products_inventory": "Produits et Inventaire",
"all_products": "Tous les produits"
}
}
}

View File

@@ -1,75 +1,79 @@
{
"products": {
"title": "Produkter",
"product": "Produkt",
"add_product": "Produkt derbäisetzen",
"edit_product": "Produkt änneren",
"delete_product": "Produkt läschen",
"product_name": "Produktnumm",
"product_code": "Produktcode",
"sku": "SKU",
"price": "Präis",
"sale_price": "Verkafspräis",
"cost": "Käschten",
"stock": "Lager",
"in_stock": "Op Lager",
"out_of_stock": "Net op Lager",
"low_stock": "Niddregen Stock",
"availability": "Disponibilitéit",
"available": "Disponibel",
"unavailable": "Net disponibel",
"brand": "Mark",
"category": "Kategorie",
"categories": "Kategorien",
"image": "Bild",
"images": "Biller",
"main_image": "Haaptbild",
"gallery": "Galerie",
"weight": "Gewiicht",
"dimensions": "Dimensiounen",
"color": "Faarf",
"size": "Gréisst",
"material": "Material",
"condition": "Zoustand",
"new": "Nei",
"used": "Gebraucht",
"refurbished": "Iwwerholl",
"no_products": "Keng Produkter fonnt",
"search_products": "Produkter sichen...",
"filter_by_category": "No Kategorie filteren",
"filter_by_status": "No Status filteren",
"sort_by": "Sortéieren no",
"sort_newest": "Neisten",
"sort_oldest": "Eelsten",
"sort_price_low": "Präis: Niddreg op Héich",
"sort_price_high": "Präis: Héich op Niddreg",
"sort_name_az": "Numm: A-Z",
"sort_name_za": "Numm: Z-A"
},
"messages": {
"product_deleted_successfully": "Product deleted successfully",
"please_fill_in_all_required_fields": "Please fill in all required fields",
"product_updated_successfully": "Product updated successfully",
"failed_to_load_media_library": "Failed to load media library",
"no_store_associated_with_this_product": "No store associated with this product",
"please_select_an_image_file": "Please select an image file",
"image_must_be_less_than_10mb": "Image must be less than 10MB",
"image_uploaded_successfully": "Image uploaded successfully",
"product_removed_from_store_catalog": "Product removed from store catalog.",
"please_select_a_store": "Please select a store",
"please_enter_a_product_title_english": "Please enter a product title (English)",
"product_created_successfully": "Product created successfully",
"please_select_a_store_first": "Please select a store first"
},
"features": {
"products_limit": {
"name": "Produkter",
"description": "Maximal Unzuel vu Produkter am Katalog",
"unit": "Produkter"
"products": {
"title": "Produkter",
"product": "Produkt",
"add_product": "Produkt derbäisetzen",
"edit_product": "Produkt änneren",
"delete_product": "Produkt läschen",
"product_name": "Produktnumm",
"product_code": "Produktcode",
"sku": "SKU",
"price": "Präis",
"sale_price": "Verkafspräis",
"cost": "Käschten",
"stock": "Lager",
"in_stock": "Op Lager",
"out_of_stock": "Net op Lager",
"low_stock": "Niddregen Stock",
"availability": "Disponibilitéit",
"available": "Disponibel",
"unavailable": "Net disponibel",
"brand": "Mark",
"category": "Kategorie",
"categories": "Kategorien",
"image": "Bild",
"images": "Biller",
"main_image": "Haaptbild",
"gallery": "Galerie",
"weight": "Gewiicht",
"dimensions": "Dimensiounen",
"color": "Faarf",
"size": "Gréisst",
"material": "Material",
"condition": "Zoustand",
"new": "Nei",
"used": "Gebraucht",
"refurbished": "Iwwerholl",
"no_products": "Keng Produkter fonnt",
"search_products": "Produkter sichen...",
"filter_by_category": "No Kategorie filteren",
"filter_by_status": "No Status filteren",
"sort_by": "Sortéieren no",
"sort_newest": "Neisten",
"sort_oldest": "Eelsten",
"sort_price_low": "Präis: Niddreg op Héich",
"sort_price_high": "Präis: Héich op Niddreg",
"sort_name_az": "Numm: A-Z",
"sort_name_za": "Numm: Z-A"
},
"product_import_export": {
"name": "Import/Export",
"description": "Mass-Import an -Export vu Produkter"
"messages": {
"product_deleted_successfully": "Product deleted successfully",
"please_fill_in_all_required_fields": "Please fill in all required fields",
"product_updated_successfully": "Product updated successfully",
"failed_to_load_media_library": "Failed to load media library",
"no_store_associated_with_this_product": "No store associated with this product",
"please_select_an_image_file": "Please select an image file",
"image_must_be_less_than_10mb": "Image must be less than 10MB",
"image_uploaded_successfully": "Image uploaded successfully",
"product_removed_from_store_catalog": "Product removed from store catalog.",
"please_select_a_store": "Please select a store",
"please_enter_a_product_title_english": "Please enter a product title (English)",
"product_created_successfully": "Product created successfully",
"please_select_a_store_first": "Please select a store first"
},
"features": {
"products_limit": {
"name": "Produkter",
"description": "Maximal Unzuel vu Produkter am Katalog",
"unit": "Produkter"
},
"product_import_export": {
"name": "Import/Export",
"description": "Mass-Import an -Export vu Produkter"
}
},
"menu": {
"products_inventory": "Produkter & Inventar",
"all_products": "All Produkter"
}
}
}