Skip to main content

llm-localize

Fill in missing translations in your i18n files with an LLM, without breaking them.

LLMs translate well but are careless with the parts of a message that aren't prose. llm-localize sends only untranslated messages, then checks each translation before it is written:

  • Placeholders (%s, %(name)s, {name}, Android's %1$s, iOS's %@) must match the source exactly. Named and numbered ones may move; unnamed ones (%s, {}) must stay in order.
  • HTML tags must keep the same names, order and attributes. Only text attributes (title, alt, placeholder, aria-label, aria-description, and value on an <input> button) may change value, and the content of <script> and <style> must stay as it is. Numbered tags, like react-i18next's <1>…</1>, must all be kept, in any order.
  • URLs (http, https, ftp, mailto:, tel:, www.) and email addresses must be unchanged, and none may be added.
  • Control characters that the model invented (e.g. — corrupted into \x14) are rejected.
  • Plurals are translated once per plural form of the target language. The model is told which numbers each form covers ("used when n is 2, 3, 4, 22, …"), worked out from a PO file's Plural-Forms header, or from the Unicode CLDR plural rules for formats that name forms one, few, many, other.
  • ICU messages like {count, plural, one {# file} other {# files}} (in JSON and XLIFF) must keep their arguments and select cases, and get a plural case for each category the target language uses.
  • Format checks. PO files are run through msgfmt --check afterwards, and any entry it rejects is blanked. Errors no translation caused, like a message defined twice, stop with an error instead. A PO file without a real charset, or in another one, is saved as UTF-8, so any translation fits.

A translation that fails a check is dropped, so that message stays untranslated and is retried on the next run. Fuzzy entries are retranslated and lose their fuzzy flag.

It runs on its own as a command line tool, or as a Django app. The engine is format-agnostic: it ships with gettext PO, JSON, Android, iOS, XLIFF, Markdown and Word formats (see Formats), and others plug in as small classes (see Adding a format).

Install

pip install llm-localize             # command line tool and Python API
pip install "llm-localize[django]"   # plus the Django app
uv tool install llm-localize         # just the command, in its own environment

The only dependency is polib; the django extra adds Django. LLM APIs are called over plain HTTP with the standard library, so no provider SDK is needed. Install gettext if you want the msgfmt check (brew install gettext, apt install gettext).

Quick start

export OPENAI_API_KEY=...          # or ANTHROPIC_API_KEY, GEMINI_API_KEY, XAI_API_KEY with --provider
llm-localize locale/fr/LC_MESSAGES/messages.po
llm-localize locales/fr.json locales/de.json          # from locales/en.json
./manage.py makemessages -a --translate               # Django, with llm_localize.contrib.django installed

Documentation

The full documentation is at llm-localize.readthedocs.io:

Privacy and cost

Your source strings and their context comments are sent to the LLM provider. Only untranslated, fuzzy or broken messages are sent, so a run after the first one costs little.

Development

uv sync --group dev
uv run pytest
uv run ruff check .

# The core without Django, as CI runs it
uv pip uninstall django pytest-django && uv run --no-sync pytest -p no:django
uv sync --group dev   # to put them back

The documentation is built with MkDocs: uv run --with-requirements docs/requirements.txt mkdocs serve.

License

MIT, see LICENSE. The table of language names from Django is under the BSD 3-Clause license, in licenses/Django-LICENSE.txt. Data from the Unicode CLDR, like plural rules, is under the Unicode License v3, in licenses/Unicode-LICENSE.txt.

Metadata

Release files for llm-localize 0.1.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 llm-localize 0.1.0
File Size Uploaded Provenance Actions
llm_localize-0.1.0.tar.gz 214.7 kB With provenance Details for llm_localize-0.1.0.tar.gz

Built distribution (wheel)

Table of built distributions (wheels) for llm-localize 0.1.0
File Interpreter ABI Platform Actions
llm_localize-0.1.0-py3-none-any.whl Python 3 none any Details for llm_localize-0.1.0-py3-none-any.whl

Total release size: 344.1 kB

Release files / llm_localize-0.1.0.tar.gz

Download URL llm_localize-0.1.0.tar.gz
Size 214.7 kB
Tags Source
SHA-256 checksum
How to use checksums
25f50d17be06bfc6eaf2941f40fc35661519bb47899ac7cc77069f325e6a3822
BLAKE2b-256 checksum
How to use checksums
86a272b020a99e2cdb937bfb889d167da4ec4552c6c90a08cd5c33a2901108e9
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

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.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 31, 2026.

Transparency log

Release files / llm_localize-0.1.0-py3-none-any.whl

Download URL llm_localize-0.1.0-py3-none-any.whl
Size 129.4 kB
Tags Python 3
SHA-256 checksum
How to use checksums
38a641fe60570d57f7c2419abcfdb51eb767505896b6e8cef1b7626af3817cdc
BLAKE2b-256 checksum
How to use checksums
77ff5824be83b0763f27e5b6b82e6a092e35961c8ebe2d8fe83b0d79dc7346b1
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

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.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 31, 2026.

Transparency log

Security for llm-localize 0.1.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.

Full provenance

Both files in this release have been uploaded with provenance metadata.

Select from 2 files

Attestation for llm_localize-0.1.0.tar.gz

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 31, 2026.

Transparency log

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.

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