Puedes ver todo el código que discuto aquí en este repositorio de GitHub.
Desde que descubrí Typst en 2025, he migrado muchos de mis archivos a este lenguaje. Entre esos estaba mi CV. Desde hace tiempo había querido implementar mi CV de manera que pudiera separar los datos de la presentación, y así poder actualizar los datos esquemáticamente y que alguna plantilla produjera el PDF correspondiente. Por un tiempo intenté con LaTeX, pero es terrible para manejar datos externos como JSON o YAML. Luego intenté con HTML, pero manejar el formato de un documento con páginas separadas es una pesadilla. Typst resultó ser perfecto para la tarea: recibe archivos JSON, YAML, CSV e incluso archivos de BibLaTeX, y ofrece mucho control para generar documentos en PDF en lugar de páginas web.
Entonces eso hice: migré mi CV a Typst, mis datos a archivos YAML, CSV y BibLaTeX, y empecé a llevar registro en un repositorio de Git. Pero luego se me ocurrió la siguiente idea: puedo automatizar la generación de mi CV directamente en GitHub y mantener una versión siempre actualizada de mi CV allí.
La idea es entonces la siguiente:
- Hago cambios a los archivos, generalmente actualizando algún dato (e.g., una nueva charla documentada en un CSV o una nueva publicación agregada al archivo BibLaTeX correspondiente).
- En lugar de generar un PDF en mi computador, hago push a estos datos a GitHub.
- GitHub genera dos versiones en PDF del CV usando GitHub Actions, una en español y otra en inglés.
- GitHub lanza estas dos versiones como un release y reescribe el último release disponible.
Esto ofrece la ventaja de tener un único enlace junto con un único punto de actualización.
Prefacio: Introducción breve a GitHub Actions
Si ya conoces GitHub Actions, puedes pasar a la siguiente sección. Si no, lo cuento rápidamente.
GitHub Actions en un sistema de GitHub que permite ejecutar acciones en la nube. GitHub genera una máquina virtual temporal, y corre los comandos que especifiques. Como todo lo de GitHub, está pensado para el desarrollo de software. Por ejemplo, se usa para correr tests en la nube cuando se sube código al repositorio, o para generar versiones de lanzamiento de un paquete.
Una acción de GitHub Actions se configura mediante un archivo YAML que guardamos en la carpeta .github/workflows en nuestro repositorio. Allí especificamos alguna información básica y cuándo debe correr esta acción. Existen ya varias acciones preprogramadas disponibles en GitHub Marketplace con instrucciones de cómo usarlas. Sobre cuándo correr la acción, podemos decirle a GitHub que corra esta acción cada vez que hacemos push al repositorio (que es lo que hago con mi CV), que permita ejecutarla manualmente, periódicamente, etc.
Typst y GitHub Actions
La idea general es entonces generar el CV usando Typst directamente en la nube usando GitHub Actions. Para eso, configuré la siguiente acción que ejecuta los siguientes pasos:
-
Toma el repositorio en su estado actual (checkout).
- uses: actions/checkout@v4 -
Instala Typst.
- uses: typst-community/setup-typst@v5 -
Instala FontAwesome y PT Sans (las fuentes que usa mi CV).
- name: Install Font Awesome run: | curl -sSL -o fa.zip https://github.com/FortAwesome/Font-Awesome/releases/download/6.7.2/fontawesome-free-6.7.2-desktop.zip unzip -q fa.zip -d fa mkdir -p fonts find fa -name "*.otf" -exec cp {} fonts/ \; - name: Install PT Sans run: | mkdir -p fonts base=https://github.com/google/fonts/raw/main/ofl/ptsans for f in Regular Bold Italic BoldItalic; do curl -sSL -o "fonts/PT_Sans-Web-$f.ttf" "$base/PT_Sans-Web-$f.ttf" done -
Genera el PDF de mi CV.
- name: Compile PDFs run: typst compile --font-path fonts main.typ LoaizaCV.pdf
La acción luce así:
steps:
- uses: actions/checkout@v4
- uses: typst-community/setup-typst@v5
- name: Install Font Awesome
run: |
curl -sSL -o fa.zip https://github.com/FortAwesome/Font-Awesome/releases/download/6.7.2/fontawesome-free-6.7.2-desktop.zip
unzip -q fa.zip -d fa
mkdir -p fonts
find fa -name "*.otf" -exec cp {} fonts/ \;
- name: Install PT Sans
run: |
mkdir -p fonts
base=https://github.com/google/fonts/raw/main/ofl/ptsans
for f in Regular Bold Italic BoldItalic; do
curl -sSL -o "fonts/PT_Sans-Web-$f.ttf" "$base/PT_Sans-Web-$f.ttf"
done
- name: Compile PDFs
run: typst compile --font-path fonts main.typ LoaizaCV.pdf
Con esto ya tengo un PDF de mi CV. Ahora podemos sacarlo como un release de GitHub agregando lo siguiente a esta acción.
- name: Delete previous release and tag
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: gh release delete latest --cleanup-tag --yes || true
- name: Create release
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
gh release create latest LoaizaCV.pdf \
--title "Latest" \
--notes "Automatic build of ${GITHUB_SHA::7}" \
--target "$GITHUB_SHA" \
Esto genera una versión de mi CV disponible para el público en un enlace fijo https://github.com/juanrloaiza/cv/releases/download/latest/LoaizaCV.pdf.
Finalmente, le decimos a GitHub Actions que haga todo esto cada vez que hago push al repositorio:
name: Rolling release
on:
push:
branches: [main]
permissions:
contents: write
Con esto la acción completa queda así:
name: Rolling release
on:
push:
branches: [main]
permissions:
contents: write
jobs:
release:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: typst-community/setup-typst@v5
- name: Install Font Awesome
run: |
curl -sSL -o fa.zip https://github.com/FortAwesome/Font-Awesome/releases/download/6.7.2/fontawesome-free-6.7.2-desktop.zip
unzip -q fa.zip -d fa
mkdir -p fonts
find fa -name "*.otf" -exec cp {} fonts/ \;
- name: Install PT Sans
run: |
mkdir -p fonts
base=https://github.com/google/fonts/raw/main/ofl/ptsans
for f in Regular Bold Italic BoldItalic; do
curl -sSL -o "fonts/PT_Sans-Web-$f.ttf" "$base/PT_Sans-Web-$f.ttf"
done
- name: Compile PDFs
run: typst compile --font-path fonts main.typ LoaizaCV.pdf
- name: Delete previous release and tag
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: gh release delete latest --cleanup-tag --yes || true
- name: Create release
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
gh release create latest LoaizaCV_*.pdf \
--title "Latest" \
--notes "Automatic build of ${GITHUB_SHA::7}" \
--target "$GITHUB_SHA" \
Generando el CV en dos idiomas
Ahora bien, yo quiero que mi CV se genere tanto en inglés como en español. Para lograr esto, necesitamos varias cosas:
- Typst debe detectar el idioma con alguna variable configurable.
- Basado en ese idioma, debe traducir varios de los textos del CV.
Lo primero podemos lograrlo con una variable simple en Typst (aunque volveré a eso en un momento). Para lo segundo, tomando un patrón recurrente en la internacionalización de páginas web, implementé una función de traducción que toma un archivo de traducciones (en mi caso un YAML) y nos devuelve la versión correspondiente según el idioma en el que estemos.
#let lang = "es"
#let translations = yaml("i18n/translations.yml")
#let t = key => translations.at(key).at(lang)
Así, cuando necesito una versión en inglés de, por ejemplo, la palabra “Educación”, puedo obtenerla de la siguiente manera:
#t("education") // "Educación" o "Education" dependiendo de la configuración de #lang y #t()
Eso permite generar fácilmente un CV en español o en inglés cambiando la variable lang. Pero recordemos que Typst correrá en la nube, y por lo tanto no tendremos cómo cambiar la variable en el documento una vez hagamos push al repositorio. ¿Cómo controlamos entonces la variable de idioma?
Typst ofrece un módulo System que nos permite fijar variables como argumentos al compilador. Podemos entonces configurar la variable lang de la siguiente manera:
#let lang = sys.inputs.at("lang", default: "es")
Esto hace que por defecto, el CV se genere en español, pero que podamos controlar la variable usando --input lang=... como argumento cuando compilamos el documento.
typst compile --input lang=es main.typ LoaizaCV_es.pdf # Genera un PDF en español
typst compile --input lang=en main.typ LoaizaCV_en.pdf # Genera un PDF en inglés
Ahora solo tenemos que cambiar ligeramente la acción que corre el compilador de Typst para que corra con ambos idiomas, y la parte que hace el release para que tome ambas versiones del CV:
- name: Compile PDFs
run: |
typst compile --font-path fonts --input lang=es main.typ LoaizaCV_es.pdf
typst compile --font-path fonts --input lang=en main.typ LoaizaCV_en.pdf
...
- name: Create release
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: | # Toma todos los archivos LoaizaCV_*.pdf
gh release create latest LoaizaCV_*.pdf \
--title "Latest" \
--notes "Automatic build of ${GITHUB_SHA::7}" \
--target "$GITHUB_SHA" \
¡Y listo! Ahora cada vez que hacemos push al repositorio, se genera automáticamente una versión en español y una versión en inglés del CV.