Translation on Firefox Translations models; new logo

- Email translation moves from LibreTranslate to our own translator
  service (translator/): Mozilla's Firefox Translations models on the
  Bergamot engine, fastText language detection (176 languages). Polish,
  English, German, French, Spanish and Italian on first start (~350 MB
  instead of ~10 GB); Admin panel > Email translation installs and
  removes languages. Built and pushed as the `translator` image.
- Every message is translated paragraph by paragraph as plain text;
  names travel with their sentence and are kept only where the model
  changed them; a sentence start the model copied ("Enclosed") is tried
  again in lower case; list markers are not sent
- The Translate button shows only for installed languages
- New logo: favicon, app/maskable/iPhone icons, notification badge,
  email logo and calendar copy regenerated; BIMI logo rebuilt in SVG
  Tiny PS with its gradients; masks render in browsers
- Launch screen background is the app's dark grey

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-10-18 22:04:04 +02:00
co-authored by Claude Opus 5.5
parent 8a1b9979e9
commit 972e10876b
38 changed files with 1627 additions and 223 deletions
+17 -21
View File
@@ -72,7 +72,7 @@ x-backend-env: &backend-env
# Spelling and grammar check in the compose window. Empty turns it off.
LANGUAGETOOL_URL: ${LANGUAGETOOL_URL-http://languagetool:8010}
# Email translation; empty turns it off.
LIBRETRANSLATE_URL: ${LIBRETRANSLATE_URL-http://libretranslate:5000}
TRANSLATOR_URL: ${TRANSLATOR_URL-http://translator:5000}
LOG_LEVEL: ${LOG_LEVEL:-INFO}
UNDO_SECONDS: ${UNDO_SECONDS:-10}
SESSION_TTL_DAYS: ${SESSION_TTL_DAYS:-30}
@@ -111,13 +111,13 @@ services:
- |
set -e
mkdir -p /mnt/postgres /mnt/blobs /mnt/backups /mnt/redis /mnt/meili /mnt/state \
/mnt/languagetool-ngrams /mnt/libretranslate
/mnt/languagetool-ngrams /mnt/translator
# Only recurse when ownership is actually wrong: `chown -R` over a large
# blob store on every start would be minutes of pointless disk churn.
[ "$$(stat -c %u /mnt/blobs)" = "10001" ] || chown -R 10001:10001 /mnt/blobs
[ "$$(stat -c %u /mnt/backups)" = "999" ] || chown -R 999:999 /mnt/backups
[ "$$(stat -c %u /mnt/redis)" = "999" ] || chown -R 999:999 /mnt/redis
[ "$$(stat -c %u /mnt/libretranslate)" = "1032" ] || chown -R 1032:65534 /mnt/libretranslate
[ "$$(stat -c %u /mnt/translator)" = "10001" ] || chown -R 10001:10001 /mnt/translator
chmod 700 /mnt/backups
echo "[init] data directories ready"
volumes:
@@ -316,30 +316,26 @@ services:
cpus: ${LANGUAGETOOL_CPUS:-1.0}
logging: *logging
# Email translation (app/translation.py), all on this server. The first
# start downloads every language model (a few GB) into DATA_ROOT; later
# starts reuse them. A model is loaded into memory the first time its
# language is used.
libretranslate:
image: libretranslate/libretranslate:v1.9.6
# Email translation (translator/, app/translation.py), all on this server:
# Mozilla's Firefox Translations models and fastText language detection.
# The first start downloads the default languages (about 350 MB) into
# DATA_ROOT; more are installed from the admin panel.
translator:
image: ${REGISTRY_PREFIX:-webmail}/translator:${IMAGE_TAG:-local}
build:
context: .
dockerfile: docker/Dockerfile.translator
environment:
LT_DISABLE_WEB_UI: "true"
LT_UPDATE_MODELS: "false"
LT_THREADS: ${LIBRETRANSLATE_THREADS:-2}
TRANSLATOR_LANGUAGES: ${TRANSLATOR_LANGUAGES:-pl,de,fr,es,it}
TRANSLATOR_THREADS: ${TRANSLATOR_THREADS:-2}
TZ: ${TZ:-UTC}
volumes:
- ${DATA_ROOT:-/NO-.env-FOUND-RUN-deploy_webmail.sh-init-FIRST}/libretranslate:/home/libretranslate/.local
healthcheck:
test: ["CMD-SHELL", "python3 -c \"import urllib.request; urllib.request.urlopen('http://127.0.0.1:5000/languages', timeout=4)\""]
interval: 30s
timeout: 6s
retries: 5
start_period: 30m # the first start downloads the models
- ${DATA_ROOT:-/NO-.env-FOUND-RUN-deploy_webmail.sh-init-FIRST}/translator:/data
depends_on:
init: { condition: service_completed_successfully }
restart: unless-stopped
mem_limit: ${LIBRETRANSLATE_MEM_LIMIT:-6g}
cpus: ${LIBRETRANSLATE_CPUS:-2.0}
mem_limit: ${TRANSLATOR_MEM_LIMIT:-2g}
cpus: ${TRANSLATOR_CPUS:-2.0}
logging: *logging
# Bayes tokens and fuzzy hashes. Separate from the app's redis on purpose