Skip to content

Latest commit

 

History

26 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

SDK Documentation Build Template

From structured Markdown to a versioned documentation site and deterministic PDF, with one configuration for local preview and GitHub Pages.

Build Documentation Python 3.11 Sphinx 8.1.3 MyST 4.0.1 PDF XeLaTeX Docs Chinese and English Use this template

English · 简体中文

This repository is designed for SDKs, hardware platforms, robotics systems, and other developer-facing technical documentation. Authors maintain only the Markdown, reStructuredText, and image assets under projects/; the build system discovers languages, generates navigation, isolates Chinese and English builds, typesets PDFs, manages versions, and publishes the static site.

It is more than a Markdown-to-HTML script. Content structure, site information architecture, bilingual routing, PDF fonts, and the CI environment are governed by the same verifiable build contract so local previews and remote outputs stay aligned.

Quick start · Core design · Content model · Configuration · PDF · Versions · Troubleshooting

Core design

Goal Current mechanism
Separate content from tooling projects/ contains documentation; source/ contains the build system; a manifest owns synchronized copies
Support two content models Document trees preserve directory READMEs; project catalogs select only entry READMEs and declared assets
Keep every output on one catalog Synchronization, language detection, HTML navigation, and PDF scanning share one DocumentCatalog
Enable bilingual UI only when valid Chinese-only, English-only, and bilingual repositories are detected automatically; the switch appears only for bilingual builds
Keep outputs reproducible Python versions are pinned, and PDF builds require XeLaTeX plus exact fonts with no silent fallback
Align local and CI builds Local builds and GitHub Actions use the same configuration, font roles, and PDF path
Isolate documentation versions Every configured Git branch is built in its own worktree without switching the primary working directory

Outputs

  • A static documentation site built with Sphinx 8 and the Read the Docs Theme.
  • Markdown, tables, math, task lists, and extended syntax through MyST Parser.
  • Isolated search indexes and static assets for Chinese and English, with exact counterpart links.
  • Chinese and English PDFs generated by XeLaTeX with a cover, contents, page numbers, bookmarks, and article page breaks.
  • Consistent PDF treatment for code blocks, inline code, tables, links, images, and WebP assets.
  • Multi-version navigation and GitHub Pages deployment driven by .github/versions.json.
  • Optional giscus comments, edit links, dark styling, a version menu, and PDF downloads.

Quick start

Requirements

Scenario Required environment
HTML build Python 3.11 recommended; Python packages can be installed automatically
PDF build XeLaTeX and every font declared in source/config.yaml
Multi-version build Git and locally accessible branches referenced by .github/versions.json

1. Create a local environment

git clone https://github.com/kurisaW/sdk_build_doc_template.git
cd sdk_build_doc_template
python -m venv .venv
# Windows PowerShell
.\.venv\Scripts\Activate.ps1
cd source
python build_local.py --check
# Linux/macOS
source .venv/bin/activate
cd source
python build_local.py --check

--check validates both package availability and the exact versions pinned in requirements.txt. Missing packages are installed by default; add --no-auto-install for a read-only check.

2. Add project documentation

