Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
101 changes: 96 additions & 5 deletions .github/workflows/docs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,13 @@ concurrency:
# Versions published in the switcher. The first entry is treated as the
# default (the site root redirects to it). Keep PAGES_VERSIONS, the
# versions.json manifest, and the landing redirect below in sync.
#
# Languages are NOT configured here: each branch declares its own set in
# docs/languages.txt (first entry = default). A branch that ships that file is
# published with a per-language layout (<version>/<lang>/...) plus a
# per-version languages.json the language switcher reads; a branch without it
# keeps the legacy single-language layout (<version>/...). This keeps older,
# English-only branches working unchanged.
env:
PAGES_VERSIONS: 'master develop 2.0dev'
PAGES_DEFAULT: 'master'
Expand Down Expand Up @@ -59,7 +66,19 @@ jobs:
python -m venv "$RUNNER_TEMP/venv-pr"
"$RUNNER_TEMP/venv-pr/bin/pip" install --upgrade pip
"$RUNNER_TEMP/venv-pr/bin/pip" install -r docs/requirements.txt
"$RUNNER_TEMP/venv-pr/bin/sphinx-build" -b html docs/source "$RUNNER_TEMP/_site_pr"
# Build every language this branch declares (validates the gettext
# catalogs too), or just English when no languages.txt is present.
if [ -f docs/languages.txt ]; then
langs=$(grep -vE '^[[:space:]]*#|^[[:space:]]*$' docs/languages.txt)
else
langs=en
fi
for lang in $langs; do
echo "::group::Build PR ($lang)"
DOCS_LANGUAGE="$lang" "$RUNNER_TEMP/venv-pr/bin/sphinx-build" -b html \
docs/source "$RUNNER_TEMP/_site_pr/$lang"
echo "::endgroup::"
done

