v0.1.1 · 100% on-device · MIT

translate

Apple Translation from your terminal.

A UNIX filter and a drop-in HTTP server for DeepL, LibreTranslate, and Google Translate v2 - all wrapped around Apple's on-device Translation framework. No cloud, no LLM, no API keys, no rate limits.

100% on-device No API keys 3 drop-in APIs NetworkGuard enforced
$brew install Arthur-Ficial/tap/translate

Source: github.com/Arthur-Ficial/translate

Requires: macOS 26 Tahoe · Apple Silicon · Translation models installed via System Settings

Everything runs on your device. No network calls. No data leaves your Mac. Enforced at runtime by a URLProtocol guard that hard-exits any HTTP attempt.
Watch it work

Text in. Translation out.

The same binary is a UNIX filter, a batch translator, and a drop-in HTTP server. Pick the surface you need - the engine is the same.

Terminal — translate (real captures, not stubs)
$ translate "Hallo Welt" --to en --no-install --quiet Hello world $ translate "hello world" --from en --to de --no-install --quiet Hallo Welt $ translate "good morning" "see you tomorrow" --from en --to de --no-install --quiet Guten Morgen Bis morgen $ translate --detect-only "Ceci est une phrase française avec plusieurs mots." fr 0.999956 $ printf 'Hallo Welt.\n\nGuten Morgen.\n' | translate --to en --from de --no-install --quiet --format ndjson {"from":"de","to":"en","src":"Hallo Welt.","dst":"Hello world.","conf":1} {"from":"de","to":"en","src":"Guten Morgen.\n","dst":"Good morning.\n","conf":1} $ translate --version 0.1.1
Why translate

Zero cost. Zero downloads. Zero limits.

Apple's Translation framework ships with macOS Tahoe. translate is a thin Swift wrapper that makes it accessible from the shell and from existing translation client SDKs.

$0
Per request
No API keys, no per-character billing, no usage tier. Translate a million strings.
100%
On-device
No network calls. Hard-enforced at runtime by NetworkGuard - any HTTP attempt aborts.
3
APIs spoken
Drop-in for DeepL v2, LibreTranslate, and Google Translate v2. Existing clients work unchanged.
199
Tests passing
140 Swift unit + integration tests, plus 59 real-client scenes that drive the official deepl SDK, libretranslatepy, and raw requests against the live server.
Two surfaces, one engine

What translate does.

UNIX filter for the shell, HTTP server for everything else. Same Apple Translation framework underneath.

Translate

translate --to en

The default mode. Reads stdin (or positional args, or --file), detects the source language, runs Apple's on-device Translation framework, writes the result to stdout.

$ translate "Hallo Welt, wie geht es dir?" --to en --no-install --quiet
Hello world, how are you?

Detect

translate --detect-only

Identify the language without translating. Returns BCP-47 code and confidence (0..1) via Apple's NaturalLanguage framework. Use it to route text to the right downstream pipeline.

$ translate --detect-only "Det är svenska."
sv	0.999955

Stream

translate --batch | --format ndjson

Pipe arbitrary-size text through. Paragraph-mode buffers full paragraphs; --batch treats each line as an independent unit. URLs, emails, and code spans pass through untranslated.

$ printf 'Hallo.\n\nWelt.\n' | translate --to en --from de --no-install --quiet --format ndjson
{"from":"de","to":"en","src":"Hallo.","dst":"Hello.","conf":1}
{"from":"de","to":"en","src":"Welt.\n","dst":"World.\n","conf":1}

Serve

translate --serve

HTTP server byte-compatible with three production translation APIs. The official deepl Python SDK, libretranslatepy, and any Google v2 REST client work unchanged - just override the base URL.

$ translate --serve --port 8989
translate: serving on http://127.0.0.1:8989

See the next section for real wire traffic.
Real wire traffic

The DeepL, LibreTranslate, and Google v2 surfaces.

Every request and response below was captured at build time by running translate --serve on a free port and hitting it with curl. No paraphrasing, no pseudo-code -- the bytes the server sent are the bytes you see.

DeepL v2 compatible

POST /v2/translate -- single string
curl -s -X POST --data-urlencode 'text=Hallo Welt.' --data-urlencode target_lang=EN --data-urlencode source_lang=DE http://127.0.0.1:8989/v2/translate
HTTP/1.1 response
HTTP/1.1 200 OK
Content-Type: application/json
Access-Control-Allow-Origin: *
Access-Control-Allow-Headers: Authorization, Content-Type, X-goog-api-key, DeepL-Auth-Key
Access-Control-Allow-Methods: GET, POST, OPTIONS
Access-Control-Expose-Headers: Content-Type
Content-Length: 97

