Equicord/src/equicordplugins/keyboardNavigation/index.tsx
M acf7abe77a
feat(i18n): Add translation keys and implement localization for 80+ p… (#772)
* 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>
2026-02-15 09:39:58 -05:00

143 lines
4.9 KiB
TypeScript

/*
* Vencord, a Discord client mod
* Copyright (c) 2024 Vendicated and contributors
* SPDX-License-Identifier: GPL-3.0-or-later
*/
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";
import { registerAction } from "./commands";
import { openCommandPalette } from "./components/CommandPalette";
const cl = classNameFactory("vc-command-palette-");
let isRecordingGlobal: boolean = false;
export const settings = definePluginSettings({
hotkey: {
description: t("keyboardNavigation.settings.hotkey"),
type: OptionType.COMPONENT,
default: ["Control", "Shift", "P"],
component: () => {
const [isRecording, setIsRecording] = useState(false);
const recordKeybind = (setIsRecording: (value: boolean) => void) => {
const keys: Set<string> = new Set();
const keyLists: string[][] = [];
setIsRecording(true);
isRecordingGlobal = true;
const updateKeys = () => {
if (keys.size === 0 || !document.querySelector(`.${cl("key-recorder-button")}`)) {
const longestArray = keyLists.reduce((a, b) => a.length > b.length ? a : b);
if (longestArray.length > 0) {
settings.store.hotkey = longestArray.map(key => key.toLowerCase());
}
setIsRecording(false);
isRecordingGlobal = false;
document.removeEventListener("keydown", keydownListener);
document.removeEventListener("keyup", keyupListener);
}
keyLists.push(Array.from(keys));
};
const keydownListener = (e: KeyboardEvent) => {
const { key } = e;
if (!keys.has(key)) {
keys.add(key);
}
updateKeys();
};
const keyupListener = (e: KeyboardEvent) => {
keys.delete(e.key);
updateKeys();
};
document.addEventListener("keydown", keydownListener);
document.addEventListener("keyup", keyupListener);
};
return (
<>
<div className={cl("key-recorder-container")} onClick={() => recordKeybind(setIsRecording)}>
<div className={`${cl("key-recorder")} ${isRecording ? cl("recording") : ""}`}>
{settings.store.hotkey.map(word => word.charAt(0).toUpperCase() + word.slice(1)).join(" + ")}
<button className={`${cl("key-recorder-button")} ${isRecording ? cl("recording-button") : ""}`} disabled={isRecording}>
{isRecording ? t("keyboardNavigation.ui.recording") : t("keyboardNavigation.ui.recordKeybind")}
</button>
</div>
</div>
</>
);
}
},
allowMouseControl: {
description: t("keyboardNavigation.settings.allowMouseControl"),
type: OptionType.BOOLEAN,
default: true
}
});
export default definePlugin({
name: "KeyboardNavigation",
description: t("keyboardNavigation.description"),
authors: [Devs.Ethan],
settings,
start() {
document.addEventListener("keydown", this.event);
if (IS_DEV) {
registerAction({
id: "openDevSettings",
label: t("keyboardNavigation.commands.openDevSettings"),
callback: () => SettingsRouter.openUserSettings("equicord_patch_helper_panel"),
registrar: "Equicord"
});
}
},
stop() {
document.removeEventListener("keydown", this.event);
},
event(e: KeyboardEvent) {
enum Modifiers {
control = "ctrlKey",
shift = "shiftKey",
alt = "altKey",
meta = "metaKey"
}
const { hotkey } = settings.store;
const pressedKey = e.key.toLowerCase();
if (isRecordingGlobal) return;
for (let i = 0; i < hotkey.length; i++) {
const lowercasedRequiredKey = hotkey[i].toLowerCase();
if (lowercasedRequiredKey in Modifiers && !e[Modifiers[lowercasedRequiredKey]]) {
return;
}
if (!(lowercasedRequiredKey in Modifiers) && pressedKey !== lowercasedRequiredKey) {
return;
}
}
closeAllModals();
if (document.querySelector(`.${cl("root")}`)) return;
openCommandPalette();
}
});