Skip to content

feat(plugins): group auto-translation extension plugin#300

Merged
rmyndharis merged 7 commits into
rmyndharis:mainfrom
dallascyclist:feat/whatsapp-translation-plugin
Jun 18, 2026
Merged

feat(plugins): group auto-translation extension plugin#300
rmyndharis merged 7 commits into
rmyndharis:mainfrom
dallascyclist:feat/whatsapp-translation-plugin

Conversation

@dallascyclist

Copy link
Copy Markdown
Contributor

Summary

Ports the WhatsApp group auto-translation feature (originally proposed as a core module in #278) to a first-party EXTENSION plugin, built on the Tier-2 capability layer from #294. The translation logic was already isolated behind ports, so the framework-agnostic core lifts in unchanged; the OpenWA wiring is now ctx.messages / ctx.engine / ctx.storage. Registered disabled by default — enable via POST /plugins/translation/enable.

Supersedes #278. Thanks for landing #294 so quickly — ctx.messages/ctx.engine are exactly what this needed.

How it maps to the Tier-2 layer

  • ChatGatewayctx.messages.sendText/reply (sends routed through MessageService, persistence preserved) + ctx.engine.getGroupInfo (admin resolution).
  • ConfigStorectx.storage (one GroupState JSON per group).
  • Config → ctx.config (manifest configSchema; defaults to http://localhost:7001).
  • Hook → ctx.registerHook('message:received', …) in onEnable.
  • The core (coordinator, command parser, reply formatter, ports) is reused unchanged.

What's included

  • src/plugins/extensions/translation/ — the plugin: core/ (reused), libretranslate.client.ts (timeout + circuit breaker), plugin-chat.gateway.ts, plugin-config.store.ts, index.ts, manifest.json.
  • Registered (disabled) in ExtensionsRegistrar, mirroring auto-reply.
  • One small engine passthrough: mentionedIds on IncomingMessage (whatsapp-web.js already attaches it). It enables @mention command targeting — the reliable cross-user identity under LID, since mentions and message authors share the @lid namespace.

Behavior

Per-message source detection (LibreTranslate) with learn-by-observation of each participant's language; one combined quote-reply per message into the other participants' languages; never translates a message into its own language (resilient to detector misfires on colloquial text). In-group /tr commands (on/off, setlang, auto, ignore/unignore, grant/revoke, status, help) — every command replies. Permissions: group admins (LID-aware via the group owner) plus admin-delegated members. The bot's own sends are fromMe and route through message:sent, so there is no translation loop.

Configuration

libretranslateUrl (default http://localhost:7001), libretranslateApiKey?, timeoutMs, commandPrefix (/tr), minLength, maxLength, denyReply — see manifest.json configSchema; set per-instance via the plugins config API.

Testing

  • 543 unit tests pass (the lifted core suite + the new ctx-backed gateway/store shims + the mentionedIds mapper cases); lint + format clean; build clean.
  • The shared core was validated end-to-end against live WhatsApp + a self-hosted LibreTranslate in feat: WhatsApp group auto-translation (LibreTranslate) #278, which shook out four real bugs — all fixed and carried into this core.

Known limitations / follow-ups

  • Cross-user targeting under LID works via @mention; non-owner admin auto-detection on a differing scheme could build on the new senderPhone / RESOLVE_LID_TO_PHONE ([Feature]: How we can get phone number from @lid #263) — a follow-up.
  • onGroupJoin for announce-on-add (currently announces on first activity); per-plugin send throttle; media/caption translation; dashboard config UI — all follow-ups.
  • LibreTranslate add the ability to use a remote LibreTranlate via configurable API key / URL

One-field passthrough (whatsapp-web.js already attaches mentionedIds) so command handlers can target a user by @mention — the reliable cross-user identity under WhatsApp's LID scheme, since mentions and message authors share the @lid namespace. Additive and optional.
Ports the translation feature onto the Tier-2 capability layer (rmyndharis#294): the framework-agnostic core/ (coordinator, command parser, reply formatter, ports) is reused unchanged, with ChatGateway/ConfigStore implemented over ctx.messages / ctx.engine / ctx.storage and per-group state in plugin KV storage. Registered disabled by default; enable via POST /plugins/translation/enable. Supersedes the core-module approach in rmyndharis#278 now that the plugin send-capability exists.
… live

- Add the configSchema to the translation plugin's registered manifest so GET /plugins exposes it and the dashboard config form (rmyndharis#303) can render the LibreTranslate URL + API key (and other) fields. The schema was previously only in manifest.json, which built-in registration does not read.
- Implement onConfigChange to rebuild the coordinator from the updated config, so a URL/key change saved from the dashboard takes effect immediately without a disable/enable cycle. Extracted buildCoordinator() shared by onEnable/onConfigChange.
@rmyndharis rmyndharis merged commit 8c0c755 into rmyndharis:main Jun 18, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants