Launchee translate: DeepL from the clipboard, formal or informal

Copy, type en2de, press ↩: Launchee sends the clipboard to DeepL and puts the translation back. Formal by default, -du or -tu for the informal form.

The Launchee app icon: the white hexagon edelweiss logo on a black square, with the name Launchee under it and a red text caret after the name

I translate with 1 keyword in my launcher. I copy a text, open Launchee with ⌘Space, type en2de and press ↩. The German translation replaces the clipboard, and a notice shows its first line. I paste it where I need it.

The translation comes from the DeepL API, which I have used for years (see Translatee). In 2024 I had 1 Alfred keyword per Python script. Now it's 1 pack file in Launchee and 1 shared script, built with Claude Code on 7th November 2026. For the launcher itself, see Launchee: my own keyboard launcher for macOS.

The keywords

The keyword is <from>2<to>. German and French targets come in the formal form by default, because most of what I translate is for work. To get the informal form, add the pronoun: -du for German, -tu for French.

Keyword Translates
en2de English to German, with "Sie"
en2de-du English to German, with "du"
en2fr English to French, with "vous"
en2fr-tu English to French, with "tu"
fr2de French to German, with "Sie"
fr2de-du French to German, with "du"
de2fr German to French, with "vous"
de2fr-tu German to French, with "tu"
fr2en French to English (British)
de2en German to English (British)

Typing en2de shows both German rows, so I pick the form with the arrow keys and never have to remember the suffix.

The same sentence, with both forms:

Keyword Result
en2de Guten Morgen, könnten Sie mir den Bericht bitte bis Freitag zukommen lassen?
en2de-du Guten Morgen, könntest du mir den Bericht bis Freitag schicken?

DeepL doesn't just swap the pronoun. The formal version also gets "bitte" and the more polite "zukommen lassen".

Text after the keyword wins over the clipboard: en2fr-tu see you tomorrow translates the typed words.

Why a suffix for the formality

I had 3 options for formal and informal:

Option For Against
A suffix keyword (the pick): en2de-du Both rows show, nothing to recall 2 keywords per German or French target
A word after the keyword: en2de du 1 keyword Clashes with typed text: is "du" the text?
↩ formal, ⌘↩ informal 1 row Hidden: nothing on screen says which key is which

The suffix is the only one I can see in the bar.

How it works

The pack. ~/.launchee/commands/translate.jsonc holds the 10 commands. Each one runs the script with the clipboard on standard input and copies the output to the clipboard:

{"id": "deepl-en2de-du", "title": "Translate English to German (du)", "keyword": "en2de-du", "arg": "optional",
 "stdin": "clipboard", "output": "copy", "timeout": 25,
 "run": ["~/ai/_shared/deepl.py", "--from", "en", "--to", "de", "--formality", "informal", "{query}"]}

The script. ~/ai/_shared/deepl.py is standard-library Python, so any NicAI agent can use it too:

pbpaste | python3 ~/ai/_shared/deepl.py --from en --to de --formality informal
python3 ~/ai/_shared/deepl.py --to fr --formality formal "Could you send me the report?"
  • Formality. formal sends DeepL prefer_more, informal sends prefer_less. The prefer_ values never fail: for a language without formal and informal forms, DeepL ignores them. DeepL supports formality for German, French, Italian, Spanish, Dutch, Polish, Portuguese, Japanese and Russian.
  • English and Portuguese. DeepL needs a variant for these targets. The script sends EN-GB and PT-PT.
  • The key. It reads DEEPL_API_KEY from my shared .env. A key that ends in :fx is a free key, and the script then calls api-free.deepl.com instead of api.deepl.com.
  • Errors. An empty clipboard, a refused key (403) or a used-up monthly quota (456) ends in a Launchee notice with the reason. The clipboard keeps the original text.

The runner. Launchee runs the script in a child process with a 25 s deadline, as every command, so a slow DeepL answer never blocks the bar.

Adding a language

The pack is generated: 3 languages give 6 pairs, and German and French targets get 2 rows each. A 4th language, such as Spanish with -tu, means 1 more line in the generator and 1 more run. The script needs no change.

Further reading

The API reference for the translate call, with the formality values:

Which languages support formality:

The plans, including the free API:

NicAI
Written by NicAI, Nic's AI assistant, for his personal knowledge base. Researched and drafted by the model, not hand-written by Nic. Verify anything you plan to act on.