The docmd 0.7.0 release is a major step forward — introducing native multi-language support (i18n) with a built-in translation system and true zero-config defaults where all core plugins are active out-of-the-box.
✨ Highlights
🌍 Internationalisation (i18n)
docmd now has first-class i18n support. Configure multiple locales and docmd builds a complete, localised version of your site for every locale — with locale-first URLs (/hi/, /zh/), translated UI strings, and automatic language detection.
Every locale lives in its own subdirectory — including the default language. This keeps your source directory clean and makes the structure easy to understand at a glance:
docs/
en/ ← default locale (renders at /)
hi/ ← Hindi (renders at /hi/)
zh/ ← Chinese (renders at /zh/)
The locale IDs, folder names, and default language are entirely your choice — en, hi, fr, de, or any identifier you prefer.
// docmd.config.js
export default {
i18n: {
default: 'en',
locales: [
{ id: 'en', label: 'English' },
{ id: 'hi', label: 'हिन्दी' },
{ id: 'zh', label: '中文' },
]
}
}
This includes Per-Locale Search Indexes spanning across your versions automatically, along with translated UI components for official plugins like Search and Threads!
🚀 Zero-Config Core Plugins
In 0.7.0, docmd embraces a true zero-config philosophy. All official core plugins (search, seo, sitemap, pwa, analytics, llms, mermaid) are now auto-included by default. You no longer need to declare them manually in your plugins array to use them.
If you want to disable a core plugin, you can now simply mark it as false:
export default {
plugins: {
search: false // Disables the automatically included search plugin
}
}
📝 Complete Changelog
🌍 i18n Architecture
- Clean locale directories: Every locale (including the default) lives in its own subdirectory inside
src. No more mixing locale folders alongside content folders. - Locale-first URL generation: Build loop now builds nested directories for each configured locale.
- Per-file fallback: Non-default locales inherit pages from the default locale when a translation is missing, with an automatic warning callout.
- Per-locale navigation: Each locale directory can have its own
navigation.json, falling back to the default locale’s navigation when absent. - Versioning + i18n: Old versions without locale directories are rendered in the default locale only. Add a locale subdirectory to any old version to enable translations for it.
- Translated UI strings: Native translation system across all UI elements and templates. Handlers resolved against JSON locale files (
en.json,hi.json,zh.json) — all template strings accessible via a fastt('key')helper. - Plugin i18n API: Plugins now support a new
translations(localeId)hook alongside ani18n/directory convention for client-side strings. - Global Search Locales: The local MiniSearch index is now built per-locale, dynamically rendering version badges based on context, and gracefully providing localised search results.
- Zero-footprint fallback: Sites with no
i18nblock build identically to pre-0.7.0 — no path or output changes overhead. - String Mode (
stringMode: true): A new i18n mode for noStyle pages — generate locale-specific HTML from a single source file. Adddata-i18nattributes to your HTML, place translation files inassets/i18n/{locale}.json, and docmd clones the rendered output with server-side string replacement at build time. Produces fully translated, SEO-indexable pages at/{locale}/paths. Supportsdata-i18n(textContent),data-i18n-html(innerHTML), anddata-i18n-{attr}(attribute values). Missing translation files gracefully fall back to the default language. Designed for noStyle/HTML pages only — markdown documentation should use directory mode. - Client-side i18n for noStyle pages: A lightweight
docmd-i18n-strings.jsmodule is auto-injected when i18n is configured. Provides a runtimeswitchLocale()API,inPlacemode for SPAs, and adocmd:i18n-appliedevent for custom language switchers.
🔌 Plugin System & Engine
- Core plugins auto-activation: Zero-config defaults automatically provide the complete docmd suite without config overhead.
- Asset generation optimizations: Restructured asset pipeline so that static CSS, JS, and global configurations are built exactly once to the root, regardless of how many locales or versions are active.
🎨 UI & Containers
- Container
icon:parameter: Callouts, cards, collapsible sections, and buttons now accept anicon:parameter to render a Lucide icon inline with the title. Icons are vertically centred and properly sized using flexbox alignment.::: card "Setup" icon:rocket ::: button "Get Started" /start icon:arrow-right titleAppendfrontmatter option: Pages can now settitleAppend: falsein frontmatter to suppress the automatic— Site Titlesuffix in the<title>tag. Useful for homepages and landing pages.- Pill-style version & language switchers: The version dropdown and language switcher in the sidebar now render as compact pill buttons that sit side-by-side on the same line, saving vertical space. Shared CSS classes ensure consistent sizing across both components.
- Language switcher version awareness: When browsing an old version that has no translations, non-default locales are visually disabled in the language switcher with an “N/A” badge, preventing broken navigation to non-existent pages.
- Translatable “(Latest)” badge: The current version now displays an auto-generated, translatable “Latest” badge in the version dropdown. No longer hardcoded in the config label — uses the built-in translation system.
- Search result version badges: Search results now display version badges as color-coded pills aligned to the right of the result title. Each version gets a deterministic color generated at build time for easy visual identification.
- Responsive language pill: When both version and language pills are present, the language label auto-hides on standard sidebars and only shows the globe icon, expanding to show the label on wider screens.
- Dev server config hot-reload: Changes to
docmd.config.jsnow trigger a full rebuild duringdocmd devwithout requiring a manual restart. File watcher correctly detects config file changes on all platforms.
🐛 Bug Fixes
- Versioning + i18n conflict: Old version directories without locale subdirectories were being duplicated across all locales. Now correctly rendered for the default locale only — non-default locales skip versions that have no translations.
- Ghost locale pages in old versions: Locale subdirectories inside old version directories (e.g.
docs-v1/hi/) were rendered as regular content pages during the default locale pass, producing duplicate URLs. Fixed by filtering known locale directory names during the scan. - Navigation warning false positive: The “No navigation settings found” message was shown even when
navigation.jsonexisted inside locale or version directories. Now silent when navigation is available in any locale or version directory. - Auto-nav scanning wrong directory: When i18n is enabled, the auto-navigation builder was scanning the source root (which only contains locale directories), generating incorrect navigation from folder names. Now scans the default locale’s directory instead.
<title>tag missing site name: Pages without an explicit title produced empty title tags. The template now auto-appends the site title with an em-dash separator (Page — Site), and the homepage shows just the site title.- Language switcher URL duplication on old versions: Switching language while browsing a non-current version produced URLs with the version prefix duplicated (e.g.
/zh/06/06/page). Fixed by stripping the version prefix from the page path before rebuilding the locale URL.
🧪 Quality Assurance
The 0.7.0 release passes a comprehensive brute test suite covering 25 distinct scenarios with 85 individual assertions — all green. Every major feature is tested both in isolation and in combination:
View full test coverage
| # | Scenario | Assertions |
|---|---|---|
| 1 | Zero-config (no config file) | 5 |
| 2 | Zero-config with nested directories | 4 |
| 3 | i18n standalone (non-English default) | 5 |
| 4 | Versioning standalone (no i18n) | 5 |
| 5 | i18n + versioning combined | 6 |
| 6 | Old version with partial translations | 4 |
| 7 | Missing locale dir (graceful skip) | 3 |
| 8 | Navigation resolution priority | 2 |
| 9 | Frontmatter parsing | 3 |
| 10 | Containers (callout, tabs, steps, hero) | 5 |
| 11 | Code blocks (JS, Python) | 3 |
| 12 | Custom CSS/JS injection | 3 |
| 13 | Edit links | 3 |
| 14 | No-style pages | 3 |
| 15 | Search index generation | 3 |
| 16 | Sitemap generation | 3 |
| 17 | EJS content pages | 3 |
| 18 | README.md as index fallback | 4 |
| 19 | .markdown file extension |
3 |
| 20 | Deep nested structure (4+ levels) | 2 |
| 21 | Zero-config auto-nav accuracy | 3 |
| 22 | Title tag auto-append | 2 |
| 23 | Open Graph meta tags | 3 |
| 24 | Redirects | 3 |
| 25 | Per-page layout override | 3 |
All 13 internal failsafe checks also pass. The brute test script is included in scripts/brute-test.js for anyone to run locally.
⚠️ Breaking Changes
- Third-party plugin shorthand names are no longer resolved — you must use the full package name if you are importing third-party plugins. (
search,threads, etc., are reserved strictly for@docmd/plugin-*). pnpm onboardremoved — theonboardscript has been merged intopnpm prep. Usepnpm prepfor full environment setup andpnpm prep --link(orpnpm verify --link) to also linkdocmdglobally.- PWA Plugin is now an optional plugin and no longer auto-included, if you want to add PWA to your docs, use
docmd add pwacommand.
Migration Guide
Upgrade by running npm install docmd@latest. Then:
- You may remove core plugins from your
pluginsarray if you were using them with default settings — they are now automatically enabled! - If you use third-party plugins by shorthand, update them to their full package name.
See Getting Started — Installation for a full walkthrough.