← Blog

Un blog de auto-traducción: SQLite, un editor de Markdown y un LLM local

DEENESRUUK

Este blog tiene una propiedad ligeramente inusual: escribo una publicación una vez, en inglés, y un modelo de lenguaje local produce las versiones en ruso y ucraniano. Aquí está la maquinaria, y como siempre, donde deliberadamente mantuve el modelo fuera de la ruta crítica.

Las publicaciones son datos, no archivos

La primera versión del blog almacenaba cada publicación como un archivo Markdown compilado en tiempo de construcción. Genial para un desarrollador, inútil para editar sobre la marcha: cada corrección implicaba una reconstrucción y un despliegue. Así que las publicaciones pasaron a SQLite, una fila por (slug, language), y el Markdown se renderiza a HTML en tiempo de solicitud.

Ese único cambio lo desbloqueó todo lo demás: un editor de administración. Detrás del /admin con solo clave de acceso, hay un editor de Markdown simple: título, slug, etiquetas, un gran campo de contenido y un interruptor Publicado. Escribir o corregir una publicación es ahora un área de texto y un botón Guardar, sin ningún paso de compilación a la vista.

Un botón, dos idiomas

El sitio es trilingüe (EN / RU / UK), y mantener tres copias escritas a mano de cada publicación sincronizadas es exactamente el tipo de tarea tediosa que envejece. Así que junto a cada publicación en inglés hay un botón “Translate → RU & UK”.

Al pulsarlo, el servidor entrega la publicación a un modelo local Gemma (vía Ollama en la LAN; ningún texto sale de la red). Un prompt estricto le indica que traduzca el título, la descripción y el cuerpo manteniendo todo Markdown, bloques de código, URLs y términos técnicos (SQLite, BGP, nombres de archivo) exactamente como están escritos. La traducción se ejecuta en segundo plano — los modelos de lenguaje tardan — y el resultado se guarda como un borrador.

Esa palabra importa. Las traducciones nunca se publican solas. Llegan como borradores para que pueda leerlas, corregir la frase torpe (especialmente en ucraniano), y solo entonces pasarlas a estado activo. El modelo escribe un primer borrador; un humano da el visto bueno.

El lado del lector

Cada publicación termina en tres URLs: /blog/..., /ru/blog/..., /uk/blog/..., con un pequeño selector de idioma en el artículo que solo muestra las versiones que están realmente publicadas. Cada página lleva su propia URL canónica, datos estructurados BlogPosting en su idioma y una entrada en el sitemap, para que los motores de búsqueda vean tres artículos localizados correctos en lugar de una página con una cadena de consulta.

Y debido a que la honestidad es barata y la confianza no lo es, cada publicación y el índice del blog llevan una breve nota de transparencia: la mayoría de las publicaciones se redactan con asistencia de IA, y las versiones RU/UK son traducidas por máquina y revisadas.

El mismo principio, otra vez

Si han leído otras publicaciones aquí reconocerán la forma. El LLM es un asistente de redacción y traducción, no la fuente de verdad: esa es la fila de SQLite. Se ejecuta a un lado, bajo demanda, produciendo borradores que un humano aprueba; si Gemma estuviera caído, el blog no se daría cuenta, simplemente aún no tendría una traducción fresca.

Un modelo de lenguaje es una forma maravillosa de empezar una frase en otro idioma. Es un mal lugar para terminar la decisión editorial. Este blog está construido alrededor de esa línea.

Transparencia: la mayoría de las entradas se redactan con ayuda de IA, y las versiones que no están en inglés se traducen automáticamente con un LLM local y luego se revisan. ¿Has visto un error? Avísame, por favor.