Files
EverShelf/translations/es.json
T
dadaloop82 7364e75881 feat: Google Drive OAuth via http://localhost redirect (no public domain required)
- Switch redirect URI from server IP to http://localhost (works everywhere)
- Add manual code exchange flow: user copies URL from browser, pastes in app
- New PHP action gdrive_oauth_exchange to exchange auth code for refresh token
- Fix  null bug in gdrive_oauth_exchange (was read before initialization)
- Add #gdrive-code-section UI with input + submit button in index.html
- Update _gdriveAuthorize() to show code section and store redirect_uri
- Add _gdriveSubmitCode() JS function for manual code submission
- Update setup wizard and backup tab to show http://localhost as redirect URI
- Add 5 new translation keys (gdrive_redirect_uri_hint, gdrive_code_title,
  gdrive_code_hint, gdrive_code_submit, gdrive_code_empty) in all 5 languages
- Update gdrive_oauth_steps in all translations to reflect new flow
- Document Google Drive OAuth setup in README.md
- Dark mode: comprehensive fix for 30+ components with hardcoded light colors
2026-05-18 18:41:56 +00:00

1282 lines
62 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": "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"
},
"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",
"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"
},
"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 &nbsp;·&nbsp; 🌙 = Cena &nbsp;·&nbsp; 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"
},
"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 &rarr; Seguridad y privacidad &rarr; Más ajustes de seguridad &rarr; 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» &rarr; Importar &rarr; 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."
},
"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) &mdash; peso, grasa, IMC</li><li>Xiaomi Mi Body Composition Scale 2</li><li>Genérico &mdash; 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>"
}
},
"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"
},
"confirm": {
"remove_item": "¿Realmente quieres eliminar este producto del inventario?",
"kiosk_exit": "¿Salir del modo kiosco?",
"cancel": "Cancelar",
"proceed": "Confirmar"
},
"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:"
},
"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"
},
"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"
}
}