* 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 <keircn@proton.me>
Co-authored-by: thororen1234 <78185467+thororen1234@users.noreply.github.com>
100 lines
4.3 KiB
TypeScript
100 lines
4.3 KiB
TypeScript
/*
|
|
* Vencord, a Discord client mod
|
|
* Copyright (c) 2024 Vendicated and contributors
|
|
* SPDX-License-Identifier: GPL-3.0-or-later
|
|
*/
|
|
|
|
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";
|
|
|
|
let hidechatbuttonsopen: boolean | undefined;
|
|
|
|
const settings = definePluginSettings({
|
|
Color: {
|
|
type: OptionType.BOOLEAN,
|
|
description: t("hideChatButtons.settings.color"),
|
|
default: false,
|
|
},
|
|
Open: {
|
|
type: OptionType.BOOLEAN,
|
|
description: t("hideChatButtons.settings.open"),
|
|
default: false,
|
|
onChange: (store: { open: boolean; }) => {
|
|
hidechatbuttonsopen = store.open;
|
|
}
|
|
},
|
|
});
|
|
|
|
function HideToggleButton(props: { open: boolean | undefined, onClick: MouseEventHandler<HTMLButtonElement>; }) {
|
|
return (<ChatBarButton
|
|
onClick={props.onClick}
|
|
tooltip={props.open ? t("hideChatButtons.ui.close") : t("hideChatButtons.ui.open")}
|
|
>
|
|
<svg
|
|
fill={settings.store.Color && props.open ? "#c32a32" : "currentColor"}
|
|
fillRule="evenodd"
|
|
width="20"
|
|
height="20"
|
|
viewBox="0 0 24 24"
|
|
style={{ scale: "1.096", translate: "0 -1px" }}
|
|
>
|
|
{props.open ?
|
|
<><path d="M1.3 21.3a1 1 0 1 0 1.4 1.4l20-20a1 1 0 0 0-1.4-1.4l-20 20ZM3.16 16.05c.18.24.53.26.74.05l.72-.72c.18-.18.2-.45.05-.66a15.7 15.7 0 0 1-1.43-2.52.48.48 0 0 1 0-.4c.4-.9 1.18-2.37 2.37-3.72C7.13 6.38 9.2 5 12 5c.82 0 1.58.12 2.28.33.18.05.38 0 .52-.13l.8-.8c.25-.25.18-.67-.15-.79A9.79 9.79 0 0 0 12 3C4.89 3 1.73 10.11 1.11 11.7a.83.83 0 0 0 0 .6c.25.64.9 2.15 2.05 3.75Z"></path><path d="M8.18 10.81c-.13.43.36.65.67.34l2.3-2.3c.31-.31.09-.8-.34-.67a4 4 0 0 0-2.63 2.63ZM12.85 15.15c-.31.31-.09.8.34.67a4.01 4.01 0 0 0 2.63-2.63c.13-.43-.36-.65-.67-.34l-2.3 2.3Z"></path> <path d="M9.72 18.67a.52.52 0 0 0-.52.13l-.8.8c-.25.25-.18.67.15.79 1.03.38 2.18.61 3.45.61 7.11 0 10.27-7.11 10.89-8.7a.83.83 0 0 0 0-.6c-.25-.64-.9-2.15-2.05-3.75a.49.49 0 0 0-.74-.05l-.72.72a.51.51 0 0 0-.05.66 15.7 15.7 0 0 1 1.43 2.52c.06.13.06.27 0 .4-.4.9-1.18 2.37-2.37 3.72C16.87 17.62 14.8 19 12 19c-.82 0-1.58-.12-2.28-.33Z"></path></> :
|
|
<path d="M22.89 11.7c.07.2.07.4 0 .6C22.27 13.9 19.1 21 12 21c-7.11 0-10.27-7.11-10.89-8.7a.83.83 0 0 1 0-.6C1.73 10.1 4.9 3 12 3c7.11 0 10.27 7.11 10.89 8.7Zm-4.5-3.62A15.11 15.11 0 0 1 20.85 12c-.38.88-1.18 2.47-2.46 3.92C16.87 17.62 14.8 19 12 19c-2.8 0-4.87-1.38-6.39-3.08A15.11 15.11 0 0 1 3.15 12c.38-.88 1.18-2.47 2.46-3.92C7.13 6.38 9.2 5 12 5c2.8 0 4.87 1.38 6.39 3.08ZM15.56 11.77c.2-.1.44.02.44.23a4 4 0 1 1-4-4c.21 0 .33.25.23.44a2.5 2.5 0 0 0 3.32 3.32Z" />
|
|
}
|
|
</svg>
|
|
</ChatBarButton>);
|
|
}
|
|
|
|
function ButtonsInnerComponent({ buttons }: { buttons: ReactNode[]; }) {
|
|
if (!buttons || buttons.every(x => (x as any)?.props?.disabled === true)) return null;
|
|
|
|
const [open, setOpen] = useState(hidechatbuttonsopen);
|
|
|
|
useEffect(() => {
|
|
hidechatbuttonsopen = open;
|
|
}, [open]);
|
|
|
|
return (
|
|
<div key="chat-bar-buttons-menu" id="chat-bar-buttons-menu" style={{
|
|
display: "flex",
|
|
flexWrap: "nowrap",
|
|
overflowX: "auto",
|
|
overflowY: "hidden"
|
|
}}>
|
|
{open && buttons.map((b, i) => <React.Fragment key={i}>{b}</React.Fragment>)}
|
|
<HideToggleButton onClick={() => setOpen(!open)} open={open} />
|
|
</div>
|
|
);
|
|
}
|
|
|
|
export default definePlugin({
|
|
name: "HideChatButtons",
|
|
description: t("hideChatButtons.description"),
|
|
settings: settings,
|
|
authors: [EquicordDevs.iamme],
|
|
patches: [
|
|
{
|
|
find: '"sticker")',
|
|
replacement: {
|
|
match: /(?<="div",\{.{0,15}children:)(.+?)\}/,
|
|
replace: "$self.buttonsInner($1)}"
|
|
}
|
|
}
|
|
],
|
|
startAt: StartAt.Init,
|
|
buttonsInner(buttons: ReactNode[]) {
|
|
return <ButtonsInnerComponent buttons={buttons} />;
|
|
},
|
|
start() {
|
|
hidechatbuttonsopen = settings.store.Open;
|
|
},
|
|
stop() {
|
|
hidechatbuttonsopen = undefined;
|
|
}
|
|
});
|