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¶
Open the link in your invitation email. It is valid for 14 days.
Sign up with the invited email address. Opening the link proves that you can read that mailbox, so the address counts as verified.
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.
Create an organization, for example “Example Agency”. You become its owner.
Under Sites, choose Add a site and fill in:
Field
Value
Name
Example website
Base URL
https://www.example.comSource language
English
Adapters
django CMS
Engines
DeepL and LLM
Content is only sent to the engines you enable here.
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.
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¶
Connect a site through the API explains what a real connector does.
Manage the glossary keeps product names and key terms consistent.
The content model describes units, segments and fingerprints in depth.