Skip to main content

No project description provided

Project description

djangocms-deepl-translations

Allows to translate Django CMS 5+ content using the DeepL API.

Pipeline badge Coverage badge Release badge Django Packages

Installation

  1. Install the module from PyPI:

    python3 -m pip install djangocms-deepl-translations
    

    Or, if you're using poetry :

    poetry add djangocms-deepl-translations
    
  2. Optionally, install the versioning extension from PyPI:

    python3 -m pip install djangocms-deepl-translations[versioning]
    

    Or, if you're using poetry :

    poetry add djangocms-deepl-translations[versioning]
    
  3. 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 before djangocms_deepl_translations. The contrib’s ready() 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",
    
  4. 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: when True (default), Django's system check warns when installed CMS plugin types have no translation config. Set to False to disable these warnings.

  • DJANGOCMS_DEEPL_TRANSLATIONS_BULK_TRANSLATE_DEFAULT_USER_ID: optional integer user id used by bulk_translate_pages (and related bulk commands) when --user is 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):

  1. 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.
  2. 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

  1. Install project dependencies with Poetry from the repository root (see Installation for runtime deps):

    poetry install
    
  2. Install Poethepoet so the poe tasks are available (it is listed under the dev dependency group):

    poetry install --with dev
    
  3. Optional — auto-translation of .po files uses django-deep-translator via the translate_messages management command. Install the i18n_tools optional 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 .po files under djangocms_deepl_translations/locale/ and contrib locale/ trees.
  • translate_messages — fill empty/fuzzy entries in those .po files using machine translation (requires --with i18n_tools).
  • compilemessages — compile .po to .mo for 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.

  1. 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)"
    
  2. Install the runtimes you need, e.g. pyenv install 3.10.13 (repeat for 3.11, 3.12, …).
  3. 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-version so python3.10, python3.11, … resolve correctly.
  4. 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


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

djangocms_deepl_translations-0.2.2.tar.gz (77.5 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

djangocms_deepl_translations-0.2.2-py3-none-any.whl (116.6 kB view details)

Uploaded Python 3

File details

Details for the file djangocms_deepl_translations-0.2.2.tar.gz.

File metadata

File hashes

Hashes for djangocms_deepl_translations-0.2.2.tar.gz
Algorithm Hash digest
SHA256 925b1c4577ecbb1b47855d36f52b0627e42b17d1a51ab60f3fe45078febac631
MD5 248b5c477bc632accc36daacba20218d
BLAKE2b-256 3572ceae53d8158988e3d78adb45f2adc992ed3104147b3173ae7c3359000a8b

See more details on using hashes here.

File details

Details for the file djangocms_deepl_translations-0.2.2-py3-none-any.whl.

File metadata

File hashes

Hashes for djangocms_deepl_translations-0.2.2-py3-none-any.whl
Algorithm Hash digest
SHA256 bb46d2ac3c019fa95808e00cd6786adcb78af2ae7ab463c924b262110c3c4683
MD5 007ad3c9dc5918912bfcd84975073de8
BLAKE2b-256 1c3d305d3d98496a344da1302dc69016b55614d9c02c7712aacb5a9fad2f5a6f

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page