Plugin

Translate

Translate messages with Google Translate, DeepL or Kagi.

Chat Utility
index.tsx
Download

Source

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