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:
prefixproduces/en/,/es/URLs - content_structure:
dirusescontent/en/,content/es/folders - gettext_domain: Domain name for PO/MO files (default
messages)
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
- RTL Layout — RTL layout for Arabic/Hebrew
- Translator Guide — Contributor workflow for translations