Multi-Language
Baan has first-class multi-language support — not an afterthought plugin. Each article can have separate Markdown files per locale, URLs include the locale prefix, and the admin UI itself is available in multiple languages. AI-assisted translation can draft translated versions of your posts with one click.
What’s Supported
Section titled “What’s Supported”| Details | |
|---|---|
| Content locales | ja, en, es, pt-BR, zh-TW, ko, vi, id, th, fr, de (11 languages) |
| Admin UI languages | English, Japanese, Spanish, Portuguese, Traditional Chinese, Korean, Vietnamese, Indonesian, Thai, French, German (11 languages) |
| Translation assistant | AI drafts translations using your configured AI provider |
lang attribute | <html lang> is automatically updated to match the current locale on both the public site and admin panel |
Single-Language vs Multi-Language Mode
Section titled “Single-Language vs Multi-Language Mode”Single-Language Mode (default)
Section titled “Single-Language Mode (default)”Articles are stored as index.{defaultLocale}.md (e.g. index.en.md) and served without a locale prefix in the URL:
https://your-blog.com/posts/my-articleUse this mode if your blog is in one language only.
Multi-Language Mode
Section titled “Multi-Language Mode”Articles are stored as index.ja.md, index.en.md, etc. and served with a locale prefix:
https://your-blog.com/ja/posts/my-articlehttps://your-blog.com/en/posts/my-articleEach locale version is independent — you can publish the Japanese version while the English version is still a draft.
How to Enable Multi-Language Mode
Section titled “How to Enable Multi-Language Mode”- Go to Admin → Settings → Language
- Toggle Multi-language mode on
- Set your default locale (used when no locale is specified in the URL)
- Select which locales to enable from the 11 available
- Save
Switching Modes with the CLI
Section titled “Switching Modes with the CLI”If you use baan sync and switch from single-language to multi-language mode:
-
Do not clear sync state (
~/.baan/sync/) before switching. The state stores the locale for each file — preserving it lets the CLI continue tracking files that were synced without a locale suffix. -
Rename vault files to add locale suffixes after switching. Files without suffixes are skipped with a warning in multi-language mode:
Terminal window # rename: my-article.md → my-article.en.mdmv my-article.md my-article.en.md -
If you cleared state before renaming, run
baan synconce after renaming — the CLI will attempt to create the articles, detect they already exist (409), and re-record them in state automatically.
Writing Multilingual Articles
Section titled “Writing Multilingual Articles”In the Built-in Editor
Section titled “In the Built-in Editor”When multi-language mode is enabled, the post editor shows a locale selector tab. Switch between locales to write or edit each language version of the same article.
With the AI Translation Assistant
Section titled “With the AI Translation Assistant”- Open an article that has at least one locale version written
- Switch to the target locale tab
- Click Translate with AI — Baan drafts the translation using your configured AI provider
- Review and edit the draft, then publish when ready
With External Editors (Baan CLI)
Section titled “With External Editors (Baan CLI)”In multi-language mode, every Markdown file must declare its locale — either via a filename suffix (.en.md) or a locale: field in frontmatter. The CLI reads language settings from Admin at sync time — Admin is always the source of truth.
There are two supported styles:
Style 1: Locale suffix in filename — append the locale code before .md. Works with any editor.
vault/├── my-article/│ ├── my-article.en.md ← article ID: my-article, locale: en│ ├── my-article.ja.md│ └── images/│ └── hero.jpg ← shared across all localesStyle 2: Title-based filename + frontmatter locale: — ideal for Obsidian, where locale suffixes interfere with internal links and wikilinks.
vault/├── Getting Started with Node.js/│ ├── Getting Started with Node.js.md ← locale: en (in frontmatter)│ ├── Node.js 入門.md ← locale: ja (in frontmatter)│ └── images/│ └── hero.jpg---title: Getting Started with Node.jslocale: endate: 2026-04-01---Both styles can coexist in the same vault. Frontmatter locale: takes priority over the filename suffix when both are present.
Syncing all locales at once:
baan sync ./vault # syncs all locale filesbaan sync ./vault --locale en # syncs only files whose locale resolves to "en"Images are shared across all locale versions — upload once, referenced by all.
Language Settings
Section titled “Language Settings”In Admin → Settings → Language you can configure:
| Setting | Description |
|---|---|
| Multi-language mode | Toggle on/off |
| Default locale | The locale served when no prefix is in the URL |
| Enabled locales | Which of the 11 locales are active on your site |
| Language Priority | Whether to follow the visitor’s browser language or always use the site default |
| Admin UI language | The language of the admin panel (per-user setting) |
Language Priority
Section titled “Language Priority”When multi-language mode is enabled, a Language Priority section appears at the bottom of the Language settings page. This controls what happens when a visitor accesses the root path (/):
| Option | Behavior |
|---|---|
| Use site default language (default) | All visitors are directed to the configured default locale, regardless of browser settings |
| Follow browser language | Visitors are redirected to their browser’s preferred language if it is supported |
Default is “Use site default language” — if your default locale is en, visiting / will always go to /en. This is the most predictable behavior for most sites.
SEO in Multi-Language Mode
Section titled “SEO in Multi-Language Mode”lang attribute
Section titled “lang attribute”Baan automatically sets the lang attribute on the <html> element to match the current locale:
- Public site — An inline script in the locale layout sets
langsynchronously as the page is parsed, before any content is rendered. This means SSR, SSG, and ISR pages all have the correctlangfrom the very first render —/en/...pages havelang="en",/ja/...pages havelang="ja", and so on. A client-side component keepslangin sync during client-side navigation. - Admin panel —
langreflects the admin UI language selected by the current user (stored inlocalStorage), and is updated immediately when the user switches languages.
hreflang tags
Section titled “hreflang tags”When multi-language mode is enabled, Baan automatically outputs hreflang link tags in the <head> of each page, pointing search engines to the equivalent page in each available locale. This tells Google and other search engines which version to show to which audience.
<link rel="alternate" hreflang="ja" href="https://your-blog.com/ja/posts/my-article" /><link rel="alternate" hreflang="en" href="https://your-blog.com/en/posts/my-article" /><link rel="alternate" hreflang="x-default" href="https://your-blog.com/ja/posts/my-article" />x-default points to the default locale configured in Admin → Settings → Language.
For article pages, hreflang tags are only output for locales where a translated version of the article actually exists — locale versions that have not been written are excluded.