# --- Push / manual run: build every version and assemble the site ---
- name: Configure GitHub Pages
Expand Down Expand Up @@ -94,8 +113,30 @@ jobs:
python -m venv "$venv"
"$venv/bin/pip" install --upgrade pip
"$venv/bin/pip" install -r "$worktree/docs/requirements.txt"
DOCS_VERSION="$v" "$venv/bin/sphinx-build" -b html \
"$worktree/docs/source" "_site/$v"
if [ -f "$worktree/docs/languages.txt" ]; then
# New layout: one subdirectory per language, a languages.json
# manifest, and a landing page redirecting to the default language.
langs=$(grep -vE '^[[:space:]]*#|^[[:space:]]*$' "$worktree/docs/languages.txt")
default_lang=$(printf '%s\n' $langs | head -n1)
for lang in $langs; do
DOCS_VERSION="$v" DOCS_LANGUAGE="$lang" "$venv/bin/sphinx-build" \
-b html "$worktree/docs/source" "_site/$v/$lang"
done
json=$(printf '"%s",' $langs); json="[${json%,}]"
printf '%s\n' "$json" > "_site/$v/languages.json"
{
echo '<!DOCTYPE html>'
echo '<html lang="en"><head><meta charset="utf-8">'
echo "<meta http-equiv=\"refresh\" content=\"0; url=./$default_lang/\">"
echo "<link rel=\"canonical\" href=\"./$default_lang/\">"
echo '<title>ALAMODE documentation</title></head>'
echo "<body>Redirecting to the <a href=\"./$default_lang/\">documentation</a>&hellip;</body></html>"
} > "_site/$v/index.html"
else
# Legacy single-language layout (English only).
DOCS_VERSION="$v" "$venv/bin/sphinx-build" -b html \
"$worktree/docs/source" "_site/$v"
fi
git worktree remove --force "$worktree"
echo "::endgroup::"
done
Expand All @@ -104,10 +145,11 @@ jobs:
if: github.event_name != 'pull_request'
run: |
set -euo pipefail
# versions.json: the manifest the switcher reads at runtime.
# versions.json: the manifest the version switcher reads at runtime.
json=$(printf '"%s",' $PAGES_VERSIONS); json="[${json%,}]"
printf '%s\n' "$json" > _site/versions.json
# Root landing page: redirect to the default version.
# Root landing page: redirect to the default version (whose own
# index then redirects to its default language, if it has several).
{
echo '<!DOCTYPE html>'
echo '<html lang="en"><head><meta charset="utf-8">'
Expand All @@ -126,6 +168,55 @@ jobs:
with:
path: _site

build-pdf-ja:
name: Build Japanese PDF
runs-on: ubuntu-latest
defaults:
run:
shell: bash
steps:
- uses: actions/checkout@v4

- name: Setup Python
uses: actions/setup-python@v5
with:
python-version: '3.10'

# LuaLaTeX + LuaTeX-ja (ltjsbook class, Harano Aji fonts) for Japanese,
# plus GNU FreeFont for the Latin body text Sphinx defaults to.
- name: Install TeX Live (LuaLaTeX + Japanese)
run: |
set -euo pipefail
sudo apt-get update
sudo apt-get install -y --no-install-recommends \
latexmk \
texlive-luatex \
texlive-latex-recommended \
texlive-latex-extra \
texlive-fonts-recommended \
texlive-lang-japanese \
fonts-freefont-otf

- name: Build Japanese PDF
run: |
set -euo pipefail
python -m venv "$RUNNER_TEMP/venv-pdf"
"$RUNNER_TEMP/venv-pdf/bin/pip" install --upgrade pip
"$RUNNER_TEMP/venv-pdf/bin/pip" install -r docs/requirements.txt
DOCS_LANGUAGE=ja "$RUNNER_TEMP/venv-pdf/bin/sphinx-build" -b latex \
docs/source "$RUNNER_TEMP/latex-ja"
# all-pdf drives latexmk, which the generated latexmkrc points at
# lualatex; halt on the first error so failures surface in the log.
make -C "$RUNNER_TEMP/latex-ja" all-pdf \
LATEXMKOPTS="-interaction=nonstopmode -halt-on-error"

- name: Upload Japanese PDF
uses: actions/upload-artifact@v4
with:
name: alamode-ja-pdf
path: ${{ runner.temp }}/latex-ja/ALAMODE.pdf
if-no-files-found: error

deploy:
name: Deploy to GitHub Pages
# Never publish from pull requests.
Expand Down
36 changes: 32 additions & 4 deletions docs/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,11 @@ SPHINXBUILD = sphinx-build
PAPER =
BUILDDIR = build

# Translation languages besides the English source. Keep this in sync with
# docs/languages.txt, which the docs CI workflow reads per branch to decide
# which languages to publish.
LANGUAGES = ja

# User-friendly check for sphinx-build
ifeq ($(shell which $(SPHINXBUILD) >/dev/null 2>&1; echo $$?), 1)
$(error The '$(SPHINXBUILD)' command was not found. Make sure you have Sphinx installed, then set the SPHINXBUILD environment variable to point to the full path of the '$(SPHINXBUILD)' executable. Alternatively you can add the directory with the executable to your PATH. If you don't have Sphinx installed, grab it from http://sphinx-doc.org/)
Expand All @@ -16,14 +21,18 @@ endif
PAPEROPT_a4 = -D latex_paper_size=a4
PAPEROPT_letter = -D latex_paper_size=letter
ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) source
# Each language needs its own doctree cache, because the build environment is
# language-specific (sharing one cache forces a full rebuild on every switch).
JASPHINXOPTS = -d $(BUILDDIR)/doctrees-ja $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) source
# the i18n builder cannot share the environment and doctrees with the others
I18NSPHINXOPTS = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) source

.PHONY: help clean html dirhtml singlehtml pickle json htmlhelp qthelp devhelp epub latex latexpdf text man changes linkcheck doctest gettext
.PHONY: help clean html html-ja dirhtml singlehtml pickle json htmlhelp qthelp devhelp epub latex latexpdf latexpdf-ja text man changes linkcheck doctest gettext update-po

