Files
EverShelf/translations/fr.json
T
dadaloop82 d33b0ca2fe Harden security, modularize API bootstrap, and fix scale SSE auth.
Block web access to sensitive paths, require API_TOKEN for mutations, encrypt GitHub issue credentials in .env, auto-provision tokens for same-origin clients, and pass api_token in scale relay URLs since EventSource cannot send headers.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-06-03 18:04:19 +00:00

1441 lines
74 KiB
JSON
Raw Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
{
"app": {
"name": "EverShelf",
"loading": "Chargement..."
},
"nav": {
"title": "EverShelf",
"home": "Accueil",
"inventory": "Garde-manger",
"recipes": "Recettes",
"shopping": "Courses",
"log": "Journal",
"settings": "Paramètres"
},
"btn": {
"back": "← Retour",
"save": "💾 Enregistrer",
"cancel": "✕ Annuler",
"close": "Fermer",
"add": "✅ Ajouter",
"delete": "Supprimer",
"edit": "✏️ Modifier",
"use": "Utiliser",
"edit_item": "Modifier",
"search": "🔍 Rechercher",
"go": "✅ Valider",
"toggle_password": "👁️ Afficher/Masquer",
"load_more": "Charger plus...",
"save_config": "💾 Enregistrer la configuration",
"save_product": "💾 Enregistrer le produit",
"restart": "↺ Redémarrer",
"reset_default": "↺ Rétablir les valeurs par défaut",
"save_info": "💾 Enregistrer les informations",
"retry": "🔄 Réessayer",
"yes_short": "Oui",
"no_short": "Non"
},
"form": {
"select_placeholder": "-- Sélectionner --"
},
"locations": {
"dispensa": "Garde-manger",
"frigo": "Réfrigérateur",
"freezer": "Congélateur",
"altro": "Autre"
},
"categories": {
"latticini": "Produits laitiers",
"carne": "Viande",
"pesce": "Poisson",
"frutta": "Fruits",
"verdura": "Légumes",
"pasta": "Pâtes & Riz",
"pane": "Pain & Boulangerie",
"surgelati": "Surgelés",
"bevande": "Boissons",
"condimenti": "Condiments",
"snack": "Snacks & Sucreries",
"conserve": "Conserves",
"cereali": "Céréales & Légumineuses",
"igiene": "Hygiène",
"pulizia": "Entretien",
"altro": "Autre",
"select": "-- Sélectionner --"
},
"units": {
"pz": "pcs",
"conf": "pkg",
"g": "g",
"ml": "ml",
"pieces": "Pièces",
"grams": "Grammes",
"box": "Paquet",
"boxes": "Paquets",
"millilitres": "Millilitres",
"from": "de"
},
"shopping_sections": {
"frutta_verdura": "Fruits & Légumes",
"carne_pesce": "Viande & Poisson",
"latticini": "Produits laitiers & Frais",
"pane_dolci": "Pain & Pâtisseries",
"pasta": "Pâtes & Céréales",
"conserve": "Conserves & Sauces",
"surgelati": "Surgelés",
"bevande": "Boissons",
"pulizia_igiene": "Nettoyage & Hygiène",
"altro": "Autre"
},
"dashboard": {
"expired_title": "🚫 Périmé",
"expiring_title": "⏰ Expire bientôt",
"stats_period": "📊 30 derniers jours",
"opened_title": "📦 Produits ouverts",
"review_title": "🔍 À vérifier",
"review_hint": "Quantités inhabituelles. Confirmez si elles sont correctes ou modifiez-les.",
"quick_recipe": "Recette rapide avec les produits qui expirent",
"banner_review_title": "Quantité anormale",
"banner_review_action_ok": "C'est correct",
"banner_review_action_finish": "🗑️ Tout fini",
"banner_review_action_edit": "Corriger",
"banner_review_action_weigh": "Peser",
"banner_review_dismiss": "Ignorer",
"banner_prediction_title": "Consommation à vérifier",
"banner_prediction_hint": "L'estimation de consommation s'adapte aux données récentes : confirmez uniquement si la quantité actuelle est correcte.",
"banner_prediction_action_confirm": "Confirmer {qty} {unit}",
"banner_prediction_action_weigh": "Peser maintenant",
"banner_prediction_action_edit": "Mettre à jour la quantité",
"banner_expired_title": "Produit périmé",
"banner_expired_today": "Périmé aujourd'hui",
"banner_expired_days": "Périmé il y a {days} jours",
"banner_expired_action_use": "Utiliser quand même",
"banner_expired_action_finished": "Je l'ai terminé !",
"banner_expired_action_throw": "Je l'ai jeté",
"banner_expired_action_edit": "Corriger la date",
"banner_anomaly_action_edit": "Corriger l'inventaire",
"banner_anomaly_action_dismiss": "La quantité est correcte",
"banner_no_expiry_title": "Date manquante : {name}",
"banner_no_expiry_detail": "Ce produit n'a pas de date de péremption. Voulez-vous en ajouter une ou confirmer qu'il ne périme pas ?",
"banner_no_expiry_action_set": "Définir une date de péremption",
"banner_no_expiry_action_dismiss": "Ne périme pas ✓",
"banner_no_expiry_toast_dismissed": "Marqué comme « sans date limite »",
"banner_expiring_title": "Expire bientôt",
"banner_expiring_today": "Expire aujourd'hui !",
"banner_expiring_tomorrow": "Expire demain",
"banner_expiring_days": "Expire dans {days} jours",
"banner_expiring_action_use": "Utiliser maintenant",
"banner_finished_title": "terminé ?",
"banner_finished_detail": "J'ai enregistré que {name} a atteint zéro stock. Est-il vraiment épuisé ou en avez-vous encore ?",
"banner_finished_action_yes": "Oui, c'est fini",
"banner_finished_action_no": "Non, j'en ai encore",
"banner_review_unusual_pkg_title": "Taille de paquet inhabituelle",
"banner_review_unusual_pkg_detail": "Vous avez défini un paquet de {qty} {unit} — la taille semble très grande. Vérifiez si c'est correct ou modifiez.",
"banner_review_low_qty_title": "Quantité très faible",
"banner_review_low_qty_detail": "Vous n'avez que {qty} en stock — cela semble très peu, peut-être une erreur de saisie. Confirmez si c'est correct.",
"banner_review_high_qty_title": "Quantité inhabituellement élevée",
"banner_review_high_qty_detail": "Vous avez {qty} en stock — le chiffre semble très élevé. Confirmez si c'est correct ou modifiez.",
"banner_prediction_rate_day": "Moyenne ~{n} {unit}/jour",
"banner_prediction_rate_week": "Moyenne ~{n} {unit}/semaine",
"banner_prediction_days_ago": "Il y a {n} jours vous avez réapprovisionné",
"banner_prediction_more": "estimation précédente : {expected} {unit}{time} ; quantité actuelle : {actual} {unit}.",
"banner_prediction_less": "estimation : {expected} {unit}{time} ; quantité actuelle : {actual} {unit}. Si votre rythme d'utilisation a changé, la prévision se met à jour automatiquement.",
"banner_finished_zero": "L'inventaire indique zéro, mais les mouvements enregistrés suggèrent qu'il ne devrait pas être vide.",
"banner_finished_expected": "D'après les enregistrements vous devriez avoir encore {qty} {unit}.",
"banner_finished_check": "Pouvez-vous vérifier ?",
"banner_anomaly_phantom_title": "vous avez plus de stock que prévu",
"banner_anomaly_phantom_detail": "L'inventaire indique {inv_qty} {unit}, mais selon les enregistrements vous ne devriez avoir que {expected_qty} {unit}. Avez-vous ajouté du stock sans l'enregistrer ?",
"banner_anomaly_untracked_title": "stock non enregistré comme entrée",
"banner_anomaly_untracked_detail": "Vous avez <strong>{inv_qty} {unit}</strong> en inventaire, mais les sorties enregistrées dépassent les entrées — le stock initial n'a probablement jamais été ajouté comme transaction « entrée ». Vous pouvez corriger la quantité ou saisir les entrées manquantes.",
"banner_anomaly_ghost_title": "vous avez moins de stock que prévu",
"banner_anomaly_ghost_detail": "D'après les opérations enregistrées vous devriez avoir {expected_qty} {unit} de {name}, mais l'inventaire n'en montre que {inv_qty} {unit}. Avez-vous pris du stock sans l'enregistrer ?",
"banner_dup_loss_title": "Vérification double sortie : {name}",
"banner_dup_loss_detail": "Doublon possible dans {location} : deux sorties rapprochées ({qty_pair}) en ~{seconds}s. Vérifiez et corrigez si besoin.",
"banner_dup_loss_action_fix": "Corriger la quantité",
"banner_dup_loss_action_open": "Ouvrir la fiche produit",
"banner_dup_loss_action_done": "Déjà vérifié",
"banner_dup_loss_toast_done": "Contrôle marqué comme vérifié",
"consumed": "Consommé : {n} ({pct}%)",
"wasted": "Gaspillé : {n} ({pct}%)",
"more_opened": "et {n} autres ouverts...",
"banner_expired_detail": "{when} · il vous reste encore <strong>{qty}</strong>.",
"banner_opened_detail": "{when} dans {location} · il vous reste encore <strong>{qty}</strong>.",
"banner_explain_title": "Demander une explication à Gemini",
"banner_explain_btn": "Expliquer",
"banner_analyzing": "🤖 Analyse en cours…"
},
"inventory": {
"title": "Garde-manger",
"filter_all": "Tout",
"search_placeholder": "🔍 Rechercher un produit...",
"recent_title": "🕐 Utilisés récemment",
"popular_title": "⭐ Les plus utilisés",
"empty": "Aucun produit ici.\nScannez un produit pour l'ajouter !",
"no_items_found": "Aucun article trouvé",
"qty_remainder_suffix": "restant",
"vacuum_badge": "🫙 Sous vide",
"opened_badge": "📭 Ouvert",
"label_expiry": "📅 Péremption",
"label_storage": "🫙 Conservation",
"label_status": "📭 État",
"opened_since": "Ouvert depuis le {date}",
"label_position": "📍 Emplacement",
"label_quantity": "📦 Quantité",
"label_added": "📅 Ajouté",
"empty_text": "Aucun produit ici.<br>Scannez un produit pour l'ajouter !",
"empty_db": "Aucun produit dans la base de données.<br>Scannez un produit pour commencer !",
"qty_trace": "< 1"
},
"scan": {
"title": "Scanner",
"mode_shopping": "🛒 Mode courses",
"mode_shopping_end": "✅ Terminer les courses",
"spesa_btn": "🛒 Courses",
"zoom": "Zoom",
"tab_barcode": "Code-barres",
"tab_name": "Nom",
"tab_ai": "IA",
"recents_label": "Récents",
"torch_hint": "Torche",
"torch_on": "Torche activée",
"torch_off": "Torche désactivée",
"torch_unavailable": "Torche non disponible sur cet appareil",
"flip_hint": "Retourner la caméra",
"flip_front": "Caméra frontale",
"flip_back": "Caméra arrière",
"num_ocr_btn": "🔢 Lire les chiffres avec l'IA",
"num_ocr_searching": "Recherche du code-barres avec l'IA...",
"num_ocr_found": "Code trouvé : {code}",
"num_ocr_not_found": "Aucun code-barres trouvé dans l'image",
"barcode_placeholder": "Entrez le code-barres...",
"quick_name_divider": "ou tapez le nom",
"quick_name_placeholder": "Ex. : Pommes, Courgettes, Pain...",
"manual_entry": "✏️ Saisie manuelle",
"ai_identify": "🤖 Identifier avec l'IA",
"hint": "Scannez le code-barres, tapez le nom du produit ou utilisez l'IA pour l'identifier",
"debug_toggle": "🐛 Journal de débogage",
"barcode_acquired": "🔖 Code-barres scanné : {code}",
"scan_barcode": "🔖 Scanner le code-barres",
"create_named": "Créer {name}",
"new_without_barcode": "Nouveau produit sans code-barres",
"status_ready": "Pointez la caméra sur le code-barres",
"status_scanning": "Scan en cours...",
"status_partial": "Lu : {code} — vérification...",
"status_invalid": "Invalide : {code} — nouvel essai",
"status_confirmed": "Confirmé !",
"status_parallel": "Scan combiné actif...",
"status_ocr_searching": "Je lis les chiffres du code-barres...",
"status_ai_visual_searching": "J'essaie maintenant de reconnaître le produit...",
"method_ai_ocr": "Gemini OCR",
"method_ai_vision": "Gemini Vision",
"ai_fallback_searching": "Identification IA en cours...",
"ai_fallback_found": "Produit identifié par l'IA",
"ai_fallback_not_found": "IA : produit non reconnu",
"ai_fallback_exhausted": "IA : produit non reconnu — réessayez avec le code-barres",
"ai_overlay_msg": "Gemini Vision analyse le produit...",
"ai_retry_btn": "Reessayer avec l'IA",
"ai_match_title": "Produit reconnu par l'IA",
"ai_match_subtitle": "Choisissez un produit deja en stock ou ajoutez celui detecte.",
"ai_match_existing": "Correspondances possibles dans le stock",
"ai_match_none": "Aucun produit similaire trouve dans le stock.",
"ai_match_use_btn": "Utiliser celui-ci",
"ai_match_add_btn": "Ajouter \"{name}\"",
"ai_detected_label": "IA a detecte"
},
"action": {
"title": "Que voulez-vous faire ?",
"add_btn": "📥 AJOUTER",
"add_sub": "au garde-manger/réfrigérateur",
"use_btn": "📤 UTILISER / CONSOMMER",
"use_sub": "depuis le garde-manger/réfrigérateur",
"have_title": "📦 Déjà en stock !",
"add_more_sub": "en ajouter",
"use_qty_sub": "combien vous avez utilisé",
"throw_btn": "🗑️ JETER",
"throw_sub": "jeter",
"edit_sub": "péremption, emplacement…",
"create_recipe_btn": "Recette"
},
"add": {
"title": "Ajouter au garde-manger",
"location_label": "📍 Où le rangez-vous ?",
"quantity_label": "📦 Quantité",
"conf_size_label": "📦 Chaque paquet contient :",
"conf_size_placeholder": "ex. 300",
"vacuum_label": "🫙 Sous vide",
"vacuum_hint": "La date de péremption sera automatiquement prolongée",
"submit": "✅ Ajouter",
"purchase_type_label": "🛒 Ce produit est...",
"new_btn": "🆕 Vient d'être acheté",
"existing_btn": "📦 Je l'avais déjà",
"remaining_label": "📦 Quantité restante",
"remaining_hint": "Approximativement combien en reste-t-il ?",
"remaining_full": "🟢 Plein",
"remaining_half": "🟠 À moitié",
"estimated_expiry": "Date de péremption estimée :",
"suffix_freezer": "(congélateur)",
"suffix_vacuum": "(sous vide)",
"hint_modify": "📝 Vous pouvez modifier la date ou la scanner avec la caméra",
"scan_expiry_title": "📷 Scanner la date de péremption",
"product_added": "✅ {name} ajouté !{qty}",
"suffix_freezer_vacuum": "(congélateur + sous vide)",
"history_badge_tip": "Moyenne de {n} entrées précédentes",
"vacuum_question": "Sous vide ?",
"vacuum_saved": "🔒 Sous vide !"
},
"use": {
"title": "Utiliser / Consommer",
"location_label": "📍 Depuis où ?",
"quantity_label": "Combien avez-vous utilisé ?",
"change": "modifier",
"partial_hint": "Ou précisez la quantité utilisée :",
"partial_piece_hint": "Avez-vous utilisé seulement une partie ?",
"piece": "pièce",
"one_whole": "1 entier",
"use_all": "🗑️ Tout utilisé / Terminé",
"submit": "📤 Utiliser cette quantité",
"available": "📦 Disponible :",
"opened_badge": "OUVERT",
"not_in_inventory": "⚠️ Produit absent de l'inventaire.",
"expiry_warning": "⚠️ Utilisez en premier celui{loc} qui expire le {date} — {when} !",
"expiry_warning_opened": "⚠️ Celui{loc} est ouvert depuis {when} — utilisez-le en premier !",
"throw_title": "🗑️ Jeter le produit",
"throw_all": "🗑️ Tout jeter ({qty})",
"throw_qty_label": "Quelle quantité jeter ?",
"throw_qty_hint": "ou entrez une quantité :",
"throw_partial_btn": "🗑️ Jeter cette quantité",
"when_expired": "périmé il y a {n} jours",
"when_today": "expire <strong>aujourd'hui</strong>",
"when_tomorrow": "expire <strong>demain</strong>",
"when_days": "expire dans <strong>{n} jours</strong>",
"toast_used": "📤 {qty} de {name} utilisé",
"toast_bring": "🛒 Produit terminé → ajouté à Bring !",
"toast_opened_finished": "🔓 Emballage ouvert de {name} terminé !",
"disambiguation_hint": "Que voulez-vous dire par « tout fini » ?",
"disambiguation_all": "🗑️ Tout finir ({qty})",
"error_exceeds_stock": "⚠️ Vous ne pouvez pas utiliser plus que ce que vous avez disponible !",
"use_all_confirm_title": "✅ Tout terminer",
"use_all_confirm_msg": "Confirmez que vous avez terminé le produit :",
"use_all_confirm_btn": "✅ Oui, terminé",
"throw_all_confirm_title": "🗑️ Tout jeter",
"throw_all_confirm_msg": "Voulez-vous vraiment jeter tout le produit ?",
"throw_all_confirm_btn": "🗑️ Oui, jeter"
},
"product": {
"title_new": "Nouveau produit",
"title_edit": "Modifier le produit",
"ai_fill": "📷 Prendre une photo et identifier avec l'IA",
"ai_fill_hint": "L'IA remplira automatiquement les champs du produit",
"name_label": "🏷️ Nom du produit *",
"name_placeholder": "Ex. : Lait entier, Pâtes penne...",
"brand_label": "🏢 Marque",
"brand_placeholder": "Ex. : Barilla, Danone, Heinz...",
"category_label": "📂 Catégorie",
"unit_label": "📏 Unité de mesure",
"default_qty_label": "🔢 Quantité par défaut",
"conf_size_label": "📦 Chaque paquet contient :",
"conf_size_placeholder": "ex. 300",
"notes_label": "📝 Notes",
"notes_placeholder": "Ex. : sans lactose, biologique, conserver au réfrigérateur après ouverture...",
"barcode_label": "🔖 Code-barres",
"barcode_placeholder": "Code-barres (si disponible)",
"barcode_hint": "⚠️ Ajoutez le code-barres pour la prochaine fois, il suffira de scanner !",
"submit": "💾 Enregistrer le produit",
"name_required": "Entrez le nom du produit",
"conf_size_required": "Précisez le contenu du paquet",
"expiry_estimated": "Date de péremption estimée :",
"scan_expiry": "Scanner la date de péremption",
"expiry_hint": "📝 Vous pouvez modifier la date ou la scanner avec la caméra",
"add_batch": "📦 + Lot avec une date différente",
"package_info": "📦 Paquet : {info}",
"edit_catalog": "⚙️ Modifier les infos produit (nom, marque, catégorie…)",
"not_recognized": "⚠️ Produit non reconnu",
"edit_info": "✏️ Modifier les informations",
"modify_details": "MODIFIER\npéremption, emplacement…",
"already_in_pantry": "📋 Déjà dans le garde-manger",
"no_barcode": "Pas de code-barres",
"unknown_product": "Produit non reconnu",
"edit_name_brand": "Modifier nom/marque",
"weight_label": "Poids",
"origin_label": "Origine",
"labels_label": "Labels",
"select_variant": "Sélectionnez la variante exacte ou utilisez les données IA :"
},
"products": {
"title": "📦 Tous les produits",
"search_placeholder": "🔍 Rechercher un produit...",
"empty": "Aucun produit dans la base de données.\nScannez un produit pour commencer !",
"no_category": "Aucun produit dans cette catégorie"
},
"recipes": {
"title": "🍳 Recettes",
"generate": "✨ Générer une nouvelle recette",
"archive_empty": "Aucune recette enregistrée. Générez votre première recette !",
"dialog_title": "🍳 Recette",
"dialog_desc": "Je vais générer une recette saine en utilisant les ingrédients du garde-manger, en priorisant les produits qui expirent.",
"meal_label": "🕐 Quel repas ?",
"persons_label": "👥 Pour combien de personnes ?",
"meal_type_label": "🎯 Type de repas",
"opt_fast": "⚡ Repas rapide",
"opt_light": "🥗 Appétit léger",
"opt_expiry": "⏰ Prioriser les produits qui expirent",
"opt_healthy": "💚 Extra sain",
"opt_opened": "📦 Prioriser les produits ouverts",
"opt_zero_waste": "♻️ Zéro déchet",
"generate_btn": "✨ Générer la recette",
"loading_msg": "Préparation de votre recette...",
"start_cooking": "👨‍🍳 Mode cuisine",
"regenerate": "🔄 En générer une autre",
"regen_choice_title": "Que veux-tu faire de cette recette ?",
"regen_replace": "🔄 En générer une autre (ignorer celle-ci)",
"regen_save_new": "💾 Sauvegarder dans l'archive et en générer une nouvelle",
"close_btn": "✅ Fermer",
"ingredients_title": "🧾 Ingrédients",
"tools_title": "Matériel nécessaire",
"steps_title": "👨‍🍳 Étapes",
"no_steps": "Aucune étape disponible",
"generate_error": "Erreur de génération",
"persons_short": "pers.",
"use_ingredient_title": "Utiliser l'ingrédient",
"recipe_qty_label": "Recette",
"from_where_label": "Depuis où ?",
"amount_label": "Combien",
"use_amount_btn": "Utiliser cette quantité",
"use_all_btn": "Tout utiliser / Terminé",
"packs_label": "Paquets",
"quantity_in_total": "Quantité en {unit} (total : {total})",
"packs_of_have": "Paquets de {size} (vous en avez {count})",
"scale_wait_stable": "Attendez 10s de poids stable pour le remplissage automatique…",
"ingredient_scaled_toast": "📦 Ingrédient déduit du garde-manger !",
"finished_added_bring_toast": "🛒 Produit terminé → ajouté à Bring !",
"load_error": "Erreur de chargement",
"favorite": "Ajouter aux favoris",
"unfavorite": "Retirer des favoris",
"adjust_persons": "Personnes",
"nutrition_title": "Valeurs nutritionnelles (par portion)",
"nutrition_kcal": "Calories",
"nutrition_protein": "Protéines",
"nutrition_carbs": "Glucides",
"nutrition_fat": "Lipides",
"nutrition_per_serving": "Valeurs estimées par portion",
"storage_title": "Comment conserver les restes",
"storage_days": "{n} jours",
"storage_immediately": "À consommer immédiatement"
},
"shopping": {
"title": "🛒 Liste de courses",
"bring_loading": "Connexion à Bring !...",
"bring_not_configured": "Bring ! n'est pas configuré. Ajoutez votre e-mail et mot de passe dans les <a href='#' onclick=\"showPage('settings');return false;\">paramètres</a>.",
"tab_to_buy": "🛍️ À acheter",
"tab_forecast": "🧠 Prévision",
"total_label": "💰 Total estimé",
"section_to_buy": "🛍️ À acheter",
"suggestions_title": "💡 Suggestions IA",
"suggestions_add": "✅ Ajouter la sélection à Bring !",
"search_prices": "🔍 Rechercher tous les prix",
"suggest_btn": "Suggérer des achats",
"smart_title": "🧠 Prévisions intelligentes",
"smart_empty": "Aucune prévision disponible.<br>Ajoutez des produits à votre garde-manger pour recevoir des prévisions intelligentes.",
"smart_filter_all": "Tout",
"smart_filter_critical": "🔴 Urgent",
"smart_filter_high": "🟠 Bientôt",
"smart_filter_medium": "🟡 Planifier",
"smart_filter_low": "🟢 Prévision",
"smart_add": "🛒 Ajouter la sélection à Bring !",
"empty": "Liste de courses vide !\nUtilisez le bouton ci-dessous pour générer des suggestions.",
"already_in_list": "🛒 \"{name}\" est déjà dans la liste de courses",
"already_in_list_short": "️ Déjà dans la liste de courses",
"add_prompt": "Voulez-vous l'ajouter à la liste de courses ?",
"smart_already": "📊 Les prévisions achats prédisent déjà {name}",
"all_searched": "Tous les produits ont déjà été recherchés. Utilisez 🔄 pour rechercher individuellement.",
"search_complete": "Recherche terminée : {count} produits",
"removed_sufficient": "🧹 {removed} produit(s) avec stock suffisant retiré(s) de la liste",
"suggest_buy": "🛒 Acheter : {qty} {unit}",
"suggest_buy_approx": "🛒 Au minimum : {qty} {unit}",
"suggest_buy_tip": "Quantité suggérée basée sur vos 14 derniers jours de consommation",
"suggest_buy_approx_tip": "Estimation minimale basée sur la consommation (achetez le format le plus proche)",
"bring_badge": "🛒 Déjà sur Bring !",
"add_urgent_toast": "🔴 {n} produit(s) urgent(s) automatiquement ajouté(s) à Bring !",
"migration_done": "✅ {migrated} mis à jour, {skipped} déjà ok",
"added_to_bring": "🛒 {n} produits ajoutés à Bring !",
"added_to_bring_skip": "{n} déjà présents",
"all_on_bring": "Tous les produits étaient déjà sur Bring !",
"freq_high": "📈 Fréquent",
"freq_regular": "📊 Régulier",
"freq_occasional": "📉 Occasionnel",
"out_of_stock": "Rupture de stock",
"scan_toast": "📷 Scanner : {name}",
"empty_category": "Aucun produit dans cette catégorie",
"session_empty": "🛒 Aucun produit encore",
"urgency_critical": "Urgent",
"urgency_high": "Bientôt",
"urgency_medium": "Planifier",
"urgency_low": "Prévision",
"urgency_medium_short": "Moyen",
"urgency_low_short": "Ok",
"tag_urgent": "🔴 Urgent",
"tag_priority": "⭐ Priorité",
"tag_check": "✅ Vérifier",
"smart_already_predicted": "📊 Les prévisions achats prédisent déjà <strong>{name}</strong>{urgency}.",
"item_removed": "✅ {name} retiré de la liste !",
"urgency_spec_critical": "⚡ Urgent",
"urgency_spec_high": "🟠 Bientôt",
"bring_add_n": "Ajouter {n} à Bring !",
"bring_add_selected": "Ajouter la sélection à Bring !",
"bring_adding": "Ajout en cours...",
"bring_added_one": "1 produit ajouté à Bring !",
"bring_added_many": "{n} produits ajoutés à Bring !",
"bring_skipped": "({n} déjà dans la liste)",
"force_sync": "Forcer la synchronisation Bring !",
"scan_target_label": "Vous cherchez",
"scan_target_found": "Trouvé ! Retirer de la liste",
"bring_add_one": "Ajouter 1 produit à Bring !",
"bring_add_many": "Ajouter {n} produits à Bring !",
"syncing": "Synchronisation…",
"sync_done": "Synchronisation terminée",
"price_searching": "Recherche en cours...",
"search_action": "Rechercher",
"open_action": "Ouvrir",
"not_found": "Non trouvé",
"search_price": "Rechercher le prix",
"tap_to_scan": "Appuyez pour scanner",
"tag_title": "Tag",
"remove_title": "Retirer",
"found_count": "{found}/{total} produits trouvés",
"savings_offers": "· 🏷️ Vous économisez {amount}€ avec les offres",
"searching_progress": "Recherche {current}/{total}...",
"remove_error": "Erreur de suppression",
"btn_fetch_prices": "Trouver les prix",
"price_total_label": "💰 Total estimé :",
"price_loading": "Recherche des prix…",
"price_not_found": "prix n/d",
"suggest_loading": "Analyse en cours...",
"suggest_error": "Erreur de génération des suggestions",
"priority_high": "Élevée",
"priority_medium": "Moyenne",
"priority_low": "Faible",
"smart_last_update": "Mis à jour {time}",
"names_already_updated": "Tous les noms sont déjà à jour"
},
"ai": {
"title": "🤖 Identification IA",
"capture": "📸 Prendre une photo",
"retake": "🔄 Reprendre",
"hint": "Prenez une photo du produit et l'IA essaiera de l'identifier",
"identifying": "🤖 Identification du produit...",
"no_api_key": "⚠️ Clé API Gemini non configurée.\n<small>Ajoutez GEMINI_API_KEY au fichier .env sur le serveur.</small>",
"fields_filled": "✅ Champs remplis par l'IA",
"use_data": "✅ Utiliser les données IA",
"use_data_no_barcode": "✅ Utiliser les données IA (sans code-barres)"
},
"log": {
"title": "📒 Journal des opérations",
"type_added": "Ajouté",
"type_waste": "Jeté",
"type_used": "Utilisé",
"type_bring": "Ajouté à Bring !",
"undone_badge": "Annulé",
"undo_title": "Annuler cette opération",
"load_error": "Erreur de chargement du journal",
"empty": "Aucune opération enregistrée.",
"undo_action_remove": "suppression de",
"undo_action_restore": "réapprovisionnement de",
"undo_confirm": "Annuler cette opération ?\n→ {action} {name}",
"undo_success": "↩ Opération annulée pour {name}",
"already_undone": "Opération déjà annulée",
"too_old": "Impossible d'annuler des opérations de plus de 24 heures",
"undo_error": "Erreur lors de l'annulation",
"recipe_prefix": "Recette"
},
"chat": {
"title": "Chef Gemini",
"welcome": "Bonjour ! Je suis votre assistant cuisine",
"welcome_desc": "Demandez-moi de préparer un jus, un snack, un plat rapide… Je connais votre garde-manger, vos appareils et vos préférences !",
"suggestion_snack": "🍿 Snack rapide",
"suggestion_juice": "🥤 Jus/Smoothie",
"suggestion_light": "🥗 Quelque chose de léger",
"suggestion_expiry": "⏰ Utiliser les produits qui expirent",
"clear": "Nouvelle conversation",
"placeholder": "Demandez quelque chose...",
"cleared": "Chat effacé",
"suggestion_snack_text": "Que puis-je préparer comme snack rapide ?",
"suggestion_juice_text": "Faites-moi un jus ou un smoothie avec ce que j'ai",
"suggestion_light_text": "J'ai faim mais je veux quelque chose de léger",
"suggestion_expiry_text": "Qu'est-ce qui va bientôt expirer et comment l'utiliser ?",
"transfer_to_recipes": "Transférer aux recettes",
"transferring": "Transfert en cours...",
"transferred": "Ajouté aux recettes !",
"open_recipe": "Ouvrir la recette",
"quick_recipe_prompt": "Suggérez une recette rapide POUR UNE PERSONNE en utilisant les produits qui expirent en premier ! Ignorez les congélateurs, concentrez-vous sur le réfrigérateur et le garde-manger."
},
"cooking": {
"close": "Fermer",
"tts_btn": "Lire à voix haute",
"restart": "↺ Recommencer",
"replay": "🔊 Rejouer",
"timer": "⏱️ {time} · Minuterie",
"prev": "◀ Précédent",
"next": "Suivant ▶",
"ingredient_used": "✔️ Déduit",
"ingredient_use_btn": "📦 Utiliser",
"ingredient_deduct_title": "Déduire du garde-manger",
"timer_expired_tts": "Minuterie {label} terminée !",
"timer_warning_tts": "Attention ! {label} : 10 secondes restantes !",
"recipe_done_tts": "Recette terminée ! Bon appétit !",
"expires_chip": "exp. {date}",
"finish": "✅ Terminer",
"step_fallback": "Étape {n}",
"zerowaste_label": "♻️ Déchet",
"zerowaste_tip_title": "Conseil zéro déchet"
},
"settings": {
"title": "⚙️ Paramètres",
"tab_api": "Clés API",
"tab_bring": "Bring !",
"tab_recipe": "Recettes",
"tab_mealplan": "Plan hebdomadaire",
"tab_appliances": "Appareils",
"tab_spesa": "Courses en ligne",
"tab_camera": "Caméra",
"tab_security": "Sécurité",
"tab_tts": "Voix (TTS)",
"tab_language": "Langue",
"tab_scale": "Balance connectée",
"gemini": {
"title": "🤖 Google Gemini IA",
"hint": "Clé API pour l'identification des produits, les dates de péremption et les recettes.",
"key_label": "Clé API Gemini"
},
"bring": {
"title": "🛒 Liste de courses Bring !",
"hint": "Identifiants pour l'intégration de la liste de courses Bring !",
"email_label": "📧 E-mail Bring !",
"password_label": "🔒 Mot de passe Bring !"
},
"price": {
"title": "💰 Estimation des prix (IA)",
"hint": "Afficher le coût estimé par produit dans la liste de courses à l'aide de l'IA.",
"enabled_label": "Activer l'estimation des prix",
"country_label": "🌍 Pays de référence",
"currency_label": "💱 Devise",
"update_label": "🔄 Actualiser les prix tous les",
"update_suffix": "mois"
},
"recipe": {
"title": "🍳 Préférences de recettes",
"hint": "Configurez les options par défaut pour la génération de recettes.",
"persons_label": "👥 Portions par défaut",
"options_label": "🎯 Options de recette par défaut",
"fast": "⚡ Repas rapide",
"light": "🥗 Repas léger",
"expiry": "⏰ Priorité péremption",
"healthy": "💚 Extra sain",
"opened": "📦 Priorité produits ouverts",
"zerowaste": "♻️ Zéro déchet",
"dietary_label": "🚫 Intolérances / Restrictions",
"dietary_placeholder": "Ex. : sans gluten, sans lactose, végétarien..."
},
"mealplan": {
"title": "📅 Plan de repas hebdomadaire",
"hint": "Définissez le type de repas pour chaque jour. Il sera utilisé comme guide pour la génération de recettes.",
"enabled": "✅ Activer le plan hebdomadaire",
"legend": "🌤️ = Déjeuner &nbsp;·&nbsp; 🌙 = Dîner &nbsp;·&nbsp; Appuyez sur un badge pour le modifier.",
"types_title": "📋 Types disponibles",
"reset_btn": "↺ Restaurer les valeurs par défaut"
},
"appliances": {
"title": "🔌 Appareils disponibles",
"hint": "Indiquez les appareils que vous possédez. Ils seront pris en compte lors de la génération de recettes.",
"new_placeholder": "Ex. : Machine à pain, Thermomix, Friteuse à air...",
"quick_title": "Ajout rapide :",
"oven": "🔥 Four",
"microwave": "📡 Micro-ondes",
"air_fryer": "🍟 Friteuse à air",
"bread_maker": "🍞 Machine à pain",
"bimby": "🤖 Thermomix/Cookeo",
"mixer": "🌀 Robot pâtissier",
"steamer": "♨️ Cuiseur vapeur",
"pressure_cooker": "🫕 Cocotte-minute",
"toaster": "🍞 Grille-pain",
"blender": "🍹 Mixeur",
"empty": "Aucun appareil ajouté"
},
"spesa": {
"title": "🛍️ Courses en ligne",
"hint": "Configurez le fournisseur de courses en ligne.",
"provider_label": "🏪 Fournisseur",
"email_label": "📧 E-mail",
"password_label": "🔒 Mot de passe",
"login_btn": "🔐 Connexion",
"ai_prompt_label": "🤖 Prompt IA de sélection de produit",
"ai_prompt_placeholder": "Instructions pour l'IA lors du choix entre plusieurs produits...",
"ai_prompt_hint": "L'IA utilise ce prompt pour choisir le produit le plus approprié parmi les résultats. Laissez vide pour le comportement par défaut.",
"configure_first": "Configurez d'abord les courses en ligne dans les paramètres",
"missing_credentials": "Entrez l'e-mail et le mot de passe",
"login_in_progress": "Connexion en cours...",
"login_error_prefix": "Erreur :",
"login_network_error_prefix": "Erreur réseau :",
"login_success_default": "Connexion réussie !",
"result_name_label": "Nom",
"result_card_label": "Carte",
"result_pickup_label": "Point de retrait",
"result_points_label": "Points fidélité",
"connected_relogin": "✅ Connecté — Se reconnecter",
"connected_as": "Connecté en tant que {name}"
},
"camera": {
"title": "📷 Caméra",
"hint": "Choisissez la caméra à utiliser pour le scan de code-barres et l'identification IA.",
"device_label": "📸 Caméra par défaut",
"back": "📱 Arrière (par défaut)",
"front": "🤳 Frontale",
"devices_hint": "Si vous avez plusieurs caméras, vous pouvez en sélectionner une dans la liste ci-dessus après avoir accordé les permissions.",
"detect_btn": "🔄 Détecter les caméras",
"ai_fallback_label": "Identification visuelle IA (repli 5s)",
"ai_fallback_hint": "Si aucun code-barres n'est lu en 5 secondes, une image est automatiquement envoyée à l'IA pour identifier visuellement le produit. Nécessite Gemini configuré."
},
"security": {
"title": "🔒 Certificat HTTPS",
"hint": "Si le navigateur affiche l'erreur « Votre connexion n'est pas privée » (ERR_CERT_AUTHORITY_INVALID), vous devez installer le certificat CA sur l'appareil.",
"download_btn": "📥 Télécharger le certificat CA",
"token_title": "🔑 Token de paramètres",
"token_label": "Token d'accès",
"token_hint": "Si `SETTINGS_TOKEN` est configuré dans le `.env` du serveur, entrez le token ici avant de sauvegarder les paramètres. Laissez vide si non configuré.",
"token_placeholder": "(vide = pas de protection)",
"token_required_hint": "🔒 Ce serveur nécessite un token pour sauvegarder les paramètres.",
"cert_instructions": "<strong>Instructions pour Chrome (Android) :</strong><br>1. Téléchargez le certificat ci-dessus<br>2. Allez dans <em>Paramètres &rarr; Sécurité &amp; Confidentialité &rarr; Plus de paramètres de sécurité &rarr; Installer depuis le stockage</em><br>3. Sélectionnez le fichier <em>EverShelf_CA.crt</em> téléchargé<br>4. Choisissez « CA » et confirmez<br>5. Redémarrez Chrome<br><br><strong>Instructions pour Chrome (PC) :</strong><br>1. Téléchargez le certificat ci-dessus<br>2. Allez dans <em>chrome://settings/certificates</em><br>3. Onglet « Autorités » &rarr; Importer &rarr; sélectionnez le fichier<br>4. Cochez « Approuver ce certificat pour identifier les sites web »<br>5. Redémarrez Chrome"
},
"tts": {
"title": "🔊 Voix & TTS",
"hint": "Configurez la synthèse vocale via une API REST externe. Les étapes de recette et les minuteries expirées seront envoyées à l'endpoint configuré.",
"enabled": "✅ Activer la TTS",
"engine_label": "⚙️ Moteur TTS",
"engine_browser": "🔇 Navigateur (hors ligne, aucune configuration requise)",
"engine_server": "🌐 Serveur externe (Home Assistant, API REST...)",
"voice_label": "🗣️ Voix",
"rate_label": "⚡ Vitesse",
"pitch_label": "🎵 Tonalité",
"url_label": "🌐 URL de l'endpoint",
"method_label": "📡 Méthode HTTP",
"auth_label": "🔐 Authentification",
"auth_bearer": "Bearer Token",
"auth_custom": "En-tête personnalisé",
"auth_none": "Aucune",
"token_label": "🔑 Bearer Token",
"custom_header_name": "📋 Nom de l'en-tête",
"custom_header_value": "📋 Valeur de l'en-tête",
"content_type_label": "📄 Content-Type",
"payload_key_label": "🗝️ Champ texte dans le payload",
"payload_key_hint": "Nom du champ JSON qui contiendra le texte à lire (ex. : message, text).",
"extra_fields_label": " Champs supplémentaires (JSON)",
"extra_fields_placeholder": "{\"entity_id\": \"media_player.salon\"}",
"extra_fields_hint": "Champs supplémentaires à inclure dans le payload, en format JSON. Laissez vide si non nécessaire.",
"test_btn": "🔊 Envoyer une voix de test",
"voices_loading": "Chargement des voix…",
"voice_not_supported": "Voix non supportée par ce navigateur",
"voices_none": "Aucune voix disponible sur cet appareil",
"voices_hint": "Les voix disponibles dépendent du système d'exploitation et du navigateur. Appuyez sur ↺ si la liste ne se charge pas.",
"url_missing": "⚠️ URL de l'endpoint manquante.",
"test_sending": "⏳ Envoi…",
"test_ok": "✅ Réponse {code} — vérifiez que le haut-parleur a parlé.",
"heard_question": "Avez-vous entendu la voix ?",
"heard_yes": "Oui, je l'ai entendu",
"heard_no": "Non, je n'ai rien entendu",
"test_ok_kiosk": "TTS fonctionne.",
"test_fail_steps": "Vérifiez : 1) le volume média n'est pas 0 ; 2) Google Text-to-Speech est installé et mis à jour ; 3) le pack vocal français est téléchargé dans les paramètres TTS Android."
},
"language": {
"title": "🌐 Langue",
"hint": "Sélectionnez la langue de l'interface.",
"label": "🌐 Langue",
"restart_notice": "La page sera rechargée pour appliquer la nouvelle langue."
},
"screensaver": {
"label": "Activer l'économiseur d'écran",
"card_title": "🌙 Économiseur d'écran",
"card_hint": "Affiche une horloge avec des informations utiles après 5 minutes d'inactivité. Désactivé par défaut.",
"timeout_1": "1 minute",
"timeout_2": "2 minutes",
"timeout_5": "5 minutes",
"timeout_10": "10 minutes",
"timeout_15": "15 minutes",
"timeout_30": "30 minutes",
"timeout_60": "1 heure",
"start_after": "⏱️ Démarrer après"
},
"scale": {
"title": "⚖️ Balance connectée",
"hint": "Connectez une balance Bluetooth via la passerelle Android pour lire automatiquement le poids.",
"tab": "Balance connectée",
"enabled": "✅ Activer la balance connectée",
"url_label": "🌐 URL de la passerelle WebSocket",
"url_placeholder": "ws://192.168.1.x:8765",
"url_hint": "URL affichée par l'application Android (même réseau Wi-Fi). Ex. :",
"test_btn": "🔗 Tester la connexion",
"download_btn": "📥 Télécharger la passerelle Android (APK)",
"download_hint": "Application Android qui connecte votre balance BLE et EverShelf.",
"download_sub": "Source : evershelf-scale-gateway/ dans la racine du projet",
"live_weight": "poids en temps réel",
"auto_reconnect": "🔁 Reconnexion : automatique",
"kiosk_title": "📡 Balance BLE intégrée dans le kiosque",
"kiosk_hint": "La balance est directement gérée par la passerelle BLE interne du kiosque. Pour associer un nouvel appareil, utilisez l'assistant de configuration.",
"kiosk_reconfigure": "🔄 Reconfigurer la balance BLE",
"ble_protocols": "<p style=\"margin:0 0 6px;font-weight:600\">🔌 Protocoles BLE supportés :</p><ul style=\"margin:0 0 0 16px;padding:0;font-size:0.8rem\"><li>Bluetooth SIG Weight Scale (0x181D)</li><li>Bluetooth SIG Body Composition (0x181B) &mdash; poids, graisse, IMC</li><li>Xiaomi Mi Body Composition Scale 2</li><li>Générique &mdash; heuristique automatique pour 100+ modèles</li></ul>"
},
"kiosk": {
"hint": "Transformez une tablette Android en panneau EverShelf permanent avec passerelle BLE intégrée.",
"download_btn": "📥 Télécharger EverShelf Kiosk (APK)",
"download_sub": "Mode kiosque plein écran + passerelle de balance intégrée. Source : evershelf-kiosk/",
"native_title": "Configuration du kiosque",
"native_hint": "URL du serveur, balance BLE, économiseur d'écran et assistant de configuration.",
"native_btn": "Ouvrir la configuration du kiosque",
"native_tap_hint": "Appuyez sur le bouton engrenage en haut à droite",
"native_update_hint": "Mettez à jour l'application kiosque pour utiliser cette fonctionnalité",
"update_title": "Mise à jour du kiosque",
"check_updates_btn": "🔍 Vérifier les mises à jour",
"needs_update": "⚠️ Le kiosque installé ne supporte pas cette fonctionnalité. Mettez à jour l'application kiosque pour l'activer."
},
"saved": "✅ Configuration enregistrée !",
"saved_local": "✅ Configuration enregistrée localement",
"saved_local_error": "⚠️ Enregistré localement, erreur serveur : {error}",
"theme": {
"title": "🌙 Apparence",
"hint": "Choisissez le thème de l'interface.",
"label": "🌙 Thème",
"off": "☀️ Clair",
"on": "🌙 Sombre",
"auto": "🔄 Automatique (système)"
},
"zerowaste": {
"card_title": "♻️ Conseils zéro déchet",
"card_hint": "Pendant la cuisson, affichez des conseils pour réutiliser les déchets produits à chaque étape (épluchures, eau de cuisson, etc.). Désactivé par défaut.",
"label": "Afficher les conseils pendant la cuisson"
},
"backup": {
"tab": "Sauvegarde",
"local_title": "Sauvegarde locale",
"local_hint": "Instantané quotidien de la base de données. Configurez le nombre de jours de rétention.",
"enabled": "Activer la sauvegarde automatique quotidienne",
"retention_days": "Rétention (jours)",
"retention_info": "Les sauvegardes sont conservées pendant",
"backup_now": "Sauvegarder maintenant",
"backing_up": "Sauvegarde en cours…",
"backed_up": "Sauvegarde terminée",
"backup_error": "Erreur de sauvegarde",
"last_backup": "Dernière sauvegarde",
"no_backup_yet": "Aucune sauvegarde créée",
"list_empty": "Aucune sauvegarde disponible",
"restore_btn": "Restaurer",
"restore_confirm": "Restaurer la sauvegarde",
"delete_btn": "Supprimer",
"delete_confirm": "Supprimer la sauvegarde",
"gdrive_title": "Google Drive",
"gdrive_hint": "Sauvegardez automatiquement sur Google Drive via OAuth 2.0. Aucune bibliothèque externe requise.",
"gdrive_enabled": "Activer la sauvegarde Google Drive",
"gdrive_folder_id": "ID du dossier Drive",
"gdrive_folder_id_hint": "Copiez l'ID depuis l'URL du dossier Drive : …/folders/<strong>ID</strong>",
"gdrive_retention_days": "Rétention Drive (jours, 0=tout garder)",
"gdrive_test": "Tester la connexion",
"gdrive_ok": "Connexion réussie !",
"gdrive_error": "Échec de la connexion",
"gdrive_push_now": "Téléverser sur Drive maintenant",
"gdrive_pushing": "Téléversement en cours…",
"gdrive_pushed": "Téléversé sur Drive",
"gdrive_wizard_hint": "Optionnel : sauvegarde quotidienne automatique sur Google Drive via OAuth 2.0.",
"gdrive_skip": "Passer — configurer plus tard dans Paramètres",
"gdrive_client_id": "Client ID",
"gdrive_client_secret": "Client Secret",
"gdrive_redirect_uri_hint": "Ajoute <strong>http://localhost</strong> comme URI de redirection autorisé dans la Google Cloud Console. Fonctionne sur n'importe quel serveur, même sans domaine public.",
"gdrive_code_title": "Coller l'URL ou le code d'autorisation",
"gdrive_code_hint": "Après autorisation, le navigateur ouvre http://localhost et peut afficher une erreur de connexion — c'est normal. Copie l'URL dans la barre d'adresse (ex. <code>http://localhost/?code=4%2F0A...</code>) et colle-la ici.",
"gdrive_code_submit": "Confirmer",
"gdrive_code_empty": "Coller d'abord l'URL ou le code d'autorisation",
"gdrive_redirect_uri_label": "URI de redirection (ajouter dans Google Cloud Console) :",
"gdrive_oauth_authorize": "Autoriser avec Google",
"gdrive_oauth_authorized": "Autorisé",
"gdrive_oauth_not_authorized": "Pas encore autorisé",
"gdrive_oauth_window_opened": "Fenêtre ouverte — autorisez et revenez ici",
"gdrive_oauth_how_to": "Configurer OAuth 2.0 (étape par étape)",
"gdrive_oauth_steps": "<li>Allez sur <a href='https://console.cloud.google.com/' target='_blank' rel='noopener'>console.cloud.google.com</a> et sélectionnez votre projet</li><li>Activez l<strong>API Google Drive</strong> : <em>API et services → Activer les API → Google Drive API</em></li><li>Allez dans <em>API et services → Identifiants → Créer des identifiants → ID client OAuth</em></li><li>Type dapplication : <strong>Application Web</strong> ; ajoutez lURL affichée ci-dessous comme <em>URI de redirection autorisé</em></li><li>Copiez le <strong>Client ID</strong> et le <strong>Client Secret</strong> dans les champs ci-dessus et enregistrez</li><li>Cliquez sur <strong>Autoriser avec Google</strong> : connectez-vous et accordez laccès</li><li>La fenêtre se ferme automatiquement une fois terminé et les sauvegardes sont prêtes</li>"
},
"shopping": {
"tab": "Liste de courses",
"title": "Liste de courses",
"hint": "Configurez la liste de courses intégrée ou connectez Bring!.",
"enable_label": "Activer la liste de courses",
"mode_label": "Fournisseur",
"mode_internal": "Intégré (sans Bring!)",
"mode_bring": "Bring! (application externe)",
"bring_section_title": "Configuration Bring!",
"ai_section_title": "Assistance IA",
"smart_suggestions_label": "Suggestions IA",
"forecast_label": "Prévision des produits bientôt épuisés",
"auto_add_label": "Ajouter automatiquement quand",
"auto_add_suffix": "restant en stock (0 = seulement quand épuisé)"
},
"ha": {
"tab": "Home Assistant",
"title": "Home Assistant",
"hint": "Connectez EverShelf à Home Assistant pour les automations, les notifications push et les capteurs REST.",
"enabled": "Activer l'intégration Home Assistant",
"connection_title": "Connexion",
"url_label": "URL Home Assistant",
"url_placeholder": "http://192.168.1.50:8123",
"url_hint": "URL de base de votre instance Home Assistant.",
"token_label": "Jeton d'accès longue durée",
"token_hint": "Générez depuis Profil HA → Sécurité → Jetons d'accès longue durée.",
"token_placeholder": "eyJhbGci...",
"token_saved": "Jeton enregistré (masqué pour des raisons de sécurité)",
"test_btn": "Tester la connexion",
"test_ok": "Connecté à {version}",
"test_fail": "Connexion échouée : {error}",
"test_bad_token": "HA accessible mais le jeton est invalide",
"testing": "Test en cours…",
"error_no_url": "Veuillez d'abord saisir l'URL de Home Assistant.",
"tts_title": "TTS sur enceinte connectée",
"tts_hint": "Lisez les étapes de recette sur un media player Home Assistant.",
"tts_entity_label": "Entity ID du lecteur multimédia",
"tts_entity_placeholder": "media_player.salon",
"tts_entity_hint": "Entity ID du lecteur multimédia HA. Disponible dans HA : Outils développeur → États.",
"tts_platform_label": "Plateforme TTS",
"tts_platform_speak": "tts.speak (recommandé)",
"tts_platform_notify": "notify.* (service de notification)",
"tts_apply_btn": "Appliquer le preset HA à l'onglet TTS",
"tts_apply_hint": "Pré-remplit l'onglet TTS avec l'URL et le jeton de Home Assistant.",
"tts_preset_applied": "Preset HA appliqué à l'onglet TTS.",
"webhook_title": "Automations Webhook",
"webhook_hint": "Envoyez des données à Home Assistant lors d'événements dans le garde-manger.",
"webhook_id_label": "ID Webhook",
"webhook_id_placeholder": "evershelf_webhook_abc123",
"webhook_id_hint": "ID du webhook créé dans HA. Copiez depuis : HA → Paramètres → Automations → Créer → Déclencheur Webhook.",
"webhook_events_label": "Notifier pour ces événements",
"event_expiry": "Produits expirant bientôt (quotidien)",
"event_shopping": "Article ajouté à la liste de courses",
"event_stock": "Niveau de stock mis à jour",
"expiry_days_label": "Préavis d'expiration (jours)",
"expiry_days_hint": "Envoyer l'alerte d'expiration N jours avant la date d'expiration.",
"webhook_help": "Dans HA : Paramètres → Automations → Créer → Déclencheur : Webhook → copier l'ID généré.",
"notify_title": "Notifications push",
"notify_hint": "Envoyez des notifications push sur votre téléphone via un service notify de Home Assistant.",
"notify_service_label": "Service notify",
"notify_service_placeholder": "notify.mobile_app_mon_telephone",
"notify_service_hint": "Nom du service notify HA. Laissez vide pour désactiver.",
"sensor_title": "Capteurs REST",
"sensor_hint": "Ajoutez à configuration.yaml pour créer des capteurs EverShelf dans Home Assistant.",
"sensor_copy_btn": "Copier le YAML",
"sensor_copied": "YAML copié dans le presse-papiers !",
"save_btn": "Enregistrer les paramètres HA",
"ha_hint": "Si vous utilisez Home Assistant, utilisez l'onglet Home Assistant pour configurer TTS, webhooks et capteurs."
}
},
"expiry": {
"today": "AUJOURD'HUI",
"tomorrow": "Demain",
"days": "{days} jours",
"expired_days": "il y a {days}j",
"expired_yesterday": "Hier",
"expired_today": "Aujourd'hui",
"badge_today": "⚠️ Expire aujourd'hui !",
"badge_tomorrow": "⏰ Demain",
"badge_tomorrow_long": "⏰ Expire demain",
"badge_days": "⏰ {n} jours",
"badge_expired_ago": "⚠️ Périmé il y a {n}j",
"badge_expired": "⛔ Périmé !",
"badge_stable": "✅ Stable",
"badge_expiring_short": "⏰ Exp. dans {n}j",
"badge_ok_still": "✅ Encore {n}j",
"badge_expires_red": "🔴 Exp. dans {n}j",
"badge_expires_yellow": "🟡 Exp. dans {n}j",
"badge_expired_bare": "⚠️ Périmé",
"badge_expires_warn": "⚠️ Exp. dans {n}j",
"badge_days_left": "⏳ ~{n}j restants",
"days_approx": "~{n} jours",
"weeks_approx": "~{n} semaines",
"months_approx": "~{n} mois",
"years_approx": "~{n} ans",
"expired_today_long": "Périmé aujourd'hui",
"expired_ago_long": "Périmé il y a {n} jours",
"expired_suffix": "— Périmé !",
"expired_suffix_ok": "— Périmé (encore ok)",
"expired_suffix_warning": "— Périmé (vérifier d'abord)",
"opened_ago_long": "Ouvert il y a {n} jours",
"opened_today_long": "Ouvert aujourd'hui",
"opened_suffix": "— Ouvert depuis trop longtemps !",
"opened_suffix_ok": "— Ouvert (encore ok)",
"opened_suffix_warning": "— Ouvert (vérifier d'abord)",
"days_compact": "{n}j",
"badge_check_soon": "Vérifier prochainement"
},
"status": {
"ok": "OK",
"check": "Vérifier",
"discard": "Jeter",
"tip_freezer_ok": "Au congélateur : encore sûr (~{n}j de marge)",
"tip_freezer_check": "Au congélateur depuis longtemps, peut avoir perdu en qualité. Consommer rapidement",
"tip_freezer_danger": "Au congélateur trop longtemps, risque de brûlure de congélation et de dégradation",
"tip_highRisk_check": "Périmé récemment, vérifiez l'odeur et l'aspect avant de consommer",
"tip_highRisk_danger": "Produit périssable périmé : jeter pour la sécurité",
"tip_medRisk_check1": "Vérifiez l'aspect et l'odeur avant de consommer",
"tip_medRisk_check2": "Périmé depuis un moment, vérifiez soigneusement avant utilisation",
"tip_medRisk_danger": "Trop longtemps depuis la péremption, mieux vaut jeter",
"tip_lowRisk_ok": "Produit longue conservation, encore sûr à consommer",
"tip_lowRisk_check": "Périmé depuis plus d'un mois, vérifiez l'intégrité de l'emballage",
"tip_lowRisk_danger": "Périmé depuis trop longtemps, mieux vaut ne pas risquer"
},
"toast": {
"product_saved": "Produit enregistré !",
"product_created": "Produit créé !",
"product_updated": "✅ Produit mis à jour !",
"product_removed": "Produit supprimé",
"updated": "Mis à jour !",
"quantity_confirmed": "✓ Quantité confirmée",
"added_to_inventory": "✅ {name} ajouté !",
"removed_from_list": "✅ {name} retiré de la liste !",
"removed_from_list_short": "Retiré de la liste",
"added_to_shopping": "🛒 Ajouté à la liste de courses !",
"removed_from_shopping": "🛒 Retiré de la liste de courses",
"finished_to_bring": "🛒 Produit terminé → ajouté à Bring !",
"thrown_away": "🗑️ {name} jeté !",
"thrown_away_partial": "🗑️ {qty} {unit} de {name} jeté(s)",
"finished_all": "📤 {name} terminé !",
"product_finished_confirmed": "✅ Supprimé — ajoutez-le à nouveau lors du réapprovisionnement",
"appliance_added": "Appareil ajouté",
"item_added": "{name} ajouté"
},
"antiwaste": {
"title": "🌱 Rapport anti-gaspi",
"grade_label": "Note",
"you": "Vous",
"avg_label": "Moy.",
"better": "🎉 Vous gaspillez {diff}% de moins que la moyenne {country} !",
"worse": "⚠️ Vous gaspillez plus que la moyenne {country}. Des progrès sont possibles !",
"on_par": "→ Vous êtes dans la moyenne {country}. Vous pouvez faire mieux !",
"saved_money": "~{amount}/mois économisé",
"saved_meals": "~{n} repas sauvés",
"saved_co2": "{n} kg CO₂ évités",
"trend_title": "Tendance (3 derniers mois)",
"months_ago_2": "-60 jours",
"months_ago_1": "-30 jours",
"this_month": "Maintenant",
"country_it": "Moy. italienne",
"country_de": "Moy. allemande",
"country_en": "Moy. américaine",
"source": "Sources : REDUCE, Eurostat, USDA 2021",
"live_on": "Données en direct",
"live_off": "Hors ligne",
"meals": "repas",
"annual_info": "📅 Vous ~{you} kg/an · moy. ~{avg} kg/an",
"badge_rate": "taux de perte",
"badge_saved_money": "économisé vs moy.",
"badge_wasted": "articles perdus",
"badge_better": "moins que la moy."
},
"error": {
"generic": "Erreur",
"network": "Erreur réseau",
"no_api_key": "Configurez la clé API dans les paramètres",
"loading": "Erreur de chargement du produit",
"not_found": "Produit introuvable",
"not_found_manual": "Produit introuvable. Entrez-le manuellement.",
"search": "Erreur de recherche. Réessayez.",
"search_short": "Erreur de recherche",
"save": "Erreur d'enregistrement",
"connection": "Erreur de connexion",
"camera": "Impossible d'accéder à la caméra",
"bring_add": "Erreur d'ajout à Bring !",
"bring_connection": "Erreur de connexion à Bring !",
"identification": "Erreur d'identification",
"ai_quota": "Quota IA épuisé. Réessayez dans quelques minutes.",
"barcode_empty": "Entrez un code-barres",
"barcode_format": "Le code-barres ne doit contenir que des chiffres (4-14 chiffres)",
"barcode_checksum": "Somme de contrôle EAN invalide — vérifiez les chiffres du code-barres",
"min_chars": "Tapez au moins 2 caractères",
"not_in_inventory": "Produit absent de l'inventaire",
"appliance_exists": "L'appareil existe déjà",
"already_exists": "Existe déjà",
"network_retry": "Erreur de connexion. Réessayez.",
"select_items": "Sélectionnez au moins un produit",
"server_offline": "Connexion au serveur perdue",
"server_restored": "Connexion au serveur rétablie",
"server_retry": "Réessayer",
"unknown": "Erreur inconnue",
"prefix": "Erreur",
"no_inventory_entry": "Aucune entrée d'inventaire trouvée",
"offline_title": "Aucune connexion",
"offline_subtitle": "L'app ne peut pas atteindre le serveur. Vérifiez votre connexion Wi-Fi.",
"offline_checking": "Vérification de la connexion…",
"offline_restored": "Connexion rétablie !",
"offline_continue": "Continuer en mode hors ligne",
"offline_reading_cache": "Lecture depuis le cache local",
"offline_ops_pending": "{n} opérations en attente",
"offline_synced": "{n} opérations synchronisées",
"offline_ai_disabled": "Indisponible hors ligne",
"offline_cache_ready": "Offline — {n} produits en cache"
},
"confirm_placeholder_search": null,
"confirm": {
"remove_item": "Voulez-vous vraiment supprimer ce produit de l'inventaire ?",
"kiosk_exit": "Quitter le mode kiosque ?",
"cancel": "Annuler",
"proceed": "Confirmer",
"discard_one": "Jeter 1 pièce"
},
"location": {
"dispensa": "Garde-manger",
"frigo": "Réfrigérateur",
"freezer": "Congélateur"
},
"edit": {
"title": "Modifier {name}",
"unknown_hint": "Entrez le nom du produit et les informations",
"label_name": "🏷️ Nom du produit",
"choose_location_title": "Quel emplacement ?",
"choose_location_hint": "Choisissez l'emplacement à modifier :",
"confirm_large_qty": "Vous définissez la quantité à {qty} {unit}. Cela semble inhabituellement élevé. Confirmer ?"
},
"screensaver": {
"recipe_btn": "Recettes",
"scan_btn": "Scanner un produit"
},
"days": {
"mon": "Lundi",
"tue": "Mardi",
"wed": "Mercredi",
"thu": "Jeudi",
"fri": "Vendredi",
"sat": "Samedi",
"sun": "Dimanche",
"mon_short": "Lun",
"tue_short": "Mar",
"wed_short": "Mer",
"thu_short": "Jeu",
"fri_short": "Ven",
"sat_short": "Sam",
"sun_short": "Dim"
},
"meal_types": {
"lunch": "Déjeuner",
"dinner": "Dîner",
"colazione": "Petit-déjeuner",
"merenda": "Goûter",
"dolce": "Dessert",
"succo": "Jus de fruits",
"pranzo": "Déjeuner",
"cena": "Dîner"
},
"scale": {
"status_connected": "Balance connectée",
"status_searching": "Passerelle connectée, attente de la balance…",
"status_disconnected": "Passerelle de balance inaccessible",
"status_error": "Erreur de connexion à la passerelle",
"not_connected": "Passerelle de balance non connectée",
"read_btn": "⚖️ Lire depuis la balance",
"reading_title": "Lecture de la balance",
"place_on_scale": "Posez le produit sur la balance…",
"waiting_stable": "Le poids sera capturé automatiquement une fois la lecture stable.",
"no_url": "Entrez l'URL de la passerelle",
"testing": "⏳ Test de connexion…",
"connected_ok": "Connexion à la passerelle réussie !",
"timeout": "Délai dépassé : pas de réponse de la passerelle",
"error_connect": "Impossible de se connecter à la passerelle",
"tab": "Balance connectée",
"low_weight": "Poids < 10 g · entrez manuellement\n(la lecture automatique nécessite au moins 10 g)",
"density_hint": "(densité {density} g/ml)",
"ml_hint": "(sera converti en ml)",
"weight_detected": "Poids détecté — attendez 10s de stabilité…",
"weight_too_low": "Poids trop faible — attente…",
"stable": "✓ Stable",
"auto_confirm": "✅ {val} {unit} — confirmation automatique dans 5s (appuyez pour annuler)",
"cancelled_replace": "Annulé — replacez l'ingrédient sur la balance pour reprendre"
},
"prediction": {
"expected_qty": "Attendu : {expected} {unit}",
"actual_qty": "Actuel : {actual} {unit}",
"check_suggestion": "Vérifiez ou pesez la quantité restante"
},
"date": {
"today": "📅 Aujourd'hui",
"yesterday": "📅 Hier"
},
"scanner": {
"title_barcode": "🔖 Scanner le code-barres",
"barcode_hint": "Cadrez le code-barres du produit",
"barcode_manual_placeholder": "Ou entrez manuellement...",
"barcode_use_btn": "✅ Utiliser ce code",
"ai_identifying": "🤖 Identification du produit...",
"ai_analyzing": "🤖 Analyse IA en cours...",
"product_label_hint": "Cadrez l'étiquette du produit",
"expiry_label_hint": "Cadrez la date de péremption imprimée sur le produit",
"capture_btn": "📸 Capturer",
"capture_photo_btn": "📸 Prendre une photo",
"retake_btn": "🔄 Reprendre",
"camera_error_hint": "Assurez-vous d'utiliser HTTPS et d'avoir accordé les permissions caméra.<br>Vous pouvez entrer le code-barres manuellement ou utiliser l'identification IA.",
"no_barcode": "Pas de code-barres",
"save_new_btn": "🆕 Aucun de ceux-ci — enregistrer comme nouveau"
},
"lowstock": {
"title": "⚠️ Stock faible !",
"message": "{name} est presque épuisé — il ne reste que {qty}.",
"question": "Voulez-vous l'ajouter à la liste de courses ?",
"yes": "🛒 Oui, ajouter à Bring !",
"no": "Non, pour l'instant ça va"
},
"move": {
"title": "📦 Déplacer le reste ?",
"question": "Voulez-vous déplacer {thing} de {name} vers un autre emplacement ?",
"question_short": "Voulez-vous déplacer {thing} vers un autre emplacement ?",
"thing_opened": "l'emballage ouvert",
"thing_rest": "le reste",
"stay_btn": "Non, rester dans {location}",
"moved_toast": "📦 Emballage ouvert déplacé vers {location}",
"vacuum_restore": "🫙 Restaurer sous vide",
"vacuum_seal_rest": "🔒 Mettre le reste sous vide"
},
"nova": {
"1": "Non transformé",
"2": "Ingrédient culinaire",
"3": "Transformé",
"4": "Ultra-transformé"
},
"meal_plan_types": {
"pasta": "Pâtes",
"riso": "Riz",
"carne": "Viande",
"pesce": "Poisson",
"legumi": "Légumineuses",
"uova": "Œufs",
"formaggio": "Fromage",
"pizza": "Pizza",
"affettati": "Charcuterie",
"verdure": "Légumes",
"zuppa": "Soupe",
"insalata": "Salade",
"pane": "Pain/Sandwich",
"dolce": "Dessert",
"libero": "Libre"
},
"meal_sub": {
"dolce_torta": "Gâteau",
"dolce_crema": "Crème / Pudding",
"dolce_crumble": "Crumble / Tarte",
"dolce_biscotti": "Biscuits / Pâtisseries",
"dolce_frutta": "Dessert aux fruits",
"succo_dolce": "Sucré / Fruité",
"succo_energizzante": "Énergisant",
"succo_detox": "Détox / Vert",
"succo_rinfrescante": "Rafraîchissant",
"succo_vitaminico": "Vitaminé / Agrumes"
},
"meal_plan": {
"reset_success": "Plan hebdomadaire réinitialisé",
"not_available": "non disponible dans le garde-manger",
"suggested_by": "suggéré par le plan hebdomadaire"
},
"nutrition": {
"title": "🥗 Analyse alimentaire",
"score_excellent": "😄 Excellent",
"score_good": "🙂 Bien",
"score_improve": "😬 Améliorable",
"label_health": "🌿 Santé",
"label_variety": "🎨 Variété",
"label_fresh": "❄️ Frais",
"source": "Basé sur {n} produits dans votre garde-manger · EverShelf",
"products_count": "produits",
"today_title": "🥗 Votre garde-manger aujourd'hui",
"products_n": "{n} produits",
"macros_title": "Macronutriments estimés",
"macros_proteins": "Protéines",
"macros_carbs": "Glucides",
"macros_fat": "Lipides",
"macros_fiber": "Fibres",
"macros_source": "Estimation basée sur {n} produits en stock"
},
"facts": {
"greeting_morning": "Bonjour",
"greeting_afternoon": "Bon après-midi",
"greeting_evening": "Bonsoir",
"pantry_waiting": "{greeting} ! Votre garde-manger vous attend.",
"expired_one": "Vous avez 1 produit périmé dans votre garde-manger. Vérifiez-le !",
"expired_many": "Vous avez {n} produits périmés dans votre garde-manger. Vérifiez-les !",
"expired_list": "Produits périmés : {names}",
"expired_list_more": "et {n} autres",
"freezer_expired_ok": "{name} est périmé, mais étant au congélateur il peut encore être bon ! Vérifiez.",
"freezer_expired_old": "{name} au congélateur est périmé depuis trop longtemps. Mieux vaut le jeter.",
"fridge_expired_one": "Vous avez 1 produit périmé dans le réfrigérateur !",
"fridge_expired_many": "Vous avez {n} produits périmés dans le réfrigérateur !",
"expiring_today": "{name} expire aujourd'hui ! Utilisez-le immédiatement.",
"expiring_tomorrow": "{name} expire demain. Planifiez !",
"expiring_days": "{name} expire dans {days} jours.",
"expiring_many": "Vous avez {n} produits qui expirent bientôt.",
"expiring_this_week": "{n} produits expirent cette semaine. Planifiez vos repas en conséquence !",
"expiring_item_loc": "{name} ({loc}) expire dans {days} {dayslabel}.",
"expiring_this_month": "{n} produits expireront ce mois-ci.",
"shopping_add": "Ajouter à la liste : {names} 🛒",
"shopping_more": "et {n} autres",
"shopping_empty": "Liste de courses vide. Tout est en stock ! ✅",
"in_fridge": "Dans le réfrigérateur : {name}.",
"in_freezer": "Dans le congélateur : {name}. N'oubliez pas !",
"top_category": "Catégorie principale : {icon} {cat} avec {n} produits.",
"cat_meat": "Vous avez {n} produits carnés. 🥩",
"cat_dairy": "Vous avez {n} produits laitiers chez vous. 🥛",
"cat_veggies": "Vous avez {n} types de légumes. Super pour la santé ! 🥬",
"cat_fruit": "Vous avez {n} types de fruits. 🍎",
"cat_drinks": "Vous avez {n} boissons disponibles. 🥤",
"cat_frozen": "Vous avez {n} articles surgelés. ❄️",
"cat_pasta": "Vous avez {n} types de pâtes. 🍝 Et si on faisait une carbonara ?",
"cat_canned": "Vous avez {n} conserves dans le garde-manger. 🥫",
"cat_snacks": "Vous avez {n} snacks. Résistez à la tentation ! 🍪",
"cat_condiments": "Vous avez {n} condiments disponibles. 🧂",
"item_random": "Le saviez-vous ? Vous avez {name} dans {loc}.",
"item_qty": "{name} : vous en avez {qty}.",
"no_expiry_count": "{n} produits n'ont pas de date de péremption.",
"furthest_expiry": "Le produit avec la date de péremption la plus lointaine est {name} : {months} mois.",
"high_qty": "Vous avez un beau stock de {name} : {qty} !",
"low_qty_item": "{name} est presque épuisé. L'ajouter à votre liste de courses ?",
"low_qty_count": "{n} produits sont presque épuisés.",
"morning_bread": "Bonjour ! Vous avez du pain pour le petit-déjeuner. 🍞",
"morning_milk": "Y a-t-il du lait dans le réfrigérateur pour un cappuccino ? ☕🥛",
"morning_fruit": "Bonjour ! Des fruits frais sont un excellent début de journée. 🍎",
"noon_pasta": "C'est l'heure du déjeuner… Et si on faisait un bon bol de pâtes ? 🍝",
"noon_salad": "Une salade fraîche pour le déjeuner ? Vous avez {n} légumes ! 🥗",
"evening_meat": "Pour le dîner, vous pourriez utiliser la viande que vous avez. 🥩",
"evening_fish": "Et si on mangeait du poisson ce soir ? 🐟",
"evening_expiring": "Vous avez {n} produits qui expirent cette semaine — utilisez-les ce soir !",
"night_reminder": "Bonne nuit ! N'oubliez pas d'utiliser demain : {names}.",
"weekly_balance": "Bilan hebdomadaire : +{in} ajoutés, {out} consommés.",
"weekly_added": "Vous avez ajouté {n} produits cette semaine.",
"weekly_consumed": "Vous avez consommé {n} produits cette semaine. Bravo !",
"tip_freezer": "💡 Les produits surgelés durent bien plus longtemps que la date de péremption.",
"tip_bread": "💡 Le pain congelé garde sa fraîcheur pendant des semaines.",
"tip_fifo": "💡 Pour éviter le gaspillage, utilisez en premier les produits les plus proches de la péremption (FIFO).",
"tip_meat": "💡 La viande au congélateur peut se conserver jusqu'à 6 mois en toute sécurité.",
"tip_no_refreeze": "💡 Ne jamais recongeler un produit décongelé. Cuisinez-le immédiatement !",
"tip_fridge": "💡 Un réfrigérateur bien rangé vous fait gagner du temps et de l'argent.",
"tip_canned": "💡 Les conserves ouvertes doivent aller au réfrigérateur et être consommées en quelques jours.",
"top_brand": "La marque la plus courante dans votre garde-manger est {brand} avec {n} produits.",
"combo_pasta": "Vous avez des pâtes et des condiments : prêt pour un premier plat ! 🍝",
"combo_sandwich": "Pain et viande : un sandwich rapide est toujours une bonne idée ! 🥪",
"combo_balanced": "Légumes et viande : vous avez tout pour un repas équilibré ! 🥗🥩",
"pantry_empty": "Le garde-manger est vide ! Il est temps de faire les courses. 🛒",
"pantry_empty_scan": "Aucun produit enregistré. Scannez quelque chose pour commencer !",
"location_distribution": "Distribution : {parts}",
"day": "jour",
"days": "jours"
},
"kiosk_session": {
"first_item": "Premier article : {name} !",
"items_two_four": "{n} articles — on démarre 🚀",
"items_five_nine": "{n} articles — bon rythme ! 💪",
"items_ten_twenty": "{n} articles — presque un record 🏆",
"items_twenty_plus": "{n} articles — courses épiques ! 🛒🔥",
"duplicates_one": "1 doublon (même article deux fois)",
"duplicates_many": "{n} doublons (pris plusieurs fois)",
"top_category": "Catégorie principale : {cat} ({count}×)",
"items_fallback": "{n} article{plural} ajouté{plural}"
},
"kiosk": {
"check_btn": "🔍 Vérifier les mises à jour",
"checking": "⏳ Vérification…",
"error_check": "Erreur lors de la vérification des mises à jour",
"error_start_install": "Erreur au démarrage de l'installation",
"version_installed": "Installé : {v}",
"update_available": "⬆️ Nouvelle version disponible : <strong>{latest}</strong> (installée : {current})",
"up_to_date": "✅ Vous êtes à jour — version <strong>{v}</strong>",
"too_old": "⚠️ Le kiosque installé est trop ancien pour la vérification automatique des mises à jour.<br>Appuyez sur le bouton ci-dessous pour télécharger et installer la nouvelle version directement.",
"manual_install": "⚠️ Ce kiosque ne supporte pas l'installation automatique.<br><strong>Procédure manuelle :</strong><br>1. Quittez le kiosque (bouton ✕ en haut à gauche)<br>2. Désinstallez l'application EverShelf Kiosk<br>3. Téléchargez et installez le nouvel APK depuis GitHub :",
"starting_download": "⏳ Démarrage du téléchargement…",
"install_btn": "⬇️ Installer la mise à jour",
"exit_title": "Quitter le kiosque",
"refresh_title": "Actualiser la page"
},
"update": {
"new_version": "Nouvelle version",
"btn": "Mettre à jour"
},
"gemini": {
"chat_title": "Discussion avec Gemini",
"not_configured": "🤖 Gemini non configuré — définissez GEMINI_API_KEY dans les paramètres"
},
"appliances": {
"empty": "Aucun appareil ajouté"
},
"about": {
"title": "À propos",
"version": "Version",
"report_bug": "Signaler un bug",
"report_bug_hint": "Quelque chose ne fonctionne pas ? Envoyez-nous un rapport directement depuis l'application.",
"report_bug_modal_title": "Signaler un bug",
"report_type_bug": "Bug",
"report_type_feature": "Fonctionnalité",
"report_type_question": "Question",
"report_field_title": "Titre",
"report_field_title_ph": "Brève description du problème",
"report_field_desc": "Description",
"report_field_desc_ph": "Décrivez le problème en détail…",
"report_field_steps": "Étapes pour reproduire (optionnel)",
"report_field_steps_ph": "1. Aller à…\n2. Appuyer sur…\n3. Voir l'erreur…",
"report_auto_info": "Joint automatiquement : version {version}, langue {lang}.",
"report_send_btn": "Envoyer le rapport",
"report_bug_sending": "Envoi…",
"report_bug_sent": "Rapport envoyé — merci !",
"report_bug_error": "Impossible d'envoyer le rapport. Vérifiez votre connexion.",
"changelog": "Journal des modifications",
"github": "Dépôt GitHub"
},
"export": {
"title": "Exporter l'inventaire",
"hint": "Téléchargez l'inventaire actuel en CSV ou ouvrez la version imprimable (PDF).",
"btn_csv": "Télécharger CSV",
"btn_pdf": "PDF / Imprimer",
"btn_title": "Exporter"
},
"startup": {
"connecting": "Connexion au serveur...",
"check_php_memory": "Mémoire PHP",
"check_php_timeout": "Délai PHP",
"check_php_upload": "Upload PHP",
"check_data_dir": "Dossier de données",
"check_rate_limits": "Dossier rate limits",
"check_backups": "Dossier sauvegardes",
"check_write_test": "Test d'écriture disque",
"check_disk_space": "Espace disque",
"check_db_connect": "Connexion base de données",
"check_db_tables": "Tables de la BDD",
"check_db_integrity": "Intégrité BDD",
"check_db_wal": "Mode WAL",
"check_db_size": "Taille de la BDD",
"check_db_rows": "Données inventaire",
"check_env": "Fichier .env",
"check_gemini": "Clé Gemini AI",
"check_bring_creds": "Identifiants Bring!",
"check_bring_token": "Token Bring!",
"check_curl_ssl": "cURL SSL",
"check_internet": "Connexion internet",
"fresh_install": "nouvelle installation",
"warnings_found": "avertissements détectés",
"all_ok": "Système OK",
"critical_error_short": "Erreur critique",
"critical_error": "Erreur critique : l'application ne peut pas démarrer. Vérifiez les logs.",
"error_network": "Impossible de contacter le serveur. Vérifiez votre connexion réseau.",
"retry": "Réessayer",
"syncing_local": "Synchronisation des données locales...",
"sync_done": "Données locales synchronisées",
"token_required": "Jeton API requis",
"token_autoconfig": "Configuration de l'accès...",
"token_prompt_title": "🔒 Jeton API",
"token_prompt_hint": "Saisissez la valeur API_TOKEN du fichier .env du serveur.",
"token_prompt_btn": "Continuer"
},
"stats_monthly": {
"title": "Statistiques Mensuelles",
"consumed": "produits utilisés",
"trend_up": "+{pct}% vs {prev}",
"trend_down": "-{pct}% vs {prev}",
"trend_same": "même rythme que le mois dernier",
"added": "ajoutés",
"wasted": "gaspillés",
"top_used": "le plus utilisé",
"top_cats": "Catégories principales",
"source": "Historique des transactions · mois en cours"
}
}