Install Ponyglot with an AI agent

This page is written for coding agents such as Claude Code, Cursor or Copilot, and for the people who use them. It gives the exact steps to add Ponyglot to a Django project, and marks the steps that need a person. A plain-text index of everything is at /llms.txt.

Status: early access (alpha). Accounts are invite-only; the agent can do all the local setup without one.

Rules for agents

  1. Don’t publish content. Ponyglot delivers translations as drafts (django CMS, Wagtail) or as suggestions (models). Leave publishing and applying to an editor. Don’t set PUBLISH_BY_DEFAULT unless the person asks for it.
  2. Don’t spend money without approval. Requesting translation is billed. Run ponyglot translate --estimate first, show the result, and only run ponyglot translate after the person agrees. Never add --yes (confirms large jobs) on your own.
  3. Keep the API key out of the repository. Read it from the environment (PONYGLOT_API_KEY); don’t write it into settings files or commit it.
  4. Account, subscription and API key are the person’s job. Don’t try to sign up or buy a plan; tell the person what’s needed (step 5).

1. Detect the stack

Check the project’s dependencies and INSTALLED_APPS:

Found Content Install Add to INSTALLED_APPS
cms (django CMS 5.1+) Pages, posts, aliases, other frontend-editable models pip install "djangocms-ponyglot[versioning]" "ponyglot", "djangocms_ponyglot"
wagtail and wagtail_localize Pages and snippets see below "ponyglot", "wagtail_ponyglot"
parler Models translated with django-parler pip install "ponyglot[parler]" "ponyglot", "ponyglot.contrib.parler"
modeltranslation Models translated with django-modeltranslation (also wagtail-modeltranslation) pip install "ponyglot[modeltranslation]" "ponyglot", "ponyglot.contrib.modeltranslation"
locale/ directories with .po files Interface strings (gettext) pip install "ponyglot[gettext]" none, see step 8

Combine them as needed ("ponyglot" only once). A django CMS site with djangocms-stories or another parler app usually needs both djangocms_ponyglot and ponyglot.contrib.parler.

Wagtail: the wagtail-ponyglot connector isn’t publicly available yet; the package on PyPI is only a name reservation. Don’t install it. Tell the person to ask at hello@ponyglot.app for early access. Models translated with wagtail-modeltranslation work today through ponyglot[modeltranslation].

Requirements: Python 3.10+, Django 5.2+. django CMS 5.1+; without djangocms-versioning 2.7+, translations can’t arrive as drafts and wait until an editor applies them. For django-modeltranslation, Ponyglot only fills languages whose database columns already exist.

If none of these libraries is installed, the project has no translatable content in the database yet. Choosing a translation library is a design decision for the person, not part of this setup.

2. Install and configure

Add the package to the project’s dependency file (pyproject.toml, requirements.txt, …) the way the project already does it, then install. Add to the settings:

import os

INSTALLED_APPS += [
    "ponyglot",
    "djangocms_ponyglot",        # django CMS
    "ponyglot.contrib.parler",   # django-parler models
]

PONYGLOT = {
    "API_KEY": os.environ.get("PONYGLOT_API_KEY", ""),
    "SOURCE_LANGUAGE": "en",     # the language editors write in; must be in LANGUAGES
}

Use the project’s existing way of reading environment variables if it has one (django-environ, python-decouple, …). The site’s languages come from LANGUAGES; set PONYGLOT["LANGUAGES"] only to limit them. All settings: connector settings.

3. Migrate and check

python manage.py migrate
python manage.py check

Without an API key, check shows the warning ponyglot.W001. That’s expected at this point. ponyglot.E001 means SOURCE_LANGUAGE isn’t one of the site’s languages: fix it before going on.

4. Count the content (no account needed)

python manage.py ponyglot backfill --dry-run

This runs locally and sends nothing. It prints the number of units, segments and source characters. Show it to the person: it’s the size of the first translation. Characters are counted per target language, so multiply by the number of target languages. Translation-memory hits and existing translations aren’t billed. For django CMS, python manage.py ponyglot_fields --translated lists which plugin fields will be translated.

5. What the person does

Stop here and tell the person:

  1. Account: request an invitation at hello@ponyglot.app (early access).
  2. Site: in the dashboard at app.ponyglot.app, create a site with the source and target languages.
  3. API key: on the site’s page, under API keys (needs the admin or owner role). Store it as the environment variable PONYGLOT_API_KEY locally and in deployment.
  4. Subscription: connecting and pushing content works without one; requesting hosted translation needs a subscription that covers the site. See plans.

6. Connect and push the content

With PONYGLOT_API_KEY set:

python manage.py ponyglot check      # settings and connection; non-zero exit on failure
python manage.py ponyglot backfill   # first push of all existing content
python manage.py ponyglot status     # per language: ✓ / stale / review / missing

Existing translations are imported on the first push, so nothing is translated twice.

Then make the sync run regularly. Saving content only marks it as changed; ponyglot sync pushes changes, reports editors’ reviews and fetches translations. Add it the way the project runs background work, for example:

# worker process (Procfile, systemd, container)
python manage.py ponyglot sync --loop 60
# or cron, every few minutes
*/5 * * * * cd /path/to/project && python manage.py ponyglot sync

See run the sync.

7. Translate (needs the person’s approval)

python manage.py ponyglot translate --estimate                 # cost; nothing is sent to an engine
python manage.py ponyglot translate --wait                     # after the person agreed
python manage.py ponyglot translate --language fr --estimate   # one language
python manage.py ponyglot sync                                 # fetch the translations

If translate says the job needs confirmation, show the estimate to the person; add --yes only if they confirm.

Where the translations arrive, for the person to review:

  • django CMS: as drafts; toolbar › Language › Ponyglot translations.
  • Models: admin › Ponyglot › Translation suggestions, with a diff; Apply or Reject. Add PonyglotAdminMixin to the model admins for per-object dialogs (how-to).
  • Whole site: admin › Ponyglot › Translation dashboard.

8. .po files (optional)

export PONYGLOT_API_KEY=pg_…    # a site with the gettext adapter
python manage.py makemessages -l de -l fr
ponyglot po sync locale          # writes translations into the .po and .mo files

Run it on a checkout of the default branch and commit the result to a review branch. Merging is the approval. Don’t merge it yourself.

When something fails

Commands exit non-zero with a message on failure.

Message Fix
No adapter installed Add an adapter (step 1) to INSTALLED_APPS.
ponyglot.W001 No API key yet (step 5).
ponyglot.E001 Set PONYGLOT["SOURCE_LANGUAGE"] to one of LANGUAGES.
subscription_inactive or HTTP 402 No active subscription for this site; the person handles billing.
This job needs confirmation Show the estimate; --yes only with the person’s OK.

More: install guide, connector commands, docs. Questions: hello@ponyglot.app.

Ponyglot is a personal project of Fabian Braun, the django CMS fellow; it is not a product of the django CMS Association. Connectors are BSD-3-Clause.