gettext-translator
This program uses several cloud and local AI models to translate gettext PO files.
Features
- Supports several backends, both local HuggingFace models, self-hosted Ollama, and remote API services.
- Extensible. You can write your own translation plugins.
- Translates only the missing entries, of one or many PO files, or whole directories.
- Each unique string is translated once, even if it appears in many files.
- Supports
msgctxtfor better contextual translation, and plural forms (msgid_plural). - Validates the translations: those that lose or change placeholders (
%s,%(name)s,{name}) or HTML tags are discarded, somsgfmt --checkkeeps passing. - Optional cache of translations between runs.
- Dry-run mode, and output to another file or directory.
- Supports tagging of AI-generated translations.
- Supports automatic detection of language.
Backends
See the README.md file in each plugin's directory for examples and information about the backends. Currently this system works with the following backends:
- Azure AI Translator (README): remote API, commercial, API key required.
- OpenAI ChatGPT (README): remote API, several models, commercial, API key required.
- Google Gemini (README): remote API, several models, commercial with a free layer, API key required.
- MarianMT (README): local HuggingFace Helsinki-NLP model, free, auth token might be required.
- NLLB (README): local HuggingFace NLLB model, free, auth token might be required.
- Ollama (README): self-hosted (by yourself) Ollama server running free models.
Installation
Python 3.12 or newer is required. Install the program with the backends you want to use:
pip install "gettext-translator[ollama]"
pip install "gettext-translator[chatgpt,gemini]"
pip install "gettext-translator[all]"
From source code
Install the plugin interface, the program and the backends you need, from the root of the repository:
pip install -e translators/gettext-translator-service -e . -e translators/gettext-translator-ollama
General CLI arguments
The command line tool supports the following arguments:
--info: Shows information about the backend.--backend: Which backend to use.--po: One or more .po files or directories. Directories are searched recursively for .po files.--src: The source language. Default: en.--dst: The language to translate to. Files whoseLanguageheader is a different language are skipped.--fuzzy: Remove the fuzzy flag from all the entries before translating.--context: Optional default translation context for msgid without msgctxt.--ascribe: Add anAI-translatedcomment to each translated entry. Existing comments are kept.--config: Path to the YAML configuration file for the backend. Default: config.yaml.--dry-run: Show the translations without saving any file.--output: Save to this .po file (single input file) or directory (keeping the relative paths), instead of overwriting the input files.--cache: Path to a SQLite file where the translations are cached, so they are not requested again in later runs. The cache is specific to the backend, model and languages.--verbose: Show useful information. Possible values: debug, info, warning, error, critical. Default: warning.--version: Shows the version.--help: Shows the help message.
The exit code is 1 if there was an error, or if there were strings to translate but none could be translated.
Per backend configuration
To avoid cluttering of the command line arguments, each backend has its own configuration file, in YAML format. This file contains the backend's-specific options, as described in each plugin's README.md file. Please refer to those files (linked above), or use the --info argument to display the README.md and list the required options for each backend (view usage example below).
Values with the form "env:VARIABLE" are read from the environment variable VARIABLE, which is useful for API keys.
You must specify the path to the configuration file using the --config argument.
A sample configuration file for each backend is provided in each plugin's directory, under translators/gettext-translator-<backend>/<backend>-sample.yaml.
Usage examples
View the README file for the plugin and which options are required for it:
gettext-translator --info --backend chatgpt
Translate using the Azure AI Translator backend:
gettext-translator --backend azure --src es --dst de_DE --config translators/gettext-translator-azure/azure-sample.yaml --po example/messages.po
Translate using the ChatGPT backend, adding a comment attributing translations to AI:
gettext-translator --backend chatgpt --src es --dst de_DE --config translators/gettext-translator-chatgpt/chatgpt-sample.yaml --po example/messages.po --ascribe
Preview the translation of all the German .po files of a project with Ollama, caching the results, and then save them (the second run uses the cache and doesn't call the model again):
gettext-translator --backend ollama --src en --dst de --config ollama.yaml --po locale/ --cache translations.db --dry-run
gettext-translator --backend ollama --src en --dst de --config ollama.yaml --po locale/ --cache translations.db
Plural forms
The number of plural forms is read from the Plural-Forms header of each file (2 if it is missing). LLM backends (ChatGPT, Gemini, Ollama) translate every plural form. The machine translation backends (Azure, MarianMT, NLLB) translate the singular and the plural msgid separately, which is right for languages with two plural forms; for languages with more forms (Russian, Polish, Arabic...) use an LLM backend.
Architecture
This software was designed with extensibility as a priority, so it's not restricted to a single service or provider. It is based on an auto-discovery plugin system, and users can create additional plugins as needed. See gettext-translator-service to write your own.
classDiagram
class TranslatorService {
<<abstract>>
+REQUIRES_CONFIG: list[str]
+config: Settings
+configure()
+translate(items) list[dict]
+show_info()
}
class GettextTranslator {
+translate() bool
}
GettextTranslator --> TranslatorService : uses the plugin chosen with --backend
GettextTranslator --> TranslationCache : --cache
TranslatorService <|-- TranslatorAzure
TranslatorService <|-- TranslatorChatGPT
TranslatorService <|-- TranslatorGemini
TranslatorService <|-- TranslatorMarianMT
TranslatorService <|-- TranslatorNLLB
TranslatorService <|-- TranslatorOllama
Development
make dev # editable install of the packages and the dev tools
make check # lint, tests, build and twine check
Releases are published to PyPI by the Publish GitHub workflow when a vX.Y.Z tag is pushed (make release). Only the packages whose version changed are uploaded. Run make help for the other targets.
Notes
- It is recommended that you learn about gettext and the format of PO files. But of course, if you are reading this, you should already know it.
- Why gettext?
- It uses full strings in the source language as keys. This is the most relevant reason, as it means you don't have to search for abstract keys like
page.title.hellooritem.specification. While that approach may work for a few strings, it becomes complicated and chaotic with hundreds or thousands of them. - The original key string is used as a fallback. If a translation doesn't exist, the original string is displayed.
- It's a tried and trusted GNU standard.
- It uses full strings in the source language as keys. This is the most relevant reason, as it means you don't have to search for abstract keys like
- For the example PO file, the best contextual results were obtained using Azure's AI Translator service and the
qwen3:14bmodel in Ollama.
License
Copyright (C) 2026 Rodolfo González González.
Licensed under GPL 3.0.
Metadata
Release files for gettext-translator 0.1.1
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | |
|---|---|---|---|---|
| gettext_translator-0.1.1.tar.gz | 29.3 kB | Without provenance | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| gettext_translator-0.1.1-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 56.8 kB
Release files / gettext_translator-0.1.1.tar.gz
| Download URL | gettext_translator-0.1.1.tar.gz |
|---|---|
| Size | 29.3 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
fc5ed034be75063bb17e150fc8cea4dbe842fa32f752ba243fd835f23f9d1a85
|
|
BLAKE2b-256 checksum How to use checksums |
bc2c10c08b92528913b8bc6ff5c4c0cf64ad0130356630cd24ea998663a2354b
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.14.8
|
Release files / gettext_translator-0.1.1-py3-none-any.whl
| Download URL | gettext_translator-0.1.1-py3-none-any.whl |
|---|---|
| Size | 27.4 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
e530819d969e73341a1bdbe67e5cbfa4b03ce0f4d26f988df270df238e706ce8
|
|
BLAKE2b-256 checksum How to use checksums |
9f0594f1fb960d4aad8eb751f5ff1dac8c6b18e765965a6f6f1ae60b154efa2d
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.14.8
|
Security for gettext-translator 0.1.1
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.