Skip to content

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.

Details
Content localesja, en, es, pt-BR, zh-TW, ko, vi, id, th, fr, de (11 languages)
Admin UI languagesEnglish, Japanese, Spanish, Portuguese, Traditional Chinese, Korean, Vietnamese, Indonesian, Thai, French, German (11 languages)
Translation assistantAI 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

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-article

Use this mode if your blog is in one language only.

Articles are stored as index.ja.md, index.en.md, etc. and served with a locale prefix:

https://your-blog.com/ja/posts/my-article
https://your-blog.com/en/posts/my-article

Each locale version is independent — you can publish the Japanese version while the English version is still a draft.


  1. Go to Admin → Settings → Language
  2. Toggle Multi-language mode on
  3. Set your default locale (used when no locale is specified in the URL)
  4. Select which locales to enable from the 11 available
  5. Save

If you use baan sync and switch from single-language to multi-language mode:

  1. 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.

  2. 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.md
    mv my-article.md my-article.en.md
  3. If you cleared state before renaming, run baan sync once after renaming — the CLI will attempt to create the articles, detect they already exist (409), and re-record them in state automatically.


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.

  1. Open an article that has at least one locale version written
  2. Switch to the target locale tab
  3. Click Translate with AI — Baan drafts the translation using your configured AI provider
  4. Review and edit the draft, then publish when ready

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 locales

Style 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.js
locale: en
date: 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:

Terminal window
baan sync ./vault # syncs all locale files
baan sync ./vault --locale en # syncs only files whose locale resolves to "en"

Images are shared across all locale versions — upload once, referenced by all.


In Admin → Settings → Language you can configure:

SettingDescription
Multi-language modeToggle on/off
Default localeThe locale served when no prefix is in the URL
Enabled localesWhich of the 11 locales are active on your site
Language PriorityWhether to follow the visitor’s browser language or always use the site default
Admin UI languageThe language of the admin panel (per-user setting)

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 (/):

OptionBehavior
Use site default language (default)All visitors are directed to the configured default locale, regardless of browser settings
Follow browser languageVisitors 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.


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 lang synchronously as the page is parsed, before any content is rendered. This means SSR, SSG, and ISR pages all have the correct lang from the very first render — /en/... pages have lang="en", /ja/... pages have lang="ja", and so on. A client-side component keeps lang in sync during client-side navigation.
  • Admin panellang reflects the admin UI language selected by the current user (stored in localStorage), and is updated immediately when the user switches languages.

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.