Enabling Translations in your Mastodon Node with LibreTranslate

The translate button showing up in the Mastodon UI

Out-of-the-box, Mastodon supports post translation using an external service. But to take advantage of it, you have to set up the services and bind your Mastodon instance to them.

It turns out this is a relatively simple process with only a few sharp edges. I’ve documented my walk to a working configuration here. This process was supported by the Mastodon documentation and this delightful tutorial for setting up LibreTranslate in Docker.

Set up storage and Docker configs for LibreTranslate

For our translation service, we’ll use LibreTranslate, which can be locally installed as a web service. To start, we’ll go ahead and create some new storage and configure it. We’ll run this all as a user with Docker permissions

sudo mkdir /media/squire/libretranslate
sudo chown $USER:$USER /media/squire/libretranslate
cd /media/squire/libretranslate
mkdir admin
mkdir docker
mkdir data/{keys,local}

With that all set up, we’ll build out our Docker compose rule and an environment file to prep up the LibreTranslate project.

docker/docker-compose.yml

version: "3"

services:
  libretranslate:
    container_name: libretranslate
    image: libretranslate/libretranslate:v1.3.11
    restart: unless-stopped
    dns:
      - 1.1.1.1
      - 8.8.8.8
    ports:
      - "5000:5000"
    healthcheck:
      test: ['CMD-SHELL', './venv/bin/python scripts/healthcheck.py']
    env_file:
      - libretranslate.env
    volumes:
     - libretranslate_api_keys:/app/db
     - libretranslate_local:/home/libretranslate/.local

volumes:
  libretranslate_api_keys:
    driver_opts:
      type: none
      device: /media/squire/libretranslate/data/keys
      o: bind
  libretranslate_local:
    driver_opts:
      type: none
      device: /media/squire/libretranslate/data/local
      o: bind

Worth noting here is the volume bindings from our local directories to the Docker volumes. You’ll want to adjust those to the correct directory names on your setup.

Our libretranslate.env file configures our instance. The meaning of these keys is documented in LibreTranslate’s GitHub project

LT_DEBUG=true
#LT_UPDATE_MODELS=true
#LT_SSL=true
LT_SUGGESTIONS=false
LT_METRICS=true

#LT_API_KEYS=YES

LT_THREADS=12
LT_FRONTEND_TIMEOUT=2000

#LT_REQ_LIMIT=400
#LT_CHAR_LIMIT=1200
LT_API_KEYS_DB_PATH=/app/db/api_keys.db

Worth noting here:

  • I’ve disabled LT_SSL because I’m only accepting local connections. For similar reason, I’m not using LT_API_KEYS and commented that out as well. If you do use API keys, I found it necesary to touch keys/api_keys.db to prime the file and then to chmod the file to the corect user (which is 1203:1203 for reasons I’m not entirely sure of).
  • I’ve also disabled LT_UPDATE_MODELS. When the Docker image comes up, the first thing the server tries to do is update its models, which takes an awful long time (my server knows about 60 models). While it’s doing that, the server will reject all API queries. If you get connection reset by peer errors while trying to connect, that may be what it’s attempting to do. I’ll come back later and enable this, but for testing purposes I left it off and will let my models go stale.

With these pieces configured, we can fire up the server. From the docker directory:

docker compose up

Once the Docker image has loaded, we’ll want to use utility scripts in the image to pull the initial dataset. Connect to the Docker instance with

docker exec -it libretranslate bash

… and then run the initial download script for the translation data.

for i in `/app/venv/bin/argospm list`;do /app/venv/bin/argospm install $i;done

This will take awhile (about 10 minutes in my case); take a break.

Once that’s done, you should be able to see the core argos-translatepackages that LibreTranslate uses as its language model. Exit your Docker shell and do

ls -1 /media/squire/libretranslate/data/local/share/argos-translate/packages

You should see several that look like

ar_en
de_en
en_ar
en_de
en_es
en_fi
translate-az_en-1_5
translate-ca_en-1_7
translate-cs_en-1_5
translate-da_en-1_3
translate-el_en-1_5

… etc.

At this point, if you want to configure an API key you can, but I skipped that step.

You should be able now to test the server:

curl -XPOST -H "Content-type: application/json" -d '{
"q": "Bolha.io is the most cool project in the fediverso",
"source": "en",
"target": "pt"
}' 'http://localhost:5000/translate'

You should get a response like {"translatedText":"Bolha.io é o projeto mais legal no fediverso"} . If you do, congrats! LibreTranslate is live on your machine!

Bind your Mastodon node to your LibreTranslate instance

With the server up and running, binding to it is extremely straightforward. In your Mastodon installation, find the .env.production file and configure

# translation config
DEFAULT_LOCALE=en
ALLOWED_PRIVATE_ADDRESSES=127.0.0.1
LIBRE_TRANSLATE_ENDPOINT=http://127.0.0.1:5000

Now reboot mastodon (sudo systemctl restart mastodon-web). When it comes back up, posts in languages other than your configured native language should offer you a translation option! Click Translate under the post to do the thing.

A successful translation

Register translate as a service

Just one more step: Let’s go ahead and set up LibreTranslate as a systemd service it comes up automatically on boot. Add the file /media/squire/libretranslate/admin/libretranslate.service:

# Copy this file to /etc/systemd/system/libretranslate.service
[Unit]
Description=LibreTranslate
After=network.target

[Service]
# Set User and WorkingDirectory to the correct values
User=your-libretranslate-user
WorkingDirectory=/media/squire/libretranslate/docker
Type=oneshot
RemainAfterExit=true
ExecStart=docker compose up -d --remove-orphans
ExecStop=docker compose down

[Install]
WantedBy=multi-user.target

All set! As the first comment says, copy it to /etc/systemd/system/libretranslate.service, chown it to root:root, and systemctl start libretranslate. Make sure to set the correct values for WorkingDirectory and User for your installation, of course.

Comments