De README a sitio de documentación bilingüe con MkDocs Material

De README a sitio de documentación bilingüe con MkDocs Material

El plugin de Jitsi para Moodle que mantengo, mod_jitsi, tenía toda su documentación en un sitio: el README.md. Y no era un README cualquiera, eran más de 600 líneas cubriendo instalación, opciones de servidor (GCP, JaaS, servidor propio), modo JWT, grabaciones, asistencia, permisos… Un buen README, pero un README al fin y al cabo.

El problema de un README largo es que no escala como documentación. Nadie lee 600 líneas de corrido en GitHub. No hay buscador. No hay navegación lateral. No hay forma cómoda de enlazar a “la sección de configuración del JWT”. Y si quieres traducirlo, acabas con dos archivos gigantes que se desincronizan a la primera.

Así que me decidí a montar un sitio de documentación de verdad, con buscador, navegación, modo claro/oscuro y dos idiomas. Esto es lo que usé y por qué.

Por qué MkDocs Material

Me planteé tres opciones: Docusaurus, Hugo (que ya uso para este blog) y MkDocs.

  • Docusaurus es potente pero arrastra todo el ecosistema de React/Node. Para una documentación que es básicamente Markdown, me parecía matar moscas a cañonazos.
  • Hugo lo domino, pero montar un tema de documentación decente con buscador e i18n desde cero es trabajo.
  • MkDocs con el tema Material te da, casi de fábrica: buscador client-side, navegación lateral, índice por página, modo claro/oscuro automático, resaltado de código con botón de copiar, y un diseño que ya parece profesional sin tocar una línea de CSS.

Para documentación técnica, MkDocs Material es el camino corto. Gana por simplicidad: escribes Markdown y ya.

El esqueleto

Se instala en un entorno virtual de Python y poco más:

1python3 -m venv .venv
2source .venv/bin/activate
3pip install mkdocs-material mkdocs-static-i18n

La estructura mínima es un mkdocs.yml y una carpeta docs/ con tus Markdown:

jitsi-docs/
├── mkdocs.yml
└── docs/
    ├── index.md
    ├── getting-started/
    │   ├── requirements.md
    │   └── installation.md
    └── ...

Y el mkdocs.yml con lo esencial del tema:

 1site_name: mod_jitsi Documentation
 2theme:
 3  name: material
 4  palette:
 5    - media: "(prefers-color-scheme)"
 6      toggle: { icon: material/brightness-auto, name: Cambiar a claro }
 7    - media: "(prefers-color-scheme: light)"
 8      scheme: default
 9      toggle: { icon: material/brightness-7, name: Cambiar a oscuro }
10    - media: "(prefers-color-scheme: dark)"
11      scheme: slate
12      toggle: { icon: material/brightness-4, name: Usar preferencia del sistema }
13  features:
14    - navigation.sections
15    - navigation.indexes
16    - search.suggest
17    - content.code.copy

Con eso ya tienes un sitio con buscador, tres estados de tema (auto/claro/oscuro) y botón de copiar en cada bloque de código. mkdocs serve te lo levanta en local para ir viendo los cambios al guardar.

Lo que el README ya me daba hecho

Aquí está la parte buena de haber tenido un README extenso: ya era casi la documentación. No partí de cero. Troceé esas 600 líneas en páginas temáticas (requisitos, instalación, inicio rápido, opciones de servidor, JWT, grabaciones, asistencia, moderación, permisos…) y de paso saqué el contenido directo del código del plugin: los ajustes salen de settings.php, los permisos de db/access.php (15 capacidades mod/jitsi:*).

Moraleja: si mantienes un proyecto open source, un buen README es una inversión doble. Sirve en GitHub y es la materia prima de tu sitio de docs el día que decidas montarlo.

Bilingüe sin duplicar el proyecto

Quería inglés (es un plugin de moodle.org, audiencia internacional) y español. El plugin mkdocs-static-i18n lo resuelve de forma elegante con la estructura suffix: por cada página tienes el archivo base y una variante con el sufijo del idioma.

docs/
├── index.md        ← inglés (idioma por defecto)
├── index.es.md     ← español
├── getting-started/
│   ├── installation.md
│   └── installation.es.md

Y en mkdocs.yml:

 1plugins:
 2  - search
 3  - i18n:
 4      docs_structure: suffix
 5      languages:
 6        - locale: en
 7          default: true
 8          name: English
 9          build: true
10        - locale: es
11          name: Español
12          build: true
13          nav_translations:
14            Getting started: Primeros pasos
15            Installation: Instalación
16            Configuration: Configuración

nav_translations es el detalle que marca la diferencia: traduce las etiquetas del menú lateral sin que tengas que duplicar la estructura de navegación. El resultado es el inglés en la raíz (/jitsi/docs/) y el español en /jitsi/docs/es/, con un selector de idioma en la cabecera.

El truco: servirlo bajo un subpath de una web que ya existe

No quería un subdominio nuevo (docs.…) ni un hosting aparte. La documentación es de un plugin que ya tiene su landing en sergiocomeron.com/jitsi/, así que lo lógico era colgar las docs debajo, en sergiocomeron.com/jitsi/docs/.

MkDocs lo pone fácil con dos líneas:

1site_url: https://sergiocomeron.com/jitsi/docs/
2site_dir: /opt/homebrew/var/www/sergiocomeron/jitsi/docs

site_dir apunta directamente al docroot de Apache, dentro de la carpeta del sitio principal pero sin tocar la landing jitsi/index.html. Construir es literalmente:

1mkdocs build --strict

Lo metí en un build-docs.sh de una línea y listo: edito los .md, ejecuto el script y Apache sirve la versión nueva al instante. Sin pipeline, sin deploy a ningún sitio. La salida generada va al .gitignore (lo versionado es el fuente en docs/).

La piedra con la que tropecé: la CSP

Mi sitio sirve una Content-Security-Policy en modo bloqueo. Al publicar las docs, el buscador de Material no funcionaba: en la consola, Refused to create a worker. Material ejecuta el indexado de búsqueda en un web worker que se carga desde un blob:, y mi CSP no lo permitía.

La solución fue añadir una directiva a la CSP:

worker-src 'self' blob:;

Es el típico detalle que solo aparece cuando integras una herramienta de terceros en un sitio que ya tienes endurecido. Si tu CSP es permisiva no lo notarás; si la tienes en modo bloqueo, anótalo.

El resultado

sergiocomeron.com/jitsi/docs/ — un sitio de documentación con buscador, navegación, modo claro/oscuro y dos idiomas, generado del mismo Markdown que mantengo en el repositorio del plugin, y servido desde el mismo Mac mini que sirve todo lo demás. Cero coste, cero servicios externos.

Lo mejor: actualizar la documentación ahora es editar un .md y correr un script. Lo que antes era hacer scroll por un README de 600 líneas, ahora es un sitio que se busca, se navega y se enlaza. Y si algún día el plugin crece, la documentación crece con él sin convertirse en un muro de texto.

Si mantienes un proyecto open source y tu documentación vive en un README que ya no cabe en sí mismo, MkDocs Material es una tarde de trabajo bien invertida.