Skip to main content

Muffin-Babel

Tests PyPI Version Python Versions

Muffin-Babel is an extension for the Muffin web framework that adds internationalization (i18n) support using Babel.


Requirements

  • Python >= 3.11

Installation

Install via pip:

pip install muffin-babel

Usage

Basic Setup

import muffin
import muffin_babel

app = muffin.Application("example")

# Initialize the plugin
babel = muffin_babel.Plugin()
babel.setup(app, locale_folders=["src/locale"])

Inside a Route

@app.route("/")
async def index(request):
    assert babel.current_locale
    return babel.gettext("Hello World!")

Locale Selector

The locale is detected for every request by the plugin's selector. By default it uses the Accept-Language header (muffin_babel.select_locale_by_request), but it can be replaced:

@babel.locale_selector
async def get_locale(request):
    return request.query.get("lang") or await muffin_babel.select_locale_by_request(request)

The selector receives the request and returns a locale name (or None to fall back to the default_locale). Detection is only active when auto_detect_locale is enabled.

Current Locale

babel.current_locale  # -> babel.Locale, default_locale until a request sets it
babel.current_locale = "ru"  # unknown locales are silently ignored

with babel.locale_ctx("ru"):
    babel.gettext("Hello World!")

Translation Functions

Function Description
gettext(string, domain=None, **variables) Translate a string with the current locale
ngettext(singular, plural, num, domain=None, **variables) Translate with plural forms, num chooses the form
pgettext(context, string, domain=None, **variables) Like gettext but with a context
npgettext(context, singular, plural, num, domain=None, **variables) Like ngettext but with a context
get_translations(domain=None, locale=None) Load the babel.support.Translations catalog itself
babel.gettext("Hello %(user)s", user="John")  # -> "Hello John"
babel.ngettext("%(num)s apple", "%(num)s apples", 2)  # -> "2 apples"

Variables are interpolated with the %-style mapping syntax. A missing or unusable variable is logged and the untranslated string is returned. Catalogs are loaded on demand and cached per (domain, locale) for the process lifetime, so recompiled .mo files require a restart.


Jinja2 Integration

With the muffin-jinja2 plugin installed, Muffin-Babel adds the jinja2.ext.i18n extension to the Jinja2 environment on startup and installs gettext (with %(name)s interpolation) and ngettext as template globals. Both use the current domain and locale:

<h1>{{ gettext('Welcome!') }}</h1>

Set configure_jinja2=False (or BABEL_CONFIGURE_JINJA2 = False in the app config) to leave the templates untouched.


Plugin Options

Option Default Description
auto_detect_locale True Middleware for automatic locale detection
configure_jinja2 True Enable i18n in the muffin-jinja2 plugin
default_locale "en" Default fallback locale
domain "messages" Default domain name for translation files
locale_folders ["locales"] Folders to search for translation files
sources_map [("**.py", "python"), ("**.html", "jinja2")] File pattern to extractor method mapping
options_map {"**.html": {"encoding": "utf-8"}} Options for the extractors

Options can be passed directly during setup:

babel.setup(app, default_locale="fr")

Or set via Muffin application config using the BABEL_ prefix:

BABEL_DEFAULT_LOCALE = "fr"

Note: Muffin config keys are case-insensitive. Unknown options are ignored silently, typos in option names are not reported.


Commands

The plugin registers commands for the Muffin manage CLI.

Extract Messages

Scan your sources and write (or update) a .po catalog in the first locale_folders entry — <locale_folders[0]>/<locale>/LC_MESSAGES/<domain>.po:

$ muffin app_package babel-extract-messages [OPTIONS] [DIRNAMES ...]
  • DIRNAMES — directories to scan (sources_map decides which extractor is used)
  • --project — project name in the header (default: the application name)
  • --domain — catalog domain (default: messages)
  • --no-locations — do not write source line references
  • --charset — output charset (default: utf-8)
  • --locale — locale of the catalog to write (default: default_locale)

Compile Messages

Compile every <locale>/LC_MESSAGES/<domain>.po of all locale_folders into .mo binaries:

$ muffin app_package babel-compile-messages [OPTIONS]
  • --use-fuzzy — compile fuzzy entries as well
  • --domain — catalog domain (default: messages)

Export as CSV

Print a .po catalog as CSV (id,string,context,comment) to stdout:

$ muffin app_package babel-export-csv [OPTIONS]
  • --domain — catalog domain (default: messages)
  • --locale — locale to export (default: default_locale)

This helps with sending strings to translators or spreadsheets.

Workflow

  1. babel-extract-messages collects strings from the sources into a .po file.
  2. Translators fill in the .po file (or work on the exported CSV).
  3. babel-compile-messages produces the .mo files the application loads on demand.
  4. Restart the application — the compiled catalogs are cached per process.

Example

The example/ directory contains a runnable application with Russian translations:

uv run uvicorn example:app --port 5000

Then open http://localhost:5000/?lang=ru. The same command is available as make example.


Contributing

Development happens at: https://github.com/klen/muffin-babel

Feel free to open issues or pull requests.


Bug Tracker

Found a bug? Have a suggestion? Report it here: 👉 https://github.com/klen/muffin-babel/issues


License

Licensed under the MIT license


Author

klen (Kirill Klenov)

Metadata

Release files for muffin-babel 1.9.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for muffin-babel 1.9.0
File Size Uploaded Provenance Actions
muffin_babel-1.9.0.tar.gz 8.0 kB Without provenance Details for muffin_babel-1.9.0.tar.gz

Built distribution (wheel)

Table of built distributions (wheels) for muffin-babel 1.9.0
File Interpreter ABI Platform Actions
muffin_babel-1.9.0-py3-none-any.whl Python 3 none any Details for muffin_babel-1.9.0-py3-none-any.whl

Total release size: 15.8 kB

Release files / muffin_babel-1.9.0.tar.gz

Download URL muffin_babel-1.9.0.tar.gz
Size 8.0 kB
Tags Source
SHA-256 checksum
How to use checksums
67c6e155b047f6203eddb6ccc16902b99d3c09b9fafc12a4a53dc581b28df751
BLAKE2b-256 checksum
How to use checksums
b3c71ebf64141e8a5dfe0316c43175c301e604fea0d1df82124b2dbf35e05b6e
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via uv/0.13.6 {"installer":{"name":"uv","version":"0.13.6","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"26.04","id":"resolute","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

Release files / muffin_babel-1.9.0-py3-none-any.whl

Download URL muffin_babel-1.9.0-py3-none-any.whl
Size 7.8 kB
Tags Python 3
SHA-256 checksum
How to use checksums
2a81cb2af33bdf7e63284dd458b96ecde9605fae5c00d178ca6cfcf7c79a2095
BLAKE2b-256 checksum
How to use checksums
564e5972c683fe12eaa821aa7aa0edb44927952178f01e00affefa6761afd5e7
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via uv/0.13.6 {"installer":{"name":"uv","version":"0.13.6","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"26.04","id":"resolute","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

Security for muffin-babel 1.9.0

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

No provenance found

None of the files in this release were uploaded with provenance metadata.

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

Release history Release notifications | RSS feed

This release

1.9.0 This release

2 release files No provenance

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page