● onlineping: build: 3a91763
6 posts published_
TranslateEra

TranslateEra

PublicMINECRAFT PLUGIN

TranslateEra

Automatic chat translation for Minecraft (Paper 1.21+). When a player sends a chat message, every other player receives it translated into their own language — based on their Minecraft client language, or a language they pick manually.

  • 🌍 Automatic — uses each player's Minecraft locale, no setup needed per player
  • 🎛️ Per-player control — anyone can turn translation off, or switch language without changing their Minecraft language
  • Optimized — fully asynchronous, cached, and de-duplicated; the main server thread is never blocked
  • 🔌 Pluggable engines — self-hosted LibreTranslate, Google Gemini, or Groq
  • 💾 SQLite storage — per-player settings stored in an embedded database, scales to large player counts

Requirements

  • Java 21+
  • Minecraft 1.21+, any server in the Bukkit/Spigot family
  • A translation engine (see below). The easiest free options are Groq (API key) or self-hosted LibreTranslate (Docker/Python).

Minecraft versions

One jar covers 1.21.0 → 26.2 (the latest release) — no per-version builds. This works because TranslateEra deliberately avoids NMS/version-specific code and uses only stable API. It is compiled against the 1.21.0 API floor (so every method exists on 1.21.0 and every later release) and has been verified to compile cleanly against the whole range, including the 1.21 → 26 major-version transition: 1.21.1, 1.21.4, 1.21.8, 1.21.11, 26.1 and 26.2. Newer releases are expected to keep working as long as this stable API remains.

Minecraft moved to a calendar-based versioning scheme in 2026 (after 1.21.11 came 26.1, 26.2, ...). The plugin keeps api-version: '1.21' so it loads on the widest range — from 1.21.0 up through the newest 26.x servers.

Supported servers

One jar runs on the whole plugin family — it uses only cross-compatible API (AsyncPlayerChatEvent, the BungeeCord Chat API, getLocale()):

Server Supported
Bukkit / CraftBukkit
Spigot
Paper
Purpur
Folia ✅ (regionized-thread safe; folia-supported: true)

Modded platforms (Forge, NeoForge, Fabric/Quilt) are not supported directly — they run mods, not Bukkit plugins. To use TranslateEra there, run a hybrid server such as Mohist/Arclight (Forge/NeoForge) or Banner/Cardboard (Fabric/Quilt), which load Bukkit plugins on a modded server.

Installation

  1. Download TranslateEra-<version>.jar (or build it, see Building).
  2. Drop it into your server's plugins/ folder.
  3. Start the server once to generate plugins/TranslateEra/config.yml.
  4. Pick and configure a translation engine (below), then run /lang reload or restart.

On the console you should see: Translation provider: <name>.


Choosing a translation engine

Set the provider field in config.yml to libretranslate, gemini, or groq.

Provider Quality Speed Cost Notes
Groq Good Very fast Free tier Generous limits, great for chat volume
Gemini High Fast Free tier ~15 requests/min on the free tier
LibreTranslate Medium Fast (local) Free Self-hosted, unlimited, fully offline-capable

If the selected provider's API key is empty, the plugin safely falls back to LibreTranslate.

Option A — Groq (recommended, easiest)

  1. Go to https://console.groq.com/keys and sign in.
  2. Click Create API Key and copy it (starts with gsk_).
  3. In config.yml:
    provider: groq
    groq:
      api-key: "gsk_your_key_here"
      model: "llama-3.1-8b-instant"
  4. Run /lang reload.

Option B — Google Gemini

  1. Go to https://aistudio.google.com/app/apikey and sign in.
  2. Click Create API key and copy it (starts with AIza).
  3. In config.yml:
    provider: gemini
    gemini:
      api-key: "AIza_your_key_here"
      model: "gemini-2.0-flash"
  4. Run /lang reload.

Option C — Self-hosted LibreTranslate

Run your own translation server. Two ways:

With Docker (recommended)

