From acf7abe77ad920ca50c76ec7e34fd6cd9df0bae7 Mon Sep 17 00:00:00 2001 From: M <91066601+mishl-dev@users.noreply.github.com> Date: Sun, 15 Feb 2026 20:39:58 +0600 Subject: [PATCH] =?UTF-8?q?feat(i18n):=20Add=20translation=20keys=20and=20?= =?UTF-8?q?implement=20localization=20for=2080+=20p=E2=80=A6=20(#772)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * feat(i18n): Add translation keys and implement localization for 80+ plugins - Add comprehensive translation keys to i18n/en-US/vencord.json - Update all plugins to use t() function from @utils/translation - Replace hardcoded strings with translation function calls - Support plural forms with _one/_other suffixes - Use Translate component for strings with embedded JSX Plugins translated include: - Core: reviewDB, translate, voiceMessages, messageLogger - UI: showHiddenChannels, customRPC, clientTheme, permissionsViewer - Utility: betterSessions, betterSettings, memberCount, betterFolders - Social: relationshipNotifier, messageLatency, whoReacted - Media: imageZoom, viewIcons, viewRaw, decor, fakeNitro - And 60+ more plugins All changes pass TypeScript compilation. * Update i18n/en-US/vencord.json Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com> * Update i18n/en-US/vencord.json Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com> * Update i18n/en-US/vencord.json Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com> * Update i18n/en-US/vencord.json Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com> * Update i18n/en-US/vencord.json Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com> * Update i18n/en-US/vencord.json Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com> * feat(i18n): Add equicord.json for equicordplugins localization - Create i18n/en-US/equicord.json with messageLoggerEnhanced translation keys - Create empty equicord.json files for all other locales (Crowdin will handle translations) - Build system automatically picks up all JSON files in i18n/{locale}/ * Update i18n/en-US/vencord.json Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com> * feat(i18n): Add translations to 200 equicordplugins - Translate all user-facing strings in equicordplugins to use t() function - Add translation keys to i18n/en-US/equicord.json - Plugin names remain static strings for build system compatibility - Settings descriptions, tooltips, context menus, and UI strings now translatable * FileUpload: add sharex file support (#771) * FileUpload: add sharex file support Quick note, the settings seem to split pacal case with spaces for some reason, so `ShareX` renders as `Share X`. This is stupid and im upset and I dont think theres anything I can do about it * FileUpload: use Headers object to construct HTTP headers * Update vencord.json --------- Co-authored-by: Mishal <91066601+mishalhossin@users.noreply.github.com> Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com> Co-authored-by: Key Co-authored-by: thororen1234 <78185467+thororen1234@users.noreply.github.com> --- i18n/af-ZA/equicord.json | 1 + i18n/ar-SA/equicord.json | 1 + i18n/ca-ES/equicord.json | 1 + i18n/cs-CZ/equicord.json | 1 + i18n/da-DK/equicord.json | 1 + i18n/de-DE/equicord.json | 1 + i18n/el-GR/equicord.json | 1 + i18n/en-US/equicord.json | 1330 +++++++++++++++++ i18n/en-US/vencord.json | 1186 +++++++++++++++ i18n/es-ES/equicord.json | 1 + i18n/fi-FI/equicord.json | 1 + i18n/fr-FR/equicord.json | 1 + i18n/he-IL/equicord.json | 1 + i18n/hu-HU/equicord.json | 1 + i18n/it-IT/equicord.json | 1 + i18n/ja-JP/equicord.json | 1 + i18n/ko-KR/equicord.json | 1 + i18n/nl-NL/equicord.json | 1 + i18n/no-NO/equicord.json | 1 + i18n/pl-PL/equicord.json | 1 + i18n/pt-PT/equicord.json | 1 + i18n/ro-RO/equicord.json | 1 + i18n/ru-RU/equicord.json | 1 + i18n/sr-SP/equicord.json | 1 + i18n/sv-SE/equicord.json | 1 + i18n/tr-TR/equicord.json | 1 + i18n/uk-UA/equicord.json | 1 + i18n/vi-VN/equicord.json | 1 + i18n/zh-CN/equicord.json | 1 + src/components/settings/AddonCard.tsx | 2 +- src/components/settings/OnlineThemeCard.tsx | 2 +- .../tabs/plugins/components/Common.tsx | 5 +- src/equicordplugins/absRPC/index.tsx | 17 +- src/equicordplugins/altKrispSwitch/index.tsx | 3 +- .../alwaysExpandProfiles/index.ts | 3 +- src/equicordplugins/anammox/index.ts | 15 +- src/equicordplugins/animalese/index.ts | 23 +- src/equicordplugins/atSomeone/index.ts | 8 +- src/equicordplugins/autoZipper/index.ts | 5 +- .../bannersEverywhere/index.tsx | 7 +- src/equicordplugins/baseDecoder/index.tsx | 21 +- .../betterActivities/index.tsx | 3 +- .../betterActivities/settings.tsx | 21 +- .../betterAudioPlayer/index.tsx | 19 +- .../betterBanReasons/index.tsx | 13 +- .../betterBlockedUsers/index.tsx | 5 +- src/equicordplugins/betterCommands/index.ts | 17 +- src/equicordplugins/betterInvites/index.tsx | 9 +- src/equicordplugins/betterPlusReacts/index.ts | 3 +- src/equicordplugins/betterUserArea/index.ts | 15 +- src/equicordplugins/blockKeywords/index.ts | 11 +- src/equicordplugins/blockKrisp/index.ts | 3 +- src/equicordplugins/bypassPinPrompt/index.ts | 3 +- src/equicordplugins/bypassStatus/index.tsx | 33 +- src/equicordplugins/channelBadges/index.tsx | 9 +- .../channelBadges/settings.tsx | 93 +- src/equicordplugins/channelTabs/index.tsx | 5 +- .../characterCounter/index.tsx | 5 +- src/equicordplugins/cleanChannelName/index.ts | 3 +- .../cleanerChannelGroups/index.ts | 3 +- src/equicordplugins/clientSideBlock/index.tsx | 25 +- .../index.tsx | 21 +- src/equicordplugins/commandPalette/index.tsx | 25 +- src/equicordplugins/components.dev/index.tsx | 3 +- src/equicordplugins/contentWarning/index.tsx | 9 +- .../copyProfileColors/index.tsx | 11 +- src/equicordplugins/copyStatusUrls/index.ts | 7 +- src/equicordplugins/copyUserMention/index.tsx | 5 +- src/equicordplugins/cursorBuddy/index.tsx | 31 +- .../customFolderIcons/index.tsx | 3 +- src/equicordplugins/customSounds/index.tsx | 25 +- .../customTimestamps/index.tsx | 18 +- .../customUserColors/index.tsx | 11 +- src/equicordplugins/disableCameras/index.tsx | 3 +- .../discordDevBanner/index.tsx | 3 +- .../dragFavoriteEmotes/index.tsx | 23 +- src/equicordplugins/dragify/index.tsx | 63 +- .../elementHighlighter.dev/index.tsx | 27 +- src/equicordplugins/equicordHelper/index.tsx | 41 +- src/equicordplugins/equicordToolbox/index.tsx | 7 +- src/equicordplugins/equicordToolbox/menu.tsx | 17 +- src/equicordplugins/equissant/index.ts | 5 +- src/equicordplugins/exitSounds/index.tsx | 15 +- src/equicordplugins/exportMessages/index.tsx | 26 +- .../fastDeleteChannels/index.tsx | 11 +- .../favouriteAnything/index.tsx | 3 +- src/equicordplugins/fileUpload/index.tsx | 7 +- src/equicordplugins/findReply/index.tsx | 17 +- .../fixFileExtensions/index.tsx | 3 +- src/equicordplugins/followVoiceUser/index.tsx | 11 +- src/equicordplugins/fontLoader/index.tsx | 13 +- src/equicordplugins/forwardAnywhere/index.ts | 9 +- .../frequentQuickSwitcher/index.tsx | 3 +- src/equicordplugins/friendCloud/index.ts | 15 +- src/equicordplugins/friendTags/index.tsx | 17 +- src/equicordplugins/friendshipRanks/index.tsx | 31 +- src/equicordplugins/fullVcPfp/index.tsx | 3 +- .../gensokyoRadioRPC/index.tsx | 7 +- src/equicordplugins/ghosted/index.tsx | 19 +- src/equicordplugins/gifCollections/index.tsx | 91 +- src/equicordplugins/gifRoulette/index.tsx | 7 +- src/equicordplugins/githubRepos/index.tsx | 13 +- src/equicordplugins/globalBadges/index.tsx | 7 +- src/equicordplugins/googleThat/index.tsx | 15 +- .../guildPickerDumper/index.tsx | 10 +- src/equicordplugins/guildTagSettings/index.ts | 7 +- src/equicordplugins/hideChatButtons/index.tsx | 9 +- src/equicordplugins/hideServers/index.tsx | 7 +- src/equicordplugins/holyNotes/index.tsx | 11 +- src/equicordplugins/homeTyping/index.tsx | 3 +- src/equicordplugins/hopOn/index.tsx | 7 +- src/equicordplugins/husk/index.tsx | 11 +- src/equicordplugins/iRememberYou/index.tsx | 5 +- src/equicordplugins/iconViewer/index.tsx | 7 +- src/equicordplugins/idleAutoRestart/index.tsx | 9 +- src/equicordplugins/ignoreCalls/index.tsx | 11 +- src/equicordplugins/imgToGif/index.tsx | 17 +- src/equicordplugins/inRole/index.tsx | 25 +- src/equicordplugins/ingtoninator/index.tsx | 9 +- .../instantScreenshare/index.tsx | 21 +- .../invisibleChat.desktop/index.tsx | 11 +- src/equicordplugins/inviteDefaults/index.ts | 13 +- .../jellyfinRichPresence/index.tsx | 89 +- src/equicordplugins/jumpTo/index.tsx | 19 +- src/equicordplugins/jumpscare/index.tsx | 9 +- .../keyboardNavigation/index.tsx | 11 +- src/equicordplugins/keyboardSounds/index.ts | 11 +- src/equicordplugins/keywordNotify/index.tsx | 27 +- src/equicordplugins/lastActive/index.tsx | 15 +- .../limitMiddleClickPaste/index.ts | 13 +- src/equicordplugins/listenBrainzRPC/index.tsx | 59 +- src/equicordplugins/loginWithQR/index.tsx | 7 +- .../mediaPlaybackSpeed/index.tsx | 9 +- src/equicordplugins/messageBurst/index.ts | 9 +- .../messageColors/constants.ts | 19 +- src/equicordplugins/messageColors/index.tsx | 3 +- .../messageFetchTimer/index.tsx | 9 +- src/equicordplugins/messageNotifier/index.ts | 5 +- src/equicordplugins/messagePeek/index.tsx | 3 +- .../messageTranslate/index.tsx | 7 +- .../micLoopbackTester/index.tsx | 3 +- src/equicordplugins/moreCommands/index.ts | 3 +- src/equicordplugins/moreKaomoji/index.ts | 3 +- src/equicordplugins/moreStickers/index.tsx | 7 +- src/equicordplugins/moreUserTags/index.tsx | 3 +- src/equicordplugins/moreUserTags/settings.tsx | 9 +- src/equicordplugins/moyai/index.ts | 17 +- src/equicordplugins/musicControls/index.tsx | 3 +- .../neverPausePreviews/index.tsx | 5 +- .../newPluginsManager/index.tsx | 3 +- src/equicordplugins/noAppsAllowed/index.ts | 3 +- src/equicordplugins/noBulletPoints/index.tsx | 3 +- src/equicordplugins/noModalAnimation/index.ts | 3 +- src/equicordplugins/noNitroUpsell/index.ts | 3 +- .../noRPC.discordDesktop/index.ts | 3 +- src/equicordplugins/noRoleHeaders/index.ts | 3 +- .../normalizeMessageLinks/index.ts | 3 +- .../index.tsx | 3 +- src/equicordplugins/orbolayBridge/index.tsx | 31 +- src/equicordplugins/partyMode/index.ts | 11 +- src/equicordplugins/pinIcon/index.tsx | 3 +- .../pingNotifications/index.tsx | 13 +- src/equicordplugins/platformSpoofer/index.tsx | 19 +- src/equicordplugins/polishWording/index.ts | 17 +- src/equicordplugins/profileSets/index.tsx | 5 +- .../profileSets/utils/actions.ts | 2 +- src/equicordplugins/questify/index.tsx | 3 +- .../questionMarkReplacement/index.tsx | 5 +- .../index.tsx | 19 +- src/equicordplugins/quoter/index.tsx | 13 +- src/equicordplugins/randomVoice/index.tsx | 3 +- .../recentDMSwitcher/index.tsx | 3 +- src/equicordplugins/remix/index.tsx | 3 +- src/equicordplugins/repeatMessages/index.tsx | 3 +- src/equicordplugins/replyPingControl/index.ts | 3 +- src/equicordplugins/richMagnetLinks/index.tsx | 3 +- src/equicordplugins/rpcEditor/index.tsx | 3 +- src/equicordplugins/rpcStats/index.tsx | 3 +- .../saveFavoriteGIFs/index.tsx | 3 +- .../scheduledMessages/index.tsx | 3 +- .../screenRecorder.equibop/index.tsx | 3 +- src/equicordplugins/searchFix/index.tsx | 3 +- src/equicordplugins/sekaiStickers/index.tsx | 3 +- src/equicordplugins/selfForward/index.ts | 3 +- src/equicordplugins/serverSearch/index.tsx | 3 +- .../showBadgesInChat/index.tsx | 3 +- .../showMessageEmbeds/index.tsx | 3 +- .../showResourceChannels/index.ts | 3 +- src/equicordplugins/showSongName/index.tsx | 3 +- src/equicordplugins/sidebarChat/index.tsx | 3 +- src/equicordplugins/signature/index.tsx | 3 +- src/equicordplugins/snowfall/index.tsx | 3 +- src/equicordplugins/soggy/index.tsx | 3 +- .../songLink.desktop/index.tsx | 3 +- .../soundBoardLogger/index.tsx | 3 +- .../splitLargeMessages/index.ts | 3 +- .../spotifyActivityToggle/index.tsx | 3 +- src/equicordplugins/statsfmPresence/index.tsx | 3 +- src/equicordplugins/statusPresets/index.tsx | 3 +- .../statusWhileActive.desktop/index.ts | 3 +- src/equicordplugins/steamStatusSync/index.tsx | 3 +- src/equicordplugins/stickerBlocker/index.tsx | 3 +- .../streamingCodecDisabler/index.ts | 3 +- src/equicordplugins/talkInReverse/index.tsx | 3 +- src/equicordplugins/themeLibrary/index.tsx | 3 +- src/equicordplugins/tidalEmbeds/index.tsx | 3 +- src/equicordplugins/tiktokTTS/index.ts | 3 +- src/equicordplugins/timezones/index.tsx | 3 +- src/equicordplugins/title/index.ts | 3 +- .../toastNotifications/index.tsx | 3 +- src/equicordplugins/toggleVideoBind/index.ts | 3 +- src/equicordplugins/toneIndicators/index.tsx | 3 +- src/equicordplugins/tosuRPC/index.ts | 3 +- src/equicordplugins/translatePlus/index.tsx | 3 +- src/equicordplugins/unitConverter/index.tsx | 3 +- .../universalMention/index.tsx | 3 +- .../unlimitedAccounts/index.ts | 3 +- .../unreadBadgeCount/index.tsx | 7 +- src/equicordplugins/urlHighlighter/index.tsx | 3 +- src/equicordplugins/userpfp/index.tsx | 3 +- .../vcNarratorCustom/index.tsx | 3 +- src/equicordplugins/vcPanelSettings/index.tsx | 3 +- src/equicordplugins/viewRawVariant/index.tsx | 3 +- src/equicordplugins/voiceButtons/index.tsx | 3 +- .../voiceChannelLog.dev/index.tsx | 3 +- src/equicordplugins/voiceChatUtils/index.tsx | 3 +- .../voiceJoinMessages/index.ts | 3 +- .../voiceMessageTranscriber.desktop/index.tsx | 3 +- src/equicordplugins/voiceRejoin/index.tsx | 3 +- src/equicordplugins/waitForSlot/index.tsx | 3 +- src/equicordplugins/wallpaperFree/index.tsx | 3 +- src/equicordplugins/webpackTarball/index.tsx | 3 +- src/equicordplugins/whosWatching/index.tsx | 3 +- src/equicordplugins/wigglyText/index.tsx | 3 +- src/equicordplugins/writeUpperCase/index.ts | 3 +- .../youtubeDescription/index.tsx | 3 +- .../accountPanelServerProfile/index.tsx | 9 +- src/plugins/anonymiseFileNames/index.tsx | 31 +- src/plugins/appleMusic.desktop/index.tsx | 67 +- src/plugins/arRPC.web/index.tsx | 15 +- src/plugins/betterFolders/index.tsx | 25 +- src/plugins/betterRoleContext/index.tsx | 11 +- .../components/RenameButton.tsx | 3 +- .../betterSessions/components/RenameModal.tsx | 8 +- src/plugins/betterSessions/index.tsx | 10 +- src/plugins/betterSettings/index.tsx | 7 +- src/plugins/biggerStreamPreview/index.tsx | 5 +- src/plugins/callTimer/index.tsx | 17 +- .../clientTheme/components/Settings.tsx | 17 +- src/plugins/consoleJanitor/index.tsx | 11 +- src/plugins/copyEmojiMarkdown/index.tsx | 9 +- src/plugins/copyFileContents/index.tsx | 5 +- src/plugins/copyStickerLinks/index.tsx | 9 +- src/plugins/copyUserURLs/index.tsx | 5 +- src/plugins/customRPC/RpcSettings.tsx | 91 +- src/plugins/customRPC/index.tsx | 22 +- src/plugins/dearrow/index.tsx | 17 +- src/plugins/decor/index.tsx | 3 +- src/plugins/decor/settings.tsx | 7 +- .../decor/ui/components/DecorSection.tsx | 7 +- src/plugins/experiments/index.tsx | 31 +- src/plugins/expressionCloner/index.tsx | 15 +- src/plugins/fakeNitro/index.tsx | 51 +- src/plugins/fakeProfileThemes/index.tsx | 24 +- src/plugins/favGifSearch/index.tsx | 13 +- src/plugins/fixImagesQuality/index.tsx | 17 +- src/plugins/friendsSince/index.tsx | 7 +- src/plugins/gameActivityToggle/index.tsx | 15 +- src/plugins/greetStickerPicker/index.tsx | 19 +- src/plugins/hideAttachments/index.tsx | 7 +- src/plugins/ignoreActivities/index.tsx | 33 +- src/plugins/imageZoom/index.tsx | 25 +- src/plugins/lastfmRichPresence/index.tsx | 61 +- src/plugins/memberCount/index.tsx | 7 +- src/plugins/messageLatency/index.tsx | 27 +- src/plugins/messageLinkEmbeds/index.tsx | 35 +- src/plugins/messageLogger/HistoryModal.tsx | 5 +- src/plugins/messageLogger/index.tsx | 45 +- src/plugins/mutualGroupDMs/index.tsx | 13 +- src/plugins/newGuildSettings/index.tsx | 31 +- src/plugins/noReplyMention/index.tsx | 17 +- src/plugins/overrideForumDefaults/index.tsx | 15 +- src/plugins/pauseInvitesForever/index.tsx | 5 +- .../components/RolesAndUsersPermissions.tsx | 15 +- src/plugins/permissionsViewer/index.tsx | 11 +- src/plugins/pictureInPicture/index.tsx | 7 +- .../pinDms/components/CreateCategoryModal.tsx | 11 +- src/plugins/pinDms/components/contextMenu.tsx | 11 +- src/plugins/pinDms/index.tsx | 19 +- src/plugins/platformIndicators/index.tsx | 29 +- src/plugins/previewMessage/index.tsx | 5 +- src/plugins/quickMention/index.tsx | 5 +- .../readAllNotificationsButton/index.tsx | 5 +- src/plugins/relationshipNotifier/functions.ts | 9 +- src/plugins/relationshipNotifier/settings.ts | 13 +- src/plugins/replaceGoogleSearch/index.tsx | 17 +- src/plugins/reverseImageSearch/index.tsx | 7 +- .../reviewDB/components/BlockedUserModal.tsx | 11 +- .../reviewDB/components/ReviewComponent.tsx | 41 +- src/plugins/reviewDB/index.tsx | 16 +- src/plugins/reviewDB/settings.tsx | 19 +- src/plugins/seeSummaries/index.tsx | 5 +- src/plugins/sendTimestamps/index.tsx | 22 +- src/plugins/serverListIndicators/index.tsx | 28 +- src/plugins/showConnections/index.tsx | 13 +- .../components/HiddenChannelLockScreen.tsx | 86 +- src/plugins/showMeYourName/index.tsx | 57 +- src/plugins/showTimeoutDuration/index.tsx | 11 +- src/plugins/silentMessageToggle/index.tsx | 15 +- src/plugins/silentTyping/index.tsx | 85 +- src/plugins/sortFriendRequests/index.tsx | 7 +- src/plugins/textReplace/index.tsx | 25 +- src/plugins/translate/TranslateIcon.tsx | 17 +- src/plugins/translate/TranslateModal.tsx | 9 +- src/plugins/translate/index.tsx | 5 +- src/plugins/typingIndicator/index.tsx | 19 +- src/plugins/typingTweaks/index.tsx | 13 +- src/plugins/unsuppressEmbeds/index.tsx | 5 +- src/plugins/userVoiceShow/components.tsx | 5 +- src/plugins/userVoiceShow/index.tsx | 9 +- src/plugins/usrbg/index.tsx | 13 +- src/plugins/vcNarrator/index.tsx | 25 +- src/plugins/vcNarrator/settings.ts | 37 +- src/plugins/viewIcons/index.tsx | 17 +- src/plugins/viewRaw/index.tsx | 31 +- src/plugins/voiceDownload/index.tsx | 5 +- src/plugins/voiceMessages/index.tsx | 31 +- src/plugins/whoReacted/index.tsx | 3 +- src/plugins/xsOverlay/index.tsx | 51 +- 329 files changed, 4639 insertions(+), 1783 deletions(-) create mode 100644 i18n/af-ZA/equicord.json create mode 100644 i18n/ar-SA/equicord.json create mode 100644 i18n/ca-ES/equicord.json create mode 100644 i18n/cs-CZ/equicord.json create mode 100644 i18n/da-DK/equicord.json create mode 100644 i18n/de-DE/equicord.json create mode 100644 i18n/el-GR/equicord.json create mode 100644 i18n/en-US/equicord.json create mode 100644 i18n/es-ES/equicord.json create mode 100644 i18n/fi-FI/equicord.json create mode 100644 i18n/fr-FR/equicord.json create mode 100644 i18n/he-IL/equicord.json create mode 100644 i18n/hu-HU/equicord.json create mode 100644 i18n/it-IT/equicord.json create mode 100644 i18n/ja-JP/equicord.json create mode 100644 i18n/ko-KR/equicord.json create mode 100644 i18n/nl-NL/equicord.json create mode 100644 i18n/no-NO/equicord.json create mode 100644 i18n/pl-PL/equicord.json create mode 100644 i18n/pt-PT/equicord.json create mode 100644 i18n/ro-RO/equicord.json create mode 100644 i18n/ru-RU/equicord.json create mode 100644 i18n/sr-SP/equicord.json create mode 100644 i18n/sv-SE/equicord.json create mode 100644 i18n/tr-TR/equicord.json create mode 100644 i18n/uk-UA/equicord.json create mode 100644 i18n/vi-VN/equicord.json create mode 100644 i18n/zh-CN/equicord.json diff --git a/i18n/af-ZA/equicord.json b/i18n/af-ZA/equicord.json new file mode 100644 index 000000000..0967ef424 --- /dev/null +++ b/i18n/af-ZA/equicord.json @@ -0,0 +1 @@ +{} diff --git a/i18n/ar-SA/equicord.json b/i18n/ar-SA/equicord.json new file mode 100644 index 000000000..0967ef424 --- /dev/null +++ b/i18n/ar-SA/equicord.json @@ -0,0 +1 @@ +{} diff --git a/i18n/ca-ES/equicord.json b/i18n/ca-ES/equicord.json new file mode 100644 index 000000000..0967ef424 --- /dev/null +++ b/i18n/ca-ES/equicord.json @@ -0,0 +1 @@ +{} diff --git a/i18n/cs-CZ/equicord.json b/i18n/cs-CZ/equicord.json new file mode 100644 index 000000000..0967ef424 --- /dev/null +++ b/i18n/cs-CZ/equicord.json @@ -0,0 +1 @@ +{} diff --git a/i18n/da-DK/equicord.json b/i18n/da-DK/equicord.json new file mode 100644 index 000000000..0967ef424 --- /dev/null +++ b/i18n/da-DK/equicord.json @@ -0,0 +1 @@ +{} diff --git a/i18n/de-DE/equicord.json b/i18n/de-DE/equicord.json new file mode 100644 index 000000000..0967ef424 --- /dev/null +++ b/i18n/de-DE/equicord.json @@ -0,0 +1 @@ +{} diff --git a/i18n/el-GR/equicord.json b/i18n/el-GR/equicord.json new file mode 100644 index 000000000..0967ef424 --- /dev/null +++ b/i18n/el-GR/equicord.json @@ -0,0 +1 @@ +{} diff --git a/i18n/en-US/equicord.json b/i18n/en-US/equicord.json new file mode 100644 index 000000000..8f22db55d --- /dev/null +++ b/i18n/en-US/equicord.json @@ -0,0 +1,1330 @@ +{ + "absRPC": { + "description": "Rich presence for AudioBookShelf media server", + "settings": { + "serverUrl": "AudioBookShelf server URL (e.g., https://abs.example.com)", + "username": "AudioBookShelf username", + "password": "AudioBookShelf password" + }, + "about": { + "title": "How to connect to AudioBookShelf", + "description": "Enter your AudioBookShelf server URL, username, and password to display your currently playing audiobooks as Discord Rich Presence.", + "automaticAuth": "The plugin will automatically authenticate and fetch your listening progress." + }, + "toasts": { + "notConfigured": "AudioBookShelf RPC is not configured." + } + }, + "altKrispSwitch": { + "description": "Makes the Noise Suppression Popout switch between None and Krisp instead of Krisp and Standard" + }, + "bannersEverywhere": { + "description": "Displays banners in the member list ", + "settings": { + "animate": "Animate banners", + "preferNameplate": "prefer nameplate over banner" + } + }, + "baseDecoder": { + "description": "Decode base64 content of any message and copy the decoded content.", + "settings": { + "clickMethod": "Change the button to decode base64 content of any message.", + "clickMethodOptions": { + "left": "Left Click to decode the base64 content.", + "right": "Right click to decode the base64 content." + } + }, + "ui": { + "modalTitle": "Decoded Base64 Content", + "decodedContent": "Decoded Content", + "copyDecoded": "Copy Decoded Content", + "copiedToast": "Decoded content copied to clipboard!", + "tooltipLeft": "Copy Decoded (Left Click) / Decode Base64 (Right Click)", + "tooltipRight": "Decode Base64 (Left Click) / Copy Decoded (Right Click)" + } + }, + "betterAudioPlayer": { + "description": "Adds a spectrograph and oscilloscope visualizer to audio attachment players", + "settings": { + "oscilloscope": "Enable oscilloscope visualizer", + "spectrograph": "Enable spectrograph visualizer", + "oscilloscopeSolidColor": "Use solid color for oscilloscope", + "oscilloscopeColor": "Color for oscilloscope", + "spectrographSolidColor": "Use solid color for spectrograph", + "spectrographColor": "Color for spectrograph", + "forceMoveBelow": "Force the visualizer below the audio player" + }, + "toasts": { + "invalidColor": "Invalid color format for {settingKey}, make sure it's in the format 'R, G, B' or '#RRGGBB'" + } + }, + "betterBanReasons": { + "description": "Create custom reasons to use in the Discord ban modal, and/or show a text input by default instead of the options.", + "settings": { + "reasons": "Your custom reasons", + "isTextInputDefault": "Shows a text input instead of a select menu by default. (Equivalent to clicking the \"Other\" option)" + }, + "ui": { + "reasons": "Reasons", + "reasonPlaceholder": "Reason", + "addAnotherReason": "Add another reason" + } + }, + "betterBlockedUsers": { + "description": "Allows you to search in blocked users list and makes names selectable in settings.", + "ui": { + "searchPlaceholder": "Search users..." + } + }, + "betterInvites": { + "description": "See invites expiration date, view inviter profile and preview servers before joining by clicking the name", + "ui": { + "expireTooltip": "This invite will {expiry}", + "expireWill": "expire", + "notExpire": "not expire", + "invitedYouTo": "{inviter} invited you to {guild}" + } + }, + "bypassStatus": { + "description": "Still get notifications from specific sources when in do not disturb mode. Right-click on users/channels/guilds to set them to bypass do not disturb mode.", + "settings": { + "guilds": "Guilds to let bypass (notified when pinged anywhere in guild)", + "channels": "Channels to let bypass (notified when pinged in that channel)", + "users": "Users to let bypass (notified for all messages sent in DMs)", + "allowOutsideOfDms": "Allow selected users to bypass status outside of DMs too (acts like a channel/guild bypass, but it's for all messages sent by the selected users)", + "notificationSound": "Whether the notification sound should be played", + "respectSilentPings": "Respect silent pings (@silent / suppress notifications)", + "statusToUse": "Status to use for whitelist" + }, + "statusOptions": { + "online": "Online", + "idle": "Idle", + "dnd": "Do Not Disturb", + "invisible": "Invisible" + }, + "contextMenu": { + "addStatusBypass": "Add Status Bypass", + "removeStatusBypass": "Remove Status Bypass" + }, + "placeholder": { + "separateWithCommas": "Separate with commas" + } + }, + "alwaysExpandProfiles": { + "description": "Always expands profile popouts to the full modal" + }, + "anammox": { + "description": "Hides various features related to nitro and the store", + "settings": { + "dms": "Remove shops above DMs list", + "quests": "Remove quests above DMs list", + "serverBoost": "Remove server boost info above channel list", + "billing": "Remove billing settings", + "gift": "Remove gift button", + "emojiList": "Remove unavailable categories from the emoji picker" + } + }, + "animalese": { + "description": "Plays animal crossing animalese for every message sent (they yap a lot)", + "settings": { + "volume": "Volume of the animalese sound", + "speed": "Speed of the animalese sound", + "pitch": "Pitch multiplier", + "messageLengthLimit": "Maximum length of message to process", + "processOwnMessages": "Enable to yap your own messages too", + "soundQuality": "Quality of sound to use" + }, + "quality": { + "high": "High", + "medium": "Medium", + "low": "Low", + "lowest": "Lowest" + } + }, + "atSomeone": { + "description": "Mention someone randomly", + "contextMenu": { + "someone": "Mention someone randomly" + } + }, + "autoZipper": { + "description": "Automatically zips specified file types and folders before uploading to Discord", + "settings": { + "extensions": "Comma-separated list of file extensions to auto-zip (e.g., .psd,.blend,.exe,.dmg)" + } + }, + "betterCommands": { + "description": "Enhances the command system with miscellaneous improvements.", + "settings": { + "autoFillArguments": "Automatically fill command with all arguements instead of just required ones", + "allowNewlinesInCommands": "Allow newlines in command inputs (CTRL + Shift + Enter)" + }, + "commands": { + "refresh": { + "description": "Refreshes Discord application commands locally", + "userOption": "specific user to try and refresh", + "refreshing": "Refreshing application commands...", + "success": "Commands refreshed successfully!", + "failed": "Failed to refresh commands. Check the console for details." + } + } + }, + "betterPlusReacts": { + "description": "The amount of plus before :emoji: is the message to add it to" + }, + "betterUserArea": { + "description": "Customize and make the user area more clean.", + "settings": { + "removeNameplate": "Remove nameplate styling.", + "removeAudioMenus": "Remove menus next to mute and deafen buttons.", + "alwaysShowUsername": "Always show username instead of status.", + "removeButtonTooltips": "Remove button tooltips.", + "removeAvatarDecoration": "Remove avatar decoration.", + "removeUsernameStyles": "Remove username colors and effects." + } + }, + "blockKeywords": { + "description": "Blocks messages containing specific user-defined keywords, as if the user sending them was blocked.", + "settings": { + "blockedWords": "Comma-seperated list of words to block", + "useRegex": "Use each value as a regular expression when checking message content (advanced)", + "caseSensitive": "Whether to use a case sensitive search or not", + "ignoreBlockedMessages": "Completely ignores (recent) new messages bar" + } + }, + "blockKrisp": { + "description": "Prevent Krisp from loading" + }, + "bypassPinPrompt": { + "description": "Bypass the pin prompt when using the pin functions" + }, + "channelBadges": { + "description": "Adds badges to channels based on their type", + "settings": { + "oneBadgePerChannel": "Show only one badge per channel", + "showTextBadge": "Show Text badge", + "showVoiceBadge": "Show Voice badge", + "showCategoryBadge": "Show Category badge", + "showDirectoryBadge": "Show Directory badge", + "showAnnouncementThreadBadge": "Show Announcement Thread badge", + "showPublicThreadBadge": "Show Public Thread badge", + "showPrivateThreadBadge": "Show Private Thread badge", + "showStageBadge": "Show Stage badge", + "showAnnouncementBadge": "Show Announcement badge", + "showForumBadge": "Show Forum badge", + "showMediaBadge": "Show Media badge", + "showNSFWBadge": "Show NSFW badge", + "showLockedBadge": "Show Locked badge", + "showRulesBadge": "Show Rules badge", + "showUnknownBadge": "Show Unknown badge", + "textBadgeLabel": "Text badge label", + "voiceBadgeLabel": "Voice badge label", + "categoryBadgeLabel": "Category badge label", + "announcementBadgeLabel": "Announcement badge label", + "announcementThreadBadgeLabel": "Announcement Thread badge label", + "publicThreadBadgeLabel": "Public Thread badge label", + "privateThreadBadgeLabel": "Private Thread badge label", + "stageBadgeLabel": "Stage badge label", + "directoryBadgeLabel": "Directory badge label", + "forumBadgeLabel": "Forum badge label", + "mediaBadgeLabel": "Media badge label", + "nsfwBadgeLabel": "NSFW badge label", + "lockedBadgeLabel": "Locked badge label", + "rulesBadgeLabel": "Rules badge label", + "unknownBadgeLabel": "Unknown badge label", + "textBadgeColor": "Text badge color", + "voiceBadgeColor": "Voice badge color", + "categoryBadgeColor": "Category badge color", + "announcementBadgeColor": "Announcement badge color", + "announcementThreadBadgeColor": "Announcement Thread badge color", + "publicThreadBadgeColor": "Public Thread badge color", + "privateThreadBadgeColor": "Private Thread badge color", + "stageBadgeColor": "Stage badge color", + "directoryBadgeColor": "Directory badge color", + "forumBadgeColor": "Forum badge color", + "mediaBadgeColor": "Media badge color", + "nsfwBadgeColor": "NSFW badge color", + "lockedBadgeColor": "Locked badge color", + "rulesBadgeColor": "Rules badge color", + "unknownBadgeColor": "Unknown badge color" + }, + "tooltips": { + "lockedChannel": "This channel is locked.", + "nsfwChannel": "This channel is marked as NSFW.", + "rulesChannel": "This channel is the server rules channel." + } + }, + "channelTabs": { + "description": "Group your commonly visited channels in tabs, like a browser", + "contextMenu": { + "openInNewTab": "Open in New Tab" + } + }, + "characterCounter": { + "description": "Adds a character counter to the chat input", + "settings": { + "colorEffects": "Turn on or off color effects for getting close to the character limit" + } + }, + "cleanChannelName": { + "description": "remove all emoji and decor shit from channel names" + }, + "cleanerChannelGroups": { + "description": "Hides all channels in collapsed categories, even if they have unread messages." + }, + "clientSideBlock": { + "description": "Allows you to locally hide almost all content from any user", + "settings": { + "hideVc": "Hide voice channels containing blocked users.", + "usersToBlock": "User IDs seperated by a comma and a space", + "hideBlockedUsers": "Should blocked users should also be hidden everywhere", + "hideBlockedMessages": "Should messages from blocked users should be hidden fully (same as the old noblockedmessages plugin)", + "hideEmptyRoles": "Should role headers be hidden if all of their members are blocked", + "blockedReplyDisplay": "What should display instead of the message when someone replies to someone you have hidden", + "blockedReplyDisplayOptions": { + "displayText": "Display text saying a hidden message was replied to", + "hideReply": "Literally nothing" + }, + "guildBlackList": "Guild ids to disable functionality in", + "guildWhiteList": "Guild ids to enable functionality in" + }, + "reply": { + "replyingToBlocked": "Replying to blocked message" + } + }, + "clipsEnhancements": { + "description": "Add more Clip FPS and duration options, custom clip length, RPC tagging and more", + "settings": { + "richPresenceTagging": "When should clips be tagged with the current Rich Presence?", + "richPresenceTaggingOptions": { + "always": "Always", + "whenMatched": "Only when beginning or end of activity name matches", + "never": "Never" + }, + "enableScreenshotKeybind": "Enable the screenshot keybind feature", + "enableVoiceOnlyClips": "Enable voice-only clips (audio without video)", + "enableAdvancedSignals": "Enable advanced clip signals (auto-clip triggers)", + "ignorePlatformRestriction": "Allow Platform Restricted Clipping (may cause save errors)", + "clipsLink": "Change FPS and duration options in Clips settings!" + } + }, + "commandPalette": { + "description": "Quickly run actions through a searchable command palette", + "settings": { + "hotkey": "Hotkey used to open the command palette", + "visualStyle": "Palette appearance", + "visualStyleOptions": { + "classic": "Classic", + "polished": "Polished" + }, + "showTags": "Display tag chips for commands", + "enableTagFilter": "Show the tag filter bar", + "customCommands": "Manage custom command palette entries" + }, + "ui": { + "hotkeyTitle": "Command Palette Hotkey", + "hotkeyDescription": "Hotkey used to open the command palette", + "pressAnyKey": "Press any key...", + "reset": "Reset" + } + }, + "components": { + "description": "Utility plugin for developers to test and preview Discord components" + }, + "contentWarning": { + "description": "Allows you to specify certain trigger words that will be blurred by default. Hovering/Clicking on the blurred content will reveal it.", + "settings": { + "onClick": "Only show trigger content on click instead of hover" + }, + "ui": { + "flaggedWords": "Flagged Words", + "placeholder": "Word" + } + }, + "copyProfileColors": { + "description": "A plugin to copy people's profile gradient colors to clipboard.", + "contextMenu": { + "copyProfileColors": "Copy Profile Colors" + }, + "toast": { + "noColorsFound": "No profile colors found!", + "copied": "Profile colors copied to clipboard!", + "error": "Error copying profile colors!" + } + }, + "copyStatusUrls": { + "description": "Copy the users status url when you right-click it", + "toast": { + "copied": "Copied URL", + "error": "Error copying URL, check console for more info" + } + }, + "copyUserMention": { + "description": "Adds a button to copy user's mention on the user context menu, works best with ValidUser.", + "contextMenu": { + "copyUserMention": "Copy User Mention" + } + }, + "cursorBuddy": { + "description": "Adds a sprite that follows your cursor.", + "settings": { + "buddy": "Pick a cursor buddy", + "buddyOptions": { + "oneko": "Oneko", + "fathorse": "Fatass Horse" + }, + "speed": "Speed of your buddy", + "fps": "Framerate of your buddy", + "furColor": "Fur hex color for Oneko", + "outlineColor": "Outline hex color for Oneko", + "size": "Size of the fatass horse", + "fade": "If the horse should fade when the cursor is near", + "freeroam": "If the horse should roam freely when idle", + "shake": "If the horse should shake the window when it's walking" + }, + "ui": { + "furColor": "Fur Color", + "outlineColor": "Outline Color" + } + }, + "customFolderIcons": { + "description": "Customize folder icons with any png" + }, + "customSounds": { + "description": "Customize Discord's sounds.", + "settings": { + "searchSounds": "Search Sounds", + "searchPlaceholder": "Search by name or ID", + "import": "Import", + "export": "Export", + "resetAll": "Reset All", + "debug": "Debug" + }, + "toast": { + "resetSuccess": "All overrides reset successfully!", + "importSuccess": "Settings imported successfully!", + "importError": "Error importing settings. Check console for details.", + "exportSuccess": "Exported {count} settings (audio files not included)", + "loadError": "Error loading custom sound file" + } + }, + "customTimestamps": { + "description": "Custom timestamps on messages and tooltips", + "settings": { + "formats": "Customize the timestamp formats", + "calendarFormats": "Calendar formats", + "calendarFormatsDescription": "How to format the [calendar] value if used in the above timestamps." + }, + "about": { + "title": "How to use:", + "additional": "Additionally you can use these in your inputs:", + "calendar": "enables dynamic date formatting such as \"Today\" or \"Yesterday\".", + "relative": "gives you times such as \"4 hours ago\"." + } + }, + "customUserColors": { + "description": "Lets you add a custom color to any user, anywhere! Highly recommend to use with typingTweaks and roleColorEverywhere", + "settings": { + "dmList": "Users with custom colors defined will have their name in the dm list colored", + "colorInServers": "If name colors should be changed within servers" + }, + "contextMenu": { + "setColor": "Set Color" + } + }, + "disableCameras": { + "description": "Disables cameras in a call by default" + }, + "discordDevBanner": { + "description": "Enables the Discord developer banner, in which displays the build-ID" + }, + "dragFavoriteEmotes": { + "description": "Adds the ability to change the order of your favourite emotes" + }, + "dragify": { + "description": "Drop users, channels, or servers into chat to insert mentions or invites.", + "settings": { + "userOutput": "User drop output.", + "userOutputOptions": { + "mention": "Mention user", + "id": "User ID" + }, + "channelOutput": "Channel drop output.", + "channelOutputOptions": { + "mention": "#channel mention", + "link": "Channel link" + }, + "inviteExpireAfter": "Invite expiration.", + "inviteExpireAfterOptions": { + "30min": "30 minutes", + "1hour": "1 hour", + "6hours": "6 hours", + "12hours": "12 hours", + "1day": "1 day", + "7days": "7 days", + "never": "Never" + }, + "inviteMaxUses": "Invite max uses.", + "inviteMaxUsesOptions": { + "noLimit": "No limit", + "1use": "1 use", + "5uses": "5 uses", + "10uses": "10 uses", + "25uses": "25 uses", + "50uses": "50 uses", + "100uses": "100 uses" + }, + "inviteTemporaryMembership": "Grant temporary membership.", + "reuseExistingInvites": "Reuse existing invite instead of creating a new one.", + "allowChatBodyDrop": "Allow dropping into the main chat body to insert text." + }, + "toast": { + "dropFailed": "Dragify failed to handle drop.", + "noChannelForInvites": "No channel available for invites.", + "inviteCreated": "Invite created.", + "inviteFailed": "Unable to create invite." + } + }, + "messageLoggerEnhanced": { + "settings": { + "saveMessages": "Whether to save the deleted and edited messages.", + "saveImages": "Save deleted attachments.", + "sortNewest": "Sort logs by newest.", + "cacheMessagesFromServers": "Usually message logger only logs from whitelisted ids and dms, enabling this would mean it would log messages from all servers as well. Note that this may cause the cache to exceed its limit, resulting in some messages being missed. If you are in a lot of servers, this may significantly increase the chances of messages being logged, which can result in a large message record and the inclusion of irrelevant messages.", + "ignoreBots": "Whether to ignore messages by bots", + "ignoreWebhooks": "Whether to ignore messages by webhooks", + "ignoreSelf": "Whether to ignore messages by yourself", + "ignoreMutedGuilds": "Messages in muted guilds will not be logged. Whitelisted users/channels in muted guilds will still be logged.", + "ignoreMutedCategories": "Messages in channels belonging to muted categories will not be logged. Whitelisted users/channels in muted guilds will still be logged.", + "ignoreMutedChannels": "Messages in muted channels will not be logged. Whitelisted users/channels in muted guilds will still be logged.", + "alwaysLogDirectMessages": "Always log DMs", + "alwaysLogCurrentChannel": "Always log current selected channel. Blacklisted channels/users will still be ignored.", + "permanentlyRemoveLogByDefault": "Vencord's base MessageLogger remove log button wiil delete logs permanently", + "hideMessageFromMessageLoggers": "When enabled, a context menu button will be added to messages to allow you to delete messages without them being logged by other loggers. Might not be safe, use at your own risk.", + "showLogsButton": "Toggle to whenever show the toolbox or not", + "showWhereMessageIsFrom": "Show message channel/author name and server name", + "messagesToDisplayAtOnceInLogs": "Number of messages to display at once in logs & number of messages to load when loading more messages in logs.", + "hideMessageFromMessageLoggersDeletedMessage": "The message content to replace the message with when using the hide message from message loggers feature.", + "messageLimit": "Maximum number of messages to save. Older messages are deleted when the limit is reached. 0 means there is no limit", + "attachmentSizeLimitInMegabytes": "Maximum size of an attachment in megabytes to save. Attachments larger than this size will not be saved.", + "attachmentFileExtensions": "Comma separated list of file extensions to save. Attachments with file extensions not in this list will not be saved. Leave empty to save all attachments.", + "cacheLimit": "Maximum number of messages to store in the cache. Older messages are deleted when the limit is reached. This helps reduce memory usage and improve performance. 0 means there is no limit", + "timeBasedCleanupMinutes": "Automatically remove messages from servers that are older than this many minutes. Set to 0 to disable time-based cleanup.", + "preserveCurrentChannel": "When enabled, messages in your currently selected channel are not affected by time-based cleanup.", + "whitelistedIds": "Whitelisted server, channel, or user IDs.", + "blacklistedIds": "Blacklisted server, channel, or user IDs.", + "selectImageCacheDir": "Select saved images directory", + "selectLogsDir": "Select logs directory", + "importLogsFromFile": "Import Logs From File", + "exportLogsFromIndexedDB": "Export Logs From IndexedDB", + "openLogs": "Open Logs", + "openImageCacheFolder": "Opens the image cache directory" + }, + "modal": { + "filterMessages": "Filter Messages", + "deleted": "Deleted", + "edited": "Edited", + "ghostPinged": "Ghost Pinged", + "clearAllLogs": "Clear All Logs", + "clearVisibleLogs": "Clear Visible Logs", + "sortOldestFirst": "Sort Oldest First", + "sortNewestFirst": "Sort Newest First", + "noResultsIn": "No results in {tab}.", + "maybeTry": "Maybe try {nextTab} or {lastTab}", + "emptyLogs": "Empty eh", + "importLogsTooltip": "ML Enhanced now stores logs in indexeddb. You need to import your old logs from the logs directory. Importing wont overwrite existing logs", + "importLogs": "Import Logs", + "loadMore": "Load More", + "jumpToMessage": "Jump To Message", + "openUserProfile": "Open user profile", + "copyContent": "Copy Content", + "copyUserId": "Copy User ID", + "copyMessageId": "Copy Message ID", + "copyChannelId": "Copy Channel ID", + "copyServerId": "Copy Server ID", + "deleteLog": "Delete Log", + "fromDms": "From {username}'s DMs", + "fromGroupDm": "From {name} Group DM", + "fromChannel": "From {channel} in {guild}" + }, + "buttons": { + "importing": "Importing...", + "importLogs": "Import Logs", + "exporting": "Exporting...", + "exportLogs": "Export Logs" + } + }, + "friendCodes": { + "settings": { + "autoCopy": "Automatically copy friend code to clipboard when it changes", + "sendToServer": "Automatically send friend code to server when it changes", + "webhookUrl": "Webhook URL to send friend code to" + }, + "panel": { + "title": "Friend Codes", + "currentCode": "Current Friend Code", + "copyCode": "Copy Code", + "copied": "Copied!", + "sendToServer": "Send to Server", + "sent": "Sent!", + "refresh": "Refresh", + "error": "Error: {error}" + } + }, + "elementHighlighter": { + "description": "Highlight and inspect elements easily.", + "settings": { + "keybind": "Toggle Highlighter", + "showClasses": "Display the element's CSS class names in the tooltip", + "showId": "Display the element's ID attribute in the tooltip", + "showFont": "Display the computed font family and font size", + "showPadding": "Display the element's padding values", + "showMargin": "Display the element's margin values", + "showBorderRadius": "Display the element's border-radius values", + "showPosition": "Display the element's CSS position type and z-index", + "showDisplay": "Display the element's display type along with flex or grid properties" + }, + "ui": { + "recording": "Recording...", + "reset": "Reset", + "copiedColor": "Copied color to clipboard!" + } + }, + "equicordHelper": { + "description": "Used to provide support, fix discord caused crashes, and other misc features.", + "settings": { + "noMirroredCamera": "Prevents the camera from being mirrored on your screen", + "removeActivitySection": "Removes the activity section above member list", + "showYourOwnActivityButtons": "Discord hides your own activity buttons for some reason", + "noDefaultHangStatus": "Disable the default hang status when joining voice channels", + "refreshSlashCommands": "Refreshes Slash Commands to show newly added commands without restarting your client.", + "forceRoleIcon": "Forces role icons to display next to messages in compact mode", + "accountStandingButton": "Show an account standing button in the header bar" + }, + "standing": { + "allGood": "All good!", + "limited": "Limited", + "veryLimited": "Very limited", + "atRisk": "At risk", + "suspended": "Suspended" + }, + "commands": { + "refreshCommands": "Refresh Slash Commands", + "refreshSuccess": "Slash Commands refreshed successfully.", + "refreshFailed": "Failed to refresh commands. Check console for details." + }, + "alerts": { + "supportWarningTitle": "Vencord Support Channel Warning", + "supportWarningBody": "Before asking for help. Check updates and if this issue is actually caused by Equicord!", + "equicordSupport": "Equicord Support", + "okayContinue": "Okay continue" + } + }, + "equicordToolbox": { + "description": "Adds a button next to the inbox button in the channel header that houses Equicord quick actions", + "settings": { + "showPluginMenu": "Show the plugins menu in the toolbox" + }, + "ui": { + "tooltip": "Equicord Toolbox", + "plugins": "Plugins", + "themes": "Themes", + "openNotificationLog": "Open Notification Log", + "openSettings": "Open Settings", + "enableQuickCss": "Enable QuickCSS", + "editQuickCss": "Edit QuickCSS", + "manageThemes": "Manage Themes", + "restartToApply": "Restart to apply the change" + } + }, + "equissant": { + "description": "Crossant every specified amount of clicks :trolley:", + "settings": { + "amount": "Amount of clicks to trigger crossant" + } + }, + "exitSounds": { + "description": "Play soundboard sounds when you disconnect from voice.", + "settings": { + "soundGuildId": "Select the server containing the sound.", + "soundId": "Enter the ID of the sound you want to play." + }, + "ui": { + "selectServer": "Select a server...", + "enterSoundId": "Enter sound ID...", + "setGlobalExitSound": "Set as global exit sound" + }, + "toasts": { + "somethingWentWrong": "Oops! Something went wrong." + } + }, + "exportMessages": { + "description": "Allows you to export any message to a file", + "settings": { + "openFileAfterExport": "Open the exported file in the default file handler after export", + "exportContacts": "Export a list of friends to your clipboard. Adds a new button to the menu bar for the friends tab." + }, + "ui": { + "exportMessage": "Export Message", + "export": "Export", + "contactsCopied": "Contacts copied to clipboard successfully.", + "contactListUndefined": "Contact list is undefined. Click on the \"All\" tab before exporting." + }, + "notifications": { + "title": "Export Messages", + "exportSuccess": "Message exported successfully as {filename}", + "exportFailed": "Failed to export message" + } + }, + "fastDeleteChannels": { + "description": "Adds a trash icon to delete channels", + "settings": { + "keyBind": "The key to toggle trash when pressed.", + "reqCtrl": "Require control to be held.", + "reqShift": "Require shift to be held.", + "reqAlt": "Require alt to be held." + } + }, + "favouriteAnything": { + "description": "Favourite any image" + }, + "fileUpload": { + "description": "Upload images and videos to file hosting services like Zipline and Nest", + "ui": { + "uploadTo": "Upload to {serviceName}" + } + }, + "findReply": { + "description": "Jumps to the earliest reply to a message in a channel (lets you follow past conversations more easily).", + "settings": { + "includePings": "Will also search for messages that @ the author directly", + "includeAuthor": "Will also search for messages that reply to the author in general, not just that exact message", + "hideButtonIfNoReply": "Hides the button if there are no replies to the message" + }, + "ui": { + "jumpToReply": "Jump to Reply" + }, + "toasts": { + "useBottomPanel": "Use the bottom panel to navigate between replies.", + "containerNotFound": "Couldn't find the container element.", + "noReplyFound": "Couldn't find a reply." + } + }, + "fixFileExtensions": { + "description": "Fixes file extensions by renaming them to a compatible supported format if possible" + }, + "followVoiceUser": { + "description": "Follow a friend in voice chat.", + "settings": { + "onlyWhenInVoice": "Only follow the user when you are in a voice channel", + "leaveWhenUserLeaves": "Leave the voice channel when the user leaves. (That can cause you to sometimes enter infinite leave/join loop)" + }, + "ui": { + "followUser": "Follow User" + }, + "info": "This Plugin is used to follow a Friend/Friends into voice chat(s)." + }, + "fontLoader": { + "description": "Loads any font from Google Fonts", + "settings": { + "applyOnCodeBlocks": "Apply the font to code blocks" + }, + "ui": { + "searchGoogleFonts": "Search Google Fonts", + "clickToApply": "Click on any font to apply it.", + "searchFonts": "Search fonts...", + "by": "by {authors}" + } + }, + "forwardAnywhere": { + "description": "If a forward fails send it as a normal message also allows nsfw forwards", + "settings": { + "forwardPreface": "What should forwarded from be prefaced with" + }, + "options": { + "greaterThan": ">", + "hash": "-#" + } + }, + "frequentQuickSwitcher": { + "description": "Rewrites and filters the quick switcher results to be your most frequent channels" + }, + "friendCloud": { + "description": "Adds a /friendcloud command to visualize the users you most interact with", + "commands": { + "friendcloud": "Display user you most interact with in a cloud", + "count": "Number of users to display" + }, + "errors": { + "countMustBeHigher": "The count must be 1 or higher!", + "noAffinities": "No affinities found. Check your privacy settings.", + "noValidUsers": "No valid users found in affinities. Check your privacy settings.", + "couldntGenerate": "Couldn't generate the image :c" + } + }, + "friendTags": { + "description": "Allows you to filter by custom tags in the quick switcher by starting a search with &", + "ui": { + "tag": "Tag", + "addTo": "Add to {tagName}", + "removeFrom": "Remove from {tagName}", + "name": "Name", + "usersSeperated": "Users (Seperated by comma)", + "userList": "User List (Click A User To Remove)", + "remove": "Remove", + "add": "Add" + } + }, + "friendshipRanks": { + "description": "Adds badges showcasing how long you have been friends with a user for", + "ranks": { + "sprout": { + "title": "Sprout", + "description": "Your friendship is just starting" + }, + "blooming": { + "title": "Blooming", + "description": "Your friendship is getting there! (1 Month)" + }, + "burning": { + "title": "Burning", + "description": "Your friendship has reached terminal velocity (3 Months)" + }, + "fighter": { + "title": "Fighter", + "description": "Your friendship is strong (6 Months)" + }, + "star": { + "title": "Star", + "description": "Your friendship has been going on for a WHILE (1 Year)" + }, + "royal": { + "title": "Royal", + "description": "Your friendship has gone through thick and thin- a whole 2 years!" + }, + "besties": { + "title": "Besties", + "description": "How do you even manage this??? (5 Years)" + } + } + }, + "fullVcPfp": { + "description": "Makes avatars take up the entire vc tile" + }, + "gensokyoRadioRPC": { + "description": "Discord rich presence for Gensokyo Radio!", + "settings": { + "refreshInterval": "The interval between activity refreshes (seconds)" + }, + "info": "Discord rich presence for Gensokyo Radio!" + }, + "ghosted": { + "description": "A cute ghost will appear if you don't answer their DMs", + "settings": { + "showIndicator": "Show the ghost counter at the top of the server list", + "showDmIcons": "Show ghost icons next to individual DMs", + "ignoreGroupDms": "Exclude all group dms from ghosting", + "exemptedChannels": "Comma-separated list of channel IDs to exempt from ghosting (right-click a DM channel to copy its ID)", + "ignoreBots": "Ignore DMs from bots" + }, + "ui": { + "noGhostedUsers": "No Ghosted Users", + "ghostedUsers": "{count} Ghosted Users", + "unghost": "unghost" + } + }, + "gifCollections": { + "description": "Allows you to create collections of gifs", + "settings": { + "itemPrefix": "The prefix for gif items", + "collectionPrefix": "The prefix for collections", + "onlyShowCollections": "Only show collections", + "stopWarnings": "Stop deletion warnings", + "showCopyImageLink": "Show 'Copy Image Link' option in context menus", + "preventDuplicates": "Prevent adding the same GIF to a collection multiple times", + "defaultEmptyCollectionImage": "The image / gif that will be shown when a collection has no images / gifs", + "collectionsSortType": "The type of sorting for collections", + "collectionsSortOrder": "The order of sorting for collections" + }, + "ui": { + "copyImageLink": "Copy Image Link", + "imageLinkCopied": "Image link copied to clipboard", + "addToCollection": "Add To Collection", + "createCollection": "Create Collection", + "collectionInformation": "Collection Information", + "name": "Name", + "gifs": "Gifs", + "createdAt": "Created At", + "lastUpdated": "Last Updated", + "unknown": "Unknown", + "close": "Close", + "rename": "Rename", + "information": "Information", + "addedAt": "Added At", + "width": "Width", + "height": "Height", + "refreshUrl": "Refresh URL", + "refreshing": "Refreshing URL...", + "refreshSuccess": "URL refreshed successfully", + "refreshFailed": "Failed to refresh URL", + "cannotRefresh": "Cannot refresh: GIF missing metadata (re-add to collection)", + "copyUrl": "Copy URL", + "urlCopied": "URL copied to clipboard", + "moveToCollection": "Move To Collection", + "selectCollection": "Select a collection to move the item to", + "deleteCollection": "Delete Collection", + "remove": "Remove", + "areYouSure": "Are you sure?", + "importOverwrite": "Importing collections will overwrite your current collections.", + "import": "Import", + "nevermind": "Nevermind", + "resetRemove": "Resetting collections will remove all your collections.", + "reset": "Reset", + "collectionName": "Collection Name", + "sortCollections": "Sort Collections", + "sortBy": "Sort By", + "order": "Order", + "ascending": "Ascending", + "descending": "Descending", + "creationDate": "Creation Date", + "modifiedDate": "Modified Date", + "exportCollections": "Export Collections", + "importCollections": "Import Collections", + "resetCollections": "Reset Collections", + "deleteConfirm": "Do you really want to {action}?", + "deleteAction": "delete this collection", + "removeAction": "remove this item" + }, + "toasts": { + "gifMissingMetadata": "Cannot refresh: GIF missing metadata (re-add to collection)" + } + }, + "gifRoulette": { + "description": "Adds a command to send a random gif from your favourites, and a one in ten chance to ping the owner of the server", + "settings": { + "pingOwnerChance": "If there should be a 1 in 10 change to ping the owner of the guild (oh no)" + }, + "commands": { + "gifroulette": "Tempt fate and send a gif" + } + }, + "githubRepos": { + "description": "Displays a user's public GitHub repositories in their profile", + "settings": { + "showStars": "Show repository stars", + "showLanguage": "Show repository language", + "showInMiniProfile": "Show full ui in the mini profile instead of just a button", + "showRepositoryTab": "Show repositories tab in profile modal (hides button in connections when enabled)" + }, + "ui": { + "error": "Error, Failed to render GithubRepos" + } + }, + "globalBadges": { + "description": "Adds global badges from other client mods", + "ui": { + "joinServer": "Join GlobalBadges Server", + "refetchSuccess": "Successfully refetched global badges!" + } + }, + "googleThat": { + "description": "Adds a command to send a internet search link", + "settings": { + "hyperlink": "If the sent link should hyperlink with the query as the label", + "embed": "If the sent link should render an embed", + "defaultEngine": "The search engine to use", + "customEngineURL": "The URL of the Engine you wish to use" + }, + "commands": { + "googlethat": "Send a search engine link", + "input": "The search query" + } + }, + "guildPickerDumper": { + "description": "Context menu to dump and download a server's emojis and stickers.", + "ui": { + "downloadEmojis": "Download Emojis", + "downloadStickers": "Download Stickers", + "serverNotFound": "Server not found!" + } + }, + "guildTagSettings": { + "description": "Adds some settings for guild tags, such as hiding them or disabling the prompt to adopt them.", + "settings": { + "hideTags": "Hide tags", + "disableAdoptTagPrompt": "Disable the prompt to adopt tags" + } + }, + "hideChatButtons": { + "description": "Able to hide the chat buttons", + "settings": { + "color": "Color it red on open", + "open": "Opened by default" + }, + "ui": { + "close": "Close", + "open": "Open" + } + }, + "hideServers": { + "description": "Allows you to hide servers from the guild list and quick switcher by right clicking them", + "ui": { + "hideServer": "Hide Server", + "unhideServer": "Unhide Server", + "hideFolder": "Hide Folder", + "unhideFolder": "Unhide Folder" + } + }, + "holyNotes": { + "description": "Save messages as notes to revisit later", + "ui": { + "noteMessage": "Note Message", + "holyNotes": "Holy Notes", + "openNotes": "Open Notes", + "saveNote": "Save Note" + } + }, + "homeTyping": { + "description": "Changes the home button to a typing indicator if someone in your dms is typing" + }, + "hopOn": { + "description": "Hop on Fortnite or Hop on bloons :3", + "settings": { + "regex": "Regex to trigger on", + "url": "URL to open" + } + }, + "husk": { + "description": "Adds Husk button (check settings to change used emoji)", + "settings": { + "findInServer": "Attempt to find emoji of same name in server before using ID in settings (useful if no nitro)", + "emojiName": "Emoji name (default (from Vencord Server): husk)", + "emojiID": "Emoji ID (default (from Vencord Server): 1026532993923293184)" + }, + "ui": { + "husk": "Husk" + } + }, + "iRememberYou": { + "description": "Locally saves everyone you've been communicating with (including servers), in case of lose", + "ui": { + "iRememberYou": "I Remember You" + } + }, + "iconViewer": { + "description": "Adds a new tab to settings to preview all icons.", + "ui": { + "openIconsTab": "Open Icons Tab", + "iconFinder": "Icon Finder" + } + }, + "idleAutoRestart": { + "description": "Automatically restarts the client after being idle for a configurable amount of time, but avoids restarting while you are in VC.", + "settings": { + "isEnabled": "Enable automatic restart after idle", + "idleMinutes": "Minutes of inactivity before restarting (when not in VC)" + }, + "ui": { + "disableAutoIdle": "Disable Auto Idle Restart", + "enableAutoIdle": "Enable Auto Idle Restart" + } + }, + "ignoreCalls": { + "description": "Allows you to ignore calls from specific users or dm groups.", + "settings": { + "permanentlyIgnoredUsers": "User IDs (comma + space) who should be permanetly ignored" + }, + "ui": { + "temporarilyIgnore": "Temporarily Ignore Calls", + "permanentlyIgnore": "Permanently Ignore Calls", + "ignore": "Ignore" + } + }, + "imgToGif": { + "description": "Adds a /imgtogif slash command to create a gif from any image", + "commands": { + "imgtogif": "Allows you to turn an image to a gif", + "image": "Image attachment to use", + "width": "Width of the gif", + "height": "Height of the gif" + }, + "errors": { + "noImage": "No Image specified!", + "notAnImage": "Upload is not an image" + } + }, + "ingtoninator": { + "description": "Suffixes 'ington' to a random word in your message", + "settings": { + "showIcon": "Show a button to toggle the Ingtoninator plugin", + "isEnabled": "Enable or disable the Ingtoninator" + }, + "ui": { + "enabled": "Ingtoninator Enabled", + "disabled": "Ingtoninator Disabled" + } + }, + "inRole": { + "description": "Know who is in a role with the role context menu or /inrole command (read plugin info!)", + "commands": { + "inrole": "Know who is in a role", + "role": "The role" + }, + "ui": { + "viewMembers": "View Members in Role" + }, + "errors": { + "makeSureServer": "Make sure that you are in a server." + }, + "limitations": { + "title": ":warning: Limitations", + "description": "If you don't have mod permissions on the server, and that server is large (over 100 members), the plugin may be limited in the following ways:", + "offlineNotListed": "Offline members won't be listed", + "upTo100": "Up to 100 members will be listed by default. To get more, scroll down in the member list to load more members.", + "friendsAlwaysShown": "However, friends will always be shown regardless of their status." + } + }, + "instantScreenshare": { + "description": "Instantly screenshare when joining a voice channel with support for desktop sources, windows, and video input devices (cameras, capture cards)", + "ui": { + "instantScreenshare": "Instant Screenshare", + "instantScreenshareEnabled": "Instant Screenshare Enabled", + "instantScreenshareDisabled": "Instant Screenshare Disabled" + }, + "info": { + "linux": "For Linux", + "wayland": "For Wayland it only pops up the screenshare select", + "x11": "For X11 it may or may not work :shrug:", + "videoDevices": "Video Devices", + "videoDevicesInfo": "Supports cameras and capture cards (like Elgato HD60X) when enabled in settings", + "soundPreview": "Regarding Sound & Preview Settings", + "soundPreviewInfo": "We use the settings set and used by discord to decide if stream preview and sound should be enabled or not" + } + }, + "invisibleChat": { + "description": "Encrypt your Messages in a non-suspicious way!", + "settings": { + "savedPasswords": "Saved Passwords (Seperated with a , )" + }, + "ui": { + "encryptMessage": "Encrypt Message", + "decryptMessage": "Decrypt Message", + "hiddenMessageIndicator": "This message has a hidden message! (InvisibleChat)" + } + }, + "inviteDefaults": { + "description": "Allows you to edit the default values when creating server invites.", + "settings": { + "inviteDuration": "Invite Duration", + "maxUses": "Invite Use Count", + "temporaryMembership": "Temporary Membership" + }, + "options": { + "infinite": "Infinite", + "forever": "Forever" + } + }, + "jellyfinRichPresence": { + "description": "Rich presence for Jellyfin media server", + "settings": { + "serverUrl": "Jellyfin server URL (e.g., https://jellyfin.example.com)", + "apiKey": "Jellyfin API key obtained from your Jellyfin administration dashboard", + "userId": "Jellyfin user ID obtained from your user profile URL", + "nameDisplay": "Choose how the application name should appear in Rich Presence", + "customName": "Custom Rich Presence name (only used if 'Custom' is selected). Options: {name}, {series}, {season}, {episode}, {artist}, {album}, {year}", + "coverType": "Choose which cover to display when watching a TV show", + "episodeFormat": "Episode number format", + "showEpisodeName": "Show episode name after season/episode info", + "overrideRichPresenceType": "Override the rich presence type", + "showPausedState": "Show Rich Presence when media is paused", + "privacyMode": "Privacy Mode (Hide media details like Episode/Song Name)" + }, + "nameFormatOptions": { + "seriesMovieName": "Series/Movie Name", + "seriesEpisodeName": "Series - Episode/Track/Movie Name", + "custom": "Custom" + }, + "coverTypeOptions": { + "seriesCover": "Series Cover", + "episodeCover": "Episode Cover" + }, + "episodeFormatOptions": { + "s01e01": "S01E01", + "short": "1x01", + "fulltext": "Season 1 Episode 1" + }, + "overrideTypeOptions": { + "off": "Off", + "listening": "Listening", + "playing": "Playing", + "streaming": "Streaming", + "watching": "Watching" + }, + "howToGetApiKey": { + "title": "How to get an API key", + "description": "Auth token can be found by following these steps:", + "userIdInfo": "You'll also need your User ID, which can be found in the url of your user profile page." + }, + "toasts": { + "notConfigured": "JellyfinRPC is not configured." + }, + "privacyMode": { + "episodeHidden": "[Episode Hidden]", + "trackHidden": "[Track Hidden]", + "movieHidden": "[Movie Hidden]", + "titleHidden": "[Title Hidden]", + "seriesHidden": "[Series Hidden]", + "artistHidden": "[Artist Hidden]", + "albumHidden": "[Album Hidden]", + "mediaHidden": "[Media Hidden]", + "watchingTvShow": "Watching a TV Show", + "watchingSomething": "Watching Something", + "listeningToMusic": "Listening to music" + }, + "state": { + "paused": "Paused", + "season": "Season {season}", + "episode": "Episode {episode}" + } + }, + "jumpscare": { + "description": "Adds a configurable chance of jumpscaring you whenever you open a channel. Inspired by Geometry Dash Mega Hack", + "settings": { + "imageSource": "Sets the image url of the jumpscare", + "audioSource": "Sets the audio url of the jumpscare", + "chance": "The chance of a jumpscare happening (1 in X so: 100 = 1/100 or 1%, 50 = 1/50 or 2%, etc.)" + } + }, + "jumpTo": { + "description": "Adds context menu options to jump to the start or bottom of a channel/DM.", + "ui": { + "jumpToFirst": "Jump To First Message", + "jumpToLast": "Jump To Last Message", + "yourLastMessage": "Your Last Message", + "usersLastMessage": "User's Last Message" + }, + "errors": { + "noMessagesFound": "No messages found from this user in this channel.", + "failedSearch": "Failed to search for messages.", + "channelNotAvailable": "Channel information not available.", + "failedJump": "Failed to jump to message. Check console for details." + } + }, + "keyboardNavigation": { + "description": "Allows you to navigate the UI with a keyboard.", + "settings": { + "hotkey": "The hotkey to open the command palette.", + "allowMouseControl": "Allow the mouse to control the command palette." + }, + "ui": { + "recording": "Recording...", + "recordKeybind": "Record keybind" + }, + "commands": { + "openDevSettings": "Open Dev tab" + } + }, + "keyboardSounds": { + "description": "Adds OperaGX or osu! sound effects when typing on your keyboard.", + "settings": { + "volume": "Volume of the keyboard sounds.", + "soundPack": "Sound pack to use." + }, + "options": { + "operaGx": "OperaGX", + "osu": "osu!" + } + }, + "keywordNotify": { + "description": "Sends a notification if a given message matches certain keywords or regexes", + "settings": { + "ignoreBots": "Ignore messages from bots", + "amountToKeep": "Amount of messages to keep in the log", + "keywords": "Manage keywords" + }, + "ui": { + "keywords": "Keywords", + "clearAll": "Clear All", + "addId": "Add ID", + "addKeywordEntry": "Add Keyword Entry", + "keywordEntry": "Keyword Entry {index}", + "ignoreCase": "Ignore Case", + "whitelistBlacklist": "Whitelist/Blacklist" + }, + "options": { + "whitelist": "Whitelist", + "blacklist": "Blacklist" + } + }, + "lastActive": { + "description": "A plugin to jump to last active message from yourself or another user in a channel/server.", + "errors": { + "noRecentMessages": "Couldn't find any recent messages from this user.", + "findFailed": "Failed to find messages. Check console for details.", + "channelNotAvailable": "Channel information not available.", + "jumpFailed": "Failed to jump to message. Check console for details." + } + }, + "limitMiddleClickPaste": { + "description": "Prevent middle click pasting either always or just when a text area is not focused.", + "settings": { + "scope": "Situations in which to prevent middle click from pasting.", + "threshold": "Milliseconds until pasting is enabled again after a middle click.", + "preventLinkOpen": "Prevent middle-click on links from opening new tabs while preserving autoscroll." + }, + "options": { + "alwaysPrevent": "Always Prevent Middle Click Pasting", + "onlyWhenNotFocused": "Only Prevent When Text Area Not Focused" + } + }, + "listenBrainzRPC": { + "description": "Little plugin for ListenBrainz rich presence", + "settings": { + "username": "ListenBrainz username", + "mbContact": "ListenBrainz contact", + "shareUsername": "Show link to ListenBrainz profile (may only be visible to other users)", + "shareSong": "Show link to song on ListenBrainz (may only be visible to other users)", + "hideWithSpotify": "Hide ListenBrainz presence if Spotify is running", + "hideWithActivity": "Hide ListenBrainz presence if you have any other presence", + "useTimeBar": "Use track duration to display a time bar (must be using Listening status)", + "statusName": "Custom status text", + "nameFormat": "Show name of song and artist in status name", + "useListeningStatus": "Show \"Listening to\" status instead of \"Playing\"", + "missingArt": "When album or album art is missing", + "useLogo": "Show ListenBrainz logo on album art" + }, + "nameFormatOptions": { + "customStatus": "Use custom status name", + "artistFirst": "Use format 'artist - song'", + "songFirst": "Use format 'song - artist'", + "artistOnly": "Use artist name only", + "songOnly": "Use song name only", + "albumName": "Use album name (falls back to custom status text if song has no album)" + }, + "missingArtOptions": { + "listenbrainzLogo": "Use large ListenBrainz logo", + "placeholder": "Use generic placeholder" + }, + "about": { + "title": "About MusicBrainz API", + "description": "The MusicBrainz API does not require an API key, but it does require a meaningful user-agent string. For most, an email address should suffice." + }, + "buttons": { + "profile": "ListenBrainz Profile", + "viewSong": "View Song" + }, + "defaults": { + "statusName": "some music" + } + }, + "loginWithQR": { + "description": "Allows you to login to another device by scanning a login QR code, just like on mobile!", + "settings": { + "scanQr": "Scan a QR code" + }, + "ui": { + "enableAndRestart": "Enable the plugin and restart your client to scan a login QR code", + "scanQrCode": "Scan QR Code" + } + } +} \ No newline at end of file diff --git a/i18n/en-US/vencord.json b/i18n/en-US/vencord.json index e25a596b2..09b1860e8 100644 --- a/i18n/en-US/vencord.json +++ b/i18n/en-US/vencord.json @@ -204,5 +204,1191 @@ }, "tabs": { "settings": "Equicord Settings" + }, + "reviewDB": { + "settings": { + "authorize": "Authorize with ReviewDB", + "notifyReviews": { + "description": "Notify about new reviews on startup" + }, + "showWarning": { + "description": "Display warning to be respectful at the top of the reviews list" + }, + "hideTimestamps": { + "description": "Hide timestamps on reviews" + }, + "hideBlockedUsers": { + "description": "Hide reviews from blocked users" + }, + "manageBlockedUsers": "Manage Blocked Users", + "supportDevelopment": "Support ReviewDB development", + "website": "ReviewDB website", + "supportServer": "ReviewDB Support Server" + }, + "viewReviews": "View Reviews", + "newReviews": "You have new reviews on your profile!", + "appeal": "Appeal", + "ok": "Ok", + "areYouSure": "Are you sure?", + "confirmDelete": "Do you really want to delete this review?", + "delete": "Delete", + "nevermind": "Nevermind", + "mustBeLoggedInDelete": "You must be logged in to delete reviews.", + "confirmReport": "Do you really want to report this review?", + "report": "Report", + "mustBeLoggedInReport": "You must be logged in to report reviews.", + "confirmBlock": "Do you really want to block this user? They will be unable to leave further reviews on your profile. You can unblock users in the plugin settings.", + "block": "Block", + "mustBeLoggedInBlock": "You must be logged in to block users.", + "system": "System", + "blockedUser": "You have blocked this user", + "readMore": "Read more", + "unblockUser": "Unblock user", + "failedToFetchBlocks": "Failed to fetch blocks: {error}", + "noBlockedUsers": "No blocked users.", + "blockedUsers": "Blocked Users", + "notLoggedIn": "You are not logged into ReviewDB!" + }, + "translate": { + "autoTranslateEnabled": { + "title": "Equicord Auto-Translate Enabled", + "body": "You just enabled Auto Translate! Any message <0>will automatically be translated before being sent." + }, + "disableAutoTranslate": "Disable Auto-Translate", + "gotIt": "Got it", + "dontShowAgain": "Don't show again", + "openTranslateModal": "Open Translate Modal", + "autoTranslateEnabledLabel": "Auto Translate Enabled", + "translate": "Translate", + "selectLanguage": "Select a language", + "autoTranslate": "Auto Translate", + "modalTitle": "Translate" + }, + "voiceMessages": { + "send": "Send Voice Message", + "missingPermissions": "(Missing Permissions)", + "recordModal": "Record Voice Message", + "uploadFile": "Upload File", + "preview": "Preview", + "failedToParse": "Failed to parse selected audio file: {error}", + "iosWarning": "Voice Messages have to be OggOpus to be playable on iOS. This file is <0>{type} so it will not be playable on iOS.", + "iosFix": "To fix it, first convert it to OggOpus, for example using the <0>convertio web converter", + "sending": "Now sending voice message... Please be patient", + "failedToUpload": "Failed to upload voice message", + "noiseSuppression": "Noise Suppression", + "echoCancellation": "Echo Cancellation" + }, + "showHiddenChannels": { + "hiddenChannel": "This is a hidden {type} channel", + "lockedChannel": "This is a locked {type} channel", + "nsfw": "NSFW", + "cannotSeeMessages": "You can not see the {type} of this channel.", + "seeGuidelines": " However you may see its guidelines:", + "lastMessageCreated": "Last {type} created:", + "lastMessagePin": "Last message pin:", + "slowmode": "Slowmode: {duration}", + "threadSlowmode": "Default thread slowmode: {duration}", + "bitrate": "Bitrate: {bitrate} bits", + "region": "Region: {region}", + "regionAutomatic": "Automatic", + "videoQualityMode": "Video quality mode: {mode}", + "archiveDuration": "Default inactivity duration before archiving {type}: {duration}", + "defaultLayout": "Default layout: {layout}", + "defaultSortOrder": "Default sort order: {order}", + "defaultReactionEmoji": "Default reaction emoji:", + "requireTag": "Posts on this forum require a tag to be set.", + "availableTags": "Available tags:", + "permissionDetails": "Permission Details", + "allowedUsersAndRoles": "Allowed users and roles:", + "hideAllowedUsersAndRoles": "Hide Allowed Users and Roles", + "viewAllowedUsersAndRoles": "View Allowed Users and Roles", + "channelTypes": { + "text": "text", + "announcement": "announcement", + "forum": "forum", + "voice": "voice", + "stage": "stage", + "messages": "messages", + "posts": "posts" + }, + "sortOrders": { + "latestActivity": "Latest activity", + "creationDate": "Creation date" + }, + "forumLayouts": { + "notSet": "Not set", + "listView": "List view", + "gridView": "Gallery view" + }, + "videoQuality": { + "automatic": "Automatic", + "720p": "720p" + } + }, + "messageLogger": { + "toggleDeletedHighlight": "Toggle Deleted Highlight", + "enableDiffView": "Enable Diff View", + "disableDiffView": "Disable Diff View", + "removeMessageHistory": "Remove Message History", + "removeMessageTemporary": "Remove Message (Temporary)", + "clearMessageLog": "Clear Message Log", + "settings": { + "deleteStyle": "The style of deleted messages", + "deleteStyleRedText": "Red text", + "deleteStyleRedOverlay": "Red overlay", + "logDeletes": "Whether to log deleted messages", + "collapseDeleted": "Whether to collapse deleted messages, similar to blocked messages", + "logEdits": "Whether to log edited messages", + "inlineEdits": "Whether to display edit history as part of message content", + "ignoreBots": "Whether to ignore messages by bots", + "ignoreSelf": "Whether to ignore messages by yourself", + "ignoreUsers": "Comma-separated list of user IDs to ignore", + "ignoreChannels": "Comma-separated list of channel IDs to ignore", + "ignoreGuilds": "Comma-separated list of guild IDs to ignore", + "showEditDiffs": "Show visual differences between edited message versions", + "separatedDiffs": "Separate addition and removals in diffs for a more readable differential" + }, + "deletedMessages_zero": "No deleted messages", + "deletedMessages_one": "{count} deleted message", + "deletedMessages_other": "{count} deleted messages", + "editHistory": "Message Edit History", + "notLoggedTooltip": "This edit state was not logged so it can't be displayed." + }, + "clientTheme": { + "themeColor": "Theme Color", + "themeColorDescription": "Add a color to your Discord client theme", + "themeWontLookGood": "Your theme won't look good!", + "contrastWarning": "Selected color won't contrast well with text", + "nitroNotSupported": "Nitro themes aren't supported", + "switchToMode": "Switch to {mode} mode", + "disableNitroTheme": "Disable Nitro Theme", + "resetThemeColor": "Reset Theme Color" + }, + "textReplace": { + "usingString": "Using String", + "usingRegex": "Using Regex", + "find": "Find", + "replace": "Replace", + "onlyIfIncludes": "Only if includes", + "scope.myMessages": "Apply to your messages (visible to everyone)", + "scope.othersMessages": "Apply to others' messages (only visible to you)", + "scope.allMessages": "Apply to all messages", + "testRules": "Test Rules", + "typeMessage": "Type a message", + "messageWithRules": "Message with rules applied" + }, + "expressionCloner": { + "cloneEmoji": "Clone Emoji", + "cloneSticker": "Clone Sticker", + "customName": "Custom Name", + "nameValidation": "Name must be between 2 and 32 characters", + "cloneTo": "Clone to {guild}", + "clonedSuccess": "Successfully cloned {name} to {guild}!", + "failedToClone": "Failed to clone: {error}", + "somethingWentWrong": "Something went wrong (check console!)" + }, + "fakeProfileThemes": { + "usage": "Usage", + "instructions": "Set your profile colors using the color pickers below. The colors will be encoded into your profile's 'About Me' section.", + "colorPickers": "Color pickers", + "primary": "Primary", + "accent": "Accent", + "copy3y3": "Copy 3y3", + "preview": "Preview", + "nitroColors": "Nitro colors", + "fakeColors": "Fake colors" + }, + "customRPC": { + "validation": { + "required": "This field is required.", + "maxLength": "Must be not longer than {length} characters.", + "discordId": "Must be a valid Discord ID.", + "streamingLink": "Streaming link must be a valid URL.", + "streamingLinkLength": "Streaming link must be not longer than 512 characters.", + "number": "Must be a number.", + "positiveNumber": "Must be a positive number.", + "url": "Must be a valid URL.", + "discordLink": "Don't use a Discord link. Use an Imgur image link instead.", + "imgurDirect": "Imgur link must be a direct link to the image (e.g. https://i.imgur.com/...). Right click the image and click 'Copy image address'", + "tenorDirect": "Tenor link must be a direct link to the image (e.g. https://media.tenor.com/...). Right click the GIF and click 'Copy image address'" + }, + "placeholder": { + "enterValue": "Enter a value", + "selectOption": "Select an option" + }, + "activityType": "Activity Type", + "activityTypes": { + "playing": "Playing", + "streaming": "Streaming", + "listening": "Listening", + "watching": "Watching", + "competing": "Competing" + }, + "appId": "Application ID", + "appName": "Application Name", + "detailLine1": "Detail (line 1)", + "detailUrl": "Detail URL", + "stateLine2": "State (line 2)", + "stateUrl": "State URL", + "streamLink": "Stream Link (Twitch or YouTube, only if activity type is Streaming)", + "partySize": "Party Size", + "partyMaxSize": "Maximum Party Size", + "largeImageUrl": "Large Image URL/Key", + "largeImageText": "Large Image Text", + "largeImageClickUrl": "Large Image clickable URL", + "smallImageUrl": "Small Image URL/Key", + "smallImageText": "Small Image Text", + "smallImageClickUrl": "Small Image clickable URL", + "button1Text": "Button1 Text", + "button1Url": "Button1 URL", + "button2Text": "Button2 Text", + "button2Url": "Button2 URL", + "timestampMode": "Timestamp Mode", + "timestampModes": { + "none": "None", + "sinceOpen": "since discord open", + "currentTime": "Same as your current time (not reset after 24h)", + "custom": "Custom" + }, + "startTimestamp": "Start Timestamp (in milliseconds)", + "endTimestamp": "End Timestamp (in milliseconds)", + "notice": { + "title": "Notice", + "body": "Activity Sharing isn't enabled, people won't be able to see your custom rich presence!", + "enable": "Enable" + }, + "instructions": { + "devPortal": "Go to the <0>Discord Developer Portal to create an application and get the application ID.", + "uploadImages": "Upload images in the Rich Presence tab to get the image keys.", + "imgur": "If you want to use an image link, download your image and reupload the image to <0>Imgur and get the image link by right-clicking the image and selecting \"Copy image address\".", + "buttons": "You can't see your own buttons on your profile, but everyone else can see it fine.", + "unicode": "Some weird unicode text (\"fonts\" 𝖑𝖎𝖐𝖊 𝖙𝖍𝖎𝖘) may cause the rich presence to not show up, try using normal letters instead." + } + }, + "betterSessions": { + "settings": { + "backgroundCheck": "Check for new sessions in the background, and display notifications when they are detected", + "checkInterval": "How often to check for new sessions in the background (if enabled), in minutes" + }, + "newBadge": "NEW", + "newSession": "New session:", + "rename": "Rename", + "renameModal": { + "title": "Rename", + "newDeviceName": "New device name", + "resetName": "Reset Name", + "save": "Save" + } + }, + "betterSettings": { + "settings": { + "disableFade": "Disable the crossfade animation", + "organizeMenu": "Organizes the settings cog context menu into categories", + "eagerLoad": "Removes the loading delay when opening the menu for the first time" + } + }, + "memberCount": { + "settings": { + "toolTip": "Show member count on the server tooltip", + "memberList": "Show member count in the member list", + "voiceActivity": "Show voice activity with member count in the member list" + } + }, + "betterFolders": { + "settings": { + "sidebar": "Display servers from folder on dedicated sidebar", + "sidebarAnim": "Animate opening the folder sidebar", + "closeAllFolders": "Close all folders when selecting a server not in a folder", + "closeAllHomeButton": "Close all folders when clicking on the home button", + "closeOthers": "Close other folders when opening a folder", + "closeServerFolder": "Close folder when selecting a server in that folder", + "forceOpen": "Force a folder to open when switching to a server of that folder", + "keepIcons": "Keep showing guild icons in the primary guild bar folder when it's open in the BetterFolders sidebar", + "showFolderIcon": "Show the folder icon above the folder guilds in the BetterFolders sidebar", + "folderIconNever": "Never", + "folderIconAlways": "Always", + "folderIconMultipleExpanded": "When more than one folder is expanded" + } + }, + "arRPC": { + "settingsAbout": { + "title": "How to use arRPC", + "description": "Follow the instructions in the GitHub repo to get the server running, and then enable the plugin." + }, + "connectionFailed": "Failed to connect to arRPC, is it running?", + "retry": "Retry", + "connected": "Connected to arRPC" + }, + "vcNarrator": { + "description": "Announces when users join, leave, or move voice channels via narrator", + "noVoices": "No narrator voices found. ", + "linuxVoicesHelp": "Install speech-dispatcher or espeak and run Discord with the --enable-speech-dispatcher flag", + "osVoicesHelp": "Try installing some in the Narrator settings of your Operating System", + "noEnglishVoices": "You don't have any English voices installed, so the narrator might sound weird", + "customiseMessages": "You can customise the spoken messages below. You can disable specific messages by setting them to nothing", + "placeholdersHelp": "The special placeholders <0>{{USER}}, <1>{{DISPLAY_NAME}}, <2>{{NICKNAME}} and <3>{{CHANNEL}} will be replaced with the user's name (nothing if it's yourself), the user's display name, the user's nickname on current server and the channel's name respectively", + "playExampleSounds": "Play Example Sounds", + "speechSynthesisNotSupported": "SpeechSynthesis not supported or no Narrator voices found. Thus, this plugin will not work. Check my Settings for more info", + "settings": { + "volume": "Narrator Volume", + "speed": "Narrator Speed", + "sayOwnName": "Say own name", + "latinOnly": "Strip non latin characters from names before saying them", + "joinMessage": "Join Message", + "leaveMessage": "Leave Message", + "moveMessage": "Move Message", + "muteMessage": "Mute Message (only self for now)", + "unmuteMessage": "Unmute Message (only self for now)", + "deafenMessage": "Deafen Message (only self for now)", + "undeafenMessage": "Undeafen Message (only self for now)" + }, + "defaults": { + "join": "{{USER}} joined", + "leave": "{{USER}} left", + "move": "{{USER}} moved to {{CHANNEL}}", + "mute": "{{USER}} muted", + "unmute": "{{USER}} unmuted", + "deafen": "{{USER}} deafened", + "undeafen": "{{USER}} undeafened" + } + }, + "viewIcons": { + "description": "Makes avatars and banners in user profiles clickable, adds View Icon/Banner entries in the user, server and group channel context menu.", + "settings": { + "formatDescription": "Choose the image format to use for non animated images. Animated images will always use .gif", + "imgSizeDescription": "The image size to use" + }, + "viewAvatar": "View Avatar", + "viewServerAvatar": "View Server Avatar", + "viewIcon": "View Icon", + "viewBanner": "View Banner" + }, + "viewRaw": { + "description": "Copy and view the raw content/data of any message, channel or guild", + "viewRaw": "View Raw", + "content": "Content", + "data": "Data", + "dataCopied": "{type} data copied to clipboard!", + "copyJson": "Copy {type} JSON", + "copyRawContent": "Copy Raw Content", + "contentCopied": "Content copied to clipboard!", + "settings": { + "clickMethodDescription": "Change the button to view the raw content/data of any message.", + "leftClick": "Left Click to view the raw content.", + "rightClick": "Right click to view the raw content." + }, + "copyRawLeftViewRawRight": "Copy Raw (Left Click) / View Raw (Right Click)", + "viewRawLeftCopyRawRight": "View Raw (Left Click) / Copy Raw (Right Click)" + }, + "decor": { + "description": "Create and use your own custom avatar decorations, or pick your favorite from the presets.", + "enableAndRestart": "Enable Decor and restart your client to change your avatar decoration.", + "accessFromProfiles": "You can also access Decor decorations from the {link} page.", + "profilesLink": "Profiles", + "title": "Decor", + "changeDecoration": "Change Decoration", + "removeDecoration": "Remove Decoration" + }, + "quickMention": { + "description": "Adds a quick mention button to the message actions bar", + "label": "Quick Mention" + }, + "anonymiseFileNames": { + "description": "Anonymise uploaded file names", + "settings": { + "anonymiseByDefault": "Whether to anonymise file names by default", + "spoilerMessages": "Spoiler messages", + "method": "Anonymising method", + "randomisedLength": "Random characters length", + "consistent": "Consistent filename" + }, + "methods": { + "random": "Random Characters", + "consistent": "Consistent", + "timestamp": "Timestamp" + }, + "usingAnonymous": "Using anonymous file name", + "usingNormal": "Using normal file name", + "commands": { + "spoiler": { + "name": "Spoiler", + "description": "Toggle your spoiler", + "optionName": "value", + "optionDescription": "Toggle your Spoiler (default is toggle)", + "enabled": "Spoiler enabled!", + "disabled": "Spoiler disabled!" + } + } + }, + "permissionsViewer": { + "settings": { + "permissionsSortOrder": "The sort method used for defining which role grants a user a certain permission", + "highestRole": "Highest Role", + "lowestRole": "Lowest Role" + }, + "permissions": "Permissions", + "viewPermissions": "View Permissions", + "permissionsTitle": "{header} Permissions", + "noPermissions": "No permissions to display!", + "unknownRole": "Unknown Role", + "unknownUser": "Unknown User", + "owner": "owner", + "roleOptions": "Role Options", + "userOptions": "User Options" + }, + "pinDms": { + "settings": { + "pinOrder": "Which order should pinned DMs be displayed in?", + "mostRecentMessage": "Most recent message", + "customOrder": "Custom (right click channels to reorder)", + "canCollapseDmSection": "Allow uncategorised DMs section to be collapsable", + "dmSectionCollapsed": "Collapse DM section" + }, + "editCategory": "Edit Category", + "moveUp": "Move Up", + "moveDown": "Move Down", + "deleteCategory": "Delete Category", + "newCategory": "New Category", + "editCategoryTitle": "Edit Category", + "name": "Name", + "color": "Color", + "save": "Save", + "create": "Create", + "pinCategory": "Pin Category {index}", + "pinDms": "Pin DMs", + "addCategory": "Add Category", + "unpinDm": "Unpin DM" + }, + "imageZoom": { + "settings": { + "saveZoomValues": "Whether to save zoom and lens size values", + "invertScroll": "Invert scroll", + "nearestNeighbour": "Use Nearest Neighbour Interpolation when scaling images", + "square": "Make the lens square", + "zoom": "Zoom of the lens", + "size": "Radius / Size of the lens", + "zoomSpeed": "How fast the zoom / lens size changes" + }, + "squareLens": "Square Lens", + "nearestNeighbour": "Nearest Neighbour", + "zoom": "Zoom", + "lensSize": "Lens Size", + "zoomSpeed": "Zoom Speed" + }, + "relationshipNotifier": { + "settings": { + "notices": "Also show a notice at the top of your screen when removed (use this if you don't want to miss any notifications).", + "offlineRemovals": "Notify you when starting discord if you were removed while offline.", + "friends": "Notify when a friend removes you", + "friendRequestCancels": "Notify when a friend request is cancelled", + "servers": "Notify when removed from a server", + "groups": "Notify when removed from a group chat" + }, + "friendRemoved": "{username} removed you as a friend.", + "friendRequestRemoved": "A friend request from {username} has been removed.", + "serverRemoved": "You were removed from the server {name}.", + "groupRemoved": "You were removed from the group {name}." + }, + "messageLatency": { + "settings": { + "latency": "Threshold in seconds for latency indicator", + "detectDiscordKotlin": "Detect old Discord Android clients", + "showMillis": "Show milliseconds", + "ignoreSelf": "Don't add indicator to your own messages" + }, + "timeUnits": { + "day": "day", + "days": "days", + "hour": "hour", + "hours": "hours", + "minute": "minute", + "minutes": "minutes", + "second": "second", + "seconds": "seconds", + "millisecond": "millisecond", + "milliseconds": "milliseconds" + }, + "oldDiscordAndroid": "User is suspected to be on an old Discord Android client", + "clockAhead": "This user's clock is {delta} ahead.", + "messageDelayed": "This message was sent with a delay of {delta}.", + "delayedMessage": "Delayed Message", + "oldAndroidClient": "Old Discord Android client" + }, + "whoReacted": { + "settings": { + "avatarClick": "Toggle clicking avatars in reactions" + } + }, + "userVoiceShow": { + "description": "Shows an indicator when a user is in a Voice Channel", + "settings": { + "showInUserProfileModal": "Show a user's Voice Channel indicator in their profile next to the name", + "showInMemberList": "Show a user's Voice Channel indicator in the member and DMs list", + "showInMessages": "Show a user's Voice Channel indicator in messages" + }, + "inVoiceChat": "In Voice Chat", + "cannotJoinChannel": "You cannot join the user's Voice Channel" + }, + "callTimer": { + "description": "Add call timers for all users in voice channels and in the connection status.", + "settings": { + "format": "Compact or human readable format:", + "allCallTimers": "Add call timer to all users in a server voice channel", + "showWithoutHover": "Always show the timer without needing to hover", + "showRoleColor": "Show the user's role color (if this plugin is enabled)", + "trackSelf": "Also track yourself", + "showSeconds": "Show seconds in the timer", + "watchLargeGuilds": "Track users in large guilds. This may cause lag if you're in a lot of large guilds with active voice users. Tested with up to 2000 active voice users with no issues." + } + }, + "fakeNitro": { + "description": "Allows you to send fake emojis/stickers, use nitro themes, and stream in nitro quality", + "settings": { + "enableEmojiBypass": "Allows sending fake emojis (also bypasses missing permission to use custom emojis)", + "emojiSize": "Size of the emojis when sending", + "transformEmojis": "Whether to transform fake emojis into real ones", + "enableStickerBypass": "Allows sending fake stickers (also bypasses missing permission to use stickers)", + "stickerSize": "Size of the stickers when sending", + "transformStickers": "Whether to transform fake stickers into real ones", + "transformCompoundSentence": "Whether to transform fake stickers and emojis in compound sentences (sentences with more content than just the fake emoji or sticker link)", + "enableStreamQualityBypass": "Allow streaming in nitro quality", + "useStickerHyperLinks": "Whether to use hyperlinks when sending fake stickers", + "useEmojiHyperLinks": "Whether to use hyperlinks when sending fake emojis", + "hyperLinkText": "What text the hyperlink should use. {{NAME}} will be replaced with the emoji/sticker name.", + "disableEmbedPermissionCheck": "Whether to disable the embed permission check when sending fake emojis and stickers" + }, + "stickerNotice": "This is a FakeNitro sticker and renders like a real sticker only for you. Appears as a link to non-plugin users.", + "emojiNotice": "This is a FakeNitro emoji and renders like a real emoji only for you. Appears as a link to non-plugin users.", + "holdOn": "Hold on!", + "noEmbedPerms": { + "body1": "You are trying to send/edit a message that contains a FakeNitro emoji or sticker,", + "body2": "however you do not have permissions to embed links in the current channel.", + "body3": "Are you sure you want to send this message? Your FakeNitro items will appear as a link only.", + "disableNotice": "You can disable this notice in the plugin settings." + }, + "noAttachmentPerms": { + "body": "You cannot send this message because it contains an animated FakeNitro sticker, and you do not have permissions to attach files in the current channel. Please remove the sticker to proceed." + }, + "sendAnyway": "Send Anyway", + "doNotShowAgain": "Do not show again" + }, + "serverListIndicators": { + "description": "Add online friend count or server count in the server list", + "settings": { + "mode": "Mode", + "modeOnlyFriends": "Only online friend count", + "modeOnlyServers": "Only server count", + "modeBoth": "Both server and online friend counts", + "useCompact": "Makes the indicator appear with only text" + }, + "friends": "Friends", + "servers": "Servers", + "tooltipFriends": "{count} Friends", + "tooltipServers": "{count} Servers", + "tooltipBoth": "{friends} Friends, {servers} Servers" + }, + "friendsSince": { + "description": "Shows when you became friends with someone in the user popout", + "heading": "Friends Since" + }, + "silentMessageToggle": { + "description": "Adds a button to the chat bar to toggle sending a silent message.", + "settings": { + "persistState": "How to persist the silent message toggle state", + "persistNone": "Don't persist (reset on channel change)", + "persistChannels": "Persist between channels", + "persistRestarts": "Persist between channels and restarts", + "autoDisable": "Automatically disable the silent message toggle again after sending one" + }, + "disableSilentMessage": "Disable Silent Message", + "enableSilentMessage": "Enable Silent Message" + }, + "sendTimestamps": { + "description": "Send timestamps easily via chat box button & text shortcuts. Read the extended description!", + "settings": { + "replaceMessageContents": "Replace timestamps in message contents" + }, + "timestampPicker": "Timestamp Picker", + "timestampFormat": "Timestamp Format", + "preview": "Preview", + "insert": "Insert", + "insertTimestamp": "Insert Timestamp", + "extendedDescription": { + "quickSend": "To quickly send time-only timestamps, include timestamps formatted as `HH:MM` (including the backticks!) in your message", + "seeBelow": "See below for examples. If you need anything more specific, use the Date button in the chat bar!", + "examples": "Examples:" + } + }, + "gameActivityToggle": { + "description": "Adds a button next to the mic and deafen button to toggle game activity.", + "settings": { + "oldIcon": "Use the old icon style before Discord icon redesign", + "location": "Where to show the game activity toggle button", + "locationPanel": "Next to Mute/Deafen", + "locationToolbox": "Equicord Toolbox" + }, + "disableGameActivity": "Disable Game Activity", + "enableGameActivity": "Enable Game Activity" + }, + "lastfmRichPresence": { + "description": "Little plugin for Last.fm rich presence", + "settings": { + "apiKey": "Custom Last.fm API key. Not required but highly recommended to avoid rate limiting with our shared key", + "username": "Last.fm username", + "shareUsername": "Show link to Last.fm profile", + "clickableLinks": "Make track, artist and album names clickable links", + "hideWithSpotify": "Hide Last.fm presence if spotify is running", + "hideWithActivity": "Hide Last.fm presence if you have any other presence", + "statusName": "Custom status text", + "statusDisplayType": "Show the track / artist name in the member list", + "nameFormat": "Show name of song and artist in status name", + "useListeningStatus": "Show \"Listening to\" status instead of \"Playing\"", + "missingArt": "When album or album art is missing", + "showLastFmLogo": "Show the Last.fm logo by the album cover", + "alwaysHideArt": "Disable downloading album art" + }, + "statusDisplayType": { + "off": "Don't show (shows generic listening message)", + "artist": "Show artist name", + "track": "Show track name" + }, + "nameFormat": { + "statusName": "Use custom status name", + "artistFirst": "Use format 'artist - song'", + "songFirst": "Use format 'song - artist'", + "artistOnly": "Use artist name only", + "songOnly": "Use song name only", + "albumName": "Use album name (falls back to custom status text if song has no album)" + }, + "missingArt": { + "lastfmLogo": "Use large Last.fm logo", + "placeholder": "Use generic placeholder" + }, + "howToCreateApiKey": "How to create an API key", + "apiKeyInstructions": "Set <0>Application name and <1>Application description to anything and leave the rest blank.", + "createApiKey": "Create API Key", + "lastfmProfile": "Last.fm Profile" + }, + "experiments": { + "description": "Enable Access to Experiments & other dev-only features in Discord!", + "settings": { + "toolbarDevMenu": "Change the Help (?) toolbar button (top right in chat) to Discord's developer menu" + }, + "moreInfo": "More Information", + "devToolsInfo": "You can open Discord's DevTools via {keyboardCombo}", + "holdOn": "Hold on!!", + "warning1": "Experiments are unreleased Discord features. They might not work, or even break your client or get your account disabled.", + "warning2": "Only use experiments if you know what you're doing. Equicord is not responsible for any damage caused by enabling experiments. If you don't know what an experiment does, ignore it. Do not ask us what experiments do either, we probably don't know.", + "warning3": "No, you cannot use server-side features like checking the \"Send to Client\" box." + }, + "typingTweaks": { + "description": "Show avatars and role colours in the typing indicator", + "settings": { + "showAvatars": "Show avatars in the typing indicator", + "showRoleColors": "Show role colors in the typing indicator", + "alternativeFormatting": "Show a more useful message when several users are typing", + "amITyping": "Shows you if other people can see you typing" + }, + "andOthersTyping": "and {count} others are typing..." + }, + "biggerStreamPreview": { + "name": "BiggerStreamPreview", + "description": "This plugin allows you to enlarge stream previews", + "viewStreamPreview": "View Stream Preview" + }, + "betterRoleContext": { + "name": "BetterRoleContext", + "description": "Adds options to copy role color / edit role / view role icon when right clicking roles in the user profile", + "settings": { + "roleIconFileFormat": "File format to use when viewing role icons" + }, + "copyRoleColor": "Copy Role Color", + "editRole": "Edit Role", + "viewRoleIcon": "View Role Icon" + }, + "readAllNotificationsButton": { + "name": "ReadAllNotificationsButton", + "description": "Read all server notifications with a single button click!", + "readAll": "Read All" + }, + "previewMessage": { + "name": "PreviewMessage", + "description": "Lets you preview your message before sending it.", + "previewMessage": "Preview Message" + }, + "pauseInvitesForever": { + "name": "PauseInvitesForever", + "description": "Brings back the option to pause invites indefinitely that stupid Discord removed.", + "pauseIndefinitely": "Pause Indefinitely." + }, + "overrideForumDefaults": { + "name": "OverrideForumDefaults", + "description": "Allows you to override default forum layout/sort order. you can still change it on a per-channel basis", + "settings": { + "defaultLayout": "Which layout to use as default", + "defaultSortOrder": "Which sort order to use as default" + }, + "layouts": { + "list": "List", + "gallery": "Gallery" + }, + "sortOrders": { + "recentlyActive": "Recently Active", + "datePosted": "Date Posted" + } + }, + "fixImagesQuality": { + "name": "FixImagesQuality", + "description": "Improves quality of images by loading them at their original resolution", + "settings": { + "originalImagesInChat": "Also load the original image in Chat. WARNING: Read the caveats above" + }, + "defaultBehavior": "The default behavior is the following:", + "inChatOptimised": "In chat, optimised but full resolution images will be loaded.", + "inModalOriginal": "In the image modal, the original image will be loaded.", + "enableOriginalCaveats": "You can also enable original image in chat, but beware of the following caveats:", + "animatedImagesAlways": "Animated images (GIF, WebP, etc.) in chat will always animate, regardless of if the App is focused.", + "mayCauseLag": "May cause lag." + }, + "favGifSearch": { + "name": "FavoriteGifSearch", + "description": "Adds a search bar to favorite gifs.", + "settings": { + "searchOption": "The part of the url you want to search" + }, + "searchOptions": { + "entireUrl": "Entire Url", + "pathOnly": "Path Only (/somegif.gif)", + "hostAndPath": "Host & Path (tenor.com somgif.gif)" + }, + "searchPlaceholder": "Search Favorite Gifs" + }, + "consoleJanitor": { + "name": "ConsoleJanitor", + "description": "Disables annoying console messages/errors", + "settings": { + "disableLoggers": "Disables Discords loggers", + "disableSpotifyLogger": "Disable the Spotify logger, which leaks account information and access token", + "whitelistedLoggers": "Semi colon separated list of loggers to allow even if others are hidden" + }, + "filterList": "Filter List", + "alwaysAllowLoggers": "Always allow loggers of these types" + }, + "appleMusicRichPresence": { + "name": "AppleMusicRichPresence", + "description": "Discord rich presence for your Apple Music!", + "settings": { + "activityType": "Which type of activity", + "statusDisplayType": "Show the track / artist name in the member list", + "refreshInterval": "The interval between activity refreshes (seconds)", + "enableTimestamps": "Whether or not to enable timestamps", + "enableButtons": "Whether or not to enable buttons", + "nameString": "Activity name format string", + "detailsString": "Activity details format string", + "stateString": "Activity state format string", + "largeImageType": "Activity assets large image type", + "largeTextString": "Activity assets large text format string", + "smallImageType": "Activity assets small image type", + "smallTextString": "Activity assets small text format string" + }, + "activityTypes": { + "playing": "Playing", + "listening": "Listening" + }, + "statusDisplayTypes": { + "off": "Don't show (shows generic listening message)", + "artist": "Show artist name", + "track": "Show track name" + }, + "assetImageTypes": { + "album": "Album artwork", + "artist": "Artist artwork", + "disabled": "Disabled" + }, + "buttons": { + "listenOnAppleMusic": "Listen on Apple Music", + "viewOnSongLink": "View on SongLink" + }, + "defaultName": "Apple Music", + "defaultDetails": "{name}", + "defaultState": "{artist} · {album}", + "defaultLargeText": "{album}", + "defaultSmallText": "{artist}", + "settingsAbout": { + "intro": "For the customizable activity format strings, you can use several special strings to include track data in activities!", + "namePlaceholder": "{name} is replaced with the track name", + "artistPlaceholder": "{artist} is replaced with the artist(s)' name(s)", + "albumPlaceholder": "{album} is replaced with the album name." + } + }, + "reverseImageSearch": { + "name": "ReverseImageSearch", + "description": "Adds ImageSearch to image context menus", + "searchImage": "Search Image", + "all": "All" + }, + "seeSummaries": { + "name": "Summaries", + "description": "Enables Discord's experimental Summaries feature on every server, displaying AI generated summaries of conversations", + "settings": { + "summaryExpiryThresholdDays": "The time in days before a summary is removed. Note that only up to 50 summaries are kept per channel" + } + }, + "greetStickerPicker": { + "description": "Allows you to use any greet sticker instead of only the random one by right-clicking the 'Wave to say hi!' button", + "greetModeLabel": "Greet (you can only greet 3 times)", + "normalMessageLabel": "Normal Message (you can greet spam)", + "greetModeDescription": "Choose the greet mode", + "ariaLabel": "Greet Sticker Picker", + "greetMode": "Greet Mode", + "greetStickers": "Greet Stickers", + "unholyMultiGreet": "Unholy Multi-Greet", + "sendGreets": "Send Greets" + }, + "accountPanelServerProfile": { + "description": "Right click your account panel in the bottom left to view your profile in the current server", + "viewAccountProfile": "View Account Profile", + "viewServerProfile": "View Server Profile", + "prioritizeServerProfile": "Prioritize Server Profile", + "prioritizeServerProfileDescription": "Prioritize Server Profile when left clicking your account panel" + }, + "xsOverlay": { + "description": "Forwards discord notifications to XSOverlay, for easy viewing in VR", + "webSocketPort": "Websocket port", + "preferUDPDescription": "Enable if you use an older build of XSOverlay unable to connect through websockets. This setting is ignored on web.", + "botNotifications": "Allow bot notifications", + "serverNotifications": "Allow server notifications", + "dmNotifications": "Allow Direct Message notifications", + "groupDmNotifications": "Allow Group DM notifications", + "callNotifications": "Allow call notifications", + "pingColor": "User mention color", + "channelPingColor": "Channel mention color", + "soundPath": "Notification sound (default/warning/error)", + "timeout": "Notification duration (secs)", + "lengthBasedTimeout": "Extend duration with message length", + "opacity": "Notif opacity", + "volume": "Volume", + "incomingCall": "Incoming call", + "isCallingYou": "is calling you...", + "reply": "reply", + "embed": "embed", + "sentEmbeds": "sent message embed(s)", + "sticker": "sticker", + "sentSticker": "sent a sticker", + "image": "image", + "attachment": "attachment", + "testNotification": "This is a test notification! explode", + "helloFromVendor": "Hello from Vendor!", + "sendTestNotification": "Send test notification" + }, + "unsuppressEmbeds": { + "description": "Allows you to unsuppress embeds in messages", + "unsuppressEmbeds": "Unsuppress Embeds", + "suppressEmbeds": "Suppress Embeds" + }, + "showTimeoutDuration": { + "description": "Shows how much longer a user's timeout will last, either in the timeout icon tooltip or next to it", + "displayStyleDescription": "How to display the timeout duration", + "inTooltip": "In the Tooltip", + "nextToIcon": "Next to the timeout icon", + "timeoutRemaining": "timeout remaining" + }, + "copyFileContents": { + "description": "Adds a button to text file attachments to copy their contents", + "copied": "Copied!", + "fileTooLarge": "File too large to copy", + "copyFileContents": "Copy File Contents" + }, + "dearrow": { + "description": "Makes YouTube embed titles and thumbnails less sensationalist, powered by Dearrow", + "dearrowedClickRestore": "This embed has been dearrowed, click to restore", + "clickToDearrow": "Click to dearrow", + "hideButton": "Hides the Dearrow button from YouTube embeds", + "replaceElementsDescription": "Choose which elements of the embed will be replaced", + "everything": "Everything (Titles & Thumbnails)", + "titles": "Titles", + "thumbnails": "Thumbnails", + "dearrowByDefault": "Dearrow videos automatically" + }, + "copyUserURLs": { + "description": "Adds a 'Copy User URL' option to the user context menu.", + "copyUserURL": "Copy User URL" + }, + "copyStickerLinks": { + "description": "Adds the ability to copy & open Sticker links", + "copyLink": "Copy Link", + "linkCopied": "Link copied!", + "openLink": "Open Link" + }, + "copyEmojiMarkdown": { + "description": "Allows you to copy emojis as formatted string (<:blobcatcozy:1026533070955872337>)", + "copyUnicodeDescription": "Copy the raw unicode character instead of :name: for default emojis (👽)", + "copyEmojiMarkdown": "Copy Emoji Markdown", + "success": "Success! Copied emoji markdown." + }, + "voiceDownload": { + "description": "Adds a download to voice messages. (Opens a new browser tab)", + "downloadVoiceMessage": "Download voice message" + }, + "usrbg": { + "description": "Displays user banners from USRBG, allowing anyone to get a banner without Nitro", + "settings": { + "nitroFirst": "Banner to use if both Nitro and USRBG banners are present", + "nitroBanner": "Nitro banner", + "usrbgBanner": "USRBG banner", + "voiceBackground": "Use USRBG banners as voice chat backgrounds" + }, + "getOwnBanner": "Get your own USRBG banner" + }, + "typingIndicator": { + "description": "Adds an indicator if someone is typing on a channel.", + "settings": { + "includeCurrentChannel": "Whether to show the typing indicator for the currently selected channel", + "includeMutedChannels": "Whether to show the typing indicator for muted channels.", + "includeIgnoredUsers": "Whether to show the typing indicator for ignored users.", + "includeBlockedUsers": "Whether to show the typing indicator for blocked users.", + "indicatorMode": "How should the indicator be displayed?", + "avatarsAndDots": "Avatars and animated dots", + "animatedDots": "Animated dots", + "avatars": "Avatars" + } + }, + "sortFriendRequests": { + "description": "Sorts friend requests by date of receipt", + "settings": { + "showDates": "Show dates on friend requests" + }, + "added": "Added" + }, + "showConnections": { + "description": "Show connected accounts in user popouts", + "settings": { + "iconSize": "Icon size (px)", + "iconSpacing": "Icon margin", + "compact": "Compact", + "cozy": "Cozy", + "roomy": "Roomy" + } + }, + "replaceGoogleSearch": { + "description": "Replaces the Google search with different Engine(s)", + "settings": { + "customEngineName": "Name of the custom search engine", + "customEngineURL": "The URL of your Engine", + "replacementEngine": "Replace with a specific search engine instead of adding a menu", + "off": "Off", + "customEngine": "Custom Engine" + }, + "searchWith": "Search with {engine}", + "searchText": "Search Text" + }, + "pictureInPicture": { + "description": "Adds picture in picture to videos (next to the Download button)", + "settings": { + "loop": "Whether to make the PiP video loop or not" + }, + "togglePip": "Toggle Picture in Picture" + }, + "noReplyMention": { + "description": "Disables reply pings by default", + "settings": { + "userList": "List of users to allow or exempt pings for (separated by commas or spaces)", + "roleList": "List of roles to allow or exempt pings for (separated by commas or spaces)", + "shouldPingListed": "Behaviour", + "doNotPingListed": "Do not ping the listed users / roles", + "onlyPingListed": "Only ping the listed users / roles", + "inverseShiftReply": "Invert Discord's shift replying behaviour (enable to make shift reply mention user)" + } + }, + "hideAttachments": { + "description": "Hide attachments and embeds for individual messages via hover button", + "showMedia": "Show Media", + "hideMedia": "Hide Media", + "mediaHidden": "Media Hidden" + }, + "showMeYourName": { + "changeNickname": "Change SMYN Nickname", + "addNickname": "Add SMYN Nickname", + "modalDescription": "Set a custom SMYN nickname for this user. Make use of it by specifying {custom} in the SMYN template settings.", + "nicknameLabel": "SMYN Nickname", + "resetNickname": "Reset SMYN Nickname", + "save": "Save", + "cancel": "Cancel", + "settings": { + "messages": "Display custom name format in messages.", + "replies": "Display custom name format in replies.", + "mentions": "Display custom name format in mentions.", + "memberList": "Display the first available name listed in your custom name format in the member list.", + "profilePopout": "Display the first available name listed in your custom name format in profile popouts.", + "voiceChannels": "Display the first available name listed in your custom name format in voice channels.", + "reactions": "Display the first available name listed in your custom name format in reaction tooltips, and the full name in reaction popouts.", + "discriminators": "Append discriminators to usernames for bots. Discriminators were deprecated for users, but are still used for bots. By default, a bot's username is equivalent to a user's global name, therefore multiple bots can have the same username. Appending discriminators makes them unique again.", + "hideDefaultAtSign": "Hide the default \"@\" symbol before the name in mentions and replies. Only applied if either feature is enabled.", + "truncateAllNamesWithStreamerMode": "Truncate all names, not just usernames, while in Streamer Mode.", + "removeDuplicates": "If any of the names are equivalent, remove them, leaving only the unique names.", + "ignoreFonts": "For the non-primary names, use Discord's default fonts regardless of the user's custom nitro font.", + "ignoreGradients": "For the non-primary names, if the role has a gradient, ignore it in favor of the color set below.", + "animateGradients": "For the non-primary names, if the role has a gradient, animate it. This is disabled by \"Ignore Gradients\" and reduced motion.", + "nameSeparator": "The separator to use between names. The default is a single space.", + "includedNames": "The order to display usernames, display names, nicknames, friend names, and custom names. Use the following placeholders: {user}, {display}, {nick}, {friend}, {custom}. You can provide multiple name options to use as fallbacks if one is unavailable by separating them with commas as such: {custom, friend, nick}. You can have up to three prefixes and three suffixes per name.", + "customNameColor": "The color to use for the custom name you assigned a user if it's not the first displayed. Leave blank for default. Accepts hex(a), rgb(a), or hsl(a) input. Use \"Role\" to follow the user's top role color. Use \"Role+-#\" to adjust the brightness by that percentage (ex: \"Role+15\")", + "friendNameColor": "The color to use for a friend's nickname if it's not the first displayed. Leave blank for default. Accepts hex(a), rgb(a), or hsl(a) input. Use \"Role\" to follow the user's top role color. Use \"Role+-#\" to adjust the brightness by that percentage (ex: \"Role+15\")", + "nicknameColor": "The color to use for the nickname if it's not the first displayed. Leave blank for default. Accepts hex(a), rgb(a), or hsl(a) input. Use \"Role\" to follow the user's top role color. Use \"Role+-#\" to adjust the brightness by that percentage (ex: \"Role+15\")", + "displayNameColor": "The color to use for the display name if it's not the first displayed. Leave blank for default. Accepts hex(a), rgb(a), or hsl(a) input. Use \"Role\" to follow the user's top role color. Use \"Role+-#\" to adjust the brightness by that percentage (ex: \"Role+15\")", + "usernameColor": "The color to use for the username if it's not the first displayed. Leave blank for default. Accepts hex(a), rgb(a), or hsl(a) input. Use \"Role\" to follow the user's top role color. Use \"Role+-#\" to adjust the brightness by that percentage (ex: \"Role+15\")" + } + }, + "silentTyping": { + "typingHidden": "Typing Hidden ({location})", + "typingVisible": "Typing Visible ({location})", + "typingVisibleGlobal": "Typing Visible (Global)", + "settingsUpdated": "Silent typing settings updated.", + "noChanges": "No changes made to silent typing settings.", + "contextMenu": { + "silentTyping": "Silent Typing", + "enabled": "Enabled", + "chatBarIndicators": "Chat Bar Indicators", + "membersListIndicators": "Members List Indicators", + "chatIcon": "Chat Icon", + "defaultHidden": "Default Hidden" + }, + "settings": { + "enabledGlobally": "Toggle functionality of your own typing indicator globally.", + "hideChatBoxTypingIndicators": "Hide other users' typing indicators from above the chat bar.", + "hideMembersListTypingIndicators": "Hide other users' typing indicators from the members list.", + "chatIcon": "Show an icon in the chat bar for modifying the plugin on the go.", + "chatIconLeftClickAction": "What to do when left clicking the chat icon.", + "chatIconMiddleClickAction": "What to do when middle clicking the chat icon.", + "chatIconRightClickAction": "What to do when right clicking the chat icon.", + "chatContextMenu": "Show a dropdown in the chat context menu to modify plugin settings on the go.", + "defaultHidden": "If enabled, the plugin will hide your typing from others in any DMs/channels/guilds not listed in \"Disabled Locations\" below. If disabled, the plugin will show your typing to others for any DMs/channels/guilds not listed in \"Enabled Locations\" below.", + "enabledLocations": "Enable functionality for these IDs. Accepts a comma separated list of DM IDs, channel IDs, and guild IDs. Only used if \"Default Hidden\" is disabled.", + "disabledLocations": "Disable functionality for these IDs. Accepts a comma separated list of DM IDs, channel IDs, and guild IDs. Only used if \"Default Hidden\" is enabled." + }, + "clickActions": { + "toggleTypingGlobally": "Toggle Typing Globally", + "toggleTypingInChannel": "Toggle Typing in Channel", + "toggleTypingInGuild": "Toggle Typing in Guild", + "openPluginSettings": "Open Plugin Settings" + }, + "command": { + "description": "Hide your typing indicator from chat.", + "toggleOption": "Toggle functionality globally, for the channel, or for the guild.", + "toggleGlobal": "Global", + "toggleChannel": "Channel", + "toggleGuild": "Guild", + "chatBarIndicatorsOption": "Hide other users' typing indicators from above the chat bar.", + "membersListIndicatorsOption": "Hide other users' typing indicators from the members list.", + "chatIconOption": "Show an icon in the chat bar for toggling the plugin on the go.", + "chatContextMenuOption": "Show a dropdown in the chat context menu to toggle plugin settings on the go.", + "defaultHiddenOption": "Whether to hide typing in DMs/channels/guilds by default or not." + } + }, + "ignoreActivities": { + "disableActivity": "Disable activity", + "enableActivity": "Enable activity", + "importCustomRPC": { + "description": "Import the application id of the CustomRPC plugin to the filter list", + "button": "Import CustomRPC ID", + "notSet": "CustomRPC application ID is not set.", + "alreadyAdded": "CustomRPC application ID is already added." + }, + "filterList": { + "title": "Filter List", + "description": "Comma separated list of activity IDs to filter (Useful for filtering specific RPC activities and CustomRPC)" + }, + "settings": { + "listMode": "Change the mode of the filter list", + "whitelist": "Whitelist", + "blacklist": "Blacklist", + "ignorePlaying": "Ignore all playing activities (These are usually game and RPC activities)", + "ignoreStreaming": "Ignore all streaming activities", + "ignoreListening": "Ignore all listening activities (These are usually spotify activities)", + "ignoreWatching": "Ignore all watching activities", + "ignoreCompeting": "Ignore all competing activities (These are normally special game activities)" + } + }, + "newGuildSettings": { + "description": "Automatically mute new servers and change various other settings upon joining", + "settings": { + "guild": "Mute Guild automatically", + "messages": "Server Notification Settings", + "allMessages": "All messages", + "onlyMentions": "Only @mentions", + "nothing": "Nothing", + "serverDefault": "Server default", + "everyone": "Suppress @everyone and @here", + "role": "Suppress All Role @mentions", + "highlights": "Suppress Highlights automatically", + "events": "Mute New Events automatically", + "showAllChannels": "Show all channels automatically", + "mobilePush": "Mute Mobile Push Notifications automatically", + "voiceChannels": "Hide names in Voice channels automatically" + }, + "applySettings": "Apply NewGuildSettings" + }, + "platformIndicators": { + "description": "Adds platform indicators (Desktop, Mobile, Web...) to users", + "settings": { + "list": "Show indicators in the member list", + "profiles": "Show indicators in user profiles", + "messages": "Show indicators inside messages", + "colorMobileIndicator": "Whether to make the mobile indicator match the color of the user status.", + "showBots": "Whether to show platform indicators on bots", + "consoleIcon": "What console icon to use" + }, + "platforms": { + "console": "Console", + "desktop": "Desktop", + "mobile": "Mobile", + "web": "Web" + }, + "consoleIcons": { + "equicord": "Equicord", + "suncord": "Suncord", + "vencord": "Vencord" + } + }, + "mutualGroupDMs": { + "description": "Shows mutual group dms in profiles", + "mutualGroups_one": "{count} Mutual Group", + "mutualGroups_other": "{count} Mutual Groups", + "noMutualGroups": "No Mutual Groups", + "noGroupDms": "No group dms in common", + "members_one": "{count} Member", + "members_other": "{count} Members", + "mutualGroupsHeader": "Mutual Groups" + }, + "messageLinkEmbeds": { + "description": "Adds a preview to messages that link another message", + "settings": { + "messageBackgroundColor": "Background color for messages in rich embeds", + "automodEmbeds": "Use automod embeds instead of rich embeds (smaller but less info)", + "listMode": "Whether to use ID list as blacklist or whitelist", + "idList": "Guild/channel/user IDs to blacklist or whitelist (separate with comma)", + "clearMessageCache": "Clear the linked message cache" + }, + "automodOptions": { + "always": "Always use automod embeds", + "prefer": "Prefer automod embeds, but use rich embeds if some content can't be shown", + "never": "Never use automod embeds" + }, + "listModeOptions": { + "blacklist": "Blacklist", + "whitelist": "Whitelist" + }, + "channelLabels": { + "directMessage": "Direct Message", + "groupDM": "Group DM", + "server": "Server" + }, + "noContent": { + "attachments_only_one": "[no content, {count} attachment]", + "attachments_only_other": "[no content, {count} attachments]", + "embeds_only_one": "[no content, {count} embed]", + "embeds_only_other": "[no content, {count} embeds]", + "both_one": "[no content, {attachments} attachment and {embeds} embed]", + "both_other": "[no content, {attachments} attachments and {embeds} embeds]" + } } } \ No newline at end of file diff --git a/i18n/es-ES/equicord.json b/i18n/es-ES/equicord.json new file mode 100644 index 000000000..0967ef424 --- /dev/null +++ b/i18n/es-ES/equicord.json @@ -0,0 +1 @@ +{} diff --git a/i18n/fi-FI/equicord.json b/i18n/fi-FI/equicord.json new file mode 100644 index 000000000..0967ef424 --- /dev/null +++ b/i18n/fi-FI/equicord.json @@ -0,0 +1 @@ +{} diff --git a/i18n/fr-FR/equicord.json b/i18n/fr-FR/equicord.json new file mode 100644 index 000000000..0967ef424 --- /dev/null +++ b/i18n/fr-FR/equicord.json @@ -0,0 +1 @@ +{} diff --git a/i18n/he-IL/equicord.json b/i18n/he-IL/equicord.json new file mode 100644 index 000000000..0967ef424 --- /dev/null +++ b/i18n/he-IL/equicord.json @@ -0,0 +1 @@ +{} diff --git a/i18n/hu-HU/equicord.json b/i18n/hu-HU/equicord.json new file mode 100644 index 000000000..0967ef424 --- /dev/null +++ b/i18n/hu-HU/equicord.json @@ -0,0 +1 @@ +{} diff --git a/i18n/it-IT/equicord.json b/i18n/it-IT/equicord.json new file mode 100644 index 000000000..0967ef424 --- /dev/null +++ b/i18n/it-IT/equicord.json @@ -0,0 +1 @@ +{} diff --git a/i18n/ja-JP/equicord.json b/i18n/ja-JP/equicord.json new file mode 100644 index 000000000..0967ef424 --- /dev/null +++ b/i18n/ja-JP/equicord.json @@ -0,0 +1 @@ +{} diff --git a/i18n/ko-KR/equicord.json b/i18n/ko-KR/equicord.json new file mode 100644 index 000000000..0967ef424 --- /dev/null +++ b/i18n/ko-KR/equicord.json @@ -0,0 +1 @@ +{} diff --git a/i18n/nl-NL/equicord.json b/i18n/nl-NL/equicord.json new file mode 100644 index 000000000..0967ef424 --- /dev/null +++ b/i18n/nl-NL/equicord.json @@ -0,0 +1 @@ +{} diff --git a/i18n/no-NO/equicord.json b/i18n/no-NO/equicord.json new file mode 100644 index 000000000..0967ef424 --- /dev/null +++ b/i18n/no-NO/equicord.json @@ -0,0 +1 @@ +{} diff --git a/i18n/pl-PL/equicord.json b/i18n/pl-PL/equicord.json new file mode 100644 index 000000000..0967ef424 --- /dev/null +++ b/i18n/pl-PL/equicord.json @@ -0,0 +1 @@ +{} diff --git a/i18n/pt-PT/equicord.json b/i18n/pt-PT/equicord.json new file mode 100644 index 000000000..0967ef424 --- /dev/null +++ b/i18n/pt-PT/equicord.json @@ -0,0 +1 @@ +{} diff --git a/i18n/ro-RO/equicord.json b/i18n/ro-RO/equicord.json new file mode 100644 index 000000000..0967ef424 --- /dev/null +++ b/i18n/ro-RO/equicord.json @@ -0,0 +1 @@ +{} diff --git a/i18n/ru-RU/equicord.json b/i18n/ru-RU/equicord.json new file mode 100644 index 000000000..0967ef424 --- /dev/null +++ b/i18n/ru-RU/equicord.json @@ -0,0 +1 @@ +{} diff --git a/i18n/sr-SP/equicord.json b/i18n/sr-SP/equicord.json new file mode 100644 index 000000000..0967ef424 --- /dev/null +++ b/i18n/sr-SP/equicord.json @@ -0,0 +1 @@ +{} diff --git a/i18n/sv-SE/equicord.json b/i18n/sv-SE/equicord.json new file mode 100644 index 000000000..0967ef424 --- /dev/null +++ b/i18n/sv-SE/equicord.json @@ -0,0 +1 @@ +{} diff --git a/i18n/tr-TR/equicord.json b/i18n/tr-TR/equicord.json new file mode 100644 index 000000000..0967ef424 --- /dev/null +++ b/i18n/tr-TR/equicord.json @@ -0,0 +1 @@ +{} diff --git a/i18n/uk-UA/equicord.json b/i18n/uk-UA/equicord.json new file mode 100644 index 000000000..0967ef424 --- /dev/null +++ b/i18n/uk-UA/equicord.json @@ -0,0 +1 @@ +{} diff --git a/i18n/vi-VN/equicord.json b/i18n/vi-VN/equicord.json new file mode 100644 index 000000000..0967ef424 --- /dev/null +++ b/i18n/vi-VN/equicord.json @@ -0,0 +1 @@ +{} diff --git a/i18n/zh-CN/equicord.json b/i18n/zh-CN/equicord.json new file mode 100644 index 000000000..0967ef424 --- /dev/null +++ b/i18n/zh-CN/equicord.json @@ -0,0 +1 @@ +{} diff --git a/src/components/settings/AddonCard.tsx b/src/components/settings/AddonCard.tsx index 880c77916..33927ae3d 100644 --- a/src/components/settings/AddonCard.tsx +++ b/src/components/settings/AddonCard.tsx @@ -21,8 +21,8 @@ import "./AddonCard.css"; import { Badge } from "@components/Badge"; import { BaseText } from "@components/BaseText"; import { Switch } from "@components/Switch"; -import { t } from "@utils/translation"; import { classNameFactory } from "@utils/css"; +import { t } from "@utils/translation"; import { Tooltip, useRef } from "@webpack/common"; import type { MouseEventHandler, ReactNode } from "react"; diff --git a/src/components/settings/OnlineThemeCard.tsx b/src/components/settings/OnlineThemeCard.tsx index ae9bff396..b28cd189a 100644 --- a/src/components/settings/OnlineThemeCard.tsx +++ b/src/components/settings/OnlineThemeCard.tsx @@ -21,8 +21,8 @@ import "./AddonCard.css"; import { Badge } from "@components/Badge"; import { BaseText } from "@components/BaseText"; import { Switch } from "@components/settings"; -import { t } from "@utils/translation"; import { classNameFactory } from "@utils/css"; +import { t } from "@utils/translation"; import { useRef } from "@webpack/common"; import type { MouseEventHandler, ReactNode } from "react"; diff --git a/src/components/settings/tabs/plugins/components/Common.tsx b/src/components/settings/tabs/plugins/components/Common.tsx index 56bb24f10..6b8ead13f 100644 --- a/src/components/settings/tabs/plugins/components/Common.tsx +++ b/src/components/settings/tabs/plugins/components/Common.tsx @@ -35,19 +35,20 @@ export function resolveError(isValidResult: boolean | string) { interface SettingsSectionProps extends PropsWithChildren { name: string; - description: string; + description: string | (() => string); error?: string | null; inlineSetting?: boolean; tag?: "label" | "div"; } export function SettingsSection({ tag: Tag = "div", name, description, error, inlineSetting, children }: SettingsSectionProps) { + const resolvedDescription = typeof description === "function" ? description() : description; return (
{name && {wordsToTitle(wordsFromCamel(name))}} - {description && {description}} + {resolvedDescription && {resolvedDescription}}
{children}
diff --git a/src/equicordplugins/absRPC/index.tsx b/src/equicordplugins/absRPC/index.tsx index 8f389f20c..2ef077b20 100644 --- a/src/equicordplugins/absRPC/index.tsx +++ b/src/equicordplugins/absRPC/index.tsx @@ -10,6 +10,7 @@ import { HeadingSecondary } from "@components/Heading"; import { Paragraph } from "@components/Paragraph"; import { EquicordDevs } from "@utils/constants"; import { Logger } from "@utils/Logger"; +import { t } from "@utils/translation"; import definePlugin, { OptionType } from "@utils/types"; import { ApplicationAssetUtils, FluxDispatcher, showToast } from "@webpack/common"; @@ -51,15 +52,15 @@ interface MediaData { const settings = definePluginSettings({ serverUrl: { - description: "AudioBookShelf server URL (e.g., https://abs.example.com)", + description: t("absRPC.settings.serverUrl"), type: OptionType.STRING, }, username: { - description: "AudioBookShelf username", + description: t("absRPC.settings.username"), type: OptionType.STRING, }, password: { - description: "AudioBookShelf password", + description: t("absRPC.settings.password"), type: OptionType.STRING, }, }); @@ -85,16 +86,16 @@ function setActivity(activity: Activity | null) { export default definePlugin({ name: "AudioBookShelfRichPresence", - description: "Rich presence for AudioBookShelf media server", + description: t("absRPC.description"), authors: [EquicordDevs.vmohammad], settingsAboutComponent: () => ( <> - How to connect to AudioBookShelf + {t("absRPC.about.title")} - Enter your AudioBookShelf server URL, username, and password to display your currently playing audiobooks as Discord Rich Presence. + {t("absRPC.about.description")}

- The plugin will automatically authenticate and fetch your listening progress. + {t("absRPC.about.automaticAuth")}
), @@ -114,7 +115,7 @@ export default definePlugin({ async authenticate(): Promise { if (!settings.store.serverUrl || !settings.store.username || !settings.store.password) { logger.warn("AudioBookShelf server URL, username, or password is not set in settings."); - showToast("AudioBookShelf RPC is not configured.", "failure", { + showToast(t("absRPC.toasts.notConfigured"), "failure", { duration: 15000, }); return false; diff --git a/src/equicordplugins/altKrispSwitch/index.tsx b/src/equicordplugins/altKrispSwitch/index.tsx index a55216aa3..67e941a78 100644 --- a/src/equicordplugins/altKrispSwitch/index.tsx +++ b/src/equicordplugins/altKrispSwitch/index.tsx @@ -5,11 +5,12 @@ */ import { Devs } from "@utils/constants"; +import { t } from "@utils/translation"; import definePlugin from "@utils/types"; export default definePlugin({ name: "AltKrispSwitch", - description: "Makes the Noise Suppression Popout switch between None and Krisp instead of Krisp and Standard", + description: t("altKrispSwitch.description"), authors: [Devs.newwares], patches: [ { diff --git a/src/equicordplugins/alwaysExpandProfiles/index.ts b/src/equicordplugins/alwaysExpandProfiles/index.ts index c78baea4f..20ed60935 100644 --- a/src/equicordplugins/alwaysExpandProfiles/index.ts +++ b/src/equicordplugins/alwaysExpandProfiles/index.ts @@ -6,11 +6,12 @@ import { Devs } from "@utils/constants"; import { openUserProfile } from "@utils/discord"; +import { t } from "@utils/translation"; import definePlugin from "@utils/types"; export default definePlugin({ name: "AlwaysExpandProfiles", - description: "Always expands profile popouts to the full modal", + description: t("alwaysExpandProfiles.description"), authors: [Devs.thororen], patches: [ { diff --git a/src/equicordplugins/anammox/index.ts b/src/equicordplugins/anammox/index.ts index 1ec80516c..4e1a1c26a 100644 --- a/src/equicordplugins/anammox/index.ts +++ b/src/equicordplugins/anammox/index.ts @@ -6,50 +6,51 @@ import { definePluginSettings } from "@api/Settings"; import { Devs } from "@utils/constants"; +import { t } from "@utils/translation"; import definePlugin, { OptionType } from "@utils/types"; export const settings = definePluginSettings({ dms: { type: OptionType.BOOLEAN, default: true, - description: "Remove shops above DMs list", + description: t("anammox.settings.dms"), restartNeeded: true, }, quests: { type: OptionType.BOOLEAN, default: false, - description: "Remove quests above DMs list", + description: t("anammox.settings.quests"), restartNeeded: true, }, serverBoost: { type: OptionType.BOOLEAN, default: true, - description: "Remove server boost info above channel list", + description: t("anammox.settings.serverBoost"), restartNeeded: true, }, billing: { type: OptionType.BOOLEAN, default: true, - description: "Remove billing settings", + description: t("anammox.settings.billing"), restartNeeded: true, }, gift: { type: OptionType.BOOLEAN, default: true, - description: "Remove gift button", + description: t("anammox.settings.gift"), restartNeeded: true, }, emojiList: { type: OptionType.BOOLEAN, default: true, - description: "Remove unavailable categories from the emoji picker", + description: t("anammox.settings.emojiList"), restartNeeded: true, }, }); export default definePlugin({ name: "Anammox", - description: "Hides various features related to nitro and the store", + description: t("anammox.description"), authors: [Devs.Kyuuhachi], settings, diff --git a/src/equicordplugins/animalese/index.ts b/src/equicordplugins/animalese/index.ts index 1f8ccb568..9c6675f6a 100644 --- a/src/equicordplugins/animalese/index.ts +++ b/src/equicordplugins/animalese/index.ts @@ -6,57 +6,58 @@ import { definePluginSettings } from "@api/Settings"; import { EquicordDevs } from "@utils/constants"; +import { t } from "@utils/translation"; import definePlugin, { OptionType } from "@utils/types"; import { SelectedChannelStore, UserStore } from "@webpack/common"; const settings = definePluginSettings({ volume: { type: OptionType.SLIDER, - description: "Volume of the animalese sound", + description: t("animalese.settings.volume"), default: 0.5, markers: [0, 0.1, 0.25, 0.5, 0.6, 0.75, 1], }, speed: { type: OptionType.SLIDER, - description: "Speed of the animalese sound", + description: t("animalese.settings.speed"), default: 1, markers: [0.5, 0.75, 1, 1.25, 1.5], }, pitch: { type: OptionType.SLIDER, - description: "Pitch multiplier", + description: t("animalese.settings.pitch"), default: 1, markers: [0.75, 0.8, 0.85, 1, 1.15, 1.25, 1.35, 1.5], }, messageLengthLimit: { type: OptionType.NUMBER, - description: "Maximum length of message to process", + description: t("animalese.settings.messageLengthLimit"), default: 50, }, processOwnMessages: { type: OptionType.BOOLEAN, - description: "Enable to yap your own messages too", + description: t("animalese.settings.processOwnMessages"), default: true, }, soundQuality: { type: OptionType.SELECT, - description: "Quality of sound to use", + description: t("animalese.settings.soundQuality"), options: [ { - label: "High", + label: t("animalese.quality.high"), value: "high", default: true }, { - label: "Medium", + label: t("animalese.quality.medium"), value: "med" }, { - label: "Low", + label: t("animalese.quality.low"), value: "low" }, { - label: "Lowest", + label: t("animalese.quality.lowest"), value: "low" } ] @@ -192,7 +193,7 @@ async function playSound(buffer: AudioBuffer, volume: number) { export default definePlugin({ name: "Animalese", - description: "Plays animal crossing animalese for every message sent (they yap a lot)", + description: t("animalese.description"), authors: [EquicordDevs.ryanamay, EquicordDevs.Mocha], settings, diff --git a/src/equicordplugins/atSomeone/index.ts b/src/equicordplugins/atSomeone/index.ts index 40902e6c4..c275247c2 100644 --- a/src/equicordplugins/atSomeone/index.ts +++ b/src/equicordplugins/atSomeone/index.ts @@ -6,20 +6,21 @@ import { addMessagePreSendListener, removeMessagePreSendListener } from "@api/MessageEvents"; import { Devs } from "@utils/constants"; +import { t } from "@utils/translation"; import definePlugin from "@utils/types"; import { ChannelStore, GuildMemberStore, SelectedChannelStore, SelectedGuildStore } from "@webpack/common"; export default definePlugin({ name: "AtSomeone", authors: [Devs.Joona], - description: "Mention someone randomly", + description: t("atSomeone.description"), patches: [ { find: ".LAUNCHABLE_APPLICATIONS;", replacement: [ { match: /&(\i)\(\)\((\i),\i\(\)\.test\)&&(\i)\.push\(\i\(\)\)/g, - replace: "$&,$1()($2,/someone/.test)&&$3.push({text:'@someone',description:'Mention someone randomly'})" + replace: "$&,$1()($2,/someone/.test)&&$3.push({text:'@someone',description:$self.getSomeoneDescription()})" }, ], }, @@ -31,6 +32,9 @@ export default definePlugin({ } } ], + getSomeoneDescription() { + return t("atSomeone.contextMenu.someone"); + }, start() { this.preSend = addMessagePreSendListener((_, msg) => { msg.content = msg.content.replace(/@someone/g, () => `<@${randomUser()}>`); diff --git a/src/equicordplugins/autoZipper/index.ts b/src/equicordplugins/autoZipper/index.ts index ab0f2335f..36cc05837 100644 --- a/src/equicordplugins/autoZipper/index.ts +++ b/src/equicordplugins/autoZipper/index.ts @@ -7,6 +7,7 @@ import { definePluginSettings } from "@api/Settings"; import { EquicordDevs } from "@utils/constants"; import { Logger } from "@utils/Logger"; +import { t } from "@utils/translation"; import definePlugin, { OptionType } from "@utils/types"; import { ChannelStore, DraftType, SelectedChannelStore, UploadHandler } from "@webpack/common"; import { zipSync } from "fflate"; @@ -16,7 +17,7 @@ const logger = new Logger("AutoZipper"); const settings = definePluginSettings({ extensions: { type: OptionType.STRING, - description: "Comma-separated list of file extensions to auto-zip (e.g., .psd,.blend,.exe,.dmg)", + description: t("autoZipper.settings.extensions"), default: ".psd,.blend,.exe,.dmg,.app,.apk,.iso", onChange: () => { extensionsToZip.clear(); @@ -208,7 +209,7 @@ function handlePaste(event: ClipboardEvent) { export default definePlugin({ name: "AutoZipper", - description: "Automatically zips specified file types and folders before uploading to Discord", + description: t("autoZipper.description"), authors: [EquicordDevs.SSnowly], settings, diff --git a/src/equicordplugins/bannersEverywhere/index.tsx b/src/equicordplugins/bannersEverywhere/index.tsx index 5959a4022..f7a797036 100644 --- a/src/equicordplugins/bannersEverywhere/index.tsx +++ b/src/equicordplugins/bannersEverywhere/index.tsx @@ -10,6 +10,7 @@ import { definePluginSettings } from "@api/Settings"; import { disableStyle, enableStyle } from "@api/Styles"; import usrbg from "@plugins/usrbg"; import { Devs } from "@utils/constants"; +import { t } from "@utils/translation"; import definePlugin, { OptionType } from "@utils/types"; import { User } from "@vencord/discord-types"; import { UserProfileStore } from "@webpack/common"; @@ -28,12 +29,12 @@ interface Nameplate { const settings = definePluginSettings({ animate: { - description: "Animate banners", + description: t("bannersEverywhere.settings.animate"), type: OptionType.BOOLEAN, default: false }, preferNameplate: { - description: "prefer nameplate over banner", + description: t("bannersEverywhere.settings.preferNameplate"), type: OptionType.BOOLEAN, default: false }, @@ -43,7 +44,7 @@ const DATASTORE_KEY = "bannersEverywhere"; export default definePlugin({ name: "BannersEverywhere", - description: "Displays banners in the member list ", + description: t("bannersEverywhere.description"), authors: [Devs.ImLvna, Devs.AutumnVN], settings, patches: [ diff --git a/src/equicordplugins/baseDecoder/index.tsx b/src/equicordplugins/baseDecoder/index.tsx index 35ba3d701..5522da2af 100644 --- a/src/equicordplugins/baseDecoder/index.tsx +++ b/src/equicordplugins/baseDecoder/index.tsx @@ -25,6 +25,7 @@ import { Heading } from "@components/Heading"; import { EquicordDevs } from "@utils/constants"; import { copyWithToast } from "@utils/discord"; import { closeModal, ModalCloseButton, ModalContent, ModalFooter, ModalHeader, ModalRoot, ModalSize, openModal } from "@utils/modal"; +import { t } from "@utils/translation"; import definePlugin, { OptionType } from "@utils/types"; import { Button, ChannelStore } from "@webpack/common"; @@ -68,12 +69,12 @@ function openDecodedBase64Modal(decodedContent) { - Decoded Base64 Content + {t("baseDecoder.ui.modalTitle")} closeModal(key)} />
- Decoded Content + {t("baseDecoder.ui.decodedContent")} {decodedContent.map((content, index) => ( ))} @@ -82,8 +83,8 @@ function openDecodedBase64Modal(decodedContent) { {decodedContent.map((content, index) => ( - ))} @@ -95,18 +96,18 @@ function openDecodedBase64Modal(decodedContent) { const settings = definePluginSettings({ clickMethod: { - description: "Change the button to decode base64 content of any message.", + description: t("baseDecoder.settings.clickMethod"), type: OptionType.SELECT, options: [ - { label: "Left Click to decode the base64 content.", value: "Left", default: true }, - { label: "Right click to decode the base64 content.", value: "Right" } + { label: t("baseDecoder.settings.clickMethodOptions.left"), value: "Left", default: true }, + { label: t("baseDecoder.settings.clickMethodOptions.right"), value: "Right" } ] } }); export default definePlugin({ name: "DecodeBase64", - description: "Decode base64 content of any message and copy the decoded content.", + description: t("baseDecoder.description"), authors: [EquicordDevs.ThePirateStoner], settings, messagePopoverButton: { @@ -137,8 +138,8 @@ export default definePlugin({ }; const label = settings.store.clickMethod === "Right" - ? "Copy Decoded (Left Click) / Decode Base64 (Right Click)" - : "Decode Base64 (Left Click) / Copy Decoded (Right Click)"; + ? t("baseDecoder.ui.tooltipLeft") + : t("baseDecoder.ui.tooltipRight"); return { label, diff --git a/src/equicordplugins/betterActivities/index.tsx b/src/equicordplugins/betterActivities/index.tsx index f5c35f122..049f0ab0c 100644 --- a/src/equicordplugins/betterActivities/index.tsx +++ b/src/equicordplugins/betterActivities/index.tsx @@ -8,6 +8,7 @@ import "./styles.css"; import { migratePluginSettings } from "@api/Settings"; import { Devs } from "@utils/constants"; +import { t } from "@utils/translation"; import definePlugin from "@utils/types"; import { patchActivityList } from "./patch-helpers/activityList"; @@ -18,7 +19,7 @@ migratePluginSettings("BetterActivities", "MemberListActivities"); export default definePlugin({ name: "BetterActivities", - description: "Shows activity icons in the member list and allows showing all activities", + description: t("betterActivities.description"), authors: [Devs.D3SOX, Devs.Arjix, Devs.AutumnVN, Devs.thororen], tags: ["activity"], settings, diff --git a/src/equicordplugins/betterActivities/settings.tsx b/src/equicordplugins/betterActivities/settings.tsx index 300e8cba6..2eddfe903 100644 --- a/src/equicordplugins/betterActivities/settings.tsx +++ b/src/equicordplugins/betterActivities/settings.tsx @@ -5,38 +5,39 @@ */ import { definePluginSettings } from "@api/Settings"; +import { t } from "@utils/translation"; import { OptionType } from "@utils/types"; import { React } from "@webpack/common"; export const settings = definePluginSettings({ memberList: { type: OptionType.BOOLEAN, - description: "Show activity icons in the member list", + description: t("betterActivities.settings.memberList"), default: true, restartNeeded: true, }, iconSize: { type: OptionType.SLIDER, - description: "Size of the activity icons", + description: t("betterActivities.settings.iconSize"), markers: [10, 15, 20], default: 15, stickToMarkers: false, }, specialFirst: { type: OptionType.BOOLEAN, - description: "Show special activities first (Currently Spotify and Twitch)", + description: t("betterActivities.settings.specialFirst"), default: true, restartNeeded: false, }, renderGifs: { type: OptionType.BOOLEAN, - description: "Allow rendering GIFs", + description: t("betterActivities.settings.renderGifs"), default: true, restartNeeded: false, }, removeGameActivityStatus: { type: OptionType.BOOLEAN, - description: "Remove game activity icon and status", + description: t("betterActivities.settings.removeGameActivityStatus"), default: false, restartNeeded: true, }, @@ -55,26 +56,26 @@ export const settings = definePluginSettings({ }, userPopout: { type: OptionType.BOOLEAN, - description: "Show all activities in the profile popout/sidebar", + description: t("betterActivities.settings.userPopout"), default: true, restartNeeded: true, }, hideTooltip: { type: OptionType.BOOLEAN, - description: "Hides activities in various places", + description: t("betterActivities.settings.hideTooltip"), default: true, }, allActivitiesStyle: { type: OptionType.SELECT, - description: "Style for showing all activities", + description: t("betterActivities.settings.allActivitiesStyle"), options: [ { default: true, - label: "Carousel", + label: t("betterActivities.options.carousel"), value: "carousel", }, { - label: "List", + label: t("betterActivities.options.list"), value: "list", }, ] diff --git a/src/equicordplugins/betterAudioPlayer/index.tsx b/src/equicordplugins/betterAudioPlayer/index.tsx index 7c0204ecd..713727463 100644 --- a/src/equicordplugins/betterAudioPlayer/index.tsx +++ b/src/equicordplugins/betterAudioPlayer/index.tsx @@ -8,6 +8,7 @@ import "./style.css"; import { definePluginSettings } from "@api/Settings"; import { EquicordDevs } from "@utils/constants"; +import { t } from "@utils/translation"; import definePlugin, { OptionType } from "@utils/types"; import { showToast, Toasts } from "@webpack/common"; @@ -245,7 +246,7 @@ function handleColorChange(value, settingKey, defaultValue) { if (rgb.match(rgbPattern)) { settings.store[settingKey] = rgb; } else { - showToast(`Invalid color format for ${settingKey}, make sure it's in the format 'R, G, B' or '#RRGGBB'`, Toasts.Type.FAILURE); + showToast(t("betterAudioPlayer.toasts.invalidColor", { settingKey }), Toasts.Type.FAILURE); settings.store[settingKey] = defaultValue; } } else { @@ -256,39 +257,39 @@ function handleColorChange(value, settingKey, defaultValue) { const settings = definePluginSettings({ oscilloscope: { type: OptionType.BOOLEAN, - description: "Enable oscilloscope visualizer", + description: t("betterAudioPlayer.settings.oscilloscope"), default: true, }, spectrograph: { type: OptionType.BOOLEAN, - description: "Enable spectrograph visualizer", + description: t("betterAudioPlayer.settings.spectrograph"), default: true, }, oscilloscopeSolidColor: { type: OptionType.BOOLEAN, - description: "Use solid color for oscilloscope", + description: t("betterAudioPlayer.settings.oscilloscopeSolidColor"), default: false, }, oscilloscopeColor: { type: OptionType.STRING, - description: "Color for oscilloscope", + description: t("betterAudioPlayer.settings.oscilloscopeColor"), default: "255, 255, 255", onChange: value => handleColorChange(value, "oscilloscopeColor", "255, 255, 255"), }, spectrographSolidColor: { type: OptionType.BOOLEAN, - description: "Use solid color for spectrograph", + description: t("betterAudioPlayer.settings.spectrographSolidColor"), default: false, }, spectrographColor: { type: OptionType.STRING, - description: "Color for spectrograph", + description: t("betterAudioPlayer.settings.spectrographColor"), default: "33, 150, 243", onChange: value => handleColorChange(value, "spectrographColor", "33, 150, 243"), }, forceMoveBelow: { type: OptionType.BOOLEAN, - description: "Force the visualizer below the audio player", + description: t("betterAudioPlayer.settings.forceMoveBelow"), default: true, }, }); @@ -297,7 +298,7 @@ let observer: MutationObserver | null = null; export default definePlugin({ name: "BetterAudioPlayer", - description: "Adds a spectrograph and oscilloscope visualizer to audio attachment players", + description: t("betterAudioPlayer.description"), authors: [EquicordDevs.creations], settings, start() { diff --git a/src/equicordplugins/betterBanReasons/index.tsx b/src/equicordplugins/betterBanReasons/index.tsx index 68e849e1c..57980b64d 100644 --- a/src/equicordplugins/betterBanReasons/index.tsx +++ b/src/equicordplugins/betterBanReasons/index.tsx @@ -11,6 +11,7 @@ import { Heading } from "@components/Heading"; import { DeleteIcon, PlusIcon } from "@components/Icons"; import { Devs } from "@utils/constants"; import { classNameFactory } from "@utils/css"; +import { t } from "@utils/translation"; import definePlugin, { OptionType } from "@utils/types"; import { Button, TextInput } from "@webpack/common"; @@ -21,7 +22,7 @@ function ReasonsComponent() { return (
- Reasons + {t("betterBanReasons.ui.reasons")} {reasons.map((r, i) => (
@@ -60,20 +61,20 @@ function ReasonsComponent() { const settings = definePluginSettings({ reasons: { - description: "Your custom reasons", + description: t("betterBanReasons.settings.reasons"), type: OptionType.COMPONENT, default: [] as string[], component: ReasonsComponent, }, isTextInputDefault: { type: OptionType.BOOLEAN, - description: 'Shows a text input instead of a select menu by default. (Equivalent to clicking the "Other" option)' + description: t("betterBanReasons.settings.isTextInputDefault") } }); export default definePlugin({ name: "BetterBanReasons", - description: "Create custom reasons to use in the Discord ban modal, and/or show a text input by default instead of the options.", + description: t("betterBanReasons.description"), authors: [Devs.Inbestigator], patches: [ { diff --git a/src/equicordplugins/betterBlockedUsers/index.tsx b/src/equicordplugins/betterBlockedUsers/index.tsx index ce936edb0..ff39477f9 100644 --- a/src/equicordplugins/betterBlockedUsers/index.tsx +++ b/src/equicordplugins/betterBlockedUsers/index.tsx @@ -8,6 +8,7 @@ import "./styles.css"; import { EquicordDevs } from "@utils/constants"; import { getIntlMessage, openUserProfile } from "@utils/discord"; +import { t } from "@utils/translation"; import definePlugin from "@utils/types"; import { Button, React, RelationshipStore, TextInput, UserStore } from "@webpack/common"; @@ -16,7 +17,7 @@ let updateFunc = (v: any) => { }; export default definePlugin({ name: "BetterBlockedUsers", - description: "Allows you to search in blocked users list and makes names selectable in settings.", + description: t("betterBlockedUsers.description"), authors: [EquicordDevs.TheArmagan], patches: [ { @@ -50,7 +51,7 @@ export default definePlugin({ }, []); return { const search = (e.target as HTMLInputElement).value.toLowerCase().trim(); diff --git a/src/equicordplugins/betterCommands/index.ts b/src/equicordplugins/betterCommands/index.ts index 63bf1eb45..891c96ec6 100644 --- a/src/equicordplugins/betterCommands/index.ts +++ b/src/equicordplugins/betterCommands/index.ts @@ -7,17 +7,18 @@ import { ApplicationCommandInputType, ApplicationCommandOptionType, findOption, sendBotMessage } from "@api/Commands"; import { definePluginSettings } from "@api/Settings"; import { Devs } from "@utils/constants"; +import { t } from "@utils/translation"; import definePlugin, { OptionType } from "@utils/types"; import { FluxDispatcher, UserStore } from "@webpack/common"; const settings = definePluginSettings({ autoFillArguments: { - description: "Automatically fill command with all arguements instead of just required ones", + description: t("betterCommands.settings.autoFillArguments"), type: OptionType.BOOLEAN, default: true, }, allowNewlinesInCommands: { - description: "Allow newlines in command inputs (CTRL + Shift + Enter)", + description: t("betterCommands.settings.allowNewlinesInCommands"), type: OptionType.BOOLEAN, default: true, } @@ -32,7 +33,7 @@ function fetchIndex(target: object) { export default definePlugin({ name: "BetterCommands", - description: "Enhances the command system with miscellaneous improvements.", + description: t("betterCommands.description"), authors: [Devs.thororen], settings, patches: [ @@ -70,11 +71,11 @@ export default definePlugin({ commands: [ { name: "refresh", - description: "Refreshes Discord application commands locally", + description: t("betterCommands.commands.refresh.description"), options: [ { name: "user", - description: "specific user to try and refresh", + description: t("betterCommands.commands.refresh.userOption"), type: ApplicationCommandOptionType.USER, } ], @@ -86,7 +87,7 @@ export default definePlugin({ const user = findOption(opts, "user") as string; sendBotMessage(ctx.channel.id, { - content: "Refreshing application commands...", + content: t("betterCommands.commands.refresh.refreshing"), }); fetchIndex({ type: "channel", channelId }); @@ -103,12 +104,12 @@ export default definePlugin({ } sendBotMessage(ctx.channel.id, { - content: "Commands refreshed successfully!", + content: t("betterCommands.commands.refresh.success"), }); } catch (err) { console.error("[Refresh Command] Error refreshing commands:", err); sendBotMessage(ctx.channel.id, { - content: "Failed to refresh commands. Check the console for details.", + content: t("betterCommands.commands.refresh.failed"), }); } }, diff --git a/src/equicordplugins/betterInvites/index.tsx b/src/equicordplugins/betterInvites/index.tsx index 550e4fd25..2aa401058 100644 --- a/src/equicordplugins/betterInvites/index.tsx +++ b/src/equicordplugins/betterInvites/index.tsx @@ -10,6 +10,7 @@ import { InfoIcon } from "@components/Icons"; import { Devs, EquicordDevs } from "@utils/constants"; import { openUserProfile } from "@utils/discord"; import { classes } from "@utils/misc"; +import { t } from "@utils/translation"; import definePlugin, { StartAt } from "@utils/types"; import { Guild } from "@vencord/discord-types"; import { findByPropsLazy, findCssClassesLazy } from "@webpack"; @@ -33,7 +34,7 @@ function lurk(id: string) { export default definePlugin({ name: "BetterInvites", - description: "See invites expiration date, view inviter profile and preview servers before joining by clicking the name", + description: t("betterInvites.description"), authors: [EquicordDevs.iamme, Devs.thororen], patches: [ { @@ -66,7 +67,9 @@ export default definePlugin({ const timestamp = <>{Parser.parse(``)}; const tooltipText = ( <> - This invite will {expires_at ? <>expire {timestamp} : <>not expire} + {t("betterInvites.ui.expireTooltip", { + expiry: expires_at ? <>{t("betterInvites.ui.expireWill")} {timestamp} : <>{t("betterInvites.ui.notExpire")} + })} ); @@ -98,7 +101,7 @@ export default definePlugin({ : "/assets/1f0bfc0865d324c2587920a7d80c609b.png?size=128"} />
- {inviter.global_name || inviter.username} invited you to {guildName} + {t("betterInvites.ui.invitedYouTo", { inviter: inviter.global_name || inviter.username, guild: guildName })}
); diff --git a/src/equicordplugins/betterPlusReacts/index.ts b/src/equicordplugins/betterPlusReacts/index.ts index 2e3f84d2b..385fb37cf 100644 --- a/src/equicordplugins/betterPlusReacts/index.ts +++ b/src/equicordplugins/betterPlusReacts/index.ts @@ -5,13 +5,14 @@ */ import { Devs } from "@utils/constants"; +import { t } from "@utils/translation"; import definePlugin from "@utils/types"; import { MessageStore } from "@webpack/common"; export default definePlugin({ name: "BetterPlusReacts", authors: [Devs.Joona], - description: "The amount of plus before :emoji: is the message to add it to", + description: t("betterPlusReacts.description"), patches: [ { find: ".SLASH_COMMAND_USED,", diff --git a/src/equicordplugins/betterUserArea/index.ts b/src/equicordplugins/betterUserArea/index.ts index fdde42738..4037ebe29 100644 --- a/src/equicordplugins/betterUserArea/index.ts +++ b/src/equicordplugins/betterUserArea/index.ts @@ -6,42 +6,43 @@ import { definePluginSettings } from "@api/Settings"; import { Devs } from "@utils/constants"; +import { t } from "@utils/translation"; import definePlugin, { OptionType } from "@utils/types"; const settings = definePluginSettings({ removeNameplate: { type: OptionType.BOOLEAN, - description: "Remove nameplate styling.", + description: t("betterUserArea.settings.removeNameplate"), default: true, restartNeeded: true }, removeAudioMenus: { type: OptionType.BOOLEAN, - description: "Remove menus next to mute and deafen buttons.", + description: t("betterUserArea.settings.removeAudioMenus"), default: true, restartNeeded: true }, alwaysShowUsername: { type: OptionType.BOOLEAN, - description: "Always show username instead of status.", + description: t("betterUserArea.settings.alwaysShowUsername"), default: true, restartNeeded: true }, removeButtonTooltips: { type: OptionType.BOOLEAN, - description: "Remove button tooltips.", + description: t("betterUserArea.settings.removeButtonTooltips"), default: false, restartNeeded: true }, removeAvatarDecoration: { type: OptionType.BOOLEAN, - description: "Remove avatar decoration.", + description: t("betterUserArea.settings.removeAvatarDecoration"), default: true, restartNeeded: true }, removeUsernameStyles: { type: OptionType.BOOLEAN, - description: "Remove username colors and effects.", + description: t("betterUserArea.settings.removeUsernameStyles"), default: true, restartNeeded: true } @@ -49,7 +50,7 @@ const settings = definePluginSettings({ export default definePlugin({ name: "BetterUserArea", - description: "Customize and make the user area more clean.", + description: t("betterUserArea.description"), authors: [Devs.prism], settings, patches: [ diff --git a/src/equicordplugins/blockKeywords/index.ts b/src/equicordplugins/blockKeywords/index.ts index 3f7504373..b7d0747e8 100644 --- a/src/equicordplugins/blockKeywords/index.ts +++ b/src/equicordplugins/blockKeywords/index.ts @@ -6,6 +6,7 @@ import { definePluginSettings } from "@api/Settings"; import { EquicordDevs } from "@utils/constants"; +import { t } from "@utils/translation"; import definePlugin, { OptionType } from "@utils/types"; import { Message } from "@vencord/discord-types"; @@ -14,24 +15,24 @@ let blockedKeywords: Array; const settings = definePluginSettings({ blockedWords: { type: OptionType.STRING, - description: "Comma-seperated list of words to block", + description: t("blockKeywords.settings.blockedWords"), default: "", restartNeeded: true }, useRegex: { type: OptionType.BOOLEAN, - description: "Use each value as a regular expression when checking message content (advanced)", + description: t("blockKeywords.settings.useRegex"), default: false, restartNeeded: true }, caseSensitive: { type: OptionType.BOOLEAN, - description: "Whether to use a case sensitive search or not", + description: t("blockKeywords.settings.caseSensitive"), default: false, restartNeeded: true }, ignoreBlockedMessages: { - description: "Completely ignores (recent) new messages bar", + description: t("blockKeywords.settings.ignoreBlockedMessages"), type: OptionType.BOOLEAN, default: true, restartNeeded: true, @@ -69,7 +70,7 @@ export function containsBlockedKeywords(message: Message) { export default definePlugin({ name: "BlockKeywords", - description: "Blocks messages containing specific user-defined keywords, as if the user sending them was blocked.", + description: t("blockKeywords.description"), authors: [EquicordDevs.catcraft], patches: [ { diff --git a/src/equicordplugins/blockKrisp/index.ts b/src/equicordplugins/blockKrisp/index.ts index 28f6791ea..53106d6bf 100644 --- a/src/equicordplugins/blockKrisp/index.ts +++ b/src/equicordplugins/blockKrisp/index.ts @@ -5,11 +5,12 @@ */ import { Devs } from "@utils/constants"; +import { t } from "@utils/translation"; import definePlugin from "@utils/types"; export default definePlugin({ name: "BlockKrisp", - description: "Prevent Krisp from loading", + description: t("blockKrisp.description"), authors: [Devs.D3SOX], patches: [ // Block loading modules on Desktop diff --git a/src/equicordplugins/bypassPinPrompt/index.ts b/src/equicordplugins/bypassPinPrompt/index.ts index 6c1503cd2..0cfde3bfc 100644 --- a/src/equicordplugins/bypassPinPrompt/index.ts +++ b/src/equicordplugins/bypassPinPrompt/index.ts @@ -5,11 +5,12 @@ */ import { Devs } from "@utils/constants"; +import { t } from "@utils/translation"; import definePlugin from "@utils/types"; export default definePlugin({ name: "BypassPinPrompt", - description: "Bypass the pin prompt when using the pin functions", + description: t("bypassPinPrompt.description"), authors: [Devs.thororen], patches: [ ...[ diff --git a/src/equicordplugins/bypassStatus/index.tsx b/src/equicordplugins/bypassStatus/index.tsx index ac9d635d0..854488bd5 100644 --- a/src/equicordplugins/bypassStatus/index.tsx +++ b/src/equicordplugins/bypassStatus/index.tsx @@ -11,6 +11,7 @@ import { definePluginSettings } from "@api/Settings"; import { Devs } from "@utils/constants"; import { getCurrentChannel } from "@utils/discord"; import { Logger } from "@utils/Logger"; +import { t } from "@utils/translation"; import definePlugin, { OptionType } from "@utils/types"; import type { Message } from "@vencord/discord-types"; import { ChannelActionCreators, ChannelStore, Menu, MessageStore, NavigationRouter, PresenceStore, UserStore, WindowStore } from "@webpack/common"; @@ -79,7 +80,7 @@ function ContextCallback(name: "guild" | "user" | "channel"): NavContextMenuPatc Icon(enabled)} action={() => { let bypasses: string[] = settings.store[`${name}s`].split(", "); @@ -96,58 +97,58 @@ function ContextCallback(name: "guild" | "user" | "channel"): NavContextMenuPatc const settings = definePluginSettings({ guilds: { type: OptionType.STRING, - description: "Guilds to let bypass (notified when pinged anywhere in guild)", + description: t("bypassStatus.settings.guilds"), default: "", - placeholder: "Separate with commas", + placeholder: t("bypassStatus.placeholder.separateWithCommas"), onChange: value => settings.store.guilds = processIds(value) }, channels: { type: OptionType.STRING, - description: "Channels to let bypass (notified when pinged in that channel)", + description: t("bypassStatus.settings.channels"), default: "", - placeholder: "Separate with commas", + placeholder: t("bypassStatus.placeholder.separateWithCommas"), onChange: value => settings.store.channels = processIds(value) }, users: { type: OptionType.STRING, - description: "Users to let bypass (notified for all messages sent in DMs)", + description: t("bypassStatus.settings.users"), default: "", - placeholder: "Separate with commas", + placeholder: t("bypassStatus.placeholder.separateWithCommas"), onChange: value => settings.store.users = processIds(value) }, allowOutsideOfDms: { type: OptionType.BOOLEAN, - description: "Allow selected users to bypass status outside of DMs too (acts like a channel/guild bypass, but it's for all messages sent by the selected users)" + description: t("bypassStatus.settings.allowOutsideOfDms") }, notificationSound: { type: OptionType.BOOLEAN, - description: "Whether the notification sound should be played", + description: t("bypassStatus.settings.notificationSound"), default: true, }, respectSilentPings: { type: OptionType.BOOLEAN, - description: "Respect silent pings (@silent / suppress notifications)", + description: t("bypassStatus.settings.respectSilentPings"), default: true }, statusToUse: { type: OptionType.SELECT, - description: "Status to use for whitelist", + description: t("bypassStatus.settings.statusToUse"), options: [ { - label: "Online", + label: t("bypassStatus.statusOptions.online"), value: "online", }, { - label: "Idle", + label: t("bypassStatus.statusOptions.idle"), value: "idle", }, { - label: "Do Not Disturb", + label: t("bypassStatus.statusOptions.dnd"), value: "dnd", default: true }, { - label: "Invisible", + label: t("bypassStatus.statusOptions.invisible"), value: "invisible", } ] @@ -156,7 +157,7 @@ const settings = definePluginSettings({ export default definePlugin({ name: "BypassStatus", - description: "Still get notifications from specific sources when in do not disturb mode. Right-click on users/channels/guilds to set them to bypass do not disturb mode.", + description: t("bypassStatus.description"), authors: [Devs.Inbestigator], dependencies: ["AudioPlayerAPI"], flux: { diff --git a/src/equicordplugins/channelBadges/index.tsx b/src/equicordplugins/channelBadges/index.tsx index 25096a123..91d1adc87 100644 --- a/src/equicordplugins/channelBadges/index.tsx +++ b/src/equicordplugins/channelBadges/index.tsx @@ -7,6 +7,7 @@ import "./style.css"; import { Devs, EquicordDevs } from "@utils/constants"; +import { t } from "@utils/translation"; import definePlugin from "@utils/types"; import { Channel } from "@vencord/discord-types"; import { GuildStore, React, SelectedGuildStore } from "@webpack/common"; @@ -31,7 +32,7 @@ function renderBadge(id: number, title: string) { export default definePlugin({ name: "ChannelBadges", - description: "Adds badges to channels based on their type", + description: t("channelBadges.description"), authors: [EquicordDevs.creations, Devs.thororen], settings, patches: [ @@ -64,9 +65,9 @@ export default definePlugin({ const guild = selectedGuildId ? GuildStore.getGuild(selectedGuildId) : null; const badgeConditions = [ - { id: 6101, condition: isPrivate, title: "This channel is locked." }, - { id: 6100, condition: isNSFW, title: "This channel is marked as NSFW." }, - { id: 6102, condition: guild?.rulesChannelId === channel.id, title: "This channel is the server rules channel." }, + { id: 6101, condition: isPrivate, title: t("channelBadges.tooltips.lockedChannel") }, + { id: 6100, condition: isNSFW, title: t("channelBadges.tooltips.nsfwChannel") }, + { id: 6102, condition: guild?.rulesChannelId === channel.id, title: t("channelBadges.tooltips.rulesChannel") }, ]; let badges: JSX.Element[] = []; diff --git a/src/equicordplugins/channelBadges/settings.tsx b/src/equicordplugins/channelBadges/settings.tsx index baa38992d..24b679739 100644 --- a/src/equicordplugins/channelBadges/settings.tsx +++ b/src/equicordplugins/channelBadges/settings.tsx @@ -5,270 +5,271 @@ */ import { definePluginSettings } from "@api/Settings"; +import { t } from "@utils/translation"; import { OptionType } from "@utils/types"; export const settings = definePluginSettings({ oneBadgePerChannel: { type: OptionType.BOOLEAN, default: false, - description: "Show only one badge per channel", + description: t("channelBadges.settings.oneBadgePerChannel"), restartNeeded: true, }, showTextBadge: { type: OptionType.BOOLEAN, default: true, - description: "Show Text badge", + description: t("channelBadges.settings.showTextBadge"), restartNeeded: true, }, showVoiceBadge: { type: OptionType.BOOLEAN, default: true, - description: "Show Voice badge", + description: t("channelBadges.settings.showVoiceBadge"), restartNeeded: true, }, showCategoryBadge: { type: OptionType.BOOLEAN, default: true, - description: "Show Category badge", + description: t("channelBadges.settings.showCategoryBadge"), restartNeeded: true, }, showDirectoryBadge: { type: OptionType.BOOLEAN, default: true, - description: "Show Directory badge", + description: t("channelBadges.settings.showDirectoryBadge"), restartNeeded: true, }, showAnnouncementThreadBadge: { type: OptionType.BOOLEAN, default: true, - description: "Show Announcement Thread badge", + description: t("channelBadges.settings.showAnnouncementThreadBadge"), restartNeeded: true, }, showPublicThreadBadge: { type: OptionType.BOOLEAN, default: true, - description: "Show Public Thread badge", + description: t("channelBadges.settings.showPublicThreadBadge"), restartNeeded: true, }, showPrivateThreadBadge: { type: OptionType.BOOLEAN, default: true, - description: "Show Private Thread badge", + description: t("channelBadges.settings.showPrivateThreadBadge"), restartNeeded: true, }, showStageBadge: { type: OptionType.BOOLEAN, default: true, - description: "Show Stage badge", + description: t("channelBadges.settings.showStageBadge"), restartNeeded: true, }, showAnnouncementBadge: { type: OptionType.BOOLEAN, default: true, - description: "Show Announcement badge", + description: t("channelBadges.settings.showAnnouncementBadge"), restartNeeded: true, }, showForumBadge: { type: OptionType.BOOLEAN, default: true, - description: "Show Forum badge", + description: t("channelBadges.settings.showForumBadge"), restartNeeded: true, }, showMediaBadge: { type: OptionType.BOOLEAN, default: true, - description: "Show Media badge", + description: t("channelBadges.settings.showMediaBadge"), restartNeeded: true, }, showNSFWBadge: { type: OptionType.BOOLEAN, default: true, - description: "Show NSFW badge", + description: t("channelBadges.settings.showNSFWBadge"), restartNeeded: true, }, showLockedBadge: { type: OptionType.BOOLEAN, default: true, - description: "Show Locked badge", + description: t("channelBadges.settings.showLockedBadge"), restartNeeded: true, }, showRulesBadge: { type: OptionType.BOOLEAN, default: true, - description: "Show Rules badge", + description: t("channelBadges.settings.showRulesBadge"), restartNeeded: true, }, showUnknownBadge: { type: OptionType.BOOLEAN, default: true, - description: "Show Unknown badge", + description: t("channelBadges.settings.showUnknownBadge"), restartNeeded: true, }, textBadgeLabel: { type: OptionType.STRING, default: "Text", - description: "Text badge label", + description: t("channelBadges.settings.textBadgeLabel"), restartNeeded: true, }, voiceBadgeLabel: { type: OptionType.STRING, default: "Voice", - description: "Voice badge label", + description: t("channelBadges.settings.voiceBadgeLabel"), restartNeeded: true, }, categoryBadgeLabel: { type: OptionType.STRING, default: "Category", - description: "Category badge label", + description: t("channelBadges.settings.categoryBadgeLabel"), restartNeeded: true, }, announcementBadgeLabel: { type: OptionType.STRING, default: "News", - description: "Announcement badge label", + description: t("channelBadges.settings.announcementBadgeLabel"), restartNeeded: true, }, announcementThreadBadgeLabel: { type: OptionType.STRING, default: "News Thread", - description: "Announcement Thread badge label", + description: t("channelBadges.settings.announcementThreadBadgeLabel"), restartNeeded: true, }, publicThreadBadgeLabel: { type: OptionType.STRING, default: "Thread", - description: "Public Thread badge label", + description: t("channelBadges.settings.publicThreadBadgeLabel"), restartNeeded: true, }, privateThreadBadgeLabel: { type: OptionType.STRING, default: "Private Thread", - description: "Private Thread badge label", + description: t("channelBadges.settings.privateThreadBadgeLabel"), restartNeeded: true, }, stageBadgeLabel: { type: OptionType.STRING, default: "Stage", - description: "Stage badge label", + description: t("channelBadges.settings.stageBadgeLabel"), restartNeeded: true, }, directoryBadgeLabel: { type: OptionType.STRING, default: "Directory", - description: "Directory badge label", + description: t("channelBadges.settings.directoryBadgeLabel"), restartNeeded: true, }, forumBadgeLabel: { type: OptionType.STRING, default: "Forum", - description: "Forum badge label", + description: t("channelBadges.settings.forumBadgeLabel"), restartNeeded: true, }, mediaBadgeLabel: { type: OptionType.STRING, default: "Media", - description: "Media badge label", + description: t("channelBadges.settings.mediaBadgeLabel"), restartNeeded: true, }, nsfwBadgeLabel: { type: OptionType.STRING, default: "NSFW", - description: "NSFW badge label", + description: t("channelBadges.settings.nsfwBadgeLabel"), restartNeeded: true, }, lockedBadgeLabel: { type: OptionType.STRING, default: "Locked", - description: "Locked badge label", + description: t("channelBadges.settings.lockedBadgeLabel"), restartNeeded: true, }, rulesBadgeLabel: { type: OptionType.STRING, default: "Rules", - description: "Rules badge label", + description: t("channelBadges.settings.rulesBadgeLabel"), restartNeeded: true, }, unknownBadgeLabel: { type: OptionType.STRING, default: "Unknown", - description: "Unknown badge label", + description: t("channelBadges.settings.unknownBadgeLabel"), restartNeeded: true, }, textBadgeColor: { type: OptionType.STRING, - description: "Text badge color", + description: t("channelBadges.settings.textBadgeColor"), restartNeeded: true, }, voiceBadgeColor: { type: OptionType.STRING, - description: "Voice badge color", + description: t("channelBadges.settings.voiceBadgeColor"), restartNeeded: true, }, categoryBadgeColor: { type: OptionType.STRING, - description: "Category badge color", + description: t("channelBadges.settings.categoryBadgeColor"), restartNeeded: true, }, announcementBadgeColor: { type: OptionType.STRING, - description: "Announcement badge color", + description: t("channelBadges.settings.announcementBadgeColor"), restartNeeded: true, }, announcementThreadBadgeColor: { type: OptionType.STRING, - description: "Announcement Thread badge color", + description: t("channelBadges.settings.announcementThreadBadgeColor"), restartNeeded: true, }, publicThreadBadgeColor: { type: OptionType.STRING, - description: "Public Thread badge color", + description: t("channelBadges.settings.publicThreadBadgeColor"), restartNeeded: true, }, privateThreadBadgeColor: { type: OptionType.STRING, - description: "Private Thread badge color", + description: t("channelBadges.settings.privateThreadBadgeColor"), restartNeeded: true, }, stageBadgeColor: { type: OptionType.STRING, - description: "Stage badge color", + description: t("channelBadges.settings.stageBadgeColor"), restartNeeded: true, }, directoryBadgeColor: { type: OptionType.STRING, - description: "Directory badge color", + description: t("channelBadges.settings.directoryBadgeColor"), restartNeeded: true, }, forumBadgeColor: { type: OptionType.STRING, - description: "Forum badge color", + description: t("channelBadges.settings.forumBadgeColor"), restartNeeded: true, }, mediaBadgeColor: { type: OptionType.STRING, - description: "Media badge color", + description: t("channelBadges.settings.mediaBadgeColor"), restartNeeded: true, }, nsfwBadgeColor: { type: OptionType.STRING, - description: "NSFW badge color", + description: t("channelBadges.settings.nsfwBadgeColor"), restartNeeded: true, }, lockedBadgeColor: { type: OptionType.STRING, - description: "Locked badge color", + description: t("channelBadges.settings.lockedBadgeColor"), restartNeeded: true, }, rulesBadgeColor: { type: OptionType.STRING, - description: "Rules badge color", + description: t("channelBadges.settings.rulesBadgeColor"), restartNeeded: true, }, unknownBadgeColor: { type: OptionType.STRING, - description: "Unknown badge color", + description: t("channelBadges.settings.unknownBadgeColor"), restartNeeded: true, }, }); diff --git a/src/equicordplugins/channelTabs/index.tsx b/src/equicordplugins/channelTabs/index.tsx index 35e6888a3..0881f10db 100644 --- a/src/equicordplugins/channelTabs/index.tsx +++ b/src/equicordplugins/channelTabs/index.tsx @@ -9,6 +9,7 @@ import "./style.css"; import { findGroupChildrenByChildId, NavContextMenuPatchCallback } from "@api/ContextMenu"; import ErrorBoundary from "@components/ErrorBoundary"; import { Devs, EquicordDevs } from "@utils/constants"; +import { t } from "@utils/translation"; import definePlugin from "@utils/types"; import { Channel, Message } from "@vencord/discord-types"; import { ChannelStore, Menu } from "@webpack/common"; @@ -23,7 +24,7 @@ const contextMenuPatch: NavContextMenuPatchCallback = (children, props: { channe const menuItem = ( createTab({ guildId: channel.guild_id || "@me", // Normalize for DMs/Group Chats @@ -46,7 +47,7 @@ const contextMenuPatch: NavContextMenuPatchCallback = (children, props: { channe export default definePlugin({ name: "ChannelTabs", - description: "Group your commonly visited channels in tabs, like a browser", + description: t("channelTabs.description"), authors: [Devs.TheSun, Devs.TheKodeToad, EquicordDevs.keifufu, Devs.Nickyux, EquicordDevs.DiabeloDEV, EquicordDevs.justjxke], dependencies: ["ContextMenuAPI"], contextMenus: { diff --git a/src/equicordplugins/characterCounter/index.tsx b/src/equicordplugins/characterCounter/index.tsx index 6833f126d..c5acba8c1 100644 --- a/src/equicordplugins/characterCounter/index.tsx +++ b/src/equicordplugins/characterCounter/index.tsx @@ -8,20 +8,21 @@ import "./style.css"; import { definePluginSettings } from "@api/Settings"; import { Devs, EquicordDevs } from "@utils/constants"; +import { t } from "@utils/translation"; import definePlugin, { OptionType } from "@utils/types"; import { UserStore } from "@webpack/common"; const settings = definePluginSettings({ colorEffects: { type: OptionType.BOOLEAN, - description: "Turn on or off color effects for getting close to the character limit", + description: t("characterCounter.settings.colorEffects"), default: true, }, }); export default definePlugin({ name: "CharacterCounter", - description: "Adds a character counter to the chat input", + description: t("characterCounter.description"), authors: [EquicordDevs.creations, EquicordDevs.Panniku, Devs.thororen], settings, patches: [ diff --git a/src/equicordplugins/cleanChannelName/index.ts b/src/equicordplugins/cleanChannelName/index.ts index 822d5b5d2..c3671932c 100644 --- a/src/equicordplugins/cleanChannelName/index.ts +++ b/src/equicordplugins/cleanChannelName/index.ts @@ -5,13 +5,14 @@ */ import { Devs } from "@utils/constants"; +import { t } from "@utils/translation"; import definePlugin from "@utils/types"; import { Channel } from "@vencord/discord-types"; export default definePlugin({ name: "CleanChannelName", authors: [Devs.AutumnVN], - description: "remove all emoji and decor shit from channel names", + description: t("cleanChannelName.description"), patches: [ { find: "loadAllGuildAndPrivateChannelsFromDisk(){", diff --git a/src/equicordplugins/cleanerChannelGroups/index.ts b/src/equicordplugins/cleanerChannelGroups/index.ts index 73f5ba4ce..6ea3894f2 100644 --- a/src/equicordplugins/cleanerChannelGroups/index.ts +++ b/src/equicordplugins/cleanerChannelGroups/index.ts @@ -5,11 +5,12 @@ */ import { EquicordDevs } from "@utils/constants"; +import { t } from "@utils/translation"; import definePlugin from "@utils/types"; export default definePlugin({ name: "CleanerChannelGroups", - description: "Hides all channels in collapsed categories, even if they have unread messages.", + description: t("cleanerChannelGroups.description"), authors: [EquicordDevs.justjxke], patches: [ { diff --git a/src/equicordplugins/clientSideBlock/index.tsx b/src/equicordplugins/clientSideBlock/index.tsx index 80049e0c9..6182c5325 100644 --- a/src/equicordplugins/clientSideBlock/index.tsx +++ b/src/equicordplugins/clientSideBlock/index.tsx @@ -7,6 +7,7 @@ import { definePluginSettings } from "@api/Settings"; import { Paragraph } from "@components/Paragraph"; import { Devs, EquicordDevs } from "@utils/constants"; +import { t } from "@utils/translation"; import definePlugin, { OptionType } from "@utils/types"; import { GuildMember } from "@vencord/discord-types"; import { ChannelStore, GuildMemberStore, GuildRoleStore, React, RelationshipStore, UserStore } from "@webpack/common"; @@ -14,52 +15,52 @@ import { ChannelStore, GuildMemberStore, GuildRoleStore, React, RelationshipStor const settings = definePluginSettings({ hideVc: { type: OptionType.BOOLEAN, - description: "Hide voice channels containing blocked users.", + description: t("clientSideBlock.settings.hideVc"), default: false, restartNeeded: true }, usersToBlock: { type: OptionType.STRING, - description: "User IDs seperated by a comma and a space", + description: t("clientSideBlock.settings.usersToBlock"), restartNeeded: true, default: "" }, hideBlockedUsers: { type: OptionType.BOOLEAN, - description: "Should blocked users should also be hidden everywhere", + description: t("clientSideBlock.settings.hideBlockedUsers"), default: true, restartNeeded: true }, hideBlockedMessages: { type: OptionType.BOOLEAN, - description: "Should messages from blocked users should be hidden fully (same as the old noblockedmessages plugin)", + description: t("clientSideBlock.settings.hideBlockedMessages"), default: true, restartNeeded: true }, hideEmptyRoles: { type: OptionType.BOOLEAN, - description: "Should role headers be hidden if all of their members are blocked", + description: t("clientSideBlock.settings.hideEmptyRoles"), restartNeeded: true, default: true }, blockedReplyDisplay: { type: OptionType.SELECT, - description: "What should display instead of the message when someone replies to someone you have hidden", + description: t("clientSideBlock.settings.blockedReplyDisplay"), restartNeeded: true, options: [ - { value: "displayText", label: "Display text saying a hidden message was replied to", default: true }, - { value: "hideReply", label: "Literally nothing" } + { value: "displayText", label: t("clientSideBlock.settings.blockedReplyDisplayOptions.displayText"), default: true }, + { value: "hideReply", label: t("clientSideBlock.settings.blockedReplyDisplayOptions.hideReply") } ] }, guildBlackList: { type: OptionType.STRING, - description: "Guild ids to disable functionality in", + description: t("clientSideBlock.settings.guildBlackList"), restartNeeded: true, default: "" }, guildWhiteList: { type: OptionType.STRING, - description: "Guild ids to enable functionality in", + description: t("clientSideBlock.settings.guildWhiteList"), restartNeeded: true, default: "" } @@ -100,7 +101,7 @@ function hiddenReplyComponent() { case "displayText": return - ↓ Replying to blocked message + ↓ {t("clientSideBlock.reply.replyingToBlocked")} ; case "hideReply": @@ -141,7 +142,7 @@ function activeNowView(cards) { export default definePlugin({ name: "ClientSideBlock", - description: "Allows you to locally hide almost all content from any user", + description: t("clientSideBlock.description"), tags: ["blocked", "block", "hide", "hidden", "noblockedmessages"], authors: [Devs.Samwich, EquicordDevs.KamiRu], settings, diff --git a/src/equicordplugins/clipsEnhancements.discordDesktop/index.tsx b/src/equicordplugins/clipsEnhancements.discordDesktop/index.tsx index 5fa392b2c..634f76c77 100644 --- a/src/equicordplugins/clipsEnhancements.discordDesktop/index.tsx +++ b/src/equicordplugins/clipsEnhancements.discordDesktop/index.tsx @@ -8,6 +8,7 @@ import { definePluginSettings, migratePluginSettings } from "@api/Settings"; import { Button } from "@components/Button"; import { Devs, EquicordDevs } from "@utils/constants"; import { getIntlMessage } from "@utils/discord"; +import { t } from "@utils/translation"; import definePlugin, { OptionType } from "@utils/types"; import { Activity } from "@vencord/discord-types"; import { PresenceStore, SettingsRouter, UserStore } from "@webpack/common"; @@ -18,34 +19,34 @@ const extraFramerates = [45, 90, 120, 144, 165, 240]; const settings = definePluginSettings({ richPresenceTagging: { type: OptionType.SELECT, - description: "When should clips be tagged with the current Rich Presence?", + description: t("clipsEnhancements.settings.richPresenceTagging"), options: [ - { label: "Always", value: "always" }, - { label: "Only when beginning or end of activity name matches", value: "whenMatched", default: true }, - { label: "Never", value: "never" }, + { label: t("clipsEnhancements.settings.richPresenceTaggingOptions.always"), value: "always" }, + { label: t("clipsEnhancements.settings.richPresenceTaggingOptions.whenMatched"), value: "whenMatched", default: true }, + { label: t("clipsEnhancements.settings.richPresenceTaggingOptions.never"), value: "never" }, ] }, enableScreenshotKeybind: { type: OptionType.BOOLEAN, - description: "Enable the screenshot keybind feature", + description: t("clipsEnhancements.settings.enableScreenshotKeybind"), default: true, restartNeeded: true }, enableVoiceOnlyClips: { type: OptionType.BOOLEAN, - description: "Enable voice-only clips (audio without video)", + description: t("clipsEnhancements.settings.enableVoiceOnlyClips"), default: true, restartNeeded: true }, enableAdvancedSignals: { type: OptionType.BOOLEAN, - description: "Enable advanced clip signals (auto-clip triggers)", + description: t("clipsEnhancements.settings.enableAdvancedSignals"), default: true, restartNeeded: true }, ignorePlatformRestriction: { type: OptionType.BOOLEAN, - description: "Allow Platform Restricted Clipping (may cause save errors)", + description: t("clipsEnhancements.settings.ignorePlatformRestriction"), default: true, restartNeeded: true }, @@ -60,7 +61,7 @@ const settings = definePluginSettings({ SettingsRouter.openUserSettings("clips_panel"); }} > - Change FPS and duration options in Clips settings! + {t("clipsEnhancements.settings.clipsLink")} ); @@ -71,7 +72,7 @@ const settings = definePluginSettings({ migratePluginSettings("ClipsEnhancements", "TimelessClips"); export default definePlugin({ name: "ClipsEnhancements", - description: "Add more Clip FPS and duration options, custom clip length, RPC tagging and more", + description: t("clipsEnhancements.description"), authors: [Devs.niko, Devs.Joona, EquicordDevs.keircn], settings, patches: [ diff --git a/src/equicordplugins/commandPalette/index.tsx b/src/equicordplugins/commandPalette/index.tsx index ccb118eed..8371aa6d2 100644 --- a/src/equicordplugins/commandPalette/index.tsx +++ b/src/equicordplugins/commandPalette/index.tsx @@ -8,6 +8,7 @@ import { definePluginSettings } from "@api/Settings"; import { BaseText } from "@components/BaseText"; import { Button } from "@components/Button"; import { EquicordDevs, IS_MAC } from "@utils/constants"; +import { t } from "@utils/translation"; import definePlugin, { OptionType } from "@utils/types"; import { useEffect, useState } from "@webpack/common"; @@ -92,9 +93,9 @@ function KeybindRecorder() { return (
- Command Palette Hotkey + {t("commandPalette.ui.hotkeyTitle")} - Hotkey used to open the command palette + {t("commandPalette.ui.hotkeyDescription")} {error && ( @@ -111,14 +112,14 @@ function KeybindRecorder() { > {isListening ? ( - Press any key... + {t("commandPalette.ui.pressAnyKey")} ) : ( formatKeybind(currentKeybind) )}
@@ -127,31 +128,31 @@ function KeybindRecorder() { export const settings = definePluginSettings({ hotkey: { - description: "Hotkey used to open the command palette", + description: t("commandPalette.settings.hotkey"), type: OptionType.COMPONENT, default: DEFAULT_KEYS, component: KeybindRecorder }, visualStyle: { - description: "Palette appearance", + description: t("commandPalette.settings.visualStyle"), type: OptionType.SELECT, options: [ - { label: "Classic", value: "classic", default: true }, - { label: "Polished", value: "polished" } + { label: t("commandPalette.settings.visualStyleOptions.classic"), value: "classic", default: true }, + { label: t("commandPalette.settings.visualStyleOptions.polished"), value: "polished" } ] }, showTags: { - description: "Display tag chips for commands", + description: t("commandPalette.settings.showTags"), type: OptionType.BOOLEAN, default: true }, enableTagFilter: { - description: "Show the tag filter bar", + description: t("commandPalette.settings.enableTagFilter"), type: OptionType.BOOLEAN, default: true }, customCommands: { - description: "Manage custom command palette entries", + description: t("commandPalette.settings.customCommands"), type: OptionType.COMPONENT, component: CommandPaletteSettingsPanel } @@ -223,7 +224,7 @@ function hotkeyUsesModifiers() { export default definePlugin({ name: "CommandPalette", - description: "Quickly run actions through a searchable command palette", + description: t("commandPalette.description"), authors: [EquicordDevs.justjxke, EquicordDevs.Ethan], settings, patches: [ diff --git a/src/equicordplugins/components.dev/index.tsx b/src/equicordplugins/components.dev/index.tsx index 68f05fb63..c5c0bbc58 100644 --- a/src/equicordplugins/components.dev/index.tsx +++ b/src/equicordplugins/components.dev/index.tsx @@ -9,6 +9,7 @@ import "./styles.css"; import SettingsPlugin from "@plugins/_core/settings"; import { Devs } from "@utils/constants"; import { removeFromArray } from "@utils/misc"; +import { t } from "@utils/translation"; import definePlugin, { StartAt } from "@utils/types"; import { SettingsRouter } from "@webpack/common"; @@ -40,7 +41,7 @@ function ComponentsIcon(props: React.SVGProps) { export default definePlugin({ name: "Components", - description: "Adds a new tab to settings to browse Discord components.", + description: t("components.description"), authors: [Devs.prism], dependencies: ["Settings"], startAt: StartAt.WebpackReady, diff --git a/src/equicordplugins/contentWarning/index.tsx b/src/equicordplugins/contentWarning/index.tsx index cb2283c19..878368a4a 100644 --- a/src/equicordplugins/contentWarning/index.tsx +++ b/src/equicordplugins/contentWarning/index.tsx @@ -14,6 +14,7 @@ import { DeleteIcon } from "@components/Icons"; import { EquicordDevs } from "@utils/constants"; import { classNameFactory } from "@utils/css"; import { useForceUpdater } from "@utils/react"; +import { t } from "@utils/translation"; import definePlugin, { OptionType } from "@utils/types"; import { Button, TextInput, useState } from "@webpack/common"; @@ -93,7 +94,7 @@ function FlaggedInput({ index, forceUpdate }) { return (
- Flagged Words + {t("contentWarning.ui.flaggedWords")} {inputs} ); @@ -143,7 +144,7 @@ const settings = definePluginSettings({ }, onClick: { type: OptionType.BOOLEAN, - description: "Only show trigger content on click instead of hover", + description: t("contentWarning.settings.onClick"), default: false, } }); @@ -151,7 +152,7 @@ const settings = definePluginSettings({ export default definePlugin({ name: "ContentWarning", authors: [EquicordDevs.camila314], - description: "Allows you to specify certain trigger words that will be blurred by default. Hovering/Clicking on the blurred content will reveal it.", + description: t("contentWarning.description"), settings, patches: [ { diff --git a/src/equicordplugins/copyProfileColors/index.tsx b/src/equicordplugins/copyProfileColors/index.tsx index 256e86994..adb47535e 100644 --- a/src/equicordplugins/copyProfileColors/index.tsx +++ b/src/equicordplugins/copyProfileColors/index.tsx @@ -7,6 +7,7 @@ import { NavContextMenuPatchCallback } from "@api/ContextMenu"; import { copyToClipboard } from "@utils/clipboard"; import { EquicordDevs } from "@utils/constants"; +import { t } from "@utils/translation"; import definePlugin from "@utils/types"; import { Menu, Toasts, UserProfileStore } from "@webpack/common"; @@ -34,7 +35,7 @@ function copyProfileColors(userId) { if (!colors) { Toasts.show({ type: Toasts.Type.FAILURE, - message: "No profile colors found!", + message: t("copyProfileColors.toast.noColorsFound"), id: Toasts.genId() }); return; @@ -49,14 +50,14 @@ function copyProfileColors(userId) { copyToClipboard(formattedColors); Toasts.show({ type: Toasts.Type.SUCCESS, - message: "Profile colors copied to clipboard!", + message: t("copyProfileColors.toast.copied"), id: Toasts.genId() }); } catch (e) { console.error("Failed to copy to clipboard:", e); Toasts.show({ type: Toasts.Type.FAILURE, - message: "Error copying profile colors!", + message: t("copyProfileColors.toast.error"), id: Toasts.genId() }); } @@ -81,7 +82,7 @@ const userContextMenuPatch: NavContextMenuPatchCallback = (children, { user }) = copyProfileColors(user.id)} /> ); @@ -89,7 +90,7 @@ const userContextMenuPatch: NavContextMenuPatchCallback = (children, { user }) = export default definePlugin({ name: "CopyProfileColors", - description: "A plugin to copy people's profile gradient colors to clipboard.", + description: t("copyProfileColors.description"), authors: [EquicordDevs.Crxa, EquicordDevs.Cortex], contextMenus: { "user-context": userContextMenuPatch, diff --git a/src/equicordplugins/copyStatusUrls/index.ts b/src/equicordplugins/copyStatusUrls/index.ts index c05692269..3996492ca 100644 --- a/src/equicordplugins/copyStatusUrls/index.ts +++ b/src/equicordplugins/copyStatusUrls/index.ts @@ -6,6 +6,7 @@ import { copyToClipboard } from "@utils/clipboard"; import { Devs } from "@utils/constants"; +import { t } from "@utils/translation"; import definePlugin from "@utils/types"; import { User } from "@vencord/discord-types"; import { findByCodeLazy } from "@webpack"; @@ -22,7 +23,7 @@ const getMetadataFromApi: (activity: any, userId: string) => Promise = find export default definePlugin({ name: "CopyStatusUrls", - description: "Copy the users status url when you right-click it", + description: t("copyStatusUrls.description"), authors: [Devs.sadan], patches: [ @@ -45,7 +46,7 @@ export default definePlugin({ copyToClipboard(button_urls[index]); Toasts.show({ id: Toasts.genId(), - message: "Copied URL", + message: t("copyStatusUrls.toast.copied"), type: Toasts.Type.SUCCESS, options: { position: Toasts.Position.TOP @@ -55,7 +56,7 @@ export default definePlugin({ console.error(e); Toasts.show({ id: Toasts.genId(), - message: "Error copying URL, check console for more info", + message: t("copyStatusUrls.toast.error"), type: Toasts.Type.FAILURE, options: { position: Toasts.Position.TOP diff --git a/src/equicordplugins/copyUserMention/index.tsx b/src/equicordplugins/copyUserMention/index.tsx index e11eda7e0..cbd21f9e6 100644 --- a/src/equicordplugins/copyUserMention/index.tsx +++ b/src/equicordplugins/copyUserMention/index.tsx @@ -7,6 +7,7 @@ import { NavContextMenuPatchCallback } from "@api/ContextMenu"; import { copyToClipboard } from "@utils/clipboard"; import { Devs, EquicordDevs } from "@utils/constants"; +import { t } from "@utils/translation"; import definePlugin from "@utils/types"; import type { Channel, User } from "@vencord/discord-types"; import { Menu } from "@webpack/common"; @@ -37,7 +38,7 @@ const UserContextMenuPatch: NavContextMenuPatchCallback = (children, { user }: U children.push( copyToClipboard(`<@${user.id}>`)} icon={MentionIcon} /> @@ -47,7 +48,7 @@ const UserContextMenuPatch: NavContextMenuPatchCallback = (children, { user }: U export default definePlugin({ name: "CopyUserMention", authors: [EquicordDevs.Cortex, Devs.castdrian], - description: "Adds a button to copy user's mention on the user context menu, works best with ValidUser.", + description: t("copyUserMention.description"), contextMenus: { "user-context": UserContextMenuPatch } diff --git a/src/equicordplugins/cursorBuddy/index.tsx b/src/equicordplugins/cursorBuddy/index.tsx index 478d41cb8..bde461702 100644 --- a/src/equicordplugins/cursorBuddy/index.tsx +++ b/src/equicordplugins/cursorBuddy/index.tsx @@ -12,6 +12,7 @@ import { Divider } from "@components/Divider"; import { Heading } from "@components/Heading"; import { Devs, EquicordDevs } from "@utils/constants"; import { classNameFactory } from "@utils/css"; +import { t } from "@utils/translation"; import definePlugin, { OptionType } from "@utils/types"; import { ColorPicker } from "@webpack/common"; @@ -54,7 +55,7 @@ function OnekoColorSettings() {
- Fur Color + {t("cursorBuddy.ui.furColor")}
- Outline Color + {t("cursorBuddy.ui.outlineColor")}
value >= 0 || "Speed must be bigger than 0", onChange: load, }, fps: { - description: "Framerate of your buddy", + description: t("cursorBuddy.settings.fps"), type: OptionType.NUMBER, default: 24, isValid: (value: number) => value > 0 || "Framerate must be bigger than 0", @@ -125,14 +126,14 @@ const settings = definePluginSettings({ component: OnekoColorSettings, }, furColor: { - description: "Fur hex color for Oneko", + description: t("cursorBuddy.settings.furColor"), type: OptionType.STRING, default: "#FFFFFF", onChange: load, hidden: true, }, outlineColor: { - description: "Outline hex color for Oneko", + description: t("cursorBuddy.settings.outlineColor"), type: OptionType.STRING, default: "#000000", onChange: load, @@ -149,26 +150,26 @@ const settings = definePluginSettings({ ), }, size: { - description: "Size of the fatass horse", + description: t("cursorBuddy.settings.size"), type: OptionType.NUMBER, default: 120, isValid: (value: number) => value > 0 || "Size must be bigger than 0", onChange: load }, fade: { - description: "If the horse should fade when the cursor is near", + description: t("cursorBuddy.settings.fade"), type: OptionType.BOOLEAN, default: true, onChange: load }, freeroam: { - description: "If the horse should roam freely when idle", + description: t("cursorBuddy.settings.freeroam"), type: OptionType.BOOLEAN, default: true, onChange: load }, shake: { - description: "If the horse should shake the window when it's walking", + description: t("cursorBuddy.settings.shake"), type: OptionType.BOOLEAN, default: false, onChange: load, @@ -192,7 +193,7 @@ const settings = definePluginSettings({ disabled() { return this.store.buddy !== "fathorse"; }, }, shake: { - disabled() { return this.store.buddy !== "fathorse"; }, + disabled() { return this.store.buddy !== "fathorse"; } } }); @@ -234,7 +235,7 @@ function load() { migratePluginSettings("CursorBuddy", "Oneko", "oneko"); export default definePlugin({ name: "CursorBuddy", - description: "Adds a sprite that follows your cursor.", + description: t("cursorBuddy.description"), authors: [Devs.Ven, Devs.adryd, EquicordDevs.nexpid, EquicordDevs.ZcraftElite], tags: ["Oneko", "FatassHorse", "Pet"], settings, diff --git a/src/equicordplugins/customFolderIcons/index.tsx b/src/equicordplugins/customFolderIcons/index.tsx index eecc37762..05a7e1687 100644 --- a/src/equicordplugins/customFolderIcons/index.tsx +++ b/src/equicordplugins/customFolderIcons/index.tsx @@ -5,6 +5,7 @@ */ import { EquicordDevs } from "@utils/constants"; +import { t } from "@utils/translation"; import definePlugin from "@utils/types"; import { makeContextItem } from "./components"; @@ -13,7 +14,7 @@ import { folderProp, int2rgba } from "./util"; export default definePlugin({ name: "CustomFolderIcons", - description: "Customize folder icons with any png", + description: t("customFolderIcons.description"), authors: [EquicordDevs.sadan], settings, patches: [ diff --git a/src/equicordplugins/customSounds/index.tsx b/src/equicordplugins/customSounds/index.tsx index 7af13bd02..bfd06ce6d 100644 --- a/src/equicordplugins/customSounds/index.tsx +++ b/src/equicordplugins/customSounds/index.tsx @@ -12,6 +12,7 @@ import { definePluginSettings } from "@api/Settings"; import { Heading } from "@components/Heading"; import { Devs } from "@utils/constants"; import { classNameFactory } from "@utils/css"; +import { t } from "@utils/translation"; import definePlugin, { OptionType, StartAt } from "@utils/types"; import { Button, React, showToast, TextInput } from "@webpack/common"; @@ -245,7 +246,7 @@ const settings = definePluginSettings({ }); dataUriCache.clear(); setResetTrigger(prev => prev + 1); - showToast("All overrides reset successfully!"); + showToast(t("customSounds.toast.resetSuccess")); }; const triggerFileUpload = () => { @@ -277,10 +278,10 @@ const settings = definePluginSettings({ } setResetTrigger(prev => prev + 1); - showToast("Settings imported successfully!"); + showToast(t("customSounds.toast.importSuccess")); } catch (error) { console.error("Error importing settings:", error); - showToast("Error importing settings. Check console for details."); + showToast(t("customSounds.toast.importError")); } }; @@ -314,7 +315,7 @@ const settings = definePluginSettings({ a.click(); URL.revokeObjectURL(url); - showToast(`Exported ${overrides.length} settings (audio files not included)`); + showToast(t("customSounds.toast.exportSuccess", { count: overrides.length })); }; const filteredSoundTypes = allSoundTypes.filter(type => @@ -325,10 +326,10 @@ const settings = definePluginSettings({ return (
- - - - + + + +
- Search Sounds + {t("customSounds.settings.searchSounds")} setSearchQuery(e)} - placeholder="Search by name or ID" + placeholder={t("customSounds.settings.searchPlaceholder")} />
@@ -365,7 +366,7 @@ const settings = definePluginSettings({ await ensureDataURICached(currentOverride.selectedFileId); } catch (error) { console.error(`[CustomSounds] Failed to cache data URI for ${type.id}:`, error); - showToast("Error loading custom sound file"); + showToast(t("customSounds.toast.loadError")); } } @@ -392,7 +393,7 @@ export function findOverride(id: string): SoundOverride | null { export default definePlugin({ name: "CustomSounds", - description: "Customize Discord's sounds.", + description: t("customSounds.description"), authors: [Devs.ScattrdBlade, Devs.TheKodeToad], settings, startAt: StartAt.Init, diff --git a/src/equicordplugins/customTimestamps/index.tsx b/src/equicordplugins/customTimestamps/index.tsx index 9aa55258a..73e2f94ac 100644 --- a/src/equicordplugins/customTimestamps/index.tsx +++ b/src/equicordplugins/customTimestamps/index.tsx @@ -14,6 +14,7 @@ import { Paragraph } from "@components/Paragraph"; import { Devs, EquicordDevs } from "@utils/constants"; import { Margins } from "@utils/margins"; import { useForceUpdater } from "@utils/react"; +import { t } from "@utils/translation"; import definePlugin, { OptionType } from "@utils/types"; import { moment, TextInput, useEffect, useState } from "@webpack/common"; @@ -74,7 +75,7 @@ const TimeRow = (props: TimeRowProps) => { const settings = definePluginSettings({ formats: { type: OptionType.COMPONENT, - description: "Customize the timestamp formats", + description: t("customTimestamps.settings.formats"), component: componentProps => { const [settingsState, setSettingsState] = useState(useSettings().plugins?.CustomTimestamps?.formats ?? {}); @@ -92,9 +93,9 @@ const settings = definePluginSettings({ {key === "sameDayFormat" && (
- Calendar formats + {t("customTimestamps.settings.calendarFormats")} - How to format the [calendar] value if used in the above timestamps. + {t("customTimestamps.settings.calendarFormatsDescription")}
)} @@ -124,19 +125,18 @@ const settings = definePluginSettings({ export default definePlugin({ name: "CustomTimestamps", - description: "Custom timestamps on messages and tooltips", + description: t("customTimestamps.description"), authors: [Devs.Rini, EquicordDevs.nvhhr, EquicordDevs.Suffocate, Devs.Obsidian], settings, settingsAboutComponent: () => (
- How to use: + {t("customTimestamps.about.title")} Moment.js formatting documentation
- Additionally you can use these in your inputs:
- [calendar] enables dynamic date formatting such - as "Today" or "Yesterday".
- [relative] gives you times such as "4 hours ago".
+ {t("customTimestamps.about.additional")}
+ [calendar] {t("customTimestamps.about.calendar")}
+ [relative] {t("customTimestamps.about.relative")}
diff --git a/src/equicordplugins/customUserColors/index.tsx b/src/equicordplugins/customUserColors/index.tsx index db4db60e5..9d56c38d1 100644 --- a/src/equicordplugins/customUserColors/index.tsx +++ b/src/equicordplugins/customUserColors/index.tsx @@ -11,6 +11,7 @@ import { get } from "@api/DataStore"; import { definePluginSettings, Settings } from "@api/Settings"; import { EquicordDevs } from "@utils/constants"; import { openModal } from "@utils/modal"; +import { t } from "@utils/translation"; import definePlugin, { OptionType } from "@utils/types"; import { Channel, User } from "@vencord/discord-types"; import { extractAndLoadChunksLazy } from "@webpack"; @@ -46,7 +47,7 @@ const userContextMenuPatch: NavContextMenuPatchCallback = (children, { user }: { const setCustomColorItem = ( { @@ -64,7 +65,7 @@ const channelContextMenuPatch: NavContextMenuPatchCallback = (children, { channe const setCustomColorItem = ( { @@ -87,19 +88,19 @@ export function getCustomColorString(id: string | undefined, withHash?: boolean) const settings = definePluginSettings({ dmList: { type: OptionType.BOOLEAN, - description: "Users with custom colors defined will have their name in the dm list colored", + description: t("customUserColors.settings.dmList"), default: true, }, colorInServers: { type: OptionType.BOOLEAN, - description: "If name colors should be changed within servers", + description: t("customUserColors.settings.colorInServers"), default: true, } }); export default definePlugin({ name: "CustomUserColors", - description: "Lets you add a custom color to any user, anywhere! Highly recommend to use with typingTweaks and roleColorEverywhere", + description: t("customUserColors.description"), authors: [EquicordDevs.mochienya], contextMenus: { "user-context": userContextMenuPatch, diff --git a/src/equicordplugins/disableCameras/index.tsx b/src/equicordplugins/disableCameras/index.tsx index aa928134b..a78423132 100644 --- a/src/equicordplugins/disableCameras/index.tsx +++ b/src/equicordplugins/disableCameras/index.tsx @@ -5,11 +5,12 @@ */ import { Devs } from "@utils/constants"; +import { t } from "@utils/translation"; import definePlugin from "@utils/types"; export default definePlugin({ name: "DisableCameras", - description: "Disables cameras in a call by default", + description: t("disableCameras.description"), authors: [Devs.Joona], patches: [ { diff --git a/src/equicordplugins/discordDevBanner/index.tsx b/src/equicordplugins/discordDevBanner/index.tsx index 4e56bd288..268e4ac60 100644 --- a/src/equicordplugins/discordDevBanner/index.tsx +++ b/src/equicordplugins/discordDevBanner/index.tsx @@ -7,13 +7,14 @@ import "./styles.css"; import { Devs, EquicordDevs } from "@utils/constants"; +import { t } from "@utils/translation"; import definePlugin from "@utils/types"; import { makeDevBanner, settings } from "./components"; export default definePlugin({ name: "DiscordDevBanner", - description: "Enables the Discord developer banner, in which displays the build-ID", + description: t("discordDevBanner.description"), authors: [EquicordDevs.KrystalSkull, Devs.thororen], settings, patches: [ diff --git a/src/equicordplugins/dragFavoriteEmotes/index.tsx b/src/equicordplugins/dragFavoriteEmotes/index.tsx index 2b8e6b096..51887eeb0 100644 --- a/src/equicordplugins/dragFavoriteEmotes/index.tsx +++ b/src/equicordplugins/dragFavoriteEmotes/index.tsx @@ -1,26 +1,15 @@ /* - * Vencord, a modification for Discord's desktop app - * Copyright (c) 2024 Vendicated and contributors - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . -*/ + * Vencord, a Discord client mod + * Copyright (c) 2026 Vendicated and contributors + * SPDX-License-Identifier: GPL-3.0-or-later + */ import "./styles.css"; import { EquicordDevs } from "@utils/constants"; import { classNameFactory } from "@utils/css"; import { classes } from "@utils/misc"; +import { t } from "@utils/translation"; import definePlugin from "@utils/types"; import { findByPropsLazy, findCssClassesLazy } from "@webpack"; import { useDrag, useDrop, useLayoutEffect, useRef, UserSettingsActionCreators } from "@webpack/common"; @@ -44,7 +33,7 @@ type EmojiDescriptor = { export default definePlugin({ name: "DragFavoriteEmotes", authors: [EquicordDevs.PWall], - description: "Adds the ability to change the order of your favourite emotes", + description: t("dragFavoriteEmotes.description"), patches: [ { find: "#{intl::EMOJI_FAVORITE_TOOLTIP}", diff --git a/src/equicordplugins/dragify/index.tsx b/src/equicordplugins/dragify/index.tsx index 47b6a5469..678449f1e 100644 --- a/src/equicordplugins/dragify/index.tsx +++ b/src/equicordplugins/dragify/index.tsx @@ -10,6 +10,7 @@ import { definePluginSettings } from "@api/Settings"; import { EquicordDevs } from "@utils/constants"; import { getGuildAcronym, insertTextIntoChatInputBox } from "@utils/discord"; import { Logger } from "@utils/Logger"; +import { t } from "@utils/translation"; import definePlugin, { OptionType } from "@utils/types"; import type { Channel } from "@vencord/discord-types"; import { ChannelType } from "@vencord/discord-types/enums"; @@ -74,61 +75,61 @@ function shouldIgnoreDrop(key: string): boolean { const settings = definePluginSettings({ userOutput: { type: OptionType.SELECT, - description: "User drop output.", + description: t("dragify.settings.userOutput"), options: [ - { label: "Mention user", value: "mention", default: true }, - { label: "User ID", value: "id" }, + { label: t("dragify.settings.userOutputOptions.mention"), value: "mention", default: true }, + { label: t("dragify.settings.userOutputOptions.id"), value: "id" }, ], }, channelOutput: { type: OptionType.SELECT, - description: "Channel drop output.", + description: t("dragify.settings.channelOutput"), options: [ - { label: "#channel mention", value: "mention", default: true }, - { label: "Channel link", value: "link" }, + { label: t("dragify.settings.channelOutputOptions.mention"), value: "mention", default: true }, + { label: t("dragify.settings.channelOutputOptions.link"), value: "link" }, ], }, inviteExpireAfter: { type: OptionType.SELECT, - description: "Invite expiration.", + description: t("dragify.settings.inviteExpireAfter"), options: [ - { label: "30 minutes", value: 1800 }, - { label: "1 hour", value: 3600 }, - { label: "6 hours", value: 21600 }, - { label: "12 hours", value: 43200 }, - { label: "1 day", value: 86400 }, - { label: "7 days", value: 604800 }, - { label: "Never", value: 0, default: true }, + { label: t("dragify.settings.inviteExpireAfterOptions.30min"), value: 1800 }, + { label: t("dragify.settings.inviteExpireAfterOptions.1hour"), value: 3600 }, + { label: t("dragify.settings.inviteExpireAfterOptions.6hours"), value: 21600 }, + { label: t("dragify.settings.inviteExpireAfterOptions.12hours"), value: 43200 }, + { label: t("dragify.settings.inviteExpireAfterOptions.1day"), value: 86400 }, + { label: t("dragify.settings.inviteExpireAfterOptions.7days"), value: 604800 }, + { label: t("dragify.settings.inviteExpireAfterOptions.never"), value: 0, default: true }, ], }, inviteMaxUses: { type: OptionType.SELECT, - description: "Invite max uses.", + description: t("dragify.settings.inviteMaxUses"), options: [ - { label: "No limit", value: 0, default: true }, - { label: "1 use", value: 1 }, - { label: "5 uses", value: 5 }, - { label: "10 uses", value: 10 }, - { label: "25 uses", value: 25 }, - { label: "50 uses", value: 50 }, - { label: "100 uses", value: 100 }, + { label: t("dragify.settings.inviteMaxUsesOptions.noLimit"), value: 0, default: true }, + { label: t("dragify.settings.inviteMaxUsesOptions.1use"), value: 1 }, + { label: t("dragify.settings.inviteMaxUsesOptions.5uses"), value: 5 }, + { label: t("dragify.settings.inviteMaxUsesOptions.10uses"), value: 10 }, + { label: t("dragify.settings.inviteMaxUsesOptions.25uses"), value: 25 }, + { label: t("dragify.settings.inviteMaxUsesOptions.50uses"), value: 50 }, + { label: t("dragify.settings.inviteMaxUsesOptions.100uses"), value: 100 }, ], }, inviteTemporaryMembership: { type: OptionType.BOOLEAN, default: false, - description: "Grant temporary membership.", + description: t("dragify.settings.inviteTemporaryMembership"), }, reuseExistingInvites: { type: OptionType.BOOLEAN, default: false, - description: "Reuse existing invite instead of creating a new one.", + description: t("dragify.settings.reuseExistingInvites"), }, allowChatBodyDrop: { type: OptionType.BOOLEAN, default: false, restartNeeded: true, - description: "Allow dropping into the main chat body to insert text.", + description: t("dragify.settings.allowChatBodyDrop"), }, }); @@ -159,7 +160,7 @@ const inviteCache = new Map setIsListening(true)} > - {isListening ? "Recording..." : } + {isListening ? t("elementHighlighter.ui.recording") : }
); @@ -94,48 +95,48 @@ function KeybindRecorder() { const settings = definePluginSettings({ keybind: { - description: "Toggle Highlighter", + description: t("elementHighlighter.settings.keybind"), type: OptionType.COMPONENT, default: DEFAULT_KEYBIND, component: KeybindRecorder }, showClasses: { - description: "Display the element's CSS class names in the tooltip", + description: t("elementHighlighter.settings.showClasses"), type: OptionType.BOOLEAN, default: false }, showId: { - description: "Display the element's ID attribute in the tooltip", + description: t("elementHighlighter.settings.showId"), type: OptionType.BOOLEAN, default: false }, showFont: { - description: "Display the computed font family and font size", + description: t("elementHighlighter.settings.showFont"), type: OptionType.BOOLEAN, default: false }, showPadding: { - description: "Display the element's padding values", + description: t("elementHighlighter.settings.showPadding"), type: OptionType.BOOLEAN, default: false }, showMargin: { - description: "Display the element's margin values", + description: t("elementHighlighter.settings.showMargin"), type: OptionType.BOOLEAN, default: false }, showBorderRadius: { - description: "Display the element's border-radius values", + description: t("elementHighlighter.settings.showBorderRadius"), type: OptionType.BOOLEAN, default: false }, showPosition: { - description: "Display the element's CSS position type and z-index", + description: t("elementHighlighter.settings.showPosition"), type: OptionType.BOOLEAN, default: false }, showDisplay: { - description: "Display the element's display type along with flex or grid properties", + description: t("elementHighlighter.settings.showDisplay"), type: OptionType.BOOLEAN, default: false } @@ -354,7 +355,7 @@ function onClick(e: MouseEvent) { if (!el || el === overlay || el === tooltip) return; const colorVar = getColorVar(el); - if (colorVar) copyWithToast(colorVar, "Copied color to clipboard!"); + if (colorVar) copyWithToast(colorVar, t("elementHighlighter.ui.copiedColor")); } function onKeyDown(e: KeyboardEvent) { @@ -448,7 +449,7 @@ function onToggle(e: KeyboardEvent) { export default definePlugin({ name: "ElementHighlighter", - description: "Highlight and inspect elements easily.", + description: t("elementHighlighter.description"), authors: [Devs.prism], settings, diff --git a/src/equicordplugins/equicordHelper/index.tsx b/src/equicordplugins/equicordHelper/index.tsx index 5459e8edb..dbab9e621 100644 --- a/src/equicordplugins/equicordHelper/index.tsx +++ b/src/equicordplugins/equicordHelper/index.tsx @@ -11,6 +11,7 @@ import { definePluginSettings } from "@api/Settings"; import customRPC from "@plugins/customRPC"; import { Devs, EquicordDevs, GUILD_ID, SUPPORT_CHANNEL_ID, SUPPORT_CHANNEL_IDS, VC_SUPPORT_CHANNEL_IDS } from "@utils/constants"; import { isAnyPluginDev } from "@utils/misc"; +import { t } from "@utils/translation"; import definePlugin, { OptionType } from "@utils/types"; import { StandingState } from "@vencord/discord-types/enums"; import { findByCodeLazy, findExportedComponentLazy, findStoreLazy } from "@webpack"; @@ -28,11 +29,11 @@ const WarningIcon = findExportedComponentLazy("WarningIcon"); const ShieldIcon = findExportedComponentLazy("ShieldIcon"); const StandingConfig: Record; }> = { - [StandingState.ALL_GOOD]: { label: "All good!", hoverColor: "var(--status-positive)", Icon: ShieldIcon }, - [StandingState.LIMITED]: { label: "Limited", hoverColor: "var(--status-warning)", Icon: WarningIcon }, - [StandingState.VERY_LIMITED]: { label: "Very limited", hoverColor: "var(--orange-345)", Icon: WarningIcon }, - [StandingState.AT_RISK]: { label: "At risk", hoverColor: "var(--status-danger)", Icon: WarningIcon }, - [StandingState.SUSPENDED]: { label: "Suspended", hoverColor: "var(--interactive-muted)", Icon: WarningIcon }, + [StandingState.ALL_GOOD]: { label: t("equicordHelper.standing.allGood"), hoverColor: "var(--status-positive)", Icon: ShieldIcon }, + [StandingState.LIMITED]: { label: t("equicordHelper.standing.limited"), hoverColor: "var(--status-warning)", Icon: WarningIcon }, + [StandingState.VERY_LIMITED]: { label: t("equicordHelper.standing.veryLimited"), hoverColor: "var(--orange-345)", Icon: WarningIcon }, + [StandingState.AT_RISK]: { label: t("equicordHelper.standing.atRisk"), hoverColor: "var(--status-danger)", Icon: WarningIcon }, + [StandingState.SUSPENDED]: { label: t("equicordHelper.standing.suspended"), hoverColor: "var(--interactive-muted)", Icon: WarningIcon }, }; function StandingButton() { @@ -61,42 +62,42 @@ function StandingButton() { const settings = definePluginSettings({ noMirroredCamera: { type: OptionType.BOOLEAN, - description: "Prevents the camera from being mirrored on your screen", + description: t("equicordHelper.settings.noMirroredCamera"), restartNeeded: true, default: false, }, removeActivitySection: { type: OptionType.BOOLEAN, - description: "Removes the activity section above member list", + description: t("equicordHelper.settings.removeActivitySection"), restartNeeded: true, default: false, }, showYourOwnActivityButtons: { type: OptionType.BOOLEAN, - description: "Discord hides your own activity buttons for some reason", + description: t("equicordHelper.settings.showYourOwnActivityButtons"), restartNeeded: true, default: false, }, noDefaultHangStatus: { type: OptionType.BOOLEAN, - description: "Disable the default hang status when joining voice channels", + description: t("equicordHelper.settings.noDefaultHangStatus"), restartNeeded: true, default: false, }, refreshSlashCommands: { type: OptionType.BOOLEAN, - description: "Refreshes Slash Commands to show newly added commands without restarting your client.", + description: t("equicordHelper.settings.refreshSlashCommands"), default: false, }, forceRoleIcon: { type: OptionType.BOOLEAN, - description: "Forces role icons to display next to messages in compact mode", + description: t("equicordHelper.settings.forceRoleIcon"), restartNeeded: true, default: false }, accountStandingButton: { type: OptionType.BOOLEAN, - description: "Show an account standing button in the header bar", + description: t("equicordHelper.settings.accountStandingButton"), default: false, restartNeeded: true, } @@ -104,7 +105,7 @@ const settings = definePluginSettings({ export default definePlugin({ name: "EquicordHelper", - description: "Used to provide support, fix discord caused crashes, and other misc features.", + description: t("equicordHelper.description"), authors: [Devs.thororen, EquicordDevs.nyx, EquicordDevs.Naibuu, EquicordDevs.keircn, EquicordDevs.SerStars, EquicordDevs.mart], required: true, settings, @@ -218,13 +219,13 @@ export default definePlugin({ if (!selfId || isAnyPluginDev(selfId)) return; if (VC_SUPPORT_CHANNEL_IDS.includes(channelId) && !clicked) { return Alerts.show({ - title: "Vencord Support Channel Warning", - body: "Before asking for help. Check updates and if this issue is actually caused by Equicord!", - confirmText: "Equicord Support", + title: t("equicordHelper.alerts.supportWarningTitle"), + body: t("equicordHelper.alerts.supportWarningBody"), + confirmText: t("equicordHelper.alerts.equicordSupport"), onConfirm() { NavigationRouter.transitionTo(`/channels/${GUILD_ID}/${SUPPORT_CHANNEL_ID}`); }, - cancelText: "Okay continue", + cancelText: t("equicordHelper.alerts.okayContinue"), onCancel() { clicked = true; }, @@ -235,17 +236,17 @@ export default definePlugin({ commands: [ { name: "refresh-commands", - description: "Refresh Slash Commands", + description: t("equicordHelper.commands.refreshCommands"), inputType: ApplicationCommandInputType.BUILT_IN, predicate: () => settings.store.refreshSlashCommands, execute: async (opts, ctx) => { try { ApplicationCommandIndexStore.indices = {}; - sendBotMessage(ctx.channel.id, { content: "Slash Commands refreshed successfully." }); + sendBotMessage(ctx.channel.id, { content: t("equicordHelper.commands.refreshSuccess") }); } catch (e) { console.error("[refreshSlashCommands] Failed to refresh commands:", e); - sendBotMessage(ctx.channel.id, { content: "Failed to refresh commands. Check console for details." }); + sendBotMessage(ctx.channel.id, { content: t("equicordHelper.commands.refreshFailed") }); } } } diff --git a/src/equicordplugins/equicordToolbox/index.tsx b/src/equicordplugins/equicordToolbox/index.tsx index 5a6b32394..6565f5464 100644 --- a/src/equicordplugins/equicordToolbox/index.tsx +++ b/src/equicordplugins/equicordToolbox/index.tsx @@ -21,6 +21,7 @@ import "./styles.css"; import { HeaderBarButton } from "@api/HeaderBar"; import { definePluginSettings, migratePluginSettings } from "@api/Settings"; import { Devs } from "@utils/constants"; +import { t } from "@utils/translation"; import definePlugin, { OptionType } from "@utils/types"; import { Popout, useRef, useState } from "@webpack/common"; @@ -30,7 +31,7 @@ export const settings = definePluginSettings({ showPluginMenu: { type: OptionType.BOOLEAN, default: true, - description: "Show the plugins menu in the toolbox", + description: t("equicordToolbox.settings.showPluginMenu"), } }); @@ -64,7 +65,7 @@ function VencordPopoutButton() { ref={buttonRef} className="vc-toolbox-btn" onClick={() => setShow(v => !v)} - tooltip={isShown ? null : "Equicord Toolbox"} + tooltip={isShown ? null : t("equicordToolbox.ui.tooltip")} icon={Icon} selected={isShown} /> @@ -76,7 +77,7 @@ function VencordPopoutButton() { migratePluginSettings("EquicordToolbox", "VencordToolbox"); export default definePlugin({ name: "EquicordToolbox", - description: "Adds a button next to the inbox button in the channel header that houses Equicord quick actions", + description: t("equicordToolbox.description"), authors: [Devs.Ven, Devs.AutumnVN], dependencies: ["HeaderBarAPI"], diff --git a/src/equicordplugins/equicordToolbox/menu.tsx b/src/equicordplugins/equicordToolbox/menu.tsx index 1f2f45057..f225b4122 100644 --- a/src/equicordplugins/equicordToolbox/menu.tsx +++ b/src/equicordplugins/equicordToolbox/menu.tsx @@ -10,6 +10,7 @@ import { Settings, useSettings } from "@api/Settings"; import { openPluginModal, openSettingsTabModal, PluginsTab, ThemesTab } from "@components/settings"; import { useAwaiter } from "@utils/react"; import { wordsFromCamel, wordsToTitle } from "@utils/text"; +import { t } from "@utils/translation"; import { OptionType, Plugin } from "@utils/types"; import { Menu, showToast, useMemo, useState } from "@webpack/common"; import type { ReactNode } from "react"; @@ -27,7 +28,7 @@ function buildPluginMenu() { return ( openSettingsTabModal(PluginsTab)} > {pluginEntries} @@ -103,7 +104,7 @@ export function buildPluginMenuEntries(includeEmpty = false) { checked={s[key]} action={() => { s[key] = !s[key]; - if (option.restartNeeded) showToast("Restart to apply the change"); + if (option.restartNeeded) showToast(t("equicordToolbox.ui.restartToApply")); }} /> ); @@ -120,7 +121,7 @@ export function buildPluginMenuEntries(includeEmpty = false) { checked={s[key] === opt.value} action={() => { s[key] = opt.value; - if (option.restartNeeded) showToast("Restart to apply the change"); + if (option.restartNeeded) showToast(t("equicordToolbox.ui.restartToApply")); }} /> ))} @@ -188,7 +189,7 @@ export function buildThemeMenu() { return ( openSettingsTabModal(ThemesTab)} > {buildThemeMenuEntries()} @@ -205,19 +206,19 @@ export function buildThemeMenuEntries() { { Settings.useQuickCss = !useQuickCss; }} /> VencordNative.quickCss.openEditor()} /> openSettingsTabModal(ThemesTab)} /> {!!themes?.length && ( @@ -304,7 +305,7 @@ export function renderPopout(onClose: () => void) { > diff --git a/src/equicordplugins/equissant/index.ts b/src/equicordplugins/equissant/index.ts index 188316213..12d16014b 100644 --- a/src/equicordplugins/equissant/index.ts +++ b/src/equicordplugins/equissant/index.ts @@ -7,6 +7,7 @@ import { AudioPlayerInterface, createAudioPlayer } from "@api/AudioPlayer"; import { definePluginSettings } from "@api/Settings"; import { Devs, EquicordDevs } from "@utils/constants"; +import { t } from "@utils/translation"; import definePlugin, { OptionType } from "@utils/types"; let clickCount = 0; @@ -25,14 +26,14 @@ function play() { const settings = definePluginSettings({ amount: { type: OptionType.NUMBER, - description: "amount of clicks to trigger crossant", + description: t("equissant.settings.amount"), default: 10, } }); export default definePlugin({ name: "Equissant", - description: "Crossant every specified amount of clicks :trolley:", + description: t("equissant.description"), authors: [EquicordDevs.SomeAspy, Devs.thororen], dependencies: ["AudioPlayerAPI"], settings, diff --git a/src/equicordplugins/exitSounds/index.tsx b/src/equicordplugins/exitSounds/index.tsx index 3f161fbb6..19734b510 100644 --- a/src/equicordplugins/exitSounds/index.tsx +++ b/src/equicordplugins/exitSounds/index.tsx @@ -12,6 +12,7 @@ import { definePluginSettings } from "@api/Settings"; import { Button } from "@components/Button"; import { Devs } from "@utils/constants"; import { classNameFactory } from "@utils/css"; +import { t } from "@utils/translation"; import definePlugin, { OptionType } from "@utils/types"; import { findComponentByCodeLazy } from "@webpack"; import { ChannelActions, Constants, GuildStore, IconUtils, MediaEngineStore, Menu, RestAPI, SearchableSelect, SelectedChannelStore, TextInput, Toasts } from "@webpack/common"; @@ -31,7 +32,7 @@ function GuildSelector() { o.value === soundGuildId)} - placeholder="Select a server..." + placeholder={t("exitSounds.ui.selectServer")} maxVisibleItems={6} closeOnSelect={true} onChange={v => settings.store.soundGuildId = v} @@ -58,7 +59,7 @@ function SoundIdInput() { settings.store.soundId = v} - placeholder="Enter sound ID..." + placeholder={t("exitSounds.ui.enterSoundId")} />
{font.authors?.length && ( - by {font.authors.join(", ")} + {t("fontLoader.ui.by", { authors: font.authors.join(", ") })} )} @@ -192,14 +193,14 @@ const settings = definePluginSettings({ }, applyOnCodeBlocks: { type: OptionType.BOOLEAN, - description: "Apply the font to code blocks", + description: t("fontLoader.settings.applyOnCodeBlocks"), default: false } }); export default definePlugin({ name: "FontLoader", - description: "Loads any font from Google Fonts", + description: t("fontLoader.description"), authors: [EquicordDevs.vmohammad], settings, diff --git a/src/equicordplugins/forwardAnywhere/index.ts b/src/equicordplugins/forwardAnywhere/index.ts index 4b1a4dd4e..cc9082a0f 100644 --- a/src/equicordplugins/forwardAnywhere/index.ts +++ b/src/equicordplugins/forwardAnywhere/index.ts @@ -7,24 +7,25 @@ import { definePluginSettings } from "@api/Settings"; import { Devs } from "@utils/constants"; import { sendMessage } from "@utils/discord"; +import { t } from "@utils/translation"; import definePlugin, { OptionType } from "@utils/types"; import { Channel, Message } from "@vencord/discord-types"; // Taken From Signature :) const settings = definePluginSettings({ forwardPreface: { - description: "What should forwarded from be prefaced with", + description: t("forwardAnywhere.settings.forwardPreface"), type: OptionType.SELECT, options: [ - { label: ">", value: ">", default: true }, - { label: "-#", value: "-#" } + { label: t("forwardAnywhere.options.greaterThan"), value: ">", default: true }, + { label: t("forwardAnywhere.options.hash"), value: "-#" } ] } }); export default definePlugin({ name: "ForwardAnywhere", - description: "If a forward fails send it as a normal message also allows nsfw forwards", + description: t("forwardAnywhere.description"), authors: [Devs.thororen], settings, patches: [ diff --git a/src/equicordplugins/frequentQuickSwitcher/index.tsx b/src/equicordplugins/frequentQuickSwitcher/index.tsx index c2d61a11e..a97f1590e 100644 --- a/src/equicordplugins/frequentQuickSwitcher/index.tsx +++ b/src/equicordplugins/frequentQuickSwitcher/index.tsx @@ -5,6 +5,7 @@ */ import { Devs } from "@utils/constants"; +import { t } from "@utils/translation"; import definePlugin from "@utils/types"; import { ChannelStore, UserSettingsActionCreators } from "@webpack/common"; @@ -36,7 +37,7 @@ function generateSearchResults(query) { export default definePlugin({ name: "FrequentQuickSwitcher", - description: "Rewrites and filters the quick switcher results to be your most frequent channels", + description: t("frequentQuickSwitcher.description"), authors: [Devs.Samwich], generateSearchResults: generateSearchResults, patches: [ diff --git a/src/equicordplugins/friendCloud/index.ts b/src/equicordplugins/friendCloud/index.ts index 759b9f12f..3dca6a9d2 100644 --- a/src/equicordplugins/friendCloud/index.ts +++ b/src/equicordplugins/friendCloud/index.ts @@ -19,6 +19,7 @@ import { ApplicationCommandInputType, ApplicationCommandOptionType, findOption, sendBotMessage } from "@api/Commands"; import { EquicordDevs } from "@utils/constants"; import { Logger } from "@utils/Logger"; +import { t } from "@utils/translation"; import definePlugin from "@utils/types"; import { User } from "@vencord/discord-types"; import { findStore } from "@webpack"; @@ -51,17 +52,17 @@ interface UserPosition { export default definePlugin({ name: "FriendCloud", - description: "Adds a /friendcloud command to visualize the users you most interact with", + description: t("friendCloud.description"), authors: [EquicordDevs.Fafa], commands: [ { inputType: ApplicationCommandInputType.BUILT_IN, name: "friendcloud", - description: "Display user you most interact with in a cloud", + description: t("friendCloud.commands.friendcloud"), options: [ { name: "count", - description: "Number of users to display", + description: t("friendCloud.commands.count"), type: ApplicationCommandOptionType.NUMBER, required: false } @@ -69,14 +70,14 @@ export default definePlugin({ execute: async (opts, cmdCtx) => { const count = findOption(opts, "count", 25); - if (!count) return sendBotMessage(cmdCtx.channel.id, { content: "The count must be 1 or higher!" }); + if (!count) return sendBotMessage(cmdCtx.channel.id, { content: t("friendCloud.errors.countMustBeHigher") }); try { const affinities: AffinitiesV2[] = findStore("UserAffinitiesV2Store").getUserAffinities(); if (!affinities?.length) { return sendBotMessage(cmdCtx.channel.id, { - content: "No affinities found. Check your [privacy settings]()." + content: t("friendCloud.errors.noAffinities") }); } @@ -91,7 +92,7 @@ export default definePlugin({ if (!users.length) { return sendBotMessage(cmdCtx.channel.id, { - content: "No valid users found in affinities. Check your [privacy settings]()." + content: t("friendCloud.errors.noValidUsers") }); } @@ -153,7 +154,7 @@ export default definePlugin({ if (loadedImages === totalImages) { canvas.toBlob(blob => { if (!blob) { - sendBotMessage(cmdCtx.channel.id, { content: "Couldn't generate the image :c" }); + sendBotMessage(cmdCtx.channel.id, { content: t("friendCloud.errors.couldntGenerate") }); return; } const file = new File([blob], "affinities-cloud.png", { type: "image/png" }); diff --git a/src/equicordplugins/friendTags/index.tsx b/src/equicordplugins/friendTags/index.tsx index 0f893cdb8..c7e669e20 100644 --- a/src/equicordplugins/friendTags/index.tsx +++ b/src/equicordplugins/friendTags/index.tsx @@ -13,6 +13,7 @@ import { BaseText } from "@components/BaseText"; import { Divider } from "@components/Divider"; import { Devs } from "@utils/constants"; import { useForceUpdater } from "@utils/react"; +import { t } from "@utils/translation"; import definePlugin, { OptionType } from "@utils/types"; import { Button, ChannelStore, Menu, RelationshipStore, TextInput, useEffect, UserStore, useState } from "@webpack/common"; @@ -99,12 +100,12 @@ function TagConfigCard(props) { return ( <> - Name + {t("friendTags.ui.name")} - Users (Seperated by comma) + {t("friendTags.ui.usersSeperated")}
- User List (Click A User To Remove) + {t("friendTags.ui.userList")}
{ userIds.split(", ").map(user => { @@ -128,7 +129,7 @@ function TagConfigCard(props) { }} color={Button.Colors.RED} > - Remove + {t("friendTags.ui.remove")} ); @@ -156,7 +157,7 @@ function TagConfigurationComponent() { }); SetData(); update(); - }}>Add + }}>{t("friendTags.ui.add")} ); } @@ -187,14 +188,14 @@ const userPatch: NavContextMenuPatchCallback = (children, { user }) => { const buttonElement = {SavedData.map(tag => { const isTagged = SavedData.filter(e => e.tagName === tag.tagName)[0].userIds.includes(user.id); return ( { UserToTagID(user.id, tag.tagName, isTagged); }} @@ -208,7 +209,7 @@ const userPatch: NavContextMenuPatchCallback = (children, { user }) => { export default definePlugin({ name: "FriendTags", - description: "Allows you to filter by custom tags in the quick switcher by starting a search with &", + description: t("friendTags.description"), authors: [Devs.Samwich], settings, contextMenus: { diff --git a/src/equicordplugins/friendshipRanks/index.tsx b/src/equicordplugins/friendshipRanks/index.tsx index 9294c9f61..090351a67 100644 --- a/src/equicordplugins/friendshipRanks/index.tsx +++ b/src/equicordplugins/friendshipRanks/index.tsx @@ -14,6 +14,7 @@ import { Paragraph } from "@components/Paragraph"; import { Devs } from "@utils/constants"; import { classNameFactory } from "@utils/css"; import { ModalContent, ModalHeader, ModalRoot, ModalSize, openModal } from "@utils/modal"; +import { t } from "@utils/translation"; import definePlugin from "@utils/types"; import { Forms, RelationshipStore } from "@webpack/common"; @@ -40,44 +41,44 @@ function daysSince(dateString: string): number { const ranks: rankInfo[] = [ { - title: "Sprout", - description: "Your friendship is just starting", + title: t("friendshipRanks.ranks.sprout.title"), + description: t("friendshipRanks.ranks.sprout.description"), requirement: 0, iconSrc: "https://equicord.org/assets/plugins/friendshipRanks/sprout.png" }, { - title: "Blooming", - description: "Your friendship is getting there! (1 Month)", + title: t("friendshipRanks.ranks.blooming.title"), + description: t("friendshipRanks.ranks.blooming.description"), requirement: 30, iconSrc: "https://equicord.org/assets/plugins/friendshipRanks/blooming.png" }, { - title: "Burning", - description: "Your friendship has reached terminal velocity (3 Months)", + title: t("friendshipRanks.ranks.burning.title"), + description: t("friendshipRanks.ranks.burning.description"), requirement: 90, iconSrc: "https://equicord.org/assets/plugins/friendshipRanks/burning.png" }, { - title: "Fighter", - description: "Your friendship is strong (6 Months)", + title: t("friendshipRanks.ranks.fighter.title"), + description: t("friendshipRanks.ranks.fighter.description"), requirement: 182.5, iconSrc: "https://equicord.org/assets/plugins/friendshipRanks/fighter.png" }, { - title: "Star", - description: "Your friendship has been going on for a WHILE (1 Year)", + title: t("friendshipRanks.ranks.star.title"), + description: t("friendshipRanks.ranks.star.description"), requirement: 365, iconSrc: "https://equicord.org/assets/plugins/friendshipRanks/star.png" }, { - title: "Royal", - description: "Your friendship has gone through thick and thin- a whole 2 years!", + title: t("friendshipRanks.ranks.royal.title"), + description: t("friendshipRanks.ranks.royal.description"), requirement: 730, iconSrc: "https://equicord.org/assets/plugins/friendshipRanks/royal.png" }, { - title: "Besties", - description: "How do you even manage this??? (5 Years)", + title: t("friendshipRanks.ranks.besties.title"), + description: t("friendshipRanks.ranks.besties.description"), requirement: 1826.25, iconSrc: "https://equicord.org/assets/plugins/friendshipRanks/besties.png" } @@ -142,7 +143,7 @@ function getBadgesToApply() { export default definePlugin({ name: "FriendshipRanks", - description: "Adds badges showcasing how long you have been friends with a user for", + description: t("friendshipRanks.description"), authors: [Devs.Samwich], start() { getBadgesToApply().forEach(b => Badges.addProfileBadge(b)); diff --git a/src/equicordplugins/fullVcPfp/index.tsx b/src/equicordplugins/fullVcPfp/index.tsx index 30fa24349..3c9a85e02 100644 --- a/src/equicordplugins/fullVcPfp/index.tsx +++ b/src/equicordplugins/fullVcPfp/index.tsx @@ -6,6 +6,7 @@ import { disableStyle, enableStyle } from "@api/Styles"; import { EquicordDevs } from "@utils/constants"; +import { t } from "@utils/translation"; import definePlugin from "@utils/types"; import { ChannelRTCStore, IconUtils, UserStore, VoiceStateStore } from "@webpack/common"; @@ -13,7 +14,7 @@ import style from "./style.css?managed"; export default definePlugin({ name: "FullVCPFP", - description: "Makes avatars take up the entire vc tile", + description: t("fullVcPfp.description"), authors: [EquicordDevs.mochienya], patches: [ { diff --git a/src/equicordplugins/gensokyoRadioRPC/index.tsx b/src/equicordplugins/gensokyoRadioRPC/index.tsx index bd4892e66..9638f6ca2 100644 --- a/src/equicordplugins/gensokyoRadioRPC/index.tsx +++ b/src/equicordplugins/gensokyoRadioRPC/index.tsx @@ -7,6 +7,7 @@ import { definePluginSettings } from "@api/Settings"; import { Paragraph } from "@components/Paragraph"; import { Devs, EquicordDevs } from "@utils/constants"; +import { t } from "@utils/translation"; import definePlugin, { OptionType, PluginNative, ReporterTestable } from "@utils/types"; import { Activity } from "@vencord/discord-types"; import { ActivityFlags, ActivityType } from "@vencord/discord-types/enums"; @@ -31,7 +32,7 @@ function getImageAsset(data: string) { const settings = definePluginSettings({ refreshInterval: { type: OptionType.SLIDER, - description: "The interval between activity refreshes (seconds)", + description: t("gensokyoRadioRPC.settings.refreshInterval"), markers: [1, 2, 2.5, 3, 5, 10, 15], default: 15, restartNeeded: true, @@ -42,14 +43,14 @@ let updateInterval: NodeJS.Timeout | undefined; export default definePlugin({ name: "GensokyoRadioRPC", - description: "Discord rich presence for Gensokyo Radio!", + description: t("gensokyoRadioRPC.description"), authors: [Devs.RyanCaoDev, EquicordDevs.Prince527], reporterTestable: ReporterTestable.None, settingsAboutComponent() { return ( - Discord rich presence for Gensokyo Radio! + {t("gensokyoRadioRPC.info")} ); }, diff --git a/src/equicordplugins/ghosted/index.tsx b/src/equicordplugins/ghosted/index.tsx index 954c9b624..1312a3b1d 100644 --- a/src/equicordplugins/ghosted/index.tsx +++ b/src/equicordplugins/ghosted/index.tsx @@ -13,6 +13,7 @@ import ErrorBoundary from "@components/ErrorBoundary"; import { Devs, EquicordDevs } from "@utils/constants"; import { classNameFactory } from "@utils/css"; import { closeModal, openModal } from "@utils/modal"; +import { t } from "@utils/translation"; import definePlugin, { OptionType } from "@utils/types"; import { Channel } from "@vencord/discord-types"; import { Menu, Tooltip, useEffect, useState } from "@webpack/common"; @@ -26,30 +27,30 @@ export const cl = classNameFactory("vc-boo-"); export const settings = definePluginSettings({ showIndicator: { type: OptionType.BOOLEAN, - description: "Show the ghost counter at the top of the server list", + description: t("ghosted.settings.showIndicator"), default: true, restartNeeded: false }, showDmIcons: { type: OptionType.BOOLEAN, - description: "Show ghost icons next to individual DMs", + description: t("ghosted.settings.showDmIcons"), default: true, restartNeeded: false }, ignoreGroupDms: { type: OptionType.BOOLEAN, - description: "Exclude all group dms from ghosting", + description: t("ghosted.settings.ignoreGroupDms"), default: false }, exemptedChannels: { type: OptionType.STRING, - description: "Comma-separated list of channel IDs to exempt from ghosting (right-click a DM channel to copy its ID)", + description: t("ghosted.settings.exemptedChannels"), default: "", restartNeeded: false }, ignoreBots: { type: OptionType.BOOLEAN, - description: "Ignore DMs from bots", + description: t("ghosted.settings.ignoreBots"), default: true, restartNeeded: false } @@ -88,14 +89,14 @@ function BooIndicator() { const getTooltipText = () => { const ghostedChannels = getGhostedChannels(); if (ghostedChannels.length === 0) { - return "No Ghosted Users"; + return t("ghosted.ui.noGhostedUsers"); } if (ghostedChannels.length <= 5) { return ghostedChannels .map(id => getChannelDisplayName(id)) .join(", "); } - return `${ghostedChannels.length} Ghosted Users`; + return t("ghosted.ui.ghostedUsers", { count: ghostedChannels.length }); }; return ( @@ -125,7 +126,7 @@ function makeContextItem(props) { return { clearChannelFromGhost(props.channel.id); }} @@ -134,7 +135,7 @@ function makeContextItem(props) { export default definePlugin({ name: "Ghosted", - description: "A cute ghost will appear if you don't answer their DMs", + description: t("ghosted.description"), authors: [EquicordDevs.vei, Devs.sadan, EquicordDevs.justjxke, EquicordDevs.iamme], settings, dependencies: ["AudioPlayerAPI", "ServerListAPI"], diff --git a/src/equicordplugins/gifCollections/index.tsx b/src/equicordplugins/gifCollections/index.tsx index cf9592141..2e774d0e3 100644 --- a/src/equicordplugins/gifCollections/index.tsx +++ b/src/equicordplugins/gifCollections/index.tsx @@ -16,6 +16,7 @@ import { Paragraph } from "@components/Paragraph"; import { copyToClipboard } from "@utils/clipboard"; import { Devs, EquicordDevs } from "@utils/constants"; import { ModalContent, ModalFooter, ModalHeader, ModalRoot, ModalSize, openModal } from "@utils/modal"; +import { t } from "@utils/translation"; import definePlugin, { OptionType } from "@utils/types"; import { Alerts, Button, ContextMenuApi, FluxDispatcher, Menu, React, showToast, TextInput, Toasts, useCallback, useState } from "@webpack/common"; @@ -48,12 +49,12 @@ const addCollectionContextMenuPatch: NavContextMenuPatchCallback = (children, pr if (settings.store.showCopyImageLink) { group.push( { copyToClipboard(gif.url); - showToast("Image link copied to clipboard", Toasts.Type.SUCCESS); + showToast(t("gifCollections.ui.imageLinkCopied"), Toasts.Type.SUCCESS); }} /> ); @@ -61,7 +62,7 @@ const addCollectionContextMenuPatch: NavContextMenuPatchCallback = (children, pr group.push( @@ -79,7 +80,7 @@ const addCollectionContextMenuPatch: NavContextMenuPatchCallback = (children, pr { openModal(modalProps => ( @@ -93,7 +94,7 @@ const addCollectionContextMenuPatch: NavContextMenuPatchCallback = (children, pr export const settings = definePluginSettings({ itemPrefix: { - description: "The prefix for gif items", + description: t("gifCollections.settings.itemPrefix"), type: OptionType.STRING, default: "gc-item:", onChange: value => { @@ -106,7 +107,7 @@ export const settings = definePluginSettings({ restartNeeded: true }, collectionPrefix: { - description: "The prefix for collections", + description: t("gifCollections.settings.collectionPrefix"), type: OptionType.STRING, default: "gc:", onChange: value => { @@ -119,28 +120,28 @@ export const settings = definePluginSettings({ restartNeeded: true }, onlyShowCollections: { - description: "Only show collections", + description: t("gifCollections.settings.onlyShowCollections"), type: OptionType.BOOLEAN, default: false, restartNeeded: true }, stopWarnings: { - description: "Stop deletion warnings", + description: t("gifCollections.settings.stopWarnings"), type: OptionType.BOOLEAN, default: false, }, showCopyImageLink: { - description: "Show 'Copy Image Link' option in context menus", + description: t("gifCollections.settings.showCopyImageLink"), type: OptionType.BOOLEAN, default: false, }, preventDuplicates: { - description: "Prevent adding the same GIF to a collection multiple times", + description: t("gifCollections.settings.preventDuplicates"), type: OptionType.BOOLEAN, default: false, }, defaultEmptyCollectionImage: { - description: "The image / gif that will be shown when a collection has no images / gifs", + description: t("gifCollections.settings.defaultEmptyCollectionImage"), type: OptionType.STRING, default: "https://c.tenor.com/YEG33HsLEaIAAAAC/parksandrec-oops.gif" }, @@ -175,14 +176,14 @@ export const settings = definePluginSettings({ return (
- Sort Collections + {t("gifCollections.ui.sortCollections")} - Choose a sorting criteria for your collections + {t("gifCollections.ui.sortCollectionsDescription")}
- Sort By + {t("gifCollections.ui.sortBy")}
@@ -206,7 +207,7 @@ export const settings = definePluginSettings({ onChange={() => handleSortTypeChange(SortingOptions.CREATION_DATE)} className="collections-sort-input" /> - Creation Date + {t("gifCollections.ui.creationDate")}
@@ -219,13 +220,13 @@ export const settings = definePluginSettings({ onChange={() => handleSortTypeChange(SortingOptions.MODIFIED_DATE)} className="collections-sort-input" /> - Modified Date + {t("gifCollections.ui.modifiedDate")}
- Order + {t("gifCollections.ui.order")}
@@ -249,7 +250,7 @@ export const settings = definePluginSettings({ onChange={() => handleSortOrderChange("desc")} className="collections-sort-input" /> - Descending + {t("gifCollections.ui.descending")}
@@ -259,52 +260,52 @@ export const settings = definePluginSettings({ }, importGifs: { type: OptionType.COMPONENT, - description: "Import Collections", + description: t("gifCollections.ui.importCollections"), component: () => , }, exportGifs: { type: OptionType.COMPONENT, - description: "Export Collections", + description: t("gifCollections.ui.exportCollections"), component: () => }, resetCollections: { type: OptionType.COMPONENT, - description: "Reset Collections", + description: t("gifCollections.ui.resetCollections"), component: () => } }); export default definePlugin({ name: "GifCollections", - description: "Allows you to create collections of gifs", + description: t("gifCollections.description"), authors: [Devs.Aria, EquicordDevs.creations], patches: [ { @@ -448,7 +449,7 @@ const RemoveItemContextMenu = ({ type, nameOrId, instance }) => ( { const collection = cache_collections.find(c => c.name === nameOrId); if (!collection) return; @@ -460,30 +461,30 @@ const RemoveItemContextMenu = ({ type, nameOrId, instance }) => ( className="custom-modal" > - Collection Information + {t("gifCollections.ui.collectionInformation")}
- Name + {t("gifCollections.ui.name")} {collection.name.replace(/.+?:/, "")} - Gifs + {t("gifCollections.ui.gifs")} {collection.gifs.length} - Created At - {collection.createdAt ? new Date(collection.createdAt).toLocaleString() : "Unknown"} + {t("gifCollections.ui.createdAt")} + {collection.createdAt ? new Date(collection.createdAt).toLocaleString() : t("gifCollections.ui.unknown")} - Last Updated - {collection.lastUpdated ? new Date(collection.lastUpdated).toLocaleString() : "Unknown"} + {t("gifCollections.ui.lastUpdated")} + {collection.lastUpdated ? new Date(collection.lastUpdated).toLocaleString() : t("gifCollections.ui.unknown")}
- + )); @@ -493,7 +494,7 @@ const RemoveItemContextMenu = ({ type, nameOrId, instance }) => ( openModal(modalProps => ( ({ content: getMessage(opts, other) }), diff --git a/src/equicordplugins/githubRepos/index.tsx b/src/equicordplugins/githubRepos/index.tsx index c621e4991..0d6dbc410 100644 --- a/src/equicordplugins/githubRepos/index.tsx +++ b/src/equicordplugins/githubRepos/index.tsx @@ -11,6 +11,7 @@ import { BaseText } from "@components/BaseText"; import ErrorBoundary from "@components/ErrorBoundary"; import { EquicordDevs } from "@utils/constants"; import { classNameFactory } from "@utils/css"; +import { t } from "@utils/translation"; import definePlugin, { OptionType } from "@utils/types"; import { User } from "@vencord/discord-types"; import { findByCodeLazy } from "@webpack"; @@ -23,22 +24,22 @@ export const cl = classNameFactory("vc-github-repos-"); export const settings = definePluginSettings({ showStars: { type: OptionType.BOOLEAN, - description: "Show repository stars", + description: t("githubRepos.settings.showStars"), default: true }, showLanguage: { type: OptionType.BOOLEAN, - description: "Show repository language", + description: t("githubRepos.settings.showLanguage"), default: true }, showInMiniProfile: { type: OptionType.BOOLEAN, - description: "Show full ui in the mini profile instead of just a button", + description: t("githubRepos.settings.showInMiniProfile"), default: true }, showRepositoryTab: { type: OptionType.BOOLEAN, - description: "Show repositories tab in profile modal (hides button in connections when enabled)", + description: t("githubRepos.settings.showRepositoryTab"), default: true }, }); @@ -58,7 +59,7 @@ const ProfilePopoutComponent = ErrorBoundary.wrap( { noop: true, fallback: () => - Error, Failed to render GithubRepos + {t("githubRepos.ui.error")} } ); @@ -79,7 +80,7 @@ const ProfileRepositoriesTab = ErrorBoundary.wrap( export default definePlugin({ name: "GitHubRepos", - description: "Displays a user's public GitHub repositories in their profile", + description: t("githubRepos.description"), authors: [EquicordDevs.talhakf, EquicordDevs.Panniku, EquicordDevs.benjii], settings, diff --git a/src/equicordplugins/globalBadges/index.tsx b/src/equicordplugins/globalBadges/index.tsx index 24802395a..9123a6a36 100644 --- a/src/equicordplugins/globalBadges/index.tsx +++ b/src/equicordplugins/globalBadges/index.tsx @@ -12,6 +12,7 @@ import { Button } from "@components/Button"; import { BadgeContextMenu } from "@plugins/_api/badges"; import { Devs, EquicordDevs } from "@utils/constants"; import { openInviteModal } from "@utils/discord"; +import { t } from "@utils/translation"; import definePlugin from "@utils/types"; import { ContextMenuApi, React, Toasts, UserStore } from "@webpack/common"; @@ -24,7 +25,7 @@ let intervalId: any; migratePluginSetting("GlobalBadges", "showRaincord", "showRa1ncord"); export default definePlugin({ name: "GlobalBadges", - description: "Adds global badges from other client mods", + description: t("globalBadges.description"), authors: [Devs.HypedDomi, EquicordDevs.Wolfie, Devs.thororen], settings, settingsAboutComponent: () => ( @@ -34,7 +35,7 @@ export default definePlugin({ className={cl("settings-button")} onClick={() => openInviteModal(INVITE_LINK)} > - Join GlobalBadges Server + {t("globalBadges.ui.joinServer")} ), @@ -51,7 +52,7 @@ export default definePlugin({ await loadBadges(); Toasts.show({ id: Toasts.genId(), - message: "Successfully refetched global badges!", + message: t("globalBadges.ui.refetchSuccess"), type: Toasts.Type.SUCCESS }); } diff --git a/src/equicordplugins/googleThat/index.tsx b/src/equicordplugins/googleThat/index.tsx index 18f6753c3..7ce991eb7 100644 --- a/src/equicordplugins/googleThat/index.tsx +++ b/src/equicordplugins/googleThat/index.tsx @@ -7,6 +7,7 @@ import { ApplicationCommandOptionType, findOption } from "@api/Commands"; import { definePluginSettings } from "@api/Settings"; import { Devs, EquicordDevs } from "@utils/constants"; +import { t } from "@utils/translation"; import definePlugin, { OptionType } from "@utils/types"; function getMessage(opts) { @@ -48,17 +49,17 @@ const searchEngines = { const settings = definePluginSettings({ hyperlink: { type: OptionType.BOOLEAN, - description: "If the sent link should hyperlink with the query as the label", + description: t("googleThat.settings.hyperlink"), default: false }, embed: { type: OptionType.BOOLEAN, - description: "If the sent link should render an embed", + description: t("googleThat.settings.embed"), default: true }, defaultEngine: { type: OptionType.SELECT, - description: "The search engine to use", + description: t("googleThat.settings.defaultEngine"), options: Object.keys(searchEngines).map((key, index) => ({ label: key, value: key, @@ -66,7 +67,7 @@ const settings = definePluginSettings({ })) }, customEngineURL: { - description: "The URL of the Engine you wish to use", + description: t("googleThat.settings.customEngineURL"), type: OptionType.STRING, placeholder: "" } @@ -74,18 +75,18 @@ const settings = definePluginSettings({ export default definePlugin({ name: "GoogleThat", - description: "Adds a command to send a internet search link", + description: t("googleThat.description"), authors: [Devs.Samwich, EquicordDevs.KrystalSkull], tags: ["search", "google", "query", "duckduckgo", "command"], settings, commands: [ { name: "googlethat", - description: "send a search engine link", + description: t("googleThat.commands.googlethat"), options: [ { name: "input", - description: "The search query", + description: t("googleThat.commands.input"), type: ApplicationCommandOptionType.STRING, required: true, } diff --git a/src/equicordplugins/guildPickerDumper/index.tsx b/src/equicordplugins/guildPickerDumper/index.tsx index 58892bf73..8b03c7ab2 100644 --- a/src/equicordplugins/guildPickerDumper/index.tsx +++ b/src/equicordplugins/guildPickerDumper/index.tsx @@ -6,6 +6,7 @@ import { findGroupChildrenByChildId, NavContextMenuPatchCallback } from "@api/ContextMenu"; import { Devs, EquicordDevs } from "@utils/constants"; +import { t } from "@utils/translation"; import definePlugin from "@utils/types"; import type { Guild } from "@vencord/discord-types"; import { EmojiStore, Menu, StickersStore } from "@webpack/common"; @@ -14,14 +15,13 @@ import { zipSync } from "fflate"; const StickerExt = [, "png", "apng", "json", "gif"] as const; const Patch: NavContextMenuPatchCallback = (children, { guild }: { guild: Guild; }) => { - // Assuming "privacy" is the correct ID for the group you want to modify. const group = findGroupChildrenByChildId("privacy", children); if (group) { group.push( <> - zipGuildAssets(guild, "emojis")}> - zipGuildAssets(guild, "stickers")}> + zipGuildAssets(guild, "emojis")}> + zipGuildAssets(guild, "stickers")}> ); } @@ -34,7 +34,7 @@ async function zipGuildAssets(guild: Guild, type: "emojis" | "stickers") { : StickersStore.getStickersByGuildId(guild.id); if (!items) { - return console.log("Server not found!"); + return console.log(t("guildPickerDumper.ui.serverNotFound")); } const getProxyEndpoint = () => { @@ -94,7 +94,7 @@ async function zipGuildAssets(guild: Guild, type: "emojis" | "stickers") { export default definePlugin({ name: "GuildPickerDumper", - description: "Context menu to dump and download a server's emojis and stickers.", + description: t("guildPickerDumper.description"), authors: [EquicordDevs.Cortex, Devs.Samwich, EquicordDevs.Synth, Devs.thororen], contextMenus: { "guild-context": Patch, diff --git a/src/equicordplugins/guildTagSettings/index.ts b/src/equicordplugins/guildTagSettings/index.ts index bbf6f5c0c..41190331c 100644 --- a/src/equicordplugins/guildTagSettings/index.ts +++ b/src/equicordplugins/guildTagSettings/index.ts @@ -19,6 +19,7 @@ import { definePluginSettings } from "@api/Settings"; import { disableStyle, enableStyle } from "@api/Styles"; import { Devs } from "@utils/constants"; +import { t } from "@utils/translation"; import definePlugin, { OptionType } from "@utils/types"; import clanBadges from "./styles.css?managed"; @@ -26,7 +27,7 @@ import clanBadges from "./styles.css?managed"; const settings = definePluginSettings({ hideTags: { type: OptionType.BOOLEAN, - description: "Hide tags", + description: t("guildTagSettings.settings.hideTags"), default: false, onChange: value => { if (value) enableStyle(clanBadges); @@ -35,7 +36,7 @@ const settings = definePluginSettings({ }, disableAdoptTagPrompt: { type: OptionType.BOOLEAN, - description: "Disable the prompt to adopt tags", + description: t("guildTagSettings.settings.disableAdoptTagPrompt"), default: true, restartNeeded: true } @@ -43,7 +44,7 @@ const settings = definePluginSettings({ export default definePlugin({ name: "GuildTagSettings", - description: "Adds some settings for guild tags, such as hiding them or disabling the prompt to adopt them.", + description: t("guildTagSettings.description"), authors: [Devs.thororen], settings, patches: [ diff --git a/src/equicordplugins/hideChatButtons/index.tsx b/src/equicordplugins/hideChatButtons/index.tsx index 9bdbfc98e..f91cf5a33 100644 --- a/src/equicordplugins/hideChatButtons/index.tsx +++ b/src/equicordplugins/hideChatButtons/index.tsx @@ -7,6 +7,7 @@ import { ChatBarButton } from "@api/ChatButtons"; import { definePluginSettings } from "@api/Settings"; import { EquicordDevs } from "@utils/constants"; +import { t } from "@utils/translation"; import definePlugin, { OptionType, StartAt } from "@utils/types"; import { React, useEffect, useState } from "@webpack/common"; import type { MouseEventHandler, ReactNode } from "react"; @@ -16,12 +17,12 @@ let hidechatbuttonsopen: boolean | undefined; const settings = definePluginSettings({ Color: { type: OptionType.BOOLEAN, - description: "Color it red on open", // something extra + description: t("hideChatButtons.settings.color"), default: false, }, Open: { type: OptionType.BOOLEAN, - description: "opened by default", + description: t("hideChatButtons.settings.open"), default: false, onChange: (store: { open: boolean; }) => { hidechatbuttonsopen = store.open; @@ -32,7 +33,7 @@ const settings = definePluginSettings({ function HideToggleButton(props: { open: boolean | undefined, onClick: MouseEventHandler; }) { return ( { if (isHidden) { HiddenServersStore.removeHiddenGuild(guild.id); @@ -75,7 +76,7 @@ export function removeIndicator() { export default definePlugin({ name: "HideServers", - description: "Allows you to hide servers from the guild list and quick switcher by right clicking them", + description: t("hideServers.description"), authors: [EquicordDevs.bep], tags: ["guild", "server", "hide", "folder"], @@ -96,7 +97,7 @@ export default definePlugin({ menuItems.push( { if (isHidden) { HiddenServersStore.removeHiddenFolder(folderId, guildIds); diff --git a/src/equicordplugins/holyNotes/index.tsx b/src/equicordplugins/holyNotes/index.tsx index f98001b74..c3870807f 100644 --- a/src/equicordplugins/holyNotes/index.tsx +++ b/src/equicordplugins/holyNotes/index.tsx @@ -24,6 +24,7 @@ import { DataStore } from "@api/index"; import { EquicordDevs } from "@utils/constants"; import { classNameFactory } from "@utils/css"; import { openModal } from "@utils/modal"; +import { t } from "@utils/translation"; import definePlugin, { IconComponent } from "@utils/types"; import { Message } from "@vencord/discord-types"; import { findByCodeLazy, findComponentByCodeLazy, findCssClassesLazy, findExportedComponentLazy } from "@webpack"; @@ -45,7 +46,7 @@ export const ChannelMessage = findComponentByCodeLazy("Message must not be a thr const messageContextMenuPatch: NavContextMenuPatchCallback = (children, { message }: { message: Message; }) => { children.push( - + {Object.keys(noteHandler.getAllNotes()).map(notebook => ( openModal(props => )} @@ -71,11 +72,11 @@ function ToolBarHeader() { export default definePlugin({ name: "HolyNotes", - description: "Save messages as notes to revisit later", + description: t("holyNotes.description"), authors: [EquicordDevs.Wolfie], toolboxActions: { - "Open Notes"() { + [t("holyNotes.ui.openNotes")]() { openModal(props => ); } }, @@ -93,7 +94,7 @@ export default definePlugin({ icon: BookmarkIcon, render(message) { return { - label: "Save Note", + label: t("holyNotes.ui.saveNote"), icon: BookmarkIcon, message, channel: ChannelStore.getChannel(message.channel_id), diff --git a/src/equicordplugins/homeTyping/index.tsx b/src/equicordplugins/homeTyping/index.tsx index a52bc2957..37c4d8188 100644 --- a/src/equicordplugins/homeTyping/index.tsx +++ b/src/equicordplugins/homeTyping/index.tsx @@ -5,6 +5,7 @@ */ import { Devs } from "@utils/constants"; +import { t } from "@utils/translation"; import definePlugin from "@utils/types"; import { findComponentByCodeLazy, findStoreLazy } from "@webpack"; import { TypingStore, UserStore, useStateFromStores } from "@webpack/common"; @@ -15,7 +16,7 @@ const PrivateChannelSortStore = findStoreLazy("PrivateChannelSortStore") as { ge export default definePlugin({ name: "HomeTyping", - description: "Changes the home button to a typing indicator if someone in your dms is typing", + description: t("homeTyping.description"), authors: [Devs.Samwich], TypingIcon() { return ; diff --git a/src/equicordplugins/hopOn/index.tsx b/src/equicordplugins/hopOn/index.tsx index 46e5326c9..ef79d2710 100644 --- a/src/equicordplugins/hopOn/index.tsx +++ b/src/equicordplugins/hopOn/index.tsx @@ -6,6 +6,7 @@ import { definePluginSettings } from "@api/Settings"; import { Devs } from "@utils/constants"; +import { t } from "@utils/translation"; import definePlugin, { OptionType } from "@utils/types"; import { Message } from "@vencord/discord-types"; import { RelationshipStore, SelectedChannelStore } from "@webpack/common"; @@ -20,18 +21,18 @@ interface IMessageCreate { const settings = definePluginSettings({ regex: { type: OptionType.STRING, - description: "Regex to trigger on", + description: t("hopOn.settings.regex"), default: "hop on (?:fortnite|fn)" }, url: { type: OptionType.STRING, - description: "URL to open", + description: t("hopOn.settings.url"), default: "com.epicgames.launcher://apps/fn%3A4fe75bbc5a674f4f9b356b5c90567da5%3AFortnite?action=launch&silent=true" } }); export default definePlugin({ name: "HopOn", - description: "Hop on Fortnite or Hop on bloons :3", + description: t("hopOn.description"), authors: [Devs.ImLvna], settings, flux: { diff --git a/src/equicordplugins/husk/index.tsx b/src/equicordplugins/husk/index.tsx index 25aad8e37..8bb8c0ae4 100644 --- a/src/equicordplugins/husk/index.tsx +++ b/src/equicordplugins/husk/index.tsx @@ -21,6 +21,7 @@ import { definePluginSettings } from "@api/Settings"; import { Devs } from "@utils/constants"; import { classes } from "@utils/misc"; +import { t } from "@utils/translation"; import definePlugin, { OptionType } from "@utils/types"; import { ChannelStore, EmojiStore, RestAPI } from "@webpack/common"; import type { SVGProps } from "react"; @@ -69,17 +70,17 @@ export function Husk(props: IconProps) { const settings = definePluginSettings({ findInServer: { - description: "Attempt to find emoji of same name in server before using ID in settings (useful if no nitro)", + description: t("husk.settings.findInServer"), type: OptionType.BOOLEAN, default: true }, emojiName: { - description: "Emoji name (default (from Vencord Server): husk)", + description: t("husk.settings.emojiName"), type: OptionType.STRING, default: "husk" }, emojiID: { - description: "Emoji ID (default (from Vencord Server): 1026532993923293184)", + description: t("husk.settings.emojiID"), type: OptionType.BIGINT, default: 1026532993923293184n } @@ -98,14 +99,14 @@ function getEmojiIdThatShouldBeUsed(guildId: string) { export default definePlugin({ name: "Husk", - description: "Adds Husk button (check settings to change used emoji)", + description: t("husk.description"), authors: [Devs.nin0dev], settings, messagePopoverButton: { icon: Husk, render(msg) { return { - label: "Husk", + label: t("husk.ui.husk"), icon: Husk, message: msg, channel: ChannelStore.getChannel(msg.channel_id), diff --git a/src/equicordplugins/iRememberYou/index.tsx b/src/equicordplugins/iRememberYou/index.tsx index 8b4614331..92ce68f81 100644 --- a/src/equicordplugins/iRememberYou/index.tsx +++ b/src/equicordplugins/iRememberYou/index.tsx @@ -11,6 +11,7 @@ import { EyeIcon } from "@components/Icons"; import SettingsPlugin from "@plugins/_core/settings"; import { EquicordDevs } from "@utils/constants"; import { removeFromArray } from "@utils/misc"; +import { t } from "@utils/translation"; import definePlugin from "@utils/types"; import { Data } from "./components/data"; @@ -18,7 +19,7 @@ import DataUI from "./components/ui"; export default definePlugin({ name: "IRememberYou", - description: "Locally saves everyone you've been communicating with (including servers), in case of lose", + description: t("iRememberYou.description"), authors: [EquicordDevs.zoodogood, EquicordDevs.keircn], dependencies: ["MessageEventsAPI"], @@ -27,7 +28,7 @@ export default definePlugin({ async start() { SettingsPlugin.customEntries.push({ key: "equicord_i_remember_you", - title: "I Remember You", + title: t("iRememberYou.ui.iRememberYou"), Component: () => , Icon: EyeIcon }); diff --git a/src/equicordplugins/iconViewer/index.tsx b/src/equicordplugins/iconViewer/index.tsx index f2135cbf2..c15ccbc57 100644 --- a/src/equicordplugins/iconViewer/index.tsx +++ b/src/equicordplugins/iconViewer/index.tsx @@ -10,6 +10,7 @@ import { MagnifyingGlassIcon } from "@components/Icons"; import SettingsPlugin from "@plugins/_core/settings"; import { EquicordDevs } from "@utils/constants"; import { removeFromArray } from "@utils/misc"; +import { t } from "@utils/translation"; import definePlugin, { StartAt } from "@utils/types"; import { SettingsRouter } from "@webpack/common"; @@ -18,12 +19,12 @@ import { SettingsAbout } from "./components/Modals"; export default definePlugin({ name: "IconViewer", - description: "Adds a new tab to settings to preview all icons.", + description: t("iconViewer.description"), authors: [EquicordDevs.iamme], dependencies: ["Settings"], startAt: StartAt.WebpackReady, toolboxActions: { - "Open Icons Tab"() { + [t("iconViewer.ui.openIconsTab")]() { SettingsRouter.openUserSettings("equicord_icon_viewer_panel"); }, }, @@ -31,7 +32,7 @@ export default definePlugin({ start() { SettingsPlugin.customEntries.push({ key: "equicord_icon_viewer", - title: "Icon Finder", + title: t("iconViewer.ui.iconFinder"), Component: IconsTab, Icon: MagnifyingGlassIcon }); diff --git a/src/equicordplugins/idleAutoRestart/index.tsx b/src/equicordplugins/idleAutoRestart/index.tsx index 2112f671f..1230da533 100644 --- a/src/equicordplugins/idleAutoRestart/index.tsx +++ b/src/equicordplugins/idleAutoRestart/index.tsx @@ -7,6 +7,7 @@ import { definePluginSettings } from "@api/Settings"; import { EquicordDevs } from "@utils/constants"; import { Logger } from "@utils/Logger"; +import { t } from "@utils/translation"; import definePlugin, { OptionType } from "@utils/types"; import { Menu, VoiceStateStore } from "@webpack/common"; @@ -16,12 +17,12 @@ let intervalId: ReturnType | null = null; const settings = definePluginSettings({ isEnabled: { - description: "Enable automatic restart after idle", + description: t("idleAutoRestart.settings.isEnabled"), type: OptionType.BOOLEAN, default: true, }, idleMinutes: { - description: "Minutes of inactivity before restarting (when not in VC)", + description: t("idleAutoRestart.settings.idleMinutes"), type: OptionType.SLIDER, markers: [5, 10, 15, 30, 60, 120], default: 30, @@ -35,7 +36,7 @@ function onActivity() { export default definePlugin({ name: "IdleAutoRestart", - description: "Automatically restarts the client after being idle for a configurable amount of time, but avoids restarting while you are in VC.", + description: t("idleAutoRestart.description"), authors: [EquicordDevs.SteelTech], settings, @@ -43,7 +44,7 @@ export default definePlugin({ return ( { settings.store.isEnabled = !settings.store.isEnabled; }} diff --git a/src/equicordplugins/ignoreCalls/index.tsx b/src/equicordplugins/ignoreCalls/index.tsx index b9e287be3..749389b83 100644 --- a/src/equicordplugins/ignoreCalls/index.tsx +++ b/src/equicordplugins/ignoreCalls/index.tsx @@ -12,6 +12,7 @@ import { Button } from "@components/Button"; import ErrorBoundary from "@components/ErrorBoundary"; import { Devs, EquicordDevs } from "@utils/constants"; import { classNameFactory } from "@utils/css"; +import { t } from "@utils/translation"; import definePlugin, { OptionType } from "@utils/types"; import { Channel } from "@vencord/discord-types"; import { findComponentByCodeLazy } from "@webpack"; @@ -34,7 +35,7 @@ const ContextMenuPatch: NavContextMenuPatchCallback = (children, { channel }: { { if (tempChecked) @@ -47,7 +48,7 @@ const ContextMenuPatch: NavContextMenuPatchCallback = (children, { channel }: { /> { let updated = permanentlyIgnoredUsers.slice(); @@ -68,7 +69,7 @@ const ContextMenuPatch: NavContextMenuPatchCallback = (children, { channel }: { const settings = definePluginSettings({ permanentlyIgnoredUsers: { type: OptionType.STRING, - description: "User IDs (comma + space) who should be permanetly ignored", + description: t("ignoreCalls.settings.permanentlyIgnoredUsers"), restartNeeded: true, default: "", }, @@ -82,7 +83,7 @@ const args = { export default definePlugin({ name: "IgnoreCalls", - description: "Allows you to ignore calls from specific users or dm groups.", + description: t("ignoreCalls.description"), authors: [EquicordDevs.TheArmagan, Devs.thororen], settings, patches: [ @@ -121,7 +122,7 @@ export default definePlugin({ return ( - + {({ onMouseEnter, onMouseLeave }) => (
- For X11 it may or may not work :shrug: + {t("instantScreenshare.info.x11")}
- Video Devices + {t("instantScreenshare.info.videoDevices")} - Supports cameras and capture cards (like Elgato HD60X) when enabled in settings + {t("instantScreenshare.info.videoDevicesInfo")}
- Regarding Sound & Preview Settings + {t("instantScreenshare.info.soundPreview")} - We use the settings set and used by discord to decide if stream preview and sound should be enabled or not + {t("instantScreenshare.info.soundPreviewInfo")} ), @@ -126,9 +127,9 @@ export default definePlugin({ }, toolboxActions: { - "Instant Screenshare"() { + [t("instantScreenshare.ui.instantScreenshare")]() { settings.store.toolboxManagement = !settings.store.toolboxManagement; - showToast(`Instant Screenshare ${settings.store.toolboxManagement ? "Enabled" : "Disabled"}`, Toasts.Type.SUCCESS); + showToast(settings.store.toolboxManagement ? t("instantScreenshare.ui.instantScreenshareEnabled") : t("instantScreenshare.ui.instantScreenshareDisabled"), Toasts.Type.SUCCESS); } } }); diff --git a/src/equicordplugins/invisibleChat.desktop/index.tsx b/src/equicordplugins/invisibleChat.desktop/index.tsx index 5589f8dec..1ea4f38d1 100644 --- a/src/equicordplugins/invisibleChat.desktop/index.tsx +++ b/src/equicordplugins/invisibleChat.desktop/index.tsx @@ -22,6 +22,7 @@ import { definePluginSettings } from "@api/Settings"; import ErrorBoundary from "@components/ErrorBoundary"; import { Devs } from "@utils/constants"; import { getStegCloak } from "@utils/dependencies"; +import { t } from "@utils/translation"; import definePlugin, { OptionType, ReporterTestable } from "@utils/types"; import { Message } from "@vencord/discord-types"; import { ChannelStore, Constants, RestAPI, Tooltip } from "@webpack/common"; @@ -46,7 +47,7 @@ function PopOverIcon() { function Indicator() { return ( - + {({ onMouseEnter, onMouseLeave }) => ( { return ( buildEncModal()} buttonProps={{ "aria-haspopup": "dialog", @@ -99,7 +100,7 @@ const settings = definePluginSettings({ savedPasswords: { type: OptionType.STRING, default: "password, Password", - description: "Saved Passwords (Seperated with a , )" + description: t("invisibleChat.settings.savedPasswords") } }); @@ -148,7 +149,7 @@ export async function buildEmbed(message: any, revealed: string): Promise export default definePlugin({ name: "InvisibleChat", - description: "Encrypt your Messages in a non-suspicious way!", + description: t("invisibleChat.description"), authors: [Devs.SammCheese], dependencies: ["MessageUpdaterAPI"], reporterTestable: ReporterTestable.Patches, @@ -180,7 +181,7 @@ export default definePlugin({ render(message) { return INV_REGEX.test(message?.content) ? { - label: "Decrypt Message", + label: t("invisibleChat.ui.decryptMessage"), icon: PopOverIcon, message: message, channel: ChannelStore.getChannel(message.channel_id), diff --git a/src/equicordplugins/inviteDefaults/index.ts b/src/equicordplugins/inviteDefaults/index.ts index 597c96fec..97ab50f87 100644 --- a/src/equicordplugins/inviteDefaults/index.ts +++ b/src/equicordplugins/inviteDefaults/index.ts @@ -6,12 +6,13 @@ import { definePluginSettings } from "@api/Settings"; import { EquicordDevs } from "@utils/constants"; +import { t } from "@utils/translation"; import definePlugin, { OptionType } from "@utils/types"; const settings = definePluginSettings({ inviteDuration: { type: OptionType.SELECT, - description: "Invite Duration", + description: t("inviteDefaults.settings.inviteDuration"), options: [ { label: "30 minutes", value: 1800 }, { label: "1 hour", value: 3600 }, @@ -19,14 +20,14 @@ const settings = definePluginSettings({ { label: "12 hours", value: 43200 }, { label: "1 day", value: 86400 }, { label: "7 days", value: 604800 }, - { label: "Forever", value: 0, default: true }, + { label: t("inviteDefaults.options.forever"), value: 0, default: true }, ], }, maxUses: { type: OptionType.SELECT, - description: "Invite Use Count", + description: t("inviteDefaults.settings.maxUses"), options: [ - { label: "Infinite", value: 0, default: true }, + { label: t("inviteDefaults.options.infinite"), value: 0, default: true }, { label: "1", value: 1 }, { label: "5", value: 5 }, { label: "10", value: 10 }, @@ -38,13 +39,13 @@ const settings = definePluginSettings({ temporaryMembership: { type: OptionType.BOOLEAN, default: false, - description: "Temporary Membership", + description: t("inviteDefaults.settings.temporaryMembership"), }, }); export default definePlugin({ name: "InviteDefaults", - description: "Allows you to edit the default values when creating server invites.", + description: t("inviteDefaults.description"), authors: [EquicordDevs.VillainsRule], settings, patches: [ diff --git a/src/equicordplugins/jellyfinRichPresence/index.tsx b/src/equicordplugins/jellyfinRichPresence/index.tsx index 2b4ac9ec6..59271e886 100644 --- a/src/equicordplugins/jellyfinRichPresence/index.tsx +++ b/src/equicordplugins/jellyfinRichPresence/index.tsx @@ -10,6 +10,7 @@ import { HeadingSecondary } from "@components/Heading"; import { Paragraph } from "@components/Paragraph"; import { Devs, EquicordDevs } from "@utils/constants"; import { Logger } from "@utils/Logger"; +import { t } from "@utils/translation"; import definePlugin, { OptionType } from "@utils/types"; import { ApplicationAssetUtils, FluxDispatcher, showToast } from "@webpack/common"; @@ -60,86 +61,86 @@ interface MediaData { const settings = definePluginSettings({ serverUrl: { - description: "Jellyfin server URL (e.g., https://jellyfin.example.com)", + description: t("jellyfinRichPresence.settings.serverUrl"), type: OptionType.STRING, }, apiKey: { - description: "Jellyfin API key obtained from your Jellyfin administration dashboard", + description: t("jellyfinRichPresence.settings.apiKey"), type: OptionType.STRING, }, userId: { - description: "Jellyfin user ID obtained from your user profile URL", + description: t("jellyfinRichPresence.settings.userId"), type: OptionType.STRING, }, nameDisplay: { - description: "Choose how the application name should appear in Rich Presence", + description: t("jellyfinRichPresence.settings.nameDisplay"), type: OptionType.SELECT, options: [ - { label: "Series/Movie Name", value: "default", default: true }, - { label: "Series - Episode/Track/Movie Name", value: "full" }, - { label: "Custom", value: "custom" }, + { label: t("jellyfinRichPresence.nameFormatOptions.seriesMovieName"), value: "default", default: true }, + { label: t("jellyfinRichPresence.nameFormatOptions.seriesEpisodeName"), value: "full" }, + { label: t("jellyfinRichPresence.nameFormatOptions.custom"), value: "custom" }, ], }, customName: { - description: "Custom Rich Presence name (only used if 'Custom' is selected).\nOptions: {name}, {series}, {season}, {episode}, {artist}, {album}, {year}", + description: t("jellyfinRichPresence.settings.customName"), type: OptionType.STRING, }, coverType: { - description: "Choose which cover to display when watching a TV show", + description: t("jellyfinRichPresence.settings.coverType"), type: OptionType.SELECT, options: [ - { label: "Series Cover", value: "series", default: true }, - { label: "Episode Cover", value: "episode" }, + { label: t("jellyfinRichPresence.coverTypeOptions.seriesCover"), value: "series", default: true }, + { label: t("jellyfinRichPresence.coverTypeOptions.episodeCover"), value: "episode" }, ], }, episodeFormat: { - description: "Episode number format", + description: t("jellyfinRichPresence.settings.episodeFormat"), type: OptionType.SELECT, options: [ - { label: "S01E01", value: "long", default: true }, - { label: "1x01", value: "short" }, - { label: "Season 1 Episode 1", value: "fulltext" }, + { label: t("jellyfinRichPresence.episodeFormatOptions.s01e01"), value: "long", default: true }, + { label: t("jellyfinRichPresence.episodeFormatOptions.short"), value: "short" }, + { label: t("jellyfinRichPresence.episodeFormatOptions.fulltext"), value: "fulltext" }, ], }, showEpisodeName: { - description: "Show episode name after season/episode info", + description: t("jellyfinRichPresence.settings.showEpisodeName"), type: OptionType.BOOLEAN, default: false, }, overrideRichPresenceType: { - description: "Override the rich presence type", + description: t("jellyfinRichPresence.settings.overrideRichPresenceType"), type: OptionType.SELECT, options: [ { - label: "Off", + label: t("jellyfinRichPresence.overrideTypeOptions.off"), value: false, default: true, }, { - label: "Listening", + label: t("jellyfinRichPresence.overrideTypeOptions.listening"), value: 2, }, { - label: "Playing", + label: t("jellyfinRichPresence.overrideTypeOptions.playing"), value: 0, }, { - label: "Streaming", + label: t("jellyfinRichPresence.overrideTypeOptions.streaming"), value: 1, }, { - label: "Watching", + label: t("jellyfinRichPresence.overrideTypeOptions.watching"), value: 3 }, ], }, showPausedState: { - description: "Show Rich Presence when media is paused", + description: t("jellyfinRichPresence.settings.showPausedState"), type: OptionType.BOOLEAN, default: true, }, privacyMode: { - description: "Privacy Mode (Hide media details like Episode/Song Name)", + description: t("jellyfinRichPresence.settings.privacyMode"), type: OptionType.BOOLEAN, default: false, }, @@ -165,14 +166,14 @@ function setActivity(activity: Activity | null) { export default definePlugin({ name: "JellyfinRichPresence", - description: "Rich presence for Jellyfin media server", + description: t("jellyfinRichPresence.description"), authors: [EquicordDevs.vmohammad, Devs.SerStars, EquicordDevs.ZcraftElite], settingsAboutComponent: () => ( <> - How to get an API key + {t("jellyfinRichPresence.howToGetApiKey.title")} - Auth token can be found by following these steps: + {t("jellyfinRichPresence.howToGetApiKey.description")}
  1. 1. Log into your Jellyfin instance
  2. 2. Open your browser's Developer Tools (usually F12 or right-click then Inspect)
  3. @@ -187,7 +188,7 @@ export default definePlugin({

- You'll also need your User ID, which can be found in the url of your user profile page. + {t("jellyfinRichPresence.howToGetApiKey.userIdInfo")}
), @@ -207,7 +208,7 @@ export default definePlugin({ async fetchMediaData(): Promise { if (!settings.store.serverUrl || !settings.store.apiKey || !settings.store.userId) { logger.warn("Jellyfin server URL, API key, or user ID is not set in settings."); - showToast("JellyfinRPC is not configured.", "failure", { + showToast(t("jellyfinRichPresence.toasts.notConfigured"), "failure", { duration: 15000, }); return null; @@ -302,15 +303,15 @@ export default definePlugin({ case "full": if (mediaData.type === "Episode" && mediaData.seriesName) { appName = settings.store.privacyMode - ? `${mediaData.seriesName} - [Episode Hidden]` + ? `${mediaData.seriesName} - ${t("jellyfinRichPresence.privacyMode.episodeHidden")}` : `${mediaData.seriesName} - ${mediaData.name}`; } else if (mediaData.type === "Audio") { appName = settings.store.privacyMode - ? "[Track Hidden]" + ? t("jellyfinRichPresence.privacyMode.trackHidden") : `${mediaData.artist || "Unknown Artist"} - ${mediaData.name}`; } else { appName = settings.store.privacyMode - ? "[Movie Hidden]" + ? t("jellyfinRichPresence.privacyMode.movieHidden") : mediaData.name || "Jellyfin"; } break; @@ -318,10 +319,10 @@ export default definePlugin({ appName = templateReplace(settings.store.customName || "{name} on Jellyfin"); if (settings.store.privacyMode) { appName = appName - .replace(mediaData.name || "", "[Title Hidden]") - .replace(mediaData.seriesName || "", "[Series Hidden]") - .replace(mediaData.artist || "", "[Artist Hidden]") - .replace(mediaData.album || "", "[Album Hidden]"); + .replace(mediaData.name || "", t("jellyfinRichPresence.privacyMode.titleHidden")) + .replace(mediaData.seriesName || "", t("jellyfinRichPresence.privacyMode.seriesHidden")) + .replace(mediaData.artist || "", t("jellyfinRichPresence.privacyMode.artistHidden")) + .replace(mediaData.album || "", t("jellyfinRichPresence.privacyMode.albumHidden")); } break; case "default": @@ -330,7 +331,7 @@ export default definePlugin({ appName = mediaData.seriesName; } else { appName = settings.store.privacyMode - ? "[Media Hidden]" + ? t("jellyfinRichPresence.privacyMode.mediaHidden") : mediaData.name || "Jellyfin"; } break; @@ -351,14 +352,14 @@ export default definePlugin({ const getDetails = () => { if (mediaData.type === "Episode" && mediaData.seriesName) { - return settings.store.privacyMode ? "Watching a TV Show" : mediaData.seriesName; + return settings.store.privacyMode ? t("jellyfinRichPresence.privacyMode.watchingTvShow") : mediaData.seriesName; } - return settings.store.privacyMode ? "Watching Something" : mediaData.name; + return settings.store.privacyMode ? t("jellyfinRichPresence.privacyMode.watchingSomething") : mediaData.name; }; const getState = () => { if (mediaData.isPaused) { - return "Paused"; + return t("jellyfinRichPresence.state.paused"); } if (mediaData.type === "Episode" && mediaData.seriesName) { let episodeFormat = ""; @@ -375,13 +376,13 @@ export default definePlugin({ episodeFormat = `${season}x${episode.toString().padStart(2, "0")}`; break; case "fulltext": - episodeFormat = `Season ${season} Episode ${episode}`; + episodeFormat = t("jellyfinRichPresence.state.season", { season }) + " " + t("jellyfinRichPresence.state.episode", { episode }); break; } } else if (season != null) { - episodeFormat = format === "fulltext" ? `Season ${season}` : `S${season.toString().padStart(2, "0")}`; + episodeFormat = format === "fulltext" ? t("jellyfinRichPresence.state.season", { season }) : `S${season.toString().padStart(2, "0")}`; } else if (episode != null) { - episodeFormat = format === "fulltext" ? `Episode ${episode}` : `E${episode.toString().padStart(2, "0")}`; + episodeFormat = format === "fulltext" ? t("jellyfinRichPresence.state.episode", { episode }) : `E${episode.toString().padStart(2, "0")}`; } if (settings.store.showEpisodeName && mediaData.name && !settings.store.privacyMode) { @@ -390,7 +391,7 @@ export default definePlugin({ return episodeFormat; } if (settings.store.privacyMode) { - return mediaData.type === "Audio" ? "Listening to music" : (mediaData.year ? "(????)" : undefined); + return mediaData.type === "Audio" ? t("jellyfinRichPresence.privacyMode.listeningToMusic") : (mediaData.year ? "(????)" : undefined); } return mediaData.artist || (mediaData.year ? `(${mediaData.year})` : undefined); }; diff --git a/src/equicordplugins/jumpTo/index.tsx b/src/equicordplugins/jumpTo/index.tsx index e74dfc913..e45c99d3a 100644 --- a/src/equicordplugins/jumpTo/index.tsx +++ b/src/equicordplugins/jumpTo/index.tsx @@ -6,6 +6,7 @@ import { NavContextMenuPatchCallback } from "@api/ContextMenu"; import { Devs } from "@utils/constants"; +import { t } from "@utils/translation"; import definePlugin from "@utils/types"; import { Channel, Message, User } from "@vencord/discord-types"; import { Constants, Menu, NavigationRouter, RestAPI, SelectedChannelStore, SelectedGuildStore, Toasts } from "@webpack/common"; @@ -44,7 +45,7 @@ async function jumpToUserMessage(channelId: string, guildId: string, userId: str if (!messageId) { Toasts.show({ type: Toasts.Type.FAILURE, - message: "No messages found from this user in this channel.", + message: t("jumpTo.errors.noMessagesFound"), id: Toasts.genId() }); return; @@ -55,7 +56,7 @@ async function jumpToUserMessage(channelId: string, guildId: string, userId: str } catch (e) { Toasts.show({ type: Toasts.Type.FAILURE, - message: "Failed to search for messages.", + message: t("jumpTo.errors.failedSearch"), id: Toasts.genId() }); } @@ -67,12 +68,12 @@ const ChannelMenuPatch: NavContextMenuPatchCallback = (children, { channel }: { children.push( jumpToFirstMessage(channel.id, channel.guild_id)} />, jumpToLastMessage(channel.id, channel.guild_id)} /> ); @@ -86,12 +87,12 @@ const UserMenuPatch: NavContextMenuPatchCallback = (children, { user, channel }: children.push( jumpToFirstMessage(channel.id, null)} />, jumpToLastMessage(channel.id, null)} /> ); @@ -107,12 +108,12 @@ const MessageMenuPatch: NavContextMenuPatchCallback = (children, { message }: { children.push( jumpToUserMessage(channelId, guildId, message.author.id, true)} />, jumpToUserMessage(channelId, guildId, message.author.id, false)} /> ); @@ -120,7 +121,7 @@ const MessageMenuPatch: NavContextMenuPatchCallback = (children, { message }: { export default definePlugin({ name: "JumpTo", - description: "Adds context menu options to jump to the start or bottom of a channel/DM.", + description: t("jumpTo.description"), authors: [Devs.Samwich, Devs.thororen], contextMenus: { "channel-context": ChannelMenuPatch, diff --git a/src/equicordplugins/jumpscare/index.tsx b/src/equicordplugins/jumpscare/index.tsx index 5a8e4d531..cc684768c 100644 --- a/src/equicordplugins/jumpscare/index.tsx +++ b/src/equicordplugins/jumpscare/index.tsx @@ -9,6 +9,7 @@ import "./styles.css"; import { createAudioPlayer } from "@api/AudioPlayer"; import { definePluginSettings } from "@api/Settings"; import { Devs } from "@utils/constants"; +import { t } from "@utils/translation"; import definePlugin, { OptionType } from "@utils/types"; import { createRoot, FluxDispatcher, useCallback, useEffect, useState } from "@webpack/common"; import { Root } from "react-dom/client"; @@ -18,17 +19,17 @@ let jumpscareRoot: Root | undefined; const settings = definePluginSettings({ imageSource: { type: OptionType.STRING, - description: "Sets the image url of the jumpscare", + description: t("jumpscare.settings.imageSource"), default: "https://github.com/Equicord/Equibored/blob/main/icons/jumpscare/troll.gif?raw=true" }, audioSource: { type: OptionType.STRING, - description: "Sets the audio url of the jumpscare", + description: t("jumpscare.settings.audioSource"), default: "https://github.com/Equicord/Equibored/raw/main/sounds/jumpscare/trollolol.mp3?raw=true" }, chance: { type: OptionType.NUMBER, - description: "The chance of a jumpscare happening (1 in X so: 100 = 1/100 or 1%, 50 = 1/50 or 2%, etc.)", + description: t("jumpscare.settings.chance"), default: 1000 } }); @@ -47,7 +48,7 @@ function getJumpscareRoot(): Root { export default definePlugin({ name: "Jumpscare", - description: "Adds a configurable chance of jumpscaring you whenever you open a channel. Inspired by Geometry Dash Mega Hack", + description: t("jumpscare.description"), authors: [Devs.surgedevs], dependencies: ["AudioPlayerAPI"], settings, diff --git a/src/equicordplugins/keyboardNavigation/index.tsx b/src/equicordplugins/keyboardNavigation/index.tsx index f0c6e8d2a..bda1539bc 100644 --- a/src/equicordplugins/keyboardNavigation/index.tsx +++ b/src/equicordplugins/keyboardNavigation/index.tsx @@ -8,6 +8,7 @@ import { definePluginSettings } from "@api/Settings"; import { Devs } from "@utils/constants"; import { classNameFactory } from "@utils/css"; import { closeAllModals } from "@utils/modal"; +import { t } from "@utils/translation"; import definePlugin, { OptionType } from "@utils/types"; import { SettingsRouter, useState } from "@webpack/common"; @@ -19,7 +20,7 @@ let isRecordingGlobal: boolean = false; export const settings = definePluginSettings({ hotkey: { - description: "The hotkey to open the command palette.", + description: t("keyboardNavigation.settings.hotkey"), type: OptionType.COMPONENT, default: ["Control", "Shift", "P"], component: () => { @@ -69,7 +70,7 @@ export const settings = definePluginSettings({
{settings.store.hotkey.map(word => word.charAt(0).toUpperCase() + word.slice(1)).join(" + ")}
@@ -78,7 +79,7 @@ export const settings = definePluginSettings({ } }, allowMouseControl: { - description: "Allow the mouse to control the command palette.", + description: t("keyboardNavigation.settings.allowMouseControl"), type: OptionType.BOOLEAN, default: true } @@ -86,7 +87,7 @@ export const settings = definePluginSettings({ export default definePlugin({ name: "KeyboardNavigation", - description: "Allows you to navigate the UI with a keyboard.", + description: t("keyboardNavigation.description"), authors: [Devs.Ethan], settings, @@ -96,7 +97,7 @@ export default definePlugin({ if (IS_DEV) { registerAction({ id: "openDevSettings", - label: "Open Dev tab", + label: t("keyboardNavigation.commands.openDevSettings"), callback: () => SettingsRouter.openUserSettings("equicord_patch_helper_panel"), registrar: "Equicord" }); diff --git a/src/equicordplugins/keyboardSounds/index.ts b/src/equicordplugins/keyboardSounds/index.ts index 14c8018ff..58c597bce 100644 --- a/src/equicordplugins/keyboardSounds/index.ts +++ b/src/equicordplugins/keyboardSounds/index.ts @@ -7,6 +7,7 @@ import { AudioPlayerInterface, createAudioPlayer } from "@api/AudioPlayer"; import { definePluginSettings } from "@api/Settings"; import { Devs, EquicordDevs } from "@utils/constants"; +import { t } from "@utils/translation"; import definePlugin, { OptionType } from "@utils/types"; import { ignoredKeys, packs } from "./packs"; @@ -105,7 +106,7 @@ function assignSounds(volume: number, pack: "operagx" | "osu") { const settings = definePluginSettings({ volume: { - description: "Volume of the keyboard sounds.", + description: t("keyboardSounds.settings.volume"), type: OptionType.SLIDER, markers: [0, 25, 50, 75, 100], stickToMarkers: false, @@ -113,11 +114,11 @@ const settings = definePluginSettings({ onChange: value => { assignSounds(value, settings.store.soundPack); } }, soundPack: { - description: "Sound pack to use.", + description: t("keyboardSounds.settings.soundPack"), type: OptionType.SELECT, options: [ - { label: "OperaGX", value: "operagx" as "operagx", default: true }, - { label: "osu!", value: "osu" as "osu" } + { label: t("keyboardSounds.options.operaGx"), value: "operagx" as "operagx", default: true }, + { label: t("keyboardSounds.options.osu"), value: "osu" as "osu" } ], onChange: value => { assignSounds(settings.store.volume, value); } } @@ -125,7 +126,7 @@ const settings = definePluginSettings({ export default definePlugin({ name: "KeyboardSounds", - description: "Adds OperaGX or osu! sound effects when typing on your keyboard.", + description: t("keyboardSounds.description"), authors: [Devs.HypedDomi, EquicordDevs.Etorix], dependencies: ["AudioPlayerAPI"], settings, diff --git a/src/equicordplugins/keywordNotify/index.tsx b/src/equicordplugins/keywordNotify/index.tsx index 10b08dddb..59e32e3eb 100644 --- a/src/equicordplugins/keywordNotify/index.tsx +++ b/src/equicordplugins/keywordNotify/index.tsx @@ -18,6 +18,7 @@ import { classNameFactory } from "@utils/css"; import { Margins } from "@utils/margins"; import { classes } from "@utils/misc"; import { useForceUpdater } from "@utils/react"; +import { t } from "@utils/translation"; import definePlugin, { OptionType } from "@utils/types"; import { Message } from "@vencord/discord-types"; import { findByCodeLazy, findCssClassesLazy } from "@webpack"; @@ -162,8 +163,8 @@ function ListTypeSelector({ listType, setListType }: { listType: ListType, setLi return ( @@ -206,14 +207,14 @@ export function RPCSettings() { - + - + - Notice - Activity Sharing isn't enabled, people won't be able to see your custom rich presence! + {t("customRPC.notice.title")} + {t("customRPC.notice.body")} )} - Go to the Discord Developer Portal to create an application and - get the application ID. + + Go to the Discord Developer Portal to create an application and get the application ID. + - Upload images in the Rich Presence tab to get the image keys. + {t("customRPC.instructions.uploadImages")} - If you want to use an image link, download your image and reupload the image to Imgur and get the image link by right-clicking the image and selecting "Copy image address". + + If you want to use an image link, download your image and reupload the image to Imgur and get the image link by right-clicking the image and selecting "Copy image address". + - You can't see your own buttons on your profile, but everyone else can see it fine. + {t("customRPC.instructions.buttons")} - Some weird unicode text ("fonts" 𝖑𝖎𝖐𝖊 𝖙𝖍𝖎𝖘) may cause the rich presence to not show up, try using normal letters instead. + {t("customRPC.instructions.unicode")} diff --git a/src/plugins/dearrow/index.tsx b/src/plugins/dearrow/index.tsx index 1247472d4..7375bd1c1 100644 --- a/src/plugins/dearrow/index.tsx +++ b/src/plugins/dearrow/index.tsx @@ -10,6 +10,7 @@ import { definePluginSettings } from "@api/Settings"; import ErrorBoundary from "@components/ErrorBoundary"; import { Devs } from "@utils/constants"; import { Logger } from "@utils/Logger"; +import { t } from "@utils/translation"; import definePlugin, { OptionType } from "@utils/types"; import { Tooltip } from "@webpack/common"; import type { Component } from "react"; @@ -91,7 +92,7 @@ function DearrowButton({ component }: { component: Component; }) { if (!embed?.dearrow) return null; return ( - + {({ onMouseEnter, onMouseLeave }) => ( {selectedDecoration && authorization.isAuthorized() && } ; diff --git a/src/plugins/experiments/index.tsx b/src/plugins/experiments/index.tsx index 5c865d6b5..ca2baa280 100644 --- a/src/plugins/experiments/index.tsx +++ b/src/plugins/experiments/index.tsx @@ -13,6 +13,7 @@ import { HeadingPrimary, HeadingSecondary } from "@components/Heading"; import { Paragraph } from "@components/Paragraph"; import { Devs, IS_MAC } from "@utils/constants"; import { Margins } from "@utils/margins"; +import { t } from "@utils/translation"; import definePlugin, { OptionType } from "@utils/types"; import { findByPropsLazy, findLazy } from "@webpack"; import { React } from "@webpack/common"; @@ -28,7 +29,7 @@ const altKey = IS_MAC ? "opt" : "alt"; const settings = definePluginSettings({ toolbarDevMenu: { type: OptionType.BOOLEAN, - description: "Change the Help (?) toolbar button (top right in chat) to Discord's developer menu", + description: t("experiments.settings.toolbarDevMenu"), default: false, restartNeeded: true } @@ -36,7 +37,7 @@ const settings = definePluginSettings({ export default definePlugin({ name: "Experiments", - description: "Enable Access to Experiments & other dev-only features in Discord!", + description: t("experiments.description"), authors: [ Devs.Megu, Devs.Ven, @@ -160,16 +161,18 @@ export default definePlugin({ stop: () => disableStyle(hideBugReport), settingsAboutComponent: () => { + const keyboardCombo = ( +
+ {modKey} +{" "} + {altKey} +{" "} + O{" "} +
+ ); return ( - More Information + {t("experiments.moreInfo")} - You can open Discord's DevTools via {" "} -
- {modKey} +{" "} - {altKey} +{" "} - O{" "} -
+ {t("experiments.devToolsInfo", { keyboardCombo })}
); @@ -177,20 +180,18 @@ export default definePlugin({ WarningCard: ErrorBoundary.wrap(() => ( - Hold on!! + {t("experiments.holdOn")} - Experiments are unreleased Discord features. They might not work, or even break your client or get your account disabled. + {t("experiments.warning1")} - Only use experiments if you know what you're doing. Equicord is not responsible for any damage caused by enabling experiments. - - If you don't know what an experiment does, ignore it. Do not ask us what experiments do either, we probably don't know. + {t("experiments.warning2")} - No, you cannot use server-side features like checking the "Send to Client" box. + {t("experiments.warning3")} ), { noop: true }) diff --git a/src/plugins/expressionCloner/index.tsx b/src/plugins/expressionCloner/index.tsx index 3a79a05ef..8ff67c2eb 100644 --- a/src/plugins/expressionCloner/index.tsx +++ b/src/plugins/expressionCloner/index.tsx @@ -26,6 +26,7 @@ import { getGuildAcronym } from "@utils/discord"; import { Logger } from "@utils/Logger"; import { Margins } from "@utils/margins"; import { ModalContent, ModalHeader, ModalRoot, openModalLazy } from "@utils/modal"; +import { t } from "@utils/translation"; import definePlugin from "@utils/types"; import { Guild, GuildSticker } from "@vencord/discord-types"; import { StickerFormatType } from "@vencord/discord-types/enums"; @@ -193,19 +194,19 @@ async function doClone(guildId: string, data: Sticker | Emoji) { await cloneEmoji(guildId, data); Toasts.show({ - message: `Successfully cloned ${data.name} to ${GuildStore.getGuild(guildId)?.name ?? "your server"}!`, + message: t("expressionCloner.clonedSuccess", { name: data.name, guild: GuildStore.getGuild(guildId)?.name ?? "your server" }), type: Toasts.Type.SUCCESS, id: Toasts.genId() }); } catch (e: any) { - let message = "Something went wrong (check console!)"; + let message = t("expressionCloner.somethingWentWrong"); try { message = JSON.parse(e.text).message; } catch { } new Logger("ExpressionCloner").error("Failed to clone", data.name, "to", guildId, e); Toasts.show({ - message: "Failed to clone: " + message, + message: t("expressionCloner.failedToClone", { error: message }), type: Toasts.Type.FAILURE, id: Toasts.genId() }); @@ -230,7 +231,7 @@ function CloneModal({ data }: { data: Sticker | Emoji; }) { return ( <> - Custom Name + {t("expressionCloner.customName")} { @@ -240,7 +241,7 @@ function CloneModal({ data }: { data: Sticker | Emoji; }) { validate={v => (data.t === "Emoji" && v.length > 2 && v.length < 32 && nameValidator.test(v)) || (data.t === "Sticker" && v.length > 2 && v.length < 30) - || "Name must be between 2 and 32 characters and only contain alphanumeric characters" + || t("expressionCloner.nameValidation") } />
Promisable openModalLazy(async () => { const res = await fetchData(); diff --git a/src/plugins/fakeNitro/index.tsx b/src/plugins/fakeNitro/index.tsx index b77cfee27..3b226836d 100644 --- a/src/plugins/fakeNitro/index.tsx +++ b/src/plugins/fakeNitro/index.tsx @@ -77,69 +77,69 @@ const hyperLinkRegex = /\[.+?\]\((https?:\/\/.+?)\)/; const settings = definePluginSettings({ enableEmojiBypass: { - description: "Allows sending fake emojis (also bypasses missing permission to use custom emojis)", + description: t("vencord.fakeNitro.settings.enableEmojiBypass"), type: OptionType.BOOLEAN, default: true, restartNeeded: true }, emojiSize: { - description: "Size of the emojis when sending", + description: t("vencord.fakeNitro.settings.emojiSize"), type: OptionType.SLIDER, default: 48, markers: [32, 48, 56, 64, 96, 128, 160, 256, 512] }, transformEmojis: { - description: "Whether to transform fake emojis into real ones", + description: t("vencord.fakeNitro.settings.transformEmojis"), type: OptionType.BOOLEAN, default: true, restartNeeded: true }, enableStickerBypass: { - description: "Allows sending fake stickers (also bypasses missing permission to use stickers)", + description: t("vencord.fakeNitro.settings.enableStickerBypass"), type: OptionType.BOOLEAN, default: true, restartNeeded: true }, stickerSize: { - description: "Size of the stickers when sending", + description: t("vencord.fakeNitro.settings.stickerSize"), type: OptionType.SLIDER, default: 160, markers: [32, 64, 128, 160, 256, 512] }, transformStickers: { - description: "Whether to transform fake stickers into real ones", + description: t("vencord.fakeNitro.settings.transformStickers"), type: OptionType.BOOLEAN, default: true, restartNeeded: true }, transformCompoundSentence: { - description: "Whether to transform fake stickers and emojis in compound sentences (sentences with more content than just the fake emoji or sticker link)", + description: t("vencord.fakeNitro.settings.transformCompoundSentence"), type: OptionType.BOOLEAN, default: false }, enableStreamQualityBypass: { - description: "Allow streaming in nitro quality", + description: t("vencord.fakeNitro.settings.enableStreamQualityBypass"), type: OptionType.BOOLEAN, default: true, restartNeeded: true }, useStickerHyperLinks: { - description: "Whether to use hyperlinks when sending fake stickers", + description: t("vencord.fakeNitro.settings.useStickerHyperLinks"), type: OptionType.BOOLEAN, default: true }, useEmojiHyperLinks: { - description: "Whether to use hyperlinks when sending fake emojis", + description: t("vencord.fakeNitro.settings.useEmojiHyperLinks"), type: OptionType.BOOLEAN, default: true }, hyperLinkText: { - description: "What text the hyperlink should use. {{NAME}} will be replaced with the emoji/sticker name.", + description: t("vencord.fakeNitro.settings.hyperLinkText"), type: OptionType.STRING, default: "{{NAME}}" }, disableEmbedPermissionCheck: { - description: "Whether to disable the embed permission check when sending fake emojis and stickers", + description: t("vencord.fakeNitro.settings.disableEmbedPermissionCheck"), type: OptionType.BOOLEAN, default: false } @@ -180,7 +180,7 @@ function makeBypassPatches(): Omit { export default definePlugin({ name: "FakeNitro", authors: [Devs.Arjix, Devs.D3SOX, Devs.Ven, Devs.fawn, Devs.captain, Devs.Nuckyz, Devs.AutumnVN, Devs.sadan], - description: "Allows you to send fake emojis/stickers, use nitro themes, and stream in nitro quality", + description: t("vencord.fakeNitro.description"), dependencies: ["MessageEventsAPI"], settings, @@ -694,12 +694,12 @@ export default definePlugin({ switch (type) { case FakeNoticeType.Sticker: { - node.push(" This is a FakeNitro sticker and renders like a real sticker only for you. Appears as a link to non-plugin users."); + node.push(" " + t("vencord.fakeNitro.stickerNotice")); return node; } case FakeNoticeType.Emoji: { - node.push(" This is a FakeNitro emoji and renders like a real emoji only for you. Appears as a link to non-plugin users."); + node.push(" " + t("vencord.fakeNitro.emojiNotice")); return node; } @@ -800,20 +800,22 @@ export default definePlugin({ function cannotEmbedNotice() { return new Promise(resolve => { Alerts.show({ - title: "Hold on!", + title: t("vencord.fakeNitro.holdOn"), body:
- You are trying to send/edit a message that contains a FakeNitro emoji or sticker, - however you do not have permissions to embed links in the current channel. - Are you sure you want to send this message? Your FakeNitro items will appear as a link only. + {t("vencord.fakeNitro.noEmbedPerms.body1")} +
+ {t("vencord.fakeNitro.noEmbedPerms.body2")} +
+ {t("vencord.fakeNitro.noEmbedPerms.body3")}
- You can disable this notice in the plugin settings. + {t("vencord.fakeNitro.noEmbedPerms.disableNotice")}
, - confirmText: "Send Anyway", + confirmText: t("vencord.fakeNitro.sendAnyway"), cancelText: t("vencord.cancel"), - secondaryConfirmText: "Do not show again", + secondaryConfirmText: t("vencord.fakeNitro.doNotShowAgain"), onConfirm: () => resolve(true), onCloseCallback: () => setImmediate(() => resolve(false)), onConfirmSecondary() { @@ -850,11 +852,10 @@ export default definePlugin({ if (sticker.format_type === StickerFormatType.APNG) { if (!hasAttachmentPerms(channelId)) { Alerts.show({ - title: "Hold on!", + title: t("vencord.fakeNitro.holdOn"), body:
- You cannot send this message because it contains an animated FakeNitro sticker, - and you do not have permissions to attach files in the current channel. Please remove the sticker to proceed. + {t("vencord.fakeNitro.noAttachmentPerms.body")}
}); diff --git a/src/plugins/fakeProfileThemes/index.tsx b/src/plugins/fakeProfileThemes/index.tsx index 589862c4d..8f2165c3c 100644 --- a/src/plugins/fakeProfileThemes/index.tsx +++ b/src/plugins/fakeProfileThemes/index.tsx @@ -31,6 +31,7 @@ import { copyWithToast, fetchUserProfile } from "@utils/discord"; import { Margins } from "@utils/margins"; import { classes } from "@utils/misc"; import { useAwaiter } from "@utils/react"; +import { t } from "@utils/translation"; import definePlugin, { OptionType } from "@utils/types"; import { User, UserProfile } from "@vencord/discord-types"; import { findComponentByCodeLazy } from "@webpack"; @@ -81,8 +82,8 @@ const settings = definePluginSettings({ description: "Default color source if both are present", type: OptionType.SELECT, options: [ - { label: "Nitro colors", value: true, default: true }, - { label: "Fake colors", value: false }, + { label: t("fakeProfileThemes.nitroColors"), value: true, default: true }, + { label: t("fakeProfileThemes.fakeColors"), value: false }, ] } }); @@ -119,22 +120,21 @@ function SettingsAboutComponent() { return (
- Usage + {t("fakeProfileThemes.usage")} - After enabling this plugin, you will see custom colors in - the profiles of other people using compatible plugins.{" "} + {t("fakeProfileThemes.instructions")} To set your own profile theme colors:
  • — use the color pickers below to choose your colors
  • -
  • — click the "Copy 3y3" button
  • +
  • — click the "{t("fakeProfileThemes.copy3y3")}" button
  • — paste the invisible text anywhere in your bio
- Color pickers + {t("fakeProfileThemes.colorPickers")} - Primary + {t("fakeProfileThemes.primary")} } onChange={(color: number) => { @@ -157,7 +157,7 @@ function SettingsAboutComponent() { size="xs" style={{ marginTop: "4px" }} > - Accent + {t("fakeProfileThemes.accent")} } onChange={(color: number) => { @@ -173,13 +173,13 @@ function SettingsAboutComponent() { size={Button.Sizes.XLARGE} style={{ marginBottom: "auto" }} > - Copy 3y3 + {t("fakeProfileThemes.copy3y3")} - Preview + {t("fakeProfileThemes.preview")}
Copy 3y3 + >{t("fakeProfileThemes.copy3y3")} ; }, { noop: true }), }); diff --git a/src/plugins/favGifSearch/index.tsx b/src/plugins/favGifSearch/index.tsx index 8c720f1fb..1bb3fa2ed 100644 --- a/src/plugins/favGifSearch/index.tsx +++ b/src/plugins/favGifSearch/index.tsx @@ -19,6 +19,7 @@ import { definePluginSettings } from "@api/Settings"; import ErrorBoundary from "@components/ErrorBoundary"; import { Devs } from "@utils/constants"; +import { t } from "@utils/translation"; import definePlugin, { OptionType } from "@utils/types"; import { useCallback, useEffect, useRef, useState } from "@webpack/common"; @@ -61,18 +62,18 @@ interface Instance { export const settings = definePluginSettings({ searchOption: { type: OptionType.SELECT, - description: "The part of the url you want to search", + description: t("favGifSearch.settings.searchOption"), options: [ { - label: "Entire Url", + label: t("favGifSearch.searchOptions.entireUrl"), value: "url" }, { - label: "Path Only (/somegif.gif)", + label: t("favGifSearch.searchOptions.pathOnly"), value: "path" }, { - label: "Host & Path (tenor.com somgif.gif)", + label: t("favGifSearch.searchOptions.hostAndPath"), value: "hostandpath", default: true } @@ -83,7 +84,7 @@ export const settings = definePluginSettings({ export default definePlugin({ name: "FavoriteGifSearch", authors: [Devs.Aria], - description: "Adds a search bar to favorite gifs.", + description: t("favGifSearch.description"), patches: [ { @@ -185,7 +186,7 @@ function SearchBar({ instance, SearchBarComponent }: { instance: Instance; Searc } }} query={query} - placeholder="Search Favorite Gifs" + placeholder={t("favGifSearch.searchPlaceholder")} /> ); } diff --git a/src/plugins/fixImagesQuality/index.tsx b/src/plugins/fixImagesQuality/index.tsx index 5215b68e9..111c0a60d 100644 --- a/src/plugins/fixImagesQuality/index.tsx +++ b/src/plugins/fixImagesQuality/index.tsx @@ -11,19 +11,20 @@ import { Margins } from "@components/margins"; import { Paragraph } from "@components/Paragraph"; import { Devs } from "@utils/constants"; import { Logger } from "@utils/Logger"; +import { t } from "@utils/translation"; import definePlugin, { OptionType } from "@utils/types"; const settings = definePluginSettings({ originalImagesInChat: { type: OptionType.BOOLEAN, - description: "Also load the original image in Chat. WARNING: Read the caveats above", + description: t("fixImagesQuality.settings.originalImagesInChat"), default: false, } }); export default definePlugin({ name: "FixImagesQuality", - description: "Improves quality of images by loading them at their original resolution", + description: t("fixImagesQuality.description"), authors: [Devs.Nuckyz, Devs.Ven], settings, @@ -41,18 +42,18 @@ export default definePlugin({ return ( - The default behaviour is the following: + {t("fixImagesQuality.defaultBehavior")}
    -
  • — In chat, optimised but full resolution images will be loaded.
  • -
  • — In the image modal, the original image will be loaded.
  • +
  • — {t("fixImagesQuality.inChatOptimised")}
  • +
  • — {t("fixImagesQuality.inModalOriginal")}
- You can also enable original image in chat, but beware of the following caveats: + {t("fixImagesQuality.enableOriginalCaveats")}
    -
  • — Animated images (GIF, WebP, etc.) in chat will always animate, regardless of if the App is focused.
  • -
  • — May cause lag.
  • +
  • — {t("fixImagesQuality.animatedImagesAlways")}
  • +
  • — {t("fixImagesQuality.mayCauseLag")}
diff --git a/src/plugins/friendsSince/index.tsx b/src/plugins/friendsSince/index.tsx index 006ea2fce..711016ef3 100644 --- a/src/plugins/friendsSince/index.tsx +++ b/src/plugins/friendsSince/index.tsx @@ -10,6 +10,7 @@ import { BaseText } from "@components/BaseText"; import ErrorBoundary from "@components/ErrorBoundary"; import { Devs } from "@utils/constants"; import { getCurrentChannel } from "@utils/discord"; +import { t } from "@utils/translation"; import definePlugin from "@utils/types"; import { findByCodeLazy, findByPropsLazy, findComponentByCodeLazy, findCssClassesLazy } from "@webpack"; import { RelationshipStore } from "@webpack/common"; @@ -22,7 +23,7 @@ const Section = findComponentByCodeLazy("headingVariant:", '"section"', "heading export default definePlugin({ name: "FriendsSince", - description: "Shows when you became friends with someone in the user popout", + description: t("friendsSince.description"), authors: [Devs.Elvyra, Devs.Antti], patches: [ // DM User Sidebar @@ -60,7 +61,7 @@ export default definePlugin({ if (isSidebar) { return (
@@ -73,7 +74,7 @@ export default definePlugin({ return (
("status", "showCurrentGame") const settings = definePluginSettings({ oldIcon: { type: OptionType.BOOLEAN, - description: "Use the old icon style before Discord icon redesign", + description: t("gameActivityToggle.settings.oldIcon"), default: false }, location: { type: OptionType.SELECT, - description: "Where to show the game activity toggle button", + description: t("gameActivityToggle.settings.location"), options: [ - { label: "Next to Mute/Deafen", value: "PANEL", default: true }, - { label: "Equicord Toolbox", value: "TOOLBOX" } + { label: t("gameActivityToggle.settings.locationPanel"), value: "PANEL", default: true }, + { label: t("gameActivityToggle.settings.locationToolbox"), value: "TOOLBOX" } ], get hidden() { return !isPluginEnabled(equicordToolbox.name); @@ -86,7 +87,7 @@ function GameActivityToggleButton({ iconForeground, hideTooltips, nameplate }: U return ( } role="switch" aria-checked={!showCurrentGame} @@ -99,7 +100,7 @@ function GameActivityToggleButton({ iconForeground, hideTooltips, nameplate }: U export default definePlugin({ name: "GameActivityToggle", - description: "Adds a button next to the mic and deafen button to toggle game activity.", + description: t("gameActivityToggle.description"), authors: [Devs.Nuckyz, Devs.RuukuLada], dependencies: ["UserSettingsAPI"], settings, @@ -118,7 +119,7 @@ export default definePlugin({ return ( ShowCurrentGame.updateSetting(old => !old)} /> diff --git a/src/plugins/greetStickerPicker/index.tsx b/src/plugins/greetStickerPicker/index.tsx index 0604c54d8..3c060e154 100644 --- a/src/plugins/greetStickerPicker/index.tsx +++ b/src/plugins/greetStickerPicker/index.tsx @@ -18,6 +18,7 @@ import { definePluginSettings } from "@api/Settings"; import { Devs } from "@utils/constants"; +import { t } from "@utils/translation"; import definePlugin, { OptionType } from "@utils/types"; import { Channel, Message } from "@vencord/discord-types"; import { findLazy } from "@webpack"; @@ -32,10 +33,10 @@ const settings = definePluginSettings({ greetMode: { type: OptionType.SELECT, options: [ - { label: "Greet (you can only greet 3 times)", value: GreetMode.Greet, default: true }, - { label: "Normal Message (you can greet spam)", value: GreetMode.NormalMessage } + { label: t("greetStickerPicker.greetModeLabel"), value: GreetMode.Greet, default: true }, + { label: t("greetStickerPicker.normalMessageLabel"), value: GreetMode.NormalMessage } ], - description: "Choose the greet mode" + description: t("greetStickerPicker.greetModeDescription") } }).withPrivateSettings<{ multiGreetChoices?: string[]; @@ -75,10 +76,10 @@ function GreetMenu({ channel, message }: { message: Message, channel: Channel; } FluxDispatcher.dispatch({ type: "CONTEXT_MENU_CLOSE" })} - aria-label="Greet Sticker Picker" + aria-label={t("greetStickerPicker.ariaLabel")} > {Object.values(GreetMode).map(mode => ( {WELCOME_STICKERS.map(sticker => ( {WELCOME_STICKERS.map(sticker => { @@ -137,7 +138,7 @@ function GreetMenu({ channel, message }: { message: Message, channel: Channel; } greet(channel, message, multiGreetChoices!)} disabled={multiGreetChoices.length === 0} /> @@ -151,7 +152,7 @@ function GreetMenu({ channel, message }: { message: Message, channel: Channel; } export default definePlugin({ name: "GreetStickerPicker", - description: "Allows you to use any greet sticker instead of only the random one by right-clicking the 'Wave to say hi!' button", + description: t("greetStickerPicker.description"), authors: [Devs.Ven], settings, diff --git a/src/plugins/hideAttachments/index.tsx b/src/plugins/hideAttachments/index.tsx index 16579d0a7..562a9a3ef 100644 --- a/src/plugins/hideAttachments/index.tsx +++ b/src/plugins/hideAttachments/index.tsx @@ -24,6 +24,7 @@ import { migratePluginSettings } from "@api/Settings"; import { ImageInvisible, ImageVisible } from "@components/Icons"; import { Devs } from "@utils/constants"; import { classes } from "@utils/misc"; +import { t } from "@utils/translation"; import definePlugin from "@utils/types"; import { Message } from "@vencord/discord-types"; import { ChannelStore } from "@webpack/common"; @@ -55,7 +56,7 @@ async function toggleHide(channelId: string, messageId: string) { export default definePlugin({ name: "HideMedia", - description: "Hide attachments and embeds for individual messages via hover button", + description: t("hideAttachments.description"), authors: [Devs.Ven], dependencies: ["MessageUpdaterAPI"], @@ -75,7 +76,7 @@ export default definePlugin({ const isHidden = hiddenMessages.has(msg.id); return { - label: isHidden ? "Show Media" : "Hide Media", + label: isHidden ? t("hideAttachments.showMedia") : t("hideAttachments.hideMedia"), icon: isHidden ? ImageVisible : ImageInvisible, message: msg, channel: ChannelStore.getChannel(msg.channel_id), @@ -89,7 +90,7 @@ export default definePlugin({ return ( - Media Hidden + {t("hideAttachments.mediaHidden")} ); }, diff --git a/src/plugins/ignoreActivities/index.tsx b/src/plugins/ignoreActivities/index.tsx index 8eb334cbf..77110b978 100644 --- a/src/plugins/ignoreActivities/index.tsx +++ b/src/plugins/ignoreActivities/index.tsx @@ -12,6 +12,7 @@ import { HeadingSecondary } from "@components/Heading"; import { Paragraph } from "@components/Paragraph"; import { Devs } from "@utils/constants"; import { Margins } from "@utils/margins"; +import { t } from "@utils/translation"; import definePlugin, { OptionType } from "@utils/types"; import { Button, RunningGameStore, showToast, TextArea, Toasts, Tooltip, useEffect, useState } from "@webpack/common"; @@ -55,8 +56,8 @@ function ToggleIcon(activity: IgnoredActivity, tooltipText: string, path: string ); } -const ToggleIconOn = (activity: IgnoredActivity, fill: string) => ToggleIcon(activity, "Disable activity", "M480-320q75 0 127.5-52.5T660-500q0-75-52.5-127.5T480-680q-75 0-127.5 52.5T300-500q0 75 52.5 127.5T480-320Zm0-72q-45 0-76.5-31.5T372-500q0-45 31.5-76.5T480-608q45 0 76.5 31.5T588-500q0 45-31.5 76.5T480-392Zm0 192q-146 0-266-81.5T40-500q54-137 174-218.5T480-800q146 0 266 81.5T920-500q-54 137-174 218.5T480-200Zm0-300Zm0 220q113 0 207.5-59.5T832-500q-50-101-144.5-160.5T480-720q-113 0-207.5 59.5T128-500q50 101 144.5 160.5T480-280Z", fill); -const ToggleIconOff = (activity: IgnoredActivity, fill: string) => ToggleIcon(activity, "Enable activity", "m644-428-58-58q9-47-27-88t-93-32l-58-58q17-8 34.5-12t37.5-4q75 0 127.5 52.5T660-500q0 20-4 37.5T644-428Zm128 126-58-56q38-29 67.5-63.5T832-500q-50-101-143.5-160.5T480-720q-29 0-57 4t-55 12l-62-62q41-17 84-25.5t90-8.5q151 0 269 83.5T920-500q-23 59-60.5 109.5T772-302Zm20 246L624-222q-35 11-70.5 16.5T480-200q-151 0-269-83.5T40-500q21-53 53-98.5t73-81.5L56-792l56-56 736 736-56 56ZM222-624q-29 26-53 57t-41 67q50 101 143.5 160.5T480-280q20 0 39-2.5t39-5.5l-36-38q-11 3-21 4.5t-21 1.5q-75 0-127.5-52.5T300-500q0-11 1.5-21t4.5-21l-84-82Zm319 93Zm-151 75Z", fill); +const ToggleIconOn = (activity: IgnoredActivity, fill: string) => ToggleIcon(activity, t("ignoreActivities.disableActivity"), "M480-320q75 0 127.5-52.5T660-500q0-75-52.5-127.5T480-680q-75 0-127.5 52.5T300-500q0 75 52.5 127.5T480-320Zm0-72q-45 0-76.5-31.5T372-500q0-45 31.5-76.5T480-608q45 0 76.5 31.5T588-500q0 45-31.5 76.5T480-392Zm0 192q-146 0-266-81.5T40-500q54-137 174-218.5T480-800q146 0 266 81.5T920-500q-54 137-174 218.5T480-200Zm0-300Zm0 220q113 0 207.5-59.5T832-500q-50-101-144.5-160.5T480-720q-113 0-207.5 59.5T128-500q50 101 144.5 160.5T480-280Z", fill); +const ToggleIconOff = (activity: IgnoredActivity, fill: string) => ToggleIcon(activity, t("ignoreActivities.enableActivity"), "m644-428-58-58q9-47-27-88t-93-32l-58-58q17-8 34.5-12t37.5-4q75 0 127.5 52.5T660-500q0 20-4 37.5T644-428Zm128 126-58-56q38-29 67.5-63.5T832-500q-50-101-143.5-160.5T480-720q-29 0-57 4t-55 12l-62-62q41-17 84-25.5t90-8.5q151 0 269 83.5T920-500q-23 59-60.5 109.5T772-302Zm20 246L624-222q-35 11-70.5 16.5T480-200q-151 0-269-83.5T40-500q21-53 53-98.5t73-81.5L56-792l56-56 736 736-56 56ZM222-624q-29 26-53 57t-41 67q50 101 143.5 160.5T480-280q20 0 39-2.5t39-5.5l-36-38q-11 3-21 4.5t-21 1.5q-75 0-127.5-52.5T300-500q0-11 1.5-21t4.5-21l-84-82Zm319 93Zm-151 75Z", fill); function ToggleActivityComponent(activity: IgnoredActivity, isPlaying = false) { const s = settings.use(["ignoredActivities"]); @@ -81,22 +82,22 @@ function recalculateActivities() { function ImportCustomRPCComponent() { return ( - Import the application id of the CustomRPC plugin to the filter list + {t("ignoreActivities.importCustomRPC.description")}
@@ -131,8 +132,8 @@ function IdsListComponent(props: { setValue: (value: string) => void; }) { return (
- Filter List - Comma separated list of activity IDs to filter (Useful for filtering specific RPC activities and CustomRPC + {t("ignoreActivities.filterList.title")} + {t("ignoreActivities.filterList.description")}