i18n Quickstart

Set up a bilingual site with gettext PO/MO in 5 minutes

2 min read 330 words

This guide walks you through setting up a bilingual (English/Spanish) site with Bengal's gettext workflow.

1. Configure Languages

Add tobengal.toml:

[i18n]
default_language = "en"
strategy = "prefix"
content_structure = "dir"
fallback_to_default = true
gettext_domain = "messages"
languages = [
    { code = "en", name = "English", weight = 1 },
    { code = "es", name = "Español", weight = 2 },
]
  • strategy:prefix produces /en/, /es/URLs
  • content_structure:dir uses content/en/, content/es/folders
  • gettext_domain: Domain name for PO/MO files (defaultmessages)

2. Create Content Structure

content/
├── en/
│   ├── _index.md      # English home
│   └── about.md
└── es/
    ├── _index.md      # Spanish home
    └── about.md

Each locale has its own directory. Pages with the same path (e.g.about.md) are linked as translations via translation_key.

3. Extract UI Strings

Scan your templates fort("key")calls:

bengal i18n extract -o messages.pot

This creates messages.potwith all keys found in templates. Copy it to each locale:

mkdir -p i18n/en/LC_MESSAGES i18n/es/LC_MESSAGES
cp messages.pot i18n/en/LC_MESSAGES/messages.po
cp messages.pot i18n/es/LC_MESSAGES/messages.po

4. Add Translations

Edit each.po file. Example i18n/es/LC_MESSAGES/messages.po:

msgid "Home"
msgstr "Inicio"

msgid "About"
msgstr "Acerca de"

msgid "Welcome"
msgstr "Bienvenido"

Use a PO editor like Poedit for a friendlier workflow.

5. Compile and Build

bengal i18n compile
bengal build

The compile step converts .po.mo (binary, faster at runtime). Output goes to public/en/, public/es/, etc.

6. Check Coverage

bengal i18n status

Shows per-locale translation coverage. Use --fail-on-missing-translationsin CI to gate on completeness.

Template Usage

In Kida or Jinja templates:

{# Translate a key #}
{{ t("Home") }}

{# With parameters #}
{{ t("greeting", {"name": user.name}) }}

{# Override language #}
{{ t("About", lang="es") }}

{# Current locale #}
<html lang="{{ current_lang() }}">

Next Steps