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

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. 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",
    
  3. 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.

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.1.0.tar.gz (71.4 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.1.0-py3-none-any.whl (102.6 kB view details)

Uploaded Python 3

File details

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

File metadata

File hashes

Hashes for djangocms_deepl_translations-0.1.0.tar.gz
Algorithm Hash digest
SHA256 74f363df02ec581b4839647bed91aed83bebe0f249eeb935aa384355d81e807d
MD5 1a4d47a131e31c58de3b6821eb4a7f40
BLAKE2b-256 7adb57352df9ad4941e89dff627f330482d20cea88ec13cab8d5c015825ce796

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for djangocms_deepl_translations-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 47ffaada44821c1b7301306a8b71bd295a73aa413fa40b24292a9400ab1ff3c0
MD5 bce0f552c57c0e50c4bb9eb61fcfcefb
BLAKE2b-256 cf4700e5661c03643aac5285d7e172ab973f92f9616ae14eeb8f8bb4d02699cc

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