feat(mcp): tools de idiomas y traducciones
- Nueva categoria tools/languages: list_web_languages, get_record_translations y set_record_translations (registros, config, textos_generales y vars de modulo via builder_custom). - Param lang opcional en list_table_records y get_record (options.translates de CocoDB). - Docs actualizados (03/04/06/09/11b + ACAI_ENDPOINTS) con el modelo de cms_traducciones y los workflows de traduccion.
This commit is contained in:
@@ -203,6 +203,16 @@ Acceso en Twig:
|
||||
|
||||
Las variables son **propiedades del objeto iterado**, no variables sueltas.
|
||||
|
||||
## Traducir las variables de un módulo
|
||||
|
||||
Los valores textuales de las variables de un módulo (títulos, descripciones, wysiwyg, etc.) NO se guardan en la fila de la página, sino en la tabla `builder_custom`. Por eso una traducción de módulo apunta siempre a `builder_custom`, no a `apartados` ni a la tabla de la página.
|
||||
|
||||
Para traducir las vars de una instancia de módulo:
|
||||
1. `get_module_config_vars({ tableName, recordNum, sectionId })` devuelve `varsMeta`: por cada variable, su ubicación física `{ fieldName, recordNum }` en `builder_custom` (y por cada item en las vars multi).
|
||||
2. `set_record_translations({ tableName: "builder_custom", recordNum: <de varsMeta>, prefix, fields: { <fieldName de varsMeta>: "texto traducido" } })`.
|
||||
|
||||
El nombre humano de la variable (p.ej. `titulo`) NO es el nombre de columna real (p.ej. `title2`): usa siempre el `fieldName` que da `varsMeta`. Ver el workflow completo en `09-mcp-tools-reference.md`.
|
||||
|
||||
## Layout global vs módulos
|
||||
|
||||
`header`, `footer`, `style` global y `javascript` global NO son módulos normales. Viven en `cms/lib/plugins/builder_saas/layout.json` y se editan con tools dedicadas (`get_layout_field` / `set_layout_field`). Ver `08-layout-and-libraries.md`.
|
||||
|
||||
@@ -152,6 +152,20 @@ create_or_update_record:
|
||||
metatag_descripcion: "Descubre nuestros servicios…"
|
||||
```
|
||||
|
||||
## Traducciones (multiidioma)
|
||||
|
||||
En sitios multiidioma las traducciones NO viven en la fila del registro: se guardan en la tabla central `cms_traducciones`, indexadas por `(prefix = código de idioma, tableName sin cms_, fieldName, recordNum)`. El valor (`fieldValue`) se almacena en Base64, pero es transparente: las tools y el motor codifican/decodifican por ti, tú siempre trabajas con texto plano.
|
||||
|
||||
- El idioma base usa el prefix `www` y sus URLs no llevan prefijo. Los idiomas secundarios (p.ej. `en`) sirven bajo `/en/...`. Consulta los activos con `list_web_languages`.
|
||||
- Solo se traducen los tipos de campo traducibles: `textfield`, `textbox`, `wysiwyg`, `codigo` y `multitext` (este último se traduce como el JSON serializado completo en una sola fila).
|
||||
- Un valor vacío (`''`) en `set_record_translations` **borra** la traducción y el runtime cae al idioma base.
|
||||
- Para leer un registro ya traducido, pasa `lang: "<prefix>"` a `get_record` o `list_table_records`.
|
||||
- El campo `identificador` de `textos_generales` (los literales del filtro Twig `| translate`) se traduce por su campo `texto`.
|
||||
|
||||
### Regla dura: nunca traduzcas `enlace`
|
||||
|
||||
El campo `enlace` NUNCA se traduce a mano — lo mantiene el motor CocoEnlace. La action PHP rechaza cualquier intento de traducir `enlace`. No lo incluyas en `set_record_translations`.
|
||||
|
||||
## Patrón canónico — Detalle de registro
|
||||
|
||||
Para cualquier tabla con campo `enlace` (productos, noticias, vacantes, servicios), **el detalle se resuelve por convención** vía sección general `custom-{tableName}`. Ver `03-modules-and-sections.md` para detalles.
|
||||
|
||||
@@ -149,7 +149,7 @@ $datos = CmsApi::get("productos", "", "", "", [
|
||||
| `uploads` | bool | `true` | Incluir datos de upload fields |
|
||||
| `relations` | bool/array | `true` | Resolver foreign keys. Array para limitar: `['categoria']` |
|
||||
| `relationsDepth` | int | 2 | Profundidad de relaciones anidadas |
|
||||
| `translates` | string | idioma actual | Código de idioma para `| translate` |
|
||||
| `translates` | string/bool | idioma actual | Código de idioma (prefix, p.ej. `'en'`) para devolver los campos ya traducidos desde `cms_traducciones`. `true` usa el idioma activo de la request |
|
||||
| `groupBy` | string | null | Cláusula GROUP BY |
|
||||
| `aggregates` | array | `[]` | Funciones de agregación |
|
||||
| `onlyFields` | array | null | Seleccionar solo ciertos campos |
|
||||
@@ -157,6 +157,8 @@ $datos = CmsApi::get("productos", "", "", "", [
|
||||
| `redis` | bool | null | Forzar cache Redis |
|
||||
| `redis_expire` | int | 60 | TTL del cache (segundos) |
|
||||
|
||||
**Idioma en lectura**: pasar `options['translates'] => '<prefix>'` hace que `CmsApi::get`/`cmsApi` devuelva los valores traducidos de los campos traducibles. Las tools MCP `list_table_records` y `get_record` exponen esto con su parámetro `lang` (que se traduce a `options.translates`). A nivel HTTP, `cms_api` v3 también fuerza el idioma con el header `X-ACAI-ACCEPT-LANGUAGE: <prefix>`, que tiene el mismo efecto que `translates` para toda la request. Ver `09-mcp-tools-reference.md` (sección Idiomas y traducciones) para el flujo de escritura con `set_record_translations`.
|
||||
|
||||
### Insert — `CmsApi::insert()`
|
||||
|
||||
```php
|
||||
|
||||
@@ -153,6 +153,20 @@ Tools del MCP `playwright`. El browser headless es del agente — el usuario NO
|
||||
|------|--------|
|
||||
| `refresh_acai_token` | Renueva el JWT cuando expira (errores 403) |
|
||||
|
||||
### Idiomas y traducciones
|
||||
|
||||
Las webs multiidioma guardan las traducciones en la tabla central `cms_traducciones`. Ver `04-pages-and-records.md` y `11b-rules-cheat-sheet.md`.
|
||||
|
||||
| Tool | Acción | Notas |
|
||||
|------|--------|-------|
|
||||
| `list_web_languages` | Lista los idiomas activos del sitio (`settings.dat.php [idiomas]`) | Devuelve `prefix`/`urlPrefix`/`isDefault`. `prefix="www"` = idioma base (URLs sin prefijo); otro prefix (p.ej. `en`) = idioma bajo `/en/...` |
|
||||
| `get_record_translations` | Lee traducciones de uno o varios registros | Por `tableName` (sin `cms_`) + `recordNums`. Opcional `fields` y `prefix`. Devuelve `{recordNum:{prefix:{fieldName:valor}}}` ya decodificado |
|
||||
| `set_record_translations` | Escribe traducciones de un registro + idioma | `tableName`+`recordNum`+`prefix`+`fields`. `''` borra la traducción. **`enlace` prohibido** (lo mantiene CocoEnlace) |
|
||||
|
||||
Además, las tools de lectura `list_table_records` y `get_record` aceptan el parámetro opcional `lang` (prefix, p.ej. `'en'`): devuelven los valores ya traducidos de los campos traducibles (el motor CocoDB aplica la traducción en lectura).
|
||||
|
||||
Campos traducibles por tipo: `textfield`, `textbox`, `wysiwyg`, `codigo`, `multitext` (el multitext se traduce como el JSON serializado completo en una sola fila). El valor en la DB va en Base64, pero es transparente: pasas y recibes texto plano.
|
||||
|
||||
### Documentación
|
||||
|
||||
| Tool | Acción |
|
||||
@@ -279,6 +293,32 @@ Notas:
|
||||
- En modo producción todas estas tools sincronizan automáticamente con el servidor real (no solo modifican local).
|
||||
- Si solo tienes el `recordId` y necesitas saber qué `fieldName` tiene uploads, llama antes a `get_table_schema({ minimal: true })` y filtra los campos `type: "upload"`.
|
||||
|
||||
### 12. Traducir un registro a otro idioma
|
||||
|
||||
Ejemplo: traducir la vacante num=12 al inglés.
|
||||
|
||||
1. `list_web_languages` — obtén el `prefix` del idioma destino (p.ej. `en`). El prefix `www` es el idioma base y NO se traduce por aquí (se edita con los campos normales del registro).
|
||||
2. (Opcional) `get_record({ tableName: "vacantes", recordNum: 12 })` para leer los textos originales, o `get_record_translations({ tableName: "vacantes", recordNums: [12], prefix: "en" })` para ver qué falta.
|
||||
3. `set_record_translations({ tableName: "vacantes", recordNum: 12, prefix: "en", fields: { titulo: "...", descripcion: "..." } })`. Solo campos traducibles (`textfield`, `textbox`, `wysiwyg`, `codigo`, `multitext`). **NUNCA** incluyas `enlace`. Un `''` borra esa traducción.
|
||||
4. Verifica con `get_record({ tableName: "vacantes", recordNum: 12, lang: "en" })` — devuelve los valores ya traducidos.
|
||||
|
||||
### 13. Traducir las variables de un módulo
|
||||
|
||||
Los textos de un módulo Builder viven en la tabla `builder_custom`, no en la tabla de la página.
|
||||
|
||||
1. `list_web_languages` — obtén el `prefix` destino.
|
||||
2. `get_module_config_vars({ tableName, recordNum, sectionId })` — devuelve `varsMeta`: por cada variable su `{ fieldName, recordNum }` físico en `builder_custom` (y por item en vars multi).
|
||||
3. Por cada variable a traducir, `set_record_translations({ tableName: "builder_custom", recordNum: <de varsMeta>, prefix, fields: { <fieldName de varsMeta>: "texto traducido" } })`.
|
||||
4. Para vars multi, repite con el `recordNum`/`fieldName` de cada item que devuelve `varsMeta`.
|
||||
|
||||
### 14. Traducir un texto general (literal de plantilla)
|
||||
|
||||
Los literales del filtro Twig `| translate` son registros normales de la tabla `textos_generales`; se traduce su campo `texto`.
|
||||
|
||||
1. `list_web_languages` — obtén el `prefix` destino.
|
||||
2. `list_table_records({ tableName: "textos_generales", where: "identificador = '...'", fields: ["num", "identificador", "texto"] })` para localizar el `num`.
|
||||
3. `set_record_translations({ tableName: "textos_generales", recordNum: <num>, prefix, fields: { texto: "traducción" } })`.
|
||||
|
||||
## Reglas globales para todas las tools
|
||||
|
||||
1. **`tableName` siempre SIN prefijo `cms_`** (excepto en `queryDB` Twig y en el `middleWare` de `set_hook_middleware`).
|
||||
|
||||
@@ -87,6 +87,20 @@ Resumen ejecutable de reglas críticas, tipos de campo, filtros y formatos de da
|
||||
| `multitext` | String JSON | `"[{\"item\":\"valor\"}]"` |
|
||||
| `upload` | NO enviar — usar `upload_record_image` después |
|
||||
|
||||
## Traducciones (multiidioma)
|
||||
|
||||
| Regla | Detalle |
|
||||
|-------|---------|
|
||||
| Prefix `www` = idioma base | URLs sin prefijo. Otro prefix (p.ej. `en`) sirve bajo `/en/...` — lista con `list_web_languages` |
|
||||
| Nunca traducir `enlace` | Lo mantiene CocoEnlace; la action PHP lo rechaza |
|
||||
| Valor `''` borra la traducción | `set_record_translations` con `''` elimina la fila y cae al idioma base |
|
||||
| Base64 transparente | El valor se guarda Base64 en `cms_traducciones`; tú siempre pasas/recibes texto plano |
|
||||
| `multitext` = JSON completo | Se traduce el JSON serializado entero en una sola fila, no item por item |
|
||||
| Campos traducibles | Solo `textfield`, `textbox`, `wysiwyg`, `codigo`, `multitext` |
|
||||
| Leer traducido | `get_record`/`list_table_records` con `lang: "<prefix>"` |
|
||||
| Vars de módulo | Se traducen sobre `builder_custom` usando `varsMeta` de `get_module_config_vars` |
|
||||
| Textos generales | Traducir el campo `texto` del registro en `textos_generales` (localiza por `identificador`) |
|
||||
|
||||
## Variables globales en Twig
|
||||
|
||||
| Variable | Descripción |
|
||||
|
||||
Reference in New Issue
Block a user