{
  "translations": [
    {
      "detected_source_language": "DE",
      "text": "Hello world.",
      "billed_characters": 11
    }
  ]
}
POST /v2/translate -- batch (3 strings)
curl -s -X POST --data-urlencode text=Hallo --data-urlencode text=Welt --data-urlencode 'text=Guten Morgen' --data-urlencode target_lang=EN --data-urlencode source_lang=DE http://127.0.0.1:8989/v2/translate
HTTP/1.1 response
HTTP/1.1 200 OK
Content-Type: application/json
Access-Control-Allow-Origin: *
Access-Control-Allow-Headers: Authorization, Content-Type, X-goog-api-key, DeepL-Auth-Key
Access-Control-Allow-Methods: GET, POST, OPTIONS
Access-Control-Expose-Headers: Content-Type
Content-Length: 239

{
  "translations": [
    {
      "detected_source_language": "DE",
      "text": "Hello",
      "billed_characters": 5
    },
    {
      "detected_source_language": "DE",
      "text": "World",
      "billed_characters": 4
    },
    {
      "detected_source_language": "DE",
      "text": "Good morning",
      "billed_characters": 12
    }
  ]
}
GET /v2/languages
curl -s http://127.0.0.1:8989/v2/languages
HTTP/1.1 response (truncated)
HTTP/1.1 200 OK
Content-Type: application/json
Access-Control-Allow-Origin: *
Access-Control-Allow-Headers: Authorization, Content-Type, X-goog-api-key, DeepL-Auth-Key
Access-Control-Allow-Methods: GET, POST, OPTIONS
Access-Control-Expose-Headers: Content-Type
Content-Length: 1163

[
  {
    "language": "AR",
    "name": "Arabic"
  },
  {
    "language": "BG",
    "name": "Bulgarian"
  },
  {
    "language": "CS",
    "name": "Czech"
  },
  {
    "language": "DA",
    "name": "Danish"
  },
  {
    "_": "... 29 more"
  }
]
GET /v2/usage
curl -s http://127.0.0.1:8989/v2/usage
HTTP/1.1 response
HTTP/1.1 200 OK
Content-Type: application/json
Access-Control-Allow-Origin: *
Access-Control-Allow-Headers: Authorization, Content-Type, X-goog-api-key, DeepL-Auth-Key
Access-Control-Allow-Methods: GET, POST, OPTIONS
Access-Control-Expose-Headers: Content-Type
Content-Length: 50

{
  "character_count": 0,
  "character_limit": 1000000000
}

LibreTranslate compatible

POST /translate -- JSON body
curl -s -X POST -H "Content-Type: application/json" -d '{"q": "Hallo Welt.", "source": "de", "target": "en", "format": "text"}' http://127.0.0.1:8989/translate
HTTP/1.1 response
HTTP/1.1 200 OK
Content-Type: application/json
Access-Control-Allow-Origin: *
Access-Control-Allow-Headers: Authorization, Content-Type, X-goog-api-key, DeepL-Auth-Key
Access-Control-Allow-Methods: GET, POST, OPTIONS
Access-Control-Expose-Headers: Content-Type
Content-Length: 33

{
  "translatedText": "Hello world."
}
POST /translate -- array q
curl -s -X POST -H "Content-Type: application/json" -d '{"q": ["Hallo", "Welt", "Foo"], "source": "de", "target": "en"}' http://127.0.0.1:8989/translate
HTTP/1.1 response
HTTP/1.1 200 OK
Content-Type: application/json
Access-Control-Allow-Origin: *
Access-Control-Allow-Headers: Authorization, Content-Type, X-goog-api-key, DeepL-Auth-Key
Access-Control-Allow-Methods: GET, POST, OPTIONS
Access-Control-Expose-Headers: Content-Type
Content-Length: 42

{
  "translatedText": [
    "Hello",
    "World",
    "Foo"
  ]
}
POST /translate -- source=auto includes detectedLanguage
curl -s -X POST -H "Content-Type: application/json" -d '{"q": "Das ist ein deutscher Satz mit genug Worten.", "source": "auto", "target": "en"}' http://127.0.0.1:8989/translate
HTTP/1.1 response
HTTP/1.1 200 OK
Content-Type: application/json
Access-Control-Allow-Origin: *
Access-Control-Allow-Headers: Authorization, Content-Type, X-goog-api-key, DeepL-Auth-Key
Access-Control-Allow-Methods: GET, POST, OPTIONS
Access-Control-Expose-Headers: Content-Type
Content-Length: 119

{
  "detectedLanguage": {
    "confidence": 100,
    "language": "de"
  },
  "translatedText": "This is a German sentence with enough words."
}
POST /detect
curl -s -X POST -H "Content-Type: application/json" -d '{"q": "Das ist ein deutscher Satz mit genug Worten zum Erkennen."}' http://127.0.0.1:8989/detect
HTTP/1.1 response
HTTP/1.1 200 OK
Content-Type: application/json
Access-Control-Allow-Origin: *
Access-Control-Allow-Headers: Authorization, Content-Type, X-goog-api-key, DeepL-Auth-Key
Access-Control-Allow-Methods: GET, POST, OPTIONS
Access-Control-Expose-Headers: Content-Type
Content-Length: 36

