Skip to content

Languages and translation

A workflow that serves customers in several countries has to answer three questions: which language a model writes in, how to translate a text without breaking what a later step still needs — a name, a code, a marker — and how each language writes a date, an amount, a time. Models handle the first two well when they are told exactly what to do; the third is better left to Format as Text, which writes 18. Oktober 2026 and 12,50 € the same way every time.

Subtitles have their own page: Translating captions translates timed captions line by line without touching the timing, with glossaries and a repair round. This page is about the text around them.

  • Say it, in the system prompt: “Write in German”. A model asked in English for a text about Italy may otherwise answer in either.
  • Or follow the reader: “reply in the language the customer wrote in”. In the email-sorting lab an email in Italian got its reply in Italian, one in English in English. Ask for the language code as well ("reply_language": "it"), so the rest of the workflow can choose the right template or voice for it.
  • Or pass it as data: a locale that comes with an order (de-CH) goes into the prompt through a template — “Write in the language of this locale: [locale]” — and into Format as Text, so the words and the figures agree.

Text Generation translates well when the system prompt says what a translator would ask:

  • Translate the meaning and the tone, not word by word: a notice should read as if it had been written in that language.
  • What is never translated: the brand, product and place names, codes. List them.
  • What a later step fills in: keep every [marker] exactly as written, and say what each marker will hold. A translator who sees [date] cannot know that it becomes “domenica 18 ottobre 2026”; in the lab the Italian translation wrote “del [date]”, which is correct for “del 18 ottobre” and wrong for “del domenica 18 ottobre”. Asking harder did not fix it; choosing a form that fits every language did — the date without the weekday.

And keep data out of the text. A source that says “on Saturday 18 October … a refund of EUR 12.50” is translated around those words; the lab’s first attempt, told to keep dates and prices as written, left “Saturday 18 October” in English inside the Italian, German and French notices, and “EUR 12.50” with a decimal point. Write the source with markers — “on [date] … a refund of [refund]” — and fill them after the translation with values that Format as Text writes in each language. The date, the amount and the code then cannot be mistranslated, and they are the same in every language because they come from the same data.

Before filling, check that the markers survived: a Replace Text with use_regex, find \[(booking_code|date|refund)\] and replace_with $0 leaves the text unchanged and counts the markers on count — 3 in every language of the lab.

Pattern How Use it when
One answer, a key per language Text Generation in JSON mode returns {"it": …, "de": …, "fr": …}; Extract reads each short texts in a few languages: one call, the same terms in every language, the cheapest
One step per language the list of languages is enumerated and Text Generation runs once per language long texts, many languages, or a different model or brief per language
One template per language the texts are written once by people; Select by Key picks the template by locale legal lines, confirmations, anything that must not vary — no model at all

Many workflows combine them: fixed sentences from per-language templates, a model only for the part that must be written, and Format as Text for every figure.

Node Setting Note
Format as Text locale and currency, also as inputs numbers, money, percentages and dates in the reader’s conventions
Product Description language: en, it, de, fr, es, pt, nl, pl, ja, ko, zh writes the listing directly in that language
Caption Translation target_language, glossary timed captions; see Translating captions
Speech to Text the spoken language, or detection see Transcription and captions

A ferry company on an Alpine lake cancels a crossing because of the wind and tells each booked passenger in their language. The notice is written once in English, with markers; one Text Generation step translates it into Italian, German and French in one JSON answer; a Replace counts the markers in each translation; Format as Text writes the date and the refund in each language; a template fills the markers.

The lab: four inputs — the notice in English, the booking code, the day of the crossing in ISO form and the refund; Translate into three languages (Text Generation, JSON mode); three Extract steps read the Italian, German and French notices; for each language a Replace counts the markers (3), two Format as Text steps write the date and the refund in it-IT, de-DE and fr-FR, and a Text Template fills the notice.

The source:

Dear passenger, because of strong wind the 14:20 crossing from Bellano Pier to Varenna Pier on [date] will not run.
Your booking [booking_code] has been moved to the 15:05 crossing on the Aurora, at no extra cost. If that time does
not suit you, you can change it for free until 13:00, or ask for a full refund of [refund] at any ticket office. We
are sorry for the inconvenience. Lake Line Ferries

with date 2026-10-18, refund 12.5, booking_code LLF-7Q42. The results:

it — Gentile passeggero, a causa del forte vento la traversata delle 14:20 da Bellano Pier a Varenna Pier del 18 ottobre 2026 non verrà effettuata. La prenotazione LLF-7Q42 è stata spostata sulla traversata delle 15:05 a bordo dell’Aurora, senza costi aggiuntivi. […] richiedere un rimborso completo di 12,50 € presso qualsiasi biglietteria.

de — Sehr geehrter Fahrgast, aufgrund starken Windes fällt die Überfahrt um 14:20 Uhr von Bellano Pier nach Varenna Pier am 18. Oktober 2026 aus. Ihre Buchung LLF-7Q42 wurde ohne Aufpreis auf die Überfahrt um 15:05 Uhr mit der Aurora umgebucht. […] eine vollständige Rückerstattung von 12,50 € beantragen.

fr — Cher passager, en raison de vents violents, la traversée de 14 h 20 de Bellano Pier à Varenna Pier le 18 octobre 2026 n’aura pas lieu. Votre réservation LLF-7Q42 a été reportée sur la traversée de 15 h 05 à bord de l’Aurora, sans frais supplémentaires. […] demander le remboursement intégral de 12,50 € à n’importe quelle billetterie.

  • The names stayed as they are; the times follow each language (14:20 Uhr, 14 h 20), as the brief asked.
  • The date and the refund were never seen by the model: Format as Text wrote 18 ottobre 2026, 18. Oktober 2026, 18 octobre 2026 and 12,50 €.
  • It took three runs to get here, and each taught one rule of this page: the first left “Saturday 18 October” and “EUR 12.50” untranslated (keep data out of the text); the second and third wrote “del domenica” (choose a form that fits every language).
  • A model is a fluent translator, not a native one: the German used “an jeder Fahrkartenschalterstelle”, a word a German speaker would not write. Have a native speaker read the first notices of a new template.

The run costs about 0.04 credits: one call for the three languages.

Terminal window
node madoo-install-example.mjs lab-languages --api <your Madoo API URL> --key <key.json> --run
Symptom Cause What to do
A date or an amount stays in the source language or format it was in the text, and the model was told to keep it write it as a marker and fill it with Format as Text per language
A marker is missing or translated ([datum]) the model rewrote it say in the system prompt to keep every [marker] exactly as written; count them with Replace before filling
A sentence does not agree with the value filled in the translator did not know what the marker holds say what each marker holds; choose a form that fits every language
The answer is in the wrong language the language was not stated state it in the system prompt, or ask for the customer’s language and its code
A name was translated it was not listed as untranslatable list brand, product and place names in the system prompt
A word reads oddly to a native speaker a model’s fluency is not a native’s have the first texts of a new template read by a native speaker