Your first translation

In this tutorial you set up Ponyglot Cloud from scratch and translate one page. You play the part of a connector with the reference client, a small script that speaks the Ponyglot API. By the end you will have:

  • an organization with one site and an API key,

  • a django CMS pricing page, with its existing German, French and Italian translations, stored in Ponyglot,

  • seen how a change on the page makes translations stale,

  • translated only what changed, pulled the results as drafts and approved them,

  • seen the result in the dashboard’s segment × language matrix.

It takes about half an hour.

Before you start

You need:

  • an invitation to Ponyglot. During early access, you join through an invitation email.

  • Python 3.10 or newer and a terminal. The reference client uses only the standard library, so there is nothing to install.

  • a subscription for the translation step. Hosted translation needs a plan that covers your site (see Plans and usage). Everything before that step works without one.

Local development server

You can follow the tutorial against a local development server of Ponyglot Cloud instead of the hosted service. Use http://app.localhost:8000 for the dashboard and http://api.localhost:8000/v1 for the API, and keep the background worker running, because translation jobs run there. A local server may not require a subscription.

Accept the invitation and sign in

  1. Open the link in your invitation email. It is valid for 14 days.

  2. Sign up with the invited email address. Opening the link proves that you can read that mailbox, so the address counts as verified.

  3. Choose a password, or sign up with a passkey if your browser offers one.

You land on the dashboard at https://app.ponyglot.app/.

Create an organization and a site

An organization holds your sites, glossary, translation memory, brand voice, members and subscription. A site is one website or app that sends content to Ponyglot.

  1. Create an organization, for example “Example Agency”. You become its owner.

  2. Under Sites, choose Add a site and fill in:

    Field

    Value

    Name

    Example website

    Base URL

    https://www.example.com

    Source language

    English

    Adapters

    django CMS

    Engines

    DeepL and LLM

    Content is only sent to the engines you enable here.

  3. Add three target languages: German, French and Italian. Leave formality on Default, the engine on Automatic (DeepL where it supports the language, otherwise the LLM) and Writable checked.

  4. Save.

Create an API key

On the site’s page, under API keys, enter a name such as “Tutorial” and choose Create API key. The key starts with pg_.

Important

Copy the key now. Ponyglot stores only a hash of it and can’t show it again. If you lose it, revoke it and create a new one.

In your terminal, set the key and the API address:

$ export PONYGLOT_API_KEY=pg_…
$ export PONYGLOT_API_URL=https://api.ponyglot.app/v1

Get the reference client

Download the reference client and the two example pages into one directory:

Check that the key works:

$ python refclient.py site

The client prints your site with its source language, target languages and enabled engines.

Introduce the connector

A connector starts with a handshake. It reports its version and the languages configured on the website. Ponyglot answers with the site settings and warns about mismatches.

$ python refclient.py handshake --languages en de fr it

The response lists de, fr and it with "writable": true, and warnings is empty. Try --languages en de fr to see a warning that Italian isn’t configured on your site, then run the command above again.

Push a page

The file djangocms_pricing.json describes a django CMS pricing page as one unit (djangocms:page:42) with nine segments: the title, the meta description, text plugins, a link text and an image’s alt text. Most segments already carry German, French and Italian translations, as a site that’s already multilingual would send them.

$ python refclient.py push djangocms_pricing.json
{
  "external_key": "djangocms:page:42",
  "unit_created": true,
  "added": 9,
  "changed": 0,
  "removed": 0,
  "unchanged": 0,
  "stale_translations": 0,
  "imported_translations": 23,
  "fingerprint_mismatches": []
}

Ponyglot stored the 23 existing translations as approved. They also seed your translation memory. Now look at the page’s matrix:

$ python refclient.py status djangocms:page:42
Pricing  /pricing/
2 of 9 segments need work

segment              DE      FR      IT
title                ✓       ✓       ✓
meta_description     ✓       ✓       ✓
plugin:101:body      ✓       ✓       ✓
plugin:103:title     ✓       ✓       ✓
plugin:103:body      ✓       ✓       ✓
plugin:104:title     ✓       ✓       ✓
plugin:104:body      ✓       ✓       ·
plugin:105:link_text ✓       ✓       ✓
plugin:106:alt       ·       ·       ·

✓ means approved and current, · means missing. The Italian Agency text and the alt text have no translation yet.

Change the source

An editor changes the Pro plan’s text on the English page. The connector pushes the complete page again:

$ python refclient.py push djangocms_pricing_edited.json

The response shows "changed": 1 and "stale_translations": 3. Ponyglot compared the segment’s fingerprint with the stored one, noticed the new text, and now considers its three translations stale. The other segments are untouched.

$ python refclient.py status djangocms:page:42

plugin:103:body now shows stale in all three languages. Seven segment translations need work: three stale, four missing.

Translate what changed

Note

This step uses hosted engines and needs a subscription. If you are the organization’s owner, choose a plan under Billing. Without one, the request fails with HTTP 402 and a message that explains what’s missing.

Ask for a delta translation. It covers everything missing or stale in the site’s writable languages. --wait polls until the job has finished.

$ python refclient.py translate --wait
job 1 delta [de, fr, it]: succeeded · 7/7 segments · 414 characters · 0 failed

The 414 characters are the source characters sent to a translation engine: three alt texts, one Agency text and three Pro texts, markup included. Segments found in your translation memory cost nothing. The job number and the IDs below will differ on your site.

Pull the results as drafts

A real connector now fetches the results and writes them as drafts (django CMS, Wagtail) or suggestions (models). Nothing is published. Pull them without acknowledging first:

$ python refclient.py pull
r_5012  de  djangocms:page:42  plugin:103:body
        <p>79 € pro Site und Monat, 500.000 Zeichen und Translation Memory inklusive.</p>
…
7 result(s)

Run it again: the same results are still there. Until the connector acknowledges them, Ponyglot keeps offering them, so a crash between fetching and writing loses nothing.

Now write the drafts (the reference client only prints them), acknowledge them, and play the editor who approves every draft:

$ python refclient.py pull --ack --approve

The client reports {'acknowledged': 7} and {'updated': 7, 'ignored': []}. Approved texts go into the translation memory, so the next page that uses the same sentence gets it for free.

Tip

To reject a single draft instead, use its result ID: python refclient.py review rejected r_5012. The segment counts as missing again and the next delta job translates it.

See the result

$ python refclient.py status djangocms:page:42

Every cell shows ✓. Now open the dashboard:

  • The site page shows counts per language (up to date, stale, in review, missing, needs attention) and the job you ran.

  • Content lists the site’s units. Open Pricing to see the same segment × language matrix, with the action Retranslate stale → drafts.

  • Memory lists the approved translations, including the imported ones.

  • Usage shows the characters of this month’s job.

What you learned

  • A connector pushes complete snapshots of units. Ponyglot works out what was added, changed or removed.

  • A changed source makes its translations stale. A delta job translates only stale and missing segments.

  • Results arrive as drafts. The connector acknowledges them, and editors approve or reject them on the site.

Next steps