[
  {
    "confidence": 100,
    "language": "de"
  }
]

Google Translate v2 compatible

POST /language/translate/v2 -- single q (form)
curl -s -X POST --data-urlencode 'q=Hallo Welt.' --data-urlencode target=en --data-urlencode source=de http://127.0.0.1:8989/language/translate/v2
HTTP/1.1 response
HTTP/1.1 200 OK
Content-Type: application/json
Access-Control-Allow-Origin: *
Access-Control-Allow-Headers: Authorization, Content-Type, X-goog-api-key, DeepL-Auth-Key
Access-Control-Allow-Methods: GET, POST, OPTIONS
Access-Control-Expose-Headers: Content-Type
Content-Length: 91

{
  "data": {
    "translations": [
      {
        "detectedSourceLanguage": "de",
        "translatedText": "Hello world."
      }
    ]
  }
}
POST /language/translate/v2 -- repeated q (batch)
curl -s -X POST --data-urlencode q=Hallo --data-urlencode q=Welt --data-urlencode target=en --data-urlencode source=de http://127.0.0.1:8989/language/translate/v2
HTTP/1.1 response
HTTP/1.1 200 OK
Content-Type: application/json
Access-Control-Allow-Origin: *
Access-Control-Allow-Headers: Authorization, Content-Type, X-goog-api-key, DeepL-Auth-Key
Access-Control-Allow-Methods: GET, POST, OPTIONS
Access-Control-Expose-Headers: Content-Type
Content-Length: 141

{
  "data": {
    "translations": [
      {
        "detectedSourceLanguage": "de",
        "translatedText": "Hello"
      },
      {
        "detectedSourceLanguage": "de",
        "translatedText": "World"
      }
    ]
  }
}
GET /language/translate/v2/languages
curl -s http://127.0.0.1:8989/language/translate/v2/languages
HTTP/1.1 response (truncated)
HTTP/1.1 200 OK
Content-Type: application/json
Access-Control-Allow-Origin: *
Access-Control-Allow-Headers: Authorization, Content-Type, X-goog-api-key, DeepL-Auth-Key
Access-Control-Allow-Methods: GET, POST, OPTIONS
Access-Control-Expose-Headers: Content-Type
Content-Length: 1186

{
  "data": {
    "languages": [
      {
        "language": "ar",
        "name": "Arabic"
      },
      {
        "language": "bg",
        "name": "Bulgarian"
      },
      {
        "language": "cs",
        "name": "Czech"
      },
      {
        "language": "da",
        "name": "Danish"
      },
      {
        "_": "... 29 more"
      }
    ]
  }
}
GET /health (any client, any time)
curl -s http://127.0.0.1:8989/health
HTTP/1.1 response
HTTP/1.1 200 OK
Content-Type: application/json
Access-Control-Allow-Origin: *
Access-Control-Allow-Headers: Authorization, Content-Type, X-goog-api-key, DeepL-Auth-Key
Access-Control-Allow-Methods: GET, POST, OPTIONS
Access-Control-Expose-Headers: Content-Type
Content-Length: 33

{
  "ok": true,
  "service": "translate"
}
How it works

Apple's translation engine. UNIX semantics. HTTP wrapper.

translate is a thin Swift CLI over the Translation framework. The model lives in macOS Tahoe - translate just gives you a way to call it from the shell, the pipe, or another process.

1

Text in (any source)

Positional args, stdin pipe (echo x | translate --to en), --file, or HTTP body when running --serve. UTF-8 only.

2

Translation, on-device

translate calls TranslationSession on your Mac's Apple Silicon. The model is shipped with macOS - no download per request, no API key, no quota.

3

Structured output

Plain text, JSON, or NDJSON. Pipe to jq, feed into apfel for summaries, or speak DeepL / LibreTranslate / Google v2 over HTTP.

The data flow

stdin / args / --file / HTTP body
NetworkGuard (URLProtocol)
Apple Translation framework
JSON / NDJSON / Plain → stdout / HTTP

NetworkGuard registers a URLProtocol that intercepts every http / https / ws / wss request inside the translate process and exits with code 2 plus a stderr message. The HTTP server itself is unaffected because Hummingbird opens kernel sockets that URLProtocol does not see - the guard only catches outbound URLSession calls, which is exactly the surface a future bug or dependency could leak through.

Real text, real translate

Public-domain corpus, real outcomes.

Every example below is processed by running the real translate binary (v0.1.1) on a public-domain text from the UN OHCHR archives, Wikisource, and a handful of CC0 fixtures composed for this site - at build time, on a Mac, with no network. Each card shows the source, the on-device translation, the detected source language with confidence, plus the full JSON output. Nothing is mocked or post-processed.

Alle Menschen sind frei und gleich an Würde und Rechten geboren. Sie sind mit Vernunft und Gewissen begabt und sollen einander im Geist der Brüderlichkeit begegnen.
treaty 1948 Public Domain (UN OHCHR)

Universal Declaration of Human Rights - Article 1 (German)

Die kanonische Übersetzung der Allgemeinen Erklärung der Menschenrechte. translate runs the German Article 1 to English on-device, preserving the legal cadence.

$ translate --from de --to en --no-install --quiet --format json < input.txt
Translation 1 record
de · German
Alle Menschen sind frei und gleich an Würde und Rechten geboren. Sie sind mit Vernunft und Gewissen begabt und sollen einander im Geist der Brüderlichkeit begegnen.
en · English
All people are born free and equal in dignity and rights. They are endowed with reason and conscience and should meet each other in the spirit of brotherhood.
detection confidence 100.0%
{} Raw JSON on-device output
[
  {
    "from": "de",
    "to": "en",
    "src": "Alle Menschen sind frei und gleich an Würde und Rechten geboren. Sie sind mit Vernunft und Gewissen begabt und sollen einander im Geist der Brüderlichkeit begegnen.\n",
    "dst": "All people are born free and equal in dignity and rights. They are endowed with reason and conscience and should meet each other in the spirit of brotherhood.\n",
    "conf": 1
  }
]
Source
Tous les êtres humains naissent libres et égaux en dignité et en droits. Ils sont doués de raison et de conscience et doivent agir les uns envers les autres dans un esprit de fraternité.
treaty 1948 Public Domain (UN OHCHR)

Universal Declaration of Human Rights - Article 1 (French)

The same article, this time in French. translate auto-detects the source language when --from is omitted.

$ translate --to en --no-install --quiet --format json < input.txt
Translation 1 record
fr · French
Tous les êtres humains naissent libres et égaux en dignité et en droits. Ils sont doués de raison et de conscience et doivent agir les uns envers les autres dans un esprit de fraternité.
en · English
All human beings are born free and equal in dignity and rights. They are endowed with reason and conscience and must act towards each other in a spirit of brotherhood.
detection confidence 100.0%
{} Raw JSON on-device output
[
  {
    "from": "fr",
    "to": "en",
    "src": "Tous les êtres humains naissent libres et égaux en dignité et en droits. Ils sont doués de raison et de conscience et doivent agir les uns envers les autres dans un esprit de fraternité.\n",
    "dst": "All human beings are born free and equal in dignity and rights. They are endowed with reason and conscience and must act towards each other in a spirit of brotherhood.\n",
    "conf": 0.999983
  }
]
Source
すべての人間は、生まれながらにして自由であり、かつ、尊厳と権利とについて平等である。人間は、理性と良心とを授けられており、互いに同胞の精神をもって行動しなければならない。
treaty 1948 Public Domain (UN OHCHR)

Universal Declaration of Human Rights - Article 1 (Japanese)

Japanese script through Apple's on-device model. No round trip to a cloud service, no API key, deterministic output.

$ translate --from ja --to en --no-install --quiet --format json < input.txt
Translation 1 record
ja · Japanese
すべての人間は、生まれながらにして自由であり、かつ、尊厳と権利とについて平等である。人間は、理性と良心とを授けられており、互いに同胞の精神をもって行動しなければならない。
en · English
All human beings are born free and equal in dignity and rights. Humans are endowed with reason and conscience, and must act with each other in the spirit of compatriots.
detection confidence 100.0%
{} Raw JSON on-device output
[
  {
    "from": "ja",
    "to": "en",
    "src": "すべての人間は、生まれながらにして自由であり、かつ、尊厳と権利とについて平等である。人間は、理性と良心とを授けられており、互いに同胞の精神をもって行動しなければならない。\n",
    "dst": "All human beings are born free and equal in dignity and rights. Humans are endowed with reason and conscience, and must act with each other in the spirit of compatriots.\n",
    "conf": 1
  }
]
Source
يولد جميع الناس أحرارا متساوين في الكرامة والحقوق. وقد وهبوا عقلا وضميرا وعليهم أن يعامل بعضهم بعضا بروح الإخاء.
treaty 1948 Public Domain (UN OHCHR)

Universal Declaration of Human Rights - Article 1 (Arabic)

Right-to-left Arabic script. Apple's Translation framework handles bidi cleanly; translate just gets out of the way.

$ translate --from ar --to en --no-install --quiet --format json < input.txt
Translation 1 record
ar · Arabic
يولد جميع الناس أحرارا متساوين في الكرامة والحقوق. وقد وهبوا عقلا وضميرا وعليهم أن يعامل بعضهم بعضا بروح الإخاء.
en · English
All people are born free and equal in dignity and rights. They are endowed with reason and conscience and must treat each other in a spirit of brotherhood.
detection confidence 100.0%
{} Raw JSON on-device output
[
  {
    "from": "ar",
    "to": "en",
    "src": "يولد جميع الناس أحرارا متساوين في الكرامة والحقوق. وقد وهبوا عقلا وضميرا وعليهم أن يعامل بعضهم بعضا بروح الإخاء.\n",
    "dst": "All people are born free and equal in dignity and rights. They are endowed with reason and conscience and must treat each other in a spirit of brotherhood.\n",
    "conf": 1
  }
]
Source
Sah ein Knab' ein Röslein stehn, Röslein auf der Heiden, War so jung und morgenschön, Lief er schnell, es nah zu sehn, Sah's mit vielen Freuden. Röslein, Röslein, Röslein rot, Röslein auf der Heiden.
poetry 1799 Public Domain

Goethe - Heidenröslein (1799)

Goethe's most famous Volkslied. Short lines, dense rhyme. translate keeps line breaks because preserve-newlines is on by default - paragraph cadence survives.

$ translate --from de --to en --no-install --quiet --format json < input.txt
Translation 1 record
de · German
Sah ein Knab' ein Röslein stehn, Röslein auf der Heiden, War so jung und morgenschön, Lief er schnell, es nah zu sehn, Sah's mit vielen Freuden. Röslein, Röslein, Röslein rot, Röslein auf der Heiden.
en · English
Saw a boy stand a rose, Little horse on the heathen, Was so young and beautiful tomorrow, He ran fast to see it up close, Saw it with many joys. Röslein, Röslein, Röslein red, Little horse on the heathen.
detection confidence 100.0%
{} Raw JSON on-device output
[
  {
    "from": "de",
    "to": "en",
    "src": "Sah ein Knab' ein Röslein stehn,\nRöslein auf der Heiden,\nWar so jung und morgenschön,\nLief er schnell, es nah zu sehn,\nSah's mit vielen Freuden.\nRöslein, Röslein, Röslein rot,\nRöslein auf der Heiden.\n",
    "dst": "Saw a boy stand a rose,\nLittle horse on the heathen,\nWas so young and beautiful tomorrow,\nHe ran fast to see it up close,\nSaw it with many joys.\nRöslein, Röslein, Röslein red,\nLittle horse on the heathen.\n",
    "conf": 1
  }
]
Source
En un lugar de la Mancha, de cuyo nombre no quiero acordarme, no ha mucho tiempo que vivía un hidalgo de los de lanza en astillero, adarga antigua, rocín flaco y galgo corredor.
literature 1605 Public Domain

Cervantes - Don Quijote (opening, 1605)

The first sentence of Don Quixote. 17th-century Castilian Spanish, archaic syntax, three nested clauses. A robust test of long-form translation.

$ translate --from es --to en --no-install --quiet --format json < input.txt
Translation 1 record
es · Spanish
En un lugar de la Mancha, de cuyo nombre no quiero acordarme, no ha mucho tiempo que vivía un hidalgo de los de lanza en astillero, adarga antigua, rocín flaco y galgo corredor.
en · English
In a place in La Mancha, whose name I don't want to remember, not long ago there lived a hidalgo of those with a spear in a shipyard, old adarga, skinny rocín and greyhound runner.
detection confidence 100.0%
{} Raw JSON on-device output
[
  {
    "from": "es",
    "to": "en",
    "src": "En un lugar de la Mancha, de cuyo nombre no quiero acordarme, no ha mucho tiempo que vivía un hidalgo de los de lanza en astillero, adarga antigua, rocín flaco y galgo corredor.\n",
    "dst": "In a place in La Mancha, whose name I don't want to remember, not long ago there lived a hidalgo of those with a spear in a shipyard, old adarga, skinny rocín and greyhound runner.\n",
    "conf": 1
  }
]
Source
Все счастливые семьи похожи друг на друга, каждая несчастливая семья несчастлива по-своему.
literature 1877 Public Domain

Tolstoy - Anna Karenina (opening, 1877)

The most quoted opening line in Russian literature. Cyrillic script, idiomatic comparison structure.

$ translate --from ru --to en --no-install --quiet --format json < input.txt
Translation 1 record
ru · Russian
Все счастливые семьи похожи друг на друга, каждая несчастливая семья несчастлива по-своему.
en · English
All happy families are similar to each other, each unhappy family is unhappy in its own way.
detection confidence 100.0%
{} Raw JSON on-device output
[
  {
    "from": "ru",
    "to": "en",
    "src": "Все счастливые семьи похожи друг на друга, каждая несчастливая семья несчастлива по-своему.\n",
    "dst": "All happy families are similar to each other, each unhappy family is unhappy in its own way.\n",
    "conf": 1
  }
]
Source
Hallo Welt. Bitte besuche https://example.com oder schreibe an arti.ficial@fullstackoptimization.com. Der Befehl ist `translate --to en`. ```sh translate --to en --format ndjson < input.txt ``` Alles dazwischen wird übersetzt.
format 2026 CC0 (composed for this site)

Markdown with code, URLs, and emails

Hand-crafted German prose with three protected-span types: a fenced code block, an inline backtick span, and email/URL tokens. translate masks all four and emits them byte-identical in the translated output.

$ translate --from de --to en --no-install --quiet --format json < input.txt
Translation 4 records
de · German
Hallo Welt. Bitte besuche https://example.com oder schreibe an arti.ficial@fullstackoptimization.com.
en · English
Hello world. Please visithttps://example.comOr write toarti.ficial@fullstackoptimization.com.
de · German
Der Befehl ist `translate --to en`.
en · English
The command is`translate --to en`.
de · German
```sh translate --to en --format ndjson < input.txt ```
en · English
```sh translate --to en --format ndjson < input.txt ```
de · German
Alles dazwischen wird übersetzt.
en · English
Everything in between is translated.
detection confidence 100.0%
{} Raw JSON on-device output
[
  {
    "from": "de",
    "to": "en",
    "src": "Hallo Welt. Bitte besuche https://example.com oder schreibe an arti.ficial@fullstackoptimization.com.",
    "dst": "Hello world. Please visithttps://example.comOr write toarti.ficial@fullstackoptimization.com.",
    "conf": 1
  },
  {
    "from": "de",
    "to": "en",
    "src": "Der Befehl ist `translate --to en`.",
    "dst": "The command is`translate --to en`.",
    "conf": 1
  },
  {
    "from": "de",
    "to": "en",
    "src": "```sh\ntranslate --to en --format ndjson < input.txt\n```",
    "dst": "```sh\ntranslate --to en --format ndjson < input.txt\n```",
    "conf": 1
  },
  {
    "from": "de",
    "to": "en",
    "src": "Alles dazwischen wird übersetzt.\n",
    "dst": "Everything in between is translated.\n",
    "conf": 1
  }
]
Source
Guten Morgen. Buenos días. Bonjour. おはようございます。 Доброе утро.
batch 2026 CC0 (composed for this site)

Polyglot greetings - batch mode

Five short greetings, one per line. translate --batch treats each line as an independent translation unit, runs them through one batched session call, and emits one JSON record per input.

$ translate --batch --to en --no-install --quiet --format ndjson < input.txt
Translation 5 records
es · Spanish
Guten Morgen.
en · English
Good morning.
es · Spanish
Buenos días.
en · English
Good morning.
es · Spanish
Bonjour.
en · English
Bonjour.
es · Spanish
おはようございます。
en · English
おはようございます。
es · Spanish
Доброе утро.
en · English
Доброе утро.
detection confidence 70.2%
{} Raw JSON on-device output
[
  {
    "from": "es",
    "to": "en",
    "src": "Guten Morgen.",
    "dst": "Good morning.",
    "conf": 0.702423
  },
  {
    "from": "es",
    "to": "en",
    "src": "Buenos días.",
    "dst": "Good morning.",
    "conf": 0.702423
  },
  {
    "from": "es",
    "to": "en",
    "src": "Bonjour.",
    "dst": "Bonjour.",
    "conf": 0.702423
  },
  {
    "from": "es",
    "to": "en",
    "src": "おはようございます。",
    "dst": "おはようございます。",
    "conf": 0.702423
  },
  {
    "from": "es",
    "to": "en",
    "src": "Доброе утро.",
    "dst": "Доброе утро.",
    "conf": 0.702423
  }
]
Source
Detta är en kort svensk mening med tillräckligt många ord för säker språkdetektering.
detect 2026 CC0 (composed for this site)

Detect - Swedish

translate --detect-only prints the BCP-47 language code and confidence (0..1) without translating. Same NaturalLanguage engine that Mail and Notes use.

$ translate --detect-only --quiet < input.txt
? Language detection no translation
sv Swedish
confidence 100.0%
{} Raw JSON on-device output
{
  "detect": {
    "language": "sv",
    "confidence": 0.999976
  }
}
Source
Questa è una frase italiana abbastanza lunga per essere riconosciuta con sicurezza dal rilevatore.
detect 2026 CC0 (composed for this site)

Detect - Italian

Romance family member. NaturalLanguage distinguishes Italian from Spanish and French even on short inputs.

$ translate --detect-only --quiet < input.txt
? Language detection no translation
it Italian
confidence 100.0%
{} Raw JSON on-device output
{
  "detect": {
    "language": "it",
    "confidence": 0.999998
  }
}
Source
Esta é uma frase em português com palavras suficientes para identificar o idioma com alta confiança.
detect 2026 CC0 (composed for this site)

Detect - Portuguese

Brazilian Portuguese, the most populous Lusophone variant. Detection returns the base language code; downstream code can pair it with a region tag.

$ translate --detect-only --quiet < input.txt
? Language detection no translation
pt Portuguese
confidence 100.0%
{} Raw JSON on-device output
{
  "detect": {
    "language": "pt",
    "confidence": 0.999948
  }
}
Source
Dit is een Nederlandse zin met voldoende woorden om de taal te herkennen.
detect 2026 CC0 (composed for this site)

Detect - Dutch

Germanic language, lexically close to German and English. The detector relies on character n-gram patterns, not single tokens.

$ translate --detect-only --quiet < input.txt
? Language detection no translation
nl Dutch
confidence 100.0%
{} Raw JSON on-device output
{
  "detect": {
    "language": "nl",
    "confidence": 1
  }
}
Source
Dette er en norsk setning med nok ord til at språkgjenkjennelse fungerer pålitelig.
detect 2026 CC0 (composed for this site)

Detect - Norwegian Bokmål

Norwegian and Danish are mutually intelligible in writing. The detector usually picks the right one, but occasionally tags Bokmål as Danish.

$ translate --detect-only --quiet < input.txt
? Language detection no translation
nb Norwegian
confidence 100.0%
{} Raw JSON on-device output
{
  "detect": {
    "language": "nb",
    "confidence": 0.999997
  }
}
Source
To jest zdanie po polsku z wystarczającą liczbą słów do niezawodnego rozpoznania języka.
detect 2026 CC0 (composed for this site)

Detect - Polish

Western Slavic, Latin script with diacritics. Easy to distinguish from Czech because of łŻźć patterns.

$ translate --detect-only --quiet < input.txt
? Language detection no translation
pl Polish
confidence 100.0%
{} Raw JSON on-device output
{
  "detect": {
    "language": "pl",
    "confidence": 0.999986
  }
}
Source
Це українське речення з достатньою кількістю слів для впевненого розпізнавання мови.
detect 2026 CC0 (composed for this site)

Detect - Ukrainian

Cyrillic script, distinguished from Russian by ї, є, і. NaturalLanguage's training data covers it explicitly.

$ translate --detect-only --quiet < input.txt
? Language detection no translation
uk Ukrainian
confidence 100.0%
{} Raw JSON on-device output
{
  "detect": {
    "language": "uk",
    "confidence": 1
  }
}
Source
이것은 한국어 문장이며 언어 인식 테스트를 위해 충분히 깁니다.
detect 2026 CC0 (composed for this site)

Detect - Korean

Hangul syllabary. Visually unambiguous; detection is almost always 100% confidence.

$ translate --detect-only --quiet < input.txt
? Language detection no translation
ko Korean
confidence 100.0%
{} Raw JSON on-device output
{
  "detect": {
    "language": "ko",
    "confidence": 1
  }
}
Source
Đây là một câu tiếng Việt với đủ số lượng từ để nhận dạng ngôn ngữ một cách đáng tin cậy.
detect 2026 CC0 (composed for this site)

Detect - Vietnamese

Latin script with extensive diacritics for tone marks. The combination is unique enough that detection is reliable on a single sentence.

$ translate --detect-only --quiet < input.txt
? Language detection no translation
vi Vietnamese
confidence 100.0%
{} Raw JSON on-device output
{
  "detect": {
    "language": "vi",
    "confidence": 1
  }
}
Source
นี่คือประโยคภาษาไทยที่มีคำเพียงพอสำหรับการตรวจจับภาษาอย่างน่าเชื่อถือ
detect 2026 CC0 (composed for this site)

Detect - Thai

Thai script, no inter-word spaces, abugida structure. The detector handles unsegmented text natively.

$ translate --detect-only --quiet < input.txt
? Language detection no translation
th Thai
confidence 100.0%
{} Raw JSON on-device output
{
  "detect": {
    "language": "th",
    "confidence": 1
  }
}
Source
यह एक हिंदी वाक्य है जिसमें भाषा की पहचान विश्वसनीय रूप से करने के लिए पर्याप्त शब्द हैं।
detect 2026 CC0 (composed for this site)

Detect - Hindi (Devanagari)

Devanagari script. Shared with Sanskrit, Marathi, and others, but the detector picks Hindi from word-frequency cues.

