No project description provided
Project description
djangocms-deepl-translations
Allows to translate Django CMS 5+ content using the DeepL API.
Installation
-
Install the module from PyPI:
python3 -m pip install djangocms-deepl-translationsOr, if you're using poetry :
poetry add djangocms-deepl-translations -
Add it in your
INSTALLED_APPS:"djangocms_deepl_translations", "djangocms_transfer",Important — Order when using contribs: If you use optional contribs (e.g.
djangocms_deepl_translations.contrib.djangocms_stories), list them beforedjangocms_deepl_translations. The contrib’sready()must run before the main app’s admin registers its URLs, so that the contrib can register its “translate to” view in the registry. Otherwise the admin will not expose the contrib’s translation URL.Example with the Stories contrib:
"djangocms_deepl_translations.contrib.djangocms_stories", "djangocms_deepl_translations", "djangocms_transfer", -
Run the migrations:
python manage.py migrate
Configuration
Required settings
DJANGOCMS_DEEPL_TRANSLATIONS_API_KEY: set in your Django settings.
Optional settings
-
DJANGOCMS_DEEPL_TRANSLATIONS_API_LANGUAGE_MAPPING: a dict mapping your project’s language codes to DeepL API language codes (e.g."en"→"EN-GB","fr"→"FR"). If unset, the default mapping is used (fr→"FR",en→"EN-GB",es→"ES",de→"DE",it→"IT",pt→"PT-PT",nl→"NL"). -
DJANGOCMS_DEEPL_TRANSLATIONS_WARN_UNCONFIGURED_PLUGINS: whenTrue(default), Django's system check warns when installed CMS plugin types have no translation config. Set toFalseto disable these warnings. -
DJANGOCMS_DEEPL_TRANSLATIONS_BULK_TRANSLATE_DEFAULT_USER_ID: optional integer user id used bybulk_translate_pages(and related bulk commands) when--useris not passed; falls back to the first superuser if unset.
Plugin translation config: DJANGOCMS_DEEPL_TRANSLATIONS_PLUGIN_CONFIG
This setting defines, for each CMS plugin type, which model fields are sent to the DeepL API and how embedded plugins (e.g. links inside text) are handled. Entries override or extend the built-in defaults (TextPlugin from djangocms-text, LinkPlugin from djangocms-link).
Each key is a plugin type name (the class __name__, e.g. "TextPlugin", "LinkPlugin"). Each value is a dict with the following optional parameters:
| Parameter | Description |
|---|---|
translatable_fields |
Tuple of field paths whose values are sent to the DeepL API. Each item is a field name (e.g. "name") or a nested path using /: e.g. "config/accordion_item_header" |
no_translation |
Boolean. If True, this plugin type is not translated (no API call). Use for structural or non-text plugins. Cannot be combined with translatable_fields. |
Example (override default, add a custom plugin):
DJANGOCMS_DEEPL_TRANSLATIONS_PLUGIN_CONFIG = {
# Override TextPlugin
"TextPlugin": {
"translatable_fields": ("body",),
},
# Add config for a plugin that has no translatable content
"StructuralPlugin": {
"no_translation": True,
},
# Add config for a custom plugin with two translatable fields
"MyCustomPlugin": {
"translatable_fields": ("title", "description"),
},
# Nested path: value at plugin_data["data"]["config"]["accordion_item_header"]
"AccordionItemPlugin": {
"translatable_fields": ("config/accordion_item_header",),
},
}
When DJANGOCMS_DEEPL_TRANSLATIONS_WARN_UNCONFIGURED_PLUGINS is True (default), Django's system check (e.g. manage.py check) warns with a single message listing all installed plugin types that have no entry in this config (or in the built-in defaults), so you can add one and avoid incomplete translations. The message also mentions the suggest_deepl_plugin_config command to generate a base config.
Management command: suggest_deepl_plugin_config
The command suggest_deepl_plugin_config lists all installed CMS plugin types that do not yet have a translation config (neither in the built-in defaults nor in DJANGOCMS_DEEPL_TRANSLATIONS_PLUGIN_CONFIG). It prints on stdout a ready-to-paste Python snippet that adds an entry for each of them with no_translation: True, so that the system check no longer warns and translation is explicitly disabled until you configure them.
When to use it: When you first set up the module or after installing new CMS plugins, to quickly get a full config and then replace no_translation: True with real options (e.g. translatable_fields) only for the plugins you want to translate.
Usage:
python manage.py suggest_deepl_plugin_config
Example output (when some plugins are unconfigured):
# Add this to your settings to disable translation for plugins not yet configured.
# Then replace no_translation=True with translatable_fields (etc.) as needed.
DJANGOCMS_DEEPL_TRANSLATIONS_PLUGIN_CONFIG = {
"PlaceholderPlugin": {
"no_translation": True,
},
"URLFieldPlugin": {
"no_translation": True,
},
}
Copy the printed block into your settings file. If every installed plugin already has a config, the command prints a success message and no snippet.
Management command: bulk_translate_pages
Bulk-translate published CMS pages from a source language to a target language using the same pipeline as the admin “Translate to” action (PageTranslator + DeepL API). Only pages that have a published PageContent in the source language (via djangocms-versioning) are processed.
Two-phase run (default, without --create-only):
- Phase 1 — For each page: create and publish target-language page content with empty placeholders (titles/slugs/meta still translated). This makes target pages exist so links in content can resolve correctly on the next pass.
- Phase 2 — Full translation: export placeholders, translate plugins, fill target, publish.
Typical workflow: Run the full command once (both phases). If you maintain many pages and need targets to exist before a second pass, you can run with --create-only first, then run again without it to execute phase 2 only on the pages that completed phase 1.
Usage:
python manage.py bulk_translate_pages --source-language fr --target-language en
| Option | Description |
|---|---|
--source-language |
Required. Django/CMS language code (e.g. fr, en). |
--target-language |
Required. Target language code. |
--page-ids |
Optional. One or more page primary keys. If set, only those pages are processed (each must still be published in the source language). Example: --page-ids 12 34 56. |
--create-only |
Only phase 1: create/publish empty target contents; no placeholder translation. |
--fail-silently |
On error, log to stderr and continue. Default: stop and re-raise on first error (full traceback). |
--user |
User ID used for versioning publish actions. Default: DJANGOCMS_DEEPL_TRANSLATIONS_BULK_TRANSLATE_DEFAULT_USER_ID if set, otherwise the first superuser. |
See also Optional settings for DJANGOCMS_DEEPL_TRANSLATIONS_BULK_TRANSLATE_DEFAULT_USER_ID. The command name is bulk_translate_pages (python manage.py bulk_translate_pages).
Optional contribs
Optional integrations (e.g. for translating articles from djangocms-stories) live under djangocms_deepl_translations.contrib.*. Add the contrib app to INSTALLED_APPS before djangocms_deepl_translations (see Installation above), so that the contrib’s ready() runs first and registers its “translate to” view in the admin.
| Contrib | App name | Purpose |
|---|---|---|
| Stories (posts/articles) | djangocms_deepl_translations.contrib.djangocms_stories |
DeepL translation for djangocms-stories posts; toolbar “Translate to” on post detail views. |
When the Stories contrib is installed, you can bulk-translate posts (published source PostContent only) with:
python manage.py bulk_translate_stories_posts --source-language fr --target-language en
Options mirror bulk_translate_pages above: --post-ids, --create-only, --fail-silently, --user (with post primary keys instead of page ids).
Extracting / updating translations (i18n_tools, Poe, makemessages, translate_messages, compilemessages)
Prerequisites
-
Install project dependencies with Poetry from the repository root (see Installation for runtime deps):
poetry install -
Install Poethepoet so the
poetasks are available (it is listed under thedevdependency group):poetry install --with dev
-
Optional — auto-translation of
.pofiles uses django-deep-translator via thetranslate_messagesmanagement command. Install thei18n_toolsoptional group:poetry install --with i18n_tools
You can combine groups, e.g.
poetry install --with dev,i18n_tools.
The i18n_tools package
The i18n_tools/ directory holds a small Django entrypoint (i18n_tools/manage.py) and settings (i18n_tools/settings.py) used only to run:
makemessages— extract/update translatable strings into.pofiles underdjangocms_deepl_translations/locale/and contriblocale/trees.translate_messages— fill empty/fuzzy entries in those.pofiles using machine translation (requires--with i18n_tools).compilemessages— compile.poto.mofor use at runtime.
These commands are wired as Poe tasks in pyproject.toml ([tool.poe.tasks.*]).
Poe tasks
After poetry install --with dev (and --with i18n_tools when using translate_messages), run tasks as poe <task> or, from the repo root:
poetry makemessages --language fr
poetry translate_messages -l fr
poetry compilemessages
| Task | Purpose |
|---|---|
poetry makemessages |
Regenerate .po for one locale (-l / --language, default fr). Run for each language you maintain, e.g. poetry makemessages --language de and poetry makemessages --language fr. |
poetry translate_messages |
Auto-translate untranslated/fuzzy strings in .po for the target locale (-l) from the source locale (-s / --source-language, default en). |
poe compilemessages |
Compile .po → .mo for one locale (-l, default en). Run per locale or invoke poetry run python3 i18n_tools/manage.py compilemessages with no -l to compile every catalog Django finds. |
Example: after makemessages, refresh bothFrench and German catalogs from English:
Make messages for French and German:
# Generate .po files for French and German
poetry makemessages -l fr
poetry makemessages -l de
Fill .po using English as source (default -s is en):
# Fill .po using English as source (default -s is en)
poetry translate_messages -l fr
poetry translate_messages -l de
Then compile both locales for runtime:
poe compilemessages
Note: Machine translation depends on django-deep-translator’s backend configuration (e.g. API keys if applicable). Untranslated strings only are updated when using -u (already set in the Poe task).
Contributing
Feel free to send feedbacks on the module using it's Home page. See CONTRIBUTING.md for contributions.
Tests
Tests are located in the tests directory.
Tests are written with pytest. They are based on a testapp models :
To run the tests, you must launch the command ./run_tests.sh
A coverage report can be generated using the command ./run_coverage.sh
Cross-version matrix (tox)
CI runs tox (see tox.ini) against the Python, Django, and django CMS versions declared as PyPI classifiers in pyproject.toml: django CMS 5.0.x with Django 4.2 / 5.0 / 5.1 / 5.2 / 6.0, and Python 3.10–3.14 (Django 6.x envs use Python ≥ 3.12 only). Interpreters missing on the machine are skipped (skip_missing_interpreters).
Local examples:
pip install "tox>=4.21"
tox run -e py312-django52-cms50 # one environment
# Full matrix: use run-parallel (not `run -p`) — tox 4 puts `-p` on the parallel subcommand.
tox run-parallel # parallel envs; default -p = auto (all logical CPUs)
tox p # short alias for run-parallel
tox run-parallel -p 4 # at most 4 envs at once (less RAM / less load)
tox run -e coverage # coverage + `coverage.xml` (default `python3`, Django 5.2, CMS 5)
Parallelism: tox run executes each environment sequentially. For several envs at once, use tox run-parallel (or tox p); -p auto / -p N applies to that subcommand, not to tox run. Optional pytest -n auto (pytest-xdist) inside one env: tox run -e py312-django52-cms50 -- tests -n auto (Django DB settings may need tweaks); prefer run-parallel for the matrix first.
pyenv
tox does not read ~/.pyenv/versions by itself: it looks for python3.10, python3.11, … on your PATH. That usually means the pyenv shims (~/.pyenv/shims), after init.
- Load pyenv in the shell you use to run tox (bash example):
export PYENV_ROOT="${PYENV_ROOT:-$HOME/.pyenv}" export PATH="$PYENV_ROOT/bin:$PATH" eval "$(pyenv init - bash)" # zsh: eval "$(pyenv init - zsh)"
- Install the runtimes you need, e.g.
pyenv install 3.10.13(repeat for 3.11, 3.12, …). - Expose every version to shims in this repo (often required when tox is installed via pipx, which otherwise sees a minimal
PATH):cd /path/to/djangocms-deepl-translations pyenv local 3.14 3.12 3.11 3.10 # use your exact `pyenv versions` names
This creates/updates.python-versionsopython3.10,python3.11, … resolve correctly. - Check before tox:
command -v python3.10 && python3.10 -V.
The deprecated tox-pyenv plugin targeted tox 3; with tox 4, pyenv local + shims on PATH is the usual approach (reference).
If your IDE terminal does not load ~/.bashrc / ~/.zshrc, pyenv may never be on PATH — run the eval "$(pyenv init …)" block in that terminal or use a login shell.
License
This project is licensed under the GNU GPLv3 License - see the LICENSE file for details.
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 djangocms_deepl_translations-0.1.0.tar.gz.
File metadata
- Download URL: djangocms_deepl_translations-0.1.0.tar.gz
- Upload date:
- Size: 71.4 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.14.3
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
74f363df02ec581b4839647bed91aed83bebe0f249eeb935aa384355d81e807d
|
|
| MD5 |
1a4d47a131e31c58de3b6821eb4a7f40
|
|
| BLAKE2b-256 |
7adb57352df9ad4941e89dff627f330482d20cea88ec13cab8d5c015825ce796
|
File details
Details for the file djangocms_deepl_translations-0.1.0-py3-none-any.whl.
File metadata
- Download URL: djangocms_deepl_translations-0.1.0-py3-none-any.whl
- Upload date:
- Size: 102.6 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.14.3
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
47ffaada44821c1b7301306a8b71bd295a73aa413fa40b24292a9400ab1ff3c0
|
|
| MD5 |
bce0f552c57c0e50c4bb9eb61fcfcefb
|
|
| BLAKE2b-256 |
cf4700e5661c03643aac5285d7e172ab973f92f9616ae14eeb8f8bb4d02699cc
|