docker run -d --name libretranslate -p 5000:5000 \
  -v lt-models:/home/libretranslate/.local \
  libretranslate/libretranslate --load-only en,tr,de,es,fr,ru,ar
  • --load-only en,tr,... — only these languages are downloaded (faster startup, less RAM). Add whatever languages your players use.
  • -v lt-models:... — persists the downloaded models so they aren't re-downloaded.
  • First startup downloads the models and can take a few minutes.

Make it start automatically with Docker:

docker update --restart unless-stopped libretranslate

Verify it works:

curl http://localhost:5000/languages
curl -s -X POST http://localhost:5000/translate \
  -H "Content-Type: application/json" \
  -d '{"q":"Hello world","source":"en","target":"tr"}'

Note: the container needs internet access on first run to download models. If you see Temporary failure in name resolution or an IndexError about languages, the container couldn't reach the internet — check Docker's DNS and restart.

With Python (pip)

pip install libretranslate
libretranslate --load-only en,tr,de --host 0.0.0.0 --port 5000

Point the plugin at it

provider: libretranslate
libretranslate:
  url: "http://localhost:5000"   # change if LibreTranslate runs on another host
  api-key: ""                     # only if your instance requires one

Then run /lang reload.


Commands

Command Description Permission
/lang on Enable translation for yourself translateera.use (default)
/lang off Disable translation; see original messages translateera.use
/lang set <code> Pick a language manually (e.g. tr, en, de) translateera.use
/lang reset Go back to your Minecraft client language translateera.use
/lang status Show your current settings translateera.use
/lang list List supported languages translateera.use
/lang reload Reload the configuration translateera.admin (op)

Aliases: /translate, /dil.

Hover over a translated message to see the original text.


Configuration reference

provider: libretranslate        # libretranslate | gemini | groq

libretranslate:
  url: "http://localhost:5000"
  api-key: ""

gemini:
  api-key: ""
  model: "gemini-2.0-flash"

groq:
  api-key: ""
  model: "llama-3.1-8b-instant"

# If the primary provider fails, these are tried in order (empty-key ones are skipped).
fallback:
  order: [groq, gemini, libretranslate]

# Chat line format. Other chat plugins' formatting no longer applies (we re-send the
# message), so reproduce yours here. Supports {player}, {message}, and %PlaceholderAPI%.
format:
  chat: "{player}: {message}"
  translated-tag: ""            # optional tag before translated messages, e.g. "&7[T] "

# Content that should not be translated; masked before translation and restored after.
protect:
  urls: true
  coordinates: true
  mentions: true               # @name mentions

translation:
  enabled-by-default: true      # is translation ON for new players?
  cache:
    max-size: 50000             # max cached translations
    expire-after-write-minutes: 360
  max-message-length: 256       # longer messages are delivered untranslated
  cooldown-ms: 0                # per-player anti-spam; 0 disables

metrics: true                   # anonymous bStats stats; false to opt out
  • Custom messages: all plugin text lives in plugins/TranslateEra/messages.yml — edit it to reword or localize (supports & colour codes).
  • PlaceholderAPI: install it to use %...% placeholders (e.g. %luckperms_prefix%) in format.chat.
  • Hover: hovering a translated message shows the original text.

How it works (performance)

  • Cross-platform delivery: messages can't be rewritten per-recipient, so the AsyncPlayerChatEvent is cancelled and each recipient is sent the translation individually via the BungeeCord Chat API — available on every Bukkit-family server.
  • Off the main thread: the chat event already runs async, and the HTTP calls use the JDK's async HttpClient on a dedicated worker pool — the main thread never blocks.
  • De-duplication: recipients are grouped by target language, so each language is translated once and delivered to everyone who needs it.
  • Caching: a Caffeine cache keyed by (text, language) means repeated phrases cost nothing; concurrent requests for the same pair are coalesced into one provider call.
  • Skip when unnecessary: recipients who share the sender's language, or who turned translation off, receive the original with no translation call.
  • Storage: per-player settings live in an embedded SQLite database (plugins/TranslateEra/players.db) with single-row upserts — no full-file rewrites.

Building from source

Requires JDK 21 and Maven.

mvn clean package

The shaded plugin jar is produced at target/TranslateEra-<version>.jar.


License

MIT LICENSE

← all projectsGitHub ↗
ESC
↑↓ navigate openesc close