$ translate --detect-only --quiet < input.txt
? Language detection no translation
hi Hindi
confidence 100.0%
{} Raw JSON on-device output
{
  "detect": {
    "language": "hi",
    "confidence": 1
  }
}
Source
Αυτή είναι μια ελληνική πρόταση με αρκετές λέξεις για αξιόπιστη αναγνώριση γλώσσας.
detect 2026 CC0 (composed for this site)

Detect - Greek

Greek script. Visually distinct, single-language script - detection is typically 99%+ confidence.

$ translate --detect-only --quiet < input.txt
? Language detection no translation
el Greek
confidence 100.0%
{} Raw JSON on-device output
{
  "detect": {
    "language": "el",
    "confidence": 1
  }
}
Source
Tämä on suomalainen lause, jossa on riittävästi sanoja luotettavaan kielentunnistukseen.
detect 2026 CC0 (composed for this site)

Detect - Finnish

Uralic, agglutinating. Long words and high vowel density make Finnish unmistakable to character n-gram models.

$ translate --detect-only --quiet < input.txt
? Language detection no translation
fi Finnish
confidence 100.0%
{} Raw JSON on-device output
{
  "detect": {
    "language": "fi",
    "confidence": 1
  }
}
Source
Ez egy magyar mondat elegendő szóval a megbízható nyelvfelismeréshez.
detect 2026 CC0 (composed for this site)

Detect - Hungarian

Uralic again, but distinct from Finnish. The double consonants and ő/ű give it away.

$ translate --detect-only --quiet < input.txt
? Language detection no translation
hu Hungarian
confidence 100.0%
{} Raw JSON on-device output
{
  "detect": {
    "language": "hu",
    "confidence": 0.999998
  }
}
Source
Toto je česká věta s dostatečným počtem slov pro spolehlivou identifikaci jazyka.
detect 2026 CC0 (composed for this site)

Detect - Czech

Western Slavic with the famous háčky (š, č, ř, ž, ě). The ř is unique to Czech globally.

$ translate --detect-only --quiet < input.txt
? Language detection no translation
cs Czech
confidence 100.0%
{} Raw JSON on-device output
{
  "detect": {
    "language": "cs",
    "confidence": 0.999966
  }
}
Source
Dieser Abschnitt ist hauptsächlich auf Deutsch geschrieben, enthält aber den englischen Satz "the rain in Spain stays mainly in the plain" als Zitat. Anschließend folgt wieder eine längere deutsche Erklärung, damit die Sprachstatistik klar überwiegt.
detect 2026 CC0 (composed for this site)

Mixed - German with English fragments

A German paragraph that quotes English. NaturalLanguage uses the dominant character n-grams across the whole prefix and picks the majority language. Confidence drops below 1.0 -- the lower the number, the more mixed the input.

$ translate --detect-only --quiet < input.txt
? Language detection no translation
de German
confidence 100.0%
{} Raw JSON on-device output
{
  "detect": {
    "language": "de",
    "confidence": 0.999979
  }
}
Source
Voici un paragraphe principalement en français qui présente quelques mots en anglais comme "hello world" et un peu d'espagnol comme "buenos días, amigos". Ensuite la prose française reprend pour s'assurer que cette langue reste majoritaire dans le texte.
detect 2026 CC0 (composed for this site)

Mixed - French majority with English and Spanish

Three Romance/Germanic languages in one paragraph. The detector sees them all but picks the dominant by character distribution. Lower confidence reflects the noise.

$ translate --detect-only --quiet --langs fr,en,es < input.txt
? Language detection no translation
fr French
confidence 100.0%
{} Raw JSON on-device output
{
  "detect": {
    "language": "fr",
    "confidence": 0.999996
  }
}
Source
Hello world this is enough for detection
detect 2026 CC0 (composed for this site)

Detection hints - constrain ambiguous short input

Short ambiguous strings produce low confidence (or get rejected with a usage error). Pass --langs to constrain detection to the languages your domain actually expects -- the model picks the best candidate from that set.

$ translate --detect-only --quiet --langs de,en,fr,es,it < input.txt
? Language detection no translation
en English
confidence 99.8%
{} Raw JSON on-device output
{
  "detect": {
    "language": "en",
    "confidence": 0.998134
  }
}
Source
Install

Get translate.

Two install paths. Pick one. Both run the same binary.

Homebrew (recommended)
brew tap Arthur-Ficial/tap
brew install Arthur-Ficial/tap/translate
Build from source
git clone https://github.com/Arthur-Ficial/translate
cd translate && make install

No Xcode required. Builds with Command Line Tools. Requires macOS 26 Tahoe with Apple Silicon. Translation models install through System Settings · General · Language & Region · Translation Languages.

The apfel family

Apple's on-device intelligence, exposed as UNIX tools.

Each tool wraps one Apple framework. Together they are the apfel ecosystem - what apfel does for text generation, the others do for vision, speech, embeddings, and translation.