fix(api): les uids du catalogue sont en anglais, pas des slugs français
reference-seed-data.ts reste rédigé en français (c'est juste le libellé
d'autoring, jamais stocké/exposé), mais la clé stable (`Diet.key`/
`Category.key`/`Ingredient.key`) qu'on en dérive doit elle-même être un
identifiant anglais, indépendant de la langue d'autoring — pas juste le
même texte français passé à slugify().
- apps/api/src/db/catalog-en-keys.ts : dictionnaire écrit à la main
(label français -> clé anglaise) pour les 5 régimes, 14 allergènes et
437 ingrédients ; getEnglishKey() lève une erreur explicite si un
nouvel élément n'a pas encore d'entrée plutôt que de retomber sur un
slug français silencieux.
- scripts/validate-catalog-en-keys.ts : vérifie que chaque diet/allergène/
ingrédient de reference-seed-data.ts a une entrée, et que les clés
anglaises résultantes sont uniques (437/437, 14/14, 5/5 — zéro manquant,
zéro collision).
- reference-seed-data.ts et scripts/generate-catalog-i18n.ts utilisent
désormais getEnglishKey() au lieu de slugify(nom français).
- Nouvelle migration (20260818193000_catalog_keys_to_english) qui
remappe les lignes déjà seedées avec un slug français (par la migration
précédente) vers leur clé anglaise définitive.
- apps/web/src/locales/fr/translation.json régénéré : catalog.* est
maintenant indexé par clé anglaise ("vegetarian", "eggs",
"ground_beef"...), toujours avec le libellé français en valeur.
- Tests/step-definitions mis à jour (getEnglishKey() au lieu de
slugify()) ; 102 tests Mocha + 32 scénarios Cucumber passent contre la
base migrée. Vérifié aussi en direct via GET /reference/diets et
/reference/allergies.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
parent
1d9bb6d112
commit
4b85531601
13 changed files with 1522 additions and 501 deletions
2
.gitignore
vendored
2
.gitignore
vendored
|
|
@ -150,5 +150,3 @@ tmp-mockups/
|
||||||
|
|
||||||
# IA
|
# IA
|
||||||
.claude/
|
.claude/
|
||||||
# Scratch output of apps/api/scripts/generate-catalog-i18n.ts — regenerate on demand.
|
|
||||||
apps/api/scripts/backfill.sql
|
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
import assert from "node:assert/strict";
|
import assert from "node:assert/strict";
|
||||||
import { Then, When } from "@cucumber/cucumber";
|
import { Then, When } from "@cucumber/cucumber";
|
||||||
import { prisma } from "../../src/db/prisma.js";
|
import { prisma } from "../../src/db/prisma.js";
|
||||||
import { slugify } from "../../src/utils/slugify.js";
|
import { getEnglishKey } from "../../src/db/catalog-en-keys.js";
|
||||||
import type { CustomWorld } from "../support/world.js";
|
import type { CustomWorld } from "../support/world.js";
|
||||||
|
|
||||||
/** Splits a comma-separated list of names from a `.feature` string into trimmed, non-empty parts. */
|
/** Splits a comma-separated list of names from a `.feature` string into trimmed, non-empty parts. */
|
||||||
|
|
@ -22,7 +22,7 @@ function splitNames(names: string): string[] {
|
||||||
async function allergyIdsFor(names: string[]): Promise<number[]> {
|
async function allergyIdsFor(names: string[]): Promise<number[]> {
|
||||||
const allergies = await prisma.allergy.findMany({ include: { category: true } });
|
const allergies = await prisma.allergy.findMany({ include: { category: true } });
|
||||||
return names.map((name) => {
|
return names.map((name) => {
|
||||||
const key = slugify(name);
|
const key = getEnglishKey(name);
|
||||||
const match = allergies.find((allergy) => allergy.category.key === key);
|
const match = allergies.find((allergy) => allergy.category.key === key);
|
||||||
if (!match) throw new Error(`No seeded allergen named "${name}"`);
|
if (!match) throw new Error(`No seeded allergen named "${name}"`);
|
||||||
return match.id;
|
return match.id;
|
||||||
|
|
@ -30,14 +30,14 @@ async function allergyIdsFor(names: string[]): Promise<number[]> {
|
||||||
}
|
}
|
||||||
|
|
||||||
When("I set my regime to {string}", async function (this: CustomWorld, dietName: string) {
|
When("I set my regime to {string}", async function (this: CustomWorld, dietName: string) {
|
||||||
const diet = await prisma.diet.findFirstOrThrow({ where: { key: slugify(dietName) } });
|
const diet = await prisma.diet.findFirstOrThrow({ where: { key: getEnglishKey(dietName) } });
|
||||||
this.response = await this.agent.patch("/profile/diet").send({ dietId: diet.id });
|
this.response = await this.agent.patch("/profile/diet").send({ dietId: diet.id });
|
||||||
});
|
});
|
||||||
|
|
||||||
Then(
|
Then(
|
||||||
"my profile's regime should be {string}",
|
"my profile's regime should be {string}",
|
||||||
async function (this: CustomWorld, dietName: string) {
|
async function (this: CustomWorld, dietName: string) {
|
||||||
const diet = await prisma.diet.findFirstOrThrow({ where: { key: slugify(dietName) } });
|
const diet = await prisma.diet.findFirstOrThrow({ where: { key: getEnglishKey(dietName) } });
|
||||||
assert.equal(this.response.body.dietId, diet.id);
|
assert.equal(this.response.body.dietId, diet.id);
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
import assert from "node:assert/strict";
|
import assert from "node:assert/strict";
|
||||||
import { Given, Then, When } from "@cucumber/cucumber";
|
import { Given, Then, When } from "@cucumber/cucumber";
|
||||||
import { prisma } from "../../src/db/prisma.js";
|
import { prisma } from "../../src/db/prisma.js";
|
||||||
import { slugify } from "../../src/utils/slugify.js";
|
import { getEnglishKey } from "../../src/db/catalog-en-keys.js";
|
||||||
import { TEST_REFERENCE_DATE } from "../../test-support/reference-date.js";
|
import { TEST_REFERENCE_DATE } from "../../test-support/reference-date.js";
|
||||||
import type { CustomWorld } from "../support/world.js";
|
import type { CustomWorld } from "../support/world.js";
|
||||||
|
|
||||||
|
|
@ -12,7 +12,7 @@ import type { CustomWorld } from "../support/world.js";
|
||||||
* matching.
|
* matching.
|
||||||
*/
|
*/
|
||||||
async function findIngredientId(name: string): Promise<number> {
|
async function findIngredientId(name: string): Promise<number> {
|
||||||
const ingredient = await prisma.ingredient.findFirstOrThrow({ where: { key: slugify(name) } });
|
const ingredient = await prisma.ingredient.findFirstOrThrow({ where: { key: getEnglishKey(name) } });
|
||||||
return ingredient.id;
|
return ingredient.id;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -64,7 +64,7 @@ Then(
|
||||||
ingredients: Array<{ ingredient: { key: string } }>;
|
ingredients: Array<{ ingredient: { key: string } }>;
|
||||||
steps: Array<{ description: string }>;
|
steps: Array<{ description: string }>;
|
||||||
};
|
};
|
||||||
const expectedKey = slugify(ingredientName);
|
const expectedKey = getEnglishKey(ingredientName);
|
||||||
assert.ok(body.ingredients.some((line) => line.ingredient.key === expectedKey));
|
assert.ok(body.ingredients.some((line) => line.ingredient.key === expectedKey));
|
||||||
assert.ok(body.steps.some((s) => s.description === step));
|
assert.ok(body.steps.some((s) => s.description === step));
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
import assert from "node:assert/strict";
|
import assert from "node:assert/strict";
|
||||||
import { Then } from "@cucumber/cucumber";
|
import { Then } from "@cucumber/cucumber";
|
||||||
import { slugify } from "../../src/utils/slugify.js";
|
import { getEnglishKey } from "../../src/db/catalog-en-keys.js";
|
||||||
import type { CustomWorld } from "../support/world.js";
|
import type { CustomWorld } from "../support/world.js";
|
||||||
|
|
||||||
// The feature file still names an item by its French label, for
|
// The feature file still names an item by its French label, for
|
||||||
|
|
@ -11,7 +11,7 @@ Then(
|
||||||
"the reference list response should include {string}",
|
"the reference list response should include {string}",
|
||||||
function (this: CustomWorld, name: string) {
|
function (this: CustomWorld, name: string) {
|
||||||
const keys = (this.response.body as Array<{ key: string }>).map((item) => item.key);
|
const keys = (this.response.body as Array<{ key: string }>).map((item) => item.key);
|
||||||
const expectedKey = slugify(name);
|
const expectedKey = getEnglishKey(name);
|
||||||
assert.ok(keys.includes(expectedKey), `expected ${JSON.stringify(keys)} to include "${expectedKey}"`);
|
assert.ok(keys.includes(expectedKey), `expected ${JSON.stringify(keys)} to include "${expectedKey}"`);
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,465 @@
|
||||||
|
-- Auto-generated once by scripts/gen-english-remap-sql.ts — do not re-run,
|
||||||
|
-- do not hand-edit. Remaps every Diet/Category(allergen)/Ingredient row's
|
||||||
|
-- "key" from the French slug the previous migration
|
||||||
|
-- (20260818_catalog_labels_to_keys) produced to the hand-assigned English
|
||||||
|
-- key in catalog-en-keys.ts.
|
||||||
|
|
||||||
|
UPDATE "diet" SET "key" = 'omnivore' WHERE "key" = 'omnivore';
|
||||||
|
UPDATE "diet" SET "key" = 'vegetarian' WHERE "key" = 'vegetarien';
|
||||||
|
UPDATE "diet" SET "key" = 'vegan' WHERE "key" = 'vegan';
|
||||||
|
UPDATE "diet" SET "key" = 'pescatarian' WHERE "key" = 'pescetarien';
|
||||||
|
UPDATE "diet" SET "key" = 'gluten_free' WHERE "key" = 'sans_gluten';
|
||||||
|
|
||||||
|
UPDATE "category" SET "key" = 'gluten' WHERE "key" = 'gluten';
|
||||||
|
UPDATE "category" SET "key" = 'crustaceans' WHERE "key" = 'crustaces';
|
||||||
|
UPDATE "category" SET "key" = 'eggs' WHERE "key" = 'oeufs';
|
||||||
|
UPDATE "category" SET "key" = 'fish' WHERE "key" = 'poissons';
|
||||||
|
UPDATE "category" SET "key" = 'peanuts' WHERE "key" = 'arachides';
|
||||||
|
UPDATE "category" SET "key" = 'soy' WHERE "key" = 'soja';
|
||||||
|
UPDATE "category" SET "key" = 'milk' WHERE "key" = 'lait';
|
||||||
|
UPDATE "category" SET "key" = 'tree_nuts' WHERE "key" = 'fruits_a_coque';
|
||||||
|
UPDATE "category" SET "key" = 'celery' WHERE "key" = 'celeri';
|
||||||
|
UPDATE "category" SET "key" = 'mustard' WHERE "key" = 'moutarde';
|
||||||
|
UPDATE "category" SET "key" = 'sesame_seeds' WHERE "key" = 'graines_de_sesame';
|
||||||
|
UPDATE "category" SET "key" = 'sulfites' WHERE "key" = 'sulfites';
|
||||||
|
UPDATE "category" SET "key" = 'lupin' WHERE "key" = 'lupin';
|
||||||
|
UPDATE "category" SET "key" = 'molluscs' WHERE "key" = 'mollusques';
|
||||||
|
|
||||||
|
UPDATE "ingredients" SET "key" = 'tomato' WHERE "key" = 'tomate';
|
||||||
|
UPDATE "ingredients" SET "key" = 'onion' WHERE "key" = 'oignon';
|
||||||
|
UPDATE "ingredients" SET "key" = 'shallot' WHERE "key" = 'echalote';
|
||||||
|
UPDATE "ingredients" SET "key" = 'garlic' WHERE "key" = 'ail';
|
||||||
|
UPDATE "ingredients" SET "key" = 'carrot' WHERE "key" = 'carotte';
|
||||||
|
UPDATE "ingredients" SET "key" = 'zucchini' WHERE "key" = 'courgette';
|
||||||
|
UPDATE "ingredients" SET "key" = 'cucumber' WHERE "key" = 'concombre';
|
||||||
|
UPDATE "ingredients" SET "key" = 'gherkins' WHERE "key" = 'cornichons';
|
||||||
|
UPDATE "ingredients" SET "key" = 'bell_pepper' WHERE "key" = 'poivron';
|
||||||
|
UPDATE "ingredients" SET "key" = 'mushroom' WHERE "key" = 'champignon';
|
||||||
|
UPDATE "ingredients" SET "key" = 'porcini' WHERE "key" = 'cepes';
|
||||||
|
UPDATE "ingredients" SET "key" = 'eggplant' WHERE "key" = 'aubergine';
|
||||||
|
UPDATE "ingredients" SET "key" = 'broccoli' WHERE "key" = 'brocoli';
|
||||||
|
UPDATE "ingredients" SET "key" = 'cauliflower' WHERE "key" = 'chou_fleur';
|
||||||
|
UPDATE "ingredients" SET "key" = 'white_cabbage' WHERE "key" = 'chou_blanc';
|
||||||
|
UPDATE "ingredients" SET "key" = 'red_cabbage' WHERE "key" = 'chou_rouge';
|
||||||
|
UPDATE "ingredients" SET "key" = 'brussels_sprouts' WHERE "key" = 'chou_de_bruxelles';
|
||||||
|
UPDATE "ingredients" SET "key" = 'spinach' WHERE "key" = 'epinard';
|
||||||
|
UPDATE "ingredients" SET "key" = 'swiss_chard' WHERE "key" = 'blette';
|
||||||
|
UPDATE "ingredients" SET "key" = 'lettuce' WHERE "key" = 'salade';
|
||||||
|
UPDATE "ingredients" SET "key" = 'arugula' WHERE "key" = 'roquette';
|
||||||
|
UPDATE "ingredients" SET "key" = 'watercress' WHERE "key" = 'cresson';
|
||||||
|
UPDATE "ingredients" SET "key" = 'leek' WHERE "key" = 'poireau';
|
||||||
|
UPDATE "ingredients" SET "key" = 'celery' WHERE "key" = 'celeri';
|
||||||
|
UPDATE "ingredients" SET "key" = 'radish' WHERE "key" = 'radis';
|
||||||
|
UPDATE "ingredients" SET "key" = 'beetroot' WHERE "key" = 'betterave';
|
||||||
|
UPDATE "ingredients" SET "key" = 'turnip' WHERE "key" = 'navet';
|
||||||
|
UPDATE "ingredients" SET "key" = 'parsnip' WHERE "key" = 'panais';
|
||||||
|
UPDATE "ingredients" SET "key" = 'green_bean' WHERE "key" = 'haricot_vert';
|
||||||
|
UPDATE "ingredients" SET "key" = 'pea' WHERE "key" = 'petit_pois';
|
||||||
|
UPDATE "ingredients" SET "key" = 'corn' WHERE "key" = 'mais';
|
||||||
|
UPDATE "ingredients" SET "key" = 'artichoke' WHERE "key" = 'artichaut';
|
||||||
|
UPDATE "ingredients" SET "key" = 'fennel' WHERE "key" = 'fenouil';
|
||||||
|
UPDATE "ingredients" SET "key" = 'endive' WHERE "key" = 'endive';
|
||||||
|
UPDATE "ingredients" SET "key" = 'pumpkin' WHERE "key" = 'potiron';
|
||||||
|
UPDATE "ingredients" SET "key" = 'butternut_squash' WHERE "key" = 'butternut';
|
||||||
|
UPDATE "ingredients" SET "key" = 'asparagus' WHERE "key" = 'asperge';
|
||||||
|
UPDATE "ingredients" SET "key" = 'avocado' WHERE "key" = 'avocat';
|
||||||
|
UPDATE "ingredients" SET "key" = 'potato' WHERE "key" = 'pomme_de_terre';
|
||||||
|
UPDATE "ingredients" SET "key" = 'sweet_potato' WHERE "key" = 'patate_douce';
|
||||||
|
UPDATE "ingredients" SET "key" = 'cherry_tomato' WHERE "key" = 'tomates_cerises';
|
||||||
|
UPDATE "ingredients" SET "key" = 'bok_choy' WHERE "key" = 'pak_choi';
|
||||||
|
UPDATE "ingredients" SET "key" = 'soybean_sprouts' WHERE "key" = 'germes_de_soja';
|
||||||
|
UPDATE "ingredients" SET "key" = 'shiitake' WHERE "key" = 'shiitake';
|
||||||
|
UPDATE "ingredients" SET "key" = 'daikon' WHERE "key" = 'daikon';
|
||||||
|
UPDATE "ingredients" SET "key" = 'fresh_green_chili' WHERE "key" = 'piment_vert_frais';
|
||||||
|
UPDATE "ingredients" SET "key" = 'lemon' WHERE "key" = 'citron';
|
||||||
|
UPDATE "ingredients" SET "key" = 'lime' WHERE "key" = 'citron_vert';
|
||||||
|
UPDATE "ingredients" SET "key" = 'apple' WHERE "key" = 'pomme';
|
||||||
|
UPDATE "ingredients" SET "key" = 'pear' WHERE "key" = 'poire';
|
||||||
|
UPDATE "ingredients" SET "key" = 'banana' WHERE "key" = 'banane';
|
||||||
|
UPDATE "ingredients" SET "key" = 'orange' WHERE "key" = 'orange';
|
||||||
|
UPDATE "ingredients" SET "key" = 'clementine' WHERE "key" = 'clementine';
|
||||||
|
UPDATE "ingredients" SET "key" = 'grapefruit' WHERE "key" = 'pamplemousse';
|
||||||
|
UPDATE "ingredients" SET "key" = 'strawberry' WHERE "key" = 'fraise';
|
||||||
|
UPDATE "ingredients" SET "key" = 'raspberry' WHERE "key" = 'framboise';
|
||||||
|
UPDATE "ingredients" SET "key" = 'blueberry' WHERE "key" = 'myrtille';
|
||||||
|
UPDATE "ingredients" SET "key" = 'blackberry' WHERE "key" = 'mure';
|
||||||
|
UPDATE "ingredients" SET "key" = 'cherry' WHERE "key" = 'cerise';
|
||||||
|
UPDATE "ingredients" SET "key" = 'apricot' WHERE "key" = 'abricot';
|
||||||
|
UPDATE "ingredients" SET "key" = 'peach' WHERE "key" = 'peche';
|
||||||
|
UPDATE "ingredients" SET "key" = 'plum' WHERE "key" = 'prune';
|
||||||
|
UPDATE "ingredients" SET "key" = 'grape' WHERE "key" = 'raisin';
|
||||||
|
UPDATE "ingredients" SET "key" = 'melon' WHERE "key" = 'melon';
|
||||||
|
UPDATE "ingredients" SET "key" = 'watermelon' WHERE "key" = 'pasteque';
|
||||||
|
UPDATE "ingredients" SET "key" = 'pineapple' WHERE "key" = 'ananas';
|
||||||
|
UPDATE "ingredients" SET "key" = 'mango' WHERE "key" = 'mangue';
|
||||||
|
UPDATE "ingredients" SET "key" = 'kiwi' WHERE "key" = 'kiwi';
|
||||||
|
UPDATE "ingredients" SET "key" = 'fig' WHERE "key" = 'figue';
|
||||||
|
UPDATE "ingredients" SET "key" = 'date' WHERE "key" = 'datte';
|
||||||
|
UPDATE "ingredients" SET "key" = 'lychee' WHERE "key" = 'litchi';
|
||||||
|
UPDATE "ingredients" SET "key" = 'pomegranate' WHERE "key" = 'grenade';
|
||||||
|
UPDATE "ingredients" SET "key" = 'rhubarb' WHERE "key" = 'rhubarbe';
|
||||||
|
UPDATE "ingredients" SET "key" = 'quince' WHERE "key" = 'coing';
|
||||||
|
UPDATE "ingredients" SET "key" = 'basil' WHERE "key" = 'basilic';
|
||||||
|
UPDATE "ingredients" SET "key" = 'parsley' WHERE "key" = 'persil';
|
||||||
|
UPDATE "ingredients" SET "key" = 'thyme' WHERE "key" = 'thym';
|
||||||
|
UPDATE "ingredients" SET "key" = 'rosemary' WHERE "key" = 'romarin';
|
||||||
|
UPDATE "ingredients" SET "key" = 'bay_leaf' WHERE "key" = 'laurier';
|
||||||
|
UPDATE "ingredients" SET "key" = 'chives' WHERE "key" = 'ciboulette';
|
||||||
|
UPDATE "ingredients" SET "key" = 'fresh_cilantro' WHERE "key" = 'coriandre_fraiche';
|
||||||
|
UPDATE "ingredients" SET "key" = 'mint' WHERE "key" = 'menthe';
|
||||||
|
UPDATE "ingredients" SET "key" = 'oregano' WHERE "key" = 'origan';
|
||||||
|
UPDATE "ingredients" SET "key" = 'dill' WHERE "key" = 'aneth';
|
||||||
|
UPDATE "ingredients" SET "key" = 'tarragon' WHERE "key" = 'estragon';
|
||||||
|
UPDATE "ingredients" SET "key" = 'savory' WHERE "key" = 'sarriette';
|
||||||
|
UPDATE "ingredients" SET "key" = 'marjoram' WHERE "key" = 'marjolaine';
|
||||||
|
UPDATE "ingredients" SET "key" = 'sage' WHERE "key" = 'sauge';
|
||||||
|
UPDATE "ingredients" SET "key" = 'chervil' WHERE "key" = 'cerfeuil';
|
||||||
|
UPDATE "ingredients" SET "key" = 'ginger' WHERE "key" = 'gingembre';
|
||||||
|
UPDATE "ingredients" SET "key" = 'lemongrass' WHERE "key" = 'citronnelle';
|
||||||
|
UPDATE "ingredients" SET "key" = 'kaffir_lime' WHERE "key" = 'combava';
|
||||||
|
UPDATE "ingredients" SET "key" = 'rabbit' WHERE "key" = 'lapin';
|
||||||
|
UPDATE "ingredients" SET "key" = 'ground_beef' WHERE "key" = 'boeuf_hache';
|
||||||
|
UPDATE "ingredients" SET "key" = 'beef_steak' WHERE "key" = 'steak_de_boeuf';
|
||||||
|
UPDATE "ingredients" SET "key" = 'beef_roast' WHERE "key" = 'roti_de_boeuf';
|
||||||
|
UPDATE "ingredients" SET "key" = 'veal_cutlet' WHERE "key" = 'escalope_de_veau';
|
||||||
|
UPDATE "ingredients" SET "key" = 'pork_tenderloin' WHERE "key" = 'filet_mignon_de_porc';
|
||||||
|
UPDATE "ingredients" SET "key" = 'pork_chop' WHERE "key" = 'cote_de_porc';
|
||||||
|
UPDATE "ingredients" SET "key" = 'lamb' WHERE "key" = 'agneau';
|
||||||
|
UPDATE "ingredients" SET "key" = 'leg_of_lamb' WHERE "key" = 'gigot_d_agneau';
|
||||||
|
UPDATE "ingredients" SET "key" = 'bacon_lardons' WHERE "key" = 'lardons';
|
||||||
|
UPDATE "ingredients" SET "key" = 'bacon' WHERE "key" = 'bacon';
|
||||||
|
UPDATE "ingredients" SET "key" = 'ham' WHERE "key" = 'jambon_blanc';
|
||||||
|
UPDATE "ingredients" SET "key" = 'cured_ham' WHERE "key" = 'jambon_cru';
|
||||||
|
UPDATE "ingredients" SET "key" = 'sausage' WHERE "key" = 'saucisse';
|
||||||
|
UPDATE "ingredients" SET "key" = 'chorizo' WHERE "key" = 'chorizo';
|
||||||
|
UPDATE "ingredients" SET "key" = 'merguez' WHERE "key" = 'merguez';
|
||||||
|
UPDATE "ingredients" SET "key" = 'prosciutto' WHERE "key" = 'prosciutto';
|
||||||
|
UPDATE "ingredients" SET "key" = 'pancetta' WHERE "key" = 'pancetta';
|
||||||
|
UPDATE "ingredients" SET "key" = 'mortadella' WHERE "key" = 'mortadelle';
|
||||||
|
UPDATE "ingredients" SET "key" = 'salami' WHERE "key" = 'salami';
|
||||||
|
UPDATE "ingredients" SET "key" = 'chicken' WHERE "key" = 'poulet';
|
||||||
|
UPDATE "ingredients" SET "key" = 'turkey' WHERE "key" = 'dinde';
|
||||||
|
UPDATE "ingredients" SET "key" = 'duck' WHERE "key" = 'canard';
|
||||||
|
UPDATE "ingredients" SET "key" = 'duck_breast' WHERE "key" = 'magret_de_canard';
|
||||||
|
UPDATE "ingredients" SET "key" = 'salmon' WHERE "key" = 'saumon';
|
||||||
|
UPDATE "ingredients" SET "key" = 'tuna' WHERE "key" = 'thon';
|
||||||
|
UPDATE "ingredients" SET "key" = 'cod' WHERE "key" = 'cabillaud';
|
||||||
|
UPDATE "ingredients" SET "key" = 'trout' WHERE "key" = 'truite';
|
||||||
|
UPDATE "ingredients" SET "key" = 'sardine' WHERE "key" = 'sardine';
|
||||||
|
UPDATE "ingredients" SET "key" = 'anchovy' WHERE "key" = 'anchois';
|
||||||
|
UPDATE "ingredients" SET "key" = 'whiting' WHERE "key" = 'merlan';
|
||||||
|
UPDATE "ingredients" SET "key" = 'surimi' WHERE "key" = 'surimi';
|
||||||
|
UPDATE "ingredients" SET "key" = 'sea_bass' WHERE "key" = 'bar_loup_de_mer';
|
||||||
|
UPDATE "ingredients" SET "key" = 'sea_bream' WHERE "key" = 'dorade';
|
||||||
|
UPDATE "ingredients" SET "key" = 'sole' WHERE "key" = 'sole';
|
||||||
|
UPDATE "ingredients" SET "key" = 'turbot' WHERE "key" = 'turbot';
|
||||||
|
UPDATE "ingredients" SET "key" = 'hake' WHERE "key" = 'merlu';
|
||||||
|
UPDATE "ingredients" SET "key" = 'pollock' WHERE "key" = 'colin';
|
||||||
|
UPDATE "ingredients" SET "key" = 'saithe' WHERE "key" = 'lieu_noir';
|
||||||
|
UPDATE "ingredients" SET "key" = 'haddock' WHERE "key" = 'eglefin';
|
||||||
|
UPDATE "ingredients" SET "key" = 'mackerel' WHERE "key" = 'maquereau';
|
||||||
|
UPDATE "ingredients" SET "key" = 'herring' WHERE "key" = 'hareng';
|
||||||
|
UPDATE "ingredients" SET "key" = 'red_mullet' WHERE "key" = 'rouget';
|
||||||
|
UPDATE "ingredients" SET "key" = 'skate' WHERE "key" = 'raie';
|
||||||
|
UPDATE "ingredients" SET "key" = 'monkfish' WHERE "key" = 'lotte';
|
||||||
|
UPDATE "ingredients" SET "key" = 'halibut' WHERE "key" = 'fletan';
|
||||||
|
UPDATE "ingredients" SET "key" = 'swordfish' WHERE "key" = 'espadon';
|
||||||
|
UPDATE "ingredients" SET "key" = 'carp' WHERE "key" = 'carpe';
|
||||||
|
UPDATE "ingredients" SET "key" = 'pike' WHERE "key" = 'brochet';
|
||||||
|
UPDATE "ingredients" SET "key" = 'perch' WHERE "key" = 'perche';
|
||||||
|
UPDATE "ingredients" SET "key" = 'tilapia' WHERE "key" = 'tilapia';
|
||||||
|
UPDATE "ingredients" SET "key" = 'pangasius' WHERE "key" = 'panga';
|
||||||
|
UPDATE "ingredients" SET "key" = 'smoked_salmon' WHERE "key" = 'saumon_fume';
|
||||||
|
UPDATE "ingredients" SET "key" = 'dried_fish' WHERE "key" = 'poisson_seche';
|
||||||
|
UPDATE "ingredients" SET "key" = 'shrimp' WHERE "key" = 'crevettes';
|
||||||
|
UPDATE "ingredients" SET "key" = 'langoustine' WHERE "key" = 'langoustines';
|
||||||
|
UPDATE "ingredients" SET "key" = 'lobster' WHERE "key" = 'homard';
|
||||||
|
UPDATE "ingredients" SET "key" = 'crab' WHERE "key" = 'crabe';
|
||||||
|
UPDATE "ingredients" SET "key" = 'spiny_lobster' WHERE "key" = 'langouste';
|
||||||
|
UPDATE "ingredients" SET "key" = 'mussels' WHERE "key" = 'moules';
|
||||||
|
UPDATE "ingredients" SET "key" = 'oysters' WHERE "key" = 'huitres';
|
||||||
|
UPDATE "ingredients" SET "key" = 'scallops' WHERE "key" = 'saint_jacques';
|
||||||
|
UPDATE "ingredients" SET "key" = 'squid' WHERE "key" = 'calamar';
|
||||||
|
UPDATE "ingredients" SET "key" = 'octopus' WHERE "key" = 'poulpe';
|
||||||
|
UPDATE "ingredients" SET "key" = 'clams' WHERE "key" = 'palourdes';
|
||||||
|
UPDATE "ingredients" SET "key" = 'whelks' WHERE "key" = 'bulots';
|
||||||
|
UPDATE "ingredients" SET "key" = 'semolina' WHERE "key" = 'semoule';
|
||||||
|
UPDATE "ingredients" SET "key" = 'couscous' WHERE "key" = 'couscous';
|
||||||
|
UPDATE "ingredients" SET "key" = 'bulgur' WHERE "key" = 'boulgour';
|
||||||
|
UPDATE "ingredients" SET "key" = 'polenta' WHERE "key" = 'polenta';
|
||||||
|
UPDATE "ingredients" SET "key" = 'quinoa' WHERE "key" = 'quinoa';
|
||||||
|
UPDATE "ingredients" SET "key" = 'pasta' WHERE "key" = 'pates';
|
||||||
|
UPDATE "ingredients" SET "key" = 'whole_wheat_pasta' WHERE "key" = 'pates_completes';
|
||||||
|
UPDATE "ingredients" SET "key" = 'rice' WHERE "key" = 'riz';
|
||||||
|
UPDATE "ingredients" SET "key" = 'basmati_rice' WHERE "key" = 'riz_basmati';
|
||||||
|
UPDATE "ingredients" SET "key" = 'brown_rice' WHERE "key" = 'riz_complet';
|
||||||
|
UPDATE "ingredients" SET "key" = 'oats' WHERE "key" = 'flocons_d_avoine';
|
||||||
|
UPDATE "ingredients" SET "key" = 'spaghetti' WHERE "key" = 'spaghetti';
|
||||||
|
UPDATE "ingredients" SET "key" = 'penne' WHERE "key" = 'penne';
|
||||||
|
UPDATE "ingredients" SET "key" = 'tagliatelle' WHERE "key" = 'tagliatelles';
|
||||||
|
UPDATE "ingredients" SET "key" = 'lasagna_sheets' WHERE "key" = 'lasagnes_feuilles';
|
||||||
|
UPDATE "ingredients" SET "key" = 'gnocchi' WHERE "key" = 'gnocchi';
|
||||||
|
UPDATE "ingredients" SET "key" = 'arborio_rice' WHERE "key" = 'riz_arborio';
|
||||||
|
UPDATE "ingredients" SET "key" = 'rice_noodles' WHERE "key" = 'nouilles_de_riz';
|
||||||
|
UPDATE "ingredients" SET "key" = 'udon_noodles' WHERE "key" = 'nouilles_udon';
|
||||||
|
UPDATE "ingredients" SET "key" = 'soba_noodles' WHERE "key" = 'nouilles_soba';
|
||||||
|
UPDATE "ingredients" SET "key" = 'chinese_noodles' WHERE "key" = 'nouilles_chinoises';
|
||||||
|
UPDATE "ingredients" SET "key" = 'rice_vermicelli' WHERE "key" = 'vermicelles_de_riz';
|
||||||
|
UPDATE "ingredients" SET "key" = 'soy_vermicelli' WHERE "key" = 'vermicelles_de_soja';
|
||||||
|
UPDATE "ingredients" SET "key" = 'sticky_rice' WHERE "key" = 'riz_gluant';
|
||||||
|
UPDATE "ingredients" SET "key" = 'sushi_rice' WHERE "key" = 'riz_a_sushi';
|
||||||
|
UPDATE "ingredients" SET "key" = 'jasmine_rice' WHERE "key" = 'riz_jasmin';
|
||||||
|
UPDATE "ingredients" SET "key" = 'green_lentils' WHERE "key" = 'lentilles_vertes';
|
||||||
|
UPDATE "ingredients" SET "key" = 'red_lentils' WHERE "key" = 'lentilles_corail';
|
||||||
|
UPDATE "ingredients" SET "key" = 'chickpeas' WHERE "key" = 'pois_chiches';
|
||||||
|
UPDATE "ingredients" SET "key" = 'white_beans' WHERE "key" = 'haricots_blancs';
|
||||||
|
UPDATE "ingredients" SET "key" = 'kidney_beans' WHERE "key" = 'haricots_rouges';
|
||||||
|
UPDATE "ingredients" SET "key" = 'black_beans' WHERE "key" = 'haricots_noirs';
|
||||||
|
UPDATE "ingredients" SET "key" = 'split_peas' WHERE "key" = 'pois_casses';
|
||||||
|
UPDATE "ingredients" SET "key" = 'fava_beans' WHERE "key" = 'feves';
|
||||||
|
UPDATE "ingredients" SET "key" = 'edamame' WHERE "key" = 'edamame';
|
||||||
|
UPDATE "ingredients" SET "key" = 'pinto_beans' WHERE "key" = 'haricots_pinto';
|
||||||
|
UPDATE "ingredients" SET "key" = 'peanuts_shelled' WHERE "key" = 'cacahuetes';
|
||||||
|
UPDATE "ingredients" SET "key" = 'almonds' WHERE "key" = 'amandes';
|
||||||
|
UPDATE "ingredients" SET "key" = 'walnuts' WHERE "key" = 'noix';
|
||||||
|
UPDATE "ingredients" SET "key" = 'hazelnuts' WHERE "key" = 'noisettes';
|
||||||
|
UPDATE "ingredients" SET "key" = 'cashews' WHERE "key" = 'noix_de_cajou';
|
||||||
|
UPDATE "ingredients" SET "key" = 'pistachios' WHERE "key" = 'pistaches';
|
||||||
|
UPDATE "ingredients" SET "key" = 'pecans' WHERE "key" = 'noix_de_pecan';
|
||||||
|
UPDATE "ingredients" SET "key" = 'almond_powder' WHERE "key" = 'poudre_d_amande';
|
||||||
|
UPDATE "ingredients" SET "key" = 'pine_nuts' WHERE "key" = 'pignons_de_pin';
|
||||||
|
UPDATE "ingredients" SET "key" = 'sunflower_seeds' WHERE "key" = 'graines_de_tournesol';
|
||||||
|
UPDATE "ingredients" SET "key" = 'pumpkin_seeds' WHERE "key" = 'graines_de_courge';
|
||||||
|
UPDATE "ingredients" SET "key" = 'shredded_coconut' WHERE "key" = 'noix_de_coco_rapee';
|
||||||
|
UPDATE "ingredients" SET "key" = 'raisins' WHERE "key" = 'raisins_secs';
|
||||||
|
UPDATE "ingredients" SET "key" = 'prunes' WHERE "key" = 'pruneaux';
|
||||||
|
UPDATE "ingredients" SET "key" = 'dried_apricots' WHERE "key" = 'abricots_secs';
|
||||||
|
UPDATE "ingredients" SET "key" = 'sesame_seeds' WHERE "key" = 'graines_de_sesame';
|
||||||
|
UPDATE "ingredients" SET "key" = 'black_mushrooms' WHERE "key" = 'champignons_noirs';
|
||||||
|
UPDATE "ingredients" SET "key" = 'nori_seaweed' WHERE "key" = 'algue_nori';
|
||||||
|
UPDATE "ingredients" SET "key" = 'wakame_seaweed' WHERE "key" = 'algue_wakame';
|
||||||
|
UPDATE "ingredients" SET "key" = 'kombu_seaweed' WHERE "key" = 'algue_kombu';
|
||||||
|
UPDATE "ingredients" SET "key" = 'bamboo_shoots' WHERE "key" = 'pousses_de_bambou';
|
||||||
|
UPDATE "ingredients" SET "key" = 'water_chestnuts' WHERE "key" = 'chataignes_d_eau';
|
||||||
|
UPDATE "ingredients" SET "key" = 'bread' WHERE "key" = 'pain';
|
||||||
|
UPDATE "ingredients" SET "key" = 'sandwich_bread' WHERE "key" = 'pain_de_mie';
|
||||||
|
UPDATE "ingredients" SET "key" = 'whole_wheat_bread' WHERE "key" = 'pain_complet';
|
||||||
|
UPDATE "ingredients" SET "key" = 'baguette' WHERE "key" = 'baguette';
|
||||||
|
UPDATE "ingredients" SET "key" = 'rye_bread' WHERE "key" = 'pain_de_seigle';
|
||||||
|
UPDATE "ingredients" SET "key" = 'breadcrumbs' WHERE "key" = 'chapelure';
|
||||||
|
UPDATE "ingredients" SET "key" = 'burger_bun' WHERE "key" = 'pain_a_burger';
|
||||||
|
UPDATE "ingredients" SET "key" = 'brioche_bun' WHERE "key" = 'pain_brioche';
|
||||||
|
UPDATE "ingredients" SET "key" = 'hot_dog_bun' WHERE "key" = 'pain_a_hot_dog';
|
||||||
|
UPDATE "ingredients" SET "key" = 'pita_bread' WHERE "key" = 'pain_pita';
|
||||||
|
UPDATE "ingredients" SET "key" = 'bagel' WHERE "key" = 'pain_bagel';
|
||||||
|
UPDATE "ingredients" SET "key" = 'naan' WHERE "key" = 'naan';
|
||||||
|
UPDATE "ingredients" SET "key" = 'wrap_bread' WHERE "key" = 'pain_wrap';
|
||||||
|
UPDATE "ingredients" SET "key" = 'viennese_bread' WHERE "key" = 'pain_viennois';
|
||||||
|
UPDATE "ingredients" SET "key" = 'country_bread' WHERE "key" = 'pain_de_campagne';
|
||||||
|
UPDATE "ingredients" SET "key" = 'multigrain_bread' WHERE "key" = 'pain_aux_cereales';
|
||||||
|
UPDATE "ingredients" SET "key" = 'bread_roll' WHERE "key" = 'petit_pain';
|
||||||
|
UPDATE "ingredients" SET "key" = 'swedish_bread' WHERE "key" = 'pain_suedois';
|
||||||
|
UPDATE "ingredients" SET "key" = 'gluten_free_bread' WHERE "key" = 'pain_sans_gluten';
|
||||||
|
UPDATE "ingredients" SET "key" = 'rusk' WHERE "key" = 'biscotte';
|
||||||
|
UPDATE "ingredients" SET "key" = 'croutons' WHERE "key" = 'croutons';
|
||||||
|
UPDATE "ingredients" SET "key" = 'focaccia' WHERE "key" = 'focaccia';
|
||||||
|
UPDATE "ingredients" SET "key" = 'ciabatta' WHERE "key" = 'ciabatta';
|
||||||
|
UPDATE "ingredients" SET "key" = 'corn_tortilla' WHERE "key" = 'tortilla_de_mais';
|
||||||
|
UPDATE "ingredients" SET "key" = 'wheat_tortilla' WHERE "key" = 'tortilla_de_ble';
|
||||||
|
UPDATE "ingredients" SET "key" = 'puff_pastry' WHERE "key" = 'pate_feuilletee';
|
||||||
|
UPDATE "ingredients" SET "key" = 'shortcrust_pastry' WHERE "key" = 'pate_brisee';
|
||||||
|
UPDATE "ingredients" SET "key" = 'pizza_dough' WHERE "key" = 'pate_a_pizza';
|
||||||
|
UPDATE "ingredients" SET "key" = 'sweet_shortcrust_pastry' WHERE "key" = 'pate_a_tarte_sablee';
|
||||||
|
UPDATE "ingredients" SET "key" = 'milk' WHERE "key" = 'lait';
|
||||||
|
UPDATE "ingredients" SET "key" = 'butter' WHERE "key" = 'beurre';
|
||||||
|
UPDATE "ingredients" SET "key" = 'creme_fraiche' WHERE "key" = 'creme_fraiche';
|
||||||
|
UPDATE "ingredients" SET "key" = 'liquid_cream' WHERE "key" = 'creme_liquide';
|
||||||
|
UPDATE "ingredients" SET "key" = 'cheese' WHERE "key" = 'fromage';
|
||||||
|
UPDATE "ingredients" SET "key" = 'emmental' WHERE "key" = 'emmental';
|
||||||
|
UPDATE "ingredients" SET "key" = 'gruyere' WHERE "key" = 'gruyere';
|
||||||
|
UPDATE "ingredients" SET "key" = 'parmesan' WHERE "key" = 'parmesan';
|
||||||
|
UPDATE "ingredients" SET "key" = 'mozzarella' WHERE "key" = 'mozzarella';
|
||||||
|
UPDATE "ingredients" SET "key" = 'goat_cheese' WHERE "key" = 'chevre_fromage';
|
||||||
|
UPDATE "ingredients" SET "key" = 'feta' WHERE "key" = 'feta';
|
||||||
|
UPDATE "ingredients" SET "key" = 'comte' WHERE "key" = 'comte';
|
||||||
|
UPDATE "ingredients" SET "key" = 'fromage_blanc' WHERE "key" = 'fromage_blanc';
|
||||||
|
UPDATE "ingredients" SET "key" = 'mascarpone' WHERE "key" = 'mascarpone';
|
||||||
|
UPDATE "ingredients" SET "key" = 'yogurt' WHERE "key" = 'yaourt';
|
||||||
|
UPDATE "ingredients" SET "key" = 'burrata' WHERE "key" = 'burrata';
|
||||||
|
UPDATE "ingredients" SET "key" = 'ricotta' WHERE "key" = 'ricotta';
|
||||||
|
UPDATE "ingredients" SET "key" = 'pecorino' WHERE "key" = 'pecorino';
|
||||||
|
UPDATE "ingredients" SET "key" = 'gorgonzola' WHERE "key" = 'gorgonzola';
|
||||||
|
UPDATE "ingredients" SET "key" = 'cheddar' WHERE "key" = 'cheddar';
|
||||||
|
UPDATE "ingredients" SET "key" = 'egg' WHERE "key" = 'oeuf';
|
||||||
|
UPDATE "ingredients" SET "key" = 'coconut_milk' WHERE "key" = 'lait_de_coco';
|
||||||
|
UPDATE "ingredients" SET "key" = 'coconut_cream' WHERE "key" = 'creme_de_coco';
|
||||||
|
UPDATE "ingredients" SET "key" = 'almond_milk' WHERE "key" = 'lait_d_amande';
|
||||||
|
UPDATE "ingredients" SET "key" = 'oat_milk' WHERE "key" = 'lait_d_avoine';
|
||||||
|
UPDATE "ingredients" SET "key" = 'tofu' WHERE "key" = 'tofu';
|
||||||
|
UPDATE "ingredients" SET "key" = 'silken_tofu' WHERE "key" = 'tofu_soyeux';
|
||||||
|
UPDATE "ingredients" SET "key" = 'herbes_de_provence' WHERE "key" = 'herbes_de_provence';
|
||||||
|
UPDATE "ingredients" SET "key" = 'black_pepper' WHERE "key" = 'poivre_noir';
|
||||||
|
UPDATE "ingredients" SET "key" = 'paprika' WHERE "key" = 'paprika';
|
||||||
|
UPDATE "ingredients" SET "key" = 'espelette_pepper' WHERE "key" = 'piment_d_espelette';
|
||||||
|
UPDATE "ingredients" SET "key" = 'cayenne_pepper' WHERE "key" = 'piment_de_cayenne';
|
||||||
|
UPDATE "ingredients" SET "key" = 'cumin' WHERE "key" = 'cumin';
|
||||||
|
UPDATE "ingredients" SET "key" = 'curry_powder' WHERE "key" = 'curry_poudre';
|
||||||
|
UPDATE "ingredients" SET "key" = 'turmeric' WHERE "key" = 'curcuma';
|
||||||
|
UPDATE "ingredients" SET "key" = 'cinnamon' WHERE "key" = 'cannelle';
|
||||||
|
UPDATE "ingredients" SET "key" = 'nutmeg' WHERE "key" = 'muscade';
|
||||||
|
UPDATE "ingredients" SET "key" = 'saffron' WHERE "key" = 'safran';
|
||||||
|
UPDATE "ingredients" SET "key" = 'clove' WHERE "key" = 'clou_de_girofle';
|
||||||
|
UPDATE "ingredients" SET "key" = 'vanilla_bean' WHERE "key" = 'vanille_gousse';
|
||||||
|
UPDATE "ingredients" SET "key" = 'white_pepper' WHERE "key" = 'poivre_blanc';
|
||||||
|
UPDATE "ingredients" SET "key" = 'pink_pepper' WHERE "key" = 'poivre_rose';
|
||||||
|
UPDATE "ingredients" SET "key" = 'sichuan_pepper' WHERE "key" = 'poivre_du_sichuan';
|
||||||
|
UPDATE "ingredients" SET "key" = 'smoked_paprika' WHERE "key" = 'paprika_fume';
|
||||||
|
UPDATE "ingredients" SET "key" = 'bird_eye_chili' WHERE "key" = 'piment_oiseau';
|
||||||
|
UPDATE "ingredients" SET "key" = 'juniper_berries' WHERE "key" = 'baies_de_genievre';
|
||||||
|
UPDATE "ingredients" SET "key" = 'star_anise' WHERE "key" = 'anis_etoile_badiane';
|
||||||
|
UPDATE "ingredients" SET "key" = 'green_anise' WHERE "key" = 'anis_vert';
|
||||||
|
UPDATE "ingredients" SET "key" = 'fennel_seeds' WHERE "key" = 'graines_de_fenouil';
|
||||||
|
UPDATE "ingredients" SET "key" = 'sumac' WHERE "key" = 'sumac';
|
||||||
|
UPDATE "ingredients" SET "key" = 'nigella' WHERE "key" = 'nigelle';
|
||||||
|
UPDATE "ingredients" SET "key" = 'allspice' WHERE "key" = 'quatre_epices';
|
||||||
|
UPDATE "ingredients" SET "key" = 'colombo_powder' WHERE "key" = 'colombo_poudre';
|
||||||
|
UPDATE "ingredients" SET "key" = 'baharat' WHERE "key" = 'baharat';
|
||||||
|
UPDATE "ingredients" SET "key" = 'horseradish' WHERE "key" = 'raifort';
|
||||||
|
UPDATE "ingredients" SET "key" = 'herb_salt' WHERE "key" = 'sel_aux_herbes';
|
||||||
|
UPDATE "ingredients" SET "key" = 'celery_salt' WHERE "key" = 'sel_de_celeri';
|
||||||
|
UPDATE "ingredients" SET "key" = 'fleur_de_sel' WHERE "key" = 'fleur_de_sel';
|
||||||
|
UPDATE "ingredients" SET "key" = 'salt' WHERE "key" = 'sel';
|
||||||
|
UPDATE "ingredients" SET "key" = 'five_spice' WHERE "key" = 'cinq_epices';
|
||||||
|
UPDATE "ingredients" SET "key" = 'garam_masala' WHERE "key" = 'garam_masala';
|
||||||
|
UPDATE "ingredients" SET "key" = 'coriander_seeds' WHERE "key" = 'graines_de_coriandre';
|
||||||
|
UPDATE "ingredients" SET "key" = 'cardamom' WHERE "key" = 'cardamome';
|
||||||
|
UPDATE "ingredients" SET "key" = 'fenugreek' WHERE "key" = 'fenugrec';
|
||||||
|
UPDATE "ingredients" SET "key" = 'jalapeno' WHERE "key" = 'piment_jalapeno';
|
||||||
|
UPDATE "ingredients" SET "key" = 'chipotle' WHERE "key" = 'piment_chipotle';
|
||||||
|
UPDATE "ingredients" SET "key" = 'poblano_pepper' WHERE "key" = 'piment_poblano';
|
||||||
|
UPDATE "ingredients" SET "key" = 'habanero' WHERE "key" = 'piment_habanero';
|
||||||
|
UPDATE "ingredients" SET "key" = 'ras_el_hanout' WHERE "key" = 'ras_el_hanout';
|
||||||
|
UPDATE "ingredients" SET "key" = 'zaatar' WHERE "key" = 'za_atar';
|
||||||
|
UPDATE "ingredients" SET "key" = 'soy_sauce' WHERE "key" = 'sauce_soja';
|
||||||
|
UPDATE "ingredients" SET "key" = 'mustard' WHERE "key" = 'moutarde';
|
||||||
|
UPDATE "ingredients" SET "key" = 'mayonnaise' WHERE "key" = 'mayonnaise';
|
||||||
|
UPDATE "ingredients" SET "key" = 'ketchup' WHERE "key" = 'ketchup';
|
||||||
|
UPDATE "ingredients" SET "key" = 'tabasco' WHERE "key" = 'tabasco';
|
||||||
|
UPDATE "ingredients" SET "key" = 'worcestershire_sauce' WHERE "key" = 'sauce_worcestershire';
|
||||||
|
UPDATE "ingredients" SET "key" = 'fish_sauce' WHERE "key" = 'sauce_nuoc_mam';
|
||||||
|
UPDATE "ingredients" SET "key" = 'wasabi' WHERE "key" = 'wasabi';
|
||||||
|
UPDATE "ingredients" SET "key" = 'harissa' WHERE "key" = 'harissa';
|
||||||
|
UPDATE "ingredients" SET "key" = 'curry_paste' WHERE "key" = 'pate_de_curry';
|
||||||
|
UPDATE "ingredients" SET "key" = 'peanut_butter' WHERE "key" = 'beurre_de_cacahuete';
|
||||||
|
UPDATE "ingredients" SET "key" = 'dijon_mustard' WHERE "key" = 'moutarde_de_dijon';
|
||||||
|
UPDATE "ingredients" SET "key" = 'wholegrain_mustard' WHERE "key" = 'moutarde_a_l_ancienne';
|
||||||
|
UPDATE "ingredients" SET "key" = 'barbecue_sauce' WHERE "key" = 'sauce_barbecue';
|
||||||
|
UPDATE "ingredients" SET "key" = 'tartar_sauce' WHERE "key" = 'sauce_tartare';
|
||||||
|
UPDATE "ingredients" SET "key" = 'cocktail_sauce' WHERE "key" = 'sauce_cocktail';
|
||||||
|
UPDATE "ingredients" SET "key" = 'bearnaise_sauce' WHERE "key" = 'sauce_bearnaise';
|
||||||
|
UPDATE "ingredients" SET "key" = 'hollandaise_sauce' WHERE "key" = 'sauce_hollandaise';
|
||||||
|
UPDATE "ingredients" SET "key" = 'bechamel_sauce' WHERE "key" = 'sauce_bechamel';
|
||||||
|
UPDATE "ingredients" SET "key" = 'teriyaki_sauce' WHERE "key" = 'sauce_teriyaki';
|
||||||
|
UPDATE "ingredients" SET "key" = 'ponzu_sauce' WHERE "key" = 'sauce_ponzu';
|
||||||
|
UPDATE "ingredients" SET "key" = 'chimichurri' WHERE "key" = 'chimichurri';
|
||||||
|
UPDATE "ingredients" SET "key" = 'red_pesto' WHERE "key" = 'pesto_rouge_tomates_sechees';
|
||||||
|
UPDATE "ingredients" SET "key" = 'pesto' WHERE "key" = 'pesto';
|
||||||
|
UPDATE "ingredients" SET "key" = 'oyster_sauce' WHERE "key" = 'sauce_huitre';
|
||||||
|
UPDATE "ingredients" SET "key" = 'hoisin_sauce' WHERE "key" = 'sauce_hoisin';
|
||||||
|
UPDATE "ingredients" SET "key" = 'sriracha' WHERE "key" = 'sauce_sriracha';
|
||||||
|
UPDATE "ingredients" SET "key" = 'sweet_chili_sauce' WHERE "key" = 'sauce_sweet_chili';
|
||||||
|
UPDATE "ingredients" SET "key" = 'miso' WHERE "key" = 'miso';
|
||||||
|
UPDATE "ingredients" SET "key" = 'shrimp_paste' WHERE "key" = 'pate_de_crevettes';
|
||||||
|
UPDATE "ingredients" SET "key" = 'red_curry_paste' WHERE "key" = 'pate_de_curry_rouge_thai';
|
||||||
|
UPDATE "ingredients" SET "key" = 'green_curry_paste' WHERE "key" = 'pate_de_curry_vert_thai';
|
||||||
|
UPDATE "ingredients" SET "key" = 'tahini' WHERE "key" = 'tahini';
|
||||||
|
UPDATE "ingredients" SET "key" = 'olive_oil' WHERE "key" = 'huile_d_olive';
|
||||||
|
UPDATE "ingredients" SET "key" = 'sunflower_oil' WHERE "key" = 'huile_de_tournesol';
|
||||||
|
UPDATE "ingredients" SET "key" = 'rapeseed_oil' WHERE "key" = 'huile_de_colza';
|
||||||
|
UPDATE "ingredients" SET "key" = 'coconut_oil' WHERE "key" = 'huile_de_coco';
|
||||||
|
UPDATE "ingredients" SET "key" = 'sesame_oil' WHERE "key" = 'huile_de_sesame';
|
||||||
|
UPDATE "ingredients" SET "key" = 'cider_vinegar' WHERE "key" = 'vinaigre_de_cidre';
|
||||||
|
UPDATE "ingredients" SET "key" = 'white_vinegar' WHERE "key" = 'vinaigre_blanc';
|
||||||
|
UPDATE "ingredients" SET "key" = 'balsamic_vinegar' WHERE "key" = 'vinaigre_balsamique';
|
||||||
|
UPDATE "ingredients" SET "key" = 'capers' WHERE "key" = 'capres';
|
||||||
|
UPDATE "ingredients" SET "key" = 'olives' WHERE "key" = 'olives';
|
||||||
|
UPDATE "ingredients" SET "key" = 'white_wine' WHERE "key" = 'vin_blanc_cuisine';
|
||||||
|
UPDATE "ingredients" SET "key" = 'red_wine' WHERE "key" = 'vin_rouge_cuisine';
|
||||||
|
UPDATE "ingredients" SET "key" = 'red_wine_vinegar' WHERE "key" = 'vinaigre_de_vin_rouge';
|
||||||
|
UPDATE "ingredients" SET "key" = 'white_wine_vinegar' WHERE "key" = 'vinaigre_de_vin_blanc';
|
||||||
|
UPDATE "ingredients" SET "key" = 'sherry_vinegar' WHERE "key" = 'vinaigre_de_xeres';
|
||||||
|
UPDATE "ingredients" SET "key" = 'walnut_oil' WHERE "key" = 'huile_de_noix';
|
||||||
|
UPDATE "ingredients" SET "key" = 'hazelnut_oil' WHERE "key" = 'huile_de_noisette';
|
||||||
|
UPDATE "ingredients" SET "key" = 'peanut_oil' WHERE "key" = 'huile_d_arachide';
|
||||||
|
UPDATE "ingredients" SET "key" = 'chili_oil' WHERE "key" = 'huile_pimentee';
|
||||||
|
UPDATE "ingredients" SET "key" = 'rice_vinegar' WHERE "key" = 'vinaigre_de_riz';
|
||||||
|
UPDATE "ingredients" SET "key" = 'mirin' WHERE "key" = 'mirin';
|
||||||
|
UPDATE "ingredients" SET "key" = 'sake' WHERE "key" = 'sake_cuisine';
|
||||||
|
UPDATE "ingredients" SET "key" = 'lemon_juice' WHERE "key" = 'jus_de_citron';
|
||||||
|
UPDATE "ingredients" SET "key" = 'lime_juice' WHERE "key" = 'jus_de_citron_vert';
|
||||||
|
UPDATE "ingredients" SET "key" = 'orange_juice' WHERE "key" = 'jus_d_orange';
|
||||||
|
UPDATE "ingredients" SET "key" = 'apple_juice' WHERE "key" = 'jus_de_pomme';
|
||||||
|
UPDATE "ingredients" SET "key" = 'grape_juice' WHERE "key" = 'jus_de_raisin';
|
||||||
|
UPDATE "ingredients" SET "key" = 'tomato_juice' WHERE "key" = 'jus_de_tomate';
|
||||||
|
UPDATE "ingredients" SET "key" = 'cranberry_juice' WHERE "key" = 'jus_de_cranberry';
|
||||||
|
UPDATE "ingredients" SET "key" = 'coffee' WHERE "key" = 'cafe';
|
||||||
|
UPDATE "ingredients" SET "key" = 'tea' WHERE "key" = 'the';
|
||||||
|
UPDATE "ingredients" SET "key" = 'beer' WHERE "key" = 'biere_cuisine';
|
||||||
|
UPDATE "ingredients" SET "key" = 'cider' WHERE "key" = 'cidre_cuisine';
|
||||||
|
UPDATE "ingredients" SET "key" = 'champagne' WHERE "key" = 'champagne_vin_petillant_cuisine';
|
||||||
|
UPDATE "ingredients" SET "key" = 'port_wine' WHERE "key" = 'porto_cuisine';
|
||||||
|
UPDATE "ingredients" SET "key" = 'vin_jaune' WHERE "key" = 'vin_jaune_cuisine';
|
||||||
|
UPDATE "ingredients" SET "key" = 'cognac' WHERE "key" = 'cognac';
|
||||||
|
UPDATE "ingredients" SET "key" = 'rum' WHERE "key" = 'rhum';
|
||||||
|
UPDATE "ingredients" SET "key" = 'whisky' WHERE "key" = 'whisky';
|
||||||
|
UPDATE "ingredients" SET "key" = 'vodka' WHERE "key" = 'vodka';
|
||||||
|
UPDATE "ingredients" SET "key" = 'wheat_flour' WHERE "key" = 'farine_de_ble';
|
||||||
|
UPDATE "ingredients" SET "key" = 'whole_wheat_flour' WHERE "key" = 'farine_complete';
|
||||||
|
UPDATE "ingredients" SET "key" = 'corn_flour' WHERE "key" = 'farine_de_mais';
|
||||||
|
UPDATE "ingredients" SET "key" = 'buckwheat_flour' WHERE "key" = 'farine_de_sarrasin';
|
||||||
|
UPDATE "ingredients" SET "key" = 'rice_flour' WHERE "key" = 'farine_de_riz';
|
||||||
|
UPDATE "ingredients" SET "key" = 'vegetable_stock_cube' WHERE "key" = 'bouillon_cube_legumes';
|
||||||
|
UPDATE "ingredients" SET "key" = 'chicken_stock_cube' WHERE "key" = 'bouillon_cube_volaille';
|
||||||
|
UPDATE "ingredients" SET "key" = 'tomato_paste' WHERE "key" = 'concentre_de_tomate';
|
||||||
|
UPDATE "ingredients" SET "key" = 'tomato_coulis' WHERE "key" = 'coulis_de_tomate';
|
||||||
|
UPDATE "ingredients" SET "key" = 'canned_peeled_tomatoes' WHERE "key" = 'tomates_pelees_conserve';
|
||||||
|
UPDATE "ingredients" SET "key" = 'sun_dried_tomatoes' WHERE "key" = 'tomates_sechees';
|
||||||
|
UPDATE "ingredients" SET "key" = 'veal_stock' WHERE "key" = 'fond_de_veau';
|
||||||
|
UPDATE "ingredients" SET "key" = 'chicken_stock' WHERE "key" = 'fond_de_volaille';
|
||||||
|
UPDATE "ingredients" SET "key" = 'beef_stock_cube' WHERE "key" = 'bouillon_cube_boeuf';
|
||||||
|
UPDATE "ingredients" SET "key" = 'fish_stock_cube' WHERE "key" = 'bouillon_cube_poisson';
|
||||||
|
UPDATE "ingredients" SET "key" = 'vegetable_broth' WHERE "key" = 'bouillon_de_legumes';
|
||||||
|
UPDATE "ingredients" SET "key" = 'chicken_broth' WHERE "key" = 'bouillon_de_volaille';
|
||||||
|
UPDATE "ingredients" SET "key" = 'beef_broth' WHERE "key" = 'bouillon_de_boeuf';
|
||||||
|
UPDATE "ingredients" SET "key" = 'court_bouillon' WHERE "key" = 'court_bouillon';
|
||||||
|
UPDATE "ingredients" SET "key" = 'dashi' WHERE "key" = 'dashi_bouillon_japonais';
|
||||||
|
UPDATE "ingredients" SET "key" = 'shellfish_bisque' WHERE "key" = 'bisque_de_crustaces';
|
||||||
|
UPDATE "ingredients" SET "key" = 'tapioca_flour' WHERE "key" = 'farine_de_tapioca';
|
||||||
|
UPDATE "ingredients" SET "key" = 'masa_harina' WHERE "key" = 'masa_harina';
|
||||||
|
UPDATE "ingredients" SET "key" = 'water' WHERE "key" = 'eau';
|
||||||
|
UPDATE "ingredients" SET "key" = 'sparkling_water' WHERE "key" = 'eau_gazeuse';
|
||||||
|
UPDATE "ingredients" SET "key" = 'orange_blossom_water' WHERE "key" = 'eau_de_fleur_d_oranger';
|
||||||
|
UPDATE "ingredients" SET "key" = 'rose_water' WHERE "key" = 'eau_de_rose';
|
||||||
|
UPDATE "ingredients" SET "key" = 'fish_fumet' WHERE "key" = 'fumet_de_poisson';
|
||||||
|
UPDATE "ingredients" SET "key" = 'bakers_yeast' WHERE "key" = 'levure_boulangere';
|
||||||
|
UPDATE "ingredients" SET "key" = 'baking_powder' WHERE "key" = 'levure_chimique';
|
||||||
|
UPDATE "ingredients" SET "key" = 'cornstarch' WHERE "key" = 'maizena';
|
||||||
|
UPDATE "ingredients" SET "key" = 'lupin_flour' WHERE "key" = 'farine_de_lupin';
|
||||||
|
UPDATE "ingredients" SET "key" = 'gelatin' WHERE "key" = 'gelatine';
|
||||||
|
UPDATE "ingredients" SET "key" = 'baking_soda' WHERE "key" = 'bicarbonate_de_soude';
|
||||||
|
UPDATE "ingredients" SET "key" = 'potato_starch' WHERE "key" = 'fecule_de_pomme_de_terre';
|
||||||
|
UPDATE "ingredients" SET "key" = 'sugar' WHERE "key" = 'sucre';
|
||||||
|
UPDATE "ingredients" SET "key" = 'honey' WHERE "key" = 'miel';
|
||||||
|
UPDATE "ingredients" SET "key" = 'maple_syrup' WHERE "key" = 'sirop_d_erable';
|
||||||
|
UPDATE "ingredients" SET "key" = 'brown_sugar' WHERE "key" = 'sucre_roux';
|
||||||
|
UPDATE "ingredients" SET "key" = 'powdered_sugar' WHERE "key" = 'sucre_glace';
|
||||||
|
UPDATE "ingredients" SET "key" = 'demerara_sugar' WHERE "key" = 'cassonade';
|
||||||
|
UPDATE "ingredients" SET "key" = 'dark_chocolate' WHERE "key" = 'chocolat_noir';
|
||||||
|
UPDATE "ingredients" SET "key" = 'milk_chocolate' WHERE "key" = 'chocolat_au_lait';
|
||||||
|
UPDATE "ingredients" SET "key" = 'white_chocolate' WHERE "key" = 'chocolat_blanc';
|
||||||
|
UPDATE "ingredients" SET "key" = 'chocolate_chips' WHERE "key" = 'pepites_de_chocolat';
|
||||||
|
UPDATE "ingredients" SET "key" = 'cocoa_powder' WHERE "key" = 'cacao_en_poudre';
|
||||||
|
UPDATE "ingredients" SET "key" = 'vanilla_extract' WHERE "key" = 'extrait_de_vanille';
|
||||||
|
UPDATE "ingredients" SET "key" = 'palm_sugar' WHERE "key" = 'sucre_de_palme';
|
||||||
|
UPDATE "ingredients" SET "key" = 'cane_syrup' WHERE "key" = 'sirop_de_sucre_de_canne';
|
||||||
|
|
||||||
|
|
@ -1,99 +1,49 @@
|
||||||
/**
|
/**
|
||||||
* One-off generator, run by hand whenever the catalog's reference data
|
* One-off generator, run by hand whenever the catalog's reference data
|
||||||
* changes (a new ingredient/diet/allergen added to
|
* changes (a new ingredient/diet/allergen added to
|
||||||
* `db/reference-seed-data.ts`): derives every row's slug `key` from its
|
* `db/reference-seed-data.ts`, or an English key corrected in
|
||||||
* French name (see `slugify.ts`), fails loudly on any collision, and
|
* `catalog-en-keys.ts`): regenerates
|
||||||
* regenerates `apps/web/src/locales/fr/translation.json`'s
|
* `apps/web/src/locales/fr/translation.json`'s
|
||||||
* `catalog.{diets,allergens,ingredients}` sections (key -> French label),
|
* `catalog.{diets,allergens,ingredients}` sections (English key -> French
|
||||||
* merged in without touching the rest of the file.
|
* label), merged in without touching the rest of the file.
|
||||||
*
|
*
|
||||||
* Also (re-)writes `backfill.sql` alongside itself — the `UPDATE ... SET
|
* Doesn't touch the database — a brand new diet/allergen/ingredient is
|
||||||
* key = ...` statements a migration adding a brand new item needs to carry
|
* created fresh by `seedReferenceData`'s normal create path (see
|
||||||
* forward, in case that ever happens again; the one for this refactor's own
|
* `reference-seed-data.ts`), no backfill needed. Renaming an *existing*
|
||||||
* migration (`prisma/migrations/20260818190000_catalog_labels_to_keys/`)
|
* item's English key in `catalog-en-keys.ts` does need a one-off migration
|
||||||
* was generated once and copied in by hand, and `backfill.sql` itself is
|
* (`UPDATE ... SET key = ...`, keyed by the *old* key value) written by
|
||||||
* gitignored scratch output, not the source of truth.
|
* hand for that occasion — see
|
||||||
|
* `prisma/migrations/20260818193000_catalog_keys_to_english/` for the shape
|
||||||
|
* one looks like.
|
||||||
*
|
*
|
||||||
* Never imported by the app itself — a dev-time tool, run via
|
* Never imported by the app itself — a dev-time tool, run via
|
||||||
* `tsx scripts/generate-catalog-i18n.ts`.
|
* `tsx scripts/generate-catalog-i18n.ts`.
|
||||||
*/
|
*/
|
||||||
import { readFileSync, writeFileSync } from "node:fs";
|
import { readFileSync, writeFileSync } from "node:fs";
|
||||||
import { fileURLToPath } from "node:url";
|
import { fileURLToPath } from "node:url";
|
||||||
|
import { getEnglishKey } from "../src/db/catalog-en-keys.js";
|
||||||
import { ALLERGENS, DIETS, INGREDIENT_GROUPS } from "../src/db/reference-seed-data.js";
|
import { ALLERGENS, DIETS, INGREDIENT_GROUPS } from "../src/db/reference-seed-data.js";
|
||||||
import { slugify } from "../src/utils/slugify.js";
|
|
||||||
|
|
||||||
const here = fileURLToPath(new URL(".", import.meta.url));
|
const here = fileURLToPath(new URL(".", import.meta.url));
|
||||||
|
|
||||||
function toKeyLabelMap(labels: string[]): Record<string, string> {
|
function toKeyLabelMap(labels: string[]): Record<string, string> {
|
||||||
const map: Record<string, string> = {};
|
const map: Record<string, string> = {};
|
||||||
const seenKeys = new Map<string, string>();
|
|
||||||
for (const label of labels) {
|
for (const label of labels) {
|
||||||
const key = slugify(label);
|
map[getEnglishKey(label)] = label;
|
||||||
const clashingLabel = seenKeys.get(key);
|
|
||||||
if (clashingLabel !== undefined && clashingLabel !== label) {
|
|
||||||
throw new Error(`Slug collision: "${clashingLabel}" and "${label}" both slugify to "${key}"`);
|
|
||||||
}
|
|
||||||
seenKeys.set(key, label);
|
|
||||||
map[key] = label;
|
|
||||||
}
|
}
|
||||||
return map;
|
return map;
|
||||||
}
|
}
|
||||||
|
|
||||||
const dietLabels = DIETS;
|
const diets = toKeyLabelMap(DIETS);
|
||||||
const allergenLabels = ALLERGENS.map((a) => a.name);
|
const allergens = toKeyLabelMap(ALLERGENS.map((a) => a.name));
|
||||||
const ingredientLabels = INGREDIENT_GROUPS.flatMap((g) => g.items.map((i) => i.name));
|
const ingredients = toKeyLabelMap(INGREDIENT_GROUPS.flatMap((g) => g.items.map((i) => i.name)));
|
||||||
|
|
||||||
const diets = toKeyLabelMap(dietLabels);
|
|
||||||
const allergens = toKeyLabelMap(allergenLabels);
|
|
||||||
const ingredients = toKeyLabelMap(ingredientLabels);
|
|
||||||
|
|
||||||
console.log(
|
console.log(
|
||||||
`diets: ${Object.keys(diets).length}, allergens: ${Object.keys(allergens).length}, ingredients: ${Object.keys(ingredients).length}`,
|
`diets: ${Object.keys(diets).length}, allergens: ${Object.keys(allergens).length}, ingredients: ${Object.keys(ingredients).length}`,
|
||||||
);
|
);
|
||||||
|
|
||||||
// --- Merge into the fr locale file -----------------------------------------
|
|
||||||
const localePath = here + "../../web/src/locales/fr/translation.json";
|
const localePath = here + "../../web/src/locales/fr/translation.json";
|
||||||
const locale = JSON.parse(readFileSync(localePath, "utf8"));
|
const locale = JSON.parse(readFileSync(localePath, "utf8"));
|
||||||
locale.catalog = { diets, allergens, ingredients };
|
locale.catalog = { diets, allergens, ingredients };
|
||||||
writeFileSync(localePath, JSON.stringify(locale, null, 2) + "\n");
|
writeFileSync(localePath, JSON.stringify(locale, null, 2) + "\n");
|
||||||
console.log(`wrote ${localePath}`);
|
console.log(`wrote ${localePath}`);
|
||||||
|
|
||||||
// --- Emit the migration's backfill SQL --------------------------------------
|
|
||||||
function escapeSql(value: string): string {
|
|
||||||
return value.replace(/'/g, "''");
|
|
||||||
}
|
|
||||||
|
|
||||||
// The migration this feeds renames each table's "name" column to "key"
|
|
||||||
// *before* running this backfill — so by the time these UPDATEs run, the
|
|
||||||
// "key" column still holds the old French label value (just under its new
|
|
||||||
// column name), which is exactly what the WHERE clause below matches on.
|
|
||||||
const dietUpdates = Object.entries(diets)
|
|
||||||
.map(([key, label]) => `UPDATE "diet" SET "key" = '${escapeSql(key)}' WHERE "key" = '${escapeSql(label)}';`)
|
|
||||||
.join("\n");
|
|
||||||
const categoryUpdates = Object.entries(allergens)
|
|
||||||
.map(
|
|
||||||
([key, label]) => `UPDATE "category" SET "key" = '${escapeSql(key)}' WHERE "key" = '${escapeSql(label)}';`,
|
|
||||||
)
|
|
||||||
.join("\n");
|
|
||||||
const ingredientUpdates = Object.entries(ingredients)
|
|
||||||
.map(
|
|
||||||
([key, label]) =>
|
|
||||||
`UPDATE "ingredients" SET "key" = '${escapeSql(key)}' WHERE "key" = '${escapeSql(label)}';`,
|
|
||||||
)
|
|
||||||
.join("\n");
|
|
||||||
|
|
||||||
const sql = `-- Auto-generated by scripts/generate-catalog-i18n.ts — do not hand-edit.
|
|
||||||
-- Backfills the "key" column (just renamed from "name" by this migration's
|
|
||||||
-- preceding statement, so it still holds the old French label) to its slug
|
|
||||||
-- value, for every row already seeded in a database this migration runs
|
|
||||||
-- against. A fresh database has none of these rows yet (the seed script
|
|
||||||
-- inserts by "key" from the start), so this is a no-op there.
|
|
||||||
|
|
||||||
${dietUpdates}
|
|
||||||
|
|
||||||
${categoryUpdates}
|
|
||||||
|
|
||||||
${ingredientUpdates}
|
|
||||||
`;
|
|
||||||
writeFileSync(here + "backfill.sql", sql);
|
|
||||||
console.log(`wrote ${here}backfill.sql`);
|
|
||||||
|
|
|
||||||
43
apps/api/scripts/validate-catalog-en-keys.ts
Normal file
43
apps/api/scripts/validate-catalog-en-keys.ts
Normal file
|
|
@ -0,0 +1,43 @@
|
||||||
|
/**
|
||||||
|
* One-off validation, run by hand: checks that `catalog-en-keys.ts` has an
|
||||||
|
* entry for every diet/allergen/ingredient currently in
|
||||||
|
* `reference-seed-data.ts`, and that the resulting English keys are unique
|
||||||
|
* within each table. Not part of the app or the seed itself — just a
|
||||||
|
* pre-flight check while building/editing the dictionary by hand.
|
||||||
|
*/
|
||||||
|
import { ALLERGENS, DIETS, INGREDIENT_GROUPS } from "../src/db/reference-seed-data.js";
|
||||||
|
import { getEnglishKey } from "../src/db/catalog-en-keys.js";
|
||||||
|
|
||||||
|
function check(label: string, names: string[]) {
|
||||||
|
const keys = new Map<string, string>();
|
||||||
|
const missing: string[] = [];
|
||||||
|
const duplicates: string[] = [];
|
||||||
|
for (const name of names) {
|
||||||
|
let key: string;
|
||||||
|
try {
|
||||||
|
key = getEnglishKey(name);
|
||||||
|
} catch {
|
||||||
|
missing.push(name);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
const existing = keys.get(key);
|
||||||
|
if (existing !== undefined && existing !== name) {
|
||||||
|
duplicates.push(`"${existing}" and "${name}" both map to "${key}"`);
|
||||||
|
}
|
||||||
|
keys.set(key, name);
|
||||||
|
}
|
||||||
|
console.log(`${label}: ${names.length} names, ${keys.size} unique keys`);
|
||||||
|
if (missing.length > 0) {
|
||||||
|
console.log(` MISSING (${missing.length}):`, missing);
|
||||||
|
}
|
||||||
|
if (duplicates.length > 0) {
|
||||||
|
console.log(` DUPLICATES (${duplicates.length}):`, duplicates);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
check("Diets", DIETS);
|
||||||
|
check("Allergens", ALLERGENS.map((a) => a.name));
|
||||||
|
check(
|
||||||
|
"Ingredients",
|
||||||
|
INGREDIENT_GROUPS.flatMap((g) => g.items.map((i) => i.name)),
|
||||||
|
);
|
||||||
557
apps/api/src/db/catalog-en-keys.ts
Normal file
557
apps/api/src/db/catalog-en-keys.ts
Normal file
|
|
@ -0,0 +1,557 @@
|
||||||
|
/**
|
||||||
|
* 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<string, string> = {
|
||||||
|
Omnivore: "omnivore",
|
||||||
|
Végétarien: "vegetarian",
|
||||||
|
Végan: "vegan",
|
||||||
|
Pescétarien: "pescatarian",
|
||||||
|
"Sans gluten": "gluten_free",
|
||||||
|
};
|
||||||
|
|
||||||
|
const ALLERGEN_KEYS: Record<string, string> = {
|
||||||
|
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<string, string> = {
|
||||||
|
// --- 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<string, string> = {
|
||||||
|
...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);
|
||||||
|
}
|
||||||
|
|
@ -5,7 +5,7 @@ import type {
|
||||||
IngredientSubcategory,
|
IngredientSubcategory,
|
||||||
PrismaClient,
|
PrismaClient,
|
||||||
} from "@prisma/client";
|
} from "@prisma/client";
|
||||||
import { slugify } from "../utils/slugify.js";
|
import { getEnglishKey } from "./catalog-en-keys.js";
|
||||||
|
|
||||||
// Short, optional-to-pick regime list — `UserProfile.dietId` stays
|
// Short, optional-to-pick regime list — `UserProfile.dietId` stays
|
||||||
// nullable, this is not meant to be exhaustive. Exported for
|
// nullable, this is not meant to be exhaustive. Exported for
|
||||||
|
|
@ -890,14 +890,16 @@ const INGREDIENTS: Array<
|
||||||
*
|
*
|
||||||
* Every `name` below (`DIETS`, `ALLERGENS`, `INGREDIENT_GROUPS`) is an
|
* Every `name` below (`DIETS`, `ALLERGENS`, `INGREDIENT_GROUPS`) is an
|
||||||
* *authoring* label, never written to the database or seen by a client —
|
* *authoring* label, never written to the database or seen by a client —
|
||||||
* {@link slugify} derives each row's real, stable `key` from it once, up
|
* {@link getEnglishKey} resolves each row's real, stable, English `key`
|
||||||
* front. The database only ever stores that slug; the French label itself
|
* from it (see `catalog-en-keys.ts` for why the key must be English even
|
||||||
* lives in `apps/web`'s `locales/fr/translation.json` (`catalog.*`
|
* though this file's labels are French). The database only ever stores
|
||||||
|
* that key; the French label itself lives in `apps/web`'s
|
||||||
|
* `locales/fr/translation.json` (`catalog.*`
|
||||||
* namespace, kept in sync by `scripts/generate-catalog-i18n.ts`).
|
* namespace, kept in sync by `scripts/generate-catalog-i18n.ts`).
|
||||||
*/
|
*/
|
||||||
export async function seedReferenceData(prisma: PrismaClient): Promise<void> {
|
export async function seedReferenceData(prisma: PrismaClient): Promise<void> {
|
||||||
for (const name of DIETS) {
|
for (const name of DIETS) {
|
||||||
const key = slugify(name);
|
const key = getEnglishKey(name);
|
||||||
await prisma.diet.upsert({ where: { key }, update: {}, create: { key } });
|
await prisma.diet.upsert({ where: { key }, update: {}, create: { key } });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -908,7 +910,7 @@ export async function seedReferenceData(prisma: PrismaClient): Promise<void> {
|
||||||
// must correct `kind` on an already-existing category if the
|
// must correct `kind` on an already-existing category if the
|
||||||
// classification above ever changes, not just skip it.
|
// classification above ever changes, not just skip it.
|
||||||
for (const { name, kind } of ALLERGENS) {
|
for (const { name, kind } of ALLERGENS) {
|
||||||
const key = slugify(name);
|
const key = getEnglishKey(name);
|
||||||
const category = await prisma.category.upsert({
|
const category = await prisma.category.upsert({
|
||||||
where: { key },
|
where: { key },
|
||||||
update: { kind },
|
update: { kind },
|
||||||
|
|
@ -929,18 +931,18 @@ export async function seedReferenceData(prisma: PrismaClient): Promise<void> {
|
||||||
// test-suite case) that's zero updates, on a real re-deploy it's however
|
// test-suite case) that's zero updates, on a real re-deploy it's however
|
||||||
// many rows were edited in code since the last deploy, never the full
|
// many rows were edited in code since the last deploy, never the full
|
||||||
// list.
|
// list.
|
||||||
const ingredientKeys = INGREDIENTS.map((i) => slugify(i.name));
|
const ingredientKeys = INGREDIENTS.map((i) => getEnglishKey(i.name));
|
||||||
const existingIngredients = await prisma.ingredient.findMany({
|
const existingIngredients = await prisma.ingredient.findMany({
|
||||||
where: { key: { in: ingredientKeys } },
|
where: { key: { in: ingredientKeys } },
|
||||||
select: { id: true, key: true, icon: true, category: true, subcategory: true },
|
select: { id: true, key: true, icon: true, category: true, subcategory: true },
|
||||||
});
|
});
|
||||||
const existingByKey = new Map(existingIngredients.map((i) => [i.key, i]));
|
const existingByKey = new Map(existingIngredients.map((i) => [i.key, i]));
|
||||||
|
|
||||||
const missingIngredients = INGREDIENTS.filter((i) => !existingByKey.has(slugify(i.name)));
|
const missingIngredients = INGREDIENTS.filter((i) => !existingByKey.has(getEnglishKey(i.name)));
|
||||||
if (missingIngredients.length > 0) {
|
if (missingIngredients.length > 0) {
|
||||||
await prisma.ingredient.createMany({
|
await prisma.ingredient.createMany({
|
||||||
data: missingIngredients.map(({ name, icon, category, subcategory }) => ({
|
data: missingIngredients.map(({ name, icon, category, subcategory }) => ({
|
||||||
key: slugify(name),
|
key: getEnglishKey(name),
|
||||||
icon,
|
icon,
|
||||||
category,
|
category,
|
||||||
subcategory,
|
subcategory,
|
||||||
|
|
@ -949,7 +951,7 @@ export async function seedReferenceData(prisma: PrismaClient): Promise<void> {
|
||||||
}
|
}
|
||||||
|
|
||||||
const changed = INGREDIENTS.filter((i) => {
|
const changed = INGREDIENTS.filter((i) => {
|
||||||
const existing = existingByKey.get(slugify(i.name));
|
const existing = existingByKey.get(getEnglishKey(i.name));
|
||||||
return (
|
return (
|
||||||
existing &&
|
existing &&
|
||||||
(existing.icon !== i.icon ||
|
(existing.icon !== i.icon ||
|
||||||
|
|
@ -958,7 +960,7 @@ export async function seedReferenceData(prisma: PrismaClient): Promise<void> {
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
for (const { name, icon, category, subcategory } of changed) {
|
for (const { name, icon, category, subcategory } of changed) {
|
||||||
await prisma.ingredient.update({ where: { key: slugify(name) }, data: { icon, category, subcategory } });
|
await prisma.ingredient.update({ where: { key: getEnglishKey(name) }, data: { icon, category, subcategory } });
|
||||||
}
|
}
|
||||||
|
|
||||||
// Re-resolve every ingredient's id (existing + just-created) and every
|
// Re-resolve every ingredient's id (existing + just-created) and every
|
||||||
|
|
@ -977,10 +979,10 @@ export async function seedReferenceData(prisma: PrismaClient): Promise<void> {
|
||||||
|
|
||||||
const links: Array<{ ingredientId: number; allergyId: number }> = [];
|
const links: Array<{ ingredientId: number; allergyId: number }> = [];
|
||||||
for (const { name, allergenNames } of INGREDIENTS) {
|
for (const { name, allergenNames } of INGREDIENTS) {
|
||||||
const ingredientId = ingredientIdByKey.get(slugify(name));
|
const ingredientId = ingredientIdByKey.get(getEnglishKey(name));
|
||||||
if (ingredientId === undefined) continue;
|
if (ingredientId === undefined) continue;
|
||||||
for (const allergenName of allergenNames) {
|
for (const allergenName of allergenNames) {
|
||||||
const allergyId = allergyIdByCategoryKey.get(slugify(allergenName));
|
const allergyId = allergyIdByCategoryKey.get(getEnglishKey(allergenName));
|
||||||
if (allergyId !== undefined) links.push({ ingredientId, allergyId });
|
if (allergyId !== undefined) links.push({ ingredientId, allergyId });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -996,10 +998,10 @@ export async function seedReferenceData(prisma: PrismaClient): Promise<void> {
|
||||||
|
|
||||||
const dietLinks: Array<{ ingredientId: number; dietId: number }> = [];
|
const dietLinks: Array<{ ingredientId: number; dietId: number }> = [];
|
||||||
for (const { name, dietNames } of INGREDIENTS) {
|
for (const { name, dietNames } of INGREDIENTS) {
|
||||||
const ingredientId = ingredientIdByKey.get(slugify(name));
|
const ingredientId = ingredientIdByKey.get(getEnglishKey(name));
|
||||||
if (ingredientId === undefined) continue;
|
if (ingredientId === undefined) continue;
|
||||||
for (const dietName of dietNames) {
|
for (const dietName of dietNames) {
|
||||||
const dietId = dietIdByKey.get(slugify(dietName));
|
const dietId = dietIdByKey.get(getEnglishKey(dietName));
|
||||||
if (dietId !== undefined) dietLinks.push({ ingredientId, dietId });
|
if (dietId !== undefined) dietLinks.push({ ingredientId, dietId });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,7 @@ import { expect } from "chai";
|
||||||
import request from "supertest";
|
import request from "supertest";
|
||||||
import { createApp } from "../src/app.js";
|
import { createApp } from "../src/app.js";
|
||||||
import { prisma } from "../src/db/prisma.js";
|
import { prisma } from "../src/db/prisma.js";
|
||||||
import { slugify } from "../src/utils/slugify.js";
|
import { getEnglishKey } from "../src/db/catalog-en-keys.js";
|
||||||
import { resetDatabase } from "../test-support/reset-db.js";
|
import { resetDatabase } from "../test-support/reset-db.js";
|
||||||
|
|
||||||
function buildSignupPayload(): SignupInput {
|
function buildSignupPayload(): SignupInput {
|
||||||
|
|
@ -40,7 +40,7 @@ describe("Profile", () => {
|
||||||
it("sets the profile's regime to a valid, seeded diet", async () => {
|
it("sets the profile's regime to a valid, seeded diet", async () => {
|
||||||
const agent = request.agent(app);
|
const agent = request.agent(app);
|
||||||
await agent.post("/auth/signup").send(buildSignupPayload());
|
await agent.post("/auth/signup").send(buildSignupPayload());
|
||||||
const diet = await prisma.diet.findFirstOrThrow({ where: { key: slugify("Végétarien") } });
|
const diet = await prisma.diet.findFirstOrThrow({ where: { key: getEnglishKey("Végétarien") } });
|
||||||
|
|
||||||
const res = await agent.patch("/profile/diet").send({ dietId: diet.id });
|
const res = await agent.patch("/profile/diet").send({ dietId: diet.id });
|
||||||
|
|
||||||
|
|
@ -51,7 +51,7 @@ describe("Profile", () => {
|
||||||
it("clears the regime when dietId is null", async () => {
|
it("clears the regime when dietId is null", async () => {
|
||||||
const agent = request.agent(app);
|
const agent = request.agent(app);
|
||||||
await agent.post("/auth/signup").send(buildSignupPayload());
|
await agent.post("/auth/signup").send(buildSignupPayload());
|
||||||
const diet = await prisma.diet.findFirstOrThrow({ where: { key: slugify("Végan") } });
|
const diet = await prisma.diet.findFirstOrThrow({ where: { key: getEnglishKey("Végan") } });
|
||||||
await agent.patch("/profile/diet").send({ dietId: diet.id });
|
await agent.patch("/profile/diet").send({ dietId: diet.id });
|
||||||
|
|
||||||
const res = await agent.patch("/profile/diet").send({ dietId: null });
|
const res = await agent.patch("/profile/diet").send({ dietId: null });
|
||||||
|
|
@ -84,8 +84,8 @@ describe("Profile", () => {
|
||||||
const agent = request.agent(app);
|
const agent = request.agent(app);
|
||||||
await agent.post("/auth/signup").send(buildSignupPayload());
|
await agent.post("/auth/signup").send(buildSignupPayload());
|
||||||
const allergies = await prisma.allergy.findMany({ include: { category: true } });
|
const allergies = await prisma.allergy.findMany({ include: { category: true } });
|
||||||
const peanuts = allergies.find((a) => a.category.key === slugify("Arachides"));
|
const peanuts = allergies.find((a) => a.category.key === getEnglishKey("Arachides"));
|
||||||
const gluten = allergies.find((a) => a.category.key === slugify("Gluten"));
|
const gluten = allergies.find((a) => a.category.key === getEnglishKey("Gluten"));
|
||||||
if (!peanuts || !gluten) throw new Error("expected seeded allergens missing");
|
if (!peanuts || !gluten) throw new Error("expected seeded allergens missing");
|
||||||
|
|
||||||
const initial = await agent.get("/profile/allergies");
|
const initial = await agent.get("/profile/allergies");
|
||||||
|
|
@ -105,8 +105,8 @@ describe("Profile", () => {
|
||||||
const agent = request.agent(app);
|
const agent = request.agent(app);
|
||||||
await agent.post("/auth/signup").send(buildSignupPayload());
|
await agent.post("/auth/signup").send(buildSignupPayload());
|
||||||
const allergies = await prisma.allergy.findMany({ include: { category: true } });
|
const allergies = await prisma.allergy.findMany({ include: { category: true } });
|
||||||
const peanuts = allergies.find((a) => a.category.key === slugify("Arachides"));
|
const peanuts = allergies.find((a) => a.category.key === getEnglishKey("Arachides"));
|
||||||
const gluten = allergies.find((a) => a.category.key === slugify("Gluten"));
|
const gluten = allergies.find((a) => a.category.key === getEnglishKey("Gluten"));
|
||||||
if (!peanuts || !gluten) throw new Error("expected seeded allergens missing");
|
if (!peanuts || !gluten) throw new Error("expected seeded allergens missing");
|
||||||
|
|
||||||
await agent.patch("/profile/allergies").send({ allergyIds: [peanuts.id] });
|
await agent.patch("/profile/allergies").send({ allergyIds: [peanuts.id] });
|
||||||
|
|
@ -141,8 +141,8 @@ describe("Profile", () => {
|
||||||
it("starts empty, then reflects a saved selection", async () => {
|
it("starts empty, then reflects a saved selection", async () => {
|
||||||
const agent = request.agent(app);
|
const agent = request.agent(app);
|
||||||
await agent.post("/auth/signup").send(buildSignupPayload());
|
await agent.post("/auth/signup").send(buildSignupPayload());
|
||||||
const tomate = await prisma.ingredient.findFirstOrThrow({ where: { key: slugify("Tomate") } });
|
const tomate = await prisma.ingredient.findFirstOrThrow({ where: { key: getEnglishKey("Tomate") } });
|
||||||
const oignon = await prisma.ingredient.findFirstOrThrow({ where: { key: slugify("Oignon") } });
|
const oignon = await prisma.ingredient.findFirstOrThrow({ where: { key: getEnglishKey("Oignon") } });
|
||||||
|
|
||||||
const initial = await agent.get("/profile/disliked-ingredients");
|
const initial = await agent.get("/profile/disliked-ingredients");
|
||||||
expect(initial.body).to.deep.equal([]);
|
expect(initial.body).to.deep.equal([]);
|
||||||
|
|
@ -160,8 +160,8 @@ describe("Profile", () => {
|
||||||
it("replaces (not merges) the previous selection", async () => {
|
it("replaces (not merges) the previous selection", async () => {
|
||||||
const agent = request.agent(app);
|
const agent = request.agent(app);
|
||||||
await agent.post("/auth/signup").send(buildSignupPayload());
|
await agent.post("/auth/signup").send(buildSignupPayload());
|
||||||
const tomate = await prisma.ingredient.findFirstOrThrow({ where: { key: slugify("Tomate") } });
|
const tomate = await prisma.ingredient.findFirstOrThrow({ where: { key: getEnglishKey("Tomate") } });
|
||||||
const oignon = await prisma.ingredient.findFirstOrThrow({ where: { key: slugify("Oignon") } });
|
const oignon = await prisma.ingredient.findFirstOrThrow({ where: { key: getEnglishKey("Oignon") } });
|
||||||
|
|
||||||
await agent
|
await agent
|
||||||
.patch("/profile/disliked-ingredients")
|
.patch("/profile/disliked-ingredients")
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,7 @@ import { expect } from "chai";
|
||||||
import request from "supertest";
|
import request from "supertest";
|
||||||
import { createApp } from "../src/app.js";
|
import { createApp } from "../src/app.js";
|
||||||
import { prisma } from "../src/db/prisma.js";
|
import { prisma } from "../src/db/prisma.js";
|
||||||
import { slugify } from "../src/utils/slugify.js";
|
import { getEnglishKey } from "../src/db/catalog-en-keys.js";
|
||||||
import { resetDatabase } from "../test-support/reset-db.js";
|
import { resetDatabase } from "../test-support/reset-db.js";
|
||||||
|
|
||||||
/** See `auth.test.ts` — generated rather than hardcoded, no test fixture looks like a real person's data. */
|
/** See `auth.test.ts` — generated rather than hardcoded, no test fixture looks like a real person's data. */
|
||||||
|
|
@ -22,7 +22,7 @@ function buildSignupPayload(): SignupInput {
|
||||||
|
|
||||||
/** Resolves a reference ingredient's id by its `reference-seed-data.ts` French name (slugified to match its `key`). */
|
/** Resolves a reference ingredient's id by its `reference-seed-data.ts` French name (slugified to match its `key`). */
|
||||||
async function ingredientId(name: string): Promise<number> {
|
async function ingredientId(name: string): Promise<number> {
|
||||||
const ingredient = await prisma.ingredient.findFirstOrThrow({ where: { key: slugify(name) } });
|
const ingredient = await prisma.ingredient.findFirstOrThrow({ where: { key: getEnglishKey(name) } });
|
||||||
return ingredient.id;
|
return ingredient.id;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -164,7 +164,9 @@ describe("Recipes", () => {
|
||||||
const { agent } = await signup();
|
const { agent } = await signup();
|
||||||
const tomate = await ingredientId("Tomate");
|
const tomate = await ingredientId("Tomate");
|
||||||
const oeuf = await ingredientId("Œuf");
|
const oeuf = await ingredientId("Œuf");
|
||||||
const vegetarien = await prisma.diet.findFirstOrThrow({ where: { key: "vegetarien" } });
|
const vegetarien = await prisma.diet.findFirstOrThrow({
|
||||||
|
where: { key: getEnglishKey("Végétarien") },
|
||||||
|
});
|
||||||
|
|
||||||
const res = await agent.post("/recipes").send({
|
const res = await agent.post("/recipes").send({
|
||||||
name: "Omelette provençale",
|
name: "Omelette provençale",
|
||||||
|
|
@ -184,8 +186,12 @@ describe("Recipes", () => {
|
||||||
res.body.steps.map((s: { description: string; order: number }) => s.order),
|
res.body.steps.map((s: { description: string; order: number }) => s.order),
|
||||||
).to.deep.equal([0, 1]);
|
).to.deep.equal([0, 1]);
|
||||||
// Allergens aggregated across ingredients — "Œuf" carries "Œufs".
|
// Allergens aggregated across ingredients — "Œuf" carries "Œufs".
|
||||||
expect(res.body.allergens.map((a: { key: string }) => a.key)).to.include("oeufs");
|
expect(res.body.allergens.map((a: { key: string }) => a.key)).to.include(
|
||||||
expect(res.body.diets.map((d: { key: string }) => d.key)).to.deep.equal(["vegetarien"]);
|
getEnglishKey("Œufs"),
|
||||||
|
);
|
||||||
|
expect(res.body.diets.map((d: { key: string }) => d.key)).to.deep.equal([
|
||||||
|
getEnglishKey("Végétarien"),
|
||||||
|
]);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("defaults to PERSONAL visibility, and stamps the author's current household", async () => {
|
it("defaults to PERSONAL visibility, and stamps the author's current household", async () => {
|
||||||
|
|
@ -280,7 +286,7 @@ describe("Recipes", () => {
|
||||||
|
|
||||||
expect(res.status).to.equal(200);
|
expect(res.status).to.equal(200);
|
||||||
expect(res.body.name).to.equal("Salade");
|
expect(res.body.name).to.equal("Salade");
|
||||||
expect(res.body.ingredients[0].ingredient.key).to.equal("tomate");
|
expect(res.body.ingredients[0].ingredient.key).to.equal(getEnglishKey("Tomate"));
|
||||||
expect(res.body.isFavorite).to.equal(false);
|
expect(res.body.isFavorite).to.equal(false);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
@ -365,7 +371,7 @@ describe("Recipes", () => {
|
||||||
expect(res.body.name).to.equal("Salade composée");
|
expect(res.body.name).to.equal("Salade composée");
|
||||||
expect(res.body.visibility).to.equal("PUBLIC");
|
expect(res.body.visibility).to.equal("PUBLIC");
|
||||||
expect(res.body.ingredients).to.have.length(1);
|
expect(res.body.ingredients).to.have.length(1);
|
||||||
expect(res.body.ingredients[0].ingredient.key).to.equal("oignon");
|
expect(res.body.ingredients[0].ingredient.key).to.equal(getEnglishKey("Oignon"));
|
||||||
expect(res.body.steps).to.have.length(2);
|
expect(res.body.steps).to.have.length(2);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,7 @@ import request from "supertest";
|
||||||
import { createApp } from "../src/app.js";
|
import { createApp } from "../src/app.js";
|
||||||
import { prisma } from "../src/db/prisma.js";
|
import { prisma } from "../src/db/prisma.js";
|
||||||
import { resetDatabase } from "../test-support/reset-db.js";
|
import { resetDatabase } from "../test-support/reset-db.js";
|
||||||
import { slugify } from "../src/utils/slugify.js";
|
import { getEnglishKey } from "../src/db/catalog-en-keys.js";
|
||||||
|
|
||||||
describe("Reference data", () => {
|
describe("Reference data", () => {
|
||||||
const app = createApp();
|
const app = createApp();
|
||||||
|
|
@ -22,7 +22,7 @@ describe("Reference data", () => {
|
||||||
|
|
||||||
expect(res.status).to.equal(200);
|
expect(res.status).to.equal(200);
|
||||||
expect(res.body).to.have.length(5);
|
expect(res.body).to.have.length(5);
|
||||||
expect(res.body.map((d: { key: string }) => d.key)).to.include(slugify("Végétarien"));
|
expect(res.body.map((d: { key: string }) => d.key)).to.include(getEnglishKey("Végétarien"));
|
||||||
expect(res.body[0]).to.have.keys(["id", "key"]);
|
expect(res.body[0]).to.have.keys(["id", "key"]);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
@ -33,7 +33,7 @@ describe("Reference data", () => {
|
||||||
|
|
||||||
expect(res.status).to.equal(200);
|
expect(res.status).to.equal(200);
|
||||||
expect(res.body).to.have.length(14);
|
expect(res.body).to.have.length(14);
|
||||||
expect(res.body.map((a: { key: string }) => a.key)).to.include(slugify("Arachides"));
|
expect(res.body.map((a: { key: string }) => a.key)).to.include(getEnglishKey("Arachides"));
|
||||||
expect(res.body[0]).to.have.keys(["id", "key", "kind"]);
|
expect(res.body[0]).to.have.keys(["id", "key", "kind"]);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
@ -41,7 +41,7 @@ describe("Reference data", () => {
|
||||||
const res = await request(app).get("/reference/allergies");
|
const res = await request(app).get("/reference/allergies");
|
||||||
|
|
||||||
const byKey = (name: string) =>
|
const byKey = (name: string) =>
|
||||||
res.body.find((a: { key: string }) => a.key === slugify(name));
|
res.body.find((a: { key: string }) => a.key === getEnglishKey(name));
|
||||||
expect(byKey("Gluten").kind).to.equal("INTOLERANCE");
|
expect(byKey("Gluten").kind).to.equal("INTOLERANCE");
|
||||||
expect(byKey("Sulfites").kind).to.equal("INTOLERANCE");
|
expect(byKey("Sulfites").kind).to.equal("INTOLERANCE");
|
||||||
expect(byKey("Arachides").kind).to.equal("ALLERGY");
|
expect(byKey("Arachides").kind).to.equal("ALLERGY");
|
||||||
|
|
@ -55,7 +55,7 @@ describe("Reference data", () => {
|
||||||
|
|
||||||
expect(res.status).to.equal(200);
|
expect(res.status).to.equal(200);
|
||||||
expect(res.body.length).to.be.greaterThan(0);
|
expect(res.body.length).to.be.greaterThan(0);
|
||||||
expect(res.body.map((i: { key: string }) => i.key)).to.include(slugify("Tomate"));
|
expect(res.body.map((i: { key: string }) => i.key)).to.include(getEnglishKey("Tomate"));
|
||||||
expect(res.body[0]).to.have.keys([
|
expect(res.body[0]).to.have.keys([
|
||||||
"id",
|
"id",
|
||||||
"key",
|
"key",
|
||||||
|
|
@ -71,9 +71,9 @@ describe("Reference data", () => {
|
||||||
const res = await request(app).get("/reference/ingredients");
|
const res = await request(app).get("/reference/ingredients");
|
||||||
|
|
||||||
const byKey = (name: string) =>
|
const byKey = (name: string) =>
|
||||||
res.body.find((i: { key: string }) => i.key === slugify(name));
|
res.body.find((i: { key: string }) => i.key === getEnglishKey(name));
|
||||||
expect(byKey("Œuf").allergens.map((a: { key: string }) => a.key)).to.include(
|
expect(byKey("Œuf").allergens.map((a: { key: string }) => a.key)).to.include(
|
||||||
slugify("Œufs"),
|
getEnglishKey("Œufs"),
|
||||||
);
|
);
|
||||||
expect(byKey("Tomate").allergens).to.deep.equal([]);
|
expect(byKey("Tomate").allergens).to.deep.equal([]);
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -301,465 +301,465 @@
|
||||||
"catalog": {
|
"catalog": {
|
||||||
"diets": {
|
"diets": {
|
||||||
"omnivore": "Omnivore",
|
"omnivore": "Omnivore",
|
||||||
"vegetarien": "Végétarien",
|
"vegetarian": "Végétarien",
|
||||||
"vegan": "Végan",
|
"vegan": "Végan",
|
||||||
"pescetarien": "Pescétarien",
|
"pescatarian": "Pescétarien",
|
||||||
"sans_gluten": "Sans gluten"
|
"gluten_free": "Sans gluten"
|
||||||
},
|
},
|
||||||
"allergens": {
|
"allergens": {
|
||||||
"gluten": "Gluten",
|
"gluten": "Gluten",
|
||||||
"crustaces": "Crustacés",
|
"crustaceans": "Crustacés",
|
||||||
"oeufs": "Œufs",
|
"eggs": "Œufs",
|
||||||
"poissons": "Poissons",
|
"fish": "Poissons",
|
||||||
"arachides": "Arachides",
|
"peanuts": "Arachides",
|
||||||
"soja": "Soja",
|
"soy": "Soja",
|
||||||
"lait": "Lait",
|
"milk": "Lait",
|
||||||
"fruits_a_coque": "Fruits à coque",
|
"tree_nuts": "Fruits à coque",
|
||||||
"celeri": "Céleri",
|
"celery": "Céleri",
|
||||||
"moutarde": "Moutarde",
|
"mustard": "Moutarde",
|
||||||
"graines_de_sesame": "Graines de sésame",
|
"sesame_seeds": "Graines de sésame",
|
||||||
"sulfites": "Sulfites",
|
"sulfites": "Sulfites",
|
||||||
"lupin": "Lupin",
|
"lupin": "Lupin",
|
||||||
"mollusques": "Mollusques"
|
"molluscs": "Mollusques"
|
||||||
},
|
},
|
||||||
"ingredients": {
|
"ingredients": {
|
||||||
"tomate": "Tomate",
|
"tomato": "Tomate",
|
||||||
"oignon": "Oignon",
|
"onion": "Oignon",
|
||||||
"echalote": "Échalote",
|
"shallot": "Échalote",
|
||||||
"ail": "Ail",
|
"garlic": "Ail",
|
||||||
"carotte": "Carotte",
|
"carrot": "Carotte",
|
||||||
"courgette": "Courgette",
|
"zucchini": "Courgette",
|
||||||
"concombre": "Concombre",
|
"cucumber": "Concombre",
|
||||||
"cornichons": "Cornichons",
|
"gherkins": "Cornichons",
|
||||||
"poivron": "Poivron",
|
"bell_pepper": "Poivron",
|
||||||
"champignon": "Champignon",
|
"mushroom": "Champignon",
|
||||||
"cepes": "Cèpes",
|
"porcini": "Cèpes",
|
||||||
"aubergine": "Aubergine",
|
"eggplant": "Aubergine",
|
||||||
"brocoli": "Brocoli",
|
"broccoli": "Brocoli",
|
||||||
"chou_fleur": "Chou-fleur",
|
"cauliflower": "Chou-fleur",
|
||||||
"chou_blanc": "Chou blanc",
|
"white_cabbage": "Chou blanc",
|
||||||
"chou_rouge": "Chou rouge",
|
"red_cabbage": "Chou rouge",
|
||||||
"chou_de_bruxelles": "Chou de Bruxelles",
|
"brussels_sprouts": "Chou de Bruxelles",
|
||||||
"epinard": "Épinard",
|
"spinach": "Épinard",
|
||||||
"blette": "Blette",
|
"swiss_chard": "Blette",
|
||||||
"salade": "Salade",
|
"lettuce": "Salade",
|
||||||
"roquette": "Roquette",
|
"arugula": "Roquette",
|
||||||
"cresson": "Cresson",
|
"watercress": "Cresson",
|
||||||
"poireau": "Poireau",
|
"leek": "Poireau",
|
||||||
"celeri": "Céleri",
|
"celery": "Céleri",
|
||||||
"radis": "Radis",
|
"radish": "Radis",
|
||||||
"betterave": "Betterave",
|
"beetroot": "Betterave",
|
||||||
"navet": "Navet",
|
"turnip": "Navet",
|
||||||
"panais": "Panais",
|
"parsnip": "Panais",
|
||||||
"haricot_vert": "Haricot vert",
|
"green_bean": "Haricot vert",
|
||||||
"petit_pois": "Petit pois",
|
"pea": "Petit pois",
|
||||||
"mais": "Maïs",
|
"corn": "Maïs",
|
||||||
"artichaut": "Artichaut",
|
"artichoke": "Artichaut",
|
||||||
"fenouil": "Fenouil",
|
"fennel": "Fenouil",
|
||||||
"endive": "Endive",
|
"endive": "Endive",
|
||||||
"potiron": "Potiron",
|
"pumpkin": "Potiron",
|
||||||
"butternut": "Butternut",
|
"butternut_squash": "Butternut",
|
||||||
"asperge": "Asperge",
|
"asparagus": "Asperge",
|
||||||
"avocat": "Avocat",
|
"avocado": "Avocat",
|
||||||
"pomme_de_terre": "Pomme de terre",
|
"potato": "Pomme de terre",
|
||||||
"patate_douce": "Patate douce",
|
"sweet_potato": "Patate douce",
|
||||||
"tomates_cerises": "Tomates cerises",
|
"cherry_tomato": "Tomates cerises",
|
||||||
"pak_choi": "Pak-choï",
|
"bok_choy": "Pak-choï",
|
||||||
"germes_de_soja": "Germes de soja",
|
"soybean_sprouts": "Germes de soja",
|
||||||
"shiitake": "Shiitake",
|
"shiitake": "Shiitake",
|
||||||
"daikon": "Daikon",
|
"daikon": "Daikon",
|
||||||
"piment_vert_frais": "Piment vert frais",
|
"fresh_green_chili": "Piment vert frais",
|
||||||
"citron": "Citron",
|
"lemon": "Citron",
|
||||||
"citron_vert": "Citron vert",
|
"lime": "Citron vert",
|
||||||
"pomme": "Pomme",
|
"apple": "Pomme",
|
||||||
"poire": "Poire",
|
"pear": "Poire",
|
||||||
"banane": "Banane",
|
"banana": "Banane",
|
||||||
"orange": "Orange",
|
"orange": "Orange",
|
||||||
"clementine": "Clémentine",
|
"clementine": "Clémentine",
|
||||||
"pamplemousse": "Pamplemousse",
|
"grapefruit": "Pamplemousse",
|
||||||
"fraise": "Fraise",
|
"strawberry": "Fraise",
|
||||||
"framboise": "Framboise",
|
"raspberry": "Framboise",
|
||||||
"myrtille": "Myrtille",
|
"blueberry": "Myrtille",
|
||||||
"mure": "Mûre",
|
"blackberry": "Mûre",
|
||||||
"cerise": "Cerise",
|
"cherry": "Cerise",
|
||||||
"abricot": "Abricot",
|
"apricot": "Abricot",
|
||||||
"peche": "Pêche",
|
"peach": "Pêche",
|
||||||
"prune": "Prune",
|
"plum": "Prune",
|
||||||
"raisin": "Raisin",
|
"grape": "Raisin",
|
||||||
"melon": "Melon",
|
"melon": "Melon",
|
||||||
"pasteque": "Pastèque",
|
"watermelon": "Pastèque",
|
||||||
"ananas": "Ananas",
|
"pineapple": "Ananas",
|
||||||
"mangue": "Mangue",
|
"mango": "Mangue",
|
||||||
"kiwi": "Kiwi",
|
"kiwi": "Kiwi",
|
||||||
"figue": "Figue",
|
"fig": "Figue",
|
||||||
"datte": "Datte",
|
"date": "Datte",
|
||||||
"litchi": "Litchi",
|
"lychee": "Litchi",
|
||||||
"grenade": "Grenade",
|
"pomegranate": "Grenade",
|
||||||
"rhubarbe": "Rhubarbe",
|
"rhubarb": "Rhubarbe",
|
||||||
"coing": "Coing",
|
"quince": "Coing",
|
||||||
"basilic": "Basilic",
|
"basil": "Basilic",
|
||||||
"persil": "Persil",
|
"parsley": "Persil",
|
||||||
"thym": "Thym",
|
"thyme": "Thym",
|
||||||
"romarin": "Romarin",
|
"rosemary": "Romarin",
|
||||||
"laurier": "Laurier",
|
"bay_leaf": "Laurier",
|
||||||
"ciboulette": "Ciboulette",
|
"chives": "Ciboulette",
|
||||||
"coriandre_fraiche": "Coriandre fraîche",
|
"fresh_cilantro": "Coriandre fraîche",
|
||||||
"menthe": "Menthe",
|
"mint": "Menthe",
|
||||||
"origan": "Origan",
|
"oregano": "Origan",
|
||||||
"aneth": "Aneth",
|
"dill": "Aneth",
|
||||||
"estragon": "Estragon",
|
"tarragon": "Estragon",
|
||||||
"sarriette": "Sarriette",
|
"savory": "Sarriette",
|
||||||
"marjolaine": "Marjolaine",
|
"marjoram": "Marjolaine",
|
||||||
"sauge": "Sauge",
|
"sage": "Sauge",
|
||||||
"cerfeuil": "Cerfeuil",
|
"chervil": "Cerfeuil",
|
||||||
"gingembre": "Gingembre",
|
"ginger": "Gingembre",
|
||||||
"citronnelle": "Citronnelle",
|
"lemongrass": "Citronnelle",
|
||||||
"combava": "Combava",
|
"kaffir_lime": "Combava",
|
||||||
"lapin": "Lapin",
|
"rabbit": "Lapin",
|
||||||
"boeuf_hache": "Bœuf haché",
|
"ground_beef": "Bœuf haché",
|
||||||
"steak_de_boeuf": "Steak de bœuf",
|
"beef_steak": "Steak de bœuf",
|
||||||
"roti_de_boeuf": "Rôti de bœuf",
|
"beef_roast": "Rôti de bœuf",
|
||||||
"escalope_de_veau": "Escalope de veau",
|
"veal_cutlet": "Escalope de veau",
|
||||||
"filet_mignon_de_porc": "Filet mignon de porc",
|
"pork_tenderloin": "Filet mignon de porc",
|
||||||
"cote_de_porc": "Côte de porc",
|
"pork_chop": "Côte de porc",
|
||||||
"agneau": "Agneau",
|
"lamb": "Agneau",
|
||||||
"gigot_d_agneau": "Gigot d'agneau",
|
"leg_of_lamb": "Gigot d'agneau",
|
||||||
"lardons": "Lardons",
|
"bacon_lardons": "Lardons",
|
||||||
"bacon": "Bacon",
|
"bacon": "Bacon",
|
||||||
"jambon_blanc": "Jambon blanc",
|
"ham": "Jambon blanc",
|
||||||
"jambon_cru": "Jambon cru",
|
"cured_ham": "Jambon cru",
|
||||||
"saucisse": "Saucisse",
|
"sausage": "Saucisse",
|
||||||
"chorizo": "Chorizo",
|
"chorizo": "Chorizo",
|
||||||
"merguez": "Merguez",
|
"merguez": "Merguez",
|
||||||
"prosciutto": "Prosciutto",
|
"prosciutto": "Prosciutto",
|
||||||
"pancetta": "Pancetta",
|
"pancetta": "Pancetta",
|
||||||
"mortadelle": "Mortadelle",
|
"mortadella": "Mortadelle",
|
||||||
"salami": "Salami",
|
"salami": "Salami",
|
||||||
"poulet": "Poulet",
|
"chicken": "Poulet",
|
||||||
"dinde": "Dinde",
|
"turkey": "Dinde",
|
||||||
"canard": "Canard",
|
"duck": "Canard",
|
||||||
"magret_de_canard": "Magret de canard",
|
"duck_breast": "Magret de canard",
|
||||||
"saumon": "Saumon",
|
"salmon": "Saumon",
|
||||||
"thon": "Thon",
|
"tuna": "Thon",
|
||||||
"cabillaud": "Cabillaud",
|
"cod": "Cabillaud",
|
||||||
"truite": "Truite",
|
"trout": "Truite",
|
||||||
"sardine": "Sardine",
|
"sardine": "Sardine",
|
||||||
"anchois": "Anchois",
|
"anchovy": "Anchois",
|
||||||
"merlan": "Merlan",
|
"whiting": "Merlan",
|
||||||
"surimi": "Surimi",
|
"surimi": "Surimi",
|
||||||
"bar_loup_de_mer": "Bar (loup de mer)",
|
"sea_bass": "Bar (loup de mer)",
|
||||||
"dorade": "Dorade",
|
"sea_bream": "Dorade",
|
||||||
"sole": "Sole",
|
"sole": "Sole",
|
||||||
"turbot": "Turbot",
|
"turbot": "Turbot",
|
||||||
"merlu": "Merlu",
|
"hake": "Merlu",
|
||||||
"colin": "Colin",
|
"pollock": "Colin",
|
||||||
"lieu_noir": "Lieu noir",
|
"saithe": "Lieu noir",
|
||||||
"eglefin": "Églefin",
|
"haddock": "Églefin",
|
||||||
"maquereau": "Maquereau",
|
"mackerel": "Maquereau",
|
||||||
"hareng": "Hareng",
|
"herring": "Hareng",
|
||||||
"rouget": "Rouget",
|
"red_mullet": "Rouget",
|
||||||
"raie": "Raie",
|
"skate": "Raie",
|
||||||
"lotte": "Lotte",
|
"monkfish": "Lotte",
|
||||||
"fletan": "Flétan",
|
"halibut": "Flétan",
|
||||||
"espadon": "Espadon",
|
"swordfish": "Espadon",
|
||||||
"carpe": "Carpe",
|
"carp": "Carpe",
|
||||||
"brochet": "Brochet",
|
"pike": "Brochet",
|
||||||
"perche": "Perche",
|
"perch": "Perche",
|
||||||
"tilapia": "Tilapia",
|
"tilapia": "Tilapia",
|
||||||
"panga": "Panga",
|
"pangasius": "Panga",
|
||||||
"saumon_fume": "Saumon fumé",
|
"smoked_salmon": "Saumon fumé",
|
||||||
"poisson_seche": "Poisson séché",
|
"dried_fish": "Poisson séché",
|
||||||
"crevettes": "Crevettes",
|
"shrimp": "Crevettes",
|
||||||
"langoustines": "Langoustines",
|
"langoustine": "Langoustines",
|
||||||
"homard": "Homard",
|
"lobster": "Homard",
|
||||||
"crabe": "Crabe",
|
"crab": "Crabe",
|
||||||
"langouste": "Langouste",
|
"spiny_lobster": "Langouste",
|
||||||
"moules": "Moules",
|
"mussels": "Moules",
|
||||||
"huitres": "Huîtres",
|
"oysters": "Huîtres",
|
||||||
"saint_jacques": "Saint-Jacques",
|
"scallops": "Saint-Jacques",
|
||||||
"calamar": "Calamar",
|
"squid": "Calamar",
|
||||||
"poulpe": "Poulpe",
|
"octopus": "Poulpe",
|
||||||
"palourdes": "Palourdes",
|
"clams": "Palourdes",
|
||||||
"bulots": "Bulots",
|
"whelks": "Bulots",
|
||||||
"semoule": "Semoule",
|
"semolina": "Semoule",
|
||||||
"couscous": "Couscous",
|
"couscous": "Couscous",
|
||||||
"boulgour": "Boulgour",
|
"bulgur": "Boulgour",
|
||||||
"polenta": "Polenta",
|
"polenta": "Polenta",
|
||||||
"quinoa": "Quinoa",
|
"quinoa": "Quinoa",
|
||||||
"pates": "Pâtes",
|
"pasta": "Pâtes",
|
||||||
"pates_completes": "Pâtes complètes",
|
"whole_wheat_pasta": "Pâtes complètes",
|
||||||
"riz": "Riz",
|
"rice": "Riz",
|
||||||
"riz_basmati": "Riz basmati",
|
"basmati_rice": "Riz basmati",
|
||||||
"riz_complet": "Riz complet",
|
"brown_rice": "Riz complet",
|
||||||
"flocons_d_avoine": "Flocons d'avoine",
|
"oats": "Flocons d'avoine",
|
||||||
"spaghetti": "Spaghetti",
|
"spaghetti": "Spaghetti",
|
||||||
"penne": "Penne",
|
"penne": "Penne",
|
||||||
"tagliatelles": "Tagliatelles",
|
"tagliatelle": "Tagliatelles",
|
||||||
"lasagnes_feuilles": "Lasagnes (feuilles)",
|
"lasagna_sheets": "Lasagnes (feuilles)",
|
||||||
"gnocchi": "Gnocchi",
|
"gnocchi": "Gnocchi",
|
||||||
"riz_arborio": "Riz arborio",
|
"arborio_rice": "Riz arborio",
|
||||||
"nouilles_de_riz": "Nouilles de riz",
|
"rice_noodles": "Nouilles de riz",
|
||||||
"nouilles_udon": "Nouilles udon",
|
"udon_noodles": "Nouilles udon",
|
||||||
"nouilles_soba": "Nouilles soba",
|
"soba_noodles": "Nouilles soba",
|
||||||
"nouilles_chinoises": "Nouilles chinoises",
|
"chinese_noodles": "Nouilles chinoises",
|
||||||
"vermicelles_de_riz": "Vermicelles de riz",
|
"rice_vermicelli": "Vermicelles de riz",
|
||||||
"vermicelles_de_soja": "Vermicelles de soja",
|
"soy_vermicelli": "Vermicelles de soja",
|
||||||
"riz_gluant": "Riz gluant",
|
"sticky_rice": "Riz gluant",
|
||||||
"riz_a_sushi": "Riz à sushi",
|
"sushi_rice": "Riz à sushi",
|
||||||
"riz_jasmin": "Riz jasmin",
|
"jasmine_rice": "Riz jasmin",
|
||||||
"lentilles_vertes": "Lentilles vertes",
|
"green_lentils": "Lentilles vertes",
|
||||||
"lentilles_corail": "Lentilles corail",
|
"red_lentils": "Lentilles corail",
|
||||||
"pois_chiches": "Pois chiches",
|
"chickpeas": "Pois chiches",
|
||||||
"haricots_blancs": "Haricots blancs",
|
"white_beans": "Haricots blancs",
|
||||||
"haricots_rouges": "Haricots rouges",
|
"kidney_beans": "Haricots rouges",
|
||||||
"haricots_noirs": "Haricots noirs",
|
"black_beans": "Haricots noirs",
|
||||||
"pois_casses": "Pois cassés",
|
"split_peas": "Pois cassés",
|
||||||
"feves": "Fèves",
|
"fava_beans": "Fèves",
|
||||||
"edamame": "Edamame",
|
"edamame": "Edamame",
|
||||||
"haricots_pinto": "Haricots pinto",
|
"pinto_beans": "Haricots pinto",
|
||||||
"cacahuetes": "Cacahuètes",
|
"peanuts_shelled": "Cacahuètes",
|
||||||
"amandes": "Amandes",
|
"almonds": "Amandes",
|
||||||
"noix": "Noix",
|
"walnuts": "Noix",
|
||||||
"noisettes": "Noisettes",
|
"hazelnuts": "Noisettes",
|
||||||
"noix_de_cajou": "Noix de cajou",
|
"cashews": "Noix de cajou",
|
||||||
"pistaches": "Pistaches",
|
"pistachios": "Pistaches",
|
||||||
"noix_de_pecan": "Noix de pécan",
|
"pecans": "Noix de pécan",
|
||||||
"poudre_d_amande": "Poudre d'amande",
|
"almond_powder": "Poudre d'amande",
|
||||||
"pignons_de_pin": "Pignons de pin",
|
"pine_nuts": "Pignons de pin",
|
||||||
"graines_de_tournesol": "Graines de tournesol",
|
"sunflower_seeds": "Graines de tournesol",
|
||||||
"graines_de_courge": "Graines de courge",
|
"pumpkin_seeds": "Graines de courge",
|
||||||
"noix_de_coco_rapee": "Noix de coco râpée",
|
"shredded_coconut": "Noix de coco râpée",
|
||||||
"raisins_secs": "Raisins secs",
|
"raisins": "Raisins secs",
|
||||||
"pruneaux": "Pruneaux",
|
"prunes": "Pruneaux",
|
||||||
"abricots_secs": "Abricots secs",
|
"dried_apricots": "Abricots secs",
|
||||||
"graines_de_sesame": "Graines de sésame",
|
"sesame_seeds": "Graines de sésame",
|
||||||
"champignons_noirs": "Champignons noirs",
|
"black_mushrooms": "Champignons noirs",
|
||||||
"algue_nori": "Algue nori",
|
"nori_seaweed": "Algue nori",
|
||||||
"algue_wakame": "Algue wakamé",
|
"wakame_seaweed": "Algue wakamé",
|
||||||
"algue_kombu": "Algue kombu",
|
"kombu_seaweed": "Algue kombu",
|
||||||
"pousses_de_bambou": "Pousses de bambou",
|
"bamboo_shoots": "Pousses de bambou",
|
||||||
"chataignes_d_eau": "Châtaignes d'eau",
|
"water_chestnuts": "Châtaignes d'eau",
|
||||||
"pain": "Pain",
|
"bread": "Pain",
|
||||||
"pain_de_mie": "Pain de mie",
|
"sandwich_bread": "Pain de mie",
|
||||||
"pain_complet": "Pain complet",
|
"whole_wheat_bread": "Pain complet",
|
||||||
"baguette": "Baguette",
|
"baguette": "Baguette",
|
||||||
"pain_de_seigle": "Pain de seigle",
|
"rye_bread": "Pain de seigle",
|
||||||
"chapelure": "Chapelure",
|
"breadcrumbs": "Chapelure",
|
||||||
"pain_a_burger": "Pain à burger",
|
"burger_bun": "Pain à burger",
|
||||||
"pain_brioche": "Pain brioché",
|
"brioche_bun": "Pain brioché",
|
||||||
"pain_a_hot_dog": "Pain à hot-dog",
|
"hot_dog_bun": "Pain à hot-dog",
|
||||||
"pain_pita": "Pain pita",
|
"pita_bread": "Pain pita",
|
||||||
"pain_bagel": "Pain bagel",
|
"bagel": "Pain bagel",
|
||||||
"naan": "Naan",
|
"naan": "Naan",
|
||||||
"pain_wrap": "Pain wrap",
|
"wrap_bread": "Pain wrap",
|
||||||
"pain_viennois": "Pain viennois",
|
"viennese_bread": "Pain viennois",
|
||||||
"pain_de_campagne": "Pain de campagne",
|
"country_bread": "Pain de campagne",
|
||||||
"pain_aux_cereales": "Pain aux céréales",
|
"multigrain_bread": "Pain aux céréales",
|
||||||
"petit_pain": "Petit pain",
|
"bread_roll": "Petit pain",
|
||||||
"pain_suedois": "Pain suédois",
|
"swedish_bread": "Pain suédois",
|
||||||
"pain_sans_gluten": "Pain sans gluten",
|
"gluten_free_bread": "Pain sans gluten",
|
||||||
"biscotte": "Biscotte",
|
"rusk": "Biscotte",
|
||||||
"croutons": "Croûtons",
|
"croutons": "Croûtons",
|
||||||
"focaccia": "Focaccia",
|
"focaccia": "Focaccia",
|
||||||
"ciabatta": "Ciabatta",
|
"ciabatta": "Ciabatta",
|
||||||
"tortilla_de_mais": "Tortilla de maïs",
|
"corn_tortilla": "Tortilla de maïs",
|
||||||
"tortilla_de_ble": "Tortilla de blé",
|
"wheat_tortilla": "Tortilla de blé",
|
||||||
"pate_feuilletee": "Pâte feuilletée",
|
"puff_pastry": "Pâte feuilletée",
|
||||||
"pate_brisee": "Pâte brisée",
|
"shortcrust_pastry": "Pâte brisée",
|
||||||
"pate_a_pizza": "Pâte à pizza",
|
"pizza_dough": "Pâte à pizza",
|
||||||
"pate_a_tarte_sablee": "Pâte à tarte sablée",
|
"sweet_shortcrust_pastry": "Pâte à tarte sablée",
|
||||||
"lait": "Lait",
|
"milk": "Lait",
|
||||||
"beurre": "Beurre",
|
"butter": "Beurre",
|
||||||
"creme_fraiche": "Crème fraîche",
|
"creme_fraiche": "Crème fraîche",
|
||||||
"creme_liquide": "Crème liquide",
|
"liquid_cream": "Crème liquide",
|
||||||
"fromage": "Fromage",
|
"cheese": "Fromage",
|
||||||
"emmental": "Emmental",
|
"emmental": "Emmental",
|
||||||
"gruyere": "Gruyère",
|
"gruyere": "Gruyère",
|
||||||
"parmesan": "Parmesan",
|
"parmesan": "Parmesan",
|
||||||
"mozzarella": "Mozzarella",
|
"mozzarella": "Mozzarella",
|
||||||
"chevre_fromage": "Chèvre (fromage)",
|
"goat_cheese": "Chèvre (fromage)",
|
||||||
"feta": "Feta",
|
"feta": "Feta",
|
||||||
"comte": "Comté",
|
"comte": "Comté",
|
||||||
"fromage_blanc": "Fromage blanc",
|
"fromage_blanc": "Fromage blanc",
|
||||||
"mascarpone": "Mascarpone",
|
"mascarpone": "Mascarpone",
|
||||||
"yaourt": "Yaourt",
|
"yogurt": "Yaourt",
|
||||||
"burrata": "Burrata",
|
"burrata": "Burrata",
|
||||||
"ricotta": "Ricotta",
|
"ricotta": "Ricotta",
|
||||||
"pecorino": "Pecorino",
|
"pecorino": "Pecorino",
|
||||||
"gorgonzola": "Gorgonzola",
|
"gorgonzola": "Gorgonzola",
|
||||||
"cheddar": "Cheddar",
|
"cheddar": "Cheddar",
|
||||||
"oeuf": "Œuf",
|
"egg": "Œuf",
|
||||||
"lait_de_coco": "Lait de coco",
|
"coconut_milk": "Lait de coco",
|
||||||
"creme_de_coco": "Crème de coco",
|
"coconut_cream": "Crème de coco",
|
||||||
"lait_d_amande": "Lait d'amande",
|
"almond_milk": "Lait d'amande",
|
||||||
"lait_d_avoine": "Lait d'avoine",
|
"oat_milk": "Lait d'avoine",
|
||||||
"tofu": "Tofu",
|
"tofu": "Tofu",
|
||||||
"tofu_soyeux": "Tofu soyeux",
|
"silken_tofu": "Tofu soyeux",
|
||||||
"herbes_de_provence": "Herbes de Provence",
|
"herbes_de_provence": "Herbes de Provence",
|
||||||
"poivre_noir": "Poivre noir",
|
"black_pepper": "Poivre noir",
|
||||||
"paprika": "Paprika",
|
"paprika": "Paprika",
|
||||||
"piment_d_espelette": "Piment d'Espelette",
|
"espelette_pepper": "Piment d'Espelette",
|
||||||
"piment_de_cayenne": "Piment de Cayenne",
|
"cayenne_pepper": "Piment de Cayenne",
|
||||||
"cumin": "Cumin",
|
"cumin": "Cumin",
|
||||||
"curry_poudre": "Curry (poudre)",
|
"curry_powder": "Curry (poudre)",
|
||||||
"curcuma": "Curcuma",
|
"turmeric": "Curcuma",
|
||||||
"cannelle": "Cannelle",
|
"cinnamon": "Cannelle",
|
||||||
"muscade": "Muscade",
|
"nutmeg": "Muscade",
|
||||||
"safran": "Safran",
|
"saffron": "Safran",
|
||||||
"clou_de_girofle": "Clou de girofle",
|
"clove": "Clou de girofle",
|
||||||
"vanille_gousse": "Vanille (gousse)",
|
"vanilla_bean": "Vanille (gousse)",
|
||||||
"poivre_blanc": "Poivre blanc",
|
"white_pepper": "Poivre blanc",
|
||||||
"poivre_rose": "Poivre rose",
|
"pink_pepper": "Poivre rose",
|
||||||
"poivre_du_sichuan": "Poivre du Sichuan",
|
"sichuan_pepper": "Poivre du Sichuan",
|
||||||
"paprika_fume": "Paprika fumé",
|
"smoked_paprika": "Paprika fumé",
|
||||||
"piment_oiseau": "Piment oiseau",
|
"bird_eye_chili": "Piment oiseau",
|
||||||
"baies_de_genievre": "Baies de genièvre",
|
"juniper_berries": "Baies de genièvre",
|
||||||
"anis_etoile_badiane": "Anis étoilé (badiane)",
|
"star_anise": "Anis étoilé (badiane)",
|
||||||
"anis_vert": "Anis vert",
|
"green_anise": "Anis vert",
|
||||||
"graines_de_fenouil": "Graines de fenouil",
|
"fennel_seeds": "Graines de fenouil",
|
||||||
"sumac": "Sumac",
|
"sumac": "Sumac",
|
||||||
"nigelle": "Nigelle",
|
"nigella": "Nigelle",
|
||||||
"quatre_epices": "Quatre épices",
|
"allspice": "Quatre épices",
|
||||||
"colombo_poudre": "Colombo (poudre)",
|
"colombo_powder": "Colombo (poudre)",
|
||||||
"baharat": "Baharat",
|
"baharat": "Baharat",
|
||||||
"raifort": "Raifort",
|
"horseradish": "Raifort",
|
||||||
"sel_aux_herbes": "Sel aux herbes",
|
"herb_salt": "Sel aux herbes",
|
||||||
"sel_de_celeri": "Sel de céleri",
|
"celery_salt": "Sel de céleri",
|
||||||
"fleur_de_sel": "Fleur de sel",
|
"fleur_de_sel": "Fleur de sel",
|
||||||
"sel": "Sel",
|
"salt": "Sel",
|
||||||
"cinq_epices": "Cinq épices",
|
"five_spice": "Cinq épices",
|
||||||
"garam_masala": "Garam masala",
|
"garam_masala": "Garam masala",
|
||||||
"graines_de_coriandre": "Graines de coriandre",
|
"coriander_seeds": "Graines de coriandre",
|
||||||
"cardamome": "Cardamome",
|
"cardamom": "Cardamome",
|
||||||
"fenugrec": "Fenugrec",
|
"fenugreek": "Fenugrec",
|
||||||
"piment_jalapeno": "Piment jalapeño",
|
"jalapeno": "Piment jalapeño",
|
||||||
"piment_chipotle": "Piment chipotle",
|
"chipotle": "Piment chipotle",
|
||||||
"piment_poblano": "Piment poblano",
|
"poblano_pepper": "Piment poblano",
|
||||||
"piment_habanero": "Piment habanero",
|
"habanero": "Piment habanero",
|
||||||
"ras_el_hanout": "Ras el hanout",
|
"ras_el_hanout": "Ras el hanout",
|
||||||
"za_atar": "Za'atar",
|
"zaatar": "Za'atar",
|
||||||
"sauce_soja": "Sauce soja",
|
"soy_sauce": "Sauce soja",
|
||||||
"moutarde": "Moutarde",
|
"mustard": "Moutarde",
|
||||||
"mayonnaise": "Mayonnaise",
|
"mayonnaise": "Mayonnaise",
|
||||||
"ketchup": "Ketchup",
|
"ketchup": "Ketchup",
|
||||||
"tabasco": "Tabasco",
|
"tabasco": "Tabasco",
|
||||||
"sauce_worcestershire": "Sauce Worcestershire",
|
"worcestershire_sauce": "Sauce Worcestershire",
|
||||||
"sauce_nuoc_mam": "Sauce nuoc-mâm",
|
"fish_sauce": "Sauce nuoc-mâm",
|
||||||
"wasabi": "Wasabi",
|
"wasabi": "Wasabi",
|
||||||
"harissa": "Harissa",
|
"harissa": "Harissa",
|
||||||
"pate_de_curry": "Pâte de curry",
|
"curry_paste": "Pâte de curry",
|
||||||
"beurre_de_cacahuete": "Beurre de cacahuète",
|
"peanut_butter": "Beurre de cacahuète",
|
||||||
"moutarde_de_dijon": "Moutarde de Dijon",
|
"dijon_mustard": "Moutarde de Dijon",
|
||||||
"moutarde_a_l_ancienne": "Moutarde à l'ancienne",
|
"wholegrain_mustard": "Moutarde à l'ancienne",
|
||||||
"sauce_barbecue": "Sauce barbecue",
|
"barbecue_sauce": "Sauce barbecue",
|
||||||
"sauce_tartare": "Sauce tartare",
|
"tartar_sauce": "Sauce tartare",
|
||||||
"sauce_cocktail": "Sauce cocktail",
|
"cocktail_sauce": "Sauce cocktail",
|
||||||
"sauce_bearnaise": "Sauce béarnaise",
|
"bearnaise_sauce": "Sauce béarnaise",
|
||||||
"sauce_hollandaise": "Sauce hollandaise",
|
"hollandaise_sauce": "Sauce hollandaise",
|
||||||
"sauce_bechamel": "Sauce béchamel",
|
"bechamel_sauce": "Sauce béchamel",
|
||||||
"sauce_teriyaki": "Sauce teriyaki",
|
"teriyaki_sauce": "Sauce teriyaki",
|
||||||
"sauce_ponzu": "Sauce ponzu",
|
"ponzu_sauce": "Sauce ponzu",
|
||||||
"chimichurri": "Chimichurri",
|
"chimichurri": "Chimichurri",
|
||||||
"pesto_rouge_tomates_sechees": "Pesto rouge (tomates séchées)",
|
"red_pesto": "Pesto rouge (tomates séchées)",
|
||||||
"pesto": "Pesto",
|
"pesto": "Pesto",
|
||||||
"sauce_huitre": "Sauce huître",
|
"oyster_sauce": "Sauce huître",
|
||||||
"sauce_hoisin": "Sauce hoisin",
|
"hoisin_sauce": "Sauce hoisin",
|
||||||
"sauce_sriracha": "Sauce sriracha",
|
"sriracha": "Sauce sriracha",
|
||||||
"sauce_sweet_chili": "Sauce sweet chili",
|
"sweet_chili_sauce": "Sauce sweet chili",
|
||||||
"miso": "Miso",
|
"miso": "Miso",
|
||||||
"pate_de_crevettes": "Pâte de crevettes",
|
"shrimp_paste": "Pâte de crevettes",
|
||||||
"pate_de_curry_rouge_thai": "Pâte de curry rouge (thaï)",
|
"red_curry_paste": "Pâte de curry rouge (thaï)",
|
||||||
"pate_de_curry_vert_thai": "Pâte de curry vert (thaï)",
|
"green_curry_paste": "Pâte de curry vert (thaï)",
|
||||||
"tahini": "Tahini",
|
"tahini": "Tahini",
|
||||||
"huile_d_olive": "Huile d'olive",
|
"olive_oil": "Huile d'olive",
|
||||||
"huile_de_tournesol": "Huile de tournesol",
|
"sunflower_oil": "Huile de tournesol",
|
||||||
"huile_de_colza": "Huile de colza",
|
"rapeseed_oil": "Huile de colza",
|
||||||
"huile_de_coco": "Huile de coco",
|
"coconut_oil": "Huile de coco",
|
||||||
"huile_de_sesame": "Huile de sésame",
|
"sesame_oil": "Huile de sésame",
|
||||||
"vinaigre_de_cidre": "Vinaigre de cidre",
|
"cider_vinegar": "Vinaigre de cidre",
|
||||||
"vinaigre_blanc": "Vinaigre blanc",
|
"white_vinegar": "Vinaigre blanc",
|
||||||
"vinaigre_balsamique": "Vinaigre balsamique",
|
"balsamic_vinegar": "Vinaigre balsamique",
|
||||||
"capres": "Câpres",
|
"capers": "Câpres",
|
||||||
"olives": "Olives",
|
"olives": "Olives",
|
||||||
"vin_blanc_cuisine": "Vin blanc (cuisine)",
|
"white_wine": "Vin blanc (cuisine)",
|
||||||
"vin_rouge_cuisine": "Vin rouge (cuisine)",
|
"red_wine": "Vin rouge (cuisine)",
|
||||||
"vinaigre_de_vin_rouge": "Vinaigre de vin rouge",
|
"red_wine_vinegar": "Vinaigre de vin rouge",
|
||||||
"vinaigre_de_vin_blanc": "Vinaigre de vin blanc",
|
"white_wine_vinegar": "Vinaigre de vin blanc",
|
||||||
"vinaigre_de_xeres": "Vinaigre de xérès",
|
"sherry_vinegar": "Vinaigre de xérès",
|
||||||
"huile_de_noix": "Huile de noix",
|
"walnut_oil": "Huile de noix",
|
||||||
"huile_de_noisette": "Huile de noisette",
|
"hazelnut_oil": "Huile de noisette",
|
||||||
"huile_d_arachide": "Huile d'arachide",
|
"peanut_oil": "Huile d'arachide",
|
||||||
"huile_pimentee": "Huile pimentée",
|
"chili_oil": "Huile pimentée",
|
||||||
"vinaigre_de_riz": "Vinaigre de riz",
|
"rice_vinegar": "Vinaigre de riz",
|
||||||
"mirin": "Mirin",
|
"mirin": "Mirin",
|
||||||
"sake_cuisine": "Saké (cuisine)",
|
"sake": "Saké (cuisine)",
|
||||||
"jus_de_citron": "Jus de citron",
|
"lemon_juice": "Jus de citron",
|
||||||
"jus_de_citron_vert": "Jus de citron vert",
|
"lime_juice": "Jus de citron vert",
|
||||||
"jus_d_orange": "Jus d'orange",
|
"orange_juice": "Jus d'orange",
|
||||||
"jus_de_pomme": "Jus de pomme",
|
"apple_juice": "Jus de pomme",
|
||||||
"jus_de_raisin": "Jus de raisin",
|
"grape_juice": "Jus de raisin",
|
||||||
"jus_de_tomate": "Jus de tomate",
|
"tomato_juice": "Jus de tomate",
|
||||||
"jus_de_cranberry": "Jus de cranberry",
|
"cranberry_juice": "Jus de cranberry",
|
||||||
"cafe": "Café",
|
"coffee": "Café",
|
||||||
"the": "Thé",
|
"tea": "Thé",
|
||||||
"biere_cuisine": "Bière (cuisine)",
|
"beer": "Bière (cuisine)",
|
||||||
"cidre_cuisine": "Cidre (cuisine)",
|
"cider": "Cidre (cuisine)",
|
||||||
"champagne_vin_petillant_cuisine": "Champagne / vin pétillant (cuisine)",
|
"champagne": "Champagne / vin pétillant (cuisine)",
|
||||||
"porto_cuisine": "Porto (cuisine)",
|
"port_wine": "Porto (cuisine)",
|
||||||
"vin_jaune_cuisine": "Vin jaune (cuisine)",
|
"vin_jaune": "Vin jaune (cuisine)",
|
||||||
"cognac": "Cognac",
|
"cognac": "Cognac",
|
||||||
"rhum": "Rhum",
|
"rum": "Rhum",
|
||||||
"whisky": "Whisky",
|
"whisky": "Whisky",
|
||||||
"vodka": "Vodka",
|
"vodka": "Vodka",
|
||||||
"farine_de_ble": "Farine de blé",
|
"wheat_flour": "Farine de blé",
|
||||||
"farine_complete": "Farine complète",
|
"whole_wheat_flour": "Farine complète",
|
||||||
"farine_de_mais": "Farine de maïs",
|
"corn_flour": "Farine de maïs",
|
||||||
"farine_de_sarrasin": "Farine de sarrasin",
|
"buckwheat_flour": "Farine de sarrasin",
|
||||||
"farine_de_riz": "Farine de riz",
|
"rice_flour": "Farine de riz",
|
||||||
"bouillon_cube_legumes": "Bouillon cube légumes",
|
"vegetable_stock_cube": "Bouillon cube légumes",
|
||||||
"bouillon_cube_volaille": "Bouillon cube volaille",
|
"chicken_stock_cube": "Bouillon cube volaille",
|
||||||
"concentre_de_tomate": "Concentré de tomate",
|
"tomato_paste": "Concentré de tomate",
|
||||||
"coulis_de_tomate": "Coulis de tomate",
|
"tomato_coulis": "Coulis de tomate",
|
||||||
"tomates_pelees_conserve": "Tomates pelées (conserve)",
|
"canned_peeled_tomatoes": "Tomates pelées (conserve)",
|
||||||
"tomates_sechees": "Tomates séchées",
|
"sun_dried_tomatoes": "Tomates séchées",
|
||||||
"fond_de_veau": "Fond de veau",
|
"veal_stock": "Fond de veau",
|
||||||
"fond_de_volaille": "Fond de volaille",
|
"chicken_stock": "Fond de volaille",
|
||||||
"bouillon_cube_boeuf": "Bouillon cube bœuf",
|
"beef_stock_cube": "Bouillon cube bœuf",
|
||||||
"bouillon_cube_poisson": "Bouillon cube poisson",
|
"fish_stock_cube": "Bouillon cube poisson",
|
||||||
"bouillon_de_legumes": "Bouillon de légumes",
|
"vegetable_broth": "Bouillon de légumes",
|
||||||
"bouillon_de_volaille": "Bouillon de volaille",
|
"chicken_broth": "Bouillon de volaille",
|
||||||
"bouillon_de_boeuf": "Bouillon de bœuf",
|
"beef_broth": "Bouillon de bœuf",
|
||||||
"court_bouillon": "Court-bouillon",
|
"court_bouillon": "Court-bouillon",
|
||||||
"dashi_bouillon_japonais": "Dashi (bouillon japonais)",
|
"dashi": "Dashi (bouillon japonais)",
|
||||||
"bisque_de_crustaces": "Bisque de crustacés",
|
"shellfish_bisque": "Bisque de crustacés",
|
||||||
"farine_de_tapioca": "Farine de tapioca",
|
"tapioca_flour": "Farine de tapioca",
|
||||||
"masa_harina": "Masa harina",
|
"masa_harina": "Masa harina",
|
||||||
"eau": "Eau",
|
"water": "Eau",
|
||||||
"eau_gazeuse": "Eau gazeuse",
|
"sparkling_water": "Eau gazeuse",
|
||||||
"eau_de_fleur_d_oranger": "Eau de fleur d'oranger",
|
"orange_blossom_water": "Eau de fleur d'oranger",
|
||||||
"eau_de_rose": "Eau de rose",
|
"rose_water": "Eau de rose",
|
||||||
"fumet_de_poisson": "Fumet de poisson",
|
"fish_fumet": "Fumet de poisson",
|
||||||
"levure_boulangere": "Levure boulangère",
|
"bakers_yeast": "Levure boulangère",
|
||||||
"levure_chimique": "Levure chimique",
|
"baking_powder": "Levure chimique",
|
||||||
"maizena": "Maïzena",
|
"cornstarch": "Maïzena",
|
||||||
"farine_de_lupin": "Farine de lupin",
|
"lupin_flour": "Farine de lupin",
|
||||||
"gelatine": "Gélatine",
|
"gelatin": "Gélatine",
|
||||||
"bicarbonate_de_soude": "Bicarbonate de soude",
|
"baking_soda": "Bicarbonate de soude",
|
||||||
"fecule_de_pomme_de_terre": "Fécule de pomme de terre",
|
"potato_starch": "Fécule de pomme de terre",
|
||||||
"sucre": "Sucre",
|
"sugar": "Sucre",
|
||||||
"miel": "Miel",
|
"honey": "Miel",
|
||||||
"sirop_d_erable": "Sirop d'érable",
|
"maple_syrup": "Sirop d'érable",
|
||||||
"sucre_roux": "Sucre roux",
|
"brown_sugar": "Sucre roux",
|
||||||
"sucre_glace": "Sucre glace",
|
"powdered_sugar": "Sucre glace",
|
||||||
"cassonade": "Cassonade",
|
"demerara_sugar": "Cassonade",
|
||||||
"chocolat_noir": "Chocolat noir",
|
"dark_chocolate": "Chocolat noir",
|
||||||
"chocolat_au_lait": "Chocolat au lait",
|
"milk_chocolate": "Chocolat au lait",
|
||||||
"chocolat_blanc": "Chocolat blanc",
|
"white_chocolate": "Chocolat blanc",
|
||||||
"pepites_de_chocolat": "Pépites de chocolat",
|
"chocolate_chips": "Pépites de chocolat",
|
||||||
"cacao_en_poudre": "Cacao en poudre",
|
"cocoa_powder": "Cacao en poudre",
|
||||||
"extrait_de_vanille": "Extrait de vanille",
|
"vanilla_extract": "Extrait de vanille",
|
||||||
"sucre_de_palme": "Sucre de palme",
|
"palm_sugar": "Sucre de palme",
|
||||||
"sirop_de_sucre_de_canne": "Sirop de sucre de canne"
|
"cane_syrup": "Sirop de sucre de canne"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue