Hi team, I build a website with Hugo, the website has a documentation section, each document has a different version, users can choose to view the documents corresponding to different versions. How to display the corresponding version number when switching to a version, just like a drop-down list?
You can either create subfolders in content folder for each version like :
Content
-- version1
-- version2
or you may use separate subdomains for every version of whole documentation.
In Docsy theme, they provide version selector, but even there you would require your own strategy to host versions.
Also, a similar issue is resolved as per this comment, where the every version is deployed in a separate git branch.
We really need an out-of-the-box solution for versions.
Docsy’s git branch approach works - I guess - but has a major drawback - the versions menu definition is bound to a branch, meaning you need to redeploy all previous versions every time you deploy a new version. Otherwise their version menus will not show the latest version. The problem will worsen the more versions you deploy. Or you can try to come up with a workaround to patch the older versions’ hugo.yaml
files directly on the web server, which could be messy.
Another drawback of the git branch approach is you loose reusability. If I wanted to reuse content between versions (which is more than likely), I wouldn’t be able to. Changing a single typo in common content would again mean redeploying all previous versions, plus the manual work of changing the content in multiple branches.
With the added complexity of:
- Multilingual sites (now we have another dimension)
- Filling vertically (versions)
- Filling horizontally (languages)
True, but all the Static Site Generators cover the basics. The things that make a difference include:
- Advanced features like multi-lingual and versions
- Architecture–you want it to be as flexible as possible to be able to implement any features not offered natively
And while having a flexible architecture is great, some cornerstone features are simply not feasible as shortcodes/plugins. Versioning is one of them.
Hi @gvaley, I never had time to write up how it works, but with some customizations we made something like what you describe at GitHub - kube-logging/kube-logging.github.io: Logging operator documentation .
It’s been a while so I won’t remember every detail, but:
- the versions each have their own branch and their own github workflow, so they can be deployed independently
- there is some magic using a custom output called
releases
that generates the list for the version dropdown on main, based on the versions list that you define in the config.toml, docsy-style. - every version includes that list using some js (see kube-logging.github.io/layouts/partials/navbar-version-selector.html at master · kube-logging/kube-logging.github.io · GitHub, kube-logging.github.io/layouts/partials/navbar-version-selector.release at master · kube-logging/kube-logging.github.io · GitHub, )
- there is a customization that if a page exists in main, then it sets the canonical url to the latest release (kube-logging.github.io/layouts/partials/hooks/head-end.html at e25e1fbd8c9d9dd80f397bd0199720c66f21a85c · kube-logging/kube-logging.github.io · GitHub)
- The workflows of the separate versions publish their output under
baseurl/versionnumber/docs/
- The latest version (published by the main workflow) is under
baseurl/docs/
It’s probably somewhat overengineered, but seemed a good idea at the time.
I know that some of the approaches in the wild were implemented before modules and/or segmentation became available. Just thinking out loud, a couple of questions for all…
With multilingual sites, are you currently translating by file (e.g., foo.de.md
) or by directory (e.g., content/de/foo.md
)?
If you are translating by directory, would you be willing to translate by file for future projects, or to convert an existing site in the same way?
Translating by file has some advantages:
- It’s easy to see when translated content is missing.
- It’s easy to see which resources are shared or potentially missing.
content/
├── common/
│ ├── go.mod
│ ├── snippet-1.en.md
│ ├── snippet-1.de.md
│ ├── snippet-2.en.md
│ └── snippet-2.de.md
├── v1/
│ ├── tutorials/
│ │ ├── tutorial-1/
│ │ │ ├── index.de.md
│ │ │ ├── index.en.md
│ │ │ ├── photo.de.jpg
│ │ │ └── photo.en.jpg
│ │ ├── tutorial-2/
│ │ │ ├── index.en.md <-- where's the de version?
│ │ │ └── photo.en.jpg <-- shared resource, should there be a de version?
│ │ ├── _index.de.md
│ │ └── _index.en.md
│ ├── _index.de.md
│ ├── _index.en.md
│ └── go.mod
└── v2/
├── _index.de.md
├── _index.en.md
└── go.mod
If the structure above is acceptable, a mono repo with multiple modules (including content that’s shared across versions) and (possibly) segmented builds might be a decent approach.
Appreciate the discussion.
Off the top of my head, this structure immediately introduces an issue: If we have to name resources differently for each lang, this means redoing all links to those resources inside the MD…unless we have an intelligent mechanism that automatically translates a photo.md
target to photo.de.md
, photo.en.md
according to the current lang.
As a smaller drawback, it makes the tree harder to browse, especially in the presence of dozens of languages.
If I had to choose, I’d have separate folders.
My 2 cents on your other points:
- Personally, I wouldn’t warry about missing resources in one lang or another, as Hugo will report them missing when running server or build.
- This spurred a thought in my mind - wouldn’t it be nice to show a default language (say, EN) when a translation is missing in a language? This would also help with broken links issues when an article is completely missing.
You don’t.
https://gohugo.io/content-management/multilingual/#page-bundles
No, it won’t. See above.
You can use module mounts for content, and lang.Merge for page collections.