help:
@echo "Please use \`make <target>' where <target> is one of"
@echo " html to make standalone HTML files"
@echo " html to make standalone HTML files (English)"
@echo " html-ja to make standalone HTML files (Japanese)"
@echo " dirhtml to make HTML files named index.html in directories"
@echo " singlehtml to make a single large HTML file"
@echo " pickle to make pickle files"
Expand All @@ -33,13 +42,15 @@ help:
@echo " devhelp to make HTML files and a Devhelp project"
@echo " epub to make an epub"
@echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter"
@echo " latexpdf to make LaTeX files and run them through pdflatex"
@echo " latexpdf to make LaTeX files and run them through pdflatex (English)"
@echo " latexpdf-ja to make the Japanese PDF and run it through lualatex"
@echo " latexpdfja to make LaTeX files and run them through platex/dvipdfmx"
@echo " text to make text files"
@echo " man to make manual pages"
@echo " texinfo to make Texinfo files"
@echo " info to make Texinfo files and run them through makeinfo"
@echo " gettext to make PO message catalogs"
@echo " gettext to make PO message catalogs (translation templates)"
@echo " update-po to create/refresh source/locale/<lang> catalogs for $(LANGUAGES)"
@echo " changes to make an overview of all changed/added/deprecated items"
@echo " xml to make Docutils-native XML files"
@echo " pseudoxml to make pseudoxml-XML files for display purposes"
Expand All @@ -54,6 +65,11 @@ html:
@echo
@echo "Build finished. The HTML pages are in $(BUILDDIR)/html."

html-ja:
DOCS_LANGUAGE=ja $(SPHINXBUILD) -b html $(JASPHINXOPTS) $(BUILDDIR)/html/ja
@echo
@echo "Build finished. The Japanese HTML pages are in $(BUILDDIR)/html/ja."

