Skip to content

tool — tools / text sources / select-to-translate ​

Does not attach to the ASR→MT→TTS pipeline; it provides capability through global hotkeys + action_*: select-to-translate, word capture, text injection, external data sources, and so on. Multiple instances allowed.

⚠️ Tools must use the real type: "tool" — do not hang action_* off middleware: that makes both the Hub category and the hotkey semantics wrong.


Declaration ​

json
{
  "id": "example.select_translate",
  "version": "1.0.0",
  "target_app_version": "0.2",
  "type": "tool",
  "entrypoint": "select_translate.py:SelectTranslatePlugin",
  "hotkeys": [
    { "action": "translate_selection", "default": "Alt+T", "name": "划词翻译" }
  ],
  "config_schema": [
    { "key": "capture_mode", "label": "捕获方式", "type": "select",
      "choices": ["auto", "clipboard"], "default": "auto" },
    { "key": "speak_translation", "label": "划词后朗读译文", "type": "boolean", "default": false }
  ]
}

hotkeys[].action maps to the action_<action> method in your implementation.

Enabled plugins with type=tool are preloaded during the scan phase (they must register their hotkeys), so initialize() runs at startup — don't do heavy work in it.


Minimal skeleton ​

python
from transbox.plugins.base import BasePlugin


class HelloTool(BasePlugin):
    def initialize(self, config=None) -> None:
        super().initialize(config)
        self.host.register_plugin_hotkey(self.id, "run", "Alt+T", name="我的工具")

    def action_run(self, **kwargs) -> dict:
        ok = self.host.feed_direct_caption("hello", "auto", tts=False, drop_noise=False)
        return {"ok": ok}

    def handle_host_event(self, event_name: str, payload: dict) -> None:
        if event_name == "pipeline.state":
            self.host.log("info", f"pipeline: {payload.get('running')}")

    def shutdown(self) -> None:
        self.host.unregister_plugin_hotkeys(self.id)
        super().shutdown()
  • hotkeys registers declaratively (the host calls RegisterHotKey on the Qt main thread); you can also register at runtime with host.register_plugin_hotkey(...), see Global hotkeys.
  • Action dispatch: handle_action(action, params) → action_<action>(**params); on the QML side call it with bridge.invokePluginAction / invokePluginActionAsync.
  • The returned dict is handed back to the caller as-is.

Feeding text into the captions ​

Two paths (see Captions & translation):

UseWhen
host.feed_direct_caption(text, lang, tts=…, drop_noise=…)Source text only; let the host run the full chain (SI running = full chain; not running = lightweight MT + captions + history)
host.feed_caption(text, translation, lang, source=…)You already have the translation (select-to-translate, caption-bridge frame patches) and don't want MT to run again

For tools, drop_noise must be False (never swallow short words).


Typical scenarios ​

ScenarioKey point
Select-to-translateRead the clipboard/selection → host.translate() or feed_direct_caption → optionally host.speak()
External data sourceA background thread polls/subscribes → feed_direct_caption
Text-injection HUDhost.create_plugin_window(...) opens a click-through + capture-safe floating window (Plugin windows)
Batch processinghost.begin_progress() + is_progress_cancelled() (File pickers & long tasks)

Reference implementation ​

extensions/community_select_translate/ (select-to-translate; the canonical type=tool example).


TransBox — empowering borderless cross-language communication for everyone