diplomail (Stage D): language detection + lazy translation cache
Tests · Go / test (push) Successful in 1m59s
Tests · Go / test (pull_request) Successful in 2m0s
Tests · Integration / integration (pull_request) Successful in 1m35s

Replaces the LangUndetermined placeholder with whatlanggo-backed
body detection on every send path, then adds a translation cache
keyed on (message_id, target_lang) populated lazily on the
per-message read endpoint. The noop translator that ships with
Stage D returns engine="noop", which the service treats as
"translation unavailable" — wiring a real backend (LibreTranslate
HTTP client is the documented next step) is a one-file swap.

GetMessage and ListInbox now accept a targetLang argument; the HTTP
layer resolves the caller's accounts.preferred_language and
forwards it. Inbox uses the cache only (never calls the
translator) so bulk reads stay fast under future SaaS backends.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
Ilia Denisov
2026-05-15 19:16:12 +02:00
parent 362f92e520
commit e22f4b7800
16 changed files with 599 additions and 24 deletions
+2 -2
View File
@@ -157,7 +157,7 @@ func (s *Service) SendPlayerBroadcast(ctx context.Context, in SendPlayerBroadcas
SenderIP: in.SenderIP,
Subject: subject,
Body: body,
BodyLang: LangUndetermined,
BodyLang: s.deps.Detector.Detect(body),
BroadcastScope: BroadcastScopeGameBroadcast,
}
rcptInserts := make([]RecipientInsert, 0, len(members))
@@ -429,7 +429,7 @@ func (s *Service) buildAdminMessageInsert(callerKind string, callerUserID *uuid.
SenderIP: senderIP,
Subject: subject,
Body: body,
BodyLang: LangUndetermined,
BodyLang: s.deps.Detector.Detect(body),
BroadcastScope: scope,
}
switch callerKind {