Files
EverShelf/translations/en.json
T
dadaloop82 c3b19a6c48 feat: expired banner for opened products, AI model fallback, TTS cooking improvements
- Banner: detect expired opened-products via effective shelf-life (opened_at +
  estimateOpenedExpiryDays), not just raw expiry_date — fixes Fagioli/Panna case
- Banner: expired items show safety tip inline; danger-level items (fridge dairy,
  meat, fish) get red banner + 'L'ho buttato' as primary button, 'Usa comunque'
  demoted to grey; safety-ok/warning items keep original button order
- Banner: anomaly dismiss button now shows current inventory qty ('La quantità è
  giusta (2 pz)') so the action is unambiguous
- AI: add callGeminiWithFallback() helper — tries gemini-2.5-flash first (separate
  quota), falls back to gemini-2.0-flash; applied to all endpoints (expiry, chat,
  identify, recipe non-streaming, shopping name classifier)
- AI: show friendly 'Quota AI esaurita' message instead of raw Gemini error string
- Cooking TTS: fix auto-speak broken since 'auto-speak removed' comment — each step
  is now read automatically on navigate and on first step when entering cooking mode
- Cooking TTS: remove incorrect s.tts_enabled gate — _cookingTTS toggle is the only
  gate; browser Web Speech API used by default without requiring Settings config
- Cooking TTS: timer fires '10 secondi rimanenti' warning at T-10s
- Cooking TTS: announce recipe completion ('Buon appetito!') on last step confirm
- i18n: add timer_warning_tts, recipe_done_tts, error.ai_quota keys (IT/EN/DE)
- CSS: add banner-expired-danger, banner-safety-* styles for unsafe expired items
2026-04-28 12:46:00 +00:00

714 lines
33 KiB
JSON
Raw Blame History

This file contains ambiguous Unicode characters
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": "Loading..."
},
"nav": {
"title": "🏠 EverShelf",
"home": "Home",
"inventory": "Pantry",
"recipes": "Recipes",
"shopping": "Shopping",
"log": "Log"
},
"btn": {
"back": "← Back",
"save": "💾 Save",
"cancel": "✕ Cancel",
"close": "Close",
"add": "✅ Add",
"delete": "Delete",
"edit": "✏️ Edit",
"search": "🔍 Search",
"go": "✅ Go",
"toggle_password": "👁️ Show/Hide",
"load_more": "Load more...",
"save_config": "💾 Save Configuration",
"save_product": "💾 Save Product",
"restart": "↺ Restart",
"reset_default": "↺ Reset to default",
"save_info": "💾 Save information",
"retry": "🔄 Retry"
},
"locations": {
"dispensa": "Pantry",
"frigo": "Fridge",
"freezer": "Freezer",
"altro": "Other"
},
"categories": {
"latticini": "Dairy",
"carne": "Meat",
"pesce": "Fish",
"frutta": "Fruit",
"verdura": "Vegetables",
"pasta": "Pasta & Rice",
"pane": "Bread & Bakery",
"surgelati": "Frozen",
"bevande": "Beverages",
"condimenti": "Condiments",
"snack": "Snacks & Sweets",
"conserve": "Canned Goods",
"cereali": "Cereals & Legumes",
"igiene": "Hygiene",
"pulizia": "Household",
"altro": "Other",
"select": "-- Select --"
},
"units": {
"pz": "pcs",
"conf": "pkg",
"g": "g",
"ml": "ml",
"pieces": "Pieces",
"grams": "Grams",
"box": "Package",
"boxes": "Packages"
},
"shopping_sections": {
"frutta_verdura": "Fruits & Vegetables",
"carne_pesce": "Meat & Fish",
"latticini": "Dairy & Fresh",
"pane_dolci": "Bread & Sweets",
"pasta": "Pasta & Cereals",
"conserve": "Canned & Sauces",
"surgelati": "Frozen",
"bevande": "Beverages",
"pulizia_igiene": "Cleaning & Hygiene",
"altro": "Other"
},
"dashboard": {
"expired_title": "🚫 Expired",
"expiring_title": "⏰ Expiring Soon",
"stats_period": "📊 Last 30 days",
"opened_title": "📦 Opened Products",
"review_title": "🔍 To Review",
"review_hint": "Quantities that seem unusual. Confirm if correct or modify.",
"quick_recipe": "🍳 Quick recipe with expiring products",
"banner_review_title": "Anomalous quantity",
"banner_review_action_ok": "It's correct",
"banner_review_action_edit": "Correct",
"banner_review_action_weigh": "Weigh",
"banner_review_dismiss": "Dismiss",
"banner_prediction_title": "Anomalous consumption",
"banner_prediction_hint": "Based on predictions, this quantity doesn't match expected consumption.",
"banner_prediction_action_confirm": "Confirm {qty} {unit} is correct",
"banner_prediction_action_weigh": "Weigh now",
"banner_prediction_action_edit": "Update quantity",
"banner_expired_title": "Expired product",
"banner_expired_today": "Expired today",
"banner_expired_days": "Expired {days} days ago",
"banner_expired_action_use": "Use anyway",
"banner_expired_action_throw": "I threw it away",
"banner_expired_action_edit": "Fix date",
"banner_anomaly_action_edit": "Fix inventory",
"banner_anomaly_action_dismiss": "Quantity is correct",
"banner_expiring_title": "Expiring soon",
"banner_expiring_today": "Expires today!",
"banner_expiring_tomorrow": "Expires tomorrow",
"banner_expiring_days": "Expires in {days} days",
"banner_expiring_action_use": "Use now",
"banner_finished_title": "finished?",
"banner_finished_detail": "I recorded that {name} reached zero stock. Is it really gone, or do you still have some?",
"banner_finished_action_yes": "Yes, it's done",
"banner_finished_action_no": "No, I still have some",
"banner_review_unusual_pkg_title": "Unusual package size",
"banner_review_unusual_pkg_detail": "You set a package of {qty} {unit} — the size seems very large. Check if correct or edit.",
"banner_review_low_qty_title": "Very low quantity",
"banner_review_low_qty_detail": "You only have {qty} in stock — seems very little, could be a typo. Confirm if correct.",
"banner_review_high_qty_title": "Unusually high quantity",
"banner_review_high_qty_detail": "You have {qty} in stock — the figure seems very high. Confirm if correct or edit.",
"banner_prediction_rate_day": "Average ~{n} {unit}/day",
"banner_prediction_rate_week": "Average ~{n} {unit}/week",
"banner_prediction_days_ago": "{n} days ago you restocked",
"banner_prediction_more": "I expected {expected} {unit}{time}, but you have {actual} {unit}. Did you add stock without recording it?",
"banner_prediction_less": "I expected {expected} {unit}{time}, but you only have {actual} {unit}. Did you use more than usual?",
"banner_finished_zero": "Inventory shows zero, but recorded movements suggest it shouldn't be empty.",
"banner_finished_expected": "According to records you should still have {qty} {unit}.",
"banner_finished_check": "Can you check?",
"banner_anomaly_phantom_title": "you have more stock than expected",
"banner_anomaly_phantom_detail": "Inventory shows {inv_qty} {unit}, but based on records you should only have {expected_qty} {unit}. Did you add stock without recording it?",
"banner_anomaly_ghost_title": "you have less stock than expected",
"banner_anomaly_ghost_detail": "Based on recorded operations you should have {expected_qty} {unit} of {name}, but inventory shows only {inv_qty} {unit}. Did you take stock without recording it?",
"consumed": "Consumed: {n} ({pct}%)",
"wasted": "Wasted: {n} ({pct}%)",
"more_opened": "and {n} more opened...",
"banner_expired_detail": "{when} · you still have <strong>{qty}</strong>."
},
"inventory": {
"title": "Pantry",
"filter_all": "All",
"search_placeholder": "🔍 Search product...",
"recent_title": "🕐 Recently used",
"popular_title": "⭐ Most used",
"empty": "No products here.\nScan a product to add it!",
"no_items_found": "No inventory items found",
"qty_remainder_suffix": "left",
"vacuum_badge": "🫙 Vacuum sealed",
"opened_badge": "📭 Opened",
"label_expiry": "📅 Expiry",
"label_storage": "🫙 Storage",
"label_status": "📭 Status",
"opened_since": "Opened since {date}",
"label_position": "📍 Location",
"label_quantity": "📦 Quantity",
"label_added": "📅 Added",
"empty_text": "No products here.<br>Scan a product to add it!",
"empty_db": "No products in the database.<br>Scan a product to get started!"
},
"scan": {
"title": "Scan Product",
"mode_shopping": "🛒 Shopping Mode",
"mode_shopping_end": "✅ End shopping",
"zoom": "Zoom",
"barcode_placeholder": "Enter barcode...",
"quick_name_divider": "or type the name",
"quick_name_placeholder": "E.g.: Apples, Zucchini, Bread...",
"manual_entry": "✏️ Manual Entry",
"ai_identify": "🤖 Identify with AI",
"hint": "Scan the barcode, type the product name, or use AI to identify it",
"debug_toggle": "🐛 Debug Log",
"barcode_acquired": "🔖 Barcode scanned: {code}",
"scan_barcode": "🔖 Scan Barcode"
},
"action": {
"title": "What do you want to do?",
"add_btn": "📥 ADD",
"add_sub": "to pantry/fridge",
"use_btn": "📤 USE / CONSUME",
"use_sub": "from pantry/fridge",
"have_title": "📦 Already in stock!",
"add_more_sub": "add more",
"use_qty_sub": "how much you used",
"throw_btn": "🗑️ DISCARD",
"throw_sub": "throw away",
"edit_sub": "expiry, location…"
},
"add": {
"title": "Add to Pantry",
"location_label": "📍 Where do you put it?",
"quantity_label": "📦 Quantity",
"conf_size_label": "📦 Each package contains:",
"conf_size_placeholder": "e.g. 300",
"vacuum_label": "🫙 Vacuum sealed",
"vacuum_hint": "Expiry date will be extended automatically",
"submit": "✅ Add",
"purchase_type_label": "🛒 This product is...",
"new_btn": "🆕 Just bought",
"existing_btn": "📦 I already had it",
"remaining_label": "📦 Remaining quantity",
"remaining_hint": "Approximately how much is left?",
"remaining_full": "🟢 Full",
"remaining_half": "🟠 Half",
"estimated_expiry": "Estimated expiry:",
"suffix_freezer": "(freezer)",
"suffix_vacuum": "(vacuum sealed)",
"hint_modify": "📝 You can change the date or scan it with the camera",
"scan_expiry_title": "📷 Scan Expiry Date",
"product_added": "✅ {name} added!{qty}",
"suffix_freezer_vacuum": "(freezer + vacuum sealed)"
},
"use": {
"title": "Use / Consume",
"location_label": "📍 From where?",
"quantity_label": "How much did you use?",
"partial_hint": "Or specify the quantity used:",
"use_all": "🗑️ Used ALL / Finished",
"submit": "📤 Use this quantity",
"available": "📦 Available:",
"not_in_inventory": "⚠️ Product not in inventory.",
"expiry_warning": "⚠️ Use first the one{loc} that expires on {date} — {when}!",
"throw_title": "🗑️ Discard Product",
"throw_all": "🗑️ Discard ALL ({qty})",
"throw_qty_label": "How much to discard?",
"throw_qty_hint": "or enter a quantity:",
"throw_partial_btn": "🗑️ Discard this quantity",
"when_expired": "expired {n} days ago",
"when_today": "expires <strong>today</strong>",
"when_tomorrow": "expires <strong>tomorrow</strong>",
"when_days": "expires in <strong>{n} days</strong>",
"toast_used": "📤 Used {qty} of {name}",
"toast_bring": "🛒 Product finished → added to Bring!"
},
"product": {
"title_new": "New Product",
"title_edit": "Edit Product",
"ai_fill": "📷 Take photo and identify with AI",
"ai_fill_hint": "AI will automatically fill in the product fields",
"name_label": "🏷️ Product Name *",
"name_placeholder": "E.g.: Whole milk, Penne pasta...",
"brand_label": "🏢 Brand",
"brand_placeholder": "E.g.: Barilla, Granarolo, Mutti...",
"category_label": "📂 Category",
"unit_label": "📏 Unit of measure",
"default_qty_label": "🔢 Default quantity",
"conf_size_label": "📦 Each package contains:",
"conf_size_placeholder": "e.g. 300",
"notes_label": "📝 Notes",
"notes_placeholder": "E.g.: lactose free, organic, store in fridge after opening...",
"barcode_label": "🔖 Barcode",
"barcode_placeholder": "Barcode (if available)",
"barcode_hint": "⚠️ Add the barcode so next time you just need to scan it!",
"submit": "💾 Save Product",
"name_required": "Enter the product name",
"conf_size_required": "Specify the package content",
"expiry_estimated": "Estimated expiry:",
"scan_expiry": "Scan expiry date",
"expiry_hint": "📝 You can edit the date or scan it with the camera",
"add_batch": "📦 + Batch with different expiry",
"package_info": "📦 Package: {info}",
"edit_catalog": "⚙️ Edit product info (name, brand, category…)",
"not_recognized": "⚠️ Product not recognized",
"edit_info": "✏️ Edit information",
"modify_details": "EDIT\nexpiry, location…",
"already_in_pantry": "📋 Already in pantry",
"no_barcode": "No barcode"
},
"products": {
"title": "📦 All Products",
"search_placeholder": "🔍 Search product...",
"empty": "No products in database.\nScan a product to get started!",
"no_category": "No products in this category"
},
"recipes": {
"title": "🍳 Recipes",
"generate": "✨ Generate new recipe"
},
"shopping": {
"title": "🛒 Shopping List",
"bring_loading": "Connecting to Bring!...",
"tab_to_buy": "🛍️ To buy",
"tab_forecast": "🧠 Forecast",
"total_label": "💰 Estimated total",
"section_to_buy": "🛍️ To buy",
"suggestions_title": "💡 AI Suggestions",
"suggestions_add": "✅ Add selected to Bring!",
"search_prices": "🔍 Search all prices",
"suggest_btn": "🤖 Suggest what to buy",
"smart_title": "🧠 Smart Predictions",
"smart_empty": "No predictions available.<br>Add products to your pantry to receive smart predictions.",
"smart_filter_all": "All",
"smart_filter_critical": "🔴 Urgent",
"smart_filter_high": "🟠 Soon",
"smart_filter_medium": "🟡 Plan",
"smart_filter_low": "🟢 Forecast",
"smart_add": "🛒 Add selected to Bring!",
"empty": "Shopping list empty!\nUse the button below to generate suggestions.",
"already_in_list": "🛒 \"{name}\" is already in the shopping list",
"already_in_list_short": "️ Already in the shopping list",
"add_prompt": "Do you want to add it to the shopping list?",
"smart_already": "📊 Smart shopping already predicts {name}",
"all_searched": "All products have already been searched. Use 🔄 to search individual ones.",
"search_complete": "Search complete: {count} products",
"removed_sufficient": "🧹 {removed} product(s) with sufficient stock removed from the list",
"bring_badge": "🛒 Already on Bring!",
"add_urgent_toast": "🔴 {n} urgent product(s) automatically added to Bring!",
"migration_done": "✅ {migrated} updated, {skipped} already ok",
"added_to_bring": "🛒 {n} products added to Bring!",
"added_to_bring_skip": "{n} already present",
"all_on_bring": "All products were already on Bring!",
"freq_high": "📈 Frequent",
"freq_regular": "📊 Regular",
"freq_occasional": "📉 Occasional",
"out_of_stock": "Out of stock",
"scan_toast": "📷 Scan: {name}",
"empty_category": "No products in this category",
"session_empty": "🛒 No products yet",
"urgency_critical": "Urgent",
"urgency_high": "Soon",
"urgency_medium": "Plan",
"urgency_low": "Forecast",
"urgency_medium_short": "Medium",
"urgency_low_short": "Ok",
"tag_urgent": "🔴 Urgent",
"tag_priority": "⭐ Priority",
"tag_check": "✅ Check",
"smart_already_predicted": "📊 Smart shopping already predicts <strong>{name}</strong>{urgency}.",
"item_removed": "✅ {name} removed from list!",
"urgency_spec_critical": "⚡ Urgent",
"urgency_spec_high": "🟠 Soon"
},
"ai": {
"title": "🤖 AI Identification",
"capture": "📸 Take Photo",
"retake": "🔄 Retake",
"hint": "Take a photo of the product and AI will try to identify it",
"identifying": "🤖 Identifying product...",
"no_api_key": "⚠️ Gemini API key not configured.\n<small>Add GEMINI_API_KEY to the .env file on the server.</small>",
"fields_filled": "✅ Fields filled by AI",
"use_data": "✅ Use AI data",
"use_data_no_barcode": "✅ Use AI data (no barcode)"
},
"log": {
"title": "📒 Operations Log",
"type_added": "Added",
"type_waste": "Discarded",
"type_used": "Used",
"type_bring": "Added to Bring!",
"undone_badge": "Undone",
"undo_title": "Undo this operation",
"load_error": "Error loading log",
"empty": "No operations recorded.",
"undo_action_remove": "removal of",
"undo_action_restore": "restock of",
"undo_confirm": "Undo this operation?\n→ {action} {name}",
"undo_success": "↩ Operation undone for {name}",
"already_undone": "Operation already undone",
"too_old": "Cannot undo operations older than 24 hours",
"undo_error": "Error during undo"
},
"chat": {
"title": "Gemini Chef",
"welcome": "Hi! I'm your kitchen assistant",
"welcome_desc": "Ask me to make you a juice, a snack, a quick dish... I know your pantry, your appliances and your preferences!",
"suggestion_snack": "🍿 Quick snack",
"suggestion_juice": "🥤 Juice/Smoothie",
"suggestion_light": "🥗 Something light",
"suggestion_expiry": "⏰ Use expiring items",
"clear": "New conversation",
"placeholder": "Ask something...",
"cleared": "Chat cleared",
"suggestion_snack_text": "What can I make for a quick snack?",
"suggestion_juice_text": "Make me a juice or smoothie with what I have",
"suggestion_light_text": "I'm hungry but want something light",
"suggestion_expiry_text": "What's about to expire and how can I use it?"
},
"cooking": {
"close": "Close",
"tts_btn": "Read aloud",
"restart": "↺ Restart",
"replay": "🔊 Replay",
"timer": "⏱️ {time} · Timer",
"prev": "◀ Previous",
"next": "Next ▶",
"ingredient_used": "✔️ Deducted",
"ingredient_use_btn": "📦 Use",
"ingredient_deduct_title": "Deduct from pantry",
"timer_expired_tts": "Timer {label} expired!",
"timer_warning_tts": "Heads up! {label}: 10 seconds left!",
"recipe_done_tts": "Recipe complete! Enjoy your meal!"
},
"settings": {
"title": "⚙️ Settings",
"tab_api": "API Keys",
"tab_bring": "Bring!",
"tab_recipe": "Recipes",
"tab_mealplan": "Weekly Plan",
"tab_appliances": "Appliances",
"tab_spesa": "Online Shopping",
"tab_camera": "Camera",
"tab_security": "Security",
"tab_tts": "Voice (TTS)",
"tab_language": "Language",
"tab_scale": "Smart Scale",
"gemini": {
"title": "🤖 Google Gemini AI",
"hint": "API key for product identification, expiry dates and recipes.",
"key_label": "Gemini API Key"
},
"bring": {
"title": "🛒 Bring! Shopping List",
"hint": "Credentials for the Bring! shopping list integration.",
"email_label": "📧 Bring! Email",
"password_label": "🔒 Bring! Password"
},
"recipe": {
"title": "🍳 Recipe Preferences",
"hint": "Configure the default options for recipe generation.",
"persons_label": "👥 Default servings",
"options_label": "🎯 Default recipe options",
"fast": "⚡ Quick Meal",
"light": "🥗 Light Meal",
"expiry": "⏰ Expiry Priority",
"healthy": "💚 Extra Healthy",
"opened": "📦 Open Items Priority",
"zerowaste": "♻️ Zero Waste",
"dietary_label": "🚫 Intolerances / Restrictions",
"dietary_placeholder": "E.g.: gluten free, lactose free, vegetarian..."
},
"mealplan": {
"title": "📅 Weekly Meal Plan",
"hint": "Set the meal type for each day. It will be used as a guide in recipe generation.",
"enabled": "✅ Enable weekly meal plan",
"legend": "🌤️ = Lunch · 🌙 = Dinner · Tap a badge to change it.",
"types_title": "📋 Available types"
},
"appliances": {
"title": "🔌 Available Appliances",
"hint": "Indicate the appliances you have. They will be considered in recipe generation.",
"new_placeholder": "E.g.: Bread machine, Thermomix, Air fryer...",
"quick_title": "Quick add:",
"oven": "🔥 Oven",
"microwave": "📡 Microwave",
"air_fryer": "🍟 Air fryer",
"bread_maker": "🍞 Bread maker",
"bimby": "🤖 Thermomix/Cookeo",
"mixer": "🌀 Stand mixer",
"steamer": "♨️ Steamer",
"pressure_cooker": "🫕 Pressure cooker",
"toaster": "🍞 Toaster",
"blender": "🍹 Blender",
"empty": "No appliances added"
},
"spesa": {
"title": "🛍️ Online Shopping",
"hint": "Configure the online shopping provider.",
"provider_label": "🏪 Provider",
"email_label": "📧 Email",
"password_label": "🔒 Password",
"login_btn": "🔐 Login",
"ai_prompt_label": "🤖 AI product selection prompt",
"ai_prompt_placeholder": "Instructions for AI when choosing between multiple products...",
"ai_prompt_hint": "AI uses this prompt to choose the most appropriate product from results. Leave empty for default behavior.",
"configure_first": "Configure Online Shopping in settings first"
},
"camera": {
"title": "📷 Camera",
"hint": "Choose which camera to use for barcode scanning and AI identification.",
"device_label": "📸 Default camera",
"back": "📱 Rear (default)",
"front": "🤳 Front",
"devices_hint": "If you have multiple cameras, you can select a specific one from the list above after granting permissions.",
"detect_btn": "🔄 Detect cameras"
},
"security": {
"title": "🔒 HTTPS Certificate",
"hint": "If the browser shows the error \"Your connection is not private\" (ERR_CERT_AUTHORITY_INVALID), you need to install the CA certificate on the device.",
"download_btn": "📥 Download CA Certificate"
},
"tts": {
"title": "🔊 Voice & TTS",
"hint": "Configure text-to-speech via any external REST API. Recipe steps and expired timers will be sent to the configured endpoint.",
"enabled": "✅ Enable TTS",
"url_label": "🌐 Endpoint URL",
"method_label": "📡 HTTP Method",
"auth_label": "🔐 Authentication",
"auth_bearer": "Bearer Token",
"auth_custom": "Custom Header",
"auth_none": "None",
"token_label": "🔑 Bearer Token",
"custom_header_name": "📋 Header name",
"custom_header_value": "📋 Header value",
"content_type_label": "📄 Content-Type",
"payload_key_label": "🗝️ Text field in payload",
"payload_key_hint": "Name of the JSON field that will contain the text to read (e.g.: message, text).",
"extra_fields_label": " Extra fields (JSON)",
"extra_fields_placeholder": "{\"entity_id\": \"media_player.living_room\"}",
"extra_fields_hint": "Additional fields to include in the payload, in JSON format. Leave empty if not needed.",
"test_btn": "🔊 Send Test Voice"
},
"language": {
"title": "🌐 Language",
"hint": "Select the interface language.",
"label": "🌐 Language",
"restart_notice": "The page will reload to apply the new language."
},
"scale": {
"title": "⚖️ Smart Scale",
"hint": "Connect a Bluetooth scale via the Android gateway to automatically read weight.",
"tab": "Smart Scale",
"enabled": "✅ Enable smart scale",
"url_label": "🌐 WebSocket Gateway URL",
"url_placeholder": "ws://192.168.1.x:8765",
"url_hint": "URL shown by the Android app (same Wi-Fi network). E.g.:",
"test_btn": "🔗 Test connection",
"download_btn": "📥 Download Android Gateway (APK)",
"download_hint": "Android app that bridges your BLE scale and EverShelf.",
"download_sub": "Source: evershelf-scale-gateway/ in the project root"
},
"kiosk": {
"hint": "Turn an Android tablet into an always-on EverShelf panel with built-in BLE scale gateway.",
"download_btn": "📥 Download EverShelf Kiosk (APK)",
"download_sub": "Full-screen kiosk mode + integrated scale gateway. Source: evershelf-kiosk/"
},
"saved": "✅ Configuration saved!",
"saved_local": "✅ Configuration saved locally",
"saved_local_error": "⚠️ Saved locally, server error: {error}"
},
"expiry": {
"today": "TODAY",
"tomorrow": "Tomorrow",
"days": "{days} days",
"expired_days": "{days}d ago",
"expired_yesterday": "Yesterday",
"expired_today": "Today",
"badge_today": "⚠️ Expires today!",
"badge_tomorrow": "⏰ Tomorrow",
"badge_tomorrow_long": "⏰ Expires tomorrow",
"badge_days": "⏰ {n} days",
"badge_expired_ago": "⚠️ Expired {n}d ago",
"badge_expired": "⛔ Expired!",
"badge_stable": "✅ Stable",
"badge_expiring_short": "⏰ Exp. in {n}d",
"badge_ok_still": "✅ Still {n}d",
"badge_expires_red": "🔴 Exp. in {n}d",
"badge_expires_yellow": "🟡 Exp. in {n}d",
"badge_expired_bare": "⚠️ Expired",
"badge_expires_warn": "⚠️ Exp. in {n}d",
"badge_days_left": "⏳ ~{n}d left",
"days_approx": "~{n} days",
"weeks_approx": "~{n} weeks",
"months_approx": "~{n} months",
"years_approx": "~{n} years",
"expired_today_long": "Expired today",
"expired_ago_long": "Expired {n} days ago",
"expired_suffix": "— Expired!",
"days_compact": "{n}d"
},
"status": {
"ok": "OK",
"check": "Check",
"discard": "Discard",
"tip_freezer_ok": "In freezer: still safe (~{n}d margin)",
"tip_freezer_check": "In freezer for a long time, may have lost quality. Consume soon",
"tip_freezer_danger": "In freezer too long, risk of freezer burn and degradation",
"tip_highRisk_check": "Expired recently, check smell and appearance before consuming",
"tip_highRisk_danger": "Perishable product expired: discard for safety",
"tip_medRisk_check1": "Check appearance and smell before consuming",
"tip_medRisk_check2": "Expired a while ago, check carefully before use",
"tip_medRisk_danger": "Too long since expiry, better to discard",
"tip_lowRisk_ok": "Long-lasting product, still safe to consume",
"tip_lowRisk_check": "Expired over a month ago, check package integrity",
"tip_lowRisk_danger": "Expired too long ago, better not to risk it"
},
"toast": {
"product_saved": "Product saved!",
"product_created": "Product created!",
"product_updated": "✅ Product updated!",
"product_removed": "Product removed",
"updated": "Updated!",
"quantity_confirmed": "✓ Quantity confirmed",
"added_to_inventory": "✅ {name} added!",
"removed_from_list": "✅ {name} removed from the list!",
"removed_from_list_short": "Removed from the list",
"added_to_shopping": "🛒 Added to the shopping list!",
"removed_from_shopping": "🛒 Removed from the shopping list",
"finished_to_bring": "🛒 Product finished → added to Bring!",
"thrown_away": "🗑️ {name} thrown away!",
"thrown_away_partial": "🗑️ Thrown away {qty} {unit} of {name}",
"product_finished_confirmed": "✅ Removed — add it again when you restock",
"appliance_added": "Appliance added",
"item_added": "{name} added"
},
"error": {
"generic": "Error",
"loading": "Error loading product",
"not_found": "Product not found",
"not_found_manual": "Product not found. Enter it manually.",
"search": "Search error. Try again.",
"search_short": "Search error",
"save": "Error saving",
"connection": "Connection error",
"camera": "Cannot access camera",
"bring_add": "Error adding to Bring!",
"bring_connection": "Bring! connection error",
"identification": "Identification error",
"ai_quota": "AI quota exhausted. Please try again in a few minutes.",
"barcode_empty": "Enter a barcode",
"barcode_format": "Barcode must contain only numbers (4-14 digits)",
"min_chars": "Type at least 2 characters",
"not_in_inventory": "Product not in inventory",
"appliance_exists": "Appliance already exists",
"already_exists": "Already exists",
"network_retry": "Connection error. Try again."
},
"confirm": {
"remove_item": "Do you really want to remove this product from inventory?",
"kiosk_exit": "Exit kiosk mode?"
},
"edit": {
"title": "Edit {name}",
"unknown_hint": "Enter the product name and information",
"label_name": "🏷️ Product name"
},
"screensaver": {
"recipe_btn": "Recipes",
"scan_btn": "Scan product"
},
"days": {
"mon": "Monday",
"tue": "Tuesday",
"wed": "Wednesday",
"thu": "Thursday",
"fri": "Friday",
"sat": "Saturday",
"sun": "Sunday"
},
"meal_types": {
"lunch": "Lunch",
"dinner": "Dinner"
},
"scale": {
"status_connected": "Scale connected",
"status_searching": "Gateway connected, waiting for scale…",
"status_disconnected": "Scale gateway unreachable",
"status_error": "Gateway connection error",
"not_connected": "Scale gateway not connected",
"read_btn": "⚖️ Read from scale",
"reading_title": "Scale reading",
"place_on_scale": "Place the product on the scale…",
"waiting_stable": "Weight will be captured automatically once the reading is stable.",
"no_url": "Enter the gateway URL",
"testing": "⏳ Testing connection…",
"connected_ok": "Gateway connection successful!",
"timeout": "Timeout: no response from gateway",
"error_connect": "Cannot connect to gateway",
"tab": "Smart Scale",
"low_weight": "Weight < 10 g · enter manually\n(auto-reading requires at least 10 g)",
"density_hint": "(density {density} g/ml)",
"ml_hint": "(will be converted to ml)",
"weight_detected": "Weight detected — wait 10s for stability…",
"weight_too_low": "Weight too low — waiting…",
"stable": "✓ Stable",
"auto_confirm": "✅ {val} {unit} — auto-confirm in 5s (tap to cancel)",
"cancelled_replace": "Cancelled — replace the ingredient on the scale to resume"
},
"prediction": {
"expected_qty": "Expected: {expected} {unit}",
"actual_qty": "Current: {actual} {unit}",
"check_suggestion": "Check or weigh the remaining quantity"
},
"date": {
"today": "📅 Today",
"yesterday": "📅 Yesterday"
},
"scanner": {
"title_barcode": "🔖 Scan Barcode",
"barcode_hint": "Frame the product barcode",
"barcode_manual_placeholder": "Or enter manually...",
"barcode_use_btn": "✅ Use this code",
"ai_identifying": "🤖 Identifying product...",
"ai_analyzing": "🤖 AI analysis in progress...",
"product_label_hint": "Frame the product label",
"expiry_label_hint": "Frame the expiry date printed on the product",
"capture_btn": "📸 Capture",
"capture_photo_btn": "📸 Take Photo",
"retake_btn": "🔄 Retake",
"camera_error_hint": "Ensure you use HTTPS and have granted camera permissions.<br>You can enter the barcode manually or use AI identification.",
"no_barcode": "No barcode"
},
"lowstock": {
"title": "⚠️ Running low!",
"message": "{name} is running low — only {qty} remaining.",
"question": "Do you want to add it to the shopping list?",
"yes": "🛒 Yes, add to Bring!",
"no": "No, I'm fine for now"
},
"move": {
"title": "📦 Move the rest?",
"question": "Do you want to move the {thing} of {name} to another location?",
"question_short": "Do you want to move the {thing} to another location?",
"thing_opened": "opened package",
"thing_rest": "rest",
"stay_btn": "No, stay in {location}",
"moved_toast": "📦 Opened package moved to {location}",
"vacuum_restore": "🫙 Restore vacuum sealed"
},
"nova": {
"1": "Unprocessed",
"2": "Culinary ingredient",
"3": "Processed",
"4": "Ultra-processed"
}
}