Request-safe gettext localization and locale negotiation for Starlette
Project description
starlette-i18n
Request-safe gettext localization and locale negotiation for Starlette applications.
Requirements
- Python 3.11+ (CI validates Python 3.11, 3.12, 3.13, and 3.14)
- Starlette newer than 1.2.0 and below 2.0
Install
uv add starlette-i18n
pip install starlette-i18n
Quick start
Compile gettext catalogs before starting the application, then load them once:
from starlette.applications import Starlette
from starlette.responses import PlainTextResponse
from starlette_i18n import LocaleMiddleware, TranslationCatalog, gettext
catalog = TranslationCatalog.load("locales", domain="messages", default_locale="en")
app = Starlette()
app.add_middleware(LocaleMiddleware, catalog=catalog)
async def homepage(request):
return PlainTextResponse(gettext("Success"))
app.add_route("/", homepage)
The selected Locale is also available as request.state.locale. The public translation helpers are gettext, ngettext, gettext_lazy, and get_locale.
Locale selection
LocaleMiddleware selects one catalog for each HTTP request in this order:
- A valid configured locale cookie (
localeby default). - The request's
Accept-Languageheader. - The catalog's configured default locale.
Header values are parsed as a q-weighted priority list and resolved using RFC 4647 lookup. Exact complex tags work: a zh-CN request selects a zh_CN catalog directory, while pt-BR can fall back to a pt catalog. Invalid values and q=0 entries are ignored. A wildcard falls back to the configured default when no explicit supported locale matches.
Responses include Content-Language. The middleware adds configured selection inputs (Cookie and Accept-Language by default) to Vary so shared caches do not serve the wrong representation.
Configure another cookie name, or disable cookies entirely:
app.add_middleware(LocaleMiddleware, catalog=catalog, cookie_name="language")
app.add_middleware(LocaleMiddleware, catalog=catalog, cookie_name=None)
ASGI and Jinja safety
The active locale is stored in a ContextVar and is reset after every request, including exceptions. Concurrent requests therefore cannot leak translations into one another.
Do not install gettext functions into a shared Jinja environment per request: Jinja's installation mutates global environment state. Pass a request-local callable instead:
html = template.render(request=request, _=request.state.locale.translate)
Then use {{ _("Success") }} in the template. See examples/jinja_app.py.
Examples
uv run --with uvicorn examples/basic_usage.py
uv run --with 'uvicorn[standard]' uvicorn examples.uvicorn_runner:app --reload
uv run --with gunicorn --with uvicorn gunicorn -c examples/gunicorn_conf.py examples.gunicorn_runner:app
curl -H 'Accept-Language: ru' http://127.0.0.1:8000/
Migrating from 2.x
3.0 is a breaking release. It requires Python 3.11+, moves the package to src/, uses pyproject.toml and uv, and replaces LocaleDefaultMiddleware, LocaleFromCookieMiddleware, LocaleFromHeaderMiddleware, and the old ordering-dependent LocaleMiddleware with the single LocaleMiddleware shown above. Load catalogs with TranslationCatalog.load() instead of load_gettext_translations().
Further documentation
Development
uv sync --all-groups
make lint
make test
make build
License
starlette-i18n is distributed under the Apache License 2.0. Report vulnerabilities through the security policy.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file starlette_i18n-3.0.0.tar.gz.
File metadata
- Download URL: starlette_i18n-3.0.0.tar.gz
- Upload date:
- Size: 64.9 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
af4557c07158b6b785ba6b18bff108ef4a914f041f9ac52cb424cab85a76880f
|
|
| MD5 |
8f529c2c32b9e672709e9edd8750761d
|
|
| BLAKE2b-256 |
b0991c82ee6457fce547fc1d87cd6be92a5dd6f6f12a9154754c28d67cf6e440
|
Provenance
The following attestation bundles were made for starlette_i18n-3.0.0.tar.gz:
Publisher:
publish.yml on bigbag/starlette-i18n
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
starlette_i18n-3.0.0.tar.gz -
Subject digest:
af4557c07158b6b785ba6b18bff108ef4a914f041f9ac52cb424cab85a76880f - Sigstore transparency entry: 2211913749
- Sigstore integration time:
-
Permalink:
bigbag/starlette-i18n@f0504cdd2b2f7a3f2beaba5ae6d6ebae6f75fb7c -
Branch / Tag:
refs/tags/v3.0.0 - Owner: https://github.com/bigbag
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@f0504cdd2b2f7a3f2beaba5ae6d6ebae6f75fb7c -
Trigger Event:
push
-
Statement type:
File details
Details for the file starlette_i18n-3.0.0-py3-none-any.whl.
File metadata
- Download URL: starlette_i18n-3.0.0-py3-none-any.whl
- Upload date:
- Size: 12.5 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
62319160d97090736abb888d7f4bc2e3218b5599dc6515916145dc5d3da7654a
|
|
| MD5 |
9db008f61a5cccd375fb8cb799c5e749
|
|
| BLAKE2b-256 |
0d9e20630439800ad775b17766f9ed93f393a37812104f052c2da8b150d02828
|
Provenance
The following attestation bundles were made for starlette_i18n-3.0.0-py3-none-any.whl:
Publisher:
publish.yml on bigbag/starlette-i18n
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
starlette_i18n-3.0.0-py3-none-any.whl -
Subject digest:
62319160d97090736abb888d7f4bc2e3218b5599dc6515916145dc5d3da7654a - Sigstore transparency entry: 2211913777
- Sigstore integration time:
-
Permalink:
bigbag/starlette-i18n@f0504cdd2b2f7a3f2beaba5ae6d6ebae6f75fb7c -
Branch / Tag:
refs/tags/v3.0.0 - Owner: https://github.com/bigbag
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@f0504cdd2b2f7a3f2beaba5ae6d6ebae6f75fb7c -
Trigger Event:
push
-
Statement type: