- Add product search screen (/products/search) as primary add flow; "Add" button on products list opens search, manual entry remains as fallback - Add to shelf bottom sheet with AnimatedSwitcher success view (green checkmark) and SnackBar confirmation on the search screen via onAdded callback - Manual add (AddProductScreen) shows SnackBar on success before popping back - Extend AddProductScreen with optional nutrition fields (calories, protein, fat, carbs, fiber); auto-fills from catalog selection and auto-expands section - Auto-upsert catalog product on backend when nutrition data is provided without a primary_product_id, linking the user product to the catalog - Add fiber_per_100g field to CatalogProduct model and CreateRequest - Add 16 new L10n keys across all 12 locales (addProduct, addManually, searchProducts, quantity, storageDays, addToShelf, nutritionOptional, calories, protein, fat, carbs, fiber, productAddedToShelf, etc.) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
204 lines
7.3 KiB
Plaintext
204 lines
7.3 KiB
Plaintext
{
|
|
"@@locale": "fr",
|
|
"appTitle": "FoodAI",
|
|
"greetingMorning": "Bonjour",
|
|
"greetingAfternoon": "Bon après-midi",
|
|
"greetingEvening": "Bonsoir",
|
|
"caloriesUnit": "kcal",
|
|
"gramsUnit": "g",
|
|
"goalLabel": "objectif :",
|
|
"consumed": "Consommé",
|
|
"remaining": "Restant",
|
|
"exceeded": "Dépassé",
|
|
"proteinLabel": "Protéines",
|
|
"fatLabel": "Lipides",
|
|
"carbsLabel": "Glucides",
|
|
"today": "Aujourd'hui",
|
|
"yesterday": "Hier",
|
|
"mealsSection": "Repas",
|
|
"addDish": "Ajouter un plat",
|
|
"scanDish": "Scanner",
|
|
"menu": "Menu",
|
|
"dishHistory": "Historique des plats",
|
|
"recommendCook": "Nous recommandons de cuisiner",
|
|
"camera": "Appareil photo",
|
|
"gallery": "Galerie",
|
|
"analyzingPhoto": "Analyse de la photo...",
|
|
"inQueue": "Vous êtes en file d'attente",
|
|
"queuePosition": "Position {position}",
|
|
"@queuePosition": {
|
|
"placeholders": {
|
|
"position": {
|
|
"type": "int"
|
|
}
|
|
}
|
|
},
|
|
"processing": "Traitement...",
|
|
"upgradePrompt": "Passer la file ? Passez à Premium →",
|
|
"recognitionFailed": "Reconnaissance échouée. Réessayez.",
|
|
"dishRecognition": "Reconnaissance de plats",
|
|
"all": "Tous",
|
|
"dishRecognized": "Plat reconnu",
|
|
"recognizing": "Reconnaissance en cours…",
|
|
"recognitionError": "Erreur de reconnaissance",
|
|
"dishResultTitle": "Plat reconnu",
|
|
"selectDish": "Sélectionner un plat",
|
|
"dishNotRecognized": "Plat non reconnu",
|
|
"tryAgain": "Réessayer",
|
|
"nutritionApproximate": "Les valeurs nutritionnelles sont approximatives — estimées à partir de la photo.",
|
|
"portion": "Portion",
|
|
"mealType": "Type de repas",
|
|
"dateLabel": "Date",
|
|
"addToJournal": "Ajouter au journal",
|
|
"addFailed": "Échec de l'ajout. Réessayez.",
|
|
"historyTitle": "Historique des reconnaissances",
|
|
"historyLoadError": "Impossible de charger l'historique",
|
|
"retry": "Réessayer",
|
|
"noHistory": "Aucune reconnaissance pour l'instant",
|
|
"profileTitle": "Profil",
|
|
"edit": "Modifier",
|
|
"bodyParams": "PARAMÈTRES CORPORELS",
|
|
"goalActivity": "OBJECTIF & ACTIVITÉ",
|
|
"nutrition": "NUTRITION",
|
|
"settings": "PARAMÈTRES",
|
|
"height": "Taille",
|
|
"weight": "Poids",
|
|
"age": "Âge",
|
|
"gender": "Sexe",
|
|
"genderMale": "Masculin",
|
|
"genderFemale": "Féminin",
|
|
"goalLoss": "Perte de poids",
|
|
"goalMaintain": "Maintien",
|
|
"goalGain": "Prise de masse",
|
|
"activityLow": "Faible",
|
|
"activityMedium": "Moyenne",
|
|
"activityHigh": "Élevée",
|
|
"calorieGoal": "Objectif calorique",
|
|
"mealTypes": "Types de repas",
|
|
"formulaNote": "Calculé avec la formule de Mifflin-St Jeor",
|
|
"language": "Langue",
|
|
"notSet": "Non défini",
|
|
"calorieHint": "Saisissez les paramètres corporels pour calculer l'objectif calorique",
|
|
"logout": "Se déconnecter",
|
|
"editProfile": "Modifier le profil",
|
|
"cancel": "Annuler",
|
|
"save": "Enregistrer",
|
|
"nameLabel": "Nom",
|
|
"heightCm": "Taille (cm)",
|
|
"weightKg": "Poids (kg)",
|
|
"birthDate": "Date de naissance",
|
|
"nameRequired": "Saisir le nom",
|
|
"profileUpdated": "Profil mis à jour",
|
|
"profileSaveFailed": "Échec de l'enregistrement",
|
|
"mealTypeBreakfast": "Petit-déjeuner",
|
|
"mealTypeSecondBreakfast": "Deuxième petit-déjeuner",
|
|
"mealTypeLunch": "Déjeuner",
|
|
"mealTypeAfternoonSnack": "Goûter",
|
|
"mealTypeDinner": "Dîner",
|
|
"mealTypeSnack": "Collation",
|
|
"navHome": "Accueil",
|
|
"navProducts": "Produits",
|
|
"navRecipes": "Recettes",
|
|
"addFromReceiptOrPhoto": "Ajouter depuis ticket ou photo",
|
|
"chooseMethod": "Choisir la méthode",
|
|
"photoReceipt": "Photographier le ticket",
|
|
"photoReceiptSubtitle": "Reconnaissance de tous les produits du ticket",
|
|
"photoProducts": "Photographier les produits",
|
|
"photoProductsSubtitle": "Réfrigérateur, table, étagère — jusqu'à 3 photos",
|
|
"addPackagedFood": "Ajouter un aliment emballé",
|
|
"scanBarcode": "Scanner le code-barres",
|
|
"portionWeightG": "Poids de la portion (g)",
|
|
"productNotFound": "Produit introuvable",
|
|
"enterManually": "Saisir manuellement",
|
|
"perHundredG": "pour 100 g",
|
|
"searchFoodHint": "Rechercher produits et plats...",
|
|
"recentlyUsedLabel": "Récemment utilisés",
|
|
"productsSection": "Produits",
|
|
"dishesSection": "Plats",
|
|
"noResultsForQuery": "Rien trouvé pour \"{query}\"",
|
|
"@noResultsForQuery": {
|
|
"placeholders": {
|
|
"query": {
|
|
"type": "String"
|
|
}
|
|
}
|
|
},
|
|
"servingsLabel": "Portions",
|
|
"addToDiary": "Ajouter au journal",
|
|
"scanDishPhoto": "Scanner une photo",
|
|
"planningForDate": "",
|
|
"@planningForDate": {
|
|
"placeholders": {
|
|
"date": {
|
|
"type": "String"
|
|
}
|
|
}
|
|
},
|
|
"markAsEaten": "Marquer comme mangé",
|
|
"plannedMealLabel": "Planifié",
|
|
"generateWeekLabel": "Planifier la semaine",
|
|
"generateWeekSubtitle": "L'IA créera un menu avec petit-déjeuner, déjeuner et dîner pour toute la semaine",
|
|
"generatingMenu": "Génération du menu...",
|
|
"dayPlannedLabel": "Jour planifié",
|
|
"planMenuButton": "Planifier les repas",
|
|
"planMenuTitle": "Que planifier ?",
|
|
"planOptionSingleMeal": "Un repas",
|
|
"planOptionSingleMealDesc": "Choisir un jour et un type de repas",
|
|
"planOptionDay": "Un jour",
|
|
"planOptionDayDesc": "Tous les repas d'une journée",
|
|
"planOptionDays": "Plusieurs jours",
|
|
"planOptionDaysDesc": "Personnaliser la période",
|
|
"planOptionWeek": "Une semaine",
|
|
"planOptionWeekDesc": "7 jours d'un coup",
|
|
"planSelectDate": "Choisir une date",
|
|
"planSelectMealType": "Type de repas",
|
|
"planSelectRange": "Choisir la période",
|
|
"planGenerateButton": "Planifier",
|
|
"planGenerating": "Génération du plan…",
|
|
"planSuccess": "Menu planifié !",
|
|
"planProductsTitle": "Produits pour le menu",
|
|
"planProductsSubtitle": "L'IA tiendra compte des produits sélectionnés lors de la génération des recettes",
|
|
"planProductsEmpty": "Aucun produit ajouté",
|
|
"planProductsEmptyMessage": "Ajoutez des produits que vous avez à la maison — l'IA suggérera des recettes à partir de ce que vous avez déjà",
|
|
"planProductsAddProducts": "Ajouter des produits",
|
|
"planProductsContinue": "Continuer",
|
|
"planProductsSkip": "Ignorer la sélection des produits",
|
|
"planProductsSkipNoProducts": "Planifier sans produits",
|
|
"planProductsSelectAll": "Tout sélectionner",
|
|
"planProductsDeselectAll": "Tout désélectionner",
|
|
"recentScans": "Scans récents",
|
|
"seeAllScans": "Tout voir",
|
|
"productJobHistoryTitle": "Historique des scans",
|
|
"jobTypeReceipt": "Reçu",
|
|
"jobTypeProducts": "Produits",
|
|
"scanSubmitting": "Envoi...",
|
|
"processingProducts": "Traitement...",
|
|
"clearAllProducts": "Tout effacer",
|
|
"clearAllConfirmTitle": "Effacer tous les produits ?",
|
|
"clearAllConfirmMessage": "Tous les produits seront définitivement supprimés.",
|
|
"addManually": "Manuellement",
|
|
"scan": "Scanner",
|
|
"addProduct": "Ajouter",
|
|
"searchProducts": "Rechercher des produits",
|
|
"searchProductsHint": "Tapez un nom de produit ou ajoutez manuellement",
|
|
"noSearchResults": "Aucun résultat pour \"{query}\"",
|
|
"@noSearchResults": {
|
|
"placeholders": {
|
|
"query": {
|
|
"type": "String"
|
|
}
|
|
}
|
|
},
|
|
"quantity": "Quantité",
|
|
"storageDays": "Jours de conservation",
|
|
"addToShelf": "Ajouter au garde-manger",
|
|
"errorGeneric": "Une erreur est survenue",
|
|
"nutritionOptional": "Nutrition pour 100g (facultatif)",
|
|
"calories": "Calories",
|
|
"protein": "Protéines",
|
|
"fat": "Graisses",
|
|
"carbs": "Glucides",
|
|
"fiber": "Fibres",
|
|
"productAddedToShelf": "Ajouté au garde-manger"
|
|
}
|