Actualiza la guía de autoservicio de traducción con la llamada real a fea/v1/crear-traduccion (#225, ya en producción), verificada de extremo a extremo por Claudix contra prod con un post desechable.
9.6 KiB
Guía de traducción (EN/FR/IT/PT) en autoservicio — para Inma / Mixbot
Para quién es este documento: para Inma y Mixbot, a partir de la conversación del 2026-08-31 en Buzz: además del audio (#222, ver
docs/guia-tts-audio-autoservicio-inma-mixbot.md), Rafa confirmó que la traducción se traspasa también. El endpoint para enlazar traducciones (PR #225) se hizo bajo el paraguas del propio #222.Motores autorizados por Rafa (2026-08-31): un agente local con Haiku desde el propio Claude/Cowork de Inma (no la API de pago de Rafa — es otra cuenta, otro caso), o MiniMax con el mismo token ya compartido para el audio. Gemma queda fuera para vosotros: es un modelo local que corre en la GPU del PC de Rafa, no accesible desde fuera.
0. Crear y enlazar la traducción — ya resuelto
Ya existe un endpoint que crea el post traducido y lo enlaza con Polylang (idioma + grupo de traducción) en una sola llamada — no hace falta tocar nada de bajo nivel:
POST https://www.feadulta.com/wp-json/fea/v1/crear-traduccion
Authorization: Basic <usuario:contraseña_de_aplicación>
Content-Type: multipart/form-data
es_id=<ID del post ES>
lang=en|fr|it|pt
title=<título traducido>
content=<HTML traducido>
excerpt=<opcional>
status=draft|publish (default draft)
model=<opcional, solo trazabilidad — p.ej. "minimax" o "haiku-local">
Respuesta (201 si crea, 200 si ya existía — es idempotente, repetir la llamada con el
mismo es_id/lang nunca duplica):
{"es_id": 56786, "lang": "en", "translation_id": 56787, "created": true,
"url": "https://www.feadulta.com/en/?p=56787"}
Por detrás replica exactamente lo que hacía scripts/fea_translate_helper.php::create en
local: asigna el idioma antes de las categorías, mapea cada categoría del ES a su
equivalente traducida (o la deja en español si no existe traducción de esa categoría),
preserva el resto del grupo de traducciones si el ES ya tenía otros idiomas, y añade los
metas de trazabilidad (traduccion_automatica, traduccion_origen, traduccion_modelo,
traduccion_fecha).
Verificado por Claudix el 2026-08-31 con una prueba real de extremo a extremo en producción
(post ES desechable → traducción EN creada → confirmado con pll_get_post_translations que
el grupo quedó {es: ..., en: ...} — todo borrado después).
1. Las reglas de traducción (igual las use vuestro Claude/Haiku o MiniMax)
Esto es el prompt real que usa el pipeline de Rafa (scripts/translate_post.py), verificado
palabra por palabra el 2026-08-31 contra el código — usadlo tal cual, no lo resumáis:
Eres un traductor profesional de textos religiosos cristianos (espiritualidad y teología católica). Traduce del español al {idioma destino}. REGLAS ESTRICTAS:
- Conserva EXACTAMENTE el marcado HTML (etiquetas y atributos) y los shortcodes entre
[ ]y{ }. No los traduzcas ni los reordenes.- NO traduzcas las referencias bíblicas ni sus abreviaturas (p. ej. "Jn 3, 16", "Isaías 5, 1-7", "Mt 5"). Déjalas idénticas.
- Conserva los nombres propios de persona y lugar (salvo exónimos establecidos).
- Glosario fijo: "Fe Adulta" → "Fe Adulta" (en/fr/it/pt, no se traduce); "EFFA" → "EFFA" (igual, en los 4 idiomas).
- Traducción FIEL: no resumas, no añadas, no comentes.
Para el título, además: que quede natural en el idioma destino (no lo dejéis en español salvo que sea un nombre propio o una marca), y si es un modismo, traducid el sentido, no lo calquéis literal.
2. El "learning" del título — dadle el primer párrafo como contexto
Esto es lo que pedía Rafa explícitamente documentar. Aviso de precisión: este cambio
existe como commit (4475ebb, rama feat/issue-200-title-context) pero no está fusionado
a main — verificado el 2026-08-31 comparando el histórico. O sea: si alguna vez volvéis a
usar scripts/translate_post.py tal cual desde main, el título se traduce SIN este contexto.
Para vuestro proceso propio (agente Haiku o llamada directa a MiniMax) aplicad la técnica de
todas formas, es la que ya dio mejor resultado en pruebas:
- Traducid primero el cuerpo del artículo, el título al final — necesitáis el cuerpo ya traducido (o al menos leído) para poder darle contexto al título.
- Al traducir el título, añadid al prompt el primer párrafo del cuerpo en español (recortado a 2000 caracteres), como contexto de significado — no se traduce ni se incluye literal en la salida, solo ayuda al modelo a entender modismos o dobles sentidos del título que sin ese contexto salen mal traducidos.
- Instrucción exacta añadida al prompt del título: "Si es un modismo, interpreta su sentido según el contexto, no lo calques."
3. Troceo de artículos largos
Si usáis MiniMax para traducir (no Haiku, que admite el artículo entero de una vez gracias a su contexto de 200k), trocead el HTML por párrafos completos (nunca a mitad de una etiqueta) en bloques de ~5.000 caracteres, y unid las traducciones de cada trozo en el mismo orden.
4. QA — checklist antes de dar una traducción por buena
Reformulado en REST puro (el script original, gate_mec2.php, corre dentro de WP y usa
funciones de Polylang no disponibles desde fuera — pero las comprobaciones sí son igual de
válidas mirando el JSON de cada post por la API):
Para cada origen ES y cada idioma que hayáis traducido, comparad contra el post ES:
- Cobertura: los 4 idiomas presentes (o los que toque — Pagola nunca lleva traducción automática, ver §5).
- Estado: la traducción en
drafthasta que se revise (salvo que el ES ya estépublishy la carta lo pida — verdocs/guia-publicacion-carta-inma.md). - Sin residuos de generación: buscar literalmente en el
contentdevuelto por la API cadenas como</strong>**,</strong></strong>,<>,<<<INI>>>,<<<FIN>>>,|||FIN, o cualquier resto de las marcas del prompt. - Sin alfabetos ajenos: ningún carácter árabe/cirílico/CJK en el resultado (residuo típico de generación que se cuela cuando el modelo "piensa" en otro idioma).
- Mismo nº de párrafos que el ES (contar apariciones de
<pen el HTML). Un desajuste suele significar que el modelo se comió contenido en el troceado. - Mismo nº de enlaces
<a href>que el ES — es el check que más falla y el más importante: en la carta 739, el italiano perdió 15 de 39 enlaces en uno de los trozos troceados mientras EN/FR salieron bien, y nada posterior lo detecta si no lo comprobáis aquí. Si hay menos enlaces en la traducción que en el ES, no la deis por buena. - Referencias bíblicas equivalentes: extraer patrones tipo
capítulo,versículode ambos textos y comparar solo capítulo:versículo, no la abreviatura del libro completa (el inglés cambia la coma por dos puntos y traduce el nombre:Mt 15,21-28en ES pasa aMatthew 15:21-28en EN — comparar literal daría un falso positivo de "referencia perdida"). - Título distinto del ES (salvo portugués, donde algunos nombres propios/citas coinciden de forma legítima).
Capa editorial adicional si tenéis acceso a un modelo capaz de juzgar fidelidad (vuestro
Claude/Haiku local sirve para esto): pedidle que lea origen y traducción y devuelva un
veredicto approve / needs_review / rewrite con la cita exacta del problema — descartad
cualquier hallazgo cuya cita no aparezca literal en el texto (evita ediciones basadas en
alucinaciones del propio revisor).
5. Excepciones que no lleváis por la vía automática
- Autores que aportan su propia traducción humana (hoy, Pagola: 4 DOCX por carta, adjuntos en el issue de la semana) — nunca generéis fallback automático para ellos aunque falte alguno de los 4 idiomas.
- Textos litúrgicos enlazados desde la carta (evangelio, lecturas) — confirmar con Rafa si entran en el alcance de "todo lo de la carta" o se dejan fuera; ha habido confusión antes sobre esto (no dar por hecho que "ya deben estar traducidos").
6. Cómo leer la cuota de MiniMax
Con el mismo token que ya tenéis para el audio:
curl -s https://api.minimax.io/v1/token_plan/remains \
-H "Authorization: Bearer <TOKEN>" -H "Content-Type: application/json"
Del JSON de respuesta:
base_resp.status_codedebe ser0(cualquier otro valor es error de cuenta/plan, verbase_resp.status_msg).model_remainses una lista por modelo. El de texto/traducción es el que tienemodel_name == "general"; los de audio son losspeech-2.8-*que ya usáis para TTS.- De cada entrada:
current_interval_remaining_percent(cuánto queda de la ventana de 5h que se resetea sola —end_timees cuándo) ycurrent_weekly_remaining_percent/weekly_end_time(la ventana semanal, más amplia). Restad a 100 para saber "cuánto habéis gastado" si preferís verlo así.
Igual que con el audio: un HTTP 200 no es garantía de cuota — cuando t2a_v2 o el endpoint
de traducción devuelvan base_resp.status_code=2056 (plan agotado) o 1039 (límite de
ritmo), parad y reintentad más tarde, no machaquéis la API.
7. Qué falta para que esto sea autoservicio de verdad
Con el endpoint del §0 ya no queda ningún bloqueante de infraestructura conocido para crear
y enlazar traducciones por REST. Lo que sigue siendo trabajo vuestro, no de infraestructura:
generar el texto (motores del principio del documento), aplicar el QA del §4 antes de
llamar al endpoint, y decidir cuándo pasáis una traducción de draft a publish (mismo
criterio que la carta en español, ver docs/guia-publicacion-carta-inma.md).