- Python 100%
|
|
||
|---|---|---|
| chat_translate | ||
| docs | ||
| tests | ||
| .gitignore | ||
| .pre-commit-config.yaml | ||
| AGENTS.md | ||
| config.example.yaml | ||
| LICENSE | ||
| pyproject.toml | ||
| pytest.ini | ||
| README.md | ||
| requirements.txt | ||
| setup.cfg | ||
chat-translate
A Python bot that provides real-time message translation across multiple chat platforms.
Features
- Multi-backend: supports Matrix, Signal (via signal-cli REST API), and XMPP.
- Configurable target language per room or per user.
- Language resolution order: user override → room default → skip.
- Replies in-thread to the original message with the translated text.
- Propagates edits and redactions/deletions of translated messages.
- Auto-detects source language.
- Pluggable translation engines: Google Translate (default) or LibreTranslate.
- Matrix: supports end-to-end encrypted (E2EE) rooms when
libolmandpython-olmare available. - Signal: connects via WebSocket, auto-joins groups, supports message edits and remote deletes.
- XMPP: MUC (group chat) support with OMEMO encryption (Blind Trust Before Verification), message edits (XEP-0308), and retractions (XEP-0424).
Quick Start
1. Install dependencies
# Matrix only
pip install "chat-translate[matrix]"
# Signal only
pip install "chat-translate[signal]"
# XMPP only
pip install "chat-translate[xmpp]"
# All backends
pip install "chat-translate[all]"
# LibreTranslate backend (instead of default Google Translate)
pip install "chat-translate[libretranslate]"
# Or install from source with all deps
pip install -r requirements.txt
For Matrix E2EE support (encrypted rooms), you also need libolm installed on
your system (e.g. pacman -S libolm python-olm on Arch, apt install libolm-dev on Debian/Ubuntu).
For Signal, you need a running signal-cli-rest-api instance with a registered phone number.
For XMPP, you need a Jabber account for the bot. OMEMO encryption is enabled by default and uses Blind Trust Before Verification (BTBV).
2. Configure
Copy the example configuration and edit it:
cp config.example.yaml config.yaml
3. Run
python -m chat_translate -c config.yaml
Use -v for verbose/debug logging.
Configuration Reference
At least one backend (matrix, signal, or xmpp) must be configured.
Multiple can be active simultaneously — they run independently.
Translation Backend
The translation section is optional. If omitted, Google Translate is used.
translation:
backend: google # "google" or "libretranslate"
# LibreTranslate-specific:
# api_url: "http://localhost:5000"
# api_key: "your-api-key"
| Field | Required | Default | Description |
|---|---|---|---|
translation.backend |
No | google |
Translation engine: google or libretranslate |
translation.api_url |
No | http://localhost:5000 |
LibreTranslate API URL (only for libretranslate backend) |
translation.api_key |
No | — | API key for authenticated LibreTranslate instances |
Chat Backends
matrix:
homeserver: https://matrix.example.com
user_id: "@translate-bot:example.com"
password: "s3cret"
rooms:
"!roomid1:example.com":
language: en
users:
"@alice:example.com":
language: it
signal:
phone_number: "+1234567890"
api_url: "http://localhost:8080"
rooms:
"base64groupid==":
language: en
users:
"+0987654321":
language: de
xmpp:
jid: "translate-bot@example.com"
password: "s3cret"
rooms:
"room@conference.example.com":
language: en
users:
"room@conference.example.com/alice":
language: de
Matrix Fields
| Field | Required | Description |
|---|---|---|
matrix.homeserver |
Yes | Matrix homeserver URL |
matrix.user_id |
Yes | Bot's Matrix user ID |
matrix.device_id |
No** | Device ID (required when using access_token) |
matrix.password |
No* | Bot account password |
matrix.access_token |
No* | Pre-existing access token |
matrix.store_path |
No | Directory to persist encryption keys (default: store) |
matrix.import_keys_file |
No | Path to E2E room keys file exported from Element |
matrix.import_keys_passphrase |
No | Passphrase for the exported keys file |
matrix.recovery_key |
No | Matrix recovery key — used to cross-sign the bot's device so Element shows it as verified |
matrix.rooms.<room_id>.language |
No | Default target language for the room |
matrix.rooms.<room_id>.users.<user_id>.language |
No | Target language override for a specific user |
* Either password or access_token must be provided.
Signal Fields
| Field | Required | Description |
|---|---|---|
signal.phone_number |
Yes | Bot's registered Signal phone number |
signal.api_url |
No | signal-cli REST API base URL (default: http://localhost:8080) |
signal.rooms.<group_id>.language |
No | Default target language for the group |
signal.rooms.<group_id>.users.<phone>.language |
No | Target language override for a specific user |
XMPP Fields
| Field | Required | Description |
|---|---|---|
xmpp.jid |
Yes | Bot's Jabber ID (e.g. bot@example.com) |
xmpp.password |
Yes | Bot account password |
xmpp.nick |
No | Nickname in MUC rooms (default: translate-bot) |
xmpp.omemo_enabled |
No | Enable OMEMO encryption (default: true) |
xmpp.omemo_storage_path |
No | Path to store OMEMO key material (default: omemo_store) |
xmpp.rooms.<room_jid>.language |
No | Default target language for the room |
xmpp.rooms.<room_jid>.users.<nick_jid>.language |
No | Target language override for a specific user |
Users are identified by their full MUC JID: room@conference.example.com/nickname.
XMPP Setup
The XMPP backend connects to any standard XMPP server via slixmpp. OMEMO encryption is provided by slixmpp-omemo.
1. Create a bot account
Register an account on your XMPP server for the bot (e.g. via
prosodyctl adduser bot@example.com on Prosody, or the server's web interface).
2. Invite the bot to MUC rooms
Invite the bot's JID to your MUC room. The bot will auto-join configured rooms on startup.
3. OMEMO
OMEMO is enabled by default with Blind Trust Before Verification (BTBV) — all
devices are automatically trusted on first encounter (similar to Matrix's TOFU
approach). Key material is persisted under omemo_storage_path.
To disable OMEMO (e.g. for unencrypted rooms):
xmpp:
omemo_enabled: false
Signal Setup
The Signal backend requires a running signal-cli-rest-api instance.
1. Start the signal-cli REST API container
docker run -d --name signal-api \
-p 8080:8080 \
-v ./signal-data:/home/.local/share/signal-cli \
bbernhard/signal-cli-rest-api
The volume (./signal-data) persists credentials across container restarts.
2. Register or link a phone number
You have two options:
Option A: Link to an existing account (recommended)
This makes signal-cli act as a secondary device (like Signal Desktop), keeping your phone as the primary device:
# Get a QR code for linking
curl -X GET 'http://localhost:8080/v1/qrcodelink?device_name=chat-translate-bot' \
--output qr.png
# Open qr.png and scan it from your Signal app:
# Settings → Linked Devices → Link New Device
After linking, the bot receives messages from all your groups alongside your
phone. Use the rooms filter in your config to limit which groups get
translated.
Option B: Register a dedicated number
This takes over the phone number entirely — your existing Signal app on that number will be deregistered. Use this with a dedicated VoIP/prepaid number:
# Request verification via SMS
curl -X POST 'http://localhost:8080/v1/register/+1234567890'
If the first API call returns this error:
{
"error": "Captcha required for verification, use --captcha CAPTCHA\nTo get the token, go to https://signalcaptchas.org/registration/generate.html\nAfter solving the captcha, right-click on the \"Open Signal\" link and copy the link.\n"
}
Then you will have to verify yourself through a CAPTCHA. Open https://signalcaptchas.org/registration/generate.html, solve the CAPTCHA, and copy the link from the page (the "Open Signal" link).
Then use the copied CAPTCHA string to verify:
curl -X POST 'http://localhost:8080/v1/register/+1234567890' \
--header 'Content-Type: application/json' \
-d '{"captcha": "signalcaptcha://signal-hcaptcha......"}'
You should then receive a code via SMS. Use that code to verify:
# Verify with the code you receive
curl -X POST 'http://localhost:8080/v1/register/+1234567890/verify/123456'
3. Join groups
The bot auto-joins configured groups on startup if possible, but Signal groups require an invitation first. Have a group member invite the bot's phone number, then start the bot — it will accept and begin translating.
To find the group ID for your config, list your groups:
curl 'http://localhost:8080/v1/groups/+1234567890'
The id field in each group object is the value to use in signal.rooms.
4. Configure the bot
signal:
phone_number: "+1234567890"
api_url: "http://localhost:8080"
rooms:
"base64groupid==":
language: en
users:
"+0987654321":
language: de
Device Verification
XMPP (OMEMO)
The XMPP backend uses Blind Trust Before Verification (BTBV). All OMEMO devices are automatically trusted on first contact. No manual verification step is required.
Matrix
The bot automatically trusts all devices it encounters (TOFU). To verify the bot's device from another Matrix client, send the following command in any room the bot is in:
!verify
The bot will initiate SAS (emoji) verification via to_device messages with all known devices of the sender. Your client should show a verification popup — accept it to mark the bot as verified.
Note: Element's built-in "Verify User" button uses in-room verification, which is not supported by the underlying
matrix-niolibrary. The!verifycommand works around this by using the to_device verification protocol.
Cross-signing (green badge in Element)
Element marks a device as verified only when it carries a cross-signing
signature from the account's self-signing key. Since matrix-nio doesn't
natively support cross-signing, the bot implements it manually.
To enable it, set your recovery key (the one you saved when setting up Security & Privacy in Element) in the configuration:
matrix:
recovery_key: "EsTc LW2K PGiF ..."
On startup the bot will:
- Decrypt the self-signing private key from SSSS (server-side secret storage).
- Sign its own device keys with that key.
- Upload the signature to the homeserver.
After a restart (or a /keys/query refresh in Element) the bot's device will
show the green "Verified" badge.
Development
# Install all dependencies (core + backends + dev)
python -m venv .venv
source .venv/bin/activate
pip install -r requirements.txt
# Run tests
pytest
# Run linters
pre-commit run --all-files
License
MIT