projects/
`-- getting_started/
    |-- README_zh.md
    |-- README.md
    |-- install_zh.md
    |-- install.md
    `-- figures/
        `-- installation.png

Chinese documents use the _zh suffix. English documents use the same base name without _zh. Update the project metadata, categories, and ordering in source/config.yaml, then build.

3. Build and preview

cd source
python build_local.py --clean --serve

Open http://localhost:8000. Final artifacts are written to:

source/_build/html/index.html
source/_build/html/_static/<project.name>.pdf
source/_build/html/_static/<project.name>_EN.pdf   # generated when English is detected

Skip PDF generation during routine web content review:

python build_local.py --clean --no-pdf --serve

Build pipeline

projects/ + repository README
                |
                v
        language detection
                |
                v
        doc_generator.py
   sync sources + create navigation
                |
        +-------+-------+
        |               |
        v               v
  Sphinx HTML      Sphinx LaTeX
  zh/en isolated       + XeLaTeX
        |               |
        +-------+-------+
                v
       source/_build/html/

A local build performs the following steps:

  1. Validate pinned Python dependencies and install missing packages through an available package index.
  2. Synchronize allowed documents and assets from projects/ into the Sphinx source directory.
  3. Synchronize the shared document catalog and generate language-specific navigation.
  4. Build Chinese and English HTML independently, then merge them into one site.
  5. Generate one or two PDFs according to the detected languages and validate each output file.
  6. Remove synchronized copies, LaTeX files, doctrees, and build metadata while retaining final HTML and PDFs.

Content model

Source layout

.
|-- projects/                         # Primary documentation source of truth
|   |-- README_zh.md                  # Optional: projects Chinese home/language marker
|   |-- README.md                     # Optional: projects English home/language marker
|   `-- <section>/
|       |-- README_zh.md              # Optional: Chinese directory landing page
|       |-- README.md                 # Optional: English directory landing page
|       |-- <topic>_zh.md             # Chinese article
|       |-- <topic>.md                # English article
|       `-- figures/                  # Image assets
|-- source/
|   |-- build_local.py                # Local single-version entry point
|   |-- build.py                      # Multi-version entry point
|   |-- build_manager.py              # Worktree and version orchestration
|   |-- doc_generator.py              # Synchronization and navigation generation
|   |-- config.yaml                   # Project configuration
|   |-- conf.py                       # Sphinx and LaTeX configuration
|   |-- requirements.txt              # Pinned dependencies
|   |-- tests/                        # Build mechanism tests
|   |-- utils/                        # Build modules
|   |-- _static/                      # Website assets
|   `-- _templates/                   # Page templates
|-- .github/versions.json             # Version definitions
|-- .github/workflows/build-docs.yml  # CI and Pages deployment
|-- README_zh.md                      # Chinese repository README/home fallback
`-- README.md                         # English repository README/home fallback

projects/ is the content source of truth. Do not edit same-named directories or READMEs that appear under source/ during a build; they are tracked by .doc_generator_manifest.json and cleaned automatically.

Language naming

Document type Chinese English
Site or directory home README_zh.md README.md
Markdown article <name>_zh.md <name>.md
reStructuredText article <name>_zh.rst <name>.rst

Counterpart pages should be placed in the same directory and share the same base name. For example, install_zh.md pairs with install.md. In a bilingual site, the switch falls back to the target-language home page when an exact counterpart does not exist.

Language detection precedence

generation.language_detection uses README_zh.md and README.md as markers by default. recursive_tree follows this precedence:

  1. If either marker exists at the root of projects/, those root markers are authoritative and completely determine the available languages.
  2. If no marker exists at the root of projects/, repository-root READMEs and directory READMEs are inspected together.
  3. A single detected language produces a single-language site with no language switch.
  4. Detecting both Chinese and English produces isolated bilingual builds and enables the switch.
  5. With no marker anywhere, PDF generation stops with an explicit language-detection error.

Consequently, projects/README_zh.md without projects/README.md keeps the site Chinese-only even when an English README exists deeper in the tree. This prevents a partial translation from exposing an incomplete bilingual site.

project_catalog counts only selected project entry READMEs plus home READMEs at projects_dir or repository root. Individual projects may provide partial language coverage; the bilingual site and switch are enabled when the final catalog contains both languages. Vendor packages, board sources, and unselected nested READMEs never affect language detection.

Site home precedence

Each language resolves its home page independently:

generation.default_page
          |
          | missing
          v
repository-root README fallback
          |
          | missing
          v
generated language index
  • generation.default_page is relative to repository.projects_dir; absolute paths and .. are rejected.
  • Repository-root README fallback is enabled only when the root of projects/ has no language README at all.
  • The fallback README is copied to a manifest-owned temporary location. The repository source file is never modified.
  • Markdown, MyST, RST, and HTML image references in a fallback README are resolved and synchronized with the same relative URLs. Missing images and path escapes fail the build.

Discovery and navigation modes

Source selection and navigation are separate concerns:

Repository shape generation.discovery.mode generation.navigation.mode Behavior
Tutorials, manuals, knowledge bases recursive_tree directory_tree Recursively synchronize supported files and use directory READMEs as section homes
SDK/BSP example collections project_catalog categories Synchronize only selected project-root READMEs and asset_globs, then group them by category

In project_catalog, patterns without / match only first-level directories under projects_dir; nested project roots require an explicit relative path such as dual_core/core0. The build fails on empty pattern matches, duplicate category matches, projects without an entry README, unknown navigation categories, path escapes, and missing or unsynchronized README images.

HTML, language detection, source synchronization, and PDF scanning all consume the same DocumentCatalog, preventing the website from showing only project pages while PDF independently pulls in vendor READMEs.

One README per directory

For every directory and language, the landing page is selected in this order:

  1. The README configured by generation.directory_index.
  2. An existing index_zh.rst / index.rst, or the corresponding Markdown index.
  3. A generated language-specific index.

This rule applies to recursive_tree. A directory README may contain an introduction or only a level-one heading. The generator appends a hidden toctree only to its synchronized copy. In PDF output, a navigation README contributes its level-one heading but not its body; if the README is the directory's only document, it is treated as a standalone article. In project_catalog, a project-root README is project content: its project title and body are both retained in PDF.

Ordering and headings

  • Top-level sections follow generation.navigation.order; configured but unlisted categories are appended naturally. generation.output_structure remains a legacy compatibility key.
  • Documents are naturally sorted by path. Prefixes such as 01_ and 02_ provide stable explicit ordering.
  • categories.<path>.name and name_en control generated page and PDF section labels.
  • Each article should normally contain one level-one heading without duplicating its filename prefix.
  • Common manual heading numbers are stripped only for LaTeX output; HTML and source Markdown remain unchanged.

Configuration

Start from a complete template in source/config_templates/: use recursive_tree.yaml for documentation repositories and project_catalog.yaml for SDK/BSP example collections.

The following configuration covers directory-tree generation, bilingual homes, section ordering, and strict PDF fonts:

project:
  name: "Example_SDK"
  title: "Example SDK Developer Documentation"
  title_en: "Example SDK Documentation"
  description: "Example SDK development, integration, and debugging documentation."
  description_en: "Development, integration, and debugging documentation for Example SDK."
  version: "1.0.0"
  author: "Example Team"
  copyright: "2026, Example Team"
  website: "https://example.com"

repository:
  name: "example-sdk-docs"
  projects_dir: "../projects"
  docs_dir: "."

categories:
  getting_started:
    name: "快速上手篇"
    name_en: "Getting Started"
    description: "环境准备和首个示例。"
    description_en: "Environment setup and first example."
  applications:
    name: "应用篇"
    name_en: "Applications"

generation:
  mode: "directory_tree"
  discovery:
    mode: "recursive_tree"
  navigation:
    mode: "directory_tree"
    order:
      - "getting_started"
      - "applications"
  language_detection:
    zh: "README_zh.md"
    en: "README.md"
  default_language: "zh"
  default_page:
    zh: "README_zh.md"
    en: "README.md"
  directory_index:
    zh: "README_zh.md"
    en: "README.md"
  sync_extensions:
    - ".md"
    - ".rst"
    - ".png"
    - ".jpg"
    - ".jpeg"
    - ".gif"
    - ".svg"
    - ".webp"
  pdf_style: "web"
  pdf_fonts:
    latin: "TeX Gyre Termes"
    cjk_body: "FandolSong-Regular.otf"
    cjk_heading: "FandolHei-Regular.otf"
    cjk_emphasis: "FandolKai-Regular.otf"
    code: "Source Code Pro"

sphinx:
  theme: "sphinx_rtd_theme"
  extensions:
    - "myst_parser"
  source_suffix:
    ".rst": "restructuredtext"
    ".md": "markdown"

giscus:
  enabled: false
Setting Purpose
project.name Project identifier, PDF filename, and default PDF cover title
project.title HTML site title
project.title_en Optional title used by a generated English home page
project.description / description_en Generated home description and localized PDF cover summary
repository.projects_dir Documentation source directory, relative to source/config.yaml
repository.docs_dir Sphinx source directory; normally .
generation.discovery.mode recursive_tree for a document tree or project_catalog for a strict project catalog
generation.navigation.mode directory_tree for source directories or categories for configured groups
generation.navigation.order Preferred top-level directory or category order
generation.default_language Preferred language; an actually detected language is selected when unavailable
generation.default_page Per-language site home, relative to projects_dir
generation.directory_index Per-language directory landing filename
generation.sync_extensions Document and asset suffixes allowed into the Sphinx source
generation.pdf_style web by default; thesis, graduate, or academic enables thesis preview parameters
generation.pdf_fonts Exact font assigned to each PDF text role
giscus.enabled Loads giscus when repository and category identifiers are also configured

Use strict project-catalog mode for an SDK/BSP example repository:

categories:
  basic:
    name: "基础篇"
    name_en: "Basics"
    patterns:
      - "Titan_basic_*"
  multicore:
    name: "多核通信篇"
    name_en: "Multicore Communication"
    patterns:
      - "Titan_dual_core/Titan_dual_core0"
      - "Titan_dual_core/Titan_dual_core1"

generation:
  mode: "project_catalog"          # Compatibility marker for older tooling
  discovery:
    mode: "project_catalog"
    entry_files:
      zh: "README_zh.md"
      en: "README.md"
    asset_globs:
      - "figures/**"
    unmatched_projects: "error"
    duplicate_categories: "error"
  navigation:
    mode: "categories"
    order:
      - "basic"
      - "multicore"

Local build

Run these commands from source/:

Command Purpose
python build_local.py Build HTML and PDF for the current working tree
python build_local.py --clean Remove old HTML and perform a complete rebuild
python build_local.py --serve Start a local static server after building
python build_local.py --serve --port 8080 Preview on a custom port
python build_local.py --no-pdf Build HTML only
python build_local.py --check Validate and, when needed, install Python dependencies
python build_local.py --check --no-auto-install Validate dependencies without installing
python build_local.py --check-branch Validate the current branch-to-version mapping

Dependencies and package indexes

Automatic installation probes PyPI, the Tsinghua mirror, and the Alibaba Cloud mirror concurrently, then ranks reachable indexes by latency. An existing PIP_INDEX_URL is tried first, followed by detected fallback indexes.

# Windows PowerShell
$env:DOCS_PIP_MIRROR = "tsinghua"  # auto | official | china | tsinghua | aliyun
python build_local.py --check

$env:DOCS_PIP_INDEX_URL = "https://your-mirror.example/simple/"
python build_local.py --check
# Linux/macOS
DOCS_PIP_MIRROR=official python build_local.py --check
DOCS_PIP_INDEX_URL=https://your-mirror.example/simple/ python build_local.py --check

PDF build

PDF generation has one supported path: Sphinx LaTeX -> XeLaTeX. It does not fall back to browser printing or another engine, preventing silent differences between local and CI layouts.

Default fonts

Text role Font
English, numbers, and other Latin text TeX Gyre Termes
Chinese body text FandolSong-Regular.otf
Chinese headings FandolHei-Regular.otf
Chinese emphasis FandolKai-Regular.otf
Code blocks Source Code Pro

Validate the toolchain independently:

cd source
python utils/pdf_environment.py --no-auto-install

The local script can attempt to install system dependencies through apt-get on Linux, Homebrew on macOS, or Chocolatey on Windows. This is best-effort and depends on system privileges and the package manager. Otherwise install TeX Live or MiKTeX manually and expose xelatex on PATH or in a supported standard location.

PDF layout rules include:

  • Generate Chinese and English PDFs according to detected languages; English filenames receive _EN.
  • Separate the cover and contents, retain centered page numbers, and show the project name in body headers.
  • Represent top-level directories as level-one bookmarks, articles as level-two bookmarks, and include headings through level three.
  • Start each regular article on a new page and keep directory README navigation prose out of the PDF.
  • Control first-line indentation, margins, paragraph spacing, heading spacing, and list spacing centrally in LaTeX.
  • Wrap table content to the text width; render code blocks with a monospaced font, restrained background, and controlled long-line wrapping.
  • Keep inline code at body size and use the body Latin font for English and numbers.
  • Convert WebP images to JPEG during LaTeX preparation for XeLaTeX compatibility.

Font names must match config.yaml exactly. The build fails when any font is unavailable and never substitutes a merely similar font.

Versions and GitHub Pages

.github/versions.json is the source of truth for documentation versions:

{
  "versions": [
    {
      "name": "main",
      "display_name": "latest",
      "branch": "main",
      "url_path": "latest",
      "description": "Latest development version"
    },
    {
      "name": "v1.0",
      "display_name": "v1.0",
      "branch": "v1.0",
      "url_path": "v1.0",
      "description": "Stable 1.0 documentation"
    }
  ],
  "default_version": "main",
  "latest_version": "main"
}

Every version requires name, display_name, branch, and url_path. Version maintenance commands:

cd source
python build.py --validate
python build.py --list-versions
python build.py --clean

build.py isolates branches with Git worktrees and writes the final site to source/source_build/html/. Use build_local.py for routine local preview to avoid unnecessary all-version builds.

GitHub Actions validates versions, installs dependencies, verifies XeLaTeX and fonts, builds all versions, uploads artifacts, and publishes gh-pages on Python 3.11/Ubuntu. The workflow watches source/**, projects/**, and .github/versions.json, and also supports manual workflow_dispatch runs.

Cleanup contract

python build_local.py --clean removes stale output before rebuilding, but never deletes documentation sources:

Preserved Removed automatically
All source files under projects/ Manifest-recorded synchronized copies under source/
Repository-root READMEs source/_build/latex/
Final site under source/_build/html/ source/_build/html/.doctrees/
PDFs under source/_build/html/_static/ source/_build/html/.buildinfo
Build scripts, configuration, templates, and static assets Empty synchronized directories and the generation manifest

Failed builds may retain intermediate files for diagnosis. Fix the cause and run python build_local.py --clean again.

Troubleshooting

Symptom What to check
No language detected for PDF Ensure a configured README marker exists in projects/, a document directory, or the repository root
Language switch is missing The authoritative detection result must include both README_zh.md and README.md
Switching returns to the other home page The current article has no same-path, same-base-name counterpart
Unexpected site home Check root markers in projects/, generation.default_page, and stale output
Python dependency installation fails Check proxy/certificates and set DOCS_PIP_MIRROR or DOCS_PIP_INDEX_URL
XeLaTeX or font validation fails Run python utils/pdf_environment.py --no-auto-install for the exact missing item
PDF has no body content Navigation READMEs do not become body articles when regular content is expected
Preview port is busy Run python build_local.py --serve --port 8081
Multi-version worktree fails Verify target branches, git worktree list, and the installed Git version

Validate dependencies without installation:

python build_local.py --check --no-auto-install

Install pinned dependencies manually:

python -m pip install -r requirements.txt

Development and verification

After changing the build system, run from source/:

python -m unittest discover -s tests -v
python build_local.py --check --no-auto-install
python build_local.py --clean
python build.py --validate

Ownership boundaries:

  • Documentation and images: projects/
  • Site and PDF configuration: source/config.yaml, source/conf.py
  • Build logic: source/*.py, source/utils/
  • Website styling and behavior: source/_static/, source/_templates/
  • Version definitions: .github/versions.json
  • CI and Pages deployment: .github/workflows/build-docs.yml

Do not commit generated _build/, source_build/, temporary LaTeX files, or synchronized source copies.

About

SDK Documentation Build Template

Resources

Stars

3 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages