widgets props | ui shit | i18n

This commit is contained in:
lovebird 2026-04-16 16:04:33 +02:00
parent e566206149
commit 2c724d590c
10 changed files with 392 additions and 105 deletions

View File

@ -138,6 +138,8 @@ export const PageCardWidgetSchema = z.object({
showFooter: z.boolean().default(true),
showAuthor: z.boolean().default(true),
showActions: z.boolean().default(true),
showTitle: z.boolean().default(true),
showDescription: z.boolean().default(false),
contentDisplay: ContentDisplaySchema.default('below'),
variables: WidgetVariablesSchema,
});

View File

@ -19,7 +19,6 @@ import TopNavigation from "@/components/TopNavigation";
import Footer from "@/components/Footer";
import { DragDropProvider } from "@/contexts/DragDropContext";
import { useAppStore } from "@/store/appStore";
import { serverUrl } from "@/lib/db";
const GlobalDragDrop = React.lazy(() => import("@/components/GlobalDragDrop"));
// Register all widgets on app boot
@ -88,9 +87,14 @@ Tetris = React.lazy(() => import("./apps/tetris/Tetris"));
FileBrowser = React.lazy(() => import("./modules/storage/FileBrowser"));
const VersionMap = React.lazy(() => import("./pages/VersionMap"));
/*
const UserCollections = React.lazy(() => import("./pages/UserCollections"));
const Collections = React.lazy(() => import("./pages/Collections"));
const NewCollection = React.lazy(() => import("./pages/NewCollection"));
<Route path="/user/:userId/collections" element={<React.Suspense fallback={<div>Loading...</div>}><UserCollections /></React.Suspense>} />
<Route path="/collections/new" element={<React.Suspense fallback={<div>Loading...</div>}><NewCollection /></React.Suspense>} />
<Route path="/collections/:userId/:slug" element={<React.Suspense fallback={<div>Loading...</div>}><Collections /></React.Suspense>} />
*/
const UserPage = React.lazy(() => import("./modules/pages/UserPage"));
const NewPage = React.lazy(() => import("./modules/pages/NewPage"));
const NewPost = React.lazy(() => import("./modules/posts/NewPost"));
@ -155,11 +159,8 @@ const AppWrapper = () => {
<Route path="/user/:userId/posts" element={<UserProfile />} />
<Route path="/user/:userId/pages" element={<UserProfile />} />
<Route path="/user/:userId/pictures" element={<UserProfile />} />
<Route path="/user/:userId/collections" element={<React.Suspense fallback={<div>Loading...</div>}><UserCollections /></React.Suspense>} />
<Route path="/user/:userId/pages/new" element={<React.Suspense fallback={<div>Loading...</div>}><NewPage /></React.Suspense>} />
<Route path="/user/:username/pages/:slug" element={<React.Suspense fallback={<div>Loading...</div>}><UserPage /></React.Suspense>} />
<Route path="/collections/new" element={<React.Suspense fallback={<div>Loading...</div>}><NewCollection /></React.Suspense>} />
<Route path="/collections/:userId/:slug" element={<React.Suspense fallback={<div>Loading...</div>}><Collections /></React.Suspense>} />
<Route path="/tags/:tag" element={<TagPage />} />
<Route path="/latest" element={<Index />} />
<Route path="/top" element={<Index />} />

View File

@ -1,14 +1,18 @@
{
"10001": "10001",
"\"Highlights and details\"": "\"Aspectos destacados y detalles\"",
"(stored securely)": "(guardado en lugar seguro)",
"# Common Features\n\n* Supported protocols: ModbusTCP, Serial, WebSocket and REST\n* Modern web interface with built-in HMI designer\n* Many safety features for fault detection, overload and overheat\n* Supported: Omron PIDs and VFDs, Delta VFD, Sako VFD\n\n### Features Sheetpress\n\n* Sequential Heating to deal with power supply limits\n* Supports up to 32 PID controllers, Omron E5x - via Modbus-RTU\n* Temperature & Pressure Profiles\n* Adaptive Pressure\n* Cost monitoring\n\n### Features Injection Machine\n\n* Temperature & Pressure Profiles\n* Adaptive Pressure / Post flow\n\n### Features Extrusion Machine\n\n* Temperature & Pressure Profiles\n* Adaptive Pressure / Post flow\n\n## Resources\n\n* [Knowledgebase](https://polymech.info/en/resources/cassandra/home/)\n* [Modbus Interface](https://polymech.info/en/resources/cassandra/modbus/)\n* [Cassandra Firmware source](https://git.polymech.info/polymech/firmware-base)\n* [Cassandra Firmware documentation - DeepWiki](https://deepwiki.com/polymech-info/firmware/1-overview)": "# Características comunes\n\n* Protocolos compatibles: ModbusTCP, serie, WebSocket y REST\n* Moderna interfaz web con diseñador de HMI integrado\n* Numerosas funciones de seguridad para detección de fallos, sobrecarga y sobrecalentamiento\n* Compatible: PIDs y VFDs Omron, Delta VFD, Sako VFD\n\n### Características Sheetpress\n\n* Calentamiento secuencial para hacer frente a los límites de alimentación\n* Admite hasta 32 controladores PID, Omron E5x - a través de Modbus-RTU\n* Perfiles de temperatura y presión\n* Presión adaptativa\n* Control de costes\n\n### Características Máquina de inyección\n\n* Perfiles de temperatura y presión\n* Presión adaptativa / Postflujo\n\n### Características Máquina de extrusión\n\n* Perfiles de temperatura y presión\n* Presión adaptativa / Postflujo\n\n## Recursos\n\n* [Base de conocimientos](https://polymech.info/en/resources/cassandra/home/)\n* [Interfaz Modbus](https://polymech.info/en/resources/cassandra/modbus/)\n* [Fuente del firmware Cassandra](https://git.polymech.info/polymech/firmware-base)\n* [Documentación del Firmware Cassandra - DeepWiki](https://deepwiki.com/polymech-info/firmware/1-overview)\n",
"# Vintage Delux Specifications\n\n| Specification | Value |\n| ---------------------- | ------------------------------------------------------ |\n| Variant | Vintage Delux |\n| Weight | 27 Kg |\n| Package Dimensions | 70 x 45 x 45 cm |\n| Plunger Diameter | 25 mm |\n| Usable Barrel Length | Up to 45 cm |\n| Supported Voltage | 220V / 110V |\n| Input Flake Size | Small - Medium |\n| Transmission | 1 : 1 |\n| Mold Interface | M20 thread / Cone Nozzle |\n| Heatbands | 3 (250W) / Ceramic |\n| Temperature Controller | 2 RexC-100 |\n| Shotsize | 145g |\n| Features | Shutoff Valve, Adjustable Mould Height, Quick Clamping |": "# Especificaciones Vintage Delux\n\n| Especificación | Valor |\n| ------------------------------ | -------------------------------------------------------------- |\n| Variante | Vintage Delux |\n| Peso | 27 Kg |\n| Dimensiones del paquete | 70 x 45 x 45 cm |\n| Diámetro del émbolo | 25 mm |\n| Longitud útil del cañón | Hasta 45 cm |\n| Tensión soportada | 220V / 110V |\n| Tamaño de la escama de entrada | Pequeño - Mediano |\n| Transmisión | 1 : 1 |\n| Interfaz de molde | Rosca M20 / Boquilla cónica |\n| Bandas de calor | 3 (250W) / Cerámica |\n| Controlador de temperatura | 2 - RexC-100 |\n| Tamaño del disparo | 145g |\n| Características | Válvula de cierre, altura del molde ajustable, sujeción rápida |\n",
"## Lydia Plastic Extruder Printhead (SJ25)\n\nHigh\\-throughput, modular pellet extruder for robotic and gantry 3D printing. Engineered for clean melt flow, wide material compatibility, and fast integration.\n\n- Compact head for precise, consistent deposition\n- Quick\\-swap nozzles and heater zones; adaptive temperature and pressure control\n- Integrates with 6\\-axis robots and open CNC/PLC controls\n- Processes virgin and recycled pellets/flakes reliably\n- Visual/audio feedback and web\\-configurable parameters\n- Robust, service\\-friendly design for industrial duty\n- Ideal for large\\-format prototypes, tooling, and end\\-use parts\n\nContact us for detailed specs, nozzle sizes, and integration kits.": "## Lydia - Cabezal de impresión de extrusión de plástico (SJ25)\n\nExtrusora de pelets modular de alto rendimiento para impresión 3D robótica y de pórtico. Diseñada para un flujo de fusión limpio, una amplia compatibilidad de materiales y una integración rápida.\n\n* Cabezal compacto para una deposición precisa y uniforme\n* Boquillas y zonas de calentamiento intercambiables; control adaptativo de la temperatura y la presión\n* Se integra con robots de 6 ejes y controles CNC/PLC abiertos\n* Procesa de forma fiable pelets y copos vírgenes y reciclados\n* Información visual y sonora y parámetros configurables desde la web\n* Diseño robusto y de fácil mantenimiento para uso industrial\n* Ideal para prototipos de gran formato, utillaje y piezas de uso final\n\nPóngase en contacto con nosotros para obtener especificaciones detalladas, tamaños de boquillas y kits de integración.\n",
"+1 555 000 0000": "+1 555 000 0000",
"+1 555 123 4567": "+1 555 123 4567",
"<h3>Processing Time</h3><p>Orders placed before 2:00 PM (local time) on business days are typically processed and shipped the same day. Orders placed after this cut-off or on weekends/holidays will be processed the next business day.</p>": "<h3>Tiempo de procesamiento</h3><p>Los pedidos realizados antes de las 14:00 (hora local) en días laborables suelen procesarse y enviarse el mismo día. Los pedidos realizados después de esta hora límite o en fines de semana o festivos se tramitarán el siguiente día laborable.</p>",
"<h3>Tracking</h3><p>Once your order ships, you will receive a confirmation email with a tracking number. You can use this number to track your package on the carrier's website.</p>": "<h3>Seguimiento</h3><p>Una vez enviado el pedido, recibirá un correo electrónico de confirmación con un número de seguimiento. Puede utilizar este número para rastrear su paquete en el sitio web del transportista.</p>",
"| **Name** | Lydia - Printhead |\n| --- | --- |\n| **Version** | 3.5 |\n| **Weight** | 35KG - 60KG |\n| **Package Dimensions** | 80 x 80 x 300 cm |\n| **Screw Diameter** | 25 - 35 mm |\n| **Barrel Diameter** | 40mm - 55mm |\n| **Barrel Length** | 42cm - 70cm |\n| **Voltage** | 220V - 380V |\n| **Gearbox** | 1:30 |\n| **Supported VFDs** | Delta, ABB, Omron & Sako |\n| **Supported Robots** | ABB & Kuga |\n| **Communication** | Modbus-RTU/TCP / REST / Websocket |\n| **Motor Power** | 1.5 - 3kW |\n| **Input Flake Size** | Small - Medium |\n": "| **Nombre** | Lydia - Cabezal de impresión |\n| ---------------------------------- | --------------------------------- |\n| **Versión** | 3.5 |\n| **Peso** | 35KG - 60KG |\n| **Dimensiones del paquete** | 80 x 80 x 300 cm |\n| **Diámetro del tornillo** | 25 - 35 mm |\n| **Diámetro del cañón** | 40 mm - 55 mm |\n| **Longitud del cañón** | 42cm - 70cm |\n| **Tensión** | 220V - 380V |\n| **Caja de cambios** | 1:30 |\n| **VFD compatibles** | Delta, ABB, Omron y Sako |\n| **Robots compatibles** | ABB y Kuga |\n| **Comunicación** | Modbus-RTU/TCP / REST / Websocket |\n| **Potencia del motor** | 1,5 - 3 kW |\n| **Tamaño de la escama de entrada** | Pequeño - Mediano |\n",
"| Name | PolyMech Controller EDC |\n|------|----------------------------|\n| Protocols | Modbus-RTU / ModbusTCP / Serial / WebSocket / REST |\n| Processor | ESP-32-S3 |\n| Board | Waveshare-6-Channel |\n| Connectivity | Wifi / Bluetooth / USB-C / RS485 |\n| Supported VFDs | Omron, ABB, Delta, Hynang, Sako |\n| Supported Temperature Controllers | Omron-E5x |\n| GPIO | 6 Digital / 2 PWM / 2 Analog In |\n| Status | Mature |\n| Version | V1.0 (Revision A) |\n| License | [CERN OHL v2](https://ohwr.org/cern_ohl_s_v2.txt) |\n| Weight | 25 Kg |\n": "| Nombre | Controlador PolyMech - EDC |\n| ---------------------------------------- | ------------------------------------------------- |\n| Protocolos | Modbus-RTU / ModbusTCP / Serie / WebSocket / REST |\n| Procesador | ESP-32-S3 |\n| Junta | Waveshare-6-Canales |\n| Conectividad | Wifi / Bluetooth / USB-C / RS485 |\n| VFD compatibles | Omron, ABB, Delta, Hynang, Sako |\n| Controladores de temperatura compatibles | Omron-E5x |\n| GPIO | 6 Entradas digitales / 2 PWM / 2 analógicas |\n| Estado | Maduro |\n| Versión | V1.0 (Revisión A) |\n| Licencia | [CERN OHL v2](https://ohwr.org/cern_ohl_s_v2.txt) |\n| Peso | 25 Kg |\n",
"0% means centroids must be at least 1 cell-size apart. 100% allows exact duplicates.": "0% significa que los centroides deben estar separados por al menos 1 tamaño de celda. 100% permite duplicados exactos.",
"1 file(s) added successfully!": "¡1 archivo(s) añadido(s) con éxito!",
"1. Command line — one file": "1. Línea de comandos - un archivo",
"1. Parquet-Powered Flat Database": "1. Base de datos plana basada en parquet",
"1. System Overview": "1. Visión general del sistema",
@ -59,16 +63,20 @@
"Acme Corp": "Acme Corp",
"Actions": "Acciones",
"active": "activo",
"Active Marker": "Marcador activo",
"Active Permissions": "Permisos activos",
"Add": "Añadir",
"Add a comment...": "Añade un comentario...",
"Add a container to start building your layout": "Añade un contenedor para empezar a construir tu diseño",
"Add a set of sample control points to this plot": "Añadir un conjunto de puntos de control de muestra a este gráfico",
"Add Address": "Añadir dirección",
"Add AI filter": "Añadir filtro AI",
"Add all": "Añadir todo",
"Add Button": "Botón Añadir",
"Add Child": "Añadir niño",
"Add Container": "Añadir contenedor",
"Add Content": "Añadir contenido",
"Add Images": "Añadir imágenes",
"Add Link": "Añadir enlace",
"Add rich text content with Markdown support": "Añadir contenido de texto enriquecido compatible con Markdown",
"Add Samples": "Añadir muestras",
@ -84,12 +92,21 @@
"Address": "Dirección",
"Address Picker": "Selector de direcciones",
"Admin": "Admin",
"Administrative": "Administrativo",
"Advanced": "Avanzado",
"ADVANCED": "AVANZADO",
"Agent": "Agente",
"AI Assistant": "Asistente AI",
"AI Chat": "Chat AI",
"AI Context for Potential Customer Matching": "Contexto AI para la búsqueda de clientes potenciales",
"AI filters run finished": "Finalizada la ejecución de los filtros AI",
"AI grid filters": "Filtros de rejilla AI",
"AI Image Generator": "Generador de imágenes AI",
"AI Image Wizard": "Asistente para imágenes AI",
"AI Layout": "Diseño AI",
"AI Model": "Modelo de IA",
"AI-generated from emails and scraped pages. May be inaccurate.": "Generado por IA a partir de correos electrónicos y páginas raspadas. Puede ser inexacta.",
"AI: edit context for Potential customer scoring": "AI: editar el contexto para la puntuación de clientes potenciales",
"AIMLAPI API Key": "Clave API AIMLAPI",
"All": "Todos",
"All groups": "Todos los grupos",
@ -97,7 +114,9 @@
"All statuses": "Todos los estados",
"All Stop": "Todos Stop",
"All Types": "Todos los tipos",
"Allow Location Details": "Permitir detalles de ubicación",
"Allow Missing Data Gaps": "Permitir la falta de datos",
"Allow toggling between density heatmap and center points.": "Permitir alternar entre el mapa de calor de densidad y los puntos centrales.",
"AP Gateway": "Pasarela AP",
"AP IP Address": "Dirección IP AP",
"AP Password": "Contraseña AP",
@ -109,22 +128,34 @@
"API Error on /api/vfs/ls/software: Forbidden": "Error de API en /api/vfs/ls/software: Prohibido",
"API Keys": "Claves API",
"API URL": "URL API",
"Append to Existing Post": "Añadir a entrada existente",
"Application ideas (with notes)": "Ideas de aplicación (con notas)",
"Apply": "Solicitar",
"Apply saved type excludes as DataGrid filters": "Aplicar exclusiones de tipo guardadas como filtros de DataGrid",
"Arbor injection machine that provides fast, repeatable, comfortable, safe and precise injection of plastic!\n\n#### \"Highlights and details\"\n\n- All parts are precision manufactured, using modern CNC and manual machines\n- Smooth and precise plunging experience\n- The plunger has a replaceable bronze tip\n- 2 mold interfaces: cone for press, and M20 thread interface\n- Heat-shield and insulation\n- Step-less mould height adjustment\n- Mould guide pins and slots\n- Transmission 1:1\n- Shot size: 145G\n- Quick Clamping\n- Shutoff valve\n- Mostly Stainless, Aluminum\n\n#### Services\n\n- After - Sales Service\n- 3 years Warranty\n- Cheap replacements for consumables\n- Customization to user needs\n- Mold design and fabrication\n\n": "Inyectora Arbor que proporciona una inyección de plástico rápida, repetible, cómoda, segura y precisa.\n\n#### \"Aspectos destacados y detalles\"\n\n* Todas las piezas se fabrican con precisión, utilizando modernas máquinas CNC y manuales\n* Experiencia de inmersión suave y precisa\n* El émbolo tiene una punta de bronce reemplazable\n* 2 interfaces de molde: cono para prensa e interfaz de rosca M20\n* Escudo térmico y aislamiento\n* Ajuste de la altura del molde sin escalones\n* Pasadores y ranuras de guía del molde\n* Transmisión 1:1\n* Tamaño del disparo: 145G\n* Sujeción rápida\n* Válvula de cierre\n* Principalmente inoxidable, aluminio\n\n#### Servicios\n\n* Servicio postventa\n* 3 años de garantía\n* Sustitución barata de consumibles\n* Adaptación a las necesidades del usuario\n* Diseño y fabricación de moldes\n",
"Are you sure you want to delete": "¿Estás seguro de que quieres borrar",
"Are you sure you want to delete this category?": "¿Está seguro de que desea eliminar esta categoría?",
"Are you sure you want to delete this image version? This action cannot be undone and will permanently remove the image from your account.": "¿Está seguro de que desea eliminar esta versión de la imagen? Esta acción no se puede deshacer y eliminará permanentemente la imagen de su cuenta.",
"Are you sure you want to delete this picture? This action cannot be undone.": "¿Estás seguro de que quieres borrar esta foto? Esta acción no se puede deshacer.",
"Are you sure you want to delete this post? This action cannot be undone.": "¿Estás seguro de que quieres borrar este mensaje? Esta acción no se puede deshacer.",
"Area Selector": "Selector de zona",
"Areas Scanned:": "Áreas escaneadas:",
"Argument 0:": "Argumento 0:",
"Argument 1:": "Argumento 1:",
"Argument 2 (Optional):": "Argumento 2 (opcional):",
"Arguments:": "Argumentos:",
"Ask Questions": "Haga preguntas",
"Aspect Ratio": "Relación de aspecto",
"Assembly and connection tips": "Consejos de montaje y conexión",
"Assign types to allow using them in this category.": "Asignar tipos para permitir su uso en esta categoría.",
"Assigned ACL Groups": "Grupos ACL asignados",
"Assigned types": "Tipos asignados",
"Assigned Types": "Tipos asignados",
"Associated Controllers:": "Controladores asociados:",
"Associated Signal Plot (Optional)": "Gráfico de señales asociadas (opcional)",
"Auto": "Auto",
"AUTO": "AUTO",
"Auto Detect": "Detección automática",
"AUTO MULTI": "AUTO MULTI",
"AUTO MULTI BALANCED": "AUTO MULTI BALANCED",
"AUTO_MULTI": "AUTO_MULTI",
@ -141,6 +172,7 @@
"BALANCE": "BALANCE",
"BALANCE_MAX_DIFF": "BALANCE_MAX_DIFF",
"Banner description text": "Texto de descripción del banner",
"Based on this grid search campaign": "Basándose en esta campaña de búsqueda en la red",
"Batch done": "Lote realizado",
"Batch Page Translation": "Traducción de páginas por lotes",
"Be the first to comment!": "¡Sé el primero en comentar!",
@ -151,6 +183,7 @@
"blocked": "bloqueado",
"Boolean": "Booleano",
"bounced": "rebotado",
"Branch / part of larger firm": "Sucursal / parte de una empresa más grande",
"Bria API Key": "Clave API de Bria",
"Browse": "Visite",
"Browse Files": "Examinar archivos",
@ -179,6 +212,7 @@
"Campaigns": "Campañas",
"Can I resize images from URLs?": "¿Puedo cambiar el tamaño de las imágenes a partir de URL?",
"Cancel": "Cancelar",
"Caption / Description": "Leyenda / Descripción",
"Características": "Características",
"Carina": "Carina",
"Cart": "Carrito",
@ -187,13 +221,18 @@
"Cassandra Right": "Cassandra Derecha",
"Castor": "Ricino",
"Categories": "Categorías",
"Categories updated": "Categorías actualizadas",
"Category": "Categoría",
"Category created": "Categoría creada",
"Category deleted": "Categoría eliminada",
"Category Feed": "Categoría Alimentación",
"Category Filter": "Categoría Filtro",
"Category Hierarchy": "Jerarquía de categorías",
"Category ID": "Categoría ID",
"Category Manager": "Responsable de categoría",
"Category Slugs": "Categoría Babosas",
"CE": "CE",
"Cell value type (for sorting / filters)": "Tipo de valor de celda (para clasificación / filtros)",
"Cell:": "Celda:",
"cells": "células",
"Center Content": "Contenido central",
@ -212,10 +251,18 @@
"Chat Buttons": "Botones de chat",
"Chat Logs": "Registros de chat",
"Child Profiles (Sub-plots)": "Perfiles de los niños (subtramas)",
"Choose a method to specify the geographic target for your analysis.": "Elija un método para especificar el objetivo geográfico de su análisis.",
"Choose a page to display": "Elija una página para mostrar",
"Choose a page to link in the menu.": "Elija una página para enlazar en el menú.",
"Choose a picture from your published images": "Elija una imagen de las publicadas",
"Choose between full search view or minimal dashboard view.": "Elija entre la vista de búsqueda completa o la vista mínima del panel de control.",
"Choose File": "Elegir archivo",
"Choose Files": "Elegir archivos",
"Choose Files or Drop Here": "Elegir archivos o soltar aquí",
"Choose from the options below to start generating or uploading content.": "Elija una de las opciones siguientes para empezar a generar o cargar contenidos.",
"Choose one of your existing posts to add these images to.": "Elige una de tus entradas existentes para añadir estas imágenes.",
"Choose or Drop Files": "Elegir o soltar archivos",
"Cities, Provinces, Countries, or GIDs": "Ciudades, provincias, países o GID",
"City": "Ciudad",
"Clear": "Claro",
"Clear All": "Borrar todo",
@ -224,6 +271,7 @@
"Clear Chart": "Gráfico claro",
"Clear Grid": "Rejilla transparente",
"Clear Index": "Índice claro",
"Clear selection": "Borrar selección",
"Clear user filter": "Borrar filtro de usuario",
"Clears the server-side content cache (memory) and the disk-based image cache. Use this if content is not updating correctly.": "Borra la caché de contenidos del servidor (memoria) y la caché de imágenes del disco. Utilícelo si el contenido no se actualiza correctamente.",
"CLI examples": "Ejemplos CLI",
@ -231,6 +279,7 @@
"Click \"Add Widget\" to start building your HMI": "Haga clic en \"Añadir Widget\" para empezar a crear su HMI",
"Click \"Pick Video\" to select a background video": "Haz clic en \"Elegir vídeo\" para seleccionar un vídeo de fondo",
"Click anywhere on the map to inspect administrative areas, or use the search below.": "Haga clic en cualquier lugar del mapa para inspeccionar las zonas administrativas, o utilice la búsqueda que aparece a continuación.",
"Click on a location to open the detail panel with address, ratings, and contact info.": "Haga clic en un lugar para abrir el panel de detalles con la dirección, las valoraciones y la información de contacto.",
"Click to copy": "Haga clic para copiar",
"Click to see all emails": "Haga clic para ver todos los correos electrónicos",
"Click types in the top bar to add variables": "Haga clic en tipos en la barra superior para añadir variables",
@ -246,20 +295,25 @@
"Coma B": "Coma B",
"Comma-separated category slugs to filter by (leave empty for all)": "Categorías separadas por comas por las que filtrar (dejar vacío para todas)",
"Commons": "Comunes",
"Company size (estimate)": "Tamaño de la empresa (estimación)",
"Comparsion": "Comparación",
"Competitors Map": "Mapa de la competencia",
"Complete": "Complete",
"components": "componentes",
"Components": "Componentes",
"Condiciones": "Condiciones",
"Configure": "Configure",
"Configure the new control point. Press Enter to confirm or Esc to cancel.": "Configure el nuevo punto de control. Pulse Intro para confirmar o Esc para cancelar.",
"Configure the series to be displayed on the chart.": "Configure las series que se mostrarán en el gráfico.",
"Configure your grid granularity and start the scan.": "Configure la granularidad de su cuadrícula e inicie la exploración.",
"Confirm Selection": "Confirmar selección",
"Connect": "Conectar",
"Connect to a Modbus server to see controller data.": "Conectarse a un servidor Modbus para ver los datos del controlador.",
"Connect to view register data.": "Conéctate para ver los datos del registro.",
"Connected, but no register data received yet. Waiting for data...": "Conectado, pero aún no se han recibido datos de registro. Esperando datos...",
"Connects to an existing Wi-Fi network.": "Se conecta a una red Wi-Fi existente.",
"Constrain process sequentially per boundary": "Limitar el proceso secuencialmente por frontera",
"Contact notes": "Notas de contacto",
"Contacto (particular)": "Contacto (particular)",
"Contacts": "Contactos",
"contacts were added successfully.": "los contactos se han añadido correctamente.",
@ -267,9 +321,13 @@
"Container added": "Contenedor añadido",
"Containers": "Contenedores",
"Content": "Contenido",
"Content Display": "Visualización de contenidos",
"Content not found": "Contenido no encontrado",
"Content saved!": "¡Contenido guardado!",
"Content type": "Tipo de contenido",
"Content Type": "Tipo de contenido",
"Context": "Contexto",
"Context Preset (Optional)": "Contexto preestablecido (opcional)",
"Continue": "Continúe en",
"Control Points": "Puntos de control",
"Control Points List": "Lista de puntos de control",
@ -277,6 +335,7 @@
"Controller Partitions": "Particiones del controlador",
"Copied 1 widget(s)": "Copiado 1 widget(s)",
"Copied container with 1 widget(s)": "Contenedor copiado con 1 widget(s)",
"Copied container with 7 widget(s)": "Contenedor copiado con 7 widget(s)",
"Copy": "Copia",
"Copy \"{plotName}\" to...": "Copiar \"{plotName}\" a...",
"Copy \"{profileName}\" to...": "Copiar \"{nombredeperfil}\" a...",
@ -311,6 +370,7 @@
"CTA Buttons": "Botones CTA",
"Current": "Actual",
"Current Page Link": "Enlace a la página actual",
"Current Selection": "Selección actual",
"Current Status": "Situación actual",
"Custom Widgets": "Widgets personalizados",
"Dashboard": "Cuadro de mandos",
@ -333,18 +393,25 @@
"Delete": "Borrar",
"Delete All Translations": "Borrar todas las traducciones",
"Delete control point": "Borrar punto de control",
"Delete Image Version": "Borrar versión de imagen",
"Delete Picture": "Borrar imagen",
"Delete Post": "Suprimir puesto",
"Delete Profile": "Borrar perfil",
"Delete selected": "Borrar seleccionados",
"Delta Vfd[15]": "Delta Vfd[15]",
"Describe the image you want to create or edit... (Ctrl+V to paste images)": "Describe la imagen que quieres crear o editar... (Ctrl+V para pegar imágenes)",
"Describe the page you want the AI to create. It can generate text and images for you.": "Describe la página que quieres que cree la IA. Puede generar texto e imágenes por ti.",
"Describe your photo... You can use **markdown** formatting!": "Describe tu foto... ¡Puedes utilizar el formato **markdown**!",
"Describe your post... Supports **bold**, *italic*, lists, etc.": "Describe tu puesto... Apoya **negrita**, *cursiva*listas, etc.\n",
"Description": "Descripción",
"Description (Optional)": "Descripción (opcional)",
"design": "diseño",
"DESIGN": "DISEÑO",
"Destination Group": "Grupo Destino",
"Details": "Detalles",
"Developer": "Desarrollador",
"Device Hostname": "Nombre de host del dispositivo",
"Differentiators": "Diferenciadores",
"Disable All": "Desactivar todo",
"Discard & Exit": "Descartar y salir",
"Discard changes?": "¿Descartar cambios?",
@ -357,14 +424,27 @@
"Display a filtered feed for a specific category with heading and content type filter": "Mostrar un feed filtrado para una categoría específica con filtro de encabezamiento y tipo de contenido.",
"Display a single page card with details": "Mostrar una tarjeta de una sola página con detalles",
"Display a single photo card with details": "Mostrar una sola tarjeta con foto y detalles",
"Display density points and grid centers from the simulator.": "Muestra los puntos de densidad y los centros de cuadrícula del simulador.",
"Display Message": "Mostrar mensaje",
"Display Name": "Mostrar nombre",
"Display name (optional, defaults to field id)": "Nombre para mostrar (opcional, por defecto es el id del campo)",
"Display photos in a responsive grid layout": "Mostrar fotos en una cuadrícula adaptable",
"Display Preset": "Preselección de pantalla",
"Display red/green boundary polygons for searched regions.": "Mostrar polígonos de límites rojos/verdes para las regiones buscadas.",
"Display the actual found location pins and clusters.": "Muestra los pines de localización y los clusters encontrados.",
"Display the main home feed with photos, categories, and sorting": "Mostrar el feed de inicio principal con fotos, categorías y clasificación",
"Display the map in stylized poster view with themed overlays.": "Visualice el mapa en vista de póster estilizado con superposiciones temáticas.",
"Display the page description on the card": "Mostrar la descripción de la página en la tarjeta",
"Display the page title on the card": "Mostrar el título de la página en la tarjeta",
"Display the picture description": "Mostrar la descripción de la imagen",
"Display the picture title": "Mostrar el título de la imagen",
"Display the picture/post description beneath the title": "Mostrar la imagen/descripción del post debajo del título",
"Display the picture/post description on feed cards": "Mostrar la imagen/descripción del post en las tarjetas de alimentación",
"Display the picture/post title": "Mostrar el título de la imagen/post",
"Display the picture/post title on feed cards": "Mostrar el título de la imagen/post en las tarjetas de alimentación",
"Display the selected category name as heading (when no custom heading is set)": "Mostrar el nombre de la categoría seleccionada como encabezamiento (cuando no se ha establecido un encabezamiento personalizado)",
"Does pm-image work on Windows?": "¿Funciona pm-image en Windows?",
"Domestic": "Doméstico",
"Don't have an account? Sign up": "¿No tiene una cuenta? Regístrese",
"Done": "Hecho",
"Download": "Descargar",
@ -372,12 +452,16 @@
"Download English Translations": "Descargar traducciones al inglés",
"Download JSON for {name}": "Descargar JSON para {nombre}",
"Download Plot": "Descargar parcela",
"Download selected": "Descarga seleccionada",
"Download settings JSON": "Descargar JSON de configuración",
"Download Waypoints (GeoJSON)": "Descargar Waypoints (GeoJSON)",
"draft": "borrador",
"Drag and drop images here or click Add Images": "Arrastre y suelte las imágenes aquí o haga clic en Añadir imágenes",
"Drag and resize widgets": "Arrastrar y cambiar el tamaño de los widgets",
"Drag files anywhere to start": "Arrastre los archivos a cualquier lugar para empezar",
"Drop <": "Drop &lt;",
"Drop >": "Drop &gt;",
"Drop files to upload": "Archivos para cargar",
"Dual": "Doble",
"Dual pane": "Doble cristal",
"Dump JSON": "Volcar JSON",
@ -391,6 +475,7 @@
"e.g. Main Business, EU Branch": "Por ejemplo, empresa principal, sucursal de la UE",
"e.g. restaurant, lodging": "por ejemplo, restaurante, alojamiento",
"e.g. Ring doorbell, leave at reception…": "Por ejemplo, llamar al timbre, dejar en recepción...",
"e.g. We want B2B marketing agencies; prioritize firms offering SEO and paid ads…": "p. ej. Queremos agencias de marketing B2B; dar prioridad a las empresas que ofrezcan SEO y anuncios de pago...",
"e.g., HVAC contractors": "por ejemplo, contratistas de HVAC",
"E.g., Quick Ramp Up": "Por ejemplo, Quick Ramp Up",
"e.g., Start Heating": "p. ej., Iniciar calefacción",
@ -399,9 +484,11 @@
"Edit Campaign": "Editar campaña",
"Edit Details": "Editar detalles",
"Edit Home Page": "Editar página de inicio",
"Edit in Lightbox": "Editar en Lightbox",
"Edit mode: Add, move, and configure widgets": "Modo edición: Añadir, mover y configurar widgets",
"Edit mode: Configure containers and add widgets": "Modo edición: Configurar contenedores y añadir widgets",
"Edit Picture": "Editar imagen",
"Edit Post": "Editar puesto",
"Edit Product": "Editar producto",
"Edit Profile": "Editar perfil",
"Edit Profile Page": "Editar página de perfil",
@ -421,6 +508,10 @@
"Enable All": "Activar todo",
"Enable Auto-Enrichments (Website & Email Lookup)": "Activar el enriquecimiento automático (búsqueda de sitios web y correo electrónico)",
"Enable control unavailable for {name}": "Habilitar control no disponible para {nombre}",
"Enable Distance Ruler": "Activar regla de distancia",
"Enable Grid Simulator": "Activar el simulador de red",
"Enable Layer Toggles": "Activar los conmutadores de capa",
"Enable Statistics Panel": "Activar el panel de estadísticas",
"Enabled": "Activado",
"End Index": "Índice final",
"Enrich Visible Locations": "Enriquecer los lugares visibles",
@ -450,20 +541,25 @@
"err": "err",
"Error": "Error",
"ERROR": "ERROR",
"Estimate": "Estimación",
"EUR": "EUR",
"Ex": "Ex",
"Exclude": "Excluir",
"Exclude Types (comma separated)": "Tipos de exclusión (separados por comas)",
"Excludes any of (types)": "Excluye cualquiera de (tipos)",
"Exit Fullscreen": "Salir de pantalla completa",
"Expand": "Ampliar",
"Export": "Exportar",
"Export JSON": "Exportar JSON",
"Export to CSV": "Exportar a CSV",
"Express": "Express",
"Ext": "Ext",
"Extr": "Extr",
"Extracted Web Content": "Contenido web extraído",
"Extru": "Extru",
"Extrud": "Extrud",
"Extrude": "Extrusión",
"extruder": "extrusora",
"Extruder": "Extrusora",
"Extruders": "Extrusoras",
"Extrudr": "Extrudr",
@ -472,15 +568,18 @@
"failed": "fallido",
"Failed to flush cache": "Error al vaciar la caché",
"Failed to load content": "Error al cargar el contenido",
"Failed to load image versions": "Error al cargar versiones de imagen",
"Failed to load profile data": "Error al cargar los datos del perfil",
"Failed to load user profile": "Error al cargar el perfil de usuario",
"Failed to load your images": "Error al cargar las imágenes",
"Failed to save file": "Error al guardar el archivo",
"Fallback image shown while video loads": "Se muestra una imagen de reserva mientras se carga el vídeo",
"FAQ (questions and answers)": "FAQ (preguntas y respuestas)",
"Fast & Direct": "Rápido y directo",
"Favorite Coils": "Bobinas favoritas",
"Favorite Registers": "Registros favoritos",
"Favorites": "Favoritos",
"Features": "Características",
"Features at a glance": "Características",
"Fields": "Campos",
"File": "Archivo",
@ -491,6 +590,8 @@
"Files": "Archivos",
"FILES": "ARCHIVOS",
"Fill": "Rellene",
"Fill Height": "Altura de llenado",
"Fill the parent container height (use when embedding in a fixed-height layout)": "Rellena la altura del contenedor padre (se utiliza cuando se incrusta en un diseño de altura fija)",
"Filling": "Relleno",
"Filter": "Filtro",
"Filter by content type": "Filtrar por tipo de contenido",
@ -499,6 +600,7 @@
"Filter to show only a specific content type": "Filtro para mostrar sólo un tipo de contenido específico",
"Finish": "Acabado",
"Flex Container": "Contenedor flexible",
"Flexible container added": "Contenedor flexible añadido",
"Floating support chat button that expands into a full chat panel.": "Botón flotante de chat de soporte que se expande en un panel de chat completo.",
"Flush Cache": "Vaciar caché",
"Flush System Cache": "Vaciar la caché del sistema",
@ -520,6 +622,7 @@
"Found": "Encontrado",
"Found places with these types will be ignored globally.": "Los lugares encontrados con estos tipos serán ignorados globalmente.",
"Found Types:": "Tipos encontrados:",
"Free shipping on orders over $75": "Envío gratuito en pedidos superiores a 75",
"Full Overlap": "Solapamiento total",
"Full Text Search (extract text from files)": "Búsqueda de texto completo (extraer texto de archivos)",
"Full-width hero banner with background video, text overlay, and call-to-action buttons": "Banner principal de ancho completo con vídeo de fondo, texto superpuesto y botones de llamada a la acción",
@ -530,10 +633,12 @@
"Gallery": "Galería",
"General": "General",
"General Settings": "Configuración general",
"Generate": "Genere",
"Generate AI Image": "Generar imagen AI",
"Generate AI images or upload your own photos to share.": "Genera imágenes AI o sube tus propias fotos para compartirlas.",
"Generate an image from a text prompt": "Generar una imagen a partir de un texto",
"Generate complete pages with AI-powered text and images.": "Genere páginas completas con texto e imágenes basados en IA.",
"Generate Image": "Generar imagen",
"Generate Text Only": "Generar sólo texto",
"Generate Title & Description with AI": "Generar título y descripción con IA",
"Generate with AI": "Generar con IA",
@ -546,18 +651,23 @@
"Global Groups": "Grupos mundiales",
"Global Settings": "Ajustes globales",
"Glossaries": "Glosarios",
"Go Home": "Volver a casa",
"Go to app": "Ir a la aplicación",
"Google API Key": "Clave API de Google",
"Gracefully restart the server process. Systemd will automatically bring it back online. This will cause a brief downtime.": "Reinicie el proceso del servidor. Systemd lo volverá a poner en línea automáticamente. Esto causará un breve tiempo de inactividad.",
"Grant": "Subvención",
"Grant Access": "Conceder acceso",
"Grid Columns": "Columnas de cuadrícula",
"Grid filters": "Filtros de rejilla",
"Grid filters: type excludes, AI context, and AI column filters": "Filtros de rejilla: exclusión de tipos, contexto AI y filtros de columna AI",
"Grid Generation Limit": "Límite de generación de la red",
"Grid search": "Búsqueda en la cuadrícula",
"Grid Search": "Búsqueda en la cuadrícula",
"Grid Simulation Mode": "Modo de simulación de red",
"Grid:": "Rejilla:",
"GridSearch": "GridSearch",
"Grounding with Google Search": "Toma de tierra con Google Search",
"Grounding with Image Search": "Toma de tierra con búsqueda de imágenes",
"Group": "Grupo",
"group selected": "grupo seleccionado",
"Groups": "Grupos",
@ -589,6 +699,8 @@
"How do I resize without losing quality?": "¿Cómo puedo cambiar el tamaño sin perder calidad?",
"How does caching work?": "¿Cómo funciona la caché?",
"How It Works: The TypeScript Engine": "Cómo funciona: El motor TypeScript",
"How the image should fit within the card": "Cómo debe encajar la imagen en la tarjeta",
"How to display title and description": "Cómo mostrar el título y la descripción",
"How to resize images (quick start)": "Cómo cambiar el tamaño de las imágenes (inicio rápido)",
"HTML Content": "Contenido HTML",
"HTML heading level": "Nivel de encabezamiento HTML",
@ -605,6 +717,10 @@
"If a region is physically missing GHS raster data, allow it to pass instead of auto-failing": "Si a una región le faltan físicamente datos ráster GHS, permita que pase en lugar de que falle automáticamente.",
"If enabled, it ignores ALL density, elevation, geometry overlap, and custom filters. Will push all raw items": "Si se activa, ignora TODOS los filtros de densidad, elevación, superposición de geometría y personalizados. Empujará todos los elementos sin procesar",
"Image": "Imagen",
"Image Actions": "Acciones de imagen",
"Image Fit": "Ajuste de imagen",
"Image quick published as new post!": "¡Imagen publicada rápidamente como nuevo post!",
"Image Settings & Metadata": "Ajustes de imagen y metadatos",
"Image Tools": "Herramientas de imagen",
"Image Tools enabled: AI can generate and embed images in the content": "Herramientas de imagen habilitadas: La IA puede generar e incrustar imágenes en el contenido",
"Image URL...": "URL de la imagen...",
@ -619,21 +735,29 @@
"Impressum": "Impresionante",
"In": "En",
"in seconds": "en segundos",
"Include Actions": "Incluir acciones",
"Include Author": "Incluir autor",
"Include page context": "Incluir el contexto de la página",
"Include page title": "Incluir el título de la página",
"Index Mount": "Monte índice",
"Industries": "Industrias",
"info": "información",
"Info": "Información",
"Initial Prompt...": "Pregunta inicial...",
"Initial Search Query": "Consulta de búsqueda inicial",
"Initializing Interface...": "Inicializando Interfaz...",
"injectors": "inyectores",
"Injectors": "Inyectores",
"Insert Link": "Insertar enlace",
"Inspected Location": "Ubicación inspeccionada",
"Instant Quote": "Presupuesto instantáneo",
"Instructions for the model (what to score or extract)": "Instrucciones para el modelo (qué puntuar o extraer)",
"Integrations": "Integraciones",
"Interactive gallery with main viewer and filmstrip navigation": "Galería interactiva con visor principal y navegación por películas",
"Interactive map with clustering, regional analysis, and grid search simulator.": "Mapa interactivo con agrupación, análisis regional y simulador de búsqueda de cuadrículas.",
"Interlocked": "Entrelazados",
"Internal notes, instructions…": "Notas internas, instrucciones...",
"International": "Internacional",
"Interval between sends (seconds)": "Intervalo entre envíos (segundos)",
"Invisible": "Invisible",
"ipc — one JSON line per connection (TCP; Unix socket on Linux/macOS)": "ipc - una línea JSON por conexión (TCP; socket Unix en Linux/macOS)",
@ -644,6 +768,7 @@
"Jammed": "Atascado",
"Jane Doe": "Jane Doe",
"jane@example.com": "jane@example.com",
"Job Failed": "Trabajo fallido",
"Job ID:": "ID del puesto:",
"Joined": "Se unió a",
"Joystick": "Joystick",
@ -686,17 +811,22 @@
"Loading Cassandra settings...": "Cargando configuración de Cassandra...",
"Loading comments...": "Cargando comentarios...",
"Loading Editor...": "Cargando Editor...",
"Loading filters…": "Cargando filtros...",
"Loading gallery items...": "Cargando elementos de la galería...",
"Loading gallery...": "Cargando galería...",
"Loading groups...": "Cargando grupos...",
"Loading map data...": "Cargando datos del mapa...",
"Loading network settings...": "Cargando configuración de red...",
"Loading page...": "Cargando página...",
"Loading past searches...": "Cargando búsquedas anteriores...",
"Loading picture...": "Cargando imagen...",
"Loading pictures...": "Cargando imágenes...",
"Loading post...": "Cargando post...",
"Loading products...": "Cargando productos...",
"Loading profile...": "Cargando perfil...",
"Loading profiles from Modbus...": "Cargando perfiles de Modbus...",
"Loading search results...": "Cargando resultados de búsqueda...",
"Loading Spreadsheet viewer...": "Cargando Visor de hojas de cálculo...",
"Loading system metrics...": "Cargando métricas del sistema...",
"Loading vendor profiles…": "Cargando perfiles de proveedores...",
"Loading versions...": "Cargando versiones...",
@ -708,6 +838,8 @@
"Logs Dashboard": "Cuadro de mandos de registros",
"Low": "Bajo",
"Lydia - Plastic Extruder - Robot Printhead - SJ25": "Lydia - Extrusora de plástico - Cabezal de impresión robotizado - SJ25",
"Lydia Extruder Family": "Familia Lydia Extruder",
"Lydia SJ30 — Production-Grade Open-Source Extruder": "Lydia SJ30 - Extrusora de código abierto para producción",
"machines": "máquinas",
"Machines": "Máquinas",
"Main": "Principal",
@ -721,11 +853,14 @@
"Manage saved snapshots of this page.": "Gestionar las instantáneas guardadas de esta página.",
"Manage slave devices (max 1).": "Gestionar dispositivos esclavos (máx. 1).",
"Manage users, global resource groups, and hierarchical permissions.": "Gestione usuarios, grupos de recursos globales y permisos jerárquicos.",
"Manage Variables": "Gestionar variables",
"Manage your account settings and preferences": "Gestionar la configuración y las preferencias de su cuenta",
"MANUAL": "MANUAL",
"MANUAL MULTI": "MANUAL MULTI",
"MANUAL_MULTI": "MANUAL_MULTI",
"Map capped at": "Mapa limitado a",
"Map Pick": "Mapa",
"Map Target Location": "Mapa Localización del objetivo",
"March Newsletter": "Boletín de marzo",
"Markdown": "Markdown",
"Mask / Filter": "Máscara / Filtro",
@ -744,11 +879,14 @@
"messages in context": "mensajes en contexto",
"meta": "meta",
"Meta": "Meta",
"Metal Work Machines": "Máquinas para trabajar el metal",
"Method": "Método",
"Mid": "Medio",
"Min": "Min",
"Min Density (p/km²)": "Densidad mínima (p/km²)",
"Min GHS Built Area": "Superficie mínima construida SGA",
"Min GHS Population": "Min GHS Población",
"Mine": "Mina",
"Minimum Height (px)": "Altura mínima (px)",
"Minimum height of the banner in pixels": "Altura mínima del banner en píxeles",
"MINLOAD": "CARGA MÍNIMA",
@ -760,6 +898,7 @@
"Move control point down": "Mover el punto de control hacia abajo",
"Move control point up": "Mover el punto de control hacia arriba",
"MULTI_TIMEOUT": "MULTI_TIMEOUT",
"My Awesome Post": "Mi impresionante post",
"My Files": "Mis archivos",
"My only": "Mi único",
"My Profile": "Mi perfil",
@ -773,7 +912,9 @@
"Network Settings": "Ajustes de red",
"New": "Nuevo",
"New Campaign": "Nueva campaña",
"New Category": "Nueva categoría",
"New Chat": "Nuevo chat",
"New filter": "Nuevo filtro",
"New Group Name": "Nombre del nuevo grupo",
"New group name…": "Nuevo nombre de grupo...",
"New Page": "Página nueva",
@ -786,17 +927,23 @@
"No coils data available. Try refreshing.": "No hay datos de bobinas disponibles. Prueba a actualizar.",
"No comments yet": "Aún no hay comentarios",
"No containers yet": "Aún no hay contenedores",
"No content yet": "Aún no hay contenido",
"No enabled profile": "Perfil no habilitado",
"No file browser context": "Sin contexto de explorador de archivos",
"No glossaries found.": "No se han encontrado glosarios.",
"No groups": "No hay grupos",
"No hidden fees at checkout": "Sin gastos ocultos al pagar",
"No image available to save": "No hay imagen disponible para guardar",
"No images added yet": "Aún no se han añadido imágenes",
"No images selected": "No hay imágenes seleccionadas",
"No Level": "Sin nivel",
"No matching locations found for": "No se han encontrado coincidencias para",
"No Operation": "Ninguna operación",
"No other versions available for this image.": "No hay otras versiones disponibles para esta imagen.",
"No Overlap (Dist)": "Sin solapamiento (Dist)",
"No page selected": "Ninguna página seleccionada",
"No pages available": "No hay páginas disponibles",
"No pages found": "No se han encontrado páginas",
"No picture selected": "No hay imagen seleccionada",
"No pictures available": "No hay fotos disponibles",
"No pictures yet": "Aún no hay fotos",
@ -826,6 +973,7 @@
"Offset": "Desplazamiento",
"OK": "OK",
"OL": "OL",
"On": "En",
"ON": "EN",
"ONLINE": "EN LÍNEA",
"Open": "Abrir",
@ -848,18 +996,23 @@
"Overall progress": "Progreso general",
"Overlay Darkness": "Oscuridad superpuesta",
"OVERLOAD": "SOBRECARGA",
"overrides grid run for Potential customer": "anula la ejecución de la red para el cliente Potencial",
"Overview": "Visión general",
"Own": "Propio",
"P Machines": "Máquinas P",
"Page": "Página",
"PAGE": "PÁGINA",
"Page Card": "Tarjeta de página",
"Page created! Redirecting you now...": "¡Página creada! Redirigiéndote ahora...",
"Page hidden": "Página oculta",
"Page JSON dumped to console and clipboard": "Página JSON volcada a consola y portapapeles",
"Page linked to this category": "Página vinculada a esta categoría",
"Page made private": "Página privada",
"Page made public": "Página hecha pública",
"Page saved": "Página guardada",
"Page Title": "Título de la página",
"Page Tools": "Herramientas de página",
"pages": "páginas",
"Pages": "Páginas",
"Parent": "Padres",
"Particular (sin intermediarios)": "Particular (sin intermediarios)",
@ -883,14 +1036,45 @@
"Photo Grid": "Rejilla fotográfica",
"Photo Grid Widget": "Widget de cuadrícula de fotos",
"Photos": "Fotos",
"Pick": "Elige",
"Pick a background video or image": "Elige un vídeo o una imagen de fondo",
"Pick Image": "Elegir imagen",
"Pick the starting point or administrative region for the map.": "Elija el punto de partida o la región administrativa para el mapa.",
"Picked Regions": "Regiones elegidas",
"Picture deleted": "Imagen eliminada",
"pictures": "imágenes",
"Pictures": "Fotos",
"PID Control": "Control PID",
"Pl Machines": "Máquinas Pl",
"Pla Machines": "Máquinas Pla",
"Placeholder Text": "Texto del marcador de posición",
"Places": "Lugares",
"Plain": "Llano",
"Plas Machines": "Máquinas Plas",
"Plast Machines": "Máquinas Plast",
"Plasti Machines": "Máquinas Plasti",
"Plastic Machines": "Máquinas de plástico",
"Plastic Machines": "Máquinas de plástico",
"Plastic P Machines": "Máquinas de plástico P",
"Plastic Pr Machines": "Máquinas Pr de plástico",
"Plastic Presses": "Prensas de plástico",
"Plastic Pro Machines": "Máquinas Plastic Pro",
"Plastic Proc Machines": "Máquinas de plástico Proc",
"Plastic Proce Machines": "Máquinas de procesamiento de plástico",
"Plastic Proces Machines": "Máquinas de procesamiento de plásticos",
"Plastic Process Machines": "Máquinas para plásticos",
"Plastic Processi Machines": "Máquinas para la transformación de plásticos",
"Plastic Processin Machines": "Máquinas para la transformación de plásticos",
"Plastic Processing Machines": "Máquinas de transformación de plásticos",
"Plastic Processing Machines ": "Máquinas de transformación de plásticos",
"Plastic Processing Machines (": "Máquinas de transformación de plásticos (",
"Plastic Processing Machines ( ": "Máquinas de transformación de plásticos (",
"Plastic Processing Machines ( N": "Máquinas de transformación de plásticos ( N",
"Plastic Processing Machines ( Ne": "Máquinas para la transformación de plásticos ( Ne",
"Plastic Processing Machines ( New": "Máquinas de transformación de plásticos ( Nuevo",
"Plastic Processing Machines ( New ": "Máquinas de transformación de plásticos ( Nuevo",
"Plastic Processing Machines ( New )": "Máquinas para la transformación de plásticos ( Nuevo )",
"Plastic Procu Machines": "Máquinas Procu de plástico",
"Play from start": "Jugar desde el principio",
"Playground": "Parque infantil",
"Please select a region using the Area Selector first to define the search bounds.": "Seleccione primero una región con el selector de área para definir los límites de la búsqueda.",
@ -898,26 +1082,42 @@
"Plunger": "Émbolo",
"PlungingAuto": "PlungingAuto",
"PlungingMan": "PlungingMan",
"Point Targeting": "Orientación por puntos",
"PolyMech - Cassandra": "PolyMech - Casandra",
"Polymech Controller": "Controlador Polymech",
"Polymer Processing Equipment & Engineering Solutions": "Equipos de procesamiento de polímeros y soluciones de ingeniería",
"Pop-out": "Desplegable",
"Pop:": "Pop:",
"Post Comment": "Publicar comentario",
"Post deleted": "Puesto eliminado",
"Post Description (Markdown)": "Descripción del mensaje (Markdown)",
"Post published successfully!": "¡Post publicado con éxito!",
"Post Settings & Visibility": "Configuración y visibilidad de las entradas",
"Post Title": "Título del puesto",
"Post updated successfully!": "¡Post actualizado con éxito!",
"Post Wizard": "Post Wizard",
"Poster Image": "Imagen del cartel",
"Poster Mode": "Modo cartel",
"PostFlow": "PostFlow",
"posts": "puestos",
"Posts": "Puestos",
"POSTS": "PUESTOS",
"Potential customer": "Cliente potencial",
"Precision marker active": "Marcador de precisión activo",
"Precision Unit Alpha": "Unidad de precisión Alfa",
"Preferred": "Preferido",
"Press": "Pulse",
"Press Cylinder": "Cilindro de prensa",
"Press Cylinder Controls": "Controles del cilindro de prensado",
"Presscylinder": "Cilindro a presión",
"Preview": "Vista previa",
"Preview & Simulate": "Previsualizar y simular",
"Price": "Precio",
"Price range": "Precios",
"Print Debug Info to Console": "Imprimir información de depuración en la consola",
"Priv": "Priv",
"Private": "Privado",
"Processing link...": "Enlace de procesamiento...",
"Product Settings": "Ajustes del producto",
"Products": "Productos",
"Products & Services": "Productos y servicios",
@ -936,12 +1136,19 @@
"Properties:": "Propiedades:",
"Provider & Model": "Proveedor y modelo",
"Provider ID": "ID de proveedor",
"pts": "pts",
"Pub": "Pub",
"Public": "Público",
"Publish": "Publique",
"Publish as Picture": "Publicar como imagen",
"Publishing...": "Publicar...",
"Purchases": "Compras",
"PV": "FV",
"Query": "Consulta",
"Quick build recipes": "Recetas de construcción rápida",
"Quick Publish": "Publicación rápida",
"Quick Publish (Default)": "Publicación rápida (por defecto)",
"Quick Publish as Post (Default)": "Publicación rápida como entrada (por defecto)",
"Rating": "Clasificación",
"Raw Data": "Datos brutos",
"Ready to Launch": "Listo para el lanzamiento",
@ -956,10 +1163,12 @@
"Reference Images": "Imágenes de referencia",
"References, example projects, and offtheshelf parts (Amazon, McMasterCarr, and others)": "Referencias, proyectos de ejemplo y piezas estándar (Amazon, McMaster-Carr y otros)",
"Refresh Rate": "Frecuencia de actualización",
"Region": "Región",
"Regions": "Regiones",
"Registers": "Registros",
"Related documentation": "Documentación relacionada",
"REMOTE": "REMOTO",
"Remove": "Eliminar",
"Remove all": "Eliminar todo",
"Remove all control points from this plot": "Eliminar todos los puntos de control de este gráfico",
"Remove button": "Quitar botón",
@ -977,7 +1186,9 @@
"resize — cover (crop), contain (letterbox), rotate / flip": "redimensionar - cubrir (recortar), contener (letterbox), rotar / voltear",
"resize — fit inside a box (default), write WebP / AVIF by extension": "redimensionar - encajar dentro de una caja (por defecto), escribir WebP / AVIF por extensión",
"resize — square images (1:1)": "redimensionar - imágenes cuadradas (1:1)",
"Resolution": "Resolución",
"Resolution (km)": "Resolución (km)",
"Resolving Location Data": "Resolución de datos de localización",
"Resolving location...": "Resolver la ubicación...",
"Resources": "Recursos",
"Restart": "Reinicie",
@ -985,15 +1196,20 @@
"Restart Server": "Reiniciar el servidor",
"Restore": "Restaurar",
"results": "resultados",
"Retry Job": "Reintentar trabajo",
"Retrying...": "Reintentando...",
"rev": "rev",
"reviews": "reseñas",
"revs": "revoluciones",
"Root Category": "Categoría Raíz",
"run": "ejecute",
"Run Action": "Ejecutar acción",
"Run AI filters (selection or all)": "Ejecutar filtros AI (selección o todos)",
"Run on all rows": "Ejecutar en todas las filas",
"Run this control point action now": "Ejecute ahora esta acción de punto de control",
"S": "S",
"sales@acme.com": "sales@acme.com",
"Same-day dispatch on orders before 2 PM": "Envío en el mismo día para pedidos realizados antes de las 14.00 horas",
"Samplesignalplot 0": "Gráfico de señal de muestreo 0",
"Save": "Guardar",
"Save All Settings": "Guardar todos los ajustes",
@ -1001,15 +1217,19 @@
"Save API Keys": "Guardar claves API",
"Save As": "Guardar como",
"Save as file": "Guardar como archivo",
"Save as Version": "Guardar como versión",
"Save as Widget": "Guardar como widget",
"Save Changes": "Guardar cambios",
"Save current as template": "Guardar actual como plantilla",
"Save filter definitions": "Guardar definiciones de filtros",
"Save Settings": "Guardar ajustes",
"Save Signal Plot": "Guardar trazado de señal",
"Save STA Settings": "Guardar ajustes STA",
"Save to DB": "Guardar en BD",
"Save to DeepL": "Guardar en DeepL",
"Save Version": "Guardar versión",
"Saved": "Guardado",
"Saved per search in this browser": "Guardado por búsqueda en este navegador",
"Saved to file browser": "Guardado en el explorador de archivos",
"Saving...": "Ahorrar...",
"Saving…": "Ahorrar...",
@ -1027,6 +1247,7 @@
"Search Configuration & Metadata": "Configuración de búsqueda y metadatos",
"Search countries, regions, cities to add...": "Buscar países, regiones, ciudades para añadir...",
"Search Files (Ctrl+F / F3)": "Buscar archivos (Ctrl+F / F3)",
"Search for a city, region, or address...": "Buscar una ciudad, región o dirección...",
"Search groups…": "Buscar grupos...",
"Search Limit per grid cell (Max 100)": "Límite de búsqueda por celda de la cuadrícula (máx. 100)",
"Search page or heading...": "Buscar página o título...",
@ -1038,6 +1259,8 @@
"Search Tools": "Herramientas de búsqueda",
"Search...": "Buscar...",
"Search…": "Buscar...",
"Searches": "Búsquedas",
"Searching for locations...": "Buscando ubicaciones...",
"secret": "secreto",
"Secret": "Secreto",
"Section heading displayed above the feed": "Título de la sección que aparece sobre el feed",
@ -1054,6 +1277,7 @@
"Select a destination profile. The content of \"{profileName}\" will overwrite the selected profile. This action cannot be undone.": "Seleccione un perfil de destino. El contenido de \"{nombredelperfil}\" sobrescribirá el perfil seleccionado. Esta acción no se puede deshacer.",
"Select a page…": "Seleccione una página...",
"Select a plot to overwrite": "Seleccione una parcela para sobrescribir",
"Select a Post to Append To": "Seleccione una entrada a la que anexar",
"Select a profile to overwrite": "Seleccione un perfil para sobrescribir",
"Select a register or coil address": "Seleccione una dirección de registro o de bobina",
"Select a signal plot to associate and edit": "Seleccione un trazado de señal para asociar y editar",
@ -1063,10 +1287,14 @@
"Select a video-intern picture to use as background": "Seleccione una imagen de vídeo interna para utilizarla como fondo",
"Select category...": "Seleccionar categoría...",
"Select File & Import": "Seleccione Archivo e Importar",
"Select Files": "Seleccionar archivos",
"Select Known Coil...": "Seleccionar bobina conocida...",
"Select Location": "Seleccione el lugar",
"Select one or more countries, regions, or cities to perform the grid search.": "Seleccione uno o varios países, regiones o ciudades para realizar la búsqueda en la cuadrícula.",
"Select Page": "Seleccionar página",
"Select Picture": "Seleccionar imagen",
"Select source...": "Seleccionar fuente...",
"Select the AI model for image generation": "Seleccionar el modelo de IA para la generación de imágenes",
"Select type": "Seleccione el tipo",
"Selected": "Selección",
"Selected child profiles will start, stop, pause, and resume with this parent profile.": "Los perfiles hijos seleccionados se iniciarán, detendrán, pausarán y reanudarán con este perfil padre.",
@ -1095,10 +1323,12 @@
"SerpAPI Key": "Clave SerpAPI",
"serve — HTTP REST": "servir - HTTP REST",
"Server Management": "Gestión de servidores",
"Services": "Servicios",
"Sessions": "Sesiones",
"Set All": "Fijar todo",
"Set All SP": "Fijar todo SP",
"Set as Default": "Fijar por defecto",
"Set as Preferred Version": "Establecer como versión preferida",
"Set group…": "Establecer grupo...",
"Set status…": "Establecer estado...",
"Settings": "Ajustes",
@ -1113,12 +1343,17 @@
"Sheetpr": "Sheetpr",
"Sheetpre": "Sheetpre",
"Sheetpres": "Sheetpres",
"sheetpress": "hoja de prensa",
"Sheetpress": "Prensa",
"Sheetpress — Perfect for Fablab Workshops": "Sheetpress - Perfecto para talleres Fablab",
"Shipping Addresses": "Direcciones de envío",
"Shipping Information": "Información de envío",
"Shipping Rates": "Tarifas de envío",
"Shortest": "El más corto",
"Shortplot 70s": "Trama corta 70s",
"Show Actions": "Mostrar acciones",
"Show Author": "Mostrar autor",
"Show author avatar and name": "Mostrar avatar y nombre del autor",
"Show author avatar and name on feed cards": "Mostrar el avatar y el nombre del autor en las tarjetas de alimentación",
"Show Categories": "Mostrar categorías",
"Show Categories Sidebar": "Mostrar la barra lateral de categorías",
@ -1126,24 +1361,37 @@
"Show Date": "Fecha del espectáculo",
"Show Description": "Descripción del espectáculo",
"Show Footer": "Mostrar pie de página",
"Show footer with likes, comments, and actions": "Mostrar pie de página con \"Me gusta\", comentarios y acciones",
"Show GADM Regions": "Mostrar regiones GADM",
"Show Global Footer": "Mostrar pie de página global",
"Show grid search simulator and regional playback tools.": "Mostrar simulador de búsqueda de cuadrículas y herramientas de reproducción regional.",
"Show Grid Simulator": "Mostrar simulador de rejilla",
"Show grid/large/list view toggle buttons": "Mostrar botones de alternancia de vista de cuadrícula/grande/lista",
"Show Header": "Mostrar cabecera",
"Show header with author information": "Mostrar cabecera con información del autor",
"Show Last Updated": "Mostrar última actualización",
"Show Layout Toggles": "Mostrar interruptores de diseño",
"Show Legend": "Mostrar leyenda",
"Show like and comment buttons": "Mostrar botones de me gusta y comentarios",
"Show like, comment, download buttons": "Mostrar botones de \"Me gusta\", \"Comentar\" y \"Descargar",
"Show likes and comments on feed cards": "Mostrar \"me gusta\" y comentarios en las tarjetas de alimentación",
"Show Parent Path": "Mostrar ruta padre",
"Show PV": "Mostrar PV",
"Show Search Results": "Mostrar resultados de búsqueda",
"Show Social": "Show Social",
"Show Sort Bar": "Mostrar barra de clasificación",
"Show SP": "Mostrar SP",
"Show subcategories": "Mostrar subcategorías",
"Show summary statistics for the visible map area.": "Mostrar estadísticas resumidas del área visible del mapa.",
"Show Table of Contents": "Mostrar índice",
"Show the category tree sidebar on desktop": "Mostrar la barra lateral del árbol de categorías en el escritorio",
"Show the site footer below the feed": "Mostrar el pie de página del sitio debajo del feed",
"Show the sort and category toggle bar": "Mostrar la barra de clasificación y categorías",
"Show Title": "Mostrar título",
"Show tool for measuring distances on the map.": "Mostrar herramienta para medir distancias en el mapa.",
"Showing all users": "Mostrar todos los usuarios",
"Showing my pages": "Mostrar mis páginas",
"shredders": "trituradoras",
"Shredders": "Trituradoras",
"Sign in": "Iniciar sesión",
"Sign In": "Iniciar sesión",
@ -1168,11 +1416,13 @@
"Slot": "Ranura",
"Slot:": "Ranura:",
"Slug": "Babosa",
"Smart & Optimized": "Inteligente y optimizado",
"SMTP Servers": "Servidores SMTP",
"Snake": "Serpiente",
"Snapshot": "Instantánea",
"Snippets": "Recortes",
"Social": "Social",
"software": "software",
"Software": "Software",
"Sort By": "Ordenar por",
"Sort: name (asc)": "Ordenar: nombre (ascendente)",
@ -1184,6 +1434,7 @@
"Specs Table": "Tabla de especificaciones",
"Spiral In": "En espiral",
"Spiral Out": "Salida en espiral",
"Split": "Dividir",
"Square Geometric Grid": "Cuadrícula geométrica cuadrada",
"STA Gateway": "Pasarela STA",
"STA IP Address": "Dirección IP STA",
@ -1193,6 +1444,7 @@
"STA SSID": "STA SSID",
"STA Subnet Mask": "Máscara de subred STA",
"STALLED": "BLOQUEADO",
"Standard": "Estándar",
"Start": "Inicio",
"Start Import": "Iniciar importación",
"Start Index": "Inicio Índice",
@ -1216,14 +1468,17 @@
"Structure": "Estructura",
"Structure and alias types enabled for this product. You can also change them under Product Settings.": "Tipos de estructura y alias habilitados para este producto. También puede cambiarlos en Configuración del producto.",
"Structured fields from the types selected above (saved with this form).": "Campos estructurados de los tipos seleccionados anteriormente (guardados con este formulario).",
"Style Presets": "Preajustes de estilo",
"Subject": "Asunto",
"Subs": "Suplentes",
"Summary": "Resumen",
"Support Chat": "Chat de asistencia",
"Support Chat (Instant Quotes)": "Chat de asistencia (presupuestos instantáneos)",
"Support Chat Widget": "Widget de chat de asistencia",
"Switch mount": "Montaje del interruptor",
"Switch to edit mode to add containers": "Cambiar al modo de edición para añadir contenedores",
"Switch to edit mode to add widgets": "Cambiar al modo de edición para añadir widgets",
"Switched to post editing mode": "Cambio al modo de postedición",
"System": "Sistema",
"System Calls": "Llamadas al sistema",
"System Control": "Control del sistema",
@ -1247,7 +1502,9 @@
"terms": "términos",
"terms to DeepL + DB": "términos a DeepL + DB",
"Text Block": "Bloque de texto",
"Text shown when content is empty": "Texto mostrado cuando el contenido está vacío",
"The C++ Batch Generator Pipeline": "El proceso del generador de lotes de C",
"The marker can be positioned anywhere on the global map. Coordinates update in real-time as you drag.": "El marcador puede situarse en cualquier lugar del mapa global. Las coordenadas se actualizan en tiempo real a medida que se arrastra.",
"These types drive the \"Type data\" section when editing this product.": "Estos tipos dirigen la sección \"Datos de tipo\" al editar este producto.",
"This action cannot be undone and will disconnect any associated ACLs.": "Esta acción no se puede deshacer y desconectará cualquier ACL asociada.",
"This hostname is used for both STA and AP modes. Changes here will be saved with either form.": "Este nombre de host se utiliza tanto para los modos STA como AP. Los cambios aquí se guardarán con cualquiera de los dos modos.",
@ -1259,6 +1516,7 @@
"Timeline:": "Calendario:",
"Tiras para arrancar (opcional)": "Tiras para arrancar (opcional)",
"Title (Optional)": "Título (opcional)",
"Title for Publishing (Optional)": "Título para la publicación (opcional)",
"Toggle the display of the author name.": "Conmutar la visualización del nombre del autor.",
"Toggle the display of the category paths.": "Conmutar la visualización de las rutas de categorías.",
"Toggle the display of the global app footer site-wide.": "Activa la visualización del pie de página global de la aplicación en todo el sitio.",
@ -1287,6 +1545,7 @@
"Type data": "Tipo de datos",
"Type data (per type id)": "Datos de tipo (por id de tipo)",
"Type Properties": "Propiedades de tipo",
"Type to Search Global Targets": "Tipo para buscar objetivos globales",
"Type updated": "Tipo actualizado",
"Type:": "Tipo:",
"Types": "Tipos",
@ -1297,10 +1556,13 @@
"Unlisted": "Sin clasificar",
"unsubscribed": "darse de baja",
"Update": "Actualización",
"Update Post": "Puesto de actualización",
"Update Profile": "Actualizar perfil",
"Updated i18n files": "Archivos i18n actualizados",
"Updating...": "Actualizando...",
"Upload": "Cargar",
"Upload All JSON": "Cargar todo el JSON",
"Upload as Files": "Cargar como archivos",
"Upload as Picture": "Cargar como imagen",
"Upload Images": "Cargar imágenes",
"Upload images or select from gallery": "Sube imágenes o selecciónalas de la galería",
@ -1308,7 +1570,10 @@
"Upload Plot": "Cargar parcela",
"Upload Video": "Cargar vídeo",
"Upload videos to share with the community. Automatic processing and optimization.": "Sube vídeos para compartirlos con la comunidad. Procesamiento y optimización automáticos.",
"Use Google Image Search for visual context.": "Utiliza la búsqueda de imágenes de Google para obtener un contexto visual.",
"Use Google Search to improve image relevance and accuracy.": "Utiliza la Búsqueda de Google para mejorar la relevancia y precisión de las imágenes.",
"Use my current location": "Utilizar mi ubicación actual",
"Use Selection": "Selección de uso",
"User Defined": "Definido por el usuario",
"User Filter": "Filtro de usuario",
"User not found": "Usuario no encontrado",
@ -1335,8 +1600,10 @@
"Visit": "Visite",
"Visit Website": "Visitar el sitio web",
"Visual": "Visual",
"Voice": "Voz",
"Voice + AI": "Voz + IA",
"Watched Items": "Artículos vigilados",
"We ship worldwide": "Enviamos a todo el mundo",
"Web Search": "Búsqueda en la Web",
"Website": "Página web",
"Welcome": "Bienvenido",
@ -1346,6 +1613,7 @@
"What is IPC for?": "¿Para qué sirve la CIP?",
"What is pm-image?": "¿Qué es pm-image?",
"What would you like to create?": "¿Qué le gustaría crear?",
"When on, saved type excludes apply as DataGrid filters — remove a rule to show that type. Import to contacts uses the rows you see in List view.": "Cuando está activada, las exclusiones de tipos guardados se aplican como filtros de DataGrid: elimine una regla para mostrar ese tipo. La importación a contactos utiliza las filas que se ven en la vista Lista.",
"When Slave Mode is enabled, all Omron controllers will be disabled for processing.": "Cuando se activa el modo esclavo, todos los controladores Omron se desactivarán para el procesamiento.",
"Where do you want to search?": "¿Dónde quiere buscar?",
"Where is the full API reference?": "¿Dónde está la referencia completa de la API?",
@ -1361,6 +1629,7 @@
"Window (min)": "Ventana (min)",
"Window Offset": "Desplazamiento de la ventana",
"Wood Working Machines": "Máquinas para trabajar la madera",
"Workflows": "Flujos de trabajo",
"Write Coil": "Bobina de escritura",
"Write GPIO": "Escribir GPIO",
"Write Holding Register": "Registro de retención de escritura",

View File

@ -459,6 +459,8 @@ export function registerAllWidgets() {
showFooter: true,
showAuthor: true,
showActions: true,
showTitle: true,
showDescription: false,
contentDisplay: 'below',
variables: {}
},
@ -493,6 +495,18 @@ export function registerAllWidgets() {
description: 'Show like and comment buttons',
default: true
},
showTitle: {
type: 'boolean',
label: 'Show Title',
description: 'Display the page title on the card',
default: true
},
showDescription: {
type: 'boolean',
label: 'Show Description',
description: 'Display the page description on the card',
default: false
},
contentDisplay: {
type: 'select',
label: 'Content Display',

View File

@ -30,7 +30,8 @@ const TARGET_LANGS = [
...TargetLanguageCodeSchema.options[1].options,
].sort();
const TRANSLATABLE_WIDGET_IDS = new Set(['markdown-text', 'html-block']);
const TRANSLATABLE_WIDGET_IDS = new Set(['markdown-text', 'html-block', 'category-feed']);
const TRANSLATABLE_PROPS = ['content', 'heading'];
interface TranslatableItem {
key: string;
@ -93,18 +94,21 @@ export const BatchPageTranslateDialog: React.FC<BatchPageTranslateDialogProps> =
if (pageLayout) {
iterateWidgets(pageLayout as any, (w: any) => {
if (TRANSLATABLE_WIDGET_IDS.has(w.widgetId)) {
const content = w.props?.content;
if (content && typeof content === 'string' && content.trim()) {
const def = widgetRegistry.get(w.widgetId);
const typeName = def?.metadata.name || w.widgetId;
if (!w.id || !w.props) return;
const def = widgetRegistry.get(w.widgetId);
const typeName = def?.metadata.name || w.widgetId;
console.log(w.widgetId, typeName);
for (const prop of TRANSLATABLE_PROPS) {
if (prop === 'content' && !TRANSLATABLE_WIDGET_IDS.has(w.widgetId)) continue;
const val = w.props[prop];
if (typeof val === 'string' && val.trim()) {
items.push({
key: `${w.id}:content`,
key: `${w.id}:${prop}`,
widgetId: w.id,
widgetTypeId: w.widgetId,
propPath: 'content',
label: `${typeName} (${w.id.slice(0, 8)}…)`,
sourceText: content,
propPath: prop,
label: `${typeName} ${prop} (${w.id.slice(0, 8)}…)`,
sourceText: val,
});
}
}

View File

@ -71,7 +71,7 @@ const PageCard: React.FC<PageCardProps> = ({
/** When false/undefined, grid uses square crop; when true, allow flexible height below image. */
const gridTitleSlot = !!(showTitle ?? preset?.showTitle);
const gridTitleOn = (showTitle ?? preset?.showTitle) !== false;
const gridDescriptionOn = (showDescription ?? preset?.showDescription) !== false;
const gridDescriptionOn = !!(showDescription ?? preset?.showDescription);
const handleLike = (e: React.MouseEvent) => {
e.stopPropagation();
@ -136,7 +136,7 @@ const PageCard: React.FC<PageCardProps> = ({
{(showTitle ?? preset?.showTitle) !== false && (
<div className="font-semibold text-sm">{title}</div>
)}
{(showDescription ?? preset?.showDescription) !== false && description && (
{!!(showDescription ?? preset?.showDescription) && description && (
<div className="text-sm text-foreground/90 line-clamp-3">
<MarkdownRenderer content={description} className="prose-sm dark:prose-invert" />
</div>

View File

@ -14,6 +14,8 @@ const PageCardWidgetEdit: React.FC<PageCardWidgetProps> = ({
showFooter = true,
showAuthor = true,
showActions = true,
showTitle = true,
showDescription = false,
contentDisplay = 'below',
onPropsChange
}) => {
@ -86,7 +88,7 @@ const PageCardWidgetEdit: React.FC<PageCardWidgetProps> = ({
showHeader={showHeader}
showContent={showFooter}
created_at={page.created_at}
preset={{ showAuthor, showActions }}
preset={{ showTitle, showDescription, showAuthor, showActions }}
/>
)}
<div className="absolute top-2 right-2 z-10">

View File

@ -10,6 +10,8 @@ export interface PageCardWidgetProps {
showFooter?: boolean;
showAuthor?: boolean;
showActions?: boolean;
showTitle?: boolean;
showDescription?: boolean;
contentDisplay?: 'below' | 'overlay' | 'overlay-always';
widgetInstanceId?: string;
onPropsChange?: (props: Record<string, any>) => void;
@ -62,7 +64,7 @@ export function usePageCardData(propPageId: string | null) {
setPage({
id: pageData.id,
title: pageData.title,
description: (pageData.meta as any)?.description || null,
description: pageData.description || (pageData.meta as any)?.description || null,
slug: pageData.slug,
user_id: pageData.owner,
likes_count: 0,
@ -90,6 +92,8 @@ const PageCardWidgetView: React.FC<PageCardWidgetProps> = ({
showFooter = true,
showAuthor = true,
showActions = true,
showTitle = true,
showDescription = false,
contentDisplay = 'below',
className,
}) => {
@ -135,7 +139,7 @@ const PageCardWidgetView: React.FC<PageCardWidgetProps> = ({
showHeader={showHeader}
showContent={showFooter}
created_at={page.created_at}
preset={{ showAuthor, showActions }}
preset={{ showTitle, showDescription, showAuthor, showActions }}
className={className}
/>
</div>

View File

@ -4,9 +4,8 @@ import MediaCard from "@/components/MediaCard";
import { normalizeMediaType, isVideoType } from "@/lib/mediaRegistry";
import { PHOTO_GRID_THUMBNAIL_WIDTH, PHOTO_GRID_IMAGE_FORMAT } from "@/constants";
import { Button } from "@/components/ui/button";
import { LayoutGrid, Grid, ArrowLeft } from 'lucide-react';
import { Link } from "react-router-dom";
import { LayoutGrid } from 'lucide-react';
import { CompactPostHeader } from './components/CompactPostHeader';
export const ThumbsRenderer: React.FC<PostRendererProps> = (props) => {
const {
@ -15,47 +14,43 @@ export const ThumbsRenderer: React.FC<PostRendererProps> = (props) => {
onViewModeChange,
onExportMarkdown,
post,
authorProfile
authorProfile,
isEditMode,
localPost,
setLocalPost,
mediaItem,
isOwner,
onSaveChanges,
onEditModeToggle,
onEditPost,
onDeletePicture,
onDeletePost,
onCategoryManagerOpen,
localMediaItems
} = props;
// Use a similar grid layout as PhotoGrid
return (
<div className="py-4 space-y-4">
{/* Header / Controls */}
<div className="flex items-center justify-between bg-card p-3 rounded-lg border shadow-sm">
<div className="flex items-center space-x-3">
<Button variant="ghost" size="sm" onClick={() => window.history.back()}>
<ArrowLeft className="h-5 w-5 mr-1" />
Back
</Button>
<h1 className="text-lg font-semibold truncate max-w-[200px] md:max-w-md">
{post?.title || 'Gallery'}
</h1>
</div>
<div className="flex items-center gap-1">
<div className="flex items-center bg-muted/50 rounded-lg p-1 mr-2 border">
<Button
variant="secondary"
size="sm"
className="h-8 w-8 p-0 text-muted-foreground"
onClick={() => onViewModeChange('thumbs')}
title="Thumbs View"
>
<Grid className="h-4 w-4" />
</Button>
<Button
variant="ghost"
size="sm"
className="h-8 w-8 p-0"
onClick={() => onViewModeChange('compact')}
title="Compact View"
>
<LayoutGrid className="h-4 w-4" />
</Button>
</div>
</div>
</div>
<div className="space-y-4">
<CompactPostHeader
isEditMode={!!isEditMode}
post={post}
localPost={localPost}
setLocalPost={setLocalPost!}
mediaItem={mediaItem}
authorProfile={authorProfile!}
isOwner={!!isOwner}
embedded={props.embedded}
onViewModeChange={onViewModeChange!}
onExportMarkdown={onExportMarkdown!}
onSaveChanges={onSaveChanges!}
onEditModeToggle={onEditModeToggle!}
onEditPost={onEditPost!}
onDeletePicture={onDeletePicture!}
onDeletePost={onDeletePost!}
onCategoryManagerOpen={onCategoryManagerOpen}
mediaItems={mediaItems}
localMediaItems={localMediaItems}
/>
{/* Grid Content */}
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4 gap-4">

View File

@ -117,43 +117,51 @@ export const CompactPostHeader: React.FC<CompactPostHeaderProps> = ({
</div>
) : (
<div className="p-3 border-b">
{/* Full-width text, then toolbar on its own row — avoids squeezing description next to Export / wide controls */}
<div className={`flex flex-col gap-3 ${embedded ? 'flex-col-reverse' : ''}`}>
{/* Title, description, categories — always full width of the column */}
<div className="flex flex-col-reverse gap-3">
{/* Title + Description */}
<div className="min-w-0 w-full">
{post && (post.description || (post.title && post.title !== mediaItem?.title)) && (
<>
{post.title && post.title !== mediaItem?.title && (<h1 className="text-lg font-bold mb-1">{post.title}</h1>)}
{post.description && <MarkdownRenderer content={post.description} className="prose-sm text-sm text-foreground/90 mb-2" />}
{/* Category Breadcrumbs */}
{(() => {
const displayPaths = (post as any).category_paths || [];
if (displayPaths.length === 0) return null;
return (
<div className="flex flex-col gap-1 mt-2">
{displayPaths.map((path: any[], pathIdx: number) => (
<div key={pathIdx} className="flex items-center gap-2 text-sm text-muted-foreground">
<FolderTree className="h-4 w-4 shrink-0" />
{path.map((cat: any, idx: number) => (
<span key={cat.id} className="flex items-center">
{idx > 0 && <span className="mx-1 text-muted-foreground/50">/</span>}
<a href={`/categories/${cat.slug}`} className="hover:text-primary transition-colors hover:underline">
{cat.name}
</a>
</span>
))}
</div>
))}
</div>
);
})()}
</>
{post && post.title && post.title !== mediaItem?.title && (
<h1 className="text-lg font-bold mb-1">{post.title}</h1>
)}
{post?.description && <MarkdownRenderer content={post.description} className="prose-sm text-sm text-foreground/90 mb-2" />}
</div>
{/* Actions row — does not share a horizontal flex row with markdown */}
{/* Category Breadcrumbs */}
{(() => {
const displayPaths = (post as any)?.category_paths || [];
if (displayPaths.length === 0) return null;
return (
<div className="flex flex-col gap-1">
{displayPaths.map((path: any[], pathIdx: number) => (
<div key={pathIdx} className="flex items-center gap-2 text-sm text-muted-foreground">
<FolderTree className="h-4 w-4 shrink-0" />
{path.map((cat: any, idx: number) => (
<span key={cat.id} className="flex items-center">
{idx > 0 && <span className="mx-1 text-muted-foreground/50">/</span>}
<a href={`/categories/${cat.slug}`} className="hover:text-primary transition-colors hover:underline">
{cat.name}
</a>
</span>
))}
</div>
))}
</div>
);
})()}
{/* Author / Date */}
<div>
<UserAvatarBlock
userId={mediaItem.user_id}
avatarUrl={authorProfile?.avatar_url}
displayName={authorProfile?.display_name}
createdAt={mediaItem.created_at}
className="w-8 h-8"
/>
</div>
{/* Actions toolbar */}
<div className="flex items-center justify-end gap-1 flex-wrap shrink-0">
<div className="flex items-center bg-muted/50 rounded-lg p-1 mr-1 border">
<Button
@ -176,7 +184,6 @@ export const CompactPostHeader: React.FC<CompactPostHeaderProps> = ({
</Button>
</div>
{/* Open Standalone - break out of embedded view */}
{embedded && post?.id && (
<Button
variant="ghost"
@ -220,17 +227,6 @@ export const CompactPostHeader: React.FC<CompactPostHeaderProps> = ({
</div>
</div>
)}
{/* Author / Date Row */}
<div className="px-3 py-2 border-b">
<UserAvatarBlock
userId={mediaItem.user_id}
avatarUrl={authorProfile?.avatar_url}
displayName={authorProfile?.display_name}
createdAt={mediaItem.created_at}
className="w-8 h-8"
/>
</div>
</>
);
};