Internationalization (i18n)

2026-06-20

Content Internationalization

Content is organized into directories by language code. When starting the preview, specify the language using the --lang parameter:

# Specify via parameter
everkm-publish serve --lang zh_CN

# Or specify via environment variable
export EVERKM_LANG=zh_CN
everkm-publish serve

For example, supporting two languages zh_CN and en_US, the directory structure is as follows:

<work_dir>/
├── zh_CN/
│   └── blog/
│       └── hello.md
├── en_US/
│   └── blog/
│       └── hello.md
└── __everkm/
    └── everkm.yaml

When --lang is not specified, the content root is <work_dir>/ (compatible with single-language sites).

Switching Language During Preview

During local preview, you can switch the interface language without restarting the server:

  • URL parameter: http://localhost:9081/?_lang=zh_CN
  • Cookie: set __lang=zh_CN

This is useful for viewing site configuration, breadcrumbs, templates, and other text that changes with language. Body content can only be switched via command-line parameters.

Configuration Text Internationalization

String values in the site configuration (everkm.yaml) can use @i18n:<key> to reference translations from language packs:

config:
  site:
    name: "@i18n:site.title"

folders:
  "/docs/":
    breadcrumbs:
      - title: "@i18n:nav.docs"
        url: /docs/

During rendering, these are automatically replaced with the corresponding language text based on the current --lang / ?_lang / cookie setting.

Note: @i18n: only supports whole-value replacement, not inline mixing (e.g., Welcome @i18n:site.name is not supported).

Language Pack Location and Priority

Language packs support two formats: *.i18n.md and *.i18n.yaml. Merge order (low → high, later entries override earlier ones):

  1. Theme templates/ directory and its subdirectories
  2. __everkm/extend/templates/ (if it exists)
  3. __everkm/extend/dcard/ (if it exists; *.i18n.yaml filenames are automatically used as namespaces, e.g., keys in download.i18n.yaml become download.*)
  4. __everkm/i18n/ (project-level, highest priority)

During preview, modifications to language packs under __everkm/i18n/ take effect automatically without restarting. Changes under extend/ trigger a reload of templates and language packs.

Project Language Packs (*.i18n.yaml)

Project language packs are stored in __everkm/i18n/ and use a single-file multi-language format (one file contains translations for all languages).

File Naming

FilenameDescription
_root.i18n.yamlRoot namespace, keys have no prefix
{name}.i18n.yamlNamespace is {name}, keys automatically get a name. prefix

Filenames only allow [A-Za-z0-9_]+; _root is reserved for the root namespace.

Translation Object Syntax

# __everkm/i18n/_root.i18n.yaml

# Method 1: Explicit _default (recommended, best readability)
site:
  title:
    _default: Everkm Publish
    zh_CN: 易记发布
    en_US: Everkm Publish
    _memo: Browser title, og:title    # Remark, not rendered

# Method 2: Shorthand multi-language (no _default needed)
nav:
  home:
    zh_CN: 首页
    en_US: Home

# Method 3: Plain string leaf (equivalent to _default)
blog: Blog

Rules:

  • _default — fallback translation, used when the requested language has no match
  • _memo — remark field, ignored during rendering
  • String sub-items not starting with _ — language code translations
  • Plain string leaf — equivalent to { _default: "<text>" }, only writes to the _default slot
  • Translation objects must not contain nested mappings; otherwise an error is reported and the item is ignored

Language Code Convention

Language codes are literally consistent with the site's --lang parameter; no automatic conversion between zh and zh_CN is performed:

--lang parameterYAML syntax
zh_CNzh_CN:
en_USen_US:
zhzh:

Namespace Language Packs

# __everkm/i18n/shop.i18n.yaml (namespace="shop")

cart:
  title:
    zh_CN: 购物车
    en_US: Cart
checkout: Pay now      # → shop.checkout @ _default

When referenced in templates, the namespace prefix is included: @i18n:shop.cart.title.

Lookup Priority

For key K and requested language L (e.g., zh_CN):

  1. Translation in language L (exact match)
  2. Translation in config.default_lang language
  3. Translation in the _default language slot
  4. Original value @i18n:<key> kept as-is (log warning)

Coexistence with Theme *.i18n.md

Themes continue to use existing templates/*.i18n.md (separate files per language). During merging, project yaml overrides theme md for the same key.

Template UI Text

Interface text within theme templates is read from language packs using the built-in function t.

Theme Language Pack Format

Place language packs in the theme's templates/ directory or its subdirectories. Two formats are supported and can coexist.

.i18n.md (separate files per language)

Level-1 headings serve as keys, and the content area under each heading is the corresponding value. Leading and trailing whitespace is automatically trimmed.

File naming: <Language Code>.i18n.md; namespace: <Namespace>.<Language Code>.i18n.md.

en_US.i18n.md

# My name
Everkm Publish

details.en_US.i18n.md

# toc
Table Of Contents

.i18n.yaml (single-file multi-language)

File naming: {Namespace}.i18n.yaml, filename is the namespace.

# templates/nav.i18n.yaml (namespace="nav")
home:
  zh_CN: 首页
  en_US: Home
  _default: Home

For the same key, .i18n.yaml overrides .i18n.md; project-level __everkm/i18n/*.i18n.yaml has the highest priority (see merge order above).

Referencing in Templates

Keys with a namespace need the prefix <namespace>: (note the trailing space):

<p>{{t(text="My name")}}</p>
<p>{{t(text="details: toc")}}</p>
<p>{{t(text="nav: home")}}</p>

Multi-language Images

  1. Place an identically named image in the same directory, adding .<Language Code> before the extension, e.g., logo.en_US.png
  2. Use img_src in templates:
<img src="{{img_src(file='logo.png')}}" />

With --lang=en_US, the output is logo.en_US.png.