Plugin

Translate

Translate messages with Google Translate, DeepL or Kagi.

Chat Utility
index.tsx
Download

Source

src/plugins/translate/index.tsx
1import "./styles.css";
2
3import { findGroupChildrenByChildId, NavContextMenuPatchCallback } from "@api/ContextMenu";
4import { Devs } from "@utils/constants";
5import definePlugin from "@utils/types";
6import { Message } from "@vencord/discord-types";
7import { ChannelStore, Menu } from "@webpack/common";
8
9import { settings } from "./settings";
10import { setShouldShowTranslateEnabledTooltip, TranslateChatBarIcon, TranslateIcon } from "./TranslateIcon";
11import { handleTranslate, TranslationAccessory } from "./TranslationAccessory";
12import { translate } from "./utils";
13
14const messageCtxPatch: NavContextMenuPatchCallback = (children, { message }: { message: Message; }) => {
15 const content = getMessageContent(message);
16 if (!content) return;
17
18 const group = findGroupChildrenByChildId("copy-text", children);
19 if (!group) return;
20
21 group.splice(group.findIndex(c => c?.props?.id === "copy-text") + 1, 0, (
22 <Menu.MenuItem
23 id="vc-trans"
24 label="Translate"
25 icon={TranslateIcon}
26 action={async () => {
27 const trans = await translate("received", content);
28 handleTranslate(message.id, trans);
29 }}
30 />
31 ));
32};
33
34
35function getMessageContent(message: Message) {
36 // Message snapshots is an array, which allows for nested snapshots, which Discord does not do yet.
37 // no point collecting content or rewriting this to render in a certain way that makes sense
38 // for something currently impossible.
39 return message.content
40 || message.messageSnapshots?.[0]?.message.content
41 || message.embeds?.find(embed => embed.type === "auto_moderation_message")?.rawDescription || "";
42}
43
44let tooltipTimeout: any;
45
46export default definePlugin({
47 name: "Translate",
48 description: "Translate messages with Google Translate, DeepL or Kagi.",
49 tags: ["Chat", "Utility"],
50 authors: [Devs.Ven, Devs.AshtonMemer, Devs.koish1],
51 settings,
52 contextMenus: {
53 "message": messageCtxPatch
54 },
55 // not used, just here in case some other plugin wants it or w/e
56 translate,
57
58 renderMessageAccessory: props => <TranslationAccessory message={props.message} />,
59
60 chatBarButton: {
61 icon: TranslateIcon,
62 render: TranslateChatBarIcon
63 },
64
65 messagePopoverButton: {
66 icon: TranslateIcon,
67 render(message: Message) {
68 const content = getMessageContent(message);
69 if (!content) return null;
70
71 return {
72 label: "Translate",
73 icon: TranslateIcon,
74 message,
75 channel: ChannelStore.getChannel(message.channel_id),
76 onClick: async () => {
77 const trans = await translate("received", content);
78 handleTranslate(message.id, trans);
79 }
80 };
81 }
82 },
83
84 async onBeforeMessageSend(_, message) {
85 if (!settings.store.autoTranslate) return;
86 if (!message.content) return;
87
88 setShouldShowTranslateEnabledTooltip?.(true);
89 clearTimeout(tooltipTimeout);
90 tooltipTimeout = setTimeout(() => setShouldShowTranslateEnabledTooltip?.(false), 2000);
91
92 const trans = await translate("sent", message.content);
93 message.content = trans.text;
94 }
95});
96