fix: shopping list categories were English-only and untranslated, page too narrow

Confirmed from a real screenshot: every item in an all-French shopping list
was uncategorized because guessAisle() only matched English keywords —
"sometimes reorganize doesn't work" was actually "always fails on non-English
ingredient names". Also fixed:

- Categories are now translated (grocery-categories.ts stores locale-
  independent slugs like "produce", translated for display via
  shoppingLists.categories.* instead of storing/rendering the English label
  directly)
- Added French keyword coverage to the aisle guesser so auto-categorization
  actually works for French recipes
- Users can now type a custom category name from the item's category menu
- The sort-mode dropdown was showing the raw value ("category") instead of
  its label — base-ui's Select.Value has no built-in value->label lookup,
  it needs an explicit render function, which no Select in this call site
  had
- Widened the shopping list detail page (max-w-lg -> max-w-2xl)
- Root-caused a second bug visible in the same screenshot: ingredients with
  the quantity embedded in the name (e.g. "1 avocat") still showed that way
  even though quantity/unit were already populated separately, because the
  extraction helper only fired when quantity was empty. Now it always
  cleans the name but only backfills quantity/unit when they're missing,
  and runs at shopping-list generation time too (not just recipe save) so
  it also cleans up already-contaminated recipes, not just new ones.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
Arnaud
2026-07-10 11:03:11 +02:00
parent 5afc7cd182
commit 51a323b054
7 changed files with 202 additions and 61 deletions
+14 -1
View File
@@ -826,7 +826,20 @@
"listDeleted": "List deleted",
"listDeleteFailed": "Failed to delete list",
"changeCategory": "Change category",
"deleteItem": "Delete item"
"deleteItem": "Delete item",
"aisleOther": "Other",
"newCategoryPlaceholder": "New category…",
"addCategory": "Add",
"categories": {
"produce": "Produce",
"dairyEggs": "Dairy & Eggs",
"meatSeafood": "Meat & Seafood",
"bakery": "Bakery",
"frozen": "Frozen",
"pantry": "Pantry",
"spicesCondiments": "Spices & Condiments",
"beverages": "Beverages"
}
},
"collections": {
"title": "Collections",
+14 -1
View File
@@ -814,7 +814,20 @@
"listDeleted": "Liste supprimée",
"listDeleteFailed": "Échec de la suppression de la liste",
"changeCategory": "Changer de catégorie",
"deleteItem": "Supprimer l'article"
"deleteItem": "Supprimer l'article",
"aisleOther": "Autre",
"newCategoryPlaceholder": "Nouvelle catégorie…",
"addCategory": "Ajouter",
"categories": {
"produce": "Fruits & légumes",
"dairyEggs": "Produits laitiers & œufs",
"meatSeafood": "Viande & poisson",
"bakery": "Boulangerie",
"frozen": "Surgelés",
"pantry": "Épicerie",
"spicesCondiments": "Épices & condiments",
"beverages": "Boissons"
}
},
"collections": {
"title": "Collections",