HUGO v163

Cómo implementé un sitio multilingüe en Hugo con un solo archivo por artículo, sin prefijo para el idioma por defecto y recursos junto al contenido.

Después de varias pruebas, finalmente simplifiqué la estructura del sitio para que sea realmente mantenible. Ahora todo el contenido multilingüe vive en un único archivo .md por artículo, los recursos (imágenes, PDF) se ubican junto al artículo, y el idioma por defecto —castellano— se sirve sin prefijo en la URL.

Organización de los artículos

Cada artículo es un archivo .md ubicado directamente bajo content/blog/, o bien una carpeta con un index.md y sus recursos. Por ejemplo:

content/blog/
├── 20250601_antena_moxon.md        # artículo sin imágenes
└── 20250701_restauracion_bc348/    # artículo con fotos y documentos
    ├── index.md
    ├── fotos/
    │   ├── antes.jpg
    │   └── despues.jpg
    └── doc/
        └── esquema.pdf

Si el artículo no lleva imágenes, basta con un archivo .md. Si necesita adjuntos, se crea una carpeta con el slug del artículo y se ponen los archivos ahí adentro.

Multilenguaje sin fricción

Hugo maneja los idiomas, pero la estructura tradicional obligaba a duplicar contenido en carpetas separadas por idioma. En este sitio:

  • El idioma por defecto es castellano y se sirve en la raíz (/post/).
  • Los otros idiomas se sirven con prefijo: /en/post/ y /pt-br/post/.
  • Todo el contenido traducido está en el mismo archivo .md, como campos content del front matter. También se pueden definir títulos, descripciones y leads por idioma.

Ejemplo de front matter:

content:
  es: Este es el artículo en español.

  en: This is the article in English.

  pt-br: Este é o artigo em português.

Los templates simplemente muestran el campo que corresponde al idioma activo. Si una traducción no existe, se usa el contenido en castellano como fallback.

Revertí los data files

En una versión anterior usaba archivos YAML externos en /data/ para almacenar las traducciones. Resultó engorroso: dos archivos por artículo, búsquedas adicionales, y los data files no aparecen en los resultados de búsqueda de Hugo. Volví a meter todo en el .md: un artículo, un archivo, todos los idiomas.

Recursos junto al artículo

Eliminé static/post-images/. Ahora las imágenes y documentos de cada artículo se guardan en una subcarpeta (fotos/, doc/, etc.) dentro de la carpeta del artículo. Ventajas:

  • Los recursos viajan con el artículo (fácil mover, renombrar o borrar).
  • Las rutas relativas en Markdown son más simples: ![antes](fotos/antes.jpg).
  • No se mezclan imágenes de distintos artículos en un mismo directorio gigante.

Template único para renderizado

Un renderizador común lee el .Page (ya sea una página simple o un _index.md de sección), extrae el campo de contenido según el idioma y lo pasa por markdownify. Los resúmenes también toman el lead traducido o los primeros párrafos del contenido correspondiente.

Resultado

Con este esquema:

  • Publicar un artículo nuevo es crear un archivo y escribir.
  • Añadir imágenes es meterlas en una subcarpeta dentro del artículo.
  • Agregar un idioma es copiar y traducir un bloque YAML en el mismo archivo.
  • Las URLs quedan limpias y canónicas: /mi-post/, /en/my-post/, /pt-br/meu-post/.

Una estructura chiquita y autosuficiente, sin dependencias externas, fácil de mantener y escalar.