babel-lsp
Language server for Python Babel i18n. Works with .py, Jinja templates, and .po/.pot catalog files.
Features
- Diagnostics — 32 checks across source files, PO catalogs, and the whole project
- Hover — translation table for any
_("msgid")call - Completion — msgid completion in translation calls
- Inlay hints — inline translation previews next to
_()calls - Code actions — remove fuzzy flags, fill missing translations, rename msgid across all files
- Go-to-definition / references / rename — treat msgids as first-class symbols
babel-lsp check— headless CLI linter, same rules as the LSP
Diagnostics
| Code | What it catches |
|---|---|
msg/empty-id |
_("") — empty string is the catalog header sentinel |
msg/fstring-in-call |
_(f"…") — f-string is interpolated before gettext sees it |
msg/format-before-call |
_("…" % x) — format applied before gettext |
msg/implicit-concat |
_("a" "b") — implicit string concatenation |
msg/non-constant-id |
_(variable) — pybabel cannot extract non-literal ids |
msg/unknown-id |
msgid not found in any catalog or template |
msg/missing-in-locale |
msgid translated in some locales but empty in others |
po/header-missing |
missing or incomplete catalog header |
po/duplicate-id |
same msgid appears twice in one file |
po/obsolete |
#~ entry absent from the .pot template |
po/missing-translation |
empty msgstr in a .po file |
po/fuzzy |
entry marked #, fuzzy |
po/blank |
msgstr is whitespace-only |
po/plural-count |
wrong number of plural forms vs. nplurals |
po/same-plurals |
all plural forms are identical |
po/format-mismatch |
printf/brace placeholder missing from translation |
po/extra-variable |
translation has extra placeholders not in source |
po/unchanged |
translation is identical to the source string |
po/newline-count |
\n count differs between source and translation |
po/whitespace-edges |
leading/trailing whitespace differs |
po/end-punctuation |
trailing punctuation differs |
po/double-space |
translation has double space not in source |
po/repeated-word |
consecutive repeated word in translation |
po/escape-mismatch |
backslash escape sequences differ |
po/bracket-count |
bracket count differs |
po/accelerator-mismatch |
& accelerator marker count differs |
po/xml-tag-mismatch |
XML/HTML tag structure differs |
po/url-changed |
URL from source is absent or path-altered |
po/number-mismatch |
numeric literals differ |
proj/inconsistent-translation |
same msgid translated differently in the same locale |
proj/missing-locale-file |
a locale has .po for some domains but not all |
proj/unused-id |
msgid exists in catalog but is never referenced in source |
Installation
uv tool install babel-lsp
Or with pip:
pip install babel-lsp
Or download a pre-built binary from the releases page.
Configuration
Place a babel-lsp.toml (or pyproject.toml [tool.babel-lsp] section) at your project root.
# Directories to search for .po/.pot files (auto-detected if absent)
locale_dirs = ["locale"]
# Default locale for features that need one
default_locale = "en"
# Restrict to specific translation domains
# domains = ["messages", "admin"]
# Additional translation functions beyond the built-ins
# (_, gettext, ngettext, pgettext, npgettext, lazy_gettext, …)
extra_keywords = ["my_gettext"]
# Extensions treated as Jinja templates
jinja_extensions = [".html", ".jinja", ".jinja2", ".j2"]
# Locale to show in inlay hints (defaults to first alphabetical locale)
# inlay_hint_locale = "de"
# Path to pybabel (auto-discovered on PATH if absent)
# pybabel_path = "/path/to/pybabel"
[diagnostics]
# Run only these checks (default: all)
# select = ["po/fuzzy", "po/missing-translation"]
# Suppress specific checks
ignore = ["po/unchanged", "po/same-plurals"]
# Override severity per code
[diagnostics.severity]
"po/fuzzy" = "warning"
"proj/unused-id" = "hint"
[unchanged]
# msgids to skip for po/unchanged (e.g. single-word proper nouns)
ignore = ["OK", "PDF"]
CLI
# Check the current project
babel-lsp check
# Check specific paths
babel-lsp check locale/ src/
# Run only selected checks
babel-lsp check --select po/fuzzy,po/missing-translation
# Suppress checks
babel-lsp check --ignore po/unchanged
# Auto-fix what can be fixed (fuzzy flags, missing translations)
babel-lsp check --fix
# Output formats: concise (default), full, json, json-lines, grouped,
# github, gitlab, junit, pylint
babel-lsp check --output-format github
# Exit 0 even with findings (useful in pre-commit hooks that only annotate)
babel-lsp check --exit-zero
Editor Setup
Zed
Install from the Zed extensions panel (Cmd+Shift+X) — search for babel-lsp and click Install. It activates automatically for Python files.
To control server order alongside other language servers, add to ~/.config/zed/settings.json:
{
"languages": {
"Python": { "language_servers": ["babel-lsp", "..."] }
}
}
Helix
Merge editors/helix/languages.toml into ~/.config/helix/languages.toml.
Neovim
Requires Neovim 0.11+. Add to your init.lua:
require("lspconfig").babel_lsp.setup {}
Or use the minimal snippet from editors/neovim/babel_lsp.lua.
Other editors
The server speaks standard LSP over stdio:
babel-lsp lsp --stdio
Fixtures
fixtures/ contains one minimal workspace per diagnostic code. Use them to verify diagnostics work or as templates for your own test setups:
babel-lsp check fixtures/po-fuzzy/
babel-lsp check fixtures/po-fuzzy/ --select po/fuzzy
Metadata
Release files for babel-lsp 0.3.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Built distributions (wheels)
| File | Reset | |||
|---|---|---|---|---|
| babel_lsp-0.3.0-py3-none-win_amd64.whl | Python 3 | none | Windows x86-64 | Details |
| babel_lsp-0.3.0-py3-none-manylinux_2_28_x86_64.whl | Python 3 | none | Linux glibc 2.28+ x86-64 | Details |
| babel_lsp-0.3.0-py3-none-manylinux_2_28_aarch64.whl | Python 3 | none | Linux glibc 2.28+ ARM64 | Details |
| babel_lsp-0.3.0-py3-none-macosx_11_0_arm64.whl | Python 3 | none | macOS 11.0+ ARM64 | Details |
| babel_lsp-0.3.0-py3-none-macosx_10_12_x86_64.whl | Python 3 | none | macOS 10.12+ x86-64 | Details |
Total release size: 12.9 MB
Release files / babel_lsp-0.3.0-py3-none-win_amd64.whl
| Download URL | babel_lsp-0.3.0-py3-none-win_amd64.whl |
|---|---|
| Size | 2.7 MB |
| Tags | Python 3 Windows x86-64 |
|
SHA-256 checksum How to use checksums |
cbdef3da5f869f74d07136ba3ee870f47799374af63a7354f06592f366caf87a
|
|
BLAKE2b-256 checksum How to use checksums |
fe7907141cf73836c477f7c5c4a034844b4803eb5abec3fd3f2e75be7ff9e683
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
uv/0.12.17 {"installer":{"name":"uv","version":"0.12.17","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
|
Release files / babel_lsp-0.3.0-py3-none-manylinux_2_28_x86_64.whl
| Download URL | babel_lsp-0.3.0-py3-none-manylinux_2_28_x86_64.whl |
|---|---|
| Size | 2.7 MB |
| Tags | Linux glibc 2.28+ x86-64 Python 3 |
|
SHA-256 checksum How to use checksums |
ace71f58f52b312bfa94abf55ebb60b6ac05a9fa91db43d486d45d41fd5f2124
|
|
BLAKE2b-256 checksum How to use checksums |
61d426ab13eaa74e4ec4b62babe3812d94f5cc7153fc472ed4823a2060ae89b4
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
uv/0.12.17 {"installer":{"name":"uv","version":"0.12.17","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
|
Release files / babel_lsp-0.3.0-py3-none-manylinux_2_28_aarch64.whl
| Download URL | babel_lsp-0.3.0-py3-none-manylinux_2_28_aarch64.whl |
|---|---|
| Size | 2.6 MB |
| Tags | Linux glibc 2.28+ ARM64 Python 3 |
|
SHA-256 checksum How to use checksums |
f2e3850f848935475ecf576ec1986f50fe0541f869f1d29187e9f97bf5db38bc
|
|
BLAKE2b-256 checksum How to use checksums |
488cf1f531ad78b4853301786add5195a64028a7a486aabb0008b3c29640f394
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
uv/0.12.17 {"installer":{"name":"uv","version":"0.12.17","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
|
Release files / babel_lsp-0.3.0-py3-none-macosx_11_0_arm64.whl
| Download URL | babel_lsp-0.3.0-py3-none-macosx_11_0_arm64.whl |
|---|---|
| Size | 2.5 MB |
| Tags | Python 3 macOS 11.0+ ARM64 |
|
SHA-256 checksum How to use checksums |
f5daf691591d35fdb3c5ae4da4e48334919fd1da26093976642e05fb9c64549a
|
|
BLAKE2b-256 checksum How to use checksums |
0fd80e137b332abdbb98fc0f481dc8accbb8a81b04c69aa8f83e34f5c869de95
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
uv/0.12.17 {"installer":{"name":"uv","version":"0.12.17","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
|
Release files / babel_lsp-0.3.0-py3-none-macosx_10_12_x86_64.whl
| Download URL | babel_lsp-0.3.0-py3-none-macosx_10_12_x86_64.whl |
|---|---|
| Size | 2.5 MB |
| Tags | Python 3 macOS 10.12+ x86-64 |
|
SHA-256 checksum How to use checksums |
284678956b20dc9c7a0d99a97f8ca7ad5972397488a76787fbd6c40e792979cd
|
|
BLAKE2b-256 checksum How to use checksums |
d1afdb556adc612ec4ea6520b74c742f260ee7224af139ce488d8a0a02a87c7d
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
uv/0.12.17 {"installer":{"name":"uv","version":"0.12.17","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
|