/** * English key for every catalog reference label — `Diet`/`Category` * (allergens)/`Ingredient` rows must carry a stable, storage-safe `key` * that is itself English, independent of whatever language the *seed's* * authoring label (`DIETS`/`ALLERGENS`/`INGREDIENT_GROUPS` in * `reference-seed-data.ts`, currently French) happens to be in — a French * `key` would tie the identifier to the one language it's meant to be * decoupled from (see `utils/slugify.ts`'s doc comment and `apps/web`'s * `locales/fr/translation.json` `catalog.*` namespace, which resolves the * *display* label from this same key). * * Hand-assigned (not machine-translated) — an English label is chosen once * and never changes, exactly like the key it produces (via {@link * slugify}). Keyed by the exact French authoring label so * `reference-seed-data.ts` and `scripts/generate-catalog-i18n.ts` can look * a row's key up by the same string they already have in hand. * * `getEnglishKey` throws on a missing entry rather than falling back to * slugifying the French label — a silently-French key defeats the point, * so a newly-added diet/allergen/ingredient must get an entry here before * it can seed. */ import { slugify } from "../utils/slugify.js"; const DIET_KEYS: Record = { Omnivore: "omnivore", Végétarien: "vegetarian", Végan: "vegan", Pescétarien: "pescatarian", "Sans gluten": "gluten_free", }; const ALLERGEN_KEYS: Record = { Gluten: "gluten", Crustacés: "crustaceans", Œufs: "eggs", Poissons: "fish", Arachides: "peanuts", Soja: "soy", Lait: "milk", "Fruits à coque": "tree_nuts", Céleri: "celery", Moutarde: "mustard", "Graines de sésame": "sesame_seeds", Sulfites: "sulfites", Lupin: "lupin", Mollusques: "molluscs", }; // Grouped by (category, subcategory), mirroring `INGREDIENT_GROUPS` in // reference-seed-data.ts, purely so a translator can find/check an entry // against its source group — this is one flat lookup table at runtime. const INGREDIENT_KEYS: Record = { // --- Produits frais / Légumes --------------------------------------- Tomate: "tomato", Oignon: "onion", Échalote: "shallot", Ail: "garlic", Carotte: "carrot", Courgette: "zucchini", Concombre: "cucumber", Cornichons: "gherkins", Poivron: "bell_pepper", Champignon: "mushroom", Cèpes: "porcini", Aubergine: "eggplant", Brocoli: "broccoli", "Chou-fleur": "cauliflower", "Chou blanc": "white_cabbage", "Chou rouge": "red_cabbage", "Chou de Bruxelles": "brussels_sprouts", Épinard: "spinach", Blette: "swiss_chard", Salade: "lettuce", Roquette: "arugula", Cresson: "watercress", Poireau: "leek", Radis: "radish", Betterave: "beetroot", Navet: "turnip", Panais: "parsnip", "Haricot vert": "green_bean", "Petit pois": "pea", Maïs: "corn", Artichaut: "artichoke", Fenouil: "fennel", Endive: "endive", Potiron: "pumpkin", Butternut: "butternut_squash", Asperge: "asparagus", Avocat: "avocado", "Pomme de terre": "potato", "Patate douce": "sweet_potato", "Tomates cerises": "cherry_tomato", "Pak-choï": "bok_choy", "Germes de soja": "soybean_sprouts", Shiitake: "shiitake", Daikon: "daikon", "Piment vert frais": "fresh_green_chili", // --- Produits frais / Fruits ----------------------------------------- Citron: "lemon", "Citron vert": "lime", Pomme: "apple", Poire: "pear", Banane: "banana", Orange: "orange", Clémentine: "clementine", Pamplemousse: "grapefruit", Fraise: "strawberry", Framboise: "raspberry", Myrtille: "blueberry", Mûre: "blackberry", Cerise: "cherry", Abricot: "apricot", Pêche: "peach", Prune: "plum", Raisin: "grape", Melon: "melon", Pastèque: "watermelon", Ananas: "pineapple", Mangue: "mango", Kiwi: "kiwi", Figue: "fig", Datte: "date", Litchi: "lychee", Grenade: "pomegranate", Rhubarbe: "rhubarb", Coing: "quince", // --- Produits frais / Herbes fraîches --------------------------------- Basilic: "basil", Persil: "parsley", Thym: "thyme", Romarin: "rosemary", Laurier: "bay_leaf", Ciboulette: "chives", "Coriandre fraîche": "fresh_cilantro", Menthe: "mint", Origan: "oregano", Aneth: "dill", Estragon: "tarragon", Sarriette: "savory", Marjolaine: "marjoram", Sauge: "sage", Cerfeuil: "chervil", Gingembre: "ginger", Citronnelle: "lemongrass", Combava: "kaffir_lime", // --- Boucherie & poissonnerie / Viandes ------------------------------- Lapin: "rabbit", "Bœuf haché": "ground_beef", "Steak de bœuf": "beef_steak", "Rôti de bœuf": "beef_roast", "Escalope de veau": "veal_cutlet", "Filet mignon de porc": "pork_tenderloin", "Côte de porc": "pork_chop", Agneau: "lamb", "Gigot d'agneau": "leg_of_lamb", Lardons: "bacon_lardons", Bacon: "bacon", "Jambon blanc": "ham", "Jambon cru": "cured_ham", Saucisse: "sausage", Chorizo: "chorizo", Merguez: "merguez", Prosciutto: "prosciutto", Pancetta: "pancetta", Mortadelle: "mortadella", Salami: "salami", // --- Boucherie & poissonnerie / Volailles ----------------------------- Poulet: "chicken", Dinde: "turkey", Canard: "duck", "Magret de canard": "duck_breast", // --- Boucherie & poissonnerie / Poissons ------------------------------- Saumon: "salmon", Thon: "tuna", Cabillaud: "cod", Truite: "trout", Sardine: "sardine", Anchois: "anchovy", Merlan: "whiting", Surimi: "surimi", "Bar (loup de mer)": "sea_bass", Dorade: "sea_bream", Sole: "sole", Turbot: "turbot", Merlu: "hake", Colin: "pollock", "Lieu noir": "saithe", Églefin: "haddock", Maquereau: "mackerel", Hareng: "herring", Rouget: "red_mullet", Raie: "skate", Lotte: "monkfish", Flétan: "halibut", Espadon: "swordfish", Carpe: "carp", Brochet: "pike", Perche: "perch", Tilapia: "tilapia", Panga: "pangasius", "Saumon fumé": "smoked_salmon", "Poisson séché": "dried_fish", // --- Boucherie & poissonnerie / Crustacés & fruits de mer ------------- Crevettes: "shrimp", Langoustines: "langoustine", Homard: "lobster", Crabe: "crab", Langouste: "spiny_lobster", Moules: "mussels", Huîtres: "oysters", "Saint-Jacques": "scallops", Calamar: "squid", Poulpe: "octopus", Palourdes: "clams", Bulots: "whelks", // --- Épicerie sèche / Féculents ---------------------------------------- Semoule: "semolina", Couscous: "couscous", Boulgour: "bulgur", Polenta: "polenta", Quinoa: "quinoa", Pâtes: "pasta", "Pâtes complètes": "whole_wheat_pasta", Riz: "rice", "Riz basmati": "basmati_rice", "Riz complet": "brown_rice", "Flocons d'avoine": "oats", Spaghetti: "spaghetti", Penne: "penne", Tagliatelles: "tagliatelle", "Lasagnes (feuilles)": "lasagna_sheets", Gnocchi: "gnocchi", "Riz arborio": "arborio_rice", "Nouilles de riz": "rice_noodles", "Nouilles udon": "udon_noodles", "Nouilles soba": "soba_noodles", "Nouilles chinoises": "chinese_noodles", "Vermicelles de riz": "rice_vermicelli", "Vermicelles de soja": "soy_vermicelli", "Riz gluant": "sticky_rice", "Riz à sushi": "sushi_rice", "Riz jasmin": "jasmine_rice", // --- Épicerie sèche / Légumineuses -------------------------------------- "Lentilles vertes": "green_lentils", "Lentilles corail": "red_lentils", "Pois chiches": "chickpeas", "Haricots blancs": "white_beans", "Haricots rouges": "kidney_beans", "Haricots noirs": "black_beans", "Pois cassés": "split_peas", Fèves: "fava_beans", Edamame: "edamame", "Haricots pinto": "pinto_beans", // --- Épicerie sèche / Graines & fruits secs ---------------------------- Cacahuètes: "peanuts_shelled", Amandes: "almonds", Noix: "walnuts", Noisettes: "hazelnuts", "Noix de cajou": "cashews", Pistaches: "pistachios", "Noix de pécan": "pecans", "Poudre d'amande": "almond_powder", "Pignons de pin": "pine_nuts", "Graines de tournesol": "sunflower_seeds", "Graines de courge": "pumpkin_seeds", "Noix de coco râpée": "shredded_coconut", "Raisins secs": "raisins", Pruneaux: "prunes", "Abricots secs": "dried_apricots", // --- Épicerie sèche / Autres -------------------------------------------- "Champignons noirs": "black_mushrooms", "Algue nori": "nori_seaweed", "Algue wakamé": "wakame_seaweed", "Algue kombu": "kombu_seaweed", "Pousses de bambou": "bamboo_shoots", "Châtaignes d'eau": "water_chestnuts", // --- Boulangerie / Pains ------------------------------------------------- Pain: "bread", "Pain de mie": "sandwich_bread", "Pain complet": "whole_wheat_bread", Baguette: "baguette", "Pain de seigle": "rye_bread", Chapelure: "breadcrumbs", "Pain à burger": "burger_bun", "Pain brioché": "brioche_bun", "Pain à hot-dog": "hot_dog_bun", "Pain pita": "pita_bread", "Pain bagel": "bagel", Naan: "naan", "Pain wrap": "wrap_bread", "Pain viennois": "viennese_bread", "Pain de campagne": "country_bread", "Pain aux céréales": "multigrain_bread", "Petit pain": "bread_roll", "Pain suédois": "swedish_bread", "Pain sans gluten": "gluten_free_bread", Biscotte: "rusk", Croûtons: "croutons", Focaccia: "focaccia", Ciabatta: "ciabatta", "Tortilla de maïs": "corn_tortilla", "Tortilla de blé": "wheat_tortilla", // --- Boulangerie / Pâtes à cuire ----------------------------------------- "Pâte feuilletée": "puff_pastry", "Pâte brisée": "shortcrust_pastry", "Pâte à pizza": "pizza_dough", "Pâte à tarte sablée": "sweet_shortcrust_pastry", // --- Crémerie & fromage / Produits laitiers ------------------------------ Lait: "milk", Beurre: "butter", "Crème fraîche": "creme_fraiche", "Crème liquide": "liquid_cream", Fromage: "cheese", Emmental: "emmental", Gruyère: "gruyere", Parmesan: "parmesan", Mozzarella: "mozzarella", "Chèvre (fromage)": "goat_cheese", Feta: "feta", Comté: "comte", "Fromage blanc": "fromage_blanc", Mascarpone: "mascarpone", Yaourt: "yogurt", Burrata: "burrata", Ricotta: "ricotta", Pecorino: "pecorino", Gorgonzola: "gorgonzola", Cheddar: "cheddar", // --- Crémerie & fromage / Œufs ------------------------------------------- Œuf: "egg", // --- Crémerie & fromage / Alternatives ------------------------------------ "Lait de coco": "coconut_milk", "Crème de coco": "coconut_cream", "Lait d'amande": "almond_milk", "Lait d'avoine": "oat_milk", Tofu: "tofu", "Tofu soyeux": "silken_tofu", // --- Condiments & épices / Épices ----------------------------------------- "Herbes de Provence": "herbes_de_provence", "Poivre noir": "black_pepper", Paprika: "paprika", "Piment d'Espelette": "espelette_pepper", "Piment de Cayenne": "cayenne_pepper", Cumin: "cumin", "Curry (poudre)": "curry_powder", Curcuma: "turmeric", Cannelle: "cinnamon", Muscade: "nutmeg", Safran: "saffron", "Clou de girofle": "clove", "Vanille (gousse)": "vanilla_bean", "Poivre blanc": "white_pepper", "Poivre rose": "pink_pepper", "Poivre du Sichuan": "sichuan_pepper", "Paprika fumé": "smoked_paprika", "Piment oiseau": "bird_eye_chili", "Baies de genièvre": "juniper_berries", "Anis étoilé (badiane)": "star_anise", "Anis vert": "green_anise", "Graines de fenouil": "fennel_seeds", Sumac: "sumac", Nigelle: "nigella", "Quatre épices": "allspice", "Colombo (poudre)": "colombo_powder", Baharat: "baharat", Raifort: "horseradish", "Sel aux herbes": "herb_salt", "Sel de céleri": "celery_salt", "Fleur de sel": "fleur_de_sel", Sel: "salt", "Cinq épices": "five_spice", "Garam masala": "garam_masala", "Graines de coriandre": "coriander_seeds", Cardamome: "cardamom", Fenugrec: "fenugreek", "Piment jalapeño": "jalapeno", "Piment chipotle": "chipotle", "Piment poblano": "poblano_pepper", "Piment habanero": "habanero", "Ras el hanout": "ras_el_hanout", "Za'atar": "zaatar", // --- Condiments & épices / Sauces ------------------------------------------- "Sauce soja": "soy_sauce", Moutarde: "mustard", Mayonnaise: "mayonnaise", Ketchup: "ketchup", Tabasco: "tabasco", "Sauce Worcestershire": "worcestershire_sauce", "Sauce nuoc-mâm": "fish_sauce", Wasabi: "wasabi", Harissa: "harissa", "Pâte de curry": "curry_paste", "Beurre de cacahuète": "peanut_butter", "Moutarde de Dijon": "dijon_mustard", "Moutarde à l'ancienne": "wholegrain_mustard", "Sauce barbecue": "barbecue_sauce", "Sauce tartare": "tartar_sauce", "Sauce cocktail": "cocktail_sauce", "Sauce béarnaise": "bearnaise_sauce", "Sauce hollandaise": "hollandaise_sauce", "Sauce béchamel": "bechamel_sauce", "Sauce teriyaki": "teriyaki_sauce", "Sauce ponzu": "ponzu_sauce", Chimichurri: "chimichurri", "Pesto rouge (tomates séchées)": "red_pesto", Pesto: "pesto", "Sauce huître": "oyster_sauce", "Sauce hoisin": "hoisin_sauce", "Sauce sriracha": "sriracha", "Sauce sweet chili": "sweet_chili_sauce", Miso: "miso", "Pâte de crevettes": "shrimp_paste", "Pâte de curry rouge (thaï)": "red_curry_paste", "Pâte de curry vert (thaï)": "green_curry_paste", Tahini: "tahini", // --- Condiments & épices / Assaisonnements ----------------------------------- "Huile d'olive": "olive_oil", "Huile de tournesol": "sunflower_oil", "Huile de colza": "rapeseed_oil", "Huile de coco": "coconut_oil", "Huile de sésame": "sesame_oil", "Vinaigre de cidre": "cider_vinegar", "Vinaigre blanc": "white_vinegar", "Vinaigre balsamique": "balsamic_vinegar", Câpres: "capers", Olives: "olives", "Vin blanc (cuisine)": "white_wine", "Vin rouge (cuisine)": "red_wine", "Vinaigre de vin rouge": "red_wine_vinegar", "Vinaigre de vin blanc": "white_wine_vinegar", "Vinaigre de xérès": "sherry_vinegar", "Huile de noix": "walnut_oil", "Huile de noisette": "hazelnut_oil", "Huile d'arachide": "peanut_oil", "Huile pimentée": "chili_oil", "Vinaigre de riz": "rice_vinegar", Mirin: "mirin", "Saké (cuisine)": "sake", "Jus de citron": "lemon_juice", "Jus de citron vert": "lime_juice", "Jus d'orange": "orange_juice", "Jus de pomme": "apple_juice", "Jus de raisin": "grape_juice", "Jus de tomate": "tomato_juice", "Jus de cranberry": "cranberry_juice", Café: "coffee", Thé: "tea", "Bière (cuisine)": "beer", "Cidre (cuisine)": "cider", "Champagne / vin pétillant (cuisine)": "champagne", "Porto (cuisine)": "port_wine", "Vin jaune (cuisine)": "vin_jaune", Cognac: "cognac", Rhum: "rum", Whisky: "whisky", Vodka: "vodka", // --- Aides culinaires / Bases ------------------------------------------- "Farine de blé": "wheat_flour", "Farine complète": "whole_wheat_flour", "Farine de maïs": "corn_flour", "Farine de sarrasin": "buckwheat_flour", "Farine de riz": "rice_flour", "Bouillon cube légumes": "vegetable_stock_cube", "Bouillon cube volaille": "chicken_stock_cube", "Concentré de tomate": "tomato_paste", "Coulis de tomate": "tomato_coulis", "Tomates pelées (conserve)": "canned_peeled_tomatoes", "Tomates séchées": "sun_dried_tomatoes", "Fond de veau": "veal_stock", "Fond de volaille": "chicken_stock", "Bouillon cube bœuf": "beef_stock_cube", "Bouillon cube poisson": "fish_stock_cube", "Bouillon de légumes": "vegetable_broth", "Bouillon de volaille": "chicken_broth", "Bouillon de bœuf": "beef_broth", "Court-bouillon": "court_bouillon", "Dashi (bouillon japonais)": "dashi", "Bisque de crustacés": "shellfish_bisque", "Farine de tapioca": "tapioca_flour", "Masa harina": "masa_harina", Eau: "water", "Eau gazeuse": "sparkling_water", "Eau de fleur d'oranger": "orange_blossom_water", "Eau de rose": "rose_water", "Fumet de poisson": "fish_fumet", // --- Aides culinaires / Épaississants ------------------------------------- "Levure boulangère": "bakers_yeast", "Levure chimique": "baking_powder", Maïzena: "cornstarch", "Farine de lupin": "lupin_flour", Gélatine: "gelatin", "Bicarbonate de soude": "baking_soda", "Fécule de pomme de terre": "potato_starch", // --- Aides culinaires / Sucres --------------------------------------------- Sucre: "sugar", Miel: "honey", "Sirop d'érable": "maple_syrup", "Sucre roux": "brown_sugar", "Sucre glace": "powdered_sugar", Cassonade: "demerara_sugar", "Chocolat noir": "dark_chocolate", "Chocolat au lait": "milk_chocolate", "Chocolat blanc": "white_chocolate", "Pépites de chocolat": "chocolate_chips", "Cacao en poudre": "cocoa_powder", "Extrait de vanille": "vanilla_extract", "Sucre de palme": "palm_sugar", "Sirop de sucre de canne": "cane_syrup", }; const ALL_KEYS: Record = { ...DIET_KEYS, ...ALLERGEN_KEYS, ...INGREDIENT_KEYS, }; /** * Resolves a seed-time French authoring label to its English `key` — * throws if it's missing an entry above rather than silently falling back * to a French slug, since a new diet/allergen/ingredient needs a * deliberately-chosen English key before it can seed at all. * `slugify` still runs over the result so a stray character/casing slip in * the table above can't produce a key that doesn't match the * `[a-z0-9_]`-only shape every other key has. */ export function getEnglishKey(frenchLabel: string): string { const english = ALL_KEYS[frenchLabel]; if (english === undefined) { throw new Error( `No English key registered for "${frenchLabel}" — add one to catalog-en-keys.ts`, ); } return slugify(english); }