98c38f017e
When the barcode scanner cannot read a code within 5 seconds and Gemini is available, a camera frame is automatically captured and sent to the new gemini_barcode_visual endpoint for visual product identification. The result pre-fills the product form identically to a barcode scan. - PHP: new geminiBarcodeVisual() function + router case + aiActions entry - PHP: barcode_ai_fallback setting in getServerSettings() + saveSettings() boolMap - JS: _aiFallbackTimer (cleared on detection/stop), 5s timer in initScanner() - JS: _tryGeminiVisualBarcode() — captures JPEG frame, calls API, saves product - JS: barcode_ai_fallback wired into serverKeys, applyUI, collectUI, POST body - HTML: AI fallback toggle in Settings → Camera card - Translations: ai_fallback_* strings in scan + settings.camera (it/en/de/fr/es) Feature is disabled by default (BARCODE_AI_FALLBACK=false).
1406 lines
70 KiB
JSON
1406 lines
70 KiB
JSON
{
|
||
"app": {
|
||
"name": "EverShelf",
|
||
"loading": "Cargando..."
|
||
},
|
||
"nav": {
|
||
"title": "EverShelf",
|
||
"home": "Inicio",
|
||
"inventory": "Despensa",
|
||
"recipes": "Recetas",
|
||
"shopping": "Compras",
|
||
"log": "Registro",
|
||
"settings": "Ajustes"
|
||
},
|
||
"btn": {
|
||
"back": "← Volver",
|
||
"save": "💾 Guardar",
|
||
"cancel": "✕ Cancelar",
|
||
"close": "Cerrar",
|
||
"add": "✅ Añadir",
|
||
"delete": "Eliminar",
|
||
"edit": "✏️ Editar",
|
||
"use": "Usar",
|
||
"edit_item": "Editar",
|
||
"search": "🔍 Buscar",
|
||
"go": "✅ Ir",
|
||
"toggle_password": "👁️ Mostrar/Ocultar",
|
||
"load_more": "Cargar más...",
|
||
"save_config": "💾 Guardar configuración",
|
||
"save_product": "💾 Guardar producto",
|
||
"restart": "↺ Reiniciar",
|
||
"reset_default": "↺ Restablecer valores por defecto",
|
||
"save_info": "💾 Guardar información",
|
||
"retry": "🔄 Reintentar",
|
||
"yes_short": "Sí",
|
||
"no_short": "No"
|
||
},
|
||
"form": {
|
||
"select_placeholder": "-- Seleccionar --"
|
||
},
|
||
"locations": {
|
||
"dispensa": "Despensa",
|
||
"frigo": "Nevera",
|
||
"freezer": "Congelador",
|
||
"altro": "Otro"
|
||
},
|
||
"categories": {
|
||
"latticini": "Lácteos",
|
||
"carne": "Carne",
|
||
"pesce": "Pescado",
|
||
"frutta": "Fruta",
|
||
"verdura": "Verduras",
|
||
"pasta": "Pasta y Arroz",
|
||
"pane": "Pan y Panadería",
|
||
"surgelati": "Congelados",
|
||
"bevande": "Bebidas",
|
||
"condimenti": "Condimentos",
|
||
"snack": "Snacks y Dulces",
|
||
"conserve": "Conservas",
|
||
"cereali": "Cereales y Legumbres",
|
||
"igiene": "Higiene",
|
||
"pulizia": "Limpieza",
|
||
"altro": "Otro",
|
||
"select": "-- Seleccionar --"
|
||
},
|
||
"units": {
|
||
"pz": "uds",
|
||
"conf": "paq",
|
||
"g": "g",
|
||
"ml": "ml",
|
||
"pieces": "Unidades",
|
||
"grams": "Gramos",
|
||
"box": "Paquete",
|
||
"boxes": "Paquetes",
|
||
"millilitres": "Mililitros",
|
||
"from": "de"
|
||
},
|
||
"shopping_sections": {
|
||
"frutta_verdura": "Frutas y Verduras",
|
||
"carne_pesce": "Carne y Pescado",
|
||
"latticini": "Lácteos y Frescos",
|
||
"pane_dolci": "Pan y Dulces",
|
||
"pasta": "Pasta y Cereales",
|
||
"conserve": "Conservas y Salsas",
|
||
"surgelati": "Congelados",
|
||
"bevande": "Bebidas",
|
||
"pulizia_igiene": "Limpieza e Higiene",
|
||
"altro": "Otro"
|
||
},
|
||
"dashboard": {
|
||
"expired_title": "🚫 Caducado",
|
||
"expiring_title": "⏰ Caduca pronto",
|
||
"stats_period": "📊 Últimos 30 días",
|
||
"opened_title": "📦 Productos abiertos",
|
||
"review_title": "🔍 Por revisar",
|
||
"review_hint": "Cantidades inusuales. Confirma si son correctas o modifícalas.",
|
||
"quick_recipe": "Receta rápida con productos que caducan",
|
||
"banner_review_title": "Cantidad anormal",
|
||
"banner_review_action_ok": "Es correcto",
|
||
"banner_review_action_finish": "🗑️ Todo terminado",
|
||
"banner_review_action_edit": "Corregir",
|
||
"banner_review_action_weigh": "Pesar",
|
||
"banner_review_dismiss": "Ignorar",
|
||
"banner_prediction_title": "Consumo por revisar",
|
||
"banner_prediction_hint": "La estimación de consumo se adapta a los datos recientes: confirma solo si la cantidad actual es correcta.",
|
||
"banner_prediction_action_confirm": "Confirmar {qty} {unit}",
|
||
"banner_prediction_action_weigh": "Pesar ahora",
|
||
"banner_prediction_action_edit": "Actualizar cantidad",
|
||
"banner_expired_title": "Producto caducado",
|
||
"banner_expired_today": "Caducado hoy",
|
||
"banner_expired_days": "Caducado hace {days} días",
|
||
"banner_expired_action_use": "Usar de todas formas",
|
||
"banner_expired_action_finished": "¡Ya lo terminé!",
|
||
"banner_expired_action_throw": "Lo tiré",
|
||
"banner_expired_action_edit": "Corregir fecha",
|
||
"banner_anomaly_action_edit": "Corregir inventario",
|
||
"banner_anomaly_action_dismiss": "La cantidad es correcta",
|
||
"banner_no_expiry_title": "Caducidad faltante: {name}",
|
||
"banner_no_expiry_detail": "Este producto no tiene fecha de caducidad. ¿Quieres añadir una o confirmar que no caduca?",
|
||
"banner_no_expiry_action_set": "Establecer fecha de caducidad",
|
||
"banner_no_expiry_action_dismiss": "No caduca ✓",
|
||
"banner_no_expiry_toast_dismissed": "Marcado como «sin fecha de caducidad»",
|
||
"banner_expiring_title": "Caduca pronto",
|
||
"banner_expiring_today": "¡Caduca hoy!",
|
||
"banner_expiring_tomorrow": "Caduca mañana",
|
||
"banner_expiring_days": "Caduca en {days} días",
|
||
"banner_expiring_action_use": "Usar ahora",
|
||
"banner_finished_title": "¿terminado?",
|
||
"banner_finished_detail": "Registré que {name} llegó a cero de stock. ¿Realmente se acabó o todavía tienes algo?",
|
||
"banner_finished_action_yes": "Sí, se acabó",
|
||
"banner_finished_action_no": "No, todavía tengo",
|
||
"banner_review_unusual_pkg_title": "Tamaño de paquete inusual",
|
||
"banner_review_unusual_pkg_detail": "Configuraste un paquete de {qty} {unit} — el tamaño parece muy grande. Comprueba si es correcto o edita.",
|
||
"banner_review_low_qty_title": "Cantidad muy baja",
|
||
"banner_review_low_qty_detail": "Solo tienes {qty} en stock — parece muy poco, puede ser un error de escritura. Confirma si es correcto.",
|
||
"banner_review_high_qty_title": "Cantidad inusualmente alta",
|
||
"banner_review_high_qty_detail": "Tienes {qty} en stock — la cifra parece muy alta. Confirma si es correcto o edita.",
|
||
"banner_prediction_rate_day": "Media ~{n} {unit}/día",
|
||
"banner_prediction_rate_week": "Media ~{n} {unit}/semana",
|
||
"banner_prediction_days_ago": "Hace {n} días reabasteciste",
|
||
"banner_prediction_more": "estimación anterior: {expected} {unit}{time}; cantidad actual: {actual} {unit}.",
|
||
"banner_prediction_less": "estimación: {expected} {unit}{time}; cantidad actual: {actual} {unit}. Si tu ritmo de uso cambió, la previsión se actualiza automáticamente.",
|
||
"banner_finished_zero": "El inventario muestra cero, pero los movimientos registrados sugieren que no debería estar vacío.",
|
||
"banner_finished_expected": "Según los registros deberías tener todavía {qty} {unit}.",
|
||
"banner_finished_check": "¿Puedes comprobarlo?",
|
||
"banner_anomaly_phantom_title": "tienes más stock del esperado",
|
||
"banner_anomaly_phantom_detail": "El inventario indica {inv_qty} {unit}, pero según los registros solo deberías tener {expected_qty} {unit}. ¿Añadiste stock sin registrarlo?",
|
||
"banner_anomaly_untracked_title": "stock no registrado como entrada",
|
||
"banner_anomaly_untracked_detail": "Tienes <strong>{inv_qty} {unit}</strong> en inventario, pero las salidas registradas superan las entradas — el stock inicial probablemente nunca se añadió como transacción «entrada». Puedes corregir la cantidad o registrar las entradas faltantes.",
|
||
"banner_anomaly_ghost_title": "tienes menos stock del esperado",
|
||
"banner_anomaly_ghost_detail": "Según las operaciones registradas deberías tener {expected_qty} {unit} de {name}, pero el inventario solo muestra {inv_qty} {unit}. ¿Tomaste stock sin registrarlo?",
|
||
"consumed": "Consumido: {n} ({pct}%)",
|
||
"wasted": "Desperdiciado: {n} ({pct}%)",
|
||
"more_opened": "y {n} más abiertos...",
|
||
"banner_expired_detail": "{when} · aún tienes <strong>{qty}</strong>.",
|
||
"banner_opened_detail": "{when} en {location} · aún tienes <strong>{qty}</strong>.",
|
||
"banner_explain_title": "Pedir explicación a Gemini",
|
||
"banner_explain_btn": "Explicar",
|
||
"banner_analyzing": "🤖 Analizando…"
|
||
},
|
||
"inventory": {
|
||
"title": "Despensa",
|
||
"filter_all": "Todo",
|
||
"search_placeholder": "🔍 Buscar producto...",
|
||
"recent_title": "🕐 Usados recientemente",
|
||
"popular_title": "⭐ Más usados",
|
||
"empty": "No hay productos aquí.\n¡Escanea un producto para añadirlo!",
|
||
"no_items_found": "No se encontraron artículos",
|
||
"qty_remainder_suffix": "restante",
|
||
"vacuum_badge": "🫙 Al vacío",
|
||
"opened_badge": "📭 Abierto",
|
||
"label_expiry": "📅 Caducidad",
|
||
"label_storage": "🫙 Almacenamiento",
|
||
"label_status": "📭 Estado",
|
||
"opened_since": "Abierto desde el {date}",
|
||
"label_position": "📍 Ubicación",
|
||
"label_quantity": "📦 Cantidad",
|
||
"label_added": "📅 Añadido",
|
||
"empty_text": "No hay productos aquí.<br>¡Escanea un producto para añadirlo!",
|
||
"empty_db": "No hay productos en la base de datos.<br>¡Escanea un producto para empezar!",
|
||
"qty_trace": "< 1"
|
||
},
|
||
"scan": {
|
||
"title": "Escáner",
|
||
"mode_shopping": "🛒 Modo compras",
|
||
"mode_shopping_end": "✅ Finalizar compras",
|
||
"spesa_btn": "🛒 Compras",
|
||
"zoom": "Zoom",
|
||
"tab_barcode": "Código de barras",
|
||
"tab_name": "Nombre",
|
||
"tab_ai": "IA",
|
||
"recents_label": "Recientes",
|
||
"torch_hint": "Linterna",
|
||
"torch_on": "Linterna encendida",
|
||
"torch_off": "Linterna apagada",
|
||
"torch_unavailable": "Linterna no disponible en este dispositivo",
|
||
"flip_hint": "Cambiar cámara",
|
||
"flip_front": "Cámara frontal",
|
||
"flip_back": "Cámara trasera",
|
||
"num_ocr_btn": "🔢 Leer números con IA",
|
||
"num_ocr_searching": "Buscando código de barras con IA...",
|
||
"num_ocr_found": "Código encontrado: {code}",
|
||
"num_ocr_not_found": "No se encontró código de barras en la imagen",
|
||
"barcode_placeholder": "Introduce el código de barras...",
|
||
"quick_name_divider": "o escribe el nombre",
|
||
"quick_name_placeholder": "Ej.: Manzanas, Calabacín, Pan...",
|
||
"manual_entry": "✏️ Entrada manual",
|
||
"ai_identify": "🤖 Identificar con IA",
|
||
"hint": "Escanea el código de barras, escribe el nombre del producto o usa la IA para identificarlo",
|
||
"debug_toggle": "🐛 Registro de depuración",
|
||
"barcode_acquired": "🔖 Código de barras escaneado: {code}",
|
||
"scan_barcode": "🔖 Escanear código de barras",
|
||
"create_named": "Crear {name}",
|
||
"new_without_barcode": "Nuevo producto sin código de barras",
|
||
"status_ready": "Apunta la cámara al código de barras",
|
||
"status_scanning": "Escaneando...",
|
||
"status_partial": "Detectado: {code} — verificando...",
|
||
"status_invalid": "Inválido: {code} — reintentando",
|
||
"status_confirmed": "Confirmado!",
|
||
"status_parallel": "Escaneo combinado activo...",
|
||
"ai_fallback_searching": "Identificación de IA en curso...",
|
||
"ai_fallback_found": "Producto identificado por IA",
|
||
"ai_fallback_not_found": "IA: producto no reconocido"
|
||
},
|
||
"action": {
|
||
"title": "¿Qué quieres hacer?",
|
||
"add_btn": "📥 AÑADIR",
|
||
"add_sub": "a la despensa/nevera",
|
||
"use_btn": "📤 USAR / CONSUMIR",
|
||
"use_sub": "de la despensa/nevera",
|
||
"have_title": "📦 ¡Ya en stock!",
|
||
"add_more_sub": "añadir más",
|
||
"use_qty_sub": "cuánto usaste",
|
||
"throw_btn": "🗑️ DESECHAR",
|
||
"throw_sub": "tirar",
|
||
"edit_sub": "caducidad, ubicación…",
|
||
"create_recipe_btn": "Receta"
|
||
},
|
||
"add": {
|
||
"title": "Añadir a la despensa",
|
||
"location_label": "📍 ¿Dónde lo guardas?",
|
||
"quantity_label": "📦 Cantidad",
|
||
"conf_size_label": "📦 Cada paquete contiene:",
|
||
"conf_size_placeholder": "ej. 300",
|
||
"vacuum_label": "🫙 Al vacío",
|
||
"vacuum_hint": "La fecha de caducidad se ampliará automáticamente",
|
||
"submit": "✅ Añadir",
|
||
"purchase_type_label": "🛒 Este producto es...",
|
||
"new_btn": "🆕 Recién comprado",
|
||
"existing_btn": "📦 Ya lo tenía",
|
||
"remaining_label": "📦 Cantidad restante",
|
||
"remaining_hint": "¿Aproximadamente cuánto queda?",
|
||
"remaining_full": "🟢 Lleno",
|
||
"remaining_half": "🟠 Por la mitad",
|
||
"estimated_expiry": "Caducidad estimada:",
|
||
"suffix_freezer": "(congelador)",
|
||
"suffix_vacuum": "(al vacío)",
|
||
"hint_modify": "📝 Puedes cambiar la fecha o escanearla con la cámara",
|
||
"scan_expiry_title": "📷 Escanear fecha de caducidad",
|
||
"product_added": "✅ ¡{name} añadido!{qty}",
|
||
"suffix_freezer_vacuum": "(congelador + al vacío)",
|
||
"history_badge_tip": "Media de {n} entradas anteriores",
|
||
"vacuum_question": "¿Al vacío?",
|
||
"vacuum_saved": "🔒 ¡Al vacío!"
|
||
},
|
||
"use": {
|
||
"title": "Usar / Consumir",
|
||
"location_label": "📍 ¿De dónde?",
|
||
"quantity_label": "¿Cuánto usaste?",
|
||
"change": "cambiar",
|
||
"partial_hint": "O especifica la cantidad usada:",
|
||
"partial_piece_hint": "¿Usaste solo una parte?",
|
||
"piece": "unidad",
|
||
"one_whole": "1 entero",
|
||
"use_all": "🗑️ Todo usado / Terminado",
|
||
"submit": "📤 Usar esta cantidad",
|
||
"available": "📦 Disponible:",
|
||
"opened_badge": "ABIERTO",
|
||
"not_in_inventory": "⚠️ Producto no en inventario.",
|
||
"expiry_warning": "⚠️ ¡Usa primero el{loc} que caduca el {date} — {when}!",
|
||
"expiry_warning_opened": "⚠️ El{loc} lleva abierto {when} — ¡úsalo primero!",
|
||
"throw_title": "🗑️ Desechar producto",
|
||
"throw_all": "🗑️ Desechar TODO ({qty})",
|
||
"throw_qty_label": "¿Cuánto desechar?",
|
||
"throw_qty_hint": "o introduce una cantidad:",
|
||
"throw_partial_btn": "🗑️ Desechar esta cantidad",
|
||
"when_expired": "caducado hace {n} días",
|
||
"when_today": "caduca <strong>hoy</strong>",
|
||
"when_tomorrow": "caduca <strong>mañana</strong>",
|
||
"when_days": "caduca en <strong>{n} días</strong>",
|
||
"toast_used": "📤 {qty} de {name} usado",
|
||
"toast_bring": "🛒 Producto terminado → añadido a Bring!",
|
||
"toast_opened_finished": "🔓 ¡Paquete abierto de {name} terminado!",
|
||
"disambiguation_hint": "¿Qué quieres decir con «todo terminado»?",
|
||
"disambiguation_all": "🗑️ Terminar TODO ({qty})",
|
||
"error_exceeds_stock": "⚠️ ¡No puedes usar más de lo que tienes disponible!",
|
||
"use_all_confirm_title": "✅ Terminar todo",
|
||
"use_all_confirm_msg": "Confirma que has terminado el producto:",
|
||
"use_all_confirm_btn": "✅ Sí, terminado",
|
||
"throw_all_confirm_title": "🗑️ Desechar todo",
|
||
"throw_all_confirm_msg": "¿Realmente quieres tirar todo el producto?",
|
||
"throw_all_confirm_btn": "🗑️ Sí, desechar"
|
||
},
|
||
"product": {
|
||
"title_new": "Nuevo producto",
|
||
"title_edit": "Editar producto",
|
||
"ai_fill": "📷 Sacar foto e identificar con IA",
|
||
"ai_fill_hint": "La IA rellenará automáticamente los campos del producto",
|
||
"name_label": "🏷️ Nombre del producto *",
|
||
"name_placeholder": "Ej.: Leche entera, Pasta penne...",
|
||
"brand_label": "🏢 Marca",
|
||
"brand_placeholder": "Ej.: Barilla, Danone, Heinz...",
|
||
"category_label": "📂 Categoría",
|
||
"unit_label": "📏 Unidad de medida",
|
||
"default_qty_label": "🔢 Cantidad por defecto",
|
||
"conf_size_label": "📦 Cada paquete contiene:",
|
||
"conf_size_placeholder": "ej. 300",
|
||
"notes_label": "📝 Notas",
|
||
"notes_placeholder": "Ej.: sin lactosa, ecológico, guardar en nevera tras abrir...",
|
||
"barcode_label": "🔖 Código de barras",
|
||
"barcode_placeholder": "Código de barras (si disponible)",
|
||
"barcode_hint": "⚠️ ¡Añade el código de barras para la próxima vez solo tendrás que escanear!",
|
||
"submit": "💾 Guardar producto",
|
||
"name_required": "Introduce el nombre del producto",
|
||
"conf_size_required": "Especifica el contenido del paquete",
|
||
"expiry_estimated": "Caducidad estimada:",
|
||
"scan_expiry": "Escanear fecha de caducidad",
|
||
"expiry_hint": "📝 Puedes editar la fecha o escanearla con la cámara",
|
||
"add_batch": "📦 + Lote con fecha diferente",
|
||
"package_info": "📦 Paquete: {info}",
|
||
"edit_catalog": "⚙️ Editar información del producto (nombre, marca, categoría…)",
|
||
"not_recognized": "⚠️ Producto no reconocido",
|
||
"edit_info": "✏️ Editar información",
|
||
"modify_details": "EDITAR\ncaducidad, ubicación…",
|
||
"already_in_pantry": "📋 Ya en la despensa",
|
||
"no_barcode": "Sin código de barras",
|
||
"unknown_product": "Producto no reconocido",
|
||
"edit_name_brand": "Editar nombre/marca",
|
||
"weight_label": "Peso",
|
||
"origin_label": "Origen",
|
||
"labels_label": "Etiquetas",
|
||
"select_variant": "Selecciona la variante exacta o usa los datos de IA:"
|
||
},
|
||
"products": {
|
||
"title": "📦 Todos los productos",
|
||
"search_placeholder": "🔍 Buscar producto...",
|
||
"empty": "No hay productos en la base de datos.\n¡Escanea un producto para empezar!",
|
||
"no_category": "No hay productos en esta categoría"
|
||
},
|
||
"recipes": {
|
||
"title": "🍳 Recetas",
|
||
"generate": "✨ Generar nueva receta",
|
||
"archive_empty": "No hay recetas guardadas. ¡Genera tu primera receta!",
|
||
"dialog_title": "🍳 Receta",
|
||
"dialog_desc": "Generaré una receta saludable usando ingredientes de la despensa, priorizando los productos que caducan.",
|
||
"meal_label": "🕐 ¿Qué comida?",
|
||
"persons_label": "👥 ¿Para cuántas personas?",
|
||
"meal_type_label": "🎯 Tipo de comida",
|
||
"opt_fast": "⚡ Comida rápida",
|
||
"opt_light": "🥗 Apetito ligero",
|
||
"opt_expiry": "⏰ Priorizar productos que caducan",
|
||
"opt_healthy": "💚 Extra saludable",
|
||
"opt_opened": "📦 Priorizar productos abiertos",
|
||
"opt_zero_waste": "♻️ Cero desperdicio",
|
||
"generate_btn": "✨ Generar receta",
|
||
"loading_msg": "Preparando tu receta...",
|
||
"start_cooking": "👨🍳 Modo cocina",
|
||
"regenerate": "🔄 Generar otra",
|
||
"regen_choice_title": "¿Qué quieres hacer con esta receta?",
|
||
"regen_replace": "🔄 Generar otra (descartar esta)",
|
||
"regen_save_new": "💾 Guardar en el archivo y generar una nueva",
|
||
"close_btn": "✅ Cerrar",
|
||
"ingredients_title": "🧾 Ingredientes",
|
||
"tools_title": "Equipo necesario",
|
||
"steps_title": "👨🍳 Pasos",
|
||
"no_steps": "No hay pasos disponibles",
|
||
"generate_error": "Error de generación",
|
||
"persons_short": "com.",
|
||
"use_ingredient_title": "Usar ingrediente",
|
||
"recipe_qty_label": "Receta",
|
||
"from_where_label": "¿De dónde?",
|
||
"amount_label": "Cuánto",
|
||
"use_amount_btn": "Usar esta cantidad",
|
||
"use_all_btn": "Usar TODO / Terminado",
|
||
"packs_label": "Paquetes",
|
||
"quantity_in_total": "Cantidad en {unit} (total: {total})",
|
||
"packs_of_have": "Paquetes de {size} (tienes {count} paquetes)",
|
||
"scale_wait_stable": "Espera 10s de peso estable para el relleno automático…",
|
||
"ingredient_scaled_toast": "📦 ¡Ingrediente deducido de la despensa!",
|
||
"finished_added_bring_toast": "🛒 Producto terminado → ¡añadido a Bring!",
|
||
"load_error": "Error de carga",
|
||
"favorite": "Añadir a favoritos",
|
||
"unfavorite": "Quitar de favoritos",
|
||
"adjust_persons": "Personas"
|
||
},
|
||
"shopping": {
|
||
"title": "🛒 Lista de la compra",
|
||
"bring_loading": "Conectando a Bring!...",
|
||
"bring_not_configured": "Bring! no está configurado. Añade tu email y contraseña en los <a href='#' onclick=\"showPage('settings');return false;\">ajustes</a>.",
|
||
"tab_to_buy": "🛍️ Por comprar",
|
||
"tab_forecast": "🧠 Previsión",
|
||
"total_label": "💰 Total estimado",
|
||
"section_to_buy": "🛍️ Por comprar",
|
||
"suggestions_title": "💡 Sugerencias IA",
|
||
"suggestions_add": "✅ Añadir selección a Bring!",
|
||
"search_prices": "🔍 Buscar todos los precios",
|
||
"suggest_btn": "Sugerir qué comprar",
|
||
"smart_title": "🧠 Predicciones inteligentes",
|
||
"smart_empty": "No hay predicciones disponibles.<br>Añade productos a tu despensa para recibir predicciones inteligentes.",
|
||
"smart_filter_all": "Todo",
|
||
"smart_filter_critical": "🔴 Urgente",
|
||
"smart_filter_high": "🟠 Pronto",
|
||
"smart_filter_medium": "🟡 Planificar",
|
||
"smart_filter_low": "🟢 Previsión",
|
||
"smart_add": "🛒 Añadir selección a Bring!",
|
||
"empty": "¡Lista de la compra vacía!\nUsa el botón de abajo para generar sugerencias.",
|
||
"already_in_list": "🛒 \"{name}\" ya está en la lista de la compra",
|
||
"already_in_list_short": "ℹ️ Ya en la lista de la compra",
|
||
"add_prompt": "¿Quieres añadirlo a la lista de la compra?",
|
||
"smart_already": "📊 Las predicciones de compra ya predicen {name}",
|
||
"all_searched": "Todos los productos ya han sido buscados. Usa 🔄 para buscar individualmente.",
|
||
"search_complete": "Búsqueda completada: {count} productos",
|
||
"removed_sufficient": "🧹 {removed} producto(s) con stock suficiente eliminado(s) de la lista",
|
||
"suggest_buy": "🛒 Comprar: {qty} {unit}",
|
||
"suggest_buy_approx": "🛒 Al menos: {qty} {unit}",
|
||
"suggest_buy_tip": "Cantidad sugerida basada en tus últimos 14 días de consumo",
|
||
"suggest_buy_approx_tip": "Estimación mínima basada en el consumo (compra el tamaño de paquete más cercano)",
|
||
"bring_badge": "🛒 Ya en Bring!",
|
||
"add_urgent_toast": "🔴 {n} producto(s) urgente(s) añadido(s) automáticamente a Bring!",
|
||
"migration_done": "✅ {migrated} actualizado(s), {skipped} ya estaban ok",
|
||
"added_to_bring": "🛒 {n} productos añadidos a Bring!",
|
||
"added_to_bring_skip": "{n} ya presentes",
|
||
"all_on_bring": "¡Todos los productos ya estaban en Bring!",
|
||
"freq_high": "📈 Frecuente",
|
||
"freq_regular": "📊 Regular",
|
||
"freq_occasional": "📉 Ocasional",
|
||
"out_of_stock": "Sin stock",
|
||
"scan_toast": "📷 Escanear: {name}",
|
||
"empty_category": "No hay productos en esta categoría",
|
||
"session_empty": "🛒 Sin productos aún",
|
||
"urgency_critical": "Urgente",
|
||
"urgency_high": "Pronto",
|
||
"urgency_medium": "Planificar",
|
||
"urgency_low": "Previsión",
|
||
"urgency_medium_short": "Medio",
|
||
"urgency_low_short": "Ok",
|
||
"tag_urgent": "🔴 Urgente",
|
||
"tag_priority": "⭐ Prioridad",
|
||
"tag_check": "✅ Comprobar",
|
||
"smart_already_predicted": "📊 Las predicciones inteligentes ya predicen <strong>{name}</strong>{urgency}.",
|
||
"item_removed": "✅ ¡{name} eliminado de la lista!",
|
||
"urgency_spec_critical": "⚡ Urgente",
|
||
"urgency_spec_high": "🟠 Pronto",
|
||
"bring_add_n": "Añadir {n} a Bring!",
|
||
"bring_add_selected": "Añadir selección a Bring!",
|
||
"bring_adding": "Añadiendo...",
|
||
"bring_added_one": "1 producto añadido a Bring!",
|
||
"bring_added_many": "{n} productos añadidos a Bring!",
|
||
"bring_skipped": "({n} ya en la lista)",
|
||
"force_sync": "Forzar sincronización de Bring!",
|
||
"scan_target_label": "Estás buscando",
|
||
"scan_target_found": "¡Encontrado! Eliminar de la lista",
|
||
"bring_add_one": "Añadir 1 producto a Bring!",
|
||
"bring_add_many": "Añadir {n} productos a Bring!",
|
||
"syncing": "Sincronizando…",
|
||
"sync_done": "Sincronización completada",
|
||
"price_searching": "Buscando...",
|
||
"search_action": "Buscar",
|
||
"open_action": "Abrir",
|
||
"not_found": "No encontrado",
|
||
"search_price": "Buscar precio",
|
||
"tap_to_scan": "Toca para escanear",
|
||
"tag_title": "Etiqueta",
|
||
"remove_title": "Eliminar",
|
||
"found_count": "{found}/{total} productos encontrados",
|
||
"savings_offers": "· 🏷️ Ahorras {amount}€ con ofertas",
|
||
"searching_progress": "Buscando {current}/{total}...",
|
||
"remove_error": "Error al eliminar",
|
||
"btn_fetch_prices": "Buscar precios",
|
||
"price_total_label": "💰 Total estimado:",
|
||
"price_loading": "Buscando precios…",
|
||
"price_not_found": "precio n/d",
|
||
"suggest_loading": "Analizando...",
|
||
"suggest_error": "Error al generar sugerencias",
|
||
"priority_high": "Alta",
|
||
"priority_medium": "Media",
|
||
"priority_low": "Baja",
|
||
"smart_last_update": "Actualizado {time}",
|
||
"names_already_updated": "Todos los nombres ya están actualizados"
|
||
},
|
||
"ai": {
|
||
"title": "🤖 Identificación IA",
|
||
"capture": "📸 Sacar foto",
|
||
"retake": "🔄 Repetir",
|
||
"hint": "Saca una foto del producto y la IA intentará identificarlo",
|
||
"identifying": "🤖 Identificando producto...",
|
||
"no_api_key": "⚠️ Clave API de Gemini no configurada.\n<small>Añade GEMINI_API_KEY al archivo .env en el servidor.</small>",
|
||
"fields_filled": "✅ Campos rellenados por IA",
|
||
"use_data": "✅ Usar datos de IA",
|
||
"use_data_no_barcode": "✅ Usar datos de IA (sin código de barras)"
|
||
},
|
||
"log": {
|
||
"title": "📒 Registro de operaciones",
|
||
"type_added": "Añadido",
|
||
"type_waste": "Desechado",
|
||
"type_used": "Usado",
|
||
"type_bring": "Añadido a Bring!",
|
||
"undone_badge": "Deshecho",
|
||
"undo_title": "Deshacer esta operación",
|
||
"load_error": "Error al cargar el registro",
|
||
"empty": "No hay operaciones registradas.",
|
||
"undo_action_remove": "eliminación de",
|
||
"undo_action_restore": "reabastecimiento de",
|
||
"undo_confirm": "¿Deshacer esta operación?\n→ {action} {name}",
|
||
"undo_success": "↩ Operación deshecha para {name}",
|
||
"already_undone": "Operación ya deshecha",
|
||
"too_old": "No se pueden deshacer operaciones de más de 24 horas",
|
||
"undo_error": "Error al deshacer",
|
||
"recipe_prefix": "Receta"
|
||
},
|
||
"chat": {
|
||
"title": "Chef Gemini",
|
||
"welcome": "¡Hola! Soy tu asistente de cocina",
|
||
"welcome_desc": "¡Pídeme que te prepare un zumo, un snack, un plato rápido… Conozco tu despensa, tus electrodomésticos y tus preferencias!",
|
||
"suggestion_snack": "🍿 Snack rápido",
|
||
"suggestion_juice": "🥤 Zumo/Batido",
|
||
"suggestion_light": "🥗 Algo ligero",
|
||
"suggestion_expiry": "⏰ Usar productos que caducan",
|
||
"clear": "Nueva conversación",
|
||
"placeholder": "Pregunta algo...",
|
||
"cleared": "Chat borrado",
|
||
"suggestion_snack_text": "¿Qué puedo preparar como snack rápido?",
|
||
"suggestion_juice_text": "Hazme un zumo o batido con lo que tengo",
|
||
"suggestion_light_text": "Tengo hambre pero quiero algo ligero",
|
||
"suggestion_expiry_text": "¿Qué está a punto de caducar y cómo puedo usarlo?",
|
||
"transfer_to_recipes": "Transferir a recetas",
|
||
"transferring": "Transfiriendo...",
|
||
"transferred": "¡Añadido a recetas!",
|
||
"open_recipe": "Abrir receta",
|
||
"quick_recipe_prompt": "¡Sugiere una receta rápida PARA UNA PERSONA usando los productos que caducan primero! Ignora el congelador, céntrate en la nevera y la despensa."
|
||
},
|
||
"cooking": {
|
||
"close": "Cerrar",
|
||
"tts_btn": "Leer en voz alta",
|
||
"restart": "↺ Reiniciar",
|
||
"replay": "🔊 Repetir",
|
||
"timer": "⏱️ {time} · Temporizador",
|
||
"prev": "◀ Anterior",
|
||
"next": "Siguiente ▶",
|
||
"ingredient_used": "✔️ Deducido",
|
||
"ingredient_use_btn": "📦 Usar",
|
||
"ingredient_deduct_title": "Deducir de la despensa",
|
||
"timer_expired_tts": "¡Temporizador {label} finalizado!",
|
||
"timer_warning_tts": "¡Atención! {label}: ¡10 segundos restantes!",
|
||
"recipe_done_tts": "¡Receta completada! ¡Buen provecho!",
|
||
"expires_chip": "cad. {date}",
|
||
"finish": "✅ Finalizar",
|
||
"step_fallback": "Paso {n}",
|
||
"zerowaste_label": "♻️ Desperdicio",
|
||
"zerowaste_tip_title": "Consejo sin desperdicios"
|
||
},
|
||
"settings": {
|
||
"title": "⚙️ Ajustes",
|
||
"tab_api": "Claves API",
|
||
"tab_bring": "Bring!",
|
||
"tab_recipe": "Recetas",
|
||
"tab_mealplan": "Plan semanal",
|
||
"tab_appliances": "Electrodomésticos",
|
||
"tab_spesa": "Compra online",
|
||
"tab_camera": "Cámara",
|
||
"tab_security": "Seguridad",
|
||
"tab_tts": "Voz (TTS)",
|
||
"tab_language": "Idioma",
|
||
"tab_scale": "Báscula inteligente",
|
||
"gemini": {
|
||
"title": "🤖 Google Gemini IA",
|
||
"hint": "Clave API para identificación de productos, fechas de caducidad y recetas.",
|
||
"key_label": "Clave API Gemini"
|
||
},
|
||
"bring": {
|
||
"title": "🛒 Lista de la compra Bring!",
|
||
"hint": "Credenciales para la integración con la lista de la compra Bring!",
|
||
"email_label": "📧 Email Bring!",
|
||
"password_label": "🔒 Contraseña Bring!"
|
||
},
|
||
"price": {
|
||
"title": "💰 Estimación de precios (IA)",
|
||
"hint": "Mostrar el coste estimado por producto en la lista de la compra usando IA.",
|
||
"enabled_label": "Activar estimación de precios",
|
||
"country_label": "🌍 País de referencia",
|
||
"currency_label": "💱 Moneda",
|
||
"update_label": "🔄 Actualizar precios cada",
|
||
"update_suffix": "meses"
|
||
},
|
||
"recipe": {
|
||
"title": "🍳 Preferencias de recetas",
|
||
"hint": "Configura las opciones predeterminadas para la generación de recetas.",
|
||
"persons_label": "👥 Raciones por defecto",
|
||
"options_label": "🎯 Opciones de receta por defecto",
|
||
"fast": "⚡ Comida rápida",
|
||
"light": "🥗 Comida ligera",
|
||
"expiry": "⏰ Prioridad caducidad",
|
||
"healthy": "💚 Extra saludable",
|
||
"opened": "📦 Prioridad productos abiertos",
|
||
"zerowaste": "♻️ Cero desperdicio",
|
||
"dietary_label": "🚫 Intolerancias / Restricciones",
|
||
"dietary_placeholder": "Ej.: sin gluten, sin lactosa, vegetariano..."
|
||
},
|
||
"mealplan": {
|
||
"title": "📅 Plan de comidas semanal",
|
||
"hint": "Establece el tipo de comida para cada día. Se usará como guía en la generación de recetas.",
|
||
"enabled": "✅ Activar plan semanal",
|
||
"legend": "🌤️ = Almuerzo · 🌙 = Cena · Toca un badge para cambiarlo.",
|
||
"types_title": "📋 Tipos disponibles",
|
||
"reset_btn": "↺ Restaurar valores por defecto"
|
||
},
|
||
"appliances": {
|
||
"title": "🔌 Electrodomésticos disponibles",
|
||
"hint": "Indica los electrodomésticos que tienes. Se tendrán en cuenta en la generación de recetas.",
|
||
"new_placeholder": "Ej.: Panificadora, Thermomix, Freidora de aire...",
|
||
"quick_title": "Añadir rápido:",
|
||
"oven": "🔥 Horno",
|
||
"microwave": "📡 Microondas",
|
||
"air_fryer": "🍟 Freidora de aire",
|
||
"bread_maker": "🍞 Panificadora",
|
||
"bimby": "🤖 Thermomix/Cookeo",
|
||
"mixer": "🌀 Robot de cocina",
|
||
"steamer": "♨️ Vaporera",
|
||
"pressure_cooker": "🫕 Olla a presión",
|
||
"toaster": "🍞 Tostadora",
|
||
"blender": "🍹 Batidora",
|
||
"empty": "No hay electrodomésticos añadidos"
|
||
},
|
||
"spesa": {
|
||
"title": "🛍️ Compra online",
|
||
"hint": "Configura el proveedor de compra online.",
|
||
"provider_label": "🏪 Proveedor",
|
||
"email_label": "📧 Email",
|
||
"password_label": "🔒 Contraseña",
|
||
"login_btn": "🔐 Iniciar sesión",
|
||
"ai_prompt_label": "🤖 Prompt IA de selección de producto",
|
||
"ai_prompt_placeholder": "Instrucciones para la IA al elegir entre varios productos...",
|
||
"ai_prompt_hint": "La IA usa este prompt para elegir el producto más apropiado de los resultados. Deja vacío para el comportamiento por defecto.",
|
||
"configure_first": "Configura primero la compra online en ajustes",
|
||
"missing_credentials": "Introduce email y contraseña",
|
||
"login_in_progress": "Iniciando sesión...",
|
||
"login_error_prefix": "Error:",
|
||
"login_network_error_prefix": "Error de red:",
|
||
"login_success_default": "¡Inicio de sesión exitoso!",
|
||
"result_name_label": "Nombre",
|
||
"result_card_label": "Tarjeta",
|
||
"result_pickup_label": "Punto de recogida",
|
||
"result_points_label": "Puntos de fidelidad",
|
||
"connected_relogin": "✅ Conectado — Iniciar sesión de nuevo",
|
||
"connected_as": "Conectado como {name}"
|
||
},
|
||
"camera": {
|
||
"title": "📷 Cámara",
|
||
"hint": "Elige qué cámara usar para el escaneo de códigos de barras e identificación IA.",
|
||
"device_label": "📸 Cámara por defecto",
|
||
"back": "📱 Trasera (por defecto)",
|
||
"front": "🤳 Frontal",
|
||
"devices_hint": "Si tienes varias cámaras, puedes seleccionar una específica de la lista de arriba tras conceder los permisos.",
|
||
"detect_btn": "🔄 Detectar cámaras",
|
||
"ai_fallback_label": "Identificación visual IA (repuesto 5s)",
|
||
"ai_fallback_hint": "Si no se lee ningún código de barras en 5 segundos, se envía automáticamente un fotograma a la IA para identificar el producto visualmente. Requiere Gemini configurado."
|
||
},
|
||
"security": {
|
||
"title": "🔒 Certificado HTTPS",
|
||
"hint": "Si el navegador muestra el error «Tu conexión no es privada» (ERR_CERT_AUTHORITY_INVALID), necesitas instalar el certificado CA en el dispositivo.",
|
||
"download_btn": "📥 Descargar certificado CA",
|
||
"token_title": "🔑 Token de ajustes",
|
||
"token_label": "Token de acceso",
|
||
"token_hint": "Si `SETTINGS_TOKEN` está configurado en el `.env` del servidor, introduce el token aquí antes de guardar los ajustes. Deja vacío si no está configurado.",
|
||
"token_placeholder": "(vacío = sin protección)",
|
||
"token_required_hint": "🔒 Este servidor requiere un token para guardar los ajustes.",
|
||
"cert_instructions": "<strong>Instrucciones para Chrome (Android):</strong><br>1. Descarga el certificado de arriba<br>2. Ve a <em>Ajustes → Seguridad y privacidad → Más ajustes de seguridad → Instalar desde almacenamiento</em><br>3. Selecciona el archivo <em>EverShelf_CA.crt</em> descargado<br>4. Elige «CA» y confirma<br>5. Reinicia Chrome<br><br><strong>Instrucciones para Chrome (PC):</strong><br>1. Descarga el certificado de arriba<br>2. Ve a <em>chrome://settings/certificates</em><br>3. Pestaña «Autoridades» → Importar → selecciona el archivo<br>4. Marca «Confiar en este certificado para identificar sitios web»<br>5. Reinicia Chrome"
|
||
},
|
||
"tts": {
|
||
"title": "🔊 Voz & TTS",
|
||
"hint": "Configura la síntesis de voz mediante cualquier API REST externa. Los pasos de la receta y los temporizadores expirados se enviarán al endpoint configurado.",
|
||
"enabled": "✅ Activar TTS",
|
||
"engine_label": "⚙️ Motor TTS",
|
||
"engine_browser": "🔇 Navegador (sin conexión, sin configuración requerida)",
|
||
"engine_server": "🌐 Servidor externo (Home Assistant, API REST...)",
|
||
"voice_label": "🗣️ Voz",
|
||
"rate_label": "⚡ Velocidad",
|
||
"pitch_label": "🎵 Tono",
|
||
"url_label": "🌐 URL del endpoint",
|
||
"method_label": "📡 Método HTTP",
|
||
"auth_label": "🔐 Autenticación",
|
||
"auth_bearer": "Bearer Token",
|
||
"auth_custom": "Cabecera personalizada",
|
||
"auth_none": "Ninguna",
|
||
"token_label": "🔑 Bearer Token",
|
||
"custom_header_name": "📋 Nombre de cabecera",
|
||
"custom_header_value": "📋 Valor de cabecera",
|
||
"content_type_label": "📄 Content-Type",
|
||
"payload_key_label": "🗝️ Campo de texto en el payload",
|
||
"payload_key_hint": "Nombre del campo JSON que contendrá el texto a leer (ej.: message, text).",
|
||
"extra_fields_label": "➕ Campos adicionales (JSON)",
|
||
"extra_fields_placeholder": "{\"entity_id\": \"media_player.salon\"}",
|
||
"extra_fields_hint": "Campos adicionales a incluir en el payload, en formato JSON. Deja vacío si no es necesario.",
|
||
"test_btn": "🔊 Enviar voz de prueba",
|
||
"voices_loading": "Cargando voces…",
|
||
"voice_not_supported": "Voz no compatible con este navegador",
|
||
"voices_none": "No hay voces disponibles en este dispositivo",
|
||
"voices_hint": "Las voces disponibles dependen del SO y el navegador. Pulsa ↺ si la lista no carga.",
|
||
"url_missing": "⚠️ URL del endpoint faltante.",
|
||
"test_sending": "⏳ Enviando…",
|
||
"test_ok": "✅ Respuesta {code} — comprueba que el altavoz haya hablado.",
|
||
"heard_question": "¿Has escuchado la voz?",
|
||
"heard_yes": "Sí, la escuché",
|
||
"heard_no": "No, no escuché nada",
|
||
"test_ok_kiosk": "TTS funcionando.",
|
||
"test_fail_steps": "Comprueba: 1) el volumen del multimedia no es 0; 2) Google Text-to-Speech está instalado y actualizado; 3) el paquete de voz español está descargado en la configuración TTS de Android."
|
||
},
|
||
"language": {
|
||
"title": "🌐 Idioma",
|
||
"hint": "Selecciona el idioma de la interfaz.",
|
||
"label": "🌐 Idioma",
|
||
"restart_notice": "La página se recargará para aplicar el nuevo idioma."
|
||
},
|
||
"screensaver": {
|
||
"label": "Activar protector de pantalla",
|
||
"card_title": "🌙 Protector de pantalla",
|
||
"card_hint": "Muestra un reloj con información útil después de 5 minutos de inactividad. Desactivado por defecto.",
|
||
"timeout_1": "1 minuto",
|
||
"timeout_2": "2 minutos",
|
||
"timeout_5": "5 minutos",
|
||
"timeout_10": "10 minutos",
|
||
"timeout_15": "15 minutos",
|
||
"timeout_30": "30 minutos",
|
||
"timeout_60": "1 hora",
|
||
"start_after": "⏱️ Iniciar tras"
|
||
},
|
||
"scale": {
|
||
"title": "⚖️ Báscula inteligente",
|
||
"hint": "Conecta una báscula Bluetooth mediante la pasarela Android para leer el peso automáticamente.",
|
||
"tab": "Báscula inteligente",
|
||
"enabled": "✅ Activar báscula inteligente",
|
||
"url_label": "🌐 URL de la pasarela WebSocket",
|
||
"url_placeholder": "ws://192.168.1.x:8765",
|
||
"url_hint": "URL mostrada por la app Android (misma red Wi-Fi). Ej.:",
|
||
"test_btn": "🔗 Probar conexión",
|
||
"download_btn": "📥 Descargar pasarela Android (APK)",
|
||
"download_hint": "App Android que conecta tu báscula BLE con EverShelf.",
|
||
"download_sub": "Fuente: evershelf-scale-gateway/ en la raíz del proyecto",
|
||
"live_weight": "peso en tiempo real",
|
||
"auto_reconnect": "🔁 Reconexión: automática",
|
||
"kiosk_title": "📡 Báscula BLE integrada en el kiosco",
|
||
"kiosk_hint": "La báscula está gestionada directamente por la pasarela BLE interna del kiosco. Para vincular un nuevo dispositivo, usa el asistente de configuración.",
|
||
"kiosk_reconfigure": "🔄 Reconfigurar báscula BLE",
|
||
"ble_protocols": "<p style=\"margin:0 0 6px;font-weight:600\">🔌 Protocolos BLE soportados:</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) — peso, grasa, IMC</li><li>Xiaomi Mi Body Composition Scale 2</li><li>Genérico — heurística automática para 100+ modelos</li></ul>"
|
||
},
|
||
"kiosk": {
|
||
"hint": "Convierte una tableta Android en un panel EverShelf permanente con pasarela BLE integrada.",
|
||
"download_btn": "📥 Descargar EverShelf Kiosk (APK)",
|
||
"download_sub": "Modo kiosco a pantalla completa + pasarela de báscula integrada. Fuente: evershelf-kiosk/",
|
||
"native_title": "Configuración del kiosco",
|
||
"native_hint": "URL del servidor, báscula BLE, protector de pantalla y asistente de configuración.",
|
||
"native_btn": "Abrir configuración del kiosco",
|
||
"native_tap_hint": "Toca el botón de engranaje en la parte superior derecha",
|
||
"native_update_hint": "Actualiza la app del kiosco para usar esta función",
|
||
"update_title": "Actualización del kiosco",
|
||
"check_updates_btn": "🔍 Buscar actualizaciones",
|
||
"needs_update": "⚠️ El kiosco instalado no admite esta función. Actualiza la app del kiosco para activarla."
|
||
},
|
||
"saved": "✅ ¡Configuración guardada!",
|
||
"saved_local": "✅ Configuración guardada localmente",
|
||
"saved_local_error": "⚠️ Guardado localmente, error del servidor: {error}",
|
||
"theme": {
|
||
"title": "🌙 Apariencia",
|
||
"hint": "Elige el tema de la interfaz.",
|
||
"label": "🌙 Tema",
|
||
"off": "☀️ Claro",
|
||
"on": "🌙 Oscuro",
|
||
"auto": "🔄 Automático (sistema)"
|
||
},
|
||
"zerowaste": {
|
||
"card_title": "♻️ Consejos sin desperdicios",
|
||
"card_hint": "Durante la cocción, muestra consejos sobre cómo reutilizar los restos generados en cada paso (peladuras, agua de cocción, etc.). Desactivado por defecto.",
|
||
"label": "Mostrar consejos durante la cocción"
|
||
},
|
||
"backup": {
|
||
"tab": "Copia de seguridad",
|
||
"local_title": "Copia local",
|
||
"local_hint": "Instantánea diaria de la base de datos. Configura cuántos días de copias de seguridad conservar.",
|
||
"enabled": "Activar copia de seguridad diaria automática",
|
||
"retention_days": "Retención (días)",
|
||
"retention_info": "Las copias se conservan durante",
|
||
"backup_now": "Hacer copia ahora",
|
||
"backing_up": "Haciendo copia…",
|
||
"backed_up": "Copia completada",
|
||
"backup_error": "Error en la copia",
|
||
"last_backup": "Última copia",
|
||
"no_backup_yet": "Aún no se ha creado ninguna copia",
|
||
"list_empty": "No hay copias disponibles",
|
||
"restore_btn": "Restaurar",
|
||
"restore_confirm": "Restaurar la copia",
|
||
"delete_btn": "Eliminar",
|
||
"delete_confirm": "Eliminar la copia",
|
||
"gdrive_title": "Google Drive",
|
||
"gdrive_hint": "Copias de seguridad automáticas en Google Drive via OAuth 2.0. No se requieren bibliotecas externas.",
|
||
"gdrive_enabled": "Activar copia en Google Drive",
|
||
"gdrive_folder_id": "ID de carpeta de Drive",
|
||
"gdrive_folder_id_hint": "Copia el ID desde la URL de la carpeta de Drive: …/folders/<strong>ID</strong>",
|
||
"gdrive_retention_days": "Retención en Drive (días, 0=mantener todo)",
|
||
"gdrive_test": "Probar conexión",
|
||
"gdrive_ok": "Conexión exitosa!",
|
||
"gdrive_error": "Conexión fallida",
|
||
"gdrive_push_now": "Subir a Drive ahora",
|
||
"gdrive_pushing": "Subiendo…",
|
||
"gdrive_pushed": "Subido a Drive",
|
||
"gdrive_wizard_hint": "Opcional: copia de seguridad diaria automática en Google Drive via OAuth 2.0.",
|
||
"gdrive_skip": "Omitir — configurar después en Ajustes",
|
||
"gdrive_client_id": "Client ID",
|
||
"gdrive_client_secret": "Client Secret",
|
||
"gdrive_redirect_uri_hint": "Agrega <strong>http://localhost</strong> como URI de redireccionamiento autorizado en Google Cloud Console. Funciona en cualquier servidor, incluso sin dominio público.",
|
||
"gdrive_code_title": "Pegar la URL o el código de autorización",
|
||
"gdrive_code_hint": "Tras autorizar, el navegador abrirá http://localhost y puede mostrar un error de conexión — es normal. Copia la URL de la barra de direcciones (ej. <code>http://localhost/?code=4%2F0A...</code>) y pégala aquí.",
|
||
"gdrive_code_submit": "Confirmar",
|
||
"gdrive_code_empty": "Pega primero la URL o el código de autorización",
|
||
"gdrive_redirect_uri_label": "URI de redirección (agregar en Google Cloud Console):",
|
||
"gdrive_oauth_authorize": "Autorizar con Google",
|
||
"gdrive_oauth_authorized": "Autorizado",
|
||
"gdrive_oauth_not_authorized": "Aún no autorizado",
|
||
"gdrive_oauth_window_opened": "Ventana abierta — autoriza y regresa aquí",
|
||
"gdrive_oauth_how_to": "Cómo configurar OAuth 2.0 (paso a paso)",
|
||
"gdrive_oauth_steps": "<li>Ve a <a href='https://console.cloud.google.com/' target='_blank' rel='noopener'>console.cloud.google.com</a> y selecciona tu proyecto</li><li>Habilita la <strong>API de Google Drive</strong>: <em>API y servicios → Habilitar API → Google Drive API</em></li><li>Ve a <em>API y servicios → Credenciales → Crear credenciales → ID de cliente OAuth</em></li><li>Tipo de aplicación: <strong>Aplicación web</strong>; agrega la URL mostrada abajo como <em>URI de redirección autorizado</em></li><li>Copia el <strong>Client ID</strong> y el <strong>Client Secret</strong> en los campos de arriba y guarda</li><li>Haz clic en <strong>Autorizar con Google</strong>: inicia sesión en tu cuenta de Google y concede acceso</li><li>La ventana se cierra automáticamente al finalizar y las copias de seguridad están listas</li>"
|
||
},
|
||
"shopping": {
|
||
"tab": "Lista de la compra",
|
||
"title": "Lista de la compra",
|
||
"hint": "Configura la lista de la compra integrada o conecta Bring!.",
|
||
"enable_label": "Activar lista de la compra",
|
||
"mode_label": "Proveedor",
|
||
"mode_internal": "Integrado (sin Bring!)",
|
||
"mode_bring": "Bring! (app externa)",
|
||
"bring_section_title": "Configuración de Bring!",
|
||
"ai_section_title": "Asistencia IA",
|
||
"smart_suggestions_label": "Sugerencias IA",
|
||
"forecast_label": "Previsión de productos por agotar",
|
||
"auto_add_label": "Añadir automáticamente cuando",
|
||
"auto_add_suffix": "restante en stock (0 = solo cuando se agota)"
|
||
},
|
||
"ha": {
|
||
"tab": "Home Assistant",
|
||
"title": "Home Assistant",
|
||
"hint": "Conecta EverShelf a Home Assistant para automatizaciones, notificaciones push y sensores REST.",
|
||
"enabled": "Activar integración con Home Assistant",
|
||
"connection_title": "Conexión",
|
||
"url_label": "URL de Home Assistant",
|
||
"url_placeholder": "http://192.168.1.50:8123",
|
||
"url_hint": "URL base de tu instancia de Home Assistant.",
|
||
"token_label": "Token de acceso de larga duración",
|
||
"token_hint": "Genera desde Perfil HA → Seguridad → Tokens de acceso de larga duración.",
|
||
"token_placeholder": "eyJhbGci...",
|
||
"token_saved": "Token guardado (oculto por seguridad)",
|
||
"test_btn": "Probar conexión",
|
||
"test_ok": "Conectado a {version}",
|
||
"test_fail": "Conexión fallida: {error}",
|
||
"test_bad_token": "HA accesible pero el token no es válido",
|
||
"testing": "Probando…",
|
||
"error_no_url": "Por favor, introduce primero la URL de Home Assistant.",
|
||
"tts_title": "TTS en altavoz inteligente",
|
||
"tts_hint": "Lee los pasos de la receta en un reproductor de medios de Home Assistant.",
|
||
"tts_entity_label": "Entity ID del reproductor multimedia",
|
||
"tts_entity_placeholder": "media_player.salon",
|
||
"tts_entity_hint": "ID de entidad del reproductor multimedia HA. Encuéntralo en HA: Herramientas para desarrolladores → Estados.",
|
||
"tts_platform_label": "Plataforma TTS",
|
||
"tts_platform_speak": "tts.speak (recomendado)",
|
||
"tts_platform_notify": "notify.* (servicio de notificaciones)",
|
||
"tts_apply_btn": "Aplicar preset HA a la pestaña TTS",
|
||
"tts_apply_hint": "Pre-rellena la pestaña TTS con la URL y el token de Home Assistant.",
|
||
"tts_preset_applied": "Preset HA aplicado a la pestaña TTS.",
|
||
"webhook_title": "Automatizaciones Webhook",
|
||
"webhook_hint": "Envía datos a Home Assistant cuando ocurren eventos en la despensa.",
|
||
"webhook_id_label": "ID de Webhook",
|
||
"webhook_id_placeholder": "evershelf_webhook_abc123",
|
||
"webhook_id_hint": "ID del webhook creado en HA. Copia desde: HA → Ajustes → Automatizaciones → Crear → Disparador Webhook.",
|
||
"webhook_events_label": "Notificar en estos eventos",
|
||
"event_expiry": "Productos próximos a caducar (diario)",
|
||
"event_shopping": "Artículo añadido a la lista de compras",
|
||
"event_stock": "Nivel de stock actualizado",
|
||
"expiry_days_label": "Antelación de caducidad (días)",
|
||
"expiry_days_hint": "Enviar alerta de caducidad N días antes de la fecha.",
|
||
"webhook_help": "En HA: Ajustes → Automatizaciones → Crear automatización → Disparador: Webhook → copia el ID generado.",
|
||
"notify_title": "Notificaciones push",
|
||
"notify_hint": "Envía notificaciones push a tu teléfono mediante un servicio notify de Home Assistant.",
|
||
"notify_service_label": "Servicio notify",
|
||
"notify_service_placeholder": "notify.mobile_app_mi_telefono",
|
||
"notify_service_hint": "Nombre del servicio notify de HA. Déjalo vacío para desactivar.",
|
||
"sensor_title": "Sensores REST",
|
||
"sensor_hint": "Añade a configuration.yaml para crear sensores de EverShelf en Home Assistant.",
|
||
"sensor_copy_btn": "Copiar YAML",
|
||
"sensor_copied": "¡YAML copiado al portapapeles!",
|
||
"save_btn": "Guardar ajustes HA",
|
||
"ha_hint": "Si usas Home Assistant, utiliza la pestaña Home Assistant para configurar TTS, webhooks y sensores."
|
||
}
|
||
},
|
||
"expiry": {
|
||
"today": "HOY",
|
||
"tomorrow": "Mañana",
|
||
"days": "{days} días",
|
||
"expired_days": "hace {days}d",
|
||
"expired_yesterday": "Ayer",
|
||
"expired_today": "Hoy",
|
||
"badge_today": "⚠️ ¡Caduca hoy!",
|
||
"badge_tomorrow": "⏰ Mañana",
|
||
"badge_tomorrow_long": "⏰ Caduca mañana",
|
||
"badge_days": "⏰ {n} días",
|
||
"badge_expired_ago": "⚠️ Caducado hace {n}d",
|
||
"badge_expired": "⛔ ¡Caducado!",
|
||
"badge_stable": "✅ Estable",
|
||
"badge_expiring_short": "⏰ Cad. en {n}d",
|
||
"badge_ok_still": "✅ Aún {n}d",
|
||
"badge_expires_red": "🔴 Cad. en {n}d",
|
||
"badge_expires_yellow": "🟡 Cad. en {n}d",
|
||
"badge_expired_bare": "⚠️ Caducado",
|
||
"badge_expires_warn": "⚠️ Cad. en {n}d",
|
||
"badge_days_left": "⏳ ~{n}d restantes",
|
||
"days_approx": "~{n} días",
|
||
"weeks_approx": "~{n} semanas",
|
||
"months_approx": "~{n} meses",
|
||
"years_approx": "~{n} años",
|
||
"expired_today_long": "Caducado hoy",
|
||
"expired_ago_long": "Caducado hace {n} días",
|
||
"expired_suffix": "— ¡Caducado!",
|
||
"expired_suffix_ok": "— Caducado (aún ok)",
|
||
"expired_suffix_warning": "— Caducado (comprobar primero)",
|
||
"opened_ago_long": "Abierto hace {n} días",
|
||
"opened_today_long": "Abierto hoy",
|
||
"opened_suffix": "— ¡Abierto demasiado tiempo!",
|
||
"opened_suffix_ok": "— Abierto (aún ok)",
|
||
"opened_suffix_warning": "— Abierto (comprobar primero)",
|
||
"days_compact": "{n}d",
|
||
"badge_check_soon": "Comprobar pronto"
|
||
},
|
||
"status": {
|
||
"ok": "OK",
|
||
"check": "Comprobar",
|
||
"discard": "Desechar",
|
||
"tip_freezer_ok": "En congelador: aún seguro (~{n}d de margen)",
|
||
"tip_freezer_check": "En el congelador mucho tiempo, puede haber perdido calidad. Consumir pronto",
|
||
"tip_freezer_danger": "En el congelador demasiado tiempo, riesgo de quemadura por congelación y degradación",
|
||
"tip_highRisk_check": "Caducado recientemente, comprueba el olor y el aspecto antes de consumir",
|
||
"tip_highRisk_danger": "Producto perecedero caducado: desechar por seguridad",
|
||
"tip_medRisk_check1": "Comprueba el aspecto y el olor antes de consumir",
|
||
"tip_medRisk_check2": "Caducado hace tiempo, comprueba cuidadosamente antes de usar",
|
||
"tip_medRisk_danger": "Demasiado tiempo desde la caducidad, mejor desechar",
|
||
"tip_lowRisk_ok": "Producto de larga duración, aún seguro para consumir",
|
||
"tip_lowRisk_check": "Caducado hace más de un mes, comprueba la integridad del envase",
|
||
"tip_lowRisk_danger": "Caducado hace demasiado tiempo, mejor no arriesgarse"
|
||
},
|
||
"toast": {
|
||
"product_saved": "¡Producto guardado!",
|
||
"product_created": "¡Producto creado!",
|
||
"product_updated": "✅ ¡Producto actualizado!",
|
||
"product_removed": "Producto eliminado",
|
||
"updated": "¡Actualizado!",
|
||
"quantity_confirmed": "✓ Cantidad confirmada",
|
||
"added_to_inventory": "✅ ¡{name} añadido!",
|
||
"removed_from_list": "✅ ¡{name} eliminado de la lista!",
|
||
"removed_from_list_short": "Eliminado de la lista",
|
||
"added_to_shopping": "🛒 ¡Añadido a la lista de la compra!",
|
||
"removed_from_shopping": "🛒 Eliminado de la lista de la compra",
|
||
"finished_to_bring": "🛒 Producto terminado → ¡añadido a Bring!",
|
||
"thrown_away": "🗑️ ¡{name} tirado!",
|
||
"thrown_away_partial": "🗑️ {qty} {unit} de {name} tirado(s)",
|
||
"finished_all": "📤 ¡{name} terminado!",
|
||
"product_finished_confirmed": "✅ Eliminado — añádelo de nuevo cuando reabastezcas",
|
||
"appliance_added": "Electrodoméstico añadido",
|
||
"item_added": "{name} añadido"
|
||
},
|
||
"antiwaste": {
|
||
"title": "🌱 Informe anti-desperdicio",
|
||
"grade_label": "Nota",
|
||
"you": "Tú",
|
||
"avg_label": "Media",
|
||
"better": "🎉 ¡Desperdicias un {diff}% menos que la media {country}!",
|
||
"worse": "⚠️ Desperdicias más que la media {country}. ¡Hay margen de mejora!",
|
||
"on_par": "→ Estás en la media {country}. ¡Puedes hacerlo mejor!",
|
||
"saved_money": "~{amount}/mes ahorrado",
|
||
"saved_meals": "~{n} comidas salvadas",
|
||
"saved_co2": "{n} kg CO₂ evitados",
|
||
"trend_title": "Tendencia (últimos 3 meses)",
|
||
"months_ago_2": "-60 días",
|
||
"months_ago_1": "-30 días",
|
||
"this_month": "Ahora",
|
||
"country_it": "Media italiana",
|
||
"country_de": "Media alemana",
|
||
"country_en": "Media estadounidense",
|
||
"source": "Fuentes: REDUCE, Eurostat, USDA 2021",
|
||
"live_on": "Datos en vivo",
|
||
"live_off": "Sin conexión",
|
||
"meals": "comidas",
|
||
"annual_info": "📅 Tú ~{you} kg/año · media ~{avg} kg/año",
|
||
"badge_rate": "tasa de pérdida",
|
||
"badge_saved_money": "ahorrado vs media",
|
||
"badge_wasted": "artículos perdidos",
|
||
"badge_better": "menos que la media"
|
||
},
|
||
"error": {
|
||
"generic": "Error",
|
||
"network": "Error de red",
|
||
"no_api_key": "Configura la clave API en los ajustes",
|
||
"loading": "Error al cargar el producto",
|
||
"not_found": "Producto no encontrado",
|
||
"not_found_manual": "Producto no encontrado. Introdúcelo manualmente.",
|
||
"search": "Error de búsqueda. Inténtalo de nuevo.",
|
||
"search_short": "Error de búsqueda",
|
||
"save": "Error al guardar",
|
||
"connection": "Error de conexión",
|
||
"camera": "No se puede acceder a la cámara",
|
||
"bring_add": "Error al añadir a Bring!",
|
||
"bring_connection": "Error de conexión con Bring!",
|
||
"identification": "Error de identificación",
|
||
"ai_quota": "Cuota de IA agotada. Inténtalo de nuevo en unos minutos.",
|
||
"barcode_empty": "Introduce un código de barras",
|
||
"barcode_format": "El código de barras solo puede contener números (4-14 dígitos)",
|
||
"min_chars": "Escribe al menos 2 caracteres",
|
||
"not_in_inventory": "Producto no en inventario",
|
||
"appliance_exists": "El electrodoméstico ya existe",
|
||
"already_exists": "Ya existe",
|
||
"network_retry": "Error de conexión. Inténtalo de nuevo.",
|
||
"select_items": "Selecciona al menos un producto",
|
||
"server_offline": "Conexión con el servidor perdida",
|
||
"server_restored": "Conexión con el servidor restaurada",
|
||
"server_retry": "Reintentar",
|
||
"unknown": "Error desconocido",
|
||
"prefix": "Error",
|
||
"no_inventory_entry": "No se encontró ninguna entrada de inventario",
|
||
"offline_title": "Sin conexión",
|
||
"offline_subtitle": "La app no puede conectar con el servidor. Verifica tu conexión Wi-Fi.",
|
||
"offline_checking": "Verificando conexión…",
|
||
"offline_restored": "¡Conexión restaurada!",
|
||
"offline_continue": "Continuar en modo sin conexión",
|
||
"offline_reading_cache": "Leyendo desde caché local",
|
||
"offline_ops_pending": "{n} operaciones pendientes",
|
||
"offline_synced": "{n} operaciones sincronizadas",
|
||
"offline_ai_disabled": "No disponible sin conexión",
|
||
"offline_cache_ready": "Offline — {n} productos en caché"
|
||
},
|
||
"confirm_placeholder_search": null,
|
||
"confirm": {
|
||
"remove_item": "¿Realmente quieres eliminar este producto del inventario?",
|
||
"kiosk_exit": "¿Salir del modo kiosco?",
|
||
"cancel": "Cancelar",
|
||
"proceed": "Confirmar",
|
||
"discard_one": "Tirar 1 unidad"
|
||
},
|
||
"location": {
|
||
"dispensa": "Despensa",
|
||
"frigo": "Nevera",
|
||
"freezer": "Congelador"
|
||
},
|
||
"edit": {
|
||
"title": "Editar {name}",
|
||
"unknown_hint": "Introduce el nombre del producto y la información",
|
||
"label_name": "🏷️ Nombre del producto",
|
||
"choose_location_title": "¿Qué ubicación?",
|
||
"choose_location_hint": "Elige la ubicación a editar:",
|
||
"confirm_large_qty": "Estás configurando la cantidad a {qty} {unit}. Esto parece inusualmente alto. ¿Confirmar?"
|
||
},
|
||
"screensaver": {
|
||
"recipe_btn": "Recetas",
|
||
"scan_btn": "Escanear producto"
|
||
},
|
||
"days": {
|
||
"mon": "Lunes",
|
||
"tue": "Martes",
|
||
"wed": "Miércoles",
|
||
"thu": "Jueves",
|
||
"fri": "Viernes",
|
||
"sat": "Sábado",
|
||
"sun": "Domingo",
|
||
"mon_short": "Lun",
|
||
"tue_short": "Mar",
|
||
"wed_short": "Mié",
|
||
"thu_short": "Jue",
|
||
"fri_short": "Vie",
|
||
"sat_short": "Sáb",
|
||
"sun_short": "Dom"
|
||
},
|
||
"meal_types": {
|
||
"lunch": "Almuerzo",
|
||
"dinner": "Cena",
|
||
"colazione": "Desayuno",
|
||
"merenda": "Merienda",
|
||
"dolce": "Postre",
|
||
"succo": "Zumo de fruta",
|
||
"pranzo": "Almuerzo",
|
||
"cena": "Cena"
|
||
},
|
||
"scale": {
|
||
"status_connected": "Báscula conectada",
|
||
"status_searching": "Pasarela conectada, esperando báscula…",
|
||
"status_disconnected": "Pasarela de báscula inaccesible",
|
||
"status_error": "Error de conexión con la pasarela",
|
||
"not_connected": "Pasarela de báscula no conectada",
|
||
"read_btn": "⚖️ Leer desde báscula",
|
||
"reading_title": "Lectura de báscula",
|
||
"place_on_scale": "Coloca el producto en la báscula…",
|
||
"waiting_stable": "El peso se capturará automáticamente cuando la lectura sea estable.",
|
||
"no_url": "Introduce la URL de la pasarela",
|
||
"testing": "⏳ Probando conexión…",
|
||
"connected_ok": "¡Conexión con la pasarela exitosa!",
|
||
"timeout": "Tiempo de espera agotado: sin respuesta de la pasarela",
|
||
"error_connect": "No se puede conectar a la pasarela",
|
||
"tab": "Báscula inteligente",
|
||
"low_weight": "Peso < 10 g · introduce manualmente\n(la lectura automática requiere al menos 10 g)",
|
||
"density_hint": "(densidad {density} g/ml)",
|
||
"ml_hint": "(se convertirá a ml)",
|
||
"weight_detected": "Peso detectado — espera 10s de estabilidad…",
|
||
"weight_too_low": "Peso demasiado bajo — esperando…",
|
||
"stable": "✓ Estable",
|
||
"auto_confirm": "✅ {val} {unit} — confirmación automática en 5s (toca para cancelar)",
|
||
"cancelled_replace": "Cancelado — vuelve a colocar el ingrediente en la báscula para continuar"
|
||
},
|
||
"prediction": {
|
||
"expected_qty": "Esperado: {expected} {unit}",
|
||
"actual_qty": "Actual: {actual} {unit}",
|
||
"check_suggestion": "Comprueba o pesa la cantidad restante"
|
||
},
|
||
"date": {
|
||
"today": "📅 Hoy",
|
||
"yesterday": "📅 Ayer"
|
||
},
|
||
"scanner": {
|
||
"title_barcode": "🔖 Escanear código de barras",
|
||
"barcode_hint": "Encuadra el código de barras del producto",
|
||
"barcode_manual_placeholder": "O introduce manualmente...",
|
||
"barcode_use_btn": "✅ Usar este código",
|
||
"ai_identifying": "🤖 Identificando producto...",
|
||
"ai_analyzing": "🤖 Análisis IA en curso...",
|
||
"product_label_hint": "Encuadra la etiqueta del producto",
|
||
"expiry_label_hint": "Encuadra la fecha de caducidad impresa en el producto",
|
||
"capture_btn": "📸 Capturar",
|
||
"capture_photo_btn": "📸 Sacar foto",
|
||
"retake_btn": "🔄 Repetir",
|
||
"camera_error_hint": "Asegúrate de usar HTTPS y haber concedido los permisos de cámara.<br>Puedes introducir el código de barras manualmente o usar la identificación IA.",
|
||
"no_barcode": "Sin código de barras",
|
||
"save_new_btn": "🆕 Ninguno de estos — guardar como nuevo"
|
||
},
|
||
"lowstock": {
|
||
"title": "⚠️ ¡Stock bajo!",
|
||
"message": "{name} se está agotando — solo quedan {qty}.",
|
||
"question": "¿Quieres añadirlo a la lista de la compra?",
|
||
"yes": "🛒 Sí, añadir a Bring!",
|
||
"no": "No, por ahora estoy bien"
|
||
},
|
||
"move": {
|
||
"title": "📦 ¿Mover el resto?",
|
||
"question": "¿Quieres mover {thing} de {name} a otra ubicación?",
|
||
"question_short": "¿Quieres mover {thing} a otra ubicación?",
|
||
"thing_opened": "el paquete abierto",
|
||
"thing_rest": "el resto",
|
||
"stay_btn": "No, quedarse en {location}",
|
||
"moved_toast": "📦 Paquete abierto movido a {location}",
|
||
"vacuum_restore": "🫙 Restaurar al vacío",
|
||
"vacuum_seal_rest": "🔒 Sellar el resto al vacío"
|
||
},
|
||
"nova": {
|
||
"1": "Sin procesar",
|
||
"2": "Ingrediente culinario",
|
||
"3": "Procesado",
|
||
"4": "Ultraprocesado"
|
||
},
|
||
"meal_plan_types": {
|
||
"pasta": "Pasta",
|
||
"riso": "Arroz",
|
||
"carne": "Carne",
|
||
"pesce": "Pescado",
|
||
"legumi": "Legumbres",
|
||
"uova": "Huevos",
|
||
"formaggio": "Queso",
|
||
"pizza": "Pizza",
|
||
"affettati": "Fiambres",
|
||
"verdure": "Verduras",
|
||
"zuppa": "Sopa",
|
||
"insalata": "Ensalada",
|
||
"pane": "Pan/Bocadillo",
|
||
"dolce": "Postre",
|
||
"libero": "Libre"
|
||
},
|
||
"meal_sub": {
|
||
"dolce_torta": "Tarta",
|
||
"dolce_crema": "Crema / Pudín",
|
||
"dolce_crumble": "Crumble / Tarta",
|
||
"dolce_biscotti": "Galletas / Pastelería",
|
||
"dolce_frutta": "Postre de fruta",
|
||
"succo_dolce": "Dulce / Afrutado",
|
||
"succo_energizzante": "Energizante",
|
||
"succo_detox": "Detox / Verde",
|
||
"succo_rinfrescante": "Refrescante",
|
||
"succo_vitaminico": "Vitamínico / Cítricos"
|
||
},
|
||
"meal_plan": {
|
||
"reset_success": "Plan semanal restablecido",
|
||
"not_available": "no disponible en la despensa",
|
||
"suggested_by": "sugerido por el plan semanal"
|
||
},
|
||
"nutrition": {
|
||
"title": "🥗 Análisis alimentario",
|
||
"score_excellent": "😄 Excelente",
|
||
"score_good": "🙂 Bien",
|
||
"score_improve": "😬 Mejorable",
|
||
"label_health": "🌿 Salud",
|
||
"label_variety": "🎨 Variedad",
|
||
"label_fresh": "❄️ Fresco",
|
||
"source": "Basado en {n} productos en tu despensa · EverShelf",
|
||
"products_count": "productos",
|
||
"today_title": "🥗 Tu despensa hoy",
|
||
"products_n": "{n} productos",
|
||
"macros_title": "Macronutrientes estimados",
|
||
"macros_proteins": "Proteínas",
|
||
"macros_carbs": "Carbohidratos",
|
||
"macros_fat": "Grasas",
|
||
"macros_fiber": "Fibra",
|
||
"macros_source": "Estimación basada en {n} productos en despensa"
|
||
},
|
||
"facts": {
|
||
"greeting_morning": "Buenos días",
|
||
"greeting_afternoon": "Buenas tardes",
|
||
"greeting_evening": "Buenas noches",
|
||
"pantry_waiting": "¡{greeting}! Tu despensa te espera.",
|
||
"expired_one": "Tienes 1 producto caducado en tu despensa. ¡Compruébalo!",
|
||
"expired_many": "Tienes {n} productos caducados en tu despensa. ¡Compruébalos!",
|
||
"expired_list": "Productos caducados: {names}",
|
||
"expired_list_more": "y {n} más",
|
||
"freezer_expired_ok": "{name} está caducado, pero al estar en el congelador puede estar bien. ¡Compruébalo!",
|
||
"freezer_expired_old": "{name} en el congelador lleva demasiado tiempo caducado. Mejor tirarlo.",
|
||
"fridge_expired_one": "¡Tienes 1 producto caducado en la nevera!",
|
||
"fridge_expired_many": "¡Tienes {n} productos caducados en la nevera!",
|
||
"expiring_today": "¡{name} caduca hoy! Úsalo enseguida.",
|
||
"expiring_tomorrow": "{name} caduca mañana. ¡Planifica!",
|
||
"expiring_days": "{name} caduca en {days} días.",
|
||
"expiring_many": "Tienes {n} productos que caducan pronto.",
|
||
"expiring_this_week": "¡{n} productos caducan esta semana. Planifica tus comidas en consecuencia!",
|
||
"expiring_item_loc": "{name} ({loc}) caduca en {days} {dayslabel}.",
|
||
"expiring_this_month": "{n} productos caducarán este mes.",
|
||
"shopping_add": "Añadir a la lista: {names} 🛒",
|
||
"shopping_more": "y {n} más",
|
||
"shopping_empty": "¡Lista de la compra vacía. Todo en stock! ✅",
|
||
"in_fridge": "En la nevera: {name}.",
|
||
"in_freezer": "En el congelador: {name}. ¡No lo olvides!",
|
||
"top_category": "La categoría principal es {icon} {cat} con {n} productos.",
|
||
"cat_meat": "Tienes {n} productos cárnicos. 🥩",
|
||
"cat_dairy": "Tienes {n} productos lácteos en casa. 🥛",
|
||
"cat_veggies": "Tienes {n} tipos de verduras. ¡Genial para la salud! 🥬",
|
||
"cat_fruit": "Tienes {n} tipos de fruta. 🍎",
|
||
"cat_drinks": "Tienes {n} bebidas disponibles. 🥤",
|
||
"cat_frozen": "Tienes {n} artículos congelados. ❄️",
|
||
"cat_pasta": "Tienes {n} tipos de pasta. 🍝 ¿Y si hacemos una carbonara?",
|
||
"cat_canned": "Tienes {n} conservas en la despensa. 🥫",
|
||
"cat_snacks": "Tienes {n} snacks. ¡Resiste la tentación! 🍪",
|
||
"cat_condiments": "Tienes {n} condimentos disponibles. 🧂",
|
||
"item_random": "¿Sabías que tienes {name} en {loc}?",
|
||
"item_qty": "{name}: tienes {qty}.",
|
||
"no_expiry_count": "{n} productos no tienen fecha de caducidad.",
|
||
"furthest_expiry": "El producto con la fecha de caducidad más lejana es {name}: {months} meses.",
|
||
"high_qty": "¡Tienes un buen stock de {name}: {qty}!",
|
||
"low_qty_item": "{name} se está agotando. ¿Añadirlo a tu lista de la compra?",
|
||
"low_qty_count": "{n} productos están casi agotados.",
|
||
"morning_bread": "¡Buenos días! Tienes pan para el desayuno. 🍞",
|
||
"morning_milk": "¿Hay leche en la nevera para un café con leche? ☕🥛",
|
||
"morning_fruit": "¡Buenos días! Algo de fruta fresca es un gran comienzo. 🍎",
|
||
"noon_pasta": "Es hora de comer… ¿Y si preparamos un buen plato de pasta? 🍝",
|
||
"noon_salad": "¿Una ensalada fresca para comer? ¡Tienes {n} verduras! 🥗",
|
||
"evening_meat": "Para cenar podrías usar la carne que tienes. 🥩",
|
||
"evening_fish": "¿Qué tal pescado para cenar? 🐟",
|
||
"evening_expiring": "Tienes {n} productos que caducan esta semana — ¡úsalos esta noche!",
|
||
"night_reminder": "¡Buenas noches! Recuerda usar mañana: {names}.",
|
||
"weekly_balance": "Balance semanal: +{in} añadidos, −{out} consumidos.",
|
||
"weekly_added": "Has añadido {n} productos esta semana.",
|
||
"weekly_consumed": "Has consumido {n} productos esta semana. ¡Bien hecho!",
|
||
"tip_freezer": "💡 Los productos congelados duran mucho más que la fecha de caducidad.",
|
||
"tip_bread": "💡 El pan congelado conserva su frescura durante semanas.",
|
||
"tip_fifo": "💡 Para evitar desperdicios, usa primero los productos más cercanos a la caducidad (FIFO).",
|
||
"tip_meat": "💡 La carne en el congelador puede durar hasta 6 meses con seguridad.",
|
||
"tip_no_refreeze": "💡 Nunca vuelvas a congelar un producto descongelado. ¡Cocínalo enseguida!",
|
||
"tip_fridge": "💡 Una nevera ordenada te ahorra tiempo y dinero.",
|
||
"tip_canned": "💡 Las conservas abiertas deben ir a la nevera y consumirse en pocos días.",
|
||
"top_brand": "La marca más común en tu despensa es {brand} con {n} productos.",
|
||
"combo_pasta": "Tienes pasta y condimentos: ¡listo para un primer plato! 🍝",
|
||
"combo_sandwich": "Pan y carne: ¡un sándwich rápido siempre es buena idea! 🥪",
|
||
"combo_balanced": "Verduras y carne: ¡tienes todo para una comida equilibrada! 🥗🥩",
|
||
"pantry_empty": "¡La despensa está vacía! Es hora de ir al supermercado. 🛒",
|
||
"pantry_empty_scan": "No hay productos registrados. ¡Escanea algo para empezar!",
|
||
"location_distribution": "Distribución: {parts}",
|
||
"day": "día",
|
||
"days": "días"
|
||
},
|
||
"kiosk_session": {
|
||
"first_item": "¡Primer artículo: {name}!",
|
||
"items_two_four": "{n} artículos — arrancando 🚀",
|
||
"items_five_nine": "{n} artículos — ¡buen ritmo! 💪",
|
||
"items_ten_twenty": "{n} artículos — casi un récord 🏆",
|
||
"items_twenty_plus": "{n} artículos — ¡compra épica! 🛒🔥",
|
||
"duplicates_one": "1 duplicado (mismo artículo dos veces)",
|
||
"duplicates_many": "{n} duplicados (cogido varias veces)",
|
||
"top_category": "Categoría principal: {cat} ({count}×)",
|
||
"items_fallback": "{n} artículo{plural} añadido{plural}"
|
||
},
|
||
"kiosk": {
|
||
"check_btn": "🔍 Buscar actualizaciones",
|
||
"checking": "⏳ Comprobando…",
|
||
"error_check": "Error durante la comprobación de actualizaciones",
|
||
"error_start_install": "Error al iniciar la instalación",
|
||
"version_installed": "Instalado: {v}",
|
||
"update_available": "⬆️ Nueva versión disponible: <strong>{latest}</strong> (instalada: {current})",
|
||
"up_to_date": "✅ Estás actualizado — versión <strong>{v}</strong>",
|
||
"too_old": "⚠️ El kiosco instalado es demasiado antiguo para la comprobación automática de actualizaciones.<br>Pulsa el botón de abajo para descargar e instalar la nueva versión directamente.",
|
||
"manual_install": "⚠️ Este kiosco no admite instalación automática.<br><strong>Procedimiento manual:</strong><br>1. Sal del kiosco (botón ✕ arriba a la izquierda)<br>2. Desinstala la app EverShelf Kiosk<br>3. Descarga e instala el nuevo APK desde GitHub:",
|
||
"starting_download": "⏳ Iniciando descarga…",
|
||
"install_btn": "⬇️ Instalar actualización",
|
||
"exit_title": "Salir del kiosco",
|
||
"refresh_title": "Actualizar página"
|
||
},
|
||
"update": {
|
||
"new_version": "Nueva versión",
|
||
"btn": "Actualizar"
|
||
},
|
||
"gemini": {
|
||
"chat_title": "Chat con Gemini",
|
||
"not_configured": "🤖 Gemini no configurado — establece GEMINI_API_KEY en los ajustes"
|
||
},
|
||
"appliances": {
|
||
"empty": "No hay electrodomésticos añadidos"
|
||
},
|
||
"about": {
|
||
"title": "Acerca de",
|
||
"version": "Versión",
|
||
"report_bug": "Reportar un error",
|
||
"report_bug_hint": "¿Algo no funciona? Envíanos un informe directamente desde la app.",
|
||
"report_bug_modal_title": "Reportar un error",
|
||
"report_type_bug": "Error",
|
||
"report_type_feature": "Función",
|
||
"report_type_question": "Pregunta",
|
||
"report_field_title": "Título",
|
||
"report_field_title_ph": "Breve descripción del problema",
|
||
"report_field_desc": "Descripción",
|
||
"report_field_desc_ph": "Describe el problema en detalle…",
|
||
"report_field_steps": "Pasos para reproducir (opcional)",
|
||
"report_field_steps_ph": "1. Ir a…\n2. Tocar…\n3. Ver el error…",
|
||
"report_auto_info": "Adjuntado automáticamente: versión {version}, idioma {lang}.",
|
||
"report_send_btn": "Enviar informe",
|
||
"report_bug_sending": "Enviando…",
|
||
"report_bug_sent": "¡Informe enviado — gracias!",
|
||
"report_bug_error": "No se pudo enviar el informe. Comprueba tu conexión.",
|
||
"changelog": "Registro de cambios",
|
||
"github": "Repositorio GitHub"
|
||
},
|
||
"export": {
|
||
"title": "Exportar inventario",
|
||
"hint": "Descarga el inventario actual en CSV o abre la versión imprimible (PDF).",
|
||
"btn_csv": "Descargar CSV",
|
||
"btn_pdf": "PDF / Imprimir",
|
||
"btn_title": "Exportar"
|
||
},
|
||
"startup": {
|
||
"connecting": "Conectando al servidor...",
|
||
"check_php_memory": "Memoria PHP",
|
||
"check_php_timeout": "Tiempo de espera PHP",
|
||
"check_php_upload": "Upload PHP",
|
||
"check_data_dir": "Carpeta de datos",
|
||
"check_rate_limits": "Dir. rate limits",
|
||
"check_backups": "Dir. copias de seguridad",
|
||
"check_write_test": "Prueba escritura disco",
|
||
"check_disk_space": "Espacio en disco",
|
||
"check_db_connect": "Conexión base de datos",
|
||
"check_db_tables": "Tablas de la BD",
|
||
"check_db_integrity": "Integridad BD",
|
||
"check_db_wal": "Modo WAL",
|
||
"check_db_size": "Tamaño de la BD",
|
||
"check_db_rows": "Datos del inventario",
|
||
"check_env": "Archivo .env",
|
||
"check_gemini": "Clave Gemini AI",
|
||
"check_bring_creds": "Credenciales Bring!",
|
||
"check_bring_token": "Token de Bring!",
|
||
"check_curl_ssl": "cURL SSL",
|
||
"check_internet": "Conexión a internet",
|
||
"fresh_install": "instalación nueva",
|
||
"warnings_found": "avisos detectados",
|
||
"all_ok": "Sistema OK",
|
||
"critical_error_short": "Error crítico",
|
||
"critical_error": "Error crítico: la aplicación no puede iniciarse. Revisa los registros del servidor.",
|
||
"error_network": "No se puede contactar con el servidor. Comprueba tu conexión de red.",
|
||
"retry": "Reintentar",
|
||
"syncing_local": "Sincronizando datos locales...",
|
||
"sync_done": "Datos locales sincronizados"
|
||
},
|
||
"stats_monthly": {
|
||
"title": "Estadísticas Mensuales",
|
||
"consumed": "productos usados",
|
||
"trend_up": "+{pct}% vs {prev}",
|
||
"trend_down": "-{pct}% vs {prev}",
|
||
"trend_same": "mismo ritmo que el mes pasado",
|
||
"added": "añadidos",
|
||
"wasted": "desperdiciados",
|
||
"top_used": "más usado",
|
||
"top_cats": "Categorías principales",
|
||
"source": "Historial de transacciones · mes actual"
|
||
}
|
||
} |