dirhtml:
$(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml
@echo
Expand Down Expand Up @@ -116,6 +132,12 @@ latexpdf:
$(MAKE) -C $(BUILDDIR)/latex all-pdf
@echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex."

latexpdf-ja:
DOCS_LANGUAGE=ja $(SPHINXBUILD) -b latex $(JASPHINXOPTS) $(BUILDDIR)/latex/ja
@echo "Running LaTeX files through lualatex..."
$(MAKE) -C $(BUILDDIR)/latex/ja all-pdf
@echo "lualatex finished; the PDF file is in $(BUILDDIR)/latex/ja."

latexpdfja:
$(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
@echo "Running LaTeX files through platex and dvipdfmx..."
Expand Down Expand Up @@ -150,6 +172,12 @@ gettext:
@echo
@echo "Build finished. The message catalogs are in $(BUILDDIR)/locale."

update-po: gettext
sphinx-intl update -p $(BUILDDIR)/locale $(foreach lang,$(LANGUAGES),-l $(lang))
@echo
@echo "Updated translation catalogs under source/locale for: $(LANGUAGES)."
@echo "Edit the .po files (fill in msgstr), then rebuild with e.g. 'make html-ja'."

changes:
$(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes
@echo
Expand Down
8 changes: 8 additions & 0 deletions docs/languages.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
# Languages published for this branch's documentation, one code per line.
# The first entry is the default (the per-version landing page redirects to it).
# The docs CI workflow reads this file to decide which languages to build and
# lists them in the per-version languages.json the language switcher reads.
# 'en' is the source language; others are gettext translations under
# docs/source/locale/<code>/. Keep in sync with LANGUAGES in docs/Makefile.
en
ja
1 change: 1 addition & 0 deletions docs/requirements.txt
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
sphinx==7.4.7
furo==2024.8.6
sphinx-intl==2.3.1
45 changes: 45 additions & 0 deletions docs/source/_static/language-switcher.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
/* Floating multi-language switcher injected by language-switcher.js.
Mirrors version-switcher.css and sits directly above the version switcher
in the bottom-left corner. Uses Furo's CSS variables so it adapts to
light/dark mode automatically, with sensible fallbacks under other themes. */
.language-switcher {
position: fixed;
bottom: 3.6rem; /* stacked above the version switcher (bottom: 1rem) */
left: 1rem;
z-index: 30;
display: flex;
align-items: center;
gap: 0.4rem;
padding: 0.35rem 0.6rem;
font-size: 0.8rem;
border-radius: 0.4rem;
background: var(--color-background-secondary, #f4f4f5);
color: var(--color-foreground-primary, #1a1a1a);
border: 1px solid var(--color-background-border, #d0d0d0);
box-shadow: 0 1px 4px rgba(0, 0, 0, 0.15);
}

.language-switcher__label {
font-weight: 600;
white-space: nowrap;
}

.language-switcher__select {
font: inherit;
padding: 0.1rem 0.3rem;
border-radius: 0.25rem;
background: var(--color-background-primary, #ffffff);
color: var(--color-foreground-primary, #1a1a1a);
border: 1px solid var(--color-background-border, #d0d0d0);
cursor: pointer;
}

/* Keep the switcher out of the way on narrow screens, staying stacked above
the version switcher (which moves to bottom: 0.5rem at this breakpoint). */
@media (max-width: 46em) {
.language-switcher {
bottom: 3rem;
left: 0.5rem;
font-size: 0.75rem;
}
}
107 changes: 107 additions & 0 deletions docs/source/_static/language-switcher.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
// Multi-language documentation switcher for ALAMODE.
//
// Companion to version-switcher.js. It derives the published layout from its
// own URL and reads the per-version languages.json manifest emitted by the
// deploy workflow:
//
// <site root>/<version>/languages.json -> ["en", "ja"]
// <site root>/<version>/<lang>/... -> the built docs for each language
//
// This file lives at <site root>/<version>/<lang>/_static/language-switcher.js.
// Switching language stays within the current version (every language a
// version declares is built for that version, so the target always exists).
//
// Only versions that ship translations carry a languages.json, so on English-
// only versions (or local builds) the manifest is absent and no switcher is
// shown -- the page is unaffected.
(function () {
"use strict";

// Display names for language codes. Codes without an entry fall back to the
// raw code, so a new language renders (just untranslated) before it is added.
var LANG_LABELS = {
en: "English",
ja: "日本語", // 日本語
fr: "Français",
de: "Deutsch",
es: "Español",
zh: "中文", // 中文
ko: "한국어", // 한국어
};

var thisScript = document.currentScript;
var MARKER = "/_static/language-switcher.js";

function labelFor(code) {
return Object.prototype.hasOwnProperty.call(LANG_LABELS, code)
? LANG_LABELS[code]
: code;
}

function start() {
if (!thisScript || thisScript.src.indexOf(MARKER) === -1) {
return; // Unexpected layout; fail quietly rather than break the page.
}
// langRoot = <site root>/<version>/<lang>
// versionRoot = <site root>/<version>
var langRoot = thisScript.src.slice(0, thisScript.src.indexOf(MARKER));
var versionRoot = langRoot.slice(0, langRoot.lastIndexOf("/"));
if (!versionRoot) {
return; // Layout shallower than expected; bail rather than guess.
}
var current = decodeURIComponent(langRoot.slice(langRoot.lastIndexOf("/") + 1));

fetch(versionRoot + "/languages.json", { cache: "no-cache" })
.then(function (resp) { return resp.json(); })
.then(function (languages) { render(languages, versionRoot, current); })
.catch(function () { /* manifest missing: English-only or local build */ });
}

function render(languages, versionRoot, current) {
// Nothing to switch between unless there are at least two languages.
if (!Array.isArray(languages) || languages.length < 2) {
return;
}

var box = document.createElement("div");
box.className = "language-switcher";

var label = document.createElement("label");
label.className = "language-switcher__label";
label.textContent = "Language";
label.setAttribute("for", "language-switcher-select");

var select = document.createElement("select");
select.id = "language-switcher-select";
select.className = "language-switcher__select";

languages.forEach(function (entry) {
var code = typeof entry === "string" ? entry : entry.code;
var option = document.createElement("option");
option.value = code;
option.textContent = labelFor(code);
if (code === current) {
option.selected = true;
}
select.appendChild(option);
});

select.addEventListener("change", function () {
// Stay in the current version; jump to the chosen language's landing page.
// Same-page paths are not guaranteed to exist across languages, so the
// language root is the safest target.
window.location.href =
versionRoot + "/" + encodeURIComponent(select.value) + "/";
});

box.appendChild(label);
box.appendChild(select);
document.body.appendChild(box);
}

if (document.readyState === "loading") {
document.addEventListener("DOMContentLoaded", start);
} else {
start();
}
})();
Loading
Loading